From d5b6b9aa1ea247201c555a7d2da1d241fe7b57fc Mon Sep 17 00:00:00 2001 From: str4d Date: Sat, 19 May 2018 07:46:38 +1200 Subject: [PATCH 001/330] Test note nullifier in key component test vectors --- librustzcash/src/tests/key_components.rs | 64 ++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/librustzcash/src/tests/key_components.rs b/librustzcash/src/tests/key_components.rs index d63c4d4..a31a9a0 100644 --- a/librustzcash/src/tests/key_components.rs +++ b/librustzcash/src/tests/key_components.rs @@ -27,6 +27,8 @@ fn key_components() { note_v: u64, note_r: [u8; 32], note_cm: [u8; 32], + note_pos: u64, + note_nf: [u8; 32], }; // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_key_components.py @@ -86,6 +88,12 @@ fn key_components() { 0x18, 0x50, 0xc9, 0xfe, 0xd4, 0x4f, 0xce, 0x08, 0x06, 0x27, 0x8f, 0x08, 0x3e, 0xf2, 0xdd, 0x07, 0x64, 0x39, ], + note_pos: 0, + note_nf: [ + 0x44, 0xfa, 0xd6, 0x56, 0x4f, 0xfd, 0xec, 0x9f, 0xa1, 0x9c, 0x43, 0xa2, 0x8f, 0x86, + 0x1d, 0x5e, 0xbf, 0x60, 0x23, 0x46, 0x00, 0x7d, 0xe7, 0x62, 0x67, 0xd9, 0x75, 0x27, + 0x47, 0xab, 0x40, 0x63, + ], }, TestVector { sk: [ @@ -142,6 +150,12 @@ fn key_components() { 0x89, 0xe1, 0x0e, 0x26, 0x6b, 0xcf, 0xa3, 0x1c, 0x31, 0xb2, 0x9a, 0x53, 0xae, 0x72, 0xca, 0xd4, 0x69, 0x50, ], + note_pos: 763714296, + note_nf: [ + 0x67, 0x9e, 0xb0, 0xc3, 0xa7, 0x57, 0xe2, 0xae, 0x83, 0xcd, 0xb4, 0x2a, 0x1a, 0xb2, + 0x59, 0xd7, 0x83, 0x88, 0x31, 0x54, 0x19, 0xad, 0xc7, 0x1d, 0x2e, 0x37, 0x63, 0x17, + 0x4c, 0x2e, 0x9d, 0x93, + ], }, TestVector { sk: [ @@ -198,6 +212,12 @@ fn key_components() { 0xb7, 0x40, 0x82, 0x96, 0x66, 0x17, 0x70, 0xb1, 0x01, 0xb0, 0xaa, 0x87, 0x83, 0x9f, 0x4e, 0x55, 0xf1, 0x51, ], + note_pos: 1527428592, + note_nf: [ + 0xe9, 0x8f, 0x6a, 0x8f, 0x34, 0xff, 0x49, 0x80, 0x59, 0xb3, 0xc7, 0x31, 0xb9, 0x1f, + 0x45, 0x11, 0x08, 0xc4, 0x95, 0x4d, 0x91, 0x94, 0x84, 0x36, 0x1c, 0xf9, 0xb4, 0x8f, + 0x59, 0xae, 0x1d, 0x14, + ], }, TestVector { sk: [ @@ -254,6 +274,12 @@ fn key_components() { 0xbd, 0x10, 0x5d, 0x88, 0x39, 0x21, 0x2e, 0x0d, 0x16, 0x44, 0xb9, 0xd5, 0x5c, 0xaa, 0x60, 0xd1, 0x9b, 0x6c, ], + note_pos: 2291142888, + note_nf: [ + 0x55, 0x47, 0xaa, 0x12, 0xff, 0x80, 0xa6, 0xb3, 0x30, 0x4e, 0x3b, 0x05, 0x86, 0x56, + 0x47, 0x2a, 0xbd, 0x2c, 0x81, 0x83, 0xb5, 0x9d, 0x07, 0x37, 0xb9, 0x3c, 0xee, 0x75, + 0x8b, 0xec, 0x47, 0xa1, + ], }, TestVector { sk: [ @@ -310,6 +336,12 @@ fn key_components() { 0xcf, 0x1e, 0x67, 0x15, 0xbf, 0xe7, 0x0b, 0x63, 0x2d, 0x04, 0x4b, 0x26, 0xfb, 0x2b, 0xc7, 0x1b, 0x7f, 0x36, ], + note_pos: 3054857184, + note_nf: [ + 0x8a, 0x9a, 0xbd, 0xa3, 0xd4, 0xef, 0x85, 0xca, 0xf2, 0x2b, 0xfa, 0xf2, 0xc4, 0x8f, + 0x62, 0x38, 0x2a, 0x73, 0xa1, 0x62, 0x4e, 0xb8, 0xeb, 0x2b, 0xd0, 0x0d, 0x27, 0x03, + 0x01, 0xbf, 0x3d, 0x13, + ], }, TestVector { sk: [ @@ -366,6 +398,12 @@ fn key_components() { 0x1d, 0x74, 0xc5, 0xbc, 0xf2, 0xe1, 0xef, 0x95, 0x66, 0x90, 0x44, 0x73, 0x01, 0x69, 0xde, 0x1a, 0x5b, 0x4c, ], + note_pos: 3818571480, + note_nf: [ + 0x33, 0x2a, 0xd9, 0x9e, 0xb9, 0xe9, 0x77, 0xeb, 0x62, 0x7a, 0x12, 0x2d, 0xbf, 0xb2, + 0xf2, 0x5f, 0xe5, 0x88, 0xe5, 0x97, 0x75, 0x3e, 0xc5, 0x58, 0x0f, 0xf2, 0xbe, 0x20, + 0xb6, 0xc9, 0xa7, 0xe1, + ], }, TestVector { sk: [ @@ -422,6 +460,12 @@ fn key_components() { 0x90, 0xb6, 0xe0, 0xf2, 0xf4, 0xbf, 0x4e, 0xc4, 0xa0, 0xdb, 0x5b, 0xbc, 0xcb, 0x5b, 0x78, 0x3a, 0x1e, 0x55, ], + note_pos: 287318480, + note_nf: [ + 0xfc, 0x74, 0xcd, 0x0e, 0x4b, 0xe0, 0x49, 0x57, 0xb1, 0x96, 0xcf, 0x87, 0x34, 0xae, + 0x99, 0x23, 0x96, 0xaf, 0x4c, 0xfa, 0x8f, 0xec, 0xbb, 0x86, 0xf9, 0x61, 0xe6, 0xb4, + 0x07, 0xd5, 0x1e, 0x11, + ], }, TestVector { sk: [ @@ -478,6 +522,12 @@ fn key_components() { 0x60, 0xa0, 0x06, 0xf8, 0x2b, 0xb7, 0xad, 0xcd, 0x75, 0x22, 0x3f, 0xa8, 0x59, 0x36, 0xf7, 0x8c, 0x2b, 0x23, ], + note_pos: 1051032776, + note_nf: [ + 0xd2, 0xe8, 0x87, 0xbd, 0x85, 0x4a, 0x80, 0x2b, 0xce, 0x85, 0x70, 0x53, 0x02, 0x0f, + 0x5d, 0x3e, 0x7c, 0x8a, 0xe5, 0x26, 0x7c, 0x5b, 0x65, 0x83, 0xb3, 0xd2, 0x12, 0xcc, + 0x8b, 0xb6, 0x98, 0x90, + ], }, TestVector { sk: [ @@ -534,6 +584,12 @@ fn key_components() { 0x23, 0x36, 0xc2, 0xa0, 0x5a, 0x08, 0x03, 0x23, 0x9b, 0x5b, 0x88, 0xfd, 0x92, 0x07, 0x8f, 0xea, 0x4d, 0x04, ], + note_pos: 1814747072, + note_nf: [ + 0xa8, 0x2f, 0x17, 0x50, 0xcc, 0x5b, 0x2b, 0xee, 0x64, 0x9a, 0x36, 0x5c, 0x04, 0x20, + 0xed, 0x87, 0x07, 0x5b, 0x88, 0x71, 0xfd, 0xa4, 0xa7, 0xf5, 0x84, 0x0d, 0x6b, 0xbe, + 0xb1, 0x7c, 0xd6, 0x20, + ], }, TestVector { sk: [ @@ -590,6 +646,12 @@ fn key_components() { 0x64, 0x41, 0x9b, 0x0e, 0x55, 0x0a, 0xbb, 0xcb, 0x8e, 0x2b, 0xcb, 0xda, 0x8b, 0x63, 0xe4, 0x1d, 0xeb, 0x37, ], + note_pos: 2578461368, + note_nf: [ + 0x65, 0x36, 0x74, 0x87, 0x3b, 0x3c, 0x67, 0x0c, 0x58, 0x85, 0x84, 0x73, 0xe7, 0xfe, + 0x72, 0x19, 0x72, 0xfb, 0x96, 0xe2, 0x15, 0xb8, 0x73, 0x77, 0xa1, 0x7c, 0xa3, 0x71, + 0x0d, 0x93, 0xc9, 0xe9, + ], }, ]; @@ -662,5 +724,7 @@ fn key_components() { note.cm(&JUBJUB).into_repr().write_le(&mut vec).unwrap(); assert_eq!(&vec, &tv.note_cm); } + + assert_eq!(note.nf(&fvk, tv.note_pos, &JUBJUB), tv.note_nf); } } From fae919ec1cdbb474eb6053d8e3e534f80aa115d8 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 22 Oct 2018 17:36:23 +0100 Subject: [PATCH 002/330] Rename zcash_wallet to zcash_client_backend, set to 2018 edition --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- {zcash_wallet => zcash_client_backend}/Cargo.toml | 3 ++- .../LICENSE-APACHE | 0 {zcash_wallet => zcash_client_backend}/LICENSE-MIT | 0 {zcash_wallet => zcash_client_backend}/README.md | 4 ++-- zcash_client_backend/src/lib.rs | 12 ++++++++++++ zcash_wallet/src/lib.rs | 7 ------- 8 files changed, 21 insertions(+), 15 deletions(-) rename {zcash_wallet => zcash_client_backend}/Cargo.toml (65%) rename {zcash_wallet => zcash_client_backend}/LICENSE-APACHE (100%) rename {zcash_wallet => zcash_client_backend}/LICENSE-MIT (100%) rename {zcash_wallet => zcash_client_backend}/README.md (92%) create mode 100644 zcash_client_backend/src/lib.rs delete mode 100644 zcash_wallet/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index ea0af88..7aa24e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -507,6 +507,10 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "zcash_client_backend" +version = "0.0.0" + [[package]] name = "zcash_primitives" version = "0.0.0" @@ -536,10 +540,6 @@ dependencies = [ "sapling-crypto 0.0.1", ] -[[package]] -name = "zcash_wallet" -version = "0.0.0" - [[package]] name = "zip32" version = "0.0.0" diff --git a/Cargo.toml b/Cargo.toml index f25ea72..03c5178 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,9 +6,9 @@ members = [ "librustzcash", "pairing", "sapling-crypto", + "zcash_client_backend", "zcash_primitives", "zcash_proofs", - "zcash_wallet", "zip32", ] diff --git a/zcash_wallet/Cargo.toml b/zcash_client_backend/Cargo.toml similarity index 65% rename from zcash_wallet/Cargo.toml rename to zcash_client_backend/Cargo.toml index a7b6c91..f3c6fd6 100644 --- a/zcash_wallet/Cargo.toml +++ b/zcash_client_backend/Cargo.toml @@ -1,8 +1,9 @@ [package] -name = "zcash_wallet" +name = "zcash_client_backend" version = "0.0.0" authors = [ "Jack Grigg ", ] +edition = "2018" [dependencies] diff --git a/zcash_wallet/LICENSE-APACHE b/zcash_client_backend/LICENSE-APACHE similarity index 100% rename from zcash_wallet/LICENSE-APACHE rename to zcash_client_backend/LICENSE-APACHE diff --git a/zcash_wallet/LICENSE-MIT b/zcash_client_backend/LICENSE-MIT similarity index 100% rename from zcash_wallet/LICENSE-MIT rename to zcash_client_backend/LICENSE-MIT diff --git a/zcash_wallet/README.md b/zcash_client_backend/README.md similarity index 92% rename from zcash_wallet/README.md rename to zcash_client_backend/README.md index 14c1a38..da5c9e2 100644 --- a/zcash_wallet/README.md +++ b/zcash_client_backend/README.md @@ -1,6 +1,6 @@ -# zcash_wallet +# zcash_client_backend -This library contains Rust structs and traits for creating shielded Zcash wallets. +This library contains Rust structs and traits for creating shielded Zcash light clients. ## License diff --git a/zcash_client_backend/src/lib.rs b/zcash_client_backend/src/lib.rs new file mode 100644 index 0000000..0563126 --- /dev/null +++ b/zcash_client_backend/src/lib.rs @@ -0,0 +1,12 @@ +//! *A crate for implementing Zcash light clients.* +//! +//! `zcash_client_backend` contains Rust structs and traits for creating shielded Zcash +//! light clients. + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/zcash_wallet/src/lib.rs b/zcash_wallet/src/lib.rs deleted file mode 100644 index 31e1bb2..0000000 --- a/zcash_wallet/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} From f25a8a557e4bad5636d93d128fa8f7a6f690a973 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 10 Apr 2019 07:00:48 -0700 Subject: [PATCH 003/330] Convert zip32 crate into a module of zcash_primitives --- Cargo.lock | 19 +- Cargo.toml | 1 - librustzcash/Cargo.toml | 1 - librustzcash/src/rustzcash.rs | 3 +- zcash_primitives/Cargo.toml | 2 + zcash_primitives/src/lib.rs | 3 + .../lib.rs => zcash_primitives/src/zip32.rs | 12 +- zip32/.gitignore | 3 - zip32/COPYRIGHT | 14 -- zip32/Cargo.toml | 25 --- zip32/LICENSE-APACHE | 201 ------------------ zip32/LICENSE-MIT | 23 -- zip32/README.md | 17 -- 13 files changed, 12 insertions(+), 312 deletions(-) rename zip32/src/lib.rs => zcash_primitives/src/zip32.rs (99%) delete mode 100644 zip32/.gitignore delete mode 100644 zip32/COPYRIGHT delete mode 100644 zip32/Cargo.toml delete mode 100644 zip32/LICENSE-APACHE delete mode 100644 zip32/LICENSE-MIT delete mode 100644 zip32/README.md diff --git a/Cargo.lock b/Cargo.lock index 7aa24e4..2229651 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "aes" version = "0.2.0" @@ -295,7 +297,6 @@ dependencies = [ "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", "zcash_proofs 0.0.0", - "zip32 0.0.0", ] [[package]] @@ -515,10 +516,12 @@ version = "0.0.0" name = "zcash_primitives" version = "0.0.0" dependencies = [ + "aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto_api_chachapoly 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", + "fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", @@ -540,20 +543,6 @@ dependencies = [ "sapling-crypto 0.0.1", ] -[[package]] -name = "zip32" -version = "0.0.0" -dependencies = [ - "aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0", - "fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", - "sapling-crypto 0.0.1", - "zcash_primitives 0.0.0", -] - [metadata] "checksum aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6fb1737cdc8da3db76e90ca817a194249a38fcb500c2e6ecec39b29448aa873" "checksum aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67cc03b0a090a05cb01e96998a01905d7ceedce1bc23b756c0bb7faa0682ccb1" diff --git a/Cargo.toml b/Cargo.toml index 03c5178..c5e2257 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ members = [ "zcash_client_backend", "zcash_primitives", "zcash_proofs", - "zip32", ] [profile.release] diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index e633152..3edc928 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -24,7 +24,6 @@ rand = "0.4" sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } zcash_proofs = { path = "../zcash_proofs" } -zip32 = { path = "../zip32" } [dependencies.blake2-rfc] git = "https://github.com/gtank/blake2-rfc" diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index da448b0..fb72827 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -8,7 +8,6 @@ extern crate rand; extern crate sapling_crypto; extern crate zcash_primitives; extern crate zcash_proofs; -extern crate zip32; extern crate lazy_static; @@ -58,7 +57,7 @@ use std::ffi::OsString; use std::os::windows::ffi::OsStringExt; use sapling_crypto::primitives::{ProofGenerationKey, ViewingKey}; -use zcash_primitives::{note_encryption::sapling_ka_agree, sapling::spend_sig, JUBJUB}; +use zcash_primitives::{note_encryption::sapling_ka_agree, sapling::spend_sig, zip32, JUBJUB}; use zcash_proofs::{ load_parameters, sapling::{CommitmentTreeWitness, SaplingProvingContext, SaplingVerificationContext}, diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index 644c7eb..06a117b 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -6,9 +6,11 @@ authors = [ ] [dependencies] +aes = "0.2" byteorder = "1" crypto_api_chachapoly = "0.1" ff = { path = "../ff" } +fpe = "0.1" hex = "0.3" lazy_static = "1" pairing = { path = "../pairing" } diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 38ac7a4..962811e 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -1,10 +1,12 @@ #[macro_use] extern crate lazy_static; +extern crate aes; extern crate blake2_rfc; extern crate byteorder; extern crate crypto_api_chachapoly; extern crate ff; +extern crate fpe; extern crate hex; extern crate pairing; extern crate rand; @@ -19,6 +21,7 @@ pub mod note_encryption; pub mod sapling; mod serialize; pub mod transaction; +pub mod zip32; #[cfg(test)] mod test_vectors; diff --git a/zip32/src/lib.rs b/zcash_primitives/src/zip32.rs similarity index 99% rename from zip32/src/lib.rs rename to zcash_primitives/src/zip32.rs index d89ba87..db5adcd 100644 --- a/zip32/src/lib.rs +++ b/zcash_primitives/src/zip32.rs @@ -1,12 +1,3 @@ -extern crate aes; -extern crate blake2_rfc; -extern crate byteorder; -extern crate ff; -extern crate fpe; -extern crate pairing; -extern crate sapling_crypto; -extern crate zcash_primitives; - use aes::Aes256; use blake2_rfc::blake2b::Blake2b; use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt}; @@ -18,7 +9,8 @@ use sapling_crypto::{ primitives::{Diversifier, PaymentAddress, ViewingKey}, }; use std::io::{self, Read, Write}; -use zcash_primitives::{ + +use crate::{ keys::{prf_expand, prf_expand_vec, ExpandedSpendingKey, FullViewingKey, OutgoingViewingKey}, JUBJUB, }; diff --git a/zip32/.gitignore b/zip32/.gitignore deleted file mode 100644 index 6936990..0000000 --- a/zip32/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target -**/*.rs.bk -Cargo.lock diff --git a/zip32/COPYRIGHT b/zip32/COPYRIGHT deleted file mode 100644 index e58e868..0000000 --- a/zip32/COPYRIGHT +++ /dev/null @@ -1,14 +0,0 @@ -Copyrights in the "zip32" library are retained by their contributors. No -copyright assignment is required to contribute to the "zip32" library. - -The "zip32" library is licensed under either of - - * Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT) - -at your option. - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/zip32/Cargo.toml b/zip32/Cargo.toml deleted file mode 100644 index 05923c8..0000000 --- a/zip32/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "zip32" -version = "0.0.0" -authors = [ - "Jack Grigg ", -] -license = "MIT/Apache-2.0" - -description = "Library for implementing shielded hierarchical deterministic wallets" -documentation = "https://docs.rs/zip32/" -homepage = "https://github.com/zcash-hackworks/zip32" -repository = "https://github.com/zcash-hackworks/zip32" - -[dependencies] -aes = "0.2" -byteorder = "1" -ff = { path = "../ff" } -fpe = "0.1" -pairing = { path = "../pairing" } -sapling-crypto = { path = "../sapling-crypto" } -zcash_primitives = { path = "../zcash_primitives" } - -[dependencies.blake2-rfc] -git = "https://github.com/gtank/blake2-rfc" -rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" diff --git a/zip32/LICENSE-APACHE b/zip32/LICENSE-APACHE deleted file mode 100644 index 16fe87b..0000000 --- a/zip32/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. diff --git a/zip32/LICENSE-MIT b/zip32/LICENSE-MIT deleted file mode 100644 index 31aa793..0000000 --- a/zip32/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/zip32/README.md b/zip32/README.md deleted file mode 100644 index 898d56c..0000000 --- a/zip32/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# zip32 [![Crates.io](https://img.shields.io/crates/v/zip32.svg)](https://crates.io/crates/zip32) # - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. From 81b2b1b5545c6080b2050a06f5426fbe7c49e6b8 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 15 Oct 2018 15:51:40 +0100 Subject: [PATCH 004/330] Wallet spending key derivation path --- Cargo.lock | 3 +++ zcash_client_backend/Cargo.toml | 1 + zcash_client_backend/src/constants.rs | 4 ++++ zcash_client_backend/src/constants/mainnet.rs | 4 ++++ zcash_client_backend/src/constants/testnet.rs | 4 ++++ zcash_client_backend/src/keys.rs | 24 +++++++++++++++++++ zcash_client_backend/src/lib.rs | 9 ++----- 7 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 zcash_client_backend/src/constants.rs create mode 100644 zcash_client_backend/src/constants/mainnet.rs create mode 100644 zcash_client_backend/src/constants/testnet.rs create mode 100644 zcash_client_backend/src/keys.rs diff --git a/Cargo.lock b/Cargo.lock index 2229651..d3b592d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -511,6 +511,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "zcash_client_backend" version = "0.0.0" +dependencies = [ + "zcash_primitives 0.0.0", +] [[package]] name = "zcash_primitives" diff --git a/zcash_client_backend/Cargo.toml b/zcash_client_backend/Cargo.toml index f3c6fd6..d1993ba 100644 --- a/zcash_client_backend/Cargo.toml +++ b/zcash_client_backend/Cargo.toml @@ -7,3 +7,4 @@ authors = [ edition = "2018" [dependencies] +zcash_primitives = { path = "../zcash_primitives" } diff --git a/zcash_client_backend/src/constants.rs b/zcash_client_backend/src/constants.rs new file mode 100644 index 0000000..8e5727c --- /dev/null +++ b/zcash_client_backend/src/constants.rs @@ -0,0 +1,4 @@ +//! Zcash global and per-network constants. + +pub mod mainnet; +pub mod testnet; diff --git a/zcash_client_backend/src/constants/mainnet.rs b/zcash_client_backend/src/constants/mainnet.rs new file mode 100644 index 0000000..753956e --- /dev/null +++ b/zcash_client_backend/src/constants/mainnet.rs @@ -0,0 +1,4 @@ +/// The mainnet coin type for ZEC, as defined by [SLIP 44]. +/// +/// [SLIP 44]: https://github.com/satoshilabs/slips/blob/master/slip-0044.md +pub const COIN_TYPE: u32 = 133; diff --git a/zcash_client_backend/src/constants/testnet.rs b/zcash_client_backend/src/constants/testnet.rs new file mode 100644 index 0000000..836340c --- /dev/null +++ b/zcash_client_backend/src/constants/testnet.rs @@ -0,0 +1,4 @@ +/// The testnet coin type for ZEC, as defined by [SLIP 44]. +/// +/// [SLIP 44]: https://github.com/satoshilabs/slips/blob/master/slip-0044.md +pub const COIN_TYPE: u32 = 1; diff --git a/zcash_client_backend/src/keys.rs b/zcash_client_backend/src/keys.rs new file mode 100644 index 0000000..4d4cd6f --- /dev/null +++ b/zcash_client_backend/src/keys.rs @@ -0,0 +1,24 @@ +//! Helper functions for managing light client key material. + +use zcash_primitives::zip32::{ChildIndex, ExtendedSpendingKey}; + +/// Derives the ZIP 32 [`ExtendedSpendingKey`] for a given coin type and account from the +/// given seed. +/// +/// # Examples +/// +/// ``` +/// use zcash_client_backend::{constants::testnet::COIN_TYPE, keys::spending_key}; +/// +/// let extsk = spending_key(&[0; 32][..], COIN_TYPE, 0); +/// ``` +pub fn spending_key(seed: &[u8], coin_type: u32, account: u32) -> ExtendedSpendingKey { + ExtendedSpendingKey::from_path( + &ExtendedSpendingKey::master(&seed), + &[ + ChildIndex::Hardened(32), + ChildIndex::Hardened(coin_type), + ChildIndex::Hardened(account), + ], + ) +} diff --git a/zcash_client_backend/src/lib.rs b/zcash_client_backend/src/lib.rs index 0563126..de76975 100644 --- a/zcash_client_backend/src/lib.rs +++ b/zcash_client_backend/src/lib.rs @@ -3,10 +3,5 @@ //! `zcash_client_backend` contains Rust structs and traits for creating shielded Zcash //! light clients. -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} +pub mod constants; +pub mod keys; From 17f60a03540d51e495bb9d2b82db12e6cb9ff221 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 17 Oct 2018 10:06:13 +0100 Subject: [PATCH 005/330] Implement PaymentAddress encoding and decoding --- Cargo.lock | 10 + zcash_client_backend/Cargo.toml | 6 + zcash_client_backend/src/constants/mainnet.rs | 8 + zcash_client_backend/src/constants/testnet.rs | 8 + zcash_client_backend/src/encoding.rs | 173 ++++++++++++++++++ zcash_client_backend/src/lib.rs | 1 + 6 files changed, 206 insertions(+) create mode 100644 zcash_client_backend/src/encoding.rs diff --git a/Cargo.lock b/Cargo.lock index d3b592d..34b20d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,6 +38,11 @@ dependencies = [ "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bech32" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bellman" version = "0.1.0" @@ -512,6 +517,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "zcash_client_backend" version = "0.0.0" dependencies = [ + "bech32 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pairing 0.14.2", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", ] @@ -551,6 +560,7 @@ dependencies = [ "checksum aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67cc03b0a090a05cb01e96998a01905d7ceedce1bc23b756c0bb7faa0682ccb1" "checksum aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6810b7fb9f2bb4f76f05ac1c170b8dde285b6308955dc3afd89710268c958d9e" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum bech32 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58946044516aa9dc922182e0d6e9d124a31aafe6b421614654eb27cf90cec09c" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)" = "" diff --git a/zcash_client_backend/Cargo.toml b/zcash_client_backend/Cargo.toml index d1993ba..bc57fdb 100644 --- a/zcash_client_backend/Cargo.toml +++ b/zcash_client_backend/Cargo.toml @@ -7,4 +7,10 @@ authors = [ edition = "2018" [dependencies] +bech32 = "0.6" +pairing = { path = "../pairing" } +sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } + +[dev-dependencies] +rand = "0.4" diff --git a/zcash_client_backend/src/constants/mainnet.rs b/zcash_client_backend/src/constants/mainnet.rs index 753956e..2850c45 100644 --- a/zcash_client_backend/src/constants/mainnet.rs +++ b/zcash_client_backend/src/constants/mainnet.rs @@ -2,3 +2,11 @@ /// /// [SLIP 44]: https://github.com/satoshilabs/slips/blob/master/slip-0044.md pub const COIN_TYPE: u32 = 133; + +/// The HRP for a Bech32-encoded mainnet [`PaymentAddress`]. +/// +/// Defined in section 5.6.4 of the [Zcash Protocol Specification]. +/// +/// [`PaymentAddress`]: sapling_crypto::primitives::PaymentAddress +/// [Zcash Protocol Specification]: https://github.com/zcash/zips/blob/master/protocol/protocol.pdf +pub const HRP_SAPLING_PAYMENT_ADDRESS: &str = "zs"; diff --git a/zcash_client_backend/src/constants/testnet.rs b/zcash_client_backend/src/constants/testnet.rs index 836340c..f4ea3c2 100644 --- a/zcash_client_backend/src/constants/testnet.rs +++ b/zcash_client_backend/src/constants/testnet.rs @@ -2,3 +2,11 @@ /// /// [SLIP 44]: https://github.com/satoshilabs/slips/blob/master/slip-0044.md pub const COIN_TYPE: u32 = 1; + +/// The HRP for a Bech32-encoded testnet [`PaymentAddress`]. +/// +/// Defined in section 5.6.4 of the [Zcash Protocol Specification]. +/// +/// [`PaymentAddress`]: sapling_crypto::primitives::PaymentAddress +/// [Zcash Protocol Specification]: https://github.com/zcash/zips/blob/master/protocol/protocol.pdf +pub const HRP_SAPLING_PAYMENT_ADDRESS: &str = "ztestsapling"; diff --git a/zcash_client_backend/src/encoding.rs b/zcash_client_backend/src/encoding.rs new file mode 100644 index 0000000..7150621 --- /dev/null +++ b/zcash_client_backend/src/encoding.rs @@ -0,0 +1,173 @@ +//! Encoding and decoding functions for Zcash key and address structs. +//! +//! Human-Readable Prefixes (HRPs) for Bech32 encodings are located in the [`constants`] +//! module. + +use bech32::{convert_bits, Bech32, Error}; +use pairing::bls12_381::Bls12; +use sapling_crypto::{ + jubjub::edwards, + primitives::{Diversifier, PaymentAddress}, +}; +use std::io::{self, Write}; +use zcash_primitives::JUBJUB; + +fn bech32_encode(hrp: &str, write: F) -> String +where + F: Fn(&mut dyn Write) -> io::Result<()>, +{ + let mut data: Vec = vec![]; + write(&mut data).expect("Should be able to write to a Vec"); + + let converted = + convert_bits(&data, 8, 5, true).expect("Should be able to convert Vec to Vec"); + let encoded = Bech32::new_check_data(hrp.into(), converted).expect("hrp is not empty"); + + encoded.to_string() +} + +fn bech32_decode(hrp: &str, s: &str, read: F) -> Result, Error> +where + F: Fn(Vec) -> Option, +{ + let decoded = s.parse::()?; + if decoded.hrp() == hrp { + convert_bits(decoded.data(), 5, 8, false).map(|data| read(data)) + } else { + Ok(None) + } +} + +/// Writes a [`PaymentAddress`] as a Bech32-encoded string. +/// +/// # Examples +/// +/// ``` +/// use pairing::bls12_381::Bls12; +/// use rand::{SeedableRng, XorShiftRng}; +/// use sapling_crypto::{ +/// jubjub::edwards, +/// primitives::{Diversifier, PaymentAddress}, +/// }; +/// use zcash_client_backend::{ +/// constants::testnet::HRP_SAPLING_PAYMENT_ADDRESS, +/// encoding::encode_payment_address, +/// }; +/// use zcash_primitives::JUBJUB; +/// +/// let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); +/// +/// let pa = PaymentAddress { +/// diversifier: Diversifier([0u8; 11]), +/// pk_d: edwards::Point::::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB), +/// }; +/// +/// assert_eq!( +/// encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, &pa), +/// "ztestsapling1qqqqqqqqqqqqqqqqqqxrrfaccydp867g6zg7ne5ht37z38jtfyw0ygmp0ja6hhf07twjq6awtaj", +/// ); +/// ``` +pub fn encode_payment_address(hrp: &str, addr: &PaymentAddress) -> String { + bech32_encode(hrp, |w| { + w.write_all(&addr.diversifier.0)?; + addr.pk_d.write(w) + }) +} + +/// Decodes a [`PaymentAddress`] from a Bech32-encoded string. +/// +/// # Examples +/// +/// ``` +/// use pairing::bls12_381::Bls12; +/// use rand::{SeedableRng, XorShiftRng}; +/// use sapling_crypto::{ +/// jubjub::edwards, +/// primitives::{Diversifier, PaymentAddress}, +/// }; +/// use zcash_client_backend::{ +/// constants::testnet::HRP_SAPLING_PAYMENT_ADDRESS, +/// encoding::decode_payment_address, +/// }; +/// use zcash_primitives::JUBJUB; +/// +/// let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); +/// +/// let pa = PaymentAddress { +/// diversifier: Diversifier([0u8; 11]), +/// pk_d: edwards::Point::::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB), +/// }; +/// +/// assert_eq!( +/// decode_payment_address( +/// HRP_SAPLING_PAYMENT_ADDRESS, +/// "ztestsapling1qqqqqqqqqqqqqqqqqqxrrfaccydp867g6zg7ne5ht37z38jtfyw0ygmp0ja6hhf07twjq6awtaj", +/// ), +/// Ok(Some(pa)), +/// ); +/// ``` +pub fn decode_payment_address(hrp: &str, s: &str) -> Result>, Error> { + bech32_decode(hrp, s, |data| { + let mut diversifier = Diversifier([0; 11]); + diversifier.0.copy_from_slice(&data[0..11]); + edwards::Point::::read(&data[11..], &JUBJUB) + .ok()? + .as_prime_order(&JUBJUB) + .map(|pk_d| PaymentAddress { pk_d, diversifier }) + }) +} + +#[cfg(test)] +mod tests { + use pairing::bls12_381::Bls12; + use rand::{SeedableRng, XorShiftRng}; + use sapling_crypto::{ + jubjub::edwards, + primitives::{Diversifier, PaymentAddress}, + }; + use zcash_primitives::JUBJUB; + + use super::{decode_payment_address, encode_payment_address}; + use crate::constants; + + #[test] + fn payment_address() { + let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + + let addr = PaymentAddress { + diversifier: Diversifier([0u8; 11]), + pk_d: edwards::Point::::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB), + }; + + let encoded_main = + "zs1qqqqqqqqqqqqqqqqqqxrrfaccydp867g6zg7ne5ht37z38jtfyw0ygmp0ja6hhf07twjqj2ug6x"; + let encoded_test = + "ztestsapling1qqqqqqqqqqqqqqqqqqxrrfaccydp867g6zg7ne5ht37z38jtfyw0ygmp0ja6hhf07twjq6awtaj"; + + assert_eq!( + encode_payment_address(constants::mainnet::HRP_SAPLING_PAYMENT_ADDRESS, &addr), + encoded_main + ); + assert_eq!( + decode_payment_address( + constants::mainnet::HRP_SAPLING_PAYMENT_ADDRESS, + encoded_main + ) + .unwrap(), + Some(addr.clone()) + ); + + assert_eq!( + encode_payment_address(constants::testnet::HRP_SAPLING_PAYMENT_ADDRESS, &addr), + encoded_test + ); + assert_eq!( + decode_payment_address( + constants::testnet::HRP_SAPLING_PAYMENT_ADDRESS, + encoded_test + ) + .unwrap(), + Some(addr) + ); + } +} diff --git a/zcash_client_backend/src/lib.rs b/zcash_client_backend/src/lib.rs index de76975..02de4b4 100644 --- a/zcash_client_backend/src/lib.rs +++ b/zcash_client_backend/src/lib.rs @@ -4,4 +4,5 @@ //! light clients. pub mod constants; +pub mod encoding; pub mod keys; From dd9c9ffa3fb65f99dcf2e05c3e6f06bd494b2c0d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 30 Jan 2019 14:31:32 +0000 Subject: [PATCH 006/330] Add encodings for ExtendedSpendingKey and ExtendedFullViewingKey --- zcash_client_backend/src/constants/mainnet.rs | 16 +++++ zcash_client_backend/src/constants/testnet.rs | 16 +++++ zcash_client_backend/src/encoding.rs | 59 ++++++++++++++++++- 3 files changed, 90 insertions(+), 1 deletion(-) diff --git a/zcash_client_backend/src/constants/mainnet.rs b/zcash_client_backend/src/constants/mainnet.rs index 2850c45..ed90697 100644 --- a/zcash_client_backend/src/constants/mainnet.rs +++ b/zcash_client_backend/src/constants/mainnet.rs @@ -3,6 +3,22 @@ /// [SLIP 44]: https://github.com/satoshilabs/slips/blob/master/slip-0044.md pub const COIN_TYPE: u32 = 133; +/// The HRP for a Bech32-encoded mainnet [`ExtendedSpendingKey`]. +/// +/// Defined in [ZIP 32]. +/// +/// [`ExtendedSpendingKey`]: zcash_primitives::zip32::ExtendedSpendingKey +/// [ZIP 32]: https://github.com/zcash/zips/blob/master/zip-0032.rst +pub const HRP_SAPLING_EXTENDED_SPENDING_KEY: &str = "secret-extended-key-main"; + +/// The HRP for a Bech32-encoded mainnet [`ExtendedFullViewingKey`]. +/// +/// Defined in [ZIP 32]. +/// +/// [`ExtendedFullViewingKey`]: zcash_primitives::zip32::ExtendedFullViewingKey +/// [ZIP 32]: https://github.com/zcash/zips/blob/master/zip-0032.rst +pub const HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY: &str = "zxviews"; + /// The HRP for a Bech32-encoded mainnet [`PaymentAddress`]. /// /// Defined in section 5.6.4 of the [Zcash Protocol Specification]. diff --git a/zcash_client_backend/src/constants/testnet.rs b/zcash_client_backend/src/constants/testnet.rs index f4ea3c2..f151110 100644 --- a/zcash_client_backend/src/constants/testnet.rs +++ b/zcash_client_backend/src/constants/testnet.rs @@ -3,6 +3,22 @@ /// [SLIP 44]: https://github.com/satoshilabs/slips/blob/master/slip-0044.md pub const COIN_TYPE: u32 = 1; +/// The HRP for a Bech32-encoded testnet [`ExtendedSpendingKey`]. +/// +/// Defined in [ZIP 32]. +/// +/// [`ExtendedSpendingKey`]: zcash_primitives::zip32::ExtendedSpendingKey +/// [ZIP 32]: https://github.com/zcash/zips/blob/master/zip-0032.rst +pub const HRP_SAPLING_EXTENDED_SPENDING_KEY: &str = "secret-extended-key-test"; + +/// The HRP for a Bech32-encoded testnet [`ExtendedFullViewingKey`]. +/// +/// Defined in [ZIP 32]. +/// +/// [`ExtendedFullViewingKey`]: zcash_primitives::zip32::ExtendedFullViewingKey +/// [ZIP 32]: https://github.com/zcash/zips/blob/master/zip-0032.rst +pub const HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY: &str = "zxviewtestsapling"; + /// The HRP for a Bech32-encoded testnet [`PaymentAddress`]. /// /// Defined in section 5.6.4 of the [Zcash Protocol Specification]. diff --git a/zcash_client_backend/src/encoding.rs b/zcash_client_backend/src/encoding.rs index 7150621..3a201ad 100644 --- a/zcash_client_backend/src/encoding.rs +++ b/zcash_client_backend/src/encoding.rs @@ -10,7 +10,10 @@ use sapling_crypto::{ primitives::{Diversifier, PaymentAddress}, }; use std::io::{self, Write}; -use zcash_primitives::JUBJUB; +use zcash_primitives::{ + zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}, + JUBJUB, +}; fn bech32_encode(hrp: &str, write: F) -> String where @@ -38,6 +41,60 @@ where } } +/// Writes an [`ExtendedSpendingKey`] as a Bech32-encoded string. +/// +/// # Examples +/// +/// ``` +/// use zcash_client_backend::{ +/// constants::testnet::{COIN_TYPE, HRP_SAPLING_EXTENDED_SPENDING_KEY}, +/// encoding::encode_extended_spending_key, +/// keys::spending_key, +/// }; +/// +/// let extsk = spending_key(&[0; 32][..], COIN_TYPE, 0); +/// let encoded = encode_extended_spending_key(HRP_SAPLING_EXTENDED_SPENDING_KEY, &extsk); +/// ``` +pub fn encode_extended_spending_key(hrp: &str, extsk: &ExtendedSpendingKey) -> String { + bech32_encode(hrp, |w| extsk.write(w)) +} + +/// Decodes an [`ExtendedSpendingKey`] from a Bech32-encoded string. +pub fn decode_extended_spending_key( + hrp: &str, + s: &str, +) -> Result, Error> { + bech32_decode(hrp, s, |data| ExtendedSpendingKey::read(&data[..]).ok()) +} + +/// Writes an [`ExtendedFullViewingKey`] as a Bech32-encoded string. +/// +/// # Examples +/// +/// ``` +/// use zcash_client_backend::{ +/// constants::testnet::{COIN_TYPE, HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY}, +/// encoding::encode_extended_full_viewing_key, +/// keys::spending_key, +/// }; +/// use zcash_primitives::zip32::ExtendedFullViewingKey; +/// +/// let extsk = spending_key(&[0; 32][..], COIN_TYPE, 0); +/// let extfvk = ExtendedFullViewingKey::from(&extsk); +/// let encoded = encode_extended_full_viewing_key(HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, &extfvk); +/// ``` +pub fn encode_extended_full_viewing_key(hrp: &str, extfvk: &ExtendedFullViewingKey) -> String { + bech32_encode(hrp, |w| extfvk.write(w)) +} + +/// Decodes an [`ExtendedFullViewingKey`] from a Bech32-encoded string. +pub fn decode_extended_full_viewing_key( + hrp: &str, + s: &str, +) -> Result, Error> { + bech32_decode(hrp, s, |data| ExtendedFullViewingKey::read(&data[..]).ok()) +} + /// Writes a [`PaymentAddress`] as a Bech32-encoded string. /// /// # Examples From a3a9ee26825265e15d6c7c061dff3c8c1ceeff7b Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 2 Jul 2019 00:07:48 +0100 Subject: [PATCH 007/330] Validate PaymentAddress diversifier when decoding --- zcash_client_backend/src/encoding.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/zcash_client_backend/src/encoding.rs b/zcash_client_backend/src/encoding.rs index 3a201ad..17ef335 100644 --- a/zcash_client_backend/src/encoding.rs +++ b/zcash_client_backend/src/encoding.rs @@ -167,6 +167,11 @@ pub fn decode_payment_address(hrp: &str, s: &str) -> Result(&JUBJUB).is_none() { + return None; + } + edwards::Point::::read(&data[11..], &JUBJUB) .ok()? .as_prime_order(&JUBJUB) @@ -227,4 +232,26 @@ mod tests { Some(addr) ); } + + #[test] + fn invalid_diversifier() { + let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + + let addr = PaymentAddress { + diversifier: Diversifier([1u8; 11]), + pk_d: edwards::Point::::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB), + }; + + let encoded_main = + encode_payment_address(constants::mainnet::HRP_SAPLING_PAYMENT_ADDRESS, &addr); + + assert_eq!( + decode_payment_address( + constants::mainnet::HRP_SAPLING_PAYMENT_ADDRESS, + &encoded_main + ) + .unwrap(), + None + ); + } } From 999dcbfcab0171678824f775bdfad87d7592cea0 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 4 Jun 2019 13:15:12 +0100 Subject: [PATCH 008/330] Migrate to blake2b_simd and blake2s_simd crates The primary reason for migrating is that these crates provide APIs for setting the personalisation string. This enables us to depend solely on published crates, and thus publish our own crates. The SIMD implementations are ported from libsodium. Closes #67. --- Cargo.lock | 43 ++++++--- librustzcash/Cargo.toml | 6 +- librustzcash/src/equihash.rs | 15 +-- librustzcash/src/rustzcash.rs | 10 +- sapling-crypto/Cargo.toml | 6 +- sapling-crypto/src/circuit/blake2s.rs | 4 +- sapling-crypto/src/circuit/test/mod.rs | 6 +- sapling-crypto/src/group_hash.rs | 16 ++-- sapling-crypto/src/lib.rs | 3 +- sapling-crypto/src/primitives/mod.rs | 21 ++-- sapling-crypto/src/util.rs | 4 +- zcash_primitives/Cargo.toml | 5 +- zcash_primitives/src/keys.rs | 13 ++- zcash_primitives/src/lib.rs | 2 +- zcash_primitives/src/note_encryption.rs | 20 ++-- zcash_primitives/src/transaction/sighash.rs | 100 +++++++++++--------- zcash_primitives/src/zip32.rs | 14 ++- zcash_proofs/Cargo.toml | 5 +- zcash_proofs/src/hashreader.rs | 6 +- zcash_proofs/src/lib.rs | 2 +- 20 files changed, 172 insertions(+), 129 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34b20d2..ab8b628 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,9 +30,14 @@ dependencies = [ "stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "arrayref" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "arrayvec" -version = "0.4.7" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -70,12 +75,22 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "blake2-rfc" -version = "0.2.18" -source = "git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9#7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" +name = "blake2b_simd" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "blake2s_simd" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -292,7 +307,8 @@ name = "librustzcash" version = "0.1.0" dependencies = [ "bellman 0.1.0", - "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", + "blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2s_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -435,7 +451,8 @@ name = "sapling-crypto" version = "0.0.1" dependencies = [ "bellman 0.1.0", - "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", + "blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2s_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", @@ -529,7 +546,7 @@ name = "zcash_primitives" version = "0.0.0" dependencies = [ "aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", + "blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto_api_chachapoly 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", @@ -547,7 +564,7 @@ name = "zcash_proofs" version = "0.0.0" dependencies = [ "bellman 0.1.0", - "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", + "blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "pairing 0.14.2", @@ -559,11 +576,13 @@ dependencies = [ "checksum aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6fb1737cdc8da3db76e90ca817a194249a38fcb500c2e6ecec39b29448aa873" "checksum aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67cc03b0a090a05cb01e96998a01905d7ceedce1bc23b756c0bb7faa0682ccb1" "checksum aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6810b7fb9f2bb4f76f05ac1c170b8dde285b6308955dc3afd89710268c958d9e" -"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" +"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum bech32 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58946044516aa9dc922182e0d6e9d124a31aafe6b421614654eb27cf90cec09c" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" -"checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)" = "" +"checksum blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d909f9ef55928e57e7de9638828bc9407233b5cb0904066a7edebbaa9946db2f" +"checksum blake2s_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fa20660ff9f1e6d0a05444b5ebbbae13e4c018d4c66cc78c7e421e3396358a52" "checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" "checksum block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "370424437b9459f3dfd68428ed9376ddfe03d8b70ede29cc533b3557df186ab4" "checksum block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc4358306e344bf9775d0197fd00d2603e5afb0771bb353538630f022068ea3" diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index 3edc928..e75a71c 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -15,6 +15,8 @@ crate-type = ["staticlib"] [dependencies] bellman = { path = "../bellman" } +blake2b_simd = "0.5" +blake2s_simd = "0.5" ff = { path = "../ff" } libc = "0.2" pairing = { path = "../pairing" } @@ -24,7 +26,3 @@ rand = "0.4" sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } zcash_proofs = { path = "../zcash_proofs" } - -[dependencies.blake2-rfc] -git = "https://github.com/gtank/blake2-rfc" -rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" diff --git a/librustzcash/src/equihash.rs b/librustzcash/src/equihash.rs index da2693b..d251bc1 100644 --- a/librustzcash/src/equihash.rs +++ b/librustzcash/src/equihash.rs @@ -1,4 +1,4 @@ -use blake2_rfc::blake2b::{Blake2b, Blake2bResult}; +use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams, State as Blake2bState}; use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; use std::io::Cursor; use std::mem::size_of; @@ -33,7 +33,7 @@ impl Params { } impl Node { - fn new(p: &Params, state: &Blake2b, i: u32) -> Self { + fn new(p: &Params, state: &Blake2bState, i: u32) -> Self { let hash = generate_hash(state, i / p.indices_per_hash_output()); let start = ((i % p.indices_per_hash_output()) * p.n / 8) as usize; let end = start + (p.n as usize) / 8; @@ -99,15 +99,18 @@ impl Node { } } -fn initialise_state(n: u32, k: u32, digest_len: u8) -> Blake2b { +fn initialise_state(n: u32, k: u32, digest_len: u8) -> Blake2bState { let mut personalization: Vec = Vec::from("ZcashPoW"); personalization.write_u32::(n).unwrap(); personalization.write_u32::(k).unwrap(); - Blake2b::with_params(digest_len as usize, &[], &[], &personalization) + Blake2bParams::new() + .hash_length(digest_len as usize) + .personal(&personalization) + .to_state() } -fn generate_hash(base_state: &Blake2b, i: u32) -> Blake2bResult { +fn generate_hash(base_state: &Blake2bState, i: u32) -> Blake2bHash { let mut lei = [0u8; 4]; (&mut lei[..]).write_u32::(i).unwrap(); @@ -249,7 +252,7 @@ pub fn is_valid_solution_iterative( return rows[0].is_zero(hash_len); } -fn tree_validator(p: &Params, state: &Blake2b, indices: &[u32]) -> Option { +fn tree_validator(p: &Params, state: &Blake2bState, indices: &[u32]) -> Option { if indices.len() > 1 { let end = indices.len(); let mid = end / 2; diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index fb72827..51a980e 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -1,5 +1,6 @@ extern crate bellman; -extern crate blake2_rfc; +extern crate blake2b_simd; +extern crate blake2s_simd; extern crate byteorder; extern crate ff; extern crate libc; @@ -33,7 +34,7 @@ use bellman::groth16::{ create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof, }; -use blake2_rfc::blake2s::Blake2s; +use blake2s_simd::Params as Blake2sParams; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; @@ -336,7 +337,10 @@ pub extern "system" fn librustzcash_crh_ivk( let ak = unsafe { &*ak }; let nk = unsafe { &*nk }; - let mut h = Blake2s::with_params(32, &[], &[], CRH_IVK_PERSONALIZATION); + let mut h = Blake2sParams::new() + .hash_length(32) + .personal(CRH_IVK_PERSONALIZATION) + .to_state(); h.update(ak); h.update(nk); let mut h = h.finalize().as_ref().to_vec(); diff --git a/sapling-crypto/Cargo.toml b/sapling-crypto/Cargo.toml index d985219..7d43774 100644 --- a/sapling-crypto/Cargo.toml +++ b/sapling-crypto/Cargo.toml @@ -14,15 +14,13 @@ features = ["expose-arith"] [dependencies] bellman = { path = "../bellman" } +blake2b_simd = "0.5" +blake2s_simd = "0.5" ff = { path = "../ff" } rand = "0.4" digest = "0.7" byteorder = "1" -[dependencies.blake2-rfc] -git = "https://github.com/gtank/blake2-rfc" -rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" - [dev-dependencies] hex-literal = "0.1" rust-crypto = "0.2" diff --git a/sapling-crypto/src/circuit/blake2s.rs b/sapling-crypto/src/circuit/blake2s.rs index 93af806..46bbe67 100644 --- a/sapling-crypto/src/circuit/blake2s.rs +++ b/sapling-crypto/src/circuit/blake2s.rs @@ -320,13 +320,13 @@ pub fn blake2s>( #[cfg(test)] mod test { + use blake2s_simd::Params as Blake2sParams; use rand::{XorShiftRng, SeedableRng, Rng}; use pairing::bls12_381::{Bls12}; use ::circuit::boolean::{Boolean, AllocatedBit}; use ::circuit::test::TestConstraintSystem; use super::blake2s; use bellman::{ConstraintSystem}; - use blake2_rfc::blake2s::Blake2s; #[test] fn test_blank_hash() { @@ -392,7 +392,7 @@ mod test { for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) { - let mut h = Blake2s::with_params(32, &[], &[], b"12345678"); + let mut h = Blake2sParams::new().hash_length(32).personal(b"12345678").to_state(); let data: Vec = (0..input_len).map(|_| rng.gen()).collect(); diff --git a/sapling-crypto/src/circuit/test/mod.rs b/sapling-crypto/src/circuit/test/mod.rs index 18a77ba..79d128a 100644 --- a/sapling-crypto/src/circuit/test/mod.rs +++ b/sapling-crypto/src/circuit/test/mod.rs @@ -16,7 +16,7 @@ use byteorder::{BigEndian, ByteOrder}; use std::cmp::Ordering; use std::collections::BTreeMap; -use blake2_rfc::blake2s::Blake2s; +use blake2s_simd::{Params as Blake2sParams, State as Blake2sState}; #[derive(Debug)] enum NamedObject { @@ -96,7 +96,7 @@ fn proc_lc( fn hash_lc( terms: &[(Variable, E::Fr)], - h: &mut Blake2s + h: &mut Blake2sState ) { let map = proc_lc::(terms); @@ -226,7 +226,7 @@ impl TestConstraintSystem { } pub fn hash(&self) -> String { - let mut h = Blake2s::new(32); + let mut h = Blake2sParams::new().hash_length(32).to_state(); { let mut buf = [0u8; 24]; diff --git a/sapling-crypto/src/group_hash.rs b/sapling-crypto/src/group_hash.rs index 43e87e8..7369e04 100644 --- a/sapling-crypto/src/group_hash.rs +++ b/sapling-crypto/src/group_hash.rs @@ -8,7 +8,7 @@ use ff::{ PrimeField }; -use blake2_rfc::blake2s::Blake2s; +use blake2s_simd::Params; use constants; /// Produces a random point in the Jubjub curve. @@ -25,13 +25,15 @@ pub fn group_hash( // Check to see that scalar field is 255 bits assert!(E::Fr::NUM_BITS == 255); - let mut h = Blake2s::with_params(32, &[], &[], personalization); - h.update(constants::GH_FIRST_BLOCK); - h.update(tag); - let h = h.finalize().as_ref().to_vec(); - assert!(h.len() == 32); + let h = Params::new() + .hash_length(32) + .personal(personalization) + .to_state() + .update(constants::GH_FIRST_BLOCK) + .update(tag) + .finalize(); - match edwards::Point::::read(&h[..], params) { + match edwards::Point::::read(h.as_ref(), params) { Ok(p) => { let p = p.mul_by_cofactor(params); diff --git a/sapling-crypto/src/lib.rs b/sapling-crypto/src/lib.rs index ae37573..0535d9a 100644 --- a/sapling-crypto/src/lib.rs +++ b/sapling-crypto/src/lib.rs @@ -1,6 +1,7 @@ extern crate pairing; extern crate bellman; -extern crate blake2_rfc; +extern crate blake2b_simd; +extern crate blake2s_simd; extern crate digest; extern crate ff; extern crate rand; diff --git a/sapling-crypto/src/primitives/mod.rs b/sapling-crypto/src/primitives/mod.rs index fea332c..4026392 100644 --- a/sapling-crypto/src/primitives/mod.rs +++ b/sapling-crypto/src/primitives/mod.rs @@ -22,7 +22,7 @@ use jubjub::{ FixedGenerators }; -use blake2_rfc::blake2s::Blake2s; +use blake2s_simd::Params as Blake2sParams; #[derive(Clone)] pub struct ValueCommitment { @@ -87,9 +87,12 @@ impl ViewingKey { self.ak.write(&mut preimage[0..32]).unwrap(); self.nk.write(&mut preimage[32..64]).unwrap(); - let mut h = Blake2s::with_params(32, &[], &[], constants::CRH_IVK_PERSONALIZATION); - h.update(&preimage); - let mut h = h.finalize().as_ref().to_vec(); + let mut h = [0; 32]; + h.copy_from_slice(Blake2sParams::new() + .hash_length(32) + .personal(constants::CRH_IVK_PERSONALIZATION) + .hash(&preimage) + .as_bytes()); // Drop the most significant five bits, so it can be interpreted as a scalar. h[31] &= 0b0000_0111; @@ -255,10 +258,12 @@ impl Note { let mut nf_preimage = [0u8; 64]; viewing_key.nk.write(&mut nf_preimage[0..32]).unwrap(); rho.write(&mut nf_preimage[32..64]).unwrap(); - let mut h = Blake2s::with_params(32, &[], &[], constants::PRF_NF_PERSONALIZATION); - h.update(&nf_preimage); - - h.finalize().as_ref().to_vec() + Blake2sParams::new() + .hash_length(32) + .personal(constants::PRF_NF_PERSONALIZATION) + .hash(&nf_preimage) + .as_bytes() + .to_vec() } /// Computes the note commitment diff --git a/sapling-crypto/src/util.rs b/sapling-crypto/src/util.rs index e67e660..1e759ba 100644 --- a/sapling-crypto/src/util.rs +++ b/sapling-crypto/src/util.rs @@ -1,9 +1,9 @@ -use blake2_rfc::blake2b::Blake2b; +use blake2b_simd::Params; use jubjub::{JubjubEngine, ToUniform}; pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> E::Fs { - let mut hasher = Blake2b::with_params(64, &[], &[], persona); + let mut hasher = Params::new().hash_length(64).personal(persona).to_state(); hasher.update(a); hasher.update(b); let ret = hasher.finalize(); diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index 06a117b..771f351 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -7,6 +7,7 @@ authors = [ [dependencies] aes = "0.2" +blake2b_simd = "0.5" byteorder = "1" crypto_api_chachapoly = "0.1" ff = { path = "../ff" } @@ -17,7 +18,3 @@ pairing = { path = "../pairing" } rand = "0.4" sapling-crypto = { path = "../sapling-crypto" } sha2 = "0.8" - -[dependencies.blake2-rfc] -git = "https://github.com/gtank/blake2-rfc" -rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" diff --git a/zcash_primitives/src/keys.rs b/zcash_primitives/src/keys.rs index e6066e3..fca31ed 100644 --- a/zcash_primitives/src/keys.rs +++ b/zcash_primitives/src/keys.rs @@ -2,7 +2,7 @@ //! //! Implements section 4.2.2 of the Zcash Protocol Specification. -use blake2_rfc::blake2b::{Blake2b, Blake2bResult}; +use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; use ff::{PrimeField, PrimeFieldRepr}; use sapling_crypto::{ jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, ToUniform, Unknown}, @@ -13,12 +13,15 @@ use std::io::{self, Read, Write}; pub const PRF_EXPAND_PERSONALIZATION: &'static [u8; 16] = b"Zcash_ExpandSeed"; /// PRF^expand(sk, t) := BLAKE2b-512("Zcash_ExpandSeed", sk || t) -pub fn prf_expand(sk: &[u8], t: &[u8]) -> Blake2bResult { - prf_expand_vec(sk, &[t]) +pub fn prf_expand(sk: &[u8], t: &[u8]) -> Blake2bHash { + prf_expand_vec(sk, &vec![t]) } -pub fn prf_expand_vec(sk: &[u8], ts: &[&[u8]]) -> Blake2bResult { - let mut h = Blake2b::with_params(64, &[], &[], PRF_EXPAND_PERSONALIZATION); +pub fn prf_expand_vec(sk: &[u8], ts: &[&[u8]]) -> Blake2bHash { + let mut h = Blake2bParams::new() + .hash_length(64) + .personal(PRF_EXPAND_PERSONALIZATION) + .to_state(); h.update(sk); for t in ts { h.update(t); diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 962811e..eb33461 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -2,7 +2,7 @@ extern crate lazy_static; extern crate aes; -extern crate blake2_rfc; +extern crate blake2b_simd; extern crate byteorder; extern crate crypto_api_chachapoly; extern crate ff; diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 3d1c55b..610b746 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -1,6 +1,6 @@ //! Implementation of in-band secret distribution for Zcash transactions. -use blake2_rfc::blake2b::{Blake2b, Blake2bResult}; +use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf}; use ff::{PrimeField, PrimeFieldRepr}; @@ -168,14 +168,15 @@ where fn kdf_sapling( dhsecret: edwards::Point, epk: &edwards::Point, -) -> Blake2bResult { +) -> Blake2bHash { let mut input = [0u8; 64]; dhsecret.write(&mut input[0..32]).unwrap(); epk.write(&mut input[32..64]).unwrap(); - let mut h = Blake2b::with_params(32, &[], &[], KDF_SAPLING_PERSONALIZATION); - h.update(&input); - h.finalize() + Blake2bParams::new() + .hash_length(32) + .personal(KDF_SAPLING_PERSONALIZATION) + .hash(&input) } /// Sapling PRF^ock. @@ -186,16 +187,17 @@ fn prf_ock( cv: &edwards::Point, cmu: &Fr, epk: &edwards::Point, -) -> Blake2bResult { +) -> Blake2bHash { let mut ock_input = [0u8; 128]; ock_input[0..32].copy_from_slice(&ovk.0); cv.write(&mut ock_input[32..64]).unwrap(); cmu.into_repr().write_le(&mut ock_input[64..96]).unwrap(); epk.write(&mut ock_input[96..128]).unwrap(); - let mut h = Blake2b::with_params(32, &[], &[], PRF_OCK_PERSONALIZATION); - h.update(&ock_input); - h.finalize() + Blake2bParams::new() + .hash_length(32) + .personal(PRF_OCK_PERSONALIZATION) + .hash(&ock_input) } /// An API for encrypting Sapling notes. diff --git a/zcash_primitives/src/transaction/sighash.rs b/zcash_primitives/src/transaction/sighash.rs index 85302ee..774e7b4 100644 --- a/zcash_primitives/src/transaction/sighash.rs +++ b/zcash_primitives/src/transaction/sighash.rs @@ -1,4 +1,4 @@ -use blake2_rfc::blake2b::Blake2b; +use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; use byteorder::{LittleEndian, WriteBytesExt}; use ff::{PrimeField, PrimeFieldRepr}; @@ -39,7 +39,7 @@ macro_rules! update_i64 { macro_rules! update_hash { ($h:expr, $cond:expr, $value:expr) => { if $cond { - $h.update(&$value); + $h.update(&$value.as_ref()); } else { $h.update(&[0; 32]); } @@ -67,47 +67,51 @@ impl SigHashVersion { } } -fn prevout_hash(tx: &TransactionData) -> Vec { +fn prevout_hash(tx: &TransactionData) -> Blake2bHash { let mut data = Vec::with_capacity(tx.vin.len() * 36); for t_in in &tx.vin { t_in.prevout.write(&mut data).unwrap(); } - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_PREVOUTS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() + Blake2bParams::new() + .hash_length(32) + .personal(ZCASH_PREVOUTS_HASH_PERSONALIZATION) + .hash(&data) } -fn sequence_hash(tx: &TransactionData) -> Vec { +fn sequence_hash(tx: &TransactionData) -> Blake2bHash { let mut data = Vec::with_capacity(tx.vin.len() * 4); for t_in in &tx.vin { (&mut data) .write_u32::(t_in.sequence) .unwrap(); } - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SEQUENCE_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() + Blake2bParams::new() + .hash_length(32) + .personal(ZCASH_SEQUENCE_HASH_PERSONALIZATION) + .hash(&data) } -fn outputs_hash(tx: &TransactionData) -> Vec { +fn outputs_hash(tx: &TransactionData) -> Blake2bHash { let mut data = Vec::with_capacity(tx.vout.len() * (4 + 1)); for t_out in &tx.vout { t_out.write(&mut data).unwrap(); } - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_OUTPUTS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() + Blake2bParams::new() + .hash_length(32) + .personal(ZCASH_OUTPUTS_HASH_PERSONALIZATION) + .hash(&data) } -fn single_output_hash(tx_out: &TxOut) -> Vec { +fn single_output_hash(tx_out: &TxOut) -> Blake2bHash { let mut data = vec![]; tx_out.write(&mut data).unwrap(); - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_OUTPUTS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() + Blake2bParams::new() + .hash_length(32) + .personal(ZCASH_OUTPUTS_HASH_PERSONALIZATION) + .hash(&data) } -fn joinsplits_hash(tx: &TransactionData) -> Vec { +fn joinsplits_hash(tx: &TransactionData) -> Blake2bHash { let mut data = Vec::with_capacity( tx.joinsplits.len() * if tx.version < SAPLING_TX_VERSION { @@ -120,12 +124,13 @@ fn joinsplits_hash(tx: &TransactionData) -> Vec { js.write(&mut data).unwrap(); } data.extend_from_slice(&tx.joinsplit_pubkey.unwrap()); - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_JOINSPLITS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() + Blake2bParams::new() + .hash_length(32) + .personal(ZCASH_JOINSPLITS_HASH_PERSONALIZATION) + .hash(&data) } -fn shielded_spends_hash(tx: &TransactionData) -> Vec { +fn shielded_spends_hash(tx: &TransactionData) -> Blake2bHash { let mut data = Vec::with_capacity(tx.shielded_spends.len() * 384); for s_spend in &tx.shielded_spends { s_spend.cv.write(&mut data).unwrap(); @@ -134,19 +139,21 @@ fn shielded_spends_hash(tx: &TransactionData) -> Vec { s_spend.rk.write(&mut data).unwrap(); data.extend_from_slice(&s_spend.zkproof); } - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() + Blake2bParams::new() + .hash_length(32) + .personal(ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION) + .hash(&data) } -fn shielded_outputs_hash(tx: &TransactionData) -> Vec { +fn shielded_outputs_hash(tx: &TransactionData) -> Blake2bHash { let mut data = Vec::with_capacity(tx.shielded_outputs.len() * 948); for s_out in &tx.shielded_outputs { s_out.write(&mut data).unwrap(); } - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() + Blake2bParams::new() + .hash_length(32) + .personal(ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION) + .hash(&data) } pub fn signature_hash_data( @@ -158,26 +165,16 @@ pub fn signature_hash_data( let sigversion = SigHashVersion::from_tx(tx); match sigversion { SigHashVersion::Overwinter | SigHashVersion::Sapling => { - let hash_outputs = if (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE - && (hash_type & SIGHASH_MASK) != SIGHASH_NONE - { - outputs_hash(tx) - } else if (hash_type & SIGHASH_MASK) == SIGHASH_SINGLE - && transparent_input.is_some() - && transparent_input.as_ref().unwrap().0 < tx.vout.len() - { - single_output_hash(&tx.vout[transparent_input.as_ref().unwrap().0]) - } else { - vec![0; 32] - }; - let mut personal = [0; 16]; (&mut personal[..12]).copy_from_slice(ZCASH_SIGHASH_PERSONALIZATION_PREFIX); (&mut personal[12..]) .write_u32::(consensus_branch_id) .unwrap(); - let mut h = Blake2b::with_params(32, &[], &[], &personal); + let mut h = Blake2bParams::new() + .hash_length(32) + .personal(&personal) + .to_state(); let mut tmp = [0; 8]; update_u32!(h, tx.header(), tmp); @@ -190,7 +187,20 @@ pub fn signature_hash_data( && (hash_type & SIGHASH_MASK) != SIGHASH_NONE, sequence_hash(tx) ); - h.update(&hash_outputs); + if (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE + && (hash_type & SIGHASH_MASK) != SIGHASH_NONE + { + h.update(outputs_hash(tx).as_ref()); + } else if (hash_type & SIGHASH_MASK) == SIGHASH_SINGLE + && transparent_input.is_some() + && transparent_input.as_ref().unwrap().0 < tx.vout.len() + { + h.update( + single_output_hash(&tx.vout[transparent_input.as_ref().unwrap().0]).as_ref(), + ); + } else { + h.update(&[0; 32]); + }; update_hash!(h, !tx.joinsplits.is_empty(), joinsplits_hash(tx)); if sigversion == SigHashVersion::Sapling { update_hash!(h, !tx.shielded_spends.is_empty(), shielded_spends_hash(tx)); diff --git a/zcash_primitives/src/zip32.rs b/zcash_primitives/src/zip32.rs index db5adcd..a34ae18 100644 --- a/zcash_primitives/src/zip32.rs +++ b/zcash_primitives/src/zip32.rs @@ -1,5 +1,5 @@ use aes::Aes256; -use blake2_rfc::blake2b::Blake2b; +use blake2b_simd::Params as Blake2bParams; use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt}; use ff::Field; use fpe::ff1::{BinaryNumeralString, FF1}; @@ -33,7 +33,10 @@ struct FVKFingerprint([u8; 32]); impl From<&FullViewingKey> for FVKFingerprint { fn from(fvk: &FullViewingKey) -> Self { - let mut h = Blake2b::with_params(32, &[], &[], ZIP32_SAPLING_FVFP_PERSONALIZATION); + let mut h = Blake2bParams::new() + .hash_length(32) + .personal(ZIP32_SAPLING_FVFP_PERSONALIZATION) + .to_state(); h.update(&fvk.to_bytes()); let mut fvfp = [0u8; 32]; fvfp.copy_from_slice(h.finalize().as_bytes()); @@ -225,9 +228,10 @@ impl std::fmt::Debug for ExtendedFullViewingKey { impl ExtendedSpendingKey { pub fn master(seed: &[u8]) -> Self { - let mut h = Blake2b::with_params(64, &[], &[], ZIP32_SAPLING_MASTER_PERSONALIZATION); - h.update(seed); - let i = h.finalize(); + let i = Blake2bParams::new() + .hash_length(64) + .personal(ZIP32_SAPLING_MASTER_PERSONALIZATION) + .hash(seed); let sk_m = &i.as_bytes()[..32]; let mut c_m = [0u8; 32]; diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index 5bcdb26..2139749 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -7,12 +7,9 @@ authors = [ [dependencies] bellman = { path = "../bellman" } +blake2b_simd = "0.5" byteorder = "1" ff = { path = "../ff" } pairing = { path = "../pairing" } rand = "0.4" sapling-crypto = { path = "../sapling-crypto" } - -[dependencies.blake2-rfc] -git = "https://github.com/gtank/blake2-rfc" -rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" diff --git a/zcash_proofs/src/hashreader.rs b/zcash_proofs/src/hashreader.rs index a422d52..dbe686f 100644 --- a/zcash_proofs/src/hashreader.rs +++ b/zcash_proofs/src/hashreader.rs @@ -1,10 +1,10 @@ -use blake2_rfc::blake2b::Blake2b; +use blake2b_simd::State; use std::io::{self, Read}; /// Abstraction over a reader which hashes the data being read. pub struct HashReader { reader: R, - hasher: Blake2b, + hasher: State, } impl HashReader { @@ -12,7 +12,7 @@ impl HashReader { pub fn new(reader: R) -> Self { HashReader { reader: reader, - hasher: Blake2b::new(64), + hasher: State::new(), } } diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs index ca17a8b..d061818 100644 --- a/zcash_proofs/src/lib.rs +++ b/zcash_proofs/src/lib.rs @@ -1,5 +1,5 @@ extern crate bellman; -extern crate blake2_rfc; +extern crate blake2b_simd; extern crate byteorder; extern crate ff; extern crate pairing; From d1ce6749fe4147b60e6c14e509925933d773f010 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 10 Jul 2019 13:12:26 -0400 Subject: [PATCH 009/330] Bump minimum Rust version to 1.36 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a773623..9ddae8a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: rust rust: - - 1.32.0 + - 1.36.0 cache: cargo From 785f22ca5a49f595d4f82416899fe957ae002ffb Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 3 Oct 2018 13:18:39 +0100 Subject: [PATCH 010/330] Move Sapling commitment tree hash into zcash_primitives --- librustzcash/src/rustzcash.rs | 32 +++++++--------------------- zcash_primitives/src/sapling.rs | 37 ++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index fb72827..20af7ed 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -11,7 +11,7 @@ extern crate zcash_proofs; extern crate lazy_static; -use ff::{BitIterator, PrimeField, PrimeFieldRepr}; +use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use sapling_crypto::{ @@ -22,7 +22,6 @@ use sapling_crypto::{ fs::{Fs, FsRepr}, FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder, ToUniform, Unknown, }, - pedersen_hash::{pedersen_hash, Personalization}, redjubjub::{self, Signature}, }; @@ -57,7 +56,11 @@ use std::ffi::OsString; use std::os::windows::ffi::OsStringExt; use sapling_crypto::primitives::{ProofGenerationKey, ViewingKey}; -use zcash_primitives::{note_encryption::sapling_ka_agree, sapling::spend_sig, zip32, JUBJUB}; +use zcash_primitives::{ + note_encryption::sapling_ka_agree, + sapling::{merkle_hash, spend_sig}, + zip32, JUBJUB, +}; use zcash_proofs::{ load_parameters, sapling::{CommitmentTreeWitness, SaplingProvingContext, SaplingVerificationContext}, @@ -254,28 +257,7 @@ pub extern "system" fn librustzcash_merkle_hash( // size of the representation let b_repr = read_le(unsafe { &(&*b)[..] }); - let mut lhs = [false; 256]; - let mut rhs = [false; 256]; - - for (a, b) in lhs.iter_mut().rev().zip(BitIterator::new(a_repr)) { - *a = b; - } - - for (a, b) in rhs.iter_mut().rev().zip(BitIterator::new(b_repr)) { - *a = b; - } - - let tmp = pedersen_hash::( - Personalization::MerkleTree(depth), - lhs.iter() - .map(|&x| x) - .take(Fr::NUM_BITS as usize) - .chain(rhs.iter().map(|&x| x).take(Fr::NUM_BITS as usize)), - &JUBJUB, - ) - .into_xy() - .0 - .into_repr(); + let tmp = merkle_hash(depth, &a_repr, &b_repr); // Should be okay, caller is responsible for ensuring the pointer // is a valid pointer to 32 bytes that can be mutated. diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index b59dc2b..62f5118 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -1,10 +1,45 @@ -use pairing::bls12_381::Bls12; +use ff::{BitIterator, PrimeField}; +use pairing::bls12_381::{Bls12, Fr, FrRepr}; use rand::OsRng; use sapling_crypto::{ jubjub::{fs::Fs, FixedGenerators, JubjubBls12}, + pedersen_hash::{pedersen_hash, Personalization}, redjubjub::{PrivateKey, PublicKey, Signature}, }; +use JUBJUB; + +/// Compute a parent node in the Sapling commitment tree given its two children. +pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr { + let lhs = { + let mut tmp = [false; 256]; + for (a, b) in tmp.iter_mut().rev().zip(BitIterator::new(lhs)) { + *a = b; + } + tmp + }; + + let rhs = { + let mut tmp = [false; 256]; + for (a, b) in tmp.iter_mut().rev().zip(BitIterator::new(rhs)) { + *a = b; + } + tmp + }; + + pedersen_hash::( + Personalization::MerkleTree(depth), + lhs.iter() + .map(|&x| x) + .take(Fr::NUM_BITS as usize) + .chain(rhs.iter().map(|&x| x).take(Fr::NUM_BITS as usize)), + &JUBJUB, + ) + .into_xy() + .0 + .into_repr() +} + /// Create the spendAuthSig for a Sapling SpendDescription. pub fn spend_sig( ask: PrivateKey, From 8f3f95ee0830a2d17d20106ae6ee2e89eb3bb4d8 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 3 Oct 2018 20:09:17 +0100 Subject: [PATCH 011/330] Sapling commitment tree empty roots --- zcash_primitives/src/lib.rs | 1 + zcash_primitives/src/merkle_tree.rs | 113 ++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 zcash_primitives/src/merkle_tree.rs diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 962811e..07d2385 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -17,6 +17,7 @@ use sapling_crypto::jubjub::JubjubBls12; pub mod block; pub mod keys; +pub mod merkle_tree; pub mod note_encryption; pub mod sapling; mod serialize; diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs new file mode 100644 index 0000000..cb74ea1 --- /dev/null +++ b/zcash_primitives/src/merkle_tree.rs @@ -0,0 +1,113 @@ +use ff::PrimeField; +use pairing::bls12_381::{Bls12, Fr, FrRepr}; +use sapling_crypto::primitives::Note; + +use sapling::merkle_hash; + +const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32; + +trait Hashable: Clone + Copy { + /// Returns the parent node within the tree of the two given nodes. + fn combine(usize, &Self, &Self) -> Self; + + /// Returns a blank leaf node. + fn blank() -> Self; +} + +#[derive(Clone, Copy)] +pub struct Node { + repr: FrRepr, +} + +impl Node { + pub fn new(repr: FrRepr) -> Self { + Node { repr } + } +} + +impl Hashable for Node { + fn combine(depth: usize, lhs: &Self, rhs: &Self) -> Self { + Node { + repr: merkle_hash(depth, &lhs.repr, &rhs.repr), + } + } + + fn blank() -> Self { + Node { + repr: Note::::uncommitted().into_repr(), + } + } +} + +impl From for Fr { + fn from(node: Node) -> Self { + Fr::from_repr(node.repr).expect("Tree nodes should be in the prime field") + } +} + +lazy_static! { + static ref EMPTY_ROOTS: Vec = { + let mut v = vec![Node::blank()]; + for d in 0..SAPLING_COMMITMENT_TREE_DEPTH { + let next = Node::combine(d, &v[d], &v[d]); + v.push(next); + } + v + }; +} + +#[cfg(test)] +mod tests { + use super::EMPTY_ROOTS; + + use ff::PrimeFieldRepr; + use hex; + + const HEX_EMPTY_ROOTS: [&str; 33] = [ + "0100000000000000000000000000000000000000000000000000000000000000", + "817de36ab2d57feb077634bca77819c8e0bd298c04f6fed0e6a83cc1356ca155", + "ffe9fc03f18b176c998806439ff0bb8ad193afdb27b2ccbc88856916dd804e34", + "d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c", + "e110de65c907b9dea4ae0bd83a4b0a51bea175646a64c12b4c9f931b2cb31b49", + "912d82b2c2bca231f71efcf61737fbf0a08befa0416215aeef53e8bb6d23390a", + "8ac9cf9c391e3fd42891d27238a81a8a5c1d3a72b1bcbea8cf44a58ce7389613", + "d6c639ac24b46bd19341c91b13fdcab31581ddaf7f1411336a271f3d0aa52813", + "7b99abdc3730991cc9274727d7d82d28cb794edbc7034b4f0053ff7c4b680444", + "43ff5457f13b926b61df552d4e402ee6dc1463f99a535f9a713439264d5b616b", + "ba49b659fbd0b7334211ea6a9d9df185c757e70aa81da562fb912b84f49bce72", + "4777c8776a3b1e69b73a62fa701fa4f7a6282d9aee2c7a6b82e7937d7081c23c", + "ec677114c27206f5debc1c1ed66f95e2b1885da5b7be3d736b1de98579473048", + "1b77dac4d24fb7258c3c528704c59430b630718bec486421837021cf75dab651", + "bd74b25aacb92378a871bf27d225cfc26baca344a1ea35fdd94510f3d157082c", + "d6acdedf95f608e09fa53fb43dcd0990475726c5131210c9e5caeab97f0e642f", + "1ea6675f9551eeb9dfaaa9247bc9858270d3d3a4c5afa7177a984d5ed1be2451", + "6edb16d01907b759977d7650dad7e3ec049af1a3d875380b697c862c9ec5d51c", + "cd1c8dbf6e3acc7a80439bc4962cf25b9dce7c896f3a5bd70803fc5a0e33cf00", + "6aca8448d8263e547d5ff2950e2ed3839e998d31cbc6ac9fd57bc6002b159216", + "8d5fa43e5a10d11605ac7430ba1f5d81fb1b68d29a640405767749e841527673", + "08eeab0c13abd6069e6310197bf80f9c1ea6de78fd19cbae24d4a520e6cf3023", + "0769557bc682b1bf308646fd0b22e648e8b9e98f57e29f5af40f6edb833e2c49", + "4c6937d78f42685f84b43ad3b7b00f81285662f85c6a68ef11d62ad1a3ee0850", + "fee0e52802cb0c46b1eb4d376c62697f4759f6c8917fa352571202fd778fd712", + "16d6252968971a83da8521d65382e61f0176646d771c91528e3276ee45383e4a", + "d2e1642c9a462229289e5b0e3b7f9008e0301cbb93385ee0e21da2545073cb58", + "a5122c08ff9c161d9ca6fc462073396c7d7d38e8ee48cdb3bea7e2230134ed6a", + "28e7b841dcbc47cceb69d7cb8d94245fb7cb2ba3a7a6bc18f13f945f7dbd6e2a", + "e1f34b034d4a3cd28557e2907ebf990c918f64ecb50a94f01d6fda5ca5c7ef72", + "12935f14b676509b81eb49ef25f39269ed72309238b4c145803544b646dca62d", + "b2eed031d4d6a4f02a097f80b54cc1541d4163c6b6f5971f88b6e41d35c53814", + "fbc2f4300c01f0b7820d00e3347c8da4ee614674376cbc45359daa54f9b5493e", + ]; + + #[test] + fn empty_root_test_vectors() { + let mut tmp = [0u8; 32]; + for i in 0..HEX_EMPTY_ROOTS.len() { + EMPTY_ROOTS[i] + .repr + .write_le(&mut tmp[..]) + .expect("length is 32 bytes"); + assert_eq!(hex::encode(tmp), HEX_EMPTY_ROOTS[i]); + } + } +} From f4059a5faa1ccb5d3c86f4ecc4e17d13cf1eca33 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 8 Oct 2018 14:52:27 +0100 Subject: [PATCH 012/330] Sapling commitment tree --- zcash_primitives/src/merkle_tree.rs | 263 +++++++++++++++++++++++++++- 1 file changed, 262 insertions(+), 1 deletion(-) diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index cb74ea1..6e458e4 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -1,6 +1,7 @@ use ff::PrimeField; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use sapling_crypto::primitives::Note; +use std::collections::VecDeque; use sapling::merkle_hash; @@ -56,12 +57,147 @@ lazy_static! { }; } +struct PathFiller { + queue: VecDeque, +} + +impl PathFiller { + fn empty() -> Self { + PathFiller { + queue: VecDeque::new(), + } + } + + fn next(&mut self, depth: usize) -> Node { + self.queue.pop_front().unwrap_or_else(|| EMPTY_ROOTS[depth]) + } +} + +/// A Merkle tree of Sapling note commitments. +pub struct CommitmentTree { + left: Option, + right: Option, + parents: Vec>, +} + +impl CommitmentTree { + /// Creates an empty tree. + pub fn new() -> Self { + CommitmentTree { + left: None, + right: None, + parents: vec![], + } + } + + /// Returns the number of notes in the tree. + pub fn size(&self) -> usize { + self.parents.iter().enumerate().fold( + match (self.left.is_some(), self.right.is_some()) { + (false, false) => 0, + (true, false) | (false, true) => 1, + (true, true) => 2, + }, + |acc, (i, p)| { + // Treat occupation of parents array as a binary number + // (right-shifted by 1) + acc + if p.is_some() { 1 << (i + 1) } else { 0 } + }, + ) + } + + fn is_complete(&self, depth: usize) -> bool { + self.left.is_some() + && self.right.is_some() + && self.parents.len() == depth - 1 + && self.parents.iter().fold(true, |acc, p| acc && p.is_some()) + } + + /// Adds a note to the tree. Returns an error if the tree is full. + pub fn append(&mut self, node: Node) -> Result<(), ()> { + self.append_inner(node, SAPLING_COMMITMENT_TREE_DEPTH) + } + + fn append_inner(&mut self, node: Node, depth: usize) -> Result<(), ()> { + if self.is_complete(depth) { + // Tree is full + return Err(()); + } + + match (self.left, self.right) { + (None, _) => self.left = Some(node), + (_, None) => self.right = Some(node), + (Some(l), Some(r)) => { + let mut combined = Node::combine(0, &l, &r); + self.left = Some(node); + self.right = None; + + for i in 0..depth { + if i < self.parents.len() { + if let Some(p) = self.parents[i] { + combined = Node::combine(i + 1, &p, &combined); + self.parents[i] = None; + } else { + self.parents[i] = Some(combined); + break; + } + } else { + self.parents.push(Some(combined)); + break; + } + } + } + } + + Ok(()) + } + + /// Returns the current root of the tree. + pub fn root(&self) -> Node { + self.root_inner(SAPLING_COMMITMENT_TREE_DEPTH, PathFiller::empty()) + } + + fn root_inner(&self, depth: usize, mut filler: PathFiller) -> Node { + assert!(depth > 0); + + // 1) Hash left and right leaves together. + // - Empty leaves are used as needed. + let leaf_root = Node::combine( + 0, + &match self.left { + Some(node) => node, + None => filler.next(0), + }, + &match self.right { + Some(node) => node, + None => filler.next(0), + }, + ); + + // 2) Hash in parents up to the currently-filled depth. + // - Roots of the empty subtrees are used as needed. + let mid_root = self + .parents + .iter() + .enumerate() + .fold(leaf_root, |root, (i, p)| match p { + Some(node) => Node::combine(i + 1, node, &root), + None => Node::combine(i + 1, &root, &filler.next(i + 1)), + }); + + // 3) Hash in roots of the empty subtrees up to the final depth. + ((self.parents.len() + 1)..depth) + .fold(mid_root, |root, d| Node::combine(d, &root, &filler.next(d))) + } +} + #[cfg(test)] mod tests { - use super::EMPTY_ROOTS; + use super::{CommitmentTree, Hashable, Node, PathFiller, EMPTY_ROOTS}; use ff::PrimeFieldRepr; use hex; + use pairing::bls12_381::FrRepr; const HEX_EMPTY_ROOTS: [&str; 33] = [ "0100000000000000000000000000000000000000000000000000000000000000", @@ -99,6 +235,28 @@ mod tests { "fbc2f4300c01f0b7820d00e3347c8da4ee614674376cbc45359daa54f9b5493e", ]; + const TESTING_DEPTH: usize = 4; + + struct TestCommitmentTree(CommitmentTree); + + impl TestCommitmentTree { + fn new() -> Self { + TestCommitmentTree(CommitmentTree::new()) + } + + fn size(&self) -> usize { + self.0.size() + } + + fn append(&mut self, node: Node) -> Result<(), ()> { + self.0.append_inner(node, TESTING_DEPTH) + } + + fn root(&self) -> Node { + self.0.root_inner(TESTING_DEPTH, PathFiller::empty()) + } + } + #[test] fn empty_root_test_vectors() { let mut tmp = [0u8; 32]; @@ -110,4 +268,107 @@ mod tests { assert_eq!(hex::encode(tmp), HEX_EMPTY_ROOTS[i]); } } + + #[test] + fn sapling_empty_root() { + let mut tmp = [0u8; 32]; + CommitmentTree::new() + .root() + .repr + .write_le(&mut tmp[..]) + .expect("length is 32 bytes"); + assert_eq!( + hex::encode(tmp), + "fbc2f4300c01f0b7820d00e3347c8da4ee614674376cbc45359daa54f9b5493e" + ); + } + + #[test] + fn empty_commitment_tree_roots() { + let tree = CommitmentTree::new(); + let mut tmp = [0u8; 32]; + for i in 1..HEX_EMPTY_ROOTS.len() { + tree.root_inner(i, PathFiller::empty()) + .repr + .write_le(&mut tmp[..]) + .expect("length is 32 bytes"); + assert_eq!(hex::encode(tmp), HEX_EMPTY_ROOTS[i]); + } + } + + #[test] + fn test_sapling_tree() { + // From https://github.com/zcash/zcash/blob/master/src/test/data/merkle_commitments_sapling.json + // Byte-reversed because the original test vectors are loaded using uint256S() + let commitments = [ + "b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55", + "225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458", + "7c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c", + "50421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030", + "aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc12", + "f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a02", + "bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e", + "da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a511", + "3a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f77446", + "c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f163008", + "f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702", + "e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c608", + "8cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e826", + "22fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c03", + "f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c", + "3a3661bc12b72646c94bc6c92796e81953985ee62d80a9ec3645a9a95740ac15", + ]; + + // From https://github.com/zcash/zcash/blob/master/src/test/data/merkle_roots_sapling.json + let roots = [ + "8c3daa300c9710bf24d2595536e7c80ff8d147faca726636d28e8683a0c27703", + "8611f17378eb55e8c3c3f0a5f002e2b0a7ca39442fc928322b8072d1079c213d", + "3db73b998d536be0e1c2ec124df8e0f383ae7b602968ff6a5276ca0695023c46", + "7ac2e6442fec5970e116dfa4f2ee606f395366cafb1fa7dfd6c3de3ce18c4363", + "6a8f11ab2a11c262e39ed4ea3825ae6c94739ccf94479cb69402c5722b034532", + "149595eed0b54a7e694cc8a68372525b9ae2c7b102514f527460db91eb690565", + "8c0432f1994a2381a7a4b5fda770336011f9e0b30784f9a5597901619c797045", + "e780c48d70420601f3313ff8488d7766b70c059c53aa3cda2ff1ef57ff62383c", + "f919f03caaed8a2c60f58c0d43838f83e670dc7e8ccd25daa04a13f3e8f45541", + "74f32b36629724038e71cbd6823b5a666440205a7d1a9242e95870b53d81f34a", + "a4af205a4e1ee02102866b23a68930ac33efda9235832f49b17fcc4939be4525", + "a946a42f1636045a16e65b2308e036d9da70089686c87c692e45912bd1cab772", + "a1db2dbac055364c1cb43cbeb49c7e2815bff855122602a2ad0fb981a91e0e39", + "16329b3ba4f0640f4d306532d9ea6ba0fbf0e70e44ed57d27b4277ed9cda6849", + "7b6523b2d9b23f72fec6234aa6a1f8fae3dba1c6a266023ea8b1826feba7a25c", + "5c0bea7e17bde5bee4eb795c2eec3d389a68da587b36dd687b134826ecc09308", + ]; + + fn assert_root_eq(root: Node, expected: &str) { + let mut tmp = [0u8; 32]; + root.repr + .write_le(&mut tmp[..]) + .expect("length is 32 bytes"); + assert_eq!(hex::encode(tmp), expected); + } + + let mut tree = TestCommitmentTree::new(); + assert_eq!(tree.size(), 0); + + for i in 0..16 { + let mut cm = FrRepr::default(); + cm.read_le(&hex::decode(commitments[i]).unwrap()[..]) + .expect("length is 32 bytes"); + + let cm = Node::new(cm); + + // Append a commitment to the tree + assert!(tree.append(cm).is_ok()); + + // Size incremented by one. + assert_eq!(tree.size(), i + 1); + + // Check tree root consistency + assert_root_eq(tree.root(), roots[i]); + } + + // Tree should be full now + let node = Node::blank(); + assert!(tree.append(node).is_err()); + } } From bf74915053d490fa4af507c32d9c4e55ca6ef7f2 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 9 Nov 2018 00:07:25 +1300 Subject: [PATCH 013/330] Move CommitmentTreeWitness into zcash_primitives --- Cargo.lock | 1 + librustzcash/src/rustzcash.rs | 3 +- zcash_primitives/src/merkle_tree.rs | 75 ++++++++++++++++++++++++++- zcash_proofs/Cargo.toml | 1 + zcash_proofs/src/lib.rs | 1 + zcash_proofs/src/sapling/mod.rs | 2 +- zcash_proofs/src/sapling/prover.rs | 78 ++--------------------------- 7 files changed, 83 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34b20d2..26def55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -553,6 +553,7 @@ dependencies = [ "pairing 0.14.2", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", + "zcash_primitives 0.0.0", ] [metadata] diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 20af7ed..96bb718 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -57,13 +57,14 @@ use std::os::windows::ffi::OsStringExt; use sapling_crypto::primitives::{ProofGenerationKey, ViewingKey}; use zcash_primitives::{ + merkle_tree::CommitmentTreeWitness, note_encryption::sapling_ka_agree, sapling::{merkle_hash, spend_sig}, zip32, JUBJUB, }; use zcash_proofs::{ load_parameters, - sapling::{CommitmentTreeWitness, SaplingProvingContext, SaplingVerificationContext}, + sapling::{SaplingProvingContext, SaplingVerificationContext}, }; pub mod equihash; diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 6e458e4..a715215 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -1,6 +1,7 @@ -use ff::PrimeField; +use byteorder::{LittleEndian, ReadBytesExt}; +use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; -use sapling_crypto::primitives::Note; +use sapling_crypto::{circuit::sapling::TREE_DEPTH, primitives::Note}; use std::collections::VecDeque; use sapling::merkle_hash; @@ -191,6 +192,76 @@ impl CommitmentTree { } } +/// A witness to a path from a position in a particular Sapling commitment tree +/// to the root of that tree. +pub struct CommitmentTreeWitness { + pub auth_path: Vec>, + pub position: u64, +} + +impl CommitmentTreeWitness { + pub fn from_slice(mut witness: &[u8]) -> Result { + // Skip the first byte, which should be "32" to signify the length of + // the following vector of Pedersen hashes. + assert_eq!(witness[0], TREE_DEPTH as u8); + witness = &witness[1..]; + + // Begin to construct the authentication path + let mut auth_path = vec![None; TREE_DEPTH]; + + // The vector works in reverse + for i in (0..TREE_DEPTH).rev() { + // skip length of inner vector + assert_eq!(witness[0], 32); // the length of a pedersen hash + witness = &witness[1..]; + + // Grab the sibling node at this depth in the tree + let mut sibling = [0u8; 32]; + sibling.copy_from_slice(&witness[0..32]); + witness = &witness[32..]; + + // Sibling node should be an element of Fr + let sibling = match { + let mut repr = FrRepr::default(); + repr.read_le(&sibling[..]).expect("length is 32 bytes"); + Fr::from_repr(repr) + } { + Ok(p) => p, + Err(_) => return Err(()), + }; + + // Set the value in the auth path; we put false here + // for now (signifying the position bit) which we'll + // fill in later. + auth_path[i] = Some((sibling, false)); + } + + // Read the position from the witness + let position = witness + .read_u64::() + .expect("should have had index at the end"); + + // Given the position, let's finish constructing the authentication + // path + let mut tmp = position; + for i in 0..TREE_DEPTH { + auth_path[i].as_mut().map(|p| p.1 = (tmp & 1) == 1); + + tmp >>= 1; + } + + // The witness should be empty now; if it wasn't, the caller would + // have provided more information than they should have, indicating + // a bug downstream + assert_eq!(witness.len(), 0); + + Ok(CommitmentTreeWitness { + auth_path, + position, + }) + } +} + #[cfg(test)] mod tests { use super::{CommitmentTree, Hashable, Node, PathFiller, EMPTY_ROOTS}; diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index 5bcdb26..85a7210 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -12,6 +12,7 @@ ff = { path = "../ff" } pairing = { path = "../pairing" } rand = "0.4" sapling-crypto = { path = "../sapling-crypto" } +zcash_primitives = { path = "../zcash_primitives" } [dependencies.blake2-rfc] git = "https://github.com/gtank/blake2-rfc" diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs index ca17a8b..97dd501 100644 --- a/zcash_proofs/src/lib.rs +++ b/zcash_proofs/src/lib.rs @@ -5,6 +5,7 @@ extern crate ff; extern crate pairing; extern crate rand; extern crate sapling_crypto; +extern crate zcash_primitives; use bellman::groth16::{prepare_verifying_key, Parameters, PreparedVerifyingKey, VerifyingKey}; use pairing::bls12_381::Bls12; diff --git a/zcash_proofs/src/sapling/mod.rs b/zcash_proofs/src/sapling/mod.rs index 2cfb2e9..4c37306 100644 --- a/zcash_proofs/src/sapling/mod.rs +++ b/zcash_proofs/src/sapling/mod.rs @@ -6,7 +6,7 @@ use sapling_crypto::jubjub::{ mod prover; mod verifier; -pub use self::prover::{CommitmentTreeWitness, SaplingProvingContext}; +pub use self::prover::SaplingProvingContext; pub use self::verifier::SaplingVerificationContext; // This function computes `value` in the exponent of the value commitment base diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index 3a3511c..feb1d2c 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -1,92 +1,22 @@ use bellman::groth16::{ create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof, }; -use byteorder::{LittleEndian, ReadBytesExt}; -use ff::{Field, PrimeField, PrimeFieldRepr}; -use pairing::bls12_381::{Bls12, Fr, FrRepr}; +use ff::Field; +use pairing::bls12_381::{Bls12, Fr}; use rand::{OsRng, Rand}; use sapling_crypto::{ circuit::{ multipack, - sapling::{Output, Spend, TREE_DEPTH}, + sapling::{Output, Spend}, }, jubjub::{edwards, fs::Fs, FixedGenerators, JubjubBls12, Unknown}, primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, redjubjub::{PrivateKey, PublicKey, Signature}, }; +use zcash_primitives::merkle_tree::CommitmentTreeWitness; use super::compute_value_balance; -/// A witness to a path from a postion in a particular Sapling commitment tree -/// to the root of that tree. -pub struct CommitmentTreeWitness { - auth_path: Vec>, - position: u64, -} - -impl CommitmentTreeWitness { - pub fn from_slice(mut witness: &[u8]) -> Result { - // Skip the first byte, which should be "32" to signify the length of - // the following vector of Pedersen hashes. - assert_eq!(witness[0], TREE_DEPTH as u8); - witness = &witness[1..]; - - // Begin to construct the authentication path - let mut auth_path = vec![None; TREE_DEPTH]; - - // The vector works in reverse - for i in (0..TREE_DEPTH).rev() { - // skip length of inner vector - assert_eq!(witness[0], 32); // the length of a pedersen hash - witness = &witness[1..]; - - // Grab the sibling node at this depth in the tree - let mut sibling = [0u8; 32]; - sibling.copy_from_slice(&witness[0..32]); - witness = &witness[32..]; - - // Sibling node should be an element of Fr - let sibling = match { - let mut repr = FrRepr::default(); - repr.read_le(&sibling[..]).expect("length is 32 bytes"); - Fr::from_repr(repr) - } { - Ok(p) => p, - Err(_) => return Err(()), - }; - - // Set the value in the auth path; we put false here - // for now (signifying the position bit) which we'll - // fill in later. - auth_path[i] = Some((sibling, false)); - } - - // Read the position from the witness - let position = witness - .read_u64::() - .expect("should have had index at the end"); - - // Given the position, let's finish constructing the authentication - // path - let mut tmp = position; - for i in 0..TREE_DEPTH { - auth_path[i].as_mut().map(|p| p.1 = (tmp & 1) == 1); - - tmp >>= 1; - } - - // The witness should be empty now; if it wasn't, the caller would - // have provided more information than they should have, indicating - // a bug downstream - assert_eq!(witness.len(), 0); - - Ok(CommitmentTreeWitness { - auth_path, - position, - }) - } -} - /// A context object for creating the Sapling components of a Zcash transaction. pub struct SaplingProvingContext { bsk: Fs, From 667d6101c9dc3916559d74fb9b4ccbd093f54e47 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 10 Oct 2018 17:43:02 +0100 Subject: [PATCH 014/330] Sapling incremental witnesses --- zcash_primitives/src/merkle_tree.rs | 374 +++++++++++++++++++++++++++- 1 file changed, 366 insertions(+), 8 deletions(-) diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index a715215..2a6eaf2 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -3,6 +3,7 @@ use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use sapling_crypto::{circuit::sapling::TREE_DEPTH, primitives::Note}; use std::collections::VecDeque; +use std::iter; use sapling::merkle_hash; @@ -16,7 +17,7 @@ trait Hashable: Clone + Copy { fn blank() -> Self; } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct Node { repr: FrRepr, } @@ -75,6 +76,7 @@ impl PathFiller { } /// A Merkle tree of Sapling note commitments. +#[derive(Clone)] pub struct CommitmentTree { left: Option, right: Option, @@ -192,25 +194,203 @@ impl CommitmentTree { } } +#[derive(Clone)] +pub struct IncrementalWitness { + tree: CommitmentTree, + filled: Vec, + cursor_depth: usize, + cursor: Option, +} + +impl IncrementalWitness { + pub fn from_tree(tree: &CommitmentTree) -> IncrementalWitness { + IncrementalWitness { + tree: tree.clone(), + filled: vec![], + cursor_depth: 0, + cursor: None, + } + } + + /// Returns the position of the witnessed note in the commitment tree. + pub fn position(&self) -> usize { + self.tree.size() - 1 + } + + fn filler(&self) -> PathFiller { + let cursor_root = self + .cursor + .as_ref() + .map(|c| c.root_inner(self.cursor_depth, PathFiller::empty())); + + let queue = if let Some(node) = cursor_root { + self.filled + .iter() + .cloned() + .chain(iter::once(node)) + .collect() + } else { + self.filled.iter().cloned().collect() + }; + + PathFiller { queue } + } + + /// Finds the next "depth" of an unfilled subtree. + fn next_depth(&self) -> usize { + let mut skip = self.filled.len(); + + if self.tree.left.is_none() { + if skip > 0 { + skip -= 1; + } else { + return 0; + } + } + + if self.tree.right.is_none() { + if skip > 0 { + skip -= 1; + } else { + return 0; + } + } + + let mut d = 1; + for p in &self.tree.parents { + if p.is_none() { + if skip > 0 { + skip -= 1; + } else { + return d; + } + } + d += 1; + } + + d + skip + } + + /// Tracks a note that has been added to the underlying tree. Returns an + /// error if the tree is full. + pub fn append(&mut self, node: Node) -> Result<(), ()> { + self.append_inner(node, SAPLING_COMMITMENT_TREE_DEPTH) + } + + fn append_inner(&mut self, node: Node, depth: usize) -> Result<(), ()> { + if let Some(mut cursor) = self.cursor.take() { + cursor + .append_inner(node, depth) + .expect("cursor should not be full"); + if cursor.is_complete(self.cursor_depth) { + self.filled + .push(cursor.root_inner(self.cursor_depth, PathFiller::empty())); + } else { + self.cursor = Some(cursor); + } + } else { + self.cursor_depth = self.next_depth(); + if self.cursor_depth >= depth { + // Tree is full + return Err(()); + } + + if self.cursor_depth == 0 { + self.filled.push(node); + } else { + let mut cursor = CommitmentTree::new(); + cursor + .append_inner(node, depth) + .expect("cursor should not be full"); + self.cursor = Some(cursor); + } + } + + Ok(()) + } + + /// Returns the current root of the tree corresponding to the witness. + pub fn root(&self) -> Node { + self.root_inner(SAPLING_COMMITMENT_TREE_DEPTH) + } + + fn root_inner(&self, depth: usize) -> Node { + self.tree.root_inner(depth, self.filler()) + } + + /// Returns the current witness, or None if the tree is empty. + pub fn path(&self) -> Option { + self.path_inner(SAPLING_COMMITMENT_TREE_DEPTH) + } + + fn path_inner(&self, depth: usize) -> Option { + let mut filler = self.filler(); + let mut auth_path = Vec::new(); + + if let Some(node) = self.tree.left { + if self.tree.right.is_some() { + auth_path.push(Some((node, true))); + } else { + auth_path.push(Some((filler.next(0), false))); + } + } else { + // Can't create an authentication path for the beginning of the tree + return None; + } + + for (i, p) in self.tree.parents.iter().enumerate() { + auth_path.push(match p { + Some(node) => Some((*node, true)), + None => Some((filler.next(i + 1), false)), + }); + } + + for i in self.tree.parents.len()..(depth - 1) { + auth_path.push(Some((filler.next(i + 1), false))); + } + assert_eq!(auth_path.len(), depth); + + Some(CommitmentTreeWitness::from_path( + auth_path + .iter() + .map(|n| n.map(|(node, b)| (node.into(), b))) + .collect(), + self.position() as u64, + )) + } +} + /// A witness to a path from a position in a particular Sapling commitment tree /// to the root of that tree. +#[derive(Debug, PartialEq)] pub struct CommitmentTreeWitness { pub auth_path: Vec>, pub position: u64, } impl CommitmentTreeWitness { - pub fn from_slice(mut witness: &[u8]) -> Result { + pub fn from_path(auth_path: Vec>, position: u64) -> Self { + CommitmentTreeWitness { + auth_path, + position, + } + } + + pub fn from_slice(witness: &[u8]) -> Result { + Self::from_slice_with_depth(witness, TREE_DEPTH) + } + + pub fn from_slice_with_depth(mut witness: &[u8], depth: usize) -> Result { // Skip the first byte, which should be "32" to signify the length of // the following vector of Pedersen hashes. - assert_eq!(witness[0], TREE_DEPTH as u8); + assert_eq!(witness[0], depth as u8); witness = &witness[1..]; // Begin to construct the authentication path - let mut auth_path = vec![None; TREE_DEPTH]; + let mut auth_path = vec![None; depth]; // The vector works in reverse - for i in (0..TREE_DEPTH).rev() { + for i in (0..depth).rev() { // skip length of inner vector assert_eq!(witness[0], 32); // the length of a pedersen hash witness = &witness[1..]; @@ -244,7 +424,7 @@ impl CommitmentTreeWitness { // Given the position, let's finish constructing the authentication // path let mut tmp = position; - for i in 0..TREE_DEPTH { + for i in 0..depth { auth_path[i].as_mut().map(|p| p.1 = (tmp & 1) == 1); tmp >>= 1; @@ -264,7 +444,10 @@ impl CommitmentTreeWitness { #[cfg(test)] mod tests { - use super::{CommitmentTree, Hashable, Node, PathFiller, EMPTY_ROOTS}; + use super::{ + CommitmentTree, CommitmentTreeWitness, Hashable, IncrementalWitness, Node, PathFiller, + EMPTY_ROOTS, + }; use ff::PrimeFieldRepr; use hex; @@ -328,6 +511,26 @@ mod tests { } } + struct TestIncrementalWitness(IncrementalWitness); + + impl TestIncrementalWitness { + fn from_tree(tree: &TestCommitmentTree) -> Self { + TestIncrementalWitness(IncrementalWitness::from_tree(&tree.0)) + } + + fn append(&mut self, node: Node) -> Result<(), ()> { + self.0.append_inner(node, TESTING_DEPTH) + } + + fn root(&self) -> Node { + self.0.root_inner(TESTING_DEPTH) + } + + fn path(&self) -> Option { + self.0.path_inner(TESTING_DEPTH) + } + } + #[test] fn empty_root_test_vectors() { let mut tmp = [0u8; 32]; @@ -410,6 +613,130 @@ mod tests { "5c0bea7e17bde5bee4eb795c2eec3d389a68da587b36dd687b134826ecc09308", ]; + // From https://github.com/zcash/zcash/blob/master/src/test/data/merkle_path_sapling.json + let paths = [ + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c20ffe9fc03f18b176c998806439ff0bb8ad193afdb27b2ccbc88856916dd804e3420817de36ab2d57feb077634bca77819c8e0bd298c04f6fed0e6a83cc1356ca15520225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c20ffe9fc03f18b176c998806439ff0bb8ad193afdb27b2ccbc88856916dd804e342037b3a0921a4047e617bde62b8958f86c010e6af6cc650959b9f50af8c7e8392620225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c20ffe9fc03f18b176c998806439ff0bb8ad193afdb27b2ccbc88856916dd804e342037b3a0921a4047e617bde62b8958f86c010e6af6cc650959b9f50af8c7e8392620b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c20ffe9fc03f18b176c998806439ff0bb8ad193afdb27b2ccbc88856916dd804e3420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c20ffe9fc03f18b176c998806439ff0bb8ad193afdb27b2ccbc88856916dd804e3420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c20ffe9fc03f18b176c998806439ff0bb8ad193afdb27b2ccbc88856916dd804e342062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6662050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300200000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c2031d39685384e4ea322594d99a15aa8bdd8cc5cd6724410fa385b8d5447f1740220f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c2031d39685384e4ea322594d99a15aa8bdd8cc5cd6724410fa385b8d5447f1740220f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c2031d39685384e4ea322594d99a15aa8bdd8cc5cd6724410fa385b8d5447f174022062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6662050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300200000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c2031d39685384e4ea322594d99a15aa8bdd8cc5cd6724410fa385b8d5447f174022062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0300000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c20f0321eea8e13c2f3a567f894c9738759d9d01e64ec259caf2cecca61374c157320f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c20f0321eea8e13c2f3a567f894c9738759d9d01e64ec259caf2cecca61374c157320f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c20f0321eea8e13c2f3a567f894c9738759d9d01e64ec259caf2cecca61374c15732062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6662050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300200000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c20f0321eea8e13c2f3a567f894c9738759d9d01e64ec259caf2cecca61374c15732062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0300000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420817de36ab2d57feb077634bca77819c8e0bd298c04f6fed0e6a83cc1356ca15520f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020400000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c2082c424de0185a63f6ce0aa65d3d55890748af44bb4bb5822a9a21df34546d32220f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c2082c424de0185a63f6ce0aa65d3d55890748af44bb4bb5822a9a21df34546d32220f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c2082c424de0185a63f6ce0aa65d3d55890748af44bb4bb5822a9a21df34546d3222062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6662050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300200000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c2082c424de0185a63f6ce0aa65d3d55890748af44bb4bb5822a9a21df34546d3222062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0300000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f655186564206ab2e08286c36f6fe4374baebdc28b97e2f1f4ea3544fafd8a6489f42824bf0e20f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020400000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f655186564206ab2e08286c36f6fe4374baebdc28b97e2f1f4ea3544fafd8a6489f42824bf0e20aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc120500000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6662050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300200000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0300000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020400000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc120500000000000000", + "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110600000000000000", + "0420109713c6c346ab0b17904ae18d101d92a98a612116a3f787043c802b55d5573120130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", + "0420109713c6c346ab0b17904ae18d101d92a98a612116a3f787043c802b55d5573120130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000", + "0420109713c6c346ab0b17904ae18d101d92a98a612116a3f787043c802b55d5573120130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6662050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300200000000000000", + "0420109713c6c346ab0b17904ae18d101d92a98a612116a3f787043c802b55d5573120130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0300000000000000", + "0420109713c6c346ab0b17904ae18d101d92a98a612116a3f787043c802b55d55731201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020400000000000000", + "0420109713c6c346ab0b17904ae18d101d92a98a612116a3f787043c802b55d55731201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc120500000000000000", + "0420109713c6c346ab0b17904ae18d101d92a98a612116a3f787043c802b55d55731201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110600000000000000", + "0420109713c6c346ab0b17904ae18d101d92a98a612116a3f787043c802b55d55731201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e0700000000000000", + "0420bced38e720c8eab9b3b8b2959e5a8b8dda2b2537f6ea71c8e2aea8834a9af54220130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", + "0420bced38e720c8eab9b3b8b2959e5a8b8dda2b2537f6ea71c8e2aea8834a9af54220130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000", + "0420bced38e720c8eab9b3b8b2959e5a8b8dda2b2537f6ea71c8e2aea8834a9af54220130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6662050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300200000000000000", + "0420bced38e720c8eab9b3b8b2959e5a8b8dda2b2537f6ea71c8e2aea8834a9af54220130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0300000000000000", + "0420bced38e720c8eab9b3b8b2959e5a8b8dda2b2537f6ea71c8e2aea8834a9af542201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020400000000000000", + "0420bced38e720c8eab9b3b8b2959e5a8b8dda2b2537f6ea71c8e2aea8834a9af542201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc120500000000000000", + "0420bced38e720c8eab9b3b8b2959e5a8b8dda2b2537f6ea71c8e2aea8834a9af542201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110600000000000000", + "0420bced38e720c8eab9b3b8b2959e5a8b8dda2b2537f6ea71c8e2aea8834a9af542201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e0700000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20ffe9fc03f18b176c998806439ff0bb8ad193afdb27b2ccbc88856916dd804e3420817de36ab2d57feb077634bca77819c8e0bd298c04f6fed0e6a83cc1356ca15520c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f1630080800000000000000", + "042094d3061a43d999e95bab82684aeb53d0a381b40e33a80abfc5c05e25b0a91d0f20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", + "042094d3061a43d999e95bab82684aeb53d0a381b40e33a80abfc5c05e25b0a91d0f20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000", + "042094d3061a43d999e95bab82684aeb53d0a381b40e33a80abfc5c05e25b0a91d0f20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6662050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300200000000000000", + "042094d3061a43d999e95bab82684aeb53d0a381b40e33a80abfc5c05e25b0a91d0f20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0300000000000000", + "042094d3061a43d999e95bab82684aeb53d0a381b40e33a80abfc5c05e25b0a91d0f201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020400000000000000", + "042094d3061a43d999e95bab82684aeb53d0a381b40e33a80abfc5c05e25b0a91d0f201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc120500000000000000", + "042094d3061a43d999e95bab82684aeb53d0a381b40e33a80abfc5c05e25b0a91d0f201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110600000000000000", + "042094d3061a43d999e95bab82684aeb53d0a381b40e33a80abfc5c05e25b0a91d0f201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e0700000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20ffe9fc03f18b176c998806439ff0bb8ad193afdb27b2ccbc88856916dd804e342076bd791f7708c0b6f5a348d574032e07ce3b1929daae19530346f5de955d543c20c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f1630080800000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20ffe9fc03f18b176c998806439ff0bb8ad193afdb27b2ccbc88856916dd804e342076bd791f7708c0b6f5a348d574032e07ce3b1929daae19530346f5de955d543c203a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774460900000000000000", + "042061ae87cb694e8237accda801c8271a8a9d4ffc2581aebf923f5227f24c6bb92a20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", + "042061ae87cb694e8237accda801c8271a8a9d4ffc2581aebf923f5227f24c6bb92a20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000", + "042061ae87cb694e8237accda801c8271a8a9d4ffc2581aebf923f5227f24c6bb92a20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6662050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300200000000000000", + "042061ae87cb694e8237accda801c8271a8a9d4ffc2581aebf923f5227f24c6bb92a20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0300000000000000", + "042061ae87cb694e8237accda801c8271a8a9d4ffc2581aebf923f5227f24c6bb92a201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020400000000000000", + "042061ae87cb694e8237accda801c8271a8a9d4ffc2581aebf923f5227f24c6bb92a201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc120500000000000000", + "042061ae87cb694e8237accda801c8271a8a9d4ffc2581aebf923f5227f24c6bb92a201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110600000000000000", + "042061ae87cb694e8237accda801c8271a8a9d4ffc2581aebf923f5227f24c6bb92a201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e0700000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20ffe9fc03f18b176c998806439ff0bb8ad193afdb27b2ccbc88856916dd804e3420635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b614420c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f1630080800000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20ffe9fc03f18b176c998806439ff0bb8ad193afdb27b2ccbc88856916dd804e3420635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b6144203a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774460900000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20ffe9fc03f18b176c998806439ff0bb8ad193afdb27b2ccbc88856916dd804e3420cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173220e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080a00000000000000", + "04208850438b439403c52a62aa6c81280ce5ea92bc5ff899ada6933c6afddc882e1820130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", + "04208850438b439403c52a62aa6c81280ce5ea92bc5ff899ada6933c6afddc882e1820130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000", + "04208850438b439403c52a62aa6c81280ce5ea92bc5ff899ada6933c6afddc882e1820130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6662050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300200000000000000", + "04208850438b439403c52a62aa6c81280ce5ea92bc5ff899ada6933c6afddc882e1820130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0300000000000000", + "04208850438b439403c52a62aa6c81280ce5ea92bc5ff899ada6933c6afddc882e18201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020400000000000000", + "04208850438b439403c52a62aa6c81280ce5ea92bc5ff899ada6933c6afddc882e18201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc120500000000000000", + "04208850438b439403c52a62aa6c81280ce5ea92bc5ff899ada6933c6afddc882e18201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110600000000000000", + "04208850438b439403c52a62aa6c81280ce5ea92bc5ff899ada6933c6afddc882e18201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e0700000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20130266c8ace013b416e56be57600a9da16e136df92231a964613e2885cce756620635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b614420c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f1630080800000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20130266c8ace013b416e56be57600a9da16e136df92231a964613e2885cce756620635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b6144203a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774460900000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20130266c8ace013b416e56be57600a9da16e136df92231a964613e2885cce756620cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173220e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080a00000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20130266c8ace013b416e56be57600a9da16e136df92231a964613e2885cce756620cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173220f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020b00000000000000", + "0420c9cd5269cd697706cb0745d57f66e5ba4a5051fb910127318d283f751910ac7120130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", + "0420c9cd5269cd697706cb0745d57f66e5ba4a5051fb910127318d283f751910ac7120130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000", + "0420c9cd5269cd697706cb0745d57f66e5ba4a5051fb910127318d283f751910ac7120130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6662050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300200000000000000", + "0420c9cd5269cd697706cb0745d57f66e5ba4a5051fb910127318d283f751910ac7120130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0300000000000000", + "0420c9cd5269cd697706cb0745d57f66e5ba4a5051fb910127318d283f751910ac71201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020400000000000000", + "0420c9cd5269cd697706cb0745d57f66e5ba4a5051fb910127318d283f751910ac71201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc120500000000000000", + "0420c9cd5269cd697706cb0745d57f66e5ba4a5051fb910127318d283f751910ac71201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110600000000000000", + "0420c9cd5269cd697706cb0745d57f66e5ba4a5051fb910127318d283f751910ac71201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e0700000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20c2b786e4ab72ae4f01c7241bc056817b19d42bc85107f42c3fd3a9b9e98f156420635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b614420c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f1630080800000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20c2b786e4ab72ae4f01c7241bc056817b19d42bc85107f42c3fd3a9b9e98f156420635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b6144203a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774460900000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20c2b786e4ab72ae4f01c7241bc056817b19d42bc85107f42c3fd3a9b9e98f156420cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173220e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080a00000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20c2b786e4ab72ae4f01c7241bc056817b19d42bc85107f42c3fd3a9b9e98f156420cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173220f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020b00000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c20817de36ab2d57feb077634bca77819c8e0bd298c04f6fed0e6a83cc1356ca1552022fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c030c00000000000000", + "04203cf9ea50bea2cebf829213d91c098813d11dbe5c6696cdaefab3249dbf892f5e20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", + "04203cf9ea50bea2cebf829213d91c098813d11dbe5c6696cdaefab3249dbf892f5e20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000", + "04203cf9ea50bea2cebf829213d91c098813d11dbe5c6696cdaefab3249dbf892f5e20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6662050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300200000000000000", + "04203cf9ea50bea2cebf829213d91c098813d11dbe5c6696cdaefab3249dbf892f5e20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0300000000000000", + "04203cf9ea50bea2cebf829213d91c098813d11dbe5c6696cdaefab3249dbf892f5e201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020400000000000000", + "04203cf9ea50bea2cebf829213d91c098813d11dbe5c6696cdaefab3249dbf892f5e201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc120500000000000000", + "04203cf9ea50bea2cebf829213d91c098813d11dbe5c6696cdaefab3249dbf892f5e201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110600000000000000", + "04203cf9ea50bea2cebf829213d91c098813d11dbe5c6696cdaefab3249dbf892f5e201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e0700000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20cd6db4bcd77d6ca695b9579f9ec5791d106f83b69118bb3a2a2a99f63779e06720635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b614420c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f1630080800000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20cd6db4bcd77d6ca695b9579f9ec5791d106f83b69118bb3a2a2a99f63779e06720635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b6144203a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774460900000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20cd6db4bcd77d6ca695b9579f9ec5791d106f83b69118bb3a2a2a99f63779e06720cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173220e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080a00000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20cd6db4bcd77d6ca695b9579f9ec5791d106f83b69118bb3a2a2a99f63779e06720cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173220f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020b00000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c2045d573e80606a552974215e13b5d3e7b4dd8675c77b8d612d293475ee139b9472022fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c030c00000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c2045d573e80606a552974215e13b5d3e7b4dd8675c77b8d612d293475ee139b947208cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260d00000000000000", + "04201d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", + "04201d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2420f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826420b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550100000000000000", + "04201d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6662050421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300200000000000000", + "04201d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c20130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f242062324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666207c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0300000000000000", + "04201d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020400000000000000", + "04201d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c20aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc120500000000000000", + "04201d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110600000000000000", + "04201d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c201fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656420eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd72420bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e0700000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20076795f3651049c8895a7d127eb9bb4a17698da400430b33fdd06b1d8160394020635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b614420c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f1630080800000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20076795f3651049c8895a7d127eb9bb4a17698da400430b33fdd06b1d8160394020635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b6144203a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774460900000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20076795f3651049c8895a7d127eb9bb4a17698da400430b33fdd06b1d8160394020cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173220e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080a00000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20076795f3651049c8895a7d127eb9bb4a17698da400430b33fdd06b1d8160394020cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173220f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020b00000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c20afa80a9a1bb8b6aad144cfb53e0bab004dd541c8b72025ae694bb60d6050a5322022fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c030c00000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c20afa80a9a1bb8b6aad144cfb53e0bab004dd541c8b72025ae694bb60d6050a532208cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260d00000000000000", + "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c205991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c349203a3661bc12b72646c94bc6c92796e81953985ee62d80a9ec3645a9a95740ac150e00000000000000", + ]; + fn assert_root_eq(root: Node, expected: &str) { let mut tmp = [0u8; 32]; root.repr @@ -421,6 +748,8 @@ mod tests { let mut tree = TestCommitmentTree::new(); assert_eq!(tree.size(), 0); + let mut witnesses = vec![]; + let mut paths_i = 0; for i in 0..16 { let mut cm = FrRepr::default(); cm.read_le(&hex::decode(commitments[i]).unwrap()[..]) @@ -428,7 +757,10 @@ mod tests { let cm = Node::new(cm); - // Append a commitment to the tree + // Witness here + witnesses.push(TestIncrementalWitness::from_tree(&tree)); + + // Now append a commitment to the tree assert!(tree.append(cm).is_ok()); // Size incremented by one. @@ -436,10 +768,36 @@ mod tests { // Check tree root consistency assert_root_eq(tree.root(), roots[i]); + + let mut first = true; // The first witness can never form a path + for witness in witnesses.as_mut_slice() { + // Append the same commitment to all the witnesses + assert!(witness.append(cm).is_ok()); + + if first { + assert!(witness.path().is_none()); + } else { + let path = witness.path().expect("should be able to create a path"); + let expected = CommitmentTreeWitness::from_slice_with_depth( + &mut hex::decode(paths[paths_i]).unwrap(), + TESTING_DEPTH, + ) + .unwrap(); + assert_eq!(path, expected); + paths_i += 1; + } + + assert_eq!(witness.root(), tree.root()); + + first = false; + } } // Tree should be full now let node = Node::blank(); assert!(tree.append(node).is_err()); + for witness in witnesses.as_mut_slice() { + assert!(witness.append(node).is_err()); + } } } From 70a70690586138fa4e2bb7c97c65b96d8e492c93 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 1 Dec 2018 17:16:32 +0000 Subject: [PATCH 015/330] Helper for serializing Option --- zcash_primitives/src/serialize.rs | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/zcash_primitives/src/serialize.rs b/zcash_primitives/src/serialize.rs index f142943..8312312 100644 --- a/zcash_primitives/src/serialize.rs +++ b/zcash_primitives/src/serialize.rs @@ -82,6 +82,37 @@ impl Vector { } } +pub struct Optional; + +impl Optional { + pub fn read(mut reader: R, func: F) -> io::Result> + where + F: Fn(&mut R) -> io::Result, + { + match reader.read_u8()? { + 0 => Ok(None), + 1 => Ok(Some(func(&mut reader)?)), + _ => Err(io::Error::new( + io::ErrorKind::InvalidInput, + "non-canonical Option", + )), + } + } + + pub fn write(mut writer: W, val: &Option, func: F) -> io::Result<()> + where + F: Fn(&mut W, &T) -> io::Result<()>, + { + match val { + None => writer.write_u8(0), + Some(e) => { + writer.write_u8(1)?; + func(&mut writer, e) + } + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -153,4 +184,46 @@ mod tests { eval!(vec![7; 260], expected); } } + + #[test] + fn optional() { + macro_rules! eval { + ($value:expr, $expected:expr, $write:expr, $read:expr) => { + let mut data = vec![]; + Optional::write(&mut data, &$value, $write).unwrap(); + assert_eq!(&data[..], &$expected[..]); + match Optional::read(&data[..], $read) { + Ok(v) => assert_eq!(v, $value), + Err(e) => panic!("Unexpected error: {:?}", e), + } + }; + } + + macro_rules! eval_u8 { + ($value:expr, $expected:expr) => { + eval!($value, $expected, |w, e| w.write_u8(*e), |r| r.read_u8()) + }; + } + + macro_rules! eval_vec { + ($value:expr, $expected:expr) => { + eval!( + $value, + $expected, + |w, v| Vector::write(w, v, |w, e| w.write_u8(*e)), + |r| Vector::read(r, |r| r.read_u8()) + ) + }; + } + + eval_u8!(None, [0]); + eval_u8!(Some(0), [1, 0]); + eval_u8!(Some(1), [1, 1]); + eval_u8!(Some(5), [1, 5]); + + eval_vec!(Some(vec![]), [1, 0]); + eval_vec!(Some(vec![0]), [1, 1, 0]); + eval_vec!(Some(vec![1]), [1, 1, 1]); + eval_vec!(Some(vec![5; 8]), [1, 8, 5, 5, 5, 5, 5, 5, 5, 5]); + } } From 9b4186705af5aa63ff871984028322aa5a511e6e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 1 Dec 2018 17:17:16 +0000 Subject: [PATCH 016/330] Add serialization APIs to CommitmentTree and IncrementalWitness --- zcash_primitives/src/merkle_tree.rs | 269 ++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 2a6eaf2..8fbc2a3 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -3,9 +3,11 @@ use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use sapling_crypto::{circuit::sapling::TREE_DEPTH, primitives::Note}; use std::collections::VecDeque; +use std::io::{self, Read, Write}; use std::iter; use sapling::merkle_hash; +use serialize::{Optional, Vector}; const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32; @@ -26,6 +28,16 @@ impl Node { pub fn new(repr: FrRepr) -> Self { Node { repr } } + + pub fn read(mut reader: R) -> io::Result { + let mut repr = FrRepr::default(); + repr.read_le(&mut reader)?; + Ok(Node::new(repr)) + } + + pub fn write(&self, mut writer: W) -> io::Result<()> { + self.repr.write_le(&mut writer) + } } impl Hashable for Node { @@ -93,6 +105,26 @@ impl CommitmentTree { } } + pub fn read(mut reader: R) -> io::Result { + let left = Optional::read(&mut reader, |r| Node::read(r))?; + let right = Optional::read(&mut reader, |r| Node::read(r))?; + let parents = Vector::read(&mut reader, |r| Optional::read(r, |r| Node::read(r)))?; + + Ok(CommitmentTree { + left, + right, + parents, + }) + } + + pub fn write(&self, mut writer: W) -> io::Result<()> { + Optional::write(&mut writer, &self.left, |w, n| n.write(w))?; + Optional::write(&mut writer, &self.right, |w, n| n.write(w))?; + Vector::write(&mut writer, &self.parents, |w, e| { + Optional::write(w, e, |w, n| n.write(w)) + }) + } + /// Returns the number of notes in the tree. pub fn size(&self) -> usize { self.parents.iter().enumerate().fold( @@ -212,6 +244,29 @@ impl IncrementalWitness { } } + pub fn read(mut reader: R) -> io::Result { + let tree = CommitmentTree::read(&mut reader)?; + let filled = Vector::read(&mut reader, |r| Node::read(r))?; + let cursor = Optional::read(&mut reader, |r| CommitmentTree::read(r))?; + + let mut witness = IncrementalWitness { + tree, + filled, + cursor_depth: 0, + cursor, + }; + + witness.cursor_depth = witness.next_depth(); + + Ok(witness) + } + + pub fn write(&self, mut writer: W) -> io::Result<()> { + self.tree.write(&mut writer)?; + Vector::write(&mut writer, &self.filled, |w, n| n.write(w))?; + Optional::write(&mut writer, &self.cursor, |w, t| t.write(w)) + } + /// Returns the position of the witnessed note in the commitment tree. pub fn position(&self) -> usize { self.tree.size() - 1 @@ -452,6 +507,7 @@ mod tests { use ff::PrimeFieldRepr; use hex; use pairing::bls12_381::FrRepr; + use std::io::{self, Read, Write}; const HEX_EMPTY_ROOTS: [&str; 33] = [ "0100000000000000000000000000000000000000000000000000000000000000", @@ -498,6 +554,15 @@ mod tests { TestCommitmentTree(CommitmentTree::new()) } + pub fn read(reader: R) -> io::Result { + let tree = CommitmentTree::read(reader)?; + Ok(TestCommitmentTree(tree)) + } + + pub fn write(&self, writer: W) -> io::Result<()> { + self.0.write(writer) + } + fn size(&self) -> usize { self.0.size() } @@ -518,6 +583,15 @@ mod tests { TestIncrementalWitness(IncrementalWitness::from_tree(&tree.0)) } + pub fn read(reader: R) -> io::Result { + let witness = IncrementalWitness::read(reader)?; + Ok(TestIncrementalWitness(witness)) + } + + pub fn write(&self, writer: W) -> io::Result<()> { + self.0.write(writer) + } + fn append(&mut self, node: Node) -> Result<(), ()> { self.0.append_inner(node, TESTING_DEPTH) } @@ -613,6 +687,26 @@ mod tests { "5c0bea7e17bde5bee4eb795c2eec3d389a68da587b36dd687b134826ecc09308", ]; + // From https://github.com/zcash/zcash/blob/master/src/test/data/merkle_serialization_sapling.json + let tree_ser = [ + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f550000", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b1145800", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c00010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc12000200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f655186564", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f655186564", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e000201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f655186564", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f655186564", + "013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744600030000010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d", + "013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f163008030000010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d", + "01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702000301cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173200010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d", + "01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080301cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173200010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d", + "018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e82600030001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d", + "018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c03030001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d", + "01f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0003015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c34901002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d", + "01f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c013a3661bc12b72646c94bc6c92796e81953985ee62d80a9ec3645a9a95740ac1503015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c34901002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d", + ]; + // From https://github.com/zcash/zcash/blob/master/src/test/data/merkle_path_sapling.json let paths = [ "0420d8283386ef2ef07ebdbb4383c12a739a953a4d6e0d6fb1139a4036d693bfbb6c20ffe9fc03f18b176c998806439ff0bb8ad193afdb27b2ccbc88856916dd804e3420817de36ab2d57feb077634bca77819c8e0bd298c04f6fed0e6a83cc1356ca15520225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580000000000000000", @@ -737,6 +831,146 @@ mod tests { "04200d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d20002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c205991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c349203a3661bc12b72646c94bc6c92796e81953985ee62d80a9ec3645a9a95740ac150e00000000000000", ]; + // From https://github.com/zcash/zcash/blob/master/src/test/data/merkle_witness_serialization_sapling.json + let witness_ser = [ + "00000001b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5500", + "00000002b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b1145800", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000001225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b1145800", + "00000002b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b1145801017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0000", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000001225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b1145801017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0000", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458000001017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0000", + "00000003b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826400", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000002225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826400", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580001f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a826400", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c00010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6660150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a03000", + "00000003b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a82640101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc120000", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000002225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a82640101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc120000", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580001f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a82640101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc120000", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c00010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6660150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc120000", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666000101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc120000", + "00000003b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a82640101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a0200", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000002225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a82640101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a0200", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580001f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a82640101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a0200", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c00010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6660150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a0200", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666000101aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a0200", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc12000200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a0200", + "00000003b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a82640101bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e000101eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000002225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a82640101bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e000101eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580001f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a82640101bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e000101eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c00010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6660150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a0300101bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e000101eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e666000101bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e000101eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc12000200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020101bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e0000", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f655186564000101bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e0000", + "00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2400", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2400", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580002f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2400", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c00010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6660250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2400", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e66601130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2400", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc12000200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656402f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a02d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c00", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c00", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e000201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a51100", + "00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774460000", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774460000", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580002f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774460000", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c00010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6660250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774460000", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e66601130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774460000", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc12000200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656402f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a02d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c01013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774460000", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c01013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774460000", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e000201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a51101013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774460000", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f6551865640001013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f774460000", + "00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f16300800", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f16300800", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580002f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f16300800", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c00010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6660250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f16300800", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e66601130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f16300800", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc12000200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656402f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a02d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c01013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f16300800", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c01013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f16300800", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e000201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a51101013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f16300800", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f6551865640001013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f16300800", + "013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744600030000010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d01c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f16300800", + "00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f240101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702000101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f240101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702000101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580002f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f240101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702000101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c00010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6660250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f240101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702000101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e66601130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f240101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702000101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc12000200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656402f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a02d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c0101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702000101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c0101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702000101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e000201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702000101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f655186564000101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702000101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744600030000010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d01c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f1630080101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020000", + "013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f163008030000010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d000101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c37020000", + "00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f240101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f240101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580002f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f240101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c00010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6660250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f240101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e66601130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f240101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc12000200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656402f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a02d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c0101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c0101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e000201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f655186564000101f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080101cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef31732", + "013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744600030000010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d02c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f163008635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b614400", + "013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f163008030000010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d01635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b614400", + "01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702000301cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173200010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d01e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60800", + "00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e82600020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e82600020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580002f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e82600020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c00010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6660250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e82600020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e66601130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e82600020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc12000200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656402f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a02d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c01018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e82600020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c01018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e82600020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e000201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a51101018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e82600020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f6551865640001018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e82600020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744600030000010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d02c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f163008635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b614401018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260000", + "013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f163008030000010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d01635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b614401018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260000", + "01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702000301cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173200010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d01e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60801018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260000", + "01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080301cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173200010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d0001018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260000", + "00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c03020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c03020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580002f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c03020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c00010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6660250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c03020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e66601130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f2401018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c03020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc12000200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656402f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a02d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c01018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c03020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c01018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c03020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e000201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a51101018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c03020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f6551865640001018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c03020001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744600030000010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d02c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f163008635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b614401018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c0300", + "013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f163008030000010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d01635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b614401018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c0300", + "01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702000301cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173200010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d01e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c60801018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c0300", + "01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080301cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173200010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d0001018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c0300", + "018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e82600030001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d0122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c0300", + "00000004b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f240101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c34901002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000003225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f240101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c34901002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580002f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f240101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c34901002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c00010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6660250421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f240101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c34901002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e66601130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f240101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c34901002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc12000200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656402f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a02d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c0101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c34901002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c0101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c34901002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e000201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656401da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c34901002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f655186564000101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0002015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c34901002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c", + "013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744600030000010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d02c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f163008635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b61440101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0001015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c349", + "013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f163008030000010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d01635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b61440101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0001015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c349", + "01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702000301cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173200010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d01e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0001015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c349", + "01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080301cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173200010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d000101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0001015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c349", + "018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e82600030001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d0122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c030101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0000", + "018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c03030001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d000101f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0000", + "00000005b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f241d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c00", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f55000004225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b11458f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f241d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c00", + "01b02310f2e087e55bfd07ef5e242e3b87ee5d00c9ab52f61e6bd42542f93a6f5501225747f3b5d5dab4e5a424f81f85c904ff43286e0f3fd07ef0b8c6a627b114580003f2c6ff34520c4ed63159b5ad4e99712fe64e3b4add73c66218e9797ac15a8264130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f241d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c00", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c00010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e6660350421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f241d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c00", + "017c3ea01a6e3a3d90cf59cd789e467044b5cd78eb2c84cc6816f960746d0e036c0150421d6c2c94571dfaaa135a4ff15bf916681ebd62c0e43e69e3b90684d0a030010162324ff2c329e99193a74d28a585a3c167a93bf41a255135529c913bd9b1e66602130adab3afe0931c42f058efb1381c2dce6cc768ad7964330146bf88b2b34f241d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c00", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc12000200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656403f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a02d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c1d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c00", + "01aaec63863aaa0b2e3b8009429bdddd455e59be6f40ccab887a32eb98723efc1201f76748d40d5ee5f9a608512e7954dd515f86e8f6d009141c89163de1cf351a020200011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656402d0c26e22b78df58552b4fd61e8883a70f9011556b2e14b80ff23c591db7dbc4c1d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c00", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e000201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f65518656402da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5111d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c00", + "01bc8a5ec71647415c380203b681f7717366f3501661512225b6dc3e121efc0b2e01da1adda2ccde9381e11151686c121e7f52d19a990439161c7eb5a9f94be5a5110201eb97b35d826f55a65e23ea7febf38fadea8517312ca79346c129a277260fd724011fb189b02ad2f7c6b0d09bd5691c4896c28269da3d4ba768b1b446f655186564011d73ff8e39cff60ff0d6402cc752a3351f1b434dccfa1941da3b1e422b73a33c00", + "013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744600030000010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d03c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f163008635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b6144076795f3651049c8895a7d127eb9bb4a17698da400430b33fdd06b1d8160394000", + "013a27fed5dbbc475d3880360e38638c882fd9b273b618fc433106896083f7744601c7ca8f7df8fd997931d33985d935ee2d696856cc09cc516d419ea6365f163008030000010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d02635c0b1b8035705127dc3f672191b4958ad331f9134117e3ba7d721f712b6144076795f3651049c8895a7d127eb9bb4a17698da400430b33fdd06b1d8160394000", + "01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c3702000301cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173200010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d02e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c608076795f3651049c8895a7d127eb9bb4a17698da400430b33fdd06b1d8160394000", + "01f0fa37e8063b139d342246142fc48e7c0c50d0a62c97768589e06466742c370201e6d4d7685894d01b32f7e081ab188930be6c2b9f76d6847b7f382e3dddd7c6080301cca46d2249e0d79669b8ad2e8c3fc5e67a8501112aa4e572fe03a1868ef3173200010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d01076795f3651049c8895a7d127eb9bb4a17698da400430b33fdd06b1d8160394000", + "018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e82600030001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d0222fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c03afa80a9a1bb8b6aad144cfb53e0bab004dd541c8b72025ae694bb60d6050a53200", + "018cebb73be883466d18d3b0c06990520e80b936440a2c9fd184d92a1f06c4e8260122fab8bcdb88154dbf5877ad1e2d7f1b541bc8a5ec1b52266095381339c27c03030001002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d01afa80a9a1bb8b6aad144cfb53e0bab004dd541c8b72025ae694bb60d6050a53200", + "01f43e3aac61e5a753062d4d0508c26ceaf5e4c0c58ba3c956e104b5d2cf67c41c0003015991131c5c25911b35fcea2a8343e2dfd7a4d5b45493390e0cb184394d91c34901002df68503da9247dfde6585cb8c9fa94897cf21735f8fc1b32116ef474de05c010d6b42350c11df4fcc17987c13d8492ba4e8b3f31eb9baff9be5d8890cfa512d013a3661bc12b72646c94bc6c92796e81953985ee62d80a9ec3645a9a95740ac1500", + ]; + fn assert_root_eq(root: Node, expected: &str) { let mut tmp = [0u8; 32]; root.repr @@ -745,11 +979,39 @@ mod tests { assert_eq!(hex::encode(tmp), expected); } + fn assert_tree_ser_eq(tree: &TestCommitmentTree, expected: &str) { + // Check that the tree matches its encoding + let mut tmp = Vec::new(); + tree.write(&mut tmp).unwrap(); + assert_eq!(hex::encode(&tmp[..]), expected); + + // Check round-trip encoding + let decoded = TestCommitmentTree::read(&hex::decode(expected).unwrap()[..]).unwrap(); + tmp.clear(); + decoded.write(&mut tmp).unwrap(); + assert_eq!(hex::encode(tmp), expected); + } + + fn assert_witness_ser_eq(witness: &TestIncrementalWitness, expected: &str) { + // Check that the witness matches its encoding + let mut tmp = Vec::new(); + witness.write(&mut tmp).unwrap(); + assert_eq!(hex::encode(&tmp[..]), expected); + + // Check round-trip encoding + let decoded = + TestIncrementalWitness::read(&hex::decode(expected).unwrap()[..]).unwrap(); + tmp.clear(); + decoded.write(&mut tmp).unwrap(); + assert_eq!(hex::encode(tmp), expected); + } + let mut tree = TestCommitmentTree::new(); assert_eq!(tree.size(), 0); let mut witnesses = vec![]; let mut paths_i = 0; + let mut witness_ser_i = 0; for i in 0..16 { let mut cm = FrRepr::default(); cm.read_le(&hex::decode(commitments[i]).unwrap()[..]) @@ -769,6 +1031,9 @@ mod tests { // Check tree root consistency assert_root_eq(tree.root(), roots[i]); + // Check serialization of tree + assert_tree_ser_eq(&tree, tree_ser[i]); + let mut first = true; // The first witness can never form a path for witness in witnesses.as_mut_slice() { // Append the same commitment to all the witnesses @@ -787,6 +1052,10 @@ mod tests { paths_i += 1; } + // Check witness serialization + assert_witness_ser_eq(witness, witness_ser[witness_ser_i]); + witness_ser_i += 1; + assert_eq!(witness.root(), tree.root()); first = false; From 98d7621135b8abcd68a04ab56c20a418edbac047 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 19 Mar 2019 22:10:34 +1300 Subject: [PATCH 017/330] Don't assert when parsing a CommitmentTreeWitness --- zcash_primitives/src/merkle_tree.rs | 31 ++++++++++++++++++----------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 8fbc2a3..3608335 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -436,9 +436,11 @@ impl CommitmentTreeWitness { } pub fn from_slice_with_depth(mut witness: &[u8], depth: usize) -> Result { - // Skip the first byte, which should be "32" to signify the length of + // Skip the first byte, which should be "depth" to signify the length of // the following vector of Pedersen hashes. - assert_eq!(witness[0], depth as u8); + if witness[0] != depth as u8 { + return Err(()); + } witness = &witness[1..]; // Begin to construct the authentication path @@ -447,7 +449,9 @@ impl CommitmentTreeWitness { // The vector works in reverse for i in (0..depth).rev() { // skip length of inner vector - assert_eq!(witness[0], 32); // the length of a pedersen hash + if witness[0] != 32 { // the length of a pedersen hash + return Err(()); + } witness = &witness[1..]; // Grab the sibling node at this depth in the tree @@ -472,9 +476,10 @@ impl CommitmentTreeWitness { } // Read the position from the witness - let position = witness - .read_u64::() - .expect("should have had index at the end"); + let position = match witness.read_u64::() { + Ok(pos) => pos, + Err(_) => return Err(()), + }; // Given the position, let's finish constructing the authentication // path @@ -488,12 +493,14 @@ impl CommitmentTreeWitness { // The witness should be empty now; if it wasn't, the caller would // have provided more information than they should have, indicating // a bug downstream - assert_eq!(witness.len(), 0); - - Ok(CommitmentTreeWitness { - auth_path, - position, - }) + if witness.is_empty() { + Ok(CommitmentTreeWitness { + auth_path, + position, + }) + } else { + Err(()) + } } } From 263bbe1207b1c3c9e9014f9f74648e110bc35eae Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 19 Mar 2019 22:11:29 +1300 Subject: [PATCH 018/330] Use Iterator::all() in place of Iterator::fold() --- zcash_primitives/src/merkle_tree.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 3608335..0a830ba 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -145,7 +145,7 @@ impl CommitmentTree { self.left.is_some() && self.right.is_some() && self.parents.len() == depth - 1 - && self.parents.iter().fold(true, |acc, p| acc && p.is_some()) + && self.parents.iter().all(|p| p.is_some()) } /// Adds a note to the tree. Returns an error if the tree is full. From b9cea33804fa5fb8390162ba2e8a54744b55485e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 16 Apr 2019 00:27:44 +0100 Subject: [PATCH 019/330] Move merkle_tree::Node into sapling module This makes the merkle_tree module properly generic over the tree hash. It still hard-codes a depth 32 tree, because Rust doesn't yet support generic sizes, and we are unlikely to need to alter the tree depth in future circuit changes. --- zcash_primitives/src/merkle_tree.rs | 153 +++++++++------------------- zcash_primitives/src/sapling.rs | 64 +++++++++++- zcash_proofs/src/sapling/prover.rs | 10 +- 3 files changed, 118 insertions(+), 109 deletions(-) diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 0a830ba..08bf992 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -1,81 +1,35 @@ use byteorder::{LittleEndian, ReadBytesExt}; -use ff::{PrimeField, PrimeFieldRepr}; -use pairing::bls12_381::{Bls12, Fr, FrRepr}; -use sapling_crypto::{circuit::sapling::TREE_DEPTH, primitives::Note}; +use sapling_crypto::circuit::sapling::TREE_DEPTH; use std::collections::VecDeque; use std::io::{self, Read, Write}; use std::iter; -use sapling::merkle_hash; +use sapling::SAPLING_COMMITMENT_TREE_DEPTH; use serialize::{Optional, Vector}; -const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32; +/// A hashable node within a Merkle tree. +pub trait Hashable: Clone + Copy { + /// Parses a node from the given byte source. + fn read(reader: R) -> io::Result; + + /// Serializes this node. + fn write(&self, writer: W) -> io::Result<()>; -trait Hashable: Clone + Copy { /// Returns the parent node within the tree of the two given nodes. fn combine(usize, &Self, &Self) -> Self; /// Returns a blank leaf node. fn blank() -> Self; + + /// Returns the empty root for the given depth. + fn empty_root(usize) -> Self; } -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Node { - repr: FrRepr, -} - -impl Node { - pub fn new(repr: FrRepr) -> Self { - Node { repr } - } - - pub fn read(mut reader: R) -> io::Result { - let mut repr = FrRepr::default(); - repr.read_le(&mut reader)?; - Ok(Node::new(repr)) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - self.repr.write_le(&mut writer) - } -} - -impl Hashable for Node { - fn combine(depth: usize, lhs: &Self, rhs: &Self) -> Self { - Node { - repr: merkle_hash(depth, &lhs.repr, &rhs.repr), - } - } - - fn blank() -> Self { - Node { - repr: Note::::uncommitted().into_repr(), - } - } -} - -impl From for Fr { - fn from(node: Node) -> Self { - Fr::from_repr(node.repr).expect("Tree nodes should be in the prime field") - } -} - -lazy_static! { - static ref EMPTY_ROOTS: Vec = { - let mut v = vec![Node::blank()]; - for d in 0..SAPLING_COMMITMENT_TREE_DEPTH { - let next = Node::combine(d, &v[d], &v[d]); - v.push(next); - } - v - }; -} - -struct PathFiller { +struct PathFiller { queue: VecDeque, } -impl PathFiller { +impl PathFiller { fn empty() -> Self { PathFiller { queue: VecDeque::new(), @@ -83,19 +37,21 @@ impl PathFiller { } fn next(&mut self, depth: usize) -> Node { - self.queue.pop_front().unwrap_or_else(|| EMPTY_ROOTS[depth]) + self.queue + .pop_front() + .unwrap_or_else(|| Node::empty_root(depth)) } } /// A Merkle tree of Sapling note commitments. #[derive(Clone)] -pub struct CommitmentTree { +pub struct CommitmentTree { left: Option, right: Option, parents: Vec>, } -impl CommitmentTree { +impl CommitmentTree { /// Creates an empty tree. pub fn new() -> Self { CommitmentTree { @@ -192,7 +148,7 @@ impl CommitmentTree { self.root_inner(SAPLING_COMMITMENT_TREE_DEPTH, PathFiller::empty()) } - fn root_inner(&self, depth: usize, mut filler: PathFiller) -> Node { + fn root_inner(&self, depth: usize, mut filler: PathFiller) -> Node { assert!(depth > 0); // 1) Hash left and right leaves together. @@ -227,15 +183,15 @@ impl CommitmentTree { } #[derive(Clone)] -pub struct IncrementalWitness { - tree: CommitmentTree, +pub struct IncrementalWitness { + tree: CommitmentTree, filled: Vec, cursor_depth: usize, - cursor: Option, + cursor: Option>, } -impl IncrementalWitness { - pub fn from_tree(tree: &CommitmentTree) -> IncrementalWitness { +impl IncrementalWitness { + pub fn from_tree(tree: &CommitmentTree) -> IncrementalWitness { IncrementalWitness { tree: tree.clone(), filled: vec![], @@ -272,7 +228,7 @@ impl IncrementalWitness { self.tree.size() - 1 } - fn filler(&self) -> PathFiller { + fn filler(&self) -> PathFiller { let cursor_root = self .cursor .as_ref() @@ -374,11 +330,11 @@ impl IncrementalWitness { } /// Returns the current witness, or None if the tree is empty. - pub fn path(&self) -> Option { + pub fn path(&self) -> Option> { self.path_inner(SAPLING_COMMITMENT_TREE_DEPTH) } - fn path_inner(&self, depth: usize) -> Option { + fn path_inner(&self, depth: usize) -> Option> { let mut filler = self.filler(); let mut auth_path = Vec::new(); @@ -406,10 +362,7 @@ impl IncrementalWitness { assert_eq!(auth_path.len(), depth); Some(CommitmentTreeWitness::from_path( - auth_path - .iter() - .map(|n| n.map(|(node, b)| (node.into(), b))) - .collect(), + auth_path, self.position() as u64, )) } @@ -418,13 +371,13 @@ impl IncrementalWitness { /// A witness to a path from a position in a particular Sapling commitment tree /// to the root of that tree. #[derive(Debug, PartialEq)] -pub struct CommitmentTreeWitness { - pub auth_path: Vec>, +pub struct CommitmentTreeWitness { + pub auth_path: Vec>, pub position: u64, } -impl CommitmentTreeWitness { - pub fn from_path(auth_path: Vec>, position: u64) -> Self { +impl CommitmentTreeWitness { + pub fn from_path(auth_path: Vec>, position: u64) -> Self { CommitmentTreeWitness { auth_path, position, @@ -449,7 +402,8 @@ impl CommitmentTreeWitness { // The vector works in reverse for i in (0..depth).rev() { // skip length of inner vector - if witness[0] != 32 { // the length of a pedersen hash + if witness[0] != 32 { + // the length of a pedersen hash return Err(()); } witness = &witness[1..]; @@ -460,11 +414,7 @@ impl CommitmentTreeWitness { witness = &witness[32..]; // Sibling node should be an element of Fr - let sibling = match { - let mut repr = FrRepr::default(); - repr.read_le(&sibling[..]).expect("length is 32 bytes"); - Fr::from_repr(repr) - } { + let sibling = match Node::read(&sibling[..]) { Ok(p) => p, Err(_) => return Err(()), }; @@ -506,10 +456,8 @@ impl CommitmentTreeWitness { #[cfg(test)] mod tests { - use super::{ - CommitmentTree, CommitmentTreeWitness, Hashable, IncrementalWitness, Node, PathFiller, - EMPTY_ROOTS, - }; + use super::{CommitmentTree, CommitmentTreeWitness, Hashable, IncrementalWitness, PathFiller}; + use sapling::Node; use ff::PrimeFieldRepr; use hex; @@ -554,7 +502,7 @@ mod tests { const TESTING_DEPTH: usize = 4; - struct TestCommitmentTree(CommitmentTree); + struct TestCommitmentTree(CommitmentTree); impl TestCommitmentTree { fn new() -> Self { @@ -583,7 +531,7 @@ mod tests { } } - struct TestIncrementalWitness(IncrementalWitness); + struct TestIncrementalWitness(IncrementalWitness); impl TestIncrementalWitness { fn from_tree(tree: &TestCommitmentTree) -> Self { @@ -607,7 +555,7 @@ mod tests { self.0.root_inner(TESTING_DEPTH) } - fn path(&self) -> Option { + fn path(&self) -> Option> { self.0.path_inner(TESTING_DEPTH) } } @@ -616,9 +564,8 @@ mod tests { fn empty_root_test_vectors() { let mut tmp = [0u8; 32]; for i in 0..HEX_EMPTY_ROOTS.len() { - EMPTY_ROOTS[i] - .repr - .write_le(&mut tmp[..]) + Node::empty_root(i) + .write(&mut tmp[..]) .expect("length is 32 bytes"); assert_eq!(hex::encode(tmp), HEX_EMPTY_ROOTS[i]); } @@ -627,10 +574,9 @@ mod tests { #[test] fn sapling_empty_root() { let mut tmp = [0u8; 32]; - CommitmentTree::new() + CommitmentTree::::new() .root() - .repr - .write_le(&mut tmp[..]) + .write(&mut tmp[..]) .expect("length is 32 bytes"); assert_eq!( hex::encode(tmp), @@ -640,12 +586,11 @@ mod tests { #[test] fn empty_commitment_tree_roots() { - let tree = CommitmentTree::new(); + let tree = CommitmentTree::::new(); let mut tmp = [0u8; 32]; for i in 1..HEX_EMPTY_ROOTS.len() { tree.root_inner(i, PathFiller::empty()) - .repr - .write_le(&mut tmp[..]) + .write(&mut tmp[..]) .expect("length is 32 bytes"); assert_eq!(hex::encode(tmp), HEX_EMPTY_ROOTS[i]); } @@ -980,9 +925,7 @@ mod tests { fn assert_root_eq(root: Node, expected: &str) { let mut tmp = [0u8; 32]; - root.repr - .write_le(&mut tmp[..]) - .expect("length is 32 bytes"); + root.write(&mut tmp[..]).expect("length is 32 bytes"); assert_eq!(hex::encode(tmp), expected); } diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index 62f5118..356f072 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -1,14 +1,19 @@ -use ff::{BitIterator, PrimeField}; +use ff::{BitIterator, PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use rand::OsRng; use sapling_crypto::{ jubjub::{fs::Fs, FixedGenerators, JubjubBls12}, pedersen_hash::{pedersen_hash, Personalization}, + primitives::Note, redjubjub::{PrivateKey, PublicKey, Signature}, }; +use std::io::{self, Read, Write}; +use crate::merkle_tree::Hashable; use JUBJUB; +pub(crate) const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32; + /// Compute a parent node in the Sapling commitment tree given its two children. pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr { let lhs = { @@ -40,6 +45,63 @@ pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr { .into_repr() } +/// A node within a Merkle tree. +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Node { + repr: FrRepr, +} + +impl Node { + pub fn new(repr: FrRepr) -> Self { + Node { repr } + } +} + +impl Hashable for Node { + fn read(mut reader: R) -> io::Result { + let mut repr = FrRepr::default(); + repr.read_le(&mut reader)?; + Ok(Node::new(repr)) + } + + fn write(&self, mut writer: W) -> io::Result<()> { + self.repr.write_le(&mut writer) + } + + fn combine(depth: usize, lhs: &Self, rhs: &Self) -> Self { + Node { + repr: merkle_hash(depth, &lhs.repr, &rhs.repr), + } + } + + fn blank() -> Self { + Node { + repr: Note::::uncommitted().into_repr(), + } + } + + fn empty_root(depth: usize) -> Self { + EMPTY_ROOTS[depth] + } +} + +impl From for Fr { + fn from(node: Node) -> Self { + Fr::from_repr(node.repr).expect("Tree nodes should be in the prime field") + } +} + +lazy_static! { + static ref EMPTY_ROOTS: Vec = { + let mut v = vec![Node::blank()]; + for d in 0..SAPLING_COMMITMENT_TREE_DEPTH { + let next = Node::combine(d, &v[d], &v[d]); + v.push(next); + } + v + }; +} + /// Create the spendAuthSig for a Sapling SpendDescription. pub fn spend_sig( ask: PrivateKey, diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index feb1d2c..4d63033 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -13,7 +13,7 @@ use sapling_crypto::{ primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, redjubjub::{PrivateKey, PublicKey, Signature}, }; -use zcash_primitives::merkle_tree::CommitmentTreeWitness; +use zcash_primitives::{merkle_tree::CommitmentTreeWitness, sapling::Node}; use super::compute_value_balance; @@ -43,7 +43,7 @@ impl SaplingProvingContext { ar: Fs, value: u64, anchor: Fr, - witness: CommitmentTreeWitness, + witness: CommitmentTreeWitness, proving_key: &Parameters, verifying_key: &PreparedVerifyingKey, params: &JubjubBls12, @@ -112,7 +112,11 @@ impl SaplingProvingContext { payment_address: Some(payment_address), commitment_randomness: Some(rcm), ar: Some(ar), - auth_path: witness.auth_path, + auth_path: witness + .auth_path + .iter() + .map(|n| n.map(|(node, b)| (node.into(), b))) + .collect(), anchor: Some(anchor), }; From e67560b154a203601a45faef346c3bf5be99a7f7 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 16 Apr 2019 08:29:09 +0100 Subject: [PATCH 020/330] Document merkle_tree module --- zcash_primitives/src/merkle_tree.rs | 62 ++++++++++++++++++++++++++--- zcash_primitives/src/sapling.rs | 4 +- 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 08bf992..3b4af3a 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -1,3 +1,5 @@ +//! Implementation of a Merkle tree of commitments used to prove the existence of notes. + use byteorder::{LittleEndian, ReadBytesExt}; use sapling_crypto::circuit::sapling::TREE_DEPTH; use std::collections::VecDeque; @@ -43,7 +45,10 @@ impl PathFiller { } } -/// A Merkle tree of Sapling note commitments. +/// A Merkle tree of note commitments. +/// +/// The depth of the Merkle tree is fixed at 32, equal to the depth of the Sapling +/// commitment tree. #[derive(Clone)] pub struct CommitmentTree { left: Option, @@ -61,6 +66,7 @@ impl CommitmentTree { } } + /// Reads a `CommitmentTree` from its serialized form. pub fn read(mut reader: R) -> io::Result { let left = Optional::read(&mut reader, |r| Node::read(r))?; let right = Optional::read(&mut reader, |r| Node::read(r))?; @@ -73,6 +79,7 @@ impl CommitmentTree { }) } + /// Serializes this tree as an array of bytes. pub fn write(&self, mut writer: W) -> io::Result<()> { Optional::write(&mut writer, &self.left, |w, n| n.write(w))?; Optional::write(&mut writer, &self.right, |w, n| n.write(w))?; @@ -104,7 +111,9 @@ impl CommitmentTree { && self.parents.iter().all(|p| p.is_some()) } - /// Adds a note to the tree. Returns an error if the tree is full. + /// Adds a note to the tree. + /// + /// Returns an error if the tree is full. pub fn append(&mut self, node: Node) -> Result<(), ()> { self.append_inner(node, SAPLING_COMMITMENT_TREE_DEPTH) } @@ -182,6 +191,40 @@ impl CommitmentTree { } } +/// An updatable witness to a path from a position in a particular [`CommitmentTree`]. +/// +/// Appending the same commitments in the same order to both the original +/// [`CommitmentTree`] and this `IncrementalWitness` will result in a witness to the path +/// from the target position to the root of the updated tree. +/// +/// # Examples +/// +/// ``` +/// extern crate pairing; +/// extern crate rand; +/// extern crate zcash_primitives; +/// +/// use pairing::bls12_381::FrRepr; +/// use rand::{OsRng, Rand}; +/// use zcash_primitives::{ +/// merkle_tree::{CommitmentTree, IncrementalWitness}, +/// sapling::Node, +/// }; +/// +/// let mut rng = OsRng::new().unwrap(); +/// let mut tree = CommitmentTree::::new(); +/// +/// tree.append(Node::new(FrRepr::rand(&mut rng))); +/// tree.append(Node::new(FrRepr::rand(&mut rng))); +/// let mut witness = IncrementalWitness::from_tree(&tree); +/// assert_eq!(witness.position(), 1); +/// assert_eq!(tree.root(), witness.root()); +/// +/// let cmu = Node::new(FrRepr::rand(&mut rng)); +/// tree.append(cmu); +/// witness.append(cmu); +/// assert_eq!(tree.root(), witness.root()); +/// ``` #[derive(Clone)] pub struct IncrementalWitness { tree: CommitmentTree, @@ -191,6 +234,8 @@ pub struct IncrementalWitness { } impl IncrementalWitness { + /// Creates an `IncrementalWitness` for the most recent commitment added to the given + /// [`CommitmentTree`]. pub fn from_tree(tree: &CommitmentTree) -> IncrementalWitness { IncrementalWitness { tree: tree.clone(), @@ -200,6 +245,7 @@ impl IncrementalWitness { } } + /// Reads an `IncrementalWitness` from its serialized form. pub fn read(mut reader: R) -> io::Result { let tree = CommitmentTree::read(&mut reader)?; let filled = Vector::read(&mut reader, |r| Node::read(r))?; @@ -217,6 +263,7 @@ impl IncrementalWitness { Ok(witness) } + /// Serializes this `IncrementalWitness` as an array of bytes. pub fn write(&self, mut writer: W) -> io::Result<()> { self.tree.write(&mut writer)?; Vector::write(&mut writer, &self.filled, |w, n| n.write(w))?; @@ -282,8 +329,9 @@ impl IncrementalWitness { d + skip } - /// Tracks a note that has been added to the underlying tree. Returns an - /// error if the tree is full. + /// Tracks a note that has been added to the underlying tree. + /// + /// Returns an error if the tree is full. pub fn append(&mut self, node: Node) -> Result<(), ()> { self.append_inner(node, SAPLING_COMMITMENT_TREE_DEPTH) } @@ -368,8 +416,8 @@ impl IncrementalWitness { } } -/// A witness to a path from a position in a particular Sapling commitment tree -/// to the root of that tree. +/// A witness to a path from a position in a particular commitment tree to the root of +/// that tree. #[derive(Debug, PartialEq)] pub struct CommitmentTreeWitness { pub auth_path: Vec>, @@ -377,6 +425,7 @@ pub struct CommitmentTreeWitness { } impl CommitmentTreeWitness { + /// Constructs a witness directly from its path and position. pub fn from_path(auth_path: Vec>, position: u64) -> Self { CommitmentTreeWitness { auth_path, @@ -384,6 +433,7 @@ impl CommitmentTreeWitness { } } + /// Reads a witness from its serialized form. pub fn from_slice(witness: &[u8]) -> Result { Self::from_slice_with_depth(witness, TREE_DEPTH) } diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index 356f072..517d9fd 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -1,3 +1,5 @@ +//! Structs and constants specific to the Sapling shielded pool. + use ff::{BitIterator, PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use rand::OsRng; @@ -45,7 +47,7 @@ pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr { .into_repr() } -/// A node within a Merkle tree. +/// A node within the Sapling commitment tree. #[derive(Clone, Copy, Debug, PartialEq)] pub struct Node { repr: FrRepr, From 79006ecbdff7a216b78025252fd13c4709f197f2 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 16 Apr 2019 08:40:38 +0100 Subject: [PATCH 021/330] Unify Sapling tree depth constants When sapling-crypto is refactored, the zcash_primitives::sapling constant would become the canonical one. --- zcash_primitives/src/merkle_tree.rs | 5 ++--- zcash_primitives/src/sapling.rs | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 3b4af3a..2dcc5cc 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -1,7 +1,6 @@ //! Implementation of a Merkle tree of commitments used to prove the existence of notes. use byteorder::{LittleEndian, ReadBytesExt}; -use sapling_crypto::circuit::sapling::TREE_DEPTH; use std::collections::VecDeque; use std::io::{self, Read, Write}; use std::iter; @@ -435,10 +434,10 @@ impl CommitmentTreeWitness { /// Reads a witness from its serialized form. pub fn from_slice(witness: &[u8]) -> Result { - Self::from_slice_with_depth(witness, TREE_DEPTH) + Self::from_slice_with_depth(witness, SAPLING_COMMITMENT_TREE_DEPTH) } - pub fn from_slice_with_depth(mut witness: &[u8], depth: usize) -> Result { + fn from_slice_with_depth(mut witness: &[u8], depth: usize) -> Result { // Skip the first byte, which should be "depth" to signify the length of // the following vector of Pedersen hashes. if witness[0] != depth as u8 { diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index 517d9fd..0ee808c 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -14,7 +14,8 @@ use std::io::{self, Read, Write}; use crate::merkle_tree::Hashable; use JUBJUB; -pub(crate) const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32; +pub(crate) const SAPLING_COMMITMENT_TREE_DEPTH: usize = + sapling_crypto::circuit::sapling::TREE_DEPTH; /// Compute a parent node in the Sapling commitment tree given its two children. pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr { From 07dbfbef591d39029afef1ae84b52dab116fd0c3 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 3 Jun 2019 11:14:01 +0100 Subject: [PATCH 022/330] Address Eirik's review comments --- zcash_primitives/src/merkle_tree.rs | 8 ++++---- zcash_primitives/src/serialize.rs | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 2dcc5cc..e48f8ee 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -90,10 +90,10 @@ impl CommitmentTree { /// Returns the number of notes in the tree. pub fn size(&self) -> usize { self.parents.iter().enumerate().fold( - match (self.left.is_some(), self.right.is_some()) { - (false, false) => 0, - (true, false) | (false, true) => 1, - (true, true) => 2, + match (self.left, self.right) { + (None, None) => 0, + (Some(_), None) | (None, Some(_)) => 1, + (Some(_), Some(_)) => 2, }, |acc, (i, p)| { // Treat occupation of parents array as a binary number diff --git a/zcash_primitives/src/serialize.rs b/zcash_primitives/src/serialize.rs index 8312312..41778dc 100644 --- a/zcash_primitives/src/serialize.rs +++ b/zcash_primitives/src/serialize.rs @@ -221,6 +221,7 @@ mod tests { eval_u8!(Some(1), [1, 1]); eval_u8!(Some(5), [1, 5]); + eval_vec!(None as Option>, [0]); eval_vec!(Some(vec![]), [1, 0]); eval_vec!(Some(vec![0]), [1, 1, 0]); eval_vec!(Some(vec![1]), [1, 1, 1]); From 504c3eaeae9685bf2fe48a21aa0bc150d135409c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 15 Jul 2019 16:33:43 +0200 Subject: [PATCH 023/330] Address Daira's review comments --- zcash_primitives/src/merkle_tree.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index e48f8ee..118d7db 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -87,13 +87,14 @@ impl CommitmentTree { }) } - /// Returns the number of notes in the tree. + /// Returns the number of leaf nodes in the tree. pub fn size(&self) -> usize { self.parents.iter().enumerate().fold( match (self.left, self.right) { (None, None) => 0, - (Some(_), None) | (None, Some(_)) => 1, + (Some(_), None) => 1, (Some(_), Some(_)) => 2, + (None, Some(_)) => unreachable!(), }, |acc, (i, p)| { // Treat occupation of parents array as a binary number @@ -110,7 +111,7 @@ impl CommitmentTree { && self.parents.iter().all(|p| p.is_some()) } - /// Adds a note to the tree. + /// Adds a leaf node to the tree. /// /// Returns an error if the tree is full. pub fn append(&mut self, node: Node) -> Result<(), ()> { @@ -269,7 +270,7 @@ impl IncrementalWitness { Optional::write(&mut writer, &self.cursor, |w, t| t.write(w)) } - /// Returns the position of the witnessed note in the commitment tree. + /// Returns the position of the witnessed leaf node in the commitment tree. pub fn position(&self) -> usize { self.tree.size() - 1 } @@ -328,7 +329,7 @@ impl IncrementalWitness { d + skip } - /// Tracks a note that has been added to the underlying tree. + /// Tracks a leaf node that has been added to the underlying tree. /// /// Returns an error if the tree is full. pub fn append(&mut self, node: Node) -> Result<(), ()> { From 7a6642b221b3936aff93b9eeb35d8d112e128de4 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 10 Jul 2019 18:35:05 -0400 Subject: [PATCH 024/330] Migrate ff to rand_core 0.3 (used by rand 0.5) --- Cargo.lock | 17 +++++++++++++++- ff/Cargo.toml | 2 +- ff/ff_derive/src/lib.rs | 43 +++++++++++++++++++---------------------- ff/src/lib.rs | 9 ++++++--- 4 files changed, 43 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03b2a4d..b41ccd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -186,7 +186,7 @@ version = "0.4.0" dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff_derive 0.3.0", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -424,6 +424,19 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "redox_syscall" version = "0.1.40" @@ -623,6 +636,8 @@ dependencies = [ "checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" diff --git a/ff/Cargo.toml b/ff/Cargo.toml index 22db67a..f428ccd 100644 --- a/ff/Cargo.toml +++ b/ff/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/ebfull/ff" [dependencies] byteorder = "1" -rand = "0.4" +rand_core = "0.3" ff_derive = { version = "0.3.0", path = "ff_derive", optional = true } [features] diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index 45d3445..aea7a50 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -136,13 +136,6 @@ fn prime_field_repr_impl(repr: &syn::Ident, limbs: usize) -> proc_macro2::TokenS } } - impl ::rand::Rand for #repr { - #[inline(always)] - fn rand(rng: &mut R) -> Self { - #repr(rng.gen()) - } - } - impl ::std::fmt::Display for #repr { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { try!(write!(f, "0x")); @@ -839,22 +832,6 @@ fn prime_field_impl( } } - impl ::rand::Rand for #name { - /// Computes a uniformly random element using rejection sampling. - fn rand(rng: &mut R) -> Self { - loop { - let mut tmp = #name(#repr::rand(rng)); - - // Mask away the unused bits at the beginning. - tmp.0.as_mut()[#top_limb_index] &= 0xffffffffffffffff >> REPR_SHAVE_BITS; - - if tmp.is_valid() { - return tmp - } - } - } - } - impl From<#name> for #repr { fn from(e: #name) -> #repr { e.into_repr() @@ -904,6 +881,26 @@ fn prime_field_impl( } impl ::ff::Field for #name { + /// Computes a uniformly random element using rejection sampling. + fn random(rng: &mut R) -> Self { + loop { + let mut tmp = { + let mut repr = [0u64; #limbs]; + for i in 0..#limbs { + repr[i] = rng.next_u64(); + } + #name(#repr(repr)) + }; + + // Mask away the unused bits at the beginning. + tmp.0.as_mut()[#top_limb_index] &= 0xffffffffffffffff >> REPR_SHAVE_BITS; + + if tmp.is_valid() { + return tmp + } + } + } + #[inline] fn zero() -> Self { #name(#repr::from(0)) diff --git a/ff/src/lib.rs b/ff/src/lib.rs index a9d117f..482dc46 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -1,7 +1,7 @@ #![allow(unused_imports)] extern crate byteorder; -extern crate rand; +extern crate rand_core; #[cfg(feature = "derive")] #[macro_use] @@ -10,14 +10,18 @@ extern crate ff_derive; #[cfg(feature = "derive")] pub use ff_derive::*; +use rand_core::RngCore; use std::error::Error; use std::fmt; use std::io::{self, Read, Write}; /// This trait represents an element of a field. pub trait Field: - Sized + Eq + Copy + Clone + Send + Sync + fmt::Debug + fmt::Display + 'static + rand::Rand + Sized + Eq + Copy + Clone + Send + Sync + fmt::Debug + fmt::Display + 'static { + /// Returns an element chosen uniformly at random using a user-provided RNG. + fn random(rng: &mut R) -> Self; + /// Returns the zero element of the field, the additive identity. fn zero() -> Self; @@ -100,7 +104,6 @@ pub trait PrimeFieldRepr: + fmt::Debug + fmt::Display + 'static - + rand::Rand + AsRef<[u64]> + AsMut<[u64]> + From From ce6e2a5825a816c5b3bd29b54d76896518a5b1a0 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 10 Jul 2019 18:35:57 -0400 Subject: [PATCH 025/330] Migrate group to rand 0.5 --- Cargo.lock | 30 ++++++++++- group/Cargo.toml | 2 +- group/src/lib.rs | 16 ++---- group/src/tests/mod.rs | 111 +++++++++++++++++++++++++---------------- 4 files changed, 104 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b41ccd8..159946b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,6 +136,14 @@ name = "byteorder" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "constant_time_eq" version = "0.1.3" @@ -213,6 +221,11 @@ dependencies = [ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -267,7 +280,7 @@ name = "group" version = "0.1.0" dependencies = [ "ff 0.4.0", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -424,6 +437,18 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_core" version = "0.3.1" @@ -603,6 +628,7 @@ dependencies = [ "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" "checksum byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "980479e6fde23246dfb54d47580d66b4e99202e7579c5eaa9fe10ecb5ebd2182" "checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crypto_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f855e87e75a4799e18b8529178adcde6fd4f97c1449ff4821e747ff728bb102" @@ -611,6 +637,7 @@ dependencies = [ "checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce3371c82bfbd984f624cab093f55e7336f5a6e589f8518e1258f54f011b89ad" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" @@ -636,6 +663,7 @@ dependencies = [ "checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" +"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" diff --git a/group/Cargo.toml b/group/Cargo.toml index ad3f84d..020a5bd 100644 --- a/group/Cargo.toml +++ b/group/Cargo.toml @@ -14,4 +14,4 @@ repository = "https://github.com/ebfull/group" [dependencies] ff = { path = "../ff" } -rand = "0.4" +rand = "0.5" diff --git a/group/src/lib.rs b/group/src/lib.rs index fc924c3..a97a72c 100644 --- a/group/src/lib.rs +++ b/group/src/lib.rs @@ -2,6 +2,7 @@ extern crate ff; extern crate rand; use ff::{PrimeField, PrimeFieldDecodingError, ScalarEngine, SqrtField}; +use rand::RngCore; use std::error::Error; use std::fmt; @@ -13,23 +14,16 @@ pub use self::wnaf::Wnaf; /// Projective representation of an elliptic curve point guaranteed to be /// in the correct prime order subgroup. pub trait CurveProjective: - PartialEq - + Eq - + Sized - + Copy - + Clone - + Send - + Sync - + fmt::Debug - + fmt::Display - + rand::Rand - + 'static + PartialEq + Eq + Sized + Copy + Clone + Send + Sync + fmt::Debug + fmt::Display + 'static { type Engine: ScalarEngine; type Scalar: PrimeField + SqrtField; type Base: SqrtField; type Affine: CurveAffine; + /// Returns an element chosen uniformly at random using a user-provided RNG. + fn random(rng: &mut R) -> Self; + /// Returns the additive identity. fn zero() -> Self; diff --git a/group/src/tests/mod.rs b/group/src/tests/mod.rs index b4c47db..5d7e546 100644 --- a/group/src/tests/mod.rs +++ b/group/src/tests/mod.rs @@ -1,9 +1,13 @@ -use rand::{Rand, Rng, SeedableRng, XorShiftRng}; +use ff::{Field, PrimeField}; +use rand::{SeedableRng, XorShiftRng}; use {CurveAffine, CurveProjective, EncodedPoint}; pub fn curve_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); // Negation edge case with zero. { @@ -21,7 +25,7 @@ pub fn curve_tests() { // Addition edge cases with zero { - let mut r = G::rand(&mut rng); + let mut r = G::random(&mut rng); let rcopy = r; r.add_assign(&G::zero()); assert_eq!(r, rcopy); @@ -45,9 +49,10 @@ pub fn curve_tests() { // Transformations { - let a = G::rand(&mut rng); + let a = G::random(&mut rng); let b = a.into_affine().into_projective(); - let c = a.into_affine() + let c = a + .into_affine() .into_projective() .into_affine() .into_projective(); @@ -65,11 +70,12 @@ pub fn curve_tests() { } fn random_wnaf_tests() { - use ff::PrimeField; - use wnaf::*; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); { let mut table = vec![]; @@ -77,8 +83,8 @@ fn random_wnaf_tests() { for w in 2..14 { for _ in 0..100 { - let g = G::rand(&mut rng); - let s = G::Scalar::rand(&mut rng).into_repr(); + let g = G::random(&mut rng); + let s = G::Scalar::random(&mut rng).into_repr(); let mut g1 = g; g1.mul_assign(s); @@ -95,8 +101,8 @@ fn random_wnaf_tests() { fn only_compiles_if_send(_: &S) {} for _ in 0..100 { - let g = G::rand(&mut rng); - let s = G::Scalar::rand(&mut rng).into_repr(); + let g = G::random(&mut rng); + let s = G::Scalar::random(&mut rng).into_repr(); let mut g1 = g; g1.mul_assign(s); @@ -129,7 +135,8 @@ fn random_wnaf_tests() { let mut wnaf = Wnaf::new(); { // Populate the vectors. - wnaf.base(rng.gen(), 1).scalar(rng.gen()); + wnaf.base(G::random(&mut rng), 1) + .scalar(G::Scalar::random(&mut rng).into_repr()); } wnaf.base(g, 1).scalar(s) }; @@ -137,7 +144,8 @@ fn random_wnaf_tests() { let mut wnaf = Wnaf::new(); { // Populate the vectors. - wnaf.base(rng.gen(), 1).scalar(rng.gen()); + wnaf.base(G::random(&mut rng), 1) + .scalar(G::Scalar::random(&mut rng).into_repr()); } wnaf.scalar(s).base(g) }; @@ -145,7 +153,8 @@ fn random_wnaf_tests() { let mut wnaf = Wnaf::new(); { // Populate the vectors. - wnaf.base(rng.gen(), 1).scalar(rng.gen()); + wnaf.base(G::random(&mut rng), 1) + .scalar(G::Scalar::random(&mut rng).into_repr()); } let mut shared = wnaf.base(g, 1).shared(); @@ -157,7 +166,8 @@ fn random_wnaf_tests() { let mut wnaf = Wnaf::new(); { // Populate the vectors. - wnaf.base(rng.gen(), 1).scalar(rng.gen()); + wnaf.base(G::random(&mut rng), 1) + .scalar(G::Scalar::random(&mut rng).into_repr()); } let mut shared = wnaf.scalar(s).shared(); @@ -179,14 +189,15 @@ fn random_wnaf_tests() { } fn random_negation_tests() { - use ff::Field; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let r = G::rand(&mut rng); + let r = G::random(&mut rng); - let s = G::Scalar::rand(&mut rng); + let s = G::Scalar::random(&mut rng); let mut sneg = s; sneg.negate(); @@ -210,11 +221,14 @@ fn random_negation_tests() { } fn random_doubling_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let mut a = G::rand(&mut rng); - let mut b = G::rand(&mut rng); + let mut a = G::random(&mut rng); + let mut b = G::random(&mut rng); // 2(a + b) let mut tmp1 = a; @@ -237,15 +251,18 @@ fn random_doubling_tests() { } fn random_multiplication_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let mut a = G::rand(&mut rng); - let mut b = G::rand(&mut rng); + let mut a = G::random(&mut rng); + let mut b = G::random(&mut rng); let a_affine = a.into_affine(); let b_affine = b.into_affine(); - let s = G::Scalar::rand(&mut rng); + let s = G::Scalar::random(&mut rng); // s ( a + b ) let mut tmp1 = a; @@ -269,12 +286,15 @@ fn random_multiplication_tests() { } fn random_addition_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let a = G::rand(&mut rng); - let b = G::rand(&mut rng); - let c = G::rand(&mut rng); + let a = G::random(&mut rng); + let b = G::random(&mut rng); + let c = G::random(&mut rng); let a_affine = a.into_affine(); let b_affine = b.into_affine(); let c_affine = c.into_affine(); @@ -347,10 +367,13 @@ fn random_addition_tests() { } fn random_transformation_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let g = G::rand(&mut rng); + let g = G::random(&mut rng); let g_affine = g.into_affine(); let g_projective = g_affine.into_projective(); assert_eq!(g, g_projective); @@ -358,24 +381,25 @@ fn random_transformation_tests() { // Batch normalization for _ in 0..10 { - let mut v = (0..1000).map(|_| G::rand(&mut rng)).collect::>(); + let mut v = (0..1000).map(|_| G::random(&mut rng)).collect::>(); for i in &v { assert!(!i.is_normalized()); } - use rand::distributions::{IndependentSample, Range}; - let between = Range::new(0, 1000); + use rand::distributions::{Distribution, Uniform}; + let between = Uniform::new(0, 1000); // Sprinkle in some normalized points for _ in 0..5 { - v[between.ind_sample(&mut rng)] = G::zero(); + v[between.sample(&mut rng)] = G::zero(); } for _ in 0..5 { - let s = between.ind_sample(&mut rng); + let s = between.sample(&mut rng); v[s] = v[s].into_affine().into_projective(); } - let expected_v = v.iter() + let expected_v = v + .iter() .map(|v| v.into_affine().into_projective()) .collect::>(); G::batch_normalization(&mut v); @@ -389,7 +413,10 @@ fn random_transformation_tests() { } fn random_encoding_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); assert_eq!( G::zero().into_uncompressed().into_affine().unwrap(), @@ -402,7 +429,7 @@ fn random_encoding_tests() { ); for _ in 0..1000 { - let mut r = G::Projective::rand(&mut rng).into_affine(); + let mut r = G::Projective::random(&mut rng).into_affine(); let uncompressed = r.into_uncompressed(); let de_uncompressed = uncompressed.into_affine().unwrap(); From a7e22b3550d1b129d564af12d86a9e634b10ff2e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 10 Jul 2019 18:36:40 -0400 Subject: [PATCH 026/330] Migrate pairing to rand 0.5 --- Cargo.lock | 3 +- pairing/Cargo.toml | 5 +- pairing/src/bls12_381/ec.rs | 24 ++++--- pairing/src/bls12_381/fq.rs | 121 ++++++++++++++++++++++------------ pairing/src/bls12_381/fq12.rs | 31 ++++----- pairing/src/bls12_381/fq2.rs | 19 +++--- pairing/src/bls12_381/fq6.rs | 46 +++++++------ pairing/src/bls12_381/fr.rs | 121 ++++++++++++++++++++++------------ pairing/src/lib.rs | 3 + pairing/src/tests/engine.rs | 49 ++++++++------ pairing/src/tests/field.rs | 60 ++++++++++------- pairing/src/tests/repr.rs | 45 ++++++++----- 12 files changed, 325 insertions(+), 202 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 159946b..7764696 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -385,7 +385,8 @@ dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "group 0.1.0", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/pairing/Cargo.toml b/pairing/Cargo.toml index 3446f46..b6ba134 100644 --- a/pairing/Cargo.toml +++ b/pairing/Cargo.toml @@ -15,11 +15,14 @@ homepage = "https://github.com/ebfull/pairing" repository = "https://github.com/ebfull/pairing" [dependencies] -rand = "0.4" +rand_core = "0.3" byteorder = "1" ff = { path = "../ff", features = ["derive"] } group = { path = "../group" } +[dev-dependencies] +rand = "0.5" + [features] unstable-features = ["expose-arith"] expose-arith = [] diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index f5a6d8f..b20dea8 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -200,11 +200,16 @@ macro_rules! curve_impl { } - impl Rand for $projective { - fn rand(rng: &mut R) -> Self { + impl CurveProjective for $projective { + type Engine = Bls12; + type Scalar = $scalarfield; + type Base = $basefield; + type Affine = $affine; + + fn random(rng: &mut R) -> Self { loop { - let x = rng.gen(); - let greatest = rng.gen(); + let x = $basefield::random(rng); + let greatest = rng.next_u32() % 2 != 0; if let Some(p) = $affine::get_point_from_x(x, greatest) { let p = p.scale_by_cofactor(); @@ -215,13 +220,6 @@ macro_rules! curve_impl { } } } - } - - impl CurveProjective for $projective { - type Engine = Bls12; - type Scalar = $scalarfield; - type Base = $basefield; - type Affine = $affine; // The point at infinity is always represented by // Z = 0. @@ -629,7 +627,7 @@ pub mod g1 { use super::g2::G2Affine; use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; - use rand::{Rand, Rng}; + use rand_core::RngCore; use std::fmt; use {Engine, PairingCurveAffine}; @@ -1276,7 +1274,7 @@ pub mod g2 { use super::g1::G1Affine; use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; - use rand::{Rand, Rng}; + use rand_core::RngCore; use std::fmt; use {Engine, PairingCurveAffine}; diff --git a/pairing/src/bls12_381/fq.rs b/pairing/src/bls12_381/fq.rs index fd0d416..b006812 100644 --- a/pairing/src/bls12_381/fq.rs +++ b/pairing/src/bls12_381/fq.rs @@ -1173,7 +1173,7 @@ fn test_neg_one() { } #[cfg(test)] -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand::{SeedableRng, XorShiftRng}; #[test] fn test_fq_repr_ordering() { @@ -1396,7 +1396,10 @@ fn test_fq_repr_num_bits() { #[test] fn test_fq_repr_sub_noborrow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let mut t = FqRepr([ 0x827a4a08041ebd9, @@ -1426,7 +1429,7 @@ fn test_fq_repr_sub_noborrow() { ); for _ in 0..1000 { - let mut a = FqRepr::rand(&mut rng); + let mut a = Fq::random(&mut rng).into_repr(); a.0[5] >>= 30; let mut b = a; for _ in 0..10 { @@ -1483,7 +1486,10 @@ fn test_fq_repr_sub_noborrow() { #[test] fn test_fq_repr_add_nocarry() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let mut t = FqRepr([ 0x827a4a08041ebd9, @@ -1514,9 +1520,9 @@ fn test_fq_repr_add_nocarry() { // Test for the associativity of addition. for _ in 0..1000 { - let mut a = FqRepr::rand(&mut rng); - let mut b = FqRepr::rand(&mut rng); - let mut c = FqRepr::rand(&mut rng); + let mut a = Fq::random(&mut rng).into_repr(); + let mut b = Fq::random(&mut rng).into_repr(); + let mut c = Fq::random(&mut rng).into_repr(); // Unset the first few bits, so that overflow won't occur. a.0[5] >>= 3; @@ -1595,10 +1601,13 @@ fn test_fq_is_valid() { ])).is_valid() ); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let a = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); assert!(a.is_valid()); } } @@ -1708,13 +1717,16 @@ fn test_fq_add_assign() { // Test associativity - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Generate a, b, c and ensure (a + b) + c == a + (b + c). - let a = Fq::rand(&mut rng); - let b = Fq::rand(&mut rng); - let c = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); + let b = Fq::random(&mut rng); + let c = Fq::random(&mut rng); let mut tmp1 = a; tmp1.add_assign(&b); @@ -1818,12 +1830,15 @@ fn test_fq_sub_assign() { ); } - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Ensure that (a - b) + (b - a) = 0. - let a = Fq::rand(&mut rng); - let b = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); + let b = Fq::random(&mut rng); let mut tmp1 = a; tmp1.sub_assign(&b); @@ -1865,13 +1880,16 @@ fn test_fq_mul_assign() { ])) ); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000000 { // Ensure that (a * b) * c = a * (b * c) - let a = Fq::rand(&mut rng); - let b = Fq::rand(&mut rng); - let c = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); + let b = Fq::random(&mut rng); + let c = Fq::random(&mut rng); let mut tmp1 = a; tmp1.mul_assign(&b); @@ -1887,10 +1905,10 @@ fn test_fq_mul_assign() { for _ in 0..1000000 { // Ensure that r * (a + b + c) = r*a + r*b + r*c - let r = Fq::rand(&mut rng); - let mut a = Fq::rand(&mut rng); - let mut b = Fq::rand(&mut rng); - let mut c = Fq::rand(&mut rng); + let r = Fq::random(&mut rng); + let mut a = Fq::random(&mut rng); + let mut b = Fq::random(&mut rng); + let mut c = Fq::random(&mut rng); let mut tmp1 = a; tmp1.add_assign(&b); @@ -1932,11 +1950,14 @@ fn test_fq_squaring() { ])).unwrap() ); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000000 { // Ensure that (a * a) = a^2 - let a = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); let mut tmp = a; tmp.square(); @@ -1952,13 +1973,16 @@ fn test_fq_squaring() { fn test_fq_inverse() { assert!(Fq::zero().inverse().is_none()); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let one = Fq::one(); for _ in 0..1000 { // Ensure that a * a^-1 = 1 - let mut a = Fq::rand(&mut rng); + let mut a = Fq::random(&mut rng); let ainv = a.inverse().unwrap(); a.mul_assign(&ainv); assert_eq!(a, one); @@ -1967,11 +1991,14 @@ fn test_fq_inverse() { #[test] fn test_fq_double() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Ensure doubling a is equivalent to adding a to itself. - let mut a = Fq::rand(&mut rng); + let mut a = Fq::random(&mut rng); let mut b = a; b.add_assign(&a); a.double(); @@ -1988,11 +2015,14 @@ fn test_fq_negate() { assert!(a.is_zero()); } - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Ensure (a - (-a)) = 0. - let mut a = Fq::rand(&mut rng); + let mut a = Fq::random(&mut rng); let mut b = a; b.negate(); a.add_assign(&b); @@ -2003,12 +2033,15 @@ fn test_fq_negate() { #[test] fn test_fq_pow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for i in 0..1000 { // Exponentiate by various small numbers and ensure it consists with repeated // multiplication. - let a = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); let target = a.pow(&[i]); let mut c = Fq::one(); for _ in 0..i { @@ -2019,7 +2052,7 @@ fn test_fq_pow() { for _ in 0..1000 { // Exponentiating by the modulus should have no effect in a prime field. - let a = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); assert_eq!(a, a.pow(Fq::char())); } @@ -2029,13 +2062,16 @@ fn test_fq_pow() { fn test_fq_sqrt() { use ff::SqrtField; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); assert_eq!(Fq::zero().sqrt().unwrap(), Fq::zero()); for _ in 0..1000 { // Ensure sqrt(a^2) = a or -a - let a = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); let mut nega = a; nega.negate(); let mut b = a; @@ -2048,7 +2084,7 @@ fn test_fq_sqrt() { for _ in 0..1000 { // Ensure sqrt(a)^2 = a for random a - let a = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); if let Some(mut tmp) = a.sqrt() { tmp.square(); @@ -2108,11 +2144,14 @@ fn test_fq_from_into_repr() { // Zero should be in the field. assert!(Fq::from_repr(FqRepr::from(0)).unwrap().is_zero()); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Try to turn Fq elements into representations and back again, and compare. - let a = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); let a_repr = a.into_repr(); let b_repr = FqRepr::from(a); assert_eq!(a_repr, b_repr); @@ -2205,7 +2244,7 @@ fn test_fq_ordering() { #[test] fn fq_repr_tests() { - ::tests::repr::random_repr_tests::(); + ::tests::repr::random_repr_tests::(); } #[test] diff --git a/pairing/src/bls12_381/fq12.rs b/pairing/src/bls12_381/fq12.rs index b24fcaa..4f675cf 100644 --- a/pairing/src/bls12_381/fq12.rs +++ b/pairing/src/bls12_381/fq12.rs @@ -2,7 +2,7 @@ use super::fq::FROBENIUS_COEFF_FQ12_C1; use super::fq2::Fq2; use super::fq6::Fq6; use ff::Field; -use rand::{Rand, Rng}; +use rand_core::{RngCore}; /// An element of Fq12, represented by c0 + c1 * w. #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -17,15 +17,6 @@ impl ::std::fmt::Display for Fq12 { } } -impl Rand for Fq12 { - fn rand(rng: &mut R) -> Self { - Fq12 { - c0: rng.gen(), - c1: rng.gen(), - } - } -} - impl Fq12 { pub fn conjugate(&mut self) { self.c1.negate(); @@ -49,6 +40,13 @@ impl Fq12 { } impl Field for Fq12 { + fn random(rng: &mut R) -> Self { + Fq12 { + c0: Fq6::random(rng), + c1: Fq6::random(rng), + } + } + fn zero() -> Self { Fq12 { c0: Fq6::zero(), @@ -153,13 +151,16 @@ use rand::{SeedableRng, XorShiftRng}; #[test] fn test_fq12_mul_by_014() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let c0 = Fq2::rand(&mut rng); - let c1 = Fq2::rand(&mut rng); - let c5 = Fq2::rand(&mut rng); - let mut a = Fq12::rand(&mut rng); + let c0 = Fq2::random(&mut rng); + let c1 = Fq2::random(&mut rng); + let c5 = Fq2::random(&mut rng); + let mut a = Fq12::random(&mut rng); let mut b = a; a.mul_by_014(&c0, &c1, &c5); diff --git a/pairing/src/bls12_381/fq2.rs b/pairing/src/bls12_381/fq2.rs index 363439a..c69f13c 100644 --- a/pairing/src/bls12_381/fq2.rs +++ b/pairing/src/bls12_381/fq2.rs @@ -1,6 +1,6 @@ use super::fq::{FROBENIUS_COEFF_FQ2_C1, Fq, NEGATIVE_ONE}; use ff::{Field, SqrtField}; -use rand::{Rand, Rng}; +use rand_core::RngCore; use std::cmp::Ordering; @@ -56,16 +56,14 @@ impl Fq2 { } } -impl Rand for Fq2 { - fn rand(rng: &mut R) -> Self { +impl Field for Fq2 { + fn random(rng: &mut R) -> Self { Fq2 { - c0: rng.gen(), - c1: rng.gen(), + c0: Fq::random(rng), + c1: Fq::random(rng), } } -} -impl Field for Fq2 { fn zero() -> Self { Fq2 { c0: Fq::zero(), @@ -883,7 +881,10 @@ use rand::{SeedableRng, XorShiftRng}; #[test] fn test_fq2_mul_nonresidue() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let nqr = Fq2 { c0: Fq::one(), @@ -891,7 +892,7 @@ fn test_fq2_mul_nonresidue() { }; for _ in 0..1000 { - let mut a = Fq2::rand(&mut rng); + let mut a = Fq2::random(&mut rng); let mut b = a; a.mul_by_nonresidue(); b.mul_assign(&nqr); diff --git a/pairing/src/bls12_381/fq6.rs b/pairing/src/bls12_381/fq6.rs index 36c6e28..21c8310 100644 --- a/pairing/src/bls12_381/fq6.rs +++ b/pairing/src/bls12_381/fq6.rs @@ -1,7 +1,7 @@ use super::fq::{FROBENIUS_COEFF_FQ6_C1, FROBENIUS_COEFF_FQ6_C2}; use super::fq2::Fq2; use ff::Field; -use rand::{Rand, Rng}; +use rand_core::RngCore; /// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2). #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -17,15 +17,6 @@ impl ::std::fmt::Display for Fq6 { } } -impl Rand for Fq6 { - fn rand(rng: &mut R) -> Self { - Fq6 { - c0: rng.gen(), - c1: rng.gen(), - c2: rng.gen(), - } - } -} impl Fq6 { /// Multiply by quadratic nonresidue v. @@ -110,6 +101,14 @@ impl Fq6 { } impl Field for Fq6 { + fn random(rng: &mut R) -> Self { + Fq6 { + c0: Fq2::random(rng), + c1: Fq2::random(rng), + c2: Fq2::random(rng), + } + } + fn zero() -> Self { Fq6 { c0: Fq2::zero(), @@ -306,7 +305,10 @@ use rand::{SeedableRng, XorShiftRng}; #[test] fn test_fq6_mul_nonresidue() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let nqr = Fq6 { c0: Fq2::zero(), @@ -315,7 +317,7 @@ fn test_fq6_mul_nonresidue() { }; for _ in 0..1000 { - let mut a = Fq6::rand(&mut rng); + let mut a = Fq6::random(&mut rng); let mut b = a; a.mul_by_nonresidue(); b.mul_assign(&nqr); @@ -326,11 +328,14 @@ fn test_fq6_mul_nonresidue() { #[test] fn test_fq6_mul_by_1() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let c1 = Fq2::rand(&mut rng); - let mut a = Fq6::rand(&mut rng); + let c1 = Fq2::random(&mut rng); + let mut a = Fq6::random(&mut rng); let mut b = a; a.mul_by_1(&c1); @@ -346,12 +351,15 @@ fn test_fq6_mul_by_1() { #[test] fn test_fq6_mul_by_01() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let c0 = Fq2::rand(&mut rng); - let c1 = Fq2::rand(&mut rng); - let mut a = Fq6::rand(&mut rng); + let c0 = Fq2::random(&mut rng); + let c1 = Fq2::random(&mut rng); + let mut a = Fq6::random(&mut rng); let mut b = a; a.mul_by_01(&c0, &c1); diff --git a/pairing/src/bls12_381/fr.rs b/pairing/src/bls12_381/fr.rs index 5e57631..20811cd 100644 --- a/pairing/src/bls12_381/fr.rs +++ b/pairing/src/bls12_381/fr.rs @@ -6,7 +6,7 @@ use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr}; pub struct Fr(FrRepr); #[cfg(test)] -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand::{SeedableRng, XorShiftRng}; #[test] fn test_fr_repr_ordering() { @@ -197,7 +197,10 @@ fn test_fr_repr_num_bits() { #[test] fn test_fr_repr_sub_noborrow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let mut t = FrRepr([ 0x8e62a7e85264e2c3, @@ -221,7 +224,7 @@ fn test_fr_repr_sub_noborrow() { ); for _ in 0..1000 { - let mut a = FrRepr::rand(&mut rng); + let mut a = Fr::random(&mut rng).into_repr(); a.0[3] >>= 30; let mut b = a; for _ in 0..10 { @@ -296,7 +299,10 @@ fn test_fr_legendre() { #[test] fn test_fr_repr_add_nocarry() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let mut t = FrRepr([ 0xd64f669809cbc6a4, @@ -322,9 +328,9 @@ fn test_fr_repr_add_nocarry() { // Test for the associativity of addition. for _ in 0..1000 { - let mut a = FrRepr::rand(&mut rng); - let mut b = FrRepr::rand(&mut rng); - let mut c = FrRepr::rand(&mut rng); + let mut a = Fr::random(&mut rng).into_repr(); + let mut b = Fr::random(&mut rng).into_repr(); + let mut c = Fr::random(&mut rng).into_repr(); // Unset the first few bits, so that overflow won't occur. a.0[3] >>= 3; @@ -397,10 +403,13 @@ fn test_fr_is_valid() { ])).is_valid() ); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let a = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); assert!(a.is_valid()); } } @@ -492,13 +501,16 @@ fn test_fr_add_assign() { // Test associativity - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Generate a, b, c and ensure (a + b) + c == a + (b + c). - let a = Fr::rand(&mut rng); - let b = Fr::rand(&mut rng); - let c = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); + let b = Fr::random(&mut rng); + let c = Fr::random(&mut rng); let mut tmp1 = a; tmp1.add_assign(&b); @@ -586,12 +598,15 @@ fn test_fr_sub_assign() { ); } - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Ensure that (a - b) + (b - a) = 0. - let a = Fr::rand(&mut rng); - let b = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); + let b = Fr::random(&mut rng); let mut tmp1 = a; tmp1.sub_assign(&b); @@ -627,13 +642,16 @@ fn test_fr_mul_assign() { ])) ); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000000 { // Ensure that (a * b) * c = a * (b * c) - let a = Fr::rand(&mut rng); - let b = Fr::rand(&mut rng); - let c = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); + let b = Fr::random(&mut rng); + let c = Fr::random(&mut rng); let mut tmp1 = a; tmp1.mul_assign(&b); @@ -649,10 +667,10 @@ fn test_fr_mul_assign() { for _ in 0..1000000 { // Ensure that r * (a + b + c) = r*a + r*b + r*c - let r = Fr::rand(&mut rng); - let mut a = Fr::rand(&mut rng); - let mut b = Fr::rand(&mut rng); - let mut c = Fr::rand(&mut rng); + let r = Fr::random(&mut rng); + let mut a = Fr::random(&mut rng); + let mut b = Fr::random(&mut rng); + let mut c = Fr::random(&mut rng); let mut tmp1 = a; tmp1.add_assign(&b); @@ -690,11 +708,14 @@ fn test_fr_squaring() { ])).unwrap() ); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000000 { // Ensure that (a * a) = a^2 - let a = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); let mut tmp = a; tmp.square(); @@ -710,13 +731,16 @@ fn test_fr_squaring() { fn test_fr_inverse() { assert!(Fr::zero().inverse().is_none()); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let one = Fr::one(); for _ in 0..1000 { // Ensure that a * a^-1 = 1 - let mut a = Fr::rand(&mut rng); + let mut a = Fr::random(&mut rng); let ainv = a.inverse().unwrap(); a.mul_assign(&ainv); assert_eq!(a, one); @@ -725,11 +749,14 @@ fn test_fr_inverse() { #[test] fn test_fr_double() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Ensure doubling a is equivalent to adding a to itself. - let mut a = Fr::rand(&mut rng); + let mut a = Fr::random(&mut rng); let mut b = a; b.add_assign(&a); a.double(); @@ -746,11 +773,14 @@ fn test_fr_negate() { assert!(a.is_zero()); } - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Ensure (a - (-a)) = 0. - let mut a = Fr::rand(&mut rng); + let mut a = Fr::random(&mut rng); let mut b = a; b.negate(); a.add_assign(&b); @@ -761,12 +791,15 @@ fn test_fr_negate() { #[test] fn test_fr_pow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for i in 0..1000 { // Exponentiate by various small numbers and ensure it consists with repeated // multiplication. - let a = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); let target = a.pow(&[i]); let mut c = Fr::one(); for _ in 0..i { @@ -777,7 +810,7 @@ fn test_fr_pow() { for _ in 0..1000 { // Exponentiating by the modulus should have no effect in a prime field. - let a = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); assert_eq!(a, a.pow(Fr::char())); } @@ -787,13 +820,16 @@ fn test_fr_pow() { fn test_fr_sqrt() { use ff::SqrtField; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); assert_eq!(Fr::zero().sqrt().unwrap(), Fr::zero()); for _ in 0..1000 { // Ensure sqrt(a^2) = a or -a - let a = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); let mut nega = a; nega.negate(); let mut b = a; @@ -806,7 +842,7 @@ fn test_fr_sqrt() { for _ in 0..1000 { // Ensure sqrt(a)^2 = a for random a - let a = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); if let Some(mut tmp) = a.sqrt() { tmp.square(); @@ -858,11 +894,14 @@ fn test_fr_from_into_repr() { // Zero should be in the field. assert!(Fr::from_repr(FrRepr::from(0)).unwrap().is_zero()); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Try to turn Fr elements into representations and back again, and compare. - let a = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); let a_repr = a.into_repr(); let b_repr = FrRepr::from(a); assert_eq!(a_repr, b_repr); @@ -982,5 +1021,5 @@ fn fr_field_tests() { #[test] fn fr_repr_tests() { - ::tests::repr::random_repr_tests::(); + ::tests::repr::random_repr_tests::(); } diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs index 686938f..d498c35 100644 --- a/pairing/src/lib.rs +++ b/pairing/src/lib.rs @@ -14,6 +14,9 @@ extern crate byteorder; extern crate ff; extern crate group; +extern crate rand_core; + +#[cfg(test)] extern crate rand; #[cfg(test)] diff --git a/pairing/src/tests/engine.rs b/pairing/src/tests/engine.rs index 7b1944d..8616129 100644 --- a/pairing/src/tests/engine.rs +++ b/pairing/src/tests/engine.rs @@ -1,14 +1,17 @@ use group::{CurveAffine, CurveProjective}; -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand::{SeedableRng, XorShiftRng}; use {Engine, Field, PairingCurveAffine, PrimeField}; pub fn engine_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..10 { - let a = E::G1::rand(&mut rng).into_affine(); - let b = E::G2::rand(&mut rng).into_affine(); + let a = E::G1::random(&mut rng).into_affine(); + let b = E::G2::random(&mut rng).into_affine(); assert!(a.pairing_with(&b) == b.pairing_with(&a)); assert!(a.pairing_with(&b) == E::pairing(a, b)); @@ -18,10 +21,10 @@ pub fn engine_tests() { let z1 = E::G1Affine::zero().prepare(); let z2 = E::G2Affine::zero().prepare(); - let a = E::G1::rand(&mut rng).into_affine().prepare(); - let b = E::G2::rand(&mut rng).into_affine().prepare(); - let c = E::G1::rand(&mut rng).into_affine().prepare(); - let d = E::G2::rand(&mut rng).into_affine().prepare(); + let a = E::G1::random(&mut rng).into_affine().prepare(); + let b = E::G2::random(&mut rng).into_affine().prepare(); + let c = E::G1::random(&mut rng).into_affine().prepare(); + let d = E::G2::random(&mut rng).into_affine().prepare(); assert_eq!( E::Fqk::one(), @@ -49,12 +52,15 @@ pub fn engine_tests() { } fn random_miller_loop_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); // Exercise the miller loop for a reduced pairing for _ in 0..1000 { - let a = E::G1::rand(&mut rng); - let b = E::G2::rand(&mut rng); + let a = E::G1::random(&mut rng); + let b = E::G2::random(&mut rng); let p2 = E::pairing(a, b); @@ -68,10 +74,10 @@ fn random_miller_loop_tests() { // Exercise a double miller loop for _ in 0..1000 { - let a = E::G1::rand(&mut rng); - let b = E::G2::rand(&mut rng); - let c = E::G1::rand(&mut rng); - let d = E::G2::rand(&mut rng); + let a = E::G1::random(&mut rng); + let b = E::G2::random(&mut rng); + let c = E::G1::random(&mut rng); + let d = E::G2::random(&mut rng); let ab = E::pairing(a, b); let cd = E::pairing(c, d); @@ -92,14 +98,17 @@ fn random_miller_loop_tests() { } fn random_bilinearity_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let a = E::G1::rand(&mut rng); - let b = E::G2::rand(&mut rng); + let a = E::G1::random(&mut rng); + let b = E::G2::random(&mut rng); - let c = E::Fr::rand(&mut rng); - let d = E::Fr::rand(&mut rng); + let c = E::Fr::random(&mut rng); + let d = E::Fr::random(&mut rng); let mut ac = a; ac.mul_assign(c); diff --git a/pairing/src/tests/field.rs b/pairing/src/tests/field.rs index 55396a7..0f2f1b2 100644 --- a/pairing/src/tests/field.rs +++ b/pairing/src/tests/field.rs @@ -2,11 +2,14 @@ use ff::{Field, LegendreSymbol, PrimeField, SqrtField}; use rand::{Rng, SeedableRng, XorShiftRng}; pub fn random_frobenius_tests>(characteristic: C, maxpower: usize) { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { for i in 0..(maxpower + 1) { - let mut a = F::rand(&mut rng); + let mut a = F::random(&mut rng); let mut b = a; for _ in 0..i { @@ -20,10 +23,13 @@ pub fn random_frobenius_tests>(characteristic: C, maxp } pub fn random_sqrt_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..10000 { - let a = F::rand(&mut rng); + let a = F::random(&mut rng); let mut b = a; b.square(); assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); @@ -54,7 +60,10 @@ pub fn random_sqrt_tests() { } pub fn random_field_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); random_multiplication_tests::(&mut rng); random_addition_tests::(&mut rng); @@ -76,14 +85,14 @@ pub fn random_field_tests() { // Multiplication by zero { - let mut a = F::rand(&mut rng); + let mut a = F::random(&mut rng); a.mul_assign(&F::zero()); assert!(a.is_zero()); } // Addition by zero { - let mut a = F::rand(&mut rng); + let mut a = F::random(&mut rng); let copy = a; a.add_assign(&F::zero()); assert_eq!(a, copy); @@ -106,7 +115,10 @@ pub fn from_str_tests() { } { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { let n: u64 = rng.gen(); @@ -126,9 +138,9 @@ pub fn from_str_tests() { fn random_multiplication_tests(rng: &mut R) { for _ in 0..10000 { - let a = F::rand(rng); - let b = F::rand(rng); - let c = F::rand(rng); + let a = F::random(rng); + let b = F::random(rng); + let c = F::random(rng); let mut t0 = a; // (a * b) * c t0.mul_assign(&b); @@ -149,9 +161,9 @@ fn random_multiplication_tests(rng: &mut R) { fn random_addition_tests(rng: &mut R) { for _ in 0..10000 { - let a = F::rand(rng); - let b = F::rand(rng); - let c = F::rand(rng); + let a = F::random(rng); + let b = F::random(rng); + let c = F::random(rng); let mut t0 = a; // (a + b) + c t0.add_assign(&b); @@ -172,8 +184,8 @@ fn random_addition_tests(rng: &mut R) { fn random_subtraction_tests(rng: &mut R) { for _ in 0..10000 { - let a = F::rand(rng); - let b = F::rand(rng); + let b = F::random(rng); + let a = F::random(rng); let mut t0 = a; // (a - b) t0.sub_assign(&b); @@ -190,7 +202,7 @@ fn random_subtraction_tests(rng: &mut R) { fn random_negation_tests(rng: &mut R) { for _ in 0..10000 { - let a = F::rand(rng); + let a = F::random(rng); let mut b = a; b.negate(); b.add_assign(&a); @@ -201,7 +213,7 @@ fn random_negation_tests(rng: &mut R) { fn random_doubling_tests(rng: &mut R) { for _ in 0..10000 { - let mut a = F::rand(rng); + let mut a = F::random(rng); let mut b = a; a.add_assign(&b); b.double(); @@ -212,7 +224,7 @@ fn random_doubling_tests(rng: &mut R) { fn random_squaring_tests(rng: &mut R) { for _ in 0..10000 { - let mut a = F::rand(rng); + let mut a = F::random(rng); let mut b = a; a.mul_assign(&b); b.square(); @@ -225,7 +237,7 @@ fn random_inversion_tests(rng: &mut R) { assert!(F::zero().inverse().is_none()); for _ in 0..10000 { - let mut a = F::rand(rng); + let mut a = F::random(rng); let b = a.inverse().unwrap(); // probablistically nonzero a.mul_assign(&b); @@ -237,10 +249,10 @@ fn random_expansion_tests(rng: &mut R) { for _ in 0..10000 { // Compare (a + b)(c + d) and (a*c + b*c + a*d + b*d) - let a = F::rand(rng); - let b = F::rand(rng); - let c = F::rand(rng); - let d = F::rand(rng); + let a = F::random(rng); + let b = F::random(rng); + let c = F::random(rng); + let d = F::random(rng); let mut t0 = a; t0.add_assign(&b); diff --git a/pairing/src/tests/repr.rs b/pairing/src/tests/repr.rs index 09dd441..692c4d3 100644 --- a/pairing/src/tests/repr.rs +++ b/pairing/src/tests/repr.rs @@ -1,21 +1,24 @@ -use ff::PrimeFieldRepr; +use ff::{PrimeField, PrimeFieldRepr}; use rand::{SeedableRng, XorShiftRng}; -pub fn random_repr_tests() { - random_encoding_tests::(); - random_shl_tests::(); - random_shr_tests::(); +pub fn random_repr_tests() { + random_encoding_tests::

(); + random_shl_tests::

(); + random_shr_tests::

(); } -fn random_encoding_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); +fn random_encoding_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let r = R::rand(&mut rng); + let r = P::random(&mut rng).into_repr(); // Big endian { - let mut rdecoded = R::default(); + let mut rdecoded =

::Repr::default(); let mut v: Vec = vec![]; r.write_be(&mut v).unwrap(); @@ -26,7 +29,7 @@ fn random_encoding_tests() { // Little endian { - let mut rdecoded = R::default(); + let mut rdecoded =

::Repr::default(); let mut v: Vec = vec![]; r.write_le(&mut v).unwrap(); @@ -36,8 +39,8 @@ fn random_encoding_tests() { } { - let mut rdecoded_le = R::default(); - let mut rdecoded_be_flip = R::default(); + let mut rdecoded_le =

::Repr::default(); + let mut rdecoded_be_flip =

::Repr::default(); let mut v: Vec = vec![]; r.write_le(&mut v).unwrap(); @@ -55,11 +58,14 @@ fn random_encoding_tests() { } } -fn random_shl_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); +fn random_shl_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { - let r = R::rand(&mut rng); + let r = P::random(&mut rng).into_repr(); for shift in 0..(r.num_bits() + 1) { let mut r1 = r; @@ -76,11 +82,14 @@ fn random_shl_tests() { } } -fn random_shr_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); +fn random_shr_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { - let r = R::rand(&mut rng); + let r = P::random(&mut rng).into_repr(); for shift in 0..(r.num_bits() + 1) { let mut r1 = r; From 4606a0cefb4b557f3fdbf0e38fa481d0aa3b7463 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 10 Jul 2019 19:40:20 -0400 Subject: [PATCH 027/330] Migrate bellman to rand 0.5 --- Cargo.lock | 3 ++- bellman/Cargo.toml | 5 ++++- bellman/src/domain.rs | 20 ++++++++++---------- bellman/src/groth16/generator.rs | 18 +++++++++--------- bellman/src/groth16/mod.rs | 6 +++--- bellman/src/groth16/prover.rs | 8 ++++---- bellman/src/groth16/tests/dummy_engine.rs | 22 +++++++++------------- bellman/src/lib.rs | 5 ++++- bellman/src/multiexp.rs | 6 +++--- bellman/tests/mimc.rs | 10 +++++----- 10 files changed, 53 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7764696..9eb4dc4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,7 +61,8 @@ dependencies = [ "group 0.1.0", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/bellman/Cargo.toml b/bellman/Cargo.toml index 20602c2..72a8034 100644 --- a/bellman/Cargo.toml +++ b/bellman/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/ebfull/bellman" version = "0.1.0" [dependencies] -rand = "0.4" +rand_core = "0.3" bit-vec = "0.4.4" ff = { path = "../ff" } futures = "0.1" @@ -20,6 +20,9 @@ crossbeam = { version = "0.3", optional = true } pairing = { path = "../pairing", optional = true } byteorder = "1" +[dev-dependencies] +rand = "0.5" + [features] groth16 = ["pairing"] multicore = ["futures-cpupool", "crossbeam", "num_cpus"] diff --git a/bellman/src/domain.rs b/bellman/src/domain.rs index 4606ce5..5d7d500 100644 --- a/bellman/src/domain.rs +++ b/bellman/src/domain.rs @@ -375,16 +375,16 @@ fn parallel_fft>( #[test] fn polynomial_arith() { use pairing::bls12_381::Bls12; - use rand::{self, Rand}; + use rand_core::RngCore; - fn test_mul(rng: &mut R) + fn test_mul(rng: &mut R) { let worker = Worker::new(); for coeffs_a in 0..70 { for coeffs_b in 0..70 { - let mut a: Vec<_> = (0..coeffs_a).map(|_| Scalar::(E::Fr::rand(rng))).collect(); - let mut b: Vec<_> = (0..coeffs_b).map(|_| Scalar::(E::Fr::rand(rng))).collect(); + let mut a: Vec<_> = (0..coeffs_a).map(|_| Scalar::(E::Fr::random(rng))).collect(); + let mut b: Vec<_> = (0..coeffs_b).map(|_| Scalar::(E::Fr::random(rng))).collect(); // naive evaluation let mut naive = vec![Scalar(E::Fr::zero()); coeffs_a + coeffs_b]; @@ -423,9 +423,9 @@ fn polynomial_arith() { #[test] fn fft_composition() { use pairing::bls12_381::Bls12; - use rand; + use rand_core::RngCore; - fn test_comp(rng: &mut R) + fn test_comp(rng: &mut R) { let worker = Worker::new(); @@ -434,7 +434,7 @@ fn fft_composition() { let mut v = vec![]; for _ in 0..coeffs { - v.push(Scalar::(rng.gen())); + v.push(Scalar::(E::Fr::random(rng))); } let mut domain = EvaluationDomain::from_coeffs(v.clone()).unwrap(); @@ -462,10 +462,10 @@ fn fft_composition() { #[test] fn parallel_fft_consistency() { use pairing::bls12_381::Bls12; - use rand::{self, Rand}; + use rand_core::RngCore; use std::cmp::min; - fn test_consistency(rng: &mut R) + fn test_consistency(rng: &mut R) { let worker = Worker::new(); @@ -473,7 +473,7 @@ fn parallel_fft_consistency() { for log_d in 0..10 { let d = 1 << log_d; - let v1 = (0..d).map(|_| Scalar::(E::Fr::rand(rng))).collect::>(); + let v1 = (0..d).map(|_| Scalar::(E::Fr::random(rng))).collect::>(); let mut v1 = EvaluationDomain::from_coeffs(v1).unwrap(); let mut v2 = EvaluationDomain::from_coeffs(v1.coeffs.clone()).unwrap(); diff --git a/bellman/src/groth16/generator.rs b/bellman/src/groth16/generator.rs index 50d5bd7..3e15b2b 100644 --- a/bellman/src/groth16/generator.rs +++ b/bellman/src/groth16/generator.rs @@ -1,4 +1,4 @@ -use rand::Rng; +use rand_core::RngCore; use std::sync::Arc; @@ -35,15 +35,15 @@ pub fn generate_random_parameters( circuit: C, rng: &mut R ) -> Result, SynthesisError> - where E: Engine, C: Circuit, R: Rng + where E: Engine, C: Circuit, R: RngCore { - let g1 = rng.gen(); - let g2 = rng.gen(); - let alpha = rng.gen(); - let beta = rng.gen(); - let gamma = rng.gen(); - let delta = rng.gen(); - let tau = rng.gen(); + let g1 = E::G1::random(rng); + let g2 = E::G2::random(rng); + let alpha = E::Fr::random(rng); + let beta = E::Fr::random(rng); + let gamma = E::Fr::random(rng); + let delta = E::Fr::random(rng); + let tau = E::Fr::random(rng); generate_parameters::( circuit, diff --git a/bellman/src/groth16/mod.rs b/bellman/src/groth16/mod.rs index e613d66..767150c 100644 --- a/bellman/src/groth16/mod.rs +++ b/bellman/src/groth16/mod.rs @@ -487,7 +487,7 @@ mod test_with_bls12_381 { use {Circuit, SynthesisError, ConstraintSystem}; use ff::Field; - use rand::{Rand, thread_rng}; + use rand::{thread_rng}; use pairing::bls12_381::{Bls12, Fr}; #[test] @@ -547,8 +547,8 @@ mod test_with_bls12_381 { let pvk = prepare_verifying_key::(¶ms.vk); for _ in 0..100 { - let a = Fr::rand(rng); - let b = Fr::rand(rng); + let a = Fr::random(rng); + let b = Fr::random(rng); let mut c = a; c.mul_assign(&b); diff --git a/bellman/src/groth16/prover.rs b/bellman/src/groth16/prover.rs index c674622..ceb3dce 100644 --- a/bellman/src/groth16/prover.rs +++ b/bellman/src/groth16/prover.rs @@ -1,4 +1,4 @@ -use rand::Rng; +use rand_core::RngCore; use std::sync::Arc; @@ -189,10 +189,10 @@ pub fn create_random_proof>( params: P, rng: &mut R ) -> Result, SynthesisError> - where E: Engine, C: Circuit, R: Rng + where E: Engine, C: Circuit, R: RngCore { - let r = rng.gen(); - let s = rng.gen(); + let r = E::Fr::random(rng); + let s = E::Fr::random(rng); create_proof::(circuit, params, r, s) } diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index d5f37a9..654b814 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -6,7 +6,7 @@ use pairing::{Engine, PairingCurveAffine}; use std::cmp::Ordering; use std::fmt; -use rand::{Rand, Rng}; +use rand_core::RngCore; use std::num::Wrapping; const MODULUS_R: Wrapping = Wrapping(64513); @@ -20,13 +20,11 @@ impl fmt::Display for Fr { } } -impl Rand for Fr { - fn rand(rng: &mut R) -> Self { - Fr(Wrapping(rng.gen()) % MODULUS_R) - } -} - impl Field for Fr { + fn random(rng: &mut R) -> Self { + Fr(Wrapping(rng.next_u32()) % MODULUS_R) + } + fn zero() -> Self { Fr(Wrapping(0)) } @@ -145,12 +143,6 @@ impl PartialOrd for FrRepr { } } -impl Rand for FrRepr { - fn rand(rng: &mut R) -> Self { - FrRepr([rng.gen()]) - } -} - impl fmt::Display for FrRepr { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "{}", (self.0)[0]) @@ -300,6 +292,10 @@ impl CurveProjective for Fr { type Scalar = Fr; type Engine = DummyEngine; + fn random(rng: &mut R) -> Self { + ::random(rng) + } + fn zero() -> Self { ::zero() } diff --git a/bellman/src/lib.rs b/bellman/src/lib.rs index d22d90f..bf9a4e1 100644 --- a/bellman/src/lib.rs +++ b/bellman/src/lib.rs @@ -2,7 +2,7 @@ extern crate ff; extern crate group; #[cfg(feature = "pairing")] extern crate pairing; -extern crate rand; +extern crate rand_core; extern crate futures; extern crate bit_vec; @@ -15,6 +15,9 @@ extern crate futures_cpupool; #[cfg(feature = "multicore")] extern crate num_cpus; +#[cfg(test)] +extern crate rand; + pub mod multicore; mod multiexp; pub mod domain; diff --git a/bellman/src/multiexp.rs b/bellman/src/multiexp.rs index d24572b..c655397 100644 --- a/bellman/src/multiexp.rs +++ b/bellman/src/multiexp.rs @@ -274,14 +274,14 @@ fn test_with_bls12() { acc } - use rand::{self, Rand}; + use rand; use pairing::{bls12_381::Bls12, Engine}; const SAMPLES: usize = 1 << 14; let rng = &mut rand::thread_rng(); - let v = Arc::new((0..SAMPLES).map(|_| ::Fr::rand(rng).into_repr()).collect::>()); - let g = Arc::new((0..SAMPLES).map(|_| ::G1::rand(rng).into_affine()).collect::>()); + let v = Arc::new((0..SAMPLES).map(|_| ::Fr::random(rng).into_repr()).collect::>()); + let g = Arc::new((0..SAMPLES).map(|_| ::G1::random(rng).into_affine()).collect::>()); let naive = naive_multiexp(g.clone(), v.clone()); diff --git a/bellman/tests/mimc.rs b/bellman/tests/mimc.rs index 1d554a5..d08940f 100644 --- a/bellman/tests/mimc.rs +++ b/bellman/tests/mimc.rs @@ -4,13 +4,13 @@ extern crate pairing; extern crate rand; // For randomness (during paramgen and proof generation) -use rand::{thread_rng, Rng}; +use rand::thread_rng; // For benchmarking use std::time::{Duration, Instant}; // Bring in some tools for using pairing-friendly curves -use ff::Field; +use ff::{Field, ScalarEngine}; use pairing::Engine; // We're going to use the BLS12-381 pairing-friendly elliptic curve. @@ -172,7 +172,7 @@ fn test_mimc() { let rng = &mut thread_rng(); // Generate the MiMC round constants - let constants = (0..MIMC_ROUNDS).map(|_| rng.gen()).collect::>(); + let constants = (0..MIMC_ROUNDS).map(|_| ::Fr::random(rng)).collect::>(); println!("Creating parameters..."); @@ -203,8 +203,8 @@ fn test_mimc() { for _ in 0..SAMPLES { // Generate a random preimage and compute the image - let xl = rng.gen(); - let xr = rng.gen(); + let xl = ::Fr::random(rng); + let xr = ::Fr::random(rng); let image = mimc::(xl, xr, &constants); proof_vec.truncate(0); From adfc88926bbf3cfc0984fcce9b0b7702b1cb356a Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 11 Jul 2019 08:46:47 -0400 Subject: [PATCH 028/330] Migrate sapling-crypto to rand 0.5 --- Cargo.lock | 2 +- sapling-crypto/Cargo.toml | 2 +- sapling-crypto/examples/bench.rs | 27 ++-- sapling-crypto/src/circuit/blake2s.rs | 15 +- sapling-crypto/src/circuit/ecc.rs | 70 ++++++--- sapling-crypto/src/circuit/lookup.rs | 23 ++- sapling-crypto/src/circuit/multipack.rs | 5 +- sapling-crypto/src/circuit/num.rs | 24 +-- sapling-crypto/src/circuit/pedersen_hash.rs | 10 +- sapling-crypto/src/circuit/sapling/mod.rs | 44 ++++-- sapling-crypto/src/circuit/sha256.rs | 10 +- sapling-crypto/src/circuit/uint32.rs | 45 ++++-- sapling-crypto/src/jubjub/edwards.rs | 2 +- sapling-crypto/src/jubjub/fs.rs | 161 ++++++++++++-------- sapling-crypto/src/jubjub/montgomery.rs | 2 +- sapling-crypto/src/jubjub/tests.rs | 59 +++++-- sapling-crypto/src/redjubjub.rs | 16 +- 17 files changed, 347 insertions(+), 170 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9eb4dc4..a823c3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -498,7 +498,7 @@ dependencies = [ "ff 0.4.0", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/sapling-crypto/Cargo.toml b/sapling-crypto/Cargo.toml index 7d43774..3d895db 100644 --- a/sapling-crypto/Cargo.toml +++ b/sapling-crypto/Cargo.toml @@ -17,7 +17,7 @@ bellman = { path = "../bellman" } blake2b_simd = "0.5" blake2s_simd = "0.5" ff = { path = "../ff" } -rand = "0.4" +rand = "0.5" digest = "0.7" byteorder = "1" diff --git a/sapling-crypto/examples/bench.rs b/sapling-crypto/examples/bench.rs index 4b7a707..9b4c0ae 100644 --- a/sapling-crypto/examples/bench.rs +++ b/sapling-crypto/examples/bench.rs @@ -1,8 +1,10 @@ +extern crate ff; extern crate sapling_crypto; extern crate bellman; extern crate rand; extern crate pairing; +use ff::Field; use std::time::{Duration, Instant}; use sapling_crypto::jubjub::{ JubjubBls12, @@ -18,14 +20,17 @@ use sapling_crypto::primitives::{ ValueCommitment }; use bellman::groth16::*; -use rand::{XorShiftRng, SeedableRng, Rng}; +use rand::{XorShiftRng, SeedableRng, Rng, RngCore}; use pairing::bls12_381::{Bls12, Fr}; const TREE_DEPTH: usize = 32; fn main() { let jubjub_params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); println!("Creating sample parameters..."); let groth_params = generate_random_parameters::( @@ -48,10 +53,10 @@ fn main() { for _ in 0..SAMPLES { let value_commitment = ValueCommitment { value: 1, - randomness: rng.gen() + randomness: fs::Fs::random(rng) }; - let nsk: fs::Fs = rng.gen(); + let nsk = fs::Fs::random(rng); let ak = edwards::Point::rand(rng, jubjub_params).mul_by_cofactor(jubjub_params); let proof_generation_key = ProofGenerationKey { @@ -64,7 +69,11 @@ fn main() { let payment_address; loop { - let diversifier = Diversifier(rng.gen()); + let diversifier = { + let mut d = [0; 11]; + rng.fill_bytes(&mut d); + Diversifier(d) + }; if let Some(p) = viewing_key.into_payment_address( diversifier, @@ -76,10 +85,10 @@ fn main() { } } - let commitment_randomness: fs::Fs = rng.gen(); - let auth_path = vec![Some((rng.gen(), rng.gen())); TREE_DEPTH]; - let ar: fs::Fs = rng.gen(); - let anchor: Fr = rng.gen(); + let commitment_randomness = fs::Fs::random(rng); + let auth_path = vec![Some((Fr::random(rng), rng.gen())); TREE_DEPTH]; + let ar = fs::Fs::random(rng); + let anchor = Fr::random(rng); let start = Instant::now(); let _ = create_random_proof(Spend { diff --git a/sapling-crypto/src/circuit/blake2s.rs b/sapling-crypto/src/circuit/blake2s.rs index 46bbe67..e6748ba 100644 --- a/sapling-crypto/src/circuit/blake2s.rs +++ b/sapling-crypto/src/circuit/blake2s.rs @@ -366,7 +366,10 @@ mod test { // doesn't result in more constraints. let mut cs = TestConstraintSystem::::new(); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let input_bits: Vec<_> = (0..512) .map(|_| Boolean::constant(rng.gen())) .chain((0..512) @@ -380,7 +383,10 @@ mod test { #[test] fn test_blake2s_constant_constraints() { let mut cs = TestConstraintSystem::::new(); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let input_bits: Vec<_> = (0..512).map(|_| Boolean::constant(rng.gen())).collect(); blake2s(&mut cs, &input_bits, b"12345678").unwrap(); assert_eq!(cs.num_constraints(), 0); @@ -388,7 +394,10 @@ mod test { #[test] fn test_blake2s() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) { diff --git a/sapling-crypto/src/circuit/ecc.rs b/sapling-crypto/src/circuit/ecc.rs index 1071649..3fc9713 100644 --- a/sapling-crypto/src/circuit/ecc.rs +++ b/sapling-crypto/src/circuit/ecc.rs @@ -748,7 +748,7 @@ impl MontgomeryPoint { #[cfg(test)] mod test { use bellman::{ConstraintSystem}; - use rand::{XorShiftRng, SeedableRng, Rand, Rng}; + use rand::{XorShiftRng, SeedableRng, Rng}; use ff::{BitIterator, Field, PrimeField}; use pairing::bls12_381::{Bls12, Fr}; use ::circuit::test::*; @@ -774,7 +774,10 @@ mod test { #[test] fn test_into_edwards() { let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { let mut cs = TestConstraintSystem::::new(); @@ -798,12 +801,12 @@ mod test { assert!(q.x.get_value().unwrap() == u); assert!(q.y.get_value().unwrap() == v); - cs.set("u/num", rng.gen()); + cs.set("u/num", Fr::random(rng)); assert_eq!(cs.which_is_unsatisfied().unwrap(), "u computation"); cs.set("u/num", u); assert!(cs.is_satisfied()); - cs.set("v/num", rng.gen()); + cs.set("v/num", Fr::random(rng)); assert_eq!(cs.which_is_unsatisfied().unwrap(), "v computation"); cs.set("v/num", v); assert!(cs.is_satisfied()); @@ -813,7 +816,10 @@ mod test { #[test] fn test_interpret() { let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { let p = edwards::Point::::rand(rng, ¶ms); @@ -853,8 +859,8 @@ mod test { // Random (x, y) are unlikely to be on the curve. for _ in 0..100 { - let x = rng.gen(); - let y = rng.gen(); + let x = Fr::random(rng); + let y = Fr::random(rng); let mut cs = TestConstraintSystem::::new(); let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || { @@ -873,13 +879,16 @@ mod test { #[test] fn test_edwards_fixed_base_multiplication() { let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { let mut cs = TestConstraintSystem::::new(); let p = params.generator(FixedGenerators::NoteCommitmentRandomness); - let s = Fs::rand(rng); + let s = Fs::random(rng); let q = p.mul(s, params); let (x1, y1) = q.into_xy(); @@ -908,13 +917,16 @@ mod test { #[test] fn test_edwards_multiplication() { let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { let mut cs = TestConstraintSystem::::new(); let p = edwards::Point::::rand(rng, params); - let s = Fs::rand(rng); + let s = Fs::random(rng); let q = p.mul(s, params); let (x0, y0) = p.into_xy(); @@ -965,7 +977,10 @@ mod test { #[test] fn test_conditionally_select() { let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); @@ -1031,7 +1046,10 @@ mod test { #[test] fn test_edwards_addition() { let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { let p1 = edwards::Point::::rand(rng, params); @@ -1077,19 +1095,19 @@ mod test { assert!(p3.y.get_value().unwrap() == y2); let u = cs.get("addition/U/num"); - cs.set("addition/U/num", rng.gen()); + cs.set("addition/U/num", Fr::random(rng)); assert_eq!(cs.which_is_unsatisfied(), Some("addition/U computation")); cs.set("addition/U/num", u); assert!(cs.is_satisfied()); let x3 = cs.get("addition/x3/num"); - cs.set("addition/x3/num", rng.gen()); + cs.set("addition/x3/num", Fr::random(rng)); assert_eq!(cs.which_is_unsatisfied(), Some("addition/x3 computation")); cs.set("addition/x3/num", x3); assert!(cs.is_satisfied()); let y3 = cs.get("addition/y3/num"); - cs.set("addition/y3/num", rng.gen()); + cs.set("addition/y3/num", Fr::random(rng)); assert_eq!(cs.which_is_unsatisfied(), Some("addition/y3 computation")); cs.set("addition/y3/num", y3); assert!(cs.is_satisfied()); @@ -1099,7 +1117,10 @@ mod test { #[test] fn test_edwards_doubling() { let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { let p1 = edwards::Point::::rand(rng, params); @@ -1134,11 +1155,14 @@ mod test { #[test] fn test_montgomery_addition() { let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { let p1 = loop { - let x: Fr = rng.gen(); + let x = Fr::random(rng); let s: bool = rng.gen(); if let Some(p) = montgomery::Point::::get_for_x(x, s, params) { @@ -1147,7 +1171,7 @@ mod test { }; let p2 = loop { - let x: Fr = rng.gen(); + let x = Fr::random(rng); let s: bool = rng.gen(); if let Some(p) = montgomery::Point::::get_for_x(x, s, params) { @@ -1194,17 +1218,17 @@ mod test { assert!(p3.x.get_value().unwrap() == x2); assert!(p3.y.get_value().unwrap() == y2); - cs.set("addition/yprime/num", rng.gen()); + cs.set("addition/yprime/num", Fr::random(rng)); assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate yprime")); cs.set("addition/yprime/num", y2); assert!(cs.is_satisfied()); - cs.set("addition/xprime/num", rng.gen()); + cs.set("addition/xprime/num", Fr::random(rng)); assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate xprime")); cs.set("addition/xprime/num", x2); assert!(cs.is_satisfied()); - cs.set("addition/lambda/num", rng.gen()); + cs.set("addition/lambda/num", Fr::random(rng)); assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate lambda")); } } diff --git a/sapling-crypto/src/circuit/lookup.rs b/sapling-crypto/src/circuit/lookup.rs index 272f5f6..4b6e13b 100644 --- a/sapling-crypto/src/circuit/lookup.rs +++ b/sapling-crypto/src/circuit/lookup.rs @@ -196,7 +196,7 @@ pub fn lookup3_xy_with_conditional_negation( #[cfg(test)] mod test { - use rand::{SeedableRng, Rand, Rng, XorShiftRng}; + use rand::{SeedableRng, Rng, XorShiftRng}; use super::*; use ::circuit::test::*; use ::circuit::boolean::{Boolean, AllocatedBit}; @@ -204,7 +204,10 @@ mod test { #[test] fn test_lookup3_xy() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0656]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { let mut cs = TestConstraintSystem::::new(); @@ -226,7 +229,7 @@ mod test { let bits = vec![a, b, c]; - let points: Vec<(Fr, Fr)> = (0..8).map(|_| (rng.gen(), rng.gen())).collect(); + let points: Vec<(Fr, Fr)> = (0..8).map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))).collect(); let res = lookup3_xy(&mut cs, &bits, &points).unwrap(); @@ -244,7 +247,10 @@ mod test { #[test] fn test_lookup3_xy_with_conditional_negation() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { let mut cs = TestConstraintSystem::::new(); @@ -266,7 +272,7 @@ mod test { let bits = vec![a, b, c]; - let points: Vec<(Fr, Fr)> = (0..4).map(|_| (rng.gen(), rng.gen())).collect(); + let points: Vec<(Fr, Fr)> = (0..4).map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))).collect(); let res = lookup3_xy_with_conditional_negation(&mut cs, &bits, &points).unwrap(); @@ -285,12 +291,15 @@ mod test { #[test] fn test_synth() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let window_size = 4; let mut assignment = vec![Fr::zero(); 1 << window_size]; - let constants: Vec<_> = (0..(1 << window_size)).map(|_| Fr::rand(&mut rng)).collect(); + let constants: Vec<_> = (0..(1 << window_size)).map(|_| Fr::random(&mut rng)).collect(); synth::(window_size, &constants, &mut assignment); diff --git a/sapling-crypto/src/circuit/multipack.rs b/sapling-crypto/src/circuit/multipack.rs index bf1b046..fd7cbfb 100644 --- a/sapling-crypto/src/circuit/multipack.rs +++ b/sapling-crypto/src/circuit/multipack.rs @@ -86,7 +86,10 @@ fn test_multipacking() { use ::circuit::test::*; use super::boolean::{AllocatedBit, Boolean}; - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for num_bits in 0..1500 { let mut cs = TestConstraintSystem::::new(); diff --git a/sapling-crypto/src/circuit/num.rs b/sapling-crypto/src/circuit/num.rs index 919d921..7201356 100644 --- a/sapling-crypto/src/circuit/num.rs +++ b/sapling-crypto/src/circuit/num.rs @@ -455,7 +455,7 @@ impl Num { #[cfg(test)] mod test { - use rand::{SeedableRng, Rand, Rng, XorShiftRng}; + use rand::{SeedableRng, XorShiftRng}; use bellman::{ConstraintSystem}; use ff::{BitIterator, Field, PrimeField}; use pairing::bls12_381::{Bls12, Fr}; @@ -502,12 +502,15 @@ mod test { #[test] fn test_num_conditional_reversal() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); { let mut cs = TestConstraintSystem::::new(); - let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(rng.gen())).unwrap(); - let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(rng.gen())).unwrap(); + let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::random(&mut rng))).unwrap(); + let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::random(&mut rng))).unwrap(); let condition = Boolean::constant(false); let (c, d) = AllocatedNum::conditionally_reverse(&mut cs, &a, &b, &condition).unwrap(); @@ -520,8 +523,8 @@ mod test { { let mut cs = TestConstraintSystem::::new(); - let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(rng.gen())).unwrap(); - let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(rng.gen())).unwrap(); + let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::random(&mut rng))).unwrap(); + let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::random(&mut rng))).unwrap(); let condition = Boolean::constant(true); let (c, d) = AllocatedNum::conditionally_reverse(&mut cs, &a, &b, &condition).unwrap(); @@ -573,10 +576,13 @@ mod test { #[test] fn test_into_bits() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for i in 0..200 { - let r = Fr::rand(&mut rng); + let r = Fr::random(&mut rng); let mut cs = TestConstraintSystem::::new(); let n = AllocatedNum::alloc(&mut cs, || Ok(r)).unwrap(); @@ -597,7 +603,7 @@ mod test { } } - cs.set("num", Fr::rand(&mut rng)); + cs.set("num", Fr::random(&mut rng)); assert!(!cs.is_satisfied()); cs.set("num", r); assert!(cs.is_satisfied()); diff --git a/sapling-crypto/src/circuit/pedersen_hash.rs b/sapling-crypto/src/circuit/pedersen_hash.rs index 297a0e0..f26b98e 100644 --- a/sapling-crypto/src/circuit/pedersen_hash.rs +++ b/sapling-crypto/src/circuit/pedersen_hash.rs @@ -121,7 +121,10 @@ mod test { #[test] fn test_pedersen_hash_constraints() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let params = &JubjubBls12::new(); let mut cs = TestConstraintSystem::::new(); @@ -146,7 +149,10 @@ mod test { #[test] fn test_pedersen_hash() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let params = &JubjubBls12::new(); for length in 0..751 { diff --git a/sapling-crypto/src/circuit/sapling/mod.rs b/sapling-crypto/src/circuit/sapling/mod.rs index e84b94a..2c4d566 100644 --- a/sapling-crypto/src/circuit/sapling/mod.rs +++ b/sapling-crypto/src/circuit/sapling/mod.rs @@ -600,22 +600,25 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { fn test_input_circuit_with_bls12_381() { use ff::{BitIterator, Field}; use pairing::bls12_381::*; - use rand::{SeedableRng, Rng, XorShiftRng}; + use rand::{SeedableRng, Rng, RngCore, XorShiftRng}; use ::circuit::test::*; use jubjub::{JubjubBls12, fs, edwards}; let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x58, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let tree_depth = 32; for _ in 0..10 { let value_commitment = ValueCommitment { value: rng.gen(), - randomness: rng.gen() + randomness: fs::Fs::random(rng), }; - let nsk: fs::Fs = rng.gen(); + let nsk = fs::Fs::random(rng); let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params); let proof_generation_key = ::primitives::ProofGenerationKey { @@ -628,7 +631,11 @@ fn test_input_circuit_with_bls12_381() { let payment_address; loop { - let diversifier = ::primitives::Diversifier(rng.gen()); + let diversifier = { + let mut d = [0; 11]; + rng.fill_bytes(&mut d); + ::primitives::Diversifier(d) + }; if let Some(p) = viewing_key.into_payment_address( diversifier, @@ -641,9 +648,9 @@ fn test_input_circuit_with_bls12_381() { } let g_d = payment_address.diversifier.g_d(params).unwrap(); - let commitment_randomness: fs::Fs = rng.gen(); - let auth_path = vec![Some((rng.gen(), rng.gen())); tree_depth]; - let ar: fs::Fs = rng.gen(); + let commitment_randomness = fs::Fs::random(rng); + let auth_path = vec![Some((Fr::random(rng), rng.gen())); tree_depth]; + let ar = fs::Fs::random(rng); { let rk = viewing_key.rk(ar, params).into_xy(); @@ -732,20 +739,23 @@ fn test_input_circuit_with_bls12_381() { fn test_output_circuit_with_bls12_381() { use ff::Field; use pairing::bls12_381::*; - use rand::{SeedableRng, Rng, XorShiftRng}; + use rand::{SeedableRng, Rng, RngCore, XorShiftRng}; use ::circuit::test::*; use jubjub::{JubjubBls12, fs, edwards}; let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x58, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { let value_commitment = ValueCommitment { value: rng.gen(), - randomness: rng.gen() + randomness: fs::Fs::random(rng), }; - let nsk: fs::Fs = rng.gen(); + let nsk = fs::Fs::random(rng); let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params); let proof_generation_key = ::primitives::ProofGenerationKey { @@ -758,7 +768,11 @@ fn test_output_circuit_with_bls12_381() { let payment_address; loop { - let diversifier = ::primitives::Diversifier(rng.gen()); + let diversifier = { + let mut d = [0; 11]; + rng.fill_bytes(&mut d); + ::primitives::Diversifier(d) + }; if let Some(p) = viewing_key.into_payment_address( diversifier, @@ -770,8 +784,8 @@ fn test_output_circuit_with_bls12_381() { } } - let commitment_randomness: fs::Fs = rng.gen(); - let esk: fs::Fs = rng.gen(); + let commitment_randomness = fs::Fs::random(rng); + let esk = fs::Fs::random(rng); { let mut cs = TestConstraintSystem::::new(); diff --git a/sapling-crypto/src/circuit/sha256.rs b/sapling-crypto/src/circuit/sha256.rs index 7b55fc8..4837640 100644 --- a/sapling-crypto/src/circuit/sha256.rs +++ b/sapling-crypto/src/circuit/sha256.rs @@ -341,7 +341,10 @@ mod test { #[test] fn test_full_block() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let iv = get_sha256_iv(); @@ -370,7 +373,10 @@ mod test { use crypto::sha2::Sha256; use crypto::digest::Digest; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) { diff --git a/sapling-crypto/src/circuit/uint32.rs b/sapling-crypto/src/circuit/uint32.rs index 6dd4535..daca627 100644 --- a/sapling-crypto/src/circuit/uint32.rs +++ b/sapling-crypto/src/circuit/uint32.rs @@ -420,7 +420,10 @@ mod test { #[test] fn test_uint32_from_bits_be() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { let mut v = (0..32).map(|_| Boolean::constant(rng.gen())).collect::>(); @@ -451,7 +454,10 @@ mod test { #[test] fn test_uint32_from_bits() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { let mut v = (0..32).map(|_| Boolean::constant(rng.gen())).collect::>(); @@ -482,7 +488,10 @@ mod test { #[test] fn test_uint32_xor() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); @@ -524,7 +533,10 @@ mod test { #[test] fn test_uint32_addmany_constants() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); @@ -563,7 +575,10 @@ mod test { #[test] fn test_uint32_addmany() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); @@ -620,7 +635,10 @@ mod test { #[test] fn test_uint32_rotr() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let mut num = rng.gen(); @@ -650,7 +668,10 @@ mod test { #[test] fn test_uint32_shr() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..50 { for i in 0..60 { @@ -670,7 +691,10 @@ mod test { #[test] fn test_uint32_sha256_maj() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); @@ -711,7 +735,10 @@ mod test { #[test] fn test_uint32_sha256_ch() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); diff --git a/sapling-crypto/src/jubjub/edwards.rs b/sapling-crypto/src/jubjub/edwards.rs index 16d21e7..95b6120 100644 --- a/sapling-crypto/src/jubjub/edwards.rs +++ b/sapling-crypto/src/jubjub/edwards.rs @@ -188,7 +188,7 @@ impl Point { pub fn rand(rng: &mut R, params: &E::Params) -> Self { loop { - let y: E::Fr = rng.gen(); + let y = E::Fr::random(rng); if let Some(p) = Self::get_for_y(y, rng.gen(), params) { return p; diff --git a/sapling-crypto/src/jubjub/fs.rs b/sapling-crypto/src/jubjub/fs.rs index 6a51573..55df2cb 100644 --- a/sapling-crypto/src/jubjub/fs.rs +++ b/sapling-crypto/src/jubjub/fs.rs @@ -4,6 +4,7 @@ use ff::{ LegendreSymbol::{self, *}, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, SqrtField, }; +use rand::RngCore; use super::ToUniform; @@ -42,13 +43,6 @@ const NEGATIVE_ONE: Fs = Fs(FsRepr([0xaa9f02ab1d6124de, 0xb3524a6466112932, 0x73 #[derive(Copy, Clone, PartialEq, Eq, Default, Debug)] pub struct FsRepr(pub [u64; 4]); -impl ::rand::Rand for FsRepr { - #[inline(always)] - fn rand(rng: &mut R) -> Self { - FsRepr(rng.gen()) - } -} - impl ::std::fmt::Display for FsRepr { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { @@ -240,21 +234,6 @@ impl ::std::fmt::Display for Fs } } -impl ::rand::Rand for Fs { - fn rand(rng: &mut R) -> Self { - loop { - let mut tmp = Fs(FsRepr::rand(rng)); - - // Mask away the unused bits at the beginning. - tmp.0.as_mut()[3] &= 0xffffffffffffffff >> REPR_SHAVE_BITS; - - if tmp.is_valid() { - return tmp - } - } - } -} - impl From for FsRepr { fn from(e: Fs) -> FsRepr { e.into_repr() @@ -303,6 +282,25 @@ impl PrimeField for Fs { } impl Field for Fs { + fn random(rng: &mut R) -> Self { + loop { + let mut tmp = { + let mut repr = [0u64; 4]; + for i in 0..4 { + repr[i] = rng.next_u64(); + } + Fs(FsRepr(repr)) + }; + + // Mask away the unused bits at the beginning. + tmp.0.as_mut()[3] &= 0xffffffffffffffff >> REPR_SHAVE_BITS; + + if tmp.is_valid() { + return tmp + } + } + } + #[inline] fn zero() -> Self { Fs(FsRepr::from(0)) @@ -622,7 +620,7 @@ fn test_neg_one() { } #[cfg(test)] -use rand::{SeedableRng, XorShiftRng, Rand}; +use rand::{SeedableRng, XorShiftRng}; #[test] fn test_fs_repr_ordering() { @@ -760,14 +758,17 @@ fn test_fs_repr_num_bits() { #[test] fn test_fs_repr_sub_noborrow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let mut t = FsRepr([0x8e62a7e85264e2c3, 0xb23d34c1941d3ca, 0x5976930b7502dd15, 0x600f3fb517bf5495]); t.sub_noborrow(&FsRepr([0xd64f669809cbc6a4, 0xfa76cb9d90cf7637, 0xfefb0df9038d43b3, 0x298a30c744b31acf])); assert!(t == FsRepr([0xb813415048991c1f, 0x10ad07ae88725d92, 0x5a7b851271759961, 0x36850eedd30c39c5])); for _ in 0..1000 { - let mut a = FsRepr::rand(&mut rng); + let mut a = Fs::random(&mut rng).into_repr(); a.0[3] >>= 30; let mut b = a; for _ in 0..10 { @@ -806,7 +807,10 @@ fn test_fs_legendre() { #[test] fn test_fr_repr_add_nocarry() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let mut t = FsRepr([0xd64f669809cbc6a4, 0xfa76cb9d90cf7637, 0xfefb0df9038d43b3, 0x298a30c744b31acf]); t.add_nocarry(&FsRepr([0x8e62a7e85264e2c3, 0xb23d34c1941d3ca, 0x5976930b7502dd15, 0x600f3fb517bf5495])); @@ -814,9 +818,9 @@ fn test_fr_repr_add_nocarry() { // Test for the associativity of addition. for _ in 0..1000 { - let mut a = FsRepr::rand(&mut rng); - let mut b = FsRepr::rand(&mut rng); - let mut c = FsRepr::rand(&mut rng); + let mut a = Fs::random(&mut rng).into_repr(); + let mut b = Fs::random(&mut rng).into_repr(); + let mut c = Fs::random(&mut rng).into_repr(); // Unset the first few bits, so that overflow won't occur. a.0[3] >>= 3; @@ -865,10 +869,13 @@ fn test_fs_is_valid() { assert!(Fs(FsRepr([0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9])).is_valid()); assert!(!Fs(FsRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])).is_valid()); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let a = Fs::rand(&mut rng); + let a = Fs::random(&mut rng); assert!(a.is_valid()); } } @@ -903,13 +910,16 @@ fn test_fs_add_assign() { // Test associativity - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Generate a, b, c and ensure (a + b) + c == a + (b + c). - let a = Fs::rand(&mut rng); - let b = Fs::rand(&mut rng); - let c = Fs::rand(&mut rng); + let a = Fs::random(&mut rng); + let b = Fs::random(&mut rng); + let c = Fs::random(&mut rng); let mut tmp1 = a; tmp1.add_assign(&b); @@ -948,12 +958,15 @@ fn test_fs_sub_assign() { assert_eq!(tmp, Fs(FsRepr([0x361e16aef5cce835, 0x55bbde2536e274c1, 0x4dc77a63fd15ee75, 0x1e14bb37c14f230]))); } - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Ensure that (a - b) + (b - a) = 0. - let a = Fs::rand(&mut rng); - let b = Fs::rand(&mut rng); + let a = Fs::random(&mut rng); + let b = Fs::random(&mut rng); let mut tmp1 = a; tmp1.sub_assign(&b); @@ -972,13 +985,16 @@ fn test_fs_mul_assign() { tmp.mul_assign(&Fs(FsRepr([0xdae00fc63c9fa90f, 0x5a5ed89b96ce21ce, 0x913cd26101bd6f58, 0x3f0822831697fe9]))); assert!(tmp == Fs(FsRepr([0xb68ecb61d54d2992, 0x5ff95874defce6a6, 0x3590eb053894657d, 0x53823a118515933]))); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000000 { // Ensure that (a * b) * c = a * (b * c) - let a = Fs::rand(&mut rng); - let b = Fs::rand(&mut rng); - let c = Fs::rand(&mut rng); + let a = Fs::random(&mut rng); + let b = Fs::random(&mut rng); + let c = Fs::random(&mut rng); let mut tmp1 = a; tmp1.mul_assign(&b); @@ -994,10 +1010,10 @@ fn test_fs_mul_assign() { for _ in 0..1000000 { // Ensure that r * (a + b + c) = r*a + r*b + r*c - let r = Fs::rand(&mut rng); - let mut a = Fs::rand(&mut rng); - let mut b = Fs::rand(&mut rng); - let mut c = Fs::rand(&mut rng); + let r = Fs::random(&mut rng); + let mut a = Fs::random(&mut rng); + let mut b = Fs::random(&mut rng); + let mut c = Fs::random(&mut rng); let mut tmp1 = a; tmp1.add_assign(&b); @@ -1022,11 +1038,14 @@ fn test_fr_squaring() { a.square(); assert_eq!(a, Fs::from_repr(FsRepr([0x12c7f55cbc52fbaa, 0xdedc98a0b5e6ce9e, 0xad2892726a5396a, 0x9fe82af8fee77b3])).unwrap()); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000000 { // Ensure that (a * a) = a^2 - let a = Fs::rand(&mut rng); + let a = Fs::random(&mut rng); let mut tmp = a; tmp.square(); @@ -1042,13 +1061,16 @@ fn test_fr_squaring() { fn test_fs_inverse() { assert!(Fs::zero().inverse().is_none()); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let one = Fs::one(); for _ in 0..1000 { // Ensure that a * a^-1 = 1 - let mut a = Fs::rand(&mut rng); + let mut a = Fs::random(&mut rng); let ainv = a.inverse().unwrap(); a.mul_assign(&ainv); assert_eq!(a, one); @@ -1057,11 +1079,14 @@ fn test_fs_inverse() { #[test] fn test_fs_double() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Ensure doubling a is equivalent to adding a to itself. - let mut a = Fs::rand(&mut rng); + let mut a = Fs::random(&mut rng); let mut b = a; b.add_assign(&a); a.double(); @@ -1078,11 +1103,14 @@ fn test_fs_negate() { assert!(a.is_zero()); } - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Ensure (a - (-a)) = 0. - let mut a = Fs::rand(&mut rng); + let mut a = Fs::random(&mut rng); let mut b = a; b.negate(); a.add_assign(&b); @@ -1093,12 +1121,15 @@ fn test_fs_negate() { #[test] fn test_fs_pow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for i in 0..1000 { // Exponentiate by various small numbers and ensure it consists with repeated // multiplication. - let a = Fs::rand(&mut rng); + let a = Fs::random(&mut rng); let target = a.pow(&[i]); let mut c = Fs::one(); for _ in 0..i { @@ -1109,7 +1140,7 @@ fn test_fs_pow() { for _ in 0..1000 { // Exponentiating by the modulus should have no effect in a prime field. - let a = Fs::rand(&mut rng); + let a = Fs::random(&mut rng); assert_eq!(a, a.pow(Fs::char())); } @@ -1117,13 +1148,16 @@ fn test_fs_pow() { #[test] fn test_fs_sqrt() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); assert_eq!(Fs::zero().sqrt().unwrap(), Fs::zero()); for _ in 0..1000 { // Ensure sqrt(a^2) = a or -a - let a = Fs::rand(&mut rng); + let a = Fs::random(&mut rng); let mut nega = a; nega.negate(); let mut b = a; @@ -1136,7 +1170,7 @@ fn test_fs_sqrt() { for _ in 0..1000 { // Ensure sqrt(a)^2 = a for random a - let a = Fs::rand(&mut rng); + let a = Fs::random(&mut rng); if let Some(mut tmp) = a.sqrt() { tmp.square(); @@ -1166,11 +1200,14 @@ fn test_fs_from_into_repr() { // Zero should be in the field. assert!(Fs::from_repr(FsRepr::from(0)).unwrap().is_zero()); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Try to turn Fs elements into representations and back again, and compare. - let a = Fs::rand(&mut rng); + let a = Fs::random(&mut rng); let a_repr = a.into_repr(); let b_repr = FsRepr::from(a); assert_eq!(a_repr, b_repr); diff --git a/sapling-crypto/src/jubjub/montgomery.rs b/sapling-crypto/src/jubjub/montgomery.rs index 76203eb..28dce8e 100644 --- a/sapling-crypto/src/jubjub/montgomery.rs +++ b/sapling-crypto/src/jubjub/montgomery.rs @@ -104,7 +104,7 @@ impl Point { pub fn rand(rng: &mut R, params: &E::Params) -> Self { loop { - let x: E::Fr = rng.gen(); + let x = E::Fr::random(rng); match Self::get_for_x(x, rng.gen(), params) { Some(p) => { diff --git a/sapling-crypto/src/jubjub/tests.rs b/sapling-crypto/src/jubjub/tests.rs index eb7e36b..19aae80 100644 --- a/sapling-crypto/src/jubjub/tests.rs +++ b/sapling-crypto/src/jubjub/tests.rs @@ -14,7 +14,7 @@ use ff::{ LegendreSymbol }; -use rand::{XorShiftRng, SeedableRng, Rand}; +use rand::{RngCore, XorShiftRng, SeedableRng}; pub fn test_suite(params: &E::Params) { test_back_and_forth::(params); @@ -78,7 +78,10 @@ fn is_on_twisted_edwards_curve>( } fn test_loworder(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let inf = montgomery::Point::zero(); // try to find a point of order 8 @@ -109,15 +112,18 @@ fn test_loworder(params: &E::Params) { fn test_mul_associativity(params: &E::Params) { use self::edwards::Point; - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { // Pick a random point and multiply it by the cofactor let base = Point::::rand(rng, params).mul_by_cofactor(params); - let mut a = E::Fs::rand(rng); - let b = E::Fs::rand(rng); - let c = E::Fs::rand(rng); + let mut a = E::Fs::random(rng); + let b = E::Fs::random(rng); + let c = E::Fs::random(rng); let res1 = base.mul(a, params).mul(b, params).mul(c, params); let res2 = base.mul(b, params).mul(c, params).mul(a, params); @@ -143,7 +149,10 @@ fn test_mul_associativity(params: &E::Params) { fn test_order(params: &E::Params) { use self::edwards::Point; - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); // The neutral element is in the prime order subgroup. assert!(Point::::zero().as_prime_order(params).is_some()); @@ -170,7 +179,10 @@ fn test_order(params: &E::Params) { } fn test_addition_associativity(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { use self::montgomery::Point; @@ -194,7 +206,10 @@ fn test_addition_associativity(params: &E::Params) { } fn test_identities(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); { use self::edwards::Point; @@ -228,11 +243,14 @@ fn test_identities(params: &E::Params) { } fn test_get_for(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let y = E::Fr::rand(rng); - let sign = bool::rand(rng); + let y = E::Fr::random(rng); + let sign = rng.next_u32() % 2 == 1; if let Some(mut p) = edwards::Point::::get_for_y(y, sign, params) { assert!(p.into_xy().0.into_repr().is_odd() == sign); @@ -247,7 +265,10 @@ fn test_get_for(params: &E::Params) { } fn test_read_write(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { let e = edwards::Point::::rand(rng, params); @@ -262,7 +283,10 @@ fn test_read_write(params: &E::Params) { } fn test_rand(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { let p = montgomery::Point::::rand(rng, params); @@ -281,10 +305,13 @@ fn test_rand(params: &E::Params) { } fn test_back_and_forth(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x5d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let s = E::Fs::rand(rng); + let s = E::Fs::random(rng); let edwards_p1 = edwards::Point::::rand(rng, params); let mont_p1 = montgomery::Point::from_edwards(&edwards_p1, params); let mont_p2 = montgomery::Point::::rand(rng, params); diff --git a/sapling-crypto/src/redjubjub.rs b/sapling-crypto/src/redjubjub.rs index 00e2f8f..2b34654 100644 --- a/sapling-crypto/src/redjubjub.rs +++ b/sapling-crypto/src/redjubjub.rs @@ -2,7 +2,7 @@ //! See section 5.4.6 of the Sapling protocol specification. use ff::{Field, PrimeField, PrimeFieldRepr}; -use rand::{Rng, Rand}; +use rand::{Rng}; use std::io::{self, Read, Write}; use jubjub::{FixedGenerators, JubjubEngine, JubjubParams, Unknown, edwards::Point}; @@ -184,7 +184,7 @@ pub fn batch_verify<'a, E: JubjubEngine, R: Rng>( let mut c = h_star::(&entry.sig.rbar[..], entry.msg); - let z = E::Fs::rand(rng); + let z = E::Fs::random(rng); s.mul_assign(&z); s.negate(); @@ -218,13 +218,13 @@ mod tests { let params = &JubjubBls12::new(); let p_g = FixedGenerators::SpendingKeyGenerator; - let sk1 = PrivateKey::(rng.gen()); + let sk1 = PrivateKey::(Fs::random(rng)); let vk1 = PublicKey::from_private(&sk1, p_g, params); let msg1 = b"Foo bar"; let sig1 = sk1.sign(msg1, rng, p_g, params); assert!(vk1.verify(msg1, &sig1, p_g, params)); - let sk2 = PrivateKey::(rng.gen()); + let sk2 = PrivateKey::(Fs::random(rng)); let vk2 = PublicKey::from_private(&sk2, p_g, params); let msg2 = b"Foo bar"; let sig2 = sk2.sign(msg2, rng, p_g, params); @@ -262,7 +262,7 @@ mod tests { } }; - let sk = PrivateKey::(rng.gen()); + let sk = PrivateKey::(Fs::random(rng)); let vk = PublicKey::from_private(&sk, p_g, params); // TODO: This test will need to change when #77 is fixed @@ -281,7 +281,7 @@ mod tests { let params = &JubjubBls12::new(); for _ in 0..1000 { - let sk = PrivateKey::(rng.gen()); + let sk = PrivateKey::(Fs::random(rng)); let vk = PublicKey::from_private(&sk, p_g, params); let msg = b"Foo bar"; let sig = sk.sign(msg, rng, p_g, params); @@ -314,7 +314,7 @@ mod tests { let params = &JubjubBls12::new(); for _ in 0..1000 { - let sk = PrivateKey::(rng.gen()); + let sk = PrivateKey::(Fs::random(rng)); let vk = PublicKey::from_private(&sk, p_g, params); let msg1 = b"Foo bar"; @@ -328,7 +328,7 @@ mod tests { assert!(!vk.verify(msg1, &sig2, p_g, params)); assert!(!vk.verify(msg2, &sig1, p_g, params)); - let alpha = rng.gen(); + let alpha = Fs::random(rng); let rsk = sk.randomize(alpha); let rvk = vk.randomize(alpha, p_g, params); From 6149166ccb41d500eef227a9e6ec492086f9be9b Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 11 Jul 2019 09:00:24 -0400 Subject: [PATCH 029/330] Migrate zcash_primitives to rand 0.5 --- Cargo.lock | 2 +- zcash_primitives/Cargo.toml | 2 +- zcash_primitives/src/merkle_tree.rs | 12 +++++---- zcash_primitives/src/note_encryption.rs | 32 +++++++++++++---------- zcash_primitives/src/transaction/tests.rs | 10 ++++--- 5 files changed, 34 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a823c3e..d846871 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -594,7 +594,7 @@ dependencies = [ "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index 771f351..d82b3bc 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -15,6 +15,6 @@ fpe = "0.1" hex = "0.3" lazy_static = "1" pairing = { path = "../pairing" } -rand = "0.4" +rand = "0.5" sapling-crypto = { path = "../sapling-crypto" } sha2 = "0.8" diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 118d7db..3b94bd9 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -200,12 +200,14 @@ impl CommitmentTree { /// # Examples /// /// ``` +/// extern crate ff; /// extern crate pairing; /// extern crate rand; /// extern crate zcash_primitives; /// -/// use pairing::bls12_381::FrRepr; -/// use rand::{OsRng, Rand}; +/// use ff::{Field, PrimeField}; +/// use pairing::bls12_381::Fr; +/// use rand::OsRng; /// use zcash_primitives::{ /// merkle_tree::{CommitmentTree, IncrementalWitness}, /// sapling::Node, @@ -214,13 +216,13 @@ impl CommitmentTree { /// let mut rng = OsRng::new().unwrap(); /// let mut tree = CommitmentTree::::new(); /// -/// tree.append(Node::new(FrRepr::rand(&mut rng))); -/// tree.append(Node::new(FrRepr::rand(&mut rng))); +/// tree.append(Node::new(Fr::random(&mut rng).into_repr())); +/// tree.append(Node::new(Fr::random(&mut rng).into_repr())); /// let mut witness = IncrementalWitness::from_tree(&tree); /// assert_eq!(witness.position(), 1); /// assert_eq!(tree.root(), witness.root()); /// -/// let cmu = Node::new(FrRepr::rand(&mut rng)); +/// let cmu = Node::new(Fr::random(&mut rng).into_repr()); /// tree.append(cmu); /// witness.append(cmu); /// assert_eq!(tree.root(), witness.root()); diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 610b746..b1b483f 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -211,12 +211,14 @@ fn prf_ock( /// # Examples /// /// ``` +/// extern crate ff; /// extern crate pairing; /// extern crate rand; /// extern crate sapling_crypto; /// +/// use ff::Field; /// use pairing::bls12_381::Bls12; -/// use rand::{OsRng, Rand}; +/// use rand::OsRng; /// use sapling_crypto::{ /// jubjub::fs::Fs, /// primitives::{Diversifier, PaymentAddress, ValueCommitment}, @@ -238,7 +240,7 @@ fn prf_ock( /// let ovk = OutgoingViewingKey([0; 32]); /// /// let value = 1000; -/// let rcv = Fs::rand(&mut rng); +/// let rcv = Fs::random(&mut rng); /// let cv = ValueCommitment:: { /// value, /// randomness: rcv.clone(), @@ -558,9 +560,9 @@ pub fn try_sapling_output_recovery( #[cfg(test)] mod tests { use crypto_api_chachapoly::ChachaPolyIetf; - use ff::{PrimeField, PrimeFieldRepr}; + use ff::{Field, PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; - use rand::{thread_rng, Rand, Rng}; + use rand::{thread_rng, RngCore}; use sapling_crypto::{ jubjub::{ edwards, @@ -692,8 +694,8 @@ mod tests { assert_eq!(Memo::default().to_utf8(), None); } - fn random_enc_ciphertext( - mut rng: &mut Rng, + fn random_enc_ciphertext( + mut rng: &mut R, ) -> ( OutgoingViewingKey, Fs, @@ -704,7 +706,7 @@ mod tests { [u8; OUT_CIPHERTEXT_SIZE], ) { let diversifier = Diversifier([0; 11]); - let ivk = Fs::rand(&mut rng); + let ivk = Fs::random(&mut rng); let pk_d = diversifier.g_d::(&JUBJUB).unwrap().mul(ivk, &JUBJUB); let pa = PaymentAddress { diversifier, pk_d }; @@ -712,11 +714,13 @@ mod tests { let value = 100; let value_commitment = ValueCommitment:: { value, - randomness: Fs::rand(&mut rng), + randomness: Fs::random(&mut rng), }; let cv = value_commitment.cm(&JUBJUB).into(); - let note = pa.create_note(value, Fs::rand(&mut rng), &JUBJUB).unwrap(); + let note = pa + .create_note(value, Fs::random(&mut rng), &JUBJUB) + .unwrap(); let cmu = note.cm(&JUBJUB); let ovk = OutgoingViewingKey([0; 32]); @@ -849,7 +853,7 @@ mod tests { let (_, _, _, cmu, epk, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); assert_eq!( - try_sapling_note_decryption(&Fs::rand(&mut rng), &epk, &cmu, &enc_ciphertext), + try_sapling_note_decryption(&Fs::random(&mut rng), &epk, &cmu, &enc_ciphertext), None ); } @@ -878,7 +882,7 @@ mod tests { let (_, ivk, _, _, epk, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); assert_eq!( - try_sapling_note_decryption(&ivk, &epk, &Fr::rand(&mut rng), &enc_ciphertext), + try_sapling_note_decryption(&ivk, &epk, &Fr::random(&mut rng), &enc_ciphertext), None ); } @@ -970,7 +974,7 @@ mod tests { assert_eq!( try_sapling_compact_note_decryption( - &Fs::rand(&mut rng), + &Fs::random(&mut rng), &epk, &cmu, &enc_ciphertext[..COMPACT_NOTE_SIZE] @@ -1006,7 +1010,7 @@ mod tests { try_sapling_compact_note_decryption( &ivk, &epk, - &Fr::rand(&mut rng), + &Fr::random(&mut rng), &enc_ciphertext[..COMPACT_NOTE_SIZE] ), None @@ -1137,7 +1141,7 @@ mod tests { try_sapling_output_recovery( &ovk, &cv, - &Fr::rand(&mut rng), + &Fr::random(&mut rng), &epk, &enc_ciphertext, &out_ciphertext diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index 1275bba..7ef691f 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -1,6 +1,10 @@ +use ff::Field; use pairing::bls12_381::Bls12; -use rand::{thread_rng, Rng}; -use sapling_crypto::{jubjub::FixedGenerators, redjubjub::PrivateKey}; +use rand::thread_rng; +use sapling_crypto::{ + jubjub::{fs::Fs, FixedGenerators}, + redjubjub::PrivateKey, +}; use super::{ components::{Amount, Script}, @@ -194,7 +198,7 @@ fn tx_write_rejects_unexpected_binding_sig() { // Fails with an unexpected binding signature { let rng = &mut thread_rng(); - let sk = PrivateKey::(rng.gen()); + let sk = PrivateKey::(Fs::random(rng)); let sig = sk.sign( b"Foo bar", rng, From ccf75c39c125a806cb811ff32f780f21fba70c9f Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 11 Jul 2019 09:03:04 -0400 Subject: [PATCH 030/330] Migrate remaining crates to rand 0.5 --- Cargo.lock | 6 +++--- librustzcash/Cargo.toml | 2 +- zcash_client_backend/Cargo.toml | 2 +- zcash_client_backend/src/encoding.rs | 28 ++++++++++++++++++++-------- zcash_proofs/Cargo.toml | 2 +- zcash_proofs/src/sapling/prover.rs | 6 +++--- 6 files changed, 29 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d846871..0efc26d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -328,7 +328,7 @@ dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", "zcash_proofs 0.0.0", @@ -576,7 +576,7 @@ version = "0.0.0" dependencies = [ "bech32 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", ] @@ -608,7 +608,7 @@ dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", ] diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index e75a71c..f37b899 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -22,7 +22,7 @@ libc = "0.2" pairing = { path = "../pairing" } lazy_static = "1" byteorder = "1" -rand = "0.4" +rand = "0.5" sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } zcash_proofs = { path = "../zcash_proofs" } diff --git a/zcash_client_backend/Cargo.toml b/zcash_client_backend/Cargo.toml index bc57fdb..38c9988 100644 --- a/zcash_client_backend/Cargo.toml +++ b/zcash_client_backend/Cargo.toml @@ -13,4 +13,4 @@ sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } [dev-dependencies] -rand = "0.4" +rand = "0.5" diff --git a/zcash_client_backend/src/encoding.rs b/zcash_client_backend/src/encoding.rs index 17ef335..3d70b41 100644 --- a/zcash_client_backend/src/encoding.rs +++ b/zcash_client_backend/src/encoding.rs @@ -112,7 +112,10 @@ pub fn decode_extended_full_viewing_key( /// }; /// use zcash_primitives::JUBJUB; /// -/// let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); +/// let rng = &mut XorShiftRng::from_seed([ +/// 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, +/// 0xbc, 0xe5, +/// ]); /// /// let pa = PaymentAddress { /// diversifier: Diversifier([0u8; 11]), @@ -121,7 +124,7 @@ pub fn decode_extended_full_viewing_key( /// /// assert_eq!( /// encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, &pa), -/// "ztestsapling1qqqqqqqqqqqqqqqqqqxrrfaccydp867g6zg7ne5ht37z38jtfyw0ygmp0ja6hhf07twjq6awtaj", +/// "ztestsapling1qqqqqqqqqqqqqqqqqrjq05nyfku05msvu49mawhg6kr0wwljahypwyk2h88z6975u563j0ym7pe", /// ); /// ``` pub fn encode_payment_address(hrp: &str, addr: &PaymentAddress) -> String { @@ -148,7 +151,10 @@ pub fn encode_payment_address(hrp: &str, addr: &PaymentAddress) -> String /// }; /// use zcash_primitives::JUBJUB; /// -/// let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); +/// let rng = &mut XorShiftRng::from_seed([ +/// 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, +/// 0xbc, 0xe5, +/// ]); /// /// let pa = PaymentAddress { /// diversifier: Diversifier([0u8; 11]), @@ -158,7 +164,7 @@ pub fn encode_payment_address(hrp: &str, addr: &PaymentAddress) -> String /// assert_eq!( /// decode_payment_address( /// HRP_SAPLING_PAYMENT_ADDRESS, -/// "ztestsapling1qqqqqqqqqqqqqqqqqqxrrfaccydp867g6zg7ne5ht37z38jtfyw0ygmp0ja6hhf07twjq6awtaj", +/// "ztestsapling1qqqqqqqqqqqqqqqqqrjq05nyfku05msvu49mawhg6kr0wwljahypwyk2h88z6975u563j0ym7pe", /// ), /// Ok(Some(pa)), /// ); @@ -194,7 +200,10 @@ mod tests { #[test] fn payment_address() { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let addr = PaymentAddress { diversifier: Diversifier([0u8; 11]), @@ -202,9 +211,9 @@ mod tests { }; let encoded_main = - "zs1qqqqqqqqqqqqqqqqqqxrrfaccydp867g6zg7ne5ht37z38jtfyw0ygmp0ja6hhf07twjqj2ug6x"; + "zs1qqqqqqqqqqqqqqqqqrjq05nyfku05msvu49mawhg6kr0wwljahypwyk2h88z6975u563j8nfaxd"; let encoded_test = - "ztestsapling1qqqqqqqqqqqqqqqqqqxrrfaccydp867g6zg7ne5ht37z38jtfyw0ygmp0ja6hhf07twjq6awtaj"; + "ztestsapling1qqqqqqqqqqqqqqqqqrjq05nyfku05msvu49mawhg6kr0wwljahypwyk2h88z6975u563j0ym7pe"; assert_eq!( encode_payment_address(constants::mainnet::HRP_SAPLING_PAYMENT_ADDRESS, &addr), @@ -235,7 +244,10 @@ mod tests { #[test] fn invalid_diversifier() { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let addr = PaymentAddress { diversifier: Diversifier([1u8; 11]), diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index 34bd520..7072fb2 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -11,6 +11,6 @@ blake2b_simd = "0.5" byteorder = "1" ff = { path = "../ff" } pairing = { path = "../pairing" } -rand = "0.4" +rand = "0.5" sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index 4d63033..5600cdb 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -3,7 +3,7 @@ use bellman::groth16::{ }; use ff::Field; use pairing::bls12_381::{Bls12, Fr}; -use rand::{OsRng, Rand}; +use rand::OsRng; use sapling_crypto::{ circuit::{ multipack, @@ -59,7 +59,7 @@ impl SaplingProvingContext { let mut rng = OsRng::new().expect("should be able to construct RNG"); // We create the randomness of the value commitment - let rcv = Fs::rand(&mut rng); + let rcv = Fs::random(&mut rng); // Accumulate the value commitment randomness in the context { @@ -194,7 +194,7 @@ impl SaplingProvingContext { // We construct ephemeral randomness for the value commitment. This // randomness is not given back to the caller, but the synthetic // blinding factor `bsk` is accumulated in the context. - let rcv = Fs::rand(&mut rng); + let rcv = Fs::random(&mut rng); // Accumulate the value commitment randomness in the context { From 5728bda2c1a91dd0a5942153652510cb496a1400 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 11 Jul 2019 10:27:05 -0400 Subject: [PATCH 031/330] Replace rust-crypto with sha2 in sapling-crypto dev-dependencies This removes rand < 0.5 from our Cargo.lock. --- Cargo.lock | 82 +--------------------------- sapling-crypto/Cargo.toml | 2 +- sapling-crypto/src/circuit/sha256.rs | 6 +- sapling-crypto/src/lib.rs | 2 +- 4 files changed, 5 insertions(+), 87 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0efc26d..034f7ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -227,20 +227,6 @@ name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "futures" version = "0.1.21" @@ -255,11 +241,6 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "gcc" -version = "0.3.54" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "generic-array" version = "0.9.0" @@ -419,26 +400,6 @@ dependencies = [ "proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rand" version = "0.5.6" @@ -464,28 +425,6 @@ name = "rand_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "redox_syscall" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rust-crypto" -version = "0.2.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "sapling-crypto" version = "0.0.1" @@ -499,7 +438,7 @@ dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -531,16 +470,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "time" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "typenum" version = "1.10.0" @@ -640,11 +569,8 @@ dependencies = [ "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce3371c82bfbd984f624cab093f55e7336f5a6e589f8518e1258f54f011b89ad" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" @@ -663,18 +589,12 @@ dependencies = [ "checksum proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5cb6f960ad471404618e9817c0e5d10b1ae74cfdf01fab89ea0641fe7fb2892" "checksum proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b331c6ad3411474cd55540398dc7ad89fc41488e64ec71fdecc9c9b86de96fb0" "checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" -"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" -"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" -"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" -"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "30dc6118470d69ce0fdcf7e6f95e95853f7f4f72f80d835d4519577c323814ab" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" -"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" diff --git a/sapling-crypto/Cargo.toml b/sapling-crypto/Cargo.toml index 3d895db..34e91eb 100644 --- a/sapling-crypto/Cargo.toml +++ b/sapling-crypto/Cargo.toml @@ -23,4 +23,4 @@ byteorder = "1" [dev-dependencies] hex-literal = "0.1" -rust-crypto = "0.2" +sha2 = "0.8" diff --git a/sapling-crypto/src/circuit/sha256.rs b/sapling-crypto/src/circuit/sha256.rs index 4837640..86147f8 100644 --- a/sapling-crypto/src/circuit/sha256.rs +++ b/sapling-crypto/src/circuit/sha256.rs @@ -370,8 +370,7 @@ mod test { #[test] fn test_against_vectors() { - use crypto::sha2::Sha256; - use crypto::digest::Digest; + use sha2::{Digest, Sha256}; let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, @@ -383,8 +382,7 @@ mod test { let mut h = Sha256::new(); let data: Vec = (0..input_len).map(|_| rng.gen()).collect(); h.input(&data); - let mut hash_result = [0u8; 32]; - h.result(&mut hash_result[..]); + let hash_result = h.result(); let mut cs = TestConstraintSystem::::new(); let mut input_bits = vec![]; diff --git a/sapling-crypto/src/lib.rs b/sapling-crypto/src/lib.rs index 0535d9a..da3bbc4 100644 --- a/sapling-crypto/src/lib.rs +++ b/sapling-crypto/src/lib.rs @@ -12,7 +12,7 @@ extern crate byteorder; extern crate hex_literal; #[cfg(test)] -extern crate crypto; +extern crate sha2; pub mod jubjub; pub mod group_hash; From 83e1af104e9371aeea85db9c60f07b52857e053f Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 12 Jul 2019 23:51:35 -0400 Subject: [PATCH 032/330] Migrate ff, group, pairing, and bellman to rand 0.6 --- Cargo.lock | 119 ++++++++++++++++++++++++++++++++-- bellman/Cargo.toml | 4 +- ff/Cargo.toml | 2 +- group/Cargo.toml | 3 +- group/src/lib.rs | 1 + group/src/tests/mod.rs | 3 +- pairing/Cargo.toml | 4 +- pairing/src/bls12_381/fq.rs | 4 +- pairing/src/bls12_381/fq12.rs | 4 +- pairing/src/bls12_381/fq2.rs | 4 +- pairing/src/bls12_381/fq6.rs | 4 +- pairing/src/bls12_381/fr.rs | 4 +- pairing/src/lib.rs | 2 +- pairing/src/tests/engine.rs | 3 +- pairing/src/tests/field.rs | 21 +++--- pairing/src/tests/repr.rs | 3 +- 16 files changed, 154 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 034f7ee..d4aee36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,6 +43,11 @@ dependencies = [ "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "autocfg" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bech32" version = "0.6.0" @@ -61,8 +66,8 @@ dependencies = [ "group 0.1.0", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -195,7 +200,7 @@ version = "0.4.0" dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff_derive 0.3.0", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -262,7 +267,8 @@ name = "group" version = "0.1.0" dependencies = [ "ff 0.4.0", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -367,8 +373,8 @@ dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "group 0.1.0", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -412,6 +418,33 @@ dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_core" version = "0.3.1" @@ -425,6 +458,70 @@ name = "rand_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sapling-crypto" version = "0.0.1" @@ -548,6 +645,7 @@ dependencies = [ "checksum aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6810b7fb9f2bb4f76f05ac1c170b8dde285b6308955dc3afd89710268c958d9e" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" +"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" "checksum bech32 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58946044516aa9dc922182e0d6e9d124a31aafe6b421614654eb27cf90cec09c" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" @@ -590,8 +688,17 @@ dependencies = [ "checksum proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b331c6ad3411474cd55540398dc7ad89fc41488e64ec71fdecc9c9b86de96fb0" "checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" "checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "30dc6118470d69ce0fdcf7e6f95e95853f7f4f72f80d835d4519577c323814ab" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" diff --git a/bellman/Cargo.toml b/bellman/Cargo.toml index 72a8034..a56b1ed 100644 --- a/bellman/Cargo.toml +++ b/bellman/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/ebfull/bellman" version = "0.1.0" [dependencies] -rand_core = "0.3" +rand_core = "0.4" bit-vec = "0.4.4" ff = { path = "../ff" } futures = "0.1" @@ -21,7 +21,7 @@ pairing = { path = "../pairing", optional = true } byteorder = "1" [dev-dependencies] -rand = "0.5" +rand = "0.6" [features] groth16 = ["pairing"] diff --git a/ff/Cargo.toml b/ff/Cargo.toml index f428ccd..853f19d 100644 --- a/ff/Cargo.toml +++ b/ff/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/ebfull/ff" [dependencies] byteorder = "1" -rand_core = "0.3" +rand_core = "0.4" ff_derive = { version = "0.3.0", path = "ff_derive", optional = true } [features] diff --git a/group/Cargo.toml b/group/Cargo.toml index 020a5bd..f278b4e 100644 --- a/group/Cargo.toml +++ b/group/Cargo.toml @@ -14,4 +14,5 @@ repository = "https://github.com/ebfull/group" [dependencies] ff = { path = "../ff" } -rand = "0.5" +rand = "0.6" +rand_xorshift = "0.1" diff --git a/group/src/lib.rs b/group/src/lib.rs index a97a72c..448c5a3 100644 --- a/group/src/lib.rs +++ b/group/src/lib.rs @@ -1,5 +1,6 @@ extern crate ff; extern crate rand; +extern crate rand_xorshift; use ff::{PrimeField, PrimeFieldDecodingError, ScalarEngine, SqrtField}; use rand::RngCore; diff --git a/group/src/tests/mod.rs b/group/src/tests/mod.rs index 5d7e546..2b58b6c 100644 --- a/group/src/tests/mod.rs +++ b/group/src/tests/mod.rs @@ -1,5 +1,6 @@ use ff::{Field, PrimeField}; -use rand::{SeedableRng, XorShiftRng}; +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; use {CurveAffine, CurveProjective, EncodedPoint}; diff --git a/pairing/Cargo.toml b/pairing/Cargo.toml index b6ba134..5a065e2 100644 --- a/pairing/Cargo.toml +++ b/pairing/Cargo.toml @@ -15,13 +15,13 @@ homepage = "https://github.com/ebfull/pairing" repository = "https://github.com/ebfull/pairing" [dependencies] -rand_core = "0.3" +rand_core = "0.4" byteorder = "1" ff = { path = "../ff", features = ["derive"] } group = { path = "../group" } [dev-dependencies] -rand = "0.5" +rand_xorshift = "0.1" [features] unstable-features = ["expose-arith"] diff --git a/pairing/src/bls12_381/fq.rs b/pairing/src/bls12_381/fq.rs index b006812..0f54196 100644 --- a/pairing/src/bls12_381/fq.rs +++ b/pairing/src/bls12_381/fq.rs @@ -1173,7 +1173,9 @@ fn test_neg_one() { } #[cfg(test)] -use rand::{SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +#[cfg(test)] +use rand_xorshift::XorShiftRng; #[test] fn test_fq_repr_ordering() { diff --git a/pairing/src/bls12_381/fq12.rs b/pairing/src/bls12_381/fq12.rs index 4f675cf..f07a337 100644 --- a/pairing/src/bls12_381/fq12.rs +++ b/pairing/src/bls12_381/fq12.rs @@ -147,7 +147,9 @@ impl Field for Fq12 { } #[cfg(test)] -use rand::{SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +#[cfg(test)] +use rand_xorshift::XorShiftRng; #[test] fn test_fq12_mul_by_014() { diff --git a/pairing/src/bls12_381/fq2.rs b/pairing/src/bls12_381/fq2.rs index c69f13c..994a28a 100644 --- a/pairing/src/bls12_381/fq2.rs +++ b/pairing/src/bls12_381/fq2.rs @@ -877,7 +877,9 @@ fn test_fq2_legendre() { } #[cfg(test)] -use rand::{SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +#[cfg(test)] +use rand_xorshift::XorShiftRng; #[test] fn test_fq2_mul_nonresidue() { diff --git a/pairing/src/bls12_381/fq6.rs b/pairing/src/bls12_381/fq6.rs index 21c8310..87e64cb 100644 --- a/pairing/src/bls12_381/fq6.rs +++ b/pairing/src/bls12_381/fq6.rs @@ -301,7 +301,9 @@ impl Field for Fq6 { } #[cfg(test)] -use rand::{SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +#[cfg(test)] +use rand_xorshift::XorShiftRng; #[test] fn test_fq6_mul_nonresidue() { diff --git a/pairing/src/bls12_381/fr.rs b/pairing/src/bls12_381/fr.rs index 20811cd..cb378f4 100644 --- a/pairing/src/bls12_381/fr.rs +++ b/pairing/src/bls12_381/fr.rs @@ -6,7 +6,9 @@ use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr}; pub struct Fr(FrRepr); #[cfg(test)] -use rand::{SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +#[cfg(test)] +use rand_xorshift::XorShiftRng; #[test] fn test_fr_repr_ordering() { diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs index d498c35..1c8d90c 100644 --- a/pairing/src/lib.rs +++ b/pairing/src/lib.rs @@ -17,7 +17,7 @@ extern crate group; extern crate rand_core; #[cfg(test)] -extern crate rand; +extern crate rand_xorshift; #[cfg(test)] pub mod tests; diff --git a/pairing/src/tests/engine.rs b/pairing/src/tests/engine.rs index 8616129..fc74f1b 100644 --- a/pairing/src/tests/engine.rs +++ b/pairing/src/tests/engine.rs @@ -1,5 +1,6 @@ use group::{CurveAffine, CurveProjective}; -use rand::{SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +use rand_xorshift::XorShiftRng; use {Engine, Field, PairingCurveAffine, PrimeField}; diff --git a/pairing/src/tests/field.rs b/pairing/src/tests/field.rs index 0f2f1b2..0a33a73 100644 --- a/pairing/src/tests/field.rs +++ b/pairing/src/tests/field.rs @@ -1,5 +1,6 @@ use ff::{Field, LegendreSymbol, PrimeField, SqrtField}; -use rand::{Rng, SeedableRng, XorShiftRng}; +use rand_core::{RngCore, SeedableRng}; +use rand_xorshift::XorShiftRng; pub fn random_frobenius_tests>(characteristic: C, maxpower: usize) { let mut rng = XorShiftRng::from_seed([ @@ -121,7 +122,7 @@ pub fn from_str_tests() { ]); for _ in 0..1000 { - let n: u64 = rng.gen(); + let n = rng.next_u64(); let a = F::from_str(&format!("{}", n)).unwrap(); let b = F::from_repr(n.into()).unwrap(); @@ -136,7 +137,7 @@ pub fn from_str_tests() { assert!(F::from_str("00000000000").is_none()); } -fn random_multiplication_tests(rng: &mut R) { +fn random_multiplication_tests(rng: &mut R) { for _ in 0..10000 { let a = F::random(rng); let b = F::random(rng); @@ -159,7 +160,7 @@ fn random_multiplication_tests(rng: &mut R) { } } -fn random_addition_tests(rng: &mut R) { +fn random_addition_tests(rng: &mut R) { for _ in 0..10000 { let a = F::random(rng); let b = F::random(rng); @@ -182,7 +183,7 @@ fn random_addition_tests(rng: &mut R) { } } -fn random_subtraction_tests(rng: &mut R) { +fn random_subtraction_tests(rng: &mut R) { for _ in 0..10000 { let b = F::random(rng); let a = F::random(rng); @@ -200,7 +201,7 @@ fn random_subtraction_tests(rng: &mut R) { } } -fn random_negation_tests(rng: &mut R) { +fn random_negation_tests(rng: &mut R) { for _ in 0..10000 { let a = F::random(rng); let mut b = a; @@ -211,7 +212,7 @@ fn random_negation_tests(rng: &mut R) { } } -fn random_doubling_tests(rng: &mut R) { +fn random_doubling_tests(rng: &mut R) { for _ in 0..10000 { let mut a = F::random(rng); let mut b = a; @@ -222,7 +223,7 @@ fn random_doubling_tests(rng: &mut R) { } } -fn random_squaring_tests(rng: &mut R) { +fn random_squaring_tests(rng: &mut R) { for _ in 0..10000 { let mut a = F::random(rng); let mut b = a; @@ -233,7 +234,7 @@ fn random_squaring_tests(rng: &mut R) { } } -fn random_inversion_tests(rng: &mut R) { +fn random_inversion_tests(rng: &mut R) { assert!(F::zero().inverse().is_none()); for _ in 0..10000 { @@ -245,7 +246,7 @@ fn random_inversion_tests(rng: &mut R) { } } -fn random_expansion_tests(rng: &mut R) { +fn random_expansion_tests(rng: &mut R) { for _ in 0..10000 { // Compare (a + b)(c + d) and (a*c + b*c + a*d + b*d) diff --git a/pairing/src/tests/repr.rs b/pairing/src/tests/repr.rs index 692c4d3..67badd8 100644 --- a/pairing/src/tests/repr.rs +++ b/pairing/src/tests/repr.rs @@ -1,5 +1,6 @@ use ff::{PrimeField, PrimeFieldRepr}; -use rand::{SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +use rand_xorshift::XorShiftRng; pub fn random_repr_tests() { random_encoding_tests::

(); From 60d344a0a7d60b047a6c6c2d1fbc2adbc0b18265 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 12 Jul 2019 23:54:59 -0400 Subject: [PATCH 033/330] Migrate sapling-crypto to rand_core 0.4 --- Cargo.lock | 3 +- sapling-crypto/Cargo.toml | 3 +- sapling-crypto/examples/bench.rs | 8 ++-- sapling-crypto/src/circuit/blake2s.rs | 10 +++-- sapling-crypto/src/circuit/ecc.rs | 14 ++++--- sapling-crypto/src/circuit/lookup.rs | 15 +++---- sapling-crypto/src/circuit/multipack.rs | 6 ++- sapling-crypto/src/circuit/num.rs | 4 +- sapling-crypto/src/circuit/pedersen_hash.rs | 7 ++-- sapling-crypto/src/circuit/sapling/mod.rs | 13 ++++--- sapling-crypto/src/circuit/sha256.rs | 7 ++-- sapling-crypto/src/circuit/uint32.rs | 43 +++++++++++---------- sapling-crypto/src/jubjub/edwards.rs | 9 ++--- sapling-crypto/src/jubjub/fs.rs | 6 ++- sapling-crypto/src/jubjub/montgomery.rs | 9 ++--- sapling-crypto/src/jubjub/tests.rs | 3 +- sapling-crypto/src/lib.rs | 5 ++- sapling-crypto/src/redjubjub.rs | 29 ++++++++++---- 18 files changed, 115 insertions(+), 79 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4aee36..4c36e99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -534,7 +534,8 @@ dependencies = [ "ff 0.4.0", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/sapling-crypto/Cargo.toml b/sapling-crypto/Cargo.toml index 34e91eb..da28615 100644 --- a/sapling-crypto/Cargo.toml +++ b/sapling-crypto/Cargo.toml @@ -17,10 +17,11 @@ bellman = { path = "../bellman" } blake2b_simd = "0.5" blake2s_simd = "0.5" ff = { path = "../ff" } -rand = "0.5" +rand_core = "0.4" digest = "0.7" byteorder = "1" [dev-dependencies] hex-literal = "0.1" +rand_xorshift = "0.1" sha2 = "0.8" diff --git a/sapling-crypto/examples/bench.rs b/sapling-crypto/examples/bench.rs index 9b4c0ae..e9ffc13 100644 --- a/sapling-crypto/examples/bench.rs +++ b/sapling-crypto/examples/bench.rs @@ -1,8 +1,9 @@ extern crate ff; extern crate sapling_crypto; extern crate bellman; -extern crate rand; extern crate pairing; +extern crate rand_core; +extern crate rand_xorshift; use ff::Field; use std::time::{Duration, Instant}; @@ -20,7 +21,8 @@ use sapling_crypto::primitives::{ ValueCommitment }; use bellman::groth16::*; -use rand::{XorShiftRng, SeedableRng, Rng, RngCore}; +use rand_core::{RngCore, SeedableRng}; +use rand_xorshift::XorShiftRng; use pairing::bls12_381::{Bls12, Fr}; const TREE_DEPTH: usize = 32; @@ -86,7 +88,7 @@ fn main() { } let commitment_randomness = fs::Fs::random(rng); - let auth_path = vec![Some((Fr::random(rng), rng.gen())); TREE_DEPTH]; + let auth_path = vec![Some((Fr::random(rng), rng.next_u32() % 2 != 0)); TREE_DEPTH]; let ar = fs::Fs::random(rng); let anchor = Fr::random(rng); diff --git a/sapling-crypto/src/circuit/blake2s.rs b/sapling-crypto/src/circuit/blake2s.rs index e6748ba..8627dc0 100644 --- a/sapling-crypto/src/circuit/blake2s.rs +++ b/sapling-crypto/src/circuit/blake2s.rs @@ -321,8 +321,10 @@ pub fn blake2s>( #[cfg(test)] mod test { use blake2s_simd::Params as Blake2sParams; - use rand::{XorShiftRng, SeedableRng, Rng}; use pairing::bls12_381::{Bls12}; + use rand_core::{RngCore, SeedableRng}; + use rand_xorshift::XorShiftRng; + use ::circuit::boolean::{Boolean, AllocatedBit}; use ::circuit::test::TestConstraintSystem; use super::blake2s; @@ -371,7 +373,7 @@ mod test { 0xe5, ]); let input_bits: Vec<_> = (0..512) - .map(|_| Boolean::constant(rng.gen())) + .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) .chain((0..512) .map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into())) .collect(); @@ -387,7 +389,7 @@ mod test { 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, ]); - let input_bits: Vec<_> = (0..512).map(|_| Boolean::constant(rng.gen())).collect(); + let input_bits: Vec<_> = (0..512).map(|_| Boolean::constant(rng.next_u32() % 2 != 0)).collect(); blake2s(&mut cs, &input_bits, b"12345678").unwrap(); assert_eq!(cs.num_constraints(), 0); } @@ -403,7 +405,7 @@ mod test { { let mut h = Blake2sParams::new().hash_length(32).personal(b"12345678").to_state(); - let data: Vec = (0..input_len).map(|_| rng.gen()).collect(); + let data: Vec = (0..input_len).map(|_| rng.next_u32() as u8).collect(); h.update(&data); diff --git a/sapling-crypto/src/circuit/ecc.rs b/sapling-crypto/src/circuit/ecc.rs index 3fc9713..9b4dbbc 100644 --- a/sapling-crypto/src/circuit/ecc.rs +++ b/sapling-crypto/src/circuit/ecc.rs @@ -748,9 +748,11 @@ impl MontgomeryPoint { #[cfg(test)] mod test { use bellman::{ConstraintSystem}; - use rand::{XorShiftRng, SeedableRng, Rng}; use ff::{BitIterator, Field, PrimeField}; use pairing::bls12_381::{Bls12, Fr}; + use rand_core::{RngCore, SeedableRng}; + use rand_xorshift::XorShiftRng; + use ::circuit::test::*; use ::jubjub::{ montgomery, @@ -1001,10 +1003,10 @@ mod test { y: num_y0 }; - let mut should_we_select = rng.gen(); + let mut should_we_select = rng.next_u32() % 2 != 0; // Conditionally allocate - let mut b = if rng.gen() { + let mut b = if rng.next_u32() % 2 != 0 { Boolean::from(AllocatedBit::alloc( cs.namespace(|| "condition"), Some(should_we_select) @@ -1014,7 +1016,7 @@ mod test { }; // Conditionally negate - if rng.gen() { + if rng.next_u32() % 2 != 0 { b = b.not(); should_we_select = !should_we_select; } @@ -1163,7 +1165,7 @@ mod test { for _ in 0..100 { let p1 = loop { let x = Fr::random(rng); - let s: bool = rng.gen(); + let s: bool = rng.next_u32() % 2 != 0; if let Some(p) = montgomery::Point::::get_for_x(x, s, params) { break p; @@ -1172,7 +1174,7 @@ mod test { let p2 = loop { let x = Fr::random(rng); - let s: bool = rng.gen(); + let s: bool = rng.next_u32() % 2 != 0; if let Some(p) = montgomery::Point::::get_for_x(x, s, params) { break p; diff --git a/sapling-crypto/src/circuit/lookup.rs b/sapling-crypto/src/circuit/lookup.rs index 4b6e13b..d57f17c 100644 --- a/sapling-crypto/src/circuit/lookup.rs +++ b/sapling-crypto/src/circuit/lookup.rs @@ -196,11 +196,12 @@ pub fn lookup3_xy_with_conditional_negation( #[cfg(test)] mod test { - use rand::{SeedableRng, Rng, XorShiftRng}; use super::*; use ::circuit::test::*; use ::circuit::boolean::{Boolean, AllocatedBit}; use pairing::bls12_381::{Bls12, Fr}; + use rand_core::{RngCore, SeedableRng}; + use rand_xorshift::XorShiftRng; #[test] fn test_lookup3_xy() { @@ -212,17 +213,17 @@ mod test { for _ in 0..100 { let mut cs = TestConstraintSystem::::new(); - let a_val = rng.gen(); + let a_val = rng.next_u32() % 2 != 0; let a = Boolean::from( AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap() ); - let b_val = rng.gen(); + let b_val = rng.next_u32() % 2 != 0; let b = Boolean::from( AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap() ); - let c_val = rng.gen(); + let c_val = rng.next_u32() % 2 != 0; let c = Boolean::from( AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap() ); @@ -255,17 +256,17 @@ mod test { for _ in 0..100 { let mut cs = TestConstraintSystem::::new(); - let a_val = rng.gen(); + let a_val = rng.next_u32() % 2 != 0; let a = Boolean::from( AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap() ); - let b_val = rng.gen(); + let b_val = rng.next_u32() % 2 != 0; let b = Boolean::from( AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap() ); - let c_val = rng.gen(); + let c_val = rng.next_u32() % 2 != 0; let c = Boolean::from( AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap() ); diff --git a/sapling-crypto/src/circuit/multipack.rs b/sapling-crypto/src/circuit/multipack.rs index fd7cbfb..fdecd34 100644 --- a/sapling-crypto/src/circuit/multipack.rs +++ b/sapling-crypto/src/circuit/multipack.rs @@ -80,9 +80,11 @@ pub fn compute_multipacking( #[test] fn test_multipacking() { - use rand::{SeedableRng, Rng, XorShiftRng}; use bellman::{ConstraintSystem}; use pairing::bls12_381::{Bls12}; + use rand_core::{RngCore, SeedableRng}; + use rand_xorshift::XorShiftRng; + use ::circuit::test::*; use super::boolean::{AllocatedBit, Boolean}; @@ -94,7 +96,7 @@ fn test_multipacking() { for num_bits in 0..1500 { let mut cs = TestConstraintSystem::::new(); - let bits: Vec = (0..num_bits).map(|_| rng.gen()).collect(); + let bits: Vec = (0..num_bits).map(|_| rng.next_u32() % 2 != 0).collect(); let circuit_bits = bits.iter().enumerate() .map(|(i, &b)| { diff --git a/sapling-crypto/src/circuit/num.rs b/sapling-crypto/src/circuit/num.rs index 7201356..1cdfe22 100644 --- a/sapling-crypto/src/circuit/num.rs +++ b/sapling-crypto/src/circuit/num.rs @@ -455,10 +455,12 @@ impl Num { #[cfg(test)] mod test { - use rand::{SeedableRng, XorShiftRng}; use bellman::{ConstraintSystem}; use ff::{BitIterator, Field, PrimeField}; use pairing::bls12_381::{Bls12, Fr}; + use rand_core::SeedableRng; + use rand_xorshift::XorShiftRng; + use ::circuit::test::*; use super::{AllocatedNum, Boolean}; diff --git a/sapling-crypto/src/circuit/pedersen_hash.rs b/sapling-crypto/src/circuit/pedersen_hash.rs index f26b98e..dd000d3 100644 --- a/sapling-crypto/src/circuit/pedersen_hash.rs +++ b/sapling-crypto/src/circuit/pedersen_hash.rs @@ -112,12 +112,13 @@ pub fn pedersen_hash( #[cfg(test)] mod test { - use rand::{SeedableRng, Rng, XorShiftRng}; use super::*; use ::circuit::test::*; use ::circuit::boolean::{Boolean, AllocatedBit}; use ff::PrimeField; use pairing::bls12_381::{Bls12, Fr}; + use rand_core::{RngCore, SeedableRng}; + use rand_xorshift::XorShiftRng; #[test] fn test_pedersen_hash_constraints() { @@ -128,7 +129,7 @@ mod test { let params = &JubjubBls12::new(); let mut cs = TestConstraintSystem::::new(); - let input: Vec = (0..(Fr::NUM_BITS * 2)).map(|_| rng.gen()).collect(); + let input: Vec = (0..(Fr::NUM_BITS * 2)).map(|_| rng.next_u32() % 2 != 0).collect(); let input_bools: Vec = input.iter().enumerate().map(|(i, b)| { Boolean::from( @@ -157,7 +158,7 @@ mod test { for length in 0..751 { for _ in 0..5 { - let mut input: Vec = (0..length).map(|_| rng.gen()).collect(); + let mut input: Vec = (0..length).map(|_| rng.next_u32() % 2 != 0).collect(); let mut cs = TestConstraintSystem::::new(); diff --git a/sapling-crypto/src/circuit/sapling/mod.rs b/sapling-crypto/src/circuit/sapling/mod.rs index 2c4d566..469ab2e 100644 --- a/sapling-crypto/src/circuit/sapling/mod.rs +++ b/sapling-crypto/src/circuit/sapling/mod.rs @@ -600,7 +600,9 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { fn test_input_circuit_with_bls12_381() { use ff::{BitIterator, Field}; use pairing::bls12_381::*; - use rand::{SeedableRng, Rng, RngCore, XorShiftRng}; + use rand_core::{RngCore, SeedableRng}; + use rand_xorshift::XorShiftRng; + use ::circuit::test::*; use jubjub::{JubjubBls12, fs, edwards}; @@ -614,7 +616,7 @@ fn test_input_circuit_with_bls12_381() { for _ in 0..10 { let value_commitment = ValueCommitment { - value: rng.gen(), + value: rng.next_u64(), randomness: fs::Fs::random(rng), }; @@ -649,7 +651,7 @@ fn test_input_circuit_with_bls12_381() { let g_d = payment_address.diversifier.g_d(params).unwrap(); let commitment_randomness = fs::Fs::random(rng); - let auth_path = vec![Some((Fr::random(rng), rng.gen())); tree_depth]; + let auth_path = vec![Some((Fr::random(rng), rng.next_u32() % 2 != 0)); tree_depth]; let ar = fs::Fs::random(rng); { @@ -739,7 +741,8 @@ fn test_input_circuit_with_bls12_381() { fn test_output_circuit_with_bls12_381() { use ff::Field; use pairing::bls12_381::*; - use rand::{SeedableRng, Rng, RngCore, XorShiftRng}; + use rand_core::{RngCore, SeedableRng}; + use rand_xorshift::XorShiftRng; use ::circuit::test::*; use jubjub::{JubjubBls12, fs, edwards}; @@ -751,7 +754,7 @@ fn test_output_circuit_with_bls12_381() { for _ in 0..100 { let value_commitment = ValueCommitment { - value: rng.gen(), + value: rng.next_u64(), randomness: fs::Fs::random(rng), }; diff --git a/sapling-crypto/src/circuit/sha256.rs b/sapling-crypto/src/circuit/sha256.rs index 86147f8..3b32282 100644 --- a/sapling-crypto/src/circuit/sha256.rs +++ b/sapling-crypto/src/circuit/sha256.rs @@ -308,7 +308,8 @@ mod test { use circuit::boolean::AllocatedBit; use pairing::bls12_381::Bls12; use circuit::test::TestConstraintSystem; - use rand::{XorShiftRng, SeedableRng, Rng}; + use rand_core::{RngCore, SeedableRng}; + use rand_xorshift::XorShiftRng; #[test] fn test_blank_hash() { @@ -353,7 +354,7 @@ mod test { Boolean::from( AllocatedBit::alloc( cs.namespace(|| format!("input bit {}", i)), - Some(rng.gen()) + Some(rng.next_u32() % 2 != 0) ).unwrap() ) }).collect(); @@ -380,7 +381,7 @@ mod test { for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) { let mut h = Sha256::new(); - let data: Vec = (0..input_len).map(|_| rng.gen()).collect(); + let data: Vec = (0..input_len).map(|_| rng.next_u32() as u8).collect(); h.input(&data); let hash_result = h.result(); diff --git a/sapling-crypto/src/circuit/uint32.rs b/sapling-crypto/src/circuit/uint32.rs index daca627..939b544 100644 --- a/sapling-crypto/src/circuit/uint32.rs +++ b/sapling-crypto/src/circuit/uint32.rs @@ -409,7 +409,6 @@ impl UInt32 { #[cfg(test)] mod test { - use rand::{XorShiftRng, SeedableRng, Rng}; use ::circuit::boolean::{Boolean}; use super::{UInt32}; use ff::Field; @@ -417,6 +416,8 @@ mod test { use ::circuit::test::*; use bellman::{ConstraintSystem}; use circuit::multieq::MultiEq; + use rand_core::{RngCore, SeedableRng}; + use rand_xorshift::XorShiftRng; #[test] fn test_uint32_from_bits_be() { @@ -426,7 +427,7 @@ mod test { ]); for _ in 0..1000 { - let mut v = (0..32).map(|_| Boolean::constant(rng.gen())).collect::>(); + let mut v = (0..32).map(|_| Boolean::constant(rng.next_u32() % 2 != 0)).collect::>(); let b = UInt32::from_bits_be(&v); @@ -460,7 +461,7 @@ mod test { ]); for _ in 0..1000 { - let mut v = (0..32).map(|_| Boolean::constant(rng.gen())).collect::>(); + let mut v = (0..32).map(|_| Boolean::constant(rng.next_u32() % 2 != 0)).collect::>(); let b = UInt32::from_bits(&v); @@ -496,9 +497,9 @@ mod test { for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); - let a: u32 = rng.gen(); - let b: u32 = rng.gen(); - let c: u32 = rng.gen(); + let a = rng.next_u32(); + let b = rng.next_u32(); + let c = rng.next_u32(); let mut expected = a ^ b ^ c; @@ -541,9 +542,9 @@ mod test { for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); - let a: u32 = rng.gen(); - let b: u32 = rng.gen(); - let c: u32 = rng.gen(); + let a = rng.next_u32(); + let b = rng.next_u32(); + let c = rng.next_u32(); let a_bit = UInt32::constant(a); let b_bit = UInt32::constant(b); @@ -583,10 +584,10 @@ mod test { for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); - let a: u32 = rng.gen(); - let b: u32 = rng.gen(); - let c: u32 = rng.gen(); - let d: u32 = rng.gen(); + let a = rng.next_u32(); + let b = rng.next_u32(); + let c = rng.next_u32(); + let d = rng.next_u32(); let mut expected = (a ^ b).wrapping_add(c).wrapping_add(d); @@ -640,7 +641,7 @@ mod test { 0xe5, ]); - let mut num = rng.gen(); + let mut num = rng.next_u32(); let a = UInt32::constant(num); @@ -675,7 +676,7 @@ mod test { for _ in 0..50 { for i in 0..60 { - let num = rng.gen(); + let num = rng.next_u32(); let a = UInt32::constant(num).shr(i); let b = UInt32::constant(num.wrapping_shr(i as u32)); @@ -699,9 +700,9 @@ mod test { for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); - let a: u32 = rng.gen(); - let b: u32 = rng.gen(); - let c: u32 = rng.gen(); + let a = rng.next_u32(); + let b = rng.next_u32(); + let c = rng.next_u32(); let mut expected = (a & b) ^ (a & c) ^ (b & c); @@ -743,9 +744,9 @@ mod test { for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); - let a: u32 = rng.gen(); - let b: u32 = rng.gen(); - let c: u32 = rng.gen(); + let a = rng.next_u32(); + let b = rng.next_u32(); + let c = rng.next_u32(); let mut expected = (a & b) ^ ((!a) & c); diff --git a/sapling-crypto/src/jubjub/edwards.rs b/sapling-crypto/src/jubjub/edwards.rs index 95b6120..e912aca 100644 --- a/sapling-crypto/src/jubjub/edwards.rs +++ b/sapling-crypto/src/jubjub/edwards.rs @@ -8,9 +8,7 @@ use super::{ montgomery }; -use rand::{ - Rng -}; +use rand_core::RngCore; use std::marker::PhantomData; @@ -185,12 +183,13 @@ impl Point { convert_subgroup(&tmp) } - pub fn rand(rng: &mut R, params: &E::Params) -> Self + pub fn rand(rng: &mut R, params: &E::Params) -> Self { loop { let y = E::Fr::random(rng); + let sign = rng.next_u32() % 2 != 0; - if let Some(p) = Self::get_for_y(y, rng.gen(), params) { + if let Some(p) = Self::get_for_y(y, sign, params) { return p; } } diff --git a/sapling-crypto/src/jubjub/fs.rs b/sapling-crypto/src/jubjub/fs.rs index 55df2cb..017292b 100644 --- a/sapling-crypto/src/jubjub/fs.rs +++ b/sapling-crypto/src/jubjub/fs.rs @@ -4,7 +4,7 @@ use ff::{ LegendreSymbol::{self, *}, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, SqrtField, }; -use rand::RngCore; +use rand_core::RngCore; use super::ToUniform; @@ -620,7 +620,9 @@ fn test_neg_one() { } #[cfg(test)] -use rand::{SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +#[cfg(test)] +use rand_xorshift::XorShiftRng; #[test] fn test_fs_repr_ordering() { diff --git a/sapling-crypto/src/jubjub/montgomery.rs b/sapling-crypto/src/jubjub/montgomery.rs index 28dce8e..9bd6023 100644 --- a/sapling-crypto/src/jubjub/montgomery.rs +++ b/sapling-crypto/src/jubjub/montgomery.rs @@ -8,9 +8,7 @@ use super::{ edwards }; -use rand::{ - Rng -}; +use rand_core::RngCore; use std::marker::PhantomData; @@ -101,12 +99,13 @@ impl Point { convert_subgroup(&tmp) } - pub fn rand(rng: &mut R, params: &E::Params) -> Self + pub fn rand(rng: &mut R, params: &E::Params) -> Self { loop { let x = E::Fr::random(rng); + let sign = rng.next_u32() % 2 != 0; - match Self::get_for_x(x, rng.gen(), params) { + match Self::get_for_x(x, sign, params) { Some(p) => { return p }, diff --git a/sapling-crypto/src/jubjub/tests.rs b/sapling-crypto/src/jubjub/tests.rs index 19aae80..e15b81e 100644 --- a/sapling-crypto/src/jubjub/tests.rs +++ b/sapling-crypto/src/jubjub/tests.rs @@ -14,7 +14,8 @@ use ff::{ LegendreSymbol }; -use rand::{RngCore, XorShiftRng, SeedableRng}; +use rand_core::{RngCore, SeedableRng}; +use rand_xorshift::XorShiftRng; pub fn test_suite(params: &E::Params) { test_back_and_forth::(params); diff --git a/sapling-crypto/src/lib.rs b/sapling-crypto/src/lib.rs index da3bbc4..14e713d 100644 --- a/sapling-crypto/src/lib.rs +++ b/sapling-crypto/src/lib.rs @@ -4,13 +4,16 @@ extern crate blake2b_simd; extern crate blake2s_simd; extern crate digest; extern crate ff; -extern crate rand; +extern crate rand_core; extern crate byteorder; #[cfg(test)] #[macro_use] extern crate hex_literal; +#[cfg(test)] +extern crate rand_xorshift; + #[cfg(test)] extern crate sha2; diff --git a/sapling-crypto/src/redjubjub.rs b/sapling-crypto/src/redjubjub.rs index 2b34654..cd02347 100644 --- a/sapling-crypto/src/redjubjub.rs +++ b/sapling-crypto/src/redjubjub.rs @@ -2,7 +2,7 @@ //! See section 5.4.6 of the Sapling protocol specification. use ff::{Field, PrimeField, PrimeFieldRepr}; -use rand::{Rng}; +use rand_core::RngCore; use std::io::{self, Read, Write}; use jubjub::{FixedGenerators, JubjubEngine, JubjubParams, Unknown, edwards::Point}; @@ -71,7 +71,7 @@ impl PrivateKey { write_scalar::(&self.0, writer) } - pub fn sign( + pub fn sign( &self, msg: &[u8], rng: &mut R, @@ -163,7 +163,7 @@ pub struct BatchEntry<'a, E: JubjubEngine> { // TODO: #82: This is a naive implementation currently, // and doesn't use multiexp. -pub fn batch_verify<'a, E: JubjubEngine, R: Rng>( +pub fn batch_verify<'a, E: JubjubEngine, R: RngCore>( rng: &mut R, batch: &[BatchEntry<'a, E>], p_g: FixedGenerators, @@ -206,7 +206,8 @@ pub fn batch_verify<'a, E: JubjubEngine, R: Rng>( #[cfg(test)] mod tests { use pairing::bls12_381::Bls12; - use rand::thread_rng; + use rand_core::SeedableRng; + use rand_xorshift::XorShiftRng; use jubjub::{JubjubBls12, fs::Fs, edwards}; @@ -214,7 +215,10 @@ mod tests { #[test] fn test_batch_verify() { - let rng = &mut thread_rng(); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let params = &JubjubBls12::new(); let p_g = FixedGenerators::SpendingKeyGenerator; @@ -244,7 +248,10 @@ mod tests { #[test] fn cofactor_check() { - let rng = &mut thread_rng(); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let params = &JubjubBls12::new(); let zero = edwards::Point::zero(); let p_g = FixedGenerators::SpendingKeyGenerator; @@ -276,7 +283,10 @@ mod tests { #[test] fn round_trip_serialization() { - let rng = &mut thread_rng(); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let p_g = FixedGenerators::SpendingKeyGenerator; let params = &JubjubBls12::new(); @@ -309,7 +319,10 @@ mod tests { #[test] fn random_signatures() { - let rng = &mut thread_rng(); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let p_g = FixedGenerators::SpendingKeyGenerator; let params = &JubjubBls12::new(); From 8f7adec0d940e6e260d4abb14d2c09e3b6662ce6 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 13 Jul 2019 00:16:54 -0400 Subject: [PATCH 034/330] Migrate zcash_primitives to rand_core 0.4 --- Cargo.lock | 3 +- zcash_primitives/Cargo.toml | 3 +- zcash_primitives/src/lib.rs | 3 +- zcash_primitives/src/merkle_tree.rs | 4 +- zcash_primitives/src/note_encryption.rs | 58 +++++++++++------------ zcash_primitives/src/sapling.rs | 2 +- zcash_primitives/src/transaction/tests.rs | 4 +- 7 files changed, 40 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4c36e99..e435c6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -621,7 +621,8 @@ dependencies = [ "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index d82b3bc..10c6d00 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -15,6 +15,7 @@ fpe = "0.1" hex = "0.3" lazy_static = "1" pairing = { path = "../pairing" } -rand = "0.5" +rand_core = "0.4" +rand_os = "0.1" sapling-crypto = { path = "../sapling-crypto" } sha2 = "0.8" diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 70bd8fa..90d69e6 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -9,7 +9,8 @@ extern crate ff; extern crate fpe; extern crate hex; extern crate pairing; -extern crate rand; +extern crate rand_core; +extern crate rand_os; extern crate sapling_crypto; extern crate sha2; diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 3b94bd9..a692073 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -202,12 +202,12 @@ impl CommitmentTree { /// ``` /// extern crate ff; /// extern crate pairing; -/// extern crate rand; +/// extern crate rand_os; /// extern crate zcash_primitives; /// /// use ff::{Field, PrimeField}; /// use pairing::bls12_381::Fr; -/// use rand::OsRng; +/// use rand_os::OsRng; /// use zcash_primitives::{ /// merkle_tree::{CommitmentTree, IncrementalWitness}, /// sapling::Node, diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index b1b483f..728818f 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -5,7 +5,8 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf}; use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr}; -use rand::{OsRng, Rng}; +use rand_core::RngCore; +use rand_os::OsRng; use sapling_crypto::{ jubjub::{ edwards, @@ -138,9 +139,7 @@ fn generate_esk() -> Fs { // create random 64 byte buffer let mut rng = OsRng::new().expect("should be able to construct RNG"); let mut buffer = [0u8; 64]; - for i in 0..buffer.len() { - buffer[i] = rng.gen(); - } + rng.fill_bytes(&mut buffer); // reduce to uniform value Fs::to_uniform(&buffer[..]) @@ -213,12 +212,12 @@ fn prf_ock( /// ``` /// extern crate ff; /// extern crate pairing; -/// extern crate rand; +/// extern crate rand_os; /// extern crate sapling_crypto; /// /// use ff::Field; /// use pairing::bls12_381::Bls12; -/// use rand::OsRng; +/// use rand_os::OsRng; /// use sapling_crypto::{ /// jubjub::fs::Fs, /// primitives::{Diversifier, PaymentAddress, ValueCommitment}, @@ -562,7 +561,8 @@ mod tests { use crypto_api_chachapoly::ChachaPolyIetf; use ff::{Field, PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; - use rand::{thread_rng, RngCore}; + use rand_core::RngCore; + use rand_os::OsRng; use sapling_crypto::{ jubjub::{ edwards, @@ -848,7 +848,7 @@ mod tests { #[test] fn decryption_with_invalid_ivk() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (_, _, _, cmu, epk, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); @@ -860,7 +860,7 @@ mod tests { #[test] fn decryption_with_invalid_epk() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (_, ivk, _, cmu, _, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); @@ -877,7 +877,7 @@ mod tests { #[test] fn decryption_with_invalid_cmu() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (_, ivk, _, _, epk, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); @@ -889,7 +889,7 @@ mod tests { #[test] fn decryption_with_invalid_tag() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (_, ivk, _, cmu, epk, mut enc_ciphertext, _) = random_enc_ciphertext(&mut rng); @@ -902,7 +902,7 @@ mod tests { #[test] fn decryption_with_invalid_version_byte() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -924,7 +924,7 @@ mod tests { #[test] fn decryption_with_invalid_diversifier() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -946,7 +946,7 @@ mod tests { #[test] fn decryption_with_incorrect_diversifier() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -968,7 +968,7 @@ mod tests { #[test] fn compact_decryption_with_invalid_ivk() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (_, _, _, cmu, epk, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); @@ -985,7 +985,7 @@ mod tests { #[test] fn compact_decryption_with_invalid_epk() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (_, ivk, _, cmu, _, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); @@ -1002,7 +1002,7 @@ mod tests { #[test] fn compact_decryption_with_invalid_cmu() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (_, ivk, _, _, epk, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); @@ -1019,7 +1019,7 @@ mod tests { #[test] fn compact_decryption_with_invalid_version_byte() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1046,7 +1046,7 @@ mod tests { #[test] fn compact_decryption_with_invalid_diversifier() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1073,7 +1073,7 @@ mod tests { #[test] fn compact_decryption_with_incorrect_diversifier() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1100,7 +1100,7 @@ mod tests { #[test] fn recovery_with_invalid_ovk() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (mut ovk, _, cv, cmu, epk, enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1114,7 +1114,7 @@ mod tests { #[test] fn recovery_with_invalid_cv() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (ovk, _, _, cmu, epk, enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1133,7 +1133,7 @@ mod tests { #[test] fn recovery_with_invalid_cmu() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (ovk, _, cv, _, epk, enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1152,7 +1152,7 @@ mod tests { #[test] fn recovery_with_invalid_epk() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (ovk, _, cv, cmu, _, enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1171,7 +1171,7 @@ mod tests { #[test] fn recovery_with_invalid_enc_tag() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1185,7 +1185,7 @@ mod tests { #[test] fn recovery_with_invalid_out_tag() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (ovk, _, cv, cmu, epk, enc_ciphertext, mut out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1199,7 +1199,7 @@ mod tests { #[test] fn recovery_with_invalid_version_byte() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1221,7 +1221,7 @@ mod tests { #[test] fn recovery_with_invalid_diversifier() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1243,7 +1243,7 @@ mod tests { #[test] fn recovery_with_incorrect_diversifier() { - let mut rng = thread_rng(); + let mut rng = OsRng::new().expect("should be able to construct RNG"); let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index 0ee808c..7f2b6f2 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -2,7 +2,7 @@ use ff::{BitIterator, PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; -use rand::OsRng; +use rand_os::OsRng; use sapling_crypto::{ jubjub::{fs::Fs, FixedGenerators, JubjubBls12}, pedersen_hash::{pedersen_hash, Personalization}, diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index 7ef691f..81f8e21 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -1,6 +1,6 @@ use ff::Field; use pairing::bls12_381::Bls12; -use rand::thread_rng; +use rand_os::OsRng; use sapling_crypto::{ jubjub::{fs::Fs, FixedGenerators}, redjubjub::PrivateKey, @@ -197,7 +197,7 @@ fn tx_write_rejects_unexpected_binding_sig() { // Fails with an unexpected binding signature { - let rng = &mut thread_rng(); + let rng = &mut OsRng::new().expect("should be able to construct RNG"); let sk = PrivateKey::(Fs::random(rng)); let sig = sk.sign( b"Foo bar", From b0913afdd7f179466bb13dd4ad2a78d90a9a9d60 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 13 Jul 2019 01:54:47 -0400 Subject: [PATCH 035/330] Migrate remaining crates to rand_core 0.4 --- Cargo.lock | 21 +++++---------------- librustzcash/Cargo.toml | 3 ++- librustzcash/src/rustzcash.rs | 10 +++++----- librustzcash/src/tests/key_agreement.rs | 7 +++++-- zcash_client_backend/Cargo.toml | 3 ++- zcash_client_backend/src/encoding.rs | 9 ++++++--- zcash_proofs/Cargo.toml | 2 +- zcash_proofs/src/lib.rs | 2 +- zcash_proofs/src/sapling/prover.rs | 2 +- 9 files changed, 28 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e435c6d..d1cb83f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -315,7 +315,8 @@ dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", "zcash_proofs 0.0.0", @@ -406,18 +407,6 @@ dependencies = [ "proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rand" version = "0.6.5" @@ -603,7 +592,8 @@ version = "0.0.0" dependencies = [ "bech32 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", ] @@ -636,7 +626,7 @@ dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "pairing 0.14.2", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", ] @@ -689,7 +679,6 @@ dependencies = [ "checksum proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5cb6f960ad471404618e9817c0e5d10b1ae74cfdf01fab89ea0641fe7fb2892" "checksum proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b331c6ad3411474cd55540398dc7ad89fc41488e64ec71fdecc9c9b86de96fb0" "checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" -"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index f37b899..d67d4ee 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -22,7 +22,8 @@ libc = "0.2" pairing = { path = "../pairing" } lazy_static = "1" byteorder = "1" -rand = "0.5" +rand_core = "0.4" +rand_os = "0.1" sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } zcash_proofs = { path = "../zcash_proofs" } diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index cfb26e1..7f10d1c 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -5,7 +5,8 @@ extern crate byteorder; extern crate ff; extern crate libc; extern crate pairing; -extern crate rand; +extern crate rand_core; +extern crate rand_os; extern crate sapling_crypto; extern crate zcash_primitives; extern crate zcash_proofs; @@ -37,7 +38,8 @@ use blake2s_simd::Params as Blake2sParams; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use rand::{OsRng, Rng}; +use rand_core::RngCore; +use rand_os::OsRng; use std::io::BufReader; use libc::{c_char, c_uchar, int64_t, size_t, uint32_t, uint64_t}; @@ -388,9 +390,7 @@ pub extern "system" fn librustzcash_sapling_generate_r(result: *mut [c_uchar; 32 // create random 64 byte buffer let mut rng = OsRng::new().expect("should be able to construct RNG"); let mut buffer = [0u8; 64]; - for i in 0..buffer.len() { - buffer[i] = rng.gen(); - } + rng.fill_bytes(&mut buffer); // reduce to uniform value let r = ::Fs::to_uniform(&buffer[..]); diff --git a/librustzcash/src/tests/key_agreement.rs b/librustzcash/src/tests/key_agreement.rs index a72abf0..9d22561 100644 --- a/librustzcash/src/tests/key_agreement.rs +++ b/librustzcash/src/tests/key_agreement.rs @@ -1,6 +1,7 @@ use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::Bls12; -use rand::{OsRng, Rng}; +use rand_core::RngCore; +use rand_os::OsRng; use sapling_crypto::jubjub::{edwards, JubjubBls12}; use sapling_crypto::primitives::{Diversifier, ViewingKey}; @@ -22,7 +23,9 @@ fn test_key_agreement() { // Create a random address with the viewing key let addr = loop { - match vk.into_payment_address(Diversifier(rng.gen()), ¶ms) { + let mut d = [0; 11]; + rng.fill_bytes(&mut d); + match vk.into_payment_address(Diversifier(d), ¶ms) { Some(a) => break a, None => {} } diff --git a/zcash_client_backend/Cargo.toml b/zcash_client_backend/Cargo.toml index 38c9988..8e7e055 100644 --- a/zcash_client_backend/Cargo.toml +++ b/zcash_client_backend/Cargo.toml @@ -13,4 +13,5 @@ sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } [dev-dependencies] -rand = "0.5" +rand_core = "0.4" +rand_xorshift = "0.1" diff --git a/zcash_client_backend/src/encoding.rs b/zcash_client_backend/src/encoding.rs index 3d70b41..d816201 100644 --- a/zcash_client_backend/src/encoding.rs +++ b/zcash_client_backend/src/encoding.rs @@ -101,7 +101,8 @@ pub fn decode_extended_full_viewing_key( /// /// ``` /// use pairing::bls12_381::Bls12; -/// use rand::{SeedableRng, XorShiftRng}; +/// use rand_core::SeedableRng; +/// use rand_xorshift::XorShiftRng; /// use sapling_crypto::{ /// jubjub::edwards, /// primitives::{Diversifier, PaymentAddress}, @@ -140,7 +141,8 @@ pub fn encode_payment_address(hrp: &str, addr: &PaymentAddress) -> String /// /// ``` /// use pairing::bls12_381::Bls12; -/// use rand::{SeedableRng, XorShiftRng}; +/// use rand_core::SeedableRng; +/// use rand_xorshift::XorShiftRng; /// use sapling_crypto::{ /// jubjub::edwards, /// primitives::{Diversifier, PaymentAddress}, @@ -188,7 +190,8 @@ pub fn decode_payment_address(hrp: &str, s: &str) -> Result Date: Sun, 14 Jul 2019 12:19:01 +0100 Subject: [PATCH 036/330] Migrate to rand 0.7 --- Cargo.lock | 218 ++++++++-------------- bellman/Cargo.toml | 4 +- ff/Cargo.toml | 2 +- group/Cargo.toml | 4 +- librustzcash/Cargo.toml | 4 +- librustzcash/src/rustzcash.rs | 4 +- librustzcash/src/tests/key_agreement.rs | 2 +- pairing/Cargo.toml | 4 +- sapling-crypto/Cargo.toml | 4 +- zcash_client_backend/Cargo.toml | 4 +- zcash_primitives/Cargo.toml | 4 +- zcash_primitives/src/note_encryption.rs | 48 ++--- zcash_primitives/src/sapling.rs | 2 +- zcash_primitives/src/transaction/tests.rs | 2 +- zcash_proofs/Cargo.toml | 2 +- zcash_proofs/src/sapling/prover.rs | 6 +- 16 files changed, 126 insertions(+), 188 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d1cb83f..fac19e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,8 +66,8 @@ dependencies = [ "group 0.1.0", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -75,11 +75,6 @@ name = "bit-vec" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "bitflags" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "blake2b_simd" version = "0.5.1" @@ -143,11 +138,12 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "cloudabi" -version = "0.0.3" +name = "c2-chacha" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -200,7 +196,7 @@ version = "0.4.0" dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff_derive 0.3.0", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -227,11 +223,6 @@ dependencies = [ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "futures" version = "0.1.21" @@ -262,13 +253,22 @@ dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "getrandom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "group" version = "0.1.0" dependencies = [ "ff 0.4.0", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -295,12 +295,15 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.0.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "libc" -version = "0.2.40" +version = "0.2.59" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -312,11 +315,11 @@ dependencies = [ "blake2s_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", "zcash_proofs 0.0.0", @@ -354,7 +357,7 @@ name = "num_cpus" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -374,10 +377,15 @@ dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "group 0.1.0", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ppv-lite86" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "proc-macro-hack" version = "0.4.0" @@ -409,106 +417,57 @@ dependencies = [ [[package]] name = "rand" -version = "0.6.5" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_chacha" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" -version = "0.3.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rand_hc" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_os" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_xorshift" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -523,8 +482,8 @@ dependencies = [ "ff 0.4.0", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -539,6 +498,11 @@ dependencies = [ "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "spin" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "stream-cipher" version = "0.1.1" @@ -567,33 +531,14 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "winapi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "zcash_client_backend" version = "0.0.0" dependencies = [ "bech32 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", ] @@ -609,10 +554,10 @@ dependencies = [ "ff 0.4.0", "fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -626,7 +571,7 @@ dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "pairing 0.14.2", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", ] @@ -640,7 +585,6 @@ dependencies = [ "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" "checksum bech32 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58946044516aa9dc922182e0d6e9d124a31aafe6b421614654eb27cf90cec09c" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" -"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d909f9ef55928e57e7de9638828bc9407233b5cb0904066a7edebbaa9946db2f" "checksum blake2s_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fa20660ff9f1e6d0a05444b5ebbbae13e4c018d4c66cc78c7e421e3396358a52" "checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" @@ -649,7 +593,7 @@ dependencies = [ "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" "checksum byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "980479e6fde23246dfb54d47580d66b4e99202e7579c5eaa9fe10ecb5ebd2182" "checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crypto_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f855e87e75a4799e18b8529178adcde6fd4f97c1449ff4821e747ff728bb102" @@ -658,16 +602,16 @@ dependencies = [ "checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce3371c82bfbd984f624cab093f55e7336f5a6e589f8518e1258f54f011b89ad" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" +"checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4da5f0e01bd8a71a224a4eedecaacfcabda388dbb7a80faf04d3514287572d95" "checksum hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d340b6514f232f6db1bd16db65302a5278a04fef9ce867cb932e7e5fa21130a" -"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" -"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" +"checksum libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)" = "3262021842bf00fe07dbd6cf34ff25c99d7a7ebef8deea84db72be3ea3bb0aff" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3eceac7784c5dc97c2d6edf30259b4e153e6e2b42b3c85e9a6e9f45d06caef6e" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" @@ -675,26 +619,20 @@ dependencies = [ "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d620c9c26834b34f039489ac0dfdb12c7ac15ccaf818350a64c9b5334a452ad7" "checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" +"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ba8d4f9257b85eb6cdf13f055cea3190520aab1409ca2ab43493ea4820c25f0" "checksum proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5cb6f960ad471404618e9817c0e5d10b1ae74cfdf01fab89ea0641fe7fb2892" "checksum proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b331c6ad3411474cd55540398dc7ad89fc41488e64ec71fdecc9c9b86de96fb0" "checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" +"checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d" +"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rand_os 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e8c83d0434e67e7a92be561af33f3ca17ff9899a4acf28030fabb8c5c323a1a" +"checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" +"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" "checksum stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "30dc6118470d69ce0fdcf7e6f95e95853f7f4f72f80d835d4519577c323814ab" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/bellman/Cargo.toml b/bellman/Cargo.toml index a56b1ed..b15671e 100644 --- a/bellman/Cargo.toml +++ b/bellman/Cargo.toml @@ -9,7 +9,6 @@ repository = "https://github.com/ebfull/bellman" version = "0.1.0" [dependencies] -rand_core = "0.4" bit-vec = "0.4.4" ff = { path = "../ff" } futures = "0.1" @@ -18,10 +17,11 @@ group = { path = "../group" } num_cpus = { version = "1", optional = true } crossbeam = { version = "0.3", optional = true } pairing = { path = "../pairing", optional = true } +rand_core = "0.5" byteorder = "1" [dev-dependencies] -rand = "0.6" +rand = "0.7" [features] groth16 = ["pairing"] diff --git a/ff/Cargo.toml b/ff/Cargo.toml index 853f19d..212f6c4 100644 --- a/ff/Cargo.toml +++ b/ff/Cargo.toml @@ -10,8 +10,8 @@ repository = "https://github.com/ebfull/ff" [dependencies] byteorder = "1" -rand_core = "0.4" ff_derive = { version = "0.3.0", path = "ff_derive", optional = true } +rand_core = "0.5" [features] default = [] diff --git a/group/Cargo.toml b/group/Cargo.toml index f278b4e..7d2d531 100644 --- a/group/Cargo.toml +++ b/group/Cargo.toml @@ -14,5 +14,5 @@ repository = "https://github.com/ebfull/group" [dependencies] ff = { path = "../ff" } -rand = "0.6" -rand_xorshift = "0.1" +rand = "0.7" +rand_xorshift = "0.2" diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index d67d4ee..ffc38fa 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -22,8 +22,8 @@ libc = "0.2" pairing = { path = "../pairing" } lazy_static = "1" byteorder = "1" -rand_core = "0.4" -rand_os = "0.1" +rand_core = "0.5" +rand_os = "0.2" sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } zcash_proofs = { path = "../zcash_proofs" } diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 7f10d1c..eabbc1b 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -388,7 +388,7 @@ fn test_gen_r() { #[no_mangle] pub extern "system" fn librustzcash_sapling_generate_r(result: *mut [c_uchar; 32]) { // create random 64 byte buffer - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let mut buffer = [0u8; 64]; rng.fill_bytes(&mut buffer); @@ -858,7 +858,7 @@ pub extern "system" fn librustzcash_sprout_prove( drop(sprout_fs); // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let proof = create_random_proof(js, ¶ms, &mut rng).expect("proving should not fail"); diff --git a/librustzcash/src/tests/key_agreement.rs b/librustzcash/src/tests/key_agreement.rs index 9d22561..412ecc3 100644 --- a/librustzcash/src/tests/key_agreement.rs +++ b/librustzcash/src/tests/key_agreement.rs @@ -13,7 +13,7 @@ use { #[test] fn test_key_agreement() { let params = JubjubBls12::new(); - let mut rng = OsRng::new().unwrap(); + let mut rng = OsRng; // Create random viewing key let vk = ViewingKey:: { diff --git a/pairing/Cargo.toml b/pairing/Cargo.toml index 5a065e2..759fd3d 100644 --- a/pairing/Cargo.toml +++ b/pairing/Cargo.toml @@ -15,13 +15,13 @@ homepage = "https://github.com/ebfull/pairing" repository = "https://github.com/ebfull/pairing" [dependencies] -rand_core = "0.4" byteorder = "1" ff = { path = "../ff", features = ["derive"] } group = { path = "../group" } +rand_core = "0.5" [dev-dependencies] -rand_xorshift = "0.1" +rand_xorshift = "0.2" [features] unstable-features = ["expose-arith"] diff --git a/sapling-crypto/Cargo.toml b/sapling-crypto/Cargo.toml index da28615..0026f6c 100644 --- a/sapling-crypto/Cargo.toml +++ b/sapling-crypto/Cargo.toml @@ -17,11 +17,11 @@ bellman = { path = "../bellman" } blake2b_simd = "0.5" blake2s_simd = "0.5" ff = { path = "../ff" } -rand_core = "0.4" +rand_core = "0.5" digest = "0.7" byteorder = "1" [dev-dependencies] hex-literal = "0.1" -rand_xorshift = "0.1" +rand_xorshift = "0.2" sha2 = "0.8" diff --git a/zcash_client_backend/Cargo.toml b/zcash_client_backend/Cargo.toml index 8e7e055..1d7848e 100644 --- a/zcash_client_backend/Cargo.toml +++ b/zcash_client_backend/Cargo.toml @@ -13,5 +13,5 @@ sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } [dev-dependencies] -rand_core = "0.4" -rand_xorshift = "0.1" +rand_core = "0.5" +rand_xorshift = "0.2" diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index 10c6d00..56070e4 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -15,7 +15,7 @@ fpe = "0.1" hex = "0.3" lazy_static = "1" pairing = { path = "../pairing" } -rand_core = "0.4" -rand_os = "0.1" +rand_core = "0.5" +rand_os = "0.2" sapling-crypto = { path = "../sapling-crypto" } sha2 = "0.8" diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 728818f..1964361 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -137,7 +137,7 @@ impl Memo { fn generate_esk() -> Fs { // create random 64 byte buffer - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let mut buffer = [0u8; 64]; rng.fill_bytes(&mut buffer); @@ -228,7 +228,7 @@ fn prf_ock( /// JUBJUB, /// }; /// -/// let mut rng = OsRng::new().unwrap(); +/// let mut rng = OsRng; /// /// let diversifier = Diversifier([0; 11]); /// let pk_d = diversifier.g_d::(&JUBJUB).unwrap(); @@ -848,7 +848,7 @@ mod tests { #[test] fn decryption_with_invalid_ivk() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (_, _, _, cmu, epk, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); @@ -860,7 +860,7 @@ mod tests { #[test] fn decryption_with_invalid_epk() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (_, ivk, _, cmu, _, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); @@ -877,7 +877,7 @@ mod tests { #[test] fn decryption_with_invalid_cmu() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (_, ivk, _, _, epk, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); @@ -889,7 +889,7 @@ mod tests { #[test] fn decryption_with_invalid_tag() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (_, ivk, _, cmu, epk, mut enc_ciphertext, _) = random_enc_ciphertext(&mut rng); @@ -902,7 +902,7 @@ mod tests { #[test] fn decryption_with_invalid_version_byte() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -924,7 +924,7 @@ mod tests { #[test] fn decryption_with_invalid_diversifier() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -946,7 +946,7 @@ mod tests { #[test] fn decryption_with_incorrect_diversifier() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -968,7 +968,7 @@ mod tests { #[test] fn compact_decryption_with_invalid_ivk() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (_, _, _, cmu, epk, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); @@ -985,7 +985,7 @@ mod tests { #[test] fn compact_decryption_with_invalid_epk() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (_, ivk, _, cmu, _, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); @@ -1002,7 +1002,7 @@ mod tests { #[test] fn compact_decryption_with_invalid_cmu() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (_, ivk, _, _, epk, enc_ciphertext, _) = random_enc_ciphertext(&mut rng); @@ -1019,7 +1019,7 @@ mod tests { #[test] fn compact_decryption_with_invalid_version_byte() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1046,7 +1046,7 @@ mod tests { #[test] fn compact_decryption_with_invalid_diversifier() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1073,7 +1073,7 @@ mod tests { #[test] fn compact_decryption_with_incorrect_diversifier() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1100,7 +1100,7 @@ mod tests { #[test] fn recovery_with_invalid_ovk() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (mut ovk, _, cv, cmu, epk, enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1114,7 +1114,7 @@ mod tests { #[test] fn recovery_with_invalid_cv() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (ovk, _, _, cmu, epk, enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1133,7 +1133,7 @@ mod tests { #[test] fn recovery_with_invalid_cmu() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (ovk, _, cv, _, epk, enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1152,7 +1152,7 @@ mod tests { #[test] fn recovery_with_invalid_epk() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (ovk, _, cv, cmu, _, enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1171,7 +1171,7 @@ mod tests { #[test] fn recovery_with_invalid_enc_tag() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1185,7 +1185,7 @@ mod tests { #[test] fn recovery_with_invalid_out_tag() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (ovk, _, cv, cmu, epk, enc_ciphertext, mut out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1199,7 +1199,7 @@ mod tests { #[test] fn recovery_with_invalid_version_byte() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1221,7 +1221,7 @@ mod tests { #[test] fn recovery_with_invalid_diversifier() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); @@ -1243,7 +1243,7 @@ mod tests { #[test] fn recovery_with_incorrect_diversifier() { - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) = random_enc_ciphertext(&mut rng); diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index 7f2b6f2..ad7e309 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -113,7 +113,7 @@ pub fn spend_sig( params: &JubjubBls12, ) -> Signature { // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; // We compute `rsk`... let rsk = ask.randomize(ar); diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index 81f8e21..d9788ff 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -197,7 +197,7 @@ fn tx_write_rejects_unexpected_binding_sig() { // Fails with an unexpected binding signature { - let rng = &mut OsRng::new().expect("should be able to construct RNG"); + let rng = &mut OsRng; let sk = PrivateKey::(Fs::random(rng)); let sig = sk.sign( b"Foo bar", diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index e6bfd17..1eca6fd 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -11,6 +11,6 @@ blake2b_simd = "0.5" byteorder = "1" ff = { path = "../ff" } pairing = { path = "../pairing" } -rand_os = "0.1" +rand_os = "0.2" sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index df0b19d..fce4d8e 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -56,7 +56,7 @@ impl SaplingProvingContext { (), > { // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; // We create the randomness of the value commitment let rcv = Fs::random(&mut rng); @@ -189,7 +189,7 @@ impl SaplingProvingContext { params: &JubjubBls12, ) -> (Proof, edwards::Point) { // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; // We construct ephemeral randomness for the value commitment. This // randomness is not given back to the caller, but the synthetic @@ -250,7 +250,7 @@ impl SaplingProvingContext { params: &JubjubBls12, ) -> Result { // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); + let mut rng = OsRng; // Grab the current `bsk` from the context let bsk = PrivateKey::(self.bsk); From c4e14ad0b1617bc693bc6ec28162be3a41d8e8be Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 14 Jul 2019 12:25:24 +0100 Subject: [PATCH 037/330] Address libc deprecations --- librustzcash/src/rustzcash.rs | 42 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index eabbc1b..1db70ac 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -42,7 +42,7 @@ use rand_core::RngCore; use rand_os::OsRng; use std::io::BufReader; -use libc::{c_char, c_uchar, int64_t, size_t, uint32_t, uint64_t}; +use libc::{c_char, c_uchar, size_t}; use std::ffi::CStr; use std::fs::File; use std::path::{Path, PathBuf}; @@ -404,7 +404,7 @@ pub extern "system" fn librustzcash_sapling_generate_r(result: *mut [c_uchar; 32 fn priv_get_note( diversifier: *const [c_uchar; 11], pk_d: *const [c_uchar; 32], - value: uint64_t, + value: u64, r: *const [c_uchar; 32], ) -> Result, ()> { let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); @@ -444,11 +444,11 @@ fn priv_get_note( pub extern "system" fn librustzcash_sapling_compute_nf( diversifier: *const [c_uchar; 11], pk_d: *const [c_uchar; 32], - value: uint64_t, + value: u64, r: *const [c_uchar; 32], ak: *const [c_uchar; 32], nk: *const [c_uchar; 32], - position: uint64_t, + position: u64, result: *mut [c_uchar; 32], ) -> bool { let note = match priv_get_note(diversifier, pk_d, value, r) { @@ -489,7 +489,7 @@ pub extern "system" fn librustzcash_sapling_compute_nf( pub extern "system" fn librustzcash_sapling_compute_cm( diversifier: *const [c_uchar; 11], pk_d: *const [c_uchar; 32], - value: uint64_t, + value: u64, r: *const [c_uchar; 32], result: *mut [c_uchar; 32], ) -> bool { @@ -562,8 +562,8 @@ pub extern "system" fn librustzcash_sapling_ka_derivepublic( #[no_mangle] pub extern "system" fn librustzcash_eh_isvalid( - n: uint32_t, - k: uint32_t, + n: u32, + k: u32, input: *const c_uchar, input_len: size_t, nonce: *const c_uchar, @@ -700,7 +700,7 @@ pub extern "system" fn librustzcash_sapling_check_output( #[no_mangle] pub extern "system" fn librustzcash_sapling_final_check( ctx: *mut SaplingVerificationContext, - value_balance: int64_t, + value_balance: i64, binding_sig: *const [c_uchar; 64], sighash_value: *const [c_uchar; 32], ) -> bool { @@ -728,31 +728,31 @@ pub extern "system" fn librustzcash_sprout_prove( // First input in_sk1: *const [c_uchar; 32], - in_value1: uint64_t, + in_value1: u64, in_rho1: *const [c_uchar; 32], in_r1: *const [c_uchar; 32], in_auth1: *const [c_uchar; 1 + 33 * SPROUT_TREE_DEPTH + 8], // Second input in_sk2: *const [c_uchar; 32], - in_value2: uint64_t, + in_value2: u64, in_rho2: *const [c_uchar; 32], in_r2: *const [c_uchar; 32], in_auth2: *const [c_uchar; 1 + 33 * SPROUT_TREE_DEPTH + 8], // First output out_pk1: *const [c_uchar; 32], - out_value1: uint64_t, + out_value1: u64, out_r1: *const [c_uchar; 32], // Second output out_pk2: *const [c_uchar; 32], - out_value2: uint64_t, + out_value2: u64, out_r2: *const [c_uchar; 32], // Public value - vpub_old: uint64_t, - vpub_new: uint64_t, + vpub_old: u64, + vpub_new: u64, ) { let phi = unsafe { *phi }; let rt = unsafe { *rt }; @@ -878,8 +878,8 @@ pub extern "system" fn librustzcash_sprout_verify( nf2: *const [c_uchar; 32], cm1: *const [c_uchar; 32], cm2: *const [c_uchar; 32], - vpub_old: uint64_t, - vpub_new: uint64_t, + vpub_old: u64, + vpub_new: u64, ) -> bool { // Prepare the public input for the verifier let mut public_input = Vec::with_capacity((32 * 8) + (8 * 2)); @@ -923,7 +923,7 @@ pub extern "system" fn librustzcash_sapling_output_proof( diversifier: *const [c_uchar; 11], pk_d: *const [c_uchar; 32], rcm: *const [c_uchar; 32], - value: uint64_t, + value: u64, cv: *mut [c_uchar; 32], zkproof: *mut [c_uchar; GROTH_PROOF_SIZE], ) -> bool { @@ -1015,7 +1015,7 @@ pub extern "system" fn librustzcash_sapling_spend_sig( #[no_mangle] pub extern "system" fn librustzcash_sapling_binding_sig( ctx: *const SaplingProvingContext, - value_balance: int64_t, + value_balance: i64, sighash: *const [c_uchar; 32], result: *mut [c_uchar; 64], ) -> bool { @@ -1040,7 +1040,7 @@ pub extern "system" fn librustzcash_sapling_spend_proof( diversifier: *const [c_uchar; 11], rcm: *const [c_uchar; 32], ar: *const [c_uchar; 32], - value: uint64_t, + value: u64, anchor: *const [c_uchar; 32], witness: *const [c_uchar; 1 + 33 * SAPLING_TREE_DEPTH + 8], cv: *mut [c_uchar; 32], @@ -1161,7 +1161,7 @@ pub extern "system" fn librustzcash_zip32_xsk_master( #[no_mangle] pub extern "system" fn librustzcash_zip32_xsk_derive( xsk_parent: *const [c_uchar; 169], - i: uint32_t, + i: u32, xsk_i: *mut [c_uchar; 169], ) { let xsk_parent = zip32::ExtendedSpendingKey::read(&unsafe { *xsk_parent }[..]) @@ -1177,7 +1177,7 @@ pub extern "system" fn librustzcash_zip32_xsk_derive( #[no_mangle] pub extern "system" fn librustzcash_zip32_xfvk_derive( xfvk_parent: *const [c_uchar; 169], - i: uint32_t, + i: u32, xfvk_i: *mut [c_uchar; 169], ) -> bool { let xfvk_parent = zip32::ExtendedFullViewingKey::read(&unsafe { *xfvk_parent }[..]) From 7f60f0f881e6f24e6dade62a5534f7acc3112888 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Wed, 10 Jul 2019 11:07:22 -0700 Subject: [PATCH 038/330] Make some methods in DiversifierKey, DiversiferIndex pub --- zcash_primitives/src/zip32.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zcash_primitives/src/zip32.rs b/zcash_primitives/src/zip32.rs index db5adcd..54f386d 100644 --- a/zcash_primitives/src/zip32.rs +++ b/zcash_primitives/src/zip32.rs @@ -94,7 +94,7 @@ struct ChainCode([u8; 32]); pub struct DiversifierIndex(pub [u8; 11]); impl DiversifierIndex { - fn new() -> Self { + pub fn new() -> Self { DiversifierIndex([0; 11]) } @@ -113,10 +113,10 @@ impl DiversifierIndex { /// A key used to derive diversifiers for a particular child key #[derive(Clone, Copy, Debug, PartialEq)] -struct DiversifierKey([u8; 32]); +pub struct DiversifierKey(pub [u8; 32]); impl DiversifierKey { - fn master(sk_m: &[u8]) -> Self { + pub fn master(sk_m: &[u8]) -> Self { let mut dk_m = [0u8; 32]; dk_m.copy_from_slice(&prf_expand(sk_m, &[0x10]).as_bytes()[..32]); DiversifierKey(dk_m) @@ -131,7 +131,7 @@ impl DiversifierKey { /// Returns the first index starting from j that generates a valid /// diversifier, along with the corresponding diversifier. Returns /// an error if the diversifier space is exhausted. - fn diversifier(&self, mut j: DiversifierIndex) -> Result<(DiversifierIndex, Diversifier), ()> { + pub fn diversifier(&self, mut j: DiversifierIndex) -> Result<(DiversifierIndex, Diversifier), ()> { let ff = FF1::::new(&self.0, 2).unwrap(); loop { // Generate d_j From 0255dca16e5f699770c8d99537cbc783623e9267 Mon Sep 17 00:00:00 2001 From: str4d Date: Fri, 26 Jul 2019 19:43:42 +0100 Subject: [PATCH 039/330] Clarify masking of bits in Field::random impls Co-Authored-By: Daira Hopwood --- ff/ff_derive/src/lib.rs | 2 +- sapling-crypto/src/jubjub/fs.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index aea7a50..df2625b 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -892,7 +892,7 @@ fn prime_field_impl( #name(#repr(repr)) }; - // Mask away the unused bits at the beginning. + // Mask away the unused most-significant bits. tmp.0.as_mut()[#top_limb_index] &= 0xffffffffffffffff >> REPR_SHAVE_BITS; if tmp.is_valid() { diff --git a/sapling-crypto/src/jubjub/fs.rs b/sapling-crypto/src/jubjub/fs.rs index 017292b..baa16ef 100644 --- a/sapling-crypto/src/jubjub/fs.rs +++ b/sapling-crypto/src/jubjub/fs.rs @@ -292,7 +292,7 @@ impl Field for Fs { Fs(FsRepr(repr)) }; - // Mask away the unused bits at the beginning. + // Mask away the unused most-significant bits. tmp.0.as_mut()[3] &= 0xffffffffffffffff >> REPR_SHAVE_BITS; if tmp.is_valid() { From 01618038bfa274094d1c3a6dd20b61b6b7891371 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 18 Nov 2018 11:20:59 +0000 Subject: [PATCH 040/330] TxProver trait to abstract over the circuit parameters An implementation using local parameters is provided in the zcash_proofs crate. --- Cargo.lock | 33 +++ zcash_primitives/src/lib.rs | 1 + zcash_primitives/src/prover.rs | 162 +++++++++++++++ .../src/transaction/components.rs | 2 +- zcash_proofs/Cargo.toml | 1 + zcash_proofs/src/lib.rs | 2 + zcash_proofs/src/prover.rs | 190 ++++++++++++++++++ 7 files changed, 390 insertions(+), 1 deletion(-) create mode 100644 zcash_primitives/src/prover.rs create mode 100644 zcash_proofs/src/prover.rs diff --git a/Cargo.lock b/Cargo.lock index fac19e3..a9a4f97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -185,6 +185,15 @@ dependencies = [ "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "directories" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -531,6 +540,25 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "zcash_client_backend" version = "0.0.0" @@ -569,6 +597,7 @@ dependencies = [ "bellman 0.1.0", "blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "pairing 0.14.2", "rand_os 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -600,6 +629,7 @@ dependencies = [ "checksum crypto_api_chachapoly 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9ee35dbace0831b5fe7cb9b43eb029aa14a10f594a115025d4628a2baa63ab" "checksum digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603" "checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" +"checksum directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72d337a64190607d4fcca2cb78982c5dd57f4916e19696b48a575fa746b6cb0f" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce3371c82bfbd984f624cab093f55e7336f5a6e589f8518e1258f54f011b89ad" "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" @@ -636,3 +666,6 @@ dependencies = [ "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 90d69e6..797b9b6 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -20,6 +20,7 @@ pub mod block; pub mod keys; pub mod merkle_tree; pub mod note_encryption; +pub mod prover; pub mod sapling; mod serialize; pub mod transaction; diff --git a/zcash_primitives/src/prover.rs b/zcash_primitives/src/prover.rs new file mode 100644 index 0000000..87a76c7 --- /dev/null +++ b/zcash_primitives/src/prover.rs @@ -0,0 +1,162 @@ +//! Abstractions over the proving system and parameters. + +use pairing::bls12_381::{Bls12, Fr}; +use sapling_crypto::{ + jubjub::{edwards, fs::Fs, Unknown}, + primitives::{Diversifier, PaymentAddress, ProofGenerationKey}, + redjubjub::{PublicKey, Signature}, +}; + +use crate::{ + merkle_tree::CommitmentTreeWitness, sapling::Node, transaction::components::GROTH_PROOF_SIZE, +}; + +/// Interface for creating zero-knowledge proofs for shielded transactions. +pub trait TxProver { + /// Type for persisting any necessary context across multiple Sapling proofs. + type SaplingProvingContext; + + /// Instantiate a new Sapling proving context. + fn new_sapling_proving_context(&self) -> Self::SaplingProvingContext; + + /// Create the value commitment, re-randomized key, and proof for a Sapling + /// [`SpendDescription`], while accumulating its value commitment randomness inside + /// the context for later use. + /// + /// [`SpendDescription`]: crate::transaction::components::SpendDescription + fn spend_proof( + &self, + ctx: &mut Self::SaplingProvingContext, + proof_generation_key: ProofGenerationKey, + diversifier: Diversifier, + rcm: Fs, + ar: Fs, + value: u64, + anchor: Fr, + witness: CommitmentTreeWitness, + ) -> Result< + ( + [u8; GROTH_PROOF_SIZE], + edwards::Point, + PublicKey, + ), + (), + >; + + /// Create the value commitment and proof for a Sapling [`OutputDescription`], + /// while accumulating its value commitment randomness inside the context for later + /// use. + /// + /// [`OutputDescription`]: crate::transaction::components::OutputDescription + fn output_proof( + &self, + ctx: &mut Self::SaplingProvingContext, + esk: Fs, + payment_address: PaymentAddress, + rcm: Fs, + value: u64, + ) -> ([u8; GROTH_PROOF_SIZE], edwards::Point); + + /// Create the `bindingSig` for a Sapling transaction. All calls to + /// [`TxProver::spend_proof`] and [`TxProver::output_proof`] must be completed before + /// calling this function. + fn binding_sig( + &self, + ctx: &mut Self::SaplingProvingContext, + value_balance: i64, + sighash: &[u8; 32], + ) -> Result; +} + +#[cfg(test)] +pub(crate) mod mock { + use ff::Field; + use pairing::bls12_381::{Bls12, Fr}; + use rand_os::OsRng; + use sapling_crypto::{ + jubjub::{edwards, fs::Fs, FixedGenerators, Unknown}, + primitives::{Diversifier, PaymentAddress, ProofGenerationKey, ValueCommitment}, + redjubjub::{PublicKey, Signature}, + }; + + use crate::{ + merkle_tree::CommitmentTreeWitness, sapling::Node, + transaction::components::GROTH_PROOF_SIZE, JUBJUB, + }; + + use super::TxProver; + + pub(crate) struct MockTxProver; + + #[cfg(test)] + impl TxProver for MockTxProver { + type SaplingProvingContext = (); + + fn new_sapling_proving_context(&self) -> Self::SaplingProvingContext {} + + fn spend_proof( + &self, + _ctx: &mut Self::SaplingProvingContext, + proof_generation_key: ProofGenerationKey, + _diversifier: Diversifier, + _rcm: Fs, + ar: Fs, + value: u64, + _anchor: Fr, + _witness: CommitmentTreeWitness, + ) -> Result< + ( + [u8; GROTH_PROOF_SIZE], + edwards::Point, + PublicKey, + ), + (), + > { + let mut rng = OsRng; + + let cv = ValueCommitment:: { + value, + randomness: Fs::random(&mut rng), + } + .cm(&JUBJUB) + .into(); + + let rk = PublicKey::(proof_generation_key.ak.clone().into()).randomize( + ar, + FixedGenerators::SpendingKeyGenerator, + &JUBJUB, + ); + + Ok(([0u8; GROTH_PROOF_SIZE], cv, rk)) + } + + fn output_proof( + &self, + _ctx: &mut Self::SaplingProvingContext, + _esk: Fs, + _payment_address: PaymentAddress, + _rcm: Fs, + value: u64, + ) -> ([u8; GROTH_PROOF_SIZE], edwards::Point) { + let mut rng = OsRng; + + let cv = ValueCommitment:: { + value, + randomness: Fs::random(&mut rng), + } + .cm(&JUBJUB) + .into(); + + ([0u8; GROTH_PROOF_SIZE], cv) + } + + fn binding_sig( + &self, + _ctx: &mut Self::SaplingProvingContext, + _value_balance: i64, + _sighash: &[u8; 32], + ) -> Result { + Err(()) + } + } +} diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index b8153f3..141d0ff 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -11,7 +11,7 @@ use serialize::Vector; use JUBJUB; // π_A + π_B + π_C -const GROTH_PROOF_SIZE: usize = (48 + 96 + 48); +pub const GROTH_PROOF_SIZE: usize = (48 + 96 + 48); // π_A + π_A' + π_B + π_B' + π_C + π_C' + π_K + π_H const PHGR_PROOF_SIZE: usize = (33 + 33 + 65 + 33 + 33 + 33 + 33 + 33); diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index 1eca6fd..9e989fa 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -9,6 +9,7 @@ authors = [ bellman = { path = "../bellman" } blake2b_simd = "0.5" byteorder = "1" +directories = "1" ff = { path = "../ff" } pairing = { path = "../pairing" } rand_os = "0.2" diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs index dd6975c..26aa2f1 100644 --- a/zcash_proofs/src/lib.rs +++ b/zcash_proofs/src/lib.rs @@ -1,6 +1,7 @@ extern crate bellman; extern crate blake2b_simd; extern crate byteorder; +extern crate directories; extern crate ff; extern crate pairing; extern crate rand_os; @@ -14,6 +15,7 @@ use std::io::{self, BufReader}; use std::path::Path; mod hashreader; +pub mod prover; pub mod sapling; pub fn load_parameters( diff --git a/zcash_proofs/src/prover.rs b/zcash_proofs/src/prover.rs new file mode 100644 index 0000000..005d7eb --- /dev/null +++ b/zcash_proofs/src/prover.rs @@ -0,0 +1,190 @@ +//! Abstractions over the proving system and parameters for ease of use. + +use bellman::groth16::{Parameters, PreparedVerifyingKey}; +use directories::BaseDirs; +use pairing::bls12_381::{Bls12, Fr}; +use sapling_crypto::{ + jubjub::{edwards, fs::Fs, Unknown}, + primitives::{Diversifier, PaymentAddress, ProofGenerationKey}, + redjubjub::{PublicKey, Signature}, +}; +use std::path::Path; +use zcash_primitives::{ + merkle_tree::CommitmentTreeWitness, prover::TxProver, sapling::Node, + transaction::components::GROTH_PROOF_SIZE, JUBJUB, +}; + +use crate::{load_parameters, sapling::SaplingProvingContext}; + +const SAPLING_SPEND_HASH: &str = "8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c"; +const SAPLING_OUTPUT_HASH: &str = "657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028"; + +/// An implementation of [`TxProver`] using Sapling Spend and Output parameters from +/// locally-accessible paths. +pub struct LocalTxProver { + spend_params: Parameters, + spend_vk: PreparedVerifyingKey, + output_params: Parameters, +} + +impl LocalTxProver { + /// Creates a `LocalTxProver` using parameters from the given local paths. + /// + /// # Examples + /// + /// ```should_panic + /// use std::path::Path; + /// use zcash_proofs::prover::LocalTxProver; + /// + /// let tx_prover = LocalTxProver::new( + /// Path::new("/path/to/sapling-spend.params"), + /// Path::new("/path/to/sapling-output.params"), + /// ); + /// ``` + /// + /// # Panics + /// + /// This function will panic if the paths do not point to valid parameter files with + /// the expected hashes. + pub fn new(spend_path: &Path, output_path: &Path) -> Self { + let (spend_params, spend_vk, output_params, _, _) = load_parameters( + spend_path, + SAPLING_SPEND_HASH, + output_path, + SAPLING_OUTPUT_HASH, + None, + None, + ); + LocalTxProver { + spend_params, + spend_vk, + output_params, + } + } + + /// Attempts to create a `LocalTxProver` using parameters from the default local + /// location. + /// + /// Returns `None` if any of the parameters cannot be found in the default local + /// location. + /// + /// # Examples + /// + /// ``` + /// use zcash_proofs::prover::LocalTxProver; + /// + /// match LocalTxProver::with_default_location() { + /// Some(tx_prover) => (), + /// None => println!("Please run zcash-fetch-params or fetch-params.sh to download the parameters."), + /// } + /// ``` + /// + /// # Panics + /// + /// This function will panic if the parameters in the default local location do not + /// have the expected hashes. + pub fn with_default_location() -> Option { + let base_dirs = BaseDirs::new()?; + let unix_params_dir = base_dirs.home_dir().join(".zcash-params"); + let win_osx_params_dir = base_dirs.data_dir().join("ZcashParams"); + let (spend_path, output_path) = if unix_params_dir.exists() { + ( + unix_params_dir.join("sapling-spend.params"), + unix_params_dir.join("sapling-output.params"), + ) + } else if win_osx_params_dir.exists() { + ( + win_osx_params_dir.join("sapling-spend.params"), + win_osx_params_dir.join("sapling-output.params"), + ) + } else { + return None; + }; + if !(spend_path.exists() && output_path.exists()) { + return None; + } + + Some(LocalTxProver::new(&spend_path, &output_path)) + } +} + +impl TxProver for LocalTxProver { + type SaplingProvingContext = SaplingProvingContext; + + fn new_sapling_proving_context(&self) -> Self::SaplingProvingContext { + SaplingProvingContext::new() + } + + fn spend_proof( + &self, + ctx: &mut Self::SaplingProvingContext, + proof_generation_key: ProofGenerationKey, + diversifier: Diversifier, + rcm: Fs, + ar: Fs, + value: u64, + anchor: Fr, + witness: CommitmentTreeWitness, + ) -> Result< + ( + [u8; GROTH_PROOF_SIZE], + edwards::Point, + PublicKey, + ), + (), + > { + let (proof, cv, rk) = ctx.spend_proof( + proof_generation_key, + diversifier, + rcm, + ar, + value, + anchor, + witness, + &self.spend_params, + &self.spend_vk, + &JUBJUB, + )?; + + let mut zkproof = [0u8; GROTH_PROOF_SIZE]; + proof + .write(&mut zkproof[..]) + .expect("should be able to serialize a proof"); + + Ok((zkproof, cv, rk)) + } + + fn output_proof( + &self, + ctx: &mut Self::SaplingProvingContext, + esk: Fs, + payment_address: PaymentAddress, + rcm: Fs, + value: u64, + ) -> ([u8; GROTH_PROOF_SIZE], edwards::Point) { + let (proof, cv) = ctx.output_proof( + esk, + payment_address, + rcm, + value, + &self.output_params, + &JUBJUB, + ); + + let mut zkproof = [0u8; GROTH_PROOF_SIZE]; + proof + .write(&mut zkproof[..]) + .expect("should be able to serialize a proof"); + + (zkproof, cv) + } + + fn binding_sig( + &self, + ctx: &mut Self::SaplingProvingContext, + value_balance: i64, + sighash: &[u8; 32], + ) -> Result { + ctx.binding_sig(value_balance, sighash, &JUBJUB) + } +} From 1862354ea6d43ed5619b2dd2dbe29eb8442a25bc Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 20 Nov 2018 13:37:21 +0000 Subject: [PATCH 041/330] Sapling transaction builder --- Cargo.lock | 1 + zcash_primitives/Cargo.toml | 1 + zcash_primitives/src/lib.rs | 1 + zcash_primitives/src/merkle_tree.rs | 2 +- zcash_primitives/src/note_encryption.rs | 2 +- zcash_primitives/src/transaction/builder.rs | 615 ++++++++++++++++++++ zcash_primitives/src/transaction/mod.rs | 1 + 7 files changed, 621 insertions(+), 2 deletions(-) create mode 100644 zcash_primitives/src/transaction/builder.rs diff --git a/Cargo.lock b/Cargo.lock index a9a4f97..fc8644f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -584,6 +584,7 @@ dependencies = [ "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", + "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index 56070e4..804f8c6 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -15,6 +15,7 @@ fpe = "0.1" hex = "0.3" lazy_static = "1" pairing = { path = "../pairing" } +rand = "0.7" rand_core = "0.5" rand_os = "0.2" sapling-crypto = { path = "../sapling-crypto" } diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 797b9b6..d6ddcc9 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -9,6 +9,7 @@ extern crate ff; extern crate fpe; extern crate hex; extern crate pairing; +extern crate rand; extern crate rand_core; extern crate rand_os; extern crate sapling_crypto; diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index a692073..aa1596d 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -420,7 +420,7 @@ impl IncrementalWitness { /// A witness to a path from a position in a particular commitment tree to the root of /// that tree. -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub struct CommitmentTreeWitness { pub auth_path: Vec>, pub position: u64, diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 1964361..d0a7250 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -135,7 +135,7 @@ impl Memo { } } -fn generate_esk() -> Fs { +pub fn generate_esk() -> Fs { // create random 64 byte buffer let mut rng = OsRng; let mut buffer = [0u8; 64]; diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs new file mode 100644 index 0000000..9f6cccd --- /dev/null +++ b/zcash_primitives/src/transaction/builder.rs @@ -0,0 +1,615 @@ +//! Structs for building transactions. + +use ff::Field; +use pairing::bls12_381::{Bls12, Fr}; +use rand::{rngs::OsRng, seq::SliceRandom, CryptoRng, RngCore}; +use sapling_crypto::{ + jubjub::fs::Fs, + primitives::{Diversifier, Note, PaymentAddress}, + redjubjub::PrivateKey, +}; +use zip32::ExtendedSpendingKey; + +use crate::{ + keys::OutgoingViewingKey, + merkle_tree::{CommitmentTreeWitness, IncrementalWitness}, + note_encryption::{generate_esk, Memo, SaplingNoteEncryption}, + prover::TxProver, + sapling::{spend_sig, Node}, + transaction::{ + components::{Amount, OutputDescription, SpendDescription}, + signature_hash_data, Transaction, TransactionData, SIGHASH_ALL, + }, + JUBJUB, +}; + +const DEFAULT_FEE: Amount = Amount(10000); +const DEFAULT_TX_EXPIRY_DELTA: u32 = 20; + +/// If there are any shielded inputs, always have at least two shielded outputs, padding +/// with dummy outputs if necessary. See https://github.com/zcash/zcash/issues/3615 +const MIN_SHIELDED_OUTPUTS: usize = 2; + +#[derive(Debug)] +pub struct Error(ErrorKind); + +impl Error { + pub fn kind(&self) -> &ErrorKind { + &self.0 + } +} + +#[derive(Debug, PartialEq)] +pub enum ErrorKind { + AnchorMismatch, + BindingSig, + ChangeIsNegative(i64), + InvalidAddress, + InvalidAmount, + InvalidWitness, + NoChangeAddress, + SpendProof, +} + +struct SpendDescriptionInfo { + extsk: ExtendedSpendingKey, + diversifier: Diversifier, + note: Note, + alpha: Fs, + witness: CommitmentTreeWitness, +} + +pub struct SaplingOutput { + ovk: OutgoingViewingKey, + to: PaymentAddress, + note: Note, + memo: Memo, +} + +impl SaplingOutput { + pub fn new( + rng: &mut R, + ovk: OutgoingViewingKey, + to: PaymentAddress, + value: Amount, + memo: Option, + ) -> Result { + let g_d = match to.g_d(&JUBJUB) { + Some(g_d) => g_d, + None => return Err(Error(ErrorKind::InvalidAddress)), + }; + if value.0 < 0 { + return Err(Error(ErrorKind::InvalidAmount)); + } + + let rcm = Fs::random(rng); + + let note = Note { + g_d, + pk_d: to.pk_d.clone(), + value: value.0 as u64, + r: rcm, + }; + + Ok(SaplingOutput { + ovk, + to, + note, + memo: memo.unwrap_or_default(), + }) + } + + pub fn build( + self, + prover: &P, + ctx: &mut P::SaplingProvingContext, + ) -> OutputDescription { + let encryptor = + SaplingNoteEncryption::new(self.ovk, self.note.clone(), self.to.clone(), self.memo); + + let (zkproof, cv) = prover.output_proof( + ctx, + encryptor.esk().clone(), + self.to, + self.note.r, + self.note.value, + ); + + let cmu = self.note.cm(&JUBJUB); + + let enc_ciphertext = encryptor.encrypt_note_plaintext(); + let out_ciphertext = encryptor.encrypt_outgoing_plaintext(&cv, &cmu); + + let ephemeral_key = encryptor.epk().clone().into(); + + OutputDescription { + cv, + cmu, + ephemeral_key, + enc_ciphertext, + out_ciphertext, + zkproof, + } + } +} + +/// Metadata about a transaction created by a [`Builder`]. +pub struct TransactionMetadata { + spend_indices: Vec, + output_indices: Vec, +} + +impl TransactionMetadata { + fn new() -> Self { + TransactionMetadata { + spend_indices: vec![], + output_indices: vec![], + } + } + + /// Returns the index within the transaction of the [`SpendDescription`] corresponding + /// to the `n`-th call to [`Builder::add_sapling_spend`]. + /// + /// Note positions are randomized when building transactions for indistinguishability. + /// This means that the transaction consumer cannot assume that e.g. the first spend + /// they added (via the first call to [`Builder::add_sapling_spend`]) is the first + /// [`SpendDescription`] in the transaction. + pub fn spend_index(&self, n: usize) -> Option { + self.spend_indices.get(n).map(|i| *i) + } + + /// Returns the index within the transaction of the [`OutputDescription`] corresponding + /// to the `n`-th call to [`Builder::add_sapling_output`]. + /// + /// Note positions are randomized when building transactions for indistinguishability. + /// This means that the transaction consumer cannot assume that e.g. the first output + /// they added (via the first call to [`Builder::add_sapling_output`]) is the first + /// [`OutputDescription`] in the transaction. + pub fn output_index(&self, n: usize) -> Option { + self.output_indices.get(n).map(|i| *i) + } +} + +/// Generates a [`Transaction`] from its inputs and outputs. +pub struct Builder { + rng: OsRng, + mtx: TransactionData, + fee: Amount, + anchor: Option, + spends: Vec, + outputs: Vec, + change_address: Option<(OutgoingViewingKey, PaymentAddress)>, +} + +impl Builder { + /// Creates a new `Builder` targeted for inclusion in the block with the given height, + /// using default values for general transaction fields. + /// + /// # Default values + /// + /// The expiry height will be set to the given height plus the default transaction + /// expiry delta (20 blocks). + /// + /// The fee will be set to the default fee (0.0001 ZEC). + pub fn new(height: u32) -> Builder { + let mut mtx = TransactionData::new(); + mtx.expiry_height = height + DEFAULT_TX_EXPIRY_DELTA; + + Builder { + rng: OsRng, + mtx, + fee: DEFAULT_FEE, + anchor: None, + spends: vec![], + outputs: vec![], + change_address: None, + } + } + + /// Adds a Sapling note to be spent in this transaction. + /// + /// Returns an error if the given witness does not have the same anchor as previous + /// witnesses, or has no path. + pub fn add_sapling_spend( + &mut self, + extsk: ExtendedSpendingKey, + diversifier: Diversifier, + note: Note, + witness: IncrementalWitness, + ) -> Result<(), Error> { + // Consistency check: all anchors must equal the first one + if let Some(anchor) = self.anchor { + let witness_root: Fr = witness.root().into(); + if witness_root != anchor { + return Err(Error(ErrorKind::AnchorMismatch)); + } + } else { + self.anchor = Some(witness.root().into()) + } + let witness = witness.path().ok_or(Error(ErrorKind::InvalidWitness))?; + + let alpha = Fs::random(&mut self.rng); + + self.mtx.value_balance.0 += note.value as i64; + + self.spends.push(SpendDescriptionInfo { + extsk, + diversifier, + note, + alpha, + witness, + }); + + Ok(()) + } + + /// Adds a Sapling address to send funds to. + pub fn add_sapling_output( + &mut self, + ovk: OutgoingViewingKey, + to: PaymentAddress, + value: Amount, + memo: Option, + ) -> Result<(), Error> { + let output = SaplingOutput::new(&mut self.rng, ovk, to, value, memo)?; + + self.mtx.value_balance.0 -= value.0; + + self.outputs.push(output); + + Ok(()) + } + + /// Sets the Sapling address to which any change will be sent. + /// + /// By default, change is sent to the Sapling address corresponding to the first note + /// being spent (i.e. the first call to [`Builder::add_sapling_spend`]). + pub fn send_change_to(&mut self, ovk: OutgoingViewingKey, to: PaymentAddress) { + self.change_address = Some((ovk, to)); + } + + /// Builds a transaction from the configured spends and outputs. + /// + /// Upon success, returns a tuple containing the final transaction, and the + /// [`TransactionMetadata`] generated during the build process. + /// + /// `consensus_branch_id` must be valid for the block height that this transaction is + /// targeting. An invalid `consensus_branch_id` will *not* result in an error from + /// this function, and instead will generate a transaction that will be rejected by + /// the network. + pub fn build( + mut self, + consensus_branch_id: u32, + prover: impl TxProver, + ) -> Result<(Transaction, TransactionMetadata), Error> { + let mut tx_metadata = TransactionMetadata::new(); + + // + // Consistency checks + // + + // Valid change + let change = self.mtx.value_balance.0 - self.fee.0; + if change.is_negative() { + return Err(Error(ErrorKind::ChangeIsNegative(change))); + } + + // + // Change output + // + + if change.is_positive() { + // Send change to the specified change address. If no change address + // was set, send change to the first Sapling address given as input. + let change_address = if let Some(change_address) = self.change_address.take() { + change_address + } else if !self.spends.is_empty() { + ( + self.spends[0].extsk.expsk.ovk, + PaymentAddress { + diversifier: self.spends[0].diversifier, + pk_d: self.spends[0].note.pk_d.clone(), + }, + ) + } else { + return Err(Error(ErrorKind::NoChangeAddress)); + }; + + self.add_sapling_output(change_address.0, change_address.1, Amount(change), None)?; + } + + // + // Record initial positions of spends and outputs + // + let mut spends: Vec<_> = self.spends.into_iter().enumerate().collect(); + let mut outputs: Vec<_> = self + .outputs + .into_iter() + .enumerate() + .map(|(i, o)| Some((i, o))) + .collect(); + + // + // Sapling spends and outputs + // + + let mut ctx = prover.new_sapling_proving_context(); + let anchor = self.anchor.expect("anchor was set if spends were added"); + + // Pad Sapling outputs + let orig_outputs_len = outputs.len(); + if !spends.is_empty() { + while outputs.len() < MIN_SHIELDED_OUTPUTS { + outputs.push(None); + } + } + + // Randomize order of inputs and outputs + spends.shuffle(&mut self.rng); + outputs.shuffle(&mut self.rng); + tx_metadata.spend_indices.resize(spends.len(), 0); + tx_metadata.output_indices.resize(orig_outputs_len, 0); + + // Create Sapling SpendDescriptions + for (i, (pos, spend)) in spends.iter().enumerate() { + let proof_generation_key = spend.extsk.expsk.proof_generation_key(&JUBJUB); + + let mut nullifier = [0u8; 32]; + nullifier.copy_from_slice(&spend.note.nf( + &proof_generation_key.into_viewing_key(&JUBJUB), + spend.witness.position, + &JUBJUB, + )); + + let (zkproof, cv, rk) = prover + .spend_proof( + &mut ctx, + proof_generation_key, + spend.diversifier, + spend.note.r, + spend.alpha, + spend.note.value, + anchor, + spend.witness.clone(), + ) + .map_err(|()| Error(ErrorKind::SpendProof))?; + + self.mtx.shielded_spends.push(SpendDescription { + cv, + anchor: anchor, + nullifier, + rk, + zkproof, + spend_auth_sig: None, + }); + + // Record the post-randomized spend location + tx_metadata.spend_indices[*pos] = i; + } + + // Create Sapling OutputDescriptions + for (i, output) in outputs.into_iter().enumerate() { + let output_desc = if let Some((pos, output)) = output { + // Record the post-randomized output location + tx_metadata.output_indices[pos] = i; + + output.build(&prover, &mut ctx) + } else { + // This is a dummy output + let (dummy_to, dummy_note) = { + let (diversifier, g_d) = { + let mut diversifier; + let g_d; + loop { + let mut d = [0; 11]; + self.rng.fill_bytes(&mut d); + diversifier = Diversifier(d); + if let Some(val) = diversifier.g_d::(&JUBJUB) { + g_d = val; + break; + } + } + (diversifier, g_d) + }; + + let pk_d = { + let dummy_ivk = Fs::random(&mut self.rng); + g_d.mul(dummy_ivk, &JUBJUB) + }; + + ( + PaymentAddress { + diversifier, + pk_d: pk_d.clone(), + }, + Note { + g_d, + pk_d, + r: Fs::random(&mut self.rng), + value: 0, + }, + ) + }; + + let esk = generate_esk(); + let epk = dummy_note.g_d.mul(esk, &JUBJUB); + + let (zkproof, cv) = + prover.output_proof(&mut ctx, esk, dummy_to, dummy_note.r, dummy_note.value); + + let cmu = dummy_note.cm(&JUBJUB); + + let mut enc_ciphertext = [0u8; 580]; + let mut out_ciphertext = [0u8; 80]; + self.rng.fill_bytes(&mut enc_ciphertext[..]); + self.rng.fill_bytes(&mut out_ciphertext[..]); + + OutputDescription { + cv, + cmu, + ephemeral_key: epk.into(), + enc_ciphertext, + out_ciphertext, + zkproof, + } + }; + + self.mtx.shielded_outputs.push(output_desc); + } + + // + // Signatures + // + + let mut sighash = [0u8; 32]; + sighash.copy_from_slice(&signature_hash_data( + &self.mtx, + consensus_branch_id, + SIGHASH_ALL, + None, + )); + + // Create Sapling spendAuth and binding signatures + for (i, (_, spend)) in spends.into_iter().enumerate() { + self.mtx.shielded_spends[i].spend_auth_sig = Some(spend_sig( + PrivateKey(spend.extsk.expsk.ask), + spend.alpha, + &sighash, + &JUBJUB, + )); + } + self.mtx.binding_sig = Some( + prover + .binding_sig(&mut ctx, self.mtx.value_balance.0, &sighash) + .map_err(|()| Error(ErrorKind::BindingSig))?, + ); + + Ok(( + self.mtx.freeze().expect("Transaction should be complete"), + tx_metadata, + )) + } +} + +#[cfg(test)] +mod tests { + use ff::{Field, PrimeField}; + use rand::rngs::OsRng; + use sapling_crypto::jubjub::fs::Fs; + + use super::{Builder, ErrorKind}; + use crate::{ + merkle_tree::{CommitmentTree, IncrementalWitness}, + prover::mock::MockTxProver, + sapling::Node, + transaction::components::Amount, + zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}, + JUBJUB, + }; + + #[test] + fn fails_on_negative_output() { + let extsk = ExtendedSpendingKey::master(&[]); + let extfvk = ExtendedFullViewingKey::from(&extsk); + let ovk = extfvk.fvk.ovk; + let to = extfvk.default_address().unwrap().1; + + let mut builder = Builder::new(0); + match builder.add_sapling_output(ovk, to, Amount(-1), None) { + Err(e) => assert_eq!(e.kind(), &ErrorKind::InvalidAmount), + Ok(_) => panic!("Should have failed"), + } + } + + #[test] + fn fails_on_negative_change() { + let mut rng = OsRng; + + // Just use the master key as the ExtendedSpendingKey for this test + let extsk = ExtendedSpendingKey::master(&[]); + + // Fails with no inputs or outputs + // 0.0001 t-ZEC fee + { + let builder = Builder::new(0); + match builder.build(1, MockTxProver) { + Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(-10000)), + Ok(_) => panic!("Should have failed"), + } + } + + let extfvk = ExtendedFullViewingKey::from(&extsk); + let ovk = extfvk.fvk.ovk; + let to = extfvk.default_address().unwrap().1; + + // Fail if there is only a Sapling output + // 0.0005 z-ZEC out, 0.0001 t-ZEC fee + { + let mut builder = Builder::new(0); + builder + .add_sapling_output(ovk.clone(), to.clone(), Amount(50000), None) + .unwrap(); + match builder.build(1, MockTxProver) { + Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(-60000)), + Ok(_) => panic!("Should have failed"), + } + } + + let note1 = to + .create_note(59999, Fs::random(&mut rng), &JUBJUB) + .unwrap(); + let cm1 = Node::new(note1.cm(&JUBJUB).into_repr()); + let mut tree = CommitmentTree::new(); + tree.append(cm1).unwrap(); + let mut witness1 = IncrementalWitness::from_tree(&tree); + + // Fail if there is only a Sapling output + // 0.0005 z-ZEC out, 0.0001 t-ZEC fee, 0.00059999 z-ZEC in + { + let mut builder = Builder::new(0); + builder + .add_sapling_spend( + extsk.clone(), + to.diversifier, + note1.clone(), + witness1.clone(), + ) + .unwrap(); + builder + .add_sapling_output(ovk.clone(), to.clone(), Amount(50000), None) + .unwrap(); + match builder.build(1, MockTxProver) { + Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(-1)), + Ok(_) => panic!("Should have failed"), + } + } + + let note2 = to.create_note(1, Fs::random(&mut rng), &JUBJUB).unwrap(); + let cm2 = Node::new(note2.cm(&JUBJUB).into_repr()); + tree.append(cm2).unwrap(); + witness1.append(cm2).unwrap(); + let witness2 = IncrementalWitness::from_tree(&tree); + + // Succeeds if there is sufficient input + // 0.0005 z-ZEC out, 0.0001 t-ZEC fee, 0.0006 z-ZEC in + // + // (Still fails because we are using a MockTxProver which doesn't correctly + // compute bindingSig.) + { + let mut builder = Builder::new(0); + builder + .add_sapling_spend(extsk.clone(), to.diversifier, note1, witness1) + .unwrap(); + builder + .add_sapling_spend(extsk, to.diversifier, note2, witness2) + .unwrap(); + builder + .add_sapling_output(ovk, to, Amount(50000), None) + .unwrap(); + match builder.build(1, MockTxProver) { + Err(e) => assert_eq!(e.kind(), &ErrorKind::BindingSig), + Ok(_) => panic!("Should have failed"), + } + } + } +} diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index 35e042a..19f4396 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -8,6 +8,7 @@ use std::ops::Deref; use serialize::Vector; +pub mod builder; pub mod components; mod sighash; From dab3c002b765807c2c5c89063cf880e189705e29 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 24 May 2019 12:30:14 +0100 Subject: [PATCH 042/330] Script opcode and data support Overrides the shift-left operator for pushing opcodes onto the Script, matching the notation used in zcashd. --- zcash_primitives/src/legacy.rs | 105 ++++++++++++++++++ zcash_primitives/src/lib.rs | 1 + .../src/transaction/components.rs | 16 +-- zcash_primitives/src/transaction/sighash.rs | 3 +- zcash_primitives/src/transaction/tests.rs | 7 +- 5 files changed, 111 insertions(+), 21 deletions(-) create mode 100644 zcash_primitives/src/legacy.rs diff --git a/zcash_primitives/src/legacy.rs b/zcash_primitives/src/legacy.rs new file mode 100644 index 0000000..ac22c6b --- /dev/null +++ b/zcash_primitives/src/legacy.rs @@ -0,0 +1,105 @@ +//! Support for legacy transparent addresses and scripts. + +use byteorder::{ReadBytesExt, WriteBytesExt}; +use std::io::{self, Read, Write}; +use std::ops::Shl; + +use crate::serialize::Vector; + +/// Script opcodes. +enum OpCode { + // push value + PushData1 = 0x4c, + PushData2 = 0x4d, + PushData4 = 0x4e, +} + +/// A serialized script, used inside transparent inputs and outputs of a transaction. +#[derive(Debug, Default)] +pub struct Script(pub Vec); + +impl Script { + pub fn read(mut reader: R) -> io::Result { + let script = Vector::read(&mut reader, |r| r.read_u8())?; + Ok(Script(script)) + } + + pub fn write(&self, mut writer: W) -> io::Result<()> { + Vector::write(&mut writer, &self.0, |w, e| w.write_u8(*e)) + } +} + +impl Shl for Script { + type Output = Self; + + fn shl(mut self, rhs: OpCode) -> Self { + self.0.push(rhs as u8); + self + } +} + +impl Shl<&[u8]> for Script { + type Output = Self; + + fn shl(mut self, data: &[u8]) -> Self { + if data.len() < OpCode::PushData1 as usize { + self.0.push(data.len() as u8); + } else if data.len() <= 0xff { + self.0.push(OpCode::PushData1 as u8); + self.0.push(data.len() as u8); + } else if data.len() <= 0xffff { + self.0.push(OpCode::PushData2 as u8); + self.0.extend(&(data.len() as u16).to_le_bytes()); + } else { + self.0.push(OpCode::PushData4 as u8); + self.0.extend(&(data.len() as u32).to_le_bytes()); + } + self.0.extend(data); + self + } +} + +#[cfg(test)] +mod tests { + use super::{OpCode, Script}; + + #[test] + fn script_opcode() { + { + let script = Script::default() << OpCode::PushData1; + assert_eq!(&script.0, &[OpCode::PushData1 as u8]); + } + } + + #[test] + fn script_pushdata() { + { + let script = Script::default() << &[1, 2, 3, 4][..]; + assert_eq!(&script.0, &[4, 1, 2, 3, 4]); + } + + { + let short_data = vec![2; 100]; + let script = Script::default() << &short_data[..]; + assert_eq!(script.0[0], OpCode::PushData1 as u8); + assert_eq!(script.0[1] as usize, 100); + assert_eq!(&script.0[2..], &short_data[..]); + } + + { + let medium_data = vec![7; 1024]; + let script = Script::default() << &medium_data[..]; + assert_eq!(script.0[0], OpCode::PushData2 as u8); + assert_eq!(&script.0[1..3], &[0x00, 0x04][..]); + assert_eq!(&script.0[3..], &medium_data[..]); + } + + { + let long_data = vec![42; 1_000_000]; + let script = Script::default() << &long_data[..]; + assert_eq!(script.0[0], OpCode::PushData4 as u8); + assert_eq!(&script.0[1..5], &[0x40, 0x42, 0x0f, 0x00][..]); + assert_eq!(&script.0[5..], &long_data[..]); + } + } +} diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index d6ddcc9..a95d000 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -19,6 +19,7 @@ use sapling_crypto::jubjub::JubjubBls12; pub mod block; pub mod keys; +pub mod legacy; pub mod merkle_tree; pub mod note_encryption; pub mod prover; diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index 141d0ff..d4479b5 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -7,7 +7,7 @@ use sapling_crypto::{ }; use std::io::{self, Read, Write}; -use serialize::Vector; +use legacy::Script; use JUBJUB; // π_A + π_B + π_C @@ -58,20 +58,6 @@ impl Amount { } } -#[derive(Debug)] -pub struct Script(pub Vec); - -impl Script { - pub fn read(mut reader: R) -> io::Result { - let script = Vector::read(&mut reader, |r| r.read_u8())?; - Ok(Script(script)) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - Vector::write(&mut writer, &self.0, |w, e| w.write_u8(*e)) - } -} - #[derive(Debug)] pub struct OutPoint { hash: [u8; 32], diff --git a/zcash_primitives/src/transaction/sighash.rs b/zcash_primitives/src/transaction/sighash.rs index 774e7b4..bcc971a 100644 --- a/zcash_primitives/src/transaction/sighash.rs +++ b/zcash_primitives/src/transaction/sighash.rs @@ -3,10 +3,11 @@ use byteorder::{LittleEndian, WriteBytesExt}; use ff::{PrimeField, PrimeFieldRepr}; use super::{ - components::{Amount, Script, TxOut}, + components::{Amount, TxOut}, Transaction, TransactionData, OVERWINTER_VERSION_GROUP_ID, SAPLING_TX_VERSION, SAPLING_VERSION_GROUP_ID, }; +use legacy::Script; const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &'static [u8; 12] = b"ZcashSigHash"; const ZCASH_PREVOUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashPrevoutHash"; diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index d9788ff..1ebac3a 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -6,11 +6,8 @@ use sapling_crypto::{ redjubjub::PrivateKey, }; -use super::{ - components::{Amount, Script}, - sighash::signature_hash, - Transaction, TransactionData, -}; +use super::{components::Amount, sighash::signature_hash, Transaction, TransactionData}; +use legacy::Script; use JUBJUB; #[test] From c26188a0bb5dc6bd850aefa1b350bf0c38cf2d17 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 24 May 2019 13:23:27 +0100 Subject: [PATCH 043/330] TransparentAddress struct for P2PKH and P2SH --- zcash_primitives/src/legacy.rs | 65 +++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/zcash_primitives/src/legacy.rs b/zcash_primitives/src/legacy.rs index ac22c6b..02977ab 100644 --- a/zcash_primitives/src/legacy.rs +++ b/zcash_primitives/src/legacy.rs @@ -12,6 +12,17 @@ enum OpCode { PushData1 = 0x4c, PushData2 = 0x4d, PushData4 = 0x4e, + + // stack ops + Dup = 0x76, + + // bit logic + Equal = 0x87, + EqualVerify = 0x88, + + // crypto + Hash160 = 0xa9, + CheckSig = 0xac, } /// A serialized script, used inside transparent inputs and outputs of a transaction. @@ -59,9 +70,37 @@ impl Shl<&[u8]> for Script { } } +/// A transparent address corresponding to either a public key or a `Script`. +#[derive(Debug, PartialEq)] +pub enum TransparentAddress { + PublicKey([u8; 20]), + Script([u8; 20]), +} + +impl TransparentAddress { + /// Generate the `scriptPubKey` corresponding to this address. + pub fn script(&self) -> Script { + match self { + TransparentAddress::PublicKey(key_id) => { + // P2PKH script + Script::default() + << OpCode::Dup + << OpCode::Hash160 + << &key_id[..] + << OpCode::EqualVerify + << OpCode::CheckSig + } + TransparentAddress::Script(script_id) => { + // P2SH script + Script::default() << OpCode::Hash160 << &script_id[..] << OpCode::Equal + } + } + } +} + #[cfg(test)] mod tests { - use super::{OpCode, Script}; + use super::{OpCode, Script, TransparentAddress}; #[test] fn script_opcode() { @@ -102,4 +141,28 @@ mod tests { assert_eq!(&script.0[5..], &long_data[..]); } } + + #[test] + fn p2pkh() { + let addr = TransparentAddress::PublicKey([4; 20]); + assert_eq!( + &addr.script().0, + &[ + 0x76, 0xa9, 0x14, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x88, 0xac, + ] + ) + } + + #[test] + fn p2sh() { + let addr = TransparentAddress::Script([7; 20]); + assert_eq!( + &addr.script().0, + &[ + 0xa9, 0x14, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x87, + ] + ) + } } From a1cd9dfbac68f7ec2f3760a2c27c58afc6fcfad7 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 24 May 2019 13:32:55 +0100 Subject: [PATCH 044/330] transaction::Builder::add_transparent_output() --- zcash_primitives/src/transaction/builder.rs | 69 +++++++++++++++++-- .../src/transaction/components.rs | 4 +- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 9f6cccd..2def3a8 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -12,12 +12,13 @@ use zip32::ExtendedSpendingKey; use crate::{ keys::OutgoingViewingKey, + legacy::TransparentAddress, merkle_tree::{CommitmentTreeWitness, IncrementalWitness}, note_encryption::{generate_esk, Memo, SaplingNoteEncryption}, prover::TxProver, sapling::{spend_sig, Node}, transaction::{ - components::{Amount, OutputDescription, SpendDescription}, + components::{Amount, OutputDescription, SpendDescription, TxOut}, signature_hash_data, Transaction, TransactionData, SIGHASH_ALL, }, JUBJUB, @@ -260,6 +261,24 @@ impl Builder { Ok(()) } + /// Adds a transparent address to send funds to. + pub fn add_transparent_output( + &mut self, + to: &TransparentAddress, + value: Amount, + ) -> Result<(), Error> { + if value.0 < 0 { + return Err(Error(ErrorKind::InvalidAmount)); + } + + self.mtx.vout.push(TxOut { + value, + script_pubkey: to.script(), + }); + + Ok(()) + } + /// Sets the Sapling address to which any change will be sent. /// /// By default, change is sent to the Sapling address corresponding to the first note @@ -289,7 +308,14 @@ impl Builder { // // Valid change - let change = self.mtx.value_balance.0 - self.fee.0; + let change = self.mtx.value_balance.0 + - self.fee.0 + - self + .mtx + .vout + .iter() + .map(|output| output.value.0) + .sum::(); if change.is_negative() { return Err(Error(ErrorKind::ChangeIsNegative(change))); } @@ -499,6 +525,7 @@ mod tests { use super::{Builder, ErrorKind}; use crate::{ + legacy::TransparentAddress, merkle_tree::{CommitmentTree, IncrementalWitness}, prover::mock::MockTxProver, sapling::Node, @@ -521,6 +548,15 @@ mod tests { } } + #[test] + fn fails_on_negative_transparent_output() { + let mut builder = Builder::new(0); + match builder.add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount(-1)) { + Err(e) => assert_eq!(e.kind(), &ErrorKind::InvalidAmount), + Ok(_) => panic!("Should have failed"), + } + } + #[test] fn fails_on_negative_change() { let mut rng = OsRng; @@ -555,6 +591,19 @@ mod tests { } } + // Fail if there is only a transparent output + // 0.0005 t-ZEC out, 0.0001 t-ZEC fee + { + let mut builder = Builder::new(0); + builder + .add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount(50000)) + .unwrap(); + match builder.build(1, MockTxProver) { + Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(-60000)), + Ok(_) => panic!("Should have failed"), + } + } + let note1 = to .create_note(59999, Fs::random(&mut rng), &JUBJUB) .unwrap(); @@ -563,8 +612,8 @@ mod tests { tree.append(cm1).unwrap(); let mut witness1 = IncrementalWitness::from_tree(&tree); - // Fail if there is only a Sapling output - // 0.0005 z-ZEC out, 0.0001 t-ZEC fee, 0.00059999 z-ZEC in + // Fail if there is insufficient input + // 0.0003 z-ZEC out, 0.0002 t-ZEC out, 0.0001 t-ZEC fee, 0.00059999 z-ZEC in { let mut builder = Builder::new(0); builder @@ -576,7 +625,10 @@ mod tests { ) .unwrap(); builder - .add_sapling_output(ovk.clone(), to.clone(), Amount(50000), None) + .add_sapling_output(ovk.clone(), to.clone(), Amount(30000), None) + .unwrap(); + builder + .add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount(20000)) .unwrap(); match builder.build(1, MockTxProver) { Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(-1)), @@ -591,7 +643,7 @@ mod tests { let witness2 = IncrementalWitness::from_tree(&tree); // Succeeds if there is sufficient input - // 0.0005 z-ZEC out, 0.0001 t-ZEC fee, 0.0006 z-ZEC in + // 0.0003 z-ZEC out, 0.0002 t-ZEC out, 0.0001 t-ZEC fee, 0.0006 z-ZEC in // // (Still fails because we are using a MockTxProver which doesn't correctly // compute bindingSig.) @@ -604,7 +656,10 @@ mod tests { .add_sapling_spend(extsk, to.diversifier, note2, witness2) .unwrap(); builder - .add_sapling_output(ovk, to, Amount(50000), None) + .add_sapling_output(ovk, to, Amount(30000), None) + .unwrap(); + builder + .add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount(20000)) .unwrap(); match builder.build(1, MockTxProver) { Err(e) => assert_eq!(e.kind(), &ErrorKind::BindingSig), diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index d4479b5..f04c5aa 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -107,8 +107,8 @@ impl TxIn { #[derive(Debug)] pub struct TxOut { - value: Amount, - script_pubkey: Script, + pub value: Amount, + pub script_pubkey: Script, } impl TxOut { From 54ef63baced8160ac3396966b60941ceab1dbb3f Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 12 Jun 2019 17:36:09 +0100 Subject: [PATCH 045/330] Place zcash_proofs::prover::LocalTxProver behind a feature flag This enables zcash_proofs to be compiled to WASM, which the directories crate doesn't support. --- zcash_proofs/Cargo.toml | 6 +++++- zcash_proofs/src/lib.rs | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index 9e989fa..598e013 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -9,9 +9,13 @@ authors = [ bellman = { path = "../bellman" } blake2b_simd = "0.5" byteorder = "1" -directories = "1" +directories = { version = "1", optional = true } ff = { path = "../ff" } pairing = { path = "../pairing" } rand_os = "0.2" sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } + +[features] +default = ["local-prover"] +local-prover = ["directories"] diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs index 26aa2f1..d2dc877 100644 --- a/zcash_proofs/src/lib.rs +++ b/zcash_proofs/src/lib.rs @@ -1,13 +1,15 @@ extern crate bellman; extern crate blake2b_simd; extern crate byteorder; -extern crate directories; extern crate ff; extern crate pairing; extern crate rand_os; extern crate sapling_crypto; extern crate zcash_primitives; +#[cfg(feature = "local-prover")] +extern crate directories; + use bellman::groth16::{prepare_verifying_key, Parameters, PreparedVerifyingKey, VerifyingKey}; use pairing::bls12_381::Bls12; use std::fs::File; @@ -15,9 +17,11 @@ use std::io::{self, BufReader}; use std::path::Path; mod hashreader; -pub mod prover; pub mod sapling; +#[cfg(feature = "local-prover")] +pub mod prover; + pub fn load_parameters( spend_path: &Path, spend_hash: &str, From 4b61120cd0658938ac3cb537c9538c098f1ac4b7 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 12 Jun 2019 23:11:06 +0100 Subject: [PATCH 046/330] Pass tx builder RNG to SaplingNoteEncryption --- zcash_primitives/src/note_encryption.rs | 21 ++++++++++----------- zcash_primitives/src/transaction/builder.rs | 16 +++++++++++----- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index d0a7250..42e1398 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -5,8 +5,7 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf}; use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr}; -use rand_core::RngCore; -use rand_os::OsRng; +use rand_core::{CryptoRng, RngCore}; use sapling_crypto::{ jubjub::{ edwards, @@ -135,9 +134,8 @@ impl Memo { } } -pub fn generate_esk() -> Fs { +pub fn generate_esk(rng: &mut R) -> Fs { // create random 64 byte buffer - let mut rng = OsRng; let mut buffer = [0u8; 64]; rng.fill_bytes(&mut buffer); @@ -247,7 +245,7 @@ fn prf_ock( /// let note = to.create_note(value, rcv, &JUBJUB).unwrap(); /// let cmu = note.cm(&JUBJUB); /// -/// let enc = SaplingNoteEncryption::new(ovk, note, to, Memo::default()); +/// let enc = SaplingNoteEncryption::new(ovk, note, to, Memo::default(), &mut rng); /// let encCiphertext = enc.encrypt_note_plaintext(); /// let outCiphertext = enc.encrypt_outgoing_plaintext(&cv.cm(&JUBJUB).into(), &cmu); /// ``` @@ -262,13 +260,14 @@ pub struct SaplingNoteEncryption { impl SaplingNoteEncryption { /// Creates a new encryption context for the given note. - pub fn new( + pub fn new( ovk: OutgoingViewingKey, note: Note, to: PaymentAddress, memo: Memo, + rng: &mut R, ) -> SaplingNoteEncryption { - let esk = generate_esk(); + let esk = generate_esk(rng); let epk = note.g_d.mul(esk, &JUBJUB); SaplingNoteEncryption { @@ -561,7 +560,7 @@ mod tests { use crypto_api_chachapoly::ChachaPolyIetf; use ff::{Field, PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; - use rand_core::RngCore; + use rand_core::{CryptoRng, RngCore}; use rand_os::OsRng; use sapling_crypto::{ jubjub::{ @@ -694,7 +693,7 @@ mod tests { assert_eq!(Memo::default().to_utf8(), None); } - fn random_enc_ciphertext( + fn random_enc_ciphertext( mut rng: &mut R, ) -> ( OutgoingViewingKey, @@ -724,7 +723,7 @@ mod tests { let cmu = note.cm(&JUBJUB); let ovk = OutgoingViewingKey([0; 32]); - let ne = SaplingNoteEncryption::new(ovk, note, pa, Memo([0; 512])); + let ne = SaplingNoteEncryption::new(ovk, note, pa, Memo([0; 512]), rng); let epk = ne.epk(); let enc_ciphertext = ne.encrypt_note_plaintext(); let out_ciphertext = ne.encrypt_outgoing_plaintext(&cv, &cmu); @@ -1371,7 +1370,7 @@ mod tests { // Test encryption // - let mut ne = SaplingNoteEncryption::new(ovk, note, to, Memo(tv.memo)); + let mut ne = SaplingNoteEncryption::new(ovk, note, to, Memo(tv.memo), &mut OsRng); // Swap in the ephemeral keypair from the test vectors ne.esk = esk; ne.epk = epk; diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 2def3a8..2ea4d0d 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -100,13 +100,19 @@ impl SaplingOutput { }) } - pub fn build( + pub fn build( self, prover: &P, ctx: &mut P::SaplingProvingContext, + rng: &mut R, ) -> OutputDescription { - let encryptor = - SaplingNoteEncryption::new(self.ovk, self.note.clone(), self.to.clone(), self.memo); + let encryptor = SaplingNoteEncryption::new( + self.ovk, + self.note.clone(), + self.to.clone(), + self.memo, + rng, + ); let (zkproof, cv) = prover.output_proof( ctx, @@ -419,7 +425,7 @@ impl Builder { // Record the post-randomized output location tx_metadata.output_indices[pos] = i; - output.build(&prover, &mut ctx) + output.build(&prover, &mut ctx, &mut self.rng) } else { // This is a dummy output let (dummy_to, dummy_note) = { @@ -457,7 +463,7 @@ impl Builder { ) }; - let esk = generate_esk(); + let esk = generate_esk(&mut self.rng); let epk = dummy_note.g_d.mul(esk, &JUBJUB); let (zkproof, cv) = From 532299d46eaa2802356049b209a40e6289ad2621 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 12 Jun 2019 23:11:51 +0100 Subject: [PATCH 047/330] Allow transaction::Builder RNG to be configured --- zcash_primitives/src/transaction/builder.rs | 27 ++++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 2ea4d0d..4edcd20 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -178,8 +178,8 @@ impl TransactionMetadata { } /// Generates a [`Transaction`] from its inputs and outputs. -pub struct Builder { - rng: OsRng, +pub struct Builder { + rng: R, mtx: TransactionData, fee: Amount, anchor: Option, @@ -188,9 +188,9 @@ pub struct Builder { change_address: Option<(OutgoingViewingKey, PaymentAddress)>, } -impl Builder { +impl Builder { /// Creates a new `Builder` targeted for inclusion in the block with the given height, - /// using default values for general transaction fields. + /// using default values for general transaction fields and the default OS random. /// /// # Default values /// @@ -198,12 +198,27 @@ impl Builder { /// expiry delta (20 blocks). /// /// The fee will be set to the default fee (0.0001 ZEC). - pub fn new(height: u32) -> Builder { + pub fn new(height: u32) -> Self { + Builder::new_with_rng(height, OsRng) + } +} + +impl Builder { + /// Creates a new `Builder` targeted for inclusion in the block with the given height + /// and randomness source, using default values for general transaction fields. + /// + /// # Default values + /// + /// The expiry height will be set to the given height plus the default transaction + /// expiry delta (20 blocks). + /// + /// The fee will be set to the default fee (0.0001 ZEC). + pub fn new_with_rng(height: u32, rng: R) -> Builder { let mut mtx = TransactionData::new(); mtx.expiry_height = height + DEFAULT_TX_EXPIRY_DELTA; Builder { - rng: OsRng, + rng, mtx, fee: DEFAULT_FEE, anchor: None, From 17f6bbcc67d6d82704d14fc58069b71db77ff0ad Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 12 Jun 2019 23:12:55 +0100 Subject: [PATCH 048/330] Pass tx builder RNG to spend_sig() --- librustzcash/src/rustzcash.rs | 5 ++++- zcash_primitives/src/sapling.rs | 10 ++++------ zcash_primitives/src/transaction/builder.rs | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 1db70ac..4f27fa1 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -1002,8 +1002,11 @@ pub extern "system" fn librustzcash_sapling_spend_sig( Err(_) => return false, }; + // Initialize secure RNG + let mut rng = OsRng; + // Do the signing - let sig = spend_sig(ask, ar, unsafe { &*sighash }, &JUBJUB); + let sig = spend_sig(ask, ar, unsafe { &*sighash }, &mut rng, &JUBJUB); // Write out the signature sig.write(&mut (unsafe { &mut *result })[..]) diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index ad7e309..bd981e6 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -2,7 +2,7 @@ use ff::{BitIterator, PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; -use rand_os::OsRng; +use rand_core::{CryptoRng, RngCore}; use sapling_crypto::{ jubjub::{fs::Fs, FixedGenerators, JubjubBls12}, pedersen_hash::{pedersen_hash, Personalization}, @@ -106,15 +106,13 @@ lazy_static! { } /// Create the spendAuthSig for a Sapling SpendDescription. -pub fn spend_sig( +pub fn spend_sig( ask: PrivateKey, ar: Fs, sighash: &[u8; 32], + rng: &mut R, params: &JubjubBls12, ) -> Signature { - // Initialize secure RNG - let mut rng = OsRng; - // We compute `rsk`... let rsk = ask.randomize(ar); @@ -130,7 +128,7 @@ pub fn spend_sig( // Do the signing rsk.sign( &data_to_be_signed, - &mut rng, + rng, FixedGenerators::SpendingKeyGenerator, params, ) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 4edcd20..5c0e643 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -522,6 +522,7 @@ impl Builder { PrivateKey(spend.extsk.expsk.ask), spend.alpha, &sighash, + &mut self.rng, &JUBJUB, )); } From fa50d551c8c7d969157d4b3d42e9cbda85548051 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 25 Jul 2019 18:30:56 +0100 Subject: [PATCH 049/330] Move Amount impl into a submodule --- .../src/transaction/components.rs | 90 +------------------ .../src/transaction/components/amount.rs | 89 ++++++++++++++++++ 2 files changed, 92 insertions(+), 87 deletions(-) create mode 100644 zcash_primitives/src/transaction/components/amount.rs diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index f04c5aa..f72dfc5 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -10,6 +10,9 @@ use std::io::{self, Read, Write}; use legacy::Script; use JUBJUB; +mod amount; +pub use self::amount::Amount; + // π_A + π_B + π_C pub const GROTH_PROOF_SIZE: usize = (48 + 96 + 48); // π_A + π_A' + π_B + π_B' + π_C + π_C' + π_K + π_H @@ -18,46 +21,6 @@ const PHGR_PROOF_SIZE: usize = (33 + 33 + 65 + 33 + 33 + 33 + 33 + 33); const ZC_NUM_JS_INPUTS: usize = 2; const ZC_NUM_JS_OUTPUTS: usize = 2; -const COIN: i64 = 1_0000_0000; -const MAX_MONEY: i64 = 21_000_000 * COIN; - -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Amount(pub i64); - -impl Amount { - // Read an Amount from a signed 64-bit little-endian integer. - pub fn read_i64(mut reader: R, allow_negative: bool) -> io::Result { - let amount = reader.read_i64::()?; - if 0 <= amount && amount <= MAX_MONEY { - Ok(Amount(amount)) - } else if allow_negative && -MAX_MONEY <= amount && amount < 0 { - Ok(Amount(amount)) - } else { - Err(io::Error::new( - io::ErrorKind::InvalidData, - if allow_negative { - "Amount not in {-MAX_MONEY..MAX_MONEY}" - } else { - "Amount not in {0..MAX_MONEY}" - }, - )) - } - } - - // Read an Amount from an unsigned 64-bit little-endian integer. - pub fn read_u64(mut reader: R) -> io::Result { - let amount = reader.read_u64::()?; - if amount <= MAX_MONEY as u64 { - Ok(Amount(amount as i64)) - } else { - Err(io::Error::new( - io::ErrorKind::InvalidData, - "Amount not in {0..MAX_MONEY}", - )) - } - } -} - #[derive(Debug)] pub struct OutPoint { hash: [u8; 32], @@ -432,50 +395,3 @@ impl JSDescription { writer.write_all(&self.ciphertexts[1]) } } - -#[cfg(test)] -mod tests { - use super::{Amount, MAX_MONEY}; - - #[test] - fn amount_in_range() { - let zero = b"\x00\x00\x00\x00\x00\x00\x00\x00"; - assert_eq!(Amount::read_u64(&zero[..]).unwrap(), Amount(0)); - assert_eq!(Amount::read_i64(&zero[..], false).unwrap(), Amount(0)); - assert_eq!(Amount::read_i64(&zero[..], true).unwrap(), Amount(0)); - - let neg_one = b"\xff\xff\xff\xff\xff\xff\xff\xff"; - assert!(Amount::read_u64(&neg_one[..]).is_err()); - assert!(Amount::read_i64(&neg_one[..], false).is_err()); - assert_eq!(Amount::read_i64(&neg_one[..], true).unwrap(), Amount(-1)); - - let max_money = b"\x00\x40\x07\x5a\xf0\x75\x07\x00"; - assert_eq!(Amount::read_u64(&max_money[..]).unwrap(), Amount(MAX_MONEY)); - assert_eq!( - Amount::read_i64(&max_money[..], false).unwrap(), - Amount(MAX_MONEY) - ); - assert_eq!( - Amount::read_i64(&max_money[..], true).unwrap(), - Amount(MAX_MONEY) - ); - - let max_money_p1 = b"\x01\x40\x07\x5a\xf0\x75\x07\x00"; - assert!(Amount::read_u64(&max_money_p1[..]).is_err()); - assert!(Amount::read_i64(&max_money_p1[..], false).is_err()); - assert!(Amount::read_i64(&max_money_p1[..], true).is_err()); - - let neg_max_money = b"\x00\xc0\xf8\xa5\x0f\x8a\xf8\xff"; - assert!(Amount::read_u64(&neg_max_money[..]).is_err()); - assert!(Amount::read_i64(&neg_max_money[..], false).is_err()); - assert_eq!( - Amount::read_i64(&neg_max_money[..], true).unwrap(), - Amount(-MAX_MONEY) - ); - - let neg_max_money_m1 = b"\xff\xbf\xf8\xa5\x0f\x8a\xf8\xff"; - assert!(Amount::read_u64(&neg_max_money_m1[..]).is_err()); - assert!(Amount::read_i64(&neg_max_money_m1[..], false).is_err()); - assert!(Amount::read_i64(&neg_max_money_m1[..], true).is_err()); - } -} diff --git a/zcash_primitives/src/transaction/components/amount.rs b/zcash_primitives/src/transaction/components/amount.rs new file mode 100644 index 0000000..593e98c --- /dev/null +++ b/zcash_primitives/src/transaction/components/amount.rs @@ -0,0 +1,89 @@ +use byteorder::{LittleEndian, ReadBytesExt}; +use std::io::{self, Read}; + +const COIN: i64 = 1_0000_0000; +const MAX_MONEY: i64 = 21_000_000 * COIN; + +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Amount(pub i64); + +impl Amount { + // Read an Amount from a signed 64-bit little-endian integer. + pub fn read_i64(mut reader: R, allow_negative: bool) -> io::Result { + let amount = reader.read_i64::()?; + if 0 <= amount && amount <= MAX_MONEY { + Ok(Amount(amount)) + } else if allow_negative && -MAX_MONEY <= amount && amount < 0 { + Ok(Amount(amount)) + } else { + Err(io::Error::new( + io::ErrorKind::InvalidData, + if allow_negative { + "Amount not in {-MAX_MONEY..MAX_MONEY}" + } else { + "Amount not in {0..MAX_MONEY}" + }, + )) + } + } + + // Read an Amount from an unsigned 64-bit little-endian integer. + pub fn read_u64(mut reader: R) -> io::Result { + let amount = reader.read_u64::()?; + if amount <= MAX_MONEY as u64 { + Ok(Amount(amount as i64)) + } else { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "Amount not in {0..MAX_MONEY}", + )) + } + } +} + +#[cfg(test)] +mod tests { + use super::{Amount, MAX_MONEY}; + + #[test] + fn amount_in_range() { + let zero = b"\x00\x00\x00\x00\x00\x00\x00\x00"; + assert_eq!(Amount::read_u64(&zero[..]).unwrap(), Amount(0)); + assert_eq!(Amount::read_i64(&zero[..], false).unwrap(), Amount(0)); + assert_eq!(Amount::read_i64(&zero[..], true).unwrap(), Amount(0)); + + let neg_one = b"\xff\xff\xff\xff\xff\xff\xff\xff"; + assert!(Amount::read_u64(&neg_one[..]).is_err()); + assert!(Amount::read_i64(&neg_one[..], false).is_err()); + assert_eq!(Amount::read_i64(&neg_one[..], true).unwrap(), Amount(-1)); + + let max_money = b"\x00\x40\x07\x5a\xf0\x75\x07\x00"; + assert_eq!(Amount::read_u64(&max_money[..]).unwrap(), Amount(MAX_MONEY)); + assert_eq!( + Amount::read_i64(&max_money[..], false).unwrap(), + Amount(MAX_MONEY) + ); + assert_eq!( + Amount::read_i64(&max_money[..], true).unwrap(), + Amount(MAX_MONEY) + ); + + let max_money_p1 = b"\x01\x40\x07\x5a\xf0\x75\x07\x00"; + assert!(Amount::read_u64(&max_money_p1[..]).is_err()); + assert!(Amount::read_i64(&max_money_p1[..], false).is_err()); + assert!(Amount::read_i64(&max_money_p1[..], true).is_err()); + + let neg_max_money = b"\x00\xc0\xf8\xa5\x0f\x8a\xf8\xff"; + assert!(Amount::read_u64(&neg_max_money[..]).is_err()); + assert!(Amount::read_i64(&neg_max_money[..], false).is_err()); + assert_eq!( + Amount::read_i64(&neg_max_money[..], true).unwrap(), + Amount(-MAX_MONEY) + ); + + let neg_max_money_m1 = b"\xff\xbf\xf8\xa5\x0f\x8a\xf8\xff"; + assert!(Amount::read_u64(&neg_max_money_m1[..]).is_err()); + assert!(Amount::read_i64(&neg_max_money_m1[..], false).is_err()); + assert!(Amount::read_i64(&neg_max_money_m1[..], true).is_err()); + } +} From 0ea4408d46e7e54c7d42854e87a0595b1a338c27 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 25 Jul 2019 20:50:17 +0100 Subject: [PATCH 050/330] Amount::{zero, is_positive, is_negative} --- zcash_primitives/src/transaction/builder.rs | 4 ++-- .../src/transaction/components/amount.rs | 17 +++++++++++++++++ zcash_primitives/src/transaction/mod.rs | 4 ++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 5c0e643..a2ea4af 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -79,7 +79,7 @@ impl SaplingOutput { Some(g_d) => g_d, None => return Err(Error(ErrorKind::InvalidAddress)), }; - if value.0 < 0 { + if value.is_negative() { return Err(Error(ErrorKind::InvalidAmount)); } @@ -288,7 +288,7 @@ impl Builder { to: &TransparentAddress, value: Amount, ) -> Result<(), Error> { - if value.0 < 0 { + if value.is_negative() { return Err(Error(ErrorKind::InvalidAmount)); } diff --git a/zcash_primitives/src/transaction/components/amount.rs b/zcash_primitives/src/transaction/components/amount.rs index 593e98c..eedfe2a 100644 --- a/zcash_primitives/src/transaction/components/amount.rs +++ b/zcash_primitives/src/transaction/components/amount.rs @@ -8,6 +8,11 @@ const MAX_MONEY: i64 = 21_000_000 * COIN; pub struct Amount(pub i64); impl Amount { + /// Returns a zero-valued Amount. + pub const fn zero() -> Self { + Amount(0) + } + // Read an Amount from a signed 64-bit little-endian integer. pub fn read_i64(mut reader: R, allow_negative: bool) -> io::Result { let amount = reader.read_i64::()?; @@ -39,6 +44,18 @@ impl Amount { )) } } + + /// Returns `true` if `self` is positive and `false` if the number is zero or + /// negative. + pub const fn is_positive(self) -> bool { + self.0.is_positive() + } + + /// Returns `true` if `self` is negative and `false` if the number is zero or + /// positive. + pub const fn is_negative(self) -> bool { + self.0.is_negative() + } } #[cfg(test)] diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index 19f4396..d8024eb 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -112,7 +112,7 @@ impl TransactionData { vout: vec![], lock_time: 0, expiry_height: 0, - value_balance: Amount(0), + value_balance: Amount::zero(), shielded_spends: vec![], shielded_outputs: vec![], joinsplits: vec![], @@ -190,7 +190,7 @@ impl Transaction { let so = Vector::read(&mut reader, OutputDescription::read)?; (vb, ss, so) } else { - (Amount(0), vec![], vec![]) + (Amount::zero(), vec![], vec![]) }; let (joinsplits, joinsplit_pubkey, joinsplit_sig) = if version >= 2 { From ab60b8804ae9d6900e51c61a93ce45309b19d822 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 25 Jul 2019 20:53:42 +0100 Subject: [PATCH 051/330] impl operators for Amount --- zcash_primitives/src/transaction/builder.rs | 24 ++++++------- .../src/transaction/components/amount.rs | 36 +++++++++++++++++++ 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index a2ea4af..b7bcb62 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -44,7 +44,7 @@ impl Error { pub enum ErrorKind { AnchorMismatch, BindingSig, - ChangeIsNegative(i64), + ChangeIsNegative(Amount), InvalidAddress, InvalidAmount, InvalidWitness, @@ -252,7 +252,7 @@ impl Builder { let alpha = Fs::random(&mut self.rng); - self.mtx.value_balance.0 += note.value as i64; + self.mtx.value_balance += Amount(note.value as i64); self.spends.push(SpendDescriptionInfo { extsk, @@ -275,7 +275,7 @@ impl Builder { ) -> Result<(), Error> { let output = SaplingOutput::new(&mut self.rng, ovk, to, value, memo)?; - self.mtx.value_balance.0 -= value.0; + self.mtx.value_balance -= value; self.outputs.push(output); @@ -329,14 +329,14 @@ impl Builder { // // Valid change - let change = self.mtx.value_balance.0 - - self.fee.0 + let change = self.mtx.value_balance + - self.fee - self .mtx .vout .iter() - .map(|output| output.value.0) - .sum::(); + .map(|output| output.value) + .sum::(); if change.is_negative() { return Err(Error(ErrorKind::ChangeIsNegative(change))); } @@ -362,7 +362,7 @@ impl Builder { return Err(Error(ErrorKind::NoChangeAddress)); }; - self.add_sapling_output(change_address.0, change_address.1, Amount(change), None)?; + self.add_sapling_output(change_address.0, change_address.1, change, None)?; } // @@ -591,7 +591,7 @@ mod tests { { let builder = Builder::new(0); match builder.build(1, MockTxProver) { - Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(-10000)), + Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(Amount(-10000))), Ok(_) => panic!("Should have failed"), } } @@ -608,7 +608,7 @@ mod tests { .add_sapling_output(ovk.clone(), to.clone(), Amount(50000), None) .unwrap(); match builder.build(1, MockTxProver) { - Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(-60000)), + Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(Amount(-60000))), Ok(_) => panic!("Should have failed"), } } @@ -621,7 +621,7 @@ mod tests { .add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount(50000)) .unwrap(); match builder.build(1, MockTxProver) { - Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(-60000)), + Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(Amount(-60000))), Ok(_) => panic!("Should have failed"), } } @@ -653,7 +653,7 @@ mod tests { .add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount(20000)) .unwrap(); match builder.build(1, MockTxProver) { - Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(-1)), + Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(Amount(-1))), Ok(_) => panic!("Should have failed"), } } diff --git a/zcash_primitives/src/transaction/components/amount.rs b/zcash_primitives/src/transaction/components/amount.rs index eedfe2a..fa9ee06 100644 --- a/zcash_primitives/src/transaction/components/amount.rs +++ b/zcash_primitives/src/transaction/components/amount.rs @@ -1,5 +1,7 @@ use byteorder::{LittleEndian, ReadBytesExt}; use std::io::{self, Read}; +use std::iter::Sum; +use std::ops::{Add, AddAssign, Sub, SubAssign}; const COIN: i64 = 1_0000_0000; const MAX_MONEY: i64 = 21_000_000 * COIN; @@ -58,6 +60,40 @@ impl Amount { } } +impl Add for Amount { + type Output = Amount; + + fn add(self, rhs: Amount) -> Amount { + Amount(self.0 + rhs.0) + } +} + +impl AddAssign for Amount { + fn add_assign(&mut self, rhs: Amount) { + *self = *self + rhs + } +} + +impl Sub for Amount { + type Output = Amount; + + fn sub(self, rhs: Amount) -> Amount { + Amount(self.0 - rhs.0) + } +} + +impl SubAssign for Amount { + fn sub_assign(&mut self, rhs: Amount) { + *self = *self - rhs + } +} + +impl Sum for Amount { + fn sum>(iter: I) -> Amount { + iter.fold(Amount::zero(), Add::add) + } +} + #[cfg(test)] mod tests { use super::{Amount, MAX_MONEY}; From 59ed258c7f673031cb22524004d72d54991cb38e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 25 Jul 2019 22:37:16 +0100 Subject: [PATCH 052/330] Make Amount opaque, and use it more This helps to ensure type-safety of values that are required to satisfy zatoshi range bounds. --- librustzcash/src/rustzcash.rs | 11 ++ zcash_primitives/src/prover.rs | 14 ++- zcash_primitives/src/transaction/builder.rs | 68 ++++++++--- .../src/transaction/components.rs | 29 +++-- .../src/transaction/components/amount.rs | 115 ++++++++++++------ zcash_primitives/src/transaction/mod.rs | 9 +- zcash_primitives/src/transaction/sighash.rs | 11 +- zcash_primitives/src/transaction/tests.rs | 12 +- zcash_proofs/src/prover.rs | 9 +- zcash_proofs/src/sapling/mod.rs | 5 +- zcash_proofs/src/sapling/prover.rs | 6 +- zcash_proofs/src/sapling/verifier.rs | 3 +- 12 files changed, 203 insertions(+), 89 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 4f27fa1..0fad706 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -63,6 +63,7 @@ use zcash_primitives::{ merkle_tree::CommitmentTreeWitness, note_encryption::sapling_ka_agree, sapling::{merkle_hash, spend_sig}, + transaction::components::Amount, zip32, JUBJUB, }; use zcash_proofs::{ @@ -704,6 +705,11 @@ pub extern "system" fn librustzcash_sapling_final_check( binding_sig: *const [c_uchar; 64], sighash_value: *const [c_uchar; 32], ) -> bool { + let value_balance = match Amount::from_i64(value_balance, true) { + Ok(vb) => vb, + Err(()) => return false, + }; + // Deserialize the signature let binding_sig = match Signature::read(&(unsafe { &*binding_sig })[..]) { Ok(sig) => sig, @@ -1022,6 +1028,11 @@ pub extern "system" fn librustzcash_sapling_binding_sig( sighash: *const [c_uchar; 32], result: *mut [c_uchar; 64], ) -> bool { + let value_balance = match Amount::from_i64(value_balance, true) { + Ok(vb) => vb, + Err(()) => return false, + }; + // Sign let sig = match unsafe { &*ctx }.binding_sig(value_balance, unsafe { &*sighash }, &JUBJUB) { Ok(s) => s, diff --git a/zcash_primitives/src/prover.rs b/zcash_primitives/src/prover.rs index 87a76c7..1d40965 100644 --- a/zcash_primitives/src/prover.rs +++ b/zcash_primitives/src/prover.rs @@ -8,7 +8,9 @@ use sapling_crypto::{ }; use crate::{ - merkle_tree::CommitmentTreeWitness, sapling::Node, transaction::components::GROTH_PROOF_SIZE, + merkle_tree::CommitmentTreeWitness, + sapling::Node, + transaction::components::{Amount, GROTH_PROOF_SIZE}, }; /// Interface for creating zero-knowledge proofs for shielded transactions. @@ -63,7 +65,7 @@ pub trait TxProver { fn binding_sig( &self, ctx: &mut Self::SaplingProvingContext, - value_balance: i64, + value_balance: Amount, sighash: &[u8; 32], ) -> Result; } @@ -80,8 +82,10 @@ pub(crate) mod mock { }; use crate::{ - merkle_tree::CommitmentTreeWitness, sapling::Node, - transaction::components::GROTH_PROOF_SIZE, JUBJUB, + merkle_tree::CommitmentTreeWitness, + sapling::Node, + transaction::components::{Amount, GROTH_PROOF_SIZE}, + JUBJUB, }; use super::TxProver; @@ -153,7 +157,7 @@ pub(crate) mod mock { fn binding_sig( &self, _ctx: &mut Self::SaplingProvingContext, - _value_balance: i64, + _value_balance: Amount, _sighash: &[u8; 32], ) -> Result { Err(()) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index b7bcb62..36490e4 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -18,13 +18,12 @@ use crate::{ prover::TxProver, sapling::{spend_sig, Node}, transaction::{ - components::{Amount, OutputDescription, SpendDescription, TxOut}, + components::{amount::DEFAULT_FEE, Amount, OutputDescription, SpendDescription, TxOut}, signature_hash_data, Transaction, TransactionData, SIGHASH_ALL, }, JUBJUB, }; -const DEFAULT_FEE: Amount = Amount(10000); const DEFAULT_TX_EXPIRY_DELTA: u32 = 20; /// If there are any shielded inputs, always have at least two shielded outputs, padding @@ -88,7 +87,7 @@ impl SaplingOutput { let note = Note { g_d, pk_d: to.pk_d.clone(), - value: value.0 as u64, + value: value.into(), r: rcm, }; @@ -252,7 +251,8 @@ impl Builder { let alpha = Fs::random(&mut self.rng); - self.mtx.value_balance += Amount(note.value as i64); + self.mtx.value_balance += + Amount::from_u64(note.value).map_err(|_| Error(ErrorKind::InvalidAmount))?; self.spends.push(SpendDescriptionInfo { extsk, @@ -528,7 +528,7 @@ impl Builder { } self.mtx.binding_sig = Some( prover - .binding_sig(&mut ctx, self.mtx.value_balance.0, &sighash) + .binding_sig(&mut ctx, self.mtx.value_balance, &sighash) .map_err(|()| Error(ErrorKind::BindingSig))?, ); @@ -564,7 +564,7 @@ mod tests { let to = extfvk.default_address().unwrap().1; let mut builder = Builder::new(0); - match builder.add_sapling_output(ovk, to, Amount(-1), None) { + match builder.add_sapling_output(ovk, to, Amount::from_i64(-1, true).unwrap(), None) { Err(e) => assert_eq!(e.kind(), &ErrorKind::InvalidAmount), Ok(_) => panic!("Should have failed"), } @@ -573,7 +573,10 @@ mod tests { #[test] fn fails_on_negative_transparent_output() { let mut builder = Builder::new(0); - match builder.add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount(-1)) { + match builder.add_transparent_output( + &TransparentAddress::PublicKey([0; 20]), + Amount::from_i64(-1, true).unwrap(), + ) { Err(e) => assert_eq!(e.kind(), &ErrorKind::InvalidAmount), Ok(_) => panic!("Should have failed"), } @@ -591,7 +594,10 @@ mod tests { { let builder = Builder::new(0); match builder.build(1, MockTxProver) { - Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(Amount(-10000))), + Err(e) => assert_eq!( + e.kind(), + &ErrorKind::ChangeIsNegative(Amount::from_i64(-10000, true).unwrap()) + ), Ok(_) => panic!("Should have failed"), } } @@ -605,10 +611,18 @@ mod tests { { let mut builder = Builder::new(0); builder - .add_sapling_output(ovk.clone(), to.clone(), Amount(50000), None) + .add_sapling_output( + ovk.clone(), + to.clone(), + Amount::from_u64(50000).unwrap(), + None, + ) .unwrap(); match builder.build(1, MockTxProver) { - Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(Amount(-60000))), + Err(e) => assert_eq!( + e.kind(), + &ErrorKind::ChangeIsNegative(Amount::from_i64(-60000, true).unwrap()) + ), Ok(_) => panic!("Should have failed"), } } @@ -618,10 +632,16 @@ mod tests { { let mut builder = Builder::new(0); builder - .add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount(50000)) + .add_transparent_output( + &TransparentAddress::PublicKey([0; 20]), + Amount::from_u64(50000).unwrap(), + ) .unwrap(); match builder.build(1, MockTxProver) { - Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(Amount(-60000))), + Err(e) => assert_eq!( + e.kind(), + &ErrorKind::ChangeIsNegative(Amount::from_i64(-60000, true).unwrap()) + ), Ok(_) => panic!("Should have failed"), } } @@ -647,13 +667,24 @@ mod tests { ) .unwrap(); builder - .add_sapling_output(ovk.clone(), to.clone(), Amount(30000), None) + .add_sapling_output( + ovk.clone(), + to.clone(), + Amount::from_u64(30000).unwrap(), + None, + ) .unwrap(); builder - .add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount(20000)) + .add_transparent_output( + &TransparentAddress::PublicKey([0; 20]), + Amount::from_u64(20000).unwrap(), + ) .unwrap(); match builder.build(1, MockTxProver) { - Err(e) => assert_eq!(e.kind(), &ErrorKind::ChangeIsNegative(Amount(-1))), + Err(e) => assert_eq!( + e.kind(), + &ErrorKind::ChangeIsNegative(Amount::from_i64(-1, true).unwrap()) + ), Ok(_) => panic!("Should have failed"), } } @@ -678,10 +709,13 @@ mod tests { .add_sapling_spend(extsk, to.diversifier, note2, witness2) .unwrap(); builder - .add_sapling_output(ovk, to, Amount(30000), None) + .add_sapling_output(ovk, to, Amount::from_u64(30000).unwrap(), None) .unwrap(); builder - .add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount(20000)) + .add_transparent_output( + &TransparentAddress::PublicKey([0; 20]), + Amount::from_u64(20000).unwrap(), + ) .unwrap(); match builder.build(1, MockTxProver) { Err(e) => assert_eq!(e.kind(), &ErrorKind::BindingSig), diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index f72dfc5..c7dcebd 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -10,7 +10,7 @@ use std::io::{self, Read, Write}; use legacy::Script; use JUBJUB; -mod amount; +pub mod amount; pub use self::amount::Amount; // π_A + π_B + π_C @@ -76,7 +76,12 @@ pub struct TxOut { impl TxOut { pub fn read(mut reader: &mut R) -> io::Result { - let value = Amount::read_i64(&mut reader, false)?; + let value = { + let mut tmp = [0; 8]; + reader.read_exact(&mut tmp)?; + Amount::from_i64_le_bytes(tmp, false) + } + .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "value out of range"))?; let script_pubkey = Script::read(&mut reader)?; Ok(TxOut { @@ -86,7 +91,7 @@ impl TxOut { } pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_i64::(self.value.0)?; + writer.write_all(&self.value.to_i64_le_bytes())?; self.script_pubkey.write(&mut writer) } } @@ -298,10 +303,20 @@ impl std::fmt::Debug for JSDescription { impl JSDescription { pub fn read(mut reader: R, use_groth: bool) -> io::Result { // Consensus rule (§4.3): Canonical encoding is enforced here - let vpub_old = Amount::read_u64(&mut reader)?; + let vpub_old = { + let mut tmp = [0; 8]; + reader.read_exact(&mut tmp)?; + Amount::from_u64_le_bytes(tmp) + } + .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "vpub_old out of range"))?; // Consensus rule (§4.3): Canonical encoding is enforced here - let vpub_new = Amount::read_u64(&mut reader)?; + let vpub_new = { + let mut tmp = [0; 8]; + reader.read_exact(&mut tmp)?; + Amount::from_u64_le_bytes(tmp) + } + .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "vpub_new out of range"))?; // Consensus rule (§4.3): One of vpub_old and vpub_new being zero is // enforced by CheckTransactionWithoutProofVerification() in zcashd. @@ -374,8 +389,8 @@ impl JSDescription { } pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_i64::(self.vpub_old.0)?; - writer.write_i64::(self.vpub_new.0)?; + writer.write_all(&self.vpub_old.to_i64_le_bytes())?; + writer.write_all(&self.vpub_new.to_i64_le_bytes())?; writer.write_all(&self.anchor)?; writer.write_all(&self.nullifiers[0])?; writer.write_all(&self.nullifiers[1])?; diff --git a/zcash_primitives/src/transaction/components/amount.rs b/zcash_primitives/src/transaction/components/amount.rs index fa9ee06..dca7056 100644 --- a/zcash_primitives/src/transaction/components/amount.rs +++ b/zcash_primitives/src/transaction/components/amount.rs @@ -1,13 +1,13 @@ -use byteorder::{LittleEndian, ReadBytesExt}; -use std::io::{self, Read}; use std::iter::Sum; use std::ops::{Add, AddAssign, Sub, SubAssign}; const COIN: i64 = 1_0000_0000; const MAX_MONEY: i64 = 21_000_000 * COIN; +pub const DEFAULT_FEE: Amount = Amount(10000); + #[derive(Clone, Copy, Debug, PartialEq)] -pub struct Amount(pub i64); +pub struct Amount(i64); impl Amount { /// Returns a zero-valued Amount. @@ -15,38 +15,51 @@ impl Amount { Amount(0) } - // Read an Amount from a signed 64-bit little-endian integer. - pub fn read_i64(mut reader: R, allow_negative: bool) -> io::Result { - let amount = reader.read_i64::()?; + /// Creates an Amount from an i64. + /// + /// Returns an error if the amount is out of range. + pub fn from_i64(amount: i64, allow_negative: bool) -> Result { if 0 <= amount && amount <= MAX_MONEY { Ok(Amount(amount)) } else if allow_negative && -MAX_MONEY <= amount && amount < 0 { Ok(Amount(amount)) } else { - Err(io::Error::new( - io::ErrorKind::InvalidData, - if allow_negative { - "Amount not in {-MAX_MONEY..MAX_MONEY}" - } else { - "Amount not in {0..MAX_MONEY}" - }, - )) + Err(()) } } - // Read an Amount from an unsigned 64-bit little-endian integer. - pub fn read_u64(mut reader: R) -> io::Result { - let amount = reader.read_u64::()?; + /// Creates an Amount from a u64. + /// + /// Returns an error if the amount is out of range. + pub fn from_u64(amount: u64) -> Result { if amount <= MAX_MONEY as u64 { Ok(Amount(amount as i64)) } else { - Err(io::Error::new( - io::ErrorKind::InvalidData, - "Amount not in {0..MAX_MONEY}", - )) + Err(()) } } + /// Reads an Amount from a signed 64-bit little-endian integer. + /// + /// Returns an error if the amount is out of range. + pub fn from_i64_le_bytes(bytes: [u8; 8], allow_negative: bool) -> Result { + let amount = i64::from_le_bytes(bytes); + Amount::from_i64(amount, allow_negative) + } + + /// Reads an Amount from an unsigned 64-bit little-endian integer. + /// + /// Returns an error if the amount is out of range. + pub fn from_u64_le_bytes(bytes: [u8; 8]) -> Result { + let amount = u64::from_le_bytes(bytes); + Amount::from_u64(amount) + } + + /// Returns the Amount encoded as a signed 64-bit little-endian integer. + pub fn to_i64_le_bytes(self) -> [u8; 8] { + self.0.to_le_bytes() + } + /// Returns `true` if `self` is positive and `false` if the number is zero or /// negative. pub const fn is_positive(self) -> bool { @@ -60,6 +73,18 @@ impl Amount { } } +impl From for i64 { + fn from(amount: Amount) -> i64 { + amount.0 + } +} + +impl From for u64 { + fn from(amount: Amount) -> u64 { + amount.0 as u64 + } +} + impl Add for Amount { type Output = Amount; @@ -101,42 +126,54 @@ mod tests { #[test] fn amount_in_range() { let zero = b"\x00\x00\x00\x00\x00\x00\x00\x00"; - assert_eq!(Amount::read_u64(&zero[..]).unwrap(), Amount(0)); - assert_eq!(Amount::read_i64(&zero[..], false).unwrap(), Amount(0)); - assert_eq!(Amount::read_i64(&zero[..], true).unwrap(), Amount(0)); + assert_eq!(Amount::from_u64_le_bytes(zero.clone()).unwrap(), Amount(0)); + assert_eq!( + Amount::from_i64_le_bytes(zero.clone(), false).unwrap(), + Amount(0) + ); + assert_eq!( + Amount::from_i64_le_bytes(zero.clone(), true).unwrap(), + Amount(0) + ); let neg_one = b"\xff\xff\xff\xff\xff\xff\xff\xff"; - assert!(Amount::read_u64(&neg_one[..]).is_err()); - assert!(Amount::read_i64(&neg_one[..], false).is_err()); - assert_eq!(Amount::read_i64(&neg_one[..], true).unwrap(), Amount(-1)); + assert!(Amount::from_u64_le_bytes(neg_one.clone()).is_err()); + assert!(Amount::from_i64_le_bytes(neg_one.clone(), false).is_err()); + assert_eq!( + Amount::from_i64_le_bytes(neg_one.clone(), true).unwrap(), + Amount(-1) + ); let max_money = b"\x00\x40\x07\x5a\xf0\x75\x07\x00"; - assert_eq!(Amount::read_u64(&max_money[..]).unwrap(), Amount(MAX_MONEY)); assert_eq!( - Amount::read_i64(&max_money[..], false).unwrap(), + Amount::from_u64_le_bytes(max_money.clone()).unwrap(), Amount(MAX_MONEY) ); assert_eq!( - Amount::read_i64(&max_money[..], true).unwrap(), + Amount::from_i64_le_bytes(max_money.clone(), false).unwrap(), + Amount(MAX_MONEY) + ); + assert_eq!( + Amount::from_i64_le_bytes(max_money.clone(), true).unwrap(), Amount(MAX_MONEY) ); let max_money_p1 = b"\x01\x40\x07\x5a\xf0\x75\x07\x00"; - assert!(Amount::read_u64(&max_money_p1[..]).is_err()); - assert!(Amount::read_i64(&max_money_p1[..], false).is_err()); - assert!(Amount::read_i64(&max_money_p1[..], true).is_err()); + assert!(Amount::from_u64_le_bytes(max_money_p1.clone()).is_err()); + assert!(Amount::from_i64_le_bytes(max_money_p1.clone(), false).is_err()); + assert!(Amount::from_i64_le_bytes(max_money_p1.clone(), true).is_err()); let neg_max_money = b"\x00\xc0\xf8\xa5\x0f\x8a\xf8\xff"; - assert!(Amount::read_u64(&neg_max_money[..]).is_err()); - assert!(Amount::read_i64(&neg_max_money[..], false).is_err()); + assert!(Amount::from_u64_le_bytes(neg_max_money.clone()).is_err()); + assert!(Amount::from_i64_le_bytes(neg_max_money.clone(), false).is_err()); assert_eq!( - Amount::read_i64(&neg_max_money[..], true).unwrap(), + Amount::from_i64_le_bytes(neg_max_money.clone(), true).unwrap(), Amount(-MAX_MONEY) ); let neg_max_money_m1 = b"\xff\xbf\xf8\xa5\x0f\x8a\xf8\xff"; - assert!(Amount::read_u64(&neg_max_money_m1[..]).is_err()); - assert!(Amount::read_i64(&neg_max_money_m1[..], false).is_err()); - assert!(Amount::read_i64(&neg_max_money_m1[..], true).is_err()); + assert!(Amount::from_u64_le_bytes(neg_max_money_m1.clone()).is_err()); + assert!(Amount::from_i64_le_bytes(neg_max_money_m1.clone(), false).is_err()); + assert!(Amount::from_i64_le_bytes(neg_max_money_m1.clone(), true).is_err()); } } diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index d8024eb..e5b83e5 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -185,7 +185,12 @@ impl Transaction { }; let (value_balance, shielded_spends, shielded_outputs) = if is_sapling_v4 { - let vb = Amount::read_i64(&mut reader, true)?; + let vb = { + let mut tmp = [0; 8]; + reader.read_exact(&mut tmp)?; + Amount::from_i64_le_bytes(tmp, true) + } + .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "valueBalance out of range"))?; let ss = Vector::read(&mut reader, SpendDescription::read)?; let so = Vector::read(&mut reader, OutputDescription::read)?; (vb, ss, so) @@ -262,7 +267,7 @@ impl Transaction { } if is_sapling_v4 { - writer.write_i64::(self.value_balance.0)?; + writer.write_all(&self.value_balance.to_i64_le_bytes())?; Vector::write(&mut writer, &self.shielded_spends, |w, e| e.write(w))?; Vector::write(&mut writer, &self.shielded_outputs, |w, e| e.write(w))?; } diff --git a/zcash_primitives/src/transaction/sighash.rs b/zcash_primitives/src/transaction/sighash.rs index bcc971a..b4e9a69 100644 --- a/zcash_primitives/src/transaction/sighash.rs +++ b/zcash_primitives/src/transaction/sighash.rs @@ -30,13 +30,6 @@ macro_rules! update_u32 { }; } -macro_rules! update_i64 { - ($h:expr, $value:expr, $tmp:expr) => { - (&mut $tmp[..8]).write_i64::($value).unwrap(); - $h.update(&$tmp[..8]); - }; -} - macro_rules! update_hash { ($h:expr, $cond:expr, $value:expr) => { if $cond { @@ -214,7 +207,7 @@ pub fn signature_hash_data( update_u32!(h, tx.lock_time, tmp); update_u32!(h, tx.expiry_height, tmp); if sigversion == SigHashVersion::Sapling { - update_i64!(h, tx.value_balance.0, tmp); + h.update(&tx.value_balance.to_i64_le_bytes()); } update_u32!(h, hash_type, tmp); @@ -222,7 +215,7 @@ pub fn signature_hash_data( let mut data = vec![]; tx.vin[n].prevout.write(&mut data).unwrap(); script_code.write(&mut data).unwrap(); - (&mut data).write_i64::(amount.0).unwrap(); + data.extend_from_slice(&amount.to_i64_le_bytes()); (&mut data) .write_u32::(tx.vin[n].sequence) .unwrap(); diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index 1ebac3a..7d84100 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -1902,7 +1902,11 @@ fn zip_0143() { for tv in test_vectors { let tx = Transaction::read(&tv.tx[..]).unwrap(); let transparent_input = if let Some(n) = tv.transparent_input { - Some((n as usize, Script(tv.script_code), Amount(tv.amount))) + Some(( + n as usize, + Script(tv.script_code), + Amount::from_i64(tv.amount, false).unwrap(), + )) } else { None }; @@ -5393,7 +5397,11 @@ fn zip_0243() { for tv in test_vectors { let tx = Transaction::read(&tv.tx[..]).unwrap(); let transparent_input = if let Some(n) = tv.transparent_input { - Some((n as usize, Script(tv.script_code), Amount(tv.amount))) + Some(( + n as usize, + Script(tv.script_code), + Amount::from_i64(tv.amount, false).unwrap(), + )) } else { None }; diff --git a/zcash_proofs/src/prover.rs b/zcash_proofs/src/prover.rs index 005d7eb..4b5b0f4 100644 --- a/zcash_proofs/src/prover.rs +++ b/zcash_proofs/src/prover.rs @@ -10,8 +10,11 @@ use sapling_crypto::{ }; use std::path::Path; use zcash_primitives::{ - merkle_tree::CommitmentTreeWitness, prover::TxProver, sapling::Node, - transaction::components::GROTH_PROOF_SIZE, JUBJUB, + merkle_tree::CommitmentTreeWitness, + prover::TxProver, + sapling::Node, + transaction::components::{Amount, GROTH_PROOF_SIZE}, + JUBJUB, }; use crate::{load_parameters, sapling::SaplingProvingContext}; @@ -182,7 +185,7 @@ impl TxProver for LocalTxProver { fn binding_sig( &self, ctx: &mut Self::SaplingProvingContext, - value_balance: i64, + value_balance: Amount, sighash: &[u8; 32], ) -> Result { ctx.binding_sig(value_balance, sighash, &JUBJUB) diff --git a/zcash_proofs/src/sapling/mod.rs b/zcash_proofs/src/sapling/mod.rs index 4c37306..98c4ba3 100644 --- a/zcash_proofs/src/sapling/mod.rs +++ b/zcash_proofs/src/sapling/mod.rs @@ -2,6 +2,7 @@ use pairing::bls12_381::Bls12; use sapling_crypto::jubjub::{ edwards, fs::FsRepr, FixedGenerators, JubjubBls12, JubjubParams, Unknown, }; +use zcash_primitives::transaction::components::Amount; mod prover; mod verifier; @@ -11,12 +12,12 @@ pub use self::verifier::SaplingVerificationContext; // This function computes `value` in the exponent of the value commitment base fn compute_value_balance( - value: i64, + value: Amount, params: &JubjubBls12, ) -> Option> { // Compute the absolute value (failing if -i64::MAX is // the value) - let abs = match value.checked_abs() { + let abs = match i64::from(value).checked_abs() { Some(a) => a as u64, None => return None, }; diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index fce4d8e..4b5a5f4 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -13,7 +13,9 @@ use sapling_crypto::{ primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, redjubjub::{PrivateKey, PublicKey, Signature}, }; -use zcash_primitives::{merkle_tree::CommitmentTreeWitness, sapling::Node}; +use zcash_primitives::{ + merkle_tree::CommitmentTreeWitness, sapling::Node, transaction::components::Amount, +}; use super::compute_value_balance; @@ -245,7 +247,7 @@ impl SaplingProvingContext { /// and output_proof() must be completed before calling this function. pub fn binding_sig( &self, - value_balance: i64, + value_balance: Amount, sighash: &[u8; 32], params: &JubjubBls12, ) -> Result { diff --git a/zcash_proofs/src/sapling/verifier.rs b/zcash_proofs/src/sapling/verifier.rs index e83c426..47fc9fe 100644 --- a/zcash_proofs/src/sapling/verifier.rs +++ b/zcash_proofs/src/sapling/verifier.rs @@ -6,6 +6,7 @@ use sapling_crypto::{ jubjub::{edwards, FixedGenerators, JubjubBls12, Unknown}, redjubjub::{PublicKey, Signature}, }; +use zcash_primitives::transaction::components::Amount; use super::compute_value_balance; @@ -169,7 +170,7 @@ impl SaplingVerificationContext { /// have been checked before calling this function. pub fn final_check( &self, - value_balance: i64, + value_balance: Amount, sighash_value: &[u8; 32], binding_sig: Signature, params: &JubjubBls12, From 3891fe57d4a67c4b85dd2064d4bd26aa535d2374 Mon Sep 17 00:00:00 2001 From: Marco Stronati Date: Tue, 6 Aug 2019 23:41:33 +0200 Subject: [PATCH 053/330] Make initialization of sprout validation key optional This makes the C interface behave like `zcash_proofs` and allows to init the library without downloading the heavy sprout parameters. In the special case where `librustzcash_init_zksnark_params` is called with the sprout arguments path set to NULL and length set to 0, the arguments are passed as None to `load_parameters`. --- librustzcash/src/rustzcash.rs | 41 ++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 1db70ac..0f47d8f 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -143,9 +143,13 @@ pub extern "system" fn librustzcash_init_zksnark_params( let output_path = Path::new(OsStr::from_bytes(unsafe { slice::from_raw_parts(output_path, output_path_len) })); - let sprout_path = Path::new(OsStr::from_bytes(unsafe { - slice::from_raw_parts(sprout_path, sprout_path_len) - })); + let sprout_path = if sprout_path.is_null() && sprout_path_len == 0 { + None + } else { + Some(Path::new(OsStr::from_bytes(unsafe { + slice::from_raw_parts(sprout_path, sprout_path_len) + }))) + }; init_zksnark_params( spend_path, @@ -174,8 +178,13 @@ pub extern "system" fn librustzcash_init_zksnark_params( OsString::from_wide(unsafe { slice::from_raw_parts(spend_path, spend_path_len) }); let output_path = OsString::from_wide(unsafe { slice::from_raw_parts(output_path, output_path_len) }); - let sprout_path = - OsString::from_wide(unsafe { slice::from_raw_parts(sprout_path, sprout_path_len) }); + let sprout_path = if sprout_path.is_null() && sprout_path_len == 0 { + None + } else { + Some(OsStr::from_wide(unsafe { + slice::from_raw_parts(sprout_path, sprout_path_len) + })) + }; init_zksnark_params( Path::new(&spend_path), @@ -192,7 +201,7 @@ fn init_zksnark_params( spend_hash: *const c_char, output_path: &Path, output_hash: *const c_char, - sprout_path: &Path, + sprout_path: Option<&Path>, sprout_hash: *const c_char, ) { // Initialize jubjub parameters here @@ -206,9 +215,15 @@ fn init_zksnark_params( .to_str() .expect("hash should be a valid string"); - let sprout_hash = unsafe { CStr::from_ptr(sprout_hash) } - .to_str() - .expect("hash should be a valid string"); + let sprout_hash_option = if sprout_path.is_none() { + None + } else { + Some( + unsafe { CStr::from_ptr(sprout_hash) } + .to_str() + .expect("hash should be a valid string"), + ) + }; // Load params let (spend_params, spend_vk, output_params, output_vk, sprout_vk) = load_parameters( @@ -216,8 +231,8 @@ fn init_zksnark_params( spend_hash, output_path, output_hash, - Some(sprout_path), - Some(sprout_hash), + sprout_path, + sprout_hash_option, ); // Caller is responsible for calling this function once, so @@ -225,11 +240,11 @@ fn init_zksnark_params( unsafe { SAPLING_SPEND_PARAMS = Some(spend_params); SAPLING_OUTPUT_PARAMS = Some(output_params); - SPROUT_GROTH16_PARAMS_PATH = Some(sprout_path.to_owned()); + SPROUT_GROTH16_PARAMS_PATH = sprout_path.map(|p| p.to_owned()); SAPLING_SPEND_VK = Some(spend_vk); SAPLING_OUTPUT_VK = Some(output_vk); - SPROUT_GROTH16_VK = Some(sprout_vk.unwrap()); + SPROUT_GROTH16_VK = sprout_vk; } } From 7c07914bfdd9e896602b4582ccbd715743a23d5c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 8 Aug 2019 00:55:23 +0100 Subject: [PATCH 054/330] Separate Amount::{from_i64, from_nonnegative_i64} APIs This is more intuitive than a boolean flag for handling non-negative Amounts stored in i64 values. --- librustzcash/src/rustzcash.rs | 4 +- zcash_primitives/src/transaction/builder.rs | 12 ++--- .../src/transaction/components.rs | 2 +- .../src/transaction/components/amount.rs | 54 ++++++++++++------- zcash_primitives/src/transaction/mod.rs | 2 +- zcash_primitives/src/transaction/tests.rs | 4 +- 6 files changed, 46 insertions(+), 32 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 0fad706..99c3187 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -705,7 +705,7 @@ pub extern "system" fn librustzcash_sapling_final_check( binding_sig: *const [c_uchar; 64], sighash_value: *const [c_uchar; 32], ) -> bool { - let value_balance = match Amount::from_i64(value_balance, true) { + let value_balance = match Amount::from_i64(value_balance) { Ok(vb) => vb, Err(()) => return false, }; @@ -1028,7 +1028,7 @@ pub extern "system" fn librustzcash_sapling_binding_sig( sighash: *const [c_uchar; 32], result: *mut [c_uchar; 64], ) -> bool { - let value_balance = match Amount::from_i64(value_balance, true) { + let value_balance = match Amount::from_i64(value_balance) { Ok(vb) => vb, Err(()) => return false, }; diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 36490e4..ba07f34 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -564,7 +564,7 @@ mod tests { let to = extfvk.default_address().unwrap().1; let mut builder = Builder::new(0); - match builder.add_sapling_output(ovk, to, Amount::from_i64(-1, true).unwrap(), None) { + match builder.add_sapling_output(ovk, to, Amount::from_i64(-1).unwrap(), None) { Err(e) => assert_eq!(e.kind(), &ErrorKind::InvalidAmount), Ok(_) => panic!("Should have failed"), } @@ -575,7 +575,7 @@ mod tests { let mut builder = Builder::new(0); match builder.add_transparent_output( &TransparentAddress::PublicKey([0; 20]), - Amount::from_i64(-1, true).unwrap(), + Amount::from_i64(-1).unwrap(), ) { Err(e) => assert_eq!(e.kind(), &ErrorKind::InvalidAmount), Ok(_) => panic!("Should have failed"), @@ -596,7 +596,7 @@ mod tests { match builder.build(1, MockTxProver) { Err(e) => assert_eq!( e.kind(), - &ErrorKind::ChangeIsNegative(Amount::from_i64(-10000, true).unwrap()) + &ErrorKind::ChangeIsNegative(Amount::from_i64(-10000).unwrap()) ), Ok(_) => panic!("Should have failed"), } @@ -621,7 +621,7 @@ mod tests { match builder.build(1, MockTxProver) { Err(e) => assert_eq!( e.kind(), - &ErrorKind::ChangeIsNegative(Amount::from_i64(-60000, true).unwrap()) + &ErrorKind::ChangeIsNegative(Amount::from_i64(-60000).unwrap()) ), Ok(_) => panic!("Should have failed"), } @@ -640,7 +640,7 @@ mod tests { match builder.build(1, MockTxProver) { Err(e) => assert_eq!( e.kind(), - &ErrorKind::ChangeIsNegative(Amount::from_i64(-60000, true).unwrap()) + &ErrorKind::ChangeIsNegative(Amount::from_i64(-60000).unwrap()) ), Ok(_) => panic!("Should have failed"), } @@ -683,7 +683,7 @@ mod tests { match builder.build(1, MockTxProver) { Err(e) => assert_eq!( e.kind(), - &ErrorKind::ChangeIsNegative(Amount::from_i64(-1, true).unwrap()) + &ErrorKind::ChangeIsNegative(Amount::from_i64(-1).unwrap()) ), Ok(_) => panic!("Should have failed"), } diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index c7dcebd..d50b4fb 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -79,7 +79,7 @@ impl TxOut { let value = { let mut tmp = [0; 8]; reader.read_exact(&mut tmp)?; - Amount::from_i64_le_bytes(tmp, false) + Amount::from_nonnegative_i64_le_bytes(tmp) } .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "value out of range"))?; let script_pubkey = Script::read(&mut reader)?; diff --git a/zcash_primitives/src/transaction/components/amount.rs b/zcash_primitives/src/transaction/components/amount.rs index dca7056..d244876 100644 --- a/zcash_primitives/src/transaction/components/amount.rs +++ b/zcash_primitives/src/transaction/components/amount.rs @@ -18,10 +18,19 @@ impl Amount { /// Creates an Amount from an i64. /// /// Returns an error if the amount is out of range. - pub fn from_i64(amount: i64, allow_negative: bool) -> Result { - if 0 <= amount && amount <= MAX_MONEY { + pub fn from_i64(amount: i64) -> Result { + if -MAX_MONEY <= amount && amount <= MAX_MONEY { Ok(Amount(amount)) - } else if allow_negative && -MAX_MONEY <= amount && amount < 0 { + } else { + Err(()) + } + } + + /// Creates a non-negative Amount from an i64. + /// + /// Returns an error if the amount is out of range. + pub fn from_nonnegative_i64(amount: i64) -> Result { + if 0 <= amount && amount <= MAX_MONEY { Ok(Amount(amount)) } else { Err(()) @@ -42,9 +51,17 @@ impl Amount { /// Reads an Amount from a signed 64-bit little-endian integer. /// /// Returns an error if the amount is out of range. - pub fn from_i64_le_bytes(bytes: [u8; 8], allow_negative: bool) -> Result { + pub fn from_i64_le_bytes(bytes: [u8; 8]) -> Result { let amount = i64::from_le_bytes(bytes); - Amount::from_i64(amount, allow_negative) + Amount::from_i64(amount) + } + + /// Reads a non-negative Amount from a signed 64-bit little-endian integer. + /// + /// Returns an error if the amount is out of range. + pub fn from_nonnegative_i64_le_bytes(bytes: [u8; 8]) -> Result { + let amount = i64::from_le_bytes(bytes); + Amount::from_nonnegative_i64(amount) } /// Reads an Amount from an unsigned 64-bit little-endian integer. @@ -128,19 +145,16 @@ mod tests { let zero = b"\x00\x00\x00\x00\x00\x00\x00\x00"; assert_eq!(Amount::from_u64_le_bytes(zero.clone()).unwrap(), Amount(0)); assert_eq!( - Amount::from_i64_le_bytes(zero.clone(), false).unwrap(), - Amount(0) - ); - assert_eq!( - Amount::from_i64_le_bytes(zero.clone(), true).unwrap(), + Amount::from_nonnegative_i64_le_bytes(zero.clone()).unwrap(), Amount(0) ); + assert_eq!(Amount::from_i64_le_bytes(zero.clone()).unwrap(), Amount(0)); let neg_one = b"\xff\xff\xff\xff\xff\xff\xff\xff"; assert!(Amount::from_u64_le_bytes(neg_one.clone()).is_err()); - assert!(Amount::from_i64_le_bytes(neg_one.clone(), false).is_err()); + assert!(Amount::from_nonnegative_i64_le_bytes(neg_one.clone()).is_err()); assert_eq!( - Amount::from_i64_le_bytes(neg_one.clone(), true).unwrap(), + Amount::from_i64_le_bytes(neg_one.clone()).unwrap(), Amount(-1) ); @@ -150,30 +164,30 @@ mod tests { Amount(MAX_MONEY) ); assert_eq!( - Amount::from_i64_le_bytes(max_money.clone(), false).unwrap(), + Amount::from_nonnegative_i64_le_bytes(max_money.clone()).unwrap(), Amount(MAX_MONEY) ); assert_eq!( - Amount::from_i64_le_bytes(max_money.clone(), true).unwrap(), + Amount::from_i64_le_bytes(max_money.clone()).unwrap(), Amount(MAX_MONEY) ); let max_money_p1 = b"\x01\x40\x07\x5a\xf0\x75\x07\x00"; assert!(Amount::from_u64_le_bytes(max_money_p1.clone()).is_err()); - assert!(Amount::from_i64_le_bytes(max_money_p1.clone(), false).is_err()); - assert!(Amount::from_i64_le_bytes(max_money_p1.clone(), true).is_err()); + assert!(Amount::from_nonnegative_i64_le_bytes(max_money_p1.clone()).is_err()); + assert!(Amount::from_i64_le_bytes(max_money_p1.clone()).is_err()); let neg_max_money = b"\x00\xc0\xf8\xa5\x0f\x8a\xf8\xff"; assert!(Amount::from_u64_le_bytes(neg_max_money.clone()).is_err()); - assert!(Amount::from_i64_le_bytes(neg_max_money.clone(), false).is_err()); + assert!(Amount::from_nonnegative_i64_le_bytes(neg_max_money.clone()).is_err()); assert_eq!( - Amount::from_i64_le_bytes(neg_max_money.clone(), true).unwrap(), + Amount::from_i64_le_bytes(neg_max_money.clone()).unwrap(), Amount(-MAX_MONEY) ); let neg_max_money_m1 = b"\xff\xbf\xf8\xa5\x0f\x8a\xf8\xff"; assert!(Amount::from_u64_le_bytes(neg_max_money_m1.clone()).is_err()); - assert!(Amount::from_i64_le_bytes(neg_max_money_m1.clone(), false).is_err()); - assert!(Amount::from_i64_le_bytes(neg_max_money_m1.clone(), true).is_err()); + assert!(Amount::from_nonnegative_i64_le_bytes(neg_max_money_m1.clone()).is_err()); + assert!(Amount::from_i64_le_bytes(neg_max_money_m1.clone()).is_err()); } } diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index e5b83e5..aac0d35 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -188,7 +188,7 @@ impl Transaction { let vb = { let mut tmp = [0; 8]; reader.read_exact(&mut tmp)?; - Amount::from_i64_le_bytes(tmp, true) + Amount::from_i64_le_bytes(tmp) } .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "valueBalance out of range"))?; let ss = Vector::read(&mut reader, SpendDescription::read)?; diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index 7d84100..4cd5d72 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -1905,7 +1905,7 @@ fn zip_0143() { Some(( n as usize, Script(tv.script_code), - Amount::from_i64(tv.amount, false).unwrap(), + Amount::from_nonnegative_i64(tv.amount).unwrap(), )) } else { None @@ -5400,7 +5400,7 @@ fn zip_0243() { Some(( n as usize, Script(tv.script_code), - Amount::from_i64(tv.amount, false).unwrap(), + Amount::from_nonnegative_i64(tv.amount).unwrap(), )) } else { None From e6663212fff323d2750fdc6cf754da860cad1533 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 8 Aug 2019 09:21:09 +0100 Subject: [PATCH 055/330] Improve documentation for Amount --- .../src/transaction/components/amount.rs | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/zcash_primitives/src/transaction/components/amount.rs b/zcash_primitives/src/transaction/components/amount.rs index d244876..f2d9d0f 100644 --- a/zcash_primitives/src/transaction/components/amount.rs +++ b/zcash_primitives/src/transaction/components/amount.rs @@ -6,6 +6,17 @@ const MAX_MONEY: i64 = 21_000_000 * COIN; pub const DEFAULT_FEE: Amount = Amount(10000); +/// A type-safe representation of some quantity of Zcash. +/// +/// An Amount can only be constructed from an integer that is within the valid monetary +/// range of `{-MAX_MONEY..MAX_MONEY}` (where `MAX_MONEY` = 21,000,000 × 10⁸ zatoshis). +/// However, this range is not preserved as an invariant internally; it is possible to +/// add two valid Amounts together to obtain an invalid Amount. It is the user's +/// responsibility to handle the result of serializing potentially-invalid Amounts. In +/// particular, a [`Transaction`] containing serialized invalid Amounts will be rejected +/// by the network consensus rules. +/// +/// [`Transaction`]: crate::transaction::Transaction #[derive(Clone, Copy, Debug, PartialEq)] pub struct Amount(i64); @@ -17,7 +28,7 @@ impl Amount { /// Creates an Amount from an i64. /// - /// Returns an error if the amount is out of range. + /// Returns an error if the amount is outside the range `{-MAX_MONEY..MAX_MONEY}`. pub fn from_i64(amount: i64) -> Result { if -MAX_MONEY <= amount && amount <= MAX_MONEY { Ok(Amount(amount)) @@ -28,7 +39,7 @@ impl Amount { /// Creates a non-negative Amount from an i64. /// - /// Returns an error if the amount is out of range. + /// Returns an error if the amount is outside the range `{0..MAX_MONEY}`. pub fn from_nonnegative_i64(amount: i64) -> Result { if 0 <= amount && amount <= MAX_MONEY { Ok(Amount(amount)) @@ -39,7 +50,7 @@ impl Amount { /// Creates an Amount from a u64. /// - /// Returns an error if the amount is out of range. + /// Returns an error if the amount is outside the range `{0..MAX_MONEY}`. pub fn from_u64(amount: u64) -> Result { if amount <= MAX_MONEY as u64 { Ok(Amount(amount as i64)) @@ -50,7 +61,7 @@ impl Amount { /// Reads an Amount from a signed 64-bit little-endian integer. /// - /// Returns an error if the amount is out of range. + /// Returns an error if the amount is outside the range `{-MAX_MONEY..MAX_MONEY}`. pub fn from_i64_le_bytes(bytes: [u8; 8]) -> Result { let amount = i64::from_le_bytes(bytes); Amount::from_i64(amount) @@ -58,7 +69,7 @@ impl Amount { /// Reads a non-negative Amount from a signed 64-bit little-endian integer. /// - /// Returns an error if the amount is out of range. + /// Returns an error if the amount is outside the range `{0..MAX_MONEY}`. pub fn from_nonnegative_i64_le_bytes(bytes: [u8; 8]) -> Result { let amount = i64::from_le_bytes(bytes); Amount::from_nonnegative_i64(amount) @@ -66,7 +77,7 @@ impl Amount { /// Reads an Amount from an unsigned 64-bit little-endian integer. /// - /// Returns an error if the amount is out of range. + /// Returns an error if the amount is outside the range `{0..MAX_MONEY}`. pub fn from_u64_le_bytes(bytes: [u8; 8]) -> Result { let amount = u64::from_le_bytes(bytes); Amount::from_u64(amount) @@ -77,13 +88,13 @@ impl Amount { self.0.to_le_bytes() } - /// Returns `true` if `self` is positive and `false` if the number is zero or + /// Returns `true` if `self` is positive and `false` if the Amount is zero or /// negative. pub const fn is_positive(self) -> bool { self.0.is_positive() } - /// Returns `true` if `self` is negative and `false` if the number is zero or + /// Returns `true` if `self` is negative and `false` if the Amount is zero or /// positive. pub const fn is_negative(self) -> bool { self.0.is_negative() From 3a73f946c58ba914f5c3f1d468f194e67b23a01d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 13 Aug 2019 15:10:57 +0100 Subject: [PATCH 056/330] Simplify structure of transaction builder errors --- zcash_primitives/src/transaction/builder.rs | 57 ++++++++------------- 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index ba07f34..ff9c35f 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -30,17 +30,8 @@ const DEFAULT_TX_EXPIRY_DELTA: u32 = 20; /// with dummy outputs if necessary. See https://github.com/zcash/zcash/issues/3615 const MIN_SHIELDED_OUTPUTS: usize = 2; -#[derive(Debug)] -pub struct Error(ErrorKind); - -impl Error { - pub fn kind(&self) -> &ErrorKind { - &self.0 - } -} - #[derive(Debug, PartialEq)] -pub enum ErrorKind { +pub enum Error { AnchorMismatch, BindingSig, ChangeIsNegative(Amount), @@ -76,10 +67,10 @@ impl SaplingOutput { ) -> Result { let g_d = match to.g_d(&JUBJUB) { Some(g_d) => g_d, - None => return Err(Error(ErrorKind::InvalidAddress)), + None => return Err(Error::InvalidAddress), }; if value.is_negative() { - return Err(Error(ErrorKind::InvalidAmount)); + return Err(Error::InvalidAmount); } let rcm = Fs::random(rng); @@ -242,17 +233,16 @@ impl Builder { if let Some(anchor) = self.anchor { let witness_root: Fr = witness.root().into(); if witness_root != anchor { - return Err(Error(ErrorKind::AnchorMismatch)); + return Err(Error::AnchorMismatch); } } else { self.anchor = Some(witness.root().into()) } - let witness = witness.path().ok_or(Error(ErrorKind::InvalidWitness))?; + let witness = witness.path().ok_or(Error::InvalidWitness)?; let alpha = Fs::random(&mut self.rng); - self.mtx.value_balance += - Amount::from_u64(note.value).map_err(|_| Error(ErrorKind::InvalidAmount))?; + self.mtx.value_balance += Amount::from_u64(note.value).map_err(|_| Error::InvalidAmount)?; self.spends.push(SpendDescriptionInfo { extsk, @@ -289,7 +279,7 @@ impl Builder { value: Amount, ) -> Result<(), Error> { if value.is_negative() { - return Err(Error(ErrorKind::InvalidAmount)); + return Err(Error::InvalidAmount); } self.mtx.vout.push(TxOut { @@ -338,7 +328,7 @@ impl Builder { .map(|output| output.value) .sum::(); if change.is_negative() { - return Err(Error(ErrorKind::ChangeIsNegative(change))); + return Err(Error::ChangeIsNegative(change)); } // @@ -359,7 +349,7 @@ impl Builder { }, ) } else { - return Err(Error(ErrorKind::NoChangeAddress)); + return Err(Error::NoChangeAddress); }; self.add_sapling_output(change_address.0, change_address.1, change, None)?; @@ -419,7 +409,7 @@ impl Builder { anchor, spend.witness.clone(), ) - .map_err(|()| Error(ErrorKind::SpendProof))?; + .map_err(|()| Error::SpendProof)?; self.mtx.shielded_spends.push(SpendDescription { cv, @@ -529,7 +519,7 @@ impl Builder { self.mtx.binding_sig = Some( prover .binding_sig(&mut ctx, self.mtx.value_balance, &sighash) - .map_err(|()| Error(ErrorKind::BindingSig))?, + .map_err(|()| Error::BindingSig)?, ); Ok(( @@ -545,7 +535,7 @@ mod tests { use rand::rngs::OsRng; use sapling_crypto::jubjub::fs::Fs; - use super::{Builder, ErrorKind}; + use super::{Builder, Error}; use crate::{ legacy::TransparentAddress, merkle_tree::{CommitmentTree, IncrementalWitness}, @@ -565,7 +555,7 @@ mod tests { let mut builder = Builder::new(0); match builder.add_sapling_output(ovk, to, Amount::from_i64(-1).unwrap(), None) { - Err(e) => assert_eq!(e.kind(), &ErrorKind::InvalidAmount), + Err(e) => assert_eq!(e, Error::InvalidAmount), Ok(_) => panic!("Should have failed"), } } @@ -577,7 +567,7 @@ mod tests { &TransparentAddress::PublicKey([0; 20]), Amount::from_i64(-1).unwrap(), ) { - Err(e) => assert_eq!(e.kind(), &ErrorKind::InvalidAmount), + Err(e) => assert_eq!(e, Error::InvalidAmount), Ok(_) => panic!("Should have failed"), } } @@ -595,8 +585,8 @@ mod tests { let builder = Builder::new(0); match builder.build(1, MockTxProver) { Err(e) => assert_eq!( - e.kind(), - &ErrorKind::ChangeIsNegative(Amount::from_i64(-10000).unwrap()) + e, + Error::ChangeIsNegative(Amount::from_i64(-10000).unwrap()) ), Ok(_) => panic!("Should have failed"), } @@ -620,8 +610,8 @@ mod tests { .unwrap(); match builder.build(1, MockTxProver) { Err(e) => assert_eq!( - e.kind(), - &ErrorKind::ChangeIsNegative(Amount::from_i64(-60000).unwrap()) + e, + Error::ChangeIsNegative(Amount::from_i64(-60000).unwrap()) ), Ok(_) => panic!("Should have failed"), } @@ -639,8 +629,8 @@ mod tests { .unwrap(); match builder.build(1, MockTxProver) { Err(e) => assert_eq!( - e.kind(), - &ErrorKind::ChangeIsNegative(Amount::from_i64(-60000).unwrap()) + e, + Error::ChangeIsNegative(Amount::from_i64(-60000).unwrap()) ), Ok(_) => panic!("Should have failed"), } @@ -681,10 +671,7 @@ mod tests { ) .unwrap(); match builder.build(1, MockTxProver) { - Err(e) => assert_eq!( - e.kind(), - &ErrorKind::ChangeIsNegative(Amount::from_i64(-1).unwrap()) - ), + Err(e) => assert_eq!(e, Error::ChangeIsNegative(Amount::from_i64(-1).unwrap())), Ok(_) => panic!("Should have failed"), } } @@ -718,7 +705,7 @@ mod tests { ) .unwrap(); match builder.build(1, MockTxProver) { - Err(e) => assert_eq!(e.kind(), &ErrorKind::BindingSig), + Err(e) => assert_eq!(e, Error::BindingSig), Ok(_) => panic!("Should have failed"), } } From 1760b275a7388bbe1e12e126640c2f520b422e92 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 13 Aug 2019 15:24:08 +0100 Subject: [PATCH 057/330] Simplify transaction builder tests Requires impl PartialEq for Transaction, which is implemented as a TxId comparison (relying on the invariant that Transaction is immutable). --- zcash_primitives/src/transaction/builder.rs | 69 +++++++++------------ zcash_primitives/src/transaction/mod.rs | 6 ++ 2 files changed, 35 insertions(+), 40 deletions(-) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index ff9c35f..a3134c3 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -131,6 +131,7 @@ impl SaplingOutput { } /// Metadata about a transaction created by a [`Builder`]. +#[derive(Debug, PartialEq)] pub struct TransactionMetadata { spend_indices: Vec, output_indices: Vec, @@ -554,22 +555,22 @@ mod tests { let to = extfvk.default_address().unwrap().1; let mut builder = Builder::new(0); - match builder.add_sapling_output(ovk, to, Amount::from_i64(-1).unwrap(), None) { - Err(e) => assert_eq!(e, Error::InvalidAmount), - Ok(_) => panic!("Should have failed"), - } + assert_eq!( + builder.add_sapling_output(ovk, to, Amount::from_i64(-1).unwrap(), None), + Err(Error::InvalidAmount) + ); } #[test] fn fails_on_negative_transparent_output() { let mut builder = Builder::new(0); - match builder.add_transparent_output( - &TransparentAddress::PublicKey([0; 20]), - Amount::from_i64(-1).unwrap(), - ) { - Err(e) => assert_eq!(e, Error::InvalidAmount), - Ok(_) => panic!("Should have failed"), - } + assert_eq!( + builder.add_transparent_output( + &TransparentAddress::PublicKey([0; 20]), + Amount::from_i64(-1).unwrap(), + ), + Err(Error::InvalidAmount) + ); } #[test] @@ -583,13 +584,10 @@ mod tests { // 0.0001 t-ZEC fee { let builder = Builder::new(0); - match builder.build(1, MockTxProver) { - Err(e) => assert_eq!( - e, - Error::ChangeIsNegative(Amount::from_i64(-10000).unwrap()) - ), - Ok(_) => panic!("Should have failed"), - } + assert_eq!( + builder.build(1, MockTxProver), + Err(Error::ChangeIsNegative(Amount::from_i64(-10000).unwrap())) + ); } let extfvk = ExtendedFullViewingKey::from(&extsk); @@ -608,13 +606,10 @@ mod tests { None, ) .unwrap(); - match builder.build(1, MockTxProver) { - Err(e) => assert_eq!( - e, - Error::ChangeIsNegative(Amount::from_i64(-60000).unwrap()) - ), - Ok(_) => panic!("Should have failed"), - } + assert_eq!( + builder.build(1, MockTxProver), + Err(Error::ChangeIsNegative(Amount::from_i64(-60000).unwrap())) + ); } // Fail if there is only a transparent output @@ -627,13 +622,10 @@ mod tests { Amount::from_u64(50000).unwrap(), ) .unwrap(); - match builder.build(1, MockTxProver) { - Err(e) => assert_eq!( - e, - Error::ChangeIsNegative(Amount::from_i64(-60000).unwrap()) - ), - Ok(_) => panic!("Should have failed"), - } + assert_eq!( + builder.build(1, MockTxProver), + Err(Error::ChangeIsNegative(Amount::from_i64(-60000).unwrap())) + ); } let note1 = to @@ -670,10 +662,10 @@ mod tests { Amount::from_u64(20000).unwrap(), ) .unwrap(); - match builder.build(1, MockTxProver) { - Err(e) => assert_eq!(e, Error::ChangeIsNegative(Amount::from_i64(-1).unwrap())), - Ok(_) => panic!("Should have failed"), - } + assert_eq!( + builder.build(1, MockTxProver), + Err(Error::ChangeIsNegative(Amount::from_i64(-1).unwrap())) + ); } let note2 = to.create_note(1, Fs::random(&mut rng), &JUBJUB).unwrap(); @@ -704,10 +696,7 @@ mod tests { Amount::from_u64(20000).unwrap(), ) .unwrap(); - match builder.build(1, MockTxProver) { - Err(e) => assert_eq!(e, Error::BindingSig), - Ok(_) => panic!("Should have failed"), - } + assert_eq!(builder.build(1, MockTxProver), Err(Error::BindingSig)) } } } diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index aac0d35..a8ecb17 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -50,6 +50,12 @@ impl Deref for Transaction { } } +impl PartialEq for Transaction { + fn eq(&self, other: &Transaction) -> bool { + self.txid == other.txid + } +} + pub struct TransactionData { pub overwintered: bool, pub version: u32, From a28d94ff2e30897aca6806ff66d0d059f50f706e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 14 Aug 2019 00:16:09 +0100 Subject: [PATCH 058/330] Panic if Amount addition or subtraction overflows --- .../src/transaction/components/amount.rs | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/zcash_primitives/src/transaction/components/amount.rs b/zcash_primitives/src/transaction/components/amount.rs index f2d9d0f..8d358fb 100644 --- a/zcash_primitives/src/transaction/components/amount.rs +++ b/zcash_primitives/src/transaction/components/amount.rs @@ -117,7 +117,7 @@ impl Add for Amount { type Output = Amount; fn add(self, rhs: Amount) -> Amount { - Amount(self.0 + rhs.0) + Amount::from_i64(self.0 + rhs.0).expect("addition should remain in range") } } @@ -131,7 +131,7 @@ impl Sub for Amount { type Output = Amount; fn sub(self, rhs: Amount) -> Amount { - Amount(self.0 - rhs.0) + Amount::from_i64(self.0 - rhs.0).expect("subtraction should remain in range") } } @@ -201,4 +201,32 @@ mod tests { assert!(Amount::from_nonnegative_i64_le_bytes(neg_max_money_m1.clone()).is_err()); assert!(Amount::from_i64_le_bytes(neg_max_money_m1.clone()).is_err()); } + + #[test] + #[should_panic] + fn add_panics_on_overflow() { + let v = Amount(MAX_MONEY); + let sum = v + Amount(1); + } + + #[test] + #[should_panic] + fn add_assign_panics_on_overflow() { + let mut a = Amount(MAX_MONEY); + a += Amount(1); + } + + #[test] + #[should_panic] + fn sub_panics_on_underflow() { + let v = Amount(-MAX_MONEY); + let diff = v - Amount(1); + } + + #[test] + #[should_panic] + fn sub_assign_panics_on_underflow() { + let mut a = Amount(-MAX_MONEY); + a -= Amount(1); + } } From 4a6c9ec4259931d14bd6be87d53c12850991ebaf Mon Sep 17 00:00:00 2001 From: str4d Date: Wed, 14 Aug 2019 00:30:18 +0100 Subject: [PATCH 059/330] Comment that we support a minimal set of script opcodes Co-Authored-By: Daira Hopwood --- zcash_primitives/src/legacy.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zcash_primitives/src/legacy.rs b/zcash_primitives/src/legacy.rs index 02977ab..d1d7c1a 100644 --- a/zcash_primitives/src/legacy.rs +++ b/zcash_primitives/src/legacy.rs @@ -6,7 +6,7 @@ use std::ops::Shl; use crate::serialize::Vector; -/// Script opcodes. +/// Minimal subset of script opcodes. enum OpCode { // push value PushData1 = 0x4c, From 2f1cae62b11e2c1d49e584ffaab99fbf47759734 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 22 Jul 2019 23:51:32 +0100 Subject: [PATCH 060/330] Upgrade to fpe 0.2 --- Cargo.lock | 66 +++++++++++++------------------------ zcash_primitives/Cargo.toml | 4 +-- 2 files changed, 24 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fc8644f..ae3cbd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,32 +2,31 @@ # It is not intended for manual editing. [[package]] name = "aes" -version = "0.2.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "aes-soft" -version = "0.2.0" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "aesni" -version = "0.4.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -108,10 +107,10 @@ dependencies = [ [[package]] name = "block-cipher-trait" -version = "0.5.3" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -122,11 +121,6 @@ dependencies = [ "byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "byte-tools" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byte-tools" version = "0.3.0" @@ -222,10 +216,10 @@ dependencies = [ [[package]] name = "fpe" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", @@ -369,11 +363,6 @@ dependencies = [ "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "opaque-debug" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "opaque-debug" version = "0.2.2" @@ -512,14 +501,6 @@ name = "spin" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "stream-cipher" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syn" version = "0.14.9" @@ -575,12 +556,12 @@ dependencies = [ name = "zcash_primitives" version = "0.0.0" dependencies = [ - "aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto_api_chachapoly 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", - "fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fpe 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", @@ -607,9 +588,9 @@ dependencies = [ ] [metadata] -"checksum aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6fb1737cdc8da3db76e90ca817a194249a38fcb500c2e6ecec39b29448aa873" -"checksum aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67cc03b0a090a05cb01e96998a01905d7ceedce1bc23b756c0bb7faa0682ccb1" -"checksum aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6810b7fb9f2bb4f76f05ac1c170b8dde285b6308955dc3afd89710268c958d9e" +"checksum aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "54eb1d8fe354e5fc611daf4f2ea97dd45a765f4f1e4512306ec183ae2e8f20c9" +"checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" +"checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" @@ -618,9 +599,8 @@ dependencies = [ "checksum blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d909f9ef55928e57e7de9638828bc9407233b5cb0904066a7edebbaa9946db2f" "checksum blake2s_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fa20660ff9f1e6d0a05444b5ebbbae13e4c018d4c66cc78c7e421e3396358a52" "checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" -"checksum block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "370424437b9459f3dfd68428ed9376ddfe03d8b70ede29cc533b3557df186ab4" +"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" "checksum block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc4358306e344bf9775d0197fd00d2603e5afb0771bb353538630f022068ea3" -"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" "checksum byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "980479e6fde23246dfb54d47580d66b4e99202e7579c5eaa9fe10ecb5ebd2182" "checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" @@ -632,7 +612,7 @@ dependencies = [ "checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" "checksum directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72d337a64190607d4fcca2cb78982c5dd57f4916e19696b48a575fa746b6cb0f" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce3371c82bfbd984f624cab093f55e7336f5a6e589f8518e1258f54f011b89ad" +"checksum fpe 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21988a326139165b75e3196bc6962ca638e5fb0c95102fbf152a3743174b01e4" "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" @@ -648,7 +628,6 @@ dependencies = [ "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d620c9c26834b34f039489ac0dfdb12c7ac15ccaf818350a64c9b5334a452ad7" "checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ba8d4f9257b85eb6cdf13f055cea3190520aab1409ca2ab43493ea4820c25f0" @@ -663,7 +642,6 @@ dependencies = [ "checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" -"checksum stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "30dc6118470d69ce0fdcf7e6f95e95853f7f4f72f80d835d4519577c323814ab" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index 804f8c6..5327905 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -6,12 +6,12 @@ authors = [ ] [dependencies] -aes = "0.2" +aes = "0.3" blake2b_simd = "0.5" byteorder = "1" crypto_api_chachapoly = "0.1" ff = { path = "../ff" } -fpe = "0.1" +fpe = "0.2" hex = "0.3" lazy_static = "1" pairing = { path = "../pairing" } From a12b8053b0f1f97ed537f9b7787cbafd162683ca Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 22 Jul 2019 23:57:24 +0100 Subject: [PATCH 061/330] Upgrade to digest 0.8 --- Cargo.lock | 20 +------------------- sapling-crypto/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ae3cbd8..2fb2992 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -163,14 +163,6 @@ dependencies = [ "crypto_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "digest" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "digest" version = "0.8.0" @@ -240,14 +232,6 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "generic-array" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "generic-array" version = "0.12.0" @@ -476,7 +460,7 @@ dependencies = [ "blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "blake2s_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", @@ -608,7 +592,6 @@ dependencies = [ "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crypto_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f855e87e75a4799e18b8529178adcde6fd4f97c1449ff4821e747ff728bb102" "checksum crypto_api_chachapoly 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9ee35dbace0831b5fe7cb9b43eb029aa14a10f594a115025d4628a2baa63ab" -"checksum digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603" "checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" "checksum directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72d337a64190607d4fcca2cb78982c5dd57f4916e19696b48a575fa746b6cb0f" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" @@ -616,7 +599,6 @@ dependencies = [ "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" -"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" "checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4da5f0e01bd8a71a224a4eedecaacfcabda388dbb7a80faf04d3514287572d95" diff --git a/sapling-crypto/Cargo.toml b/sapling-crypto/Cargo.toml index 0026f6c..c3aedd3 100644 --- a/sapling-crypto/Cargo.toml +++ b/sapling-crypto/Cargo.toml @@ -18,7 +18,7 @@ blake2b_simd = "0.5" blake2s_simd = "0.5" ff = { path = "../ff" } rand_core = "0.5" -digest = "0.7" +digest = "0.8" byteorder = "1" [dev-dependencies] From ec321382e11b9715344306ab5a3c377279a97fee Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 23 Jul 2019 00:18:53 +0100 Subject: [PATCH 062/330] Upgrade to bech32 0.7 --- Cargo.lock | 6 +++--- zcash_client_backend/Cargo.toml | 2 +- zcash_client_backend/src/encoding.rs | 15 +++++---------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2fb2992..60bcbad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,7 +49,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bech32" -version = "0.6.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -528,7 +528,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "zcash_client_backend" version = "0.0.0" dependencies = [ - "bech32 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -578,7 +578,7 @@ dependencies = [ "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" -"checksum bech32 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58946044516aa9dc922182e0d6e9d124a31aafe6b421614654eb27cf90cec09c" +"checksum bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0089c35ab7c6f2bc55ab23f769913f0ac65b1023e7e74638a1f43128dd5df2" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" "checksum blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d909f9ef55928e57e7de9638828bc9407233b5cb0904066a7edebbaa9946db2f" "checksum blake2s_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fa20660ff9f1e6d0a05444b5ebbbae13e4c018d4c66cc78c7e421e3396358a52" diff --git a/zcash_client_backend/Cargo.toml b/zcash_client_backend/Cargo.toml index 1d7848e..31fba49 100644 --- a/zcash_client_backend/Cargo.toml +++ b/zcash_client_backend/Cargo.toml @@ -7,7 +7,7 @@ authors = [ edition = "2018" [dependencies] -bech32 = "0.6" +bech32 = "0.7" pairing = { path = "../pairing" } sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } diff --git a/zcash_client_backend/src/encoding.rs b/zcash_client_backend/src/encoding.rs index d816201..0c0a50b 100644 --- a/zcash_client_backend/src/encoding.rs +++ b/zcash_client_backend/src/encoding.rs @@ -3,7 +3,7 @@ //! Human-Readable Prefixes (HRPs) for Bech32 encodings are located in the [`constants`] //! module. -use bech32::{convert_bits, Bech32, Error}; +use bech32::{self, Error, FromBase32, ToBase32}; use pairing::bls12_381::Bls12; use sapling_crypto::{ jubjub::edwards, @@ -21,21 +21,16 @@ where { let mut data: Vec = vec![]; write(&mut data).expect("Should be able to write to a Vec"); - - let converted = - convert_bits(&data, 8, 5, true).expect("Should be able to convert Vec to Vec"); - let encoded = Bech32::new_check_data(hrp.into(), converted).expect("hrp is not empty"); - - encoded.to_string() + bech32::encode(hrp, data.to_base32()).expect("hrp is invalid") } fn bech32_decode(hrp: &str, s: &str, read: F) -> Result, Error> where F: Fn(Vec) -> Option, { - let decoded = s.parse::()?; - if decoded.hrp() == hrp { - convert_bits(decoded.data(), 5, 8, false).map(|data| read(data)) + let (decoded_hrp, data) = bech32::decode(s)?; + if decoded_hrp == hrp { + Vec::::from_base32(&data).map(|data| read(data)) } else { Ok(None) } From 32115363240a97c3d63f29baf6f49112ec48b609 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 23 Jul 2019 00:30:18 +0100 Subject: [PATCH 063/330] Upgrade to crypto_api_chachapoly >= 0.2.1 --- Cargo.lock | 6 +++--- zcash_primitives/Cargo.toml | 2 +- zcash_primitives/src/note_encryption.rs | 21 +++++---------------- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 60bcbad..a733501 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -157,7 +157,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crypto_api_chachapoly" -version = "0.1.8" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crypto_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -543,7 +543,7 @@ dependencies = [ "aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto_api_chachapoly 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto_api_chachapoly 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "fpe 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -591,7 +591,7 @@ dependencies = [ "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crypto_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f855e87e75a4799e18b8529178adcde6fd4f97c1449ff4821e747ff728bb102" -"checksum crypto_api_chachapoly 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9ee35dbace0831b5fe7cb9b43eb029aa14a10f594a115025d4628a2baa63ab" +"checksum crypto_api_chachapoly 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95b2ad7cab08fd71addba81df5077c49df208effdfb3118a1519f9cdeac5aaf2" "checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" "checksum directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72d337a64190607d4fcca2cb78982c5dd57f4916e19696b48a575fa746b6cb0f" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index 5327905..ba724be 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -9,7 +9,7 @@ authors = [ aes = "0.3" blake2b_simd = "0.5" byteorder = "1" -crypto_api_chachapoly = "0.1" +crypto_api_chachapoly = "0.2.1" ff = { path = "../ff" } fpe = "0.2" hex = "0.3" diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 42e1398..d6b66ce 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -444,23 +444,12 @@ pub fn try_sapling_compact_note_decryption( let shared_secret = sapling_ka_agree(ivk, epk); let key = kdf_sapling(shared_secret, &epk); - // Prefix plaintext with 64 zero-bytes to skip over Poly1305 keying output - const CHACHA20_BLOCK_SIZE: usize = 64; - let mut plaintext = [0; CHACHA20_BLOCK_SIZE + COMPACT_NOTE_SIZE]; - plaintext[CHACHA20_BLOCK_SIZE..].copy_from_slice(&enc_ciphertext[0..COMPACT_NOTE_SIZE]); - assert_eq!( - ChaCha20Ietf::cipher() - .decrypt( - &mut plaintext, - CHACHA20_BLOCK_SIZE + COMPACT_NOTE_SIZE, - key.as_bytes(), - &[0u8; 12], - ) - .ok()?, - CHACHA20_BLOCK_SIZE + COMPACT_NOTE_SIZE - ); + // Start from block 1 to skip over Poly1305 keying output + let mut plaintext = [0; COMPACT_NOTE_SIZE]; + plaintext.copy_from_slice(&enc_ciphertext); + ChaCha20Ietf::xor(key.as_bytes(), &[0u8; 12], 1, &mut plaintext); - parse_note_plaintext_without_memo(ivk, cmu, &plaintext[CHACHA20_BLOCK_SIZE..]) + parse_note_plaintext_without_memo(ivk, cmu, &plaintext) } /// Recovery of the full note plaintext by the sender. From 3e35dd215c0c03eed5b0e22f26da2f5ab8a06cde Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 30 Jul 2019 21:04:33 +0100 Subject: [PATCH 064/330] cargo update --- Cargo.lock | 262 ++++++++++++++++++++++++++--------------------------- 1 file changed, 131 insertions(+), 131 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a733501..3ca7b39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,8 +16,8 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -26,7 +26,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -36,15 +36,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayvec" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "autocfg" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -57,13 +57,13 @@ name = "bellman" version = "0.1.0" dependencies = [ "bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "group 0.1.0", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -76,33 +76,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "blake2b_simd" -version = "0.5.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "blake2s_simd" -version = "0.5.1" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "block-buffer" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -110,25 +110,25 @@ name = "block-cipher-trait" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "block-padding" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "byte-tools" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.2.2" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -140,6 +140,11 @@ dependencies = [ "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cfg-if" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "constant_time_eq" version = "0.1.3" @@ -165,10 +170,10 @@ dependencies = [ [[package]] name = "digest" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -176,7 +181,7 @@ name = "directories" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -189,7 +194,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "ff" version = "0.4.0" dependencies = [ - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff_derive 0.3.0", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -198,11 +203,11 @@ dependencies = [ name = "ff_derive" version = "0.3.0" dependencies = [ - "num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -212,15 +217,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures" -version = "0.1.21" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -228,13 +233,13 @@ name = "futures-cpupool" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "generic-array" -version = "0.12.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -242,11 +247,11 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -265,32 +270,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hex-literal" -version = "0.1.1" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal-impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hex-literal-impl" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy_static" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "libc" -version = "0.2.59" +version = "0.2.61" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -298,15 +300,15 @@ name = "librustzcash" version = "0.1.0" dependencies = [ "bellman 0.1.0", - "blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2s_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2s_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", "zcash_proofs 0.0.0", @@ -314,49 +316,53 @@ dependencies = [ [[package]] name = "nodrop" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num-bigint" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.39" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.5" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "num_cpus" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "opaque-debug" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "pairing" version = "0.14.2" dependencies = [ - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "group 0.1.0", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -370,20 +376,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro-hack" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "proc-macro-hack-impl" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.14" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -391,10 +397,10 @@ dependencies = [ [[package]] name = "quote" -version = "0.6.8" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -402,19 +408,18 @@ name = "rand" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_chacha" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -424,7 +429,7 @@ name = "rand_core" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -437,10 +442,10 @@ dependencies = [ [[package]] name = "rand_os" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -457,12 +462,12 @@ name = "sapling-crypto" version = "0.0.1" dependencies = [ "bellman 0.1.0", - "blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2s_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2s_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -474,24 +479,19 @@ name = "sha2" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "spin" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "syn" version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -541,8 +541,8 @@ name = "zcash_primitives" version = "0.0.0" dependencies = [ "aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto_api_chachapoly 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "fpe 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -551,7 +551,7 @@ dependencies = [ "pairing 0.14.2", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -561,12 +561,12 @@ name = "zcash_proofs" version = "0.0.0" dependencies = [ "bellman 0.1.0", - "blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "pairing 0.14.2", - "rand_os 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", ] @@ -576,54 +576,54 @@ dependencies = [ "checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" "checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" -"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" +"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" "checksum bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0089c35ab7c6f2bc55ab23f769913f0ac65b1023e7e74638a1f43128dd5df2" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" -"checksum blake2b_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d909f9ef55928e57e7de9638828bc9407233b5cb0904066a7edebbaa9946db2f" -"checksum blake2s_simd 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fa20660ff9f1e6d0a05444b5ebbbae13e4c018d4c66cc78c7e421e3396358a52" -"checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" +"checksum blake2b_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "461f4b879a8eb70c1debf7d0788a9a5ff15f1ea9d25925fea264ef4258bed6b2" +"checksum blake2s_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3a84d2614b18a5367d357331a90fd533d5ceb1e86abc319320df2104ab744c2a" +"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" "checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" -"checksum block-padding 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc4358306e344bf9775d0197fd00d2603e5afb0771bb353538630f022068ea3" -"checksum byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "980479e6fde23246dfb54d47580d66b4e99202e7579c5eaa9fe10ecb5ebd2182" -"checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87" +"checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" +"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" +"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" "checksum crypto_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f855e87e75a4799e18b8529178adcde6fd4f97c1449ff4821e747ff728bb102" "checksum crypto_api_chachapoly 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95b2ad7cab08fd71addba81df5077c49df208effdfb3118a1519f9cdeac5aaf2" -"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" +"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" "checksum directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72d337a64190607d4fcca2cb78982c5dd57f4916e19696b48a575fa746b6cb0f" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fpe 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21988a326139165b75e3196bc6962ca638e5fb0c95102fbf152a3743174b01e4" -"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" +"checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" -"checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55" +"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +"checksum getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "34f33de6f0ae7c9cb5e574502a562e2b512799e32abb801cd1e79ad952b62b49" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" -"checksum hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4da5f0e01bd8a71a224a4eedecaacfcabda388dbb7a80faf04d3514287572d95" -"checksum hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d340b6514f232f6db1bd16db65302a5278a04fef9ce867cb932e7e5fa21130a" +"checksum hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc2928beef125e519d69ae1baa8c37ea2e0d3848545217f6db0179c5eb1d639" +"checksum hex-literal-impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "520870c3213943eb8d7803e80180d12a6c7ceb4ae74602544529d1643dc4ddda" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.59 (registry+https://github.com/rust-lang/crates.io-index)" = "3262021842bf00fe07dbd6cf34ff25c99d7a7ebef8deea84db72be3ea3bb0aff" -"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" -"checksum num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3eceac7784c5dc97c2d6edf30259b4e153e6e2b42b3c85e9a6e9f45d06caef6e" -"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" -"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" -"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" +"checksum libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)" = "c665266eb592905e8503ba3403020f4b8794d26263f412ca33171600eca9a6fa" +"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "57450397855d951f1a41305e54851b1a7b8f5d2e349543a02a2effe25459f718" +"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" +"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" +"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" -"checksum proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ba8d4f9257b85eb6cdf13f055cea3190520aab1409ca2ab43493ea4820c25f0" -"checksum proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5cb6f960ad471404618e9817c0e5d10b1ae74cfdf01fab89ea0641fe7fb2892" -"checksum proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b331c6ad3411474cd55540398dc7ad89fc41488e64ec71fdecc9c9b86de96fb0" -"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" +"checksum proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "463bf29e7f11344e58c9e01f171470ab15c925c6822ad75028cc1c0e1d1eb63b" +"checksum proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38c47dcb1594802de8c02f3b899e2018c78291168a22c281be21ea0fb4796842" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" -"checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d" +"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_os 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e8c83d0434e67e7a92be561af33f3ca17ff9899a4acf28030fabb8c5c323a1a" +"checksum rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddb525a78d3a0b0e05b6fe0f7df14d7a4dc957944c7b403911ba5a0f1c694967" "checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" -"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" From 13933d8c51bb1d681c7b471f9be91477e42f5363 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 30 Jul 2019 21:28:27 +0100 Subject: [PATCH 065/330] Use modern clippy linter syntax --- pairing/src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs index 1c8d90c..7edb180 100644 --- a/pairing/src/lib.rs +++ b/pairing/src/lib.rs @@ -2,12 +2,12 @@ // common mistakes or strange code patterns. If the `cargo-clippy` feature // is provided, all compiler warnings are prohibited. #![cfg_attr(feature = "cargo-clippy", deny(warnings))] -#![cfg_attr(feature = "cargo-clippy", allow(inline_always))] -#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] -#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] -#![cfg_attr(feature = "cargo-clippy", allow(many_single_char_names))] -#![cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))] -#![cfg_attr(feature = "cargo-clippy", allow(write_literal))] +#![cfg_attr(feature = "cargo-clippy", allow(clippy::inline_always))] +#![cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))] +#![cfg_attr(feature = "cargo-clippy", allow(clippy::unreadable_literal))] +#![cfg_attr(feature = "cargo-clippy", allow(clippy::many_single_char_names))] +#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))] +#![cfg_attr(feature = "cargo-clippy", allow(clippy::write_literal))] // Force public structures to implement Debug #![deny(missing_debug_implementations)] From 81786c24c05be529fd5890f99c53b56739b95270 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 30 Jul 2019 21:30:59 +0100 Subject: [PATCH 066/330] Fix clippy linter errors in pairing crate --- pairing/src/bls12_381/ec.rs | 4 ++-- pairing/src/bls12_381/fq12.rs | 4 ++-- pairing/src/bls12_381/fq6.rs | 6 +++--- pairing/src/lib.rs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index b20dea8..fa659bd 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -955,7 +955,7 @@ pub mod g1 { let negyrepr = negy.into_repr(); let p = G1Affine { - x: x, + x, y: if yrepr < negyrepr { y } else { negy }, infinity: false, }; @@ -1637,7 +1637,7 @@ pub mod g2 { negy.negate(); let p = G2Affine { - x: x, + x, y: if y < negy { y } else { negy }, infinity: false, }; diff --git a/pairing/src/bls12_381/fq12.rs b/pairing/src/bls12_381/fq12.rs index f07a337..3c726d2 100644 --- a/pairing/src/bls12_381/fq12.rs +++ b/pairing/src/bls12_381/fq12.rs @@ -168,8 +168,8 @@ fn test_fq12_mul_by_014() { a.mul_by_014(&c0, &c1, &c5); b.mul_assign(&Fq12 { c0: Fq6 { - c0: c0, - c1: c1, + c0, + c1, c2: Fq2::zero(), }, c1: Fq6 { diff --git a/pairing/src/bls12_381/fq6.rs b/pairing/src/bls12_381/fq6.rs index 87e64cb..dbe58f7 100644 --- a/pairing/src/bls12_381/fq6.rs +++ b/pairing/src/bls12_381/fq6.rs @@ -343,7 +343,7 @@ fn test_fq6_mul_by_1() { a.mul_by_1(&c1); b.mul_assign(&Fq6 { c0: Fq2::zero(), - c1: c1, + c1, c2: Fq2::zero(), }); @@ -366,8 +366,8 @@ fn test_fq6_mul_by_01() { a.mul_by_01(&c0, &c1); b.mul_assign(&Fq6 { - c0: c0, - c1: c1, + c0, + c1, c2: Fq2::zero(), }); diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs index 7edb180..a81d1a1 100644 --- a/pairing/src/lib.rs +++ b/pairing/src/lib.rs @@ -100,7 +100,7 @@ pub trait Engine: ScalarEngine { G2: Into, { Self::final_exponentiation(&Self::miller_loop( - [(&(p.into().prepare()), &(q.into().prepare()))].into_iter(), + [(&(p.into().prepare()), &(q.into().prepare()))].iter(), )).unwrap() } } From 7ea6d10480795f60ade4041963b3f51f1ebc9472 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 4 May 2019 17:47:18 +0100 Subject: [PATCH 067/330] Move redjubjub into zcash_primitives --- Cargo.lock | 1 + librustzcash/src/rustzcash.rs | 2 +- librustzcash/src/tests/signatures.rs | 6 ++---- sapling-crypto/src/lib.rs | 2 -- zcash_primitives/Cargo.toml | 3 +++ zcash_primitives/src/lib.rs | 5 +++++ zcash_primitives/src/prover.rs | 4 ++-- {sapling-crypto => zcash_primitives}/src/redjubjub.rs | 9 +++++---- zcash_primitives/src/sapling.rs | 2 +- zcash_primitives/src/transaction/builder.rs | 2 +- zcash_primitives/src/transaction/components.rs | 6 ++---- zcash_primitives/src/transaction/mod.rs | 2 +- zcash_primitives/src/transaction/tests.rs | 6 ++---- {sapling-crypto => zcash_primitives}/src/util.rs | 3 +-- zcash_proofs/src/prover.rs | 2 +- zcash_proofs/src/sapling/prover.rs | 6 ++++-- zcash_proofs/src/sapling/verifier.rs | 6 ++++-- 17 files changed, 36 insertions(+), 31 deletions(-) rename {sapling-crypto => zcash_primitives}/src/redjubjub.rs (98%) rename {sapling-crypto => zcash_primitives}/src/util.rs (84%) diff --git a/Cargo.lock b/Cargo.lock index 3ca7b39..53bc275 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -552,6 +552,7 @@ dependencies = [ "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 99c3187..bff8093 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -24,7 +24,6 @@ use sapling_crypto::{ fs::{Fs, FsRepr}, FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder, ToUniform, Unknown, }, - redjubjub::{self, Signature}, }; use sapling_crypto::circuit::sapling::TREE_DEPTH as SAPLING_TREE_DEPTH; @@ -62,6 +61,7 @@ use sapling_crypto::primitives::{ProofGenerationKey, ViewingKey}; use zcash_primitives::{ merkle_tree::CommitmentTreeWitness, note_encryption::sapling_ka_agree, + redjubjub::{self, Signature}, sapling::{merkle_hash, spend_sig}, transaction::components::Amount, zip32, JUBJUB, diff --git a/librustzcash/src/tests/signatures.rs b/librustzcash/src/tests/signatures.rs index 2b28437..034b05a 100644 --- a/librustzcash/src/tests/signatures.rs +++ b/librustzcash/src/tests/signatures.rs @@ -1,9 +1,7 @@ use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::Bls12; -use sapling_crypto::{ - jubjub::{FixedGenerators, JubjubEngine}, - redjubjub::{PrivateKey, PublicKey, Signature}, -}; +use sapling_crypto::jubjub::{FixedGenerators, JubjubEngine}; +use zcash_primitives::redjubjub::{PrivateKey, PublicKey, Signature}; use super::JUBJUB; diff --git a/sapling-crypto/src/lib.rs b/sapling-crypto/src/lib.rs index 14e713d..3662629 100644 --- a/sapling-crypto/src/lib.rs +++ b/sapling-crypto/src/lib.rs @@ -23,5 +23,3 @@ pub mod circuit; pub mod pedersen_hash; pub mod primitives; pub mod constants; -pub mod redjubjub; -pub mod util; diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index ba724be..49b1b7d 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -20,3 +20,6 @@ rand_core = "0.5" rand_os = "0.2" sapling-crypto = { path = "../sapling-crypto" } sha2 = "0.8" + +[dev-dependencies] +rand_xorshift = "0.2" diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index a95d000..771f13d 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -15,6 +15,9 @@ extern crate rand_os; extern crate sapling_crypto; extern crate sha2; +#[cfg(test)] +extern crate rand_xorshift; + use sapling_crypto::jubjub::JubjubBls12; pub mod block; @@ -23,9 +26,11 @@ pub mod legacy; pub mod merkle_tree; pub mod note_encryption; pub mod prover; +pub mod redjubjub; pub mod sapling; mod serialize; pub mod transaction; +mod util; pub mod zip32; #[cfg(test)] diff --git a/zcash_primitives/src/prover.rs b/zcash_primitives/src/prover.rs index 1d40965..a4af8d4 100644 --- a/zcash_primitives/src/prover.rs +++ b/zcash_primitives/src/prover.rs @@ -4,11 +4,11 @@ use pairing::bls12_381::{Bls12, Fr}; use sapling_crypto::{ jubjub::{edwards, fs::Fs, Unknown}, primitives::{Diversifier, PaymentAddress, ProofGenerationKey}, - redjubjub::{PublicKey, Signature}, }; use crate::{ merkle_tree::CommitmentTreeWitness, + redjubjub::{PublicKey, Signature}, sapling::Node, transaction::components::{Amount, GROTH_PROOF_SIZE}, }; @@ -78,11 +78,11 @@ pub(crate) mod mock { use sapling_crypto::{ jubjub::{edwards, fs::Fs, FixedGenerators, Unknown}, primitives::{Diversifier, PaymentAddress, ProofGenerationKey, ValueCommitment}, - redjubjub::{PublicKey, Signature}, }; use crate::{ merkle_tree::CommitmentTreeWitness, + redjubjub::{PublicKey, Signature}, sapling::Node, transaction::components::{Amount, GROTH_PROOF_SIZE}, JUBJUB, diff --git a/sapling-crypto/src/redjubjub.rs b/zcash_primitives/src/redjubjub.rs similarity index 98% rename from sapling-crypto/src/redjubjub.rs rename to zcash_primitives/src/redjubjub.rs index cd02347..955c7e3 100644 --- a/sapling-crypto/src/redjubjub.rs +++ b/zcash_primitives/src/redjubjub.rs @@ -3,10 +3,12 @@ use ff::{Field, PrimeField, PrimeFieldRepr}; use rand_core::RngCore; +use sapling_crypto::jubjub::{ + edwards::Point, FixedGenerators, JubjubEngine, JubjubParams, Unknown, +}; use std::io::{self, Read, Write}; -use jubjub::{FixedGenerators, JubjubEngine, JubjubParams, Unknown, edwards::Point}; -use util::{hash_to_scalar}; +use util::hash_to_scalar; fn read_scalar(reader: R) -> io::Result { let mut s_repr = ::Repr::default(); @@ -208,8 +210,7 @@ mod tests { use pairing::bls12_381::Bls12; use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; - - use jubjub::{JubjubBls12, fs::Fs, edwards}; + use sapling_crypto::jubjub::{edwards, fs::Fs, JubjubBls12}; use super::*; diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index bd981e6..002cc1a 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -7,11 +7,11 @@ use sapling_crypto::{ jubjub::{fs::Fs, FixedGenerators, JubjubBls12}, pedersen_hash::{pedersen_hash, Personalization}, primitives::Note, - redjubjub::{PrivateKey, PublicKey, Signature}, }; use std::io::{self, Read, Write}; use crate::merkle_tree::Hashable; +use crate::redjubjub::{PrivateKey, PublicKey, Signature}; use JUBJUB; pub(crate) const SAPLING_COMMITMENT_TREE_DEPTH: usize = diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index a3134c3..792582d 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -6,7 +6,6 @@ use rand::{rngs::OsRng, seq::SliceRandom, CryptoRng, RngCore}; use sapling_crypto::{ jubjub::fs::Fs, primitives::{Diversifier, Note, PaymentAddress}, - redjubjub::PrivateKey, }; use zip32::ExtendedSpendingKey; @@ -16,6 +15,7 @@ use crate::{ merkle_tree::{CommitmentTreeWitness, IncrementalWitness}, note_encryption::{generate_esk, Memo, SaplingNoteEncryption}, prover::TxProver, + redjubjub::PrivateKey, sapling::{spend_sig, Node}, transaction::{ components::{amount::DEFAULT_FEE, Amount, OutputDescription, SpendDescription, TxOut}, diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index d50b4fb..1785344 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -1,13 +1,11 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; -use sapling_crypto::{ - jubjub::{edwards, Unknown}, - redjubjub::{PublicKey, Signature}, -}; +use sapling_crypto::jubjub::{edwards, Unknown}; use std::io::{self, Read, Write}; use legacy::Script; +use redjubjub::{PublicKey, Signature}; use JUBJUB; pub mod amount; diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index a8ecb17..6e2d15f 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -1,11 +1,11 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use hex; -use sapling_crypto::redjubjub::Signature; use sha2::{Digest, Sha256}; use std::fmt; use std::io::{self, Read, Write}; use std::ops::Deref; +use redjubjub::Signature; use serialize::Vector; pub mod builder; diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index 4cd5d72..041ac21 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -1,13 +1,11 @@ use ff::Field; use pairing::bls12_381::Bls12; use rand_os::OsRng; -use sapling_crypto::{ - jubjub::{fs::Fs, FixedGenerators}, - redjubjub::PrivateKey, -}; +use sapling_crypto::jubjub::{fs::Fs, FixedGenerators}; use super::{components::Amount, sighash::signature_hash, Transaction, TransactionData}; use legacy::Script; +use redjubjub::PrivateKey; use JUBJUB; #[test] diff --git a/sapling-crypto/src/util.rs b/zcash_primitives/src/util.rs similarity index 84% rename from sapling-crypto/src/util.rs rename to zcash_primitives/src/util.rs index 1e759ba..f46e0a2 100644 --- a/sapling-crypto/src/util.rs +++ b/zcash_primitives/src/util.rs @@ -1,6 +1,5 @@ use blake2b_simd::Params; - -use jubjub::{JubjubEngine, ToUniform}; +use sapling_crypto::jubjub::{JubjubEngine, ToUniform}; pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> E::Fs { let mut hasher = Params::new().hash_length(64).personal(persona).to_state(); diff --git a/zcash_proofs/src/prover.rs b/zcash_proofs/src/prover.rs index 4b5b0f4..c59ba62 100644 --- a/zcash_proofs/src/prover.rs +++ b/zcash_proofs/src/prover.rs @@ -6,12 +6,12 @@ use pairing::bls12_381::{Bls12, Fr}; use sapling_crypto::{ jubjub::{edwards, fs::Fs, Unknown}, primitives::{Diversifier, PaymentAddress, ProofGenerationKey}, - redjubjub::{PublicKey, Signature}, }; use std::path::Path; use zcash_primitives::{ merkle_tree::CommitmentTreeWitness, prover::TxProver, + redjubjub::{PublicKey, Signature}, sapling::Node, transaction::components::{Amount, GROTH_PROOF_SIZE}, JUBJUB, diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index 4b5a5f4..3d30524 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -11,10 +11,12 @@ use sapling_crypto::{ }, jubjub::{edwards, fs::Fs, FixedGenerators, JubjubBls12, Unknown}, primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, - redjubjub::{PrivateKey, PublicKey, Signature}, }; use zcash_primitives::{ - merkle_tree::CommitmentTreeWitness, sapling::Node, transaction::components::Amount, + merkle_tree::CommitmentTreeWitness, + redjubjub::{PrivateKey, PublicKey, Signature}, + sapling::Node, + transaction::components::Amount, }; use super::compute_value_balance; diff --git a/zcash_proofs/src/sapling/verifier.rs b/zcash_proofs/src/sapling/verifier.rs index 47fc9fe..ac4f3f7 100644 --- a/zcash_proofs/src/sapling/verifier.rs +++ b/zcash_proofs/src/sapling/verifier.rs @@ -4,9 +4,11 @@ use pairing::bls12_381::{Bls12, Fr}; use sapling_crypto::{ circuit::multipack, jubjub::{edwards, FixedGenerators, JubjubBls12, Unknown}, - redjubjub::{PublicKey, Signature}, }; -use zcash_primitives::transaction::components::Amount; +use zcash_primitives::{ + redjubjub::{PublicKey, Signature}, + transaction::components::Amount, +}; use super::compute_value_balance; From 2ae5804a679aea51128050ab3f5aa94e770fbd98 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 5 Aug 2019 22:45:12 +0100 Subject: [PATCH 068/330] Move Sprout and Sapling circuits into zcash_proofs --- Cargo.lock | 2 + librustzcash/src/rustzcash.rs | 4 +- sapling-crypto/src/circuit/mod.rs | 6 +- zcash_primitives/src/sapling.rs | 3 +- zcash_proofs/Cargo.toml | 4 ++ .../examples/bench.rs | 3 +- zcash_proofs/src/circuit.rs | 2 + .../src/circuit/sapling.rs | 52 ++++++++++-------- .../src/circuit/sprout/commitment.rs | 4 +- .../src/circuit/sprout/input.rs | 4 +- .../src/circuit/sprout/mod.rs | 8 +-- .../src/circuit/sprout/output.rs | 2 +- .../src/circuit/sprout/prfs.rs | 4 +- .../src/circuit/sprout/test_vectors.dat | Bin zcash_proofs/src/lib.rs | 7 +++ zcash_proofs/src/sapling/prover.rs | 6 +- 16 files changed, 63 insertions(+), 48 deletions(-) rename {sapling-crypto => zcash_proofs}/examples/bench.rs (97%) create mode 100644 zcash_proofs/src/circuit.rs rename sapling-crypto/src/circuit/sapling/mod.rs => zcash_proofs/src/circuit/sapling.rs (95%) rename {sapling-crypto => zcash_proofs}/src/circuit/sprout/commitment.rs (92%) rename {sapling-crypto => zcash_proofs}/src/circuit/sprout/input.rs (98%) rename {sapling-crypto => zcash_proofs}/src/circuit/sprout/mod.rs (98%) rename {sapling-crypto => zcash_proofs}/src/circuit/sprout/output.rs (95%) rename {sapling-crypto => zcash_proofs}/src/circuit/sprout/prfs.rs (95%) rename {sapling-crypto => zcash_proofs}/src/circuit/sprout/test_vectors.dat (100%) diff --git a/Cargo.lock b/Cargo.lock index 53bc275..3bc3137 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -567,7 +567,9 @@ dependencies = [ "directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "pairing 0.14.2", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", ] diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index bff8093..92f8d04 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -26,8 +26,8 @@ use sapling_crypto::{ }, }; -use sapling_crypto::circuit::sapling::TREE_DEPTH as SAPLING_TREE_DEPTH; -use sapling_crypto::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH}; +use zcash_proofs::circuit::sapling::TREE_DEPTH as SAPLING_TREE_DEPTH; +use zcash_proofs::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH}; use bellman::groth16::{ create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof, diff --git a/sapling-crypto/src/circuit/mod.rs b/sapling-crypto/src/circuit/mod.rs index fe0fe50..4902f67 100644 --- a/sapling-crypto/src/circuit/mod.rs +++ b/sapling-crypto/src/circuit/mod.rs @@ -1,4 +1,3 @@ -#[cfg(test)] pub mod test; pub mod boolean; @@ -12,9 +11,6 @@ pub mod pedersen_hash; pub mod multipack; pub mod sha256; -pub mod sapling; -pub mod sprout; - use bellman::{ SynthesisError }; @@ -25,7 +21,7 @@ use bellman::{ /// This basically is just an extension to `Option` /// which allows for a convenient mapping to an /// error on `None`. -trait Assignment { +pub trait Assignment { fn get(&self) -> Result<&T, SynthesisError>; } diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index 002cc1a..0b94e4e 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -14,8 +14,7 @@ use crate::merkle_tree::Hashable; use crate::redjubjub::{PrivateKey, PublicKey, Signature}; use JUBJUB; -pub(crate) const SAPLING_COMMITMENT_TREE_DEPTH: usize = - sapling_crypto::circuit::sapling::TREE_DEPTH; +pub const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32; /// Compute a parent node in the Sapling commitment tree given its two children. pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr { diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index 598e013..fdb0bf8 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -16,6 +16,10 @@ rand_os = "0.2" sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } +[dev-dependencies] +rand_core = "0.5" +rand_xorshift = "0.2" + [features] default = ["local-prover"] local-prover = ["directories"] diff --git a/sapling-crypto/examples/bench.rs b/zcash_proofs/examples/bench.rs similarity index 97% rename from sapling-crypto/examples/bench.rs rename to zcash_proofs/examples/bench.rs index e9ffc13..9adf028 100644 --- a/sapling-crypto/examples/bench.rs +++ b/zcash_proofs/examples/bench.rs @@ -4,6 +4,7 @@ extern crate bellman; extern crate pairing; extern crate rand_core; extern crate rand_xorshift; +extern crate zcash_proofs; use ff::Field; use std::time::{Duration, Instant}; @@ -12,7 +13,7 @@ use sapling_crypto::jubjub::{ edwards, fs, }; -use sapling_crypto::circuit::sapling::{ +use zcash_proofs::circuit::sapling::{ Spend }; use sapling_crypto::primitives::{ diff --git a/zcash_proofs/src/circuit.rs b/zcash_proofs/src/circuit.rs new file mode 100644 index 0000000..85fa1cf --- /dev/null +++ b/zcash_proofs/src/circuit.rs @@ -0,0 +1,2 @@ +pub mod sapling; +pub mod sprout; diff --git a/sapling-crypto/src/circuit/sapling/mod.rs b/zcash_proofs/src/circuit/sapling.rs similarity index 95% rename from sapling-crypto/src/circuit/sapling/mod.rs rename to zcash_proofs/src/circuit/sapling.rs index 469ab2e..64bf163 100644 --- a/sapling-crypto/src/circuit/sapling/mod.rs +++ b/zcash_proofs/src/circuit/sapling.rs @@ -6,28 +6,28 @@ use bellman::{ Circuit }; -use jubjub::{ +use sapling_crypto::jubjub::{ JubjubEngine, FixedGenerators }; -use constants; +use sapling_crypto::constants; -use primitives::{ +use sapling_crypto::primitives::{ ValueCommitment, ProofGenerationKey, PaymentAddress }; -use super::Assignment; -use super::boolean; -use super::ecc; -use super::pedersen_hash; -use super::blake2s; -use super::num; -use super::multipack; +use sapling_crypto::circuit::Assignment; +use sapling_crypto::circuit::boolean; +use sapling_crypto::circuit::ecc; +use sapling_crypto::circuit::pedersen_hash; +use sapling_crypto::circuit::blake2s; +use sapling_crypto::circuit::num; +use sapling_crypto::circuit::multipack; -pub const TREE_DEPTH: usize = 32; +pub const TREE_DEPTH: usize = zcash_primitives::sapling::SAPLING_COMMITMENT_TREE_DEPTH; /// This is an instance of the `Spend` circuit. pub struct Spend<'a, E: JubjubEngine> { @@ -602,9 +602,12 @@ fn test_input_circuit_with_bls12_381() { use pairing::bls12_381::*; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; - - use ::circuit::test::*; - use jubjub::{JubjubBls12, fs, edwards}; + use sapling_crypto::{ + circuit::test::*, + jubjub::{JubjubBls12, fs, edwards}, + pedersen_hash, + primitives::{Diversifier, Note, ProofGenerationKey}, + }; let params = &JubjubBls12::new(); let rng = &mut XorShiftRng::from_seed([ @@ -623,7 +626,7 @@ fn test_input_circuit_with_bls12_381() { let nsk = fs::Fs::random(rng); let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params); - let proof_generation_key = ::primitives::ProofGenerationKey { + let proof_generation_key = ProofGenerationKey { ak: ak.clone(), nsk: nsk.clone() }; @@ -636,7 +639,7 @@ fn test_input_circuit_with_bls12_381() { let diversifier = { let mut d = [0; 11]; rng.fill_bytes(&mut d); - ::primitives::Diversifier(d) + Diversifier(d) }; if let Some(p) = viewing_key.into_payment_address( @@ -657,7 +660,7 @@ fn test_input_circuit_with_bls12_381() { { let rk = viewing_key.rk(ar, params).into_xy(); let expected_value_cm = value_commitment.cm(params).into_xy(); - let note = ::primitives::Note { + let note = Note { value: value_commitment.value, g_d: g_d.clone(), pk_d: payment_address.pk_d.clone(), @@ -685,8 +688,8 @@ fn test_input_circuit_with_bls12_381() { lhs.reverse(); rhs.reverse(); - cur = ::pedersen_hash::pedersen_hash::( - ::pedersen_hash::Personalization::MerkleTree(i), + cur = pedersen_hash::pedersen_hash::( + pedersen_hash::Personalization::MerkleTree(i), lhs.into_iter() .take(Fr::NUM_BITS as usize) .chain(rhs.into_iter().take(Fr::NUM_BITS as usize)), @@ -743,8 +746,11 @@ fn test_output_circuit_with_bls12_381() { use pairing::bls12_381::*; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; - use ::circuit::test::*; - use jubjub::{JubjubBls12, fs, edwards}; + use sapling_crypto::{ + circuit::test::*, + jubjub::{JubjubBls12, fs, edwards}, + primitives::{Diversifier, ProofGenerationKey}, + }; let params = &JubjubBls12::new(); let rng = &mut XorShiftRng::from_seed([ @@ -761,7 +767,7 @@ fn test_output_circuit_with_bls12_381() { let nsk = fs::Fs::random(rng); let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params); - let proof_generation_key = ::primitives::ProofGenerationKey { + let proof_generation_key = ProofGenerationKey { ak: ak.clone(), nsk: nsk.clone() }; @@ -774,7 +780,7 @@ fn test_output_circuit_with_bls12_381() { let diversifier = { let mut d = [0; 11]; rng.fill_bytes(&mut d); - ::primitives::Diversifier(d) + Diversifier(d) }; if let Some(p) = viewing_key.into_payment_address( diff --git a/sapling-crypto/src/circuit/sprout/commitment.rs b/zcash_proofs/src/circuit/sprout/commitment.rs similarity index 92% rename from sapling-crypto/src/circuit/sprout/commitment.rs rename to zcash_proofs/src/circuit/sprout/commitment.rs index a32f05c..4d9f00b 100644 --- a/sapling-crypto/src/circuit/sprout/commitment.rs +++ b/zcash_proofs/src/circuit/sprout/commitment.rs @@ -1,9 +1,9 @@ use pairing::{Engine}; use bellman::{ConstraintSystem, SynthesisError}; -use circuit::sha256::{ +use sapling_crypto::circuit::sha256::{ sha256 }; -use circuit::boolean::{ +use sapling_crypto::circuit::boolean::{ Boolean }; diff --git a/sapling-crypto/src/circuit/sprout/input.rs b/zcash_proofs/src/circuit/sprout/input.rs similarity index 98% rename from sapling-crypto/src/circuit/sprout/input.rs rename to zcash_proofs/src/circuit/sprout/input.rs index ce69bc0..e12723a 100644 --- a/sapling-crypto/src/circuit/sprout/input.rs +++ b/zcash_proofs/src/circuit/sprout/input.rs @@ -1,9 +1,9 @@ use pairing::{Engine}; use bellman::{ConstraintSystem, SynthesisError}; -use circuit::sha256::{ +use sapling_crypto::circuit::sha256::{ sha256_block_no_padding }; -use circuit::boolean::{ +use sapling_crypto::circuit::boolean::{ AllocatedBit, Boolean }; diff --git a/sapling-crypto/src/circuit/sprout/mod.rs b/zcash_proofs/src/circuit/sprout/mod.rs similarity index 98% rename from sapling-crypto/src/circuit/sprout/mod.rs rename to zcash_proofs/src/circuit/sprout/mod.rs index 7027b4a..db2ea0d 100644 --- a/sapling-crypto/src/circuit/sprout/mod.rs +++ b/zcash_proofs/src/circuit/sprout/mod.rs @@ -1,11 +1,11 @@ use ff::Field; use pairing::Engine; use bellman::{ConstraintSystem, SynthesisError, Circuit, LinearCombination}; -use circuit::boolean::{ +use sapling_crypto::circuit::boolean::{ AllocatedBit, Boolean }; -use circuit::multipack::pack_into_inputs; +use sapling_crypto::circuit::multipack::pack_into_inputs; mod prfs; mod commitment; @@ -355,7 +355,7 @@ fn witness_u252( #[test] fn test_sprout_constraints() { use pairing::bls12_381::{Bls12}; - use ::circuit::test::*; + use sapling_crypto::circuit::test::*; use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian}; @@ -479,7 +479,7 @@ fn test_sprout_constraints() { expected_inputs.write_u64::(vpub_old.unwrap()).unwrap(); expected_inputs.write_u64::(vpub_new.unwrap()).unwrap(); - use circuit::multipack; + use sapling_crypto::circuit::multipack; let expected_inputs = multipack::bytes_to_bits(&expected_inputs); let expected_inputs = multipack::compute_multipacking::(&expected_inputs); diff --git a/sapling-crypto/src/circuit/sprout/output.rs b/zcash_proofs/src/circuit/sprout/output.rs similarity index 95% rename from sapling-crypto/src/circuit/sprout/output.rs rename to zcash_proofs/src/circuit/sprout/output.rs index 9cdbf52..65bcd49 100644 --- a/sapling-crypto/src/circuit/sprout/output.rs +++ b/zcash_proofs/src/circuit/sprout/output.rs @@ -1,6 +1,6 @@ use pairing::{Engine}; use bellman::{ConstraintSystem, SynthesisError}; -use circuit::boolean::{Boolean}; +use sapling_crypto::circuit::boolean::{Boolean}; use super::*; use super::prfs::*; diff --git a/sapling-crypto/src/circuit/sprout/prfs.rs b/zcash_proofs/src/circuit/sprout/prfs.rs similarity index 95% rename from sapling-crypto/src/circuit/sprout/prfs.rs rename to zcash_proofs/src/circuit/sprout/prfs.rs index fff8648..53f65a0 100644 --- a/sapling-crypto/src/circuit/sprout/prfs.rs +++ b/zcash_proofs/src/circuit/sprout/prfs.rs @@ -1,9 +1,9 @@ use pairing::{Engine}; use bellman::{ConstraintSystem, SynthesisError}; -use circuit::sha256::{ +use sapling_crypto::circuit::sha256::{ sha256_block_no_padding }; -use circuit::boolean::{ +use sapling_crypto::circuit::boolean::{ Boolean }; diff --git a/sapling-crypto/src/circuit/sprout/test_vectors.dat b/zcash_proofs/src/circuit/sprout/test_vectors.dat similarity index 100% rename from sapling-crypto/src/circuit/sprout/test_vectors.dat rename to zcash_proofs/src/circuit/sprout/test_vectors.dat diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs index d2dc877..2a3c8f2 100644 --- a/zcash_proofs/src/lib.rs +++ b/zcash_proofs/src/lib.rs @@ -10,12 +10,19 @@ extern crate zcash_primitives; #[cfg(feature = "local-prover")] extern crate directories; +#[cfg(test)] +extern crate rand_core; + +#[cfg(test)] +extern crate rand_xorshift; + use bellman::groth16::{prepare_verifying_key, Parameters, PreparedVerifyingKey, VerifyingKey}; use pairing::bls12_381::Bls12; use std::fs::File; use std::io::{self, BufReader}; use std::path::Path; +pub mod circuit; mod hashreader; pub mod sapling; diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index 3d30524..78958ad 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -5,10 +5,7 @@ use ff::Field; use pairing::bls12_381::{Bls12, Fr}; use rand_os::OsRng; use sapling_crypto::{ - circuit::{ - multipack, - sapling::{Output, Spend}, - }, + circuit::multipack, jubjub::{edwards, fs::Fs, FixedGenerators, JubjubBls12, Unknown}, primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, }; @@ -20,6 +17,7 @@ use zcash_primitives::{ }; use super::compute_value_balance; +use crate::circuit::sapling::{Output, Spend}; /// A context object for creating the Sapling components of a Zcash transaction. pub struct SaplingProvingContext { From 61c633db1e3098071d4b9167874686a711501649 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 6 Aug 2019 00:48:36 +0100 Subject: [PATCH 069/330] Move Jubjub and Pedersen hash gadgets into zcash_proofs These are currently too Zcash-specific to be generalized, and need some targeted refactoring. --- sapling-crypto/src/circuit/mod.rs | 2 -- zcash_proofs/src/circuit.rs | 3 ++ .../src/circuit/ecc.rs | 19 +++++++------ .../src/circuit/pedersen_hash.rs | 28 +++++++++---------- zcash_proofs/src/circuit/sapling.rs | 4 +-- 5 files changed, 28 insertions(+), 28 deletions(-) rename {sapling-crypto => zcash_proofs}/src/circuit/ecc.rs (99%) rename {sapling-crypto => zcash_proofs}/src/circuit/pedersen_hash.rs (90%) diff --git a/sapling-crypto/src/circuit/mod.rs b/sapling-crypto/src/circuit/mod.rs index 4902f67..016f33e 100644 --- a/sapling-crypto/src/circuit/mod.rs +++ b/sapling-crypto/src/circuit/mod.rs @@ -6,8 +6,6 @@ pub mod uint32; pub mod blake2s; pub mod num; pub mod lookup; -pub mod ecc; -pub mod pedersen_hash; pub mod multipack; pub mod sha256; diff --git a/zcash_proofs/src/circuit.rs b/zcash_proofs/src/circuit.rs index 85fa1cf..ac7e74c 100644 --- a/zcash_proofs/src/circuit.rs +++ b/zcash_proofs/src/circuit.rs @@ -1,2 +1,5 @@ +pub mod ecc; +pub mod pedersen_hash; + pub mod sapling; pub mod sprout; diff --git a/sapling-crypto/src/circuit/ecc.rs b/zcash_proofs/src/circuit/ecc.rs similarity index 99% rename from sapling-crypto/src/circuit/ecc.rs rename to zcash_proofs/src/circuit/ecc.rs index 9b4dbbc..e6cba96 100644 --- a/sapling-crypto/src/circuit/ecc.rs +++ b/zcash_proofs/src/circuit/ecc.rs @@ -6,27 +6,27 @@ use bellman::{ ConstraintSystem }; -use super::{ +use sapling_crypto::circuit::{ Assignment }; -use super::num::{ +use sapling_crypto::circuit::num::{ AllocatedNum, Num }; -use ::jubjub::{ +use sapling_crypto::jubjub::{ edwards, JubjubEngine, JubjubParams, FixedGenerators }; -use super::lookup::{ +use sapling_crypto::circuit::lookup::{ lookup3_xy }; -use super::boolean::Boolean; +use sapling_crypto::circuit::boolean::Boolean; #[derive(Clone)] pub struct EdwardsPoint { @@ -753,22 +753,23 @@ mod test { use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; - use ::circuit::test::*; - use ::jubjub::{ + use sapling_crypto::circuit::test::*; + use sapling_crypto::jubjub::{ montgomery, edwards, JubjubBls12, JubjubParams, FixedGenerators }; - use ::jubjub::fs::Fs; + use sapling_crypto::jubjub::fs::Fs; + use super::{ MontgomeryPoint, EdwardsPoint, AllocatedNum, fixed_base_multiplication }; - use super::super::boolean::{ + use sapling_crypto::circuit::boolean::{ Boolean, AllocatedBit }; diff --git a/sapling-crypto/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs similarity index 90% rename from sapling-crypto/src/circuit/pedersen_hash.rs rename to zcash_proofs/src/circuit/pedersen_hash.rs index dd000d3..bbaf999 100644 --- a/sapling-crypto/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -1,23 +1,20 @@ -use super::*; use super::ecc::{ MontgomeryPoint, EdwardsPoint }; -use super::boolean::Boolean; -use ::jubjub::*; +use sapling_crypto::circuit::boolean::Boolean; +use sapling_crypto::jubjub::*; use bellman::{ - ConstraintSystem + ConstraintSystem, SynthesisError }; -use super::lookup::*; -pub use pedersen_hash::Personalization; +use sapling_crypto::circuit::lookup::*; +pub use sapling_crypto::pedersen_hash::Personalization; -impl Personalization { - fn get_constant_bools(&self) -> Vec { - self.get_bits() +fn get_constant_bools(person: &Personalization) -> Vec { + person.get_bits() .into_iter() .map(|e| Boolean::constant(e)) .collect() - } } pub fn pedersen_hash( @@ -28,7 +25,7 @@ pub fn pedersen_hash( ) -> Result, SynthesisError> where CS: ConstraintSystem { - let personalization = personalization.get_constant_bools(); + let personalization = get_constant_bools(&personalization); assert_eq!(personalization.len(), 6); let mut edwards_result = None; @@ -113,8 +110,9 @@ pub fn pedersen_hash( #[cfg(test)] mod test { use super::*; - use ::circuit::test::*; - use ::circuit::boolean::{Boolean, AllocatedBit}; + use sapling_crypto::circuit::test::*; + use sapling_crypto::circuit::boolean::{Boolean, AllocatedBit}; + use sapling_crypto::pedersen_hash; use ff::PrimeField; use pairing::bls12_381::{Bls12, Fr}; use rand_core::{RngCore, SeedableRng}; @@ -177,7 +175,7 @@ mod test { assert!(cs.is_satisfied()); - let expected = ::pedersen_hash::pedersen_hash::( + let expected = pedersen_hash::pedersen_hash::( Personalization::MerkleTree(1), input.clone().into_iter(), params @@ -187,7 +185,7 @@ mod test { assert_eq!(res.get_y().get_value().unwrap(), expected.1); // Test against the output of a different personalization - let unexpected = ::pedersen_hash::pedersen_hash::( + let unexpected = pedersen_hash::pedersen_hash::( Personalization::MerkleTree(0), input.into_iter(), params diff --git a/zcash_proofs/src/circuit/sapling.rs b/zcash_proofs/src/circuit/sapling.rs index 64bf163..1fc6e6c 100644 --- a/zcash_proofs/src/circuit/sapling.rs +++ b/zcash_proofs/src/circuit/sapling.rs @@ -21,8 +21,8 @@ use sapling_crypto::primitives::{ use sapling_crypto::circuit::Assignment; use sapling_crypto::circuit::boolean; -use sapling_crypto::circuit::ecc; -use sapling_crypto::circuit::pedersen_hash; +use super::ecc; +use super::pedersen_hash; use sapling_crypto::circuit::blake2s; use sapling_crypto::circuit::num; use sapling_crypto::circuit::multipack; From b8af749b4019da2cb1b85d797f9b7b10f5f13e4b Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 6 Aug 2019 01:13:35 +0100 Subject: [PATCH 070/330] Move generic circuit gadgets into bellman --- Cargo.lock | 4 ++++ bellman/Cargo.toml | 4 ++++ .../src/circuit/mod.rs => bellman/src/gadgets.rs | 2 +- .../src/circuit => bellman/src/gadgets}/blake2s.rs | 8 ++++---- .../src/circuit => bellman/src/gadgets}/boolean.rs | 6 +++--- .../src/circuit => bellman/src/gadgets}/lookup.rs | 6 +++--- .../src/circuit => bellman/src/gadgets}/multieq.rs | 2 +- .../circuit => bellman/src/gadgets}/multipack.rs | 6 +++--- .../src/circuit => bellman/src/gadgets}/num.rs | 6 +++--- .../src/circuit => bellman/src/gadgets}/sha256.rs | 6 +++--- .../circuit => bellman/src/gadgets}/test/mod.rs | 2 +- .../src/circuit => bellman/src/gadgets}/uint32.rs | 10 +++++----- bellman/src/lib.rs | 12 ++++++++++++ librustzcash/src/rustzcash.rs | 2 +- sapling-crypto/src/lib.rs | 1 - zcash_proofs/src/circuit/ecc.rs | 12 ++++++------ zcash_proofs/src/circuit/pedersen_hash.rs | 8 ++++---- zcash_proofs/src/circuit/sapling.rs | 14 +++++++------- zcash_proofs/src/circuit/sprout/commitment.rs | 4 ++-- zcash_proofs/src/circuit/sprout/input.rs | 4 ++-- zcash_proofs/src/circuit/sprout/mod.rs | 8 ++++---- zcash_proofs/src/circuit/sprout/output.rs | 2 +- zcash_proofs/src/circuit/sprout/prfs.rs | 4 ++-- zcash_proofs/src/sapling/prover.rs | 8 +++++--- zcash_proofs/src/sapling/verifier.rs | 10 +++++----- 25 files changed, 86 insertions(+), 65 deletions(-) rename sapling-crypto/src/circuit/mod.rs => bellman/src/gadgets.rs (97%) rename {sapling-crypto/src/circuit => bellman/src/gadgets}/blake2s.rs (99%) rename {sapling-crypto/src/circuit => bellman/src/gadgets}/boolean.rs (99%) rename {sapling-crypto/src/circuit => bellman/src/gadgets}/lookup.rs (98%) rename {sapling-crypto/src/circuit => bellman/src/gadgets}/multieq.rs (99%) rename {sapling-crypto/src/circuit => bellman/src/gadgets}/multipack.rs (96%) rename {sapling-crypto/src/circuit => bellman/src/gadgets}/num.rs (99%) rename {sapling-crypto/src/circuit => bellman/src/gadgets}/sha256.rs (98%) rename {sapling-crypto/src/circuit => bellman/src/gadgets}/test/mod.rs (99%) rename {sapling-crypto/src/circuit => bellman/src/gadgets}/uint32.rs (99%) diff --git a/Cargo.lock b/Cargo.lock index 3bc3137..670966e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,16 +57,20 @@ name = "bellman" version = "0.1.0" dependencies = [ "bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2s_simd 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "group 0.1.0", + "hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/bellman/Cargo.toml b/bellman/Cargo.toml index b15671e..70521e7 100644 --- a/bellman/Cargo.toml +++ b/bellman/Cargo.toml @@ -10,6 +10,7 @@ version = "0.1.0" [dependencies] bit-vec = "0.4.4" +blake2s_simd = "0.5" ff = { path = "../ff" } futures = "0.1" futures-cpupool = { version = "0.1", optional = true } @@ -21,7 +22,10 @@ rand_core = "0.5" byteorder = "1" [dev-dependencies] +hex-literal = "0.1" rand = "0.7" +rand_xorshift = "0.2" +sha2 = "0.8" [features] groth16 = ["pairing"] diff --git a/sapling-crypto/src/circuit/mod.rs b/bellman/src/gadgets.rs similarity index 97% rename from sapling-crypto/src/circuit/mod.rs rename to bellman/src/gadgets.rs index 016f33e..6c4b09c 100644 --- a/sapling-crypto/src/circuit/mod.rs +++ b/bellman/src/gadgets.rs @@ -9,7 +9,7 @@ pub mod lookup; pub mod multipack; pub mod sha256; -use bellman::{ +use crate::{ SynthesisError }; diff --git a/sapling-crypto/src/circuit/blake2s.rs b/bellman/src/gadgets/blake2s.rs similarity index 99% rename from sapling-crypto/src/circuit/blake2s.rs rename to bellman/src/gadgets/blake2s.rs index 8627dc0..cef50eb 100644 --- a/sapling-crypto/src/circuit/blake2s.rs +++ b/bellman/src/gadgets/blake2s.rs @@ -2,7 +2,7 @@ use pairing::{ Engine, }; -use bellman::{ +use crate::{ SynthesisError, ConstraintSystem }; @@ -325,10 +325,10 @@ mod test { use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; - use ::circuit::boolean::{Boolean, AllocatedBit}; - use ::circuit::test::TestConstraintSystem; + use crate::gadgets::boolean::{Boolean, AllocatedBit}; + use crate::gadgets::test::TestConstraintSystem; use super::blake2s; - use bellman::{ConstraintSystem}; + use crate::{ConstraintSystem}; #[test] fn test_blank_hash() { diff --git a/sapling-crypto/src/circuit/boolean.rs b/bellman/src/gadgets/boolean.rs similarity index 99% rename from sapling-crypto/src/circuit/boolean.rs rename to bellman/src/gadgets/boolean.rs index 2fe6ef1..f6c11b6 100644 --- a/sapling-crypto/src/circuit/boolean.rs +++ b/bellman/src/gadgets/boolean.rs @@ -1,7 +1,7 @@ use ff::{BitIterator, Field, PrimeField}; use pairing::Engine; -use bellman::{ +use crate::{ ConstraintSystem, SynthesisError, LinearCombination, @@ -801,10 +801,10 @@ impl From for Boolean { #[cfg(test)] mod test { - use bellman::{ConstraintSystem}; + use crate::{ConstraintSystem}; use ff::{Field, PrimeField}; use pairing::bls12_381::{Bls12, Fr}; - use ::circuit::test::*; + use crate::gadgets::test::*; use super::{ AllocatedBit, Boolean, diff --git a/sapling-crypto/src/circuit/lookup.rs b/bellman/src/gadgets/lookup.rs similarity index 98% rename from sapling-crypto/src/circuit/lookup.rs rename to bellman/src/gadgets/lookup.rs index d57f17c..86ab10f 100644 --- a/sapling-crypto/src/circuit/lookup.rs +++ b/bellman/src/gadgets/lookup.rs @@ -7,7 +7,7 @@ use super::num::{ Num }; use super::boolean::Boolean; -use bellman::{ +use crate::{ ConstraintSystem }; @@ -197,8 +197,8 @@ pub fn lookup3_xy_with_conditional_negation( #[cfg(test)] mod test { use super::*; - use ::circuit::test::*; - use ::circuit::boolean::{Boolean, AllocatedBit}; + use crate::gadgets::test::*; + use crate::gadgets::boolean::{Boolean, AllocatedBit}; use pairing::bls12_381::{Bls12, Fr}; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; diff --git a/sapling-crypto/src/circuit/multieq.rs b/bellman/src/gadgets/multieq.rs similarity index 99% rename from sapling-crypto/src/circuit/multieq.rs rename to bellman/src/gadgets/multieq.rs index 4cfc3b8..b1dfd7c 100644 --- a/sapling-crypto/src/circuit/multieq.rs +++ b/bellman/src/gadgets/multieq.rs @@ -1,7 +1,7 @@ use ff::{Field, PrimeField}; use pairing::Engine; -use bellman::{ +use crate::{ SynthesisError, ConstraintSystem, LinearCombination, diff --git a/sapling-crypto/src/circuit/multipack.rs b/bellman/src/gadgets/multipack.rs similarity index 96% rename from sapling-crypto/src/circuit/multipack.rs rename to bellman/src/gadgets/multipack.rs index fdecd34..b9b5877 100644 --- a/sapling-crypto/src/circuit/multipack.rs +++ b/bellman/src/gadgets/multipack.rs @@ -1,6 +1,6 @@ use ff::{Field, PrimeField}; use pairing::Engine; -use bellman::{ConstraintSystem, SynthesisError}; +use crate::{ConstraintSystem, SynthesisError}; use super::boolean::{Boolean}; use super::num::Num; use super::Assignment; @@ -80,12 +80,12 @@ pub fn compute_multipacking( #[test] fn test_multipacking() { - use bellman::{ConstraintSystem}; + use crate::{ConstraintSystem}; use pairing::bls12_381::{Bls12}; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; - use ::circuit::test::*; + use crate::gadgets::test::*; use super::boolean::{AllocatedBit, Boolean}; let mut rng = XorShiftRng::from_seed([ diff --git a/sapling-crypto/src/circuit/num.rs b/bellman/src/gadgets/num.rs similarity index 99% rename from sapling-crypto/src/circuit/num.rs rename to bellman/src/gadgets/num.rs index 1cdfe22..077301f 100644 --- a/sapling-crypto/src/circuit/num.rs +++ b/bellman/src/gadgets/num.rs @@ -1,7 +1,7 @@ use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr}; use pairing::Engine; -use bellman::{ +use crate::{ SynthesisError, ConstraintSystem, LinearCombination, @@ -455,13 +455,13 @@ impl Num { #[cfg(test)] mod test { - use bellman::{ConstraintSystem}; + use crate::{ConstraintSystem}; use ff::{BitIterator, Field, PrimeField}; use pairing::bls12_381::{Bls12, Fr}; use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; - use ::circuit::test::*; + use crate::gadgets::test::*; use super::{AllocatedNum, Boolean}; #[test] diff --git a/sapling-crypto/src/circuit/sha256.rs b/bellman/src/gadgets/sha256.rs similarity index 98% rename from sapling-crypto/src/circuit/sha256.rs rename to bellman/src/gadgets/sha256.rs index 3b32282..2e4669e 100644 --- a/sapling-crypto/src/circuit/sha256.rs +++ b/bellman/src/gadgets/sha256.rs @@ -1,7 +1,7 @@ use super::uint32::UInt32; use super::multieq::MultiEq; use super::boolean::Boolean; -use bellman::{ConstraintSystem, SynthesisError}; +use crate::{ConstraintSystem, SynthesisError}; use pairing::Engine; const ROUND_CONSTANTS: [u32; 64] = [ @@ -305,9 +305,9 @@ fn sha256_compression_function( #[cfg(test)] mod test { use super::*; - use circuit::boolean::AllocatedBit; + use crate::gadgets::boolean::AllocatedBit; use pairing::bls12_381::Bls12; - use circuit::test::TestConstraintSystem; + use crate::gadgets::test::TestConstraintSystem; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; diff --git a/sapling-crypto/src/circuit/test/mod.rs b/bellman/src/gadgets/test/mod.rs similarity index 99% rename from sapling-crypto/src/circuit/test/mod.rs rename to bellman/src/gadgets/test/mod.rs index 79d128a..dc6adbf 100644 --- a/sapling-crypto/src/circuit/test/mod.rs +++ b/bellman/src/gadgets/test/mod.rs @@ -1,7 +1,7 @@ use ff::{Field, PrimeField, PrimeFieldRepr}; use pairing::Engine; -use bellman::{ +use crate::{ LinearCombination, SynthesisError, ConstraintSystem, diff --git a/sapling-crypto/src/circuit/uint32.rs b/bellman/src/gadgets/uint32.rs similarity index 99% rename from sapling-crypto/src/circuit/uint32.rs rename to bellman/src/gadgets/uint32.rs index 939b544..90f8d7e 100644 --- a/sapling-crypto/src/circuit/uint32.rs +++ b/bellman/src/gadgets/uint32.rs @@ -1,7 +1,7 @@ use ff::{Field, PrimeField}; use pairing::Engine; -use bellman::{ +use crate::{ SynthesisError, ConstraintSystem, LinearCombination @@ -409,13 +409,13 @@ impl UInt32 { #[cfg(test)] mod test { - use ::circuit::boolean::{Boolean}; + use crate::gadgets::boolean::{Boolean}; use super::{UInt32}; use ff::Field; use pairing::bls12_381::{Bls12}; - use ::circuit::test::*; - use bellman::{ConstraintSystem}; - use circuit::multieq::MultiEq; + use crate::gadgets::test::*; + use crate::{ConstraintSystem}; + use crate::gadgets::multieq::MultiEq; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; diff --git a/bellman/src/lib.rs b/bellman/src/lib.rs index bf9a4e1..ee6bb88 100644 --- a/bellman/src/lib.rs +++ b/bellman/src/lib.rs @@ -6,6 +6,7 @@ extern crate rand_core; extern crate futures; extern crate bit_vec; +extern crate blake2s_simd; extern crate byteorder; #[cfg(feature = "multicore")] @@ -15,9 +16,20 @@ extern crate futures_cpupool; #[cfg(feature = "multicore")] extern crate num_cpus; +#[cfg(test)] +#[macro_use] +extern crate hex_literal; + #[cfg(test)] extern crate rand; +#[cfg(test)] +extern crate rand_xorshift; + +#[cfg(test)] +extern crate sha2; + +pub mod gadgets; pub mod multicore; mod multiexp; pub mod domain; diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 92f8d04..a05d8ef 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -17,7 +17,6 @@ use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use sapling_crypto::{ - circuit::multipack, constants::CRH_IVK_PERSONALIZATION, jubjub::{ edwards, @@ -29,6 +28,7 @@ use sapling_crypto::{ use zcash_proofs::circuit::sapling::TREE_DEPTH as SAPLING_TREE_DEPTH; use zcash_proofs::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH}; +use bellman::gadgets::multipack; use bellman::groth16::{ create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof, }; diff --git a/sapling-crypto/src/lib.rs b/sapling-crypto/src/lib.rs index 3662629..4e944e0 100644 --- a/sapling-crypto/src/lib.rs +++ b/sapling-crypto/src/lib.rs @@ -19,7 +19,6 @@ extern crate sha2; pub mod jubjub; pub mod group_hash; -pub mod circuit; pub mod pedersen_hash; pub mod primitives; pub mod constants; diff --git a/zcash_proofs/src/circuit/ecc.rs b/zcash_proofs/src/circuit/ecc.rs index e6cba96..cb11eb6 100644 --- a/zcash_proofs/src/circuit/ecc.rs +++ b/zcash_proofs/src/circuit/ecc.rs @@ -6,11 +6,11 @@ use bellman::{ ConstraintSystem }; -use sapling_crypto::circuit::{ +use bellman::gadgets::{ Assignment }; -use sapling_crypto::circuit::num::{ +use bellman::gadgets::num::{ AllocatedNum, Num }; @@ -22,11 +22,11 @@ use sapling_crypto::jubjub::{ FixedGenerators }; -use sapling_crypto::circuit::lookup::{ +use bellman::gadgets::lookup::{ lookup3_xy }; -use sapling_crypto::circuit::boolean::Boolean; +use bellman::gadgets::boolean::Boolean; #[derive(Clone)] pub struct EdwardsPoint { @@ -753,7 +753,7 @@ mod test { use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; - use sapling_crypto::circuit::test::*; + use bellman::gadgets::test::*; use sapling_crypto::jubjub::{ montgomery, edwards, @@ -769,7 +769,7 @@ mod test { AllocatedNum, fixed_base_multiplication }; - use sapling_crypto::circuit::boolean::{ + use bellman::gadgets::boolean::{ Boolean, AllocatedBit }; diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index bbaf999..30a948f 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -2,12 +2,12 @@ use super::ecc::{ MontgomeryPoint, EdwardsPoint }; -use sapling_crypto::circuit::boolean::Boolean; +use bellman::gadgets::boolean::Boolean; use sapling_crypto::jubjub::*; use bellman::{ ConstraintSystem, SynthesisError }; -use sapling_crypto::circuit::lookup::*; +use bellman::gadgets::lookup::*; pub use sapling_crypto::pedersen_hash::Personalization; fn get_constant_bools(person: &Personalization) -> Vec { @@ -110,8 +110,8 @@ pub fn pedersen_hash( #[cfg(test)] mod test { use super::*; - use sapling_crypto::circuit::test::*; - use sapling_crypto::circuit::boolean::{Boolean, AllocatedBit}; + use bellman::gadgets::test::*; + use bellman::gadgets::boolean::{Boolean, AllocatedBit}; use sapling_crypto::pedersen_hash; use ff::PrimeField; use pairing::bls12_381::{Bls12, Fr}; diff --git a/zcash_proofs/src/circuit/sapling.rs b/zcash_proofs/src/circuit/sapling.rs index 1fc6e6c..e381240 100644 --- a/zcash_proofs/src/circuit/sapling.rs +++ b/zcash_proofs/src/circuit/sapling.rs @@ -19,13 +19,13 @@ use sapling_crypto::primitives::{ PaymentAddress }; -use sapling_crypto::circuit::Assignment; -use sapling_crypto::circuit::boolean; +use bellman::gadgets::Assignment; +use bellman::gadgets::boolean; use super::ecc; use super::pedersen_hash; -use sapling_crypto::circuit::blake2s; -use sapling_crypto::circuit::num; -use sapling_crypto::circuit::multipack; +use bellman::gadgets::blake2s; +use bellman::gadgets::num; +use bellman::gadgets::multipack; pub const TREE_DEPTH: usize = zcash_primitives::sapling::SAPLING_COMMITMENT_TREE_DEPTH; @@ -598,12 +598,12 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { #[test] fn test_input_circuit_with_bls12_381() { + use bellman::gadgets::test::*; use ff::{BitIterator, Field}; use pairing::bls12_381::*; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; use sapling_crypto::{ - circuit::test::*, jubjub::{JubjubBls12, fs, edwards}, pedersen_hash, primitives::{Diversifier, Note, ProofGenerationKey}, @@ -742,12 +742,12 @@ fn test_input_circuit_with_bls12_381() { #[test] fn test_output_circuit_with_bls12_381() { + use bellman::gadgets::test::*; use ff::Field; use pairing::bls12_381::*; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; use sapling_crypto::{ - circuit::test::*, jubjub::{JubjubBls12, fs, edwards}, primitives::{Diversifier, ProofGenerationKey}, }; diff --git a/zcash_proofs/src/circuit/sprout/commitment.rs b/zcash_proofs/src/circuit/sprout/commitment.rs index 4d9f00b..ba889a3 100644 --- a/zcash_proofs/src/circuit/sprout/commitment.rs +++ b/zcash_proofs/src/circuit/sprout/commitment.rs @@ -1,9 +1,9 @@ use pairing::{Engine}; use bellman::{ConstraintSystem, SynthesisError}; -use sapling_crypto::circuit::sha256::{ +use bellman::gadgets::sha256::{ sha256 }; -use sapling_crypto::circuit::boolean::{ +use bellman::gadgets::boolean::{ Boolean }; diff --git a/zcash_proofs/src/circuit/sprout/input.rs b/zcash_proofs/src/circuit/sprout/input.rs index e12723a..a84e3a6 100644 --- a/zcash_proofs/src/circuit/sprout/input.rs +++ b/zcash_proofs/src/circuit/sprout/input.rs @@ -1,9 +1,9 @@ use pairing::{Engine}; use bellman::{ConstraintSystem, SynthesisError}; -use sapling_crypto::circuit::sha256::{ +use bellman::gadgets::sha256::{ sha256_block_no_padding }; -use sapling_crypto::circuit::boolean::{ +use bellman::gadgets::boolean::{ AllocatedBit, Boolean }; diff --git a/zcash_proofs/src/circuit/sprout/mod.rs b/zcash_proofs/src/circuit/sprout/mod.rs index db2ea0d..c28b8d7 100644 --- a/zcash_proofs/src/circuit/sprout/mod.rs +++ b/zcash_proofs/src/circuit/sprout/mod.rs @@ -1,11 +1,11 @@ use ff::Field; use pairing::Engine; use bellman::{ConstraintSystem, SynthesisError, Circuit, LinearCombination}; -use sapling_crypto::circuit::boolean::{ +use bellman::gadgets::boolean::{ AllocatedBit, Boolean }; -use sapling_crypto::circuit::multipack::pack_into_inputs; +use bellman::gadgets::multipack::pack_into_inputs; mod prfs; mod commitment; @@ -355,7 +355,7 @@ fn witness_u252( #[test] fn test_sprout_constraints() { use pairing::bls12_381::{Bls12}; - use sapling_crypto::circuit::test::*; + use bellman::gadgets::test::*; use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian}; @@ -479,7 +479,7 @@ fn test_sprout_constraints() { expected_inputs.write_u64::(vpub_old.unwrap()).unwrap(); expected_inputs.write_u64::(vpub_new.unwrap()).unwrap(); - use sapling_crypto::circuit::multipack; + use bellman::gadgets::multipack; let expected_inputs = multipack::bytes_to_bits(&expected_inputs); let expected_inputs = multipack::compute_multipacking::(&expected_inputs); diff --git a/zcash_proofs/src/circuit/sprout/output.rs b/zcash_proofs/src/circuit/sprout/output.rs index 65bcd49..f2e504a 100644 --- a/zcash_proofs/src/circuit/sprout/output.rs +++ b/zcash_proofs/src/circuit/sprout/output.rs @@ -1,6 +1,6 @@ use pairing::{Engine}; use bellman::{ConstraintSystem, SynthesisError}; -use sapling_crypto::circuit::boolean::{Boolean}; +use bellman::gadgets::boolean::{Boolean}; use super::*; use super::prfs::*; diff --git a/zcash_proofs/src/circuit/sprout/prfs.rs b/zcash_proofs/src/circuit/sprout/prfs.rs index 53f65a0..0b3e42c 100644 --- a/zcash_proofs/src/circuit/sprout/prfs.rs +++ b/zcash_proofs/src/circuit/sprout/prfs.rs @@ -1,9 +1,9 @@ use pairing::{Engine}; use bellman::{ConstraintSystem, SynthesisError}; -use sapling_crypto::circuit::sha256::{ +use bellman::gadgets::sha256::{ sha256_block_no_padding }; -use sapling_crypto::circuit::boolean::{ +use bellman::gadgets::boolean::{ Boolean }; diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index 78958ad..7ca8bce 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -1,11 +1,13 @@ -use bellman::groth16::{ - create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof, +use bellman::{ + gadgets::multipack, + groth16::{ + create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof, + }, }; use ff::Field; use pairing::bls12_381::{Bls12, Fr}; use rand_os::OsRng; use sapling_crypto::{ - circuit::multipack, jubjub::{edwards, fs::Fs, FixedGenerators, JubjubBls12, Unknown}, primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, }; diff --git a/zcash_proofs/src/sapling/verifier.rs b/zcash_proofs/src/sapling/verifier.rs index ac4f3f7..01cba0c 100644 --- a/zcash_proofs/src/sapling/verifier.rs +++ b/zcash_proofs/src/sapling/verifier.rs @@ -1,10 +1,10 @@ -use bellman::groth16::{verify_proof, PreparedVerifyingKey, Proof}; +use bellman::{ + gadgets::multipack, + groth16::{verify_proof, PreparedVerifyingKey, Proof}, +}; use ff::Field; use pairing::bls12_381::{Bls12, Fr}; -use sapling_crypto::{ - circuit::multipack, - jubjub::{edwards, FixedGenerators, JubjubBls12, Unknown}, -}; +use sapling_crypto::jubjub::{edwards, FixedGenerators, JubjubBls12, Unknown}; use zcash_primitives::{ redjubjub::{PublicKey, Signature}, transaction::components::Amount, From 5fb9b86ba01df08179ee1c297e158ddfdcb28557 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 6 Aug 2019 10:46:40 +0100 Subject: [PATCH 071/330] Move Jubjub, Pedersen hash and primitives into zcash_primitives --- Cargo.lock | 8 +++--- librustzcash/Cargo.toml | 1 - librustzcash/src/rustzcash.rs | 27 ++++++++++--------- librustzcash/src/tests/key_agreement.rs | 4 +-- librustzcash/src/tests/key_components.rs | 2 +- librustzcash/src/tests/mod.rs | 2 +- librustzcash/src/tests/signatures.rs | 2 +- sapling-crypto/src/lib.rs | 6 ----- zcash_client_backend/Cargo.toml | 1 - zcash_client_backend/src/encoding.rs | 24 ++++++++--------- zcash_primitives/Cargo.toml | 3 ++- .../benches/pedersen_hash.rs | 16 ++++++----- .../src/constants.rs | 0 .../src/group_hash.rs | 0 .../src/jubjub/edwards.rs | 0 .../src/jubjub/fs.rs | 0 .../src/jubjub/mod.rs | 0 .../src/jubjub/montgomery.rs | 0 .../src/jubjub/tests.rs | 0 zcash_primitives/src/keys.rs | 4 +-- zcash_primitives/src/lib.rs | 15 ++++++++--- zcash_primitives/src/note_encryption.rs | 12 ++++----- .../src/pedersen_hash.rs | 0 .../src/primitives.rs | 0 zcash_primitives/src/prover.rs | 5 ++-- zcash_primitives/src/redjubjub.rs | 5 ++-- zcash_primitives/src/sapling.rs | 2 +- zcash_primitives/src/transaction/builder.rs | 5 ++-- .../src/transaction/components.rs | 2 +- zcash_primitives/src/transaction/tests.rs | 3 ++- zcash_primitives/src/util.rs | 3 ++- zcash_primitives/src/zip32.rs | 3 ++- zcash_proofs/Cargo.toml | 1 - zcash_proofs/examples/bench.rs | 6 ++--- zcash_proofs/src/circuit/ecc.rs | 6 ++--- zcash_proofs/src/circuit/pedersen_hash.rs | 6 ++--- zcash_proofs/src/circuit/sapling.rs | 10 +++---- zcash_proofs/src/lib.rs | 1 - zcash_proofs/src/prover.rs | 2 +- zcash_proofs/src/sapling/mod.rs | 2 +- zcash_proofs/src/sapling/prover.rs | 2 +- zcash_proofs/src/sapling/verifier.rs | 2 +- 42 files changed, 99 insertions(+), 94 deletions(-) rename {sapling-crypto => zcash_primitives}/benches/pedersen_hash.rs (50%) rename {sapling-crypto => zcash_primitives}/src/constants.rs (100%) rename {sapling-crypto => zcash_primitives}/src/group_hash.rs (100%) rename {sapling-crypto => zcash_primitives}/src/jubjub/edwards.rs (100%) rename {sapling-crypto => zcash_primitives}/src/jubjub/fs.rs (100%) rename {sapling-crypto => zcash_primitives}/src/jubjub/mod.rs (100%) rename {sapling-crypto => zcash_primitives}/src/jubjub/montgomery.rs (100%) rename {sapling-crypto => zcash_primitives}/src/jubjub/tests.rs (100%) rename {sapling-crypto => zcash_primitives}/src/pedersen_hash.rs (100%) rename sapling-crypto/src/primitives/mod.rs => zcash_primitives/src/primitives.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 670966e..ef4f552 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,7 +57,7 @@ name = "bellman" version = "0.1.0" dependencies = [ "bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2s_simd 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2s_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", @@ -313,7 +313,6 @@ dependencies = [ "pairing 0.14.2", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", "zcash_proofs 0.0.0", ] @@ -536,7 +535,6 @@ dependencies = [ "pairing 0.14.2", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", ] @@ -546,18 +544,19 @@ version = "0.0.0" dependencies = [ "aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "blake2b_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2s_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto_api_chachapoly 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "fpe 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sapling-crypto 0.0.1", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -574,7 +573,6 @@ dependencies = [ "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sapling-crypto 0.0.1", "zcash_primitives 0.0.0", ] diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index ffc38fa..3256d14 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -24,6 +24,5 @@ lazy_static = "1" byteorder = "1" rand_core = "0.5" rand_os = "0.2" -sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } zcash_proofs = { path = "../zcash_proofs" } diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index a05d8ef..b1e0a30 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -7,7 +7,6 @@ extern crate libc; extern crate pairing; extern crate rand_core; extern crate rand_os; -extern crate sapling_crypto; extern crate zcash_primitives; extern crate zcash_proofs; @@ -16,7 +15,7 @@ extern crate lazy_static; use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; -use sapling_crypto::{ +use zcash_primitives::{ constants::CRH_IVK_PERSONALIZATION, jubjub::{ edwards, @@ -57,10 +56,12 @@ use std::ffi::OsString; #[cfg(target_os = "windows")] use std::os::windows::ffi::OsStringExt; -use sapling_crypto::primitives::{ProofGenerationKey, ViewingKey}; use zcash_primitives::{ merkle_tree::CommitmentTreeWitness, note_encryption::sapling_ka_agree, + primitives::{ + Diversifier, Note, PaymentAddress, ProofGenerationKey, ViewingKey, + }, redjubjub::{self, Signature}, sapling::{merkle_hash, spend_sig}, transaction::components::Amount, @@ -236,7 +237,7 @@ fn init_zksnark_params( #[no_mangle] pub extern "system" fn librustzcash_tree_uncommitted(result: *mut [c_uchar; 32]) { - let tmp = sapling_crypto::primitives::Note::::uncommitted().into_repr(); + let tmp = Note::::uncommitted().into_repr(); // Should be okay, caller is responsible for ensuring the pointer // is a valid pointer to 32 bytes that can be mutated. @@ -341,7 +342,7 @@ pub extern "system" fn librustzcash_crh_ivk( #[no_mangle] pub extern "system" fn librustzcash_check_diversifier(diversifier: *const [c_uchar; 11]) -> bool { - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); + let diversifier = Diversifier(unsafe { *diversifier }); diversifier.g_d::(&JUBJUB).is_some() } @@ -352,7 +353,7 @@ pub extern "system" fn librustzcash_ivk_to_pkd( result: *mut [c_uchar; 32], ) -> bool { let ivk = read_fs(unsafe { &*ivk }); - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); + let diversifier = Diversifier(unsafe { *diversifier }); if let Some(g_d) = diversifier.g_d::(&JUBJUB) { let pk_d = g_d.mul(ivk, &JUBJUB); @@ -407,8 +408,8 @@ fn priv_get_note( pk_d: *const [c_uchar; 32], value: u64, r: *const [c_uchar; 32], -) -> Result, ()> { - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); +) -> Result, ()> { + let diversifier = Diversifier(unsafe { *diversifier }); let g_d = match diversifier.g_d::(&JUBJUB) { Some(g_d) => g_d, None => return Err(()), @@ -430,7 +431,7 @@ fn priv_get_note( Err(_) => return Err(()), }; - let note = sapling_crypto::primitives::Note { + let note = Note { value, g_d, pk_d, @@ -539,7 +540,7 @@ pub extern "system" fn librustzcash_sapling_ka_derivepublic( esk: *const [c_uchar; 32], result: *mut [c_uchar; 32], ) -> bool { - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); + let diversifier = Diversifier(unsafe { *diversifier }); // Compute g_d from the diversifier let g_d = match diversifier.g_d::(&JUBJUB) { @@ -940,7 +941,7 @@ pub extern "system" fn librustzcash_sapling_output_proof( }; // Grab the diversifier from the caller. - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); + let diversifier = Diversifier(unsafe { *diversifier }); // Grab pk_d from the caller. let pk_d = match edwards::Point::::read(&(unsafe { &*pk_d })[..], &JUBJUB) { @@ -955,7 +956,7 @@ pub extern "system" fn librustzcash_sapling_output_proof( }; // Construct a payment address - let payment_address = sapling_crypto::primitives::PaymentAddress { + let payment_address = PaymentAddress { pk_d: pk_d, diversifier: diversifier, }; @@ -1086,7 +1087,7 @@ pub extern "system" fn librustzcash_sapling_spend_proof( }; // Grab the diversifier from the caller - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); + let diversifier = Diversifier(unsafe { *diversifier }); // The caller chooses the note randomness let rcm = match Fs::from_repr(read_fs(&(unsafe { &*rcm })[..])) { diff --git a/librustzcash/src/tests/key_agreement.rs b/librustzcash/src/tests/key_agreement.rs index 412ecc3..ab1cc84 100644 --- a/librustzcash/src/tests/key_agreement.rs +++ b/librustzcash/src/tests/key_agreement.rs @@ -2,8 +2,8 @@ use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::Bls12; use rand_core::RngCore; use rand_os::OsRng; -use sapling_crypto::jubjub::{edwards, JubjubBls12}; -use sapling_crypto::primitives::{Diversifier, ViewingKey}; +use zcash_primitives::jubjub::{edwards, JubjubBls12}; +use zcash_primitives::primitives::{Diversifier, ViewingKey}; use { librustzcash_sapling_generate_r, librustzcash_sapling_ka_agree, diff --git a/librustzcash/src/tests/key_components.rs b/librustzcash/src/tests/key_components.rs index 5f332e9..99d3f52 100644 --- a/librustzcash/src/tests/key_components.rs +++ b/librustzcash/src/tests/key_components.rs @@ -1,6 +1,6 @@ use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::Bls12; -use sapling_crypto::{ +use zcash_primitives::{ jubjub::{fs::FsRepr, FixedGenerators, JubjubEngine, JubjubParams}, primitives::{Diversifier, ProofGenerationKey}, }; diff --git a/librustzcash/src/tests/mod.rs b/librustzcash/src/tests/mod.rs index a8cdcb7..dba7387 100644 --- a/librustzcash/src/tests/mod.rs +++ b/librustzcash/src/tests/mod.rs @@ -1,4 +1,4 @@ -use sapling_crypto::jubjub::{FixedGenerators, JubjubParams}; +use zcash_primitives::jubjub::{FixedGenerators, JubjubParams}; use super::JUBJUB; diff --git a/librustzcash/src/tests/signatures.rs b/librustzcash/src/tests/signatures.rs index 034b05a..68ac799 100644 --- a/librustzcash/src/tests/signatures.rs +++ b/librustzcash/src/tests/signatures.rs @@ -1,6 +1,6 @@ use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::Bls12; -use sapling_crypto::jubjub::{FixedGenerators, JubjubEngine}; +use zcash_primitives::jubjub::{FixedGenerators, JubjubEngine}; use zcash_primitives::redjubjub::{PrivateKey, PublicKey, Signature}; use super::JUBJUB; diff --git a/sapling-crypto/src/lib.rs b/sapling-crypto/src/lib.rs index 4e944e0..af5dbb1 100644 --- a/sapling-crypto/src/lib.rs +++ b/sapling-crypto/src/lib.rs @@ -16,9 +16,3 @@ extern crate rand_xorshift; #[cfg(test)] extern crate sha2; - -pub mod jubjub; -pub mod group_hash; -pub mod pedersen_hash; -pub mod primitives; -pub mod constants; diff --git a/zcash_client_backend/Cargo.toml b/zcash_client_backend/Cargo.toml index 31fba49..9996a47 100644 --- a/zcash_client_backend/Cargo.toml +++ b/zcash_client_backend/Cargo.toml @@ -9,7 +9,6 @@ edition = "2018" [dependencies] bech32 = "0.7" pairing = { path = "../pairing" } -sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } [dev-dependencies] diff --git a/zcash_client_backend/src/encoding.rs b/zcash_client_backend/src/encoding.rs index 0c0a50b..e84defa 100644 --- a/zcash_client_backend/src/encoding.rs +++ b/zcash_client_backend/src/encoding.rs @@ -5,7 +5,7 @@ use bech32::{self, Error, FromBase32, ToBase32}; use pairing::bls12_381::Bls12; -use sapling_crypto::{ +use zcash_primitives::{ jubjub::edwards, primitives::{Diversifier, PaymentAddress}, }; @@ -98,15 +98,15 @@ pub fn decode_extended_full_viewing_key( /// use pairing::bls12_381::Bls12; /// use rand_core::SeedableRng; /// use rand_xorshift::XorShiftRng; -/// use sapling_crypto::{ -/// jubjub::edwards, -/// primitives::{Diversifier, PaymentAddress}, -/// }; /// use zcash_client_backend::{ /// constants::testnet::HRP_SAPLING_PAYMENT_ADDRESS, /// encoding::encode_payment_address, /// }; -/// use zcash_primitives::JUBJUB; +/// use zcash_primitives::{ +/// jubjub::edwards, +/// primitives::{Diversifier, PaymentAddress}, +/// JUBJUB, +/// }; /// /// let rng = &mut XorShiftRng::from_seed([ /// 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, @@ -138,15 +138,15 @@ pub fn encode_payment_address(hrp: &str, addr: &PaymentAddress) -> String /// use pairing::bls12_381::Bls12; /// use rand_core::SeedableRng; /// use rand_xorshift::XorShiftRng; -/// use sapling_crypto::{ -/// jubjub::edwards, -/// primitives::{Diversifier, PaymentAddress}, -/// }; /// use zcash_client_backend::{ /// constants::testnet::HRP_SAPLING_PAYMENT_ADDRESS, /// encoding::decode_payment_address, /// }; -/// use zcash_primitives::JUBJUB; +/// use zcash_primitives::{ +/// jubjub::edwards, +/// primitives::{Diversifier, PaymentAddress}, +/// JUBJUB, +/// }; /// /// let rng = &mut XorShiftRng::from_seed([ /// 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, @@ -187,7 +187,7 @@ mod tests { use pairing::bls12_381::Bls12; use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; - use sapling_crypto::{ + use zcash_primitives::{ jubjub::edwards, primitives::{Diversifier, PaymentAddress}, }; diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index 49b1b7d..b3173b7 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -8,6 +8,7 @@ authors = [ [dependencies] aes = "0.3" blake2b_simd = "0.5" +blake2s_simd = "0.5" byteorder = "1" crypto_api_chachapoly = "0.2.1" ff = { path = "../ff" } @@ -18,8 +19,8 @@ pairing = { path = "../pairing" } rand = "0.7" rand_core = "0.5" rand_os = "0.2" -sapling-crypto = { path = "../sapling-crypto" } sha2 = "0.8" [dev-dependencies] +hex-literal = "0.1" rand_xorshift = "0.2" diff --git a/sapling-crypto/benches/pedersen_hash.rs b/zcash_primitives/benches/pedersen_hash.rs similarity index 50% rename from sapling-crypto/benches/pedersen_hash.rs rename to zcash_primitives/benches/pedersen_hash.rs index c5968de..a8f944e 100644 --- a/sapling-crypto/benches/pedersen_hash.rs +++ b/zcash_primitives/benches/pedersen_hash.rs @@ -1,20 +1,22 @@ #![feature(test)] -extern crate rand; +extern crate rand_core; +extern crate rand_os; extern crate test; extern crate pairing; -extern crate sapling_crypto; +extern crate zcash_primitives; -use rand::{Rand, thread_rng}; +use rand_core::RngCore; +use rand_os::OsRng; use pairing::bls12_381::Bls12; -use sapling_crypto::jubjub::JubjubBls12; -use sapling_crypto::pedersen_hash::{pedersen_hash, Personalization}; +use zcash_primitives::jubjub::JubjubBls12; +use zcash_primitives::pedersen_hash::{pedersen_hash, Personalization}; #[bench] fn bench_pedersen_hash(b: &mut test::Bencher) { let params = JubjubBls12::new(); - let rng = &mut thread_rng(); - let bits = (0..510).map(|_| bool::rand(rng)).collect::>(); + let rng = &mut OsRng; + let bits = (0..510).map(|_| (rng.next_u32() % 2) != 0).collect::>(); let personalization = Personalization::MerkleTree(31); b.iter(|| { diff --git a/sapling-crypto/src/constants.rs b/zcash_primitives/src/constants.rs similarity index 100% rename from sapling-crypto/src/constants.rs rename to zcash_primitives/src/constants.rs diff --git a/sapling-crypto/src/group_hash.rs b/zcash_primitives/src/group_hash.rs similarity index 100% rename from sapling-crypto/src/group_hash.rs rename to zcash_primitives/src/group_hash.rs diff --git a/sapling-crypto/src/jubjub/edwards.rs b/zcash_primitives/src/jubjub/edwards.rs similarity index 100% rename from sapling-crypto/src/jubjub/edwards.rs rename to zcash_primitives/src/jubjub/edwards.rs diff --git a/sapling-crypto/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs similarity index 100% rename from sapling-crypto/src/jubjub/fs.rs rename to zcash_primitives/src/jubjub/fs.rs diff --git a/sapling-crypto/src/jubjub/mod.rs b/zcash_primitives/src/jubjub/mod.rs similarity index 100% rename from sapling-crypto/src/jubjub/mod.rs rename to zcash_primitives/src/jubjub/mod.rs diff --git a/sapling-crypto/src/jubjub/montgomery.rs b/zcash_primitives/src/jubjub/montgomery.rs similarity index 100% rename from sapling-crypto/src/jubjub/montgomery.rs rename to zcash_primitives/src/jubjub/montgomery.rs diff --git a/sapling-crypto/src/jubjub/tests.rs b/zcash_primitives/src/jubjub/tests.rs similarity index 100% rename from sapling-crypto/src/jubjub/tests.rs rename to zcash_primitives/src/jubjub/tests.rs diff --git a/zcash_primitives/src/keys.rs b/zcash_primitives/src/keys.rs index fca31ed..ae2c77a 100644 --- a/zcash_primitives/src/keys.rs +++ b/zcash_primitives/src/keys.rs @@ -4,7 +4,7 @@ use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; use ff::{PrimeField, PrimeFieldRepr}; -use sapling_crypto::{ +use crate::{ jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, ToUniform, Unknown}, primitives::{ProofGenerationKey, ViewingKey}, }; @@ -188,7 +188,7 @@ impl FullViewingKey { #[cfg(test)] mod tests { use pairing::bls12_381::Bls12; - use sapling_crypto::jubjub::{edwards, FixedGenerators, JubjubParams, PrimeOrder}; + use crate::jubjub::{edwards, FixedGenerators, JubjubParams, PrimeOrder}; use std::error::Error; use super::FullViewingKey; diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 771f13d..1d4806e 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -3,6 +3,7 @@ extern crate lazy_static; extern crate aes; extern crate blake2b_simd; +extern crate blake2s_simd; extern crate byteorder; extern crate crypto_api_chachapoly; extern crate ff; @@ -12,19 +13,25 @@ extern crate pairing; extern crate rand; extern crate rand_core; extern crate rand_os; -extern crate sapling_crypto; extern crate sha2; +#[cfg(test)] +#[macro_use] +extern crate hex_literal; + #[cfg(test)] extern crate rand_xorshift; -use sapling_crypto::jubjub::JubjubBls12; - pub mod block; +pub mod constants; +pub mod group_hash; +pub mod jubjub; pub mod keys; pub mod legacy; pub mod merkle_tree; pub mod note_encryption; +pub mod pedersen_hash; +pub mod primitives; pub mod prover; pub mod redjubjub; pub mod sapling; @@ -36,6 +43,8 @@ pub mod zip32; #[cfg(test)] mod test_vectors; +use jubjub::JubjubBls12; + lazy_static! { pub static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() }; } diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index d6b66ce..e6804cf 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -6,7 +6,7 @@ use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf}; use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr}; use rand_core::{CryptoRng, RngCore}; -use sapling_crypto::{ +use crate::{ jubjub::{ edwards, fs::{Fs, FsRepr}, @@ -211,18 +211,16 @@ fn prf_ock( /// extern crate ff; /// extern crate pairing; /// extern crate rand_os; -/// extern crate sapling_crypto; +/// extern crate zcash_primitives; /// /// use ff::Field; /// use pairing::bls12_381::Bls12; /// use rand_os::OsRng; -/// use sapling_crypto::{ -/// jubjub::fs::Fs, -/// primitives::{Diversifier, PaymentAddress, ValueCommitment}, -/// }; /// use zcash_primitives::{ +/// jubjub::fs::Fs, /// keys::OutgoingViewingKey, /// note_encryption::{Memo, SaplingNoteEncryption}, +/// primitives::{Diversifier, PaymentAddress, ValueCommitment}, /// JUBJUB, /// }; /// @@ -551,7 +549,7 @@ mod tests { use pairing::bls12_381::{Bls12, Fr, FrRepr}; use rand_core::{CryptoRng, RngCore}; use rand_os::OsRng; - use sapling_crypto::{ + use crate::{ jubjub::{ edwards, fs::{Fs, FsRepr}, diff --git a/sapling-crypto/src/pedersen_hash.rs b/zcash_primitives/src/pedersen_hash.rs similarity index 100% rename from sapling-crypto/src/pedersen_hash.rs rename to zcash_primitives/src/pedersen_hash.rs diff --git a/sapling-crypto/src/primitives/mod.rs b/zcash_primitives/src/primitives.rs similarity index 100% rename from sapling-crypto/src/primitives/mod.rs rename to zcash_primitives/src/primitives.rs diff --git a/zcash_primitives/src/prover.rs b/zcash_primitives/src/prover.rs index a4af8d4..a434b4e 100644 --- a/zcash_primitives/src/prover.rs +++ b/zcash_primitives/src/prover.rs @@ -1,7 +1,7 @@ //! Abstractions over the proving system and parameters. use pairing::bls12_381::{Bls12, Fr}; -use sapling_crypto::{ +use crate::{ jubjub::{edwards, fs::Fs, Unknown}, primitives::{Diversifier, PaymentAddress, ProofGenerationKey}, }; @@ -75,7 +75,8 @@ pub(crate) mod mock { use ff::Field; use pairing::bls12_381::{Bls12, Fr}; use rand_os::OsRng; - use sapling_crypto::{ + + use crate::{ jubjub::{edwards, fs::Fs, FixedGenerators, Unknown}, primitives::{Diversifier, PaymentAddress, ProofGenerationKey, ValueCommitment}, }; diff --git a/zcash_primitives/src/redjubjub.rs b/zcash_primitives/src/redjubjub.rs index 955c7e3..b709419 100644 --- a/zcash_primitives/src/redjubjub.rs +++ b/zcash_primitives/src/redjubjub.rs @@ -3,7 +3,7 @@ use ff::{Field, PrimeField, PrimeFieldRepr}; use rand_core::RngCore; -use sapling_crypto::jubjub::{ +use crate::jubjub::{ edwards::Point, FixedGenerators, JubjubEngine, JubjubParams, Unknown, }; use std::io::{self, Read, Write}; @@ -210,7 +210,8 @@ mod tests { use pairing::bls12_381::Bls12; use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; - use sapling_crypto::jubjub::{edwards, fs::Fs, JubjubBls12}; + + use crate::jubjub::{edwards, fs::Fs, JubjubBls12}; use super::*; diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index 0b94e4e..4590c79 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -3,7 +3,7 @@ use ff::{BitIterator, PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use rand_core::{CryptoRng, RngCore}; -use sapling_crypto::{ +use crate::{ jubjub::{fs::Fs, FixedGenerators, JubjubBls12}, pedersen_hash::{pedersen_hash, Personalization}, primitives::Note, diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 792582d..f32af7a 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -3,7 +3,7 @@ use ff::Field; use pairing::bls12_381::{Bls12, Fr}; use rand::{rngs::OsRng, seq::SliceRandom, CryptoRng, RngCore}; -use sapling_crypto::{ +use crate::{ jubjub::fs::Fs, primitives::{Diversifier, Note, PaymentAddress}, }; @@ -534,7 +534,8 @@ impl Builder { mod tests { use ff::{Field, PrimeField}; use rand::rngs::OsRng; - use sapling_crypto::jubjub::fs::Fs; + + use crate::jubjub::fs::Fs; use super::{Builder, Error}; use crate::{ diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index 1785344..c8cfadc 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -1,7 +1,7 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; -use sapling_crypto::jubjub::{edwards, Unknown}; +use crate::jubjub::{edwards, Unknown}; use std::io::{self, Read, Write}; use legacy::Script; diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index 041ac21..7c770c5 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -1,7 +1,8 @@ use ff::Field; use pairing::bls12_381::Bls12; use rand_os::OsRng; -use sapling_crypto::jubjub::{fs::Fs, FixedGenerators}; + +use crate::jubjub::{fs::Fs, FixedGenerators}; use super::{components::Amount, sighash::signature_hash, Transaction, TransactionData}; use legacy::Script; diff --git a/zcash_primitives/src/util.rs b/zcash_primitives/src/util.rs index f46e0a2..1fdcde7 100644 --- a/zcash_primitives/src/util.rs +++ b/zcash_primitives/src/util.rs @@ -1,5 +1,6 @@ use blake2b_simd::Params; -use sapling_crypto::jubjub::{JubjubEngine, ToUniform}; + +use crate::jubjub::{JubjubEngine, ToUniform}; pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> E::Fs { let mut hasher = Params::new().hash_length(64).personal(persona).to_state(); diff --git a/zcash_primitives/src/zip32.rs b/zcash_primitives/src/zip32.rs index 0c60cf2..44b55f5 100644 --- a/zcash_primitives/src/zip32.rs +++ b/zcash_primitives/src/zip32.rs @@ -4,7 +4,8 @@ use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt}; use ff::Field; use fpe::ff1::{BinaryNumeralString, FF1}; use pairing::bls12_381::Bls12; -use sapling_crypto::{ + +use crate::{ jubjub::{fs::Fs, FixedGenerators, JubjubEngine, JubjubParams, ToUniform}, primitives::{Diversifier, PaymentAddress, ViewingKey}, }; diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index fdb0bf8..b7fa659 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -13,7 +13,6 @@ directories = { version = "1", optional = true } ff = { path = "../ff" } pairing = { path = "../pairing" } rand_os = "0.2" -sapling-crypto = { path = "../sapling-crypto" } zcash_primitives = { path = "../zcash_primitives" } [dev-dependencies] diff --git a/zcash_proofs/examples/bench.rs b/zcash_proofs/examples/bench.rs index 9adf028..a187ec6 100644 --- a/zcash_proofs/examples/bench.rs +++ b/zcash_proofs/examples/bench.rs @@ -1,14 +1,14 @@ extern crate ff; -extern crate sapling_crypto; extern crate bellman; extern crate pairing; extern crate rand_core; extern crate rand_xorshift; +extern crate zcash_primitives; extern crate zcash_proofs; use ff::Field; use std::time::{Duration, Instant}; -use sapling_crypto::jubjub::{ +use zcash_primitives::jubjub::{ JubjubBls12, edwards, fs, @@ -16,7 +16,7 @@ use sapling_crypto::jubjub::{ use zcash_proofs::circuit::sapling::{ Spend }; -use sapling_crypto::primitives::{ +use zcash_primitives::primitives::{ Diversifier, ProofGenerationKey, ValueCommitment diff --git a/zcash_proofs/src/circuit/ecc.rs b/zcash_proofs/src/circuit/ecc.rs index cb11eb6..593c57d 100644 --- a/zcash_proofs/src/circuit/ecc.rs +++ b/zcash_proofs/src/circuit/ecc.rs @@ -15,7 +15,7 @@ use bellman::gadgets::num::{ Num }; -use sapling_crypto::jubjub::{ +use zcash_primitives::jubjub::{ edwards, JubjubEngine, JubjubParams, @@ -754,14 +754,14 @@ mod test { use rand_xorshift::XorShiftRng; use bellman::gadgets::test::*; - use sapling_crypto::jubjub::{ + use zcash_primitives::jubjub::{ montgomery, edwards, JubjubBls12, JubjubParams, FixedGenerators }; - use sapling_crypto::jubjub::fs::Fs; + use zcash_primitives::jubjub::fs::Fs; use super::{ MontgomeryPoint, diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index 30a948f..0b67597 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -3,12 +3,12 @@ use super::ecc::{ EdwardsPoint }; use bellman::gadgets::boolean::Boolean; -use sapling_crypto::jubjub::*; +use zcash_primitives::jubjub::*; use bellman::{ ConstraintSystem, SynthesisError }; use bellman::gadgets::lookup::*; -pub use sapling_crypto::pedersen_hash::Personalization; +pub use zcash_primitives::pedersen_hash::Personalization; fn get_constant_bools(person: &Personalization) -> Vec { person.get_bits() @@ -112,7 +112,7 @@ mod test { use super::*; use bellman::gadgets::test::*; use bellman::gadgets::boolean::{Boolean, AllocatedBit}; - use sapling_crypto::pedersen_hash; + use zcash_primitives::pedersen_hash; use ff::PrimeField; use pairing::bls12_381::{Bls12, Fr}; use rand_core::{RngCore, SeedableRng}; diff --git a/zcash_proofs/src/circuit/sapling.rs b/zcash_proofs/src/circuit/sapling.rs index e381240..1349c8c 100644 --- a/zcash_proofs/src/circuit/sapling.rs +++ b/zcash_proofs/src/circuit/sapling.rs @@ -6,14 +6,14 @@ use bellman::{ Circuit }; -use sapling_crypto::jubjub::{ +use zcash_primitives::jubjub::{ JubjubEngine, FixedGenerators }; -use sapling_crypto::constants; +use zcash_primitives::constants; -use sapling_crypto::primitives::{ +use zcash_primitives::primitives::{ ValueCommitment, ProofGenerationKey, PaymentAddress @@ -603,7 +603,7 @@ fn test_input_circuit_with_bls12_381() { use pairing::bls12_381::*; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; - use sapling_crypto::{ + use zcash_primitives::{ jubjub::{JubjubBls12, fs, edwards}, pedersen_hash, primitives::{Diversifier, Note, ProofGenerationKey}, @@ -747,7 +747,7 @@ fn test_output_circuit_with_bls12_381() { use pairing::bls12_381::*; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; - use sapling_crypto::{ + use zcash_primitives::{ jubjub::{JubjubBls12, fs, edwards}, primitives::{Diversifier, ProofGenerationKey}, }; diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs index 2a3c8f2..3851481 100644 --- a/zcash_proofs/src/lib.rs +++ b/zcash_proofs/src/lib.rs @@ -4,7 +4,6 @@ extern crate byteorder; extern crate ff; extern crate pairing; extern crate rand_os; -extern crate sapling_crypto; extern crate zcash_primitives; #[cfg(feature = "local-prover")] diff --git a/zcash_proofs/src/prover.rs b/zcash_proofs/src/prover.rs index c59ba62..1c1a972 100644 --- a/zcash_proofs/src/prover.rs +++ b/zcash_proofs/src/prover.rs @@ -3,7 +3,7 @@ use bellman::groth16::{Parameters, PreparedVerifyingKey}; use directories::BaseDirs; use pairing::bls12_381::{Bls12, Fr}; -use sapling_crypto::{ +use zcash_primitives::{ jubjub::{edwards, fs::Fs, Unknown}, primitives::{Diversifier, PaymentAddress, ProofGenerationKey}, }; diff --git a/zcash_proofs/src/sapling/mod.rs b/zcash_proofs/src/sapling/mod.rs index 98c4ba3..9aa62f1 100644 --- a/zcash_proofs/src/sapling/mod.rs +++ b/zcash_proofs/src/sapling/mod.rs @@ -1,5 +1,5 @@ use pairing::bls12_381::Bls12; -use sapling_crypto::jubjub::{ +use zcash_primitives::jubjub::{ edwards, fs::FsRepr, FixedGenerators, JubjubBls12, JubjubParams, Unknown, }; use zcash_primitives::transaction::components::Amount; diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index 7ca8bce..e914171 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -7,7 +7,7 @@ use bellman::{ use ff::Field; use pairing::bls12_381::{Bls12, Fr}; use rand_os::OsRng; -use sapling_crypto::{ +use zcash_primitives::{ jubjub::{edwards, fs::Fs, FixedGenerators, JubjubBls12, Unknown}, primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, }; diff --git a/zcash_proofs/src/sapling/verifier.rs b/zcash_proofs/src/sapling/verifier.rs index 01cba0c..0801023 100644 --- a/zcash_proofs/src/sapling/verifier.rs +++ b/zcash_proofs/src/sapling/verifier.rs @@ -4,7 +4,7 @@ use bellman::{ }; use ff::Field; use pairing::bls12_381::{Bls12, Fr}; -use sapling_crypto::jubjub::{edwards, FixedGenerators, JubjubBls12, Unknown}; +use zcash_primitives::jubjub::{edwards, FixedGenerators, JubjubBls12, Unknown}; use zcash_primitives::{ redjubjub::{PublicKey, Signature}, transaction::components::Amount, From 1b865ecfdf3d6743fa2e044b77f273db0e28cb9d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 6 Aug 2019 10:52:04 +0100 Subject: [PATCH 072/330] Remove sapling-crypto --- Cargo.lock | 17 --- Cargo.toml | 1 - sapling-crypto/.gitignore | 3 - sapling-crypto/COPYRIGHT | 14 --- sapling-crypto/Cargo.toml | 27 ----- sapling-crypto/LICENSE-APACHE | 201 ---------------------------------- sapling-crypto/LICENSE-MIT | 23 ---- sapling-crypto/README.md | 23 ---- sapling-crypto/src/lib.rs | 18 --- 9 files changed, 327 deletions(-) delete mode 100644 sapling-crypto/.gitignore delete mode 100644 sapling-crypto/COPYRIGHT delete mode 100644 sapling-crypto/Cargo.toml delete mode 100644 sapling-crypto/LICENSE-APACHE delete mode 100644 sapling-crypto/LICENSE-MIT delete mode 100644 sapling-crypto/README.md delete mode 100644 sapling-crypto/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index ef4f552..d6f658a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -460,23 +460,6 @@ dependencies = [ "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "sapling-crypto" -version = "0.0.1" -dependencies = [ - "bellman 0.1.0", - "blake2b_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2s_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0", - "hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "sha2" version = "0.8.0" diff --git a/Cargo.toml b/Cargo.toml index c5e2257..69639cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,6 @@ members = [ "group", "librustzcash", "pairing", - "sapling-crypto", "zcash_client_backend", "zcash_primitives", "zcash_proofs", diff --git a/sapling-crypto/.gitignore b/sapling-crypto/.gitignore deleted file mode 100644 index 6aa1064..0000000 --- a/sapling-crypto/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target/ -**/*.rs.bk -Cargo.lock diff --git a/sapling-crypto/COPYRIGHT b/sapling-crypto/COPYRIGHT deleted file mode 100644 index f2c6a3b..0000000 --- a/sapling-crypto/COPYRIGHT +++ /dev/null @@ -1,14 +0,0 @@ -Copyrights in the "sapling-crypto" library are retained by their contributors. No -copyright assignment is required to contribute to the "sapling-crypto" library. - -The "sapling-crypto" library is licensed under either of - - * Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT) - -at your option. - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/sapling-crypto/Cargo.toml b/sapling-crypto/Cargo.toml deleted file mode 100644 index c3aedd3..0000000 --- a/sapling-crypto/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -authors = ["Sean Bowe "] -description = "Cryptographic library for Zcash Sapling" -documentation = "https://github.com/zcash-hackworks/sapling" -homepage = "https://github.com/zcash-hackworks/sapling" -license = "MIT/Apache-2.0" -name = "sapling-crypto" -repository = "https://github.com/zcash-hackworks/sapling" -version = "0.0.1" - -[dependencies.pairing] -path = "../pairing" -features = ["expose-arith"] - -[dependencies] -bellman = { path = "../bellman" } -blake2b_simd = "0.5" -blake2s_simd = "0.5" -ff = { path = "../ff" } -rand_core = "0.5" -digest = "0.8" -byteorder = "1" - -[dev-dependencies] -hex-literal = "0.1" -rand_xorshift = "0.2" -sha2 = "0.8" diff --git a/sapling-crypto/LICENSE-APACHE b/sapling-crypto/LICENSE-APACHE deleted file mode 100644 index 16fe87b..0000000 --- a/sapling-crypto/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. diff --git a/sapling-crypto/LICENSE-MIT b/sapling-crypto/LICENSE-MIT deleted file mode 100644 index 31aa793..0000000 --- a/sapling-crypto/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/sapling-crypto/README.md b/sapling-crypto/README.md deleted file mode 100644 index f5d3bce..0000000 --- a/sapling-crypto/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# sapling-crypto - -This repository contains a (work-in-progress) implementation of Zcash's "Sapling" cryptography. - -## Security Warnings - -This library is currently under development and has not been reviewed. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/sapling-crypto/src/lib.rs b/sapling-crypto/src/lib.rs deleted file mode 100644 index af5dbb1..0000000 --- a/sapling-crypto/src/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -extern crate pairing; -extern crate bellman; -extern crate blake2b_simd; -extern crate blake2s_simd; -extern crate digest; -extern crate ff; -extern crate rand_core; -extern crate byteorder; - -#[cfg(test)] -#[macro_use] -extern crate hex_literal; - -#[cfg(test)] -extern crate rand_xorshift; - -#[cfg(test)] -extern crate sha2; From bc7ea564d32291a6723d57573119f2869f2ab265 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Thu, 15 Aug 2019 10:38:40 -0600 Subject: [PATCH 073/330] cargo fmt pairing --- pairing/src/bls12_381/ec.rs | 239 +++++++++++++++++++++------------- pairing/src/bls12_381/fq.rs | 60 +++++---- pairing/src/bls12_381/fq12.rs | 2 +- pairing/src/bls12_381/fq2.rs | 171 +++++++++++++++--------- pairing/src/bls12_381/fq6.rs | 1 - pairing/src/bls12_381/fr.rs | 54 ++++---- pairing/src/bls12_381/mod.rs | 4 +- pairing/src/lib.rs | 15 +-- pairing/src/tests/field.rs | 4 +- 9 files changed, 323 insertions(+), 227 deletions(-) diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index fa659bd..9a78e37 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -14,11 +14,10 @@ macro_rules! curve_impl { pub struct $affine { pub(crate) x: $basefield, pub(crate) y: $basefield, - pub(crate) infinity: bool + pub(crate) infinity: bool, } - impl ::std::fmt::Display for $affine - { + impl ::std::fmt::Display for $affine { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { if self.infinity { write!(f, "{}(Infinity)", $name) @@ -30,13 +29,12 @@ macro_rules! curve_impl { #[derive(Copy, Clone, Debug, Eq)] pub struct $projective { - pub(crate) x: $basefield, - pub(crate) y: $basefield, - pub(crate) z: $basefield + pub(crate) x: $basefield, + pub(crate) y: $basefield, + pub(crate) z: $basefield, } - impl ::std::fmt::Display for $projective - { + impl ::std::fmt::Display for $projective { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, "{}", self.into_affine()) } @@ -89,7 +87,9 @@ macro_rules! curve_impl { let mut res = $projective::zero(); for i in bits { res.double(); - if i { res.add_assign_mixed(self) } + if i { + res.add_assign_mixed(self) + } } res } @@ -112,12 +112,8 @@ macro_rules! curve_impl { $affine { x: x, - y: if (y < negy) ^ greatest { - y - } else { - negy - }, - infinity: false + y: if (y < negy) ^ greatest { y } else { negy }, + infinity: false, } }) } @@ -156,7 +152,7 @@ macro_rules! curve_impl { $affine { x: $basefield::zero(), y: $basefield::one(), - infinity: true + infinity: true, } } @@ -182,7 +178,6 @@ macro_rules! curve_impl { fn into_projective(&self) -> $projective { (*self).into() } - } impl PairingCurveAffine for $affine { @@ -197,7 +192,6 @@ macro_rules! curve_impl { fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult { self.perform_pairing(other) } - } impl CurveProjective for $projective { @@ -227,7 +221,7 @@ macro_rules! curve_impl { $projective { x: $basefield::zero(), y: $basefield::one(), - z: $basefield::zero() + z: $basefield::zero(), } } @@ -245,8 +239,7 @@ macro_rules! curve_impl { self.is_zero() || self.z == $basefield::one() } - fn batch_normalization(v: &mut [Self]) - { + fn batch_normalization(v: &mut [Self]) { // Montgomery’s Trick and Fast Implementation of Masked AES // Genelle, Prouff and Quisquater // Section 3.2 @@ -254,9 +247,10 @@ macro_rules! curve_impl { // First pass: compute [a, ab, abc, ...] let mut prod = Vec::with_capacity(v.len()); let mut tmp = $basefield::one(); - for g in v.iter_mut() - // Ignore normalized elements - .filter(|g| !g.is_normalized()) + for g in v + .iter_mut() + // Ignore normalized elements + .filter(|g| !g.is_normalized()) { tmp.mul_assign(&g.z); prod.push(tmp); @@ -266,13 +260,19 @@ macro_rules! curve_impl { tmp = tmp.inverse().unwrap(); // Guaranteed to be nonzero. // Second pass: iterate backwards to compute inverses - for (g, s) in v.iter_mut() - // Backwards - .rev() - // Ignore normalized elements - .filter(|g| !g.is_normalized()) - // Backwards, skip last element, fill in one for last term. - .zip(prod.into_iter().rev().skip(1).chain(Some($basefield::one()))) + for (g, s) in v + .iter_mut() + // Backwards + .rev() + // Ignore normalized elements + .filter(|g| !g.is_normalized()) + // Backwards, skip last element, fill in one for last term. + .zip( + prod.into_iter() + .rev() + .skip(1) + .chain(Some($basefield::one())), + ) { // tmp := tmp * g.z; g.z := tmp * s = 1/z let mut newtmp = tmp; @@ -283,9 +283,7 @@ macro_rules! curve_impl { } // Perform affine transformations - for g in v.iter_mut() - .filter(|g| !g.is_normalized()) - { + for g in v.iter_mut().filter(|g| !g.is_normalized()) { let mut z = g.z; // 1/z z.square(); // 1/z^2 g.x.mul_assign(&z); // x/z^2 @@ -538,8 +536,7 @@ macro_rules! curve_impl { let mut found_one = false; - for i in BitIterator::new(other.into()) - { + for i in BitIterator::new(other.into()) { if found_one { res.double(); } else { @@ -577,7 +574,7 @@ macro_rules! curve_impl { $projective { x: p.x, y: p.y, - z: $basefield::one() + z: $basefield::one(), } } } @@ -594,7 +591,7 @@ macro_rules! curve_impl { $affine { x: p.x, y: p.y, - infinity: false + infinity: false, } } else { // Z is nonzero, so it must have an inverse in a field. @@ -614,12 +611,12 @@ macro_rules! curve_impl { $affine { x: x, y: y, - infinity: false + infinity: false, } } } } - } + }; } pub mod g1 { @@ -990,7 +987,8 @@ pub mod g1 { 0x9fe83b1b4a5d648d, 0xf583cc5a508f6a40, 0xc3ad2aefde0bb13, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0x60aa6f9552f03aae, 0xecd01d5181300d35, @@ -998,7 +996,8 @@ pub mod g1 { 0xe760f57922998c9d, 0x953703f5795a39e5, 0xfe3ae0922df702c, - ])).unwrap(), + ])) + .unwrap(), infinity: false, }; assert!(!p.is_on_curve()); @@ -1015,7 +1014,8 @@ pub mod g1 { 0xea034ee2928b30a8, 0xbd8833dc7c79a7f7, 0xe45c9f0c0438675, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0x3b450eb1ab7b5dad, 0xa65cb81e975e8675, @@ -1023,7 +1023,8 @@ pub mod g1 { 0x753ddf21a2601d20, 0x532d0b640bd3ff8b, 0x118d2c543f031102, - ])).unwrap(), + ])) + .unwrap(), infinity: false, }; assert!(!p.is_on_curve()); @@ -1041,7 +1042,8 @@ pub mod g1 { 0xf35de9ce0d6b4e84, 0x265bddd23d1dec54, 0x12a8778088458308, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0x8a22defa0d526256, 0xc57ca55456fcb9ae, @@ -1049,7 +1051,8 @@ pub mod g1 { 0x921beef89d4f29df, 0x5b6fda44ad85fa78, 0xed74ab9f302cbe0, - ])).unwrap(), + ])) + .unwrap(), infinity: false, }; assert!(p.is_on_curve()); @@ -1067,7 +1070,8 @@ pub mod g1 { 0x485e77d50a5df10d, 0x4c6fcac4b55fd479, 0x86ed4d9906fb064, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0xd25ee6461538c65, 0x9f3bbb2ecd3719b9, @@ -1075,7 +1079,8 @@ pub mod g1 { 0xcefca68333c35288, 0x570c8005f8573fa6, 0x152ca696fe034442, - ])).unwrap(), + ])) + .unwrap(), z: Fq::one(), }; @@ -1087,7 +1092,8 @@ pub mod g1 { 0x5f44314ec5e3fb03, 0x24e8538737c6e675, 0x8abd623a594fba8, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0x6b0528f088bb7044, 0x2fdeb5c82917ff9e, @@ -1095,7 +1101,8 @@ pub mod g1 { 0xd65104c6f95a872a, 0x1f2998a5a9c61253, 0xe74846154a9e44, - ])).unwrap(), + ])) + .unwrap(), z: Fq::one(), }); @@ -1111,7 +1118,8 @@ pub mod g1 { 0xc4f9a52a428e23bb, 0xd178b28dd4f407ef, 0x17fb8905e9183c69 - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0xd0de9d65292b7710, 0xf6a05f2bcf1d9ca7, @@ -1119,7 +1127,8 @@ pub mod g1 { 0xeec8d1a5b7466c58, 0x4bc362649dce6376, 0x430cbdc5455b00a - ])).unwrap(), + ])) + .unwrap(), infinity: false, } ); @@ -1135,7 +1144,8 @@ pub mod g1 { 0x485e77d50a5df10d, 0x4c6fcac4b55fd479, 0x86ed4d9906fb064, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0xd25ee6461538c65, 0x9f3bbb2ecd3719b9, @@ -1143,7 +1153,8 @@ pub mod g1 { 0xcefca68333c35288, 0x570c8005f8573fa6, 0x152ca696fe034442, - ])).unwrap(), + ])) + .unwrap(), z: Fq::one(), }; @@ -1161,7 +1172,8 @@ pub mod g1 { 0x4b914c16687dcde0, 0x66c8baf177d20533, 0xaf960cff3d83833 - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0x3f0675695f5177a8, 0x2b6d82ae178a1ba0, @@ -1169,7 +1181,8 @@ pub mod g1 { 0x1771a65b60572f4e, 0x8b547c1313b27555, 0x135075589a687b1e - ])).unwrap(), + ])) + .unwrap(), infinity: false, } ); @@ -1192,7 +1205,8 @@ pub mod g1 { 0x71ffa8021531705, 0x7418d484386d267, 0xd5108d8ff1fbd6, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0xa776ccbfe9981766, 0x255632964ff40f4a, @@ -1200,7 +1214,8 @@ pub mod g1 { 0x520f74773e74c8c3, 0x484c8fc982008f0, 0xee2c3d922008cc6, - ])).unwrap(), + ])) + .unwrap(), infinity: false, }; @@ -1212,7 +1227,8 @@ pub mod g1 { 0xc6e05201e5f83991, 0xf7c75910816f207c, 0x18d4043e78103106, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0xa776ccbfe9981766, 0x255632964ff40f4a, @@ -1220,7 +1236,8 @@ pub mod g1 { 0x520f74773e74c8c3, 0x484c8fc982008f0, 0xee2c3d922008cc6, - ])).unwrap(), + ])) + .unwrap(), infinity: false, }; @@ -1235,7 +1252,8 @@ pub mod g1 { 0x9676ff02ec39c227, 0x4c12c15d7e55b9f3, 0x57fd1e317db9bd, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0x1288334016679345, 0xf955cd68615ff0b5, @@ -1243,7 +1261,8 @@ pub mod g1 { 0x1267d70db51049fb, 0x4696deb9ab2ba3e7, 0xb1e4e11177f59d4, - ])).unwrap(), + ])) + .unwrap(), infinity: false, }; @@ -1673,7 +1692,8 @@ pub mod g2 { 0x7a17a004747e3dbe, 0xcc65406a7c2e5a73, 0x10b8c03d64db4d0c, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xd30e70fe2f029778, 0xda30772df0f5212e, @@ -1681,7 +1701,8 @@ pub mod g2 { 0xfb777e5b9b568608, 0x789bac1fec71a2b9, 0x1342f02e2da54405, - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -1691,7 +1712,8 @@ pub mod g2 { 0x663015d9410eb608, 0x78e82a79d829a544, 0x40a00545bb3c1e, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x4709802348e79377, 0xb5ac4dc9204bcfbd, @@ -1699,7 +1721,8 @@ pub mod g2 { 0x15008b1dc399e8df, 0x68128fd0548a3829, 0x16a613db5c873aaa, - ])).unwrap(), + ])) + .unwrap(), }, infinity: false, }; @@ -1718,7 +1741,8 @@ pub mod g2 { 0x41abba710d6c692c, 0xffcc4b2b62ce8484, 0x6993ec01b8934ed, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xb94e92d5f874e26, 0x44516408bc115d95, @@ -1726,7 +1750,8 @@ pub mod g2 { 0xa5a0c2b7131f3555, 0x83800965822367e7, 0x10cf1d3ad8d90bfa, - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -1736,7 +1761,8 @@ pub mod g2 { 0x5a9171720e73eb51, 0x38eb4fd8d658adb7, 0xb649051bbc1164d, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x9225814253d7df75, 0xc196c2513477f887, @@ -1744,7 +1770,8 @@ pub mod g2 { 0x55f2b8efad953e04, 0x7379345eda55265e, 0x377f2e6208fd4cb, - ])).unwrap(), + ])) + .unwrap(), }, infinity: false, }; @@ -1764,7 +1791,8 @@ pub mod g2 { 0x2199bc19c48c393d, 0x4a151b732a6075bf, 0x17762a3b9108c4a7, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x26f461e944bbd3d1, 0x298f3189a9cf6ed6, @@ -1772,7 +1800,8 @@ pub mod g2 { 0x7e147f3f9e6e241, 0x72a9b63583963fff, 0x158b0083c000462, - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -1782,7 +1811,8 @@ pub mod g2 { 0x68cad19430706b4d, 0x3ccfb97b924dcea8, 0x1660f93434588f8d, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xaaed3985b6dcb9c7, 0xc1e985d6d898d9f4, @@ -1790,7 +1820,8 @@ pub mod g2 { 0x3940a2dbb914b529, 0xbeb88137cf34f3e7, 0x1699ee577c61b694, - ])).unwrap(), + ])) + .unwrap(), }, infinity: false, }; @@ -1810,7 +1841,8 @@ pub mod g2 { 0x72556c999f3707ac, 0x4617f2e6774e9711, 0x100b2fe5bffe030b, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x7a33555977ec608, 0xe23039d1fe9c0881, @@ -1818,7 +1850,8 @@ pub mod g2 { 0x4637c4f417667e2e, 0x93ebe7c3e41f6acc, 0xde884f89a9a371b, - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -1828,7 +1861,8 @@ pub mod g2 { 0x25fd427b4122f231, 0xd83112aace35cae, 0x191b2432407cbb7f, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xf68ae82fe97662f5, 0xe986057068b50b7d, @@ -1836,7 +1870,8 @@ pub mod g2 { 0x9eaa6d19de569196, 0xf6a03d31e2ec2183, 0x3bdafaf7ca9b39b, - ])).unwrap(), + ])) + .unwrap(), }, z: Fq2::one(), }; @@ -1850,7 +1885,8 @@ pub mod g2 { 0x8e73a96b329ad190, 0x27c546f75ee1f3ab, 0xa33d27add5e7e82, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x93b1ebcd54870dfe, 0xf1578300e1342e11, @@ -1858,7 +1894,8 @@ pub mod g2 { 0x2089faf462438296, 0x828e5848cd48ea66, 0x141ecbac1deb038b, - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -1868,7 +1905,8 @@ pub mod g2 { 0x2767032fc37cc31d, 0xd5ee2aba84fd10fe, 0x16576ccd3dd0a4e8, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x4da9b6f6a96d1dd2, 0x9657f7da77f1650e, @@ -1876,7 +1914,8 @@ pub mod g2 { 0x31898db63f87363a, 0xabab040ddbd097cc, 0x11ad236b9ba02990, - ])).unwrap(), + ])) + .unwrap(), }, z: Fq2::one(), }); @@ -1894,7 +1933,8 @@ pub mod g2 { 0xf1273e6406eef9cc, 0xababd760ff05cb92, 0xd7c20456617e89 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xd1a50b8572cbd2b8, 0x238f0ac6119d07df, @@ -1902,7 +1942,8 @@ pub mod g2 { 0x8b203284c51edf6b, 0xc8a0b730bbb21f5e, 0x1a3b59d29a31274 - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -1912,7 +1953,8 @@ pub mod g2 { 0x64528ab3863633dc, 0x159384333d7cba97, 0x4cb84741f3cafe8 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x242af0dc3640e1a4, 0xe90a73ad65c66919, @@ -1920,7 +1962,8 @@ pub mod g2 { 0x38528f92b689644d, 0xb6884deec59fb21f, 0x3c075d3ec52ba90 - ])).unwrap(), + ])) + .unwrap(), }, infinity: false, } @@ -1938,7 +1981,8 @@ pub mod g2 { 0x72556c999f3707ac, 0x4617f2e6774e9711, 0x100b2fe5bffe030b, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x7a33555977ec608, 0xe23039d1fe9c0881, @@ -1946,7 +1990,8 @@ pub mod g2 { 0x4637c4f417667e2e, 0x93ebe7c3e41f6acc, 0xde884f89a9a371b, - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -1956,7 +2001,8 @@ pub mod g2 { 0x25fd427b4122f231, 0xd83112aace35cae, 0x191b2432407cbb7f, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xf68ae82fe97662f5, 0xe986057068b50b7d, @@ -1964,7 +2010,8 @@ pub mod g2 { 0x9eaa6d19de569196, 0xf6a03d31e2ec2183, 0x3bdafaf7ca9b39b, - ])).unwrap(), + ])) + .unwrap(), }, z: Fq2::one(), }; @@ -1984,7 +2031,8 @@ pub mod g2 { 0xbcedcfce1e52d986, 0x9755d4a3926e9862, 0x18bab73760fd8024 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x4e7c5e0a2ae5b99e, 0x96e582a27f028961, @@ -1992,7 +2040,8 @@ pub mod g2 { 0xeb0cf5e610ef4fe7, 0x7b4c2bae8db6e70b, 0xf136e43909fca0 - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -2002,7 +2051,8 @@ pub mod g2 { 0xa5a2a51f7fde787b, 0x8b92866bc6384188, 0x81a53fe531d64ef - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x4c5d607666239b34, 0xeddb5f48304d14b3, @@ -2010,7 +2060,8 @@ pub mod g2 { 0xb271f52f12ead742, 0x244e6c2015c83348, 0x19e2deae6eb9b441 - ])).unwrap(), + ])) + .unwrap(), }, infinity: false, } diff --git a/pairing/src/bls12_381/fq.rs b/pairing/src/bls12_381/fq.rs index 0f54196..d272545 100644 --- a/pairing/src/bls12_381/fq.rs +++ b/pairing/src/bls12_381/fq.rs @@ -1582,26 +1582,24 @@ fn test_fq_is_valid() { a.0.sub_noborrow(&FqRepr::from(1)); assert!(a.is_valid()); assert!(Fq(FqRepr::from(0)).is_valid()); - assert!( - Fq(FqRepr([ - 0xdf4671abd14dab3e, - 0xe2dc0c9f534fbd33, - 0x31ca6c880cc444a6, - 0x257a67e70ef33359, - 0xf9b29e493f899b36, - 0x17c8be1800b9f059 - ])).is_valid() - ); - assert!( - !Fq(FqRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff - ])).is_valid() - ); + assert!(Fq(FqRepr([ + 0xdf4671abd14dab3e, + 0xe2dc0c9f534fbd33, + 0x31ca6c880cc444a6, + 0x257a67e70ef33359, + 0xf9b29e493f899b36, + 0x17c8be1800b9f059 + ])) + .is_valid()); + assert!(!Fq(FqRepr([ + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff + ])) + .is_valid()); let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, @@ -1949,7 +1947,8 @@ fn test_fq_squaring() { 0xdc05c659b4e15b27, 0x79361e5a802c6a23, 0x24bcbe5d51b9a6f - ])).unwrap() + ])) + .unwrap() ); let mut rng = XorShiftRng::from_seed([ @@ -2099,16 +2098,15 @@ fn test_fq_sqrt() { #[test] fn test_fq_from_into_repr() { // q + 1 should not be in the field - assert!( - Fq::from_repr(FqRepr([ - 0xb9feffffffffaaac, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a - ])).is_err() - ); + assert!(Fq::from_repr(FqRepr([ + 0xb9feffffffffaaac, + 0x1eabfffeb153ffff, + 0x6730d2a0f6b0f624, + 0x64774b84f38512bf, + 0x4b1ba7b6434bacd7, + 0x1a0111ea397fe69a + ])) + .is_err()); // q should not be in the field assert!(Fq::from_repr(Fq::char()).is_err()); diff --git a/pairing/src/bls12_381/fq12.rs b/pairing/src/bls12_381/fq12.rs index 3c726d2..dcfdef1 100644 --- a/pairing/src/bls12_381/fq12.rs +++ b/pairing/src/bls12_381/fq12.rs @@ -2,7 +2,7 @@ use super::fq::FROBENIUS_COEFF_FQ12_C1; use super::fq2::Fq2; use super::fq6::Fq6; use ff::Field; -use rand_core::{RngCore}; +use rand_core::RngCore; /// An element of Fq12, represented by c0 + c1 * w. #[derive(Copy, Clone, Debug, Eq, PartialEq)] diff --git a/pairing/src/bls12_381/fq2.rs b/pairing/src/bls12_381/fq2.rs index 994a28a..7818280 100644 --- a/pairing/src/bls12_381/fq2.rs +++ b/pairing/src/bls12_381/fq2.rs @@ -1,4 +1,4 @@ -use super::fq::{FROBENIUS_COEFF_FQ2_C1, Fq, NEGATIVE_ONE}; +use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE}; use ff::{Field, SqrtField}; use rand_core::RngCore; @@ -261,12 +261,11 @@ fn test_fq2_basics() { ); assert!(Fq2::zero().is_zero()); assert!(!Fq2::one().is_zero()); - assert!( - !Fq2 { - c0: Fq::zero(), - c1: Fq::one(), - }.is_zero() - ); + assert!(!Fq2 { + c0: Fq::zero(), + c1: Fq::one(), + } + .is_zero()); } #[test] @@ -309,7 +308,8 @@ fn test_fq2_squaring() { 0xf7f295a94e58ae7c, 0x41b76dcc1c3fbe5e, 0x7080c5fa1d8e042, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x38f473b3c870a4ab, 0x6ad3291177c8c7e5, @@ -317,7 +317,8 @@ fn test_fq2_squaring() { 0xbfb99020604137a0, 0xfc58a7b7be815407, 0x10d1615e75250a21, - ])).unwrap(), + ])) + .unwrap(), }; a.square(); assert_eq!( @@ -330,7 +331,8 @@ fn test_fq2_squaring() { 0xcb674157618da176, 0x4cf17b5893c3d327, 0x7eac81369c43361 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xc1579cf58e980cf8, 0xa23eb7e12dd54d98, @@ -338,7 +340,8 @@ fn test_fq2_squaring() { 0x38d0d7275a9689e1, 0x739c983042779a65, 0x1542a61c8a8db994 - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -356,7 +359,8 @@ fn test_fq2_mul() { 0x9ee53e7e84d7532e, 0x1c202d8ed97afb45, 0x51d3f9253e2516f, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xa7348a8b511aedcf, 0x143c215d8176b319, @@ -364,7 +368,8 @@ fn test_fq2_mul() { 0x9533e4a9a5158be, 0x7a5e1ecb676d65f9, 0x180c3ee46656b008, - ])).unwrap(), + ])) + .unwrap(), }; a.mul_assign(&Fq2 { c0: Fq::from_repr(FqRepr([ @@ -374,7 +379,8 @@ fn test_fq2_mul() { 0xcd460f9f0c23e430, 0x6c9110292bfa409, 0x2c93a72eb8af83e, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x4b1c3f936d8992d4, 0x1d2a72916dba4c8a, @@ -382,7 +388,8 @@ fn test_fq2_mul() { 0x57a06d3135a752ae, 0x634cd3c6c565096d, 0x19e17334d4e93558, - ])).unwrap(), + ])) + .unwrap(), }); assert_eq!( a, @@ -394,7 +401,8 @@ fn test_fq2_mul() { 0x5511fe4d84ee5f78, 0x5310a202d92f9963, 0x1751afbe166e5399 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x84af0e1bd630117a, 0x6c63cd4da2c2aa7, @@ -402,7 +410,8 @@ fn test_fq2_mul() { 0xc975106579c275ee, 0x33a9ac82ce4c5083, 0x1ef1a36c201589d - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -422,7 +431,8 @@ fn test_fq2_inverse() { 0x9ee53e7e84d7532e, 0x1c202d8ed97afb45, 0x51d3f9253e2516f, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xa7348a8b511aedcf, 0x143c215d8176b319, @@ -430,7 +440,8 @@ fn test_fq2_inverse() { 0x9533e4a9a5158be, 0x7a5e1ecb676d65f9, 0x180c3ee46656b008, - ])).unwrap(), + ])) + .unwrap(), }; let a = a.inverse().unwrap(); assert_eq!( @@ -443,7 +454,8 @@ fn test_fq2_inverse() { 0xdfba703293941c30, 0xa6c3d8f9586f2636, 0x1351ef01941b70c4 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x8c39fd76a8312cb4, 0x15d7b6b95defbff0, @@ -451,7 +463,8 @@ fn test_fq2_inverse() { 0xcbf651a0f367afb2, 0xdf4e54f0d3ef15a6, 0x103bdf241afb0019 - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -469,7 +482,8 @@ fn test_fq2_addition() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -477,7 +491,8 @@ fn test_fq2_addition() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837, - ])).unwrap(), + ])) + .unwrap(), }; a.add_assign(&Fq2 { c0: Fq::from_repr(FqRepr([ @@ -487,7 +502,8 @@ fn test_fq2_addition() { 0x3b88899a42a6318f, 0x986a4a62fa82a49d, 0x13ce433fa26027f5, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x66323bf80b58b9b9, 0xa1379b6facf6e596, @@ -495,7 +511,8 @@ fn test_fq2_addition() { 0x2236f55246d0d44d, 0x4c8c1800eb104566, 0x11d6e20e986c2085, - ])).unwrap(), + ])) + .unwrap(), }); assert_eq!( a, @@ -507,7 +524,8 @@ fn test_fq2_addition() { 0xf4ef57d604b6bca2, 0x65309427b3d5d090, 0x14c715d5553f01d2 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xfdb032e7d9079a94, 0x35a2809d15468d83, @@ -515,7 +533,8 @@ fn test_fq2_addition() { 0xd62fa51334f560fa, 0x9ad265eb46e01984, 0x1303f3465112c8bc - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -533,7 +552,8 @@ fn test_fq2_subtraction() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -541,7 +561,8 @@ fn test_fq2_subtraction() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837, - ])).unwrap(), + ])) + .unwrap(), }; a.sub_assign(&Fq2 { c0: Fq::from_repr(FqRepr([ @@ -551,7 +572,8 @@ fn test_fq2_subtraction() { 0x3b88899a42a6318f, 0x986a4a62fa82a49d, 0x13ce433fa26027f5, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x66323bf80b58b9b9, 0xa1379b6facf6e596, @@ -559,7 +581,8 @@ fn test_fq2_subtraction() { 0x2236f55246d0d44d, 0x4c8c1800eb104566, 0x11d6e20e986c2085, - ])).unwrap(), + ])) + .unwrap(), }); assert_eq!( a, @@ -571,7 +594,8 @@ fn test_fq2_subtraction() { 0xe255902672ef6c43, 0x7f77a718021c342d, 0x72ba14049fe9881 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xeb4abaf7c255d1cd, 0x11df49bc6cacc256, @@ -579,7 +603,8 @@ fn test_fq2_subtraction() { 0xf63905f39ad8cb1f, 0x4cd5dd9fb40b3b8f, 0x957411359ba6e4c - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -597,7 +622,8 @@ fn test_fq2_negation() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -605,7 +631,8 @@ fn test_fq2_negation() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837, - ])).unwrap(), + ])) + .unwrap(), }; a.negate(); assert_eq!( @@ -618,7 +645,8 @@ fn test_fq2_negation() { 0xab107d49317487ab, 0x7e555df189f880e3, 0x19083f5486a10cbd - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x228109103250c9d0, 0x8a411ad149045812, @@ -626,7 +654,8 @@ fn test_fq2_negation() { 0xb07e9bc405608611, 0xfcd559cbe77bd8b8, 0x18d400b280d93e62 - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -644,7 +673,8 @@ fn test_fq2_doubling() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -652,7 +682,8 @@ fn test_fq2_doubling() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837, - ])).unwrap(), + ])) + .unwrap(), }; a.double(); assert_eq!( @@ -665,7 +696,8 @@ fn test_fq2_doubling() { 0x72cd9c7784211627, 0x998c938972a657e7, 0x1f1a52b65bdb3b9 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x2efbeddf9b5dc1b6, 0x28d5ca5ad09f4fdb, @@ -673,7 +705,8 @@ fn test_fq2_doubling() { 0x67f15f81dc49195b, 0x9c8c9bd4b79fa83d, 0x25a226f714d506e - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -691,7 +724,8 @@ fn test_fq2_frobenius_map() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -699,7 +733,8 @@ fn test_fq2_frobenius_map() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837, - ])).unwrap(), + ])) + .unwrap(), }; a.frobenius_map(0); assert_eq!( @@ -712,7 +747,8 @@ fn test_fq2_frobenius_map() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -720,7 +756,8 @@ fn test_fq2_frobenius_map() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837 - ])).unwrap(), + ])) + .unwrap(), } ); a.frobenius_map(1); @@ -734,7 +771,8 @@ fn test_fq2_frobenius_map() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x228109103250c9d0, 0x8a411ad149045812, @@ -742,7 +780,8 @@ fn test_fq2_frobenius_map() { 0xb07e9bc405608611, 0xfcd559cbe77bd8b8, 0x18d400b280d93e62 - ])).unwrap(), + ])) + .unwrap(), } ); a.frobenius_map(1); @@ -756,7 +795,8 @@ fn test_fq2_frobenius_map() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -764,7 +804,8 @@ fn test_fq2_frobenius_map() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837 - ])).unwrap(), + ])) + .unwrap(), } ); a.frobenius_map(2); @@ -778,7 +819,8 @@ fn test_fq2_frobenius_map() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -786,7 +828,8 @@ fn test_fq2_frobenius_map() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837 - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -805,7 +848,8 @@ fn test_fq2_sqrt() { 0xdb4a116b5bf74aa1, 0x1e58b2159dfe10e2, 0x7ca7da1f13606ac - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xfa8de88b7516d2c3, 0x371a75ed14f41629, @@ -813,9 +857,11 @@ fn test_fq2_sqrt() { 0x212611bca4e99121, 0x8ee5394d77afb3d, 0xec92336650e49d5 - ])).unwrap(), - }.sqrt() + ])) .unwrap(), + } + .sqrt() + .unwrap(), Fq2 { c0: Fq::from_repr(FqRepr([ 0x40b299b2704258c5, @@ -824,7 +870,8 @@ fn test_fq2_sqrt() { 0x8d7f1f723d02c1d3, 0x881b3e01b611c070, 0x10f6963bbad2ebc5 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xc099534fc209e752, 0x7670594665676447, @@ -832,7 +879,8 @@ fn test_fq2_sqrt() { 0x6b852aeaf2afcb1b, 0xa4c93b08105d71a9, 0x8d7cfff94216330 - ])).unwrap(), + ])) + .unwrap(), } ); @@ -845,10 +893,12 @@ fn test_fq2_sqrt() { 0x64774b84f38512bf, 0x4b1ba7b6434bacd7, 0x1a0111ea397fe69a - ])).unwrap(), - c1: Fq::zero(), - }.sqrt() + ])) .unwrap(), + c1: Fq::zero(), + } + .sqrt() + .unwrap(), Fq2 { c0: Fq::zero(), c1: Fq::from_repr(FqRepr([ @@ -858,7 +908,8 @@ fn test_fq2_sqrt() { 0x64774b84f38512bf, 0x4b1ba7b6434bacd7, 0x1a0111ea397fe69a - ])).unwrap(), + ])) + .unwrap(), } ); } diff --git a/pairing/src/bls12_381/fq6.rs b/pairing/src/bls12_381/fq6.rs index dbe58f7..b85c95d 100644 --- a/pairing/src/bls12_381/fq6.rs +++ b/pairing/src/bls12_381/fq6.rs @@ -17,7 +17,6 @@ impl ::std::fmt::Display for Fq6 { } } - impl Fq6 { /// Multiply by quadratic nonresidue v. pub fn mul_by_nonresidue(&mut self) { diff --git a/pairing/src/bls12_381/fr.rs b/pairing/src/bls12_381/fr.rs index cb378f4..018e67a 100644 --- a/pairing/src/bls12_381/fr.rs +++ b/pairing/src/bls12_381/fr.rs @@ -388,22 +388,20 @@ fn test_fr_is_valid() { a.0.sub_noborrow(&FrRepr::from(1)); assert!(a.is_valid()); assert!(Fr(FrRepr::from(0)).is_valid()); - assert!( - Fr(FrRepr([ - 0xffffffff00000000, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48 - ])).is_valid() - ); - assert!( - !Fr(FrRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff - ])).is_valid() - ); + assert!(Fr(FrRepr([ + 0xffffffff00000000, + 0x53bda402fffe5bfe, + 0x3339d80809a1d805, + 0x73eda753299d7d48 + ])) + .is_valid()); + assert!(!Fr(FrRepr([ + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff + ])) + .is_valid()); let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, @@ -707,7 +705,8 @@ fn test_fr_squaring() { 0xb79a310579e76ec2, 0xac1da8d0a9af4e5f, 0x13f629c49bf23e97 - ])).unwrap() + ])) + .unwrap() ); let mut rng = XorShiftRng::from_seed([ @@ -857,14 +856,13 @@ fn test_fr_sqrt() { #[test] fn test_fr_from_into_repr() { // r + 1 should not be in the field - assert!( - Fr::from_repr(FrRepr([ - 0xffffffff00000002, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48 - ])).is_err() - ); + assert!(Fr::from_repr(FrRepr([ + 0xffffffff00000002, + 0x53bda402fffe5bfe, + 0x3339d80809a1d805, + 0x73eda753299d7d48 + ])) + .is_err()); // r should not be in the field assert!(Fr::from_repr(Fr::char()).is_err()); @@ -967,7 +965,8 @@ fn test_fr_display() { 0x185ec8eb3f5b5aee, 0x684499ffe4b9dd99, 0x7c9bba7afb68faa - ])).unwrap() + ])) + .unwrap() ), "Fr(0x07c9bba7afb68faa684499ffe4b9dd99185ec8eb3f5b5aeec3cae746a3b5ecc7)".to_string() ); @@ -979,7 +978,8 @@ fn test_fr_display() { 0xb0ad10817df79b6a, 0xd034a80a2b74132b, 0x41cf9a1336f50719 - ])).unwrap() + ])) + .unwrap() ), "Fr(0x41cf9a1336f50719d034a80a2b74132bb0ad10817df79b6a44c71298ff198106)".to_string() ); diff --git a/pairing/src/bls12_381/mod.rs b/pairing/src/bls12_381/mod.rs index 7bc03c6..deb6ffc 100644 --- a/pairing/src/bls12_381/mod.rs +++ b/pairing/src/bls12_381/mod.rs @@ -9,8 +9,8 @@ mod fr; mod tests; pub use self::ec::{ - G1, G1Affine, G1Compressed, G1Prepared, G1Uncompressed, G2, G2Affine, G2Compressed, G2Prepared, - G2Uncompressed, + G1Affine, G1Compressed, G1Prepared, G1Uncompressed, G2Affine, G2Compressed, G2Prepared, + G2Uncompressed, G1, G2, }; pub use self::fq::{Fq, FqRepr}; pub use self::fq12::Fq12; diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs index a81d1a1..952185c 100644 --- a/pairing/src/lib.rs +++ b/pairing/src/lib.rs @@ -37,8 +37,7 @@ pub trait Engine: ScalarEngine { Base = Self::Fq, Scalar = Self::Fr, Affine = Self::G1Affine, - > - + From; + > + From; /// The affine representation of an element in G1. type G1Affine: PairingCurveAffine< @@ -48,8 +47,7 @@ pub trait Engine: ScalarEngine { Projective = Self::G1, Pair = Self::G2Affine, PairingResult = Self::Fqk, - > - + From; + > + From; /// The projective representation of an element in G2. type G2: CurveProjective< @@ -57,8 +55,7 @@ pub trait Engine: ScalarEngine { Base = Self::Fqe, Scalar = Self::Fr, Affine = Self::G2Affine, - > - + From; + > + From; /// The affine representation of an element in G2. type G2Affine: PairingCurveAffine< @@ -68,8 +65,7 @@ pub trait Engine: ScalarEngine { Projective = Self::G2, Pair = Self::G1Affine, PairingResult = Self::Fqk, - > - + From; + > + From; /// The base field that hosts G1. type Fq: PrimeField + SqrtField; @@ -101,7 +97,8 @@ pub trait Engine: ScalarEngine { { Self::final_exponentiation(&Self::miller_loop( [(&(p.into().prepare()), &(q.into().prepare()))].iter(), - )).unwrap() + )) + .unwrap() } } diff --git a/pairing/src/tests/field.rs b/pairing/src/tests/field.rs index 0a33a73..8f3d8d9 100644 --- a/pairing/src/tests/field.rs +++ b/pairing/src/tests/field.rs @@ -117,8 +117,8 @@ pub fn from_str_tests() { { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { From 9a4f6812f1476f465bcff7b7528706f0054f144a Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Thu, 15 Aug 2019 10:38:41 -0600 Subject: [PATCH 074/330] cargo fmt bellman --- bellman/src/domain.rs | 101 +- bellman/src/gadgets.rs | 14 +- bellman/src/gadgets/blake2s.rs | 238 ++-- bellman/src/gadgets/boolean.rs | 1203 ++++++++++++--------- bellman/src/gadgets/lookup.rs | 193 ++-- bellman/src/gadgets/multieq.rs | 76 +- bellman/src/gadgets/multipack.rs | 79 +- bellman/src/gadgets/num.rs | 289 +++-- bellman/src/gadgets/sha256.rs | 231 ++-- bellman/src/gadgets/test/mod.rs | 199 ++-- bellman/src/gadgets/uint32.rs | 383 +++---- bellman/src/groth16/generator.rs | 211 ++-- bellman/src/groth16/mod.rs | 322 +++--- bellman/src/groth16/prover.rs | 189 ++-- bellman/src/groth16/tests/dummy_engine.rs | 45 +- bellman/src/groth16/tests/mod.rs | 166 ++- bellman/src/groth16/verifier.rs | 35 +- bellman/src/lib.rs | 180 ++- bellman/src/multicore.rs | 47 +- bellman/src/multiexp.rs | 120 +- bellman/tests/mimc.rs | 96 +- 21 files changed, 2252 insertions(+), 2165 deletions(-) diff --git a/bellman/src/domain.rs b/bellman/src/domain.rs index 5d7d500..808d2af 100644 --- a/bellman/src/domain.rs +++ b/bellman/src/domain.rs @@ -13,9 +13,7 @@ use ff::{Field, PrimeField, ScalarEngine}; use group::CurveProjective; -use super::{ - SynthesisError -}; +use super::SynthesisError; use super::multicore::Worker; @@ -25,7 +23,7 @@ pub struct EvaluationDomain> { omega: E::Fr, omegainv: E::Fr, geninv: E::Fr, - minv: E::Fr + minv: E::Fr, } impl> EvaluationDomain { @@ -41,8 +39,7 @@ impl> EvaluationDomain { self.coeffs } - pub fn from_coeffs(mut coeffs: Vec) -> Result, SynthesisError> - { + pub fn from_coeffs(mut coeffs: Vec) -> Result, SynthesisError> { // Compute the size of our evaluation domain let mut m = 1; let mut exp = 0; @@ -53,7 +50,7 @@ impl> EvaluationDomain { // The pairing-friendly curve may not be able to support // large enough (radix2) evaluation domains. if exp >= E::Fr::S { - return Err(SynthesisError::PolynomialDegreeTooLarge) + return Err(SynthesisError::PolynomialDegreeTooLarge); } } @@ -72,17 +69,18 @@ impl> EvaluationDomain { omega: omega, omegainv: omega.inverse().unwrap(), geninv: E::Fr::multiplicative_generator().inverse().unwrap(), - minv: E::Fr::from_str(&format!("{}", m)).unwrap().inverse().unwrap() + minv: E::Fr::from_str(&format!("{}", m)) + .unwrap() + .inverse() + .unwrap(), }) } - pub fn fft(&mut self, worker: &Worker) - { + pub fn fft(&mut self, worker: &Worker) { best_fft(&mut self.coeffs, worker, &self.omega, self.exp); } - pub fn ifft(&mut self, worker: &Worker) - { + pub fn ifft(&mut self, worker: &Worker) { best_fft(&mut self.coeffs, worker, &self.omegainv, self.exp); worker.scope(self.coeffs.len(), |scope, chunk| { @@ -98,8 +96,7 @@ impl> EvaluationDomain { }); } - pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr) - { + pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr) { worker.scope(self.coeffs.len(), |scope, chunk| { for (i, v) in self.coeffs.chunks_mut(chunk).enumerate() { scope.spawn(move || { @@ -113,14 +110,12 @@ impl> EvaluationDomain { }); } - pub fn coset_fft(&mut self, worker: &Worker) - { + pub fn coset_fft(&mut self, worker: &Worker) { self.distribute_powers(worker, E::Fr::multiplicative_generator()); self.fft(worker); } - pub fn icoset_fft(&mut self, worker: &Worker) - { + pub fn icoset_fft(&mut self, worker: &Worker) { let geninv = self.geninv; self.ifft(worker); @@ -139,9 +134,11 @@ impl> EvaluationDomain { /// The target polynomial is the zero polynomial in our /// evaluation domain, so we must perform division over /// a coset. - pub fn divide_by_z_on_coset(&mut self, worker: &Worker) - { - let i = self.z(&E::Fr::multiplicative_generator()).inverse().unwrap(); + pub fn divide_by_z_on_coset(&mut self, worker: &Worker) { + let i = self + .z(&E::Fr::multiplicative_generator()) + .inverse() + .unwrap(); worker.scope(self.coeffs.len(), |scope, chunk| { for v in self.coeffs.chunks_mut(chunk) { @@ -159,7 +156,11 @@ impl> EvaluationDomain { assert_eq!(self.coeffs.len(), other.coeffs.len()); worker.scope(self.coeffs.len(), |scope, chunk| { - for (a, b) in self.coeffs.chunks_mut(chunk).zip(other.coeffs.chunks(chunk)) { + for (a, b) in self + .coeffs + .chunks_mut(chunk) + .zip(other.coeffs.chunks(chunk)) + { scope.spawn(move || { for (a, b) in a.iter_mut().zip(b.iter()) { a.group_mul_assign(&b.0); @@ -174,7 +175,11 @@ impl> EvaluationDomain { assert_eq!(self.coeffs.len(), other.coeffs.len()); worker.scope(self.coeffs.len(), |scope, chunk| { - for (a, b) in self.coeffs.chunks_mut(chunk).zip(other.coeffs.chunks(chunk)) { + for (a, b) in self + .coeffs + .chunks_mut(chunk) + .zip(other.coeffs.chunks(chunk)) + { scope.spawn(move || { for (a, b) in a.iter_mut().zip(b.iter()) { a.group_sub_assign(&b); @@ -200,7 +205,7 @@ impl PartialEq for Point { } } -impl Copy for Point { } +impl Copy for Point {} impl Clone for Point { fn clone(&self) -> Point { @@ -231,7 +236,7 @@ impl PartialEq for Scalar { } } -impl Copy for Scalar { } +impl Copy for Scalar {} impl Clone for Scalar { fn clone(&self) -> Scalar { @@ -254,8 +259,7 @@ impl Group for Scalar { } } -fn best_fft>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32) -{ +fn best_fft>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32) { let log_cpus = worker.log_num_cpus(); if log_n <= log_cpus { @@ -265,8 +269,7 @@ fn best_fft>(a: &mut [T], worker: &Worker, omega: & } } -fn serial_fft>(a: &mut [T], omega: &E::Fr, log_n: u32) -{ +fn serial_fft>(a: &mut [T], omega: &E::Fr, log_n: u32) { fn bitreverse(mut n: u32, l: u32) -> u32 { let mut r = 0; for _ in 0..l { @@ -288,22 +291,22 @@ fn serial_fft>(a: &mut [T], omega: &E::Fr, log_n: u let mut m = 1; for _ in 0..log_n { - let w_m = omega.pow(&[(n / (2*m)) as u64]); + let w_m = omega.pow(&[(n / (2 * m)) as u64]); let mut k = 0; while k < n { let mut w = E::Fr::one(); for j in 0..m { - let mut t = a[(k+j+m) as usize]; + let mut t = a[(k + j + m) as usize]; t.group_mul_assign(&w); - let mut tmp = a[(k+j) as usize]; + let mut tmp = a[(k + j) as usize]; tmp.group_sub_assign(&t); - a[(k+j+m) as usize] = tmp; - a[(k+j) as usize].group_add_assign(&t); + a[(k + j + m) as usize] = tmp; + a[(k + j) as usize].group_add_assign(&t); w.mul_assign(&w_m); } - k += 2*m; + k += 2 * m; } m *= 2; @@ -315,9 +318,8 @@ fn parallel_fft>( worker: &Worker, omega: &E::Fr, log_n: u32, - log_cpus: u32 -) -{ + log_cpus: u32, +) { assert!(log_n >= log_cpus); let num_cpus = 1 << log_cpus; @@ -377,14 +379,17 @@ fn polynomial_arith() { use pairing::bls12_381::Bls12; use rand_core::RngCore; - fn test_mul(rng: &mut R) - { + fn test_mul(rng: &mut R) { let worker = Worker::new(); for coeffs_a in 0..70 { for coeffs_b in 0..70 { - let mut a: Vec<_> = (0..coeffs_a).map(|_| Scalar::(E::Fr::random(rng))).collect(); - let mut b: Vec<_> = (0..coeffs_b).map(|_| Scalar::(E::Fr::random(rng))).collect(); + let mut a: Vec<_> = (0..coeffs_a) + .map(|_| Scalar::(E::Fr::random(rng))) + .collect(); + let mut b: Vec<_> = (0..coeffs_b) + .map(|_| Scalar::(E::Fr::random(rng))) + .collect(); // naive evaluation let mut naive = vec![Scalar(E::Fr::zero()); coeffs_a + coeffs_b]; @@ -425,8 +430,7 @@ fn fft_composition() { use pairing::bls12_381::Bls12; use rand_core::RngCore; - fn test_comp(rng: &mut R) - { + fn test_comp(rng: &mut R) { let worker = Worker::new(); for coeffs in 0..10 { @@ -465,19 +469,20 @@ fn parallel_fft_consistency() { use rand_core::RngCore; use std::cmp::min; - fn test_consistency(rng: &mut R) - { + fn test_consistency(rng: &mut R) { let worker = Worker::new(); for _ in 0..5 { for log_d in 0..10 { let d = 1 << log_d; - let v1 = (0..d).map(|_| Scalar::(E::Fr::random(rng))).collect::>(); + let v1 = (0..d) + .map(|_| Scalar::(E::Fr::random(rng))) + .collect::>(); let mut v1 = EvaluationDomain::from_coeffs(v1).unwrap(); let mut v2 = EvaluationDomain::from_coeffs(v1.coeffs.clone()).unwrap(); - for log_cpus in log_d..min(log_d+1, 3) { + for log_cpus in log_d..min(log_d + 1, 3) { parallel_fft(&mut v1.coeffs, &worker, &v1.omega, log_d, log_cpus); serial_fft(&mut v2.coeffs, &v2.omega, log_d); diff --git a/bellman/src/gadgets.rs b/bellman/src/gadgets.rs index 6c4b09c..cf366df 100644 --- a/bellman/src/gadgets.rs +++ b/bellman/src/gadgets.rs @@ -1,17 +1,15 @@ pub mod test; -pub mod boolean; -pub mod multieq; -pub mod uint32; pub mod blake2s; -pub mod num; +pub mod boolean; pub mod lookup; +pub mod multieq; pub mod multipack; +pub mod num; pub mod sha256; +pub mod uint32; -use crate::{ - SynthesisError -}; +use crate::SynthesisError; // TODO: This should probably be removed and we // should use existing helper methods on `Option` @@ -27,7 +25,7 @@ impl Assignment for Option { fn get(&self) -> Result<&T, SynthesisError> { match *self { Some(ref v) => Ok(v), - None => Err(SynthesisError::AssignmentMissing) + None => Err(SynthesisError::AssignmentMissing), } } } diff --git a/bellman/src/gadgets/blake2s.rs b/bellman/src/gadgets/blake2s.rs index cef50eb..c5cee23 100644 --- a/bellman/src/gadgets/blake2s.rs +++ b/bellman/src/gadgets/blake2s.rs @@ -1,19 +1,10 @@ -use pairing::{ - Engine, -}; +use pairing::Engine; -use crate::{ - SynthesisError, - ConstraintSystem -}; +use crate::{ConstraintSystem, SynthesisError}; -use super::boolean::{ - Boolean -}; +use super::boolean::Boolean; -use super::uint32::{ - UInt32 -}; +use super::uint32::UInt32; use super::multieq::MultiEq; @@ -65,7 +56,7 @@ const SIGMA: [[usize; 16]; 10] = [ [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], - [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0] + [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0], ]; /* @@ -98,17 +89,30 @@ fn mixing_g, M>( c: usize, d: usize, x: &UInt32, - y: &UInt32 + y: &UInt32, ) -> Result<(), SynthesisError> - where M: ConstraintSystem> +where + M: ConstraintSystem>, { - v[a] = UInt32::addmany(cs.namespace(|| "mixing step 1"), &[v[a].clone(), v[b].clone(), x.clone()])?; + v[a] = UInt32::addmany( + cs.namespace(|| "mixing step 1"), + &[v[a].clone(), v[b].clone(), x.clone()], + )?; v[d] = v[d].xor(cs.namespace(|| "mixing step 2"), &v[a])?.rotr(R1); - v[c] = UInt32::addmany(cs.namespace(|| "mixing step 3"), &[v[c].clone(), v[d].clone()])?; + v[c] = UInt32::addmany( + cs.namespace(|| "mixing step 3"), + &[v[c].clone(), v[d].clone()], + )?; v[b] = v[b].xor(cs.namespace(|| "mixing step 4"), &v[c])?.rotr(R2); - v[a] = UInt32::addmany(cs.namespace(|| "mixing step 5"), &[v[a].clone(), v[b].clone(), y.clone()])?; + v[a] = UInt32::addmany( + cs.namespace(|| "mixing step 5"), + &[v[a].clone(), v[b].clone(), y.clone()], + )?; v[d] = v[d].xor(cs.namespace(|| "mixing step 6"), &v[a])?.rotr(R3); - v[c] = UInt32::addmany(cs.namespace(|| "mixing step 7"), &[v[c].clone(), v[d].clone()])?; + v[c] = UInt32::addmany( + cs.namespace(|| "mixing step 7"), + &[v[c].clone(), v[d].clone()], + )?; v[b] = v[b].xor(cs.namespace(|| "mixing step 8"), &v[c])?.rotr(R4); Ok(()) @@ -162,15 +166,13 @@ fn mixing_g, M>( END FUNCTION. */ - fn blake2s_compression>( mut cs: CS, h: &mut [UInt32], m: &[UInt32], t: u64, - f: bool -) -> Result<(), SynthesisError> -{ + f: bool, +) -> Result<(), SynthesisError> { assert_eq!(h.len(), 8); assert_eq!(m.len(), 16); @@ -196,10 +198,16 @@ fn blake2s_compression>( assert_eq!(v.len(), 16); v[12] = v[12].xor(cs.namespace(|| "first xor"), &UInt32::constant(t as u32))?; - v[13] = v[13].xor(cs.namespace(|| "second xor"), &UInt32::constant((t >> 32) as u32))?; + v[13] = v[13].xor( + cs.namespace(|| "second xor"), + &UInt32::constant((t >> 32) as u32), + )?; if f { - v[14] = v[14].xor(cs.namespace(|| "third xor"), &UInt32::constant(u32::max_value()))?; + v[14] = v[14].xor( + cs.namespace(|| "third xor"), + &UInt32::constant(u32::max_value()), + )?; } { @@ -210,20 +218,92 @@ fn blake2s_compression>( let s = SIGMA[i % 10]; - mixing_g(cs.namespace(|| "mixing invocation 1"), &mut v, 0, 4, 8, 12, &m[s[ 0]], &m[s[ 1]])?; - mixing_g(cs.namespace(|| "mixing invocation 2"), &mut v, 1, 5, 9, 13, &m[s[ 2]], &m[s[ 3]])?; - mixing_g(cs.namespace(|| "mixing invocation 3"), &mut v, 2, 6, 10, 14, &m[s[ 4]], &m[s[ 5]])?; - mixing_g(cs.namespace(|| "mixing invocation 4"), &mut v, 3, 7, 11, 15, &m[s[ 6]], &m[s[ 7]])?; + mixing_g( + cs.namespace(|| "mixing invocation 1"), + &mut v, + 0, + 4, + 8, + 12, + &m[s[0]], + &m[s[1]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 2"), + &mut v, + 1, + 5, + 9, + 13, + &m[s[2]], + &m[s[3]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 3"), + &mut v, + 2, + 6, + 10, + 14, + &m[s[4]], + &m[s[5]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 4"), + &mut v, + 3, + 7, + 11, + 15, + &m[s[6]], + &m[s[7]], + )?; - mixing_g(cs.namespace(|| "mixing invocation 5"), &mut v, 0, 5, 10, 15, &m[s[ 8]], &m[s[ 9]])?; - mixing_g(cs.namespace(|| "mixing invocation 6"), &mut v, 1, 6, 11, 12, &m[s[10]], &m[s[11]])?; - mixing_g(cs.namespace(|| "mixing invocation 7"), &mut v, 2, 7, 8, 13, &m[s[12]], &m[s[13]])?; - mixing_g(cs.namespace(|| "mixing invocation 8"), &mut v, 3, 4, 9, 14, &m[s[14]], &m[s[15]])?; + mixing_g( + cs.namespace(|| "mixing invocation 5"), + &mut v, + 0, + 5, + 10, + 15, + &m[s[8]], + &m[s[9]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 6"), + &mut v, + 1, + 6, + 11, + 12, + &m[s[10]], + &m[s[11]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 7"), + &mut v, + 2, + 7, + 8, + 13, + &m[s[12]], + &m[s[13]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 8"), + &mut v, + 3, + 4, + 9, + 14, + &m[s[14]], + &m[s[15]], + )?; } } for i in 0..8 { - let mut cs = cs.namespace(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i=i)); + let mut cs = cs.namespace(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i = i)); h[i] = h[i].xor(cs.namespace(|| "first xor"), &v[i])?; h[i] = h[i].xor(cs.namespace(|| "second xor"), &v[i + 8])?; @@ -262,9 +342,8 @@ fn blake2s_compression>( pub fn blake2s>( mut cs: CS, input: &[Boolean], - personalization: &[u8] -) -> Result, SynthesisError> -{ + personalization: &[u8], +) -> Result, SynthesisError> { use byteorder::{ByteOrder, LittleEndian}; assert_eq!(personalization.len(), 8); @@ -279,8 +358,12 @@ pub fn blake2s>( h.push(UInt32::constant(0x9B05688C)); // Personalization is stored here - h.push(UInt32::constant(0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4]))); - h.push(UInt32::constant(0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8]))); + h.push(UInt32::constant( + 0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4]), + )); + h.push(UInt32::constant( + 0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8]), + )); let mut blocks: Vec> = vec![]; @@ -312,7 +395,13 @@ pub fn blake2s>( { let cs = cs.namespace(|| "final block"); - blake2s_compression(cs, &mut h, &blocks[blocks.len() - 1], (input.len() / 8) as u64, true)?; + blake2s_compression( + cs, + &mut h, + &blocks[blocks.len() - 1], + (input.len() / 8) as u64, + true, + )?; } Ok(h.iter().flat_map(|b| b.into_bits()).collect()) @@ -321,14 +410,14 @@ pub fn blake2s>( #[cfg(test)] mod test { use blake2s_simd::Params as Blake2sParams; - use pairing::bls12_381::{Bls12}; + use pairing::bls12_381::Bls12; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; - use crate::gadgets::boolean::{Boolean, AllocatedBit}; - use crate::gadgets::test::TestConstraintSystem; use super::blake2s; - use crate::{ConstraintSystem}; + use crate::gadgets::boolean::{AllocatedBit, Boolean}; + use crate::gadgets::test::TestConstraintSystem; + use crate::ConstraintSystem; #[test] fn test_blank_hash() { @@ -356,7 +445,13 @@ mod test { #[test] fn test_blake2s_constraints() { let mut cs = TestConstraintSystem::::new(); - let input_bits: Vec<_> = (0..512).map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into()).collect(); + let input_bits: Vec<_> = (0..512) + .map(|i| { + AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)) + .unwrap() + .into() + }) + .collect(); blake2s(&mut cs, &input_bits, b"12345678").unwrap(); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 21518); @@ -369,14 +464,17 @@ mod test { let mut cs = TestConstraintSystem::::new(); let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); let input_bits: Vec<_> = (0..512) - .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) - .chain((0..512) - .map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into())) - .collect(); + .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) + .chain((0..512).map(|i| { + AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)) + .unwrap() + .into() + })) + .collect(); blake2s(&mut cs, &input_bits, b"12345678").unwrap(); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 21518); @@ -386,10 +484,12 @@ mod test { fn test_blake2s_constant_constraints() { let mut cs = TestConstraintSystem::::new(); let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); - let input_bits: Vec<_> = (0..512).map(|_| Boolean::constant(rng.next_u32() % 2 != 0)).collect(); + let input_bits: Vec<_> = (0..512) + .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) + .collect(); blake2s(&mut cs, &input_bits, b"12345678").unwrap(); assert_eq!(cs.num_constraints(), 0); } @@ -397,13 +497,15 @@ mod test { #[test] fn test_blake2s() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); - for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) - { - let mut h = Blake2sParams::new().hash_length(32).personal(b"12345678").to_state(); + for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) { + let mut h = Blake2sParams::new() + .hash_length(32) + .personal(b"12345678") + .to_state(); let data: Vec = (0..input_len).map(|_| rng.next_u32() as u8).collect(); @@ -419,7 +521,11 @@ mod test { for bit_i in 0..8 { let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i)); - input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into()); + input_bits.push( + AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)) + .unwrap() + .into(), + ); } } @@ -427,17 +533,19 @@ mod test { assert!(cs.is_satisfied()); - let mut s = hash_result.as_ref().iter() - .flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8)); + let mut s = hash_result + .as_ref() + .iter() + .flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8)); for b in r { match b { Boolean::Is(b) => { assert!(s.next().unwrap() == b.get_value().unwrap()); - }, + } Boolean::Not(b) => { assert!(s.next().unwrap() != b.get_value().unwrap()); - }, + } Boolean::Constant(b) => { assert!(input_len == 0); assert!(s.next().unwrap() == b); diff --git a/bellman/src/gadgets/boolean.rs b/bellman/src/gadgets/boolean.rs index f6c11b6..414b290 100644 --- a/bellman/src/gadgets/boolean.rs +++ b/bellman/src/gadgets/boolean.rs @@ -1,23 +1,16 @@ use ff::{BitIterator, Field, PrimeField}; use pairing::Engine; -use crate::{ - ConstraintSystem, - SynthesisError, - LinearCombination, - Variable -}; +use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; -use super::{ - Assignment -}; +use super::Assignment; /// Represents a variable in the constraint system which is guaranteed /// to be either zero or one. #[derive(Clone)] pub struct AllocatedBit { variable: Variable, - value: Option + value: Option, } impl AllocatedBit { @@ -35,18 +28,22 @@ impl AllocatedBit { pub fn alloc_conditionally( mut cs: CS, value: Option, - must_be_false: &AllocatedBit + must_be_false: &AllocatedBit, ) -> Result - where E: Engine, - CS: ConstraintSystem + where + E: Engine, + CS: ConstraintSystem, { - let var = cs.alloc(|| "boolean", || { - if *value.get()? { - Ok(E::Fr::one()) - } else { - Ok(E::Fr::zero()) - } - })?; + let var = cs.alloc( + || "boolean", + || { + if *value.get()? { + Ok(E::Fr::one()) + } else { + Ok(E::Fr::zero()) + } + }, + )?; // Constrain: (1 - must_be_false - a) * a = 0 // if must_be_false is true, the equation @@ -58,31 +55,32 @@ impl AllocatedBit { || "boolean constraint", |lc| lc + CS::one() - must_be_false.variable - var, |lc| lc + var, - |lc| lc + |lc| lc, ); Ok(AllocatedBit { variable: var, - value: value + value: value, }) } /// Allocate a variable in the constraint system which can only be a /// boolean value. - pub fn alloc( - mut cs: CS, - value: Option, - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn alloc(mut cs: CS, value: Option) -> Result + where + E: Engine, + CS: ConstraintSystem, { - let var = cs.alloc(|| "boolean", || { - if *value.get()? { - Ok(E::Fr::one()) - } else { - Ok(E::Fr::zero()) - } - })?; + let var = cs.alloc( + || "boolean", + || { + if *value.get()? { + Ok(E::Fr::one()) + } else { + Ok(E::Fr::zero()) + } + }, + )?; // Constrain: (1 - a) * a = 0 // This constrains a to be either 0 or 1. @@ -90,38 +88,38 @@ impl AllocatedBit { || "boolean constraint", |lc| lc + CS::one() - var, |lc| lc + var, - |lc| lc + |lc| lc, ); Ok(AllocatedBit { variable: var, - value: value + value: value, }) } /// Performs an XOR operation over the two operands, returning /// an `AllocatedBit`. - pub fn xor( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn xor(mut cs: CS, a: &Self, b: &Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { let mut result_value = None; - let result_var = cs.alloc(|| "xor result", || { - if *a.value.get()? ^ *b.value.get()? { - result_value = Some(true); + let result_var = cs.alloc( + || "xor result", + || { + if *a.value.get()? ^ *b.value.get()? { + result_value = Some(true); - Ok(E::Fr::one()) - } else { - result_value = Some(false); + Ok(E::Fr::one()) + } else { + result_value = Some(false); - Ok(E::Fr::zero()) - } - })?; + Ok(E::Fr::zero()) + } + }, + )?; // Constrain (a + a) * (b) = (a + b - c) // Given that a and b are boolean constrained, if they @@ -142,38 +140,38 @@ impl AllocatedBit { || "xor constraint", |lc| lc + a.variable + a.variable, |lc| lc + b.variable, - |lc| lc + a.variable + b.variable - result_var + |lc| lc + a.variable + b.variable - result_var, ); Ok(AllocatedBit { variable: result_var, - value: result_value + value: result_value, }) } /// Performs an AND operation over the two operands, returning /// an `AllocatedBit`. - pub fn and( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn and(mut cs: CS, a: &Self, b: &Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { let mut result_value = None; - let result_var = cs.alloc(|| "and result", || { - if *a.value.get()? & *b.value.get()? { - result_value = Some(true); + let result_var = cs.alloc( + || "and result", + || { + if *a.value.get()? & *b.value.get()? { + result_value = Some(true); - Ok(E::Fr::one()) - } else { - result_value = Some(false); + Ok(E::Fr::one()) + } else { + result_value = Some(false); - Ok(E::Fr::zero()) - } - })?; + Ok(E::Fr::zero()) + } + }, + )?; // Constrain (a) * (b) = (c), ensuring c is 1 iff // a AND b are both 1. @@ -181,37 +179,37 @@ impl AllocatedBit { || "and constraint", |lc| lc + a.variable, |lc| lc + b.variable, - |lc| lc + result_var + |lc| lc + result_var, ); Ok(AllocatedBit { variable: result_var, - value: result_value + value: result_value, }) } /// Calculates `a AND (NOT b)`. - pub fn and_not( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn and_not(mut cs: CS, a: &Self, b: &Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { let mut result_value = None; - let result_var = cs.alloc(|| "and not result", || { - if *a.value.get()? & !*b.value.get()? { - result_value = Some(true); + let result_var = cs.alloc( + || "and not result", + || { + if *a.value.get()? & !*b.value.get()? { + result_value = Some(true); - Ok(E::Fr::one()) - } else { - result_value = Some(false); + Ok(E::Fr::one()) + } else { + result_value = Some(false); - Ok(E::Fr::zero()) - } - })?; + Ok(E::Fr::zero()) + } + }, + )?; // Constrain (a) * (1 - b) = (c), ensuring c is 1 iff // a is true and b is false, and otherwise c is 0. @@ -219,37 +217,37 @@ impl AllocatedBit { || "and not constraint", |lc| lc + a.variable, |lc| lc + CS::one() - b.variable, - |lc| lc + result_var + |lc| lc + result_var, ); Ok(AllocatedBit { variable: result_var, - value: result_value + value: result_value, }) } /// Calculates `(NOT a) AND (NOT b)`. - pub fn nor( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn nor(mut cs: CS, a: &Self, b: &Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { let mut result_value = None; - let result_var = cs.alloc(|| "nor result", || { - if !*a.value.get()? & !*b.value.get()? { - result_value = Some(true); + let result_var = cs.alloc( + || "nor result", + || { + if !*a.value.get()? & !*b.value.get()? { + result_value = Some(true); - Ok(E::Fr::one()) - } else { - result_value = Some(false); + Ok(E::Fr::one()) + } else { + result_value = Some(false); - Ok(E::Fr::zero()) - } - })?; + Ok(E::Fr::zero()) + } + }, + )?; // Constrain (1 - a) * (1 - b) = (c), ensuring c is 1 iff // a and b are both false, and otherwise c is 0. @@ -257,21 +255,20 @@ impl AllocatedBit { || "nor constraint", |lc| lc + CS::one() - a.variable, |lc| lc + CS::one() - b.variable, - |lc| lc + result_var + |lc| lc + result_var, ); Ok(AllocatedBit { variable: result_var, - value: result_value + value: result_value, }) } } pub fn u64_into_boolean_vec_le>( mut cs: CS, - value: Option -) -> Result, SynthesisError> -{ + value: Option, +) -> Result, SynthesisError> { let values = match value { Some(ref value) => { let mut tmp = Vec::with_capacity(64); @@ -281,27 +278,28 @@ pub fn u64_into_boolean_vec_le>( } tmp - }, - None => { - vec![None; 64] } + None => vec![None; 64], }; - let bits = values.into_iter().enumerate().map(|(i, b)| { - Ok(Boolean::from(AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - b - )?)) - }).collect::, SynthesisError>>()?; + let bits = values + .into_iter() + .enumerate() + .map(|(i, b)| { + Ok(Boolean::from(AllocatedBit::alloc( + cs.namespace(|| format!("bit {}", i)), + b, + )?)) + }) + .collect::, SynthesisError>>()?; Ok(bits) } pub fn field_into_boolean_vec_le, F: PrimeField>( cs: CS, - value: Option -) -> Result, SynthesisError> -{ + value: Option, +) -> Result, SynthesisError> { let v = field_into_allocated_bits_le::(cs, value)?; Ok(v.into_iter().map(|e| Boolean::from(e)).collect()) @@ -309,9 +307,8 @@ pub fn field_into_boolean_vec_le, F: PrimeFie pub fn field_into_allocated_bits_le, F: PrimeField>( mut cs: CS, - value: Option -) -> Result, SynthesisError> -{ + value: Option, +) -> Result, SynthesisError> { // Deconstruct in big-endian bit order let values = match value { Some(ref value) => { @@ -333,19 +330,17 @@ pub fn field_into_allocated_bits_le, F: Prime assert_eq!(tmp.len(), F::NUM_BITS as usize); tmp - }, - None => { - vec![None; F::NUM_BITS as usize] } + None => vec![None; F::NUM_BITS as usize], }; // Allocate in little-endian order - let bits = values.into_iter().rev().enumerate().map(|(i, b)| { - AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - b - ) - }).collect::, SynthesisError>>()?; + let bits = values + .into_iter() + .rev() + .enumerate() + .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), b)) + .collect::, SynthesisError>>()?; Ok(bits) } @@ -359,24 +354,21 @@ pub enum Boolean { /// Negated view of the boolean variable Not(AllocatedBit), /// Constant (not an allocated variable) - Constant(bool) + Constant(bool), } impl Boolean { pub fn is_constant(&self) -> bool { match *self { Boolean::Constant(_) => true, - _ => false + _ => false, } } - pub fn enforce_equal( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result<(), SynthesisError> - where E: Engine, - CS: ConstraintSystem + pub fn enforce_equal(mut cs: CS, a: &Self, b: &Self) -> Result<(), SynthesisError> + where + E: Engine, + CS: ConstraintSystem, { match (a, b) { (&Boolean::Constant(a), &Boolean::Constant(b)) => { @@ -385,33 +377,33 @@ impl Boolean { } else { Err(SynthesisError::Unsatisfiable) } - }, + } (&Boolean::Constant(true), a) | (a, &Boolean::Constant(true)) => { cs.enforce( || "enforce equal to one", |lc| lc, |lc| lc, - |lc| lc + CS::one() - &a.lc(CS::one(), E::Fr::one()) + |lc| lc + CS::one() - &a.lc(CS::one(), E::Fr::one()), ); Ok(()) - }, + } (&Boolean::Constant(false), a) | (a, &Boolean::Constant(false)) => { cs.enforce( || "enforce equal to zero", |lc| lc, |lc| lc, - |_| a.lc(CS::one(), E::Fr::one()) + |_| a.lc(CS::one(), E::Fr::one()), ); Ok(()) - }, + } (a, b) => { cs.enforce( || "enforce equal", |lc| lc, |lc| lc, - |_| a.lc(CS::one(), E::Fr::one()) - &b.lc(CS::one(), E::Fr::one()) + |_| a.lc(CS::one(), E::Fr::one()) - &b.lc(CS::one(), E::Fr::one()), ); Ok(()) @@ -423,16 +415,11 @@ impl Boolean { match self { &Boolean::Constant(c) => Some(c), &Boolean::Is(ref v) => v.get_value(), - &Boolean::Not(ref v) => v.get_value().map(|b| !b) + &Boolean::Not(ref v) => v.get_value().map(|b| !b), } } - pub fn lc( - &self, - one: Variable, - coeff: E::Fr - ) -> LinearCombination - { + pub fn lc(&self, one: Variable, coeff: E::Fr) -> LinearCombination { match self { &Boolean::Constant(c) => { if c { @@ -440,10 +427,8 @@ impl Boolean { } else { LinearCombination::::zero() } - }, - &Boolean::Is(ref v) => { - LinearCombination::::zero() + (coeff, v.get_variable()) - }, + } + &Boolean::Is(ref v) => LinearCombination::::zero() + (coeff, v.get_variable()), &Boolean::Not(ref v) => { LinearCombination::::zero() + (coeff, one) - (coeff, v.get_variable()) } @@ -460,59 +445,54 @@ impl Boolean { match self { &Boolean::Constant(c) => Boolean::Constant(!c), &Boolean::Is(ref v) => Boolean::Not(v.clone()), - &Boolean::Not(ref v) => Boolean::Is(v.clone()) + &Boolean::Not(ref v) => Boolean::Is(v.clone()), } } /// Perform XOR over two boolean operands - pub fn xor<'a, E, CS>( - cs: CS, - a: &'a Self, - b: &'a Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn xor<'a, E, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { match (a, b) { (&Boolean::Constant(false), x) | (x, &Boolean::Constant(false)) => Ok(x.clone()), (&Boolean::Constant(true), x) | (x, &Boolean::Constant(true)) => Ok(x.not()), // a XOR (NOT b) = NOT(a XOR b) - (is @ &Boolean::Is(_), not @ &Boolean::Not(_)) | (not @ &Boolean::Not(_), is @ &Boolean::Is(_)) => { - Ok(Boolean::xor( - cs, - is, - ¬.not() - )?.not()) - }, + (is @ &Boolean::Is(_), not @ &Boolean::Not(_)) + | (not @ &Boolean::Not(_), is @ &Boolean::Is(_)) => { + Ok(Boolean::xor(cs, is, ¬.not())?.not()) + } // a XOR b = (NOT a) XOR (NOT b) - (&Boolean::Is(ref a), &Boolean::Is(ref b)) | (&Boolean::Not(ref a), &Boolean::Not(ref b)) => { + (&Boolean::Is(ref a), &Boolean::Is(ref b)) + | (&Boolean::Not(ref a), &Boolean::Not(ref b)) => { Ok(Boolean::Is(AllocatedBit::xor(cs, a, b)?)) } } } /// Perform AND over two boolean operands - pub fn and<'a, E, CS>( - cs: CS, - a: &'a Self, - b: &'a Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn and<'a, E, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { match (a, b) { // false AND x is always false - (&Boolean::Constant(false), _) | (_, &Boolean::Constant(false)) => Ok(Boolean::Constant(false)), + (&Boolean::Constant(false), _) | (_, &Boolean::Constant(false)) => { + Ok(Boolean::Constant(false)) + } // true AND x is always x (&Boolean::Constant(true), x) | (x, &Boolean::Constant(true)) => Ok(x.clone()), // a AND (NOT b) - (&Boolean::Is(ref is), &Boolean::Not(ref not)) | (&Boolean::Not(ref not), &Boolean::Is(ref is)) => { + (&Boolean::Is(ref is), &Boolean::Not(ref not)) + | (&Boolean::Not(ref not), &Boolean::Is(ref is)) => { Ok(Boolean::Is(AllocatedBit::and_not(cs, is, not)?)) - }, + } // (NOT a) AND (NOT b) = a NOR b (&Boolean::Not(ref a), &Boolean::Not(ref b)) => { Ok(Boolean::Is(AllocatedBit::nor(cs, a, b)?)) - }, + } // a AND b (&Boolean::Is(ref a), &Boolean::Is(ref b)) => { Ok(Boolean::Is(AllocatedBit::and(cs, a, b)?)) @@ -525,27 +505,26 @@ impl Boolean { mut cs: CS, a: &'a Self, b: &'a Self, - c: &'a Self + c: &'a Self, ) -> Result - where E: Engine, - CS: ConstraintSystem + where + E: Engine, + CS: ConstraintSystem, { let ch_value = match (a.get_value(), b.get_value(), c.get_value()) { (Some(a), Some(b), Some(c)) => { // (a and b) xor ((not a) and c) Some((a & b) ^ ((!a) & c)) - }, - _ => None + } + _ => None, }; match (a, b, c) { - (&Boolean::Constant(_), - &Boolean::Constant(_), - &Boolean::Constant(_)) => { + (&Boolean::Constant(_), &Boolean::Constant(_), &Boolean::Constant(_)) => { // They're all constants, so we can just compute the value. return Ok(Boolean::Constant(ch_value.expect("they're all constants"))); - }, + } (&Boolean::Constant(false), _, c) => { // If a is false // (a and b) xor ((not a) and c) @@ -554,29 +533,21 @@ impl Boolean { // equals // c return Ok(c.clone()); - }, + } (a, &Boolean::Constant(false), c) => { // If b is false // (a and b) xor ((not a) and c) // equals // ((not a) and c) - return Boolean::and( - cs, - &a.not(), - &c - ); - }, + return Boolean::and(cs, &a.not(), &c); + } (a, b, &Boolean::Constant(false)) => { // If c is false // (a and b) xor ((not a) and c) // equals // (a and b) - return Boolean::and( - cs, - &a, - &b - ); - }, + return Boolean::and(cs, &a, &b); + } (a, b, &Boolean::Constant(true)) => { // If c is true // (a and b) xor ((not a) and c) @@ -584,12 +555,8 @@ impl Boolean { // (a and b) xor (not a) // equals // not (a and (not b)) - return Ok(Boolean::and( - cs, - &a, - &b.not() - )?.not()); - }, + return Ok(Boolean::and(cs, &a, &b.not())?.not()); + } (a, &Boolean::Constant(true), c) => { // If b is true // (a and b) xor ((not a) and c) @@ -597,53 +564,47 @@ impl Boolean { // a xor ((not a) and c) // equals // not ((not a) and (not c)) - return Ok(Boolean::and( - cs, - &a.not(), - &c.not() - )?.not()); - }, + return Ok(Boolean::and(cs, &a.not(), &c.not())?.not()); + } (&Boolean::Constant(true), _, _) => { // If a is true // (a and b) xor ((not a) and c) // equals // b xor ((not a) and c) // So we just continue! - }, - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_)) - => {} + } + (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) + | (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) + | (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) + | (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) + | (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) + | (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) + | (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) + | (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_)) => {} } - let ch = cs.alloc(|| "ch", || { - ch_value.get().map(|v| { - if *v { - E::Fr::one() - } else { - E::Fr::zero() - } - }) - })?; + let ch = cs.alloc( + || "ch", + || { + ch_value + .get() + .map(|v| if *v { E::Fr::one() } else { E::Fr::zero() }) + }, + )?; // a(b - c) = ch - c cs.enforce( || "ch computation", - |_| b.lc(CS::one(), E::Fr::one()) - - &c.lc(CS::one(), E::Fr::one()), + |_| b.lc(CS::one(), E::Fr::one()) - &c.lc(CS::one(), E::Fr::one()), |_| a.lc(CS::one(), E::Fr::one()), - |lc| lc + ch - &c.lc(CS::one(), E::Fr::one()) + |lc| lc + ch - &c.lc(CS::one(), E::Fr::one()), ); Ok(AllocatedBit { value: ch_value, - variable: ch - }.into()) + variable: ch, + } + .into()) } /// Computes (a and b) xor (a and c) xor (b and c) @@ -653,58 +614,45 @@ impl Boolean { b: &'a Self, c: &'a Self, ) -> Result - where E: Engine, - CS: ConstraintSystem + where + E: Engine, + CS: ConstraintSystem, { let maj_value = match (a.get_value(), b.get_value(), c.get_value()) { (Some(a), Some(b), Some(c)) => { // (a and b) xor (a and c) xor (b and c) Some((a & b) ^ (a & c) ^ (b & c)) - }, - _ => None + } + _ => None, }; match (a, b, c) { - (&Boolean::Constant(_), - &Boolean::Constant(_), - &Boolean::Constant(_)) => { + (&Boolean::Constant(_), &Boolean::Constant(_), &Boolean::Constant(_)) => { // They're all constants, so we can just compute the value. return Ok(Boolean::Constant(maj_value.expect("they're all constants"))); - }, + } (&Boolean::Constant(false), b, c) => { // If a is false, // (a and b) xor (a and c) xor (b and c) // equals // (b and c) - return Boolean::and( - cs, - b, - c - ); - }, + return Boolean::and(cs, b, c); + } (a, &Boolean::Constant(false), c) => { // If b is false, // (a and b) xor (a and c) xor (b and c) // equals // (a and c) - return Boolean::and( - cs, - a, - c - ); - }, + return Boolean::and(cs, a, c); + } (a, b, &Boolean::Constant(false)) => { // If c is false, // (a and b) xor (a and c) xor (b and c) // equals // (a and b) - return Boolean::and( - cs, - a, - b - ); - }, + return Boolean::and(cs, a, b); + } (a, b, &Boolean::Constant(true)) => { // If c is true, // (a and b) xor (a and c) xor (b and c) @@ -712,54 +660,40 @@ impl Boolean { // (a and b) xor (a) xor (b) // equals // not ((not a) and (not b)) - return Ok(Boolean::and( - cs, - &a.not(), - &b.not() - )?.not()); - }, + return Ok(Boolean::and(cs, &a.not(), &b.not())?.not()); + } (a, &Boolean::Constant(true), c) => { // If b is true, // (a and b) xor (a and c) xor (b and c) // equals // (a) xor (a and c) xor (c) - return Ok(Boolean::and( - cs, - &a.not(), - &c.not() - )?.not()); - }, + return Ok(Boolean::and(cs, &a.not(), &c.not())?.not()); + } (&Boolean::Constant(true), b, c) => { // If a is true, // (a and b) xor (a and c) xor (b and c) // equals // (b) xor (c) xor (b and c) - return Ok(Boolean::and( - cs, - &b.not(), - &c.not() - )?.not()); - }, - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_)) - => {} + return Ok(Boolean::and(cs, &b.not(), &c.not())?.not()); + } + (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) + | (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) + | (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) + | (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) + | (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) + | (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) + | (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) + | (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_)) => {} } - let maj = cs.alloc(|| "maj", || { - maj_value.get().map(|v| { - if *v { - E::Fr::one() - } else { - E::Fr::zero() - } - }) - })?; + let maj = cs.alloc( + || "maj", + || { + maj_value + .get() + .map(|v| if *v { E::Fr::one() } else { E::Fr::zero() }) + }, + )?; // ¬(¬a ∧ ¬b) ∧ ¬(¬a ∧ ¬c) ∧ ¬(¬b ∧ ¬c) // (1 - ((1 - a) * (1 - b))) * (1 - ((1 - a) * (1 - c))) * (1 - ((1 - b) * (1 - c))) @@ -770,26 +704,24 @@ impl Boolean { // (b) * (c) = (bc) // (2bc - b - c) * (a) = bc - maj - let bc = Self::and( - cs.namespace(|| "b and c"), - b, - c - )?; + let bc = Self::and(cs.namespace(|| "b and c"), b, c)?; cs.enforce( || "maj computation", - |_| bc.lc(CS::one(), E::Fr::one()) - + &bc.lc(CS::one(), E::Fr::one()) - - &b.lc(CS::one(), E::Fr::one()) - - &c.lc(CS::one(), E::Fr::one()), + |_| { + bc.lc(CS::one(), E::Fr::one()) + &bc.lc(CS::one(), E::Fr::one()) + - &b.lc(CS::one(), E::Fr::one()) + - &c.lc(CS::one(), E::Fr::one()) + }, |_| a.lc(CS::one(), E::Fr::one()), - |_| bc.lc(CS::one(), E::Fr::one()) - maj + |_| bc.lc(CS::one(), E::Fr::one()) - maj, ); Ok(AllocatedBit { value: maj_value, - variable: maj - }.into()) + variable: maj, + } + .into()) } } @@ -801,16 +733,11 @@ impl From for Boolean { #[cfg(test)] mod test { - use crate::{ConstraintSystem}; + use super::{field_into_allocated_bits_le, u64_into_boolean_vec_le, AllocatedBit, Boolean}; + use crate::gadgets::test::*; + use crate::ConstraintSystem; use ff::{Field, PrimeField}; use pairing::bls12_381::{Bls12, Fr}; - use crate::gadgets::test::*; - use super::{ - AllocatedBit, - Boolean, - field_into_allocated_bits_le, - u64_into_boolean_vec_le - }; #[test] fn test_allocated_bit() { @@ -839,10 +766,24 @@ mod test { assert!(cs.is_satisfied()); assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("xor result") == if *a_val ^ *b_val { Field::one() } else { Field::zero() }); + assert!( + cs.get("xor result") + == if *a_val ^ *b_val { + Field::one() + } else { + Field::zero() + } + ); // Invert the result and check if the constraint system is still satisfied - cs.set("xor result", if *a_val ^ *b_val { Field::zero() } else { Field::one() }); + cs.set( + "xor result", + if *a_val ^ *b_val { + Field::zero() + } else { + Field::one() + }, + ); assert!(!cs.is_satisfied()); } } @@ -861,10 +802,24 @@ mod test { assert!(cs.is_satisfied()); assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("and result") == if *a_val & *b_val { Field::one() } else { Field::zero() }); + assert!( + cs.get("and result") + == if *a_val & *b_val { + Field::one() + } else { + Field::zero() + } + ); // Invert the result and check if the constraint system is still satisfied - cs.set("and result", if *a_val & *b_val { Field::zero() } else { Field::one() }); + cs.set( + "and result", + if *a_val & *b_val { + Field::zero() + } else { + Field::one() + }, + ); assert!(!cs.is_satisfied()); } } @@ -883,10 +838,24 @@ mod test { assert!(cs.is_satisfied()); assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("and not result") == if *a_val & !*b_val { Field::one() } else { Field::zero() }); + assert!( + cs.get("and not result") + == if *a_val & !*b_val { + Field::one() + } else { + Field::zero() + } + ); // Invert the result and check if the constraint system is still satisfied - cs.set("and not result", if *a_val & !*b_val { Field::zero() } else { Field::one() }); + cs.set( + "and not result", + if *a_val & !*b_val { + Field::zero() + } else { + Field::one() + }, + ); assert!(!cs.is_satisfied()); } } @@ -905,10 +874,24 @@ mod test { assert!(cs.is_satisfied()); assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("nor result") == if !*a_val & !*b_val { Field::one() } else { Field::zero() }); + assert!( + cs.get("nor result") + == if !*a_val & !*b_val { + Field::one() + } else { + Field::zero() + } + ); // Invert the result and check if the constraint system is still satisfied - cs.set("nor result", if !*a_val & !*b_val { Field::zero() } else { Field::one() }); + cs.set( + "nor result", + if !*a_val & !*b_val { + Field::zero() + } else { + Field::one() + }, + ); assert!(!cs.is_satisfied()); } } @@ -923,8 +906,12 @@ mod test { { let mut cs = TestConstraintSystem::::new(); - let mut a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap()); - let mut b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap()); + let mut a = Boolean::from( + AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap(), + ); + let mut b = Boolean::from( + AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap(), + ); if a_neg { a = a.not(); @@ -935,16 +922,15 @@ mod test { Boolean::enforce_equal(&mut cs, &a, &b).unwrap(); - assert_eq!( - cs.is_satisfied(), - (a_bool ^ a_neg) == (b_bool ^ b_neg) - ); + assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg)); } { let mut cs = TestConstraintSystem::::new(); let mut a = Boolean::Constant(a_bool); - let mut b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap()); + let mut b = Boolean::from( + AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap(), + ); if a_neg { a = a.not(); @@ -955,15 +941,14 @@ mod test { Boolean::enforce_equal(&mut cs, &a, &b).unwrap(); - assert_eq!( - cs.is_satisfied(), - (a_bool ^ a_neg) == (b_bool ^ b_neg) - ); + assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg)); } { let mut cs = TestConstraintSystem::::new(); - let mut a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap()); + let mut a = Boolean::from( + AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap(), + ); let mut b = Boolean::Constant(b_bool); if a_neg { @@ -975,10 +960,7 @@ mod test { Boolean::enforce_equal(&mut cs, &a, &b).unwrap(); - assert_eq!( - cs.is_satisfied(), - (a_bool ^ a_neg) == (b_bool ^ b_neg) - ); + assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg)); } { let mut cs = TestConstraintSystem::::new(); @@ -1015,43 +997,43 @@ mod test { let mut b = Boolean::from(AllocatedBit::alloc(&mut cs, Some(true)).unwrap()); match b { - Boolean::Is(_) => {}, - _ => panic!("unexpected value") + Boolean::Is(_) => {} + _ => panic!("unexpected value"), } b = b.not(); match b { - Boolean::Not(_) => {}, - _ => panic!("unexpected value") + Boolean::Not(_) => {} + _ => panic!("unexpected value"), } b = b.not(); match b { - Boolean::Is(_) => {}, - _ => panic!("unexpected value") + Boolean::Is(_) => {} + _ => panic!("unexpected value"), } b = Boolean::constant(true); match b { - Boolean::Constant(true) => {}, - _ => panic!("unexpected value") + Boolean::Constant(true) => {} + _ => panic!("unexpected value"), } b = b.not(); match b { - Boolean::Constant(false) => {}, - _ => panic!("unexpected value") + Boolean::Constant(false) => {} + _ => panic!("unexpected value"), } b = b.not(); match b { - Boolean::Constant(true) => {}, - _ => panic!("unexpected value") + Boolean::Constant(true) => {} + _ => panic!("unexpected value"), } } @@ -1062,7 +1044,7 @@ mod test { AllocatedTrue, AllocatedFalse, NegatedAllocatedTrue, - NegatedAllocatedFalse + NegatedAllocatedFalse, } impl OperandType { @@ -1073,7 +1055,7 @@ mod test { OperandType::AllocatedTrue => false, OperandType::AllocatedFalse => false, OperandType::NegatedAllocatedTrue => false, - OperandType::NegatedAllocatedFalse => false + OperandType::NegatedAllocatedFalse => false, } } @@ -1084,12 +1066,11 @@ mod test { OperandType::AllocatedTrue => true, OperandType::AllocatedFalse => false, OperandType::NegatedAllocatedTrue => false, - OperandType::NegatedAllocatedFalse => true + OperandType::NegatedAllocatedFalse => true, } } } - #[test] fn test_boolean_xor() { let variants = [ @@ -1098,7 +1079,7 @@ mod test { OperandType::AllocatedTrue, OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse + OperandType::NegatedAllocatedFalse, ]; for first_operand in variants.iter().cloned() { @@ -1115,10 +1096,18 @@ mod test { match operand { OperandType::True => Boolean::constant(true), OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), + OperandType::AllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + } + OperandType::AllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + } + OperandType::NegatedAllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not() + } + OperandType::NegatedAllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not() + } } }; @@ -1131,97 +1120,161 @@ mod test { assert!(cs.is_satisfied()); match (first_operand, second_operand, c) { - (OperandType::True, OperandType::True, Boolean::Constant(false)) => {}, - (OperandType::True, OperandType::False, Boolean::Constant(true)) => {}, - (OperandType::True, OperandType::AllocatedTrue, Boolean::Not(_)) => {}, - (OperandType::True, OperandType::AllocatedFalse, Boolean::Not(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Is(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Is(_)) => {}, + (OperandType::True, OperandType::True, Boolean::Constant(false)) => {} + (OperandType::True, OperandType::False, Boolean::Constant(true)) => {} + (OperandType::True, OperandType::AllocatedTrue, Boolean::Not(_)) => {} + (OperandType::True, OperandType::AllocatedFalse, Boolean::Not(_)) => {} + (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Is(_)) => {} + (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Is(_)) => {} - (OperandType::False, OperandType::True, Boolean::Constant(true)) => {}, - (OperandType::False, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::AllocatedTrue, Boolean::Is(_)) => {}, - (OperandType::False, OperandType::AllocatedFalse, Boolean::Is(_)) => {}, - (OperandType::False, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {}, - (OperandType::False, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {}, + (OperandType::False, OperandType::True, Boolean::Constant(true)) => {} + (OperandType::False, OperandType::False, Boolean::Constant(false)) => {} + (OperandType::False, OperandType::AllocatedTrue, Boolean::Is(_)) => {} + (OperandType::False, OperandType::AllocatedFalse, Boolean::Is(_)) => {} + (OperandType::False, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {} + (OperandType::False, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {} - (OperandType::AllocatedTrue, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::AllocatedTrue, OperandType::False, Boolean::Is(_)) => {}, - (OperandType::AllocatedTrue, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::AllocatedTrue, OperandType::True, Boolean::Not(_)) => {} + (OperandType::AllocatedTrue, OperandType::False, Boolean::Is(_)) => {} + ( + OperandType::AllocatedTrue, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Not(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::NegatedAllocatedTrue, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Not(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::NegatedAllocatedFalse, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, + } - (OperandType::AllocatedFalse, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::AllocatedFalse, OperandType::False, Boolean::Is(_)) => {}, - (OperandType::AllocatedFalse, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::AllocatedFalse, OperandType::True, Boolean::Not(_)) => {} + (OperandType::AllocatedFalse, OperandType::False, Boolean::Is(_)) => {} + ( + OperandType::AllocatedFalse, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedFalse, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Not(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::NegatedAllocatedTrue, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Not(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::NegatedAllocatedFalse, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, + } - (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::False, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedTrue, Boolean::Not(ref v)) => { + (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Is(_)) => {} + (OperandType::NegatedAllocatedTrue, OperandType::False, Boolean::Not(_)) => {} + ( + OperandType::NegatedAllocatedTrue, + OperandType::AllocatedTrue, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedFalse, Boolean::Not(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::AllocatedFalse, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, + } - (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::False, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedTrue, Boolean::Not(ref v)) => { + (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Is(_)) => {} + (OperandType::NegatedAllocatedFalse, OperandType::False, Boolean::Not(_)) => {} + ( + OperandType::NegatedAllocatedFalse, + OperandType::AllocatedTrue, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedFalse, Boolean::Not(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::AllocatedFalse, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, + } - _ => panic!("this should never be encountered") + _ => panic!("this should never be encountered"), } } } @@ -1235,7 +1288,7 @@ mod test { OperandType::AllocatedTrue, OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse + OperandType::NegatedAllocatedFalse, ]; for first_operand in variants.iter().cloned() { @@ -1252,10 +1305,18 @@ mod test { match operand { OperandType::True => Boolean::constant(true), OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), + OperandType::AllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + } + OperandType::AllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + } + OperandType::NegatedAllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not() + } + OperandType::NegatedAllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not() + } } }; @@ -1268,98 +1329,183 @@ mod test { assert!(cs.is_satisfied()); match (first_operand, second_operand, c) { - (OperandType::True, OperandType::True, Boolean::Constant(true)) => {}, - (OperandType::True, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::True, OperandType::AllocatedTrue, Boolean::Is(_)) => {}, - (OperandType::True, OperandType::AllocatedFalse, Boolean::Is(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {}, + (OperandType::True, OperandType::True, Boolean::Constant(true)) => {} + (OperandType::True, OperandType::False, Boolean::Constant(false)) => {} + (OperandType::True, OperandType::AllocatedTrue, Boolean::Is(_)) => {} + (OperandType::True, OperandType::AllocatedFalse, Boolean::Is(_)) => {} + (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {} + (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {} - (OperandType::False, OperandType::True, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::AllocatedTrue, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::AllocatedFalse, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::NegatedAllocatedTrue, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::NegatedAllocatedFalse, Boolean::Constant(false)) => {}, + (OperandType::False, OperandType::True, Boolean::Constant(false)) => {} + (OperandType::False, OperandType::False, Boolean::Constant(false)) => {} + (OperandType::False, OperandType::AllocatedTrue, Boolean::Constant(false)) => {} + (OperandType::False, OperandType::AllocatedFalse, Boolean::Constant(false)) => { + } + ( + OperandType::False, + OperandType::NegatedAllocatedTrue, + Boolean::Constant(false), + ) => {} + ( + OperandType::False, + OperandType::NegatedAllocatedFalse, + Boolean::Constant(false), + ) => {} - (OperandType::AllocatedTrue, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::AllocatedTrue, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::AllocatedTrue, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::AllocatedTrue, OperandType::True, Boolean::Is(_)) => {} + (OperandType::AllocatedTrue, OperandType::False, Boolean::Constant(false)) => {} + ( + OperandType::AllocatedTrue, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedTrue, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::one()); assert_eq!(v.value, Some(true)); - }, + } - (OperandType::AllocatedFalse, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::AllocatedFalse, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::AllocatedFalse, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::AllocatedFalse, OperandType::True, Boolean::Is(_)) => {} + (OperandType::AllocatedFalse, OperandType::False, Boolean::Constant(false)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, + } - (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Not(_)) => {} + ( + OperandType::NegatedAllocatedTrue, + OperandType::False, + Boolean::Constant(false), + ) => {} + ( + OperandType::NegatedAllocatedTrue, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("nor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("nor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, + } - (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Not(_)) => {} + ( + OperandType::NegatedAllocatedFalse, + OperandType::False, + Boolean::Constant(false), + ) => {} + ( + OperandType::NegatedAllocatedFalse, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("nor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("nor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, + } _ => { - panic!("unexpected behavior at {:?} AND {:?}", first_operand, second_operand); + panic!( + "unexpected behavior at {:?} AND {:?}", + first_operand, second_operand + ); } } } @@ -1391,7 +1537,10 @@ mod test { fn test_field_into_allocated_bits_le() { let mut cs = TestConstraintSystem::::new(); - let r = Fr::from_str("9147677615426976802526883532204139322118074541891858454835346926874644257775").unwrap(); + let r = Fr::from_str( + "9147677615426976802526883532204139322118074541891858454835346926874644257775", + ) + .unwrap(); let bits = field_into_allocated_bits_le(&mut cs, Some(r)).unwrap(); @@ -1417,7 +1566,7 @@ mod test { OperandType::AllocatedTrue, OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse + OperandType::NegatedAllocatedFalse, ]; for first_operand in variants.iter().cloned() { @@ -1430,8 +1579,8 @@ mod test { let c; // ch = (a and b) xor ((not a) and c) - let expected = (first_operand.val() & second_operand.val()) ^ - ((!first_operand.val()) & third_operand.val()); + let expected = (first_operand.val() & second_operand.val()) + ^ ((!first_operand.val()) & third_operand.val()); { let mut dyn_construct = |operand, name| { @@ -1440,10 +1589,20 @@ mod test { match operand { OperandType::True => Boolean::constant(true), OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), + OperandType::AllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + } + OperandType::AllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + } + OperandType::NegatedAllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + .not() + } + OperandType::NegatedAllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + .not() + } } }; @@ -1458,19 +1617,17 @@ mod test { assert_eq!(maj.get_value().unwrap(), expected); - if first_operand.is_constant() || - second_operand.is_constant() || - third_operand.is_constant() + if first_operand.is_constant() + || second_operand.is_constant() + || third_operand.is_constant() { - if first_operand.is_constant() && - second_operand.is_constant() && - third_operand.is_constant() + if first_operand.is_constant() + && second_operand.is_constant() + && third_operand.is_constant() { assert_eq!(cs.num_constraints(), 0); } - } - else - { + } else { assert_eq!(cs.get("ch"), { if expected { Fr::one() @@ -1500,7 +1657,7 @@ mod test { OperandType::AllocatedTrue, OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse + OperandType::NegatedAllocatedFalse, ]; for first_operand in variants.iter().cloned() { @@ -1513,9 +1670,9 @@ mod test { let c; // maj = (a and b) xor (a and c) xor (b and c) - let expected = (first_operand.val() & second_operand.val()) ^ - (first_operand.val() & third_operand.val()) ^ - (second_operand.val() & third_operand.val()); + let expected = (first_operand.val() & second_operand.val()) + ^ (first_operand.val() & third_operand.val()) + ^ (second_operand.val() & third_operand.val()); { let mut dyn_construct = |operand, name| { @@ -1524,10 +1681,20 @@ mod test { match operand { OperandType::True => Boolean::constant(true), OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), + OperandType::AllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + } + OperandType::AllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + } + OperandType::NegatedAllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + .not() + } + OperandType::NegatedAllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + .not() + } } }; @@ -1542,19 +1709,17 @@ mod test { assert_eq!(maj.get_value().unwrap(), expected); - if first_operand.is_constant() || - second_operand.is_constant() || - third_operand.is_constant() + if first_operand.is_constant() + || second_operand.is_constant() + || third_operand.is_constant() { - if first_operand.is_constant() && - second_operand.is_constant() && - third_operand.is_constant() + if first_operand.is_constant() + && second_operand.is_constant() + && third_operand.is_constant() { assert_eq!(cs.num_constraints(), 0); } - } - else - { + } else { assert_eq!(cs.get("maj"), { if expected { Fr::one() diff --git a/bellman/src/gadgets/lookup.rs b/bellman/src/gadgets/lookup.rs index 86ab10f..bbb1da6 100644 --- a/bellman/src/gadgets/lookup.rs +++ b/bellman/src/gadgets/lookup.rs @@ -1,23 +1,15 @@ use ff::Field; use pairing::Engine; -use super::*; -use super::num::{ - AllocatedNum, - Num -}; use super::boolean::Boolean; -use crate::{ - ConstraintSystem -}; +use super::num::{AllocatedNum, Num}; +use super::*; +use crate::ConstraintSystem; // Synthesize the constants for each base pattern. -fn synth<'a, E: Engine, I>( - window_size: usize, - constants: I, - assignment: &mut [E::Fr] -) - where I: IntoIterator +fn synth<'a, E: Engine, I>(window_size: usize, constants: I, assignment: &mut [E::Fr]) +where + I: IntoIterator, { assert_eq!(assignment.len(), 1 << window_size); @@ -39,16 +31,20 @@ fn synth<'a, E: Engine, I>( pub fn lookup3_xy( mut cs: CS, bits: &[Boolean], - coords: &[(E::Fr, E::Fr)] + coords: &[(E::Fr, E::Fr)], ) -> Result<(AllocatedNum, AllocatedNum), SynthesisError> - where CS: ConstraintSystem +where + CS: ConstraintSystem, { assert_eq!(bits.len(), 3); assert_eq!(coords.len(), 8); // Calculate the index into `coords` - let i = - match (bits[0].get_value(), bits[1].get_value(), bits[2].get_value()) { + let i = match ( + bits[0].get_value(), + bits[1].get_value(), + bits[2].get_value(), + ) { (Some(a_value), Some(b_value), Some(c_value)) => { let mut tmp = 0; if a_value { @@ -61,25 +57,15 @@ pub fn lookup3_xy( tmp += 4; } Some(tmp) - }, - _ => None + } + _ => None, }; // Allocate the x-coordinate resulting from the lookup - let res_x = AllocatedNum::alloc( - cs.namespace(|| "x"), - || { - Ok(coords[*i.get()?].0) - } - )?; + let res_x = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(coords[*i.get()?].0))?; // Allocate the y-coordinate resulting from the lookup - let res_y = AllocatedNum::alloc( - cs.namespace(|| "y"), - || { - Ok(coords[*i.get()?].1) - } - )?; + let res_y = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(coords[*i.get()?].1))?; // Compute the coefficients for the lookup constraints let mut x_coeffs = [E::Fr::zero(); 8]; @@ -93,30 +79,38 @@ pub fn lookup3_xy( cs.enforce( || "x-coordinate lookup", - |lc| lc + (x_coeffs[0b001], one) + |lc| { + lc + (x_coeffs[0b001], one) + &bits[1].lc::(one, x_coeffs[0b011]) + &bits[2].lc::(one, x_coeffs[0b101]) - + &precomp.lc::(one, x_coeffs[0b111]), + + &precomp.lc::(one, x_coeffs[0b111]) + }, |lc| lc + &bits[0].lc::(one, E::Fr::one()), - |lc| lc + res_x.get_variable() + |lc| { + lc + res_x.get_variable() - (x_coeffs[0b000], one) - &bits[1].lc::(one, x_coeffs[0b010]) - &bits[2].lc::(one, x_coeffs[0b100]) - - &precomp.lc::(one, x_coeffs[0b110]), + - &precomp.lc::(one, x_coeffs[0b110]) + }, ); cs.enforce( || "y-coordinate lookup", - |lc| lc + (y_coeffs[0b001], one) + |lc| { + lc + (y_coeffs[0b001], one) + &bits[1].lc::(one, y_coeffs[0b011]) + &bits[2].lc::(one, y_coeffs[0b101]) - + &precomp.lc::(one, y_coeffs[0b111]), + + &precomp.lc::(one, y_coeffs[0b111]) + }, |lc| lc + &bits[0].lc::(one, E::Fr::one()), - |lc| lc + res_y.get_variable() + |lc| { + lc + res_y.get_variable() - (y_coeffs[0b000], one) - &bits[1].lc::(one, y_coeffs[0b010]) - &bits[2].lc::(one, y_coeffs[0b100]) - - &precomp.lc::(one, y_coeffs[0b110]), + - &precomp.lc::(one, y_coeffs[0b110]) + }, ); Ok((res_x, res_y)) @@ -127,16 +121,16 @@ pub fn lookup3_xy( pub fn lookup3_xy_with_conditional_negation( mut cs: CS, bits: &[Boolean], - coords: &[(E::Fr, E::Fr)] + coords: &[(E::Fr, E::Fr)], ) -> Result<(Num, Num), SynthesisError> - where CS: ConstraintSystem +where + CS: ConstraintSystem, { assert_eq!(bits.len(), 3); assert_eq!(coords.len(), 4); // Calculate the index into `coords` - let i = - match (bits[0].get_value(), bits[1].get_value()) { + let i = match (bits[0].get_value(), bits[1].get_value()) { (Some(a_value), Some(b_value)) => { let mut tmp = 0; if a_value { @@ -146,22 +140,19 @@ pub fn lookup3_xy_with_conditional_negation( tmp += 2; } Some(tmp) - }, - _ => None + } + _ => None, }; // Allocate the y-coordinate resulting from the lookup // and conditional negation - let y = AllocatedNum::alloc( - cs.namespace(|| "y"), - || { - let mut tmp = coords[*i.get()?].1; - if *bits[2].get_value().get()? { - tmp.negate(); - } - Ok(tmp) + let y = AllocatedNum::alloc(cs.namespace(|| "y"), || { + let mut tmp = coords[*i.get()?].1; + if *bits[2].get_value().get()? { + tmp.negate(); } - )?; + Ok(tmp) + })?; let one = CS::one(); @@ -174,21 +165,21 @@ pub fn lookup3_xy_with_conditional_negation( let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[0], &bits[1])?; let x = Num::zero() - .add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00]) - .add_bool_with_coeff(one, &bits[0], x_coeffs[0b01]) - .add_bool_with_coeff(one, &bits[1], x_coeffs[0b10]) - .add_bool_with_coeff(one, &precomp, x_coeffs[0b11]); + .add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00]) + .add_bool_with_coeff(one, &bits[0], x_coeffs[0b01]) + .add_bool_with_coeff(one, &bits[1], x_coeffs[0b10]) + .add_bool_with_coeff(one, &precomp, x_coeffs[0b11]); - let y_lc = precomp.lc::(one, y_coeffs[0b11]) + - &bits[1].lc::(one, y_coeffs[0b10]) + - &bits[0].lc::(one, y_coeffs[0b01]) + - (y_coeffs[0b00], one); + let y_lc = precomp.lc::(one, y_coeffs[0b11]) + + &bits[1].lc::(one, y_coeffs[0b10]) + + &bits[0].lc::(one, y_coeffs[0b01]) + + (y_coeffs[0b00], one); cs.enforce( || "y-coordinate lookup", |lc| lc + &y_lc + &y_lc, |lc| lc + &bits[2].lc::(one, E::Fr::one()), - |lc| lc + &y_lc - y.get_variable() + |lc| lc + &y_lc - y.get_variable(), ); Ok((x, y.into())) @@ -197,8 +188,8 @@ pub fn lookup3_xy_with_conditional_negation( #[cfg(test)] mod test { use super::*; + use crate::gadgets::boolean::{AllocatedBit, Boolean}; use crate::gadgets::test::*; - use crate::gadgets::boolean::{Boolean, AllocatedBit}; use pairing::bls12_381::{Bls12, Fr}; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; @@ -206,40 +197,42 @@ mod test { #[test] fn test_lookup3_xy() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..100 { let mut cs = TestConstraintSystem::::new(); let a_val = rng.next_u32() % 2 != 0; - let a = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap() - ); + let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()); let b_val = rng.next_u32() % 2 != 0; - let b = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap() - ); + let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap()); let c_val = rng.next_u32() % 2 != 0; - let c = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap() - ); + let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap()); let bits = vec![a, b, c]; - let points: Vec<(Fr, Fr)> = (0..8).map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))).collect(); + let points: Vec<(Fr, Fr)> = (0..8) + .map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))) + .collect(); let res = lookup3_xy(&mut cs, &bits, &points).unwrap(); assert!(cs.is_satisfied()); let mut index = 0; - if a_val { index += 1 } - if b_val { index += 2 } - if c_val { index += 4 } + if a_val { + index += 1 + } + if b_val { + index += 2 + } + if c_val { + index += 4 + } assert_eq!(res.0.get_value().unwrap(), points[index].0); assert_eq!(res.1.get_value().unwrap(), points[index].1); @@ -249,43 +242,45 @@ mod test { #[test] fn test_lookup3_xy_with_conditional_negation() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..100 { let mut cs = TestConstraintSystem::::new(); let a_val = rng.next_u32() % 2 != 0; - let a = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap() - ); + let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()); let b_val = rng.next_u32() % 2 != 0; - let b = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap() - ); + let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap()); let c_val = rng.next_u32() % 2 != 0; - let c = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap() - ); + let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap()); let bits = vec![a, b, c]; - let points: Vec<(Fr, Fr)> = (0..4).map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))).collect(); + let points: Vec<(Fr, Fr)> = (0..4) + .map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))) + .collect(); let res = lookup3_xy_with_conditional_negation(&mut cs, &bits, &points).unwrap(); assert!(cs.is_satisfied()); let mut index = 0; - if a_val { index += 1 } - if b_val { index += 2 } + if a_val { + index += 1 + } + if b_val { + index += 2 + } assert_eq!(res.0.get_value().unwrap(), points[index].0); let mut tmp = points[index].1; - if c_val { tmp.negate() } + if c_val { + tmp.negate() + } assert_eq!(res.1.get_value().unwrap(), tmp); } } @@ -293,14 +288,16 @@ mod test { #[test] fn test_synth() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); let window_size = 4; let mut assignment = vec![Fr::zero(); 1 << window_size]; - let constants: Vec<_> = (0..(1 << window_size)).map(|_| Fr::random(&mut rng)).collect(); + let constants: Vec<_> = (0..(1 << window_size)) + .map(|_| Fr::random(&mut rng)) + .collect(); synth::(window_size, &constants, &mut assignment); diff --git a/bellman/src/gadgets/multieq.rs b/bellman/src/gadgets/multieq.rs index b1dfd7c..510802d 100644 --- a/bellman/src/gadgets/multieq.rs +++ b/bellman/src/gadgets/multieq.rs @@ -1,14 +1,9 @@ use ff::{Field, PrimeField}; use pairing::Engine; -use crate::{ - SynthesisError, - ConstraintSystem, - LinearCombination, - Variable -}; +use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; -pub struct MultiEq>{ +pub struct MultiEq> { cs: CS, ops: usize, bits_used: usize, @@ -23,12 +18,11 @@ impl> MultiEq { ops: 0, bits_used: 0, lhs: LinearCombination::zero(), - rhs: LinearCombination::zero() + rhs: LinearCombination::zero(), } } - fn accumulate(&mut self) - { + fn accumulate(&mut self) { let ops = self.ops; let lhs = self.lhs.clone(); let rhs = self.rhs.clone(); @@ -36,7 +30,7 @@ impl> MultiEq { || format!("multieq {}", ops), |_| lhs, |lc| lc + CS::one(), - |_| rhs + |_| rhs, ); self.lhs = LinearCombination::zero(); self.rhs = LinearCombination::zero(); @@ -48,9 +42,8 @@ impl> MultiEq { &mut self, num_bits: usize, lhs: &LinearCombination, - rhs: &LinearCombination - ) - { + rhs: &LinearCombination, + ) { // Check if we will exceed the capacity if (E::Fr::CAPACITY as usize) <= (self.bits_used + num_bits) { self.accumulate(); @@ -68,67 +61,60 @@ impl> MultiEq { impl> Drop for MultiEq { fn drop(&mut self) { if self.bits_used > 0 { - self.accumulate(); + self.accumulate(); } } } -impl> ConstraintSystem for MultiEq -{ +impl> ConstraintSystem for MultiEq { type Root = Self; fn one() -> Variable { CS::one() } - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.cs.alloc(annotation, f) } - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.cs.alloc_input(annotation, f) } - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, annotation: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { self.cs.enforce(annotation, a, b, c) } fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { self.cs.get_root().push_namespace(name_fn) } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { self.cs.get_root().pop_namespace() } - fn get_root(&mut self) -> &mut Self::Root - { + fn get_root(&mut self) -> &mut Self::Root { self } } diff --git a/bellman/src/gadgets/multipack.rs b/bellman/src/gadgets/multipack.rs index b9b5877..34df7cd 100644 --- a/bellman/src/gadgets/multipack.rs +++ b/bellman/src/gadgets/multipack.rs @@ -1,20 +1,18 @@ -use ff::{Field, PrimeField}; -use pairing::Engine; -use crate::{ConstraintSystem, SynthesisError}; -use super::boolean::{Boolean}; +use super::boolean::Boolean; use super::num::Num; use super::Assignment; +use crate::{ConstraintSystem, SynthesisError}; +use ff::{Field, PrimeField}; +use pairing::Engine; /// Takes a sequence of booleans and exposes them as compact /// public inputs -pub fn pack_into_inputs( - mut cs: CS, - bits: &[Boolean] -) -> Result<(), SynthesisError> - where E: Engine, CS: ConstraintSystem +pub fn pack_into_inputs(mut cs: CS, bits: &[Boolean]) -> Result<(), SynthesisError> +where + E: Engine, + CS: ConstraintSystem, { - for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() - { + for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() { let mut num = Num::::zero(); let mut coeff = E::Fr::one(); for bit in bits { @@ -23,44 +21,38 @@ pub fn pack_into_inputs( coeff.double(); } - let input = cs.alloc_input(|| format!("input {}", i), || { - Ok(*num.get_value().get()?) - })?; + let input = cs.alloc_input(|| format!("input {}", i), || Ok(*num.get_value().get()?))?; // num * 1 = input cs.enforce( || format!("packing constraint {}", i), |_| num.lc(E::Fr::one()), |lc| lc + CS::one(), - |lc| lc + input + |lc| lc + input, ); } Ok(()) } -pub fn bytes_to_bits(bytes: &[u8]) -> Vec -{ - bytes.iter() - .flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1)) - .collect() +pub fn bytes_to_bits(bytes: &[u8]) -> Vec { + bytes + .iter() + .flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1)) + .collect() } -pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec -{ - bytes.iter() - .flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1)) - .collect() +pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec { + bytes + .iter() + .flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1)) + .collect() } -pub fn compute_multipacking( - bits: &[bool] -) -> Vec -{ +pub fn compute_multipacking(bits: &[bool]) -> Vec { let mut result = vec![]; - for bits in bits.chunks(E::Fr::CAPACITY as usize) - { + for bits in bits.chunks(E::Fr::CAPACITY as usize) { let mut cur = E::Fr::zero(); let mut coeff = E::Fr::one(); @@ -80,13 +72,13 @@ pub fn compute_multipacking( #[test] fn test_multipacking() { - use crate::{ConstraintSystem}; - use pairing::bls12_381::{Bls12}; + use crate::ConstraintSystem; + use pairing::bls12_381::Bls12; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; - use crate::gadgets::test::*; use super::boolean::{AllocatedBit, Boolean}; + use crate::gadgets::test::*; let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, @@ -98,16 +90,15 @@ fn test_multipacking() { let bits: Vec = (0..num_bits).map(|_| rng.next_u32() % 2 != 0).collect(); - let circuit_bits = bits.iter().enumerate() - .map(|(i, &b)| { - Boolean::from( - AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - Some(b) - ).unwrap() - ) - }) - .collect::>(); + let circuit_bits = bits + .iter() + .enumerate() + .map(|(i, &b)| { + Boolean::from( + AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), Some(b)).unwrap(), + ) + }) + .collect::>(); let expected_inputs = compute_multipacking::(&bits); diff --git a/bellman/src/gadgets/num.rs b/bellman/src/gadgets/num.rs index 077301f..84843c1 100644 --- a/bellman/src/gadgets/num.rs +++ b/bellman/src/gadgets/num.rs @@ -1,78 +1,61 @@ use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr}; use pairing::Engine; -use crate::{ - SynthesisError, - ConstraintSystem, - LinearCombination, - Variable -}; +use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; -use super::{ - Assignment -}; +use super::Assignment; -use super::boolean::{ - self, - Boolean, - AllocatedBit -}; +use super::boolean::{self, AllocatedBit, Boolean}; pub struct AllocatedNum { value: Option, - variable: Variable + variable: Variable, } impl Clone for AllocatedNum { fn clone(&self) -> Self { AllocatedNum { value: self.value, - variable: self.variable + variable: self.variable, } } } impl AllocatedNum { - pub fn alloc( - mut cs: CS, - value: F, - ) -> Result - where CS: ConstraintSystem, - F: FnOnce() -> Result + pub fn alloc(mut cs: CS, value: F) -> Result + where + CS: ConstraintSystem, + F: FnOnce() -> Result, { let mut new_value = None; - let var = cs.alloc(|| "num", || { - let tmp = value()?; + let var = cs.alloc( + || "num", + || { + let tmp = value()?; - new_value = Some(tmp); + new_value = Some(tmp); - Ok(tmp) - })?; + Ok(tmp) + }, + )?; Ok(AllocatedNum { value: new_value, - variable: var + variable: var, }) } - pub fn inputize( - &self, - mut cs: CS - ) -> Result<(), SynthesisError> - where CS: ConstraintSystem + pub fn inputize(&self, mut cs: CS) -> Result<(), SynthesisError> + where + CS: ConstraintSystem, { - let input = cs.alloc_input( - || "input variable", - || { - Ok(*self.value.get()?) - } - )?; + let input = cs.alloc_input(|| "input variable", || Ok(*self.value.get()?))?; cs.enforce( || "enforce input is correct", |lc| lc + input, |lc| lc + CS::one(), - |lc| lc + self.variable + |lc| lc + self.variable, ); Ok(()) @@ -83,18 +66,17 @@ impl AllocatedNum { /// order, requiring that the representation /// strictly exists "in the field" (i.e., a /// congruency is not allowed.) - pub fn into_bits_le_strict( - &self, - mut cs: CS - ) -> Result, SynthesisError> - where CS: ConstraintSystem + pub fn into_bits_le_strict(&self, mut cs: CS) -> Result, SynthesisError> + where + CS: ConstraintSystem, { pub fn kary_and( mut cs: CS, - v: &[AllocatedBit] + v: &[AllocatedBit], ) -> Result - where E: Engine, - CS: ConstraintSystem + where + E: Engine, + CS: ConstraintSystem, { assert!(v.len() > 0); @@ -109,7 +91,7 @@ impl AllocatedNum { cur = Some(AllocatedBit::and( cs.namespace(|| format!("and {}", i)), cur.as_ref().unwrap(), - v + v, )?); } } @@ -145,10 +127,7 @@ impl AllocatedNum { if b { // This is part of a run of ones. Let's just // allocate the boolean with the expected value. - let a_bit = AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - a_bit - )?; + let a_bit = AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), a_bit)?; // ... and add it to the current run of ones. current_run.push(a_bit.clone()); result.push(a_bit); @@ -162,7 +141,7 @@ impl AllocatedNum { } last_run = Some(kary_and( cs.namespace(|| format!("run ending at {}", i)), - ¤t_run + ¤t_run, )?); current_run.truncate(0); } @@ -175,7 +154,7 @@ impl AllocatedNum { let a_bit = AllocatedBit::alloc_conditionally( cs.namespace(|| format!("bit {}", i)), a_bit, - &last_run.as_ref().expect("char always starts with a one") + &last_run.as_ref().expect("char always starts with a one"), )?; result.push(a_bit); } @@ -201,12 +180,7 @@ impl AllocatedNum { lc = lc - self.variable; - cs.enforce( - || "unpacking constraint", - |lc| lc, - |lc| lc, - |_| lc - ); + cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc); // Convert into booleans, and reverse for little-endian bit order Ok(result.into_iter().map(|b| Boolean::from(b)).rev().collect()) @@ -215,16 +189,11 @@ impl AllocatedNum { /// Convert the allocated number into its little-endian representation. /// Note that this does not strongly enforce that the commitment is /// "in the field." - pub fn into_bits_le( - &self, - mut cs: CS - ) -> Result, SynthesisError> - where CS: ConstraintSystem + pub fn into_bits_le(&self, mut cs: CS) -> Result, SynthesisError> + where + CS: ConstraintSystem, { - let bits = boolean::field_into_allocated_bits_le( - &mut cs, - self.value - )?; + let bits = boolean::field_into_allocated_bits_le(&mut cs, self.value)?; let mut lc = LinearCombination::zero(); let mut coeff = E::Fr::one(); @@ -237,94 +206,91 @@ impl AllocatedNum { lc = lc - self.variable; - cs.enforce( - || "unpacking constraint", - |lc| lc, - |lc| lc, - |_| lc - ); + cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc); Ok(bits.into_iter().map(|b| Boolean::from(b)).collect()) } - pub fn mul( - &self, - mut cs: CS, - other: &Self - ) -> Result - where CS: ConstraintSystem + pub fn mul(&self, mut cs: CS, other: &Self) -> Result + where + CS: ConstraintSystem, { let mut value = None; - let var = cs.alloc(|| "product num", || { - let mut tmp = *self.value.get()?; - tmp.mul_assign(other.value.get()?); + let var = cs.alloc( + || "product num", + || { + let mut tmp = *self.value.get()?; + tmp.mul_assign(other.value.get()?); - value = Some(tmp); + value = Some(tmp); - Ok(tmp) - })?; + Ok(tmp) + }, + )?; // Constrain: a * b = ab cs.enforce( || "multiplication constraint", |lc| lc + self.variable, |lc| lc + other.variable, - |lc| lc + var + |lc| lc + var, ); Ok(AllocatedNum { value: value, - variable: var + variable: var, }) } - pub fn square( - &self, - mut cs: CS - ) -> Result - where CS: ConstraintSystem + pub fn square(&self, mut cs: CS) -> Result + where + CS: ConstraintSystem, { let mut value = None; - let var = cs.alloc(|| "squared num", || { - let mut tmp = *self.value.get()?; - tmp.square(); + let var = cs.alloc( + || "squared num", + || { + let mut tmp = *self.value.get()?; + tmp.square(); - value = Some(tmp); + value = Some(tmp); - Ok(tmp) - })?; + Ok(tmp) + }, + )?; // Constrain: a * a = aa cs.enforce( || "squaring constraint", |lc| lc + self.variable, |lc| lc + self.variable, - |lc| lc + var + |lc| lc + var, ); Ok(AllocatedNum { value: value, - variable: var + variable: var, }) } - pub fn assert_nonzero( - &self, - mut cs: CS - ) -> Result<(), SynthesisError> - where CS: ConstraintSystem + pub fn assert_nonzero(&self, mut cs: CS) -> Result<(), SynthesisError> + where + CS: ConstraintSystem, { - let inv = cs.alloc(|| "ephemeral inverse", || { - let tmp = *self.value.get()?; - - if tmp.is_zero() { - Err(SynthesisError::DivisionByZero) - } else { - Ok(tmp.inverse().unwrap()) - } - })?; + let inv = cs.alloc( + || "ephemeral inverse", + || { + let tmp = *self.value.get()?; + + if tmp.is_zero() { + Err(SynthesisError::DivisionByZero) + } else { + Ok(tmp.inverse().unwrap()) + } + }, + )?; // Constrain a * inv = 1, which is only valid // iff a has a multiplicative inverse, untrue @@ -333,7 +299,7 @@ impl AllocatedNum { || "nonzero assertion constraint", |lc| lc + self.variable, |lc| lc + inv, - |lc| lc + CS::one() + |lc| lc + CS::one(), ); Ok(()) @@ -346,44 +312,39 @@ impl AllocatedNum { mut cs: CS, a: &Self, b: &Self, - condition: &Boolean + condition: &Boolean, ) -> Result<(Self, Self), SynthesisError> - where CS: ConstraintSystem + where + CS: ConstraintSystem, { - let c = Self::alloc( - cs.namespace(|| "conditional reversal result 1"), - || { - if *condition.get_value().get()? { - Ok(*b.value.get()?) - } else { - Ok(*a.value.get()?) - } + let c = Self::alloc(cs.namespace(|| "conditional reversal result 1"), || { + if *condition.get_value().get()? { + Ok(*b.value.get()?) + } else { + Ok(*a.value.get()?) } - )?; + })?; cs.enforce( || "first conditional reversal", |lc| lc + a.variable - b.variable, |_| condition.lc(CS::one(), E::Fr::one()), - |lc| lc + a.variable - c.variable + |lc| lc + a.variable - c.variable, ); - let d = Self::alloc( - cs.namespace(|| "conditional reversal result 2"), - || { - if *condition.get_value().get()? { - Ok(*a.value.get()?) - } else { - Ok(*b.value.get()?) - } + let d = Self::alloc(cs.namespace(|| "conditional reversal result 2"), || { + if *condition.get_value().get()? { + Ok(*a.value.get()?) + } else { + Ok(*b.value.get()?) } - )?; + })?; cs.enforce( || "second conditional reversal", |lc| lc + b.variable - a.variable, |_| condition.lc(CS::one(), E::Fr::one()), - |lc| lc + b.variable - d.variable + |lc| lc + b.variable - d.variable, ); Ok((c, d)) @@ -400,14 +361,14 @@ impl AllocatedNum { pub struct Num { value: Option, - lc: LinearCombination + lc: LinearCombination, } impl From> for Num { fn from(num: AllocatedNum) -> Num { Num { value: num.value, - lc: LinearCombination::::zero() + num.variable + lc: LinearCombination::::zero() + num.variable, } } } @@ -416,7 +377,7 @@ impl Num { pub fn zero() -> Self { Num { value: Some(E::Fr::zero()), - lc: LinearCombination::zero() + lc: LinearCombination::zero(), } } @@ -428,13 +389,7 @@ impl Num { LinearCombination::zero() + (coeff, &self.lc) } - pub fn add_bool_with_coeff( - self, - one: Variable, - bit: &Boolean, - coeff: E::Fr - ) -> Self - { + pub fn add_bool_with_coeff(self, one: Variable, bit: &Boolean, coeff: E::Fr) -> Self { let newval = match (self.value, bit.get_value()) { (Some(mut curval), Some(bval)) => { if bval { @@ -442,27 +397,27 @@ impl Num { } Some(curval) - }, - _ => None + } + _ => None, }; Num { value: newval, - lc: self.lc + &bit.lc(one, coeff) + lc: self.lc + &bit.lc(one, coeff), } } } #[cfg(test)] mod test { - use crate::{ConstraintSystem}; + use crate::ConstraintSystem; use ff::{BitIterator, Field, PrimeField}; use pairing::bls12_381::{Bls12, Fr}; use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; - use crate::gadgets::test::*; use super::{AllocatedNum, Boolean}; + use crate::gadgets::test::*; #[test] fn test_allocated_num() { @@ -491,8 +446,10 @@ mod test { fn test_num_multiplication() { let mut cs = TestConstraintSystem::::new(); - let n = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap(); - let n2 = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap(); + let n = + AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap(); + let n2 = + AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap(); let n3 = n.mul(&mut cs, &n2).unwrap(); assert!(cs.is_satisfied()); @@ -505,8 +462,8 @@ mod test { #[test] fn test_num_conditional_reversal() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); { let mut cs = TestConstraintSystem::::new(); @@ -573,14 +530,17 @@ mod test { cs.set("bit 254/boolean", Fr::one()); // this makes the conditional boolean constraint fail - assert_eq!(cs.which_is_unsatisfied().unwrap(), "bit 254/boolean constraint"); + assert_eq!( + cs.which_is_unsatisfied().unwrap(), + "bit 254/boolean constraint" + ); } #[test] fn test_into_bits() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for i in 0..200 { @@ -597,7 +557,10 @@ mod test { assert!(cs.is_satisfied()); - for (b, a) in BitIterator::new(r.into_repr()).skip(1).zip(bits.iter().rev()) { + for (b, a) in BitIterator::new(r.into_repr()) + .skip(1) + .zip(bits.iter().rev()) + { if let &Boolean::Is(ref a) = a { assert_eq!(b, a.get_value().unwrap()); } else { diff --git a/bellman/src/gadgets/sha256.rs b/bellman/src/gadgets/sha256.rs index 2e4669e..cb057f8 100644 --- a/bellman/src/gadgets/sha256.rs +++ b/bellman/src/gadgets/sha256.rs @@ -1,6 +1,6 @@ -use super::uint32::UInt32; -use super::multieq::MultiEq; use super::boolean::Boolean; +use super::multieq::MultiEq; +use super::uint32::UInt32; use crate::{ConstraintSystem, SynthesisError}; use pairing::Engine; @@ -12,37 +12,35 @@ const ROUND_CONSTANTS: [u32; 64] = [ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, ]; const IV: [u32; 8] = [ - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, - 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, ]; pub fn sha256_block_no_padding( mut cs: CS, - input: &[Boolean] + input: &[Boolean], ) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem +where + E: Engine, + CS: ConstraintSystem, { assert_eq!(input.len(), 512); - Ok(sha256_compression_function( - &mut cs, - &input, - &get_sha256_iv() - )? - .into_iter() - .flat_map(|e| e.into_bits_be()) - .collect()) + Ok( + sha256_compression_function(&mut cs, &input, &get_sha256_iv())? + .into_iter() + .flat_map(|e| e.into_bits_be()) + .collect(), + ) } -pub fn sha256( - mut cs: CS, - input: &[Boolean] -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem +pub fn sha256(mut cs: CS, input: &[Boolean]) -> Result, SynthesisError> +where + E: Engine, + CS: ConstraintSystem, { assert!(input.len() % 8 == 0); @@ -62,16 +60,10 @@ pub fn sha256( let mut cur = get_sha256_iv(); for (i, block) in padded.chunks(512).enumerate() { - cur = sha256_compression_function( - cs.namespace(|| format!("block {}", i)), - block, - &cur - )?; + cur = sha256_compression_function(cs.namespace(|| format!("block {}", i)), block, &cur)?; } - Ok(cur.into_iter() - .flat_map(|e| e.into_bits_be()) - .collect()) + Ok(cur.into_iter().flat_map(|e| e.into_bits_be()).collect()) } fn get_sha256_iv() -> Vec { @@ -81,16 +73,19 @@ fn get_sha256_iv() -> Vec { fn sha256_compression_function( cs: CS, input: &[Boolean], - current_hash_value: &[UInt32] + current_hash_value: &[UInt32], ) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem +where + E: Engine, + CS: ConstraintSystem, { assert_eq!(input.len(), 512); assert_eq!(current_hash_value.len(), 8); - let mut w = input.chunks(32) - .map(|e| UInt32::from_bits_be(e)) - .collect::>(); + let mut w = input + .chunks(32) + .map(|e| UInt32::from_bits_be(e)) + .collect::>(); // We can save some constraints by combining some of // the constraints in different u32 additions @@ -100,30 +95,18 @@ fn sha256_compression_function( let cs = &mut cs.namespace(|| format!("w extension {}", i)); // s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3) - let mut s0 = w[i-15].rotr(7); - s0 = s0.xor( - cs.namespace(|| "first xor for s0"), - &w[i-15].rotr(18) - )?; - s0 = s0.xor( - cs.namespace(|| "second xor for s0"), - &w[i-15].shr(3) - )?; + let mut s0 = w[i - 15].rotr(7); + s0 = s0.xor(cs.namespace(|| "first xor for s0"), &w[i - 15].rotr(18))?; + s0 = s0.xor(cs.namespace(|| "second xor for s0"), &w[i - 15].shr(3))?; // s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10) - let mut s1 = w[i-2].rotr(17); - s1 = s1.xor( - cs.namespace(|| "first xor for s1"), - &w[i-2].rotr(19) - )?; - s1 = s1.xor( - cs.namespace(|| "second xor for s1"), - &w[i-2].shr(10) - )?; + let mut s1 = w[i - 2].rotr(17); + s1 = s1.xor(cs.namespace(|| "first xor for s1"), &w[i - 2].rotr(19))?; + s1 = s1.xor(cs.namespace(|| "second xor for s1"), &w[i - 2].shr(10))?; let tmp = UInt32::addmany( cs.namespace(|| "computation of w[i]"), - &[w[i-16].clone(), s0, w[i-7].clone(), s1] + &[w[i - 16].clone(), s0, w[i - 7].clone(), s1], )?; // w[i] := w[i-16] + s0 + w[i-7] + s1 @@ -134,29 +117,21 @@ fn sha256_compression_function( enum Maybe { Deferred(Vec), - Concrete(UInt32) + Concrete(UInt32), } impl Maybe { - fn compute( - self, - cs: M, - others: &[UInt32] - ) -> Result - where E: Engine, - CS: ConstraintSystem, - M: ConstraintSystem> + fn compute(self, cs: M, others: &[UInt32]) -> Result + where + E: Engine, + CS: ConstraintSystem, + M: ConstraintSystem>, { Ok(match self { - Maybe::Concrete(ref v) => { - return Ok(v.clone()) - }, + Maybe::Concrete(ref v) => return Ok(v.clone()), Maybe::Deferred(mut v) => { v.extend(others.into_iter().cloned()); - UInt32::addmany( - cs, - &v - )? + UInt32::addmany(cs, &v)? } }) } @@ -177,22 +152,11 @@ fn sha256_compression_function( // S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25) let new_e = e.compute(cs.namespace(|| "deferred e computation"), &[])?; let mut s1 = new_e.rotr(6); - s1 = s1.xor( - cs.namespace(|| "first xor for s1"), - &new_e.rotr(11) - )?; - s1 = s1.xor( - cs.namespace(|| "second xor for s1"), - &new_e.rotr(25) - )?; + s1 = s1.xor(cs.namespace(|| "first xor for s1"), &new_e.rotr(11))?; + s1 = s1.xor(cs.namespace(|| "second xor for s1"), &new_e.rotr(25))?; // ch := (e and f) xor ((not e) and g) - let ch = UInt32::sha256_ch( - cs.namespace(|| "ch"), - &new_e, - &f, - &g - )?; + let ch = UInt32::sha256_ch(cs.namespace(|| "ch"), &new_e, &f, &g)?; // temp1 := h + S1 + ch + k[i] + w[i] let temp1 = vec![ @@ -200,28 +164,17 @@ fn sha256_compression_function( s1, ch, UInt32::constant(ROUND_CONSTANTS[i]), - w[i].clone() + w[i].clone(), ]; // S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22) let new_a = a.compute(cs.namespace(|| "deferred a computation"), &[])?; let mut s0 = new_a.rotr(2); - s0 = s0.xor( - cs.namespace(|| "first xor for s0"), - &new_a.rotr(13) - )?; - s0 = s0.xor( - cs.namespace(|| "second xor for s0"), - &new_a.rotr(22) - )?; + s0 = s0.xor(cs.namespace(|| "first xor for s0"), &new_a.rotr(13))?; + s0 = s0.xor(cs.namespace(|| "second xor for s0"), &new_a.rotr(22))?; // maj := (a and b) xor (a and c) xor (b and c) - let maj = UInt32::sha256_maj( - cs.namespace(|| "maj"), - &new_a, - &b, - &c - )?; + let maj = UInt32::sha256_maj(cs.namespace(|| "maj"), &new_a, &b, &c)?; // temp2 := S0 + maj let temp2 = vec![s0, maj]; @@ -244,7 +197,13 @@ fn sha256_compression_function( d = c; c = b; b = new_a; - a = Maybe::Deferred(temp1.iter().cloned().chain(temp2.iter().cloned()).collect::>()); + a = Maybe::Deferred( + temp1 + .iter() + .cloned() + .chain(temp2.iter().cloned()) + .collect::>(), + ); } /* @@ -261,42 +220,42 @@ fn sha256_compression_function( let h0 = a.compute( cs.namespace(|| "deferred h0 computation"), - &[current_hash_value[0].clone()] + &[current_hash_value[0].clone()], )?; let h1 = UInt32::addmany( cs.namespace(|| "new h1"), - &[current_hash_value[1].clone(), b] + &[current_hash_value[1].clone(), b], )?; let h2 = UInt32::addmany( cs.namespace(|| "new h2"), - &[current_hash_value[2].clone(), c] + &[current_hash_value[2].clone(), c], )?; let h3 = UInt32::addmany( cs.namespace(|| "new h3"), - &[current_hash_value[3].clone(), d] + &[current_hash_value[3].clone(), d], )?; let h4 = e.compute( cs.namespace(|| "deferred h4 computation"), - &[current_hash_value[4].clone()] + &[current_hash_value[4].clone()], )?; let h5 = UInt32::addmany( cs.namespace(|| "new h5"), - &[current_hash_value[5].clone(), f] + &[current_hash_value[5].clone(), f], )?; let h6 = UInt32::addmany( cs.namespace(|| "new h6"), - &[current_hash_value[6].clone(), g] + &[current_hash_value[6].clone(), g], )?; let h7 = UInt32::addmany( cs.namespace(|| "new h7"), - &[current_hash_value[7].clone(), h] + &[current_hash_value[7].clone(), h], )?; Ok(vec![h0, h1, h2, h3, h4, h5, h6, h7]) @@ -306,8 +265,8 @@ fn sha256_compression_function( mod test { use super::*; use crate::gadgets::boolean::AllocatedBit; - use pairing::bls12_381::Bls12; use crate::gadgets::test::TestConstraintSystem; + use pairing::bls12_381::Bls12; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; @@ -318,11 +277,7 @@ mod test { let mut cs = TestConstraintSystem::::new(); let mut input_bits: Vec<_> = (0..512).map(|_| Boolean::Constant(false)).collect(); input_bits[0] = Boolean::Constant(true); - let out = sha256_compression_function( - &mut cs, - &input_bits, - &iv - ).unwrap(); + let out = sha256_compression_function(&mut cs, &input_bits, &iv).unwrap(); let out_bits: Vec<_> = out.into_iter().flat_map(|e| e.into_bits_be()).collect(); assert!(cs.is_satisfied()); @@ -343,27 +298,26 @@ mod test { #[test] fn test_full_block() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); let iv = get_sha256_iv(); let mut cs = TestConstraintSystem::::new(); - let input_bits: Vec<_> = (0..512).map(|i| { - Boolean::from( - AllocatedBit::alloc( - cs.namespace(|| format!("input bit {}", i)), - Some(rng.next_u32() % 2 != 0) - ).unwrap() - ) - }).collect(); + let input_bits: Vec<_> = (0..512) + .map(|i| { + Boolean::from( + AllocatedBit::alloc( + cs.namespace(|| format!("input bit {}", i)), + Some(rng.next_u32() % 2 != 0), + ) + .unwrap(), + ) + }) + .collect(); - sha256_compression_function( - cs.namespace(|| "sha256"), - &input_bits, - &iv - ).unwrap(); + sha256_compression_function(cs.namespace(|| "sha256"), &input_bits, &iv).unwrap(); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints() - 512, 25840); @@ -374,12 +328,11 @@ mod test { use sha2::{Digest, Sha256}; let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); - for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) - { + for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) { let mut h = Sha256::new(); let data: Vec = (0..input_len).map(|_| rng.next_u32() as u8).collect(); h.input(&data); @@ -392,7 +345,11 @@ mod test { for bit_i in (0..8).rev() { let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i)); - input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into()); + input_bits.push( + AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)) + .unwrap() + .into(), + ); } } @@ -400,17 +357,19 @@ mod test { assert!(cs.is_satisfied()); - let mut s = hash_result.as_ref().iter() - .flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8)); + let mut s = hash_result + .as_ref() + .iter() + .flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8)); for b in r { match b { Boolean::Is(b) => { assert!(s.next().unwrap() == b.get_value().unwrap()); - }, + } Boolean::Not(b) => { assert!(s.next().unwrap() != b.get_value().unwrap()); - }, + } Boolean::Constant(b) => { assert!(input_len == 0); assert!(s.next().unwrap() == b); diff --git a/bellman/src/gadgets/test/mod.rs b/bellman/src/gadgets/test/mod.rs index dc6adbf..58ba040 100644 --- a/bellman/src/gadgets/test/mod.rs +++ b/bellman/src/gadgets/test/mod.rs @@ -1,13 +1,7 @@ use ff::{Field, PrimeField, PrimeFieldRepr}; use pairing::Engine; -use crate::{ - LinearCombination, - SynthesisError, - ConstraintSystem, - Variable, - Index -}; +use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; use std::collections::HashMap; use std::fmt::Write; @@ -22,7 +16,7 @@ use blake2s_simd::{Params as Blake2sParams, State as Blake2sState}; enum NamedObject { Constraint(usize), Var(Variable), - Namespace + Namespace, } /// Constraint system for testing purposes. @@ -33,10 +27,10 @@ pub struct TestConstraintSystem { LinearCombination, LinearCombination, LinearCombination, - String + String, )>, inputs: Vec<(E::Fr, String)>, - aux: Vec<(E::Fr, String)> + aux: Vec<(E::Fr, String)>, } #[derive(Clone, Copy)] @@ -48,7 +42,7 @@ impl PartialEq for OrderedVariable { match (self.0.get_unchecked(), other.0.get_unchecked()) { (Index::Input(ref a), Index::Input(ref b)) => a == b, (Index::Aux(ref a), Index::Aux(ref b)) => a == b, - _ => false + _ => false, } } } @@ -63,20 +57,17 @@ impl Ord for OrderedVariable { (Index::Input(ref a), Index::Input(ref b)) => a.cmp(b), (Index::Aux(ref a), Index::Aux(ref b)) => a.cmp(b), (Index::Input(_), Index::Aux(_)) => Ordering::Less, - (Index::Aux(_), Index::Input(_)) => Ordering::Greater + (Index::Aux(_), Index::Input(_)) => Ordering::Greater, } } } -fn proc_lc( - terms: &[(Variable, E::Fr)], -) -> BTreeMap -{ +fn proc_lc(terms: &[(Variable, E::Fr)]) -> BTreeMap { let mut map = BTreeMap::new(); for &(var, coeff) in terms { map.entry(OrderedVariable(var)) - .or_insert(E::Fr::zero()) - .add_assign(&coeff); + .or_insert(E::Fr::zero()) + .add_assign(&coeff); } // Remove terms that have a zero coefficient to normalize @@ -94,11 +85,7 @@ fn proc_lc( map } -fn hash_lc( - terms: &[(Variable, E::Fr)], - h: &mut Blake2sState -) -{ +fn hash_lc(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) { let map = proc_lc::(terms); let mut buf = [0u8; 9 + 32]; @@ -110,13 +97,13 @@ fn hash_lc( Index::Input(i) => { buf[0] = b'I'; BigEndian::write_u64(&mut buf[1..9], i as u64); - }, + } Index::Aux(i) => { buf[0] = b'A'; BigEndian::write_u64(&mut buf[1..9], i as u64); } } - + coeff.into_repr().write_be(&mut buf[9..]).unwrap(); h.update(&buf); @@ -126,15 +113,14 @@ fn hash_lc( fn eval_lc( terms: &[(Variable, E::Fr)], inputs: &[(E::Fr, String)], - aux: &[(E::Fr, String)] -) -> E::Fr -{ + aux: &[(E::Fr, String)], +) -> E::Fr { let mut acc = E::Fr::zero(); for &(var, ref coeff) in terms { let mut tmp = match var.get_unchecked() { Index::Input(index) => inputs[index].0, - Index::Aux(index) => aux[index].0 + Index::Aux(index) => aux[index].0, }; tmp.mul_assign(&coeff); @@ -147,14 +133,17 @@ fn eval_lc( impl TestConstraintSystem { pub fn new() -> TestConstraintSystem { let mut map = HashMap::new(); - map.insert("ONE".into(), NamedObject::Var(TestConstraintSystem::::one())); + map.insert( + "ONE".into(), + NamedObject::Var(TestConstraintSystem::::one()), + ); TestConstraintSystem { named_objects: map, current_namespace: vec![], constraints: vec![], inputs: vec![(E::Fr::one(), "ONE".into())], - aux: vec![] + aux: vec![], } } @@ -167,9 +156,9 @@ impl TestConstraintSystem { tmp }; - let powers_of_two = (0..E::Fr::NUM_BITS).map(|i| { - E::Fr::from_str("2").unwrap().pow(&[i as u64]) - }).collect::>(); + let powers_of_two = (0..E::Fr::NUM_BITS) + .map(|i| E::Fr::from_str("2").unwrap().pow(&[i as u64])) + .collect::>(); let pp = |s: &mut String, lc: &LinearCombination| { write!(s, "(").unwrap(); @@ -196,7 +185,7 @@ impl TestConstraintSystem { match var.0.get_unchecked() { Index::Input(i) => { write!(s, "`{}`", &self.inputs[i].1).unwrap(); - }, + } Index::Aux(i) => { write!(s, "`{}`", &self.aux[i].1).unwrap(); } @@ -259,45 +248,41 @@ impl TestConstraintSystem { a.mul_assign(&b); if a != c { - return Some(&*path) + return Some(&*path); } } None } - pub fn is_satisfied(&self) -> bool - { + pub fn is_satisfied(&self) -> bool { self.which_is_unsatisfied().is_none() } - pub fn num_constraints(&self) -> usize - { + pub fn num_constraints(&self) -> usize { self.constraints.len() } - pub fn set(&mut self, path: &str, to: E::Fr) - { + pub fn set(&mut self, path: &str, to: E::Fr) { match self.named_objects.get(path) { - Some(&NamedObject::Var(ref v)) => { - match v.get_unchecked() { - Index::Input(index) => self.inputs[index].0 = to, - Index::Aux(index) => self.aux[index].0 = to - } - } - Some(e) => panic!("tried to set path `{}` to value, but `{:?}` already exists there.", path, e), - _ => panic!("no variable exists at path: {}", path) + Some(&NamedObject::Var(ref v)) => match v.get_unchecked() { + Index::Input(index) => self.inputs[index].0 = to, + Index::Aux(index) => self.aux[index].0 = to, + }, + Some(e) => panic!( + "tried to set path `{}` to value, but `{:?}` already exists there.", + path, e + ), + _ => panic!("no variable exists at path: {}", path), } } - pub fn verify(&self, expected: &[E::Fr]) -> bool - { + pub fn verify(&self, expected: &[E::Fr]) -> bool { assert_eq!(expected.len() + 1, self.inputs.len()); - for (a, b) in self.inputs.iter().skip(1).zip(expected.iter()) - { + for (a, b) in self.inputs.iter().skip(1).zip(expected.iter()) { if &a.0 != b { - return false + return false; } } @@ -308,8 +293,7 @@ impl TestConstraintSystem { self.inputs.len() } - pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr - { + pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr { let (assignment, name) = self.inputs[index].clone(); assert_eq!(path, name); @@ -317,17 +301,17 @@ impl TestConstraintSystem { assignment } - pub fn get(&mut self, path: &str) -> E::Fr - { + pub fn get(&mut self, path: &str) -> E::Fr { match self.named_objects.get(path) { - Some(&NamedObject::Var(ref v)) => { - match v.get_unchecked() { - Index::Input(index) => self.inputs[index].0, - Index::Aux(index) => self.aux[index].0 - } - } - Some(e) => panic!("tried to get value of path `{}`, but `{:?}` exists there (not a variable)", path, e), - _ => panic!("no variable exists at path: {}", path) + Some(&NamedObject::Var(ref v)) => match v.get_unchecked() { + Index::Input(index) => self.inputs[index].0, + Index::Aux(index) => self.aux[index].0, + }, + Some(e) => panic!( + "tried to get value of path `{}`, but `{:?}` exists there (not a variable)", + path, e + ), + _ => panic!("no variable exists at path: {}", path), } } @@ -348,8 +332,7 @@ fn compute_path(ns: &[String], this: String) -> String { let mut name = String::new(); let mut needs_separation = false; - for ns in ns.iter().chain(Some(&this).into_iter()) - { + for ns in ns.iter().chain(Some(&this).into_iter()) { if needs_separation { name += "/"; } @@ -364,12 +347,11 @@ fn compute_path(ns: &[String], this: String) -> String { impl ConstraintSystem for TestConstraintSystem { type Root = Self; - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { let index = self.aux.len(); let path = compute_path(&self.current_namespace, annotation().into()); @@ -380,12 +362,11 @@ impl ConstraintSystem for TestConstraintSystem { Ok(var) } - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { let index = self.inputs.len(); let path = compute_path(&self.current_namespace, annotation().into()); @@ -396,17 +377,13 @@ impl ConstraintSystem for TestConstraintSystem { Ok(var) } - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, annotation: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { let path = compute_path(&self.current_namespace, annotation().into()); let index = self.constraints.len(); @@ -420,7 +397,9 @@ impl ConstraintSystem for TestConstraintSystem { } fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { let name = name_fn().into(); let path = compute_path(&self.current_namespace, name.clone()); @@ -428,13 +407,11 @@ impl ConstraintSystem for TestConstraintSystem { self.current_namespace.push(name); } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { assert!(self.current_namespace.pop().is_some()); } - fn get_root(&mut self) -> &mut Self::Root - { + fn get_root(&mut self) -> &mut Self::Root { self } } @@ -447,28 +424,26 @@ fn test_cs() { let mut cs = TestConstraintSystem::::new(); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 0); - let a = cs.namespace(|| "a").alloc(|| "var", || Ok(Fr::from_str("10").unwrap())).unwrap(); - let b = cs.namespace(|| "b").alloc(|| "var", || Ok(Fr::from_str("4").unwrap())).unwrap(); - let c = cs.alloc(|| "product", || Ok(Fr::from_str("40").unwrap())).unwrap(); + let a = cs + .namespace(|| "a") + .alloc(|| "var", || Ok(Fr::from_str("10").unwrap())) + .unwrap(); + let b = cs + .namespace(|| "b") + .alloc(|| "var", || Ok(Fr::from_str("4").unwrap())) + .unwrap(); + let c = cs + .alloc(|| "product", || Ok(Fr::from_str("40").unwrap())) + .unwrap(); - cs.enforce( - || "mult", - |lc| lc + a, - |lc| lc + b, - |lc| lc + c - ); + cs.enforce(|| "mult", |lc| lc + a, |lc| lc + b, |lc| lc + c); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 1); cs.set("a/var", Fr::from_str("4").unwrap()); let one = TestConstraintSystem::::one(); - cs.enforce( - || "eq", - |lc| lc + a, - |lc| lc + one, - |lc| lc + b - ); + cs.enforce(|| "eq", |lc| lc + a, |lc| lc + one, |lc| lc + b); assert!(!cs.is_satisfied()); assert!(cs.which_is_unsatisfied() == Some("mult")); diff --git a/bellman/src/gadgets/uint32.rs b/bellman/src/gadgets/uint32.rs index 90f8d7e..4c0d376 100644 --- a/bellman/src/gadgets/uint32.rs +++ b/bellman/src/gadgets/uint32.rs @@ -1,16 +1,9 @@ use ff::{Field, PrimeField}; use pairing::Engine; -use crate::{ - SynthesisError, - ConstraintSystem, - LinearCombination -}; +use crate::{ConstraintSystem, LinearCombination, SynthesisError}; -use super::boolean::{ - Boolean, - AllocatedBit -}; +use super::boolean::{AllocatedBit, Boolean}; use super::multieq::MultiEq; @@ -20,13 +13,12 @@ use super::multieq::MultiEq; pub struct UInt32 { // Least significant bit first bits: Vec, - value: Option + value: Option, } impl UInt32 { /// Construct a constant `UInt32` from a `u32` - pub fn constant(value: u32) -> Self - { + pub fn constant(value: u32) -> Self { let mut bits = Vec::with_capacity(32); let mut tmp = value; @@ -42,17 +34,15 @@ impl UInt32 { UInt32 { bits: bits, - value: Some(value) + value: Some(value), } } /// Allocate a `UInt32` in the constraint system - pub fn alloc( - mut cs: CS, - value: Option - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn alloc(mut cs: CS, value: Option) -> Result + where + E: Engine, + CS: ConstraintSystem, { let values = match value { Some(mut val) => { @@ -64,23 +54,24 @@ impl UInt32 { } v - }, - None => vec![None; 32] + } + None => vec![None; 32], }; - let bits = values.into_iter() - .enumerate() - .map(|(i, v)| { - Ok(Boolean::from(AllocatedBit::alloc( - cs.namespace(|| format!("allocated bit {}", i)), - v - )?)) - }) - .collect::, SynthesisError>>()?; + let bits = values + .into_iter() + .enumerate() + .map(|(i, v)| { + Ok(Boolean::from(AllocatedBit::alloc( + cs.namespace(|| format!("allocated bit {}", i)), + v, + )?)) + }) + .collect::, SynthesisError>>()?; Ok(UInt32 { bits: bits, - value: value + value: value, }) } @@ -96,19 +87,22 @@ impl UInt32 { value.as_mut().map(|v| *v <<= 1); match b.get_value() { - Some(true) => { value.as_mut().map(|v| *v |= 1); }, - Some(false) => {}, - None => { value = None; } + Some(true) => { + value.as_mut().map(|v| *v |= 1); + } + Some(false) => {} + None => { + value = None; + } } } UInt32 { value: value, - bits: bits.iter().rev().cloned().collect() + bits: bits.iter().rev().cloned().collect(), } } - /// Turns this `UInt32` into its little-endian byte order representation. pub fn into_bits(&self) -> Vec { self.bits.clone() @@ -116,8 +110,7 @@ impl UInt32 { /// Converts a little-endian byte order representation of bits into a /// `UInt32`. - pub fn from_bits(bits: &[Boolean]) -> Self - { + pub fn from_bits(bits: &[Boolean]) -> Self { assert_eq!(bits.len(), 32); let new_bits = bits.to_vec(); @@ -131,43 +124,45 @@ impl UInt32 { if b { value.as_mut().map(|v| *v |= 1); } - }, - &Boolean::Is(ref b) => { - match b.get_value() { - Some(true) => { value.as_mut().map(|v| *v |= 1); }, - Some(false) => {}, - None => { value = None } - } - }, - &Boolean::Not(ref b) => { - match b.get_value() { - Some(false) => { value.as_mut().map(|v| *v |= 1); }, - Some(true) => {}, - None => { value = None } - } } + &Boolean::Is(ref b) => match b.get_value() { + Some(true) => { + value.as_mut().map(|v| *v |= 1); + } + Some(false) => {} + None => value = None, + }, + &Boolean::Not(ref b) => match b.get_value() { + Some(false) => { + value.as_mut().map(|v| *v |= 1); + } + Some(true) => {} + None => value = None, + }, } } UInt32 { value: value, - bits: new_bits + bits: new_bits, } } pub fn rotr(&self, by: usize) -> Self { let by = by % 32; - let new_bits = self.bits.iter() - .skip(by) - .chain(self.bits.iter()) - .take(32) - .cloned() - .collect(); + let new_bits = self + .bits + .iter() + .skip(by) + .chain(self.bits.iter()) + .take(32) + .cloned() + .collect(); UInt32 { bits: new_bits, - value: self.value.map(|v| v.rotate_right(by as u32)) + value: self.value.map(|v| v.rotate_right(by as u32)), } } @@ -176,17 +171,18 @@ impl UInt32 { let fill = Boolean::constant(false); - let new_bits = self.bits - .iter() // The bits are least significant first - .skip(by) // Skip the bits that will be lost during the shift - .chain(Some(&fill).into_iter().cycle()) // Rest will be zeros - .take(32) // Only 32 bits needed! - .cloned() - .collect(); + let new_bits = self + .bits + .iter() // The bits are least significant first + .skip(by) // Skip the bits that will be lost during the shift + .chain(Some(&fill).into_iter().cycle()) // Rest will be zeros + .take(32) // Only 32 bits needed! + .cloned() + .collect(); UInt32 { bits: new_bits, - value: self.value.map(|v| v >> by as u32) + value: self.value.map(|v| v >> by as u32), } } @@ -196,121 +192,99 @@ impl UInt32 { b: &Self, c: &Self, tri_fn: F, - circuit_fn: U + circuit_fn: U, ) -> Result - where E: Engine, - CS: ConstraintSystem, - F: Fn(u32, u32, u32) -> u32, - U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result + where + E: Engine, + CS: ConstraintSystem, + F: Fn(u32, u32, u32) -> u32, + U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result, { let new_value = match (a.value, b.value, c.value) { - (Some(a), Some(b), Some(c)) => { - Some(tri_fn(a, b, c)) - }, - _ => None + (Some(a), Some(b), Some(c)) => Some(tri_fn(a, b, c)), + _ => None, }; - let bits = a.bits.iter() - .zip(b.bits.iter()) - .zip(c.bits.iter()) - .enumerate() - .map(|(i, ((a, b), c))| circuit_fn(&mut cs, i, a, b, c)) - .collect::>()?; + let bits = a + .bits + .iter() + .zip(b.bits.iter()) + .zip(c.bits.iter()) + .enumerate() + .map(|(i, ((a, b), c))| circuit_fn(&mut cs, i, a, b, c)) + .collect::>()?; Ok(UInt32 { bits: bits, - value: new_value + value: new_value, }) } /// Compute the `maj` value (a and b) xor (a and c) xor (b and c) /// during SHA256. - pub fn sha256_maj( - cs: CS, - a: &Self, - b: &Self, - c: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn sha256_maj(cs: CS, a: &Self, b: &Self, c: &Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { - Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ (a & c) ^ (b & c), - |cs, i, a, b, c| { - Boolean::sha256_maj( - cs.namespace(|| format!("maj {}", i)), - a, - b, - c - ) - } + Self::triop( + cs, + a, + b, + c, + |a, b, c| (a & b) ^ (a & c) ^ (b & c), + |cs, i, a, b, c| Boolean::sha256_maj(cs.namespace(|| format!("maj {}", i)), a, b, c), ) } /// Compute the `ch` value `(a and b) xor ((not a) and c)` /// during SHA256. - pub fn sha256_ch( - cs: CS, - a: &Self, - b: &Self, - c: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn sha256_ch(cs: CS, a: &Self, b: &Self, c: &Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { - Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ ((!a) & c), - |cs, i, a, b, c| { - Boolean::sha256_ch( - cs.namespace(|| format!("ch {}", i)), - a, - b, - c - ) - } + Self::triop( + cs, + a, + b, + c, + |a, b, c| (a & b) ^ ((!a) & c), + |cs, i, a, b, c| Boolean::sha256_ch(cs.namespace(|| format!("ch {}", i)), a, b, c), ) } /// XOR this `UInt32` with another `UInt32` - pub fn xor( - &self, - mut cs: CS, - other: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn xor(&self, mut cs: CS, other: &Self) -> Result + where + E: Engine, + CS: ConstraintSystem, { let new_value = match (self.value, other.value) { - (Some(a), Some(b)) => { - Some(a ^ b) - }, - _ => None + (Some(a), Some(b)) => Some(a ^ b), + _ => None, }; - let bits = self.bits.iter() - .zip(other.bits.iter()) - .enumerate() - .map(|(i, (a, b))| { - Boolean::xor( - cs.namespace(|| format!("xor of bit {}", i)), - a, - b - ) - }) - .collect::>()?; + let bits = self + .bits + .iter() + .zip(other.bits.iter()) + .enumerate() + .map(|(i, (a, b))| Boolean::xor(cs.namespace(|| format!("xor of bit {}", i)), a, b)) + .collect::>()?; Ok(UInt32 { bits: bits, - value: new_value + value: new_value, }) } /// Perform modular addition of several `UInt32` objects. - pub fn addmany( - mut cs: M, - operands: &[Self] - ) -> Result - where E: Engine, - CS: ConstraintSystem, - M: ConstraintSystem> + pub fn addmany(mut cs: M, operands: &[Self]) -> Result + where + E: Engine, + CS: ConstraintSystem, + M: ConstraintSystem>, { // Make some arbitrary bounds for ourselves to avoid overflows // in the scalar field @@ -337,7 +311,7 @@ impl UInt32 { match op.value { Some(val) => { result_value.as_mut().map(|v| *v += val as u64); - }, + } None => { // If any of our operands have unknown value, we won't // know the value of the result @@ -381,7 +355,7 @@ impl UInt32 { // Allocate the bit let b = AllocatedBit::alloc( cs.namespace(|| format!("result bit {}", i)), - result_value.map(|v| (v >> i) & 1 == 1) + result_value.map(|v| (v >> i) & 1 == 1), )?; // Add this bit to the result combination @@ -402,32 +376,34 @@ impl UInt32 { Ok(UInt32 { bits: result_bits, - value: modular_value + value: modular_value, }) } } #[cfg(test)] mod test { - use crate::gadgets::boolean::{Boolean}; - use super::{UInt32}; - use ff::Field; - use pairing::bls12_381::{Bls12}; - use crate::gadgets::test::*; - use crate::{ConstraintSystem}; + use super::UInt32; + use crate::gadgets::boolean::Boolean; use crate::gadgets::multieq::MultiEq; + use crate::gadgets::test::*; + use crate::ConstraintSystem; + use ff::Field; + use pairing::bls12_381::Bls12; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; #[test] fn test_uint32_from_bits_be() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { - let mut v = (0..32).map(|_| Boolean::constant(rng.next_u32() % 2 != 0)).collect::>(); + let mut v = (0..32) + .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) + .collect::>(); let b = UInt32::from_bits_be(&v); @@ -435,19 +411,18 @@ mod test { match bit { &Boolean::Constant(bit) => { assert!(bit == ((b.value.unwrap() >> i) & 1 == 1)); - }, - _ => unreachable!() + } + _ => unreachable!(), } } let expected_to_be_same = b.into_bits_be(); - for x in v.iter().zip(expected_to_be_same.iter()) - { + for x in v.iter().zip(expected_to_be_same.iter()) { match x { - (&Boolean::Constant(true), &Boolean::Constant(true)) => {}, - (&Boolean::Constant(false), &Boolean::Constant(false)) => {}, - _ => unreachable!() + (&Boolean::Constant(true), &Boolean::Constant(true)) => {} + (&Boolean::Constant(false), &Boolean::Constant(false)) => {} + _ => unreachable!(), } } } @@ -456,12 +431,14 @@ mod test { #[test] fn test_uint32_from_bits() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { - let mut v = (0..32).map(|_| Boolean::constant(rng.next_u32() % 2 != 0)).collect::>(); + let mut v = (0..32) + .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) + .collect::>(); let b = UInt32::from_bits(&v); @@ -469,19 +446,18 @@ mod test { match bit { &Boolean::Constant(bit) => { assert!(bit == ((b.value.unwrap() >> i) & 1 == 1)); - }, - _ => unreachable!() + } + _ => unreachable!(), } } let expected_to_be_same = b.into_bits(); - for x in v.iter().zip(expected_to_be_same.iter()) - { + for x in v.iter().zip(expected_to_be_same.iter()) { match x { - (&Boolean::Constant(true), &Boolean::Constant(true)) => {}, - (&Boolean::Constant(false), &Boolean::Constant(false)) => {}, - _ => unreachable!() + (&Boolean::Constant(true), &Boolean::Constant(true)) => {} + (&Boolean::Constant(false), &Boolean::Constant(false)) => {} + _ => unreachable!(), } } } @@ -490,8 +466,8 @@ mod test { #[test] fn test_uint32_xor() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { @@ -518,10 +494,10 @@ mod test { match b { &Boolean::Is(ref b) => { assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Not(ref b) => { assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Constant(b) => { assert!(b == (expected & 1 == 1)); } @@ -535,8 +511,8 @@ mod test { #[test] fn test_uint32_addmany_constants() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { @@ -554,7 +530,8 @@ mod test { let r = { let mut cs = MultiEq::new(&mut cs); - let r = UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap(); + let r = + UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap(); r }; @@ -577,8 +554,8 @@ mod test { #[test] fn test_uint32_addmany() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { @@ -611,13 +588,11 @@ mod test { match b { &Boolean::Is(ref b) => { assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Not(ref b) => { assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, - &Boolean::Constant(_) => { - unreachable!() } + &Boolean::Constant(_) => unreachable!(), } expected >>= 1; @@ -637,8 +612,8 @@ mod test { #[test] fn test_uint32_rotr() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); let mut num = rng.next_u32(); @@ -656,8 +631,8 @@ mod test { match b { &Boolean::Constant(b) => { assert_eq!(b, tmp & 1 == 1); - }, - _ => unreachable!() + } + _ => unreachable!(), } tmp >>= 1; @@ -670,8 +645,8 @@ mod test { #[test] fn test_uint32_shr() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..50 { @@ -693,8 +668,8 @@ mod test { #[test] fn test_uint32_sha256_maj() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { @@ -720,10 +695,10 @@ mod test { match b { &Boolean::Is(ref b) => { assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Not(ref b) => { assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Constant(b) => { assert!(b == (expected & 1 == 1)); } @@ -737,8 +712,8 @@ mod test { #[test] fn test_uint32_sha256_ch() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { @@ -764,10 +739,10 @@ mod test { match b { &Boolean::Is(ref b) => { assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Not(ref b) => { assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Constant(b) => { assert!(b == (expected & 1 == 1)); } diff --git a/bellman/src/groth16/generator.rs b/bellman/src/groth16/generator.rs index 3e15b2b..596464f 100644 --- a/bellman/src/groth16/generator.rs +++ b/bellman/src/groth16/generator.rs @@ -6,36 +6,24 @@ use ff::{Field, PrimeField}; use group::{CurveAffine, CurveProjective, Wnaf}; use pairing::Engine; -use super::{ - Parameters, - VerifyingKey -}; +use super::{Parameters, VerifyingKey}; -use ::{ - SynthesisError, - Circuit, - ConstraintSystem, - LinearCombination, - Variable, - Index -}; +use {Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; -use ::domain::{ - EvaluationDomain, - Scalar -}; +use domain::{EvaluationDomain, Scalar}; -use ::multicore::{ - Worker -}; +use multicore::Worker; /// Generates a random common reference string for /// a circuit. pub fn generate_random_parameters( circuit: C, - rng: &mut R + rng: &mut R, ) -> Result, SynthesisError> - where E: Engine, C: Circuit, R: RngCore +where + E: Engine, + C: Circuit, + R: RngCore, { let g1 = E::G1::random(rng); let g2 = E::G2::random(rng); @@ -45,16 +33,7 @@ pub fn generate_random_parameters( let delta = E::Fr::random(rng); let tau = E::Fr::random(rng); - generate_parameters::( - circuit, - g1, - g2, - alpha, - beta, - gamma, - delta, - tau - ) + generate_parameters::(circuit, g1, g2, alpha, beta, gamma, delta, tau) } /// This is our assembly structure that we'll use to synthesize the @@ -68,18 +47,17 @@ struct KeypairAssembly { ct_inputs: Vec>, at_aux: Vec>, bt_aux: Vec>, - ct_aux: Vec> + ct_aux: Vec>, } impl ConstraintSystem for KeypairAssembly { type Root = Self; - fn alloc( - &mut self, - _: A, - _: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, _: A, _: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { // There is no assignment, so we don't even invoke the // function for obtaining one. @@ -94,12 +72,11 @@ impl ConstraintSystem for KeypairAssembly { Ok(Variable(Index::Aux(index))) } - fn alloc_input( - &mut self, - _: A, - _: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, _: A, _: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { // There is no assignment, so we don't even invoke the // function for obtaining one. @@ -114,48 +91,59 @@ impl ConstraintSystem for KeypairAssembly { Ok(Variable(Index::Input(index))) } - fn enforce( - &mut self, - _: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, _: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { fn eval( l: LinearCombination, inputs: &mut [Vec<(E::Fr, usize)>], aux: &mut [Vec<(E::Fr, usize)>], - this_constraint: usize - ) - { + this_constraint: usize, + ) { for (index, coeff) in l.0 { match index { Variable(Index::Input(id)) => inputs[id].push((coeff, this_constraint)), - Variable(Index::Aux(id)) => aux[id].push((coeff, this_constraint)) + Variable(Index::Aux(id)) => aux[id].push((coeff, this_constraint)), } } } - eval(a(LinearCombination::zero()), &mut self.at_inputs, &mut self.at_aux, self.num_constraints); - eval(b(LinearCombination::zero()), &mut self.bt_inputs, &mut self.bt_aux, self.num_constraints); - eval(c(LinearCombination::zero()), &mut self.ct_inputs, &mut self.ct_aux, self.num_constraints); + eval( + a(LinearCombination::zero()), + &mut self.at_inputs, + &mut self.at_aux, + self.num_constraints, + ); + eval( + b(LinearCombination::zero()), + &mut self.bt_inputs, + &mut self.bt_aux, + self.num_constraints, + ); + eval( + c(LinearCombination::zero()), + &mut self.ct_inputs, + &mut self.ct_aux, + self.num_constraints, + ); self.num_constraints += 1; } fn push_namespace(&mut self, _: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { // Do nothing; we don't care about namespaces in this context. } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { // Do nothing; we don't care about namespaces in this context. } @@ -173,9 +161,11 @@ pub fn generate_parameters( beta: E::Fr, gamma: E::Fr, delta: E::Fr, - tau: E::Fr + tau: E::Fr, ) -> Result, SynthesisError> - where E: Engine, C: Circuit +where + E: Engine, + C: Circuit, { let mut assembly = KeypairAssembly { num_inputs: 0, @@ -186,7 +176,7 @@ pub fn generate_parameters( ct_inputs: vec![], at_aux: vec![], bt_aux: vec![], - ct_aux: vec![] + ct_aux: vec![], }; // Allocate the "one" input variable @@ -198,11 +188,7 @@ pub fn generate_parameters( // Input constraints to ensure full density of IC query // x * 0 = 0 for i in 0..assembly.num_inputs { - assembly.enforce(|| "", - |lc| lc + Variable(Index::Input(i)), - |lc| lc, - |lc| lc, - ); + assembly.enforce(|| "", |lc| lc + Variable(Index::Input(i)), |lc| lc, |lc| lc); } // Create bases for blind evaluation of polynomials at tau @@ -240,10 +226,9 @@ pub fn generate_parameters( { let powers_of_tau = powers_of_tau.as_mut(); worker.scope(powers_of_tau.len(), |scope, chunk| { - for (i, powers_of_tau) in powers_of_tau.chunks_mut(chunk).enumerate() - { + for (i, powers_of_tau) in powers_of_tau.chunks_mut(chunk).enumerate() { scope.spawn(move || { - let mut current_tau_power = tau.pow(&[(i*chunk) as u64]); + let mut current_tau_power = tau.pow(&[(i * chunk) as u64]); for p in powers_of_tau { p.0 = current_tau_power; @@ -260,14 +245,15 @@ pub fn generate_parameters( // Compute the H query with multiple threads worker.scope(h.len(), |scope, chunk| { - for (h, p) in h.chunks_mut(chunk).zip(powers_of_tau.as_ref().chunks(chunk)) + for (h, p) in h + .chunks_mut(chunk) + .zip(powers_of_tau.as_ref().chunks(chunk)) { let mut g1_wnaf = g1_wnaf.shared(); scope.spawn(move || { // Set values of the H query to g1^{(tau^i * t(tau)) / delta} - for (h, p) in h.iter_mut().zip(p.iter()) - { + for (h, p) in h.iter_mut().zip(p.iter()) { // Compute final exponent let mut exp = p.0; exp.mul_assign(&coeff); @@ -320,9 +306,8 @@ pub fn generate_parameters( beta: &E::Fr, // Worker - worker: &Worker - ) - { + worker: &Worker, + ) { // Sanity check assert_eq!(a.len(), at.len()); assert_eq!(a.len(), bt.len()); @@ -333,31 +318,32 @@ pub fn generate_parameters( // Evaluate polynomials in multiple threads worker.scope(a.len(), |scope, chunk| { - for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a.chunks_mut(chunk) - .zip(b_g1.chunks_mut(chunk)) - .zip(b_g2.chunks_mut(chunk)) - .zip(ext.chunks_mut(chunk)) - .zip(at.chunks(chunk)) - .zip(bt.chunks(chunk)) - .zip(ct.chunks(chunk)) + for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a + .chunks_mut(chunk) + .zip(b_g1.chunks_mut(chunk)) + .zip(b_g2.chunks_mut(chunk)) + .zip(ext.chunks_mut(chunk)) + .zip(at.chunks(chunk)) + .zip(bt.chunks(chunk)) + .zip(ct.chunks(chunk)) { let mut g1_wnaf = g1_wnaf.shared(); let mut g2_wnaf = g2_wnaf.shared(); scope.spawn(move || { - for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a.iter_mut() - .zip(b_g1.iter_mut()) - .zip(b_g2.iter_mut()) - .zip(ext.iter_mut()) - .zip(at.iter()) - .zip(bt.iter()) - .zip(ct.iter()) + for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a + .iter_mut() + .zip(b_g1.iter_mut()) + .zip(b_g2.iter_mut()) + .zip(ext.iter_mut()) + .zip(at.iter()) + .zip(bt.iter()) + .zip(ct.iter()) { fn eval_at_tau( powers_of_tau: &[Scalar], - p: &[(E::Fr, usize)] - ) -> E::Fr - { + p: &[(E::Fr, usize)], + ) -> E::Fr { let mut acc = E::Fr::zero(); for &(ref coeff, index) in p { @@ -422,7 +408,7 @@ pub fn generate_parameters( &gamma_inverse, &alpha, &beta, - &worker + &worker, ); // Evaluate for auxiliary variables. @@ -440,7 +426,7 @@ pub fn generate_parameters( &delta_inverse, &alpha, &beta, - &worker + &worker, ); // Don't allow any elements be unconstrained, so that @@ -461,7 +447,7 @@ pub fn generate_parameters( gamma_g2: g2.mul(gamma).into_affine(), delta_g1: g1.mul(delta).into_affine(), delta_g2: g2.mul(delta).into_affine(), - ic: ic.into_iter().map(|e| e.into_affine()).collect() + ic: ic.into_iter().map(|e| e.into_affine()).collect(), }; Ok(Parameters { @@ -470,8 +456,23 @@ pub fn generate_parameters( l: Arc::new(l.into_iter().map(|e| e.into_affine()).collect()), // Filter points at infinity away from A/B queries - a: Arc::new(a.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()), - b_g1: Arc::new(b_g1.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()), - b_g2: Arc::new(b_g2.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()) + a: Arc::new( + a.into_iter() + .filter(|e| !e.is_zero()) + .map(|e| e.into_affine()) + .collect(), + ), + b_g1: Arc::new( + b_g1.into_iter() + .filter(|e| !e.is_zero()) + .map(|e| e.into_affine()) + .collect(), + ), + b_g2: Arc::new( + b_g2.into_iter() + .filter(|e| !e.is_zero()) + .map(|e| e.into_affine()) + .collect(), + ), }) } diff --git a/bellman/src/groth16/mod.rs b/bellman/src/groth16/mod.rs index 767150c..85b7952 100644 --- a/bellman/src/groth16/mod.rs +++ b/bellman/src/groth16/mod.rs @@ -1,17 +1,12 @@ use group::{CurveAffine, EncodedPoint}; -use pairing::{ - Engine, - PairingCurveAffine, -}; +use pairing::{Engine, PairingCurveAffine}; -use ::{ - SynthesisError -}; +use SynthesisError; +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use multiexp::SourceBuilder; use std::io::{self, Read, Write}; use std::sync::Arc; -use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; #[cfg(test)] mod tests; @@ -28,23 +23,17 @@ pub use self::verifier::*; pub struct Proof { pub a: E::G1Affine, pub b: E::G2Affine, - pub c: E::G1Affine + pub c: E::G1Affine, } impl PartialEq for Proof { fn eq(&self, other: &Self) -> bool { - self.a == other.a && - self.b == other.b && - self.c == other.c + self.a == other.a && self.b == other.b && self.c == other.c } } impl Proof { - pub fn write( - &self, - mut writer: W - ) -> io::Result<()> - { + pub fn write(&self, mut writer: W) -> io::Result<()> { writer.write_all(self.a.into_compressed().as_ref())?; writer.write_all(self.b.into_compressed().as_ref())?; writer.write_all(self.c.into_compressed().as_ref())?; @@ -52,48 +41,56 @@ impl Proof { Ok(()) } - pub fn read( - mut reader: R - ) -> io::Result - { + pub fn read(mut reader: R) -> io::Result { let mut g1_repr = ::Compressed::empty(); let mut g2_repr = ::Compressed::empty(); reader.read_exact(g1_repr.as_mut())?; let a = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) } else { Ok(e) - })?; + } + })?; reader.read_exact(g2_repr.as_mut())?; let b = g2_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) } else { Ok(e) - })?; + } + })?; reader.read_exact(g1_repr.as_mut())?; let c = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) } else { Ok(e) - })?; + } + })?; - Ok(Proof { - a: a, - b: b, - c: c - }) + Ok(Proof { a: a, b: b, c: c }) } } @@ -122,27 +119,23 @@ pub struct VerifyingKey { // for all public inputs. Because all public inputs have a dummy constraint, // this is the same size as the number of inputs, and never contains points // at infinity. - pub ic: Vec + pub ic: Vec, } impl PartialEq for VerifyingKey { fn eq(&self, other: &Self) -> bool { - self.alpha_g1 == other.alpha_g1 && - self.beta_g1 == other.beta_g1 && - self.beta_g2 == other.beta_g2 && - self.gamma_g2 == other.gamma_g2 && - self.delta_g1 == other.delta_g1 && - self.delta_g2 == other.delta_g2 && - self.ic == other.ic + self.alpha_g1 == other.alpha_g1 + && self.beta_g1 == other.beta_g1 + && self.beta_g2 == other.beta_g2 + && self.gamma_g2 == other.gamma_g2 + && self.delta_g1 == other.delta_g1 + && self.delta_g2 == other.delta_g2 + && self.ic == other.ic } } impl VerifyingKey { - pub fn write( - &self, - mut writer: W - ) -> io::Result<()> - { + pub fn write(&self, mut writer: W) -> io::Result<()> { writer.write_all(self.alpha_g1.into_uncompressed().as_ref())?; writer.write_all(self.beta_g1.into_uncompressed().as_ref())?; writer.write_all(self.beta_g2.into_uncompressed().as_ref())?; @@ -157,30 +150,39 @@ impl VerifyingKey { Ok(()) } - pub fn read( - mut reader: R - ) -> io::Result - { + pub fn read(mut reader: R) -> io::Result { let mut g1_repr = ::Uncompressed::empty(); let mut g2_repr = ::Uncompressed::empty(); reader.read_exact(g1_repr.as_mut())?; - let alpha_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let alpha_g1 = g1_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; reader.read_exact(g1_repr.as_mut())?; - let beta_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let beta_g1 = g1_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; reader.read_exact(g2_repr.as_mut())?; - let beta_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let beta_g2 = g2_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; reader.read_exact(g2_repr.as_mut())?; - let gamma_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let gamma_g2 = g2_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; reader.read_exact(g1_repr.as_mut())?; - let delta_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let delta_g1 = g1_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; reader.read_exact(g2_repr.as_mut())?; - let delta_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let delta_g2 = g2_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; let ic_len = reader.read_u32::()? as usize; @@ -189,13 +191,18 @@ impl VerifyingKey { for _ in 0..ic_len { reader.read_exact(g1_repr.as_mut())?; let g1 = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) - })?; + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) + } else { + Ok(e) + } + })?; ic.push(g1); } @@ -207,7 +214,7 @@ impl VerifyingKey { gamma_g2: gamma_g2, delta_g1: delta_g1, delta_g2: delta_g2, - ic: ic + ic: ic, }) } } @@ -216,7 +223,7 @@ impl VerifyingKey { pub struct Parameters { pub vk: VerifyingKey, - // Elements of the form ((tau^i * t(tau)) / delta) for i between 0 and + // Elements of the form ((tau^i * t(tau)) / delta) for i between 0 and // m-2 inclusive. Never contains points at infinity. pub h: Arc>, @@ -234,26 +241,22 @@ pub struct Parameters { // G1 and G2 for C/B queries, respectively. Never contains points at // infinity for the same reason as the "A" polynomials. pub b_g1: Arc>, - pub b_g2: Arc> + pub b_g2: Arc>, } impl PartialEq for Parameters { fn eq(&self, other: &Self) -> bool { - self.vk == other.vk && - self.h == other.h && - self.l == other.l && - self.a == other.a && - self.b_g1 == other.b_g1 && - self.b_g2 == other.b_g2 + self.vk == other.vk + && self.h == other.h + && self.l == other.l + && self.a == other.a + && self.b_g1 == other.b_g1 + && self.b_g2 == other.b_g2 } } impl Parameters { - pub fn write( - &self, - mut writer: W - ) -> io::Result<()> - { + pub fn write(&self, mut writer: W) -> io::Result<()> { self.vk.write(&mut writer)?; writer.write_u32::(self.h.len() as u32)?; @@ -284,27 +287,26 @@ impl Parameters { Ok(()) } - pub fn read( - mut reader: R, - checked: bool - ) -> io::Result - { + pub fn read(mut reader: R, checked: bool) -> io::Result { let read_g1 = |reader: &mut R| -> io::Result { let mut repr = ::Uncompressed::empty(); reader.read_exact(repr.as_mut())?; if checked { - repr - .into_affine() + repr.into_affine() } else { - repr - .into_affine_unchecked() + repr.into_affine_unchecked() } .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) + } else { + Ok(e) + } }) }; @@ -313,17 +315,20 @@ impl Parameters { reader.read_exact(repr.as_mut())?; if checked { - repr - .into_affine() + repr.into_affine() } else { - repr - .into_affine_unchecked() + repr.into_affine_unchecked() } .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) + } else { + Ok(e) + } }) }; @@ -376,7 +381,7 @@ impl Parameters { l: Arc::new(l), a: Arc::new(a), b_g1: Arc::new(b_g1), - b_g2: Arc::new(b_g2) + b_g2: Arc::new(b_g2), }) } } @@ -389,39 +394,30 @@ pub struct PreparedVerifyingKey { /// -delta in G2 neg_delta_g2: ::Prepared, /// Copy of IC from `VerifiyingKey`. - ic: Vec + ic: Vec, } pub trait ParameterSource { type G1Builder: SourceBuilder; type G2Builder: SourceBuilder; - fn get_vk( - &mut self, - num_ic: usize - ) -> Result, SynthesisError>; - fn get_h( - &mut self, - num_h: usize - ) -> Result; - fn get_l( - &mut self, - num_l: usize - ) -> Result; + fn get_vk(&mut self, num_ic: usize) -> Result, SynthesisError>; + fn get_h(&mut self, num_h: usize) -> Result; + fn get_l(&mut self, num_l: usize) -> Result; fn get_a( &mut self, num_inputs: usize, - num_aux: usize + num_aux: usize, ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>; fn get_b_g1( &mut self, num_inputs: usize, - num_aux: usize + num_aux: usize, ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>; fn get_b_g2( &mut self, num_inputs: usize, - num_aux: usize + num_aux: usize, ) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError>; } @@ -429,54 +425,39 @@ impl<'a, E: Engine> ParameterSource for &'a Parameters { type G1Builder = (Arc>, usize); type G2Builder = (Arc>, usize); - fn get_vk( - &mut self, - _: usize - ) -> Result, SynthesisError> - { + fn get_vk(&mut self, _: usize) -> Result, SynthesisError> { Ok(self.vk.clone()) } - fn get_h( - &mut self, - _: usize - ) -> Result - { + fn get_h(&mut self, _: usize) -> Result { Ok((self.h.clone(), 0)) } - fn get_l( - &mut self, - _: usize - ) -> Result - { + fn get_l(&mut self, _: usize) -> Result { Ok((self.l.clone(), 0)) } fn get_a( &mut self, num_inputs: usize, - _: usize - ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> - { + _: usize, + ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> { Ok(((self.a.clone(), 0), (self.a.clone(), num_inputs))) } fn get_b_g1( &mut self, num_inputs: usize, - _: usize - ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> - { + _: usize, + ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> { Ok(((self.b_g1.clone(), 0), (self.b_g1.clone(), num_inputs))) } fn get_b_g2( &mut self, num_inputs: usize, - _: usize - ) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError> - { + _: usize, + ) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError> { Ok(((self.b_g2.clone(), 0), (self.b_g2.clone(), num_inputs))) } } @@ -484,41 +465,38 @@ impl<'a, E: Engine> ParameterSource for &'a Parameters { #[cfg(test)] mod test_with_bls12_381 { use super::*; - use {Circuit, SynthesisError, ConstraintSystem}; + use {Circuit, ConstraintSystem, SynthesisError}; use ff::Field; - use rand::{thread_rng}; use pairing::bls12_381::{Bls12, Fr}; + use rand::thread_rng; #[test] fn serialization() { struct MySillyCircuit { a: Option, - b: Option + b: Option, } impl Circuit for MySillyCircuit { fn synthesize>( self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { + cs: &mut CS, + ) -> Result<(), SynthesisError> { let a = cs.alloc(|| "a", || self.a.ok_or(SynthesisError::AssignmentMissing))?; let b = cs.alloc(|| "b", || self.b.ok_or(SynthesisError::AssignmentMissing))?; - let c = cs.alloc_input(|| "c", || { - let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?; - let b = self.b.ok_or(SynthesisError::AssignmentMissing)?; + let c = cs.alloc_input( + || "c", + || { + let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?; + let b = self.b.ok_or(SynthesisError::AssignmentMissing)?; - a.mul_assign(&b); - Ok(a) - })?; + a.mul_assign(&b); + Ok(a) + }, + )?; - cs.enforce( - || "a*b=c", - |lc| lc + a, - |lc| lc + b, - |lc| lc + c - ); + cs.enforce(|| "a*b=c", |lc| lc + a, |lc| lc + b, |lc| lc + c); Ok(()) } @@ -526,10 +504,9 @@ mod test_with_bls12_381 { let rng = &mut thread_rng(); - let params = generate_random_parameters::( - MySillyCircuit { a: None, b: None }, - rng - ).unwrap(); + let params = + generate_random_parameters::(MySillyCircuit { a: None, b: None }, rng) + .unwrap(); { let mut v = vec![]; @@ -555,11 +532,12 @@ mod test_with_bls12_381 { let proof = create_random_proof( MySillyCircuit { a: Some(a), - b: Some(b) + b: Some(b), }, ¶ms, - rng - ).unwrap(); + rng, + ) + .unwrap(); let mut v = vec![]; proof.write(&mut v).unwrap(); diff --git a/bellman/src/groth16/prover.rs b/bellman/src/groth16/prover.rs index ceb3dce..a502ac3 100644 --- a/bellman/src/groth16/prover.rs +++ b/bellman/src/groth16/prover.rs @@ -8,43 +8,23 @@ use ff::{Field, PrimeField}; use group::{CurveAffine, CurveProjective}; use pairing::Engine; -use super::{ - ParameterSource, - Proof -}; +use super::{ParameterSource, Proof}; -use ::{ - SynthesisError, - Circuit, - ConstraintSystem, - LinearCombination, - Variable, - Index -}; +use {Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; -use ::domain::{ - EvaluationDomain, - Scalar -}; +use domain::{EvaluationDomain, Scalar}; -use ::multiexp::{ - DensityTracker, - FullDensity, - multiexp -}; +use multiexp::{multiexp, DensityTracker, FullDensity}; -use ::multicore::{ - Worker -}; +use multicore::Worker; fn eval( lc: &LinearCombination, mut input_density: Option<&mut DensityTracker>, mut aux_density: Option<&mut DensityTracker>, input_assignment: &[E::Fr], - aux_assignment: &[E::Fr] -) -> E::Fr -{ + aux_assignment: &[E::Fr], +) -> E::Fr { let mut acc = E::Fr::zero(); for &(index, coeff) in lc.0.iter() { @@ -56,7 +36,7 @@ fn eval( if let Some(ref mut v) = input_density { v.inc(i); } - }, + } Variable(Index::Aux(i)) => { tmp = aux_assignment[i]; if let Some(ref mut v) = aux_density { @@ -66,10 +46,10 @@ fn eval( } if coeff == E::Fr::one() { - acc.add_assign(&tmp); + acc.add_assign(&tmp); } else { - tmp.mul_assign(&coeff); - acc.add_assign(&tmp); + tmp.mul_assign(&coeff); + acc.add_assign(&tmp); } } @@ -89,18 +69,17 @@ struct ProvingAssignment { // Assignments of variables input_assignment: Vec, - aux_assignment: Vec + aux_assignment: Vec, } impl ConstraintSystem for ProvingAssignment { type Root = Self; - fn alloc( - &mut self, - _: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, _: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.aux_assignment.push(f()?); self.a_aux_density.add_element(); @@ -109,12 +88,11 @@ impl ConstraintSystem for ProvingAssignment { Ok(Variable(Index::Aux(self.aux_assignment.len() - 1))) } - fn alloc_input( - &mut self, - _: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, _: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.input_assignment.push(f()?); self.b_input_density.add_element(); @@ -122,17 +100,13 @@ impl ConstraintSystem for ProvingAssignment { Ok(Variable(Index::Input(self.input_assignment.len() - 1))) } - fn enforce( - &mut self, - _: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, _: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { let a = a(LinearCombination::zero()); let b = b(LinearCombination::zero()); @@ -146,14 +120,14 @@ impl ConstraintSystem for ProvingAssignment { None, Some(&mut self.a_aux_density), &self.input_assignment, - &self.aux_assignment + &self.aux_assignment, ))); self.b.push(Scalar(eval( &b, Some(&mut self.b_input_density), Some(&mut self.b_aux_density), &self.input_assignment, - &self.aux_assignment + &self.aux_assignment, ))); self.c.push(Scalar(eval( &c, @@ -164,18 +138,19 @@ impl ConstraintSystem for ProvingAssignment { None, None, &self.input_assignment, - &self.aux_assignment + &self.aux_assignment, ))); } fn push_namespace(&mut self, _: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { // Do nothing; we don't care about namespaces in this context. } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { // Do nothing; we don't care about namespaces in this context. } @@ -187,9 +162,12 @@ impl ConstraintSystem for ProvingAssignment { pub fn create_random_proof>( circuit: C, params: P, - rng: &mut R + rng: &mut R, ) -> Result, SynthesisError> - where E: Engine, C: Circuit, R: RngCore +where + E: Engine, + C: Circuit, + R: RngCore, { let r = E::Fr::random(rng); let s = E::Fr::random(rng); @@ -201,9 +179,11 @@ pub fn create_proof>( circuit: C, mut params: P, r: E::Fr, - s: E::Fr + s: E::Fr, ) -> Result, SynthesisError> - where E: Engine, C: Circuit +where + E: Engine, + C: Circuit, { let mut prover = ProvingAssignment { a_aux_density: DensityTracker::new(), @@ -213,7 +193,7 @@ pub fn create_proof>( b: vec![], c: vec![], input_assignment: vec![], - aux_assignment: vec![] + aux_assignment: vec![], }; prover.alloc_input(|| "", || Ok(E::Fr::one()))?; @@ -221,11 +201,7 @@ pub fn create_proof>( circuit.synthesize(&mut prover)?; for i in 0..prover.input_assignment.len() { - prover.enforce(|| "", - |lc| lc + Variable(Index::Input(i)), - |lc| lc, - |lc| lc, - ); + prover.enforce(|| "", |lc| lc + Variable(Index::Input(i)), |lc| lc, |lc| lc); } let worker = Worker::new(); @@ -259,31 +235,76 @@ pub fn create_proof>( }; // TODO: parallelize if it's even helpful - let input_assignment = Arc::new(prover.input_assignment.into_iter().map(|s| s.into_repr()).collect::>()); - let aux_assignment = Arc::new(prover.aux_assignment.into_iter().map(|s| s.into_repr()).collect::>()); + let input_assignment = Arc::new( + prover + .input_assignment + .into_iter() + .map(|s| s.into_repr()) + .collect::>(), + ); + let aux_assignment = Arc::new( + prover + .aux_assignment + .into_iter() + .map(|s| s.into_repr()) + .collect::>(), + ); - let l = multiexp(&worker, params.get_l(aux_assignment.len())?, FullDensity, aux_assignment.clone()); + let l = multiexp( + &worker, + params.get_l(aux_assignment.len())?, + FullDensity, + aux_assignment.clone(), + ); let a_aux_density_total = prover.a_aux_density.get_total_density(); - let (a_inputs_source, a_aux_source) = params.get_a(input_assignment.len(), a_aux_density_total)?; + let (a_inputs_source, a_aux_source) = + params.get_a(input_assignment.len(), a_aux_density_total)?; - let a_inputs = multiexp(&worker, a_inputs_source, FullDensity, input_assignment.clone()); - let a_aux = multiexp(&worker, a_aux_source, Arc::new(prover.a_aux_density), aux_assignment.clone()); + let a_inputs = multiexp( + &worker, + a_inputs_source, + FullDensity, + input_assignment.clone(), + ); + let a_aux = multiexp( + &worker, + a_aux_source, + Arc::new(prover.a_aux_density), + aux_assignment.clone(), + ); let b_input_density = Arc::new(prover.b_input_density); let b_input_density_total = b_input_density.get_total_density(); let b_aux_density = Arc::new(prover.b_aux_density); let b_aux_density_total = b_aux_density.get_total_density(); - let (b_g1_inputs_source, b_g1_aux_source) = params.get_b_g1(b_input_density_total, b_aux_density_total)?; + let (b_g1_inputs_source, b_g1_aux_source) = + params.get_b_g1(b_input_density_total, b_aux_density_total)?; - let b_g1_inputs = multiexp(&worker, b_g1_inputs_source, b_input_density.clone(), input_assignment.clone()); - let b_g1_aux = multiexp(&worker, b_g1_aux_source, b_aux_density.clone(), aux_assignment.clone()); + let b_g1_inputs = multiexp( + &worker, + b_g1_inputs_source, + b_input_density.clone(), + input_assignment.clone(), + ); + let b_g1_aux = multiexp( + &worker, + b_g1_aux_source, + b_aux_density.clone(), + aux_assignment.clone(), + ); - let (b_g2_inputs_source, b_g2_aux_source) = params.get_b_g2(b_input_density_total, b_aux_density_total)?; - - let b_g2_inputs = multiexp(&worker, b_g2_inputs_source, b_input_density, input_assignment); + let (b_g2_inputs_source, b_g2_aux_source) = + params.get_b_g2(b_input_density_total, b_aux_density_total)?; + + let b_g2_inputs = multiexp( + &worker, + b_g2_inputs_source, + b_input_density, + input_assignment, + ); let b_g2_aux = multiexp(&worker, b_g2_aux_source, b_aux_density, aux_assignment); if vk.delta_g1.is_zero() || vk.delta_g2.is_zero() { @@ -325,6 +346,6 @@ pub fn create_proof>( Ok(Proof { a: g_a.into_affine(), b: g_b.into_affine(), - c: g_c.into_affine() + c: g_c.into_affine(), }) } diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 654b814..4c5874d 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -1,12 +1,13 @@ use ff::{ - Field, LegendreSymbol, PrimeField, PrimeFieldDecodingError, - PrimeFieldRepr, ScalarEngine, SqrtField}; + Field, LegendreSymbol, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine, + SqrtField, +}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use pairing::{Engine, PairingCurveAffine}; +use rand_core::RngCore; use std::cmp::Ordering; use std::fmt; -use rand_core::RngCore; use std::num::Wrapping; const MODULUS_R: Wrapping = Wrapping(64513); @@ -80,9 +81,13 @@ impl SqrtField for Fr { fn legendre(&self) -> LegendreSymbol { // s = self^((r - 1) // 2) let s = self.pow([32256]); - if s == ::zero() { LegendreSymbol::Zero } - else if s == ::one() { LegendreSymbol::QuadraticResidue } - else { LegendreSymbol::QuadraticNonResidue } + if s == ::zero() { + LegendreSymbol::Zero + } else if s == ::one() { + LegendreSymbol::QuadraticResidue + } else { + LegendreSymbol::QuadraticNonResidue + } } fn sqrt(&self) -> Option { @@ -100,7 +105,7 @@ impl SqrtField for Fr { let mut m = Fr::S; while t != ::one() { - let mut i = 1; + let mut i = 1; { let mut t2i = t; t2i.square(); @@ -258,15 +263,18 @@ impl Engine for DummyEngine { type G2Affine = Fr; type Fq = Fr; type Fqe = Fr; - + // TODO: This should be F_645131 or something. Doesn't matter for now. type Fqk = Fr; fn miller_loop<'a, I>(i: I) -> Self::Fqk - where I: IntoIterator::Prepared, - &'a ::Prepared - )> + where + I: IntoIterator< + Item = &'a ( + &'a ::Prepared, + &'a ::Prepared, + ), + >, { let mut acc = ::zero(); @@ -280,8 +288,7 @@ impl Engine for DummyEngine { } /// Perform final exponentiation of the result of a miller loop. - fn final_exponentiation(this: &Self::Fqk) -> Option - { + fn final_exponentiation(this: &Self::Fqk) -> Option { Some(*this) } } @@ -308,9 +315,7 @@ impl CurveProjective for Fr { ::is_zero(self) } - fn batch_normalization(_: &mut [Self]) { - - } + fn batch_normalization(_: &mut [Self]) {} fn is_normalized(&self) -> bool { true @@ -332,8 +337,7 @@ impl CurveProjective for Fr { ::negate(self); } - fn mul_assign::Repr>>(&mut self, other: S) - { + fn mul_assign::Repr>>(&mut self, other: S) { let tmp = Fr::from_repr(other.into()).unwrap(); ::mul_assign(self, &tmp); @@ -415,8 +419,7 @@ impl CurveAffine for Fr { ::negate(self); } - fn mul::Repr>>(&self, other: S) -> Self::Projective - { + fn mul::Repr>>(&self, other: S) -> Self::Projective { let mut res = *self; let tmp = Fr::from_repr(other.into()).unwrap(); diff --git a/bellman/src/groth16/tests/mod.rs b/bellman/src/groth16/tests/mod.rs index 0e05c36..e6a36e4 100644 --- a/bellman/src/groth16/tests/mod.rs +++ b/bellman/src/groth16/tests/mod.rs @@ -6,86 +6,82 @@ use self::dummy_engine::*; use std::marker::PhantomData; -use ::{ - Circuit, - ConstraintSystem, - SynthesisError -}; +use {Circuit, ConstraintSystem, SynthesisError}; -use super::{ - generate_parameters, - prepare_verifying_key, - create_proof, - verify_proof -}; +use super::{create_proof, generate_parameters, prepare_verifying_key, verify_proof}; struct XORDemo { a: Option, b: Option, - _marker: PhantomData + _marker: PhantomData, } impl Circuit for XORDemo { - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { - let a_var = cs.alloc(|| "a", || { - if self.a.is_some() { - if self.a.unwrap() { - Ok(E::Fr::one()) + fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { + let a_var = cs.alloc( + || "a", + || { + if self.a.is_some() { + if self.a.unwrap() { + Ok(E::Fr::one()) + } else { + Ok(E::Fr::zero()) + } } else { - Ok(E::Fr::zero()) + Err(SynthesisError::AssignmentMissing) } - } else { - Err(SynthesisError::AssignmentMissing) - } - })?; + }, + )?; cs.enforce( || "a_boolean_constraint", |lc| lc + CS::one() - a_var, |lc| lc + a_var, - |lc| lc + |lc| lc, ); - let b_var = cs.alloc(|| "b", || { - if self.b.is_some() { - if self.b.unwrap() { - Ok(E::Fr::one()) + let b_var = cs.alloc( + || "b", + || { + if self.b.is_some() { + if self.b.unwrap() { + Ok(E::Fr::one()) + } else { + Ok(E::Fr::zero()) + } } else { - Ok(E::Fr::zero()) + Err(SynthesisError::AssignmentMissing) } - } else { - Err(SynthesisError::AssignmentMissing) - } - })?; + }, + )?; cs.enforce( || "b_boolean_constraint", |lc| lc + CS::one() - b_var, |lc| lc + b_var, - |lc| lc + |lc| lc, ); - let c_var = cs.alloc_input(|| "c", || { - if self.a.is_some() && self.b.is_some() { - if self.a.unwrap() ^ self.b.unwrap() { - Ok(E::Fr::one()) + let c_var = cs.alloc_input( + || "c", + || { + if self.a.is_some() && self.b.is_some() { + if self.a.unwrap() ^ self.b.unwrap() { + Ok(E::Fr::one()) + } else { + Ok(E::Fr::zero()) + } } else { - Ok(E::Fr::zero()) + Err(SynthesisError::AssignmentMissing) } - } else { - Err(SynthesisError::AssignmentMissing) - } - })?; + }, + )?; cs.enforce( || "c_xor_constraint", |lc| lc + a_var + a_var, |lc| lc + b_var, - |lc| lc + a_var + b_var - c_var + |lc| lc + a_var + b_var - c_var, ); Ok(()) @@ -106,19 +102,10 @@ fn test_xordemo() { let c = XORDemo:: { a: None, b: None, - _marker: PhantomData + _marker: PhantomData, }; - generate_parameters( - c, - g1, - g2, - alpha, - beta, - gamma, - delta, - tau - ).unwrap() + generate_parameters(c, g1, g2, alpha, beta, gamma, delta, tau).unwrap() }; // This will synthesize the constraint system: @@ -226,32 +213,35 @@ fn test_xordemo() { 59158 */ - let u_i = [59158, 48317, 21767, 10402].iter().map(|e| { - Fr::from_str(&format!("{}", e)).unwrap() - }).collect::>(); - let v_i = [0, 0, 60619, 30791].iter().map(|e| { - Fr::from_str(&format!("{}", e)).unwrap() - }).collect::>(); - let w_i = [0, 23320, 41193, 41193].iter().map(|e| { - Fr::from_str(&format!("{}", e)).unwrap() - }).collect::>(); + let u_i = [59158, 48317, 21767, 10402] + .iter() + .map(|e| Fr::from_str(&format!("{}", e)).unwrap()) + .collect::>(); + let v_i = [0, 0, 60619, 30791] + .iter() + .map(|e| Fr::from_str(&format!("{}", e)).unwrap()) + .collect::>(); + let w_i = [0, 23320, 41193, 41193] + .iter() + .map(|e| Fr::from_str(&format!("{}", e)).unwrap()) + .collect::>(); - for (u, a) in u_i.iter() - .zip(¶ms.a[..]) - { + for (u, a) in u_i.iter().zip(¶ms.a[..]) { assert_eq!(u, a); } - for (v, b) in v_i.iter() - .filter(|&&e| e != Fr::zero()) - .zip(¶ms.b_g1[..]) + for (v, b) in v_i + .iter() + .filter(|&&e| e != Fr::zero()) + .zip(¶ms.b_g1[..]) { assert_eq!(v, b); } - for (v, b) in v_i.iter() - .filter(|&&e| e != Fr::zero()) - .zip(¶ms.b_g2[..]) + for (v, b) in v_i + .iter() + .filter(|&&e| e != Fr::zero()) + .zip(¶ms.b_g2[..]) { assert_eq!(v, b); } @@ -296,15 +286,10 @@ fn test_xordemo() { let c = XORDemo { a: Some(true), b: Some(false), - _marker: PhantomData + _marker: PhantomData, }; - create_proof( - c, - ¶ms, - r, - s - ).unwrap() + create_proof(c, ¶ms, r, s).unwrap() }; // A(x) = @@ -320,7 +305,7 @@ fn test_xordemo() { expected_a.add_assign(&u_i[0]); // a_0 = 1 expected_a.add_assign(&u_i[1]); // a_1 = 1 expected_a.add_assign(&u_i[2]); // a_2 = 1 - // a_3 = 0 + // a_3 = 0 assert_eq!(proof.a, expected_a); } @@ -337,7 +322,7 @@ fn test_xordemo() { expected_b.add_assign(&v_i[0]); // a_0 = 1 expected_b.add_assign(&v_i[1]); // a_1 = 1 expected_b.add_assign(&v_i[2]); // a_2 = 1 - // a_3 = 0 + // a_3 = 0 assert_eq!(proof.b, expected_b); } @@ -378,7 +363,10 @@ fn test_xordemo() { expected_c.add_assign(¶ms.l[0]); // H query answer - for (i, coeff) in [5040, 11763, 10755, 63633, 128, 9747, 8739].iter().enumerate() { + for (i, coeff) in [5040, 11763, 10755, 63633, 128, 9747, 8739] + .iter() + .enumerate() + { let coeff = Fr::from_str(&format!("{}", coeff)).unwrap(); let mut tmp = params.h[i]; @@ -389,9 +377,5 @@ fn test_xordemo() { assert_eq!(expected_c, proof.c); } - assert!(verify_proof( - &pvk, - &proof, - &[Fr::one()] - ).unwrap()); + assert!(verify_proof(&pvk, &proof, &[Fr::one()]).unwrap()); } diff --git a/bellman/src/groth16/verifier.rs b/bellman/src/groth16/verifier.rs index 71c7478..926955a 100644 --- a/bellman/src/groth16/verifier.rs +++ b/bellman/src/groth16/verifier.rs @@ -2,20 +2,11 @@ use ff::PrimeField; use group::{CurveAffine, CurveProjective}; use pairing::{Engine, PairingCurveAffine}; -use super::{ - Proof, - VerifyingKey, - PreparedVerifyingKey -}; +use super::{PreparedVerifyingKey, Proof, VerifyingKey}; -use ::{ - SynthesisError -}; +use SynthesisError; -pub fn prepare_verifying_key( - vk: &VerifyingKey -) -> PreparedVerifyingKey -{ +pub fn prepare_verifying_key(vk: &VerifyingKey) -> PreparedVerifyingKey { let mut gamma = vk.gamma_g2; gamma.negate(); let mut delta = vk.delta_g2; @@ -25,16 +16,15 @@ pub fn prepare_verifying_key( alpha_g1_beta_g2: E::pairing(vk.alpha_g1, vk.beta_g2), neg_gamma_g2: gamma.prepare(), neg_delta_g2: delta.prepare(), - ic: vk.ic.clone() + ic: vk.ic.clone(), } } pub fn verify_proof<'a, E: Engine>( pvk: &'a PreparedVerifyingKey, proof: &Proof, - public_inputs: &[E::Fr] -) -> Result -{ + public_inputs: &[E::Fr], +) -> Result { if (public_inputs.len() + 1) != pvk.ic.len() { return Err(SynthesisError::MalformedVerifyingKey); } @@ -53,11 +43,14 @@ pub fn verify_proof<'a, E: Engine>( // A * B + inputs * (-gamma) + C * (-delta) = alpha * beta // which allows us to do a single final exponentiation. - Ok(E::final_exponentiation( - &E::miller_loop([ + Ok(E::final_exponentiation(&E::miller_loop( + [ (&proof.a.prepare(), &proof.b.prepare()), (&acc.into_affine().prepare(), &pvk.neg_gamma_g2), - (&proof.c.prepare(), &pvk.neg_delta_g2) - ].into_iter()) - ).unwrap() == pvk.alpha_g1_beta_g2) + (&proof.c.prepare(), &pvk.neg_delta_g2), + ] + .into_iter(), + )) + .unwrap() + == pvk.alpha_g1_beta_g2) } diff --git a/bellman/src/lib.rs b/bellman/src/lib.rs index ee6bb88..96400c9 100644 --- a/bellman/src/lib.rs +++ b/bellman/src/lib.rs @@ -4,10 +4,10 @@ extern crate group; extern crate pairing; extern crate rand_core; -extern crate futures; extern crate bit_vec; extern crate blake2s_simd; extern crate byteorder; +extern crate futures; #[cfg(feature = "multicore")] extern crate crossbeam; @@ -29,20 +29,20 @@ extern crate rand_xorshift; #[cfg(test)] extern crate sha2; -pub mod gadgets; -pub mod multicore; -mod multiexp; pub mod domain; +pub mod gadgets; #[cfg(feature = "groth16")] pub mod groth16; +pub mod multicore; +mod multiexp; use ff::{Field, ScalarEngine}; -use std::ops::{Add, Sub}; -use std::fmt; use std::error::Error; +use std::fmt; use std::io; use std::marker::PhantomData; +use std::ops::{Add, Sub}; /// Computations are expressed in terms of arithmetic circuits, in particular /// rank-1 quadratic constraint systems. The `Circuit` trait represents a @@ -50,10 +50,7 @@ use std::marker::PhantomData; /// CRS generation and during proving. pub trait Circuit { /// Synthesize the circuit into a rank-1 quadratic constraint system - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError>; + fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError>; } /// Represents a variable in our constraint system. @@ -79,7 +76,7 @@ impl Variable { #[derive(Copy, Clone, PartialEq, Debug)] pub enum Index { Input(usize), - Aux(usize) + Aux(usize), } /// This represents a linear combination of some variables, with coefficients @@ -206,7 +203,7 @@ pub enum SynthesisError { /// During verification, our verifying key was malformed. MalformedVerifyingKey, /// During CRS generation, we observed an unconstrained auxiliary variable - UnconstrainedVariable + UnconstrainedVariable, } impl From for SynthesisError { @@ -218,14 +215,16 @@ impl From for SynthesisError { impl Error for SynthesisError { fn description(&self) -> &str { match *self { - SynthesisError::AssignmentMissing => "an assignment for a variable could not be computed", + SynthesisError::AssignmentMissing => { + "an assignment for a variable could not be computed" + } SynthesisError::DivisionByZero => "division by zero", SynthesisError::Unsatisfiable => "unsatisfiable constraint system", SynthesisError::PolynomialDegreeTooLarge => "polynomial degree is too large", SynthesisError::UnexpectedIdentity => "encountered an identity element in the CRS", SynthesisError::IoError(_) => "encountered an I/O error", SynthesisError::MalformedVerifyingKey => "malformed verifying key", - SynthesisError::UnconstrainedVariable => "auxiliary variable was unconstrained" + SynthesisError::UnconstrainedVariable => "auxiliary variable was unconstrained", } } } @@ -257,40 +256,36 @@ pub trait ConstraintSystem: Sized { /// determine the assignment of the variable. The given `annotation` function is invoked /// in testing contexts in order to derive a unique name for this variable in the current /// namespace. - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into; + fn alloc(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into; /// Allocate a public variable in the constraint system. The provided function is used to /// determine the assignment of the variable. - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into; + fn alloc_input(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into; /// Enforce that `A` * `B` = `C`. The `annotation` function is invoked in testing contexts /// in order to derive a unique name for the constraint in the current namespace. - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination; + fn enforce(&mut self, annotation: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination; /// Create a new (sub)namespace and enter into it. Not intended /// for downstream use; use `namespace` instead. fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR; + where + NR: Into, + N: FnOnce() -> NR; /// Exit out of the existing namespace. Not intended for /// downstream use; use `namespace` instead. @@ -301,11 +296,10 @@ pub trait ConstraintSystem: Sized { fn get_root(&mut self) -> &mut Self::Root; /// Begin a namespace for this constraint system. - fn namespace<'a, NR, N>( - &'a mut self, - name_fn: N - ) -> Namespace<'a, E, Self::Root> - where NR: Into, N: FnOnce() -> NR + fn namespace<'a, NR, N>(&'a mut self, name_fn: N) -> Namespace<'a, E, Self::Root> + where + NR: Into, + N: FnOnce() -> NR, { self.get_root().push_namespace(name_fn); @@ -324,37 +318,31 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem> ConstraintSystem for Name CS::one() } - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.0.alloc(annotation, f) } - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.0.alloc_input(annotation, f) } - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, annotation: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { self.0.enforce(annotation, a, b, c) } @@ -364,18 +352,18 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem> ConstraintSystem for Name // never a root constraint system. fn push_namespace(&mut self, _: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { panic!("only the root's push_namespace should be called"); } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { panic!("only the root's pop_namespace should be called"); } - fn get_root(&mut self) -> &mut Self::Root - { + fn get_root(&mut self) -> &mut Self::Root { self.0.get_root() } } @@ -395,54 +383,48 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem> ConstraintSystem for &'cs CS::one() } - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { (**self).alloc(annotation, f) } - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { (**self).alloc_input(annotation, f) } - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, annotation: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { (**self).enforce(annotation, a, b, c) } fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { (**self).push_namespace(name_fn) } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { (**self).pop_namespace() } - fn get_root(&mut self) -> &mut Self::Root - { + fn get_root(&mut self) -> &mut Self::Root { (**self).get_root() } } diff --git a/bellman/src/multicore.rs b/bellman/src/multicore.rs index 8d0b00c..e8b2dae 100644 --- a/bellman/src/multicore.rs +++ b/bellman/src/multicore.rs @@ -6,15 +6,15 @@ #[cfg(feature = "multicore")] mod implementation { - use num_cpus; - use futures::{Future, IntoFuture, Poll}; - use futures_cpupool::{CpuPool, CpuFuture}; use crossbeam::{self, Scope}; + use futures::{Future, IntoFuture, Poll}; + use futures_cpupool::{CpuFuture, CpuPool}; + use num_cpus; #[derive(Clone)] pub struct Worker { cpus: usize, - pool: CpuPool + pool: CpuPool, } impl Worker { @@ -24,7 +24,7 @@ mod implementation { pub(crate) fn new_with_cpus(cpus: usize) -> Worker { Worker { cpus: cpus, - pool: CpuPool::new(cpus) + pool: CpuPool::new(cpus), } } @@ -36,26 +36,22 @@ mod implementation { log2_floor(self.cpus) } - pub fn compute( - &self, f: F - ) -> WorkerFuture - where F: FnOnce() -> R + Send + 'static, - R: IntoFuture + 'static, - R::Future: Send + 'static, - R::Item: Send + 'static, - R::Error: Send + 'static + pub fn compute(&self, f: F) -> WorkerFuture + where + F: FnOnce() -> R + Send + 'static, + R: IntoFuture + 'static, + R::Future: Send + 'static, + R::Item: Send + 'static, + R::Error: Send + 'static, { WorkerFuture { - future: self.pool.spawn_fn(f) + future: self.pool.spawn_fn(f), } } - pub fn scope<'a, F, R>( - &self, - elements: usize, - f: F - ) -> R - where F: FnOnce(&Scope<'a>, usize) -> R + pub fn scope<'a, F, R>(&self, elements: usize, f: F) -> R + where + F: FnOnce(&Scope<'a>, usize) -> R, { let chunk_size = if elements < self.cpus { 1 @@ -63,22 +59,19 @@ mod implementation { elements / self.cpus }; - crossbeam::scope(|scope| { - f(scope, chunk_size) - }) + crossbeam::scope(|scope| f(scope, chunk_size)) } } pub struct WorkerFuture { - future: CpuFuture + future: CpuFuture, } impl Future for WorkerFuture { type Item = T; type Error = E; - fn poll(&mut self) -> Poll - { + fn poll(&mut self) -> Poll { self.future.poll() } } @@ -88,7 +81,7 @@ mod implementation { let mut pow = 0; - while (1 << (pow+1)) <= num { + while (1 << (pow + 1)) <= num { pow += 1; } diff --git a/bellman/src/multiexp.rs b/bellman/src/multiexp.rs index c655397..fabb978 100644 --- a/bellman/src/multiexp.rs +++ b/bellman/src/multiexp.rs @@ -1,11 +1,11 @@ -use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; -use group::{CurveAffine, CurveProjective}; -use std::sync::Arc; -use std::io; -use bit_vec::{self, BitVec}; -use std::iter; -use futures::{Future}; use super::multicore::Worker; +use bit_vec::{self, BitVec}; +use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; +use futures::Future; +use group::{CurveAffine, CurveProjective}; +use std::io; +use std::iter; +use std::sync::Arc; use super::SynthesisError; @@ -19,7 +19,10 @@ pub trait SourceBuilder: Send + Sync + 'static + Clone { /// A source of bases, like an iterator. pub trait Source { /// Parses the element from the source. Fails if the point is at infinity. - fn add_assign_mixed(&mut self, to: &mut ::Projective) -> Result<(), SynthesisError>; + fn add_assign_mixed( + &mut self, + to: &mut ::Projective, + ) -> Result<(), SynthesisError>; /// Skips `amt` elements from the source, avoiding deserialization. fn skip(&mut self, amt: usize) -> Result<(), SynthesisError>; @@ -34,13 +37,20 @@ impl SourceBuilder for (Arc>, usize) { } impl Source for (Arc>, usize) { - fn add_assign_mixed(&mut self, to: &mut ::Projective) -> Result<(), SynthesisError> { + fn add_assign_mixed( + &mut self, + to: &mut ::Projective, + ) -> Result<(), SynthesisError> { if self.0.len() <= self.1 { - return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into()); + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + "expected more bases from source", + ) + .into()); } if self.0[self.1].is_zero() { - return Err(SynthesisError::UnexpectedIdentity) + return Err(SynthesisError::UnexpectedIdentity); } to.add_assign_mixed(&self.0[self.1]); @@ -52,7 +62,11 @@ impl Source for (Arc>, usize) { fn skip(&mut self, amt: usize) -> Result<(), SynthesisError> { if self.0.len() <= self.1 { - return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into()); + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + "expected more bases from source", + ) + .into()); } self.1 += amt; @@ -63,7 +77,7 @@ impl Source for (Arc>, usize) { pub trait QueryDensity { /// Returns whether the base exists. - type Iter: Iterator; + type Iter: Iterator; fn iter(self) -> Self::Iter; fn get_query_size(self) -> Option; @@ -92,7 +106,7 @@ impl<'a> QueryDensity for &'a FullDensity { pub struct DensityTracker { bv: BitVec, - total_density: usize + total_density: usize, } impl<'a> QueryDensity for &'a DensityTracker { @@ -111,7 +125,7 @@ impl DensityTracker { pub fn new() -> DensityTracker { DensityTracker { bv: BitVec::new(), - total_density: 0 + total_density: 0, } } @@ -138,12 +152,13 @@ fn multiexp_inner( exponents: Arc::Fr as PrimeField>::Repr>>, mut skip: u32, c: u32, - handle_trivial: bool -) -> Box::Projective, Error=SynthesisError>> - where for<'a> &'a Q: QueryDensity, - D: Send + Sync + 'static + Clone + AsRef, - G: CurveAffine, - S: SourceBuilder + handle_trivial: bool, +) -> Box::Projective, Error = SynthesisError>> +where + for<'a> &'a Q: QueryDensity, + D: Send + Sync + 'static + Clone + AsRef, + G: CurveAffine, + S: SourceBuilder, { // Perform this region of the multiexp let this = { @@ -212,16 +227,24 @@ fn multiexp_inner( // There's another region more significant. Calculate and join it with // this region recursively. Box::new( - this.join(multiexp_inner(pool, bases, density_map, exponents, skip, c, false)) - .map(move |(this, mut higher)| { - for _ in 0..c { - higher.double(); - } + this.join(multiexp_inner( + pool, + bases, + density_map, + exponents, + skip, + c, + false, + )) + .map(move |(this, mut higher)| { + for _ in 0..c { + higher.double(); + } - higher.add_assign(&this); + higher.add_assign(&this); - higher - }) + higher + }), ) } } @@ -232,12 +255,13 @@ pub fn multiexp( pool: &Worker, bases: S, density_map: D, - exponents: Arc::Fr as PrimeField>::Repr>> -) -> Box::Projective, Error=SynthesisError>> - where for<'a> &'a Q: QueryDensity, - D: Send + Sync + 'static + Clone + AsRef, - G: CurveAffine, - S: SourceBuilder + exponents: Arc::Fr as PrimeField>::Repr>>, +) -> Box::Projective, Error = SynthesisError>> +where + for<'a> &'a Q: QueryDensity, + D: Send + Sync + 'static + Clone + AsRef, + G: CurveAffine, + S: SourceBuilder, { let c = if exponents.len() < 32 { 3u32 @@ -260,9 +284,8 @@ pub fn multiexp( fn test_with_bls12() { fn naive_multiexp( bases: Arc>, - exponents: Arc::Repr>> - ) -> G::Projective - { + exponents: Arc::Repr>>, + ) -> G::Projective { assert_eq!(bases.len(), exponents.len()); let mut acc = G::Projective::zero(); @@ -274,25 +297,28 @@ fn test_with_bls12() { acc } - use rand; use pairing::{bls12_381::Bls12, Engine}; + use rand; const SAMPLES: usize = 1 << 14; let rng = &mut rand::thread_rng(); - let v = Arc::new((0..SAMPLES).map(|_| ::Fr::random(rng).into_repr()).collect::>()); - let g = Arc::new((0..SAMPLES).map(|_| ::G1::random(rng).into_affine()).collect::>()); + let v = Arc::new( + (0..SAMPLES) + .map(|_| ::Fr::random(rng).into_repr()) + .collect::>(), + ); + let g = Arc::new( + (0..SAMPLES) + .map(|_| ::G1::random(rng).into_affine()) + .collect::>(), + ); let naive = naive_multiexp(g.clone(), v.clone()); let pool = Worker::new(); - let fast = multiexp( - &pool, - (g, 0), - FullDensity, - v - ).wait().unwrap(); + let fast = multiexp(&pool, (g, 0), FullDensity, v).wait().unwrap(); assert_eq!(naive, fast); } diff --git a/bellman/tests/mimc.rs b/bellman/tests/mimc.rs index d08940f..18aaece 100644 --- a/bellman/tests/mimc.rs +++ b/bellman/tests/mimc.rs @@ -14,31 +14,21 @@ use ff::{Field, ScalarEngine}; use pairing::Engine; // We're going to use the BLS12-381 pairing-friendly elliptic curve. -use pairing::bls12_381::{ - Bls12 -}; +use pairing::bls12_381::Bls12; // We'll use these interfaces to construct our circuit. -use bellman::{ - Circuit, - ConstraintSystem, - SynthesisError -}; +use bellman::{Circuit, ConstraintSystem, SynthesisError}; // We're going to use the Groth16 proving system. use bellman::groth16::{ - Proof, - generate_random_parameters, - prepare_verifying_key, - create_random_proof, - verify_proof, + create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof, Proof, }; const MIMC_ROUNDS: usize = 322; /// This is an implementation of MiMC, specifically a /// variant named `LongsightF322p3` for BLS12-381. -/// See http://eprint.iacr.org/2016/492 for more +/// See http://eprint.iacr.org/2016/492 for more /// information about this construction. /// /// ``` @@ -49,12 +39,7 @@ const MIMC_ROUNDS: usize = 322; /// return xL /// } /// ``` -fn mimc( - mut xl: E::Fr, - mut xr: E::Fr, - constants: &[E::Fr] -) -> E::Fr -{ +fn mimc(mut xl: E::Fr, mut xr: E::Fr, constants: &[E::Fr]) -> E::Fr { assert_eq!(constants.len(), MIMC_ROUNDS); for i in 0..MIMC_ROUNDS { @@ -76,31 +61,29 @@ fn mimc( struct MiMCDemo<'a, E: Engine> { xl: Option, xr: Option, - constants: &'a [E::Fr] + constants: &'a [E::Fr], } /// Our demo circuit implements this `Circuit` trait which /// is used during paramgen and proving in order to /// synthesize the constraint system. impl<'a, E: Engine> Circuit for MiMCDemo<'a, E> { - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { + fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { assert_eq!(self.constants.len(), MIMC_ROUNDS); // Allocate the first component of the preimage. let mut xl_value = self.xl; - let mut xl = cs.alloc(|| "preimage xl", || { - xl_value.ok_or(SynthesisError::AssignmentMissing) - })?; + let mut xl = cs.alloc( + || "preimage xl", + || xl_value.ok_or(SynthesisError::AssignmentMissing), + )?; // Allocate the second component of the preimage. let mut xr_value = self.xr; - let mut xr = cs.alloc(|| "preimage xr", || { - xr_value.ok_or(SynthesisError::AssignmentMissing) - })?; + let mut xr = cs.alloc( + || "preimage xr", + || xr_value.ok_or(SynthesisError::AssignmentMissing), + )?; for i in 0..MIMC_ROUNDS { // xL, xR := xR + (xL + Ci)^3, xL @@ -112,15 +95,16 @@ impl<'a, E: Engine> Circuit for MiMCDemo<'a, E> { e.square(); e }); - let mut tmp = cs.alloc(|| "tmp", || { - tmp_value.ok_or(SynthesisError::AssignmentMissing) - })?; + let mut tmp = cs.alloc( + || "tmp", + || tmp_value.ok_or(SynthesisError::AssignmentMissing), + )?; cs.enforce( || "tmp = (xL + Ci)^2", |lc| lc + xl + (self.constants[i], CS::one()), |lc| lc + xl + (self.constants[i], CS::one()), - |lc| lc + tmp + |lc| lc + tmp, ); // new_xL = xR + (xL + Ci)^3 @@ -133,23 +117,25 @@ impl<'a, E: Engine> Circuit for MiMCDemo<'a, E> { e }); - let mut new_xl = if i == (MIMC_ROUNDS-1) { + let mut new_xl = if i == (MIMC_ROUNDS - 1) { // This is the last round, xL is our image and so // we allocate a public input. - cs.alloc_input(|| "image", || { - new_xl_value.ok_or(SynthesisError::AssignmentMissing) - })? + cs.alloc_input( + || "image", + || new_xl_value.ok_or(SynthesisError::AssignmentMissing), + )? } else { - cs.alloc(|| "new_xl", || { - new_xl_value.ok_or(SynthesisError::AssignmentMissing) - })? + cs.alloc( + || "new_xl", + || new_xl_value.ok_or(SynthesisError::AssignmentMissing), + )? }; cs.enforce( || "new_xL = xR + (xL + Ci)^3", |lc| lc + tmp, |lc| lc + xl + (self.constants[i], CS::one()), - |lc| lc + new_xl - xr + |lc| lc + new_xl - xr, ); // xR = xL @@ -172,7 +158,9 @@ fn test_mimc() { let rng = &mut thread_rng(); // Generate the MiMC round constants - let constants = (0..MIMC_ROUNDS).map(|_| ::Fr::random(rng)).collect::>(); + let constants = (0..MIMC_ROUNDS) + .map(|_| ::Fr::random(rng)) + .collect::>(); println!("Creating parameters..."); @@ -181,7 +169,7 @@ fn test_mimc() { let c = MiMCDemo:: { xl: None, xr: None, - constants: &constants + constants: &constants, }; generate_random_parameters(c, rng).unwrap() @@ -216,7 +204,7 @@ fn test_mimc() { let c = MiMCDemo { xl: Some(xl), xr: Some(xr), - constants: &constants + constants: &constants, }; // Create a groth16 proof with our parameters. @@ -230,20 +218,16 @@ fn test_mimc() { let start = Instant::now(); let proof = Proof::read(&proof_vec[..]).unwrap(); // Check the proof - assert!(verify_proof( - &pvk, - &proof, - &[image] - ).unwrap()); + assert!(verify_proof(&pvk, &proof, &[image]).unwrap()); total_verifying += start.elapsed(); } let proving_avg = total_proving / SAMPLES; - let proving_avg = proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 - + (proving_avg.as_secs() as f64); + let proving_avg = + proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (proving_avg.as_secs() as f64); let verifying_avg = total_verifying / SAMPLES; - let verifying_avg = verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 - + (verifying_avg.as_secs() as f64); + let verifying_avg = + verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (verifying_avg.as_secs() as f64); println!("Average proving time: {:?} seconds", proving_avg); println!("Average verifying time: {:?} seconds", verifying_avg); From 81c58172c30678fc0aa86b0ef747ca6cc8412e18 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Thu, 15 Aug 2019 10:39:55 -0600 Subject: [PATCH 075/330] cargo fmt zcash_primitives --- zcash_primitives/benches/pedersen_hash.rs | 12 +- zcash_primitives/src/constants.rs | 28 +- zcash_primitives/src/group_hash.rs | 19 +- zcash_primitives/src/jubjub/edwards.rs | 125 ++-- zcash_primitives/src/jubjub/fs.rs | 560 ++++++++++++++---- zcash_primitives/src/jubjub/mod.rs | 139 +++-- zcash_primitives/src/jubjub/montgomery.rs | 87 +-- zcash_primitives/src/jubjub/tests.rs | 49 +- zcash_primitives/src/keys.rs | 6 +- zcash_primitives/src/note_encryption.rs | 22 +- zcash_primitives/src/pedersen_hash.rs | 22 +- zcash_primitives/src/primitives.rs | 168 +++--- zcash_primitives/src/prover.rs | 2 +- zcash_primitives/src/redjubjub.rs | 48 +- zcash_primitives/src/sapling.rs | 6 +- zcash_primitives/src/transaction/builder.rs | 6 +- .../src/transaction/components.rs | 2 +- zcash_primitives/src/zip32.rs | 5 +- 18 files changed, 786 insertions(+), 520 deletions(-) diff --git a/zcash_primitives/benches/pedersen_hash.rs b/zcash_primitives/benches/pedersen_hash.rs index a8f944e..b647740 100644 --- a/zcash_primitives/benches/pedersen_hash.rs +++ b/zcash_primitives/benches/pedersen_hash.rs @@ -1,14 +1,14 @@ #![feature(test)] +extern crate pairing; extern crate rand_core; extern crate rand_os; extern crate test; -extern crate pairing; extern crate zcash_primitives; +use pairing::bls12_381::Bls12; use rand_core::RngCore; use rand_os::OsRng; -use pairing::bls12_381::Bls12; use zcash_primitives::jubjub::JubjubBls12; use zcash_primitives::pedersen_hash::{pedersen_hash, Personalization}; @@ -16,10 +16,10 @@ use zcash_primitives::pedersen_hash::{pedersen_hash, Personalization}; fn bench_pedersen_hash(b: &mut test::Bencher) { let params = JubjubBls12::new(); let rng = &mut OsRng; - let bits = (0..510).map(|_| (rng.next_u32() % 2) != 0).collect::>(); + let bits = (0..510) + .map(|_| (rng.next_u32() % 2) != 0) + .collect::>(); let personalization = Personalization::MerkleTree(31); - b.iter(|| { - pedersen_hash::(personalization, bits.clone(), ¶ms) - }); + b.iter(|| pedersen_hash::(personalization, bits.clone(), ¶ms)); } diff --git a/zcash_primitives/src/constants.rs b/zcash_primitives/src/constants.rs index dfdd36f..c21184d 100644 --- a/zcash_primitives/src/constants.rs +++ b/zcash_primitives/src/constants.rs @@ -2,39 +2,31 @@ /// This is chosen to be some random string that we couldn't have anticipated when we designed /// the algorithm, for rigidity purposes. /// We deliberately use an ASCII hex string of 32 bytes here. -pub const GH_FIRST_BLOCK: &'static [u8; 64] - = b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0"; +pub const GH_FIRST_BLOCK: &'static [u8; 64] = + b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0"; // BLAKE2s invocation personalizations /// BLAKE2s Personalization for CRH^ivk = BLAKE2s(ak | nk) -pub const CRH_IVK_PERSONALIZATION: &'static [u8; 8] - = b"Zcashivk"; +pub const CRH_IVK_PERSONALIZATION: &'static [u8; 8] = b"Zcashivk"; /// BLAKE2s Personalization for PRF^nf = BLAKE2s(nk | rho) -pub const PRF_NF_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_nf"; +pub const PRF_NF_PERSONALIZATION: &'static [u8; 8] = b"Zcash_nf"; // Group hash personalizations /// BLAKE2s Personalization for Pedersen hash generators. -pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_PH"; +pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8] = b"Zcash_PH"; /// BLAKE2s Personalization for the group hash for key diversification -pub const KEY_DIVERSIFICATION_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_gd"; +pub const KEY_DIVERSIFICATION_PERSONALIZATION: &'static [u8; 8] = b"Zcash_gd"; /// BLAKE2s Personalization for the spending key base point -pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_G_"; +pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_G_"; /// BLAKE2s Personalization for the proof generation key base point -pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_H_"; +pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_H_"; /// BLAKE2s Personalization for the value commitment generator for the value -pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_cv"; +pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_cv"; /// BLAKE2s Personalization for the nullifier position generator (for computing rho) -pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_J_"; +pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_J_"; diff --git a/zcash_primitives/src/group_hash.rs b/zcash_primitives/src/group_hash.rs index 7369e04..dec59cd 100644 --- a/zcash_primitives/src/group_hash.rs +++ b/zcash_primitives/src/group_hash.rs @@ -1,12 +1,6 @@ -use jubjub::{ - JubjubEngine, - PrimeOrder, - edwards -}; +use jubjub::{edwards, JubjubEngine, PrimeOrder}; -use ff::{ - PrimeField -}; +use ff::PrimeField; use blake2s_simd::Params; use constants; @@ -17,9 +11,8 @@ use constants; pub fn group_hash( tag: &[u8], personalization: &[u8], - params: &E::Params -) -> Option> -{ + params: &E::Params, +) -> Option> { assert_eq!(personalization.len(), 8); // Check to see that scalar field is 255 bits @@ -42,7 +35,7 @@ pub fn group_hash( } else { None } - }, - Err(_) => None + } + Err(_) => None, } } diff --git a/zcash_primitives/src/jubjub/edwards.rs b/zcash_primitives/src/jubjub/edwards.rs index e912aca..b3cdd64 100644 --- a/zcash_primitives/src/jubjub/edwards.rs +++ b/zcash_primitives/src/jubjub/edwards.rs @@ -1,22 +1,12 @@ use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; -use super::{ - JubjubEngine, - JubjubParams, - Unknown, - PrimeOrder, - montgomery -}; +use super::{montgomery, JubjubEngine, JubjubParams, PrimeOrder, Unknown}; use rand_core::RngCore; use std::marker::PhantomData; -use std::io::{ - self, - Write, - Read -}; +use std::io::{self, Read, Write}; // Represents the affine point (X/Z, Y/Z) via the extended // twisted Edwards coordinates. @@ -29,46 +19,38 @@ pub struct Point { y: E::Fr, t: E::Fr, z: E::Fr, - _marker: PhantomData + _marker: PhantomData, } -fn convert_subgroup(from: &Point) -> Point -{ +fn convert_subgroup(from: &Point) -> Point { Point { x: from.x, y: from.y, t: from.t, z: from.z, - _marker: PhantomData + _marker: PhantomData, } } -impl From<&Point> for Point -{ - fn from(p: &Point) -> Point - { +impl From<&Point> for Point { + fn from(p: &Point) -> Point { p.clone() } } -impl From> for Point -{ - fn from(p: Point) -> Point - { +impl From> for Point { + fn from(p: Point) -> Point { convert_subgroup(&p) } } -impl From<&Point> for Point -{ - fn from(p: &Point) -> Point - { +impl From<&Point> for Point { + fn from(p: &Point) -> Point { convert_subgroup(p) } } -impl Clone for Point -{ +impl Clone for Point { fn clone(&self) -> Self { convert_subgroup(self) } @@ -99,11 +81,7 @@ impl PartialEq for Point { } impl Point { - pub fn read( - reader: R, - params: &E::Params - ) -> io::Result - { + pub fn read(reader: R, params: &E::Params) -> io::Result { let mut y_repr = ::Repr::default(); y_repr.read_le(reader)?; @@ -111,22 +89,18 @@ impl Point { y_repr.as_mut()[3] &= 0x7fffffffffffffff; match E::Fr::from_repr(y_repr) { - Ok(y) => { - match Self::get_for_y(y, x_sign, params) { - Some(p) => Ok(p), - None => { - Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve")) - } - } + Ok(y) => match Self::get_for_y(y, x_sign, params) { + Some(p) => Ok(p), + None => Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve")), }, - Err(_) => { - Err(io::Error::new(io::ErrorKind::InvalidInput, "y is not in field")) - } + Err(_) => Err(io::Error::new( + io::ErrorKind::InvalidInput, + "y is not in field", + )), } } - pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> Option - { + pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> Option { // Given a y on the curve, x^2 = (y^2 - 1) / (dy^2 + 1) // This is defined for all valid y-coordinates, // as dy^2 + 1 = 0 has no solution in Fr. @@ -162,29 +136,25 @@ impl Point { y: y, t: t, z: E::Fr::one(), - _marker: PhantomData + _marker: PhantomData, }) - }, - None => None + } + None => None, } - }, - None => None + } + None => None, } } /// This guarantees the point is in the prime order subgroup #[must_use] - pub fn mul_by_cofactor(&self, params: &E::Params) -> Point - { - let tmp = self.double(params) - .double(params) - .double(params); + pub fn mul_by_cofactor(&self, params: &E::Params) -> Point { + let tmp = self.double(params).double(params).double(params); convert_subgroup(&tmp) } - pub fn rand(rng: &mut R, params: &E::Params) -> Self - { + pub fn rand(rng: &mut R, params: &E::Params) -> Self { loop { let y = E::Fr::random(rng); let sign = rng.next_u32() % 2 != 0; @@ -197,11 +167,7 @@ impl Point { } impl Point { - pub fn write( - &self, - writer: W - ) -> io::Result<()> - { + pub fn write(&self, writer: W) -> io::Result<()> { let (x, y) = self.into_xy(); assert_eq!(E::Fr::NUM_BITS, 255); @@ -216,16 +182,12 @@ impl Point { } /// Convert from a Montgomery point - pub fn from_montgomery( - m: &montgomery::Point, - params: &E::Params - ) -> Self - { + pub fn from_montgomery(m: &montgomery::Point, params: &E::Params) -> Self { match m.into_xy() { None => { // Map the point at infinity to the neutral element. Point::zero() - }, + } Some((x, y)) => { // The map from a Montgomery curve is defined as: // (x, y) -> (u, v) where @@ -258,7 +220,7 @@ impl Point { y: neg1, t: E::Fr::zero(), z: E::Fr::one(), - _marker: PhantomData + _marker: PhantomData, } } else { // Otherwise, as stated above, the mapping is still @@ -317,7 +279,7 @@ impl Point { y: v, t: t, z: z, - _marker: PhantomData + _marker: PhantomData, } } } @@ -340,12 +302,11 @@ impl Point { y: E::Fr::one(), t: E::Fr::zero(), z: E::Fr::one(), - _marker: PhantomData + _marker: PhantomData, } } - pub fn into_xy(&self) -> (E::Fr, E::Fr) - { + pub fn into_xy(&self) -> (E::Fr, E::Fr) { let zinv = self.z.inverse().unwrap(); let mut x = self.x; @@ -432,13 +393,12 @@ impl Point { y: y3, t: t3, z: z3, - _marker: PhantomData + _marker: PhantomData, } } #[must_use] - pub fn add(&self, other: &Self, params: &E::Params) -> Self - { + pub fn add(&self, other: &Self, params: &E::Params) -> Self { // See "Twisted Edwards Curves Revisited" // Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson // 3.1 Unified Addition in E^e @@ -505,17 +465,12 @@ impl Point { y: y3, t: t3, z: z3, - _marker: PhantomData + _marker: PhantomData, } } #[must_use] - pub fn mul::Repr>>( - &self, - scalar: S, - params: &E::Params - ) -> Self - { + pub fn mul::Repr>>(&self, scalar: S, params: &E::Params) -> Self { // Standard double-and-add scalar multiplication let mut res = Self::zero(); diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index baa16ef..768bd83 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -9,7 +9,12 @@ use rand_core::RngCore; use super::ToUniform; // s = 6554484396890773809930967563523245729705921265872317281365359162392183254199 -const MODULUS: FsRepr = FsRepr([0xd0970e5ed6f72cb7, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9]); +const MODULUS: FsRepr = FsRepr([ + 0xd0970e5ed6f72cb7, + 0xa6682093ccc81082, + 0x6673b0101343b00, + 0xe7db4ea6533afa9, +]); // The number of bits needed to represent the modulus. const MODULUS_BITS: u32 = 252; @@ -19,32 +24,56 @@ const MODULUS_BITS: u32 = 252; const REPR_SHAVE_BITS: u32 = 4; // R = 2**256 % s -const R: FsRepr = FsRepr([0x25f80bb3b99607d9, 0xf315d62f66b6e750, 0x932514eeeb8814f4, 0x9a6fc6f479155c6]); +const R: FsRepr = FsRepr([ + 0x25f80bb3b99607d9, + 0xf315d62f66b6e750, + 0x932514eeeb8814f4, + 0x9a6fc6f479155c6, +]); // R2 = R^2 % s -const R2: FsRepr = FsRepr([0x67719aa495e57731, 0x51b0cef09ce3fc26, 0x69dab7fac026e9a5, 0x4f6547b8d127688]); +const R2: FsRepr = FsRepr([ + 0x67719aa495e57731, + 0x51b0cef09ce3fc26, + 0x69dab7fac026e9a5, + 0x4f6547b8d127688, +]); // INV = -(s^{-1} mod 2^64) mod s const INV: u64 = 0x1ba3a358ef788ef9; // GENERATOR = 6 (multiplicative generator of r-1 order, that is also quadratic nonresidue) -const GENERATOR: FsRepr = FsRepr([0x720b1b19d49ea8f1, 0xbf4aa36101f13a58, 0x5fa8cc968193ccbb, 0xe70cbdc7dccf3ac]); +const GENERATOR: FsRepr = FsRepr([ + 0x720b1b19d49ea8f1, + 0xbf4aa36101f13a58, + 0x5fa8cc968193ccbb, + 0xe70cbdc7dccf3ac, +]); // 2^S * t = MODULUS - 1 with t odd const S: u32 = 1; // 2^S root of unity computed by GENERATOR^t -const ROOT_OF_UNITY: FsRepr = FsRepr([0xaa9f02ab1d6124de, 0xb3524a6466112932, 0x7342261215ac260b, 0x4d6b87b1da259e2]); +const ROOT_OF_UNITY: FsRepr = FsRepr([ + 0xaa9f02ab1d6124de, + 0xb3524a6466112932, + 0x7342261215ac260b, + 0x4d6b87b1da259e2, +]); // -((2**256) mod s) mod s -const NEGATIVE_ONE: Fs = Fs(FsRepr([0xaa9f02ab1d6124de, 0xb3524a6466112932, 0x7342261215ac260b, 0x4d6b87b1da259e2])); +const NEGATIVE_ONE: Fs = Fs(FsRepr([ + 0xaa9f02ab1d6124de, + 0xb3524a6466112932, + 0x7342261215ac260b, + 0x4d6b87b1da259e2, +])); /// This is the underlying representation of an element of `Fs`. #[derive(Copy, Clone, PartialEq, Eq, Default, Debug)] pub struct FsRepr(pub [u64; 4]); -impl ::std::fmt::Display for FsRepr -{ +impl ::std::fmt::Display for FsRepr { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { try!(write!(f, "0x")); for i in self.0.iter().rev() { @@ -83,9 +112,9 @@ impl Ord for FsRepr { fn cmp(&self, other: &FsRepr) -> ::std::cmp::Ordering { for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) { if a < b { - return ::std::cmp::Ordering::Less + return ::std::cmp::Ordering::Less; } else if a > b { - return ::std::cmp::Ordering::Greater + return ::std::cmp::Ordering::Greater; } } @@ -227,8 +256,7 @@ impl PrimeFieldRepr for FsRepr { #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Fs(FsRepr); -impl ::std::fmt::Display for Fs -{ +impl ::std::fmt::Display for Fs { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, "Fs({})", self.into_repr()) } @@ -256,9 +284,16 @@ impl PrimeField for Fs { fn into_repr(&self) -> FsRepr { let mut r = *self; - r.mont_reduce((self.0).0[0], (self.0).0[1], - (self.0).0[2], (self.0).0[3], - 0, 0, 0, 0); + r.mont_reduce( + (self.0).0[0], + (self.0).0[1], + (self.0).0[2], + (self.0).0[3], + 0, + 0, + 0, + 0, + ); r.0 } @@ -296,7 +331,7 @@ impl Field for Fs { tmp.0.as_mut()[3] &= 0xffffffffffffffff >> REPR_SHAVE_BITS; if tmp.is_valid() { - return tmp + return tmp; } } } @@ -414,8 +449,7 @@ impl Field for Fs { } #[inline] - fn mul_assign(&mut self, other: &Fs) - { + fn mul_assign(&mut self, other: &Fs) { let mut carry = 0; let r0 = mac_with_carry(0, (self.0).0[0], (other.0).0[0], &mut carry); let r1 = mac_with_carry(0, (self.0).0[0], (other.0).0[1], &mut carry); @@ -444,8 +478,7 @@ impl Field for Fs { } #[inline] - fn square(&mut self) - { + fn square(&mut self) { let mut carry = 0; let r1 = mac_with_carry(0, (self.0).0[0], (self.0).0[1], &mut carry); let r2 = mac_with_carry(0, (self.0).0[0], (self.0).0[2], &mut carry); @@ -507,9 +540,8 @@ impl Fs { mut r4: u64, mut r5: u64, mut r6: u64, - mut r7: u64 - ) - { + mut r7: u64, + ) { // The Montgomery reduction here is based on Algorithm 14.32 in // Handbook of Applied Cryptography // . @@ -579,13 +611,21 @@ impl ToUniform for Fs { } impl SqrtField for Fs { - fn legendre(&self) -> LegendreSymbol { // s = self^((s - 1) // 2) - let s = self.pow([0x684b872f6b7b965b, 0x53341049e6640841, 0x83339d80809a1d80, 0x73eda753299d7d4]); - if s == Self::zero() { Zero } - else if s == Self::one() { QuadraticResidue } - else { QuadraticNonResidue } + let s = self.pow([ + 0x684b872f6b7b965b, + 0x53341049e6640841, + 0x83339d80809a1d80, + 0x73eda753299d7d4, + ]); + if s == Self::zero() { + Zero + } else if s == Self::one() { + QuadraticResidue + } else { + QuadraticNonResidue + } } fn sqrt(&self) -> Option { @@ -593,24 +633,25 @@ impl SqrtField for Fs { // https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2) // a1 = self^((s - 3) // 4) - let mut a1 = self.pow([0xb425c397b5bdcb2d, 0x299a0824f3320420, 0x4199cec0404d0ec0, 0x39f6d3a994cebea]); + let mut a1 = self.pow([ + 0xb425c397b5bdcb2d, + 0x299a0824f3320420, + 0x4199cec0404d0ec0, + 0x39f6d3a994cebea, + ]); let mut a0 = a1; a0.square(); a0.mul_assign(self); - if a0 == NEGATIVE_ONE - { + if a0 == NEGATIVE_ONE { None - } - else - { + } else { a1.mul_assign(self); Some(a1) } } } - #[test] fn test_neg_one() { let mut o = Fs::one(); @@ -636,12 +677,30 @@ fn test_fs_repr_ordering() { assert!(b > a); } - assert_equality(FsRepr([9999, 9999, 9999, 9999]), FsRepr([9999, 9999, 9999, 9999])); - assert_equality(FsRepr([9999, 9998, 9999, 9999]), FsRepr([9999, 9998, 9999, 9999])); - assert_equality(FsRepr([9999, 9999, 9999, 9997]), FsRepr([9999, 9999, 9999, 9997])); - assert_lt(FsRepr([9999, 9997, 9999, 9998]), FsRepr([9999, 9997, 9999, 9999])); - assert_lt(FsRepr([9999, 9997, 9998, 9999]), FsRepr([9999, 9997, 9999, 9999])); - assert_lt(FsRepr([9, 9999, 9999, 9997]), FsRepr([9999, 9999, 9999, 9997])); + assert_equality( + FsRepr([9999, 9999, 9999, 9999]), + FsRepr([9999, 9999, 9999, 9999]), + ); + assert_equality( + FsRepr([9999, 9998, 9999, 9999]), + FsRepr([9999, 9998, 9999, 9999]), + ); + assert_equality( + FsRepr([9999, 9999, 9999, 9997]), + FsRepr([9999, 9999, 9999, 9997]), + ); + assert_lt( + FsRepr([9999, 9997, 9999, 9998]), + FsRepr([9999, 9997, 9999, 9999]), + ); + assert_lt( + FsRepr([9999, 9997, 9998, 9999]), + FsRepr([9999, 9997, 9999, 9999]), + ); + assert_lt( + FsRepr([9, 9999, 9999, 9997]), + FsRepr([9999, 9999, 9999, 9997]), + ); } #[test] @@ -670,13 +729,34 @@ fn test_fs_repr_is_zero() { #[test] fn test_fs_repr_div2() { - let mut a = FsRepr([0xbd2920b19c972321, 0x174ed0466a3be37e, 0xd468d5e3b551f0b5, 0xcb67c072733beefc]); + let mut a = FsRepr([ + 0xbd2920b19c972321, + 0x174ed0466a3be37e, + 0xd468d5e3b551f0b5, + 0xcb67c072733beefc, + ]); a.div2(); - assert_eq!(a, FsRepr([0x5e949058ce4b9190, 0x8ba76823351df1bf, 0x6a346af1daa8f85a, 0x65b3e039399df77e])); + assert_eq!( + a, + FsRepr([ + 0x5e949058ce4b9190, + 0x8ba76823351df1bf, + 0x6a346af1daa8f85a, + 0x65b3e039399df77e + ]) + ); for _ in 0..10 { a.div2(); } - assert_eq!(a, FsRepr([0x6fd7a524163392e4, 0x16a2e9da08cd477c, 0xdf9a8d1abc76aa3e, 0x196cf80e4e677d])); + assert_eq!( + a, + FsRepr([ + 0x6fd7a524163392e4, + 0x16a2e9da08cd477c, + 0xdf9a8d1abc76aa3e, + 0x196cf80e4e677d + ]) + ); for _ in 0..200 { a.div2(); } @@ -695,32 +775,46 @@ fn test_fs_repr_div2() { #[test] fn test_fs_repr_shr() { - let mut a = FsRepr([0xb33fbaec482a283f, 0x997de0d3a88cb3df, 0x9af62d2a9a0e5525, 0x36003ab08de70da1]); + let mut a = FsRepr([ + 0xb33fbaec482a283f, + 0x997de0d3a88cb3df, + 0x9af62d2a9a0e5525, + 0x36003ab08de70da1, + ]); a.shr(0); assert_eq!( a, - FsRepr([0xb33fbaec482a283f, 0x997de0d3a88cb3df, 0x9af62d2a9a0e5525, 0x36003ab08de70da1]) + FsRepr([ + 0xb33fbaec482a283f, + 0x997de0d3a88cb3df, + 0x9af62d2a9a0e5525, + 0x36003ab08de70da1 + ]) ); a.shr(1); assert_eq!( a, - FsRepr([0xd99fdd762415141f, 0xccbef069d44659ef, 0xcd7b16954d072a92, 0x1b001d5846f386d0]) + FsRepr([ + 0xd99fdd762415141f, + 0xccbef069d44659ef, + 0xcd7b16954d072a92, + 0x1b001d5846f386d0 + ]) ); a.shr(50); assert_eq!( a, - FsRepr([0xbc1a7511967bf667, 0xc5a55341caa4b32f, 0x75611bce1b4335e, 0x6c0]) + FsRepr([ + 0xbc1a7511967bf667, + 0xc5a55341caa4b32f, + 0x75611bce1b4335e, + 0x6c0 + ]) ); a.shr(130); - assert_eq!( - a, - FsRepr([0x1d5846f386d0cd7, 0x1b0, 0x0, 0x0]) - ); + assert_eq!(a, FsRepr([0x1d5846f386d0cd7, 0x1b0, 0x0, 0x0])); a.shr(64); - assert_eq!( - a, - FsRepr([0x1b0, 0x0, 0x0, 0x0]) - ); + assert_eq!(a, FsRepr([0x1b0, 0x0, 0x0, 0x0])); } #[test] @@ -765,9 +859,26 @@ fn test_fs_repr_sub_noborrow() { 0xe5, ]); - let mut t = FsRepr([0x8e62a7e85264e2c3, 0xb23d34c1941d3ca, 0x5976930b7502dd15, 0x600f3fb517bf5495]); - t.sub_noborrow(&FsRepr([0xd64f669809cbc6a4, 0xfa76cb9d90cf7637, 0xfefb0df9038d43b3, 0x298a30c744b31acf])); - assert!(t == FsRepr([0xb813415048991c1f, 0x10ad07ae88725d92, 0x5a7b851271759961, 0x36850eedd30c39c5])); + let mut t = FsRepr([ + 0x8e62a7e85264e2c3, + 0xb23d34c1941d3ca, + 0x5976930b7502dd15, + 0x600f3fb517bf5495, + ]); + t.sub_noborrow(&FsRepr([ + 0xd64f669809cbc6a4, + 0xfa76cb9d90cf7637, + 0xfefb0df9038d43b3, + 0x298a30c744b31acf, + ])); + assert!( + t == FsRepr([ + 0xb813415048991c1f, + 0x10ad07ae88725d92, + 0x5a7b851271759961, + 0x36850eedd30c39c5 + ]) + ); for _ in 0..1000 { let mut a = Fs::random(&mut rng).into_repr(); @@ -801,9 +912,19 @@ fn test_fs_legendre() { assert_eq!(QuadraticResidue, Fs::one().legendre()); assert_eq!(Zero, Fs::zero().legendre()); - let e = FsRepr([0x8385eec23df1f88e, 0x9a01fb412b2dba16, 0x4c928edcdd6c22f, 0x9f2df7ef69ecef9]); + let e = FsRepr([ + 0x8385eec23df1f88e, + 0x9a01fb412b2dba16, + 0x4c928edcdd6c22f, + 0x9f2df7ef69ecef9, + ]); assert_eq!(QuadraticResidue, Fs::from_repr(e).unwrap().legendre()); - let e = FsRepr([0xe8ed9f299da78568, 0x35efdebc88b2209, 0xc82125cb1f916dbe, 0x6813d2b38c39bd0]); + let e = FsRepr([ + 0xe8ed9f299da78568, + 0x35efdebc88b2209, + 0xc82125cb1f916dbe, + 0x6813d2b38c39bd0, + ]); assert_eq!(QuadraticNonResidue, Fs::from_repr(e).unwrap().legendre()); } @@ -814,9 +935,27 @@ fn test_fr_repr_add_nocarry() { 0xe5, ]); - let mut t = FsRepr([0xd64f669809cbc6a4, 0xfa76cb9d90cf7637, 0xfefb0df9038d43b3, 0x298a30c744b31acf]); - t.add_nocarry(&FsRepr([0x8e62a7e85264e2c3, 0xb23d34c1941d3ca, 0x5976930b7502dd15, 0x600f3fb517bf5495])); - assert_eq!(t, FsRepr([0x64b20e805c30a967, 0x59a9ee9aa114a02, 0x5871a104789020c9, 0x8999707c5c726f65])); + let mut t = FsRepr([ + 0xd64f669809cbc6a4, + 0xfa76cb9d90cf7637, + 0xfefb0df9038d43b3, + 0x298a30c744b31acf, + ]); + t.add_nocarry(&FsRepr([ + 0x8e62a7e85264e2c3, + 0xb23d34c1941d3ca, + 0x5976930b7502dd15, + 0x600f3fb517bf5495, + ])); + assert_eq!( + t, + FsRepr([ + 0x64b20e805c30a967, + 0x59a9ee9aa114a02, + 0x5871a104789020c9, + 0x8999707c5c726f65 + ]) + ); // Test for the associativity of addition. for _ in 0..1000 { @@ -868,8 +1007,20 @@ fn test_fs_is_valid() { a.0.sub_noborrow(&FsRepr::from(1)); assert!(a.is_valid()); assert!(Fs(FsRepr::from(0)).is_valid()); - assert!(Fs(FsRepr([0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9])).is_valid()); - assert!(!Fs(FsRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])).is_valid()); + assert!(Fs(FsRepr([ + 0xd0970e5ed6f72cb6, + 0xa6682093ccc81082, + 0x6673b0101343b00, + 0xe7db4ea6533afa9 + ])) + .is_valid()); + assert!(!Fs(FsRepr([ + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff + ])) + .is_valid()); let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, @@ -886,25 +1037,80 @@ fn test_fs_is_valid() { fn test_fs_add_assign() { { // Random number - let mut tmp = Fs::from_str("4577408157467272683998459759522778614363623736323078995109579213719612604198").unwrap(); + let mut tmp = Fs::from_str( + "4577408157467272683998459759522778614363623736323078995109579213719612604198", + ) + .unwrap(); assert!(tmp.is_valid()); // Test that adding zero has no effect. tmp.add_assign(&Fs(FsRepr::from(0))); - assert_eq!(tmp, Fs(FsRepr([0x8e6bfff4722d6e67, 0x5643da5c892044f9, 0x9465f4b281921a69, 0x25f752d3edd7162]))); + assert_eq!( + tmp, + Fs(FsRepr([ + 0x8e6bfff4722d6e67, + 0x5643da5c892044f9, + 0x9465f4b281921a69, + 0x25f752d3edd7162 + ])) + ); // Add one and test for the result. tmp.add_assign(&Fs(FsRepr::from(1))); - assert_eq!(tmp, Fs(FsRepr([0x8e6bfff4722d6e68, 0x5643da5c892044f9, 0x9465f4b281921a69, 0x25f752d3edd7162]))); + assert_eq!( + tmp, + Fs(FsRepr([ + 0x8e6bfff4722d6e68, + 0x5643da5c892044f9, + 0x9465f4b281921a69, + 0x25f752d3edd7162 + ])) + ); // Add another random number that exercises the reduction. - tmp.add_assign(&Fs(FsRepr([0xb634d07bc42d4a70, 0xf724f0c008411f5f, 0x456d4053d865af34, 0x24ce814e8c63027]))); - assert_eq!(tmp, Fs(FsRepr([0x44a0d070365ab8d8, 0x4d68cb1c91616459, 0xd9d3350659f7c99e, 0x4ac5d4227a3a189]))); + tmp.add_assign(&Fs(FsRepr([ + 0xb634d07bc42d4a70, + 0xf724f0c008411f5f, + 0x456d4053d865af34, + 0x24ce814e8c63027, + ]))); + assert_eq!( + tmp, + Fs(FsRepr([ + 0x44a0d070365ab8d8, + 0x4d68cb1c91616459, + 0xd9d3350659f7c99e, + 0x4ac5d4227a3a189 + ])) + ); // Add one to (s - 1) and test for the result. - tmp = Fs(FsRepr([0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9])); + tmp = Fs(FsRepr([ + 0xd0970e5ed6f72cb6, + 0xa6682093ccc81082, + 0x6673b0101343b00, + 0xe7db4ea6533afa9, + ])); tmp.add_assign(&Fs(FsRepr::from(1))); assert!(tmp.0.is_zero()); // Add a random number to another one such that the result is s - 1 - tmp = Fs(FsRepr([0xa11fda5950ce3636, 0x922e0dbccfe0ca0e, 0xacebb6e215b82d4a, 0x97ffb8cdc3aee93])); - tmp.add_assign(&Fs(FsRepr([0x2f7734058628f680, 0x143a12d6fce74674, 0x597b841eeb7c0db6, 0x4fdb95d88f8c115]))); - assert_eq!(tmp, Fs(FsRepr([0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9]))); + tmp = Fs(FsRepr([ + 0xa11fda5950ce3636, + 0x922e0dbccfe0ca0e, + 0xacebb6e215b82d4a, + 0x97ffb8cdc3aee93, + ])); + tmp.add_assign(&Fs(FsRepr([ + 0x2f7734058628f680, + 0x143a12d6fce74674, + 0x597b841eeb7c0db6, + 0x4fdb95d88f8c115, + ]))); + assert_eq!( + tmp, + Fs(FsRepr([ + 0xd0970e5ed6f72cb6, + 0xa6682093ccc81082, + 0x6673b0101343b00, + 0xe7db4ea6533afa9 + ])) + ); // Add one to the result and test for it. tmp.add_assign(&Fs(FsRepr::from(1))); assert!(tmp.0.is_zero()); @@ -941,23 +1147,72 @@ fn test_fs_add_assign() { fn test_fs_sub_assign() { { // Test arbitrary subtraction that tests reduction. - let mut tmp = Fs(FsRepr([0xb384d9f6877afd99, 0x4442513958e1a1c1, 0x352c4b8a95eccc3f, 0x2db62dee4b0f2])); - tmp.sub_assign(&Fs(FsRepr([0xec5bd2d13ed6b05a, 0x2adc0ab3a39b5fa, 0x82d3360a493e637e, 0x53ccff4a64d6679]))); - assert_eq!(tmp, Fs(FsRepr([0x97c015841f9b79f6, 0xe7fcb121eb6ffc49, 0xb8c050814de2a3c1, 0x943c0589dcafa21]))); + let mut tmp = Fs(FsRepr([ + 0xb384d9f6877afd99, + 0x4442513958e1a1c1, + 0x352c4b8a95eccc3f, + 0x2db62dee4b0f2, + ])); + tmp.sub_assign(&Fs(FsRepr([ + 0xec5bd2d13ed6b05a, + 0x2adc0ab3a39b5fa, + 0x82d3360a493e637e, + 0x53ccff4a64d6679, + ]))); + assert_eq!( + tmp, + Fs(FsRepr([ + 0x97c015841f9b79f6, + 0xe7fcb121eb6ffc49, + 0xb8c050814de2a3c1, + 0x943c0589dcafa21 + ])) + ); // Test the opposite subtraction which doesn't test reduction. - tmp = Fs(FsRepr([0xec5bd2d13ed6b05a, 0x2adc0ab3a39b5fa, 0x82d3360a493e637e, 0x53ccff4a64d6679])); - tmp.sub_assign(&Fs(FsRepr([0xb384d9f6877afd99, 0x4442513958e1a1c1, 0x352c4b8a95eccc3f, 0x2db62dee4b0f2]))); - assert_eq!(tmp, Fs(FsRepr([0x38d6f8dab75bb2c1, 0xbe6b6f71e1581439, 0x4da6ea7fb351973e, 0x539f491c768b587]))); + tmp = Fs(FsRepr([ + 0xec5bd2d13ed6b05a, + 0x2adc0ab3a39b5fa, + 0x82d3360a493e637e, + 0x53ccff4a64d6679, + ])); + tmp.sub_assign(&Fs(FsRepr([ + 0xb384d9f6877afd99, + 0x4442513958e1a1c1, + 0x352c4b8a95eccc3f, + 0x2db62dee4b0f2, + ]))); + assert_eq!( + tmp, + Fs(FsRepr([ + 0x38d6f8dab75bb2c1, + 0xbe6b6f71e1581439, + 0x4da6ea7fb351973e, + 0x539f491c768b587 + ])) + ); // Test for sensible results with zero tmp = Fs(FsRepr::from(0)); tmp.sub_assign(&Fs(FsRepr::from(0))); assert!(tmp.is_zero()); - tmp = Fs(FsRepr([0x361e16aef5cce835, 0x55bbde2536e274c1, 0x4dc77a63fd15ee75, 0x1e14bb37c14f230])); + tmp = Fs(FsRepr([ + 0x361e16aef5cce835, + 0x55bbde2536e274c1, + 0x4dc77a63fd15ee75, + 0x1e14bb37c14f230, + ])); tmp.sub_assign(&Fs(FsRepr::from(0))); - assert_eq!(tmp, Fs(FsRepr([0x361e16aef5cce835, 0x55bbde2536e274c1, 0x4dc77a63fd15ee75, 0x1e14bb37c14f230]))); + assert_eq!( + tmp, + Fs(FsRepr([ + 0x361e16aef5cce835, + 0x55bbde2536e274c1, + 0x4dc77a63fd15ee75, + 0x1e14bb37c14f230 + ])) + ); } let mut rng = XorShiftRng::from_seed([ @@ -983,9 +1238,26 @@ fn test_fs_sub_assign() { #[test] fn test_fs_mul_assign() { - let mut tmp = Fs(FsRepr([0xb433b01287f71744, 0x4eafb86728c4d108, 0xfdd52c14b9dfbe65, 0x2ff1f3434821118])); - tmp.mul_assign(&Fs(FsRepr([0xdae00fc63c9fa90f, 0x5a5ed89b96ce21ce, 0x913cd26101bd6f58, 0x3f0822831697fe9]))); - assert!(tmp == Fs(FsRepr([0xb68ecb61d54d2992, 0x5ff95874defce6a6, 0x3590eb053894657d, 0x53823a118515933]))); + let mut tmp = Fs(FsRepr([ + 0xb433b01287f71744, + 0x4eafb86728c4d108, + 0xfdd52c14b9dfbe65, + 0x2ff1f3434821118, + ])); + tmp.mul_assign(&Fs(FsRepr([ + 0xdae00fc63c9fa90f, + 0x5a5ed89b96ce21ce, + 0x913cd26101bd6f58, + 0x3f0822831697fe9, + ]))); + assert!( + tmp == Fs(FsRepr([ + 0xb68ecb61d54d2992, + 0x5ff95874defce6a6, + 0x3590eb053894657d, + 0x53823a118515933 + ])) + ); let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, @@ -1035,10 +1307,24 @@ fn test_fs_mul_assign() { #[test] fn test_fr_squaring() { - let mut a = Fs(FsRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xe7db4ea6533afa8])); + let mut a = Fs(FsRepr([ + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xe7db4ea6533afa8, + ])); assert!(a.is_valid()); a.square(); - assert_eq!(a, Fs::from_repr(FsRepr([0x12c7f55cbc52fbaa, 0xdedc98a0b5e6ce9e, 0xad2892726a5396a, 0x9fe82af8fee77b3])).unwrap()); + assert_eq!( + a, + Fs::from_repr(FsRepr([ + 0x12c7f55cbc52fbaa, + 0xdedc98a0b5e6ce9e, + 0xad2892726a5396a, + 0x9fe82af8fee77b3 + ])) + .unwrap() + ); let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, @@ -1185,17 +1471,38 @@ fn test_fs_sqrt() { #[test] fn test_fs_from_into_repr() { // r + 1 should not be in the field - assert!(Fs::from_repr(FsRepr([0xd0970e5ed6f72cb8, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9])).is_err()); + assert!(Fs::from_repr(FsRepr([ + 0xd0970e5ed6f72cb8, + 0xa6682093ccc81082, + 0x6673b0101343b00, + 0xe7db4ea6533afa9 + ])) + .is_err()); // r should not be in the field assert!(Fs::from_repr(Fs::char()).is_err()); // Multiply some arbitrary representations to see if the result is as expected. - let a = FsRepr([0x5f2d0c05d0337b71, 0xa1df2b0f8a20479, 0xad73785e71bb863, 0x504a00480c9acec]); + let a = FsRepr([ + 0x5f2d0c05d0337b71, + 0xa1df2b0f8a20479, + 0xad73785e71bb863, + 0x504a00480c9acec, + ]); let mut a_fs = Fs::from_repr(a).unwrap(); - let b = FsRepr([0x66356ff51e477562, 0x60a92ab55cf7603, 0x8e4273c7364dd192, 0x36df8844a344dc5]); + let b = FsRepr([ + 0x66356ff51e477562, + 0x60a92ab55cf7603, + 0x8e4273c7364dd192, + 0x36df8844a344dc5, + ]); let b_fs = Fs::from_repr(b).unwrap(); - let c = FsRepr([0x7eef61708f4f2868, 0x747a7e6cf52946fb, 0x83dd75d7c9120017, 0x762f5177f0f3df7]); + let c = FsRepr([ + 0x7eef61708f4f2868, + 0x747a7e6cf52946fb, + 0x83dd75d7c9120017, + 0x762f5177f0f3df7, + ]); a_fs.mul_assign(&b_fs); assert_eq!(a_fs.into_repr(), c); @@ -1222,15 +1529,39 @@ fn test_fs_from_into_repr() { #[test] fn test_fs_repr_display() { assert_eq!( - format!("{}", FsRepr([0xa296db59787359df, 0x8d3e33077430d318, 0xd1abf5c606102eb7, 0xcbc33ee28108f0])), + format!( + "{}", + FsRepr([ + 0xa296db59787359df, + 0x8d3e33077430d318, + 0xd1abf5c606102eb7, + 0xcbc33ee28108f0 + ]) + ), "0x00cbc33ee28108f0d1abf5c606102eb78d3e33077430d318a296db59787359df".to_string() ); assert_eq!( - format!("{}", FsRepr([0x14cb03535054a620, 0x312aa2bf2d1dff52, 0x970fe98746ab9361, 0xc1e18acf82711e6])), + format!( + "{}", + FsRepr([ + 0x14cb03535054a620, + 0x312aa2bf2d1dff52, + 0x970fe98746ab9361, + 0xc1e18acf82711e6 + ]) + ), "0x0c1e18acf82711e6970fe98746ab9361312aa2bf2d1dff5214cb03535054a620".to_string() ); assert_eq!( - format!("{}", FsRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])), + format!( + "{}", + FsRepr([ + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff + ]) + ), "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string() ); assert_eq!( @@ -1242,11 +1573,29 @@ fn test_fs_repr_display() { #[test] fn test_fs_display() { assert_eq!( - format!("{}", Fs::from_repr(FsRepr([0x5528efb9998a01a3, 0x5bd2add5cb357089, 0xc061fa6adb491f98, 0x70db9d143db03d9])).unwrap()), + format!( + "{}", + Fs::from_repr(FsRepr([ + 0x5528efb9998a01a3, + 0x5bd2add5cb357089, + 0xc061fa6adb491f98, + 0x70db9d143db03d9 + ])) + .unwrap() + ), "Fs(0x070db9d143db03d9c061fa6adb491f985bd2add5cb3570895528efb9998a01a3)".to_string() ); assert_eq!( - format!("{}", Fs::from_repr(FsRepr([0xd674745e2717999e, 0xbeb1f52d3e96f338, 0x9c7ae147549482b9, 0x999706024530d22])).unwrap()), + format!( + "{}", + Fs::from_repr(FsRepr([ + 0xd674745e2717999e, + 0xbeb1f52d3e96f338, + 0x9c7ae147549482b9, + 0x999706024530d22 + ])) + .unwrap() + ), "Fs(0x0999706024530d229c7ae147549482b9beb1f52d3e96f338d674745e2717999e)".to_string() ); } @@ -1260,14 +1609,19 @@ fn test_fs_num_bits() { #[test] fn test_fs_root_of_unity() { assert_eq!(Fs::S, 1); - assert_eq!(Fs::multiplicative_generator(), Fs::from_repr(FsRepr::from(6)).unwrap()); assert_eq!( - Fs::multiplicative_generator().pow([0x684b872f6b7b965b, 0x53341049e6640841, 0x83339d80809a1d80, 0x73eda753299d7d4]), + Fs::multiplicative_generator(), + Fs::from_repr(FsRepr::from(6)).unwrap() + ); + assert_eq!( + Fs::multiplicative_generator().pow([ + 0x684b872f6b7b965b, + 0x53341049e6640841, + 0x83339d80809a1d80, + 0x73eda753299d7d4 + ]), Fs::root_of_unity() ); - assert_eq!( - Fs::root_of_unity().pow([1 << Fs::S]), - Fs::one() - ); + assert_eq!(Fs::root_of_unity().pow([1 << Fs::S]), Fs::one()); assert!(Fs::multiplicative_generator().sqrt().is_none()); } diff --git a/zcash_primitives/src/jubjub/mod.rs b/zcash_primitives/src/jubjub/mod.rs index 71e1875..7ab0d0e 100644 --- a/zcash_primitives/src/jubjub/mod.rs +++ b/zcash_primitives/src/jubjub/mod.rs @@ -24,10 +24,7 @@ use group_hash::group_hash; use constants; -use pairing::bls12_381::{ - Bls12, - Fr -}; +use pairing::bls12_381::{Bls12, Fr}; /// This is an implementation of the twisted Edwards Jubjub curve. pub mod edwards; @@ -44,11 +41,11 @@ pub mod tests; /// Point of unknown order. #[derive(Debug)] -pub enum Unknown { } +pub enum Unknown {} /// Point of prime order. #[derive(Debug)] -pub enum PrimeOrder { } +pub enum PrimeOrder {} /// Fixed generators of the Jubjub curve of unknown /// exponent. @@ -80,7 +77,7 @@ pub enum FixedGenerators { /// base at spend time. SpendingKeyGenerator = 5, - Max = 6 + Max = 6, } pub trait ToUniform { @@ -151,10 +148,18 @@ pub struct JubjubBls12 { } impl JubjubParams for JubjubBls12 { - fn edwards_d(&self) -> &Fr { &self.edwards_d } - fn montgomery_a(&self) -> &Fr { &self.montgomery_a } - fn montgomery_2a(&self) -> &Fr { &self.montgomery_2a } - fn scale(&self) -> &Fr { &self.scale } + fn edwards_d(&self) -> &Fr { + &self.edwards_d + } + fn montgomery_a(&self) -> &Fr { + &self.montgomery_a + } + fn montgomery_2a(&self) -> &Fr { + &self.montgomery_2a + } + fn scale(&self) -> &Fr { + &self.scale + } fn pedersen_hash_generators(&self) -> &[edwards::Point] { &self.pedersen_hash_generators } @@ -170,12 +175,10 @@ impl JubjubParams for JubjubBls12 { fn pedersen_circuit_generators(&self) -> &[Vec>] { &self.pedersen_circuit_generators } - fn generator(&self, base: FixedGenerators) -> &edwards::Point - { + fn generator(&self, base: FixedGenerators) -> &edwards::Point { &self.fixed_base_generators[base as usize] } - fn circuit_generators(&self, base: FixedGenerators) -> &[Vec<(Fr, Fr)>] - { + fn circuit_generators(&self, base: FixedGenerators) -> &[Vec<(Fr, Fr)>] { &self.fixed_base_circuit_generators[base as usize][..] } fn pedersen_hash_exp_window_size() -> u32 { @@ -191,13 +194,19 @@ impl JubjubBls12 { let mut tmp_params = JubjubBls12 { // d = -(10240/10241) - edwards_d: Fr::from_str("19257038036680949359750312669786877991949435402254120286184196891950884077233").unwrap(), + edwards_d: Fr::from_str( + "19257038036680949359750312669786877991949435402254120286184196891950884077233", + ) + .unwrap(), // A = 40962 montgomery_a: montgomery_a, // 2A = 2.A montgomery_2a: montgomery_2a, // scaling factor = sqrt(4 / (a - d)) - scale: Fr::from_str("17814886934372412843466061268024708274627479829237077604635722030778476050649").unwrap(), + scale: Fr::from_str( + "17814886934372412843466061268024708274627479829237077604635722030778476050649", + ) + .unwrap(), // We'll initialize these below pedersen_hash_generators: vec![], @@ -210,19 +219,14 @@ impl JubjubBls12 { fn find_group_hash( m: &[u8], personalization: &[u8; 8], - params: &E::Params - ) -> edwards::Point - { + params: &E::Params, + ) -> edwards::Point { let mut tag = m.to_vec(); let i = tag.len(); tag.push(0u8); loop { - let gh = group_hash( - &tag, - personalization, - params - ); + let gh = group_hash(&tag, personalization, params); // We don't want to overflow and start reusing generators assert!(tag[i] != u8::max_value()); @@ -239,18 +243,18 @@ impl JubjubBls12 { let mut pedersen_hash_generators = vec![]; for m in 0..5 { - use byteorder::{WriteBytesExt, LittleEndian}; + use byteorder::{LittleEndian, WriteBytesExt}; let mut segment_number = [0u8; 4]; - (&mut segment_number[0..4]).write_u32::(m).unwrap(); + (&mut segment_number[0..4]) + .write_u32::(m) + .unwrap(); - pedersen_hash_generators.push( - find_group_hash( - &segment_number, - constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, - &tmp_params - ) - ); + pedersen_hash_generators.push(find_group_hash( + &segment_number, + constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, + &tmp_params, + )); } // Check for duplicates, far worse than spec inconsistencies! @@ -259,7 +263,7 @@ impl JubjubBls12 { panic!("Neutral element!"); } - for p2 in pedersen_hash_generators.iter().skip(i+1) { + for p2 in pedersen_hash_generators.iter().skip(i + 1) { if p1 == p2 { panic!("Duplicate generator!"); } @@ -307,25 +311,46 @@ impl JubjubBls12 { // Create the bases for other parts of the protocol { - let mut fixed_base_generators = vec![edwards::Point::zero(); FixedGenerators::Max as usize]; + let mut fixed_base_generators = + vec![edwards::Point::zero(); FixedGenerators::Max as usize]; - fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] = - find_group_hash(&[], constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION, &tmp_params); + fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] = find_group_hash( + &[], + constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION, + &tmp_params, + ); fixed_base_generators[FixedGenerators::NoteCommitmentRandomness as usize] = - find_group_hash(b"r", constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, &tmp_params); + find_group_hash( + b"r", + constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, + &tmp_params, + ); - fixed_base_generators[FixedGenerators::NullifierPosition as usize] = - find_group_hash(&[], constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION, &tmp_params); + fixed_base_generators[FixedGenerators::NullifierPosition as usize] = find_group_hash( + &[], + constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION, + &tmp_params, + ); - fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] = - find_group_hash(b"v", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params); + fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] = find_group_hash( + b"v", + constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, + &tmp_params, + ); fixed_base_generators[FixedGenerators::ValueCommitmentRandomness as usize] = - find_group_hash(b"r", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params); + find_group_hash( + b"r", + constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, + &tmp_params, + ); - fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] = - find_group_hash(&[], constants::SPENDING_KEY_GENERATOR_PERSONALIZATION, &tmp_params); + fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] = find_group_hash( + &[], + constants::SPENDING_KEY_GENERATOR_PERSONALIZATION, + &tmp_params, + ); // Check for duplicates, far worse than spec inconsistencies! for (i, p1) in fixed_base_generators.iter().enumerate() { @@ -333,7 +358,7 @@ impl JubjubBls12 { panic!("Neutral element!"); } - for p2 in fixed_base_generators.iter().skip(i+1) { + for p2 in fixed_base_generators.iter().skip(i + 1) { if p1 == p2 { panic!("Duplicate generator!"); } @@ -413,10 +438,14 @@ fn test_jubjub_bls12() { let test_repr = hex!("9d12b88b08dcbef8a11ee0712d94cb236ee2f4ca17317075bfafc82ce3139d31"); let p = edwards::Point::::read(&test_repr[..], ¶ms).unwrap(); let q = edwards::Point::::get_for_y( - Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(), + Fr::from_str( + "22440861827555040311190986994816762244378363690614952020532787748720529117853", + ) + .unwrap(), false, - ¶ms - ).unwrap(); + ¶ms, + ) + .unwrap(); assert!(p == q); @@ -424,10 +453,14 @@ fn test_jubjub_bls12() { let test_repr = hex!("9d12b88b08dcbef8a11ee0712d94cb236ee2f4ca17317075bfafc82ce3139db1"); let p = edwards::Point::::read(&test_repr[..], ¶ms).unwrap(); let q = edwards::Point::::get_for_y( - Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(), + Fr::from_str( + "22440861827555040311190986994816762244378363690614952020532787748720529117853", + ) + .unwrap(), true, - ¶ms - ).unwrap(); + ¶ms, + ) + .unwrap(); assert!(p == q); } diff --git a/zcash_primitives/src/jubjub/montgomery.rs b/zcash_primitives/src/jubjub/montgomery.rs index 9bd6023..e0bc4bf 100644 --- a/zcash_primitives/src/jubjub/montgomery.rs +++ b/zcash_primitives/src/jubjub/montgomery.rs @@ -1,12 +1,6 @@ use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; -use super::{ - JubjubEngine, - JubjubParams, - Unknown, - PrimeOrder, - edwards -}; +use super::{edwards, JubjubEngine, JubjubParams, PrimeOrder, Unknown}; use rand_core::RngCore; @@ -17,29 +11,25 @@ pub struct Point { x: E::Fr, y: E::Fr, infinity: bool, - _marker: PhantomData + _marker: PhantomData, } -fn convert_subgroup(from: &Point) -> Point -{ +fn convert_subgroup(from: &Point) -> Point { Point { x: from.x, y: from.y, infinity: from.infinity, - _marker: PhantomData + _marker: PhantomData, } } -impl From> for Point -{ - fn from(p: Point) -> Point - { +impl From> for Point { + fn from(p: Point) -> Point { convert_subgroup(&p) } } -impl Clone for Point -{ +impl Clone for Point { fn clone(&self) -> Self { convert_subgroup(self) } @@ -50,16 +40,13 @@ impl PartialEq for Point { match (self.infinity, other.infinity) { (true, true) => true, (true, false) | (false, true) => false, - (false, false) => { - self.x == other.x && self.y == other.y - } + (false, false) => self.x == other.x && self.y == other.y, } } } impl Point { - pub fn get_for_x(x: E::Fr, sign: bool, params: &E::Params) -> Option - { + pub fn get_for_x(x: E::Fr, sign: bool, params: &E::Params) -> Option { // Given an x on the curve, y = sqrt(x^3 + A*x^2 + x) let mut x2 = x; @@ -81,34 +68,28 @@ impl Point { x: x, y: y, infinity: false, - _marker: PhantomData - }) - }, - None => None + _marker: PhantomData, + }); + } + None => None, } } /// This guarantees the point is in the prime order subgroup #[must_use] - pub fn mul_by_cofactor(&self, params: &E::Params) -> Point - { - let tmp = self.double(params) - .double(params) - .double(params); + pub fn mul_by_cofactor(&self, params: &E::Params) -> Point { + let tmp = self.double(params).double(params).double(params); convert_subgroup(&tmp) } - pub fn rand(rng: &mut R, params: &E::Params) -> Self - { + pub fn rand(rng: &mut R, params: &E::Params) -> Self { loop { let x = E::Fr::random(rng); let sign = rng.next_u32() % 2 != 0; match Self::get_for_x(x, sign, params) { - Some(p) => { - return p - }, + Some(p) => return p, None => {} } } @@ -117,11 +98,7 @@ impl Point { impl Point { /// Convert from an Edwards point - pub fn from_edwards( - e: &edwards::Point, - params: &E::Params - ) -> Self - { + pub fn from_edwards(e: &edwards::Point, params: &E::Params) -> Self { let (x, y) = e.into_xy(); if y == E::Fr::one() { @@ -149,7 +126,7 @@ impl Point { x: E::Fr::zero(), y: E::Fr::zero(), infinity: false, - _marker: PhantomData + _marker: PhantomData, } } else { // The mapping is defined as above. @@ -176,7 +153,7 @@ impl Point { x: u, y: v, infinity: false, - _marker: PhantomData + _marker: PhantomData, } } } @@ -197,12 +174,11 @@ impl Point { x: E::Fr::zero(), y: E::Fr::zero(), infinity: true, - _marker: PhantomData + _marker: PhantomData, } } - pub fn into_xy(&self) -> Option<(E::Fr, E::Fr)> - { + pub fn into_xy(&self) -> Option<(E::Fr, E::Fr)> { if self.infinity { None } else { @@ -272,13 +248,12 @@ impl Point { x: x3, y: y3, infinity: false, - _marker: PhantomData + _marker: PhantomData, } } #[must_use] - pub fn add(&self, other: &Self, params: &E::Params) -> Self - { + pub fn add(&self, other: &Self, params: &E::Params) -> Self { // This is a standard affine point addition formula // See 4.3.2 The group law for Weierstrass curves // Montgomery curves and the Montgomery Ladder @@ -301,7 +276,10 @@ impl Point { { let mut tmp = other.x; tmp.sub_assign(&self.x); - delta.mul_assign(&tmp.inverse().expect("self.x != other.x, so this must be nonzero")); + delta.mul_assign( + &tmp.inverse() + .expect("self.x != other.x, so this must be nonzero"), + ); } let mut x3 = delta; @@ -320,7 +298,7 @@ impl Point { x: x3, y: y3, infinity: false, - _marker: PhantomData + _marker: PhantomData, } } } @@ -328,12 +306,7 @@ impl Point { } #[must_use] - pub fn mul::Repr>>( - &self, - scalar: S, - params: &E::Params - ) -> Self - { + pub fn mul::Repr>>(&self, scalar: S, params: &E::Params) -> Self { // Standard double-and-add scalar multiplication let mut res = Self::zero(); diff --git a/zcash_primitives/src/jubjub/tests.rs b/zcash_primitives/src/jubjub/tests.rs index e15b81e..1b4f8d1 100644 --- a/zcash_primitives/src/jubjub/tests.rs +++ b/zcash_primitives/src/jubjub/tests.rs @@ -1,18 +1,6 @@ -use super::{ - JubjubEngine, - JubjubParams, - PrimeOrder, - montgomery, - edwards -}; +use super::{edwards, montgomery, JubjubEngine, JubjubParams, PrimeOrder}; -use ff::{ - Field, - PrimeField, - PrimeFieldRepr, - SqrtField, - LegendreSymbol -}; +use ff::{Field, LegendreSymbol, PrimeField, PrimeFieldRepr, SqrtField}; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; @@ -30,12 +18,7 @@ pub fn test_suite(params: &E::Params) { test_read_write::(params); } -fn is_on_mont_curve>( - x: E::Fr, - y: E::Fr, - params: &P -) -> bool -{ +fn is_on_mont_curve>(x: E::Fr, y: E::Fr, params: &P) -> bool { let mut lhs = y; lhs.square(); @@ -56,9 +39,8 @@ fn is_on_mont_curve>( fn is_on_twisted_edwards_curve>( x: E::Fr, y: E::Fr, - params: &P -) -> bool -{ + params: &P, +) -> bool { let mut x2 = x; x2.square(); @@ -156,7 +138,9 @@ fn test_order(params: &E::Params) { ]); // The neutral element is in the prime order subgroup. - assert!(Point::::zero().as_prime_order(params).is_some()); + assert!(Point::::zero() + .as_prime_order(params) + .is_some()); for _ in 0..50 { // Pick a random point and multiply it by the cofactor @@ -256,11 +240,7 @@ fn test_get_for(params: &E::Params) { if let Some(mut p) = edwards::Point::::get_for_y(y, sign, params) { assert!(p.into_xy().0.into_repr().is_odd() == sign); p = p.negate(); - assert!( - edwards::Point::::get_for_y(y, !sign, params).unwrap() - == - p - ); + assert!(edwards::Point::::get_for_y(y, !sign, params).unwrap() == p); } } } @@ -321,13 +301,9 @@ fn test_back_and_forth(params: &E::Params) { let mont = mont_p1.add(&mont_p2, params).mul(s, params); let edwards = edwards_p1.add(&edwards_p2, params).mul(s, params); - assert!( - montgomery::Point::from_edwards(&edwards, params) == mont - ); + assert!(montgomery::Point::from_edwards(&edwards, params) == mont); - assert!( - edwards::Point::from_montgomery(&mont, params) == edwards - ); + assert!(edwards::Point::from_montgomery(&mont, params) == edwards); } } @@ -411,8 +387,7 @@ fn test_jubjub_params(params: &E::Params) { let mut pacc = E::Fs::zero().into_repr(); let mut nacc = E::Fs::char(); - for _ in 0..params.pedersen_hash_chunks_per_generator() - { + for _ in 0..params.pedersen_hash_chunks_per_generator() { // tmp = cur * 4 let mut tmp = cur; tmp.mul2(); diff --git a/zcash_primitives/src/keys.rs b/zcash_primitives/src/keys.rs index ae2c77a..ad86059 100644 --- a/zcash_primitives/src/keys.rs +++ b/zcash_primitives/src/keys.rs @@ -2,12 +2,12 @@ //! //! Implements section 4.2.2 of the Zcash Protocol Specification. -use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; -use ff::{PrimeField, PrimeFieldRepr}; use crate::{ jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, ToUniform, Unknown}, primitives::{ProofGenerationKey, ViewingKey}, }; +use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; +use ff::{PrimeField, PrimeFieldRepr}; use std::io::{self, Read, Write}; pub const PRF_EXPAND_PERSONALIZATION: &'static [u8; 16] = b"Zcash_ExpandSeed"; @@ -187,8 +187,8 @@ impl FullViewingKey { #[cfg(test)] mod tests { - use pairing::bls12_381::Bls12; use crate::jubjub::{edwards, FixedGenerators, JubjubParams, PrimeOrder}; + use pairing::bls12_381::Bls12; use std::error::Error; use super::FullViewingKey; diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index e6804cf..5412945 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -1,11 +1,5 @@ //! Implementation of in-band secret distribution for Zcash transactions. -use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf}; -use ff::{PrimeField, PrimeFieldRepr}; -use pairing::bls12_381::{Bls12, Fr}; -use rand_core::{CryptoRng, RngCore}; use crate::{ jubjub::{ edwards, @@ -14,6 +8,12 @@ use crate::{ }, primitives::{Diversifier, Note, PaymentAddress}, }; +use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf}; +use ff::{PrimeField, PrimeFieldRepr}; +use pairing::bls12_381::{Bls12, Fr}; +use rand_core::{CryptoRng, RngCore}; use std::fmt; use std::str; @@ -544,11 +544,6 @@ pub fn try_sapling_output_recovery( #[cfg(test)] mod tests { - use crypto_api_chachapoly::ChachaPolyIetf; - use ff::{Field, PrimeField, PrimeFieldRepr}; - use pairing::bls12_381::{Bls12, Fr, FrRepr}; - use rand_core::{CryptoRng, RngCore}; - use rand_os::OsRng; use crate::{ jubjub::{ edwards, @@ -557,6 +552,11 @@ mod tests { }, primitives::{Diversifier, PaymentAddress, ValueCommitment}, }; + use crypto_api_chachapoly::ChachaPolyIetf; + use ff::{Field, PrimeField, PrimeFieldRepr}; + use pairing::bls12_381::{Bls12, Fr, FrRepr}; + use rand_core::{CryptoRng, RngCore}; + use rand_os::OsRng; use super::{ kdf_sapling, prf_ock, sapling_ka_agree, try_sapling_compact_note_decryption, diff --git a/zcash_primitives/src/pedersen_hash.rs b/zcash_primitives/src/pedersen_hash.rs index aacca37..f21b17b 100644 --- a/zcash_primitives/src/pedersen_hash.rs +++ b/zcash_primitives/src/pedersen_hash.rs @@ -4,14 +4,13 @@ use jubjub::*; #[derive(Copy, Clone)] pub enum Personalization { NoteCommitment, - MerkleTree(usize) + MerkleTree(usize), } impl Personalization { pub fn get_bits(&self) -> Vec { match *self { - Personalization::NoteCommitment => - vec![true, true, true, true, true, true], + Personalization::NoteCommitment => vec![true, true, true, true, true, true], Personalization::MerkleTree(num) => { assert!(num < 63); @@ -24,12 +23,16 @@ impl Personalization { pub fn pedersen_hash( personalization: Personalization, bits: I, - params: &E::Params + params: &E::Params, ) -> edwards::Point - where I: IntoIterator, - E: JubjubEngine +where + I: IntoIterator, + E: JubjubEngine, { - let mut bits = personalization.get_bits().into_iter().chain(bits.into_iter()); + let mut bits = personalization + .get_bits() + .into_iter() + .chain(bits.into_iter()); let mut result = edwards::Point::zero(); let mut generators = params.pedersen_hash_exp_table().iter(); @@ -79,12 +82,13 @@ pub fn pedersen_hash( break; } - let mut table: &[Vec>] = &generators.next().expect("we don't have enough generators"); + let mut table: &[Vec>] = + &generators.next().expect("we don't have enough generators"); let window = JubjubBls12::pedersen_hash_exp_window_size(); let window_mask = (1 << window) - 1; let mut acc = acc.into_repr(); - + let mut tmp = edwards::Point::zero(); while !acc.is_zero() { diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index 4026392..d1282b7 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -4,60 +4,47 @@ use constants; use group_hash::group_hash; -use pedersen_hash::{ - pedersen_hash, - Personalization -}; +use pedersen_hash::{pedersen_hash, Personalization}; -use byteorder::{ - LittleEndian, - WriteBytesExt -}; +use byteorder::{LittleEndian, WriteBytesExt}; -use jubjub::{ - JubjubEngine, - JubjubParams, - edwards, - PrimeOrder, - FixedGenerators -}; +use jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder}; use blake2s_simd::Params as Blake2sParams; #[derive(Clone)] pub struct ValueCommitment { pub value: u64, - pub randomness: E::Fs + pub randomness: E::Fs, } impl ValueCommitment { - pub fn cm( - &self, - params: &E::Params - ) -> edwards::Point - { - params.generator(FixedGenerators::ValueCommitmentValue) - .mul(self.value, params) - .add( - ¶ms.generator(FixedGenerators::ValueCommitmentRandomness) - .mul(self.randomness, params), - params - ) + pub fn cm(&self, params: &E::Params) -> edwards::Point { + params + .generator(FixedGenerators::ValueCommitmentValue) + .mul(self.value, params) + .add( + ¶ms + .generator(FixedGenerators::ValueCommitmentRandomness) + .mul(self.randomness, params), + params, + ) } } #[derive(Clone)] pub struct ProofGenerationKey { pub ak: edwards::Point, - pub nsk: E::Fs + pub nsk: E::Fs, } impl ProofGenerationKey { pub fn into_viewing_key(&self, params: &E::Params) -> ViewingKey { ViewingKey { ak: self.ak.clone(), - nk: params.generator(FixedGenerators::ProofGenerationKey) - .mul(self.nsk, params) + nk: params + .generator(FixedGenerators::ProofGenerationKey) + .mul(self.nsk, params), } } } @@ -65,19 +52,16 @@ impl ProofGenerationKey { #[derive(Debug)] pub struct ViewingKey { pub ak: edwards::Point, - pub nk: edwards::Point + pub nk: edwards::Point, } impl ViewingKey { - pub fn rk( - &self, - ar: E::Fs, - params: &E::Params - ) -> edwards::Point { + pub fn rk(&self, ar: E::Fs, params: &E::Params) -> edwards::Point { self.ak.add( - ¶ms.generator(FixedGenerators::SpendingKeyGenerator) - .mul(ar, params), - params + ¶ms + .generator(FixedGenerators::SpendingKeyGenerator) + .mul(ar, params), + params, ) } @@ -88,11 +72,13 @@ impl ViewingKey { self.nk.write(&mut preimage[32..64]).unwrap(); let mut h = [0; 32]; - h.copy_from_slice(Blake2sParams::new() - .hash_length(32) - .personal(constants::CRH_IVK_PERSONALIZATION) - .hash(&preimage) - .as_bytes()); + h.copy_from_slice( + Blake2sParams::new() + .hash_length(32) + .personal(constants::CRH_IVK_PERSONALIZATION) + .hash(&preimage) + .as_bytes(), + ); // Drop the most significant five bits, so it can be interpreted as a scalar. h[31] &= 0b0000_0111; @@ -106,15 +92,14 @@ impl ViewingKey { pub fn into_payment_address( &self, diversifier: Diversifier, - params: &E::Params - ) -> Option> - { + params: &E::Params, + ) -> Option> { diversifier.g_d(params).map(|g_d| { let pk_d = g_d.mul(self.ivk(), params); PaymentAddress { pk_d: pk_d, - diversifier: diversifier + diversifier: diversifier, } }) } @@ -126,17 +111,20 @@ pub struct Diversifier(pub [u8; 11]); impl Diversifier { pub fn g_d( &self, - params: &E::Params - ) -> Option> - { - group_hash::(&self.0, constants::KEY_DIVERSIFICATION_PERSONALIZATION, params) + params: &E::Params, + ) -> Option> { + group_hash::( + &self.0, + constants::KEY_DIVERSIFICATION_PERSONALIZATION, + params, + ) } } #[derive(Clone, Debug)] pub struct PaymentAddress { pub pk_d: edwards::Point, - pub diversifier: Diversifier + pub diversifier: Diversifier, } impl PartialEq for PaymentAddress { @@ -146,11 +134,7 @@ impl PartialEq for PaymentAddress { } impl PaymentAddress { - pub fn g_d( - &self, - params: &E::Params - ) -> Option> - { + pub fn g_d(&self, params: &E::Params) -> Option> { self.diversifier.g_d(params) } @@ -158,16 +142,13 @@ impl PaymentAddress { &self, value: u64, randomness: E::Fs, - params: &E::Params - ) -> Option> - { - self.g_d(params).map(|g_d| { - Note { - value: value, - r: randomness, - g_d: g_d, - pk_d: self.pk_d.clone() - } + params: &E::Params, + ) -> Option> { + self.g_d(params).map(|g_d| Note { + value: value, + r: randomness, + g_d: g_d, + pk_d: self.pk_d.clone(), }) } } @@ -181,7 +162,7 @@ pub struct Note { /// The public key of the address, g_d^ivk pub pk_d: edwards::Point, /// The commitment randomness - pub r: E::Fs + pub r: E::Fs, } impl PartialEq for Note { @@ -204,13 +185,14 @@ impl Note { } /// Computes the note commitment, returning the full point. - fn cm_full_point(&self, params: &E::Params) -> edwards::Point - { + fn cm_full_point(&self, params: &E::Params) -> edwards::Point { // Calculate the note contents, as bytes let mut note_contents = vec![]; // Writing the value in little endian - (&mut note_contents).write_u64::(self.value).unwrap(); + (&mut note_contents) + .write_u64::(self.value) + .unwrap(); // Write g_d self.g_d.write(&mut note_contents).unwrap(); @@ -223,36 +205,29 @@ impl Note { // Compute the Pedersen hash of the note contents let hash_of_contents = pedersen_hash( Personalization::NoteCommitment, - note_contents.into_iter() - .flat_map(|byte| { - (0..8).map(move |i| ((byte >> i) & 1) == 1) - }), - params + note_contents + .into_iter() + .flat_map(|byte| (0..8).map(move |i| ((byte >> i) & 1) == 1)), + params, ); // Compute final commitment - params.generator(FixedGenerators::NoteCommitmentRandomness) - .mul(self.r, params) - .add(&hash_of_contents, params) + params + .generator(FixedGenerators::NoteCommitmentRandomness) + .mul(self.r, params) + .add(&hash_of_contents, params) } /// Computes the nullifier given the viewing key and /// note position - pub fn nf( - &self, - viewing_key: &ViewingKey, - position: u64, - params: &E::Params - ) -> Vec - { + pub fn nf(&self, viewing_key: &ViewingKey, position: u64, params: &E::Params) -> Vec { // Compute rho = cm + position.G - let rho = self - .cm_full_point(params) - .add( - ¶ms.generator(FixedGenerators::NullifierPosition) - .mul(position, params), - params - ); + let rho = self.cm_full_point(params).add( + ¶ms + .generator(FixedGenerators::NullifierPosition) + .mul(position, params), + params, + ); // Compute nf = BLAKE2s(nk | rho) let mut nf_preimage = [0u8; 64]; @@ -267,8 +242,7 @@ impl Note { } /// Computes the note commitment - pub fn cm(&self, params: &E::Params) -> E::Fr - { + pub fn cm(&self, params: &E::Params) -> E::Fr { // The commitment is in the prime order subgroup, so mapping the // commitment to the x-coordinate is an injective encoding. self.cm_full_point(params).into_xy().0 diff --git a/zcash_primitives/src/prover.rs b/zcash_primitives/src/prover.rs index a434b4e..7c66737 100644 --- a/zcash_primitives/src/prover.rs +++ b/zcash_primitives/src/prover.rs @@ -1,10 +1,10 @@ //! Abstractions over the proving system and parameters. -use pairing::bls12_381::{Bls12, Fr}; use crate::{ jubjub::{edwards, fs::Fs, Unknown}, primitives::{Diversifier, PaymentAddress, ProofGenerationKey}, }; +use pairing::bls12_381::{Bls12, Fr}; use crate::{ merkle_tree::CommitmentTreeWitness, diff --git a/zcash_primitives/src/redjubjub.rs b/zcash_primitives/src/redjubjub.rs index b709419..370f63d 100644 --- a/zcash_primitives/src/redjubjub.rs +++ b/zcash_primitives/src/redjubjub.rs @@ -1,11 +1,9 @@ //! Implementation of RedJubjub, a specialization of RedDSA to the Jubjub curve. //! See section 5.4.6 of the Sapling protocol specification. +use crate::jubjub::{edwards::Point, FixedGenerators, JubjubEngine, JubjubParams, Unknown}; use ff::{Field, PrimeField, PrimeFieldRepr}; use rand_core::RngCore; -use crate::jubjub::{ - edwards::Point, FixedGenerators, JubjubEngine, JubjubParams, Unknown, -}; use std::io::{self, Read, Write}; use util::hash_to_scalar; @@ -150,10 +148,15 @@ impl PublicKey { Err(_) => return false, }; // 0 = h_G(-S . P_G + R + c . vk) - self.0.mul(c, params).add(&r, params).add( - ¶ms.generator(p_g).mul(s, params).negate().into(), - params - ).mul_by_cofactor(params).eq(&Point::zero()) + self.0 + .mul(c, params) + .add(&r, params) + .add( + ¶ms.generator(p_g).mul(s, params).negate().into(), + params, + ) + .mul_by_cofactor(params) + .eq(&Point::zero()) } } @@ -170,8 +173,7 @@ pub fn batch_verify<'a, E: JubjubEngine, R: RngCore>( batch: &[BatchEntry<'a, E>], p_g: FixedGenerators, params: &E::Params, -) -> bool -{ +) -> bool { let mut acc = Point::::zero(); for entry in batch { @@ -218,8 +220,8 @@ mod tests { #[test] fn test_batch_verify() { let rng = &mut XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); let params = &JubjubBls12::new(); let p_g = FixedGenerators::SpendingKeyGenerator; @@ -237,8 +239,16 @@ mod tests { assert!(vk2.verify(msg2, &sig2, p_g, params)); let mut batch = vec![ - BatchEntry { vk: vk1, msg: msg1, sig: sig1 }, - BatchEntry { vk: vk2, msg: msg2, sig: sig2 } + BatchEntry { + vk: vk1, + msg: msg1, + sig: sig1, + }, + BatchEntry { + vk: vk2, + msg: msg2, + sig: sig2, + }, ]; assert!(batch_verify(rng, &batch, p_g, params)); @@ -251,8 +261,8 @@ mod tests { #[test] fn cofactor_check() { let rng = &mut XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); let params = &JubjubBls12::new(); let zero = edwards::Point::zero(); @@ -286,8 +296,8 @@ mod tests { #[test] fn round_trip_serialization() { let rng = &mut XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); let p_g = FixedGenerators::SpendingKeyGenerator; let params = &JubjubBls12::new(); @@ -322,8 +332,8 @@ mod tests { #[test] fn random_signatures() { let rng = &mut XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); let p_g = FixedGenerators::SpendingKeyGenerator; let params = &JubjubBls12::new(); diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index 4590c79..02282d3 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -1,13 +1,13 @@ //! Structs and constants specific to the Sapling shielded pool. -use ff::{BitIterator, PrimeField, PrimeFieldRepr}; -use pairing::bls12_381::{Bls12, Fr, FrRepr}; -use rand_core::{CryptoRng, RngCore}; use crate::{ jubjub::{fs::Fs, FixedGenerators, JubjubBls12}, pedersen_hash::{pedersen_hash, Personalization}, primitives::Note, }; +use ff::{BitIterator, PrimeField, PrimeFieldRepr}; +use pairing::bls12_381::{Bls12, Fr, FrRepr}; +use rand_core::{CryptoRng, RngCore}; use std::io::{self, Read, Write}; use crate::merkle_tree::Hashable; diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index f32af7a..b0e96f5 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -1,12 +1,12 @@ //! Structs for building transactions. -use ff::Field; -use pairing::bls12_381::{Bls12, Fr}; -use rand::{rngs::OsRng, seq::SliceRandom, CryptoRng, RngCore}; use crate::{ jubjub::fs::Fs, primitives::{Diversifier, Note, PaymentAddress}, }; +use ff::Field; +use pairing::bls12_381::{Bls12, Fr}; +use rand::{rngs::OsRng, seq::SliceRandom, CryptoRng, RngCore}; use zip32::ExtendedSpendingKey; use crate::{ diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index c8cfadc..7d2ffbb 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -1,7 +1,7 @@ +use crate::jubjub::{edwards, Unknown}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; -use crate::jubjub::{edwards, Unknown}; use std::io::{self, Read, Write}; use legacy::Script; diff --git a/zcash_primitives/src/zip32.rs b/zcash_primitives/src/zip32.rs index 44b55f5..7412406 100644 --- a/zcash_primitives/src/zip32.rs +++ b/zcash_primitives/src/zip32.rs @@ -135,7 +135,10 @@ impl DiversifierKey { /// Returns the first index starting from j that generates a valid /// diversifier, along with the corresponding diversifier. Returns /// an error if the diversifier space is exhausted. - pub fn diversifier(&self, mut j: DiversifierIndex) -> Result<(DiversifierIndex, Diversifier), ()> { + pub fn diversifier( + &self, + mut j: DiversifierIndex, + ) -> Result<(DiversifierIndex, Diversifier), ()> { let ff = FF1::::new(&self.0, 2).unwrap(); loop { // Generate d_j From 272be622128eb3dfabe63f9abb8fe91c77257e2c Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Thu, 15 Aug 2019 10:40:07 -0600 Subject: [PATCH 076/330] cargo fmt zcash_proofs --- zcash_proofs/examples/bench.rs | 69 +-- zcash_proofs/src/circuit/ecc.rs | 547 +++++++----------- zcash_proofs/src/circuit/pedersen_hash.rs | 109 ++-- zcash_proofs/src/circuit/sapling.rs | 287 ++++----- zcash_proofs/src/circuit/sprout/commitment.rs | 21 +- zcash_proofs/src/circuit/sprout/input.rs | 113 ++-- zcash_proofs/src/circuit/sprout/mod.rs | 194 +++---- zcash_proofs/src/circuit/sprout/output.rs | 36 +- zcash_proofs/src/circuit/sprout/prfs.rs | 60 +- zcash_proofs/src/prover.rs | 2 +- zcash_proofs/src/sapling/prover.rs | 4 +- 11 files changed, 595 insertions(+), 847 deletions(-) diff --git a/zcash_proofs/examples/bench.rs b/zcash_proofs/examples/bench.rs index a187ec6..a5c8a13 100644 --- a/zcash_proofs/examples/bench.rs +++ b/zcash_proofs/examples/bench.rs @@ -1,30 +1,20 @@ -extern crate ff; extern crate bellman; +extern crate ff; extern crate pairing; extern crate rand_core; extern crate rand_xorshift; extern crate zcash_primitives; extern crate zcash_proofs; -use ff::Field; -use std::time::{Duration, Instant}; -use zcash_primitives::jubjub::{ - JubjubBls12, - edwards, - fs, -}; -use zcash_proofs::circuit::sapling::{ - Spend -}; -use zcash_primitives::primitives::{ - Diversifier, - ProofGenerationKey, - ValueCommitment -}; use bellman::groth16::*; +use ff::Field; +use pairing::bls12_381::{Bls12, Fr}; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; -use pairing::bls12_381::{Bls12, Fr}; +use std::time::{Duration, Instant}; +use zcash_primitives::jubjub::{edwards, fs, JubjubBls12}; +use zcash_primitives::primitives::{Diversifier, ProofGenerationKey, ValueCommitment}; +use zcash_proofs::circuit::sapling::Spend; const TREE_DEPTH: usize = 32; @@ -45,10 +35,11 @@ fn main() { commitment_randomness: None, ar: None, auth_path: vec![None; TREE_DEPTH], - anchor: None + anchor: None, }, - rng - ).unwrap(); + rng, + ) + .unwrap(); const SAMPLES: u32 = 50; @@ -56,7 +47,7 @@ fn main() { for _ in 0..SAMPLES { let value_commitment = ValueCommitment { value: 1, - randomness: fs::Fs::random(rng) + randomness: fs::Fs::random(rng), }; let nsk = fs::Fs::random(rng); @@ -64,7 +55,7 @@ fn main() { let proof_generation_key = ProofGenerationKey { ak: ak.clone(), - nsk: nsk.clone() + nsk: nsk.clone(), }; let viewing_key = proof_generation_key.into_viewing_key(jubjub_params); @@ -78,11 +69,7 @@ fn main() { Diversifier(d) }; - if let Some(p) = viewing_key.into_payment_address( - diversifier, - jubjub_params - ) - { + if let Some(p) = viewing_key.into_payment_address(diversifier, jubjub_params) { payment_address = p; break; } @@ -94,21 +81,25 @@ fn main() { let anchor = Fr::random(rng); let start = Instant::now(); - let _ = create_random_proof(Spend { - params: jubjub_params, - value_commitment: Some(value_commitment), - proof_generation_key: Some(proof_generation_key), - payment_address: Some(payment_address), - commitment_randomness: Some(commitment_randomness), - ar: Some(ar), - auth_path: auth_path, - anchor: Some(anchor) - }, &groth_params, rng).unwrap(); + let _ = create_random_proof( + Spend { + params: jubjub_params, + value_commitment: Some(value_commitment), + proof_generation_key: Some(proof_generation_key), + payment_address: Some(payment_address), + commitment_randomness: Some(commitment_randomness), + ar: Some(ar), + auth_path: auth_path, + anchor: Some(anchor), + }, + &groth_params, + rng, + ) + .unwrap(); total_time += start.elapsed(); } let avg = total_time / SAMPLES; - let avg = avg.subsec_nanos() as f64 / 1_000_000_000f64 - + (avg.as_secs() as f64); + let avg = avg.subsec_nanos() as f64 / 1_000_000_000f64 + (avg.as_secs() as f64); println!("Average proving time (in seconds): {}", avg); } diff --git a/zcash_proofs/src/circuit/ecc.rs b/zcash_proofs/src/circuit/ecc.rs index 593c57d..4c07829 100644 --- a/zcash_proofs/src/circuit/ecc.rs +++ b/zcash_proofs/src/circuit/ecc.rs @@ -1,37 +1,22 @@ use ff::Field; use pairing::Engine; -use bellman::{ - SynthesisError, - ConstraintSystem -}; +use bellman::{ConstraintSystem, SynthesisError}; -use bellman::gadgets::{ - Assignment -}; +use bellman::gadgets::Assignment; -use bellman::gadgets::num::{ - AllocatedNum, - Num -}; +use bellman::gadgets::num::{AllocatedNum, Num}; -use zcash_primitives::jubjub::{ - edwards, - JubjubEngine, - JubjubParams, - FixedGenerators -}; +use zcash_primitives::jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams}; -use bellman::gadgets::lookup::{ - lookup3_xy -}; +use bellman::gadgets::lookup::lookup3_xy; use bellman::gadgets::boolean::Boolean; #[derive(Clone)] pub struct EdwardsPoint { x: AllocatedNum, - y: AllocatedNum + y: AllocatedNum, } /// Perform a fixed-base scalar multiplication with @@ -40,32 +25,40 @@ pub fn fixed_base_multiplication( mut cs: CS, base: FixedGenerators, by: &[Boolean], - params: &E::Params + params: &E::Params, ) -> Result, SynthesisError> - where CS: ConstraintSystem, - E: JubjubEngine +where + CS: ConstraintSystem, + E: JubjubEngine, { // Represents the result of the multiplication let mut result = None; - for (i, (chunk, window)) in by.chunks(3) - .zip(params.circuit_generators(base).iter()) - .enumerate() + for (i, (chunk, window)) in by + .chunks(3) + .zip(params.circuit_generators(base).iter()) + .enumerate() { - let chunk_a = chunk.get(0).map(|e| e.clone()).unwrap_or(Boolean::constant(false)); - let chunk_b = chunk.get(1).map(|e| e.clone()).unwrap_or(Boolean::constant(false)); - let chunk_c = chunk.get(2).map(|e| e.clone()).unwrap_or(Boolean::constant(false)); + let chunk_a = chunk + .get(0) + .map(|e| e.clone()) + .unwrap_or(Boolean::constant(false)); + let chunk_b = chunk + .get(1) + .map(|e| e.clone()) + .unwrap_or(Boolean::constant(false)); + let chunk_c = chunk + .get(2) + .map(|e| e.clone()) + .unwrap_or(Boolean::constant(false)); let (x, y) = lookup3_xy( cs.namespace(|| format!("window table lookup {}", i)), &[chunk_a, chunk_b, chunk_c], - window + window, )?; - let p = EdwardsPoint { - x: x, - y: y - }; + let p = EdwardsPoint { x: x, y: y }; if result.is_none() { result = Some(p); @@ -73,7 +66,7 @@ pub fn fixed_base_multiplication( result = Some(result.unwrap().add( cs.namespace(|| format!("addition {}", i)), &p, - params + params, )?); } } @@ -93,22 +86,14 @@ impl EdwardsPoint { pub fn assert_not_small_order( &self, mut cs: CS, - params: &E::Params + params: &E::Params, ) -> Result<(), SynthesisError> - where CS: ConstraintSystem + where + CS: ConstraintSystem, { - let tmp = self.double( - cs.namespace(|| "first doubling"), - params - )?; - let tmp = tmp.double( - cs.namespace(|| "second doubling"), - params - )?; - let tmp = tmp.double( - cs.namespace(|| "third doubling"), - params - )?; + let tmp = self.double(cs.namespace(|| "first doubling"), params)?; + let tmp = tmp.double(cs.namespace(|| "second doubling"), params)?; + let tmp = tmp.double(cs.namespace(|| "third doubling"), params)?; // (0, -1) is a small order point, but won't ever appear here // because cofactor is 2^3, and we performed three doublings. @@ -119,11 +104,9 @@ impl EdwardsPoint { Ok(()) } - pub fn inputize( - &self, - mut cs: CS - ) -> Result<(), SynthesisError> - where CS: ConstraintSystem + pub fn inputize(&self, mut cs: CS) -> Result<(), SynthesisError> + where + CS: ConstraintSystem, { self.x.inputize(cs.namespace(|| "x"))?; self.y.inputize(cs.namespace(|| "y"))?; @@ -132,21 +115,15 @@ impl EdwardsPoint { } /// This converts the point into a representation. - pub fn repr( - &self, - mut cs: CS - ) -> Result, SynthesisError> - where CS: ConstraintSystem + pub fn repr(&self, mut cs: CS) -> Result, SynthesisError> + where + CS: ConstraintSystem, { let mut tmp = vec![]; - let x = self.x.into_bits_le_strict( - cs.namespace(|| "unpack x") - )?; + let x = self.x.into_bits_le_strict(cs.namespace(|| "unpack x"))?; - let y = self.y.into_bits_le_strict( - cs.namespace(|| "unpack y") - )?; + let y = self.y.into_bits_le_strict(cs.namespace(|| "unpack y"))?; tmp.extend(y); tmp.push(x[0].clone()); @@ -159,34 +136,20 @@ impl EdwardsPoint { pub fn witness( mut cs: CS, p: Option>, - params: &E::Params + params: &E::Params, ) -> Result - where CS: ConstraintSystem + where + CS: ConstraintSystem, { let p = p.map(|p| p.into_xy()); // Allocate x - let x = AllocatedNum::alloc( - cs.namespace(|| "x"), - || { - Ok(p.get()?.0) - } - )?; + let x = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(p.get()?.0))?; // Allocate y - let y = AllocatedNum::alloc( - cs.namespace(|| "y"), - || { - Ok(p.get()?.1) - } - )?; + let y = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(p.get()?.1))?; - Self::interpret( - cs.namespace(|| "point interpretation"), - &x, - &y, - params - ) + Self::interpret(cs.namespace(|| "point interpretation"), &x, &y, params) } /// Returns `self` if condition is true, and the neutral @@ -194,9 +157,10 @@ impl EdwardsPoint { pub fn conditionally_select( &self, mut cs: CS, - condition: &Boolean + condition: &Boolean, ) -> Result - where CS: ConstraintSystem + where + CS: ConstraintSystem, { // Compute x' = self.x if condition, and 0 otherwise let x_prime = AllocatedNum::alloc(cs.namespace(|| "x'"), || { @@ -215,7 +179,7 @@ impl EdwardsPoint { || "x' computation", |lc| lc + self.x.get_variable(), |_| condition.lc(one, E::Fr::one()), - |lc| lc + x_prime.get_variable() + |lc| lc + x_prime.get_variable(), ); // Compute y' = self.y if condition, and 1 otherwise @@ -234,13 +198,12 @@ impl EdwardsPoint { || "y' computation", |lc| lc + self.y.get_variable(), |_| condition.lc(one, E::Fr::one()), - |lc| lc + y_prime.get_variable() - - &condition.not().lc(one, E::Fr::one()) + |lc| lc + y_prime.get_variable() - &condition.not().lc(one, E::Fr::one()), ); Ok(EdwardsPoint { x: x_prime, - y: y_prime + y: y_prime, }) } @@ -251,9 +214,10 @@ impl EdwardsPoint { &self, mut cs: CS, by: &[Boolean], - params: &E::Params + params: &E::Params, ) -> Result - where CS: ConstraintSystem + where + CS: ConstraintSystem, { // Represents the current "magnitude" of the base // that we're operating over. Starts at self, @@ -269,8 +233,9 @@ impl EdwardsPoint { } else { // Double the previous value curbase = Some( - curbase.unwrap() - .double(cs.namespace(|| format!("doubling {}", i)), params)? + curbase + .unwrap() + .double(cs.namespace(|| format!("doubling {}", i)), params)?, ); } @@ -278,12 +243,10 @@ impl EdwardsPoint { // is true, this will return `curbase`. Otherwise it will // return the neutral element, which will have no effect on // the result. - let thisbase = curbase.as_ref() - .unwrap() - .conditionally_select( - cs.namespace(|| format!("selection {}", i)), - bit - )?; + let thisbase = curbase + .as_ref() + .unwrap() + .conditionally_select(cs.namespace(|| format!("selection {}", i)), bit)?; if result.is_none() { result = Some(thisbase); @@ -291,7 +254,7 @@ impl EdwardsPoint { result = Some(result.unwrap().add( cs.namespace(|| format!("addition {}", i)), &thisbase, - params + params, )?); } } @@ -303,9 +266,10 @@ impl EdwardsPoint { mut cs: CS, x: &AllocatedNum, y: &AllocatedNum, - params: &E::Params + params: &E::Params, ) -> Result - where CS: ConstraintSystem + where + CS: ConstraintSystem, { // -x^2 + y^2 = 1 + dx^2y^2 @@ -316,25 +280,20 @@ impl EdwardsPoint { let one = CS::one(); cs.enforce( || "on curve check", - |lc| lc - x2.get_variable() - + y2.get_variable(), + |lc| lc - x2.get_variable() + y2.get_variable(), |lc| lc + one, - |lc| lc + one - + (*params.edwards_d(), x2y2.get_variable()) + |lc| lc + one + (*params.edwards_d(), x2y2.get_variable()), ); Ok(EdwardsPoint { x: x.clone(), - y: y.clone() + y: y.clone(), }) } - pub fn double( - &self, - mut cs: CS, - params: &E::Params - ) -> Result - where CS: ConstraintSystem + pub fn double(&self, mut cs: CS, params: &E::Params) -> Result + where + CS: ConstraintSystem, { // Compute T = (x1 + y1) * (x1 + y1) let t = AllocatedNum::alloc(cs.namespace(|| "T"), || { @@ -351,11 +310,9 @@ impl EdwardsPoint { cs.enforce( || "T computation", - |lc| lc + self.x.get_variable() - + self.y.get_variable(), - |lc| lc + self.x.get_variable() - + self.y.get_variable(), - |lc| lc + t.get_variable() + |lc| lc + self.x.get_variable() + self.y.get_variable(), + |lc| lc + self.x.get_variable() + self.y.get_variable(), + |lc| lc + t.get_variable(), ); // Compute A = x1 * y1 @@ -374,7 +331,7 @@ impl EdwardsPoint { || "C computation", |lc| lc + (*params.edwards_d(), a.get_variable()), |lc| lc + a.get_variable(), - |lc| lc + c.get_variable() + |lc| lc + c.get_variable(), ); // Compute x3 = (2.A) / (1 + C) @@ -390,10 +347,8 @@ impl EdwardsPoint { t0.mul_assign(&t1); Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) } + None => Err(SynthesisError::DivisionByZero), } })?; @@ -402,8 +357,7 @@ impl EdwardsPoint { || "x3 computation", |lc| lc + one + c.get_variable(), |lc| lc + x3.get_variable(), - |lc| lc + a.get_variable() - + a.get_variable() + |lc| lc + a.get_variable() + a.get_variable(), ); // Compute y3 = (U - 2.A) / (1 - C) @@ -421,10 +375,8 @@ impl EdwardsPoint { t0.mul_assign(&t1); Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) } + None => Err(SynthesisError::DivisionByZero), } })?; @@ -432,15 +384,10 @@ impl EdwardsPoint { || "y3 computation", |lc| lc + one - c.get_variable(), |lc| lc + y3.get_variable(), - |lc| lc + t.get_variable() - - a.get_variable() - - a.get_variable() + |lc| lc + t.get_variable() - a.get_variable() - a.get_variable(), ); - Ok(EdwardsPoint { - x: x3, - y: y3 - }) + Ok(EdwardsPoint { x: x3, y: y3 }) } /// Perform addition between any two points @@ -448,9 +395,10 @@ impl EdwardsPoint { &self, mut cs: CS, other: &Self, - params: &E::Params + params: &E::Params, ) -> Result - where CS: ConstraintSystem + where + CS: ConstraintSystem, { // Compute U = (x1 + y1) * (x2 + y2) let u = AllocatedNum::alloc(cs.namespace(|| "U"), || { @@ -467,11 +415,9 @@ impl EdwardsPoint { cs.enforce( || "U computation", - |lc| lc + self.x.get_variable() - + self.y.get_variable(), - |lc| lc + other.x.get_variable() - + other.y.get_variable(), - |lc| lc + u.get_variable() + |lc| lc + self.x.get_variable() + self.y.get_variable(), + |lc| lc + other.x.get_variable() + other.y.get_variable(), + |lc| lc + u.get_variable(), ); // Compute A = y2 * x1 @@ -493,7 +439,7 @@ impl EdwardsPoint { || "C computation", |lc| lc + (*params.edwards_d(), a.get_variable()), |lc| lc + b.get_variable(), - |lc| lc + c.get_variable() + |lc| lc + c.get_variable(), ); // Compute x3 = (A + B) / (1 + C) @@ -509,10 +455,8 @@ impl EdwardsPoint { t0.mul_assign(&t1); Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) } + None => Err(SynthesisError::DivisionByZero), } })?; @@ -521,8 +465,7 @@ impl EdwardsPoint { || "x3 computation", |lc| lc + one + c.get_variable(), |lc| lc + x3.get_variable(), - |lc| lc + a.get_variable() - + b.get_variable() + |lc| lc + a.get_variable() + b.get_variable(), ); // Compute y3 = (U - A - B) / (1 - C) @@ -539,10 +482,8 @@ impl EdwardsPoint { t0.mul_assign(&t1); Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) } + None => Err(SynthesisError::DivisionByZero), } })?; @@ -550,21 +491,16 @@ impl EdwardsPoint { || "y3 computation", |lc| lc + one - c.get_variable(), |lc| lc + y3.get_variable(), - |lc| lc + u.get_variable() - - a.get_variable() - - b.get_variable() + |lc| lc + u.get_variable() - a.get_variable() - b.get_variable(), ); - Ok(EdwardsPoint { - x: x3, - y: y3 - }) + Ok(EdwardsPoint { x: x3, y: y3 }) } } pub struct MontgomeryPoint { x: Num, - y: Num + y: Num, } impl MontgomeryPoint { @@ -574,9 +510,10 @@ impl MontgomeryPoint { pub fn into_edwards( &self, mut cs: CS, - params: &E::Params + params: &E::Params, ) -> Result, SynthesisError> - where CS: ConstraintSystem + where + CS: ConstraintSystem, { // Compute u = (scale*x) / y let u = AllocatedNum::alloc(cs.namespace(|| "u"), || { @@ -588,10 +525,8 @@ impl MontgomeryPoint { t0.mul_assign(&invy); Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) } + None => Err(SynthesisError::DivisionByZero), } })?; @@ -599,7 +534,7 @@ impl MontgomeryPoint { || "u computation", |lc| lc + &self.y.lc(E::Fr::one()), |lc| lc + u.get_variable(), - |lc| lc + &self.x.lc(*params.scale()) + |lc| lc + &self.x.lc(*params.scale()), ); // Compute v = (x - 1) / (x + 1) @@ -614,42 +549,28 @@ impl MontgomeryPoint { t0.mul_assign(&t1); Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) } + None => Err(SynthesisError::DivisionByZero), } })?; let one = CS::one(); cs.enforce( || "v computation", - |lc| lc + &self.x.lc(E::Fr::one()) - + one, + |lc| lc + &self.x.lc(E::Fr::one()) + one, |lc| lc + v.get_variable(), - |lc| lc + &self.x.lc(E::Fr::one()) - - one, + |lc| lc + &self.x.lc(E::Fr::one()) - one, ); - Ok(EdwardsPoint { - x: u, - y: v - }) + Ok(EdwardsPoint { x: u, y: v }) } /// Interprets an (x, y) pair as a point /// in Montgomery, does not check that it's /// on the curve. Useful for constants and /// window table lookups. - pub fn interpret_unchecked( - x: Num, - y: Num - ) -> Self - { - MontgomeryPoint { - x: x, - y: y - } + pub fn interpret_unchecked(x: Num, y: Num) -> Self { + MontgomeryPoint { x: x, y: y } } /// Performs an affine point addition, not defined for @@ -658,9 +579,10 @@ impl MontgomeryPoint { &self, mut cs: CS, other: &Self, - params: &E::Params + params: &E::Params, ) -> Result - where CS: ConstraintSystem + where + CS: ConstraintSystem, { // Compute lambda = (y' - y) / (x' - x) let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || { @@ -674,22 +596,16 @@ impl MontgomeryPoint { Some(d) => { n.mul_assign(&d); Ok(n) - }, - None => { - Err(SynthesisError::DivisionByZero) } + None => Err(SynthesisError::DivisionByZero), } })?; cs.enforce( || "evaluate lambda", - |lc| lc + &other.x.lc(E::Fr::one()) - - &self.x.lc(E::Fr::one()), - + |lc| lc + &other.x.lc(E::Fr::one()) - &self.x.lc(E::Fr::one()), |lc| lc + lambda.get_variable(), - - |lc| lc + &other.y.lc(E::Fr::one()) - - &self.y.lc(E::Fr::one()) + |lc| lc + &other.y.lc(E::Fr::one()) - &self.y.lc(E::Fr::one()), ); // Compute x'' = lambda^2 - A - x - x' @@ -709,10 +625,12 @@ impl MontgomeryPoint { || "evaluate xprime", |lc| lc + lambda.get_variable(), |lc| lc + lambda.get_variable(), - |lc| lc + (*params.montgomery_a(), one) + |lc| { + lc + (*params.montgomery_a(), one) + &self.x.lc(E::Fr::one()) + &other.x.lc(E::Fr::one()) + xprime.get_variable() + }, ); // Compute y' = -(y + lambda(x' - x)) @@ -729,57 +647,41 @@ impl MontgomeryPoint { // y' + y = lambda(x - x') cs.enforce( || "evaluate yprime", - |lc| lc + &self.x.lc(E::Fr::one()) - - xprime.get_variable(), - + |lc| lc + &self.x.lc(E::Fr::one()) - xprime.get_variable(), |lc| lc + lambda.get_variable(), - - |lc| lc + yprime.get_variable() - + &self.y.lc(E::Fr::one()) + |lc| lc + yprime.get_variable() + &self.y.lc(E::Fr::one()), ); Ok(MontgomeryPoint { x: xprime.into(), - y: yprime.into() + y: yprime.into(), }) } } #[cfg(test)] mod test { - use bellman::{ConstraintSystem}; + use bellman::ConstraintSystem; use ff::{BitIterator, Field, PrimeField}; use pairing::bls12_381::{Bls12, Fr}; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; use bellman::gadgets::test::*; - use zcash_primitives::jubjub::{ - montgomery, - edwards, - JubjubBls12, - JubjubParams, - FixedGenerators - }; use zcash_primitives::jubjub::fs::Fs; + use zcash_primitives::jubjub::{ + edwards, montgomery, FixedGenerators, JubjubBls12, JubjubParams, + }; - use super::{ - MontgomeryPoint, - EdwardsPoint, - AllocatedNum, - fixed_base_multiplication - }; - use bellman::gadgets::boolean::{ - Boolean, - AllocatedBit - }; + use super::{fixed_base_multiplication, AllocatedNum, EdwardsPoint, MontgomeryPoint}; + use bellman::gadgets::boolean::{AllocatedBit, Boolean}; #[test] fn test_into_edwards() { let params = &JubjubBls12::new(); let rng = &mut XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..100 { @@ -789,12 +691,8 @@ mod test { let (u, v) = edwards::Point::from_montgomery(&p, params).into_xy(); let (x, y) = p.into_xy().unwrap(); - let numx = AllocatedNum::alloc(cs.namespace(|| "mont x"), || { - Ok(x) - }).unwrap(); - let numy = AllocatedNum::alloc(cs.namespace(|| "mont y"), || { - Ok(y) - }).unwrap(); + let numx = AllocatedNum::alloc(cs.namespace(|| "mont x"), || Ok(x)).unwrap(); + let numy = AllocatedNum::alloc(cs.namespace(|| "mont y"), || Ok(y)).unwrap(); let p = MontgomeryPoint::interpret_unchecked(numx.into(), numy.into()); @@ -820,19 +718,15 @@ mod test { fn test_interpret() { let params = &JubjubBls12::new(); let rng = &mut XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..100 { let p = edwards::Point::::rand(rng, ¶ms); let mut cs = TestConstraintSystem::::new(); - let q = EdwardsPoint::witness( - &mut cs, - Some(p.clone()), - ¶ms - ).unwrap(); + let q = EdwardsPoint::witness(&mut cs, Some(p.clone()), ¶ms).unwrap(); let p = p.into_xy(); @@ -846,12 +740,8 @@ mod test { let (x, y) = p.into_xy(); let mut cs = TestConstraintSystem::::new(); - let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || { - Ok(x) - }).unwrap(); - let numy = AllocatedNum::alloc(cs.namespace(|| "y"), || { - Ok(y) - }).unwrap(); + let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(x)).unwrap(); + let numy = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(y)).unwrap(); let p = EdwardsPoint::interpret(&mut cs, &numx, &numy, ¶ms).unwrap(); @@ -866,12 +756,8 @@ mod test { let y = Fr::random(rng); let mut cs = TestConstraintSystem::::new(); - let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || { - Ok(x) - }).unwrap(); - let numy = AllocatedNum::alloc(cs.namespace(|| "y"), || { - Ok(y) - }).unwrap(); + let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(x)).unwrap(); + let numy = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(y)).unwrap(); EdwardsPoint::interpret(&mut cs, &numx, &numy, ¶ms).unwrap(); @@ -880,11 +766,11 @@ mod test { } #[test] - fn test_edwards_fixed_base_multiplication() { + fn test_edwards_fixed_base_multiplication() { let params = &JubjubBls12::new(); let rng = &mut XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..100 { @@ -899,18 +785,23 @@ mod test { s_bits.reverse(); s_bits.truncate(Fs::NUM_BITS as usize); - let s_bits = s_bits.into_iter() - .enumerate() - .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("scalar bit {}", i)), Some(b)).unwrap()) - .map(|v| Boolean::from(v)) - .collect::>(); + let s_bits = s_bits + .into_iter() + .enumerate() + .map(|(i, b)| { + AllocatedBit::alloc(cs.namespace(|| format!("scalar bit {}", i)), Some(b)) + .unwrap() + }) + .map(|v| Boolean::from(v)) + .collect::>(); let q = fixed_base_multiplication( cs.namespace(|| "multiplication"), FixedGenerators::NoteCommitmentRandomness, &s_bits, - params - ).unwrap(); + params, + ) + .unwrap(); assert_eq!(q.x.get_value().unwrap(), x1); assert_eq!(q.y.get_value().unwrap(), y1); @@ -921,8 +812,8 @@ mod test { fn test_edwards_multiplication() { let params = &JubjubBls12::new(); let rng = &mut XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..100 { @@ -935,45 +826,37 @@ mod test { let (x0, y0) = p.into_xy(); let (x1, y1) = q.into_xy(); - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || { - Ok(x0) - }).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || { - Ok(y0) - }).unwrap(); + let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || Ok(x0)).unwrap(); + let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || Ok(y0)).unwrap(); let p = EdwardsPoint { x: num_x0, - y: num_y0 + y: num_y0, }; let mut s_bits = BitIterator::new(s.into_repr()).collect::>(); s_bits.reverse(); s_bits.truncate(Fs::NUM_BITS as usize); - let s_bits = s_bits.into_iter() - .enumerate() - .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("scalar bit {}", i)), Some(b)).unwrap()) - .map(|v| Boolean::from(v)) - .collect::>(); + let s_bits = s_bits + .into_iter() + .enumerate() + .map(|(i, b)| { + AllocatedBit::alloc(cs.namespace(|| format!("scalar bit {}", i)), Some(b)) + .unwrap() + }) + .map(|v| Boolean::from(v)) + .collect::>(); - let q = p.mul( - cs.namespace(|| "scalar mul"), - &s_bits, - params - ).unwrap(); + let q = p + .mul(cs.namespace(|| "scalar mul"), &s_bits, params) + .unwrap(); assert!(cs.is_satisfied()); - assert_eq!( - q.x.get_value().unwrap(), - x1 - ); + assert_eq!(q.x.get_value().unwrap(), x1); - assert_eq!( - q.y.get_value().unwrap(), - y1 - ); + assert_eq!(q.y.get_value().unwrap(), y1); } } @@ -981,8 +864,8 @@ mod test { fn test_conditionally_select() { let params = &JubjubBls12::new(); let rng = &mut XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..1000 { @@ -992,26 +875,22 @@ mod test { let (x0, y0) = p.into_xy(); - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || { - Ok(x0) - }).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || { - Ok(y0) - }).unwrap(); + let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || Ok(x0)).unwrap(); + let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || Ok(y0)).unwrap(); let p = EdwardsPoint { x: num_x0, - y: num_y0 + y: num_y0, }; let mut should_we_select = rng.next_u32() % 2 != 0; // Conditionally allocate let mut b = if rng.next_u32() % 2 != 0 { - Boolean::from(AllocatedBit::alloc( - cs.namespace(|| "condition"), - Some(should_we_select) - ).unwrap()) + Boolean::from( + AllocatedBit::alloc(cs.namespace(|| "condition"), Some(should_we_select)) + .unwrap(), + ) } else { Boolean::constant(should_we_select) }; @@ -1022,7 +901,9 @@ mod test { should_we_select = !should_we_select; } - let q = p.conditionally_select(cs.namespace(|| "select"), &b).unwrap(); + let q = p + .conditionally_select(cs.namespace(|| "select"), &b) + .unwrap(); assert!(cs.is_satisfied()); @@ -1050,8 +931,8 @@ mod test { fn test_edwards_addition() { let params = &JubjubBls12::new(); let rng = &mut XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..100 { @@ -1066,28 +947,20 @@ mod test { let mut cs = TestConstraintSystem::::new(); - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || { - Ok(x0) - }).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || { - Ok(y0) - }).unwrap(); + let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || Ok(x0)).unwrap(); + let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || Ok(y0)).unwrap(); - let num_x1 = AllocatedNum::alloc(cs.namespace(|| "x1"), || { - Ok(x1) - }).unwrap(); - let num_y1 = AllocatedNum::alloc(cs.namespace(|| "y1"), || { - Ok(y1) - }).unwrap(); + let num_x1 = AllocatedNum::alloc(cs.namespace(|| "x1"), || Ok(x1)).unwrap(); + let num_y1 = AllocatedNum::alloc(cs.namespace(|| "y1"), || Ok(y1)).unwrap(); let p1 = EdwardsPoint { x: num_x0, - y: num_y0 + y: num_y0, }; let p2 = EdwardsPoint { x: num_x1, - y: num_y1 + y: num_y1, }; let p3 = p1.add(cs.namespace(|| "addition"), &p2, params).unwrap(); @@ -1121,8 +994,8 @@ mod test { fn test_edwards_doubling() { let params = &JubjubBls12::new(); let rng = &mut XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..100 { @@ -1134,16 +1007,12 @@ mod test { let mut cs = TestConstraintSystem::::new(); - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || { - Ok(x0) - }).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || { - Ok(y0) - }).unwrap(); + let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || Ok(x0)).unwrap(); + let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || Ok(y0)).unwrap(); let p1 = EdwardsPoint { x: num_x0, - y: num_y0 + y: num_y0, }; let p2 = p1.double(cs.namespace(|| "doubling"), params).unwrap(); @@ -1159,8 +1028,8 @@ mod test { fn test_montgomery_addition() { let params = &JubjubBls12::new(); let rng = &mut XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); for _ in 0..100 { @@ -1190,28 +1059,20 @@ mod test { let mut cs = TestConstraintSystem::::new(); - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || { - Ok(x0) - }).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || { - Ok(y0) - }).unwrap(); + let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || Ok(x0)).unwrap(); + let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || Ok(y0)).unwrap(); - let num_x1 = AllocatedNum::alloc(cs.namespace(|| "x1"), || { - Ok(x1) - }).unwrap(); - let num_y1 = AllocatedNum::alloc(cs.namespace(|| "y1"), || { - Ok(y1) - }).unwrap(); + let num_x1 = AllocatedNum::alloc(cs.namespace(|| "x1"), || Ok(x1)).unwrap(); + let num_y1 = AllocatedNum::alloc(cs.namespace(|| "y1"), || Ok(y1)).unwrap(); let p1 = MontgomeryPoint { x: num_x0.into(), - y: num_y0.into() + y: num_y0.into(), }; let p2 = MontgomeryPoint { x: num_x1.into(), - y: num_y1.into() + y: num_y1.into(), }; let p3 = p1.add(cs.namespace(|| "addition"), &p2, params).unwrap(); diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index 0b67597..21c0bf5 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -1,17 +1,13 @@ -use super::ecc::{ - MontgomeryPoint, - EdwardsPoint -}; +use super::ecc::{EdwardsPoint, MontgomeryPoint}; use bellman::gadgets::boolean::Boolean; -use zcash_primitives::jubjub::*; -use bellman::{ - ConstraintSystem, SynthesisError -}; use bellman::gadgets::lookup::*; +use bellman::{ConstraintSystem, SynthesisError}; +use zcash_primitives::jubjub::*; pub use zcash_primitives::pedersen_hash::Personalization; fn get_constant_bools(person: &Personalization) -> Vec { - person.get_bits() + person + .get_bits() .into_iter() .map(|e| Boolean::constant(e)) .collect() @@ -21,9 +17,10 @@ pub fn pedersen_hash( mut cs: CS, personalization: Personalization, bits: &[Boolean], - params: &E::Params + params: &E::Params, ) -> Result, SynthesisError> - where CS: ConstraintSystem +where + CS: ConstraintSystem, { let personalization = get_constant_bools(&personalization); assert_eq!(personalization.len(), 6); @@ -36,8 +33,7 @@ pub fn pedersen_hash( let mut segment_i = 0; loop { let mut segment_result = None; - let mut segment_windows = &segment_generators.next() - .expect("enough segments")[..]; + let mut segment_windows = &segment_generators.next().expect("enough segments")[..]; let mut window_i = 0; while let Some(a) = bits.next() { @@ -47,7 +43,7 @@ pub fn pedersen_hash( let tmp = lookup3_xy_with_conditional_negation( cs.namespace(|| format!("segment {}, window {}", segment_i, window_i)), &[a.clone(), b.clone(), c.clone()], - &segment_windows[0] + &segment_windows[0], )?; let tmp = MontgomeryPoint::interpret_unchecked(tmp.0, tmp.1); @@ -55,12 +51,14 @@ pub fn pedersen_hash( match segment_result { None => { segment_result = Some(tmp); - }, + } Some(ref mut segment_result) => { *segment_result = tmp.add( - cs.namespace(|| format!("addition of segment {}, window {}", segment_i, window_i)), + cs.namespace(|| { + format!("addition of segment {}, window {}", segment_i, window_i) + }), segment_result, - params + params, )?; } } @@ -79,22 +77,24 @@ pub fn pedersen_hash( // Convert this segment into twisted Edwards form. let segment_result = segment_result.into_edwards( cs.namespace(|| format!("conversion of segment {} into edwards", segment_i)), - params + params, )?; match edwards_result { Some(ref mut edwards_result) => { *edwards_result = segment_result.add( - cs.namespace(|| format!("addition of segment {} to accumulator", segment_i)), + cs.namespace(|| { + format!("addition of segment {} to accumulator", segment_i) + }), edwards_result, - params + params, )?; - }, + } None => { edwards_result = Some(segment_result); } } - }, + } None => { // We didn't process any new bits. break; @@ -110,37 +110,44 @@ pub fn pedersen_hash( #[cfg(test)] mod test { use super::*; + use bellman::gadgets::boolean::{AllocatedBit, Boolean}; use bellman::gadgets::test::*; - use bellman::gadgets::boolean::{Boolean, AllocatedBit}; - use zcash_primitives::pedersen_hash; use ff::PrimeField; use pairing::bls12_381::{Bls12, Fr}; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; + use zcash_primitives::pedersen_hash; #[test] fn test_pedersen_hash_constraints() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); let params = &JubjubBls12::new(); let mut cs = TestConstraintSystem::::new(); - let input: Vec = (0..(Fr::NUM_BITS * 2)).map(|_| rng.next_u32() % 2 != 0).collect(); + let input: Vec = (0..(Fr::NUM_BITS * 2)) + .map(|_| rng.next_u32() % 2 != 0) + .collect(); - let input_bools: Vec = input.iter().enumerate().map(|(i, b)| { - Boolean::from( - AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap() - ) - }).collect(); + let input_bools: Vec = input + .iter() + .enumerate() + .map(|(i, b)| { + Boolean::from( + AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap(), + ) + }) + .collect(); pedersen_hash( cs.namespace(|| "pedersen hash"), Personalization::NoteCommitment, &input_bools, - params - ).unwrap(); + params, + ) + .unwrap(); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 1377); @@ -149,8 +156,8 @@ mod test { #[test] fn test_pedersen_hash() { let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, ]); let params = &JubjubBls12::new(); @@ -160,26 +167,33 @@ mod test { let mut cs = TestConstraintSystem::::new(); - let input_bools: Vec = input.iter().enumerate().map(|(i, b)| { - Boolean::from( - AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap() - ) - }).collect(); + let input_bools: Vec = input + .iter() + .enumerate() + .map(|(i, b)| { + Boolean::from( + AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)) + .unwrap(), + ) + }) + .collect(); let res = pedersen_hash( cs.namespace(|| "pedersen hash"), Personalization::MerkleTree(1), &input_bools, - params - ).unwrap(); + params, + ) + .unwrap(); assert!(cs.is_satisfied()); let expected = pedersen_hash::pedersen_hash::( Personalization::MerkleTree(1), input.clone().into_iter(), - params - ).into_xy(); + params, + ) + .into_xy(); assert_eq!(res.get_x().get_value().unwrap(), expected.0); assert_eq!(res.get_y().get_value().unwrap(), expected.1); @@ -188,8 +202,9 @@ mod test { let unexpected = pedersen_hash::pedersen_hash::( Personalization::MerkleTree(0), input.into_iter(), - params - ).into_xy(); + params, + ) + .into_xy(); assert!(res.get_x().get_value().unwrap() != unexpected.0); assert!(res.get_y().get_value().unwrap() != unexpected.1); diff --git a/zcash_proofs/src/circuit/sapling.rs b/zcash_proofs/src/circuit/sapling.rs index 1349c8c..0554ff4 100644 --- a/zcash_proofs/src/circuit/sapling.rs +++ b/zcash_proofs/src/circuit/sapling.rs @@ -1,31 +1,20 @@ use ff::{Field, PrimeField, PrimeFieldRepr}; -use bellman::{ - SynthesisError, - ConstraintSystem, - Circuit -}; +use bellman::{Circuit, ConstraintSystem, SynthesisError}; -use zcash_primitives::jubjub::{ - JubjubEngine, - FixedGenerators -}; +use zcash_primitives::jubjub::{FixedGenerators, JubjubEngine}; use zcash_primitives::constants; -use zcash_primitives::primitives::{ - ValueCommitment, - ProofGenerationKey, - PaymentAddress -}; +use zcash_primitives::primitives::{PaymentAddress, ProofGenerationKey, ValueCommitment}; -use bellman::gadgets::Assignment; -use bellman::gadgets::boolean; use super::ecc; use super::pedersen_hash; use bellman::gadgets::blake2s; -use bellman::gadgets::num; +use bellman::gadgets::boolean; use bellman::gadgets::multipack; +use bellman::gadgets::num; +use bellman::gadgets::Assignment; pub const TREE_DEPTH: usize = zcash_primitives::sapling::SAPLING_COMMITMENT_TREE_DEPTH; @@ -54,7 +43,7 @@ pub struct Spend<'a, E: JubjubEngine> { /// The anchor; the root of the tree. If the note being /// spent is zero-value, this can be anything. - pub anchor: Option + pub anchor: Option, } /// This is an output circuit instance. @@ -71,7 +60,7 @@ pub struct Output<'a, E: JubjubEngine> { pub commitment_randomness: Option, /// The ephemeral secret key for DH with recipient - pub esk: Option + pub esk: Option, } /// Exposes a Pedersen commitment to the value as an @@ -79,15 +68,16 @@ pub struct Output<'a, E: JubjubEngine> { fn expose_value_commitment( mut cs: CS, value_commitment: Option>, - params: &E::Params + params: &E::Params, ) -> Result, SynthesisError> - where E: JubjubEngine, - CS: ConstraintSystem +where + E: JubjubEngine, + CS: ConstraintSystem, { // Booleanize the value into little-endian bit order let value_bits = boolean::u64_into_boolean_vec_le( cs.namespace(|| "value"), - value_commitment.as_ref().map(|c| c.value) + value_commitment.as_ref().map(|c| c.value), )?; // Compute the note value in the exponent @@ -95,7 +85,7 @@ fn expose_value_commitment( cs.namespace(|| "compute the value in the exponent"), FixedGenerators::ValueCommitmentValue, &value_bits, - params + params, )?; // Booleanize the randomness. This does not ensure @@ -103,7 +93,7 @@ fn expose_value_commitment( // it doesn't matter for security. let rcv = boolean::field_into_boolean_vec_le( cs.namespace(|| "rcv"), - value_commitment.as_ref().map(|c| c.randomness) + value_commitment.as_ref().map(|c| c.randomness), )?; // Compute the randomness in the exponent @@ -111,15 +101,11 @@ fn expose_value_commitment( cs.namespace(|| "computation of rcv"), FixedGenerators::ValueCommitmentRandomness, &rcv, - params + params, )?; // Compute the Pedersen commitment to the value - let cv = value.add( - cs.namespace(|| "computation of cv"), - &rcv, - params - )?; + let cv = value.add(cs.namespace(|| "computation of cv"), &rcv, params)?; // Expose the commitment as an input to the circuit cv.inputize(cs.namespace(|| "commitment point"))?; @@ -128,43 +114,32 @@ fn expose_value_commitment( } impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { - fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> - { + fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { // Prover witnesses ak (ensures that it's on the curve) let ak = ecc::EdwardsPoint::witness( cs.namespace(|| "ak"), self.proof_generation_key.as_ref().map(|k| k.ak.clone()), - self.params + self.params, )?; // There are no sensible attacks on small order points // of ak (that we're aware of!) but it's a cheap check, // so we do it. - ak.assert_not_small_order( - cs.namespace(|| "ak not small order"), - self.params - )?; + ak.assert_not_small_order(cs.namespace(|| "ak not small order"), self.params)?; // Rerandomize ak and expose it as an input to the circuit { - let ar = boolean::field_into_boolean_vec_le( - cs.namespace(|| "ar"), - self.ar - )?; + let ar = boolean::field_into_boolean_vec_le(cs.namespace(|| "ar"), self.ar)?; // Compute the randomness in the exponent let ar = ecc::fixed_base_multiplication( cs.namespace(|| "computation of randomization for the signing key"), FixedGenerators::SpendingKeyGenerator, &ar, - self.params + self.params, )?; - let rk = ak.add( - cs.namespace(|| "computation of rk"), - &ar, - self.params - )?; + let rk = ak.add(cs.namespace(|| "computation of rk"), &ar, self.params)?; rk.inputize(cs.namespace(|| "rk"))?; } @@ -175,7 +150,7 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { // Witness nsk as bits let nsk = boolean::field_into_boolean_vec_le( cs.namespace(|| "nsk"), - self.proof_generation_key.as_ref().map(|k| k.nsk.clone()) + self.proof_generation_key.as_ref().map(|k| k.nsk.clone()), )?; // NB: We don't ensure that the bit representation of nsk @@ -188,7 +163,7 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { cs.namespace(|| "computation of nk"), FixedGenerators::ProofGenerationKey, &nsk, - self.params + self.params, )?; } @@ -196,9 +171,7 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { let mut ivk_preimage = vec![]; // Place ak in the preimage for CRH^ivk - ivk_preimage.extend( - ak.repr(cs.namespace(|| "representation of ak"))? - ); + ivk_preimage.extend(ak.repr(cs.namespace(|| "representation of ak"))?); // This is the nullifier preimage for PRF^nf let mut nf_preimage = vec![]; @@ -206,9 +179,7 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { // Extend ivk and nf preimages with the representation of // nk. { - let repr_nk = nk.repr( - cs.namespace(|| "representation of nk") - )?; + let repr_nk = nk.repr(cs.namespace(|| "representation of nk"))?; ivk_preimage.extend(repr_nk.iter().cloned()); nf_preimage.extend(repr_nk); @@ -221,7 +192,7 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { let mut ivk = blake2s::blake2s( cs.namespace(|| "computation of ivk"), &ivk_preimage, - constants::CRH_IVK_PERSONALIZATION + constants::CRH_IVK_PERSONALIZATION, )?; // drop_5 to ensure it's in the field @@ -239,7 +210,7 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { ecc::EdwardsPoint::witness( cs.namespace(|| "witness g_d"), self.payment_address.as_ref().and_then(|a| a.g_d(params)), - self.params + self.params, )? }; @@ -247,17 +218,10 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { // is already done in the Output circuit, and this proof ensures // g_d is bound to a product of that check, but for defense in // depth let's check it anyway. It's cheap. - g_d.assert_not_small_order( - cs.namespace(|| "g_d not small order"), - self.params - )?; + g_d.assert_not_small_order(cs.namespace(|| "g_d not small order"), self.params)?; // Compute pk_d = g_d^ivk - let pk_d = g_d.mul( - cs.namespace(|| "compute pk_d"), - &ivk, - self.params - )?; + let pk_d = g_d.mul(cs.namespace(|| "compute pk_d"), &ivk, self.params)?; // Compute note contents: // value (in big endian) followed by g_d and pk_d @@ -271,18 +235,14 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { let value_bits = expose_value_commitment( cs.namespace(|| "value commitment"), self.value_commitment, - self.params + self.params, )?; // Compute the note's value as a linear combination // of the bits. let mut coeff = E::Fr::one(); for bit in &value_bits { - value_num = value_num.add_bool_with_coeff( - CS::one(), - bit, - coeff - ); + value_num = value_num.add_bool_with_coeff(CS::one(), bit, coeff); coeff.double(); } @@ -291,14 +251,10 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { } // Place g_d in the note - note_contents.extend( - g_d.repr(cs.namespace(|| "representation of g_d"))? - ); + note_contents.extend(g_d.repr(cs.namespace(|| "representation of g_d"))?); // Place pk_d in the note - note_contents.extend( - pk_d.repr(cs.namespace(|| "representation of pk_d"))? - ); + note_contents.extend(pk_d.repr(cs.namespace(|| "representation of pk_d"))?); assert_eq!( note_contents.len(), @@ -312,14 +268,14 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { cs.namespace(|| "note content hash"), pedersen_hash::Personalization::NoteCommitment, ¬e_contents, - self.params + self.params, )?; { // Booleanize the randomness for the note commitment let rcm = boolean::field_into_boolean_vec_le( cs.namespace(|| "rcm"), - self.commitment_randomness + self.commitment_randomness, )?; // Compute the note commitment randomness in the exponent @@ -327,7 +283,7 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { cs.namespace(|| "computation of commitment randomness"), FixedGenerators::NoteCommitmentRandomness, &rcm, - self.params + self.params, )?; // Randomize the note commitment. Pedersen hashes are not @@ -335,7 +291,7 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { cm = cm.add( cs.namespace(|| "randomization of note commitment"), &rcm, - self.params + self.params, )?; } @@ -356,7 +312,7 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { // depth of the tree. let cur_is_right = boolean::Boolean::from(boolean::AllocatedBit::alloc( cs.namespace(|| "position bit"), - e.map(|e| e.1) + e.map(|e| e.1), )?); // Push this boolean for nullifier computation later @@ -364,19 +320,15 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { // Witness the authentication path element adjacent // at this depth. - let path_element = num::AllocatedNum::alloc( - cs.namespace(|| "path element"), - || { - Ok(e.get()?.0) - } - )?; + let path_element = + num::AllocatedNum::alloc(cs.namespace(|| "path element"), || Ok(e.get()?.0))?; // Swap the two if the current subtree is on the right let (xl, xr) = num::AllocatedNum::conditionally_reverse( cs.namespace(|| "conditional reversal of preimage"), &cur, &path_element, - &cur_is_right + &cur_is_right, )?; // We don't need to be strict, because the function is @@ -392,20 +344,19 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { cs.namespace(|| "computation of pedersen hash"), pedersen_hash::Personalization::MerkleTree(i), &preimage, - self.params - )?.get_x().clone(); // Injective encoding + self.params, + )? + .get_x() + .clone(); // Injective encoding } { let real_anchor_value = self.anchor; // Allocate the "real" anchor that will be exposed. - let rt = num::AllocatedNum::alloc( - cs.namespace(|| "conditional anchor"), - || { - Ok(*real_anchor_value.get()?) - } - )?; + let rt = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || { + Ok(*real_anchor_value.get()?) + })?; // (cur - rt) * value = 0 // if value is zero, cur and rt can be different @@ -414,7 +365,7 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { || "conditionally enforce correct root", |lc| lc + cur.get_variable() - rt.get_variable(), |lc| lc + &value_num.lc(E::Fr::one()), - |lc| lc + |lc| lc, ); // Expose the anchor @@ -430,29 +381,27 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { cs.namespace(|| "g^position"), FixedGenerators::NullifierPosition, &position_bits, - self.params + self.params, )?; // Add the position to the commitment rho = rho.add( cs.namespace(|| "faerie gold prevention"), &position, - self.params + self.params, )?; } - + // Let's compute nf = BLAKE2s(nk || rho) - nf_preimage.extend( - rho.repr(cs.namespace(|| "representation of rho"))? - ); + nf_preimage.extend(rho.repr(cs.namespace(|| "representation of rho"))?); assert_eq!(nf_preimage.len(), 512); - + // Compute nf let nf = blake2s::blake2s( cs.namespace(|| "nf computation"), &nf_preimage, - constants::PRF_NF_PERSONALIZATION + constants::PRF_NF_PERSONALIZATION, )?; multipack::pack_into_inputs(cs.namespace(|| "pack nullifier"), &nf) @@ -460,8 +409,7 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { } impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { - fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> - { + fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { // Let's start to construct our note, which contains // value (big endian) let mut note_contents = vec![]; @@ -471,7 +419,7 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { note_contents.extend(expose_value_commitment( cs.namespace(|| "value commitment"), self.value_commitment, - self.params + self.params, )?); // Let's deal with g_d @@ -483,7 +431,7 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { let g_d = ecc::EdwardsPoint::witness( cs.namespace(|| "witness g_d"), self.payment_address.as_ref().and_then(|a| a.g_d(params)), - self.params + self.params, )?; // g_d is ensured to be large order. The relationship @@ -495,29 +443,17 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { // // Further, if it were small order, epk would be // small order too! - g_d.assert_not_small_order( - cs.namespace(|| "g_d not small order"), - self.params - )?; + g_d.assert_not_small_order(cs.namespace(|| "g_d not small order"), self.params)?; // Extend our note contents with the representation of // g_d. - note_contents.extend( - g_d.repr(cs.namespace(|| "representation of g_d"))? - ); + note_contents.extend(g_d.repr(cs.namespace(|| "representation of g_d"))?); // Booleanize our ephemeral secret key - let esk = boolean::field_into_boolean_vec_le( - cs.namespace(|| "esk"), - self.esk - )?; + let esk = boolean::field_into_boolean_vec_le(cs.namespace(|| "esk"), self.esk)?; // Create the ephemeral public key from g_d. - let epk = g_d.mul( - cs.namespace(|| "epk computation"), - &esk, - self.params - )?; + let epk = g_d.mul(cs.namespace(|| "epk computation"), &esk, self.params)?; // Expose epk publicly. epk.inputize(cs.namespace(|| "epk"))?; @@ -534,13 +470,13 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { // endian bits (to match the representation) let y_contents = boolean::field_into_boolean_vec_le( cs.namespace(|| "pk_d bits of y"), - pk_d.map(|e| e.1) + pk_d.map(|e| e.1), )?; // Witness the sign bit let sign_bit = boolean::Boolean::from(boolean::AllocatedBit::alloc( cs.namespace(|| "pk_d bit of x"), - pk_d.map(|e| e.0.into_repr().is_odd()) + pk_d.map(|e| e.0.into_repr().is_odd()), )?); // Extend the note with pk_d representation @@ -560,14 +496,14 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { cs.namespace(|| "note content hash"), pedersen_hash::Personalization::NoteCommitment, ¬e_contents, - self.params + self.params, )?; { // Booleanize the randomness let rcm = boolean::field_into_boolean_vec_le( cs.namespace(|| "rcm"), - self.commitment_randomness + self.commitment_randomness, )?; // Compute the note commitment randomness in the exponent @@ -575,14 +511,14 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { cs.namespace(|| "computation of commitment randomness"), FixedGenerators::NoteCommitmentRandomness, &rcm, - self.params + self.params, )?; // Randomize our note commitment cm = cm.add( cs.namespace(|| "randomization of note commitment"), &rcm, - self.params + self.params, )?; } @@ -604,7 +540,7 @@ fn test_input_circuit_with_bls12_381() { use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; use zcash_primitives::{ - jubjub::{JubjubBls12, fs, edwards}, + jubjub::{edwards, fs, JubjubBls12}, pedersen_hash, primitives::{Diversifier, Note, ProofGenerationKey}, }; @@ -628,7 +564,7 @@ fn test_input_circuit_with_bls12_381() { let proof_generation_key = ProofGenerationKey { ak: ak.clone(), - nsk: nsk.clone() + nsk: nsk.clone(), }; let viewing_key = proof_generation_key.into_viewing_key(params); @@ -642,11 +578,7 @@ fn test_input_circuit_with_bls12_381() { Diversifier(d) }; - if let Some(p) = viewing_key.into_payment_address( - diversifier, - params - ) - { + if let Some(p) = viewing_key.into_payment_address(diversifier, params) { payment_address = p; break; } @@ -664,15 +596,14 @@ fn test_input_circuit_with_bls12_381() { value: value_commitment.value, g_d: g_d.clone(), pk_d: payment_address.pk_d.clone(), - r: commitment_randomness.clone() + r: commitment_randomness.clone(), }; let mut position = 0u64; let cm: Fr = note.cm(params); let mut cur = cm.clone(); - for (i, val) in auth_path.clone().into_iter().enumerate() - { + for (i, val) in auth_path.clone().into_iter().enumerate() { let (uncle, b) = val.unwrap(); let mut lhs = cur; @@ -691,10 +622,12 @@ fn test_input_circuit_with_bls12_381() { cur = pedersen_hash::pedersen_hash::( pedersen_hash::Personalization::MerkleTree(i), lhs.into_iter() - .take(Fr::NUM_BITS as usize) - .chain(rhs.into_iter().take(Fr::NUM_BITS as usize)), - params - ).into_xy().0; + .take(Fr::NUM_BITS as usize) + .chain(rhs.into_iter().take(Fr::NUM_BITS as usize)), + params, + ) + .into_xy() + .0; if b { position |= 1 << i; @@ -716,14 +649,17 @@ fn test_input_circuit_with_bls12_381() { commitment_randomness: Some(commitment_randomness), ar: Some(ar), auth_path: auth_path.clone(), - anchor: Some(cur) + anchor: Some(cur), }; instance.synthesize(&mut cs).unwrap(); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 98777); - assert_eq!(cs.hash(), "d37c738e83df5d9b0bb6495ac96abf21bcb2697477e2c15c2c7916ff7a3b6a89"); + assert_eq!( + cs.hash(), + "d37c738e83df5d9b0bb6495ac96abf21bcb2697477e2c15c2c7916ff7a3b6a89" + ); assert_eq!(cs.get("randomization of note commitment/x3/num"), cm); @@ -731,8 +667,14 @@ fn test_input_circuit_with_bls12_381() { assert_eq!(cs.get_input(0, "ONE"), Fr::one()); assert_eq!(cs.get_input(1, "rk/x/input variable"), rk.0); assert_eq!(cs.get_input(2, "rk/y/input variable"), rk.1); - assert_eq!(cs.get_input(3, "value commitment/commitment point/x/input variable"), expected_value_cm.0); - assert_eq!(cs.get_input(4, "value commitment/commitment point/y/input variable"), expected_value_cm.1); + assert_eq!( + cs.get_input(3, "value commitment/commitment point/x/input variable"), + expected_value_cm.0 + ); + assert_eq!( + cs.get_input(4, "value commitment/commitment point/y/input variable"), + expected_value_cm.1 + ); assert_eq!(cs.get_input(5, "anchor/input variable"), cur); assert_eq!(cs.get_input(6, "pack nullifier/input 0"), expected_nf[0]); assert_eq!(cs.get_input(7, "pack nullifier/input 1"), expected_nf[1]); @@ -748,7 +690,7 @@ fn test_output_circuit_with_bls12_381() { use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; use zcash_primitives::{ - jubjub::{JubjubBls12, fs, edwards}, + jubjub::{edwards, fs, JubjubBls12}, primitives::{Diversifier, ProofGenerationKey}, }; @@ -769,7 +711,7 @@ fn test_output_circuit_with_bls12_381() { let proof_generation_key = ProofGenerationKey { ak: ak.clone(), - nsk: nsk.clone() + nsk: nsk.clone(), }; let viewing_key = proof_generation_key.into_viewing_key(params); @@ -783,11 +725,7 @@ fn test_output_circuit_with_bls12_381() { Diversifier(d) }; - if let Some(p) = viewing_key.into_payment_address( - diversifier, - params - ) - { + if let Some(p) = viewing_key.into_payment_address(diversifier, params) { payment_address = p; break; } @@ -804,30 +742,41 @@ fn test_output_circuit_with_bls12_381() { value_commitment: Some(value_commitment.clone()), payment_address: Some(payment_address.clone()), commitment_randomness: Some(commitment_randomness), - esk: Some(esk.clone()) + esk: Some(esk.clone()), }; instance.synthesize(&mut cs).unwrap(); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 7827); - assert_eq!(cs.hash(), "c26d5cdfe6ccd65c03390902c02e11393ea6bb96aae32a7f2ecb12eb9103faee"); + assert_eq!( + cs.hash(), + "c26d5cdfe6ccd65c03390902c02e11393ea6bb96aae32a7f2ecb12eb9103faee" + ); - let expected_cm = payment_address.create_note( - value_commitment.value, - commitment_randomness, - params - ).expect("should be valid").cm(params); + let expected_cm = payment_address + .create_note(value_commitment.value, commitment_randomness, params) + .expect("should be valid") + .cm(params); let expected_value_cm = value_commitment.cm(params).into_xy(); - let expected_epk = payment_address.g_d(params).expect("should be valid").mul(esk, params); + let expected_epk = payment_address + .g_d(params) + .expect("should be valid") + .mul(esk, params); let expected_epk_xy = expected_epk.into_xy(); assert_eq!(cs.num_inputs(), 6); assert_eq!(cs.get_input(0, "ONE"), Fr::one()); - assert_eq!(cs.get_input(1, "value commitment/commitment point/x/input variable"), expected_value_cm.0); - assert_eq!(cs.get_input(2, "value commitment/commitment point/y/input variable"), expected_value_cm.1); + assert_eq!( + cs.get_input(1, "value commitment/commitment point/x/input variable"), + expected_value_cm.0 + ); + assert_eq!( + cs.get_input(2, "value commitment/commitment point/y/input variable"), + expected_value_cm.1 + ); assert_eq!(cs.get_input(3, "epk/x/input variable"), expected_epk_xy.0); assert_eq!(cs.get_input(4, "epk/y/input variable"), expected_epk_xy.1); assert_eq!(cs.get_input(5, "commitment/input variable"), expected_cm); diff --git a/zcash_proofs/src/circuit/sprout/commitment.rs b/zcash_proofs/src/circuit/sprout/commitment.rs index ba889a3..fba1217 100644 --- a/zcash_proofs/src/circuit/sprout/commitment.rs +++ b/zcash_proofs/src/circuit/sprout/commitment.rs @@ -1,20 +1,18 @@ -use pairing::{Engine}; +use bellman::gadgets::boolean::Boolean; +use bellman::gadgets::sha256::sha256; use bellman::{ConstraintSystem, SynthesisError}; -use bellman::gadgets::sha256::{ - sha256 -}; -use bellman::gadgets::boolean::{ - Boolean -}; +use pairing::Engine; pub fn note_comm( cs: CS, a_pk: &[Boolean], value: &[Boolean], rho: &[Boolean], - r: &[Boolean] + r: &[Boolean], ) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem +where + E: Engine, + CS: ConstraintSystem, { assert_eq!(a_pk.len(), 256); assert_eq!(value.len(), 64); @@ -35,8 +33,5 @@ pub fn note_comm( image.extend(rho.iter().cloned()); image.extend(r.iter().cloned()); - sha256( - cs, - &image - ) + sha256(cs, &image) } diff --git a/zcash_proofs/src/circuit/sprout/input.rs b/zcash_proofs/src/circuit/sprout/input.rs index a84e3a6..ad6091f 100644 --- a/zcash_proofs/src/circuit/sprout/input.rs +++ b/zcash_proofs/src/circuit/sprout/input.rs @@ -1,16 +1,11 @@ -use pairing::{Engine}; +use bellman::gadgets::boolean::{AllocatedBit, Boolean}; +use bellman::gadgets::sha256::sha256_block_no_padding; use bellman::{ConstraintSystem, SynthesisError}; -use bellman::gadgets::sha256::{ - sha256_block_no_padding -}; -use bellman::gadgets::boolean::{ - AllocatedBit, - Boolean -}; +use pairing::Engine; -use super::*; -use super::prfs::*; use super::commitment::note_comm; +use super::prfs::*; +use super::*; pub struct InputNote { pub nf: Vec, @@ -27,49 +22,33 @@ impl InputNote { h_sig: &[Boolean], nonce: bool, auth_path: [Option<([u8; 32], bool)>; TREE_DEPTH], - rt: &[Boolean] + rt: &[Boolean], ) -> Result - where E: Engine, CS: ConstraintSystem + where + E: Engine, + CS: ConstraintSystem, { let a_sk = witness_u252( cs.namespace(|| "a_sk"), - a_sk.as_ref().map(|a_sk| &a_sk.0[..]) + a_sk.as_ref().map(|a_sk| &a_sk.0[..]), )?; - let rho = witness_u256( - cs.namespace(|| "rho"), - rho.as_ref().map(|rho| &rho.0[..]) - )?; + let rho = witness_u256(cs.namespace(|| "rho"), rho.as_ref().map(|rho| &rho.0[..]))?; - let r = witness_u256( - cs.namespace(|| "r"), - r.as_ref().map(|r| &r.0[..]) - )?; + let r = witness_u256(cs.namespace(|| "r"), r.as_ref().map(|r| &r.0[..]))?; - let a_pk = prf_a_pk( - cs.namespace(|| "a_pk computation"), - &a_sk - )?; + let a_pk = prf_a_pk(cs.namespace(|| "a_pk computation"), &a_sk)?; - let nf = prf_nf( - cs.namespace(|| "nf computation"), - &a_sk, - &rho - )?; + let nf = prf_nf(cs.namespace(|| "nf computation"), &a_sk, &rho)?; - let mac = prf_pk( - cs.namespace(|| "mac computation"), - &a_sk, - h_sig, - nonce - )?; + let mac = prf_pk(cs.namespace(|| "mac computation"), &a_sk, h_sig, nonce)?; let cm = note_comm( cs.namespace(|| "cm computation"), &a_pk, &value.bits_le(), &rho, - &r + &r, )?; // Witness into the merkle tree @@ -80,13 +59,13 @@ impl InputNote { let cur_is_right = AllocatedBit::alloc( cs.namespace(|| "cur is right"), - layer.as_ref().map(|&(_, p)| p) + layer.as_ref().map(|&(_, p)| p), )?; let lhs = cur; let rhs = witness_u256( cs.namespace(|| "sibling"), - layer.as_ref().map(|&(ref sibling, _)| &sibling[..]) + layer.as_ref().map(|&(ref sibling, _)| &sibling[..]), )?; // Conditionally swap if cur is right @@ -94,19 +73,16 @@ impl InputNote { cs.namespace(|| "conditional swap"), &lhs[..], &rhs[..], - &cur_is_right + &cur_is_right, )?; - cur = sha256_block_no_padding( - cs.namespace(|| "hash of this layer"), - &preimage - )?; + cur = sha256_block_no_padding(cs.namespace(|| "hash of this layer"), &preimage)?; } // enforce must be true if the value is nonzero let enforce = AllocatedBit::alloc( cs.namespace(|| "enforce"), - value.get_value().map(|n| n != 0) + value.get_value().map(|n| n != 0), )?; // value * (1 - enforce) = 0 @@ -116,7 +92,7 @@ impl InputNote { || "enforce validity", |_| value.lc(), |lc| lc + CS::one() - enforce.get_variable(), - |lc| lc + |lc| lc, ); assert_eq!(cur.len(), rt.len()); @@ -132,14 +108,11 @@ impl InputNote { || format!("conditionally enforce correct root for bit {}", i), |_| cur.lc(CS::one(), E::Fr::one()) - &rt.lc(CS::one(), E::Fr::one()), |lc| lc + enforce.get_variable(), - |lc| lc + |lc| lc, ); } - Ok(InputNote { - mac: mac, - nf: nf - }) + Ok(InputNote { mac: mac, nf: nf }) } } @@ -149,9 +122,11 @@ pub fn conditionally_swap_u256( mut cs: CS, lhs: &[Boolean], rhs: &[Boolean], - condition: &AllocatedBit + condition: &AllocatedBit, ) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem, +where + E: Engine, + CS: ConstraintSystem, { assert_eq!(lhs.len(), 256); assert_eq!(rhs.len(), 256); @@ -164,13 +139,9 @@ pub fn conditionally_swap_u256( let x = Boolean::from(AllocatedBit::alloc( cs.namespace(|| "x"), - condition.get_value().and_then(|v| { - if v { - rhs.get_value() - } else { - lhs.get_value() - } - }) + condition + .get_value() + .and_then(|v| if v { rhs.get_value() } else { lhs.get_value() }), )?); // x = (1-condition)lhs + (condition)rhs @@ -184,33 +155,25 @@ pub fn conditionally_swap_u256( // x = rhs cs.enforce( || "conditional swap for x", - |lc| lc + &rhs.lc(CS::one(), E::Fr::one()) - - &lhs.lc(CS::one(), E::Fr::one()), + |lc| lc + &rhs.lc(CS::one(), E::Fr::one()) - &lhs.lc(CS::one(), E::Fr::one()), |lc| lc + condition.get_variable(), - |lc| lc + &x.lc(CS::one(), E::Fr::one()) - - &lhs.lc(CS::one(), E::Fr::one()) + |lc| lc + &x.lc(CS::one(), E::Fr::one()) - &lhs.lc(CS::one(), E::Fr::one()), ); let y = Boolean::from(AllocatedBit::alloc( cs.namespace(|| "y"), - condition.get_value().and_then(|v| { - if v { - lhs.get_value() - } else { - rhs.get_value() - } - }) + condition + .get_value() + .and_then(|v| if v { lhs.get_value() } else { rhs.get_value() }), )?); // y = (1-condition)rhs + (condition)lhs // y - rhs = condition (lhs - rhs) cs.enforce( || "conditional swap for y", - |lc| lc + &lhs.lc(CS::one(), E::Fr::one()) - - &rhs.lc(CS::one(), E::Fr::one()), + |lc| lc + &lhs.lc(CS::one(), E::Fr::one()) - &rhs.lc(CS::one(), E::Fr::one()), |lc| lc + condition.get_variable(), - |lc| lc + &y.lc(CS::one(), E::Fr::one()) - - &rhs.lc(CS::one(), E::Fr::one()) + |lc| lc + &y.lc(CS::one(), E::Fr::one()) - &rhs.lc(CS::one(), E::Fr::one()), ); new_lhs.push(x); diff --git a/zcash_proofs/src/circuit/sprout/mod.rs b/zcash_proofs/src/circuit/sprout/mod.rs index c28b8d7..358e1bb 100644 --- a/zcash_proofs/src/circuit/sprout/mod.rs +++ b/zcash_proofs/src/circuit/sprout/mod.rs @@ -1,16 +1,13 @@ +use bellman::gadgets::boolean::{AllocatedBit, Boolean}; +use bellman::gadgets::multipack::pack_into_inputs; +use bellman::{Circuit, ConstraintSystem, LinearCombination, SynthesisError}; use ff::Field; use pairing::Engine; -use bellman::{ConstraintSystem, SynthesisError, Circuit, LinearCombination}; -use bellman::gadgets::boolean::{ - AllocatedBit, - Boolean -}; -use bellman::gadgets::multipack::pack_into_inputs; -mod prfs; mod commitment; mod input; mod output; +mod prfs; use self::input::*; use self::output::*; @@ -37,39 +34,29 @@ pub struct JSInput { pub a_sk: Option, pub rho: Option, pub r: Option, - pub auth_path: [Option<([u8; 32], bool)>; TREE_DEPTH] + pub auth_path: [Option<([u8; 32], bool)>; TREE_DEPTH], } pub struct JSOutput { pub value: Option, pub a_pk: Option, - pub r: Option + pub r: Option, } impl Circuit for JoinSplit { - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { + fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { assert_eq!(self.inputs.len(), 2); assert_eq!(self.outputs.len(), 2); // vpub_old is the value entering the // JoinSplit from the "outside" value // pool - let vpub_old = NoteValue::new( - cs.namespace(|| "vpub_old"), - self.vpub_old - )?; + let vpub_old = NoteValue::new(cs.namespace(|| "vpub_old"), self.vpub_old)?; // vpub_new is the value leaving the // JoinSplit into the "outside" value // pool - let vpub_new = NoteValue::new( - cs.namespace(|| "vpub_new"), - self.vpub_new - )?; + let vpub_new = NoteValue::new(cs.namespace(|| "vpub_new"), self.vpub_new)?; // The left hand side of the balance equation // vpub_old + inputs[0].value + inputs[1].value @@ -80,22 +67,17 @@ impl Circuit for JoinSplit { let mut rhs = vpub_new.lc(); // Witness rt (merkle tree root) - let rt = witness_u256( - cs.namespace(|| "rt"), - self.rt.as_ref().map(|v| &v[..]) - ).unwrap(); + let rt = witness_u256(cs.namespace(|| "rt"), self.rt.as_ref().map(|v| &v[..])).unwrap(); // Witness h_sig let h_sig = witness_u256( cs.namespace(|| "h_sig"), - self.h_sig.as_ref().map(|v| &v[..]) - ).unwrap(); + self.h_sig.as_ref().map(|v| &v[..]), + ) + .unwrap(); // Witness phi - let phi = witness_u252( - cs.namespace(|| "phi"), - self.phi.as_ref().map(|v| &v[..]) - ).unwrap(); + let phi = witness_u252(cs.namespace(|| "phi"), self.phi.as_ref().map(|v| &v[..])).unwrap(); let mut input_notes = vec![]; let mut lhs_total = self.vpub_old; @@ -110,17 +92,14 @@ impl Circuit for JoinSplit { } // Allocate the value of the note - let value = NoteValue::new( - cs.namespace(|| "value"), - input.value - )?; + let value = NoteValue::new(cs.namespace(|| "value"), input.value)?; // Compute the nonce (for PRF inputs) which is false // for the first input, and true for the second input. let nonce = match i { 0 => false, 1 => true, - _ => unreachable!() + _ => unreachable!(), }; // Perform input note computations @@ -133,7 +112,7 @@ impl Circuit for JoinSplit { &h_sig, nonce, input.auth_path, - &rt + &rt, )?); // Add the note value to the left hand side of @@ -148,10 +127,8 @@ impl Circuit for JoinSplit { { // Expected sum of the left hand side of the balance // equation, expressed as a 64-bit unsigned integer - let lhs_total = NoteValue::new( - cs.namespace(|| "total value of left hand side"), - lhs_total - )?; + let lhs_total = + NoteValue::new(cs.namespace(|| "total value of left hand side"), lhs_total)?; // Enforce that the left hand side can be expressed as a 64-bit // integer @@ -159,7 +136,7 @@ impl Circuit for JoinSplit { || "left hand side can be expressed as a 64-bit unsigned integer", |_| lhs.clone(), |lc| lc + CS::one(), - |_| lhs_total.lc() + |_| lhs_total.lc(), ); } @@ -169,17 +146,14 @@ impl Circuit for JoinSplit { for (i, output) in self.outputs.into_iter().enumerate() { let cs = &mut cs.namespace(|| format!("output {}", i)); - let value = NoteValue::new( - cs.namespace(|| "value"), - output.value - )?; + let value = NoteValue::new(cs.namespace(|| "value"), output.value)?; // Compute the nonce (for PRF inputs) which is false // for the first output, and true for the second output. let nonce = match i { 0 => false, 1 => true, - _ => unreachable!() + _ => unreachable!(), }; // Perform output note computations @@ -190,7 +164,7 @@ impl Circuit for JoinSplit { output.r, &phi, &h_sig, - nonce + nonce, )?); // Add the note value to the right hand side of @@ -203,7 +177,7 @@ impl Circuit for JoinSplit { || "balance equation", |_| lhs.clone(), |lc| lc + CS::one(), - |_| rhs + |_| rhs, ); let mut public_inputs = vec![]; @@ -229,15 +203,14 @@ impl Circuit for JoinSplit { pub struct NoteValue { value: Option, // Least significant digit first - bits: Vec + bits: Vec, } impl NoteValue { - fn new( - mut cs: CS, - value: Option - ) -> Result - where E: Engine, CS: ConstraintSystem, + fn new(mut cs: CS, value: Option) -> Result + where + E: Engine, + CS: ConstraintSystem, { let mut values; match value { @@ -247,7 +220,7 @@ impl NoteValue { values.push(Some(val & 1 == 1)); val >>= 1; } - }, + } None => { values = vec![None; 64]; } @@ -255,28 +228,27 @@ impl NoteValue { let mut bits = vec![]; for (i, value) in values.into_iter().enumerate() { - bits.push( - AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - value - )? - ); + bits.push(AllocatedBit::alloc( + cs.namespace(|| format!("bit {}", i)), + value, + )?); } Ok(NoteValue { value: value, - bits: bits + bits: bits, }) } /// Encodes the bits of the value into little-endian /// byte order. fn bits_le(&self) -> Vec { - self.bits.chunks(8) - .flat_map(|v| v.iter().rev()) - .cloned() - .map(|e| Boolean::from(e)) - .collect() + self.bits + .chunks(8) + .flat_map(|v| v.iter().rev()) + .cloned() + .map(|e| Boolean::from(e)) + .collect() } /// Computes this value as a linear combination of @@ -304,15 +276,18 @@ fn witness_bits( mut cs: CS, value: Option<&[u8]>, num_bits: usize, - skip_bits: usize + skip_bits: usize, ) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem, +where + E: Engine, + CS: ConstraintSystem, { let bit_values = if let Some(value) = value { let mut tmp = vec![]; - for b in value.iter() - .flat_map(|&m| (0..8).rev().map(move |i| m >> i & 1 == 1)) - .skip(skip_bits) + for b in value + .iter() + .flat_map(|&m| (0..8).rev().map(move |i| m >> i & 1 == 1)) + .skip(skip_bits) { tmp.push(Some(b)); } @@ -327,37 +302,35 @@ fn witness_bits( for (i, value) in bit_values.into_iter().enumerate() { bits.push(Boolean::from(AllocatedBit::alloc( cs.namespace(|| format!("bit {}", i)), - value + value, )?)); } Ok(bits) } -fn witness_u256( - cs: CS, - value: Option<&[u8]>, -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem, +fn witness_u256(cs: CS, value: Option<&[u8]>) -> Result, SynthesisError> +where + E: Engine, + CS: ConstraintSystem, { witness_bits(cs, value, 256, 0) } -fn witness_u252( - cs: CS, - value: Option<&[u8]>, -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem, +fn witness_u252(cs: CS, value: Option<&[u8]>) -> Result, SynthesisError> +where + E: Engine, + CS: ConstraintSystem, { witness_bits(cs, value, 252, 4) } #[test] fn test_sprout_constraints() { - use pairing::bls12_381::{Bls12}; use bellman::gadgets::test::*; + use pairing::bls12_381::Bls12; - use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian}; + use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; let test_vector = include_bytes!("test_vectors.dat"); let mut test_vector = &test_vector[..]; @@ -393,9 +366,7 @@ fn test_sprout_constraints() { } let mut position = test_vector.read_u64::().unwrap(); for i in 0..TREE_DEPTH { - auth_path[i].as_mut().map(|p| { - p.1 = (position & 1) == 1 - }); + auth_path[i].as_mut().map(|p| p.1 = (position & 1) == 1); position >>= 1; } @@ -407,15 +378,13 @@ fn test_sprout_constraints() { let r = Some(CommitmentRandomness(get_u256(&mut test_vector))); let a_sk = Some(SpendingKey(get_u256(&mut test_vector))); - inputs.push( - JSInput { - value: value, - a_sk: a_sk, - rho: rho, - r: r, - auth_path: auth_path - } - ); + inputs.push(JSInput { + value: value, + a_sk: a_sk, + rho: rho, + r: r, + auth_path: auth_path, + }); } let mut outputs = vec![]; @@ -426,13 +395,11 @@ fn test_sprout_constraints() { get_u256(&mut test_vector); let r = Some(CommitmentRandomness(get_u256(&mut test_vector))); - outputs.push( - JSOutput { - value: value, - a_pk: a_pk, - r: r - } - ); + outputs.push(JSOutput { + value: value, + a_pk: a_pk, + r: r, + }); } let vpub_old = Some(test_vector.read_u64::().unwrap()); @@ -454,7 +421,7 @@ fn test_sprout_constraints() { phi: phi, inputs: inputs, outputs: outputs, - rt: rt + rt: rt, }; js.synthesize(&mut cs).unwrap(); @@ -465,7 +432,10 @@ fn test_sprout_constraints() { assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 1989085); assert_eq!(cs.num_inputs(), 10); - assert_eq!(cs.hash(), "1a228d3c6377130d1778c7885811dc8b8864049cb5af8aff7e6cd46c5bc4b84c"); + assert_eq!( + cs.hash(), + "1a228d3c6377130d1778c7885811dc8b8864049cb5af8aff7e6cd46c5bc4b84c" + ); let mut expected_inputs = vec![]; expected_inputs.extend(rt.unwrap().to_vec()); @@ -476,8 +446,12 @@ fn test_sprout_constraints() { expected_inputs.extend(mac2.to_vec()); expected_inputs.extend(cm1.to_vec()); expected_inputs.extend(cm2.to_vec()); - expected_inputs.write_u64::(vpub_old.unwrap()).unwrap(); - expected_inputs.write_u64::(vpub_new.unwrap()).unwrap(); + expected_inputs + .write_u64::(vpub_old.unwrap()) + .unwrap(); + expected_inputs + .write_u64::(vpub_new.unwrap()) + .unwrap(); use bellman::gadgets::multipack; diff --git a/zcash_proofs/src/circuit/sprout/output.rs b/zcash_proofs/src/circuit/sprout/output.rs index f2e504a..a9a1e48 100644 --- a/zcash_proofs/src/circuit/sprout/output.rs +++ b/zcash_proofs/src/circuit/sprout/output.rs @@ -1,13 +1,13 @@ -use pairing::{Engine}; +use bellman::gadgets::boolean::Boolean; use bellman::{ConstraintSystem, SynthesisError}; -use bellman::gadgets::boolean::{Boolean}; +use pairing::Engine; -use super::*; -use super::prfs::*; use super::commitment::note_comm; +use super::prfs::*; +use super::*; pub struct OutputNote { - pub cm: Vec + pub cm: Vec, } impl OutputNote { @@ -18,37 +18,29 @@ impl OutputNote { r: Option, phi: &[Boolean], h_sig: &[Boolean], - nonce: bool + nonce: bool, ) -> Result - where E: Engine, CS: ConstraintSystem, + where + E: Engine, + CS: ConstraintSystem, { - let rho = prf_rho( - cs.namespace(|| "rho"), - phi, - h_sig, - nonce - )?; + let rho = prf_rho(cs.namespace(|| "rho"), phi, h_sig, nonce)?; let a_pk = witness_u256( cs.namespace(|| "a_pk"), - a_pk.as_ref().map(|a_pk| &a_pk.0[..]) + a_pk.as_ref().map(|a_pk| &a_pk.0[..]), )?; - let r = witness_u256( - cs.namespace(|| "r"), - r.as_ref().map(|r| &r.0[..]) - )?; + let r = witness_u256(cs.namespace(|| "r"), r.as_ref().map(|r| &r.0[..]))?; let cm = note_comm( cs.namespace(|| "cm computation"), &a_pk, &value.bits_le(), &rho, - &r + &r, )?; - Ok(OutputNote { - cm: cm - }) + Ok(OutputNote { cm: cm }) } } diff --git a/zcash_proofs/src/circuit/sprout/prfs.rs b/zcash_proofs/src/circuit/sprout/prfs.rs index 0b3e42c..ea87b08 100644 --- a/zcash_proofs/src/circuit/sprout/prfs.rs +++ b/zcash_proofs/src/circuit/sprout/prfs.rs @@ -1,11 +1,7 @@ -use pairing::{Engine}; +use bellman::gadgets::boolean::Boolean; +use bellman::gadgets::sha256::sha256_block_no_padding; use bellman::{ConstraintSystem, SynthesisError}; -use bellman::gadgets::sha256::{ - sha256_block_no_padding -}; -use bellman::gadgets::boolean::{ - Boolean -}; +use pairing::Engine; fn prf( cs: CS, @@ -14,9 +10,11 @@ fn prf( c: bool, d: bool, x: &[Boolean], - y: &[Boolean] + y: &[Boolean], ) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem +where + E: Engine, + CS: ConstraintSystem, { assert_eq!(x.len(), 252); assert_eq!(y.len(), 256); @@ -31,27 +29,35 @@ fn prf( assert_eq!(image.len(), 512); - sha256_block_no_padding( - cs, - &image - ) + sha256_block_no_padding(cs, &image) } -pub fn prf_a_pk( - cs: CS, - a_sk: &[Boolean] -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem +pub fn prf_a_pk(cs: CS, a_sk: &[Boolean]) -> Result, SynthesisError> +where + E: Engine, + CS: ConstraintSystem, { - prf(cs, true, true, false, false, a_sk, &(0..256).map(|_| Boolean::constant(false)).collect::>()) + prf( + cs, + true, + true, + false, + false, + a_sk, + &(0..256) + .map(|_| Boolean::constant(false)) + .collect::>(), + ) } pub fn prf_nf( cs: CS, a_sk: &[Boolean], - rho: &[Boolean] + rho: &[Boolean], ) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem +where + E: Engine, + CS: ConstraintSystem, { prf(cs, true, true, true, false, a_sk, rho) } @@ -60,9 +66,11 @@ pub fn prf_pk( cs: CS, a_sk: &[Boolean], h_sig: &[Boolean], - nonce: bool + nonce: bool, ) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem +where + E: Engine, + CS: ConstraintSystem, { prf(cs, false, nonce, false, false, a_sk, h_sig) } @@ -71,9 +79,11 @@ pub fn prf_rho( cs: CS, phi: &[Boolean], h_sig: &[Boolean], - nonce: bool + nonce: bool, ) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem +where + E: Engine, + CS: ConstraintSystem, { prf(cs, false, nonce, true, false, phi, h_sig) } diff --git a/zcash_proofs/src/prover.rs b/zcash_proofs/src/prover.rs index 1c1a972..6dd5767 100644 --- a/zcash_proofs/src/prover.rs +++ b/zcash_proofs/src/prover.rs @@ -3,11 +3,11 @@ use bellman::groth16::{Parameters, PreparedVerifyingKey}; use directories::BaseDirs; use pairing::bls12_381::{Bls12, Fr}; +use std::path::Path; use zcash_primitives::{ jubjub::{edwards, fs::Fs, Unknown}, primitives::{Diversifier, PaymentAddress, ProofGenerationKey}, }; -use std::path::Path; use zcash_primitives::{ merkle_tree::CommitmentTreeWitness, prover::TxProver, diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index e914171..283e76b 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -1,8 +1,6 @@ use bellman::{ gadgets::multipack, - groth16::{ - create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof, - }, + groth16::{create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof}, }; use ff::Field; use pairing::bls12_381::{Bls12, Fr}; From a7c5993597c93dd4839f51c639d13faa71fd6022 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Thu, 15 Aug 2019 10:41:48 -0600 Subject: [PATCH 077/330] cargo fmt --- ff/ff_derive/src/lib.rs | 127 ++++++++++++++------------- librustzcash/src/rustzcash.rs | 4 +- zcash_client_backend/src/encoding.rs | 4 +- 3 files changed, 67 insertions(+), 68 deletions(-) diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index df2625b..5f8e642 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -52,13 +52,8 @@ pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let mut gen = proc_macro2::TokenStream::new(); - let (constants_impl, sqrt_impl) = prime_field_constants_and_sqrt( - &ast.ident, - &repr_ident, - modulus, - limbs, - generator, - ); + let (constants_impl, sqrt_impl) = + prime_field_constants_and_sqrt(&ast.ident, &repr_ident, modulus, limbs, generator); gen.extend(constants_impl); gen.extend(prime_field_repr_impl(&repr_ident, limbs)); @@ -359,7 +354,8 @@ fn biguint_num_bits(mut v: BigUint) -> u32 { fn exp(base: BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint { let mut ret = BigUint::one(); - for i in exp.to_bytes_be() + for i in exp + .to_bytes_be() .into_iter() .flat_map(|x| (0..8).rev().map(move |i| (x >> i).is_odd())) { @@ -380,11 +376,13 @@ fn test_exp() { &BigUint::from_str("5489673498567349856734895").unwrap(), &BigUint::from_str( "52435875175126190479447740508185965837690552500527637822603658699938581184513" - ).unwrap() + ) + .unwrap() ), BigUint::from_str( "4371221214068404307866768905142520595925044802278091865033317963560480051536" - ).unwrap() + ) + .unwrap() ); } @@ -423,7 +421,7 @@ fn prime_field_constants_and_sqrt( let mod_minus_1_over_2 = biguint_to_u64_vec((&modulus - BigUint::from_str("1").unwrap()) >> 1, limbs); - let legendre_impl = quote!{ + let legendre_impl = quote! { fn legendre(&self) -> ::ff::LegendreSymbol { // s = self^((modulus - 1) // 2) let s = self.pow(#mod_minus_1_over_2); @@ -445,7 +443,7 @@ fn prime_field_constants_and_sqrt( // Compute -R as (m - r) let rneg = biguint_to_u64_vec(&modulus - &r, limbs); - quote!{ + quote! { impl ::ff::SqrtField for #name { #legendre_impl @@ -472,7 +470,7 @@ fn prime_field_constants_and_sqrt( let t_plus_1_over_2 = biguint_to_u64_vec((&t + BigUint::one()) >> 1, limbs); let t = biguint_to_u64_vec(t.clone(), limbs); - quote!{ + quote! { impl ::ff::SqrtField for #name { #legendre_impl @@ -519,7 +517,7 @@ fn prime_field_constants_and_sqrt( } } } else { - quote!{} + quote! {} }; // Compute R^2 mod m @@ -536,36 +534,39 @@ fn prime_field_constants_and_sqrt( } inv = inv.wrapping_neg(); - (quote! { - /// This is the modulus m of the prime field - const MODULUS: #repr = #repr([#(#modulus,)*]); + ( + quote! { + /// This is the modulus m of the prime field + const MODULUS: #repr = #repr([#(#modulus,)*]); - /// The number of bits needed to represent the modulus. - const MODULUS_BITS: u32 = #modulus_num_bits; + /// The number of bits needed to represent the modulus. + const MODULUS_BITS: u32 = #modulus_num_bits; - /// The number of bits that must be shaved from the beginning of - /// the representation when randomly sampling. - const REPR_SHAVE_BITS: u32 = #repr_shave_bits; + /// The number of bits that must be shaved from the beginning of + /// the representation when randomly sampling. + const REPR_SHAVE_BITS: u32 = #repr_shave_bits; - /// 2^{limbs*64} mod m - const R: #repr = #repr(#r); + /// 2^{limbs*64} mod m + const R: #repr = #repr(#r); - /// 2^{limbs*64*2} mod m - const R2: #repr = #repr(#r2); + /// 2^{limbs*64*2} mod m + const R2: #repr = #repr(#r2); - /// -(m^{-1} mod m) mod m - const INV: u64 = #inv; + /// -(m^{-1} mod m) mod m + const INV: u64 = #inv; - /// Multiplicative generator of `MODULUS` - 1 order, also quadratic - /// nonresidue. - const GENERATOR: #repr = #repr(#generator); + /// Multiplicative generator of `MODULUS` - 1 order, also quadratic + /// nonresidue. + const GENERATOR: #repr = #repr(#generator); - /// 2^s * t = MODULUS - 1 with t odd - const S: u32 = #s; + /// 2^s * t = MODULUS - 1 with t odd + const S: u32 = #s; - /// 2^s root of unity computed by GENERATOR^t - const ROOT_OF_UNITY: #repr = #repr(#root_of_unity); - }, sqrt_impl) + /// 2^s root of unity computed by GENERATOR^t + const ROOT_OF_UNITY: #repr = #repr(#root_of_unity); + }, + sqrt_impl, + ) } /// Implement PrimeField for the derived type. @@ -585,9 +586,9 @@ fn prime_field_impl( mont_paramlist.append_separated( (0..(limbs * 2)).map(|i| (i, get_temp(i))).map(|(i, x)| { if i != 0 { - quote!{mut #x: u64} + quote! {mut #x: u64} } else { - quote!{#x: u64} + quote! {#x: u64} } }), proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), @@ -600,7 +601,7 @@ fn prime_field_impl( for i in 0..limbs { { let temp = get_temp(i); - gen.extend(quote!{ + gen.extend(quote! { let k = #temp.wrapping_mul(INV); let mut carry = 0; ::ff::mac_with_carry(#temp, k, MODULUS.0[0], &mut carry); @@ -609,7 +610,7 @@ fn prime_field_impl( for j in 1..limbs { let temp = get_temp(i + j); - gen.extend(quote!{ + gen.extend(quote! { #temp = ::ff::mac_with_carry(#temp, k, MODULUS.0[#j], &mut carry); }); } @@ -617,17 +618,17 @@ fn prime_field_impl( let temp = get_temp(i + limbs); if i == 0 { - gen.extend(quote!{ + gen.extend(quote! { #temp = ::ff::adc(#temp, 0, &mut carry); }); } else { - gen.extend(quote!{ + gen.extend(quote! { #temp = ::ff::adc(#temp, carry2, &mut carry); }); } if i != (limbs - 1) { - gen.extend(quote!{ + gen.extend(quote! { let carry2 = carry; }); } @@ -636,7 +637,7 @@ fn prime_field_impl( for i in 0..limbs { let temp = get_temp(limbs + i); - gen.extend(quote!{ + gen.extend(quote! { (self.0).0[#i] = #temp; }); } @@ -648,14 +649,14 @@ fn prime_field_impl( let mut gen = proc_macro2::TokenStream::new(); for i in 0..(limbs - 1) { - gen.extend(quote!{ + gen.extend(quote! { let mut carry = 0; }); for j in (i + 1)..limbs { let temp = get_temp(i + j); if i == 0 { - gen.extend(quote!{ + gen.extend(quote! { let #temp = ::ff::mac_with_carry(0, (#a.0).0[#i], (#a.0).0[#j], &mut carry); }); } else { @@ -667,7 +668,7 @@ fn prime_field_impl( let temp = get_temp(i + limbs); - gen.extend(quote!{ + gen.extend(quote! { let #temp = carry; }); } @@ -677,21 +678,21 @@ fn prime_field_impl( let temp1 = get_temp(limbs * 2 - i - 1); if i == 1 { - gen.extend(quote!{ + gen.extend(quote! { let #temp0 = #temp1 >> 63; }); } else if i == (limbs * 2 - 1) { - gen.extend(quote!{ + gen.extend(quote! { let #temp0 = #temp0 << 1; }); } else { - gen.extend(quote!{ + gen.extend(quote! { let #temp0 = (#temp0 << 1) | (#temp1 >> 63); }); } } - gen.extend(quote!{ + gen.extend(quote! { let mut carry = 0; }); @@ -699,7 +700,7 @@ fn prime_field_impl( let temp0 = get_temp(i * 2); let temp1 = get_temp(i * 2 + 1); if i == 0 { - gen.extend(quote!{ + gen.extend(quote! { let #temp0 = ::ff::mac_with_carry(0, (#a.0).0[#i], (#a.0).0[#i], &mut carry); }); } else { @@ -708,7 +709,7 @@ fn prime_field_impl( }); } - gen.extend(quote!{ + gen.extend(quote! { let #temp1 = ::ff::adc(#temp1, 0, &mut carry); }); } @@ -719,7 +720,7 @@ fn prime_field_impl( proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), ); - gen.extend(quote!{ + gen.extend(quote! { self.mont_reduce(#mont_calling); }); @@ -734,7 +735,7 @@ fn prime_field_impl( let mut gen = proc_macro2::TokenStream::new(); for i in 0..limbs { - gen.extend(quote!{ + gen.extend(quote! { let mut carry = 0; }); @@ -742,7 +743,7 @@ fn prime_field_impl( let temp = get_temp(i + j); if i == 0 { - gen.extend(quote!{ + gen.extend(quote! { let #temp = ::ff::mac_with_carry(0, (#a.0).0[#i], (#b.0).0[#j], &mut carry); }); } else { @@ -754,7 +755,7 @@ fn prime_field_impl( let temp = get_temp(i + limbs); - gen.extend(quote!{ + gen.extend(quote! { let #temp = carry; }); } @@ -765,29 +766,29 @@ fn prime_field_impl( proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), ); - gen.extend(quote!{ + gen.extend(quote! { self.mont_reduce(#mont_calling); }); gen } - let squaring_impl = sqr_impl(quote!{self}, limbs); - let multiply_impl = mul_impl(quote!{self}, quote!{other}, limbs); + let squaring_impl = sqr_impl(quote! {self}, limbs); + let multiply_impl = mul_impl(quote! {self}, quote! {other}, limbs); let montgomery_impl = mont_impl(limbs); // (self.0).0[0], (self.0).0[1], ..., 0, 0, 0, 0, ... let mut into_repr_params = proc_macro2::TokenStream::new(); into_repr_params.append_separated( (0..limbs) - .map(|i| quote!{ (self.0).0[#i] }) - .chain((0..limbs).map(|_| quote!{0})), + .map(|i| quote! { (self.0).0[#i] }) + .chain((0..limbs).map(|_| quote! {0})), proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), ); let top_limb_index = limbs - 1; - quote!{ + quote! { impl ::std::marker::Copy for #name { } impl ::std::clone::Clone for #name { diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index b1e0a30..0697272 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -59,9 +59,7 @@ use std::os::windows::ffi::OsStringExt; use zcash_primitives::{ merkle_tree::CommitmentTreeWitness, note_encryption::sapling_ka_agree, - primitives::{ - Diversifier, Note, PaymentAddress, ProofGenerationKey, ViewingKey, - }, + primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ViewingKey}, redjubjub::{self, Signature}, sapling::{merkle_hash, spend_sig}, transaction::components::Amount, diff --git a/zcash_client_backend/src/encoding.rs b/zcash_client_backend/src/encoding.rs index e84defa..d39973d 100644 --- a/zcash_client_backend/src/encoding.rs +++ b/zcash_client_backend/src/encoding.rs @@ -5,11 +5,11 @@ use bech32::{self, Error, FromBase32, ToBase32}; use pairing::bls12_381::Bls12; +use std::io::{self, Write}; use zcash_primitives::{ jubjub::edwards, primitives::{Diversifier, PaymentAddress}, }; -use std::io::{self, Write}; use zcash_primitives::{ zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}, JUBJUB, @@ -187,11 +187,11 @@ mod tests { use pairing::bls12_381::Bls12; use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; + use zcash_primitives::JUBJUB; use zcash_primitives::{ jubjub::edwards, primitives::{Diversifier, PaymentAddress}, }; - use zcash_primitives::JUBJUB; use super::{decode_payment_address, encode_payment_address}; use crate::constants; From 7461f8936d2da1a98ef405ae9163f6af121132d8 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Thu, 15 Aug 2019 10:45:24 -0600 Subject: [PATCH 078/330] Update travis to require formatting --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 9ddae8a..399eaf1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,5 +4,9 @@ rust: cache: cargo +before_script: + - rustup component add rustfmt + script: + - cargo fmt --all -- --check - cargo test --verbose --release --all From 40f768ed606d04f372bfb55c5a06361a72d2b0f3 Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Sat, 17 Aug 2019 11:58:22 +0200 Subject: [PATCH 079/330] Fix off-by-one so pedersen_hash doesn't consume too many generators. --- zcash_proofs/src/circuit/pedersen_hash.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index 21c0bf5..3cd9367 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -26,12 +26,12 @@ where assert_eq!(personalization.len(), 6); let mut edwards_result = None; - let mut bits = personalization.iter().chain(bits.iter()); + let mut bits = personalization.iter().chain(bits.iter()).peekable(); let mut segment_generators = params.pedersen_circuit_generators().iter(); let boolean_false = Boolean::constant(false); let mut segment_i = 0; - loop { + while bits.peek().is_some() { let mut segment_result = None; let mut segment_windows = &segment_generators.next().expect("enough segments")[..]; From 081937162ce7cea128d7fd6adea30d35ef14b584 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 19 Aug 2019 11:29:06 +0300 Subject: [PATCH 080/330] Initial commit --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..6eefe94 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# zcash-mmr \ No newline at end of file From ae364f3ae7d284ccb1e00be21c0654a785d727a3 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 20 Aug 2019 18:05:14 +0300 Subject: [PATCH 081/330] initial commit --- .gitignore | 4 + Cargo.toml | 10 ++ src/lib.rs | 66 ++++++++++++ src/tree.rs | 290 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 370 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs create mode 100644 src/tree.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..293dd90 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target +**/*.rs.bk +Cargo.lock +.idea \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c64cb6a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "zcash-mmr" +version = "0.1.0" +authors = ["NikVolf "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +owning_ref = "0.3" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..abc0d45 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,66 @@ +//! MMR library for Zcash +//! +//! To be used in zebra and via FFI bindings in zcashd + +extern crate owning_ref; + +mod tree; + +#[repr(C)] +#[derive(Debug)] +pub struct NodeData { + subtree_commitment: [u8; 32], + start_time: u32, + end_time: u32, + start_target: u32, + end_target: u32, + start_sapling_root: [u8; 32], + end_sapling_root: [u8; 32], + subtree_total_work: u64, + start_height: u32, + end_height: u32, + shielded_tx: u64, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub enum NodeLink { + Stored(u32), + Generated(u32), +} + +#[repr(C)] +#[derive(Debug)] +pub struct MMRNode { + left: Option, + right: Option, + data: NodeData, +} + +impl MMRNode { + fn complete(&self) -> bool { + let leaves = self.data.end_height - self.data.start_height + 1; + leaves & (leaves - 1) == 0 + } +} + +impl From for MMRNode { + fn from(s: NodeData) -> Self { + MMRNode { left: None, right: None, data: s } + } +} + +#[no_mangle] +pub extern fn append( + stored: *const MMRNode, + stored_count: u32, + generated: *const MMRNode, + generated_count: u32, + append_count: *mut u32, + append_buffer: *mut MMRNode, +) -> MMRNode { + + // TODO: construct tree and write to (append_count, append_buffer) + // TODO: also return generated?? + unimplemented!() +} diff --git a/src/tree.rs b/src/tree.rs new file mode 100644 index 0000000..9027f21 --- /dev/null +++ b/src/tree.rs @@ -0,0 +1,290 @@ +use std::collections::HashMap; + +use crate::{MMRNode, NodeLink, NodeData}; + +#[derive(Default)] +struct Tree { + stored: HashMap, + + generated: HashMap, + + // number of persistent(!) tree entries + stored_count: u32, + + // number of virtual nodes generated + generated_count: u32, +} + +impl Tree { + fn resolve_link(&self, link: NodeLink) -> IndexedNode { + match link { + NodeLink::Generated(index) => { + // TODO: maybe graceful error? + let node = self.generated.get(&index).expect("caller should ensure id generated"); + IndexedNode { + node, + link, + } + }, + NodeLink::Stored(index) => { + // TODO: maybe graceful error? + let node = self.stored.get(&index).expect("caller should ensure id stored"); + IndexedNode { + node, + link, + } + }, + } + } + + fn push(&mut self, data: MMRNode) -> NodeLink { + let idx = self.stored_count; + self.stored_count = self.stored_count + 1; + self.stored.insert(idx, data); + NodeLink::Stored(idx) + } + + fn push_generated(&mut self, data: MMRNode) -> NodeLink { + let idx = self.generated_count; + self.generated_count = self.generated_count + 1; + self.generated.insert(idx, data); + NodeLink::Generated(idx) + } + + pub fn populate(loaded: Vec) -> Self { + let mut result = Tree::default(); + result.stored_count = loaded.len() as u32; + for (idx, item) in loaded.into_iter().enumerate() { + result.stored.insert(idx as u32, item); + } + + result + } +} + +/// plain list of nodes that has to be appended to the end of the tree as the result of append operation +/// along with new root +pub struct AppendTransaction { + pub appended: Vec, + pub new_root: NodeLink, +} + +struct IndexedNode<'a> { + node: &'a MMRNode, + link: NodeLink, +} + +fn combine_data(left: &NodeData, right: &NodeData) -> NodeData { + NodeData { + // TODO: hash children + subtree_commitment: [0u8; 32], + start_time: left.start_time, + end_time: right.end_time, + start_target: left.start_target, + end_target: right.end_target, + start_sapling_root: left.start_sapling_root, + end_sapling_root: right.end_sapling_root, + + // TODO: sum work? + subtree_total_work: 0, + start_height: left.start_height, + end_height: right.end_height, + shielded_tx: left.shielded_tx + right.shielded_tx, + } +} + +fn combine_nodes<'a>(left: IndexedNode<'a>, right: IndexedNode<'a>) -> MMRNode { + MMRNode { + left: Some(left.link), + right: Some(right.link), + data: combine_data(&left.node.data, &right.node.data), + } +} + +fn append(tree: &mut Tree, root: NodeLink, new_leaf: NodeData) -> AppendTransaction { + + let is_complete= tree.resolve_link(root).node.complete(); + + let (new_root_node, mut appended) = if is_complete { + let new_leaf_link = tree.push(new_leaf.into()); + + let mut appended = Vec::new(); + appended.push(new_leaf_link); + + // since we dethrone stored root, new one is always generated + let new_root_node = combine_nodes( + tree.resolve_link(root), + tree.resolve_link(new_leaf_link), + ); + + (new_root_node, appended) + + + } else { + let (root_left_child, root_right_child) = { + let root = tree.resolve_link(root).node; + ( + root.left.expect("Root should always have left child"), + root.right.expect("Root should always have right child"), + ) + }; + + let nested_append = append(tree, root_right_child, new_leaf); + let mut appended = nested_append.appended; + let subtree_root = nested_append.new_root; + + let new_root_node = combine_nodes( + tree.resolve_link(root_left_child), + tree.resolve_link(subtree_root), + ); + + (new_root_node, appended) + }; + + let new_root = if new_root_node.complete() { + let new_root= tree.push(new_root_node); + appended.push(new_root); + new_root + } else { + tree.push_generated(new_root_node) + }; + + AppendTransaction { + new_root, + appended, + } +} + +#[cfg(test)] +mod tests { + + use super::{MMRNode, NodeData, Tree, append, NodeLink}; + + fn leaf(height: u32) -> NodeData { + NodeData { + // TODO: hash children + subtree_commitment: [0u8; 32], + start_time: 0, + end_time: 0, + start_target: 0, + end_target: 0, + start_sapling_root: [0u8; 32], + end_sapling_root: [0u8; 32], + + // TODO: sum work? + subtree_total_work: 0, + start_height: height, + end_height: height, + shielded_tx: 7, + } + } + + fn node(start_height: u32, end_height: u32) -> NodeData { + NodeData { + // TODO: hash children + subtree_commitment: [0u8; 32], + start_time: 0, + end_time: 0, + start_target: 0, + end_target: 0, + start_sapling_root: [0u8; 32], + end_sapling_root: [0u8; 32], + + // TODO: sum work? + subtree_total_work: 0, + start_height: start_height, + end_height: end_height, + shielded_tx: 7, + } + } + + // size should be power of 2-1 + fn initial() -> Tree { + let node1: MMRNode = leaf(1).into(); + let node2: MMRNode = leaf(2).into(); + + let node3 = MMRNode { + data: node(1, 2), + left: Some(NodeLink::Stored(0)), + right: Some(NodeLink::Stored(1)), + }; + + Tree::populate(vec![node1, node2, node3]) + } + + #[test] + fn discrete_append() { + let mut tree = initial(); + let append_tx = append( + &mut tree, NodeLink::Stored(2), + leaf(3) + ); + let new_root_link = append_tx.new_root; + let new_root = tree.resolve_link(new_root_link).node; + + // initial tree: (2) + // / \ + // (0) (1) + // + // new tree: + // (4g) + // / \ + // (2) \ + // / \ \ + // (0) (1) (3) + // + // so only (3) is added as real leaf + // while new root, (4g) is generated one + assert_eq!(new_root.data.end_height, 3); + assert_eq!(append_tx.appended.len(), 1); + + let append_tx = append(&mut tree, new_root_link, leaf(4)); + let new_root_link = append_tx.new_root; + let new_root = tree.resolve_link(new_root_link).node; + + // intermediate tree: + // (4g) + // / \ + // (2) \ + // / \ \ + // (0) (1) (3) + // + // new tree: + // ( 6 ) + // / \ + // (2) (5) + // / \ / \ + // (0) (1) (3) (4) + // + // so (4), (5), (6) are added as real leaves + // and new root, (6) is stored one + assert_eq!(new_root.data.end_height, 4); + assert_eq!(append_tx.appended.len(), 3); + + let append_tx = append(&mut tree, new_root_link, leaf(5)); + let new_root_link = append_tx.new_root; + let new_root = tree.resolve_link(new_root_link).node; + + // intermediate tree: + // ( 6 ) + // / \ + // (2) (5) + // / \ / \ + // (0) (1) (3) (4) + // + // new tree: + // ( 8g ) + // / \ + // ( 6 ) \ + // / \ \ + // (2) (5) \ + // / \ / \ \ + // (0) (1) (3) (4) (7) + // + // so (7) is added as real leaf + // and new root, (8g) is generated one + assert_eq!(new_root.data.end_height, 5); + assert_eq!(append_tx.appended.len(), 1); + } + +} \ No newline at end of file From c794cdc6803ba01f00aa6790dd2d7d45b7c6f5d3 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 20 Aug 2019 18:09:09 +0300 Subject: [PATCH 082/330] fix signature and generate h --- bindings.h | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 +- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 bindings.h diff --git a/bindings.h b/bindings.h new file mode 100644 index 0000000..818dfc8 --- /dev/null +++ b/bindings.h @@ -0,0 +1,59 @@ +#include +#include +#include +#include + +template +struct Option; + +struct NodeLink { + enum class Tag { + Stored, + Generated, + }; + + struct Stored_Body { + uint32_t _0; + }; + + struct Generated_Body { + uint32_t _0; + }; + + Tag tag; + union { + Stored_Body stored; + Generated_Body generated; + }; +}; + +struct NodeData { + uint8_t subtree_commitment[32]; + uint32_t start_time; + uint32_t end_time; + uint32_t start_target; + uint32_t end_target; + uint8_t start_sapling_root[32]; + uint8_t end_sapling_root[32]; + uint64_t subtree_total_work; + uint32_t start_height; + uint32_t end_height; + uint64_t shielded_tx; +}; + +struct MMRNode { + Option left; + Option right; + NodeData data; +}; + +extern "C" { + +void append(const MMRNode *stored, + uint32_t stored_count, + const MMRNode *generated, + uint32_t generated_count, + uint32_t *append_count, + MMRNode *append_buffer); + +} // extern "C" diff --git a/src/lib.rs b/src/lib.rs index abc0d45..726e473 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,7 +58,7 @@ pub extern fn append( generated_count: u32, append_count: *mut u32, append_buffer: *mut MMRNode, -) -> MMRNode { +) { // TODO: construct tree and write to (append_count, append_buffer) // TODO: also return generated?? From d4b6c0e1a2084335b89f0e16baabfba829eecf8c Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Mon, 19 Aug 2019 14:04:41 +0200 Subject: [PATCH 083/330] Use expect to remove unreachable break. --- zcash_proofs/src/circuit/pedersen_hash.rs | 40 ++++++++++------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index 3cd9367..9558acc 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -72,32 +72,28 @@ where window_i += 1; } - match segment_result { - Some(segment_result) => { - // Convert this segment into twisted Edwards form. - let segment_result = segment_result.into_edwards( - cs.namespace(|| format!("conversion of segment {} into edwards", segment_i)), + let segment_result = segment_result.expect( + "bits is not exhausted due to while condition; + thus there must be a segment window; + thus there must be a segment result", + ); + + // Convert this segment into twisted Edwards form. + let segment_result = segment_result.into_edwards( + cs.namespace(|| format!("conversion of segment {} into edwards", segment_i)), + params, + )?; + + match edwards_result { + Some(ref mut edwards_result) => { + *edwards_result = segment_result.add( + cs.namespace(|| format!("addition of segment {} to accumulator", segment_i)), + edwards_result, params, )?; - - match edwards_result { - Some(ref mut edwards_result) => { - *edwards_result = segment_result.add( - cs.namespace(|| { - format!("addition of segment {} to accumulator", segment_i) - }), - edwards_result, - params, - )?; - } - None => { - edwards_result = Some(segment_result); - } - } } None => { - // We didn't process any new bits. - break; + edwards_result = Some(segment_result); } } From 845babc3c213a1de8fdd79f7c5b665be9c2f3d25 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 20 Aug 2019 18:42:44 +0300 Subject: [PATCH 084/330] remove unuse dep --- Cargo.toml | 5 ----- src/lib.rs | 2 -- 2 files changed, 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c64cb6a..0157039 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,8 +3,3 @@ name = "zcash-mmr" version = "0.1.0" authors = ["NikVolf "] edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -owning_ref = "0.3" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 726e473..f164295 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,8 +2,6 @@ //! //! To be used in zebra and via FFI bindings in zcashd -extern crate owning_ref; - mod tree; #[repr(C)] From fec7e077649f1d89936b024367abed4568b63b1b Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 20 Aug 2019 20:07:50 +0300 Subject: [PATCH 085/330] refactor and fix warnings --- src/lib.rs | 14 +++--- src/tree.rs | 137 ++++++++++++++++++++++++++-------------------------- 2 files changed, 76 insertions(+), 75 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f164295..cc73098 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,8 @@ mod tree; +pub use tree::Tree; + #[repr(C)] #[derive(Debug)] pub struct NodeData { @@ -50,12 +52,12 @@ impl From for MMRNode { #[no_mangle] pub extern fn append( - stored: *const MMRNode, - stored_count: u32, - generated: *const MMRNode, - generated_count: u32, - append_count: *mut u32, - append_buffer: *mut MMRNode, + _stored: *const MMRNode, + _stored_count: u32, + _generated: *const MMRNode, + _generated_count: u32, + _append_count: *mut u32, + _append_buffer: *mut MMRNode, ) { // TODO: construct tree and write to (append_count, append_buffer) diff --git a/src/tree.rs b/src/tree.rs index 9027f21..5495b49 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use crate::{MMRNode, NodeLink, NodeData}; #[derive(Default)] -struct Tree { +pub struct Tree { stored: HashMap, generated: HashMap, @@ -15,6 +15,13 @@ struct Tree { generated_count: u32, } +/// plain list of nodes that has to be appended to the end of the tree as the result of append operation +/// along with new root +pub struct AppendTransaction { + pub appended: Vec, + pub new_root: NodeLink, +} + impl Tree { fn resolve_link(&self, link: NodeLink) -> IndexedNode { match link { @@ -60,14 +67,64 @@ impl Tree { result } + + + pub fn append(&mut self, root: NodeLink, new_leaf: NodeData) -> AppendTransaction { + + let is_complete= self.resolve_link(root).node.complete(); + + let (new_root_node, mut appended) = if is_complete { + let new_leaf_link = self.push(new_leaf.into()); + + let mut appended = Vec::new(); + appended.push(new_leaf_link); + + // since we dethrone stored root, new one is always generated + let new_root_node = combine_nodes( + self.resolve_link(root), + self.resolve_link(new_leaf_link), + ); + + (new_root_node, appended) + + + } else { + let (root_left_child, root_right_child) = { + let root = self.resolve_link(root).node; + ( + root.left.expect("Root should always have left child"), + root.right.expect("Root should always have right child"), + ) + }; + + let nested_append = self.append(root_right_child, new_leaf); + let appended = nested_append.appended; + let subtree_root = nested_append.new_root; + + let new_root_node = combine_nodes( + self.resolve_link(root_left_child), + self.resolve_link(subtree_root), + ); + + (new_root_node, appended) + }; + + let new_root = if new_root_node.complete() { + let new_root= self.push(new_root_node); + appended.push(new_root); + new_root + } else { + self.push_generated(new_root_node) + }; + + AppendTransaction { + new_root, + appended, + } + } + } -/// plain list of nodes that has to be appended to the end of the tree as the result of append operation -/// along with new root -pub struct AppendTransaction { - pub appended: Vec, - pub new_root: NodeLink, -} struct IndexedNode<'a> { node: &'a MMRNode, @@ -101,64 +158,10 @@ fn combine_nodes<'a>(left: IndexedNode<'a>, right: IndexedNode<'a>) -> MMRNode { } } -fn append(tree: &mut Tree, root: NodeLink, new_leaf: NodeData) -> AppendTransaction { - - let is_complete= tree.resolve_link(root).node.complete(); - - let (new_root_node, mut appended) = if is_complete { - let new_leaf_link = tree.push(new_leaf.into()); - - let mut appended = Vec::new(); - appended.push(new_leaf_link); - - // since we dethrone stored root, new one is always generated - let new_root_node = combine_nodes( - tree.resolve_link(root), - tree.resolve_link(new_leaf_link), - ); - - (new_root_node, appended) - - - } else { - let (root_left_child, root_right_child) = { - let root = tree.resolve_link(root).node; - ( - root.left.expect("Root should always have left child"), - root.right.expect("Root should always have right child"), - ) - }; - - let nested_append = append(tree, root_right_child, new_leaf); - let mut appended = nested_append.appended; - let subtree_root = nested_append.new_root; - - let new_root_node = combine_nodes( - tree.resolve_link(root_left_child), - tree.resolve_link(subtree_root), - ); - - (new_root_node, appended) - }; - - let new_root = if new_root_node.complete() { - let new_root= tree.push(new_root_node); - appended.push(new_root); - new_root - } else { - tree.push_generated(new_root_node) - }; - - AppendTransaction { - new_root, - appended, - } -} - #[cfg(test)] mod tests { - use super::{MMRNode, NodeData, Tree, append, NodeLink}; + use super::{MMRNode, NodeData, Tree, NodeLink}; fn leaf(height: u32) -> NodeData { NodeData { @@ -198,7 +201,6 @@ mod tests { } } - // size should be power of 2-1 fn initial() -> Tree { let node1: MMRNode = leaf(1).into(); let node2: MMRNode = leaf(2).into(); @@ -215,10 +217,7 @@ mod tests { #[test] fn discrete_append() { let mut tree = initial(); - let append_tx = append( - &mut tree, NodeLink::Stored(2), - leaf(3) - ); + let append_tx = tree.append(NodeLink::Stored(2), leaf(3)); let new_root_link = append_tx.new_root; let new_root = tree.resolve_link(new_root_link).node; @@ -238,7 +237,7 @@ mod tests { assert_eq!(new_root.data.end_height, 3); assert_eq!(append_tx.appended.len(), 1); - let append_tx = append(&mut tree, new_root_link, leaf(4)); + let append_tx = tree.append(new_root_link, leaf(4)); let new_root_link = append_tx.new_root; let new_root = tree.resolve_link(new_root_link).node; @@ -261,7 +260,7 @@ mod tests { assert_eq!(new_root.data.end_height, 4); assert_eq!(append_tx.appended.len(), 3); - let append_tx = append(&mut tree, new_root_link, leaf(5)); + let append_tx = tree.append(new_root_link, leaf(5)); let new_root_link = append_tx.new_root; let new_root = tree.resolve_link(new_root_link).node; From 66c31be6c500951c099673132586199b52e1391a Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 20 Aug 2019 20:10:29 +0300 Subject: [PATCH 086/330] commit from cbindgen --- bindings.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bindings.h b/bindings.h index 818dfc8..fca8fa6 100644 --- a/bindings.h +++ b/bindings.h @@ -49,11 +49,11 @@ struct MMRNode { extern "C" { -void append(const MMRNode *stored, - uint32_t stored_count, - const MMRNode *generated, - uint32_t generated_count, - uint32_t *append_count, - MMRNode *append_buffer); +void append(const MMRNode *_stored, + uint32_t _stored_count, + const MMRNode *_generated, + uint32_t _generated_count, + uint32_t *_append_count, + MMRNode *_append_buffer); } // extern "C" From e59738b4eecafe2a3d1ebd10544dfd95fe4fd43d Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 16 Aug 2019 22:52:54 -0600 Subject: [PATCH 087/330] cargo fix --edition for ff --- ff/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 482dc46..fd1a502 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -266,7 +266,7 @@ pub trait PrimeField: Field { } /// Convert this prime field element into a biginteger representation. - fn from_repr(Self::Repr) -> Result; + fn from_repr(_: Self::Repr) -> Result; /// Convert a biginteger representation into a prime field element, if /// the number is an element of the field. From 4991e53f48db37b6b1317dce6b1486e0f6bd1295 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 16 Aug 2019 22:58:05 -0600 Subject: [PATCH 088/330] cargo fix --edition for bellman --- bellman/src/gadgets/uint32.rs | 4 ++-- bellman/src/groth16/generator.rs | 6 +++--- bellman/src/groth16/mod.rs | 6 +++--- bellman/src/groth16/prover.rs | 8 ++++---- bellman/src/groth16/tests/mod.rs | 2 +- bellman/src/groth16/verifier.rs | 2 +- bellman/tests/mimc.rs | 8 ++++---- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/bellman/src/gadgets/uint32.rs b/bellman/src/gadgets/uint32.rs index 4c0d376..ef3f44a 100644 --- a/bellman/src/gadgets/uint32.rs +++ b/bellman/src/gadgets/uint32.rs @@ -401,7 +401,7 @@ mod test { ]); for _ in 0..1000 { - let mut v = (0..32) + let v = (0..32) .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) .collect::>(); @@ -436,7 +436,7 @@ mod test { ]); for _ in 0..1000 { - let mut v = (0..32) + let v = (0..32) .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) .collect::>(); diff --git a/bellman/src/groth16/generator.rs b/bellman/src/groth16/generator.rs index 596464f..2ece8b7 100644 --- a/bellman/src/groth16/generator.rs +++ b/bellman/src/groth16/generator.rs @@ -8,11 +8,11 @@ use pairing::Engine; use super::{Parameters, VerifyingKey}; -use {Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; +use crate::{Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; -use domain::{EvaluationDomain, Scalar}; +use crate::domain::{EvaluationDomain, Scalar}; -use multicore::Worker; +use crate::multicore::Worker; /// Generates a random common reference string for /// a circuit. diff --git a/bellman/src/groth16/mod.rs b/bellman/src/groth16/mod.rs index 85b7952..428176b 100644 --- a/bellman/src/groth16/mod.rs +++ b/bellman/src/groth16/mod.rs @@ -1,10 +1,10 @@ use group::{CurveAffine, EncodedPoint}; use pairing::{Engine, PairingCurveAffine}; -use SynthesisError; +use crate::SynthesisError; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; -use multiexp::SourceBuilder; +use crate::multiexp::SourceBuilder; use std::io::{self, Read, Write}; use std::sync::Arc; @@ -465,7 +465,7 @@ impl<'a, E: Engine> ParameterSource for &'a Parameters { #[cfg(test)] mod test_with_bls12_381 { use super::*; - use {Circuit, ConstraintSystem, SynthesisError}; + use crate::{Circuit, ConstraintSystem, SynthesisError}; use ff::Field; use pairing::bls12_381::{Bls12, Fr}; diff --git a/bellman/src/groth16/prover.rs b/bellman/src/groth16/prover.rs index a502ac3..7fe282f 100644 --- a/bellman/src/groth16/prover.rs +++ b/bellman/src/groth16/prover.rs @@ -10,13 +10,13 @@ use pairing::Engine; use super::{ParameterSource, Proof}; -use {Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; +use crate::{Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; -use domain::{EvaluationDomain, Scalar}; +use crate::domain::{EvaluationDomain, Scalar}; -use multiexp::{multiexp, DensityTracker, FullDensity}; +use crate::multiexp::{multiexp, DensityTracker, FullDensity}; -use multicore::Worker; +use crate::multicore::Worker; fn eval( lc: &LinearCombination, diff --git a/bellman/src/groth16/tests/mod.rs b/bellman/src/groth16/tests/mod.rs index e6a36e4..d8be98e 100644 --- a/bellman/src/groth16/tests/mod.rs +++ b/bellman/src/groth16/tests/mod.rs @@ -6,7 +6,7 @@ use self::dummy_engine::*; use std::marker::PhantomData; -use {Circuit, ConstraintSystem, SynthesisError}; +use crate::{Circuit, ConstraintSystem, SynthesisError}; use super::{create_proof, generate_parameters, prepare_verifying_key, verify_proof}; diff --git a/bellman/src/groth16/verifier.rs b/bellman/src/groth16/verifier.rs index 926955a..065a3b0 100644 --- a/bellman/src/groth16/verifier.rs +++ b/bellman/src/groth16/verifier.rs @@ -4,7 +4,7 @@ use pairing::{Engine, PairingCurveAffine}; use super::{PreparedVerifyingKey, Proof, VerifyingKey}; -use SynthesisError; +use crate::SynthesisError; pub fn prepare_verifying_key(vk: &VerifyingKey) -> PreparedVerifyingKey { let mut gamma = vk.gamma_g2; diff --git a/bellman/tests/mimc.rs b/bellman/tests/mimc.rs index 18aaece..94c0d63 100644 --- a/bellman/tests/mimc.rs +++ b/bellman/tests/mimc.rs @@ -90,12 +90,12 @@ impl<'a, E: Engine> Circuit for MiMCDemo<'a, E> { let cs = &mut cs.namespace(|| format!("round {}", i)); // tmp = (xL + Ci)^2 - let mut tmp_value = xl_value.map(|mut e| { + let tmp_value = xl_value.map(|mut e| { e.add_assign(&self.constants[i]); e.square(); e }); - let mut tmp = cs.alloc( + let tmp = cs.alloc( || "tmp", || tmp_value.ok_or(SynthesisError::AssignmentMissing), )?; @@ -110,14 +110,14 @@ impl<'a, E: Engine> Circuit for MiMCDemo<'a, E> { // new_xL = xR + (xL + Ci)^3 // new_xL = xR + tmp * (xL + Ci) // new_xL - xR = tmp * (xL + Ci) - let mut new_xl_value = xl_value.map(|mut e| { + let new_xl_value = xl_value.map(|mut e| { e.add_assign(&self.constants[i]); e.mul_assign(&tmp_value.unwrap()); e.add_assign(&xr_value.unwrap()); e }); - let mut new_xl = if i == (MIMC_ROUNDS - 1) { + let new_xl = if i == (MIMC_ROUNDS - 1) { // This is the last round, xL is our image and so // we allocate a public input. cs.alloc_input( From fc3dd8198bc66cf227bb911f0921b3e918ec3941 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 16 Aug 2019 22:58:49 -0600 Subject: [PATCH 089/330] cargo fix --edition for group --- group/src/tests/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/group/src/tests/mod.rs b/group/src/tests/mod.rs index 2b58b6c..1970667 100644 --- a/group/src/tests/mod.rs +++ b/group/src/tests/mod.rs @@ -2,7 +2,7 @@ use ff::{Field, PrimeField}; use rand::SeedableRng; use rand_xorshift::XorShiftRng; -use {CurveAffine, CurveProjective, EncodedPoint}; +use crate::{CurveAffine, CurveProjective, EncodedPoint}; pub fn curve_tests() { let mut rng = XorShiftRng::from_seed([ @@ -71,7 +71,7 @@ pub fn curve_tests() { } fn random_wnaf_tests() { - use wnaf::*; + use crate::wnaf::*; let mut rng = XorShiftRng::from_seed([ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, From e12d315ab9db4337207ed14eb8fcfd90084670a4 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Fri, 16 Aug 2019 23:06:18 -0600 Subject: [PATCH 090/330] Warning cleanup --- zcash_primitives/src/jubjub/mod.rs | 2 +- zcash_primitives/src/transaction/components/amount.rs | 4 ++-- zcash_proofs/src/circuit/pedersen_hash.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/zcash_primitives/src/jubjub/mod.rs b/zcash_primitives/src/jubjub/mod.rs index 7ab0d0e..e626db1 100644 --- a/zcash_primitives/src/jubjub/mod.rs +++ b/zcash_primitives/src/jubjub/mod.rs @@ -374,7 +374,7 @@ impl JubjubBls12 { let mut pedersen_circuit_generators = vec![]; // Process each segment - for mut gen in tmp_params.pedersen_hash_generators.iter().cloned() { + for gen in tmp_params.pedersen_hash_generators.iter().cloned() { let mut gen = montgomery::Point::from_edwards(&gen, &tmp_params); let mut windows = vec![]; for _ in 0..tmp_params.pedersen_hash_chunks_per_generator() { diff --git a/zcash_primitives/src/transaction/components/amount.rs b/zcash_primitives/src/transaction/components/amount.rs index 8d358fb..f3f89af 100644 --- a/zcash_primitives/src/transaction/components/amount.rs +++ b/zcash_primitives/src/transaction/components/amount.rs @@ -206,7 +206,7 @@ mod tests { #[should_panic] fn add_panics_on_overflow() { let v = Amount(MAX_MONEY); - let sum = v + Amount(1); + let _sum = v + Amount(1); } #[test] @@ -220,7 +220,7 @@ mod tests { #[should_panic] fn sub_panics_on_underflow() { let v = Amount(-MAX_MONEY); - let diff = v - Amount(1); + let _diff = v - Amount(1); } #[test] diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index 21c0bf5..7a541b7 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -163,7 +163,7 @@ mod test { for length in 0..751 { for _ in 0..5 { - let mut input: Vec = (0..length).map(|_| rng.next_u32() % 2 != 0).collect(); + let input: Vec = (0..length).map(|_| rng.next_u32() % 2 != 0).collect(); let mut cs = TestConstraintSystem::::new(); From f1b6e88f9f8d63ca60adeeef18e37d78bb9d5d0c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 20 Aug 2019 23:46:53 +0100 Subject: [PATCH 091/330] Add a GitHub Actions workflow for Ubuntu and Windows --- .github/workflows/rust.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/workflows/rust.yml diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..81d0285 --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,20 @@ +name: Rust + +on: [push] + +jobs: + test: + name: Test on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + + steps: + - uses: actions/checkout@v1 + - name: Check formatting + run: cargo fmt --all -- --check + - name: Build + run: cargo build --verbose --release --all + - name: Run tests + run: cargo test --verbose --release --all From b0d8747697b0cdac898bd1220d0513d677f142e3 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 20 Aug 2019 16:54:11 -0600 Subject: [PATCH 092/330] cargo fix --edition for zcash_primitives --- zcash_primitives/src/block.rs | 2 +- zcash_primitives/src/group_hash.rs | 4 ++-- zcash_primitives/src/jubjub/fs.rs | 4 ++-- zcash_primitives/src/jubjub/mod.rs | 6 +++--- zcash_primitives/src/lib.rs | 2 +- zcash_primitives/src/merkle_tree.rs | 10 +++++----- zcash_primitives/src/pedersen_hash.rs | 2 +- zcash_primitives/src/primitives.rs | 8 ++++---- zcash_primitives/src/redjubjub.rs | 2 +- zcash_primitives/src/sapling.rs | 2 +- zcash_primitives/src/transaction/builder.rs | 2 +- zcash_primitives/src/transaction/components.rs | 6 +++--- zcash_primitives/src/transaction/mod.rs | 4 ++-- zcash_primitives/src/transaction/sighash.rs | 2 +- zcash_primitives/src/transaction/tests.rs | 6 +++--- 15 files changed, 31 insertions(+), 31 deletions(-) diff --git a/zcash_primitives/src/block.rs b/zcash_primitives/src/block.rs index 05b65e0..c0eb92f 100644 --- a/zcash_primitives/src/block.rs +++ b/zcash_primitives/src/block.rs @@ -4,7 +4,7 @@ use std::fmt; use std::io::{self, Read, Write}; use std::ops::Deref; -use serialize::Vector; +use crate::serialize::Vector; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct BlockHash(pub [u8; 32]); diff --git a/zcash_primitives/src/group_hash.rs b/zcash_primitives/src/group_hash.rs index dec59cd..e67ca49 100644 --- a/zcash_primitives/src/group_hash.rs +++ b/zcash_primitives/src/group_hash.rs @@ -1,9 +1,9 @@ -use jubjub::{edwards, JubjubEngine, PrimeOrder}; +use crate::jubjub::{edwards, JubjubEngine, PrimeOrder}; use ff::PrimeField; use blake2s_simd::Params; -use constants; +use crate::constants; /// Produces a random point in the Jubjub curve. /// The point is guaranteed to be prime order diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index 768bd83..90a179f 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -75,9 +75,9 @@ pub struct FsRepr(pub [u64; 4]); impl ::std::fmt::Display for FsRepr { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - try!(write!(f, "0x")); + r#try!(write!(f, "0x")); for i in self.0.iter().rev() { - try!(write!(f, "{:016x}", *i)); + r#try!(write!(f, "{:016x}", *i)); } Ok(()) diff --git a/zcash_primitives/src/jubjub/mod.rs b/zcash_primitives/src/jubjub/mod.rs index e626db1..8d9e227 100644 --- a/zcash_primitives/src/jubjub/mod.rs +++ b/zcash_primitives/src/jubjub/mod.rs @@ -20,9 +20,9 @@ use ff::{Field, PrimeField, SqrtField}; use pairing::Engine; -use group_hash::group_hash; +use crate::group_hash::group_hash; -use constants; +use crate::constants; use pairing::bls12_381::{Bls12, Fr}; @@ -122,7 +122,7 @@ pub trait JubjubParams: Sized { fn generator(&self, base: FixedGenerators) -> &edwards::Point; /// Returns a window table [0, 1, ..., 8] for different magnitudes of some /// fixed generator. - fn circuit_generators(&self, FixedGenerators) -> &[Vec<(E::Fr, E::Fr)>]; + fn circuit_generators(&self, _: FixedGenerators) -> &[Vec<(E::Fr, E::Fr)>]; /// Returns the window size for exponentiation of Pedersen hash generators /// outside the circuit fn pedersen_hash_exp_window_size() -> u32; diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 1d4806e..8bc5fe8 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -43,7 +43,7 @@ pub mod zip32; #[cfg(test)] mod test_vectors; -use jubjub::JubjubBls12; +use crate::jubjub::JubjubBls12; lazy_static! { pub static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() }; diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index aa1596d..288ad21 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -5,8 +5,8 @@ use std::collections::VecDeque; use std::io::{self, Read, Write}; use std::iter; -use sapling::SAPLING_COMMITMENT_TREE_DEPTH; -use serialize::{Optional, Vector}; +use crate::sapling::SAPLING_COMMITMENT_TREE_DEPTH; +use crate::serialize::{Optional, Vector}; /// A hashable node within a Merkle tree. pub trait Hashable: Clone + Copy { @@ -17,13 +17,13 @@ pub trait Hashable: Clone + Copy { fn write(&self, writer: W) -> io::Result<()>; /// Returns the parent node within the tree of the two given nodes. - fn combine(usize, &Self, &Self) -> Self; + fn combine(_: usize, _: &Self, _: &Self) -> Self; /// Returns a blank leaf node. fn blank() -> Self; /// Returns the empty root for the given depth. - fn empty_root(usize) -> Self; + fn empty_root(_: usize) -> Self; } struct PathFiller { @@ -509,7 +509,7 @@ impl CommitmentTreeWitness { #[cfg(test)] mod tests { use super::{CommitmentTree, CommitmentTreeWitness, Hashable, IncrementalWitness, PathFiller}; - use sapling::Node; + use crate::sapling::Node; use ff::PrimeFieldRepr; use hex; diff --git a/zcash_primitives/src/pedersen_hash.rs b/zcash_primitives/src/pedersen_hash.rs index f21b17b..0274a1e 100644 --- a/zcash_primitives/src/pedersen_hash.rs +++ b/zcash_primitives/src/pedersen_hash.rs @@ -1,5 +1,5 @@ use ff::{Field, PrimeField, PrimeFieldRepr}; -use jubjub::*; +use crate::jubjub::*; #[derive(Copy, Clone)] pub enum Personalization { diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index d1282b7..10a6d6b 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -1,14 +1,14 @@ use ff::{Field, PrimeField, PrimeFieldRepr}; -use constants; +use crate::constants; -use group_hash::group_hash; +use crate::group_hash::group_hash; -use pedersen_hash::{pedersen_hash, Personalization}; +use crate::pedersen_hash::{pedersen_hash, Personalization}; use byteorder::{LittleEndian, WriteBytesExt}; -use jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder}; +use crate::jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder}; use blake2s_simd::Params as Blake2sParams; diff --git a/zcash_primitives/src/redjubjub.rs b/zcash_primitives/src/redjubjub.rs index 370f63d..6721b5e 100644 --- a/zcash_primitives/src/redjubjub.rs +++ b/zcash_primitives/src/redjubjub.rs @@ -6,7 +6,7 @@ use ff::{Field, PrimeField, PrimeFieldRepr}; use rand_core::RngCore; use std::io::{self, Read, Write}; -use util::hash_to_scalar; +use crate::util::hash_to_scalar; fn read_scalar(reader: R) -> io::Result { let mut s_repr = ::Repr::default(); diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index 02282d3..d84eec2 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -12,7 +12,7 @@ use std::io::{self, Read, Write}; use crate::merkle_tree::Hashable; use crate::redjubjub::{PrivateKey, PublicKey, Signature}; -use JUBJUB; +use crate::JUBJUB; pub const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32; diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index b0e96f5..244f41b 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -7,7 +7,7 @@ use crate::{ use ff::Field; use pairing::bls12_381::{Bls12, Fr}; use rand::{rngs::OsRng, seq::SliceRandom, CryptoRng, RngCore}; -use zip32::ExtendedSpendingKey; +use crate::zip32::ExtendedSpendingKey; use crate::{ keys::OutgoingViewingKey, diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index 7d2ffbb..31a7f4e 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -4,9 +4,9 @@ use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use std::io::{self, Read, Write}; -use legacy::Script; -use redjubjub::{PublicKey, Signature}; -use JUBJUB; +use crate::legacy::Script; +use crate::redjubjub::{PublicKey, Signature}; +use crate::JUBJUB; pub mod amount; pub use self::amount::Amount; diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index 6e2d15f..319ba85 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -5,8 +5,8 @@ use std::fmt; use std::io::{self, Read, Write}; use std::ops::Deref; -use redjubjub::Signature; -use serialize::Vector; +use crate::redjubjub::Signature; +use crate::serialize::Vector; pub mod builder; pub mod components; diff --git a/zcash_primitives/src/transaction/sighash.rs b/zcash_primitives/src/transaction/sighash.rs index b4e9a69..1b05658 100644 --- a/zcash_primitives/src/transaction/sighash.rs +++ b/zcash_primitives/src/transaction/sighash.rs @@ -7,7 +7,7 @@ use super::{ Transaction, TransactionData, OVERWINTER_VERSION_GROUP_ID, SAPLING_TX_VERSION, SAPLING_VERSION_GROUP_ID, }; -use legacy::Script; +use crate::legacy::Script; const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &'static [u8; 12] = b"ZcashSigHash"; const ZCASH_PREVOUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashPrevoutHash"; diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index 7c770c5..d772944 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -5,9 +5,9 @@ use rand_os::OsRng; use crate::jubjub::{fs::Fs, FixedGenerators}; use super::{components::Amount, sighash::signature_hash, Transaction, TransactionData}; -use legacy::Script; -use redjubjub::PrivateKey; -use JUBJUB; +use crate::legacy::Script; +use crate::redjubjub::PrivateKey; +use crate::JUBJUB; #[test] fn tx_read_write() { From cc0fc98c22e89316631d7ed15a0e20f90cc12623 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 20 Aug 2019 17:07:40 -0600 Subject: [PATCH 093/330] cargo fix --edition for pairing --- pairing/src/bls12_381/ec.rs | 8 ++++---- pairing/src/bls12_381/fq.rs | 10 +++++----- pairing/src/bls12_381/fq12.rs | 4 ++-- pairing/src/bls12_381/fq2.rs | 6 +++--- pairing/src/bls12_381/fq6.rs | 4 ++-- pairing/src/bls12_381/fr.rs | 10 +++++----- pairing/src/bls12_381/mod.rs | 2 +- pairing/src/bls12_381/tests/mod.rs | 2 +- pairing/src/lib.rs | 2 +- pairing/src/tests/engine.rs | 2 +- 10 files changed, 25 insertions(+), 25 deletions(-) diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index 9a78e37..3fc2b43 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -626,7 +626,7 @@ pub mod g1 { use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use rand_core::RngCore; use std::fmt; - use {Engine, PairingCurveAffine}; + use crate::{Engine, PairingCurveAffine}; curve_impl!( "G1", @@ -934,7 +934,7 @@ pub mod g1 { #[test] fn g1_generator() { - use SqrtField; + use crate::SqrtField; let mut x = Fq::zero(); let mut i = 0; @@ -1295,7 +1295,7 @@ pub mod g2 { use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use rand_core::RngCore; use std::fmt; - use {Engine, PairingCurveAffine}; + use crate::{Engine, PairingCurveAffine}; curve_impl!( "G2", @@ -1640,7 +1640,7 @@ pub mod g2 { #[test] fn g2_generator() { - use SqrtField; + use crate::SqrtField; let mut x = Fq2::zero(); let mut i = 0; diff --git a/pairing/src/bls12_381/fq.rs b/pairing/src/bls12_381/fq.rs index d272545..08135e3 100644 --- a/pairing/src/bls12_381/fq.rs +++ b/pairing/src/bls12_381/fq.rs @@ -2225,10 +2225,10 @@ fn test_fq_root_of_unity() { #[test] fn fq_field_tests() { - ::tests::field::random_field_tests::(); - ::tests::field::random_sqrt_tests::(); - ::tests::field::random_frobenius_tests::(Fq::char(), 13); - ::tests::field::from_str_tests::(); + crate::tests::field::random_field_tests::(); + crate::tests::field::random_sqrt_tests::(); + crate::tests::field::random_frobenius_tests::(Fq::char(), 13); + crate::tests::field::from_str_tests::(); } #[test] @@ -2244,7 +2244,7 @@ fn test_fq_ordering() { #[test] fn fq_repr_tests() { - ::tests::repr::random_repr_tests::(); + crate::tests::repr::random_repr_tests::(); } #[test] diff --git a/pairing/src/bls12_381/fq12.rs b/pairing/src/bls12_381/fq12.rs index dcfdef1..097b692 100644 --- a/pairing/src/bls12_381/fq12.rs +++ b/pairing/src/bls12_381/fq12.rs @@ -187,6 +187,6 @@ fn test_fq12_mul_by_014() { fn fq12_field_tests() { use ff::PrimeField; - ::tests::field::random_field_tests::(); - ::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); + crate::tests::field::random_field_tests::(); + crate::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); } diff --git a/pairing/src/bls12_381/fq2.rs b/pairing/src/bls12_381/fq2.rs index 7818280..3587d73 100644 --- a/pairing/src/bls12_381/fq2.rs +++ b/pairing/src/bls12_381/fq2.rs @@ -958,7 +958,7 @@ fn test_fq2_mul_nonresidue() { fn fq2_field_tests() { use ff::PrimeField; - ::tests::field::random_field_tests::(); - ::tests::field::random_sqrt_tests::(); - ::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); + crate::tests::field::random_field_tests::(); + crate::tests::field::random_sqrt_tests::(); + crate::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); } diff --git a/pairing/src/bls12_381/fq6.rs b/pairing/src/bls12_381/fq6.rs index b85c95d..0f434ff 100644 --- a/pairing/src/bls12_381/fq6.rs +++ b/pairing/src/bls12_381/fq6.rs @@ -378,6 +378,6 @@ fn test_fq6_mul_by_01() { fn fq6_field_tests() { use ff::PrimeField; - ::tests::field::random_field_tests::(); - ::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); + crate::tests::field::random_field_tests::(); + crate::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); } diff --git a/pairing/src/bls12_381/fr.rs b/pairing/src/bls12_381/fr.rs index 018e67a..76f3ffe 100644 --- a/pairing/src/bls12_381/fr.rs +++ b/pairing/src/bls12_381/fr.rs @@ -1015,13 +1015,13 @@ fn test_fr_root_of_unity() { #[test] fn fr_field_tests() { - ::tests::field::random_field_tests::(); - ::tests::field::random_sqrt_tests::(); - ::tests::field::random_frobenius_tests::(Fr::char(), 13); - ::tests::field::from_str_tests::(); + crate::tests::field::random_field_tests::(); + crate::tests::field::random_sqrt_tests::(); + crate::tests::field::random_frobenius_tests::(Fr::char(), 13); + crate::tests::field::from_str_tests::(); } #[test] fn fr_repr_tests() { - ::tests::repr::random_repr_tests::(); + crate::tests::repr::random_repr_tests::(); } diff --git a/pairing/src/bls12_381/mod.rs b/pairing/src/bls12_381/mod.rs index deb6ffc..8fc6bbd 100644 --- a/pairing/src/bls12_381/mod.rs +++ b/pairing/src/bls12_381/mod.rs @@ -366,5 +366,5 @@ impl G2Prepared { #[test] fn bls12_engine_tests() { - ::tests::engine::engine_tests::(); + crate::tests::engine::engine_tests::(); } diff --git a/pairing/src/bls12_381/tests/mod.rs b/pairing/src/bls12_381/tests/mod.rs index b5b75a3..636fcfe 100644 --- a/pairing/src/bls12_381/tests/mod.rs +++ b/pairing/src/bls12_381/tests/mod.rs @@ -2,7 +2,7 @@ use ff::PrimeFieldRepr; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use super::*; -use *; +use crate::*; #[test] fn test_pairing_result_against_relic() { diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs index 952185c..4e11107 100644 --- a/pairing/src/lib.rs +++ b/pairing/src/lib.rs @@ -87,7 +87,7 @@ pub trait Engine: ScalarEngine { >; /// Perform final exponentiation of the result of a miller loop. - fn final_exponentiation(&Self::Fqk) -> Option; + fn final_exponentiation(_: &Self::Fqk) -> Option; /// Performs a complete pairing operation `(p, q)`. fn pairing(p: G1, q: G2) -> Self::Fqk diff --git a/pairing/src/tests/engine.rs b/pairing/src/tests/engine.rs index fc74f1b..b6ae50e 100644 --- a/pairing/src/tests/engine.rs +++ b/pairing/src/tests/engine.rs @@ -2,7 +2,7 @@ use group::{CurveAffine, CurveProjective}; use rand_core::SeedableRng; use rand_xorshift::XorShiftRng; -use {Engine, Field, PairingCurveAffine, PrimeField}; +use crate::{Engine, Field, PairingCurveAffine, PrimeField}; pub fn engine_tests() { let mut rng = XorShiftRng::from_seed([ From f523ac285d8759773592b2bf1b93fd442269d8ba Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 20 Aug 2019 17:17:21 -0600 Subject: [PATCH 094/330] cargo fmt --- bellman/src/groth16/mod.rs | 2 +- pairing/src/bls12_381/ec.rs | 4 ++-- zcash_primitives/src/group_hash.rs | 2 +- zcash_primitives/src/pedersen_hash.rs | 2 +- zcash_primitives/src/transaction/builder.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bellman/src/groth16/mod.rs b/bellman/src/groth16/mod.rs index 428176b..9fa3bc8 100644 --- a/bellman/src/groth16/mod.rs +++ b/bellman/src/groth16/mod.rs @@ -3,8 +3,8 @@ use pairing::{Engine, PairingCurveAffine}; use crate::SynthesisError; -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use crate::multiexp::SourceBuilder; +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{self, Read, Write}; use std::sync::Arc; diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index 3fc2b43..6759991 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -622,11 +622,11 @@ macro_rules! curve_impl { pub mod g1 { use super::super::{Bls12, Fq, Fq12, FqRepr, Fr, FrRepr}; use super::g2::G2Affine; + use crate::{Engine, PairingCurveAffine}; use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use rand_core::RngCore; use std::fmt; - use crate::{Engine, PairingCurveAffine}; curve_impl!( "G1", @@ -1291,11 +1291,11 @@ pub mod g1 { pub mod g2 { use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr, FrRepr}; use super::g1::G1Affine; + use crate::{Engine, PairingCurveAffine}; use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use rand_core::RngCore; use std::fmt; - use crate::{Engine, PairingCurveAffine}; curve_impl!( "G2", diff --git a/zcash_primitives/src/group_hash.rs b/zcash_primitives/src/group_hash.rs index e67ca49..8549c5e 100644 --- a/zcash_primitives/src/group_hash.rs +++ b/zcash_primitives/src/group_hash.rs @@ -2,8 +2,8 @@ use crate::jubjub::{edwards, JubjubEngine, PrimeOrder}; use ff::PrimeField; -use blake2s_simd::Params; use crate::constants; +use blake2s_simd::Params; /// Produces a random point in the Jubjub curve. /// The point is guaranteed to be prime order diff --git a/zcash_primitives/src/pedersen_hash.rs b/zcash_primitives/src/pedersen_hash.rs index 0274a1e..835e9c7 100644 --- a/zcash_primitives/src/pedersen_hash.rs +++ b/zcash_primitives/src/pedersen_hash.rs @@ -1,5 +1,5 @@ -use ff::{Field, PrimeField, PrimeFieldRepr}; use crate::jubjub::*; +use ff::{Field, PrimeField, PrimeFieldRepr}; #[derive(Copy, Clone)] pub enum Personalization { diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 244f41b..a5df4c8 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -1,5 +1,6 @@ //! Structs for building transactions. +use crate::zip32::ExtendedSpendingKey; use crate::{ jubjub::fs::Fs, primitives::{Diversifier, Note, PaymentAddress}, @@ -7,7 +8,6 @@ use crate::{ use ff::Field; use pairing::bls12_381::{Bls12, Fr}; use rand::{rngs::OsRng, seq::SliceRandom, CryptoRng, RngCore}; -use crate::zip32::ExtendedSpendingKey; use crate::{ keys::OutgoingViewingKey, From 7809711a81074e021b1db354c9243d67f8603cc2 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 20 Aug 2019 18:19:11 -0600 Subject: [PATCH 095/330] cargo fix --edition for librustzcash --- librustzcash/src/tests/key_agreement.rs | 2 +- librustzcash/src/tests/key_components.rs | 2 +- librustzcash/src/tests/notes.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/librustzcash/src/tests/key_agreement.rs b/librustzcash/src/tests/key_agreement.rs index ab1cc84..d942e10 100644 --- a/librustzcash/src/tests/key_agreement.rs +++ b/librustzcash/src/tests/key_agreement.rs @@ -5,7 +5,7 @@ use rand_os::OsRng; use zcash_primitives::jubjub::{edwards, JubjubBls12}; use zcash_primitives::primitives::{Diversifier, ViewingKey}; -use { +use crate::{ librustzcash_sapling_generate_r, librustzcash_sapling_ka_agree, librustzcash_sapling_ka_derivepublic, }; diff --git a/librustzcash/src/tests/key_components.rs b/librustzcash/src/tests/key_components.rs index 99d3f52..a034b9f 100644 --- a/librustzcash/src/tests/key_components.rs +++ b/librustzcash/src/tests/key_components.rs @@ -7,7 +7,7 @@ use zcash_primitives::{ use super::JUBJUB; -use { +use crate::{ librustzcash_ask_to_ak, librustzcash_check_diversifier, librustzcash_crh_ivk, librustzcash_ivk_to_pkd, librustzcash_nsk_to_nk, }; diff --git a/librustzcash/src/tests/notes.rs b/librustzcash/src/tests/notes.rs index 6f8c0f5..6b48b5f 100644 --- a/librustzcash/src/tests/notes.rs +++ b/librustzcash/src/tests/notes.rs @@ -1,5 +1,5 @@ -use librustzcash_sapling_compute_cm; -use librustzcash_sapling_compute_nf; +use crate::librustzcash_sapling_compute_cm; +use crate::librustzcash_sapling_compute_nf; #[test] fn notes() { From b35a819a091f32f571a147bf99830c50cb2fb0a8 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 20 Aug 2019 18:24:47 -0600 Subject: [PATCH 096/330] Replace try! macro --- ff/ff_derive/src/lib.rs | 8 ++++---- zcash_primitives/src/jubjub/fs.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index 5f8e642..8801a91 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -122,9 +122,9 @@ fn prime_field_repr_impl(repr: &syn::Ident, limbs: usize) -> proc_macro2::TokenS impl ::std::fmt::Debug for #repr { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - try!(write!(f, "0x")); + write!(f, "0x")?; for i in self.0.iter().rev() { - try!(write!(f, "{:016x}", *i)); + write!(f, "{:016x}", *i)?; } Ok(()) @@ -133,9 +133,9 @@ fn prime_field_repr_impl(repr: &syn::Ident, limbs: usize) -> proc_macro2::TokenS impl ::std::fmt::Display for #repr { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - try!(write!(f, "0x")); + write!(f, "0x")?; for i in self.0.iter().rev() { - try!(write!(f, "{:016x}", *i)); + write!(f, "{:016x}", *i)?; } Ok(()) diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index 90a179f..fc14a86 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -75,9 +75,9 @@ pub struct FsRepr(pub [u64; 4]); impl ::std::fmt::Display for FsRepr { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - r#try!(write!(f, "0x")); + r#write!(f, "0x")?; for i in self.0.iter().rev() { - r#try!(write!(f, "{:016x}", *i)); + r#write!(f, "{:016x}", *i)?; } Ok(()) From 09882c6d08fdd323f6dd16729dc00ffba56adb8c Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 20 Aug 2019 18:31:20 -0600 Subject: [PATCH 097/330] Add edition = 2018 --- bellman/Cargo.toml | 1 + ff/Cargo.toml | 1 + ff/ff_derive/Cargo.toml | 1 + group/Cargo.toml | 1 + librustzcash/Cargo.toml | 3 ++- pairing/Cargo.toml | 1 + zcash_primitives/Cargo.toml | 1 + 7 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bellman/Cargo.toml b/bellman/Cargo.toml index 70521e7..f21e4e1 100644 --- a/bellman/Cargo.toml +++ b/bellman/Cargo.toml @@ -7,6 +7,7 @@ license = "MIT/Apache-2.0" name = "bellman" repository = "https://github.com/ebfull/bellman" version = "0.1.0" +edition = "2018" [dependencies] bit-vec = "0.4.4" diff --git a/ff/Cargo.toml b/ff/Cargo.toml index 212f6c4..93dfb9f 100644 --- a/ff/Cargo.toml +++ b/ff/Cargo.toml @@ -7,6 +7,7 @@ documentation = "https://docs.rs/ff/" homepage = "https://github.com/ebfull/ff" license = "MIT/Apache-2.0" repository = "https://github.com/ebfull/ff" +edition = "2018" [dependencies] byteorder = "1" diff --git a/ff/ff_derive/Cargo.toml b/ff/ff_derive/Cargo.toml index 914e392..e822460 100644 --- a/ff/ff_derive/Cargo.toml +++ b/ff/ff_derive/Cargo.toml @@ -7,6 +7,7 @@ documentation = "https://docs.rs/ff/" homepage = "https://github.com/ebfull/ff" license = "MIT/Apache-2.0" repository = "https://github.com/ebfull/ff" +edition = "2018" [lib] proc-macro = true diff --git a/group/Cargo.toml b/group/Cargo.toml index 7d2d531..2b09f09 100644 --- a/group/Cargo.toml +++ b/group/Cargo.toml @@ -11,6 +11,7 @@ description = "Elliptic curve group traits and utilities" documentation = "https://docs.rs/group/" homepage = "https://github.com/ebfull/group" repository = "https://github.com/ebfull/group" +edition = "2018" [dependencies] ff = { path = "../ff" } diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index 3256d14..8290191 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -6,7 +6,8 @@ authors = [ "Jack Grigg ", "Jay Graber ", "Simon Liu " - ] +] +edition = "2018" [lib] name = "rustzcash" diff --git a/pairing/Cargo.toml b/pairing/Cargo.toml index 759fd3d..8fadb32 100644 --- a/pairing/Cargo.toml +++ b/pairing/Cargo.toml @@ -13,6 +13,7 @@ description = "Pairing-friendly elliptic curve library" documentation = "https://docs.rs/pairing/" homepage = "https://github.com/ebfull/pairing" repository = "https://github.com/ebfull/pairing" +edition ="2018" [dependencies] byteorder = "1" diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index b3173b7..5e1bf91 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.0" authors = [ "Jack Grigg ", ] +edition = "2018" [dependencies] aes = "0.3" From 4b021fcf4d70296750258ce03186b83fc631093a Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 20 Aug 2019 22:01:46 -0600 Subject: [PATCH 098/330] cargo fix --edition-idioms for ff --- ff/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ff/src/lib.rs b/ff/src/lib.rs index fd1a502..14e3594 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -1,7 +1,7 @@ #![allow(unused_imports)] -extern crate byteorder; -extern crate rand_core; + + #[cfg(feature = "derive")] #[macro_use] @@ -210,7 +210,7 @@ impl Error for PrimeFieldDecodingError { } impl fmt::Display for PrimeFieldDecodingError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match *self { PrimeFieldDecodingError::NotInField(ref repr) => { write!(f, "{} is not an element of the field", repr) From a5f25c50589b21f38aa6cc446423934fefdfbfa0 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 20 Aug 2019 22:07:24 -0600 Subject: [PATCH 099/330] cargo fix --edition-idioms for bellman --- bellman/src/groth16/tests/dummy_engine.rs | 4 +-- bellman/src/lib.rs | 30 ++++++++++------------- bellman/src/multiexp.rs | 4 +-- bellman/tests/mimc.rs | 8 +++--- 4 files changed, 21 insertions(+), 25 deletions(-) diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 4c5874d..4692078 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -16,7 +16,7 @@ const MODULUS_R: Wrapping = Wrapping(64513); pub struct Fr(Wrapping); impl fmt::Display for Fr { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{}", (self.0).0) } } @@ -149,7 +149,7 @@ impl PartialOrd for FrRepr { } impl fmt::Display for FrRepr { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{}", (self.0)[0]) } } diff --git a/bellman/src/lib.rs b/bellman/src/lib.rs index 96400c9..e8ebaae 100644 --- a/bellman/src/lib.rs +++ b/bellman/src/lib.rs @@ -1,18 +1,16 @@ -extern crate ff; -extern crate group; -#[cfg(feature = "pairing")] -extern crate pairing; -extern crate rand_core; -extern crate bit_vec; -extern crate blake2s_simd; -extern crate byteorder; -extern crate futures; + + + + + + + + #[cfg(feature = "multicore")] extern crate crossbeam; -#[cfg(feature = "multicore")] -extern crate futures_cpupool; + #[cfg(feature = "multicore")] extern crate num_cpus; @@ -23,11 +21,9 @@ extern crate hex_literal; #[cfg(test)] extern crate rand; -#[cfg(test)] -extern crate rand_xorshift; -#[cfg(test)] -extern crate sha2; + + pub mod domain; pub mod gadgets; @@ -230,7 +226,7 @@ impl Error for SynthesisError { } impl fmt::Display for SynthesisError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { if let &SynthesisError::IoError(ref e) = self { write!(f, "I/O error: ")?; e.fmt(f) @@ -309,7 +305,7 @@ pub trait ConstraintSystem: Sized { /// This is a "namespaced" constraint system which borrows a constraint system (pushing /// a namespace context) and, when dropped, pops out of the namespace context. -pub struct Namespace<'a, E: ScalarEngine, CS: ConstraintSystem + 'a>(&'a mut CS, PhantomData); +pub struct Namespace<'a, E: ScalarEngine, CS: ConstraintSystem>(&'a mut CS, PhantomData); impl<'cs, E: ScalarEngine, CS: ConstraintSystem> ConstraintSystem for Namespace<'cs, E, CS> { type Root = CS::Root; diff --git a/bellman/src/multiexp.rs b/bellman/src/multiexp.rs index fabb978..b7729a8 100644 --- a/bellman/src/multiexp.rs +++ b/bellman/src/multiexp.rs @@ -153,7 +153,7 @@ fn multiexp_inner( mut skip: u32, c: u32, handle_trivial: bool, -) -> Box::Projective, Error = SynthesisError>> +) -> Box::Projective, Error = SynthesisError>> where for<'a> &'a Q: QueryDensity, D: Send + Sync + 'static + Clone + AsRef, @@ -256,7 +256,7 @@ pub fn multiexp( bases: S, density_map: D, exponents: Arc::Fr as PrimeField>::Repr>>, -) -> Box::Projective, Error = SynthesisError>> +) -> Box::Projective, Error = SynthesisError>> where for<'a> &'a Q: QueryDensity, D: Send + Sync + 'static + Clone + AsRef, diff --git a/bellman/tests/mimc.rs b/bellman/tests/mimc.rs index 94c0d63..7db26a5 100644 --- a/bellman/tests/mimc.rs +++ b/bellman/tests/mimc.rs @@ -1,7 +1,7 @@ -extern crate bellman; -extern crate ff; -extern crate pairing; -extern crate rand; + + + + // For randomness (during paramgen and proof generation) use rand::thread_rng; From 07c690cf73f89c69f9882d36bd16db1d83ab160f Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 20 Aug 2019 22:08:10 -0600 Subject: [PATCH 100/330] cargo fix --edition-idioms for group --- group/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/group/src/lib.rs b/group/src/lib.rs index 448c5a3..ab8ac0e 100644 --- a/group/src/lib.rs +++ b/group/src/lib.rs @@ -1,6 +1,6 @@ -extern crate ff; -extern crate rand; -extern crate rand_xorshift; + + + use ff::{PrimeField, PrimeFieldDecodingError, ScalarEngine, SqrtField}; use rand::RngCore; @@ -180,7 +180,7 @@ impl Error for GroupDecodingError { } impl fmt::Display for GroupDecodingError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match *self { GroupDecodingError::CoordinateDecodingError(description, ref err) => { write!(f, "{} decoding error: {}", description, err) From 9807a5c1cc3bb98d0c122f58f7a3f3c559d32864 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 20 Aug 2019 22:16:40 -0600 Subject: [PATCH 101/330] cargo fix --edition-idioms for pairing --- pairing/src/bls12_381/ec.rs | 12 ++++++------ pairing/src/bls12_381/fq12.rs | 2 +- pairing/src/bls12_381/fq2.rs | 2 +- pairing/src/bls12_381/fq6.rs | 2 +- pairing/src/lib.rs | 11 +++++------ 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs index 6759991..6bebc24 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/pairing/src/bls12_381/ec.rs @@ -18,7 +18,7 @@ macro_rules! curve_impl { } impl ::std::fmt::Display for $affine { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { if self.infinity { write!(f, "{}(Infinity)", $name) } else { @@ -35,7 +35,7 @@ macro_rules! curve_impl { } impl ::std::fmt::Display for $projective { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "{}", self.into_affine()) } } @@ -656,7 +656,7 @@ pub mod g1 { } impl fmt::Debug for G1Uncompressed { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.0[..].fmt(formatter) } } @@ -766,7 +766,7 @@ pub mod g1 { } impl fmt::Debug for G1Compressed { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.0[..].fmt(formatter) } } @@ -1325,7 +1325,7 @@ pub mod g2 { } impl fmt::Debug for G2Uncompressed { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.0[..].fmt(formatter) } } @@ -1451,7 +1451,7 @@ pub mod g2 { } impl fmt::Debug for G2Compressed { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.0[..].fmt(formatter) } } diff --git a/pairing/src/bls12_381/fq12.rs b/pairing/src/bls12_381/fq12.rs index 097b692..0d6e066 100644 --- a/pairing/src/bls12_381/fq12.rs +++ b/pairing/src/bls12_381/fq12.rs @@ -12,7 +12,7 @@ pub struct Fq12 { } impl ::std::fmt::Display for Fq12 { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "Fq12({} + {} * w)", self.c0, self.c1) } } diff --git a/pairing/src/bls12_381/fq2.rs b/pairing/src/bls12_381/fq2.rs index 3587d73..c115dd2 100644 --- a/pairing/src/bls12_381/fq2.rs +++ b/pairing/src/bls12_381/fq2.rs @@ -12,7 +12,7 @@ pub struct Fq2 { } impl ::std::fmt::Display for Fq2 { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "Fq2({} + {} * u)", self.c0, self.c1) } } diff --git a/pairing/src/bls12_381/fq6.rs b/pairing/src/bls12_381/fq6.rs index 0f434ff..e2b49c9 100644 --- a/pairing/src/bls12_381/fq6.rs +++ b/pairing/src/bls12_381/fq6.rs @@ -12,7 +12,7 @@ pub struct Fq6 { } impl ::std::fmt::Display for Fq6 { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "Fq6({} + {} * v, {} * v^2)", self.c0, self.c1, self.c2) } } diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs index 4e11107..4c1f6b7 100644 --- a/pairing/src/lib.rs +++ b/pairing/src/lib.rs @@ -11,13 +11,12 @@ // Force public structures to implement Debug #![deny(missing_debug_implementations)] -extern crate byteorder; -extern crate ff; -extern crate group; -extern crate rand_core; -#[cfg(test)] -extern crate rand_xorshift; + + + + + #[cfg(test)] pub mod tests; From 573ffc4e062d5fda7bcb7337a5ede972d6e34af6 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 20 Aug 2019 22:17:29 -0600 Subject: [PATCH 102/330] cargo fix --edition-idioms for librustzcash --- librustzcash/src/rustzcash.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 0697272..8d95880 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -1,16 +1,16 @@ -extern crate bellman; -extern crate blake2b_simd; -extern crate blake2s_simd; -extern crate byteorder; -extern crate ff; -extern crate libc; -extern crate pairing; -extern crate rand_core; -extern crate rand_os; -extern crate zcash_primitives; -extern crate zcash_proofs; -extern crate lazy_static; + + + + + + + + + + + +use lazy_static; use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; From c28ae31c71563e37f5eae088e01bbd25f59fe004 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 20 Aug 2019 22:20:22 -0600 Subject: [PATCH 103/330] cargo fix --edition-idioms for zcash_primitives --- zcash_primitives/src/block.rs | 2 +- zcash_primitives/src/jubjub/fs.rs | 4 +-- zcash_primitives/src/lib.rs | 29 +++++++++---------- .../src/transaction/components.rs | 8 ++--- zcash_primitives/src/transaction/mod.rs | 4 +-- zcash_primitives/src/zip32.rs | 4 +-- 6 files changed, 25 insertions(+), 26 deletions(-) diff --git a/zcash_primitives/src/block.rs b/zcash_primitives/src/block.rs index c0eb92f..f2802b4 100644 --- a/zcash_primitives/src/block.rs +++ b/zcash_primitives/src/block.rs @@ -10,7 +10,7 @@ use crate::serialize::Vector; pub struct BlockHash(pub [u8; 32]); impl fmt::Display for BlockHash { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let mut data = self.0.clone(); data.reverse(); formatter.write_str(&hex::encode(data)) diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index fc14a86..b3c61dc 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -74,7 +74,7 @@ const NEGATIVE_ONE: Fs = Fs(FsRepr([ pub struct FsRepr(pub [u64; 4]); impl ::std::fmt::Display for FsRepr { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { r#write!(f, "0x")?; for i in self.0.iter().rev() { r#write!(f, "{:016x}", *i)?; @@ -257,7 +257,7 @@ impl PrimeFieldRepr for FsRepr { pub struct Fs(FsRepr); impl ::std::fmt::Display for Fs { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "Fs({})", self.into_repr()) } } diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 8bc5fe8..5dd5f58 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -1,26 +1,25 @@ #[macro_use] extern crate lazy_static; -extern crate aes; -extern crate blake2b_simd; -extern crate blake2s_simd; -extern crate byteorder; -extern crate crypto_api_chachapoly; -extern crate ff; -extern crate fpe; -extern crate hex; -extern crate pairing; -extern crate rand; -extern crate rand_core; -extern crate rand_os; -extern crate sha2; + + + + + + + + + + + + + #[cfg(test)] #[macro_use] extern crate hex_literal; -#[cfg(test)] -extern crate rand_xorshift; + pub mod block; pub mod constants; diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index 31a7f4e..001ff42 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -104,7 +104,7 @@ pub struct SpendDescription { } impl std::fmt::Debug for SpendDescription { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { write!( f, "SpendDescription(cv = {:?}, anchor = {:?}, nullifier = {:?}, rk = {:?}, spend_auth_sig = {:?})", @@ -186,7 +186,7 @@ pub struct OutputDescription { } impl std::fmt::Debug for OutputDescription { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { write!( f, "OutputDescription(cv = {:?}, cmu = {:?}, ephemeral_key = {:?})", @@ -253,7 +253,7 @@ enum SproutProof { } impl std::fmt::Debug for SproutProof { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { match self { SproutProof::Groth(_) => write!(f, "SproutProof::Groth"), SproutProof::PHGR(_) => write!(f, "SproutProof::PHGR"), @@ -275,7 +275,7 @@ pub struct JSDescription { } impl std::fmt::Debug for JSDescription { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { write!( f, "JSDescription( diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index 319ba85..567d689 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -28,7 +28,7 @@ const SAPLING_TX_VERSION: u32 = 4; pub struct TxId(pub [u8; 32]); impl fmt::Display for TxId { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let mut data = self.0.clone(); data.reverse(); formatter.write_str(&hex::encode(data)) @@ -74,7 +74,7 @@ pub struct TransactionData { } impl std::fmt::Debug for TransactionData { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { write!( f, "TransactionData( diff --git a/zcash_primitives/src/zip32.rs b/zcash_primitives/src/zip32.rs index 7412406..8788809 100644 --- a/zcash_primitives/src/zip32.rs +++ b/zcash_primitives/src/zip32.rs @@ -198,7 +198,7 @@ impl std::cmp::PartialEq for ExtendedSpendingKey { } impl std::fmt::Debug for ExtendedSpendingKey { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { write!( f, "ExtendedSpendingKey(d = {}, tag_p = {:?}, i = {:?})", @@ -221,7 +221,7 @@ impl std::cmp::PartialEq for ExtendedFullViewingKey { } impl std::fmt::Debug for ExtendedFullViewingKey { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { write!( f, "ExtendedFullViewingKey(d = {}, tag_p = {:?}, i = {:?})", From 76795a90149f0c3ed9e1c53d2b40d653c724c197 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Tue, 20 Aug 2019 22:22:03 -0600 Subject: [PATCH 104/330] cargo fmt --- bellman/src/lib.rs | 14 -------------- bellman/tests/mimc.rs | 5 ----- ff/src/lib.rs | 3 --- group/src/lib.rs | 4 ---- librustzcash/src/rustzcash.rs | 12 ------------ pairing/src/lib.rs | 7 ------- zcash_primitives/src/lib.rs | 16 ---------------- 7 files changed, 61 deletions(-) diff --git a/bellman/src/lib.rs b/bellman/src/lib.rs index e8ebaae..a75c85f 100644 --- a/bellman/src/lib.rs +++ b/bellman/src/lib.rs @@ -1,13 +1,3 @@ - - - - - - - - - - #[cfg(feature = "multicore")] extern crate crossbeam; @@ -21,10 +11,6 @@ extern crate hex_literal; #[cfg(test)] extern crate rand; - - - - pub mod domain; pub mod gadgets; #[cfg(feature = "groth16")] diff --git a/bellman/tests/mimc.rs b/bellman/tests/mimc.rs index 7db26a5..e9a4c7c 100644 --- a/bellman/tests/mimc.rs +++ b/bellman/tests/mimc.rs @@ -1,8 +1,3 @@ - - - - - // For randomness (during paramgen and proof generation) use rand::thread_rng; diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 14e3594..fb692c2 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -1,8 +1,5 @@ #![allow(unused_imports)] - - - #[cfg(feature = "derive")] #[macro_use] extern crate ff_derive; diff --git a/group/src/lib.rs b/group/src/lib.rs index ab8ac0e..0d50f8a 100644 --- a/group/src/lib.rs +++ b/group/src/lib.rs @@ -1,7 +1,3 @@ - - - - use ff::{PrimeField, PrimeFieldDecodingError, ScalarEngine, SqrtField}; use rand::RngCore; use std::error::Error; diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 8d95880..ea1676d 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -1,15 +1,3 @@ - - - - - - - - - - - - use lazy_static; use ff::{PrimeField, PrimeFieldRepr}; diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs index 4c1f6b7..b5b46e3 100644 --- a/pairing/src/lib.rs +++ b/pairing/src/lib.rs @@ -11,13 +11,6 @@ // Force public structures to implement Debug #![deny(missing_debug_implementations)] - - - - - - - #[cfg(test)] pub mod tests; diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 5dd5f58..644d7fb 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -1,26 +1,10 @@ #[macro_use] extern crate lazy_static; - - - - - - - - - - - - - - #[cfg(test)] #[macro_use] extern crate hex_literal; - - pub mod block; pub mod constants; pub mod group_hash; From 37531ed7479755a944317c6e2699d125036d7aa2 Mon Sep 17 00:00:00 2001 From: Marco Stronati Date: Wed, 21 Aug 2019 08:28:44 +0200 Subject: [PATCH 105/330] Fixes after feedback --- librustzcash/src/rustzcash.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 0f47d8f..dca6617 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -143,7 +143,7 @@ pub extern "system" fn librustzcash_init_zksnark_params( let output_path = Path::new(OsStr::from_bytes(unsafe { slice::from_raw_parts(output_path, output_path_len) })); - let sprout_path = if sprout_path.is_null() && sprout_path_len == 0 { + let sprout_path = if sprout_path.is_null() { None } else { Some(Path::new(OsStr::from_bytes(unsafe { @@ -178,7 +178,7 @@ pub extern "system" fn librustzcash_init_zksnark_params( OsString::from_wide(unsafe { slice::from_raw_parts(spend_path, spend_path_len) }); let output_path = OsString::from_wide(unsafe { slice::from_raw_parts(output_path, output_path_len) }); - let sprout_path = if sprout_path.is_null() && sprout_path_len == 0 { + let sprout_path = if sprout_path.is_null() { None } else { Some(OsStr::from_wide(unsafe { @@ -215,7 +215,7 @@ fn init_zksnark_params( .to_str() .expect("hash should be a valid string"); - let sprout_hash_option = if sprout_path.is_none() { + let sprout_hash = if sprout_path.is_none() { None } else { Some( @@ -232,7 +232,7 @@ fn init_zksnark_params( output_path, output_hash, sprout_path, - sprout_hash_option, + sprout_hash, ); // Caller is responsible for calling this function once, so From fec961777c000b80b60384b8b3b13798ae6565a3 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Wed, 21 Aug 2019 16:11:29 -0600 Subject: [PATCH 106/330] Add edition = 2018 to zcash_proofs --- zcash_proofs/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index b7fa659..766db63 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.0" authors = [ "Jack Grigg ", ] +edition = "2018" [dependencies] bellman = { path = "../bellman" } From 53182aa08e305de43464729a372ea4cb7d36c3cd Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Wed, 21 Aug 2019 16:13:10 -0600 Subject: [PATCH 107/330] cargo fix --edition-idioms for zcash_proofs --- zcash_proofs/examples/bench.rs | 8 -------- zcash_proofs/src/lib.rs | 17 ----------------- 2 files changed, 25 deletions(-) diff --git a/zcash_proofs/examples/bench.rs b/zcash_proofs/examples/bench.rs index a5c8a13..62beb0a 100644 --- a/zcash_proofs/examples/bench.rs +++ b/zcash_proofs/examples/bench.rs @@ -1,11 +1,3 @@ -extern crate bellman; -extern crate ff; -extern crate pairing; -extern crate rand_core; -extern crate rand_xorshift; -extern crate zcash_primitives; -extern crate zcash_proofs; - use bellman::groth16::*; use ff::Field; use pairing::bls12_381::{Bls12, Fr}; diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs index 3851481..a83964a 100644 --- a/zcash_proofs/src/lib.rs +++ b/zcash_proofs/src/lib.rs @@ -1,20 +1,3 @@ -extern crate bellman; -extern crate blake2b_simd; -extern crate byteorder; -extern crate ff; -extern crate pairing; -extern crate rand_os; -extern crate zcash_primitives; - -#[cfg(feature = "local-prover")] -extern crate directories; - -#[cfg(test)] -extern crate rand_core; - -#[cfg(test)] -extern crate rand_xorshift; - use bellman::groth16::{prepare_verifying_key, Parameters, PreparedVerifyingKey, VerifyingKey}; use pairing::bls12_381::Bls12; use std::fs::File; From d63fa334ff3a3699fbf609573e5822abc21940d2 Mon Sep 17 00:00:00 2001 From: Eirik Ogilvie-Wigley Date: Wed, 21 Aug 2019 16:14:28 -0600 Subject: [PATCH 108/330] Remove unnecessary raw marker Co-Authored-By: str4d --- zcash_primitives/src/jubjub/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index b3c61dc..0d1578e 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -75,9 +75,9 @@ pub struct FsRepr(pub [u64; 4]); impl ::std::fmt::Display for FsRepr { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - r#write!(f, "0x")?; + write!(f, "0x")?; for i in self.0.iter().rev() { - r#write!(f, "{:016x}", *i)?; + write!(f, "{:016x}", *i)?; } Ok(()) From 261ad90d337e10aacfa18b6327eabf13a8191c61 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 22 Aug 2019 14:36:57 +0300 Subject: [PATCH 109/330] truncate leaf and test --- src/tree.rs | 104 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 91 insertions(+), 13 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index 5495b49..119673e 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -22,6 +22,11 @@ pub struct AppendTransaction { pub new_root: NodeLink, } +pub struct DeleteTransaction { + pub truncated: u32, + pub new_root: NodeLink, +} + impl Tree { fn resolve_link(&self, link: NodeLink) -> IndexedNode { match link { @@ -58,6 +63,7 @@ impl Tree { NodeLink::Generated(idx) } + // TODO: populate both stored and generated nodes? pub fn populate(loaded: Vec) -> Self { let mut result = Tree::default(); result.stored_count = loaded.len() as u32; @@ -69,7 +75,7 @@ impl Tree { } - pub fn append(&mut self, root: NodeLink, new_leaf: NodeData) -> AppendTransaction { + pub fn append_leaf(&mut self, root: NodeLink, new_leaf: NodeData) -> AppendTransaction { let is_complete= self.resolve_link(root).node.complete(); @@ -86,8 +92,6 @@ impl Tree { ); (new_root_node, appended) - - } else { let (root_left_child, root_right_child) = { let root = self.resolve_link(root).node; @@ -97,7 +101,7 @@ impl Tree { ) }; - let nested_append = self.append(root_right_child, new_leaf); + let nested_append = self.append_leaf(root_right_child, new_leaf); let appended = nested_append.appended; let subtree_root = nested_append.new_root; @@ -123,6 +127,61 @@ impl Tree { } } + fn pop(&mut self) { + self.stored.remove(&(self.stored_count-1)); + self.stored_count = self.stored_count - 1; + } + + pub fn truncate_leaf(&mut self, root: NodeLink) -> DeleteTransaction { + let root = { + let n = self.resolve_link(root); + let leaves = n.node.data.end_height - n.node.data.start_height + 1; + if leaves & 1 != 0 { + return DeleteTransaction { + truncated: 1, + new_root: n.node.left.expect("Root should have left child while deleting"), + } + } else { + n + } + }; + + let mut peaks = vec![root.node.left.expect("Root should have left child")]; + let mut subtree_root_link = root.node.right.expect("Root should have right child"); + let mut truncated = 1; + + loop { + let left_link = self.resolve_link(subtree_root_link).node.left; + if let Some(left_link) = left_link { + peaks.push(left_link); + subtree_root_link = self + .resolve_link(subtree_root_link).node.right + .expect("If left exists, right should exist as well"); + truncated += 1; + } else { + break; + } + } + + let root = peaks.drain(0..1).nth(0).expect("At lest 2 elements in peaks"); + let new_root = peaks.into_iter().fold( + root, + |root, next_peak| + self.push_generated( + combine_nodes( + self.resolve_link(root), + self.resolve_link(next_peak) + ) + ) + ); + + for _ in 0..truncated { self.pop(); } + + DeleteTransaction { + new_root, + truncated, + } + } } @@ -165,7 +224,6 @@ mod tests { fn leaf(height: u32) -> NodeData { NodeData { - // TODO: hash children subtree_commitment: [0u8; 32], start_time: 0, end_time: 0, @@ -173,8 +231,6 @@ mod tests { end_target: 0, start_sapling_root: [0u8; 32], end_sapling_root: [0u8; 32], - - // TODO: sum work? subtree_total_work: 0, start_height: height, end_height: height, @@ -184,7 +240,6 @@ mod tests { fn node(start_height: u32, end_height: u32) -> NodeData { NodeData { - // TODO: hash children subtree_commitment: [0u8; 32], start_time: 0, end_time: 0, @@ -192,8 +247,6 @@ mod tests { end_target: 0, start_sapling_root: [0u8; 32], end_sapling_root: [0u8; 32], - - // TODO: sum work? subtree_total_work: 0, start_height: start_height, end_height: end_height, @@ -214,10 +267,23 @@ mod tests { Tree::populate(vec![node1, node2, node3]) } + // returns tree with specified number of leafs and it's root + fn generated(length: u32) -> (Tree, NodeLink) { + assert!(length > 3); + let mut tree = initial(); + let mut root = NodeLink::Stored(2); + + for i in 2..length { + root = tree.append_leaf(root, leaf(i+1).into()).new_root; + } + + (tree, root) + } + #[test] fn discrete_append() { let mut tree = initial(); - let append_tx = tree.append(NodeLink::Stored(2), leaf(3)); + let append_tx = tree.append_leaf(NodeLink::Stored(2), leaf(3)); let new_root_link = append_tx.new_root; let new_root = tree.resolve_link(new_root_link).node; @@ -237,7 +303,7 @@ mod tests { assert_eq!(new_root.data.end_height, 3); assert_eq!(append_tx.appended.len(), 1); - let append_tx = tree.append(new_root_link, leaf(4)); + let append_tx = tree.append_leaf(new_root_link, leaf(4)); let new_root_link = append_tx.new_root; let new_root = tree.resolve_link(new_root_link).node; @@ -260,7 +326,7 @@ mod tests { assert_eq!(new_root.data.end_height, 4); assert_eq!(append_tx.appended.len(), 3); - let append_tx = tree.append(new_root_link, leaf(5)); + let append_tx = tree.append_leaf(new_root_link, leaf(5)); let new_root_link = append_tx.new_root; let new_root = tree.resolve_link(new_root_link).node; @@ -286,4 +352,16 @@ mod tests { assert_eq!(append_tx.appended.len(), 1); } + #[test] + fn truncate_simple() { + let (mut tree, root) = generated(9); + let delete_tx = tree.truncate_leaf(root); + + match delete_tx.new_root { + NodeLink::Stored(14) => { /* ok */ }, + _ => panic!("Root should be stored(14)") + } + + } + } \ No newline at end of file From f316c1b439f81ec373e25964e2a5b24a62e260d8 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 22 Aug 2019 14:37:26 +0300 Subject: [PATCH 110/330] remove whitespaces --- src/tree.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index 119673e..aeeb2cd 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -361,7 +361,5 @@ mod tests { NodeLink::Stored(14) => { /* ok */ }, _ => panic!("Root should be stored(14)") } - } - } \ No newline at end of file From 5c6d85671458a60d4d071958119e7697e0fdf79c Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 22 Aug 2019 15:47:49 +0300 Subject: [PATCH 111/330] extra test --- src/tree.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/tree.rs b/src/tree.rs index aeeb2cd..1ab941d 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -74,7 +74,6 @@ impl Tree { result } - pub fn append_leaf(&mut self, root: NodeLink, new_leaf: NodeData) -> AppendTransaction { let is_complete= self.resolve_link(root).node.complete(); @@ -352,6 +351,8 @@ mod tests { assert_eq!(append_tx.appended.len(), 1); } + // TODO: use assert_matches below + #[test] fn truncate_simple() { let (mut tree, root) = generated(9); @@ -362,4 +363,29 @@ mod tests { _ => panic!("Root should be stored(14)") } } + + #[test] + fn truncate_generated() { + let (mut tree, root) = generated(10); + let delete_tx = tree.truncate_leaf(root); + + match delete_tx.new_root { + NodeLink::Generated(_) => { /* ok */ }, + _ => panic!("Root now should be generated") + } + + let (left_root_child, right_root_child) = { + let root = tree.resolve_link(delete_tx.new_root); + + ( + root.node.left.expect("there should be left child for root"), + root.node.right.expect("there should be right child for root"), + ) + }; + + match (left_root_child, right_root_child) { + (NodeLink::Stored(14), NodeLink::Stored(15)) => { /* ok */ }, + _ => panic!("Root should have s(14) and s(15) children") + }; + } } \ No newline at end of file From 767d73f777758f2c39ec22eff975d7b1635664e2 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 22 Aug 2019 15:49:43 +0300 Subject: [PATCH 112/330] extra asserts --- src/tree.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tree.rs b/src/tree.rs index 1ab941d..aade996 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -181,6 +181,10 @@ impl Tree { truncated, } } + + pub fn len(&self) -> u32 { + self.stored_count + } } @@ -387,5 +391,8 @@ mod tests { (NodeLink::Stored(14), NodeLink::Stored(15)) => { /* ok */ }, _ => panic!("Root should have s(14) and s(15) children") }; + + assert_eq!(delete_tx.truncated, 2); + assert_eq!(tree.len(), 16); } } \ No newline at end of file From 3a09eef6b3aa20de3e09ef6c4764f1e9cc21cdf8 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 22 Aug 2019 15:59:18 +0300 Subject: [PATCH 113/330] some ascii fun --- src/tree.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index aade996..8b4648d 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -362,10 +362,35 @@ mod tests { let (mut tree, root) = generated(9); let delete_tx = tree.truncate_leaf(root); + // initial tree: + // + // (-------16g------) + // / \ + // (--------14-------) \ + // / \ \ + // ( 6 ) ( 13 ) \ + // / \ / \ \ + // (2) (5) (9) (12) \ + // / \ / \ / \ / \ \ + // (0) (1) (3) (4) (7) (8) (10) (11) (15) + // + // new tree: + // (--------14-------) + // / \ + // ( 6 ) ( 13 ) + // / \ / \ + // (2) (5) (9) (12) + // / \ / \ / \ / \ + // (0) (1) (3) (4) (7) (8) (10) (11) + // + // so (15) is truncated + // and new root, (14) is a stored one now + match delete_tx.new_root { NodeLink::Stored(14) => { /* ok */ }, _ => panic!("Root should be stored(14)") } + assert_eq!(tree.len(), 15); } #[test] @@ -373,11 +398,36 @@ mod tests { let (mut tree, root) = generated(10); let delete_tx = tree.truncate_leaf(root); + // initial tree: + // + // (--------18g--------) + // / \ + // (--------14-------) \ + // / \ \ + // ( 6 ) ( 13 ) \ + // / \ / \ \ + // (2) (5) (9) (12) (17) + // / \ / \ / \ / \ / \ + // (0) (1) (3) (4) (7) (8) (10) (11) (15) (16) + // + // new tree: + // (-------16g------) + // / \ + // (--------14-------) \ + // / \ \ + // ( 6 ) ( 13 ) \ + // / \ / \ \ + // (2) (5) (9) (12) \ + // / \ / \ / \ / \ \ + // (0) (1) (3) (4) (7) (8) (10) (11) (15) + + // new root is generated match delete_tx.new_root { NodeLink::Generated(_) => { /* ok */ }, _ => panic!("Root now should be generated") } + // left is 14 and right is 15 let (left_root_child, right_root_child) = { let root = tree.resolve_link(delete_tx.new_root); @@ -386,12 +436,10 @@ mod tests { root.node.right.expect("there should be right child for root"), ) }; - match (left_root_child, right_root_child) { (NodeLink::Stored(14), NodeLink::Stored(15)) => { /* ok */ }, _ => panic!("Root should have s(14) and s(15) children") }; - assert_eq!(delete_tx.truncated, 2); assert_eq!(tree.len(), 16); } From 7ad0452c01aecfea28cc6c7cbed62c20b0830b0d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 22 Aug 2019 11:21:05 +0100 Subject: [PATCH 114/330] Add macOS support to GitHub Actions workflow --- .github/workflows/rust.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 81d0285..3ba97ef 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -18,3 +18,20 @@ jobs: run: cargo build --verbose --release --all - name: Run tests run: cargo test --verbose --release --all + + macOS: + name: Test on macOS-latest + runs-on: macOS-latest + + steps: + - name: Install Rust + run: curl https://sh.rustup.rs -sSf | sh -s -- -y + - name: Install rustfmt + run: $HOME/.cargo/bin/rustup component add rustfmt + - uses: actions/checkout@v1 + - name: Check formatting + run: $HOME/.cargo/bin/cargo fmt --all -- --check + - name: Build + run: $HOME/.cargo/bin/cargo build --verbose --release --all + - name: Run tests + run: $HOME/.cargo/bin/cargo test --verbose --release --all From bd8eea97b7d81ef85181803883d0a718e3b84680 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 22 Aug 2019 17:36:05 +0300 Subject: [PATCH 115/330] add docs/comments and fix bug --- src/lib.rs | 6 ++++++ src/tree.rs | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cc73098..923322b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ mod tree; pub use tree::Tree; +/// Node metadata. #[repr(C)] #[derive(Debug)] pub struct NodeData { @@ -22,15 +23,20 @@ pub struct NodeData { shielded_tx: u64, } +/// Reference to to the tree node. #[repr(C)] #[derive(Clone, Copy, Debug)] pub enum NodeLink { + /// Reference to the stored (in the array representation) leaf/node. Stored(u32), + /// Reference to the generated leaf/node. Generated(u32), } +/// MMR Node. It is leaf when `left`, `right` are `None` and node when they are not. #[repr(C)] #[derive(Debug)] +// TODO: Better layout would be enum (node, leaf), with left, right set only for nodes? pub struct MMRNode { left: Option, right: Option, diff --git a/src/tree.rs b/src/tree.rs index 8b4648d..cd45287 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -2,6 +2,13 @@ use std::collections::HashMap; use crate::{MMRNode, NodeLink, NodeData}; +/// Represents partially loaded tree. +/// +/// Some kind of "view" into the array representation of the MMR tree. +/// With only some of the leaves/nodes pre-loaded / pre-generated. +/// Exact amount of the loaded data can be calculated by the constructing party, +/// depending on the length of the tree and maximum amount of operations that are going +/// to happen after construction. #[derive(Default)] pub struct Tree { stored: HashMap, @@ -15,15 +22,21 @@ pub struct Tree { generated_count: u32, } -/// plain list of nodes that has to be appended to the end of the tree as the result of append operation -/// along with new root +/// Result of appending one or several leaves. pub struct AppendTransaction { + /// Plain list of nodes that has to be appended to the end of the array representation + /// of the tree as the result of append operation. pub appended: Vec, + + /// New root as a result of the operation (can be generated one). pub new_root: NodeLink, } +/// Result of truncating one or severl leaves. pub struct DeleteTransaction { + /// Number of leaves that should be dropped from the end of the list. pub truncated: u32, + /// New root as the result of the operation (can be generated one). pub new_root: NodeLink, } @@ -63,7 +76,8 @@ impl Tree { NodeLink::Generated(idx) } - // TODO: populate both stored and generated nodes? + /// Populate tree with plain list of the leaves/nodes. Mostly for test, + /// since this `Tree` structure is for partially loaded tree. pub fn populate(loaded: Vec) -> Self { let mut result = Tree::default(); result.stored_count = loaded.len() as u32; @@ -74,6 +88,7 @@ impl Tree { result } + /// Append one leaf to the tree. pub fn append_leaf(&mut self, root: NodeLink, new_leaf: NodeData) -> AppendTransaction { let is_complete= self.resolve_link(root).node.complete(); @@ -131,17 +146,24 @@ impl Tree { self.stored_count = self.stored_count - 1; } + /// Truncate one leaf from the end of the tree. pub fn truncate_leaf(&mut self, root: NodeLink) -> DeleteTransaction { let root = { - let n = self.resolve_link(root); - let leaves = n.node.data.end_height - n.node.data.start_height + 1; + let (leaves, root_left_child) = { + let n = self.resolve_link(root); + ( + n.node.data.end_height - n.node.data.start_height + 1, + n.node.left.expect("Root should have left child while deleting") + ) + }; if leaves & 1 != 0 { + self.pop(); return DeleteTransaction { truncated: 1, - new_root: n.node.left.expect("Root should have left child while deleting"), + new_root: root_left_child, } } else { - n + self.resolve_link(root) } }; @@ -182,6 +204,7 @@ impl Tree { } } + /// Length of array representation of the tree. pub fn len(&self) -> u32 { self.stored_count } @@ -440,6 +463,7 @@ mod tests { (NodeLink::Stored(14), NodeLink::Stored(15)) => { /* ok */ }, _ => panic!("Root should have s(14) and s(15) children") }; + // two stored nodes should leave us (leaf 16 and no longer needed node 17) assert_eq!(delete_tx.truncated, 2); assert_eq!(tree.len(), 16); } From 27337f1bb00eced4e48c29fd17a9d95e15c0b821 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 22 Aug 2019 17:43:03 +0300 Subject: [PATCH 116/330] use assert_matches! --- Cargo.toml | 3 +++ src/lib.rs | 2 ++ src/tree.rs | 23 +++++++++-------------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0157039..522af41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,3 +3,6 @@ name = "zcash-mmr" version = "0.1.0" authors = ["NikVolf "] edition = "2018" + +[dev-dependencies] +assert_matches = "1.3.0" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 923322b..1b5ad79 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,8 @@ //! //! To be used in zebra and via FFI bindings in zcashd +#[cfg(test)] #[macro_use] extern crate assert_matches; + mod tree; pub use tree::Tree; diff --git a/src/tree.rs b/src/tree.rs index cd45287..09fff69 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -378,8 +378,6 @@ mod tests { assert_eq!(append_tx.appended.len(), 1); } - // TODO: use assert_matches below - #[test] fn truncate_simple() { let (mut tree, root) = generated(9); @@ -409,10 +407,7 @@ mod tests { // so (15) is truncated // and new root, (14) is a stored one now - match delete_tx.new_root { - NodeLink::Stored(14) => { /* ok */ }, - _ => panic!("Root should be stored(14)") - } + assert_matches!(delete_tx.new_root, NodeLink::Stored(14)); assert_eq!(tree.len(), 15); } @@ -445,10 +440,8 @@ mod tests { // (0) (1) (3) (4) (7) (8) (10) (11) (15) // new root is generated - match delete_tx.new_root { - NodeLink::Generated(_) => { /* ok */ }, - _ => panic!("Root now should be generated") - } + + assert_matches!(delete_tx.new_root, NodeLink::Generated(_)); // left is 14 and right is 15 let (left_root_child, right_root_child) = { @@ -459,10 +452,12 @@ mod tests { root.node.right.expect("there should be right child for root"), ) }; - match (left_root_child, right_root_child) { - (NodeLink::Stored(14), NodeLink::Stored(15)) => { /* ok */ }, - _ => panic!("Root should have s(14) and s(15) children") - }; + + assert_matches!( + (left_root_child, right_root_child), + (NodeLink::Stored(14), NodeLink::Stored(15)) + ); + // two stored nodes should leave us (leaf 16 and no longer needed node 17) assert_eq!(delete_tx.truncated, 2); assert_eq!(tree.len(), 16); From 5a479363ff08742ec2cbb79dfc56dbd11ffb1a92 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 22 Aug 2019 20:35:56 +0300 Subject: [PATCH 117/330] new initializer --- src/tree.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/tree.rs b/src/tree.rs index 09fff69..136c9cf 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -76,7 +76,7 @@ impl Tree { NodeLink::Generated(idx) } - /// Populate tree with plain list of the leaves/nodes. Mostly for test, + /// Populate tree with plain list of the leaves/nodes. Mostly for tests, /// since this `Tree` structure is for partially loaded tree. pub fn populate(loaded: Vec) -> Self { let mut result = Tree::default(); @@ -88,6 +88,27 @@ impl Tree { result } + pub fn new( + length: u32, + stored: Vec<(u32, MMRNode)>, + generated: Vec, + ) -> Self { + let mut result = Tree::default(); + result.stored_count = length; + + for (idx, node) in stored.into_iter() { + result.stored.insert(idx, node); + } + + result.generated_count = generated.len() as u32; + + for (idx, node) in generated.into_iter().enumerate() { + result.generated.insert(idx as u32, node); + } + + result + } + /// Append one leaf to the tree. pub fn append_leaf(&mut self, root: NodeLink, new_leaf: NodeData) -> AppendTransaction { From 894421f3b51ff535beb393c7abd61e560e97c933 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 23 Aug 2019 12:01:01 +0100 Subject: [PATCH 118/330] librustzcash: Fix typo in Windows parameter init --- librustzcash/src/rustzcash.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 7e7c1a0..bcd6f88 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -181,7 +181,7 @@ pub extern "system" fn librustzcash_init_zksnark_params( let sprout_path = if sprout_path.is_null() { None } else { - Some(OsStr::from_wide(unsafe { + Some(OsString::from_wide(unsafe { slice::from_raw_parts(sprout_path, sprout_path_len) })) }; From 5e706d5d84f1b1ce21c7862d08c7fe0300a971ed Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 23 Aug 2019 12:13:23 +0100 Subject: [PATCH 119/330] Actions: Trigger testing workflow on pull_request --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 3ba97ef..fdeb90d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,6 +1,6 @@ name: Rust -on: [push] +on: [push, pull_request] jobs: test: From ba3705cb5e941c71f44f3e362e63414791079dda Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 23 Aug 2019 12:21:47 +0100 Subject: [PATCH 120/330] librustzcash: Correctly map sprout_path --- librustzcash/src/rustzcash.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index bcd6f88..9f7be87 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -191,7 +191,7 @@ pub extern "system" fn librustzcash_init_zksnark_params( spend_hash, Path::new(&output_path), output_hash, - Path::new(&sprout_path), + sprout_path.as_ref().map(|p| Path::new(p)), sprout_hash, ) } From e7d67364cca6c63d40eb25ad3abed2688d87bee6 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 23 Aug 2019 16:25:34 +0300 Subject: [PATCH 121/330] add quickcheck(failing) also failing append --- Cargo.toml | 3 +- src/lib.rs | 1 + src/tree.rs | 128 ++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 122 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 522af41..839ef38 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,5 @@ authors = ["NikVolf "] edition = "2018" [dev-dependencies] -assert_matches = "1.3.0" \ No newline at end of file +assert_matches = "1.3.0" +quickcheck = "0.8" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 1b5ad79..e398029 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ //! To be used in zebra and via FFI bindings in zcashd #[cfg(test)] #[macro_use] extern crate assert_matches; +#[cfg(test)] #[macro_use] extern crate quickcheck; mod tree; diff --git a/src/tree.rs b/src/tree.rs index 136c9cf..5a38740 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -111,7 +111,6 @@ impl Tree { /// Append one leaf to the tree. pub fn append_leaf(&mut self, root: NodeLink, new_leaf: NodeData) -> AppendTransaction { - let is_complete= self.resolve_link(root).node.complete(); let (new_root_node, mut appended) = if is_complete { @@ -162,6 +161,18 @@ impl Tree { } } + #[cfg(test)] + fn for_children(&mut self, node: NodeLink, mut f: F) { + let (left, right) = { + let link = self.resolve_link(node); + ( + link.node.left.expect("test use only (l)"), + link.node.right.expect("test use only (r)"), + ) + }; + f(left, right) + } + fn pop(&mut self) { self.stored.remove(&(self.stored_count-1)); self.stored_count = self.stored_count - 1; @@ -268,6 +279,7 @@ fn combine_nodes<'a>(left: IndexedNode<'a>, right: IndexedNode<'a>) -> MMRNode { mod tests { use super::{MMRNode, NodeData, Tree, NodeLink}; + use quickcheck::TestResult; fn leaf(height: u32) -> NodeData { NodeData { @@ -301,7 +313,7 @@ mod tests { } } - fn initial() -> Tree { + fn initial() -> (NodeLink, Tree) { let node1: MMRNode = leaf(1).into(); let node2: MMRNode = leaf(2).into(); @@ -311,15 +323,13 @@ mod tests { right: Some(NodeLink::Stored(1)), }; - Tree::populate(vec![node1, node2, node3]) + (NodeLink::Stored(2), Tree::populate(vec![node1, node2, node3])) } // returns tree with specified number of leafs and it's root fn generated(length: u32) -> (Tree, NodeLink) { - assert!(length > 3); - let mut tree = initial(); - let mut root = NodeLink::Stored(2); - + assert!(length >= 3); + let (mut root, mut tree) = initial(); for i in 2..length { root = tree.append_leaf(root, leaf(i+1).into()).new_root; } @@ -329,8 +339,10 @@ mod tests { #[test] fn discrete_append() { - let mut tree = initial(); - let append_tx = tree.append_leaf(NodeLink::Stored(2), leaf(3)); + let (root, mut tree) = initial(); + + // ** APPEND 3 ** + let append_tx = tree.append_leaf(root, leaf(3)); let new_root_link = append_tx.new_root; let new_root = tree.resolve_link(new_root_link).node; @@ -350,6 +362,7 @@ mod tests { assert_eq!(new_root.data.end_height, 3); assert_eq!(append_tx.appended.len(), 1); + // ** APPEND 4 ** let append_tx = tree.append_leaf(new_root_link, leaf(4)); let new_root_link = append_tx.new_root; let new_root = tree.resolve_link(new_root_link).node; @@ -372,6 +385,9 @@ mod tests { // and new root, (6) is stored one assert_eq!(new_root.data.end_height, 4); assert_eq!(append_tx.appended.len(), 3); + assert_matches!(new_root_link, NodeLink::Stored(6)); + + // ** APPEND 5 ** let append_tx = tree.append_leaf(new_root_link, leaf(5)); let new_root_link = append_tx.new_root; @@ -397,6 +413,81 @@ mod tests { // and new root, (8g) is generated one assert_eq!(new_root.data.end_height, 5); assert_eq!(append_tx.appended.len(), 1); + assert_matches!(new_root_link, NodeLink::Generated(_)); + tree.for_children(new_root_link, |l, r| { + assert_matches!(l, NodeLink::Stored(6)); + assert_matches!(r, NodeLink::Stored(7)); + }); + + // *** APPEND #6 *** + + let append_tx = tree.append_leaf(new_root_link, leaf(6)); + let new_root_link = append_tx.new_root; + let new_root = tree.resolve_link(new_root_link).node; + + // intermediate tree: + // ( 8g ) + // / \ + // ( 6 ) \ + // / \ \ + // (2) (5) \ + // / \ / \ \ + // (0) (1) (3) (4) (7) + // + // new tree: + // (---8g---) + // / \ + // ( 6 ) \ + // / \ \ + // (2) (5) (9) + // / \ / \ / \ + // (0) (1) (3) (4) (7) (8) + // + // so (7) is added as real leaf + // and new root, (8g) is generated one + assert_eq!(new_root.data.end_height, 6); + assert_eq!(append_tx.appended.len(), 2); + assert_matches!(new_root_link, NodeLink::Generated(_)); + tree.for_children(new_root_link, |l, r| { + assert_matches!(l, NodeLink::Stored(6)); + assert_matches!(r, NodeLink::Stored(9)); + }); + + // *** APPEND #7 *** + + let append_tx = tree.append_leaf(new_root_link, leaf(7)); + let new_root_link = append_tx.new_root; + let new_root = tree.resolve_link(new_root_link).node; + + // intermediate tree: + // (---8g---) + // / \ + // ( 6 ) \ + // / \ \ + // (2) (5) (9) + // / \ / \ / \ + // (0) (1) (3) (4) (7) (8) + // + // new tree: + // (---12g--) + // / \ + // (---11g---) \ + // / \ \ + // ( 6 ) \ \ + // / \ \ \ + // (2) (5) (9) \ + // / \ / \ / \ \ + // (0) (1) (3) (4) (7) (8) (10) + // + // so (7) is added as real leaf + // and new root, (8g) is generated one + assert_eq!(new_root.data.end_height, 7); + assert_eq!(append_tx.appended.len(), 1); + assert_matches!(new_root_link, NodeLink::Generated(_)); + tree.for_children(new_root_link, |l, r| { + assert_matches!(l, NodeLink::Generated(_)); + assert_matches!(r, NodeLink::Stored(10)); + }); } #[test] @@ -483,4 +574,23 @@ mod tests { assert_eq!(delete_tx.truncated, 2); assert_eq!(tree.len(), 16); } + + + quickcheck! { + fn there_and_back(number: u32) -> TestResult { + if (number > 1024*1024) { + TestResult::discard() + } else { + let (mut root, mut tree) = initial(); + for i in 0..number { + root = tree.append_leaf(root, leaf(i+3)).new_root; + } + for i in 0..number { + root = tree.truncate_leaf(root).new_root; + } + + TestResult::from_bool(if let NodeLink::Stored(2) = root { true } else { false }) + } + } + } } \ No newline at end of file From d78c94b2a24604f56dcc01aaea013825518c25a5 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 2 Aug 2019 10:50:32 +0100 Subject: [PATCH 122/330] Move Equihash validator into zcash_primitives --- librustzcash/src/rustzcash.rs | 3 +-- zcash_primitives/src/block.rs | 2 ++ {librustzcash/src => zcash_primitives/src/block}/equihash.rs | 0 3 files changed, 3 insertions(+), 2 deletions(-) rename {librustzcash/src => zcash_primitives/src/block}/equihash.rs (100%) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 14b5f00..68b7048 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -45,6 +45,7 @@ use std::ffi::OsString; use std::os::windows::ffi::OsStringExt; use zcash_primitives::{ + block::equihash, merkle_tree::CommitmentTreeWitness, note_encryption::sapling_ka_agree, primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ViewingKey}, @@ -58,8 +59,6 @@ use zcash_proofs::{ sapling::{SaplingProvingContext, SaplingVerificationContext}, }; -pub mod equihash; - #[cfg(test)] mod tests; diff --git a/zcash_primitives/src/block.rs b/zcash_primitives/src/block.rs index f2802b4..63e6a05 100644 --- a/zcash_primitives/src/block.rs +++ b/zcash_primitives/src/block.rs @@ -6,6 +6,8 @@ use std::ops::Deref; use crate::serialize::Vector; +pub mod equihash; + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct BlockHash(pub [u8; 32]); diff --git a/librustzcash/src/equihash.rs b/zcash_primitives/src/block/equihash.rs similarity index 100% rename from librustzcash/src/equihash.rs rename to zcash_primitives/src/block/equihash.rs From d65fe2cda948195ee48f67923b33935a1a042374 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 2 Aug 2019 11:13:59 +0100 Subject: [PATCH 123/330] Address various clippy warnings/errors in bellman --- bellman/src/domain.rs | 22 ++++++----- bellman/src/gadgets/blake2s.rs | 4 +- bellman/src/gadgets/boolean.rs | 30 +++++++-------- bellman/src/gadgets/multieq.rs | 2 +- bellman/src/gadgets/num.rs | 12 +++--- bellman/src/gadgets/sha256.rs | 6 ++- bellman/src/gadgets/test/mod.rs | 6 +-- bellman/src/gadgets/uint32.rs | 66 +++++++++++++++----------------- bellman/src/groth16/generator.rs | 2 +- bellman/src/groth16/mod.rs | 18 ++++----- bellman/src/groth16/verifier.rs | 2 +- bellman/src/lib.rs | 5 ++- bellman/src/multicore.rs | 2 +- 13 files changed, 90 insertions(+), 87 deletions(-) diff --git a/bellman/src/domain.rs b/bellman/src/domain.rs index 808d2af..d5a86bd 100644 --- a/bellman/src/domain.rs +++ b/bellman/src/domain.rs @@ -26,15 +26,19 @@ pub struct EvaluationDomain> { minv: E::Fr, } -impl> EvaluationDomain { - pub fn as_ref(&self) -> &[G] { +impl> AsRef<[G]> for EvaluationDomain { + fn as_ref(&self) -> &[G] { &self.coeffs } +} - pub fn as_mut(&mut self) -> &mut [G] { +impl> AsMut<[G]> for EvaluationDomain { + fn as_mut(&mut self) -> &mut [G] { &mut self.coeffs } +} +impl> EvaluationDomain { pub fn into_coeffs(self) -> Vec { self.coeffs } @@ -64,9 +68,9 @@ impl> EvaluationDomain { coeffs.resize(m, G::group_zero()); Ok(EvaluationDomain { - coeffs: coeffs, - exp: exp, - omega: omega, + coeffs, + exp, + omega, omegainv: omega.inverse().unwrap(), geninv: E::Fr::multiplicative_generator().inverse().unwrap(), minv: E::Fr::from_str(&format!("{}", m)) @@ -291,7 +295,7 @@ fn serial_fft>(a: &mut [T], omega: &E::Fr, log_n: u let mut m = 1; for _ in 0..log_n { - let w_m = omega.pow(&[(n / (2 * m)) as u64]); + let w_m = omega.pow(&[u64::from(n / (2 * m))]); let mut k = 0; while k < n { @@ -337,12 +341,12 @@ fn parallel_fft>( let omega_step = omega.pow(&[(j as u64) << log_new_n]); let mut elt = E::Fr::one(); - for i in 0..(1 << log_new_n) { + for (i, tmp) in tmp.iter_mut().enumerate() { for s in 0..num_cpus { let idx = (i + (s << log_new_n)) % (1 << log_n); let mut t = a[idx]; t.group_mul_assign(&elt); - tmp[i].group_add_assign(&t); + tmp.group_add_assign(&t); elt.mul_assign(&omega_step); } elt.mul_assign(&omega_j); diff --git a/bellman/src/gadgets/blake2s.rs b/bellman/src/gadgets/blake2s.rs index c5cee23..beefe09 100644 --- a/bellman/src/gadgets/blake2s.rs +++ b/bellman/src/gadgets/blake2s.rs @@ -382,7 +382,7 @@ pub fn blake2s>( blocks.push(this_block); } - if blocks.len() == 0 { + if blocks.is_empty() { blocks.push((0..16).map(|_| UInt32::constant(0)).collect()); } @@ -433,7 +433,7 @@ mod test { let expected = hex!("c59f682376d137f3f255e671e207d1f2374ebe504e9314208a52d9f88d69e8c8"); let mut out = out.into_iter(); - for b in expected.into_iter() { + for b in expected.iter() { for i in 0..8 { let c = out.next().unwrap().get_value().unwrap(); diff --git a/bellman/src/gadgets/boolean.rs b/bellman/src/gadgets/boolean.rs index 414b290..b26bb19 100644 --- a/bellman/src/gadgets/boolean.rs +++ b/bellman/src/gadgets/boolean.rs @@ -60,7 +60,7 @@ impl AllocatedBit { Ok(AllocatedBit { variable: var, - value: value, + value, }) } @@ -93,7 +93,7 @@ impl AllocatedBit { Ok(AllocatedBit { variable: var, - value: value, + value, }) } @@ -302,7 +302,7 @@ pub fn field_into_boolean_vec_le, F: PrimeFie ) -> Result, SynthesisError> { let v = field_into_allocated_bits_le::(cs, value)?; - Ok(v.into_iter().map(|e| Boolean::from(e)).collect()) + Ok(v.into_iter().map(Boolean::from).collect()) } pub fn field_into_allocated_bits_le, F: PrimeField>( @@ -412,24 +412,24 @@ impl Boolean { } pub fn get_value(&self) -> Option { - match self { - &Boolean::Constant(c) => Some(c), - &Boolean::Is(ref v) => v.get_value(), - &Boolean::Not(ref v) => v.get_value().map(|b| !b), + match *self { + Boolean::Constant(c) => Some(c), + Boolean::Is(ref v) => v.get_value(), + Boolean::Not(ref v) => v.get_value().map(|b| !b), } } pub fn lc(&self, one: Variable, coeff: E::Fr) -> LinearCombination { - match self { - &Boolean::Constant(c) => { + match *self { + Boolean::Constant(c) => { if c { LinearCombination::::zero() + (coeff, one) } else { LinearCombination::::zero() } } - &Boolean::Is(ref v) => LinearCombination::::zero() + (coeff, v.get_variable()), - &Boolean::Not(ref v) => { + Boolean::Is(ref v) => LinearCombination::::zero() + (coeff, v.get_variable()), + Boolean::Not(ref v) => { LinearCombination::::zero() + (coeff, one) - (coeff, v.get_variable()) } } @@ -442,10 +442,10 @@ impl Boolean { /// Return a negated interpretation of this boolean. pub fn not(&self) -> Self { - match self { - &Boolean::Constant(c) => Boolean::Constant(!c), - &Boolean::Is(ref v) => Boolean::Not(v.clone()), - &Boolean::Not(ref v) => Boolean::Is(v.clone()), + match *self { + Boolean::Constant(c) => Boolean::Constant(!c), + Boolean::Is(ref v) => Boolean::Not(v.clone()), + Boolean::Not(ref v) => Boolean::Is(v.clone()), } } diff --git a/bellman/src/gadgets/multieq.rs b/bellman/src/gadgets/multieq.rs index 510802d..095017a 100644 --- a/bellman/src/gadgets/multieq.rs +++ b/bellman/src/gadgets/multieq.rs @@ -14,7 +14,7 @@ pub struct MultiEq> { impl> MultiEq { pub fn new(cs: CS) -> Self { MultiEq { - cs: cs, + cs, ops: 0, bits_used: 0, lhs: LinearCombination::zero(), diff --git a/bellman/src/gadgets/num.rs b/bellman/src/gadgets/num.rs index 84843c1..81f4fb3 100644 --- a/bellman/src/gadgets/num.rs +++ b/bellman/src/gadgets/num.rs @@ -78,7 +78,7 @@ impl AllocatedNum { E: Engine, CS: ConstraintSystem, { - assert!(v.len() > 0); + assert!(!v.is_empty()); // Let's keep this simple for now and just AND them all // manually @@ -132,7 +132,7 @@ impl AllocatedNum { current_run.push(a_bit.clone()); result.push(a_bit); } else { - if current_run.len() > 0 { + if !current_run.is_empty() { // This is the start of a run of zeros, but we need // to k-ary AND against `last_run` first. @@ -183,7 +183,7 @@ impl AllocatedNum { cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc); // Convert into booleans, and reverse for little-endian bit order - Ok(result.into_iter().map(|b| Boolean::from(b)).rev().collect()) + Ok(result.into_iter().map(Boolean::from).rev().collect()) } /// Convert the allocated number into its little-endian representation. @@ -208,7 +208,7 @@ impl AllocatedNum { cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc); - Ok(bits.into_iter().map(|b| Boolean::from(b)).collect()) + Ok(bits.into_iter().map(Boolean::from).collect()) } pub fn mul(&self, mut cs: CS, other: &Self) -> Result @@ -238,7 +238,7 @@ impl AllocatedNum { ); Ok(AllocatedNum { - value: value, + value, variable: var, }) } @@ -270,7 +270,7 @@ impl AllocatedNum { ); Ok(AllocatedNum { - value: value, + value, variable: var, }) } diff --git a/bellman/src/gadgets/sha256.rs b/bellman/src/gadgets/sha256.rs index cb057f8..e346a71 100644 --- a/bellman/src/gadgets/sha256.rs +++ b/bellman/src/gadgets/sha256.rs @@ -4,6 +4,7 @@ use super::uint32::UInt32; use crate::{ConstraintSystem, SynthesisError}; use pairing::Engine; +#[allow(clippy::unreadable_literal)] const ROUND_CONSTANTS: [u32; 64] = [ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, @@ -15,6 +16,7 @@ const ROUND_CONSTANTS: [u32; 64] = [ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, ]; +#[allow(clippy::unreadable_literal)] const IV: [u32; 8] = [ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, ]; @@ -130,7 +132,7 @@ where Ok(match self { Maybe::Concrete(ref v) => return Ok(v.clone()), Maybe::Deferred(mut v) => { - v.extend(others.into_iter().cloned()); + v.extend(others.iter().cloned()); UInt32::addmany(cs, &v)? } }) @@ -286,7 +288,7 @@ mod test { let expected = hex!("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); let mut out = out_bits.into_iter(); - for b in expected.into_iter() { + for b in expected.iter() { for i in (0..8).rev() { let c = out.next().unwrap().get_value().unwrap(); diff --git a/bellman/src/gadgets/test/mod.rs b/bellman/src/gadgets/test/mod.rs index 58ba040..eed676e 100644 --- a/bellman/src/gadgets/test/mod.rs +++ b/bellman/src/gadgets/test/mod.rs @@ -66,7 +66,7 @@ fn proc_lc(terms: &[(Variable, E::Fr)]) -> BTreeMap TestConstraintSystem { }; let powers_of_two = (0..E::Fr::NUM_BITS) - .map(|i| E::Fr::from_str("2").unwrap().pow(&[i as u64])) + .map(|i| E::Fr::from_str("2").unwrap().pow(&[u64::from(i)])) .collect::>(); let pp = |s: &mut String, lc: &LinearCombination| { @@ -286,7 +286,7 @@ impl TestConstraintSystem { } } - return true; + true } pub fn num_inputs(&self) -> usize { diff --git a/bellman/src/gadgets/uint32.rs b/bellman/src/gadgets/uint32.rs index ef3f44a..3467400 100644 --- a/bellman/src/gadgets/uint32.rs +++ b/bellman/src/gadgets/uint32.rs @@ -33,7 +33,7 @@ impl UInt32 { } UInt32 { - bits: bits, + bits, value: Some(value), } } @@ -69,10 +69,7 @@ impl UInt32 { }) .collect::, SynthesisError>>()?; - Ok(UInt32 { - bits: bits, - value: value, - }) + Ok(UInt32 { bits, value }) } pub fn into_bits_be(&self) -> Vec { @@ -98,7 +95,7 @@ impl UInt32 { } UInt32 { - value: value, + value, bits: bits.iter().rev().cloned().collect(), } } @@ -119,20 +116,20 @@ impl UInt32 { for b in new_bits.iter().rev() { value.as_mut().map(|v| *v <<= 1); - match b { - &Boolean::Constant(b) => { + match *b { + Boolean::Constant(b) => { if b { value.as_mut().map(|v| *v |= 1); } } - &Boolean::Is(ref b) => match b.get_value() { + Boolean::Is(ref b) => match b.get_value() { Some(true) => { value.as_mut().map(|v| *v |= 1); } Some(false) => {} None => value = None, }, - &Boolean::Not(ref b) => match b.get_value() { + Boolean::Not(ref b) => match b.get_value() { Some(false) => { value.as_mut().map(|v| *v |= 1); } @@ -143,7 +140,7 @@ impl UInt32 { } UInt32 { - value: value, + value, bits: new_bits, } } @@ -215,7 +212,7 @@ impl UInt32 { .collect::>()?; Ok(UInt32 { - bits: bits, + bits, value: new_value, }) } @@ -274,7 +271,7 @@ impl UInt32 { .collect::>()?; Ok(UInt32 { - bits: bits, + bits, value: new_value, }) } @@ -294,7 +291,7 @@ impl UInt32 { // Compute the maximum value of the sum so we allocate enough bits for // the result - let mut max_value = (operands.len() as u64) * (u32::max_value() as u64); + let mut max_value = (operands.len() as u64) * (u64::from(u32::max_value())); // Keep track of the resulting value let mut result_value = Some(0u64); @@ -310,7 +307,7 @@ impl UInt32 { // Accumulate the value match op.value { Some(val) => { - result_value.as_mut().map(|v| *v += val as u64); + result_value.as_mut().map(|v| *v += u64::from(val)); } None => { // If any of our operands have unknown value, we won't @@ -408,8 +405,8 @@ mod test { let b = UInt32::from_bits_be(&v); for (i, bit) in b.bits.iter().enumerate() { - match bit { - &Boolean::Constant(bit) => { + match *bit { + Boolean::Constant(bit) => { assert!(bit == ((b.value.unwrap() >> i) & 1 == 1)); } _ => unreachable!(), @@ -443,8 +440,8 @@ mod test { let b = UInt32::from_bits(&v); for (i, bit) in b.bits.iter().enumerate() { - match bit { - &Boolean::Constant(bit) => { + match *bit { + Boolean::Constant(bit) => { assert!(bit == ((b.value.unwrap() >> i) & 1 == 1)); } _ => unreachable!(), @@ -491,14 +488,14 @@ mod test { assert!(r.value == Some(expected)); for b in r.bits.iter() { - match b { - &Boolean::Is(ref b) => { + match *b { + Boolean::Is(ref b) => { assert!(b.get_value().unwrap() == (expected & 1 == 1)); } - &Boolean::Not(ref b) => { + Boolean::Not(ref b) => { assert!(!b.get_value().unwrap() == (expected & 1 == 1)); } - &Boolean::Constant(b) => { + Boolean::Constant(b) => { assert!(b == (expected & 1 == 1)); } } @@ -538,10 +535,10 @@ mod test { assert!(r.value == Some(expected)); for b in r.bits.iter() { - match b { - &Boolean::Is(_) => panic!(), - &Boolean::Not(_) => panic!(), - &Boolean::Constant(b) => { + match *b { + Boolean::Is(_) => panic!(), + Boolean::Not(_) => panic!(), + Boolean::Constant(b) => { assert!(b == (expected & 1 == 1)); } } @@ -576,8 +573,7 @@ mod test { let r = a_bit.xor(cs.namespace(|| "xor"), &b_bit).unwrap(); let r = { let mut cs = MultiEq::new(&mut cs); - let r = UInt32::addmany(cs.namespace(|| "addition"), &[r, c_bit, d_bit]).unwrap(); - r + UInt32::addmany(cs.namespace(|| "addition"), &[r, c_bit, d_bit]).unwrap() }; assert!(cs.is_satisfied()); @@ -585,14 +581,14 @@ mod test { assert!(r.value == Some(expected)); for b in r.bits.iter() { - match b { - &Boolean::Is(ref b) => { + match *b { + Boolean::Is(ref b) => { assert!(b.get_value().unwrap() == (expected & 1 == 1)); } - &Boolean::Not(ref b) => { + Boolean::Not(ref b) => { assert!(!b.get_value().unwrap() == (expected & 1 == 1)); } - &Boolean::Constant(_) => unreachable!(), + Boolean::Constant(_) => unreachable!(), } expected >>= 1; @@ -628,8 +624,8 @@ mod test { let mut tmp = num; for b in &b.bits { - match b { - &Boolean::Constant(b) => { + match *b { + Boolean::Constant(b) => { assert_eq!(b, tmp & 1 == 1); } _ => unreachable!(), diff --git a/bellman/src/groth16/generator.rs b/bellman/src/groth16/generator.rs index 2ece8b7..7ca6c9a 100644 --- a/bellman/src/groth16/generator.rs +++ b/bellman/src/groth16/generator.rs @@ -451,7 +451,7 @@ where }; Ok(Parameters { - vk: vk, + vk, h: Arc::new(h.into_iter().map(|e| e.into_affine()).collect()), l: Arc::new(l.into_iter().map(|e| e.into_affine()).collect()), diff --git a/bellman/src/groth16/mod.rs b/bellman/src/groth16/mod.rs index 9fa3bc8..44c6f22 100644 --- a/bellman/src/groth16/mod.rs +++ b/bellman/src/groth16/mod.rs @@ -90,7 +90,7 @@ impl Proof { } })?; - Ok(Proof { a: a, b: b, c: c }) + Ok(Proof { a, b, c }) } } @@ -208,13 +208,13 @@ impl VerifyingKey { } Ok(VerifyingKey { - alpha_g1: alpha_g1, - beta_g1: beta_g1, - beta_g2: beta_g2, - gamma_g2: gamma_g2, - delta_g1: delta_g1, - delta_g2: delta_g2, - ic: ic, + alpha_g1, + beta_g1, + beta_g2, + gamma_g2, + delta_g1, + delta_g2, + ic, }) } } @@ -376,7 +376,7 @@ impl Parameters { } Ok(Parameters { - vk: vk, + vk, h: Arc::new(h), l: Arc::new(l), a: Arc::new(a), diff --git a/bellman/src/groth16/verifier.rs b/bellman/src/groth16/verifier.rs index 065a3b0..5bc0581 100644 --- a/bellman/src/groth16/verifier.rs +++ b/bellman/src/groth16/verifier.rs @@ -49,7 +49,7 @@ pub fn verify_proof<'a, E: Engine>( (&acc.into_affine().prepare(), &pvk.neg_gamma_g2), (&proof.c.prepare(), &pvk.neg_delta_g2), ] - .into_iter(), + .iter(), )) .unwrap() == pvk.alpha_g1_beta_g2) diff --git a/bellman/src/lib.rs b/bellman/src/lib.rs index a75c85f..1445107 100644 --- a/bellman/src/lib.rs +++ b/bellman/src/lib.rs @@ -91,6 +91,7 @@ impl Add<(E::Fr, Variable)> for LinearCombination { impl Sub<(E::Fr, Variable)> for LinearCombination { type Output = LinearCombination; + #[allow(clippy::suspicious_arithmetic_impl)] fn sub(self, (mut coeff, var): (E::Fr, Variable)) -> LinearCombination { coeff.negate(); @@ -213,7 +214,7 @@ impl Error for SynthesisError { impl fmt::Display for SynthesisError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - if let &SynthesisError::IoError(ref e) = self { + if let SynthesisError::IoError(ref e) = *self { write!(f, "I/O error: ")?; e.fmt(f) } else { @@ -278,7 +279,7 @@ pub trait ConstraintSystem: Sized { fn get_root(&mut self) -> &mut Self::Root; /// Begin a namespace for this constraint system. - fn namespace<'a, NR, N>(&'a mut self, name_fn: N) -> Namespace<'a, E, Self::Root> + fn namespace(&mut self, name_fn: N) -> Namespace<'_, E, Self::Root> where NR: Into, N: FnOnce() -> NR, diff --git a/bellman/src/multicore.rs b/bellman/src/multicore.rs index e8b2dae..7ebc89a 100644 --- a/bellman/src/multicore.rs +++ b/bellman/src/multicore.rs @@ -23,7 +23,7 @@ mod implementation { // CPUs configured. pub(crate) fn new_with_cpus(cpus: usize) -> Worker { Worker { - cpus: cpus, + cpus, pool: CpuPool::new(cpus), } } From 3a8efd9e677ebfe6de7669b865a780ec89caabd6 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 2 Aug 2019 11:25:00 +0100 Subject: [PATCH 124/330] Address various clippy warnings/errors in zcash_primitives --- zcash_primitives/src/block.rs | 2 +- zcash_primitives/src/block/equihash.rs | 22 ++++------ zcash_primitives/src/constants.rs | 18 ++++---- zcash_primitives/src/jubjub/edwards.rs | 12 +++--- zcash_primitives/src/jubjub/fs.rs | 4 +- zcash_primitives/src/jubjub/mod.rs | 4 +- zcash_primitives/src/jubjub/montgomery.rs | 15 ++++--- zcash_primitives/src/keys.rs | 6 +-- zcash_primitives/src/merkle_tree.rs | 6 ++- zcash_primitives/src/note_encryption.rs | 6 +-- zcash_primitives/src/primitives.rs | 9 ++-- zcash_primitives/src/sapling.rs | 4 +- zcash_primitives/src/serialize.rs | 2 +- zcash_primitives/src/transaction/builder.rs | 6 +-- .../src/transaction/components.rs | 41 ++++++++----------- zcash_primitives/src/transaction/mod.rs | 23 ++++++----- zcash_primitives/src/transaction/sighash.rs | 14 +++---- zcash_primitives/src/zip32.rs | 10 ++--- 18 files changed, 97 insertions(+), 107 deletions(-) diff --git a/zcash_primitives/src/block.rs b/zcash_primitives/src/block.rs index 63e6a05..28a7441 100644 --- a/zcash_primitives/src/block.rs +++ b/zcash_primitives/src/block.rs @@ -13,7 +13,7 @@ pub struct BlockHash(pub [u8; 32]); impl fmt::Display for BlockHash { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut data = self.0.clone(); + let mut data = self.0; data.reverse(); formatter.write_str(&hex::encode(data)) } diff --git a/zcash_primitives/src/block/equihash.rs b/zcash_primitives/src/block/equihash.rs index d251bc1..9710dc9 100644 --- a/zcash_primitives/src/block/equihash.rs +++ b/zcash_primitives/src/block/equihash.rs @@ -60,10 +60,7 @@ impl Node { indices.extend(a.indices.iter()); indices }; - Node { - hash: hash, - indices: indices, - } + Node { hash, indices } } fn from_children_ref(a: &Node, b: &Node, trim: usize) -> Self { @@ -82,10 +79,7 @@ impl Node { indices.extend(b.indices.iter()); indices.extend(a.indices.iter()); } - Node { - hash: hash, - indices: indices, - } + Node { hash, indices } } fn indices_before(&self, other: &Node) -> bool { @@ -141,7 +135,7 @@ fn expand_array(vin: &[u8], bit_len: usize, byte_pad: usize) -> Vec { let mut j = 0; for b in vin { - acc_value = (acc_value << 8) | *b as u32; + acc_value = (acc_value << 8) | u32::from(*b); acc_bits += 8; // When we have bit_len or more bits in the accumulator, write the next @@ -197,7 +191,7 @@ fn distinct_indices(a: &Node, b: &Node) -> bool { } } } - return true; + true } fn validate_subtrees(p: &Params, a: &Node, b: &Node) -> bool { @@ -222,7 +216,7 @@ pub fn is_valid_solution_iterative( nonce: &[u8], indices: &[u32], ) -> bool { - let p = Params { n: n, k: k }; + let p = Params { n, k }; let mut state = initialise_state(p.n, p.k, p.hash_output()); state.update(input); @@ -249,7 +243,7 @@ pub fn is_valid_solution_iterative( } assert!(rows.len() == 1); - return rows[0].is_zero(hash_len); + rows[0].is_zero(hash_len) } fn tree_validator(p: &Params, state: &Blake2bState, indices: &[u32]) -> Option { @@ -281,7 +275,7 @@ pub fn is_valid_solution_recursive( nonce: &[u8], indices: &[u32], ) -> bool { - let p = Params { n: n, k: k }; + let p = Params { n, k }; let mut state = initialise_state(p.n, p.k, p.hash_output()); state.update(input); @@ -297,7 +291,7 @@ pub fn is_valid_solution_recursive( } pub fn is_valid_solution(n: u32, k: u32, input: &[u8], nonce: &[u8], soln: &[u8]) -> bool { - let p = Params { n: n, k: k }; + let p = Params { n, k }; let indices = indices_from_minimal(soln, p.collision_bit_length()); // Recursive validation is faster diff --git a/zcash_primitives/src/constants.rs b/zcash_primitives/src/constants.rs index c21184d..39d55f3 100644 --- a/zcash_primitives/src/constants.rs +++ b/zcash_primitives/src/constants.rs @@ -2,31 +2,31 @@ /// This is chosen to be some random string that we couldn't have anticipated when we designed /// the algorithm, for rigidity purposes. /// We deliberately use an ASCII hex string of 32 bytes here. -pub const GH_FIRST_BLOCK: &'static [u8; 64] = +pub const GH_FIRST_BLOCK: &[u8; 64] = b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0"; // BLAKE2s invocation personalizations /// BLAKE2s Personalization for CRH^ivk = BLAKE2s(ak | nk) -pub const CRH_IVK_PERSONALIZATION: &'static [u8; 8] = b"Zcashivk"; +pub const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk"; /// BLAKE2s Personalization for PRF^nf = BLAKE2s(nk | rho) -pub const PRF_NF_PERSONALIZATION: &'static [u8; 8] = b"Zcash_nf"; +pub const PRF_NF_PERSONALIZATION: &[u8; 8] = b"Zcash_nf"; // Group hash personalizations /// BLAKE2s Personalization for Pedersen hash generators. -pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8] = b"Zcash_PH"; +pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &[u8; 8] = b"Zcash_PH"; /// BLAKE2s Personalization for the group hash for key diversification -pub const KEY_DIVERSIFICATION_PERSONALIZATION: &'static [u8; 8] = b"Zcash_gd"; +pub const KEY_DIVERSIFICATION_PERSONALIZATION: &[u8; 8] = b"Zcash_gd"; /// BLAKE2s Personalization for the spending key base point -pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_G_"; +pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_G_"; /// BLAKE2s Personalization for the proof generation key base point -pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_H_"; +pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_H_"; /// BLAKE2s Personalization for the value commitment generator for the value -pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_cv"; +pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_cv"; /// BLAKE2s Personalization for the nullifier position generator (for computing rho) -pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_J_"; +pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_J_"; diff --git a/zcash_primitives/src/jubjub/edwards.rs b/zcash_primitives/src/jubjub/edwards.rs index b3cdd64..233bfb7 100644 --- a/zcash_primitives/src/jubjub/edwards.rs +++ b/zcash_primitives/src/jubjub/edwards.rs @@ -132,9 +132,9 @@ impl Point { t.mul_assign(&y); Some(Point { - x: x, - y: y, - t: t, + x, + y, + t, z: E::Fr::one(), _marker: PhantomData, }) @@ -277,8 +277,8 @@ impl Point { Point { x: u, y: v, - t: t, - z: z, + t, + z, _marker: PhantomData, } } @@ -412,7 +412,7 @@ impl Point { b.mul_assign(&other.y); // C = d * t1 * t2 - let mut c = params.edwards_d().clone(); + let mut c = *params.edwards_d(); c.mul_assign(&self.t); c.mul_assign(&other.t); diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index 0d1578e..7cf4d79 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -321,8 +321,8 @@ impl Field for Fs { loop { let mut tmp = { let mut repr = [0u64; 4]; - for i in 0..4 { - repr[i] = rng.next_u64(); + for limb in &mut repr { + *limb = rng.next_u64(); } Fs(FsRepr(repr)) }; diff --git a/zcash_primitives/src/jubjub/mod.rs b/zcash_primitives/src/jubjub/mod.rs index 8d9e227..624592e 100644 --- a/zcash_primitives/src/jubjub/mod.rs +++ b/zcash_primitives/src/jubjub/mod.rs @@ -199,9 +199,9 @@ impl JubjubBls12 { ) .unwrap(), // A = 40962 - montgomery_a: montgomery_a, + montgomery_a, // 2A = 2.A - montgomery_2a: montgomery_2a, + montgomery_2a, // scaling factor = sqrt(4 / (a - d)) scale: Fr::from_str( "17814886934372412843466061268024708274627479829237077604635722030778476050649", diff --git a/zcash_primitives/src/jubjub/montgomery.rs b/zcash_primitives/src/jubjub/montgomery.rs index e0bc4bf..0ebedd2 100644 --- a/zcash_primitives/src/jubjub/montgomery.rs +++ b/zcash_primitives/src/jubjub/montgomery.rs @@ -64,12 +64,12 @@ impl Point { y.negate(); } - return Some(Point { - x: x, - y: y, + Some(Point { + x, + y, infinity: false, _marker: PhantomData, - }); + }) } None => None, } @@ -88,9 +88,8 @@ impl Point { let x = E::Fr::random(rng); let sign = rng.next_u32() % 2 != 0; - match Self::get_for_x(x, sign, params) { - Some(p) => return p, - None => {} + if let Some(p) = Self::get_for_x(x, sign, params) { + return p; } } } @@ -214,7 +213,7 @@ impl Point { let mut delta = E::Fr::one(); { - let mut tmp = params.montgomery_a().clone(); + let mut tmp = *params.montgomery_a(); tmp.mul_assign(&self.x); tmp.double(); delta.add_assign(&tmp); diff --git a/zcash_primitives/src/keys.rs b/zcash_primitives/src/keys.rs index ad86059..8c8a4b1 100644 --- a/zcash_primitives/src/keys.rs +++ b/zcash_primitives/src/keys.rs @@ -10,11 +10,11 @@ use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; use ff::{PrimeField, PrimeFieldRepr}; use std::io::{self, Read, Write}; -pub const PRF_EXPAND_PERSONALIZATION: &'static [u8; 16] = b"Zcash_ExpandSeed"; +pub const PRF_EXPAND_PERSONALIZATION: &[u8; 16] = b"Zcash_ExpandSeed"; /// PRF^expand(sk, t) := BLAKE2b-512("Zcash_ExpandSeed", sk || t) pub fn prf_expand(sk: &[u8], t: &[u8]) -> Blake2bHash { - prf_expand_vec(sk, &vec![t]) + prf_expand_vec(sk, &[t]) } pub fn prf_expand_vec(sk: &[u8], ts: &[&[u8]]) -> Blake2bHash { @@ -111,7 +111,7 @@ impl Clone for FullViewingKey { ak: self.vk.ak.clone(), nk: self.vk.nk.clone(), }, - ovk: self.ovk.clone(), + ovk: self.ovk, } } } diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 288ad21..2721ab6 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -486,8 +486,10 @@ impl CommitmentTreeWitness { // Given the position, let's finish constructing the authentication // path let mut tmp = position; - for i in 0..depth { - auth_path[i].as_mut().map(|p| p.1 = (tmp & 1) == 1); + for entry in auth_path.iter_mut() { + if let Some(p) = entry { + p.1 = (tmp & 1) == 1; + } tmp >>= 1; } diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 5412945..0d0e83a 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -19,8 +19,8 @@ use std::str; use crate::{keys::OutgoingViewingKey, JUBJUB}; -pub const KDF_SAPLING_PERSONALIZATION: &'static [u8; 16] = b"Zcash_SaplingKDF"; -pub const PRF_OCK_PERSONALIZATION: &'static [u8; 16] = b"Zcash_Derive_ock"; +pub const KDF_SAPLING_PERSONALIZATION: &[u8; 16] = b"Zcash_SaplingKDF"; +pub const PRF_OCK_PERSONALIZATION: &[u8; 16] = b"Zcash_Derive_ock"; const COMPACT_NOTE_SIZE: usize = ( 1 + // version @@ -85,7 +85,7 @@ impl Default for Memo { impl PartialEq for Memo { fn eq(&self, rhs: &Memo) -> bool { - &self.0[..] == &rhs.0[..] + self.0[..] == rhs.0[..] } } diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index 10a6d6b..38a056a 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -97,10 +97,7 @@ impl ViewingKey { diversifier.g_d(params).map(|g_d| { let pk_d = g_d.mul(self.ivk(), params); - PaymentAddress { - pk_d: pk_d, - diversifier: diversifier, - } + PaymentAddress { pk_d, diversifier } }) } } @@ -145,9 +142,9 @@ impl PaymentAddress { params: &E::Params, ) -> Option> { self.g_d(params).map(|g_d| Note { - value: value, + value, r: randomness, - g_d: g_d, + g_d, pk_d: self.pk_d.clone(), }) } diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index d84eec2..8b8ef88 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -37,9 +37,9 @@ pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr { pedersen_hash::( Personalization::MerkleTree(depth), lhs.iter() - .map(|&x| x) + .copied() .take(Fr::NUM_BITS as usize) - .chain(rhs.iter().map(|&x| x).take(Fr::NUM_BITS as usize)), + .chain(rhs.iter().copied().take(Fr::NUM_BITS as usize)), &JUBJUB, ) .into_xy() diff --git a/zcash_primitives/src/serialize.rs b/zcash_primitives/src/serialize.rs index 41778dc..4e0fb93 100644 --- a/zcash_primitives/src/serialize.rs +++ b/zcash_primitives/src/serialize.rs @@ -70,7 +70,7 @@ impl Vector { F: Fn(&mut R) -> io::Result, { let count = CompactSize::read(&mut reader)?; - (0..count).into_iter().map(|_| func(&mut reader)).collect() + (0..count).map(|_| func(&mut reader)).collect() } pub fn write(mut writer: W, vec: &[E], func: F) -> io::Result<()> diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index a5df4c8..1f30f99 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -153,7 +153,7 @@ impl TransactionMetadata { /// they added (via the first call to [`Builder::add_sapling_spend`]) is the first /// [`SpendDescription`] in the transaction. pub fn spend_index(&self, n: usize) -> Option { - self.spend_indices.get(n).map(|i| *i) + self.spend_indices.get(n).copied() } /// Returns the index within the transaction of the [`OutputDescription`] corresponding @@ -164,7 +164,7 @@ impl TransactionMetadata { /// they added (via the first call to [`Builder::add_sapling_output`]) is the first /// [`OutputDescription`] in the transaction. pub fn output_index(&self, n: usize) -> Option { - self.output_indices.get(n).map(|i| *i) + self.output_indices.get(n).copied() } } @@ -414,7 +414,7 @@ impl Builder { self.mtx.shielded_spends.push(SpendDescription { cv, - anchor: anchor, + anchor, nullifier, rk, zkproof, diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index 001ff42..c0410c4 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -166,12 +166,10 @@ impl SpendDescription { writer.write_all(&self.zkproof)?; match self.spend_auth_sig { Some(sig) => sig.write(&mut writer), - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Missing spend auth signature", - )); - } + None => Err(io::Error::new( + io::ErrorKind::InvalidInput, + "Missing spend auth signature", + )), } } } @@ -347,23 +345,20 @@ impl JSDescription { .map(|mac| reader.read_exact(mac)) .collect::>()?; - let proof = match use_groth { - true => { - // Consensus rules (§4.3): - // - Canonical encoding is enforced in librustzcash_sprout_verify() - // - Proof validity is enforced in librustzcash_sprout_verify() - let mut proof = [0; GROTH_PROOF_SIZE]; - reader.read_exact(&mut proof)?; - SproutProof::Groth(proof) - } - false => { - // Consensus rules (§4.3): - // - Canonical encoding is enforced by PHGRProof in zcashd - // - Proof validity is enforced by JSDescription::Verify() in zcashd - let mut proof = [0; PHGR_PROOF_SIZE]; - reader.read_exact(&mut proof)?; - SproutProof::PHGR(proof) - } + let proof = if use_groth { + // Consensus rules (§4.3): + // - Canonical encoding is enforced in librustzcash_sprout_verify() + // - Proof validity is enforced in librustzcash_sprout_verify() + let mut proof = [0; GROTH_PROOF_SIZE]; + reader.read_exact(&mut proof)?; + SproutProof::Groth(proof) + } else { + // Consensus rules (§4.3): + // - Canonical encoding is enforced by PHGRProof in zcashd + // - Proof validity is enforced by JSDescription::Verify() in zcashd + let mut proof = [0; PHGR_PROOF_SIZE]; + reader.read_exact(&mut proof)?; + SproutProof::PHGR(proof) }; let mut ciphertexts = [[0; 601]; ZC_NUM_JS_OUTPUTS]; diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index 567d689..10e935b 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -29,7 +29,7 @@ pub struct TxId(pub [u8; 32]); impl fmt::Display for TxId { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut data = self.0.clone(); + let mut data = self.0; data.reverse(); formatter.write_str(&hex::encode(data)) } @@ -164,9 +164,10 @@ impl Transaction { let overwintered = (header >> 31) == 1; let version = header & 0x7FFFFFFF; - let version_group_id = match overwintered { - true => reader.read_u32::()?, - false => 0, + let version_group_id = if overwintered { + reader.read_u32::()? + } else { + 0 }; let is_overwinter_v3 = overwintered @@ -185,9 +186,10 @@ impl Transaction { let vin = Vector::read(&mut reader, TxIn::read)?; let vout = Vector::read(&mut reader, TxOut::read)?; let lock_time = reader.read_u32::()?; - let expiry_height = match is_overwinter_v3 || is_sapling_v4 { - true => reader.read_u32::()?, - false => 0, + let expiry_height = if is_overwinter_v3 || is_sapling_v4 { + reader.read_u32::()? + } else { + 0 }; let (value_balance, shielded_spends, shielded_outputs) = if is_sapling_v4 { @@ -223,9 +225,10 @@ impl Transaction { }; let binding_sig = - match is_sapling_v4 && !(shielded_spends.is_empty() && shielded_outputs.is_empty()) { - true => Some(Signature::read(&mut reader)?), - false => None, + if is_sapling_v4 && !(shielded_spends.is_empty() && shielded_outputs.is_empty()) { + Some(Signature::read(&mut reader)?) + } else { + None }; Transaction::from_data(TransactionData { diff --git a/zcash_primitives/src/transaction/sighash.rs b/zcash_primitives/src/transaction/sighash.rs index 1b05658..41c6da2 100644 --- a/zcash_primitives/src/transaction/sighash.rs +++ b/zcash_primitives/src/transaction/sighash.rs @@ -9,13 +9,13 @@ use super::{ }; use crate::legacy::Script; -const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &'static [u8; 12] = b"ZcashSigHash"; -const ZCASH_PREVOUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashPrevoutHash"; -const ZCASH_SEQUENCE_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSequencHash"; -const ZCASH_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashOutputsHash"; -const ZCASH_JOINSPLITS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashJSplitsHash"; -const ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSSpendsHash"; -const ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSOutputHash"; +const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &[u8; 12] = b"ZcashSigHash"; +const ZCASH_PREVOUTS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashPrevoutHash"; +const ZCASH_SEQUENCE_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashSequencHash"; +const ZCASH_OUTPUTS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashOutputsHash"; +const ZCASH_JOINSPLITS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashJSplitsHash"; +const ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashSSpendsHash"; +const ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashSOutputHash"; pub const SIGHASH_ALL: u32 = 1; const SIGHASH_NONE: u32 = 2; diff --git a/zcash_primitives/src/zip32.rs b/zcash_primitives/src/zip32.rs index 8788809..7cd6148 100644 --- a/zcash_primitives/src/zip32.rs +++ b/zcash_primitives/src/zip32.rs @@ -16,8 +16,8 @@ use crate::{ JUBJUB, }; -pub const ZIP32_SAPLING_MASTER_PERSONALIZATION: &'static [u8; 16] = b"ZcashIP32Sapling"; -pub const ZIP32_SAPLING_FVFP_PERSONALIZATION: &'static [u8; 16] = b"ZcashSaplingFVFP"; +pub const ZIP32_SAPLING_MASTER_PERSONALIZATION: &[u8; 16] = b"ZcashIP32Sapling"; +pub const ZIP32_SAPLING_FVFP_PERSONALIZATION: &[u8; 16] = b"ZcashSaplingFVFP"; // Common helper functions @@ -83,9 +83,9 @@ impl ChildIndex { } fn to_index(&self) -> u32 { - match self { - &ChildIndex::Hardened(i) => i + (1 << 31), - &ChildIndex::NonHardened(i) => i, + match *self { + ChildIndex::Hardened(i) => i + (1 << 31), + ChildIndex::NonHardened(i) => i, } } } From 91541675e200bfc9f51d4327a4927fda846a2597 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 2 Aug 2019 11:40:10 +0100 Subject: [PATCH 125/330] Address various clippy warnings/errors in zcash_proofs --- zcash_proofs/src/circuit/ecc.rs | 16 +++++----- zcash_proofs/src/circuit/pedersen_hash.rs | 4 +-- zcash_proofs/src/circuit/sapling.rs | 6 ++-- zcash_proofs/src/circuit/sprout/input.rs | 4 +-- zcash_proofs/src/circuit/sprout/mod.rs | 37 +++++++++-------------- zcash_proofs/src/circuit/sprout/output.rs | 4 +-- zcash_proofs/src/hashreader.rs | 2 +- zcash_proofs/src/sapling/prover.rs | 12 ++++---- 8 files changed, 39 insertions(+), 46 deletions(-) diff --git a/zcash_proofs/src/circuit/ecc.rs b/zcash_proofs/src/circuit/ecc.rs index 4c07829..76b837d 100644 --- a/zcash_proofs/src/circuit/ecc.rs +++ b/zcash_proofs/src/circuit/ecc.rs @@ -41,16 +41,16 @@ where { let chunk_a = chunk .get(0) - .map(|e| e.clone()) - .unwrap_or(Boolean::constant(false)); + .cloned() + .unwrap_or_else(|| Boolean::constant(false)); let chunk_b = chunk .get(1) - .map(|e| e.clone()) - .unwrap_or(Boolean::constant(false)); + .cloned() + .unwrap_or_else(|| Boolean::constant(false)); let chunk_c = chunk .get(2) - .map(|e| e.clone()) - .unwrap_or(Boolean::constant(false)); + .cloned() + .unwrap_or_else(|| Boolean::constant(false)); let (x, y) = lookup3_xy( cs.namespace(|| format!("window table lookup {}", i)), @@ -58,7 +58,7 @@ where window, )?; - let p = EdwardsPoint { x: x, y: y }; + let p = EdwardsPoint { x, y }; if result.is_none() { result = Some(p); @@ -570,7 +570,7 @@ impl MontgomeryPoint { /// on the curve. Useful for constants and /// window table lookups. pub fn interpret_unchecked(x: Num, y: Num) -> Self { - MontgomeryPoint { x: x, y: y } + MontgomeryPoint { x, y } } /// Performs an affine point addition, not defined for diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index 326d3ce..e77d28b 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -9,7 +9,7 @@ fn get_constant_bools(person: &Personalization) -> Vec { person .get_bits() .into_iter() - .map(|e| Boolean::constant(e)) + .map(Boolean::constant) .collect() } @@ -65,7 +65,7 @@ where segment_windows = &segment_windows[1..]; - if segment_windows.len() == 0 { + if segment_windows.is_empty() { break; } diff --git a/zcash_proofs/src/circuit/sapling.rs b/zcash_proofs/src/circuit/sapling.rs index 0554ff4..d43a628 100644 --- a/zcash_proofs/src/circuit/sapling.rs +++ b/zcash_proofs/src/circuit/sapling.rs @@ -150,7 +150,7 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { // Witness nsk as bits let nsk = boolean::field_into_boolean_vec_le( cs.namespace(|| "nsk"), - self.proof_generation_key.as_ref().map(|k| k.nsk.clone()), + self.proof_generation_key.as_ref().map(|k| k.nsk), )?; // NB: We don't ensure that the bit representation of nsk @@ -642,7 +642,7 @@ fn test_input_circuit_with_bls12_381() { let mut cs = TestConstraintSystem::::new(); let instance = Spend { - params: params, + params, value_commitment: Some(value_commitment.clone()), proof_generation_key: Some(proof_generation_key.clone()), payment_address: Some(payment_address.clone()), @@ -738,7 +738,7 @@ fn test_output_circuit_with_bls12_381() { let mut cs = TestConstraintSystem::::new(); let instance = Output { - params: params, + params, value_commitment: Some(value_commitment.clone()), payment_address: Some(payment_address.clone()), commitment_randomness: Some(commitment_randomness), diff --git a/zcash_proofs/src/circuit/sprout/input.rs b/zcash_proofs/src/circuit/sprout/input.rs index ad6091f..a2726d4 100644 --- a/zcash_proofs/src/circuit/sprout/input.rs +++ b/zcash_proofs/src/circuit/sprout/input.rs @@ -54,7 +54,7 @@ impl InputNote { // Witness into the merkle tree let mut cur = cm.clone(); - for (i, layer) in auth_path.into_iter().enumerate() { + for (i, layer) in auth_path.iter().enumerate() { let cs = &mut cs.namespace(|| format!("layer {}", i)); let cur_is_right = AllocatedBit::alloc( @@ -112,7 +112,7 @@ impl InputNote { ); } - Ok(InputNote { mac: mac, nf: nf }) + Ok(InputNote { mac, nf }) } } diff --git a/zcash_proofs/src/circuit/sprout/mod.rs b/zcash_proofs/src/circuit/sprout/mod.rs index 358e1bb..f72d792 100644 --- a/zcash_proofs/src/circuit/sprout/mod.rs +++ b/zcash_proofs/src/circuit/sprout/mod.rs @@ -234,10 +234,7 @@ impl NoteValue { )?); } - Ok(NoteValue { - value: value, - bits: bits, - }) + Ok(NoteValue { value, bits }) } /// Encodes the bits of the value into little-endian @@ -247,7 +244,7 @@ impl NoteValue { .chunks(8) .flat_map(|v| v.iter().rev()) .cloned() - .map(|e| Boolean::from(e)) + .map(Boolean::from) .collect() } @@ -379,11 +376,11 @@ fn test_sprout_constraints() { let a_sk = Some(SpendingKey(get_u256(&mut test_vector))); inputs.push(JSInput { - value: value, - a_sk: a_sk, - rho: rho, - r: r, - auth_path: auth_path, + value, + a_sk, + rho, + r, + auth_path, }); } @@ -395,11 +392,7 @@ fn test_sprout_constraints() { get_u256(&mut test_vector); let r = Some(CommitmentRandomness(get_u256(&mut test_vector))); - outputs.push(JSOutput { - value: value, - a_pk: a_pk, - r: r, - }); + outputs.push(JSOutput { value, a_pk, r }); } let vpub_old = Some(test_vector.read_u64::().unwrap()); @@ -415,13 +408,13 @@ fn test_sprout_constraints() { let mac2 = get_u256(&mut test_vector); let js = JoinSplit { - vpub_old: vpub_old, - vpub_new: vpub_new, - h_sig: h_sig, - phi: phi, - inputs: inputs, - outputs: outputs, - rt: rt, + vpub_old, + vpub_new, + h_sig, + phi, + inputs, + outputs, + rt, }; js.synthesize(&mut cs).unwrap(); diff --git a/zcash_proofs/src/circuit/sprout/output.rs b/zcash_proofs/src/circuit/sprout/output.rs index a9a1e48..73a9851 100644 --- a/zcash_proofs/src/circuit/sprout/output.rs +++ b/zcash_proofs/src/circuit/sprout/output.rs @@ -11,7 +11,7 @@ pub struct OutputNote { } impl OutputNote { - pub fn compute<'a, E, CS>( + pub fn compute( mut cs: CS, a_pk: Option, value: &NoteValue, @@ -41,6 +41,6 @@ impl OutputNote { &r, )?; - Ok(OutputNote { cm: cm }) + Ok(OutputNote { cm }) } } diff --git a/zcash_proofs/src/hashreader.rs b/zcash_proofs/src/hashreader.rs index dbe686f..f8487b8 100644 --- a/zcash_proofs/src/hashreader.rs +++ b/zcash_proofs/src/hashreader.rs @@ -11,7 +11,7 @@ impl HashReader { /// Construct a new `HashReader` given an existing `reader` by value. pub fn new(reader: R) -> Self { HashReader { - reader: reader, + reader, hasher: State::new(), } } diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index 283e76b..e5116c6 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -65,7 +65,7 @@ impl SaplingProvingContext { // Accumulate the value commitment randomness in the context { - let mut tmp = rcv.clone(); + let mut tmp = rcv; tmp.add_assign(&self.bsk); // Update the context @@ -74,7 +74,7 @@ impl SaplingProvingContext { // Construct the value commitment let value_commitment = ValueCommitment:: { - value: value, + value, randomness: rcv, }; @@ -96,7 +96,7 @@ impl SaplingProvingContext { // Let's compute the nullifier while we have the position let note = Note { - value: value, + value, g_d: diversifier .g_d::(params) .expect("was a valid diversifier before"), @@ -200,7 +200,7 @@ impl SaplingProvingContext { // Accumulate the value commitment randomness in the context { - let mut tmp = rcv.clone(); + let mut tmp = rcv; tmp.negate(); // Outputs subtract from the total. tmp.add_assign(&self.bsk); @@ -210,7 +210,7 @@ impl SaplingProvingContext { // Construct the value commitment for the proof instance let value_commitment = ValueCommitment:: { - value: value, + value, randomness: rcv, }; @@ -220,7 +220,7 @@ impl SaplingProvingContext { value_commitment: Some(value_commitment.clone()), payment_address: Some(payment_address.clone()), commitment_randomness: Some(rcm), - esk: Some(esk.clone()), + esk: Some(esk), }; // Create proof From fe93f2ff6b385f9f30bf3c278351d1d1f162a9bb Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 2 Aug 2019 12:00:15 +0100 Subject: [PATCH 126/330] Rename into_ -> to_ where &self is used. --- bellman/src/gadgets/num.rs | 10 +++--- librustzcash/src/tests/key_agreement.rs | 2 +- librustzcash/src/tests/key_components.rs | 4 +-- zcash_primitives/src/jubjub/edwards.rs | 6 ++-- zcash_primitives/src/jubjub/mod.rs | 4 +-- zcash_primitives/src/jubjub/montgomery.rs | 4 +-- zcash_primitives/src/jubjub/tests.rs | 12 +++---- zcash_primitives/src/primitives.rs | 6 ++-- zcash_primitives/src/sapling.rs | 2 +- zcash_primitives/src/transaction/builder.rs | 2 +- zcash_primitives/src/zip32.rs | 2 +- zcash_proofs/examples/bench.rs | 4 +-- zcash_proofs/src/circuit/ecc.rs | 38 ++++++++++----------- zcash_proofs/src/circuit/pedersen_hash.rs | 4 +-- zcash_proofs/src/circuit/sapling.rs | 24 ++++++------- zcash_proofs/src/sapling/prover.rs | 8 ++--- zcash_proofs/src/sapling/verifier.rs | 8 ++--- 17 files changed, 70 insertions(+), 70 deletions(-) diff --git a/bellman/src/gadgets/num.rs b/bellman/src/gadgets/num.rs index 81f4fb3..eecccef 100644 --- a/bellman/src/gadgets/num.rs +++ b/bellman/src/gadgets/num.rs @@ -66,7 +66,7 @@ impl AllocatedNum { /// order, requiring that the representation /// strictly exists "in the field" (i.e., a /// congruency is not allowed.) - pub fn into_bits_le_strict(&self, mut cs: CS) -> Result, SynthesisError> + pub fn to_bits_le_strict(&self, mut cs: CS) -> Result, SynthesisError> where CS: ConstraintSystem, { @@ -189,7 +189,7 @@ impl AllocatedNum { /// Convert the allocated number into its little-endian representation. /// Note that this does not strongly enforce that the commitment is /// "in the field." - pub fn into_bits_le(&self, mut cs: CS) -> Result, SynthesisError> + pub fn to_bits_le(&self, mut cs: CS) -> Result, SynthesisError> where CS: ConstraintSystem, { @@ -522,7 +522,7 @@ mod test { let mut cs = TestConstraintSystem::::new(); let n = AllocatedNum::alloc(&mut cs, || Ok(negone)).unwrap(); - n.into_bits_le_strict(&mut cs).unwrap(); + n.to_bits_le_strict(&mut cs).unwrap(); assert!(cs.is_satisfied()); @@ -550,9 +550,9 @@ mod test { let n = AllocatedNum::alloc(&mut cs, || Ok(r)).unwrap(); let bits = if i % 2 == 0 { - n.into_bits_le(&mut cs).unwrap() + n.to_bits_le(&mut cs).unwrap() } else { - n.into_bits_le_strict(&mut cs).unwrap() + n.to_bits_le_strict(&mut cs).unwrap() }; assert!(cs.is_satisfied()); diff --git a/librustzcash/src/tests/key_agreement.rs b/librustzcash/src/tests/key_agreement.rs index d942e10..8f2c273 100644 --- a/librustzcash/src/tests/key_agreement.rs +++ b/librustzcash/src/tests/key_agreement.rs @@ -25,7 +25,7 @@ fn test_key_agreement() { let addr = loop { let mut d = [0; 11]; rng.fill_bytes(&mut d); - match vk.into_payment_address(Diversifier(d), ¶ms) { + match vk.to_payment_address(Diversifier(d), ¶ms) { Some(a) => break a, None => {} } diff --git a/librustzcash/src/tests/key_components.rs b/librustzcash/src/tests/key_components.rs index a034b9f..a15a40a 100644 --- a/librustzcash/src/tests/key_components.rs +++ b/librustzcash/src/tests/key_components.rs @@ -678,7 +678,7 @@ fn key_components() { } let pgk = ProofGenerationKey { ak, nsk }; - let fvk = pgk.into_viewing_key(&JUBJUB); + let fvk = pgk.to_viewing_key(&JUBJUB); { let mut vec = Vec::new(); fvk.nk.write(&mut vec).unwrap(); @@ -704,7 +704,7 @@ fn key_components() { let diversifier = Diversifier(tv.default_d); assert!(librustzcash_check_diversifier(&tv.default_d)); - let addr = fvk.into_payment_address(diversifier, &JUBJUB).unwrap(); + let addr = fvk.to_payment_address(diversifier, &JUBJUB).unwrap(); { let mut vec = Vec::new(); addr.pk_d.write(&mut vec).unwrap(); diff --git a/zcash_primitives/src/jubjub/edwards.rs b/zcash_primitives/src/jubjub/edwards.rs index 233bfb7..9ef50a2 100644 --- a/zcash_primitives/src/jubjub/edwards.rs +++ b/zcash_primitives/src/jubjub/edwards.rs @@ -168,7 +168,7 @@ impl Point { impl Point { pub fn write(&self, writer: W) -> io::Result<()> { - let (x, y) = self.into_xy(); + let (x, y) = self.to_xy(); assert_eq!(E::Fr::NUM_BITS, 255); @@ -183,7 +183,7 @@ impl Point { /// Convert from a Montgomery point pub fn from_montgomery(m: &montgomery::Point, params: &E::Params) -> Self { - match m.into_xy() { + match m.to_xy() { None => { // Map the point at infinity to the neutral element. Point::zero() @@ -306,7 +306,7 @@ impl Point { } } - pub fn into_xy(&self) -> (E::Fr, E::Fr) { + pub fn to_xy(&self) -> (E::Fr, E::Fr) { let zinv = self.z.inverse().unwrap(); let mut x = self.x; diff --git a/zcash_primitives/src/jubjub/mod.rs b/zcash_primitives/src/jubjub/mod.rs index 624592e..40938f3 100644 --- a/zcash_primitives/src/jubjub/mod.rs +++ b/zcash_primitives/src/jubjub/mod.rs @@ -384,7 +384,7 @@ impl JubjubBls12 { // coeffs = g, g*2, g*3, g*4 for _ in 0..4 { - coeffs.push(g.into_xy().expect("cannot produce O")); + coeffs.push(g.to_xy().expect("cannot produce O")); g = g.add(&gen, &tmp_params); } windows.push(coeffs); @@ -411,7 +411,7 @@ impl JubjubBls12 { let mut coeffs = vec![(Fr::zero(), Fr::one())]; let mut g = gen.clone(); for _ in 0..7 { - coeffs.push(g.into_xy()); + coeffs.push(g.to_xy()); g = g.add(&gen, &tmp_params); } windows.push(coeffs); diff --git a/zcash_primitives/src/jubjub/montgomery.rs b/zcash_primitives/src/jubjub/montgomery.rs index 0ebedd2..4e6c5e1 100644 --- a/zcash_primitives/src/jubjub/montgomery.rs +++ b/zcash_primitives/src/jubjub/montgomery.rs @@ -98,7 +98,7 @@ impl Point { impl Point { /// Convert from an Edwards point pub fn from_edwards(e: &edwards::Point, params: &E::Params) -> Self { - let (x, y) = e.into_xy(); + let (x, y) = e.to_xy(); if y == E::Fr::one() { // The only solution for y = 1 is x = 0. (0, 1) is @@ -177,7 +177,7 @@ impl Point { } } - pub fn into_xy(&self) -> Option<(E::Fr, E::Fr)> { + pub fn to_xy(&self) -> Option<(E::Fr, E::Fr)> { if self.infinity { None } else { diff --git a/zcash_primitives/src/jubjub/tests.rs b/zcash_primitives/src/jubjub/tests.rs index 1b4f8d1..b2c12ae 100644 --- a/zcash_primitives/src/jubjub/tests.rs +++ b/zcash_primitives/src/jubjub/tests.rs @@ -119,13 +119,13 @@ fn test_mul_associativity(params: &E::Params) { assert!(res2 == res3); assert!(res3 == res4); - let (x, y) = res1.into_xy(); + let (x, y) = res1.to_xy(); assert!(is_on_twisted_edwards_curve(x, y, params)); - let (x, y) = res2.into_xy(); + let (x, y) = res2.to_xy(); assert!(is_on_twisted_edwards_curve(x, y, params)); - let (x, y) = res3.into_xy(); + let (x, y) = res3.to_xy(); assert!(is_on_twisted_edwards_curve(x, y, params)); } } @@ -238,7 +238,7 @@ fn test_get_for(params: &E::Params) { let sign = rng.next_u32() % 2 == 1; if let Some(mut p) = edwards::Point::::get_for_y(y, sign, params) { - assert!(p.into_xy().0.into_repr().is_odd() == sign); + assert!(p.to_xy().0.into_repr().is_odd() == sign); p = p.negate(); assert!(edwards::Point::::get_for_y(y, !sign, params).unwrap() == p); } @@ -274,12 +274,12 @@ fn test_rand(params: &E::Params) { let e = edwards::Point::::rand(rng, params); { - let (x, y) = p.into_xy().unwrap(); + let (x, y) = p.to_xy().unwrap(); assert!(is_on_mont_curve(x, y, params)); } { - let (x, y) = e.into_xy(); + let (x, y) = e.to_xy(); assert!(is_on_twisted_edwards_curve(x, y, params)); } } diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index 38a056a..727402d 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -39,7 +39,7 @@ pub struct ProofGenerationKey { } impl ProofGenerationKey { - pub fn into_viewing_key(&self, params: &E::Params) -> ViewingKey { + pub fn to_viewing_key(&self, params: &E::Params) -> ViewingKey { ViewingKey { ak: self.ak.clone(), nk: params @@ -89,7 +89,7 @@ impl ViewingKey { E::Fs::from_repr(e).expect("should be a valid scalar") } - pub fn into_payment_address( + pub fn to_payment_address( &self, diversifier: Diversifier, params: &E::Params, @@ -242,6 +242,6 @@ impl Note { pub fn cm(&self, params: &E::Params) -> E::Fr { // The commitment is in the prime order subgroup, so mapping the // commitment to the x-coordinate is an injective encoding. - self.cm_full_point(params).into_xy().0 + self.cm_full_point(params).to_xy().0 } } diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index 8b8ef88..4f57a43 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -42,7 +42,7 @@ pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr { .chain(rhs.iter().copied().take(Fr::NUM_BITS as usize)), &JUBJUB, ) - .into_xy() + .to_xy() .0 .into_repr() } diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 1f30f99..281ccbf 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -394,7 +394,7 @@ impl Builder { let mut nullifier = [0u8; 32]; nullifier.copy_from_slice(&spend.note.nf( - &proof_generation_key.into_viewing_key(&JUBJUB), + &proof_generation_key.to_viewing_key(&JUBJUB), spend.witness.position, &JUBJUB, )); diff --git a/zcash_primitives/src/zip32.rs b/zcash_primitives/src/zip32.rs index 7cd6148..e287602 100644 --- a/zcash_primitives/src/zip32.rs +++ b/zcash_primitives/src/zip32.rs @@ -434,7 +434,7 @@ impl ExtendedFullViewingKey { Ok(ret) => ret, Err(()) => return Err(()), }; - match self.fvk.vk.into_payment_address(d_j, &JUBJUB) { + match self.fvk.vk.to_payment_address(d_j, &JUBJUB) { Some(addr) => Ok((j, addr)), None => Err(()), } diff --git a/zcash_proofs/examples/bench.rs b/zcash_proofs/examples/bench.rs index 62beb0a..2f48786 100644 --- a/zcash_proofs/examples/bench.rs +++ b/zcash_proofs/examples/bench.rs @@ -50,7 +50,7 @@ fn main() { nsk: nsk.clone(), }; - let viewing_key = proof_generation_key.into_viewing_key(jubjub_params); + let viewing_key = proof_generation_key.to_viewing_key(jubjub_params); let payment_address; @@ -61,7 +61,7 @@ fn main() { Diversifier(d) }; - if let Some(p) = viewing_key.into_payment_address(diversifier, jubjub_params) { + if let Some(p) = viewing_key.to_payment_address(diversifier, jubjub_params) { payment_address = p; break; } diff --git a/zcash_proofs/src/circuit/ecc.rs b/zcash_proofs/src/circuit/ecc.rs index 76b837d..ef5bedf 100644 --- a/zcash_proofs/src/circuit/ecc.rs +++ b/zcash_proofs/src/circuit/ecc.rs @@ -121,9 +121,9 @@ impl EdwardsPoint { { let mut tmp = vec![]; - let x = self.x.into_bits_le_strict(cs.namespace(|| "unpack x"))?; + let x = self.x.to_bits_le_strict(cs.namespace(|| "unpack x"))?; - let y = self.y.into_bits_le_strict(cs.namespace(|| "unpack y"))?; + let y = self.y.to_bits_le_strict(cs.namespace(|| "unpack y"))?; tmp.extend(y); tmp.push(x[0].clone()); @@ -141,7 +141,7 @@ impl EdwardsPoint { where CS: ConstraintSystem, { - let p = p.map(|p| p.into_xy()); + let p = p.map(|p| p.to_xy()); // Allocate x let x = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(p.get()?.0))?; @@ -688,8 +688,8 @@ mod test { let mut cs = TestConstraintSystem::::new(); let p = montgomery::Point::::rand(rng, params); - let (u, v) = edwards::Point::from_montgomery(&p, params).into_xy(); - let (x, y) = p.into_xy().unwrap(); + let (u, v) = edwards::Point::from_montgomery(&p, params).to_xy(); + let (x, y) = p.to_xy().unwrap(); let numx = AllocatedNum::alloc(cs.namespace(|| "mont x"), || Ok(x)).unwrap(); let numy = AllocatedNum::alloc(cs.namespace(|| "mont y"), || Ok(y)).unwrap(); @@ -728,7 +728,7 @@ mod test { let mut cs = TestConstraintSystem::::new(); let q = EdwardsPoint::witness(&mut cs, Some(p.clone()), ¶ms).unwrap(); - let p = p.into_xy(); + let p = p.to_xy(); assert!(cs.is_satisfied()); assert_eq!(q.x.get_value().unwrap(), p.0); @@ -737,7 +737,7 @@ mod test { for _ in 0..100 { let p = edwards::Point::::rand(rng, ¶ms); - let (x, y) = p.into_xy(); + let (x, y) = p.to_xy(); let mut cs = TestConstraintSystem::::new(); let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(x)).unwrap(); @@ -779,7 +779,7 @@ mod test { let p = params.generator(FixedGenerators::NoteCommitmentRandomness); let s = Fs::random(rng); let q = p.mul(s, params); - let (x1, y1) = q.into_xy(); + let (x1, y1) = q.to_xy(); let mut s_bits = BitIterator::new(s.into_repr()).collect::>(); s_bits.reverse(); @@ -823,8 +823,8 @@ mod test { let s = Fs::random(rng); let q = p.mul(s, params); - let (x0, y0) = p.into_xy(); - let (x1, y1) = q.into_xy(); + let (x0, y0) = p.to_xy(); + let (x1, y1) = q.to_xy(); let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || Ok(x0)).unwrap(); let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || Ok(y0)).unwrap(); @@ -873,7 +873,7 @@ mod test { let p = edwards::Point::::rand(rng, params); - let (x0, y0) = p.into_xy(); + let (x0, y0) = p.to_xy(); let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || Ok(x0)).unwrap(); let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || Ok(y0)).unwrap(); @@ -941,9 +941,9 @@ mod test { let p3 = p1.add(&p2, params); - let (x0, y0) = p1.into_xy(); - let (x1, y1) = p2.into_xy(); - let (x2, y2) = p3.into_xy(); + let (x0, y0) = p1.to_xy(); + let (x1, y1) = p2.to_xy(); + let (x2, y2) = p3.to_xy(); let mut cs = TestConstraintSystem::::new(); @@ -1002,8 +1002,8 @@ mod test { let p1 = edwards::Point::::rand(rng, params); let p2 = p1.double(params); - let (x0, y0) = p1.into_xy(); - let (x1, y1) = p2.into_xy(); + let (x0, y0) = p1.to_xy(); + let (x1, y1) = p2.to_xy(); let mut cs = TestConstraintSystem::::new(); @@ -1053,9 +1053,9 @@ mod test { let p3 = p1.add(&p2, params); - let (x0, y0) = p1.into_xy().unwrap(); - let (x1, y1) = p2.into_xy().unwrap(); - let (x2, y2) = p3.into_xy().unwrap(); + let (x0, y0) = p1.to_xy().unwrap(); + let (x1, y1) = p2.to_xy().unwrap(); + let (x2, y2) = p3.to_xy().unwrap(); let mut cs = TestConstraintSystem::::new(); diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index e77d28b..409f30e 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -189,7 +189,7 @@ mod test { input.clone().into_iter(), params, ) - .into_xy(); + .to_xy(); assert_eq!(res.get_x().get_value().unwrap(), expected.0); assert_eq!(res.get_y().get_value().unwrap(), expected.1); @@ -200,7 +200,7 @@ mod test { input.into_iter(), params, ) - .into_xy(); + .to_xy(); assert!(res.get_x().get_value().unwrap() != unexpected.0); assert!(res.get_y().get_value().unwrap() != unexpected.1); diff --git a/zcash_proofs/src/circuit/sapling.rs b/zcash_proofs/src/circuit/sapling.rs index d43a628..de6887b 100644 --- a/zcash_proofs/src/circuit/sapling.rs +++ b/zcash_proofs/src/circuit/sapling.rs @@ -336,8 +336,8 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { // they will be unable to find an authentication path in the // tree with high probability. let mut preimage = vec![]; - preimage.extend(xl.into_bits_le(cs.namespace(|| "xl into bits"))?); - preimage.extend(xr.into_bits_le(cs.namespace(|| "xr into bits"))?); + preimage.extend(xl.to_bits_le(cs.namespace(|| "xl into bits"))?); + preimage.extend(xr.to_bits_le(cs.namespace(|| "xr into bits"))?); // Compute the new subtree value cur = pedersen_hash::pedersen_hash( @@ -464,7 +464,7 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { // they would like. { // Just grab pk_d from the witness - let pk_d = self.payment_address.as_ref().map(|e| e.pk_d.into_xy()); + let pk_d = self.payment_address.as_ref().map(|e| e.pk_d.to_xy()); // Witness the y-coordinate, encoded as little // endian bits (to match the representation) @@ -567,7 +567,7 @@ fn test_input_circuit_with_bls12_381() { nsk: nsk.clone(), }; - let viewing_key = proof_generation_key.into_viewing_key(params); + let viewing_key = proof_generation_key.to_viewing_key(params); let payment_address; @@ -578,7 +578,7 @@ fn test_input_circuit_with_bls12_381() { Diversifier(d) }; - if let Some(p) = viewing_key.into_payment_address(diversifier, params) { + if let Some(p) = viewing_key.to_payment_address(diversifier, params) { payment_address = p; break; } @@ -590,8 +590,8 @@ fn test_input_circuit_with_bls12_381() { let ar = fs::Fs::random(rng); { - let rk = viewing_key.rk(ar, params).into_xy(); - let expected_value_cm = value_commitment.cm(params).into_xy(); + let rk = viewing_key.rk(ar, params).to_xy(); + let expected_value_cm = value_commitment.cm(params).to_xy(); let note = Note { value: value_commitment.value, g_d: g_d.clone(), @@ -626,7 +626,7 @@ fn test_input_circuit_with_bls12_381() { .chain(rhs.into_iter().take(Fr::NUM_BITS as usize)), params, ) - .into_xy() + .to_xy() .0; if b { @@ -714,7 +714,7 @@ fn test_output_circuit_with_bls12_381() { nsk: nsk.clone(), }; - let viewing_key = proof_generation_key.into_viewing_key(params); + let viewing_key = proof_generation_key.to_viewing_key(params); let payment_address; @@ -725,7 +725,7 @@ fn test_output_circuit_with_bls12_381() { Diversifier(d) }; - if let Some(p) = viewing_key.into_payment_address(diversifier, params) { + if let Some(p) = viewing_key.to_payment_address(diversifier, params) { payment_address = p; break; } @@ -759,13 +759,13 @@ fn test_output_circuit_with_bls12_381() { .expect("should be valid") .cm(params); - let expected_value_cm = value_commitment.cm(params).into_xy(); + let expected_value_cm = value_commitment.cm(params).to_xy(); let expected_epk = payment_address .g_d(params) .expect("should be valid") .mul(esk, params); - let expected_epk_xy = expected_epk.into_xy(); + let expected_epk_xy = expected_epk.to_xy(); assert_eq!(cs.num_inputs(), 6); assert_eq!(cs.get_input(0, "ONE"), Fr::one()); diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index e5116c6..0603424 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -79,10 +79,10 @@ impl SaplingProvingContext { }; // Construct the viewing key - let viewing_key = proof_generation_key.into_viewing_key(params); + let viewing_key = proof_generation_key.to_viewing_key(params); // Construct the payment address with the viewing key / diversifier - let payment_address = match viewing_key.into_payment_address(diversifier, params) { + let payment_address = match viewing_key.to_payment_address(diversifier, params) { Some(p) => p, None => return Err(()), }; @@ -130,12 +130,12 @@ impl SaplingProvingContext { // Construct public input for circuit let mut public_input = [Fr::zero(); 7]; { - let (x, y) = rk.0.into_xy(); + let (x, y) = rk.0.to_xy(); public_input[0] = x; public_input[1] = y; } { - let (x, y) = value_commitment.cm(params).into_xy(); + let (x, y) = value_commitment.cm(params).to_xy(); public_input[2] = x; public_input[3] = y; } diff --git a/zcash_proofs/src/sapling/verifier.rs b/zcash_proofs/src/sapling/verifier.rs index 0801023..5199bd8 100644 --- a/zcash_proofs/src/sapling/verifier.rs +++ b/zcash_proofs/src/sapling/verifier.rs @@ -82,12 +82,12 @@ impl SaplingVerificationContext { // Construct public input for circuit let mut public_input = [Fr::zero(); 7]; { - let (x, y) = rk.0.into_xy(); + let (x, y) = rk.0.to_xy(); public_input[0] = x; public_input[1] = y; } { - let (x, y) = cv.into_xy(); + let (x, y) = cv.to_xy(); public_input[2] = x; public_input[3] = y; } @@ -146,12 +146,12 @@ impl SaplingVerificationContext { // Construct public input for circuit let mut public_input = [Fr::zero(); 5]; { - let (x, y) = cv.into_xy(); + let (x, y) = cv.to_xy(); public_input[0] = x; public_input[1] = y; } { - let (x, y) = epk.into_xy(); + let (x, y) = epk.to_xy(); public_input[2] = x; public_input[3] = y; } From 90165486983018853d03eb4a85ec6e0a7287361c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 2 Aug 2019 12:03:38 +0100 Subject: [PATCH 127/330] Take self directly in into_* functions --- bellman/src/gadgets/blake2s.rs | 2 +- bellman/src/gadgets/uint32.rs | 10 ++++++---- zcash_proofs/src/circuit/ecc.rs | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/bellman/src/gadgets/blake2s.rs b/bellman/src/gadgets/blake2s.rs index beefe09..672f139 100644 --- a/bellman/src/gadgets/blake2s.rs +++ b/bellman/src/gadgets/blake2s.rs @@ -404,7 +404,7 @@ pub fn blake2s>( )?; } - Ok(h.iter().flat_map(|b| b.into_bits()).collect()) + Ok(h.into_iter().flat_map(|b| b.into_bits()).collect()) } #[cfg(test)] diff --git a/bellman/src/gadgets/uint32.rs b/bellman/src/gadgets/uint32.rs index 3467400..5a93e75 100644 --- a/bellman/src/gadgets/uint32.rs +++ b/bellman/src/gadgets/uint32.rs @@ -72,8 +72,10 @@ impl UInt32 { Ok(UInt32 { bits, value }) } - pub fn into_bits_be(&self) -> Vec { - self.bits.iter().rev().cloned().collect() + pub fn into_bits_be(self) -> Vec { + let mut ret = self.bits; + ret.reverse(); + ret } pub fn from_bits_be(bits: &[Boolean]) -> Self { @@ -101,8 +103,8 @@ impl UInt32 { } /// Turns this `UInt32` into its little-endian byte order representation. - pub fn into_bits(&self) -> Vec { - self.bits.clone() + pub fn into_bits(self) -> Vec { + self.bits } /// Converts a little-endian byte order representation of bits into a diff --git a/zcash_proofs/src/circuit/ecc.rs b/zcash_proofs/src/circuit/ecc.rs index ef5bedf..fa4913a 100644 --- a/zcash_proofs/src/circuit/ecc.rs +++ b/zcash_proofs/src/circuit/ecc.rs @@ -508,7 +508,7 @@ impl MontgomeryPoint { /// a point in the birationally equivalent twisted /// Edwards curve. pub fn into_edwards( - &self, + self, mut cs: CS, params: &E::Params, ) -> Result, SynthesisError> From 7c1d4d9a5b63330d71884dc78fefcefaf8b384d5 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 18 Aug 2019 23:56:15 +0100 Subject: [PATCH 128/330] Log distinct error cases in Equihash verification --- Cargo.lock | 10 ++++++++++ zcash_primitives/Cargo.toml | 1 + zcash_primitives/src/block/equihash.rs | 7 ++++--- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6f658a..623bcc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -317,6 +317,14 @@ dependencies = [ "zcash_proofs 0.0.0", ] +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nodrop" version = "0.1.13" @@ -535,6 +543,7 @@ dependencies = [ "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -594,6 +603,7 @@ dependencies = [ "checksum hex-literal-impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "520870c3213943eb8d7803e80180d12a6c7ceb4ae74602544529d1643dc4ddda" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)" = "c665266eb592905e8503ba3403020f4b8794d26263f412ca33171600eca9a6fa" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "57450397855d951f1a41305e54851b1a7b8f5d2e349543a02a2effe25459f718" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index 5e1bf91..7019dec 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -16,6 +16,7 @@ ff = { path = "../ff" } fpe = "0.2" hex = "0.3" lazy_static = "1" +log = "0.4" pairing = { path = "../pairing" } rand = "0.7" rand_core = "0.5" diff --git a/zcash_primitives/src/block/equihash.rs b/zcash_primitives/src/block/equihash.rs index 9710dc9..2a3bb66 100644 --- a/zcash_primitives/src/block/equihash.rs +++ b/zcash_primitives/src/block/equihash.rs @@ -1,5 +1,6 @@ use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams, State as Blake2bState}; use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; +use log::error; use std::io::Cursor; use std::mem::size_of; @@ -196,13 +197,13 @@ fn distinct_indices(a: &Node, b: &Node) -> bool { fn validate_subtrees(p: &Params, a: &Node, b: &Node) -> bool { if !has_collision(a, b, p.collision_byte_length()) { - // error!("Invalid solution: invalid collision length between StepRows"); + error!("Invalid solution: invalid collision length between StepRows"); false } else if b.indices_before(a) { - // error!("Invalid solution: Index tree incorrectly ordered"); + error!("Invalid solution: Index tree incorrectly ordered"); false } else if !distinct_indices(a, b) { - // error!("Invalid solution: duplicate indices"); + error!("Invalid solution: duplicate indices"); false } else { true From 0c7eb84d36e41e562f6a9a092c67d772f46f6fc5 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 19 Aug 2019 00:21:10 +0100 Subject: [PATCH 129/330] impl FromStr for Memo Memo::from_str was previously shadowing a built-in trait method. --- zcash_primitives/src/note_encryption.rs | 37 +++++++++++++++---------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 0d0e83a..2644016 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -106,11 +106,6 @@ impl Memo { } } - /// Returns a `Memo` containing the given string, or `None` if the string is too long. - pub fn from_str(memo: &str) -> Option { - Memo::from_bytes(memo.as_bytes()) - } - /// Returns the underlying bytes of the `Memo`. pub fn as_bytes(&self) -> &[u8] { &self.0[..] @@ -134,6 +129,15 @@ impl Memo { } } +impl str::FromStr for Memo { + type Err = (); + + /// Returns a `Memo` containing the given string, or an error if the string is too long. + fn from_str(memo: &str) -> Result { + Memo::from_bytes(memo.as_bytes()).ok_or(()) + } +} + pub fn generate_esk(rng: &mut R) -> Fs { // create random 64 byte buffer let mut buffer = [0u8; 64]; @@ -557,6 +561,7 @@ mod tests { use pairing::bls12_381::{Bls12, Fr, FrRepr}; use rand_core::{CryptoRng, RngCore}; use rand_os::OsRng; + use std::str::FromStr; use super::{ kdf_sapling, prf_ock, sapling_ka_agree, try_sapling_compact_note_decryption, @@ -661,16 +666,18 @@ mod tests { 0x74, 0x20, 0x65, 0x6e, 0x6f, 0x75, 0x67, 0x68 ]) ); - assert!(Memo::from_str( - "thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \ - iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ - veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeryyyyyyyyyyyyyyyyyyyyyyyyyy \ - looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong \ - meeeeeeeeeeeeeeeeeeemooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo \ - but it's now a bit too long" - ) - .is_none()); + assert_eq!( + Memo::from_str( + "thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \ + iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ + veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeryyyyyyyyyyyyyyyyyyyyyyyyyy \ + looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong \ + meeeeeeeeeeeeeeeeeeemooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo \ + but it's now a bit too long" + ), + Err(()) + ); } #[test] From f9f17b291f044ae260df4ca205177314a63bd091 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 27 Aug 2019 19:33:18 +0100 Subject: [PATCH 130/330] Add code coverage with cargo-tarpaulin and Codecov --- .travis.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.travis.yml b/.travis.yml index 399eaf1..b9fcb7e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,12 @@ language: rust rust: - 1.36.0 +addons: + apt: + packages: + # For cargo-tarpaulin + - libssl-dev + cache: cargo before_script: @@ -9,4 +15,16 @@ before_script: script: - cargo fmt --all -- --check + - cargo build --verbose --release --all - cargo test --verbose --release --all + +before_cache: + - rm -rf "$TRAVIS_HOME/.cargo/registry/src" + - cargo install cargo-tarpaulin || echo "cargo-tarpaulin already installed" + - cargo install cargo-update || echo "cargo-update already installed" + - cargo install-update -a # update outdated cached binaries + +after_success: + # Manually exclude packages that are going to be removed from the workspace + - travis_wait cargo tarpaulin --release --timeout 600 --out Xml --packages "librustzcash,zcash_client_backend,zcash_primitives,zcash_proofs" + - bash <(curl -s https://codecov.io/bash) From ee9c88ecb0facbf8f49eff44a05bb9c1cac43aff Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 28 Aug 2019 19:39:35 +0100 Subject: [PATCH 131/330] Exclude slow tests from code coverage --- .github/workflows/rust.yml | 4 ++++ .travis.yml | 1 + zcash_proofs/src/circuit/sprout/mod.rs | 1 + 3 files changed, 6 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index fdeb90d..300a7ba 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -18,6 +18,8 @@ jobs: run: cargo build --verbose --release --all - name: Run tests run: cargo test --verbose --release --all + - name: Run slow tests + run: cargo test --verbose --release --all -- --ignored macOS: name: Test on macOS-latest @@ -35,3 +37,5 @@ jobs: run: $HOME/.cargo/bin/cargo build --verbose --release --all - name: Run tests run: $HOME/.cargo/bin/cargo test --verbose --release --all + - name: Run slow tests + run: $HOME/.cargo/bin/cargo test --verbose --release --all -- --ignored diff --git a/.travis.yml b/.travis.yml index b9fcb7e..e976cd0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,7 @@ script: - cargo fmt --all -- --check - cargo build --verbose --release --all - cargo test --verbose --release --all + - cargo test --verbose --release --all -- --ignored before_cache: - rm -rf "$TRAVIS_HOME/.cargo/registry/src" diff --git a/zcash_proofs/src/circuit/sprout/mod.rs b/zcash_proofs/src/circuit/sprout/mod.rs index 358e1bb..b946464 100644 --- a/zcash_proofs/src/circuit/sprout/mod.rs +++ b/zcash_proofs/src/circuit/sprout/mod.rs @@ -326,6 +326,7 @@ where } #[test] +#[ignore] fn test_sprout_constraints() { use bellman::gadgets::test::*; use pairing::bls12_381::Bls12; From c00b65bb783372fd16c627b73f7d65fbc82a1481 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 29 Aug 2019 01:06:41 +0100 Subject: [PATCH 132/330] Extend Travis CI timeout --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e976cd0..caa44f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,5 +27,5 @@ before_cache: after_success: # Manually exclude packages that are going to be removed from the workspace - - travis_wait cargo tarpaulin --release --timeout 600 --out Xml --packages "librustzcash,zcash_client_backend,zcash_primitives,zcash_proofs" + - travis_wait 35 cargo tarpaulin --release --timeout 600 --out Xml --packages "librustzcash,zcash_client_backend,zcash_primitives,zcash_proofs" - bash <(curl -s https://codecov.io/bash) From c05446d2aee99bc47662619500ec90be388a2748 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 29 Aug 2019 19:34:27 +0300 Subject: [PATCH 133/330] add get_peaks method --- src/tree.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/tree.rs b/src/tree.rs index 5a38740..f199461 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -109,6 +109,34 @@ impl Tree { result } + fn get_peaks(&self, root: NodeLink) -> Vec { + let (left_child_link, right_child_link) = { + let root = self.resolve_link(root); + ( + root.node.left.expect("It would stop before when root is leaf"), + root.node.right.expect("It would stop before when root is leaf"), + ) + }; + + let mut result = Vec::new(); + + let left_child = self.resolve_link(left_child_link); + if left_child.node.complete() { + result.push(left_child_link); + } else { + result.extend(self.get_peaks(left_child_link)); + } + + let right_child = self.resolve_link(right_child_link); + if right_child.node.complete() { + result.push(right_child_link); + } else { + result.extend(self.get_peaks(right_child_link)); + } + + result + } + /// Append one leaf to the tree. pub fn append_leaf(&mut self, root: NodeLink, new_leaf: NodeData) -> AppendTransaction { let is_complete= self.resolve_link(root).node.complete(); From fa04929891e96b218ed8febbe5c9f2b1c85f9161 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 2 Sep 2019 15:11:23 +0300 Subject: [PATCH 134/330] refactored append and fixed tests --- src/lib.rs | 6 ++- src/tree.rs | 107 +++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 86 insertions(+), 27 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e398029..e55c308 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,9 +48,13 @@ pub struct MMRNode { impl MMRNode { fn complete(&self) -> bool { - let leaves = self.data.end_height - self.data.start_height + 1; + let leaves = self.leaf_count(); leaves & (leaves - 1) == 0 } + + fn leaf_count(&self) -> u32 { + self.data.end_height - self.data.start_height + 1 + } } impl From for MMRNode { diff --git a/src/tree.rs b/src/tree.rs index f199461..c26696b 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -141,7 +141,7 @@ impl Tree { pub fn append_leaf(&mut self, root: NodeLink, new_leaf: NodeData) -> AppendTransaction { let is_complete= self.resolve_link(root).node.complete(); - let (new_root_node, mut appended) = if is_complete { + let (new_root, mut appended) = if is_complete { let new_leaf_link = self.push(new_leaf.into()); let mut appended = Vec::new(); @@ -153,35 +153,77 @@ impl Tree { self.resolve_link(new_leaf_link), ); - (new_root_node, appended) + (self.push_generated(new_root_node), appended) } else { - let (root_left_child, root_right_child) = { - let root = self.resolve_link(root).node; - ( - root.left.expect("Root should always have left child"), - root.right.expect("Root should always have right child"), +// let (root_left_child, root_right_child) = { +// let root = self.resolve_link(root).node; +// ( +// root.left.expect("Root should always have left child"), +// root.right.expect("Root should always have right child"), +// ) +// }; +// +// let nested_append = self.append_leaf(root_right_child, new_leaf); +// let appended = nested_append.appended; +// let subtree_root = nested_append.new_root; +// +// let new_root_node = combine_nodes( +// self.resolve_link(root_left_child), +// self.resolve_link(subtree_root), +// ); +// +// (new_root_node, appended) + + let new_leaf_link = self.push(new_leaf.into()); + let mut appended = Vec::new(); + appended.push(new_leaf_link); + + let mut peaks = self.get_peaks(root); + + let mut merge_stack = Vec::new(); + merge_stack.push(new_leaf_link); + + while let Some(next_peak) = peaks.pop() { + dbg!(next_peak); + let next_merge = merge_stack.pop().expect("there should be at least one, checked below"); + + if let Some(stored) = { + let peak = self.resolve_link(next_peak); + let m = self.resolve_link(next_merge); + if peak.node.leaf_count() == m.node.leaf_count() { + Some(combine_nodes(peak, m)) + } else { None } + } { + let link = self.push(stored); + merge_stack.push(link); + appended.push(link); + dbg!(link); + continue; + } + merge_stack.push(next_merge); + merge_stack.push(next_peak); + } + + let mut root = merge_stack.pop().expect("There should be at least one node in stack"); + while let Some(next_child) = merge_stack.pop() { + root = self.push_generated( + combine_nodes( + self.resolve_link(root), + self.resolve_link(next_child), + ) ) - }; + } - let nested_append = self.append_leaf(root_right_child, new_leaf); - let appended = nested_append.appended; - let subtree_root = nested_append.new_root; - - let new_root_node = combine_nodes( - self.resolve_link(root_left_child), - self.resolve_link(subtree_root), - ); - - (new_root_node, appended) + (root, appended) }; - let new_root = if new_root_node.complete() { - let new_root= self.push(new_root_node); - appended.push(new_root); - new_root - } else { - self.push_generated(new_root_node) - }; +// let new_root = if new_root_node.complete() { +// let new_root= self.push(new_root_node); +// appended.push(new_root); +// new_root +// } else { +// self.push_generated(new_root_node) +// }; AppendTransaction { new_root, @@ -448,7 +490,7 @@ mod tests { }); // *** APPEND #6 *** - + dbg!("go"); let append_tx = tree.append_leaf(new_root_link, leaf(6)); let new_root_link = append_tx.new_root; let new_root = tree.resolve_link(new_root_link).node; @@ -620,5 +662,18 @@ mod tests { TestResult::from_bool(if let NodeLink::Stored(2) = root { true } else { false }) } } + + fn leaf_count(number: u32) -> TestResult { + if (number > 1024 * 1024 || number < 3) { + TestResult::discard() + } else { + let (mut root, mut tree) = initial(); + for i in 0..(number-2) { + root = tree.append_leaf(root, leaf(i+3)).new_root; + } + + TestResult::from_bool(tree.resolve_link(root).node.leaf_count() == number) + } + } } } \ No newline at end of file From 68983dc0c1a1322cedca50ba63f5f5821a1634b0 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 2 Sep 2019 15:28:51 +0300 Subject: [PATCH 135/330] extra tests and notes --- src/tree.rs | 122 +++++++++++++++++----------------------------------- 1 file changed, 39 insertions(+), 83 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index c26696b..c3e0bed 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -110,8 +110,12 @@ impl Tree { } fn get_peaks(&self, root: NodeLink) -> Vec { + let (left_child_link, right_child_link) = { let root = self.resolve_link(root); + if root.node.complete() { + return vec![root.link]; + } ( root.node.left.expect("It would stop before when root is leaf"), root.node.right.expect("It would stop before when root is leaf"), @@ -139,91 +143,44 @@ impl Tree { /// Append one leaf to the tree. pub fn append_leaf(&mut self, root: NodeLink, new_leaf: NodeData) -> AppendTransaction { - let is_complete= self.resolve_link(root).node.complete(); + let new_leaf_link = self.push(new_leaf.into()); + let mut appended = Vec::new(); + appended.push(new_leaf_link); - let (new_root, mut appended) = if is_complete { - let new_leaf_link = self.push(new_leaf.into()); + let mut peaks = self.get_peaks(root); - let mut appended = Vec::new(); - appended.push(new_leaf_link); + let mut merge_stack = Vec::new(); + merge_stack.push(new_leaf_link); - // since we dethrone stored root, new one is always generated - let new_root_node = combine_nodes( - self.resolve_link(root), - self.resolve_link(new_leaf_link), - ); + while let Some(next_peak) = peaks.pop() { + let next_merge = merge_stack.pop().expect("there should be at least one, checked below"); - (self.push_generated(new_root_node), appended) - } else { -// let (root_left_child, root_right_child) = { -// let root = self.resolve_link(root).node; -// ( -// root.left.expect("Root should always have left child"), -// root.right.expect("Root should always have right child"), -// ) -// }; -// -// let nested_append = self.append_leaf(root_right_child, new_leaf); -// let appended = nested_append.appended; -// let subtree_root = nested_append.new_root; -// -// let new_root_node = combine_nodes( -// self.resolve_link(root_left_child), -// self.resolve_link(subtree_root), -// ); -// -// (new_root_node, appended) - - let new_leaf_link = self.push(new_leaf.into()); - let mut appended = Vec::new(); - appended.push(new_leaf_link); - - let mut peaks = self.get_peaks(root); - - let mut merge_stack = Vec::new(); - merge_stack.push(new_leaf_link); - - while let Some(next_peak) = peaks.pop() { - dbg!(next_peak); - let next_merge = merge_stack.pop().expect("there should be at least one, checked below"); - - if let Some(stored) = { - let peak = self.resolve_link(next_peak); - let m = self.resolve_link(next_merge); - if peak.node.leaf_count() == m.node.leaf_count() { - Some(combine_nodes(peak, m)) - } else { None } - } { - let link = self.push(stored); - merge_stack.push(link); - appended.push(link); - dbg!(link); - continue; - } - merge_stack.push(next_merge); - merge_stack.push(next_peak); + if let Some(stored) = { + let peak = self.resolve_link(next_peak); + let m = self.resolve_link(next_merge); + if peak.node.leaf_count() == m.node.leaf_count() { + Some(combine_nodes(peak, m)) + } else { None } + } { + let link = self.push(stored); + merge_stack.push(link); + appended.push(link); + continue; } + merge_stack.push(next_merge); + merge_stack.push(next_peak); + } - let mut root = merge_stack.pop().expect("There should be at least one node in stack"); - while let Some(next_child) = merge_stack.pop() { - root = self.push_generated( - combine_nodes( - self.resolve_link(root), - self.resolve_link(next_child), - ) + let mut new_root = merge_stack.pop().expect("There should be at least one node in stack"); + while let Some(next_child) = merge_stack.pop() { + new_root = self.push_generated( + combine_nodes( + self.resolve_link(new_root), + self.resolve_link(next_child), ) - } + ) + } - (root, appended) - }; - -// let new_root = if new_root_node.complete() { -// let new_root= self.push(new_root_node); -// appended.push(new_root); -// new_root -// } else { -// self.push_generated(new_root_node) -// }; AppendTransaction { new_root, @@ -490,7 +447,6 @@ mod tests { }); // *** APPEND #6 *** - dbg!("go"); let append_tx = tree.append_leaf(new_root_link, leaf(6)); let new_root_link = append_tx.new_root; let new_root = tree.resolve_link(new_root_link).node; @@ -648,14 +604,14 @@ mod tests { quickcheck! { fn there_and_back(number: u32) -> TestResult { - if (number > 1024*1024) { + if number > 1024*1024 { TestResult::discard() } else { let (mut root, mut tree) = initial(); for i in 0..number { root = tree.append_leaf(root, leaf(i+3)).new_root; } - for i in 0..number { + for _ in 0..number { root = tree.truncate_leaf(root).new_root; } @@ -664,12 +620,12 @@ mod tests { } fn leaf_count(number: u32) -> TestResult { - if (number > 1024 * 1024 || number < 3) { + if number > 1024 * 1024 || number < 3 { TestResult::discard() } else { let (mut root, mut tree) = initial(); - for i in 0..(number-2) { - root = tree.append_leaf(root, leaf(i+3)).new_root; + for i in 1..(number-1) { + root = tree.append_leaf(root, leaf(i+2)).new_root; } TestResult::from_bool(tree.resolve_link(root).node.leaf_count() == number) From 4c49f09515308b5794e1a1bebbf08a0210c625f9 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 2 Sep 2019 18:05:20 +0300 Subject: [PATCH 136/330] extra quick-checks and fixes for deleting from full root --- src/tree.rs | 105 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 94 insertions(+), 11 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index c3e0bed..008a19a 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -153,7 +153,7 @@ impl Tree { merge_stack.push(new_leaf_link); while let Some(next_peak) = peaks.pop() { - let next_merge = merge_stack.pop().expect("there should be at least one, checked below"); + let next_merge = merge_stack.pop().expect("there should be at least one, initial or re-pushed"); if let Some(stored) = { let peak = self.resolve_link(next_peak); @@ -171,7 +171,7 @@ impl Tree { merge_stack.push(next_peak); } - let mut new_root = merge_stack.pop().expect("There should be at least one node in stack"); + let mut new_root = merge_stack.pop().expect("Loop above cannot reduce the merge_stack"); while let Some(next_child) = merge_stack.pop() { new_root = self.push_generated( combine_nodes( @@ -211,7 +211,7 @@ impl Tree { let (leaves, root_left_child) = { let n = self.resolve_link(root); ( - n.node.data.end_height - n.node.data.start_height + 1, + n.node.leaf_count(), n.node.left.expect("Root should have left child while deleting") ) }; @@ -239,21 +239,21 @@ impl Tree { .expect("If left exists, right should exist as well"); truncated += 1; } else { + if root.node.complete() { truncated += 1; } break; } } - let root = peaks.drain(0..1).nth(0).expect("At lest 2 elements in peaks"); - let new_root = peaks.into_iter().fold( - root, - |root, next_peak| - self.push_generated( + let mut new_root = peaks.drain(0..1).nth(0).expect("At lest 2 elements in peaks"); + + for next_peak in peaks.into_iter() { + new_root = self.push_generated( combine_nodes( - self.resolve_link(root), + self.resolve_link(new_root), self.resolve_link(next_peak) ) - ) - ); + ); + } for _ in 0..truncated { self.pop(); } @@ -601,6 +601,22 @@ mod tests { assert_eq!(tree.len(), 16); } + #[test] + fn tree_len() { + let (mut root, mut tree) = initial(); + + assert_eq!(tree.len(), 3); + + for i in 0..2 { + root = tree.append_leaf(root, leaf(i+3)).new_root; + } + assert_eq!(tree.len(), 7); + + root = tree.truncate_leaf(root).new_root; + + assert_eq!(tree.len(), 4); + } + quickcheck! { fn there_and_back(number: u32) -> TestResult { @@ -631,5 +647,72 @@ mod tests { TestResult::from_bool(tree.resolve_link(root).node.leaf_count() == number) } } + + fn parity(number: u32) -> TestResult { + if number > 2048 * 2048 || number < 3 { + TestResult::discard() + } else { + let (mut root, mut tree) = initial(); + for i in 1..(number-1) { + root = tree.append_leaf(root, leaf(i+2)).new_root; + } + + TestResult::from_bool( + if number & number - 1 == 0 { + if let NodeLink::Stored(_) = root { true } + else { false } + } else { + if let NodeLink::Generated(_) = root { true } + else { false } + } + ) + } + } + + fn parity_with_truncate(add: u32, delete: u32) -> TestResult { + // First we add `add` number of leaves, then delete `delete` number of leaves + // What is left should be consistent with generated-stored structure + if add > 2048 * 2048 || add < delete { + TestResult::discard() + } else { + let (mut root, mut tree) = initial(); + for i in 0..add { + root = tree.append_leaf(root, leaf(i+3)).new_root; + } + for _ in 0..delete { + root = tree.truncate_leaf(root).new_root; + } + + let total = add - delete + 2; + + TestResult::from_bool( + if total & total - 1 == 0 { + if let NodeLink::Stored(_) = root { true } + else { false } + } else { + if let NodeLink::Generated(_) = root { true } + else { false } + } + ) + } + } + + fn stored_length(add: u32, delete: u32) -> TestResult { + if add > 2048 * 2048 || add < delete { + TestResult::discard() + } else { + let (mut root, mut tree) = initial(); + for i in 0..add { + root = tree.append_leaf(root, leaf(i+3)).new_root; + } + for _ in 0..delete { + root = tree.truncate_leaf(root).new_root; + } + + let total = add - delete + 2; + + TestResult::from_bool(total * total > tree.len()) + } + } } } \ No newline at end of file From d58b33fb78a2ca7d5435a9c83d41585f4c47ddb2 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 2 Sep 2019 18:18:33 +0300 Subject: [PATCH 137/330] simplify and optimize get_peaks --- src/tree.rs | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index 008a19a..22abd36 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -109,12 +109,13 @@ impl Tree { result } - fn get_peaks(&self, root: NodeLink) -> Vec { + fn get_peaks(&self, root: NodeLink, target: &mut Vec) { let (left_child_link, right_child_link) = { let root = self.resolve_link(root); if root.node.complete() { - return vec![root.link]; + target.push(root.link); + return; } ( root.node.left.expect("It would stop before when root is leaf"), @@ -122,23 +123,8 @@ impl Tree { ) }; - let mut result = Vec::new(); - - let left_child = self.resolve_link(left_child_link); - if left_child.node.complete() { - result.push(left_child_link); - } else { - result.extend(self.get_peaks(left_child_link)); - } - - let right_child = self.resolve_link(right_child_link); - if right_child.node.complete() { - result.push(right_child_link); - } else { - result.extend(self.get_peaks(right_child_link)); - } - - result + self.get_peaks(left_child_link, target); + self.get_peaks(right_child_link, target); } /// Append one leaf to the tree. @@ -147,7 +133,8 @@ impl Tree { let mut appended = Vec::new(); appended.push(new_leaf_link); - let mut peaks = self.get_peaks(root); + let mut peaks = Vec::new(); + self.get_peaks(root, &mut peaks); let mut merge_stack = Vec::new(); merge_stack.push(new_leaf_link); @@ -181,7 +168,6 @@ impl Tree { ) } - AppendTransaction { new_root, appended, @@ -612,7 +598,7 @@ mod tests { } assert_eq!(tree.len(), 7); - root = tree.truncate_leaf(root).new_root; + tree.truncate_leaf(root); assert_eq!(tree.len(), 4); } From 49f20e67359cbfd5680b4da193d325df05c64c27 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 2 Sep 2019 18:26:51 +0300 Subject: [PATCH 138/330] extra long truncate --- src/tree.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/tree.rs b/src/tree.rs index 22abd36..1dd7b81 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -603,6 +603,24 @@ mod tests { assert_eq!(tree.len(), 4); } + #[test] + fn tree_len_long() { + let (mut root, mut tree) = initial(); + + assert_eq!(tree.len(), 3); + + for i in 0..4094 { + root = tree.append_leaf(root, leaf(i+3)).new_root; + } + assert_eq!(tree.len(), 8191); // 4096*2-1 (full tree) + + for _ in 0..2049 { + root = tree.truncate_leaf(root).new_root; + } + + assert_eq!(tree.len(), 4083); // 4095 - log2(4096) + } + quickcheck! { fn there_and_back(number: u32) -> TestResult { From 615c4f662e42544e3624d37030b29643e20f5454 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 2 Sep 2019 19:51:00 +0300 Subject: [PATCH 139/330] refactor to rust-only structures --- bindings.h | 59 ---------- src/lib.rs | 72 ++++++++----- src/tree.rs | 303 ++++++++++++++++++++++++++++++---------------------- 3 files changed, 225 insertions(+), 209 deletions(-) delete mode 100644 bindings.h diff --git a/bindings.h b/bindings.h deleted file mode 100644 index fca8fa6..0000000 --- a/bindings.h +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include -#include -#include - -template -struct Option; - -struct NodeLink { - enum class Tag { - Stored, - Generated, - }; - - struct Stored_Body { - uint32_t _0; - }; - - struct Generated_Body { - uint32_t _0; - }; - - Tag tag; - union { - Stored_Body stored; - Generated_Body generated; - }; -}; - -struct NodeData { - uint8_t subtree_commitment[32]; - uint32_t start_time; - uint32_t end_time; - uint32_t start_target; - uint32_t end_target; - uint8_t start_sapling_root[32]; - uint8_t end_sapling_root[32]; - uint64_t subtree_total_work; - uint32_t start_height; - uint32_t end_height; - uint64_t shielded_tx; -}; - -struct MMRNode { - Option left; - Option right; - NodeData data; -}; - -extern "C" { - -void append(const MMRNode *_stored, - uint32_t _stored_count, - const MMRNode *_generated, - uint32_t _generated_count, - uint32_t *_append_count, - MMRNode *_append_buffer); - -} // extern "C" diff --git a/src/lib.rs b/src/lib.rs index e55c308..f6c555b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,10 +26,16 @@ pub struct NodeData { shielded_tx: u64, } +#[derive(Debug)] +pub enum Error { + ExpectedInMemory(EntryLink), + ExpectedNode(Option), +} + /// Reference to to the tree node. #[repr(C)] #[derive(Clone, Copy, Debug)] -pub enum NodeLink { +pub enum EntryLink { /// Reference to the stored (in the array representation) leaf/node. Stored(u32), /// Reference to the generated leaf/node. @@ -39,41 +45,57 @@ pub enum NodeLink { /// MMR Node. It is leaf when `left`, `right` are `None` and node when they are not. #[repr(C)] #[derive(Debug)] -// TODO: Better layout would be enum (node, leaf), with left, right set only for nodes? -pub struct MMRNode { - left: Option, - right: Option, +pub enum EntryKind { + Leaf, + Node(EntryLink, EntryLink), +} + +pub struct Entry { + kind: EntryKind, data: NodeData, } -impl MMRNode { - fn complete(&self) -> bool { +impl Entry { + pub fn complete(&self) -> bool { let leaves = self.leaf_count(); leaves & (leaves - 1) == 0 } - fn leaf_count(&self) -> u32 { + pub fn leaf_count(&self) -> u32 { self.data.end_height - self.data.start_height + 1 } -} -impl From for MMRNode { - fn from(s: NodeData) -> Self { - MMRNode { left: None, right: None, data: s } + pub fn is_leaf(&self) -> bool { + if let EntryKind::Leaf = self.kind { true } else { false } + } + + pub fn left(&self) -> Result { + match self.kind { + EntryKind::Leaf => { Err(Error::ExpectedNode(None)) } + EntryKind::Node(left, _) => Ok(left) + } + } + + pub fn right(&self) -> Result { + match self.kind { + EntryKind::Leaf => { Err(Error::ExpectedNode(None)) } + EntryKind::Node(_, right) => Ok(right) + } } } -#[no_mangle] -pub extern fn append( - _stored: *const MMRNode, - _stored_count: u32, - _generated: *const MMRNode, - _generated_count: u32, - _append_count: *mut u32, - _append_buffer: *mut MMRNode, -) { - - // TODO: construct tree and write to (append_count, append_buffer) - // TODO: also return generated?? - unimplemented!() +impl From for Entry { + fn from(s: NodeData) -> Self { + Entry { kind: EntryKind::Leaf, data: s } + } } + +impl Error { + pub (crate) fn augment(self, link: EntryLink) -> Self { + match self { + Error::ExpectedNode(None) => Error::ExpectedNode(Some(link)), + val => val + } + } +} + diff --git a/src/tree.rs b/src/tree.rs index 1dd7b81..2faebb6 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::{MMRNode, NodeLink, NodeData}; +use crate::{Entry, EntryLink, NodeData, Error, EntryKind}; /// Represents partially loaded tree. /// @@ -11,9 +11,9 @@ use crate::{MMRNode, NodeLink, NodeData}; /// to happen after construction. #[derive(Default)] pub struct Tree { - stored: HashMap, + stored: HashMap, - generated: HashMap, + generated: HashMap, // number of persistent(!) tree entries stored_count: u32, @@ -26,10 +26,10 @@ pub struct Tree { pub struct AppendTransaction { /// Plain list of nodes that has to be appended to the end of the array representation /// of the tree as the result of append operation. - pub appended: Vec, + pub appended: Vec, /// New root as a result of the operation (can be generated one). - pub new_root: NodeLink, + pub new_root: EntryLink, } /// Result of truncating one or severl leaves. @@ -37,48 +37,48 @@ pub struct DeleteTransaction { /// Number of leaves that should be dropped from the end of the list. pub truncated: u32, /// New root as the result of the operation (can be generated one). - pub new_root: NodeLink, + pub new_root: EntryLink, } impl Tree { - fn resolve_link(&self, link: NodeLink) -> IndexedNode { + fn resolve_link(&self, link: EntryLink) -> Result { match link { - NodeLink::Generated(index) => { + EntryLink::Generated(index) => { // TODO: maybe graceful error? - let node = self.generated.get(&index).expect("caller should ensure id generated"); - IndexedNode { + let node = self.generated.get(&index).ok_or(Error::ExpectedInMemory(link))?; + Ok(IndexedNode { node, link, - } + }) }, - NodeLink::Stored(index) => { + EntryLink::Stored(index) => { // TODO: maybe graceful error? - let node = self.stored.get(&index).expect("caller should ensure id stored"); - IndexedNode { + let node = self.stored.get(&index).ok_or(Error::ExpectedInMemory(link))?; + Ok(IndexedNode { node, link, - } + }) }, } } - fn push(&mut self, data: MMRNode) -> NodeLink { + fn push(&mut self, data: Entry) -> EntryLink { let idx = self.stored_count; self.stored_count = self.stored_count + 1; self.stored.insert(idx, data); - NodeLink::Stored(idx) + EntryLink::Stored(idx) } - fn push_generated(&mut self, data: MMRNode) -> NodeLink { + fn push_generated(&mut self, data: Entry) -> EntryLink { let idx = self.generated_count; self.generated_count = self.generated_count + 1; self.generated.insert(idx, data); - NodeLink::Generated(idx) + EntryLink::Generated(idx) } /// Populate tree with plain list of the leaves/nodes. Mostly for tests, /// since this `Tree` structure is for partially loaded tree. - pub fn populate(loaded: Vec) -> Self { + pub fn populate(loaded: Vec) -> Self { let mut result = Tree::default(); result.stored_count = loaded.len() as u32; for (idx, item) in loaded.into_iter().enumerate() { @@ -90,8 +90,8 @@ impl Tree { pub fn new( length: u32, - stored: Vec<(u32, MMRNode)>, - generated: Vec, + stored: Vec<(u32, Entry)>, + generated: Vec, ) -> Self { let mut result = Tree::default(); result.stored_count = length; @@ -109,32 +109,33 @@ impl Tree { result } - fn get_peaks(&self, root: NodeLink, target: &mut Vec) { + fn get_peaks(&self, root: EntryLink, target: &mut Vec) -> Result<(), Error> { let (left_child_link, right_child_link) = { - let root = self.resolve_link(root); + let root = self.resolve_link(root)?; if root.node.complete() { target.push(root.link); - return; + return Ok(()); } ( - root.node.left.expect("It would stop before when root is leaf"), - root.node.right.expect("It would stop before when root is leaf"), + root.left()?, + root.right()?, ) }; - self.get_peaks(left_child_link, target); - self.get_peaks(right_child_link, target); + self.get_peaks(left_child_link, target)?; + self.get_peaks(right_child_link, target)?; + Ok(()) } /// Append one leaf to the tree. - pub fn append_leaf(&mut self, root: NodeLink, new_leaf: NodeData) -> AppendTransaction { + pub fn append_leaf(&mut self, root: EntryLink, new_leaf: NodeData) -> Result { let new_leaf_link = self.push(new_leaf.into()); let mut appended = Vec::new(); appended.push(new_leaf_link); let mut peaks = Vec::new(); - self.get_peaks(root, &mut peaks); + self.get_peaks(root, &mut peaks)?; let mut merge_stack = Vec::new(); merge_stack.push(new_leaf_link); @@ -143,8 +144,8 @@ impl Tree { let next_merge = merge_stack.pop().expect("there should be at least one, initial or re-pushed"); if let Some(stored) = { - let peak = self.resolve_link(next_peak); - let m = self.resolve_link(next_merge); + let peak = self.resolve_link(next_peak)?; + let m = self.resolve_link(next_merge)?; if peak.node.leaf_count() == m.node.leaf_count() { Some(combine_nodes(peak, m)) } else { None } @@ -162,28 +163,28 @@ impl Tree { while let Some(next_child) = merge_stack.pop() { new_root = self.push_generated( combine_nodes( - self.resolve_link(new_root), - self.resolve_link(next_child), + self.resolve_link(new_root)?, + self.resolve_link(next_child)?, ) ) } - AppendTransaction { + Ok(AppendTransaction { new_root, appended, - } + }) } #[cfg(test)] - fn for_children(&mut self, node: NodeLink, mut f: F) { + fn for_children(&mut self, node: EntryLink, mut f: F) { let (left, right) = { - let link = self.resolve_link(node); + let link = self.resolve_link(node).expect("Failed to resolve link in test"); ( - link.node.left.expect("test use only (l)"), - link.node.right.expect("test use only (r)"), + link.left().expect("Failed to find node in test"), + link.right().expect("Failed to find node in test"), ) }; - f(left, right) + f(left, right); } fn pop(&mut self) { @@ -192,37 +193,35 @@ impl Tree { } /// Truncate one leaf from the end of the tree. - pub fn truncate_leaf(&mut self, root: NodeLink) -> DeleteTransaction { + pub fn truncate_leaf(&mut self, root: EntryLink) -> Result { let root = { let (leaves, root_left_child) = { - let n = self.resolve_link(root); + let n = self.resolve_link(root)?; ( n.node.leaf_count(), - n.node.left.expect("Root should have left child while deleting") + n.node.left()?, ) }; if leaves & 1 != 0 { self.pop(); - return DeleteTransaction { + return Ok(DeleteTransaction { truncated: 1, new_root: root_left_child, - } + }) } else { - self.resolve_link(root) + self.resolve_link(root)? } }; - let mut peaks = vec![root.node.left.expect("Root should have left child")]; - let mut subtree_root_link = root.node.right.expect("Root should have right child"); + let mut peaks = vec![root.left()?]; + let mut subtree_root_link = root.right()?; let mut truncated = 1; loop { - let left_link = self.resolve_link(subtree_root_link).node.left; - if let Some(left_link) = left_link { - peaks.push(left_link); - subtree_root_link = self - .resolve_link(subtree_root_link).node.right - .expect("If left exists, right should exist as well"); + let left_link = self.resolve_link(subtree_root_link)?.node; + if let EntryKind::Node(left, right) = left_link.kind { + peaks.push(left); + subtree_root_link = right; truncated += 1; } else { if root.node.complete() { truncated += 1; } @@ -234,19 +233,19 @@ impl Tree { for next_peak in peaks.into_iter() { new_root = self.push_generated( - combine_nodes( - self.resolve_link(new_root), - self.resolve_link(next_peak) - ) - ); + combine_nodes( + self.resolve_link(new_root)?, + self.resolve_link(next_peak)?, + ) + ); } for _ in 0..truncated { self.pop(); } - DeleteTransaction { + Ok(DeleteTransaction { new_root, truncated, - } + }) } /// Length of array representation of the tree. @@ -257,8 +256,20 @@ impl Tree { struct IndexedNode<'a> { - node: &'a MMRNode, - link: NodeLink, + node: &'a Entry, + link: EntryLink, +} + +impl<'a> IndexedNode<'a> { + + fn left(&self) -> Result { + self.node.left().map_err(|e| e.augment(self.link)) + } + + fn right(&self) -> Result { + self.node.right().map_err(|e| e.augment(self.link)) + } + } fn combine_data(left: &NodeData, right: &NodeData) -> NodeData { @@ -280,10 +291,9 @@ fn combine_data(left: &NodeData, right: &NodeData) -> NodeData { } } -fn combine_nodes<'a>(left: IndexedNode<'a>, right: IndexedNode<'a>) -> MMRNode { - MMRNode { - left: Some(left.link), - right: Some(right.link), +fn combine_nodes<'a>(left: IndexedNode<'a>, right: IndexedNode<'a>) -> Entry { + Entry { + kind: EntryKind::Node(left.link, right.link), data: combine_data(&left.node.data, &right.node.data), } } @@ -291,7 +301,7 @@ fn combine_nodes<'a>(left: IndexedNode<'a>, right: IndexedNode<'a>) -> MMRNode { #[cfg(test)] mod tests { - use super::{MMRNode, NodeData, Tree, NodeLink}; + use super::{Entry, NodeData, Tree, EntryLink, EntryKind}; use quickcheck::TestResult; fn leaf(height: u32) -> NodeData { @@ -326,25 +336,27 @@ mod tests { } } - fn initial() -> (NodeLink, Tree) { - let node1: MMRNode = leaf(1).into(); - let node2: MMRNode = leaf(2).into(); + fn initial() -> (EntryLink, Tree) { + let node1: Entry = leaf(1).into(); + let node2: Entry = leaf(2).into(); - let node3 = MMRNode { + let node3 = Entry { data: node(1, 2), - left: Some(NodeLink::Stored(0)), - right: Some(NodeLink::Stored(1)), + kind: EntryKind::Leaf, }; - (NodeLink::Stored(2), Tree::populate(vec![node1, node2, node3])) + (EntryLink::Stored(2), Tree::populate(vec![node1, node2, node3])) } // returns tree with specified number of leafs and it's root - fn generated(length: u32) -> (Tree, NodeLink) { + fn generated(length: u32) -> (Tree, EntryLink) { assert!(length >= 3); let (mut root, mut tree) = initial(); for i in 2..length { - root = tree.append_leaf(root, leaf(i+1).into()).new_root; + root = tree + .append_leaf(root, leaf(i+1).into()) + .expect("Failed to append") + .new_root; } (tree, root) @@ -355,9 +367,11 @@ mod tests { let (root, mut tree) = initial(); // ** APPEND 3 ** - let append_tx = tree.append_leaf(root, leaf(3)); + let append_tx = tree + .append_leaf(root, leaf(3)) + .expect("Failed to append"); let new_root_link = append_tx.new_root; - let new_root = tree.resolve_link(new_root_link).node; + let new_root = tree.resolve_link(new_root_link).expect("Failed to resolve root").node; // initial tree: (2) // / \ @@ -376,9 +390,12 @@ mod tests { assert_eq!(append_tx.appended.len(), 1); // ** APPEND 4 ** - let append_tx = tree.append_leaf(new_root_link, leaf(4)); + let append_tx = tree + .append_leaf(new_root_link, leaf(4)) + .expect("Failed to append"); + let new_root_link = append_tx.new_root; - let new_root = tree.resolve_link(new_root_link).node; + let new_root = tree.resolve_link(new_root_link).expect("Failed to resolve root").node; // intermediate tree: // (4g) @@ -398,13 +415,15 @@ mod tests { // and new root, (6) is stored one assert_eq!(new_root.data.end_height, 4); assert_eq!(append_tx.appended.len(), 3); - assert_matches!(new_root_link, NodeLink::Stored(6)); + assert_matches!(new_root_link, EntryLink::Stored(6)); // ** APPEND 5 ** - let append_tx = tree.append_leaf(new_root_link, leaf(5)); + let append_tx = tree + .append_leaf(new_root_link, leaf(5)) + .expect("Failed to append"); let new_root_link = append_tx.new_root; - let new_root = tree.resolve_link(new_root_link).node; + let new_root = tree.resolve_link(new_root_link).expect("Failed to resolve root").node; // intermediate tree: // ( 6 ) @@ -426,16 +445,18 @@ mod tests { // and new root, (8g) is generated one assert_eq!(new_root.data.end_height, 5); assert_eq!(append_tx.appended.len(), 1); - assert_matches!(new_root_link, NodeLink::Generated(_)); + assert_matches!(new_root_link, EntryLink::Generated(_)); tree.for_children(new_root_link, |l, r| { - assert_matches!(l, NodeLink::Stored(6)); - assert_matches!(r, NodeLink::Stored(7)); + assert_matches!(l, EntryLink::Stored(6)); + assert_matches!(r, EntryLink::Stored(7)); }); // *** APPEND #6 *** - let append_tx = tree.append_leaf(new_root_link, leaf(6)); + let append_tx = tree + .append_leaf(new_root_link, leaf(6)) + .expect("Failed to append"); let new_root_link = append_tx.new_root; - let new_root = tree.resolve_link(new_root_link).node; + let new_root = tree.resolve_link(new_root_link).expect("Failed to resolve root").node; // intermediate tree: // ( 8g ) @@ -459,17 +480,22 @@ mod tests { // and new root, (8g) is generated one assert_eq!(new_root.data.end_height, 6); assert_eq!(append_tx.appended.len(), 2); - assert_matches!(new_root_link, NodeLink::Generated(_)); + assert_matches!(new_root_link, EntryLink::Generated(_)); tree.for_children(new_root_link, |l, r| { - assert_matches!(l, NodeLink::Stored(6)); - assert_matches!(r, NodeLink::Stored(9)); + assert_matches!(l, EntryLink::Stored(6)); + assert_matches!(r, EntryLink::Stored(9)); }); // *** APPEND #7 *** - let append_tx = tree.append_leaf(new_root_link, leaf(7)); + let append_tx = tree + .append_leaf(new_root_link, leaf(7)) + .expect("Failed to append"); let new_root_link = append_tx.new_root; - let new_root = tree.resolve_link(new_root_link).node; + let new_root = tree + .resolve_link(new_root_link) + .expect("Failed to resolve root") + .node; // intermediate tree: // (---8g---) @@ -495,17 +521,19 @@ mod tests { // and new root, (8g) is generated one assert_eq!(new_root.data.end_height, 7); assert_eq!(append_tx.appended.len(), 1); - assert_matches!(new_root_link, NodeLink::Generated(_)); + assert_matches!(new_root_link, EntryLink::Generated(_)); tree.for_children(new_root_link, |l, r| { - assert_matches!(l, NodeLink::Generated(_)); - assert_matches!(r, NodeLink::Stored(10)); + assert_matches!(l, EntryLink::Generated(_)); + assert_matches!(r, EntryLink::Stored(10)); }); } #[test] fn truncate_simple() { let (mut tree, root) = generated(9); - let delete_tx = tree.truncate_leaf(root); + let delete_tx = tree + .truncate_leaf(root) + .expect("Failed to truncate"); // initial tree: // @@ -531,14 +559,16 @@ mod tests { // so (15) is truncated // and new root, (14) is a stored one now - assert_matches!(delete_tx.new_root, NodeLink::Stored(14)); + assert_matches!(delete_tx.new_root, EntryLink::Stored(14)); assert_eq!(tree.len(), 15); } #[test] fn truncate_generated() { let (mut tree, root) = generated(10); - let delete_tx = tree.truncate_leaf(root); + let delete_tx = tree + .truncate_leaf(root) + .expect("Failed to truncate"); // initial tree: // @@ -565,21 +595,21 @@ mod tests { // new root is generated - assert_matches!(delete_tx.new_root, NodeLink::Generated(_)); + assert_matches!(delete_tx.new_root, EntryLink::Generated(_)); // left is 14 and right is 15 let (left_root_child, right_root_child) = { - let root = tree.resolve_link(delete_tx.new_root); + let root = tree.resolve_link(delete_tx.new_root).expect("Failed to resolve"); ( - root.node.left.expect("there should be left child for root"), - root.node.right.expect("there should be right child for root"), + root.left().expect("Expected node"), + root.right().expect("Expected node"), ) }; assert_matches!( (left_root_child, right_root_child), - (NodeLink::Stored(14), NodeLink::Stored(15)) + (EntryLink::Stored(14), EntryLink::Stored(15)) ); // two stored nodes should leave us (leaf 16 and no longer needed node 17) @@ -594,11 +624,14 @@ mod tests { assert_eq!(tree.len(), 3); for i in 0..2 { - root = tree.append_leaf(root, leaf(i+3)).new_root; + root = tree + .append_leaf(root, leaf(i+3)) + .expect("Failed to append") + .new_root; } assert_eq!(tree.len(), 7); - tree.truncate_leaf(root); + tree.truncate_leaf(root).expect("Failed to truncate"); assert_eq!(tree.len(), 4); } @@ -610,12 +643,18 @@ mod tests { assert_eq!(tree.len(), 3); for i in 0..4094 { - root = tree.append_leaf(root, leaf(i+3)).new_root; + root = tree + .append_leaf(root, leaf(i+3)) + .expect("Failed to append") + .new_root; } assert_eq!(tree.len(), 8191); // 4096*2-1 (full tree) for _ in 0..2049 { - root = tree.truncate_leaf(root).new_root; + root = tree + .truncate_leaf(root) + .expect("Failed to truncate") + .new_root; } assert_eq!(tree.len(), 4083); // 4095 - log2(4096) @@ -629,13 +668,16 @@ mod tests { } else { let (mut root, mut tree) = initial(); for i in 0..number { - root = tree.append_leaf(root, leaf(i+3)).new_root; + root = tree + .append_leaf(root, leaf(i+3)) + .expect("Failed to append") + .new_root; } for _ in 0..number { - root = tree.truncate_leaf(root).new_root; + root = tree.truncate_leaf(root).expect("Failed to truncate").new_root; } - TestResult::from_bool(if let NodeLink::Stored(2) = root { true } else { false }) + TestResult::from_bool(if let EntryLink::Stored(2) = root { true } else { false }) } } @@ -645,10 +687,21 @@ mod tests { } else { let (mut root, mut tree) = initial(); for i in 1..(number-1) { - root = tree.append_leaf(root, leaf(i+2)).new_root; + root = tree + .append_leaf(root, leaf(i+2)) + .expect("Failed to append") + .new_root; } - TestResult::from_bool(tree.resolve_link(root).node.leaf_count() == number) + TestResult::from_bool( + tree + .resolve_link(root) + .expect("Failed to resolve root") + .node + .leaf_count() + == + number + ) } } @@ -658,15 +711,15 @@ mod tests { } else { let (mut root, mut tree) = initial(); for i in 1..(number-1) { - root = tree.append_leaf(root, leaf(i+2)).new_root; + root = tree.append_leaf(root, leaf(i+2)).expect("Failed to append").new_root; } TestResult::from_bool( if number & number - 1 == 0 { - if let NodeLink::Stored(_) = root { true } + if let EntryLink::Stored(_) = root { true } else { false } } else { - if let NodeLink::Generated(_) = root { true } + if let EntryLink::Generated(_) = root { true } else { false } } ) @@ -681,20 +734,20 @@ mod tests { } else { let (mut root, mut tree) = initial(); for i in 0..add { - root = tree.append_leaf(root, leaf(i+3)).new_root; + root = tree.append_leaf(root, leaf(i+3)).expect("Failed to append").new_root; } for _ in 0..delete { - root = tree.truncate_leaf(root).new_root; + root = tree.truncate_leaf(root).expect("Failed to truncate").new_root; } let total = add - delete + 2; TestResult::from_bool( if total & total - 1 == 0 { - if let NodeLink::Stored(_) = root { true } + if let EntryLink::Stored(_) = root { true } else { false } } else { - if let NodeLink::Generated(_) = root { true } + if let EntryLink::Generated(_) = root { true } else { false } } ) @@ -707,10 +760,10 @@ mod tests { } else { let (mut root, mut tree) = initial(); for i in 0..add { - root = tree.append_leaf(root, leaf(i+3)).new_root; + root = tree.append_leaf(root, leaf(i+3)).expect("Failed to append").new_root; } for _ in 0..delete { - root = tree.truncate_leaf(root).new_root; + root = tree.truncate_leaf(root).expect("Failed to truncate").new_root; } let total = add - delete + 2; From 771aa867c1f100a232b357b2a6a86062c570fbd5 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 3 Sep 2019 12:52:50 +0300 Subject: [PATCH 140/330] derive display for errors --- Cargo.toml | 5 ++++- src/lib.rs | 20 ++++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 839ef38..219918b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,7 @@ edition = "2018" [dev-dependencies] assert_matches = "1.3.0" -quickcheck = "0.8" \ No newline at end of file +quickcheck = "0.8" + +[dependencies] +derive_more = "0.15" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index f6c555b..f7afa46 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,8 @@ #[cfg(test)] #[macro_use] extern crate assert_matches; #[cfg(test)] #[macro_use] extern crate quickcheck; +extern crate derive_more; + mod tree; @@ -26,19 +28,25 @@ pub struct NodeData { shielded_tx: u64, } -#[derive(Debug)] +#[derive(Debug, derive_more::Display)] pub enum Error { + #[display(fmt="Node/leaf expected to be in memory: {}", _0)] ExpectedInMemory(EntryLink), - ExpectedNode(Option), + #[display(fmt="Node expected")] + ExpectedNode, + #[display(fmt="Node expected, not leaf: {}", _0)] + ExpectedNodeForLink(EntryLink), } /// Reference to to the tree node. #[repr(C)] -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, derive_more::Display)] pub enum EntryLink { /// Reference to the stored (in the array representation) leaf/node. + #[display(fmt="stored(@{})", _0)] Stored(u32), /// Reference to the generated leaf/node. + #[display(fmt="generated(@{})", _0)] Generated(u32), } @@ -71,14 +79,14 @@ impl Entry { pub fn left(&self) -> Result { match self.kind { - EntryKind::Leaf => { Err(Error::ExpectedNode(None)) } + EntryKind::Leaf => { Err(Error::ExpectedNode) } EntryKind::Node(left, _) => Ok(left) } } pub fn right(&self) -> Result { match self.kind { - EntryKind::Leaf => { Err(Error::ExpectedNode(None)) } + EntryKind::Leaf => { Err(Error::ExpectedNode) } EntryKind::Node(_, right) => Ok(right) } } @@ -93,7 +101,7 @@ impl From for Entry { impl Error { pub (crate) fn augment(self, link: EntryLink) -> Self { match self { - Error::ExpectedNode(None) => Error::ExpectedNode(Some(link)), + Error::ExpectedNode => Error::ExpectedNodeForLink(link), val => val } } From bce88797f4cc2ccb1d7526df222569c67d5baf36 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 3 Sep 2019 12:56:24 +0300 Subject: [PATCH 141/330] move node data to separate mod --- src/lib.rs | 20 ++------------------ src/node_data.rs | 37 +++++++++++++++++++++++++++++++++++++ src/tree.rs | 21 +-------------------- 3 files changed, 40 insertions(+), 38 deletions(-) create mode 100644 src/node_data.rs diff --git a/src/lib.rs b/src/lib.rs index f7afa46..1511ea7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,27 +6,11 @@ #[cfg(test)] #[macro_use] extern crate quickcheck; extern crate derive_more; - mod tree; +mod node_data; pub use tree::Tree; - -/// Node metadata. -#[repr(C)] -#[derive(Debug)] -pub struct NodeData { - subtree_commitment: [u8; 32], - start_time: u32, - end_time: u32, - start_target: u32, - end_target: u32, - start_sapling_root: [u8; 32], - end_sapling_root: [u8; 32], - subtree_total_work: u64, - start_height: u32, - end_height: u32, - shielded_tx: u64, -} +pub use node_data::NodeData; #[derive(Debug, derive_more::Display)] pub enum Error { diff --git a/src/node_data.rs b/src/node_data.rs new file mode 100644 index 0000000..8d81c71 --- /dev/null +++ b/src/node_data.rs @@ -0,0 +1,37 @@ +/// Node metadata. +#[repr(C)] +#[derive(Debug)] +pub struct NodeData { + pub subtree_commitment: [u8; 32], + pub start_time: u32, + pub end_time: u32, + pub start_target: u32, + pub end_target: u32, + pub start_sapling_root: [u8; 32], + pub end_sapling_root: [u8; 32], + pub subtree_total_work: u64, + pub start_height: u32, + pub end_height: u32, + pub shielded_tx: u64, +} + +impl NodeData { + pub fn combine(left: &NodeData, right: &NodeData) -> NodeData { + NodeData { + // TODO: hash children + subtree_commitment: [0u8; 32], + start_time: left.start_time, + end_time: right.end_time, + start_target: left.start_target, + end_target: right.end_target, + start_sapling_root: left.start_sapling_root, + end_sapling_root: right.end_sapling_root, + + // TODO: sum work? + subtree_total_work: 0, + start_height: left.start_height, + end_height: right.end_height, + shielded_tx: left.shielded_tx + right.shielded_tx, + } + } +} \ No newline at end of file diff --git a/src/tree.rs b/src/tree.rs index 2faebb6..c5fc08f 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -272,29 +272,10 @@ impl<'a> IndexedNode<'a> { } -fn combine_data(left: &NodeData, right: &NodeData) -> NodeData { - NodeData { - // TODO: hash children - subtree_commitment: [0u8; 32], - start_time: left.start_time, - end_time: right.end_time, - start_target: left.start_target, - end_target: right.end_target, - start_sapling_root: left.start_sapling_root, - end_sapling_root: right.end_sapling_root, - - // TODO: sum work? - subtree_total_work: 0, - start_height: left.start_height, - end_height: right.end_height, - shielded_tx: left.shielded_tx + right.shielded_tx, - } -} - fn combine_nodes<'a>(left: IndexedNode<'a>, right: IndexedNode<'a>) -> Entry { Entry { kind: EntryKind::Node(left.link, right.link), - data: combine_data(&left.node.data, &right.node.data), + data: NodeData::combine(&left.node.data, &right.node.data), } } From f432983f09b82b872bc78ccc4bca74174422d2db Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 3 Sep 2019 13:11:10 +0300 Subject: [PATCH 142/330] add notes and remove todos --- src/tree.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index c5fc08f..9be1b5e 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -44,7 +44,6 @@ impl Tree { fn resolve_link(&self, link: EntryLink) -> Result { match link { EntryLink::Generated(index) => { - // TODO: maybe graceful error? let node = self.generated.get(&index).ok_or(Error::ExpectedInMemory(link))?; Ok(IndexedNode { node, @@ -52,7 +51,6 @@ impl Tree { }) }, EntryLink::Stored(index) => { - // TODO: maybe graceful error? let node = self.stored.get(&index).ok_or(Error::ExpectedInMemory(link))?; Ok(IndexedNode { node, @@ -735,6 +733,7 @@ mod tests { } } + // Length of tree is always less than number of leaves squared fn stored_length(add: u32, delete: u32) -> TestResult { if add > 2048 * 2048 || add < delete { TestResult::discard() From d8c04e8143e2ee1bc958ea3996bfe3bdc8454b45 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 3 Sep 2019 17:22:21 +0300 Subject: [PATCH 143/330] node serialization --- Cargo.toml | 4 ++- src/lib.rs | 4 ++- src/node_data.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++--- src/tree.rs | 12 ++++----- 4 files changed, 73 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 219918b..355bd09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,6 @@ assert_matches = "1.3.0" quickcheck = "0.8" [dependencies] -derive_more = "0.15" \ No newline at end of file +derive_more = "0.15" +bigint = "4" +byteorder = "1" \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 1511ea7..dbc5b91 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,8 @@ #[cfg(test)] #[macro_use] extern crate assert_matches; #[cfg(test)] #[macro_use] extern crate quickcheck; extern crate derive_more; +extern crate bigint; +extern crate byteorder; mod tree; mod node_data; @@ -53,7 +55,7 @@ impl Entry { leaves & (leaves - 1) == 0 } - pub fn leaf_count(&self) -> u32 { + pub fn leaf_count(&self) -> u64 { self.data.end_height - self.data.start_height + 1 } diff --git a/src/node_data.rs b/src/node_data.rs index 8d81c71..ba7877f 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -1,3 +1,7 @@ +use byteorder::{LittleEndian, WriteBytesExt}; + +use bigint::U256; + /// Node metadata. #[repr(C)] #[derive(Debug)] @@ -9,13 +13,15 @@ pub struct NodeData { pub end_target: u32, pub start_sapling_root: [u8; 32], pub end_sapling_root: [u8; 32], - pub subtree_total_work: u64, - pub start_height: u32, - pub end_height: u32, + pub subtree_total_work: U256, + pub start_height: u64, + pub end_height: u64, pub shielded_tx: u64, } impl NodeData { + pub const MAX_SERIALIZED_SIZE: usize = 32 + 4 + 4 + 4 + 4 + 32 + 32 + 32 + 9 + 9 + 9; // =171; + pub fn combine(left: &NodeData, right: &NodeData) -> NodeData { NodeData { // TODO: hash children @@ -28,10 +34,61 @@ impl NodeData { end_sapling_root: right.end_sapling_root, // TODO: sum work? - subtree_total_work: 0, + subtree_total_work: left.subtree_total_work + right.subtree_total_work, start_height: left.start_height, end_height: right.end_height, shielded_tx: left.shielded_tx + right.shielded_tx, } } + + fn write_compact(w: &mut W, compact: u64) -> std::io::Result<()> { + match compact { + 0..=0xfc => { + w.write_all(&[compact as u8])? + }, + 0xfd..=0xffff => { + w.write_all(&[0xfd])?; + w.write_u16::(compact as u16)?; + }, + 0x10000..=0xffff_ffff => { + w.write_all(&[0xfe])?; + w.write_u32::(compact as u32)?; + }, + _ => { + w.write_all(&[0xff])?; + w.write_u64::(compact)?; + } + } + Ok(()) + } + + pub fn write(&self, w: &mut W) -> std::io::Result<()> { + w.write_all(&self.subtree_commitment)?; + w.write_u32::(self.start_time)?; + w.write_u32::(self.end_time)?; + w.write_u32::(self.start_target)?; + w.write_u32::(self.end_target)?; + w.write_all(&self.start_sapling_root)?; + w.write_all(&self.end_sapling_root)?; + + let mut work_buf = [0u8; 32]; + self.subtree_total_work.to_little_endian(&mut work_buf[..]); + w.write_all(&work_buf)?; + + Self::write_compact(w, self.start_height)?; + Self::write_compact(w, self.end_height)?; + Self::write_compact(w, self.shielded_tx)?; + Ok(()) + } + + pub fn to_bytes(&self) -> Vec { + let mut buf = [0u8; Self::MAX_SERIALIZED_SIZE]; + let pos = { + let mut cursor = std::io::Cursor::new(&mut buf[..]); + self.write(&mut cursor).expect("Cursor cannot fail"); + cursor.position() as usize + }; + + buf[0..pos].to_vec() + } } \ No newline at end of file diff --git a/src/tree.rs b/src/tree.rs index 9be1b5e..e2b1c5b 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -292,14 +292,14 @@ mod tests { end_target: 0, start_sapling_root: [0u8; 32], end_sapling_root: [0u8; 32], - subtree_total_work: 0, - start_height: height, - end_height: height, + subtree_total_work: 0.into(), + start_height: height as u64, + end_height: height as u64, shielded_tx: 7, } } - fn node(start_height: u32, end_height: u32) -> NodeData { + fn node(start_height: u64, end_height: u64) -> NodeData { NodeData { subtree_commitment: [0u8; 32], start_time: 0, @@ -308,7 +308,7 @@ mod tests { end_target: 0, start_sapling_root: [0u8; 32], end_sapling_root: [0u8; 32], - subtree_total_work: 0, + subtree_total_work: 0.into(), start_height: start_height, end_height: end_height, shielded_tx: 7, @@ -679,7 +679,7 @@ mod tests { .node .leaf_count() == - number + number as u64 ) } } From b03b4cf958d2c87f0cc95752697a50cc6c0eca52 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 3 Sep 2019 17:47:21 +0300 Subject: [PATCH 144/330] hashing with blake2 --- Cargo.toml | 3 ++- src/lib.rs | 1 + src/node_data.rs | 39 +++++++++++++++++++++++++++++++++++---- src/tree.rs | 2 ++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 355bd09..b2d0d81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,5 @@ quickcheck = "0.8" [dependencies] derive_more = "0.15" bigint = "4" -byteorder = "1" \ No newline at end of file +byteorder = "1" +blake2-rfc = { git = "https://github.com/gtank/blake2-rfc.git", rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" } diff --git a/src/lib.rs b/src/lib.rs index dbc5b91..5ba7e16 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ extern crate derive_more; extern crate bigint; extern crate byteorder; +extern crate blake2_rfc as blake2; mod tree; mod node_data; diff --git a/src/node_data.rs b/src/node_data.rs index ba7877f..10bb5b3 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -1,11 +1,12 @@ -use byteorder::{LittleEndian, WriteBytesExt}; - +use byteorder::{LittleEndian, WriteBytesExt, ByteOrder}; use bigint::U256; +use blake2::blake2b::Blake2b; /// Node metadata. #[repr(C)] #[derive(Debug)] pub struct NodeData { + pub consensus_branch_id: u32, pub subtree_commitment: [u8; 32], pub start_time: u32, pub end_time: u32, @@ -19,13 +20,44 @@ pub struct NodeData { pub shielded_tx: u64, } +pub fn blake2b_personal(personalization: &[u8], input: &[u8]) -> [u8; 32] { + let mut hasher = Blake2b::with_params(32, &[], &[], personalization); + hasher.update(input); + let mut result = [0u8; 32]; + result.copy_from_slice(hasher.finalize().as_bytes()); + result +} + +pub fn personalization(branch_id: u32) -> [u8; 16] { + let mut result = [0u8; 16]; + result[..12].copy_from_slice(b"ZcashHistory"); + LittleEndian::write_u32(&mut result[12..], branch_id); + result +} + impl NodeData { pub const MAX_SERIALIZED_SIZE: usize = 32 + 4 + 4 + 4 + 4 + 32 + 32 + 32 + 9 + 9 + 9; // =171; pub fn combine(left: &NodeData, right: &NodeData) -> NodeData { + assert_eq!(left.consensus_branch_id, right.consensus_branch_id); + + let mut hash_buf = [0u8; Self::MAX_SERIALIZED_SIZE * 2]; + let size = { + let mut cursor = ::std::io::Cursor::new(&mut hash_buf[..]); + left.write(&mut cursor).expect("Writing to memory buf with enough length cannot fail; qed"); + right.write(&mut cursor).expect("Writing to memory buf with enough length cannot fail; qed"); + cursor.position() as usize + }; + + let hash = blake2b_personal( + &personalization(left.consensus_branch_id), + &hash_buf[..size] + ); + NodeData { // TODO: hash children - subtree_commitment: [0u8; 32], + consensus_branch_id: left.consensus_branch_id, + subtree_commitment: hash, start_time: left.start_time, end_time: right.end_time, start_target: left.start_target, @@ -33,7 +65,6 @@ impl NodeData { start_sapling_root: left.start_sapling_root, end_sapling_root: right.end_sapling_root, - // TODO: sum work? subtree_total_work: left.subtree_total_work + right.subtree_total_work, start_height: left.start_height, end_height: right.end_height, diff --git a/src/tree.rs b/src/tree.rs index e2b1c5b..efb59e3 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -285,6 +285,7 @@ mod tests { fn leaf(height: u32) -> NodeData { NodeData { + consensus_branch_id: 1, subtree_commitment: [0u8; 32], start_time: 0, end_time: 0, @@ -301,6 +302,7 @@ mod tests { fn node(start_height: u64, end_height: u64) -> NodeData { NodeData { + consensus_branch_id: 1, subtree_commitment: [0u8; 32], start_time: 0, end_time: 0, From efac432128ad0fbc37803170307bb15aaffbc7eb Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 3 Sep 2019 18:13:33 +0300 Subject: [PATCH 145/330] remove todo and de-pub --- src/node_data.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/node_data.rs b/src/node_data.rs index 10bb5b3..23452c2 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -20,7 +20,7 @@ pub struct NodeData { pub shielded_tx: u64, } -pub fn blake2b_personal(personalization: &[u8], input: &[u8]) -> [u8; 32] { +fn blake2b_personal(personalization: &[u8], input: &[u8]) -> [u8; 32] { let mut hasher = Blake2b::with_params(32, &[], &[], personalization); hasher.update(input); let mut result = [0u8; 32]; @@ -28,7 +28,7 @@ pub fn blake2b_personal(personalization: &[u8], input: &[u8]) -> [u8; 32] { result } -pub fn personalization(branch_id: u32) -> [u8; 16] { +fn personalization(branch_id: u32) -> [u8; 16] { let mut result = [0u8; 16]; result[..12].copy_from_slice(b"ZcashHistory"); LittleEndian::write_u32(&mut result[12..], branch_id); @@ -55,7 +55,6 @@ impl NodeData { ); NodeData { - // TODO: hash children consensus_branch_id: left.consensus_branch_id, subtree_commitment: hash, start_time: left.start_time, @@ -64,7 +63,6 @@ impl NodeData { end_target: right.end_target, start_sapling_root: left.start_sapling_root, end_sapling_root: right.end_sapling_root, - subtree_total_work: left.subtree_total_work + right.subtree_total_work, start_height: left.start_height, end_height: right.end_height, From 872ac5af7b96b6b2ccc2231f38f06661ac7f00c9 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 3 Sep 2019 18:31:51 +0300 Subject: [PATCH 146/330] avoid drain of vec --- src/tree.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index efb59e3..bc85416 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -227,9 +227,9 @@ impl Tree { } } - let mut new_root = peaks.drain(0..1).nth(0).expect("At lest 2 elements in peaks"); + let mut new_root = *peaks.iter().nth(0).expect("At lest 2 elements in peaks"); - for next_peak in peaks.into_iter() { + for next_peak in peaks.into_iter().skip(1) { new_root = self.push_generated( combine_nodes( self.resolve_link(new_root)?, From 73ee19239c6fab84cbdb4be1d5d7db019a8568a5 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 3 Aug 2019 10:40:09 +0100 Subject: [PATCH 147/330] Replace manual address decoding with PaymentAddress::from_bytes --- librustzcash/include/librustzcash.h | 3 +-- librustzcash/src/rustzcash.rs | 29 +++++++--------------------- zcash_client_backend/src/encoding.rs | 17 +++++----------- zcash_primitives/src/primitives.rs | 24 +++++++++++++++++++++++ 4 files changed, 37 insertions(+), 36 deletions(-) diff --git a/librustzcash/include/librustzcash.h b/librustzcash/include/librustzcash.h index 4efb544..a3ca5e8 100644 --- a/librustzcash/include/librustzcash.h +++ b/librustzcash/include/librustzcash.h @@ -112,8 +112,7 @@ extern "C" { bool librustzcash_sapling_output_proof( void *ctx, const unsigned char *esk, - const unsigned char *diversifier, - const unsigned char *pk_d, + const unsigned char *payment_address, const unsigned char *rcm, const uint64_t value, unsigned char *cv, diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 717dd61..9df4437 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -927,8 +927,7 @@ pub extern "system" fn librustzcash_sprout_verify( pub extern "system" fn librustzcash_sapling_output_proof( ctx: *mut SaplingProvingContext, esk: *const [c_uchar; 32], - diversifier: *const [c_uchar; 11], - pk_d: *const [c_uchar; 32], + payment_address: *const [c_uchar; 43], rcm: *const [c_uchar; 32], value: u64, cv: *mut [c_uchar; 32], @@ -940,26 +939,12 @@ pub extern "system" fn librustzcash_sapling_output_proof( Err(_) => return false, }; - // Grab the diversifier from the caller. - let diversifier = Diversifier(unsafe { *diversifier }); - - // Grab pk_d from the caller. - let pk_d = match edwards::Point::::read(&(unsafe { &*pk_d })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - // pk_d should be prime order. - let pk_d = match pk_d.as_prime_order(&JUBJUB) { - Some(p) => p, - None => return false, - }; - - // Construct a payment address - let payment_address = PaymentAddress { - pk_d: pk_d, - diversifier: diversifier, - }; + // Grab the payment address from the caller + let payment_address = + match PaymentAddress::::from_bytes(unsafe { &*payment_address }, &JUBJUB) { + Some(pa) => pa, + None => return false, + }; // The caller provides the commitment randomness for the output note let rcm = match Fs::from_repr(read_fs(&(unsafe { &*rcm })[..])) { diff --git a/zcash_client_backend/src/encoding.rs b/zcash_client_backend/src/encoding.rs index d39973d..9e9f2fc 100644 --- a/zcash_client_backend/src/encoding.rs +++ b/zcash_client_backend/src/encoding.rs @@ -7,10 +7,7 @@ use bech32::{self, Error, FromBase32, ToBase32}; use pairing::bls12_381::Bls12; use std::io::{self, Write}; use zcash_primitives::{ - jubjub::edwards, - primitives::{Diversifier, PaymentAddress}, -}; -use zcash_primitives::{ + primitives::PaymentAddress, zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}, JUBJUB, }; @@ -168,17 +165,13 @@ pub fn encode_payment_address(hrp: &str, addr: &PaymentAddress) -> String /// ``` pub fn decode_payment_address(hrp: &str, s: &str) -> Result>, Error> { bech32_decode(hrp, s, |data| { - let mut diversifier = Diversifier([0; 11]); - diversifier.0.copy_from_slice(&data[0..11]); - // Check that the diversifier is valid - if diversifier.g_d::(&JUBJUB).is_none() { + if data.len() != 43 { return None; } - edwards::Point::::read(&data[11..], &JUBJUB) - .ok()? - .as_prime_order(&JUBJUB) - .map(|pk_d| PaymentAddress { pk_d, diversifier }) + let mut bytes = [0; 43]; + bytes.copy_from_slice(&data); + PaymentAddress::::from_bytes(&bytes, &JUBJUB) }) } diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index 727402d..ac22f15 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -131,6 +131,30 @@ impl PartialEq for PaymentAddress { } impl PaymentAddress { + /// Parses a PaymentAddress from bytes. + pub fn from_bytes(bytes: &[u8; 43], params: &E::Params) -> Option { + let diversifier = { + let mut tmp = [0; 11]; + tmp.copy_from_slice(&bytes[0..11]); + Diversifier(tmp) + }; + // Check that the diversifier is valid + if diversifier.g_d::(params).is_none() { + return None; + } + + edwards::Point::::read(&bytes[11..43], params) + .ok()? + .as_prime_order(params) + .and_then(|pk_d| { + if pk_d == edwards::Point::zero() { + None + } else { + Some(PaymentAddress { pk_d, diversifier }) + } + }) + } + pub fn g_d(&self, params: &E::Params) -> Option> { self.diversifier.g_d(params) } From 86142d044c0670b288c96f9e9fa9183eba74f2b0 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 23 Aug 2019 23:03:16 +0100 Subject: [PATCH 148/330] PaymentAddress::to_bytes --- librustzcash/src/rustzcash.rs | 9 +-------- zcash_client_backend/src/encoding.rs | 5 +---- zcash_primitives/src/primitives.rs | 8 ++++++++ 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 9df4437..e3a85e4 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -1215,14 +1215,7 @@ pub extern "system" fn librustzcash_zip32_xfvk_address( let addr_ret = unsafe { &mut *addr_ret }; j_ret.copy_from_slice(&(addr.0).0); - addr_ret - .get_mut(..11) - .unwrap() - .copy_from_slice(&addr.1.diversifier.0); - addr.1 - .pk_d - .write(addr_ret.get_mut(11..).unwrap()) - .expect("should be able to serialize a PaymentAddress"); + addr_ret.copy_from_slice(&addr.1.to_bytes()); true } diff --git a/zcash_client_backend/src/encoding.rs b/zcash_client_backend/src/encoding.rs index 9e9f2fc..4d87587 100644 --- a/zcash_client_backend/src/encoding.rs +++ b/zcash_client_backend/src/encoding.rs @@ -121,10 +121,7 @@ pub fn decode_extended_full_viewing_key( /// ); /// ``` pub fn encode_payment_address(hrp: &str, addr: &PaymentAddress) -> String { - bech32_encode(hrp, |w| { - w.write_all(&addr.diversifier.0)?; - addr.pk_d.write(w) - }) + bech32_encode(hrp, |w| w.write_all(&addr.to_bytes())) } /// Decodes a [`PaymentAddress`] from a Bech32-encoded string. diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index ac22f15..00ff2bf 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -155,6 +155,14 @@ impl PaymentAddress { }) } + /// Returns the byte encoding of this `PaymentAddress`. + pub fn to_bytes(&self) -> [u8; 43] { + let mut bytes = [0; 43]; + bytes[0..11].copy_from_slice(&self.diversifier.0); + self.pk_d.write(&mut bytes[11..]).unwrap(); + bytes + } + pub fn g_d(&self, params: &E::Params) -> Option> { self.diversifier.g_d(params) } From abbd43ff57ab16b83cb32535856866d55bb51447 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 23 Aug 2019 23:08:09 +0100 Subject: [PATCH 149/330] Make pk_d validity an invariant of PaymentAddress Introduces a PaymentAddress::from_parts constructor, and getters for the diversifier and pk_d fields (which are now private). --- librustzcash/src/tests/key_agreement.rs | 4 +- librustzcash/src/tests/key_components.rs | 2 +- zcash_client_backend/src/encoding.rs | 36 +++++++++------- zcash_primitives/src/note_encryption.rs | 20 ++++----- zcash_primitives/src/primitives.rs | 46 ++++++++++++++++----- zcash_primitives/src/transaction/builder.rs | 29 ++++++------- zcash_primitives/src/zip32.rs | 2 +- zcash_proofs/src/circuit/sapling.rs | 6 +-- zcash_proofs/src/sapling/prover.rs | 2 +- 9 files changed, 85 insertions(+), 62 deletions(-) diff --git a/librustzcash/src/tests/key_agreement.rs b/librustzcash/src/tests/key_agreement.rs index 8f2c273..1250cc7 100644 --- a/librustzcash/src/tests/key_agreement.rs +++ b/librustzcash/src/tests/key_agreement.rs @@ -47,7 +47,7 @@ fn test_key_agreement() { // Serialize pk_d for the call to librustzcash_sapling_ka_agree let mut addr_pk_d = [0u8; 32]; - addr.pk_d.write(&mut addr_pk_d[..]).unwrap(); + addr.pk_d().write(&mut addr_pk_d[..]).unwrap(); assert!(librustzcash_sapling_ka_agree( &addr_pk_d, @@ -59,7 +59,7 @@ fn test_key_agreement() { // using the diversifier and esk. let mut epk = [0u8; 32]; assert!(librustzcash_sapling_ka_derivepublic( - &addr.diversifier.0, + &addr.diversifier().0, &esk, &mut epk )); diff --git a/librustzcash/src/tests/key_components.rs b/librustzcash/src/tests/key_components.rs index a15a40a..5975e5e 100644 --- a/librustzcash/src/tests/key_components.rs +++ b/librustzcash/src/tests/key_components.rs @@ -707,7 +707,7 @@ fn key_components() { let addr = fvk.to_payment_address(diversifier, &JUBJUB).unwrap(); { let mut vec = Vec::new(); - addr.pk_d.write(&mut vec).unwrap(); + addr.pk_d().write(&mut vec).unwrap(); assert_eq!(&vec, &tv.default_pk_d); } { diff --git a/zcash_client_backend/src/encoding.rs b/zcash_client_backend/src/encoding.rs index 4d87587..4e38995 100644 --- a/zcash_client_backend/src/encoding.rs +++ b/zcash_client_backend/src/encoding.rs @@ -110,10 +110,11 @@ pub fn decode_extended_full_viewing_key( /// 0xbc, 0xe5, /// ]); /// -/// let pa = PaymentAddress { -/// diversifier: Diversifier([0u8; 11]), -/// pk_d: edwards::Point::::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB), -/// }; +/// let pa = PaymentAddress::from_parts( +/// Diversifier([0u8; 11]), +/// edwards::Point::::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB), +/// ) +/// .unwrap(); /// /// assert_eq!( /// encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, &pa), @@ -147,10 +148,11 @@ pub fn encode_payment_address(hrp: &str, addr: &PaymentAddress) -> String /// 0xbc, 0xe5, /// ]); /// -/// let pa = PaymentAddress { -/// diversifier: Diversifier([0u8; 11]), -/// pk_d: edwards::Point::::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB), -/// }; +/// let pa = PaymentAddress::from_parts( +/// Diversifier([0u8; 11]), +/// edwards::Point::::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB), +/// ) +/// .unwrap(); /// /// assert_eq!( /// decode_payment_address( @@ -193,10 +195,11 @@ mod tests { 0xbc, 0xe5, ]); - let addr = PaymentAddress { - diversifier: Diversifier([0u8; 11]), - pk_d: edwards::Point::::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB), - }; + let addr = PaymentAddress::from_parts( + Diversifier([0u8; 11]), + edwards::Point::::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB), + ) + .unwrap(); let encoded_main = "zs1qqqqqqqqqqqqqqqqqrjq05nyfku05msvu49mawhg6kr0wwljahypwyk2h88z6975u563j8nfaxd"; @@ -237,10 +240,11 @@ mod tests { 0xbc, 0xe5, ]); - let addr = PaymentAddress { - diversifier: Diversifier([1u8; 11]), - pk_d: edwards::Point::::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB), - }; + let addr = PaymentAddress::from_parts( + Diversifier([1u8; 11]), + edwards::Point::::rand(rng, &JUBJUB).mul_by_cofactor(&JUBJUB), + ) + .unwrap(); let encoded_main = encode_payment_address(constants::mainnet::HRP_SAPLING_PAYMENT_ADDRESS, &addr); diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 2644016..3b6e83b 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -232,10 +232,7 @@ fn prf_ock( /// /// let diversifier = Diversifier([0; 11]); /// let pk_d = diversifier.g_d::(&JUBJUB).unwrap(); -/// let to = PaymentAddress { -/// pk_d, -/// diversifier, -/// }; +/// let to = PaymentAddress::from_parts(diversifier, pk_d).unwrap(); /// let ovk = OutgoingViewingKey([0; 32]); /// /// let value = 1000; @@ -294,14 +291,14 @@ impl SaplingNoteEncryption { /// Generates `encCiphertext` for this note. pub fn encrypt_note_plaintext(&self) -> [u8; ENC_CIPHERTEXT_SIZE] { - let shared_secret = sapling_ka_agree(&self.esk, &self.to.pk_d); + let shared_secret = sapling_ka_agree(&self.esk, self.to.pk_d()); let key = kdf_sapling(shared_secret, &self.epk); // Note plaintext encoding is defined in section 5.5 of the Zcash Protocol // Specification. let mut input = [0; NOTE_PLAINTEXT_SIZE]; input[0] = 1; - input[1..12].copy_from_slice(&self.to.diversifier.0); + input[1..12].copy_from_slice(&self.to.diversifier().0); (&mut input[12..20]) .write_u64::(self.note.value) .unwrap(); @@ -375,7 +372,7 @@ fn parse_note_plaintext_without_memo( .g_d::(&JUBJUB)? .mul(ivk.into_repr(), &JUBJUB); - let to = PaymentAddress { pk_d, diversifier }; + let to = PaymentAddress::from_parts(diversifier, pk_d)?; let note = to.create_note(v, rcm, &JUBJUB).unwrap(); if note.cm(&JUBJUB) != *cmu { @@ -535,7 +532,7 @@ pub fn try_sapling_output_recovery( return None; } - let to = PaymentAddress { pk_d, diversifier }; + let to = PaymentAddress::from_parts(diversifier, pk_d)?; let note = to.create_note(v, rcm, &JUBJUB).unwrap(); if note.cm(&JUBJUB) != *cmu { @@ -701,7 +698,7 @@ mod tests { let diversifier = Diversifier([0; 11]); let ivk = Fs::random(&mut rng); let pk_d = diversifier.g_d::(&JUBJUB).unwrap().mul(ivk, &JUBJUB); - let pa = PaymentAddress { diversifier, pk_d }; + let pa = PaymentAddress::from_parts(diversifier, pk_d).unwrap(); // Construct the value commitment for the proof instance let value = 100; @@ -1317,10 +1314,7 @@ mod tests { let ock = prf_ock(&ovk, &cv, &cmu, &epk); assert_eq!(ock.as_bytes(), tv.ock); - let to = PaymentAddress { - pk_d, - diversifier: Diversifier(tv.default_d), - }; + let to = PaymentAddress::from_parts(Diversifier(tv.default_d), pk_d).unwrap(); let note = to.create_note(tv.v, rcm, &JUBJUB).unwrap(); assert_eq!(note.cm(&JUBJUB), cmu); diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index 00ff2bf..4f60c64 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -94,10 +94,10 @@ impl ViewingKey { diversifier: Diversifier, params: &E::Params, ) -> Option> { - diversifier.g_d(params).map(|g_d| { + diversifier.g_d(params).and_then(|g_d| { let pk_d = g_d.mul(self.ivk(), params); - PaymentAddress { pk_d, diversifier } + PaymentAddress::from_parts(diversifier, pk_d) }) } } @@ -118,10 +118,16 @@ impl Diversifier { } } +/// A Sapling payment address. +/// +/// # Invariants +/// +/// `pk_d` is guaranteed to be prime-order (i.e. in the prime-order subgroup of Jubjub, +/// and not the identity). #[derive(Clone, Debug)] pub struct PaymentAddress { - pub pk_d: edwards::Point, - pub diversifier: Diversifier, + pk_d: edwards::Point, + diversifier: Diversifier, } impl PartialEq for PaymentAddress { @@ -131,6 +137,20 @@ impl PartialEq for PaymentAddress { } impl PaymentAddress { + /// Constructs a PaymentAddress from a diversifier and a Jubjub point. + /// + /// Returns None if `pk_d` is the identity. + pub fn from_parts( + diversifier: Diversifier, + pk_d: edwards::Point, + ) -> Option { + if pk_d == edwards::Point::zero() { + None + } else { + Some(PaymentAddress { pk_d, diversifier }) + } + } + /// Parses a PaymentAddress from bytes. pub fn from_bytes(bytes: &[u8; 43], params: &E::Params) -> Option { let diversifier = { @@ -146,13 +166,7 @@ impl PaymentAddress { edwards::Point::::read(&bytes[11..43], params) .ok()? .as_prime_order(params) - .and_then(|pk_d| { - if pk_d == edwards::Point::zero() { - None - } else { - Some(PaymentAddress { pk_d, diversifier }) - } - }) + .and_then(|pk_d| PaymentAddress::from_parts(diversifier, pk_d)) } /// Returns the byte encoding of this `PaymentAddress`. @@ -163,6 +177,16 @@ impl PaymentAddress { bytes } + /// Returns the [`Diversifier`] for this `PaymentAddress`. + pub fn diversifier(&self) -> &Diversifier { + &self.diversifier + } + + /// Returns `pk_d` for this `PaymentAddress`. + pub fn pk_d(&self) -> &edwards::Point { + &self.pk_d + } + pub fn g_d(&self, params: &E::Params) -> Option> { self.diversifier.g_d(params) } diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 281ccbf..b100d9c 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -77,7 +77,7 @@ impl SaplingOutput { let note = Note { g_d, - pk_d: to.pk_d.clone(), + pk_d: to.pk_d().clone(), value: value.into(), r: rcm, }; @@ -344,10 +344,11 @@ impl Builder { } else if !self.spends.is_empty() { ( self.spends[0].extsk.expsk.ovk, - PaymentAddress { - diversifier: self.spends[0].diversifier, - pk_d: self.spends[0].note.pk_d.clone(), - }, + PaymentAddress::from_parts( + self.spends[0].diversifier, + self.spends[0].note.pk_d.clone(), + ) + .ok_or(Error::InvalidAddress)?, ) } else { return Err(Error::NoChangeAddress); @@ -450,16 +451,16 @@ impl Builder { (diversifier, g_d) }; - let pk_d = { + let (pk_d, payment_address) = loop { let dummy_ivk = Fs::random(&mut self.rng); - g_d.mul(dummy_ivk, &JUBJUB) + let pk_d = g_d.mul(dummy_ivk, &JUBJUB); + if let Some(addr) = PaymentAddress::from_parts(diversifier, pk_d.clone()) { + break (pk_d, addr); + } }; ( - PaymentAddress { - diversifier, - pk_d: pk_d.clone(), - }, + payment_address, Note { g_d, pk_d, @@ -644,7 +645,7 @@ mod tests { builder .add_sapling_spend( extsk.clone(), - to.diversifier, + *to.diversifier(), note1.clone(), witness1.clone(), ) @@ -683,10 +684,10 @@ mod tests { { let mut builder = Builder::new(0); builder - .add_sapling_spend(extsk.clone(), to.diversifier, note1, witness1) + .add_sapling_spend(extsk.clone(), *to.diversifier(), note1, witness1) .unwrap(); builder - .add_sapling_spend(extsk, to.diversifier, note2, witness2) + .add_sapling_spend(extsk, *to.diversifier(), note2, witness2) .unwrap(); builder .add_sapling_output(ovk, to, Amount::from_u64(30000).unwrap(), None) diff --git a/zcash_primitives/src/zip32.rs b/zcash_primitives/src/zip32.rs index e287602..6cbc462 100644 --- a/zcash_primitives/src/zip32.rs +++ b/zcash_primitives/src/zip32.rs @@ -548,7 +548,7 @@ mod tests { let (j_m, addr_m) = xsk_m.default_address().unwrap(); assert_eq!(j_m.0, [0; 11]); assert_eq!( - addr_m.diversifier.0, + addr_m.diversifier().0, // Computed using this Rust implementation [59, 246, 250, 31, 131, 191, 69, 99, 200, 167, 19] ); diff --git a/zcash_proofs/src/circuit/sapling.rs b/zcash_proofs/src/circuit/sapling.rs index de6887b..08e55e6 100644 --- a/zcash_proofs/src/circuit/sapling.rs +++ b/zcash_proofs/src/circuit/sapling.rs @@ -464,7 +464,7 @@ impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { // they would like. { // Just grab pk_d from the witness - let pk_d = self.payment_address.as_ref().map(|e| e.pk_d.to_xy()); + let pk_d = self.payment_address.as_ref().map(|e| e.pk_d().to_xy()); // Witness the y-coordinate, encoded as little // endian bits (to match the representation) @@ -584,7 +584,7 @@ fn test_input_circuit_with_bls12_381() { } } - let g_d = payment_address.diversifier.g_d(params).unwrap(); + let g_d = payment_address.diversifier().g_d(params).unwrap(); let commitment_randomness = fs::Fs::random(rng); let auth_path = vec![Some((Fr::random(rng), rng.next_u32() % 2 != 0)); tree_depth]; let ar = fs::Fs::random(rng); @@ -595,7 +595,7 @@ fn test_input_circuit_with_bls12_381() { let note = Note { value: value_commitment.value, g_d: g_d.clone(), - pk_d: payment_address.pk_d.clone(), + pk_d: payment_address.pk_d().clone(), r: commitment_randomness.clone(), }; diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index 0603424..9b0f871 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -100,7 +100,7 @@ impl SaplingProvingContext { g_d: diversifier .g_d::(params) .expect("was a valid diversifier before"), - pk_d: payment_address.pk_d.clone(), + pk_d: payment_address.pk_d().clone(), r: rcm, }; From d6f6b50ecda913bb5a5f91d75b8d442450719e16 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 26 Aug 2019 22:50:42 +0100 Subject: [PATCH 150/330] Check try_sapling_output_recovery fails with identity as pk_d --- zcash_primitives/src/note_encryption.rs | 73 ++++++++++++++++++------- zcash_primitives/src/primitives.rs | 11 ++++ 2 files changed, 64 insertions(+), 20 deletions(-) diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index 3b6e83b..e728c5e 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -695,10 +695,47 @@ mod tests { [u8; ENC_CIPHERTEXT_SIZE], [u8; OUT_CIPHERTEXT_SIZE], ) { - let diversifier = Diversifier([0; 11]); let ivk = Fs::random(&mut rng); + + let (ovk, ivk, cv, cmu, epk, enc_ciphertext, out_ciphertext) = + random_enc_ciphertext_with(ivk, rng); + + assert!(try_sapling_note_decryption(&ivk, &epk, &cmu, &enc_ciphertext).is_some()); + assert!(try_sapling_compact_note_decryption( + &ivk, + &epk, + &cmu, + &enc_ciphertext[..COMPACT_NOTE_SIZE] + ) + .is_some()); + assert!(try_sapling_output_recovery( + &ovk, + &cv, + &cmu, + &epk, + &enc_ciphertext, + &out_ciphertext + ) + .is_some()); + + (ovk, ivk, cv, cmu, epk, enc_ciphertext, out_ciphertext) + } + + fn random_enc_ciphertext_with( + ivk: Fs, + mut rng: &mut R, + ) -> ( + OutgoingViewingKey, + Fs, + edwards::Point, + Fr, + edwards::Point, + [u8; ENC_CIPHERTEXT_SIZE], + [u8; OUT_CIPHERTEXT_SIZE], + ) { + let diversifier = Diversifier([0; 11]); let pk_d = diversifier.g_d::(&JUBJUB).unwrap().mul(ivk, &JUBJUB); - let pa = PaymentAddress::from_parts(diversifier, pk_d).unwrap(); + let pa = PaymentAddress::from_parts_unchecked(diversifier, pk_d); // Construct the value commitment for the proof instance let value = 100; @@ -719,24 +756,6 @@ mod tests { let enc_ciphertext = ne.encrypt_note_plaintext(); let out_ciphertext = ne.encrypt_outgoing_plaintext(&cv, &cmu); - assert!(try_sapling_note_decryption(&ivk, epk, &cmu, &enc_ciphertext).is_some()); - assert!(try_sapling_compact_note_decryption( - &ivk, - epk, - &cmu, - &enc_ciphertext[..COMPACT_NOTE_SIZE] - ) - .is_some()); - assert!(try_sapling_output_recovery( - &ovk, - &cv, - &cmu, - &epk, - &enc_ciphertext, - &out_ciphertext - ) - .is_some()); - ( ovk, ivk, @@ -1253,6 +1272,20 @@ mod tests { ); } + #[test] + fn recovery_with_invalid_pk_d() { + let mut rng = OsRng; + + let ivk = Fs::zero(); + let (ovk, _, cv, cmu, epk, enc_ciphertext, out_ciphertext) = + random_enc_ciphertext_with(ivk, &mut rng); + + assert_eq!( + try_sapling_output_recovery(&ovk, &cv, &cmu, &epk, &enc_ciphertext, &out_ciphertext), + None + ); + } + #[test] fn test_vectors() { let test_vectors = crate::test_vectors::note_encryption::make_test_vectors(); diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index 4f60c64..a336673 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -151,6 +151,17 @@ impl PaymentAddress { } } + /// Constructs a PaymentAddress from a diversifier and a Jubjub point. + /// + /// Only for test code, as this explicitly bypasses the invariant. + #[cfg(test)] + pub(crate) fn from_parts_unchecked( + diversifier: Diversifier, + pk_d: edwards::Point, + ) -> Self { + PaymentAddress { pk_d, diversifier } + } + /// Parses a PaymentAddress from bytes. pub fn from_bytes(bytes: &[u8; 43], params: &E::Params) -> Option { let diversifier = { From 6b36cb5a51bc32ccda167aa062a0a0e7cfccba4e Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 6 Sep 2019 15:40:26 +0300 Subject: [PATCH 151/330] example and neccessary fixes --- examples/producer.rs | 219 +++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 + src/node_data.rs | 2 +- src/tree.rs | 27 +++--- 4 files changed, 241 insertions(+), 12 deletions(-) create mode 100644 examples/producer.rs diff --git a/examples/producer.rs b/examples/producer.rs new file mode 100644 index 0000000..b439947 --- /dev/null +++ b/examples/producer.rs @@ -0,0 +1,219 @@ +extern crate zcash_mmr as mmr; + +use mmr::{NodeData, Tree, EntryLink, Entry}; + +fn prepare_tree(vec: Vec) -> (Tree, EntryLink) { + + assert!(vec.len() > 0); + + // integer log2 of (vec.len()+1), -1 + let mut h = (32 - ((vec.len()+1) as u32).leading_zeros() - 1)-1; + let mut peak_pos = (1 << (h+1)) - 1; + + let mut nodes = Vec::new(); + let mut root_peak: Entry = vec[peak_pos-1].clone().into(); + + root_peak.update_siblings( + EntryLink::Stored((peak_pos - (1< vec.len() { + // left child, -2^h + peak_pos = peak_pos - (1< bool { let leaves = self.leaf_count(); leaves & (leaves - 1) == 0 diff --git a/src/node_data.rs b/src/node_data.rs index 23452c2..d5cec61 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -4,7 +4,7 @@ use blake2::blake2b::Blake2b; /// Node metadata. #[repr(C)] -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct NodeData { pub consensus_branch_id: u32, pub subtree_commitment: [u8; 32], diff --git a/src/tree.rs b/src/tree.rs index bc85416..11e93e3 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -88,23 +88,28 @@ impl Tree { pub fn new( length: u32, - stored: Vec<(u32, Entry)>, - generated: Vec, - ) -> Self { + peaks: Vec<(u32, Entry)>, + extra: Vec<(u32, Entry)>, + ) -> (Self, EntryLink) { let mut result = Tree::default(); result.stored_count = length; - for (idx, node) in stored.into_iter() { + let mut gen = 0; + let mut root = EntryLink::Stored(peaks[0].0); + for (idx, node) in peaks.into_iter() { result.stored.insert(idx, node); + if gen != 0 { + let next_generated = + combine_nodes(result. + resolve_link(root).expect("Inserted before, cannot fail; qed"), + result.resolve_link(EntryLink::Stored(idx)).expect("Inserted before, cannot fail; qed") + ); + root = result.push_generated(next_generated); + } + gen += 1; } - result.generated_count = generated.len() as u32; - - for (idx, node) in generated.into_iter().enumerate() { - result.generated.insert(idx as u32, node); - } - - result + (result, root) } fn get_peaks(&self, root: EntryLink, target: &mut Vec) -> Result<(), Error> { From 5d2f84a1542ea30a03b38b078a36af10cc3ec1a6 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 6 Sep 2019 18:52:27 +0300 Subject: [PATCH 152/330] carry root with tree --- examples/producer.rs | 6 ++-- src/tree.rs | 85 ++++++++++++++++++++++++++++---------------- 2 files changed, 57 insertions(+), 34 deletions(-) diff --git a/examples/producer.rs b/examples/producer.rs index b439947..5c66985 100644 --- a/examples/producer.rs +++ b/examples/producer.rs @@ -2,7 +2,7 @@ extern crate zcash_mmr as mmr; use mmr::{NodeData, Tree, EntryLink, Entry}; -fn prepare_tree(vec: Vec) -> (Tree, EntryLink) { +fn prepare_tree(vec: Vec) -> Tree { assert!(vec.len() > 0); @@ -213,7 +213,7 @@ fn main() { }, ); - let (_tree, root) = prepare_tree(initial_tree_vec); - println!("root: {}", root); + let tree = prepare_tree(initial_tree_vec); + println!("root: {}", tree.root()); } \ No newline at end of file diff --git a/src/tree.rs b/src/tree.rs index 11e93e3..cf0bf93 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -9,7 +9,6 @@ use crate::{Entry, EntryLink, NodeData, Error, EntryKind}; /// Exact amount of the loaded data can be calculated by the constructing party, /// depending on the length of the tree and maximum amount of operations that are going /// to happen after construction. -#[derive(Default)] pub struct Tree { stored: HashMap, @@ -20,6 +19,8 @@ pub struct Tree { // number of virtual nodes generated generated_count: u32, + + root: EntryLink, } /// Result of appending one or several leaves. @@ -76,22 +77,34 @@ impl Tree { /// Populate tree with plain list of the leaves/nodes. Mostly for tests, /// since this `Tree` structure is for partially loaded tree. - pub fn populate(loaded: Vec) -> Self { - let mut result = Tree::default(); + pub fn populate(loaded: Vec, root: EntryLink) -> Self { + let mut result = Tree::invalid(); result.stored_count = loaded.len() as u32; for (idx, item) in loaded.into_iter().enumerate() { result.stored.insert(idx as u32, item); } + result.root = root; result } + fn invalid() -> Self { + Tree { + root: EntryLink::Generated(0), + generated: Default::default(), + stored: Default::default(), + generated_count: 0, + stored_count: 0, + } + } + pub fn new( length: u32, peaks: Vec<(u32, Entry)>, extra: Vec<(u32, Entry)>, - ) -> (Self, EntryLink) { - let mut result = Tree::default(); + ) -> Self { + let mut result = Tree::invalid(); + result.stored_count = length; let mut gen = 0; @@ -109,7 +122,9 @@ impl Tree { gen += 1; } - (result, root) + result.root = root; + + result } fn get_peaks(&self, root: EntryLink, target: &mut Vec) -> Result<(), Error> { @@ -132,7 +147,8 @@ impl Tree { } /// Append one leaf to the tree. - pub fn append_leaf(&mut self, root: EntryLink, new_leaf: NodeData) -> Result { + pub fn append_leaf(&mut self, new_leaf: NodeData) -> Result { + let root = self.root; let new_leaf_link = self.push(new_leaf.into()); let mut appended = Vec::new(); appended.push(new_leaf_link); @@ -172,6 +188,8 @@ impl Tree { ) } + self.root = new_root; + Ok(AppendTransaction { new_root, appended, @@ -196,10 +214,10 @@ impl Tree { } /// Truncate one leaf from the end of the tree. - pub fn truncate_leaf(&mut self, root: EntryLink) -> Result { + pub fn truncate_leaf(&mut self) -> Result { let root = { let (leaves, root_left_child) = { - let n = self.resolve_link(root)?; + let n = self.resolve_link(self.root)?; ( n.node.leaf_count(), n.node.left()?, @@ -207,12 +225,13 @@ impl Tree { }; if leaves & 1 != 0 { self.pop(); + self.root = root_left_child; return Ok(DeleteTransaction { truncated: 1, new_root: root_left_child, }) } else { - self.resolve_link(root)? + self.resolve_link(self.root)? } }; @@ -245,6 +264,8 @@ impl Tree { for _ in 0..truncated { self.pop(); } + self.root = new_root; + Ok(DeleteTransaction { new_root, truncated, @@ -255,6 +276,8 @@ impl Tree { pub fn len(&self) -> u32 { self.stored_count } + + pub fn root(&self) -> EntryLink { self.root } } @@ -331,7 +354,7 @@ mod tests { kind: EntryKind::Leaf, }; - (EntryLink::Stored(2), Tree::populate(vec![node1, node2, node3])) + (EntryLink::Stored(2), Tree::populate(vec![node1, node2, node3], EntryLink::Stored(2))) } // returns tree with specified number of leafs and it's root @@ -340,7 +363,7 @@ mod tests { let (mut root, mut tree) = initial(); for i in 2..length { root = tree - .append_leaf(root, leaf(i+1).into()) + .append_leaf(leaf(i+1).into()) .expect("Failed to append") .new_root; } @@ -354,7 +377,7 @@ mod tests { // ** APPEND 3 ** let append_tx = tree - .append_leaf(root, leaf(3)) + .append_leaf(leaf(3)) .expect("Failed to append"); let new_root_link = append_tx.new_root; let new_root = tree.resolve_link(new_root_link).expect("Failed to resolve root").node; @@ -377,7 +400,7 @@ mod tests { // ** APPEND 4 ** let append_tx = tree - .append_leaf(new_root_link, leaf(4)) + .append_leaf(leaf(4)) .expect("Failed to append"); let new_root_link = append_tx.new_root; @@ -406,7 +429,7 @@ mod tests { // ** APPEND 5 ** let append_tx = tree - .append_leaf(new_root_link, leaf(5)) + .append_leaf(leaf(5)) .expect("Failed to append"); let new_root_link = append_tx.new_root; let new_root = tree.resolve_link(new_root_link).expect("Failed to resolve root").node; @@ -439,7 +462,7 @@ mod tests { // *** APPEND #6 *** let append_tx = tree - .append_leaf(new_root_link, leaf(6)) + .append_leaf(leaf(6)) .expect("Failed to append"); let new_root_link = append_tx.new_root; let new_root = tree.resolve_link(new_root_link).expect("Failed to resolve root").node; @@ -475,7 +498,7 @@ mod tests { // *** APPEND #7 *** let append_tx = tree - .append_leaf(new_root_link, leaf(7)) + .append_leaf(leaf(7)) .expect("Failed to append"); let new_root_link = append_tx.new_root; let new_root = tree @@ -518,7 +541,7 @@ mod tests { fn truncate_simple() { let (mut tree, root) = generated(9); let delete_tx = tree - .truncate_leaf(root) + .truncate_leaf() .expect("Failed to truncate"); // initial tree: @@ -553,7 +576,7 @@ mod tests { fn truncate_generated() { let (mut tree, root) = generated(10); let delete_tx = tree - .truncate_leaf(root) + .truncate_leaf() .expect("Failed to truncate"); // initial tree: @@ -611,13 +634,13 @@ mod tests { for i in 0..2 { root = tree - .append_leaf(root, leaf(i+3)) + .append_leaf(leaf(i+3)) .expect("Failed to append") .new_root; } assert_eq!(tree.len(), 7); - tree.truncate_leaf(root).expect("Failed to truncate"); + tree.truncate_leaf().expect("Failed to truncate"); assert_eq!(tree.len(), 4); } @@ -630,7 +653,7 @@ mod tests { for i in 0..4094 { root = tree - .append_leaf(root, leaf(i+3)) + .append_leaf(leaf(i+3)) .expect("Failed to append") .new_root; } @@ -638,7 +661,7 @@ mod tests { for _ in 0..2049 { root = tree - .truncate_leaf(root) + .truncate_leaf() .expect("Failed to truncate") .new_root; } @@ -655,12 +678,12 @@ mod tests { let (mut root, mut tree) = initial(); for i in 0..number { root = tree - .append_leaf(root, leaf(i+3)) + .append_leaf(leaf(i+3)) .expect("Failed to append") .new_root; } for _ in 0..number { - root = tree.truncate_leaf(root).expect("Failed to truncate").new_root; + root = tree.truncate_leaf().expect("Failed to truncate").new_root; } TestResult::from_bool(if let EntryLink::Stored(2) = root { true } else { false }) @@ -674,7 +697,7 @@ mod tests { let (mut root, mut tree) = initial(); for i in 1..(number-1) { root = tree - .append_leaf(root, leaf(i+2)) + .append_leaf(leaf(i+2)) .expect("Failed to append") .new_root; } @@ -697,7 +720,7 @@ mod tests { } else { let (mut root, mut tree) = initial(); for i in 1..(number-1) { - root = tree.append_leaf(root, leaf(i+2)).expect("Failed to append").new_root; + root = tree.append_leaf(leaf(i+2)).expect("Failed to append").new_root; } TestResult::from_bool( @@ -720,10 +743,10 @@ mod tests { } else { let (mut root, mut tree) = initial(); for i in 0..add { - root = tree.append_leaf(root, leaf(i+3)).expect("Failed to append").new_root; + root = tree.append_leaf(leaf(i+3)).expect("Failed to append").new_root; } for _ in 0..delete { - root = tree.truncate_leaf(root).expect("Failed to truncate").new_root; + root = tree.truncate_leaf().expect("Failed to truncate").new_root; } let total = add - delete + 2; @@ -747,10 +770,10 @@ mod tests { } else { let (mut root, mut tree) = initial(); for i in 0..add { - root = tree.append_leaf(root, leaf(i+3)).expect("Failed to append").new_root; + root = tree.append_leaf(leaf(i+3)).expect("Failed to append").new_root; } for _ in 0..delete { - root = tree.truncate_leaf(root).expect("Failed to truncate").new_root; + root = tree.truncate_leaf().expect("Failed to truncate").new_root; } let total = add - delete + 2; From 942a976ef5a8959997580b94b2cd1c89f3016bd7 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 6 Sep 2019 19:14:53 +0300 Subject: [PATCH 153/330] refactor numerous tests --- src/tree.rs | 212 +++++++++++++++++++++------------------------------- 1 file changed, 85 insertions(+), 127 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index cf0bf93..3e2d4b0 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -23,24 +23,6 @@ pub struct Tree { root: EntryLink, } -/// Result of appending one or several leaves. -pub struct AppendTransaction { - /// Plain list of nodes that has to be appended to the end of the array representation - /// of the tree as the result of append operation. - pub appended: Vec, - - /// New root as a result of the operation (can be generated one). - pub new_root: EntryLink, -} - -/// Result of truncating one or severl leaves. -pub struct DeleteTransaction { - /// Number of leaves that should be dropped from the end of the list. - pub truncated: u32, - /// New root as the result of the operation (can be generated one). - pub new_root: EntryLink, -} - impl Tree { fn resolve_link(&self, link: EntryLink) -> Result { match link { @@ -122,6 +104,10 @@ impl Tree { gen += 1; } + for (idx, node) in extra { + result.stored.insert(idx, node); + } + result.root = root; result @@ -147,7 +133,9 @@ impl Tree { } /// Append one leaf to the tree. - pub fn append_leaf(&mut self, new_leaf: NodeData) -> Result { + /// + /// Returns links to actual nodes that has to be persisted as the result of the append. + pub fn append_leaf(&mut self, new_leaf: NodeData) -> Result, Error> { let root = self.root; let new_leaf_link = self.push(new_leaf.into()); let mut appended = Vec::new(); @@ -190,10 +178,7 @@ impl Tree { self.root = new_root; - Ok(AppendTransaction { - new_root, - appended, - }) + Ok(appended) } #[cfg(test)] @@ -214,7 +199,9 @@ impl Tree { } /// Truncate one leaf from the end of the tree. - pub fn truncate_leaf(&mut self) -> Result { + /// + /// Returns actual number of nodes that has to be removed from the array representation. + pub fn truncate_leaf(&mut self) -> Result { let root = { let (leaves, root_left_child) = { let n = self.resolve_link(self.root)?; @@ -226,10 +213,7 @@ impl Tree { if leaves & 1 != 0 { self.pop(); self.root = root_left_child; - return Ok(DeleteTransaction { - truncated: 1, - new_root: root_left_child, - }) + return Ok(1); } else { self.resolve_link(self.root)? } @@ -266,10 +250,7 @@ impl Tree { self.root = new_root; - Ok(DeleteTransaction { - new_root, - truncated, - }) + Ok(truncated) } /// Length of array representation of the tree. @@ -277,11 +258,17 @@ impl Tree { self.stored_count } + /// Link to the root node pub fn root(&self) -> EntryLink { self.root } + + /// Reference to the root ndoe + pub fn root_node(&self) -> Result { + self.resolve_link(self.root) + } } -struct IndexedNode<'a> { +pub struct IndexedNode<'a> { node: &'a Entry, link: EntryLink, } @@ -296,6 +283,10 @@ impl<'a> IndexedNode<'a> { self.node.right().map_err(|e| e.augment(self.link)) } + pub fn node(&self) -> &Entry { + self.node + } + } fn combine_nodes<'a>(left: IndexedNode<'a>, right: IndexedNode<'a>) -> Entry { @@ -345,7 +336,7 @@ mod tests { } } - fn initial() -> (EntryLink, Tree) { + fn initial() -> Tree { let node1: Entry = leaf(1).into(); let node2: Entry = leaf(2).into(); @@ -354,33 +345,29 @@ mod tests { kind: EntryKind::Leaf, }; - (EntryLink::Stored(2), Tree::populate(vec![node1, node2, node3], EntryLink::Stored(2))) + Tree::populate(vec![node1, node2, node3], EntryLink::Stored(2)) } // returns tree with specified number of leafs and it's root - fn generated(length: u32) -> (Tree, EntryLink) { + fn generated(length: u32) -> Tree { assert!(length >= 3); - let (mut root, mut tree) = initial(); + let mut tree = initial(); for i in 2..length { - root = tree - .append_leaf(leaf(i+1).into()) - .expect("Failed to append") - .new_root; + tree.append_leaf(leaf(i+1).into()).expect("Failed to append"); } - (tree, root) + tree } #[test] fn discrete_append() { - let (root, mut tree) = initial(); + let mut tree = initial(); // ** APPEND 3 ** - let append_tx = tree + let appended = tree .append_leaf(leaf(3)) .expect("Failed to append"); - let new_root_link = append_tx.new_root; - let new_root = tree.resolve_link(new_root_link).expect("Failed to resolve root").node; + let new_root = tree.root_node().expect("Failed to resolve root").node; // initial tree: (2) // / \ @@ -396,15 +383,14 @@ mod tests { // so only (3) is added as real leaf // while new root, (4g) is generated one assert_eq!(new_root.data.end_height, 3); - assert_eq!(append_tx.appended.len(), 1); + assert_eq!(appended.len(), 1); // ** APPEND 4 ** - let append_tx = tree + let appended = tree .append_leaf(leaf(4)) .expect("Failed to append"); - let new_root_link = append_tx.new_root; - let new_root = tree.resolve_link(new_root_link).expect("Failed to resolve root").node; + let new_root = tree.root_node().expect("Failed to resolve root").node; // intermediate tree: // (4g) @@ -423,16 +409,15 @@ mod tests { // so (4), (5), (6) are added as real leaves // and new root, (6) is stored one assert_eq!(new_root.data.end_height, 4); - assert_eq!(append_tx.appended.len(), 3); - assert_matches!(new_root_link, EntryLink::Stored(6)); + assert_eq!(appended.len(), 3); + assert_matches!(tree.root(), EntryLink::Stored(6)); // ** APPEND 5 ** - let append_tx = tree + let appended = tree .append_leaf(leaf(5)) .expect("Failed to append"); - let new_root_link = append_tx.new_root; - let new_root = tree.resolve_link(new_root_link).expect("Failed to resolve root").node; + let new_root = tree.root_node().expect("Failed to resolve root").node; // intermediate tree: // ( 6 ) @@ -453,19 +438,18 @@ mod tests { // so (7) is added as real leaf // and new root, (8g) is generated one assert_eq!(new_root.data.end_height, 5); - assert_eq!(append_tx.appended.len(), 1); - assert_matches!(new_root_link, EntryLink::Generated(_)); - tree.for_children(new_root_link, |l, r| { + assert_eq!(appended.len(), 1); + assert_matches!(tree.root(), EntryLink::Generated(_)); + tree.for_children(tree.root(), |l, r| { assert_matches!(l, EntryLink::Stored(6)); assert_matches!(r, EntryLink::Stored(7)); }); // *** APPEND #6 *** - let append_tx = tree + let appended = tree .append_leaf(leaf(6)) .expect("Failed to append"); - let new_root_link = append_tx.new_root; - let new_root = tree.resolve_link(new_root_link).expect("Failed to resolve root").node; + let new_root = tree.root_node().expect("Failed to resolve root").node; // intermediate tree: // ( 8g ) @@ -488,21 +472,20 @@ mod tests { // so (7) is added as real leaf // and new root, (8g) is generated one assert_eq!(new_root.data.end_height, 6); - assert_eq!(append_tx.appended.len(), 2); - assert_matches!(new_root_link, EntryLink::Generated(_)); - tree.for_children(new_root_link, |l, r| { + assert_eq!(appended.len(), 2); + assert_matches!(tree.root(), EntryLink::Generated(_)); + tree.for_children(tree.root(), |l, r| { assert_matches!(l, EntryLink::Stored(6)); assert_matches!(r, EntryLink::Stored(9)); }); // *** APPEND #7 *** - let append_tx = tree + let appended = tree .append_leaf(leaf(7)) .expect("Failed to append"); - let new_root_link = append_tx.new_root; let new_root = tree - .resolve_link(new_root_link) + .root_node() .expect("Failed to resolve root") .node; @@ -529,9 +512,9 @@ mod tests { // so (7) is added as real leaf // and new root, (8g) is generated one assert_eq!(new_root.data.end_height, 7); - assert_eq!(append_tx.appended.len(), 1); - assert_matches!(new_root_link, EntryLink::Generated(_)); - tree.for_children(new_root_link, |l, r| { + assert_eq!(appended.len(), 1); + assert_matches!(tree.root(), EntryLink::Generated(_)); + tree.for_children(tree.root(), |l, r| { assert_matches!(l, EntryLink::Generated(_)); assert_matches!(r, EntryLink::Stored(10)); }); @@ -539,10 +522,8 @@ mod tests { #[test] fn truncate_simple() { - let (mut tree, root) = generated(9); - let delete_tx = tree - .truncate_leaf() - .expect("Failed to truncate"); + let mut tree = generated(9); + tree.truncate_leaf().expect("Failed to truncate"); // initial tree: // @@ -568,16 +549,14 @@ mod tests { // so (15) is truncated // and new root, (14) is a stored one now - assert_matches!(delete_tx.new_root, EntryLink::Stored(14)); + assert_matches!(tree.root(), EntryLink::Stored(14)); assert_eq!(tree.len(), 15); } #[test] fn truncate_generated() { - let (mut tree, root) = generated(10); - let delete_tx = tree - .truncate_leaf() - .expect("Failed to truncate"); + let mut tree = generated(10); + let deleted = tree.truncate_leaf().expect("Failed to truncate"); // initial tree: // @@ -604,11 +583,11 @@ mod tests { // new root is generated - assert_matches!(delete_tx.new_root, EntryLink::Generated(_)); + assert_matches!(tree.root(), EntryLink::Generated(_)); // left is 14 and right is 15 let (left_root_child, right_root_child) = { - let root = tree.resolve_link(delete_tx.new_root).expect("Failed to resolve"); + let root = tree.root_node().expect("Failed to resolve"); ( root.left().expect("Expected node"), @@ -622,21 +601,18 @@ mod tests { ); // two stored nodes should leave us (leaf 16 and no longer needed node 17) - assert_eq!(delete_tx.truncated, 2); + assert_eq!(deleted, 2); assert_eq!(tree.len(), 16); } #[test] fn tree_len() { - let (mut root, mut tree) = initial(); + let mut tree = initial(); assert_eq!(tree.len(), 3); for i in 0..2 { - root = tree - .append_leaf(leaf(i+3)) - .expect("Failed to append") - .new_root; + tree.append_leaf(leaf(i+3)).expect("Failed to append"); } assert_eq!(tree.len(), 7); @@ -647,23 +623,17 @@ mod tests { #[test] fn tree_len_long() { - let (mut root, mut tree) = initial(); + let mut tree = initial(); assert_eq!(tree.len(), 3); for i in 0..4094 { - root = tree - .append_leaf(leaf(i+3)) - .expect("Failed to append") - .new_root; + tree.append_leaf(leaf(i+3)).expect("Failed to append"); } assert_eq!(tree.len(), 8191); // 4096*2-1 (full tree) for _ in 0..2049 { - root = tree - .truncate_leaf() - .expect("Failed to truncate") - .new_root; + tree.truncate_leaf().expect("Failed to truncate"); } assert_eq!(tree.len(), 4083); // 4095 - log2(4096) @@ -675,18 +645,15 @@ mod tests { if number > 1024*1024 { TestResult::discard() } else { - let (mut root, mut tree) = initial(); + let mut tree = initial(); for i in 0..number { - root = tree - .append_leaf(leaf(i+3)) - .expect("Failed to append") - .new_root; + tree.append_leaf(leaf(i+3)).expect("Failed to append"); } for _ in 0..number { - root = tree.truncate_leaf().expect("Failed to truncate").new_root; + tree.truncate_leaf().expect("Failed to truncate"); } - TestResult::from_bool(if let EntryLink::Stored(2) = root { true } else { false }) + TestResult::from_bool(if let EntryLink::Stored(2) = tree.root() { true } else { false }) } } @@ -694,22 +661,13 @@ mod tests { if number > 1024 * 1024 || number < 3 { TestResult::discard() } else { - let (mut root, mut tree) = initial(); + let mut tree = initial(); for i in 1..(number-1) { - root = tree - .append_leaf(leaf(i+2)) - .expect("Failed to append") - .new_root; + tree.append_leaf(leaf(i+2)).expect("Failed to append"); } TestResult::from_bool( - tree - .resolve_link(root) - .expect("Failed to resolve root") - .node - .leaf_count() - == - number as u64 + tree.root_node().expect("no root").node.leaf_count() == number as u64 ) } } @@ -718,17 +676,17 @@ mod tests { if number > 2048 * 2048 || number < 3 { TestResult::discard() } else { - let (mut root, mut tree) = initial(); + let mut tree = initial(); for i in 1..(number-1) { - root = tree.append_leaf(leaf(i+2)).expect("Failed to append").new_root; + tree.append_leaf(leaf(i+2)).expect("Failed to append"); } TestResult::from_bool( if number & number - 1 == 0 { - if let EntryLink::Stored(_) = root { true } + if let EntryLink::Stored(_) = tree.root() { true } else { false } } else { - if let EntryLink::Generated(_) = root { true } + if let EntryLink::Generated(_) = tree.root() { true } else { false } } ) @@ -741,22 +699,22 @@ mod tests { if add > 2048 * 2048 || add < delete { TestResult::discard() } else { - let (mut root, mut tree) = initial(); + let mut tree = initial(); for i in 0..add { - root = tree.append_leaf(leaf(i+3)).expect("Failed to append").new_root; + tree.append_leaf(leaf(i+3)).expect("Failed to append"); } for _ in 0..delete { - root = tree.truncate_leaf().expect("Failed to truncate").new_root; + tree.truncate_leaf().expect("Failed to truncate"); } let total = add - delete + 2; TestResult::from_bool( if total & total - 1 == 0 { - if let EntryLink::Stored(_) = root { true } + if let EntryLink::Stored(_) = tree.root() { true } else { false } } else { - if let EntryLink::Generated(_) = root { true } + if let EntryLink::Generated(_) = tree.root() { true } else { false } } ) @@ -768,12 +726,12 @@ mod tests { if add > 2048 * 2048 || add < delete { TestResult::discard() } else { - let (mut root, mut tree) = initial(); + let mut tree = initial(); for i in 0..add { - root = tree.append_leaf(leaf(i+3)).expect("Failed to append").new_root; + tree.append_leaf(leaf(i+3)).expect("Failed to append"); } for _ in 0..delete { - root = tree.truncate_leaf().expect("Failed to truncate").new_root; + tree.truncate_leaf().expect("Failed to truncate"); } let total = add - delete + 2; From a46ace4c2d2dc83c3ec5fbdc39624b88a22d9455 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 6 Sep 2019 19:19:58 +0300 Subject: [PATCH 154/330] simplify tree preparation --- examples/producer.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/examples/producer.rs b/examples/producer.rs index 5c66985..2ef7598 100644 --- a/examples/producer.rs +++ b/examples/producer.rs @@ -9,18 +9,7 @@ fn prepare_tree(vec: Vec) -> Tree { // integer log2 of (vec.len()+1), -1 let mut h = (32 - ((vec.len()+1) as u32).leading_zeros() - 1)-1; let mut peak_pos = (1 << (h+1)) - 1; - let mut nodes = Vec::new(); - let mut root_peak: Entry = vec[peak_pos-1].clone().into(); - - root_peak.update_siblings( - EntryLink::Stored((peak_pos - (1< Date: Fri, 6 Sep 2019 19:03:12 -0400 Subject: [PATCH 155/330] Migrate ff_derive to proc-macro2 1.0 --- Cargo.lock | 32 ++++++++++++++++---------------- ff/ff_derive/Cargo.toml | 6 +++--- ff/ff_derive/src/lib.rs | 4 ++-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 623bcc0..3e587e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -210,9 +210,9 @@ dependencies = [ "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -400,18 +400,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.30" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" -version = "0.6.13" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -481,12 +481,12 @@ dependencies = [ [[package]] name = "syn" -version = "0.14.9" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -496,7 +496,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-xid" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -613,8 +613,8 @@ dependencies = [ "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "463bf29e7f11344e58c9e01f171470ab15c925c6822ad75028cc1c0e1d1eb63b" "checksum proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38c47dcb1594802de8c02f3b899e2018c78291168a22c281be21ea0fb4796842" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +"checksum proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "175a40b9cf564ce9bf050654633dbf339978706b8ead1a907bb970b63185dd95" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" @@ -622,9 +622,9 @@ dependencies = [ "checksum rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddb525a78d3a0b0e05b6fe0f7df14d7a4dc957944c7b403911ba5a0f1c694967" "checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" -"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" +"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/ff/ff_derive/Cargo.toml b/ff/ff_derive/Cargo.toml index e822460..18ac1bc 100644 --- a/ff/ff_derive/Cargo.toml +++ b/ff/ff_derive/Cargo.toml @@ -16,6 +16,6 @@ proc-macro = true num-bigint = "0.2" num-traits = "0.2" num-integer = "0.1" -proc-macro2 = "0.4" -quote = "0.6" -syn = "0.14" +proc-macro2 = "1" +quote = "1" +syn = "1" diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index 8801a91..7cdaf91 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -91,10 +91,10 @@ fn fetch_wrapped_ident(body: &syn::Data) -> Option { /// Fetch an attribute string from the derived struct. fn fetch_attr(name: &str, attrs: &[syn::Attribute]) -> Option { for attr in attrs { - if let Some(meta) = attr.interpret_meta() { + if let Ok(meta) = attr.parse_meta() { match meta { syn::Meta::NameValue(nv) => { - if nv.ident.to_string() == name { + if nv.path.get_ident().map(|i| i.to_string()) == Some(name.to_string()) { match nv.lit { syn::Lit::Str(ref s) => return Some(s.value()), _ => { From 5d0aa521c2e8d51f4b42e023004d1657d1965051 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sat, 7 Sep 2019 11:19:06 +0300 Subject: [PATCH 156/330] missing deserialization bits --- src/node_data.rs | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/node_data.rs b/src/node_data.rs index d5cec61..ab08d4a 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -1,10 +1,10 @@ -use byteorder::{LittleEndian, WriteBytesExt, ByteOrder}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt, ByteOrder}; use bigint::U256; use blake2::blake2b::Blake2b; /// Node metadata. #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct NodeData { pub consensus_branch_id: u32, pub subtree_commitment: [u8; 32], @@ -91,6 +91,17 @@ impl NodeData { Ok(()) } + fn read_compact(reader: &mut R) -> std::io::Result { + let result = match reader.read_u8()? { + i @ 0..=0xfc => i.into(), + 0xfd => reader.read_u16::()?.into(), + 0xfe => reader.read_u32::()?.into(), + _ => reader.read_u64::()?.into(), + }; + + Ok(result) + } + pub fn write(&self, w: &mut W) -> std::io::Result<()> { w.write_all(&self.subtree_commitment)?; w.write_u32::(self.start_time)?; @@ -110,6 +121,28 @@ impl NodeData { Ok(()) } + pub fn read(&self, consensus_branch_id: u32, r: &mut R) -> std::io::Result { + let mut data = Self::default(); + data.consensus_branch_id = consensus_branch_id; + r.read_exact(&mut data.subtree_commitment)?; + data.start_time = r.read_u32::()?; + data.end_time = r.read_u32::()?; + data.start_target= r.read_u32::()?; + data.end_target= r.read_u32::()?; + r.read_exact(&mut data.start_sapling_root)?; + r.read_exact(&mut data.end_sapling_root)?; + + let mut work_buf = [0u8; 32]; + r.read_exact(&mut work_buf)?; + data.subtree_total_work = U256::from_little_endian(&work_buf); + + data.start_height = Self::read_compact(r)?; + data.end_height = Self::read_compact(r)?; + data.shielded_tx = Self::read_compact(r)?; + + Ok(data) + } + pub fn to_bytes(&self) -> Vec { let mut buf = [0u8; Self::MAX_SERIALIZED_SIZE]; let pos = { From c4f8f8ea0437309b0ae0d5d8bfb013c57c164fd6 Mon Sep 17 00:00:00 2001 From: Niklas Adolfsson Date: Sat, 7 Sep 2019 10:31:01 +0200 Subject: [PATCH 157/330] fix: use rust2018 idioms --- Cargo.toml | 2 +- src/lib.rs | 7 ------- src/tree.rs | 5 +++-- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b2d0d81..6373417 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,4 +12,4 @@ quickcheck = "0.8" derive_more = "0.15" bigint = "4" byteorder = "1" -blake2-rfc = { git = "https://github.com/gtank/blake2-rfc.git", rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" } +blake2 = { package = "blake2-rfc", git = "https://github.com/gtank/blake2-rfc.git", rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" } diff --git a/src/lib.rs b/src/lib.rs index 5c3b673..cac2313 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,13 +2,6 @@ //! //! To be used in zebra and via FFI bindings in zcashd -#[cfg(test)] #[macro_use] extern crate assert_matches; -#[cfg(test)] #[macro_use] extern crate quickcheck; -extern crate derive_more; -extern crate bigint; -extern crate byteorder; -extern crate blake2_rfc as blake2; - mod tree; mod node_data; diff --git a/src/tree.rs b/src/tree.rs index 3e2d4b0..d5210e5 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -300,7 +300,8 @@ fn combine_nodes<'a>(left: IndexedNode<'a>, right: IndexedNode<'a>) -> Entry { mod tests { use super::{Entry, NodeData, Tree, EntryLink, EntryKind}; - use quickcheck::TestResult; + use quickcheck::{quickcheck, TestResult}; + use assert_matches::assert_matches; fn leaf(height: u32) -> NodeData { NodeData { @@ -740,4 +741,4 @@ mod tests { } } } -} \ No newline at end of file +} From 03524ba7d033db79d093fb2de40b47b36cad82eb Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sat, 7 Sep 2019 13:52:19 +0300 Subject: [PATCH 158/330] entry to the dedicated module --- src/entry.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 47 ++--------------------------------------------- 2 files changed, 50 insertions(+), 45 deletions(-) create mode 100644 src/entry.rs diff --git a/src/entry.rs b/src/entry.rs new file mode 100644 index 0000000..da0b131 --- /dev/null +++ b/src/entry.rs @@ -0,0 +1,48 @@ +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt, ByteOrder}; + +use crate::{EntryKind, NodeData, Error, EntryLink}; + +#[derive(Debug)] +pub struct Entry { + pub(crate) kind: EntryKind, + pub(crate) data: NodeData, +} + +impl Entry { + pub fn update_siblings(&mut self, left: EntryLink, right: EntryLink) { + self.kind = EntryKind::Node(left, right); + } + + pub fn complete(&self) -> bool { + let leaves = self.leaf_count(); + leaves & (leaves - 1) == 0 + } + + pub fn leaf_count(&self) -> u64 { + self.data.end_height - self.data.start_height + 1 + } + + pub fn is_leaf(&self) -> bool { + if let EntryKind::Leaf = self.kind { true } else { false } + } + + pub fn left(&self) -> Result { + match self.kind { + EntryKind::Leaf => { Err(Error::ExpectedNode) } + EntryKind::Node(left, _) => Ok(left) + } + } + + pub fn right(&self) -> Result { + match self.kind { + EntryKind::Leaf => { Err(Error::ExpectedNode) } + EntryKind::Node(_, right) => Ok(right) + } + } +} + +impl From for Entry { + fn from(s: NodeData) -> Self { + Entry { kind: EntryKind::Leaf, data: s } + } +} diff --git a/src/lib.rs b/src/lib.rs index cac2313..552dee2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,9 +4,11 @@ mod tree; mod node_data; +mod entry; pub use tree::Tree; pub use node_data::NodeData; +pub use entry::Entry; #[derive(Debug, derive_more::Display)] pub enum Error { @@ -38,51 +40,6 @@ pub enum EntryKind { Node(EntryLink, EntryLink), } -#[derive(Debug)] -pub struct Entry { - kind: EntryKind, - data: NodeData, -} - -impl Entry { - pub fn update_siblings(&mut self, left: EntryLink, right: EntryLink) { - self.kind = EntryKind::Node(left, right); - } - - pub fn complete(&self) -> bool { - let leaves = self.leaf_count(); - leaves & (leaves - 1) == 0 - } - - pub fn leaf_count(&self) -> u64 { - self.data.end_height - self.data.start_height + 1 - } - - pub fn is_leaf(&self) -> bool { - if let EntryKind::Leaf = self.kind { true } else { false } - } - - pub fn left(&self) -> Result { - match self.kind { - EntryKind::Leaf => { Err(Error::ExpectedNode) } - EntryKind::Node(left, _) => Ok(left) - } - } - - pub fn right(&self) -> Result { - match self.kind { - EntryKind::Leaf => { Err(Error::ExpectedNode) } - EntryKind::Node(_, right) => Ok(right) - } - } -} - -impl From for Entry { - fn from(s: NodeData) -> Self { - Entry { kind: EntryKind::Leaf, data: s } - } -} - impl Error { pub (crate) fn augment(self, link: EntryLink) -> Self { match self { From de053e1d8f23ca7ccf60619ef3443d709ad8ff6e Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sat, 7 Sep 2019 14:00:34 +0300 Subject: [PATCH 159/330] reading for Entry --- src/entry.rs | 27 ++++++++++++++++++++++++++- src/node_data.rs | 2 +- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/entry.rs b/src/entry.rs index da0b131..3ed1c71 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1,4 +1,4 @@ -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt, ByteOrder}; +use byteorder::{LittleEndian, ReadBytesExt}; use crate::{EntryKind, NodeData, Error, EntryLink}; @@ -39,6 +39,31 @@ impl Entry { EntryKind::Node(_, right) => Ok(right) } } + + pub fn read(&self, consensus_branch_id: u32, r: &mut R) -> std::io::Result { + let kind = { + match r.read_u8()? { + 0 => { + let left = r.read_u32::()?; + let right = r.read_u32::()?; + EntryKind::Node(EntryLink::Stored(left), EntryLink::Stored(right)) + }, + 1 => { + EntryKind::Leaf + }, + _ => { + return Err(std::io::Error::from(std::io::ErrorKind::InvalidData)) + }, + } + }; + + let data = NodeData::read(consensus_branch_id, r)?; + + Ok(Entry { + kind, + data, + }) + } } impl From for Entry { diff --git a/src/node_data.rs b/src/node_data.rs index ab08d4a..b95f643 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -121,7 +121,7 @@ impl NodeData { Ok(()) } - pub fn read(&self, consensus_branch_id: u32, r: &mut R) -> std::io::Result { + pub fn read(consensus_branch_id: u32, r: &mut R) -> std::io::Result { let mut data = Self::default(); data.consensus_branch_id = consensus_branch_id; r.read_exact(&mut data.subtree_commitment)?; From 49763d1c0189713f4c9e51827cb31b9574361355 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sat, 7 Sep 2019 14:04:51 +0300 Subject: [PATCH 160/330] arrange constants --- examples/producer.rs | 1 - src/entry.rs | 4 +++- src/lib.rs | 4 ++-- src/node_data.rs | 8 ++++---- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/examples/producer.rs b/examples/producer.rs index 2ef7598..7d93cba 100644 --- a/examples/producer.rs +++ b/examples/producer.rs @@ -204,5 +204,4 @@ fn main() { let tree = prepare_tree(initial_tree_vec); println!("root: {}", tree.root()); - } \ No newline at end of file diff --git a/src/entry.rs b/src/entry.rs index 3ed1c71..485b364 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1,6 +1,8 @@ use byteorder::{LittleEndian, ReadBytesExt}; -use crate::{EntryKind, NodeData, Error, EntryLink}; +use crate::{EntryKind, NodeData, Error, EntryLink, MAX_NODE_DATA_SIZE}; + +pub const MAX_ENTRY_SIZE: usize = MAX_NODE_DATA_SIZE + 9; #[derive(Debug)] pub struct Entry { diff --git a/src/lib.rs b/src/lib.rs index 552dee2..f0eb3f4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,8 @@ mod node_data; mod entry; pub use tree::Tree; -pub use node_data::NodeData; -pub use entry::Entry; +pub use node_data::{NodeData, MAX_NODE_DATA_SIZE}; +pub use entry::{Entry, MAX_ENTRY_SIZE}; #[derive(Debug, derive_more::Display)] pub enum Error { diff --git a/src/node_data.rs b/src/node_data.rs index b95f643..59591e5 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -2,6 +2,8 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt, ByteOrder}; use bigint::U256; use blake2::blake2b::Blake2b; +pub const MAX_NODE_DATA_SIZE: usize = 32 + 4 + 4 + 4 + 4 + 32 + 32 + 32 + 9 + 9 + 9; // 171 + /// Node metadata. #[repr(C)] #[derive(Debug, Clone, Default)] @@ -36,12 +38,10 @@ fn personalization(branch_id: u32) -> [u8; 16] { } impl NodeData { - pub const MAX_SERIALIZED_SIZE: usize = 32 + 4 + 4 + 4 + 4 + 32 + 32 + 32 + 9 + 9 + 9; // =171; - pub fn combine(left: &NodeData, right: &NodeData) -> NodeData { assert_eq!(left.consensus_branch_id, right.consensus_branch_id); - let mut hash_buf = [0u8; Self::MAX_SERIALIZED_SIZE * 2]; + let mut hash_buf = [0u8; MAX_NODE_DATA_SIZE * 2]; let size = { let mut cursor = ::std::io::Cursor::new(&mut hash_buf[..]); left.write(&mut cursor).expect("Writing to memory buf with enough length cannot fail; qed"); @@ -144,7 +144,7 @@ impl NodeData { } pub fn to_bytes(&self) -> Vec { - let mut buf = [0u8; Self::MAX_SERIALIZED_SIZE]; + let mut buf = [0u8; MAX_NODE_DATA_SIZE]; let pos = { let mut cursor = std::io::Cursor::new(&mut buf[..]); self.write(&mut cursor).expect("Cursor cannot fail"); From 6d9deefb934f11c91f751618fd86a5a0dbe86570 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sat, 7 Sep 2019 14:10:08 +0300 Subject: [PATCH 161/330] fix read and add from_bytes --- src/entry.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/entry.rs b/src/entry.rs index 485b364..59663fc 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -42,7 +42,7 @@ impl Entry { } } - pub fn read(&self, consensus_branch_id: u32, r: &mut R) -> std::io::Result { + pub fn read(consensus_branch_id: u32, r: &mut R) -> std::io::Result { let kind = { match r.read_u8()? { 0 => { @@ -66,6 +66,11 @@ impl Entry { data, }) } + + pub fn from_bytes(consensus_branch_id: u32, buf: &[u8]) -> std::io::Result { + let mut cursor = std::io::Cursor::new(buf); + Self::read(consensus_branch_id, &mut cursor) + } } impl From for Entry { From a9d2ce71505bd50b98ebb6278b9ecdd7e5420f56 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sat, 7 Sep 2019 18:15:18 +0300 Subject: [PATCH 162/330] from_bytes for NodeData --- src/node_data.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/node_data.rs b/src/node_data.rs index 59591e5..fd01c3a 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -153,4 +153,9 @@ impl NodeData { buf[0..pos].to_vec() } + + pub fn from_bytes(consensus_branch_id: u32, buf: &[u8]) -> std::io::Result { + let mut cursor = std::io::Cursor::new(buf); + Self::read(consensus_branch_id, &mut cursor) + } } \ No newline at end of file From ad403f1cca1c6cd5a6f1ddfce4f3bdc89a290fd8 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sat, 7 Sep 2019 18:22:37 +0300 Subject: [PATCH 163/330] add data reader --- src/tree.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tree.rs b/src/tree.rs index d5210e5..c4ab982 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -287,6 +287,9 @@ impl<'a> IndexedNode<'a> { self.node } + pub fn data(&self) -> &NodeData { + &self.node.data + } } fn combine_nodes<'a>(left: IndexedNode<'a>, right: IndexedNode<'a>) -> Entry { From 0bfd1d6b0d1aaaad4c5f4c3e97243cd9f5495bdc Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sat, 7 Sep 2019 18:30:57 +0300 Subject: [PATCH 164/330] resolve_link is of course public --- src/tree.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tree.rs b/src/tree.rs index c4ab982..36c3e4e 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -24,7 +24,7 @@ pub struct Tree { } impl Tree { - fn resolve_link(&self, link: EntryLink) -> Result { + pub fn resolve_link(&self, link: EntryLink) -> Result { match link { EntryLink::Generated(index) => { let node = self.generated.get(&index).ok_or(Error::ExpectedInMemory(link))?; From 0afa12297043e3abab6a81fad988603153105db3 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sat, 7 Sep 2019 19:18:49 +0300 Subject: [PATCH 165/330] add .travis.yml --- src/.travis.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/.travis.yml diff --git a/src/.travis.yml b/src/.travis.yml new file mode 100644 index 0000000..00e7694 --- /dev/null +++ b/src/.travis.yml @@ -0,0 +1,4 @@ +language: rust +rust: +- nightly +- stable \ No newline at end of file From 9470610b754accee4de274acfda37b2a6d07ec71 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sat, 7 Sep 2019 19:23:13 +0300 Subject: [PATCH 166/330] license and readme --- LICENSE-APACHE | 201 +++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE-MIT | 25 ++++++ README.md | 19 ++++- 3 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +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. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..5ee6ad6 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2019 Nikolay Volf + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 6eefe94..db76689 100644 --- a/README.md +++ b/README.md @@ -1 +1,18 @@ -# zcash-mmr \ No newline at end of file +# zcash-mmr + +Special implementation of merkle mountain ranges (MMR) for ZCash! + +[![Build Status](https://travis-ci.org/NikVolf/zcash-mmr.svg?branch=master)](https://travis-ci.org/NikVolf/zcash-mmr) + +# License + +`zcash-mmr` is primarily distributed under the terms of both the MIT +license and the Apache License (Version 2.0), at your choice. + +See LICENSE-APACHE, and LICENSE-MIT for details. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in `zcash-mmr` by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. From c87122561f5ca9fa25a2ab634ffde3dca2c95ebc Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sun, 8 Sep 2019 00:17:40 +0300 Subject: [PATCH 167/330] add .travis.yml --- src/.travis.yml => .travis.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/.travis.yml => .travis.yml (100%) diff --git a/src/.travis.yml b/.travis.yml similarity index 100% rename from src/.travis.yml rename to .travis.yml From a5c4d51652a08876aec2a69a1b420f22f8109879 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sun, 8 Sep 2019 09:32:47 +0300 Subject: [PATCH 168/330] improve on api --- src/entry.rs | 2 +- src/node_data.rs | 2 +- src/tree.rs | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/entry.rs b/src/entry.rs index 59663fc..982b879 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -67,7 +67,7 @@ impl Entry { }) } - pub fn from_bytes(consensus_branch_id: u32, buf: &[u8]) -> std::io::Result { + pub fn from_bytes>(consensus_branch_id: u32, buf: T) -> std::io::Result { let mut cursor = std::io::Cursor::new(buf); Self::read(consensus_branch_id, &mut cursor) } diff --git a/src/node_data.rs b/src/node_data.rs index fd01c3a..dcc8ded 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -154,7 +154,7 @@ impl NodeData { buf[0..pos].to_vec() } - pub fn from_bytes(consensus_branch_id: u32, buf: &[u8]) -> std::io::Result { + pub fn from_bytes>(consensus_branch_id: u32, buf: T) -> std::io::Result { let mut cursor = std::io::Cursor::new(buf); Self::read(consensus_branch_id, &mut cursor) } diff --git a/src/tree.rs b/src/tree.rs index 36c3e4e..b816287 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -267,7 +267,7 @@ impl Tree { } } - +#[derive(Debug)] pub struct IndexedNode<'a> { node: &'a Entry, link: EntryLink, @@ -290,6 +290,10 @@ impl<'a> IndexedNode<'a> { pub fn data(&self) -> &NodeData { &self.node.data } + + pub fn link(&self) -> EntryLink { + self.link + } } fn combine_nodes<'a>(left: IndexedNode<'a>, right: IndexedNode<'a>) -> Entry { From b73f49c96835b455b3d8203d1c70458fe99e078a Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 9 Sep 2019 11:50:41 +0300 Subject: [PATCH 169/330] add optional file generation --- examples/producer.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/examples/producer.rs b/examples/producer.rs index 7d93cba..1bc5824 100644 --- a/examples/producer.rs +++ b/examples/producer.rs @@ -1,8 +1,7 @@ -extern crate zcash_mmr as mmr; +use zcash_mmr::{NodeData, Tree, EntryLink, Entry}; +use std::io::Write; -use mmr::{NodeData, Tree, EntryLink, Entry}; - -fn prepare_tree(vec: Vec) -> Tree { +fn prepare_tree(vec: &Vec) -> Tree { assert!(vec.len() > 0); @@ -202,6 +201,22 @@ fn main() { }, ); - let tree = prepare_tree(initial_tree_vec); + let tree = prepare_tree(&initial_tree_vec); + + let mut buf = Vec::new(); + if let Some(out_file_path) = ::std::env::args().nth(1) { + for node in initial_tree_vec.into_iter() { + node.write(&mut buf); + } + + let mut file = std::fs::File::create(&out_file_path) + .expect("Failed to create output file"); + + file.write_all(&buf[..]) + .expect("Failed to write data to file"); + } + println!("root: {}", tree.root()); + + } \ No newline at end of file From 636f3e3751a4d95a2c2d4ceaa3e985f3d9ed1333 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 9 Sep 2019 11:52:57 +0300 Subject: [PATCH 170/330] update readme --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index db76689..6f75346 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,14 @@ Special implementation of merkle mountain ranges (MMR) for ZCash! [![Build Status](https://travis-ci.org/NikVolf/zcash-mmr.svg?branch=master)](https://travis-ci.org/NikVolf/zcash-mmr) +The main design goals of this mmr implementation were + +- Allow zero-cache and avoid db callbacks. As it is implemented, calling side must just smartly pre-load MMR nodes from the database (about log2(tree length) for append, twice as much for deletion). + +- Reuse as much logic between rust and c++ clients and place it here and librustzcash. + +- Close to zero memory consumption. + # License `zcash-mmr` is primarily distributed under the terms of both the MIT From 96b130e034cc277586f27879a17a8d974f9f6193 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 9 Sep 2019 14:06:05 +0300 Subject: [PATCH 171/330] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6f75346..26532bb 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Special implementation of merkle mountain ranges (MMR) for ZCash! [![Build Status](https://travis-ci.org/NikVolf/zcash-mmr.svg?branch=master)](https://travis-ci.org/NikVolf/zcash-mmr) -The main design goals of this mmr implementation were +The main design goals of this mmr implementation are - Allow zero-cache and avoid db callbacks. As it is implemented, calling side must just smartly pre-load MMR nodes from the database (about log2(tree length) for append, twice as much for deletion). From a0c33945ab3b534eb47ab0f000bbf15972b24b06 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 9 Sep 2019 14:33:49 +0300 Subject: [PATCH 172/330] write for entry --- examples/producer.rs | 2 +- src/entry.rs | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/examples/producer.rs b/examples/producer.rs index 1bc5824..108bc25 100644 --- a/examples/producer.rs +++ b/examples/producer.rs @@ -206,7 +206,7 @@ fn main() { let mut buf = Vec::new(); if let Some(out_file_path) = ::std::env::args().nth(1) { for node in initial_tree_vec.into_iter() { - node.write(&mut buf); + node.write(&mut buf).expect("Failed to write data"); } let mut file = std::fs::File::create(&out_file_path) diff --git a/src/entry.rs b/src/entry.rs index 982b879..72582c2 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1,4 +1,4 @@ -use byteorder::{LittleEndian, ReadBytesExt}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use crate::{EntryKind, NodeData, Error, EntryLink, MAX_NODE_DATA_SIZE}; @@ -67,6 +67,24 @@ impl Entry { }) } + pub fn write(&self, w: &mut W) -> std::io::Result<()> { + match self.kind { + EntryKind::Node(EntryLink::Stored(left), EntryLink::Stored(right)) => { + w.write_u8(0)?; + w.write_u32::(left)?; + w.write_u32::(right)?; + }, + EntryKind::Leaf => { + w.write_u8(1)?; + }, + _ => { return Err(std::io::Error::from(std::io::ErrorKind::InvalidData)); } + } + + self.data.write(w)?; + + Ok(()) + } + pub fn from_bytes>(consensus_branch_id: u32, buf: T) -> std::io::Result { let mut cursor = std::io::Cursor::new(buf); Self::read(consensus_branch_id, &mut cursor) From f5c1381c4c644f76a298534f74e200a0b86a080d Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 9 Sep 2019 18:23:00 +0300 Subject: [PATCH 173/330] arrange data generator example properly --- examples/producer.rs | 222 ------------------------------------- examples/producer/main.rs | 4 + examples/producer/share.rs | 75 +++++++++++++ examples/write.rs | 41 +++++++ 4 files changed, 120 insertions(+), 222 deletions(-) delete mode 100644 examples/producer.rs create mode 100644 examples/producer/main.rs create mode 100644 examples/producer/share.rs create mode 100644 examples/write.rs diff --git a/examples/producer.rs b/examples/producer.rs deleted file mode 100644 index 108bc25..0000000 --- a/examples/producer.rs +++ /dev/null @@ -1,222 +0,0 @@ -use zcash_mmr::{NodeData, Tree, EntryLink, Entry}; -use std::io::Write; - -fn prepare_tree(vec: &Vec) -> Tree { - - assert!(vec.len() > 0); - - // integer log2 of (vec.len()+1), -1 - let mut h = (32 - ((vec.len()+1) as u32).leading_zeros() - 1)-1; - let mut peak_pos = (1 << (h+1)) - 1; - let mut nodes = Vec::new(); - - loop { - - if peak_pos > vec.len() { - // left child, -2^h - peak_pos = peak_pos - (1<, + tree: Tree, + cursor: usize, + leaf_cursor: usize, +} + +impl Iterator for NodeDataIterator { + type Item = NodeData; + + fn next(&mut self) -> Option { + let result = if self.cursor == 1 { + self.leaf_cursor = 2; + Some(leaf(1)) + } else if self.cursor == 2 { + self.leaf_cursor = 3; + Some(leaf(2)) + } else if self.cursor == 3 { + Some(self.tree.root_node().expect("always exists").data().clone()) + } else if self.return_stack.len() > 0 { + self.return_stack.pop() + } else { + for n_append in + self.tree.append_leaf(leaf(self.leaf_cursor as u32)) + .expect("full tree cannot fail").into_iter().rev() + { + self.return_stack.push(self.tree.resolve_link(n_append).expect("just pushed").data().clone()) + } + self.leaf_cursor += 1; + self.return_stack.pop() + }; + + self.cursor += 1; + result + } +} + +impl NodeDataIterator { + pub fn new() -> Self { + let mut root: Entry = NodeData::combine(&leaf(1), &leaf(2)).into(); + root.update_siblings(EntryLink::Stored(0), EntryLink::Stored(1)); + let tree = + Tree::new( + 3, + vec![(2, root)], + vec![(0, leaf(1).into()), (1, leaf(2).into())] + ); + + NodeDataIterator { + return_stack: Vec::new(), + tree, + cursor: 1, + leaf_cursor: 1, + } + } +} + +fn leaf(height: u32) -> NodeData { + NodeData { + consensus_branch_id: 0, + subtree_commitment: [0u8; 32], + start_time: height*10+1, + end_time: (height+1)*10, + start_target: 100 + height*10, + end_target: 100 + (height+1)*10, + start_sapling_root: [0u8; 32], + end_sapling_root: [0u8; 32], + subtree_total_work: 0.into(), + start_height: height as u64, + end_height: height as u64, + shielded_tx: 5 + height as u64, + } +} diff --git a/examples/write.rs b/examples/write.rs new file mode 100644 index 0000000..f51e2a7 --- /dev/null +++ b/examples/write.rs @@ -0,0 +1,41 @@ +#[path= "producer/share.rs"] +mod share; + +// Test data generator +// $ cargo run --example writer -- 16 nodes.dat +// or +// $ cargo run --example writer -- 16 +// to preview + +fn main() { + let mut args = std::env::args().skip(1); + + let (number, out_file) = match args.next() { + None => { eprintln!("writer []"); std::process::exit(1); }, + Some(number) => { + (number.parse::().expect("invalid number"), args.next()) + } + }; + + let iterator = share::NodeDataIterator::new().take(number); + + if let Some(out_file_path) = out_file { + use std::io::Write; + + let mut buf = Vec::new(); + + for node in iterator{ + node.write(&mut buf).expect("Failed to write data"); + } + + let mut file = std::fs::File::create(&out_file_path) + .expect("Failed to create output file"); + + file.write_all(&buf[..]) + .expect("Failed to write data to file"); + } else { + for n in iterator { + println!("{:?}", n); + } + } +} \ No newline at end of file From 4ec651d172900a112500e9359964bb6a50fc2a5e Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 9 Sep 2019 18:28:23 +0300 Subject: [PATCH 174/330] update naming --- examples/{producer => lib}/main.rs | 0 examples/{producer/share.rs => lib/shared.rs} | 0 examples/write.rs | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename examples/{producer => lib}/main.rs (100%) rename examples/{producer/share.rs => lib/shared.rs} (100%) diff --git a/examples/producer/main.rs b/examples/lib/main.rs similarity index 100% rename from examples/producer/main.rs rename to examples/lib/main.rs diff --git a/examples/producer/share.rs b/examples/lib/shared.rs similarity index 100% rename from examples/producer/share.rs rename to examples/lib/shared.rs diff --git a/examples/write.rs b/examples/write.rs index f51e2a7..c029a85 100644 --- a/examples/write.rs +++ b/examples/write.rs @@ -1,4 +1,4 @@ -#[path= "producer/share.rs"] +#[path= "lib/shared.rs"] mod share; // Test data generator From 79cba2e500b29f77cacfe0fcc68402d221f2330d Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 10 Sep 2019 12:51:23 +0300 Subject: [PATCH 175/330] run against long examples --- examples/long.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 examples/long.rs diff --git a/examples/long.rs b/examples/long.rs new file mode 100644 index 0000000..bb2f2d4 --- /dev/null +++ b/examples/long.rs @@ -0,0 +1,73 @@ +use zcash_mmr::{Entry, EntryLink, NodeData, Tree}; + +#[path= "lib/shared.rs"] +mod share; + +fn prepare_tree(vec: &Vec) -> Tree { + + assert!(vec.len() > 0); + + // integer log2 of (vec.len()+1), -1 + let mut h = (32 - ((vec.len()+1) as u32).leading_zeros() - 1)-1; + let mut peak_pos = (1 << (h+1)) - 1; + let mut nodes = Vec::new(); + + loop { + + if peak_pos > vec.len() { + // left child, -2^h + peak_pos = peak_pos - (1< { eprintln!("writer []"); std::process::exit(1); }, + Some(number) => { + number.parse::().expect("invalid number") + } + }; + + let long_vec = share::NodeDataIterator::new().take(number) + .collect::>(); + + let now = std::time::Instant::now(); + + let tree = prepare_tree(&long_vec); + + println!("Tree final root: {}-{}", + tree.root_node().expect("root").data().start_height, + tree.root_node().expect("root").data().end_height, + ); + + println!("Prepare tree of {} length: {} ns / {} mcs / {} ms", + number, + now.elapsed().as_nanos(), now.elapsed().as_micros(), now.elapsed().as_millis() + ); +} From 89dad572efeb7294c1c89e25a4a8f40223913f88 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 12 Sep 2019 19:10:46 +0100 Subject: [PATCH 176/330] Migrate bellman to crossbeam 0.7 --- Cargo.lock | 105 ++++++++++++++++++++++++++++++- bellman/Cargo.toml | 2 +- bellman/src/domain.rs | 14 ++--- bellman/src/groth16/generator.rs | 6 +- bellman/src/multicore.rs | 8 ++- 5 files changed, 118 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3e587e4..791e0a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,7 +59,7 @@ dependencies = [ "bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "blake2s_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -156,8 +156,63 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crossbeam" -version = "0.3.2" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-channel" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-queue" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "crypto_api" @@ -325,6 +380,14 @@ dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "memoffset" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nodrop" version = "0.1.13" @@ -468,6 +531,32 @@ dependencies = [ "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scopeguard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "sha2" version = "0.8.0" @@ -587,7 +676,12 @@ dependencies = [ "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" -"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" +"checksum crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2d818a4990769aac0c7ff1360e233ef3a41adcb009ebb2036bf6915eb0f6b23c" +"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" +"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" +"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" +"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" +"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum crypto_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f855e87e75a4799e18b8529178adcde6fd4f97c1449ff4821e747ff728bb102" "checksum crypto_api_chachapoly 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95b2ad7cab08fd71addba81df5077c49df208effdfb3118a1519f9cdeac5aaf2" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" @@ -604,6 +698,7 @@ dependencies = [ "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)" = "c665266eb592905e8503ba3403020f4b8794d26263f412ca33171600eca9a6fa" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "57450397855d951f1a41305e54851b1a7b8f5d2e349543a02a2effe25459f718" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" @@ -621,6 +716,10 @@ dependencies = [ "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddb525a78d3a0b0e05b6fe0f7df14d7a4dc957944c7b403911ba5a0f1c694967" "checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" diff --git a/bellman/Cargo.toml b/bellman/Cargo.toml index f21e4e1..c27a1dc 100644 --- a/bellman/Cargo.toml +++ b/bellman/Cargo.toml @@ -17,7 +17,7 @@ futures = "0.1" futures-cpupool = { version = "0.1", optional = true } group = { path = "../group" } num_cpus = { version = "1", optional = true } -crossbeam = { version = "0.3", optional = true } +crossbeam = { version = "0.7", optional = true } pairing = { path = "../pairing", optional = true } rand_core = "0.5" byteorder = "1" diff --git a/bellman/src/domain.rs b/bellman/src/domain.rs index d5a86bd..c636855 100644 --- a/bellman/src/domain.rs +++ b/bellman/src/domain.rs @@ -91,7 +91,7 @@ impl> EvaluationDomain { let minv = self.minv; for v in self.coeffs.chunks_mut(chunk) { - scope.spawn(move || { + scope.spawn(move |_scope| { for v in v { v.group_mul_assign(&minv); } @@ -103,7 +103,7 @@ impl> EvaluationDomain { pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr) { worker.scope(self.coeffs.len(), |scope, chunk| { for (i, v) in self.coeffs.chunks_mut(chunk).enumerate() { - scope.spawn(move || { + scope.spawn(move |_scope| { let mut u = g.pow(&[(i * chunk) as u64]); for v in v.iter_mut() { v.group_mul_assign(&u); @@ -146,7 +146,7 @@ impl> EvaluationDomain { worker.scope(self.coeffs.len(), |scope, chunk| { for v in self.coeffs.chunks_mut(chunk) { - scope.spawn(move || { + scope.spawn(move |_scope| { for v in v { v.group_mul_assign(&i); } @@ -165,7 +165,7 @@ impl> EvaluationDomain { .chunks_mut(chunk) .zip(other.coeffs.chunks(chunk)) { - scope.spawn(move || { + scope.spawn(move |_scope| { for (a, b) in a.iter_mut().zip(b.iter()) { a.group_mul_assign(&b.0); } @@ -184,7 +184,7 @@ impl> EvaluationDomain { .chunks_mut(chunk) .zip(other.coeffs.chunks(chunk)) { - scope.spawn(move || { + scope.spawn(move |_scope| { for (a, b) in a.iter_mut().zip(b.iter()) { a.group_sub_assign(&b); } @@ -335,7 +335,7 @@ fn parallel_fft>( let a = &*a; for (j, tmp) in tmp.iter_mut().enumerate() { - scope.spawn(move || { + scope.spawn(move |_scope| { // Shuffle into a sub-FFT let omega_j = omega.pow(&[j as u64]); let omega_step = omega.pow(&[(j as u64) << log_new_n]); @@ -363,7 +363,7 @@ fn parallel_fft>( let tmp = &tmp; for (idx, a) in a.chunks_mut(chunk).enumerate() { - scope.spawn(move || { + scope.spawn(move |_scope| { let mut idx = idx * chunk; let mask = (1 << log_cpus) - 1; for a in a { diff --git a/bellman/src/groth16/generator.rs b/bellman/src/groth16/generator.rs index 7ca6c9a..767eddd 100644 --- a/bellman/src/groth16/generator.rs +++ b/bellman/src/groth16/generator.rs @@ -227,7 +227,7 @@ where let powers_of_tau = powers_of_tau.as_mut(); worker.scope(powers_of_tau.len(), |scope, chunk| { for (i, powers_of_tau) in powers_of_tau.chunks_mut(chunk).enumerate() { - scope.spawn(move || { + scope.spawn(move |_scope| { let mut current_tau_power = tau.pow(&[(i * chunk) as u64]); for p in powers_of_tau { @@ -251,7 +251,7 @@ where { let mut g1_wnaf = g1_wnaf.shared(); - scope.spawn(move || { + scope.spawn(move |_scope| { // Set values of the H query to g1^{(tau^i * t(tau)) / delta} for (h, p) in h.iter_mut().zip(p.iter()) { // Compute final exponent @@ -330,7 +330,7 @@ where let mut g1_wnaf = g1_wnaf.shared(); let mut g2_wnaf = g2_wnaf.shared(); - scope.spawn(move || { + scope.spawn(move |_scope| { for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a .iter_mut() .zip(b_g1.iter_mut()) diff --git a/bellman/src/multicore.rs b/bellman/src/multicore.rs index 7ebc89a..ff97e06 100644 --- a/bellman/src/multicore.rs +++ b/bellman/src/multicore.rs @@ -6,7 +6,7 @@ #[cfg(feature = "multicore")] mod implementation { - use crossbeam::{self, Scope}; + use crossbeam::{self, thread::Scope}; use futures::{Future, IntoFuture, Poll}; use futures_cpupool::{CpuFuture, CpuPool}; use num_cpus; @@ -59,7 +59,9 @@ mod implementation { elements / self.cpus }; + // TODO: Handle case where threads fail crossbeam::scope(|scope| f(scope, chunk_size)) + .expect("Threads aren't allowed to fail yet") } } @@ -152,8 +154,8 @@ mod implementation { pub struct DummyScope; impl DummyScope { - pub fn spawn(&self, f: F) { - f(); + pub fn spawn(&self, f: F) { + f(self); } } } From 0a3b0a93413290f625b9b8c9741ae1336bd3f2e9 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 12 Sep 2019 19:17:09 +0100 Subject: [PATCH 177/330] Upgrade to hex-literal 0.2 --- Cargo.lock | 32 ++++++++++++++------------------ bellman/Cargo.toml | 2 +- zcash_primitives/Cargo.toml | 2 +- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 791e0a0..a2b8298 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,7 +64,7 @@ dependencies = [ "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "group 0.1.0", - "hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -329,19 +329,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hex-literal" -version = "0.1.4" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hex-literal-impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal-impl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hex-literal-impl" -version = "0.1.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -450,17 +450,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro-hack" -version = "0.4.2" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "proc-macro-hack-impl" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "proc-macro2" version = "1.0.2" @@ -630,7 +627,7 @@ dependencies = [ "ff 0.4.0", "fpe 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", @@ -693,8 +690,8 @@ dependencies = [ "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "34f33de6f0ae7c9cb5e574502a562e2b512799e32abb801cd1e79ad952b62b49" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" -"checksum hex-literal 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc2928beef125e519d69ae1baa8c37ea2e0d3848545217f6db0179c5eb1d639" -"checksum hex-literal-impl 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "520870c3213943eb8d7803e80180d12a6c7ceb4ae74602544529d1643dc4ddda" +"checksum hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0" +"checksum hex-literal-impl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9d4c5c844e2fee0bf673d54c2c177f1713b3d2af2ff6e666b49cb7572e6cf42d" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)" = "c665266eb592905e8503ba3403020f4b8794d26263f412ca33171600eca9a6fa" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" @@ -706,8 +703,7 @@ dependencies = [ "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" -"checksum proc-macro-hack 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "463bf29e7f11344e58c9e01f171470ab15c925c6822ad75028cc1c0e1d1eb63b" -"checksum proc-macro-hack-impl 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38c47dcb1594802de8c02f3b899e2018c78291168a22c281be21ea0fb4796842" +"checksum proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e688f31d92ffd7c1ddc57a1b4e6d773c0f2a14ee437a4b0a4f5a69c80eb221c8" "checksum proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "175a40b9cf564ce9bf050654633dbf339978706b8ead1a907bb970b63185dd95" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" diff --git a/bellman/Cargo.toml b/bellman/Cargo.toml index c27a1dc..fe2a55a 100644 --- a/bellman/Cargo.toml +++ b/bellman/Cargo.toml @@ -23,7 +23,7 @@ rand_core = "0.5" byteorder = "1" [dev-dependencies] -hex-literal = "0.1" +hex-literal = "0.2" rand = "0.7" rand_xorshift = "0.2" sha2 = "0.8" diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index 7019dec..22e4aca 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -24,5 +24,5 @@ rand_os = "0.2" sha2 = "0.8" [dev-dependencies] -hex-literal = "0.1" +hex-literal = "0.2" rand_xorshift = "0.2" From b397a9c40528f25ab09bdfb4db833861eff3c2d0 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 12 Sep 2019 19:18:11 +0100 Subject: [PATCH 178/330] cargo update --- Cargo.lock | 160 ++++++++++++++++++++++++++++------------------------- 1 file changed, 84 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a2b8298..d4ade10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,7 +44,7 @@ dependencies = [ [[package]] name = "autocfg" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -57,18 +57,18 @@ name = "bellman" version = "0.1.0" dependencies = [ "bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2s_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "group 0.1.0", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -80,22 +80,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "blake2b_simd" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "blake2s_simd" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -140,7 +140,7 @@ name = "c2-chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -151,7 +151,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "constant_time_eq" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -192,7 +192,7 @@ dependencies = [ "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -211,7 +211,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -240,8 +240,8 @@ name = "directories" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -255,17 +255,17 @@ version = "0.4.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff_derive 0.3.0", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ff_derive" version = "0.3.0" dependencies = [ - "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -277,14 +277,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -292,7 +292,7 @@ name = "futures-cpupool" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -301,16 +301,17 @@ name = "generic-array" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "getrandom" -version = "0.1.8" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -346,12 +347,12 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.61" +version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -359,15 +360,15 @@ name = "librustzcash" version = "0.1.0" dependencies = [ "bellman 0.1.0", - "blake2b_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2s_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "zcash_primitives 0.0.0", "zcash_proofs 0.0.0", ] @@ -395,9 +396,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num-bigint" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -407,7 +409,7 @@ name = "num-integer" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -416,7 +418,7 @@ name = "num-traits" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -424,7 +426,7 @@ name = "num_cpus" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -439,7 +441,7 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "group 0.1.0", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -453,14 +455,14 @@ name = "proc-macro-hack" version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "proc-macro2" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -471,7 +473,7 @@ name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -479,10 +481,10 @@ name = "rand" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -492,15 +494,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -508,16 +510,16 @@ name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_os" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -525,7 +527,7 @@ name = "rand_xorshift" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -570,14 +572,14 @@ name = "syn" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "typenum" -version = "1.10.0" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -585,9 +587,14 @@ name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wasi" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -610,7 +617,7 @@ version = "0.0.0" dependencies = [ "bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "zcash_primitives 0.0.0", ] @@ -620,20 +627,20 @@ name = "zcash_primitives" version = "0.0.0" dependencies = [ "aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2s_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto_api_chachapoly 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "fpe 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -643,13 +650,13 @@ name = "zcash_proofs" version = "0.0.0" dependencies = [ "bellman 0.1.0", - "blake2b_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.4.0", "pairing 0.14.2", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "zcash_primitives 0.0.0", ] @@ -660,11 +667,11 @@ dependencies = [ "checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" -"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" +"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" "checksum bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0089c35ab7c6f2bc55ab23f769913f0ac65b1023e7e74638a1f43128dd5df2" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" -"checksum blake2b_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "461f4b879a8eb70c1debf7d0788a9a5ff15f1ea9d25925fea264ef4258bed6b2" -"checksum blake2s_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3a84d2614b18a5367d357331a90fd533d5ceb1e86abc319320df2104ab744c2a" +"checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182" +"checksum blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "979da0ce13c897d6be19e005ea77ac12b0fea0157aeeee7feb8c49f91386f0ea" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" "checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" @@ -672,7 +679,7 @@ dependencies = [ "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" +"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" "checksum crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2d818a4990769aac0c7ff1360e233ef3a41adcb009ebb2036bf6915eb0f6b23c" "checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" @@ -685,32 +692,32 @@ dependencies = [ "checksum directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72d337a64190607d4fcca2cb78982c5dd57f4916e19696b48a575fa746b6cb0f" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fpe 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21988a326139165b75e3196bc6962ca638e5fb0c95102fbf152a3743174b01e4" -"checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869" +"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -"checksum getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "34f33de6f0ae7c9cb5e574502a562e2b512799e32abb801cd1e79ad952b62b49" +"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0" "checksum hex-literal-impl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9d4c5c844e2fee0bf673d54c2c177f1713b3d2af2ff6e666b49cb7572e6cf42d" -"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)" = "c665266eb592905e8503ba3403020f4b8794d26263f412ca33171600eca9a6fa" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" -"checksum num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "57450397855d951f1a41305e54851b1a7b8f5d2e349543a02a2effe25459f718" +"checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e688f31d92ffd7c1ddc57a1b4e6d773c0f2a14ee437a4b0a4f5a69c80eb221c8" -"checksum proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "175a40b9cf564ce9bf050654633dbf339978706b8ead1a907bb970b63185dd95" +"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" -"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_os 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddb525a78d3a0b0e05b6fe0f7df14d7a4dc957944c7b403911ba5a0f1c694967" +"checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a" "checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" @@ -718,8 +725,9 @@ dependencies = [ "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" -"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" +"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" From 28dcc1c346b1657ebc1e6f096799aa05e38d0f88 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 12 Sep 2019 19:25:41 +0100 Subject: [PATCH 179/330] bellman: Fix compile errors without multicore feature --- bellman/src/gadgets/blake2s.rs | 16 +++++----------- bellman/src/gadgets/boolean.rs | 33 ++++++++++++++++---------------- bellman/src/gadgets/lookup.rs | 9 ++++----- bellman/src/gadgets/multieq.rs | 11 +++++------ bellman/src/gadgets/multipack.rs | 7 +++---- bellman/src/gadgets/num.rs | 17 ++++++++-------- bellman/src/gadgets/sha256.rs | 10 +++++----- bellman/src/gadgets/test/mod.rs | 15 +++++++-------- bellman/src/gadgets/uint32.rs | 15 +++++++-------- 9 files changed, 60 insertions(+), 73 deletions(-) diff --git a/bellman/src/gadgets/blake2s.rs b/bellman/src/gadgets/blake2s.rs index 672f139..96e554b 100644 --- a/bellman/src/gadgets/blake2s.rs +++ b/bellman/src/gadgets/blake2s.rs @@ -1,12 +1,6 @@ -use pairing::Engine; - +use super::{boolean::Boolean, multieq::MultiEq, uint32::UInt32}; use crate::{ConstraintSystem, SynthesisError}; - -use super::boolean::Boolean; - -use super::uint32::UInt32; - -use super::multieq::MultiEq; +use ff::ScalarEngine; /* 2.1. Parameters @@ -81,7 +75,7 @@ const SIGMA: [[usize; 16]; 10] = [ END FUNCTION. */ -fn mixing_g, M>( +fn mixing_g, M>( mut cs: M, v: &mut [UInt32], a: usize, @@ -166,7 +160,7 @@ where END FUNCTION. */ -fn blake2s_compression>( +fn blake2s_compression>( mut cs: CS, h: &mut [UInt32], m: &[UInt32], @@ -339,7 +333,7 @@ fn blake2s_compression>( END FUNCTION. */ -pub fn blake2s>( +pub fn blake2s>( mut cs: CS, input: &[Boolean], personalization: &[u8], diff --git a/bellman/src/gadgets/boolean.rs b/bellman/src/gadgets/boolean.rs index b26bb19..bbc0d30 100644 --- a/bellman/src/gadgets/boolean.rs +++ b/bellman/src/gadgets/boolean.rs @@ -1,5 +1,4 @@ -use ff::{BitIterator, Field, PrimeField}; -use pairing::Engine; +use ff::{BitIterator, Field, PrimeField, ScalarEngine}; use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; @@ -31,7 +30,7 @@ impl AllocatedBit { must_be_false: &AllocatedBit, ) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { let var = cs.alloc( @@ -68,7 +67,7 @@ impl AllocatedBit { /// boolean value. pub fn alloc(mut cs: CS, value: Option) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { let var = cs.alloc( @@ -101,7 +100,7 @@ impl AllocatedBit { /// an `AllocatedBit`. pub fn xor(mut cs: CS, a: &Self, b: &Self) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { let mut result_value = None; @@ -153,7 +152,7 @@ impl AllocatedBit { /// an `AllocatedBit`. pub fn and(mut cs: CS, a: &Self, b: &Self) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { let mut result_value = None; @@ -191,7 +190,7 @@ impl AllocatedBit { /// Calculates `a AND (NOT b)`. pub fn and_not(mut cs: CS, a: &Self, b: &Self) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { let mut result_value = None; @@ -229,7 +228,7 @@ impl AllocatedBit { /// Calculates `(NOT a) AND (NOT b)`. pub fn nor(mut cs: CS, a: &Self, b: &Self) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { let mut result_value = None; @@ -265,7 +264,7 @@ impl AllocatedBit { } } -pub fn u64_into_boolean_vec_le>( +pub fn u64_into_boolean_vec_le>( mut cs: CS, value: Option, ) -> Result, SynthesisError> { @@ -296,7 +295,7 @@ pub fn u64_into_boolean_vec_le>( Ok(bits) } -pub fn field_into_boolean_vec_le, F: PrimeField>( +pub fn field_into_boolean_vec_le, F: PrimeField>( cs: CS, value: Option, ) -> Result, SynthesisError> { @@ -305,7 +304,7 @@ pub fn field_into_boolean_vec_le, F: PrimeFie Ok(v.into_iter().map(Boolean::from).collect()) } -pub fn field_into_allocated_bits_le, F: PrimeField>( +pub fn field_into_allocated_bits_le, F: PrimeField>( mut cs: CS, value: Option, ) -> Result, SynthesisError> { @@ -367,7 +366,7 @@ impl Boolean { pub fn enforce_equal(mut cs: CS, a: &Self, b: &Self) -> Result<(), SynthesisError> where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { match (a, b) { @@ -419,7 +418,7 @@ impl Boolean { } } - pub fn lc(&self, one: Variable, coeff: E::Fr) -> LinearCombination { + pub fn lc(&self, one: Variable, coeff: E::Fr) -> LinearCombination { match *self { Boolean::Constant(c) => { if c { @@ -452,7 +451,7 @@ impl Boolean { /// Perform XOR over two boolean operands pub fn xor<'a, E, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { match (a, b) { @@ -474,7 +473,7 @@ impl Boolean { /// Perform AND over two boolean operands pub fn and<'a, E, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { match (a, b) { @@ -508,7 +507,7 @@ impl Boolean { c: &'a Self, ) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { let ch_value = match (a.get_value(), b.get_value(), c.get_value()) { @@ -615,7 +614,7 @@ impl Boolean { c: &'a Self, ) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { let maj_value = match (a.get_value(), b.get_value(), c.get_value()) { diff --git a/bellman/src/gadgets/lookup.rs b/bellman/src/gadgets/lookup.rs index bbb1da6..8124b22 100644 --- a/bellman/src/gadgets/lookup.rs +++ b/bellman/src/gadgets/lookup.rs @@ -1,5 +1,4 @@ -use ff::Field; -use pairing::Engine; +use ff::{Field, ScalarEngine}; use super::boolean::Boolean; use super::num::{AllocatedNum, Num}; @@ -7,7 +6,7 @@ use super::*; use crate::ConstraintSystem; // Synthesize the constants for each base pattern. -fn synth<'a, E: Engine, I>(window_size: usize, constants: I, assignment: &mut [E::Fr]) +fn synth<'a, E: ScalarEngine, I>(window_size: usize, constants: I, assignment: &mut [E::Fr]) where I: IntoIterator, { @@ -28,7 +27,7 @@ where /// Performs a 3-bit window table lookup. `bits` is in /// little-endian order. -pub fn lookup3_xy( +pub fn lookup3_xy( mut cs: CS, bits: &[Boolean], coords: &[(E::Fr, E::Fr)], @@ -118,7 +117,7 @@ where /// Performs a 3-bit window table lookup, where /// one of the bits is a sign bit. -pub fn lookup3_xy_with_conditional_negation( +pub fn lookup3_xy_with_conditional_negation( mut cs: CS, bits: &[Boolean], coords: &[(E::Fr, E::Fr)], diff --git a/bellman/src/gadgets/multieq.rs b/bellman/src/gadgets/multieq.rs index 095017a..d052822 100644 --- a/bellman/src/gadgets/multieq.rs +++ b/bellman/src/gadgets/multieq.rs @@ -1,9 +1,8 @@ -use ff::{Field, PrimeField}; -use pairing::Engine; +use ff::{Field, PrimeField, ScalarEngine}; use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; -pub struct MultiEq> { +pub struct MultiEq> { cs: CS, ops: usize, bits_used: usize, @@ -11,7 +10,7 @@ pub struct MultiEq> { rhs: LinearCombination, } -impl> MultiEq { +impl> MultiEq { pub fn new(cs: CS) -> Self { MultiEq { cs, @@ -58,7 +57,7 @@ impl> MultiEq { } } -impl> Drop for MultiEq { +impl> Drop for MultiEq { fn drop(&mut self) { if self.bits_used > 0 { self.accumulate(); @@ -66,7 +65,7 @@ impl> Drop for MultiEq { } } -impl> ConstraintSystem for MultiEq { +impl> ConstraintSystem for MultiEq { type Root = Self; fn one() -> Variable { diff --git a/bellman/src/gadgets/multipack.rs b/bellman/src/gadgets/multipack.rs index 34df7cd..1fa1967 100644 --- a/bellman/src/gadgets/multipack.rs +++ b/bellman/src/gadgets/multipack.rs @@ -2,14 +2,13 @@ use super::boolean::Boolean; use super::num::Num; use super::Assignment; use crate::{ConstraintSystem, SynthesisError}; -use ff::{Field, PrimeField}; -use pairing::Engine; +use ff::{Field, PrimeField, ScalarEngine}; /// Takes a sequence of booleans and exposes them as compact /// public inputs pub fn pack_into_inputs(mut cs: CS, bits: &[Boolean]) -> Result<(), SynthesisError> where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() { @@ -49,7 +48,7 @@ pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec { .collect() } -pub fn compute_multipacking(bits: &[bool]) -> Vec { +pub fn compute_multipacking(bits: &[bool]) -> Vec { let mut result = vec![]; for bits in bits.chunks(E::Fr::CAPACITY as usize) { diff --git a/bellman/src/gadgets/num.rs b/bellman/src/gadgets/num.rs index eecccef..b7caf6d 100644 --- a/bellman/src/gadgets/num.rs +++ b/bellman/src/gadgets/num.rs @@ -1,5 +1,4 @@ -use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr}; -use pairing::Engine; +use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, ScalarEngine}; use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; @@ -7,12 +6,12 @@ use super::Assignment; use super::boolean::{self, AllocatedBit, Boolean}; -pub struct AllocatedNum { +pub struct AllocatedNum { value: Option, variable: Variable, } -impl Clone for AllocatedNum { +impl Clone for AllocatedNum { fn clone(&self) -> Self { AllocatedNum { value: self.value, @@ -21,7 +20,7 @@ impl Clone for AllocatedNum { } } -impl AllocatedNum { +impl AllocatedNum { pub fn alloc(mut cs: CS, value: F) -> Result where CS: ConstraintSystem, @@ -75,7 +74,7 @@ impl AllocatedNum { v: &[AllocatedBit], ) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { assert!(!v.is_empty()); @@ -359,12 +358,12 @@ impl AllocatedNum { } } -pub struct Num { +pub struct Num { value: Option, lc: LinearCombination, } -impl From> for Num { +impl From> for Num { fn from(num: AllocatedNum) -> Num { Num { value: num.value, @@ -373,7 +372,7 @@ impl From> for Num { } } -impl Num { +impl Num { pub fn zero() -> Self { Num { value: Some(E::Fr::zero()), diff --git a/bellman/src/gadgets/sha256.rs b/bellman/src/gadgets/sha256.rs index e346a71..a875513 100644 --- a/bellman/src/gadgets/sha256.rs +++ b/bellman/src/gadgets/sha256.rs @@ -2,7 +2,7 @@ use super::boolean::Boolean; use super::multieq::MultiEq; use super::uint32::UInt32; use crate::{ConstraintSystem, SynthesisError}; -use pairing::Engine; +use ff::ScalarEngine; #[allow(clippy::unreadable_literal)] const ROUND_CONSTANTS: [u32; 64] = [ @@ -26,7 +26,7 @@ pub fn sha256_block_no_padding( input: &[Boolean], ) -> Result, SynthesisError> where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { assert_eq!(input.len(), 512); @@ -41,7 +41,7 @@ where pub fn sha256(mut cs: CS, input: &[Boolean]) -> Result, SynthesisError> where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { assert!(input.len() % 8 == 0); @@ -78,7 +78,7 @@ fn sha256_compression_function( current_hash_value: &[UInt32], ) -> Result, SynthesisError> where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { assert_eq!(input.len(), 512); @@ -125,7 +125,7 @@ where impl Maybe { fn compute(self, cs: M, others: &[UInt32]) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, M: ConstraintSystem>, { diff --git a/bellman/src/gadgets/test/mod.rs b/bellman/src/gadgets/test/mod.rs index eed676e..fedfe94 100644 --- a/bellman/src/gadgets/test/mod.rs +++ b/bellman/src/gadgets/test/mod.rs @@ -1,5 +1,4 @@ -use ff::{Field, PrimeField, PrimeFieldRepr}; -use pairing::Engine; +use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; @@ -20,7 +19,7 @@ enum NamedObject { } /// Constraint system for testing purposes. -pub struct TestConstraintSystem { +pub struct TestConstraintSystem { named_objects: HashMap, current_namespace: Vec, constraints: Vec<( @@ -62,7 +61,7 @@ impl Ord for OrderedVariable { } } -fn proc_lc(terms: &[(Variable, E::Fr)]) -> BTreeMap { +fn proc_lc(terms: &[(Variable, E::Fr)]) -> BTreeMap { let mut map = BTreeMap::new(); for &(var, coeff) in terms { map.entry(OrderedVariable(var)) @@ -85,7 +84,7 @@ fn proc_lc(terms: &[(Variable, E::Fr)]) -> BTreeMap(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) { +fn hash_lc(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) { let map = proc_lc::(terms); let mut buf = [0u8; 9 + 32]; @@ -110,7 +109,7 @@ fn hash_lc(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) { } } -fn eval_lc( +fn eval_lc( terms: &[(Variable, E::Fr)], inputs: &[(E::Fr, String)], aux: &[(E::Fr, String)], @@ -130,7 +129,7 @@ fn eval_lc( acc } -impl TestConstraintSystem { +impl TestConstraintSystem { pub fn new() -> TestConstraintSystem { let mut map = HashMap::new(); map.insert( @@ -344,7 +343,7 @@ fn compute_path(ns: &[String], this: String) -> String { name } -impl ConstraintSystem for TestConstraintSystem { +impl ConstraintSystem for TestConstraintSystem { type Root = Self; fn alloc(&mut self, annotation: A, f: F) -> Result diff --git a/bellman/src/gadgets/uint32.rs b/bellman/src/gadgets/uint32.rs index 5a93e75..cf8e390 100644 --- a/bellman/src/gadgets/uint32.rs +++ b/bellman/src/gadgets/uint32.rs @@ -1,5 +1,4 @@ -use ff::{Field, PrimeField}; -use pairing::Engine; +use ff::{Field, PrimeField, ScalarEngine}; use crate::{ConstraintSystem, LinearCombination, SynthesisError}; @@ -41,7 +40,7 @@ impl UInt32 { /// Allocate a `UInt32` in the constraint system pub fn alloc(mut cs: CS, value: Option) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { let values = match value { @@ -194,7 +193,7 @@ impl UInt32 { circuit_fn: U, ) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, F: Fn(u32, u32, u32) -> u32, U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result, @@ -223,7 +222,7 @@ impl UInt32 { /// during SHA256. pub fn sha256_maj(cs: CS, a: &Self, b: &Self, c: &Self) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { Self::triop( @@ -240,7 +239,7 @@ impl UInt32 { /// during SHA256. pub fn sha256_ch(cs: CS, a: &Self, b: &Self, c: &Self) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { Self::triop( @@ -256,7 +255,7 @@ impl UInt32 { /// XOR this `UInt32` with another `UInt32` pub fn xor(&self, mut cs: CS, other: &Self) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, { let new_value = match (self.value, other.value) { @@ -281,7 +280,7 @@ impl UInt32 { /// Perform modular addition of several `UInt32` objects. pub fn addmany(mut cs: M, operands: &[Self]) -> Result where - E: Engine, + E: ScalarEngine, CS: ConstraintSystem, M: ConstraintSystem>, { From 8541b2bde4e7ab194dc0097c5b58e41af090a6bb Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Wed, 8 Aug 2018 12:15:16 +0300 Subject: [PATCH 180/330] pedersen_hash: prints hashes, adds comments --- zcash_primitives/src/pedersen_hash.rs | 16 ++++++++++++++++ zcash_proofs/src/circuit/pedersen_hash.rs | 1 + 2 files changed, 17 insertions(+) diff --git a/zcash_primitives/src/pedersen_hash.rs b/zcash_primitives/src/pedersen_hash.rs index 835e9c7..f760a1f 100644 --- a/zcash_primitives/src/pedersen_hash.rs +++ b/zcash_primitives/src/pedersen_hash.rs @@ -38,12 +38,14 @@ where let mut generators = params.pedersen_hash_exp_table().iter(); loop { + // acc is let mut acc = E::Fs::zero(); let mut cur = E::Fs::one(); let mut chunks_remaining = params.pedersen_hash_chunks_per_generator(); let mut encountered_bits = false; // Grab three bits from the input + // spec: iterate over chunks (a,b,c) while let Some(a) = bits.next() { encountered_bits = true; @@ -51,6 +53,7 @@ where let c = bits.next().unwrap_or(false); // Start computing this portion of the scalar + // tmp is enc(m_j) let mut tmp = cur; if a { tmp.add_assign(&cur); @@ -105,3 +108,16 @@ where result } + +#[cfg(test)] +mod test { + use crate::jubjub::*; + + #[test] + fn test_pedersen_hash_generators() { + let params = &JubjubBls12::new(); + for (i, generator) in params.pedersen_hash_generators().iter().enumerate() { + println!("generator {}, x={}, y={}", i, generator.to_xy().0, generator.to_xy().1) + } + } +} diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index 409f30e..67d05c5 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -26,6 +26,7 @@ where assert_eq!(personalization.len(), 6); let mut edwards_result = None; + //REVIEW: bit cloning let mut bits = personalization.iter().chain(bits.iter()).peekable(); let mut segment_generators = params.pedersen_circuit_generators().iter(); let boolean_false = Boolean::constant(false); From 414d651c9c0f12d48ba2f998ede156f38f8c719a Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Thu, 9 Aug 2018 16:20:39 +0300 Subject: [PATCH 181/330] pedersen_hash: adds tests for Daniel's vector --- zcash_primitives/src/pedersen_hash.rs | 4 ++++ zcash_proofs/src/circuit/pedersen_hash.rs | 26 +++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/zcash_primitives/src/pedersen_hash.rs b/zcash_primitives/src/pedersen_hash.rs index f760a1f..f49fcb7 100644 --- a/zcash_primitives/src/pedersen_hash.rs +++ b/zcash_primitives/src/pedersen_hash.rs @@ -5,6 +5,7 @@ use ff::{Field, PrimeField, PrimeFieldRepr}; pub enum Personalization { NoteCommitment, MerkleTree(usize), + Empty, } impl Personalization { @@ -16,6 +17,9 @@ impl Personalization { (0..6).map(|i| (num >> i) & 1 == 1).collect() } + Personalization::Empty => { + vec![true, true, true, false, false, false] + } } } } diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index 67d05c5..82703fa 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -208,4 +208,30 @@ mod test { } } } + + #[test] + fn test_pedersen_hash_alternative() { + let params = &JubjubBls12::new(); + + let mut input: Vec = vec![true, true, true, false, false, false, true, true, true, false, false, false, true, true, true, false, false, false, true, true, true, false, false, false, true, true, true, false, false, false, true, true, true, false, false, false, true, true, true, false, true, false, true, true, true, true, true, false, true, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, false, true, true, true, false, false, true, true, false, true, true, true, true, true, false, true, true, false, true, true, false, true, false, true, false, true, true, false, true, false, true, true, false, false, false, false, false, true, true, false, true, false, true, true, true, true, false, true, false, true, false, false, false, false, true, true, true, false, true, true, true, false, true, false, false, true, false, true, true, true, false, false, false, true, true]; + + let mut cs = TestConstraintSystem::::new(); + + let input_bools: Vec = input.iter().enumerate().map(|(i, b)| { + Boolean::from( + AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap() + ) + }).collect(); + + let res = pedersen_hash( + cs.namespace(|| "pedersen hash"), + Personalization::Empty, + &input_bools, + params + ).unwrap(); + + assert!(cs.is_satisfied()); + println!("x={},y={}", res.get_x().get_value().unwrap(), res.get_y().get_value().unwrap()); + + } } From 15633ad434fe58f4b2a59d90e5ee0abacd1e3e11 Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Fri, 17 Aug 2018 18:34:54 +0300 Subject: [PATCH 182/330] pedersen hashes: example of size limit bug --- bellman/src/gadgets/lookup.rs | 1 + zcash_primitives/src/pedersen_hash.rs | 19 ++++++++++++++++--- zcash_proofs/src/circuit/pedersen_hash.rs | 8 ++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/bellman/src/gadgets/lookup.rs b/bellman/src/gadgets/lookup.rs index bbb1da6..0c55801 100644 --- a/bellman/src/gadgets/lookup.rs +++ b/bellman/src/gadgets/lookup.rs @@ -154,6 +154,7 @@ where Ok(tmp) })?; + let one = CS::one(); // Compute the coefficients for the lookup constraints diff --git a/zcash_primitives/src/pedersen_hash.rs b/zcash_primitives/src/pedersen_hash.rs index f49fcb7..11dc387 100644 --- a/zcash_primitives/src/pedersen_hash.rs +++ b/zcash_primitives/src/pedersen_hash.rs @@ -18,7 +18,7 @@ impl Personalization { (0..6).map(|i| (num >> i) & 1 == 1).collect() } Personalization::Empty => { - vec![true, true, true, false, false, false] + vec![true, true, true, true, true, true] } } } @@ -115,13 +115,26 @@ where #[cfg(test)] mod test { - use crate::jubjub::*; + use crate::{ + jubjub::*, + pedersen_hash::{pedersen_hash, Personalization}, + }; + use pairing::bls12_381::{Bls12, Fr}; #[test] - fn test_pedersen_hash_generators() { + fn test_pedersen_hash_noncircuit() { let params = &JubjubBls12::new(); + /* for (i, generator) in params.pedersen_hash_generators().iter().enumerate() { println!("generator {}, x={}, y={}", i, generator.to_xy().0, generator.to_xy().1) } + */ + + let mut input: Vec = vec![]; + for i in 0..(63*3*4+1) { + input.push(true); + } + let p = pedersen_hash::(Personalization::Empty, input, ¶ms).to_xy(); + println!("hash = {}, {}", p.0, p.1); } } diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index 82703fa..7f43b1c 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -41,6 +41,7 @@ where let b = bits.next().unwrap_or(&boolean_false); let c = bits.next().unwrap_or(&boolean_false); + let tmp = lookup3_xy_with_conditional_negation( cs.namespace(|| format!("segment {}, window {}", segment_i, window_i)), &[a.clone(), b.clone(), c.clone()], @@ -213,16 +214,19 @@ mod test { fn test_pedersen_hash_alternative() { let params = &JubjubBls12::new(); - let mut input: Vec = vec![true, true, true, false, false, false, true, true, true, false, false, false, true, true, true, false, false, false, true, true, true, false, false, false, true, true, true, false, false, false, true, true, true, false, false, false, true, true, true, false, true, false, true, true, true, true, true, false, true, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, false, true, true, true, false, false, true, true, false, true, true, true, true, true, false, true, true, false, true, true, false, true, false, true, false, true, true, false, true, false, true, true, false, false, false, false, false, true, true, false, true, false, true, true, true, true, false, true, false, true, false, false, false, false, true, true, true, false, true, true, true, false, true, false, false, true, false, true, true, true, false, false, false, true, true]; + let mut input: Vec = vec![]; + for i in 0..(63*3*4+1) { + input.push(true); + } let mut cs = TestConstraintSystem::::new(); + let input_bools: Vec = input.iter().enumerate().map(|(i, b)| { Boolean::from( AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap() ) }).collect(); - let res = pedersen_hash( cs.namespace(|| "pedersen hash"), Personalization::Empty, From 4835be05b0478a4c753fdbcd728502ff0ce74f7e Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Sun, 19 Aug 2018 10:04:33 +0300 Subject: [PATCH 183/330] pedersen_hash: show a tighter limit for hash sizes --- zcash_proofs/src/circuit/pedersen_hash.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index 7f43b1c..30ee06e 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -215,7 +215,7 @@ mod test { let params = &JubjubBls12::new(); let mut input: Vec = vec![]; - for i in 0..(63*3*4+1) { + for i in 0..(63*3*4-6+1) { input.push(true); } From 43496857c9b76f0e386d243eb3d0654ee7f0657e Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Tue, 4 Sep 2018 16:03:52 +0300 Subject: [PATCH 184/330] pedersen_hash: removes debug prints --- bellman/src/gadgets/lookup.rs | 1 - zcash_proofs/src/circuit/pedersen_hash.rs | 31 ----------------------- 2 files changed, 32 deletions(-) diff --git a/bellman/src/gadgets/lookup.rs b/bellman/src/gadgets/lookup.rs index 0c55801..bbb1da6 100644 --- a/bellman/src/gadgets/lookup.rs +++ b/bellman/src/gadgets/lookup.rs @@ -154,7 +154,6 @@ where Ok(tmp) })?; - let one = CS::one(); // Compute the coefficients for the lookup constraints diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index 30ee06e..409f30e 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -26,7 +26,6 @@ where assert_eq!(personalization.len(), 6); let mut edwards_result = None; - //REVIEW: bit cloning let mut bits = personalization.iter().chain(bits.iter()).peekable(); let mut segment_generators = params.pedersen_circuit_generators().iter(); let boolean_false = Boolean::constant(false); @@ -41,7 +40,6 @@ where let b = bits.next().unwrap_or(&boolean_false); let c = bits.next().unwrap_or(&boolean_false); - let tmp = lookup3_xy_with_conditional_negation( cs.namespace(|| format!("segment {}, window {}", segment_i, window_i)), &[a.clone(), b.clone(), c.clone()], @@ -209,33 +207,4 @@ mod test { } } } - - #[test] - fn test_pedersen_hash_alternative() { - let params = &JubjubBls12::new(); - - let mut input: Vec = vec![]; - for i in 0..(63*3*4-6+1) { - input.push(true); - } - - let mut cs = TestConstraintSystem::::new(); - - - let input_bools: Vec = input.iter().enumerate().map(|(i, b)| { - Boolean::from( - AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap() - ) - }).collect(); - let res = pedersen_hash( - cs.namespace(|| "pedersen hash"), - Personalization::Empty, - &input_bools, - params - ).unwrap(); - - assert!(cs.is_satisfied()); - println!("x={},y={}", res.get_x().get_value().unwrap(), res.get_y().get_value().unwrap()); - - } } From 7ee61c4f94912f549efca1af76fffeaaf66a5e9e Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Tue, 4 Sep 2018 16:28:41 +0300 Subject: [PATCH 185/330] pedersen_hash: adds test vectors for the circuit implementation --- zcash_primitives/src/pedersen_hash.rs | 33 -------------- zcash_proofs/src/circuit/pedersen_hash.rs | 53 +++++++++++++++++++++++ 2 files changed, 53 insertions(+), 33 deletions(-) diff --git a/zcash_primitives/src/pedersen_hash.rs b/zcash_primitives/src/pedersen_hash.rs index 11dc387..835e9c7 100644 --- a/zcash_primitives/src/pedersen_hash.rs +++ b/zcash_primitives/src/pedersen_hash.rs @@ -5,7 +5,6 @@ use ff::{Field, PrimeField, PrimeFieldRepr}; pub enum Personalization { NoteCommitment, MerkleTree(usize), - Empty, } impl Personalization { @@ -17,9 +16,6 @@ impl Personalization { (0..6).map(|i| (num >> i) & 1 == 1).collect() } - Personalization::Empty => { - vec![true, true, true, true, true, true] - } } } } @@ -42,14 +38,12 @@ where let mut generators = params.pedersen_hash_exp_table().iter(); loop { - // acc is let mut acc = E::Fs::zero(); let mut cur = E::Fs::one(); let mut chunks_remaining = params.pedersen_hash_chunks_per_generator(); let mut encountered_bits = false; // Grab three bits from the input - // spec: iterate over chunks (a,b,c) while let Some(a) = bits.next() { encountered_bits = true; @@ -57,7 +51,6 @@ where let c = bits.next().unwrap_or(false); // Start computing this portion of the scalar - // tmp is enc(m_j) let mut tmp = cur; if a { tmp.add_assign(&cur); @@ -112,29 +105,3 @@ where result } - -#[cfg(test)] -mod test { - use crate::{ - jubjub::*, - pedersen_hash::{pedersen_hash, Personalization}, - }; - use pairing::bls12_381::{Bls12, Fr}; - - #[test] - fn test_pedersen_hash_noncircuit() { - let params = &JubjubBls12::new(); - /* - for (i, generator) in params.pedersen_hash_generators().iter().enumerate() { - println!("generator {}, x={}, y={}", i, generator.to_xy().0, generator.to_xy().1) - } - */ - - let mut input: Vec = vec![]; - for i in 0..(63*3*4+1) { - input.push(true); - } - let p = pedersen_hash::(Personalization::Empty, input, ¶ms).to_xy(); - println!("hash = {}, {}", p.0, p.1); - } -} diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index 409f30e..acaf7c9 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -207,4 +207,57 @@ mod test { } } } + + #[test] + fn test_pedersen_hash_external_test_vectors() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); + let params = &JubjubBls12::new(); + + let expected_xs = [ + "28161926966428986673895580777285905189725480206811328272001879986576840909576", + "39669831794597628158501766225645040955899576179071014703006420393381978263045", + ]; + let expected_ys = [ + "26869991781071974894722407757894142583682396277979904369818887810555917099932", + "2112827187110048608327330788910224944044097981650120385961435904443901436107", + ]; + for length in 300..302 { + let mut input: Vec = (0..length).map(|_| rng.next_u32() % 2 != 0).collect(); + + let mut cs = TestConstraintSystem::::new(); + + let input_bools: Vec = input + .iter() + .enumerate() + .map(|(i, b)| { + Boolean::from( + AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)) + .unwrap(), + ) + }) + .collect(); + + let res = pedersen_hash( + cs.namespace(|| "pedersen hash"), + Personalization::MerkleTree(1), + &input_bools, + params, + ) + .unwrap(); + + assert!(cs.is_satisfied()); + + assert_eq!( + res.get_x().get_value().unwrap(), + Fr::from_str(expected_xs[length - 300]).unwrap() + ); + assert_eq!( + res.get_y().get_value().unwrap(), + Fr::from_str(expected_ys[length - 300]).unwrap() + ); + } + } } From 804f4cba6791dc27d2bf0d20fcc1824b5ee0f01a Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Wed, 24 Oct 2018 12:37:32 +0300 Subject: [PATCH 186/330] Add blake2s test vectors for varying sizes from go-jubjub --- bellman/src/gadgets/blake2s.rs | 74 ++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/bellman/src/gadgets/blake2s.rs b/bellman/src/gadgets/blake2s.rs index 672f139..d074f2f 100644 --- a/bellman/src/gadgets/blake2s.rs +++ b/bellman/src/gadgets/blake2s.rs @@ -554,4 +554,78 @@ mod test { } } } + + #[test] + fn test_blake2s_256_vars() { + let data: Vec = hex!("be9f9c485e670acce8b1516a378176161b20583637b6f1c536fbc1158a0a3296831df2920e57a442d5738f4be4dd6be89dd7913fc8b4d1c0a815646a4d674b77f7caf313bd880bf759fcac27037c48c2b2a20acd2fd5248e3be426c84a341c0a3c63eaf36e0d537d10b8db5c6e4c801832c41eb1a3ed602177acded8b4b803bd34339d99a18b71df399641cc8dfae2ad193fcd74b5913e704551777160d14c78f2e8d5c32716a8599c1080cb89a40ccd6ba596694a8b4a065d9f2d0667ef423ed2e418093caff884540858b4f4b62acd47edcea880523e1b1cda8eb225c128c2e9e83f14f6e7448c5733a195cac7d79a53dde5083172462c45b2f799e42af1c9").to_vec(); + assert_eq!(data.len(), 256); + + let mut cs = TestConstraintSystem::::new(); + + let mut input_bits = vec![]; + + for (byte_i, input_byte) in data.into_iter().enumerate() { + for bit_i in 0..8 { + let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i)); + + input_bits.push( + AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)) + .unwrap() + .into(), + ); + } + } + + let r = blake2s(&mut cs, &input_bits, b"12345678").unwrap(); + + assert!(cs.is_satisfied()); + + let expected = hex!("0af5695115ced92c8a0341e43869209636e9aa6472e4576f0f2b996cf812b30e"); + + let mut out = r.into_iter(); + for b in expected.into_iter() { + for i in 0..8 { + let c = out.next().unwrap().get_value().unwrap(); + + assert_eq!(c, (b >> i) & 1u8 == 1u8); + } + } + } + + #[test] + fn test_blake2s_700_vars() { + let data: Vec = hex!("5dcfe8bab4c758d2eb1ddb7ef337583e0df3e2c358e1755b7cd303a658de9a1227eed1d1114179a5c3c38d692ff2cf2d4e5c92a9516de750106774bbf9f7d063f707f4c9b6a02c0a77e4feb99e036c3ccaee7d1a31cb144093aa074bc9da608f8ff30b39c3c60e4a243cc0bbd406d1262a7d6607b31c60275c6bcc8b0ac49a06a4b629a98693c5f7640f3bca45e4977cfabc5b17f52838af3433b1fd407dbbdc131e8e4bd58bcee85bbab4b57b656c6a2ec6cf852525bc8423675e2bf29159139cd5df99db94719f3f7167230e0d5bd76f6d7891b656732cef9c3c0d48a5fa3d7a879988157b39015a85451b25af0301ca5e759ac35fea79dca38c673ec6db9f3885d9103e2dcb3304bd3d59b0b1d01babc97ef8a74d91b6ab6bf50f29eb5adf7250a28fd85db37bff0133193635da69caeefc72979cf3bef1d2896d847eea7e8a81e0927893dbd010feb6fb845d0399007d9a148a0596d86cd8f4192631f975c560f4de8da5f712c161342063af3c11029d93d6df7ff46db48343499de9ec4786cac059c4025ef418c9fe40132428ff8b91259d71d1709ff066add84ae944b45a817f60b4c1bf719e39ae23e9b413469db2310793e9137cf38741e5dd2a3c138a566dbde1950c00071b20ac457b46ba9b0a7ebdddcc212bd228d2a4c4146a970e54158477247c27871af1564b176576e9fd43bf63740bf77434bc4ea3b1a4b430e1a11714bf43160145578a575c3f78ddeaa48de97f73460f26f8df2b5d63e31800100d16bc27160fea5ced5a977ef541cfe8dadc7b3991ed1c0d4f16a3076bbfed96ba3e155113e794987af8abb133f06feefabc2ac32eb4d4d4ba1541ca08b9e518d2e74b7f946b0cbd2663d58c689359b9a565821acc619011233d1011963fa302cde34fc9c5ba2e03eeb2512f547391e940d56218e22ae325f2dfa38d4bae35744ee707aa5dc9c17674025d15390a08f5c452343546ef6da0f7").to_vec(); + assert_eq!(data.len(), 256); + + let mut cs = TestConstraintSystem::::new(); + + let mut input_bits = vec![]; + + for (byte_i, input_byte) in data.into_iter().enumerate() { + for bit_i in 0..8 { + let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i)); + + input_bits.push( + AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)) + .unwrap() + .into(), + ); + } + } + + let r = blake2s(&mut cs, &input_bits, b"12345678").unwrap(); + + assert!(cs.is_satisfied()); + + let expected = hex!("2ab8f0683167ba220eef19dccf4f9b1a8193cc09b35e0235842323950530f18a"); + + let mut out = r.into_iter(); + for b in expected.into_iter() { + for i in 0..8 { + let c = out.next().unwrap().get_value().unwrap(); + + assert_eq!(c, (b >> i) & 1u8 == 1u8); + } + } + } } From cc2a41d86c3f3a2b2a5f42228773c90dd0eeeda0 Mon Sep 17 00:00:00 2001 From: Taylor Hornby Date: Tue, 12 Mar 2019 13:46:01 -0600 Subject: [PATCH 187/330] Fix blake2s test data length assertion. --- bellman/src/gadgets/blake2s.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bellman/src/gadgets/blake2s.rs b/bellman/src/gadgets/blake2s.rs index d074f2f..d89aac5 100644 --- a/bellman/src/gadgets/blake2s.rs +++ b/bellman/src/gadgets/blake2s.rs @@ -595,7 +595,7 @@ mod test { #[test] fn test_blake2s_700_vars() { let data: Vec = hex!("5dcfe8bab4c758d2eb1ddb7ef337583e0df3e2c358e1755b7cd303a658de9a1227eed1d1114179a5c3c38d692ff2cf2d4e5c92a9516de750106774bbf9f7d063f707f4c9b6a02c0a77e4feb99e036c3ccaee7d1a31cb144093aa074bc9da608f8ff30b39c3c60e4a243cc0bbd406d1262a7d6607b31c60275c6bcc8b0ac49a06a4b629a98693c5f7640f3bca45e4977cfabc5b17f52838af3433b1fd407dbbdc131e8e4bd58bcee85bbab4b57b656c6a2ec6cf852525bc8423675e2bf29159139cd5df99db94719f3f7167230e0d5bd76f6d7891b656732cef9c3c0d48a5fa3d7a879988157b39015a85451b25af0301ca5e759ac35fea79dca38c673ec6db9f3885d9103e2dcb3304bd3d59b0b1d01babc97ef8a74d91b6ab6bf50f29eb5adf7250a28fd85db37bff0133193635da69caeefc72979cf3bef1d2896d847eea7e8a81e0927893dbd010feb6fb845d0399007d9a148a0596d86cd8f4192631f975c560f4de8da5f712c161342063af3c11029d93d6df7ff46db48343499de9ec4786cac059c4025ef418c9fe40132428ff8b91259d71d1709ff066add84ae944b45a817f60b4c1bf719e39ae23e9b413469db2310793e9137cf38741e5dd2a3c138a566dbde1950c00071b20ac457b46ba9b0a7ebdddcc212bd228d2a4c4146a970e54158477247c27871af1564b176576e9fd43bf63740bf77434bc4ea3b1a4b430e1a11714bf43160145578a575c3f78ddeaa48de97f73460f26f8df2b5d63e31800100d16bc27160fea5ced5a977ef541cfe8dadc7b3991ed1c0d4f16a3076bbfed96ba3e155113e794987af8abb133f06feefabc2ac32eb4d4d4ba1541ca08b9e518d2e74b7f946b0cbd2663d58c689359b9a565821acc619011233d1011963fa302cde34fc9c5ba2e03eeb2512f547391e940d56218e22ae325f2dfa38d4bae35744ee707aa5dc9c17674025d15390a08f5c452343546ef6da0f7").to_vec(); - assert_eq!(data.len(), 256); + assert_eq!(data.len(), 700); let mut cs = TestConstraintSystem::::new(); From abd03928b4ddd294e15fe1e383ea81e708dac09d Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Wed, 29 Aug 2018 20:13:43 +0300 Subject: [PATCH 188/330] adds test vectors for NoteCommit --- zcash_proofs/src/circuit/sapling.rs | 202 ++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) diff --git a/zcash_proofs/src/circuit/sapling.rs b/zcash_proofs/src/circuit/sapling.rs index 08e55e6..d84a2a2 100644 --- a/zcash_proofs/src/circuit/sapling.rs +++ b/zcash_proofs/src/circuit/sapling.rs @@ -87,6 +87,7 @@ where &value_bits, params, )?; + println!("value: {}, {}", value.get_x().get_value().unwrap(), value.get_y().get_value().unwrap()); // Booleanize the randomness. This does not ensure // the bit representation is "in the field" because @@ -95,6 +96,8 @@ where cs.namespace(|| "rcv"), value_commitment.as_ref().map(|c| c.randomness), )?; + println!("rcv: {}", value_commitment.as_ref().unwrap().randomness); + println!("value: {}", value_commitment.as_ref().unwrap().value); // Compute the randomness in the exponent let rcv = ecc::fixed_base_multiplication( @@ -106,6 +109,7 @@ where // Compute the Pedersen commitment to the value let cv = value.add(cs.namespace(|| "computation of cv"), &rcv, params)?; + println!("cv: {}, {}", cv.get_x().get_value().unwrap(), cv.get_y().get_value().unwrap()); // Expose the commitment as an input to the circuit cv.inputize(cs.namespace(|| "commitment point"))?; @@ -270,7 +274,17 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { ¬e_contents, self.params, )?; + println!("cm: {}, {}", cm.get_x().get_value().unwrap(), cm.get_y().get_value().unwrap()); + let mut note_contents_print: Vec<&str> = vec![]; + for b in ¬e_contents { + if b.get_value().unwrap() { + note_contents_print.push("true"); + } else { + note_contents_print.push("false"); + } + } + println!("note_contents: {}", note_contents_print.join(", ")); { // Booleanize the randomness for the note commitment let rcm = boolean::field_into_boolean_vec_le( @@ -278,6 +292,7 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { self.commitment_randomness, )?; + println!("commitment_randomness: {}", &self.commitment_randomness.unwrap()); // Compute the note commitment randomness in the exponent let rcm = ecc::fixed_base_multiplication( cs.namespace(|| "computation of commitment randomness"), @@ -285,6 +300,7 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { &rcm, self.params, )?; + println!("rcm: {}, {}", rcm.get_x().get_value().unwrap(), rcm.get_y().get_value().unwrap()); // Randomize the note commitment. Pedersen hashes are not // themselves hiding commitments. @@ -293,6 +309,8 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { &rcm, self.params, )?; + + println!("cm: {}, {}", cm.get_x().get_value().unwrap(), cm.get_y().get_value().unwrap()); } // This will store (least significant bit first) @@ -682,6 +700,190 @@ fn test_input_circuit_with_bls12_381() { } } +#[test] +fn test_input_circuit_with_bls12_381_external_test_vectors() { + use bellman::gadgets::test::*; + use ff::{BitIterator, Field}; + use pairing::bls12_381::*; + use rand_core::{RngCore, SeedableRng}; + use rand_xorshift::XorShiftRng; + use zcash_primitives::{ + jubjub::{edwards, fs, JubjubBls12}, + pedersen_hash, + primitives::{Diversifier, Note, ProofGenerationKey}, + }; + + let params = &JubjubBls12::new(); + let rng = &mut XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + let tree_depth = 32; + + let expected_cm_xs = vec![ + "43821661663052659750276289184181083197337192946256245809816728673021647664276", + "7220807656052227578299730541645543434083158611414003423211850718229633594616", + "13239753550660714843257636471668037031928211668773449453628093339627668081697", + "10900524635678389360790699587556574797582192824300145558807405770494079767974", + "1411013767457690636461779630023011774660680126764323588543800715293173598850", + "32334206652383066267661379202183359608706535021387905923603014648832344657662", + "20206750741605167608500278423400565295188703622528437817438897624149653579380", + "46716485782200334735478719487356079850582051575003452698983255860512578229998", + "31221372899739042781372142393132358519434268512685538373976981051223051220367", + "18269767207277008186871145355531741929166733260352590789136389380124992250945", + ]; + + let expected_cm_ys = vec![ + "27630722367128086497290371604583225252915685718989450292520883698391703910", + "23310648738313092772044712773481584369462075017189681529702825235349449805260", + "25709635353183537915646348052945798827495141780341329896098121888376871589480", + "10516315852014492141081718791576479298042117442649432716255936672048164184691", + "23970713991179488695004801139667700217127937225554773561645815034212389459772", + "3256052161046564597126736968199320852691566092694819239485673781545479548450", + "18887250722195819674378865377623103071236046274361890247643850134985809137409", + "36501156873031641173054592888886902104303750771545647842488588827138867116570", + "21927526310070011864833939629345235038589128172309792087590183778192091594775", + "32959334601512756708397683646222389414681003290313255304927423560477040775488", + ]; + + for i in 0..10 { + let value_commitment = ValueCommitment { + value: i, + randomness: fs::Fs::from_str(&(1000 * (i + 1)).to_string()).unwrap(), + }; + + let nsk = fs::Fs::random(rng); + let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params); + + let proof_generation_key = ProofGenerationKey { + ak: ak.clone(), + nsk: nsk.clone(), + }; + + let viewing_key = proof_generation_key.to_viewing_key(params); + + let payment_address; + + loop { + let diversifier = { + let mut d = [0; 11]; + rng.fill_bytes(&mut d); + Diversifier(d) + }; + + if let Some(p) = viewing_key.to_payment_address(diversifier, params) { + payment_address = p; + break; + } + } + + let g_d = payment_address.diversifier().g_d(params).unwrap(); + let commitment_randomness = fs::Fs::random(rng); + let auth_path = vec![Some((Fr::random(rng), rng.next_u32() % 2 != 0)); tree_depth]; + let ar = fs::Fs::random(rng); + + { + let rk = viewing_key.rk(ar, params).to_xy(); + let expected_value_cm = value_commitment.cm(params).to_xy(); + assert_eq!( + expected_value_cm.0, + Fr::from_str(&expected_cm_xs[i as usize]).unwrap() + ); + assert_eq!( + expected_value_cm.1, + Fr::from_str(&expected_cm_ys[i as usize]).unwrap() + ); + let note = Note { + value: value_commitment.value, + g_d: g_d.clone(), + pk_d: payment_address.pk_d().clone(), + r: commitment_randomness.clone(), + }; + + let mut position = 0u64; + let cm: Fr = note.cm(params); + let mut cur = cm.clone(); + + for (i, val) in auth_path.clone().into_iter().enumerate() { + let (uncle, b) = val.unwrap(); + + let mut lhs = cur; + let mut rhs = uncle; + + if b { + ::std::mem::swap(&mut lhs, &mut rhs); + } + + let mut lhs: Vec = BitIterator::new(lhs.into_repr()).collect(); + let mut rhs: Vec = BitIterator::new(rhs.into_repr()).collect(); + + lhs.reverse(); + rhs.reverse(); + + cur = pedersen_hash::pedersen_hash::( + pedersen_hash::Personalization::MerkleTree(i), + lhs.into_iter() + .take(Fr::NUM_BITS as usize) + .chain(rhs.into_iter().take(Fr::NUM_BITS as usize)), + params, + ) + .to_xy() + .0; + + if b { + position |= 1 << i; + } + } + + let expected_nf = note.nf(&viewing_key, position, params); + let expected_nf = multipack::bytes_to_bits_le(&expected_nf); + let expected_nf = multipack::compute_multipacking::(&expected_nf); + assert_eq!(expected_nf.len(), 2); + + let mut cs = TestConstraintSystem::::new(); + + let instance = Spend { + params: params, + value_commitment: Some(value_commitment.clone()), + proof_generation_key: Some(proof_generation_key.clone()), + payment_address: Some(payment_address.clone()), + commitment_randomness: Some(commitment_randomness), + ar: Some(ar), + auth_path: auth_path.clone(), + anchor: Some(cur), + }; + + instance.synthesize(&mut cs).unwrap(); + + assert!(cs.is_satisfied()); + assert_eq!(cs.num_constraints(), 98777); + assert_eq!( + cs.hash(), + "d37c738e83df5d9b0bb6495ac96abf21bcb2697477e2c15c2c7916ff7a3b6a89" + ); + + assert_eq!(cs.get("randomization of note commitment/x3/num"), cm); + + assert_eq!(cs.num_inputs(), 8); + assert_eq!(cs.get_input(0, "ONE"), Fr::one()); + assert_eq!(cs.get_input(1, "rk/x/input variable"), rk.0); + assert_eq!(cs.get_input(2, "rk/y/input variable"), rk.1); + assert_eq!( + cs.get_input(3, "value commitment/commitment point/x/input variable"), + expected_value_cm.0 + ); + assert_eq!( + cs.get_input(4, "value commitment/commitment point/y/input variable"), + expected_value_cm.1 + ); + assert_eq!(cs.get_input(5, "anchor/input variable"), cur); + assert_eq!(cs.get_input(6, "pack nullifier/input 0"), expected_nf[0]); + assert_eq!(cs.get_input(7, "pack nullifier/input 1"), expected_nf[1]); + } + } +} + #[test] fn test_output_circuit_with_bls12_381() { use bellman::gadgets::test::*; From 2b92493a45092c578b008275b1b4e19e7ae5be6e Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Tue, 4 Sep 2018 16:01:56 +0300 Subject: [PATCH 189/330] input circuit: removes debug prints --- zcash_proofs/src/circuit/sapling.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/zcash_proofs/src/circuit/sapling.rs b/zcash_proofs/src/circuit/sapling.rs index d84a2a2..7634c82 100644 --- a/zcash_proofs/src/circuit/sapling.rs +++ b/zcash_proofs/src/circuit/sapling.rs @@ -87,7 +87,6 @@ where &value_bits, params, )?; - println!("value: {}, {}", value.get_x().get_value().unwrap(), value.get_y().get_value().unwrap()); // Booleanize the randomness. This does not ensure // the bit representation is "in the field" because @@ -96,8 +95,6 @@ where cs.namespace(|| "rcv"), value_commitment.as_ref().map(|c| c.randomness), )?; - println!("rcv: {}", value_commitment.as_ref().unwrap().randomness); - println!("value: {}", value_commitment.as_ref().unwrap().value); // Compute the randomness in the exponent let rcv = ecc::fixed_base_multiplication( @@ -109,7 +106,6 @@ where // Compute the Pedersen commitment to the value let cv = value.add(cs.namespace(|| "computation of cv"), &rcv, params)?; - println!("cv: {}, {}", cv.get_x().get_value().unwrap(), cv.get_y().get_value().unwrap()); // Expose the commitment as an input to the circuit cv.inputize(cs.namespace(|| "commitment point"))?; @@ -274,17 +270,7 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { ¬e_contents, self.params, )?; - println!("cm: {}, {}", cm.get_x().get_value().unwrap(), cm.get_y().get_value().unwrap()); - let mut note_contents_print: Vec<&str> = vec![]; - for b in ¬e_contents { - if b.get_value().unwrap() { - note_contents_print.push("true"); - } else { - note_contents_print.push("false"); - } - } - println!("note_contents: {}", note_contents_print.join(", ")); { // Booleanize the randomness for the note commitment let rcm = boolean::field_into_boolean_vec_le( @@ -292,7 +278,6 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { self.commitment_randomness, )?; - println!("commitment_randomness: {}", &self.commitment_randomness.unwrap()); // Compute the note commitment randomness in the exponent let rcm = ecc::fixed_base_multiplication( cs.namespace(|| "computation of commitment randomness"), @@ -300,7 +285,6 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { &rcm, self.params, )?; - println!("rcm: {}, {}", rcm.get_x().get_value().unwrap(), rcm.get_y().get_value().unwrap()); // Randomize the note commitment. Pedersen hashes are not // themselves hiding commitments. @@ -309,8 +293,6 @@ impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { &rcm, self.params, )?; - - println!("cm: {}, {}", cm.get_x().get_value().unwrap(), cm.get_y().get_value().unwrap()); } // This will store (least significant bit first) From 2edcc12e8e2b2bca7ee40f7b996ea6e88fca75ea Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Tue, 28 Aug 2018 15:03:25 +0300 Subject: [PATCH 190/330] group_hash: adds test vectors generated by go-jubjub --- zcash_primitives/src/group_hash.rs | 92 ++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/zcash_primitives/src/group_hash.rs b/zcash_primitives/src/group_hash.rs index 8549c5e..a4d0bb5 100644 --- a/zcash_primitives/src/group_hash.rs +++ b/zcash_primitives/src/group_hash.rs @@ -39,3 +39,95 @@ pub fn group_hash( Err(_) => None, } } + +#[cfg(test)] +mod test { + use ff::PrimeField; + use pairing::bls12_381::{Bls12, Fr}; + + use crate::{ + group_hash::group_hash, + jubjub::{edwards, JubjubBls12, JubjubEngine, PrimeOrder}, + }; + + #[test] + fn test_group_hash() { + fn find_group_hash( + m: &[u8], + personalization: &[u8; 8], + params: &E::Params, + ) -> edwards::Point { + let mut tag = m.to_vec(); + let i = tag.len(); + tag.push(0u8); + + loop { + let gh = group_hash(&tag, personalization, params); + + // We don't want to overflow and start reusing generators + assert!(tag[i] != u8::max_value()); + tag[i] += 1; + + if let Some(gh) = gh { + break gh; + } + } + } + let params = JubjubBls12::new(); + + let expected_points: Vec> = vec![]; + let domains = vec![ + hex!("0b4c693149060f99"), + hex!("982fc029ed2213e4"), + hex!("5a01101e28c6b466"), + hex!("a3716d31a988b6e6"), + ]; + let msgs = vec![ + hex!("076cb41a3d40719b258b9f2d959e6e26555950ba05cee053cda7fd1b7a3e94907906959d36e3462ab8c8ec070fa99dbc0bc6e5554e9a7c30ba875fa3b3269e0dbd30b63b19313dbe3a50279e7d5d4e3787ebc794bac60c683ca8e3220fcf8a2bccf061a02635b32a1e368e82b345ae5a1af5150b0c703892b8da35a070ddacf97faf529602ef4071908b7df09d66c55da5543d1669888d64ad17785e555d202e00a8005afb0d490c0807377d45227f4474e1aa527694b0b7a0b17608b09bd44c8d8aa9debfe7a7620cd60fc623bfe26ddfb91e9ae32138dc3a0585c42ca89a61c299f9fe79f0e0237d8ee8b4d30186b77a88bd6f0d20b753a496c3bf399e9ca1b62ade8e7dd662c5a19123f077066be5dfa90e5a06c2624046ddf11ce7e53cc3f88d8aa2834363c8d38dc612d58a980317448ef79ccebdcbcd9f03d31a13727e7bff883135b87072d164436b1da4b4f214601cef55a5c5721618c0c6dac59464084b9ef9620729e8f9c7ef2c2c806f2506ccf7b8f2edcb675f8be1c50b288c3653e8db78baa785f0a0c2e059fdd2cf0104b597cdb9b82d03c63c161085da637fbfe444d3e5f9b9143088f2be54c1d293ac03967299dafca5b3c4f5e3257fe9010325531c9cc1cd67b70afad697ad750d8488b977ad3d3882f2d0050a0e22aab95eb13e80ffac09003a4282ef27820636b17ed11bc29bfe9b1941a0d5534510483f4178b327b7297b95b98832313999bedd43018e27ffb9d69777a4d7aeb1e5702171317949cb2577b897b059a976ce944a750b77ab07cf6ed4c8f45559f46dedcea4d5082772ac11ade8d1a057ce584000ef0bf4aa0b5589c5cca54fb69cc67d486ac040480efe6e5a38b3cb82c2b78ad125ee6cee4261644f38bdc34bf4da4dc087a394c313ec839a8a4ba6bcbf1eeb4afc15fd46fb9900a4744943efefffc477f8ca897e683d7d9f007f6c73ca4b64eb4ffb253f0a6137fc2956c74b9e869527b3bc5819c3d6cf6523bcd7a44599fdd6baeca754bc55d9ff338e64399d6dcaf50df0f1c5873991eb83fb92d3ce9b2bdd133b24b9edae467371563167c9402adadbfeed5d3f571a9fb1d5090004213fb333484d15ed753fbaeacf16aeb9764a960c5b7b382d2d925050fd103a0bc1ae709cfff11e701cad99d82eb42a493ef2f32862ac07cbe2494b354511cdfc6417dfa647c967026552e39cb96282e40c4ad7c3d838b2edb0df0e9b98bb90280998ff8cafa456fafaa6a769ad47599bec3fe242211424369acca65ad5507f96881130262b407d0f5fdabfbdb1b97570dd3b397fce15234674a90812f7eb6ddc5cb21db5b64e25a8449e67a7ae09d2e438d1da8ff5e06ff417d5c0d432a2fe811ad216ccd46f71202b0bd045dc3664f8d2a4b78de8991191876c38959056c02764d1cabec14de12aa059dea10d0d20b75a7f"), + hex!("814d0b90d16d7d4c270913ab375291651ea130aa5608d5fc625a8daaf49d15ac3977f879126f19f651b8b167f5debf3e824efcf7fe27789025026e91db64f271ea2b3787448bddac9992d45b3419209bd4ec43dda893af5ce21939c3cfceef2b2b3bbb8bebe19cc3e5068c54ca4eb0c80152f0a9738f01a48f2b86503213a0ea50008d77a96842749bd3aa09368f641df231b8ea58a1ab76b311cc3c5f6341216407f0e3bb9e20efc50b8430ce3eb848c53441e1c22cd358042d4f7fc0bcb41a3b45edd30d52b0acb67ec67312fbbf47b3fa1716ab14caeab013c30a886070b9e8bce8e3c6d24e57e3e96e9ad044a7e2a6ea13a6a2dbffca1b81ba76075831b167ff423523429ffa42a03654329d86475642d1b1ed9f597d45147884a88844d33bec515a0b38d1e0351647c7c522bcdcf5c9286afda49431c2e156f4a8859d28b6e19eaabee2adf42acadfd9ae8ed6b1031c4d4c9feea5380db5e56ec036ff656c3eb59f11e58bffbbd988177bd2a0116ca2870e4d471f5c7f5c36463089118ed57073bc069eb209264640b3048a0204b4af3d714e64b502b4168514f86d0269346e78ea9d0d33926e3c784f3ea3dd07ad1bc188fad41880333786e821322d0c8be675fde29ea0a3f6ed30fc46c79447f4368ffc8268fba099b5b0ca7cb75995313a556c7ab339f0c03af811bae47f4806f2b6eacec66f15e4656cefe3df08887a625f14bf497d2f8bf99a68e7361193116a3bb1765d7e8e7bc4d4864c88dbfb818334b8cfb5dca3620e097e40756a1f7d28c7868d7dd65e49bc5155e26c8973d476e25fb1ea75e382f654bdfbe2bc45540f215a357fa29cd6238e8bd1085ce625f43f40eaa1d20bcf9772890725ca27b4d38c9870d91530f95a406d90b1b77c700d0d0296a1ded208507b7284fb4d2202c7fe9a20ef96700f7eb70e3eaad51bb95e215da42794fd17d0aae260cecccf99dcbde251f6c115acbee8a30745bffa43f572383112f45e97a3316edc96a8f6f9dfd55cc99f878e627a46ef65ac95f81eedb14106dcb0b2c6c53bb9034ead2338b28b20c09f2f17f202a7b6c1be3e8885f119e4f6599e05ddcd5b74a99af7c935228899de177a93438da57ce396782f65032ef40805ec01e7375b07dd71929fddb88995da03a879437f34534514d48b1ae5ba86e096d00951e7b96ad890ed85dd4a2f79214f7193ca02facb19d9d99ca1bca3ffd237abfd57c4d9b210115f5d62a092d36b100b1f84b17889bb59fd84d47e046ec646ee99a3c14c2ad9fd78628c76035ad126ea3ac0f7543d15f569d9de5467d54f3536105e7f9d0592d2e3a3b9175f252e6243fc1694231ea5159f865d2997eeb50241c4a7ab5e0d97ec760c40212116f3b1f139c48be3696c717329878dacdd7376c81ef8c077d2eac4d8516551cac435077d2359a24e624a1b26b8"), + hex!("6b94782eb58954430de33992f53f4ee00f99977a8cfa30eda3021673182e39b046594fc8df623e23a58bb136aa294feb4c4e7a692db5b537176eb0c521fde239eb6a5218fc82bcb7de114e05120b91a605beff13a9968564aefc15255bfb6ba2ebe37832ecf9168ac65dd01015df8b9372472c9cc5b4446b73467afdabdd25a629eec87ee0221a93f7bd88125f1178d427cb21c288a8d8c3cb4d1843a57d4637bdb1eeffa1dd8276ac680140e73657ed4a84563f5b09ddfb604bf4c2ddd6075db6b02d78c4cb02a4ce3aac20aa15e3a5d5b30669b343c5239c134f76de18185a6e0a66407c26023d3049adc74b0fdde0a9176cc3e2ccb9bf03ee306953a9ac1312c68c65a284110590c29dc8baff373ad49a40e3de8098c67dca210c26f768745bfa859b0a3fc5e88985d046abcb5e6155e0e23115ad062d10d1b73af0680f9a141e379bbd177bb0f9ea3bb5f01b8a5665bf0a9ea1266138bd688572a779c0b0a69e57f40dfb418d514f8ab058ba28eeb21cefa3634300e89d204c4236848f5dd11130ba13d83c10afebd4f822c26ae0ed7ea3bc3ac92817ae405c3cf886c81bdda07447cebb71a8bc3d26973afa57e0365b8fc8c0658131734ca29afa10eeb0895d3cd5f0b84a625f53f9f3dbfc5bfac233c7c7d3ac8829475076b14e5c57026c4a63bc9a347ec3fdbcc997cea4c273f923e01fa0781f847cea54a81a4ed14117a46b0894bf4816a46b1f7af963382eeb6f58ed35fa70572a7bb3f2bf97d8c549fc55d7bf562c2d8c4d4d748b7d062cb41b025309b5587a4b2a0cedc85280dce2f58dad0943ccd591b2ee7bb39378efa09cbdd975af07c33862f560d03e1621374cadf6cb05484a23a37d3c200bc3e1780ac65b02bab7db25fe89dae218d9e7dfb60473f9f5b21a007b714eef58129518d637bd581922a54629bef62a575a98d513d9abb90b023752439e20d897242fea3fabcf3fb7eae7604fd0dd1bd5653c41276660a15d39093e4c0862d48333b77b8bc3d64a5908614b3af7c815406b3ba21598cf0c70afe7b8a8ca668dfc8376e15a0ba0d9b9a79552993d2a24f3d0689964e7141d4255a19cc9450806d632a73b88a5768d0de18c20f2b00268ce5d3a8ca2231ce3d8924335f650cb98df84bb58073166848786de3d1823075259952389c50bced6c8921e7b019977d58c5a07e57eb21ef907a9dd465962bd52beb0cbad28b434ed7fecde21953b3fd260a90fd9ab7495c47cdaa4e73fb487a5239e03fb1e74e8cf6d691126813a6f5c16ae948da8cda292fd46e79f7551f8553b21249a5679a5f56dd4b08a136ce0fe8146bddc1d60e0a9a757e1a608749bcce4ac57cdc8fafff59860fd22f95f46f3ab50812a6b877f24941c2b8e1724e527ba9ad9331e004792d2b292a7edee983e6cc22445f4fd43e9f006ddea19fbe6269f29cd"), + hex!("883b1a34c0d0a8d9387cff427ab0b476b4c6f5a09e30be336aa2bc35f38ab4cc398673fae02ab727f069e887006ac3c0b891477c4a837456417c9e817c5ccdaf12b54eb90cc18a9c30673ed36bd7fba45269437c09feff9a1bcc2993533533227a535950c98cc77f00f4e77c34184b45d865942a3d72acce4922e9c284df5589d506404648c5c3bc7f217ca023b364e74d591d75c8a19e063b2b82c28e27ce5b2afede6699d6bf8d4931244aad739b285f410f1e95c6d5e9a34982908d1c7be5f0365dbf30a7d6dbb2821bf6d55c142a15bd561f3eb202da9b59f891584b35011f5cbe77cab38263b5773360d52e29b765a03c420c75ffa2c91e8edd4a9bba4035119bc3a088ec303a6344e4dafbd8d1889cc9b3d56ee08cff1530f1a1d9a77712006ebc9a3d80f5a69e17b0a0f65d97e53e7852ddd95760c68bba78d326a28eb07908c8e630dd6e42ab272e980774c5c51825c02ed8950fc85f5711c80d5fed1d72162a4bcaefbba33c09d09e0611ad5c2bb2949daa55861b5f6f8beea02ed392d09ab0489f89b3875fe7ae90c6ecf0bddb4b9fbce6dc1f97b12ee058f00cc9672c35702dac4afbd6776e1e222d2182358e91e8d4d20b99d5f2adbac7abad48c07afc94c212278812bfc5e76da0e1b97b850020bc1ba3c0bc0093d8acf4a594a8fc1dcea70c613fcc550b7654a08ed9f50a34c21626f2b599a15a097c85785bc93d5c5034edb3590f0c6aee3dcbeac5f15be5bf6f179246c347dce5040115dccff18fbcd9e9ab485d85e89dc0995aaebe4eb8796fb01b03fe5f5c6c903845a0fc02c69d2543684a33e4eefc7e0d5635192c82fdde5e7487df95595a442a6a71e98e09073cdf318f808fd916e0de7e9182855023f4844042764fef897ccb500d520651a262d27f46c16e38187da84a3d7f9c42bb65e1940a1f3b3c2eced613e141839d77851ef833f94d9a5ec073e1b12d0a2b59b8b90c5e560baceacebe569f8ded41a67d15cd7486f45aacc1fa4e50805485a698d2722ba8fbf87442e1a2e46cde49f1600f97ae3d6f67169141a40b0628c9994c115377db6c30d822381dede366f355c71ff8c38ae4f60da77bf40e3da97f77ba6756ae766a17896ead15d4367f43fd2a4c096feb3e23d4a061fed2422e9e424f1e81e890ecc9474bb5b7d8231447d5359efa8ce4d40698d329cd5d069f50050d26a0c613a4cc3d70774537af278643799bf5d336d71a19b83a5660ebc6fefa4664167c497478ec4e8b0954fc1a41948a84f5271c4c2ab93c6848fe5abd28fa68b47ff79ba1475a46d2ddbf5a07600ee4cf76bf85bccc53d5b5094f6728542951a63c71b251429e8bb4fc95cfbf283db2b0ad2d16bc2d8ba07b193249bc974eb5392b7e9c5a0e1056ef0208e6494abe61f37d64b543acf509926f7b9f1724ce39e7690bae4d918be3295fd2") + ]; + + let ys = vec![ + "8502599294297669157183582041043506286304348771153601905088214968423735432772", + "33965310400650966081486833884535323100804531882948083108992748314044766607474", + "15277426621450144245366093477629790944965634885834431068514786570163432982421", + "35526445498940553839675656924597924255939683458731864358252626115877434851278", + ]; + let xs = vec![ + "23479585783156774250942425515624703792585157520679515316930097097463607664576", + "30414851484511157010605445406157992259368652076831836832380699127755424334026", + "34566775937206506013251574661622220967552701387632591444790779184716709173668", + "32625571922270028001313966220069858825087579007581150636305043327525524456655", + ]; + for i in 0..domains.len() { + let domain = domains[i]; + let msg = msgs[i]; + + let gh: edwards::Point = find_group_hash(&msg, &domain, ¶ms); + + let p_sign_false = + edwards::Point::::get_for_y(Fr::from_str(ys[i]).unwrap(), false, ¶ms) + .unwrap(); + let p_sign_true = + edwards::Point::::get_for_y(Fr::from_str(ys[i]).unwrap(), true, ¶ms) + .unwrap(); + let is_one_of_xs = p_sign_false.to_xy().0 == Fr::from_str(xs[i]).unwrap() + || p_sign_true.to_xy().0 == Fr::from_str(xs[i]).unwrap(); + let is_y = p_sign_false.to_xy().1 == Fr::from_str(ys[i]).unwrap() + && p_sign_true.to_xy().1 == Fr::from_str(ys[i]).unwrap(); + assert!(is_one_of_xs && is_y); + } + + for m in 0..5 { + use byteorder::{LittleEndian, WriteBytesExt}; + let mut segment_number = [0u8; 4]; + (&mut segment_number[0..4]) + .write_u32::(m) + .unwrap(); + let p: edwards::Point = + find_group_hash(&segment_number, b"Zcash_PH", ¶ms); + } + } +} From 2ee7b108af3b6b1f4cbdca2219708e95bf2e952f Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Tue, 4 Sep 2018 15:52:08 +0300 Subject: [PATCH 191/330] blake2s: adds test vectors from go-jubjub --- bellman/src/gadgets/blake2s.rs | 67 ++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/bellman/src/gadgets/blake2s.rs b/bellman/src/gadgets/blake2s.rs index d89aac5..1c52cfa 100644 --- a/bellman/src/gadgets/blake2s.rs +++ b/bellman/src/gadgets/blake2s.rs @@ -628,4 +628,71 @@ mod test { } } } + + #[test] + fn test_blake2s_test_vectors() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); + + let expecteds = [ + hex!("a1309e334376c8f36a736a4ab0e691ef931ee3ebdb9ea96187127136fea622a1"), + hex!("82fefff60f265cea255252f7c194a7f93965dffee0609ef74eb67f0d76cd41c6"), + ]; + for i in 0..2 { + let mut h = Blake2sParams::new() + .hash_length(32) + .personal(b"12345678") + .to_state(); + let input_len = 1024; + let data: Vec = (0..input_len).map(|_| rng.next_u32() as u8).collect(); + + h.update(&data); + + let hash_result = h.finalize(); + + let mut cs = TestConstraintSystem::::new(); + + let mut input_bits = vec![]; + + for (byte_i, input_byte) in data.into_iter().enumerate() { + for bit_i in 0..8 { + let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i)); + + input_bits.push( + AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)) + .unwrap() + .into(), + ); + } + } + + let r = blake2s(&mut cs, &input_bits, b"12345678").unwrap(); + + assert!(cs.is_satisfied()); + + let mut s = hash_result + .as_ref() + .iter() + .flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8)); + + for b in r { + match b { + Boolean::Is(b) => { + assert!(s.next().unwrap() == b.get_value().unwrap()); + } + Boolean::Not(b) => { + assert!(s.next().unwrap() != b.get_value().unwrap()); + } + Boolean::Constant(b) => { + assert!(input_len == 0); + assert!(s.next().unwrap() == b); + } + } + } + + assert_eq!(expecteds[i], hash_result.as_bytes()); + } + } } From f5dfe073556c050c8a32ba7f61b24868cc554ae0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Nicolas?= Date: Tue, 31 Jul 2018 10:32:31 +0200 Subject: [PATCH 192/330] A test vector for pedersen hash --- zcash_primitives/src/jubjub/edwards.rs | 1 + zcash_primitives/src/pedersen_hash.rs | 43 ++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/zcash_primitives/src/jubjub/edwards.rs b/zcash_primitives/src/jubjub/edwards.rs index 9ef50a2..9902d80 100644 --- a/zcash_primitives/src/jubjub/edwards.rs +++ b/zcash_primitives/src/jubjub/edwards.rs @@ -306,6 +306,7 @@ impl Point { } } + /// Convert to affine coordinates pub fn to_xy(&self) -> (E::Fr, E::Fr) { let zinv = self.z.inverse().unwrap(); diff --git a/zcash_primitives/src/pedersen_hash.rs b/zcash_primitives/src/pedersen_hash.rs index 835e9c7..9daeedd 100644 --- a/zcash_primitives/src/pedersen_hash.rs +++ b/zcash_primitives/src/pedersen_hash.rs @@ -105,3 +105,46 @@ where result } + +#[cfg(test)] +mod test { + + use pairing::bls12_381::{Bls12, Fr}; + use super::*; + + #[test] + fn test_pedersen_hash_points() { + + let params = &JubjubBls12::new(); + let bytes = b"Salut monde!"; + let num_bits = bytes.len() * 8; + let bits: Vec = (0..num_bits).map( + |i| ((bytes[i / 8] >> (7 - (i % 8))) & 1) == 1 + ).collect(); + + let xy = pedersen_hash::( + Personalization::NoteCommitment, + bits.clone().into_iter(), + params, + ).to_xy(); + + println!("bytes = {:?}", bytes); + let bits_int: Vec = bits.iter().map(|&i| i as u8).collect(); + println!("bits = {:?}", bits_int); + println!("x = {}", xy.0); + println!("y = {}", xy.1); + + // For bits=[] + //assert_eq!(xy.0.to_string(), "Fr(0x06b1187c11ca4fb4383b2e0d0dbbde3ad3617338b5029187ec65a5eaed5e4d0b)"); + //assert_eq!(xy.1.to_string(), "Fr(0x3ce70f536652f0dea496393a1e55c4e08b9d55508e16d11e5db40d4810cbc982)"); + + // For bits=[0] + // assert_eq!(xy.0.to_string(), "Fr(0x2fc3bc454c337f71d4f04f86304262fcbfc9ecd808716b92fc42cbe6827f7f1a)"); + // assert_eq!(xy.1.to_string(), "Fr(0x46d0d25bf1a654eedc6a9b1e5af398925113959feac31b7a2c036ff9b9ec0638)"); + + // For bits = "Salut monde!" in ASCII + assert_eq!(xy.0.to_string(), "Fr(0x676f78fa89da7c64502f790a99dfe177756867006809a6f174dcb427b345cd7c)"); + assert_eq!(xy.1.to_string(), "Fr(0x1a6994a999a0abf83afc6ec5fe0ee8c8336a171653218cbfdf269689d5cfd3aa)"); + + } +} \ No newline at end of file From 9080b4ccf3dc17bdb404a8cc3311dda5f6023175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Nicolas?= Date: Tue, 31 Jul 2018 21:42:53 +0200 Subject: [PATCH 193/330] Many test vectors for pedersen hash --- zcash_primitives/src/pedersen_hash.rs | 180 ++++++++++++++++++++++---- 1 file changed, 152 insertions(+), 28 deletions(-) diff --git a/zcash_primitives/src/pedersen_hash.rs b/zcash_primitives/src/pedersen_hash.rs index 9daeedd..fb396cc 100644 --- a/zcash_primitives/src/pedersen_hash.rs +++ b/zcash_primitives/src/pedersen_hash.rs @@ -109,42 +109,166 @@ where #[cfg(test)] mod test { - use pairing::bls12_381::{Bls12, Fr}; use super::*; + use pairing::bls12_381::Bls12; #[test] fn test_pedersen_hash_points() { + // Test vectors from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_pedersen.py + struct TestVector<'a> { + personalization: Personalization, + input_bits: Vec, + hash_x: &'a str, + hash_y: &'a str, + } + + let test_vectors = vec![ + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1], + hash_x: "Fr(0x06b1187c11ca4fb4383b2e0d0dbbde3ad3617338b5029187ec65a5eaed5e4d0b)", + hash_y: "Fr(0x3ce70f536652f0dea496393a1e55c4e08b9d55508e16d11e5db40d4810cbc982)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 0], + hash_x: "Fr(0x2fc3bc454c337f71d4f04f86304262fcbfc9ecd808716b92fc42cbe6827f7f1a)", + hash_y: "Fr(0x46d0d25bf1a654eedc6a9b1e5af398925113959feac31b7a2c036ff9b9ec0638)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 1], + hash_x: "Fr(0x4f8ce0e0a9e674b3ab9606a7d7aefba386e81583d81918127814cde41d209d97)", + hash_y: "Fr(0x312b5ab93b14c9b9af334fe1fe3c50fffb53fbd074fa40ca600febde7c97e346)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 0, 0], + hash_x: "Fr(0x2fc3bc454c337f71d4f04f86304262fcbfc9ecd808716b92fc42cbe6827f7f1a)", + hash_y: "Fr(0x46d0d25bf1a654eedc6a9b1e5af398925113959feac31b7a2c036ff9b9ec0638)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 0, 1], + hash_x: "Fr(0x21746acd049f2c54579d5bb9c106083b4bb48c8910a06565d1e39e46939ca497)", + hash_y: "Fr(0x2cb69ae2615cd02c6ad2d6e06c1a0c15d49d71051d2d702155fca07bbf2d574c)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 1, 0], + hash_x: "Fr(0x4f8ce0e0a9e674b3ab9606a7d7aefba386e81583d81918127814cde41d209d97)", + hash_y: "Fr(0x312b5ab93b14c9b9af334fe1fe3c50fffb53fbd074fa40ca600febde7c97e346)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 1, 1], + hash_x: "Fr(0x3e09bdeea175dd4acd2e106caf4a5194200af53ee3a5a71338c083093d83eba5)", + hash_y: "Fr(0x579f6f15508af07d0f1beb117beaffe99e115a7ee859d81ddaa91d1096a103df)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + hash_x: "Fr(0x208d2e11ee496eb3b37257d1b4a77907e4b21d6c46d5487fb52d5a5239587ea0)", + hash_y: "Fr(0x1eeeb47b858257b9b69d009779e38c63332e20220eb474ef9af868274132181f)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + hash_x: "Fr(0x683ffae48988d517301ba81fb2c294c16a35ed1bba6411bd17312294843f37e0)", + hash_y: "Fr(0x40f7897b86747a5a857c8bd434ce3c1079efac22ed650d7345e5da31addacaff)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![ + 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, + 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, + 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, + ], + hash_x: "Fr(0x676f78fa89da7c64502f790a99dfe177756867006809a6f174dcb427b345cd7c)", + hash_y: "Fr(0x1a6994a999a0abf83afc6ec5fe0ee8c8336a171653218cbfdf269689d5cfd3aa)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1], + hash_x: "Fr(0x61f8e2cb8e945631677b450d5e5669bc6b5f2ec69b321ac550dbe74525d7ac9a)", + hash_y: "Fr(0x4e11951ab9c9400ee38a18bd98cdb9453f1f67141ee9d9bf0c1c157d4fb34f9a)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 0], + hash_x: "Fr(0x27fa1e296c37dde8448483ce5485c2604d1d830e53812246299773a02ecd519c)", + hash_y: "Fr(0x08e499113675202cb42b4b681a31430814edebd72c5bb3bc3bfedf91fb0605df)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 1], + hash_x: "Fr(0x52112dd7a4293d049bb011683244a0f957e6ba95e1d1cf2fb6654d449a6d3fbc)", + hash_y: "Fr(0x2ae14ecd81bb5b4489d2d64b5d2eb92a684087b28dd9a4950ecdb78c014e178c)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 0, 0], + hash_x: "Fr(0x27fa1e296c37dde8448483ce5485c2604d1d830e53812246299773a02ecd519c)", + hash_y: "Fr(0x08e499113675202cb42b4b681a31430814edebd72c5bb3bc3bfedf91fb0605df)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 0, 1], + hash_x: "Fr(0x5b4032d49431e7bfa085e2bb49bfc060909272a66287b063784f1d11b28a60e9)", + hash_y: "Fr(0x4627da49652efea2637595426add6ad682a0c8821d423f04c26ef5788d35f7e3)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 1, 0], + hash_x: "Fr(0x52112dd7a4293d049bb011683244a0f957e6ba95e1d1cf2fb6654d449a6d3fbc)", + hash_y: "Fr(0x2ae14ecd81bb5b4489d2d64b5d2eb92a684087b28dd9a4950ecdb78c014e178c)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 1, 1], + hash_x: "Fr(0x099e74a82c9c1858ac40db1a85959b1362d82fdd6efb99a443829f83003b0190)", + hash_y: "Fr(0x0f76f53d026574ad77ab4c6cd2428b9d94d158a9fc0469aae47c7535ff107881)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + hash_x: "Fr(0x240da48e40637664bcf3582708491d19e28a50787ea40b0a336d61735782d10a)", + hash_y: "Fr(0x6e630ddf6e43ad5568c925a4935e8e099230af4b2e19fab7d92b7e953b4986c3)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + hash_x: "Fr(0x06a477addbbfdf2934e34bdf6e071cd1276beaed801cd1b660ddcceb161ca8c7)", + hash_y: "Fr(0x355d39425378e57f393b30423cbde3ff69198ebac2ccbbafb92e25613352b0e8)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![ + 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, + 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, + 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, + ], + hash_x: "Fr(0x094a624c5aac3569ad85428bb939d391bb5766ff87c389eb4d84d42aeaabb906)", + hash_y: "Fr(0x2cf51a8699edc64b73aa962464d4eadf038821900f9409350dc3ea2ccf12e054)", + }, + ]; + // End test vectors let params = &JubjubBls12::new(); - let bytes = b"Salut monde!"; - let num_bits = bytes.len() * 8; - let bits: Vec = (0..num_bits).map( - |i| ((bytes[i / 8] >> (7 - (i % 8))) & 1) == 1 - ).collect(); - let xy = pedersen_hash::( - Personalization::NoteCommitment, - bits.clone().into_iter(), - params, - ).to_xy(); + let v = &test_vectors[0]; + let input_bools: Vec = v.input_bits.iter().map(|&i| i == 1).collect(); - println!("bytes = {:?}", bytes); - let bits_int: Vec = bits.iter().map(|&i| i as u8).collect(); - println!("bits = {:?}", bits_int); - println!("x = {}", xy.0); - println!("y = {}", xy.1); + // The 6 bits prefix is handled separately + assert_eq!(v.personalization.get_bits(), &input_bools[..6]); - // For bits=[] - //assert_eq!(xy.0.to_string(), "Fr(0x06b1187c11ca4fb4383b2e0d0dbbde3ad3617338b5029187ec65a5eaed5e4d0b)"); - //assert_eq!(xy.1.to_string(), "Fr(0x3ce70f536652f0dea496393a1e55c4e08b9d55508e16d11e5db40d4810cbc982)"); - - // For bits=[0] - // assert_eq!(xy.0.to_string(), "Fr(0x2fc3bc454c337f71d4f04f86304262fcbfc9ecd808716b92fc42cbe6827f7f1a)"); - // assert_eq!(xy.1.to_string(), "Fr(0x46d0d25bf1a654eedc6a9b1e5af398925113959feac31b7a2c036ff9b9ec0638)"); - - // For bits = "Salut monde!" in ASCII - assert_eq!(xy.0.to_string(), "Fr(0x676f78fa89da7c64502f790a99dfe177756867006809a6f174dcb427b345cd7c)"); - assert_eq!(xy.1.to_string(), "Fr(0x1a6994a999a0abf83afc6ec5fe0ee8c8336a171653218cbfdf269689d5cfd3aa)"); + let (x, y) = + pedersen_hash::(v.personalization, input_bools.into_iter().skip(6), params) + .to_xy(); + assert_eq!(x.to_string(), v.hash_x); + assert_eq!(y.to_string(), v.hash_y); } -} \ No newline at end of file +} From be18eb240c4253cadc31a8714fa4f02e569eaab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Nicolas?= Date: Sun, 19 Aug 2018 11:01:07 +0200 Subject: [PATCH 194/330] Move test vectors into own module --- zcash_primitives/src/pedersen_hash.rs | 152 ++---------------- zcash_primitives/src/test_vectors.rs | 1 + .../src/test_vectors/pedersen_hash_vectors.rs | 138 ++++++++++++++++ 3 files changed, 149 insertions(+), 142 deletions(-) create mode 100644 zcash_primitives/src/test_vectors/pedersen_hash_vectors.rs diff --git a/zcash_primitives/src/pedersen_hash.rs b/zcash_primitives/src/pedersen_hash.rs index fb396cc..10cad94 100644 --- a/zcash_primitives/src/pedersen_hash.rs +++ b/zcash_primitives/src/pedersen_hash.rs @@ -107,154 +107,22 @@ where } #[cfg(test)] -mod test { +pub mod test { use super::*; + use crate::test_vectors::pedersen_hash_vectors; use pairing::bls12_381::Bls12; + pub struct TestVector<'a> { + pub personalization: Personalization, + pub input_bits: Vec, + pub hash_x: &'a str, + pub hash_y: &'a str, + } + #[test] fn test_pedersen_hash_points() { - // Test vectors from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_pedersen.py - struct TestVector<'a> { - personalization: Personalization, - input_bits: Vec, - hash_x: &'a str, - hash_y: &'a str, - } - - let test_vectors = vec![ - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1], - hash_x: "Fr(0x06b1187c11ca4fb4383b2e0d0dbbde3ad3617338b5029187ec65a5eaed5e4d0b)", - hash_y: "Fr(0x3ce70f536652f0dea496393a1e55c4e08b9d55508e16d11e5db40d4810cbc982)", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 0], - hash_x: "Fr(0x2fc3bc454c337f71d4f04f86304262fcbfc9ecd808716b92fc42cbe6827f7f1a)", - hash_y: "Fr(0x46d0d25bf1a654eedc6a9b1e5af398925113959feac31b7a2c036ff9b9ec0638)", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 1], - hash_x: "Fr(0x4f8ce0e0a9e674b3ab9606a7d7aefba386e81583d81918127814cde41d209d97)", - hash_y: "Fr(0x312b5ab93b14c9b9af334fe1fe3c50fffb53fbd074fa40ca600febde7c97e346)", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 0, 0], - hash_x: "Fr(0x2fc3bc454c337f71d4f04f86304262fcbfc9ecd808716b92fc42cbe6827f7f1a)", - hash_y: "Fr(0x46d0d25bf1a654eedc6a9b1e5af398925113959feac31b7a2c036ff9b9ec0638)", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 0, 1], - hash_x: "Fr(0x21746acd049f2c54579d5bb9c106083b4bb48c8910a06565d1e39e46939ca497)", - hash_y: "Fr(0x2cb69ae2615cd02c6ad2d6e06c1a0c15d49d71051d2d702155fca07bbf2d574c)", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 1, 0], - hash_x: "Fr(0x4f8ce0e0a9e674b3ab9606a7d7aefba386e81583d81918127814cde41d209d97)", - hash_y: "Fr(0x312b5ab93b14c9b9af334fe1fe3c50fffb53fbd074fa40ca600febde7c97e346)", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 1, 1], - hash_x: "Fr(0x3e09bdeea175dd4acd2e106caf4a5194200af53ee3a5a71338c083093d83eba5)", - hash_y: "Fr(0x579f6f15508af07d0f1beb117beaffe99e115a7ee859d81ddaa91d1096a103df)", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - hash_x: "Fr(0x208d2e11ee496eb3b37257d1b4a77907e4b21d6c46d5487fb52d5a5239587ea0)", - hash_y: "Fr(0x1eeeb47b858257b9b69d009779e38c63332e20220eb474ef9af868274132181f)", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - hash_x: "Fr(0x683ffae48988d517301ba81fb2c294c16a35ed1bba6411bd17312294843f37e0)", - hash_y: "Fr(0x40f7897b86747a5a857c8bd434ce3c1079efac22ed650d7345e5da31addacaff)", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![ - 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, - 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, - 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, - ], - hash_x: "Fr(0x676f78fa89da7c64502f790a99dfe177756867006809a6f174dcb427b345cd7c)", - hash_y: "Fr(0x1a6994a999a0abf83afc6ec5fe0ee8c8336a171653218cbfdf269689d5cfd3aa)", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1], - hash_x: "Fr(0x61f8e2cb8e945631677b450d5e5669bc6b5f2ec69b321ac550dbe74525d7ac9a)", - hash_y: "Fr(0x4e11951ab9c9400ee38a18bd98cdb9453f1f67141ee9d9bf0c1c157d4fb34f9a)", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 0], - hash_x: "Fr(0x27fa1e296c37dde8448483ce5485c2604d1d830e53812246299773a02ecd519c)", - hash_y: "Fr(0x08e499113675202cb42b4b681a31430814edebd72c5bb3bc3bfedf91fb0605df)", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 1], - hash_x: "Fr(0x52112dd7a4293d049bb011683244a0f957e6ba95e1d1cf2fb6654d449a6d3fbc)", - hash_y: "Fr(0x2ae14ecd81bb5b4489d2d64b5d2eb92a684087b28dd9a4950ecdb78c014e178c)", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 0, 0], - hash_x: "Fr(0x27fa1e296c37dde8448483ce5485c2604d1d830e53812246299773a02ecd519c)", - hash_y: "Fr(0x08e499113675202cb42b4b681a31430814edebd72c5bb3bc3bfedf91fb0605df)", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 0, 1], - hash_x: "Fr(0x5b4032d49431e7bfa085e2bb49bfc060909272a66287b063784f1d11b28a60e9)", - hash_y: "Fr(0x4627da49652efea2637595426add6ad682a0c8821d423f04c26ef5788d35f7e3)", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 1, 0], - hash_x: "Fr(0x52112dd7a4293d049bb011683244a0f957e6ba95e1d1cf2fb6654d449a6d3fbc)", - hash_y: "Fr(0x2ae14ecd81bb5b4489d2d64b5d2eb92a684087b28dd9a4950ecdb78c014e178c)", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 1, 1], - hash_x: "Fr(0x099e74a82c9c1858ac40db1a85959b1362d82fdd6efb99a443829f83003b0190)", - hash_y: "Fr(0x0f76f53d026574ad77ab4c6cd2428b9d94d158a9fc0469aae47c7535ff107881)", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - hash_x: "Fr(0x240da48e40637664bcf3582708491d19e28a50787ea40b0a336d61735782d10a)", - hash_y: "Fr(0x6e630ddf6e43ad5568c925a4935e8e099230af4b2e19fab7d92b7e953b4986c3)", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - hash_x: "Fr(0x06a477addbbfdf2934e34bdf6e071cd1276beaed801cd1b660ddcceb161ca8c7)", - hash_y: "Fr(0x355d39425378e57f393b30423cbde3ff69198ebac2ccbbafb92e25613352b0e8)", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![ - 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, - 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, - 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, - ], - hash_x: "Fr(0x094a624c5aac3569ad85428bb939d391bb5766ff87c389eb4d84d42aeaabb906)", - hash_y: "Fr(0x2cf51a8699edc64b73aa962464d4eadf038821900f9409350dc3ea2ccf12e054)", - }, - ]; - // End test vectors + let test_vectors = pedersen_hash_vectors::get_vectors(); let params = &JubjubBls12::new(); diff --git a/zcash_primitives/src/test_vectors.rs b/zcash_primitives/src/test_vectors.rs index 403fbc9..1347b2d 100644 --- a/zcash_primitives/src/test_vectors.rs +++ b/zcash_primitives/src/test_vectors.rs @@ -1 +1,2 @@ pub(crate) mod note_encryption; +pub(crate) mod pedersen_hash_vectors; diff --git a/zcash_primitives/src/test_vectors/pedersen_hash_vectors.rs b/zcash_primitives/src/test_vectors/pedersen_hash_vectors.rs new file mode 100644 index 0000000..a3f26d1 --- /dev/null +++ b/zcash_primitives/src/test_vectors/pedersen_hash_vectors.rs @@ -0,0 +1,138 @@ +//! Test vectors from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_pedersen.py + +use crate::pedersen_hash::{test::TestVector, Personalization}; + +pub fn get_vectors<'a>() -> Vec> { + return vec![ + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1], + hash_x: "Fr(0x06b1187c11ca4fb4383b2e0d0dbbde3ad3617338b5029187ec65a5eaed5e4d0b)", + hash_y: "Fr(0x3ce70f536652f0dea496393a1e55c4e08b9d55508e16d11e5db40d4810cbc982)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 0], + hash_x: "Fr(0x2fc3bc454c337f71d4f04f86304262fcbfc9ecd808716b92fc42cbe6827f7f1a)", + hash_y: "Fr(0x46d0d25bf1a654eedc6a9b1e5af398925113959feac31b7a2c036ff9b9ec0638)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 1], + hash_x: "Fr(0x4f8ce0e0a9e674b3ab9606a7d7aefba386e81583d81918127814cde41d209d97)", + hash_y: "Fr(0x312b5ab93b14c9b9af334fe1fe3c50fffb53fbd074fa40ca600febde7c97e346)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 0, 0], + hash_x: "Fr(0x2fc3bc454c337f71d4f04f86304262fcbfc9ecd808716b92fc42cbe6827f7f1a)", + hash_y: "Fr(0x46d0d25bf1a654eedc6a9b1e5af398925113959feac31b7a2c036ff9b9ec0638)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 0, 1], + hash_x: "Fr(0x21746acd049f2c54579d5bb9c106083b4bb48c8910a06565d1e39e46939ca497)", + hash_y: "Fr(0x2cb69ae2615cd02c6ad2d6e06c1a0c15d49d71051d2d702155fca07bbf2d574c)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 1, 0], + hash_x: "Fr(0x4f8ce0e0a9e674b3ab9606a7d7aefba386e81583d81918127814cde41d209d97)", + hash_y: "Fr(0x312b5ab93b14c9b9af334fe1fe3c50fffb53fbd074fa40ca600febde7c97e346)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 1, 1], + hash_x: "Fr(0x3e09bdeea175dd4acd2e106caf4a5194200af53ee3a5a71338c083093d83eba5)", + hash_y: "Fr(0x579f6f15508af07d0f1beb117beaffe99e115a7ee859d81ddaa91d1096a103df)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + hash_x: "Fr(0x208d2e11ee496eb3b37257d1b4a77907e4b21d6c46d5487fb52d5a5239587ea0)", + hash_y: "Fr(0x1eeeb47b858257b9b69d009779e38c63332e20220eb474ef9af868274132181f)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + hash_x: "Fr(0x683ffae48988d517301ba81fb2c294c16a35ed1bba6411bd17312294843f37e0)", + hash_y: "Fr(0x40f7897b86747a5a857c8bd434ce3c1079efac22ed650d7345e5da31addacaff)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![ + 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, + 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, + 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, + 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, + ], + hash_x: "Fr(0x676f78fa89da7c64502f790a99dfe177756867006809a6f174dcb427b345cd7c)", + hash_y: "Fr(0x1a6994a999a0abf83afc6ec5fe0ee8c8336a171653218cbfdf269689d5cfd3aa)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1], + hash_x: "Fr(0x61f8e2cb8e945631677b450d5e5669bc6b5f2ec69b321ac550dbe74525d7ac9a)", + hash_y: "Fr(0x4e11951ab9c9400ee38a18bd98cdb9453f1f67141ee9d9bf0c1c157d4fb34f9a)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 0], + hash_x: "Fr(0x27fa1e296c37dde8448483ce5485c2604d1d830e53812246299773a02ecd519c)", + hash_y: "Fr(0x08e499113675202cb42b4b681a31430814edebd72c5bb3bc3bfedf91fb0605df)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 1], + hash_x: "Fr(0x52112dd7a4293d049bb011683244a0f957e6ba95e1d1cf2fb6654d449a6d3fbc)", + hash_y: "Fr(0x2ae14ecd81bb5b4489d2d64b5d2eb92a684087b28dd9a4950ecdb78c014e178c)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 0, 0], + hash_x: "Fr(0x27fa1e296c37dde8448483ce5485c2604d1d830e53812246299773a02ecd519c)", + hash_y: "Fr(0x08e499113675202cb42b4b681a31430814edebd72c5bb3bc3bfedf91fb0605df)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 0, 1], + hash_x: "Fr(0x5b4032d49431e7bfa085e2bb49bfc060909272a66287b063784f1d11b28a60e9)", + hash_y: "Fr(0x4627da49652efea2637595426add6ad682a0c8821d423f04c26ef5788d35f7e3)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 1, 0], + hash_x: "Fr(0x52112dd7a4293d049bb011683244a0f957e6ba95e1d1cf2fb6654d449a6d3fbc)", + hash_y: "Fr(0x2ae14ecd81bb5b4489d2d64b5d2eb92a684087b28dd9a4950ecdb78c014e178c)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 1, 1], + hash_x: "Fr(0x099e74a82c9c1858ac40db1a85959b1362d82fdd6efb99a443829f83003b0190)", + hash_y: "Fr(0x0f76f53d026574ad77ab4c6cd2428b9d94d158a9fc0469aae47c7535ff107881)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + hash_x: "Fr(0x240da48e40637664bcf3582708491d19e28a50787ea40b0a336d61735782d10a)", + hash_y: "Fr(0x6e630ddf6e43ad5568c925a4935e8e099230af4b2e19fab7d92b7e953b4986c3)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + hash_x: "Fr(0x06a477addbbfdf2934e34bdf6e071cd1276beaed801cd1b660ddcceb161ca8c7)", + hash_y: "Fr(0x355d39425378e57f393b30423cbde3ff69198ebac2ccbbafb92e25613352b0e8)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![ + 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, + 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, + 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, + 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, + ], + hash_x: "Fr(0x094a624c5aac3569ad85428bb939d391bb5766ff87c389eb4d84d42aeaabb906)", + hash_y: "Fr(0x2cf51a8699edc64b73aa962464d4eadf038821900f9409350dc3ea2ccf12e054)", + }, + ]; +} From 6240c02208160305eb9646effa03a6fea3c35133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Nicolas?= Date: Sun, 19 Aug 2018 11:46:09 +0200 Subject: [PATCH 195/330] Long and random PH test vectors --- .../src/test_vectors/pedersen_hash_vectors.rs | 660 ++++++++++++++++-- 1 file changed, 592 insertions(+), 68 deletions(-) diff --git a/zcash_primitives/src/test_vectors/pedersen_hash_vectors.rs b/zcash_primitives/src/test_vectors/pedersen_hash_vectors.rs index a3f26d1..71257d2 100644 --- a/zcash_primitives/src/test_vectors/pedersen_hash_vectors.rs +++ b/zcash_primitives/src/test_vectors/pedersen_hash_vectors.rs @@ -24,50 +24,421 @@ pub fn get_vectors<'a>() -> Vec> { }, TestVector { personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 0, 0], - hash_x: "Fr(0x2fc3bc454c337f71d4f04f86304262fcbfc9ecd808716b92fc42cbe6827f7f1a)", - hash_y: "Fr(0x46d0d25bf1a654eedc6a9b1e5af398925113959feac31b7a2c036ff9b9ec0638)", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 0, 1], - hash_x: "Fr(0x21746acd049f2c54579d5bb9c106083b4bb48c8910a06565d1e39e46939ca497)", - hash_y: "Fr(0x2cb69ae2615cd02c6ad2d6e06c1a0c15d49d71051d2d702155fca07bbf2d574c)", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 1, 0], + input_bits: vec![1, 1, 1, 1, 1, 1, 1, 0, 0], hash_x: "Fr(0x4f8ce0e0a9e674b3ab9606a7d7aefba386e81583d81918127814cde41d209d97)", hash_y: "Fr(0x312b5ab93b14c9b9af334fe1fe3c50fffb53fbd074fa40ca600febde7c97e346)", }, TestVector { personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 1, 1], - hash_x: "Fr(0x3e09bdeea175dd4acd2e106caf4a5194200af53ee3a5a71338c083093d83eba5)", - hash_y: "Fr(0x579f6f15508af07d0f1beb117beaffe99e115a7ee859d81ddaa91d1096a103df)", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - hash_x: "Fr(0x208d2e11ee496eb3b37257d1b4a77907e4b21d6c46d5487fb52d5a5239587ea0)", - hash_y: "Fr(0x1eeeb47b858257b9b69d009779e38c63332e20220eb474ef9af868274132181f)", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - hash_x: "Fr(0x683ffae48988d517301ba81fb2c294c16a35ed1bba6411bd17312294843f37e0)", - hash_y: "Fr(0x40f7897b86747a5a857c8bd434ce3c1079efac22ed650d7345e5da31addacaff)", + input_bits: vec![ + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, + 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, + 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, + ], + hash_x: "Fr(0x5ce85ce655a750ceb89fcfbb0ef974b322cd0344a230f9550f06ea55c395e340)", + hash_y: "Fr(0x6e14f97c466476f1b5b6f9e826c8137ef13bae064cb41fc484605aec62ec2cfc)", }, TestVector { personalization: Personalization::NoteCommitment, input_bits: vec![ - 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, - 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, - 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, - 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, + 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, + 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, ], - hash_x: "Fr(0x676f78fa89da7c64502f790a99dfe177756867006809a6f174dcb427b345cd7c)", - hash_y: "Fr(0x1a6994a999a0abf83afc6ec5fe0ee8c8336a171653218cbfdf269689d5cfd3aa)", + hash_x: "Fr(0x6568d917fcc1b7febfb1336ea4021dd337ec7084c258091a02bd4199a815912b)", + hash_y: "Fr(0x48258fccd2757b055c292a523223a27e7fcc5a2ff692dd9edb0a4b5376940323)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![ + 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, + 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, + ], + hash_x: "Fr(0x3e24e4059b86d329a6f1e23e85b8a32e147d859cb21ae8b0649243ff658126f3)", + hash_y: "Fr(0x2b206c45c931876dc9d7611387b179dc6bba896be80cd3b5643fb235c32e3111)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, + 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, + 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, + 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, + 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, + 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, + 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, + 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, + 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, + 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, + 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, + 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, + 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, + 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, + 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, + 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, + 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, + 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, + 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, + ], + hash_x: "Fr(0x280a1b1ec18d1128fac0d436264fb09c04d1aa77d6eaf7d269ed49df8b773ff5)", + hash_y: "Fr(0x54b896d6ce31684bb35fad5f9ba0de176ee7ef0749bacc2c7a2d61ba7caca439)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, + 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, + 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, + 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, + 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, + 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, + 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, + 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, + 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, + 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, + 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, + 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, + 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, + 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, + 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, + 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, + 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, + 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, + 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, + 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, + 0, 1, 0, 1, 1, 1, 0, + ], + hash_x: "Fr(0x303815867ef8b94e102fe4e7d4fa0cce6478c6c85101921a729ad75565fc2b13)", + hash_y: "Fr(0x19cc4fe8cb4ca16904e88b1dbf8cbc6267b77be76e5047faa1a9d606639133af)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![ + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, + 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, + 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, + 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, + 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, + 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, + 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, + 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, + 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, + 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, + 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, + 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, + 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, + 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, + 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, + 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, + 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, + 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, + 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, + 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, + ], + hash_x: "Fr(0x062312368a4f766464598f35eae99e214d829c1da358ef7c039261d80ccb02b1)", + hash_y: "Fr(0x0b37e1f3f27fe80b441ab9acc571fd80b13cc55cd313303ea1867ebdd50f4cbc)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![ + 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, + 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, + 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, + 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, + 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, + 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, + 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, + 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, + 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, + 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, + 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, + 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, + 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, + 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, + 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, + 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, + 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, + 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, + 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, + 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, + 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, + 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, + 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, + 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, + 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, + ], + hash_x: "Fr(0x29d229be31c56829ade7ba291737b261492ea9faea749ed12983056da472b8e8)", + hash_y: "Fr(0x3ec896a7882f1c4b025e4ed4fdecc5acad5444a2ab9f9f819bf3182eb2a64cab)", + }, + TestVector { + personalization: Personalization::MerkleTree(0), + input_bits: vec![0, 0, 0, 0, 0, 0], + hash_x: "Fr(0x62454a957289b3930d10f3def0d512cfe0ef3de06421321221af3558de9d481d)", + hash_y: "Fr(0x0279f0aebfb66e53ff69fba16b6608dbf4319b944432f45c6e69a3dbd1f7b330)", + }, + TestVector { + personalization: Personalization::MerkleTree(0), + input_bits: vec![0, 0, 0, 0, 0, 0, 0], + hash_x: "Fr(0x283c7880f35179e201161402d9c4556b255917dbbf0142ae60519787d36d4dea)", + hash_y: "Fr(0x648224408b4b83297cd0feb4cdc4eeb224237734931145432793bcd414228dc4)", + }, + TestVector { + personalization: Personalization::MerkleTree(0), + input_bits: vec![0, 0, 0, 0, 0, 0, 1], + hash_x: "Fr(0x1f1086b287636a20063c9614db2de66bb7d49242e88060956a5e5845057f6f5d)", + hash_y: "Fr(0x6b1b395421dde74d53341caa9e01f39d7a3138efb9b57fc0381f98f4868df622)", + }, + TestVector { + personalization: Personalization::MerkleTree(0), + input_bits: vec![0, 0, 0, 0, 0, 0, 1, 0, 0], + hash_x: "Fr(0x1f1086b287636a20063c9614db2de66bb7d49242e88060956a5e5845057f6f5d)", + hash_y: "Fr(0x6b1b395421dde74d53341caa9e01f39d7a3138efb9b57fc0381f98f4868df622)", + }, + TestVector { + personalization: Personalization::MerkleTree(0), + input_bits: vec![ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, + 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, + 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, + 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, + 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, + 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, + ], + hash_x: "Fr(0x6e7f0c07ff2090b5ce4663efe13fbfd796b359758ef1e05b4db851d6f71ec5aa)", + hash_y: "Fr(0x46bc33c3d186d2359d823b181cf53b38eeb92c4082ba089bbc5c8a1b98752b94)", + }, + TestVector { + personalization: Personalization::MerkleTree(0), + input_bits: vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, + 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, + 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, + ], + hash_x: "Fr(0x67a2d1c5b4a3431240aad380b20327f3fa8b083a04a57d5f2a31bb298f22ccfb)", + hash_y: "Fr(0x2fa884df36b11b05f272b696388fe9e0ebabe90e5a0620409b178ab1360063dd)", + }, + TestVector { + personalization: Personalization::MerkleTree(0), + input_bits: vec![ + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, + 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, + 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, + 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, + ], + hash_x: "Fr(0x3b5d11aed8cf8164802c33e51f1314e1533140f85762253ecf6f9b1523543cac)", + hash_y: "Fr(0x6aa1e56a5f8e2ecafa1d1279ed074c672758572b88e44ca577574ffa4e058412)", + }, + TestVector { + personalization: Personalization::MerkleTree(0), + input_bits: vec![ + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, + 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, + 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, + 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, + 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, + 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, + 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, + 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, + 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, + 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, + 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, + 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, + 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, + 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 0, 1, + ], + hash_x: "Fr(0x412e6566869ad80f541ef8630bd8cb2a8202ccc4d2af91faf28d03cb3cc42170)", + hash_y: "Fr(0x3131b52e438fa966a2a12eacfc87e0eba6a12672062f13d66b70f128831dc620)", + }, + TestVector { + personalization: Personalization::MerkleTree(0), + input_bits: vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, + 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, + 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, + 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, + 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, + 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, + 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, + 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, + 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, + 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, + 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, + 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, + 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, + 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, + 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, + 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, + 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, + 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, + 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, + ], + hash_x: "Fr(0x428293380576357c01c0f5d660a04820a5f684414efe47a63200807da8c36563)", + hash_y: "Fr(0x1d162de79b89d3816755cd3d70c9951e3d8abb93f53d5ba10d365248c07c42ab)", + }, + TestVector { + personalization: Personalization::MerkleTree(0), + input_bits: vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, + 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, + 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, + 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, + 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, + 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, + 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, + 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, + 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, + 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, + 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, + 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, + 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, + 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, + 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, + 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, + 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, + 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, + 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, + 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, + 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, + 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, + 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, + 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, + ], + hash_x: "Fr(0x5752e8edbad2077a2129ee6bcf63b263742654cbd2e388b171faa7353db36558)", + hash_y: "Fr(0x45ce194558c09e4f32d173fb7e90c9733f8f7b987ea366f9e1d12e082a5491ce)", + }, + TestVector { + personalization: Personalization::MerkleTree(0), + input_bits: vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, + 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, + 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, + 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, + 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, + 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, + 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, + 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, + 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, + 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, + 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, + 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, + 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, + 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, + 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, + 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, + 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, + 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, + 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, + 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, + 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, + 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, + ], + hash_x: "Fr(0x177126f3b82b213429c2dd000f30f6d2e241ceb5bd176cceee47cfdb7820a519)", + hash_y: "Fr(0x3806eb24915fbe76b7e9a05de9a81aeb416cf83e482b7384b2dea23ce352e570)", }, TestVector { personalization: Personalization::MerkleTree(34), @@ -89,50 +460,203 @@ pub fn get_vectors<'a>() -> Vec> { }, TestVector { personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 0, 0], - hash_x: "Fr(0x27fa1e296c37dde8448483ce5485c2604d1d830e53812246299773a02ecd519c)", - hash_y: "Fr(0x08e499113675202cb42b4b681a31430814edebd72c5bb3bc3bfedf91fb0605df)", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 0, 1], - hash_x: "Fr(0x5b4032d49431e7bfa085e2bb49bfc060909272a66287b063784f1d11b28a60e9)", - hash_y: "Fr(0x4627da49652efea2637595426add6ad682a0c8821d423f04c26ef5788d35f7e3)", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 1, 0], + input_bits: vec![0, 1, 0, 0, 0, 1, 1, 0, 0], hash_x: "Fr(0x52112dd7a4293d049bb011683244a0f957e6ba95e1d1cf2fb6654d449a6d3fbc)", hash_y: "Fr(0x2ae14ecd81bb5b4489d2d64b5d2eb92a684087b28dd9a4950ecdb78c014e178c)", }, TestVector { personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 1, 1], - hash_x: "Fr(0x099e74a82c9c1858ac40db1a85959b1362d82fdd6efb99a443829f83003b0190)", - hash_y: "Fr(0x0f76f53d026574ad77ab4c6cd2428b9d94d158a9fc0469aae47c7535ff107881)", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - hash_x: "Fr(0x240da48e40637664bcf3582708491d19e28a50787ea40b0a336d61735782d10a)", - hash_y: "Fr(0x6e630ddf6e43ad5568c925a4935e8e099230af4b2e19fab7d92b7e953b4986c3)", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], - hash_x: "Fr(0x06a477addbbfdf2934e34bdf6e071cd1276beaed801cd1b660ddcceb161ca8c7)", - hash_y: "Fr(0x355d39425378e57f393b30423cbde3ff69198ebac2ccbbafb92e25613352b0e8)", + input_bits: vec![ + 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, + 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, + 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, + 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, + 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, + ], + hash_x: "Fr(0x45a4a919352ae421a5ecee9e58916fdd20421bc4073dac1eb9d4a9788517b242)", + hash_y: "Fr(0x3e87b326f98ef71c09c8d91c5c69b35589d1c63931fc7eb70a9fbf7d7ecd7743)", }, TestVector { personalization: Personalization::MerkleTree(34), input_bits: vec![ - 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, - 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, - 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, - 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, + 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, + 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, + 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, + 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, + 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, ], - hash_x: "Fr(0x094a624c5aac3569ad85428bb939d391bb5766ff87c389eb4d84d42aeaabb906)", - hash_y: "Fr(0x2cf51a8699edc64b73aa962464d4eadf038821900f9409350dc3ea2ccf12e054)", + hash_x: "Fr(0x4e6616fef2cc0121158ed0ff99fe5c74a16a530b55ed3029c17f4504be2d63bc)", + hash_y: "Fr(0x0e616bad2c6f53425cd0a58a72fb0cd6c7c10eff8de2b9e6751ca200794cc681)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![ + 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, + 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, + 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, + 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, + 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, + ], + hash_x: "Fr(0x361e51a064b99826b60eca3fc7c963c4bd0c242a60984ee73ae1d0f0a91a93ed)", + hash_y: "Fr(0x1eec42669df04008c4106da4959d7150172d7bb29038b2b4a3e129333491a615)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![ + 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, + 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, + 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, + 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, + 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, + 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, + 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, + 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, + 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, + 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, + 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, + 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, + 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, + 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, + 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, + 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, + 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, + 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, + 0, 0, 0, 1, 0, 1, + ], + hash_x: "Fr(0x4628b5c298b1bda5a72d27dfc66ed52381356ed9d06d80049d883cc6a86ba060)", + hash_y: "Fr(0x55dbbbe29a40a7e6c1d3863b1ce55521a655bea49a5ec4aa5af4fcdc6d07b572)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![ + 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, + 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, + 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, + 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, + 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, + 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, + 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, + 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, + 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, + 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, + 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, + 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, + 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, + 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, + 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, + 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, + 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, + 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, + 1, 1, 0, 0, 0, 0, 1, + ], + hash_x: "Fr(0x269951d9add5b838019b9f99332eee5923cede7a911e94dff8fbcdceaa94c040)", + hash_y: "Fr(0x62a5a3daf3a4cd436016829ba132ce983004597539eb3f5b33e0da09aa095c3f)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![ + 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, + 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, + 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, + 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, + 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, + 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, + 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, + 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, + 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, + 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, + 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, + 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, + 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, + 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, + 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, + 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, + 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, + 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, + 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, + 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, + ], + hash_x: "Fr(0x5ba09bdafc6846319e8b88baa2c1577ee40df4b54a2d58ae2ed079a7f9218e05)", + hash_y: "Fr(0x4616a8e8a4e7a74a4b30d12fd3316ede03116b0e051708487c4848d7e89593fe)", + }, + TestVector { + personalization: Personalization::MerkleTree(34), + input_bits: vec![ + 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, + 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, + 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, + 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, + 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, + 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, + 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, + 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, + 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, + 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, + 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, + 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, + 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, + 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, + 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, + 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, + 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, + 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, + 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, + 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, + 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, + 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, + 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, + 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, + ], + hash_x: "Fr(0x62f7ad8abd0c927d482f4954f65883cbdf4da7dfdefbee0fc4a74cb188827184)", + hash_y: "Fr(0x00b2056a5556b91df4ff76e31e608ddc6c5a543e4ea7708568e470ea3be900a5)", }, ]; } From 68ba93f5fd67d85c1ef7687ed5d3259725422f59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Nicolas?= Date: Sun, 19 Aug 2018 13:39:57 +0200 Subject: [PATCH 196/330] PH test vectors for edge-cases --- .../src/test_vectors/pedersen_hash_vectors.rs | 209 +++++++++++------- 1 file changed, 131 insertions(+), 78 deletions(-) diff --git a/zcash_primitives/src/test_vectors/pedersen_hash_vectors.rs b/zcash_primitives/src/test_vectors/pedersen_hash_vectors.rs index 71257d2..ba4f2a8 100644 --- a/zcash_primitives/src/test_vectors/pedersen_hash_vectors.rs +++ b/zcash_primitives/src/test_vectors/pedersen_hash_vectors.rs @@ -36,11 +36,11 @@ pub fn get_vectors<'a>() -> Vec> { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, - 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, + 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, ], - hash_x: "Fr(0x5ce85ce655a750ceb89fcfbb0ef974b322cd0344a230f9550f06ea55c395e340)", - hash_y: "Fr(0x6e14f97c466476f1b5b6f9e826c8137ef13bae064cb41fc484605aec62ec2cfc)", + hash_x: "Fr(0x599ab788360ae8c6d5bb7618aec37056d6227408d857fdc394078a3d7afdfe0f)", + hash_y: "Fr(0x4320c373da670e28d168f4ffd72b43208e8c815f40841682c57a3ee1d005a527)", }, TestVector { personalization: Personalization::NoteCommitment, @@ -50,11 +50,11 @@ pub fn get_vectors<'a>() -> Vec> { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, - 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, - 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, + 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, ], - hash_x: "Fr(0x6568d917fcc1b7febfb1336ea4021dd337ec7084c258091a02bd4199a815912b)", - hash_y: "Fr(0x48258fccd2757b055c292a523223a27e7fcc5a2ff692dd9edb0a4b5376940323)", + hash_x: "Fr(0x2da510317620f5dfdce1f31db6019f947eedcf02ff2972cff597a5c3ad21f5dd)", + hash_y: "Fr(0x198789969c0c33e6c359b9da4a51771f4d50863f36beef90436944fe568399f2)", }, TestVector { personalization: Personalization::NoteCommitment, @@ -64,11 +64,11 @@ pub fn get_vectors<'a>() -> Vec> { 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, - 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, + 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, + 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, ], - hash_x: "Fr(0x3e24e4059b86d329a6f1e23e85b8a32e147d859cb21ae8b0649243ff658126f3)", - hash_y: "Fr(0x2b206c45c931876dc9d7611387b179dc6bba896be80cd3b5643fb235c32e3111)", + hash_x: "Fr(0x601247c7e640992d193dfb51df6ed93446687a7f2bcd0e4a598e6feb1ef20c40)", + hash_y: "Fr(0x371931733b73e7b95c2cad55a6cebd15c83619f697c64283e54e5ef61442a743)", }, TestVector { personalization: Personalization::NoteCommitment, @@ -99,11 +99,10 @@ pub fn get_vectors<'a>() -> Vec> { 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, - 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, - 0, 0, 0, 1, 1, 1, + 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, ], - hash_x: "Fr(0x280a1b1ec18d1128fac0d436264fb09c04d1aa77d6eaf7d269ed49df8b773ff5)", - hash_y: "Fr(0x54b896d6ce31684bb35fad5f9ba0de176ee7ef0749bacc2c7a2d61ba7caca439)", + hash_x: "Fr(0x314192ecb1f2d8806a8108704c875a25d9fb7e444f9f373919adedebe8f2ae27)", + hash_y: "Fr(0x6b12b32f1372ad574799dee9eb591d961b704bf611f55fcc71f7e82cd3330b74)", }, TestVector { personalization: Personalization::NoteCommitment, @@ -134,11 +133,11 @@ pub fn get_vectors<'a>() -> Vec> { 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, - 0, 1, 0, 1, 1, 1, 0, + 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, + 0, ], - hash_x: "Fr(0x303815867ef8b94e102fe4e7d4fa0cce6478c6c85101921a729ad75565fc2b13)", - hash_y: "Fr(0x19cc4fe8cb4ca16904e88b1dbf8cbc6267b77be76e5047faa1a9d606639133af)", + hash_x: "Fr(0x0666c2bce7f362a2b807d212e9a577f116891a932affd7addec39fbf372c494e)", + hash_y: "Fr(0x6758bccfaf2e47c07756b96edea23aa8d10c33b38220bd1c411af612eeec18ab)", }, TestVector { personalization: Personalization::NoteCommitment, @@ -176,10 +175,10 @@ pub fn get_vectors<'a>() -> Vec> { 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, - 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, + 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, ], - hash_x: "Fr(0x062312368a4f766464598f35eae99e214d829c1da358ef7c039261d80ccb02b1)", - hash_y: "Fr(0x0b37e1f3f27fe80b441ab9acc571fd80b13cc55cd313303ea1867ebdd50f4cbc)", + hash_x: "Fr(0x130afe02b99375484efb0998f5331d2178e1d00e803049bb0769099420624f5f)", + hash_y: "Fr(0x5e2fc6970554ffe358652aa7968ac4fcf3de0c830e6ea492e01a38fafb68cd71)", }, TestVector { personalization: Personalization::NoteCommitment, @@ -217,10 +216,10 @@ pub fn get_vectors<'a>() -> Vec> { 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, - 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, + 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, ], - hash_x: "Fr(0x29d229be31c56829ade7ba291737b261492ea9faea749ed12983056da472b8e8)", - hash_y: "Fr(0x3ec896a7882f1c4b025e4ed4fdecc5acad5444a2ab9f9f819bf3182eb2a64cab)", + hash_x: "Fr(0x67914ebd539961b70f468fa23d4cb42133693a8ac57cd35a1e6369fe34fbedf7)", + hash_y: "Fr(0x44770870c0f0cfe59a10df95d6c21e6f1514a2f464b66377599438c126052d9f)", }, TestVector { personalization: Personalization::MerkleTree(0), @@ -254,11 +253,11 @@ pub fn get_vectors<'a>() -> Vec> { 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, - 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, - 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, + 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, + 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, ], - hash_x: "Fr(0x6e7f0c07ff2090b5ce4663efe13fbfd796b359758ef1e05b4db851d6f71ec5aa)", - hash_y: "Fr(0x46bc33c3d186d2359d823b181cf53b38eeb92c4082ba089bbc5c8a1b98752b94)", + hash_x: "Fr(0x20d2b1b0551efe511755d564f8da4f5bf285fd6051331fa5f129ad95b318f6cd)", + hash_y: "Fr(0x2834d96950de67ae80e85545f8333c6e14b5cf5be7325dac768f401e6edd9544)", }, TestVector { personalization: Personalization::MerkleTree(0), @@ -268,11 +267,11 @@ pub fn get_vectors<'a>() -> Vec> { 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, - 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, + 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, ], - hash_x: "Fr(0x67a2d1c5b4a3431240aad380b20327f3fa8b083a04a57d5f2a31bb298f22ccfb)", - hash_y: "Fr(0x2fa884df36b11b05f272b696388fe9e0ebabe90e5a0620409b178ab1360063dd)", + hash_x: "Fr(0x01f4850a0f40e07186fee1f0a276f52fb12cffe05c18eb2aa18170330a93c555)", + hash_y: "Fr(0x19b0807358e7c8cba9168815ec54c4cd76997c34c592607d172151c48d5377cb)", }, TestVector { personalization: Personalization::MerkleTree(0), @@ -282,11 +281,11 @@ pub fn get_vectors<'a>() -> Vec> { 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, - 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, + 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, + 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, ], - hash_x: "Fr(0x3b5d11aed8cf8164802c33e51f1314e1533140f85762253ecf6f9b1523543cac)", - hash_y: "Fr(0x6aa1e56a5f8e2ecafa1d1279ed074c672758572b88e44ca577574ffa4e058412)", + hash_x: "Fr(0x26dd81a3ffa37452c6a932d41eb4f2e0fedd531e9af8c2a7935b91dff653879d)", + hash_y: "Fr(0x2fc7aebb729ef5cabf0fb3f883bc2eb2603093850b0ec19c1a3c08b653e7f27f)", }, TestVector { personalization: Personalization::MerkleTree(0), @@ -317,11 +316,10 @@ pub fn get_vectors<'a>() -> Vec> { 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 0, 1, + 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, ], - hash_x: "Fr(0x412e6566869ad80f541ef8630bd8cb2a8202ccc4d2af91faf28d03cb3cc42170)", - hash_y: "Fr(0x3131b52e438fa966a2a12eacfc87e0eba6a12672062f13d66b70f128831dc620)", + hash_x: "Fr(0x1111740552773b00aa6a2334575aa94102cfbd084290a430c90eb56d6db65b85)", + hash_y: "Fr(0x6560c44b11683c20030626f89456f78a53ae8a89f565956a98ffc554b48fbb1a)", }, TestVector { personalization: Personalization::MerkleTree(0), @@ -352,11 +350,11 @@ pub fn get_vectors<'a>() -> Vec> { 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, - 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 0, 0, 0, + 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, + 0, ], - hash_x: "Fr(0x428293380576357c01c0f5d660a04820a5f684414efe47a63200807da8c36563)", - hash_y: "Fr(0x1d162de79b89d3816755cd3d70c9951e3d8abb93f53d5ba10d365248c07c42ab)", + hash_x: "Fr(0x429349ea9b5f8163bcda3014b3e15554df5173353fd73f315a49360c97265f68)", + hash_y: "Fr(0x188774bb6de41eba669be5d368942783f937acf2f418385fc5c78479b0a405ee)", }, TestVector { personalization: Personalization::MerkleTree(0), @@ -394,10 +392,10 @@ pub fn get_vectors<'a>() -> Vec> { 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, + 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, ], - hash_x: "Fr(0x5752e8edbad2077a2129ee6bcf63b263742654cbd2e388b171faa7353db36558)", - hash_y: "Fr(0x45ce194558c09e4f32d173fb7e90c9733f8f7b987ea366f9e1d12e082a5491ce)", + hash_x: "Fr(0x00e827f3ed136f3c91c61c97ab9b7cca0ea53c20e47abb5e226ede297bdd5f37)", + hash_y: "Fr(0x315cc00a54972df6a19f650d3fab5f2ad0fb07397bacb6944568618f2aa76bf6)", }, TestVector { personalization: Personalization::MerkleTree(0), @@ -435,10 +433,10 @@ pub fn get_vectors<'a>() -> Vec> { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, - 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, + 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, ], - hash_x: "Fr(0x177126f3b82b213429c2dd000f30f6d2e241ceb5bd176cceee47cfdb7820a519)", - hash_y: "Fr(0x3806eb24915fbe76b7e9a05de9a81aeb416cf83e482b7384b2dea23ce352e570)", + hash_x: "Fr(0x3ee50557c4aa9158c4bb9d5961208e6c62f55c73ad7c7695a0eba0bcb6d83d05)", + hash_y: "Fr(0x1b1a2be6e47688828aeadf2d37db298eac0c2736c2722b227871fdeeee29de33)", }, TestVector { personalization: Personalization::MerkleTree(34), @@ -472,11 +470,11 @@ pub fn get_vectors<'a>() -> Vec> { 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, - 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, - 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, + 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, ], - hash_x: "Fr(0x45a4a919352ae421a5ecee9e58916fdd20421bc4073dac1eb9d4a9788517b242)", - hash_y: "Fr(0x3e87b326f98ef71c09c8d91c5c69b35589d1c63931fc7eb70a9fbf7d7ecd7743)", + hash_x: "Fr(0x544a0b44c35dca64ee806d1af70b7c44134e5d86efed413947657ffd71adf9b2)", + hash_y: "Fr(0x5ddc5dbf12abbbc5561defd3782a32f450b3c398f52ff4629677e59e86e3ab31)", }, TestVector { personalization: Personalization::MerkleTree(34), @@ -486,11 +484,11 @@ pub fn get_vectors<'a>() -> Vec> { 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, - 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, - 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, + 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, + 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, ], - hash_x: "Fr(0x4e6616fef2cc0121158ed0ff99fe5c74a16a530b55ed3029c17f4504be2d63bc)", - hash_y: "Fr(0x0e616bad2c6f53425cd0a58a72fb0cd6c7c10eff8de2b9e6751ca200794cc681)", + hash_x: "Fr(0x6cb6490ccb0ca9ccd657146f58a7b800bc4fb2556ee37861227ee8fda724acfb)", + hash_y: "Fr(0x05c6fe100926f5cc441e54e72f024b6b12c907f2ec5680335057896411984c9f)", }, TestVector { personalization: Personalization::MerkleTree(34), @@ -500,11 +498,11 @@ pub fn get_vectors<'a>() -> Vec> { 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, - 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, - 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, + 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, ], - hash_x: "Fr(0x361e51a064b99826b60eca3fc7c963c4bd0c242a60984ee73ae1d0f0a91a93ed)", - hash_y: "Fr(0x1eec42669df04008c4106da4959d7150172d7bb29038b2b4a3e129333491a615)", + hash_x: "Fr(0x40901e2175cb7f06a00c676d54d90e59fd448f11cbbc5eb517f9fea74b795ce2)", + hash_y: "Fr(0x42d512891f91087310c9bc630c8d0ecc014596f884fd6df55dada8195ed726de)", }, TestVector { personalization: Personalization::MerkleTree(34), @@ -535,11 +533,10 @@ pub fn get_vectors<'a>() -> Vec> { 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, - 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, - 0, 0, 0, 1, 0, 1, + 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, ], - hash_x: "Fr(0x4628b5c298b1bda5a72d27dfc66ed52381356ed9d06d80049d883cc6a86ba060)", - hash_y: "Fr(0x55dbbbe29a40a7e6c1d3863b1ce55521a655bea49a5ec4aa5af4fcdc6d07b572)", + hash_x: "Fr(0x66a433542419f1a086ed0663b0e8df2ece9a04065f147896976baba1a916b6dc)", + hash_y: "Fr(0x203bd3672522e1d3c86fa6b9f3b58f20199a4216adfd40982add13a856f6f3de)", }, TestVector { personalization: Personalization::MerkleTree(34), @@ -570,11 +567,11 @@ pub fn get_vectors<'a>() -> Vec> { 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, - 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, - 1, 1, 0, 0, 0, 0, 1, + 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, + 1, ], - hash_x: "Fr(0x269951d9add5b838019b9f99332eee5923cede7a911e94dff8fbcdceaa94c040)", - hash_y: "Fr(0x62a5a3daf3a4cd436016829ba132ce983004597539eb3f5b33e0da09aa095c3f)", + hash_x: "Fr(0x119db3b38086c1a3c6c6f53c529ee62d9311d69c2d8aeeafa6e172e650d3afda)", + hash_y: "Fr(0x72287540be7d2b0f58f5c73eaa53c55bea6b79dd79873b4e47cc11787bb9a15d)", }, TestVector { personalization: Personalization::MerkleTree(34), @@ -612,10 +609,10 @@ pub fn get_vectors<'a>() -> Vec> { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, - 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, ], - hash_x: "Fr(0x5ba09bdafc6846319e8b88baa2c1577ee40df4b54a2d58ae2ed079a7f9218e05)", - hash_y: "Fr(0x4616a8e8a4e7a74a4b30d12fd3316ede03116b0e051708487c4848d7e89593fe)", + hash_x: "Fr(0x446efdcf89b70ba2b03427a0893008181d0fc4e76b84b1a500d7ee523c8e3666)", + hash_y: "Fr(0x125ee0048efb0372b92c3c15d51a7c5c77a712054cc4fdd0774563da46ec7289)", }, TestVector { personalization: Personalization::MerkleTree(34), @@ -653,10 +650,66 @@ pub fn get_vectors<'a>() -> Vec> { 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, + 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, ], - hash_x: "Fr(0x62f7ad8abd0c927d482f4954f65883cbdf4da7dfdefbee0fc4a74cb188827184)", - hash_y: "Fr(0x00b2056a5556b91df4ff76e31e608ddc6c5a543e4ea7708568e470ea3be900a5)", + hash_x: "Fr(0x72723bf0573bcb4b72d4184cfeb707d9556b7f705f56a4652707a36f2edf10f7)", + hash_y: "Fr(0x3a7f0999a6a1393bd49fc82302e7352e01176fbebb0192bf5e6ef39eb8c585ad)", + }, + TestVector { + personalization: Personalization::MerkleTree(27), + input_bits: vec![ + 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, + 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, + 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, + 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, + 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, + 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, + 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, + ], + hash_x: "Fr(0x414f6ba05f6b92da1f9051950769e1083d05615def32b016ae424309828a11f4)", + hash_y: "Fr(0x471d2109656afcb96d0609b371b132b97efcf72c6051064dd19fdc004799bfa9)", + }, + TestVector { + personalization: Personalization::MerkleTree(36), + input_bits: vec![ + 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, + 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, + 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, + 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, + ], + hash_x: "Fr(0x62d6fe1e373225a5695f3115aed8265c59e2d6275ceef6bbc53fde3fc6594024)", + hash_y: "Fr(0x407275be7d5a4c48204c8d83f5b211d09a2f285d4f0f87a928d4de9a6338e1d1)", + }, + TestVector { + personalization: Personalization::MerkleTree(0), + input_bits: vec![ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + hash_x: "Fr(0x1116a934f26b57a2c9daa6f25ac9b1a8f9dacddba30f65433ac021bf39a6bfdd)", + hash_y: "Fr(0x407275be7d5a4c48204c8d83f5b211d09a2f285d4f0f87a928d4de9a6338e1d1)", + }, + TestVector { + personalization: Personalization::NoteCommitment, + input_bits: vec![ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + ], + hash_x: "Fr(0x329e3bb2ca31ea6e13a986730237f6fd16b842a510cbabe851bdbcf57d75ee0d)", + hash_y: "Fr(0x471d2109656afcb96d0609b371b132b97efcf72c6051064dd19fdc004799bfa9)", }, ]; } From bb0a769162033b4a5f01bd1dce75abd657df1a37 Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Thu, 9 Aug 2018 09:36:36 +0300 Subject: [PATCH 197/330] ecc: tests for assert_not_small_order --- zcash_proofs/src/circuit/ecc.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/zcash_proofs/src/circuit/ecc.rs b/zcash_proofs/src/circuit/ecc.rs index fa4913a..6a6855e 100644 --- a/zcash_proofs/src/circuit/ecc.rs +++ b/zcash_proofs/src/circuit/ecc.rs @@ -1096,4 +1096,30 @@ mod test { assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate lambda")); } } + + #[test] + fn test_assert_not_small_order() { + let params = &JubjubBls12::new(); + + let check_small_order_from_strs = |x, y| { + let mut cs = TestConstraintSystem::::new(); + + //let (x,y) = (Fr::from_str("14080418777298869350588389379361252092475090129841789940098060767181937064268").unwrap(), Fr::from_str("4408371274642418797323679050836535851651768103477128764103246588657558662748").unwrap()); + let (x, y) = (Fr::from_str(x).unwrap(), Fr::from_str(y).unwrap()); + let p = edwards::Point::::get_for_y(y, false, params).unwrap(); + assert_eq!(x, p.to_xy().0); + + let p = EdwardsPoint::witness(&mut cs, Some(p), params).unwrap(); + assert!(cs.is_satisfied()); + assert!(p.assert_not_small_order(&mut cs, params).is_err()); + }; + + // zero has low order + check_small_order_from_strs("0", "1"); + // generator for the small order subgroup + check_small_order_from_strs( + "948411088638444611740115537621561973758360269817276634325562542866802143934", + "19260245455242183936012133194672327304390353749328020389743628630787497879844", + ); + } } From ace929c5ba9470886d00ada7f4aa7f944d54ac0f Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Thu, 9 Aug 2018 15:32:17 +0300 Subject: [PATCH 198/330] ecc: test_assert_not_small_order also tests for the generators --- zcash_proofs/src/circuit/ecc.rs | 40 ++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/zcash_proofs/src/circuit/ecc.rs b/zcash_proofs/src/circuit/ecc.rs index 6a6855e..9e33c47 100644 --- a/zcash_proofs/src/circuit/ecc.rs +++ b/zcash_proofs/src/circuit/ecc.rs @@ -1101,25 +1101,49 @@ mod test { fn test_assert_not_small_order() { let params = &JubjubBls12::new(); - let check_small_order_from_strs = |x, y| { + let check_small_order_from_p = |p: edwards::Point, is_small_order| { let mut cs = TestConstraintSystem::::new(); + let p = EdwardsPoint::witness(&mut cs, Some(p), params).unwrap(); + assert!(cs.is_satisfied()); + assert!(p.assert_not_small_order(&mut cs, params).is_err() == is_small_order); + }; + + let check_small_order_from_strs = |x, y| { //let (x,y) = (Fr::from_str("14080418777298869350588389379361252092475090129841789940098060767181937064268").unwrap(), Fr::from_str("4408371274642418797323679050836535851651768103477128764103246588657558662748").unwrap()); let (x, y) = (Fr::from_str(x).unwrap(), Fr::from_str(y).unwrap()); let p = edwards::Point::::get_for_y(y, false, params).unwrap(); assert_eq!(x, p.to_xy().0); - let p = EdwardsPoint::witness(&mut cs, Some(p), params).unwrap(); - assert!(cs.is_satisfied()); - assert!(p.assert_not_small_order(&mut cs, params).is_err()); + check_small_order_from_p(p, true); }; // zero has low order check_small_order_from_strs("0", "1"); - // generator for the small order subgroup - check_small_order_from_strs( - "948411088638444611740115537621561973758360269817276634325562542866802143934", - "19260245455242183936012133194672327304390353749328020389743628630787497879844", + // generator for jubjub + let (x, y) = ( + Fr::from_str( + "11076627216317271660298050606127911965867021807910416450833192264015104452986", + ) + .unwrap(), + Fr::from_str( + "44412834903739585386157632289020980010620626017712148233229312325549216099227", + ) + .unwrap(), ); + let g = edwards::Point::::get_for_y(y, false, params).unwrap(); + assert_eq!(x, g.to_xy().0); + // generator for the jubjub group + check_small_order_from_p(g.clone(), false); + // generator for the small order subgroup + let g2 = g.mul( + Fs::from_str( + "6554484396890773809930967563523245729705921265872317281365359162392183254199", + ) + .unwrap() + .into_repr(), + params, + ); + check_small_order_from_p(g2, true); } } From e0c5ef22bc2ea50c431a25a4a84633040166d5f9 Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Sat, 11 Aug 2018 13:06:20 +0300 Subject: [PATCH 199/330] ecc: makes assert_not_small_order tests deeper --- zcash_proofs/src/circuit/ecc.rs | 53 ++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/zcash_proofs/src/circuit/ecc.rs b/zcash_proofs/src/circuit/ecc.rs index 9e33c47..822c355 100644 --- a/zcash_proofs/src/circuit/ecc.rs +++ b/zcash_proofs/src/circuit/ecc.rs @@ -1120,6 +1120,16 @@ mod test { // zero has low order check_small_order_from_strs("0", "1"); + + // prime subgroup order + let prime_subgroup_order = Fs::from_str( + "6554484396890773809930967563523245729705921265872317281365359162392183254199", + ) + .unwrap(); + let largest_small_subgroup_order = Fs::from_str("8").unwrap(); + + let (zero_x, zero_y) = (Fr::from_str("0").unwrap(), Fr::from_str("1").unwrap()); + // generator for jubjub let (x, y) = ( Fr::from_str( @@ -1133,17 +1143,40 @@ mod test { ); let g = edwards::Point::::get_for_y(y, false, params).unwrap(); assert_eq!(x, g.to_xy().0); - // generator for the jubjub group check_small_order_from_p(g.clone(), false); + + // generator for the prime subgroup + let g_prime = g.mul(largest_small_subgroup_order, params); + check_small_order_from_p(g_prime.clone(), false); + let mut prime_subgroup_order_minus_1 = prime_subgroup_order.clone(); + prime_subgroup_order_minus_1.sub_assign(&Fs::from_str("1").unwrap()); + + let should_not_be_zero = g_prime.mul(prime_subgroup_order_minus_1, params); + assert_ne!(zero_x, should_not_be_zero.to_xy().0); + assert_ne!(zero_y, should_not_be_zero.to_xy().1); + let should_be_zero = should_not_be_zero.add(&g_prime, params); + assert_eq!(zero_x, should_be_zero.to_xy().0); + assert_eq!(zero_y, should_be_zero.to_xy().1); + // generator for the small order subgroup - let g2 = g.mul( - Fs::from_str( - "6554484396890773809930967563523245729705921265872317281365359162392183254199", - ) - .unwrap() - .into_repr(), - params, - ); - check_small_order_from_p(g2, true); + let g_small = g.mul(prime_subgroup_order_minus_1, params); + let g_small = g_small.add(&g, params); + check_small_order_from_p(g_small.clone(), true); + + // g_small does have order 8 + let mut largest_small_subgroup_order_minus_1 = largest_small_subgroup_order.clone(); + largest_small_subgroup_order_minus_1.sub_assign(&Fs::from_str("1").unwrap()); + + let should_not_be_zero = g_small.mul(largest_small_subgroup_order_minus_1, params); + assert_ne!(zero_x, should_not_be_zero.to_xy().0); + assert_ne!(zero_y, should_not_be_zero.to_xy().1); + + let should_be_zero = should_not_be_zero.add(&g_small, params); + assert_eq!(zero_x, should_be_zero.to_xy().0); + assert_eq!(zero_y, should_be_zero.to_xy().1); + + // take all the points from the script + // assert should be different than multiplying by cofactor, which is the solution + // is user input verified? https://github.com/zcash/librustzcash/blob/f5d2afb4eabac29b1b1cc860d66e45a5b48b4f88/src/rustzcash.rs#L299 } } From f3533e291f7b3f967ebeeab54332c12518d7b77b Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Mon, 6 Aug 2018 10:50:44 +0300 Subject: [PATCH 200/330] boolean: adds tests for alloc_conditionally --- bellman/src/gadgets/boolean.rs | 78 ++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/bellman/src/gadgets/boolean.rs b/bellman/src/gadgets/boolean.rs index b26bb19..57718b1 100644 --- a/bellman/src/gadgets/boolean.rs +++ b/bellman/src/gadgets/boolean.rs @@ -1740,4 +1740,82 @@ mod test { } } } + + #[test] + fn test_alloc_conditionally() { + { + let mut cs = TestConstraintSystem::::new(); + let b = AllocatedBit::alloc(&mut cs, Some(false)).unwrap(); + + let value = None; + // if value is none, fail with SynthesisError + let is_err = AllocatedBit::alloc_conditionally( + cs.namespace(|| "alloc_conditionally"), + value, + &b, + ) + .is_err(); + assert!(is_err); + } + + { + // since value is true, b must be false, so it should succeed + let mut cs = TestConstraintSystem::::new(); + + let value = Some(true); + let b = AllocatedBit::alloc(&mut cs, Some(false)).unwrap(); + let allocated_value = AllocatedBit::alloc_conditionally( + cs.namespace(|| "alloc_conditionally"), + value, + &b, + ) + .unwrap(); + + assert_eq!(allocated_value.get_value().unwrap(), true); + assert!(cs.is_satisfied()); + } + + { + // since value is true, b must be false, so it should fail + let mut cs = TestConstraintSystem::::new(); + + let value = Some(true); + let b = AllocatedBit::alloc(&mut cs, Some(true)).unwrap(); + let allocated_value = AllocatedBit::alloc_conditionally( + cs.namespace(|| "alloc_conditionally"), + value, + &b, + ) + .unwrap(); + + assert!(!cs.is_satisfied()); + } + + { + // since value is false, we don't care about the value of the bit + + let value = Some(false); + //check with false bit + let mut cs = TestConstraintSystem::::new(); + let b1 = AllocatedBit::alloc(&mut cs, Some(false)).unwrap(); + let allocated_value = AllocatedBit::alloc_conditionally( + cs.namespace(|| "alloc_conditionally"), + value, + &b1, + ) + .unwrap(); + + //check with true bit + let mut cs = TestConstraintSystem::::new(); + let b2 = AllocatedBit::alloc(&mut cs, Some(true)).unwrap(); + let allocated_value = AllocatedBit::alloc_conditionally( + cs.namespace(|| "alloc_conditionally"), + value, + &b2, + ) + .unwrap(); + + assert!(cs.is_satisfied()); + } + } } From d56758d42680e9c8ddb5c02832217d522bf4c43a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Nicolas?= Date: Tue, 21 Aug 2018 19:52:43 +0200 Subject: [PATCH 201/330] Calculate number of constraints and more comprehensive test --- zcash_proofs/src/circuit/pedersen_hash.rs | 78 ++++++++++++++++------- 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index acaf7c9..3e7ec31 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -114,6 +114,31 @@ mod test { use rand_xorshift::XorShiftRng; use zcash_primitives::pedersen_hash; + /// Predict the number of constraints of a Pedersen hash + fn ph_num_constraints(input_bits: usize) -> usize { + // Account for the 6 personalization bits. + let personalized_bits = 6 + input_bits; + // Constant booleans in the personalization and padding don't need lookup "precomp" constraints. + let precomputed_booleans = 2 + (personalized_bits % 3 == 1) as usize; + + // Count chunks and segments with ceiling division + let chunks = (personalized_bits + 3 - 1) / 3; + let segments = (chunks + 63 - 1) / 63; + let all_but_last_segments = segments - 1; + let last_chunks = chunks - all_but_last_segments * 63; + + // Constraints per operation + let lookup_chunk = 2; + let add_chunks = 3; // Montgomery addition + let convert_segment = 2; // Conversion to Edwards + let add_segments = 6; // Edwards addition + + return (chunks) * lookup_chunk - precomputed_booleans + + segments * convert_segment + + all_but_last_segments * ((63 - 1) * add_chunks + add_segments) + + (last_chunks - 1) * add_chunks; + } + #[test] fn test_pedersen_hash_constraints() { let mut rng = XorShiftRng::from_seed([ @@ -121,32 +146,41 @@ mod test { 0xbc, 0xe5, ]); let params = &JubjubBls12::new(); - let mut cs = TestConstraintSystem::::new(); - let input: Vec = (0..(Fr::NUM_BITS * 2)) - .map(|_| rng.next_u32() % 2 != 0) - .collect(); + for &n_bits in [0, 3 * 63 - 6, 3 * 63 - 6 + 1, 3 * 63 - 6 + 2, 255, 510].iter() { + let mut cs = TestConstraintSystem::::new(); - let input_bools: Vec = input - .iter() - .enumerate() - .map(|(i, b)| { - Boolean::from( - AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap(), - ) - }) - .collect(); + let input: Vec = (0..n_bits).map(|_| rng.next_u32() % 2 != 0).collect(); - pedersen_hash( - cs.namespace(|| "pedersen hash"), - Personalization::NoteCommitment, - &input_bools, - params, - ) - .unwrap(); + let input_bools: Vec = input + .iter() + .enumerate() + .map(|(i, b)| { + Boolean::from( + AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)) + .unwrap(), + ) + }) + .collect(); - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 1377); + pedersen_hash( + cs.namespace(|| "pedersen hash"), + Personalization::NoteCommitment, + &input_bools, + params, + ) + .unwrap(); + + assert!(cs.is_satisfied()); + + let bitness_constraints = n_bits; + let ph_constraints = ph_num_constraints(n_bits); + assert_eq!(cs.num_constraints(), bitness_constraints + ph_constraints); + // The main use case + if n_bits == 510 { + assert_eq!(cs.num_constraints(), 510 + 867) + }; + } } #[test] From 3efb7f9146efcc3dda032989ce1ba7599365915b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Nicolas?= Date: Wed, 22 Aug 2018 12:45:44 +0200 Subject: [PATCH 202/330] Test PH circuit for the size used in the Merkle tree --- zcash_proofs/src/circuit/pedersen_hash.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index 3e7ec31..5356331 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -147,7 +147,19 @@ mod test { ]); let params = &JubjubBls12::new(); - for &n_bits in [0, 3 * 63 - 6, 3 * 63 - 6 + 1, 3 * 63 - 6 + 2, 255, 510].iter() { + let leaves_len = 2 * 255; + let note_len = 64 + 256 + 256; + + for &n_bits in [ + 0, + 3 * 63 - 6, + 3 * 63 - 6 + 1, + 3 * 63 - 6 + 2, + leaves_len, + note_len, + ] + .iter() + { let mut cs = TestConstraintSystem::::new(); let input: Vec = (0..n_bits).map(|_| rng.next_u32() % 2 != 0).collect(); @@ -176,9 +188,12 @@ mod test { let bitness_constraints = n_bits; let ph_constraints = ph_num_constraints(n_bits); assert_eq!(cs.num_constraints(), bitness_constraints + ph_constraints); - // The main use case - if n_bits == 510 { - assert_eq!(cs.num_constraints(), 510 + 867) + // The actual usages + if n_bits == leaves_len { + assert_eq!(cs.num_constraints(), leaves_len + 867) + }; + if n_bits == note_len { + assert_eq!(cs.num_constraints(), note_len + 982) }; } } From 15b4c37ab01530f7e13a4987baf46e02f49d0015 Mon Sep 17 00:00:00 2001 From: Kobi Gurkan Date: Wed, 1 Aug 2018 09:26:30 +0300 Subject: [PATCH 203/330] adds test for linear relation between pedersen hash generators --- zcash_primitives/src/jubjub/mod.rs | 170 +++++++++++++++++++---------- 1 file changed, 112 insertions(+), 58 deletions(-) diff --git a/zcash_primitives/src/jubjub/mod.rs b/zcash_primitives/src/jubjub/mod.rs index 40938f3..65e04a0 100644 --- a/zcash_primitives/src/jubjub/mod.rs +++ b/zcash_primitives/src/jubjub/mod.rs @@ -216,28 +216,6 @@ impl JubjubBls12 { fixed_base_circuit_generators: vec![], }; - fn find_group_hash( - m: &[u8], - personalization: &[u8; 8], - params: &E::Params, - ) -> edwards::Point { - let mut tag = m.to_vec(); - let i = tag.len(); - tag.push(0u8); - - loop { - let gh = group_hash(&tag, personalization, params); - - // We don't want to overflow and start reusing generators - assert!(tag[i] != u8::max_value()); - tag[i] += 1; - - if let Some(gh) = gh { - break gh; - } - } - } - // Create the bases for the Pedersen hashes { let mut pedersen_hash_generators = vec![]; @@ -250,26 +228,17 @@ impl JubjubBls12 { .write_u32::(m) .unwrap(); - pedersen_hash_generators.push(find_group_hash( + pedersen_hash_generators.push(JubjubBls12::find_group_hash( &segment_number, constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, &tmp_params, )); } - // Check for duplicates, far worse than spec inconsistencies! - for (i, p1) in pedersen_hash_generators.iter().enumerate() { - if p1 == &edwards::Point::zero() { - panic!("Neutral element!"); - } - - for p2 in pedersen_hash_generators.iter().skip(i + 1) { - if p1 == p2 { - panic!("Duplicate generator!"); - } - } - } - + JubjubBls12::check_consistency_of_pedersen_hash_generators( + &tmp_params, + &pedersen_hash_generators, + ); tmp_params.pedersen_hash_generators = pedersen_hash_generators; } @@ -314,43 +283,47 @@ impl JubjubBls12 { let mut fixed_base_generators = vec![edwards::Point::zero(); FixedGenerators::Max as usize]; - fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] = find_group_hash( - &[], - constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION, - &tmp_params, - ); + fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] = + JubjubBls12::find_group_hash( + &[], + constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION, + &tmp_params, + ); fixed_base_generators[FixedGenerators::NoteCommitmentRandomness as usize] = - find_group_hash( + JubjubBls12::find_group_hash( b"r", constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, &tmp_params, ); - fixed_base_generators[FixedGenerators::NullifierPosition as usize] = find_group_hash( - &[], - constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION, - &tmp_params, - ); + fixed_base_generators[FixedGenerators::NullifierPosition as usize] = + JubjubBls12::find_group_hash( + &[], + constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION, + &tmp_params, + ); - fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] = find_group_hash( - b"v", - constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, - &tmp_params, - ); + fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] = + JubjubBls12::find_group_hash( + b"v", + constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, + &tmp_params, + ); fixed_base_generators[FixedGenerators::ValueCommitmentRandomness as usize] = - find_group_hash( + JubjubBls12::find_group_hash( b"r", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params, ); - fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] = find_group_hash( - &[], - constants::SPENDING_KEY_GENERATOR_PERSONALIZATION, - &tmp_params, - ); + fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] = + JubjubBls12::find_group_hash( + &[], + constants::SPENDING_KEY_GENERATOR_PERSONALIZATION, + &tmp_params, + ); // Check for duplicates, far worse than spec inconsistencies! for (i, p1) in fixed_base_generators.iter().enumerate() { @@ -427,6 +400,55 @@ impl JubjubBls12 { tmp_params } + + fn find_group_hash( + m: &[u8], + personalization: &[u8; 8], + params: &E::Params, + ) -> edwards::Point { + let mut tag = m.to_vec(); + let i = tag.len(); + tag.push(0u8); + + loop { + let gh = group_hash(&tag, personalization, params); + + // We don't want to overflow and start reusing generators + assert!(tag[i] != u8::max_value()); + tag[i] += 1; + + if let Some(gh) = gh { + break gh; + } + } + } + + /// Check for simple relations between the generators, that make finding collisions easy; + /// far worse than spec inconsistencies! + fn check_consistency_of_pedersen_hash_generators( + tmp_params: &E::Params, + pedersen_hash_generators: &[edwards::Point], + ) { + let sum = &edwards::Point::zero(); + for (i, p1) in pedersen_hash_generators.iter().enumerate() { + if p1 == &edwards::Point::zero() { + panic!("Neutral element!"); + } + // Used for checking no generator is a sum of previous ones. + let sum = &sum.add(&p1, &tmp_params); + for p2 in pedersen_hash_generators.iter().skip(i + 1) { + if p1 == p2 { + panic!("Duplicate generator!"); + } + if p1 == &p2.negate() { + panic!("Inverse generator!"); + } + if sum == p2 { + panic!("Linear relation between generators!"); + } + } + } + } } #[test] @@ -464,3 +486,35 @@ fn test_jubjub_bls12() { assert!(p == q); } + +#[test] +#[should_panic(expected = "Linear relation between generators!")] +fn test_jubjub_bls12_pedersen_hash_generators_consistency_check_linear_relation() { + let params = JubjubBls12::new(); + + let mut pedersen_hash_generators: Vec> = vec![]; + + use byteorder::{LittleEndian, WriteBytesExt}; + + for m in 0..5 { + let mut segment_number = [0u8; 4]; + (&mut segment_number[0..4]) + .write_u32::(m) + .unwrap(); + + let p = JubjubBls12::find_group_hash( + &segment_number, + constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, + ¶ms, + ); + pedersen_hash_generators.push(p); + } + + let p1 = pedersen_hash_generators[0].clone(); + let p2 = pedersen_hash_generators[1].clone(); + + //test for linear relation + pedersen_hash_generators.push(p1.add(&p2, ¶ms)); + + JubjubBls12::check_consistency_of_pedersen_hash_generators(¶ms, &pedersen_hash_generators); +} From e391594e9e91dde8f029a5ca9854c4d4fd6b4e13 Mon Sep 17 00:00:00 2001 From: Taylor Hornby Date: Tue, 12 Mar 2019 16:37:04 -0600 Subject: [PATCH 204/330] Fix broken linear relation checking --- zcash_primitives/src/jubjub/mod.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/zcash_primitives/src/jubjub/mod.rs b/zcash_primitives/src/jubjub/mod.rs index 65e04a0..7321932 100644 --- a/zcash_primitives/src/jubjub/mod.rs +++ b/zcash_primitives/src/jubjub/mod.rs @@ -429,13 +429,10 @@ impl JubjubBls12 { tmp_params: &E::Params, pedersen_hash_generators: &[edwards::Point], ) { - let sum = &edwards::Point::zero(); for (i, p1) in pedersen_hash_generators.iter().enumerate() { if p1 == &edwards::Point::zero() { panic!("Neutral element!"); } - // Used for checking no generator is a sum of previous ones. - let sum = &sum.add(&p1, &tmp_params); for p2 in pedersen_hash_generators.iter().skip(i + 1) { if p1 == p2 { panic!("Duplicate generator!"); @@ -443,8 +440,21 @@ impl JubjubBls12 { if p1 == &p2.negate() { panic!("Inverse generator!"); } - if sum == p2 { - panic!("Linear relation between generators!"); + } + + // check for a generator being the sum of any other two + for (j, p2) in pedersen_hash_generators.iter().enumerate() { + if j == i { + continue; + } + for (k, p3) in pedersen_hash_generators.iter().enumerate() { + if k == j || k == i { + continue; + } + let sum = &p2.add(&p3, &tmp_params); + if sum == p1 { + panic!("Linear relation between generators!"); + } } } } From caab37c3361d9a95b39adeedc9422b45355dcf65 Mon Sep 17 00:00:00 2001 From: Taylor Hornby Date: Wed, 10 Apr 2019 14:18:52 -0600 Subject: [PATCH 205/330] Fix build warnings --- bellman/src/gadgets/boolean.rs | 24 ++++++----------------- zcash_proofs/src/circuit/pedersen_hash.rs | 2 +- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/bellman/src/gadgets/boolean.rs b/bellman/src/gadgets/boolean.rs index 57718b1..a228d39 100644 --- a/bellman/src/gadgets/boolean.rs +++ b/bellman/src/gadgets/boolean.rs @@ -1781,12 +1781,8 @@ mod test { let value = Some(true); let b = AllocatedBit::alloc(&mut cs, Some(true)).unwrap(); - let allocated_value = AllocatedBit::alloc_conditionally( - cs.namespace(|| "alloc_conditionally"), - value, - &b, - ) - .unwrap(); + AllocatedBit::alloc_conditionally(cs.namespace(|| "alloc_conditionally"), value, &b) + .unwrap(); assert!(!cs.is_satisfied()); } @@ -1798,22 +1794,14 @@ mod test { //check with false bit let mut cs = TestConstraintSystem::::new(); let b1 = AllocatedBit::alloc(&mut cs, Some(false)).unwrap(); - let allocated_value = AllocatedBit::alloc_conditionally( - cs.namespace(|| "alloc_conditionally"), - value, - &b1, - ) - .unwrap(); + AllocatedBit::alloc_conditionally(cs.namespace(|| "alloc_conditionally"), value, &b1) + .unwrap(); //check with true bit let mut cs = TestConstraintSystem::::new(); let b2 = AllocatedBit::alloc(&mut cs, Some(true)).unwrap(); - let allocated_value = AllocatedBit::alloc_conditionally( - cs.namespace(|| "alloc_conditionally"), - value, - &b2, - ) - .unwrap(); + AllocatedBit::alloc_conditionally(cs.namespace(|| "alloc_conditionally"), value, &b2) + .unwrap(); assert!(cs.is_satisfied()); } diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index 5356331..5ac13e8 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -274,7 +274,7 @@ mod test { "2112827187110048608327330788910224944044097981650120385961435904443901436107", ]; for length in 300..302 { - let mut input: Vec = (0..length).map(|_| rng.next_u32() % 2 != 0).collect(); + let input: Vec = (0..length).map(|_| rng.next_u32() % 2 != 0).collect(); let mut cs = TestConstraintSystem::::new(); From 4dff8055bf37b7edc4f188770fc97600255efcfb Mon Sep 17 00:00:00 2001 From: Taylor Hornby Date: Thu, 25 Jul 2019 13:19:09 -0600 Subject: [PATCH 206/330] Remove unfinished find_group_hash test. --- zcash_primitives/src/group_hash.rs | 92 ------------------------------ 1 file changed, 92 deletions(-) diff --git a/zcash_primitives/src/group_hash.rs b/zcash_primitives/src/group_hash.rs index a4d0bb5..8549c5e 100644 --- a/zcash_primitives/src/group_hash.rs +++ b/zcash_primitives/src/group_hash.rs @@ -39,95 +39,3 @@ pub fn group_hash( Err(_) => None, } } - -#[cfg(test)] -mod test { - use ff::PrimeField; - use pairing::bls12_381::{Bls12, Fr}; - - use crate::{ - group_hash::group_hash, - jubjub::{edwards, JubjubBls12, JubjubEngine, PrimeOrder}, - }; - - #[test] - fn test_group_hash() { - fn find_group_hash( - m: &[u8], - personalization: &[u8; 8], - params: &E::Params, - ) -> edwards::Point { - let mut tag = m.to_vec(); - let i = tag.len(); - tag.push(0u8); - - loop { - let gh = group_hash(&tag, personalization, params); - - // We don't want to overflow and start reusing generators - assert!(tag[i] != u8::max_value()); - tag[i] += 1; - - if let Some(gh) = gh { - break gh; - } - } - } - let params = JubjubBls12::new(); - - let expected_points: Vec> = vec![]; - let domains = vec![ - hex!("0b4c693149060f99"), - hex!("982fc029ed2213e4"), - hex!("5a01101e28c6b466"), - hex!("a3716d31a988b6e6"), - ]; - let msgs = vec![ - hex!("076cb41a3d40719b258b9f2d959e6e26555950ba05cee053cda7fd1b7a3e94907906959d36e3462ab8c8ec070fa99dbc0bc6e5554e9a7c30ba875fa3b3269e0dbd30b63b19313dbe3a50279e7d5d4e3787ebc794bac60c683ca8e3220fcf8a2bccf061a02635b32a1e368e82b345ae5a1af5150b0c703892b8da35a070ddacf97faf529602ef4071908b7df09d66c55da5543d1669888d64ad17785e555d202e00a8005afb0d490c0807377d45227f4474e1aa527694b0b7a0b17608b09bd44c8d8aa9debfe7a7620cd60fc623bfe26ddfb91e9ae32138dc3a0585c42ca89a61c299f9fe79f0e0237d8ee8b4d30186b77a88bd6f0d20b753a496c3bf399e9ca1b62ade8e7dd662c5a19123f077066be5dfa90e5a06c2624046ddf11ce7e53cc3f88d8aa2834363c8d38dc612d58a980317448ef79ccebdcbcd9f03d31a13727e7bff883135b87072d164436b1da4b4f214601cef55a5c5721618c0c6dac59464084b9ef9620729e8f9c7ef2c2c806f2506ccf7b8f2edcb675f8be1c50b288c3653e8db78baa785f0a0c2e059fdd2cf0104b597cdb9b82d03c63c161085da637fbfe444d3e5f9b9143088f2be54c1d293ac03967299dafca5b3c4f5e3257fe9010325531c9cc1cd67b70afad697ad750d8488b977ad3d3882f2d0050a0e22aab95eb13e80ffac09003a4282ef27820636b17ed11bc29bfe9b1941a0d5534510483f4178b327b7297b95b98832313999bedd43018e27ffb9d69777a4d7aeb1e5702171317949cb2577b897b059a976ce944a750b77ab07cf6ed4c8f45559f46dedcea4d5082772ac11ade8d1a057ce584000ef0bf4aa0b5589c5cca54fb69cc67d486ac040480efe6e5a38b3cb82c2b78ad125ee6cee4261644f38bdc34bf4da4dc087a394c313ec839a8a4ba6bcbf1eeb4afc15fd46fb9900a4744943efefffc477f8ca897e683d7d9f007f6c73ca4b64eb4ffb253f0a6137fc2956c74b9e869527b3bc5819c3d6cf6523bcd7a44599fdd6baeca754bc55d9ff338e64399d6dcaf50df0f1c5873991eb83fb92d3ce9b2bdd133b24b9edae467371563167c9402adadbfeed5d3f571a9fb1d5090004213fb333484d15ed753fbaeacf16aeb9764a960c5b7b382d2d925050fd103a0bc1ae709cfff11e701cad99d82eb42a493ef2f32862ac07cbe2494b354511cdfc6417dfa647c967026552e39cb96282e40c4ad7c3d838b2edb0df0e9b98bb90280998ff8cafa456fafaa6a769ad47599bec3fe242211424369acca65ad5507f96881130262b407d0f5fdabfbdb1b97570dd3b397fce15234674a90812f7eb6ddc5cb21db5b64e25a8449e67a7ae09d2e438d1da8ff5e06ff417d5c0d432a2fe811ad216ccd46f71202b0bd045dc3664f8d2a4b78de8991191876c38959056c02764d1cabec14de12aa059dea10d0d20b75a7f"), - hex!("814d0b90d16d7d4c270913ab375291651ea130aa5608d5fc625a8daaf49d15ac3977f879126f19f651b8b167f5debf3e824efcf7fe27789025026e91db64f271ea2b3787448bddac9992d45b3419209bd4ec43dda893af5ce21939c3cfceef2b2b3bbb8bebe19cc3e5068c54ca4eb0c80152f0a9738f01a48f2b86503213a0ea50008d77a96842749bd3aa09368f641df231b8ea58a1ab76b311cc3c5f6341216407f0e3bb9e20efc50b8430ce3eb848c53441e1c22cd358042d4f7fc0bcb41a3b45edd30d52b0acb67ec67312fbbf47b3fa1716ab14caeab013c30a886070b9e8bce8e3c6d24e57e3e96e9ad044a7e2a6ea13a6a2dbffca1b81ba76075831b167ff423523429ffa42a03654329d86475642d1b1ed9f597d45147884a88844d33bec515a0b38d1e0351647c7c522bcdcf5c9286afda49431c2e156f4a8859d28b6e19eaabee2adf42acadfd9ae8ed6b1031c4d4c9feea5380db5e56ec036ff656c3eb59f11e58bffbbd988177bd2a0116ca2870e4d471f5c7f5c36463089118ed57073bc069eb209264640b3048a0204b4af3d714e64b502b4168514f86d0269346e78ea9d0d33926e3c784f3ea3dd07ad1bc188fad41880333786e821322d0c8be675fde29ea0a3f6ed30fc46c79447f4368ffc8268fba099b5b0ca7cb75995313a556c7ab339f0c03af811bae47f4806f2b6eacec66f15e4656cefe3df08887a625f14bf497d2f8bf99a68e7361193116a3bb1765d7e8e7bc4d4864c88dbfb818334b8cfb5dca3620e097e40756a1f7d28c7868d7dd65e49bc5155e26c8973d476e25fb1ea75e382f654bdfbe2bc45540f215a357fa29cd6238e8bd1085ce625f43f40eaa1d20bcf9772890725ca27b4d38c9870d91530f95a406d90b1b77c700d0d0296a1ded208507b7284fb4d2202c7fe9a20ef96700f7eb70e3eaad51bb95e215da42794fd17d0aae260cecccf99dcbde251f6c115acbee8a30745bffa43f572383112f45e97a3316edc96a8f6f9dfd55cc99f878e627a46ef65ac95f81eedb14106dcb0b2c6c53bb9034ead2338b28b20c09f2f17f202a7b6c1be3e8885f119e4f6599e05ddcd5b74a99af7c935228899de177a93438da57ce396782f65032ef40805ec01e7375b07dd71929fddb88995da03a879437f34534514d48b1ae5ba86e096d00951e7b96ad890ed85dd4a2f79214f7193ca02facb19d9d99ca1bca3ffd237abfd57c4d9b210115f5d62a092d36b100b1f84b17889bb59fd84d47e046ec646ee99a3c14c2ad9fd78628c76035ad126ea3ac0f7543d15f569d9de5467d54f3536105e7f9d0592d2e3a3b9175f252e6243fc1694231ea5159f865d2997eeb50241c4a7ab5e0d97ec760c40212116f3b1f139c48be3696c717329878dacdd7376c81ef8c077d2eac4d8516551cac435077d2359a24e624a1b26b8"), - hex!("6b94782eb58954430de33992f53f4ee00f99977a8cfa30eda3021673182e39b046594fc8df623e23a58bb136aa294feb4c4e7a692db5b537176eb0c521fde239eb6a5218fc82bcb7de114e05120b91a605beff13a9968564aefc15255bfb6ba2ebe37832ecf9168ac65dd01015df8b9372472c9cc5b4446b73467afdabdd25a629eec87ee0221a93f7bd88125f1178d427cb21c288a8d8c3cb4d1843a57d4637bdb1eeffa1dd8276ac680140e73657ed4a84563f5b09ddfb604bf4c2ddd6075db6b02d78c4cb02a4ce3aac20aa15e3a5d5b30669b343c5239c134f76de18185a6e0a66407c26023d3049adc74b0fdde0a9176cc3e2ccb9bf03ee306953a9ac1312c68c65a284110590c29dc8baff373ad49a40e3de8098c67dca210c26f768745bfa859b0a3fc5e88985d046abcb5e6155e0e23115ad062d10d1b73af0680f9a141e379bbd177bb0f9ea3bb5f01b8a5665bf0a9ea1266138bd688572a779c0b0a69e57f40dfb418d514f8ab058ba28eeb21cefa3634300e89d204c4236848f5dd11130ba13d83c10afebd4f822c26ae0ed7ea3bc3ac92817ae405c3cf886c81bdda07447cebb71a8bc3d26973afa57e0365b8fc8c0658131734ca29afa10eeb0895d3cd5f0b84a625f53f9f3dbfc5bfac233c7c7d3ac8829475076b14e5c57026c4a63bc9a347ec3fdbcc997cea4c273f923e01fa0781f847cea54a81a4ed14117a46b0894bf4816a46b1f7af963382eeb6f58ed35fa70572a7bb3f2bf97d8c549fc55d7bf562c2d8c4d4d748b7d062cb41b025309b5587a4b2a0cedc85280dce2f58dad0943ccd591b2ee7bb39378efa09cbdd975af07c33862f560d03e1621374cadf6cb05484a23a37d3c200bc3e1780ac65b02bab7db25fe89dae218d9e7dfb60473f9f5b21a007b714eef58129518d637bd581922a54629bef62a575a98d513d9abb90b023752439e20d897242fea3fabcf3fb7eae7604fd0dd1bd5653c41276660a15d39093e4c0862d48333b77b8bc3d64a5908614b3af7c815406b3ba21598cf0c70afe7b8a8ca668dfc8376e15a0ba0d9b9a79552993d2a24f3d0689964e7141d4255a19cc9450806d632a73b88a5768d0de18c20f2b00268ce5d3a8ca2231ce3d8924335f650cb98df84bb58073166848786de3d1823075259952389c50bced6c8921e7b019977d58c5a07e57eb21ef907a9dd465962bd52beb0cbad28b434ed7fecde21953b3fd260a90fd9ab7495c47cdaa4e73fb487a5239e03fb1e74e8cf6d691126813a6f5c16ae948da8cda292fd46e79f7551f8553b21249a5679a5f56dd4b08a136ce0fe8146bddc1d60e0a9a757e1a608749bcce4ac57cdc8fafff59860fd22f95f46f3ab50812a6b877f24941c2b8e1724e527ba9ad9331e004792d2b292a7edee983e6cc22445f4fd43e9f006ddea19fbe6269f29cd"), - hex!("883b1a34c0d0a8d9387cff427ab0b476b4c6f5a09e30be336aa2bc35f38ab4cc398673fae02ab727f069e887006ac3c0b891477c4a837456417c9e817c5ccdaf12b54eb90cc18a9c30673ed36bd7fba45269437c09feff9a1bcc2993533533227a535950c98cc77f00f4e77c34184b45d865942a3d72acce4922e9c284df5589d506404648c5c3bc7f217ca023b364e74d591d75c8a19e063b2b82c28e27ce5b2afede6699d6bf8d4931244aad739b285f410f1e95c6d5e9a34982908d1c7be5f0365dbf30a7d6dbb2821bf6d55c142a15bd561f3eb202da9b59f891584b35011f5cbe77cab38263b5773360d52e29b765a03c420c75ffa2c91e8edd4a9bba4035119bc3a088ec303a6344e4dafbd8d1889cc9b3d56ee08cff1530f1a1d9a77712006ebc9a3d80f5a69e17b0a0f65d97e53e7852ddd95760c68bba78d326a28eb07908c8e630dd6e42ab272e980774c5c51825c02ed8950fc85f5711c80d5fed1d72162a4bcaefbba33c09d09e0611ad5c2bb2949daa55861b5f6f8beea02ed392d09ab0489f89b3875fe7ae90c6ecf0bddb4b9fbce6dc1f97b12ee058f00cc9672c35702dac4afbd6776e1e222d2182358e91e8d4d20b99d5f2adbac7abad48c07afc94c212278812bfc5e76da0e1b97b850020bc1ba3c0bc0093d8acf4a594a8fc1dcea70c613fcc550b7654a08ed9f50a34c21626f2b599a15a097c85785bc93d5c5034edb3590f0c6aee3dcbeac5f15be5bf6f179246c347dce5040115dccff18fbcd9e9ab485d85e89dc0995aaebe4eb8796fb01b03fe5f5c6c903845a0fc02c69d2543684a33e4eefc7e0d5635192c82fdde5e7487df95595a442a6a71e98e09073cdf318f808fd916e0de7e9182855023f4844042764fef897ccb500d520651a262d27f46c16e38187da84a3d7f9c42bb65e1940a1f3b3c2eced613e141839d77851ef833f94d9a5ec073e1b12d0a2b59b8b90c5e560baceacebe569f8ded41a67d15cd7486f45aacc1fa4e50805485a698d2722ba8fbf87442e1a2e46cde49f1600f97ae3d6f67169141a40b0628c9994c115377db6c30d822381dede366f355c71ff8c38ae4f60da77bf40e3da97f77ba6756ae766a17896ead15d4367f43fd2a4c096feb3e23d4a061fed2422e9e424f1e81e890ecc9474bb5b7d8231447d5359efa8ce4d40698d329cd5d069f50050d26a0c613a4cc3d70774537af278643799bf5d336d71a19b83a5660ebc6fefa4664167c497478ec4e8b0954fc1a41948a84f5271c4c2ab93c6848fe5abd28fa68b47ff79ba1475a46d2ddbf5a07600ee4cf76bf85bccc53d5b5094f6728542951a63c71b251429e8bb4fc95cfbf283db2b0ad2d16bc2d8ba07b193249bc974eb5392b7e9c5a0e1056ef0208e6494abe61f37d64b543acf509926f7b9f1724ce39e7690bae4d918be3295fd2") - ]; - - let ys = vec![ - "8502599294297669157183582041043506286304348771153601905088214968423735432772", - "33965310400650966081486833884535323100804531882948083108992748314044766607474", - "15277426621450144245366093477629790944965634885834431068514786570163432982421", - "35526445498940553839675656924597924255939683458731864358252626115877434851278", - ]; - let xs = vec![ - "23479585783156774250942425515624703792585157520679515316930097097463607664576", - "30414851484511157010605445406157992259368652076831836832380699127755424334026", - "34566775937206506013251574661622220967552701387632591444790779184716709173668", - "32625571922270028001313966220069858825087579007581150636305043327525524456655", - ]; - for i in 0..domains.len() { - let domain = domains[i]; - let msg = msgs[i]; - - let gh: edwards::Point = find_group_hash(&msg, &domain, ¶ms); - - let p_sign_false = - edwards::Point::::get_for_y(Fr::from_str(ys[i]).unwrap(), false, ¶ms) - .unwrap(); - let p_sign_true = - edwards::Point::::get_for_y(Fr::from_str(ys[i]).unwrap(), true, ¶ms) - .unwrap(); - let is_one_of_xs = p_sign_false.to_xy().0 == Fr::from_str(xs[i]).unwrap() - || p_sign_true.to_xy().0 == Fr::from_str(xs[i]).unwrap(); - let is_y = p_sign_false.to_xy().1 == Fr::from_str(ys[i]).unwrap() - && p_sign_true.to_xy().1 == Fr::from_str(ys[i]).unwrap(); - assert!(is_one_of_xs && is_y); - } - - for m in 0..5 { - use byteorder::{LittleEndian, WriteBytesExt}; - let mut segment_number = [0u8; 4]; - (&mut segment_number[0..4]) - .write_u32::(m) - .unwrap(); - let p: edwards::Point = - find_group_hash(&segment_number, b"Zcash_PH", ¶ms); - } - } -} From 3701c2b4421616e18622c4fa0e623894435d8cb3 Mon Sep 17 00:00:00 2001 From: Taylor Hornby Date: Thu, 29 Aug 2019 15:57:02 -0600 Subject: [PATCH 207/330] Increase the number of pedersen hash generators, exercise all test vectors. --- zcash_primitives/src/jubjub/mod.rs | 2 +- zcash_primitives/src/pedersen_hash.rs | 26 ++++++++++++++++---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/zcash_primitives/src/jubjub/mod.rs b/zcash_primitives/src/jubjub/mod.rs index 7321932..d3c44b4 100644 --- a/zcash_primitives/src/jubjub/mod.rs +++ b/zcash_primitives/src/jubjub/mod.rs @@ -220,7 +220,7 @@ impl JubjubBls12 { { let mut pedersen_hash_generators = vec![]; - for m in 0..5 { + for m in 0..6 { use byteorder::{LittleEndian, WriteBytesExt}; let mut segment_number = [0u8; 4]; diff --git a/zcash_primitives/src/pedersen_hash.rs b/zcash_primitives/src/pedersen_hash.rs index 10cad94..c2668f9 100644 --- a/zcash_primitives/src/pedersen_hash.rs +++ b/zcash_primitives/src/pedersen_hash.rs @@ -124,19 +124,25 @@ pub mod test { fn test_pedersen_hash_points() { let test_vectors = pedersen_hash_vectors::get_vectors(); - let params = &JubjubBls12::new(); + assert!(test_vectors.len() > 0); - let v = &test_vectors[0]; - let input_bools: Vec = v.input_bits.iter().map(|&i| i == 1).collect(); + for v in test_vectors.iter() { + let params = &JubjubBls12::new(); - // The 6 bits prefix is handled separately - assert_eq!(v.personalization.get_bits(), &input_bools[..6]); + let input_bools: Vec = v.input_bits.iter().map(|&i| i == 1).collect(); - let (x, y) = - pedersen_hash::(v.personalization, input_bools.into_iter().skip(6), params) - .to_xy(); + // The 6 bits prefix is handled separately + assert_eq!(v.personalization.get_bits(), &input_bools[..6]); - assert_eq!(x.to_string(), v.hash_x); - assert_eq!(y.to_string(), v.hash_y); + let (x, y) = pedersen_hash::( + v.personalization, + input_bools.into_iter().skip(6), + params, + ) + .to_xy(); + + assert_eq!(x.to_string(), v.hash_x); + assert_eq!(y.to_string(), v.hash_y); + } } } From 39a73c8eda3af3ad94bde3eb9aea018b7e5c5c31 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 17 Sep 2019 00:16:33 +0100 Subject: [PATCH 208/330] Add missing cs.is_satisfied() to bellman test --- bellman/src/gadgets/boolean.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bellman/src/gadgets/boolean.rs b/bellman/src/gadgets/boolean.rs index a228d39..52b6cb8 100644 --- a/bellman/src/gadgets/boolean.rs +++ b/bellman/src/gadgets/boolean.rs @@ -1797,6 +1797,8 @@ mod test { AllocatedBit::alloc_conditionally(cs.namespace(|| "alloc_conditionally"), value, &b1) .unwrap(); + assert!(cs.is_satisfied()); + //check with true bit let mut cs = TestConstraintSystem::::new(); let b2 = AllocatedBit::alloc(&mut cs, Some(true)).unwrap(); From 9377b78b35a327b1d31abd0e109698635ee5e4bb Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 17 Sep 2019 18:03:58 +0100 Subject: [PATCH 209/330] Panic if spending_key is given a seed shorter than 32 bytes This enforces the MUST requirement in ZIP 32. A panic is used instead of an error because this should be considered an implementation error. Ideally the type system would prevent this from occurring at all. Closes #125. --- zcash_client_backend/src/keys.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/zcash_client_backend/src/keys.rs b/zcash_client_backend/src/keys.rs index 4d4cd6f..bae7f5f 100644 --- a/zcash_client_backend/src/keys.rs +++ b/zcash_client_backend/src/keys.rs @@ -5,6 +5,10 @@ use zcash_primitives::zip32::{ChildIndex, ExtendedSpendingKey}; /// Derives the ZIP 32 [`ExtendedSpendingKey`] for a given coin type and account from the /// given seed. /// +/// # Panics +/// +/// Panics if `seed` is shorter than 32 bytes. +/// /// # Examples /// /// ``` @@ -13,6 +17,10 @@ use zcash_primitives::zip32::{ChildIndex, ExtendedSpendingKey}; /// let extsk = spending_key(&[0; 32][..], COIN_TYPE, 0); /// ``` pub fn spending_key(seed: &[u8], coin_type: u32, account: u32) -> ExtendedSpendingKey { + if seed.len() < 32 { + panic!("ZIP 32 seeds MUST be at least 32 bytes"); + } + ExtendedSpendingKey::from_path( &ExtendedSpendingKey::master(&seed), &[ From 450087e2800ebe75aacaa25cd522909bf0fb0a49 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 17 Sep 2019 23:58:14 +0100 Subject: [PATCH 210/330] Add test for spending_key panic on short seed --- zcash_client_backend/src/keys.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/zcash_client_backend/src/keys.rs b/zcash_client_backend/src/keys.rs index bae7f5f..63dd5ee 100644 --- a/zcash_client_backend/src/keys.rs +++ b/zcash_client_backend/src/keys.rs @@ -30,3 +30,14 @@ pub fn spending_key(seed: &[u8], coin_type: u32, account: u32) -> ExtendedSpendi ], ) } + +#[cfg(test)] +mod tests { + use super::spending_key; + + #[test] + #[should_panic] + fn spending_key_panics_on_short_seed() { + let _ = spending_key(&[0; 31][..], 0, 0); + } +} From 1d02363752242bbcd47cae5ad940ab0007152880 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 2 Aug 2019 14:57:34 +0100 Subject: [PATCH 211/330] Add READMEs to Cargo.toml files This will cause crates.io to render each crate's README as its information page. --- bellman/Cargo.toml | 1 + ff/Cargo.toml | 1 + group/Cargo.toml | 1 + librustzcash/Cargo.toml | 1 + pairing/Cargo.toml | 1 + zcash_client_backend/Cargo.toml | 1 + zcash_primitives/Cargo.toml | 1 + zcash_proofs/Cargo.toml | 1 + 8 files changed, 8 insertions(+) diff --git a/bellman/Cargo.toml b/bellman/Cargo.toml index fe2a55a..3b2a46f 100644 --- a/bellman/Cargo.toml +++ b/bellman/Cargo.toml @@ -1,6 +1,7 @@ [package] authors = ["Sean Bowe "] description = "zk-SNARK library" +readme = "README.md" documentation = "https://github.com/ebfull/bellman" homepage = "https://github.com/ebfull/bellman" license = "MIT/Apache-2.0" diff --git a/ff/Cargo.toml b/ff/Cargo.toml index 93dfb9f..b832581 100644 --- a/ff/Cargo.toml +++ b/ff/Cargo.toml @@ -3,6 +3,7 @@ name = "ff" version = "0.4.0" authors = ["Sean Bowe "] description = "Library for building and interfacing with finite fields" +readme = "README.md" documentation = "https://docs.rs/ff/" homepage = "https://github.com/ebfull/ff" license = "MIT/Apache-2.0" diff --git a/group/Cargo.toml b/group/Cargo.toml index 2b09f09..f27eb3f 100644 --- a/group/Cargo.toml +++ b/group/Cargo.toml @@ -5,6 +5,7 @@ authors = [ "Sean Bowe ", "Jack Grigg ", ] +readme = "README.md" license = "MIT/Apache-2.0" description = "Elliptic curve group traits and utilities" diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index 8290191..becdf2a 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -7,6 +7,7 @@ authors = [ "Jay Graber ", "Simon Liu " ] +readme = "README.md" edition = "2018" [lib] diff --git a/pairing/Cargo.toml b/pairing/Cargo.toml index 8fadb32..1801ffd 100644 --- a/pairing/Cargo.toml +++ b/pairing/Cargo.toml @@ -7,6 +7,7 @@ authors = [ "Sean Bowe ", "Jack Grigg ", ] +readme = "README.md" license = "MIT/Apache-2.0" description = "Pairing-friendly elliptic curve library" diff --git a/zcash_client_backend/Cargo.toml b/zcash_client_backend/Cargo.toml index 9996a47..6199f2b 100644 --- a/zcash_client_backend/Cargo.toml +++ b/zcash_client_backend/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.0" authors = [ "Jack Grigg ", ] +readme = "README.md" edition = "2018" [dependencies] diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index 22e4aca..a026618 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.0" authors = [ "Jack Grigg ", ] +readme = "README.md" edition = "2018" [dependencies] diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index 766db63..f47714d 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.0" authors = [ "Jack Grigg ", ] +readme = "README.md" edition = "2018" [dependencies] From 4cbc0451c1f4e713886df833466923931c802f8e Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 24 Sep 2019 10:34:27 +0200 Subject: [PATCH 212/330] switch to blake2_simd --- Cargo.toml | 2 +- src/node_data.rs | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6373417..ff2a2f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,4 +12,4 @@ quickcheck = "0.8" derive_more = "0.15" bigint = "4" byteorder = "1" -blake2 = { package = "blake2-rfc", git = "https://github.com/gtank/blake2-rfc.git", rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" } +blake2 = { package = "blake2b_simd", version = "0.5" } diff --git a/src/node_data.rs b/src/node_data.rs index dcc8ded..0adc0f2 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -1,6 +1,6 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt, ByteOrder}; use bigint::U256; -use blake2::blake2b::Blake2b; +use blake2::Params as Blake2Params; pub const MAX_NODE_DATA_SIZE: usize = 32 + 4 + 4 + 4 + 4 + 32 + 32 + 32 + 9 + 9 + 9; // 171 @@ -23,10 +23,14 @@ pub struct NodeData { } fn blake2b_personal(personalization: &[u8], input: &[u8]) -> [u8; 32] { - let mut hasher = Blake2b::with_params(32, &[], &[], personalization); - hasher.update(input); + let hash_result = Blake2Params::new() + .hash_length(32) + .personal(personalization) + .to_state() + .update(input) + .finalize(); let mut result = [0u8; 32]; - result.copy_from_slice(hasher.finalize().as_bytes()); + result.copy_from_slice(hash_result.as_bytes()); result } From 38aa09b6a1d3d017b14d070f18d8567a8e5d3b19 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 24 Sep 2019 10:35:44 +0200 Subject: [PATCH 213/330] change package name --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ff2a2f8..ce17638 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "zcash-mmr" +name = "zcash_mmr" version = "0.1.0" authors = ["NikVolf "] edition = "2018" From fb6fef4e9ce94c5d7d0adabb3e84cdeb4dea221a Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 24 Sep 2019 10:36:28 +0200 Subject: [PATCH 214/330] update readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 26532bb..088208c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# zcash-mmr +# zcash_mmr Special implementation of merkle mountain ranges (MMR) for ZCash! @@ -14,7 +14,7 @@ The main design goals of this mmr implementation are # License -`zcash-mmr` is primarily distributed under the terms of both the MIT +`zcash_mmr` is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0), at your choice. See LICENSE-APACHE, and LICENSE-MIT for details. @@ -22,5 +22,5 @@ See LICENSE-APACHE, and LICENSE-MIT for details. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in `zcash-mmr` by you, as defined in the Apache-2.0 license, shall be +for inclusion in `zcash_mmr` by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. From d9a0b9c83f7082ade194f5cf78d833a7a2e85771 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 24 Sep 2019 10:31:04 +0100 Subject: [PATCH 215/330] CI: Check intra-doc links Credit: https://twitter.com/tomaka17/status/1176017851410526208 --- .github/workflows/rust.yml | 15 +++++++++++++++ bellman/src/lib.rs | 3 +++ ff/src/lib.rs | 2 ++ group/src/lib.rs | 3 +++ librustzcash/src/rustzcash.rs | 3 +++ pairing/src/lib.rs | 2 ++ zcash_client_backend/src/lib.rs | 3 +++ zcash_primitives/src/lib.rs | 3 +++ zcash_proofs/src/lib.rs | 3 +++ 9 files changed, 37 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 300a7ba..cf55d9a 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -39,3 +39,18 @@ jobs: run: $HOME/.cargo/bin/cargo test --verbose --release --all - name: Run slow tests run: $HOME/.cargo/bin/cargo test --verbose --release --all -- --ignored + + doc-links: + name: Check intra-doc links + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + override: true + - uses: actions-rs/cargo@v1 + with: + command: doc + args: --document-private-items diff --git a/bellman/src/lib.rs b/bellman/src/lib.rs index 1445107..5152b0f 100644 --- a/bellman/src/lib.rs +++ b/bellman/src/lib.rs @@ -1,3 +1,6 @@ +// Catch documentation errors caused by code changes. +#![deny(intra_doc_link_resolution_failure)] + #[cfg(feature = "multicore")] extern crate crossbeam; diff --git a/ff/src/lib.rs b/ff/src/lib.rs index fb692c2..456cbc1 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -1,3 +1,5 @@ +// Catch documentation errors caused by code changes. +#![deny(intra_doc_link_resolution_failure)] #![allow(unused_imports)] #[cfg(feature = "derive")] diff --git a/group/src/lib.rs b/group/src/lib.rs index 0d50f8a..be78b2a 100644 --- a/group/src/lib.rs +++ b/group/src/lib.rs @@ -1,3 +1,6 @@ +// Catch documentation errors caused by code changes. +#![deny(intra_doc_link_resolution_failure)] + use ff::{PrimeField, PrimeFieldDecodingError, ScalarEngine, SqrtField}; use rand::RngCore; use std::error::Error; diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index e3a85e4..068b824 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -1,3 +1,6 @@ +// Catch documentation errors caused by code changes. +#![deny(intra_doc_link_resolution_failure)] + use lazy_static; use ff::{PrimeField, PrimeFieldRepr}; diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs index b5b46e3..9f20a88 100644 --- a/pairing/src/lib.rs +++ b/pairing/src/lib.rs @@ -8,6 +8,8 @@ #![cfg_attr(feature = "cargo-clippy", allow(clippy::many_single_char_names))] #![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))] #![cfg_attr(feature = "cargo-clippy", allow(clippy::write_literal))] +// Catch documentation errors caused by code changes. +#![deny(intra_doc_link_resolution_failure)] // Force public structures to implement Debug #![deny(missing_debug_implementations)] diff --git a/zcash_client_backend/src/lib.rs b/zcash_client_backend/src/lib.rs index 02de4b4..6d1d993 100644 --- a/zcash_client_backend/src/lib.rs +++ b/zcash_client_backend/src/lib.rs @@ -3,6 +3,9 @@ //! `zcash_client_backend` contains Rust structs and traits for creating shielded Zcash //! light clients. +// Catch documentation errors caused by code changes. +#![deny(intra_doc_link_resolution_failure)] + pub mod constants; pub mod encoding; pub mod keys; diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 644d7fb..e8c2a51 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -1,3 +1,6 @@ +// Catch documentation errors caused by code changes. +#![deny(intra_doc_link_resolution_failure)] + #[macro_use] extern crate lazy_static; diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs index a83964a..a323cc3 100644 --- a/zcash_proofs/src/lib.rs +++ b/zcash_proofs/src/lib.rs @@ -1,3 +1,6 @@ +// Catch documentation errors caused by code changes. +#![deny(intra_doc_link_resolution_failure)] + use bellman::groth16::{prepare_verifying_key, Parameters, PreparedVerifyingKey, VerifyingKey}; use pairing::bls12_381::Bls12; use std::fs::File; From 1fbf38280e8cef114b4d4681d39760189e3b2e40 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 24 Sep 2019 10:42:49 +0100 Subject: [PATCH 216/330] Fix intra-doc links --- zcash_client_backend/src/constants/mainnet.rs | 2 +- zcash_client_backend/src/constants/testnet.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/zcash_client_backend/src/constants/mainnet.rs b/zcash_client_backend/src/constants/mainnet.rs index ed90697..24dbbe7 100644 --- a/zcash_client_backend/src/constants/mainnet.rs +++ b/zcash_client_backend/src/constants/mainnet.rs @@ -23,6 +23,6 @@ pub const HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY: &str = "zxviews"; /// /// Defined in section 5.6.4 of the [Zcash Protocol Specification]. /// -/// [`PaymentAddress`]: sapling_crypto::primitives::PaymentAddress +/// [`PaymentAddress`]: zcash_primitives::primitives::PaymentAddress /// [Zcash Protocol Specification]: https://github.com/zcash/zips/blob/master/protocol/protocol.pdf pub const HRP_SAPLING_PAYMENT_ADDRESS: &str = "zs"; diff --git a/zcash_client_backend/src/constants/testnet.rs b/zcash_client_backend/src/constants/testnet.rs index f151110..a83706e 100644 --- a/zcash_client_backend/src/constants/testnet.rs +++ b/zcash_client_backend/src/constants/testnet.rs @@ -23,6 +23,6 @@ pub const HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY: &str = "zxviewtestsapling"; /// /// Defined in section 5.6.4 of the [Zcash Protocol Specification]. /// -/// [`PaymentAddress`]: sapling_crypto::primitives::PaymentAddress +/// [`PaymentAddress`]: zcash_primitives::primitives::PaymentAddress /// [Zcash Protocol Specification]: https://github.com/zcash/zips/blob/master/protocol/protocol.pdf pub const HRP_SAPLING_PAYMENT_ADDRESS: &str = "ztestsapling"; From ce2416623fd95f1307fb5f1058431b3a51d45e30 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 24 Sep 2019 12:19:25 +0200 Subject: [PATCH 217/330] get rid of derive_more --- Cargo.toml | 1 - src/lib.rs | 28 +++++++++++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ce17638..d527675 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ assert_matches = "1.3.0" quickcheck = "0.8" [dependencies] -derive_more = "0.15" bigint = "4" byteorder = "1" blake2 = { package = "blake2b_simd", version = "0.5" } diff --git a/src/lib.rs b/src/lib.rs index f0eb3f4..da0cc5d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,28 +10,42 @@ pub use tree::Tree; pub use node_data::{NodeData, MAX_NODE_DATA_SIZE}; pub use entry::{Entry, MAX_ENTRY_SIZE}; -#[derive(Debug, derive_more::Display)] +#[derive(Debug)] pub enum Error { - #[display(fmt="Node/leaf expected to be in memory: {}", _0)] ExpectedInMemory(EntryLink), - #[display(fmt="Node expected")] ExpectedNode, - #[display(fmt="Node expected, not leaf: {}", _0)] ExpectedNodeForLink(EntryLink), } +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + Self::ExpectedInMemory(l) => write!(f, "Node/leaf expected to be in memory: {}", l), + Self::ExpectedNode => write!(f, "Node expected"), + Self::ExpectedNodeForLink(l) => write!(f, "Node expected, not leaf: {}", l), + } + } +} + /// Reference to to the tree node. #[repr(C)] -#[derive(Clone, Copy, Debug, derive_more::Display)] +#[derive(Clone, Copy, Debug)] pub enum EntryLink { /// Reference to the stored (in the array representation) leaf/node. - #[display(fmt="stored(@{})", _0)] Stored(u32), /// Reference to the generated leaf/node. - #[display(fmt="generated(@{})", _0)] Generated(u32), } +impl std::fmt::Display for EntryLink { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + Self::Stored(v) => write!(f, "stored({})", v), + Self::Generated(v) => write!(f, "generated({})", v), + } + } +} + /// MMR Node. It is leaf when `left`, `right` are `None` and node when they are not. #[repr(C)] #[derive(Debug)] From 7879b6332132108bdda7476a574eb5ef9cc5f9a3 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 24 Sep 2019 12:45:23 +0200 Subject: [PATCH 218/330] add docs --- src/entry.rs | 11 +++++++++++ src/lib.rs | 8 ++++++++ src/node_data.rs | 18 ++++++++++++++++++ src/tree.rs | 11 +++++++++++ 4 files changed, 48 insertions(+) diff --git a/src/entry.rs b/src/entry.rs index 72582c2..04490b3 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -2,8 +2,10 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use crate::{EntryKind, NodeData, Error, EntryLink, MAX_NODE_DATA_SIZE}; +/// Max serialized length of entry data. pub const MAX_ENTRY_SIZE: usize = MAX_NODE_DATA_SIZE + 9; +/// MMR Entry. #[derive(Debug)] pub struct Entry { pub(crate) kind: EntryKind, @@ -11,23 +13,28 @@ pub struct Entry { } impl Entry { + /// Update siblings of the entry (to promote it from leaf to node) pub fn update_siblings(&mut self, left: EntryLink, right: EntryLink) { self.kind = EntryKind::Node(left, right); } + /// Returns if is this node complete (has total of 2^N leaves) pub fn complete(&self) -> bool { let leaves = self.leaf_count(); leaves & (leaves - 1) == 0 } + /// Number of leaves under this node. pub fn leaf_count(&self) -> u64 { self.data.end_height - self.data.start_height + 1 } + /// Is this node a leaf. pub fn is_leaf(&self) -> bool { if let EntryKind::Leaf = self.kind { true } else { false } } + /// Left child pub fn left(&self) -> Result { match self.kind { EntryKind::Leaf => { Err(Error::ExpectedNode) } @@ -35,6 +42,7 @@ impl Entry { } } + /// Right child. pub fn right(&self) -> Result { match self.kind { EntryKind::Leaf => { Err(Error::ExpectedNode) } @@ -42,6 +50,7 @@ impl Entry { } } + /// Read from byte representation. pub fn read(consensus_branch_id: u32, r: &mut R) -> std::io::Result { let kind = { match r.read_u8()? { @@ -67,6 +76,7 @@ impl Entry { }) } + /// Write to byte representation. pub fn write(&self, w: &mut W) -> std::io::Result<()> { match self.kind { EntryKind::Node(EntryLink::Stored(left), EntryLink::Stored(right)) => { @@ -85,6 +95,7 @@ impl Entry { Ok(()) } + /// Convert from byte representation. pub fn from_bytes>(consensus_branch_id: u32, buf: T) -> std::io::Result { let mut cursor = std::io::Cursor::new(buf); Self::read(consensus_branch_id, &mut cursor) diff --git a/src/lib.rs b/src/lib.rs index da0cc5d..c0c781c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,19 +1,25 @@ //! MMR library for Zcash //! //! To be used in zebra and via FFI bindings in zcashd +#![warn(missing_docs)] mod tree; mod node_data; mod entry; + pub use tree::Tree; pub use node_data::{NodeData, MAX_NODE_DATA_SIZE}; pub use entry::{Entry, MAX_ENTRY_SIZE}; +/// Crate-level error type #[derive(Debug)] pub enum Error { + /// Entry expected to be presented in the tree view while it was not. ExpectedInMemory(EntryLink), + /// Entry expected to be a node. ExpectedNode, + /// Entry expected to be a node (specifying for which link this is not true). ExpectedNodeForLink(EntryLink), } @@ -50,7 +56,9 @@ impl std::fmt::Display for EntryLink { #[repr(C)] #[derive(Debug)] pub enum EntryKind { + /// Leaf entry. Leaf, + /// Node entry with children links. Node(EntryLink, EntryLink), } diff --git a/src/node_data.rs b/src/node_data.rs index 0adc0f2..a018daa 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -2,23 +2,36 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt, ByteOrder}; use bigint::U256; use blake2::Params as Blake2Params; +/// Maximum serialized size of the node metadata. pub const MAX_NODE_DATA_SIZE: usize = 32 + 4 + 4 + 4 + 4 + 32 + 32 + 32 + 9 + 9 + 9; // 171 /// Node metadata. #[repr(C)] #[derive(Debug, Clone, Default)] pub struct NodeData { + /// Consensus branch id, should be provided by deserializing node. pub consensus_branch_id: u32, + /// Subtree commitment - either block hash for leaves or hashsum of children for nodes. pub subtree_commitment: [u8; 32], + /// Start time. pub start_time: u32, + /// End time. pub end_time: u32, + /// Start target. pub start_target: u32, + /// End target. pub end_target: u32, + /// Start sapling tree root. pub start_sapling_root: [u8; 32], + /// End sapling tree root. pub end_sapling_root: [u8; 32], + /// Part of tree total work. pub subtree_total_work: U256, + /// Start height. pub start_height: u64, + /// End height pub end_height: u64, + /// Number of shielded transactions. pub shielded_tx: u64, } @@ -42,6 +55,7 @@ fn personalization(branch_id: u32) -> [u8; 16] { } impl NodeData { + /// Combine two nodes metadata. pub fn combine(left: &NodeData, right: &NodeData) -> NodeData { assert_eq!(left.consensus_branch_id, right.consensus_branch_id); @@ -106,6 +120,7 @@ impl NodeData { Ok(result) } + /// Write to the byte representation. pub fn write(&self, w: &mut W) -> std::io::Result<()> { w.write_all(&self.subtree_commitment)?; w.write_u32::(self.start_time)?; @@ -125,6 +140,7 @@ impl NodeData { Ok(()) } + /// Read from the byte representation. pub fn read(consensus_branch_id: u32, r: &mut R) -> std::io::Result { let mut data = Self::default(); data.consensus_branch_id = consensus_branch_id; @@ -147,6 +163,7 @@ impl NodeData { Ok(data) } + /// Convert to byte representation. pub fn to_bytes(&self) -> Vec { let mut buf = [0u8; MAX_NODE_DATA_SIZE]; let pos = { @@ -158,6 +175,7 @@ impl NodeData { buf[0..pos].to_vec() } + /// Convert from byte representation. pub fn from_bytes>(consensus_branch_id: u32, buf: T) -> std::io::Result { let mut cursor = std::io::Cursor::new(buf); Self::read(consensus_branch_id, &mut cursor) diff --git a/src/tree.rs b/src/tree.rs index b816287..8b65c52 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -24,6 +24,7 @@ pub struct Tree { } impl Tree { + /// Resolve link originated from this tree pub fn resolve_link(&self, link: EntryLink) -> Result { match link { EntryLink::Generated(index) => { @@ -80,6 +81,12 @@ impl Tree { } } + /// New view into the the tree array representation + /// + /// `length` is total length of the array representation + /// `peaks` is peaks of the mmr tree + /// `extra` is some extra nodes that calculated to be required during next one or more + /// operations on the tree. pub fn new( length: u32, peaks: Vec<(u32, Entry)>, @@ -267,6 +274,7 @@ impl Tree { } } +/// Reference to the node with link attached. #[derive(Debug)] pub struct IndexedNode<'a> { node: &'a Entry, @@ -283,14 +291,17 @@ impl<'a> IndexedNode<'a> { self.node.right().map_err(|e| e.augment(self.link)) } + /// Reference to the entry struct. pub fn node(&self) -> &Entry { self.node } + /// Reference to the entry metadata. pub fn data(&self) -> &NodeData { &self.node.data } + /// Actual link by what this node was resolved. pub fn link(&self) -> EntryLink { self.link } From 1eb4fb91f6ce68bf54e408f4a2737faa61473a0e Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 24 Sep 2019 13:15:35 +0200 Subject: [PATCH 219/330] add invariant about number of returned links --- src/tree.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tree.rs b/src/tree.rs index 8b65c52..4482cd8 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -142,6 +142,8 @@ impl Tree { /// Append one leaf to the tree. /// /// Returns links to actual nodes that has to be persisted as the result of the append. + /// If completed without error, at least one link to the appended + /// node (with metadata provided in `new_leaf`) will be returned. pub fn append_leaf(&mut self, new_leaf: NodeData) -> Result, Error> { let root = self.root; let new_leaf_link = self.push(new_leaf.into()); From 08806cc1097967e5b3a5f0f4f351e7ed4b579efb Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 24 Sep 2019 13:47:32 +0200 Subject: [PATCH 220/330] proper elapsed time calc --- examples/long.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/long.rs b/examples/long.rs index bb2f2d4..45e66c2 100644 --- a/examples/long.rs +++ b/examples/long.rs @@ -60,6 +60,7 @@ fn main() { let now = std::time::Instant::now(); let tree = prepare_tree(&long_vec); + let elapsed = now.elapsed(); println!("Tree final root: {}-{}", tree.root_node().expect("root").data().start_height, @@ -68,6 +69,6 @@ fn main() { println!("Prepare tree of {} length: {} ns / {} mcs / {} ms", number, - now.elapsed().as_nanos(), now.elapsed().as_micros(), now.elapsed().as_millis() + elapsed.as_nanos(), elapsed.as_micros(), elapsed.as_millis() ); } From 7f3036d2c8e78c9b93950e18e7edaa78110ef775 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 24 Sep 2019 10:53:52 +0100 Subject: [PATCH 221/330] Update READMEs --- bellman/README.md | 15 +++++++++++++-- ff/README.md | 15 +++++++++++---- group/README.md | 5 ++++- librustzcash/README.md | 9 +++++++-- pairing/README.md | 18 +++++++++++++++--- zcash_client_backend/README.md | 6 ++++-- zcash_primitives/README.md | 3 ++- zcash_proofs/README.md | 3 ++- 8 files changed, 58 insertions(+), 16 deletions(-) diff --git a/bellman/README.md b/bellman/README.md index 659a81c..d64dd9c 100644 --- a/bellman/README.md +++ b/bellman/README.md @@ -1,12 +1,23 @@ # bellman [![Crates.io](https://img.shields.io/crates/v/bellman.svg)](https://crates.io/crates/bellman) # -This is a research project being built for [Zcash](https://z.cash/). +`bellman` is a crate for building zk-SNARK circuits. It provides circuit traits +and primitive structures, as well as basic gadget implementations such as +booleans and number abstractions. + +## Roadmap + +`bellman` is being refactored into a generic proving library. Currently it is +pairing-specific, and different types of proving systems need to be implemented +as sub-modules. After the refactor, `bellman` will be generic using the `ff` and +`group` crates, while specific proving systems will be separate crates that pull +in the dependencies they require. ## License Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. diff --git a/ff/README.md b/ff/README.md index 3efef94..c3127d8 100644 --- a/ff/README.md +++ b/ff/README.md @@ -15,11 +15,15 @@ Add the `ff` crate to your `Cargo.toml`: ff = "0.4" ``` -The `ff` crate contains `Field`, `PrimeField`, `PrimeFieldRepr` and `SqrtField` traits. See the **[documentation](https://docs.rs/ff/0.4.0/ff/)** for more. +The `ff` crate contains `Field`, `PrimeField`, `PrimeFieldRepr` and `SqrtField` traits. +See the **[documentation](https://docs.rs/ff/)** for more. ### #![derive(PrimeField)] -If you need an implementation of a prime field, this library also provides a procedural macro that will expand into an efficient implementation of a prime field when supplied with the modulus. `PrimeFieldGenerator` must be an element of Fp of p-1 order, that is also quadratic nonresidue. +If you need an implementation of a prime field, this library also provides a procedural +macro that will expand into an efficient implementation of a prime field when supplied +with the modulus. `PrimeFieldGenerator` must be an element of Fp of p-1 order, that is +also quadratic nonresidue. First, enable the `derive` crate feature: @@ -41,13 +45,16 @@ extern crate ff; struct Fp(FpRepr); ``` -And that's it! `Fp` now implements `Field` and `PrimeField`. `Fp` will also implement `SqrtField` if supported. The library implements `FpRepr` itself and derives `PrimeFieldRepr` for it. +And that's it! `Fp` now implements `Field` and `PrimeField`. `Fp` will also implement +`SqrtField` if supported. The library implements `FpRepr` itself and derives +`PrimeFieldRepr` for it. ## License Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. diff --git a/group/README.md b/group/README.md index 7fadc0b..5c2398b 100644 --- a/group/README.md +++ b/group/README.md @@ -1,10 +1,13 @@ # group [![Crates.io](https://img.shields.io/crates/v/group.svg)](https://crates.io/crates/group) # +`group` is a crate for working with groups over elliptic curves. + ## License Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. diff --git a/librustzcash/README.md b/librustzcash/README.md index c21ca8e..0d6eeae 100644 --- a/librustzcash/README.md +++ b/librustzcash/README.md @@ -1,12 +1,17 @@ # librustzcash -This repository contains librustzcash, a static library for Zcash code assets written in Rust. +`librustzcash` is an FFI library crate that exposes the Zcash Rust components to +the `zcashd` full node. + +The FFI API does not have any stability guarantees, and will change as required +by `zcashd`. ## License Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * Apache License, Version 2.0, ([LICENSE-APACHE](../LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. diff --git a/pairing/README.md b/pairing/README.md index bf386de..47a25dc 100644 --- a/pairing/README.md +++ b/pairing/README.md @@ -1,6 +1,16 @@ # pairing [![Crates.io](https://img.shields.io/crates/v/pairing.svg)](https://crates.io/crates/pairing) # -This is a Rust crate for using pairing-friendly elliptic curves. Currently, only the [BLS12-381](https://z.cash/blog/new-snark-curve.html) construction is implemented. +`pairing` is a crate for using pairing-friendly elliptic curves. + +Currently, only the [BLS12-381](https://z.cash/blog/new-snark-curve.html) +construction is implemented. + +## Roadmap + +`pairing` is being refactored into a generic library for working with +pairing-friendly curves. After the refactor, `pairing` will provide basic traits +for pairing-friendly elliptic curve constructions, while specific curves will be +in separate crates. ## [Documentation](https://docs.rs/pairing/) @@ -8,13 +18,15 @@ Bring the `pairing` crate into your project just as you normally would. ## Security Warnings -This library does not make any guarantees about constant-time operations, memory access patterns, or resistance to side-channel attacks. +This library does not make any guarantees about constant-time operations, memory +access patterns, or resistance to side-channel attacks. ## License Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. diff --git a/zcash_client_backend/README.md b/zcash_client_backend/README.md index da5c9e2..af9a7ff 100644 --- a/zcash_client_backend/README.md +++ b/zcash_client_backend/README.md @@ -1,12 +1,14 @@ # zcash_client_backend -This library contains Rust structs and traits for creating shielded Zcash light clients. +This library contains Rust structs and traits for creating shielded Zcash light +clients. ## License Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. diff --git a/zcash_primitives/README.md b/zcash_primitives/README.md index b284820..02a0c33 100644 --- a/zcash_primitives/README.md +++ b/zcash_primitives/README.md @@ -6,7 +6,8 @@ This library contains Rust implementations of the Zcash primitives. Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. diff --git a/zcash_proofs/README.md b/zcash_proofs/README.md index 92d9c77..f365c5a 100644 --- a/zcash_proofs/README.md +++ b/zcash_proofs/README.md @@ -7,7 +7,8 @@ and verifying proofs. Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. From 4ad3988e432d25fbfc44998f9dad1b17f23383f2 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 24 Sep 2019 10:54:15 +0100 Subject: [PATCH 222/330] Crate docs --- bellman/src/domain.rs | 21 +-- bellman/src/gadgets.rs | 2 + bellman/src/gadgets/blake2s.rs | 4 + bellman/src/gadgets/boolean.rs | 2 + bellman/src/gadgets/lookup.rs | 2 + bellman/src/gadgets/multipack.rs | 2 + bellman/src/gadgets/num.rs | 2 + bellman/src/gadgets/sha256.rs | 5 + bellman/src/gadgets/test/mod.rs | 2 + bellman/src/gadgets/uint32.rs | 3 + bellman/src/groth16/mod.rs | 4 + bellman/src/lib.rs | 134 ++++++++++++++++++ bellman/src/multicore.rs | 11 +- ff/src/lib.rs | 2 + pairing/src/bls12_381/mod.rs | 3 + pairing/src/lib.rs | 2 + zcash_client_backend/src/constants/mainnet.rs | 2 + zcash_client_backend/src/constants/testnet.rs | 2 + zcash_primitives/src/block.rs | 2 + zcash_primitives/src/block/equihash.rs | 4 + zcash_primitives/src/constants.rs | 2 + zcash_primitives/src/group_hash.rs | 4 + zcash_primitives/src/jubjub/mod.rs | 6 + zcash_primitives/src/keys.rs | 4 +- zcash_primitives/src/lib.rs | 5 + zcash_primitives/src/pedersen_hash.rs | 2 + zcash_primitives/src/primitives.rs | 2 + zcash_primitives/src/redjubjub.rs | 6 +- .../src/transaction/components.rs | 2 + zcash_primitives/src/transaction/mod.rs | 2 + zcash_primitives/src/zip32.rs | 4 + zcash_proofs/src/circuit.rs | 2 + zcash_proofs/src/circuit/ecc.rs | 2 + zcash_proofs/src/circuit/pedersen_hash.rs | 2 + zcash_proofs/src/circuit/sapling.rs | 2 + zcash_proofs/src/circuit/sprout/mod.rs | 12 ++ zcash_proofs/src/lib.rs | 5 + zcash_proofs/src/sapling/mod.rs | 2 + 38 files changed, 259 insertions(+), 18 deletions(-) diff --git a/bellman/src/domain.rs b/bellman/src/domain.rs index c636855..ddba4f4 100644 --- a/bellman/src/domain.rs +++ b/bellman/src/domain.rs @@ -1,14 +1,15 @@ -//! This module contains an `EvaluationDomain` abstraction for -//! performing various kinds of polynomial arithmetic on top of -//! the scalar field. +//! This module contains an [`EvaluationDomain`] abstraction for performing +//! various kinds of polynomial arithmetic on top of the scalar field. //! -//! In pairing-based SNARKs like Groth16, we need to calculate -//! a quotient polynomial over a target polynomial with roots -//! at distinct points associated with each constraint of the -//! constraint system. In order to be efficient, we choose these -//! roots to be the powers of a 2^n root of unity in the field. -//! This allows us to perform polynomial operations in O(n) -//! by performing an O(n log n) FFT over such a domain. +//! In pairing-based SNARKs like [Groth16], we need to calculate a quotient +//! polynomial over a target polynomial with roots at distinct points associated +//! with each constraint of the constraint system. In order to be efficient, we +//! choose these roots to be the powers of a 2n root of unity in the +//! field. This allows us to perform polynomial operations in O(n) by performing +//! an O(n log n) FFT over such a domain. +//! +//! [`EvaluationDomain`]: crate::domain::EvaluationDomain +//! [Groth16]: https://eprint.iacr.org/2016/260 use ff::{Field, PrimeField, ScalarEngine}; use group::CurveProjective; diff --git a/bellman/src/gadgets.rs b/bellman/src/gadgets.rs index cf366df..b0ce734 100644 --- a/bellman/src/gadgets.rs +++ b/bellman/src/gadgets.rs @@ -1,3 +1,5 @@ +//! Self-contained sub-circuit implementations for various primitives. + pub mod test; pub mod blake2s; diff --git a/bellman/src/gadgets/blake2s.rs b/bellman/src/gadgets/blake2s.rs index 96e554b..e98fd55 100644 --- a/bellman/src/gadgets/blake2s.rs +++ b/bellman/src/gadgets/blake2s.rs @@ -1,3 +1,7 @@ +//! The [BLAKE2s] hash function with personalization support. +//! +//! [BLAKE2s]: https://tools.ietf.org/html/rfc7693 + use super::{boolean::Boolean, multieq::MultiEq, uint32::UInt32}; use crate::{ConstraintSystem, SynthesisError}; use ff::ScalarEngine; diff --git a/bellman/src/gadgets/boolean.rs b/bellman/src/gadgets/boolean.rs index bbc0d30..e08974d 100644 --- a/bellman/src/gadgets/boolean.rs +++ b/bellman/src/gadgets/boolean.rs @@ -1,3 +1,5 @@ +//! Gadgets for allocating bits in the circuit and performing boolean logic. + use ff::{BitIterator, Field, PrimeField, ScalarEngine}; use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; diff --git a/bellman/src/gadgets/lookup.rs b/bellman/src/gadgets/lookup.rs index 8124b22..b83844d 100644 --- a/bellman/src/gadgets/lookup.rs +++ b/bellman/src/gadgets/lookup.rs @@ -1,3 +1,5 @@ +//! Window table lookup gadgets. + use ff::{Field, ScalarEngine}; use super::boolean::Boolean; diff --git a/bellman/src/gadgets/multipack.rs b/bellman/src/gadgets/multipack.rs index 1fa1967..c0dc50e 100644 --- a/bellman/src/gadgets/multipack.rs +++ b/bellman/src/gadgets/multipack.rs @@ -1,3 +1,5 @@ +//! Helpers for packing vectors of bits into scalar field elements. + use super::boolean::Boolean; use super::num::Num; use super::Assignment; diff --git a/bellman/src/gadgets/num.rs b/bellman/src/gadgets/num.rs index b7caf6d..8be5448 100644 --- a/bellman/src/gadgets/num.rs +++ b/bellman/src/gadgets/num.rs @@ -1,3 +1,5 @@ +//! Gadgets representing numbers in the scalar field of the underlying curve. + use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, ScalarEngine}; use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; diff --git a/bellman/src/gadgets/sha256.rs b/bellman/src/gadgets/sha256.rs index a875513..0c8efea 100644 --- a/bellman/src/gadgets/sha256.rs +++ b/bellman/src/gadgets/sha256.rs @@ -1,3 +1,8 @@ +//! Circuits for the [SHA-256] hash function and its internal compression +//! function. +//! +//! [SHA-256]: https://tools.ietf.org/html/rfc6234 + use super::boolean::Boolean; use super::multieq::MultiEq; use super::uint32::UInt32; diff --git a/bellman/src/gadgets/test/mod.rs b/bellman/src/gadgets/test/mod.rs index fedfe94..47392f1 100644 --- a/bellman/src/gadgets/test/mod.rs +++ b/bellman/src/gadgets/test/mod.rs @@ -1,3 +1,5 @@ +//! Helpers for testing circuit implementations. + use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; diff --git a/bellman/src/gadgets/uint32.rs b/bellman/src/gadgets/uint32.rs index cf8e390..a10be6c 100644 --- a/bellman/src/gadgets/uint32.rs +++ b/bellman/src/gadgets/uint32.rs @@ -1,3 +1,6 @@ +//! Circuit representation of a [`u32`], with helpers for the [`sha256`] +//! gadgets. + use ff::{Field, PrimeField, ScalarEngine}; use crate::{ConstraintSystem, LinearCombination, SynthesisError}; diff --git a/bellman/src/groth16/mod.rs b/bellman/src/groth16/mod.rs index 44c6f22..1ff152d 100644 --- a/bellman/src/groth16/mod.rs +++ b/bellman/src/groth16/mod.rs @@ -1,3 +1,7 @@ +//! The [Groth16] proving system. +//! +//! [Groth16]: https://eprint.iacr.org/2016/260 + use group::{CurveAffine, EncodedPoint}; use pairing::{Engine, PairingCurveAffine}; diff --git a/bellman/src/lib.rs b/bellman/src/lib.rs index 5152b0f..a3b577b 100644 --- a/bellman/src/lib.rs +++ b/bellman/src/lib.rs @@ -1,3 +1,137 @@ +//! `bellman` is a crate for building zk-SNARK circuits. It provides circuit +//! traits and and primitive structures, as well as basic gadget implementations +//! such as booleans and number abstractions. +//! +//! # Example circuit +//! +//! Say we want to write a circuit that proves we know the preimage to some hash +//! computed using SHA-256d (calling SHA-256 twice). The preimage must have a +//! fixed length known in advance (because the circuit parameters will depend on +//! it), but can otherwise have any value. We take the following strategy: +//! +//! - Witness each bit of the preimage. +//! - Compute `hash = SHA-256d(preimage)` inside the circuit. +//! - Expose `hash` as a public input using multiscalar packing. +//! +//! ``` +//! use bellman::{ +//! gadgets::{ +//! boolean::{AllocatedBit, Boolean}, +//! multipack, +//! sha256::sha256, +//! }, +//! groth16, Circuit, ConstraintSystem, SynthesisError, +//! }; +//! use pairing::{bls12_381::Bls12, Engine}; +//! use rand::rngs::OsRng; +//! use sha2::{Digest, Sha256}; +//! +//! /// Our own SHA-256d gadget. Input and output are in little-endian bit order. +//! fn sha256d>( +//! mut cs: CS, +//! data: &[Boolean], +//! ) -> Result, SynthesisError> { +//! // Flip endianness of each input byte +//! let input: Vec<_> = data +//! .chunks(8) +//! .map(|c| c.iter().rev()) +//! .flatten() +//! .cloned() +//! .collect(); +//! +//! let mid = sha256(cs.namespace(|| "SHA-256(input)"), &input)?; +//! let res = sha256(cs.namespace(|| "SHA-256(mid)"), &mid)?; +//! +//! // Flip endianness of each output byte +//! Ok(res +//! .chunks(8) +//! .map(|c| c.iter().rev()) +//! .flatten() +//! .cloned() +//! .collect()) +//! } +//! +//! struct MyCircuit { +//! /// The input to SHA-256d we are proving that we know. Set to `None` when we +//! /// are verifying a proof (and do not have the witness data). +//! preimage: Option<[u8; 80]>, +//! } +//! +//! impl Circuit for MyCircuit { +//! fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { +//! // Compute the values for the bits of the preimage. If we are verifying a proof, +//! // we still need to create the same constraints, so we return an equivalent-size +//! // Vec of None (indicating that the value of each bit is unknown). +//! let bit_values = if let Some(preimage) = self.preimage { +//! preimage +//! .into_iter() +//! .map(|byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8)) +//! .flatten() +//! .map(|b| Some(b)) +//! .collect() +//! } else { +//! vec![None; 80 * 8] +//! }; +//! assert_eq!(bit_values.len(), 80 * 8); +//! +//! // Witness the bits of the preimage. +//! let preimage_bits = bit_values +//! .into_iter() +//! .enumerate() +//! // Allocate each bit. +//! .map(|(i, b)| { +//! AllocatedBit::alloc(cs.namespace(|| format!("preimage bit {}", i)), b) +//! }) +//! // Convert the AllocatedBits into Booleans (required for the sha256 gadget). +//! .map(|b| b.map(Boolean::from)) +//! .collect::, _>>()?; +//! +//! // Compute hash = SHA-256d(preimage). +//! let hash = sha256d(cs.namespace(|| "SHA-256d(preimage)"), &preimage_bits)?; +//! +//! // Expose the vector of 32 boolean variables as compact public inputs. +//! multipack::pack_into_inputs(cs.namespace(|| "pack hash"), &hash) +//! } +//! } +//! +//! // Create parameters for our circuit. In a production deployment these would +//! // be generated securely using a multiparty computation. +//! let params = { +//! let c = MyCircuit { preimage: None }; +//! groth16::generate_random_parameters::(c, &mut OsRng).unwrap() +//! }; +//! +//! // Prepare the verification key (for proof verification). +//! let pvk = groth16::prepare_verifying_key(¶ms.vk); +//! +//! // Pick a preimage and compute its hash. +//! let preimage = [42; 80]; +//! let hash = Sha256::digest(&Sha256::digest(&preimage)); +//! +//! // Create an instance of our circuit (with the preimage as a witness). +//! let c = MyCircuit { +//! preimage: Some(preimage), +//! }; +//! +//! // Create a Groth16 proof with our parameters. +//! let proof = groth16::create_random_proof(c, ¶ms, &mut OsRng).unwrap(); +//! +//! // Pack the hash as inputs for proof verification. +//! let hash_bits = multipack::bytes_to_bits_le(&hash); +//! let inputs = multipack::compute_multipacking::(&hash_bits); +//! +//! // Check the proof! +//! assert!(groth16::verify_proof(&pvk, &proof, &inputs).unwrap()); +//! ``` +//! +//! # Roadmap +//! +//! `bellman` is being refactored into a generic proving library. Currently it +//! is pairing-specific, and different types of proving systems need to be +//! implemented as sub-modules. After the refactor, `bellman` will be generic +//! using the [`ff`] and [`group`] crates, while specific proving systems will +//! be separate crates that pull in the dependencies they require. + // Catch documentation errors caused by code changes. #![deny(intra_doc_link_resolution_failure)] diff --git a/bellman/src/multicore.rs b/bellman/src/multicore.rs index ff97e06..ba69b5f 100644 --- a/bellman/src/multicore.rs +++ b/bellman/src/multicore.rs @@ -1,8 +1,9 @@ -//! This is an interface for dealing with the kinds of -//! parallel computations involved in bellman. It's -//! currently just a thin wrapper around CpuPool and -//! crossbeam but may be extended in the future to -//! allow for various parallelism strategies. +//! An interface for dealing with the kinds of parallel computations involved in +//! `bellman`. It's currently just a thin wrapper around [`CpuPool`] and +//! [`crossbeam`] but may be extended in the future to allow for various +//! parallelism strategies. +//! +//! [`CpuPool`]: futures_cpupool::CpuPool #[cfg(feature = "multicore")] mod implementation { diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 456cbc1..6be25da 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -1,3 +1,5 @@ +//! This crate provides traits for working with finite fields. + // Catch documentation errors caused by code changes. #![deny(intra_doc_link_resolution_failure)] #![allow(unused_imports)] diff --git a/pairing/src/bls12_381/mod.rs b/pairing/src/bls12_381/mod.rs index 8fc6bbd..e6e88dd 100644 --- a/pairing/src/bls12_381/mod.rs +++ b/pairing/src/bls12_381/mod.rs @@ -1,3 +1,6 @@ +//! An implementation of the BLS12-381 pairing-friendly elliptic curve +//! construction. + mod ec; mod fq; mod fq12; diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs index 9f20a88..89e5873 100644 --- a/pairing/src/lib.rs +++ b/pairing/src/lib.rs @@ -1,3 +1,5 @@ +//! A library for working with pairing-friendly curves. + // `clippy` is a code linting tool for improving code quality by catching // common mistakes or strange code patterns. If the `cargo-clippy` feature // is provided, all compiler warnings are prohibited. diff --git a/zcash_client_backend/src/constants/mainnet.rs b/zcash_client_backend/src/constants/mainnet.rs index 24dbbe7..f3f020d 100644 --- a/zcash_client_backend/src/constants/mainnet.rs +++ b/zcash_client_backend/src/constants/mainnet.rs @@ -1,3 +1,5 @@ +//! Constants for the Zcash main network. + /// The mainnet coin type for ZEC, as defined by [SLIP 44]. /// /// [SLIP 44]: https://github.com/satoshilabs/slips/blob/master/slip-0044.md diff --git a/zcash_client_backend/src/constants/testnet.rs b/zcash_client_backend/src/constants/testnet.rs index a83706e..5379d5a 100644 --- a/zcash_client_backend/src/constants/testnet.rs +++ b/zcash_client_backend/src/constants/testnet.rs @@ -1,3 +1,5 @@ +//! Constants for the Zcash test network. + /// The testnet coin type for ZEC, as defined by [SLIP 44]. /// /// [SLIP 44]: https://github.com/satoshilabs/slips/blob/master/slip-0044.md diff --git a/zcash_primitives/src/block.rs b/zcash_primitives/src/block.rs index 28a7441..ecb0e5b 100644 --- a/zcash_primitives/src/block.rs +++ b/zcash_primitives/src/block.rs @@ -1,3 +1,5 @@ +//! Structs and methods for handling Zcash block headers. + use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use hex; use std::fmt; diff --git a/zcash_primitives/src/block/equihash.rs b/zcash_primitives/src/block/equihash.rs index 2a3bb66..5d40465 100644 --- a/zcash_primitives/src/block/equihash.rs +++ b/zcash_primitives/src/block/equihash.rs @@ -1,3 +1,7 @@ +//! Verification functions for the [Equihash] proof-of-work algorithm. +//! +//! [Equihash]: https://zips.z.cash/protocol/protocol.pdf#equihash + use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams, State as Blake2bState}; use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; use log::error; diff --git a/zcash_primitives/src/constants.rs b/zcash_primitives/src/constants.rs index 39d55f3..37d337d 100644 --- a/zcash_primitives/src/constants.rs +++ b/zcash_primitives/src/constants.rs @@ -1,3 +1,5 @@ +//! Various constants used by the Zcash primitives. + /// First 64 bytes of the BLAKE2s input during group hash. /// This is chosen to be some random string that we couldn't have anticipated when we designed /// the algorithm, for rigidity purposes. diff --git a/zcash_primitives/src/group_hash.rs b/zcash_primitives/src/group_hash.rs index 8549c5e..6aac847 100644 --- a/zcash_primitives/src/group_hash.rs +++ b/zcash_primitives/src/group_hash.rs @@ -1,3 +1,7 @@ +//! Implementation of [group hashing into Jubjub][grouphash]. +//! +//! [grouphash]: https://zips.z.cash/protocol/protocol.pdf#concretegrouphashjubjub + use crate::jubjub::{edwards, JubjubEngine, PrimeOrder}; use ff::PrimeField; diff --git a/zcash_primitives/src/jubjub/mod.rs b/zcash_primitives/src/jubjub/mod.rs index 40938f3..4998a0b 100644 --- a/zcash_primitives/src/jubjub/mod.rs +++ b/zcash_primitives/src/jubjub/mod.rs @@ -1,3 +1,6 @@ +//! The [Jubjub] curve for efficient elliptic curve operations in circuits built +//! over [BLS12-381]. +//! //! Jubjub is a twisted Edwards curve defined over the BLS12-381 scalar //! field, Fr. It takes the form `-x^2 + y^2 = 1 + dx^2y^2` with //! `d = -(10240/10241)`. It is birationally equivalent to a Montgomery @@ -16,6 +19,9 @@ //! It is a complete twisted Edwards curve, so the equivalence with //! the Montgomery curve forms a group isomorphism, allowing points //! to be freely converted between the two forms. +//! +//! [Jubjub]: https://zips.z.cash/protocol/protocol.pdf#jubjub +//! [BLS12-381]: pairing::bls12_381 use ff::{Field, PrimeField, SqrtField}; use pairing::Engine; diff --git a/zcash_primitives/src/keys.rs b/zcash_primitives/src/keys.rs index 8c8a4b1..76914ba 100644 --- a/zcash_primitives/src/keys.rs +++ b/zcash_primitives/src/keys.rs @@ -1,6 +1,8 @@ //! Sapling key components. //! -//! Implements section 4.2.2 of the Zcash Protocol Specification. +//! Implements [section 4.2.2] of the Zcash Protocol Specification. +//! +//! [section 4.2.2]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents use crate::{ jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, ToUniform, Unknown}, diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index e8c2a51..713ca2b 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -1,3 +1,8 @@ +//! *General Zcash primitives.* +//! +//! `zcash_primitives` is a library that provides the core structs and functions necessary +//! for working with Zcash. + // Catch documentation errors caused by code changes. #![deny(intra_doc_link_resolution_failure)] diff --git a/zcash_primitives/src/pedersen_hash.rs b/zcash_primitives/src/pedersen_hash.rs index 835e9c7..690e977 100644 --- a/zcash_primitives/src/pedersen_hash.rs +++ b/zcash_primitives/src/pedersen_hash.rs @@ -1,3 +1,5 @@ +//! Implementation of the Pedersen hash function used in Sapling. + use crate::jubjub::*; use ff::{Field, PrimeField, PrimeFieldRepr}; diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs index a336673..af4fa3a 100644 --- a/zcash_primitives/src/primitives.rs +++ b/zcash_primitives/src/primitives.rs @@ -1,3 +1,5 @@ +//! Structs for core Zcash primitives. + use ff::{Field, PrimeField, PrimeFieldRepr}; use crate::constants; diff --git a/zcash_primitives/src/redjubjub.rs b/zcash_primitives/src/redjubjub.rs index 6721b5e..187ebd3 100644 --- a/zcash_primitives/src/redjubjub.rs +++ b/zcash_primitives/src/redjubjub.rs @@ -1,5 +1,7 @@ -//! Implementation of RedJubjub, a specialization of RedDSA to the Jubjub curve. -//! See section 5.4.6 of the Sapling protocol specification. +//! Implementation of [RedJubjub], a specialization of RedDSA to the Jubjub +//! curve. +//! +//! [RedJubjub]: https://zips.z.cash/protocol/protocol.pdf#concretereddsa use crate::jubjub::{edwards::Point, FixedGenerators, JubjubEngine, JubjubParams, Unknown}; use ff::{Field, PrimeField, PrimeFieldRepr}; diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index c0410c4..270bac5 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -1,3 +1,5 @@ +//! Structs representing the components within Zcash transactions. + use crate::jubjub::{edwards, Unknown}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use ff::{PrimeField, PrimeFieldRepr}; diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index 10e935b..4c203c5 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -1,3 +1,5 @@ +//! Structs and methods for handling Zcash transactions. + use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use hex; use sha2::{Digest, Sha256}; diff --git a/zcash_primitives/src/zip32.rs b/zcash_primitives/src/zip32.rs index 6cbc462..f346625 100644 --- a/zcash_primitives/src/zip32.rs +++ b/zcash_primitives/src/zip32.rs @@ -1,3 +1,7 @@ +//! Implementation of [ZIP 32] for hierarchical deterministic key management. +//! +//! [ZIP 32]: https://zips.z.cash/zip-0032 + use aes::Aes256; use blake2b_simd::Params as Blake2bParams; use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt}; diff --git a/zcash_proofs/src/circuit.rs b/zcash_proofs/src/circuit.rs index ac7e74c..6d26fa4 100644 --- a/zcash_proofs/src/circuit.rs +++ b/zcash_proofs/src/circuit.rs @@ -1,3 +1,5 @@ +//! Implementations of the Zcash circuits and Zcash-specific gadgets. + pub mod ecc; pub mod pedersen_hash; diff --git a/zcash_proofs/src/circuit/ecc.rs b/zcash_proofs/src/circuit/ecc.rs index fa4913a..e65d0ed 100644 --- a/zcash_proofs/src/circuit/ecc.rs +++ b/zcash_proofs/src/circuit/ecc.rs @@ -1,3 +1,5 @@ +//! Gadgets implementing Jubjub elliptic curve operations. + use ff::Field; use pairing::Engine; diff --git a/zcash_proofs/src/circuit/pedersen_hash.rs b/zcash_proofs/src/circuit/pedersen_hash.rs index 409f30e..15cc0c9 100644 --- a/zcash_proofs/src/circuit/pedersen_hash.rs +++ b/zcash_proofs/src/circuit/pedersen_hash.rs @@ -1,3 +1,5 @@ +//! Gadget for Zcash's Pedersen hash. + use super::ecc::{EdwardsPoint, MontgomeryPoint}; use bellman::gadgets::boolean::Boolean; use bellman::gadgets::lookup::*; diff --git a/zcash_proofs/src/circuit/sapling.rs b/zcash_proofs/src/circuit/sapling.rs index 08e55e6..aa4b7c8 100644 --- a/zcash_proofs/src/circuit/sapling.rs +++ b/zcash_proofs/src/circuit/sapling.rs @@ -1,3 +1,5 @@ +//! The Sapling circuits. + use ff::{Field, PrimeField, PrimeFieldRepr}; use bellman::{Circuit, ConstraintSystem, SynthesisError}; diff --git a/zcash_proofs/src/circuit/sprout/mod.rs b/zcash_proofs/src/circuit/sprout/mod.rs index 959ec78..1877047 100644 --- a/zcash_proofs/src/circuit/sprout/mod.rs +++ b/zcash_proofs/src/circuit/sprout/mod.rs @@ -1,3 +1,15 @@ +//! The "hybrid Sprout" circuit. +//! +//! "Hybrid Sprout" refers to the implementation of the [Sprout statement] in +//! `bellman` for [`groth16`], instead of the [original implementation][oldimpl] +//! using [`libsnark`] for [BCTV14]. +//! +//! [Sprout statement]: https://zips.z.cash/protocol/protocol.pdf#joinsplitstatement +//! [`groth16`]: bellman::groth16 +//! [oldimpl]: https://github.com/zcash/zcash/tree/v2.0.7/src/zcash/circuit +//! [`libsnark`]: https://github.com/scipr-lab/libsnark +//! [BCTV14]: https://eprint.iacr.org/2013/879 + use bellman::gadgets::boolean::{AllocatedBit, Boolean}; use bellman::gadgets::multipack::pack_into_inputs; use bellman::{Circuit, ConstraintSystem, LinearCombination, SynthesisError}; diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs index a323cc3..0a1f9f2 100644 --- a/zcash_proofs/src/lib.rs +++ b/zcash_proofs/src/lib.rs @@ -1,3 +1,8 @@ +//! *Zcash circuits and proofs.* +//! +//! `zcash_proofs` contains the zk-SNARK circuits used by Zcash, and the APIs for creating +//! and verifying proofs. + // Catch documentation errors caused by code changes. #![deny(intra_doc_link_resolution_failure)] diff --git a/zcash_proofs/src/sapling/mod.rs b/zcash_proofs/src/sapling/mod.rs index 9aa62f1..60ffd9b 100644 --- a/zcash_proofs/src/sapling/mod.rs +++ b/zcash_proofs/src/sapling/mod.rs @@ -1,3 +1,5 @@ +//! Helpers for creating Sapling proofs. + use pairing::bls12_381::Bls12; use zcash_primitives::jubjub::{ edwards, fs::FsRepr, FixedGenerators, JubjubBls12, JubjubParams, Unknown, From 43efdf992b3a135b8016122db6500d54377573de Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 24 Sep 2019 15:28:34 +0200 Subject: [PATCH 223/330] prepare tree for deleting also --- examples/long.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/examples/long.rs b/examples/long.rs index 45e66c2..85f2c13 100644 --- a/examples/long.rs +++ b/examples/long.rs @@ -12,6 +12,10 @@ fn prepare_tree(vec: &Vec) -> Tree { let mut peak_pos = (1 << (h+1)) - 1; let mut nodes = Vec::new(); + // used later + let mut last_peak_pos = 0; + let mut last_peak_h = 0; + loop { if peak_pos > vec.len() { @@ -22,17 +26,22 @@ fn prepare_tree(vec: &Vec) -> Tree { if peak_pos <= vec.len() { let mut peak: Entry = vec[peak_pos-1].clone().into(); - let left_idx = (peak_pos - (1<) -> Tree { } } - Tree::new(vec.len() as u32, nodes, vec![]) + // for deletion, everything on the right slope of the last peak should be pre-loaded + let mut extra = Vec::new(); + let mut h = last_peak_h; + let mut peak_pos = last_peak_pos; + + while h > 0 { + let left_pos = peak_pos - (1< Date: Tue, 24 Sep 2019 17:47:10 +0100 Subject: [PATCH 224/330] Unit tests for key encodings Closes #119. --- zcash_client_backend/src/encoding.rs | 86 +++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/zcash_client_backend/src/encoding.rs b/zcash_client_backend/src/encoding.rs index 4e38995..01add4c 100644 --- a/zcash_client_backend/src/encoding.rs +++ b/zcash_client_backend/src/encoding.rs @@ -183,11 +183,95 @@ mod tests { use zcash_primitives::{ jubjub::edwards, primitives::{Diversifier, PaymentAddress}, + zip32::ExtendedSpendingKey, }; - use super::{decode_payment_address, encode_payment_address}; + use super::{ + decode_extended_full_viewing_key, decode_extended_spending_key, decode_payment_address, + encode_extended_full_viewing_key, encode_extended_spending_key, encode_payment_address, + }; use crate::constants; + #[test] + fn extended_spending_key() { + let extsk = ExtendedSpendingKey::master(&[0; 32][..]); + + let encoded_main = "secret-extended-key-main1qqqqqqqqqqqqqq8n3zjjmvhhr854uy3qhpda3ml34haf0x388z5r7h4st4kpsf6qysqws3xh6qmha7gna72fs2n4clnc9zgyd22s658f65pex4exe56qjk5pqj9vfdq7dfdhjc2rs9jdwq0zl99uwycyrxzp86705rk687spn44e2uhm7h0hsagfvkk4n7n6nfer6u57v9cac84t7nl2zth0xpyfeg0w2p2wv2yn6jn923aaz0vdaml07l60ahapk6efchyxwysrvjs87qvlj"; + let encoded_test = "secret-extended-key-test1qqqqqqqqqqqqqq8n3zjjmvhhr854uy3qhpda3ml34haf0x388z5r7h4st4kpsf6qysqws3xh6qmha7gna72fs2n4clnc9zgyd22s658f65pex4exe56qjk5pqj9vfdq7dfdhjc2rs9jdwq0zl99uwycyrxzp86705rk687spn44e2uhm7h0hsagfvkk4n7n6nfer6u57v9cac84t7nl2zth0xpyfeg0w2p2wv2yn6jn923aaz0vdaml07l60ahapk6efchyxwysrvjsvzyw8j"; + + assert_eq!( + encode_extended_spending_key( + constants::mainnet::HRP_SAPLING_EXTENDED_SPENDING_KEY, + &extsk + ), + encoded_main + ); + assert_eq!( + decode_extended_spending_key( + constants::mainnet::HRP_SAPLING_EXTENDED_SPENDING_KEY, + encoded_main + ) + .unwrap(), + Some(extsk.clone()) + ); + + assert_eq!( + encode_extended_spending_key( + constants::testnet::HRP_SAPLING_EXTENDED_SPENDING_KEY, + &extsk + ), + encoded_test + ); + assert_eq!( + decode_extended_spending_key( + constants::testnet::HRP_SAPLING_EXTENDED_SPENDING_KEY, + encoded_test + ) + .unwrap(), + Some(extsk) + ); + } + + #[test] + fn extended_full_viewing_key() { + let extfvk = (&ExtendedSpendingKey::master(&[0; 32][..])).into(); + + let encoded_main = "zxviews1qqqqqqqqqqqqqq8n3zjjmvhhr854uy3qhpda3ml34haf0x388z5r7h4st4kpsf6qy3zw4wc246aw9rlfyg5ndlwvne7mwdq0qe6vxl42pqmcf8pvmmd5slmjxduqa9evgej6wa3th2505xq4nggrxdm93rxk4rpdjt5nmq2vn44e2uhm7h0hsagfvkk4n7n6nfer6u57v9cac84t7nl2zth0xpyfeg0w2p2wv2yn6jn923aaz0vdaml07l60ahapk6efchyxwysrvjsxmansf"; + let encoded_test = "zxviewtestsapling1qqqqqqqqqqqqqq8n3zjjmvhhr854uy3qhpda3ml34haf0x388z5r7h4st4kpsf6qy3zw4wc246aw9rlfyg5ndlwvne7mwdq0qe6vxl42pqmcf8pvmmd5slmjxduqa9evgej6wa3th2505xq4nggrxdm93rxk4rpdjt5nmq2vn44e2uhm7h0hsagfvkk4n7n6nfer6u57v9cac84t7nl2zth0xpyfeg0w2p2wv2yn6jn923aaz0vdaml07l60ahapk6efchyxwysrvjs8evfkz"; + + assert_eq!( + encode_extended_full_viewing_key( + constants::mainnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, + &extfvk + ), + encoded_main + ); + assert_eq!( + decode_extended_full_viewing_key( + constants::mainnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, + encoded_main + ) + .unwrap(), + Some(extfvk.clone()) + ); + + assert_eq!( + encode_extended_full_viewing_key( + constants::testnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, + &extfvk + ), + encoded_test + ); + assert_eq!( + decode_extended_full_viewing_key( + constants::testnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, + encoded_test + ) + .unwrap(), + Some(extfvk) + ); + } + #[test] fn payment_address() { let rng = &mut XorShiftRng::from_seed([ From 443f45f4306c104ce1a9e5c02b3eb6b7fb070168 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 25 Sep 2019 09:50:59 +0200 Subject: [PATCH 225/330] dry example a bit and reduce api --- examples/long.rs | 55 +++++++++++++++++------------------------------- src/entry.rs | 18 +++++++++++++--- 2 files changed, 34 insertions(+), 39 deletions(-) diff --git a/examples/long.rs b/examples/long.rs index 85f2c13..951d226 100644 --- a/examples/long.rs +++ b/examples/long.rs @@ -3,6 +3,22 @@ use zcash_mmr::{Entry, EntryLink, NodeData, Tree}; #[path= "lib/shared.rs"] mod share; +fn draft(into: &mut Vec<(u32, Entry)>, vec: &Vec, peak_pos: usize, h: u32) { + let node_data = vec[peak_pos-1].clone(); + let peak: Entry = match h { + 0 => node_data.into(), + _ => Entry::new( + node_data, + EntryLink::Stored((peak_pos - (1 << h) - 1) as u32), + EntryLink::Stored((peak_pos - 2) as u32), + ), + }; + + println!("Entry #{}: {}", into.len(), peak); + + into.push(((peak_pos-1) as u32, peak)); +} + fn prepare_tree(vec: &Vec) -> Tree { assert!(vec.len() > 0); @@ -25,19 +41,7 @@ fn prepare_tree(vec: &Vec) -> Tree { } if peak_pos <= vec.len() { - let mut peak: Entry = vec[peak_pos-1].clone().into(); - if h != 0 { - let left_idx = (peak_pos - (1<) -> Tree { h = h - 1; // drafting left child - let mut peak: Entry = vec[left_pos-1].clone().into(); - if h != 0 { - let left_idx = (left_pos - (1<) -> Tree { println!("Total extra of {} required for deletion!", extra.len()); - Tree::new(vec.len() as u32, nodes, extra) } diff --git a/src/entry.rs b/src/entry.rs index 04490b3..b208555 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -13,9 +13,12 @@ pub struct Entry { } impl Entry { - /// Update siblings of the entry (to promote it from leaf to node) - pub fn update_siblings(&mut self, left: EntryLink, right: EntryLink) { - self.kind = EntryKind::Node(left, right); + /// New entry of type node. + pub fn new(data: NodeData, left: EntryLink, right: EntryLink) -> Self { + Entry { + kind: EntryKind::Node(left, right), + data, + } } /// Returns if is this node complete (has total of 2^N leaves) @@ -107,3 +110,12 @@ impl From for Entry { Entry { kind: EntryKind::Leaf, data: s } } } + +impl std::fmt::Display for Entry { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.kind { + EntryKind::Node(l, r) => write!(f, "node({}, {}, ..)", l, r), + EntryKind::Leaf => write!(f, "leaf(..)"), + } + } +} From da0d0a669a049109ee96354072ebc86a116bce25 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 25 Sep 2019 09:53:06 +0200 Subject: [PATCH 226/330] more idiomatic naming --- examples/lib/shared.rs | 7 +++++-- src/entry.rs | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/lib/shared.rs b/examples/lib/shared.rs index 7ead49d..4cd9262 100644 --- a/examples/lib/shared.rs +++ b/examples/lib/shared.rs @@ -39,8 +39,11 @@ impl Iterator for NodeDataIterator { impl NodeDataIterator { pub fn new() -> Self { - let mut root: Entry = NodeData::combine(&leaf(1), &leaf(2)).into(); - root.update_siblings(EntryLink::Stored(0), EntryLink::Stored(1)); + let root = Entry::new( + NodeData::combine(&leaf(1), &leaf(2)), + EntryLink::Stored(0), + EntryLink::Stored(1) + ); let tree = Tree::new( 3, diff --git a/src/entry.rs b/src/entry.rs index b208555..a3f14a8 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -33,7 +33,7 @@ impl Entry { } /// Is this node a leaf. - pub fn is_leaf(&self) -> bool { + pub fn leaf(&self) -> bool { if let EntryKind::Leaf = self.kind { true } else { false } } From 4c9ebcce9a6d7a3b05b16eed9dd2e30393339505 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 25 Sep 2019 12:07:48 +0200 Subject: [PATCH 227/330] Bump Rust to 1.37 on CI --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index caa44f7..85dfd70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: rust rust: - - 1.36.0 + - 1.37.0 addons: apt: From b42477a0bfab979805e2c4fc75e8ad89a0e488a3 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sat, 28 Sep 2019 10:48:43 +0300 Subject: [PATCH 228/330] update from rand_os to fix warnings --- Cargo.lock | 13 ------------- librustzcash/Cargo.toml | 1 - librustzcash/src/rustzcash.rs | 3 +-- librustzcash/src/tests/key_agreement.rs | 3 +-- zcash_primitives/Cargo.toml | 1 - zcash_primitives/benches/pedersen_hash.rs | 4 +--- zcash_primitives/src/merkle_tree.rs | 4 ++-- zcash_primitives/src/note_encryption.rs | 6 +++--- zcash_primitives/src/prover.rs | 2 +- zcash_primitives/src/transaction/builder.rs | 2 +- zcash_primitives/src/transaction/tests.rs | 2 +- zcash_proofs/Cargo.toml | 3 +-- zcash_proofs/src/sapling/prover.rs | 2 +- 13 files changed, 13 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4ade10..4dd7851 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -368,7 +368,6 @@ dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "zcash_primitives 0.0.0", "zcash_proofs 0.0.0", ] @@ -513,15 +512,6 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand_os" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rand_xorshift" version = "0.2.0" @@ -640,7 +630,6 @@ dependencies = [ "pairing 0.14.2", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -656,7 +645,6 @@ dependencies = [ "ff 0.4.0", "pairing 0.14.2", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "zcash_primitives 0.0.0", ] @@ -717,7 +705,6 @@ dependencies = [ "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a" "checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index 8290191..b96fa10 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -24,6 +24,5 @@ pairing = { path = "../pairing" } lazy_static = "1" byteorder = "1" rand_core = "0.5" -rand_os = "0.2" zcash_primitives = { path = "../zcash_primitives" } zcash_proofs = { path = "../zcash_proofs" } diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index e3a85e4..a3da30f 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -24,8 +24,7 @@ use blake2s_simd::Params as Blake2sParams; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use rand_core::RngCore; -use rand_os::OsRng; +use rand_core::{OsRng, RngCore}; use std::io::BufReader; use libc::{c_char, c_uchar, size_t}; diff --git a/librustzcash/src/tests/key_agreement.rs b/librustzcash/src/tests/key_agreement.rs index 1250cc7..c4f56a1 100644 --- a/librustzcash/src/tests/key_agreement.rs +++ b/librustzcash/src/tests/key_agreement.rs @@ -1,7 +1,6 @@ use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::Bls12; -use rand_core::RngCore; -use rand_os::OsRng; +use rand_core::{OsRng, RngCore}; use zcash_primitives::jubjub::{edwards, JubjubBls12}; use zcash_primitives::primitives::{Diversifier, ViewingKey}; diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index 22e4aca..18838ea 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -20,7 +20,6 @@ log = "0.4" pairing = { path = "../pairing" } rand = "0.7" rand_core = "0.5" -rand_os = "0.2" sha2 = "0.8" [dev-dependencies] diff --git a/zcash_primitives/benches/pedersen_hash.rs b/zcash_primitives/benches/pedersen_hash.rs index b647740..3ea652a 100644 --- a/zcash_primitives/benches/pedersen_hash.rs +++ b/zcash_primitives/benches/pedersen_hash.rs @@ -2,13 +2,11 @@ extern crate pairing; extern crate rand_core; -extern crate rand_os; extern crate test; extern crate zcash_primitives; use pairing::bls12_381::Bls12; -use rand_core::RngCore; -use rand_os::OsRng; +use rand_core::{OsRng, RngCore}; use zcash_primitives::jubjub::JubjubBls12; use zcash_primitives::pedersen_hash::{pedersen_hash, Personalization}; diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 2721ab6..baa44e2 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -202,12 +202,12 @@ impl CommitmentTree { /// ``` /// extern crate ff; /// extern crate pairing; -/// extern crate rand_os; +/// extern crate rand_core; /// extern crate zcash_primitives; /// /// use ff::{Field, PrimeField}; /// use pairing::bls12_381::Fr; -/// use rand_os::OsRng; +/// use rand_core::OsRng; /// use zcash_primitives::{ /// merkle_tree::{CommitmentTree, IncrementalWitness}, /// sapling::Node, diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs index e728c5e..747bd8d 100644 --- a/zcash_primitives/src/note_encryption.rs +++ b/zcash_primitives/src/note_encryption.rs @@ -214,12 +214,12 @@ fn prf_ock( /// ``` /// extern crate ff; /// extern crate pairing; -/// extern crate rand_os; +/// extern crate rand_core; /// extern crate zcash_primitives; /// /// use ff::Field; /// use pairing::bls12_381::Bls12; -/// use rand_os::OsRng; +/// use rand_core::OsRng; /// use zcash_primitives::{ /// jubjub::fs::Fs, /// keys::OutgoingViewingKey, @@ -556,8 +556,8 @@ mod tests { use crypto_api_chachapoly::ChachaPolyIetf; use ff::{Field, PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; + use rand_core::OsRng; use rand_core::{CryptoRng, RngCore}; - use rand_os::OsRng; use std::str::FromStr; use super::{ diff --git a/zcash_primitives/src/prover.rs b/zcash_primitives/src/prover.rs index 7c66737..d071816 100644 --- a/zcash_primitives/src/prover.rs +++ b/zcash_primitives/src/prover.rs @@ -74,7 +74,7 @@ pub trait TxProver { pub(crate) mod mock { use ff::Field; use pairing::bls12_381::{Bls12, Fr}; - use rand_os::OsRng; + use rand_core::OsRng; use crate::{ jubjub::{edwards, fs::Fs, FixedGenerators, Unknown}, diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index b100d9c..645a6cb 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -534,7 +534,7 @@ impl Builder { #[cfg(test)] mod tests { use ff::{Field, PrimeField}; - use rand::rngs::OsRng; + use rand_core::OsRng; use crate::jubjub::fs::Fs; diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index d772944..99c7a95 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -1,6 +1,6 @@ use ff::Field; use pairing::bls12_381::Bls12; -use rand_os::OsRng; +use rand_core::OsRng; use crate::jubjub::{fs::Fs, FixedGenerators}; diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index 766db63..95e6ff2 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -13,11 +13,10 @@ byteorder = "1" directories = { version = "1", optional = true } ff = { path = "../ff" } pairing = { path = "../pairing" } -rand_os = "0.2" zcash_primitives = { path = "../zcash_primitives" } +rand_core = "0.5" [dev-dependencies] -rand_core = "0.5" rand_xorshift = "0.2" [features] diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index 9b0f871..70b529a 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -4,7 +4,7 @@ use bellman::{ }; use ff::Field; use pairing::bls12_381::{Bls12, Fr}; -use rand_os::OsRng; +use rand_core::OsRng; use zcash_primitives::{ jubjub::{edwards, fs::Fs, FixedGenerators, JubjubBls12, Unknown}, primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, From 7476e4ea28c5f15ac3099f4e8c86e9f5997aa6a2 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sat, 28 Sep 2019 12:49:37 +0300 Subject: [PATCH 229/330] alphabetical order --- zcash_proofs/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index 95e6ff2..64bd4a1 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -13,8 +13,8 @@ byteorder = "1" directories = { version = "1", optional = true } ff = { path = "../ff" } pairing = { path = "../pairing" } -zcash_primitives = { path = "../zcash_primitives" } rand_core = "0.5" +zcash_primitives = { path = "../zcash_primitives" } [dev-dependencies] rand_xorshift = "0.2" From 730d2cbc7e202c367a939a374b532fee29c502ef Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sat, 28 Sep 2019 12:50:28 +0300 Subject: [PATCH 230/330] fix outdated example --- zcash_primitives/src/merkle_tree.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index baa44e2..b8abf11 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -213,7 +213,8 @@ impl CommitmentTree { /// sapling::Node, /// }; /// -/// let mut rng = OsRng::new().unwrap(); +/// let mut rng = OsRng; +/// /// let mut tree = CommitmentTree::::new(); /// /// tree.append(Node::new(Fr::random(&mut rng).into_repr())); From 93563c3c65a763df5afdae78167dd40a3688b529 Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Fri, 4 Oct 2019 08:50:01 +0200 Subject: [PATCH 231/330] Specify rand_core >= 0.5.1 for OsRng import. --- librustzcash/Cargo.toml | 2 +- zcash_primitives/Cargo.toml | 2 +- zcash_proofs/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index a44d3b5..567bf7c 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -24,6 +24,6 @@ libc = "0.2" pairing = { path = "../pairing" } lazy_static = "1" byteorder = "1" -rand_core = "0.5" +rand_core = "0.5.1" zcash_primitives = { path = "../zcash_primitives" } zcash_proofs = { path = "../zcash_proofs" } diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index 2becbc4..1b365e3 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -20,7 +20,7 @@ lazy_static = "1" log = "0.4" pairing = { path = "../pairing" } rand = "0.7" -rand_core = "0.5" +rand_core = "0.5.1" sha2 = "0.8" [dev-dependencies] diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index 6dab0d1..9d07727 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -14,7 +14,7 @@ byteorder = "1" directories = { version = "1", optional = true } ff = { path = "../ff" } pairing = { path = "../pairing" } -rand_core = "0.5" +rand_core = "0.5.1" zcash_primitives = { path = "../zcash_primitives" } [dev-dependencies] From b872e9fc49e621fa3eed91131c25c188be7be2ea Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 8 Oct 2019 15:25:41 +1300 Subject: [PATCH 232/330] Fix pairing benchmarks They were broken by #91 but went unnoticed because CI does not compile the benchmarks, which requires the nightly toolchain. --- pairing/benches/bls12_381/ec.rs | 50 +++++++++---- pairing/benches/bls12_381/fq.rs | 109 +++++++++++++++++++++-------- pairing/benches/bls12_381/fq12.rs | 38 +++++++--- pairing/benches/bls12_381/fq2.rs | 45 ++++++++---- pairing/benches/bls12_381/fr.rs | 109 +++++++++++++++++++++-------- pairing/benches/bls12_381/mod.rs | 43 ++++++++---- pairing/benches/pairing_benches.rs | 3 +- 7 files changed, 285 insertions(+), 112 deletions(-) diff --git a/pairing/benches/bls12_381/ec.rs b/pairing/benches/bls12_381/ec.rs index d8f6618..04bed0d 100644 --- a/pairing/benches/bls12_381/ec.rs +++ b/pairing/benches/bls12_381/ec.rs @@ -1,6 +1,8 @@ mod g1 { - use rand::{Rand, SeedableRng, XorShiftRng}; + use rand_core::SeedableRng; + use rand_xorshift::XorShiftRng; + use ff::Field; use group::CurveProjective; use pairing::bls12_381::*; @@ -8,10 +10,13 @@ mod g1 { fn bench_g1_mul_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let v: Vec<(G1, Fr)> = (0..SAMPLES) - .map(|_| (G1::rand(&mut rng), Fr::rand(&mut rng))) + .map(|_| (G1::random(&mut rng), Fr::random(&mut rng))) .collect(); let mut count = 0; @@ -27,10 +32,13 @@ mod g1 { fn bench_g1_add_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let v: Vec<(G1, G1)> = (0..SAMPLES) - .map(|_| (G1::rand(&mut rng), G1::rand(&mut rng))) + .map(|_| (G1::random(&mut rng), G1::random(&mut rng))) .collect(); let mut count = 0; @@ -46,10 +54,13 @@ mod g1 { fn bench_g1_add_assign_mixed(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let v: Vec<(G1, G1Affine)> = (0..SAMPLES) - .map(|_| (G1::rand(&mut rng), G1::rand(&mut rng).into())) + .map(|_| (G1::random(&mut rng), G1::random(&mut rng).into())) .collect(); let mut count = 0; @@ -63,8 +74,10 @@ mod g1 { } mod g2 { - use rand::{Rand, SeedableRng, XorShiftRng}; + use rand_core::SeedableRng; + use rand_xorshift::XorShiftRng; + use ff::Field; use group::CurveProjective; use pairing::bls12_381::*; @@ -72,10 +85,13 @@ mod g2 { fn bench_g2_mul_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let v: Vec<(G2, Fr)> = (0..SAMPLES) - .map(|_| (G2::rand(&mut rng), Fr::rand(&mut rng))) + .map(|_| (G2::random(&mut rng), Fr::random(&mut rng))) .collect(); let mut count = 0; @@ -91,10 +107,13 @@ mod g2 { fn bench_g2_add_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let v: Vec<(G2, G2)> = (0..SAMPLES) - .map(|_| (G2::rand(&mut rng), G2::rand(&mut rng))) + .map(|_| (G2::random(&mut rng), G2::random(&mut rng))) .collect(); let mut count = 0; @@ -110,10 +129,13 @@ mod g2 { fn bench_g2_add_assign_mixed(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let v: Vec<(G2, G2Affine)> = (0..SAMPLES) - .map(|_| (G2::rand(&mut rng), G2::rand(&mut rng).into())) + .map(|_| (G2::random(&mut rng), G2::random(&mut rng).into())) .collect(); let mut count = 0; diff --git a/pairing/benches/bls12_381/fq.rs b/pairing/benches/bls12_381/fq.rs index 053a10c..b663322 100644 --- a/pairing/benches/bls12_381/fq.rs +++ b/pairing/benches/bls12_381/fq.rs @@ -1,4 +1,5 @@ -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +use rand_xorshift::XorShiftRng; use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField}; use pairing::bls12_381::*; @@ -7,12 +8,15 @@ use pairing::bls12_381::*; fn bench_fq_repr_add_nocarry(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES) .map(|_| { - let mut tmp1 = FqRepr::rand(&mut rng); - let mut tmp2 = FqRepr::rand(&mut rng); + let mut tmp1 = Fq::random(&mut rng).into_repr(); + let mut tmp2 = Fq::random(&mut rng).into_repr(); // Shave a few bits off to avoid overflow. for _ in 0..3 { tmp1.div2(); @@ -35,11 +39,14 @@ fn bench_fq_repr_add_nocarry(b: &mut ::test::Bencher) { fn bench_fq_repr_sub_noborrow(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES) .map(|_| { - let tmp1 = FqRepr::rand(&mut rng); + let tmp1 = Fq::random(&mut rng).into_repr(); let mut tmp2 = tmp1; // Ensure tmp2 is smaller than tmp1. for _ in 0..10 { @@ -62,9 +69,14 @@ fn bench_fq_repr_sub_noborrow(b: &mut ::test::Bencher) { fn bench_fq_repr_num_bits(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES) + .map(|_| Fq::random(&mut rng).into_repr()) + .collect(); let mut count = 0; b.iter(|| { @@ -78,9 +90,14 @@ fn bench_fq_repr_num_bits(b: &mut ::test::Bencher) { fn bench_fq_repr_mul2(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES) + .map(|_| Fq::random(&mut rng).into_repr()) + .collect(); let mut count = 0; b.iter(|| { @@ -95,9 +112,14 @@ fn bench_fq_repr_mul2(b: &mut ::test::Bencher) { fn bench_fq_repr_div2(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES) + .map(|_| Fq::random(&mut rng).into_repr()) + .collect(); let mut count = 0; b.iter(|| { @@ -112,10 +134,13 @@ fn bench_fq_repr_div2(b: &mut ::test::Bencher) { fn bench_fq_add_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq, Fq)> = (0..SAMPLES) - .map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng))) + .map(|_| (Fq::random(&mut rng), Fq::random(&mut rng))) .collect(); let mut count = 0; @@ -131,10 +156,13 @@ fn bench_fq_add_assign(b: &mut ::test::Bencher) { fn bench_fq_sub_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq, Fq)> = (0..SAMPLES) - .map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng))) + .map(|_| (Fq::random(&mut rng), Fq::random(&mut rng))) .collect(); let mut count = 0; @@ -150,10 +178,13 @@ fn bench_fq_sub_assign(b: &mut ::test::Bencher) { fn bench_fq_mul_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq, Fq)> = (0..SAMPLES) - .map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng))) + .map(|_| (Fq::random(&mut rng), Fq::random(&mut rng))) .collect(); let mut count = 0; @@ -169,9 +200,12 @@ fn bench_fq_mul_assign(b: &mut ::test::Bencher) { fn bench_fq_square(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -186,9 +220,12 @@ fn bench_fq_square(b: &mut ::test::Bencher) { fn bench_fq_inverse(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -201,9 +238,12 @@ fn bench_fq_inverse(b: &mut ::test::Bencher) { fn bench_fq_negate(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -218,11 +258,14 @@ fn bench_fq_negate(b: &mut ::test::Bencher) { fn bench_fq_sqrt(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec = (0..SAMPLES) .map(|_| { - let mut tmp = Fq::rand(&mut rng); + let mut tmp = Fq::random(&mut rng); tmp.square(); tmp }) @@ -239,9 +282,12 @@ fn bench_fq_sqrt(b: &mut ::test::Bencher) { fn bench_fq_into_repr(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -254,10 +300,13 @@ fn bench_fq_into_repr(b: &mut ::test::Bencher) { fn bench_fq_from_repr(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec = (0..SAMPLES) - .map(|_| Fq::rand(&mut rng).into_repr()) + .map(|_| Fq::random(&mut rng).into_repr()) .collect(); let mut count = 0; diff --git a/pairing/benches/bls12_381/fq12.rs b/pairing/benches/bls12_381/fq12.rs index 84daca2..8bf0392 100644 --- a/pairing/benches/bls12_381/fq12.rs +++ b/pairing/benches/bls12_381/fq12.rs @@ -1,4 +1,5 @@ -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +use rand_xorshift::XorShiftRng; use ff::Field; use pairing::bls12_381::*; @@ -7,10 +8,13 @@ use pairing::bls12_381::*; fn bench_fq12_add_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq12, Fq12)> = (0..SAMPLES) - .map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng))) + .map(|_| (Fq12::random(&mut rng), Fq12::random(&mut rng))) .collect(); let mut count = 0; @@ -26,10 +30,13 @@ fn bench_fq12_add_assign(b: &mut ::test::Bencher) { fn bench_fq12_sub_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq12, Fq12)> = (0..SAMPLES) - .map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng))) + .map(|_| (Fq12::random(&mut rng), Fq12::random(&mut rng))) .collect(); let mut count = 0; @@ -45,10 +52,13 @@ fn bench_fq12_sub_assign(b: &mut ::test::Bencher) { fn bench_fq12_mul_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq12, Fq12)> = (0..SAMPLES) - .map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng))) + .map(|_| (Fq12::random(&mut rng), Fq12::random(&mut rng))) .collect(); let mut count = 0; @@ -64,9 +74,12 @@ fn bench_fq12_mul_assign(b: &mut ::test::Bencher) { fn bench_fq12_squaring(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq12::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq12::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -81,9 +94,12 @@ fn bench_fq12_squaring(b: &mut ::test::Bencher) { fn bench_fq12_inverse(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq12::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq12::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { diff --git a/pairing/benches/bls12_381/fq2.rs b/pairing/benches/bls12_381/fq2.rs index 521b6ab..028c42e 100644 --- a/pairing/benches/bls12_381/fq2.rs +++ b/pairing/benches/bls12_381/fq2.rs @@ -1,4 +1,5 @@ -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +use rand_xorshift::XorShiftRng; use ff::{Field, SqrtField}; use pairing::bls12_381::*; @@ -7,10 +8,13 @@ use pairing::bls12_381::*; fn bench_fq2_add_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq2, Fq2)> = (0..SAMPLES) - .map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng))) + .map(|_| (Fq2::random(&mut rng), Fq2::random(&mut rng))) .collect(); let mut count = 0; @@ -26,10 +30,13 @@ fn bench_fq2_add_assign(b: &mut ::test::Bencher) { fn bench_fq2_sub_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq2, Fq2)> = (0..SAMPLES) - .map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng))) + .map(|_| (Fq2::random(&mut rng), Fq2::random(&mut rng))) .collect(); let mut count = 0; @@ -45,10 +52,13 @@ fn bench_fq2_sub_assign(b: &mut ::test::Bencher) { fn bench_fq2_mul_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq2, Fq2)> = (0..SAMPLES) - .map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng))) + .map(|_| (Fq2::random(&mut rng), Fq2::random(&mut rng))) .collect(); let mut count = 0; @@ -64,9 +74,12 @@ fn bench_fq2_mul_assign(b: &mut ::test::Bencher) { fn bench_fq2_squaring(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq2::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -81,9 +94,12 @@ fn bench_fq2_squaring(b: &mut ::test::Bencher) { fn bench_fq2_inverse(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq2::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -97,9 +113,12 @@ fn bench_fq2_inverse(b: &mut ::test::Bencher) { fn bench_fq2_sqrt(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq2::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { diff --git a/pairing/benches/bls12_381/fr.rs b/pairing/benches/bls12_381/fr.rs index 13b0d0e..9e767d8 100644 --- a/pairing/benches/bls12_381/fr.rs +++ b/pairing/benches/bls12_381/fr.rs @@ -1,4 +1,5 @@ -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +use rand_xorshift::XorShiftRng; use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField}; use pairing::bls12_381::*; @@ -7,12 +8,15 @@ use pairing::bls12_381::*; fn bench_fr_repr_add_nocarry(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES) .map(|_| { - let mut tmp1 = FrRepr::rand(&mut rng); - let mut tmp2 = FrRepr::rand(&mut rng); + let mut tmp1 = Fr::random(&mut rng).into_repr(); + let mut tmp2 = Fr::random(&mut rng).into_repr(); // Shave a few bits off to avoid overflow. for _ in 0..3 { tmp1.div2(); @@ -35,11 +39,14 @@ fn bench_fr_repr_add_nocarry(b: &mut ::test::Bencher) { fn bench_fr_repr_sub_noborrow(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES) .map(|_| { - let tmp1 = FrRepr::rand(&mut rng); + let tmp1 = Fr::random(&mut rng).into_repr(); let mut tmp2 = tmp1; // Ensure tmp2 is smaller than tmp1. for _ in 0..10 { @@ -62,9 +69,14 @@ fn bench_fr_repr_sub_noborrow(b: &mut ::test::Bencher) { fn bench_fr_repr_num_bits(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES) + .map(|_| Fr::random(&mut rng).into_repr()) + .collect(); let mut count = 0; b.iter(|| { @@ -78,9 +90,14 @@ fn bench_fr_repr_num_bits(b: &mut ::test::Bencher) { fn bench_fr_repr_mul2(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES) + .map(|_| Fr::random(&mut rng).into_repr()) + .collect(); let mut count = 0; b.iter(|| { @@ -95,9 +112,14 @@ fn bench_fr_repr_mul2(b: &mut ::test::Bencher) { fn bench_fr_repr_div2(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES) + .map(|_| Fr::random(&mut rng).into_repr()) + .collect(); let mut count = 0; b.iter(|| { @@ -112,10 +134,13 @@ fn bench_fr_repr_div2(b: &mut ::test::Bencher) { fn bench_fr_add_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fr, Fr)> = (0..SAMPLES) - .map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng))) + .map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))) .collect(); let mut count = 0; @@ -131,10 +156,13 @@ fn bench_fr_add_assign(b: &mut ::test::Bencher) { fn bench_fr_sub_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fr, Fr)> = (0..SAMPLES) - .map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng))) + .map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))) .collect(); let mut count = 0; @@ -150,10 +178,13 @@ fn bench_fr_sub_assign(b: &mut ::test::Bencher) { fn bench_fr_mul_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fr, Fr)> = (0..SAMPLES) - .map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng))) + .map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))) .collect(); let mut count = 0; @@ -169,9 +200,12 @@ fn bench_fr_mul_assign(b: &mut ::test::Bencher) { fn bench_fr_square(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -186,9 +220,12 @@ fn bench_fr_square(b: &mut ::test::Bencher) { fn bench_fr_inverse(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -201,9 +238,12 @@ fn bench_fr_inverse(b: &mut ::test::Bencher) { fn bench_fr_negate(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -218,11 +258,14 @@ fn bench_fr_negate(b: &mut ::test::Bencher) { fn bench_fr_sqrt(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec = (0..SAMPLES) .map(|_| { - let mut tmp = Fr::rand(&mut rng); + let mut tmp = Fr::random(&mut rng); tmp.square(); tmp }) @@ -239,9 +282,12 @@ fn bench_fr_sqrt(b: &mut ::test::Bencher) { fn bench_fr_into_repr(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -254,10 +300,13 @@ fn bench_fr_into_repr(b: &mut ::test::Bencher) { fn bench_fr_from_repr(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec = (0..SAMPLES) - .map(|_| Fr::rand(&mut rng).into_repr()) + .map(|_| Fr::random(&mut rng).into_repr()) .collect(); let mut count = 0; diff --git a/pairing/benches/bls12_381/mod.rs b/pairing/benches/bls12_381/mod.rs index 96bcdd5..2c23c2a 100644 --- a/pairing/benches/bls12_381/mod.rs +++ b/pairing/benches/bls12_381/mod.rs @@ -4,8 +4,10 @@ mod fq12; mod fq2; mod fr; -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +use rand_xorshift::XorShiftRng; +use group::CurveProjective; use pairing::bls12_381::*; use pairing::{Engine, PairingCurveAffine}; @@ -13,9 +15,12 @@ use pairing::{Engine, PairingCurveAffine}; fn bench_pairing_g1_preparation(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| G1::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| G1::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -29,9 +34,12 @@ fn bench_pairing_g1_preparation(b: &mut ::test::Bencher) { fn bench_pairing_g2_preparation(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| G2::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| G2::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -45,13 +53,16 @@ fn bench_pairing_g2_preparation(b: &mut ::test::Bencher) { fn bench_pairing_miller_loop(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(G1Prepared, G2Prepared)> = (0..SAMPLES) .map(|_| { ( - G1Affine::from(G1::rand(&mut rng)).prepare(), - G2Affine::from(G2::rand(&mut rng)).prepare(), + G1Affine::from(G1::random(&mut rng)).prepare(), + G2Affine::from(G2::random(&mut rng)).prepare(), ) }) .collect(); @@ -68,13 +79,16 @@ fn bench_pairing_miller_loop(b: &mut ::test::Bencher) { fn bench_pairing_final_exponentiation(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec = (0..SAMPLES) .map(|_| { ( - G1Affine::from(G1::rand(&mut rng)).prepare(), - G2Affine::from(G2::rand(&mut rng)).prepare(), + G1Affine::from(G1::random(&mut rng)).prepare(), + G2Affine::from(G2::random(&mut rng)).prepare(), ) }) .map(|(ref p, ref q)| Bls12::miller_loop(&[(p, q)])) @@ -92,10 +106,13 @@ fn bench_pairing_final_exponentiation(b: &mut ::test::Bencher) { fn bench_pairing_full(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(G1, G2)> = (0..SAMPLES) - .map(|_| (G1::rand(&mut rng), G2::rand(&mut rng))) + .map(|_| (G1::random(&mut rng), G2::random(&mut rng))) .collect(); let mut count = 0; diff --git a/pairing/benches/pairing_benches.rs b/pairing/benches/pairing_benches.rs index d76e50b..b083b42 100644 --- a/pairing/benches/pairing_benches.rs +++ b/pairing/benches/pairing_benches.rs @@ -3,7 +3,8 @@ extern crate ff; extern crate group; extern crate pairing; -extern crate rand; +extern crate rand_core; +extern crate rand_xorshift; extern crate test; mod bls12_381; From 80d339848f5a9243acbb3b629114ea7a80edf35a Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 8 Oct 2019 15:32:26 +1300 Subject: [PATCH 233/330] Actions: Various CI improvements - Test against MSRV - Parallel linting - Compile benchmarks on nightly --- .github/workflows/rust.yml | 94 +++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 32 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index cf55d9a..5f76fb0 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -3,45 +3,60 @@ name: Rust on: [push, pull_request] jobs: + lint: + name: Lint + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/toolchain@v1 + with: + toolchain: 1.37.0 + override: true + + # Ensure all code has been formatted with rustfmt + - run: rustup component add rustfmt + - name: Check formatting + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check --color always + test: name: Test on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest, windows-latest, macOS-latest] steps: - - uses: actions/checkout@v1 - - name: Check formatting - run: cargo fmt --all -- --check - - name: Build - run: cargo build --verbose --release --all - - name: Run tests - run: cargo test --verbose --release --all - - name: Run slow tests - run: cargo test --verbose --release --all -- --ignored - - macOS: - name: Test on macOS-latest - runs-on: macOS-latest - - steps: - - name: Install Rust - run: curl https://sh.rustup.rs -sSf | sh -s -- -y - - name: Install rustfmt - run: $HOME/.cargo/bin/rustup component add rustfmt - - uses: actions/checkout@v1 - - name: Check formatting - run: $HOME/.cargo/bin/cargo fmt --all -- --check - - name: Build - run: $HOME/.cargo/bin/cargo build --verbose --release --all - - name: Run tests - run: $HOME/.cargo/bin/cargo test --verbose --release --all - - name: Run slow tests - run: $HOME/.cargo/bin/cargo test --verbose --release --all -- --ignored + - uses: actions/checkout@v1 + - uses: actions-rs/toolchain@v1 + with: + toolchain: 1.37.0 + override: true + - name: cargo fetch + uses: actions-rs/cargo@v1 + with: + command: fetch + - name: Build tests + uses: actions-rs/cargo@v1 + with: + command: build + args: --verbose --release --all --tests + - name: Run tests + uses: actions-rs/cargo@v1 + with: + command: test + args: --verbose --release --all + - name: Run slow tests + uses: actions-rs/cargo@v1 + with: + command: test + args: --verbose --release --all -- --ignored doc-links: - name: Check intra-doc links + name: Nightly lint runs-on: ubuntu-latest steps: @@ -50,7 +65,22 @@ jobs: with: toolchain: nightly override: true - - uses: actions-rs/cargo@v1 + - name: cargo fetch + uses: actions-rs/cargo@v1 + with: + command: fetch + + # Ensure intra-documentation links all resolve correctly + # Requires #![deny(intra_doc_link_resolution_failure)] in crates. + - name: Check intra-doc links + uses: actions-rs/cargo@v1 with: command: doc - args: --document-private-items + args: --all --document-private-items + + # Build benchmarks to prevent bitrot + - name: Build benchmarks + uses: actions-rs/cargo@v1 + with: + command: build + args: --verbose --all --benches From 216f0f62a0a336b972a1d86e0a59680d1a849f3d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 8 Oct 2019 16:00:47 +1300 Subject: [PATCH 234/330] ff 0.5.0 --- Cargo.lock | 18 +++++++++--------- ff/Cargo.toml | 7 +++++-- ff/ff_derive/Cargo.toml | 5 ++++- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4dd7851..33c08a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,7 +60,7 @@ dependencies = [ "blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0", + "ff 0.5.0", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "group 0.1.0", @@ -251,16 +251,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ff" -version = "0.4.0" +version = "0.5.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff_derive 0.3.0", + "ff_derive 0.4.0", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ff_derive" -version = "0.3.0" +version = "0.4.0" dependencies = [ "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", @@ -318,7 +318,7 @@ dependencies = [ name = "group" version = "0.1.0" dependencies = [ - "ff 0.4.0", + "ff 0.5.0", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -363,7 +363,7 @@ dependencies = [ "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0", + "ff 0.5.0", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", @@ -438,7 +438,7 @@ name = "pairing" version = "0.14.2" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0", + "ff 0.5.0", "group 0.1.0", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -621,7 +621,7 @@ dependencies = [ "blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto_api_chachapoly 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0", + "ff 0.5.0", "fpe 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -642,7 +642,7 @@ dependencies = [ "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0", + "ff 0.5.0", "pairing 0.14.2", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ff/Cargo.toml b/ff/Cargo.toml index b832581..9ac1f1e 100644 --- a/ff/Cargo.toml +++ b/ff/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ff" -version = "0.4.0" +version = "0.5.0" authors = ["Sean Bowe "] description = "Library for building and interfacing with finite fields" readme = "README.md" @@ -12,9 +12,12 @@ edition = "2018" [dependencies] byteorder = "1" -ff_derive = { version = "0.3.0", path = "ff_derive", optional = true } +ff_derive = { version = "0.4.0", path = "ff_derive", optional = true } rand_core = "0.5" [features] default = [] derive = ["ff_derive"] + +[badges] +maintenance = { status = "actively-developed" } diff --git a/ff/ff_derive/Cargo.toml b/ff/ff_derive/Cargo.toml index 18ac1bc..88ba23e 100644 --- a/ff/ff_derive/Cargo.toml +++ b/ff/ff_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ff_derive" -version = "0.3.0" +version = "0.4.0" authors = ["Sean Bowe "] description = "Procedural macro library used to build custom prime field implementations" documentation = "https://docs.rs/ff/" @@ -19,3 +19,6 @@ num-integer = "0.1" proc-macro2 = "1" quote = "1" syn = "1" + +[badges] +maintenance = { status = "passively-maintained" } From aa37783c375d23c52fb3283863391b4899541127 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 8 Oct 2019 16:01:24 +1300 Subject: [PATCH 235/330] group 0.2.0 --- Cargo.lock | 6 +++--- group/Cargo.toml | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 33c08a6..bc6120f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,7 +63,7 @@ dependencies = [ "ff 0.5.0", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "group 0.1.0", + "group 0.2.0", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.14.2", @@ -316,7 +316,7 @@ dependencies = [ [[package]] name = "group" -version = "0.1.0" +version = "0.2.0" dependencies = [ "ff 0.5.0", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -439,7 +439,7 @@ version = "0.14.2" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.5.0", - "group 0.1.0", + "group 0.2.0", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/group/Cargo.toml b/group/Cargo.toml index f27eb3f..03c172f 100644 --- a/group/Cargo.toml +++ b/group/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "group" -version = "0.1.0" +version = "0.2.0" authors = [ "Sean Bowe ", "Jack Grigg ", @@ -15,6 +15,9 @@ repository = "https://github.com/ebfull/group" edition = "2018" [dependencies] -ff = { path = "../ff" } +ff = { version = "0.5.0", path = "../ff" } rand = "0.7" rand_xorshift = "0.2" + +[badges] +maintenance = { status = "actively-developed" } From 68cada53cf401f3d2bdc0ffc774b0d4fe7467173 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 8 Oct 2019 16:02:44 +1300 Subject: [PATCH 236/330] pairing 0.15.0 --- Cargo.lock | 12 ++++++------ pairing/Cargo.toml | 9 ++++++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc6120f..d4786d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,7 +66,7 @@ dependencies = [ "group 0.2.0", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", + "pairing 0.15.0", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -366,7 +366,7 @@ dependencies = [ "ff 0.5.0", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", + "pairing 0.15.0", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "zcash_primitives 0.0.0", "zcash_proofs 0.0.0", @@ -435,7 +435,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "pairing" -version = "0.14.2" +version = "0.15.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.5.0", @@ -606,7 +606,7 @@ name = "zcash_client_backend" version = "0.0.0" dependencies = [ "bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", + "pairing 0.15.0", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "zcash_primitives 0.0.0", @@ -627,7 +627,7 @@ dependencies = [ "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", + "pairing 0.15.0", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -643,7 +643,7 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.5.0", - "pairing 0.14.2", + "pairing 0.15.0", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "zcash_primitives 0.0.0", diff --git a/pairing/Cargo.toml b/pairing/Cargo.toml index 1801ffd..1c59855 100644 --- a/pairing/Cargo.toml +++ b/pairing/Cargo.toml @@ -2,7 +2,7 @@ name = "pairing" # Remember to change version string in README.md. -version = "0.14.2" +version = "0.15.0" authors = [ "Sean Bowe ", "Jack Grigg ", @@ -18,8 +18,8 @@ edition ="2018" [dependencies] byteorder = "1" -ff = { path = "../ff", features = ["derive"] } -group = { path = "../group" } +ff = { version = "0.5.0", path = "../ff", features = ["derive"] } +group = { version = "0.2.0", path = "../group" } rand_core = "0.5" [dev-dependencies] @@ -29,3 +29,6 @@ rand_xorshift = "0.2" unstable-features = ["expose-arith"] expose-arith = [] default = [] + +[badges] +maintenance = { status = "actively-developed" } From 25558893ab1f9c3a548dbd54ce9a881f65f6614c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 8 Oct 2019 16:05:46 +1300 Subject: [PATCH 237/330] bellman 0.2.0 --- Cargo.lock | 6 +++--- bellman/Cargo.toml | 11 +++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4786d8..db8a1fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,7 +54,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bellman" -version = "0.1.0" +version = "0.2.0" dependencies = [ "bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -359,7 +359,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "librustzcash" version = "0.1.0" dependencies = [ - "bellman 0.1.0", + "bellman 0.2.0", "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -638,7 +638,7 @@ dependencies = [ name = "zcash_proofs" version = "0.0.0" dependencies = [ - "bellman 0.1.0", + "bellman 0.2.0", "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/bellman/Cargo.toml b/bellman/Cargo.toml index 3b2a46f..4f125b4 100644 --- a/bellman/Cargo.toml +++ b/bellman/Cargo.toml @@ -7,19 +7,19 @@ homepage = "https://github.com/ebfull/bellman" license = "MIT/Apache-2.0" name = "bellman" repository = "https://github.com/ebfull/bellman" -version = "0.1.0" +version = "0.2.0" edition = "2018" [dependencies] bit-vec = "0.4.4" blake2s_simd = "0.5" -ff = { path = "../ff" } +ff = { version = "0.5.0", path = "../ff" } futures = "0.1" futures-cpupool = { version = "0.1", optional = true } -group = { path = "../group" } +group = { version = "0.2.0", path = "../group" } num_cpus = { version = "1", optional = true } crossbeam = { version = "0.7", optional = true } -pairing = { path = "../pairing", optional = true } +pairing = { version = "0.15.0", path = "../pairing", optional = true } rand_core = "0.5" byteorder = "1" @@ -38,3 +38,6 @@ default = ["groth16", "multicore"] name = "mimc" path = "tests/mimc.rs" required-features = ["groth16"] + +[badges] +maintenance = { status = "actively-developed" } From 8b08528bb083d955d86a33452c57f366087da540 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 8 Oct 2019 16:07:30 +1300 Subject: [PATCH 238/330] zcash_primitives 0.1.0 --- Cargo.lock | 8 ++++---- zcash_primitives/Cargo.toml | 13 ++++++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index db8a1fd..5eb1e6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -368,7 +368,7 @@ dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.15.0", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_primitives 0.0.0", + "zcash_primitives 0.1.0", "zcash_proofs 0.0.0", ] @@ -609,12 +609,12 @@ dependencies = [ "pairing 0.15.0", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_primitives 0.0.0", + "zcash_primitives 0.1.0", ] [[package]] name = "zcash_primitives" -version = "0.0.0" +version = "0.1.0" dependencies = [ "aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -646,7 +646,7 @@ dependencies = [ "pairing 0.15.0", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_primitives 0.0.0", + "zcash_primitives 0.1.0", ] [metadata] diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index 1b365e3..c83ecf1 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -1,10 +1,14 @@ [package] name = "zcash_primitives" -version = "0.0.0" +description = "Rust implementations of the Zcash primitives" +version = "0.1.0" authors = [ "Jack Grigg ", ] +homepage = "https://github.com/zcash/librustzcash" +repository = "https://github.com/zcash/librustzcash" readme = "README.md" +license = "MIT OR Apache-2.0" edition = "2018" [dependencies] @@ -13,12 +17,12 @@ blake2b_simd = "0.5" blake2s_simd = "0.5" byteorder = "1" crypto_api_chachapoly = "0.2.1" -ff = { path = "../ff" } +ff = { version = "0.5.0", path = "../ff" } fpe = "0.2" hex = "0.3" lazy_static = "1" log = "0.4" -pairing = { path = "../pairing" } +pairing = { version = "0.15.0", path = "../pairing" } rand = "0.7" rand_core = "0.5.1" sha2 = "0.8" @@ -26,3 +30,6 @@ sha2 = "0.8" [dev-dependencies] hex-literal = "0.2" rand_xorshift = "0.2" + +[badges] +maintenance = { status = "actively-developed" } From d6bc2fe0af5e8524c6601482af14541234dec087 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 8 Oct 2019 16:10:30 +1300 Subject: [PATCH 239/330] zcash_proofs 0.1.0 --- Cargo.lock | 4 ++-- zcash_proofs/Cargo.toml | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5eb1e6a..75da3c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -369,7 +369,7 @@ dependencies = [ "pairing 0.15.0", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "zcash_primitives 0.1.0", - "zcash_proofs 0.0.0", + "zcash_proofs 0.1.0", ] [[package]] @@ -636,7 +636,7 @@ dependencies = [ [[package]] name = "zcash_proofs" -version = "0.0.0" +version = "0.1.0" dependencies = [ "bellman 0.2.0", "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index 9d07727..b9de0f7 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -1,21 +1,25 @@ [package] name = "zcash_proofs" -version = "0.0.0" +description = "Zcash zk-SNARK circuits and proving APIs" +version = "0.1.0" authors = [ "Jack Grigg ", ] +homepage = "https://github.com/zcash/librustzcash" +repository = "https://github.com/zcash/librustzcash" readme = "README.md" +license = "MIT OR Apache-2.0" edition = "2018" [dependencies] -bellman = { path = "../bellman" } +bellman = { version = "0.2.0", path = "../bellman" } blake2b_simd = "0.5" byteorder = "1" directories = { version = "1", optional = true } -ff = { path = "../ff" } -pairing = { path = "../pairing" } +ff = { version = "0.5.0", path = "../ff" } +pairing = { version = "0.15.0", path = "../pairing" } rand_core = "0.5.1" -zcash_primitives = { path = "../zcash_primitives" } +zcash_primitives = { version = "0.1.0", path = "../zcash_primitives" } [dev-dependencies] rand_xorshift = "0.2" @@ -23,3 +27,6 @@ rand_xorshift = "0.2" [features] default = ["local-prover"] local-prover = ["directories"] + +[badges] +maintenance = { status = "actively-developed" } From b0ba7fe4d221b7800d9e55e468316117b4a2e778 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 8 Oct 2019 16:11:39 +1300 Subject: [PATCH 240/330] zcash_client_backend 0.1.0 --- Cargo.lock | 2 +- zcash_client_backend/Cargo.toml | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 75da3c7..2558a57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -603,7 +603,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "zcash_client_backend" -version = "0.0.0" +version = "0.1.0" dependencies = [ "bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.15.0", diff --git a/zcash_client_backend/Cargo.toml b/zcash_client_backend/Cargo.toml index 6199f2b..7594630 100644 --- a/zcash_client_backend/Cargo.toml +++ b/zcash_client_backend/Cargo.toml @@ -1,17 +1,24 @@ [package] name = "zcash_client_backend" -version = "0.0.0" +description = "APIs for creating shielded Zcash light clients" +version = "0.1.0" authors = [ "Jack Grigg ", ] +homepage = "https://github.com/zcash/librustzcash" +repository = "https://github.com/zcash/librustzcash" readme = "README.md" +license = "MIT OR Apache-2.0" edition = "2018" [dependencies] bech32 = "0.7" -pairing = { path = "../pairing" } -zcash_primitives = { path = "../zcash_primitives" } +pairing = { version = "0.15.0", path = "../pairing" } +zcash_primitives = { version = "0.1.0", path = "../zcash_primitives" } [dev-dependencies] rand_core = "0.5" rand_xorshift = "0.2" + +[badges] +maintenance = { status = "actively-developed" } From 98731c83743b6438caceb5362daeedba115cf03f Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 8 Oct 2019 16:12:50 +1300 Subject: [PATCH 241/330] librustzcash 0.2.0 --- Cargo.lock | 2 +- librustzcash/Cargo.toml | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2558a57..7a33a24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -357,7 +357,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "librustzcash" -version = "0.1.0" +version = "0.2.0" dependencies = [ "bellman 0.2.0", "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index 567bf7c..432222b 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -1,13 +1,17 @@ [package] name = "librustzcash" -version = "0.1.0" +description = "Rust FFI used by the zcashd binary. Not an official API." +version = "0.2.0" authors = [ "Sean Bowe ", "Jack Grigg ", "Jay Graber ", "Simon Liu " ] +homepage = "https://github.com/zcash/librustzcash" +repository = "https://github.com/zcash/librustzcash" readme = "README.md" +license = "MIT OR Apache-2.0" edition = "2018" [lib] @@ -16,14 +20,17 @@ path = "src/rustzcash.rs" crate-type = ["staticlib"] [dependencies] -bellman = { path = "../bellman" } +bellman = { version = "0.2.0", path = "../bellman" } blake2b_simd = "0.5" blake2s_simd = "0.5" -ff = { path = "../ff" } +ff = { version = "0.5.0", path = "../ff" } libc = "0.2" -pairing = { path = "../pairing" } +pairing = { version = "0.15.0", path = "../pairing" } lazy_static = "1" byteorder = "1" rand_core = "0.5.1" -zcash_primitives = { path = "../zcash_primitives" } -zcash_proofs = { path = "../zcash_proofs" } +zcash_primitives = { version = "0.1.0", path = "../zcash_primitives" } +zcash_proofs = { version = "0.1.0", path = "../zcash_proofs" } + +[badges] +maintenance = { status = "deprecated" } From 784439436456358d26cd7e9059df30e62975d1e5 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 8 Oct 2019 16:06:02 +0300 Subject: [PATCH 242/330] Remove unneeded extern crate --- bellman/src/gadgets/blake2s.rs | 1 + bellman/src/gadgets/sha256.rs | 1 + bellman/src/lib.rs | 13 ------------- ff/ff_derive/src/lib.rs | 8 +------- ff/src/lib.rs | 4 ---- zcash_primitives/src/jubjub/mod.rs | 2 ++ zcash_primitives/src/lib.rs | 7 +------ zcash_primitives/src/sapling.rs | 1 + 8 files changed, 7 insertions(+), 30 deletions(-) diff --git a/bellman/src/gadgets/blake2s.rs b/bellman/src/gadgets/blake2s.rs index 9b6693b..8b1ff54 100644 --- a/bellman/src/gadgets/blake2s.rs +++ b/bellman/src/gadgets/blake2s.rs @@ -408,6 +408,7 @@ pub fn blake2s>( #[cfg(test)] mod test { use blake2s_simd::Params as Blake2sParams; + use hex_literal::hex; use pairing::bls12_381::Bls12; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; diff --git a/bellman/src/gadgets/sha256.rs b/bellman/src/gadgets/sha256.rs index 0c8efea..1be898e 100644 --- a/bellman/src/gadgets/sha256.rs +++ b/bellman/src/gadgets/sha256.rs @@ -273,6 +273,7 @@ mod test { use super::*; use crate::gadgets::boolean::AllocatedBit; use crate::gadgets::test::TestConstraintSystem; + use hex_literal::hex; use pairing::bls12_381::Bls12; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; diff --git a/bellman/src/lib.rs b/bellman/src/lib.rs index a3b577b..ef13a83 100644 --- a/bellman/src/lib.rs +++ b/bellman/src/lib.rs @@ -135,19 +135,6 @@ // Catch documentation errors caused by code changes. #![deny(intra_doc_link_resolution_failure)] -#[cfg(feature = "multicore")] -extern crate crossbeam; - -#[cfg(feature = "multicore")] -extern crate num_cpus; - -#[cfg(test)] -#[macro_use] -extern crate hex_literal; - -#[cfg(test)] -extern crate rand; - pub mod domain; pub mod gadgets; #[cfg(feature = "groth16")] diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs index 7cdaf91..d47ec12 100644 --- a/ff/ff_derive/src/lib.rs +++ b/ff/ff_derive/src/lib.rs @@ -2,17 +2,11 @@ extern crate proc_macro; extern crate proc_macro2; -extern crate syn; -#[macro_use] -extern crate quote; - -extern crate num_bigint; -extern crate num_integer; -extern crate num_traits; use num_bigint::BigUint; use num_integer::Integer; use num_traits::{One, ToPrimitive, Zero}; +use quote::quote; use quote::TokenStreamExt; use std::str::FromStr; diff --git a/ff/src/lib.rs b/ff/src/lib.rs index 6be25da..b50cbd5 100644 --- a/ff/src/lib.rs +++ b/ff/src/lib.rs @@ -4,10 +4,6 @@ #![deny(intra_doc_link_resolution_failure)] #![allow(unused_imports)] -#[cfg(feature = "derive")] -#[macro_use] -extern crate ff_derive; - #[cfg(feature = "derive")] pub use ff_derive::*; diff --git a/zcash_primitives/src/jubjub/mod.rs b/zcash_primitives/src/jubjub/mod.rs index 555f3b9..9428600 100644 --- a/zcash_primitives/src/jubjub/mod.rs +++ b/zcash_primitives/src/jubjub/mod.rs @@ -469,6 +469,8 @@ impl JubjubBls12 { #[test] fn test_jubjub_bls12() { + use hex_literal::hex; + let params = JubjubBls12::new(); tests::test_suite::(¶ms); diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 713ca2b..d882f5a 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -6,12 +6,7 @@ // Catch documentation errors caused by code changes. #![deny(intra_doc_link_resolution_failure)] -#[macro_use] -extern crate lazy_static; - -#[cfg(test)] -#[macro_use] -extern crate hex_literal; +use lazy_static::lazy_static; pub mod block; pub mod constants; diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs index 4f57a43..da8b838 100644 --- a/zcash_primitives/src/sapling.rs +++ b/zcash_primitives/src/sapling.rs @@ -6,6 +6,7 @@ use crate::{ primitives::Note, }; use ff::{BitIterator, PrimeField, PrimeFieldRepr}; +use lazy_static::lazy_static; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use rand_core::{CryptoRng, RngCore}; use std::io::{self, Read, Write}; From af7e263bcc22b639637d16a1dc198fded90dae9e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 12 Oct 2018 18:22:58 +0100 Subject: [PATCH 243/330] Build protobufs for compact formats --- Cargo.lock | 27 +++++++++++ zcash_client_backend/.gitignore | 2 + zcash_client_backend/Cargo.toml | 4 ++ zcash_client_backend/build.rs | 11 +++++ .../proto/compact_formats.proto | 47 +++++++++++++++++++ zcash_client_backend/src/lib.rs | 1 + zcash_client_backend/src/proto/mod.rs | 3 ++ 7 files changed, 95 insertions(+) create mode 100644 zcash_client_backend/.gitignore create mode 100644 zcash_client_backend/build.rs create mode 100644 zcash_client_backend/proto/compact_formats.proto create mode 100644 zcash_client_backend/src/proto/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 7a33a24..d87e43d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -467,6 +467,28 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "protobuf" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "protobuf-codegen" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "protobuf-codegen-pure" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf-codegen 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "1.0.2" @@ -607,6 +629,8 @@ version = "0.1.0" dependencies = [ "bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.15.0", + "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf-codegen-pure 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "zcash_primitives 0.1.0", @@ -700,6 +724,9 @@ dependencies = [ "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e688f31d92ffd7c1ddc57a1b4e6d773c0f2a14ee437a4b0a4f5a69c80eb221c8" "checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8" +"checksum protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40361836defdd5871ff7e84096c6f6444af7fc157f8ef1789f54f147687caa20" +"checksum protobuf-codegen 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "12c6abd78435445fc86898ebbd0521a68438063d4a73e23527b7134e6bf58b4a" +"checksum protobuf-codegen-pure 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c1646acda5319f5b28b0bff4a484324df43ddae2c0f5a3f3e63c0b26095cd600" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" diff --git a/zcash_client_backend/.gitignore b/zcash_client_backend/.gitignore new file mode 100644 index 0000000..7025829 --- /dev/null +++ b/zcash_client_backend/.gitignore @@ -0,0 +1,2 @@ +# Protobufs +src/proto/ diff --git a/zcash_client_backend/Cargo.toml b/zcash_client_backend/Cargo.toml index 7594630..9e6430b 100644 --- a/zcash_client_backend/Cargo.toml +++ b/zcash_client_backend/Cargo.toml @@ -14,8 +14,12 @@ edition = "2018" [dependencies] bech32 = "0.7" pairing = { version = "0.15.0", path = "../pairing" } +protobuf = "2" zcash_primitives = { version = "0.1.0", path = "../zcash_primitives" } +[build-dependencies] +protobuf-codegen-pure = "2" + [dev-dependencies] rand_core = "0.5" rand_xorshift = "0.2" diff --git a/zcash_client_backend/build.rs b/zcash_client_backend/build.rs new file mode 100644 index 0000000..41e0214 --- /dev/null +++ b/zcash_client_backend/build.rs @@ -0,0 +1,11 @@ +use protobuf_codegen_pure; + +fn main() { + protobuf_codegen_pure::run(protobuf_codegen_pure::Args { + out_dir: "src/proto", + input: &["proto/compact_formats.proto"], + includes: &["proto"], + customize: Default::default(), + }) + .expect("protoc"); +} diff --git a/zcash_client_backend/proto/compact_formats.proto b/zcash_client_backend/proto/compact_formats.proto new file mode 100644 index 0000000..d65b658 --- /dev/null +++ b/zcash_client_backend/proto/compact_formats.proto @@ -0,0 +1,47 @@ +syntax = "proto3"; +package cash.z.wallet.sdk.rpc; +option go_package = "walletrpc"; + +// Remember that proto3 fields are all optional. A field that is not present will be set to its zero value. +// bytes fields of hashes are in canonical little-endian format. + +// CompactBlock is a packaging of ONLY the data from a block that's needed to: +// 1. Detect a payment to your shielded Sapling address +// 2. Detect a spend of your shielded Sapling notes +// 3. Update your witnesses to generate new Sapling spend proofs. +message CompactBlock { + uint32 protoVersion = 1; // the version of this wire format, for storage + uint64 height = 2; // the height of this block + bytes hash = 3; + uint32 time = 4; + bytes header = 5; // (hash and time) OR (full header) + repeated CompactTx vtx = 6; // compact transactions from this block +} + +message CompactTx { + // Index and hash will allow the receiver to call out to chain + // explorers or other data structures to retrieve more information + // about this transaction. + uint64 index = 1; + bytes hash = 2; + + // The transaction fee: present if server can provide. In the case of a + // stateless server and a transaction with transparent inputs, this will be + // unset because the calculation requires reference to prior transactions. + // in a pure-Sapling context, the fee will be calculable as: + // valueBalance + (sum(vPubNew) - sum(vPubOld) - sum(tOut)) + uint32 fee = 3; + + repeated CompactSpend spends = 4; + repeated CompactOutput outputs = 5; +} + +message CompactSpend { + bytes nf = 1; +} + +message CompactOutput { + bytes cmu = 1; + bytes epk = 2; + bytes ciphertext = 3; +} diff --git a/zcash_client_backend/src/lib.rs b/zcash_client_backend/src/lib.rs index 6d1d993..063ab62 100644 --- a/zcash_client_backend/src/lib.rs +++ b/zcash_client_backend/src/lib.rs @@ -9,3 +9,4 @@ pub mod constants; pub mod encoding; pub mod keys; +pub mod proto; diff --git a/zcash_client_backend/src/proto/mod.rs b/zcash_client_backend/src/proto/mod.rs new file mode 100644 index 0000000..e24ef5c --- /dev/null +++ b/zcash_client_backend/src/proto/mod.rs @@ -0,0 +1,3 @@ +//! Generated code for handling light client protobuf structs. + +pub mod compact_formats; From 591b1fc28fb82dbfd874127837745789b400fd86 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 12 Oct 2018 18:24:25 +0100 Subject: [PATCH 244/330] Parse compact blocks to find wallet transactions --- Cargo.lock | 13 ++ zcash_client_backend/Cargo.toml | 3 + zcash_client_backend/src/lib.rs | 2 + zcash_client_backend/src/wallet.rs | 32 ++++ zcash_client_backend/src/welding_rig.rs | 194 ++++++++++++++++++++++++ 5 files changed, 244 insertions(+) create mode 100644 zcash_client_backend/src/wallet.rs create mode 100644 zcash_client_backend/src/welding_rig.rs diff --git a/Cargo.lock b/Cargo.lock index d87e43d..75ff772 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -534,6 +534,15 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_os" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_xorshift" version = "0.2.0" @@ -628,10 +637,13 @@ name = "zcash_client_backend" version = "0.1.0" dependencies = [ "bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ff 0.5.0", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.15.0", "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf-codegen-pure 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "zcash_primitives 0.1.0", ] @@ -732,6 +744,7 @@ dependencies = [ "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a" "checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" diff --git a/zcash_client_backend/Cargo.toml b/zcash_client_backend/Cargo.toml index 9e6430b..e639efd 100644 --- a/zcash_client_backend/Cargo.toml +++ b/zcash_client_backend/Cargo.toml @@ -13,6 +13,8 @@ edition = "2018" [dependencies] bech32 = "0.7" +ff = { version = "0.5.0", path = "../ff" } +hex = "0.3" pairing = { version = "0.15.0", path = "../pairing" } protobuf = "2" zcash_primitives = { version = "0.1.0", path = "../zcash_primitives" } @@ -22,6 +24,7 @@ protobuf-codegen-pure = "2" [dev-dependencies] rand_core = "0.5" +rand_os = "0.2" rand_xorshift = "0.2" [badges] diff --git a/zcash_client_backend/src/lib.rs b/zcash_client_backend/src/lib.rs index 063ab62..87a808c 100644 --- a/zcash_client_backend/src/lib.rs +++ b/zcash_client_backend/src/lib.rs @@ -10,3 +10,5 @@ pub mod constants; pub mod encoding; pub mod keys; pub mod proto; +pub mod wallet; +pub mod welding_rig; diff --git a/zcash_client_backend/src/wallet.rs b/zcash_client_backend/src/wallet.rs new file mode 100644 index 0000000..4e85eef --- /dev/null +++ b/zcash_client_backend/src/wallet.rs @@ -0,0 +1,32 @@ +//! Structs representing transaction data scanned from the block chain by a wallet or +//! light client. + +use pairing::bls12_381::{Bls12, Fr}; +use zcash_primitives::{ + jubjub::{edwards, PrimeOrder}, + transaction::TxId, +}; + +pub struct EncCiphertextFrag(pub [u8; 52]); + +/// A subset of a [`Transaction`] relevant to wallets and light clients. +/// +/// [`Transaction`]: zcash_primitives::transaction::Transaction +pub struct WalletTx { + pub txid: TxId, + pub num_spends: usize, + pub num_outputs: usize, + pub shielded_outputs: Vec, +} + +/// A subset of an [`OutputDescription`] relevant to wallets and light clients. +/// +/// [`OutputDescription`]: zcash_primitives::transaction::components::OutputDescription +pub struct WalletShieldedOutput { + pub index: usize, + pub cmu: Fr, + pub epk: edwards::Point, + pub enc_ct: EncCiphertextFrag, + pub account: usize, + pub value: u64, +} diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs new file mode 100644 index 0000000..cac83ff --- /dev/null +++ b/zcash_client_backend/src/welding_rig.rs @@ -0,0 +1,194 @@ +//! Tools for scanning a compact representation of the Zcash block chain. + +use ff::{PrimeField, PrimeFieldRepr}; +use pairing::bls12_381::{Bls12, Fr, FrRepr}; +use zcash_primitives::{ + jubjub::{edwards, fs::Fs}, + note_encryption::try_sapling_compact_note_decryption, + transaction::TxId, + zip32::ExtendedFullViewingKey, + JUBJUB, +}; + +use crate::proto::compact_formats::{CompactBlock, CompactOutput, CompactTx}; +use crate::wallet::{EncCiphertextFrag, WalletShieldedOutput, WalletTx}; + +/// Scans a [`CompactOutput`] with a set of [`ExtendedFullViewingKey`]s. +/// +/// Returns a [`WalletShieldedOutput`] if this output belongs to any of the given +/// [`ExtendedFullViewingKey`]s. +fn scan_output( + (index, output): (usize, CompactOutput), + ivks: &[Fs], +) -> Option { + let mut repr = FrRepr::default(); + if repr.read_le(&output.cmu[..]).is_err() { + return None; + } + let cmu = match Fr::from_repr(repr) { + Ok(cmu) => cmu, + Err(_) => return None, + }; + + let epk = match edwards::Point::::read(&output.epk[..], &JUBJUB) { + Ok(p) => match p.as_prime_order(&JUBJUB) { + Some(epk) => epk, + None => return None, + }, + Err(_) => return None, + }; + + let ct = output.ciphertext; + + for (account, ivk) in ivks.iter().enumerate() { + let value = match try_sapling_compact_note_decryption(ivk, &epk, &cmu, &ct) { + Some((note, _)) => note.value, + None => continue, + }; + + // It's ours, so let's copy the ciphertext fragment and return + let mut enc_ct = EncCiphertextFrag([0u8; 52]); + enc_ct.0.copy_from_slice(&ct); + + return Some(WalletShieldedOutput { + index, + cmu, + epk, + enc_ct, + account, + value, + }); + } + None +} + +/// Scans a [`CompactTx`] with a set of [`ExtendedFullViewingKey`]s. +/// +/// Returns a [`WalletTx`] if this transaction belongs to any of the given +/// [`ExtendedFullViewingKey`]s. +fn scan_tx(tx: CompactTx, extfvks: &[ExtendedFullViewingKey]) -> Option { + let num_spends = tx.spends.len(); + let num_outputs = tx.outputs.len(); + + // Check for incoming notes + let shielded_outputs: Vec = { + let ivks: Vec<_> = extfvks.iter().map(|extfvk| extfvk.fvk.vk.ivk()).collect(); + tx.outputs + .into_iter() + .enumerate() + .filter_map(|(index, output)| scan_output((index, output), &ivks)) + .collect() + }; + + if shielded_outputs.is_empty() { + None + } else { + let mut txid = TxId([0u8; 32]); + txid.0.copy_from_slice(&tx.hash); + Some(WalletTx { + txid, + num_spends, + num_outputs, + shielded_outputs, + }) + } +} + +/// Scans a [`CompactBlock`] for transactions belonging to a set of +/// [`ExtendedFullViewingKey`]s. +/// +/// Returns a vector of [`WalletTx`]s belonging to any of the given +/// [`ExtendedFullViewingKey`]s. +pub fn scan_block(block: CompactBlock, extfvks: &[ExtendedFullViewingKey]) -> Vec { + block + .vtx + .into_iter() + .filter_map(|tx| scan_tx(tx, extfvks)) + .collect() +} + +#[cfg(test)] +mod tests { + use ff::{Field, PrimeField, PrimeFieldRepr}; + use pairing::bls12_381::Bls12; + use rand_core::RngCore; + use rand_os::OsRng; + use zcash_primitives::{ + jubjub::fs::Fs, + note_encryption::{Memo, SaplingNoteEncryption}, + primitives::Note, + transaction::components::Amount, + zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}, + JUBJUB, + }; + + use super::scan_block; + use crate::proto::compact_formats::{CompactBlock, CompactOutput, CompactTx}; + + /// Create a fake CompactBlock at the given height, containing a single output paying + /// the given address. Returns the CompactBlock and the nullifier for the new note. + fn fake_compact_block( + height: i32, + extfvk: ExtendedFullViewingKey, + value: Amount, + ) -> CompactBlock { + let to = extfvk.default_address().unwrap().1; + + // Create a fake Note for the account + let mut rng = OsRng; + let note = Note { + g_d: to.diversifier().g_d::(&JUBJUB).unwrap(), + pk_d: to.pk_d().clone(), + value: value.into(), + r: Fs::random(&mut rng), + }; + let encryptor = SaplingNoteEncryption::new( + extfvk.fvk.ovk, + note.clone(), + to.clone(), + Memo::default(), + &mut rng, + ); + let mut cmu = vec![]; + note.cm(&JUBJUB).into_repr().write_le(&mut cmu).unwrap(); + let mut epk = vec![]; + encryptor.epk().write(&mut epk).unwrap(); + let enc_ciphertext = encryptor.encrypt_note_plaintext(); + + // Create a fake CompactBlock containing the note + let mut cb = CompactBlock::new(); + cb.set_height(height as u64); + + let mut cout = CompactOutput::new(); + cout.set_cmu(cmu); + cout.set_epk(epk); + cout.set_ciphertext(enc_ciphertext[..52].to_vec()); + let mut ctx = CompactTx::new(); + let mut txid = vec![0; 32]; + rng.fill_bytes(&mut txid); + ctx.set_hash(txid); + ctx.outputs.push(cout); + cb.vtx.push(ctx); + + cb + } + + #[test] + fn scan_block_with_my_tx() { + let extsk = ExtendedSpendingKey::master(&[]); + let extfvk = ExtendedFullViewingKey::from(&extsk); + + let cb = fake_compact_block(1, extfvk.clone(), Amount::from_u64(5).unwrap()); + + let txs = scan_block(cb, &[extfvk]); + assert_eq!(txs.len(), 1); + + let tx = &txs[0]; + assert_eq!(tx.num_spends, 0); + assert_eq!(tx.num_outputs, 1); + assert_eq!(tx.shielded_outputs.len(), 1); + assert_eq!(tx.shielded_outputs[0].index, 0); + assert_eq!(tx.shielded_outputs[0].account, 0); + assert_eq!(tx.shielded_outputs[0].value, 5); + } +} From f899ecfce5bc09f6e6a50fd4aadc5dc5b70925d1 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 2 Dec 2018 12:14:02 +0000 Subject: [PATCH 245/330] Increment the commitment tree and witnesses while scanning blocks --- zcash_client_backend/src/welding_rig.rs | 180 ++++++++++++++++-------- 1 file changed, 123 insertions(+), 57 deletions(-) diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index cac83ff..73a1666 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -4,23 +4,31 @@ use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use zcash_primitives::{ jubjub::{edwards, fs::Fs}, + merkle_tree::{CommitmentTree, IncrementalWitness}, note_encryption::try_sapling_compact_note_decryption, + sapling::Node, transaction::TxId, zip32::ExtendedFullViewingKey, JUBJUB, }; -use crate::proto::compact_formats::{CompactBlock, CompactOutput, CompactTx}; +use crate::proto::compact_formats::{CompactBlock, CompactOutput}; use crate::wallet::{EncCiphertextFrag, WalletShieldedOutput, WalletTx}; /// Scans a [`CompactOutput`] with a set of [`ExtendedFullViewingKey`]s. /// -/// Returns a [`WalletShieldedOutput`] if this output belongs to any of the given -/// [`ExtendedFullViewingKey`]s. +/// Returns a [`WalletShieldedOutput`] and corresponding [`IncrementalWitness`] if this +/// output belongs to any of the given [`ExtendedFullViewingKey`]s. +/// +/// The given [`CommitmentTree`] and existing [`IncrementalWitness`]es are incremented +/// with this output's commitment. fn scan_output( (index, output): (usize, CompactOutput), ivks: &[Fs], -) -> Option { + tree: &mut CommitmentTree, + existing_witnesses: &mut [&mut IncrementalWitness], + new_witnesses: &mut [IncrementalWitness], +) -> Option<(WalletShieldedOutput, IncrementalWitness)> { let mut repr = FrRepr::default(); if repr.read_le(&output.cmu[..]).is_err() { return None; @@ -40,6 +48,16 @@ fn scan_output( let ct = output.ciphertext; + // Increment tree and witnesses + let node = Node::new(cmu.into_repr()); + for witness in existing_witnesses { + witness.append(node).unwrap(); + } + for witness in new_witnesses { + witness.append(node).unwrap(); + } + tree.append(node).unwrap(); + for (account, ivk) in ivks.iter().enumerate() { let value = match try_sapling_compact_note_decryption(ivk, &epk, &cmu, &ct) { Some((note, _)) => note.value, @@ -50,71 +68,80 @@ fn scan_output( let mut enc_ct = EncCiphertextFrag([0u8; 52]); enc_ct.0.copy_from_slice(&ct); - return Some(WalletShieldedOutput { - index, - cmu, - epk, - enc_ct, - account, - value, - }); + return Some(( + WalletShieldedOutput { + index, + cmu, + epk, + enc_ct, + account, + value, + }, + IncrementalWitness::from_tree(tree), + )); } None } -/// Scans a [`CompactTx`] with a set of [`ExtendedFullViewingKey`]s. -/// -/// Returns a [`WalletTx`] if this transaction belongs to any of the given -/// [`ExtendedFullViewingKey`]s. -fn scan_tx(tx: CompactTx, extfvks: &[ExtendedFullViewingKey]) -> Option { - let num_spends = tx.spends.len(); - let num_outputs = tx.outputs.len(); - - // Check for incoming notes - let shielded_outputs: Vec = { - let ivks: Vec<_> = extfvks.iter().map(|extfvk| extfvk.fvk.vk.ivk()).collect(); - tx.outputs - .into_iter() - .enumerate() - .filter_map(|(index, output)| scan_output((index, output), &ivks)) - .collect() - }; - - if shielded_outputs.is_empty() { - None - } else { - let mut txid = TxId([0u8; 32]); - txid.0.copy_from_slice(&tx.hash); - Some(WalletTx { - txid, - num_spends, - num_outputs, - shielded_outputs, - }) - } -} - -/// Scans a [`CompactBlock`] for transactions belonging to a set of -/// [`ExtendedFullViewingKey`]s. +/// Scans a [`CompactBlock`] with a set of [`ExtendedFullViewingKey`]s. /// /// Returns a vector of [`WalletTx`]s belonging to any of the given -/// [`ExtendedFullViewingKey`]s. -pub fn scan_block(block: CompactBlock, extfvks: &[ExtendedFullViewingKey]) -> Vec { - block - .vtx - .into_iter() - .filter_map(|tx| scan_tx(tx, extfvks)) - .collect() +/// [`ExtendedFullViewingKey`]s, and the corresponding new [`IncrementalWitness`]es. +/// +/// The given [`CommitmentTree`] and existing [`IncrementalWitness`]es are +/// incremented appropriately. +pub fn scan_block( + block: CompactBlock, + extfvks: &[ExtendedFullViewingKey], + tree: &mut CommitmentTree, + existing_witnesses: &mut [&mut IncrementalWitness], +) -> Vec<(WalletTx, Vec>)> { + let mut wtxs = vec![]; + let ivks: Vec<_> = extfvks.iter().map(|extfvk| extfvk.fvk.vk.ivk()).collect(); + + for tx in block.vtx.into_iter() { + let num_spends = tx.spends.len(); + let num_outputs = tx.outputs.len(); + + // Check for incoming notes while incrementing tree and witnesses + let mut shielded_outputs = vec![]; + let mut new_witnesses = vec![]; + for to_scan in tx.outputs.into_iter().enumerate() { + if let Some((output, new_witness)) = + scan_output(to_scan, &ivks, tree, existing_witnesses, &mut new_witnesses) + { + shielded_outputs.push(output); + new_witnesses.push(new_witness); + } + } + + if !shielded_outputs.is_empty() { + let mut txid = TxId([0u8; 32]); + txid.0.copy_from_slice(&tx.hash); + wtxs.push(( + WalletTx { + txid, + num_spends, + num_outputs, + shielded_outputs, + }, + new_witnesses, + )); + } + } + + wtxs } #[cfg(test)] mod tests { use ff::{Field, PrimeField, PrimeFieldRepr}; - use pairing::bls12_381::Bls12; + use pairing::bls12_381::{Bls12, Fr}; use rand_core::RngCore; use rand_os::OsRng; use zcash_primitives::{ - jubjub::fs::Fs, + jubjub::{fs::Fs, FixedGenerators, JubjubParams, ToUniform}, + merkle_tree::CommitmentTree, note_encryption::{Memo, SaplingNoteEncryption}, primitives::Note, transaction::components::Amount, @@ -125,6 +152,36 @@ mod tests { use super::scan_block; use crate::proto::compact_formats::{CompactBlock, CompactOutput, CompactTx}; + fn random_compact_tx(rng: &mut R) -> CompactTx { + let fake_cmu = { + let fake_cmu = Fr::random(rng); + let mut bytes = vec![]; + fake_cmu.into_repr().write_le(&mut bytes).unwrap(); + bytes + }; + let fake_epk = { + let mut buffer = vec![0; 64]; + rng.fill_bytes(&mut buffer); + let fake_esk = Fs::to_uniform(&buffer[..]); + let fake_epk = JUBJUB + .generator(FixedGenerators::SpendingKeyGenerator) + .mul(fake_esk, &JUBJUB); + let mut bytes = vec![]; + fake_epk.write(&mut bytes).unwrap(); + bytes + }; + let mut cout = CompactOutput::new(); + cout.set_cmu(fake_cmu); + cout.set_epk(fake_epk); + cout.set_ciphertext(vec![0; 52]); + let mut ctx = CompactTx::new(); + let mut txid = vec![0; 32]; + rng.fill_bytes(&mut txid); + ctx.set_hash(txid); + ctx.outputs.push(cout); + ctx + } + /// Create a fake CompactBlock at the given height, containing a single output paying /// the given address. Returns the CompactBlock and the nullifier for the new note. fn fake_compact_block( @@ -159,6 +216,9 @@ mod tests { let mut cb = CompactBlock::new(); cb.set_height(height as u64); + // Add a random Sapling tx before ours + cb.vtx.push(random_compact_tx(&mut rng)); + let mut cout = CompactOutput::new(); cout.set_cmu(cmu); cout.set_epk(epk); @@ -179,16 +239,22 @@ mod tests { let extfvk = ExtendedFullViewingKey::from(&extsk); let cb = fake_compact_block(1, extfvk.clone(), Amount::from_u64(5).unwrap()); + assert_eq!(cb.vtx.len(), 2); - let txs = scan_block(cb, &[extfvk]); + let mut tree = CommitmentTree::new(); + let txs = scan_block(cb, &[extfvk], &mut tree, &mut []); assert_eq!(txs.len(), 1); - let tx = &txs[0]; + let (tx, new_witnesses) = &txs[0]; assert_eq!(tx.num_spends, 0); assert_eq!(tx.num_outputs, 1); assert_eq!(tx.shielded_outputs.len(), 1); assert_eq!(tx.shielded_outputs[0].index, 0); assert_eq!(tx.shielded_outputs[0].account, 0); assert_eq!(tx.shielded_outputs[0].value, 5); + + // Check that the witness root matches + assert_eq!(new_witnesses.len(), 1); + assert_eq!(new_witnesses[0].root(), tree.root()); } } From 2b71121681f8d310420b9303ee69f30c9f910d3e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 2 Dec 2018 19:15:04 +0000 Subject: [PATCH 246/330] Return the entire note and recipient address when scanning an output --- zcash_client_backend/src/wallet.rs | 7 +++---- zcash_client_backend/src/welding_rig.rs | 16 ++++++---------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/zcash_client_backend/src/wallet.rs b/zcash_client_backend/src/wallet.rs index 4e85eef..a20b09f 100644 --- a/zcash_client_backend/src/wallet.rs +++ b/zcash_client_backend/src/wallet.rs @@ -4,11 +4,10 @@ use pairing::bls12_381::{Bls12, Fr}; use zcash_primitives::{ jubjub::{edwards, PrimeOrder}, + primitives::{Note, PaymentAddress}, transaction::TxId, }; -pub struct EncCiphertextFrag(pub [u8; 52]); - /// A subset of a [`Transaction`] relevant to wallets and light clients. /// /// [`Transaction`]: zcash_primitives::transaction::Transaction @@ -26,7 +25,7 @@ pub struct WalletShieldedOutput { pub index: usize, pub cmu: Fr, pub epk: edwards::Point, - pub enc_ct: EncCiphertextFrag, pub account: usize, - pub value: u64, + pub note: Note, + pub to: PaymentAddress, } diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index 73a1666..2e6f2b2 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -13,7 +13,7 @@ use zcash_primitives::{ }; use crate::proto::compact_formats::{CompactBlock, CompactOutput}; -use crate::wallet::{EncCiphertextFrag, WalletShieldedOutput, WalletTx}; +use crate::wallet::{WalletShieldedOutput, WalletTx}; /// Scans a [`CompactOutput`] with a set of [`ExtendedFullViewingKey`]s. /// @@ -59,23 +59,19 @@ fn scan_output( tree.append(node).unwrap(); for (account, ivk) in ivks.iter().enumerate() { - let value = match try_sapling_compact_note_decryption(ivk, &epk, &cmu, &ct) { - Some((note, _)) => note.value, + let (note, to) = match try_sapling_compact_note_decryption(ivk, &epk, &cmu, &ct) { + Some(ret) => ret, None => continue, }; - // It's ours, so let's copy the ciphertext fragment and return - let mut enc_ct = EncCiphertextFrag([0u8; 52]); - enc_ct.0.copy_from_slice(&ct); - return Some(( WalletShieldedOutput { index, cmu, epk, - enc_ct, account, - value, + note, + to, }, IncrementalWitness::from_tree(tree), )); @@ -251,7 +247,7 @@ mod tests { assert_eq!(tx.shielded_outputs.len(), 1); assert_eq!(tx.shielded_outputs[0].index, 0); assert_eq!(tx.shielded_outputs[0].account, 0); - assert_eq!(tx.shielded_outputs[0].value, 5); + assert_eq!(tx.shielded_outputs[0].note.value, 5); // Check that the witness root matches assert_eq!(new_witnesses.len(), 1); From fb9e9bb12f316a5970a3370aa49d3b5414118c66 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 4 Dec 2018 14:03:12 +0000 Subject: [PATCH 247/330] Check for spent notes while scanning blocks --- zcash_client_backend/src/wallet.rs | 9 ++++ zcash_client_backend/src/welding_rig.rs | 72 ++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 8 deletions(-) diff --git a/zcash_client_backend/src/wallet.rs b/zcash_client_backend/src/wallet.rs index a20b09f..c120ba5 100644 --- a/zcash_client_backend/src/wallet.rs +++ b/zcash_client_backend/src/wallet.rs @@ -15,9 +15,18 @@ pub struct WalletTx { pub txid: TxId, pub num_spends: usize, pub num_outputs: usize, + pub shielded_spends: Vec, pub shielded_outputs: Vec, } +/// A subset of a [`SpendDescription`] relevant to wallets and light clients. +/// +/// [`SpendDescription`]: zcash_primitives::transaction::components::SpendDescription +pub struct WalletShieldedSpend { + pub index: usize, + pub nf: Vec, +} + /// A subset of an [`OutputDescription`] relevant to wallets and light clients. /// /// [`OutputDescription`]: zcash_primitives::transaction::components::OutputDescription diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index 2e6f2b2..0b5a01f 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -13,7 +13,7 @@ use zcash_primitives::{ }; use crate::proto::compact_formats::{CompactBlock, CompactOutput}; -use crate::wallet::{WalletShieldedOutput, WalletTx}; +use crate::wallet::{WalletShieldedOutput, WalletShieldedSpend, WalletTx}; /// Scans a [`CompactOutput`] with a set of [`ExtendedFullViewingKey`]s. /// @@ -89,6 +89,7 @@ fn scan_output( pub fn scan_block( block: CompactBlock, extfvks: &[ExtendedFullViewingKey], + nullifiers: &[&[u8]], tree: &mut CommitmentTree, existing_witnesses: &mut [&mut IncrementalWitness], ) -> Vec<(WalletTx, Vec>)> { @@ -99,6 +100,23 @@ pub fn scan_block( let num_spends = tx.spends.len(); let num_outputs = tx.outputs.len(); + // Check for spent notes + let shielded_spends: Vec<_> = tx + .spends + .into_iter() + .enumerate() + .filter_map(|(index, spend)| { + if nullifiers.contains(&&spend.nf[..]) { + Some(WalletShieldedSpend { + index, + nf: spend.nf, + }) + } else { + None + } + }) + .collect(); + // Check for incoming notes while incrementing tree and witnesses let mut shielded_outputs = vec![]; let mut new_witnesses = vec![]; @@ -111,7 +129,7 @@ pub fn scan_block( } } - if !shielded_outputs.is_empty() { + if !(shielded_spends.is_empty() && shielded_outputs.is_empty()) { let mut txid = TxId([0u8; 32]); txid.0.copy_from_slice(&tx.hash); wtxs.push(( @@ -119,6 +137,7 @@ pub fn scan_block( txid, num_spends, num_outputs, + shielded_spends, shielded_outputs, }, new_witnesses, @@ -146,9 +165,14 @@ mod tests { }; use super::scan_block; - use crate::proto::compact_formats::{CompactBlock, CompactOutput, CompactTx}; + use crate::proto::compact_formats::{CompactBlock, CompactOutput, CompactSpend, CompactTx}; fn random_compact_tx(rng: &mut R) -> CompactTx { + let fake_nf = { + let mut nf = vec![0; 32]; + rng.fill_bytes(&mut nf); + nf + }; let fake_cmu = { let fake_cmu = Fr::random(rng); let mut bytes = vec![]; @@ -166,6 +190,8 @@ mod tests { fake_epk.write(&mut bytes).unwrap(); bytes }; + let mut cspend = CompactSpend::new(); + cspend.set_nf(fake_nf); let mut cout = CompactOutput::new(); cout.set_cmu(fake_cmu); cout.set_epk(fake_epk); @@ -174,14 +200,17 @@ mod tests { let mut txid = vec![0; 32]; rng.fill_bytes(&mut txid); ctx.set_hash(txid); + ctx.spends.push(cspend); ctx.outputs.push(cout); ctx } - /// Create a fake CompactBlock at the given height, containing a single output paying - /// the given address. Returns the CompactBlock and the nullifier for the new note. + /// Create a fake CompactBlock at the given height, with a transaction containing a + /// single spend of the given nullifier and a single output paying the given address. + /// Returns the CompactBlock. fn fake_compact_block( height: i32, + nf: [u8; 32], extfvk: ExtendedFullViewingKey, value: Amount, ) -> CompactBlock { @@ -215,6 +244,8 @@ mod tests { // Add a random Sapling tx before ours cb.vtx.push(random_compact_tx(&mut rng)); + let mut cspend = CompactSpend::new(); + cspend.set_nf(nf.to_vec()); let mut cout = CompactOutput::new(); cout.set_cmu(cmu); cout.set_epk(epk); @@ -223,6 +254,7 @@ mod tests { let mut txid = vec![0; 32]; rng.fill_bytes(&mut txid); ctx.set_hash(txid); + ctx.spends.push(cspend); ctx.outputs.push(cout); cb.vtx.push(ctx); @@ -234,16 +266,17 @@ mod tests { let extsk = ExtendedSpendingKey::master(&[]); let extfvk = ExtendedFullViewingKey::from(&extsk); - let cb = fake_compact_block(1, extfvk.clone(), Amount::from_u64(5).unwrap()); + let cb = fake_compact_block(1, [0; 32], extfvk.clone(), Amount::from_u64(5).unwrap()); assert_eq!(cb.vtx.len(), 2); let mut tree = CommitmentTree::new(); - let txs = scan_block(cb, &[extfvk], &mut tree, &mut []); + let txs = scan_block(cb, &[extfvk], &[], &mut tree, &mut []); assert_eq!(txs.len(), 1); let (tx, new_witnesses) = &txs[0]; - assert_eq!(tx.num_spends, 0); + assert_eq!(tx.num_spends, 1); assert_eq!(tx.num_outputs, 1); + assert_eq!(tx.shielded_spends.len(), 0); assert_eq!(tx.shielded_outputs.len(), 1); assert_eq!(tx.shielded_outputs[0].index, 0); assert_eq!(tx.shielded_outputs[0].account, 0); @@ -253,4 +286,27 @@ mod tests { assert_eq!(new_witnesses.len(), 1); assert_eq!(new_witnesses[0].root(), tree.root()); } + + #[test] + fn scan_block_with_my_spend() { + let extsk = ExtendedSpendingKey::master(&[]); + let extfvk = ExtendedFullViewingKey::from(&extsk); + let nf = [7; 32]; + + let cb = fake_compact_block(1, nf, extfvk, Amount::from_u64(5).unwrap()); + assert_eq!(cb.vtx.len(), 2); + + let mut tree = CommitmentTree::new(); + let txs = scan_block(cb, &[], &[&nf], &mut tree, &mut []); + assert_eq!(txs.len(), 1); + + let (tx, new_witnesses) = &txs[0]; + assert_eq!(tx.num_spends, 1); + assert_eq!(tx.num_outputs, 1); + assert_eq!(tx.shielded_spends.len(), 1); + assert_eq!(tx.shielded_outputs.len(), 0); + assert_eq!(tx.shielded_spends[0].index, 0); + assert_eq!(tx.shielded_spends[0].nf, nf); + assert_eq!(new_witnesses.len(), 0); + } } From 3b9dfc1e0b4b2bd8912546d2215e1c471e73fe82 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 11 Jan 2019 14:26:54 -0800 Subject: [PATCH 248/330] Detect change notes while scanning blocks --- zcash_client_backend/src/wallet.rs | 2 + zcash_client_backend/src/welding_rig.rs | 69 ++++++++++++++++++------- 2 files changed, 51 insertions(+), 20 deletions(-) diff --git a/zcash_client_backend/src/wallet.rs b/zcash_client_backend/src/wallet.rs index c120ba5..22df1cb 100644 --- a/zcash_client_backend/src/wallet.rs +++ b/zcash_client_backend/src/wallet.rs @@ -25,6 +25,7 @@ pub struct WalletTx { pub struct WalletShieldedSpend { pub index: usize, pub nf: Vec, + pub account: usize, } /// A subset of an [`OutputDescription`] relevant to wallets and light clients. @@ -37,4 +38,5 @@ pub struct WalletShieldedOutput { pub account: usize, pub note: Note, pub to: PaymentAddress, + pub is_change: bool, } diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index 0b5a01f..b8310e3 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -2,6 +2,7 @@ use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; +use std::collections::HashSet; use zcash_primitives::{ jubjub::{edwards, fs::Fs}, merkle_tree::{CommitmentTree, IncrementalWitness}, @@ -25,6 +26,7 @@ use crate::wallet::{WalletShieldedOutput, WalletShieldedSpend, WalletTx}; fn scan_output( (index, output): (usize, CompactOutput), ivks: &[Fs], + spent_from_accounts: &HashSet, tree: &mut CommitmentTree, existing_witnesses: &mut [&mut IncrementalWitness], new_witnesses: &mut [IncrementalWitness], @@ -64,6 +66,14 @@ fn scan_output( None => continue, }; + // A note is marked as "change" if the account that received it + // also spent notes in the same transaction. This will catch, + // for instance: + // - Change created by spending fractions of notes. + // - Notes created by consolidation transactions. + // - Notes sent from one account to itself. + let is_change = spent_from_accounts.contains(&account); + return Some(( WalletShieldedOutput { index, @@ -72,6 +82,7 @@ fn scan_output( account, note, to, + is_change, }, IncrementalWitness::from_tree(tree), )); @@ -89,7 +100,7 @@ fn scan_output( pub fn scan_block( block: CompactBlock, extfvks: &[ExtendedFullViewingKey], - nullifiers: &[&[u8]], + nullifiers: &[(&[u8], usize)], tree: &mut CommitmentTree, existing_witnesses: &mut [&mut IncrementalWitness], ) -> Vec<(WalletTx, Vec>)> { @@ -101,29 +112,45 @@ pub fn scan_block( let num_outputs = tx.outputs.len(); // Check for spent notes - let shielded_spends: Vec<_> = tx - .spends - .into_iter() - .enumerate() - .filter_map(|(index, spend)| { - if nullifiers.contains(&&spend.nf[..]) { - Some(WalletShieldedSpend { - index, - nf: spend.nf, - }) - } else { - None - } - }) - .collect(); + let shielded_spends: Vec<_> = + tx.spends + .into_iter() + .enumerate() + .filter_map(|(index, spend)| { + if let Some(account) = nullifiers.iter().find_map(|&(nf, acc)| { + if nf == &spend.nf[..] { + Some(acc) + } else { + None + } + }) { + Some(WalletShieldedSpend { + index, + nf: spend.nf, + account, + }) + } else { + None + } + }) + .collect(); + + // Collect the set of accounts that were spent from in this transaction + let spent_from_accounts: HashSet<_> = + shielded_spends.iter().map(|spend| spend.account).collect(); // Check for incoming notes while incrementing tree and witnesses let mut shielded_outputs = vec![]; let mut new_witnesses = vec![]; for to_scan in tx.outputs.into_iter().enumerate() { - if let Some((output, new_witness)) = - scan_output(to_scan, &ivks, tree, existing_witnesses, &mut new_witnesses) - { + if let Some((output, new_witness)) = scan_output( + to_scan, + &ivks, + &spent_from_accounts, + tree, + existing_witnesses, + &mut new_witnesses, + ) { shielded_outputs.push(output); new_witnesses.push(new_witness); } @@ -292,12 +319,13 @@ mod tests { let extsk = ExtendedSpendingKey::master(&[]); let extfvk = ExtendedFullViewingKey::from(&extsk); let nf = [7; 32]; + let account = 12; let cb = fake_compact_block(1, nf, extfvk, Amount::from_u64(5).unwrap()); assert_eq!(cb.vtx.len(), 2); let mut tree = CommitmentTree::new(); - let txs = scan_block(cb, &[], &[&nf], &mut tree, &mut []); + let txs = scan_block(cb, &[], &[(&nf, account)], &mut tree, &mut []); assert_eq!(txs.len(), 1); let (tx, new_witnesses) = &txs[0]; @@ -307,6 +335,7 @@ mod tests { assert_eq!(tx.shielded_outputs.len(), 0); assert_eq!(tx.shielded_spends[0].index, 0); assert_eq!(tx.shielded_spends[0].nf, nf); + assert_eq!(tx.shielded_spends[0].account, account); assert_eq!(new_witnesses.len(), 0); } } From e746f7b6f9b7f9e01104b58f24fc43c1f4a622e3 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 24 Jan 2019 23:26:14 +0000 Subject: [PATCH 249/330] Add tx index within block to WalletTx struct --- zcash_client_backend/src/wallet.rs | 1 + zcash_client_backend/src/welding_rig.rs | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/zcash_client_backend/src/wallet.rs b/zcash_client_backend/src/wallet.rs index 22df1cb..dd5229b 100644 --- a/zcash_client_backend/src/wallet.rs +++ b/zcash_client_backend/src/wallet.rs @@ -13,6 +13,7 @@ use zcash_primitives::{ /// [`Transaction`]: zcash_primitives::transaction::Transaction pub struct WalletTx { pub txid: TxId, + pub index: usize, pub num_spends: usize, pub num_outputs: usize, pub shielded_spends: Vec, diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index b8310e3..27d29bb 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -162,6 +162,7 @@ pub fn scan_block( wtxs.push(( WalletTx { txid, + index: tx.index as usize, num_spends, num_outputs, shielded_spends, @@ -269,7 +270,11 @@ mod tests { cb.set_height(height as u64); // Add a random Sapling tx before ours - cb.vtx.push(random_compact_tx(&mut rng)); + { + let mut tx = random_compact_tx(&mut rng); + tx.index = cb.vtx.len() as u64; + cb.vtx.push(tx); + } let mut cspend = CompactSpend::new(); cspend.set_nf(nf.to_vec()); @@ -283,6 +288,7 @@ mod tests { ctx.set_hash(txid); ctx.spends.push(cspend); ctx.outputs.push(cout); + ctx.index = cb.vtx.len() as u64; cb.vtx.push(ctx); cb @@ -301,6 +307,7 @@ mod tests { assert_eq!(txs.len(), 1); let (tx, new_witnesses) = &txs[0]; + assert_eq!(tx.index, 1); assert_eq!(tx.num_spends, 1); assert_eq!(tx.num_outputs, 1); assert_eq!(tx.shielded_spends.len(), 0); @@ -329,6 +336,7 @@ mod tests { assert_eq!(txs.len(), 1); let (tx, new_witnesses) = &txs[0]; + assert_eq!(tx.index, 1); assert_eq!(tx.num_spends, 1); assert_eq!(tx.num_outputs, 1); assert_eq!(tx.shielded_spends.len(), 1); From b66ac117759281c2c3ff3f8ac430e3f98f8807d1 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 14 Feb 2019 18:06:50 +0000 Subject: [PATCH 250/330] Update new witnesses with subsequent transactions in the same block --- zcash_client_backend/src/welding_rig.rs | 91 +++++++++++++++++++++---- 1 file changed, 77 insertions(+), 14 deletions(-) diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index 27d29bb..e3f9d8b 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -29,6 +29,7 @@ fn scan_output( spent_from_accounts: &HashSet, tree: &mut CommitmentTree, existing_witnesses: &mut [&mut IncrementalWitness], + block_witnesses: &mut [&mut IncrementalWitness], new_witnesses: &mut [IncrementalWitness], ) -> Option<(WalletShieldedOutput, IncrementalWitness)> { let mut repr = FrRepr::default(); @@ -55,6 +56,9 @@ fn scan_output( for witness in existing_witnesses { witness.append(node).unwrap(); } + for witness in block_witnesses { + witness.append(node).unwrap(); + } for witness in new_witnesses { witness.append(node).unwrap(); } @@ -104,7 +108,7 @@ pub fn scan_block( tree: &mut CommitmentTree, existing_witnesses: &mut [&mut IncrementalWitness], ) -> Vec<(WalletTx, Vec>)> { - let mut wtxs = vec![]; + let mut wtxs: Vec<(WalletTx, Vec>)> = vec![]; let ivks: Vec<_> = extfvks.iter().map(|extfvk| extfvk.fvk.vk.ivk()).collect(); for tx in block.vtx.into_iter() { @@ -142,17 +146,29 @@ pub fn scan_block( // Check for incoming notes while incrementing tree and witnesses let mut shielded_outputs = vec![]; let mut new_witnesses = vec![]; - for to_scan in tx.outputs.into_iter().enumerate() { - if let Some((output, new_witness)) = scan_output( - to_scan, - &ivks, - &spent_from_accounts, - tree, - existing_witnesses, - &mut new_witnesses, - ) { - shielded_outputs.push(output); - new_witnesses.push(new_witness); + { + // Grab mutable references to new witnesses from previous transactions + // in this block so that we can update them. Scoped so we don't hold + // mutable references to wtxs for too long. + let mut block_witnesses: Vec<_> = wtxs + .iter_mut() + .map(|(_, w)| w.iter_mut().collect::>()) + .flatten() + .collect(); + + for to_scan in tx.outputs.into_iter().enumerate() { + if let Some((output, new_witness)) = scan_output( + to_scan, + &ivks, + &spent_from_accounts, + tree, + existing_witnesses, + &mut block_witnesses, + &mut new_witnesses, + ) { + shielded_outputs.push(output); + new_witnesses.push(new_witness); + } } } @@ -241,6 +257,7 @@ mod tests { nf: [u8; 32], extfvk: ExtendedFullViewingKey, value: Amount, + tx_after: bool, ) -> CompactBlock { let to = extfvk.default_address().unwrap().1; @@ -291,6 +308,13 @@ mod tests { ctx.index = cb.vtx.len() as u64; cb.vtx.push(ctx); + // Optionally add another random Sapling tx after ours + if tx_after { + let mut tx = random_compact_tx(&mut rng); + tx.index = cb.vtx.len() as u64; + cb.vtx.push(tx); + } + cb } @@ -299,7 +323,13 @@ mod tests { let extsk = ExtendedSpendingKey::master(&[]); let extfvk = ExtendedFullViewingKey::from(&extsk); - let cb = fake_compact_block(1, [0; 32], extfvk.clone(), Amount::from_u64(5).unwrap()); + let cb = fake_compact_block( + 1, + [0; 32], + extfvk.clone(), + Amount::from_u64(5).unwrap(), + false, + ); assert_eq!(cb.vtx.len(), 2); let mut tree = CommitmentTree::new(); @@ -321,6 +351,39 @@ mod tests { assert_eq!(new_witnesses[0].root(), tree.root()); } + #[test] + fn scan_block_with_txs_after_my_tx() { + let extsk = ExtendedSpendingKey::master(&[]); + let extfvk = ExtendedFullViewingKey::from(&extsk); + + let cb = fake_compact_block( + 1, + [0; 32], + extfvk.clone(), + Amount::from_u64(5).unwrap(), + true, + ); + assert_eq!(cb.vtx.len(), 3); + + let mut tree = CommitmentTree::new(); + let txs = scan_block(cb, &[extfvk], &[], &mut tree, &mut []); + assert_eq!(txs.len(), 1); + + let (tx, new_witnesses) = &txs[0]; + assert_eq!(tx.index, 1); + assert_eq!(tx.num_spends, 1); + assert_eq!(tx.num_outputs, 1); + assert_eq!(tx.shielded_spends.len(), 0); + assert_eq!(tx.shielded_outputs.len(), 1); + assert_eq!(tx.shielded_outputs[0].index, 0); + assert_eq!(tx.shielded_outputs[0].account, 0); + assert_eq!(tx.shielded_outputs[0].note.value, 5); + + // Check that the witness root matches + assert_eq!(new_witnesses.len(), 1); + assert_eq!(new_witnesses[0].root(), tree.root()); + } + #[test] fn scan_block_with_my_spend() { let extsk = ExtendedSpendingKey::master(&[]); @@ -328,7 +391,7 @@ mod tests { let nf = [7; 32]; let account = 12; - let cb = fake_compact_block(1, nf, extfvk, Amount::from_u64(5).unwrap()); + let cb = fake_compact_block(1, nf, extfvk, Amount::from_u64(5).unwrap(), false); assert_eq!(cb.vtx.len(), 2); let mut tree = CommitmentTree::new(); From a3b85b8fe6baca50829e296856a0eff38f60e855 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 1 May 2019 00:08:54 +0100 Subject: [PATCH 251/330] Compute and store BlockHash inside BlockHeader --- zcash_primitives/src/block.rs | 39 +++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/zcash_primitives/src/block.rs b/zcash_primitives/src/block.rs index ecb0e5b..3140f9b 100644 --- a/zcash_primitives/src/block.rs +++ b/zcash_primitives/src/block.rs @@ -2,6 +2,7 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use hex; +use sha2::{Digest, Sha256}; use std::fmt; use std::io::{self, Read, Write}; use std::ops::Deref; @@ -22,13 +23,16 @@ impl fmt::Display for BlockHash { } /// A Zcash block header. -pub struct BlockHeader(BlockHeaderData); +pub struct BlockHeader { + hash: BlockHash, + data: BlockHeaderData, +} impl Deref for BlockHeader { type Target = BlockHeaderData; fn deref(&self) -> &BlockHeaderData { - &self.0 + &self.data } } @@ -44,12 +48,31 @@ pub struct BlockHeaderData { } impl BlockHeaderData { - pub fn freeze(self) -> BlockHeader { - BlockHeader(self) + pub fn freeze(self) -> io::Result { + BlockHeader::from_data(self) } } impl BlockHeader { + fn from_data(data: BlockHeaderData) -> io::Result { + let mut header = BlockHeader { + hash: BlockHash([0; 32]), + data, + }; + let mut raw = vec![]; + header.write(&mut raw)?; + header + .hash + .0 + .copy_from_slice(&Sha256::digest(&Sha256::digest(&raw))); + Ok(header) + } + + /// Returns the hash of this header. + pub fn hash(&self) -> BlockHash { + self.hash + } + pub fn read(mut reader: R) -> io::Result { let version = reader.read_i32::()?; @@ -70,7 +93,7 @@ impl BlockHeader { let solution = Vector::read(&mut reader, |r| r.read_u8())?; - Ok(BlockHeader(BlockHeaderData { + BlockHeader::from_data(BlockHeaderData { version, prev_block, merkle_root, @@ -79,7 +102,7 @@ impl BlockHeader { bits, nonce, solution, - })) + }) } pub fn write(&self, mut writer: W) -> io::Result<()> { @@ -206,6 +229,10 @@ mod tests { #[test] fn header_read_write() { let header = BlockHeader::read(&HEADER_MAINNET_415000[..]).unwrap(); + assert_eq!( + format!("{}", header.hash()), + "0000000001ab37793ce771262b2ffa082519aa3fe891250a1adb43baaf856168" + ); let mut encoded = Vec::with_capacity(HEADER_MAINNET_415000.len()); header.write(&mut encoded).unwrap(); assert_eq!(&HEADER_MAINNET_415000[..], &encoded[..]); From 2bbd25b36b3467089af7b81b072993245e42c9a8 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 1 May 2019 13:21:48 +0100 Subject: [PATCH 252/330] Add prevHash field to CompactBlock This enables basic verification of chain validity when CompactBlocks are received without the full header. --- .../proto/compact_formats.proto | 7 +-- zcash_client_backend/src/proto/mod.rs | 51 +++++++++++++++++++ zcash_primitives/src/block.rs | 14 +++++ 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/zcash_client_backend/proto/compact_formats.proto b/zcash_client_backend/proto/compact_formats.proto index d65b658..7e1bc54 100644 --- a/zcash_client_backend/proto/compact_formats.proto +++ b/zcash_client_backend/proto/compact_formats.proto @@ -13,9 +13,10 @@ message CompactBlock { uint32 protoVersion = 1; // the version of this wire format, for storage uint64 height = 2; // the height of this block bytes hash = 3; - uint32 time = 4; - bytes header = 5; // (hash and time) OR (full header) - repeated CompactTx vtx = 6; // compact transactions from this block + bytes prevHash = 4; + uint32 time = 5; + bytes header = 6; // (hash, prevHash, and time) OR (full header) + repeated CompactTx vtx = 7; // compact transactions from this block } message CompactTx { diff --git a/zcash_client_backend/src/proto/mod.rs b/zcash_client_backend/src/proto/mod.rs index e24ef5c..50d562b 100644 --- a/zcash_client_backend/src/proto/mod.rs +++ b/zcash_client_backend/src/proto/mod.rs @@ -1,3 +1,54 @@ //! Generated code for handling light client protobuf structs. +use zcash_primitives::block::{BlockHash, BlockHeader}; + pub mod compact_formats; + +impl compact_formats::CompactBlock { + /// Returns the [`BlockHash`] for this block. + /// + /// # Panics + /// + /// This function will panic if [`CompactBlock.header`] is not set and + /// [`CompactBlock.hash`] is not exactly 32 bytes. + /// + /// [`CompactBlock.header`]: #structfield.header + /// [`CompactBlock.hash`]: #structfield.hash + pub fn hash(&self) -> BlockHash { + if let Some(header) = self.header() { + header.hash() + } else { + BlockHash::from_slice(&self.hash) + } + } + + /// Returns the [`BlockHash`] for this block's parent. + /// + /// # Panics + /// + /// This function will panic if [`CompactBlock.header`] is not set and + /// [`CompactBlock.prevHash`] is not exactly 32 bytes. + /// + /// [`CompactBlock.header`]: #structfield.header + /// [`CompactBlock.prevHash`]: #structfield.prevHash + pub fn prev_hash(&self) -> BlockHash { + if let Some(header) = self.header() { + header.prev_block + } else { + BlockHash::from_slice(&self.prevHash) + } + } + + /// Returns the [`BlockHeader`] for this block if present. + /// + /// A convenience method that parses [`CompactBlock.header`] if present. + /// + /// [`CompactBlock.header`]: #structfield.header + pub fn header(&self) -> Option { + if self.header.is_empty() { + None + } else { + BlockHeader::read(&self.header[..]).ok() + } + } +} diff --git a/zcash_primitives/src/block.rs b/zcash_primitives/src/block.rs index 3140f9b..8432cd4 100644 --- a/zcash_primitives/src/block.rs +++ b/zcash_primitives/src/block.rs @@ -22,6 +22,20 @@ impl fmt::Display for BlockHash { } } +impl BlockHash { + /// Constructs a [`BlockHash`] from the given slice. + /// + /// # Panics + /// + /// This function will panic if the slice is not exactly 32 bytes. + pub fn from_slice(bytes: &[u8]) -> Self { + assert_eq!(bytes.len(), 32); + let mut hash = [0; 32]; + hash.copy_from_slice(&bytes); + BlockHash(hash) + } +} + /// A Zcash block header. pub struct BlockHeader { hash: BlockHash, From 1e2bc7f65ca68674d522d6220d41b7369b3fbedf Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 22 Aug 2019 00:57:04 +0100 Subject: [PATCH 253/330] Test nullifiers in constant time Checking for spent notes in a block is still not completely constant time, due to filtering out negative results of the constant-time comparison. Part of #84. --- Cargo.lock | 7 ++++ zcash_client_backend/Cargo.toml | 1 + zcash_client_backend/src/welding_rig.rs | 46 +++++++++++++------------ 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 75ff772..fe20d7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -588,6 +588,11 @@ dependencies = [ "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "subtle" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "syn" version = "1.0.5" @@ -645,6 +650,7 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "zcash_primitives 0.1.0", ] @@ -751,6 +757,7 @@ dependencies = [ "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" +"checksum subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab3af2eb31c42e8f0ccf43548232556c42737e01a96db6e1777b0be108e79799" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" diff --git a/zcash_client_backend/Cargo.toml b/zcash_client_backend/Cargo.toml index e639efd..3c8a014 100644 --- a/zcash_client_backend/Cargo.toml +++ b/zcash_client_backend/Cargo.toml @@ -17,6 +17,7 @@ ff = { version = "0.5.0", path = "../ff" } hex = "0.3" pairing = { version = "0.15.0", path = "../pairing" } protobuf = "2" +subtle = "2" zcash_primitives = { version = "0.1.0", path = "../zcash_primitives" } [build-dependencies] diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index e3f9d8b..307dcea 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -3,6 +3,7 @@ use ff::{PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr, FrRepr}; use std::collections::HashSet; +use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption}; use zcash_primitives::{ jubjub::{edwards, fs::Fs}, merkle_tree::{CommitmentTree, IncrementalWitness}, @@ -116,28 +117,29 @@ pub fn scan_block( let num_outputs = tx.outputs.len(); // Check for spent notes - let shielded_spends: Vec<_> = - tx.spends - .into_iter() - .enumerate() - .filter_map(|(index, spend)| { - if let Some(account) = nullifiers.iter().find_map(|&(nf, acc)| { - if nf == &spend.nf[..] { - Some(acc) - } else { - None - } - }) { - Some(WalletShieldedSpend { - index, - nf: spend.nf, - account, - }) - } else { - None - } - }) - .collect(); + // The only step that is not constant-time is the filter() at the end. + let shielded_spends: Vec<_> = tx + .spends + .into_iter() + .enumerate() + .map(|(index, spend)| { + // Find the first tracked nullifier that matches this spend, and produce + // a WalletShieldedSpend if there is a match, in constant time. + nullifiers + .iter() + .map(|&(nf, account)| CtOption::new(account as u64, nf.ct_eq(&spend.nf[..]))) + .fold(CtOption::new(0, 0.into()), |first, next| { + CtOption::conditional_select(&next, &first, first.is_some()) + }) + .map(|account| WalletShieldedSpend { + index, + nf: spend.nf, + account: account as usize, + }) + }) + .filter(|spend| spend.is_some().into()) + .map(|spend| spend.unwrap()) + .collect(); // Collect the set of accounts that were spent from in this transaction let spent_from_accounts: HashSet<_> = From 7fa51e38c05613c86ac3502466930d15381eb8e5 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 22 Aug 2019 15:18:50 +0100 Subject: [PATCH 254/330] Travis CI: Build before formatting check cargo fmt does not build the code, and running it in a fresh clone of the codebase will fail because the protobuf code has not been generated. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 85dfd70..f0f9e46 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,8 @@ before_script: - rustup component add rustfmt script: - - cargo fmt --all -- --check - cargo build --verbose --release --all + - cargo fmt --all -- --check - cargo test --verbose --release --all - cargo test --verbose --release --all -- --ignored From b44653e686e9b7ae16f2228f034535c5dbbdc67a Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 26 Aug 2019 11:59:07 +0100 Subject: [PATCH 255/330] Move cmu and epk parsing onto CompactOutput struct --- zcash_client_backend/src/proto/mod.rs | 31 ++++++++++++++++++++++++- zcash_client_backend/src/welding_rig.rs | 25 ++++---------------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/zcash_client_backend/src/proto/mod.rs b/zcash_client_backend/src/proto/mod.rs index 50d562b..0ab1b6d 100644 --- a/zcash_client_backend/src/proto/mod.rs +++ b/zcash_client_backend/src/proto/mod.rs @@ -1,6 +1,12 @@ //! Generated code for handling light client protobuf structs. -use zcash_primitives::block::{BlockHash, BlockHeader}; +use ff::{PrimeField, PrimeFieldRepr}; +use pairing::bls12_381::{Bls12, Fr, FrRepr}; +use zcash_primitives::{ + block::{BlockHash, BlockHeader}, + jubjub::{edwards, PrimeOrder}, + JUBJUB, +}; pub mod compact_formats; @@ -52,3 +58,26 @@ impl compact_formats::CompactBlock { } } } + +impl compact_formats::CompactOutput { + /// Returns the note commitment for this output. + /// + /// A convenience method that parses [`CompactOutput.cmu`]. + /// + /// [`CompactOutput.cmu`]: #structfield.cmu + pub fn cmu(&self) -> Result { + let mut repr = FrRepr::default(); + repr.read_le(&self.cmu[..]).map_err(|_| ())?; + Fr::from_repr(repr).map_err(|_| ()) + } + + /// Returns the ephemeral public key for this output. + /// + /// A convenience method that parses [`CompactOutput.epk`]. + /// + /// [`CompactOutput.epk`]: #structfield.epk + pub fn epk(&self) -> Result, ()> { + let p = edwards::Point::::read(&self.epk[..], &JUBJUB).map_err(|_| ())?; + p.as_prime_order(&JUBJUB).ok_or(()) + } +} diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index 307dcea..0996607 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -1,17 +1,15 @@ //! Tools for scanning a compact representation of the Zcash block chain. -use ff::{PrimeField, PrimeFieldRepr}; -use pairing::bls12_381::{Bls12, Fr, FrRepr}; +use ff::PrimeField; use std::collections::HashSet; use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption}; use zcash_primitives::{ - jubjub::{edwards, fs::Fs}, + jubjub::fs::Fs, merkle_tree::{CommitmentTree, IncrementalWitness}, note_encryption::try_sapling_compact_note_decryption, sapling::Node, transaction::TxId, zip32::ExtendedFullViewingKey, - JUBJUB, }; use crate::proto::compact_formats::{CompactBlock, CompactOutput}; @@ -33,23 +31,8 @@ fn scan_output( block_witnesses: &mut [&mut IncrementalWitness], new_witnesses: &mut [IncrementalWitness], ) -> Option<(WalletShieldedOutput, IncrementalWitness)> { - let mut repr = FrRepr::default(); - if repr.read_le(&output.cmu[..]).is_err() { - return None; - } - let cmu = match Fr::from_repr(repr) { - Ok(cmu) => cmu, - Err(_) => return None, - }; - - let epk = match edwards::Point::::read(&output.epk[..], &JUBJUB) { - Ok(p) => match p.as_prime_order(&JUBJUB) { - Some(epk) => epk, - None => return None, - }, - Err(_) => return None, - }; - + let cmu = output.cmu().ok()?; + let epk = output.epk().ok()?; let ct = output.ciphertext; // Increment tree and witnesses From e9f94119bcfc19eb92effb8c47b5cc2f31754c9e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 26 Aug 2019 12:12:32 +0100 Subject: [PATCH 256/330] Store witness inside WalletShieldedOutput --- zcash_client_backend/src/wallet.rs | 3 + zcash_client_backend/src/welding_rig.rs | 82 +++++++++++++------------ 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/zcash_client_backend/src/wallet.rs b/zcash_client_backend/src/wallet.rs index dd5229b..dc46a86 100644 --- a/zcash_client_backend/src/wallet.rs +++ b/zcash_client_backend/src/wallet.rs @@ -4,7 +4,9 @@ use pairing::bls12_381::{Bls12, Fr}; use zcash_primitives::{ jubjub::{edwards, PrimeOrder}, + merkle_tree::IncrementalWitness, primitives::{Note, PaymentAddress}, + sapling::Node, transaction::TxId, }; @@ -40,4 +42,5 @@ pub struct WalletShieldedOutput { pub note: Note, pub to: PaymentAddress, pub is_change: bool, + pub witness: IncrementalWitness, } diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index 0996607..6b9ec59 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -29,8 +29,8 @@ fn scan_output( tree: &mut CommitmentTree, existing_witnesses: &mut [&mut IncrementalWitness], block_witnesses: &mut [&mut IncrementalWitness], - new_witnesses: &mut [IncrementalWitness], -) -> Option<(WalletShieldedOutput, IncrementalWitness)> { + new_witnesses: &mut [&mut IncrementalWitness], +) -> Option { let cmu = output.cmu().ok()?; let epk = output.epk().ok()?; let ct = output.ciphertext; @@ -62,18 +62,16 @@ fn scan_output( // - Notes sent from one account to itself. let is_change = spent_from_accounts.contains(&account); - return Some(( - WalletShieldedOutput { - index, - cmu, - epk, - account, - note, - to, - is_change, - }, - IncrementalWitness::from_tree(tree), - )); + return Some(WalletShieldedOutput { + index, + cmu, + epk, + account, + note, + to, + is_change, + witness: IncrementalWitness::from_tree(tree), + }); } None } @@ -91,8 +89,8 @@ pub fn scan_block( nullifiers: &[(&[u8], usize)], tree: &mut CommitmentTree, existing_witnesses: &mut [&mut IncrementalWitness], -) -> Vec<(WalletTx, Vec>)> { - let mut wtxs: Vec<(WalletTx, Vec>)> = vec![]; +) -> Vec { + let mut wtxs: Vec = vec![]; let ivks: Vec<_> = extfvks.iter().map(|extfvk| extfvk.fvk.vk.ivk()).collect(); for tx in block.vtx.into_iter() { @@ -129,20 +127,31 @@ pub fn scan_block( shielded_spends.iter().map(|spend| spend.account).collect(); // Check for incoming notes while incrementing tree and witnesses - let mut shielded_outputs = vec![]; - let mut new_witnesses = vec![]; + let mut shielded_outputs: Vec = vec![]; { // Grab mutable references to new witnesses from previous transactions // in this block so that we can update them. Scoped so we don't hold // mutable references to wtxs for too long. let mut block_witnesses: Vec<_> = wtxs .iter_mut() - .map(|(_, w)| w.iter_mut().collect::>()) + .map(|tx| { + tx.shielded_outputs + .iter_mut() + .map(|output| &mut output.witness) + }) .flatten() .collect(); for to_scan in tx.outputs.into_iter().enumerate() { - if let Some((output, new_witness)) = scan_output( + // Grab mutable references to new witnesses from previous outputs + // in this transaction so that we can update them. Scoped so we + // don't hold mutable references to shielded_outputs for too long. + let mut new_witnesses: Vec<_> = shielded_outputs + .iter_mut() + .map(|output| &mut output.witness) + .collect(); + + if let Some(output) = scan_output( to_scan, &ivks, &spent_from_accounts, @@ -152,7 +161,6 @@ pub fn scan_block( &mut new_witnesses, ) { shielded_outputs.push(output); - new_witnesses.push(new_witness); } } } @@ -160,17 +168,14 @@ pub fn scan_block( if !(shielded_spends.is_empty() && shielded_outputs.is_empty()) { let mut txid = TxId([0u8; 32]); txid.0.copy_from_slice(&tx.hash); - wtxs.push(( - WalletTx { - txid, - index: tx.index as usize, - num_spends, - num_outputs, - shielded_spends, - shielded_outputs, - }, - new_witnesses, - )); + wtxs.push(WalletTx { + txid, + index: tx.index as usize, + num_spends, + num_outputs, + shielded_spends, + shielded_outputs, + }); } } @@ -321,7 +326,7 @@ mod tests { let txs = scan_block(cb, &[extfvk], &[], &mut tree, &mut []); assert_eq!(txs.len(), 1); - let (tx, new_witnesses) = &txs[0]; + let tx = &txs[0]; assert_eq!(tx.index, 1); assert_eq!(tx.num_spends, 1); assert_eq!(tx.num_outputs, 1); @@ -332,8 +337,7 @@ mod tests { assert_eq!(tx.shielded_outputs[0].note.value, 5); // Check that the witness root matches - assert_eq!(new_witnesses.len(), 1); - assert_eq!(new_witnesses[0].root(), tree.root()); + assert_eq!(tx.shielded_outputs[0].witness.root(), tree.root()); } #[test] @@ -354,7 +358,7 @@ mod tests { let txs = scan_block(cb, &[extfvk], &[], &mut tree, &mut []); assert_eq!(txs.len(), 1); - let (tx, new_witnesses) = &txs[0]; + let tx = &txs[0]; assert_eq!(tx.index, 1); assert_eq!(tx.num_spends, 1); assert_eq!(tx.num_outputs, 1); @@ -365,8 +369,7 @@ mod tests { assert_eq!(tx.shielded_outputs[0].note.value, 5); // Check that the witness root matches - assert_eq!(new_witnesses.len(), 1); - assert_eq!(new_witnesses[0].root(), tree.root()); + assert_eq!(tx.shielded_outputs[0].witness.root(), tree.root()); } #[test] @@ -383,7 +386,7 @@ mod tests { let txs = scan_block(cb, &[], &[(&nf, account)], &mut tree, &mut []); assert_eq!(txs.len(), 1); - let (tx, new_witnesses) = &txs[0]; + let tx = &txs[0]; assert_eq!(tx.index, 1); assert_eq!(tx.num_spends, 1); assert_eq!(tx.num_outputs, 1); @@ -392,6 +395,5 @@ mod tests { assert_eq!(tx.shielded_spends[0].index, 0); assert_eq!(tx.shielded_spends[0].nf, nf); assert_eq!(tx.shielded_spends[0].account, account); - assert_eq!(new_witnesses.len(), 0); } } From 274f860202d18350c9489cb7d3f3f3db717f8def Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 18 Sep 2019 17:08:58 +0100 Subject: [PATCH 257/330] Actions: Build before formatting check cargo fmt does not build the code, and running it in a fresh clone of the codebase will fail because the protobuf code has not been generated. --- .github/workflows/rust.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 5f76fb0..85231fa 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -14,6 +14,14 @@ jobs: toolchain: 1.37.0 override: true + # cargo fmt does not build the code, and running it in a fresh clone of + # the codebase will fail because the protobuf code has not been generated. + - name: cargo build + uses: actions-rs/cargo@v1 + with: + command: build + args: --all + # Ensure all code has been formatted with rustfmt - run: rustup component add rustfmt - name: Check formatting From 84dc3bf73c71a499245a8a360ad1ac188576f7e2 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 11 Oct 2019 07:58:29 +0300 Subject: [PATCH 258/330] license notice --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 088208c..defdafe 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The main design goals of this mmr implementation are # License -`zcash_mmr` is primarily distributed under the terms of both the MIT +`zcash_mmr` is distributed under the terms of both the MIT license and the Apache License (Version 2.0), at your choice. See LICENSE-APACHE, and LICENSE-MIT for details. From 9d4412103b80f25818f880bd9f9679d300fc8e50 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 11 Oct 2019 08:00:07 +0300 Subject: [PATCH 259/330] more clear leaf_count --- src/entry.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entry.rs b/src/entry.rs index a3f14a8..257b9dd 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -29,7 +29,7 @@ impl Entry { /// Number of leaves under this node. pub fn leaf_count(&self) -> u64 { - self.data.end_height - self.data.start_height + 1 + self.data.end_height - (self.data.start_height - 1) } /// Is this node a leaf. From cb818ecbe3798d35ba78b0ccb74b11abdd7d4c2b Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 11 Oct 2019 08:04:42 +0300 Subject: [PATCH 260/330] serialization sizes notice --- src/node_data.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/node_data.rs b/src/node_data.rs index a018daa..5d7535b 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -3,7 +3,19 @@ use bigint::U256; use blake2::Params as Blake2Params; /// Maximum serialized size of the node metadata. -pub const MAX_NODE_DATA_SIZE: usize = 32 + 4 + 4 + 4 + 4 + 32 + 32 + 32 + 9 + 9 + 9; // 171 +pub const MAX_NODE_DATA_SIZE: usize = + 32 + // subtree commitment + 4 + // start time + 4 + // end time + 4 + // start target + 4 + // end target + 32 + // start sapling tree root + 32 + // end sapling tree root + 32 + // subtree total work + 9 + // start height (compact uint) + 9 + // end height (compact uint) + 9; // shielded tx count (compact uint) + // = total of 171 /// Node metadata. #[repr(C)] From 29b8d7a7563753e958e54a996d7393eb52276583 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 11 Oct 2019 08:18:36 +0300 Subject: [PATCH 261/330] serialization roundtrip test --- src/node_data.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/node_data.rs b/src/node_data.rs index 5d7535b..bbaa98c 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -20,6 +20,7 @@ pub const MAX_NODE_DATA_SIZE: usize = /// Node metadata. #[repr(C)] #[derive(Debug, Clone, Default)] +#[cfg_attr(test, derive(PartialEq))] pub struct NodeData { /// Consensus branch id, should be provided by deserializing node. pub consensus_branch_id: u32, @@ -192,4 +193,40 @@ impl NodeData { let mut cursor = std::io::Cursor::new(buf); Self::read(consensus_branch_id, &mut cursor) } +} + +#[cfg(test)] +impl quickcheck::Arbitrary for NodeData { + fn arbitrary(gen: &mut G) -> Self { + let mut node_data = NodeData::default(); + node_data.consensus_branch_id = 0; + gen.fill_bytes(&mut node_data.subtree_commitment[..]); + node_data.start_time = gen.next_u32(); + node_data.end_time = gen.next_u32(); + node_data.start_target = gen.next_u32(); + node_data.end_target = gen.next_u32(); + gen.fill_bytes(&mut node_data.start_sapling_root[..]); + gen.fill_bytes(&mut node_data.end_sapling_root[..]); + let mut number = [0u8; 32]; + gen.fill_bytes(&mut number[..]); + node_data.subtree_total_work = U256::from_little_endian(&number[..]); + node_data.start_height = gen.next_u64(); + node_data.end_height = gen.next_u64(); + node_data.shielded_tx = gen.next_u64(); + + node_data + } +} + +#[cfg(test)] +mod tests { + use super::NodeData; + use quickcheck::{quickcheck, TestResult}; + + + quickcheck! { + fn serialization_round_trip(node_data: NodeData) -> TestResult { + TestResult::from_bool(NodeData::from_bytes(0, &node_data.to_bytes()).unwrap() == node_data) + } + } } \ No newline at end of file From e701687b691ea920bc51c867e8a870ef34cb92bf Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 11 Oct 2019 08:28:50 +0300 Subject: [PATCH 262/330] various small fixes --- README.md | 4 ++-- src/node_data.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index defdafe..f034137 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # zcash_mmr -Special implementation of merkle mountain ranges (MMR) for ZCash! +Special implementation of Merkle mountain ranges (MMR) for Zcash! [![Build Status](https://travis-ci.org/NikVolf/zcash-mmr.svg?branch=master)](https://travis-ci.org/NikVolf/zcash-mmr) -The main design goals of this mmr implementation are +The main design goals of this MMR implementation are - Allow zero-cache and avoid db callbacks. As it is implemented, calling side must just smartly pre-load MMR nodes from the database (about log2(tree length) for append, twice as much for deletion). diff --git a/src/node_data.rs b/src/node_data.rs index bbaa98c..ac545e2 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -127,7 +127,7 @@ impl NodeData { i @ 0..=0xfc => i.into(), 0xfd => reader.read_u16::()?.into(), 0xfe => reader.read_u32::()?.into(), - _ => reader.read_u64::()?.into(), + _ => reader.read_u64::()?, }; Ok(result) From 6b7a3dec9ca47837e61a455b8cb560e8851b7ac6 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 11 Oct 2019 08:44:20 +0300 Subject: [PATCH 263/330] store generated as vec --- src/tree.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index 4482cd8..d1bf936 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -12,14 +12,11 @@ use crate::{Entry, EntryLink, NodeData, Error, EntryKind}; pub struct Tree { stored: HashMap, - generated: HashMap, + generated: Vec, // number of persistent(!) tree entries stored_count: u32, - // number of virtual nodes generated - generated_count: u32, - root: EntryLink, } @@ -28,7 +25,7 @@ impl Tree { pub fn resolve_link(&self, link: EntryLink) -> Result { match link { EntryLink::Generated(index) => { - let node = self.generated.get(&index).ok_or(Error::ExpectedInMemory(link))?; + let node = self.generated.get(index as usize).ok_or(Error::ExpectedInMemory(link))?; Ok(IndexedNode { node, link, @@ -52,14 +49,13 @@ impl Tree { } fn push_generated(&mut self, data: Entry) -> EntryLink { - let idx = self.generated_count; - self.generated_count = self.generated_count + 1; - self.generated.insert(idx, data); - EntryLink::Generated(idx) + self.generated.push(data); + EntryLink::Generated(self.generated.len() as u32 - 1) } - /// Populate tree with plain list of the leaves/nodes. Mostly for tests, - /// since this `Tree` structure is for partially loaded tree. + /// Populate tree with plain list of the leaves/nodes. For now, only for tests, + /// since this `Tree` structure is for partially loaded tree (but it might change) + #[cfg(test)] pub fn populate(loaded: Vec, root: EntryLink) -> Self { let mut result = Tree::invalid(); result.stored_count = loaded.len() as u32; @@ -71,12 +67,12 @@ impl Tree { result } + // Empty tree with invalid root fn invalid() -> Self { Tree { root: EntryLink::Generated(0), generated: Default::default(), stored: Default::default(), - generated_count: 0, stored_count: 0, } } From 3082593fccfed7c99fd7779eff6a115bcd48a386 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 11 Oct 2019 08:50:44 +0300 Subject: [PATCH 264/330] add intented use of the api --- src/tree.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tree.rs b/src/tree.rs index d1bf936..65e0220 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -8,10 +8,15 @@ use crate::{Entry, EntryLink, NodeData, Error, EntryKind}; /// With only some of the leaves/nodes pre-loaded / pre-generated. /// Exact amount of the loaded data can be calculated by the constructing party, /// depending on the length of the tree and maximum amount of operations that are going -/// to happen after construction. +/// to happen after construction. `Tree` should not be used as self-contained data structure, +/// since it's internal state can grow indefinitely after serial operations. +/// Intended use of this `Tree` is to instantiate it based on partially loaded data (see example +/// how to pick right nodes from the array representation of MMR Tree), perform several operations +/// (append-s/delete-s) and then drop it. pub struct Tree { stored: HashMap, + // This can grow indefinitely if `Tree` is misused as a self-contained data structure generated: Vec, // number of persistent(!) tree entries From b9bfc07146f2576d47e9c14bf1df0f2f540c1bc5 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 11 Oct 2019 08:55:43 +0300 Subject: [PATCH 265/330] style fixes --- src/tree.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index 65e0220..1d3db06 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -48,7 +48,7 @@ impl Tree { fn push(&mut self, data: Entry) -> EntryLink { let idx = self.stored_count; - self.stored_count = self.stored_count + 1; + self.stored_count += 1; self.stored.insert(idx, data); EntryLink::Stored(idx) } @@ -84,15 +84,22 @@ impl Tree { /// New view into the the tree array representation /// - /// `length` is total length of the array representation + /// `length` is total length of the array representation (is generally not a sum of + /// peaks.len + extra.len) /// `peaks` is peaks of the mmr tree /// `extra` is some extra nodes that calculated to be required during next one or more /// operations on the tree. + /// + /// # Panics + /// + /// Will panic if `peaks` is empty. pub fn new( length: u32, peaks: Vec<(u32, Entry)>, extra: Vec<(u32, Entry)>, ) -> Self { + assert!(peaks.len() > 0); + let mut result = Tree::invalid(); result.stored_count = length; @@ -157,6 +164,9 @@ impl Tree { let mut merge_stack = Vec::new(); merge_stack.push(new_leaf_link); + // Scan the peaks right-to-left, merging together equal-sized adjacent + // complete subtrees. After this, merge_stack only contains peaks of + // unequal-sized subtrees. while let Some(next_peak) = peaks.pop() { let next_merge = merge_stack.pop().expect("there should be at least one, initial or re-pushed"); @@ -171,12 +181,15 @@ impl Tree { merge_stack.push(link); appended.push(link); continue; + } else { + merge_stack.push(next_merge); + merge_stack.push(next_peak); } - merge_stack.push(next_merge); - merge_stack.push(next_peak); } let mut new_root = merge_stack.pop().expect("Loop above cannot reduce the merge_stack"); + // Scan the peaks left-to-right, producing new generated nodes that + // connect the subtrees while let Some(next_child) = merge_stack.pop() { new_root = self.push_generated( combine_nodes( @@ -210,7 +223,8 @@ impl Tree { /// Truncate one leaf from the end of the tree. /// - /// Returns actual number of nodes that has to be removed from the array representation. + /// Returns actual number of nodes that should be removed by the caller + /// from the end of the array representation. pub fn truncate_leaf(&mut self) -> Result { let root = { let (leaves, root_left_child) = { @@ -245,7 +259,7 @@ impl Tree { } } - let mut new_root = *peaks.iter().nth(0).expect("At lest 2 elements in peaks"); + let mut new_root = *peaks.get(0).expect("At lest 1 elements in peaks"); for next_peak in peaks.into_iter().skip(1) { new_root = self.push_generated( From f24ec04340d8bb816ae95939f14193a15959a09f Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 11 Oct 2019 09:00:47 +0300 Subject: [PATCH 266/330] add is_empty --- src/tree.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tree.rs b/src/tree.rs index 1d3db06..d1d1d6f 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -289,6 +289,10 @@ impl Tree { pub fn root_node(&self) -> Result { self.resolve_link(self.root) } + + pub fn is_empty(&self) -> bool { + self.stored_count == 0 + } } /// Reference to the node with link attached. From 481e43689cd2d2aa8e0d856970d74384e06a8c2c Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 11 Oct 2019 09:04:04 +0300 Subject: [PATCH 267/330] use NodeData::combine --- src/tree.rs | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index d1d1d6f..fbadaba 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -285,11 +285,12 @@ impl Tree { /// Link to the root node pub fn root(&self) -> EntryLink { self.root } - /// Reference to the root ndoe + /// Reference to the root node. pub fn root_node(&self) -> Result { self.resolve_link(self.root) } + /// If this tree is empty. pub fn is_empty(&self) -> bool { self.stored_count == 0 } @@ -359,29 +360,12 @@ mod tests { } } - fn node(start_height: u64, end_height: u64) -> NodeData { - NodeData { - consensus_branch_id: 1, - subtree_commitment: [0u8; 32], - start_time: 0, - end_time: 0, - start_target: 0, - end_target: 0, - start_sapling_root: [0u8; 32], - end_sapling_root: [0u8; 32], - subtree_total_work: 0.into(), - start_height: start_height, - end_height: end_height, - shielded_tx: 7, - } - } - fn initial() -> Tree { let node1: Entry = leaf(1).into(); let node2: Entry = leaf(2).into(); let node3 = Entry { - data: node(1, 2), + data: NodeData::combine(&node1.data, &node2.data), kind: EntryKind::Leaf, }; From acad37924b7cd4fccaa7988e697d3747e8f87f42 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 11 Oct 2019 09:14:19 +0300 Subject: [PATCH 268/330] test updates --- src/tree.rs | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index fbadaba..d3b6dcd 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -205,7 +205,7 @@ impl Tree { } #[cfg(test)] - fn for_children(&mut self, node: EntryLink, mut f: F) { + fn for_children(&self, node: EntryLink, f: F) { let (left, right) = { let link = self.resolve_link(node).expect("Failed to resolve link in test"); ( @@ -485,7 +485,7 @@ mod tests { // (0) (1) (3) (4) (7) // // new tree: - // (---8g---) + // (---10g--) // / \ // ( 6 ) \ // / \ \ @@ -494,7 +494,7 @@ mod tests { // (0) (1) (3) (4) (7) (8) // // so (7) is added as real leaf - // and new root, (8g) is generated one + // and new root, (10g) is generated one assert_eq!(new_root.data.end_height, 6); assert_eq!(appended.len(), 2); assert_matches!(tree.root(), EntryLink::Generated(_)); @@ -533,13 +533,16 @@ mod tests { // / \ / \ / \ \ // (0) (1) (3) (4) (7) (8) (10) // - // so (7) is added as real leaf - // and new root, (8g) is generated one + // so (10) is added as real leaf + // and new root, (12g) is generated one assert_eq!(new_root.data.end_height, 7); assert_eq!(appended.len(), 1); assert_matches!(tree.root(), EntryLink::Generated(_)); tree.for_children(tree.root(), |l, r| { assert_matches!(l, EntryLink::Generated(_)); + tree.for_children(l, |l, r| + assert_matches!((l, r), (EntryLink::Stored(6), EntryLink::Stored(9))) + ); assert_matches!(r, EntryLink::Stored(10)); }); } @@ -547,7 +550,7 @@ mod tests { #[test] fn truncate_simple() { let mut tree = generated(9); - tree.truncate_leaf().expect("Failed to truncate"); + let total_truncated = tree.truncate_leaf().expect("Failed to truncate"); // initial tree: // @@ -574,6 +577,7 @@ mod tests { // and new root, (14) is a stored one now assert_matches!(tree.root(), EntryLink::Stored(14)); + assert_eq!(total_truncated, 1); assert_eq!(tree.len(), 15); } @@ -609,19 +613,11 @@ mod tests { assert_matches!(tree.root(), EntryLink::Generated(_)); - // left is 14 and right is 15 - let (left_root_child, right_root_child) = { - let root = tree.root_node().expect("Failed to resolve"); - - ( - root.left().expect("Expected node"), - root.right().expect("Expected node"), + tree.for_children(tree.root(),|left, right| + assert_matches!( + (left, right), + (EntryLink::Stored(14), EntryLink::Stored(15)) ) - }; - - assert_matches!( - (left_root_child, right_root_child), - (EntryLink::Stored(14), EntryLink::Stored(15)) ); // two stored nodes should leave us (leaf 16 and no longer needed node 17) @@ -706,7 +702,7 @@ mod tests { } TestResult::from_bool( - if number & number - 1 == 0 { + if number & (number - 1) == 0 { if let EntryLink::Stored(_) = tree.root() { true } else { false } } else { From cd1083e086782c0b69d80ad2ead468f982c25ef7 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Wed, 9 Oct 2019 11:50:48 -0700 Subject: [PATCH 269/330] Implememt sorting for TxIDs --- zcash_primitives/src/transaction/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index 10e935b..51cf9fb 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -24,7 +24,7 @@ const OVERWINTER_TX_VERSION: u32 = 3; const SAPLING_VERSION_GROUP_ID: u32 = 0x892F2085; const SAPLING_TX_VERSION: u32 = 4; -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct TxId(pub [u8; 32]); impl fmt::Display for TxId { From 42b7f328fbc99829b5ddb4df164a01ae5a4798d5 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 31 Jul 2019 16:17:08 +0100 Subject: [PATCH 270/330] legacy::Script::address This is the counterpart to legacy::TransparentAddress::script. --- zcash_primitives/src/legacy.rs | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/zcash_primitives/src/legacy.rs b/zcash_primitives/src/legacy.rs index d1d7c1a..18d0388 100644 --- a/zcash_primitives/src/legacy.rs +++ b/zcash_primitives/src/legacy.rs @@ -38,6 +38,31 @@ impl Script { pub fn write(&self, mut writer: W) -> io::Result<()> { Vector::write(&mut writer, &self.0, |w, e| w.write_u8(*e)) } + + /// Returns the address that this Script contains, if any. + pub fn address(&self) -> Option { + if self.0.len() == 25 + && self.0[0] == OpCode::Dup as u8 + && self.0[1] == OpCode::Hash160 as u8 + && self.0[2] == 0x14 + && self.0[23] == OpCode::EqualVerify as u8 + && self.0[24] == OpCode::CheckSig as u8 + { + let mut hash = [0; 20]; + hash.copy_from_slice(&self.0[3..23]); + Some(TransparentAddress::PublicKey(hash)) + } else if self.0.len() == 23 + && self.0[0] == OpCode::Hash160 as u8 + && self.0[1] == 0x14 + && self.0[22] == OpCode::Equal as u8 + { + let mut hash = [0; 20]; + hash.copy_from_slice(&self.0[2..22]); + Some(TransparentAddress::Script(hash)) + } else { + None + } + } } impl Shl for Script { @@ -151,7 +176,8 @@ mod tests { 0x76, 0xa9, 0x14, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x88, 0xac, ] - ) + ); + assert_eq!(addr.script().address(), Some(addr)); } #[test] @@ -163,6 +189,7 @@ mod tests { 0xa9, 0x14, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x87, ] - ) + ); + assert_eq!(addr.script().address(), Some(addr)); } } From 70857b0eeddee0fab848d9831df328581b53a42c Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 31 Jul 2019 16:18:31 +0100 Subject: [PATCH 271/330] Pass Script to signature_hash by reference --- zcash_primitives/src/transaction/sighash.rs | 4 +- zcash_primitives/src/transaction/tests.rs | 48 ++++++++++----------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/zcash_primitives/src/transaction/sighash.rs b/zcash_primitives/src/transaction/sighash.rs index 41c6da2..f6dcd30 100644 --- a/zcash_primitives/src/transaction/sighash.rs +++ b/zcash_primitives/src/transaction/sighash.rs @@ -154,7 +154,7 @@ pub fn signature_hash_data( tx: &TransactionData, consensus_branch_id: u32, hash_type: u32, - transparent_input: Option<(usize, Script, Amount)>, + transparent_input: Option<(usize, &Script, Amount)>, ) -> Vec { let sigversion = SigHashVersion::from_tx(tx); match sigversion { @@ -232,7 +232,7 @@ pub fn signature_hash( tx: &Transaction, consensus_branch_id: u32, hash_type: u32, - transparent_input: Option<(usize, Script, Amount)>, + transparent_input: Option<(usize, &Script, Amount)>, ) -> Vec { signature_hash_data(tx, consensus_branch_id, hash_type, transparent_input) } diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index 99c7a95..19b110a 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -212,7 +212,7 @@ fn tx_write_rejects_unexpected_binding_sig() { fn zip_0143() { struct TestVector { tx: Vec, - script_code: Vec, + script_code: Script, transparent_input: Option, hash_type: u32, amount: i64, @@ -229,7 +229,7 @@ fn zip_0143() { 0xb2, 0x83, 0x5a, 0x08, 0x05, 0x75, 0x02, 0x00, 0x02, 0x51, 0x51, 0x48, 0x1c, 0xdd, 0x86, 0xb3, 0xcc, 0x43, 0x18, 0x00, ], - script_code: vec![0x6a, 0x00, 0x00, 0x00, 0x63, 0xac, 0x53], + script_code: Script(vec![0x6a, 0x00, 0x00, 0x00, 0x63, 0xac, 0x53]), transparent_input: None, hash_type: 1, amount: 1672704339313879, @@ -518,7 +518,7 @@ fn zip_0143() { 0xb1, 0xfa, 0x45, 0xad, 0x61, 0xce, 0x9a, 0x1c, 0x47, 0x27, 0xb7, 0xaa, 0xa5, 0x35, 0x62, 0xf5, 0x23, 0xe7, 0x39, 0x52, ], - script_code: vec![0x53], + script_code: Script(vec![0x53]), transparent_input: Some(1), hash_type: 3, amount: 365293780364847, @@ -678,7 +678,7 @@ fn zip_0143() { 0x62, 0x91, 0x85, 0x00, 0x2c, 0x72, 0xc0, 0x12, 0xc4, 0x14, 0xd2, 0x38, 0x2a, 0x6d, 0x47, 0xc7, 0xb3, 0xde, 0xab, 0xa7, ], - script_code: vec![0xac, 0x00], + script_code: Script(vec![0xac, 0x00]), transparent_input: Some(0), hash_type: 3, amount: 711752082734717, @@ -960,7 +960,7 @@ fn zip_0143() { 0xce, 0x1f, 0xca, 0x2c, 0x63, 0xfe, 0x06, 0xb7, 0x98, 0x9d, 0x58, 0x4f, 0xa7, 0xd7, 0x82, 0xa8, 0x8c, 0x1e, 0x7d, 0x64, 0xb6, 0xfb, 0xf5, 0x5e, 0x35, ], - script_code: vec![0x6a, 0x53, 0x53, 0x63], + script_code: Script(vec![0x6a, 0x53, 0x53, 0x63]), transparent_input: None, hash_type: 1, amount: 379068098637835, @@ -1119,7 +1119,7 @@ fn zip_0143() { 0xc1, 0xc4, 0xf2, 0xca, 0xcd, 0xa3, 0x0b, 0xdb, 0x69, 0x30, 0x65, 0x3c, 0x0c, 0xc4, 0x48, 0x6e, 0x60, 0xe8, 0x9f, 0xa8, 0x49, 0xb3, ], - script_code: vec![0x53, 0x52], + script_code: Script(vec![0x53, 0x52]), transparent_input: Some(0), hash_type: 3, amount: 1437866676382615, @@ -1139,7 +1139,7 @@ fn zip_0143() { 0x08, 0xf0, 0x83, 0x05, 0x00, 0x09, 0x63, 0x6a, 0x52, 0x63, 0x51, 0x63, 0x00, 0x6a, 0xac, 0x9a, 0xbc, 0xef, 0x2a, 0x99, 0x08, 0x73, 0x19, 0x00, ], - script_code: vec![0x63], + script_code: Script(vec![0x63]), transparent_input: None, hash_type: 1, amount: 1993227025071196, @@ -1162,7 +1162,7 @@ fn zip_0143() { 0x87, 0x01, 0xff, 0x01, 0x86, 0xd2, 0x6f, 0xee, 0x28, 0xca, 0x06, 0x00, 0x01, 0xac, 0x5a, 0xa7, 0x27, 0xab, 0x79, 0x85, 0xda, 0x0e, 0x00, ], - script_code: vec![0x65, 0x53, 0x51], + script_code: Script(vec![0x65, 0x53, 0x51]), transparent_input: Some(1), hash_type: 130, amount: 449567650863240, @@ -1444,7 +1444,7 @@ fn zip_0143() { 0xba, 0xfe, 0xc8, 0x84, 0x0c, 0x2d, 0x25, 0x5b, 0xf5, 0xad, 0x61, 0xc4, 0x60, 0xf9, 0x8f, 0xeb, 0x82, 0xa1, 0x0f, 0xa1, 0xc0, ], - script_code: vec![0x65, 0x6a, 0x65, 0x51, 0x52, 0x65, 0x63], + script_code: Script(vec![0x65, 0x6a, 0x65, 0x51, 0x52, 0x65, 0x63]), transparent_input: None, hash_type: 1, amount: 1712463999734827, @@ -1602,7 +1602,7 @@ fn zip_0143() { 0xd9, 0xa9, 0xd9, 0xf5, 0x4f, 0xb2, 0xfe, 0x8f, 0x9f, 0x05, 0xcd, 0x11, 0x1e, 0xe4, 0x6c, 0x47, 0x10, 0xf6, 0xf6, 0x3a, 0x62, 0x69, 0x45, 0x57, ], - script_code: vec![0x53, 0x52, 0x00], + script_code: Script(vec![0x53, 0x52, 0x00]), transparent_input: Some(1), hash_type: 1, amount: 1564816348934332, @@ -1885,7 +1885,7 @@ fn zip_0143() { 0x54, 0xa7, 0x89, 0x73, 0x5b, 0x03, 0x49, 0xc4, 0xd5, 0x1c, 0x88, 0x9d, 0x08, 0x95, 0x2d, 0xdd, 0x54, 0x88, 0xbe, 0x95, 0x56, 0x05, 0x94, 0xe6, ], - script_code: vec![0x52, 0x63, 0x53, 0x51, 0x65], + script_code: Script(vec![0x52, 0x63, 0x53, 0x51, 0x65]), transparent_input: Some(0), hash_type: 2, amount: 483959951916902, @@ -1903,7 +1903,7 @@ fn zip_0143() { let transparent_input = if let Some(n) = tv.transparent_input { Some(( n as usize, - Script(tv.script_code), + &tv.script_code, Amount::from_nonnegative_i64(tv.amount).unwrap(), )) } else { @@ -1921,7 +1921,7 @@ fn zip_0143() { fn zip_0243() { struct TestVector { tx: Vec, - script_code: Vec, + script_code: Script, transparent_input: Option, hash_type: u32, amount: i64, @@ -2229,7 +2229,7 @@ fn zip_0243() { 0xe4, 0x62, 0xef, 0xf9, 0xba, 0x8b, 0x3f, 0x4b, 0xfa, 0xa1, 0x30, 0x0c, 0x26, 0x92, 0x5a, 0x87, ], - script_code: vec![0x63], + script_code: Script(vec![0x63]), transparent_input: None, hash_type: 1, amount: 1969273897303781, @@ -2462,7 +2462,7 @@ fn zip_0243() { 0xed, 0x6a, 0x9f, 0x08, 0x46, 0x4d, 0x56, 0x55, 0x93, 0xe1, 0xa6, 0x3b, 0x93, 0x85, 0x36, 0xb4, 0x92, 0x44, 0xe9, 0x7d, ], - script_code: vec![], + script_code: Script(vec![]), transparent_input: Some(1), hash_type: 2, amount: 652655344020909, @@ -3048,7 +3048,7 @@ fn zip_0243() { 0x76, 0xc5, 0x3b, 0x4d, 0xf7, 0x95, 0x39, 0x81, 0xd5, 0x5a, 0x96, 0xa6, 0xdc, 0xff, 0x99, 0x04, 0xa9, 0x08, 0x42, 0xe5, 0xba, 0xfe, 0xc8, 0x84, 0x0c, 0x2d, ], - script_code: vec![0x53, 0x63, 0x63, 0x51, 0xac, 0x00, 0x51], + script_code: Script(vec![0x53, 0x63, 0x63, 0x51, 0xac, 0x00, 0x51]), transparent_input: None, hash_type: 1, amount: 1345602751504862, @@ -3369,7 +3369,7 @@ fn zip_0243() { 0xde, 0x7f, 0x8e, 0x6a, 0x5c, 0x62, 0xa7, 0x77, 0xd1, 0x75, 0x00, 0x2a, 0x13, 0x7d, 0xe8, 0x5b, 0x88, ], - script_code: vec![], + script_code: Script(vec![]), transparent_input: None, hash_type: 1, amount: 1039204199089370, @@ -3519,7 +3519,7 @@ fn zip_0243() { 0xb5, 0x58, 0x02, 0x9a, 0x36, 0x02, 0x4d, 0x2e, 0x79, 0x0f, 0xc6, 0xfd, 0x66, 0x7f, 0x17, 0x6e, 0x0a, 0xa9, 0x9d, 0xd1, 0xd7, 0x2b, 0x57, ], - script_code: vec![0x6a, 0x51, 0x65, 0xac], + script_code: Script(vec![0x6a, 0x51, 0x65, 0xac]), transparent_input: None, hash_type: 1, amount: 691732482992802, @@ -3919,7 +3919,7 @@ fn zip_0243() { 0x30, 0x3a, 0x3a, 0xb9, 0xbb, 0x2e, 0xe3, 0x79, 0xb9, 0xaf, 0xcd, 0x1f, 0x6a, 0x3c, 0xb9, 0x00, 0x0b, 0xb1, 0x4e, ], - script_code: vec![0x53, 0x63, 0x63, 0xac, 0x63, 0x52], + script_code: Script(vec![0x53, 0x63, 0x63, 0xac, 0x63, 0x52]), transparent_input: None, hash_type: 1, amount: 1152393991505765, @@ -4083,7 +4083,7 @@ fn zip_0243() { 0x53, 0xf1, 0xd0, 0xc8, 0x65, 0xa9, 0x4a, 0xa4, 0x56, 0xdc, 0xd1, 0x8a, 0x39, 0xe2, 0xf5, 0x85, 0xd9, 0xbe, 0xa8, ], - script_code: vec![0x63, 0x00, 0x6a, 0x53, 0x63, 0x6a, 0xac, 0x00], + script_code: Script(vec![0x63, 0x00, 0x6a, 0x53, 0x63, 0x6a, 0xac, 0x00]), transparent_input: None, hash_type: 1, amount: 1788797765223798, @@ -4681,7 +4681,7 @@ fn zip_0243() { 0x31, 0xbd, 0x7c, 0x52, 0x22, 0xb6, 0x70, 0x61, 0x6e, 0x4b, 0x6c, 0xa8, 0xa2, 0x35, 0x50, 0xca, 0xd8, 0xac, 0x0d, 0xdb, 0x76, 0x45, 0xe2, 0xb9, 0x71, 0x3b, 0xe7, ], - script_code: vec![0x6a, 0x00, 0x00, 0x65, 0x53, 0xac, 0x63, 0x53, 0x63], + script_code: Script(vec![0x6a, 0x00, 0x00, 0x65, 0x53, 0xac, 0x63, 0x53, 0x63]), transparent_input: None, hash_type: 1, amount: 1871432121379810, @@ -5190,7 +5190,7 @@ fn zip_0243() { 0x1b, 0x48, 0x09, 0x8e, 0xba, 0x2c, 0x2e, 0xc2, 0x0a, 0x0a, 0xc0, 0x44, 0x3b, 0xa8, 0xe9, 0x48, 0x7b, 0xcf, 0x7d, ], - script_code: vec![0xac, 0x53, 0x63, 0x52, 0x6a, 0x51, 0xac], + script_code: Script(vec![0xac, 0x53, 0x63, 0x52, 0x6a, 0x51, 0xac]), transparent_input: None, hash_type: 1, amount: 1501997449504444, @@ -5380,7 +5380,7 @@ fn zip_0243() { 0xfb, 0x34, 0x1e, 0xf5, 0xff, 0xb4, 0x2b, 0xc2, 0xab, 0xc5, 0x08, 0xff, 0x23, 0x12, 0x48, 0xf2, 0xc2, 0xdc, 0x15, 0x77, 0x0d, 0x33, 0x72, 0x2b, 0x9c, 0x9d, 0xae, ], - script_code: vec![0xac, 0x65], + script_code: Script(vec![0xac, 0x65]), transparent_input: Some(0), hash_type: 3, amount: 391892287957268, @@ -5398,7 +5398,7 @@ fn zip_0243() { let transparent_input = if let Some(n) = tv.transparent_input { Some(( n as usize, - Script(tv.script_code), + &tv.script_code, Amount::from_nonnegative_i64(tv.amount).unwrap(), )) } else { From 3425eabda224448b3c83650f60aca3301c69907e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 31 Jul 2019 16:20:13 +0100 Subject: [PATCH 272/330] transaction::Builder::add_transparent_input() --- Cargo.lock | 28 +++++ zcash_primitives/Cargo.toml | 5 + zcash_primitives/src/transaction/builder.rs | 108 +++++++++++++++++- .../src/transaction/components.rs | 11 +- 4 files changed, 149 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe20d7a..27a6309 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -144,6 +144,11 @@ dependencies = [ "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cc" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cfg-if" version = "0.1.9" @@ -551,6 +556,16 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ripemd160" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -564,6 +579,14 @@ name = "scopeguard" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "secp256k1" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "semver" version = "0.9.0" @@ -673,6 +696,8 @@ dependencies = [ "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ripemd160 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "secp256k1 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -708,6 +733,7 @@ dependencies = [ "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" +"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" "checksum crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2d818a4990769aac0c7ff1360e233ef3a41adcb009ebb2036bf6915eb0f6b23c" @@ -752,8 +778,10 @@ dependencies = [ "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a" "checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" +"checksum ripemd160 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad5112e0dbbb87577bfbc56c42450235e3012ce336e29c5befd7807bd626da4a" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +"checksum secp256k1 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e0344a794ff109f85547039536028e12f313178ac1545e49fdf16a530d900a7b" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index c83ecf1..4766c7a 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -25,11 +25,16 @@ log = "0.4" pairing = { version = "0.15.0", path = "../pairing" } rand = "0.7" rand_core = "0.5.1" +ripemd160 = { version = "0.8", optional = true } +secp256k1 = { version = "=0.15.0", optional = true } sha2 = "0.8" [dev-dependencies] hex-literal = "0.2" rand_xorshift = "0.2" +[features] +transparent-inputs = ["ripemd160", "secp256k1"] + [badges] maintenance = { status = "actively-developed" } diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 645a6cb..e38bb8f 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -24,6 +24,12 @@ use crate::{ JUBJUB, }; +#[cfg(feature = "transparent-inputs")] +use crate::{ + legacy::Script, + transaction::components::{OutPoint, TxIn}, +}; + const DEFAULT_TX_EXPIRY_DELTA: u32 = 20; /// If there are any shielded inputs, always have at least two shielded outputs, padding @@ -130,6 +136,50 @@ impl SaplingOutput { } } +#[cfg(feature = "transparent-inputs")] +struct TransparentInputInfo { + sk: secp256k1::SecretKey, + pubkey: [u8; secp256k1::constants::PUBLIC_KEY_SIZE], + coin: TxOut, +} + +#[cfg(feature = "transparent-inputs")] +struct TransparentInputs { + secp: secp256k1::Secp256k1, + inputs: Vec, +} + +#[cfg(feature = "transparent-inputs")] +impl Default for TransparentInputs { + fn default() -> Self { + TransparentInputs { + secp: secp256k1::Secp256k1::gen_new(), + inputs: Default::default(), + } + } +} + +#[cfg(not(feature = "transparent-inputs"))] +#[derive(Default)] +struct TransparentInputs; + +impl TransparentInputs { + fn input_sum(&self) -> Amount { + #[cfg(feature = "transparent-inputs")] + { + self.inputs + .iter() + .map(|input| input.coin.value) + .sum::() + } + + #[cfg(not(feature = "transparent-inputs"))] + { + Amount::zero() + } + } +} + /// Metadata about a transaction created by a [`Builder`]. #[derive(Debug, PartialEq)] pub struct TransactionMetadata { @@ -176,6 +226,7 @@ pub struct Builder { anchor: Option, spends: Vec, outputs: Vec, + legacy: TransparentInputs, change_address: Option<(OutgoingViewingKey, PaymentAddress)>, } @@ -215,6 +266,7 @@ impl Builder { anchor: None, spends: vec![], outputs: vec![], + legacy: TransparentInputs::default(), change_address: None, } } @@ -273,6 +325,39 @@ impl Builder { Ok(()) } + /// Adds a transparent coin to be spent in this transaction. + #[cfg(feature = "transparent-inputs")] + pub fn add_transparent_input( + &mut self, + sk: secp256k1::SecretKey, + utxo: OutPoint, + coin: TxOut, + ) -> Result<(), Error> { + if coin.value.is_negative() { + return Err(Error::InvalidAmount); + } + + let pubkey = secp256k1::PublicKey::from_secret_key(&self.legacy.secp, &sk).serialize(); + match coin.script_pubkey.address() { + Some(TransparentAddress::PublicKey(hash)) => { + use ripemd160::Ripemd160; + use sha2::{Digest, Sha256}; + + if &hash[..] != &Ripemd160::digest(&Sha256::digest(&pubkey))[..] { + return Err(Error::InvalidAddress); + } + } + _ => return Err(Error::InvalidAddress), + } + + self.mtx.vin.push(TxIn::new(utxo)); + self.legacy + .inputs + .push(TransparentInputInfo { sk, pubkey, coin }); + + Ok(()) + } + /// Adds a transparent address to send funds to. pub fn add_transparent_output( &mut self, @@ -320,8 +405,7 @@ impl Builder { // // Valid change - let change = self.mtx.value_balance - - self.fee + let change = self.mtx.value_balance - self.fee + self.legacy.input_sum() - self .mtx .vout @@ -524,6 +608,26 @@ impl Builder { .map_err(|()| Error::BindingSig)?, ); + // Transparent signatures + #[cfg(feature = "transparent-inputs")] + { + for (i, info) in self.legacy.inputs.iter().enumerate() { + sighash.copy_from_slice(&signature_hash_data( + &self.mtx, + consensus_branch_id, + SIGHASH_ALL, + Some((i, &info.coin.script_pubkey, info.coin.value)), + )); + + let msg = secp256k1::Message::from_slice(&sighash).expect("32 bytes"); + let sig = self.legacy.secp.sign(&msg, &info.sk); + + // P2PKH scriptSig + self.mtx.vin[i].script_sig = + Script::default() << &sig.serialize_compact()[..] << &info.pubkey[..]; + } + } + Ok(( self.mtx.freeze().expect("Transaction should be complete"), tx_metadata, diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index 270bac5..cf83d19 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -44,11 +44,20 @@ impl OutPoint { #[derive(Debug)] pub struct TxIn { pub prevout: OutPoint, - script_sig: Script, + pub script_sig: Script, pub sequence: u32, } impl TxIn { + #[cfg(feature = "transparent-inputs")] + pub fn new(prevout: OutPoint) -> Self { + TxIn { + prevout, + script_sig: Script::default(), + sequence: std::u32::MAX, + } + } + pub fn read(mut reader: &mut R) -> io::Result { let prevout = OutPoint::read(&mut reader)?; let script_sig = Script::read(&mut reader)?; From 5a177eea27534986432e1c9addd2a22644bad94b Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Fri, 6 Sep 2019 13:37:42 -0700 Subject: [PATCH 273/330] Make mod serialize public --- zcash_primitives/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 713ca2b..d1979a6 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -26,7 +26,7 @@ pub mod primitives; pub mod prover; pub mod redjubjub; pub mod sapling; -mod serialize; +pub mod serialize; pub mod transaction; mod util; pub mod zip32; From fab9160b2619c9689c42bcfc41f20dd84266ec23 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Tue, 10 Sep 2019 10:01:13 -0700 Subject: [PATCH 274/330] transparent inputs should use serialize_der() --- zcash_primitives/src/transaction/builder.rs | 71 +++++++++++---------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index e38bb8f..ae47a32 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -457,7 +457,6 @@ impl Builder { // let mut ctx = prover.new_sapling_proving_context(); - let anchor = self.anchor.expect("anchor was set if spends were added"); // Pad Sapling outputs let orig_outputs_len = outputs.len(); @@ -474,40 +473,44 @@ impl Builder { tx_metadata.output_indices.resize(orig_outputs_len, 0); // Create Sapling SpendDescriptions - for (i, (pos, spend)) in spends.iter().enumerate() { - let proof_generation_key = spend.extsk.expsk.proof_generation_key(&JUBJUB); + if !spends.is_empty() { + let anchor = self.anchor.expect("anchor was set if spends were added"); - let mut nullifier = [0u8; 32]; - nullifier.copy_from_slice(&spend.note.nf( - &proof_generation_key.to_viewing_key(&JUBJUB), - spend.witness.position, - &JUBJUB, - )); + for (i, (pos, spend)) in spends.iter().enumerate() { + let proof_generation_key = spend.extsk.expsk.proof_generation_key(&JUBJUB); - let (zkproof, cv, rk) = prover - .spend_proof( - &mut ctx, - proof_generation_key, - spend.diversifier, - spend.note.r, - spend.alpha, - spend.note.value, + let mut nullifier = [0u8; 32]; + nullifier.copy_from_slice(&spend.note.nf( + &proof_generation_key.to_viewing_key(&JUBJUB), + spend.witness.position, + &JUBJUB, + )); + + let (zkproof, cv, rk) = prover + .spend_proof( + &mut ctx, + proof_generation_key, + spend.diversifier, + spend.note.r, + spend.alpha, + spend.note.value, + anchor, + spend.witness.clone(), + ) + .map_err(|()| Error::SpendProof)?; + + self.mtx.shielded_spends.push(SpendDescription { + cv, anchor, - spend.witness.clone(), - ) - .map_err(|()| Error::SpendProof)?; + nullifier, + rk, + zkproof, + spend_auth_sig: None, + }); - self.mtx.shielded_spends.push(SpendDescription { - cv, - anchor, - nullifier, - rk, - zkproof, - spend_auth_sig: None, - }); - - // Record the post-randomized spend location - tx_metadata.spend_indices[*pos] = i; + // Record the post-randomized spend location + tx_metadata.spend_indices[*pos] = i; + } } // Create Sapling OutputDescriptions @@ -622,9 +625,13 @@ impl Builder { let msg = secp256k1::Message::from_slice(&sighash).expect("32 bytes"); let sig = self.legacy.secp.sign(&msg, &info.sk); + // Signature has to have "SIGHASH_ALL" appended to it + let mut sig_bytes: Vec = sig.serialize_der()[..].to_vec(); + sig_bytes.extend(&[SIGHASH_ALL as u8]); + // P2PKH scriptSig self.mtx.vin[i].script_sig = - Script::default() << &sig.serialize_compact()[..] << &info.pubkey[..]; + Script::default() << &sig_bytes[..] << &info.pubkey[..]; } } From 885e09a82feeeda34c4f0bf60ad45ae8c9d52531 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Tue, 10 Sep 2019 10:30:04 -0700 Subject: [PATCH 275/330] Create OutPoint from hash and n --- zcash_primitives/src/transaction/components.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index cf83d19..2e02773 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -28,6 +28,10 @@ pub struct OutPoint { } impl OutPoint { + pub fn new(hash: [u8; 32], n: u32) -> Self { + OutPoint { hash, n } + } + pub fn read(mut reader: R) -> io::Result { let mut hash = [0; 32]; reader.read_exact(&mut hash)?; From b4799816899449292bf080da4acaa5d34ca111d0 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Thu, 12 Sep 2019 14:26:43 -0700 Subject: [PATCH 276/330] Implement clone for some structs --- zcash_primitives/src/legacy.rs | 2 +- zcash_primitives/src/transaction/components.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/zcash_primitives/src/legacy.rs b/zcash_primitives/src/legacy.rs index 18d0388..d005b25 100644 --- a/zcash_primitives/src/legacy.rs +++ b/zcash_primitives/src/legacy.rs @@ -26,7 +26,7 @@ enum OpCode { } /// A serialized script, used inside transparent inputs and outputs of a transaction. -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct Script(pub Vec); impl Script { diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs index 2e02773..dfc54fd 100644 --- a/zcash_primitives/src/transaction/components.rs +++ b/zcash_primitives/src/transaction/components.rs @@ -21,7 +21,7 @@ const PHGR_PROOF_SIZE: usize = (33 + 33 + 65 + 33 + 33 + 33 + 33 + 33); const ZC_NUM_JS_INPUTS: usize = 2; const ZC_NUM_JS_OUTPUTS: usize = 2; -#[derive(Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct OutPoint { hash: [u8; 32], n: u32, @@ -81,7 +81,7 @@ impl TxIn { } } -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct TxOut { pub value: Amount, pub script_pubkey: Script, From 4d290e7a3243adedb6ec572175747ae1789cd9b9 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Mon, 14 Oct 2019 22:20:58 -0700 Subject: [PATCH 277/330] Add regtest constants --- zcash_client_backend/src/constants.rs | 1 + zcash_client_backend/src/constants/regtest.rs | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 zcash_client_backend/src/constants/regtest.rs diff --git a/zcash_client_backend/src/constants.rs b/zcash_client_backend/src/constants.rs index 8e5727c..627bbd9 100644 --- a/zcash_client_backend/src/constants.rs +++ b/zcash_client_backend/src/constants.rs @@ -1,4 +1,5 @@ //! Zcash global and per-network constants. pub mod mainnet; +pub mod regtest; pub mod testnet; diff --git a/zcash_client_backend/src/constants/regtest.rs b/zcash_client_backend/src/constants/regtest.rs new file mode 100644 index 0000000..8f6c415 --- /dev/null +++ b/zcash_client_backend/src/constants/regtest.rs @@ -0,0 +1,45 @@ +//! # Regtest constants +//! +//! `regtest` is a `zcashd`-specific environment used for local testing. They mostly reuse +//! the testnet constants. +//! These constants are defined in [the `zcashd` codebase]. +//! [the `zcashd` codebase]: https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L482-L496 + +/// The regtest cointype reuses the testnet cointype +pub const COIN_TYPE: u32 = 1; + +/// The HRP for a Bech32-encoded regtest [`ExtendedSpendingKey`]. +/// +/// It is defined in [the `zcashd` codebase]. +/// +/// [`ExtendedSpendingKey`]: zcash_primitives::zip32::ExtendedSpendingKey +/// [the `zcashd` codebase]: https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L496 +pub const HRP_SAPLING_EXTENDED_SPENDING_KEY: &str = "secret-extended-key-regtest"; + +/// The HRP for a Bech32-encoded regtest [`ExtendedFullViewingKey`]. +/// +/// It is defined in [the `zcashd` codebase]. +/// +/// [`ExtendedFullViewingKey`]: zcash_primitives::zip32::ExtendedFullViewingKey +/// [the `zcashd` codebase]: https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L494 +pub const HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY: &str = "zxviewregtestsapling"; + +/// The HRP for a Bech32-encoded regtest [`PaymentAddress`]. +/// +/// It is defined in [the `zcashd` codebase]. +/// +/// [`PaymentAddress`]: zcash_primitives::primitives::PaymentAddress +/// [the `zcashd` codebase]: https://github.com/zcash/zcash/blob/128d863fb8be39ee294fda397c1ce3ba3b889cb2/src/chainparams.cpp#L493 +pub const HRP_SAPLING_PAYMENT_ADDRESS: &str = "zregtestsapling"; + +/// The prefix for a Base58Check-encoded regtest [`TransparentAddress::PublicKey`]. +/// Same as the testnet prefix. +/// +/// [`TransparentAddress::PublicKey`]: zcash_primitives::legacy::TransparentAddress::PublicKey +pub const B58_PUBKEY_ADDRESS_PREFIX: [u8; 2] = [0x1d, 0x25]; + +/// The prefix for a Base58Check-encoded regtest [`TransparentAddress::Script`]. +/// Same as the testnet prefix. +/// +/// [`TransparentAddress::Script`]: zcash_primitives::legacy::TransparentAddress::Script +pub const B58_SCRIPT_ADDRESS_PREFIX: [u8; 2] = [0x1c, 0xba]; From ac4acfa26e1618c4efe64f918a81dc2b337d8f94 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 31 Oct 2019 16:36:54 +0000 Subject: [PATCH 278/330] Fix rand_os warning in tests --- zcash_client_backend/src/welding_rig.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index 6b9ec59..75ed47f 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -186,8 +186,7 @@ pub fn scan_block( mod tests { use ff::{Field, PrimeField, PrimeFieldRepr}; use pairing::bls12_381::{Bls12, Fr}; - use rand_core::RngCore; - use rand_os::OsRng; + use rand_core::{OsRng, RngCore}; use zcash_primitives::{ jubjub::{fs::Fs, FixedGenerators, JubjubParams, ToUniform}, merkle_tree::CommitmentTree, From bc35a62e10f705942eb2928c57c8c8fb1c5091c7 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 31 Oct 2019 18:57:52 +0000 Subject: [PATCH 279/330] Remove rand_os dependency --- Cargo.lock | 11 ----------- zcash_client_backend/Cargo.toml | 1 - 2 files changed, 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe20d7a..d9cbf75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -534,15 +534,6 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand_os" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rand_xorshift" version = "0.2.0" @@ -648,7 +639,6 @@ dependencies = [ "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf-codegen-pure 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "zcash_primitives 0.1.0", @@ -750,7 +740,6 @@ dependencies = [ "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a" "checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" diff --git a/zcash_client_backend/Cargo.toml b/zcash_client_backend/Cargo.toml index 3c8a014..3e472fd 100644 --- a/zcash_client_backend/Cargo.toml +++ b/zcash_client_backend/Cargo.toml @@ -25,7 +25,6 @@ protobuf-codegen-pure = "2" [dev-dependencies] rand_core = "0.5" -rand_os = "0.2" rand_xorshift = "0.2" [badges] From 00280488009ffaef37cbc91be5c6748866000b2f Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 4 Nov 2019 17:48:44 +0000 Subject: [PATCH 280/330] Use C calling convention for librustzcash The Rust-to-C++ interface speaks the C ABI. The "system" ABI happens to be equivalent to the C ABI on the platforms we currently target (in particular, we don't target win32 with an x86 architecture, which would use the stdcall ABI). --- librustzcash/src/rustzcash.rs | 78 +++++++++++++++-------------------- 1 file changed, 33 insertions(+), 45 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index fc8d3ef..8f13713 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -115,7 +115,7 @@ fn fixed_scalar_mult(from: &[u8], p_g: FixedGenerators) -> edwards::Point::uncommitted().into_repr(); // Should be okay, caller is responsible for ensuring the pointer @@ -249,7 +249,7 @@ pub extern "system" fn librustzcash_tree_uncommitted(result: *mut [c_uchar; 32]) } #[no_mangle] -pub extern "system" fn librustzcash_merkle_hash( +pub extern "C" fn librustzcash_merkle_hash( depth: size_t, a: *const [c_uchar; 32], b: *const [c_uchar; 32], @@ -275,10 +275,7 @@ pub extern "system" fn librustzcash_merkle_hash( } #[no_mangle] // ToScalar -pub extern "system" fn librustzcash_to_scalar( - input: *const [c_uchar; 64], - result: *mut [c_uchar; 32], -) { +pub extern "C" fn librustzcash_to_scalar(input: *const [c_uchar; 64], result: *mut [c_uchar; 32]) { // Should be okay, because caller is responsible for ensuring // the pointer is a valid pointer to 32 bytes, and that is the // size of the representation @@ -292,10 +289,7 @@ pub extern "system" fn librustzcash_to_scalar( } #[no_mangle] -pub extern "system" fn librustzcash_ask_to_ak( - ask: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) { +pub extern "C" fn librustzcash_ask_to_ak(ask: *const [c_uchar; 32], result: *mut [c_uchar; 32]) { let ask = unsafe { &*ask }; let ak = fixed_scalar_mult(ask, FixedGenerators::SpendingKeyGenerator); @@ -305,10 +299,7 @@ pub extern "system" fn librustzcash_ask_to_ak( } #[no_mangle] -pub extern "system" fn librustzcash_nsk_to_nk( - nsk: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) { +pub extern "C" fn librustzcash_nsk_to_nk(nsk: *const [c_uchar; 32], result: *mut [c_uchar; 32]) { let nsk = unsafe { &*nsk }; let nk = fixed_scalar_mult(nsk, FixedGenerators::ProofGenerationKey); @@ -318,7 +309,7 @@ pub extern "system" fn librustzcash_nsk_to_nk( } #[no_mangle] -pub extern "system" fn librustzcash_crh_ivk( +pub extern "C" fn librustzcash_crh_ivk( ak: *const [c_uchar; 32], nk: *const [c_uchar; 32], result: *mut [c_uchar; 32], @@ -343,13 +334,13 @@ pub extern "system" fn librustzcash_crh_ivk( } #[no_mangle] -pub extern "system" fn librustzcash_check_diversifier(diversifier: *const [c_uchar; 11]) -> bool { +pub extern "C" fn librustzcash_check_diversifier(diversifier: *const [c_uchar; 11]) -> bool { let diversifier = Diversifier(unsafe { *diversifier }); diversifier.g_d::(&JUBJUB).is_some() } #[no_mangle] -pub extern "system" fn librustzcash_ivk_to_pkd( +pub extern "C" fn librustzcash_ivk_to_pkd( ivk: *const [c_uchar; 32], diversifier: *const [c_uchar; 11], result: *mut [c_uchar; 32], @@ -390,7 +381,7 @@ fn test_gen_r() { /// Return 32 byte random scalar, uniformly. #[no_mangle] -pub extern "system" fn librustzcash_sapling_generate_r(result: *mut [c_uchar; 32]) { +pub extern "C" fn librustzcash_sapling_generate_r(result: *mut [c_uchar; 32]) { // create random 64 byte buffer let mut rng = OsRng; let mut buffer = [0u8; 64]; @@ -445,7 +436,7 @@ fn priv_get_note( /// Compute Sapling note nullifier. #[no_mangle] -pub extern "system" fn librustzcash_sapling_compute_nf( +pub extern "C" fn librustzcash_sapling_compute_nf( diversifier: *const [c_uchar; 11], pk_d: *const [c_uchar; 32], value: u64, @@ -490,7 +481,7 @@ pub extern "system" fn librustzcash_sapling_compute_nf( /// Compute Sapling note commitment. #[no_mangle] -pub extern "system" fn librustzcash_sapling_compute_cm( +pub extern "C" fn librustzcash_sapling_compute_cm( diversifier: *const [c_uchar; 11], pk_d: *const [c_uchar; 32], value: u64, @@ -509,7 +500,7 @@ pub extern "system" fn librustzcash_sapling_compute_cm( } #[no_mangle] -pub extern "system" fn librustzcash_sapling_ka_agree( +pub extern "C" fn librustzcash_sapling_ka_agree( p: *const [c_uchar; 32], sk: *const [c_uchar; 32], result: *mut [c_uchar; 32], @@ -537,7 +528,7 @@ pub extern "system" fn librustzcash_sapling_ka_agree( } #[no_mangle] -pub extern "system" fn librustzcash_sapling_ka_derivepublic( +pub extern "C" fn librustzcash_sapling_ka_derivepublic( diversifier: *const [c_uchar; 11], esk: *const [c_uchar; 32], result: *mut [c_uchar; 32], @@ -565,7 +556,7 @@ pub extern "system" fn librustzcash_sapling_ka_derivepublic( } #[no_mangle] -pub extern "system" fn librustzcash_eh_isvalid( +pub extern "C" fn librustzcash_eh_isvalid( n: u32, k: u32, input: *const c_uchar, @@ -585,17 +576,14 @@ pub extern "system" fn librustzcash_eh_isvalid( } #[no_mangle] -pub extern "system" fn librustzcash_sapling_verification_ctx_init( -) -> *mut SaplingVerificationContext { +pub extern "C" fn librustzcash_sapling_verification_ctx_init() -> *mut SaplingVerificationContext { let ctx = Box::new(SaplingVerificationContext::new()); Box::into_raw(ctx) } #[no_mangle] -pub extern "system" fn librustzcash_sapling_verification_ctx_free( - ctx: *mut SaplingVerificationContext, -) { +pub extern "C" fn librustzcash_sapling_verification_ctx_free(ctx: *mut SaplingVerificationContext) { drop(unsafe { Box::from_raw(ctx) }); } @@ -604,7 +592,7 @@ const GROTH_PROOF_SIZE: usize = 48 // π_A + 48; // π_C #[no_mangle] -pub extern "system" fn librustzcash_sapling_check_spend( +pub extern "C" fn librustzcash_sapling_check_spend( ctx: *mut SaplingVerificationContext, cv: *const [c_uchar; 32], anchor: *const [c_uchar; 32], @@ -659,7 +647,7 @@ pub extern "system" fn librustzcash_sapling_check_spend( } #[no_mangle] -pub extern "system" fn librustzcash_sapling_check_output( +pub extern "C" fn librustzcash_sapling_check_output( ctx: *mut SaplingVerificationContext, cv: *const [c_uchar; 32], cm: *const [c_uchar; 32], @@ -702,7 +690,7 @@ pub extern "system" fn librustzcash_sapling_check_output( } #[no_mangle] -pub extern "system" fn librustzcash_sapling_final_check( +pub extern "C" fn librustzcash_sapling_final_check( ctx: *mut SaplingVerificationContext, value_balance: i64, binding_sig: *const [c_uchar; 64], @@ -728,7 +716,7 @@ pub extern "system" fn librustzcash_sapling_final_check( } #[no_mangle] -pub extern "system" fn librustzcash_sprout_prove( +pub extern "C" fn librustzcash_sprout_prove( proof_out: *mut [c_uchar; GROTH_PROOF_SIZE], phi: *const [c_uchar; 32], @@ -877,7 +865,7 @@ pub extern "system" fn librustzcash_sprout_prove( } #[no_mangle] -pub extern "system" fn librustzcash_sprout_verify( +pub extern "C" fn librustzcash_sprout_verify( proof: *const [c_uchar; GROTH_PROOF_SIZE], rt: *const [c_uchar; 32], h_sig: *const [c_uchar; 32], @@ -926,7 +914,7 @@ pub extern "system" fn librustzcash_sprout_verify( } #[no_mangle] -pub extern "system" fn librustzcash_sapling_output_proof( +pub extern "C" fn librustzcash_sapling_output_proof( ctx: *mut SaplingProvingContext, esk: *const [c_uchar; 32], payment_address: *const [c_uchar; 43], @@ -978,7 +966,7 @@ pub extern "system" fn librustzcash_sapling_output_proof( } #[no_mangle] -pub extern "system" fn librustzcash_sapling_spend_sig( +pub extern "C" fn librustzcash_sapling_spend_sig( ask: *const [c_uchar; 32], ar: *const [c_uchar; 32], sighash: *const [c_uchar; 32], @@ -1010,7 +998,7 @@ pub extern "system" fn librustzcash_sapling_spend_sig( } #[no_mangle] -pub extern "system" fn librustzcash_sapling_binding_sig( +pub extern "C" fn librustzcash_sapling_binding_sig( ctx: *const SaplingProvingContext, value_balance: i64, sighash: *const [c_uchar; 32], @@ -1035,7 +1023,7 @@ pub extern "system" fn librustzcash_sapling_binding_sig( } #[no_mangle] -pub extern "system" fn librustzcash_sapling_spend_proof( +pub extern "C" fn librustzcash_sapling_spend_proof( ctx: *mut SaplingProvingContext, ak: *const [c_uchar; 32], nsk: *const [c_uchar; 32], @@ -1135,19 +1123,19 @@ pub extern "system" fn librustzcash_sapling_spend_proof( } #[no_mangle] -pub extern "system" fn librustzcash_sapling_proving_ctx_init() -> *mut SaplingProvingContext { +pub extern "C" fn librustzcash_sapling_proving_ctx_init() -> *mut SaplingProvingContext { let ctx = Box::new(SaplingProvingContext::new()); Box::into_raw(ctx) } #[no_mangle] -pub extern "system" fn librustzcash_sapling_proving_ctx_free(ctx: *mut SaplingProvingContext) { +pub extern "C" fn librustzcash_sapling_proving_ctx_free(ctx: *mut SaplingProvingContext) { drop(unsafe { Box::from_raw(ctx) }); } #[no_mangle] -pub extern "system" fn librustzcash_zip32_xsk_master( +pub extern "C" fn librustzcash_zip32_xsk_master( seed: *const c_uchar, seedlen: size_t, xsk_master: *mut [c_uchar; 169], @@ -1161,7 +1149,7 @@ pub extern "system" fn librustzcash_zip32_xsk_master( } #[no_mangle] -pub extern "system" fn librustzcash_zip32_xsk_derive( +pub extern "C" fn librustzcash_zip32_xsk_derive( xsk_parent: *const [c_uchar; 169], i: u32, xsk_i: *mut [c_uchar; 169], @@ -1177,7 +1165,7 @@ pub extern "system" fn librustzcash_zip32_xsk_derive( } #[no_mangle] -pub extern "system" fn librustzcash_zip32_xfvk_derive( +pub extern "C" fn librustzcash_zip32_xfvk_derive( xfvk_parent: *const [c_uchar; 169], i: u32, xfvk_i: *mut [c_uchar; 169], @@ -1198,7 +1186,7 @@ pub extern "system" fn librustzcash_zip32_xfvk_derive( } #[no_mangle] -pub extern "system" fn librustzcash_zip32_xfvk_address( +pub extern "C" fn librustzcash_zip32_xfvk_address( xfvk: *const [c_uchar; 169], j: *const [c_uchar; 11], j_ret: *mut [c_uchar; 11], From 7722b1a50bff0de0c76ca7671f286bd5b78766a4 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 4 Nov 2019 23:48:49 +0000 Subject: [PATCH 281/330] Inline write_le --- librustzcash/src/rustzcash.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 8f13713..daf29ad 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -72,13 +72,6 @@ static mut SAPLING_SPEND_PARAMS: Option> = None; static mut SAPLING_OUTPUT_PARAMS: Option> = None; static mut SPROUT_GROTH16_PARAMS_PATH: Option = None; -/// Writes an FrRepr to [u8] of length 32 -fn write_le(f: FrRepr, to: &mut [u8]) { - assert_eq!(to.len(), 32); - - f.write_le(to).expect("length is 32 bytes"); -} - /// Reads an FrRepr from a [u8] of length 32. /// This will panic (abort) if length provided is /// not correct. @@ -244,8 +237,7 @@ pub extern "C" fn librustzcash_tree_uncommitted(result: *mut [c_uchar; 32]) { // Should be okay, caller is responsible for ensuring the pointer // is a valid pointer to 32 bytes that can be mutated. let result = unsafe { &mut *result }; - - write_le(tmp, &mut result[..]); + tmp.write_le(&mut result[..]).expect("length is 32 bytes"); } #[no_mangle] @@ -270,8 +262,7 @@ pub extern "C" fn librustzcash_merkle_hash( // Should be okay, caller is responsible for ensuring the pointer // is a valid pointer to 32 bytes that can be mutated. let result = unsafe { &mut *result }; - - write_le(tmp, &mut result[..]); + tmp.write_le(&mut result[..]).expect("length is 32 bytes"); } #[no_mangle] // ToScalar @@ -494,7 +485,10 @@ pub extern "C" fn librustzcash_sapling_compute_cm( }; let result = unsafe { &mut *result }; - write_le(note.cm(&JUBJUB).into_repr(), &mut result[..]); + note.cm(&JUBJUB) + .into_repr() + .write_le(&mut result[..]) + .expect("length is 32 bytes"); true } From 5d036194660836b064e70d74dd223ab110db333a Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 4 Nov 2019 23:50:51 +0000 Subject: [PATCH 282/330] Rename read_le to read_fr to match read_fs --- librustzcash/src/rustzcash.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index daf29ad..e96dc4d 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -75,7 +75,7 @@ static mut SPROUT_GROTH16_PARAMS_PATH: Option = None; /// Reads an FrRepr from a [u8] of length 32. /// This will panic (abort) if length provided is /// not correct. -fn read_le(from: &[u8]) -> FrRepr { +fn read_fr(from: &[u8]) -> FrRepr { assert_eq!(from.len(), 32); let mut f = FrRepr::default(); @@ -250,12 +250,12 @@ pub extern "C" fn librustzcash_merkle_hash( // Should be okay, because caller is responsible for ensuring // the pointer is a valid pointer to 32 bytes, and that is the // size of the representation - let a_repr = read_le(unsafe { &(&*a)[..] }); + let a_repr = read_fr(unsafe { &(&*a)[..] }); // Should be okay, because caller is responsible for ensuring // the pointer is a valid pointer to 32 bytes, and that is the // size of the representation - let b_repr = read_le(unsafe { &(&*b)[..] }); + let b_repr = read_fr(unsafe { &(&*b)[..] }); let tmp = merkle_hash(depth, &a_repr, &b_repr); @@ -604,7 +604,7 @@ pub extern "C" fn librustzcash_sapling_check_spend( // Deserialize the anchor, which should be an element // of Fr. - let anchor = match Fr::from_repr(read_le(&(unsafe { &*anchor })[..])) { + let anchor = match Fr::from_repr(read_fr(&(unsafe { &*anchor })[..])) { Ok(a) => a, Err(_) => return false, }; @@ -656,7 +656,7 @@ pub extern "C" fn librustzcash_sapling_check_output( // Deserialize the commitment, which should be an element // of Fr. - let cm = match Fr::from_repr(read_le(&(unsafe { &*cm })[..])) { + let cm = match Fr::from_repr(read_fr(&(unsafe { &*cm })[..])) { Ok(a) => a, Err(_) => return false, }; @@ -1071,7 +1071,7 @@ pub extern "C" fn librustzcash_sapling_spend_proof( }; // We need to compute the anchor of the Spend. - let anchor = match Fr::from_repr(read_le(unsafe { &(&*anchor)[..] })) { + let anchor = match Fr::from_repr(read_fr(unsafe { &(&*anchor)[..] })) { Ok(p) => p, Err(_) => return false, }; From 7181d603be42d5dc13ca12269a7ba76673155535 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 4 Nov 2019 23:54:04 +0000 Subject: [PATCH 283/330] Explicitly pass [u8; 32] into read_fr and read_fs --- librustzcash/src/rustzcash.rs | 56 ++++++++++++++--------------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index e96dc4d..85a1306 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -72,35 +72,23 @@ static mut SAPLING_SPEND_PARAMS: Option> = None; static mut SAPLING_OUTPUT_PARAMS: Option> = None; static mut SPROUT_GROTH16_PARAMS_PATH: Option = None; -/// Reads an FrRepr from a [u8] of length 32. -/// This will panic (abort) if length provided is -/// not correct. -fn read_fr(from: &[u8]) -> FrRepr { - assert_eq!(from.len(), 32); - +/// Reads an FrRepr from a [u8; 32]. +fn read_fr(from: &[u8; 32]) -> FrRepr { let mut f = FrRepr::default(); - f.read_le(from).expect("length is 32 bytes"); - + f.read_le(&from[..]).expect("length is 32 bytes"); f } -/// Reads an FsRepr from [u8] of length 32 -/// This will panic (abort) if length provided is -/// not correct -fn read_fs(from: &[u8]) -> FsRepr { - assert_eq!(from.len(), 32); - +/// Reads an FsRepr from a [u8; 32]. +fn read_fs(from: &[u8; 32]) -> FsRepr { let mut f = <::Fs as PrimeField>::Repr::default(); - f.read_le(from).expect("length is 32 bytes"); - + f.read_le(&from[..]).expect("length is 32 bytes"); f } -/// Reads an FsRepr from [u8] of length 32 +/// Reads an FsRepr from a [u8; 32] /// and multiplies it by the given base. -/// This will panic (abort) if length provided is -/// not correct -fn fixed_scalar_mult(from: &[u8], p_g: FixedGenerators) -> edwards::Point { +fn fixed_scalar_mult(from: &[u8; 32], p_g: FixedGenerators) -> edwards::Point { let f = read_fs(from); JUBJUB.generator(p_g).mul(f, &JUBJUB) @@ -250,12 +238,12 @@ pub extern "C" fn librustzcash_merkle_hash( // Should be okay, because caller is responsible for ensuring // the pointer is a valid pointer to 32 bytes, and that is the // size of the representation - let a_repr = read_fr(unsafe { &(&*a)[..] }); + let a_repr = read_fr(unsafe { &*a }); // Should be okay, because caller is responsible for ensuring // the pointer is a valid pointer to 32 bytes, and that is the // size of the representation - let b_repr = read_fr(unsafe { &(&*b)[..] }); + let b_repr = read_fr(unsafe { &*b }); let tmp = merkle_hash(depth, &a_repr, &b_repr); @@ -410,7 +398,7 @@ fn priv_get_note( }; // Deserialize randomness - let r = match Fs::from_repr(read_fs(&(unsafe { &*r })[..])) { + let r = match Fs::from_repr(read_fs(unsafe { &*r })) { Ok(r) => r, Err(_) => return Err(()), }; @@ -506,7 +494,7 @@ pub extern "C" fn librustzcash_sapling_ka_agree( }; // Deserialize sk - let sk = match Fs::from_repr(read_fs(&(unsafe { &*sk })[..])) { + let sk = match Fs::from_repr(read_fs(unsafe { &*sk })) { Ok(p) => p, Err(_) => return false, }; @@ -536,7 +524,7 @@ pub extern "C" fn librustzcash_sapling_ka_derivepublic( }; // Deserialize esk - let esk = match Fs::from_repr(read_fs(&(unsafe { &*esk })[..])) { + let esk = match Fs::from_repr(read_fs(unsafe { &*esk })) { Ok(p) => p, Err(_) => return false, }; @@ -604,7 +592,7 @@ pub extern "C" fn librustzcash_sapling_check_spend( // Deserialize the anchor, which should be an element // of Fr. - let anchor = match Fr::from_repr(read_fr(&(unsafe { &*anchor })[..])) { + let anchor = match Fr::from_repr(read_fr(unsafe { &*anchor })) { Ok(a) => a, Err(_) => return false, }; @@ -656,7 +644,7 @@ pub extern "C" fn librustzcash_sapling_check_output( // Deserialize the commitment, which should be an element // of Fr. - let cm = match Fr::from_repr(read_fr(&(unsafe { &*cm })[..])) { + let cm = match Fr::from_repr(read_fr(unsafe { &*cm })) { Ok(a) => a, Err(_) => return false, }; @@ -918,7 +906,7 @@ pub extern "C" fn librustzcash_sapling_output_proof( zkproof: *mut [c_uchar; GROTH_PROOF_SIZE], ) -> bool { // Grab `esk`, which the caller should have constructed for the DH key exchange. - let esk = match Fs::from_repr(read_fs(&(unsafe { &*esk })[..])) { + let esk = match Fs::from_repr(read_fs(unsafe { &*esk })) { Ok(p) => p, Err(_) => return false, }; @@ -931,7 +919,7 @@ pub extern "C" fn librustzcash_sapling_output_proof( }; // The caller provides the commitment randomness for the output note - let rcm = match Fs::from_repr(read_fs(&(unsafe { &*rcm })[..])) { + let rcm = match Fs::from_repr(read_fs(unsafe { &*rcm })) { Ok(p) => p, Err(_) => return false, }; @@ -967,7 +955,7 @@ pub extern "C" fn librustzcash_sapling_spend_sig( result: *mut [c_uchar; 64], ) -> bool { // The caller provides the re-randomization of `ak`. - let ar = match Fs::from_repr(read_fs(&(unsafe { &*ar })[..])) { + let ar = match Fs::from_repr(read_fs(unsafe { &*ar })) { Ok(p) => p, Err(_) => return false, }; @@ -1044,7 +1032,7 @@ pub extern "C" fn librustzcash_sapling_spend_proof( }; // Grab `nsk` from the caller - let nsk = match Fs::from_repr(read_fs(&(unsafe { &*nsk })[..])) { + let nsk = match Fs::from_repr(read_fs(unsafe { &*nsk })) { Ok(p) => p, Err(_) => return false, }; @@ -1059,19 +1047,19 @@ pub extern "C" fn librustzcash_sapling_spend_proof( let diversifier = Diversifier(unsafe { *diversifier }); // The caller chooses the note randomness - let rcm = match Fs::from_repr(read_fs(&(unsafe { &*rcm })[..])) { + let rcm = match Fs::from_repr(read_fs(unsafe { &*rcm })) { Ok(p) => p, Err(_) => return false, }; // The caller also chooses the re-randomization of ak - let ar = match Fs::from_repr(read_fs(&(unsafe { &*ar })[..])) { + let ar = match Fs::from_repr(read_fs(unsafe { &*ar })) { Ok(p) => p, Err(_) => return false, }; // We need to compute the anchor of the Spend. - let anchor = match Fr::from_repr(read_fr(unsafe { &(&*anchor)[..] })) { + let anchor = match Fr::from_repr(read_fr(unsafe { &*anchor })) { Ok(p) => p, Err(_) => return false, }; From 9cb8c0b3c4756afacd4d9d6ee7d490afcec94319 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 5 Nov 2019 01:04:40 +0000 Subject: [PATCH 284/330] Pull librustzcash.h documentation into crate --- librustzcash/src/rustzcash.rs | 71 +++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 85a1306..0168e0d 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -94,6 +94,8 @@ fn fixed_scalar_mult(from: &[u8; 32], p_g: FixedGenerators) -> edwards::Point::uncommitted().into_repr(); @@ -228,6 +235,13 @@ pub extern "C" fn librustzcash_tree_uncommitted(result: *mut [c_uchar; 32]) { tmp.write_le(&mut result[..]).expect("length is 32 bytes"); } +/// Computes a merkle tree hash for a given depth. The `depth` parameter should +/// not be larger than 62. +/// +/// `a` and `b` each must be of length 32, and must each be scalars of BLS12-381. +/// +/// The result of the merkle tree hash is placed in `result`, which must also be +/// of length 32. #[no_mangle] pub extern "C" fn librustzcash_merkle_hash( depth: size_t, @@ -358,7 +372,7 @@ fn test_gen_r() { let _ = Fs::from_repr(repr).unwrap(); } -/// Return 32 byte random scalar, uniformly. +/// Generate uniformly random scalar in Jubjub. The result is of length 32. #[no_mangle] pub extern "C" fn librustzcash_sapling_generate_r(result: *mut [c_uchar; 32]) { // create random 64 byte buffer @@ -413,7 +427,12 @@ fn priv_get_note( Ok(note) } -/// Compute Sapling note nullifier. +/// Compute a Sapling nullifier. +/// +/// The `diversifier` parameter must be 11 bytes in length. +/// The `pk_d`, `r`, `ak` and `nk` parameters must be of length 32. +/// The result is also of length 32 and placed in `result`. +/// Returns false if `diversifier` or `pk_d` is not valid. #[no_mangle] pub extern "C" fn librustzcash_sapling_compute_nf( diversifier: *const [c_uchar; 11], @@ -458,7 +477,12 @@ pub extern "C" fn librustzcash_sapling_compute_nf( true } -/// Compute Sapling note commitment. +/// Compute a Sapling commitment. +/// +/// The `diversifier` parameter must be 11 bytes in length. +/// The `pk_d` and `r` parameters must be of length 32. +/// The result is also of length 32 and placed in `result`. +/// Returns false if `diversifier` or `pk_d` is not valid. #[no_mangle] pub extern "C" fn librustzcash_sapling_compute_cm( diversifier: *const [c_uchar; 11], @@ -481,6 +505,10 @@ pub extern "C" fn librustzcash_sapling_compute_cm( true } +/// Compute [sk] [8] P for some 32-byte point P, and 32-byte Fs. +/// +/// If P or sk are invalid, returns false. Otherwise, the result is written to +/// the 32-byte `result` buffer. #[no_mangle] pub extern "C" fn librustzcash_sapling_ka_agree( p: *const [c_uchar; 32], @@ -509,6 +537,9 @@ pub extern "C" fn librustzcash_sapling_ka_agree( true } +/// Compute g_d = GH(diversifier) and returns false if the diversifier is +/// invalid. Computes [esk] g_d and writes the result to the 32-byte `result` +/// buffer. Returns false if `esk` is not a valid scalar. #[no_mangle] pub extern "C" fn librustzcash_sapling_ka_derivepublic( diversifier: *const [c_uchar; 11], @@ -537,6 +568,8 @@ pub extern "C" fn librustzcash_sapling_ka_derivepublic( true } +/// Validates the provided Equihash solution against the given parameters, input +/// and nonce. #[no_mangle] pub extern "C" fn librustzcash_eh_isvalid( n: u32, @@ -557,6 +590,7 @@ pub extern "C" fn librustzcash_eh_isvalid( equihash::is_valid_solution(n, k, rs_input, rs_nonce, rs_soln) } +/// Creates a Sapling verification context. Please free this when you're done. #[no_mangle] pub extern "C" fn librustzcash_sapling_verification_ctx_init() -> *mut SaplingVerificationContext { let ctx = Box::new(SaplingVerificationContext::new()); @@ -564,6 +598,8 @@ pub extern "C" fn librustzcash_sapling_verification_ctx_init() -> *mut SaplingVe Box::into_raw(ctx) } +/// Frees a Sapling verification context returned from +/// [`librustzcash_sapling_verification_ctx_init`]. #[no_mangle] pub extern "C" fn librustzcash_sapling_verification_ctx_free(ctx: *mut SaplingVerificationContext) { drop(unsafe { Box::from_raw(ctx) }); @@ -573,6 +609,8 @@ const GROTH_PROOF_SIZE: usize = 48 // π_A + 96 // π_B + 48; // π_C +/// Check the validity of a Sapling Spend description, accumulating the value +/// commitment into the context. #[no_mangle] pub extern "C" fn librustzcash_sapling_check_spend( ctx: *mut SaplingVerificationContext, @@ -628,6 +666,8 @@ pub extern "C" fn librustzcash_sapling_check_spend( ) } +/// Check the validity of a Sapling Output description, accumulating the value +/// commitment into the context. #[no_mangle] pub extern "C" fn librustzcash_sapling_check_output( ctx: *mut SaplingVerificationContext, @@ -671,6 +711,8 @@ pub extern "C" fn librustzcash_sapling_check_output( ) } +/// Finally checks the validity of the entire Sapling transaction given +/// valueBalance and the binding signature. #[no_mangle] pub extern "C" fn librustzcash_sapling_final_check( ctx: *mut SaplingVerificationContext, @@ -697,6 +739,7 @@ pub extern "C" fn librustzcash_sapling_final_check( ) } +/// Sprout JoinSplit proof generation. #[no_mangle] pub extern "C" fn librustzcash_sprout_prove( proof_out: *mut [c_uchar; GROTH_PROOF_SIZE], @@ -846,6 +889,7 @@ pub extern "C" fn librustzcash_sprout_prove( .expect("should be able to serialize a proof"); } +/// Sprout JoinSplit proof verification. #[no_mangle] pub extern "C" fn librustzcash_sprout_verify( proof: *const [c_uchar; GROTH_PROOF_SIZE], @@ -895,6 +939,8 @@ pub extern "C" fn librustzcash_sprout_verify( } } +/// This function (using the proving context) constructs an Output proof given +/// the necessary witness information. It outputs `cv` and the `zkproof`. #[no_mangle] pub extern "C" fn librustzcash_sapling_output_proof( ctx: *mut SaplingProvingContext, @@ -947,6 +993,11 @@ pub extern "C" fn librustzcash_sapling_output_proof( true } +/// Computes the signature for each Spend description, given the key `ask`, the +/// re-randomization `ar`, the 32-byte sighash `sighash`, and an output `result` +/// buffer of 64-bytes for the signature. +/// +/// This function will fail if the provided `ask` or `ar` are invalid. #[no_mangle] pub extern "C" fn librustzcash_sapling_spend_sig( ask: *const [c_uchar; 32], @@ -979,6 +1030,10 @@ pub extern "C" fn librustzcash_sapling_spend_sig( true } +/// This function (using the proving context) constructs a binding signature. +/// +/// You must provide the intended valueBalance so that we can internally check +/// consistency. #[no_mangle] pub extern "C" fn librustzcash_sapling_binding_sig( ctx: *const SaplingProvingContext, @@ -1004,6 +1059,9 @@ pub extern "C" fn librustzcash_sapling_binding_sig( true } +/// This function (using the proving context) constructs a Spend proof given the +/// necessary witness information. It outputs `cv` (the value commitment) and +/// `rk` (so that you don't have to compute it) along with the proof. #[no_mangle] pub extern "C" fn librustzcash_sapling_spend_proof( ctx: *mut SaplingProvingContext, @@ -1104,6 +1162,7 @@ pub extern "C" fn librustzcash_sapling_spend_proof( true } +/// Creates a Sapling proving context. Please free this when you're done. #[no_mangle] pub extern "C" fn librustzcash_sapling_proving_ctx_init() -> *mut SaplingProvingContext { let ctx = Box::new(SaplingProvingContext::new()); @@ -1111,11 +1170,14 @@ pub extern "C" fn librustzcash_sapling_proving_ctx_init() -> *mut SaplingProving Box::into_raw(ctx) } +/// Frees a Sapling proving context returned from +/// [`librustzcash_sapling_proving_ctx_init`]. #[no_mangle] pub extern "C" fn librustzcash_sapling_proving_ctx_free(ctx: *mut SaplingProvingContext) { drop(unsafe { Box::from_raw(ctx) }); } +/// Derive the master ExtendedSpendingKey from a seed. #[no_mangle] pub extern "C" fn librustzcash_zip32_xsk_master( seed: *const c_uchar, @@ -1130,6 +1192,7 @@ pub extern "C" fn librustzcash_zip32_xsk_master( .expect("should be able to serialize an ExtendedSpendingKey"); } +/// Derive a child ExtendedSpendingKey from a parent. #[no_mangle] pub extern "C" fn librustzcash_zip32_xsk_derive( xsk_parent: *const [c_uchar; 169], @@ -1146,6 +1209,7 @@ pub extern "C" fn librustzcash_zip32_xsk_derive( .expect("should be able to serialize an ExtendedSpendingKey"); } +/// Derive a child ExtendedFullViewingKey from a parent. #[no_mangle] pub extern "C" fn librustzcash_zip32_xfvk_derive( xfvk_parent: *const [c_uchar; 169], @@ -1167,6 +1231,7 @@ pub extern "C" fn librustzcash_zip32_xfvk_derive( true } +/// Derive a PaymentAddress from an ExtendedFullViewingKey. #[no_mangle] pub extern "C" fn librustzcash_zip32_xfvk_address( xfvk: *const [c_uchar; 169], From 8651bb41cea564f27e8bc02be6719e92ff5e1d14 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 5 Nov 2019 02:49:13 +0000 Subject: [PATCH 285/330] Clean up librustzcash imports --- librustzcash/src/rustzcash.rs | 44 ++++++++++++++--------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 0168e0d..f166bd9 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -1,38 +1,20 @@ // Catch documentation errors caused by code changes. #![deny(intra_doc_link_resolution_failure)] -use lazy_static; - -use ff::{PrimeField, PrimeFieldRepr}; -use pairing::bls12_381::{Bls12, Fr, FrRepr}; - -use zcash_primitives::{ - constants::CRH_IVK_PERSONALIZATION, - jubjub::{ - edwards, - fs::{Fs, FsRepr}, - FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder, ToUniform, Unknown, - }, +use bellman::{ + gadgets::multipack, + groth16::{create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof}, }; - -use zcash_proofs::circuit::sapling::TREE_DEPTH as SAPLING_TREE_DEPTH; -use zcash_proofs::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH}; - -use bellman::gadgets::multipack; -use bellman::groth16::{ - create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof, -}; - use blake2s_simd::Params as Blake2sParams; - use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; - -use rand_core::{OsRng, RngCore}; -use std::io::BufReader; - +use ff::{PrimeField, PrimeFieldRepr}; +use lazy_static; use libc::{c_char, c_uchar, size_t}; +use pairing::bls12_381::{Bls12, Fr, FrRepr}; +use rand_core::{OsRng, RngCore}; use std::ffi::CStr; use std::fs::File; +use std::io::BufReader; use std::path::{Path, PathBuf}; use std::slice; @@ -48,6 +30,12 @@ use std::os::windows::ffi::OsStringExt; use zcash_primitives::{ block::equihash, + constants::CRH_IVK_PERSONALIZATION, + jubjub::{ + edwards, + fs::{Fs, FsRepr}, + FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder, ToUniform, Unknown, + }, merkle_tree::CommitmentTreeWitness, note_encryption::sapling_ka_agree, primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ViewingKey}, @@ -57,6 +45,10 @@ use zcash_primitives::{ zip32, JUBJUB, }; use zcash_proofs::{ + circuit::{ + sapling::TREE_DEPTH as SAPLING_TREE_DEPTH, + sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH}, + }, load_parameters, sapling::{SaplingProvingContext, SaplingVerificationContext}, }; From de5943aea4a44d7e748ac4b038512bf7e734fb6e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 5 Nov 2019 02:50:42 +0000 Subject: [PATCH 286/330] Ignore clippy::not_unsafe_ptr_arg_deref lint --- librustzcash/src/rustzcash.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index f166bd9..83d24d0 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -1,5 +1,19 @@ // Catch documentation errors caused by code changes. #![deny(intra_doc_link_resolution_failure)] +// Clippy has a default-deny lint to prevent dereferencing raw pointer arguments +// in a non-unsafe function. However, declaring a function as unsafe has the +// side-effect that the entire function body is treated as an unsafe {} block, +// and rustc will not enforce full safety checks on the parts of the function +// that would otherwise be safe. +// +// The functions in this crate are all for FFI usage, so it's obvious to the +// caller (which is only ever zcashd) that the arguments must satisfy the +// necessary assumptions. We therefore ignore this lint to retain the benefit of +// explicitly annotating the parts of each function that must themselves satisfy +// assumptions of underlying code. +// +// See https://github.com/rust-lang/rfcs/pull/2585 for more background. +#![allow(clippy::not_unsafe_ptr_arg_deref)] use bellman::{ gadgets::multipack, From d1bc61800c162839dbbbf6e2e4fb55d33388fdde Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 6 Nov 2019 08:58:42 +0000 Subject: [PATCH 287/330] Move Sprout proof logic into zcash_proofs --- Cargo.lock | 1 - librustzcash/Cargo.toml | 1 - librustzcash/src/rustzcash.rs | 177 ++++++++------------------------- zcash_proofs/src/lib.rs | 1 + zcash_proofs/src/sprout.rs | 179 ++++++++++++++++++++++++++++++++++ 5 files changed, 222 insertions(+), 137 deletions(-) create mode 100644 zcash_proofs/src/sprout.rs diff --git a/Cargo.lock b/Cargo.lock index d9cbf75..3ab00a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,7 +362,6 @@ dependencies = [ "bellman 0.2.0", "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ff 0.5.0", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index 432222b..8f33896 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -27,7 +27,6 @@ ff = { version = "0.5.0", path = "../ff" } libc = "0.2" pairing = { version = "0.15.0", path = "../pairing" } lazy_static = "1" -byteorder = "1" rand_core = "0.5.1" zcash_primitives = { version = "0.1.0", path = "../zcash_primitives" } zcash_proofs = { version = "0.1.0", path = "../zcash_proofs" } diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 83d24d0..98c9ff7 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -15,12 +15,8 @@ // See https://github.com/rust-lang/rfcs/pull/2585 for more background. #![allow(clippy::not_unsafe_ptr_arg_deref)] -use bellman::{ - gadgets::multipack, - groth16::{create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof}, -}; +use bellman::groth16::{Parameters, PreparedVerifyingKey, Proof}; use blake2s_simd::Params as Blake2sParams; -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use ff::{PrimeField, PrimeFieldRepr}; use lazy_static; use libc::{c_char, c_uchar, size_t}; @@ -59,12 +55,10 @@ use zcash_primitives::{ zip32, JUBJUB, }; use zcash_proofs::{ - circuit::{ - sapling::TREE_DEPTH as SAPLING_TREE_DEPTH, - sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH}, - }, + circuit::sapling::TREE_DEPTH as SAPLING_TREE_DEPTH, load_parameters, sapling::{SaplingProvingContext, SaplingVerificationContext}, + sprout, }; #[cfg(test)] @@ -759,14 +753,14 @@ pub extern "C" fn librustzcash_sprout_prove( in_value1: u64, in_rho1: *const [c_uchar; 32], in_r1: *const [c_uchar; 32], - in_auth1: *const [c_uchar; 1 + 33 * SPROUT_TREE_DEPTH + 8], + in_auth1: *const [c_uchar; sprout::WITNESS_PATH_SIZE], // Second input in_sk2: *const [c_uchar; 32], in_value2: u64, in_rho2: *const [c_uchar; 32], in_r2: *const [c_uchar; 32], - in_auth2: *const [c_uchar; 1 + 33 * SPROUT_TREE_DEPTH + 8], + in_auth2: *const [c_uchar; sprout::WITNESS_PATH_SIZE], // First output out_pk1: *const [c_uchar; 32], @@ -782,94 +776,6 @@ pub extern "C" fn librustzcash_sprout_prove( vpub_old: u64, vpub_new: u64, ) { - let phi = unsafe { *phi }; - let rt = unsafe { *rt }; - let h_sig = unsafe { *h_sig }; - let in_sk1 = unsafe { *in_sk1 }; - let in_rho1 = unsafe { *in_rho1 }; - let in_r1 = unsafe { *in_r1 }; - let in_auth1 = unsafe { *in_auth1 }; - let in_sk2 = unsafe { *in_sk2 }; - let in_rho2 = unsafe { *in_rho2 }; - let in_r2 = unsafe { *in_r2 }; - let in_auth2 = unsafe { *in_auth2 }; - let out_pk1 = unsafe { *out_pk1 }; - let out_r1 = unsafe { *out_r1 }; - let out_pk2 = unsafe { *out_pk2 }; - let out_r2 = unsafe { *out_r2 }; - - let mut inputs = Vec::with_capacity(2); - { - let mut handle_input = |sk, value, rho, r, mut auth: &[u8]| { - let value = Some(value); - let rho = Some(sprout::UniqueRandomness(rho)); - let r = Some(sprout::CommitmentRandomness(r)); - let a_sk = Some(sprout::SpendingKey(sk)); - - // skip the first byte - assert_eq!(auth[0], SPROUT_TREE_DEPTH as u8); - auth = &auth[1..]; - - let mut auth_path = [None; SPROUT_TREE_DEPTH]; - for i in (0..SPROUT_TREE_DEPTH).rev() { - // skip length of inner vector - assert_eq!(auth[0], 32); - auth = &auth[1..]; - - let mut sibling = [0u8; 32]; - sibling.copy_from_slice(&auth[0..32]); - auth = &auth[32..]; - - auth_path[i] = Some((sibling, false)); - } - - let mut position = auth - .read_u64::() - .expect("should have had index at the end"); - - for i in 0..SPROUT_TREE_DEPTH { - auth_path[i].as_mut().map(|p| p.1 = (position & 1) == 1); - - position >>= 1; - } - - inputs.push(sprout::JSInput { - value: value, - a_sk: a_sk, - rho: rho, - r: r, - auth_path: auth_path, - }); - }; - - handle_input(in_sk1, in_value1, in_rho1, in_r1, &in_auth1[..]); - handle_input(in_sk2, in_value2, in_rho2, in_r2, &in_auth2[..]); - } - - let mut outputs = Vec::with_capacity(2); - { - let mut handle_output = |a_pk, value, r| { - outputs.push(sprout::JSOutput { - value: Some(value), - a_pk: Some(sprout::PayingKey(a_pk)), - r: Some(sprout::CommitmentRandomness(r)), - }); - }; - - handle_output(out_pk1, out_value1, out_r1); - handle_output(out_pk2, out_value2, out_r2); - } - - let js = sprout::JoinSplit { - vpub_old: Some(vpub_old), - vpub_new: Some(vpub_new), - h_sig: Some(h_sig), - phi: Some(phi), - inputs: inputs, - outputs: outputs, - rt: Some(rt), - }; - // Load parameters from disk let sprout_fs = File::open( unsafe { &SPROUT_GROTH16_PARAMS_PATH } @@ -885,10 +791,30 @@ pub extern "C" fn librustzcash_sprout_prove( drop(sprout_fs); - // Initialize secure RNG - let mut rng = OsRng; - - let proof = create_random_proof(js, ¶ms, &mut rng).expect("proving should not fail"); + let proof = sprout::create_proof( + unsafe { *phi }, + unsafe { *rt }, + unsafe { *h_sig }, + unsafe { *in_sk1 }, + in_value1, + unsafe { *in_rho1 }, + unsafe { *in_r1 }, + unsafe { &*in_auth1 }, + unsafe { *in_sk2 }, + in_value2, + unsafe { *in_rho2 }, + unsafe { *in_r2 }, + unsafe { &*in_auth2 }, + unsafe { *out_pk1 }, + out_value1, + unsafe { *out_r1 }, + unsafe { *out_pk2 }, + out_value2, + unsafe { *out_r2 }, + vpub_old, + vpub_new, + ¶ms, + ); proof .write(&mut (unsafe { &mut *proof_out })[..]) @@ -910,39 +836,20 @@ pub extern "C" fn librustzcash_sprout_verify( vpub_old: u64, vpub_new: u64, ) -> bool { - // Prepare the public input for the verifier - let mut public_input = Vec::with_capacity((32 * 8) + (8 * 2)); - public_input.extend(unsafe { &(&*rt)[..] }); - public_input.extend(unsafe { &(&*h_sig)[..] }); - public_input.extend(unsafe { &(&*nf1)[..] }); - public_input.extend(unsafe { &(&*mac1)[..] }); - public_input.extend(unsafe { &(&*nf2)[..] }); - public_input.extend(unsafe { &(&*mac2)[..] }); - public_input.extend(unsafe { &(&*cm1)[..] }); - public_input.extend(unsafe { &(&*cm2)[..] }); - public_input.write_u64::(vpub_old).unwrap(); - public_input.write_u64::(vpub_new).unwrap(); - - let public_input = multipack::bytes_to_bits(&public_input); - let public_input = multipack::compute_multipacking::(&public_input); - - let proof = match Proof::read(unsafe { &(&*proof)[..] }) { - Ok(p) => p, - Err(_) => return false, - }; - - // Verify the proof - match verify_proof( + sprout::verify_proof( + unsafe { &*proof }, + unsafe { &*rt }, + unsafe { &*h_sig }, + unsafe { &*mac1 }, + unsafe { &*mac2 }, + unsafe { &*nf1 }, + unsafe { &*nf2 }, + unsafe { &*cm1 }, + unsafe { &*cm2 }, + vpub_old, + vpub_new, unsafe { SPROUT_GROTH16_VK.as_ref() }.expect("parameters should have been initialized"), - &proof, - &public_input[..], - ) { - // No error, and proof verification successful - Ok(true) => true, - - // Any other case - _ => false, - } + ) } /// This function (using the proving context) constructs an Output proof given diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs index 0a1f9f2..1e8ceb2 100644 --- a/zcash_proofs/src/lib.rs +++ b/zcash_proofs/src/lib.rs @@ -15,6 +15,7 @@ use std::path::Path; pub mod circuit; mod hashreader; pub mod sapling; +pub mod sprout; #[cfg(feature = "local-prover")] pub mod prover; diff --git a/zcash_proofs/src/sprout.rs b/zcash_proofs/src/sprout.rs new file mode 100644 index 0000000..30ec821 --- /dev/null +++ b/zcash_proofs/src/sprout.rs @@ -0,0 +1,179 @@ +//! APIs for creating and verifying Sprout proofs. + +use bellman::{ + gadgets::multipack, + groth16::{self, create_random_proof, Parameters, PreparedVerifyingKey, Proof}, +}; +use pairing::bls12_381::Bls12; +use rand_core::OsRng; + +use crate::circuit::sprout::*; + +const GROTH_PROOF_SIZE: usize = 48 // π_A + + 96 // π_B + + 48; // π_C +pub const WITNESS_PATH_SIZE: usize = 1 + 33 * TREE_DEPTH + 8; + +/// Sprout JoinSplit proof generation. +pub fn create_proof( + phi: [u8; 32], + rt: [u8; 32], + h_sig: [u8; 32], + + // First input + in_sk1: [u8; 32], + in_value1: u64, + in_rho1: [u8; 32], + in_r1: [u8; 32], + in_auth1: &[u8; WITNESS_PATH_SIZE], + + // Second input + in_sk2: [u8; 32], + in_value2: u64, + in_rho2: [u8; 32], + in_r2: [u8; 32], + in_auth2: &[u8; WITNESS_PATH_SIZE], + + // First output + out_pk1: [u8; 32], + out_value1: u64, + out_r1: [u8; 32], + + // Second output + out_pk2: [u8; 32], + out_value2: u64, + out_r2: [u8; 32], + + // Public value + vpub_old: u64, + vpub_new: u64, + + proving_key: &Parameters, +) -> Proof { + let mut inputs = Vec::with_capacity(2); + { + let mut handle_input = |sk, value, rho, r, mut auth: &[u8]| { + let value = Some(value); + let rho = Some(UniqueRandomness(rho)); + let r = Some(CommitmentRandomness(r)); + let a_sk = Some(SpendingKey(sk)); + + // skip the first byte + assert_eq!(auth[0], TREE_DEPTH as u8); + auth = &auth[1..]; + + let mut auth_path = [None; TREE_DEPTH]; + for i in (0..TREE_DEPTH).rev() { + // skip length of inner vector + assert_eq!(auth[0], 32); + auth = &auth[1..]; + + let mut sibling = [0u8; 32]; + sibling.copy_from_slice(&auth[0..32]); + auth = &auth[32..]; + + auth_path[i] = Some((sibling, false)); + } + + let mut position = { + let mut bytes = [0; 8]; + bytes.copy_from_slice(&auth[0..8]); + u64::from_le_bytes(bytes) + }; + + for entry in auth_path.iter_mut() { + if let Some(p) = entry { + p.1 = (position & 1) == 1; + } + + position >>= 1; + } + + inputs.push(JSInput { + value, + a_sk, + rho, + r, + auth_path, + }); + }; + + handle_input(in_sk1, in_value1, in_rho1, in_r1, &in_auth1[..]); + handle_input(in_sk2, in_value2, in_rho2, in_r2, &in_auth2[..]); + } + + let mut outputs = Vec::with_capacity(2); + { + let mut handle_output = |a_pk, value, r| { + outputs.push(JSOutput { + value: Some(value), + a_pk: Some(PayingKey(a_pk)), + r: Some(CommitmentRandomness(r)), + }); + }; + + handle_output(out_pk1, out_value1, out_r1); + handle_output(out_pk2, out_value2, out_r2); + } + + let js = JoinSplit { + vpub_old: Some(vpub_old), + vpub_new: Some(vpub_new), + h_sig: Some(h_sig), + phi: Some(phi), + inputs, + outputs, + rt: Some(rt), + }; + + // Initialize secure RNG + let mut rng = OsRng; + + create_random_proof(js, proving_key, &mut rng).expect("proving should not fail") +} + +/// Sprout JoinSplit proof verification. +pub fn verify_proof( + proof: &[u8; GROTH_PROOF_SIZE], + rt: &[u8; 32], + h_sig: &[u8; 32], + mac1: &[u8; 32], + mac2: &[u8; 32], + nf1: &[u8; 32], + nf2: &[u8; 32], + cm1: &[u8; 32], + cm2: &[u8; 32], + vpub_old: u64, + vpub_new: u64, + verifying_key: &PreparedVerifyingKey, +) -> bool { + // Prepare the public input for the verifier + let mut public_input = Vec::with_capacity((32 * 8) + (8 * 2)); + public_input.extend(rt); + public_input.extend(h_sig); + public_input.extend(nf1); + public_input.extend(mac1); + public_input.extend(nf2); + public_input.extend(mac2); + public_input.extend(cm1); + public_input.extend(cm2); + public_input.extend(&vpub_old.to_le_bytes()); + public_input.extend(&vpub_new.to_le_bytes()); + + let public_input = multipack::bytes_to_bits(&public_input); + let public_input = multipack::compute_multipacking::(&public_input); + + let proof = match Proof::read(&proof[..]) { + Ok(p) => p, + Err(_) => return false, + }; + + // Verify the proof + match groth16::verify_proof(verifying_key, &proof, &public_input[..]) { + // No error, and proof verification successful + Ok(true) => true, + + // Any other case + _ => false, + } +} From 7fda177da818532727e53e6ee238da97b68619f9 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 7 Nov 2019 17:33:22 +0000 Subject: [PATCH 288/330] Doc link fixes --- bellman/src/gadgets/uint32.rs | 2 ++ zcash_client_backend/src/encoding.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/bellman/src/gadgets/uint32.rs b/bellman/src/gadgets/uint32.rs index a10be6c..8bf4558 100644 --- a/bellman/src/gadgets/uint32.rs +++ b/bellman/src/gadgets/uint32.rs @@ -1,5 +1,7 @@ //! Circuit representation of a [`u32`], with helpers for the [`sha256`] //! gadgets. +//! +//! [`sha256`]: crate::gadgets::sha256 use ff::{Field, PrimeField, ScalarEngine}; diff --git a/zcash_client_backend/src/encoding.rs b/zcash_client_backend/src/encoding.rs index 01add4c..ba99912 100644 --- a/zcash_client_backend/src/encoding.rs +++ b/zcash_client_backend/src/encoding.rs @@ -2,6 +2,8 @@ //! //! Human-Readable Prefixes (HRPs) for Bech32 encodings are located in the [`constants`] //! module. +//! +//! [`constants`]: crate::constants use bech32::{self, Error, FromBase32, ToBase32}; use pairing::bls12_381::Bls12; From 7be66ad8f806329d0f1eaba2f05ab583948af80f Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 7 Nov 2019 17:40:41 +0000 Subject: [PATCH 289/330] Rename Actions workflow --- .github/workflows/{rust.yml => ci.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{rust.yml => ci.yml} (99%) diff --git a/.github/workflows/rust.yml b/.github/workflows/ci.yml similarity index 99% rename from .github/workflows/rust.yml rename to .github/workflows/ci.yml index 85231fa..b3e2ae8 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: Rust +name: CI checks on: [push, pull_request] From bb3903779826aef3ebdce51dd22b1e81a8df1a1b Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 7 Nov 2019 18:16:27 +0000 Subject: [PATCH 290/330] Move code coverage from Travis CI to Actions --- .github/workflows/ci.yml | 25 +++++++++++++++++++++++++ .travis.yml | 12 ------------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3e2ae8..a76eb46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,6 +63,31 @@ jobs: command: test args: --verbose --release --all -- --ignored + codecov: + name: Code coverage + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/toolchain@v1 + with: + toolchain: 1.37.0 + override: true + - name: Install cargo-tarpaulin + uses: actions-rs/cargo@v1 + with: + command: install + args: cargo-tarpaulin + - name: Generate coverage report + uses: actions-rs/cargo@v1 + with: + command: tarpaulin + args: --release --timeout 600 --out Xml --packages "librustzcash,zcash_client_backend,zcash_primitives,zcash_proofs" + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1.0.3 + with: + token: ${{secrets.CODECOV_TOKEN}} + doc-links: name: Nightly lint runs-on: ubuntu-latest diff --git a/.travis.yml b/.travis.yml index f0f9e46..059d454 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,12 +2,6 @@ language: rust rust: - 1.37.0 -addons: - apt: - packages: - # For cargo-tarpaulin - - libssl-dev - cache: cargo before_script: @@ -21,11 +15,5 @@ script: before_cache: - rm -rf "$TRAVIS_HOME/.cargo/registry/src" - - cargo install cargo-tarpaulin || echo "cargo-tarpaulin already installed" - cargo install cargo-update || echo "cargo-update already installed" - cargo install-update -a # update outdated cached binaries - -after_success: - # Manually exclude packages that are going to be removed from the workspace - - travis_wait 35 cargo tarpaulin --release --timeout 600 --out Xml --packages "librustzcash,zcash_client_backend,zcash_primitives,zcash_proofs" - - bash <(curl -s https://codecov.io/bash) From 4ae238ea1fe0bc4f4ea1a68523095b65b889864b Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 11 Nov 2019 10:21:38 +0000 Subject: [PATCH 291/330] librustzcash crate doc --- librustzcash/src/rustzcash.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 98c9ff7..068fb77 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -1,3 +1,7 @@ +//! FFI between the C++ zcashd codebase and the Rust Zcash crates. +//! +//! This is internal to zcashd and is not an officially-supported API. + // Catch documentation errors caused by code changes. #![deny(intra_doc_link_resolution_failure)] // Clippy has a default-deny lint to prevent dereferencing raw pointer arguments From 60eac4e8b72a39cebd336151a85bb63938332ee1 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 11 Nov 2019 10:29:36 +0000 Subject: [PATCH 292/330] Escape non-link square brackets in comments --- librustzcash/src/rustzcash.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 068fb77..9c199dd 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -509,7 +509,7 @@ pub extern "C" fn librustzcash_sapling_compute_cm( true } -/// Compute [sk] [8] P for some 32-byte point P, and 32-byte Fs. +/// Computes \[sk\] \[8\] P for some 32-byte point P, and 32-byte Fs. /// /// If P or sk are invalid, returns false. Otherwise, the result is written to /// the 32-byte `result` buffer. @@ -542,7 +542,7 @@ pub extern "C" fn librustzcash_sapling_ka_agree( } /// Compute g_d = GH(diversifier) and returns false if the diversifier is -/// invalid. Computes [esk] g_d and writes the result to the 32-byte `result` +/// invalid. Computes \[esk\] g_d and writes the result to the 32-byte `result` /// buffer. Returns false if `esk` is not a valid scalar. #[no_mangle] pub extern "C" fn librustzcash_sapling_ka_derivepublic( From d9d50b98ab52b3445a3ac0bcab1e1ccf388f8262 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 13 Nov 2019 19:12:55 +0000 Subject: [PATCH 293/330] Move transparent signing onto TransparentInputs --- zcash_primitives/src/transaction/builder.rs | 49 ++++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index ae47a32..b7e2ee2 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -178,6 +178,31 @@ impl TransparentInputs { Amount::zero() } } + + #[cfg(feature = "transparent-inputs")] + fn apply_signatures(&self, mtx: &mut TransactionData, consensus_branch_id: u32) { + for (i, info) in self.inputs.iter().enumerate() { + sighash.copy_from_slice(&signature_hash_data( + mtx, + consensus_branch_id, + SIGHASH_ALL, + Some((i, &info.coin.script_pubkey, info.coin.value)), + )); + + let msg = secp256k1::Message::from_slice(&sighash).expect("32 bytes"); + let sig = self.secp.sign(&msg, &info.sk); + + // Signature has to have "SIGHASH_ALL" appended to it + let mut sig_bytes: Vec = sig.serialize_der()[..].to_vec(); + sig_bytes.extend(&[SIGHASH_ALL as u8]); + + // P2PKH scriptSig + mtx.vin[i].script_sig = Script::default() << &sig_bytes[..] << &info.pubkey[..]; + } + } + + #[cfg(not(feature = "transparent-inputs"))] + fn apply_signatures(&self, _: &mut TransactionData, _: u32) {} } /// Metadata about a transaction created by a [`Builder`]. @@ -612,28 +637,8 @@ impl Builder { ); // Transparent signatures - #[cfg(feature = "transparent-inputs")] - { - for (i, info) in self.legacy.inputs.iter().enumerate() { - sighash.copy_from_slice(&signature_hash_data( - &self.mtx, - consensus_branch_id, - SIGHASH_ALL, - Some((i, &info.coin.script_pubkey, info.coin.value)), - )); - - let msg = secp256k1::Message::from_slice(&sighash).expect("32 bytes"); - let sig = self.legacy.secp.sign(&msg, &info.sk); - - // Signature has to have "SIGHASH_ALL" appended to it - let mut sig_bytes: Vec = sig.serialize_der()[..].to_vec(); - sig_bytes.extend(&[SIGHASH_ALL as u8]); - - // P2PKH scriptSig - self.mtx.vin[i].script_sig = - Script::default() << &sig_bytes[..] << &info.pubkey[..]; - } - } + self.legacy + .apply_signatures(&mut self.mtx, consensus_branch_id); Ok(( self.mtx.freeze().expect("Transaction should be complete"), From 8d967c86096cae27d6a5dab412b0c5343567e9f1 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 13 Nov 2019 19:20:09 +0000 Subject: [PATCH 294/330] Move transparent input pushing onto TransparentInputs --- zcash_primitives/src/transaction/builder.rs | 55 ++++++++++++--------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index b7e2ee2..d350514 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -164,6 +164,37 @@ impl Default for TransparentInputs { struct TransparentInputs; impl TransparentInputs { + #[cfg(feature = "transparent-inputs")] + fn push( + &mut self, + mtx: &mut TransactionData, + sk: secp256k1::SecretKey, + utxo: OutPoint, + coin: TxOut, + ) -> Result<(), Error> { + if coin.value.is_negative() { + return Err(Error::InvalidAmount); + } + + let pubkey = secp256k1::PublicKey::from_secret_key(&self.secp, &sk).serialize(); + match coin.script_pubkey.address() { + Some(TransparentAddress::PublicKey(hash)) => { + use ripemd160::Ripemd160; + use sha2::{Digest, Sha256}; + + if &hash[..] != &Ripemd160::digest(&Sha256::digest(&pubkey))[..] { + return Err(Error::InvalidAddress); + } + } + _ => return Err(Error::InvalidAddress), + } + + mtx.vin.push(TxIn::new(utxo)); + self.inputs.push(TransparentInputInfo { sk, pubkey, coin }); + + Ok(()) + } + fn input_sum(&self) -> Amount { #[cfg(feature = "transparent-inputs")] { @@ -358,29 +389,7 @@ impl Builder { utxo: OutPoint, coin: TxOut, ) -> Result<(), Error> { - if coin.value.is_negative() { - return Err(Error::InvalidAmount); - } - - let pubkey = secp256k1::PublicKey::from_secret_key(&self.legacy.secp, &sk).serialize(); - match coin.script_pubkey.address() { - Some(TransparentAddress::PublicKey(hash)) => { - use ripemd160::Ripemd160; - use sha2::{Digest, Sha256}; - - if &hash[..] != &Ripemd160::digest(&Sha256::digest(&pubkey))[..] { - return Err(Error::InvalidAddress); - } - } - _ => return Err(Error::InvalidAddress), - } - - self.mtx.vin.push(TxIn::new(utxo)); - self.legacy - .inputs - .push(TransparentInputInfo { sk, pubkey, coin }); - - Ok(()) + self.legacy.push(&mut self.mtx, sk, utxo, coin) } /// Adds a transparent address to send funds to. From 8d6f882510613a1cd5daa05837a19d749316de49 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 13 Nov 2019 19:21:47 +0000 Subject: [PATCH 295/330] Renames after moves --- zcash_primitives/src/transaction/builder.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index d350514..00bdc24 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -195,7 +195,7 @@ impl TransparentInputs { Ok(()) } - fn input_sum(&self) -> Amount { + fn value_sum(&self) -> Amount { #[cfg(feature = "transparent-inputs")] { self.inputs @@ -282,7 +282,7 @@ pub struct Builder { anchor: Option, spends: Vec, outputs: Vec, - legacy: TransparentInputs, + transparent_inputs: TransparentInputs, change_address: Option<(OutgoingViewingKey, PaymentAddress)>, } @@ -322,7 +322,7 @@ impl Builder { anchor: None, spends: vec![], outputs: vec![], - legacy: TransparentInputs::default(), + transparent_inputs: TransparentInputs::default(), change_address: None, } } @@ -389,7 +389,7 @@ impl Builder { utxo: OutPoint, coin: TxOut, ) -> Result<(), Error> { - self.legacy.push(&mut self.mtx, sk, utxo, coin) + self.transparent_inputs.push(&mut self.mtx, sk, utxo, coin) } /// Adds a transparent address to send funds to. @@ -439,7 +439,7 @@ impl Builder { // // Valid change - let change = self.mtx.value_balance - self.fee + self.legacy.input_sum() + let change = self.mtx.value_balance - self.fee + self.transparent_inputs.value_sum() - self .mtx .vout @@ -646,7 +646,7 @@ impl Builder { ); // Transparent signatures - self.legacy + self.transparent_inputs .apply_signatures(&mut self.mtx, consensus_branch_id); Ok(( From 219391ac921dade1a8b205f08e98fdff77e87cb5 Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Thu, 14 Nov 2019 09:54:07 -0800 Subject: [PATCH 296/330] Add missing sighash declaration --- zcash_primitives/src/transaction/builder.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 00bdc24..03a8c20 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -212,6 +212,7 @@ impl TransparentInputs { #[cfg(feature = "transparent-inputs")] fn apply_signatures(&self, mtx: &mut TransactionData, consensus_branch_id: u32) { + let mut sighash = [0u8; 32]; for (i, info) in self.inputs.iter().enumerate() { sighash.copy_from_slice(&signature_hash_data( mtx, From 7eb4a6d1d9899466ccb29cefd4f005ad10109815 Mon Sep 17 00:00:00 2001 From: Gregory Hill Date: Mon, 25 Nov 2019 14:28:19 +0000 Subject: [PATCH 297/330] rename bvk to cv_sum Signed-off-by: Gregory Hill --- zcash_proofs/src/sapling/prover.rs | 19 ++++++++++--------- zcash_proofs/src/sapling/verifier.rs | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index 70b529a..8067069 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -22,7 +22,8 @@ use crate::circuit::sapling::{Output, Spend}; /// A context object for creating the Sapling components of a Zcash transaction. pub struct SaplingProvingContext { bsk: Fs, - bvk: edwards::Point, + // (sum of the Spend value commitments) - (sum of the Output value commitments) + cv_sum: edwards::Point, } impl SaplingProvingContext { @@ -30,7 +31,7 @@ impl SaplingProvingContext { pub fn new() -> Self { SaplingProvingContext { bsk: Fs::zero(), - bvk: edwards::Point::zero(), + cv_sum: edwards::Point::zero(), } } @@ -169,10 +170,10 @@ impl SaplingProvingContext { // Accumulate the value commitment in the context { let mut tmp = value_commitment.clone(); - tmp = tmp.add(&self.bvk, params); + tmp = tmp.add(&self.cv_sum, params); // Update the context - self.bvk = tmp; + self.cv_sum = tmp; } Ok((proof, value_commitment, rk)) @@ -234,10 +235,10 @@ impl SaplingProvingContext { { let mut tmp = value_commitment.clone(); tmp = tmp.negate(); // Outputs subtract from the total. - tmp = tmp.add(&self.bvk, params); + tmp = tmp.add(&self.cv_sum, params); // Update the context - self.bvk = tmp; + self.cv_sum = tmp; } (proof, value_commitment) @@ -261,7 +262,7 @@ impl SaplingProvingContext { let bvk = PublicKey::from_private(&bsk, FixedGenerators::ValueCommitmentRandomness, params); // In order to check internal consistency, let's use the accumulated value - // commitments (as the verifier would) and apply valuebalance to compare + // commitments (as the verifier would) and apply value_balance to compare // against our derived bvk. { // Compute value balance @@ -270,9 +271,9 @@ impl SaplingProvingContext { None => return Err(()), }; - // Subtract value_balance from current bvk to get final bvk + // Subtract value_balance from cv_sum to get final bvk value_balance = value_balance.negate(); - let mut tmp = self.bvk.clone(); + let mut tmp = self.cv_sum.clone(); tmp = tmp.add(&value_balance, params); // The result should be the same, unless the provided valueBalance is wrong. diff --git a/zcash_proofs/src/sapling/verifier.rs b/zcash_proofs/src/sapling/verifier.rs index 5199bd8..b886912 100644 --- a/zcash_proofs/src/sapling/verifier.rs +++ b/zcash_proofs/src/sapling/verifier.rs @@ -18,14 +18,15 @@ fn is_small_order(p: &edwards::Point, params: &JubjubBls12) /// A context object for verifying the Sapling components of a Zcash transaction. pub struct SaplingVerificationContext { - bvk: edwards::Point, + // (sum of the Spend value commitments) - (sum of the Output value commitments) + cv_sum: edwards::Point, } impl SaplingVerificationContext { /// Construct a new context to be used with a single transaction. pub fn new() -> Self { SaplingVerificationContext { - bvk: edwards::Point::zero(), + cv_sum: edwards::Point::zero(), } } @@ -54,10 +55,10 @@ impl SaplingVerificationContext { // Accumulate the value commitment in the context { let mut tmp = cv.clone(); - tmp = tmp.add(&self.bvk, params); + tmp = tmp.add(&self.cv_sum, params); // Update the context - self.bvk = tmp; + self.cv_sum = tmp; } // Grab the nullifier as a sequence of bytes @@ -137,10 +138,10 @@ impl SaplingVerificationContext { { let mut tmp = cv.clone(); tmp = tmp.negate(); // Outputs subtract from the total. - tmp = tmp.add(&self.bvk, params); + tmp = tmp.add(&self.cv_sum, params); // Update the context - self.bvk = tmp; + self.cv_sum = tmp; } // Construct public input for circuit @@ -177,8 +178,8 @@ impl SaplingVerificationContext { binding_sig: Signature, params: &JubjubBls12, ) -> bool { - // Obtain current bvk from the context - let mut bvk = PublicKey(self.bvk.clone()); + // Obtain current cv_sum from the context + let mut bvk = PublicKey(self.cv_sum.clone()); // Compute value balance let mut value_balance = match compute_value_balance(value_balance, params) { @@ -186,7 +187,7 @@ impl SaplingVerificationContext { None => return false, }; - // Subtract value_balance from current bvk to get final bvk + // Subtract value_balance from current cv_sum to get final bvk value_balance = value_balance.negate(); bvk.0 = bvk.0.add(&value_balance, params); From c24024b8e18242820fe7c74bc6099fa647fc3c11 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 25 Nov 2019 15:41:14 +0000 Subject: [PATCH 298/330] Create a consensus::BranchId enum for type safety Includes all currently-known consensus branch IDs for the Zcash network. --- zcash_primitives/src/consensus.rs | 48 +++++++++++++++++++++ zcash_primitives/src/lib.rs | 1 + zcash_primitives/src/transaction/builder.rs | 25 +++++++---- zcash_primitives/src/transaction/sighash.rs | 8 ++-- zcash_primitives/src/transaction/tests.rs | 45 +++++++++---------- 5 files changed, 93 insertions(+), 34 deletions(-) create mode 100644 zcash_primitives/src/consensus.rs diff --git a/zcash_primitives/src/consensus.rs b/zcash_primitives/src/consensus.rs new file mode 100644 index 0000000..aa2c67f --- /dev/null +++ b/zcash_primitives/src/consensus.rs @@ -0,0 +1,48 @@ +//! Consensus parameters. + +/// A globally-unique identifier for a set of consensus rules within the Zcash chain. +/// +/// Each branch ID in this enum corresponds to one of the epochs between a pair of Zcash +/// network upgrades. For example, `BranchId::Overwinter` corresponds to the blocks +/// starting at Overwinter activation, and ending the block before Sapling activation. +/// +/// The main use of the branch ID is in signature generation: transactions commit to a +/// specific branch ID by including it as part of [`signature_hash`]. This ensures +/// two-way replay protection for transactions across network upgrades. +/// +/// See [ZIP 200](https://zips.z.cash/zip-0200) for more details. +/// +/// [`signature_hash`]: crate::transaction::signature_hash +#[derive(Clone, Copy, Debug)] +pub enum BranchId { + /// The consensus rules at the launch of Zcash. + Sprout, + /// The consensus rules deployed in the [Overwinter] network upgrade. + /// + /// [Overwinter]: https://z.cash/upgrade/overwinter/ + Overwinter, + /// The consensus rules deployed in the [Sapling] network upgrade. + /// + /// [Sapling]: https://z.cash/upgrade/sapling/ + Sapling, + /// The consensus rules deployed in the [Blossom] network upgrade. + /// + /// [Blossom]: https://z.cash/upgrade/blossom/ + Blossom, + /// The consensus rules deployed in the [Heartwood] network upgrade. + /// + /// [Heartwood]: https://z.cash/upgrade/heartwood/ + Heartwood, +} + +impl From for u32 { + fn from(consensus_branch_id: BranchId) -> u32 { + match consensus_branch_id { + BranchId::Sprout => 0, + BranchId::Overwinter => 0x5ba8_1b19, + BranchId::Sapling => 0x76b8_09bb, + BranchId::Blossom => 0x2bb4_0e60, + BranchId::Heartwood => 0xf5b9_230b, + } + } +} diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index 020385e..8175a26 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -9,6 +9,7 @@ use lazy_static::lazy_static; pub mod block; +pub mod consensus; pub mod constants; pub mod group_hash; pub mod jubjub; diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 03a8c20..ce0bfe9 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -10,6 +10,7 @@ use pairing::bls12_381::{Bls12, Fr}; use rand::{rngs::OsRng, seq::SliceRandom, CryptoRng, RngCore}; use crate::{ + consensus, keys::OutgoingViewingKey, legacy::TransparentAddress, merkle_tree::{CommitmentTreeWitness, IncrementalWitness}, @@ -211,7 +212,11 @@ impl TransparentInputs { } #[cfg(feature = "transparent-inputs")] - fn apply_signatures(&self, mtx: &mut TransactionData, consensus_branch_id: u32) { + fn apply_signatures( + &self, + mtx: &mut TransactionData, + consensus_branch_id: consensus::BranchId, + ) { let mut sighash = [0u8; 32]; for (i, info) in self.inputs.iter().enumerate() { sighash.copy_from_slice(&signature_hash_data( @@ -234,7 +239,7 @@ impl TransparentInputs { } #[cfg(not(feature = "transparent-inputs"))] - fn apply_signatures(&self, _: &mut TransactionData, _: u32) {} + fn apply_signatures(&self, _: &mut TransactionData, _: consensus::BranchId) {} } /// Metadata about a transaction created by a [`Builder`]. @@ -430,7 +435,7 @@ impl Builder { /// the network. pub fn build( mut self, - consensus_branch_id: u32, + consensus_branch_id: consensus::BranchId, prover: impl TxProver, ) -> Result<(Transaction, TransactionMetadata), Error> { let mut tx_metadata = TransactionMetadata::new(); @@ -666,6 +671,7 @@ mod tests { use super::{Builder, Error}; use crate::{ + consensus, legacy::TransparentAddress, merkle_tree::{CommitmentTree, IncrementalWitness}, prover::mock::MockTxProver, @@ -713,7 +719,7 @@ mod tests { { let builder = Builder::new(0); assert_eq!( - builder.build(1, MockTxProver), + builder.build(consensus::BranchId::Sapling, MockTxProver), Err(Error::ChangeIsNegative(Amount::from_i64(-10000).unwrap())) ); } @@ -735,7 +741,7 @@ mod tests { ) .unwrap(); assert_eq!( - builder.build(1, MockTxProver), + builder.build(consensus::BranchId::Sapling, MockTxProver), Err(Error::ChangeIsNegative(Amount::from_i64(-60000).unwrap())) ); } @@ -751,7 +757,7 @@ mod tests { ) .unwrap(); assert_eq!( - builder.build(1, MockTxProver), + builder.build(consensus::BranchId::Sapling, MockTxProver), Err(Error::ChangeIsNegative(Amount::from_i64(-60000).unwrap())) ); } @@ -791,7 +797,7 @@ mod tests { ) .unwrap(); assert_eq!( - builder.build(1, MockTxProver), + builder.build(consensus::BranchId::Sapling, MockTxProver), Err(Error::ChangeIsNegative(Amount::from_i64(-1).unwrap())) ); } @@ -824,7 +830,10 @@ mod tests { Amount::from_u64(20000).unwrap(), ) .unwrap(); - assert_eq!(builder.build(1, MockTxProver), Err(Error::BindingSig)) + assert_eq!( + builder.build(consensus::BranchId::Sapling, MockTxProver), + Err(Error::BindingSig) + ) } } } diff --git a/zcash_primitives/src/transaction/sighash.rs b/zcash_primitives/src/transaction/sighash.rs index f6dcd30..4319f41 100644 --- a/zcash_primitives/src/transaction/sighash.rs +++ b/zcash_primitives/src/transaction/sighash.rs @@ -7,7 +7,7 @@ use super::{ Transaction, TransactionData, OVERWINTER_VERSION_GROUP_ID, SAPLING_TX_VERSION, SAPLING_VERSION_GROUP_ID, }; -use crate::legacy::Script; +use crate::{consensus, legacy::Script}; const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &[u8; 12] = b"ZcashSigHash"; const ZCASH_PREVOUTS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashPrevoutHash"; @@ -152,7 +152,7 @@ fn shielded_outputs_hash(tx: &TransactionData) -> Blake2bHash { pub fn signature_hash_data( tx: &TransactionData, - consensus_branch_id: u32, + consensus_branch_id: consensus::BranchId, hash_type: u32, transparent_input: Option<(usize, &Script, Amount)>, ) -> Vec { @@ -162,7 +162,7 @@ pub fn signature_hash_data( let mut personal = [0; 16]; (&mut personal[..12]).copy_from_slice(ZCASH_SIGHASH_PERSONALIZATION_PREFIX); (&mut personal[12..]) - .write_u32::(consensus_branch_id) + .write_u32::(consensus_branch_id.into()) .unwrap(); let mut h = Blake2bParams::new() @@ -230,7 +230,7 @@ pub fn signature_hash_data( pub fn signature_hash( tx: &Transaction, - consensus_branch_id: u32, + consensus_branch_id: consensus::BranchId, hash_type: u32, transparent_input: Option<(usize, &Script, Amount)>, ) -> Vec { diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index 19b110a..2dbf07e 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -5,6 +5,7 @@ use rand_core::OsRng; use crate::jubjub::{fs::Fs, FixedGenerators}; use super::{components::Amount, sighash::signature_hash, Transaction, TransactionData}; +use crate::consensus; use crate::legacy::Script; use crate::redjubjub::PrivateKey; use crate::JUBJUB; @@ -216,7 +217,7 @@ fn zip_0143() { transparent_input: Option, hash_type: u32, amount: i64, - consensus_branch_id: u32, + consensus_branch_id: consensus::BranchId, sighash: [u8; 32], }; @@ -233,7 +234,7 @@ fn zip_0143() { transparent_input: None, hash_type: 1, amount: 1672704339313879, - consensus_branch_id: 1537743641, + consensus_branch_id: consensus::BranchId::Overwinter, sighash: [ 0xa1, 0xf1, 0xa4, 0xe5, 0xcd, 0x9b, 0xd5, 0x22, 0x32, 0x2d, 0x66, 0x1e, 0xdd, 0x2a, 0xf1, 0xbf, 0x2a, 0x70, 0x19, 0xcf, 0xab, 0x94, 0xec, 0xe1, 0x8f, 0x4b, 0xa9, 0x35, @@ -522,7 +523,7 @@ fn zip_0143() { transparent_input: Some(1), hash_type: 3, amount: 365293780364847, - consensus_branch_id: 1537743641, + consensus_branch_id: consensus::BranchId::Overwinter, sighash: [ 0x23, 0x65, 0x2e, 0x76, 0xcb, 0x13, 0xb8, 0x5a, 0x0e, 0x33, 0x63, 0xbb, 0x5f, 0xca, 0x06, 0x1f, 0xa7, 0x91, 0xc4, 0x0c, 0x53, 0x3e, 0xcc, 0xee, 0x89, 0x93, 0x64, 0xe6, @@ -682,7 +683,7 @@ fn zip_0143() { transparent_input: Some(0), hash_type: 3, amount: 711752082734717, - consensus_branch_id: 1537743641, + consensus_branch_id: consensus::BranchId::Overwinter, sighash: [ 0xb3, 0x8e, 0x31, 0x70, 0x8c, 0xb7, 0x8e, 0xee, 0xc7, 0x66, 0x3e, 0xca, 0x1e, 0x01, 0xb7, 0x53, 0x9e, 0x26, 0xb7, 0x30, 0xcf, 0x44, 0x6d, 0x3b, 0xf5, 0x7a, 0x99, 0x8e, @@ -964,7 +965,7 @@ fn zip_0143() { transparent_input: None, hash_type: 1, amount: 379068098637835, - consensus_branch_id: 1537743641, + consensus_branch_id: consensus::BranchId::Overwinter, sighash: [ 0x92, 0xe7, 0xb4, 0x8f, 0x32, 0x81, 0x87, 0x71, 0x26, 0x87, 0xaf, 0x4d, 0xc1, 0x7a, 0x73, 0xfe, 0x0a, 0x70, 0xac, 0x07, 0x8d, 0x24, 0xcd, 0xcd, 0xd4, 0x58, 0xa3, 0xd6, @@ -1123,7 +1124,7 @@ fn zip_0143() { transparent_input: Some(0), hash_type: 3, amount: 1437866676382615, - consensus_branch_id: 1537743641, + consensus_branch_id: consensus::BranchId::Overwinter, sighash: [ 0xd8, 0xe9, 0xb9, 0x72, 0xb2, 0x89, 0x8e, 0xfc, 0xca, 0x8e, 0x96, 0xbc, 0x98, 0x70, 0x00, 0x8c, 0xdb, 0xc1, 0x9d, 0x45, 0xb7, 0x8d, 0x09, 0xef, 0xb1, 0x02, 0xf2, 0xd7, @@ -1143,7 +1144,7 @@ fn zip_0143() { transparent_input: None, hash_type: 1, amount: 1993227025071196, - consensus_branch_id: 1537743641, + consensus_branch_id: consensus::BranchId::Overwinter, sighash: [ 0x2b, 0x62, 0xff, 0x0c, 0x8d, 0xec, 0x4d, 0xf1, 0x8b, 0x99, 0x56, 0x61, 0x5b, 0x57, 0x4d, 0xda, 0x39, 0x42, 0xfe, 0x45, 0x2d, 0x91, 0x78, 0xb0, 0xbb, 0xb2, 0xea, 0xee, @@ -1166,7 +1167,7 @@ fn zip_0143() { transparent_input: Some(1), hash_type: 130, amount: 449567650863240, - consensus_branch_id: 1537743641, + consensus_branch_id: consensus::BranchId::Overwinter, sighash: [ 0x49, 0x3d, 0x49, 0xc3, 0xe2, 0x22, 0x5d, 0x11, 0xc4, 0x64, 0x05, 0x18, 0x20, 0x14, 0x76, 0x25, 0xf3, 0x90, 0x9f, 0xa7, 0x18, 0x9f, 0x61, 0xc7, 0xea, 0xec, 0xfc, 0x6d, @@ -1448,7 +1449,7 @@ fn zip_0143() { transparent_input: None, hash_type: 1, amount: 1712463999734827, - consensus_branch_id: 1537743641, + consensus_branch_id: consensus::BranchId::Overwinter, sighash: [ 0xbb, 0x10, 0x30, 0x0e, 0x4d, 0xaf, 0xe3, 0x0c, 0x3f, 0xf0, 0x26, 0x34, 0xd0, 0xe0, 0x03, 0x2f, 0x17, 0x15, 0xb0, 0x0c, 0xbc, 0x77, 0x3d, 0xf6, 0xb0, 0x9e, 0x00, 0x43, @@ -1606,7 +1607,7 @@ fn zip_0143() { transparent_input: Some(1), hash_type: 1, amount: 1564816348934332, - consensus_branch_id: 1537743641, + consensus_branch_id: consensus::BranchId::Overwinter, sighash: [ 0x21, 0x46, 0x62, 0xc6, 0x74, 0x50, 0x60, 0x3d, 0x8a, 0xa7, 0x3b, 0xea, 0xbb, 0xf7, 0x51, 0x8d, 0x03, 0x6c, 0xe9, 0x1d, 0xc8, 0x7b, 0x01, 0x81, 0xe8, 0xa0, 0xf3, 0xfa, @@ -1889,7 +1890,7 @@ fn zip_0143() { transparent_input: Some(0), hash_type: 2, amount: 483959951916902, - consensus_branch_id: 1537743641, + consensus_branch_id: consensus::BranchId::Overwinter, sighash: [ 0x29, 0x6f, 0xd7, 0x63, 0xf2, 0x54, 0x5e, 0x64, 0xfb, 0x5d, 0x7d, 0x49, 0xc0, 0x00, 0xd2, 0xb4, 0x18, 0xb9, 0x3b, 0xde, 0x22, 0x34, 0xf8, 0x74, 0x29, 0x11, 0xe8, 0xaf, @@ -1925,7 +1926,7 @@ fn zip_0243() { transparent_input: Option, hash_type: u32, amount: i64, - consensus_branch_id: u32, + consensus_branch_id: consensus::BranchId, sighash: [u8; 32], }; @@ -2233,7 +2234,7 @@ fn zip_0243() { transparent_input: None, hash_type: 1, amount: 1969273897303781, - consensus_branch_id: 1991772603, + consensus_branch_id: consensus::BranchId::Sapling, sighash: [ 0x63, 0xd1, 0x85, 0x34, 0xde, 0x5f, 0x2d, 0x1c, 0x9e, 0x16, 0x9b, 0x73, 0xf9, 0xc7, 0x83, 0x71, 0x8a, 0xdb, 0xef, 0x5c, 0x8a, 0x7d, 0x55, 0xb5, 0xe7, 0xa3, 0x7a, 0xff, @@ -2466,7 +2467,7 @@ fn zip_0243() { transparent_input: Some(1), hash_type: 2, amount: 652655344020909, - consensus_branch_id: 1991772603, + consensus_branch_id: consensus::BranchId::Sapling, sighash: [ 0xbb, 0xe6, 0xd8, 0x4f, 0x57, 0xc5, 0x6b, 0x29, 0xb9, 0x14, 0xc6, 0x94, 0xba, 0xac, 0xcb, 0x89, 0x12, 0x97, 0xe9, 0x61, 0xde, 0x3e, 0xb4, 0x6c, 0x68, 0xe3, 0xc8, 0x9c, @@ -3052,7 +3053,7 @@ fn zip_0243() { transparent_input: None, hash_type: 1, amount: 1345602751504862, - consensus_branch_id: 1991772603, + consensus_branch_id: consensus::BranchId::Sapling, sighash: [ 0x15, 0x53, 0xd4, 0xf1, 0x07, 0x45, 0x10, 0x71, 0x81, 0x99, 0x00, 0x5f, 0xef, 0xaa, 0xa8, 0x3e, 0x29, 0xd1, 0x63, 0xee, 0xbd, 0xf3, 0xc0, 0x33, 0x82, 0x79, 0x08, 0xac, @@ -3373,7 +3374,7 @@ fn zip_0243() { transparent_input: None, hash_type: 1, amount: 1039204199089370, - consensus_branch_id: 1991772603, + consensus_branch_id: consensus::BranchId::Sapling, sighash: [ 0x6c, 0x4e, 0x32, 0x44, 0xc2, 0xd2, 0xbf, 0xb8, 0xd6, 0xf6, 0x69, 0x97, 0x77, 0xa1, 0x1a, 0x64, 0xad, 0xfe, 0xe4, 0x9b, 0x2f, 0xc7, 0x81, 0xe6, 0x95, 0x15, 0x34, 0xf9, @@ -3523,7 +3524,7 @@ fn zip_0243() { transparent_input: None, hash_type: 1, amount: 691732482992802, - consensus_branch_id: 1991772603, + consensus_branch_id: consensus::BranchId::Sapling, sighash: [ 0x5d, 0x40, 0x5a, 0x1c, 0x4d, 0xed, 0x19, 0x87, 0x98, 0x8a, 0x10, 0x03, 0x64, 0xa3, 0xcd, 0x6f, 0xe0, 0xba, 0x22, 0x20, 0xa6, 0xab, 0xce, 0x08, 0xc5, 0x17, 0x13, 0x59, @@ -3923,7 +3924,7 @@ fn zip_0243() { transparent_input: None, hash_type: 1, amount: 1152393991505765, - consensus_branch_id: 1991772603, + consensus_branch_id: consensus::BranchId::Sapling, sighash: [ 0x58, 0x11, 0x0e, 0x23, 0x19, 0xad, 0x85, 0x50, 0x4a, 0x69, 0x8f, 0x73, 0xe7, 0xac, 0x31, 0xa7, 0x23, 0xa0, 0x29, 0xec, 0x07, 0xb7, 0x72, 0xfb, 0xb3, 0x2f, 0xba, 0x17, @@ -4087,7 +4088,7 @@ fn zip_0243() { transparent_input: None, hash_type: 1, amount: 1788797765223798, - consensus_branch_id: 1991772603, + consensus_branch_id: consensus::BranchId::Sapling, sighash: [ 0xcb, 0xfa, 0x22, 0x69, 0x9b, 0x04, 0xbe, 0xb7, 0x67, 0x07, 0xb5, 0x1d, 0x62, 0x5e, 0x94, 0xd2, 0x6c, 0x0d, 0xf8, 0xad, 0xa7, 0xcf, 0x68, 0xfc, 0xde, 0xd9, 0x60, 0x65, @@ -4685,7 +4686,7 @@ fn zip_0243() { transparent_input: None, hash_type: 1, amount: 1871432121379810, - consensus_branch_id: 1991772603, + consensus_branch_id: consensus::BranchId::Sapling, sighash: [ 0x36, 0x77, 0xa9, 0x48, 0x4f, 0x04, 0x04, 0xfb, 0x50, 0x64, 0x58, 0x56, 0xf4, 0xd4, 0xa7, 0x0b, 0x2e, 0x2b, 0x1c, 0x2d, 0x86, 0x2f, 0x1d, 0x4e, 0xf6, 0x8d, 0x52, 0x09, @@ -5194,7 +5195,7 @@ fn zip_0243() { transparent_input: None, hash_type: 1, amount: 1501997449504444, - consensus_branch_id: 1991772603, + consensus_branch_id: consensus::BranchId::Sapling, sighash: [ 0xa1, 0xcf, 0x50, 0xcf, 0xfe, 0x59, 0xbe, 0x5f, 0x31, 0x5f, 0xfe, 0x51, 0x6e, 0x28, 0x9e, 0xe8, 0x02, 0x5e, 0x59, 0x38, 0xf1, 0xe8, 0xe1, 0x88, 0x53, 0x7f, 0xf1, 0xa8, @@ -5384,7 +5385,7 @@ fn zip_0243() { transparent_input: Some(0), hash_type: 3, amount: 391892287957268, - consensus_branch_id: 1991772603, + consensus_branch_id: consensus::BranchId::Sapling, sighash: [ 0x6a, 0x3b, 0x2b, 0xcc, 0x15, 0x57, 0x89, 0xa2, 0x74, 0x39, 0xaa, 0x27, 0x5c, 0xa9, 0x9e, 0xc6, 0x48, 0xdd, 0xd5, 0x88, 0xe8, 0x2e, 0xfa, 0xe4, 0xac, 0x46, 0xba, 0x3f, From cd326f2b6a1c5b37e246b594f7073b756cf26302 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 26 Nov 2019 23:44:57 +0000 Subject: [PATCH 299/330] Consensus parameters for network upgrades --- zcash_primitives/src/consensus.rs | 191 ++++++++++++++++++++++++++++-- 1 file changed, 178 insertions(+), 13 deletions(-) diff --git a/zcash_primitives/src/consensus.rs b/zcash_primitives/src/consensus.rs index aa2c67f..f7cf480 100644 --- a/zcash_primitives/src/consensus.rs +++ b/zcash_primitives/src/consensus.rs @@ -1,5 +1,106 @@ //! Consensus parameters. +use std::fmt; + +/// Zcash consensus parameters. +pub trait Parameters { + fn activation_height(nu: NetworkUpgrade) -> Option; + + fn is_nu_active(nu: NetworkUpgrade, height: u32) -> bool { + match Self::activation_height(nu) { + Some(h) if h <= height => true, + _ => false, + } + } +} + +/// Marker struct for the production network. +#[derive(Clone, Copy, Debug)] +pub struct MainNetwork; + +impl Parameters for MainNetwork { + fn activation_height(nu: NetworkUpgrade) -> Option { + match nu { + NetworkUpgrade::Overwinter => Some(347_500), + NetworkUpgrade::Sapling => Some(419_200), + NetworkUpgrade::Blossom => Some(653_600), + NetworkUpgrade::Heartwood => None, + } + } +} + +/// Marker struct for the test network. +#[derive(Clone, Copy, Debug)] +pub struct TestNetwork; + +impl Parameters for TestNetwork { + fn activation_height(nu: NetworkUpgrade) -> Option { + match nu { + NetworkUpgrade::Overwinter => Some(207_500), + NetworkUpgrade::Sapling => Some(280_000), + NetworkUpgrade::Blossom => Some(584_000), + NetworkUpgrade::Heartwood => None, + } + } +} + +/// An event that occurs at a specified height on the Zcash chain, at which point the +/// consensus rules enforced by the network are altered. +/// +/// See [ZIP 200](https://zips.z.cash/zip-0200) for more details. +#[derive(Clone, Copy, Debug)] +pub enum NetworkUpgrade { + /// The [Overwinter] network upgrade. + /// + /// [Overwinter]: https://z.cash/upgrade/overwinter/ + Overwinter, + /// The [Sapling] network upgrade. + /// + /// [Sapling]: https://z.cash/upgrade/sapling/ + Sapling, + /// The [Blossom] network upgrade. + /// + /// [Blossom]: https://z.cash/upgrade/blossom/ + Blossom, + /// The [Heartwood] network upgrade. + /// + /// [Heartwood]: https://z.cash/upgrade/heartwood/ + Heartwood, +} + +impl fmt::Display for NetworkUpgrade { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + NetworkUpgrade::Overwinter => write!(f, "Overwinter"), + NetworkUpgrade::Sapling => write!(f, "Sapling"), + NetworkUpgrade::Blossom => write!(f, "Blossom"), + NetworkUpgrade::Heartwood => write!(f, "Heartwood"), + } + } +} + +impl NetworkUpgrade { + fn branch_id(self) -> BranchId { + match self { + NetworkUpgrade::Overwinter => BranchId::Overwinter, + NetworkUpgrade::Sapling => BranchId::Sapling, + NetworkUpgrade::Blossom => BranchId::Blossom, + NetworkUpgrade::Heartwood => BranchId::Heartwood, + } + } +} + +/// The network upgrades on the Zcash chain in order of activation. +/// +/// This order corresponds to the activation heights, but because Rust enums are +/// full-fledged algebraic data types, we need to define it manually. +const UPGRADES_IN_ORDER: &[NetworkUpgrade] = &[ + NetworkUpgrade::Overwinter, + NetworkUpgrade::Sapling, + NetworkUpgrade::Blossom, + NetworkUpgrade::Heartwood, +]; + /// A globally-unique identifier for a set of consensus rules within the Zcash chain. /// /// Each branch ID in this enum corresponds to one of the epochs between a pair of Zcash @@ -13,25 +114,17 @@ /// See [ZIP 200](https://zips.z.cash/zip-0200) for more details. /// /// [`signature_hash`]: crate::transaction::signature_hash -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum BranchId { /// The consensus rules at the launch of Zcash. Sprout, - /// The consensus rules deployed in the [Overwinter] network upgrade. - /// - /// [Overwinter]: https://z.cash/upgrade/overwinter/ + /// The consensus rules deployed by [`NetworkUpgrade::Overwinter`]. Overwinter, - /// The consensus rules deployed in the [Sapling] network upgrade. - /// - /// [Sapling]: https://z.cash/upgrade/sapling/ + /// The consensus rules deployed by [`NetworkUpgrade::Sapling`]. Sapling, - /// The consensus rules deployed in the [Blossom] network upgrade. - /// - /// [Blossom]: https://z.cash/upgrade/blossom/ + /// The consensus rules deployed by [`NetworkUpgrade::Blossom`]. Blossom, - /// The consensus rules deployed in the [Heartwood] network upgrade. - /// - /// [Heartwood]: https://z.cash/upgrade/heartwood/ + /// The consensus rules deployed by [`NetworkUpgrade::Heartwood`]. Heartwood, } @@ -46,3 +139,75 @@ impl From for u32 { } } } + +impl BranchId { + /// Returns the branch ID corresponding to the consensus rule set that is active at + /// the given height. + /// + /// This is the branch ID that should be used when creating transactions. + pub fn for_height(height: u32) -> Self { + for nu in UPGRADES_IN_ORDER.iter().rev() { + if C::is_nu_active(*nu, height) { + return nu.branch_id(); + } + } + + // Sprout rules apply before any network upgrade + BranchId::Sprout + } +} + +#[cfg(test)] +mod tests { + use super::{BranchId, Parameters, MainNetwork, NetworkUpgrade, UPGRADES_IN_ORDER}; + + #[test] + fn nu_ordering() { + for i in 1..UPGRADES_IN_ORDER.len() { + let nu_a = UPGRADES_IN_ORDER[i - 1]; + let nu_b = UPGRADES_IN_ORDER[i]; + match ( + MainNetwork::activation_height(nu_a), + MainNetwork::activation_height(nu_b), + ) { + (Some(a), Some(b)) if a < b => (), + (Some(_), None) => (), + (None, None) => (), + _ => panic!( + "{} should not be before {} in UPGRADES_IN_ORDER", + nu_a, nu_b + ), + } + } + } + + #[test] + fn nu_is_active() { + assert!(!MainNetwork::is_nu_active(NetworkUpgrade::Overwinter, 0)); + assert!(!MainNetwork::is_nu_active( + NetworkUpgrade::Overwinter, + 347_499 + )); + assert!(MainNetwork::is_nu_active( + NetworkUpgrade::Overwinter, + 347_500 + )); + } + + #[test] + fn branch_id_for_height() { + assert_eq!(BranchId::for_height::(0), BranchId::Sprout,); + assert_eq!( + BranchId::for_height::(419_199), + BranchId::Overwinter, + ); + assert_eq!( + BranchId::for_height::(419_200), + BranchId::Sapling, + ); + assert_eq!( + BranchId::for_height::(5_000_000), + BranchId::Blossom, + ); + } +} From e6a8630b350cd61b41843139faacbcd0cec97321 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 27 Nov 2019 13:12:28 +0000 Subject: [PATCH 300/330] impl TryFrom for BranchId --- zcash_primitives/src/consensus.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/zcash_primitives/src/consensus.rs b/zcash_primitives/src/consensus.rs index f7cf480..8a7385c 100644 --- a/zcash_primitives/src/consensus.rs +++ b/zcash_primitives/src/consensus.rs @@ -1,5 +1,6 @@ //! Consensus parameters. +use std::convert::TryFrom; use std::fmt; /// Zcash consensus parameters. @@ -128,6 +129,21 @@ pub enum BranchId { Heartwood, } +impl TryFrom for BranchId { + type Error = &'static str; + + fn try_from(value: u32) -> Result { + match value { + 0 => Ok(BranchId::Sprout), + 0x5ba8_1b19 => Ok(BranchId::Overwinter), + 0x76b8_09bb => Ok(BranchId::Sapling), + 0x2bb4_0e60 => Ok(BranchId::Blossom), + 0xf5b9_230b => Ok(BranchId::Heartwood), + _ => Err("Unknown consensus branch ID"), + } + } +} + impl From for u32 { fn from(consensus_branch_id: BranchId) -> u32 { match consensus_branch_id { @@ -159,7 +175,9 @@ impl BranchId { #[cfg(test)] mod tests { - use super::{BranchId, Parameters, MainNetwork, NetworkUpgrade, UPGRADES_IN_ORDER}; + use std::convert::TryFrom; + + use super::{BranchId, MainNetwork, NetworkUpgrade, Parameters, UPGRADES_IN_ORDER}; #[test] fn nu_ordering() { @@ -194,6 +212,12 @@ mod tests { )); } + #[test] + fn branch_id_from_u32() { + assert_eq!(BranchId::try_from(0), Ok(BranchId::Sprout)); + assert!(BranchId::try_from(1).is_err()); + } + #[test] fn branch_id_for_height() { assert_eq!(BranchId::for_height::(0), BranchId::Sprout,); From d5ed68470119a949585cbec8582d467148679df5 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 27 Nov 2019 15:45:13 +0000 Subject: [PATCH 301/330] zcash_client_backend::decrypt_transaction --- zcash_client_backend/src/decrypt.rs | 76 +++++++++++++++++++++++++++++ zcash_client_backend/src/lib.rs | 3 ++ 2 files changed, 79 insertions(+) create mode 100644 zcash_client_backend/src/decrypt.rs diff --git a/zcash_client_backend/src/decrypt.rs b/zcash_client_backend/src/decrypt.rs new file mode 100644 index 0000000..f9830f6 --- /dev/null +++ b/zcash_client_backend/src/decrypt.rs @@ -0,0 +1,76 @@ +use pairing::bls12_381::Bls12; +use zcash_primitives::{ + note_encryption::{try_sapling_note_decryption, try_sapling_output_recovery, Memo}, + primitives::{Note, PaymentAddress}, + transaction::Transaction, + zip32::ExtendedFullViewingKey, + JUBJUB, +}; + +/// A decrypted shielded output. +pub struct DecryptedOutput { + /// The index of the output within [`shielded_outputs`]. + /// + /// [`shielded_outputs`]: zcash_primitives::transaction::TransactionData + pub index: usize, + /// The note within the output. + pub note: Note, + /// The address the note was sent to. + pub to: PaymentAddress, + /// The memo included with the note. + pub memo: Memo, + /// True if this output was recovered using an [`OutgoingViewingKey`], meaning that + /// this is a logical output of the transaction. + /// + /// [`OutgoingViewingKey`]: zcash_primitives::keys::OutgoingViewingKey + pub outgoing: bool, +} + +/// Scans a [`Transaction`] for any information that can be decrypted by the set of +/// [`ExtendedFullViewingKey`]s. +pub fn decrypt_transaction( + tx: &Transaction, + extfvks: &[ExtendedFullViewingKey], +) -> Vec { + let mut decrypted = vec![]; + + // Cache IncomingViewingKey calculation + let vks: Vec<_> = extfvks + .iter() + .map(|extfvk| (extfvk.fvk.vk.ivk(), extfvk.fvk.ovk)) + .collect(); + + for (index, output) in tx.shielded_outputs.iter().enumerate() { + let epk = match output.ephemeral_key.as_prime_order(&JUBJUB) { + Some(p) => p, + None => continue, + }; + + for (ivk, ovk) in &vks { + let ((note, to, memo), outgoing) = + match try_sapling_note_decryption(ivk, &epk, &output.cmu, &output.enc_ciphertext) { + Some(ret) => (ret, false), + None => match try_sapling_output_recovery( + ovk, + &output.cv, + &output.cmu, + &epk, + &output.enc_ciphertext, + &output.out_ciphertext, + ) { + Some(ret) => (ret, true), + None => continue, + }, + }; + decrypted.push(DecryptedOutput { + index, + note, + to, + memo, + outgoing, + }) + } + } + + decrypted +} diff --git a/zcash_client_backend/src/lib.rs b/zcash_client_backend/src/lib.rs index 87a808c..e3852e6 100644 --- a/zcash_client_backend/src/lib.rs +++ b/zcash_client_backend/src/lib.rs @@ -7,8 +7,11 @@ #![deny(intra_doc_link_resolution_failure)] pub mod constants; +mod decrypt; pub mod encoding; pub mod keys; pub mod proto; pub mod wallet; pub mod welding_rig; + +pub use decrypt::{decrypt_transaction, DecryptedOutput}; From 26be46573ee7e0094f19d861fd29793adda6298e Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 28 Nov 2019 10:31:16 +0300 Subject: [PATCH 302/330] add hash of the node method --- src/node_data.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/node_data.rs b/src/node_data.rs index ac545e2..0e972f9 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -193,6 +193,14 @@ impl NodeData { let mut cursor = std::io::Cursor::new(buf); Self::read(consensus_branch_id, &mut cursor) } + + pub fn hash(&self) -> [u8; 32] { + let mut buf = [0u8; 32]; + + let bytes = self.to_bytes(); + + blake2b_personal(&personalization(self.consensus_branch_id), &bytes) + } } #[cfg(test)] From 9059f53873fcc59e4c6b0c4c9fb7caddc5f9f128 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 28 Nov 2019 15:31:23 +0300 Subject: [PATCH 303/330] fix review notes and other issues --- src/entry.rs | 4 ++-- src/lib.rs | 16 ++++++++++------ src/node_data.rs | 3 +-- src/tree.rs | 25 +++++++++---------------- 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/entry.rs b/src/entry.rs index 257b9dd..ab95a38 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -40,7 +40,7 @@ impl Entry { /// Left child pub fn left(&self) -> Result { match self.kind { - EntryKind::Leaf => { Err(Error::ExpectedNode) } + EntryKind::Leaf => { Err(Error::node_expected()) } EntryKind::Node(left, _) => Ok(left) } } @@ -48,7 +48,7 @@ impl Entry { /// Right child. pub fn right(&self) -> Result { match self.kind { - EntryKind::Leaf => { Err(Error::ExpectedNode) } + EntryKind::Leaf => { Err(Error::node_expected()) } EntryKind::Node(_, right) => Ok(right) } } diff --git a/src/lib.rs b/src/lib.rs index c0c781c..0c26dfa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,18 +17,16 @@ pub use entry::{Entry, MAX_ENTRY_SIZE}; pub enum Error { /// Entry expected to be presented in the tree view while it was not. ExpectedInMemory(EntryLink), - /// Entry expected to be a node. - ExpectedNode, /// Entry expected to be a node (specifying for which link this is not true). - ExpectedNodeForLink(EntryLink), + ExpectedNode(Option), } impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match *self { Self::ExpectedInMemory(l) => write!(f, "Node/leaf expected to be in memory: {}", l), - Self::ExpectedNode => write!(f, "Node expected"), - Self::ExpectedNodeForLink(l) => write!(f, "Node expected, not leaf: {}", l), + Self::ExpectedNode(None) => write!(f, "Node expected"), + Self::ExpectedNode(Some(l)) => write!(f, "Node expected, not leaf: {}", l), } } } @@ -63,9 +61,15 @@ pub enum EntryKind { } impl Error { + /// Entry expected to be a node (specifying for which link this is not true). + pub fn link_node_expected(link: EntryLink) -> Self { Self::ExpectedNode(Some(link)) } + + /// Some entry is expected to be node + pub fn node_expected() -> Self { Self::ExpectedNode(None) } + pub (crate) fn augment(self, link: EntryLink) -> Self { match self { - Error::ExpectedNode => Error::ExpectedNodeForLink(link), + Error::ExpectedNode(_) => Error::ExpectedNode(Some(link)), val => val } } diff --git a/src/node_data.rs b/src/node_data.rs index 0e972f9..55b2df2 100644 --- a/src/node_data.rs +++ b/src/node_data.rs @@ -194,9 +194,8 @@ impl NodeData { Self::read(consensus_branch_id, &mut cursor) } + /// Hash node metadata pub fn hash(&self) -> [u8; 32] { - let mut buf = [0u8; 32]; - let bytes = self.to_bytes(); blake2b_personal(&personalization(self.consensus_branch_id), &bytes) diff --git a/src/tree.rs b/src/tree.rs index d3b6dcd..c020c72 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -28,22 +28,15 @@ pub struct Tree { impl Tree { /// Resolve link originated from this tree pub fn resolve_link(&self, link: EntryLink) -> Result { - match link { - EntryLink::Generated(index) => { - let node = self.generated.get(index as usize).ok_or(Error::ExpectedInMemory(link))?; - Ok(IndexedNode { - node, - link, - }) - }, - EntryLink::Stored(index) => { - let node = self.stored.get(&index).ok_or(Error::ExpectedInMemory(link))?; - Ok(IndexedNode { - node, - link, - }) - }, - } + match link { + EntryLink::Generated(index) => self.generated.get(index as usize), + EntryLink::Stored(index) => self.stored.get(&index), + } + .map(|node| IndexedNode { + node, + link, + }) + .ok_or(Error::ExpectedInMemory(link)) } fn push(&mut self, data: Entry) -> EntryLink { From 9ea0427678797eb7e1f8692de5bd368e4cd68943 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 4 Dec 2019 13:24:26 -0800 Subject: [PATCH 304/330] MMR trees API (#118) The main design goals of this mmr implementation were 1. Avoid database callbacks. As it is implemented, calling side must just smartly pre-load MMR nodes from the database (about log2(tree length) for append, twice as much for deletion). 2. Reuse as much code/logic between rust and c++ clients. 3. Close to zero memory consumption. --- Cargo.lock | 28 +++ librustzcash/Cargo.toml | 1 + librustzcash/include/librustzcash.h | 27 +++ librustzcash/src/rustzcash.rs | 195 ++++++++++++++++++++ librustzcash/src/tests/mmr.rs | 228 ++++++++++++++++++++++++ librustzcash/src/tests/mod.rs | 1 + librustzcash/src/tests/res/tree1023.dat | Bin 0 -> 153867 bytes librustzcash/src/tests/res/tree16.dat | Bin 0 -> 2352 bytes 8 files changed, 480 insertions(+) create mode 100644 librustzcash/src/tests/mmr.rs create mode 100644 librustzcash/src/tests/res/tree1023.dat create mode 100644 librustzcash/src/tests/res/tree16.dat diff --git a/Cargo.lock b/Cargo.lock index 6b472c9..9a09a9d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -73,6 +73,15 @@ dependencies = [ "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bigint" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bit-vec" version = "0.4.4" @@ -219,6 +228,11 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crunchy" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "crypto_api" version = "0.2.2" @@ -372,6 +386,7 @@ dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.15.0", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "zcash_mmr 0.1.0 (git+https://github.com/nikvolf/zcash-mmr)", "zcash_primitives 0.1.0", "zcash_proofs 0.1.0", ] @@ -666,6 +681,16 @@ dependencies = [ "zcash_primitives 0.1.0", ] +[[package]] +name = "zcash_mmr" +version = "0.1.0" +source = "git+https://github.com/nikvolf/zcash-mmr#26be46573ee7e0094f19d861fd29793adda6298e" +dependencies = [ + "bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "zcash_primitives" version = "0.1.0" @@ -713,6 +738,7 @@ dependencies = [ "checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" "checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" "checksum bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0089c35ab7c6f2bc55ab23f769913f0ac65b1023e7e74638a1f43128dd5df2" +"checksum bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebecac13b3c745150d7b6c3ea7572d372f09d627c2077e893bf26c5c7f70d282" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" "checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182" "checksum blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "979da0ce13c897d6be19e005ea77ac12b0fea0157aeeee7feb8c49f91386f0ea" @@ -731,6 +757,7 @@ dependencies = [ "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" +"checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" "checksum crypto_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f855e87e75a4799e18b8529178adcde6fd4f97c1449ff4821e747ff728bb102" "checksum crypto_api_chachapoly 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95b2ad7cab08fd71addba81df5077c49df208effdfb3118a1519f9cdeac5aaf2" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" @@ -781,3 +808,4 @@ dependencies = [ "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum zcash_mmr 0.1.0 (git+https://github.com/nikvolf/zcash-mmr)" = "" diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index 8f33896..64999f2 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -28,6 +28,7 @@ libc = "0.2" pairing = { version = "0.15.0", path = "../pairing" } lazy_static = "1" rand_core = "0.5.1" +zcash_mmr = { git = "https://github.com/nikvolf/zcash-mmr" } zcash_primitives = { version = "0.1.0", path = "../zcash_primitives" } zcash_proofs = { version = "0.1.0", path = "../zcash_proofs" } diff --git a/librustzcash/include/librustzcash.h b/librustzcash/include/librustzcash.h index a3ca5e8..1aa85ed 100644 --- a/librustzcash/include/librustzcash.h +++ b/librustzcash/include/librustzcash.h @@ -307,6 +307,33 @@ extern "C" { unsigned char *j_ret, unsigned char *addr_ret ); + + uint32_t librustzcash_mmr_append( + uint32_t cbranch, + uint32_t t_len, + const uint32_t *ni_ptr, + const unsigned char *n_ptr, + size_t p_len, + const unsigned char *nn_ptr, + unsigned char *rt_ret, + unsigned char *buf_ret + ); + + uint32_t librustzcash_mmr_delete( + uint32_t cbranch, + uint32_t t_len, + const uint32_t *ni_ptr, + const unsigned char *n_ptr, + size_t p_len, + size_t e_len, + unsigned char *rt_ret + ); + + uint32_t librustzcash_mmr_hash_node( + uint32_t cbranch, + const unsigned char *n_ptr, + unsigned char *h_ret + ); } #endif // LIBRUSTZCASH_INCLUDE_H_ diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 9c199dd..0bfd5ad 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -65,6 +65,8 @@ use zcash_proofs::{ sprout, }; +use zcash_mmr::{Entry as MMREntry, NodeData as MMRNodeData, Tree as MMRTree}; + #[cfg(test)] mod tests; @@ -1173,3 +1175,196 @@ pub extern "C" fn librustzcash_zip32_xfvk_address( true } + +fn construct_mmr_tree( + // Consensus branch id + cbranch: u32, + // Length of tree in array representation + t_len: u32, + + // Indices of provided tree nodes, length of p_len+e_len + ni_ptr: *const u32, + // Provided tree nodes data, length of p_len+e_len + n_ptr: *const [c_uchar; zcash_mmr::MAX_ENTRY_SIZE], + + // Peaks count + p_len: size_t, + // Extra nodes loaded (for deletion) count + e_len: size_t, +) -> Result { + let (indices, nodes) = unsafe { + ( + slice::from_raw_parts(ni_ptr, p_len + e_len), + slice::from_raw_parts(n_ptr, p_len + e_len), + ) + }; + + let mut peaks = Vec::new(); + for i in 0..p_len { + peaks.push(( + indices[i], + match MMREntry::from_bytes(cbranch, &nodes[i][..]) { + Ok(entry) => entry, + _ => { + return Err("Invalid encoding"); + } // error + }, + )); + } + + let mut extra = Vec::new(); + for i in p_len..(p_len + e_len) { + extra.push(( + indices[i], + match MMREntry::from_bytes(cbranch, &nodes[i][..]) { + Ok(entry) => entry, + _ => { + return Err("Invalid encoding"); + } // error + }, + )); + } + + Ok(MMRTree::new(t_len, peaks, extra)) +} + +#[no_mangle] +pub extern "system" fn librustzcash_mmr_append( + // Consensus branch id + cbranch: u32, + // Length of tree in array representation + t_len: u32, + // Indices of provided tree nodes, length of p_len + ni_ptr: *const u32, + // Provided tree nodes data, length of p_len + n_ptr: *const [c_uchar; zcash_mmr::MAX_ENTRY_SIZE], + // Peaks count + p_len: size_t, + // New node pointer + nn_ptr: *const [u8; zcash_mmr::MAX_NODE_DATA_SIZE], + // Return of root commitment (32 byte hash) + rt_ret: *mut u8, + // Return buffer for appended leaves, should be pre-allocated of log2(t_len)+1 length + buf_ret: *mut [c_uchar; zcash_mmr::MAX_NODE_DATA_SIZE], +) -> u32 { + let new_node_bytes: &[u8; zcash_mmr::MAX_NODE_DATA_SIZE] = unsafe { + match nn_ptr.as_ref() { + Some(r) => r, + None => { + return 0; + } // Null pointer passed, error + } + }; + + let mut tree = match construct_mmr_tree(cbranch, t_len, ni_ptr, n_ptr, p_len, 0) { + Ok(t) => t, + _ => { + return 0; + } // error + }; + + let node = match MMRNodeData::from_bytes(cbranch, &new_node_bytes[..]) { + Ok(node) => node, + _ => { + return 0; + } // error + }; + + let appended = match tree.append_leaf(node) { + Ok(appended) => appended, + _ => { + return 0; + } + }; + + let return_count = appended.len(); + + let root_node = tree + .root_node() + .expect("Just added, should resolve always; qed"); + unsafe { + slice::from_raw_parts_mut(rt_ret, 32).copy_from_slice(&root_node.data().subtree_commitment); + + for (idx, next_buf) in slice::from_raw_parts_mut(buf_ret, return_count as usize) + .iter_mut() + .enumerate() + { + tree.resolve_link(appended[idx]) + .expect("This was generated by the tree and thus resolvable; qed") + .data() + .write(&mut &mut next_buf[..]) + .expect("Write using cursor with enough buffer size cannot fail; qed"); + } + } + + return_count as u32 +} + +#[no_mangle] +pub extern "system" fn librustzcash_mmr_delete( + // Consensus branch id + cbranch: u32, + // Length of tree in array representation + t_len: u32, + // Indices of provided tree nodes, length of p_len+e_len + ni_ptr: *const u32, + // Provided tree nodes data, length of p_len+e_len + n_ptr: *const [c_uchar; zcash_mmr::MAX_ENTRY_SIZE], + // Peaks count + p_len: size_t, + // Extra nodes loaded (for deletion) count + e_len: size_t, + // Return of root commitment (32 byte hash) + rt_ret: *mut u8, +) -> u32 { + let mut tree = match construct_mmr_tree(cbranch, t_len, ni_ptr, n_ptr, p_len, e_len) { + Ok(t) => t, + _ => { + return 0; + } // error + }; + + let truncate_len = match tree.truncate_leaf() { + Ok(v) => v, + _ => { + return 0; + } // Error + }; + + unsafe { + slice::from_raw_parts_mut(rt_ret, 32).copy_from_slice( + &tree + .root_node() + .expect("Just generated without errors, root should be resolving") + .data() + .subtree_commitment, + ); + } + + truncate_len +} + +#[no_mangle] +pub extern "system" fn librustzcash_mmr_hash_node( + cbranch: u32, + n_ptr: *const [u8; zcash_mmr::MAX_NODE_DATA_SIZE], + h_ret: *mut u8, +) -> u32 { + let node_bytes: &[u8; zcash_mmr::MAX_NODE_DATA_SIZE] = unsafe { + match n_ptr.as_ref() { + Some(r) => r, + None => return 1, + } + }; + + let node = match MMRNodeData::from_bytes(cbranch, &node_bytes[..]) { + Ok(n) => n, + _ => return 1, // error + }; + + unsafe { + slice::from_raw_parts_mut(h_ret, 32).copy_from_slice(&node.hash()[..]); + } + + return 0; +} diff --git a/librustzcash/src/tests/mmr.rs b/librustzcash/src/tests/mmr.rs new file mode 100644 index 0000000..6e40f7f --- /dev/null +++ b/librustzcash/src/tests/mmr.rs @@ -0,0 +1,228 @@ +use zcash_mmr::{Entry, EntryLink, NodeData}; + +use crate::{librustzcash_mmr_append, librustzcash_mmr_delete}; + +const NODE_DATA_16L: &[u8] = include_bytes!("./res/tree16.dat"); +const NODE_DATA_1023L: &[u8] = include_bytes!("./res/tree1023.dat"); + +struct TreeView { + peaks: Vec<(u32, Entry)>, + extra: Vec<(u32, Entry)>, +} + +fn draft(into: &mut Vec<(u32, Entry)>, vec: &Vec, peak_pos: usize, h: u32) { + let node_data = vec[peak_pos - 1].clone(); + let peak: Entry = match h { + 0 => node_data.into(), + _ => Entry::new( + node_data, + EntryLink::Stored((peak_pos - (1 << h) - 1) as u32), + EntryLink::Stored((peak_pos - 2) as u32), + ), + }; + + into.push(((peak_pos - 1) as u32, peak)); +} + +fn prepare_tree(vec: &Vec) -> TreeView { + assert!(vec.len() > 0); + + // integer log2 of (vec.len()+1), -1 + let mut h = (32 - ((vec.len() + 1) as u32).leading_zeros() - 1) - 1; + let mut peak_pos = (1 << (h + 1)) - 1; + let mut nodes = Vec::new(); + + // used later + let mut last_peak_pos = 0; + let mut last_peak_h = 0; + + loop { + if peak_pos > vec.len() { + // left child, -2^h + peak_pos = peak_pos - (1 << h); + h = h - 1; + } + + if peak_pos <= vec.len() { + draft(&mut nodes, vec, peak_pos, h); + + // save to be used in next loop + last_peak_pos = peak_pos; + last_peak_h = h; + + // right sibling + peak_pos = peak_pos + (1 << (h + 1)) - 1; + } + + if h == 0 { + break; + } + } + + // for deletion, everything on the right slope of the last peak should be pre-loaded + let mut extra = Vec::new(); + let mut h = last_peak_h; + let mut peak_pos = last_peak_pos; + + while h > 0 { + let left_pos = peak_pos - (1 << h); + let right_pos = peak_pos - 1; + h = h - 1; + + // drafting left child + draft(&mut extra, vec, left_pos, h); + + // drafting right child + draft(&mut extra, vec, right_pos, h); + + // continuing on right slope + peak_pos = right_pos; + } + + TreeView { + peaks: nodes, + extra, + } +} + +fn preload_tree_append(vec: &Vec) -> (Vec, Vec<[u8; zcash_mmr::MAX_ENTRY_SIZE]>) { + assert!(vec.len() > 0); + + let tree_view = prepare_tree(vec); + + let mut indices = Vec::new(); + let mut bytes = Vec::new(); + + for (idx, entry) in tree_view.peaks.into_iter() { + let mut buf = [0u8; zcash_mmr::MAX_ENTRY_SIZE]; + entry + .write(&mut &mut buf[..]) + .expect("Cannot fail if enough buffer length"); + indices.push(idx); + bytes.push(buf); + } + + (indices, bytes) +} + +// also returns number of peaks +fn preload_tree_delete( + vec: &Vec, +) -> (Vec, Vec<[u8; zcash_mmr::MAX_ENTRY_SIZE]>, usize) { + assert!(vec.len() > 0); + + let tree_view = prepare_tree(vec); + + let mut indices = Vec::new(); + let mut bytes = Vec::new(); + + let peak_count = tree_view.peaks.len(); + + for (idx, entry) in tree_view + .peaks + .into_iter() + .chain(tree_view.extra.into_iter()) + { + let mut buf = [0u8; zcash_mmr::MAX_ENTRY_SIZE]; + entry + .write(&mut &mut buf[..]) + .expect("Cannot fail if enough buffer length"); + indices.push(idx); + bytes.push(buf); + } + + (indices, bytes, peak_count) +} + +fn load_nodes(bytes: &'static [u8]) -> Vec { + let mut res = Vec::new(); + let mut cursor = std::io::Cursor::new(bytes); + while (cursor.position() as usize) < bytes.len() { + let node_data = + zcash_mmr::NodeData::read(0, &mut cursor).expect("Statically checked to be correct"); + res.push(node_data); + } + + res +} + +#[test] +fn append() { + let nodes = load_nodes(NODE_DATA_16L); + let (indices, peaks) = preload_tree_append(&nodes); + + let mut rt_ret = [0u8; 32]; + + let mut buf_ret = Vec::<[u8; zcash_mmr::MAX_NODE_DATA_SIZE]>::with_capacity(32); + + let mut new_node_data = [0u8; zcash_mmr::MAX_NODE_DATA_SIZE]; + let new_node = NodeData { + consensus_branch_id: 0, + subtree_commitment: [0u8; 32], + start_time: 101, + end_time: 110, + start_target: 190, + end_target: 200, + start_sapling_root: [0u8; 32], + end_sapling_root: [0u8; 32], + subtree_total_work: Default::default(), + start_height: 10, + end_height: 10, + shielded_tx: 13, + }; + new_node + .write(&mut &mut new_node_data[..]) + .expect("Failed to write node data"); + + let result = librustzcash_mmr_append( + 0, + nodes.len() as u32, + indices.as_ptr(), + peaks.as_ptr(), + peaks.len(), + &new_node_data, + rt_ret.as_mut_ptr(), + buf_ret.as_mut_ptr(), + ); + + unsafe { + buf_ret.set_len(result as usize); + } + + assert_eq!(result, 2); + + let new_node_1 = + NodeData::from_bytes(0, &buf_ret[0][..]).expect("Failed to reconstruct return node #1"); + + let new_node_2 = + NodeData::from_bytes(0, &buf_ret[1][..]).expect("Failed to reconstruct return node #2"); + + assert_eq!(new_node_1.start_height, 10); + assert_eq!(new_node_1.end_height, 10); + + // this is combined new node (which is `new_node_1`) + the one which was there before (for block #9) + assert_eq!(new_node_2.start_height, 9); + assert_eq!(new_node_2.end_height, 10); + assert_eq!(new_node_2.shielded_tx, 27); +} + +#[test] +fn delete() { + let nodes = load_nodes(NODE_DATA_1023L); + let (indices, nodes, peak_count) = preload_tree_delete(&nodes); + + let mut rt_ret = [0u8; 32]; + + let result = librustzcash_mmr_delete( + 0, + nodes.len() as u32, + indices.as_ptr(), + nodes.as_ptr(), + peak_count, + indices.len() - peak_count, + rt_ret.as_mut_ptr(), + ); + + // Deleting from full tree of 9 height would result in cascade deleting of 10 nodes + assert_eq!(result, 10); +} diff --git a/librustzcash/src/tests/mod.rs b/librustzcash/src/tests/mod.rs index dba7387..bbaee0a 100644 --- a/librustzcash/src/tests/mod.rs +++ b/librustzcash/src/tests/mod.rs @@ -4,6 +4,7 @@ use super::JUBJUB; mod key_agreement; mod key_components; +mod mmr; mod notes; mod signatures; diff --git a/librustzcash/src/tests/res/tree1023.dat b/librustzcash/src/tests/res/tree1023.dat new file mode 100644 index 0000000000000000000000000000000000000000..bfd79d10e851ff10e1ae67ff8dfcbcd6704e77f1 GIT binary patch literal 153867 zcmcfKc{EmE`#*5EF_9=FQBjmago+{+X^^=AB}%g)DnlWnk||0e5=ttCl2jTHsSG6* z2}L0(LzD5;Z@-`Q^sn<<>-*Sy-FrQMoO{`?&-+}ibKM>vA1;b;3g666gN$p+^T+nfIf*SWa`Zlr!c%(p8!Ml|biPF>zKPo9sPTjqT-z4+i! zbJbCu%n3*dB&0-x#Ni&r_766RykYu(Ibm#X{vTZD;Tgg9Rg}mZW|Iw04BMOk2iJLd z1znP&YNBu7d$cIs%Cdd`?P<5h9E_{pJf*B-OR#gVQR5Ay1QKo<4H6Hp*zqZ8#p+@~ zDm7{w)hP0MtH`3~ zuL8PmuJQAJGFkP^51Sv)U*7QyKrMlUTB1SX8=?9}d}DM%?aQ}?`!-8X{rX1Z`f9y* zXHL9cUGio?VDtE!66i}Hp)b)OaYh)ElZITjx_)%*=`U(iPM+cA-gqGpDgC=?G)RIY zW!e70T*(_SzJXK6_U8Y=bs-^9wy)w%-he3poEEk>{|~MU3ybZS5!yYdwN=_X>*$DN z=~n`pNea(e22>7DXw6ZZD80iTDS?EPXpn@2_3EB0tw%7G)RKNdgP=bS0K5Hi4vTyA>aAGxj1Un7`87IPTqjd4NgDX zoBs#bMMTEF9W%npvZkx$&C+f@t%>ga5gy%1`*-F2-uX!ALi4%w*GLH@q(p->N<@L} zAM7-FL(+dayd1W7|KG2V9*qyOL#||U6;l8>A{0oXq7rxd73wofrUy6~h!*_)@jYN+ z!aGN6b@SI|<#U8@b(y;%C6I8_XplyWD&4zU9DLGHe!5(GXURjO(k-JI>)xA!Ysarq zv2LHS{fszj2_)1K4bmu46BX5j-y4rsOSp)gKA~yyEB~o^wdT_{$9SuA`PMp{2Heq? z{*7-mNP?naCnA&I@f2V)>s}<%YknrfGLE?zk zkdua7>EtTrZg8Y1l((3e` zEh4%%Tsp96w_&tn+#;zhW^v}z1za6g+ROTfDxj7?LM_oCiHX~h(}rACb`v!;7b=f!a`~d%>DOcM?a}YliZYu^qbH8w zh$AJCkP;1&grpWZZOGM1u41AD$BIHqd#FK<;krGHqi3Vw$ls12yyR_h+TT-dczP{h5I9!-_ zNXTzXR@%lj-Q{9RV|mu2mOw%+(I81kximE#u)h%?S@>7|(1$B4tF*UG7k{<9MxS@p zf-ibMR8}uWUjhkzi3Ukbs*IdAi{l9cQvf(eD3D}iFF(UFdxAGBg#=^oG7IHU4J^27$t zj|cTg2_&RMgET>Ak$Fsuz{qcH83QkvU#@2Bmb!ioTDoE7%iU8aZ`eLZE#ew#2_$^S z(IAbN@ngGjQwRkUB{-2}5BHLlm1jFbg)q>$!8t>LG;!h-l}UN;-Rhk;rBsyE7w)gL zNNZxAcjia5$80UX#GgB_4=I6!lxUD-CmOP)G?!2?zJYUr?BQOMCQW5KVi93r3IHdA z0%`JOh0(Hq99|tO7L`1GMAZ7UXJN%szPQ)}yY|LCaeCW$Gw?f70tqS6AWfRQTw<_o zx%%yZ0bi$7tFAqDyA>Liwq{T8RxJ9v#!qRk^%m3;NT?+mB-zOk>+`aHoKBssr@yV` z>C9tRy^k24)f?_r-@KK&=0eKH^IOrE{*7-mNaH6n!knOMVPi+0kr8|5n|i~+!lts6 zZ*lm@pE1!$iZhwX;wEPexmJ>d@PPoJ+hh;-l9N+pJ7P6q;3)@AAqA4W z{IpY>icc;olYi6idTB)ecr*9E#jSh7lhvAz?RjBnl2TEJaIYy-rn4QfgD@~Lf%Ap}Y3fv^nx{EZsSi)Cot!EEX5`GN=f-~F`5+_HwO{av z#^GiMwXsMEB&0-xG-ay!=Hlh+6y5p`Sx!i?ni`^aCT3KG&dTg<$8 zajEgyTWdM7ICDn3Ww8vU?0B@Qt?ZT6^N;gqO>_=Wj0+yoZ!PLP|79)23TL z7x(MVZ%jMip?_Che$~K$O z{r_B5Qc`7mTPmTTcY`yA0%^vKSzRKDJ#x*WC3#Q#I($7(+`L&7CnU8j_{dX{b<4D` zj5>ytKtf71NJ=v{u%(nqC>Y?tk)e>%%$aIzq&tLzIRG3*3M6G^^@Z=BKZpufaOJbD zUE%Tj^Tt-kH8VAMPR=l8yGneK5=cmi21!K~zdkwSswNx^ zaNrnFNNLtA%^^MHVk6;T4gkl50!d9xtFpXKz+L%@;^zgQlGMs>Fv?m;P$OFlNqt_?5R6oFa- z3AIFnq@q?4d8FSnl>5%c3DsN9I#)JYawX03-1CQf{RO{1*LR(MKIlvT1~?idB{e3D zpQf>NU0IT72#+j$n{?Q<+t@b0|eWnu0--Wf9!P98=8*ou@uLP|79>a(5MQu<3cm@2_>qL7k?#ymEXAYouQ0mp*^NmEmMKvMo@ zMeKv_{7rka8v@c*{6+Tfuh@SghIh4M#FDRznvoJnNQnkXL(}bqOgrbTsn%K%Dbd~PF6B1k?ee3UYfp}NQW1@mKtf71NLq9D zv86PPP%u@36HWGTueoy3lKx~?dG zNcC_-ErEnuqCwJ{*WtM=&2qwFv3I|pA59RBNgmnew5N>!{9M2KS#b{2;$vQ-Fa4V; zX^_=?nUQbVX{JboIM=e*(krGHqi3Vx@f&d<$ zC-w;`QCaPSa)#oWl7ssPpJ}|;Px`KQ*hey(ewVk-u3;2_&RMgS1fp*d1#%#j#s%T)DWje-l@6 ze`eS0RQ;T2(Jq0X+%i7vealfxAfc9MkaYDK5sr+YPeRqD<)-E{ueArA8e2NZ*Spxb z{F7mLIUN+pXg+?KvZMgh_5tTF09E zai{nXVQvD-gi=!K`b-Uv%{$fBMFDA{o8Qaa_IZ&!u|>=1?#I_MdZ#1m^7k2=U0(TL z6n@r3BPlt3CW~Lr_QK23vnlIr?O(bDKM_3lzE}Qywz<*ao=ZB<&V{_+hTmyIQuv)F z8YqrFV=u_o4nheCpH%?rC40EnqD4#DjyOdac>IFH&BONY|NHgDi;YtDOHFka+i_A` zF!jRf>~S2~;LWPaBMMg4UNbXparm$oNLPSjhsD7^MXN+2O6 z8l)u#QJbd=`116eaSZA@I=eYN)5e{vzdhRX{tlN!Pv>_BJz7yqAfc9MkQNy*6Gh>Pn!;o$KL&I}5qrAt=^2z``^STG~6MC-C^LD##(>$qOT zbv5w2RrU&)DLhksgp@!+N;F7@OHZ+-R6;nI!NJj_kdl!R>mRSFBpi%#;OJ2xEnBvV zFLd;;U8<8p0)rY4jNIb8OGVFoTls{BzVu>~6Tf+~S0g2mkP;1&(XzN^-b$;oWnIF4 zo4NVsmp9H#d9tuL?)DqMrw1=K$H0eM&)r6E`ZtBsKrLFv7?UH1Uhl{|@M#60WfbaZ`Erw?L0nwT zgoFMKjs*qMiWR2kLnj;?lYMWNWZvujE$*u$(`xcxy4`Q~o_v=Tz}ZTHWNd7H;PHXN(ytzCs?C$O)~_`4o+o;E zLdQPObLx9<^bTH1LG z)Qas0Il{m!08Ru2l9}0RKV7ByD|y3QM>z6@$Om51ogS!_ySc^vk!r^Hm0BNul_DjO zkP;1&so7<-jeq;xwuYQ#X5_m2xLkiXJxgy>dWE`lQdxUOM5}YYMyxB`j#ceLi9w^TqC-k~?lS%wd zqy!RDqCqmZxW<;!LPEi03C>lrhkIFCu46l5IbmQx0p}J4l9iQp(Y}e%JC|hscqwF| zl6Pip#!V@$`<;^_6wlw%?o-JNPD4r{Atf3lORMXVYwpA!FdV5{zT99@=-t7={_OR0 z45W{HY<3KrvMN2{KeYrBYKaEP+={VdotrEP2IDS3`D73GTD{ta?T8J8frkn>&nS@A ztg*d2KA`kr_=CU>$@~*)CJQHb4Q@Uh6a)!N~cxSE!uiLkNE1q*;l%Gd}z*+qs z*%k96y91FDNJxnWY3;f@W*Nml6l)*MZPb=OzQ9cM<*3D-ymew@WWRhcO#BHb>v-G3IUQY{Jp*26R2QCKqTg?)7xXH0+eD-U5>lc;vRz-W zb#{grk4kxeUu=#Re{h*7$eoNuD17()Gd(QIl zH^ue7GtRp-e@%OgfB8wLg(~fRt7Bb}5=cmi25F=H({;CltDHUVoxCX-uUt3vM8}fx z&ev1DKAc%O!dScF49`K-5=f{e8l(;OOa#ZKU8Y{rsjenPlOC-t=#bqk*!vXM}l1N6c(ad~tzGey=*;_RSp~#`kR%zQuX$zRh1dJ3Q=7 z3FaoC@BpTPGPh@H_yo=-l+5^`7hb@fAsCw-HTqk>9J9-JTYBIGwGQ|C3|0KR2`K!$ zi3VzsJ(D$(?K`iOfbhWppm`L&^Bf$uvXNdB4xV)2ET%x(v}xOv8^8G7+xJa=lBc~l zBQR@@e|XlwYyr27L)kwSMkKUNM@k?eB^o4$P33GUy(b)uyWkj8NNMxt?QEnr!ok!8 z&Ke3NN5>t}{NEzC9(v-n_-N@2&GlTTTl*I8K0ctLCNmIY_^W)}Y@`GdQldfH>{!XQ zi$~{$;lr5k1O?L0 zovz&8BjloPs9G+V)>)R#7p?R5DF5~-@2DM$HBCYmJ;pnc5=cmi25HC6`XM7C7iSR) zhB$B%$R6&sYu9eJBeV$vvj8|3DUh6;+}dJ7e>tib_FSsnIQaGR`GO^0`&GWb`0cw- zaPj0333t7a5=cmi25Fa5bjTh2nWKz zEC5ag1=8-_`^KfE9#Ttpk{uWoEqx?oaB^tzOO@?wQmj5yJF6u99?grCKtf71NUpov zuAKhasOLFv!RYzc4pP#iS|^vv3|@Y^qM_^9q{a2?4eC)#Afc9Mkeqij6&#aae8Q5#K6!MzNhL|4H~kyqXrOlNX2N*>wumRG3VRu*L}z}? z9sj}aYv$_nF`w)=#75Vwoqydm4s#Pws+5v)*v-`NvlaO+g24=ql-Pgqi0!MfUw3o! zV0+U(Lcv1?oF=k|d%3%No}Hj==T}`~Fs-=kukrHWD7Ba7SvwSqn-6qnJ#D?Vx)dpa zgp_EI+}yvh{Zk(#6ik-jd?kCh*PcCIY)2d;3=AmX{H8$KyVpC$`GAAM#!_jA63g%J zxn-V9#M)H0?{z;B^DE!A>i6x1a5coF$z9%$0;Q zk^;%Yf3MHzGbqW#gEaWUnpJbk9WFt?z~KTZPtxMgC-&GCTl&^ z5=f{e8l-(*Oa~{rwB@AN9;dfj;eSW{+1_+sajMnP2+32Xdd)mh>aOJ%(3}3vmNZaq zUQ8M5k9P713NtuB(<#)Gx3?c#i5C+N`ZqYUDUkN>KNzvjXu{^8;!&daQ#SR#%{1Uo zjm_r$=)w7Q;^Eafp2Clj5=cmi2FZIr!?4A~^_+k(#sRc|LQV$`__LYb5)P&TaF$Xa z`S=8UdXVV&@Zy@n+WEVq3N&3k6*;c68VXGxj?9rL@wwDdh?GD=N;F6Zd>9U=zhU_y zuOG^N5tbWAR zN_buOM`TQ1$>S?(btxOl_nMS-=6sR2M@k^!w$UIR^k)P)t;x+s@sAWIg(vQRS-5Qa z?=+3il5-wE-&b*jc_F@4z8v)g6zYiv%GaL};pXW~OekCS?P5>h=8P53MIMfLl6ZH7 zkJ6QhM&H37zOA#+pZ<+=G*I6Dj4-eI_6)=MM&28PQoMGi%K8|X7_U35`qnzIKPTvW z7H3R2<|m-=Af|zG^Ji)V+KLAq4m}8o5`On1W2x`82UZ_lglvR<7c8>;J0_v0%>_Sq z0!oz<%E6z>5;-IvUwbrA9DgQX zo~=s>5fDB~0pvyYaIb)XBWy=V5C-M~a1K!*9XfP$na9_B!>MtHmg=3#K0GnfT*ph; zlKWX$sm49uC}#84mw z1szL1H^Ne4mZMmCbflV-8pq#uQN{eXmlSRc)Mid9%JMjalt4mCG)RF#j2LH)ZOt7y znWk4=f(NAkzWFn?GXBlLlNPVpQF^Oog0&SG5ez;e0Cbb=;a*3NhOr%CP8gUo!FfP|6dW8Lv*^y;c<-HV zpO4>oxsC*?JT81QhCt2I_DyqspCOytQNc)HM&AUuuMQ3iw7Bc8IQT zN`2QZ-6_qJ&?{sQ;NqXHTqy!RDqCq+q!pO4rCs%^O zI0sN2*~7g;LnGOa@Fon*1mLt#AcciR9ldI4KkIyHmD-JVx92OXBAwmtykBDcF(vQd zwBjv(^R18)NJxnWDKw0c}3c6jKRD9Alc;3XfnESX;qqg26Zk5HIU5kg%oBe*O6I zXtp;c6AESma6~AOA|p>_P8L*N9KK0IHHqi_=k|vp2S&G5mhHPXq4zZZTlLDoSx5;a zq(p;sJd#o3NH4gsPNnZIvwlu!=Yx@xWOl8{I2mO=D^cG_fA11AlMH2lAf&I#D7&WvRqyqnLw9s|3UgFJBvt{`7C4qk%dW$%OHSJhb#U z+CSAqLppTF0=IA@xv#U0e(Vn_C>mQHCo=6yFXktp@F1pv3W#KCMzEE6I>BHX2S|!S znMXy%u#s{I2M-o-_+v3?|j21y@un2M5?r4Ma*HAtf55lhKSiM?l7~f=BegL5XQik7jMz@R*ZO z*Xf*Rp__4Zcg~%)HyTk-K%t&!prWD~JJ$KBihwZq0;Esj=AAlqhOM6J2?q}ra8^(t z#l*yWtz1?cVY^rMZ{a#wm7I|SUj8SKR>T!s=yh8!(SNOKkCZ?{N;F8PVi+yfR?td7 zm@xseqL9<+(+O<1uA6W$sDNWfffO5i_Eh+O&mR6d-K;rw%eCBU*JYg4e!tZ+d++LL z4dR23jgBBCkdP7$(&<=6o3r+E(wA<#?Yk!)m9Jdjc&zK~HR;`k2j+X~FW-7KI$%;5 z>Io>+6AjdVgEX7JEJR=?1CgAyy?F_*wkw^>@ZKD~?`wIRxx-k#8PDXA5=cmi1}Q#)S;W!e z72LaN#3_OLkQq-8+RE=4x7M#Ut@P+kxr5=eADT%Epq_w2J<&kLB`|)hqskP5!Hfw| zB-z8g&Yn$SJ3@sp(8IwwLxGf-c>e2?BOlupBicUf5qOtUZS5&?-}Ua75YxT+-NLa? zKFH)EC6JI34bs^}#*noY%q19%a{yf+d$`xRa~If-SVS0@3BbvqKuStV9lJY30A=CoZ~zBaQ^JXi#Y{OdX5S! zGcR9DOte2#&m>6gds6Ew^79bt2`JPP4b<5rCW8C+Gr7C3s#i(*Nu3N7Q1n>)Xu9da zt=?OnP7&%de{Mdm8U5+sKt}@=m&6G3O*uD3bNa^Q{agcouRUGzxT*7ItM1Khsp1Ab z>K-B67J8%lg9`2QrlBVn4Ez*BJ zRXTdzB5RS)hC%~;wV%8N_8zJaICHhHX;Lmy0tqS6ASI_Tt5`evMuNfM3s4!^!@bU* zzr=RL4#L3n1kM`@qze}=x5PAtA06-1o3&e}wm2<9Z@<%CT?Lzpg-sRxb*~q0xrUTL zLP|79=PxkkoK`Q>QtxKV$rj~m5iKi(^2ILKK1mvQ_2Es^+<>R1kz%MPpioaVP{|jV zMAo5h55Zs>2j~OY!@W{dudp5AOBi_Cf%Am|>Egxo=iB=9mrb2uVDs>!@R!GnmNxqA z{y>DX0e*ebJSo_Ti3ncoxdN}mko%|%KeAtf55v`dUNr?K#e zRcqrX&%6D_N~4N5J;>8Ah!GAbQdPGde|+re#f7LRpioaVP^p)g3~r}YaW1C@Q`afz zbBnnwwUJujlI79e-o9eZ{tL}JD|l_upZ<-$G*HQx7-KRO4ZY$C3Lg;w8X++Bd;b?# zFJI1J`!cD7f*uae7z(5-S29gI`+f?^eEJ=}GW@AtyS%2niHPGW9+~$|M+!a{$Ru$SFNNi|y9kAsoyE;3!fcUA=n!*!m*VQtoDxpxkwh z`|^O$)i$FL7=1NzObSpZimd>%uWV0fh%K4ODU#Q^Wcv zz1s-}(>OruD3tm2>$ljx^L`Ny9xUK&qCmQFBX_E+-I%pkHoTRH`ta(&!W~ZPekP&a z&vbQ;j~A)UZJzZFDS?EPXppYoV4PW-=3fHBj0unvg`BdpZ?oMxLBhbG0*(g-(#@N9 zQcjiqydib6LDXx40*5nU%g)W!A+BFmiFa+ze%0o)%>yZcgp_EIvTrhOoLV7K?Flo+ ztZ%K#@|fIP`g)n|wuwyGR;7mU4XWlZT(nV7K%t&!pswF!8d&G2u>^y`7a)JKhkNDZ z++{mLmN4*O0Vjk4>DH}0=OxD$zgy|f*Kbf$U@&6>6ixPUuiV^wY)7aQ1_l*y5-E^w-@ZTT$Ha!V`|jIB?ix+w zQk64EWKy_=Qh*9edkeu+v*3KM;2AvJTCLBe>U%8?iY2N5%0ym z#g?b)rg4BSkv-h&&YcHrM;HYD3I>neYn0y zq4Mtf+lN**Tb784rcYb?+45rVr`0x1)1QU5Zk%=>DS?EPXprvQWqeutlPSSqoCD|{ z*~7i^^77e^uqF)51mHZTK)QFY;9IKqxlhxC?w%>hd1zHr6xihZ#iqMEBb*5XJsg}`3Zw@Q9`*AUc$M$BFVUPn!&J)M z$AL@Ks7Uc)lfd!I_m4jCE>}ZJAR#3hr27w;!>p~qlVC8;0rZLN;a(3P7O@=>Kp2<_ z!0Dhs%Fi!WZ0*^9Yt#J5bg`z&o8D6zUgWI_;oo$YH+j^f#&x!Qc}NK)q(p=CFrPWb z*?dvT=bX!ksWbU3Z^s_H$9Qs2SLFQlDBi1Kx&G43NH^3IP^c#wsQdYh2#-XNqPT0S zKF`K}!I+vHxrba8I<=L@ws#1gyFPIKexEe@6Hw?+G*EZ)8DakF%cpev5=R|9`*`gH zwWe4r8@1&epYc@^aWn2cv6ww02J;h8CX`Uu^O+i{Gxkbs4Iz|(@VNz`Ub2UK6%;&XJK_{!pv1x9X8jik z*}fY4^}@mu<-DofH7#Dh+_KGO+^e-pZtU`1y~69V#K`3d0poLTc_F2L-*q%d1%*sF z>*M7dL17vPNSH!Sj~+c?3-dDJV59>_k^-ry=&6}8v+=I}t<1#>el*K171YZ<6&Bs3 ze5&pv_wIdDimP>y5=cmi2I)}|6UDLJm0iAn#?@a5pUr%Vmks!HrKS4yT+H2&xYU|= zZU6Wms3)NCT}J~|P{d4R{iDO#1cQ$V08OTF^NNd~vDMRk!oedLoEa2Ij~|y_EDIZm z>CX#0%{#TUO1h%<#@M-Icju0k=PNW(b@B-cK}sMYB^spS$IL0#R!~Afn8pFpq>xid zNg3O%t0WwZbl~VwAU%0f&K*`ggKx>$u5B}vw+YxP1+UIXiW$A`MkM#bKYxz82wX)< zAR#3hq>?909OrAB=k>teg`YLmYEn`M?9$zTjJvV#hfvS;I-eW)`&}APPe7rbXrPLp zFseKU9%c5(42tHKa;I$MUd7A#Y7l>Dhf#{*(rC}3u;SZw=uiLVaT=(CCyX%})rMa0 z2nwHD09r<&qMkmj7#hUI)l4|(;ow+MAU%8b+*MY5!E_1!p0tkO12*R+U(QdHnQ&sf z@f4rC4o5F9IGT)o!of@c&Q=Pfva-t7 zoXI&Og2PHn7H602lWVhjy4lr$+urtXs@wR+EpsmAB73;k^XISFj*ue^%mm;>P$0c{@%r7sllMw}kD_FY9>kd{ zRxUW0|GLd!?7+s=F_q!A$)}W&5=cmi2I=_=<}&BzB>DS43Z7&*sBCh|&YhE><(K*N zuZqF;3bW8>Vv<^gs3)LMPc%^FFBlV^86TRyg-*~|zhTLlZwqcl{7FBZvF_bE?G?AY z`O4%jpWBcA^lzY}fqMFa3F9B%w0G2=3qOTKHeHK<@2oO`@5t7gQQJohS|r|f)eXFP z5c3mIco5S-6}(_-gxSh`CIMj@2Pl^8;a-)MZ`h8|A`CoOz)7J%dik>2pk3e7EQWFW zqQ&E_=9}6q6ulxXaAA9_L50rOZS+L`TF|Vro~Is3q5TwCY`A1^*GY-OJZp>QUVDn z(I8d5Vy<(3rT1*;c0LiI!dDS~_?OnnvKpBmj^ZcI7_K<4pVw=+67>WW>WK!b@)cvp zIzL$w33sZdGl`9I{tX8mYK8b>sKZ*4tlMkdQW3Um&ege0 zZcggJuL_Gn8dZK}PTgUjZjw^l)&bDUcc( zKCV9HEY58%Jo(nK5hu9Jzd5={Z;nfNp1XDF#YK8)YyP}ON+2O68l?ILrkJ%AHS}G%yZxw=Sh=u8MTp|r zS4G)czmO70NQnmN{RieL$IIa6-NemjtM6(R8Cs+#i5cAU?^>U%>oU!7Z|NDib4sWu zpioaVQ1u^}2%a+kZ7undIW?EP`cri8g)SH{YfG0NC;c|_N@er+XO&gxPyYrw8mPA) z7-4~rouOWbW>~&m#(S%I&Rgx^?Ox4M8`nhSChg(25Al3pi1`U9JcwzaDnBqaqYCR9 z<`=AdvyjKDc|&(>%fY_VJ#XX^619@57q?3Ge0YnWKLLfGKhZ!Hd|2 zlf9ae;LEe`Vrt66+$sZMC))$Ts3)LMPc%@CpO{3}q3#C(VHyX>p2E#*ZvMhnPYmJU zX$Q_u3Z#~ncB!N5&qf?PaK!(M@PeHS#*K@-W?6OPw`qLiXq`VfVU6`j2_&RMgVfx@ zyk>0$0tAD>7ofdl5BF+q{mOQP7-3*~0>_U6>GS7rW3`XwmOi@?f2Wh{yv8=+d)1oH zj0>Ld?KD_4>u`E}^){pg5>lc;YW>W-adKsA46GI*Nfms_oowDtVtF?-1u>%LlNJK>ZJpYBz$pZs#>Ox#zG z{`7D3rGaYv%ovlYXy`S8B!rI$00omh+^emvgY5_f!axrP=L7}PmoJ?b8BGNY8u zl+h^qb@G(S;I0L=5&g3c_!$fIx^UOEAtjKI5)D$@7p9)IKg}W-jB@}bkUiY1y}gU= z2yMc^OaRVB3Z$=JySo=Jynn!PTxgGf_KN5^GRyjd1lB2ky17i(@MWg@db1x$2_&RM zgVg?&Y2-W-`E_T$pwUmBJCzrBSB@Q+yHEG8MsoHTi9^O2vdbE!QBOdjo@k)jzA_J3 zN0lW6gBcT`EV74tef##E?TA%`fgTRdT?(X*jvqVf>o#B7Dyn(Bqs(J*?XOW8<6frM zs$bT-(6jzIuc+Ehqy!RDqCxuB!8EhBg0%#LaSos&vWI(hcK&2L!htX_6M$1efz;LY zE3fL^!S;_km9uMo0t)p+1NE(oso>dmGF0FeCzx!p3hR7h~GU`pY3xfks&3-qh_(v-B%Jb8co z=M~fwP^c#wsP3Ok1MB>Bl3+0S{s+YRH`>@rf&KcgU;S)vI!ieJnJ)=vBn8s%-vd7* zdVK~)7aeMUUg9R+Ftyjb_M=Bng5B%SLI=lvylS-*DS?EPXpnyWW`41@f;57`j0uo9 zg`9eN2H9@ib;7}*0?tGVq~2bJ;Tj#BByhqoVe5H2%U^uT0|GZ62JjYtdZ({(IWFv4 zmX98C0tz|NK=t%8eH=@9DH}bn{TqJ1yjA^f+Db*Ur9l$~^EDOqXNbLuVmx?JQ9z-h zXrO-eG95f~{B5$&$y#dHJP2@mVRg^9;&7-S>Ys|LQp+o(fGiji@dzmuU zANJ%C6y|Y&rcCuy(2E1cadupam3?8W>=>SW#~Y2(tk|ODUiR z2N@10$EL2Hb6+{>@5w_A3P$DnT{_dJl`iji^Xk}7v2PxX7Lo!ANzp(J5EQp%`j|QA z%NB7U^p#kIKkjBOE zaYhyJTz`Lg|A6t+pN5YNgOU~NIs(S5^5~ywvT`1G+DCaL1{iK56&Q(&zy!G;9}f{S ztPQf`M>Y*sH&`{JYrE#XS)IGneuM?H2fj@0z1(-*R1beO z3M~B9C>pE)u<|zr{88T<3r4YI*Smb|c zu>RA#{13Cu%|e8P&xRm*kv-gtOkH^Kvvzw4g29Lb)FB!$ZVnkI7y-`X^vfdy?Bxz> zhYA#Umpw?-YmVKLt<25BrXCI<*NtJ2=%0xfbgjZsGDRD_adzo zFJabOX-+U0rGa`t12zIpj2Xo#bIEGSOcB3+_V~OppKLPu%R(O=ZqD7P@XY)2mEE77 zEka^|Au%d25*LAu=k7hd?BtQ{V~?KVJ+zhAzPaSF$WL`;n_Ok>TW>Gqmdad2jRA%l zqXHu}MqsMEjX~|TwR0cOix2kJSAF))>wAIHyicd=jP#Fm_xc%Y8ljK<`&2{)M*0|m z8Iyr|=w(Y__#6q;6S9YUk%tjpBCN%~g<#P2fqF>;HWJ;H8O_nX64I#Z`MoSNem0+S zMxkfuWRnho+7;oyTKV)=7Fv!$Vt^qrDlifkfyuJ=F;@b@kO)*A*~7g^&&NxY^;UWl z3?>VpT4=z8(Onraj&Q_mRe{@@)9=jJ`fjhgV&nyrNOAvrrCNMPRQP9ByKX~bfFUs| zFcKGm$#F~1-#mXy-5zn1P#5VIUXQ_Pvo5b}UwiYbO-S9}S*x^cQDcCi#;CwZjS-k0 z>(~=WK$u>E>LPo%7kL=rHHNju!U+alAEOVA}|Hkc5#}3FeC!Six1_)yhv-sOPuvqCKC`Q z3!p@3z(mo+7zvKdxsGnpYd7i~I=6qF$D4e(%Ee*Di(S7oj>G^%VpL!x zE&@~HUV5W_iQT?Sr)&DEW?QbRS{Z*Y`r;<%t-{Jv{uTzlK4yR#0}M4r1x9L&z)W}_ z?3yLtu}r;7=Dd+bx`OqBkq_qx+bruZdHNx;dcFFlQ1r2XLn0Lz>0<;IHbUye#?VIv zUT(9*WxOo?at`H0oe>VSJAT>yp$ITaY0#|W%Ol?GA=4b`tjjw=WdRYi>fh8m*+BQ-`~cC7PQ6+vOF21=jCt(3rn zl96Vuv3i2S;|Qn~G+>fwV$1}NYZ50TwXkyLw9Mn}cQ;nsZ_!-++`aJ4iYop_r&n(* zc#s%iNQ?@M#6@6QtnH$epfJ4xWkn;gap*MIA|2Q>y5YK#hu)EI%e@SZ4ikxi=eR>?j1Lhf`@)I8~h zN^!q+xyM|REZp-}`$`-7*uUwO3XJqI0xM(vG1LHoVcrL7JK4j%$ioP)iLAxXM=6gj~rIDe{cTl`ZLSTPemOP5@lY@wY$BrvT(Qgg#!C|NDMF}Mg>OV zA~0RnJ~oVDIjHKrxF~E=*6&Q(&z!q^Ar9`|kyX}`GW`3=P-*9T{&$Sn8 zCOw-Iar9%*Oxw55E}_N%Lyb{^ks2c~Ki08l3ISny1uBy4;a=ongqJ*Pjj0d}x;{{6 zXuu|-i7`_+ZCNGf%*Xm#$h?)#AGoC_>zU#zp0@n6omN?4QqK5j86*Z65~BhmaS@my zYrB|BKo}B%x20hcX`Z@K`Z6ENDMF}Mg>OVBCzG$315E%1kcP2o^dgvCilYScOK^zzRm2f zwfHzWTx#DhXLZyVV5l)FFj8X#7Qx%qrhdy+Y`k%wb#s_@%+YTfpH@uyq zu-Cd9eeB!NP;e!ZJx5*yvMIPUHDYCYU)dYj*Bv6GkVDfk#G1E9w2fU<={_c2i zd4R`c$?=%ZJ3+^nJ72%DZ&gum$NnjTMMw-VBt`{B;v%qBtet-&0b#5Ls*LR6UgRl> z*L2ofxr1OZivjh925c&xM~o8Zrf20uXVnn7$ZCTUeqrtq<*^+f?gxl9-3uaA88B%KSX&V2P}Q;vNFRybsg|vWI(-$2VRxSZmCeVDOv->I)5+BAOU8lOuU&V%0+TCDZFi zJ}=1IB;4elo8zS4BcK$`;Rv?HW=SG3z>pXf7>SF(RQQT=RnV|2qEVnSKWxCI=%i zz>pXf7>SF(thvo^9V)urEU`i6jl;q|4X(~5UD}UUYnSO*2RC_Se7uv38UqY9Mg>M{ zjKDH@N7(c}EV{QfV@r|5`J90Bw*=o-)>;)D%&n=Z{yn>FMn3x3zpiT^$<1n5 zbV%1MY7#RTZrnRP{AW|Cb~6$K42e;Jk+=wK3v0WmCMXPvKpD_TY!9U)Sg=KF$(<50Eu4l{DX=)+6&loiZ7;20PjMNx`Rq%QT zu8i%gdZ6*)^4K7a?o54O|J)UMc~6{WjW%plYSUr1W-1r?TCozu!h6gzn7@5ZitY!?`jMPp*nD>ENN2B=F z@t|bpuzpwmA}BnLfZ9X@HXCi9naeTOetG$DPFP#isDZxSx6@~iu+Po=SfanhJ9?rA ze?{D4BnB7~qXHvw5tuV;gZ)cTm|lT$qLG*eo=40))>|n^Fc^7&@}L3JMB8VyIfa6s z7pnxBZsK|xz=%BO7Uk7t&Lzpdd~+ww|Ar@@UkMTe42e;Jk+=xVjl0KHO2EZY$ffyq z%I&q~58f~1sI0IVZ0^(^ry@FPr0qu37+|O|Dlk%G1lGVhkBucDjMYH-lReyvJSFkc zVXZM)g2Cems1O>kIcQ?ce9jK{b7x+yO|Y#sQ_0nAFKjYc$89-R!8N`$=j36F6B_zR z3@{`{1xDf`uzjrUVj2NqdIc()?BQOdwc@pa^;W7A3`QQH5^2EZp@}iNoQW;6wlWXO z3})EmCyyVc+wTkfFUs|FcKGmd2F)A=pV+7X0n`E{tLgc|S*N5LnpI`eRhdV~L zb@$&$@rK5>HP&u%{G#Y%|E5-?Q1eMrnD>FYMD}nm@-V_nkG1#>2?kvs zs2en3I_R#9N^bRzOwmawzv?)G`SR%gL+vU(~9_ejJ3@{`{1xDf` zFkjX_W=cR95`nr$_HZxK^YPMWy_MDkgUJG@$24FI&|R5DoFilF{6-$iOkO4DWLnYL z+VM%K&2@!dlv=Uix@!w}@^3_9fFUs|FcKGm1#q8tY2V&cuAA5{FB`W|tSqowf7RK@ zC();xrmn5`+x0gcH3k@Jj0%j@7=is^9eXwt5T;k4UXVT9i#&|*TFhEw&IE(54^%A; zm>!xKvxIX%qN=)NFsk2WaExQ&>993b&F+V?wjQ&!mwG*I;%lceBnB7~qXHvw5!hkY zcHv1t7!rZ{MD}nm(pvE{V7-+A1cS)}s16!1eKaw~kfSOx?#Eug10fd+2CocM1lugz zK9(!V8^&;jEVHfyAy8enr5PL_=l~Dpm3;qRBPvs z*Ggd_W278+p~e71jZuM-8Y3_fzT#Kf?SC5tY9{lgxGuZj|9+`?oZX_`d`AZ?BAbKO z&M`zE`!^&~fssB&V8SD>i+zr^c;ptQC$n1LQos3l%@#49%u!8`_DFr_s%(nhgn0}w z6IzLpd5pkn#-5fq(D>MN3Gdhb*cXqqmWt-C)BGbf_5IupzM8*e&k0Um`Ck}*K1L-m z^7AnQ%TiphzIvPxH`iP1=^XdMR~NKKYTw}EOyS*>=kUHsLMW*dzdwe=@cUy_V4VNJ z?3c6krBH&xCnTVH$sX=S<_f%)vi7l41cL`SP~4-2o5jUNo|1SOam>%!U*jFn?(yjD zGrG65)?w}+&yuyvyqkB{Ri66rKEWA@0fxk=z(`yK7S8%eI!8d5_kj|ok=PPE!I@>O zxAHPUVMqi@k_OBG4@zb^N7Q$u$En3PORaW(xs_q2a3KE8^eYeI-4sG>p3YUAxkCks z0fxk=z(`yK7RCMAGkeR2owbe;zL6JByPiuNua({4QYvNo&hGSU*=;XFP-B3h#;CwZ zjS<*H@|O{ZUfBeM4i4khc zBg>EWb~>F5%{KIE8B{oW$JyThN=hCQ0}P2#fswcf>=bLeC?P1!`#@>ZNX!V`l`&?$ zm6ZgAArUA&8n9((V$3Se^u>$Yj{6>)@c(+d({QZz_I==%nEq@+QmC`oCK6p9cTnl)hMcb)rqdb`()|Ns83W36Mqc%B!Z z<6PH$elPd7>(XJD9i|tqZR#cOufE;zeUilFy#rt5@K=!-U`UJ!jN&5LA<0xbxxu|> zaj03mA;l{+nif3Q=WX=E=EEEGX@xDj0ucpj9^;QbIbc%Ih*z>xG-W; zqSo&y2P4UEKAN3hj&F>VxEB*0y%|0Bci(3MqaGue8EskreU%XmKOq4%hsBJ|#d*Y= z3l4uRq0st3S+jtdpj~+juHlqUKaIvn%d?luuG+u-W&zYn7BDlkD{sY}ja)lQHnnBk zYMbuYCVzbvs&v*{@jHZIBpXNQ?=L;v!grej(e8E>ah%neJfZEFfW{DExZ8=*HgC1q_JEaF@oLhLI zNzSjVucL~r$>q&`%#Y5G`TFGy5(5m0F@aHB1Un@;T62Nsti)W8dEC?!G09pFL(YdD z+~8r*Mf>ETKW8;U2Vuql!;CS3(TowyTzc`ijQ&HC^Lq?F+-*ed1>dYLbtY%3q|F`{ z2PAdx_@SSV9{al_GJ#Q#5iGpR1GVG5_Q@*LU$M|jNL9F?*?H!MzF}7)Tn_Y**>gkG zr55`bU^vK`z-S*MSZPn8PuVC!Vc!QTmL73mbV}l0Ao!^qM;IJOKqaz(S)=xOJI*+5 z#lwu}XQR@xGv$uRDa?*F_-5B*@rXg1(o?-u2ky^6Vt^qrCNPSNU}psjb_#*8y#kd+ zkGL;7jBwivzRJ0T!O8>FB^I#xsD0jn+fjYsqRs87(Ze51zS>xlG;{gyi(%24Ph7WH z6&{&!ePkID0}P2Vfl*upJ1;4rA**&Wa*yq>k4haS_RBp+f7UP`A#d`!Pkh6P1F|aG zm@&XGV@zN)V+3;)+{bJPgtZ!|Tl9$gqEiz0LctkZLKqxJK;35nTYwVd7jgPMR-D-W zI{LT7oRaDlo3^{ZE%R<4kr&n~w?^B^I$Y};5(5m0F@aHB1j`bvi&X@|_6pPsdc=KE zwc=hZ_$t>C1}hIxZ&<+WQDXcOPQE?&)u!tAwL9wumEVlN;dQOP_~H|O*pa}hz>pXd7{x`ftCEe!kEZmBG>}@laEQUC<|uWqVcLJ1GlD<8y{?`@Ak?BMmj1wp`mK!GxLPWL%jlfRAa^f!;CS3(Tou+ zP;l)@A`rG$pp;m=$|X3D_~n8#c9u|ReV~+Cz#LIx{0i=u)gHH}hc?;XFKhf>CUHHx zB6wDo{-a0hTAr^6N{HPfgTw$sVoYEZ7s2uc>*6w@up|OCltp4o(XPC+;H%6f6gCT> zv{=BLP-46bS6FF%e)hr3HT-&&v}aFS63Um@EPrBEKd+=%_jE+Bv4z?!Q>4WTLn*DnaAwq#hBSy;bI6#sI^NF@e#H5p1t?xZ5LjV>c?gO@NIe(tLX3Lu3qxzbN%+}*G3vh z3@{|d1V(WY?4e-uzapoJW|EadQU253^2?X6Bx}H!Hx>mb(jbFo9V2r>=K)|vo2@Ml+qEe=4nOlIFcNkoPxvvLt;!| z6c@pY1?xhFKv=7R+DMPMFRE7D9)hp38)2}E0Tsvswi+eIui@%{Kd?I4QSjmJva)+) z+=jPzvx%^r5MMK=U_j4jcOU+|fW!bpVoYEZ7r|ah?$@w#d}F`Y_P4HtU$kVDkDkO- z?Glf}uO4gM9@Xu{CJr+O7-ozKjAo2r>Cy*3R;Bmf*x0lCr-#2J7L}?-!8U z9^tiGZ^Y02=&`?RH4_;17{ScwxAgz}QlX^qg9uQ&=n?lthY@a1!Qmf97_>f6`&hu- z(60PH-1x-NR|{{&x%|17Ul_){{(N`Z*x@4YTAu%Q}ii=>if^}g>AS{VM z-JwU^7ga0nje@Uo8DX$l0QHCkY%NNR_u|y=Z;6whP`oOw(f_o@_#avMZFzGmv=1B~ zKG!-X;&Av%BnB7~V*;bN2=+m8VVk9^l)dSYZ>gi_N6qaw>DKb6zC{Yhq#e43Ei-L6 zFbOjT7-ozKjAo2rkEG9?Jk|fkF%RYNPI3;(S*7z8f?D-YpNm+v$w#;3+C~Kz^w{4e zkqL}?j9}q%nM1jLb-$}pye>pV-7-))_h`%_$=vdb@_pnq7q*ObjK@9(m=>$VXdfe3 zX>XxVnLB~7?<1{Jdc=LvDT#ZN;HT1yFgT8YddC8`9<|SVbDP@=W-6#g>)X7JKh|<8 zSwGO`%yR#(_P11ZI*hWW_|HRPfFUs^Fp7&{&4L9RL?CRhKsC`L?u!m1+&+S@ayMbH z@&NUN1#BZ~pZDeNzuUPXV2NTwRN{^vi(-F<@BL*os_z)C!t=so=M$RU_aHIAkQfsf z#YM0$lE;$1oxC_HX%KfPKkLwi5*dwxya}C~((NSgJvwnfgRV&KhPN zwK_{;Izv}SsnEl(J}$#Zm=Qyvln42dy; zQCtN3E$Le1>Clp@6LZrrI85Dea~K| zkMLF2yEG)lZhl0yhW*X52c2)bIQ&SGF%6kHRC8~QDthei_R0iCJw`C$ziZ_h!LaWG zHG;*A`Qkj{0|kdapHOIhpmbTl{Lrp^5O-AL*V3kj^7`VVhN}XS`^(j=_n)wFs)bMN zx`TRFPP--}F~E=*6BxxsFkZ079uo>nB2bf9B<7FW=Ys`bM<;emTj1uFwb8B@n9rqn~ zH|R4wFn3qyw;H267S(7=L=Tk?5=l5sx;_Gl0fyJe1V(WYOjdMv=Aod53887Zu{ANT zRn+F3{cDQKLEN$XyP}JS9cNhJO?TOj%|FDE#OKln*`PzG&gWy+g2Idl3ek1yEa9z_#E7=XY{D&o3{$^_?q7 zlsSD@wSIdaErWx9daKT=+`LKdS(Vp~TqFh<5@Q0RxCo{ocvcQ15PlE=Dx4m1U$j@? z-X-`dH3)<46{r{%ux&WO`Q4ne-oTeB+ztan_bt`~j0270pPw&Y{i{YvFJ{`~7}NQ2 zNDMF}#so%j5v-fY+Tgg{_e-i%#-xvXyrf6^vhTV#Wt`MEd|4WDscLSs+9J#tV3;u` zFq$!f4d^5^Gh+#apOAn$PLH@RT6l1W3eMPM!eFxi>NE@34wM)lMt@o4dILUfUjOhZ zS=;Z8{a`!R!OLj>YiF6y6?t{qADl-ZF~E=*6BxxsuwH_7F`Gd6K?JCa^oaYSYQ-Hc z_$sXkgY6Zl92T%$C^3Ey*Jo(ps(oue)x^78d!)8_k#V-sLObVmHNoBVUzznA|2`gx z0fxkwz$h+)^%D)#og!6hq+&3x>*{=E)tp?v2en_Ndi5M)srludyo*OYW(+XQ7!w%H z7{RnU`P~fK^?78=*ObFoW>*vq*s~zV%OdsF$RR&p$_^j(`?)E4?C%dEOkmVw1T&-c z@4v4_1jCPRK;5H9+!q~2xc3SUzYAf|`anHn0SiUD@)6vwnpV~DavihFwkM9~Y~i>4 z-g9N~iuvvLbJV_@&O2nIio^gzVoYEZ7r|5od+Z+qVMzq4oE~vs=zO{(1z)8vVX#>M z^_~SR9PP?SajsXbd(OVp^ZB*7=G}(#o*i^5D{R`K=vk{Houy=?HP`})0fxkwz$h+) z4H7L;SBy2cvX`H4J^xwy`&m*G>qpIBS#VWV6y#gCU~F$0%ot#pF(xpYF@hNhu02}` zgzXim&-943RvKn%=Kn^!+NdC7P7Z?);K%-v5nSiODg{7+{z&CNP>Yf|+;vpz=U2 zHuiPIxx3Hzba&kHrbyL6c1YJ{S`XvR`mJaxj6;w8T@snVsK*EvE^i#%KJzmFPoFQ{ zeucfedAHEXX4)CW(N(eQlT!LsOg&nNeGD)h-h31pS#*R$@+RsuL_)}*(Y&l{F{Myl6qw89mqKP zPd_9E7!qRwqqqpBDOj*K35D$ysL?DEi^h4x#|pm6LPBBX0ct!8*nZSLe~8N-`9<_l zP40L5R*&$XA-@K_*l^~Q`jf*gmg6c0#@XLCMPh&0m_jDEEXlkAK`RbWWLWDp{BJk z{aIRLP_^@w{EgPV-CoB_yehkPcZ^9X5(5m0F@aHB1e+krRf|7&z++%nmqz)bWUr9N zMyZwUCHwBk$Hh8E4~;6mh8Y74GsXl)Ge$7aPWMI`AHVi|JFjBYzewHC@b`P|JLWDA zZXWPxE4Ve@#&SG*?CPN0QUo{?g(D#mB;0+s<5o13| zK7G?ExiK6w1{h|H35;fpV1a^b&kzD(dj%?z9&ulE7~xJ7oH0$pp!I<|%mQ{4CB`Rl zqg(dfC^FPZf7Lo{tMw1duGw=pzV?>9_vFhcm*&oYKAb>efFUs^Fp7&{GX?8HpFmg= zfjU8txG$Z!Spb#J0(KlF#wT+Z%@0}6aE)Eoav}1-4D+naJx6EeJUiNK zs9jLga{8U?8YBi75@Q0RxCk~^^kJH!*Tu12>uz$YGy2(OO-jvGJ$H6)r*`Q9t5X-K zIUmG~0frf40;3rt*xpX+S<8AEc2Wy_@cqQ3mtZK?uvP>0ogQ&tRIRwv1YczoVX%t<^@j!Q zBub1w%bl*0A2Tnpy|TOU!0jKL$J#3`svTnRcOkmVw1T&-mjNreoID+8^5uiGE z`|tnn|BwHb4kO&@g2SIoAhbSE-C4j+qh0xPoN7MFRs_5@+2e%7!qRwqqqpRM6k!s5eQ2nQ2kjXb_TW2X9&K^tAxU40hBrmSQ^@u zKhF()*m(<=}OK9wjtg=Kc%$7=B~qx0frf40;3rtSdQS@bDKceUV+kP z@hZ>aJmN11&e%gjq4j~9$O4v*65}&Dsgmbrl?PLz7992Lq(8Imu!V>5sQB#6!Ld~m z5;qP@e=)^rUc_a-(kH;N~%zLpDiSYzR(?!HfZh8Dj#Y86()EPHJZpK6_<<9;BpRHSt%U z`N4I@@lW6E&-XFE`*>lc*R#9mvA;_q6BzXv!NL_}FYvoR4d3uKKr7BuZBKc9nC~(Z z?Y6hFdf&zcNR0V?8v7VvILMj6Xdfe3sj|=x)kq-h`#{;V82hW#sI^NF@e#H5$uiNKGuUkSgU~wrbpZtoszh-1!qi^FgT8Y3S|Mi zgc9SgadKfg%88TG+{(WewJkn5Y+%3D`yXE(WGLAf+qiUhpA0P|1{e}!0;9MH<|SAc z!wH1#6{!96i2I^y#eH4yRq7B1D-TddS-`HK#P}Or^Rd10PTAFQ0X2^^+mB^f&b!_3 zb-3A==%(oDSC?4%uSQ~kAu%Q}ii=>rB9+Pc1Cyssy*l1$?)QC75v9^4Yacls9lgHD z|90KFatjH}7+{z&CNP>Yf_?1NWFNg~;6+c1_+w+wI>hR==SWVzyUwsEY)9R2%_kkM ze(15k+ba_o^%%j51iywdq@=L#19g%fabI*8;m#2p{+Wb9>jQOx1uPrw%HQPjV!f4S zwc4(!HtLq}s-$J;$lK)&t<&Mje|b+jv=%XK>NPBJd>z{MobZG(ay_Buap%O&$Ws&;J_3nZ`U zy&GVN!~jELOkflj!9qmeokEAMu}mG6aBIrWOV{<2Ti%q}?f>n1d*ayGEq!*@7d3;Q&-OWC8igllQ>aUpIza~B1G+*>~I`4qQ z07GI-U=$a@c8k&tI;4gNRRlWKkBGEN`lQd)t2{+0EQvt%W&yi{gOV@g zF3xy&y=$Y!{A7p1H5Tu>`4#rpXd7{x`fD3Q5;;)9#~gg$4P1i}v@K&i2K zmHAjL`1^u0c7sqjz=0ac0(KWA#y{Xowm!Rp!HT^dP@7v_7c*4Z=U7o#pT2%}Z0}P2Vfl*upJ0!BdzhLx7LtEXA zA=CW#biA9id+E5ulQU}msSS*H+Tb%M6f*`GW{e4pW{hB3GEPQwR@qorb(Kvr8tNav zzhOpGdA{?ZA-1yHob;7zjvhvj{oVJOz^KOvW=4Pf?0;Wn1jA2AK+Rz>V}&@6_(y`n zUrQ*oK2X*yVE56k{9{f_KCIiFCq37y4_bP*>dH3d1vdPY#0#OC`38?xa%Fu?kQiV{ zj0ue5BG?hZ9{WTnEQvrZW|7zf)IR@2@KydM6gCT>R-1V;~T%3M=o7NWc zt}ZZVLczn1Bx&8b538G3^N88W{e4pW{hA)f@_b6K-gY^T1$_(FFK5HKNFlW1;U{9 zf%0PkdxR3>pL2cOwR%6Vy;vd}mVWi3qs5u5p5KZUb5}*Sg_o|6dF-f-!~jELOkflj z!IA~*q7Q+vBm%XK9&uk(t+-zZzRE#_!Da!}UKX$?C^5d6+qkUhL_>2!x7^a|s8uWN zVnvPWRl6_6RSw%VueIosi~T14iygmy_O(>$VQw>|Bz;Za z;6*z+Hohn%&``*-x%-zAX=jCzb<;a%6?E-art%j@fesxGI^bj=GE<}V(8M|t=Y&$5m@ou{%^ z*vA0FLCyq5`xwDW`wM-_MiC18K2Wjri2I^b5_gHrg=9E9` z^Ldf{AK$duvY$_8Jo6G&cjZB{cfMvcm09H07GI-U=$a@&I%Un6ary;1uBgm zabI*8;VueiO zx!|i@M;NR;K)qoBD@BR%72MQ+7DumMsMq~K%&-!RiPI+ae5N)$F5!w@wy6BzXv!HNXG zhVmyE_I;r0=@IuuhY{{Kg2TU^Flc?CzOsP5M!WKFxjMs9lkH1Cd$g5F9hFP(=lW;5 z!N>6%Z6%~q3l#jjr&=K~z>pXd7{x`f8-hI+K_D!NK(*5&?u$AfcctK~JVY357C?3C zA#N7^i_~(oD__N>m_G_w)^53F&HA)?K64G%AKB(7w}1DA_G#b=sbMg?E?kkQ`cvpU-1cfBqW0}P2Vfl*upD-?D2 zi#_L~$(czwzW3YMef8BL3dvQ?k@eNp(Z1amJx{-d83PP6#so$)MzFmyF*(yETx+*} zFaIPRn?3B;iP=4$6#uHzD$yRxt>`w>H5xtkcS&RdqaGueyyDA{)+&?2ts18X_FjJY zf@$V0iw6=*q6To5obtFXt)F$Uj{$~*oC%EfF@lw$d6fHmUvQVU8>8_37-0B*j0udsA0t@CM4@B(0ip1N2v7zrK9yBC!TI-sbx}+x zoRdIJV*z`I^N6qGexLq!q+T~X|9dC9EB5_knU^@hWR^g7Xc6GsY7N=Oj>W zEMV_ZVtgZ)W3^(>{!bQ3H97ZoKMcEGdi8>ZdygB5HdnJEEoSeTz7B~2hQye_C@z8( z3)Y1Ufv{EswUHiiUsSEQn*?8FH^N{S11gXOtR5xCH*+^ntnxP2im<6tbFTHt3=9bg z7^QwTuJ^%MyCq>;Quj3=F~E=*6Bxxsuva2IuRF`iSKe{Y-Ei1AvH5J)*;x-?={xKz zoDoobW>{?S56l=~m@y_WnlXZ<%RKy0U~TlNWKQMFE+Mgn2WQ_KoSxrvdXK}^59YpU z&B^?L9{amiGl5Z$5zLH!8UDX76-o*}hyb;V9&ulE7~%dXIQ+v1gVqOX9}8Fm+Liyr z4a{!4IIU)1kDa+v@#=Y3qO|9<-Wstqz+`E!99!KB(VTBuClWisty#qxpEBa6SCR9@lG z&0c4i`^3acI!FvKB*p|raS^Oa;oGd7PfXnmlvS-?J`#Q1OAr#o4S zyBDuCIi&Abcs_nlr~U!a_BP?C7R?&hrKI(bp(PRn42dy;QCtM86|4(80%1u6>JB~P zzNlJpe;0g}%Ls$b0;oqUV4qQ9dE4wPjx} zNbXxDLSld+F(xpIi(nr_quP?*4vt7XKj4h9#N`v0S5>=AkRK;o=H1&SuDU^HU{dn9A3V>HG*Xh3(R&1zALWKa7`A`=+( z7{S67Hx$YI40jAO{qnkx!W79C&rqucKTEcpR+fJ-(LL91ei`;Lz_eH;M*A4SN(Tsi z%G?QreIIF+(j)GRPD$K91V5Etgu!tH)H@ciuc&?gC%4yPUHv~>+`lfds(wFawOr4! zLp8OETkT5~tGv=IcC9Q$Vt^qrCNPSNV9kOB8$=*%uRt}?Bkqe1Biz3PU*&GXVC4bo z2MgGD)IR^4JJqks+~;$*VLlr-n)!Q%n%G`?FBo{_#L#(MwfjNThIOGm!;pQbbgGX@xDj0ucpj9_mB_pxXK zVXgib)l=LPM*r%$1qUVHDmY_D2=(vgN~kU@U_Ve|d>a=u+dS6ju>8c_rIsDRXZ5<9 zIkb0jZ&qlOem+j?qvA>t5(5m0F@aHB1Zxqji&O$(dj+Z|i^P7SUHNvwS9zXLSb2aN zzykIQCC2mI=BHhQpZnWgUY?Wwc?&X-1m#`zQQkKxE>sw{LfUzE?LGGX@xDj0ucpj9?#S>>g}V zx$UQ-(PVMPC_kVy^j5LPm^JOspN&<~{1_d-!vQ_^cY9?5qaGtzk>J-**9eAvAE*&5 zX6!f4BmR%z@aGc>tq+tg3s@`KmG9tuUIi!hvP<;%E^)2qm4n;QpUtwPhp%v5VUQI# ze^K2B6(j~25@Q0RxCq7z_Sj=WVMzpP5{tyzQ2V@uq|oX2icr`rfSSbu){b`NImzWC zf9jn~vrD&-nX_@rhNrj74!*3|pFQ`e=Y*E1og+hDA~C>_7!w%91(=l7vpy3`-Wj+n zoE#Y^rxWti;dO|id2L#Y&qzzhRcoGY#f$-l8Dj#Y86(&q!L_HFP}p99vSjfpd7MYQ zq~MG-6AG;l)It`pKPWL?BsuTSj^ljn-r}|1T+fK_T*}6T#{s@+8&!jCx7||Q8efOR z07GI-U=$a@q@{#Dl|Kn3@jsL^i^Mw6uDq1stKpP-7BC4(DluMKQgN4_%1ka` zc{!K!)9Pe~W!8!-ugcEO2+(-=@RwCU&8et=5~2hsc`$|!d{Ewci+=WIJsV` zqL+5-f)2 ztuEsGF~GD~!RY%jf@K)__(bI2%#duA*Hg>*=-0{R))jX?_~h904<^Rj`Pnay#P5#* zhTk7!l34D)Fel#~b8mQz?C0g}tP|8$H_7|6alImVBJ?|d}3xjU+%AO8F?!0_jf zF@c5r3%m8MevR}R%eOWDW7R(_**I)`Q0WIt#|X)W3p27LM%Qfdvy$ubKN$U!35)~m zPw;k5;)_C;erAI<$Lx!qV{m0y*Cmr5^=UYNq3Pv^?G=B9XsE7~qw4=RGx{eB+P^Rf IIZ28C0|YG$$p8QV literal 0 HcmV?d00001 diff --git a/librustzcash/src/tests/res/tree16.dat b/librustzcash/src/tests/res/tree16.dat new file mode 100644 index 0000000000000000000000000000000000000000..bde2e74d45daade78a0124c7336fd2283cd702f3 GIT binary patch literal 2352 zcmZQzzz?{A(jq{d2gDWll~P5Pk&%s%Iif%XazG4nP7@);RFG$4V&Am%Q!8us!f65< zTDRWWtzORjIQf~y6aQuV4nMuzZna(-6iOf`fkKHMPGV%@CFC)ApaKo3b9x9Vrh+^( zGY274G=U0?fEeVQX@nG0L7s($GjGAf8&h`dIqbMPB=~jJ4)tw9^)s(0E1!9n+L8Oi z{oy81D1n>=iZpsSiJ3*PUwQdaL&27_s|rdQLr?F^Gd%Ts_1(M2GCE@Bo}B2ep94xu zASZ#+5xAL#Rf#!UXGEPdU{Nm@voRExwo7Y$^ZK;e4^Sw9oCFFbdN_%d4O9~11@1uE03ZfA zXA54H)RAOo=OJWJAW%UR5QChvkC0+2$a8S;9%gYbmCAE`7_2DCeOY?q)76D1UP$U( zznoLyl5^MU)MHR6ft&;iC3-lCokQ~I)YI-Sc^~p!P2+Psf2Hxmmaw|Y6AF5>K1Y2% ze`#lVBPcC_oCHcs^l%a@hu$@j_$hO4UAlRwG+9jL%{AkVp?0@tO}ZL-{Mv8!WXUa} mpmGW1Bv83T4<|8l_yBFf3!;ItDL@Qz&I!CKsUykB$p-+L*^;aP literal 0 HcmV?d00001 From fb8c73c9500de06c68184e6056d48de1400fa677 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 5 Dec 2019 11:06:26 +0000 Subject: [PATCH 305/330] Use iterators in construct_mmr_tree --- librustzcash/src/rustzcash.rs | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 0bfd5ad..16acd87 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -1199,31 +1199,17 @@ fn construct_mmr_tree( ) }; - let mut peaks = Vec::new(); - for i in 0..p_len { - peaks.push(( - indices[i], - match MMREntry::from_bytes(cbranch, &nodes[i][..]) { - Ok(entry) => entry, - _ => { - return Err("Invalid encoding"); - } // error + let mut peaks: Vec<_> = indices + .iter() + .zip(nodes.iter()) + .map( + |(index, node)| match MMREntry::from_bytes(cbranch, &node[..]) { + Ok(entry) => Ok((*index, entry)), + Err(_) => Err("Invalid encoding"), }, - )); - } - - let mut extra = Vec::new(); - for i in p_len..(p_len + e_len) { - extra.push(( - indices[i], - match MMREntry::from_bytes(cbranch, &nodes[i][..]) { - Ok(entry) => entry, - _ => { - return Err("Invalid encoding"); - } // error - }, - )); - } + ) + .collect::>()?; + let extra = peaks.split_off(p_len); Ok(MMRTree::new(t_len, peaks, extra)) } From 8ad33e50a6d6e2bacbfce43b08398b1f942b379d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 5 Dec 2019 11:09:55 +0000 Subject: [PATCH 306/330] Use explicit sizes for pointers to arrays in FFI --- librustzcash/src/rustzcash.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 16acd87..d0ac6fb 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -1228,8 +1228,8 @@ pub extern "system" fn librustzcash_mmr_append( p_len: size_t, // New node pointer nn_ptr: *const [u8; zcash_mmr::MAX_NODE_DATA_SIZE], - // Return of root commitment (32 byte hash) - rt_ret: *mut u8, + // Return of root commitment + rt_ret: *mut [u8; 32], // Return buffer for appended leaves, should be pre-allocated of log2(t_len)+1 length buf_ret: *mut [c_uchar; zcash_mmr::MAX_NODE_DATA_SIZE], ) -> u32 { @@ -1269,7 +1269,7 @@ pub extern "system" fn librustzcash_mmr_append( .root_node() .expect("Just added, should resolve always; qed"); unsafe { - slice::from_raw_parts_mut(rt_ret, 32).copy_from_slice(&root_node.data().subtree_commitment); + (*rt_ret).copy_from_slice(&root_node.data().subtree_commitment); for (idx, next_buf) in slice::from_raw_parts_mut(buf_ret, return_count as usize) .iter_mut() @@ -1300,8 +1300,8 @@ pub extern "system" fn librustzcash_mmr_delete( p_len: size_t, // Extra nodes loaded (for deletion) count e_len: size_t, - // Return of root commitment (32 byte hash) - rt_ret: *mut u8, + // Return of root commitment + rt_ret: *mut [u8; 32], ) -> u32 { let mut tree = match construct_mmr_tree(cbranch, t_len, ni_ptr, n_ptr, p_len, e_len) { Ok(t) => t, @@ -1318,7 +1318,7 @@ pub extern "system" fn librustzcash_mmr_delete( }; unsafe { - slice::from_raw_parts_mut(rt_ret, 32).copy_from_slice( + (*rt_ret).copy_from_slice( &tree .root_node() .expect("Just generated without errors, root should be resolving") @@ -1334,7 +1334,7 @@ pub extern "system" fn librustzcash_mmr_delete( pub extern "system" fn librustzcash_mmr_hash_node( cbranch: u32, n_ptr: *const [u8; zcash_mmr::MAX_NODE_DATA_SIZE], - h_ret: *mut u8, + h_ret: *mut [u8; 32], ) -> u32 { let node_bytes: &[u8; zcash_mmr::MAX_NODE_DATA_SIZE] = unsafe { match n_ptr.as_ref() { @@ -1349,7 +1349,7 @@ pub extern "system" fn librustzcash_mmr_hash_node( }; unsafe { - slice::from_raw_parts_mut(h_ret, 32).copy_from_slice(&node.hash()[..]); + (*h_ret).copy_from_slice(&node.hash()[..]); } return 0; From 573510115d2c3c921e1fb6cd12b093a8fa89b012 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 5 Dec 2019 11:11:32 +0000 Subject: [PATCH 307/330] Clean up remainder of MMR code --- librustzcash/src/rustzcash.rs | 2 +- librustzcash/src/tests/mmr.rs | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index d0ac6fb..e843795 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -1352,5 +1352,5 @@ pub extern "system" fn librustzcash_mmr_hash_node( (*h_ret).copy_from_slice(&node.hash()[..]); } - return 0; + 0 } diff --git a/librustzcash/src/tests/mmr.rs b/librustzcash/src/tests/mmr.rs index 6e40f7f..6c57632 100644 --- a/librustzcash/src/tests/mmr.rs +++ b/librustzcash/src/tests/mmr.rs @@ -10,7 +10,7 @@ struct TreeView { extra: Vec<(u32, Entry)>, } -fn draft(into: &mut Vec<(u32, Entry)>, vec: &Vec, peak_pos: usize, h: u32) { +fn draft(into: &mut Vec<(u32, Entry)>, vec: &[NodeData], peak_pos: usize, h: u32) { let node_data = vec[peak_pos - 1].clone(); let peak: Entry = match h { 0 => node_data.into(), @@ -24,8 +24,8 @@ fn draft(into: &mut Vec<(u32, Entry)>, vec: &Vec, peak_pos: usize, h: into.push(((peak_pos - 1) as u32, peak)); } -fn prepare_tree(vec: &Vec) -> TreeView { - assert!(vec.len() > 0); +fn prepare_tree(vec: &[NodeData]) -> TreeView { + assert!(!vec.is_empty()); // integer log2 of (vec.len()+1), -1 let mut h = (32 - ((vec.len() + 1) as u32).leading_zeros() - 1) - 1; @@ -39,8 +39,8 @@ fn prepare_tree(vec: &Vec) -> TreeView { loop { if peak_pos > vec.len() { // left child, -2^h - peak_pos = peak_pos - (1 << h); - h = h - 1; + peak_pos -= 1 << h; + h -= 1; } if peak_pos <= vec.len() { @@ -51,7 +51,7 @@ fn prepare_tree(vec: &Vec) -> TreeView { last_peak_h = h; // right sibling - peak_pos = peak_pos + (1 << (h + 1)) - 1; + peak_pos += (1 << (h + 1)) - 1; } if h == 0 { @@ -67,7 +67,7 @@ fn prepare_tree(vec: &Vec) -> TreeView { while h > 0 { let left_pos = peak_pos - (1 << h); let right_pos = peak_pos - 1; - h = h - 1; + h -= 1; // drafting left child draft(&mut extra, vec, left_pos, h); @@ -85,8 +85,8 @@ fn prepare_tree(vec: &Vec) -> TreeView { } } -fn preload_tree_append(vec: &Vec) -> (Vec, Vec<[u8; zcash_mmr::MAX_ENTRY_SIZE]>) { - assert!(vec.len() > 0); +fn preload_tree_append(vec: &[NodeData]) -> (Vec, Vec<[u8; zcash_mmr::MAX_ENTRY_SIZE]>) { + assert!(!vec.is_empty()); let tree_view = prepare_tree(vec); @@ -107,9 +107,9 @@ fn preload_tree_append(vec: &Vec) -> (Vec, Vec<[u8; zcash_mmr::MA // also returns number of peaks fn preload_tree_delete( - vec: &Vec, + vec: &[NodeData], ) -> (Vec, Vec<[u8; zcash_mmr::MAX_ENTRY_SIZE]>, usize) { - assert!(vec.len() > 0); + assert!(!vec.is_empty()); let tree_view = prepare_tree(vec); From 583a04b4de4fa0a042f0b55ddaee0a794ba29b34 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 5 Dec 2019 14:23:59 +0000 Subject: [PATCH 308/330] Pass array references correctly in MMR tests --- librustzcash/src/tests/mmr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/librustzcash/src/tests/mmr.rs b/librustzcash/src/tests/mmr.rs index 6c57632..aca4766 100644 --- a/librustzcash/src/tests/mmr.rs +++ b/librustzcash/src/tests/mmr.rs @@ -181,7 +181,7 @@ fn append() { peaks.as_ptr(), peaks.len(), &new_node_data, - rt_ret.as_mut_ptr(), + &mut rt_ret, buf_ret.as_mut_ptr(), ); @@ -220,7 +220,7 @@ fn delete() { nodes.as_ptr(), peak_count, indices.len() - peak_count, - rt_ret.as_mut_ptr(), + &mut rt_ret, ); // Deleting from full tree of 9 height would result in cascade deleting of 10 nodes From edcd884fe89ffd0eefa73668095b883c61303291 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 5 Dec 2019 14:24:31 +0000 Subject: [PATCH 309/330] Simplify short array copies --- librustzcash/src/rustzcash.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index e843795..3a6aa5d 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -1269,7 +1269,7 @@ pub extern "system" fn librustzcash_mmr_append( .root_node() .expect("Just added, should resolve always; qed"); unsafe { - (*rt_ret).copy_from_slice(&root_node.data().subtree_commitment); + *rt_ret = root_node.data().subtree_commitment; for (idx, next_buf) in slice::from_raw_parts_mut(buf_ret, return_count as usize) .iter_mut() @@ -1318,13 +1318,11 @@ pub extern "system" fn librustzcash_mmr_delete( }; unsafe { - (*rt_ret).copy_from_slice( - &tree - .root_node() - .expect("Just generated without errors, root should be resolving") - .data() - .subtree_commitment, - ); + *rt_ret = tree + .root_node() + .expect("Just generated without errors, root should be resolving") + .data() + .subtree_commitment; } truncate_len @@ -1349,7 +1347,7 @@ pub extern "system" fn librustzcash_mmr_hash_node( }; unsafe { - (*h_ret).copy_from_slice(&node.hash()[..]); + *h_ret = node.hash(); } 0 From f1619f896caa5e021c92e5c57fcea8f96326a474 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 5 Dec 2019 14:29:08 +0000 Subject: [PATCH 310/330] Clearer variable names in MMR tests --- librustzcash/src/tests/mmr.rs | 41 ++++++++++++++++------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/librustzcash/src/tests/mmr.rs b/librustzcash/src/tests/mmr.rs index aca4766..4107a75 100644 --- a/librustzcash/src/tests/mmr.rs +++ b/librustzcash/src/tests/mmr.rs @@ -10,8 +10,8 @@ struct TreeView { extra: Vec<(u32, Entry)>, } -fn draft(into: &mut Vec<(u32, Entry)>, vec: &[NodeData], peak_pos: usize, h: u32) { - let node_data = vec[peak_pos - 1].clone(); +fn draft(into: &mut Vec<(u32, Entry)>, nodes: &[NodeData], peak_pos: usize, h: u32) { + let node_data = nodes[peak_pos - 1].clone(); let peak: Entry = match h { 0 => node_data.into(), _ => Entry::new( @@ -24,27 +24,27 @@ fn draft(into: &mut Vec<(u32, Entry)>, vec: &[NodeData], peak_pos: usize, h: u32 into.push(((peak_pos - 1) as u32, peak)); } -fn prepare_tree(vec: &[NodeData]) -> TreeView { - assert!(!vec.is_empty()); +fn prepare_tree(nodes: &[NodeData]) -> TreeView { + assert!(!nodes.is_empty()); - // integer log2 of (vec.len()+1), -1 - let mut h = (32 - ((vec.len() + 1) as u32).leading_zeros() - 1) - 1; + // integer log2 of (nodes.len()+1), -1 + let mut h = (32 - ((nodes.len() + 1) as u32).leading_zeros() - 1) - 1; let mut peak_pos = (1 << (h + 1)) - 1; - let mut nodes = Vec::new(); + let mut peaks = Vec::new(); // used later let mut last_peak_pos = 0; let mut last_peak_h = 0; loop { - if peak_pos > vec.len() { + if peak_pos > nodes.len() { // left child, -2^h peak_pos -= 1 << h; h -= 1; } - if peak_pos <= vec.len() { - draft(&mut nodes, vec, peak_pos, h); + if peak_pos <= nodes.len() { + draft(&mut peaks, nodes, peak_pos, h); // save to be used in next loop last_peak_pos = peak_pos; @@ -70,25 +70,22 @@ fn prepare_tree(vec: &[NodeData]) -> TreeView { h -= 1; // drafting left child - draft(&mut extra, vec, left_pos, h); + draft(&mut extra, nodes, left_pos, h); // drafting right child - draft(&mut extra, vec, right_pos, h); + draft(&mut extra, nodes, right_pos, h); // continuing on right slope peak_pos = right_pos; } - TreeView { - peaks: nodes, - extra, - } + TreeView { peaks, extra } } -fn preload_tree_append(vec: &[NodeData]) -> (Vec, Vec<[u8; zcash_mmr::MAX_ENTRY_SIZE]>) { - assert!(!vec.is_empty()); +fn preload_tree_append(nodes: &[NodeData]) -> (Vec, Vec<[u8; zcash_mmr::MAX_ENTRY_SIZE]>) { + assert!(!nodes.is_empty()); - let tree_view = prepare_tree(vec); + let tree_view = prepare_tree(nodes); let mut indices = Vec::new(); let mut bytes = Vec::new(); @@ -107,11 +104,11 @@ fn preload_tree_append(vec: &[NodeData]) -> (Vec, Vec<[u8; zcash_mmr::MAX_E // also returns number of peaks fn preload_tree_delete( - vec: &[NodeData], + nodes: &[NodeData], ) -> (Vec, Vec<[u8; zcash_mmr::MAX_ENTRY_SIZE]>, usize) { - assert!(!vec.is_empty()); + assert!(!nodes.is_empty()); - let tree_view = prepare_tree(vec); + let tree_view = prepare_tree(nodes); let mut indices = Vec::new(); let mut bytes = Vec::new(); From cca16702487c2a42b09e3cae96ecc3cf9415e5db Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 5 Dec 2019 14:33:03 +0000 Subject: [PATCH 311/330] Clarify length of return buffer for appended leaves --- librustzcash/src/rustzcash.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 3a6aa5d..6dadf67 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -1230,7 +1230,7 @@ pub extern "system" fn librustzcash_mmr_append( nn_ptr: *const [u8; zcash_mmr::MAX_NODE_DATA_SIZE], // Return of root commitment rt_ret: *mut [u8; 32], - // Return buffer for appended leaves, should be pre-allocated of log2(t_len)+1 length + // Return buffer for appended leaves, should be pre-allocated of ceiling(log2(t_len)) length buf_ret: *mut [c_uchar; zcash_mmr::MAX_NODE_DATA_SIZE], ) -> u32 { let new_node_bytes: &[u8; zcash_mmr::MAX_NODE_DATA_SIZE] = unsafe { From eed7e8199faf16560b158f3d1dadd06c997d8cf9 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 3 Dec 2019 15:15:13 +0000 Subject: [PATCH 312/330] Pass bellman's multicore feature flag through to zcash_proofs This enables someone using zcash_proofs to disable multicore. --- zcash_proofs/Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml index b9de0f7..a887984 100644 --- a/zcash_proofs/Cargo.toml +++ b/zcash_proofs/Cargo.toml @@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0" edition = "2018" [dependencies] -bellman = { version = "0.2.0", path = "../bellman" } +bellman = { version = "0.2.0", path = "../bellman", default-features = false, features = ["groth16"] } blake2b_simd = "0.5" byteorder = "1" directories = { version = "1", optional = true } @@ -25,8 +25,9 @@ zcash_primitives = { version = "0.1.0", path = "../zcash_primitives" } rand_xorshift = "0.2" [features] -default = ["local-prover"] +default = ["local-prover", "multicore"] local-prover = ["directories"] +multicore = ["bellman/multicore"] [badges] maintenance = { status = "actively-developed" } From 0aa127d7b110ad862a0fb13171900cb085eb50b8 Mon Sep 17 00:00:00 2001 From: zancas Date: Tue, 3 Dec 2019 19:43:11 +0000 Subject: [PATCH 313/330] refactor to manage test code and data in separate modules --- zcash_primitives/src/transaction/tests.rs | 5312 +-------------- .../src/transaction/tests/data.rs | 5686 +++++++++++++++++ 2 files changed, 5692 insertions(+), 5306 deletions(-) create mode 100644 zcash_primitives/src/transaction/tests/data.rs diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index 2dbf07e..392144b 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -5,151 +5,12 @@ use rand_core::OsRng; use crate::jubjub::{fs::Fs, FixedGenerators}; use super::{components::Amount, sighash::signature_hash, Transaction, TransactionData}; -use crate::consensus; -use crate::legacy::Script; use crate::redjubjub::PrivateKey; use crate::JUBJUB; #[test] fn tx_read_write() { - // TxID: 64f0bd7fe30ce23753358fe3a2dc835b8fba9c0274c4e2c54a6f73114cb55639 - // From testnet block 280003. - let data = [ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x01, 0x8f, 0x64, 0x29, 0x96, 0xdf, 0x1e, - 0x93, 0xa6, 0xd7, 0x9a, 0xe5, 0xba, 0xae, 0x34, 0x93, 0xf4, 0x23, 0xca, 0x6c, 0x82, 0xe9, - 0x9f, 0x3e, 0x8d, 0x95, 0x24, 0xfa, 0x78, 0xbc, 0xf1, 0x61, 0x67, 0x00, 0x00, 0x00, 0x00, - 0x6b, 0x48, 0x30, 0x45, 0x02, 0x21, 0x00, 0xb6, 0x5e, 0x37, 0x22, 0x97, 0x07, 0xd9, 0xcd, - 0x48, 0x39, 0x40, 0xd2, 0xab, 0x8b, 0xdc, 0x0b, 0x74, 0xb1, 0x2d, 0xda, 0x66, 0xd0, 0x2d, - 0xbd, 0xf3, 0x6f, 0xd3, 0x83, 0xb9, 0x60, 0x2a, 0x51, 0x02, 0x20, 0x4b, 0xe7, 0xfd, 0x7a, - 0x39, 0xa4, 0xa4, 0x2d, 0xff, 0x07, 0x1a, 0x5a, 0x2b, 0xc5, 0x1b, 0x49, 0x2d, 0x33, 0xf0, - 0xbc, 0x39, 0x4b, 0xc8, 0x78, 0x61, 0xe1, 0xbc, 0xaa, 0xf2, 0xba, 0xc9, 0x3b, 0x01, 0x21, - 0x02, 0x48, 0xe7, 0x8b, 0xdc, 0x18, 0xf1, 0xa8, 0x31, 0x10, 0xc1, 0x2e, 0x40, 0x08, 0xb7, - 0x64, 0x02, 0x69, 0x61, 0xb1, 0x68, 0xfe, 0x8d, 0x5a, 0x8d, 0x94, 0x7e, 0xfe, 0x6a, 0xf8, - 0x3c, 0xc8, 0x8e, 0xff, 0xff, 0xff, 0xff, 0x01, 0xf0, 0xf2, 0x70, 0x18, 0x02, 0x00, 0x00, - 0x00, 0x19, 0x76, 0xa9, 0x14, 0xa2, 0x84, 0xd0, 0x51, 0x1d, 0x0e, 0x52, 0x0d, 0x36, 0xf4, - 0x44, 0xa3, 0x6c, 0x10, 0xbf, 0x54, 0xb4, 0xb0, 0x17, 0xcd, 0x88, 0xac, 0x00, 0x00, 0x00, - 0x00, 0xd7, 0x45, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0xca, 0x9a, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x13, 0x31, 0xa3, 0x05, 0x9e, 0x66, 0xaa, 0x6c, 0xa9, 0x7a, 0x62, 0xf5, 0x6e, - 0xa2, 0x34, 0x20, 0x75, 0x68, 0x56, 0x6f, 0x69, 0x71, 0xb3, 0x72, 0x2a, 0xe0, 0xdd, 0x82, - 0xc0, 0x03, 0x99, 0x69, 0x2a, 0xac, 0xb5, 0xfb, 0x12, 0xac, 0x58, 0x0a, 0xc2, 0x66, 0x24, - 0xa8, 0xcf, 0x0a, 0x90, 0x4c, 0xd6, 0xf4, 0xbf, 0xea, 0x55, 0x62, 0x52, 0x05, 0xcb, 0x58, - 0xf0, 0x6b, 0x1c, 0x19, 0x74, 0x23, 0x28, 0x0d, 0xea, 0xc7, 0x4e, 0xea, 0x97, 0x59, 0x8c, - 0x43, 0x14, 0xd8, 0x99, 0xa4, 0xfd, 0x85, 0x31, 0x1e, 0x04, 0x62, 0x57, 0xd2, 0xd4, 0xc2, - 0x97, 0xf1, 0x40, 0x6c, 0xf7, 0x09, 0xd9, 0x2a, 0x86, 0x07, 0xf7, 0x69, 0x8d, 0x45, 0xfe, - 0x9f, 0x41, 0xde, 0xa3, 0xa0, 0x57, 0x1c, 0x5d, 0xa5, 0xcf, 0xa7, 0x8e, 0x18, 0xeb, 0xf5, - 0x80, 0xc3, 0x61, 0x79, 0xd9, 0xd6, 0xe6, 0x32, 0x0a, 0x34, 0x8f, 0x14, 0x6c, 0x40, 0x7a, - 0xda, 0xb4, 0xcb, 0x31, 0x03, 0x92, 0xa5, 0xf5, 0xb5, 0xab, 0x28, 0x3b, 0x78, 0x34, 0x3b, - 0xa9, 0x1a, 0xbc, 0x7c, 0x4b, 0xfe, 0x23, 0xa3, 0xdb, 0xaf, 0x80, 0x37, 0xc6, 0x76, 0xe5, - 0x95, 0xa2, 0x65, 0x74, 0xb1, 0x81, 0x3b, 0xc2, 0xbf, 0x2d, 0x2e, 0x91, 0x1f, 0x6f, 0x3a, - 0xbb, 0x0b, 0xa6, 0xbc, 0xac, 0x7a, 0x29, 0x01, 0xfb, 0xdc, 0xe6, 0x5f, 0xb0, 0x7b, 0x56, - 0x36, 0x01, 0x7e, 0xf1, 0x4d, 0xff, 0x44, 0xcd, 0xee, 0xa7, 0x30, 0x47, 0x72, 0x94, 0xf2, - 0xf8, 0x61, 0x9b, 0xd3, 0xd5, 0xe6, 0xbe, 0x48, 0x98, 0xbf, 0x8d, 0x39, 0xc0, 0xe0, 0xea, - 0xe5, 0xa3, 0x68, 0x64, 0x62, 0x52, 0x06, 0xb9, 0xa8, 0xf9, 0x94, 0x0b, 0xf1, 0x66, 0x50, - 0xde, 0xf7, 0x92, 0x6e, 0xb0, 0xdb, 0x43, 0xb7, 0xd7, 0x61, 0x5e, 0x47, 0x74, 0xcf, 0x10, - 0x94, 0x82, 0xf2, 0xe8, 0x07, 0xfe, 0xe6, 0xc0, 0xc8, 0x84, 0xe8, 0x31, 0x4c, 0x67, 0xc5, - 0xd8, 0x5f, 0x4c, 0x22, 0x9c, 0xde, 0xab, 0x1e, 0x96, 0x4c, 0xf0, 0xc1, 0xad, 0xcb, 0x47, - 0xce, 0xbf, 0xc7, 0xc0, 0x67, 0xa0, 0xf3, 0xc8, 0x06, 0x81, 0x4a, 0x28, 0x5e, 0xdb, 0xb6, - 0x24, 0xf4, 0x71, 0x06, 0x29, 0x09, 0x89, 0x44, 0xac, 0x75, 0xe7, 0xc9, 0xcb, 0xc5, 0x6b, - 0xd0, 0xa0, 0x29, 0xe1, 0x11, 0x0e, 0xac, 0x60, 0xcb, 0x40, 0x77, 0xeb, 0xf1, 0x08, 0xfe, - 0x3e, 0x67, 0xcd, 0x06, 0x13, 0x91, 0xe5, 0xd6, 0x91, 0x6d, 0x5f, 0x41, 0xc0, 0x2b, 0x89, - 0x14, 0xc1, 0x2c, 0xf6, 0x05, 0xdb, 0x7d, 0x95, 0x92, 0x26, 0xe2, 0xe8, 0xff, 0x71, 0x26, - 0x3b, 0x9a, 0xf4, 0xc5, 0x9b, 0x0f, 0x4d, 0xb3, 0x15, 0xb7, 0x4c, 0xa2, 0xb0, 0xb7, 0xd2, - 0x52, 0x13, 0xd5, 0x29, 0x39, 0x54, 0xc3, 0xe5, 0x11, 0x72, 0x37, 0x0f, 0xb6, 0xc3, 0x5a, - 0xbe, 0x9c, 0xe3, 0x6e, 0xf2, 0x53, 0xe3, 0xa7, 0x2e, 0x19, 0xda, 0xc9, 0xbd, 0x73, 0x62, - 0xc4, 0x49, 0x92, 0x97, 0x42, 0x15, 0xc8, 0x2c, 0xb9, 0x0c, 0x99, 0x48, 0x8d, 0xbd, 0xe1, - 0x19, 0x63, 0xe8, 0x57, 0xce, 0xa6, 0xb8, 0x1b, 0x8e, 0xaa, 0xe3, 0x4b, 0x7c, 0xf5, 0xa9, - 0x7d, 0x6b, 0x60, 0xd4, 0x9f, 0xdf, 0xa2, 0x0f, 0x5f, 0x3c, 0x12, 0x0e, 0xf3, 0x82, 0xca, - 0x24, 0x69, 0x60, 0x4f, 0xb0, 0xc6, 0x84, 0x2c, 0x6d, 0x4f, 0xae, 0x96, 0x61, 0x66, 0x5b, - 0x5c, 0xbc, 0x61, 0x2c, 0xef, 0x13, 0x2f, 0x88, 0xfb, 0x7d, 0xa3, 0x93, 0xf3, 0x56, 0xe3, - 0xad, 0x13, 0xfc, 0x35, 0x57, 0x98, 0x0a, 0x77, 0x34, 0x23, 0x14, 0x53, 0xe4, 0x40, 0x79, - 0x04, 0x2f, 0xb4, 0x32, 0xf5, 0x5e, 0x75, 0x14, 0x84, 0xd5, 0xd6, 0xd3, 0x0f, 0xbc, 0x4f, - 0x99, 0x90, 0x13, 0xd5, 0xd4, 0xf2, 0xfb, 0x62, 0xf7, 0x14, 0x4e, 0x8d, 0xcd, 0x2a, 0xe5, - 0x95, 0x46, 0xcc, 0x43, 0x79, 0xad, 0x9f, 0x18, 0x59, 0xef, 0x80, 0xde, 0xc6, 0x6b, 0x1a, - 0x9b, 0x0b, 0x7f, 0xd2, 0xc4, 0x7b, 0xd3, 0x83, 0x02, 0xd2, 0x9c, 0x31, 0x99, 0x03, 0x29, - 0xa8, 0x95, 0x87, 0x6e, 0xd1, 0xd8, 0x4d, 0xb7, 0x57, 0x85, 0x6e, 0x75, 0xce, 0x9a, 0x1d, - 0xc7, 0xc7, 0x47, 0x2b, 0xc2, 0x18, 0xfb, 0x8d, 0x7c, 0x7d, 0x02, 0x8b, 0xb0, 0x2f, 0x10, - 0xef, 0xe7, 0xfe, 0x6a, 0x8c, 0x9c, 0xe0, 0x34, 0xfe, 0xa6, 0x6b, 0x90, 0x9c, 0x8d, 0x41, - 0x26, 0x25, 0x1c, 0x7d, 0x6e, 0x54, 0xf4, 0xcf, 0xc7, 0x78, 0xcd, 0x4f, 0x0e, 0x0b, 0xad, - 0x10, 0x96, 0x17, 0x6f, 0x2d, 0xd4, 0x5c, 0x45, 0xcb, 0xe1, 0x5e, 0x11, 0x8f, 0x90, 0xff, - 0x25, 0x45, 0xf8, 0x32, 0xf2, 0x36, 0x98, 0xf2, 0xc9, 0x53, 0x1b, 0x52, 0x65, 0x5a, 0x4c, - 0x0c, 0x89, 0x53, 0x55, 0x99, 0x28, 0xee, 0xdf, 0xc7, 0x56, 0xc3, 0x65, 0xcf, 0x92, 0x9b, - 0x84, 0x47, 0xdc, 0xdc, 0x7d, 0x82, 0x38, 0x49, 0xe0, 0x2f, 0xf6, 0x8b, 0x62, 0x78, 0xd7, - 0x54, 0x2c, 0xe0, 0xf1, 0x07, 0x0b, 0xb1, 0xad, 0x91, 0x3c, 0x1a, 0x35, 0x36, 0x25, 0xf5, - 0xd3, 0x5b, 0x14, 0xcf, 0xec, 0x84, 0xa6, 0x33, 0xd7, 0xfe, 0x25, 0x25, 0x6d, 0xcf, 0xfe, - 0x92, 0xf9, 0xa6, 0xf0, 0xfe, 0x00, 0xca, 0xaa, 0xa5, 0xb3, 0x9c, 0xc2, 0xab, 0x06, 0x76, - 0x8a, 0x42, 0xa5, 0xb4, 0x00, 0x83, 0xce, 0xa0, 0x1c, 0x96, 0xb3, 0xe6, 0x8d, 0x0f, 0x6a, - 0x58, 0x7e, 0xaf, 0x2d, 0xa6, 0xfd, 0xad, 0xc8, 0x25, 0x27, 0xf1, 0x86, 0xa6, 0x04, 0x71, - 0xce, 0x98, 0xe2, 0x7d, 0x2b, 0x11, 0xef, 0xc4, 0x79, 0x98, 0xf3, 0x03, 0x0a, 0x7a, 0x2e, - 0x5d, 0x0b, 0x0a, 0x7e, 0xb8, 0x0f, 0x6b, 0xd0, 0xe4, 0xb9, 0xc8, 0x36, 0x7c, 0x6c, 0x52, - 0x2d, 0x94, 0x15, 0xf8, 0xca, 0xec, 0x7b, 0x0a, 0x73, 0x18, 0xd5, 0x3d, 0xce, 0x39, 0x1c, - 0xf7, 0xe7, 0x38, 0x9c, 0x9a, 0x74, 0xaa, 0x6a, 0x4c, 0x21, 0x7c, 0x28, 0x85, 0x19, 0xaf, - 0x81, 0xba, 0x21, 0x22, 0xca, 0x0c, 0x58, 0x40, 0xcc, 0x02, 0xcf, 0x1b, 0xcf, 0x15, 0x0c, - 0xd3, 0xdf, 0x33, 0xc0, 0xac, 0xfd, 0x00, 0x53, 0xe6, 0x68, 0xb9, 0x26, 0x56, 0x1b, 0x92, - 0x40, 0x98, 0xd9, 0x7a, 0xaa, 0xb5, 0x7e, 0xe1, 0x11, 0x3d, 0xf9, 0x66, 0xa4, 0x22, 0xef, - 0x9b, 0x01, 0x46, 0x17, 0xbc, 0xee, 0xf0, 0x5f, 0xb6, 0x46, 0x8e, 0x33, 0x0e, 0x2d, 0xec, - 0xe3, 0xf3, 0x75, 0xe9, 0x8e, 0xf0, 0x3e, 0x5b, 0x18, 0xa9, 0x53, 0xe2, 0x30, 0x1f, 0xcc, - 0xec, 0x86, 0x20, 0x0a, 0xe4, 0x32, 0xc9, 0xc1, 0x2c, 0x30, 0x77, 0x54, 0x37, 0xf3, 0x62, - 0x97, 0x14, 0xa9, 0xfa, 0xbe, 0xb5, 0x32, 0x89, 0x40, 0x2b, 0x7f, 0xd3, 0x86, 0xce, 0xf2, - 0xb1, 0x14, 0x67, 0x23, 0xa8, 0x9d, 0x0f, 0x81, 0x65, 0x1e, 0x00, 0xca, 0xea, 0x2f, 0x3a, - 0xc9, 0xee, 0xfe, 0xfb, 0x86, 0x8d, 0x85, 0xed, 0x23, 0x54, 0xf5, 0x30, 0xfe, 0x38, 0xfe, - 0x3a, 0x3a, 0x6a, 0xab, 0x47, 0xd4, 0x2d, 0xc2, 0x13, 0x29, 0xe3, 0xad, 0x1b, 0x9d, 0x06, - 0xc0, 0xc8, 0xd6, 0x53, 0x74, 0x56, 0xf5, 0x4a, 0xd0, 0x45, 0x3f, 0x44, 0x41, 0x75, 0xd8, - 0x7e, 0xf5, 0xcd, 0xd1, 0x69, 0x46, 0x62, 0xe0, 0xa1, 0xe6, 0xe3, 0x63, 0x2e, 0xd7, 0xa8, - 0xe7, 0x6b, 0xc7, 0xb1, 0xb5, 0xa4, 0x18, 0xf0, 0x86, 0xd3, 0x40, 0x81, 0x5e, 0xc3, 0x98, - 0xf0, 0x92, 0xe9, 0x78, 0x69, 0xf5, 0xe2, 0x01, 0xc2, 0x2c, 0x87, 0x91, 0x8f, 0x76, 0x6a, - 0x35, 0x32, 0xeb, 0x9a, 0x4f, 0xc9, 0xac, 0xf1, 0x96, 0xcb, 0xc2, 0xd0, 0x28, 0x51, 0x19, - 0xa4, 0x21, 0x6d, 0x25, 0x81, 0xcd, 0x2d, 0x91, 0xbc, 0xdc, 0xe8, 0x68, 0xc4, 0x68, 0xf6, - 0xf3, 0x4c, 0xf4, 0x9e, 0x3a, 0x56, 0xce, 0x24, 0x9a, 0x2f, 0xd8, 0xcf, 0x36, 0xb0, 0x1b, - 0x0f, 0x77, 0xde, 0x72, 0x2b, 0xbc, 0xe2, 0x67, 0xe3, 0xe5, 0x52, 0x16, 0x88, 0xe6, 0x52, - 0x22, 0x23, 0x5c, 0x91, 0xc2, 0x63, 0xd8, 0x0e, 0x28, 0x29, 0x7e, 0x92, 0x9d, 0x88, 0x5b, - 0x7b, 0x9c, 0x1a, 0x16, 0x54, 0xb2, 0xd0, 0xb8, 0x75, 0x77, 0xc9, 0xa1, 0xc7, 0x25, 0xf5, - 0x44, 0x15, 0xdc, 0x5f, 0x52, 0xdd, 0xe0, 0x69, 0x5f, 0x9f, 0x6d, 0xcb, 0x4b, 0x6e, 0xe3, - 0xe3, 0xea, 0x70, 0x29, 0x04, 0xc1, 0x1f, 0xf9, 0x2f, 0x55, 0x53, 0x4c, 0x7e, 0xf9, 0x8c, - 0xe7, 0x93, 0xd7, 0x47, 0x56, 0xa4, 0x5d, 0x4e, 0x32, 0x0a, 0x42, 0x5e, 0x98, 0x2d, 0x5b, - 0x37, 0x2d, 0x6a, 0x8d, 0x41, 0xfb, 0x86, 0xba, 0x51, 0x64, 0x81, 0x68, 0x32, 0xa4, 0x81, - 0x82, 0x5c, 0x8c, 0x6a, 0xd7, 0x27, 0x09, 0x69, 0x85, 0x9e, 0x55, 0xd2, 0x36, 0x75, 0x35, - 0x06, 0x0f, 0x99, 0x85, 0x70, 0x65, 0x17, 0x04, 0x66, 0xbd, 0xb7, 0x0c, 0xb9, 0x3a, 0xb2, - 0xf9, 0xc0, 0xe2, 0x93, 0xa0, 0xa9, 0x19, 0x84, 0x3b, 0xbf, 0x34, 0xc2, 0xfe, 0x61, 0xb0, - 0xc3, 0xe3, 0x2a, 0xa7, 0x07, 0x8e, 0x83, 0xd4, 0xc1, 0x92, 0x9e, 0x1e, 0x1d, 0x86, 0x14, - 0x1c, 0xde, 0xb1, 0x89, 0x20, 0x91, 0x09, 0x75, 0xdb, 0x3a, 0x76, 0x26, 0x82, 0x05, 0x99, - 0x63, 0x0c, 0x42, 0x3a, 0xde, 0x23, 0x3d, 0x5d, 0x60, 0x68, 0x55, 0x24, 0xe8, 0xd8, 0x03, - 0x2b, 0x86, 0x1b, 0x4a, 0xad, 0x20, 0x02, 0xa8, 0xfd, 0x17, 0xc9, 0x28, 0x2b, 0x82, 0x5f, - 0x02, 0xd3, 0x53, 0xe2, 0x91, 0x37, 0x9c, 0xed, 0x00, 0xeb, 0xaa, 0x3c, 0x03, 0xe0, 0x1d, - 0x9c, 0x59, 0xf4, 0x05, 0x09, 0x9d, 0x1c, 0x34, 0x32, 0xba, 0xd0, 0x63, 0x58, 0xd6, 0xb1, - 0x94, 0x2f, 0x0b, 0xaf, 0x71, 0x09, 0x98, 0xd1, 0x0a, 0x22, 0xd1, 0x55, 0xb0, 0xfe, 0x84, - 0x99, 0x52, 0x89, 0x31, 0x26, 0x94, 0x9f, 0xf9, 0x2d, 0xe3, 0xa4, 0xc2, 0xee, 0xaf, 0xdf, - 0x68, 0x84, 0x35, 0xe3, 0x25, 0xd8, 0x1c, 0x2c, 0xe0, 0x08, 0xcf, 0x6c, 0x76, 0x03, 0x0d, - 0x4d, 0x46, 0x34, 0x2a, 0xc3, 0x37, 0x2c, 0x73, 0x98, 0x65, 0x60, 0xc4, 0xec, 0x35, 0xa6, - 0xf6, 0x49, 0xef, 0x02, 0xc1, 0x19, 0x36, 0xb7, 0x03, 0x9b, 0xc6, 0xf5, 0xd0, 0x94, 0x38, - 0xdb, 0xe4, 0x76, 0x25, 0x1b, 0x59, 0x64, 0xb6, 0x8f, 0x02, 0xee, 0xdf, 0xf7, 0xa9, 0xe0, - 0xed, 0x3e, 0x30, 0x90, 0x96, 0x5a, 0x22, 0xf2, 0xc5, 0x52, 0xce, 0x3b, 0x2b, 0x47, 0x4f, - 0xd2, 0xfc, 0x06, 0xb5, 0x09, 0x27, 0x83, 0x0a, 0x05, 0xa3, 0x03, 0xfa, 0xff, 0xd6, 0x84, - 0x82, 0xd7, 0xb7, 0x85, 0x38, 0x43, 0x25, 0x40, 0xdd, 0x32, 0x61, 0xab, 0x75, 0x9b, 0x65, - 0x82, 0x12, 0x9a, 0x7f, 0x18, 0xd8, 0x01, 0xc5, 0x43, 0x19, 0xca, 0x52, 0xa3, 0xc6, 0xa3, - 0xdb, 0x63, 0x50, 0x44, 0xd6, 0x25, 0xe2, 0x40, 0x38, 0xad, 0x42, 0x77, 0xf8, 0xd5, 0xbf, - 0x01, 0x60, 0x35, 0x16, 0x5f, 0x21, 0xb0, 0x70, 0xe8, 0x16, 0x9d, 0x65, 0x7d, 0x6e, 0xd1, - 0xfa, 0x7f, 0x8e, 0xd0, 0x9b, 0x4e, 0x1d, 0x9c, 0xa2, 0xe5, 0x1a, 0x24, 0xda, 0x55, 0xe4, - 0x3b, 0x3f, 0xca, 0x98, 0x59, 0xb2, 0x40, 0x8c, 0x26, 0xaa, 0xcb, 0xad, 0x74, 0x9e, 0xbe, - 0x88, 0x2c, 0x31, 0xe7, 0x20, 0x5e, 0x63, 0x8b, 0xb7, 0xe2, 0xbf, 0xc8, 0xa3, 0xf1, 0xc0, - 0x2c, 0x0c, 0xa7, 0xbb, 0x9d, 0xaa, 0xab, 0x7f, 0xcb, 0xf8, 0x45, 0xd8, 0x00, 0x2c, 0x3d, - 0xe7, 0x99, 0x24, 0xdc, 0xaa, 0xdc, 0x24, 0xbd, 0xc0, 0x08, 0x2f, 0x4a, 0x6b, 0x61, 0x87, - 0x6f, 0x31, 0x92, 0xa8, 0x81, 0xf5, 0x9a, 0x68, 0x2d, 0x27, 0x36, 0x85, 0xd4, 0x79, 0x5c, - 0x9b, 0xd7, 0xcc, 0xcf, 0x49, 0xde, 0x34, 0x44, 0x3a, 0x9f, 0x9c, 0xb3, 0x5b, 0xbf, 0x25, - 0x4c, 0x50, 0x61, 0x1b, 0x7c, 0x13, 0x24, 0xb1, 0x10, 0x94, 0x66, 0x7b, 0x6b, 0x60, 0x8c, - 0x39, 0xd1, 0x25, 0x2c, 0xeb, 0xcc, 0x48, 0x77, 0xce, 0xea, 0x76, 0xe1, 0x9b, 0x84, 0x2b, - 0x67, 0xf6, 0x26, 0x74, 0x3f, 0xab, 0x29, 0x77, 0x76, 0xcc, 0x9c, 0xf7, 0x9e, 0x90, 0xe8, - 0xfc, 0xe1, 0x00, 0x17, 0x90, 0xc2, 0xe7, 0xd5, 0xc9, 0x58, 0x64, 0x7c, 0xca, 0x5d, 0x33, - 0x97, 0xd2, 0x0a, 0xfc, 0xf2, 0x9b, 0xa4, 0x4f, 0x62, 0xa7, 0xc6, 0x2e, 0x90, 0x8d, 0x84, - 0x8d, 0x81, 0xa7, 0x9f, 0xad, 0xbb, 0x37, 0x0a, 0xba, 0x93, 0xb0, 0x3e, 0x41, 0xd4, 0xbc, - 0x49, 0xe2, 0x99, 0xd6, 0xd3, 0x3f, 0xaf, 0x86, 0x9f, 0x36, 0x37, 0x14, 0x14, 0xce, 0x64, - 0x6f, 0xc2, 0xca, 0x6d, 0xcf, 0xf5, 0x5a, 0x6e, 0x06, 0x39, 0xd5, 0x0c, 0xae, 0xb1, 0x14, - 0xc4, 0x18, 0xc6, 0x26, 0xb8, 0x67, 0x15, 0x43, 0x64, 0x81, 0xd1, 0x92, 0x8d, 0x55, 0xa7, - 0x56, 0xa6, 0x03, 0xe7, 0x11, 0x0c, 0x3a, 0xfe, 0x96, 0x3c, 0x2b, 0x29, 0xa4, 0x78, 0xf9, - 0xd4, 0x39, 0x7b, 0x88, 0x5a, 0x67, 0xb0, 0x93, 0xa3, 0x45, 0x79, 0x62, 0x19, 0xc1, 0x11, - 0xb7, 0xe9, 0x4d, 0xb3, 0x90, 0xaa, 0x4b, 0xb7, 0x6b, 0x66, 0xa5, 0x34, 0xe5, 0xe2, 0x67, - 0x9b, 0x27, 0xdb, 0x5f, 0x95, 0xfd, 0x09, 0xa3, 0x6b, 0x05, - ]; + let data = &self::data::tx_read_write::TX_READ_WRITE; let tx = Transaction::read(&data[..]).unwrap(); assert_eq!( format!("{}", tx.txid()), @@ -209,1697 +70,10 @@ fn tx_write_rejects_unexpected_binding_sig() { } } +mod data; #[test] fn zip_0143() { - struct TestVector { - tx: Vec, - script_code: Script, - transparent_input: Option, - hash_type: u32, - amount: i64, - consensus_branch_id: consensus::BranchId, - sighash: [u8; 32], - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0143.py - let test_vectors = vec![ - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x00, 0x02, 0xe7, 0x71, 0x98, 0x11, - 0x89, 0x3e, 0x00, 0x00, 0x09, 0x52, 0x00, 0xac, 0x65, 0x51, 0xac, 0x63, 0x65, 0x65, - 0xb2, 0x83, 0x5a, 0x08, 0x05, 0x75, 0x02, 0x00, 0x02, 0x51, 0x51, 0x48, 0x1c, 0xdd, - 0x86, 0xb3, 0xcc, 0x43, 0x18, 0x00, - ], - script_code: Script(vec![0x6a, 0x00, 0x00, 0x00, 0x63, 0xac, 0x53]), - transparent_input: None, - hash_type: 1, - amount: 1672704339313879, - consensus_branch_id: consensus::BranchId::Overwinter, - sighash: [ - 0xa1, 0xf1, 0xa4, 0xe5, 0xcd, 0x9b, 0xd5, 0x22, 0x32, 0x2d, 0x66, 0x1e, 0xdd, 0x2a, - 0xf1, 0xbf, 0x2a, 0x70, 0x19, 0xcf, 0xab, 0x94, 0xec, 0xe1, 0x8f, 0x4b, 0xa9, 0x35, - 0xb0, 0xa1, 0x90, 0x73, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x42, 0x01, 0xcf, 0xb1, 0xcd, - 0x8d, 0xbf, 0x69, 0xb8, 0x25, 0x0c, 0x18, 0xef, 0x41, 0x29, 0x4c, 0xa9, 0x79, 0x93, - 0xdb, 0x54, 0x6c, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, 0xa5, 0xe2, 0x9d, - 0x4e, 0x30, 0xa7, 0x03, 0xac, 0x6a, 0x00, 0x98, 0x42, 0x1c, 0x69, 0x37, 0x8a, 0xf1, - 0xe4, 0x0f, 0x64, 0xe1, 0x25, 0x94, 0x6f, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, - 0xb6, 0x4b, 0x69, 0x68, 0x91, 0x2a, 0x63, 0x81, 0xce, 0x3d, 0xc1, 0x66, 0xd5, 0x6a, - 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x05, 0x63, 0x63, 0x63, 0x53, 0x53, 0xe8, 0xc7, 0x20, - 0x3d, 0x02, 0xd2, 0xda, 0x86, 0x38, 0x7a, 0xe6, 0x01, 0x00, 0x08, 0x00, 0x63, 0x65, - 0x6a, 0x63, 0xac, 0x52, 0x00, 0xa7, 0x62, 0x29, 0x97, 0xf4, 0xff, 0x04, 0x00, 0x07, - 0x51, 0x51, 0x00, 0x53, 0x53, 0x65, 0x65, 0x97, 0xb0, 0xe4, 0xe4, 0xc7, 0x05, 0xfc, - 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x76, 0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, - 0xfa, 0x3d, 0x5a, 0x57, 0xef, 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, - 0xfb, 0x1a, 0x38, 0xe0, 0x1d, 0x94, 0x90, 0x3d, 0x3c, 0x3e, 0x0a, 0xd3, 0x36, 0x0c, - 0x1d, 0x37, 0x10, 0xac, 0xd2, 0x0b, 0x18, 0x3e, 0x31, 0xd4, 0x9f, 0x25, 0xc9, 0xa1, - 0x38, 0xf4, 0x9b, 0x1a, 0x53, 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x51, 0xa7, - 0xaf, 0x9d, 0xb6, 0x99, 0x0e, 0xd8, 0x3d, 0xd6, 0x4a, 0xf3, 0x59, 0x7c, 0x04, 0x32, - 0x3e, 0xa5, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, 0xb9, 0xda, 0x94, 0x8d, 0x32, - 0x0d, 0xad, 0xd6, 0x4f, 0x54, 0x31, 0xe6, 0x1d, 0xdf, 0x65, 0x8d, 0x24, 0xae, 0x67, - 0xc2, 0x2c, 0x8d, 0x13, 0x09, 0x13, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, 0x42, - 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x91, 0xe0, 0x0c, 0x7a, 0x1d, 0x48, 0xaf, 0x04, - 0x68, 0x27, 0x59, 0x1e, 0x97, 0x33, 0xa9, 0x7f, 0xa6, 0xb6, 0x79, 0xf3, 0xdc, 0x60, - 0x1d, 0x00, 0x82, 0x85, 0xed, 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0xfc, 0x1b, 0xe4, 0xaa, - 0xc0, 0x0f, 0xf2, 0x71, 0x1e, 0xbd, 0x93, 0x1d, 0xe5, 0x18, 0x85, 0x68, 0x78, 0xf7, - 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, 0x3c, - 0x94, 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, 0x79, - 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, 0x32, 0xb4, 0xf4, - 0x73, 0xf4, 0x68, 0xa0, 0x08, 0xe7, 0x23, 0x89, 0xfc, 0x03, 0x88, 0x0d, 0x78, 0x0c, - 0xb0, 0x7f, 0xcf, 0xaa, 0xbe, 0x3f, 0x1a, 0x84, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, - 0x3d, 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x55, 0xed, 0x94, 0x94, 0xc6, 0xac, - 0x89, 0x3c, 0x49, 0x72, 0x38, 0x33, 0xec, 0x89, 0x26, 0xc1, 0x03, 0x95, 0x86, 0xa7, - 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, 0x73, 0x1e, 0x98, 0x5d, 0x99, 0x58, 0x9c, 0x03, 0xb8, - 0x38, 0xe8, 0xaa, 0xf7, 0x45, 0x53, 0x3e, 0xd9, 0xe8, 0xae, 0x3a, 0x1c, 0xd0, 0x74, - 0xa5, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, 0xeb, 0xbc, 0x86, 0x2d, 0xed, - 0x42, 0x43, 0x5e, 0x02, 0x47, 0x69, 0x30, 0xd0, 0x69, 0x89, 0x6c, 0xff, 0x30, 0xeb, - 0x41, 0x4f, 0x72, 0x7b, 0x89, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, 0x6d, - 0x75, 0xa4, 0xa6, 0xf2, 0x65, 0x72, 0x50, 0x4b, 0x0b, 0x22, 0x32, 0xec, 0xb9, 0xf0, - 0xc0, 0x24, 0x11, 0xe5, 0x25, 0x96, 0xbc, 0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, - 0xff, 0xed, 0xbd, 0x12, 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, 0x7d, 0x41, 0x7a, - 0xdb, 0x3d, 0x15, 0xcc, 0x54, 0xdc, 0xb1, 0xfc, 0xe4, 0x67, 0x50, 0x0c, 0x6b, 0x8f, - 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, 0x82, 0x85, 0x7d, 0xee, 0xcc, 0x40, 0xa9, - 0x8d, 0x5f, 0x29, 0x03, 0x39, 0x5e, 0xe4, 0x76, 0x2d, 0xd2, 0x1a, 0xfd, 0xbb, 0x5d, - 0x47, 0xfa, 0x9a, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, 0xb9, 0x27, 0xb7, - 0xfa, 0xe2, 0xdb, 0x58, 0x71, 0x05, 0x41, 0x5d, 0x02, 0x42, 0x78, 0x9d, 0x38, 0xf5, - 0x0b, 0x8d, 0xbc, 0xc1, 0x29, 0xca, 0xb3, 0xd1, 0x7d, 0x19, 0xf3, 0x35, 0x5b, 0xcf, - 0x73, 0xce, 0xcb, 0x8c, 0xb8, 0xa5, 0xda, 0x01, 0x30, 0x71, 0x52, 0xf1, 0x39, 0x02, - 0xa2, 0x70, 0x57, 0x26, 0x70, 0xdc, 0x82, 0xd3, 0x90, 0x26, 0xc6, 0xcb, 0x4c, 0xd4, - 0xb0, 0xf7, 0xf5, 0xaa, 0x2a, 0x4f, 0x5a, 0x53, 0x41, 0xec, 0x5d, 0xd7, 0x15, 0x40, - 0x6f, 0x2f, 0xdd, 0x2a, 0x02, 0x73, 0x3f, 0x5f, 0x64, 0x1c, 0x8c, 0x21, 0x86, 0x2a, - 0x1b, 0xaf, 0xce, 0x26, 0x09, 0xd9, 0xee, 0xcf, 0xa1, 0x58, 0xcf, 0xb5, 0xcd, 0x79, - 0xf8, 0x80, 0x08, 0xe3, 0x15, 0xdc, 0x7d, 0x83, 0x88, 0x03, 0x6c, 0x17, 0x82, 0xfd, - 0x27, 0x95, 0xd1, 0x8a, 0x76, 0x36, 0x24, 0xc2, 0x5f, 0xa9, 0x59, 0xcc, 0x97, 0x48, - 0x9c, 0xe7, 0x57, 0x45, 0x82, 0x4b, 0x77, 0x86, 0x8c, 0x53, 0x23, 0x9c, 0xfb, 0xdf, - 0x73, 0xca, 0xec, 0x65, 0x60, 0x40, 0x37, 0x31, 0x4f, 0xaa, 0xce, 0xb5, 0x62, 0x18, - 0xc6, 0xbd, 0x30, 0xf8, 0x37, 0x4a, 0xc1, 0x33, 0x86, 0x79, 0x3f, 0x21, 0xa9, 0xfb, - 0x80, 0xad, 0x03, 0xbc, 0x0c, 0xda, 0x4a, 0x44, 0x94, 0x6c, 0x00, 0xe1, 0xb1, 0xa1, - 0xdf, 0x0e, 0x5b, 0x87, 0xb5, 0xbe, 0xce, 0x47, 0x7a, 0x70, 0x96, 0x49, 0xe9, 0x50, - 0x06, 0x05, 0x91, 0x39, 0x48, 0x12, 0x95, 0x1e, 0x1f, 0xe3, 0x89, 0x5b, 0x8c, 0xc3, - 0xd1, 0x4d, 0x2c, 0xf6, 0x55, 0x6d, 0xf6, 0xed, 0x4b, 0x4d, 0xdd, 0x3d, 0x9a, 0x69, - 0xf5, 0x33, 0x57, 0xd7, 0x76, 0x7f, 0x4f, 0x5c, 0xcb, 0xdb, 0xc5, 0x96, 0x63, 0x12, - 0x77, 0xf8, 0xfe, 0xcd, 0x08, 0xcb, 0x05, 0x6b, 0x95, 0xe3, 0x02, 0x5b, 0x97, 0x92, - 0xff, 0xf7, 0xf2, 0x44, 0xfc, 0x71, 0x62, 0x69, 0xb9, 0x26, 0xd6, 0x2e, 0x95, 0x96, - 0xfa, 0x82, 0x5c, 0x6b, 0xf2, 0x1a, 0xff, 0x9e, 0x68, 0x62, 0x5a, 0x19, 0x24, 0x40, - 0xea, 0x06, 0x82, 0x81, 0x23, 0xd9, 0x78, 0x84, 0x80, 0x6f, 0x15, 0xfa, 0x08, 0xda, - 0x52, 0x75, 0x4a, 0x10, 0x95, 0xe3, 0xff, 0x1a, 0xbd, 0x5c, 0xe4, 0xfd, 0xdf, 0xcc, - 0xfc, 0x3a, 0x61, 0x28, 0xae, 0xf7, 0x84, 0xa6, 0x46, 0x10, 0xa8, 0x9d, 0x1a, 0x70, - 0x99, 0x21, 0x6d, 0x08, 0x14, 0xd3, 0xa2, 0xd4, 0x52, 0x43, 0x1c, 0x32, 0xd4, 0x11, - 0xac, 0x1c, 0xce, 0x82, 0xad, 0x02, 0x29, 0x40, 0x7b, 0xbc, 0x48, 0x98, 0x56, 0x75, - 0xe3, 0xf8, 0x74, 0xa4, 0x53, 0x3f, 0x1d, 0x63, 0xa8, 0x4d, 0xfa, 0x3e, 0x0f, 0x46, - 0x0f, 0xe2, 0xf5, 0x7e, 0x34, 0xfb, 0xc7, 0x54, 0x23, 0xc3, 0x73, 0x7f, 0x5b, 0x2a, - 0x06, 0x15, 0xf5, 0x72, 0x2d, 0xb0, 0x41, 0xa3, 0xef, 0x66, 0xfa, 0x48, 0x3a, 0xfd, - 0x3c, 0x2e, 0x19, 0xe5, 0x94, 0x44, 0xa6, 0x4a, 0xdd, 0x6d, 0xf1, 0xd9, 0x63, 0xf5, - 0xdd, 0x5b, 0x50, 0x10, 0xd3, 0xd0, 0x25, 0xf0, 0x28, 0x7c, 0x4c, 0xf1, 0x9c, 0x75, - 0xf3, 0x3d, 0x51, 0xdd, 0xdd, 0xba, 0x5d, 0x65, 0x7b, 0x43, 0xee, 0x8d, 0xa6, 0x45, - 0x44, 0x38, 0x14, 0xcc, 0x73, 0x29, 0xf3, 0xe9, 0xb4, 0xe5, 0x4c, 0x23, 0x6c, 0x29, - 0xaf, 0x39, 0x23, 0x10, 0x17, 0x56, 0xd9, 0xfa, 0x4b, 0xd0, 0xf7, 0xd2, 0xdd, 0xaa, - 0xcb, 0x6b, 0x0f, 0x86, 0xa2, 0x65, 0x8e, 0x0a, 0x07, 0xa0, 0x5a, 0xc5, 0xb9, 0x50, - 0x05, 0x1c, 0xd2, 0x4c, 0x47, 0xa8, 0x8d, 0x13, 0xd6, 0x59, 0xba, 0x2a, 0x46, 0xca, - 0x18, 0x30, 0x81, 0x6d, 0x09, 0xcd, 0x76, 0x46, 0xf7, 0x6f, 0x71, 0x6a, 0xbe, 0xc5, - 0xde, 0x07, 0xfe, 0x9b, 0x52, 0x34, 0x10, 0x80, 0x6e, 0xa6, 0xf2, 0x88, 0xf8, 0x73, - 0x6c, 0x23, 0x35, 0x7c, 0x85, 0xf4, 0x57, 0x91, 0xe1, 0x70, 0x80, 0x29, 0xd9, 0x82, - 0x4d, 0x90, 0x70, 0x46, 0x07, 0xf3, 0x87, 0xa0, 0x3e, 0x49, 0xbf, 0x98, 0x36, 0x57, - 0x44, 0x31, 0x34, 0x5a, 0x78, 0x77, 0xef, 0xaa, 0x8a, 0x08, 0xe7, 0x30, 0x81, 0xef, - 0x8d, 0x62, 0xcb, 0x78, 0x0a, 0xb6, 0x88, 0x3a, 0x50, 0xa0, 0xd4, 0x70, 0x19, 0x0d, - 0xfb, 0xa1, 0x0a, 0x85, 0x7f, 0x82, 0x84, 0x2d, 0x38, 0x25, 0xb3, 0xd6, 0xda, 0x05, - 0x73, 0xd3, 0x16, 0xeb, 0x16, 0x0d, 0xc0, 0xb7, 0x16, 0xc4, 0x8f, 0xbd, 0x46, 0x7f, - 0x75, 0xb7, 0x80, 0x14, 0x9a, 0xe8, 0x80, 0x8f, 0x4e, 0x68, 0xf5, 0x0c, 0x05, 0x36, - 0xac, 0xdd, 0xf6, 0xf1, 0xae, 0xab, 0x01, 0x6b, 0x6b, 0xc1, 0xec, 0x14, 0x4b, 0x4e, - 0x55, 0x3a, 0xcf, 0xd6, 0x70, 0xf7, 0x7e, 0x75, 0x5f, 0xc8, 0x8e, 0x06, 0x77, 0xe3, - 0x1b, 0xa4, 0x59, 0xb4, 0x4e, 0x30, 0x77, 0x68, 0x95, 0x8f, 0xe3, 0x78, 0x9d, 0x41, - 0xc2, 0xb1, 0xff, 0x43, 0x4c, 0xb3, 0x0e, 0x15, 0x91, 0x4f, 0x01, 0xbc, 0x6b, 0xc2, - 0x30, 0x7b, 0x48, 0x8d, 0x25, 0x56, 0xd7, 0xb7, 0x38, 0x0e, 0xa4, 0xff, 0xd7, 0x12, - 0xf6, 0xb0, 0x2f, 0xe8, 0x06, 0xb9, 0x45, 0x69, 0xcd, 0x40, 0x59, 0xf3, 0x96, 0xbf, - 0x29, 0xb9, 0x9d, 0x0a, 0x40, 0xe5, 0xe1, 0x71, 0x1c, 0xa9, 0x44, 0xf7, 0x2d, 0x43, - 0x6a, 0x10, 0x2f, 0xca, 0x4b, 0x97, 0x69, 0x3d, 0xa0, 0xb0, 0x86, 0xfe, 0x9d, 0x2e, - 0x71, 0x62, 0x47, 0x0d, 0x02, 0xe0, 0xf0, 0x5d, 0x4b, 0xec, 0x95, 0x12, 0xbf, 0xb3, - 0xf3, 0x83, 0x27, 0x29, 0x6e, 0xfa, 0xa7, 0x43, 0x28, 0xb1, 0x18, 0xc2, 0x74, 0x02, - 0xc7, 0x0c, 0x3a, 0x90, 0xb4, 0x9a, 0xd4, 0xbb, 0xc6, 0x8e, 0x37, 0xc0, 0xaa, 0x7d, - 0x9b, 0x3f, 0xe1, 0x77, 0x99, 0xd7, 0x3b, 0x84, 0x1e, 0x75, 0x17, 0x13, 0xa0, 0x29, - 0x43, 0x90, 0x5a, 0xae, 0x08, 0x03, 0xfd, 0x69, 0x44, 0x2e, 0xb7, 0x68, 0x1e, 0xc2, - 0xa0, 0x56, 0x00, 0x05, 0x4e, 0x92, 0xee, 0xd5, 0x55, 0x02, 0x8f, 0x21, 0xb6, 0xa1, - 0x55, 0x26, 0x8a, 0x2d, 0xd6, 0x64, 0x0a, 0x69, 0x30, 0x1a, 0x52, 0xa3, 0x8d, 0x4d, - 0x9f, 0x9f, 0x95, 0x7a, 0xe3, 0x5a, 0xf7, 0x16, 0x71, 0x18, 0x14, 0x1c, 0xe4, 0xc9, - 0xbe, 0x0a, 0x6a, 0x49, 0x2f, 0xe7, 0x9f, 0x15, 0x81, 0xa1, 0x55, 0xfa, 0x3a, 0x2b, - 0x9d, 0xaf, 0xd8, 0x2e, 0x65, 0x0b, 0x38, 0x6a, 0xd3, 0xa0, 0x8c, 0xb6, 0xb8, 0x31, - 0x31, 0xac, 0x30, 0x0b, 0x08, 0x46, 0x35, 0x4a, 0x7e, 0xef, 0x9c, 0x41, 0x0e, 0x4b, - 0x62, 0xc4, 0x7c, 0x54, 0x26, 0x90, 0x7d, 0xfc, 0x66, 0x85, 0xc5, 0xc9, 0x9b, 0x71, - 0x41, 0xac, 0x62, 0x6a, 0xb4, 0x76, 0x1f, 0xd3, 0xf4, 0x1e, 0x72, 0x8e, 0x1a, 0x28, - 0xf8, 0x9d, 0xb8, 0x9f, 0xfd, 0xec, 0xa3, 0x64, 0xdd, 0x2f, 0x0f, 0x07, 0x39, 0xf0, - 0x53, 0x45, 0x56, 0x48, 0x31, 0x99, 0xc7, 0x1f, 0x18, 0x93, 0x41, 0xac, 0x9b, 0x78, - 0xa2, 0x69, 0x16, 0x42, 0x06, 0xa0, 0xea, 0x1c, 0xe7, 0x3b, 0xfb, 0x2a, 0x94, 0x2e, - 0x73, 0x70, 0xb2, 0x47, 0xc0, 0x46, 0xf8, 0xe7, 0x5e, 0xf8, 0xe3, 0xf8, 0xbd, 0x82, - 0x1c, 0xf5, 0x77, 0x49, 0x18, 0x64, 0xe2, 0x0e, 0x6d, 0x08, 0xfd, 0x2e, 0x32, 0xb5, - 0x55, 0xc9, 0x2c, 0x66, 0x1f, 0x19, 0x58, 0x8b, 0x72, 0xa8, 0x95, 0x99, 0x71, 0x0a, - 0x88, 0x06, 0x12, 0x53, 0xca, 0x28, 0x5b, 0x63, 0x04, 0xb3, 0x7d, 0xa2, 0xb5, 0x29, - 0x4f, 0x5c, 0xb3, 0x54, 0xa8, 0x94, 0x32, 0x28, 0x48, 0xcc, 0xbd, 0xc7, 0xc2, 0x54, - 0x5b, 0x7d, 0xa5, 0x68, 0xaf, 0xac, 0x87, 0xff, 0xa0, 0x05, 0xc3, 0x12, 0x24, 0x1c, - 0x2d, 0x57, 0xf4, 0xb4, 0x5d, 0x64, 0x19, 0xf0, 0xd2, 0xe2, 0xc5, 0xaf, 0x33, 0xae, - 0x24, 0x37, 0x85, 0xb3, 0x25, 0xcd, 0xab, 0x95, 0x40, 0x4f, 0xc7, 0xae, 0xd7, 0x05, - 0x25, 0xcd, 0xdb, 0x41, 0x87, 0x2c, 0xfc, 0xc2, 0x14, 0xb1, 0x32, 0x32, 0xed, 0xc7, - 0x86, 0x09, 0x75, 0x3d, 0xbf, 0xf9, 0x30, 0xeb, 0x0d, 0xc1, 0x56, 0x61, 0x2b, 0x9c, - 0xb4, 0x34, 0xbc, 0x4b, 0x69, 0x33, 0x92, 0xde, 0xb8, 0x7c, 0x53, 0x04, 0x35, 0x31, - 0x2e, 0xdc, 0xed, 0xc6, 0xa9, 0x61, 0x13, 0x33, 0x38, 0xd7, 0x86, 0xc4, 0xa3, 0xe1, - 0x03, 0xf6, 0x01, 0x10, 0xa1, 0x6b, 0x13, 0x37, 0x12, 0x97, 0x04, 0xbf, 0x47, 0x54, - 0xff, 0x6b, 0xa9, 0xfb, 0xe6, 0x59, 0x51, 0xe6, 0x10, 0x62, 0x0f, 0x71, 0xcd, 0xa8, - 0xfc, 0x87, 0x76, 0x25, 0xf2, 0xc5, 0xbb, 0x04, 0xcb, 0xe1, 0x22, 0x8b, 0x1e, 0x88, - 0x6f, 0x40, 0x50, 0xaf, 0xd8, 0xfe, 0x94, 0xe9, 0x7d, 0x2e, 0x9e, 0x85, 0xc6, 0xbb, - 0x74, 0x8c, 0x00, 0x42, 0xd3, 0x24, 0x9a, 0xbb, 0x13, 0x42, 0xbb, 0x0e, 0xeb, 0xf6, - 0x20, 0x58, 0xbf, 0x3d, 0xe0, 0x80, 0xd9, 0x46, 0x11, 0xa3, 0x75, 0x09, 0x15, 0xb5, - 0xdc, 0x6c, 0x0b, 0x38, 0x99, 0xd4, 0x12, 0x22, 0xba, 0xce, 0x76, 0x0e, 0xe9, 0xc8, - 0x81, 0x8d, 0xed, 0x59, 0x9e, 0x34, 0xc5, 0x6d, 0x73, 0x72, 0xaf, 0x1e, 0xb8, 0x68, - 0x52, 0xf2, 0xa7, 0x32, 0x10, 0x4b, 0xdb, 0x75, 0x07, 0x39, 0xde, 0x6c, 0x2c, 0x6e, - 0x0f, 0x9e, 0xb7, 0xcb, 0x17, 0xf1, 0x94, 0x2b, 0xfc, 0x9f, 0x4f, 0xd6, 0xeb, 0xb6, - 0xb4, 0xcd, 0xd4, 0xda, 0x2b, 0xca, 0x26, 0xfa, 0xc4, 0x57, 0x8e, 0x9f, 0x54, 0x34, - 0x05, 0xac, 0xc7, 0xd8, 0x6f, 0xf5, 0x91, 0x58, 0xbd, 0x0c, 0xba, 0x3a, 0xef, 0x6f, - 0x4a, 0x84, 0x72, 0xd1, 0x44, 0xd9, 0x9f, 0x8b, 0x8d, 0x1d, 0xed, 0xaa, 0x90, 0x77, - 0xd4, 0xf0, 0x1d, 0x4b, 0xb2, 0x7b, 0xbe, 0x31, 0xd8, 0x8f, 0xbe, 0xfa, 0xc3, 0xdc, - 0xd4, 0x79, 0x75, 0x63, 0xa2, 0x6b, 0x1d, 0x61, 0xfc, 0xd9, 0xa4, 0x64, 0xab, 0x21, - 0xed, 0x55, 0x0f, 0xe6, 0xfa, 0x09, 0x69, 0x5b, 0xa0, 0xb2, 0xf1, 0x0e, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xea, 0x64, 0x68, 0xcc, 0x6e, 0x20, 0xa6, 0x6f, 0x82, 0x6e, 0x3d, 0x14, 0xc5, 0x00, - 0x6f, 0x05, 0x63, 0x88, 0x7f, 0x5e, 0x12, 0x89, 0xbe, 0x1b, 0x20, 0x04, 0xca, 0xca, - 0x8d, 0x3f, 0x34, 0xd6, 0xe8, 0x4b, 0xf5, 0x9c, 0x1e, 0x04, 0x61, 0x9a, 0x7c, 0x23, - 0xa9, 0x96, 0x94, 0x1d, 0x88, 0x9e, 0x46, 0x22, 0xa9, 0xb9, 0xb1, 0xd5, 0x9d, 0x5e, - 0x31, 0x90, 0x94, 0x31, 0x8c, 0xd4, 0x05, 0xba, 0x27, 0xb7, 0xe2, 0xc0, 0x84, 0x76, - 0x2d, 0x31, 0x45, 0x3e, 0xc4, 0x54, 0x9a, 0x4d, 0x97, 0x72, 0x9d, 0x03, 0x34, 0x60, - 0xfc, 0xf8, 0x9d, 0x64, 0x94, 0xf2, 0xff, 0xd7, 0x89, 0xe9, 0x80, 0x82, 0xea, 0x5c, - 0xe9, 0x53, 0x4b, 0x3a, 0xcd, 0x60, 0xfe, 0x49, 0xe3, 0x7e, 0x4f, 0x66, 0x69, 0x31, - 0x67, 0x73, 0x19, 0xed, 0x89, 0xf8, 0x55, 0x88, 0x74, 0x1b, 0x31, 0x28, 0x90, 0x1a, - 0x93, 0xbd, 0x78, 0xe4, 0xbe, 0x02, 0x25, 0xa9, 0xe2, 0x69, 0x2c, 0x77, 0xc9, 0x69, - 0xed, 0x01, 0x76, 0xbd, 0xf9, 0x55, 0x59, 0x48, 0xcb, 0xd5, 0xa3, 0x32, 0xd0, 0x45, - 0xde, 0x6b, 0xa6, 0xbf, 0x44, 0x90, 0xad, 0xfe, 0x74, 0x44, 0xcd, 0x46, 0x7a, 0x09, - 0x07, 0x54, 0x17, 0xfc, 0xc0, 0x06, 0x2e, 0x49, 0xf0, 0x08, 0xc5, 0x1a, 0xd4, 0x22, - 0x74, 0x39, 0xc1, 0xb4, 0x47, 0x6c, 0xcd, 0x8e, 0x97, 0x86, 0x2d, 0xab, 0x7b, 0xe1, - 0xe8, 0xd3, 0x99, 0xc0, 0x5e, 0xf2, 0x7c, 0x6e, 0x22, 0xee, 0x27, 0x3e, 0x15, 0x78, - 0x6e, 0x39, 0x4c, 0x8f, 0x1b, 0xe3, 0x16, 0x82, 0xa3, 0x01, 0x47, 0x96, 0x3a, 0xc8, - 0xda, 0x8d, 0x41, 0xd8, 0x04, 0x25, 0x84, 0x26, 0xa3, 0xf7, 0x02, 0x89, 0xb8, 0xad, - 0x19, 0xd8, 0xde, 0x13, 0xbe, 0x4e, 0xeb, 0xe3, 0xbd, 0x4c, 0x8a, 0x6f, 0x55, 0xd6, - 0xe0, 0xc3, 0x73, 0xd4, 0x56, 0x85, 0x18, 0x79, 0xf5, 0xfb, 0xc2, 0x82, 0xdb, 0x9e, - 0x13, 0x48, 0x06, 0xbf, 0xf7, 0x1e, 0x11, 0xbc, 0x33, 0xab, 0x75, 0xdd, 0x6c, 0xa0, - 0x67, 0xfb, 0x73, 0xa0, 0x43, 0xb6, 0x46, 0xa7, 0x03, 0x39, 0xca, 0xb4, 0x92, 0x83, - 0x86, 0x78, 0x6d, 0x2f, 0x24, 0x14, 0x1e, 0xe1, 0x20, 0xfd, 0xc3, 0x4d, 0x67, 0x64, - 0xea, 0xfc, 0x66, 0x88, 0x0e, 0xe0, 0x20, 0x4f, 0x53, 0xcc, 0x11, 0x67, 0xed, 0x02, - 0xb4, 0x3a, 0x52, 0xde, 0xa3, 0xca, 0x7c, 0xff, 0x8e, 0xf3, 0x5c, 0xd8, 0xe6, 0xd7, - 0xc1, 0x11, 0xa6, 0x8e, 0xf4, 0x4b, 0xcd, 0x0c, 0x15, 0x13, 0xad, 0x47, 0xca, 0x61, - 0xc6, 0x59, 0xcc, 0x5d, 0x0a, 0x5b, 0x44, 0x0f, 0x6b, 0x9f, 0x59, 0xaf, 0xf6, 0x68, - 0x79, 0xbb, 0x66, 0x88, 0xfd, 0x28, 0x59, 0x36, 0x2b, 0x18, 0x2f, 0x20, 0x7b, 0x31, - 0x75, 0x96, 0x1f, 0x64, 0x11, 0xa4, 0x93, 0xbf, 0xfd, 0x04, 0x8e, 0x7d, 0x0d, 0x87, - 0xd8, 0x2f, 0xe6, 0xf9, 0x90, 0xa2, 0xb0, 0xa2, 0x5f, 0x5a, 0xa0, 0x11, 0x1a, 0x6e, - 0x68, 0xf3, 0x7b, 0xf6, 0xf3, 0xac, 0x2d, 0x26, 0xb8, 0x46, 0x86, 0xe5, 0x69, 0x03, - 0x8d, 0x99, 0xc1, 0x38, 0x35, 0x97, 0xfa, 0xd8, 0x11, 0x93, 0xc4, 0xc1, 0xb1, 0x6e, - 0x6a, 0x90, 0xe2, 0xd5, 0x07, 0xcd, 0xfe, 0x6f, 0xbd, 0xaa, 0x86, 0x16, 0x3e, 0x9c, - 0xf5, 0xde, 0x31, 0x00, 0x03, 0xca, 0x7e, 0x8d, 0xa0, 0x47, 0xb0, 0x90, 0xdb, 0x9f, - 0x37, 0x95, 0x2f, 0xbf, 0xee, 0x76, 0xaf, 0x61, 0x66, 0x81, 0x90, 0xbd, 0x52, 0xed, - 0x49, 0x0e, 0x67, 0x7b, 0x51, 0x5d, 0x01, 0x43, 0x84, 0x03, 0x07, 0x21, 0x9c, 0x7c, - 0x0e, 0xe7, 0xfc, 0x7b, 0xfc, 0x79, 0xf3, 0x25, 0x64, 0x4e, 0x4d, 0xf4, 0xc0, 0xd7, - 0xdb, 0x08, 0xe9, 0xf0, 0xbd, 0x02, 0x49, 0x43, 0xc7, 0x05, 0xab, 0xff, 0x89, 0x94, - 0x03, 0xa6, 0x05, 0xcf, 0xbc, 0x7e, 0xd7, 0x46, 0xa7, 0xd3, 0xf7, 0xc3, 0x7d, 0x9e, - 0x8b, 0xdc, 0x43, 0x3b, 0x7d, 0x79, 0xe0, 0x8a, 0x12, 0xf7, 0x38, 0xa8, 0xf0, 0xdb, - 0xdd, 0xfe, 0xf2, 0xf2, 0x65, 0x02, 0xf3, 0xe4, 0x7d, 0x1b, 0x0f, 0xd1, 0x1e, 0x6a, - 0x13, 0x31, 0x1f, 0xb7, 0x99, 0xc7, 0x9c, 0x64, 0x1d, 0x9d, 0xa4, 0x3b, 0x33, 0xe7, - 0xad, 0x01, 0x2e, 0x28, 0x25, 0x53, 0x98, 0x78, 0x92, 0x62, 0x27, 0x5f, 0x11, 0x75, - 0xbe, 0x84, 0x62, 0xc0, 0x14, 0x91, 0xc4, 0xd8, 0x42, 0x40, 0x6d, 0x0e, 0xc4, 0x28, - 0x2c, 0x95, 0x26, 0x17, 0x4a, 0x09, 0x87, 0x8f, 0xe8, 0xfd, 0xde, 0x33, 0xa2, 0x96, - 0x04, 0xe5, 0xe5, 0xe7, 0xb2, 0xa0, 0x25, 0xd6, 0x65, 0x0b, 0x97, 0xdb, 0xb5, 0x2b, - 0xef, 0xb5, 0x9b, 0x1d, 0x30, 0xa5, 0x74, 0x33, 0xb0, 0xa3, 0x51, 0x47, 0x44, 0x44, - 0x09, 0x9d, 0xaa, 0x37, 0x10, 0x46, 0x61, 0x32, 0x60, 0xcf, 0x33, 0x54, 0xcf, 0xcd, - 0xad, 0xa6, 0x63, 0xec, 0xe8, 0x24, 0xff, 0xd7, 0xe4, 0x43, 0x93, 0x88, 0x6a, 0x86, - 0x16, 0x5d, 0xdd, 0xdf, 0x2b, 0x4c, 0x41, 0x77, 0x35, 0x54, 0xc8, 0x69, 0x95, 0x26, - 0x94, 0x08, 0xb1, 0x1e, 0x67, 0x37, 0xa4, 0xc4, 0x47, 0x58, 0x6f, 0x69, 0x17, 0x34, - 0x46, 0xd8, 0xe4, 0x8b, 0xf8, 0x4c, 0xbc, 0x00, 0x0a, 0x80, 0x78, 0x99, 0x97, 0x3e, - 0xb9, 0x3c, 0x5e, 0x81, 0x9a, 0xad, 0x66, 0x94, 0x13, 0xf8, 0x38, 0x79, 0x33, 0xad, - 0x15, 0x84, 0xaa, 0x35, 0xe4, 0x3f, 0x4e, 0xcd, 0x1e, 0x2d, 0x04, 0x07, 0xc0, 0xb1, - 0xb8, 0x99, 0x20, 0xff, 0xdf, 0xdb, 0x9b, 0xea, 0x51, 0xac, 0x95, 0xb5, 0x57, 0xaf, - 0x71, 0xb8, 0x9f, 0x90, 0x3f, 0x5d, 0x98, 0x48, 0xf1, 0x4f, 0xcb, 0xeb, 0x18, 0x37, - 0x57, 0x0f, 0x54, 0x4d, 0x63, 0x59, 0xeb, 0x23, 0xfa, 0xf3, 0x8a, 0x08, 0x22, 0xda, - 0x36, 0xce, 0x42, 0x6c, 0x4a, 0x2f, 0xbe, 0xff, 0xeb, 0x0a, 0x8a, 0x2e, 0x29, 0x7a, - 0x9d, 0x19, 0xba, 0x15, 0x02, 0x45, 0x90, 0xe3, 0x32, 0x9d, 0x9f, 0xa9, 0x26, 0x1f, - 0x99, 0x38, 0xa4, 0x03, 0x2d, 0xd3, 0x46, 0x06, 0xc9, 0xcf, 0x9f, 0x3d, 0xd3, 0x3e, - 0x57, 0x6f, 0x05, 0xcd, 0x1d, 0xd6, 0x81, 0x1c, 0x62, 0x98, 0x75, 0x7d, 0x77, 0xd9, - 0xe8, 0x10, 0xab, 0xdb, 0x22, 0x6a, 0xfc, 0xaa, 0x43, 0x46, 0xa6, 0x56, 0x0f, 0x89, - 0x32, 0xb3, 0x18, 0x1f, 0xd3, 0x55, 0xd5, 0xd3, 0x91, 0x97, 0x61, 0x83, 0xf8, 0xd9, - 0x93, 0x88, 0x83, 0x96, 0x32, 0xd6, 0x35, 0x4f, 0x66, 0x6d, 0x09, 0xd3, 0xe5, 0x62, - 0x9e, 0xa1, 0x97, 0x37, 0x38, 0x86, 0x13, 0xd3, 0x8a, 0x34, 0xfd, 0x0f, 0x6e, 0x50, - 0xee, 0x5a, 0x0c, 0xc9, 0x67, 0x71, 0x77, 0xf5, 0x00, 0x28, 0xc1, 0x41, 0x37, 0x81, - 0x87, 0xbd, 0x28, 0x19, 0x40, 0x3f, 0xc5, 0x34, 0xf8, 0x00, 0x76, 0xe9, 0x38, 0x0c, - 0xb4, 0x96, 0x4d, 0x3b, 0x6b, 0x45, 0x81, 0x9d, 0x3b, 0x8e, 0x9c, 0xaf, 0x54, 0xf0, - 0x51, 0x85, 0x2d, 0x67, 0x1b, 0xf8, 0xc1, 0xff, 0xde, 0x2d, 0x15, 0x10, 0x75, 0x64, - 0x18, 0xcb, 0x48, 0x10, 0x93, 0x6a, 0xa5, 0x7e, 0x69, 0x65, 0xd6, 0xfb, 0x65, 0x6a, - 0x76, 0x0b, 0x7f, 0x19, 0xad, 0xf9, 0x6c, 0x17, 0x34, 0x88, 0x55, 0x21, 0x93, 0xb1, - 0x47, 0xee, 0x58, 0x85, 0x80, 0x33, 0xda, 0xc7, 0xcd, 0x0e, 0xb2, 0x04, 0xc0, 0x64, - 0x90, 0xbb, 0xde, 0xdf, 0x5f, 0x75, 0x71, 0xac, 0xb2, 0xeb, 0xe7, 0x6a, 0xce, 0xf3, - 0xf2, 0xa0, 0x1e, 0xe9, 0x87, 0x48, 0x6d, 0xfe, 0x6c, 0x3f, 0x0a, 0x5e, 0x23, 0x4c, - 0x12, 0x72, 0x58, 0xf9, 0x7a, 0x28, 0xfb, 0x5d, 0x16, 0x4a, 0x81, 0x76, 0xbe, 0x94, - 0x6b, 0x80, 0x97, 0xd0, 0xe3, 0x17, 0x28, 0x7f, 0x33, 0xbf, 0x9c, 0x16, 0xf9, 0xa5, - 0x45, 0x40, 0x9c, 0xe2, 0x9b, 0x1f, 0x42, 0x73, 0x72, 0x5f, 0xc0, 0xdf, 0x02, 0xa0, - 0x4e, 0xba, 0xe1, 0x78, 0xb3, 0x41, 0x4f, 0xb0, 0xa8, 0x2d, 0x50, 0xde, 0xb0, 0x9f, - 0xcf, 0x4e, 0x6e, 0xe9, 0xd1, 0x80, 0xff, 0x4f, 0x56, 0xff, 0x3b, 0xc1, 0xd3, 0x60, - 0x1f, 0xc2, 0xdc, 0x90, 0xd8, 0x14, 0xc3, 0x25, 0x6f, 0x49, 0x67, 0xd3, 0xa8, 0xd6, - 0x4c, 0x83, 0xfe, 0xa3, 0x39, 0xc5, 0x1f, 0x5a, 0x8e, 0x58, 0x01, 0xfb, 0xb9, 0x78, - 0x35, 0x58, 0x1b, 0x60, 0x24, 0x65, 0xde, 0xe0, 0x4b, 0x59, 0x22, 0xc2, 0x76, 0x1b, - 0x54, 0x24, 0x5b, 0xec, 0x0c, 0x9e, 0xef, 0x2d, 0xb9, 0x7d, 0x22, 0xb2, 0xb3, 0x55, - 0x6c, 0xc9, 0x69, 0xfb, 0xb1, 0x3d, 0x06, 0x50, 0x97, 0x65, 0xa5, 0x2b, 0x3f, 0xac, - 0x54, 0xb9, 0x3f, 0x42, 0x1b, 0xf0, 0x8e, 0x18, 0xd5, 0x2d, 0xdd, 0x52, 0xcc, 0x1c, - 0x8c, 0xa8, 0xad, 0xfa, 0xcc, 0xab, 0x7e, 0x5c, 0xc2, 0xf4, 0x57, 0x3f, 0xbb, 0xf8, - 0x23, 0x9b, 0xb0, 0xb8, 0xae, 0xdb, 0xf8, 0xda, 0xd1, 0x62, 0x82, 0xda, 0x5c, 0x91, - 0x25, 0xdb, 0xa1, 0xc0, 0x59, 0xd0, 0xdf, 0x8a, 0xbf, 0x62, 0x10, 0x78, 0xf0, 0x2d, - 0x6c, 0x4b, 0xc8, 0x6d, 0x40, 0x84, 0x5a, 0xc1, 0xd5, 0x97, 0x10, 0xc4, 0x5f, 0x07, - 0xd5, 0x85, 0xeb, 0x48, 0xb3, 0x2f, 0xc0, 0x16, 0x7b, 0xa2, 0x56, 0xe7, 0x3c, 0xa3, - 0xb9, 0x31, 0x1c, 0x62, 0xd1, 0x09, 0x49, 0x79, 0x57, 0xd8, 0xdb, 0xe1, 0x0a, 0xa3, - 0xe8, 0x66, 0xb4, 0x0c, 0x0b, 0xaa, 0x2b, 0xc4, 0x92, 0xc1, 0x9a, 0xd1, 0xe6, 0x37, - 0x2d, 0x96, 0x22, 0xbf, 0x16, 0x3f, 0xbf, 0xfe, 0xae, 0xee, 0x79, 0x6a, 0x3c, 0xd9, - 0xb6, 0xfb, 0xbf, 0xa4, 0xd7, 0x92, 0xf3, 0x4d, 0x7f, 0xd6, 0xe7, 0x63, 0xcd, 0x58, - 0x59, 0xdd, 0x26, 0x83, 0x3d, 0x21, 0xd9, 0xbc, 0x54, 0x52, 0xbd, 0x19, 0x51, 0x5d, - 0xff, 0x9f, 0x49, 0x95, 0xb3, 0x5b, 0xc0, 0xc1, 0xf8, 0x76, 0xe6, 0xad, 0x11, 0xf2, - 0x45, 0x2d, 0xc9, 0xae, 0x85, 0xae, 0xc0, 0x1f, 0xc5, 0x6f, 0x8c, 0xbf, 0xda, 0x75, - 0xa7, 0x72, 0x7b, 0x75, 0xeb, 0xbd, 0x6b, 0xbf, 0xfb, 0x43, 0xb6, 0x3a, 0x3b, 0x1b, - 0x67, 0x1e, 0x40, 0xfe, 0xb0, 0xdb, 0x00, 0x29, 0x74, 0xa3, 0xc3, 0xb1, 0xa7, 0x88, - 0x56, 0x72, 0x31, 0xbf, 0x63, 0x99, 0xff, 0x89, 0x23, 0x69, 0x81, 0x14, 0x9d, 0x42, - 0x38, 0x02, 0xd2, 0x34, 0x1a, 0x3b, 0xed, 0xb9, 0xdd, 0xcb, 0xac, 0x1f, 0xe7, 0xb6, - 0x43, 0x5e, 0x14, 0x79, 0xc7, 0x2e, 0x70, 0x89, 0xd0, 0x29, 0xe7, 0xfb, 0xba, 0xf3, - 0xcf, 0x37, 0xe9, 0xb9, 0xa6, 0xb7, 0x76, 0x79, 0x1e, 0x4c, 0x5e, 0x6f, 0xda, 0x57, - 0xe8, 0xd5, 0xf1, 0x4c, 0x8c, 0x35, 0xa2, 0xd2, 0x70, 0x84, 0x6b, 0x9d, 0xbe, 0x00, - 0x5c, 0xda, 0x16, 0xaf, 0x44, 0x08, 0xf3, 0xab, 0x06, 0xa9, 0x16, 0xee, 0xeb, 0x9c, - 0x95, 0x94, 0xb7, 0x04, 0x24, 0xa4, 0xc1, 0xd1, 0x71, 0x29, 0x5b, 0x67, 0x63, 0xb2, - 0x2f, 0x47, 0xf8, 0x0b, 0x53, 0xcc, 0xbb, 0x90, 0x4b, 0xd6, 0x8f, 0xd6, 0x5f, 0xbd, - 0x3f, 0xbd, 0xea, 0x10, 0x35, 0xe9, 0x8c, 0x21, 0xa7, 0xdb, 0xc9, 0x1a, 0x9b, 0x5b, - 0xc7, 0x69, 0x0f, 0x05, 0xec, 0x31, 0x7c, 0x97, 0xf8, 0x76, 0x4e, 0xb4, 0x8e, 0x91, - 0x1d, 0x42, 0x8e, 0xc8, 0xd8, 0x61, 0xb7, 0x08, 0xe8, 0x29, 0x8a, 0xcb, 0x62, 0x15, - 0x51, 0x45, 0x15, 0x5a, 0xe9, 0x5f, 0x0a, 0x1d, 0x15, 0x01, 0x03, 0x47, 0x53, 0x14, - 0x6e, 0x22, 0xd0, 0x5f, 0x58, 0x6d, 0x7f, 0x6b, 0x4f, 0xe1, 0x2d, 0xad, 0x9a, 0x17, - 0xf5, 0xdb, 0x70, 0xb1, 0xdb, 0x96, 0xb8, 0xd9, 0xa8, 0x3e, 0xda, 0xdc, 0x96, 0x6c, - 0x8a, 0x54, 0x66, 0xb6, 0x1f, 0xc9, 0x98, 0xc3, 0x1f, 0x10, 0x70, 0xd9, 0xa5, 0xc9, - 0xa6, 0xd2, 0x68, 0xd3, 0x04, 0xfe, 0x6b, 0x8f, 0xd3, 0xb4, 0x01, 0x03, 0x48, 0x61, - 0x1a, 0xbd, 0xcb, 0xd4, 0x9f, 0xe4, 0xf8, 0x5b, 0x62, 0x3c, 0x78, 0x28, 0xc7, 0x13, - 0x82, 0xe1, 0x03, 0x4e, 0xa6, 0x7b, 0xc8, 0xae, 0x97, 0x40, 0x4b, 0x0c, 0x50, 0xb2, - 0xa0, 0x4f, 0x55, 0x9e, 0x49, 0x95, 0x0a, 0xfc, 0xb0, 0xef, 0x46, 0x2a, 0x2a, 0xe0, - 0x24, 0xb0, 0xf0, 0x22, 0x4d, 0xfd, 0x73, 0x68, 0x4b, 0x88, 0xc7, 0xfb, 0xe9, 0x2d, - 0x02, 0xb6, 0x8f, 0x75, 0x9c, 0x47, 0x52, 0x66, 0x3c, 0xd7, 0xb9, 0x7a, 0x14, 0x94, - 0x36, 0x49, 0x30, 0x55, 0x21, 0x32, 0x6b, 0xde, 0x08, 0x56, 0x30, 0x86, 0x46, 0x29, - 0x29, 0x1b, 0xae, 0x25, 0xff, 0x88, 0x22, 0xa1, 0x4c, 0x4b, 0x66, 0x6a, 0x92, 0x59, - 0xad, 0x0d, 0xc4, 0x2a, 0x82, 0x90, 0xac, 0x7b, 0xc7, 0xf5, 0x3a, 0x16, 0xf3, 0x79, - 0xf7, 0x58, 0xe5, 0xde, 0x75, 0x0f, 0x04, 0xfd, 0x7c, 0xad, 0x47, 0x70, 0x1c, 0x85, - 0x97, 0xf9, 0x78, 0x88, 0xbe, 0xa6, 0xfa, 0x0b, 0xf2, 0x99, 0x99, 0x56, 0xfb, 0xfd, - 0x0e, 0xe6, 0x8e, 0xc3, 0x6e, 0x46, 0x88, 0x80, 0x9a, 0xe2, 0x31, 0xeb, 0x8b, 0xc4, - 0x36, 0x9f, 0x5f, 0xe1, 0x57, 0x3f, 0x57, 0xe0, 0x99, 0xd9, 0xc0, 0x99, 0x01, 0xbf, - 0x39, 0xca, 0xac, 0x48, 0xdc, 0x11, 0x95, 0x6a, 0x8a, 0xe9, 0x05, 0xea, 0xd8, 0x69, - 0x54, 0x54, 0x7c, 0x44, 0x8a, 0xe4, 0x3d, 0x31, 0x5e, 0x66, 0x9c, 0x42, 0x42, 0xda, - 0x56, 0x59, 0x38, 0xf4, 0x17, 0xbf, 0x43, 0xce, 0x7b, 0x2b, 0x30, 0xb1, 0xcd, 0x40, - 0x18, 0x38, 0x8e, 0x1a, 0x91, 0x0f, 0x0f, 0xc4, 0x1f, 0xb0, 0x87, 0x7a, 0x59, 0x25, - 0xe4, 0x66, 0x81, 0x9d, 0x37, 0x5b, 0x0a, 0x91, 0x2d, 0x4f, 0xe8, 0x43, 0xb7, 0x6e, - 0xf6, 0xf2, 0x23, 0xf0, 0xf7, 0xc8, 0x94, 0xf3, 0x8f, 0x7a, 0xb7, 0x80, 0xdf, 0xd7, - 0x5f, 0x66, 0x9c, 0x8c, 0x06, 0xcf, 0xfa, 0x43, 0xeb, 0x47, 0x56, 0x5a, 0x50, 0xe3, - 0xb1, 0xfa, 0x45, 0xad, 0x61, 0xce, 0x9a, 0x1c, 0x47, 0x27, 0xb7, 0xaa, 0xa5, 0x35, - 0x62, 0xf5, 0x23, 0xe7, 0x39, 0x52, - ], - script_code: Script(vec![0x53]), - transparent_input: Some(1), - hash_type: 3, - amount: 365293780364847, - consensus_branch_id: consensus::BranchId::Overwinter, - sighash: [ - 0x23, 0x65, 0x2e, 0x76, 0xcb, 0x13, 0xb8, 0x5a, 0x0e, 0x33, 0x63, 0xbb, 0x5f, 0xca, - 0x06, 0x1f, 0xa7, 0x91, 0xc4, 0x0c, 0x53, 0x3e, 0xcc, 0xee, 0x89, 0x93, 0x64, 0xe6, - 0xe6, 0x0b, 0xb4, 0xf7, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x99, 0xa6, 0x9f, 0xdf, 0x1c, - 0x5a, 0xc7, 0x73, 0x21, 0x46, 0xee, 0x5e, 0x1d, 0x6b, 0x6c, 0xa9, 0xb9, 0x18, 0x0f, - 0x96, 0x4c, 0xc9, 0xd0, 0x87, 0x8a, 0xe1, 0x37, 0x35, 0x24, 0xd7, 0xd5, 0x10, 0xe5, - 0x82, 0x27, 0xdf, 0x09, 0x51, 0x53, 0x63, 0x6a, 0x00, 0x6a, 0xac, 0x51, 0x6a, 0xb0, - 0xf1, 0x85, 0x6e, 0x28, 0xd5, 0xc8, 0xaf, 0xb0, 0x95, 0xef, 0x61, 0x84, 0xfe, 0xd6, - 0x51, 0x58, 0x90, 0x22, 0xee, 0xae, 0xa4, 0xc0, 0xce, 0x1f, 0xa6, 0xf0, 0x85, 0x09, - 0x2b, 0x04, 0x97, 0x94, 0x89, 0x17, 0x2b, 0x3e, 0xf8, 0x19, 0x4a, 0x01, 0x63, 0xf5, - 0x72, 0x4d, 0x6b, 0x02, 0xde, 0xe1, 0x36, 0xf3, 0xa9, 0xaa, 0x02, 0x00, 0x03, 0x52, - 0x52, 0xac, 0x17, 0xb7, 0x3f, 0x8d, 0x38, 0x3e, 0x00, 0x00, 0x06, 0xac, 0x63, 0x00, - 0x53, 0xac, 0x51, 0x04, 0xb4, 0x75, 0x56, 0xaf, 0x73, 0xb6, 0x08, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xe2, 0x32, 0x1d, 0x14, 0x60, 0x71, 0x78, 0x9d, 0x23, 0x35, 0x93, 0x4a, 0x68, 0x06, - 0x14, 0xe8, 0x35, 0x62, 0xf8, 0x2d, 0xfd, 0x40, 0x5b, 0x54, 0xa4, 0x5e, 0xb3, 0x2c, - 0x16, 0x54, 0x48, 0xd4, 0xd5, 0xd6, 0x1c, 0xa2, 0x85, 0x95, 0x85, 0x36, 0x9f, 0x53, - 0xf1, 0xa1, 0x37, 0xe9, 0xe8, 0x2b, 0x67, 0xb8, 0xfd, 0xaf, 0x01, 0xbd, 0xa5, 0x4a, - 0x31, 0x73, 0x11, 0x89, 0x6a, 0xe1, 0x02, 0x80, 0xa0, 0x32, 0x44, 0x0c, 0x42, 0x0a, - 0x42, 0x1e, 0x94, 0x4d, 0x1e, 0x95, 0x2b, 0x70, 0xd5, 0x82, 0x6c, 0xd3, 0xb0, 0x8b, - 0x7d, 0xb9, 0x63, 0x0f, 0xe4, 0xfd, 0x5f, 0x22, 0x12, 0x5d, 0xe8, 0x40, 0xfc, 0xc4, - 0x0b, 0x98, 0x03, 0x8a, 0xf1, 0x1d, 0x55, 0xbe, 0x25, 0x43, 0x25, 0x97, 0xb4, 0xb6, - 0x5b, 0x9e, 0xc1, 0xc7, 0xa8, 0xbb, 0xfd, 0x05, 0x2c, 0xbf, 0x7e, 0x1c, 0x17, 0x85, - 0x31, 0x49, 0x34, 0xb2, 0x62, 0xd5, 0x85, 0x37, 0x54, 0xf1, 0xf1, 0x77, 0x71, 0xcf, - 0xb7, 0x50, 0x30, 0x72, 0x65, 0x57, 0x53, 0xfa, 0x3f, 0x54, 0xec, 0xc5, 0x87, 0xe9, - 0xf8, 0x3b, 0x58, 0x19, 0x16, 0x09, 0x2d, 0xf2, 0x6e, 0x63, 0xe1, 0x89, 0x94, 0xcb, - 0x0d, 0xb9, 0x1a, 0x0b, 0xbd, 0xc7, 0xb6, 0x11, 0x9b, 0x32, 0x22, 0x2a, 0xdf, 0x5e, - 0x61, 0xd8, 0xd8, 0xae, 0x89, 0xda, 0xe4, 0x95, 0x4b, 0x54, 0x81, 0x3b, 0xb3, 0x3f, - 0x08, 0xd5, 0x62, 0xba, 0x51, 0x3f, 0xee, 0x1b, 0x09, 0xc0, 0xfc, 0xd5, 0x16, 0x05, - 0x54, 0x19, 0x47, 0x4d, 0xd7, 0xfd, 0xa0, 0x38, 0xa8, 0x9c, 0x84, 0xea, 0x7b, 0x94, - 0x68, 0x28, 0x7f, 0x0e, 0xb0, 0xc1, 0x0c, 0x4b, 0x13, 0x25, 0x20, 0x19, 0x4d, 0x3d, - 0x8d, 0x53, 0x51, 0xfc, 0x10, 0xd0, 0x9c, 0x15, 0xc8, 0xcc, 0x10, 0x1a, 0xa1, 0x66, - 0x3b, 0xbf, 0x17, 0xb8, 0x41, 0x11, 0xf3, 0x8b, 0xb4, 0x39, 0xf0, 0x73, 0x53, 0xbd, - 0xea, 0x35, 0x96, 0xd1, 0x5e, 0x71, 0x3e, 0x1e, 0x2e, 0x7d, 0x3f, 0x1c, 0x38, 0x31, - 0x35, 0xb4, 0x7f, 0xa7, 0xf8, 0x1f, 0x46, 0xdf, 0x02, 0x90, 0x2a, 0x40, 0x46, 0x99, - 0xec, 0x91, 0x2f, 0x56, 0x56, 0xc3, 0x5b, 0x85, 0x76, 0x3e, 0x4d, 0xe5, 0x83, 0xae, - 0xca, 0xa1, 0xdf, 0xd5, 0xd2, 0x67, 0x7d, 0x9c, 0x8f, 0xfe, 0xe8, 0x77, 0xf6, 0x03, - 0x40, 0xa5, 0xca, 0x0d, 0x67, 0xf6, 0xe5, 0x54, 0x12, 0x47, 0x39, 0xf8, 0x05, 0xaf, - 0x87, 0x6a, 0xee, 0xde, 0x53, 0xaa, 0x8b, 0x0f, 0x8e, 0x56, 0x04, 0xa7, 0x3c, 0x30, - 0xcb, 0xd0, 0x9d, 0xad, 0x0a, 0x3d, 0x6f, 0x8a, 0x5d, 0xcc, 0x40, 0xde, 0xf4, 0x07, - 0x97, 0x34, 0x21, 0x13, 0xba, 0x20, 0x6f, 0xae, 0x8e, 0xbe, 0x4f, 0x3b, 0xc3, 0xca, - 0xf6, 0x92, 0x59, 0xe4, 0x62, 0xef, 0xf9, 0xba, 0x8b, 0x3f, 0x4b, 0xfa, 0xa1, 0x30, - 0x0c, 0x26, 0x92, 0x5a, 0x87, 0x29, 0xcd, 0x32, 0x91, 0x5b, 0xfc, 0x96, 0x60, 0x86, - 0xf0, 0xd5, 0x56, 0x0b, 0xbe, 0x32, 0xa5, 0x98, 0xc2, 0x2a, 0xdf, 0xb4, 0x8c, 0x03, - 0x72, 0xba, 0x5d, 0x42, 0x87, 0xc0, 0xce, 0xfb, 0xac, 0xfd, 0x8c, 0xe1, 0x95, 0xb4, - 0x96, 0x3c, 0x34, 0xa9, 0x4b, 0xba, 0x7a, 0x17, 0x5d, 0xae, 0x4b, 0xbe, 0x3e, 0xf4, - 0x86, 0x3d, 0x53, 0x70, 0x03, 0x15, 0x09, 0x0f, 0x47, 0xa0, 0x68, 0xe2, 0x27, 0x43, - 0x3f, 0x9e, 0x49, 0xd3, 0xaa, 0x09, 0xe3, 0x56, 0xd8, 0xd6, 0x6d, 0x0c, 0x01, 0x21, - 0xe9, 0x1a, 0x3c, 0x4a, 0xa3, 0xf2, 0x7f, 0xa1, 0xb6, 0x03, 0x96, 0xe2, 0xb4, 0x1d, - 0xb9, 0x08, 0xfd, 0xab, 0x8b, 0x18, 0xcc, 0x73, 0x04, 0xe9, 0x4e, 0x97, 0x05, 0x68, - 0xf9, 0x42, 0x1c, 0x0d, 0xbb, 0xba, 0xf8, 0x45, 0x98, 0xd9, 0x72, 0xb0, 0x53, 0x4f, - 0x02, 0xa5, 0xe5, 0x26, 0x70, 0x43, 0x6a, 0xaa, 0x77, 0x6e, 0xd2, 0x48, 0x2a, 0xd7, - 0x03, 0x43, 0x02, 0x01, 0xe5, 0x34, 0x43, 0xc3, 0x6d, 0xcf, 0xd3, 0x4a, 0x0c, 0xb6, - 0x63, 0x78, 0x76, 0x10, 0x5e, 0x03, 0xbf, 0x3b, 0xd5, 0x8e, 0xc1, 0x48, 0xcb, 0x64, - 0x97, 0x0e, 0x32, 0x23, 0xa9, 0x1f, 0x71, 0xdf, 0xcf, 0xd5, 0xa0, 0x4b, 0x66, 0x7f, - 0xba, 0xf3, 0xd4, 0xb3, 0xb9, 0x08, 0xb9, 0x82, 0x88, 0x20, 0xdf, 0xec, 0xdd, 0x75, - 0x37, 0x50, 0xb5, 0xf9, 0xd2, 0x21, 0x6e, 0x56, 0xc6, 0x15, 0x27, 0x2f, 0x85, 0x44, - 0x64, 0xc0, 0xca, 0x4b, 0x1e, 0x85, 0xae, 0xdd, 0x03, 0x82, 0x92, 0xc4, 0xe1, 0xa5, - 0x77, 0x44, 0xeb, 0xba, 0x01, 0x0b, 0x9e, 0xbf, 0xbb, 0x01, 0x1b, 0xd6, 0xf0, 0xb7, - 0x88, 0x05, 0x02, 0x5d, 0x27, 0xf3, 0xc1, 0x77, 0x46, 0xba, 0xe1, 0x16, 0xc1, 0x5d, - 0x9f, 0x47, 0x1f, 0x0f, 0x62, 0x88, 0xa1, 0x50, 0x64, 0x7b, 0x2a, 0xfe, 0x9d, 0xf7, - 0xcc, 0xcf, 0x01, 0xf5, 0xcd, 0xe5, 0xf0, 0x46, 0x80, 0xbb, 0xfe, 0xd8, 0x7f, 0x6c, - 0xf4, 0x29, 0xfb, 0x27, 0xad, 0x6b, 0xab, 0xe7, 0x91, 0x76, 0x66, 0x11, 0xcf, 0x5b, - 0xc2, 0x0e, 0x48, 0xbe, 0xf1, 0x19, 0x25, 0x9b, 0x9b, 0x8a, 0x0e, 0x39, 0xc3, 0xdf, - 0x28, 0xcb, 0x95, 0x82, 0xea, 0x33, 0x86, 0x01, 0xcd, 0xc4, 0x81, 0xb3, 0x2f, 0xb8, - 0x2a, 0xde, 0xeb, 0xb3, 0xda, 0xde, 0x25, 0xd1, 0xa3, 0xdf, 0x20, 0xc3, 0x7e, 0x71, - 0x25, 0x06, 0xb5, 0xd9, 0x96, 0xc4, 0x9a, 0x9f, 0x0f, 0x30, 0xdd, 0xcb, 0x91, 0xfe, - 0x90, 0x04, 0xe1, 0xe8, 0x32, 0x94, 0xa6, 0xc9, 0x20, 0x3d, 0x94, 0xe8, 0xdc, 0x2c, - 0xbb, 0x44, 0x9d, 0xe4, 0x15, 0x50, 0x32, 0x60, 0x4e, 0x47, 0x99, 0x70, 0x16, 0xb3, - 0x04, 0xfd, 0x43, 0x7d, 0x82, 0x35, 0x04, 0x5e, 0x25, 0x5a, 0x19, 0xb7, 0x43, 0xa0, - 0xa9, 0xf2, 0xe3, 0x36, 0xb4, 0x4c, 0xae, 0x30, 0x7b, 0xb3, 0x98, 0x7b, 0xd3, 0xe4, - 0xe7, 0x77, 0xfb, 0xb3, 0x4c, 0x0a, 0xb8, 0xcc, 0x3d, 0x67, 0x46, 0x6c, 0x0a, 0x88, - 0xdd, 0x4c, 0xca, 0xd1, 0x8a, 0x07, 0xa8, 0xd1, 0x06, 0x8d, 0xf5, 0xb6, 0x29, 0xe5, - 0x71, 0x8d, 0x0f, 0x6d, 0xf5, 0xc9, 0x57, 0xcf, 0x71, 0xbb, 0x00, 0xa5, 0x17, 0x8f, - 0x17, 0x5c, 0xac, 0xa9, 0x44, 0xe6, 0x35, 0xc5, 0x15, 0x9f, 0x73, 0x8e, 0x24, 0x02, - 0xa2, 0xd2, 0x1a, 0xa0, 0x81, 0xe1, 0x0e, 0x45, 0x6a, 0xfb, 0x00, 0xb9, 0xf6, 0x24, - 0x16, 0xc8, 0xb9, 0xc0, 0xf7, 0x22, 0x8f, 0x51, 0x07, 0x29, 0xe0, 0xbe, 0x3f, 0x30, - 0x53, 0x13, 0xd7, 0x7f, 0x73, 0x79, 0xdc, 0x2a, 0xf2, 0x48, 0x69, 0xc6, 0xc7, 0x4e, - 0xe4, 0x47, 0x14, 0x98, 0x86, 0x1d, 0x19, 0x2f, 0x0f, 0xf0, 0xf5, 0x08, 0x28, 0x5d, - 0xab, 0x6b, 0x6a, 0x36, 0xcc, 0xf7, 0xd1, 0x22, 0x56, 0xcc, 0x76, 0xb9, 0x55, 0x03, - 0x72, 0x0a, 0xc6, 0x72, 0xd0, 0x82, 0x68, 0xd2, 0xcf, 0x77, 0x73, 0xb6, 0xba, 0x2a, - 0x5f, 0x66, 0x48, 0x47, 0xbf, 0x70, 0x7f, 0x2f, 0xc1, 0x0c, 0x98, 0xf2, 0xf0, 0x06, - 0xec, 0x22, 0xcc, 0xb5, 0xa8, 0xc8, 0xb7, 0xc4, 0x0c, 0x7c, 0x2d, 0x49, 0xa6, 0x63, - 0x9b, 0x9f, 0x2c, 0xe3, 0x3c, 0x25, 0xc0, 0x4b, 0xc4, 0x61, 0xe7, 0x44, 0xdf, 0xa5, - 0x36, 0xb0, 0x0d, 0x94, 0xba, 0xdd, 0xf4, 0xf4, 0xd1, 0x40, 0x44, 0xc6, 0x95, 0xa3, - 0x38, 0x81, 0x47, 0x7d, 0xf1, 0x24, 0xf0, 0xfc, 0xf2, 0x06, 0xa9, 0xfb, 0x2e, 0x65, - 0xe3, 0x04, 0xcd, 0xbf, 0x0c, 0x4d, 0x23, 0x90, 0x17, 0x0c, 0x13, 0x0a, 0xb8, 0x49, - 0xc2, 0xf2, 0x2b, 0x5c, 0xdd, 0x39, 0x21, 0x64, 0x0c, 0x8c, 0xf1, 0x97, 0x6a, 0xe1, - 0x01, 0x0b, 0x0d, 0xfd, 0x9c, 0xb2, 0x54, 0x3e, 0x45, 0xf9, 0x97, 0x49, 0xcc, 0x4d, - 0x61, 0xf2, 0xe8, 0xaa, 0xbf, 0xe9, 0x8b, 0xd9, 0x05, 0xfa, 0x39, 0x95, 0x1b, 0x33, - 0xea, 0x76, 0x9c, 0x45, 0xab, 0x95, 0x31, 0xc5, 0x72, 0x09, 0x86, 0x2a, 0xd1, 0x2f, - 0xd7, 0x6b, 0xa4, 0x80, 0x7e, 0x65, 0x41, 0x7b, 0x6c, 0xd1, 0x2f, 0xa8, 0xec, 0x91, - 0x6f, 0x01, 0x3e, 0xbb, 0x87, 0x06, 0xa9, 0x6e, 0xff, 0xed, 0xa0, 0x6c, 0x4b, 0xe2, - 0x4b, 0x04, 0x84, 0x63, 0x92, 0xe9, 0xd1, 0xe6, 0x93, 0x0e, 0xae, 0x01, 0xfa, 0x21, - 0xfb, 0xd7, 0x00, 0x58, 0x3f, 0xb5, 0x98, 0xb9, 0x2c, 0x8f, 0x4e, 0xb8, 0xa6, 0x1a, - 0xa6, 0x23, 0x5d, 0xb6, 0x0f, 0x28, 0x41, 0xcf, 0x3a, 0x1c, 0x6a, 0xb5, 0x4c, 0x67, - 0x06, 0x68, 0x44, 0x71, 0x1d, 0x09, 0x1e, 0xb9, 0x31, 0xa1, 0xbd, 0x62, 0x81, 0xae, - 0xdf, 0x2a, 0x0e, 0x8f, 0xab, 0x18, 0x81, 0x72, 0x02, 0xa9, 0xbe, 0x06, 0x40, 0x2e, - 0xd9, 0xcc, 0x72, 0x0c, 0x16, 0xbf, 0xe8, 0x81, 0xe4, 0xdf, 0x42, 0x55, 0xe8, 0x7a, - 0xfb, 0x7f, 0xc6, 0x2f, 0x38, 0x11, 0x6b, 0xbe, 0x03, 0xcd, 0x8a, 0x3c, 0xb1, 0x1a, - 0x27, 0xd5, 0x68, 0x41, 0x47, 0x82, 0xf4, 0x7b, 0x1a, 0x44, 0xc9, 0x7c, 0x68, 0x04, - 0x67, 0x69, 0x4b, 0xc9, 0x70, 0x9d, 0x32, 0x91, 0x6c, 0x97, 0xe8, 0x00, 0x6c, 0xbb, - 0x07, 0xba, 0x0e, 0x41, 0x80, 0xa3, 0x73, 0x80, 0x38, 0xc3, 0x74, 0xc4, 0xcc, 0xe8, - 0xf3, 0x29, 0x59, 0xaf, 0xb2, 0x5f, 0x30, 0x3f, 0x58, 0x15, 0xc4, 0x53, 0x31, 0x24, - 0xac, 0xf9, 0xd1, 0x89, 0x40, 0xe7, 0x75, 0x22, 0xac, 0x5d, 0xc4, 0xb9, 0x57, 0x0a, - 0xae, 0x8f, 0x47, 0xb7, 0xf5, 0x7f, 0xd8, 0x76, 0x7b, 0xea, 0x1a, 0x24, 0xae, 0x7b, - 0xed, 0x65, 0xb4, 0xaf, 0xdc, 0x8f, 0x12, 0x78, 0xc3, 0x0e, 0x2d, 0xb9, 0x8f, 0xd1, - 0x72, 0x73, 0x0a, 0xc6, 0xbb, 0xed, 0x4f, 0x11, 0x27, 0xcd, 0x32, 0xb0, 0x4a, 0x95, - 0xb2, 0x05, 0x52, 0x6c, 0xfc, 0xb4, 0xc4, 0xe1, 0xcc, 0x95, 0x51, 0x75, 0xb3, 0xe8, - 0xde, 0x1f, 0x5d, 0x81, 0xb1, 0x86, 0x69, 0x69, 0x23, 0x50, 0xaa, 0xa1, 0xa1, 0xd7, - 0x97, 0x61, 0x75, 0x82, 0xe5, 0x4d, 0x7a, 0x5b, 0x57, 0xa6, 0x83, 0xb3, 0x2f, 0xb1, - 0x09, 0x80, 0x62, 0xda, 0xd7, 0xb0, 0xc2, 0xeb, 0x51, 0x8f, 0x68, 0x62, 0xe8, 0x3d, - 0xb2, 0x5e, 0x3d, 0xba, 0xf7, 0xae, 0xd5, 0x04, 0xde, 0x93, 0x2a, 0xcb, 0x99, 0xd7, - 0x35, 0x99, 0x2c, 0xe6, 0x2b, 0xae, 0x9e, 0xf8, 0x93, 0xff, 0x6a, 0xcc, 0x0f, 0xfc, - 0xf8, 0xe3, 0x48, 0x3e, 0x14, 0x6b, 0x9d, 0x49, 0xdd, 0x8c, 0x78, 0x35, 0xf4, 0x3a, - 0x37, 0xdc, 0xa0, 0x78, 0x7e, 0x3e, 0xc9, 0xf6, 0x60, 0x52, 0x23, 0xd5, 0xba, 0x7a, - 0xe0, 0xab, 0x90, 0x25, 0xb7, 0x3b, 0xc0, 0x3f, 0x7f, 0xac, 0x36, 0xc0, 0x09, 0xa5, - 0x6d, 0x4d, 0x95, 0xd1, 0xe8, 0x1d, 0x3b, 0x3e, 0xbc, 0xa7, 0xe5, 0x4c, 0xc1, 0xa1, - 0x2d, 0x12, 0x7b, 0x57, 0xc8, 0x13, 0x89, 0x76, 0xe7, 0x91, 0x01, 0x3b, 0x01, 0x5f, - 0x06, 0xa6, 0x24, 0xf5, 0x21, 0xb6, 0xee, 0x04, 0xec, 0x98, 0x08, 0x93, 0xc7, 0xe5, - 0xe0, 0x1a, 0x33, 0x62, 0x03, 0x59, 0x40, 0x94, 0xf8, 0x28, 0x33, 0xd7, 0x44, 0x5f, - 0xe2, 0xd0, 0x91, 0x30, 0xf6, 0x35, 0x11, 0xda, 0x54, 0x83, 0x2d, 0xe9, 0x13, 0x6b, - 0x39, 0xf4, 0x59, 0x9f, 0x5a, 0xa5, 0xdf, 0xbb, 0x45, 0xda, 0x60, 0xcd, 0xce, 0xab, - 0x7e, 0xef, 0xde, 0x89, 0xbe, 0x63, 0xf3, 0xf7, 0xc0, 0xd2, 0x32, 0x48, 0x47, 0xcc, - 0xe1, 0x40, 0x5d, 0xef, 0x7c, 0x46, 0x9b, 0x0e, 0x27, 0x24, 0x94, 0xe5, 0xdf, 0x54, - 0xf5, 0x68, 0x65, 0x6c, 0xb9, 0xc8, 0x81, 0x8d, 0x92, 0xb7, 0x2b, 0x8b, 0xc3, 0x4d, - 0xb7, 0xbb, 0x31, 0x12, 0x48, 0x7e, 0x74, 0x6e, 0xef, 0xe4, 0xe8, 0x08, 0xbb, 0xb2, - 0x87, 0xd9, 0x9b, 0xf0, 0x7d, 0x00, 0xda, 0xbe, 0xde, 0xdc, 0x5e, 0x5f, 0x07, 0x4f, - 0xfe, 0xae, 0x0c, 0xba, 0x7d, 0xa3, 0xa5, 0x16, 0xc1, 0x73, 0xbe, 0x1c, 0x51, 0x33, - 0x23, 0xe1, 0x19, 0xf6, 0x35, 0xe8, 0x20, 0x9a, 0x07, 0x4b, 0x21, 0x6b, 0x70, 0x23, - 0xfa, 0xdc, 0x2d, 0x25, 0x94, 0x9c, 0x90, 0x03, 0x7e, 0x71, 0xe3, 0xe5, 0x50, 0x72, - 0x6d, 0x21, 0x0a, 0x2c, 0x68, 0x83, 0x42, 0xe5, 0x24, 0x40, 0x63, 0x5e, 0x9c, 0xc1, - 0x4a, 0xfe, 0x10, 0x10, 0x26, 0x21, 0xa9, 0xc9, 0xac, 0xcb, 0x78, 0x2e, 0x9e, 0x4a, - 0x5f, 0xa8, 0x7f, 0x0a, 0x95, 0x6f, 0x5b, 0x85, 0x50, 0x99, 0x60, 0x28, 0x5c, 0x22, - 0x62, 0x7c, 0x59, 0x48, 0x3a, 0x5a, 0x4c, 0x28, 0xcc, 0xe4, 0xb1, 0x56, 0xe5, 0x51, - 0x40, 0x6a, 0x7e, 0xe8, 0x35, 0x56, 0x56, 0xa2, 0x1e, 0x43, 0xe3, 0x8c, 0xe1, 0x29, - 0xfd, 0xad, 0xb7, 0x59, 0xed, 0xdf, 0xa0, 0x8f, 0x00, 0xfc, 0x8e, 0x56, 0x7c, 0xef, - 0x93, 0xc6, 0x79, 0x2d, 0x01, 0xdf, 0x05, 0xe6, 0xd5, 0x80, 0xf4, 0xd5, 0xd4, 0x8d, - 0xf0, 0x42, 0x45, 0x1a, 0x33, 0x59, 0x0d, 0x3e, 0x8c, 0xf4, 0x9b, 0x26, 0x27, 0x21, - 0x8f, 0x0c, 0x29, 0x2f, 0xa6, 0x6a, 0xda, 0x94, 0x5f, 0xa5, 0x5b, 0xb2, 0x35, 0x48, - 0xe3, 0x3a, 0x83, 0xa5, 0x62, 0x95, 0x7a, 0x31, 0x49, 0xa9, 0x93, 0xcc, 0x47, 0x23, - 0x62, 0x29, 0x87, 0x36, 0xa8, 0xb7, 0x78, 0xd9, 0x7c, 0xe4, 0x23, 0x01, 0x3d, 0x64, - 0xb3, 0x2c, 0xd1, 0x72, 0xef, 0xa5, 0x51, 0xbf, 0x7f, 0x36, 0x8f, 0x04, 0xbd, 0xae, - 0xc6, 0x09, 0x1a, 0x30, 0x04, 0xa7, 0x57, 0x59, 0x8b, 0x80, 0x1d, 0xcf, 0x67, 0x5c, - 0xb8, 0x3e, 0x43, 0xa5, 0x3a, 0xe8, 0xb2, 0x54, 0xd3, 0x33, 0xbc, 0xda, 0x20, 0xd4, - 0x81, 0x7d, 0x34, 0x77, 0xab, 0xfb, 0xa2, 0x5b, 0xb8, 0x3d, 0xf5, 0x94, 0x9c, 0x12, - 0x6f, 0x14, 0x9b, 0x1d, 0x99, 0x34, 0x1e, 0x4e, 0x6f, 0x91, 0x20, 0xf4, 0xd4, 0x1e, - 0x62, 0x91, 0x85, 0x00, 0x2c, 0x72, 0xc0, 0x12, 0xc4, 0x14, 0xd2, 0x38, 0x2a, 0x6d, - 0x47, 0xc7, 0xb3, 0xde, 0xab, 0xa7, - ], - script_code: Script(vec![0xac, 0x00]), - transparent_input: Some(0), - hash_type: 3, - amount: 711752082734717, - consensus_branch_id: consensus::BranchId::Overwinter, - sighash: [ - 0xb3, 0x8e, 0x31, 0x70, 0x8c, 0xb7, 0x8e, 0xee, 0xc7, 0x66, 0x3e, 0xca, 0x1e, 0x01, - 0xb7, 0x53, 0x9e, 0x26, 0xb7, 0x30, 0xcf, 0x44, 0x6d, 0x3b, 0xf5, 0x7a, 0x99, 0x8e, - 0x9e, 0xd9, 0x2b, 0x47, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x00, 0x02, 0x0d, 0x38, 0x6a, 0xe3, - 0x0d, 0xd3, 0x01, 0x00, 0x07, 0x00, 0x65, 0x51, 0x65, 0x53, 0x53, 0x6a, 0xd5, 0x09, - 0x42, 0xf7, 0x69, 0x67, 0x02, 0x00, 0x05, 0xac, 0x65, 0x63, 0x65, 0xac, 0x61, 0xa7, - 0xb8, 0xb9, 0xf6, 0x99, 0xd6, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x49, 0x23, 0x2f, 0x32, - 0x9f, 0xef, 0x95, 0xc7, 0xaf, 0x37, 0x00, 0x98, 0xff, 0xe4, 0x91, 0x8e, 0x0c, 0xa1, - 0xdf, 0x47, 0xf2, 0x75, 0x86, 0x7b, 0x73, 0x9e, 0x0a, 0x51, 0x4d, 0x32, 0x09, 0x32, - 0x5e, 0x21, 0x70, 0x45, 0x92, 0x7b, 0x47, 0x9c, 0x1c, 0xe2, 0xe5, 0xd5, 0x4f, 0x25, - 0x48, 0x8c, 0xad, 0x15, 0x13, 0xe3, 0xf4, 0x4a, 0x21, 0x26, 0x6c, 0xfd, 0x84, 0x16, - 0x33, 0x32, 0x7d, 0xee, 0x6c, 0xf8, 0x10, 0xfb, 0xf7, 0x39, 0x3e, 0x31, 0x7d, 0x9e, - 0x53, 0xd1, 0xbe, 0x1d, 0x5a, 0xe7, 0x83, 0x9b, 0x66, 0xb9, 0x43, 0xb9, 0xed, 0x18, - 0xf2, 0xc5, 0x30, 0xe9, 0x75, 0x42, 0x23, 0x32, 0xc3, 0x43, 0x9c, 0xce, 0x49, 0xa2, - 0x9f, 0x2a, 0x33, 0x6a, 0x48, 0x51, 0x26, 0x3c, 0x5e, 0x9b, 0xd1, 0x3d, 0x73, 0x11, - 0x09, 0xe8, 0x44, 0xb7, 0xf8, 0xc3, 0x92, 0xa5, 0xc1, 0xdc, 0xaa, 0x2a, 0xe5, 0xf5, - 0x0f, 0xf6, 0x3f, 0xab, 0x97, 0x65, 0xe0, 0x16, 0x70, 0x2c, 0x35, 0xa6, 0x7c, 0xd7, - 0x36, 0x4d, 0x3f, 0xab, 0x55, 0x2f, 0xb3, 0x49, 0xe3, 0x5c, 0x15, 0xc5, 0x02, 0x50, - 0x45, 0x3f, 0xd1, 0x8f, 0x7b, 0x85, 0x59, 0x92, 0x63, 0x2e, 0x2c, 0x76, 0xc0, 0xfb, - 0xf1, 0xef, 0x96, 0x3e, 0xa8, 0x0e, 0x32, 0x23, 0xde, 0x32, 0x77, 0xbc, 0x55, 0x92, - 0x51, 0x72, 0x58, 0x29, 0xec, 0x03, 0xf2, 0x13, 0xba, 0x89, 0x55, 0xca, 0xb2, 0x82, - 0x2f, 0xf2, 0x1a, 0x9b, 0x0a, 0x49, 0x04, 0xd6, 0x68, 0xfc, 0xd7, 0x72, 0x24, 0xbd, - 0xe3, 0xdd, 0x01, 0xf6, 0xff, 0xc4, 0x82, 0x8f, 0x6b, 0x64, 0x23, 0x0b, 0x35, 0xc6, - 0xa0, 0x49, 0x87, 0x34, 0x94, 0x27, 0x6e, 0xa1, 0xd7, 0xed, 0x5e, 0x92, 0xcb, 0x4f, - 0x90, 0xba, 0x83, 0xa9, 0xe4, 0x96, 0x01, 0xb1, 0x94, 0x04, 0x2f, 0x29, 0x00, 0xd9, - 0x9d, 0x31, 0x2d, 0x7b, 0x70, 0x50, 0x8c, 0xf1, 0x76, 0x06, 0x6d, 0x15, 0x4d, 0xbe, - 0x96, 0xef, 0x9d, 0x43, 0x67, 0xe4, 0xc8, 0x40, 0xe4, 0xa1, 0x7b, 0x5e, 0x51, 0x22, - 0xe8, 0xeb, 0xe2, 0x03, 0x8a, 0x3c, 0x5f, 0x4c, 0xba, 0xe2, 0x1e, 0xa3, 0xfa, 0x1a, - 0xe6, 0xc2, 0x5a, 0x94, 0x62, 0xeb, 0xcb, 0xb0, 0xfd, 0x5f, 0x14, 0x55, 0x4b, 0xc9, - 0x77, 0x47, 0xc3, 0x3e, 0x34, 0xda, 0x90, 0xc8, 0x02, 0xd8, 0xd0, 0xd5, 0x0b, 0xfe, - 0x37, 0x61, 0x8c, 0x58, 0x12, 0x89, 0x14, 0x84, 0xfa, 0x25, 0x93, 0x22, 0xc1, 0x50, - 0x92, 0xd4, 0x15, 0x5d, 0x86, 0x96, 0xd6, 0xf1, 0x2f, 0x24, 0xfd, 0x36, 0x44, 0x0a, - 0xb3, 0xbe, 0x08, 0x71, 0xca, 0x3d, 0xd9, 0x62, 0x53, 0x48, 0xa6, 0x14, 0xb5, 0x9b, - 0xde, 0x45, 0x88, 0x56, 0x49, 0xba, 0xe3, 0x6d, 0xe3, 0x4d, 0xef, 0x8f, 0xce, 0xc8, - 0x53, 0x43, 0x47, 0x5d, 0x97, 0x6a, 0xe1, 0xe9, 0xb2, 0x78, 0x29, 0xce, 0x2a, 0xc5, - 0xef, 0xd0, 0xb3, 0x99, 0xa8, 0xb4, 0x48, 0xbe, 0x65, 0x04, 0x29, 0x4e, 0xe6, 0xb3, - 0xc1, 0xc6, 0xa5, 0x34, 0x2d, 0x7c, 0x01, 0xae, 0x03, 0x8a, 0xd3, 0x07, 0x0c, 0x2b, - 0x1a, 0x91, 0x57, 0x3a, 0xf5, 0xe0, 0xc5, 0xe4, 0xcb, 0xbf, 0x4a, 0xcd, 0xc6, 0xb5, - 0x4c, 0x92, 0x72, 0x20, 0x0d, 0x99, 0x70, 0x25, 0x0c, 0x17, 0xc1, 0x03, 0x6f, 0x02, - 0x08, 0x5c, 0x41, 0x85, 0x8e, 0xd3, 0xa0, 0xc4, 0x81, 0x50, 0xbc, 0x69, 0x7e, 0x4a, - 0x69, 0x5f, 0xef, 0x33, 0x5f, 0x7a, 0xd0, 0x7e, 0x1a, 0x46, 0xdc, 0x76, 0x7f, 0xf8, - 0x22, 0xdb, 0x70, 0xe6, 0x02, 0x90, 0x80, 0xb9, 0x81, 0x6b, 0x22, 0x32, 0xc8, 0x1a, - 0x4c, 0x66, 0xcc, 0x58, 0x6a, 0xbf, 0xe1, 0xea, 0xa8, 0xca, 0x6c, 0xf4, 0x1f, 0xc3, - 0xc3, 0xe6, 0xc7, 0xb8, 0x86, 0xfb, 0x6d, 0xac, 0x9f, 0x02, 0x22, 0xb4, 0xfc, 0x6f, - 0xff, 0x9d, 0x05, 0x13, 0xd6, 0x1a, 0x21, 0xc8, 0x0a, 0x37, 0x76, 0x71, 0xd1, 0x35, - 0xa6, 0x68, 0xa0, 0xae, 0x2b, 0xb9, 0x34, 0xc8, 0x2c, 0x41, 0x42, 0xda, 0x69, 0xd1, - 0x02, 0xa7, 0xde, 0x9a, 0x7d, 0xf7, 0x06, 0x40, 0x0e, 0xc7, 0x98, 0x78, 0xd8, 0x68, - 0xe1, 0x7e, 0x8f, 0x71, 0xea, 0x31, 0x49, 0x5a, 0xf8, 0x19, 0xa0, 0x16, 0xcc, 0x41, - 0x9e, 0x07, 0xc5, 0x01, 0xaa, 0x83, 0x09, 0xb2, 0xe6, 0xc8, 0x5b, 0x79, 0xb2, 0x76, - 0x37, 0x33, 0xa3, 0x7b, 0xbc, 0x04, 0x20, 0xd4, 0x25, 0x37, 0xb8, 0x71, 0xb4, 0x29, - 0x4a, 0x65, 0xd3, 0xe0, 0x55, 0xff, 0x71, 0x8d, 0xd9, 0xdc, 0x8c, 0x75, 0xe7, 0xe5, - 0xb2, 0xef, 0xe4, 0x42, 0x63, 0x73, 0x71, 0xb7, 0xc4, 0x8f, 0x6e, 0xe9, 0x9e, 0x3e, - 0xa3, 0x8a, 0x4b, 0x0f, 0x2f, 0x67, 0xfc, 0x2b, 0x90, 0x8c, 0xda, 0x65, 0x7e, 0xae, - 0x75, 0x4e, 0x03, 0x7e, 0x26, 0x2e, 0x9a, 0x9f, 0x9b, 0xd7, 0xec, 0x42, 0x67, 0xed, - 0x8e, 0x96, 0x93, 0x0e, 0x10, 0x84, 0x78, 0x3c, 0x37, 0xd6, 0xf9, 0xdd, 0x15, 0xfd, - 0x29, 0xf4, 0xcc, 0x47, 0x7e, 0x66, 0xf1, 0x30, 0xd6, 0x30, 0x43, 0x0d, 0xcc, 0x01, - 0x04, 0x89, 0x9b, 0x4f, 0x9f, 0x46, 0xeb, 0x09, 0x0e, 0xf7, 0xfc, 0x90, 0xb4, 0x79, - 0xab, 0xf6, 0x1f, 0x93, 0x95, 0x5e, 0xe0, 0x0e, 0x6a, 0x18, 0x48, 0xf1, 0xab, 0x14, - 0xad, 0x33, 0x4f, 0x2b, 0x68, 0x03, 0x58, 0x08, 0xcd, 0xf1, 0xbb, 0x9e, 0x9d, 0x9a, - 0x81, 0x6b, 0xaf, 0x72, 0x8a, 0x95, 0x5b, 0x96, 0x0b, 0x77, 0x01, 0xfa, 0x62, 0x66, - 0x87, 0xdc, 0x3c, 0x9c, 0xba, 0x64, 0x63, 0x37, 0xb5, 0x3e, 0x29, 0x81, 0x6e, 0x94, - 0x82, 0xdd, 0xf5, 0x57, 0x8a, 0x87, 0x68, 0xaa, 0xe4, 0x77, 0xfc, 0xe4, 0x10, 0xac, - 0x2d, 0x5d, 0xe6, 0x09, 0x58, 0x61, 0xc1, 0x11, 0xd7, 0xfe, 0xb3, 0xe6, 0xbb, 0x4f, - 0xbb, 0x5a, 0x54, 0x95, 0x54, 0x95, 0x97, 0x27, 0x98, 0x35, 0x0a, 0x25, 0x3f, 0x05, - 0xf6, 0x6c, 0x2e, 0xcf, 0xcb, 0xc0, 0xed, 0x43, 0xf5, 0xec, 0x2e, 0x6d, 0x8d, 0xba, - 0x15, 0xa5, 0x12, 0x54, 0xd9, 0x7b, 0x18, 0x21, 0x10, 0x7c, 0x07, 0xdd, 0x9a, 0x16, - 0xef, 0x84, 0x06, 0xf9, 0x43, 0xe2, 0x82, 0xb9, 0x5d, 0x4b, 0x36, 0x25, 0x30, 0xc9, - 0x13, 0xd6, 0xba, 0x42, 0x1d, 0xf6, 0x02, 0x7d, 0xe5, 0xaf, 0x1e, 0x47, 0x45, 0xd5, - 0x86, 0x81, 0x06, 0x95, 0x4b, 0xe6, 0xc1, 0x96, 0x27, 0x80, 0xa2, 0x94, 0x10, 0x72, - 0xe9, 0x51, 0x31, 0xb1, 0x67, 0x9d, 0xf0, 0x63, 0x76, 0x25, 0x04, 0x2c, 0x37, 0xd4, - 0x8f, 0xfb, 0x15, 0x2e, 0x5e, 0xbc, 0x18, 0x5c, 0x8a, 0x2b, 0x7d, 0x43, 0x85, 0xf1, - 0xc9, 0x5a, 0xf9, 0x37, 0xdf, 0x78, 0xdf, 0xd8, 0x75, 0x7f, 0xab, 0x43, 0x49, 0x68, - 0xb0, 0xb5, 0x7c, 0x66, 0x57, 0x44, 0x68, 0xf1, 0x60, 0xb4, 0x47, 0xac, 0x82, 0x21, - 0xe5, 0x06, 0x06, 0x76, 0xa8, 0x42, 0xa1, 0xc6, 0xb7, 0x17, 0x2d, 0xd3, 0x34, 0x0f, - 0x76, 0x40, 0x70, 0xab, 0x1f, 0xe0, 0x91, 0xc5, 0xc7, 0x4c, 0x95, 0xa5, 0xdc, 0x04, - 0x33, 0x90, 0x72, 0x3a, 0x4c, 0x12, 0x7d, 0xa1, 0x4c, 0xdd, 0xe1, 0xdc, 0x26, 0x75, - 0xa6, 0x23, 0x40, 0xb3, 0xe6, 0xaf, 0xd0, 0x52, 0x2a, 0x31, 0xde, 0x26, 0xe7, 0xd1, - 0xec, 0x3a, 0x9c, 0x8a, 0x09, 0x1f, 0xfd, 0xc7, 0x5b, 0x7e, 0xcf, 0xdc, 0x7c, 0x12, - 0x99, 0x5a, 0x5e, 0x37, 0xce, 0x34, 0x88, 0xbd, 0x29, 0xf8, 0x62, 0x9d, 0x68, 0xf6, - 0x96, 0x49, 0x24, 0x48, 0xdd, 0x52, 0x66, 0x97, 0x47, 0x6d, 0xc0, 0x61, 0x34, 0x6e, - 0xbe, 0x3f, 0x67, 0x72, 0x17, 0xff, 0x9c, 0x60, 0xef, 0xce, 0x94, 0x3a, 0xf2, 0x8d, - 0xfd, 0x3f, 0x9e, 0x59, 0x69, 0x25, 0x98, 0xa6, 0x04, 0x7c, 0x23, 0xc4, 0xc0, 0x14, - 0x00, 0xf1, 0xab, 0x57, 0x30, 0xea, 0xc0, 0xae, 0x8d, 0x58, 0x43, 0xd5, 0x05, 0x1c, - 0x37, 0x62, 0x40, 0x17, 0x2a, 0xf2, 0x18, 0xd7, 0xa1, 0xec, 0xfe, 0x65, 0xb4, 0xf7, - 0x51, 0x00, 0x63, 0x89, 0x83, 0xc1, 0x4d, 0xe4, 0x97, 0x47, 0x55, 0xda, 0xde, 0x80, - 0x18, 0xc9, 0xb8, 0xf4, 0x54, 0x3f, 0xb0, 0x95, 0x96, 0x15, 0x13, 0xe6, 0x7c, 0x61, - 0xdb, 0xc5, 0x9c, 0x60, 0x7f, 0x9b, 0x51, 0xf8, 0xd0, 0x9b, 0xdc, 0xad, 0x28, 0xbc, - 0xfb, 0x9e, 0x5d, 0x27, 0x44, 0xea, 0x88, 0x48, 0xb2, 0x62, 0x3a, 0xc0, 0x7f, 0x8e, - 0xf6, 0x1a, 0x81, 0xa3, 0x59, 0x10, 0xb8, 0xa1, 0xba, 0xf3, 0x9a, 0x91, 0x9a, 0x7b, - 0x60, 0xbc, 0x60, 0x4d, 0x63, 0x18, 0x5f, 0x75, 0x92, 0x21, 0xd8, 0x47, 0xcc, 0x54, - 0xa2, 0x27, 0x65, 0xa4, 0xc3, 0x34, 0x75, 0xb5, 0x79, 0x1e, 0x9a, 0xf3, 0x27, 0x1f, - 0xc8, 0xd9, 0x35, 0x06, 0x67, 0x09, 0x0d, 0x81, 0x84, 0xec, 0x50, 0x52, 0x2d, 0x80, - 0x4f, 0x23, 0xc4, 0xfb, 0x44, 0xff, 0xa4, 0x81, 0xbc, 0x92, 0xae, 0x40, 0x8d, 0x1b, - 0x9f, 0x2b, 0x13, 0x19, 0x04, 0xf9, 0x70, 0x5c, 0x59, 0xe2, 0xf4, 0xbd, 0xe7, 0xa3, - 0xb2, 0xc0, 0x85, 0xd9, 0x3f, 0xd2, 0xab, 0xc5, 0xe1, 0x4d, 0x16, 0x30, 0x01, 0xa1, - 0x2f, 0x51, 0x93, 0x8d, 0x02, 0x1a, 0xfa, 0x92, 0x23, 0x9b, 0x87, 0x3d, 0xc6, 0xc3, - 0x57, 0xea, 0xa8, 0xaf, 0x4e, 0xe6, 0xd0, 0x05, 0x40, 0x65, 0x7f, 0xe3, 0x29, 0x14, - 0x10, 0x3b, 0x5d, 0x98, 0xf6, 0x8b, 0xd3, 0xe2, 0xb5, 0x35, 0x9f, 0x08, 0xcc, 0xd8, - 0x8d, 0x0c, 0x81, 0x1e, 0x4c, 0x31, 0xfb, 0xb4, 0x9f, 0x3a, 0x90, 0xbb, 0xd0, 0x5d, - 0xce, 0x62, 0xf3, 0x44, 0xe7, 0x07, 0x75, 0x93, 0x15, 0x9a, 0xe3, 0x50, 0x50, 0xb0, - 0x4c, 0x9e, 0x6b, 0x86, 0xbc, 0x43, 0x2d, 0xc8, 0xb0, 0x48, 0xc7, 0x3c, 0x00, 0x18, - 0xca, 0x5b, 0x69, 0x41, 0x12, 0x97, 0x73, 0x2a, 0x4e, 0x1a, 0xa9, 0x9a, 0x92, 0x8c, - 0x71, 0xe7, 0xa2, 0x4f, 0xd2, 0x77, 0x85, 0x6a, 0xa4, 0x25, 0x01, 0xe5, 0x1b, 0x01, - 0x2a, 0xea, 0x94, 0x46, 0xa2, 0x10, 0x4e, 0x93, 0xf8, 0x15, 0xa0, 0xb3, 0xa2, 0x9b, - 0x45, 0x83, 0x14, 0xf3, 0xd8, 0xbe, 0x2b, 0x98, 0x23, 0xd3, 0x42, 0xf4, 0x62, 0x13, - 0xe9, 0x42, 0xa7, 0xe1, 0x9a, 0x46, 0xe9, 0x70, 0xb5, 0xc5, 0x06, 0x70, 0x84, 0x30, - 0x31, 0x7b, 0x1b, 0xb3, 0xb3, 0x5d, 0xf6, 0x8a, 0xe3, 0x3a, 0x49, 0x26, 0xa0, 0x3e, - 0x6b, 0xfe, 0xb5, 0x51, 0x04, 0x16, 0xfc, 0xbb, 0x05, 0x24, 0xc9, 0xca, 0x50, 0x74, - 0x15, 0x6c, 0xc5, 0xa5, 0xd6, 0xfe, 0x1c, 0x99, 0x5e, 0xdc, 0x60, 0xa2, 0xf5, 0x50, - 0x41, 0x1a, 0xa4, 0x1e, 0x3d, 0xa3, 0xbd, 0xcf, 0x64, 0xbc, 0xf0, 0x4a, 0x05, 0x10, - 0x57, 0x1b, 0x93, 0x6d, 0x47, 0xe5, 0x5c, 0xec, 0x03, 0x30, 0xee, 0x8d, 0xfe, 0x73, - 0x56, 0x34, 0x04, 0xf0, 0x47, 0xd7, 0xf3, 0xa8, 0xa3, 0xd7, 0x74, 0x3b, 0xc5, 0x54, - 0x95, 0x52, 0x10, 0xf1, 0xeb, 0x0d, 0x08, 0x59, 0x9e, 0xa7, 0x7d, 0x5f, 0x97, 0x4d, - 0x87, 0x17, 0x6d, 0x37, 0xd9, 0x8b, 0x9c, 0x0a, 0xd4, 0x40, 0x40, 0x72, 0x09, 0xed, - 0x6a, 0x9f, 0x08, 0x46, 0x4d, 0x56, 0x55, 0x93, 0xe1, 0xa6, 0x3b, 0x93, 0x85, 0x36, - 0xb4, 0x92, 0x44, 0xe9, 0x7d, 0x88, 0x01, 0x73, 0xb6, 0x40, 0xf2, 0xdd, 0xb7, 0x4d, - 0x06, 0x8e, 0xcb, 0x46, 0xcf, 0x28, 0x9b, 0x7d, 0x89, 0x13, 0x07, 0xbb, 0xa3, 0x70, - 0x54, 0xcf, 0x91, 0xb3, 0x1f, 0xc8, 0x2f, 0x74, 0xd5, 0xfc, 0xc0, 0x00, 0x94, 0x2e, - 0xde, 0x91, 0x18, 0x25, 0xf5, 0x3f, 0xe6, 0x09, 0x68, 0x6f, 0x46, 0x32, 0x23, 0xb1, - 0xe9, 0xbc, 0x03, 0xbd, 0xe8, 0x95, 0xd1, 0x23, 0x8f, 0xad, 0x04, 0xa3, 0xbf, 0xce, - 0x68, 0xa0, 0x75, 0xe8, 0xa3, 0x7c, 0x0e, 0x87, 0xbf, 0x46, 0xdd, 0x01, 0x55, 0x45, - 0xf9, 0xb4, 0xfb, 0x0e, 0xec, 0x64, 0x5f, 0xfc, 0xbb, 0xe0, 0xca, 0x5f, 0x8c, 0x56, - 0x1b, 0x25, 0x7d, 0x52, 0xd6, 0x02, 0xd8, 0xc9, 0x4c, 0x50, 0x28, 0x73, 0xa0, 0x1d, - 0x92, 0x51, 0xd8, 0xc8, 0x60, 0xc0, 0x41, 0x52, 0x5b, 0x3b, 0xf4, 0xe3, 0xa2, 0xeb, - 0x92, 0x72, 0x81, 0x5c, 0x75, 0x86, 0x76, 0x84, 0x28, 0xb4, 0xc2, 0xb2, 0x5e, 0x37, - 0x45, 0xf0, 0x09, 0xc5, 0xdc, 0xe2, 0x0b, 0x69, 0xd5, 0xd7, 0xc4, 0x3c, 0xeb, 0x73, - 0x6b, 0x68, 0x31, 0xe8, 0xc1, 0x10, 0xf1, 0x6c, 0xfd, 0xb3, 0xa4, 0x67, 0xe9, 0x41, - 0x4c, 0x00, 0xec, 0xf1, 0x37, 0x31, 0x50, 0x08, 0x94, 0x55, 0x56, 0x78, 0xc4, 0x97, - 0xfa, 0xba, 0x9a, 0x95, 0xd0, 0x1c, 0xc4, 0x64, 0x39, 0x0f, 0xc4, 0xa7, 0x6b, 0xfa, - 0x8b, 0x0e, 0x1c, 0x68, 0xa5, 0x25, 0xd7, 0x06, 0xd6, 0x60, 0x4b, 0x23, 0x30, 0xb6, - 0xb3, 0x48, 0x52, 0x15, 0xf6, 0x06, 0xf1, 0x88, 0x3a, 0x75, 0x15, 0x88, 0xc7, 0xef, - 0xa5, 0x06, 0xc3, 0xe8, 0xd0, 0xc6, 0x01, 0x92, 0xe8, 0x47, 0x6b, 0xd1, 0x17, 0x5d, - 0x95, 0x62, 0x08, 0x7b, 0xdb, 0x81, 0x8e, 0x66, 0x21, 0x62, 0x86, 0xba, 0xfe, 0x47, - 0xff, 0x4d, 0xbc, 0xce, 0xd5, 0x14, 0x44, 0x48, 0x0a, 0x9a, 0x56, 0x73, 0xec, 0xe7, - 0xfa, 0xc7, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xd4, 0x1a, 0xb0, 0x05, 0x17, 0x53, 0xa7, 0xca, - 0xa8, 0x9b, 0xe3, 0x13, 0x9a, 0xfd, 0x97, 0x93, 0xb3, 0xe0, 0x2f, 0x27, 0xf0, 0x40, - 0x04, 0x65, 0x95, 0xac, 0xd4, 0x7b, 0xf1, 0x3f, 0xd0, 0xda, 0x27, 0xf0, 0x9e, 0xda, - 0x48, 0x03, 0x6d, 0x3e, 0xe4, 0x37, 0xf2, 0xee, 0x8f, 0x86, 0x06, 0xea, 0x97, 0x34, - 0x3c, 0x33, 0x58, 0x46, 0x57, 0xf4, 0x6d, 0xba, 0x99, 0xdb, 0x5c, 0xfe, 0x6c, 0xa1, - 0x76, 0xfa, 0xb7, 0xb0, 0xf3, 0xbf, 0xa0, 0xab, 0x61, 0xe3, 0x40, 0xc3, 0x4e, 0xb9, - 0xf1, 0x7c, 0x7e, 0xc2, 0xbe, 0x03, 0xb1, 0x80, 0xf0, 0xbb, 0x6f, 0x43, 0x4c, 0x2a, - 0x65, 0x42, 0xe0, 0x0e, 0x84, 0x37, 0x3f, 0x4f, 0x46, 0x49, 0xcd, 0xa3, 0x2b, 0xf6, - 0x86, 0x66, 0x61, 0x43, 0xf6, 0x22, 0xaa, 0x48, 0x04, 0x60, 0xb5, 0xaf, 0xac, 0x51, - 0x86, 0x07, 0xcd, 0x9a, 0xf8, 0xbc, 0xd6, 0xb5, 0x8c, 0x30, 0x12, 0x73, 0x16, 0xb2, - 0x5d, 0x5e, 0xa7, 0xbf, 0x6b, 0x0c, 0xab, 0x85, 0x42, 0xff, 0x69, 0xd9, 0xb2, 0xf1, - 0x80, 0xbe, 0x12, 0xed, 0x75, 0x34, 0x4a, 0x39, 0x5a, 0xa1, 0x0f, 0x85, 0x2f, 0x08, - 0x3a, 0xd6, 0x4e, 0xf4, 0x0e, 0x9c, 0x03, 0x09, 0xe9, 0xbb, 0xa5, 0x4b, 0x8c, 0xb3, - 0x3c, 0x95, 0x49, 0x8a, 0x69, 0x53, 0x8d, 0x3a, 0xe5, 0xb2, 0x5e, 0x24, 0x70, 0x98, - 0x30, 0x6f, 0xa8, 0xc7, 0x4a, 0x8e, 0xe5, 0xbc, 0xa9, 0x41, 0x53, 0x1d, 0x61, 0xaa, - 0xc2, 0x7a, 0xab, 0x3d, 0xc5, 0x61, 0x7d, 0x56, 0x06, 0xc9, 0x57, 0x7a, 0x2a, 0x83, - 0x46, 0xe8, 0xd8, 0x5b, 0x32, 0xb8, 0x50, 0x57, 0x75, 0x10, 0x8d, 0xc8, 0x5e, 0x2a, - 0xde, 0x2e, 0xac, 0x1e, 0x63, 0x6e, 0x1a, 0xf4, 0x05, 0x4c, 0x8b, 0x6f, 0x57, 0x63, - 0x2d, 0xf2, 0x69, 0xc3, 0x72, 0x3b, 0x32, 0x08, 0x72, 0xe4, 0xc5, 0x7b, 0x21, 0x83, - 0x58, 0xdc, 0x7e, 0x99, 0x05, 0xbb, 0x04, 0xed, 0xf9, 0x2e, 0xdf, 0x0d, 0xf6, 0x35, - 0xf3, 0xbf, 0x36, 0x1e, 0x57, 0xa1, 0x32, 0x96, 0xe1, 0x44, 0x7a, 0xf5, 0x08, 0x02, - 0x72, 0xd6, 0x36, 0xe2, 0x75, 0x18, 0xa9, 0x87, 0x6e, 0x15, 0xeb, 0x01, 0xf5, 0xe8, - 0xde, 0xd8, 0x18, 0x92, 0x51, 0x1c, 0xc2, 0x85, 0x1b, 0x00, 0xb8, 0x32, 0x71, 0x2a, - 0x6d, 0x3b, 0xa5, 0x66, 0x03, 0x17, 0xbc, 0xd3, 0x56, 0x76, 0x21, 0xa7, 0xcf, 0x84, - 0x45, 0x58, 0x96, 0x53, 0x26, 0x20, 0x20, 0xc3, 0x3b, 0xf7, 0x80, 0x31, 0xb8, 0xee, - 0x07, 0x07, 0xde, 0x07, 0x20, 0x68, 0xc1, 0x70, 0x57, 0x0b, 0x27, 0xe6, 0xd9, 0xf5, - 0xc6, 0xdd, 0xc3, 0x35, 0x40, 0x2e, 0xfc, 0x54, 0x88, 0x62, 0xf5, 0xa0, 0x70, 0x94, - 0xfd, 0x42, 0x8a, 0x7b, 0xbc, 0x15, 0xd7, 0xb3, 0x8d, 0x05, 0x36, 0x2c, 0x9c, 0xa9, - 0x85, 0xf5, 0x8a, 0x76, 0x64, 0x7d, 0x2b, 0xe4, 0xc2, 0xcd, 0x6b, 0x3d, 0x17, 0xd6, - 0x87, 0x09, 0x71, 0xd7, 0xa0, 0x98, 0xba, 0xf7, 0x2c, 0x6f, 0x6f, 0x12, 0x14, 0xcf, - 0x1f, 0xaa, 0xe4, 0x88, 0x03, 0x7d, 0xe2, 0x59, 0xd3, 0x41, 0x5c, 0x2f, 0x0d, 0xde, - 0xc7, 0x45, 0x70, 0x04, 0xf3, 0x57, 0x08, 0xd1, 0xec, 0xcc, 0xcc, 0x0d, 0xf6, 0x5a, - 0x04, 0x94, 0x3a, 0xd5, 0xcb, 0xc1, 0x3f, 0x29, 0x5f, 0x02, 0x0f, 0xe0, 0x56, 0xc4, - 0x0b, 0x2d, 0x88, 0xf2, 0x7d, 0xc3, 0x4c, 0xfe, 0xb8, 0x03, 0xbe, 0x34, 0x83, 0xa9, - 0xeb, 0xf9, 0xb5, 0xa9, 0x02, 0x60, 0x57, 0x72, 0x5d, 0x63, 0xea, 0xd2, 0xc0, 0xc0, - 0x03, 0x1f, 0xe2, 0x6a, 0xc1, 0xe7, 0xbd, 0xfc, 0xd6, 0xfa, 0xd8, 0x75, 0x84, 0x2d, - 0x19, 0x4f, 0x33, 0x17, 0x50, 0x46, 0x2c, 0x06, 0xb8, 0xd7, 0x98, 0x2d, 0x67, 0x99, - 0x5e, 0xd5, 0xd3, 0xae, 0x96, 0x02, 0x5a, 0xe0, 0x06, 0x7f, 0x4e, 0xb1, 0xc7, 0xc9, - 0x32, 0x31, 0xbd, 0x39, 0x77, 0x3c, 0xbe, 0x0a, 0x9d, 0x66, 0xb0, 0xc9, 0xaa, 0x8c, - 0xff, 0x6a, 0x37, 0x6e, 0x1f, 0x37, 0x2e, 0xac, 0x6a, 0xc4, 0x02, 0x6c, 0xc0, 0x94, - 0x22, 0x45, 0xd4, 0xc2, 0xdc, 0xf0, 0x2d, 0x76, 0x40, 0xff, 0xcc, 0x5a, 0x6a, 0xc3, - 0xa8, 0x7f, 0x5c, 0x41, 0x15, 0x51, 0xbc, 0xc2, 0xf2, 0x6c, 0xb9, 0x49, 0x61, 0xd5, - 0x3f, 0x95, 0xdd, 0xb1, 0x9a, 0xe9, 0x30, 0xc8, 0xd7, 0x0f, 0x03, 0x1b, 0x29, 0xa5, - 0xdf, 0x99, 0xff, 0x36, 0x69, 0x5e, 0x80, 0x2c, 0xbc, 0xb6, 0xb5, 0x8c, 0x1b, 0xa7, - 0xed, 0x5e, 0xac, 0xfa, 0x76, 0x41, 0x4a, 0x41, 0xad, 0x4a, 0x44, 0xf7, 0x1f, 0x1b, - 0x58, 0x0d, 0x34, 0xc3, 0xa9, 0x52, 0x92, 0x0b, 0x25, 0x4a, 0x14, 0x5f, 0xea, 0x51, - 0x7f, 0x5b, 0x42, 0xb2, 0xf6, 0x5e, 0xcd, 0x0f, 0x82, 0x59, 0x54, 0x78, 0xd8, 0x0a, - 0xe5, 0xc8, 0xce, 0xea, 0x12, 0xa1, 0x61, 0xcc, 0xbb, 0x5e, 0xac, 0x09, 0x99, 0x0f, - 0xc6, 0x19, 0xa4, 0x60, 0x80, 0x43, 0x6d, 0xbd, 0x08, 0xd7, 0x47, 0x84, 0xaf, 0x00, - 0x2d, 0x58, 0xe0, 0x6f, 0xaf, 0x7f, 0x3c, 0xea, 0xe7, 0xd3, 0x41, 0x9b, 0x1f, 0xca, - 0x26, 0x5a, 0x55, 0x59, 0xcf, 0x9e, 0x2d, 0x3b, 0x60, 0x97, 0x8d, 0x81, 0xa6, 0x78, - 0xb9, 0xed, 0x8e, 0x44, 0x86, 0xb4, 0xd1, 0x46, 0x09, 0xd6, 0xc1, 0x27, 0xc0, 0xc2, - 0xfb, 0xff, 0xe3, 0x0a, 0x60, 0xf7, 0xbf, 0xf1, 0xd9, 0xfb, 0x83, 0x00, 0xed, 0x00, - 0x92, 0x53, 0xba, 0x9b, 0x99, 0x6f, 0xa0, 0x52, 0x41, 0xb1, 0x0f, 0x5a, 0xc9, 0xa8, - 0x40, 0x8e, 0x92, 0x5b, 0x62, 0x6b, 0xb2, 0x1a, 0x47, 0x1f, 0xe3, 0xbe, 0xde, 0x52, - 0xbb, 0xa0, 0x97, 0xb2, 0xa9, 0x9a, 0x9b, 0xa5, 0xa8, 0x66, 0x58, 0xc3, 0xfd, 0x9e, - 0xc5, 0x5b, 0xfa, 0x9b, 0x32, 0x85, 0x67, 0x25, 0x4a, 0xb3, 0x6d, 0x2c, 0x7f, 0x44, - 0xd2, 0xc7, 0xe1, 0x3e, 0xb5, 0x4b, 0xeb, 0x70, 0xea, 0x8f, 0xa9, 0x4b, 0x6c, 0x6e, - 0x01, 0x2d, 0x79, 0xe3, 0xf5, 0x36, 0x89, 0xc2, 0xb1, 0xa1, 0x8e, 0xaf, 0x2d, 0x47, - 0x1d, 0x13, 0xc1, 0xab, 0x39, 0xd9, 0x19, 0x4a, 0xe8, 0x43, 0xab, 0x1d, 0x28, 0xff, - 0xa8, 0xf6, 0x9d, 0xc7, 0xe1, 0x5c, 0xc3, 0x8b, 0x12, 0xe8, 0xfc, 0xd7, 0x92, 0x55, - 0xb7, 0x21, 0x60, 0x56, 0xd9, 0xed, 0xb7, 0x48, 0x2f, 0xb9, 0x8a, 0xa0, 0x33, 0xb6, - 0x5e, 0x51, 0xc1, 0xa0, 0x8b, 0x8a, 0x11, 0xd8, 0x4d, 0x04, 0x09, 0xb7, 0x34, 0xf4, - 0x52, 0xaa, 0xf0, 0xd6, 0xb1, 0x8f, 0x50, 0x25, 0x86, 0x83, 0xd3, 0xf9, 0xa7, 0x6d, - 0x39, 0x9f, 0xd0, 0x47, 0xee, 0xe2, 0x88, 0xbb, 0x45, 0x85, 0x85, 0x1d, 0xc9, 0x3e, - 0xcc, 0xc6, 0x23, 0x22, 0x92, 0x4c, 0xd1, 0x3b, 0x5d, 0xd4, 0xee, 0xd6, 0x6e, 0xd8, - 0xd9, 0x97, 0x2d, 0x77, 0x26, 0x29, 0xea, 0x64, 0x74, 0x2e, 0x54, 0x73, 0x39, 0x81, - 0xb0, 0x06, 0xc0, 0x62, 0x46, 0x8e, 0x4b, 0xd8, 0xf7, 0xdd, 0x9a, 0xf6, 0x98, 0xf5, - 0x2a, 0xe8, 0x14, 0x63, 0x4e, 0x81, 0xd7, 0xf3, 0xe0, 0xc4, 0x20, 0x31, 0x7c, 0xac, - 0xa9, 0xae, 0x48, 0x11, 0xc6, 0xaf, 0x06, 0xfe, 0x80, 0xa8, 0xc0, 0x2a, 0xb7, 0xa0, - 0x0e, 0x18, 0xe4, 0xa6, 0xaa, 0x1e, 0xa1, 0xb7, 0x69, 0x45, 0xd2, 0x61, 0x5d, 0x43, - 0xac, 0x11, 0x8b, 0x56, 0xc2, 0xf2, 0x96, 0x0f, 0xe9, 0x3a, 0x02, 0x5f, 0x13, 0xec, - 0x91, 0xff, 0xc6, 0xd2, 0xc3, 0x53, 0x69, 0x9a, 0xbb, 0x09, 0x2d, 0xed, 0xc0, 0x65, - 0xdb, 0x8f, 0xa2, 0x14, 0xdb, 0xc4, 0x64, 0x66, 0xf8, 0x97, 0xb8, 0x8c, 0x58, 0xb3, - 0x01, 0x52, 0x13, 0x3a, 0xa3, 0x83, 0x1a, 0xf3, 0x7c, 0x74, 0xd9, 0x9e, 0x9e, 0x36, - 0xff, 0x70, 0x11, 0xd3, 0x23, 0x83, 0x05, 0x69, 0x15, 0x08, 0xa2, 0xc3, 0xa4, 0x3e, - 0x75, 0x5d, 0xc0, 0x81, 0xb5, 0x11, 0xd6, 0x48, 0x2a, 0x7d, 0xb6, 0x5f, 0xa9, 0x69, - 0x9e, 0xa8, 0x7f, 0xf4, 0x70, 0x99, 0xed, 0x36, 0x37, 0xdb, 0xb0, 0xa3, 0xd0, 0xef, - 0x79, 0x79, 0x6a, 0x8e, 0xf1, 0xe4, 0xd9, 0x4d, 0x42, 0xb4, 0xbc, 0x2b, 0x4a, 0x03, - 0x8a, 0xe6, 0xe4, 0x6b, 0x24, 0xcf, 0xc8, 0x41, 0x53, 0xd3, 0x1e, 0xaf, 0x89, 0x50, - 0x63, 0xa5, 0xca, 0x95, 0x9b, 0xe6, 0x3f, 0x37, 0xf2, 0xba, 0x0d, 0x43, 0x23, 0x66, - 0x73, 0x6d, 0x86, 0x32, 0xfc, 0xe0, 0x72, 0xb6, 0xae, 0x5b, 0x6f, 0x3f, 0xd5, 0x9d, - 0x3f, 0xaf, 0xf6, 0x38, 0x27, 0x5a, 0x99, 0x2f, 0xef, 0xc8, 0x7e, 0x60, 0xd4, 0x4c, - 0x2c, 0xad, 0xc2, 0xb5, 0xc4, 0x94, 0xe3, 0xe7, 0x2e, 0xb4, 0x59, 0x7c, 0x96, 0xb4, - 0x01, 0x67, 0x79, 0x9a, 0x90, 0x01, 0xa2, 0xed, 0x36, 0x76, 0xa8, 0xb4, 0x03, 0xae, - 0x25, 0xff, 0xd7, 0x72, 0xf7, 0x08, 0x1e, 0x9a, 0x32, 0xbc, 0xc1, 0xc5, 0xe2, 0xed, - 0xd4, 0xe2, 0xa6, 0x57, 0x6b, 0x78, 0x3c, 0xce, 0x3a, 0xae, 0x11, 0xfa, 0x43, 0x22, - 0x62, 0x54, 0x88, 0x56, 0x18, 0x3e, 0xe6, 0x82, 0xd5, 0xdc, 0x31, 0xbe, 0xb3, 0x8f, - 0x06, 0x1c, 0xbd, 0xec, 0xa7, 0x02, 0x1a, 0x44, 0x4e, 0x2d, 0xd4, 0x17, 0xdf, 0x26, - 0xdc, 0xd2, 0x20, 0xf2, 0xb7, 0x31, 0x77, 0x2b, 0x43, 0x9e, 0x96, 0xd6, 0x14, 0xe1, - 0xfa, 0xcb, 0x48, 0x6c, 0x7a, 0x7d, 0x51, 0x71, 0xb1, 0xde, 0x35, 0x9f, 0x6a, 0xd3, - 0xa9, 0x6f, 0x64, 0x9c, 0x96, 0x91, 0x02, 0xa1, 0x96, 0x4f, 0xb4, 0xb4, 0xa1, 0xa4, - 0x27, 0x9c, 0x68, 0xe6, 0xc3, 0x72, 0xe4, 0x21, 0x87, 0xd7, 0x54, 0xe8, 0x04, 0xa6, - 0x16, 0x53, 0x09, 0x20, 0x69, 0xfb, 0x9b, 0x6d, 0x25, 0x26, 0x68, 0x90, 0x80, 0x8b, - 0x01, 0x5d, 0xf2, 0x8c, 0x80, 0x10, 0x65, 0xda, 0x6f, 0xeb, 0xdc, 0x1a, 0x56, 0xbf, - 0xd0, 0x02, 0x62, 0x5a, 0xcf, 0xaa, 0x53, 0x73, 0xfd, 0xe1, 0x49, 0xc1, 0xcf, 0xc3, - 0x64, 0x9b, 0x48, 0x69, 0x69, 0x6d, 0x44, 0xec, 0xb1, 0x24, 0x79, 0xc5, 0xeb, 0xef, - 0x99, 0x5f, 0x10, 0x02, 0x9f, 0x8b, 0x53, 0x0e, 0xeb, 0x3f, 0xdc, 0x2e, 0x50, 0xe8, - 0x75, 0x7f, 0xc0, 0xbb, 0x9e, 0x26, 0x30, 0x23, 0xdb, 0x82, 0xf8, 0x78, 0xd9, 0xac, - 0x7f, 0xfb, 0x0b, 0xd4, 0x39, 0x1d, 0xf1, 0xd8, 0x79, 0x89, 0x9a, 0x3e, 0xf5, 0x7b, - 0xfd, 0x0d, 0x1f, 0x77, 0x55, 0x64, 0x8e, 0xdd, 0x85, 0xbb, 0x05, 0x2a, 0x6e, 0xdf, - 0x71, 0xcd, 0x26, 0x28, 0xc9, 0x87, 0x42, 0x9f, 0x36, 0xdc, 0x50, 0x5c, 0xcc, 0x43, - 0xf3, 0x0e, 0x7a, 0x86, 0x9c, 0x9e, 0x25, 0x5e, 0x2a, 0xf9, 0xfc, 0xf3, 0x0c, 0x12, - 0x17, 0x96, 0xd1, 0x90, 0x00, 0x09, 0x60, 0xcb, 0x6f, 0xe2, 0xf1, 0xbf, 0x24, 0x61, - 0x18, 0xb4, 0x98, 0xf3, 0x24, 0x7f, 0x9d, 0x48, 0x4c, 0x73, 0xcf, 0x09, 0x39, 0x30, - 0x39, 0xe4, 0x53, 0x26, 0xb8, 0xff, 0xff, 0xb3, 0xe7, 0xe6, 0x15, 0x9c, 0x46, 0x69, - 0x9f, 0x10, 0x07, 0x92, 0xd4, 0x67, 0x29, 0x50, 0x34, 0x8a, 0x90, 0x55, 0x2e, 0x45, - 0x94, 0x3b, 0xee, 0xac, 0xf0, 0x3f, 0x32, 0x16, 0xf9, 0x4e, 0x27, 0x4d, 0x63, 0xd6, - 0x37, 0xd9, 0xf1, 0x90, 0xe8, 0xa2, 0x66, 0xcd, 0xee, 0xf1, 0x53, 0x53, 0x0b, 0xee, - 0x5c, 0xb8, 0x35, 0x52, 0x60, 0x50, 0x5c, 0x2c, 0x2e, 0x5d, 0x99, 0x0f, 0xff, 0xdc, - 0x34, 0xec, 0x0f, 0xf7, 0xf1, 0xaf, 0x81, 0xb2, 0x4c, 0xed, 0x0e, 0xfa, 0x62, 0x13, - 0xda, 0x6c, 0x7c, 0x60, 0xc4, 0x87, 0xf5, 0xf7, 0xb0, 0x3f, 0x81, 0x60, 0xa0, 0x57, - 0xf4, 0x6d, 0x05, 0xbf, 0x82, 0x18, 0xb3, 0xad, 0xd9, 0xc0, 0x68, 0x93, 0xbd, 0x02, - 0xdb, 0x9b, 0x61, 0x19, 0x1d, 0xfb, 0x13, 0x3b, 0xfa, 0xbe, 0x48, 0x58, 0xe4, 0x7a, - 0x4c, 0xc3, 0x2e, 0x41, 0x6e, 0xc0, 0x8b, 0x8a, 0xc7, 0x91, 0x5a, 0x43, 0x73, 0x3f, - 0x44, 0x06, 0xe9, 0xd9, 0x67, 0xc5, 0x60, 0xf3, 0x44, 0xd7, 0xe9, 0x04, 0xa2, 0x80, - 0x45, 0xd9, 0x9f, 0x3a, 0xf8, 0xc8, 0x2e, 0x97, 0xe1, 0xb9, 0xc1, 0xb2, 0x05, 0xe5, - 0x85, 0xfb, 0xeb, 0xb4, 0x8f, 0xaf, 0x58, 0xf1, 0xb6, 0x5d, 0xca, 0x24, 0x97, 0xe0, - 0x9a, 0x70, 0xaa, 0xd4, 0x86, 0x5f, 0x85, 0x71, 0x5a, 0x28, 0x0e, 0x18, 0x6f, 0x3f, - 0xc1, 0x74, 0x0d, 0x81, 0x84, 0xd3, 0x3e, 0x83, 0x22, 0x16, 0x95, 0x21, 0xcd, 0xc1, - 0x32, 0x21, 0x29, 0x39, 0xc8, 0x4a, 0x10, 0x89, 0x64, 0xe2, 0xde, 0x74, 0xb6, 0xea, - 0x55, 0xb4, 0xcb, 0x8f, 0x6f, 0x9b, 0xee, 0x98, 0xb1, 0x0d, 0x41, 0x51, 0x09, 0x45, - 0x5f, 0x48, 0xb7, 0x76, 0x08, 0x2d, 0xc3, 0x0b, 0x4b, 0xc7, 0x34, 0x77, 0x07, 0x55, - 0x11, 0x70, 0x03, 0x08, 0x15, 0x8c, 0xe2, 0xf2, 0xf9, 0xbf, 0x0f, 0x69, 0x1b, 0x2c, - 0xe5, 0x3e, 0x61, 0x14, 0x2c, 0xb7, 0x40, 0xc1, 0x5b, 0x7b, 0x62, 0x3c, 0xf4, 0x8b, - 0x3f, 0x7b, 0xfe, 0xfa, 0x31, 0xbc, 0xdc, 0x66, 0x5c, 0x6d, 0x71, 0x23, 0xe9, 0x53, - 0x50, 0x81, 0x13, 0x75, 0x94, 0x7b, 0x05, 0x5a, 0x43, 0xdb, 0x07, 0xe0, 0x3f, 0x33, - 0x62, 0x7d, 0xf5, 0xc6, 0x38, 0xbf, 0xad, 0x95, 0x6d, 0xdc, 0x1e, 0xa7, 0xd7, 0x62, - 0x0a, 0x20, 0xf2, 0x79, 0x2f, 0x63, 0x81, 0x7a, 0x1c, 0xf3, 0x25, 0x80, 0xd0, 0x42, - 0x74, 0x23, 0x4a, 0xf2, 0xa5, 0x1b, 0x56, 0xbb, 0x68, 0xa2, 0x9e, 0x43, 0xa9, 0x54, - 0x14, 0x2b, 0xa4, 0xca, 0x68, 0x23, 0xbd, 0xe9, 0x05, 0x3d, 0x72, 0xfd, 0xad, 0xbc, - 0x61, 0xad, 0x59, 0x36, 0xc5, 0x3f, 0xdd, 0x75, 0x79, 0x44, 0x6d, 0x11, 0xc4, 0x46, - 0x07, 0xf4, 0x16, 0x30, 0xe4, 0xc0, 0x89, 0x15, 0xe6, 0x31, 0x77, 0x15, 0x50, 0xe9, - 0xce, 0x1f, 0xca, 0x2c, 0x63, 0xfe, 0x06, 0xb7, 0x98, 0x9d, 0x58, 0x4f, 0xa7, 0xd7, - 0x82, 0xa8, 0x8c, 0x1e, 0x7d, 0x64, 0xb6, 0xfb, 0xf5, 0x5e, 0x35, - ], - script_code: Script(vec![0x6a, 0x53, 0x53, 0x63]), - transparent_input: None, - hash_type: 1, - amount: 379068098637835, - consensus_branch_id: consensus::BranchId::Overwinter, - sighash: [ - 0x92, 0xe7, 0xb4, 0x8f, 0x32, 0x81, 0x87, 0x71, 0x26, 0x87, 0xaf, 0x4d, 0xc1, 0x7a, - 0x73, 0xfe, 0x0a, 0x70, 0xac, 0x07, 0x8d, 0x24, 0xcd, 0xcd, 0xd4, 0x58, 0xa3, 0xd6, - 0x86, 0x61, 0xec, 0x0a, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x24, 0x9d, 0xf0, 0x57, 0x01, - 0xda, 0xb0, 0x31, 0xc4, 0xba, 0xc1, 0xea, 0x26, 0x7a, 0x29, 0x96, 0xa2, 0x02, 0x8d, - 0x1e, 0x6a, 0x0f, 0x80, 0xa3, 0x84, 0x7c, 0x53, 0x1d, 0xba, 0x96, 0xee, 0x65, 0xa2, - 0x41, 0x89, 0xbd, 0x09, 0x52, 0xac, 0x65, 0x63, 0x65, 0xac, 0x00, 0x65, 0x00, 0xb2, - 0xa4, 0xf9, 0x51, 0xef, 0x8f, 0x49, 0x7d, 0xff, 0xf2, 0xf2, 0xf2, 0x71, 0xea, 0xb8, - 0x9c, 0x62, 0x8e, 0x18, 0xb5, 0xfc, 0xb4, 0x38, 0x82, 0x53, 0x7e, 0xaf, 0x6a, 0xd2, - 0xa6, 0xb1, 0x75, 0x46, 0x33, 0xca, 0xa8, 0x6b, 0xf2, 0xc7, 0x6f, 0x07, 0x53, 0x63, - 0x6a, 0x6a, 0x65, 0x6a, 0x53, 0xa2, 0x21, 0x0c, 0x27, 0x01, 0xea, 0x6c, 0x54, 0x2c, - 0xc8, 0xc7, 0x06, 0x00, 0x00, 0xe0, 0x11, 0x29, 0xf0, 0x3a, 0x1e, 0x9c, 0x09, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xbe, 0x07, 0x62, 0xc0, 0xb1, 0xc6, 0x58, 0x55, 0xde, 0xba, 0x84, 0x22, - 0xca, 0x4b, 0x88, 0xab, 0xee, 0xa6, 0xa4, 0x38, 0x2c, 0xf1, 0x6c, 0xcd, 0x6d, 0xc7, - 0xc3, 0x7c, 0x44, 0xe5, 0x49, 0xc4, 0x53, 0x48, 0x19, 0xac, 0xd8, 0xbb, 0x0a, 0x02, - 0xa5, 0xfa, 0x7a, 0x1c, 0x1d, 0x38, 0x06, 0xfb, 0xc3, 0x40, 0x7f, 0xd7, 0xda, 0x93, - 0xfd, 0x0d, 0xe6, 0x40, 0x0d, 0x3a, 0xb8, 0x97, 0x74, 0x85, 0xcd, 0xdf, 0xbe, 0xd5, - 0x93, 0x2f, 0x50, 0x7b, 0x79, 0x94, 0x7a, 0xdb, 0x2f, 0xad, 0x37, 0x61, 0x5a, 0xa7, - 0x17, 0xdb, 0x5f, 0x29, 0x80, 0x99, 0xf2, 0x0f, 0x26, 0x3b, 0x35, 0x9a, 0x11, 0x51, - 0xa6, 0xb7, 0x5c, 0x01, 0x36, 0x5e, 0xb1, 0x54, 0xae, 0x42, 0x14, 0x0d, 0x6e, 0x10, - 0x34, 0x2f, 0x14, 0xf3, 0x4d, 0xc3, 0x3e, 0x07, 0xff, 0x0e, 0x4d, 0x1a, 0x6b, 0xe3, - 0x75, 0xb3, 0x2f, 0x84, 0xb9, 0x2e, 0x5d, 0x81, 0xeb, 0xb6, 0x39, 0xc4, 0xf2, 0x7e, - 0x71, 0x5a, 0xa4, 0x2c, 0xc7, 0x57, 0x07, 0xd4, 0xeb, 0xd1, 0xbb, 0xfb, 0xe8, 0xf9, - 0x0f, 0xc7, 0xc9, 0x53, 0xe7, 0xa9, 0x71, 0x5e, 0x65, 0xaf, 0x82, 0x67, 0x37, 0x3d, - 0x34, 0x51, 0x67, 0x4f, 0xf0, 0x84, 0xef, 0xd9, 0x2c, 0xcf, 0x3b, 0xcc, 0x7a, 0xca, - 0x14, 0x67, 0xb6, 0x32, 0x7e, 0x4f, 0x95, 0x22, 0xb2, 0xcc, 0x57, 0x9a, 0x7a, 0x8f, - 0xff, 0x7c, 0xa7, 0xcf, 0x14, 0x5d, 0xfc, 0x13, 0xea, 0xfc, 0x34, 0x15, 0x3b, 0x2c, - 0x3e, 0x8a, 0xfb, 0xe5, 0x34, 0x44, 0xd0, 0xc7, 0x3b, 0x3b, 0xd5, 0xbc, 0x87, 0x0b, - 0x01, 0xcd, 0x45, 0x79, 0x11, 0xe3, 0x56, 0x31, 0x3f, 0xd1, 0xda, 0xfb, 0x4c, 0x81, - 0x51, 0x63, 0x4a, 0x01, 0xaf, 0xf7, 0xcf, 0x11, 0x6d, 0x43, 0x3c, 0x3d, 0x2b, 0x3a, - 0xdd, 0xa9, 0xce, 0xbe, 0x18, 0xf7, 0xd1, 0x72, 0x44, 0x3e, 0x5e, 0x7b, 0x5a, 0xc9, - 0xab, 0xe8, 0xdb, 0x22, 0x56, 0xd7, 0xeb, 0xe2, 0xff, 0x28, 0x02, 0x09, 0x39, 0x50, - 0x38, 0x70, 0x59, 0x7b, 0x9a, 0x95, 0x58, 0x92, 0xc7, 0x38, 0x02, 0x50, 0xa2, 0xd4, - 0x2e, 0xc9, 0x2b, 0xe7, 0x23, 0xfe, 0xdf, 0x2f, 0x2e, 0xde, 0x5a, 0x47, 0x2a, 0xa1, - 0xe7, 0x4f, 0x33, 0xad, 0x41, 0x90, 0x15, 0x44, 0xed, 0xbb, 0xe3, 0xac, 0x46, 0x4c, - 0xf4, 0x03, 0x19, 0x60, 0x15, 0xf4, 0xf2, 0x2a, 0xc2, 0xb8, 0xfc, 0x01, 0x49, 0x6b, - 0xea, 0xb4, 0xd4, 0x59, 0x07, 0xf4, 0x79, 0x81, 0x2a, 0x25, 0x94, 0x31, 0xa2, 0xcb, - 0xc9, 0x3d, 0x4f, 0x3b, 0x84, 0xe4, 0x0b, 0x36, 0x60, 0x20, 0x27, 0x3a, 0x67, 0x52, - 0xe5, 0x01, 0xaf, 0x6f, 0xf1, 0xb7, 0x8d, 0xdc, 0x81, 0x7e, 0x6e, 0xa3, 0x51, 0xd6, - 0x00, 0x6b, 0xec, 0xf8, 0xd2, 0xff, 0xb0, 0x39, 0x90, 0xf6, 0x77, 0x74, 0xa8, 0x1e, - 0x05, 0xb7, 0xf4, 0xbb, 0xad, 0x85, 0x77, 0xfa, 0x27, 0xc9, 0xde, 0x64, 0xe1, 0xb1, - 0x1d, 0xcf, 0x38, 0x4f, 0x59, 0x56, 0x44, 0x37, 0x48, 0x75, 0x5a, 0x9f, 0xc6, 0xf2, - 0xa0, 0x03, 0x10, 0xc3, 0x65, 0x7e, 0xba, 0xc0, 0x3b, 0xfc, 0x0b, 0x58, 0x7b, 0xef, - 0x2f, 0x45, 0xec, 0x8a, 0xcd, 0xaa, 0x51, 0xc1, 0x43, 0xb0, 0xcb, 0x25, 0xb9, 0x14, - 0x2c, 0x61, 0xbd, 0x79, 0x0a, 0x80, 0x03, 0xc2, 0x3f, 0x90, 0xcc, 0x03, 0x49, 0x5b, - 0x51, 0xe4, 0xd2, 0x84, 0x3e, 0x55, 0x7f, 0x9e, 0x25, 0x45, 0x10, 0x8c, 0x6c, 0x6f, - 0xae, 0x35, 0x9f, 0x64, 0x5c, 0x27, 0x68, 0x91, 0xc0, 0xdc, 0xab, 0x03, 0xaf, 0x18, - 0x77, 0x00, 0xc0, 0x82, 0xdc, 0x47, 0x77, 0x40, 0xfb, 0x3f, 0x2c, 0xd7, 0xbb, 0x59, - 0xfb, 0x35, 0x85, 0x54, 0xe9, 0x4c, 0x7e, 0x67, 0x8c, 0xe0, 0x1a, 0xeb, 0xf9, 0x4e, - 0x51, 0x5e, 0x03, 0x72, 0x29, 0x67, 0x99, 0x5a, 0xea, 0x85, 0x8d, 0x64, 0xe7, 0x78, - 0x9f, 0xf3, 0x06, 0x36, 0x95, 0x77, 0x22, 0x81, 0x80, 0x32, 0x6a, 0x5b, 0x0a, 0xf4, - 0x75, 0xe2, 0x7a, 0x54, 0xb2, 0x07, 0xb4, 0x03, 0x92, 0xe3, 0x76, 0x17, 0x0e, 0x3f, - 0xb0, 0x05, 0x02, 0x82, 0x61, 0xc9, 0x9c, 0x2d, 0xbd, 0x0e, 0xed, 0xee, 0x87, 0x1c, - 0x1c, 0x0f, 0x48, 0xb8, 0xe9, 0xb8, 0xe4, 0xbe, 0x77, 0xd1, 0xb7, 0x37, 0xfe, 0x21, - 0xf0, 0xfa, 0x5a, 0x18, 0xeb, 0xb5, 0x27, 0x55, 0xb5, 0xa6, 0xcf, 0x61, 0x30, 0xfb, - 0x56, 0x94, 0x4c, 0xfa, 0xb8, 0x75, 0x27, 0xc2, 0x50, 0xd1, 0x13, 0xb2, 0x9b, 0xca, - 0xc9, 0xaa, 0xa1, 0x0c, 0x2e, 0x7d, 0xe4, 0x15, 0xed, 0xb0, 0x80, 0x6c, 0x6d, 0xa0, - 0x30, 0x20, 0xa1, 0x34, 0xca, 0x7e, 0xcd, 0xc8, 0xda, 0x1b, 0xd5, 0x7a, 0x37, 0xf5, - 0x5a, 0x46, 0x94, 0x0b, 0x45, 0xb2, 0x41, 0xb1, 0xc1, 0x6e, 0xe1, 0x00, 0x92, 0x7d, - 0x1b, 0xd8, 0x60, 0xd4, 0x45, 0xa9, 0xde, 0x50, 0xd4, 0xc3, 0x84, 0xd6, 0xe1, 0xd0, - 0x01, 0x08, 0x02, 0x6c, 0x0e, 0xa5, 0xeb, 0xbf, 0x0b, 0x72, 0xfb, 0xf5, 0xc3, 0x70, - 0xbc, 0xe1, 0x8d, 0x3a, 0xcb, 0xc4, 0x65, 0x99, 0x09, 0x9b, 0xaa, 0xe1, 0xd8, 0x02, - 0xf7, 0x73, 0x33, 0x49, 0x4a, 0x7a, 0xe1, 0x30, 0xfe, 0x86, 0xe8, 0xf8, 0x18, 0xf9, - 0x26, 0x1a, 0x2d, 0xad, 0xb4, 0x12, 0x52, 0x29, 0xba, 0x0f, 0xfc, 0x0e, 0x70, 0x90, - 0x32, 0x44, 0x30, 0xb5, 0x21, 0xa9, 0x0d, 0x22, 0x4a, 0xb7, 0xa1, 0x02, 0x4e, 0x1d, - 0x89, 0x3e, 0x74, 0x04, 0xfe, 0xdb, 0x34, 0x8e, 0x4d, 0x5e, 0x22, 0x35, 0xc5, 0x9a, - 0x78, 0x76, 0xa0, 0xfc, 0x60, 0x14, 0x5c, 0x6a, 0x00, 0x96, 0x87, 0x68, 0x44, 0x60, - 0x27, 0x1e, 0xe1, 0x33, 0xa4, 0x37, 0xfe, 0x52, 0xfb, 0x6c, 0xfb, 0xa9, 0x7f, 0xce, - 0xc1, 0x61, 0xdf, 0x51, 0x5d, 0xde, 0x90, 0x5a, 0x24, 0xda, 0x6d, 0x37, 0xbd, 0xc3, - 0x40, 0x44, 0xa9, 0x55, 0xe6, 0x82, 0xb4, 0x74, 0x71, 0xca, 0x1e, 0x8c, 0x78, 0xc5, - 0x1e, 0xd3, 0x77, 0xcd, 0x4a, 0xfa, 0x89, 0x4b, 0xd9, 0xbd, 0x12, 0xe7, 0x07, 0x15, - 0x6d, 0xa0, 0x72, 0x6f, 0x7c, 0xf5, 0x72, 0x9f, 0xab, 0xe3, 0x72, 0x16, 0x04, 0x63, - 0xfe, 0x04, 0x29, 0x24, 0x4d, 0x06, 0x74, 0x89, 0xba, 0x5d, 0x09, 0x47, 0x2e, 0xcd, - 0x9b, 0xcd, 0xc4, 0xd5, 0xe4, 0xdf, 0x10, 0x1e, 0x18, 0x9d, 0xb8, 0x46, 0x3e, 0xb5, - 0x38, 0x30, 0x7b, 0x58, 0x7d, 0xef, 0xf7, 0x8d, 0xe9, 0xc7, 0x3a, 0xf2, 0x80, 0x80, - 0xb2, 0xfd, 0x05, 0x00, 0x3e, 0x11, 0xd3, 0xe1, 0xb3, 0x29, 0x9d, 0xc9, 0x52, 0x1f, - 0x8b, 0x51, 0x3b, 0xad, 0xb0, 0x10, 0xe9, 0x1b, 0xfe, 0xb9, 0x1b, 0x0b, 0x2a, 0x6c, - 0xb1, 0x29, 0xc2, 0xe8, 0x25, 0xa5, 0x97, 0xb8, 0xfb, 0x75, 0xbc, 0x56, 0x2d, 0x65, - 0x4d, 0x62, 0x10, 0x46, 0x40, 0xdd, 0x74, 0xe5, 0x6c, 0xd1, 0x4b, 0xaa, 0xba, 0x56, - 0x5b, 0x84, 0xb8, 0x45, 0xe1, 0x63, 0xd1, 0xca, 0xef, 0x25, 0x33, 0xc3, 0x98, 0x16, - 0x37, 0x20, 0x4f, 0x96, 0xa5, 0x9c, 0x8e, 0x80, 0x24, 0xd9, 0x04, 0x1b, 0x20, 0x29, - 0xe9, 0x4c, 0x15, 0x24, 0x5f, 0x1a, 0x95, 0x88, 0x40, 0xba, 0x3f, 0x38, 0x0a, 0x4d, - 0x20, 0xf1, 0x18, 0x4e, 0x77, 0x82, 0x7d, 0xe3, 0xff, 0x8f, 0x3d, 0x73, 0x45, 0x9a, - 0xfe, 0x24, 0x1f, 0x72, 0x3c, 0x08, 0x48, 0x23, 0x23, 0x0e, 0x00, 0x3d, 0x3d, 0x21, - 0xe5, 0x35, 0x01, 0xec, 0x04, 0x99, 0xb0, 0x83, 0xa7, 0xda, 0xd6, 0x85, 0xc5, 0x71, - 0x27, 0xf4, 0xde, 0x64, 0x73, 0x3a, 0x88, 0x0c, 0x2d, 0xb2, 0x8f, 0xda, 0xab, 0xf1, - 0xb5, 0x42, 0xd2, 0x05, 0xf6, 0x64, 0xa3, 0x51, 0x35, 0x71, 0x27, 0x11, 0xdc, 0xcc, - 0xd9, 0x31, 0xa5, 0x0b, 0x9c, 0x56, 0x61, 0x88, 0x23, 0x60, 0xd4, 0xca, 0xc0, 0x04, - 0x76, 0x81, 0xbc, 0x2e, 0x2b, 0x3b, 0xf6, 0xc9, 0x97, 0x60, 0xd7, 0xcf, 0xb4, 0xfa, - 0x21, 0x39, 0x43, 0x77, 0xa4, 0x55, 0x1c, 0x76, 0xd1, 0xf7, 0x5a, 0xc0, 0x3c, 0x26, - 0x20, 0x54, 0xdf, 0xfd, 0x79, 0xa9, 0xde, 0xd0, 0x5e, 0x88, 0x89, 0x58, 0x19, 0x9e, - 0xea, 0x45, 0x01, 0xe2, 0x99, 0x0a, 0x53, 0xa5, 0xcd, 0x2a, 0x46, 0xa4, 0x01, 0x57, - 0x65, 0x88, 0xfd, 0x7d, 0x05, 0x8a, 0x26, 0xf2, 0x84, 0x38, 0xe5, 0x78, 0x2f, 0x45, - 0xac, 0x1d, 0x07, 0xf6, 0xf6, 0xf5, 0xed, 0x73, 0x74, 0x1d, 0x57, 0x85, 0x83, 0x7a, - 0x6b, 0x84, 0x4b, 0x47, 0x47, 0x75, 0x71, 0x8c, 0x29, 0xdd, 0x99, 0x08, 0x4e, 0x9f, - 0x88, 0xef, 0x15, 0x3a, 0x83, 0x29, 0xf5, 0x32, 0xa6, 0x90, 0x17, 0xdc, 0x3a, 0x97, - 0xed, 0x75, 0x43, 0x67, 0x72, 0x30, 0x98, 0xe5, 0x76, 0x58, 0x40, 0xb0, 0x22, 0x89, - 0x72, 0x44, 0x74, 0x5f, 0xbb, 0xbb, 0x30, 0xa7, 0xcb, 0x54, 0xfa, 0x05, 0x11, 0x16, - 0x6e, 0x95, 0x44, 0x12, 0x20, 0x00, 0x61, 0x0b, 0xd2, 0xaa, 0xcb, 0xd8, 0x23, 0x25, - 0xa5, 0x9b, 0x95, 0x15, 0x4e, 0xcd, 0x82, 0xc8, 0x8d, 0x23, 0xab, 0xd1, 0xe2, 0x07, - 0x70, 0xff, 0xb8, 0xaa, 0xbf, 0x83, 0xfc, 0x07, 0x34, 0x96, 0x4c, 0xcd, 0x41, 0x1d, - 0x1c, 0x93, 0x57, 0x14, 0xe2, 0x4a, 0xab, 0x56, 0x6f, 0x4f, 0x08, 0x42, 0x40, 0x14, - 0xc4, 0xec, 0xa9, 0x1b, 0x59, 0x0f, 0x08, 0x2b, 0x47, 0x3f, 0x36, 0x1c, 0x87, 0x41, - 0x5d, 0x37, 0xbd, 0x20, 0xd7, 0x0f, 0xd0, 0xb5, 0x2b, 0x6d, 0xdf, 0x18, 0x65, 0xf7, - 0x66, 0x70, 0x2e, 0x32, 0xb0, 0x5b, 0x3c, 0xf1, 0x63, 0x0e, 0xe8, 0x59, 0x7a, 0xae, - 0x19, 0x63, 0x3f, 0x35, 0x16, 0xa8, 0x55, 0x5a, 0xc5, 0xbe, 0x32, 0xc6, 0x75, 0xbe, - 0x18, 0x17, 0xef, 0xbf, 0xfd, 0x93, 0x69, 0x04, 0x1a, 0x08, 0x9c, 0x28, 0x3f, 0x19, - 0x64, 0x99, 0x68, 0xc2, 0x49, 0x8c, 0xde, 0x56, 0xf5, 0x00, 0x43, 0x4f, 0x28, 0x0d, - 0x77, 0xa9, 0xc6, 0x2e, 0x43, 0xcb, 0xd3, 0xf1, 0x36, 0xa4, 0xc6, 0xa0, 0x0a, 0x43, - 0xe6, 0xed, 0x53, 0x0c, 0xb2, 0xe8, 0xae, 0x83, 0x88, 0x60, 0xad, 0xc8, 0x8a, 0xac, - 0xc7, 0xbd, 0x6a, 0x00, 0xae, 0x0c, 0x19, 0xff, 0x45, 0x33, 0xa4, 0x85, 0xef, 0xde, - 0x08, 0x2b, 0x5f, 0x4d, 0x1f, 0x7a, 0x8e, 0xbe, 0x7e, 0xd8, 0x2b, 0x7b, 0x05, 0xa8, - 0xcf, 0xe1, 0xe3, 0x73, 0x45, 0x9f, 0x1b, 0xdc, 0xbf, 0x95, 0x25, 0x74, 0x7e, 0x8c, - 0x95, 0x08, 0xa5, 0x55, 0xfa, 0xcb, 0x79, 0x87, 0x40, 0xe0, 0xbd, 0xf9, 0x94, 0xd9, - 0x73, 0x9b, 0xbe, 0x55, 0x38, 0xa0, 0xae, 0x0f, 0x07, 0x6c, 0x58, 0x2c, 0x0f, 0x5b, - 0xa8, 0x78, 0xb9, 0x9b, 0x82, 0x49, 0xdb, 0x1d, 0x7e, 0x95, 0x05, 0x6c, 0x98, 0xaf, - 0x08, 0x3d, 0x98, 0xcb, 0x0e, 0xd9, 0xe3, 0xf7, 0x43, 0x6e, 0x1c, 0x76, 0x43, 0x76, - 0x6f, 0x96, 0x6b, 0x83, 0xe9, 0x99, 0x20, 0x6e, 0xbd, 0x13, 0x93, 0xb9, 0xb2, 0xa7, - 0xf4, 0x14, 0x48, 0x0f, 0xa0, 0x17, 0x48, 0x00, 0x69, 0xf8, 0x5c, 0x77, 0x49, 0xc4, - 0x35, 0xae, 0x2f, 0xba, 0x2d, 0xdc, 0x10, 0x38, 0xd5, 0x47, 0xd8, 0x48, 0x54, 0x81, - 0x7e, 0xf3, 0x96, 0x35, 0xc2, 0x98, 0x27, 0xaa, 0xd8, 0x67, 0x26, 0xc9, 0xad, 0xe3, - 0xb2, 0x65, 0xb9, 0x08, 0x6c, 0x8b, 0x5b, 0x75, 0xef, 0x56, 0xfe, 0x4b, 0xd8, 0xb4, - 0xd6, 0x28, 0x93, 0x89, 0x5b, 0x3f, 0xd2, 0x73, 0x4f, 0xda, 0xc4, 0x64, 0x15, 0x6d, - 0x7e, 0x5e, 0xbc, 0x7e, 0xcf, 0x1d, 0x83, 0xb8, 0x6f, 0x65, 0x96, 0x37, 0xe3, 0xb1, - 0x42, 0xc1, 0x64, 0x96, 0x3b, 0x8c, 0xdc, 0xf4, 0xba, 0x4f, 0x40, 0x35, 0xdf, 0xfc, - 0x5a, 0x78, 0x94, 0x58, 0x84, 0x77, 0x81, 0x91, 0x8a, 0xc7, 0x2f, 0xc1, 0x8b, 0xbb, - 0xf5, 0x11, 0x00, 0x32, 0xe6, 0x6d, 0x75, 0xb3, 0x17, 0x1e, 0xf4, 0xb5, 0x13, 0x29, - 0x01, 0x64, 0xa7, 0x7b, 0x42, 0xb0, 0xa4, 0xcf, 0xb8, 0x96, 0x39, 0xab, 0x23, 0x84, - 0x5e, 0x1a, 0xa2, 0xa4, 0x52, 0xf3, 0x73, 0x1c, 0x8c, 0xb6, 0x50, 0x82, 0xa6, 0x22, - 0xa7, 0xc2, 0xe0, 0x01, 0x3e, 0xa4, 0x7d, 0x0b, 0xdd, 0x42, 0xd6, 0x99, 0x04, 0x66, - 0x64, 0x9a, 0x90, 0x5c, 0x68, 0x4c, 0x32, 0x51, 0x71, 0x6d, 0x61, 0xf7, 0x60, 0xd5, - 0x3d, 0xe6, 0xe3, 0xf7, 0x90, 0xfb, 0xa7, 0xf5, 0xf1, 0xf4, 0xde, 0x26, 0x71, 0x13, - 0xbd, 0xfc, 0xd7, 0x42, 0x28, 0x22, 0x33, 0x0b, 0x32, 0xd5, 0x8e, 0x67, 0x77, 0x76, - 0x5f, 0x22, 0xa4, 0x11, 0x63, 0x44, 0xee, 0xb6, 0x5b, 0x2e, 0xc5, 0x16, 0x39, 0x3a, - 0xb3, 0x75, 0x1b, 0x53, 0x56, 0xd2, 0xb0, 0xc9, 0x50, 0x0c, 0x0f, 0x3e, 0x46, 0x91, - 0x81, 0x03, 0x5b, 0xc3, 0x66, 0x0f, 0x0b, 0x8f, 0x9f, 0xbe, 0x6e, 0x40, 0xb5, 0xe8, - 0x9c, 0xb7, 0x9b, 0x06, 0x37, 0x14, 0xca, 0x75, 0xe7, 0x2e, 0x2e, 0x10, 0x0a, 0x10, - 0xd6, 0x3b, 0xf7, 0x84, 0xdf, 0x08, 0x20, 0xef, 0x25, 0xf8, 0xef, 0x40, 0xfe, 0x5f, - 0x05, 0xfb, 0x95, 0x68, 0x3f, 0x91, 0x05, 0xff, 0x3c, 0xb2, 0xd2, 0x19, 0xab, 0x76, - 0x60, 0x5a, 0x06, 0x4f, 0x69, 0x21, 0x9f, 0x1d, 0xc0, 0xd0, 0x0b, 0x3b, 0x48, 0x64, - 0x2f, 0x97, 0x0d, 0xc0, 0x0c, 0xca, 0x4b, 0x8b, 0x43, 0x30, 0x8b, 0xe1, 0x82, 0x86, - 0xec, 0x5a, 0x42, 0x88, 0xd6, 0x00, 0xa3, 0x78, 0x5c, 0xb6, 0x22, 0xd4, 0x68, 0xa4, - 0xc6, 0x96, 0x9b, 0x37, 0x92, 0xf2, 0x48, 0x50, 0x27, 0xd0, 0xad, 0x9a, 0xa4, 0xa9, - 0xc2, 0xcc, 0x97, 0x2f, 0x9e, 0xe5, 0x19, 0x0a, 0x95, 0xb1, 0xeb, 0x05, 0x8d, 0xdd, - 0xd8, 0xc0, 0x8e, 0x7d, 0x75, 0x3f, 0x5e, 0x01, 0x1b, 0x2b, 0xcf, 0xee, 0x1d, 0x52, - 0xc1, 0xc4, 0xf2, 0xca, 0xcd, 0xa3, 0x0b, 0xdb, 0x69, 0x30, 0x65, 0x3c, 0x0c, 0xc4, - 0x48, 0x6e, 0x60, 0xe8, 0x9f, 0xa8, 0x49, 0xb3, - ], - script_code: Script(vec![0x53, 0x52]), - transparent_input: Some(0), - hash_type: 3, - amount: 1437866676382615, - consensus_branch_id: consensus::BranchId::Overwinter, - sighash: [ - 0xd8, 0xe9, 0xb9, 0x72, 0xb2, 0x89, 0x8e, 0xfc, 0xca, 0x8e, 0x96, 0xbc, 0x98, 0x70, - 0x00, 0x8c, 0xdb, 0xc1, 0x9d, 0x45, 0xb7, 0x8d, 0x09, 0xef, 0xb1, 0x02, 0xf2, 0xd7, - 0x0d, 0xba, 0x01, 0xad, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x01, 0x87, 0xda, 0xa7, 0x31, 0xf5, - 0x70, 0xa7, 0xa4, 0x06, 0x0a, 0xf0, 0xce, 0x70, 0x0d, 0x31, 0xbc, 0xa7, 0xe7, 0x4b, - 0x3e, 0x3b, 0xa3, 0xd0, 0xe8, 0xa6, 0x39, 0x2a, 0x06, 0x2b, 0x8e, 0x86, 0xd9, 0xd7, - 0xd0, 0x0b, 0x21, 0x02, 0x65, 0x53, 0x06, 0x2e, 0x06, 0xb1, 0x01, 0x30, 0x11, 0xff, - 0x08, 0xf0, 0x83, 0x05, 0x00, 0x09, 0x63, 0x6a, 0x52, 0x63, 0x51, 0x63, 0x00, 0x6a, - 0xac, 0x9a, 0xbc, 0xef, 0x2a, 0x99, 0x08, 0x73, 0x19, 0x00, - ], - script_code: Script(vec![0x63]), - transparent_input: None, - hash_type: 1, - amount: 1993227025071196, - consensus_branch_id: consensus::BranchId::Overwinter, - sighash: [ - 0x2b, 0x62, 0xff, 0x0c, 0x8d, 0xec, 0x4d, 0xf1, 0x8b, 0x99, 0x56, 0x61, 0x5b, 0x57, - 0x4d, 0xda, 0x39, 0x42, 0xfe, 0x45, 0x2d, 0x91, 0x78, 0xb0, 0xbb, 0xb2, 0xea, 0xee, - 0x4d, 0xe4, 0x4a, 0x8c, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x7c, 0x82, 0x97, 0x7c, 0x0f, - 0xf7, 0x97, 0x09, 0x3e, 0x2c, 0x1f, 0x3a, 0xe8, 0x55, 0xf6, 0x5a, 0xea, 0x91, 0xe1, - 0x31, 0x2f, 0xc6, 0xb8, 0xa4, 0x35, 0x1a, 0x2e, 0xc0, 0x3e, 0x02, 0xe5, 0xd0, 0x2f, - 0x53, 0x35, 0x4b, 0x05, 0x6a, 0x53, 0x52, 0x63, 0x6a, 0x82, 0xcd, 0x1f, 0x55, 0xeb, - 0xca, 0x57, 0xb6, 0x33, 0x7c, 0x85, 0x93, 0x8a, 0x79, 0x81, 0x3d, 0x20, 0x21, 0xd6, - 0x09, 0x4c, 0x68, 0xb3, 0x75, 0xe9, 0x84, 0xf6, 0x83, 0x93, 0x30, 0x08, 0x71, 0xe3, - 0x48, 0xfc, 0x52, 0x36, 0xcc, 0xa6, 0x33, 0x05, 0xac, 0x63, 0x65, 0x51, 0x63, 0x41, - 0x87, 0x01, 0xff, 0x01, 0x86, 0xd2, 0x6f, 0xee, 0x28, 0xca, 0x06, 0x00, 0x01, 0xac, - 0x5a, 0xa7, 0x27, 0xab, 0x79, 0x85, 0xda, 0x0e, 0x00, - ], - script_code: Script(vec![0x65, 0x53, 0x51]), - transparent_input: Some(1), - hash_type: 130, - amount: 449567650863240, - consensus_branch_id: consensus::BranchId::Overwinter, - sighash: [ - 0x49, 0x3d, 0x49, 0xc3, 0xe2, 0x22, 0x5d, 0x11, 0xc4, 0x64, 0x05, 0x18, 0x20, 0x14, - 0x76, 0x25, 0xf3, 0x90, 0x9f, 0xa7, 0x18, 0x9f, 0x61, 0xc7, 0xea, 0xec, 0xfc, 0x6d, - 0xad, 0x2e, 0x82, 0x03, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x00, 0x02, 0xe9, 0x6a, 0xa7, 0x3c, - 0xd9, 0xd1, 0x04, 0x00, 0x02, 0x00, 0x53, 0x06, 0xf6, 0x99, 0xe0, 0xb1, 0x9a, 0x04, - 0x00, 0x06, 0xac, 0x65, 0x65, 0x51, 0xac, 0x51, 0x0e, 0x68, 0xae, 0x38, 0x75, 0x05, - 0x51, 0x13, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x92, 0xf1, 0x35, 0xbf, 0x5f, 0x68, 0x78, 0x7d, - 0x37, 0x0c, 0xa8, 0xc4, 0xc4, 0x07, 0x4d, 0xc5, 0xd6, 0x01, 0xae, 0x90, 0x49, 0x54, - 0x37, 0xc3, 0xc2, 0xd4, 0x8a, 0x3d, 0x96, 0x66, 0x83, 0xac, 0x05, 0x16, 0x0b, 0x7a, - 0x84, 0xea, 0xa7, 0xaa, 0xb7, 0x40, 0x09, 0xe5, 0x7a, 0x85, 0xf7, 0xbf, 0x68, 0xa2, - 0xe4, 0x82, 0x00, 0x0f, 0x82, 0x9c, 0x54, 0x50, 0x73, 0xa1, 0x5d, 0x5c, 0xd0, 0xfc, - 0xc5, 0x74, 0x39, 0xa4, 0x35, 0x0e, 0xaf, 0x09, 0x8d, 0xfb, 0x82, 0xa0, 0x85, 0xea, - 0x8a, 0x4a, 0xf6, 0xfa, 0x83, 0x81, 0xf0, 0x65, 0x88, 0x19, 0xea, 0xb4, 0x83, 0xf6, - 0x5b, 0x32, 0x5d, 0x5a, 0xed, 0xa1, 0x52, 0x32, 0xcf, 0xad, 0xec, 0x75, 0xab, 0x18, - 0x66, 0xe4, 0xc0, 0x15, 0x5a, 0x9c, 0x74, 0xa7, 0xa5, 0x7c, 0xcf, 0x34, 0xc4, 0x83, - 0xac, 0x7d, 0xa1, 0x58, 0x8a, 0x1b, 0x6b, 0x99, 0x41, 0xf1, 0x10, 0x40, 0xf9, 0x4c, - 0xf7, 0x8f, 0xad, 0x89, 0xbf, 0x11, 0xfe, 0xd6, 0x9a, 0xa0, 0xd8, 0x31, 0x05, 0xad, - 0xac, 0xdd, 0x4e, 0x5f, 0x04, 0xa6, 0x24, 0x24, 0x02, 0x3c, 0x9b, 0x9e, 0x33, 0xc4, - 0xfb, 0x7f, 0x12, 0xbd, 0xf2, 0x1f, 0x07, 0xf2, 0x65, 0xc5, 0x37, 0xd5, 0x1c, 0x65, - 0x51, 0xf4, 0x61, 0x7b, 0x91, 0x5d, 0x21, 0x99, 0x18, 0x39, 0xc3, 0xd0, 0xd3, 0x63, - 0x93, 0xd6, 0x46, 0xe0, 0xa8, 0xa4, 0x15, 0x09, 0x21, 0x7d, 0x0e, 0x7d, 0x2c, 0xa1, - 0xa0, 0xa0, 0xd6, 0x77, 0xa3, 0xea, 0xca, 0x23, 0xed, 0xeb, 0x07, 0xb7, 0x4e, 0x65, - 0x2a, 0x0b, 0xc5, 0x0c, 0x6c, 0x08, 0x3a, 0x55, 0xd6, 0xc7, 0x30, 0x6e, 0x74, 0x08, - 0x6f, 0x47, 0x68, 0x93, 0x3a, 0xa2, 0x48, 0x73, 0x68, 0x18, 0x67, 0xa7, 0x89, 0x3d, - 0x77, 0xcb, 0x7f, 0x29, 0xb8, 0xc8, 0x47, 0xc5, 0x83, 0xf2, 0xd0, 0x71, 0xa6, 0x86, - 0x61, 0x6e, 0x20, 0x67, 0x19, 0xf7, 0x61, 0xae, 0x39, 0xc1, 0x10, 0x44, 0x2e, 0x06, - 0x16, 0x3d, 0x2b, 0x84, 0x59, 0x03, 0x60, 0x69, 0x5d, 0x4e, 0x19, 0x84, 0x9e, 0x03, - 0x4f, 0x24, 0xd9, 0xad, 0x39, 0x6c, 0x19, 0xff, 0x83, 0xce, 0x74, 0xf4, 0x6e, 0x64, - 0x5f, 0x93, 0x2e, 0x14, 0x1a, 0x41, 0x19, 0x59, 0x36, 0xc8, 0x5d, 0x51, 0x44, 0x14, - 0xf1, 0x12, 0xe6, 0x0b, 0x02, 0x25, 0x37, 0xc3, 0x8d, 0x6d, 0xc6, 0xc4, 0x63, 0x83, - 0x05, 0xc9, 0xbd, 0x6c, 0x62, 0xe3, 0x66, 0xbc, 0x63, 0x12, 0x3e, 0x3e, 0x6d, 0xd3, - 0x6e, 0xed, 0xd3, 0x13, 0x6f, 0xce, 0x8d, 0xee, 0xca, 0x0a, 0xa0, 0x9a, 0x32, 0x98, - 0xa3, 0x9d, 0x83, 0x85, 0x9e, 0xfc, 0x9b, 0x2b, 0x69, 0xcf, 0x9a, 0x7d, 0xee, 0x08, - 0xa9, 0x8e, 0x4b, 0xe5, 0x58, 0xac, 0x79, 0x12, 0xfd, 0xcb, 0x42, 0x20, 0x90, 0x75, - 0x42, 0x02, 0x60, 0xf7, 0xca, 0xd0, 0xf2, 0xc0, 0x1f, 0x2a, 0xfe, 0x33, 0x07, 0x3f, - 0x26, 0x24, 0x9d, 0x94, 0x4f, 0x7a, 0x50, 0xdd, 0x84, 0x83, 0x9b, 0xc3, 0xea, 0x7f, - 0xde, 0xe4, 0xed, 0x71, 0x02, 0x9c, 0xf0, 0x75, 0x33, 0xd2, 0x6e, 0x1e, 0x27, 0xa3, - 0xef, 0xb0, 0x32, 0xc3, 0xa3, 0xb3, 0x4b, 0xd3, 0x09, 0x26, 0x22, 0xd2, 0x06, 0x2a, - 0xe5, 0x36, 0xef, 0x51, 0x49, 0xc4, 0x9b, 0x5b, 0xc9, 0x03, 0x5e, 0xaf, 0xab, 0x6e, - 0x67, 0x57, 0x61, 0x00, 0x8b, 0x0d, 0xad, 0xde, 0xec, 0xaa, 0x60, 0x44, 0x70, 0xbb, - 0xe0, 0xfa, 0xda, 0x25, 0x5d, 0x29, 0x0e, 0x92, 0xb1, 0x90, 0xc2, 0xc2, 0xd8, 0xc2, - 0x02, 0xe5, 0x45, 0x5d, 0x1f, 0xa9, 0xa9, 0xf3, 0xdb, 0x77, 0x79, 0xb5, 0x84, 0x64, - 0x34, 0x64, 0xaa, 0x80, 0x14, 0xba, 0x66, 0x99, 0x4d, 0xe2, 0x55, 0x17, 0xf8, 0x39, - 0x80, 0xe6, 0x6e, 0xe4, 0xf6, 0x03, 0x14, 0xae, 0x6d, 0xbe, 0xf4, 0x52, 0xd5, 0xd3, - 0x8b, 0x0a, 0x16, 0xf3, 0x99, 0x1f, 0x36, 0xd8, 0xa8, 0xb3, 0x9d, 0xdc, 0x0d, 0x55, - 0x95, 0xee, 0xd9, 0x87, 0x62, 0x87, 0x8c, 0xdf, 0x3f, 0x4a, 0x02, 0xdc, 0x5c, 0xda, - 0x77, 0xd5, 0xfe, 0x4f, 0xaf, 0x63, 0xa1, 0x5f, 0x56, 0x8a, 0x54, 0x0d, 0xa5, 0x7d, - 0xd9, 0xbe, 0xb6, 0xfb, 0x1a, 0x97, 0x7c, 0xcb, 0x91, 0xb4, 0xd7, 0x9c, 0xb3, 0x9b, - 0x28, 0x91, 0x1a, 0x29, 0xe7, 0xbf, 0x02, 0x8a, 0xc6, 0x10, 0x37, 0x96, 0xdf, 0xb6, - 0xb2, 0x09, 0x67, 0x23, 0x9a, 0xd3, 0x73, 0xc3, 0x8c, 0x53, 0xf6, 0xdf, 0x18, 0x23, - 0xd4, 0x95, 0x0a, 0x02, 0x83, 0xe9, 0x9b, 0x9c, 0x06, 0xab, 0x29, 0x66, 0x66, 0x7c, - 0x9d, 0xf6, 0x77, 0x71, 0x6b, 0x0c, 0xad, 0xed, 0x81, 0x8d, 0xf9, 0xe4, 0x49, 0xc0, - 0x72, 0xe2, 0x2f, 0x9d, 0x98, 0xbb, 0x0f, 0x9b, 0x03, 0xbd, 0x5f, 0xd0, 0x13, 0xfc, - 0xef, 0x3e, 0xd6, 0xa4, 0x9a, 0xeb, 0x98, 0x72, 0x02, 0x54, 0x08, 0x7e, 0xf7, 0x28, - 0xe3, 0x19, 0x47, 0xff, 0xe8, 0xf7, 0x66, 0xe6, 0x3e, 0xe4, 0x6f, 0xf2, 0x08, 0x16, - 0xd5, 0xfa, 0x8f, 0xf5, 0x5a, 0x26, 0x39, 0x89, 0x61, 0x49, 0x0a, 0xb9, 0xae, 0x36, - 0x6f, 0xc5, 0xa2, 0xd1, 0x99, 0x6e, 0xd6, 0x93, 0xcc, 0xca, 0x82, 0x35, 0x6f, 0x60, - 0x0a, 0xb0, 0x99, 0xf6, 0xec, 0xa8, 0xbf, 0xe6, 0x45, 0x27, 0x0d, 0x3f, 0x95, 0xed, - 0xba, 0x5b, 0x0d, 0xe7, 0xa3, 0x28, 0x19, 0x23, 0x3b, 0xcc, 0x75, 0x4a, 0x5c, 0xe2, - 0xe5, 0xea, 0x07, 0x84, 0x2e, 0x5f, 0xf2, 0xce, 0xbe, 0x62, 0xad, 0x76, 0xe8, 0xef, - 0xf8, 0xd1, 0x5e, 0xa4, 0xc2, 0x4a, 0x5f, 0x20, 0x78, 0x68, 0x31, 0x9a, 0x5a, 0xf6, - 0xb0, 0x35, 0xbe, 0x3f, 0x44, 0xf4, 0x34, 0x09, 0x4f, 0x6e, 0x52, 0x5b, 0xe6, 0x14, - 0xda, 0xc9, 0x20, 0xa3, 0x30, 0xbd, 0xfb, 0x26, 0xd7, 0x5f, 0xe7, 0xb4, 0xb3, 0x65, - 0xd0, 0x94, 0x45, 0x92, 0x50, 0xaa, 0xa5, 0x54, 0x44, 0x89, 0xfb, 0x1d, 0x99, 0x25, - 0x81, 0x80, 0x0a, 0x77, 0xb8, 0x91, 0x21, 0x57, 0xfc, 0x97, 0x13, 0xaa, 0xac, 0x25, - 0xb4, 0xc2, 0x6e, 0xb0, 0x3f, 0x71, 0x66, 0x46, 0x61, 0x9a, 0xf0, 0x24, 0x56, 0xae, - 0x69, 0x59, 0x62, 0xfe, 0x5e, 0x93, 0x1a, 0x63, 0xb5, 0xc7, 0x90, 0x52, 0xec, 0xd3, - 0x33, 0xe1, 0x84, 0x12, 0xdb, 0x91, 0xe1, 0x5f, 0x7c, 0xbc, 0x70, 0xb4, 0xcd, 0x7e, - 0x8e, 0x3c, 0x95, 0x1f, 0x35, 0x85, 0x72, 0xe3, 0x77, 0x67, 0xe7, 0xd5, 0x27, 0x04, - 0xa6, 0x72, 0x1b, 0x30, 0xef, 0xc4, 0x10, 0x17, 0xae, 0x4d, 0x23, 0x15, 0x58, 0xc5, - 0xc8, 0x2c, 0xc7, 0xdd, 0x7e, 0x33, 0x56, 0xc0, 0x9d, 0xc2, 0x49, 0x06, 0xf0, 0x43, - 0x8d, 0xfc, 0xc3, 0x00, 0x85, 0x6a, 0xc2, 0xce, 0xd8, 0xf7, 0x7f, 0xa8, 0x01, 0x57, - 0x36, 0xc6, 0x61, 0xe8, 0x02, 0x48, 0xae, 0xeb, 0x77, 0x48, 0x74, 0xaa, 0x79, 0xd2, - 0x90, 0xb8, 0xf5, 0x02, 0x7a, 0x0a, 0x50, 0x95, 0x37, 0xfc, 0x7c, 0x68, 0x9b, 0x7a, - 0xd8, 0x61, 0x16, 0xcf, 0xec, 0x26, 0x47, 0xcc, 0xaa, 0xe1, 0xc7, 0x4b, 0x41, 0x6f, - 0x3e, 0x6a, 0xe8, 0xf7, 0xcc, 0x60, 0xea, 0xaf, 0x7b, 0x6a, 0x59, 0x0d, 0x51, 0x54, - 0x41, 0x38, 0xe1, 0x73, 0x29, 0x45, 0x60, 0x3a, 0x53, 0x46, 0x2c, 0x60, 0xe1, 0xf6, - 0xcb, 0x0c, 0x9c, 0xa0, 0x39, 0x0c, 0x48, 0x82, 0x24, 0xc3, 0x13, 0x26, 0x9f, 0xcd, - 0x59, 0xfc, 0xb6, 0x11, 0xfb, 0x2d, 0x9b, 0x4c, 0x8f, 0xa6, 0x01, 0xbb, 0x1c, 0xb8, - 0xd0, 0x7d, 0x79, 0x7b, 0xf5, 0xde, 0x52, 0xbc, 0xee, 0xb0, 0x23, 0x01, 0xc8, 0x96, - 0x2a, 0xc1, 0xfc, 0x04, 0x91, 0xdc, 0x81, 0xaf, 0xfd, 0x6c, 0x1e, 0xbf, 0x89, 0xa1, - 0x3d, 0x6f, 0x29, 0x0e, 0xda, 0x5d, 0x5c, 0xef, 0x38, 0x22, 0x15, 0xc5, 0xe9, 0x51, - 0xd7, 0x13, 0x05, 0xef, 0x33, 0xd9, 0x73, 0x71, 0x26, 0xd0, 0xe6, 0x62, 0x90, 0x5f, - 0x12, 0x50, 0x92, 0x6f, 0x6a, 0x22, 0x99, 0x90, 0xe3, 0x8f, 0x69, 0xad, 0x9a, 0x91, - 0x92, 0xb3, 0x02, 0xf2, 0x6b, 0xdd, 0xa4, 0x65, 0xd9, 0x0b, 0x94, 0xb1, 0x2c, 0x57, - 0xfa, 0x3f, 0xd6, 0x93, 0x00, 0x83, 0xf1, 0x84, 0x43, 0x8d, 0x8a, 0x88, 0x9d, 0x3f, - 0x5e, 0xce, 0xa2, 0xc6, 0xd2, 0x3d, 0x67, 0x36, 0xf2, 0xa0, 0xf1, 0x8e, 0x26, 0xf4, - 0xfa, 0x45, 0xd1, 0xbe, 0x8f, 0x3d, 0xc4, 0xa7, 0x07, 0x13, 0x7e, 0x95, 0xd2, 0xad, - 0x59, 0x4f, 0x6c, 0x03, 0xd2, 0x49, 0x23, 0x06, 0x7a, 0xe4, 0x7f, 0xd6, 0x42, 0x5e, - 0xfb, 0x9c, 0x1d, 0x50, 0x4e, 0x6f, 0xd5, 0x57, 0x53, 0x40, 0x94, 0x56, 0x01, 0xfe, - 0x80, 0x6f, 0x57, 0x56, 0xac, 0xb5, 0x62, 0xf1, 0x3c, 0x0c, 0xa1, 0xd8, 0x03, 0xa1, - 0x95, 0xc2, 0xeb, 0xb2, 0xef, 0x02, 0xac, 0x33, 0xe6, 0xa8, 0x8d, 0xea, 0x07, 0x5b, - 0xa9, 0x96, 0xd3, 0xc3, 0x36, 0x64, 0x8e, 0x86, 0x94, 0xd3, 0xa1, 0x9d, 0x3d, 0xca, - 0x53, 0x1b, 0xeb, 0x50, 0xd4, 0x32, 0x7c, 0x5c, 0x0c, 0x23, 0xcb, 0x7c, 0xfd, 0xb0, - 0x8c, 0xa7, 0xcf, 0x2c, 0xac, 0x6b, 0xc1, 0x39, 0xd0, 0x74, 0x14, 0x73, 0xd3, 0x76, - 0x02, 0x9c, 0xb4, 0xab, 0x6b, 0xf0, 0x54, 0x55, 0x7c, 0xe2, 0x94, 0xc7, 0x28, 0xa4, - 0x68, 0x7d, 0x57, 0xec, 0x89, 0x09, 0xff, 0x51, 0xa4, 0xd0, 0x2f, 0x9d, 0xcd, 0x11, - 0x19, 0x3d, 0x7d, 0x1c, 0x9f, 0xda, 0xe6, 0xa1, 0x73, 0x96, 0xa1, 0xbf, 0x57, 0xa9, - 0x94, 0x93, 0x4f, 0x5e, 0x7a, 0x59, 0xf0, 0x45, 0xde, 0xbe, 0xaf, 0xf6, 0x2e, 0xf3, - 0x26, 0xb9, 0x47, 0xf2, 0xa8, 0xb4, 0x95, 0x55, 0xe4, 0xd9, 0x9b, 0x3b, 0xf5, 0xc8, - 0x1f, 0xf9, 0xfe, 0x31, 0x4e, 0x04, 0x7a, 0xf1, 0x52, 0x50, 0x8f, 0x57, 0x01, 0x5c, - 0xa4, 0x02, 0xc6, 0x7d, 0x92, 0x5c, 0x99, 0xac, 0xea, 0x3e, 0xe8, 0xcc, 0x4b, 0x00, - 0x8c, 0x5c, 0xb4, 0x39, 0x66, 0xe7, 0x14, 0xef, 0x48, 0x0f, 0xd0, 0x5e, 0x07, 0xc7, - 0xb2, 0xdd, 0xa9, 0xaa, 0x39, 0x66, 0x11, 0x3e, 0xaa, 0x29, 0x3d, 0x3f, 0x62, 0x2b, - 0x30, 0x9d, 0x64, 0x80, 0x3c, 0xe1, 0xe6, 0x37, 0x8b, 0x6a, 0xac, 0x4f, 0xab, 0x52, - 0x7c, 0x43, 0xcd, 0x45, 0xed, 0x0a, 0x3c, 0x1a, 0x4b, 0x9f, 0xb1, 0x8d, 0xcc, 0xcf, - 0xcd, 0xb6, 0xac, 0x0c, 0x24, 0x21, 0x63, 0x9c, 0xda, 0x00, 0x75, 0xa2, 0x0d, 0xc5, - 0x11, 0x1b, 0x8d, 0x3d, 0x31, 0x99, 0x49, 0x5b, 0xd9, 0x13, 0x3d, 0xba, 0xb9, 0x45, - 0x41, 0x41, 0x0e, 0x4f, 0xba, 0x92, 0xc7, 0xb6, 0x06, 0xa5, 0xcb, 0x12, 0x2f, 0x14, - 0x0c, 0xf1, 0xa3, 0x59, 0x6f, 0x27, 0x88, 0xf3, 0xc8, 0xb9, 0x26, 0x60, 0xf1, 0x4c, - 0xb6, 0x5a, 0xf5, 0xdd, 0x23, 0xdf, 0xdb, 0xac, 0x13, 0x71, 0xec, 0xf4, 0xb3, 0x37, - 0x12, 0xfe, 0xd2, 0x29, 0x2c, 0x44, 0xf7, 0x08, 0x34, 0xcf, 0x96, 0xc0, 0x5d, 0x58, - 0x82, 0x7e, 0x69, 0xbf, 0xc2, 0xe6, 0x96, 0xfa, 0x08, 0x74, 0x86, 0x9c, 0x02, 0xf3, - 0xdc, 0xa1, 0x1c, 0x3b, 0x90, 0xcb, 0x21, 0x4e, 0x68, 0xbc, 0x1c, 0xae, 0x03, 0x9d, - 0x7a, 0x14, 0x6c, 0xdc, 0x1d, 0x60, 0x9d, 0x7a, 0x6b, 0x3f, 0xd5, 0xd4, 0x61, 0xb0, - 0x95, 0x1c, 0x82, 0xcf, 0xb3, 0xe7, 0x63, 0xfa, 0xd2, 0xd1, 0xbc, 0x76, 0x78, 0xcd, - 0xf8, 0x27, 0x79, 0xf8, 0xfd, 0x5a, 0x1c, 0xe2, 0x2a, 0x8d, 0x3c, 0x45, 0x47, 0xab, - 0xd9, 0x59, 0x83, 0x8a, 0x46, 0xfb, 0x80, 0xaf, 0xe0, 0x1f, 0x8e, 0xcc, 0x99, 0x31, - 0x51, 0x3b, 0x19, 0x62, 0xec, 0x54, 0x08, 0x56, 0xcb, 0x18, 0x93, 0x87, 0xcf, 0xbf, - 0xcc, 0x0f, 0x7c, 0x68, 0x22, 0x3c, 0xba, 0x47, 0xfb, 0x0c, 0x9b, 0x48, 0x6e, 0x4d, - 0x99, 0x17, 0x19, 0x41, 0xf7, 0x67, 0x5a, 0x8b, 0x46, 0x32, 0x8a, 0x3b, 0xc1, 0x09, - 0xbf, 0x07, 0xc6, 0x6d, 0x5e, 0xde, 0x77, 0x1c, 0xc4, 0xc7, 0x4c, 0xe8, 0x03, 0x33, - 0x82, 0x91, 0x91, 0xee, 0xdc, 0x49, 0x35, 0x08, 0xa6, 0x44, 0x53, 0x0a, 0x61, 0x44, - 0xf2, 0x2d, 0xcf, 0x97, 0x52, 0x5a, 0x4c, 0xdc, 0xa1, 0xad, 0x71, 0x07, 0x3b, 0x08, - 0x0b, 0x73, 0xea, 0x45, 0x49, 0xf5, 0x40, 0x1b, 0xff, 0x43, 0x18, 0x26, 0x8e, 0x6a, - 0xd6, 0x37, 0x36, 0x31, 0x57, 0xa1, 0x9a, 0x53, 0xf1, 0x23, 0xa0, 0xb0, 0xe1, 0x6d, - 0x0b, 0x77, 0xf0, 0x20, 0x28, 0xda, 0x46, 0x41, 0x00, 0xfd, 0xe7, 0x6d, 0x83, 0xdd, - 0x0b, 0xb2, 0x24, 0xf7, 0xb5, 0x7a, 0x00, 0xc0, 0x2f, 0x68, 0xae, 0x64, 0x8f, 0xdc, - 0x52, 0x99, 0x57, 0xa1, 0x04, 0x90, 0xdc, 0xe1, 0xfd, 0xdb, 0xb0, 0x90, 0x4f, 0x0d, - 0x51, 0x8b, 0xb3, 0x87, 0x54, 0x40, 0x19, 0x98, 0x3b, 0x61, 0x69, 0x75, 0xa7, 0x8e, - 0x74, 0xd8, 0x54, 0xfd, 0xdc, 0x49, 0xb2, 0x55, 0x16, 0x7b, 0x55, 0xef, 0x4b, 0xee, - 0x46, 0x56, 0x68, 0xb2, 0x0e, 0xa4, 0x11, 0x8c, 0xa5, 0x69, 0xae, 0x48, 0x0e, 0x0f, - 0x6e, 0x5e, 0x04, 0x3a, 0x35, 0x7b, 0x36, 0xd3, 0xab, 0x36, 0xc8, 0x61, 0xf2, 0x27, - 0x83, 0x01, 0xdc, 0xe5, 0x76, 0x74, 0xd5, 0x07, 0x3b, 0x3a, 0x6f, 0x51, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xa0, 0x79, 0x3a, 0xf1, 0xb7, 0xd4, 0x6f, 0x95, 0x7e, 0x22, 0xd8, 0xd2, 0x58, - 0x3b, 0xf1, 0x81, 0x83, 0x6c, 0x3b, 0xe9, 0x93, 0x0b, 0xac, 0x8f, 0xa4, 0x60, 0xe9, - 0x68, 0xaa, 0x71, 0x09, 0x87, 0x0b, 0xbe, 0xd1, 0x7d, 0xf5, 0xf8, 0x88, 0xc8, 0xca, - 0x14, 0x67, 0xae, 0x17, 0xdb, 0xbc, 0xde, 0x31, 0xc1, 0x10, 0x5c, 0xb5, 0xbd, 0xa8, - 0x8a, 0xc6, 0xc6, 0x27, 0x00, 0x2c, 0xe2, 0x1c, 0x02, 0x14, 0x0f, 0xfe, 0x81, 0xec, - 0x58, 0xbf, 0x1e, 0x6d, 0x1b, 0xb7, 0xaa, 0xad, 0xa4, 0x1f, 0xba, 0x0b, 0xb5, 0x88, - 0x77, 0x8a, 0x7f, 0x65, 0x20, 0x2a, 0xd8, 0x11, 0xea, 0x73, 0xd2, 0x6c, 0x74, 0x55, - 0x03, 0x95, 0xaf, 0xf7, 0x53, 0x25, 0x10, 0x7c, 0x9b, 0x3f, 0x9a, 0xe9, 0xdc, 0xdc, - 0xd8, 0x6e, 0xd0, 0x81, 0xa2, 0xe7, 0x42, 0x47, 0x19, 0xa3, 0xd1, 0x85, 0xb7, 0xe0, - 0xa4, 0x3a, 0x47, 0x2e, 0x29, 0x8a, 0xc0, 0xaf, 0xdc, 0x52, 0x87, 0xd7, 0xad, 0x12, - 0x4c, 0xd9, 0x40, 0x5a, 0x62, 0xcd, 0x1c, 0xa0, 0x8b, 0x28, 0x2e, 0xfe, 0xf7, 0xf9, - 0x28, 0xdf, 0x76, 0xe2, 0x82, 0x1a, 0x41, 0x84, 0x13, 0xeb, 0x7c, 0xea, 0xa5, 0xff, - 0x12, 0x90, 0xb0, 0x3e, 0xc9, 0x1c, 0xe6, 0xdd, 0x28, 0x13, 0x0c, 0x3a, 0xb0, 0xb2, - 0x3b, 0x60, 0x2b, 0xd5, 0xbe, 0x5d, 0xc2, 0x60, 0x03, 0xaa, 0xe0, 0x4b, 0x33, 0xd7, - 0xbd, 0x25, 0x90, 0xe9, 0x0c, 0x8c, 0x38, 0x8e, 0xa7, 0x95, 0x51, 0x22, 0xdb, 0xac, - 0xa6, 0x7b, 0x30, 0x39, 0x5a, 0x92, 0x8b, 0x57, 0xb8, 0x57, 0x51, 0x23, 0x20, 0x5a, - 0xe1, 0x91, 0x52, 0xe4, 0x1e, 0x00, 0x29, 0x31, 0xb4, 0x57, 0x46, 0x19, 0x8e, 0x5d, - 0xd9, 0x57, 0x1a, 0x56, 0xa7, 0xe0, 0xd4, 0x23, 0xff, 0x27, 0x98, 0x9d, 0x3e, 0xb4, - 0x17, 0xec, 0xd3, 0xc3, 0x09, 0x3f, 0xb8, 0x2c, 0x56, 0x58, 0xe2, 0x96, 0x24, 0xc5, - 0x32, 0x19, 0xa6, 0x0c, 0xd0, 0xa8, 0xc4, 0xda, 0x36, 0x7e, 0x29, 0xa7, 0x17, 0x79, - 0xa7, 0x30, 0x32, 0x98, 0x5a, 0x3d, 0x1f, 0xd0, 0x3d, 0x02, 0xd0, 0x6e, 0x05, 0x56, - 0x6f, 0x3b, 0x84, 0x36, 0x7c, 0xf0, 0xfa, 0xee, 0x9b, 0xc3, 0xbd, 0x7a, 0x3a, 0x60, - 0x6a, 0x9f, 0xdb, 0x84, 0x9c, 0x5d, 0x82, 0xd0, 0xa6, 0x19, 0x23, 0xc2, 0xe5, 0xd8, - 0x02, 0x63, 0xa8, 0xa5, 0x0c, 0x38, 0xbd, 0x03, 0x87, 0x72, 0xc4, 0x14, 0x3d, 0x8b, - 0x7a, 0xcf, 0xd7, 0x4e, 0x72, 0xc0, 0x4d, 0x89, 0x24, 0x8d, 0xff, 0x20, 0xfe, 0x8d, - 0xc5, 0xec, 0x21, 0x49, 0x05, 0x0a, 0xa2, 0x41, 0x64, 0xe8, 0x5f, 0x67, 0x44, 0xad, - 0x0c, 0xac, 0xf1, 0xa8, 0xb7, 0x01, 0x26, 0xf4, 0x82, 0xc0, 0x92, 0xed, 0x9f, 0x61, - 0x27, 0xd2, 0x05, 0x0d, 0x12, 0xe8, 0x78, 0xa7, 0x96, 0x53, 0xa1, 0xe8, 0x4d, 0xae, - 0xc3, 0xeb, 0xe6, 0x2d, 0x5f, 0x6c, 0x4a, 0xbe, 0x5c, 0xe9, 0x0a, 0x7f, 0xe2, 0xe5, - 0x2a, 0x8d, 0x78, 0x46, 0xe8, 0xed, 0xf2, 0xf2, 0xbc, 0xe0, 0x5a, 0x03, 0x7c, 0x82, - 0x03, 0x22, 0xca, 0xad, 0x12, 0x61, 0x46, 0x7d, 0xcf, 0xb7, 0xd6, 0xb6, 0x13, 0x3d, - 0xc2, 0x1e, 0x80, 0x96, 0xc7, 0xe9, 0xf8, 0xe9, 0xe1, 0x0c, 0x1e, 0x3f, 0xac, 0x40, - 0x58, 0xb6, 0x82, 0xc6, 0x8e, 0x02, 0xfa, 0xca, 0xe0, 0xf9, 0xc2, 0xdd, 0x4d, 0x64, - 0xd9, 0x04, 0x61, 0x52, 0xb4, 0x76, 0x23, 0x32, 0x93, 0x9f, 0x17, 0xe6, 0xaa, 0xf7, - 0xd8, 0xb9, 0xd3, 0x58, 0xe2, 0x21, 0x8d, 0x4e, 0x0d, 0x69, 0x02, 0xf1, 0x19, 0xe1, - 0xc6, 0x4e, 0xec, 0x4c, 0x8b, 0x53, 0x28, 0x09, 0x70, 0x71, 0x31, 0xf0, 0x1f, 0x55, - 0xc7, 0xad, 0x04, 0xcf, 0xb6, 0x3f, 0x7c, 0x4a, 0x3d, 0x0a, 0x2b, 0x0f, 0xfb, 0x0b, - 0x05, 0x02, 0xbe, 0x05, 0x5b, 0x8c, 0x94, 0xca, 0x80, 0xbb, 0x0a, 0x1d, 0x13, 0xcd, - 0x4c, 0xd6, 0x9a, 0xb9, 0x83, 0x04, 0xae, 0x25, 0x15, 0xd5, 0xf7, 0x69, 0x9d, 0x4a, - 0xbe, 0xe5, 0xc2, 0x0b, 0xe6, 0x09, 0x02, 0x73, 0x51, 0x10, 0x12, 0xf2, 0x34, 0xbd, - 0x85, 0xa7, 0xef, 0xf5, 0xfb, 0x63, 0x4c, 0xff, 0x26, 0x58, 0xba, 0x65, 0x16, 0x04, - 0x85, 0x63, 0x09, 0x5e, 0xce, 0xfb, 0x30, 0x15, 0xee, 0x3f, 0x03, 0xca, 0x52, 0xa1, - 0x77, 0xf2, 0x61, 0xec, 0xdc, 0x26, 0xbc, 0x08, 0x9d, 0x34, 0xc6, 0x40, 0x48, 0x46, - 0xe9, 0xc6, 0x47, 0xfc, 0xfe, 0x98, 0xcc, 0x6a, 0xcd, 0xbb, 0x46, 0x4f, 0x64, 0x27, - 0x8a, 0xd8, 0xce, 0x9d, 0x1a, 0xe0, 0xd4, 0x15, 0xbc, 0x0c, 0x05, 0x24, 0x5f, 0xdd, - 0xaf, 0x4e, 0xbc, 0x8d, 0xc7, 0x03, 0xa8, 0x5c, 0xb2, 0x70, 0xf7, 0x96, 0xad, 0x2d, - 0x93, 0x7e, 0x2a, 0xc0, 0xd5, 0xe0, 0xa3, 0x48, 0x21, 0x75, 0x80, 0x00, 0xaa, 0x59, - 0xc9, 0xd4, 0x65, 0x24, 0x85, 0x29, 0x4e, 0xe0, 0xab, 0x29, 0x69, 0x6b, 0x21, 0x43, - 0x0f, 0xa5, 0x4d, 0xcf, 0xbf, 0x2b, 0x9c, 0x49, 0xd1, 0x42, 0x06, 0x42, 0x09, 0xee, - 0xee, 0xd4, 0xd4, 0x71, 0xff, 0xc0, 0x17, 0xd4, 0xe2, 0x0a, 0x79, 0x6b, 0x09, 0x27, - 0x80, 0x4c, 0x06, 0x1b, 0x9f, 0x4a, 0x70, 0x91, 0xfe, 0x01, 0x5a, 0xda, 0x68, 0xfd, - 0x84, 0x42, 0xe0, 0x18, 0x25, 0xc8, 0x8d, 0xfe, 0x55, 0xcf, 0x5d, 0xe3, 0x89, 0x36, - 0xf7, 0xce, 0x25, 0x31, 0x1b, 0x90, 0x2b, 0xa9, 0x7a, 0x3c, 0x12, 0xa9, 0x5c, 0xfa, - 0x1c, 0x3a, 0x59, 0x1b, 0x81, 0x8f, 0x60, 0x83, 0x27, 0x09, 0xd9, 0xe4, 0x83, 0x9e, - 0x41, 0x0f, 0xb3, 0x6b, 0x84, 0xf3, 0xac, 0x4f, 0x07, 0x0f, 0xc3, 0x5e, 0x16, 0x19, - 0x78, 0x25, 0x9e, 0x5b, 0x8e, 0xdc, 0x74, 0x4d, 0x90, 0x91, 0x9a, 0xa7, 0x70, 0xbb, - 0x36, 0x21, 0x51, 0x28, 0xe5, 0x82, 0xb5, 0x96, 0x41, 0xe2, 0x38, 0x52, 0xe9, 0x58, - 0xeb, 0x8f, 0xc3, 0xc0, 0xaa, 0x96, 0x15, 0x2b, 0xa4, 0xf7, 0x7f, 0x13, 0x8d, 0x6a, - 0x67, 0x12, 0xa3, 0xae, 0x32, 0x26, 0x01, 0x58, 0x83, 0xf8, 0x1d, 0xb2, 0x3e, 0x58, - 0x3c, 0x86, 0x9c, 0x4c, 0x71, 0x14, 0x3a, 0x6f, 0xff, 0xd6, 0x5e, 0x8d, 0xfd, 0xc5, - 0x0c, 0x99, 0xa2, 0xf1, 0xf3, 0x14, 0xcd, 0xcc, 0x71, 0x35, 0x9e, 0x23, 0x5f, 0x1d, - 0x7d, 0xc2, 0xb5, 0xf3, 0x8e, 0xf7, 0xb9, 0x70, 0x84, 0x31, 0x63, 0xc0, 0x3f, 0x9d, - 0xd4, 0x0a, 0x80, 0x15, 0xef, 0xdc, 0x87, 0x91, 0x95, 0x6a, 0x3f, 0x3c, 0xed, 0xd9, - 0xea, 0x64, 0xf8, 0xef, 0xa7, 0xa0, 0x81, 0x5a, 0x70, 0x38, 0x1d, 0x71, 0x46, 0x78, - 0x17, 0xbd, 0x04, 0xca, 0x52, 0x9a, 0xed, 0xe0, 0x7f, 0xf6, 0x0d, 0x17, 0x6a, 0xed, - 0x0f, 0x85, 0x5a, 0x2e, 0xae, 0xa8, 0x9e, 0xae, 0xac, 0xa8, 0x93, 0x58, 0xc0, 0x81, - 0x82, 0x6a, 0x08, 0x12, 0xa5, 0xbc, 0xa2, 0x8b, 0xe1, 0x37, 0x3f, 0x08, 0x6d, 0xbd, - 0xba, 0x7e, 0x43, 0xe2, 0x03, 0x21, 0x2c, 0x9f, 0xed, 0x21, 0x47, 0x4b, 0xa1, 0x9a, - 0x05, 0x5f, 0xfc, 0xc1, 0x79, 0x41, 0x2e, 0x89, 0x3a, 0x74, 0x48, 0x32, 0x29, 0x8c, - 0x5f, 0xe2, 0x4c, 0xc6, 0xb1, 0x86, 0x67, 0xf4, 0x9b, 0x34, 0xdf, 0xb1, 0x23, 0x79, - 0x26, 0x74, 0x19, 0xa9, 0xcb, 0x94, 0x03, 0xd8, 0x16, 0x7d, 0x8d, 0x1e, 0x91, 0xd2, - 0x81, 0x1a, 0x04, 0x3b, 0x29, 0x24, 0x3b, 0x06, 0x9b, 0x37, 0x58, 0x78, 0x47, 0xdc, - 0x6f, 0xcd, 0xdb, 0x18, 0x31, 0xbd, 0x1c, 0xc2, 0x56, 0x7c, 0xa0, 0x33, 0xac, 0x40, - 0xf7, 0x4a, 0xb6, 0x95, 0x5f, 0x68, 0x3b, 0x12, 0xe4, 0xe8, 0x25, 0x4e, 0x4e, 0xa7, - 0x60, 0xd3, 0x8b, 0x3f, 0x46, 0x79, 0x1c, 0x5c, 0x4c, 0xb1, 0x2b, 0xc7, 0xcc, 0xb0, - 0xed, 0x18, 0x65, 0xf2, 0x5d, 0x60, 0x1c, 0x30, 0x3f, 0x81, 0xfb, 0x1f, 0xa1, 0xdb, - 0x48, 0x53, 0x3d, 0x3d, 0x6b, 0x28, 0x8e, 0x4d, 0x9a, 0x4d, 0xff, 0x8e, 0xc2, 0x1c, - 0x96, 0xf5, 0x78, 0x39, 0x97, 0x10, 0xc8, 0x25, 0xfe, 0x7e, 0x32, 0xf9, 0x3a, 0x8c, - 0x07, 0x43, 0xf9, 0xeb, 0xd5, 0x4c, 0xc1, 0x51, 0xc7, 0x61, 0x03, 0x37, 0xae, 0xbf, - 0x7e, 0x9b, 0x91, 0x57, 0x20, 0xa5, 0x43, 0x51, 0xd4, 0x9a, 0xb8, 0xc2, 0x2f, 0xa3, - 0x49, 0x98, 0xdc, 0xf5, 0x83, 0xd4, 0x38, 0x73, 0x61, 0xef, 0x3f, 0xf8, 0x6f, 0x50, - 0xec, 0x53, 0xf4, 0x92, 0x49, 0xe4, 0xad, 0x34, 0x96, 0x03, 0x06, 0x6f, 0xc9, 0xc6, - 0x61, 0xd6, 0x9f, 0x91, 0x1d, 0xfa, 0x72, 0x41, 0xc8, 0xd5, 0x79, 0x2d, 0x43, 0xc4, - 0x57, 0xd5, 0xde, 0x96, 0x52, 0x3a, 0x53, 0xd6, 0x67, 0xec, 0x5c, 0x4e, 0xf9, 0xd5, - 0x02, 0xa1, 0x6f, 0x15, 0x22, 0x47, 0x58, 0x96, 0xd7, 0x9b, 0xc5, 0x78, 0x33, 0xe9, - 0x77, 0x17, 0x1c, 0x32, 0x4d, 0xce, 0x2a, 0x1e, 0xa1, 0xe4, 0x30, 0x4f, 0x49, 0xe4, - 0x3a, 0xe0, 0x65, 0xe3, 0xfb, 0x19, 0x6f, 0x76, 0xd9, 0xb8, 0x79, 0xc7, 0x20, 0x08, - 0x62, 0xea, 0xd1, 0x8d, 0xea, 0x5f, 0xb6, 0xa1, 0x7a, 0xce, 0xa3, 0x33, 0x86, 0xeb, - 0x4c, 0xa1, 0xb5, 0x14, 0x86, 0xa9, 0x14, 0x8f, 0xbd, 0xf9, 0xa9, 0x53, 0x32, 0xaa, - 0x60, 0x5c, 0x5d, 0x54, 0x83, 0xce, 0x4b, 0xa8, 0xec, 0xe0, 0x1a, 0x8f, 0xf2, 0xb7, - 0xef, 0x82, 0xd0, 0x5c, 0x0b, 0x6e, 0x86, 0x1b, 0x91, 0x5f, 0x13, 0xca, 0x0e, 0xb3, - 0xea, 0x13, 0xd5, 0x07, 0x08, 0x07, 0xa2, 0xcb, 0x66, 0x80, 0xa2, 0x49, 0xea, 0x9c, - 0x72, 0x24, 0x39, 0x2c, 0xbc, 0x8a, 0xb8, 0x25, 0x01, 0xb2, 0x6f, 0x11, 0x2a, 0xc7, - 0x89, 0xa1, 0x2a, 0x31, 0xad, 0x13, 0x14, 0xe2, 0xed, 0xe0, 0x8f, 0xad, 0x31, 0x43, - 0xaf, 0x30, 0xc2, 0x7f, 0x40, 0x3b, 0xc8, 0x66, 0xc7, 0x55, 0x17, 0x78, 0x52, 0xaf, - 0xd0, 0xab, 0xb9, 0x0a, 0xde, 0x1d, 0x68, 0x27, 0x26, 0xf4, 0x20, 0x08, 0xb4, 0x6a, - 0xd7, 0xf8, 0xab, 0xdb, 0x18, 0x11, 0x7f, 0x72, 0x64, 0x13, 0x90, 0xf0, 0x86, 0xb6, - 0xe1, 0x49, 0x8b, 0xe6, 0x95, 0x48, 0x52, 0x7e, 0x6a, 0xda, 0x2b, 0x38, 0xb9, 0xfe, - 0x12, 0x1e, 0xf6, 0x70, 0xaf, 0x74, 0x37, 0xd3, 0x25, 0x36, 0xd5, 0xcf, 0x5c, 0x4a, - 0xb1, 0x9d, 0xd9, 0x97, 0x71, 0x58, 0x2d, 0x03, 0x81, 0x04, 0xb7, 0xe0, 0x39, 0xa3, - 0x76, 0xf7, 0xac, 0xbb, 0xea, 0xdb, 0x34, 0xf9, 0x45, 0xbe, 0xb9, 0xd7, 0xca, 0x0e, - 0x4e, 0x3d, 0x5c, 0x5e, 0x4e, 0xb1, 0xd8, 0x52, 0x6e, 0xbd, 0x13, 0xda, 0xcb, 0x1b, - 0xa3, 0x57, 0x35, 0xc6, 0xd0, 0x4a, 0x45, 0x55, 0xac, 0xf4, 0xbf, 0x11, 0x76, 0x26, - 0x50, 0x0d, 0x77, 0xb3, 0x81, 0x89, 0xdd, 0x48, 0x88, 0x04, 0x12, 0x25, 0xac, 0xbe, - 0x38, 0x74, 0xa4, 0xc0, 0xf6, 0x07, 0xfe, 0x67, 0x45, 0xf9, 0x35, 0x5b, 0x3f, 0xa1, - 0x88, 0xf1, 0xd6, 0x5c, 0x09, 0xf3, 0x89, 0xaf, 0x1b, 0x9d, 0x62, 0x32, 0xaa, 0x79, - 0x44, 0x79, 0x19, 0xc5, 0x50, 0xf6, 0xf3, 0x1f, 0xec, 0x35, 0x48, 0x1c, 0xb9, 0x22, - 0xde, 0x2d, 0xb5, 0xb4, 0xda, 0x2f, 0x81, 0x94, 0x86, 0x17, 0x02, 0x8e, 0x32, 0x17, - 0x06, 0xa3, 0xa7, 0x78, 0xc1, 0x93, 0x8c, 0x44, 0x3b, 0xb0, 0x0e, 0x5b, 0x0f, 0xf0, - 0x6a, 0xd8, 0xab, 0x9b, 0x1a, 0xb0, 0xc1, 0x14, 0x77, 0x67, 0x3f, 0x85, 0xdf, 0x95, - 0x61, 0xdb, 0xea, 0x45, 0xd5, 0xf9, 0x78, 0x1e, 0xbe, 0x31, 0x7a, 0x07, 0x10, 0xae, - 0x54, 0x61, 0xe3, 0x4f, 0xe6, 0xf1, 0xb1, 0xaa, 0x9b, 0x4e, 0x67, 0xb1, 0x49, 0x10, - 0x98, 0x48, 0x02, 0xc2, 0xa7, 0xe3, 0x81, 0x93, 0xbc, 0x7b, 0xdc, 0x8b, 0xa3, 0xe4, - 0xe3, 0xd1, 0xd9, 0x33, 0xbf, 0xb5, 0x80, 0xf5, 0xb3, 0xe8, 0x7a, 0x2a, 0x06, 0x51, - 0x70, 0x51, 0x41, 0x0f, 0xe1, 0xb4, 0xff, 0x1e, 0xa0, 0xad, 0xe8, 0x24, 0xf3, 0x38, - 0x51, 0x54, 0x56, 0xa5, 0x7c, 0x7a, 0x91, 0x6a, 0x74, 0x38, 0x8e, 0xe8, 0xf1, 0x28, - 0x1f, 0x9a, 0xde, 0x0a, 0xe2, 0xa2, 0x61, 0x3a, 0x06, 0x12, 0xc4, 0x69, 0xdf, 0x79, - 0x2b, 0x8d, 0xf4, 0xca, 0xe4, 0xfc, 0x25, 0xc1, 0xca, 0xdb, 0xa9, 0x5a, 0x80, 0x7c, - 0xe6, 0x1e, 0x5a, 0x53, 0x03, 0xfa, 0xaf, 0x9e, 0x14, 0x65, 0x39, 0x96, 0xb5, 0xa8, - 0xad, 0xc3, 0x4f, 0xd4, 0x75, 0xef, 0x14, 0x99, 0x09, 0x4b, 0xab, 0xaf, 0x1f, 0x3f, - 0x07, 0xda, 0x9a, 0x39, 0x0b, 0x1d, 0x9f, 0xc9, 0xa0, 0x83, 0x27, 0x98, 0x7a, 0xdf, - 0xe9, 0x56, 0x48, 0x63, 0xfb, 0xdf, 0xa8, 0xf6, 0xb4, 0x6a, 0x88, 0x41, 0x58, 0x30, - 0x99, 0xaf, 0xb7, 0x87, 0x01, 0x18, 0xfa, 0xce, 0x76, 0x34, 0x7e, 0x40, 0xb6, 0xfd, - 0x8c, 0xd1, 0x55, 0x82, 0xae, 0x8e, 0x23, 0xbe, 0x9a, 0x02, 0x19, 0xbc, 0x3e, 0x4e, - 0x45, 0x46, 0xa3, 0x0d, 0x3b, 0xbb, 0xbd, 0x16, 0x86, 0x08, 0x68, 0x76, 0xbe, 0x0e, - 0x4c, 0x85, 0x9b, 0xe7, 0x1f, 0xb5, 0x8f, 0x4f, 0xab, 0x3d, 0x28, 0xc0, 0xb4, 0xf7, - 0xe7, 0x5a, 0xd1, 0xed, 0xb7, 0xf8, 0x89, 0x46, 0xfb, 0x40, 0xcf, 0xa5, 0x78, 0x6a, - 0x0f, 0xcb, 0xa1, 0x30, 0x3c, 0x83, 0x47, 0xec, 0xee, 0x93, 0xd4, 0x6d, 0x14, 0x0b, - 0xb5, 0xf6, 0x95, 0x31, 0xd6, 0x66, 0x54, 0x8b, 0x10, 0x9c, 0xe7, 0x64, 0xbe, 0xad, - 0x7c, 0x87, 0xbd, 0x4c, 0x87, 0x64, 0x94, 0xde, 0x82, 0xdb, 0x6e, 0x50, 0x73, 0xa6, - 0xc9, 0x4f, 0x7c, 0x09, 0x9a, 0x40, 0xd7, 0xa3, 0x1c, 0x4a, 0x04, 0xb6, 0x9c, 0x9f, - 0xcc, 0xf3, 0xc7, 0xdd, 0x56, 0xf5, 0x54, 0x47, 0x76, 0xc5, 0x3b, 0x4d, 0xf7, 0x95, - 0x39, 0x81, 0xd5, 0x5a, 0x96, 0xa6, 0xdc, 0xff, 0x99, 0x04, 0xa9, 0x08, 0x42, 0xe5, - 0xba, 0xfe, 0xc8, 0x84, 0x0c, 0x2d, 0x25, 0x5b, 0xf5, 0xad, 0x61, 0xc4, 0x60, 0xf9, - 0x8f, 0xeb, 0x82, 0xa1, 0x0f, 0xa1, 0xc0, - ], - script_code: Script(vec![0x65, 0x6a, 0x65, 0x51, 0x52, 0x65, 0x63]), - transparent_input: None, - hash_type: 1, - amount: 1712463999734827, - consensus_branch_id: consensus::BranchId::Overwinter, - sighash: [ - 0xbb, 0x10, 0x30, 0x0e, 0x4d, 0xaf, 0xe3, 0x0c, 0x3f, 0xf0, 0x26, 0x34, 0xd0, 0xe0, - 0x03, 0x2f, 0x17, 0x15, 0xb0, 0x0c, 0xbc, 0x77, 0x3d, 0xf6, 0xb0, 0x9e, 0x00, 0x43, - 0x38, 0x6a, 0x14, 0x18, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x13, 0xe5, 0x6c, 0x77, 0x2f, - 0x2c, 0x3b, 0x86, 0x0e, 0xa5, 0xb0, 0x3a, 0x88, 0x54, 0xbc, 0x6e, 0x65, 0x90, 0xd6, - 0x3c, 0xc0, 0xea, 0x54, 0xf1, 0x0b, 0x73, 0xba, 0x24, 0x1b, 0xf7, 0x4b, 0x63, 0x55, - 0x51, 0xa2, 0xaa, 0x06, 0x65, 0x6a, 0xac, 0x52, 0x51, 0x63, 0x36, 0x8b, 0x26, 0xd7, - 0x0a, 0x73, 0x7f, 0x26, 0x76, 0x85, 0x99, 0x8a, 0x3f, 0x7d, 0x26, 0x37, 0x91, 0x49, - 0x09, 0xc7, 0x46, 0x49, 0x5d, 0x24, 0xc4, 0x98, 0x63, 0x5e, 0xf9, 0x7a, 0xc6, 0x6a, - 0x40, 0x08, 0x94, 0xc0, 0x9f, 0x73, 0x48, 0x8e, 0x07, 0x6a, 0x53, 0x65, 0x52, 0x51, - 0x65, 0x52, 0x05, 0xf9, 0x1a, 0xd7, 0x00, 0x79, 0x65, 0xc2, 0x99, 0x36, 0x1d, 0x60, - 0x0d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7e, 0x89, 0xee, 0x09, 0x62, 0xf5, 0x8c, 0x05, 0x1d, 0x11, - 0xd0, 0x55, 0xfc, 0xe2, 0x04, 0xa5, 0x62, 0xde, 0x68, 0x08, 0x8a, 0x1b, 0x26, 0x48, - 0xb8, 0x17, 0x4c, 0xbc, 0xfc, 0x8b, 0x5b, 0x5c, 0xd0, 0x77, 0x11, 0x5a, 0xfd, 0xe1, - 0x84, 0x05, 0x05, 0x4e, 0x5d, 0xa9, 0xa0, 0x43, 0x10, 0x34, 0x2c, 0x5d, 0x3b, 0x52, - 0x6e, 0x0b, 0x02, 0xc5, 0xca, 0x17, 0x22, 0xba, 0xde, 0xee, 0x23, 0xd1, 0x45, 0xe8, - 0xeb, 0x22, 0x13, 0xfc, 0x4a, 0xf1, 0xe4, 0x50, 0xe4, 0xd5, 0x21, 0x7c, 0x66, 0x17, - 0x00, 0x8c, 0x78, 0xf4, 0xfb, 0x11, 0x12, 0xf4, 0x02, 0x8a, 0x70, 0x4f, 0xc5, 0xa9, - 0x38, 0x2c, 0x6b, 0x03, 0xe7, 0xd8, 0x08, 0x5e, 0x90, 0x6c, 0xf8, 0x4c, 0xa2, 0xc1, - 0x20, 0x7c, 0x87, 0xa2, 0xbc, 0xe2, 0x08, 0x0a, 0x98, 0x91, 0x66, 0x8d, 0x69, 0xb0, - 0x44, 0xbe, 0xce, 0xd6, 0xcd, 0xa3, 0x2c, 0x22, 0x9c, 0x91, 0x17, 0x91, 0x7a, 0xa0, - 0x7d, 0xdf, 0xfc, 0xd3, 0x77, 0x39, 0x5c, 0xba, 0x61, 0x6d, 0x63, 0xc0, 0xb6, 0x9c, - 0x01, 0xfc, 0xc4, 0x53, 0x91, 0xfd, 0x5b, 0x87, 0x63, 0xfb, 0x96, 0xd7, 0xca, 0x33, - 0x3a, 0x12, 0xde, 0x3c, 0xef, 0xa9, 0x1c, 0x6c, 0x98, 0xf9, 0x47, 0x3b, 0x8e, 0x10, - 0x4a, 0x71, 0x29, 0x3e, 0x46, 0x37, 0x47, 0x05, 0xba, 0xf6, 0x5f, 0xa4, 0x13, 0x84, - 0xba, 0x5c, 0x8e, 0x0c, 0x88, 0xa3, 0xeb, 0x07, 0xe0, 0xbe, 0x34, 0xda, 0xdd, 0xfa, - 0xbb, 0x7b, 0x65, 0x54, 0x3b, 0x5f, 0x39, 0xcb, 0x20, 0x23, 0xd4, 0x67, 0x89, 0xeb, - 0x7d, 0x98, 0x9a, 0xf7, 0x79, 0xe5, 0xb8, 0xd2, 0x83, 0x85, 0xa8, 0x5b, 0x0d, 0xa2, - 0xab, 0xe0, 0x7f, 0x0c, 0x2b, 0xb4, 0x25, 0x5f, 0xce, 0xa0, 0x31, 0x88, 0x52, 0x7a, - 0x30, 0x7d, 0x40, 0x91, 0x59, 0xe9, 0x01, 0x66, 0xfa, 0xc6, 0xa0, 0x70, 0xba, 0x05, - 0xb3, 0xe4, 0xdb, 0xfd, 0x3a, 0x2b, 0xfc, 0xc9, 0xee, 0x6e, 0xd0, 0x16, 0xc0, 0xf6, - 0x65, 0xbe, 0x81, 0x33, 0xb7, 0xdc, 0x1d, 0x86, 0x04, 0x4d, 0xb0, 0xf9, 0x03, 0x40, - 0xfb, 0x0e, 0x9f, 0x8b, 0xc2, 0xe4, 0xdb, 0x53, 0x82, 0xa8, 0xb4, 0xf8, 0x15, 0xb4, - 0xe8, 0x43, 0x4a, 0xd0, 0xdf, 0xbc, 0x51, 0xa5, 0xe9, 0xb1, 0x45, 0xe1, 0x59, 0x6c, - 0xbf, 0x46, 0x70, 0x03, 0xe0, 0x5d, 0xfd, 0xaf, 0xbb, 0x0c, 0xf3, 0xdd, 0xee, 0x28, - 0xd7, 0x6a, 0x82, 0x42, 0x8e, 0x8a, 0xba, 0x43, 0x64, 0xe8, 0x4b, 0xac, 0x37, 0x92, - 0x98, 0xdf, 0x29, 0x32, 0xe6, 0x9b, 0xb5, 0xd0, 0x0b, 0x51, 0x6e, 0xfc, 0x33, 0xae, - 0x6c, 0xc3, 0x94, 0x7c, 0xeb, 0x09, 0xed, 0x37, 0x16, 0x67, 0x21, 0x2a, 0x83, 0x1b, - 0x54, 0x85, 0xea, 0xfc, 0xe8, 0x48, 0x81, 0x88, 0xea, 0x4e, 0x27, 0xd0, 0xcd, 0xf7, - 0xdd, 0xd3, 0x48, 0xab, 0xff, 0x77, 0x7f, 0x4a, 0x13, 0xbb, 0xc7, 0x16, 0xb6, 0xa5, - 0x94, 0x4e, 0xe7, 0x27, 0x96, 0x56, 0x90, 0xe2, 0x09, 0xb4, 0x9e, 0xb9, 0x62, 0xc0, - 0x39, 0x97, 0x5f, 0x03, 0x9e, 0xd5, 0xc6, 0xe4, 0xc4, 0x00, 0xd8, 0x87, 0x75, 0x94, - 0x33, 0xd3, 0xad, 0x71, 0x6d, 0xa0, 0xcb, 0x44, 0x61, 0x13, 0xc7, 0x72, 0x7a, 0x64, - 0xb5, 0x8c, 0x3f, 0x8a, 0x0f, 0x81, 0x18, 0x9f, 0x02, 0x00, 0x52, 0x33, 0xa8, 0x13, - 0x66, 0xae, 0xe7, 0x3c, 0xec, 0x85, 0x22, 0x8e, 0xbc, 0xfd, 0x5e, 0xe3, 0xc3, 0xfb, - 0x44, 0xdb, 0x76, 0xba, 0x24, 0x3f, 0x28, 0x42, 0xb7, 0xb5, 0xfc, 0x74, 0x6a, 0x03, - 0x1b, 0x0b, 0xc4, 0xbd, 0x4f, 0xc9, 0xfd, 0x83, 0x35, 0x65, 0xea, 0x85, 0x2b, 0x92, - 0xb2, 0x24, 0xf6, 0x99, 0x03, 0x18, 0xad, 0x8c, 0x7d, 0x94, 0x37, 0xe2, 0x0e, 0x2a, - 0x1f, 0x20, 0xe8, 0x18, 0x03, 0x05, 0x7c, 0x5a, 0xba, 0xaa, 0x2e, 0x5c, 0x15, 0xb9, - 0x49, 0x45, 0xcd, 0x42, 0x4c, 0x28, 0xa5, 0xfa, 0x38, 0x5d, 0xad, 0xfe, 0x49, 0x07, - 0xb2, 0x74, 0xd8, 0x42, 0x70, 0x7d, 0xb3, 0x69, 0x7a, 0x02, 0xe6, 0xc8, 0xf5, 0x42, - 0xe5, 0xec, 0xc0, 0x7f, 0xe4, 0x73, 0x50, 0xd1, 0x01, 0x46, 0x70, 0x21, 0x2e, 0xfe, - 0x81, 0xfb, 0x7c, 0x73, 0xe8, 0x45, 0x0d, 0xf8, 0x14, 0xef, 0x62, 0x32, 0xf7, 0x49, - 0x0f, 0x63, 0xcc, 0xf0, 0x74, 0x80, 0xf8, 0x84, 0xa6, 0x6e, 0xaf, 0xfc, 0x28, 0xfe, - 0xa4, 0x48, 0xd7, 0xb4, 0x01, 0xcd, 0xae, 0x10, 0xe7, 0xc0, 0xc7, 0xf9, 0xa7, 0xb1, - 0x53, 0x31, 0x96, 0x9f, 0xc8, 0xcb, 0x36, 0x39, 0x67, 0x73, 0xde, 0x19, 0x19, 0x31, - 0xc7, 0x50, 0xf6, 0xce, 0x5c, 0xaa, 0xf2, 0x97, 0x68, 0xeb, 0xb2, 0x7d, 0xac, 0xc7, - 0x38, 0x05, 0x6a, 0x81, 0x25, 0xb4, 0x77, 0x2b, 0xf8, 0x7a, 0xe1, 0x0a, 0x8a, 0x30, - 0x9b, 0x9b, 0xd6, 0x55, 0x04, 0x3c, 0xfc, 0x31, 0x59, 0x49, 0x43, 0x68, 0xc5, 0xab, - 0x8c, 0xad, 0xb7, 0xf6, 0x71, 0xe9, 0x62, 0x6b, 0xd2, 0x63, 0xe3, 0x11, 0x81, 0xa6, - 0x04, 0xb5, 0x06, 0xa0, 0x3b, 0x43, 0x9a, 0x7f, 0xfe, 0x43, 0x55, 0x89, 0x24, 0x77, - 0xe2, 0xbd, 0xf3, 0x38, 0xc6, 0x2c, 0x39, 0x22, 0xf7, 0xd3, 0xc9, 0xa5, 0x6c, 0x71, - 0x03, 0xd9, 0x11, 0x94, 0x8a, 0x84, 0xb5, 0xae, 0x2d, 0xbb, 0x16, 0xa3, 0x76, 0x1a, - 0xdd, 0x05, 0x3a, 0x0f, 0x96, 0x7e, 0x6b, 0x5b, 0xc9, 0x42, 0x11, 0xb6, 0x54, 0x71, - 0x53, 0x26, 0x7c, 0x6e, 0xe1, 0xca, 0xd0, 0xd9, 0x74, 0xa7, 0x10, 0x88, 0x58, 0x37, - 0x35, 0xe4, 0xf6, 0x3d, 0x33, 0x15, 0x6d, 0xad, 0xd5, 0x4c, 0x2f, 0xaf, 0x89, 0x11, - 0x4a, 0x12, 0x7b, 0x97, 0xb9, 0x4c, 0xc2, 0xa2, 0x2e, 0xf3, 0x03, 0xf4, 0x59, 0xd0, - 0x4f, 0xc0, 0xb5, 0x3a, 0xce, 0x59, 0x18, 0xd4, 0x7f, 0xf3, 0x3a, 0x55, 0x8b, 0xd7, - 0x1a, 0x75, 0xf3, 0x55, 0xfb, 0xd0, 0x6b, 0xbc, 0xcf, 0x4e, 0x02, 0xc3, 0xc0, 0xa4, - 0xb6, 0x3d, 0x0c, 0xc9, 0x49, 0x80, 0x1d, 0x63, 0xa6, 0x4c, 0xb2, 0xd3, 0x23, 0x73, - 0xb2, 0xc7, 0xb2, 0x74, 0xab, 0x2d, 0xb4, 0x68, 0x21, 0x42, 0xc8, 0xb2, 0x1d, 0x84, - 0xc4, 0x81, 0xf5, 0xef, 0x21, 0xe4, 0xb5, 0xe3, 0x60, 0x34, 0x51, 0xbf, 0x94, 0x77, - 0x4d, 0x0e, 0xf4, 0x7f, 0x63, 0xfa, 0x6a, 0xbb, 0x78, 0xd2, 0x1c, 0x19, 0x3c, 0xbe, - 0x65, 0xb6, 0x95, 0xfe, 0x67, 0x42, 0x3c, 0x1e, 0x2d, 0x31, 0x2e, 0x27, 0x76, 0xfa, - 0x24, 0xec, 0xe8, 0x46, 0x83, 0xe7, 0x48, 0x76, 0xc5, 0x5e, 0xa0, 0x36, 0x9e, 0x4e, - 0xa0, 0xe8, 0x64, 0x94, 0xe0, 0x0d, 0xde, 0x23, 0x6a, 0x16, 0x89, 0x73, 0x1f, 0x0a, - 0x5d, 0x82, 0x03, 0xaf, 0xde, 0x5c, 0x42, 0x36, 0x40, 0xb8, 0x1e, 0x4f, 0x63, 0x1c, - 0x98, 0x1c, 0x11, 0xa2, 0xe1, 0xd1, 0x84, 0xc6, 0x7c, 0x52, 0x8d, 0xf9, 0x2d, 0x53, - 0xae, 0xc4, 0x4a, 0x40, 0xa4, 0xea, 0x2a, 0x13, 0x1b, 0x47, 0x33, 0xcf, 0xe4, 0x5c, - 0x6b, 0x00, 0x12, 0xc3, 0xe9, 0xe2, 0x09, 0x75, 0xba, 0xae, 0xcb, 0x02, 0x32, 0xdf, - 0x88, 0x0b, 0xd7, 0xd1, 0xde, 0x13, 0xe1, 0x34, 0x94, 0x62, 0xec, 0x8d, 0x5d, 0xf3, - 0xe7, 0x80, 0xff, 0xa7, 0x2e, 0xba, 0x8a, 0x8d, 0xf7, 0xfc, 0xf3, 0x98, 0xec, 0x23, - 0x05, 0x13, 0xca, 0x9d, 0x61, 0x23, 0xf8, 0xb9, 0xd8, 0x17, 0x85, 0x60, 0xda, 0xf9, - 0x75, 0x11, 0x19, 0x55, 0xa2, 0xbc, 0xa3, 0x42, 0x3e, 0xee, 0xfc, 0x52, 0x7b, 0xe3, - 0xa8, 0x54, 0x3e, 0xb9, 0x0a, 0x5e, 0xc0, 0x2f, 0x35, 0xa7, 0xc6, 0x4b, 0x7d, 0xd5, - 0x9a, 0x72, 0xda, 0x00, 0x74, 0x63, 0x4e, 0x01, 0xd2, 0xab, 0xf3, 0x63, 0x7a, 0xdd, - 0x77, 0xc7, 0x35, 0x0f, 0x12, 0xb0, 0x11, 0xb2, 0x94, 0x16, 0x8e, 0xc7, 0x55, 0x76, - 0xe4, 0x7d, 0x16, 0x9e, 0x39, 0x38, 0xbf, 0x6a, 0xe2, 0xaa, 0x8f, 0xf7, 0xcf, 0xba, - 0x7c, 0xac, 0xb1, 0xf9, 0x2b, 0x6e, 0x4c, 0x24, 0x97, 0xbf, 0xfa, 0x9f, 0x17, 0xca, - 0xd2, 0x42, 0xfa, 0x9c, 0x31, 0x79, 0xc1, 0xa3, 0xaa, 0x81, 0xf7, 0x36, 0x16, 0x49, - 0x57, 0x2c, 0x71, 0x5c, 0x25, 0xa1, 0xf6, 0xcd, 0x5a, 0xce, 0x82, 0xc0, 0x0a, 0xb2, - 0x34, 0x2b, 0x9c, 0x3c, 0xb4, 0xff, 0xfd, 0xda, 0x16, 0x0c, 0xa5, 0xab, 0x9e, 0x9b, - 0xaf, 0x21, 0x39, 0xef, 0x9a, 0xfb, 0xe1, 0xb1, 0xf3, 0x09, 0x46, 0x2a, 0xfc, 0xe4, - 0x62, 0xa7, 0x9b, 0xb9, 0x69, 0x8e, 0x22, 0xc9, 0x57, 0xc5, 0x90, 0xa7, 0x53, 0xa7, - 0x6b, 0x87, 0xe0, 0x09, 0x12, 0x1e, 0x06, 0xf6, 0xa1, 0xbf, 0x62, 0xa0, 0x8b, 0xf4, - 0x35, 0xd9, 0x2e, 0x2f, 0xff, 0xe8, 0x6e, 0x2a, 0x9c, 0xbb, 0xa9, 0x13, 0x3a, 0x68, - 0xe4, 0xae, 0xbf, 0x33, 0xc3, 0x84, 0x36, 0xf2, 0x54, 0x5f, 0xc2, 0xd5, 0x28, 0x32, - 0xd1, 0x65, 0xaf, 0x41, 0x5b, 0x24, 0x4a, 0xdc, 0x5f, 0x57, 0x37, 0x7d, 0xee, 0xdf, - 0x46, 0x0a, 0xa3, 0xbe, 0xb4, 0x34, 0x19, 0xc6, 0xb0, 0x82, 0xe8, 0x35, 0xce, 0x84, - 0xca, 0x13, 0xb6, 0x90, 0x8a, 0x88, 0x13, 0xc0, 0x21, 0xde, 0x9f, 0xa9, 0xa4, 0x4e, - 0x4c, 0x18, 0xdc, 0xb3, 0xd2, 0x1f, 0xaa, 0xbd, 0xb4, 0x19, 0x31, 0xb2, 0xfd, 0x49, - 0x76, 0x44, 0xdc, 0x3a, 0x15, 0x07, 0xfa, 0x5a, 0xc7, 0xc7, 0x6b, 0xee, 0xbb, 0xdb, - 0xd1, 0xd4, 0x92, 0x99, 0xa5, 0x5b, 0xd4, 0x99, 0x27, 0xe9, 0xd7, 0xf4, 0x88, 0x4e, - 0x6e, 0xd3, 0xfd, 0x5e, 0x4b, 0x7c, 0xb8, 0x35, 0xb8, 0x33, 0x08, 0x96, 0x4e, 0x3c, - 0x46, 0x87, 0x3f, 0xd6, 0x13, 0x31, 0x7b, 0x91, 0xd2, 0x92, 0x36, 0xea, 0x90, 0xe3, - 0x65, 0xd1, 0x62, 0xcc, 0x05, 0x1c, 0x84, 0x6d, 0x24, 0x21, 0x76, 0xda, 0xf6, 0xd2, - 0x86, 0x18, 0xae, 0x31, 0xfb, 0xaa, 0xe9, 0x99, 0xa9, 0x3f, 0x17, 0x5c, 0x69, 0x38, - 0xe6, 0x31, 0xa0, 0x81, 0xf2, 0xc1, 0xf3, 0xfd, 0x78, 0x25, 0x49, 0xd3, 0xf3, 0x24, - 0x57, 0x59, 0x60, 0x6d, 0x9f, 0x92, 0xd5, 0x54, 0x8a, 0xcf, 0xea, 0xdb, 0xaf, 0x9c, - 0xaa, 0x6b, 0x93, 0xdc, 0x08, 0x82, 0x8d, 0x74, 0xf6, 0xd5, 0xfd, 0xd8, 0x33, 0x31, - 0xf0, 0x96, 0x91, 0x45, 0x95, 0x52, 0x97, 0xe6, 0x9f, 0x00, 0xfd, 0x29, 0x87, 0xf2, - 0xda, 0x2b, 0x94, 0xb9, 0x95, 0xfe, 0xcb, 0xe6, 0x22, 0xa7, 0x35, 0xef, 0x7f, 0x12, - 0x07, 0xf6, 0x71, 0x62, 0x94, 0x89, 0x20, 0x2b, 0xea, 0x0b, 0x47, 0x5e, 0x51, 0x68, - 0x1a, 0xa1, 0x67, 0x78, 0xb3, 0x9b, 0xd9, 0x23, 0xc9, 0x8d, 0xc6, 0xff, 0x83, 0x73, - 0xc7, 0x9b, 0xb1, 0x70, 0x30, 0x41, 0x7b, 0xc2, 0x00, 0xc8, 0xf0, 0xb8, 0x55, 0xac, - 0xfe, 0xc1, 0x79, 0xf7, 0x67, 0x4c, 0xec, 0x27, 0x21, 0xa1, 0x0f, 0xca, 0x69, 0x3d, - 0x83, 0xcf, 0xe5, 0xb8, 0xcd, 0xcc, 0x18, 0xf8, 0x1a, 0xd6, 0x17, 0xfa, 0x26, 0xf0, - 0xdf, 0xb8, 0x36, 0x55, 0xb8, 0xa2, 0x9a, 0x7f, 0x83, 0x42, 0x32, 0x42, 0x5e, 0x8c, - 0x47, 0x45, 0x88, 0xf1, 0x8d, 0xd3, 0x26, 0xaa, 0x39, 0x6c, 0x3e, 0x47, 0x75, 0xe0, - 0x02, 0x05, 0xfc, 0x9e, 0x45, 0xf7, 0xb7, 0xd2, 0xe6, 0xd5, 0x5d, 0xcb, 0x90, 0xe2, - 0x3f, 0xf6, 0xb5, 0x08, 0x45, 0x9a, 0xa6, 0x99, 0xbf, 0xcb, 0xd5, 0x6f, 0x10, 0x99, - 0x77, 0x64, 0xd0, 0x87, 0x40, 0x89, 0x86, 0xe7, 0x3d, 0x6e, 0x28, 0x4f, 0xea, 0x9a, - 0x23, 0xc3, 0x93, 0x11, 0x78, 0x2f, 0x86, 0xca, 0xbf, 0xf9, 0x45, 0x5e, 0x4c, 0xf6, - 0x99, 0xe5, 0xf5, 0xd4, 0xbc, 0x0b, 0x39, 0x05, 0xa4, 0xe3, 0xbd, 0x01, 0xc5, 0x4d, - 0xf8, 0x64, 0x34, 0x43, 0xbe, 0x0f, 0x88, 0x90, 0x32, 0xea, 0x32, 0x5b, 0xf0, 0x71, - 0x07, 0xfd, 0x41, 0xd6, 0x73, 0xee, 0xba, 0xe6, 0xfa, 0x63, 0x7b, 0x70, 0xcc, 0x0e, - 0xd3, 0xf0, 0x09, 0x58, 0xdf, 0xb8, 0xdc, 0xf0, 0x0e, 0x85, 0xa1, 0xd0, 0xa6, 0xa8, - 0x90, 0x81, 0x40, 0xc2, 0xf4, 0x34, 0xc2, 0xe2, 0x60, 0xef, 0xb0, 0xbc, 0xa2, 0x00, - 0x35, 0x04, 0xc9, 0x99, 0x93, 0xa9, 0xe1, 0xc0, 0xff, 0x9c, 0xef, 0xe6, 0xa6, 0x65, - 0xd7, 0x91, 0x42, 0x86, 0x90, 0xe4, 0x7e, 0xf8, 0xc1, 0x31, 0xa8, 0xe9, 0xbf, 0xb4, - 0xc3, 0x08, 0x02, 0x35, 0x03, 0x2d, 0x73, 0x1b, 0x0d, 0x38, 0x41, 0x22, 0x5f, 0x1c, - 0x11, 0xe2, 0xc2, 0x8e, 0xe8, 0x4d, 0x35, 0xf9, 0x22, 0x61, 0x00, 0x56, 0x59, 0x72, - 0xeb, 0x26, 0x9d, 0x27, 0x8e, 0xf6, 0x49, 0x79, 0xbf, 0x65, 0x15, 0xed, 0x4a, 0x68, - 0x40, 0xb0, 0x88, 0x3a, 0x9e, 0x6e, 0xf6, 0x4a, 0x0e, 0xfc, 0xae, 0x1c, 0xf2, 0x1d, - 0xfe, 0x74, 0x85, 0x4e, 0x84, 0xc2, 0x74, 0x9f, 0xac, 0x03, 0x82, 0x52, 0x75, 0xc9, - 0xb6, 0x30, 0x21, 0x84, 0xc7, 0x2d, 0xf4, 0xc4, 0xbb, 0x28, 0x62, 0xe4, 0xe8, 0xa7, - 0xd9, 0xa4, 0xa2, 0x82, 0x86, 0x6f, 0x9a, 0x7b, 0x2c, 0xfc, 0x9a, 0x56, 0x31, 0x3d, - 0xa0, 0xc4, 0x7a, 0x34, 0xb7, 0xb9, 0xcd, 0xa3, 0xac, 0xe8, 0x18, 0x5f, 0x07, 0xdf, - 0x36, 0xe4, 0x48, 0xa7, 0x6a, 0xa4, 0x77, 0xf2, 0x24, 0xd8, 0x7a, 0x07, 0x4f, 0x43, - 0xaf, 0x5d, 0x5f, 0x79, 0xb3, 0xab, 0x11, 0x28, 0xf0, 0x81, 0x91, 0x44, 0x7f, 0xa6, - 0x46, 0xbf, 0xdd, 0xe5, 0xb5, 0x1e, 0x23, 0x3c, 0xa6, 0x15, 0x5d, 0x10, 0x15, 0x85, - 0xbc, 0x2c, 0x40, 0x15, 0x8a, 0xc2, 0x10, 0x6e, 0x66, 0xa2, 0x6e, 0x46, 0x42, 0x33, - 0x70, 0x63, 0x68, 0x76, 0xb4, 0x34, 0xa7, 0x4f, 0x8c, 0xe8, 0x06, 0x00, 0x50, 0xb0, - 0x82, 0xa7, 0x9b, 0x61, 0xbb, 0x5d, 0x34, 0x4e, 0xb5, 0xa1, 0x15, 0x83, 0x26, 0xce, - 0xd9, 0xa9, 0xd9, 0xf5, 0x4f, 0xb2, 0xfe, 0x8f, 0x9f, 0x05, 0xcd, 0x11, 0x1e, 0xe4, - 0x6c, 0x47, 0x10, 0xf6, 0xf6, 0x3a, 0x62, 0x69, 0x45, 0x57, - ], - script_code: Script(vec![0x53, 0x52, 0x00]), - transparent_input: Some(1), - hash_type: 1, - amount: 1564816348934332, - consensus_branch_id: consensus::BranchId::Overwinter, - sighash: [ - 0x21, 0x46, 0x62, 0xc6, 0x74, 0x50, 0x60, 0x3d, 0x8a, 0xa7, 0x3b, 0xea, 0xbb, 0xf7, - 0x51, 0x8d, 0x03, 0x6c, 0xe9, 0x1d, 0xc8, 0x7b, 0x01, 0x81, 0xe8, 0xa0, 0xf3, 0xfa, - 0x82, 0x2c, 0x7d, 0x8a, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x01, 0x59, 0x07, 0x92, 0x9a, 0x2f, - 0x3f, 0xdb, 0x0d, 0x8f, 0x79, 0x14, 0xc4, 0x2d, 0xde, 0x2d, 0x20, 0x00, 0xf5, 0xae, - 0x02, 0xd4, 0x18, 0x21, 0xc8, 0xe1, 0xee, 0x01, 0x38, 0xeb, 0xcb, 0x72, 0x8d, 0x7c, - 0x6c, 0x3c, 0x80, 0x02, 0x65, 0x53, 0x75, 0x94, 0xc6, 0x70, 0x00, 0x6f, 0x39, 0x08, - 0x22, 0x2e, 0x89, 0xd1, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x27, 0x1a, 0xbe, 0x66, 0x0e, - 0x39, 0xe0, 0x51, 0xaa, 0xa6, 0xfc, 0xa1, 0x86, 0x22, 0x76, 0xe2, 0xba, 0xa0, 0xfe, - 0x0b, 0x16, 0x2a, 0xeb, 0xcf, 0xe3, 0xd9, 0x34, 0x9c, 0x8d, 0x15, 0x4b, 0xb7, 0xee, - 0x28, 0x21, 0x2c, 0x1b, 0xaa, 0x70, 0x5d, 0x82, 0x07, 0x0d, 0x70, 0x32, 0xf2, 0x69, - 0x5d, 0x17, 0x96, 0x80, 0x9f, 0xab, 0x41, 0x24, 0x69, 0x26, 0xaf, 0x99, 0x2b, 0x6e, - 0xee, 0x95, 0xa9, 0xa0, 0x6b, 0xc4, 0x56, 0x2c, 0x5f, 0x2f, 0x1b, 0x19, 0x54, 0x95, - 0x00, 0x37, 0x2e, 0x7a, 0xd5, 0x79, 0xa6, 0xd6, 0xd7, 0x8b, 0x33, 0x15, 0x31, 0x30, - 0xfb, 0x44, 0x8f, 0xb7, 0x9e, 0x8a, 0x66, 0x9d, 0xb8, 0xa0, 0xf3, 0x5c, 0xdf, 0x9a, - 0xe5, 0xd3, 0x2d, 0x73, 0x2f, 0xc7, 0x94, 0x18, 0xe2, 0x3b, 0x45, 0x1d, 0xdc, 0x95, - 0xa2, 0x2a, 0xba, 0xbb, 0x05, 0x6e, 0xc6, 0xb5, 0xe8, 0xba, 0x4f, 0x52, 0x4d, 0xfa, - 0xfe, 0x87, 0x52, 0x62, 0xdd, 0x7b, 0xe4, 0x1c, 0xbb, 0xc6, 0x24, 0x20, 0xd4, 0xad, - 0x6d, 0xf5, 0xc9, 0xb7, 0x13, 0x60, 0x4f, 0x65, 0x60, 0x88, 0xa4, 0x48, 0x5e, 0x93, - 0xbe, 0x19, 0x07, 0xd2, 0x7a, 0xc6, 0xec, 0x3c, 0x57, 0x25, 0x9b, 0xd6, 0x98, 0x1d, - 0x42, 0xc1, 0xb7, 0x8a, 0x29, 0xad, 0x96, 0x85, 0xe6, 0x3c, 0x49, 0x4d, 0x41, 0x29, - 0x62, 0x3e, 0xa1, 0xa7, 0xff, 0xec, 0x85, 0xfa, 0x29, 0x41, 0x10, 0x73, 0xed, 0xb2, - 0x97, 0x8e, 0xf4, 0xe4, 0x69, 0xdd, 0xd5, 0xcd, 0xa9, 0x86, 0x18, 0x99, 0x95, 0xf8, - 0x8d, 0x6a, 0xb3, 0x66, 0xdb, 0x01, 0x90, 0x01, 0xf5, 0xb2, 0x52, 0x88, 0xcf, 0x86, - 0x0f, 0xd9, 0x98, 0xee, 0x57, 0x3c, 0x8c, 0xc4, 0x8a, 0xa9, 0xef, 0xcf, 0x9b, 0x61, - 0x7e, 0x04, 0x3c, 0x32, 0x9c, 0xd1, 0xaa, 0x1a, 0x0e, 0xd3, 0xa4, 0x02, 0xfb, 0x96, - 0xe3, 0x36, 0xc7, 0x19, 0xe6, 0x25, 0x3c, 0xb6, 0x91, 0xaa, 0x0d, 0xb5, 0x27, 0x36, - 0x62, 0x6e, 0xd1, 0x97, 0x88, 0x75, 0x88, 0x8e, 0xc7, 0x6c, 0x84, 0x6b, 0xc2, 0x27, - 0x27, 0x2a, 0x02, 0x53, 0x17, 0xdf, 0xf0, 0xb1, 0x14, 0x8d, 0x92, 0xd6, 0xf5, 0xfb, - 0x7d, 0x95, 0x33, 0x67, 0x70, 0xa7, 0xd1, 0x6f, 0xac, 0x1a, 0xdd, 0x86, 0x07, 0x76, - 0xcb, 0x48, 0x02, 0x21, 0xf8, 0xfb, 0x33, 0x03, 0xe4, 0xe9, 0xb0, 0x79, 0x02, 0xd2, - 0xff, 0x86, 0xfd, 0xac, 0x72, 0x09, 0x62, 0x34, 0xae, 0xd4, 0x8d, 0xe8, 0x92, 0xff, - 0x73, 0x55, 0x07, 0x3b, 0xbf, 0x06, 0x15, 0xf6, 0x7b, 0x11, 0x00, 0xcc, 0x0a, 0xa3, - 0xba, 0x3d, 0x6c, 0x1a, 0x1a, 0x90, 0x87, 0xb1, 0x19, 0xba, 0xee, 0xbf, 0xa6, 0x2b, - 0xc9, 0xf0, 0xec, 0x47, 0x9d, 0x99, 0xc1, 0xa3, 0xb1, 0x58, 0xb5, 0x14, 0xd1, 0x62, - 0x9d, 0xb3, 0x99, 0x3f, 0x11, 0x67, 0x2a, 0x26, 0x70, 0x8e, 0x5a, 0xd8, 0x16, 0xb5, - 0x47, 0xab, 0x7e, 0x82, 0x7d, 0x07, 0x1b, 0xa7, 0x84, 0x2b, 0x3e, 0x90, 0x30, 0x53, - 0x83, 0x89, 0x6e, 0xc4, 0x90, 0x5f, 0x70, 0x03, 0x8b, 0x69, 0x4e, 0x6a, 0x5a, 0x3e, - 0x43, 0x12, 0xcd, 0x82, 0x08, 0x13, 0x2b, 0x84, 0x0f, 0x05, 0xc7, 0x14, 0x52, 0x3c, - 0xa8, 0x19, 0x72, 0x0a, 0xe2, 0x27, 0xfd, 0x1a, 0xcb, 0xa7, 0x14, 0xfa, 0x03, 0xc4, - 0x5f, 0xc5, 0x39, 0x88, 0x57, 0xb4, 0x0d, 0xc1, 0x48, 0x79, 0x85, 0x6f, 0x35, 0x4b, - 0xa4, 0xd2, 0x58, 0x1d, 0x0c, 0xda, 0x54, 0xb6, 0x38, 0xba, 0x9d, 0x76, 0xf9, 0xb5, - 0x2d, 0x17, 0xc8, 0x02, 0x8e, 0xe6, 0x3f, 0x58, 0x45, 0xb5, 0xdc, 0xef, 0xa4, 0xc3, - 0x47, 0x9b, 0xce, 0x9a, 0xca, 0xd1, 0x8b, 0x4a, 0xea, 0xe0, 0x3c, 0x0e, 0xae, 0x22, - 0x5d, 0x42, 0x84, 0x8b, 0xde, 0xaa, 0x53, 0x6d, 0x03, 0x8d, 0xd3, 0xbc, 0x97, 0x9f, - 0x06, 0x58, 0x66, 0x73, 0xbc, 0x6f, 0xf1, 0xc5, 0xd3, 0xb3, 0x20, 0xf3, 0x49, 0xa5, - 0xb3, 0xa8, 0xb3, 0x55, 0x59, 0x22, 0x96, 0xaa, 0xf6, 0x1c, 0x5b, 0x72, 0x52, 0x03, - 0x3e, 0xc0, 0xa9, 0x46, 0x6a, 0x1b, 0x85, 0x76, 0x4f, 0xb0, 0x83, 0x1b, 0x4a, 0x1a, - 0x36, 0x89, 0x0e, 0x22, 0x4c, 0x01, 0xac, 0xfc, 0xe4, 0x8e, 0xe3, 0xed, 0x93, 0x87, - 0x73, 0x98, 0xe0, 0x72, 0x6d, 0x02, 0x93, 0x6d, 0x0d, 0x03, 0x2e, 0x18, 0xe3, 0x28, - 0x8b, 0x26, 0x70, 0xe1, 0x36, 0x2c, 0x32, 0xd6, 0xe4, 0x73, 0x3b, 0x9d, 0xd2, 0xd5, - 0xf2, 0x6e, 0x1f, 0xe3, 0x06, 0xf7, 0x3c, 0x00, 0x7f, 0xdd, 0xca, 0xe9, 0xd9, 0xc0, - 0xaa, 0xf1, 0x87, 0xd7, 0x42, 0x8b, 0x1e, 0x9d, 0x47, 0x9c, 0x18, 0x23, 0x7b, 0x98, - 0x28, 0xbc, 0xa8, 0xb9, 0x8c, 0x9d, 0x9b, 0xec, 0x7d, 0x82, 0x70, 0xb5, 0xd8, 0xee, - 0xc3, 0xcc, 0x4f, 0x43, 0xfa, 0x01, 0x88, 0x52, 0x1b, 0xc6, 0x1b, 0x21, 0xdd, 0x04, - 0xe3, 0x7a, 0x83, 0xec, 0xe6, 0x8c, 0xa7, 0xa2, 0xfa, 0x6c, 0x8f, 0x9e, 0x34, 0xa6, - 0x29, 0x03, 0x35, 0xaa, 0x1f, 0xbd, 0x83, 0xd5, 0x4a, 0xaf, 0x44, 0x1e, 0x31, 0x9e, - 0xa4, 0x7a, 0x86, 0x2a, 0xd0, 0x29, 0x3c, 0xed, 0xf5, 0xdd, 0x9e, 0xda, 0xde, 0xee, - 0x33, 0xcb, 0x52, 0x2c, 0xd0, 0x11, 0x8b, 0xbd, 0x81, 0x1a, 0xce, 0x9a, 0x23, 0xbd, - 0xa3, 0x9a, 0xba, 0x72, 0xf1, 0x56, 0x6f, 0xc1, 0x68, 0x84, 0x97, 0xd2, 0xa7, 0x92, - 0x8c, 0x36, 0x70, 0x15, 0x25, 0x67, 0x8b, 0xc9, 0x72, 0x14, 0xb3, 0x1b, 0x37, 0xba, - 0xb4, 0x6b, 0x88, 0xf2, 0x7f, 0x04, 0x48, 0xde, 0xcb, 0x31, 0x62, 0x2d, 0x0f, 0x0f, - 0x87, 0xa8, 0x55, 0xba, 0x54, 0x00, 0x03, 0x32, 0x03, 0x1f, 0x73, 0xab, 0xff, 0xd4, - 0x65, 0x91, 0xda, 0x0b, 0x88, 0x72, 0x35, 0x04, 0xed, 0xb2, 0x33, 0x72, 0x30, 0xda, - 0xd2, 0xac, 0xc0, 0xd8, 0xbb, 0x68, 0xbc, 0x83, 0x7a, 0x2f, 0xf9, 0x30, 0xbf, 0xf0, - 0x6f, 0xde, 0x74, 0xeb, 0x90, 0xaa, 0xe4, 0xf6, 0x0d, 0xbb, 0x6e, 0xb8, 0x27, 0xea, - 0x99, 0x88, 0x4a, 0xcd, 0x62, 0x85, 0xa9, 0x88, 0x92, 0x80, 0x2c, 0xf5, 0x9d, 0x5d, - 0x60, 0xd0, 0x16, 0x63, 0x38, 0x7b, 0x3e, 0xd2, 0x72, 0x3b, 0xd6, 0x48, 0x9e, 0x9c, - 0x2c, 0x10, 0x6d, 0x4a, 0xa2, 0xde, 0x23, 0xce, 0xd1, 0x6c, 0x72, 0x04, 0x29, 0xc7, - 0x75, 0x3a, 0x77, 0x38, 0xec, 0x7d, 0x9d, 0xb8, 0x62, 0x42, 0x29, 0xed, 0xd2, 0x17, - 0xb8, 0x0d, 0x74, 0x87, 0x5a, 0x14, 0xca, 0xe4, 0x86, 0x3f, 0x13, 0x9e, 0x9c, 0x0b, - 0x13, 0x1b, 0x2a, 0x4c, 0x28, 0x07, 0x1a, 0x38, 0xec, 0x61, 0xf6, 0x68, 0x01, 0xaa, - 0x59, 0x56, 0xfc, 0xb2, 0xa4, 0x6b, 0x95, 0x87, 0x66, 0x5b, 0x75, 0x71, 0xaa, 0x03, - 0x48, 0x1f, 0xd8, 0xd9, 0xd5, 0x69, 0x8f, 0x83, 0x6f, 0xc8, 0x63, 0x5e, 0x69, 0xe3, - 0xbd, 0xe4, 0x2f, 0x4a, 0xc0, 0x71, 0x32, 0x8b, 0x54, 0x09, 0xf6, 0xe4, 0x2d, 0x79, - 0x0a, 0xed, 0xd7, 0x3b, 0xc1, 0xa2, 0x35, 0x47, 0x23, 0xb3, 0xb8, 0x19, 0xd0, 0x63, - 0x7a, 0x6f, 0xa4, 0x66, 0x39, 0x46, 0xa3, 0x0a, 0xc5, 0xaf, 0xdd, 0x30, 0xce, 0x83, - 0x0f, 0x67, 0x91, 0xb4, 0x57, 0x52, 0x70, 0xa1, 0x72, 0x0f, 0x91, 0x86, 0x6e, 0x2b, - 0x86, 0xf4, 0x78, 0x88, 0x94, 0xc8, 0xda, 0x62, 0xd8, 0xb9, 0x1f, 0xaf, 0x52, 0x0e, - 0x3b, 0xed, 0xbc, 0x12, 0x06, 0xa5, 0xa5, 0xe6, 0xef, 0xd3, 0xdf, 0xde, 0x08, 0x43, - 0xc3, 0xb0, 0x67, 0x57, 0x64, 0x3f, 0xc0, 0x06, 0x00, 0x88, 0x38, 0xca, 0x47, 0x30, - 0x87, 0xf8, 0x97, 0x79, 0x18, 0xcc, 0x1b, 0x81, 0xc9, 0xe6, 0x8e, 0x3b, 0x88, 0x8f, - 0xe6, 0xf7, 0xc6, 0x30, 0xf1, 0xbc, 0x7a, 0xe1, 0x88, 0xf5, 0x12, 0x84, 0x20, 0x41, - 0xca, 0xda, 0x1e, 0x05, 0xf8, 0x66, 0xd2, 0x56, 0x2d, 0xbe, 0x09, 0xc4, 0xb4, 0x30, - 0x68, 0xf7, 0x54, 0xda, 0xd3, 0x4d, 0xf0, 0xfc, 0xfc, 0x18, 0x1f, 0x31, 0x80, 0x1a, - 0x79, 0x92, 0xd2, 0xf1, 0x6b, 0xe0, 0x21, 0x1b, 0x4a, 0x22, 0xf6, 0x2a, 0xab, 0x64, - 0x70, 0x1b, 0xf4, 0xa4, 0xe6, 0xd6, 0x66, 0xfc, 0x30, 0x4a, 0x5c, 0x79, 0xc6, 0x09, - 0xac, 0xc4, 0x3b, 0x00, 0xb4, 0x86, 0x48, 0x93, 0xd3, 0x7d, 0x50, 0x07, 0xf0, 0xc3, - 0x29, 0xa4, 0x75, 0x50, 0x52, 0x57, 0x75, 0x70, 0xdd, 0x38, 0xfa, 0xc0, 0x43, 0xcd, - 0x91, 0xc1, 0x2e, 0xe3, 0x4e, 0x9c, 0xfa, 0xe3, 0x92, 0xa7, 0x8b, 0xda, 0xbd, 0x4e, - 0xe3, 0x1d, 0xc0, 0xde, 0xb0, 0x2f, 0xe7, 0xb1, 0xd8, 0xb0, 0x17, 0x8a, 0xc9, 0x51, - 0x31, 0x05, 0xfc, 0xc7, 0xe3, 0x0b, 0xa8, 0xe0, 0x16, 0xaa, 0x36, 0xa6, 0xb5, 0xdf, - 0x5e, 0x5a, 0x19, 0x09, 0xf6, 0x3a, 0xba, 0x09, 0x5d, 0x98, 0x77, 0xa8, 0xf2, 0xdc, - 0x53, 0xf4, 0x6f, 0x6c, 0x9b, 0x07, 0xad, 0xdf, 0x14, 0x6f, 0x4f, 0xfa, 0x50, 0x1f, - 0x9d, 0xd3, 0xcf, 0xf9, 0x24, 0xe3, 0x01, 0x0f, 0xaf, 0x50, 0x4e, 0x2b, 0x8a, 0xca, - 0x73, 0x57, 0xac, 0xbf, 0xfe, 0xc7, 0x3a, 0xc3, 0x4c, 0x1a, 0x73, 0x16, 0x0f, 0x2c, - 0xea, 0x1e, 0x05, 0x10, 0xf8, 0x4d, 0x2f, 0xe2, 0xf7, 0x3b, 0x6e, 0x92, 0x19, 0x07, - 0xa1, 0xb7, 0xb3, 0x75, 0x12, 0x13, 0x24, 0x1b, 0x2c, 0xfa, 0xa5, 0x5a, 0x5e, 0xa4, - 0xdd, 0x51, 0x7e, 0x7b, 0x49, 0xd2, 0xde, 0x8c, 0x09, 0x08, 0x43, 0x73, 0x0d, 0x24, - 0x08, 0xa2, 0xa3, 0x04, 0xaa, 0x1e, 0x2e, 0x13, 0x70, 0xa6, 0xbf, 0x6c, 0x2b, 0xc7, - 0x3f, 0xf0, 0x0d, 0x89, 0x3b, 0xc1, 0x28, 0x5e, 0xfc, 0xa8, 0x25, 0x99, 0xd1, 0x81, - 0xf1, 0x23, 0x51, 0xf9, 0x39, 0xa9, 0x4e, 0xa8, 0xb9, 0x75, 0xc0, 0x65, 0xa9, 0x1f, - 0xf2, 0x57, 0xca, 0xc7, 0xa9, 0x23, 0x85, 0xfc, 0x8f, 0xa9, 0x21, 0xb1, 0x06, 0xba, - 0x86, 0x60, 0xc6, 0x0a, 0xc8, 0xba, 0x5e, 0xce, 0x45, 0x60, 0x6f, 0x04, 0xf3, 0x6a, - 0x3a, 0x90, 0xbb, 0x38, 0x38, 0xc4, 0x2a, 0xbf, 0x62, 0xdd, 0x2d, 0x84, 0xba, 0xbe, - 0xf3, 0xe1, 0x88, 0xe9, 0x17, 0x1a, 0xff, 0x9b, 0xc1, 0x16, 0x66, 0x90, 0x09, 0xd8, - 0x87, 0x13, 0x0a, 0xc9, 0xf7, 0x39, 0x6a, 0x62, 0x7a, 0x84, 0x74, 0xc1, 0x81, 0x1b, - 0x69, 0x6f, 0x99, 0x55, 0x2b, 0x14, 0xc4, 0x84, 0xdf, 0xe4, 0x2c, 0x24, 0xd5, 0x7c, - 0x3a, 0x9c, 0x3f, 0xea, 0x13, 0x76, 0xcd, 0xcb, 0x63, 0x42, 0x1c, 0x31, 0x4a, 0x62, - 0x2a, 0x9a, 0xef, 0x0b, 0xc0, 0x57, 0xcb, 0x11, 0xbc, 0x5e, 0x30, 0x66, 0xe3, 0x3a, - 0x3b, 0x9b, 0x31, 0xdf, 0x25, 0x75, 0xcd, 0x51, 0x85, 0xa4, 0xf3, 0xfc, 0x4e, 0x4c, - 0x3d, 0x40, 0x2e, 0xd4, 0x20, 0x46, 0xf8, 0x1f, 0x97, 0x48, 0x16, 0xd2, 0x79, 0xb1, - 0x51, 0x3a, 0xb8, 0x1d, 0x3f, 0x0a, 0x3c, 0x7f, 0x7f, 0xcf, 0x2f, 0xbb, 0x4e, 0x26, - 0x32, 0x19, 0x93, 0xa5, 0x13, 0xad, 0x3d, 0x7f, 0x4a, 0xfe, 0x6c, 0x1b, 0xbd, 0xc6, - 0x57, 0x58, 0x50, 0x80, 0xbb, 0x5a, 0x0f, 0x25, 0x97, 0x3d, 0x63, 0xeb, 0x20, 0xad, - 0xa0, 0x16, 0x6b, 0xbd, 0x8a, 0x39, 0xff, 0x93, 0x24, 0x6f, 0x27, 0x89, 0x73, 0x2a, - 0xd0, 0x55, 0x87, 0xf8, 0xdb, 0x7b, 0xc8, 0x7c, 0x24, 0x2c, 0xfd, 0x36, 0xce, 0x68, - 0x5a, 0x4b, 0x65, 0x69, 0x86, 0xc3, 0x9f, 0xd7, 0xfc, 0xb2, 0x3c, 0x91, 0x91, 0x3e, - 0x46, 0x11, 0x19, 0x1e, 0xdc, 0xc8, 0x8b, 0x78, 0xf1, 0x45, 0xea, 0x29, 0xd2, 0x71, - 0xb9, 0x40, 0xc6, 0x99, 0x41, 0xe4, 0xc3, 0xfd, 0x2d, 0x71, 0xf3, 0xb1, 0x90, 0x69, - 0x0e, 0xe1, 0x6f, 0x5d, 0x14, 0xac, 0x22, 0x24, 0xe6, 0xfc, 0x89, 0x59, 0x76, 0x54, - 0x52, 0x7d, 0xab, 0xe7, 0x2e, 0x75, 0xd2, 0xd2, 0xa1, 0x3a, 0x9f, 0xba, 0xa6, 0x37, - 0x8e, 0x8a, 0x26, 0x43, 0x21, 0x08, 0x7a, 0x19, 0x00, 0xef, 0xe3, 0xca, 0xd1, 0x4a, - 0x57, 0x96, 0x86, 0xaa, 0x36, 0x36, 0xbd, 0x37, 0x5b, 0xd3, 0x13, 0x6b, 0xee, 0x0b, - 0xda, 0xab, 0xcf, 0xac, 0x88, 0x1b, 0xc7, 0x01, 0x81, 0x27, 0x21, 0xe6, 0xfb, 0x75, - 0xaa, 0x07, 0x2d, 0x2d, 0x18, 0x7e, 0x62, 0x25, 0x8d, 0x65, 0xa1, 0x92, 0x15, 0x7c, - 0xdf, 0x2e, 0xc3, 0x21, 0x40, 0x7f, 0x68, 0x2f, 0x5e, 0xec, 0x6a, 0x32, 0x97, 0xab, - 0x20, 0xb7, 0x06, 0x1c, 0x62, 0x24, 0x57, 0x16, 0xa4, 0x4f, 0x71, 0xfb, 0xfc, 0x34, - 0xc7, 0x9b, 0x44, 0xe0, 0x9e, 0x42, 0x12, 0xac, 0x26, 0x53, 0xf6, 0xc4, 0x03, 0x64, - 0x3e, 0x1c, 0x5b, 0x9a, 0xd1, 0x34, 0xd8, 0x9c, 0x68, 0x0b, 0x70, 0x72, 0x83, 0xaf, - 0x54, 0x32, 0x6f, 0xc4, 0xf8, 0x4d, 0x6a, 0x58, 0x29, 0xa0, 0xad, 0x48, 0x30, 0x80, - 0x6c, 0x05, 0x75, 0x84, 0x92, 0xcd, 0x6a, 0xc4, 0x6b, 0xa0, 0x1a, 0x2b, 0x37, 0x22, - 0xb5, 0xe4, 0xcd, 0xaf, 0xbb, 0x3f, 0x36, 0x78, 0x5f, 0x42, 0x4a, 0xf0, 0x44, 0xda, - 0xc5, 0xdb, 0x5f, 0x7d, 0xf8, 0x39, 0xeb, 0x63, 0xc0, 0xc1, 0x7d, 0x8b, 0x0c, 0x79, - 0xdb, 0x86, 0x30, 0x94, 0x20, 0x15, 0xbe, 0x13, 0xf7, 0x9a, 0xf6, 0xf4, 0x3e, 0x5a, - 0xb0, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x81, 0x14, 0x79, 0x8f, 0x44, 0x22, 0x58, 0xee, 0xdc, 0x43, - 0x6f, 0xcc, 0x38, 0x6b, 0x36, 0xb5, 0x7e, 0x19, 0x17, 0xd7, 0x20, 0x17, 0x73, 0x66, - 0xf4, 0x24, 0xb0, 0xa5, 0x4b, 0x0b, 0x60, 0xf4, 0xfb, 0x13, 0x58, 0xc2, 0x0a, 0xa4, - 0x1d, 0xc5, 0x02, 0xe1, 0xdd, 0x8a, 0x16, 0x33, 0xf3, 0xd8, 0xe3, 0x27, 0x6b, 0x59, - 0xe7, 0xd2, 0xc4, 0xe6, 0x24, 0xa6, 0xf5, 0x36, 0x95, 0xbc, 0xaf, 0x24, 0x7e, 0x36, - 0x48, 0x3f, 0x13, 0xb2, 0x04, 0x42, 0x22, 0x37, 0xfc, 0x6a, 0xb3, 0xeb, 0xa0, 0x2f, - 0xc4, 0x14, 0x2b, 0x42, 0x97, 0xeb, 0xb5, 0x68, 0x3d, 0xb8, 0xd2, 0x43, 0x19, 0x70, - 0x6a, 0xd2, 0x6a, 0xaf, 0xd8, 0x1c, 0x53, 0xb7, 0x40, 0xf3, 0x45, 0x43, 0xa6, 0xb3, - 0xe9, 0xf5, 0xbb, 0x7d, 0x5c, 0x49, 0xe8, 0xc3, 0x7f, 0x61, 0x49, 0x21, 0x25, 0x4f, - 0x32, 0x12, 0x39, 0x4c, 0x79, 0x7d, 0x1c, 0xee, 0x78, 0x99, 0xb7, 0xb4, 0xb6, 0x5b, - 0x59, 0xb7, 0x34, 0x2f, 0x92, 0x53, 0x1c, 0x1d, 0x59, 0xe1, 0x79, 0x70, 0xb7, 0x31, - 0x74, 0x14, 0x43, 0x8c, 0xd8, 0x0b, 0xd0, 0xf9, 0xa6, 0x7c, 0x9b, 0x9e, 0x55, 0x2f, - 0x01, 0x3c, 0x11, 0x5a, 0x95, 0x4f, 0x35, 0xe0, 0x61, 0x6c, 0x68, 0xd4, 0x31, 0x63, - 0xd3, 0x34, 0xda, 0xc3, 0x82, 0x70, 0x33, 0xe5, 0xad, 0x84, 0x88, 0xbf, 0xd9, 0xc4, - 0xbb, 0xbe, 0x8f, 0x59, 0x35, 0xc6, 0xc5, 0xea, 0x04, 0xc3, 0xad, 0x49, 0xc7, 0x47, - 0xa9, 0xe7, 0x23, 0x1b, 0xcd, 0x7d, 0x16, 0x21, 0x5e, 0x6e, 0x80, 0x73, 0x7d, 0x6b, - 0x54, 0xfe, 0xc8, 0xb8, 0x84, 0x02, 0xf0, 0x47, 0x52, 0x45, 0xe1, 0x74, 0xa7, 0x45, - 0xb8, 0x31, 0xf8, 0xfe, 0x03, 0xa7, 0x6f, 0xb9, 0xce, 0xca, 0x4d, 0x22, 0xb7, 0x83, - 0xc3, 0x28, 0xc6, 0x91, 0x5c, 0x43, 0x40, 0x50, 0x64, 0xae, 0x56, 0xbc, 0x89, 0xe6, - 0x4d, 0x15, 0x78, 0xe4, 0xd3, 0xa3, 0x4b, 0xb9, 0x55, 0x91, 0xea, 0xf1, 0xd3, 0xda, - 0x02, 0xa4, 0x54, 0x9f, 0xa8, 0x0d, 0xb0, 0xff, 0x7c, 0xb0, 0x39, 0x93, 0x02, 0x8a, - 0xe1, 0x5a, 0x30, 0xe8, 0x79, 0x49, 0xaa, 0x08, 0x0e, 0x94, 0xab, 0xde, 0x68, 0x89, - 0x8c, 0x33, 0x92, 0xa2, 0x17, 0xd6, 0x49, 0x61, 0x6b, 0xbe, 0x73, 0x9b, 0x13, 0xd1, - 0x4d, 0xf0, 0x3f, 0x02, 0x76, 0x71, 0x48, 0x9b, 0xe0, 0xb4, 0xbe, 0xba, 0xaf, 0xa7, - 0xd1, 0xe6, 0x39, 0xd5, 0xb3, 0xe9, 0x94, 0xff, 0xb6, 0xb7, 0xa2, 0x09, 0xf6, 0xad, - 0xfe, 0x8d, 0x1e, 0x5c, 0xcf, 0x01, 0x0c, 0x19, 0x0a, 0x8a, 0xeb, 0x18, 0xaa, 0x9d, - 0x68, 0x7e, 0x24, 0xad, 0xc0, 0xb1, 0x13, 0x5c, 0x70, 0xc9, 0x70, 0xe0, 0x90, 0x3a, - 0xf6, 0xe1, 0x70, 0x81, 0xd5, 0x81, 0x8e, 0x88, 0xb1, 0x4e, 0x4f, 0x60, 0x1b, 0x8c, - 0x06, 0x3e, 0x3f, 0x43, 0x87, 0xff, 0xa2, 0x32, 0x2a, 0x51, 0x81, 0x90, 0x9f, 0x09, - 0x80, 0xd6, 0x89, 0xde, 0x7f, 0x8e, 0x6a, 0x5c, 0x62, 0xa7, 0x77, 0xd1, 0x75, 0x00, - 0x2a, 0x13, 0x7d, 0x02, 0x5b, 0x88, 0x88, 0x92, 0x91, 0x98, 0x11, 0x7a, 0xa5, 0xd6, - 0x19, 0x93, 0xe1, 0xdc, 0xf7, 0x58, 0x76, 0xdc, 0xa6, 0x09, 0xf9, 0xd2, 0x84, 0x71, - 0xf9, 0x97, 0xfa, 0x11, 0xf9, 0x9d, 0x42, 0x3f, 0x02, 0xf1, 0x73, 0x4b, 0xe8, 0xa5, - 0xff, 0x99, 0x7d, 0x45, 0x1e, 0xb3, 0xcf, 0x4b, 0x3d, 0xfd, 0xd9, 0xd4, 0x54, 0x5c, - 0x35, 0xb2, 0xb5, 0xa7, 0xdc, 0x17, 0xa8, 0x36, 0xb1, 0x2b, 0x43, 0xbe, 0xfc, 0x03, - 0xe0, 0xa1, 0xbd, 0x36, 0x97, 0x72, 0x33, 0x80, 0x78, 0xb4, 0xff, 0x7d, 0x8e, 0x2d, - 0x97, 0x9a, 0x34, 0x41, 0xe1, 0xc8, 0xf5, 0xaf, 0xe4, 0x7b, 0x1e, 0x7d, 0xa5, 0x6c, - 0xf0, 0x06, 0x02, 0xd0, 0x03, 0x11, 0x0c, 0x05, 0xcf, 0x48, 0xfd, 0xa3, 0xe6, 0xcc, - 0xe3, 0x2a, 0x04, 0x40, 0x00, 0xf4, 0x5c, 0x6d, 0x1e, 0x69, 0x6d, 0x24, 0x5c, 0xbd, - 0x31, 0x2b, 0xdc, 0x3a, 0x3a, 0x21, 0xc9, 0x92, 0xd0, 0x03, 0xc8, 0xcc, 0x8f, 0xa6, - 0x30, 0x6d, 0x7e, 0x13, 0x0a, 0x2b, 0xa4, 0x20, 0x18, 0xfe, 0x59, 0x69, 0x49, 0xfd, - 0x82, 0x26, 0x7b, 0xcc, 0x59, 0xdd, 0x46, 0x26, 0xef, 0xc3, 0xea, 0x74, 0x38, 0xd0, - 0x5c, 0x91, 0xb0, 0xf8, 0xe0, 0x92, 0x55, 0x0d, 0x2d, 0x39, 0xa0, 0x1e, 0xb4, 0x5e, - 0xe8, 0xf7, 0xd0, 0x9b, 0x03, 0x8d, 0x83, 0x83, 0xe1, 0x9b, 0xc3, 0x0e, 0x64, 0x03, - 0x82, 0x8c, 0xdb, 0x65, 0x2a, 0x55, 0x6b, 0x12, 0x04, 0x09, 0x31, 0x40, 0x2a, 0xa6, - 0xac, 0x34, 0xfc, 0x19, 0xfd, 0xc0, 0x6e, 0x2e, 0x77, 0x87, 0xf5, 0xb7, 0x7b, 0x04, - 0x5f, 0xd0, 0x98, 0xc0, 0x31, 0xbd, 0xbd, 0x46, 0x27, 0x76, 0x09, 0xd8, 0x42, 0xf4, - 0x84, 0x24, 0xed, 0xa3, 0x1e, 0x3c, 0xf2, 0xcd, 0xd6, 0x43, 0x85, 0xba, 0xd3, 0x11, - 0x88, 0x58, 0xd1, 0x42, 0xd9, 0x06, 0xea, 0xdb, 0x75, 0x90, 0xc9, 0x41, 0x36, 0xda, - 0x6a, 0x06, 0x35, 0x14, 0xd6, 0xa2, 0x5f, 0x7b, 0x37, 0xd7, 0x66, 0x4f, 0x9b, 0x97, - 0x09, 0x43, 0x3e, 0x6e, 0x70, 0x21, 0x18, 0xa4, 0xab, 0x9e, 0x7a, 0x7a, 0x3e, 0x62, - 0x59, 0x12, 0x99, 0x37, 0xd2, 0x9d, 0x0d, 0xb2, 0x60, 0x70, 0x52, 0x3e, 0x8b, 0x06, - 0x43, 0x13, 0x0a, 0xbe, 0xfe, 0x94, 0x3b, 0x40, 0x12, 0x98, 0xae, 0x01, 0xa3, 0xab, - 0x00, 0xab, 0xbc, 0x60, 0xd7, 0xdb, 0x93, 0x3c, 0x7f, 0x07, 0xa8, 0xbf, 0x0f, 0x7c, - 0xe1, 0x66, 0x0b, 0xcc, 0xb4, 0x5e, 0x04, 0x2b, 0x45, 0x1b, 0x93, 0x50, 0x02, 0xce, - 0xce, 0x27, 0xf3, 0x6a, 0xba, 0x56, 0x47, 0xac, 0x28, 0xd8, 0x18, 0x6c, 0xdd, 0x1f, - 0xb9, 0x5d, 0xc1, 0x35, 0xd4, 0x89, 0x92, 0xf6, 0x8d, 0xa1, 0x2a, 0xd6, 0x1a, 0xc7, - 0x56, 0x68, 0x0d, 0xd7, 0xf8, 0xd0, 0x77, 0x4a, 0xbd, 0x6c, 0xfd, 0xa2, 0xf0, 0x32, - 0xaf, 0x3b, 0xe1, 0x39, 0xa6, 0x33, 0xd6, 0x73, 0x3c, 0x75, 0xd1, 0xab, 0xa8, 0x90, - 0x18, 0xc8, 0x57, 0x2b, 0x99, 0xcd, 0x30, 0xc5, 0x37, 0x06, 0x79, 0x41, 0xdf, 0x1c, - 0x4b, 0xc1, 0xfd, 0x57, 0x0f, 0x7b, 0x4d, 0xdc, 0x97, 0x51, 0x86, 0x23, 0xe3, 0xae, - 0x4a, 0x87, 0xbd, 0xb9, 0x66, 0xc9, 0x4d, 0x86, 0x1e, 0x80, 0xde, 0x88, 0xc2, 0x92, - 0xae, 0xe9, 0x38, 0x71, 0x94, 0xe2, 0x56, 0xc6, 0x70, 0x07, 0x52, 0x30, 0x1c, 0x73, - 0xfc, 0x95, 0x65, 0xa4, 0x04, 0x80, 0xd8, 0x12, 0x6e, 0x9d, 0x08, 0x58, 0x79, 0xe2, - 0x4b, 0x16, 0xe9, 0xc4, 0x85, 0xd8, 0xf0, 0xd6, 0x18, 0xca, 0x0d, 0xd1, 0x21, 0xb5, - 0x1a, 0x7c, 0xab, 0x23, 0x0c, 0x5b, 0x45, 0x67, 0x2b, 0xdb, 0x8e, 0xa3, 0xa0, 0x40, - 0xf7, 0xaa, 0xa0, 0x98, 0xba, 0x26, 0x02, 0x5d, 0x2e, 0xab, 0x79, 0x48, 0x69, 0x3d, - 0xd5, 0xf6, 0xd3, 0x09, 0x65, 0x01, 0xe9, 0xe0, 0x71, 0x25, 0xd7, 0xeb, 0x29, 0x3b, - 0x3a, 0xba, 0xd5, 0x7f, 0xd5, 0xf0, 0x11, 0x64, 0x70, 0x2d, 0xae, 0x64, 0xbd, 0xba, - 0x8c, 0x92, 0x4f, 0xb0, 0x79, 0x96, 0x79, 0xd7, 0x7f, 0x98, 0xd3, 0x03, 0x91, 0x9f, - 0xb4, 0xa7, 0xff, 0x26, 0xa9, 0x6f, 0x13, 0x7a, 0x5e, 0x5c, 0xb9, 0x5b, 0xc4, 0xc6, - 0xff, 0x99, 0x93, 0x52, 0x6b, 0xda, 0x15, 0x03, 0x16, 0x8a, 0xb4, 0x8c, 0xbd, 0x45, - 0x15, 0x39, 0x27, 0xd3, 0x04, 0x30, 0x42, 0x3d, 0xbd, 0xf0, 0x66, 0x05, 0xf5, 0xb5, - 0x4b, 0x80, 0x8f, 0xeb, 0x22, 0xb2, 0x08, 0xb0, 0x64, 0x58, 0x18, 0x47, 0xb2, 0xf6, - 0x4c, 0xa6, 0x48, 0x37, 0x00, 0x72, 0x16, 0xde, 0x6e, 0xca, 0xff, 0xeb, 0x4b, 0x69, - 0xe6, 0x33, 0x47, 0xf8, 0x4a, 0xbc, 0xad, 0x8f, 0x2e, 0x75, 0x7d, 0x58, 0x61, 0xce, - 0x77, 0xee, 0x46, 0x51, 0x3d, 0xa7, 0x41, 0x68, 0x37, 0xdc, 0xb2, 0x3d, 0x33, 0xea, - 0x72, 0xaf, 0x23, 0xd0, 0xad, 0x8c, 0x93, 0x07, 0xd0, 0xb5, 0x85, 0x8d, 0xa9, 0x5b, - 0x77, 0xff, 0xf9, 0x02, 0x7b, 0x88, 0x59, 0xe1, 0x1d, 0xcb, 0xd5, 0x98, 0x35, 0x0e, - 0xee, 0x50, 0x93, 0x94, 0x81, 0x70, 0x8e, 0xa7, 0x08, 0xeb, 0x9f, 0x66, 0x43, 0x88, - 0xb9, 0xc6, 0x4d, 0x6a, 0xf0, 0xf9, 0x66, 0x90, 0x34, 0x24, 0x00, 0x34, 0x8e, 0x92, - 0x9e, 0x07, 0x46, 0x02, 0x53, 0xf3, 0x83, 0x90, 0xf8, 0x7b, 0xd6, 0xc0, 0x53, 0x08, - 0xc3, 0xbd, 0xe2, 0x52, 0x28, 0xe0, 0xfa, 0x08, 0x80, 0xb0, 0x8e, 0xf3, 0x4a, 0x5a, - 0x9c, 0xc0, 0xea, 0x0a, 0x67, 0xca, 0x65, 0xb6, 0xff, 0xd0, 0x05, 0x57, 0x29, 0x09, - 0xf1, 0xc4, 0x2d, 0xd7, 0x45, 0xee, 0xee, 0x9d, 0xd6, 0xb4, 0x43, 0x9c, 0x9f, 0x3f, - 0x98, 0xa1, 0x18, 0xfe, 0x16, 0x69, 0x8e, 0x9c, 0xef, 0xf5, 0x58, 0xf1, 0x60, 0x66, - 0x97, 0x5f, 0xe3, 0x95, 0x83, 0xe9, 0xb5, 0x85, 0x3b, 0x13, 0x11, 0x39, 0x15, 0x80, - 0x01, 0x9f, 0xe5, 0x5d, 0x59, 0xd1, 0xc8, 0x28, 0xd3, 0xfe, 0xb6, 0xa3, 0xb9, 0xce, - 0x92, 0xd0, 0x89, 0xae, 0x4b, 0x40, 0x8e, 0x23, 0xd6, 0xa4, 0x37, 0xd4, 0x98, 0x9b, - 0x51, 0x9b, 0x7a, 0x9e, 0xb0, 0x8a, 0xe6, 0xd4, 0x48, 0xa7, 0xa1, 0x6e, 0x8a, 0xed, - 0x26, 0xa2, 0xec, 0xd0, 0xca, 0xd8, 0x08, 0x44, 0xfd, 0x06, 0x50, 0xd8, 0xc4, 0xe4, - 0xd2, 0xaf, 0x90, 0x65, 0x67, 0x48, 0xd8, 0x09, 0x9a, 0x0c, 0x75, 0x6f, 0xc1, 0x6c, - 0xca, 0x06, 0xa3, 0x34, 0x43, 0x07, 0x02, 0xae, 0x19, 0x61, 0x66, 0x5b, 0x48, 0x45, - 0xac, 0xd1, 0xa8, 0xe3, 0x41, 0x01, 0xe6, 0x8b, 0xb6, 0x44, 0xac, 0x03, 0x4d, 0xc6, - 0x3e, 0x6e, 0x34, 0x4c, 0x3d, 0x63, 0x76, 0x2a, 0x7a, 0x5b, 0xf5, 0x9f, 0x13, 0x09, - 0x54, 0x10, 0x98, 0x1d, 0x6b, 0x6b, 0x16, 0xbc, 0xd4, 0xc9, 0xfa, 0x68, 0xaf, 0x6e, - 0x53, 0x65, 0xe9, 0x4e, 0xcb, 0xe7, 0xab, 0x8b, 0x80, 0x43, 0xdf, 0xba, 0xcb, 0x23, - 0xc8, 0x4d, 0x71, 0xa8, 0xfe, 0x5d, 0x9a, 0xc5, 0x50, 0x2c, 0xe9, 0xf7, 0x3f, 0x40, - 0x8e, 0x14, 0x37, 0x6d, 0xb8, 0x6e, 0xf5, 0x7c, 0xc3, 0x7d, 0x09, 0x89, 0x6f, 0xa9, - 0x06, 0x97, 0x2e, 0x55, 0x71, 0x80, 0xa4, 0xab, 0x5a, 0xd0, 0x9d, 0x88, 0x46, 0xdd, - 0x6d, 0xa7, 0x48, 0x76, 0x54, 0x36, 0xe0, 0x16, 0x02, 0x40, 0xf8, 0xd4, 0x1c, 0x0a, - 0xc7, 0x83, 0xf9, 0x39, 0xf2, 0xd0, 0xed, 0x26, 0x2c, 0xe8, 0x59, 0xc1, 0x31, 0xeb, - 0xc9, 0x3f, 0xf2, 0xe6, 0xe4, 0x07, 0xd4, 0xe2, 0x43, 0xe1, 0xe9, 0x31, 0xd5, 0x3a, - 0x45, 0x43, 0xb6, 0xe2, 0x6d, 0x82, 0x59, 0x6f, 0xc5, 0x3b, 0x52, 0x31, 0x2c, 0x77, - 0x6d, 0x12, 0xeb, 0x2b, 0x65, 0x9b, 0x4f, 0xb0, 0x98, 0xdf, 0x87, 0xd6, 0x83, 0xcf, - 0x9e, 0x54, 0x12, 0xee, 0x56, 0xc3, 0xfe, 0x98, 0x41, 0xd7, 0x3f, 0xd0, 0x70, 0xdf, - 0xa5, 0x1f, 0x5b, 0xaf, 0xed, 0xf2, 0x06, 0xf1, 0x3c, 0x52, 0x4e, 0x5c, 0x50, 0xca, - 0xc9, 0x90, 0x6e, 0xfa, 0x39, 0x32, 0x90, 0x04, 0x2e, 0x3b, 0xc5, 0x9f, 0x96, 0x0b, - 0x7d, 0x24, 0x0a, 0xe4, 0x43, 0xfc, 0x49, 0x26, 0x9c, 0xe0, 0x00, 0x61, 0xe6, 0x5c, - 0x6d, 0x74, 0x81, 0x2a, 0x30, 0xdd, 0x5f, 0x5f, 0xe7, 0x4e, 0xff, 0x61, 0xe0, 0xcb, - 0xab, 0x3c, 0xec, 0x75, 0xd0, 0xae, 0xf9, 0x50, 0x83, 0x18, 0x94, 0x52, 0xdd, 0x3d, - 0x9e, 0xdf, 0x44, 0x87, 0xbc, 0x73, 0x4c, 0x8b, 0x24, 0xf2, 0x12, 0x96, 0xe4, 0xe9, - 0xef, 0x11, 0x7d, 0x7f, 0xb9, 0x77, 0xe3, 0xb0, 0xe6, 0x40, 0x6e, 0x63, 0x08, 0x59, - 0x06, 0x33, 0x1a, 0x93, 0x03, 0x3d, 0x1c, 0xb8, 0x36, 0x0f, 0xe6, 0xfe, 0xa6, 0x1a, - 0x68, 0x26, 0xdf, 0x36, 0x25, 0x57, 0x89, 0xf9, 0x2e, 0x40, 0xba, 0xfc, 0xb2, 0xeb, - 0xcb, 0x9e, 0x55, 0x6f, 0x6c, 0x0c, 0xca, 0xdc, 0x6a, 0xf0, 0x8e, 0x31, 0xec, 0x4a, - 0xd5, 0x28, 0x80, 0x34, 0xe1, 0x6d, 0x15, 0x5c, 0xfd, 0xca, 0xda, 0x7b, 0xab, 0x59, - 0x9c, 0x2f, 0xa4, 0xad, 0x2e, 0x62, 0x93, 0xf9, 0xfe, 0x09, 0x71, 0x69, 0x14, 0x82, - 0x76, 0xb6, 0xa9, 0xea, 0xa7, 0x2f, 0x14, 0x8b, 0x0c, 0x95, 0x65, 0xc3, 0xc2, 0xdd, - 0x63, 0x12, 0x5e, 0x0f, 0xa5, 0x30, 0x86, 0x1a, 0x71, 0x0d, 0xf8, 0xe4, 0x81, 0xf2, - 0x71, 0x29, 0x20, 0xf8, 0x78, 0x7e, 0x0a, 0xed, 0xfe, 0x61, 0x8a, 0xff, 0x50, 0xa3, - 0xb5, 0x62, 0x13, 0x88, 0x4d, 0x62, 0x62, 0xc1, 0x1d, 0xeb, 0xf2, 0xba, 0x7e, 0x8a, - 0xd6, 0x69, 0x2c, 0xb1, 0x70, 0x78, 0x33, 0x14, 0x18, 0xda, 0x4b, 0xe0, 0x64, 0xff, - 0x52, 0x70, 0x07, 0x39, 0x34, 0xab, 0xcd, 0x2a, 0xb0, 0x46, 0x9e, 0xca, 0xf7, 0x27, - 0x5b, 0x4b, 0xd7, 0x2b, 0xc6, 0xed, 0x34, 0x47, 0x8e, 0xa4, 0x08, 0x9b, 0x73, 0x6a, - 0x16, 0xdd, 0x90, 0x6d, 0x49, 0xf2, 0x5c, 0x33, 0x82, 0x7c, 0x57, 0x1c, 0xe0, 0xb5, - 0xd7, 0x21, 0x77, 0xaa, 0x35, 0x08, 0x80, 0x4b, 0xc0, 0xf8, 0xfa, 0xa9, 0x47, 0x12, - 0x22, 0x31, 0x40, 0x2d, 0x2f, 0x5c, 0xc9, 0xa0, 0xeb, 0x0e, 0x09, 0xd4, 0x27, 0xb4, - 0x27, 0x28, 0x8d, 0x93, 0x7d, 0x9d, 0x72, 0xb7, 0x74, 0x56, 0xf8, 0x86, 0x59, 0x4c, - 0xd8, 0xc6, 0xa4, 0x62, 0xf7, 0x7f, 0xd8, 0x30, 0x76, 0x46, 0x9c, 0xc0, 0xec, 0xba, - 0x3c, 0xc4, 0x0c, 0xad, 0x69, 0xe5, 0xb5, 0x41, 0x12, 0xea, 0xb3, 0x33, 0x96, 0xae, - 0xcf, 0xbc, 0x21, 0x1f, 0x1f, 0x79, 0xcf, 0x33, 0x10, 0x8e, 0x93, 0xd9, 0x53, 0x78, - 0xba, 0xe6, 0x95, 0x82, 0x74, 0xb3, 0x10, 0x88, 0xfb, 0xd8, 0xb3, 0xa3, 0xa0, 0xd1, - 0x54, 0xa7, 0x89, 0x73, 0x5b, 0x03, 0x49, 0xc4, 0xd5, 0x1c, 0x88, 0x9d, 0x08, 0x95, - 0x2d, 0xdd, 0x54, 0x88, 0xbe, 0x95, 0x56, 0x05, 0x94, 0xe6, - ], - script_code: Script(vec![0x52, 0x63, 0x53, 0x51, 0x65]), - transparent_input: Some(0), - hash_type: 2, - amount: 483959951916902, - consensus_branch_id: consensus::BranchId::Overwinter, - sighash: [ - 0x29, 0x6f, 0xd7, 0x63, 0xf2, 0x54, 0x5e, 0x64, 0xfb, 0x5d, 0x7d, 0x49, 0xc0, 0x00, - 0xd2, 0xb4, 0x18, 0xb9, 0x3b, 0xde, 0x22, 0x34, 0xf8, 0x74, 0x29, 0x11, 0xe8, 0xaf, - 0xef, 0xd0, 0x6d, 0x57, - ], - }, - ]; - - for tv in test_vectors { + for tv in self::data::zip_0143::make_test_vectors() { let tx = Transaction::read(&tv.tx[..]).unwrap(); let transparent_input = if let Some(n) = tv.transparent_input { Some(( @@ -1912,7 +86,7 @@ fn zip_0143() { }; assert_eq!( - signature_hash(&tx, tv.consensus_branch_id, tv.hash_type, transparent_input,), + signature_hash(&tx, tv.consensus_branch_id, tv.hash_type, transparent_input), tv.sighash ); } @@ -1920,3481 +94,7 @@ fn zip_0143() { #[test] fn zip_0243() { - struct TestVector { - tx: Vec, - script_code: Script, - transparent_input: Option, - hash_type: u32, - amount: i64, - consensus_branch_id: consensus::BranchId, - sighash: [u8; 32], - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0243.py - let test_vectors = vec![ - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x00, 0x02, 0xe7, 0x71, 0x98, 0x11, - 0x89, 0x3e, 0x00, 0x00, 0x09, 0x52, 0x00, 0xac, 0x65, 0x51, 0xac, 0x63, 0x65, 0x65, - 0xb2, 0x83, 0x5a, 0x08, 0x05, 0x75, 0x02, 0x00, 0x02, 0x51, 0x51, 0x48, 0x1c, 0xdd, - 0x86, 0xb3, 0xcc, 0x43, 0x18, 0x44, 0x21, 0x17, 0x62, 0x3c, 0xeb, 0x05, 0x00, 0x03, - 0x1b, 0x3d, 0x1a, 0x02, 0x7c, 0x2c, 0x40, 0x59, 0x09, 0x58, 0xb7, 0xeb, 0x13, 0xd7, - 0x42, 0xa9, 0x97, 0x73, 0x8c, 0x46, 0xa4, 0x58, 0x96, 0x5b, 0xaf, 0x27, 0x6b, 0xa9, - 0x2f, 0x27, 0x2c, 0x72, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, 0xa5, 0xe2, - 0x9d, 0x4e, 0x30, 0xa7, 0x35, 0x94, 0xbf, 0x50, 0x98, 0x42, 0x1c, 0x69, 0x37, 0x8a, - 0xf1, 0xe4, 0x0f, 0x64, 0xe1, 0x25, 0x94, 0x6f, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, - 0xbc, 0xb6, 0x4b, 0x69, 0x68, 0x91, 0x2a, 0x63, 0x81, 0xce, 0x3d, 0xc1, 0x66, 0xd5, - 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, 0xb5, 0xfd, 0x93, 0x13, 0x25, 0xc9, - 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x51, - 0xa7, 0xaf, 0x9d, 0xb6, 0x99, 0x0e, 0xd8, 0x3d, 0xd6, 0x4a, 0xf3, 0x59, 0x7c, 0x04, - 0x32, 0x3e, 0xa5, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, 0xb9, 0xda, 0x94, 0x8d, - 0x32, 0x0d, 0xad, 0xd6, 0x4f, 0x54, 0x31, 0xe6, 0x1d, 0xdf, 0x65, 0x8d, 0x24, 0xae, - 0x67, 0xc2, 0x2c, 0x8d, 0x13, 0x09, 0x13, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, - 0x42, 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x91, 0xe0, 0x0c, 0x7a, 0x1d, 0x48, 0xaf, - 0x04, 0x68, 0x27, 0x59, 0x1e, 0x97, 0x33, 0xa9, 0x7f, 0xa6, 0xb6, 0x79, 0xf3, 0xdc, - 0x60, 0x1d, 0x00, 0x82, 0x85, 0xed, 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0xfc, 0x1b, 0xe4, - 0xaa, 0xc0, 0x0f, 0xf2, 0x71, 0x1e, 0xbd, 0x93, 0x1d, 0xe5, 0x18, 0x85, 0x68, 0x78, - 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, - 0x3c, 0x94, 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, - 0x79, 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, 0x32, 0xb4, - 0xf4, 0x73, 0xf4, 0x68, 0xa0, 0x08, 0xe7, 0x23, 0x89, 0xfc, 0x03, 0x88, 0x0d, 0x78, - 0x0c, 0xb0, 0x7f, 0xcf, 0xaa, 0xbe, 0x3f, 0x1a, 0x84, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, - 0x15, 0x3d, 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x55, 0xed, 0x94, 0x94, 0xc6, - 0xac, 0x89, 0x3c, 0x49, 0x72, 0x38, 0x33, 0xec, 0x89, 0x26, 0xc1, 0x03, 0x95, 0x86, - 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, 0x73, 0x1e, 0x98, 0x5d, 0x99, 0x58, 0x9c, 0x8b, - 0xb8, 0x38, 0xe8, 0xaa, 0xf7, 0x45, 0x53, 0x3e, 0xd9, 0xe8, 0xae, 0x3a, 0x1c, 0xd0, - 0x74, 0xa5, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, 0xeb, 0xbc, 0x86, 0x2d, - 0xed, 0x42, 0x43, 0x5e, 0x92, 0x47, 0x69, 0x30, 0xd0, 0x69, 0x89, 0x6c, 0xff, 0x30, - 0xeb, 0x41, 0x4f, 0x72, 0x7b, 0x89, 0x5a, 0x4b, 0x7b, 0xe1, 0x76, 0x93, 0x67, 0xe1, - 0xfe, 0x8a, 0xd1, 0x8d, 0xe1, 0x1e, 0x58, 0xd8, 0x8a, 0x0a, 0xd5, 0x51, 0x1d, 0x35, - 0x25, 0x12, 0x2b, 0x7b, 0x0a, 0x6f, 0x25, 0xd2, 0x8b, 0x16, 0x45, 0x7e, 0x74, 0x59, - 0x39, 0xff, 0xed, 0xbd, 0x12, 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, 0x7d, 0x41, - 0x7a, 0xdb, 0x3d, 0x15, 0xcc, 0x54, 0xdc, 0xb1, 0xfc, 0xe4, 0x67, 0x50, 0x0c, 0x6b, - 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, 0x82, 0x85, 0x7d, 0xee, 0xcc, 0x40, - 0xa9, 0x8d, 0x5f, 0x29, 0x35, 0x39, 0x5e, 0xe4, 0x76, 0x2d, 0xd2, 0x1a, 0xfd, 0xbb, - 0x5d, 0x47, 0xfa, 0x9a, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, 0xb9, 0x27, - 0xb7, 0xfa, 0xe2, 0xdb, 0x58, 0x71, 0x05, 0x41, 0x5d, 0x46, 0x42, 0x78, 0x9d, 0x38, - 0xf5, 0x0b, 0x8d, 0xbc, 0xc1, 0x29, 0xca, 0xb3, 0xd1, 0x7d, 0x19, 0xf3, 0x35, 0x5b, - 0xcf, 0x73, 0xce, 0xcb, 0x8c, 0xb8, 0xa5, 0xda, 0x01, 0x30, 0x71, 0x52, 0xf1, 0x39, - 0x36, 0xa2, 0x70, 0x57, 0x26, 0x70, 0xdc, 0x82, 0xd3, 0x90, 0x26, 0xc6, 0xcb, 0x4c, - 0xd4, 0xb0, 0xf7, 0xf5, 0xaa, 0x2a, 0x4f, 0x5a, 0x53, 0x41, 0xec, 0x5d, 0xd7, 0x15, - 0x40, 0x6f, 0x2f, 0xdd, 0x2a, 0xfa, 0x73, 0x3f, 0x5f, 0x64, 0x1c, 0x8c, 0x21, 0x86, - 0x2a, 0x1b, 0xaf, 0xce, 0x26, 0x09, 0xd9, 0xee, 0xcf, 0xa1, 0x58, 0xcf, 0xb5, 0xcd, - 0x79, 0xf8, 0x80, 0x08, 0xe3, 0x15, 0xdc, 0x7d, 0x83, 0x88, 0xe7, 0x6c, 0x17, 0x82, - 0xfd, 0x27, 0x95, 0xd1, 0x8a, 0x76, 0x36, 0x24, 0xc2, 0x5f, 0xa9, 0x59, 0xcc, 0x97, - 0x48, 0x9c, 0xe7, 0x57, 0x45, 0x82, 0x4b, 0x77, 0x86, 0x8c, 0x53, 0x23, 0x9c, 0xfb, - 0xdf, 0x73, 0xca, 0xec, 0x65, 0x60, 0x40, 0x37, 0x31, 0x4f, 0xaa, 0xce, 0xb5, 0x62, - 0x18, 0xc6, 0xbd, 0x30, 0xf8, 0x37, 0x4a, 0xc1, 0x33, 0x86, 0x79, 0x3f, 0x21, 0xa9, - 0xfb, 0x80, 0xad, 0x03, 0xbc, 0x0c, 0xda, 0x4a, 0x44, 0x94, 0x6c, 0x00, 0xe1, 0xb1, - 0xa1, 0xdf, 0x0e, 0x5b, 0x87, 0xb5, 0xbe, 0xce, 0x47, 0x7a, 0x70, 0x96, 0x49, 0xe9, - 0x50, 0x06, 0x05, 0x91, 0x39, 0x48, 0x12, 0x95, 0x1e, 0x1f, 0xe3, 0x89, 0x5b, 0x8c, - 0xc3, 0xd1, 0x4d, 0x2c, 0xf6, 0x55, 0x6d, 0xf6, 0xed, 0x4b, 0x4d, 0xdd, 0x3d, 0x9a, - 0x69, 0xf5, 0x33, 0x57, 0xd7, 0x76, 0x7f, 0x4f, 0x5c, 0xcb, 0xdb, 0xc5, 0x96, 0x63, - 0x12, 0x77, 0xf8, 0xfe, 0xcd, 0x08, 0xcb, 0x05, 0x6b, 0x95, 0xe3, 0x02, 0x5b, 0x97, - 0x92, 0xff, 0xf7, 0xf2, 0x44, 0xfc, 0x71, 0x62, 0x69, 0xb9, 0x26, 0xd6, 0x2e, 0x95, - 0x96, 0xfa, 0x82, 0x5c, 0x6b, 0xf2, 0x1a, 0xff, 0x9e, 0x68, 0x62, 0x5a, 0x6b, 0x4c, - 0xbc, 0x4b, 0x70, 0x0a, 0x36, 0x4f, 0xa7, 0x6b, 0xd8, 0x29, 0x8b, 0xc3, 0xec, 0x60, - 0x8d, 0x4c, 0xf7, 0xf3, 0x56, 0x66, 0x58, 0xd5, 0x58, 0x87, 0x14, 0xec, 0x94, 0x48, - 0xb0, 0xf0, 0x39, 0x61, 0x28, 0xae, 0xf8, 0x84, 0xa6, 0x46, 0x11, 0x4c, 0x9f, 0x1a, - 0x6d, 0xf5, 0x63, 0x19, 0x03, 0x3c, 0x31, 0x99, 0xcc, 0x7a, 0x09, 0xe9, 0xe9, 0x56, - 0x74, 0x82, 0xc9, 0x26, 0x95, 0x39, 0x02, 0x29, 0x40, 0x7b, 0xbc, 0x48, 0x98, 0x56, - 0x75, 0xe3, 0xf8, 0x74, 0xa4, 0x53, 0x3f, 0x1d, 0x63, 0xa8, 0x4d, 0xfa, 0x3e, 0x0f, - 0x46, 0x0f, 0xe2, 0xf5, 0x7e, 0x34, 0xfb, 0xc7, 0x54, 0x23, 0xb6, 0x88, 0x3a, 0x50, - 0xa0, 0xd4, 0x70, 0x19, 0x0d, 0xfb, 0xa1, 0x0a, 0x85, 0x7f, 0x82, 0x84, 0x2d, 0x38, - 0x25, 0xb3, 0xd6, 0xda, 0x05, 0x73, 0xd3, 0x16, 0xeb, 0x16, 0x0d, 0xc0, 0xb7, 0x16, - 0xc4, 0x8f, 0xbd, 0x46, 0x7f, 0x75, 0xb7, 0x80, 0x14, 0x9a, 0xe8, 0x80, 0x8f, 0x4e, - 0x68, 0xf5, 0x0c, 0x05, 0x36, 0xac, 0xdd, 0xf6, 0xf1, 0xae, 0xab, 0x01, 0x6b, 0x6b, - 0xc1, 0xec, 0x14, 0x4b, 0x4e, 0x55, 0x3a, 0xcf, 0xd6, 0x70, 0xf7, 0x7e, 0x75, 0x5f, - 0xc8, 0x8e, 0x06, 0x77, 0xe3, 0x1b, 0xa4, 0x59, 0xb4, 0x4e, 0x30, 0x77, 0x68, 0x95, - 0x8f, 0xe3, 0x78, 0x9d, 0x41, 0xc2, 0xb1, 0xff, 0x43, 0x4c, 0xb3, 0x0e, 0x15, 0x91, - 0x4f, 0x01, 0xbc, 0x6b, 0xc2, 0x30, 0x7b, 0x48, 0x8d, 0x25, 0x56, 0xd7, 0xb7, 0x38, - 0x0e, 0xa4, 0xff, 0xd7, 0x12, 0xf6, 0xb0, 0x2f, 0xe8, 0x06, 0xb9, 0x45, 0x69, 0xcd, - 0x40, 0x59, 0xf3, 0x96, 0xbf, 0x29, 0xb9, 0x9d, 0x0a, 0x40, 0xe5, 0xe1, 0x71, 0x1c, - 0xa9, 0x44, 0xf7, 0x2d, 0x43, 0x6a, 0x10, 0x2f, 0xca, 0x4b, 0x97, 0x69, 0x3d, 0xa0, - 0xb0, 0x86, 0xfe, 0x9d, 0x2e, 0x71, 0x62, 0x47, 0x0d, 0x02, 0xe0, 0xf0, 0x5d, 0x4b, - 0xec, 0x95, 0x12, 0xbf, 0xb3, 0xf3, 0x83, 0x27, 0x29, 0x6e, 0xfa, 0xa7, 0x43, 0x28, - 0xb1, 0x18, 0xc2, 0x74, 0x02, 0xc7, 0x0c, 0x3a, 0x90, 0xb4, 0x9a, 0xd4, 0xbb, 0xc6, - 0x8e, 0x37, 0xc0, 0xaa, 0x7d, 0x9b, 0x3f, 0xe1, 0x77, 0x99, 0xd7, 0x3b, 0x84, 0x1e, - 0x75, 0x17, 0x13, 0xa0, 0x29, 0x43, 0x90, 0x5a, 0xae, 0x08, 0x03, 0xfd, 0x69, 0x44, - 0x2e, 0xb7, 0x68, 0x1e, 0xc2, 0xa0, 0x56, 0x00, 0x05, 0x4e, 0x92, 0xee, 0xd5, 0x55, - 0x02, 0x8f, 0x21, 0xb6, 0xa1, 0x55, 0x26, 0x8a, 0x2d, 0xd6, 0x64, 0x0a, 0x69, 0x30, - 0x1a, 0x52, 0xa3, 0x8d, 0x4d, 0x9f, 0x9f, 0x95, 0x7a, 0xe3, 0x5a, 0xf7, 0x16, 0x71, - 0x18, 0x14, 0x1c, 0xe4, 0xc9, 0xbe, 0x0a, 0x6a, 0x49, 0x2f, 0xe7, 0x9f, 0x15, 0x81, - 0xa1, 0x55, 0xfa, 0x3a, 0x03, 0x49, 0x99, 0xc5, 0x38, 0xf7, 0xa7, 0x58, 0xbb, 0x5b, - 0x1d, 0x28, 0xfd, 0x21, 0x8f, 0xba, 0x19, 0x38, 0x74, 0x4b, 0xdb, 0x77, 0xb4, 0xa4, - 0xdf, 0xa7, 0xa5, 0xfa, 0xe9, 0x6e, 0x8c, 0xd4, 0x9b, 0x26, 0x90, 0x7d, 0xfc, 0x66, - 0x85, 0xc5, 0xc9, 0x9b, 0x71, 0x41, 0xac, 0x62, 0x6a, 0xb4, 0x76, 0x1f, 0xd3, 0xf4, - 0x1e, 0x72, 0x8e, 0x1a, 0x28, 0xf8, 0x9d, 0xb8, 0x9f, 0xfd, 0xec, 0xa3, 0x64, 0xe4, - 0xb2, 0x2d, 0x81, 0xd9, 0x96, 0x8d, 0x01, 0x19, 0xe4, 0xc7, 0xa1, 0x89, 0xad, 0xf2, - 0x2a, 0xd9, 0x68, 0x30, 0xa5, 0x4e, 0x40, 0xdc, 0x73, 0xea, 0xba, 0x6b, 0x2a, 0xaf, - 0x14, 0xf7, 0xca, 0x94, 0x2e, 0x73, 0x70, 0xb2, 0x47, 0xc0, 0x46, 0xf8, 0xe7, 0x5e, - 0xf8, 0xe3, 0xf8, 0xbd, 0x82, 0x1c, 0xf5, 0x77, 0x49, 0x18, 0x64, 0xe2, 0x0e, 0x6d, - 0x08, 0xfd, 0x2e, 0x32, 0xb5, 0x55, 0xc9, 0x2c, 0x66, 0x1f, 0x19, 0x58, 0x8b, 0x72, - 0xa8, 0x95, 0x99, 0x71, 0x0a, 0x88, 0x06, 0x12, 0x53, 0xca, 0x28, 0x5b, 0x63, 0x04, - 0xb3, 0x7d, 0xa2, 0xb5, 0x29, 0x4f, 0x5c, 0xb3, 0x54, 0xa8, 0x94, 0x32, 0x28, 0x48, - 0xcc, 0xbd, 0xc7, 0xc2, 0x54, 0x5b, 0x7d, 0xa5, 0x68, 0xaf, 0xac, 0x87, 0xff, 0xa0, - 0x05, 0xc3, 0x12, 0x24, 0x1c, 0x2d, 0x57, 0xf4, 0xb4, 0x5d, 0x64, 0x19, 0xf0, 0xd2, - 0xe2, 0xc5, 0xaf, 0x33, 0xae, 0x24, 0x37, 0x85, 0xb3, 0x25, 0xcd, 0xab, 0x95, 0x40, - 0x4f, 0xc7, 0xae, 0xd7, 0x05, 0x25, 0xcd, 0xdb, 0x41, 0x87, 0x2c, 0xfc, 0xc2, 0x14, - 0xb1, 0x32, 0x32, 0xed, 0xc7, 0x86, 0x09, 0x75, 0x3d, 0xbf, 0xf9, 0x30, 0xeb, 0x0d, - 0xc1, 0x56, 0x61, 0x2b, 0x9c, 0xb4, 0x34, 0xbc, 0x4b, 0x69, 0x33, 0x92, 0xde, 0xb8, - 0x7c, 0x53, 0x04, 0x35, 0x31, 0x2e, 0xdc, 0xed, 0xc6, 0xa9, 0x61, 0x13, 0x33, 0x38, - 0xd7, 0x86, 0xc4, 0xa3, 0xe1, 0x03, 0xf6, 0x01, 0x10, 0xa1, 0x6b, 0x13, 0x37, 0x12, - 0x97, 0x04, 0xbf, 0x47, 0x54, 0xff, 0x6b, 0xa9, 0xfb, 0xe6, 0x59, 0x51, 0xe6, 0x10, - 0x62, 0x0f, 0x71, 0xcd, 0xa8, 0xfc, 0x87, 0x76, 0x25, 0xf2, 0xc5, 0xbb, 0x04, 0xcb, - 0xe1, 0x22, 0x8b, 0x1e, 0x88, 0x6f, 0x40, 0x50, 0xaf, 0xd8, 0xfe, 0x94, 0xe9, 0x7d, - 0x2e, 0x9e, 0x85, 0xc6, 0xbb, 0x74, 0x8c, 0x00, 0x42, 0xd3, 0x24, 0x9a, 0xbb, 0x13, - 0x42, 0xbb, 0x0e, 0xeb, 0xf6, 0x20, 0x58, 0xbf, 0x3d, 0xe0, 0x80, 0xd9, 0x46, 0x11, - 0xa3, 0x75, 0x09, 0x15, 0xb5, 0xdc, 0x6c, 0x0b, 0x38, 0x99, 0xd4, 0x12, 0x22, 0xba, - 0xce, 0x76, 0x0e, 0xe9, 0xc8, 0x81, 0x8d, 0xed, 0x59, 0x9e, 0x34, 0xc5, 0x6d, 0x73, - 0x72, 0xaf, 0x1e, 0xb8, 0x68, 0x52, 0xf2, 0xa7, 0x32, 0x10, 0x4b, 0xdb, 0x75, 0x07, - 0x39, 0xde, 0x6c, 0x2c, 0x6e, 0x0f, 0x9e, 0xb7, 0xcb, 0x17, 0xf1, 0x94, 0x2b, 0xfc, - 0x9f, 0x4f, 0xd6, 0xeb, 0xb6, 0xb4, 0xcd, 0xd4, 0xda, 0x2b, 0xca, 0x26, 0xfa, 0xc4, - 0x57, 0x8e, 0x9f, 0x54, 0x34, 0x05, 0xac, 0xc7, 0xd8, 0x6f, 0xf5, 0x91, 0x58, 0xbd, - 0x0c, 0xba, 0x3a, 0xef, 0x6f, 0x4a, 0x84, 0x72, 0xd1, 0x44, 0xd9, 0x9f, 0x8b, 0x8d, - 0x1d, 0xed, 0xaa, 0x90, 0x77, 0xd4, 0xf0, 0x1d, 0x4b, 0xb2, 0x7b, 0xbe, 0x31, 0xd8, - 0x8f, 0xbe, 0xfa, 0xc3, 0xdc, 0xd4, 0x79, 0x75, 0x63, 0xa2, 0x6b, 0x1d, 0x61, 0xfc, - 0xd9, 0xa4, 0x64, 0xab, 0x21, 0xed, 0x55, 0x0f, 0xe6, 0xfa, 0x09, 0x69, 0x5b, 0xa0, - 0xb2, 0xf1, 0x0e, 0xea, 0x64, 0x68, 0xcc, 0x6e, 0x20, 0xa6, 0x6f, 0x82, 0x6e, 0x3d, - 0x14, 0xc5, 0x00, 0x6f, 0x05, 0x63, 0x88, 0x7f, 0x5e, 0x12, 0x89, 0xbe, 0x1b, 0x20, - 0x04, 0xca, 0xca, 0x8d, 0x3f, 0x34, 0xd6, 0xe8, 0x4b, 0xf5, 0x9c, 0x1e, 0x04, 0x61, - 0x9a, 0x7c, 0x23, 0xa9, 0x96, 0x94, 0x1d, 0x88, 0x9e, 0x46, 0x22, 0xa9, 0xb9, 0xb1, - 0xd5, 0x9d, 0x5e, 0x31, 0x90, 0x94, 0x31, 0x8c, 0xd4, 0x05, 0xba, 0x27, 0xb7, 0xe2, - 0xc0, 0x84, 0x76, 0x2d, 0x31, 0x45, 0x3e, 0xc4, 0x54, 0x9a, 0x4d, 0x97, 0x72, 0x9d, - 0x03, 0x34, 0x60, 0xfc, 0xf8, 0x9d, 0x64, 0x94, 0xf2, 0xff, 0xd7, 0x89, 0xe9, 0x80, - 0x82, 0xea, 0x5c, 0xe9, 0x53, 0x4b, 0x3a, 0xcd, 0x60, 0xfe, 0x49, 0xe3, 0x7e, 0x4f, - 0x66, 0x69, 0x31, 0x67, 0x73, 0x19, 0xed, 0x89, 0xf8, 0x55, 0x88, 0x74, 0x1b, 0x31, - 0x28, 0x90, 0x1a, 0x93, 0xbd, 0x78, 0xe4, 0xbe, 0x02, 0x25, 0xa9, 0xe2, 0x69, 0x2c, - 0x77, 0xc9, 0x69, 0xed, 0x01, 0x76, 0xbd, 0xf9, 0x55, 0x59, 0x48, 0xcb, 0xd5, 0xa3, - 0x32, 0xd0, 0x45, 0xde, 0x6b, 0xa6, 0xbf, 0x44, 0x90, 0xad, 0xfe, 0x74, 0x44, 0xcd, - 0x46, 0x7a, 0x09, 0x07, 0x54, 0x17, 0xfc, 0xc0, 0x06, 0x2e, 0x49, 0xf0, 0x08, 0xc5, - 0x1a, 0xd4, 0x22, 0x74, 0x39, 0xc1, 0xb4, 0x47, 0x6c, 0xcd, 0x8e, 0x97, 0x86, 0x2d, - 0xab, 0x7b, 0xe1, 0xe8, 0xd3, 0x99, 0xc0, 0x5e, 0xf2, 0x7c, 0x6e, 0x22, 0xee, 0x27, - 0x3e, 0x15, 0x78, 0x6e, 0x39, 0x4c, 0x8f, 0x1b, 0xe3, 0x16, 0x82, 0xa3, 0x01, 0x47, - 0x96, 0x3a, 0xc8, 0xda, 0x8d, 0x41, 0xd8, 0x04, 0x25, 0x84, 0x26, 0xa3, 0xf7, 0x02, - 0x89, 0xb8, 0xad, 0x19, 0xd8, 0xde, 0x13, 0xbe, 0x4e, 0xeb, 0xe3, 0xbd, 0x4c, 0x8a, - 0x6f, 0x55, 0xd6, 0xe0, 0xc3, 0x73, 0xd4, 0x56, 0x85, 0x18, 0x79, 0xf5, 0xfb, 0xc2, - 0x82, 0xdb, 0x9e, 0x13, 0x48, 0x06, 0xbf, 0xf7, 0x1e, 0x11, 0xbc, 0x33, 0xab, 0x75, - 0xdd, 0x6c, 0xa0, 0x67, 0xfb, 0x73, 0xa0, 0x43, 0xb6, 0x46, 0xa7, 0xcf, 0x39, 0xca, - 0xb4, 0x92, 0x83, 0x86, 0x78, 0x6d, 0x2f, 0x24, 0x14, 0x1e, 0xe1, 0x20, 0xfd, 0xc3, - 0x4d, 0x67, 0x64, 0xea, 0xfc, 0x66, 0x88, 0x0e, 0xe0, 0x20, 0x4f, 0x53, 0xcc, 0x11, - 0x67, 0xed, 0x20, 0xb4, 0x3a, 0x52, 0xde, 0xa3, 0xca, 0x7c, 0xff, 0x8e, 0xf3, 0x5c, - 0xd8, 0xe6, 0xd7, 0xc1, 0x11, 0xa6, 0x8e, 0xf4, 0x4b, 0xcd, 0x0c, 0x15, 0x13, 0xad, - 0x47, 0xca, 0x61, 0xc6, 0x59, 0xcc, 0x5d, 0x32, 0x5b, 0x44, 0x0f, 0x6b, 0x9f, 0x59, - 0xaf, 0xf6, 0x68, 0x79, 0xbb, 0x66, 0x88, 0xfd, 0x28, 0x59, 0x36, 0x2b, 0x18, 0x2f, - 0x20, 0x7b, 0x31, 0x75, 0x96, 0x1f, 0x64, 0x11, 0xa4, 0x93, 0xbf, 0xfd, 0x04, 0x8e, - 0x7d, 0x0d, 0x87, 0xd8, 0x2f, 0xe6, 0xf9, 0x90, 0xa2, 0xb0, 0xa2, 0x5f, 0x5a, 0xa0, - 0x11, 0x1a, 0x6e, 0x68, 0xf3, 0x7b, 0xf6, 0xf3, 0xac, 0x2d, 0x26, 0xb8, 0x46, 0x86, - 0xe5, 0x69, 0xd5, 0x8d, 0x99, 0xc1, 0x38, 0x35, 0x97, 0xfa, 0xd8, 0x11, 0x93, 0xc4, - 0xc1, 0xb1, 0x6e, 0x6a, 0x90, 0xe2, 0xd5, 0x07, 0xcd, 0xfe, 0x6f, 0xbd, 0xaa, 0x86, - 0x16, 0x3e, 0x9c, 0xf5, 0xde, 0x31, 0x00, 0xfb, 0xca, 0x7e, 0x8d, 0xa0, 0x47, 0xb0, - 0x90, 0x79, 0x36, 0x2d, 0x77, 0x92, 0xde, 0xb3, 0xca, 0x9d, 0xc1, 0x56, 0x1b, 0x87, - 0xc8, 0x2e, 0x3c, 0xb9, 0x9e, 0xb5, 0x83, 0x73, 0x19, 0x58, 0x22, 0x16, 0xa3, 0x22, - 0x67, 0x74, 0xef, 0xa9, 0x0e, 0xfb, 0x7b, 0xfc, 0x79, 0xf4, 0x25, 0x64, 0x4e, 0x4e, - 0x98, 0xc2, 0xd7, 0xd8, 0x64, 0x2b, 0x9d, 0xb8, 0x2a, 0xa7, 0x39, 0xbf, 0x2d, 0x71, - 0xcc, 0x41, 0x17, 0x22, 0x7d, 0xb2, 0x27, 0xcf, 0x0a, 0x05, 0xad, 0x9a, 0x95, 0x83, - 0x2e, 0x23, 0xc9, 0x4f, 0x27, 0x1c, 0xa0, 0xe4, 0x69, 0x4f, 0xac, 0x63, 0x22, 0x28, - 0x2e, 0xba, 0xc6, 0x98, 0x6b, 0x8f, 0xdc, 0x8a, 0xd8, 0x63, 0x08, 0x4f, 0xf1, 0x0f, - 0xd1, 0x1e, 0x6a, 0x13, 0x31, 0x1f, 0xb7, 0x99, 0xc7, 0x9c, 0x64, 0x1d, 0x9d, 0xa4, - 0x3b, 0x33, 0xe7, 0xad, 0x01, 0x2e, 0x28, 0x25, 0x53, 0x98, 0x78, 0x92, 0x62, 0x27, - 0x5f, 0x11, 0x75, 0xbe, 0x84, 0x62, 0xc0, 0x14, 0x91, 0xc4, 0xd8, 0x42, 0x40, 0x6d, - 0x0e, 0xc4, 0x28, 0x2c, 0x95, 0x26, 0x17, 0x4a, 0x09, 0x87, 0x8f, 0xe8, 0xfd, 0xde, - 0x33, 0xa2, 0x96, 0x04, 0xe5, 0xe5, 0xe7, 0xb2, 0xa0, 0x25, 0xd6, 0x65, 0x0b, 0x97, - 0xdb, 0xb5, 0x2b, 0xef, 0xb5, 0x9b, 0x1d, 0x30, 0xa5, 0x74, 0x33, 0xb0, 0xa3, 0x51, - 0x47, 0x44, 0x44, 0x09, 0x9d, 0xaa, 0x37, 0x10, 0x46, 0x61, 0x32, 0x60, 0xcf, 0x33, - 0x54, 0xcf, 0xcd, 0xad, 0xa6, 0x63, 0xec, 0xe8, 0x24, 0xff, 0xd7, 0xe4, 0x43, 0x93, - 0x88, 0x6a, 0x86, 0x16, 0x5d, 0xdd, 0xdf, 0x2b, 0x4c, 0x41, 0x77, 0x35, 0x54, 0xc8, - 0x69, 0x95, 0x26, 0x94, 0x08, 0xb1, 0x1e, 0x67, 0x37, 0xa4, 0xc4, 0x47, 0x58, 0x6f, - 0x69, 0x17, 0x34, 0x46, 0xd8, 0xe4, 0x8b, 0xf8, 0x4c, 0xbc, 0x00, 0x0a, 0x80, 0x78, - 0x99, 0x97, 0x3e, 0xb9, 0x3c, 0x5e, 0x81, 0x9a, 0xad, 0x66, 0x94, 0x13, 0xf8, 0x38, - 0x79, 0x33, 0xad, 0x15, 0x84, 0xaa, 0x35, 0xe4, 0x3f, 0x4e, 0xcd, 0x1e, 0x2d, 0x04, - 0x07, 0xc0, 0xb1, 0xb8, 0x99, 0x20, 0xff, 0xdf, 0xdb, 0x9b, 0xea, 0x51, 0xac, 0x95, - 0xb5, 0x57, 0xaf, 0x71, 0xb8, 0x9f, 0x90, 0x3f, 0x5d, 0x98, 0x48, 0xf1, 0x4f, 0xcb, - 0xeb, 0x18, 0x37, 0x57, 0x0f, 0x54, 0x4d, 0x63, 0x59, 0xeb, 0x23, 0xfa, 0xf3, 0x8a, - 0x08, 0x22, 0xda, 0x36, 0xce, 0x42, 0x6c, 0x4a, 0x2f, 0xbe, 0xff, 0xeb, 0x0a, 0x8a, - 0x2e, 0x29, 0x7a, 0x9d, 0x19, 0xba, 0x15, 0x02, 0x45, 0x90, 0xe3, 0x32, 0x9d, 0x9f, - 0xa9, 0x26, 0x1f, 0x99, 0x38, 0xa4, 0x03, 0x2d, 0xd3, 0x46, 0x06, 0xc9, 0xcf, 0x9f, - 0x3d, 0xd3, 0x3e, 0x57, 0x6f, 0x05, 0xcd, 0x1d, 0xd6, 0x81, 0x1c, 0x62, 0x98, 0x75, - 0x7d, 0x77, 0xd9, 0xe8, 0x10, 0xab, 0xdb, 0x22, 0x6a, 0xfc, 0xaa, 0x43, 0x46, 0xa6, - 0x56, 0x0f, 0x89, 0x32, 0xb3, 0x18, 0x1f, 0xd3, 0x55, 0xd5, 0xd3, 0x91, 0x97, 0x61, - 0x83, 0xf8, 0xd9, 0x93, 0x88, 0x83, 0x96, 0x32, 0xd6, 0x35, 0x4f, 0x66, 0x6d, 0x09, - 0xd3, 0xe5, 0x62, 0x9e, 0xa1, 0x97, 0x37, 0x38, 0x86, 0x13, 0xd3, 0x8a, 0x34, 0xfd, - 0x0f, 0x6e, 0x50, 0xee, 0x5a, 0x0c, 0xc9, 0x67, 0x71, 0x77, 0xf5, 0x00, 0x28, 0xc1, - 0x41, 0x37, 0x81, 0x87, 0xbd, 0x28, 0x19, 0x40, 0x3f, 0xc5, 0x34, 0xf8, 0x00, 0x76, - 0xe9, 0x38, 0x0c, 0xb4, 0x96, 0x4d, 0x3b, 0x6b, 0x45, 0x81, 0x9d, 0x3b, 0x8e, 0x9c, - 0xaf, 0x54, 0xf0, 0x51, 0x85, 0x2d, 0x67, 0x1b, 0xf8, 0xc1, 0xff, 0xde, 0x2d, 0x15, - 0x10, 0x75, 0x64, 0x18, 0xcb, 0x48, 0x10, 0x93, 0x6a, 0xa5, 0x7e, 0x69, 0x65, 0xd6, - 0xfb, 0x65, 0x6a, 0x76, 0x0b, 0x7f, 0x19, 0xad, 0xf9, 0x6c, 0x17, 0x34, 0x88, 0x55, - 0x21, 0x93, 0xb1, 0x47, 0xee, 0x58, 0x85, 0x80, 0x33, 0xda, 0xc7, 0xcd, 0x0e, 0xb2, - 0x04, 0xc0, 0x64, 0x90, 0xbb, 0xde, 0xdf, 0x5f, 0x75, 0x71, 0xac, 0xb2, 0xeb, 0xe7, - 0x6a, 0xce, 0xf3, 0xf2, 0xa0, 0x1e, 0xe9, 0x87, 0x48, 0x6d, 0xfe, 0x6c, 0x3f, 0x0a, - 0x5e, 0x23, 0x4c, 0x12, 0x72, 0x58, 0xf9, 0x7a, 0x28, 0xfb, 0x5d, 0x16, 0x4a, 0x81, - 0x76, 0xbe, 0x94, 0x6b, 0x80, 0x97, 0xd0, 0xe3, 0x17, 0x28, 0x7f, 0x33, 0xbf, 0x9c, - 0x16, 0xf9, 0xa5, 0x45, 0x40, 0x9c, 0xe2, 0x9b, 0x1f, 0x42, 0x73, 0x72, 0x5f, 0xc0, - 0xdf, 0x02, 0xa0, 0x4e, 0xba, 0xe1, 0x78, 0xb3, 0x41, 0x4f, 0xb0, 0xa8, 0x2d, 0x50, - 0xde, 0xb0, 0x9f, 0xcf, 0x4e, 0x6e, 0xe9, 0xd1, 0x80, 0xff, 0x4f, 0x56, 0xff, 0x3b, - 0xc1, 0xd3, 0x60, 0x1f, 0xc2, 0xdc, 0x90, 0xd8, 0x14, 0xc3, 0x25, 0x6f, 0x49, 0x67, - 0xd3, 0xa8, 0xd6, 0x4c, 0x83, 0xfe, 0xa3, 0x39, 0xc5, 0x1f, 0x5a, 0x8e, 0x58, 0x01, - 0xfb, 0xb9, 0x78, 0x35, 0x58, 0x1b, 0x60, 0x24, 0x65, 0xde, 0xe0, 0x4b, 0x59, 0x22, - 0xc2, 0x76, 0x1b, 0x54, 0x24, 0x5b, 0xec, 0x0c, 0x9e, 0xef, 0x2d, 0xb9, 0x7d, 0x22, - 0xb2, 0xb3, 0x55, 0x6c, 0xc9, 0x69, 0xfb, 0xb1, 0x3d, 0x06, 0x50, 0x97, 0x65, 0xa5, - 0x2b, 0x3f, 0xac, 0x54, 0xb9, 0x3f, 0x42, 0x1b, 0xf0, 0x8e, 0x18, 0xd5, 0x2d, 0xdd, - 0x52, 0xcc, 0x1c, 0x8c, 0xa8, 0xad, 0xfa, 0xcc, 0xab, 0x7e, 0x5c, 0xc2, 0xf4, 0x57, - 0x3f, 0xbb, 0xf8, 0x23, 0x9b, 0xb0, 0xb8, 0xae, 0xdb, 0xf8, 0xda, 0xd1, 0x62, 0x82, - 0xda, 0x5c, 0x91, 0x25, 0xdb, 0xa1, 0xc0, 0x59, 0xd0, 0xdf, 0x8a, 0xbf, 0x62, 0x10, - 0x78, 0xf0, 0x2d, 0x6c, 0x4b, 0xc8, 0x6d, 0x40, 0x84, 0x5a, 0xc1, 0xd5, 0x97, 0x10, - 0xc4, 0x5f, 0x07, 0xd5, 0x85, 0xeb, 0x48, 0xb3, 0x2f, 0xc0, 0x16, 0x7b, 0xa2, 0x56, - 0xe7, 0x3c, 0xa3, 0xb9, 0x31, 0x1c, 0x62, 0xd1, 0x09, 0x49, 0x79, 0x57, 0xd8, 0xdb, - 0xe1, 0x0a, 0xa3, 0xe8, 0x66, 0xb4, 0x0c, 0x0b, 0xaa, 0x2b, 0xc4, 0x92, 0xc1, 0x9a, - 0xd1, 0xe6, 0x37, 0x2d, 0x96, 0x22, 0xbf, 0x16, 0x3f, 0xbf, 0xfe, 0xae, 0xee, 0x79, - 0x6a, 0x3c, 0xd9, 0xb6, 0xfb, 0xbf, 0xa4, 0xd7, 0x92, 0xf3, 0x4d, 0x7f, 0xd6, 0xe7, - 0x63, 0xcd, 0x58, 0x59, 0xdd, 0x26, 0x83, 0x3d, 0x21, 0xd9, 0xbc, 0x54, 0x52, 0xbd, - 0x19, 0x51, 0x5d, 0xff, 0x9f, 0x49, 0x95, 0xb3, 0x5b, 0xc0, 0xc1, 0xf8, 0x76, 0xe6, - 0xad, 0x11, 0xf2, 0x45, 0x2d, 0xc9, 0xae, 0x85, 0xae, 0xc0, 0x1f, 0xc5, 0x6f, 0x8c, - 0xbf, 0xda, 0x75, 0xa7, 0x72, 0x7b, 0x75, 0xeb, 0xbd, 0x6b, 0xbf, 0xfb, 0x43, 0xb6, - 0x3a, 0x3b, 0x1b, 0x67, 0x1e, 0x40, 0xfe, 0xb0, 0xdb, 0x00, 0x29, 0x74, 0xa3, 0xc3, - 0xb1, 0xa7, 0x88, 0x56, 0x72, 0x31, 0xbf, 0x63, 0x99, 0xff, 0x89, 0x23, 0x69, 0x81, - 0x14, 0x9d, 0x42, 0x38, 0x02, 0xd2, 0x34, 0x1a, 0x3b, 0xed, 0xb9, 0xdd, 0xcb, 0xac, - 0x1f, 0xe7, 0xb6, 0x43, 0x5e, 0x14, 0x79, 0xc7, 0x2e, 0x70, 0x89, 0xb5, 0x1b, 0xfe, - 0x2f, 0xf3, 0x45, 0x85, 0x7d, 0xa9, 0xb5, 0x45, 0xe8, 0x8e, 0x32, 0x21, 0xf3, 0xf5, - 0xf7, 0x2d, 0x1e, 0x06, 0x9c, 0x9a, 0x85, 0xdd, 0x22, 0x36, 0xd3, 0x90, 0x98, 0x95, - 0x87, 0xbe, 0x00, 0x5c, 0xda, 0x16, 0xaf, 0x44, 0x08, 0xf3, 0xab, 0x06, 0xa9, 0x16, - 0xee, 0xeb, 0x9c, 0x95, 0x94, 0xb7, 0x04, 0x24, 0xa4, 0xc1, 0xd1, 0x71, 0x29, 0x5b, - 0x67, 0x63, 0xb2, 0x2f, 0x47, 0x12, 0xba, 0x7b, 0xef, 0xf0, 0xff, 0x27, 0x88, 0x3a, - 0xfa, 0xff, 0x26, 0x03, 0x4b, 0x89, 0x57, 0x35, 0x70, 0x9c, 0xf9, 0x37, 0xbd, 0x22, - 0x31, 0x89, 0x1e, 0x70, 0xeb, 0x27, 0x71, 0xe9, 0x92, 0x7c, 0x97, 0xf8, 0x76, 0x4e, - 0xb4, 0x8e, 0x91, 0x1d, 0x42, 0x8e, 0xc8, 0xd8, 0x61, 0xb7, 0x08, 0xe8, 0x29, 0x8a, - 0xcb, 0x62, 0x15, 0x51, 0x45, 0x15, 0x5a, 0xe9, 0x5f, 0x0a, 0x1d, 0x15, 0x01, 0x03, - 0x47, 0x53, 0x14, 0x6e, 0x22, 0xd0, 0x5f, 0x58, 0x6d, 0x7f, 0x6b, 0x4f, 0xe1, 0x2d, - 0xad, 0x9a, 0x17, 0xf5, 0xdb, 0x70, 0xb1, 0xdb, 0x96, 0xb8, 0xd9, 0xa8, 0x3e, 0xda, - 0xdc, 0x96, 0x6c, 0x8a, 0x54, 0x66, 0xb6, 0x1f, 0xc9, 0x98, 0xc3, 0x1f, 0x10, 0x70, - 0xd9, 0xa5, 0xc9, 0xa6, 0xd2, 0x68, 0xd3, 0x04, 0xfe, 0x6b, 0x8f, 0xd3, 0xb4, 0x01, - 0x03, 0x48, 0x61, 0x1a, 0xbd, 0xcb, 0xd4, 0x9f, 0xe4, 0xf8, 0x5b, 0x62, 0x3c, 0x78, - 0x28, 0xc7, 0x13, 0x82, 0xe1, 0x03, 0x4e, 0xa6, 0x7b, 0xc8, 0xae, 0x97, 0x40, 0x4b, - 0x0c, 0x50, 0xb2, 0xa0, 0x4f, 0x55, 0x9e, 0x49, 0x95, 0x0a, 0xfc, 0xb0, 0xef, 0x46, - 0x2a, 0x2a, 0xe0, 0x24, 0xb0, 0xf0, 0x22, 0x4d, 0xfd, 0x73, 0x68, 0x4b, 0x88, 0xc7, - 0xfb, 0xe9, 0x2d, 0x02, 0xb6, 0x8f, 0x75, 0x9c, 0x47, 0x52, 0x66, 0x3c, 0xd7, 0xb9, - 0x7a, 0x14, 0x94, 0x36, 0x49, 0x30, 0x55, 0x21, 0x32, 0x6b, 0xde, 0x08, 0x56, 0x30, - 0x86, 0x46, 0x29, 0x29, 0x1b, 0xae, 0x25, 0xff, 0x88, 0x22, 0xa1, 0x4c, 0x4b, 0x66, - 0x6a, 0x92, 0x59, 0xad, 0x0d, 0xc4, 0x2a, 0x82, 0x90, 0xac, 0x7b, 0xc7, 0xf5, 0x3a, - 0x16, 0xf3, 0x79, 0xf7, 0x58, 0xe5, 0xde, 0x75, 0x0f, 0x04, 0xfd, 0x7c, 0xad, 0x47, - 0x70, 0x1c, 0x85, 0x97, 0xf9, 0x78, 0x88, 0xbe, 0xa6, 0xfa, 0x0b, 0xf2, 0x99, 0x99, - 0x56, 0xfb, 0xfd, 0x0e, 0xe6, 0x8e, 0xc3, 0x6e, 0x46, 0x88, 0x80, 0x9a, 0xe2, 0x31, - 0xeb, 0x8b, 0xc4, 0x36, 0x9f, 0x5f, 0xe1, 0x57, 0x3f, 0x57, 0xe0, 0x99, 0xd9, 0xc0, - 0x99, 0x01, 0xbf, 0x39, 0xca, 0xac, 0x48, 0xdc, 0x11, 0x95, 0x6a, 0x8a, 0xe9, 0x05, - 0xea, 0xd8, 0x69, 0x54, 0x54, 0x7c, 0x44, 0x8a, 0xe4, 0x3d, 0x31, 0x5e, 0x66, 0x9c, - 0x42, 0x42, 0xda, 0x56, 0x59, 0x38, 0xf4, 0x17, 0xbf, 0x43, 0xce, 0x7b, 0x2b, 0x30, - 0xb1, 0xcd, 0x40, 0x18, 0x38, 0x8e, 0x1a, 0x91, 0x0f, 0x0f, 0xc4, 0x1f, 0xb0, 0x87, - 0x7a, 0x59, 0x25, 0xe4, 0x66, 0x81, 0x9d, 0x37, 0x5b, 0x0a, 0x91, 0x2d, 0x4f, 0xe8, - 0x43, 0xb7, 0x6e, 0xf6, 0xf2, 0x23, 0xf0, 0xf7, 0xc8, 0x94, 0xf3, 0x8f, 0x7a, 0xb7, - 0x80, 0xdf, 0xd7, 0x5f, 0x66, 0x9c, 0x8c, 0x06, 0xcf, 0xfa, 0x43, 0xeb, 0x47, 0x56, - 0x5a, 0x50, 0xe3, 0xb1, 0xfa, 0x45, 0xad, 0x61, 0xce, 0x9a, 0x1c, 0x47, 0x27, 0xb7, - 0xaa, 0xa5, 0x35, 0x62, 0xf5, 0x23, 0xe7, 0x39, 0x52, 0xbb, 0xf3, 0x3d, 0x8a, 0x41, - 0x04, 0x07, 0x8a, 0xde, 0x3e, 0xaa, 0xa4, 0x96, 0x99, 0xa6, 0x9f, 0xdf, 0x1c, 0x5a, - 0xc7, 0x73, 0x21, 0x46, 0xee, 0x5e, 0x1d, 0x6b, 0x6c, 0xa9, 0xb9, 0x18, 0x0f, 0x96, - 0x4c, 0xc9, 0xd0, 0x87, 0x8a, 0xe1, 0x37, 0x35, 0x24, 0xd7, 0xd5, 0x10, 0xe5, 0x82, - 0x27, 0xdf, 0x6d, 0xe9, 0xd3, 0x0d, 0x27, 0x18, 0x67, 0x64, 0x01, 0x77, 0xb0, 0xf1, - 0x85, 0x6e, 0x28, 0xd5, 0xc8, 0xaf, 0xb0, 0x95, 0xef, 0x61, 0x84, 0xfe, 0xd6, 0x51, - 0x58, 0x90, 0x22, 0xee, 0xae, 0xa4, 0xc0, 0xce, 0x1f, 0xa6, 0xf0, 0x85, 0x09, 0x2b, - 0x04, 0x97, 0x94, 0x89, 0x17, 0x2b, 0x3e, 0xf8, 0x19, 0x4a, 0x79, 0x8d, 0xf5, 0x72, - 0x4d, 0x6b, 0x05, 0xf1, 0xae, 0x00, 0x00, 0x13, 0xa0, 0x8d, 0x61, 0x2b, 0xca, 0x8a, - 0x8c, 0x31, 0x44, 0x3c, 0x10, 0x34, 0x6d, 0xbf, 0x61, 0xde, 0x84, 0x75, 0xc0, 0xbb, - 0xec, 0x51, 0x04, 0xb4, 0x75, 0x56, 0xaf, 0x3d, 0x51, 0x44, 0x58, 0xe2, 0x32, 0x1d, - 0x14, 0x60, 0x71, 0x78, 0x9d, 0x23, 0x35, 0x93, 0x4a, 0x68, 0x06, 0x14, 0xe8, 0x35, - 0x62, 0xf8, 0x2d, 0xfd, 0x40, 0x5b, 0x54, 0xa4, 0x5e, 0xb3, 0x2c, 0x16, 0x54, 0x48, - 0xd4, 0xd5, 0xd6, 0x1c, 0xa2, 0x85, 0x95, 0x85, 0x36, 0x9f, 0x53, 0xf1, 0xa1, 0x37, - 0xe9, 0xe8, 0x2b, 0x67, 0xb8, 0xfd, 0xaf, 0x01, 0xbd, 0xa5, 0x4a, 0x31, 0x73, 0x11, - 0x89, 0x6a, 0xe1, 0x02, 0x80, 0xa0, 0x32, 0x44, 0x0c, 0x42, 0x0a, 0x42, 0x1e, 0x94, - 0x4d, 0x1e, 0x95, 0x2b, 0x70, 0xd5, 0x82, 0x6c, 0xd3, 0xb0, 0x8b, 0x7d, 0xb9, 0x63, - 0x0f, 0xe4, 0xfd, 0x5f, 0x22, 0x12, 0x5d, 0xe8, 0x40, 0xfc, 0xc4, 0x0b, 0x98, 0x03, - 0x8a, 0xf1, 0x1d, 0x55, 0xbe, 0x25, 0x43, 0x25, 0x97, 0xb4, 0xb6, 0x5b, 0x9e, 0xc1, - 0xc7, 0xa8, 0xbb, 0xfd, 0x05, 0x2c, 0xbf, 0x7e, 0x1c, 0x17, 0x85, 0x31, 0x49, 0x34, - 0xb2, 0x62, 0xd5, 0x85, 0x37, 0x54, 0xf1, 0xf1, 0x77, 0x71, 0xcf, 0xb7, 0x50, 0x30, - 0x72, 0x65, 0x57, 0x53, 0xfa, 0x3f, 0x54, 0xec, 0xc5, 0x87, 0xe9, 0xf8, 0x3b, 0x58, - 0x19, 0x16, 0x09, 0x2d, 0xf2, 0x6e, 0x63, 0xe1, 0x89, 0x94, 0xcb, 0x0d, 0xb9, 0x1a, - 0x0b, 0xbd, 0xc7, 0xb6, 0x11, 0x9b, 0x32, 0x22, 0x2a, 0xdf, 0x5e, 0x61, 0xd8, 0xd8, - 0xae, 0x89, 0xda, 0xe4, 0x95, 0x4b, 0x54, 0x81, 0x3b, 0xb3, 0x3f, 0x08, 0xd5, 0x62, - 0xba, 0x51, 0x3f, 0xee, 0x1b, 0x09, 0xc0, 0xfc, 0xd5, 0x16, 0x05, 0x54, 0x19, 0x47, - 0x4d, 0xd7, 0xfd, 0xa0, 0x38, 0xa8, 0x9c, 0x84, 0xea, 0x7b, 0x94, 0x68, 0x28, 0x7f, - 0x0e, 0xb0, 0xc1, 0x0c, 0x4b, 0x13, 0x25, 0x20, 0x19, 0x4d, 0x3d, 0x8d, 0x53, 0x51, - 0xfc, 0x10, 0xd0, 0x9c, 0x15, 0xc8, 0xcc, 0x10, 0x1a, 0xa1, 0x66, 0x3b, 0xbf, 0x17, - 0xb8, 0x41, 0x11, 0xf3, 0x8b, 0xb4, 0x39, 0xf0, 0x73, 0x53, 0xbd, 0xea, 0x35, 0x96, - 0xd1, 0x5e, 0x71, 0x3e, 0x1e, 0x2e, 0x7d, 0x3f, 0x1c, 0x38, 0x31, 0x35, 0xb4, 0x7f, - 0xa7, 0xf8, 0x1f, 0x46, 0xdf, 0x7a, 0x90, 0x2a, 0x40, 0x46, 0x99, 0xec, 0x91, 0x2f, - 0x56, 0x56, 0xc3, 0x5b, 0x85, 0x76, 0x3e, 0x4d, 0xe5, 0x83, 0xae, 0xca, 0xa1, 0xdf, - 0xd5, 0xd2, 0x67, 0x7d, 0x9c, 0x8f, 0xfe, 0xe8, 0x77, 0xf6, 0x3f, 0x40, 0xa5, 0xca, - 0x0d, 0x67, 0xf6, 0xe5, 0x54, 0x12, 0x47, 0x00, 0xf8, 0x05, 0xaf, 0x87, 0x6a, 0xee, - 0xde, 0x53, 0xaa, 0x8b, 0x0f, 0x8e, 0x56, 0x04, 0xa7, 0x3c, 0x30, 0xcb, 0xd0, 0x9d, - 0xad, 0x96, 0x3d, 0x6f, 0x8a, 0x5d, 0xcc, 0x40, 0xde, 0xf4, 0x07, 0x97, 0x34, 0x21, - 0x13, 0xba, 0x20, 0x6f, 0xae, 0x8e, 0xbe, 0x4f, 0x3b, 0xc3, 0xca, 0xf6, 0x92, 0x59, - 0xe4, 0x62, 0xef, 0xf9, 0xba, 0x8b, 0x3f, 0x4b, 0xfa, 0xa1, 0x30, 0x0c, 0x26, 0x92, - 0x5a, 0x87, - ], - script_code: Script(vec![0x63]), - transparent_input: None, - hash_type: 1, - amount: 1969273897303781, - consensus_branch_id: consensus::BranchId::Sapling, - sighash: [ - 0x63, 0xd1, 0x85, 0x34, 0xde, 0x5f, 0x2d, 0x1c, 0x9e, 0x16, 0x9b, 0x73, 0xf9, 0xc7, - 0x83, 0x71, 0x8a, 0xdb, 0xef, 0x5c, 0x8a, 0x7d, 0x55, 0xb5, 0xe7, 0xa3, 0x7a, 0xff, - 0xa1, 0xdd, 0x3f, 0xf3, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0x0b, 0xbe, 0x32, 0xa5, 0x98, - 0xc2, 0x2a, 0xdf, 0xb4, 0x8c, 0xef, 0x72, 0xba, 0x5d, 0x42, 0x87, 0xc0, 0xce, 0xfb, - 0xac, 0xfd, 0x8c, 0xe1, 0x95, 0xb4, 0x96, 0x3c, 0x34, 0xa9, 0x4b, 0xba, 0x7a, 0x17, - 0x5d, 0xae, 0x4b, 0x04, 0x65, 0xac, 0x65, 0x63, 0x53, 0x70, 0x89, 0x15, 0x09, 0x0f, - 0x47, 0xa0, 0x68, 0xe2, 0x27, 0x43, 0x3f, 0x9e, 0x49, 0xd3, 0xaa, 0x09, 0xe3, 0x56, - 0xd8, 0xd6, 0x6d, 0x0c, 0x01, 0x21, 0xe9, 0x1a, 0x3c, 0x4a, 0xa3, 0xf2, 0x7f, 0xa1, - 0xb6, 0x33, 0x96, 0xe2, 0xb4, 0x1d, 0x09, 0x00, 0x63, 0x53, 0x53, 0x00, 0xac, 0x53, - 0xac, 0x51, 0x4e, 0x97, 0x05, 0x68, 0x02, 0xda, 0x07, 0x1b, 0x97, 0x0d, 0x48, 0x07, - 0x00, 0x01, 0x52, 0xa8, 0x44, 0x55, 0x0b, 0xdc, 0x20, 0x02, 0x00, 0x07, 0x52, 0x52, - 0x6a, 0x65, 0x52, 0x00, 0x52, 0xd7, 0x03, 0x43, 0x02, 0x01, 0x1b, 0x9a, 0x07, 0x66, - 0x20, 0xed, 0xc0, 0x67, 0xff, 0x02, 0x00, 0x00, 0x03, 0x53, 0xe3, 0xb8, 0xa7, 0x1f, - 0xac, 0xe1, 0xc9, 0xf3, 0x77, 0x45, 0xed, 0x36, 0x88, 0x35, 0x29, 0x30, 0x4b, 0xfd, - 0x5a, 0x39, 0x0b, 0x37, 0xbc, 0x5a, 0x34, 0x45, 0x24, 0x1f, 0x03, 0xf6, 0x4a, 0x81, - 0x88, 0x20, 0xdf, 0xed, 0xdd, 0x75, 0x37, 0x51, 0x59, 0xfb, 0xd2, 0x1e, 0xca, 0x98, - 0x72, 0x10, 0x4f, 0x8d, 0x7b, 0x3c, 0x8c, 0x86, 0x97, 0x03, 0xa1, 0xe7, 0x84, 0x8a, - 0x5c, 0x94, 0x1e, 0x45, 0xa9, 0xc7, 0x94, 0x34, 0x46, 0xd0, 0xdc, 0x96, 0x27, 0xcb, - 0x31, 0xf8, 0x0e, 0x7a, 0xa5, 0x96, 0xd4, 0x82, 0x1d, 0xc9, 0x9a, 0x7d, 0x77, 0x7c, - 0xd5, 0x7e, 0x19, 0x48, 0x42, 0xa0, 0x23, 0x47, 0x1f, 0x0f, 0x62, 0x88, 0xa1, 0x50, - 0x64, 0x7b, 0x2a, 0xfe, 0x9d, 0xf7, 0xcc, 0xcf, 0x01, 0xf5, 0xcd, 0xe5, 0xf0, 0x46, - 0x80, 0xbb, 0xfe, 0xd8, 0x7f, 0x6c, 0xf4, 0x29, 0xfb, 0x27, 0xad, 0x6b, 0xab, 0xe7, - 0x91, 0x76, 0x66, 0x11, 0xcf, 0x5b, 0xc2, 0x0e, 0x48, 0xbe, 0xf1, 0x19, 0x25, 0x9b, - 0x9b, 0x8a, 0x0e, 0x39, 0xc3, 0xdf, 0x28, 0xcb, 0x95, 0x82, 0xea, 0x33, 0x86, 0x01, - 0xcd, 0xc4, 0x81, 0xb3, 0x2f, 0xb8, 0x2a, 0xde, 0xeb, 0xb3, 0xda, 0xde, 0x25, 0xd1, - 0xa3, 0xdf, 0x20, 0xc3, 0x7e, 0x71, 0x25, 0x06, 0xb5, 0xd9, 0x96, 0xc4, 0x9a, 0x9f, - 0x0f, 0x30, 0xdd, 0xcb, 0x91, 0xfe, 0x90, 0x04, 0xe1, 0xe8, 0x32, 0x94, 0xa6, 0xc9, - 0x20, 0x3d, 0x94, 0xe8, 0xdc, 0x2c, 0xbb, 0x44, 0x9d, 0xe4, 0x15, 0x50, 0x32, 0x60, - 0x4e, 0x47, 0x99, 0x70, 0x16, 0xb3, 0x04, 0xfd, 0x43, 0x7d, 0x82, 0x35, 0x04, 0x5e, - 0x25, 0x5a, 0x19, 0xb7, 0x43, 0xa0, 0xa9, 0xf2, 0xe3, 0x36, 0xb4, 0x4c, 0xae, 0x30, - 0x7b, 0xb3, 0x98, 0x7b, 0xd3, 0xe4, 0xe7, 0x77, 0xfb, 0xb3, 0x4c, 0x0a, 0xb8, 0xcc, - 0x3d, 0x67, 0x46, 0x6c, 0x0a, 0x88, 0xdd, 0x4c, 0xca, 0xd1, 0x8a, 0x07, 0xa8, 0xd1, - 0x06, 0x8d, 0xf5, 0xb6, 0x29, 0xe5, 0x71, 0x8d, 0x0f, 0x6d, 0xf5, 0xc9, 0x57, 0xcf, - 0x71, 0xbb, 0x00, 0xa5, 0x17, 0x8f, 0x17, 0x5c, 0xac, 0xa9, 0x44, 0xe6, 0x35, 0xc5, - 0x15, 0x9f, 0x73, 0x8e, 0x24, 0x02, 0xa2, 0xd2, 0x1a, 0xa0, 0x81, 0xe1, 0x0e, 0x45, - 0x6a, 0xfb, 0x00, 0xb9, 0xf6, 0x24, 0x16, 0xc8, 0xb9, 0xc0, 0xf7, 0x22, 0x8f, 0x51, - 0x07, 0x29, 0xe0, 0xbe, 0x3f, 0x30, 0x53, 0x13, 0xd7, 0x7f, 0x73, 0x79, 0xdc, 0x2a, - 0xf2, 0x48, 0x69, 0xc6, 0xc7, 0x4e, 0xe4, 0x47, 0x14, 0x98, 0x86, 0x1d, 0x19, 0x2f, - 0x0f, 0xf0, 0xf5, 0x08, 0x28, 0x5d, 0xab, 0x6b, 0x6a, 0x36, 0xcc, 0xf7, 0xd1, 0x22, - 0x56, 0xcc, 0x76, 0xb9, 0x55, 0x03, 0x72, 0x0a, 0xc6, 0x72, 0xd0, 0x82, 0x68, 0xd2, - 0xcf, 0x77, 0x73, 0xb6, 0xba, 0x2a, 0x5f, 0x66, 0x48, 0x47, 0xbf, 0x70, 0x7f, 0x2f, - 0xc1, 0x0c, 0x98, 0xf2, 0xf0, 0x06, 0xec, 0x22, 0xcc, 0xb5, 0xa8, 0xc8, 0xb7, 0xc4, - 0x0c, 0x7c, 0x2d, 0x49, 0xa6, 0x63, 0x9b, 0x9f, 0x2c, 0xe3, 0x3c, 0x25, 0xc0, 0x4b, - 0xc4, 0x61, 0xe7, 0x44, 0xdf, 0xa5, 0x36, 0xb0, 0x0d, 0x94, 0xba, 0xdd, 0xf4, 0xf4, - 0xd1, 0x40, 0x44, 0xc6, 0x95, 0xa3, 0x38, 0x81, 0x47, 0x7d, 0xf1, 0x24, 0xf0, 0xfc, - 0xf2, 0x06, 0xa9, 0xfb, 0x2e, 0x65, 0xe3, 0x04, 0xcd, 0xbf, 0x0c, 0x4d, 0x23, 0x90, - 0x17, 0x0c, 0x13, 0x0a, 0xb8, 0x49, 0xc2, 0xf2, 0x2b, 0x5c, 0xdd, 0x39, 0x21, 0x64, - 0x0c, 0x8c, 0xf1, 0x97, 0x6a, 0xe1, 0x01, 0x0b, 0x0d, 0xfd, 0x9c, 0xb2, 0x54, 0x3e, - 0x45, 0xf9, 0x97, 0x49, 0xcc, 0x4d, 0x61, 0xf2, 0xe8, 0xaa, 0xbf, 0xe9, 0x8b, 0xd9, - 0x05, 0xfa, 0x39, 0x95, 0x1b, 0x33, 0xea, 0x76, 0x9c, 0x45, 0xab, 0x95, 0x31, 0xc5, - 0x72, 0x09, 0x86, 0x2a, 0xd1, 0x2f, 0xd7, 0x6b, 0xa4, 0x80, 0x7e, 0x65, 0x41, 0x7b, - 0x6c, 0xd1, 0x2f, 0xa8, 0xec, 0x91, 0x6f, 0x01, 0x3e, 0xbb, 0x87, 0x06, 0xa9, 0x6e, - 0xff, 0xed, 0xa0, 0x6c, 0x4b, 0xe2, 0x4b, 0x04, 0x84, 0x63, 0x92, 0xe9, 0xd1, 0xe6, - 0x93, 0x0e, 0xae, 0x01, 0xfa, 0x21, 0xfb, 0xd7, 0x00, 0x58, 0x3f, 0xb5, 0x98, 0xb9, - 0x2c, 0x8f, 0x4e, 0xb8, 0xa6, 0x1a, 0xa6, 0x23, 0x5d, 0xb6, 0x0f, 0x28, 0x41, 0xcf, - 0x3a, 0x1c, 0x6a, 0xb5, 0x4c, 0x67, 0x06, 0x68, 0x44, 0x71, 0x1d, 0x09, 0x1e, 0xb9, - 0x31, 0xa1, 0xbd, 0x62, 0x81, 0xae, 0xdf, 0x2a, 0x0e, 0x8f, 0xab, 0x18, 0x81, 0x72, - 0x02, 0xa9, 0xbe, 0x06, 0x40, 0x2e, 0xd9, 0xcc, 0x72, 0x0c, 0x16, 0xbf, 0xe8, 0x81, - 0xe4, 0xdf, 0x42, 0x55, 0xe8, 0x7a, 0xfb, 0x7f, 0xc6, 0x2f, 0x38, 0x11, 0x6b, 0xbe, - 0x03, 0xcd, 0x8a, 0x3c, 0xb1, 0x1a, 0x27, 0xd5, 0x68, 0x41, 0x47, 0x82, 0xf4, 0x7b, - 0x1a, 0x44, 0xc9, 0x7c, 0x68, 0x04, 0x67, 0x69, 0x4b, 0xc9, 0x70, 0x9d, 0x32, 0x91, - 0x6c, 0x97, 0xe8, 0x00, 0x6c, 0xbb, 0x07, 0xba, 0x0e, 0x41, 0x80, 0xa3, 0x73, 0x80, - 0x38, 0xc3, 0x74, 0xc4, 0xcc, 0xe8, 0xf3, 0x29, 0x59, 0xaf, 0xb2, 0x5f, 0x30, 0x3f, - 0x58, 0x15, 0xc4, 0x53, 0x31, 0x24, 0xac, 0xf9, 0xd1, 0x89, 0x40, 0xe7, 0x75, 0x22, - 0xac, 0x5d, 0xc4, 0xb9, 0x57, 0x0a, 0xae, 0x8f, 0x47, 0xb7, 0xf5, 0x7f, 0xd8, 0x76, - 0x7b, 0xea, 0x1a, 0x24, 0xae, 0x7b, 0xed, 0x65, 0xb4, 0xaf, 0xdc, 0x8f, 0x12, 0x78, - 0xc3, 0x0e, 0x2d, 0xb9, 0x8f, 0xd1, 0x72, 0x73, 0x0a, 0xc6, 0xbb, 0xed, 0x4f, 0x11, - 0x27, 0xcd, 0x32, 0xb0, 0x4a, 0x95, 0xb2, 0x05, 0x52, 0x6c, 0xfc, 0xb4, 0xc4, 0xe1, - 0xcc, 0x95, 0x51, 0x75, 0xb3, 0xe8, 0xde, 0x1f, 0x5d, 0x81, 0xb1, 0x86, 0x69, 0x69, - 0x23, 0x50, 0xaa, 0xa1, 0xa1, 0xd7, 0x97, 0x61, 0x75, 0x82, 0xe5, 0x4d, 0x7a, 0x5b, - 0x57, 0xa6, 0x83, 0xb3, 0x2f, 0xb1, 0x09, 0x80, 0x62, 0xda, 0xd7, 0xb0, 0xc2, 0xeb, - 0x51, 0x8f, 0x68, 0x62, 0xe8, 0x3d, 0xb2, 0x5e, 0x3d, 0xba, 0xf7, 0xae, 0xd5, 0x04, - 0xde, 0x93, 0x2a, 0xcb, 0x99, 0xd7, 0x35, 0x99, 0x2c, 0xe6, 0x2b, 0xae, 0x9e, 0xf8, - 0x93, 0xff, 0x6a, 0xcc, 0x0f, 0xfc, 0xf8, 0xe3, 0x48, 0x3e, 0x14, 0x6b, 0x9d, 0x49, - 0xdd, 0x8c, 0x78, 0x35, 0xf4, 0x3a, 0x37, 0xdc, 0xa0, 0x78, 0x7e, 0x3e, 0xc9, 0xf6, - 0x60, 0x52, 0x23, 0xd5, 0xba, 0x7a, 0xe0, 0xab, 0x90, 0x25, 0xb7, 0x3b, 0xc0, 0x3f, - 0x7f, 0xac, 0x36, 0xc0, 0x09, 0xa5, 0x6d, 0x4d, 0x95, 0xd1, 0xe8, 0x1d, 0x3b, 0x3e, - 0xbc, 0xa7, 0xe5, 0x4c, 0xc1, 0xa1, 0x2d, 0x12, 0x7b, 0x57, 0xc8, 0x13, 0x89, 0x76, - 0xe7, 0x91, 0x01, 0x3b, 0x01, 0x5f, 0x06, 0xa6, 0x24, 0xf5, 0x21, 0xb6, 0xee, 0x04, - 0xec, 0x98, 0x08, 0x93, 0xc7, 0xe5, 0xe0, 0x1a, 0x33, 0x62, 0x03, 0x59, 0x40, 0x94, - 0xf8, 0x28, 0x33, 0xd7, 0x44, 0x27, 0x88, 0x00, 0x84, 0xd3, 0x58, 0x63, 0xc8, 0xe7, - 0xeb, 0xb5, 0xc9, 0xee, 0xd9, 0x8e, 0x72, 0x57, 0x2e, 0xc4, 0x0c, 0x79, 0xb2, 0x66, - 0x23, 0xb5, 0x80, 0x22, 0xf4, 0x89, 0xb0, 0x89, 0x3d, 0x88, 0xbe, 0x63, 0xf3, 0xf8, - 0xc0, 0xd2, 0x32, 0x49, 0xeb, 0xcd, 0xe1, 0x3d, 0xb9, 0x31, 0x29, 0x41, 0xc3, 0x6c, - 0x1d, 0x1c, 0xbc, 0xab, 0xac, 0x0c, 0x78, 0xcb, 0x3b, 0x19, 0x12, 0xdb, 0x0d, 0xcb, - 0xfe, 0x18, 0x93, 0xd9, 0xb5, 0x1b, 0xe4, 0xaf, 0x1d, 0x00, 0x0b, 0xac, 0x1a, 0xd0, - 0xa3, 0xae, 0x2c, 0xe1, 0xe7, 0x32, 0x25, 0xfb, 0x11, 0x4d, 0x05, 0xaf, 0x4c, 0xef, - 0xc0, 0x6e, 0x87, 0x5f, 0x07, 0x4f, 0xfe, 0xae, 0x0c, 0xba, 0x7d, 0xa3, 0xa5, 0x16, - 0xc1, 0x73, 0xbe, 0x1c, 0x51, 0x33, 0x23, 0xe1, 0x19, 0xf6, 0x35, 0xe8, 0x20, 0x9a, - 0x07, 0x4b, 0x21, 0x6b, 0x70, 0x23, 0xfa, 0xdc, 0x2d, 0x25, 0x94, 0x9c, 0x90, 0x03, - 0x7e, 0x71, 0xe3, 0xe5, 0x50, 0x72, 0x6d, 0x21, 0x0a, 0x2c, 0x68, 0x83, 0x42, 0xe5, - 0x24, 0x40, 0x63, 0x5e, 0x9c, 0xc1, 0x4a, 0xfe, 0x10, 0x10, 0x26, 0x21, 0xa9, 0xc9, - 0xac, 0xcb, 0x78, 0x2e, 0x9e, 0x4a, 0x5f, 0xa8, 0x7f, 0x0a, 0x95, 0x6f, 0x5b, 0x85, - 0x50, 0x99, 0x60, 0x28, 0x5c, 0x22, 0x62, 0x7c, 0x59, 0x48, 0x3a, 0x5a, 0x4c, 0x28, - 0xcc, 0xe4, 0xb1, 0x56, 0xe5, 0x51, 0x40, 0x6a, 0x7e, 0xe8, 0x35, 0x56, 0x56, 0xa2, - 0x1e, 0x43, 0xe3, 0x8c, 0xe1, 0x29, 0xfd, 0xad, 0xb7, 0x59, 0xed, 0xdf, 0xa0, 0x8f, - 0x00, 0xfc, 0x8e, 0x56, 0x7c, 0xef, 0x93, 0xc6, 0x79, 0x2d, 0x01, 0xdf, 0x05, 0xe6, - 0xd5, 0x80, 0xf4, 0xd5, 0xd4, 0x8d, 0xf0, 0x42, 0x45, 0x1a, 0x33, 0x59, 0x0d, 0x3e, - 0x8c, 0xf4, 0x9b, 0x26, 0x27, 0x21, 0x8f, 0x0c, 0x29, 0x2f, 0xa6, 0x6a, 0xda, 0x94, - 0x5f, 0xa5, 0x5b, 0xb2, 0x35, 0x48, 0xe3, 0x3a, 0x83, 0xa5, 0x62, 0x95, 0x7a, 0x31, - 0x49, 0xa9, 0x93, 0xcc, 0x47, 0x23, 0x62, 0x29, 0x87, 0x36, 0xa8, 0xb7, 0x78, 0xd9, - 0x7c, 0xe4, 0x23, 0x01, 0x3d, 0x64, 0xb3, 0x2c, 0xd1, 0x72, 0xef, 0xa5, 0x51, 0xbf, - 0x7f, 0x36, 0x8f, 0x04, 0xbd, 0xae, 0xc6, 0x09, 0x1a, 0x30, 0x04, 0xa7, 0x57, 0x59, - 0x8b, 0x80, 0x1d, 0xcf, 0x67, 0x5c, 0xb8, 0x3e, 0x43, 0xa5, 0x3a, 0xe8, 0xb2, 0x54, - 0xd3, 0x33, 0xbc, 0xda, 0x20, 0xd4, 0x81, 0x7d, 0x34, 0x77, 0xab, 0xfb, 0xa2, 0x5b, - 0xb8, 0x3d, 0xf5, 0x94, 0x9c, 0x12, 0x6f, 0x14, 0x9b, 0x1d, 0x99, 0x34, 0x1e, 0x4e, - 0x6f, 0x91, 0x20, 0xf4, 0xd4, 0x1e, 0x62, 0x91, 0x85, 0x00, 0x2c, 0x72, 0xc0, 0x12, - 0xc4, 0x14, 0xd2, 0x38, 0x2a, 0x6d, 0x47, 0xc7, 0xb3, 0xde, 0xab, 0xa7, 0x70, 0xc4, - 0x00, 0xca, 0x96, 0xb2, 0x81, 0x4f, 0x6b, 0x26, 0xc3, 0xef, 0x17, 0x42, 0x9f, 0x1a, - 0x98, 0xc8, 0x5d, 0x83, 0xdb, 0x20, 0xef, 0xad, 0x48, 0xbe, 0x89, 0x96, 0xfb, 0x1b, - 0xff, 0x59, 0x1e, 0xff, 0xf3, 0x60, 0xfe, 0x11, 0x99, 0x05, 0x6c, 0x56, 0xe5, 0xfe, - 0xec, 0x61, 0xa7, 0xb8, 0xb9, 0xf6, 0x99, 0xd6, 0x01, 0x2c, 0x28, 0x49, 0x23, 0x2f, - 0x32, 0x9f, 0xef, 0x95, 0xc7, 0xaf, 0x37, 0x00, 0x98, 0xff, 0xe4, 0x91, 0x8e, 0x0c, - 0xa1, 0xdf, 0x47, 0xf2, 0x75, 0x86, 0x7b, 0x73, 0x9e, 0x0a, 0x51, 0x4d, 0x32, 0x09, - 0x32, 0x5e, 0x21, 0x70, 0x45, 0x92, 0x7b, 0x47, 0x9c, 0x1c, 0xe2, 0xe5, 0xd5, 0x4f, - 0x25, 0x48, 0x8c, 0xad, 0x15, 0x13, 0xe3, 0xf4, 0x4a, 0x21, 0x26, 0x6c, 0xfd, 0x84, - 0x16, 0x33, 0x32, 0x7d, 0xee, 0x6c, 0xf8, 0x10, 0xfb, 0xf7, 0x39, 0x3e, 0x31, 0x7d, - 0x9e, 0x53, 0xd1, 0xbe, 0x1d, 0x5a, 0xe7, 0x83, 0x9b, 0x66, 0xb9, 0x43, 0xb9, 0xed, - 0x18, 0xf2, 0xc5, 0x30, 0xe9, 0x75, 0x42, 0x23, 0x32, 0xc3, 0x43, 0x9c, 0xce, 0x49, - 0xa2, 0x9f, 0x2a, 0x33, 0x6a, 0x48, 0x51, 0x26, 0x3c, 0x5e, 0x9b, 0xd1, 0x3d, 0x73, - 0x11, 0x09, 0xe8, 0x44, 0xb7, 0xf8, 0xc3, 0x92, 0xa5, 0xc1, 0xdc, 0xaa, 0x2a, 0xe5, - 0xf5, 0x0f, 0xf6, 0x3f, 0xab, 0x97, 0x65, 0xe0, 0x16, 0x70, 0x2c, 0x35, 0xa6, 0x7c, - 0xd7, 0x36, 0x4d, 0x3f, 0xab, 0x55, 0x2f, 0xb3, 0x49, 0xe3, 0x5c, 0x15, 0xc5, 0x02, - 0x50, 0x45, 0x3f, 0xd1, 0x8f, 0x7b, 0x85, 0x59, 0x92, 0x63, 0x2e, 0x2c, 0x76, 0xc0, - 0xfb, 0xf1, 0xef, 0x96, 0x3e, 0xa8, 0x0e, 0x32, 0x23, 0xde, 0x32, 0x77, 0xbc, 0x55, - 0x92, 0x51, 0x72, 0x58, 0x29, 0xec, 0x03, 0xf2, 0x13, 0xba, 0x89, 0x55, 0xca, 0xb2, - 0x82, 0x2f, 0xf2, 0x1a, 0x9b, 0x0a, 0x49, 0x04, 0xd6, 0x68, 0xfc, 0xd7, 0x72, 0x24, - 0xbd, 0xe3, 0xdd, 0x01, 0xf6, 0xff, 0xc4, 0x82, 0x8f, 0x6b, 0x64, 0x23, 0x0b, 0x35, - 0xc6, 0xa0, 0x49, 0x87, 0x34, 0x94, 0x27, 0x6e, 0xa1, 0xd7, 0xed, 0x5e, 0x92, 0xcb, - 0x4f, 0x90, 0xba, 0x83, 0xa9, 0xe4, 0x96, 0x01, 0xb1, 0x94, 0x04, 0x2f, 0x29, 0x00, - 0xd9, 0x9d, 0x31, 0x2d, 0x7b, 0x70, 0x50, 0x8c, 0xf1, 0x76, 0x06, 0x6d, 0x15, 0x4d, - 0xbe, 0x96, 0xef, 0x9d, 0x43, 0x67, 0xe4, 0xc8, 0x40, 0xe4, 0xa1, 0x7b, 0x5e, 0x51, - 0x22, 0xe8, 0xeb, 0xe2, 0x15, 0x8a, 0x3c, 0x5f, 0x4c, 0xba, 0xe2, 0x1e, 0xa3, 0xfa, - 0x1a, 0xe6, 0xc2, 0x5a, 0x94, 0x62, 0xeb, 0xcb, 0xb0, 0xfd, 0x5f, 0x14, 0x55, 0x4b, - 0xc9, 0x77, 0x47, 0xc3, 0x3e, 0x34, 0xda, 0x90, 0xc8, 0x16, 0xd8, 0xd0, 0xd5, 0x0b, - 0xfe, 0x37, 0x61, 0x8c, 0x58, 0x12, 0x89, 0x14, 0x84, 0xfa, 0x25, 0x93, 0x22, 0xc1, - 0x50, 0x92, 0xd4, 0x15, 0x5d, 0x86, 0x96, 0xd6, 0xf1, 0x2f, 0x24, 0xfd, 0x36, 0x44, - 0x96, 0xb3, 0xbe, 0x08, 0x71, 0xca, 0x3d, 0xd9, 0x62, 0x53, 0x48, 0xa6, 0x14, 0xb5, - 0x9b, 0xde, 0x45, 0x88, 0x56, 0x49, 0xba, 0xe3, 0x6d, 0xe3, 0x4d, 0xef, 0x8f, 0xce, - 0xc8, 0x53, 0x43, 0x47, 0x5d, 0x97, 0x6a, 0xe1, 0xe9, 0xb2, 0x78, 0x29, 0xce, 0x2a, - 0xc5, 0xef, 0xd0, 0xb3, 0x99, 0xa8, 0xb4, 0x48, 0xbe, 0x65, 0x04, 0x29, 0x4e, 0xe6, - 0xb3, 0xc1, 0xc6, 0xa5, 0x34, 0x2d, 0x7c, 0x01, 0xae, 0x9d, 0x8a, 0xd3, 0x07, 0x0c, - 0x2b, 0x1a, 0x91, 0x57, 0x3a, 0xf5, 0xe0, 0xc5, 0xe4, 0xcb, 0xbf, 0x4a, 0xcd, 0xc6, - 0xb5, 0x4c, 0x92, 0x72, 0x20, 0x0d, 0x99, 0x70, 0x25, 0x0c, 0x17, 0xc1, 0x03, 0x6f, - 0x06, 0x08, 0x5c, 0x41, 0x85, 0x8e, 0xd3, 0xa0, 0xc4, 0x81, 0x50, 0xbc, 0x69, 0x7e, - 0x4a, 0x69, 0x5f, 0xef, 0x33, 0x5f, 0x7a, 0xd0, 0x7e, 0x1a, 0x46, 0xdc, 0x76, 0x7f, - 0xf8, 0x22, 0xdb, 0x70, 0xe6, 0x66, 0x90, 0x80, 0xb9, 0x81, 0x6b, 0x22, 0x32, 0xc8, - 0x1a, 0x4c, 0x66, 0xcc, 0x58, 0x6a, 0xbf, 0xe1, 0xea, 0xa8, 0xca, 0x6c, 0xf4, 0x1f, - 0xc3, 0x0e, 0xb8, 0xdc, 0x57, 0xc3, 0x7a, 0x3c, 0x39, 0xc5, 0x9c, 0x94, 0x23, 0x2d, - 0xf9, 0xd3, 0x88, 0xdb, 0xfa, 0x35, 0xc2, 0xcd, 0x5c, 0x75, 0xf3, 0x28, 0xe9, 0xfe, - 0xa7, 0x8f, 0x65, 0x56, 0x8f, 0x2b, 0xb9, 0x34, 0xc8, 0x2c, 0x41, 0x42, 0xda, 0x69, - 0xd1, 0x2c, 0xa7, 0xde, 0x9a, 0x7d, 0xf7, 0x06, 0x40, 0x0e, 0xc7, 0x98, 0x78, 0xd8, - 0x68, 0xe1, 0x7e, 0x8f, 0x71, 0xea, 0x31, 0x49, 0x5a, 0x8b, 0xae, 0x7b, 0xdc, 0x2e, - 0x48, 0xb5, 0x11, 0x87, 0x71, 0xc2, 0xfc, 0xa0, 0x78, 0xcc, 0xa1, 0xfc, 0xe0, 0xd7, - 0xef, 0x0a, 0xf3, 0x47, 0x8c, 0xf3, 0x6f, 0x69, 0xe8, 0x5a, 0x41, 0xdd, 0x29, 0xb4, - 0x29, 0x4a, 0x65, 0xd3, 0xe0, 0x55, 0xff, 0x71, 0x8d, 0xd9, 0xdc, 0x8c, 0x75, 0xe7, - 0xe5, 0xb2, 0xef, 0xe4, 0x42, 0x63, 0x73, 0x71, 0xb7, 0xc4, 0x8f, 0x6e, 0xe9, 0x9e, - 0x3e, 0xa3, 0x8a, 0x4b, 0x0f, 0x2f, 0x67, 0xfc, 0x2b, 0x90, 0x8c, 0xda, 0x65, 0x7e, - 0xae, 0x75, 0x4e, 0x03, 0x7e, 0x26, 0x2e, 0x9a, 0x9f, 0x9b, 0xd7, 0xec, 0x42, 0x67, - 0xed, 0x8e, 0x96, 0x93, 0x0e, 0x10, 0x84, 0x78, 0x3c, 0x37, 0xd6, 0xf9, 0xdd, 0x15, - 0xfd, 0x29, 0xf4, 0xcc, 0x47, 0x7e, 0x66, 0xf1, 0x30, 0xd6, 0x30, 0x43, 0x0d, 0xcc, - 0x01, 0x04, 0x89, 0x9b, 0x4f, 0x9f, 0x46, 0xeb, 0x09, 0x0e, 0xf7, 0xfc, 0x90, 0xb4, - 0x79, 0xab, 0xf6, 0x1f, 0x93, 0x95, 0x5e, 0xe0, 0x0e, 0x6a, 0x18, 0x48, 0xf1, 0xab, - 0x14, 0xad, 0x33, 0x4f, 0x2b, 0x68, 0x03, 0x58, 0x08, 0xcd, 0xf1, 0xbb, 0x9e, 0x9d, - 0x9a, 0x81, 0x6b, 0xaf, 0x72, 0x8a, 0x95, 0x5b, 0x96, 0x0b, 0x77, 0x01, 0xfa, 0x62, - 0x66, 0x87, 0xdc, 0x3c, 0x9c, 0xba, 0x64, 0x63, 0x37, 0xb5, 0x3e, 0x29, 0x81, 0x6e, - 0x94, 0x82, 0xdd, 0xf5, 0x57, 0x8a, 0x87, 0x68, 0xaa, 0xe4, 0x77, 0xfc, 0xe4, 0x10, - 0xac, 0x2d, 0x5d, 0xe6, 0x09, 0x58, 0x61, 0xc1, 0x11, 0xd7, 0xfe, 0xb3, 0xe6, 0xbb, - 0x4f, 0xbb, 0x5a, 0x54, 0x95, 0x54, 0x95, 0x97, 0x27, 0x98, 0x35, 0x0a, 0x25, 0x3f, - 0x05, 0xf6, 0x6c, 0x2e, 0xcf, 0xcb, 0xc0, 0xed, 0x43, 0xf5, 0xec, 0x2e, 0x6d, 0x8d, - 0xba, 0x15, 0xa5, 0x12, 0x54, 0xd9, 0x7b, 0x18, 0x21, 0x10, 0x7c, 0x07, 0xdd, 0x9a, - 0x16, 0xef, 0x84, 0x06, 0xf9, 0x43, 0xe2, 0x82, 0xb9, 0x5d, 0x4b, 0x36, 0x25, 0x30, - 0xc9, 0x13, 0xd6, 0xba, 0x42, 0x1d, 0xf6, 0x02, 0x7d, 0xe5, 0xaf, 0x1e, 0x47, 0x45, - 0xd5, 0x86, 0x81, 0x06, 0x95, 0x4b, 0xe6, 0xc1, 0x96, 0x27, 0x80, 0xa2, 0x94, 0x10, - 0x72, 0xe9, 0x51, 0x31, 0xb1, 0x67, 0x9d, 0xf0, 0x63, 0x76, 0x25, 0x04, 0x2c, 0x37, - 0xd4, 0x8f, 0xfb, 0x15, 0x2e, 0x5e, 0xbc, 0x18, 0x5c, 0x8a, 0x2b, 0x7d, 0x43, 0x85, - 0xf1, 0xc9, 0x5a, 0xf9, 0x37, 0xdf, 0x78, 0xdf, 0xd8, 0x75, 0x7f, 0xab, 0x43, 0x49, - 0x68, 0xb0, 0xb5, 0x7c, 0x66, 0x57, 0x44, 0x68, 0xf1, 0x60, 0xb4, 0x47, 0xac, 0x82, - 0x21, 0xe5, 0x06, 0x06, 0x76, 0xa8, 0x42, 0xa1, 0xc6, 0xb7, 0x17, 0x2d, 0xd3, 0x34, - 0x0f, 0x76, 0x40, 0x70, 0xab, 0x1f, 0xe0, 0x91, 0xc5, 0xc7, 0x4c, 0x95, 0xa5, 0xdc, - 0x04, 0x33, 0x90, 0x72, 0x3a, 0x4c, 0x12, 0x7d, 0xa1, 0x4c, 0xdd, 0xe1, 0xdc, 0x26, - 0x75, 0xa6, 0x23, 0x40, 0xb3, 0xe6, 0xaf, 0xd0, 0x52, 0x2a, 0x31, 0xde, 0x26, 0xe7, - 0xd1, 0xec, 0x3a, 0x9c, 0x8a, 0x09, 0x1f, 0xfd, 0xc7, 0x5b, 0x7e, 0xcf, 0xdc, 0x7c, - 0x12, 0x99, 0x5a, 0x5e, 0x37, 0xce, 0x34, 0x88, 0xbd, 0x29, 0xf8, 0x62, 0x9d, 0x68, - 0xf6, 0x96, 0x49, 0x24, 0x48, 0xdd, 0x52, 0x66, 0x97, 0x47, 0x6d, 0xc0, 0x61, 0x34, - 0x6e, 0xbe, 0x3f, 0x67, 0x72, 0x17, 0xff, 0x9c, 0x60, 0xef, 0xce, 0x94, 0x3a, 0xf2, - 0x8d, 0xfd, 0x3f, 0x9e, 0x59, 0x69, 0x25, 0x98, 0xa6, 0x04, 0x7c, 0x23, 0xc4, 0xc0, - 0x14, 0x00, 0xf1, 0xab, 0x57, 0x30, 0xea, 0xc0, 0xae, 0x8d, 0x58, 0x43, 0xd5, 0x05, - 0x1c, 0x37, 0x62, 0x40, 0x17, 0x2a, 0xf2, 0x18, 0xd7, 0xa1, 0xec, 0xfe, 0x65, 0xb4, - 0xf7, 0x51, 0x00, 0x63, 0x89, 0x83, 0xc1, 0x4d, 0xe4, 0x97, 0x47, 0x55, 0xda, 0xde, - 0x80, 0x18, 0xc9, 0xb8, 0xf4, 0x54, 0x3f, 0xb0, 0x95, 0x96, 0x15, 0x13, 0xe6, 0x7c, - 0x61, 0xdb, 0xc5, 0x9c, 0x60, 0x7f, 0x9b, 0x51, 0xf8, 0xd0, 0x9b, 0xdc, 0xad, 0x28, - 0xbc, 0xfb, 0x9e, 0x5d, 0x27, 0x44, 0xea, 0x88, 0x48, 0xb2, 0x62, 0x3a, 0xc0, 0x7f, - 0x8e, 0xf6, 0x1a, 0x81, 0xa3, 0x59, 0x10, 0xb8, 0xa1, 0xba, 0xf3, 0x9a, 0x91, 0x9a, - 0x7b, 0x60, 0xbc, 0x60, 0x4d, 0x63, 0x18, 0x5f, 0x75, 0x92, 0x21, 0xd8, 0x47, 0xcc, - 0x54, 0xa2, 0x27, 0x65, 0xa4, 0xc3, 0x34, 0x75, 0xb5, 0x79, 0x1e, 0x9a, 0xf3, 0x27, - 0x1f, 0xc8, 0xd9, 0x35, 0x06, 0x67, 0x09, 0x0d, 0x81, 0x84, 0xec, 0x50, 0x52, 0x2d, - 0x80, 0x4f, 0x23, 0xc4, 0xfb, 0x44, 0xff, 0xa4, 0x81, 0xbc, 0x92, 0xae, 0x40, 0x8d, - 0x1b, 0x9f, 0x2b, 0x13, 0x19, 0x04, 0xf9, 0x70, 0x5c, 0x59, 0xe2, 0xf4, 0xbd, 0xe7, - 0xa3, 0xb2, 0xc0, 0x85, 0xd9, 0x3f, 0xd2, 0xab, 0xc5, 0xe1, 0x4d, 0x16, 0x30, 0x01, - 0xa1, 0x2f, 0x51, 0x93, 0x8d, 0x02, 0x1a, 0xfa, 0x92, 0x23, 0x9b, 0x87, 0x3d, 0xc6, - 0xc3, 0x57, 0xea, 0xa8, 0xaf, 0x4e, 0xe6, 0xd0, 0x05, 0x40, 0x65, 0x7f, 0xe3, 0x29, - 0x14, 0x10, 0x3b, 0x5d, 0x98, 0xf6, 0x8b, 0xd3, 0xe2, 0xb5, 0x35, 0x9f, 0x08, 0xcc, - 0xd8, 0x8d, 0x0c, 0x81, 0x1e, 0x4c, 0x31, 0xfb, 0xb4, 0x9f, 0x3a, 0x90, 0xbb, 0xd0, - 0x5d, 0xce, 0x62, 0xf3, 0x44, 0xe7, 0x07, 0x75, 0x93, 0x15, 0x9a, 0xe3, 0x50, 0x50, - 0xb0, 0x4c, 0x9e, 0x6b, 0x86, 0xbc, 0x43, 0x2d, 0xc8, 0xb0, 0x48, 0xc7, 0x3c, 0x00, - 0x18, 0xca, 0x5b, 0x69, 0x41, 0x12, 0x97, 0x73, 0x2a, 0x4e, 0x1a, 0xa9, 0x9a, 0x92, - 0x8c, 0x71, 0xe7, 0xa2, 0x4f, 0xd2, 0x77, 0x85, 0x6a, 0xa4, 0x25, 0x01, 0xe5, 0x1b, - 0x01, 0x2a, 0xea, 0x94, 0x46, 0xa2, 0x10, 0x4e, 0x93, 0xf8, 0x15, 0xa0, 0xb3, 0xa2, - 0x9b, 0x45, 0x83, 0x14, 0xf3, 0xd8, 0xbe, 0x2b, 0x98, 0x23, 0xd3, 0x42, 0xf4, 0x62, - 0x13, 0xe9, 0x42, 0xa7, 0xe1, 0x9a, 0x46, 0xe9, 0x70, 0xb5, 0xc5, 0x06, 0x70, 0x84, - 0x30, 0x31, 0x7b, 0x1b, 0xb3, 0xb3, 0x5d, 0xf6, 0x8a, 0xe3, 0x3a, 0x49, 0x26, 0xa0, - 0x3e, 0x6b, 0xfe, 0xb5, 0x51, 0x04, 0x16, 0xfc, 0xbb, 0x05, 0x24, 0xc9, 0xca, 0x50, - 0x74, 0x15, 0x6c, 0xc5, 0xa5, 0xd6, 0xfe, 0x1c, 0x99, 0x5e, 0xdc, 0x60, 0xa2, 0xf5, - 0x50, 0x41, 0x1a, 0xa4, 0x1e, 0x3d, 0xa3, 0xbd, 0xcf, 0x64, 0xbc, 0xf0, 0x4a, 0x05, - 0x10, 0x57, 0x1b, 0x93, 0x6d, 0x47, 0xe5, 0x5c, 0xec, 0x03, 0x30, 0x00, 0x8d, 0xfe, - 0x73, 0x56, 0x34, 0x04, 0xf0, 0x47, 0xd7, 0xf3, 0xa8, 0xa3, 0xd7, 0x74, 0x3b, 0xc5, - 0x54, 0x95, 0x52, 0x10, 0xf1, 0xeb, 0x0d, 0x08, 0x59, 0x9e, 0xa7, 0x7d, 0x5f, 0x97, - 0x4d, 0x87, 0x17, 0x6d, 0x37, 0xd9, 0x8b, 0x9c, 0x0a, 0xd4, 0x40, 0x40, 0x72, 0x09, - 0xed, 0x6a, 0x9f, 0x08, 0x46, 0x4d, 0x56, 0x55, 0x93, 0xe1, 0xa6, 0x3b, 0x93, 0x85, - 0x36, 0xb4, 0x92, 0x44, 0xe9, 0x7d, - ], - script_code: Script(vec![]), - transparent_input: Some(1), - hash_type: 2, - amount: 652655344020909, - consensus_branch_id: consensus::BranchId::Sapling, - sighash: [ - 0xbb, 0xe6, 0xd8, 0x4f, 0x57, 0xc5, 0x6b, 0x29, 0xb9, 0x14, 0xc6, 0x94, 0xba, 0xac, - 0xcb, 0x89, 0x12, 0x97, 0xe9, 0x61, 0xde, 0x3e, 0xb4, 0x6c, 0x68, 0xe3, 0xc8, 0x9c, - 0x47, 0xb1, 0xa1, 0xdb, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x01, 0x46, 0xcf, 0x28, 0x9b, 0x7d, - 0x89, 0x13, 0x07, 0xbb, 0xa3, 0x70, 0x54, 0xcf, 0x91, 0xb3, 0x1f, 0xc8, 0x2f, 0x74, - 0xd5, 0xfc, 0xc0, 0x00, 0x94, 0x2e, 0xde, 0x91, 0x18, 0x25, 0xf5, 0x3f, 0xe6, 0x09, - 0x68, 0x6f, 0x46, 0x00, 0x23, 0xb1, 0xe9, 0xbc, 0x00, 0xbd, 0xe8, 0x95, 0xd1, 0x23, - 0x8f, 0xad, 0x04, 0xab, 0xa9, 0x88, 0x99, 0x66, 0x7d, 0x01, 0x00, 0x04, 0xea, 0x42, - 0x71, 0x76, 0x09, 0x84, 0x13, 0x90, 0x59, 0x18, 0xee, 0x21, 0x3d, 0x4e, 0xc1, 0x27, - 0x94, 0x74, 0x2d, 0x19, 0xf6, 0x7d, 0x6f, 0x86, 0xce, 0xf7, 0xe6, 0x98, 0x2e, 0x88, - 0x41, 0x71, 0x28, 0x73, 0xa0, 0x1d, 0x92, 0x51, 0xd8, 0xc8, 0x60, 0xc0, 0x41, 0x52, - 0x5b, 0x3b, 0xf4, 0xe3, 0xa2, 0xeb, 0x92, 0x72, 0x81, 0x5c, 0x75, 0x86, 0x76, 0x84, - 0x28, 0xb4, 0xc2, 0xb2, 0x5e, 0x37, 0x45, 0xf0, 0x09, 0xc5, 0xdc, 0xe2, 0x0b, 0x69, - 0xd5, 0xd7, 0xc4, 0x3c, 0xeb, 0x73, 0x6b, 0x68, 0x31, 0xe8, 0xc1, 0x10, 0xf1, 0x6c, - 0xfd, 0xb3, 0xa4, 0x67, 0xe9, 0x41, 0x4c, 0x00, 0xec, 0xf1, 0x37, 0x31, 0x50, 0x08, - 0x94, 0x55, 0x56, 0x78, 0xc4, 0x97, 0xfa, 0xba, 0x9a, 0x95, 0xd0, 0x1c, 0xc4, 0x64, - 0x39, 0x0f, 0xc4, 0xa7, 0x6b, 0xfa, 0x8b, 0x0e, 0x1c, 0x68, 0xa5, 0x25, 0xd7, 0x06, - 0xd6, 0x60, 0x4b, 0x23, 0x30, 0xb6, 0xb3, 0x48, 0x52, 0x15, 0xf6, 0x06, 0xf1, 0x88, - 0x3a, 0x75, 0x15, 0x88, 0xc7, 0xef, 0xa5, 0x06, 0xc3, 0xe8, 0xd0, 0xc6, 0x01, 0x92, - 0xe8, 0x47, 0x6b, 0xd1, 0x17, 0x5d, 0x95, 0x62, 0x08, 0x7b, 0xdb, 0x81, 0x8e, 0x66, - 0x21, 0x62, 0x86, 0xba, 0xfe, 0x47, 0xff, 0x4d, 0xbc, 0xce, 0xd5, 0x14, 0x44, 0x48, - 0x0a, 0x9a, 0x56, 0x73, 0xec, 0xe7, 0xfa, 0xc7, 0x3a, 0x0e, 0xd4, 0x1a, 0xb0, 0x05, - 0x17, 0x53, 0xa7, 0xca, 0xa8, 0x9b, 0xe3, 0x13, 0x9a, 0xfd, 0x97, 0x93, 0xb3, 0xe0, - 0x2f, 0x27, 0xf0, 0x40, 0x04, 0x65, 0x95, 0xac, 0xd4, 0x7b, 0xf1, 0x3f, 0xd0, 0xda, - 0x27, 0xf0, 0x9e, 0xda, 0x48, 0x03, 0x6d, 0x3e, 0xe4, 0x37, 0xf2, 0xee, 0x8f, 0x86, - 0x06, 0xea, 0x97, 0x34, 0x3c, 0x33, 0x58, 0x46, 0x57, 0xf4, 0x6d, 0xba, 0x99, 0xdb, - 0x5c, 0xfe, 0x6c, 0xa1, 0x76, 0xfa, 0xb7, 0xb0, 0xf3, 0xbf, 0xa0, 0xab, 0x61, 0xe3, - 0x40, 0xc3, 0x4e, 0xb9, 0xf1, 0x7c, 0x7e, 0xc2, 0xbe, 0x03, 0xb1, 0x80, 0xf0, 0xbb, - 0x6f, 0x43, 0x4c, 0x2a, 0x65, 0x42, 0xe0, 0x0e, 0x84, 0x37, 0x3f, 0x4f, 0x46, 0x49, - 0xcd, 0xa3, 0x2b, 0xf6, 0x86, 0x66, 0x61, 0x43, 0xf6, 0x22, 0xaa, 0x48, 0x04, 0x60, - 0xb5, 0xaf, 0xac, 0x51, 0x86, 0x07, 0xcd, 0x9a, 0xf8, 0xbc, 0xd6, 0xb5, 0x8c, 0x30, - 0x12, 0x73, 0x16, 0xb2, 0x5d, 0x5e, 0xa7, 0xbf, 0x6b, 0x0c, 0xab, 0x85, 0x42, 0xff, - 0x69, 0xd9, 0xb2, 0xf1, 0x80, 0xbe, 0x12, 0xed, 0x75, 0x34, 0x4a, 0x39, 0x5a, 0xa1, - 0x0f, 0x85, 0x2f, 0x08, 0x3a, 0xd6, 0x4e, 0xf4, 0x0e, 0x9c, 0x03, 0x09, 0xe9, 0xbb, - 0xa5, 0x4b, 0x8c, 0xb3, 0x3c, 0x95, 0x49, 0x8a, 0x69, 0x53, 0x8d, 0x3a, 0xe5, 0xb2, - 0x5e, 0x24, 0x70, 0x98, 0xe1, 0x11, 0x7c, 0x91, 0x8a, 0xaa, 0xae, 0x9c, 0xb6, 0xef, - 0x77, 0xab, 0xd1, 0xe0, 0x1c, 0xc7, 0x43, 0xd0, 0xdd, 0xd0, 0x22, 0x75, 0x95, 0x1b, - 0x92, 0x49, 0x95, 0x65, 0xce, 0x83, 0x1f, 0x30, 0x32, 0xb8, 0x50, 0x57, 0x75, 0x10, - 0x8d, 0xc8, 0x5e, 0x2a, 0xde, 0x2e, 0xac, 0x1e, 0x63, 0x6e, 0x1a, 0xf4, 0x05, 0x4c, - 0x8b, 0x6f, 0x57, 0x63, 0x2d, 0xf2, 0x69, 0xc3, 0x72, 0x3b, 0x32, 0x08, 0x72, 0xe4, - 0xc5, 0x7b, 0x21, 0x83, 0x58, 0xdc, 0x7e, 0x99, 0x05, 0xbb, 0x04, 0xed, 0xf9, 0x2e, - 0xdf, 0x0d, 0xf6, 0x35, 0xf3, 0xbf, 0x36, 0x1e, 0x57, 0xa1, 0x32, 0x96, 0xe1, 0x44, - 0x7a, 0xf5, 0xa5, 0x66, 0x65, 0x17, 0xbc, 0xd3, 0x56, 0x76, 0x21, 0xa7, 0xcf, 0x84, - 0x45, 0x58, 0x96, 0x53, 0x26, 0x20, 0x20, 0xc3, 0x3b, 0xf7, 0x80, 0x31, 0xb8, 0xee, - 0x07, 0x07, 0xde, 0x07, 0x20, 0x68, 0xc1, 0x70, 0x57, 0x03, 0x27, 0xe6, 0xd9, 0xf5, - 0xc6, 0xdd, 0xc3, 0x35, 0x40, 0x2e, 0xfc, 0x54, 0x88, 0x62, 0xf5, 0xa0, 0x70, 0x94, - 0xfd, 0x42, 0x8a, 0x7b, 0xbc, 0x15, 0xd7, 0xb3, 0x8d, 0x05, 0x36, 0x2c, 0x9c, 0xa9, - 0x85, 0xf5, 0x8a, 0x76, 0x64, 0x7d, 0x2b, 0xe4, 0xc2, 0xcd, 0x6b, 0x3d, 0x17, 0xd6, - 0x87, 0x09, 0x71, 0xd7, 0xa0, 0x98, 0xba, 0xf7, 0x2c, 0x6f, 0x6f, 0x12, 0x14, 0xcf, - 0x1f, 0xaa, 0xe4, 0x88, 0xbd, 0x7d, 0xe2, 0x59, 0xd3, 0x41, 0x5c, 0x2f, 0x0d, 0xde, - 0xc7, 0x45, 0x70, 0x04, 0xf3, 0x57, 0x08, 0xd1, 0xec, 0xcc, 0xcc, 0x0d, 0xf6, 0x5a, - 0x04, 0x94, 0x3a, 0xd5, 0xcb, 0xc1, 0x3f, 0x29, 0x5f, 0x00, 0x0f, 0xe0, 0x56, 0xc4, - 0x0b, 0x2d, 0x88, 0xf2, 0x7d, 0xc3, 0x4c, 0xfe, 0xb8, 0x03, 0xbe, 0x34, 0x83, 0xa9, - 0xeb, 0xf9, 0xb5, 0xa9, 0x02, 0x60, 0x57, 0x72, 0x5d, 0x63, 0xea, 0xd2, 0xc0, 0xc0, - 0xff, 0x1f, 0xe2, 0x6a, 0xc1, 0xe7, 0xbd, 0xfc, 0xd6, 0xfa, 0xd8, 0x75, 0x84, 0x2d, - 0x19, 0x4f, 0x33, 0x17, 0x50, 0x46, 0x2c, 0x06, 0xb8, 0xd7, 0x98, 0x2d, 0x67, 0x99, - 0x5e, 0xd5, 0xd3, 0xae, 0x96, 0xa0, 0x5a, 0xe0, 0x06, 0x7f, 0x4e, 0xb1, 0xc7, 0xc9, - 0x32, 0x31, 0xbd, 0x39, 0x77, 0x3c, 0xbe, 0x0a, 0x9d, 0x66, 0xb0, 0xc9, 0xaa, 0x8c, - 0xff, 0x6a, 0x37, 0x6e, 0x1f, 0x37, 0x2e, 0xac, 0x6a, 0xc4, 0xe4, 0x6c, 0xc0, 0x94, - 0x22, 0x45, 0xd4, 0xc2, 0xdc, 0xf0, 0x2d, 0x76, 0x40, 0xff, 0xcc, 0x5a, 0x6a, 0xc3, - 0xa8, 0x7f, 0x5c, 0x41, 0x15, 0x51, 0xbc, 0xc2, 0xf2, 0x6c, 0xb9, 0x49, 0x61, 0xd5, - 0x3f, 0x95, 0xdd, 0xb1, 0x9a, 0xe9, 0x30, 0xc8, 0xd7, 0x0f, 0x03, 0x1b, 0x29, 0xa5, - 0xdf, 0x99, 0xff, 0x36, 0x69, 0x5e, 0x80, 0x2c, 0xbc, 0xb6, 0xb1, 0xcf, 0x7d, 0xc9, - 0x7a, 0xbb, 0x3b, 0x25, 0x27, 0x64, 0xc0, 0x1a, 0x62, 0x2d, 0xfb, 0x2e, 0xcb, 0x49, - 0xce, 0x71, 0xf7, 0x38, 0x6e, 0x23, 0x89, 0x5b, 0x5a, 0xfe, 0x16, 0x61, 0x98, 0xb6, - 0x7f, 0x5b, 0x42, 0xb2, 0xf6, 0x5e, 0xcd, 0x0f, 0x82, 0x59, 0x54, 0x78, 0xd8, 0x0a, - 0xe5, 0xc8, 0xce, 0xea, 0x12, 0xa1, 0x61, 0xcc, 0xbb, 0x5e, 0xac, 0x09, 0x99, 0x0f, - 0xc6, 0x19, 0xa4, 0x60, 0x80, 0x43, 0x6d, 0xbd, 0x08, 0xd7, 0x47, 0x84, 0xaf, 0x00, - 0x2d, 0x58, 0xe0, 0x6f, 0xaf, 0x7f, 0x3c, 0xea, 0xe7, 0xd3, 0x41, 0x9b, 0x1f, 0xca, - 0x26, 0x5a, 0x55, 0x59, 0xcf, 0x9e, 0x2d, 0x3b, 0x97, 0xb2, 0xa9, 0x9a, 0x9b, 0xa5, - 0xa8, 0x66, 0x58, 0xc3, 0xfd, 0x9e, 0xc5, 0x5b, 0xfa, 0x9b, 0x32, 0x85, 0x67, 0x25, - 0x4a, 0xb3, 0x6d, 0x2c, 0x7f, 0x44, 0xd2, 0xc7, 0xe1, 0x3e, 0xb5, 0x4b, 0xeb, 0x70, - 0xea, 0x8f, 0xa9, 0x4b, 0x6c, 0x6e, 0x01, 0x2d, 0x79, 0xe3, 0xf5, 0x36, 0x89, 0xc2, - 0xb1, 0xa1, 0x8e, 0xaf, 0x2d, 0x47, 0x1d, 0x13, 0xc1, 0xab, 0x39, 0xd9, 0x19, 0x4a, - 0xe8, 0x43, 0xab, 0x1d, 0x28, 0xff, 0xa8, 0xf6, 0x9d, 0xc7, 0xe1, 0x5c, 0xc3, 0x8b, - 0x12, 0xe8, 0xfc, 0xd7, 0x92, 0x55, 0xb7, 0x21, 0x60, 0x56, 0xd9, 0xed, 0xb7, 0x48, - 0x2f, 0xb9, 0x8a, 0xa0, 0x33, 0xb6, 0x5e, 0x51, 0xc1, 0xa0, 0x8b, 0x8a, 0x11, 0xd8, - 0x4d, 0x04, 0x09, 0xb7, 0x34, 0xf4, 0x52, 0xaa, 0xf0, 0xd6, 0xb1, 0x8f, 0x50, 0x25, - 0x86, 0x83, 0xd3, 0xf9, 0xa7, 0x6d, 0x39, 0x9f, 0xd0, 0x47, 0xee, 0xe2, 0x88, 0xbb, - 0x45, 0x85, 0x85, 0x1d, 0xc9, 0x3e, 0xcc, 0xc6, 0x23, 0x22, 0x92, 0x4c, 0xd1, 0x3b, - 0x5d, 0xd4, 0xee, 0xd6, 0x6e, 0xd8, 0xd9, 0x97, 0x2d, 0x77, 0x26, 0x29, 0xea, 0x64, - 0x74, 0x2e, 0x54, 0x73, 0x39, 0x81, 0xb0, 0x06, 0xc0, 0x62, 0x46, 0x8e, 0x4b, 0xd8, - 0xf7, 0xdd, 0x9a, 0xf6, 0x98, 0xf5, 0x2a, 0xe8, 0x14, 0x63, 0x4e, 0x81, 0xd7, 0xf3, - 0xe0, 0xc4, 0x20, 0x31, 0x7c, 0xac, 0xa9, 0xae, 0x48, 0x11, 0xc6, 0xaf, 0x06, 0xfe, - 0x80, 0xa8, 0xc0, 0x2a, 0xb7, 0xa0, 0x0e, 0x18, 0xe4, 0xa6, 0xaa, 0x1e, 0xa1, 0xb7, - 0x69, 0x45, 0xd2, 0x61, 0x5d, 0x43, 0xac, 0x11, 0x8b, 0x56, 0xc2, 0xf2, 0x96, 0x0f, - 0xe9, 0x3a, 0x02, 0x5f, 0x13, 0xec, 0x91, 0xff, 0xc6, 0xd2, 0xc3, 0x53, 0x69, 0x9a, - 0xbb, 0x09, 0x2d, 0xed, 0xc0, 0x65, 0xdb, 0x8f, 0xa2, 0x14, 0xdb, 0xc4, 0x64, 0x66, - 0xf8, 0x97, 0xb8, 0x8c, 0x58, 0xb3, 0x01, 0x52, 0x13, 0x3a, 0xa3, 0x83, 0x1a, 0xf3, - 0x7c, 0x74, 0xd9, 0x9e, 0x9e, 0x36, 0xff, 0x70, 0x11, 0xd3, 0x23, 0x83, 0x05, 0x69, - 0x15, 0x08, 0xd0, 0xf1, 0xf6, 0xaa, 0xaa, 0xa4, 0x25, 0x12, 0x30, 0xc6, 0xcc, 0xc4, - 0x66, 0x68, 0xbb, 0xcf, 0x35, 0xe5, 0xa5, 0xef, 0x2f, 0x86, 0xe6, 0x65, 0xd8, 0xcf, - 0xac, 0x74, 0x76, 0xec, 0xb2, 0x43, 0x78, 0x79, 0x6a, 0x8e, 0xf2, 0xe4, 0xd9, 0x4d, - 0x43, 0x58, 0xbe, 0x2b, 0x47, 0x5f, 0xcc, 0x92, 0xdf, 0x93, 0x82, 0xc5, 0xc0, 0x69, - 0x19, 0xa0, 0xd6, 0x31, 0xec, 0x26, 0x10, 0xfe, 0xdc, 0x21, 0x9b, 0xe6, 0x3f, 0x37, - 0xf2, 0xba, 0x0d, 0x43, 0x23, 0x66, 0x73, 0x6d, 0x86, 0x32, 0xfc, 0xe0, 0x72, 0xb6, - 0xae, 0x5b, 0x6f, 0x3f, 0xd5, 0x9d, 0x3f, 0xaf, 0xf6, 0x38, 0x27, 0x5a, 0x99, 0x2f, - 0xef, 0xc8, 0x7e, 0x60, 0xd4, 0x4c, 0x2c, 0xad, 0xc2, 0xb5, 0xc4, 0x94, 0xe3, 0xe7, - 0x2e, 0xb4, 0x59, 0x7c, 0x96, 0xb4, 0x01, 0x67, 0x79, 0x9a, 0x90, 0x01, 0xa2, 0xed, - 0x36, 0x76, 0xa8, 0xb4, 0x03, 0xae, 0x25, 0xff, 0xd7, 0x72, 0xf7, 0x08, 0x1e, 0x9a, - 0x32, 0xbc, 0xc1, 0xc5, 0xe2, 0xed, 0xd4, 0xe2, 0xa6, 0x57, 0x6b, 0x78, 0x3c, 0xce, - 0x3a, 0xae, 0x11, 0xfa, 0x43, 0x22, 0x62, 0x54, 0x88, 0x56, 0x18, 0x3e, 0xe6, 0x82, - 0xd5, 0xdc, 0x31, 0xbe, 0xb3, 0x8f, 0x06, 0x1c, 0xbd, 0xec, 0xa7, 0x02, 0x1a, 0x44, - 0x4e, 0x2d, 0xd4, 0x17, 0xdf, 0x26, 0xdc, 0xd2, 0x20, 0xf2, 0xb7, 0x31, 0x77, 0x2b, - 0x43, 0x9e, 0x96, 0xd6, 0x14, 0xe1, 0xfa, 0xcb, 0x48, 0x6c, 0x7a, 0x7d, 0x51, 0x71, - 0xb1, 0xde, 0x35, 0x9f, 0x6a, 0xd3, 0xa9, 0x6f, 0x64, 0x9c, 0x96, 0x91, 0x02, 0xa1, - 0x96, 0x4f, 0xb4, 0xb4, 0xa1, 0xa4, 0x27, 0x9c, 0x68, 0xe6, 0xc3, 0x72, 0xe4, 0x21, - 0x87, 0xd7, 0x54, 0xe8, 0x04, 0xa6, 0x16, 0x53, 0x09, 0x20, 0x69, 0xfb, 0x9b, 0x6d, - 0x25, 0x26, 0x68, 0x90, 0x80, 0x8b, 0x01, 0x5d, 0xf2, 0x8c, 0x80, 0x10, 0x65, 0xda, - 0x6f, 0xeb, 0xdc, 0x1a, 0x56, 0xbf, 0xd0, 0x02, 0x62, 0x5a, 0xcf, 0xaa, 0x53, 0x73, - 0xfd, 0xe1, 0x49, 0xc1, 0xcf, 0xc3, 0x64, 0x9b, 0x48, 0x69, 0x69, 0x6d, 0x44, 0xec, - 0xb1, 0x24, 0x79, 0xc5, 0xeb, 0xef, 0x99, 0x5f, 0x10, 0x02, 0x9f, 0x8b, 0x53, 0x0e, - 0xeb, 0x3f, 0xdc, 0x2e, 0x50, 0xe8, 0x75, 0x7f, 0xc0, 0xbb, 0x9e, 0x26, 0x30, 0x23, - 0xdb, 0x82, 0xf8, 0x78, 0xd9, 0xac, 0x7f, 0xfb, 0x0b, 0xd4, 0x39, 0x1d, 0xf1, 0xd8, - 0x79, 0x89, 0x9a, 0x3e, 0xf5, 0x7b, 0xfd, 0x0d, 0x1f, 0x77, 0x55, 0x64, 0x8e, 0xdd, - 0x85, 0xbb, 0x05, 0x2a, 0x6e, 0xdf, 0x71, 0xcd, 0x26, 0x28, 0xc9, 0x87, 0x42, 0x9f, - 0x36, 0xdc, 0x50, 0x5c, 0xcc, 0x43, 0xf3, 0x0e, 0x7a, 0x86, 0x9c, 0x9e, 0x25, 0x5e, - 0x2a, 0xf9, 0xfc, 0xf3, 0x0c, 0x12, 0x17, 0x96, 0x03, 0xae, 0x17, 0x57, 0x55, 0x3b, - 0x5c, 0x94, 0x60, 0x7e, 0x00, 0xd0, 0x32, 0xfb, 0xbe, 0xd2, 0x3c, 0x4c, 0xba, 0xbf, - 0x74, 0x1d, 0x68, 0xaa, 0xb3, 0x0e, 0x0b, 0x8f, 0x15, 0xf4, 0x44, 0xd5, 0x86, 0xb3, - 0xe7, 0xe6, 0x15, 0x9c, 0x46, 0x69, 0x9f, 0x10, 0x07, 0x92, 0xd4, 0x67, 0x29, 0x50, - 0x34, 0x8a, 0x90, 0x55, 0x2e, 0x45, 0x94, 0x3b, 0xee, 0xac, 0xf0, 0x3f, 0x32, 0x16, - 0xf9, 0x4e, 0x27, 0x90, 0x6e, 0xdc, 0x63, 0x23, 0x19, 0xad, 0x8d, 0x37, 0x44, 0x7f, - 0x5c, 0x59, 0xcc, 0xde, 0x35, 0x4f, 0x99, 0xff, 0x6c, 0x7a, 0x76, 0x23, 0xf6, 0xd4, - 0x15, 0x25, 0xa8, 0x09, 0xce, 0x2f, 0x41, 0xec, 0x0f, 0xf7, 0xf1, 0xaf, 0x81, 0xb2, - 0x4c, 0xed, 0x0e, 0xfa, 0x62, 0x13, 0xda, 0x6c, 0x7c, 0x60, 0xc4, 0x87, 0xf5, 0xf7, - 0xb0, 0x3f, 0x81, 0x60, 0xa0, 0x57, 0xf4, 0x6d, 0x05, 0xbf, 0x82, 0x18, 0xb3, 0xad, - 0xd9, 0xc0, 0x68, 0x93, 0xbd, 0x02, 0xdb, 0x9b, 0x61, 0x19, 0x1d, 0xfb, 0x13, 0x3b, - 0xfa, 0xbe, 0x48, 0x58, 0xe4, 0x7a, 0x4c, 0xc3, 0x2e, 0x41, 0x6e, 0xc0, 0x8b, 0x8a, - 0xc7, 0x91, 0x5a, 0x43, 0x73, 0x3f, 0x44, 0x06, 0xe9, 0xd9, 0x67, 0xc5, 0x60, 0xf3, - 0x44, 0xd7, 0xe9, 0x04, 0xa2, 0x80, 0x45, 0xd9, 0x9f, 0x3a, 0xf8, 0xc8, 0x2e, 0x97, - 0xe1, 0xb9, 0xc1, 0xb2, 0x05, 0xe5, 0x85, 0xfb, 0xeb, 0xb4, 0x8f, 0xaf, 0x58, 0xf1, - 0xb6, 0x5d, 0xca, 0x24, 0x97, 0xe0, 0x9a, 0x70, 0xaa, 0xd4, 0x86, 0x5f, 0x85, 0x71, - 0x5a, 0x28, 0x0e, 0x18, 0x6f, 0x3f, 0xc1, 0x74, 0x0d, 0x81, 0x84, 0xd3, 0x3e, 0x83, - 0x22, 0x16, 0x95, 0x21, 0xcd, 0xc1, 0x32, 0x21, 0x29, 0x39, 0xc8, 0x4a, 0x10, 0x89, - 0x64, 0xe2, 0xde, 0x74, 0xb6, 0xea, 0x55, 0xb4, 0xcb, 0x8f, 0x6f, 0x9b, 0xee, 0x98, - 0xb1, 0x0d, 0x41, 0x51, 0x09, 0x45, 0x5f, 0x48, 0xb7, 0x76, 0x08, 0x2d, 0xc3, 0x0b, - 0x4b, 0xc7, 0x34, 0x77, 0x07, 0x55, 0x11, 0x70, 0x03, 0x08, 0x15, 0x8c, 0xe2, 0xf2, - 0xf9, 0xbf, 0x0f, 0x69, 0x1b, 0x2c, 0xe5, 0x3e, 0x61, 0x14, 0x2c, 0xb7, 0x40, 0xc1, - 0x5b, 0x7b, 0x62, 0x3c, 0xf4, 0x8b, 0x3f, 0x7b, 0xfe, 0xfa, 0x31, 0xbc, 0xdc, 0x66, - 0x5c, 0x6d, 0x71, 0x23, 0xe9, 0x53, 0x50, 0x81, 0x13, 0x75, 0x94, 0x7b, 0x05, 0x5a, - 0x43, 0xdb, 0x07, 0xe0, 0x3f, 0x33, 0x62, 0x7d, 0xf5, 0xc6, 0x38, 0xbf, 0xad, 0x95, - 0x6d, 0xdc, 0x1e, 0xa7, 0xd7, 0x62, 0x0a, 0x20, 0xf2, 0x79, 0x2f, 0x63, 0x81, 0x7a, - 0x1c, 0xf3, 0x25, 0x80, 0xd0, 0x42, 0x74, 0x23, 0x4a, 0xf2, 0xa5, 0x1b, 0x56, 0xbb, - 0x68, 0xa2, 0x9e, 0x43, 0xa9, 0x54, 0x14, 0x2b, 0xa4, 0xca, 0x68, 0x23, 0xbd, 0xe9, - 0x05, 0x3d, 0x72, 0xfd, 0xad, 0xbc, 0x61, 0xad, 0x59, 0x36, 0xc5, 0x3f, 0xdd, 0x75, - 0x79, 0x44, 0x6d, 0x11, 0xc4, 0x46, 0x07, 0xf4, 0x16, 0x30, 0xe4, 0xc0, 0x89, 0x15, - 0xe6, 0x31, 0x77, 0x15, 0x50, 0xe9, 0xce, 0x1f, 0xca, 0x2c, 0x63, 0xfe, 0x06, 0xb7, - 0x98, 0x9d, 0x58, 0x4f, 0xa7, 0xd7, 0x82, 0xa8, 0x8c, 0x1e, 0x7d, 0x64, 0xb6, 0xfb, - 0xf5, 0x5e, 0x35, 0x96, 0xaf, 0x9b, 0xcb, 0x75, 0x85, 0xf8, 0xc7, 0xd3, 0xaa, 0x5c, - 0x20, 0x82, 0xb2, 0x65, 0x24, 0x9d, 0xf0, 0x57, 0x01, 0xda, 0xb0, 0x31, 0xc4, 0xba, - 0xc1, 0xea, 0x26, 0x7a, 0x29, 0x96, 0xa2, 0x02, 0x8d, 0x1e, 0x6a, 0x0f, 0x80, 0xa3, - 0x84, 0x7c, 0x53, 0x1d, 0xba, 0x96, 0xee, 0x65, 0xa2, 0x41, 0x89, 0xbd, 0x27, 0x12, - 0xe4, 0x0e, 0x95, 0x96, 0x64, 0x98, 0x1e, 0x58, 0xb2, 0xa4, 0xf9, 0x51, 0xef, 0x8f, - 0x49, 0x7d, 0xff, 0xf2, 0xf2, 0xf2, 0x71, 0xea, 0xb8, 0x9c, 0x62, 0x8e, 0x18, 0xb5, - 0xfc, 0xb4, 0x38, 0x82, 0x53, 0x7e, 0xaf, 0x6a, 0xd2, 0xa6, 0xb1, 0x75, 0x46, 0x33, - 0xca, 0xa8, 0x6b, 0xf2, 0xc7, 0x6f, 0x39, 0x93, 0x15, 0x4f, 0xc7, 0x3e, 0x6f, 0xbb, - 0xa2, 0x21, 0x0c, 0x27, 0x43, 0xf5, 0x30, 0xa4, 0x27, 0x84, 0x9a, 0x30, 0x1e, 0x00, - 0xe0, 0x11, 0x29, 0xf0, 0x3a, 0x46, 0x07, 0xf8, 0x7c, 0xbe, 0x07, 0x62, 0xc0, 0xb1, - 0xc6, 0x58, 0x55, 0xde, 0xba, 0x84, 0x22, 0xca, 0x4b, 0x88, 0xab, 0xee, 0xa6, 0xa4, - 0x38, 0x2c, 0xf1, 0x6c, 0xcd, 0x6d, 0xc7, 0xc3, 0x7c, 0x44, 0xe5, 0x49, 0xc4, 0x53, - 0x48, 0x19, 0xac, 0xd8, 0xbb, 0x0a, 0x02, 0xa5, 0xfa, 0x7a, 0x1c, 0x1d, 0x38, 0x06, - 0xfb, 0xc3, 0x40, 0x7f, 0xd7, 0xda, 0x93, 0xfd, 0x0d, 0xe6, 0x40, 0x0d, 0x3a, 0xb8, - 0x97, 0x74, 0x85, 0xcd, 0xdf, 0xbe, 0xd5, 0x93, 0x2f, 0x50, 0x7b, 0x79, 0x94, 0x7a, - 0xdb, 0x2f, 0xad, 0x37, 0x61, 0x5a, 0xa7, 0x17, 0xdb, 0x5f, 0x29, 0x80, 0x99, 0xf2, - 0x0f, 0x26, 0x3b, 0x35, 0x9a, 0x11, 0x51, 0xa6, 0xb7, 0x5c, 0x01, 0x36, 0x5e, 0xb1, - 0x54, 0xae, 0x42, 0x14, 0x0d, 0x6e, 0x10, 0x34, 0x2f, 0x14, 0xf3, 0x4d, 0xc3, 0x3e, - 0x07, 0xff, 0x0e, 0x4d, 0x1a, 0x6b, 0xe3, 0x75, 0xb3, 0x2f, 0x84, 0xb9, 0x2e, 0x5d, - 0x81, 0xeb, 0xb6, 0x39, 0xc4, 0xf2, 0x7e, 0x71, 0x5a, 0xa4, 0x2c, 0xc7, 0x57, 0x07, - 0xd4, 0xeb, 0xd1, 0xbb, 0xfb, 0xe8, 0xf9, 0x0f, 0xc7, 0xc9, 0x53, 0xe7, 0xa9, 0x71, - 0x5e, 0x65, 0xaf, 0x82, 0x67, 0x37, 0x3d, 0x34, 0x51, 0x67, 0x4f, 0xf0, 0x84, 0xef, - 0xd9, 0x2c, 0xcf, 0x3b, 0xcc, 0x7a, 0xca, 0x14, 0x67, 0xb6, 0x32, 0x7e, 0x4f, 0x95, - 0x22, 0xb2, 0xcc, 0x57, 0x9a, 0x7a, 0x8f, 0xff, 0x7c, 0xa7, 0xcf, 0x14, 0x5d, 0xfc, - 0x13, 0xea, 0xfc, 0x34, 0x15, 0x3b, 0x2c, 0x3e, 0x8a, 0xfb, 0xe5, 0x34, 0x44, 0xd0, - 0xc7, 0x3b, 0x3b, 0xd5, 0xbc, 0x87, 0x0b, 0x01, 0xcd, 0x45, 0x79, 0x11, 0xe3, 0x56, - 0x31, 0x3f, 0xd1, 0xda, 0xfb, 0x4c, 0x81, 0x51, 0x63, 0x4a, 0x01, 0xaf, 0xf7, 0xcf, - 0x11, 0x6d, 0x43, 0x3c, 0x3d, 0x2b, 0x3a, 0xdd, 0xa9, 0xce, 0xbe, 0x18, 0xf7, 0xd1, - 0x72, 0x44, 0x3e, 0x5e, 0x7b, 0x5a, 0xc9, 0xab, 0xe8, 0xdb, 0x22, 0x56, 0xd7, 0xeb, - 0xe2, 0xff, 0x28, 0x02, 0x09, 0x39, 0x50, 0x38, 0x70, 0x59, 0x7b, 0x9a, 0x95, 0x58, - 0x92, 0xc7, 0x38, 0x96, 0x50, 0xa2, 0xd4, 0x2e, 0xc9, 0x2b, 0xe7, 0x23, 0xfe, 0xdf, - 0x2f, 0x2e, 0xde, 0x5a, 0x47, 0x2a, 0xa1, 0xe7, 0x4f, 0x33, 0xad, 0x41, 0x90, 0x15, - 0x44, 0xed, 0xbb, 0xe3, 0xac, 0x46, 0x4c, 0xf4, 0x39, 0x19, 0x60, 0x15, 0xf4, 0xf2, - 0x2a, 0xc2, 0xb8, 0xfc, 0x01, 0x49, 0x6b, 0xea, 0xb4, 0xd4, 0x59, 0x07, 0xf4, 0x79, - 0x81, 0x2a, 0x25, 0x94, 0x31, 0xa2, 0xcb, 0xc9, 0x3d, 0x4f, 0x3b, 0x84, 0xe4, 0xdd, - 0x36, 0x60, 0x20, 0x27, 0x3a, 0x67, 0x52, 0xe5, 0x01, 0xaf, 0x6f, 0xf1, 0xb7, 0x8d, - 0xdc, 0x81, 0x7e, 0x6e, 0xa3, 0xe5, 0x37, 0x5c, 0xa3, 0xfe, 0x2f, 0xb1, 0xd1, 0xa9, - 0x37, 0x15, 0xdf, 0xf9, 0x29, 0x93, 0xcc, 0xc6, 0x50, 0x4f, 0x64, 0xfc, 0xbf, 0x22, - 0x17, 0x30, 0xd9, 0xef, 0xf4, 0xf3, 0x27, 0xe0, 0xad, 0x37, 0x4f, 0x59, 0x56, 0x45, - 0x37, 0x48, 0x75, 0x5b, 0x43, 0xc8, 0xf2, 0x9d, 0x67, 0x52, 0x6f, 0x60, 0xa6, 0x18, - 0xb7, 0x33, 0x24, 0xd2, 0x24, 0x33, 0x72, 0x92, 0x1b, 0x99, 0xe3, 0xdf, 0x36, 0x85, - 0x0c, 0x60, 0xd5, 0xd9, 0x34, 0x3a, 0x48, 0x70, 0xa0, 0xe7, 0x52, 0x8c, 0x65, 0x13, - 0xc2, 0x7c, 0x56, 0x43, 0x90, 0x93, 0xf9, 0x33, 0x68, 0x1d, 0x93, 0xa4, 0xd4, 0xbc, - 0xee, 0xac, 0x2b, 0x10, 0x8c, 0x6c, 0x6f, 0xae, 0x35, 0x9f, 0x64, 0x5c, 0x27, 0x68, - 0x91, 0xc0, 0xdc, 0xab, 0x3f, 0xaf, 0x18, 0x77, 0x00, 0xc0, 0x82, 0xdc, 0x47, 0x77, - 0x40, 0xfb, 0x3f, 0x2c, 0xd7, 0xbb, 0x59, 0xfb, 0x35, 0x85, 0x54, 0xe9, 0x4c, 0x7e, - 0x67, 0x8c, 0xe0, 0x1a, 0xeb, 0xf9, 0x4e, 0x51, 0x5e, 0x49, 0x72, 0x29, 0x67, 0x99, - 0x5a, 0xea, 0x85, 0x8d, 0x64, 0xe7, 0x78, 0x9f, 0xf3, 0x06, 0x36, 0x95, 0x77, 0x22, - 0x81, 0x80, 0x32, 0x6a, 0x5b, 0x0a, 0xf4, 0x75, 0xe2, 0x7a, 0x54, 0xb2, 0x07, 0xb4, - 0x1f, 0x92, 0xe3, 0x76, 0x17, 0x0e, 0x3f, 0xb0, 0x05, 0x02, 0x82, 0x61, 0xc9, 0x9c, - 0x2d, 0xbd, 0x0e, 0xed, 0xee, 0x87, 0x1c, 0x1c, 0x0f, 0x48, 0xb8, 0xe9, 0xb8, 0xe4, - 0xbe, 0x77, 0xd1, 0xb7, 0x37, 0xfe, 0x21, 0xf0, 0xfa, 0x5a, 0x18, 0xeb, 0xb5, 0x27, - 0x55, 0xb5, 0xa6, 0xcf, 0x61, 0x30, 0xfb, 0x56, 0x94, 0x4c, 0xfa, 0xb8, 0x75, 0x27, - 0xc2, 0x50, 0xd1, 0x13, 0xb2, 0x9b, 0xca, 0xc9, 0xaa, 0xa1, 0x0c, 0x2e, 0x7d, 0xe4, - 0x15, 0xed, 0xb0, 0x80, 0x6c, 0x6d, 0xa0, 0x30, 0x20, 0xa1, 0x34, 0xca, 0x7e, 0xcd, - 0xc8, 0xda, 0x1b, 0xd5, 0x7a, 0x37, 0xf5, 0x5a, 0x46, 0x94, 0x0b, 0x45, 0xb2, 0x41, - 0xb1, 0xc1, 0x6e, 0xe1, 0x00, 0x92, 0x7d, 0x1b, 0xd8, 0x60, 0xd4, 0x45, 0xa9, 0xde, - 0x50, 0xd4, 0xc3, 0x84, 0xd6, 0xe1, 0xd0, 0x01, 0x08, 0x02, 0x6c, 0x0e, 0xa5, 0xeb, - 0xbf, 0x0b, 0x72, 0xfb, 0xf5, 0xc3, 0x70, 0xbc, 0xe1, 0x8d, 0x3a, 0xcb, 0xc4, 0x65, - 0x99, 0x09, 0x9b, 0xaa, 0xe1, 0xd8, 0x02, 0xf7, 0x73, 0x33, 0x49, 0x4a, 0x7a, 0xe1, - 0x30, 0xfe, 0x86, 0xe8, 0xf8, 0x18, 0xf9, 0x26, 0x1a, 0x2d, 0xad, 0xb4, 0x12, 0x52, - 0x29, 0xba, 0x0f, 0xfc, 0x0e, 0x70, 0x90, 0x32, 0x44, 0x30, 0xb5, 0x21, 0xa9, 0x0d, - 0x22, 0x4a, 0xb7, 0xa1, 0x02, 0x4e, 0x1d, 0x89, 0x3e, 0x74, 0x04, 0xfe, 0xdb, 0x34, - 0x8e, 0x4d, 0x5e, 0x22, 0x35, 0xc5, 0x9a, 0x78, 0x76, 0xa0, 0xfc, 0x60, 0x14, 0x5c, - 0x6a, 0x00, 0x96, 0x87, 0x68, 0x44, 0x60, 0x27, 0x1e, 0xe1, 0x33, 0xa4, 0x37, 0xfe, - 0x52, 0xfb, 0x6c, 0xfb, 0xa9, 0x7f, 0xce, 0xc1, 0x61, 0xdf, 0x51, 0x5d, 0xde, 0x90, - 0x5a, 0x24, 0xda, 0x6d, 0x37, 0xbd, 0xc3, 0x40, 0x44, 0xa9, 0x55, 0xe6, 0x82, 0xb4, - 0x74, 0x71, 0xca, 0x1e, 0x8c, 0x78, 0xc5, 0x1e, 0xd3, 0x77, 0xcd, 0x4a, 0xfa, 0x89, - 0x4b, 0xd9, 0xbd, 0x12, 0xe7, 0x07, 0x15, 0x6d, 0xa0, 0x72, 0x6f, 0x7c, 0xf5, 0x72, - 0x9f, 0xab, 0xe3, 0x72, 0x16, 0x04, 0x63, 0xfe, 0x04, 0x29, 0x24, 0x4d, 0x06, 0x74, - 0x89, 0xba, 0x5d, 0x09, 0x47, 0x2e, 0xcd, 0x9b, 0xcd, 0xc4, 0xd5, 0xe4, 0xdf, 0x10, - 0x1e, 0x18, 0x9d, 0xb8, 0x46, 0x3e, 0xb5, 0x38, 0x30, 0x7b, 0x58, 0x7d, 0xef, 0xf7, - 0x8d, 0xe9, 0xc7, 0x3a, 0xf2, 0x80, 0x80, 0xb2, 0xfd, 0x05, 0x00, 0x3e, 0x11, 0xd3, - 0xe1, 0xb3, 0x29, 0x9d, 0xc9, 0x52, 0x1f, 0x8b, 0x51, 0x3b, 0xad, 0xb0, 0x10, 0xe9, - 0x1b, 0xfe, 0xb9, 0x1b, 0x0b, 0x2a, 0x6c, 0xb1, 0x29, 0xc2, 0xe8, 0x25, 0xa5, 0x97, - 0xb8, 0xfb, 0x75, 0xbc, 0x56, 0x2d, 0x65, 0x4d, 0x62, 0x10, 0x46, 0x40, 0xdd, 0x74, - 0xe5, 0x6c, 0xd1, 0x4b, 0xaa, 0xba, 0x56, 0x5b, 0x84, 0xb8, 0x45, 0xe1, 0x63, 0xd1, - 0xca, 0xef, 0x25, 0x33, 0xc3, 0x98, 0x16, 0x37, 0x20, 0x4f, 0x96, 0xa5, 0x9c, 0x8e, - 0x80, 0x24, 0xd9, 0x04, 0x1b, 0x20, 0x29, 0xe9, 0x4c, 0x15, 0x24, 0x5f, 0x1a, 0x95, - 0x88, 0x40, 0xba, 0x3f, 0x38, 0x0a, 0x4d, 0x20, 0xf1, 0x18, 0x4e, 0x77, 0x82, 0x7d, - 0xe3, 0xff, 0x8f, 0x3d, 0x73, 0x45, 0x9a, 0xfe, 0x24, 0x1f, 0x72, 0x3c, 0x08, 0x48, - 0x23, 0x23, 0x0e, 0x00, 0x3d, 0x3d, 0x21, 0xe5, 0x35, 0x01, 0xec, 0x04, 0x99, 0xb0, - 0x83, 0xa7, 0xda, 0xd6, 0x85, 0xc5, 0x71, 0x27, 0xf4, 0xde, 0x64, 0x73, 0x3a, 0x88, - 0x0c, 0x2d, 0xb2, 0x8f, 0xda, 0xab, 0xf1, 0xb5, 0x42, 0xd2, 0x05, 0xf6, 0x64, 0xa3, - 0x51, 0x35, 0x71, 0x27, 0x11, 0xdc, 0xcc, 0xd9, 0x31, 0xa5, 0x0b, 0x9c, 0x56, 0x61, - 0x88, 0x23, 0x60, 0xd4, 0xca, 0xc0, 0x04, 0x76, 0x81, 0xbc, 0x2e, 0x2b, 0x3b, 0xf6, - 0xc9, 0x97, 0x60, 0xd7, 0xcf, 0xb4, 0xfa, 0x21, 0x39, 0x43, 0x77, 0xa4, 0x55, 0x1c, - 0x76, 0xd1, 0xf7, 0x5a, 0xc0, 0x3c, 0x26, 0x20, 0x54, 0xdf, 0xfd, 0x79, 0xa9, 0xde, - 0xd0, 0x5e, 0x88, 0x89, 0x58, 0x19, 0x9e, 0xea, 0x45, 0x01, 0xe2, 0x99, 0x0a, 0x53, - 0xa5, 0xcd, 0x2a, 0x46, 0xa4, 0x01, 0x57, 0x65, 0x88, 0xfd, 0x7d, 0x05, 0x8a, 0x26, - 0xf2, 0x84, 0x38, 0xe5, 0x78, 0x2f, 0x45, 0xac, 0x1d, 0x07, 0xf6, 0xf6, 0xf5, 0xed, - 0x73, 0x74, 0x1d, 0x57, 0x85, 0x83, 0x7a, 0x6b, 0x84, 0x4b, 0x47, 0x47, 0x75, 0x71, - 0x8c, 0x29, 0xdd, 0x99, 0x08, 0x4e, 0x9f, 0x88, 0xef, 0x15, 0x3a, 0x83, 0x29, 0xf5, - 0x32, 0xa6, 0x90, 0x17, 0xdc, 0x3a, 0x97, 0xed, 0x75, 0x43, 0x67, 0x72, 0x30, 0x98, - 0xe5, 0x76, 0x58, 0x40, 0xb0, 0x22, 0x89, 0x72, 0x44, 0x74, 0x5f, 0xbb, 0xbb, 0x30, - 0xa7, 0xcb, 0x54, 0xfa, 0x05, 0x11, 0x16, 0x6e, 0x95, 0x44, 0x12, 0x20, 0x00, 0x61, - 0x0b, 0xd2, 0xaa, 0xcb, 0xd8, 0x23, 0x25, 0xa5, 0x9b, 0x95, 0x15, 0x4e, 0xcd, 0x82, - 0xc8, 0x8d, 0x23, 0xab, 0xd1, 0xe2, 0x07, 0x70, 0xff, 0xb8, 0xaa, 0xbf, 0x83, 0xfc, - 0x07, 0x34, 0x96, 0x4c, 0xcd, 0x41, 0x1d, 0x1c, 0x93, 0x57, 0x14, 0xe2, 0x4a, 0xab, - 0x56, 0x6f, 0x4f, 0x08, 0x42, 0x40, 0x14, 0xc4, 0xec, 0xa9, 0x1b, 0x59, 0x0f, 0x08, - 0x2b, 0x47, 0x3f, 0x36, 0x1c, 0x87, 0x41, 0x5d, 0x37, 0xbd, 0x20, 0xd7, 0x0f, 0xd0, - 0xb5, 0x2b, 0x6d, 0xdf, 0x18, 0x65, 0xf7, 0x66, 0x70, 0x2e, 0x32, 0xb0, 0x5b, 0x3c, - 0xf1, 0x63, 0x0e, 0xe8, 0x59, 0x7a, 0xae, 0x19, 0x63, 0x3f, 0x35, 0x16, 0xa8, 0x55, - 0x5a, 0xc5, 0xbe, 0x32, 0xc6, 0x75, 0xbe, 0x18, 0x17, 0xef, 0xbf, 0xfd, 0x93, 0x69, - 0x04, 0xbd, 0x73, 0x4d, 0x97, 0x23, 0x3a, 0xaa, 0x38, 0x3b, 0x41, 0xba, 0x6d, 0x27, - 0xf6, 0x42, 0x84, 0x7d, 0x1e, 0xda, 0xcb, 0x4b, 0xf8, 0x22, 0xe6, 0x70, 0x80, 0x86, - 0x75, 0x18, 0xae, 0x5a, 0x8f, 0x0a, 0x43, 0xe6, 0xed, 0x53, 0x0c, 0xb2, 0xe8, 0xae, - 0x83, 0x88, 0x60, 0xad, 0xc8, 0x8a, 0xac, 0xc7, 0xbd, 0x6a, 0x00, 0xae, 0x0c, 0x19, - 0xff, 0x45, 0x33, 0xa4, 0x85, 0xef, 0xde, 0x08, 0x2b, 0xc5, 0x21, 0x40, 0x18, 0x2b, - 0x23, 0x4d, 0x1a, 0x0d, 0x0e, 0xeb, 0xdf, 0xb9, 0x87, 0x75, 0x98, 0xe0, 0x34, 0x7f, - 0xb1, 0x00, 0x1e, 0x15, 0xb5, 0xd4, 0x44, 0x6e, 0x76, 0x6c, 0xde, 0x25, 0xef, 0x79, - 0x87, 0x40, 0xe0, 0xbd, 0xf9, 0x94, 0xd9, 0x73, 0x9b, 0xbe, 0x55, 0x38, 0xa0, 0xae, - 0x0f, 0x07, 0x6c, 0x58, 0x2c, 0x0f, 0x5b, 0xa8, 0x78, 0xb9, 0x9b, 0x82, 0x49, 0xdb, - 0x1d, 0x7e, 0x95, 0x05, 0x6c, 0x98, 0xaf, 0x08, 0x3d, 0x98, 0xcb, 0x0e, 0xd9, 0xe3, - 0xf7, 0x43, 0x6e, 0x1c, 0x76, 0x43, 0x76, 0x6f, 0x96, 0x6b, 0x83, 0xe9, 0x99, 0x20, - 0x6e, 0xbd, 0x13, 0x93, 0xb9, 0xb2, 0xa7, 0xf4, 0x14, 0x48, 0x0f, 0xa0, 0x17, 0x48, - 0x00, 0x69, 0xf8, 0x5c, 0x77, 0x49, 0xc4, 0x35, 0xae, 0x2f, 0xba, 0x2d, 0xdc, 0x10, - 0x38, 0xd5, 0x47, 0xd8, 0x48, 0x54, 0x81, 0x7e, 0xf3, 0x96, 0x35, 0xc2, 0x98, 0x27, - 0xaa, 0xd8, 0x67, 0x26, 0xc9, 0xad, 0xe3, 0xb2, 0x65, 0xb9, 0x08, 0x6c, 0x8b, 0x5b, - 0x75, 0xef, 0x56, 0xfe, 0x4b, 0xd8, 0xb4, 0xd6, 0x28, 0x93, 0x89, 0x5b, 0x3f, 0xd2, - 0x73, 0x4f, 0xda, 0xc4, 0x64, 0x15, 0x6d, 0x7e, 0x5e, 0xbc, 0x7e, 0xcf, 0x1d, 0x83, - 0xb8, 0x6f, 0x65, 0x96, 0x37, 0xe3, 0xb1, 0x42, 0xc1, 0x64, 0x96, 0x3b, 0x8c, 0xdc, - 0xf4, 0xba, 0x4f, 0x40, 0x35, 0xdf, 0xfc, 0x5a, 0x78, 0x94, 0x58, 0x84, 0x77, 0x81, - 0x91, 0x8a, 0xc7, 0x2f, 0xc1, 0x8b, 0xbb, 0xf5, 0x11, 0x00, 0x32, 0xe6, 0x6d, 0x75, - 0xb3, 0x17, 0x1e, 0xf4, 0xb5, 0x13, 0x29, 0x01, 0x64, 0xa7, 0x7b, 0x42, 0xb0, 0xa4, - 0xcf, 0xb8, 0x96, 0x39, 0xab, 0x23, 0x84, 0x5e, 0x1a, 0xa2, 0xa4, 0x52, 0xf3, 0x73, - 0x1c, 0x8c, 0xb6, 0x50, 0x82, 0xa6, 0x22, 0xa7, 0xc2, 0xe0, 0x01, 0x3e, 0xa4, 0x7d, - 0x0b, 0xdd, 0x42, 0xd6, 0x99, 0x04, 0x66, 0x64, 0x9a, 0x90, 0x5c, 0x68, 0x4c, 0x32, - 0x51, 0x71, 0x6d, 0x61, 0xf7, 0x60, 0xd5, 0x3d, 0xe6, 0xe3, 0xf7, 0x90, 0xfb, 0xa7, - 0xf5, 0xf1, 0xf4, 0xde, 0x26, 0x71, 0x13, 0xbd, 0xfc, 0xd7, 0x42, 0x28, 0x22, 0x33, - 0x0b, 0x32, 0xd5, 0x8e, 0x67, 0x77, 0x76, 0x5f, 0x22, 0xa4, 0x11, 0x63, 0x44, 0xee, - 0xb6, 0x5b, 0x2e, 0xc5, 0x16, 0x39, 0x3a, 0xb3, 0x75, 0x1b, 0x53, 0x56, 0xd2, 0xb0, - 0xc9, 0x50, 0x0c, 0x0f, 0x3e, 0x46, 0x91, 0x81, 0x03, 0x5b, 0xc3, 0x66, 0x0f, 0x0b, - 0x8f, 0x9f, 0xbe, 0x6e, 0x40, 0xb5, 0xe8, 0x9c, 0xb7, 0x9b, 0x06, 0x37, 0x14, 0xca, - 0x75, 0xe7, 0x2e, 0x2e, 0x10, 0x0a, 0x10, 0xd6, 0x3b, 0xf7, 0x84, 0xdf, 0x08, 0x20, - 0xef, 0x25, 0xf8, 0xef, 0x40, 0xfe, 0x5f, 0x05, 0xfb, 0x95, 0x68, 0x3f, 0x91, 0x05, - 0xff, 0x3c, 0xb2, 0xd2, 0x19, 0xab, 0x76, 0x60, 0x5a, 0x06, 0x4f, 0x69, 0x21, 0x9f, - 0x1d, 0xc0, 0xd0, 0x0b, 0x3b, 0x48, 0x64, 0x2f, 0x97, 0x0d, 0xc0, 0x0c, 0xca, 0x4b, - 0x8b, 0x43, 0x30, 0x8b, 0xe1, 0x82, 0x86, 0xec, 0x5a, 0x42, 0x88, 0xd6, 0x00, 0xa3, - 0x78, 0x5c, 0xb6, 0x22, 0xd4, 0x68, 0xa4, 0xc6, 0x96, 0x9b, 0x37, 0x92, 0xf2, 0x48, - 0x50, 0x27, 0xd0, 0xad, 0x9a, 0xa4, 0xa9, 0xc2, 0xcc, 0x97, 0x2f, 0x9e, 0xe5, 0x19, - 0x0a, 0x95, 0xb1, 0xeb, 0x05, 0x8d, 0xdd, 0xd8, 0xc0, 0x8e, 0x7d, 0x75, 0x3f, 0x5e, - 0x01, 0x1b, 0x2b, 0xcf, 0xee, 0x1d, 0x52, 0xc1, 0xc4, 0xf2, 0xca, 0xcd, 0xa3, 0x0b, - 0xdb, 0x69, 0x30, 0x65, 0x3c, 0x0c, 0xc4, 0x48, 0x6e, 0x60, 0xe8, 0x9f, 0xa8, 0x49, - 0xb3, 0x20, 0x83, 0xba, 0x9d, 0xb4, 0x53, 0xfb, 0x8d, 0xf6, 0x83, 0xcd, 0x68, 0x75, - 0x4c, 0x87, 0xda, 0xa7, 0x31, 0xf5, 0x70, 0xa7, 0xa4, 0x06, 0x0a, 0xf0, 0xce, 0x70, - 0x0d, 0x31, 0xbc, 0xa7, 0xe7, 0x4b, 0x3e, 0x3b, 0xa3, 0xd0, 0xe8, 0xa6, 0x39, 0x2a, - 0x06, 0x2b, 0x8e, 0x86, 0xd9, 0xd7, 0xd0, 0x0b, 0x21, 0x70, 0x1e, 0x7b, 0x06, 0x2e, - 0x06, 0xb1, 0xbc, 0xd8, 0x2a, 0x01, 0xd3, 0x75, 0x62, 0x6f, 0xbf, 0x87, 0x2d, 0x27, - 0xfa, 0x45, 0x11, 0xf5, 0xf8, 0xcf, 0x8c, 0x9a, 0xbc, 0xef, 0x2a, 0x99, 0x01, 0x76, - 0xae, 0x33, 0x93, 0x25, 0xd5, 0xa5, 0x88, 0xda, 0x57, 0x96, 0xfa, 0xae, 0x5b, 0xab, - 0x7c, 0x82, 0x97, 0x7c, 0x0f, 0xf7, 0x97, 0x09, 0x3e, 0x2c, 0x1f, 0x3a, 0xe8, 0x55, - 0xf6, 0x5a, 0xea, 0x91, 0xe1, 0x31, 0x2f, 0xc6, 0xb8, 0xa4, 0x35, 0x1a, 0x2e, 0xc0, - 0x3e, 0x02, 0xe5, 0xd0, 0x2f, 0x53, 0x35, 0x4b, 0x05, 0x2f, 0xd3, 0xda, 0x0d, 0xff, - 0x82, 0xcd, 0x1f, 0x55, 0xeb, 0xca, 0x57, 0xb6, 0x33, 0x7c, 0x85, 0x93, 0x8a, 0x79, - 0x81, 0x3d, 0x20, 0x21, 0xd6, 0x09, 0x4c, 0x68, 0xb3, 0x75, 0xe9, 0x84, 0xf6, 0x83, - 0x93, 0x30, 0x08, 0x71, 0xe3, 0x48, 0xfc, 0x52, 0x36, 0xcc, 0xa6, 0x33, 0x05, 0x44, - 0xe5, 0x46, 0x39, 0xb5, 0x41, 0x87, 0x01, 0xff, 0x4c, 0xc4, 0x5a, 0x31, 0xf6, 0x2e, - 0xdd, 0x84, 0x3d, 0xbb, 0xdc, 0x5a, 0xa7, 0x27, 0xab, 0x79, 0xb4, 0x42, 0x68, 0x3c, - 0x49, 0x56, 0xbb, 0xb1, 0x95, 0xa4, 0xfa, 0x66, 0xdc, 0x9c, 0xd5, 0x42, 0xc7, 0x6b, - 0x91, 0x50, 0xc8, 0x4b, 0xf8, 0x90, 0x78, 0x99, 0x42, 0xf5, 0x5c, 0x20, 0x0b, 0x77, - 0x3e, 0xcd, 0xd7, 0x99, 0x2c, 0xff, 0x3e, 0xca, 0x24, 0xde, 0x3e, 0x09, 0x84, 0xe1, - 0x0e, 0x68, 0xae, 0x38, 0x75, 0x34, 0xb9, 0x6c, 0xde, 0x37, 0x92, 0xf1, 0x35, 0xbf, - 0x5f, 0x68, 0x78, 0x7d, 0x37, 0x0c, 0xa8, 0xc4, 0xc4, 0x07, 0x4d, 0xc5, 0xd6, 0x01, - 0xae, 0x90, 0x49, 0x54, 0x37, 0xc3, 0xc2, 0xd4, 0x8a, 0x3d, 0x96, 0x66, 0x83, 0xac, - 0x05, 0x16, 0x0b, 0x7a, 0x84, 0xea, 0xa7, 0xaa, 0xb7, 0x40, 0x09, 0xe5, 0x7a, 0x85, - 0xf7, 0xbf, 0x68, 0xa2, 0xe4, 0x82, 0x00, 0x0f, 0x82, 0x9c, 0x54, 0x50, 0x73, 0xa1, - 0x5d, 0x5c, 0xd0, 0xfc, 0xc5, 0x74, 0x39, 0xa4, 0x35, 0x0e, 0xaf, 0x09, 0x8d, 0xfb, - 0x82, 0xa0, 0x85, 0xea, 0x8a, 0x4a, 0xf6, 0xfa, 0x83, 0x81, 0xf0, 0x65, 0x88, 0x19, - 0xea, 0xb4, 0x83, 0xf6, 0x5b, 0x32, 0x5d, 0x5a, 0xed, 0xa1, 0x52, 0x32, 0xcf, 0xad, - 0xec, 0x75, 0xab, 0x18, 0x66, 0xe4, 0xc0, 0x15, 0x5a, 0x9c, 0x74, 0xa7, 0xa5, 0x7c, - 0xcf, 0x34, 0xc4, 0x83, 0xac, 0x7d, 0xa1, 0x58, 0x8a, 0x1b, 0x6b, 0x02, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x41, 0xf1, 0x10, 0x40, 0xf9, 0x4c, 0xf7, 0x8f, 0xad, 0x89, 0xbf, 0x11, 0xfe, 0xd6, - 0x9a, 0xa0, 0xd8, 0x31, 0x05, 0xad, 0xac, 0xdd, 0x4e, 0x5f, 0x04, 0xa6, 0x24, 0x24, - 0x02, 0x3c, 0x9b, 0x9e, 0x33, 0xc4, 0xfb, 0x7f, 0x12, 0xbd, 0xf2, 0x1f, 0x07, 0xf2, - 0x65, 0xc5, 0x37, 0xd5, 0x1c, 0x65, 0x51, 0xf4, 0x61, 0x7b, 0x91, 0x5d, 0x21, 0x99, - 0x18, 0x39, 0xc3, 0xd0, 0xd3, 0x63, 0x93, 0xd6, 0x46, 0xe0, 0xa8, 0xa4, 0x15, 0x09, - 0x21, 0x7d, 0x0e, 0x7d, 0x2c, 0xa1, 0xa0, 0xa0, 0xd6, 0x77, 0xa3, 0xea, 0xca, 0x23, - 0xed, 0xeb, 0x07, 0xb7, 0x4e, 0x65, 0x2a, 0x0b, 0xc5, 0x0c, 0x6c, 0x08, 0x3a, 0x55, - 0xd6, 0xc7, 0x30, 0x6e, 0x74, 0x08, 0x6f, 0x47, 0x68, 0x93, 0x3a, 0xa2, 0x48, 0x73, - 0x68, 0x18, 0x67, 0xa7, 0x89, 0x3d, 0x77, 0xcb, 0x7f, 0x29, 0xb8, 0xc8, 0x47, 0xc5, - 0x83, 0xf2, 0xd0, 0x71, 0xa6, 0x86, 0x61, 0x6e, 0x20, 0x67, 0x19, 0xf7, 0x61, 0xae, - 0x39, 0xc1, 0x10, 0x44, 0x2e, 0x06, 0x16, 0x3d, 0x2b, 0x84, 0x59, 0x03, 0x60, 0x69, - 0x5d, 0x4e, 0x19, 0x84, 0x9e, 0x63, 0x4f, 0x24, 0xd9, 0xad, 0x39, 0x6c, 0x19, 0xff, - 0x83, 0xce, 0x74, 0xf4, 0x6e, 0x64, 0x5f, 0x93, 0x2e, 0x14, 0x1a, 0x41, 0x19, 0x59, - 0x36, 0xc8, 0x5d, 0x51, 0x44, 0x14, 0xf1, 0x12, 0xe6, 0x0b, 0x1a, 0x25, 0x37, 0xc3, - 0x8d, 0x6d, 0xc6, 0xc4, 0x63, 0x83, 0x05, 0xc9, 0xbd, 0x6c, 0x62, 0xe3, 0x66, 0xbc, - 0x63, 0x12, 0x3e, 0x3e, 0x6d, 0xd3, 0x6e, 0xed, 0xd3, 0x13, 0x6f, 0xce, 0x8d, 0xee, - 0xca, 0x2a, 0xa0, 0x9a, 0x32, 0x98, 0xa3, 0x9d, 0x83, 0x85, 0x9e, 0xfc, 0x9b, 0x2b, - 0x69, 0xcf, 0x9a, 0x7d, 0xee, 0x08, 0xa9, 0x8e, 0x4b, 0xe5, 0x58, 0xac, 0x79, 0x12, - 0xfd, 0xcb, 0x42, 0x20, 0x90, 0x75, 0x42, 0x02, 0x60, 0xf7, 0xca, 0xd0, 0xf2, 0xc0, - 0x1f, 0x2a, 0xfe, 0x33, 0x07, 0x3f, 0x26, 0x24, 0x9d, 0x94, 0x4f, 0x7a, 0x50, 0xdd, - 0x84, 0x83, 0x9b, 0xc3, 0xea, 0x7f, 0xde, 0xe4, 0xed, 0x71, 0x44, 0x9c, 0xf0, 0x75, - 0x33, 0xd2, 0x6e, 0x1e, 0x27, 0xa3, 0xef, 0xb0, 0x32, 0xc3, 0xa3, 0xb3, 0x4b, 0xd3, - 0x09, 0x26, 0x22, 0xd2, 0x06, 0x2a, 0xe5, 0x36, 0xef, 0x51, 0x49, 0xc4, 0x9b, 0x5b, - 0xc9, 0x47, 0x5e, 0xaf, 0xab, 0x6e, 0x67, 0x57, 0x61, 0x00, 0x8b, 0x0d, 0xad, 0xde, - 0xec, 0xaa, 0x60, 0x44, 0x70, 0xbb, 0xe0, 0xfa, 0xda, 0x25, 0x5d, 0x29, 0x0e, 0x92, - 0xb1, 0x90, 0xc2, 0xc2, 0xd8, 0xc2, 0xde, 0xe5, 0x45, 0x5d, 0x1f, 0xa9, 0xa9, 0xf3, - 0xdb, 0x77, 0x79, 0xb5, 0x84, 0x64, 0x34, 0x64, 0xaa, 0x80, 0x14, 0xba, 0x66, 0x99, - 0x4d, 0xe2, 0x55, 0x17, 0xf8, 0x39, 0x80, 0xe6, 0x6e, 0xe4, 0xf6, 0x23, 0x14, 0xae, - 0x6d, 0xbe, 0xf4, 0x52, 0xd5, 0xd3, 0x8b, 0x0a, 0x16, 0xf3, 0x99, 0x1f, 0x36, 0xd8, - 0xa8, 0xb3, 0x9d, 0xdc, 0x0d, 0x55, 0x95, 0xee, 0xd9, 0x87, 0x62, 0x87, 0x8c, 0xdf, - 0x3f, 0x4a, 0x2e, 0xdc, 0x5c, 0xda, 0x77, 0xd5, 0xfe, 0x4f, 0xaf, 0x63, 0xa1, 0x5f, - 0x56, 0x8a, 0x54, 0x0d, 0xa5, 0x7d, 0xd9, 0xbe, 0xb6, 0xfb, 0x1a, 0x97, 0x7c, 0xcb, - 0x91, 0xb4, 0xd7, 0x9c, 0xb3, 0x9b, 0x28, 0x91, 0x1a, 0x29, 0xe7, 0xbf, 0x02, 0x8a, - 0xc6, 0x10, 0x37, 0x96, 0xdf, 0xb6, 0xb2, 0x09, 0x67, 0x23, 0x9a, 0xd3, 0x73, 0xc3, - 0x8c, 0x53, 0xf6, 0xdf, 0x18, 0x23, 0xd4, 0x95, 0x0a, 0x02, 0x83, 0xe9, 0x9b, 0x9c, - 0x06, 0xab, 0x29, 0x66, 0x66, 0x7c, 0x9d, 0xf6, 0x77, 0x71, 0x6b, 0x0c, 0xad, 0xed, - 0x81, 0x8d, 0xf9, 0xe4, 0x49, 0xc0, 0x72, 0xe2, 0x2f, 0x9d, 0x98, 0xbb, 0x0f, 0x9b, - 0x03, 0xbd, 0x5f, 0xd0, 0x13, 0xfc, 0xef, 0x3e, 0xd6, 0xa4, 0x9a, 0xeb, 0x98, 0x72, - 0x02, 0x54, 0x08, 0x7e, 0xf7, 0x28, 0xe3, 0x19, 0x47, 0xff, 0xe8, 0xf7, 0x66, 0xe6, - 0x3e, 0xe4, 0x6f, 0xf2, 0x08, 0x16, 0xd5, 0xfa, 0x8f, 0xf5, 0x5a, 0x26, 0x39, 0x89, - 0x61, 0x49, 0x0a, 0xb9, 0xae, 0x36, 0x6f, 0xc5, 0xa2, 0xd1, 0x99, 0x6e, 0xd6, 0x93, - 0xcc, 0xca, 0x82, 0x35, 0x6f, 0x60, 0x0a, 0xb0, 0x99, 0xf6, 0xec, 0xa8, 0xbf, 0xe6, - 0x45, 0x27, 0x0d, 0x3f, 0x95, 0xed, 0xba, 0x5b, 0x0d, 0xe7, 0xa3, 0x28, 0x19, 0x23, - 0x3b, 0xcc, 0x75, 0x4a, 0x5c, 0xe2, 0xe5, 0xea, 0x07, 0x84, 0x2e, 0x5f, 0xf2, 0xce, - 0xbe, 0x62, 0xad, 0x76, 0xe8, 0xef, 0xf8, 0xd1, 0x5e, 0xa4, 0xc2, 0x4a, 0x5f, 0x20, - 0x78, 0x68, 0x31, 0x9a, 0x5a, 0xf6, 0xb0, 0x35, 0xbe, 0x3f, 0x44, 0xf4, 0x34, 0x09, - 0x4f, 0x6e, 0x52, 0x5b, 0xe6, 0x14, 0xda, 0xc9, 0x20, 0xa3, 0x30, 0xbd, 0xfb, 0x26, - 0xd7, 0x5f, 0xe7, 0xb4, 0xb3, 0x65, 0xd0, 0x94, 0x45, 0x92, 0x50, 0xaa, 0xa5, 0x54, - 0x44, 0x89, 0xfb, 0x1d, 0x99, 0x25, 0x81, 0x80, 0x0a, 0x77, 0xb8, 0x91, 0x21, 0x57, - 0xfc, 0x97, 0x13, 0xaa, 0xac, 0x25, 0xb4, 0xc2, 0x6e, 0xb0, 0x3f, 0x71, 0x66, 0x46, - 0x61, 0x9a, 0xf0, 0x24, 0x56, 0xae, 0x69, 0x59, 0x62, 0xfe, 0x5e, 0x93, 0x1a, 0x63, - 0xb5, 0xc7, 0x90, 0x52, 0xec, 0xd3, 0x33, 0xe1, 0x84, 0x12, 0xdb, 0x91, 0xe1, 0x5f, - 0x7c, 0xbc, 0x70, 0xb4, 0xcd, 0x7e, 0x8e, 0x3c, 0x95, 0x1f, 0x35, 0x85, 0x72, 0xe3, - 0x77, 0x67, 0xe7, 0xd5, 0x27, 0x04, 0xa6, 0x72, 0x1b, 0x30, 0xef, 0xc4, 0x10, 0x17, - 0xae, 0x4d, 0x23, 0x15, 0x58, 0xc5, 0xc8, 0x2c, 0xc7, 0xdd, 0x7e, 0x33, 0x56, 0xc0, - 0x9d, 0xc2, 0x49, 0x06, 0xf0, 0x43, 0x8d, 0xfc, 0xc3, 0x00, 0x85, 0x6a, 0xc2, 0xce, - 0xd8, 0xf7, 0x7f, 0xa8, 0x01, 0x57, 0x36, 0xc6, 0x61, 0xe8, 0x02, 0x48, 0xae, 0xeb, - 0x77, 0x48, 0x74, 0xaa, 0x79, 0xd2, 0x90, 0xb8, 0xf5, 0x02, 0x7a, 0x0a, 0x50, 0x95, - 0x37, 0xfc, 0x7c, 0x68, 0x9b, 0x7a, 0xd8, 0x61, 0x16, 0xcf, 0xec, 0x26, 0x47, 0xcc, - 0xaa, 0xe1, 0xc7, 0x4b, 0x41, 0x6f, 0x3e, 0x6a, 0xe8, 0xf7, 0xcc, 0x60, 0xea, 0xaf, - 0x7b, 0x6a, 0x59, 0x0d, 0x51, 0x54, 0x41, 0x38, 0xe1, 0x73, 0x29, 0x45, 0x60, 0x3a, - 0x53, 0x46, 0x2c, 0x60, 0xe1, 0xf6, 0xcb, 0x0c, 0x9c, 0xa0, 0x39, 0x0c, 0x48, 0x82, - 0x24, 0xc3, 0x13, 0x26, 0x9f, 0xcd, 0x59, 0xfc, 0xb6, 0x11, 0xfb, 0x2d, 0x9b, 0x4c, - 0x8f, 0xa6, 0x01, 0xbb, 0x1c, 0xb8, 0xd0, 0x7d, 0x79, 0x7b, 0xf5, 0xde, 0x52, 0xbc, - 0xee, 0xb0, 0x23, 0x01, 0xc8, 0x96, 0x2a, 0xc1, 0xfc, 0x04, 0x91, 0xdc, 0x81, 0xaf, - 0xfd, 0x6c, 0x1e, 0xbf, 0x89, 0xa1, 0x3d, 0x6f, 0x29, 0x0e, 0xda, 0x5d, 0x5c, 0xef, - 0x38, 0x22, 0x15, 0xc5, 0xe9, 0x51, 0xd7, 0x13, 0x05, 0xef, 0x33, 0xd9, 0x73, 0x71, - 0x26, 0xd0, 0xe6, 0x62, 0x90, 0x5f, 0x12, 0x50, 0x92, 0x6f, 0x6a, 0x22, 0x99, 0x90, - 0xe3, 0x8f, 0x69, 0xad, 0x9a, 0x91, 0x92, 0xb3, 0x02, 0xf2, 0x6b, 0xdd, 0xa4, 0x65, - 0xd9, 0x0b, 0x94, 0xb1, 0x2c, 0x57, 0xfa, 0x3f, 0xd6, 0x93, 0x00, 0x83, 0xf1, 0x84, - 0x43, 0x8d, 0x8a, 0x88, 0x9d, 0x3f, 0x5e, 0xce, 0xa2, 0xc6, 0xd2, 0x3d, 0x67, 0x36, - 0xf2, 0xa0, 0xf1, 0x8e, 0x26, 0xf4, 0xfa, 0x45, 0xd1, 0xbe, 0x8f, 0x3d, 0xc4, 0xa7, - 0x07, 0x13, 0x7e, 0x95, 0xd2, 0xad, 0x59, 0x4f, 0x6c, 0x03, 0xd2, 0x49, 0x23, 0x06, - 0x7a, 0xe4, 0x7f, 0xd6, 0x42, 0x5e, 0xfb, 0x9c, 0x1d, 0x50, 0x4e, 0x6f, 0xd5, 0x57, - 0x53, 0x40, 0x94, 0x56, 0x01, 0xfe, 0x80, 0x6f, 0x57, 0x56, 0xac, 0xb5, 0x62, 0xf1, - 0x3c, 0x0c, 0xa1, 0xd8, 0x03, 0xa1, 0x95, 0xc2, 0xeb, 0xb2, 0xef, 0x02, 0xac, 0x33, - 0xe6, 0xa8, 0x8d, 0xea, 0x07, 0x5b, 0xa9, 0x96, 0xd3, 0xc3, 0x36, 0x64, 0x8e, 0x86, - 0x94, 0xd3, 0xa1, 0x9d, 0x3d, 0xca, 0x53, 0x1b, 0xeb, 0x50, 0xd4, 0x32, 0x7c, 0x5c, - 0x0c, 0x23, 0xcb, 0x7c, 0xfd, 0xb0, 0x8c, 0xa7, 0xcf, 0x2c, 0xac, 0x6b, 0xc1, 0x39, - 0xd0, 0x74, 0x14, 0x73, 0xd3, 0x76, 0x02, 0x9c, 0xb4, 0xab, 0x6b, 0xf0, 0x54, 0x55, - 0x7c, 0xe2, 0x94, 0xc7, 0x28, 0xa4, 0x68, 0x7d, 0x57, 0xec, 0x89, 0x09, 0xff, 0x51, - 0xa4, 0xd0, 0x2f, 0x9d, 0xcd, 0x11, 0x19, 0x3d, 0x7d, 0x1c, 0x9f, 0xda, 0xe6, 0xa1, - 0x73, 0x96, 0xa1, 0xbf, 0x57, 0xa9, 0x94, 0x93, 0x4f, 0x5e, 0x7a, 0x59, 0xf0, 0x45, - 0xde, 0xbe, 0xaf, 0xf6, 0x2e, 0xf3, 0x26, 0xb9, 0x47, 0xf2, 0xa8, 0xb4, 0x95, 0x55, - 0xe4, 0xd9, 0x9b, 0x3b, 0xf5, 0xc8, 0x1f, 0xf9, 0xfe, 0x31, 0x4e, 0x04, 0x7a, 0xf1, - 0x52, 0x50, 0x8f, 0x57, 0x01, 0x5c, 0xa4, 0x02, 0xc6, 0x7d, 0x92, 0x5c, 0x99, 0xac, - 0xea, 0x3e, 0xe8, 0xcc, 0x4b, 0x00, 0x8c, 0x5c, 0xb4, 0x39, 0x66, 0xe7, 0x14, 0xef, - 0x48, 0x0f, 0xd0, 0x5e, 0x07, 0xc7, 0xb2, 0xdd, 0xa9, 0xaa, 0x39, 0x66, 0x11, 0x3e, - 0xaa, 0x29, 0x3d, 0x3f, 0x62, 0x2b, 0x30, 0x9d, 0x64, 0x80, 0x3c, 0xe1, 0xe6, 0x37, - 0x8b, 0x6a, 0xac, 0x4f, 0xab, 0x52, 0x7c, 0x43, 0xcd, 0x45, 0xed, 0x0a, 0x3c, 0x1a, - 0x4b, 0x9f, 0xb1, 0x8d, 0xcc, 0xcf, 0xcd, 0xb6, 0xac, 0x0c, 0x24, 0x21, 0x63, 0x9c, - 0xda, 0x00, 0x75, 0xa2, 0x0d, 0xc5, 0x11, 0x1b, 0x8d, 0x3d, 0x31, 0x99, 0x49, 0x5b, - 0xd9, 0x13, 0x3d, 0xba, 0xb9, 0x45, 0x41, 0x41, 0x0e, 0x4f, 0xba, 0x92, 0xc7, 0xb6, - 0x06, 0xa5, 0xcb, 0x12, 0x2f, 0x14, 0x0c, 0xf1, 0xa3, 0x59, 0x6f, 0x27, 0x88, 0xf3, - 0xc8, 0xb9, 0x26, 0x60, 0xf1, 0x4c, 0xb6, 0x5a, 0xf5, 0xdd, 0x23, 0xdf, 0xdb, 0xac, - 0x13, 0x71, 0xec, 0xf4, 0xb3, 0x37, 0x12, 0xfe, 0xd2, 0x29, 0x2c, 0x44, 0xf7, 0x08, - 0x34, 0xcf, 0x96, 0xc0, 0x5d, 0x58, 0x82, 0x7e, 0x69, 0xbf, 0xc2, 0xe6, 0x96, 0xfa, - 0x08, 0x74, 0x86, 0x9c, 0x02, 0xf3, 0xdc, 0xa1, 0x1c, 0x3b, 0x90, 0xcb, 0x21, 0x4e, - 0x68, 0xbc, 0x1c, 0xae, 0x03, 0x9d, 0x7a, 0x14, 0x6c, 0xdc, 0x1d, 0x60, 0x9d, 0x7a, - 0x6b, 0x3f, 0xd5, 0xd4, 0x61, 0xb0, 0x95, 0x1c, 0x82, 0xcf, 0xb3, 0xe7, 0x63, 0xfa, - 0xd2, 0xd1, 0xbc, 0x76, 0x78, 0xcd, 0xf8, 0x27, 0x79, 0xf8, 0xfd, 0x5a, 0x1c, 0xe2, - 0x2a, 0x8d, 0x3c, 0x45, 0x47, 0xab, 0xd9, 0x59, 0x83, 0x8a, 0x46, 0xfb, 0x80, 0xaf, - 0xe0, 0x1f, 0x8e, 0xcc, 0x99, 0x31, 0x51, 0x3b, 0x19, 0x62, 0xec, 0x54, 0x08, 0x56, - 0xcb, 0x18, 0x93, 0x87, 0xcf, 0xbf, 0xcc, 0x0f, 0x7c, 0x68, 0x22, 0x3c, 0xba, 0x47, - 0xfb, 0x0c, 0x9b, 0x48, 0x6e, 0x4d, 0x99, 0x17, 0x19, 0x41, 0xf7, 0x67, 0x5a, 0x8b, - 0x46, 0x32, 0x8a, 0x3b, 0xc1, 0x09, 0xbf, 0x07, 0xc6, 0x6d, 0x5e, 0xde, 0x77, 0x1c, - 0xc4, 0xc7, 0x4c, 0xe8, 0x03, 0x33, 0x82, 0x91, 0x91, 0xee, 0xdc, 0x49, 0x35, 0x08, - 0xa6, 0x44, 0x53, 0x0a, 0x61, 0x44, 0xf2, 0x2d, 0xcf, 0x97, 0x52, 0x5a, 0x4c, 0xdc, - 0xa1, 0xad, 0x71, 0x07, 0x3b, 0x08, 0x0b, 0x73, 0xea, 0x45, 0x49, 0xf5, 0x40, 0x1b, - 0xff, 0x43, 0x18, 0x26, 0x8e, 0x6a, 0xd6, 0x37, 0x36, 0x31, 0x57, 0xa1, 0x9a, 0x53, - 0xf1, 0x23, 0xa0, 0xb0, 0xe1, 0x6d, 0x0b, 0x77, 0xf0, 0x20, 0x28, 0xda, 0x46, 0x41, - 0x00, 0xfd, 0xe7, 0x6d, 0x83, 0xdd, 0x0b, 0xb2, 0x24, 0xf7, 0xb5, 0x7a, 0x00, 0xc0, - 0x2f, 0x68, 0xae, 0x64, 0x8f, 0xdc, 0x52, 0x99, 0x57, 0xa1, 0x04, 0x90, 0xdc, 0xe1, - 0xfd, 0xdb, 0xb0, 0x90, 0x4f, 0x0d, 0x51, 0x8b, 0xb3, 0x87, 0x54, 0x40, 0x19, 0x98, - 0x3b, 0x61, 0x69, 0x75, 0xa7, 0x8e, 0x74, 0xd8, 0x54, 0xfd, 0xdc, 0x49, 0xb2, 0x55, - 0x16, 0x7b, 0x55, 0xef, 0x4b, 0xee, 0x46, 0x56, 0x68, 0xb2, 0x0e, 0xa4, 0x11, 0x8c, - 0xa5, 0x69, 0xae, 0x48, 0x0e, 0x0f, 0x6e, 0x5e, 0x04, 0x3a, 0x35, 0x7b, 0x36, 0xd3, - 0xab, 0x36, 0xc8, 0x61, 0xf2, 0x27, 0x83, 0x01, 0xdc, 0xe5, 0x76, 0x74, 0xd5, 0x07, - 0x3b, 0x3a, 0x6f, 0x51, 0x03, 0xa0, 0x79, 0x3a, 0xf1, 0xb7, 0xd4, 0x6f, 0x95, 0x7e, - 0x22, 0xd8, 0xd2, 0x58, 0x3b, 0xf1, 0x81, 0x83, 0x6c, 0x3b, 0xe9, 0x93, 0x0b, 0xac, - 0x8f, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x60, 0xe9, 0x68, 0xaa, 0x71, 0x09, 0x87, 0x0b, 0xbe, 0xd1, - 0x7d, 0xf5, 0xf8, 0x88, 0xc8, 0xca, 0x14, 0x67, 0xae, 0x17, 0xdb, 0xbc, 0xde, 0x31, - 0xc1, 0x10, 0x5c, 0xb5, 0xbd, 0xa8, 0x8a, 0xc6, 0xc6, 0x27, 0x00, 0x2c, 0xe2, 0x1c, - 0x02, 0x14, 0x0f, 0xfe, 0x81, 0xec, 0x58, 0xbf, 0x1e, 0x6d, 0x1b, 0xb7, 0xaa, 0xad, - 0xa4, 0x1f, 0xba, 0x0b, 0xb5, 0x88, 0x77, 0x8a, 0x7f, 0x65, 0x20, 0x2a, 0xd8, 0x11, - 0xea, 0x73, 0xd2, 0x6c, 0x74, 0x55, 0x03, 0x95, 0xaf, 0xf7, 0x53, 0x25, 0x10, 0x7c, - 0x9b, 0x3f, 0x9a, 0xe9, 0xdc, 0xdc, 0xd8, 0x6e, 0xd0, 0x81, 0xa2, 0xe7, 0x42, 0x47, - 0x19, 0xa3, 0xd1, 0x85, 0xb7, 0xe0, 0xa4, 0x3a, 0x47, 0x2e, 0x29, 0x8a, 0xc0, 0xaf, - 0xdc, 0x52, 0x87, 0xd7, 0xad, 0x12, 0x4c, 0xd9, 0x40, 0x5a, 0x62, 0xcd, 0x1c, 0xa0, - 0x8b, 0x28, 0x2e, 0xfe, 0xf7, 0xf9, 0x28, 0xdf, 0x76, 0xe2, 0x82, 0x1a, 0x41, 0x84, - 0x13, 0xeb, 0x7c, 0xea, 0xa5, 0xff, 0x12, 0x90, 0xb0, 0x3e, 0xc9, 0x1c, 0xe6, 0xdd, - 0x28, 0x13, 0x0c, 0x3a, 0xb0, 0xb2, 0x3b, 0x60, 0x2b, 0xd5, 0xbe, 0x5d, 0xc2, 0x60, - 0x03, 0xaa, 0xe0, 0x4b, 0x33, 0xd7, 0xbd, 0x25, 0x90, 0xe9, 0x0c, 0x8c, 0x38, 0x8e, - 0xa7, 0x95, 0x51, 0x22, 0xdb, 0xac, 0xa6, 0x7b, 0x30, 0x39, 0x5a, 0x92, 0x8b, 0x57, - 0xb8, 0x57, 0x51, 0x23, 0x20, 0x5a, 0xe1, 0x91, 0x52, 0xe4, 0x1e, 0x00, 0x29, 0x31, - 0xb4, 0x57, 0x46, 0x19, 0x8e, 0x5d, 0xd9, 0x57, 0x1a, 0x56, 0xa7, 0xe0, 0xd4, 0x23, - 0xff, 0x27, 0x98, 0x9d, 0x3e, 0xb4, 0x17, 0xec, 0xd3, 0xc3, 0x09, 0x3f, 0xb8, 0x2c, - 0x56, 0x58, 0xe2, 0x96, 0x24, 0xc5, 0x32, 0x19, 0xa6, 0x0c, 0xd0, 0xa8, 0xc4, 0xda, - 0x36, 0x7e, 0x29, 0xa7, 0x17, 0x79, 0xa7, 0x30, 0x32, 0x98, 0x5a, 0x3d, 0x1f, 0xd0, - 0x3d, 0xd4, 0xd0, 0x6e, 0x05, 0x56, 0x6f, 0x3b, 0x84, 0x36, 0x7c, 0xf0, 0xfa, 0xee, - 0x9b, 0xc3, 0xbd, 0x7a, 0x3a, 0x60, 0x6a, 0x9f, 0xdb, 0x84, 0x9c, 0x5d, 0x82, 0xd0, - 0xa6, 0x19, 0x23, 0xc2, 0xe5, 0xd8, 0xaa, 0x63, 0xa8, 0xa5, 0x0c, 0x38, 0xbd, 0x03, - 0x87, 0x72, 0xc4, 0x14, 0x3d, 0x8b, 0x7a, 0xcf, 0xd7, 0x4e, 0x72, 0xc0, 0x4d, 0x89, - 0x24, 0x8d, 0xff, 0x20, 0xfe, 0x8d, 0xc5, 0xec, 0x21, 0x49, 0x05, 0x4e, 0xa2, 0x41, - 0x64, 0xe8, 0x5f, 0x67, 0x44, 0xad, 0x0c, 0xac, 0xf1, 0xa8, 0xb7, 0x01, 0x26, 0xf4, - 0x82, 0xc0, 0x92, 0xed, 0x9f, 0x61, 0x27, 0xd2, 0x05, 0x0d, 0x12, 0xe8, 0x78, 0xa7, - 0x96, 0x53, 0xa1, 0xe8, 0x4d, 0xae, 0xc3, 0xeb, 0xe6, 0x2d, 0x5f, 0x6c, 0x4a, 0xbe, - 0x5c, 0xe9, 0x0a, 0x7f, 0xe2, 0xe5, 0x2a, 0x8d, 0x78, 0x46, 0xe8, 0xed, 0xf2, 0xf2, - 0xbc, 0xe0, 0x5a, 0x03, 0x7c, 0x82, 0x6f, 0x22, 0xca, 0xad, 0x12, 0x61, 0x46, 0x7d, - 0xcf, 0xb7, 0xd6, 0xb6, 0x13, 0x3d, 0xc2, 0x1e, 0x80, 0x96, 0xc7, 0xe9, 0xf8, 0xe9, - 0xe1, 0x0c, 0x1e, 0x3f, 0xac, 0x40, 0x58, 0xb6, 0x82, 0xc6, 0x8e, 0x54, 0xfa, 0xca, - 0xe0, 0xf9, 0xc2, 0xdd, 0x4d, 0x64, 0xd9, 0x04, 0x61, 0x52, 0xb4, 0x76, 0x23, 0x32, - 0x93, 0x9f, 0x17, 0xe6, 0xaa, 0xf7, 0xd8, 0xb9, 0xd3, 0x58, 0xe2, 0x21, 0x8d, 0x4e, - 0x0d, 0x69, 0xa4, 0xf1, 0x19, 0xe1, 0xc6, 0x4e, 0xec, 0x4c, 0x8b, 0x53, 0x28, 0x09, - 0x70, 0x71, 0x31, 0xf0, 0x1f, 0x55, 0xc7, 0xad, 0x04, 0xcf, 0xb6, 0x3f, 0x7c, 0x4a, - 0x3d, 0x0a, 0x2b, 0x0f, 0xfb, 0x0b, 0x05, 0xa6, 0xbe, 0x05, 0x5b, 0x8c, 0x94, 0xca, - 0x80, 0xbb, 0x0a, 0x1d, 0x13, 0xcd, 0x4c, 0xd6, 0x9a, 0xb9, 0x83, 0x04, 0xae, 0x25, - 0x15, 0xd5, 0xf7, 0x69, 0x9d, 0x4a, 0xbe, 0xe5, 0xc2, 0x0b, 0xe6, 0x09, 0xd8, 0x73, - 0x51, 0x10, 0x12, 0xf2, 0x34, 0xbd, 0x85, 0xa7, 0xef, 0xf5, 0xfb, 0x63, 0x4c, 0xff, - 0x26, 0x58, 0xba, 0x65, 0x16, 0x04, 0x85, 0x63, 0x09, 0x5e, 0xce, 0xfb, 0x30, 0x15, - 0xee, 0x3f, 0x03, 0xca, 0x52, 0xa1, 0x77, 0xf2, 0x61, 0xec, 0xdc, 0x26, 0xbc, 0x08, - 0x9d, 0x34, 0xc6, 0x40, 0x48, 0x46, 0xe9, 0xc6, 0x47, 0xfc, 0xfe, 0x98, 0xcc, 0x6a, - 0xcd, 0xbb, 0x46, 0x4f, 0x64, 0x27, 0x8a, 0xd8, 0xce, 0x9d, 0x1a, 0xe0, 0xd4, 0x15, - 0xbc, 0x0c, 0x05, 0x24, 0x5f, 0xdd, 0xaf, 0x4e, 0xbc, 0x8d, 0xc7, 0x03, 0xa8, 0x5c, - 0xb2, 0x70, 0xf7, 0x96, 0xad, 0x2d, 0x93, 0x7e, 0x2a, 0xc0, 0xd5, 0xe0, 0xa3, 0x48, - 0x21, 0x75, 0x80, 0x00, 0xaa, 0x59, 0xc9, 0xd4, 0x65, 0x24, 0x85, 0x29, 0x4e, 0xe0, - 0xab, 0x29, 0x69, 0x6b, 0x21, 0x43, 0x0f, 0xa5, 0x4d, 0xcf, 0xbf, 0x2b, 0x9c, 0x49, - 0xd1, 0x42, 0x06, 0x42, 0x09, 0xee, 0xee, 0xd4, 0xd4, 0x71, 0xff, 0xc0, 0x17, 0xd4, - 0xe2, 0x0a, 0x79, 0x6b, 0x09, 0x27, 0x80, 0x4c, 0x06, 0x1b, 0x9f, 0x4a, 0x70, 0x91, - 0xfe, 0x01, 0x5a, 0xda, 0x68, 0xfd, 0x84, 0x42, 0xe0, 0x18, 0x25, 0xc8, 0x8d, 0xfe, - 0x55, 0xcf, 0x5d, 0xe3, 0x89, 0x36, 0xf7, 0xce, 0x25, 0x31, 0x1b, 0x90, 0x2b, 0xa9, - 0x7a, 0x3c, 0x12, 0xa9, 0x5c, 0xfa, 0x1c, 0x3a, 0x59, 0x1b, 0x81, 0x8f, 0x60, 0x83, - 0x27, 0x09, 0xd9, 0xe4, 0x83, 0x9e, 0x41, 0x0f, 0xb3, 0x6b, 0x84, 0xf3, 0xac, 0x4f, - 0x07, 0x0f, 0xc3, 0x5e, 0x16, 0x19, 0x78, 0x25, 0x9e, 0x5b, 0x8e, 0xdc, 0x74, 0x4d, - 0x90, 0x91, 0x9a, 0xa7, 0x70, 0xbb, 0x36, 0x21, 0x51, 0x28, 0xe5, 0x82, 0xb5, 0x96, - 0x41, 0xe2, 0x38, 0x52, 0xe9, 0x58, 0xeb, 0x8f, 0xc3, 0xc0, 0xaa, 0x96, 0x15, 0x2b, - 0xa4, 0xf7, 0x7f, 0x13, 0x8d, 0x6a, 0x67, 0x12, 0xa3, 0xae, 0x32, 0x26, 0x01, 0x58, - 0x83, 0xf8, 0x1d, 0xb2, 0x3e, 0x58, 0x3c, 0x86, 0x9c, 0x4c, 0x71, 0x14, 0x3a, 0x6f, - 0xff, 0xd6, 0x5e, 0x8d, 0xfd, 0xc5, 0x0c, 0x99, 0xa2, 0xf1, 0xf3, 0x14, 0xcd, 0xcc, - 0x71, 0x35, 0x9e, 0x23, 0x5f, 0x1d, 0x7d, 0xc2, 0xb5, 0xf3, 0x8e, 0xf7, 0xb9, 0x70, - 0x84, 0x31, 0x63, 0xc0, 0x3f, 0x9d, 0xd4, 0x0a, 0x80, 0x15, 0xef, 0xdc, 0x87, 0x91, - 0x95, 0x6a, 0x3f, 0x3c, 0xed, 0xd9, 0xea, 0x64, 0xf8, 0xef, 0xa7, 0xa0, 0x81, 0x5a, - 0x70, 0x38, 0x1d, 0x71, 0x46, 0x78, 0x17, 0xbd, 0x04, 0xca, 0x52, 0x9a, 0xed, 0xe0, - 0x7f, 0xf6, 0x0d, 0x17, 0x6a, 0xed, 0x0f, 0x85, 0x5a, 0x2e, 0xae, 0xa8, 0x9e, 0xae, - 0xac, 0xa8, 0x93, 0x58, 0xc0, 0x81, 0x82, 0x6a, 0x08, 0x12, 0xa5, 0xbc, 0xa2, 0x8b, - 0xe1, 0x37, 0x3f, 0x08, 0x6d, 0xbd, 0xba, 0x7e, 0x43, 0xe2, 0x03, 0x21, 0x2c, 0x9f, - 0xed, 0x21, 0x47, 0x4b, 0xa1, 0x9a, 0x05, 0x5f, 0xfc, 0xc1, 0x79, 0x41, 0x2e, 0x89, - 0x3a, 0x74, 0x48, 0x32, 0x29, 0x8c, 0x5f, 0xe2, 0x4c, 0xc6, 0xb1, 0x86, 0x67, 0xf4, - 0x9b, 0x34, 0xdf, 0xb1, 0x23, 0x79, 0x26, 0x74, 0x19, 0xa9, 0xcb, 0x94, 0x03, 0xd8, - 0x16, 0x7d, 0x8d, 0x1e, 0x91, 0xd2, 0x81, 0x1a, 0x04, 0x3b, 0x29, 0x24, 0x3b, 0x06, - 0x9b, 0x37, 0x58, 0x78, 0x47, 0xdc, 0x6f, 0xcd, 0xdb, 0x18, 0x31, 0xbd, 0x1c, 0xc2, - 0x56, 0x7c, 0xa0, 0x33, 0xac, 0x40, 0xf7, 0x4a, 0xb6, 0x95, 0x5f, 0x68, 0x3b, 0x12, - 0xe4, 0xe8, 0x25, 0x4e, 0x4e, 0xa7, 0x60, 0xd3, 0x8b, 0x3f, 0x46, 0x79, 0x1c, 0x5c, - 0x4c, 0xb1, 0x2b, 0xc7, 0xcc, 0xb0, 0xed, 0x18, 0x65, 0xf2, 0x5d, 0x60, 0x1c, 0x30, - 0x3f, 0x81, 0xfb, 0x1f, 0xa1, 0xdb, 0x48, 0x53, 0x3d, 0x3d, 0x6b, 0x28, 0x8e, 0x4d, - 0x9a, 0x4d, 0xff, 0x8e, 0xc2, 0x1c, 0x96, 0xf5, 0x78, 0x39, 0x97, 0x10, 0xc8, 0x25, - 0xfe, 0x7e, 0x32, 0xf9, 0x3a, 0x8c, 0x07, 0x43, 0xf9, 0xeb, 0xd5, 0x4c, 0xc1, 0x51, - 0xc7, 0x61, 0x03, 0x37, 0xae, 0xbf, 0x7e, 0x9b, 0x91, 0x57, 0x20, 0xa5, 0x43, 0x51, - 0xd4, 0x9a, 0xb8, 0xc2, 0x2f, 0xa3, 0x49, 0x98, 0xdc, 0xf5, 0x83, 0xd4, 0x38, 0x73, - 0x61, 0xef, 0x3f, 0xf8, 0x6f, 0x50, 0xec, 0x53, 0xf4, 0x92, 0x49, 0xe4, 0xad, 0x34, - 0x96, 0x03, 0x06, 0x6f, 0xc9, 0xc6, 0x61, 0xd6, 0x9f, 0x91, 0x1d, 0xfa, 0x72, 0x41, - 0xc8, 0xd5, 0x79, 0x2d, 0x43, 0xc4, 0x57, 0xd5, 0xde, 0x96, 0x52, 0x3a, 0x53, 0xd6, - 0x67, 0xec, 0x5c, 0x4e, 0xf9, 0xd5, 0x02, 0xa1, 0x6f, 0x15, 0x22, 0x47, 0x58, 0x96, - 0xd7, 0x9b, 0xc5, 0x78, 0x33, 0xe9, 0x77, 0x17, 0x1c, 0x32, 0x4d, 0xce, 0x2a, 0x1e, - 0xa1, 0xe4, 0x30, 0x4f, 0x49, 0xe4, 0x3a, 0xe0, 0x65, 0xe3, 0xfb, 0x19, 0x6f, 0x76, - 0xd9, 0xb8, 0x79, 0xc7, 0x20, 0x08, 0x62, 0xea, 0xd1, 0x8d, 0xea, 0x5f, 0xb6, 0xa1, - 0x7a, 0xce, 0xa3, 0x33, 0x86, 0xeb, 0x4c, 0xa1, 0xb5, 0x14, 0x86, 0xa9, 0x14, 0x8f, - 0xbd, 0xf9, 0xa9, 0x53, 0x32, 0xaa, 0x60, 0x5c, 0x5d, 0x54, 0x83, 0xce, 0x4b, 0xa8, - 0xec, 0xe0, 0x1a, 0x8f, 0xf2, 0xb7, 0xef, 0x82, 0xd0, 0x5c, 0x0b, 0x6e, 0x86, 0x1b, - 0x91, 0x5f, 0x13, 0xca, 0x0e, 0xb3, 0xea, 0x13, 0xd5, 0x07, 0x08, 0x07, 0xa2, 0xcb, - 0x66, 0x80, 0xa2, 0x49, 0xea, 0x9c, 0x72, 0x24, 0x39, 0x2c, 0xbc, 0x8a, 0xb8, 0x25, - 0x01, 0xb2, 0x6f, 0x11, 0x2a, 0xc7, 0x89, 0xa1, 0x2a, 0x31, 0xad, 0x13, 0x14, 0xe2, - 0xed, 0xe0, 0x8f, 0xad, 0x31, 0x43, 0xaf, 0x30, 0xc2, 0x7f, 0x40, 0x3b, 0xc8, 0x66, - 0xc7, 0x55, 0x17, 0x78, 0x52, 0xaf, 0xd0, 0xab, 0xb9, 0x0a, 0xde, 0x1d, 0x68, 0x27, - 0x26, 0xf4, 0x20, 0x08, 0xb4, 0x6a, 0xd7, 0xf8, 0xab, 0xdb, 0x18, 0x11, 0x7f, 0x72, - 0x64, 0x13, 0x90, 0xf0, 0x86, 0xb6, 0xe1, 0x49, 0x8b, 0xe6, 0x95, 0x48, 0x52, 0x7e, - 0x6a, 0xda, 0x2b, 0x38, 0xb9, 0xfe, 0x12, 0x1e, 0xf6, 0x70, 0xaf, 0x74, 0x37, 0xd3, - 0x25, 0x36, 0xd5, 0xcf, 0x5c, 0x4a, 0xb1, 0x9d, 0xd9, 0x97, 0x71, 0x58, 0x2d, 0x03, - 0x81, 0x04, 0xb7, 0xe0, 0x39, 0xa3, 0x76, 0xf7, 0xac, 0xbb, 0xea, 0xdb, 0x34, 0xf9, - 0x45, 0xbe, 0xb9, 0xd7, 0xca, 0x0e, 0x4e, 0x3d, 0x5c, 0x5e, 0x4e, 0xb1, 0xd8, 0x52, - 0x6e, 0xbd, 0x13, 0xda, 0xcb, 0x1b, 0xa3, 0x57, 0x35, 0xc6, 0xd0, 0x4a, 0x45, 0x55, - 0xac, 0xf4, 0xbf, 0x11, 0x76, 0x26, 0x50, 0x0d, 0x77, 0xb3, 0x81, 0x89, 0xdd, 0x48, - 0x88, 0x04, 0x12, 0x25, 0xac, 0xbe, 0x38, 0x74, 0xa4, 0xc0, 0xf6, 0x07, 0xfe, 0x67, - 0x45, 0xf9, 0x35, 0x5b, 0x3f, 0xa1, 0x88, 0xf1, 0xd6, 0x5c, 0x09, 0xf3, 0x89, 0xaf, - 0x1b, 0x9d, 0x62, 0x32, 0xaa, 0x79, 0x44, 0x79, 0x19, 0xc5, 0x50, 0xf6, 0xf3, 0x1f, - 0xec, 0x35, 0x48, 0x1c, 0xb9, 0x22, 0xde, 0x2d, 0xb5, 0xb4, 0xda, 0x2f, 0x81, 0x94, - 0x86, 0x17, 0x02, 0x8e, 0x32, 0x17, 0x06, 0xa3, 0xa7, 0x78, 0xc1, 0x93, 0x8c, 0x44, - 0x3b, 0xb0, 0x0e, 0x5b, 0x0f, 0xf0, 0x6a, 0xd8, 0xab, 0x9b, 0x1a, 0xb0, 0xc1, 0x14, - 0x77, 0x67, 0x3f, 0x85, 0xdf, 0x95, 0x61, 0xdb, 0xea, 0x45, 0xd5, 0xf9, 0x78, 0x1e, - 0xbe, 0x31, 0x7a, 0x07, 0x10, 0xae, 0x54, 0x61, 0xe3, 0x4f, 0xe6, 0xf1, 0xb1, 0xaa, - 0x9b, 0x4e, 0x67, 0xb1, 0x49, 0x10, 0x98, 0x48, 0x02, 0xc2, 0xa7, 0xe3, 0x81, 0x93, - 0xbc, 0x7b, 0xdc, 0x8b, 0xa3, 0xe4, 0xe3, 0xd1, 0xd9, 0x33, 0xbf, 0xb5, 0x80, 0xf5, - 0xb3, 0xe8, 0x7a, 0x2a, 0x06, 0x51, 0x70, 0x51, 0x41, 0x0f, 0xe1, 0xb4, 0xff, 0x1e, - 0xa0, 0xad, 0xe8, 0x24, 0xf3, 0x38, 0x51, 0x54, 0x56, 0xa5, 0x7c, 0x7a, 0x91, 0x6a, - 0x74, 0x38, 0x8e, 0xe8, 0xf1, 0x28, 0x1f, 0x9a, 0xde, 0x0a, 0xe2, 0xa2, 0x61, 0x3a, - 0x06, 0x12, 0xc4, 0x69, 0xdf, 0x79, 0x2b, 0x8d, 0xf4, 0xca, 0xe4, 0xfc, 0x25, 0xc1, - 0xca, 0xdb, 0xa9, 0x5a, 0x80, 0x7c, 0xe6, 0x1e, 0x5a, 0x53, 0x03, 0xfa, 0xaf, 0x9e, - 0x14, 0x65, 0x39, 0x96, 0xb5, 0xa8, 0xad, 0xc3, 0x4f, 0xd4, 0x75, 0xef, 0x14, 0x99, - 0x09, 0x4b, 0xab, 0xaf, 0x1f, 0x3f, 0x07, 0xda, 0x9a, 0x39, 0x0b, 0x1d, 0x9f, 0xc9, - 0xa0, 0x83, 0x27, 0x98, 0x7a, 0xdf, 0xe9, 0x56, 0x48, 0x63, 0xfb, 0xdf, 0xa8, 0xf6, - 0xb4, 0x6a, 0x88, 0x41, 0x58, 0x30, 0x99, 0xaf, 0xb7, 0x87, 0x01, 0x18, 0xfa, 0xce, - 0x76, 0x34, 0x7e, 0x40, 0xb6, 0xfd, 0x8c, 0xd1, 0x55, 0x82, 0xae, 0x8e, 0x23, 0xbe, - 0x9a, 0x02, 0x19, 0xbc, 0x3e, 0x4e, 0x45, 0x46, 0xa3, 0x0d, 0x3b, 0xbb, 0xbd, 0x16, - 0x86, 0x08, 0x68, 0x76, 0xbe, 0x0e, 0x4c, 0x85, 0x9b, 0xe7, 0x1f, 0xb5, 0x8f, 0x4f, - 0xab, 0x3d, 0x28, 0xc0, 0xb4, 0xf7, 0xe7, 0x5a, 0xd1, 0xed, 0xb7, 0xf8, 0x89, 0x46, - 0xfb, 0x40, 0xcf, 0xa5, 0x78, 0x6a, 0x0f, 0xcb, 0xa1, 0x30, 0x3c, 0x83, 0x47, 0xec, - 0xee, 0x93, 0xd4, 0x6d, 0x14, 0x0b, 0xb5, 0xf6, 0x95, 0x31, 0xd6, 0x66, 0x54, 0x8b, - 0x10, 0x9c, 0xe7, 0x64, 0xbe, 0xad, 0x7c, 0x87, 0xbd, 0x4c, 0x87, 0x64, 0x94, 0xde, - 0x82, 0xdb, 0x6e, 0x50, 0x73, 0xa6, 0xc9, 0x4f, 0x7c, 0x09, 0x9a, 0x40, 0xd7, 0xa3, - 0x1c, 0x4a, 0x04, 0xb6, 0x9c, 0x9f, 0xcc, 0xf3, 0xc7, 0xdd, 0x56, 0xf5, 0x54, 0x47, - 0x76, 0xc5, 0x3b, 0x4d, 0xf7, 0x95, 0x39, 0x81, 0xd5, 0x5a, 0x96, 0xa6, 0xdc, 0xff, - 0x99, 0x04, 0xa9, 0x08, 0x42, 0xe5, 0xba, 0xfe, 0xc8, 0x84, 0x0c, 0x2d, - ], - script_code: Script(vec![0x53, 0x63, 0x63, 0x51, 0xac, 0x00, 0x51]), - transparent_input: None, - hash_type: 1, - amount: 1345602751504862, - consensus_branch_id: consensus::BranchId::Sapling, - sighash: [ - 0x15, 0x53, 0xd4, 0xf1, 0x07, 0x45, 0x10, 0x71, 0x81, 0x99, 0x00, 0x5f, 0xef, 0xaa, - 0xa8, 0x3e, 0x29, 0xd1, 0x63, 0xee, 0xbd, 0xf3, 0xc0, 0x33, 0x82, 0x79, 0x08, 0xac, - 0xb4, 0x6f, 0xa2, 0x4b, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x00, 0x01, 0x13, 0xf9, 0x12, 0xa5, - 0xdc, 0x0e, 0x00, 0x00, 0x09, 0x53, 0x53, 0xac, 0x63, 0x6a, 0x53, 0x63, 0xac, 0x6a, - 0x2f, 0x2c, 0x3b, 0x86, 0x0e, 0x40, 0xe3, 0x1c, 0x61, 0x8c, 0xa1, 0x7d, 0xf7, 0x15, - 0x04, 0x00, 0x01, 0x21, 0xbf, 0x07, 0x11, 0x5b, 0x3a, 0x39, 0xbb, 0x87, 0xf7, 0x23, - 0x91, 0x52, 0x4b, 0x82, 0x0e, 0xf3, 0x5c, 0xfc, 0x09, 0x58, 0xd4, 0x19, 0x2f, 0x49, - 0x59, 0xef, 0xe4, 0xb9, 0xa7, 0xb5, 0x29, 0x98, 0x8a, 0x3f, 0x7d, 0x27, 0x37, 0x91, - 0x49, 0x0a, 0x6b, 0x48, 0x49, 0x5a, 0x80, 0x06, 0x45, 0x5e, 0x86, 0x57, 0x71, 0xbe, - 0x92, 0x06, 0xd5, 0x4b, 0x43, 0x02, 0x4a, 0xf5, 0xe6, 0xc9, 0x5b, 0x33, 0xf6, 0xda, - 0xd1, 0x66, 0x6a, 0x05, 0xf9, 0x1a, 0xd7, 0x75, 0x79, 0x65, 0xc2, 0x99, 0x36, 0xe7, - 0xfa, 0x48, 0xd7, 0x7e, 0x89, 0xee, 0x09, 0x62, 0xf5, 0x8c, 0x05, 0x1d, 0x11, 0xd0, - 0x55, 0xfc, 0xe2, 0x04, 0xa5, 0x62, 0xde, 0x68, 0x08, 0x8a, 0x1b, 0x26, 0x48, 0xb8, - 0x17, 0x4c, 0xbc, 0xfc, 0x8b, 0x5b, 0x5c, 0xd0, 0x77, 0x11, 0x5a, 0xfd, 0xe1, 0x84, - 0x05, 0x05, 0x4e, 0x5d, 0xa9, 0xa0, 0x43, 0x10, 0x34, 0x2c, 0x5d, 0x3b, 0x52, 0x6e, - 0x0b, 0x02, 0xc5, 0xca, 0x17, 0x22, 0xba, 0xde, 0xee, 0x23, 0xd1, 0x45, 0xe8, 0xeb, - 0x22, 0x13, 0xfc, 0x4a, 0xf1, 0xe4, 0x50, 0xe4, 0xd5, 0x21, 0x7c, 0x66, 0x17, 0x00, - 0x8c, 0x78, 0xf4, 0xfb, 0x11, 0x12, 0xf4, 0x02, 0x8a, 0x70, 0x4f, 0xc5, 0xa9, 0x38, - 0x2c, 0x6b, 0x03, 0xe7, 0xd8, 0x08, 0x5e, 0x90, 0x6c, 0xf8, 0x4c, 0xa2, 0xc1, 0x20, - 0x7c, 0x87, 0xa2, 0xbc, 0xe2, 0x08, 0x0a, 0x98, 0x91, 0x66, 0x8d, 0x69, 0xb0, 0x44, - 0xbe, 0xce, 0xd6, 0xcd, 0xa3, 0x2c, 0x22, 0x9c, 0x91, 0x17, 0x91, 0x7a, 0xa0, 0x7d, - 0xdf, 0xfc, 0xd3, 0x77, 0x39, 0x5c, 0xba, 0x61, 0x6d, 0x63, 0xc0, 0xb6, 0x9c, 0x01, - 0xfc, 0xc4, 0x53, 0x91, 0xfd, 0x5b, 0x87, 0x63, 0xfb, 0x96, 0xd7, 0xca, 0x33, 0x3a, - 0x12, 0xde, 0x3c, 0xef, 0xa9, 0x1c, 0x6c, 0x98, 0xf9, 0x47, 0x3b, 0x8e, 0x10, 0x4a, - 0x71, 0x29, 0x3e, 0x46, 0x37, 0x47, 0x05, 0xba, 0xf6, 0x5f, 0xa4, 0x13, 0x84, 0xba, - 0x5c, 0x8e, 0x0c, 0x88, 0xa3, 0xeb, 0x07, 0xe0, 0xbe, 0x34, 0xda, 0xdd, 0xfa, 0xbb, - 0x7b, 0x65, 0x54, 0x3b, 0x5f, 0x39, 0xcb, 0x20, 0x23, 0xd4, 0x67, 0x89, 0xeb, 0x7d, - 0x98, 0x9a, 0xf7, 0x79, 0xe5, 0xb8, 0xd2, 0x83, 0x85, 0xa8, 0x5b, 0x0d, 0xa2, 0xab, - 0xe0, 0x7f, 0x0c, 0x2b, 0xb4, 0x25, 0x5f, 0xce, 0xa0, 0x31, 0x88, 0x52, 0x7a, 0x30, - 0x7d, 0x40, 0x91, 0x59, 0xe9, 0x01, 0x66, 0xfa, 0xc6, 0xa0, 0x70, 0xba, 0x05, 0xb3, - 0xe4, 0xdb, 0xfd, 0x3a, 0x2b, 0xfc, 0xc9, 0xee, 0x6e, 0xd0, 0x16, 0xc0, 0xf6, 0x65, - 0xbe, 0x81, 0x33, 0xb7, 0xdc, 0x1d, 0x86, 0x04, 0x4d, 0xb0, 0xf9, 0xdb, 0x40, 0xfb, - 0x0e, 0x9f, 0x8b, 0xc2, 0xe4, 0xdb, 0x53, 0x82, 0xa8, 0x04, 0x53, 0xfd, 0xd8, 0x8f, - 0x52, 0xb0, 0x59, 0xc7, 0x96, 0x49, 0x43, 0xc1, 0xc0, 0xdf, 0x3b, 0x6b, 0x64, 0x10, - 0xf9, 0x5d, 0xef, 0x5c, 0x04, 0x78, 0xf6, 0x85, 0xc6, 0xb3, 0x3a, 0xa0, 0xc8, 0x8e, - 0x68, 0x82, 0x42, 0x8e, 0x8c, 0xba, 0x43, 0x64, 0xea, 0x93, 0xaf, 0x37, 0x8c, 0x50, - 0x64, 0x82, 0x27, 0x36, 0x58, 0xa2, 0xc0, 0x95, 0xdd, 0x07, 0x6c, 0x39, 0x73, 0x19, - 0x1d, 0x46, 0xa1, 0x03, 0x9e, 0x5d, 0x6b, 0x7d, 0x9c, 0x08, 0x6b, 0x25, 0x85, 0x90, - 0xd3, 0x2d, 0x76, 0xe3, 0xd4, 0x20, 0x38, 0x43, 0x57, 0x0e, 0xfe, 0xed, 0x97, 0x1c, - 0x14, 0x12, 0x2f, 0x5b, 0x21, 0x5b, 0x0f, 0x38, 0xbb, 0xc7, 0x16, 0xb6, 0xa5, 0x94, - 0x4e, 0xe7, 0x27, 0x96, 0x56, 0x90, 0xe2, 0x09, 0xb4, 0x9e, 0xb9, 0x62, 0xc0, 0x39, - 0x97, 0x5f, 0x93, 0x9e, 0xd5, 0xc6, 0xe4, 0xc4, 0x00, 0xd8, 0x87, 0x75, 0x94, 0x33, - 0xd3, 0xad, 0x71, 0x6d, 0xa0, 0xcb, 0x44, 0x61, 0x13, 0xc7, 0x72, 0x7a, 0x64, 0xb5, - 0x8c, 0x3f, 0x8a, 0x0f, 0x81, 0x18, 0x9f, 0x98, 0x00, 0x52, 0x33, 0xa8, 0x13, 0x66, - 0xae, 0xe7, 0x3c, 0xec, 0x85, 0x22, 0x8e, 0xbc, 0xfd, 0x5e, 0xe3, 0xc3, 0xfb, 0x44, - 0xdb, 0x76, 0xba, 0x24, 0x3f, 0x28, 0x42, 0xb7, 0xb5, 0xfc, 0x74, 0x6a, 0xe5, 0x1b, - 0x0b, 0xc4, 0xbd, 0x4f, 0xc9, 0xfd, 0x83, 0x35, 0x65, 0xea, 0x85, 0x2b, 0x92, 0xb2, - 0x24, 0xf6, 0x99, 0x03, 0x18, 0xad, 0x8c, 0x7d, 0x94, 0x37, 0xe2, 0x0e, 0x2a, 0x1f, - 0x20, 0xe8, 0x18, 0xf9, 0x05, 0x7c, 0x5a, 0xba, 0xaa, 0x2e, 0x5c, 0x15, 0xb9, 0x49, - 0x45, 0xcd, 0x42, 0x4c, 0x28, 0xa5, 0xfa, 0x38, 0x5d, 0xad, 0xfe, 0x49, 0x07, 0xb2, - 0x74, 0xd8, 0x42, 0x70, 0x7d, 0xb3, 0x69, 0x7a, 0x5a, 0xe6, 0xc8, 0xf5, 0x42, 0xe5, - 0xec, 0xc0, 0x7f, 0xe4, 0x73, 0x50, 0xd1, 0x01, 0x46, 0x70, 0x21, 0x2e, 0xfe, 0x81, - 0xfb, 0x7c, 0x73, 0xe8, 0x45, 0x0d, 0xf8, 0x14, 0xef, 0x62, 0x32, 0xf7, 0x49, 0x0f, - 0x63, 0xcc, 0xf0, 0x74, 0x80, 0xf8, 0x84, 0xa6, 0x6e, 0xaf, 0xfc, 0x28, 0xfe, 0xa4, - 0x48, 0xd7, 0xb4, 0x01, 0xcd, 0xae, 0x10, 0xe7, 0xc0, 0xc7, 0xf9, 0xa7, 0xb1, 0x53, - 0x31, 0x96, 0x9f, 0xc8, 0xcb, 0x36, 0x39, 0x67, 0x73, 0xde, 0x19, 0x19, 0x31, 0xc7, - 0x50, 0xf6, 0xce, 0x5c, 0xaa, 0xf2, 0x97, 0x68, 0xeb, 0xb2, 0x7d, 0xac, 0xc7, 0x38, - 0x05, 0x6a, 0x81, 0x25, 0xb4, 0x77, 0x2b, 0xf8, 0x7a, 0xe1, 0x0a, 0x8a, 0x30, 0x9b, - 0x9b, 0xd6, 0x55, 0x04, 0x3c, 0xfc, 0x31, 0x59, 0x49, 0x43, 0x68, 0xc5, 0xab, 0x8c, - 0xad, 0xb7, 0xf6, 0x71, 0xe9, 0x62, 0x6b, 0xd2, 0x63, 0xe3, 0x11, 0x81, 0xa6, 0x04, - 0xb5, 0x06, 0xa0, 0x3b, 0x43, 0x9a, 0x7f, 0xfe, 0x43, 0x55, 0x89, 0x24, 0x77, 0xe2, - 0xbd, 0xf3, 0x38, 0xc6, 0x2c, 0x39, 0x22, 0xf7, 0xd3, 0xc9, 0xa5, 0x6c, 0x71, 0x03, - 0xd9, 0x11, 0x94, 0x8a, 0x84, 0xb5, 0xae, 0x2d, 0xbb, 0x16, 0xa3, 0x76, 0x1a, 0xdd, - 0x05, 0x3a, 0x0f, 0x96, 0x7e, 0x6b, 0x5b, 0xc9, 0x42, 0x11, 0xb6, 0x54, 0x71, 0x53, - 0x26, 0x7c, 0x6e, 0xe1, 0xca, 0xd0, 0xd9, 0x74, 0xa7, 0x10, 0x88, 0x58, 0x37, 0x35, - 0xe4, 0xf6, 0x3d, 0x33, 0x15, 0x6d, 0xad, 0xd5, 0x4c, 0x2f, 0xaf, 0x89, 0x11, 0x4a, - 0x12, 0x7b, 0x97, 0xb9, 0x4c, 0xc2, 0xa2, 0x2e, 0xf3, 0x03, 0xf4, 0x59, 0xd0, 0x4f, - 0xc0, 0xb5, 0x3a, 0xce, 0x59, 0x18, 0xd4, 0x7f, 0xf3, 0x3a, 0x55, 0x8b, 0xd7, 0x1a, - 0x75, 0xf3, 0x55, 0xfb, 0xd0, 0x6b, 0xbc, 0xcf, 0x4e, 0x02, 0xc3, 0xc0, 0xa4, 0xb6, - 0x3d, 0x0c, 0xc9, 0x49, 0x80, 0x1d, 0x63, 0xa6, 0x4c, 0xb2, 0xd3, 0x23, 0x73, 0xb2, - 0xc7, 0xb2, 0x74, 0xab, 0x2d, 0xb4, 0x68, 0x21, 0x42, 0xc8, 0xb2, 0x1d, 0x84, 0xc4, - 0x81, 0xf5, 0xef, 0x21, 0xe4, 0xb5, 0xe3, 0x60, 0x34, 0x51, 0xbf, 0x94, 0x77, 0x4d, - 0x0e, 0xf4, 0x7f, 0x63, 0xfa, 0x6a, 0xbb, 0x78, 0xd2, 0x1c, 0x19, 0x3c, 0xbe, 0x65, - 0xb6, 0x95, 0xfe, 0x67, 0x42, 0x3c, 0x1e, 0x2d, 0x31, 0x2e, 0x27, 0x76, 0xfa, 0x24, - 0xec, 0xe8, 0x46, 0x83, 0xe7, 0x48, 0x76, 0xc5, 0x5e, 0xa0, 0x36, 0x9e, 0x4e, 0xa0, - 0xe8, 0x64, 0x94, 0xe0, 0x0d, 0xde, 0x23, 0x6a, 0x16, 0x89, 0x73, 0x1f, 0x0a, 0x5d, - 0x82, 0x03, 0xaf, 0xde, 0x5c, 0x42, 0x36, 0x40, 0xb8, 0x1e, 0x4f, 0x63, 0x1c, 0x98, - 0x1c, 0x11, 0xa2, 0xe1, 0xd1, 0x84, 0xc6, 0x7c, 0x52, 0x8d, 0xf9, 0x2d, 0x53, 0xae, - 0xc4, 0x4a, 0x40, 0xa4, 0xea, 0x2a, 0x13, 0x1b, 0x47, 0x33, 0xcf, 0xe4, 0x5c, 0x6b, - 0x00, 0x12, 0xc3, 0xe9, 0xe2, 0x09, 0x75, 0xba, 0xae, 0xcb, 0x02, 0x32, 0xdf, 0x88, - 0x0b, 0xd7, 0xd1, 0xde, 0x13, 0xe1, 0x34, 0x94, 0x62, 0xec, 0x8d, 0x5d, 0xf3, 0xe7, - 0x80, 0xff, 0xa7, 0x2e, 0xba, 0x8a, 0x8d, 0xf7, 0xfc, 0xf3, 0x98, 0xec, 0x23, 0x05, - 0x13, 0xca, 0x9d, 0x61, 0x23, 0xf8, 0xb9, 0xd8, 0x17, 0x85, 0x60, 0xda, 0xf9, 0x75, - 0x11, 0x19, 0x55, 0xa2, 0xbc, 0xa3, 0x42, 0x3e, 0xee, 0xfc, 0x52, 0x7b, 0xe3, 0xa8, - 0x54, 0x3e, 0xb9, 0x0a, 0x5e, 0xc0, 0x2f, 0x35, 0xa7, 0xc6, 0x4b, 0x7d, 0xd5, 0x9a, - 0x72, 0xda, 0x00, 0x74, 0x63, 0x4e, 0x01, 0xd2, 0xab, 0xf3, 0x63, 0x7a, 0xdd, 0x77, - 0xc7, 0x35, 0x0f, 0x12, 0xb0, 0x11, 0xb2, 0x94, 0x16, 0x8e, 0xc7, 0x55, 0x76, 0xe4, - 0x7d, 0x16, 0x9e, 0x39, 0x38, 0xbf, 0x6a, 0xe2, 0xaa, 0x8f, 0xf7, 0xcf, 0xba, 0x7c, - 0xac, 0xb1, 0xf9, 0x2b, 0x6e, 0x4c, 0x24, 0x97, 0xbf, 0xfa, 0x9f, 0x17, 0xca, 0xd2, - 0x42, 0xfa, 0x9c, 0x31, 0x79, 0xc1, 0xa3, 0xaa, 0x81, 0xf7, 0x36, 0x16, 0x49, 0x57, - 0x2c, 0x71, 0x5c, 0x25, 0xa1, 0xf6, 0xcd, 0x5a, 0xce, 0x82, 0xc0, 0x0a, 0xb2, 0x34, - 0x2b, 0x9c, 0x3c, 0xb4, 0xff, 0xfd, 0xda, 0x16, 0x0c, 0xa5, 0xab, 0x9e, 0x9b, 0xaf, - 0x21, 0x39, 0xef, 0x9a, 0xfb, 0xe1, 0xb1, 0xf3, 0x09, 0x46, 0x2a, 0xfc, 0xe4, 0x62, - 0xa7, 0x9b, 0xb9, 0x69, 0x8e, 0x22, 0xc9, 0x57, 0xc5, 0x90, 0xa7, 0x53, 0xa7, 0x6b, - 0x87, 0xe0, 0x09, 0x12, 0x1e, 0x06, 0xf6, 0xa1, 0xbf, 0x62, 0xa0, 0x8b, 0xf4, 0x35, - 0xd9, 0x2e, 0x2f, 0xff, 0xe8, 0x6e, 0x2a, 0x9c, 0xbb, 0xa9, 0x13, 0x3a, 0x68, 0xe4, - 0xae, 0xbf, 0x33, 0xc3, 0x84, 0x36, 0xf2, 0x54, 0x5f, 0xc2, 0xd5, 0x28, 0x32, 0xd1, - 0x65, 0xaf, 0x41, 0x5b, 0x24, 0x4a, 0xdc, 0x5f, 0x57, 0x37, 0x7d, 0xee, 0xdf, 0x46, - 0x0a, 0xa3, 0xbe, 0xb4, 0x34, 0x19, 0xc6, 0xb0, 0x82, 0xe8, 0x35, 0xce, 0x84, 0xca, - 0x13, 0xb6, 0x90, 0x8a, 0x88, 0x13, 0xc0, 0x21, 0xde, 0x9f, 0xa9, 0xa4, 0x4e, 0x4c, - 0x18, 0xdc, 0xb3, 0xd2, 0x1f, 0xaa, 0x8b, 0x86, 0xc8, 0x70, 0x28, 0xd0, 0xb5, 0x53, - 0x21, 0x07, 0xf9, 0xf6, 0xfd, 0x49, 0x00, 0x22, 0x7d, 0x0d, 0x8f, 0xf2, 0xbf, 0x9d, - 0x28, 0xcb, 0xcc, 0x99, 0x6c, 0x47, 0x3c, 0xe6, 0x16, 0x41, 0xf4, 0x88, 0x4e, 0x6e, - 0xd3, 0xfd, 0x5e, 0x4b, 0x7c, 0xb8, 0x35, 0xb8, 0x33, 0x08, 0x96, 0x4e, 0x3c, 0x46, - 0x87, 0x3f, 0xd6, 0x13, 0x31, 0x7b, 0x91, 0xd2, 0x92, 0x36, 0xea, 0x90, 0xe3, 0x65, - 0x32, 0xec, 0x5d, 0x6b, 0x42, 0x32, 0xe8, 0xbc, 0xcc, 0x36, 0x75, 0xb9, 0x8b, 0x35, - 0xf8, 0xde, 0x4d, 0x08, 0x88, 0x84, 0x14, 0x6f, 0x3d, 0xb8, 0x97, 0x0b, 0x38, 0xd1, - 0xe5, 0x01, 0xae, 0xe9, 0xc1, 0xf3, 0xfd, 0x78, 0x25, 0x49, 0xd3, 0xf3, 0x24, 0x57, - 0x59, 0x60, 0x6d, 0x9f, 0x92, 0xd5, 0x54, 0x8a, 0xcf, 0xea, 0xdb, 0xaf, 0x9c, 0xaa, - 0x6b, 0x93, 0xdc, 0x08, 0x82, 0x8d, 0x74, 0xf6, 0xd5, 0xfd, 0xd8, 0x33, 0x31, 0xf0, - 0x96, 0x91, 0x45, 0x95, 0x52, 0x97, 0xe6, 0x9f, 0x00, 0xfd, 0x29, 0x87, 0xf2, 0xda, - 0x2b, 0x94, 0xb9, 0x95, 0xfe, 0xcb, 0xe6, 0x22, 0xa7, 0x35, 0xef, 0x7f, 0x12, 0x07, - 0xf6, 0x71, 0x62, 0x94, 0x89, 0x20, 0x2b, 0xea, 0x0b, 0x47, 0x5e, 0x51, 0x68, 0x1a, - 0xa1, 0x67, 0x78, 0xb3, 0x9b, 0xd9, 0x23, 0xc9, 0x8d, 0xc6, 0xff, 0x83, 0x73, 0xc7, - 0x9b, 0xb1, 0x70, 0x30, 0x41, 0x7b, 0xc2, 0x00, 0xc8, 0xf0, 0xb8, 0x55, 0xac, 0xfe, - 0xc1, 0x79, 0xf7, 0x67, 0x4c, 0xec, 0x27, 0x21, 0xa1, 0x0f, 0xca, 0x69, 0x3d, 0x83, - 0xcf, 0xe5, 0xb8, 0xcd, 0xcc, 0x18, 0xf8, 0x1a, 0xd6, 0x17, 0xfa, 0x26, 0xf0, 0xdf, - 0xb8, 0x36, 0x55, 0xb8, 0xa2, 0x9a, 0x7f, 0x83, 0x42, 0x32, 0x42, 0x5e, 0x8c, 0x47, - 0x45, 0x88, 0xf1, 0x8d, 0xd3, 0x26, 0xaa, 0x39, 0x6c, 0x3e, 0x47, 0x75, 0xe0, 0x02, - 0x05, 0xfc, 0x9e, 0x45, 0xf7, 0xb7, 0xd2, 0xe6, 0xd5, 0x5d, 0xcb, 0x90, 0xe2, 0x3f, - 0xf6, 0xb5, 0x08, 0x45, 0x9a, 0xa6, 0x99, 0xbf, 0xcb, 0xd5, 0x6f, 0x10, 0x99, 0x77, - 0x64, 0xd0, 0x87, 0x40, 0x89, 0x86, 0xe7, 0x3d, 0x6e, 0x28, 0x4f, 0xea, 0x9a, 0x23, - 0xc3, 0x93, 0x11, 0x78, 0x2f, 0x86, 0xca, 0xbf, 0xf9, 0x45, 0x5e, 0x4c, 0xf6, 0x99, - 0xe5, 0xf5, 0xd4, 0xbc, 0x0b, 0x39, 0x05, 0xa4, 0xe3, 0xbd, 0x01, 0xc5, 0x4d, 0xf8, - 0x64, 0x34, 0x43, 0xbe, 0x0f, 0x88, 0x90, 0x32, 0xea, 0x32, 0x5b, 0xf0, 0x71, 0x07, - 0xfd, 0x41, 0xd6, 0x73, 0xee, 0xba, 0xe6, 0xfa, 0x63, 0x7b, 0x70, 0xcc, 0x0e, 0xd3, - 0xf0, 0x09, 0x58, 0xdf, 0xb8, 0xdc, 0xf0, 0x0e, 0x85, 0xa1, 0xd0, 0xa6, 0xa8, 0x90, - 0x81, 0x40, 0xc2, 0xf4, 0x34, 0xc2, 0xe2, 0x60, 0xef, 0xb0, 0xbc, 0xa2, 0x00, 0x35, - 0x04, 0xc9, 0x99, 0x93, 0xa9, 0xe1, 0xc0, 0xff, 0x9c, 0xef, 0xe6, 0xa6, 0x65, 0xd7, - 0x91, 0x42, 0x86, 0x90, 0xe4, 0x7e, 0xf8, 0xc1, 0x31, 0xa8, 0xe9, 0xbf, 0xb4, 0xc3, - 0x08, 0x02, 0x35, 0x03, 0x2d, 0x73, 0x1b, 0x0d, 0x38, 0x41, 0x22, 0x5f, 0x1c, 0x11, - 0xe2, 0xc2, 0x8e, 0xe8, 0x4d, 0x35, 0xf9, 0x22, 0x61, 0x00, 0x56, 0x59, 0x72, 0xeb, - 0x26, 0x9d, 0x27, 0x8e, 0xf6, 0x49, 0x79, 0xbf, 0x65, 0x15, 0xed, 0x4a, 0x68, 0x40, - 0xb0, 0x88, 0x3a, 0x9e, 0x6e, 0xf6, 0x4a, 0x0e, 0xfc, 0xae, 0x1c, 0xf2, 0x1d, 0xfe, - 0x74, 0x85, 0x4e, 0x84, 0xc2, 0x74, 0x9f, 0xac, 0x03, 0x82, 0x52, 0x75, 0xc9, 0xb6, - 0x30, 0x21, 0x84, 0xc7, 0x2d, 0xf4, 0xc4, 0xbb, 0x28, 0x62, 0xe4, 0xe8, 0xa7, 0xd9, - 0xa4, 0xa2, 0x82, 0x86, 0x6f, 0x9a, 0x7b, 0x2c, 0xfc, 0x9a, 0x56, 0x31, 0x3d, 0xa0, - 0xc4, 0x7a, 0x34, 0xb7, 0xb9, 0xcd, 0xa3, 0xac, 0xe8, 0x18, 0x5f, 0x07, 0xdf, 0x36, - 0xe4, 0x48, 0xa7, 0x6a, 0xa4, 0x77, 0xf2, 0x24, 0xd8, 0x7a, 0x07, 0x4f, 0x43, 0xaf, - 0x5d, 0x5f, 0x79, 0xb3, 0xab, 0x11, 0x28, 0xf0, 0x81, 0x91, 0x44, 0x7f, 0xa6, 0x46, - 0xbf, 0xdd, 0xe5, 0xb5, 0x1e, 0x23, 0x3c, 0xa6, 0x15, 0x5d, 0x10, 0x15, 0x85, 0xbc, - 0x2c, 0x40, 0x15, 0x8a, 0xc2, 0x10, 0x6e, 0x66, 0xa2, 0x6e, 0x46, 0x42, 0x33, 0x70, - 0x63, 0x68, 0x76, 0xb4, 0x34, 0xa7, 0x4f, 0x8c, 0xe8, 0x06, 0x00, 0x50, 0xb0, 0x82, - 0xa7, 0x9b, 0x61, 0xbb, 0x5d, 0x34, 0x4e, 0xb5, 0xa1, 0x15, 0x83, 0x26, 0xce, 0xd9, - 0xa9, 0xd9, 0xf5, 0x4f, 0xb2, 0xfe, 0x8f, 0x9f, 0x05, 0xcd, 0x11, 0x1e, 0xe4, 0x6c, - 0x47, 0x10, 0xf6, 0xf6, 0x3a, 0x62, 0x69, 0x45, 0x57, 0xef, 0x1b, 0x12, 0xc8, 0x80, - 0x06, 0xb6, 0x78, 0x72, 0x50, 0x5f, 0x4e, 0x88, 0x3b, 0x58, 0x59, 0x07, 0x92, 0x9a, - 0x2f, 0x3f, 0xdb, 0x0d, 0x8f, 0x79, 0x14, 0xc4, 0x2d, 0xde, 0x2d, 0x20, 0x00, 0xf5, - 0xae, 0x02, 0xd4, 0x18, 0x21, 0xc8, 0xe1, 0xee, 0x01, 0x38, 0xeb, 0xcb, 0x72, 0x8d, - 0x7c, 0x6c, 0x3c, 0x80, 0x02, 0x7e, 0x43, 0x75, 0x94, 0xc6, 0x70, 0xfd, 0x6f, 0x39, - 0x08, 0x22, 0x2e, 0xe7, 0xa1, 0xb9, 0x17, 0xf8, 0x27, 0x1a, 0xbe, 0x66, 0x0e, 0x39, - 0xe0, 0x51, 0xaa, 0xa6, 0xfc, 0xa1, 0x86, 0x22, 0x76, 0xe2, 0xba, 0xa0, 0xfe, 0x0b, - 0x16, 0x2a, 0xeb, 0xcf, 0xe3, 0xd9, 0x34, 0x9c, 0x8d, 0x15, 0x4b, 0xb7, 0xee, 0x28, - 0x21, 0x2c, 0x1b, 0xaa, 0x70, 0x5d, 0x82, 0x07, 0x0d, 0x70, 0x32, 0xf2, 0x69, 0x5d, - 0x17, 0x96, 0x80, 0x9f, 0xab, 0x41, 0x24, 0x69, 0x26, 0xaf, 0x99, 0x2b, 0x6e, 0xee, - 0x95, 0xa9, 0xa0, 0x6b, 0xc4, 0x56, 0x2c, 0x5f, 0x2f, 0x1b, 0x19, 0x54, 0x95, 0x00, - 0x37, 0x2e, 0x7a, 0xd5, 0x79, 0xa6, 0xd6, 0xd7, 0x8b, 0x33, 0x15, 0x31, 0x30, 0xfb, - 0x44, 0x8f, 0xb7, 0x9e, 0x8a, 0x66, 0x9d, 0xb8, 0xa0, 0xf3, 0x5c, 0xdf, 0x9a, 0xe5, - 0xd3, 0x2d, 0x73, 0x2f, 0xc7, 0x94, 0x18, 0xe2, 0x3b, 0x45, 0x1d, 0xdc, 0x95, 0xa2, - 0x2a, 0xba, 0xbb, 0x05, 0x6e, 0xc6, 0xb5, 0xe8, 0xba, 0x4f, 0x52, 0x4d, 0xfa, 0xfe, - 0x87, 0x52, 0x62, 0xdd, 0x7b, 0xe4, 0x1c, 0xbb, 0xc6, 0x24, 0x20, 0xd4, 0xad, 0x6d, - 0xf5, 0xc9, 0xb7, 0x13, 0x60, 0x4f, 0x65, 0x60, 0x88, 0xa4, 0x48, 0x5e, 0x93, 0xbe, - 0x19, 0x07, 0xd2, 0x7a, 0xc6, 0xec, 0x3c, 0x57, 0x25, 0x9b, 0xd6, 0x98, 0x1d, 0x42, - 0xc1, 0xb7, 0x8a, 0x29, 0xad, 0x96, 0x85, 0xe6, 0x3c, 0x49, 0x4d, 0x41, 0x29, 0x62, - 0x3e, 0xa1, 0xa7, 0xff, 0xec, 0x85, 0xfa, 0x29, 0x41, 0x10, 0x73, 0xed, 0xb2, 0x97, - 0x8e, 0xf4, 0xe4, 0x69, 0xdd, 0xd5, 0xcd, 0xa9, 0x86, 0x18, 0x99, 0x95, 0xf8, 0x8d, - 0x6a, 0xb3, 0x66, 0xdb, 0x01, 0x90, 0x01, 0xf5, 0xb2, 0x52, 0x88, 0xcf, 0x86, 0x0f, - 0xd9, 0x98, 0xee, 0x57, 0x3c, 0x8c, 0xc4, 0x8a, 0xa9, 0xef, 0xcf, 0x9b, 0x61, 0x7e, - 0x04, 0x3c, 0x99, 0x00, 0x8e, 0x35, 0x00, 0x96, 0xfd, 0xa4, 0xeb, 0x24, 0xc2, 0x0f, - 0x46, 0x90, 0xf1, 0xe2, 0xc5, 0xef, 0x86, 0x6c, 0x0e, 0xe5, 0xdd, 0xa1, 0x19, 0xee, - 0xea, 0xf1, 0x19, 0xdb, 0xdc, 0xae, 0x8d, 0xc7, 0x6c, 0x84, 0x6c, 0xc2, 0x27, 0x27, - 0x2b, 0xfc, 0x54, 0x17, 0xdc, 0x4c, 0xf4, 0xc0, 0x87, 0xba, 0x34, 0xec, 0xf3, 0xa5, - 0x5b, 0x00, 0x1f, 0xf3, 0x09, 0xa8, 0x1c, 0x05, 0x2d, 0x69, 0x26, 0xa9, 0xdd, 0xf0, - 0xf7, 0x8c, 0x5f, 0xc0, 0x64, 0xc6, 0xa6, 0x40, 0x16, 0x21, 0xb3, 0x8a, 0xa5, 0x49, - 0x44, 0x19, 0x81, 0x99, 0x21, 0x0d, 0x2b, 0x42, 0xe6, 0x1d, 0xde, 0x1d, 0x08, 0xaf, - 0x55, 0x07, 0x3b, 0xbf, 0x06, 0x15, 0xf6, 0x7b, 0x11, 0x00, 0xcc, 0x2e, 0xa3, 0xba, - 0x3d, 0x6c, 0x1a, 0x1a, 0x90, 0x87, 0xb1, 0x19, 0xba, 0xee, 0xbf, 0xa6, 0x2b, 0xc9, - 0xf0, 0xec, 0x47, 0x9d, 0x99, 0xc1, 0xa3, 0xb1, 0x58, 0xb5, 0x14, 0xd1, 0x62, 0x9d, - 0xb3, 0x99, 0x3f, 0x11, 0x67, 0x2a, 0x26, 0x70, 0x8e, 0x5a, 0xd8, 0x16, 0xb5, 0x47, - 0xab, 0x7e, 0x82, 0x7d, 0x07, 0x1b, 0xa7, 0x84, 0x2b, 0x3e, 0x90, 0x30, 0x53, 0x83, - 0x89, 0x6e, 0xc4, 0x90, 0x5f, 0x70, 0xc7, 0x8b, 0x69, 0x4e, 0x6a, 0x5a, 0x3e, 0x43, - 0x12, 0xcd, 0x82, 0x08, 0x13, 0x2b, 0x84, 0x0f, 0x05, 0xc7, 0x14, 0x52, 0x3c, 0xa8, - 0x19, 0x72, 0x0a, 0xe2, 0x27, 0xfd, 0x1a, 0xcb, 0xa7, 0x14, 0xfa, 0x4f, 0xc4, 0x5f, - 0xc5, 0x39, 0x88, 0x57, 0xb4, 0x0d, 0xc1, 0x48, 0x79, 0x85, 0x6f, 0x35, 0x4b, 0xa4, - 0xd2, 0x58, 0x1d, 0x0c, 0xda, 0x54, 0xb6, 0x38, 0xba, 0x9d, 0x76, 0xf9, 0xb5, 0x2d, - 0x17, 0xc8, 0xf8, 0x8e, 0xe6, 0x3f, 0x58, 0x45, 0xb5, 0xdc, 0xef, 0xa4, 0xc3, 0x47, - 0x9b, 0xce, 0x9a, 0xca, 0xd1, 0x8b, 0x4a, 0xea, 0xe0, 0x3c, 0x0e, 0xae, 0x22, 0x5d, - 0x42, 0x84, 0x8b, 0xde, 0xaa, 0x53, 0x6d, 0x7d, 0x8d, 0xd3, 0xbc, 0x97, 0x9f, 0x06, - 0x58, 0x66, 0x73, 0xbc, 0x6f, 0xf1, 0xc5, 0xd3, 0xb3, 0x20, 0xf3, 0x49, 0xa5, 0xb3, - 0xa8, 0xb3, 0x55, 0x59, 0x22, 0x96, 0xaa, 0xf6, 0x1c, 0x5b, 0x72, 0x52, 0xf7, 0x3e, - 0xc0, 0xa9, 0x46, 0x6a, 0x1b, 0x85, 0x76, 0x4f, 0xb0, 0x83, 0x1b, 0x4a, 0x1a, 0x36, - 0x89, 0x0e, 0x22, 0x4c, 0x01, 0xac, 0xfc, 0xe4, 0x8e, 0xe3, 0xed, 0x93, 0x87, 0x73, - 0x98, 0xe0, 0x72, 0x6d, 0x02, 0x93, 0x6d, 0x0d, 0x03, 0x2e, 0x18, 0xe3, 0x28, 0x8b, - 0x26, 0x70, 0xe1, 0x36, 0x2c, 0x32, 0xd6, 0xe4, 0x73, 0x3b, 0x9d, 0xd2, 0xd5, 0xf2, - 0x6e, 0x1f, 0xe3, 0x06, 0xf7, 0x3c, 0x00, 0x7f, 0xdd, 0xca, 0xe9, 0xd9, 0xc0, 0xaa, - 0xf1, 0x87, 0xd7, 0x42, 0x8b, 0x1e, 0x9d, 0x47, 0x9c, 0x18, 0x23, 0x7b, 0x98, 0x28, - 0xbc, 0xa8, 0xb9, 0x8c, 0x9d, 0x9b, 0xec, 0x7d, 0x82, 0x70, 0xb5, 0xd8, 0xee, 0xc3, - 0xcc, 0x4f, 0x43, 0xfa, 0x01, 0x88, 0x52, 0x1b, 0xc6, 0x1b, 0x21, 0xdd, 0x04, 0xe3, - 0x7a, 0x83, 0xec, 0xe6, 0x8c, 0xa7, 0xa2, 0xfa, 0x6c, 0x8f, 0x9e, 0x34, 0xa6, 0x29, - 0x03, 0x35, 0xaa, 0x1f, 0xbd, 0x83, 0xd5, 0x4a, 0xaf, 0x44, 0x1e, 0x31, 0x9e, 0xa4, - 0x7a, 0x86, 0x2a, 0xd0, 0x29, 0x3c, 0xed, 0xf5, 0xdd, 0x9e, 0xda, 0xde, 0xee, 0x33, - 0xcb, 0x52, 0x2c, 0xd0, 0x11, 0x8b, 0xbd, 0x81, 0x1a, 0xce, 0x9a, 0x23, 0xbd, 0xa3, - 0x9a, 0xba, 0x72, 0xf1, 0x56, 0x6f, 0xc1, 0x68, 0x84, 0x97, 0xd2, 0xa7, 0x92, 0x8c, - 0x36, 0x70, 0x15, 0x25, 0x67, 0x8b, 0xc9, 0x72, 0x14, 0xb3, 0x1b, 0x37, 0xba, 0xb4, - 0x6b, 0x88, 0xf2, 0x7f, 0x04, 0x48, 0xde, 0xcb, 0x31, 0x62, 0x2d, 0x0f, 0x0f, 0x87, - 0xa8, 0x55, 0xba, 0x54, 0x00, 0x03, 0x32, 0x03, 0x1f, 0x73, 0xab, 0xff, 0xd4, 0x65, - 0x91, 0xda, 0x0b, 0x88, 0x72, 0x35, 0x04, 0xed, 0xb2, 0x33, 0x72, 0x30, 0xda, 0xd2, - 0xac, 0xc0, 0xd8, 0xbb, 0x68, 0xbc, 0x83, 0x7a, 0x2f, 0xf9, 0x30, 0xbf, 0xf0, 0x6f, - 0xde, 0x74, 0xeb, 0x90, 0xaa, 0xe4, 0xf6, 0x0d, 0xbb, 0x6e, 0xb8, 0x27, 0xea, 0x99, - 0x88, 0x4a, 0xcd, 0x62, 0x85, 0xa9, 0x88, 0x92, 0x80, 0x2c, 0xf5, 0x9d, 0x5d, 0x60, - 0xd0, 0x16, 0x63, 0x38, 0x7b, 0x3e, 0xd2, 0x72, 0x3b, 0xd6, 0x48, 0x9e, 0x9c, 0x2c, - 0x10, 0x6d, 0x4a, 0xa2, 0xde, 0x23, 0xce, 0xd1, 0x6c, 0x72, 0x04, 0x29, 0xc7, 0x75, - 0x3a, 0x77, 0x38, 0xec, 0x7d, 0x9d, 0xb8, 0x62, 0x42, 0x29, 0xed, 0xd2, 0x17, 0xb8, - 0x0d, 0x74, 0x87, 0x5a, 0x14, 0xca, 0xe4, 0x86, 0x3f, 0x13, 0x9e, 0x9c, 0x0b, 0x13, - 0x1b, 0x2a, 0x4c, 0x28, 0x07, 0x1a, 0x38, 0xec, 0x61, 0xf6, 0x68, 0x01, 0xaa, 0x59, - 0x56, 0xfc, 0xb2, 0xa4, 0x6b, 0x95, 0x87, 0x66, 0x5b, 0x75, 0x71, 0xaa, 0x03, 0x48, - 0x1f, 0xd8, 0xd9, 0xd5, 0x69, 0x8f, 0x83, 0x6f, 0xc8, 0x63, 0x5e, 0x69, 0xe3, 0xbd, - 0xe4, 0x2f, 0x4a, 0xc0, 0x71, 0x32, 0x8b, 0x54, 0x09, 0xf6, 0xe4, 0x2d, 0x79, 0x0a, - 0xed, 0xd7, 0x3b, 0xc1, 0xa2, 0x35, 0x47, 0x23, 0xb3, 0xb8, 0x19, 0xd0, 0x63, 0x7a, - 0x6f, 0xa4, 0x66, 0x39, 0x46, 0xa3, 0x0a, 0xc5, 0xaf, 0xdd, 0x30, 0xce, 0x83, 0x0f, - 0x67, 0x91, 0xb4, 0x57, 0x52, 0x70, 0xa1, 0x72, 0x0f, 0x91, 0x86, 0x6e, 0x2b, 0x86, - 0xf4, 0x78, 0x88, 0x94, 0xc8, 0xda, 0x62, 0xd8, 0xb9, 0x1f, 0xaf, 0x52, 0x0e, 0x3b, - 0xed, 0xbc, 0x12, 0x06, 0xa5, 0xa5, 0xe6, 0xef, 0xd3, 0xdf, 0xde, 0x08, 0x43, 0xc3, - 0xb0, 0x67, 0x57, 0x64, 0x3f, 0xc0, 0x06, 0x00, 0x88, 0x38, 0xca, 0x47, 0x30, 0x87, - 0xf8, 0x97, 0x79, 0x18, 0xcc, 0x1b, 0x81, 0xc9, 0xe6, 0x8e, 0x3b, 0x88, 0x8f, 0xe6, - 0xf7, 0xc6, 0x30, 0xf1, 0xbc, 0x7a, 0xe1, 0x88, 0xf5, 0x12, 0x84, 0x20, 0x41, 0xca, - 0xda, 0x1e, 0x05, 0xf8, 0x66, 0xd2, 0x56, 0x2d, 0xbe, 0x09, 0xc4, 0xb4, 0x30, 0x68, - 0xf7, 0x54, 0xda, 0xd3, 0x4d, 0xf0, 0xfc, 0xfc, 0x18, 0x1f, 0x31, 0x80, 0x1a, 0x79, - 0x92, 0xd2, 0xf1, 0x6b, 0xe0, 0x21, 0x1b, 0x4a, 0x22, 0xf6, 0x2a, 0xab, 0x64, 0x70, - 0x1b, 0xf4, 0xa4, 0xe6, 0xd6, 0x66, 0xfc, 0x30, 0x4a, 0x5c, 0x79, 0xc6, 0x09, 0xac, - 0xc4, 0x3b, 0x00, 0xb4, 0x86, 0x48, 0x93, 0xd3, 0x7d, 0x50, 0x07, 0xf0, 0xc3, 0x29, - 0xa4, 0x75, 0x50, 0x52, 0x57, 0x75, 0x70, 0xdd, 0x38, 0xfa, 0xc0, 0x43, 0xcd, 0x91, - 0xc1, 0x2e, 0xe3, 0x4e, 0x9c, 0xfa, 0xe3, 0x92, 0xa7, 0x8b, 0xda, 0xbd, 0x4e, 0xe3, - 0x1d, 0xc0, 0xde, 0xb0, 0x2f, 0xe7, 0xb1, 0xd8, 0xb0, 0x17, 0x8a, 0xc9, 0x51, 0x31, - 0x05, 0xfc, 0xc7, 0xe3, 0x0b, 0xa8, 0xe0, 0x16, 0xaa, 0x36, 0xa6, 0xb5, 0xdf, 0x5e, - 0x5a, 0x19, 0x09, 0xf6, 0x3a, 0xba, 0x09, 0x5d, 0x98, 0x77, 0xa8, 0xf2, 0x6e, 0x40, - 0x3d, 0xc2, 0x54, 0x76, 0xad, 0xd8, 0x3d, 0xb1, 0xca, 0x15, 0x8f, 0x0b, 0x42, 0x2b, - 0x5f, 0xf4, 0xdb, 0x69, 0xb1, 0x24, 0x4b, 0xc0, 0x90, 0x2e, 0xd0, 0x30, 0x3f, 0xec, - 0x73, 0xa5, 0xbf, 0xfe, 0xc7, 0x3a, 0xc3, 0x4c, 0x1a, 0x73, 0x16, 0x0f, 0x2c, 0xea, - 0x1e, 0x05, 0x10, 0xf8, 0x4d, 0x2f, 0xe2, 0xf7, 0x3b, 0x6e, 0x92, 0x19, 0x07, 0xa1, - 0xb7, 0xb3, 0x75, 0x12, 0x13, 0x24, 0x30, 0x11, 0x76, 0xb0, 0x9b, 0xc0, 0x41, 0xe4, - 0x68, 0x42, 0x3e, 0x93, 0xd5, 0xdc, 0xa3, 0x3e, 0x67, 0x1a, 0x78, 0x6d, 0x23, 0x1f, - 0x16, 0x43, 0xea, 0x66, 0x43, 0x8b, 0xa7, 0x85, 0xb8, 0x1e, 0x6c, 0x2b, 0xc7, 0x3f, - 0xf0, 0x0d, 0x89, 0x3b, 0xc1, 0x28, 0x5e, 0xfc, 0xa8, 0x25, 0x99, 0xd1, 0x81, 0xf1, - 0x23, 0x51, 0xf9, 0x39, 0xa9, 0x4e, 0xa8, 0xb9, 0x75, 0xc0, 0x65, 0xa9, 0x1f, 0xf2, - 0x57, 0xca, 0xc7, 0xa9, 0x23, 0x85, 0xfc, 0x8f, 0xa9, 0x21, 0xb1, 0x06, 0xba, 0x86, - 0x60, 0xc6, 0x0a, 0xc8, 0xba, 0x5e, 0xce, 0x45, 0x60, 0x6f, 0x04, 0xf3, 0x6a, 0x3a, - 0x90, 0xbb, 0x38, 0x38, 0xc4, 0x2a, 0xbf, 0x62, 0xdd, 0x2d, 0x84, 0xba, 0xbe, 0xf3, - 0xe1, 0x88, 0xe9, 0x17, 0x1a, 0xff, 0x9b, 0xc1, 0x16, 0x66, 0x90, 0x09, 0xd8, 0x87, - 0x13, 0x0a, 0xc9, 0xf7, 0x39, 0x6a, 0x62, 0x7a, 0x84, 0x74, 0xc1, 0x81, 0x1b, 0x69, - 0x6f, 0x99, 0x55, 0x2b, 0x14, 0xc4, 0x84, 0xdf, 0xe4, 0x2c, 0x24, 0xd5, 0x7c, 0x3a, - 0x9c, 0x3f, 0xea, 0x13, 0x76, 0xcd, 0xcb, 0x63, 0x42, 0x1c, 0x31, 0x4a, 0x62, 0x2a, - 0x9a, 0xef, 0x0b, 0xc0, 0x57, 0xcb, 0x11, 0xbc, 0x5e, 0x30, 0x66, 0xe3, 0x3a, 0x3b, - 0x9b, 0x31, 0xdf, 0x25, 0x75, 0xcd, 0x51, 0x85, 0xa4, 0xf3, 0xfc, 0x4e, 0x4c, 0x3d, - 0x40, 0x2e, 0xd4, 0x20, 0x46, 0xf8, 0x1f, 0x97, 0x48, 0x16, 0xd2, 0x79, 0xb1, 0x51, - 0x3a, 0xb8, 0x1d, 0x3f, 0x0a, 0x3c, 0x7f, 0x7f, 0xcf, 0x2f, 0xbb, 0x4e, 0x26, 0x32, - 0x19, 0x93, 0xa5, 0x13, 0xad, 0x3d, 0x7f, 0x4a, 0xfe, 0x6c, 0x1b, 0xbd, 0xc6, 0x57, - 0x58, 0x50, 0x80, 0xbb, 0x5a, 0x0f, 0x25, 0x97, 0x3d, 0x63, 0xeb, 0x20, 0xad, 0xa0, - 0x16, 0x6b, 0xbd, 0x8a, 0x39, 0xff, 0x93, 0x24, 0x6f, 0x27, 0x89, 0x73, 0x2a, 0xd0, - 0x55, 0x87, 0xf8, 0xdb, 0x7b, 0xc8, 0x7c, 0x24, 0x2c, 0xfd, 0x36, 0xce, 0x68, 0x5a, - 0x4b, 0x65, 0x69, 0x86, 0xc3, 0x9f, 0xd7, 0xfc, 0xb2, 0x3c, 0x91, 0x91, 0x3e, 0x46, - 0x11, 0x19, 0x1e, 0xdc, 0xc8, 0x8b, 0x78, 0xf1, 0x45, 0xea, 0x29, 0xd2, 0x71, 0xb9, - 0x40, 0xc6, 0x99, 0x41, 0xe4, 0xc3, 0xfd, 0x2d, 0x71, 0xf3, 0xb1, 0x90, 0x69, 0x0e, - 0xe1, 0x6f, 0x5d, 0x14, 0xac, 0x22, 0x24, 0xe6, 0xfc, 0x89, 0x59, 0x76, 0x54, 0x52, - 0x7d, 0xab, 0xe7, 0x2e, 0x75, 0xd2, 0xd2, 0xa1, 0x3a, 0x9f, 0xba, 0xa6, 0x37, 0x8e, - 0x8a, 0x26, 0x43, 0x21, 0x08, 0x7a, 0x19, 0x00, 0xef, 0xe3, 0xca, 0xd1, 0x4a, 0x57, - 0x96, 0x86, 0xaa, 0x36, 0x36, 0xbd, 0x37, 0x5b, 0xd3, 0x13, 0x6b, 0xee, 0x0b, 0xda, - 0xab, 0xcf, 0xac, 0x88, 0x1b, 0xc7, 0x01, 0x81, 0x27, 0x21, 0xe6, 0xfb, 0x75, 0xaa, - 0x07, 0x2d, 0x2d, 0x18, 0x7e, 0x62, 0x25, 0x8d, 0x65, 0xa1, 0x92, 0x15, 0x7c, 0xdf, - 0x2e, 0xc3, 0x21, 0x40, 0x7f, 0x68, 0x2f, 0x5e, 0xec, 0x6a, 0x32, 0x97, 0xab, 0x20, - 0xb7, 0x06, 0x1c, 0x62, 0x24, 0x57, 0x16, 0xa4, 0x4f, 0x71, 0xfb, 0xfc, 0x34, 0xc7, - 0x9b, 0x44, 0xe0, 0x9e, 0x42, 0x12, 0xac, 0x26, 0x53, 0xf6, 0xc4, 0x03, 0x64, 0x3e, - 0x1c, 0x5b, 0x9a, 0xd1, 0x34, 0xd8, 0x9c, 0x68, 0x0b, 0x70, 0x72, 0x83, 0xaf, 0x54, - 0x32, 0x6f, 0xc4, 0xf8, 0x4d, 0x6a, 0x58, 0x29, 0xa0, 0xad, 0x48, 0x30, 0x80, 0x6c, - 0x05, 0x75, 0x84, 0x92, 0xcd, 0x6a, 0xc4, 0x6b, 0xa0, 0x1a, 0x2b, 0x37, 0x22, 0xb5, - 0xe4, 0xcd, 0xaf, 0xbb, 0x3f, 0x36, 0x78, 0x5f, 0x42, 0x4a, 0xf0, 0x44, 0xda, 0xc5, - 0xdb, 0x5f, 0x7d, 0xf8, 0x39, 0xeb, 0x63, 0xc0, 0xc1, 0x7d, 0x8b, 0x0c, 0x79, 0xdb, - 0x86, 0x30, 0x94, 0x20, 0x15, 0xbe, 0x13, 0xf7, 0x9a, 0xf6, 0xf4, 0x3e, 0x5a, 0xb0, - 0x77, 0x81, 0x14, 0x79, 0x8f, 0x44, 0x22, 0x58, 0xee, 0xdc, 0x43, 0x6f, 0xcc, 0x38, - 0x6b, 0x36, 0xb5, 0x7e, 0x19, 0x17, 0xd7, 0x20, 0x17, 0x73, 0x66, 0xf4, 0x24, 0xb0, - 0xa5, 0x4b, 0x0b, 0x60, 0xf4, 0xfb, 0x13, 0x58, 0xc2, 0x0a, 0xa4, 0x1d, 0xc5, 0x02, - 0xe1, 0xdd, 0x8a, 0x16, 0x33, 0xf3, 0xd8, 0xe3, 0x27, 0x6b, 0x59, 0xe7, 0xd2, 0xc4, - 0xe6, 0x24, 0xa6, 0xf5, 0x36, 0x95, 0xbc, 0xaf, 0x24, 0x7e, 0x36, 0x48, 0x3f, 0x13, - 0xb2, 0x04, 0x42, 0x22, 0x37, 0xfc, 0x6a, 0xb3, 0xeb, 0xa0, 0x2f, 0xc4, 0x14, 0x2b, - 0x42, 0x97, 0xeb, 0xb5, 0x68, 0x3d, 0xb8, 0xd2, 0x43, 0x19, 0x70, 0x6a, 0xd2, 0x6a, - 0xaf, 0xd8, 0x1c, 0x53, 0xb7, 0x40, 0xf3, 0x45, 0x43, 0xa6, 0xb3, 0xe9, 0xf5, 0xbb, - 0x7d, 0x5c, 0x49, 0xe8, 0xc3, 0x7f, 0x61, 0x49, 0x21, 0x25, 0x4f, 0x32, 0x12, 0x39, - 0x4c, 0x79, 0x7d, 0x1c, 0xee, 0x78, 0x99, 0xb7, 0xb4, 0xb6, 0x5b, 0x59, 0xb7, 0x34, - 0x2f, 0x92, 0x53, 0x1c, 0x1d, 0x59, 0xe1, 0x79, 0x70, 0xb7, 0x31, 0x74, 0x14, 0x43, - 0x8c, 0xd8, 0x0b, 0xd0, 0xf9, 0xa6, 0x7c, 0x9b, 0x9e, 0x55, 0x2f, 0x01, 0x3c, 0x11, - 0x5a, 0x95, 0x4f, 0x35, 0xe0, 0x61, 0x6c, 0x68, 0xd4, 0x31, 0x63, 0xd3, 0x34, 0xda, - 0xc3, 0x82, 0x70, 0x33, 0xe5, 0xad, 0x84, 0x88, 0xbf, 0xd9, 0xc4, 0xbb, 0xbe, 0x8f, - 0x59, 0x35, 0xc6, 0xc5, 0xea, 0x04, 0xc3, 0xad, 0x49, 0xc7, 0x47, 0xa9, 0xe7, 0x23, - 0x1b, 0xcd, 0x7d, 0x16, 0x21, 0x5e, 0x6e, 0x80, 0x73, 0x7d, 0x6b, 0x54, 0xfe, 0xc8, - 0xb8, 0x84, 0x02, 0xf0, 0x47, 0x52, 0x45, 0xe1, 0x74, 0xa7, 0x45, 0xb8, 0x31, 0xf8, - 0xfe, 0x03, 0xa7, 0x6f, 0xb9, 0xce, 0xca, 0x4d, 0x22, 0xb7, 0x83, 0xc3, 0x28, 0xc6, - 0x91, 0x5c, 0x43, 0x40, 0x50, 0x64, 0xae, 0x56, 0xbc, 0x89, 0xe6, 0x4d, 0x15, 0x78, - 0xe4, 0xd3, 0xa3, 0x4b, 0xb9, 0x55, 0x91, 0xea, 0xf1, 0xd3, 0xda, 0x02, 0xa4, 0x54, - 0x9f, 0xa8, 0x0d, 0xb0, 0xff, 0x7c, 0xb0, 0x39, 0x93, 0xb6, 0x8a, 0xe1, 0x5a, 0x30, - 0xe8, 0x79, 0x49, 0xaa, 0x08, 0x0e, 0x94, 0xab, 0xde, 0x68, 0x89, 0x8c, 0x33, 0x92, - 0xa2, 0x17, 0xd6, 0x49, 0x61, 0x6b, 0xbe, 0x73, 0x9b, 0x13, 0xd1, 0x4d, 0xf0, 0x3f, - 0xf2, 0x76, 0x71, 0x48, 0x9b, 0xe0, 0xb4, 0xbe, 0xba, 0xaf, 0xa7, 0xd1, 0xe6, 0x39, - 0xd5, 0xb3, 0xe9, 0x94, 0xff, 0xb6, 0xb7, 0xa2, 0x09, 0xf6, 0xad, 0xfe, 0x8d, 0x1e, - 0x5c, 0xcf, 0x01, 0x0c, 0x19, 0x16, 0x8a, 0xeb, 0x00, 0xaa, 0x9d, 0x68, 0x7e, 0x24, - 0xad, 0xc0, 0xb1, 0x13, 0x5c, 0x70, 0xc9, 0x70, 0xe0, 0x90, 0x3a, 0xf6, 0xe1, 0x70, - 0x81, 0xd5, 0x81, 0x8e, 0x88, 0xb1, 0x4e, 0x4f, 0x60, 0x1b, 0x8c, 0x06, 0x3e, 0x3f, - 0x43, 0x87, 0xff, 0xa2, 0x32, 0x2a, 0x51, 0x81, 0x90, 0x9f, 0x09, 0x80, 0xd6, 0x89, - 0xde, 0x7f, 0x8e, 0x6a, 0x5c, 0x62, 0xa7, 0x77, 0xd1, 0x75, 0x00, 0x2a, 0x13, 0x7d, - 0xe8, 0x5b, 0x88, - ], - script_code: Script(vec![]), - transparent_input: None, - hash_type: 1, - amount: 1039204199089370, - consensus_branch_id: consensus::BranchId::Sapling, - sighash: [ - 0x6c, 0x4e, 0x32, 0x44, 0xc2, 0xd2, 0xbf, 0xb8, 0xd6, 0xf6, 0x69, 0x97, 0x77, 0xa1, - 0x1a, 0x64, 0xad, 0xfe, 0xe4, 0x9b, 0x2f, 0xc7, 0x81, 0xe6, 0x95, 0x15, 0x34, 0xf9, - 0x73, 0x44, 0x0d, 0xdb, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0xdc, 0xf7, 0x58, 0x76, 0xdc, - 0xa6, 0x09, 0xf9, 0xd2, 0x84, 0x71, 0xf9, 0x97, 0xfa, 0x11, 0xf9, 0x9d, 0x42, 0x3f, - 0x9c, 0xf1, 0x73, 0x4b, 0xe8, 0xa5, 0xff, 0x99, 0x7d, 0x45, 0x1e, 0xb3, 0xcf, 0x4b, - 0x3d, 0xfd, 0xd9, 0x06, 0xac, 0xac, 0x63, 0x52, 0x63, 0x6a, 0xdc, 0x17, 0xa8, 0x36, - 0xb1, 0x2b, 0x43, 0xbe, 0xfc, 0x0b, 0xe0, 0xa1, 0xbd, 0x36, 0x97, 0x72, 0x33, 0x80, - 0x78, 0xb4, 0xff, 0x7d, 0x8e, 0x2d, 0x97, 0x9a, 0x34, 0x41, 0xe1, 0xc8, 0xf5, 0xaf, - 0xe4, 0x7b, 0x1e, 0x7d, 0xa5, 0x6c, 0xf0, 0x06, 0x02, 0x00, 0x53, 0x11, 0x0c, 0x05, - 0xcf, 0x00, 0xfd, 0xa3, 0xe6, 0xcc, 0xe3, 0x60, 0x69, 0x04, 0x1f, 0xaf, 0xfd, 0x2f, - 0x77, 0xff, 0x06, 0x00, 0x02, 0xef, 0x12, 0xc3, 0x67, 0xf2, 0x1d, 0xea, 0x65, 0xc6, - 0xea, 0xaf, 0xb8, 0xaf, 0x58, 0x42, 0x8f, 0x6c, 0x54, 0x8e, 0x50, 0x17, 0x0f, 0x9e, - 0x6f, 0xcd, 0xdf, 0xe7, 0x51, 0xe0, 0xb6, 0x80, 0x12, 0xcb, 0x59, 0xdd, 0x46, 0x27, - 0xef, 0xc3, 0xea, 0x75, 0xdc, 0xd1, 0x5c, 0x8e, 0x0c, 0x3b, 0x8d, 0x8d, 0x7d, 0x6b, - 0x23, 0x31, 0xc8, 0xe4, 0x80, 0x16, 0x6b, 0x5a, 0xa7, 0x48, 0x5c, 0x9f, 0x0f, 0x83, - 0xe1, 0x9b, 0xc3, 0x0e, 0x64, 0x03, 0x82, 0x8c, 0xdb, 0x65, 0x2a, 0x55, 0x6b, 0x12, - 0x04, 0x09, 0x31, 0x40, 0x2a, 0xa6, 0xac, 0x34, 0xfc, 0x19, 0xfd, 0xc0, 0x6e, 0x2e, - 0x77, 0x87, 0xf5, 0x58, 0xd1, 0x42, 0xd9, 0x06, 0xea, 0xdb, 0x75, 0x90, 0xc9, 0x41, - 0x36, 0xda, 0x6a, 0x06, 0x35, 0x14, 0xd6, 0xa2, 0x5f, 0x7b, 0x37, 0xd7, 0x66, 0x4f, - 0x9b, 0x97, 0x09, 0x43, 0x3e, 0x6e, 0x70, 0x21, 0x18, 0xa4, 0xab, 0x9e, 0x7a, 0x7a, - 0x3e, 0x62, 0x59, 0x12, 0x99, 0x37, 0xd2, 0x9d, 0x0d, 0xb2, 0x60, 0x70, 0x52, 0x3e, - 0x8b, 0x06, 0x43, 0x13, 0x0a, 0xbe, 0xfe, 0x94, 0x3b, 0x40, 0x12, 0x98, 0xae, 0x01, - 0xa3, 0xab, 0x00, 0xab, 0xbc, 0x60, 0xd7, 0xdb, 0x93, 0x3c, 0x7f, 0x07, 0xa8, 0xbf, - 0x0f, 0x7c, 0xe1, 0x66, 0x0b, 0xcc, 0xb4, 0x5e, 0x04, 0x2b, 0x45, 0x1b, 0x93, 0x50, - 0x02, 0xce, 0xce, 0x27, 0xf3, 0x6a, 0xba, 0x56, 0x47, 0xac, 0x28, 0xd8, 0x18, 0x6c, - 0xdd, 0x1f, 0xb9, 0x5d, 0xc1, 0x35, 0xd4, 0x89, 0x92, 0xf6, 0x8d, 0xa1, 0x2a, 0xd6, - 0x1a, 0xc7, 0x56, 0x68, 0x0d, 0xd7, 0xf8, 0xd0, 0x77, 0x4a, 0xbd, 0x6c, 0xfd, 0xa2, - 0xf0, 0x32, 0xaf, 0x3b, 0xe1, 0x39, 0xa6, 0x33, 0xd6, 0x73, 0x3c, 0x75, 0xd1, 0xab, - 0xa8, 0x90, 0x18, 0xc8, 0x57, 0x2b, 0x99, 0xcd, 0x30, 0xc5, 0x37, 0x06, 0x79, 0x41, - 0xdf, 0x1c, 0x4b, 0xc1, 0xfd, 0x57, 0x0f, 0x7b, 0x4d, 0xdc, 0x97, 0x51, 0x86, 0x23, - 0xe3, 0xae, 0x4a, 0x87, 0xbd, 0xb9, 0x66, 0xc9, 0x4d, 0x86, 0x1e, 0x80, 0xde, 0x88, - 0xc2, 0x92, 0xae, 0xe9, 0x38, 0x71, 0x94, 0xe2, 0x56, 0xc6, 0x70, 0x07, 0x52, 0x30, - 0x1c, 0x73, 0xfc, 0x95, 0x65, 0xa4, 0x04, 0x80, 0xd8, 0x12, 0x6e, 0x9d, 0x08, 0x58, - 0x79, 0xe2, 0x4b, 0x16, 0xe9, 0xc4, 0x85, 0xd8, 0xf0, 0xd6, 0x18, 0xca, 0x0d, 0xd1, - 0x21, 0xb5, 0x1a, 0x7c, 0xab, 0x23, 0x0c, 0x5b, 0x45, 0x67, 0x2b, 0xdb, 0x8e, 0xa3, - 0xa0, 0x40, 0xf7, 0xaa, 0xa0, 0x98, 0xba, 0x26, 0x02, 0x5d, 0x2e, 0xab, 0x79, 0x48, - 0x69, 0x3d, 0xd5, 0xf6, 0xd3, 0x09, 0x65, 0x01, 0xe9, 0xe0, 0x71, 0x25, 0xd7, 0xeb, - 0x29, 0x3b, 0x3a, 0xba, 0xd5, 0x7f, 0xd5, 0xf0, 0x11, 0x64, 0x70, 0x02, 0xd6, 0x26, - 0xae, 0x88, 0xdc, 0x61, 0xe6, 0x47, 0xff, 0x46, 0x8d, 0xfa, 0x7a, 0x03, 0x07, 0x72, - 0x78, 0x79, 0x32, 0x75, 0xf1, 0x95, 0xa9, 0x75, 0x30, 0x28, 0x91, 0x78, 0x51, 0x61, - 0x80, 0xc5, 0xff, 0x99, 0x93, 0x53, 0x6b, 0xda, 0x15, 0x04, 0xba, 0x8b, 0xb4, 0x89, - 0x19, 0x88, 0xc1, 0x33, 0x4f, 0x31, 0xfb, 0x27, 0x6a, 0x03, 0x8a, 0xa8, 0xe9, 0x67, - 0xcb, 0x62, 0xa4, 0x92, 0x1b, 0xeb, 0x22, 0xb2, 0x08, 0xb0, 0x64, 0x58, 0x18, 0x47, - 0xb2, 0xf6, 0x4c, 0xa6, 0x48, 0x37, 0x00, 0x72, 0x16, 0xde, 0x6e, 0xca, 0xff, 0xeb, - 0x4b, 0x69, 0xe6, 0x33, 0x47, 0xf8, 0x4a, 0xbc, 0xad, 0x8f, 0x2e, 0x75, 0x7d, 0x58, - 0x61, 0xce, 0x77, 0xee, 0x46, 0x51, 0x3d, 0xa7, 0x41, 0x68, 0x37, 0xdc, 0xb2, 0x3d, - 0x33, 0xea, 0x72, 0xaf, 0x23, 0xd0, 0xad, 0x8c, 0x93, 0x07, 0xd0, 0xb5, 0x85, 0x8d, - 0xa9, 0x5b, 0x77, 0xff, 0xf9, 0x02, 0x7b, 0x88, 0x59, 0xe1, 0x1d, 0xcb, 0xd5, 0x98, - 0x35, 0x0e, 0xee, 0x50, 0x93, 0x94, 0x81, 0x70, 0x8e, 0xa7, 0x08, 0xeb, 0x9f, 0x66, - 0x43, 0x88, 0xb9, 0xc6, 0x4d, 0x6a, 0xf0, 0xf9, 0x66, 0x90, 0x34, 0x24, 0x00, 0x34, - 0x8e, 0x92, 0x9e, 0x07, 0x46, 0x02, 0x53, 0xf3, 0x83, 0x90, 0xf8, 0x7b, 0xd6, 0xc0, - 0x53, 0x08, 0xc3, 0xbd, 0xe2, 0x52, 0x28, 0xe0, 0xfa, 0x08, 0x80, 0xb0, 0x8e, 0xf3, - 0x4a, 0x5a, 0x9c, 0xc0, 0xea, 0x0a, 0x67, 0xca, 0x65, 0xb6, 0xff, 0xd0, 0x05, 0x57, - 0x29, 0x09, 0xf1, 0xc4, 0x2d, 0xd7, 0x45, 0xee, 0xee, 0x9d, 0xd6, 0xb4, 0x43, 0x9c, - 0x9f, 0x3f, 0x98, 0xa1, 0x18, 0xfe, 0x16, 0x69, 0x8e, 0x9c, 0xef, 0xf5, 0x58, 0xf1, - 0x60, 0x66, 0x97, 0x5f, 0xe3, 0x95, 0x83, 0xe9, 0xb5, 0x85, 0x3b, 0x13, 0x11, 0x39, - 0x15, 0x80, 0x01, 0x9f, 0xe5, 0x5d, 0x59, 0xd1, 0xc8, 0x28, 0xd3, 0xfe, 0xb6, 0xa3, - 0xb9, 0xce, 0x92, 0xd0, 0x89, 0xae, 0x4b, 0x40, 0x8e, 0x23, 0xd6, 0xa4, 0x37, 0xd4, - 0x98, 0x9b, 0x51, 0x9b, 0x7a, 0x9e, 0xb0, 0x8a, 0xe6, 0xd4, 0x48, 0xa7, 0xa1, 0x6e, - 0x8a, 0xed, 0x26, 0xa2, 0xec, 0xd0, 0xca, 0xd8, 0x08, 0x44, 0xfd, 0x06, 0x50, 0xd8, - 0xc4, 0xe4, 0xd2, 0xaf, 0x90, 0x65, 0x67, 0x48, 0xd8, 0x09, 0x9a, 0x0c, 0x75, 0x6f, - 0xc1, 0x6c, 0xca, 0x06, 0xa3, 0x34, 0x43, 0x07, 0x02, 0xae, 0x19, 0x61, 0x66, 0x5b, - 0x48, 0x45, 0xac, 0xd1, 0xa8, 0xe3, 0x41, 0x01, 0xe6, 0x8b, 0xb6, 0x44, 0xac, 0x03, - 0x4d, 0xc6, 0x3e, 0x6e, 0x34, 0x4c, 0x3d, 0x63, 0x76, 0x2a, 0x7a, 0x5b, 0xf5, 0x9f, - 0x13, 0x09, 0x54, 0x10, 0x98, 0x1d, 0x6b, 0x6b, 0x16, 0xbc, 0xd4, 0xc9, 0xfa, 0x68, - 0xaf, 0x6e, 0x53, 0x01, 0xef, 0x19, 0xbf, 0x3a, 0x43, 0x2e, 0x40, 0x6f, 0x85, 0x67, - 0xeb, 0xd9, 0x77, 0x2e, 0x92, 0xb5, 0xca, 0x5a, 0x59, 0x96, 0x71, 0xcb, 0xfd, 0x7d, - 0xdf, 0xa3, 0x63, 0xa5, 0x36, 0xb7, 0xac, 0x45, 0xf5, 0x7c, 0xc3, 0x7d, 0x09, 0x89, - 0x6f, 0xa9, 0x06, 0x97, 0x2e, 0x55, 0x71, 0x80, 0xa4, 0xab, 0x5a, 0xd0, 0x9d, 0x88, - 0x46, 0xdd, 0x6d, 0xa7, 0x48, 0x76, 0x54, 0x36, 0xe0, 0x16, 0x02, 0x40, 0xbd, 0x5c, - 0x92, 0x16, 0x66, 0xa1, 0xee, 0xaa, 0xce, 0x04, 0xa7, 0x1b, 0x50, 0x3a, 0x1c, 0xad, - 0xf8, 0x0b, 0x39, 0x24, 0x26, 0x6c, 0x59, 0x50, 0x4f, 0x8f, 0x21, 0x5f, 0x61, 0x8b, - 0x05, 0xd5, 0x45, 0x43, 0xb6, 0xe2, 0x6d, 0x82, 0x59, 0x6f, 0xc5, 0x3b, 0x52, 0x31, - 0x2c, 0x77, 0x6d, 0x12, 0xeb, 0x2b, 0x65, 0x9b, 0x4f, 0xb0, 0x98, 0xdf, 0x87, 0xd6, - 0x83, 0xcf, 0x9e, 0x54, 0x12, 0xee, 0x56, 0xc3, 0xfe, 0x98, 0x41, 0xd7, 0x3f, 0xd0, - 0x70, 0xdf, 0xa5, 0x1f, 0x5b, 0xaf, 0xed, 0xf2, 0x06, 0xf1, 0x3c, 0x52, 0x4e, 0x5c, - 0x50, 0xca, 0xc9, 0x90, 0x6e, 0xfa, 0x39, 0x32, 0x90, 0x04, 0x2e, 0x3b, 0xc5, 0x9f, - 0x96, 0x0b, 0x7d, 0x24, 0x0a, 0xe4, 0x43, 0xfc, 0x49, 0x26, 0x9c, 0xe0, 0x00, 0x61, - 0xe6, 0x5c, 0x6d, 0x74, 0x81, 0x2a, 0x30, 0xdd, 0x5f, 0x5f, 0xe7, 0x4e, 0xff, 0x61, - 0xe0, 0xcb, 0xab, 0x3c, 0xec, 0x75, 0xd0, 0xae, 0xf9, 0x50, 0x83, 0x18, 0x94, 0x52, - 0xdd, 0x3d, 0x9e, 0xdf, 0x44, 0x87, 0xbc, 0x73, 0x4c, 0x8b, 0x24, 0xf2, 0x12, 0x96, - 0xe4, 0xe9, 0xef, 0x11, 0x7d, 0x7f, 0xb9, 0x77, 0xe3, 0xb0, 0xe6, 0x40, 0x6e, 0x63, - 0x08, 0x59, 0x06, 0x33, 0x1a, 0x93, 0x03, 0x3d, 0x1c, 0xb8, 0x36, 0x0f, 0xe6, 0xfe, - 0xa6, 0x1a, 0x68, 0x26, 0xdf, 0x36, 0x25, 0x57, 0x89, 0xf9, 0x2e, 0x40, 0xba, 0xfc, - 0xb2, 0xeb, 0xcb, 0x9e, 0x55, 0x6f, 0x6c, 0x0c, 0xca, 0xdc, 0x6a, 0xf0, 0x8e, 0x31, - 0xec, 0x4a, 0xd5, 0x28, 0x80, 0x34, 0xe1, 0x6d, 0x15, 0x5c, 0xfd, 0xca, 0xda, 0x7b, - 0xab, 0x59, 0x9c, 0x2f, 0xa4, 0xad, 0x2e, 0x62, 0x93, 0xf9, 0xfe, 0x09, 0x71, 0x69, - 0x14, 0x82, 0x76, 0xb6, 0xa9, 0xea, 0xa7, 0x2f, 0x14, 0x8b, 0x0c, 0x95, 0x65, 0xc3, - 0xc2, 0xdd, 0x63, 0x12, 0x5e, 0x0f, 0xa5, 0x30, 0x86, 0x1a, 0x71, 0x0d, 0xf8, 0xe4, - 0x81, 0xf2, 0x71, 0x29, 0x20, 0xf8, 0x78, 0x7e, 0x0a, 0xed, 0xfe, 0x61, 0x8a, 0xff, - 0x50, 0xa3, 0xb5, 0x62, 0x13, 0x88, 0x4d, 0x62, 0x62, 0xc1, 0x1d, 0xeb, 0xf2, 0xba, - 0x7e, 0x8a, 0xd6, 0x69, 0x2c, 0xb1, 0x70, 0x78, 0x33, 0x14, 0x18, 0xda, 0x4b, 0xe0, - 0x64, 0xff, 0x52, 0x70, 0x07, 0x39, 0x34, 0xab, 0xcd, 0x2a, 0xb0, 0x46, 0x9e, 0xca, - 0xf7, 0x27, 0x5b, 0x4b, 0xd7, 0x2b, 0xc6, 0xed, 0x34, 0x47, 0x8e, 0xa4, 0x08, 0x9b, - 0x73, 0x6a, 0x16, 0xdd, 0x90, 0x6d, 0x49, 0xf2, 0x5c, 0x33, 0x82, 0x7c, 0x57, 0x1c, - 0xe0, 0xb5, 0xd7, 0x21, 0x77, 0xaa, 0x35, 0x08, 0x80, 0x4b, 0xc0, 0xf8, 0xfa, 0xa9, - 0x47, 0x12, 0x22, 0x31, 0x40, 0x2d, 0x2f, 0x5c, 0xc9, 0xa0, 0xeb, 0x0e, 0x09, 0xd4, - 0x27, 0xb4, 0x27, 0x28, 0x8d, 0x93, 0x7d, 0x9d, 0x72, 0xb7, 0x74, 0x56, 0xf8, 0x86, - 0x59, 0x4c, 0xd8, 0xc6, 0xa4, 0x62, 0xf7, 0x7f, 0xd8, 0x30, 0x76, 0x46, 0x9c, 0xc0, - 0xec, 0xba, 0x3c, 0xc4, 0x0c, 0xad, 0x69, 0xe5, 0xb5, 0x41, 0x12, 0xea, 0xb3, 0x33, - 0x96, 0xae, 0xcf, 0xbc, 0x21, 0x1f, 0x1f, 0x79, 0xcf, 0x33, 0x10, 0x8e, 0x93, 0xd9, - 0x53, 0x78, 0xba, 0xe6, 0x95, 0x82, 0x74, 0xb3, 0x10, 0x88, 0xfb, 0xd8, 0xb3, 0xa3, - 0xa0, 0xd1, 0x54, 0xa7, 0x89, 0x73, 0x5b, 0x03, 0x49, 0xc4, 0xd5, 0x1c, 0x88, 0x9d, - 0x08, 0x95, 0x2d, 0xdd, 0x54, 0x88, 0xbe, 0x95, 0x56, 0x05, 0x94, 0xe6, 0x73, 0xfa, - 0x05, 0x1b, 0xf9, 0xb6, 0x14, 0xa1, 0x5e, 0x10, 0x0b, 0x60, 0xa0, 0xfe, 0x9a, 0x7e, - 0x12, 0xa9, 0xb2, 0x56, 0xdf, 0x58, 0x9b, 0x3e, 0x48, 0xe5, 0xb8, 0x0f, 0xb8, 0xcf, - 0xf0, 0x3e, 0x86, 0xf6, 0x0c, 0xc0, 0x70, 0xfb, 0x23, 0xc9, 0x7d, 0x4c, 0x14, 0xfa, - 0x3a, 0x73, 0x46, 0xff, 0x55, 0x6b, 0xc6, 0x85, 0x5a, 0x5f, 0x83, 0xe3, 0xdc, 0xd9, - 0xf6, 0xea, 0xb3, 0xda, 0xbc, 0xd4, 0x77, 0x50, 0xe3, 0x4e, 0x7c, 0x09, 0x38, 0xf6, - 0x4d, 0x45, 0x1e, 0x39, 0x50, 0x9e, 0x90, 0x27, 0x47, 0xa7, 0x07, 0x55, 0x12, 0x20, - 0x95, 0x08, 0x2a, 0xb7, 0x98, 0x59, 0x19, 0x07, 0x31, 0x41, 0xb6, 0xd3, 0x70, 0x20, - 0x91, 0xab, 0x71, 0x72, 0x80, 0xbd, 0xc5, 0x5e, 0x79, 0x9c, 0x01, 0xad, 0x86, 0x41, - 0x90, 0x4e, 0x3b, 0x1d, 0xd2, 0x9e, 0x1a, 0x96, 0x4c, 0x73, 0x7d, 0x3c, 0x15, 0x5a, - 0xfb, 0x30, 0x7b, 0x74, 0x8e, 0x41, 0x12, 0xb4, 0x8b, 0x77, 0xd5, 0xed, 0x57, 0x00, - 0xe6, 0x00, 0x2b, 0x18, 0xb0, 0xfe, 0xd2, 0xcf, 0xfd, 0xf6, 0x1f, 0xd9, 0x93, 0x4b, - 0x60, 0x73, 0x2f, 0x4d, 0x37, 0x81, 0x0a, 0x91, 0xac, 0xef, 0x1e, 0x03, 0x8b, 0x81, - 0xd7, 0x36, 0xd9, 0x8e, 0xad, 0xa9, 0xcd, 0x7e, 0x0c, 0x2b, 0xe2, 0x7a, 0xb8, 0x50, - 0x32, 0x06, 0x60, 0x91, 0x22, 0x4e, 0xdf, 0x87, 0x2f, 0x79, 0x63, 0x7d, 0xda, 0x39, - 0x16, 0x79, 0x6a, 0x5c, 0x62, 0xf5, 0x7f, 0x1d, 0xe3, 0x76, 0x78, 0xb6, 0xde, 0xa0, - 0x08, 0x69, 0x93, 0x36, 0x74, 0xf8, 0x8e, 0x41, 0xa9, 0x18, 0x08, 0x07, 0x3b, 0x0f, - 0x43, 0x6e, 0xbe, 0x25, 0xa5, 0xf4, 0x4a, 0x60, 0x10, 0x33, 0xe2, 0x18, 0x4b, 0x88, - 0xdb, 0x79, 0xe9, 0x68, 0xca, 0x6d, 0x89, 0xb7, 0x49, 0x01, 0xbe, 0x6c, 0x6d, 0xb3, - 0x63, 0x65, 0x80, 0x18, 0x2e, 0x65, 0x8d, 0xfc, 0x68, 0x67, 0x67, 0xd6, 0xd8, 0x19, - 0xfa, 0x92, 0x3e, 0x0c, 0xdf, 0x3e, 0xa3, 0x65, 0x76, 0xf8, 0x52, 0xbc, 0xd4, 0xe1, - 0x96, 0xa7, 0x1a, 0x13, 0x29, 0xf6, 0xc3, 0xff, 0x8e, 0x42, 0xe3, 0x09, 0x5a, 0xbd, - 0x8e, 0xc1, 0x97, 0x99, 0x07, 0x13, 0xee, 0x89, 0x39, 0x4c, 0x57, 0x19, 0xb2, 0x76, - 0xde, 0x8f, 0x81, 0x8a, 0x34, 0xa7, 0xbe, 0xc1, 0xf2, 0x68, 0x68, 0x2e, 0x91, 0x42, - 0xc7, 0xd3, 0x87, 0x89, 0xf6, 0x76, 0xcc, 0x12, 0xb7, 0x1a, 0xb6, 0x66, 0x35, 0xc5, - 0x02, 0xe6, 0x9d, 0x05, 0xb9, 0xc7, 0xef, 0x01, 0x52, 0x97, 0x75, 0xc6, 0x23, 0xa4, - 0x8e, 0x4c, 0xc5, 0xc4, 0x15, 0xc9, 0xfd, 0x56, 0x53, 0x65, 0xa4, 0x16, 0x37, 0x68, - 0x78, 0x51, 0x53, 0x88, 0x7f, 0xb5, 0xf9, 0x63, 0xe7, 0xac, 0xc1, 0x62, 0xf2, 0x80, - 0x5f, 0x45, 0xf4, 0x44, 0x87, 0xf8, 0x5e, 0x19, 0x9c, 0x1d, 0xf4, 0xa0, 0xfc, 0xa4, - 0xd4, 0x4b, 0xaa, 0x62, 0xda, 0x7a, 0xf5, 0xed, 0x69, 0x68, 0x41, 0x12, 0xd3, 0x5f, - 0x00, 0x73, 0x73, 0x2f, 0x5a, 0x1a, 0xc3, 0xe4, 0xf0, 0x21, 0xba, 0x5c, 0x2c, 0x32, - 0xf0, 0x6e, 0x6b, 0x90, 0xfa, 0xe2, 0xd2, 0x54, 0xcf, 0x09, 0xe7, 0x69, 0x0c, 0xf4, - 0xe3, 0xaa, 0x70, 0x30, 0x98, 0x74, 0x48, 0xe1, 0x47, 0xf9, 0x43, 0xba, 0xb5, 0xca, - 0xb5, 0x58, 0x02, 0x9a, 0x36, 0x02, 0x4d, 0x2e, 0x79, 0x0f, 0xc6, 0xfd, 0x66, 0x7f, - 0x17, 0x6e, 0x0a, 0xa9, 0x9d, 0xd1, 0xd7, 0x2b, 0x57, - ], - script_code: Script(vec![0x6a, 0x51, 0x65, 0xac]), - transparent_input: None, - hash_type: 1, - amount: 691732482992802, - consensus_branch_id: consensus::BranchId::Sapling, - sighash: [ - 0x5d, 0x40, 0x5a, 0x1c, 0x4d, 0xed, 0x19, 0x87, 0x98, 0x8a, 0x10, 0x03, 0x64, 0xa3, - 0xcd, 0x6f, 0xe0, 0xba, 0x22, 0x20, 0xa6, 0xab, 0xce, 0x08, 0xc5, 0x17, 0x13, 0x59, - 0x55, 0x30, 0x65, 0xe9, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x01, 0xa4, 0x96, 0x69, 0x60, 0x21, - 0x82, 0x08, 0x46, 0x69, 0x61, 0x12, 0x94, 0x90, 0xa7, 0xd8, 0xb6, 0x5c, 0x14, 0x70, - 0xba, 0xd8, 0xdb, 0x08, 0x28, 0xef, 0x06, 0xc1, 0xcb, 0x55, 0x70, 0x0e, 0x85, 0xe2, - 0x4f, 0xde, 0xa9, 0x08, 0x52, 0x00, 0x65, 0x63, 0x52, 0x51, 0xac, 0x51, 0x87, 0x1f, - 0x88, 0xfb, 0x02, 0x57, 0x2c, 0x4f, 0x50, 0xa0, 0xf8, 0x01, 0x00, 0x06, 0x63, 0x00, - 0x63, 0x63, 0x51, 0xac, 0xcb, 0x37, 0x9c, 0x68, 0xc8, 0x7d, 0x04, 0x00, 0x03, 0x00, - 0x6a, 0x63, 0x53, 0x3c, 0x92, 0xcf, 0x4c, 0x1c, 0xac, 0x18, 0x99, 0x41, 0x99, 0xa8, - 0xec, 0x8e, 0x01, 0x00, 0x04, 0x1b, 0x31, 0xeb, 0xfb, 0xf8, 0x18, 0xa3, 0x99, 0x2b, - 0xf3, 0x68, 0xc2, 0x4e, 0x9a, 0xcc, 0x83, 0x14, 0x2b, 0x24, 0x0f, 0xec, 0x55, 0x4c, - 0xed, 0xa1, 0xd3, 0xfc, 0x04, 0x32, 0xc5, 0x72, 0x51, 0x34, 0x19, 0xaf, 0x1d, 0xe6, - 0x56, 0xfd, 0xd0, 0x39, 0x07, 0x22, 0xa7, 0xf4, 0x6a, 0x1f, 0xc0, 0x56, 0x3f, 0x0a, - 0xda, 0xb8, 0xbc, 0xbb, 0xb0, 0xd1, 0xb2, 0x29, 0xf5, 0xa5, 0xb9, 0x23, 0x03, 0x77, - 0x5a, 0x90, 0x4d, 0xec, 0x82, 0x7f, 0xd8, 0x7a, 0x18, 0x86, 0x0d, 0x6e, 0x8a, 0x4a, - 0x52, 0xb5, 0xcf, 0x44, 0xbe, 0x28, 0xa6, 0x2d, 0x41, 0x59, 0x02, 0x09, 0x3a, 0x0c, - 0x36, 0x5d, 0x29, 0x24, 0x12, 0x01, 0xb8, 0x26, 0x1a, 0x49, 0xd4, 0x91, 0xaf, 0x04, - 0x9b, 0x39, 0xe2, 0x6d, 0x13, 0x57, 0xc3, 0x06, 0x92, 0x64, 0x16, 0x77, 0x6d, 0x7d, - 0x13, 0xf8, 0x40, 0xbd, 0x82, 0xac, 0xa0, 0x1c, 0x83, 0x1c, 0x98, 0x3f, 0x19, 0x85, - 0xee, 0x0a, 0xda, 0xe8, 0xdb, 0x84, 0x47, 0xc0, 0xe5, 0x1c, 0x09, 0xdf, 0xe3, 0xde, - 0xe3, 0x88, 0x0a, 0x97, 0x13, 0xce, 0xb7, 0x45, 0xab, 0xfd, 0xd9, 0xf1, 0xc7, 0xea, - 0xd7, 0x63, 0x08, 0xcd, 0xee, 0xa2, 0x1c, 0x8b, 0x09, 0x57, 0x02, 0x7c, 0x5d, 0x00, - 0xe5, 0x0a, 0x43, 0x88, 0xc7, 0xaf, 0x2b, 0xd6, 0x43, 0xcb, 0x5e, 0xae, 0x49, 0x27, - 0x4d, 0x12, 0x30, 0xa4, 0xcd, 0x49, 0x23, 0x7a, 0xe3, 0x7b, 0x38, 0x10, 0xc2, 0xc3, - 0x95, 0x8a, 0x7d, 0xee, 0x02, 0x34, 0x30, 0x1b, 0x89, 0xa2, 0xdf, 0x2a, 0x78, 0xef, - 0x0b, 0xfb, 0x4b, 0xf6, 0xb3, 0x87, 0xdf, 0x2c, 0x6c, 0x86, 0xe6, 0x1c, 0xd1, 0x0c, - 0xa1, 0x1f, 0x81, 0x13, 0x01, 0x26, 0x07, 0xf1, 0x5b, 0x28, 0x56, 0x24, 0x0f, 0xdc, - 0x52, 0x06, 0x5a, 0x10, 0x28, 0xc8, 0xa2, 0xdd, 0xfd, 0xd1, 0x5c, 0xf5, 0x26, 0x5f, - 0x87, 0x38, 0x8a, 0xb9, 0xbf, 0x21, 0xc9, 0xa7, 0x8c, 0x59, 0x03, 0x8a, 0x98, 0xab, - 0x64, 0xfd, 0x67, 0x10, 0x77, 0xd4, 0x72, 0xc2, 0x09, 0xdd, 0x72, 0x9b, 0xd7, 0xf8, - 0x48, 0x09, 0x45, 0xfb, 0xa7, 0x52, 0x09, 0x8a, 0x94, 0xcc, 0xb2, 0x4c, 0xf3, 0xbc, - 0x09, 0x2d, 0x42, 0x36, 0x46, 0x11, 0xa2, 0x93, 0xaf, 0xf3, 0xc5, 0x79, 0x37, 0x2c, - 0x12, 0xe1, 0x50, 0x90, 0xaa, 0x27, 0x23, 0x20, 0x57, 0xf2, 0xed, 0xde, 0x4e, 0x1d, - 0xb2, 0x92, 0xf7, 0xb1, 0x86, 0x47, 0x22, 0x67, 0x35, 0x17, 0x6d, 0x90, 0xf1, 0x26, - 0x5b, 0x37, 0x98, 0xcc, 0xab, 0xac, 0x0b, 0x8d, 0x79, 0xb1, 0x77, 0x20, 0xb2, 0xba, - 0x71, 0xd7, 0x85, 0x0c, 0xc2, 0xa0, 0x87, 0x2b, 0xf0, 0xf4, 0xb8, 0x14, 0x36, 0x78, - 0x59, 0xf8, 0x99, 0x48, 0xf0, 0xa1, 0xa3, 0x83, 0x60, 0x4b, 0x9e, 0x1a, 0xa4, 0xc7, - 0xea, 0x28, 0x92, 0x05, 0x6f, 0x81, 0x28, 0x5b, 0xc2, 0x6f, 0x30, 0x08, 0x5d, 0xd0, - 0xef, 0x3b, 0x14, 0xd1, 0x7d, 0xda, 0x57, 0x30, 0x6a, 0xe4, 0xf6, 0x6c, 0x45, 0x9a, - 0xee, 0x8a, 0x4e, 0xd9, 0x02, 0xc6, 0x6e, 0x49, 0x18, 0xfa, 0xee, 0x8d, 0xc0, 0x06, - 0x72, 0x46, 0x96, 0x0d, 0xb1, 0xf8, 0xcd, 0x07, 0xbf, 0x90, 0xd7, 0x53, 0x7c, 0xc2, - 0x7b, 0xbb, 0x8c, 0x9d, 0x5b, 0x29, 0x62, 0xc4, 0x7e, 0xd1, 0x82, 0xa2, 0xfc, 0xe0, - 0x5f, 0x8e, 0x03, 0xc4, 0xe2, 0x5e, 0x49, 0x6d, 0xd5, 0x7d, 0x6a, 0xb3, 0x45, 0x8f, - 0xac, 0xbd, 0x91, 0xea, 0x22, 0x72, 0xff, 0xda, 0x47, 0xbf, 0xd0, 0x17, 0x39, 0x20, - 0xd7, 0x17, 0x51, 0x30, 0xf0, 0xe4, 0xd0, 0x93, 0x74, 0x41, 0xbc, 0xe9, 0x8c, 0xfa, - 0x5b, 0x33, 0x3b, 0x66, 0x19, 0x0f, 0x2b, 0x44, 0x71, 0x38, 0xe8, 0xc2, 0x6d, 0x84, - 0x12, 0xca, 0xc8, 0x20, 0x86, 0xd6, 0x1b, 0x5d, 0x2c, 0x8c, 0xf0, 0xbb, 0xeb, 0xac, - 0x5b, 0x89, 0xbf, 0xe8, 0x2b, 0x58, 0x91, 0x76, 0x64, 0xba, 0xb9, 0x1c, 0xe2, 0xec, - 0xe2, 0x90, 0xb2, 0x7b, 0x60, 0x52, 0xd4, 0xbf, 0x99, 0x1a, 0x33, 0xf4, 0x58, 0x1a, - 0x63, 0x36, 0x25, 0x78, 0x79, 0x58, 0x89, 0x7f, 0xca, 0x4b, 0x98, 0xb7, 0xe7, 0x27, - 0x7c, 0x5e, 0x6a, 0x1d, 0x88, 0x59, 0x48, 0xc9, 0xd4, 0x84, 0xdd, 0x0c, 0xef, 0xef, - 0x85, 0x4e, 0x81, 0x76, 0xc3, 0x97, 0xdc, 0xfa, 0x77, 0x2e, 0x71, 0x14, 0x72, 0xe7, - 0x90, 0xba, 0x8d, 0x39, 0x35, 0xd5, 0x7c, 0xa3, 0x13, 0x49, 0x37, 0x9e, 0x62, 0x83, - 0xa6, 0xaa, 0x8f, 0xc9, 0x91, 0xef, 0xc7, 0xd3, 0xb7, 0xef, 0x66, 0xb9, 0x2f, 0xe0, - 0x9d, 0x35, 0x16, 0x27, 0x0a, 0xe1, 0x9a, 0x99, 0x92, 0x16, 0xee, 0xae, 0x16, 0x21, - 0x44, 0xac, 0xea, 0x56, 0x0d, 0x17, 0x72, 0x05, 0xf2, 0x6c, 0x97, 0x03, 0xb5, 0x4e, - 0x80, 0xaf, 0x1a, 0x87, 0x94, 0xd6, 0xd3, 0xf1, 0xc5, 0xee, 0xad, 0x22, 0x0b, 0x11, - 0x9f, 0x06, 0xb2, 0x00, 0x98, 0x6c, 0x91, 0x21, 0x32, 0xcb, 0x08, 0xa9, 0x8e, 0x0f, - 0xee, 0x35, 0xe7, 0xf7, 0x7f, 0xc8, 0x52, 0x1d, 0x38, 0x77, 0x3e, 0x61, 0x4e, 0xee, - 0xb8, 0xa3, 0xea, 0xd8, 0x6a, 0x02, 0x48, 0x32, 0xe6, 0x4a, 0x4c, 0x75, 0x72, 0x0c, - 0xdc, 0xdd, 0xf9, 0xd0, 0x77, 0x09, 0xa1, 0x68, 0xd0, 0x10, 0x12, 0xc2, 0xe4, 0xf3, - 0x34, 0x30, 0xf2, 0x99, 0x70, 0xc6, 0x0b, 0xe8, 0xc5, 0xe2, 0xc8, 0xcc, 0x8a, 0x86, - 0xed, 0xcd, 0x51, 0x2d, 0xa7, 0x0d, 0xd7, 0xbb, 0x40, 0xe2, 0x7b, 0x32, 0xdf, 0x3d, - 0x77, 0x6a, 0x4a, 0x7b, 0x00, 0xe3, 0xbd, 0x8f, 0x69, 0x7f, 0x1f, 0x4e, 0x5c, 0x9f, - 0xbe, 0xbe, 0xb4, 0xe6, 0xfa, 0xd9, 0x1e, 0x09, 0x3d, 0xd5, 0xba, 0xc9, 0x92, 0xac, - 0xbc, 0xb8, 0x38, 0x3f, 0x9a, 0x8d, 0x8c, 0x04, 0xea, 0x6e, 0x2e, 0x0d, 0x03, 0xa2, - 0xdf, 0x83, 0xd4, 0xf4, 0x94, 0x59, 0x5b, 0x2c, 0xa1, 0x0b, 0x70, 0x79, 0x25, 0x9c, - 0x50, 0x7d, 0xf1, 0xec, 0xe4, 0x4d, 0xea, 0x4e, 0x9a, 0x4a, 0xe4, 0x0e, 0xc8, 0x33, - 0x1e, 0xeb, 0x03, 0x94, 0x73, 0xbd, 0x39, 0xc0, 0x9d, 0x01, 0x4b, 0x0d, 0x7b, 0xb9, - 0x01, 0x61, 0x66, 0x55, 0x4f, 0xf3, 0x8a, 0x1d, 0x77, 0xf2, 0xfd, 0xa4, 0xe7, 0xeb, - 0xa7, 0xa7, 0x8a, 0xb3, 0x1f, 0x38, 0x29, 0x42, 0x52, 0xa2, 0xb1, 0x0f, 0xd2, 0x86, - 0x5b, 0x57, 0x05, 0x05, 0x5d, 0xfe, 0x9b, 0x3e, 0x9e, 0x8f, 0x7a, 0xd5, 0xf4, 0x00, - 0x7d, 0xbe, 0x42, 0x2b, 0x3a, 0xa0, 0xbe, 0xb9, 0xd1, 0xc8, 0x9d, 0x37, 0x46, 0x08, - 0x54, 0xff, 0x6e, 0x5f, 0x03, 0xe5, 0xff, 0x3d, 0x4f, 0x18, 0x48, 0xf4, 0xcc, 0x64, - 0x21, 0x8a, 0x01, 0xf2, 0x47, 0x2b, 0xb0, 0x55, 0x80, 0x2f, 0x97, 0xf3, 0x20, 0x41, - 0xa7, 0x92, 0x79, 0x0b, 0x7c, 0x22, 0x6b, 0x04, 0xa6, 0xea, 0xe8, 0x5f, 0x1b, 0x71, - 0xca, 0x19, 0xa1, 0x71, 0x89, 0x02, 0xb4, 0xc3, 0xa3, 0xb5, 0x06, 0xd8, 0xc1, 0xb7, - 0xae, 0x72, 0x8c, 0x9b, 0x6c, 0xc3, 0x17, 0xe5, 0xe0, 0xde, 0xe5, 0x33, 0xe2, 0xe9, - 0x99, 0x73, 0xd8, 0x83, 0xa4, 0x0c, 0x6e, 0x68, 0xf2, 0x31, 0xd2, 0xcb, 0x01, 0x2f, - 0x60, 0xc1, 0x43, 0xcc, 0xab, 0xdd, 0x40, 0x45, 0x59, 0x0d, 0x9e, 0x43, 0xfb, 0xa3, - 0x6f, 0xe4, 0xcf, 0xd9, 0x7b, 0x4b, 0xdd, 0x0c, 0x4d, 0x2c, 0x93, 0xc5, 0x72, 0x8b, - 0x12, 0x87, 0xfd, 0x25, 0x41, 0x72, 0x2c, 0x69, 0x9b, 0xc1, 0xa0, 0x05, 0x83, 0xdb, - 0xc9, 0x48, 0xd5, 0x32, 0x4a, 0xc5, 0xbd, 0x7a, 0x68, 0x09, 0x64, 0x67, 0x3e, 0xdf, - 0x2c, 0x6d, 0xeb, 0xb1, 0xc8, 0xe1, 0xd0, 0x24, 0x16, 0xe6, 0xbd, 0xb2, 0xa7, 0x68, - 0x1b, 0xf4, 0x29, 0x92, 0x25, 0xc2, 0x1b, 0x5d, 0xb6, 0xa8, 0x45, 0xad, 0x10, 0x4d, - 0x34, 0x29, 0xcd, 0xc5, 0x9e, 0x3b, 0xca, 0xcf, 0x6d, 0xbc, 0x88, 0xaf, 0x0f, 0x67, - 0xdc, 0xbd, 0xf3, 0xa0, 0x72, 0x3e, 0x4d, 0x4b, 0xce, 0x32, 0x85, 0x1b, 0xb5, 0x19, - 0x7a, 0x8f, 0x43, 0x30, 0xb2, 0x72, 0x27, 0xf0, 0xb7, 0x71, 0xd0, 0xaf, 0x17, 0x5e, - 0x9c, 0x3f, 0x6e, 0x1f, 0x68, 0x46, 0x2e, 0xe7, 0xfe, 0x17, 0x97, 0xd9, 0x28, 0x40, - 0x6f, 0x92, 0x38, 0xa3, 0xf3, 0xfd, 0x83, 0x6a, 0x27, 0x56, 0xdd, 0x0a, 0x11, 0xe1, - 0xab, 0x94, 0x9d, 0x5e, 0x30, 0x89, 0x4f, 0x56, 0x29, 0x95, 0x25, 0xe6, 0x5d, 0x95, - 0x0f, 0x2e, 0xb5, 0x0b, 0x3a, 0x8e, 0xa7, 0xac, 0xad, 0x82, 0xde, 0x26, 0x2f, 0xa3, - 0x44, 0x80, 0xa2, 0x9c, 0x26, 0x19, 0xba, 0x45, 0x90, 0x3d, 0xf9, 0xa7, 0xf9, 0x86, - 0x2d, 0xc0, 0x49, 0xce, 0xf3, 0x97, 0xf7, 0x73, 0xbe, 0xed, 0xd3, 0x22, 0x6a, 0x8c, - 0xab, 0x1c, 0x86, 0x4d, 0x00, 0xb8, 0xfd, 0x37, 0xea, 0xf1, 0xd5, 0x93, 0x5a, 0x5b, - 0xbb, 0x6a, 0xd9, 0xf2, 0x7a, 0x1d, 0x8b, 0xaf, 0xc0, 0xac, 0x5f, 0x58, 0x02, 0x36, - 0x93, 0x82, 0x2a, 0x1d, 0xd4, 0xa7, 0xca, 0x1c, 0x49, 0xec, 0x81, 0x4e, 0x8f, 0xe6, - 0xe0, 0xe0, 0xde, 0x54, 0x6a, 0x4f, 0xbe, 0x7d, 0x25, 0x67, 0x0b, 0x2f, 0xc6, 0x8a, - 0x8f, 0xb2, 0xc4, 0xa6, 0x3d, 0xef, 0xec, 0x79, 0xc9, 0x0c, 0x63, 0xff, 0x96, 0xe5, - 0x40, 0xb7, 0x61, 0x5d, 0x43, 0xa6, 0x26, 0x1d, 0x57, 0x73, 0x03, 0x06, 0xb6, 0x63, - 0x2c, 0x8e, 0xe6, 0x1b, 0xaa, 0x4a, 0xb4, 0xd3, 0x08, 0x4d, 0x65, 0x9c, 0xab, 0xcf, - 0xc4, 0x06, 0x4c, 0x09, 0xd2, 0x42, 0x69, 0xb3, 0x03, 0x17, 0x10, 0xb6, 0x7d, 0x3b, - 0x0b, 0x73, 0x6f, 0xac, 0xbc, 0x18, 0x1e, 0xb1, 0xdc, 0x8c, 0x49, 0x3f, 0x10, 0xdb, - 0xe6, 0xfe, 0x45, 0xfd, 0xd4, 0xab, 0x60, 0x22, 0xfa, 0xbd, 0xd3, 0x4c, 0x09, 0xf7, - 0x51, 0x04, 0xc3, 0x85, 0xc9, 0x26, 0x83, 0x41, 0xc1, 0x6e, 0xbe, 0x80, 0xf8, 0xc8, - 0x0e, 0x8e, 0x06, 0x23, 0x06, 0x03, 0x99, 0x5a, 0xde, 0x55, 0x61, 0xfe, 0xd4, 0x5c, - 0xf8, 0xd1, 0x14, 0xd4, 0xcf, 0x02, 0x42, 0x0c, 0x4b, 0x96, 0x2d, 0xc2, 0x02, 0xf8, - 0xa5, 0x07, 0xf3, 0xd8, 0xe8, 0xa3, 0x44, 0xfb, 0xa1, 0x0a, 0x32, 0x7f, 0xf2, 0x22, - 0x54, 0xf6, 0xc3, 0xac, 0x8f, 0x3c, 0xf9, 0x70, 0x0b, 0x1f, 0xd2, 0xec, 0xbe, 0x9f, - 0x4e, 0x91, 0xe4, 0x3a, 0x65, 0x4f, 0xff, 0x02, 0x7c, 0xd9, 0x17, 0x4b, 0x63, 0x8e, - 0x6e, 0xfe, 0xc4, 0xab, 0xfb, 0xa1, 0x87, 0xf8, 0xf3, 0xdb, 0xa0, 0x45, 0x9d, 0xa6, - 0xc3, 0xf8, 0x00, 0xcb, 0x6b, 0x61, 0x33, 0xa8, 0xb4, 0xac, 0x1e, 0xf6, 0x58, 0xd1, - 0x11, 0xc0, 0x3f, 0x07, 0x22, 0x08, 0xdc, 0xc2, 0x07, 0xa2, 0x22, 0x3a, 0x70, 0x22, - 0x92, 0x43, 0x2e, 0x83, 0x06, 0xfc, 0x03, 0x04, 0x63, 0xe7, 0x54, 0xff, 0x0f, 0x15, - 0x3d, 0x97, 0xbc, 0x9c, 0xe9, 0x6d, 0xff, 0x4b, 0xed, 0x2f, 0x1e, 0xa5, 0xb8, 0xea, - 0x87, 0x6d, 0x2e, 0xe4, 0xe4, 0xf6, 0xe4, 0x9a, 0x4a, 0x85, 0xa9, 0xcf, 0x4a, 0x33, - 0xdc, 0xd9, 0x36, 0x60, 0xa4, 0x25, 0x43, 0xe5, 0x34, 0x22, 0x39, 0x0d, 0x66, 0x5b, - 0xdd, 0x30, 0x24, 0x78, 0xb3, 0x3c, 0x8d, 0x57, 0x47, 0x92, 0x41, 0x4c, 0x5f, 0xe5, - 0xb7, 0x4f, 0xe1, 0xd1, 0x69, 0x52, 0x5c, 0x99, 0x30, 0x1a, 0x3a, 0x68, 0xa0, 0xc8, - 0x5f, 0x02, 0x0f, 0xd5, 0x8f, 0x6d, 0x9f, 0x3a, 0xcb, 0x13, 0x9c, 0x96, 0x65, 0x38, - 0x56, 0xa3, 0x2e, 0x21, 0x02, 0x7a, 0xa2, 0xba, 0x18, 0x60, 0x10, 0xd5, 0x3c, 0xdd, - 0x4c, 0x41, 0x50, 0xcb, 0x2b, 0xb2, 0x42, 0x44, 0x65, 0x42, 0xb0, 0x17, 0x84, 0x40, - 0x1f, 0xa2, 0xcb, 0xf1, 0x22, 0xc9, 0xf1, 0x1d, 0x8c, 0x81, 0x36, 0x98, 0x7b, 0x67, - 0x86, 0x29, 0x93, 0x84, 0x58, 0x5f, 0x9c, 0xa2, 0x93, 0x53, 0x7b, 0x4b, 0xe5, 0x72, - 0x6f, 0x94, 0xd4, 0x77, 0x60, 0x5a, 0x8a, 0x6c, 0x53, 0x06, 0x02, 0xbb, 0x46, 0xc4, - 0xde, 0x20, 0x7f, 0xc5, 0x9e, 0x91, 0xe4, 0xa9, 0x0a, 0x91, 0x11, 0x77, 0x74, 0x69, - 0xf1, 0xe2, 0x87, 0x82, 0x76, 0x7d, 0x9d, 0xe5, 0x7d, 0xea, 0xde, 0xad, 0xcb, 0x4a, - 0xf5, 0x19, 0x3e, 0x09, 0xc9, 0xbb, 0x74, 0x73, 0x77, 0x3a, 0x8c, 0xa5, 0x6d, 0x76, - 0x51, 0x1d, 0x65, 0x99, 0x20, 0xdb, 0x99, 0x64, 0xd3, 0x2b, 0xad, 0xb6, 0x1f, 0x4c, - 0xf6, 0xb0, 0x22, 0xd7, 0xc1, 0x53, 0x93, 0x18, 0x49, 0x64, 0x3e, 0x8b, 0x99, 0xea, - 0xe0, 0x28, 0x4f, 0x8b, 0x01, 0x15, 0xb4, 0x23, 0x7a, 0x7c, 0x5d, 0x81, 0x97, 0x0f, - 0xe8, 0x7c, 0x6f, 0x84, 0xb6, 0x68, 0x6c, 0x46, 0x25, 0xdb, 0xdd, 0x9d, 0x79, 0xd2, - 0xc5, 0x55, 0xdd, 0x4f, 0xce, 0xed, 0x2c, 0x5e, 0x5e, 0x89, 0x6f, 0x63, 0x1a, 0xe4, - 0x59, 0x7e, 0x9c, 0xc0, 0xbe, 0xe7, 0xb3, 0x02, 0x5f, 0x95, 0x56, 0x10, 0x6a, 0x84, - 0x3a, 0x18, 0x22, 0x7f, 0x5a, 0xb9, 0x61, 0x7d, 0x7b, 0xcb, 0x1a, 0xf5, 0x28, 0xfa, - 0xa7, 0xa0, 0x52, 0xea, 0x4f, 0x52, 0xca, 0x59, 0x45, 0x57, 0xfd, 0xad, 0x33, 0x05, - 0x2b, 0xc8, 0x2b, 0x39, 0xc6, 0xa6, 0x09, 0xa0, 0x70, 0x75, 0x3d, 0x78, 0x8b, 0x2c, - 0x4a, 0x2c, 0xae, 0xbb, 0xe7, 0x9f, 0xf0, 0x12, 0x07, 0x1c, 0x07, 0x08, 0x10, 0x94, - 0xad, 0x60, 0x59, 0xc2, 0x8f, 0x48, 0xe5, 0x56, 0xc4, 0xe8, 0xd8, 0xc5, 0x37, 0x8b, - 0xc2, 0x93, 0x07, 0x6b, 0xb4, 0x97, 0x07, 0x5f, 0x9c, 0xa0, 0xba, 0x13, 0x11, 0x55, - 0x0f, 0xa2, 0x17, 0x3d, 0x0e, 0xb1, 0xf0, 0xbd, 0xdd, 0xf3, 0xb3, 0xd5, 0xc2, 0x43, - 0xff, 0xea, 0xbe, 0xe8, 0x23, 0xcd, 0x63, 0xb4, 0x39, 0x39, 0xce, 0x95, 0x46, 0xed, - 0x4c, 0x41, 0xe6, 0x0c, 0xcc, 0x7e, 0x1c, 0x54, 0x3c, 0xb3, 0xe2, 0xd3, 0x50, 0xe2, - 0xe2, 0xe9, 0x74, 0x21, 0x5c, 0xf7, 0xaa, 0x96, 0x9b, 0x66, 0x81, 0x14, 0xac, 0xdb, - 0x29, 0xf4, 0xcd, 0xcf, 0xdc, 0xec, 0x2a, 0x8c, 0xe4, 0xf5, 0x95, 0xf4, 0xff, 0x5f, - 0x70, 0x7e, 0x7f, 0xa4, 0xde, 0xe8, 0xbf, 0x8f, 0x39, 0x52, 0xae, 0x32, 0xe7, 0x7f, - 0x34, 0xf8, 0xb3, 0xab, 0xaa, 0xe9, 0x69, 0x28, 0xba, 0x4a, 0x6c, 0x0f, 0xbf, 0x5b, - 0x29, 0x19, 0x2d, 0xae, 0x80, 0x0d, 0xfa, 0x79, 0x57, 0x0c, 0xaf, 0x0b, 0xb8, 0x33, - 0xbd, 0x37, 0xa3, 0xd4, 0xbe, 0xaf, 0x09, 0x1f, 0x6b, 0x3e, 0x55, 0xaa, 0xe5, 0x25, - 0xf4, 0x13, 0xac, 0x80, 0x4c, 0x34, 0x7d, 0x54, 0x1d, 0x2c, 0x09, 0xec, 0x6e, 0x54, - 0x03, 0x5d, 0xf1, 0xd8, 0x30, 0x28, 0x4d, 0x9b, 0x46, 0xff, 0xd2, 0xb2, 0xeb, 0x04, - 0x0b, 0x61, 0x77, 0xd0, 0xa0, 0x9c, 0x16, 0x60, 0x34, 0xa9, 0x57, 0xb1, 0x8f, 0xf6, - 0x2e, 0x43, 0x4a, 0x3e, 0xc7, 0x32, 0x62, 0xe4, 0xb2, 0x3f, 0xec, 0x9d, 0x29, 0x0a, - 0x81, 0xc5, 0xb1, 0xf7, 0x3c, 0xb4, 0xcd, 0x1c, 0x47, 0x2b, 0x86, 0xe5, 0x34, 0xab, - 0x9e, 0x65, 0x53, 0x29, 0x5d, 0xb0, 0xcf, 0x34, 0xe1, 0x39, 0x2a, 0xad, 0x5a, 0xbc, - 0xf3, 0x98, 0x64, 0x16, 0xa7, 0x0a, 0x9d, 0xbe, 0x59, 0xbb, 0x95, 0x8e, 0xbc, 0x71, - 0x1c, 0x3a, 0xe0, 0x8c, 0xaf, 0x52, 0xec, 0xa9, 0xcb, 0x54, 0xc4, 0x58, 0xbe, 0x7f, - 0x5e, 0x62, 0x14, 0xec, 0xa0, 0xf0, 0xa3, 0x81, 0x52, 0x62, 0x20, 0x01, 0x32, 0xe6, - 0x14, 0x54, 0x37, 0xec, 0xd2, 0x1f, 0xc8, 0x03, 0x6c, 0xb0, 0x0a, 0x49, 0x13, 0x84, - 0xc3, 0x41, 0xd8, 0x72, 0xdc, 0xda, 0x31, 0xb1, 0x42, 0x96, 0x73, 0xd9, 0xc4, 0xf5, - 0x7b, 0x81, 0xa0, 0x23, 0x6d, 0xa5, 0xec, 0x55, 0x02, 0xee, 0x29, 0x63, 0x15, 0x0a, - 0x00, 0x26, 0xbd, 0x63, 0xef, 0x67, 0x9e, 0x8c, 0x25, 0xb8, 0xec, 0xee, 0x06, 0x56, - 0x4a, 0xf3, 0xb0, 0x2d, 0xea, 0xb1, 0x06, 0x97, 0xa2, 0x4d, 0xe6, 0x7d, 0x4f, 0x65, - 0x04, 0xae, 0x27, 0x37, 0xb8, 0xe1, 0x73, 0x25, 0xc2, 0xff, 0x15, 0x0c, 0x62, 0xe3, - 0x79, 0x83, 0x44, 0xa1, 0xad, 0x3c, 0xbb, 0x75, 0xb7, 0xf2, 0xa1, 0x57, 0x38, 0xf6, - 0x01, 0xcf, 0x00, 0xf7, 0xe8, 0xbc, 0x08, 0xb6, 0x89, 0x56, 0x7e, 0x4c, 0x7c, 0x01, - 0x05, 0x8b, 0xee, 0xc2, 0x90, 0x3c, 0x5c, 0xa6, 0xb4, 0xc4, 0xa5, 0x71, 0xf4, 0x60, - 0xd6, 0x05, 0x87, 0x36, 0x29, 0x96, 0xc6, 0xe1, 0x25, 0x54, 0xe8, 0xe3, 0x4e, 0x68, - 0x3a, 0x27, 0xf8, 0xa5, 0xff, 0x97, 0x1d, 0x5a, 0x0d, 0xc2, 0xf3, 0xef, 0xd3, 0x88, - 0x99, 0x87, 0xc1, 0xcc, 0x39, 0xce, 0x5d, 0x4b, 0x6b, 0x54, 0x4c, 0xe0, 0x4c, 0x71, - 0xee, 0x4b, 0xfa, 0xe5, 0x04, 0x0d, 0x61, 0xf0, 0x57, 0xe4, 0xf7, 0x70, 0x17, 0x28, - 0xf1, 0x20, 0x04, 0xa7, 0xf7, 0xed, 0xeb, 0x3a, 0xb2, 0x26, 0x09, 0xed, 0x33, 0xb0, - 0xab, 0x5d, 0x69, 0xb1, 0x2d, 0x45, 0x76, 0x57, 0x77, 0x14, 0xdf, 0xc6, 0xdd, 0xa7, - 0x1f, 0xf6, 0x01, 0x7b, 0x55, 0xb3, 0x35, 0x4d, 0x11, 0xe9, 0x21, 0x67, 0x92, 0xe5, - 0x60, 0x9f, 0xc0, 0x67, 0x88, 0xec, 0x66, 0x8e, 0xef, 0x64, 0x5e, 0x63, 0xb3, 0x7e, - 0x2d, 0x0c, 0xd2, 0x63, 0x04, 0x08, 0x00, 0xbc, 0x8a, 0xa2, 0x80, 0x15, 0x6a, 0x79, - 0x4f, 0x62, 0xa5, 0xf6, 0x93, 0xeb, 0xd9, 0x07, 0x4b, 0x5d, 0x35, 0x4a, 0x71, 0xc8, - 0xe3, 0x36, 0xde, 0x04, 0x08, 0xac, 0x70, 0x80, 0xa2, 0xae, 0xee, 0x36, 0x6c, 0x58, - 0x14, 0x6f, 0x32, 0xe3, 0x49, 0xa9, 0xbc, 0x65, 0x7e, 0xc9, 0xe5, 0x7a, 0x89, 0xa0, - 0x4c, 0xce, 0xee, 0x21, 0xbd, 0xf3, 0x79, 0x3e, 0x49, 0xa5, 0xcf, 0x71, 0x3a, 0x42, - 0xd0, 0x29, 0xdd, 0xdb, 0x3d, 0xb4, 0x95, 0x09, 0x2c, 0x37, 0xce, 0x81, 0x4b, 0xe7, - 0x3e, 0xf4, 0xec, 0x8d, 0x70, 0xe8, 0x69, 0xbd, 0x2b, 0x78, 0x8f, 0x15, 0x00, 0xfe, - 0x5e, 0xe5, 0x6c, 0x0c, 0xe7, 0x04, 0xeb, 0xa2, 0xc1, 0xa3, 0xa3, 0x29, 0x0d, 0xe6, - 0xec, 0x68, 0xcc, 0xb5, 0xef, 0x7c, 0xd0, 0x21, 0x2a, 0x3f, 0x09, 0x96, 0x92, 0xcf, - 0x00, 0x04, 0x8d, 0xe5, 0x01, 0x26, 0x19, 0xe7, 0x41, 0x69, 0x2b, 0xfc, 0x74, 0x05, - 0xba, 0x3e, 0x87, 0x5e, 0x98, 0xb7, 0xca, 0x31, 0xe9, 0x65, 0xa1, 0x6f, 0xdd, 0xb5, - 0xb0, 0xb7, 0x72, 0xa3, 0xf5, 0xd0, 0x50, 0xd8, 0xad, 0x7f, 0x60, 0x7f, 0x55, 0xc0, - 0xdc, 0x52, 0xb4, 0x8f, 0xb0, 0x2a, 0x8b, 0x1d, 0xef, 0xc6, 0xc3, 0x10, 0xb2, 0x47, - 0x55, 0x59, 0xb4, 0x7e, 0x84, 0x4e, 0xd3, 0x77, 0x60, 0xd7, 0xd1, 0x6f, 0x27, 0xcb, - 0x48, 0xbf, 0x36, 0x16, 0xc4, 0x6f, 0xb0, 0xcf, 0x3c, 0x8c, 0x28, 0xb9, 0x39, 0x27, - 0x80, 0x0a, 0x29, 0x16, 0xa4, 0x07, 0xa6, 0x0d, 0x68, 0x99, 0x7b, 0x10, 0x50, 0x51, - 0x32, 0xad, 0x33, 0xf9, 0xce, 0x26, 0xb4, 0xac, 0xba, 0x27, 0xa2, 0xa0, 0xc2, 0x18, - 0xdb, 0x15, 0xa5, 0xd7, 0xaa, 0xed, 0x4f, 0x6a, 0x72, 0x00, 0x36, 0x72, 0xca, 0x70, - 0x49, 0x8b, 0x05, 0x49, 0x4a, 0x93, 0x34, 0x1f, 0xcf, 0x96, 0xc0, 0x99, 0x4e, 0x42, - 0x7b, 0xeb, 0xd3, 0x56, 0xe4, 0x17, 0x6d, 0xec, 0x83, 0xe6, 0xfe, 0x80, 0x02, 0x9c, - 0xfc, 0x47, 0x8b, 0x88, 0xb6, 0xfd, 0x38, 0xc0, 0x39, 0xe0, 0x8b, 0x6f, 0xd9, 0x5d, - 0xab, 0xcf, 0xb2, 0x5f, 0x23, 0x8b, 0x26, 0x62, 0x06, 0xb0, 0xa2, 0xf9, 0xa2, 0xee, - 0xa1, 0xc0, 0x83, 0xfa, 0xc8, 0x08, 0xaa, 0xfa, 0x03, 0x65, 0x66, 0xcc, 0xd2, 0x02, - 0xbc, 0xfa, 0x41, 0x4e, 0x71, 0xc8, 0xb4, 0x89, 0x33, 0xc8, 0xed, 0x45, 0x28, 0x7e, - 0x1b, 0x43, 0x9b, 0x61, 0x06, 0xa5, 0x50, 0x94, 0x73, 0xf5, 0x7b, 0x87, 0x88, 0xaf, - 0x52, 0x7c, 0xf9, 0xa7, 0xab, 0xa5, 0x93, 0xdc, 0x9f, 0x5e, 0x5a, 0xca, 0x1a, 0x64, - 0x8e, 0xe4, 0x88, 0xf3, 0x6d, 0xeb, 0x4a, 0x3f, 0xdb, 0x0f, 0xf6, 0xf5, 0xa3, 0x04, - 0x4a, 0x63, 0xe1, 0x7f, 0x70, 0xa4, 0x30, 0x38, 0x24, 0x60, 0x3a, 0xb5, 0x0e, 0x9b, - 0xf7, 0x5b, 0xae, 0xb5, 0x7b, 0xfd, 0xc8, 0x9b, 0xfd, 0xbc, 0x27, 0x27, 0x9d, 0x10, - 0x73, 0xbf, 0x7f, 0x95, 0x05, 0xfb, 0x31, 0x68, 0xd2, 0x06, 0xe2, 0xbf, 0x41, 0x02, - 0xbf, 0x15, 0x9c, 0xff, 0x61, 0xe6, 0xd6, 0x6c, 0x80, 0x37, 0x50, 0xda, 0x25, 0x4c, - 0xd6, 0xb8, 0x1a, 0xed, 0x42, 0x09, 0x97, 0x94, 0xb8, 0x4e, 0xce, 0x90, 0x42, 0x18, - 0xe6, 0xf6, 0x6e, 0xc6, 0x34, 0xe9, 0x2e, 0xef, 0xf4, 0x5f, 0x52, 0xe0, 0x4b, 0x4b, - 0x79, 0x5a, 0x15, 0x25, 0xaa, 0xf9, 0xc5, 0x1d, 0x62, 0x60, 0xfb, 0xd6, 0x4e, 0x8d, - 0x8a, 0xc2, 0x66, 0xdc, 0x6e, 0x7d, 0xf6, 0x15, 0x3a, 0xd9, 0x73, 0x55, 0x83, 0x79, - 0x28, 0x40, 0x4c, 0xd5, 0x81, 0xbc, 0x9c, 0xf9, 0xdc, 0xd6, 0x67, 0x47, 0xdc, 0x97, - 0x0a, 0x9f, 0x00, 0xde, 0xb4, 0x4b, 0xd6, 0x34, 0xab, 0x04, 0x2e, 0x01, 0x04, 0xc1, - 0xce, 0x74, 0x7f, 0x53, 0x75, 0x1b, 0xc3, 0x3e, 0x38, 0x4c, 0x6b, 0x55, 0x76, 0x39, - 0x9e, 0x16, 0xf8, 0xf0, 0xcb, 0x08, 0xde, 0x35, 0x08, 0x37, 0x33, 0x95, 0x45, 0x87, - 0xc1, 0xc2, 0x4d, 0xf2, 0xae, 0x66, 0x30, 0xff, 0xfe, 0x99, 0x62, 0x15, 0xef, 0xe4, - 0xd2, 0x62, 0x6d, 0xeb, 0x20, 0x56, 0x6a, 0x8f, 0x5e, 0xad, 0x2f, 0x04, 0xdb, 0x5d, - 0x08, 0x77, 0x9c, 0x9c, 0x65, 0x9e, 0xa3, 0x43, 0xcd, 0x78, 0x46, 0x34, 0xc9, 0x9d, - 0x8c, 0x8b, 0xad, 0xa9, 0x3b, 0xe8, 0xe6, 0xda, 0x84, 0x15, 0x94, 0xba, 0xcf, 0x7c, - 0xb3, 0xe6, 0x92, 0xc7, 0x4b, 0x5f, 0xfe, 0x95, 0x78, 0x73, 0x11, 0x3a, 0x1a, 0xb0, - 0x64, 0x02, 0x6f, 0x6d, 0xee, 0x8b, 0x48, 0xa3, 0x84, 0xa1, 0x33, 0x83, 0x18, 0x36, - 0x07, 0x86, 0x50, 0x27, 0x84, 0xd1, 0x7d, 0x40, 0x0c, 0xe3, 0xd7, 0x21, 0x78, 0x7e, - 0xdc, 0x4c, 0x6b, 0x39, 0x35, 0x66, 0x25, 0x10, 0x77, 0x10, 0x00, 0x68, 0x0d, 0x78, - 0xbb, 0x49, 0xc5, 0x66, 0xef, 0x27, 0xdf, 0x61, 0xc9, 0xfe, 0xb9, 0x2c, 0x08, 0x97, - 0x59, 0x44, 0x87, 0x27, 0xa9, 0x34, 0xe3, 0x57, 0x95, 0x3d, 0xe1, 0xe9, 0xe9, 0x0f, - 0xd8, 0xdf, 0xfe, 0x40, 0xb8, 0x73, 0xbc, 0xd5, 0xb9, 0x82, 0x08, 0xdf, 0x4b, 0x2c, - 0xa2, 0x89, 0x7a, 0xf9, 0x0d, 0x8c, 0x8a, 0x23, 0x62, 0x30, 0x02, 0xa9, 0xd8, 0xbc, - 0x02, 0xe8, 0x06, 0x25, 0x4f, 0x41, 0x0e, 0x3b, 0x02, 0x40, 0x9c, 0xbe, 0xbf, 0xce, - 0x8a, 0xcf, 0x65, 0xcf, 0x39, 0x42, 0x6b, 0x64, 0xa6, 0xba, 0x93, 0x74, 0xa1, 0x3d, - 0x72, 0x59, 0x62, 0x3f, 0x65, 0xe9, 0x3e, 0x10, 0xbf, 0x1f, 0x16, 0xba, 0x7a, 0xe0, - 0x7d, 0xa9, 0x20, 0x58, 0x1c, 0x70, 0x40, 0x9e, 0xdc, 0x7b, 0x9e, 0x21, 0x4e, 0x95, - 0x91, 0x92, 0x82, 0x4c, 0x1d, 0xa6, 0x5d, 0x33, 0x7b, 0x73, 0x75, 0xf5, 0x03, 0x2f, - 0xea, 0xd3, 0xb4, 0xf3, 0x28, 0x48, 0x11, 0x95, 0x0c, 0x7a, 0x90, 0xae, 0xc9, 0x75, - 0xd4, 0xe3, 0x62, 0x9f, 0x52, 0xd1, 0x9a, 0x16, 0x4e, 0x51, 0x16, 0xef, 0x3a, 0xd0, - 0x22, 0x44, 0x2d, 0x1e, 0xec, 0x76, 0xb8, 0x88, 0x73, 0x8b, 0x53, 0xe5, 0x05, 0x58, - 0xa7, 0x0f, 0x20, 0xc8, 0xac, 0xb5, 0x8d, 0xee, 0x63, 0x27, 0x15, 0xe4, 0x78, 0xe2, - 0xbc, 0x21, 0xbc, 0xfb, 0xe3, 0x15, 0x59, 0x96, 0xca, 0xe7, 0xbd, 0x97, 0xf0, 0x2b, - 0x51, 0x6d, 0x32, 0x00, 0xfb, 0x3c, 0x17, 0x39, 0x7c, 0xc1, 0x2b, 0xb7, 0xa1, 0x9f, - 0xd4, 0x36, 0xe6, 0x7a, 0xbc, 0xe6, 0x6d, 0x30, 0xfe, 0xc0, 0x47, 0xfb, 0x27, 0x70, - 0x82, 0x0e, 0x47, 0x6f, 0x3e, 0x32, 0xbc, 0x48, 0x3b, 0xf5, 0x31, 0x64, 0xae, 0x49, - 0x70, 0xf1, 0x1b, 0x9c, 0xae, 0xe4, 0xed, 0x6c, 0xb8, 0xd2, 0xd7, 0x0f, 0x69, 0x13, - 0xd8, 0xe0, 0x2a, 0xf8, 0xfb, 0xb1, 0xe4, 0x09, 0xb4, 0xef, 0x08, 0x04, 0x48, 0xe5, - 0x3b, 0xe6, 0xe5, 0xe6, 0x05, 0x75, 0xdf, 0xde, 0x94, 0x28, 0xb0, 0x06, 0x96, 0x61, - 0x1a, 0x2f, 0x72, 0x33, 0x2a, 0xe2, 0x90, 0x23, 0xdd, 0x88, 0xae, 0x77, 0xf1, 0x5b, - 0x8a, 0xe2, 0xc2, 0x4b, 0x86, 0xcf, 0x3d, 0x57, 0x43, 0x9c, 0xaf, 0x17, 0xf2, 0x8e, - 0xda, 0x94, 0x93, 0x2e, 0xef, 0x28, 0x53, 0x4e, 0x16, 0x49, 0xce, 0xf8, 0x85, 0x40, - 0xfc, 0xb1, 0xa6, 0x3e, 0x11, 0x5c, 0x58, 0x22, 0xaf, 0xa4, 0x40, 0xc8, 0xd7, 0x9d, - 0x66, 0xf9, 0xbb, 0x1f, 0x48, 0xe1, 0x14, 0x0b, 0x06, 0xec, 0x87, 0x18, 0x3c, 0xbc, - 0x6e, 0x95, 0xf6, 0xcd, 0x5f, 0x7e, 0xbc, 0xad, 0xb8, 0x97, 0xc7, 0x7b, 0x4a, 0xfb, - 0x36, 0x7b, 0x95, 0x2d, 0xbb, 0x71, 0x7f, 0x75, 0x18, 0x90, 0xc8, 0xac, 0x30, 0x36, - 0xda, 0xcd, 0xbd, 0x78, 0x4a, 0x0d, 0x83, 0xab, 0xb8, 0x44, 0x6b, 0x3f, 0x93, 0x96, - 0x33, 0x5f, 0xbf, 0x0b, 0x44, 0xed, 0xc9, 0x9e, 0x1c, 0x67, 0xc5, 0xc3, 0x81, 0x6a, - 0xce, 0x76, 0x29, 0xe6, 0xe7, 0xb0, 0x28, 0xd6, 0xc8, 0x62, 0x74, 0x9e, 0x86, 0xeb, - 0xc5, 0x11, 0x7e, 0x21, 0xf4, 0x23, 0xe1, 0x8d, 0x09, 0x76, 0xa1, 0xf5, 0x1d, 0x45, - 0x47, 0x6d, 0xa5, 0x60, 0xff, 0x23, 0x15, 0x42, 0xbb, 0x21, 0xc3, 0xde, 0xd2, 0xf2, - 0x3b, 0x2a, 0x50, 0xe0, 0xb8, 0x22, 0x56, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x1d, 0x11, - 0x65, 0xd7, 0x60, 0x70, 0x2e, 0xf1, 0x03, 0xd2, 0x23, 0x67, 0x26, 0x90, 0x23, 0x59, - 0xbe, 0x8d, 0x79, 0x73, 0x52, 0xf9, 0x6d, 0x22, 0x46, 0xa2, 0xee, 0x0a, 0xf8, 0x0a, - 0x2a, 0x2d, 0x89, 0xa5, 0x85, 0x30, 0xd6, 0xe3, 0x6b, 0xd3, 0x3a, 0x00, 0xc1, 0xb8, - 0x93, 0xd6, 0xff, 0x8f, 0x90, 0x01, 0x44, 0x15, 0x1b, 0xee, 0x34, 0xc7, 0x94, 0x4b, - 0x99, 0xed, 0x6e, 0x79, 0x45, 0xe7, 0xf0, 0xde, 0x87, 0x26, 0x3d, 0x0b, 0xba, 0x6e, - 0x55, 0xac, 0x96, 0xa9, 0x6d, 0x49, 0x95, 0x12, 0x9b, 0xcf, 0xa9, 0xd9, 0xda, 0x6d, - 0xe6, 0xdd, 0x48, 0x26, 0x39, 0x15, 0x3a, 0x81, 0x69, 0xa4, 0xab, 0x46, 0x4e, 0x39, - 0x0b, 0x7f, 0x0a, 0x96, 0xd1, 0x4a, 0x73, 0xf7, 0x69, 0x7f, 0x7e, 0xce, 0x3c, 0xd7, - 0x81, 0xd3, 0x5d, 0xd2, 0x2a, 0xdd, 0xdd, 0x2f, 0x5d, 0x34, 0x52, 0x04, 0xe4, 0xbb, - 0x55, 0x7e, 0x88, 0x45, 0x3f, 0x18, 0x8c, 0xac, 0xbe, 0x92, 0x29, 0x87, 0xbb, 0xe3, - 0xb3, 0xd9, 0x76, 0x82, 0x61, 0x35, 0xc1, 0x03, 0xb6, 0xca, 0x18, 0x2b, 0x63, 0xe9, - 0xe6, 0x7f, 0x83, 0xdc, 0x9f, 0x48, 0x93, 0x33, 0xd5, 0x2a, 0x7f, 0xd7, 0x68, 0x8a, - 0x58, 0xd6, 0x62, 0x0b, 0x67, 0xe9, 0xc7, 0xb0, 0x91, 0x6f, 0xef, 0x90, 0xf1, 0x5d, - 0x8e, 0x4e, 0xb8, 0x0c, 0xf5, 0x99, 0x68, 0x2f, 0x95, 0x4f, 0xf4, 0xe0, 0xb3, 0x71, - 0x83, 0x13, 0x0c, 0xa2, 0xee, 0xd0, 0x91, 0x3f, 0x46, 0xa4, 0xdb, 0x99, 0x2a, 0x1c, - 0x3b, 0xf3, 0x19, 0xdc, 0x86, 0x75, 0x94, 0x01, 0x01, 0x53, 0x7c, 0xff, 0xc4, 0xa8, - 0x2d, 0x59, 0x9b, 0xbe, 0xa0, 0xd4, 0x7e, 0x7a, 0xbf, 0xa9, 0x92, 0xb4, 0x99, 0x8c, - 0xb2, 0x50, 0x09, 0x55, 0xe6, 0x1c, 0x0d, 0x46, 0xb3, 0x21, 0x17, 0xfb, 0xb9, 0x7f, - 0x7a, 0x76, 0x32, 0xd8, 0x72, 0x4b, 0x5d, 0xff, 0x67, 0xf7, 0x5e, 0x2d, 0x31, 0x74, - 0x06, 0xa0, 0xce, 0xc2, 0x89, 0xed, 0x08, 0x3b, 0x7c, 0x58, 0x19, 0x81, 0x8c, 0x50, - 0x47, 0x93, 0xde, 0x53, 0xb6, 0xbf, 0xdb, 0x51, 0x0e, 0x7c, 0xa7, 0x29, 0xba, 0x74, - 0x3d, 0x10, 0xb3, 0xe9, 0x95, 0x7e, 0xfa, 0x84, 0x20, 0x13, 0x39, 0x47, 0x7c, 0xf3, - 0x5f, 0xbb, 0x6a, 0x27, 0x9b, 0xad, 0x9e, 0x8f, 0x42, 0xb9, 0xb3, 0xfd, 0x6f, 0x3b, - 0xc7, 0x70, 0x67, 0x1d, 0x9c, 0x19, 0x12, 0x2f, 0xa3, 0x25, 0x6d, 0x09, 0x07, 0x36, - 0xb6, 0xd6, 0x4e, 0xb9, 0xcc, 0x03, 0x20, 0xf1, 0xea, 0xaa, 0x27, 0x1b, 0xa2, 0x86, - 0x1e, 0xc4, 0xb3, 0xf3, 0xf6, 0xc8, 0x40, 0xb6, 0x19, 0xff, 0x38, 0x8d, 0x81, 0xfc, - 0x40, 0x44, 0xa0, 0xd5, 0x31, 0xa4, 0xbb, 0x44, 0xc9, 0x3d, 0x09, 0x9d, 0xb0, 0x8a, - 0x9b, 0xc3, 0x46, 0xa0, 0xb6, 0x2f, 0x16, 0x8f, 0xfb, 0xdb, 0x73, 0x93, 0x66, 0xbb, - 0x53, 0x5d, 0xde, 0x66, 0xc2, 0xc1, 0x28, 0x7b, 0x3b, 0x27, 0x85, 0xae, 0xd6, 0x4c, - 0xc4, 0x0c, 0xbc, 0x7d, 0x33, 0xcb, 0xa4, 0xa9, 0xf3, 0xfc, 0xf5, 0xf8, 0x31, 0x36, - 0xa4, 0x39, 0x2d, 0x21, 0xa7, 0xf9, 0xeb, 0x1c, 0xe4, 0xb6, 0xe1, 0x7e, 0x6f, 0x4a, - 0x85, 0xa5, 0x79, 0x66, 0x9e, 0xfd, 0x0f, 0xb0, 0x98, 0x78, 0xe0, 0x88, 0xe3, 0x22, - 0xe9, 0x06, 0xe8, 0x0d, 0x27, 0xf8, 0xd0, 0xca, 0x7e, 0x79, 0x15, 0xab, 0x40, 0x96, - 0x59, 0xa6, 0xd8, 0x0f, 0xde, 0xd1, 0x0a, 0xff, 0x9f, 0xb7, 0x73, 0x74, 0x9d, 0x79, - 0x28, 0x57, 0xf6, 0x8c, 0x7e, 0x8c, 0xf5, 0x18, 0x26, 0x0a, 0x61, 0x08, 0x6d, 0xe3, - 0x2f, 0xff, 0x82, 0x39, 0xf4, 0x53, 0x61, 0x7a, 0x19, 0xf6, 0xfe, 0xc2, 0x20, 0x67, - 0x60, 0x65, 0xeb, 0xe2, 0x75, 0x7e, 0xfc, 0xac, 0xcb, 0x77, 0xfc, 0x61, 0xe5, 0x9b, - 0x97, 0x63, 0x7e, 0x92, 0x0d, 0xee, 0x5e, 0x7e, 0x7a, 0x12, 0xe9, 0xd6, 0xd2, 0x28, - 0xb2, 0x6b, 0x2f, 0xa8, 0x36, 0xf4, 0x72, 0x83, 0x69, 0xad, 0xcd, 0xfc, 0xd0, 0x04, - 0xdc, 0xf1, 0x9e, 0x27, 0xc0, 0xc0, 0x84, 0x44, 0xd2, 0x9a, 0x12, 0x2b, 0x23, 0x09, - 0xf7, 0x16, 0x3c, 0x99, 0x0e, 0xb9, 0x26, 0x1f, 0xd4, 0x15, 0xc0, 0x45, 0x4a, 0x56, - 0xaa, 0x3e, 0xaf, 0x9c, 0x1f, 0x9b, 0xff, 0xf6, 0x04, 0x77, 0x6a, 0x4d, 0x25, 0xe7, - 0xd3, 0xcd, 0xc5, 0xc5, 0xf1, 0x9c, 0xd2, 0xa8, 0x79, 0x4a, 0x4f, 0x57, 0x16, 0x7f, - 0xbc, 0x7e, 0xaa, 0x06, 0x16, 0x4d, 0x51, 0xc4, 0x53, 0x06, 0x14, 0xbc, 0xf5, 0x20, - 0xb2, 0x63, 0x82, 0x0a, 0xa1, 0x7b, 0x20, 0xb4, 0x8c, 0xbf, 0x59, 0xd8, 0xe3, 0x09, - 0x32, 0x2e, 0xbe, 0x56, 0x6f, 0xbe, 0x46, 0xe0, 0xaa, 0x29, 0x76, 0x6a, 0xdf, 0xdf, - 0x01, 0x7a, 0x71, 0x05, 0x10, 0x3c, 0x7f, 0xca, 0xb7, 0xb0, 0x76, 0x48, 0xc7, 0xc1, - 0x16, 0x04, 0x84, 0xf7, 0x7a, 0x6c, 0x70, 0xa5, 0x38, 0x1b, 0x82, 0x56, 0x40, 0xa1, - 0xbe, 0x48, 0xe4, 0x15, 0xa1, 0xe6, 0xa2, 0x7d, 0x78, 0x02, 0x2a, 0x8a, 0x2f, 0xf0, - 0x70, 0xab, 0xf1, 0x23, 0x94, 0xe3, 0xae, 0x5a, 0x8c, 0x23, 0xe3, 0x73, 0x3e, 0xa4, - 0x7a, 0x44, 0xcb, 0x2c, 0x96, 0x8b, 0xca, 0x24, 0x98, 0x37, 0xde, 0x1d, 0x39, 0xa5, - 0xa1, 0xdc, 0xae, 0x71, 0x0c, 0xe0, 0x43, 0x01, 0x69, 0xbd, 0x6e, 0x9f, 0x64, 0xab, - 0xf1, 0xe6, 0x4e, 0xc4, 0x9e, 0xd0, 0x80, 0x4e, 0xb6, 0x47, 0x74, 0x3a, 0xce, 0xa9, - 0x29, 0xed, 0x0f, 0x7c, 0x90, 0x15, 0xb0, 0xe8, 0x1e, 0x21, 0x29, 0xdb, 0x05, 0x0d, - 0x5e, 0x78, 0xe6, 0x82, 0xc8, 0x19, 0x93, 0xea, 0x87, 0x53, 0xc9, 0x91, 0xb0, 0x2e, - 0x61, 0x81, 0x0e, 0x74, 0x61, 0xed, 0x87, 0xb3, 0x80, 0xdb, 0x96, 0xab, 0xe3, 0xbe, - 0xad, 0x0f, 0x4b, 0x22, 0x12, 0xdb, 0x65, 0x8c, 0x11, 0xb8, 0x3f, 0x53, 0x11, 0x47, - 0x85, 0x27, 0x65, 0x98, 0xb0, 0x19, 0x7a, 0x7f, 0x1c, 0x25, 0x62, 0x7d, 0x79, 0x62, - 0x4d, 0xac, 0xee, 0x97, 0x7d, 0x9f, 0x4e, 0x1a, 0x35, 0xed, 0x2e, 0xaa, 0xd3, 0xcb, - 0x68, 0x25, 0x0a, 0xa9, 0xb3, 0xab, 0x1a, 0x83, 0x45, 0x72, 0x8e, 0x7d, 0x1a, 0x78, - 0xbe, 0x1f, 0xe4, 0x62, 0xce, 0x8e, 0xad, 0x52, 0x8f, 0x7c, 0x05, 0x0f, 0x1f, 0x6e, - 0x02, 0x2b, 0xa8, 0xb0, 0xce, 0xdf, 0x6e, 0x29, 0x7a, 0xb5, 0x64, 0xca, 0x1a, 0x1f, - 0xaa, 0xf4, 0xcf, 0xf1, 0xe4, 0x20, 0x32, 0xfb, 0xbb, 0x38, 0x9d, 0x3f, 0x66, 0xd5, - 0x75, 0x55, 0xef, 0x3f, 0x3e, 0x9e, 0x49, 0xc2, 0xac, 0x4e, 0x85, 0xbb, 0x75, 0x1d, - 0x62, 0x66, 0xc9, 0x03, 0x5b, 0x77, 0x9d, 0x76, 0x9d, 0x49, 0x5c, 0x91, 0x8a, 0x05, - 0x5e, 0x77, 0x67, 0xfb, 0xb4, 0xbb, 0xac, 0x3f, 0x96, 0x3d, 0xe9, 0x97, 0x46, 0xec, - 0x4d, 0xfb, 0x64, 0x2d, 0x9c, 0x2b, 0x86, 0x38, 0xe1, 0x6c, 0x16, 0xe7, 0x27, 0x70, - 0x79, 0x3b, 0x7e, 0xa1, 0xd0, 0x70, 0xc4, 0xe1, 0x1c, 0xbc, 0x20, 0xd8, 0xff, 0x3b, - 0xea, 0xd1, 0x0d, 0xb9, 0xc9, 0x4a, 0xe0, 0x48, 0x27, 0x21, 0xe1, 0xf2, 0x2c, 0xef, - 0xe0, 0xdf, 0x7c, 0x57, 0x7a, 0xa3, 0x8e, 0xc0, 0xe6, 0xc7, 0x8c, 0x9b, 0xa1, 0x64, - 0xe9, 0xdd, 0x00, 0x55, 0xdd, 0xe8, 0x3e, 0x8a, 0xd2, 0x40, 0xe6, 0xdf, 0xdb, 0xfb, - 0xe1, 0x76, 0xe4, 0x55, 0x1f, 0xdd, 0xe9, 0x2d, 0xb1, 0x67, 0x27, 0x42, 0x04, 0x41, - 0x70, 0x06, 0x58, 0xb5, 0x0e, 0xbb, 0x5a, 0x16, 0x13, 0x26, 0x7e, 0xac, 0x51, 0xc8, - 0x0b, 0x19, 0xec, 0xb7, 0x86, 0xab, 0x3b, 0xb9, 0x37, 0xf0, 0xd9, 0x8e, 0x08, 0xb9, - 0xc9, 0xcd, 0x4d, 0xf1, 0x53, 0x4e, 0xfe, 0xe3, 0x8a, 0x8f, 0x87, 0x8c, 0x9f, 0x3b, - 0xdc, 0x7e, 0xfb, 0x2d, 0x53, 0xff, 0x84, 0xfb, 0x83, 0xea, 0xe7, 0xc9, 0x9e, 0xff, - 0xa6, 0x3c, 0x96, 0x49, 0xa1, 0xf1, 0x70, 0xd2, 0x9a, 0xf0, 0x3a, 0x3b, 0x45, 0x58, - 0x9f, 0xae, 0x81, 0xeb, 0x0b, 0x5d, 0x8e, 0x0d, 0x38, 0x02, 0x1d, 0x3b, 0x5f, 0x07, - 0xe8, 0x8c, 0x99, 0x04, 0x37, 0x6d, 0x27, 0xf1, 0x3e, 0x44, 0x41, 0xd5, 0x38, 0x74, - 0x42, 0xc5, 0xea, 0x0a, 0xf5, 0xa2, 0x0a, 0x38, 0x32, 0xbc, 0x3b, 0x9c, 0x59, 0xb8, - 0x4b, 0xca, 0x39, 0xb5, 0x2c, 0xd6, 0xb1, 0xfa, 0x29, 0x32, 0xba, 0x9d, 0x66, 0xc4, - 0x12, 0xf5, 0xcd, 0x39, 0x35, 0x1e, 0x13, 0x33, 0xef, 0x85, 0xd0, 0xee, 0xe5, 0x45, - 0xa7, 0xe4, 0x06, 0xf6, 0xeb, 0x3b, 0xf8, 0x93, 0xf3, 0xed, 0xac, 0x94, 0x64, 0x33, - 0x92, 0xa2, 0x8b, 0x0e, 0x49, 0x0c, 0x51, 0xe4, 0xb7, 0x16, 0x3c, 0x1c, 0xf7, 0x57, - 0xd2, 0x24, 0x18, 0xdd, 0x63, 0x38, 0x1b, 0xa2, 0xf2, 0x98, 0x28, 0x83, 0x6f, 0xe9, - 0x78, 0xda, 0xb5, 0x20, 0x1b, 0x2d, 0xb0, 0x8c, 0x3b, 0x38, 0x9b, 0xa4, 0xb6, 0xac, - 0xf7, 0x78, 0xc2, 0xbf, 0x91, 0x02, 0xbe, 0x0c, 0x3e, 0x12, 0xd7, 0x7a, 0xea, 0x6d, - 0xf7, 0x53, 0x8e, 0x8c, 0xf3, 0x62, 0xba, 0xaa, 0xad, 0x1d, 0xc5, 0x60, 0x42, 0xc6, - 0xf2, 0x4c, 0xaf, 0x46, 0xbe, 0xd6, 0x6a, 0xbf, 0x4c, 0x40, 0x2a, 0x74, 0x92, 0x4e, - 0xcf, 0xd0, 0xa0, 0x8d, 0xed, 0xee, 0xa0, 0xef, 0xce, 0xcd, 0x35, 0x2c, 0x27, 0x5f, - 0x13, 0xed, 0x20, 0x76, 0x03, 0x82, 0x2b, 0x1e, 0xf9, 0x97, 0xb7, 0xed, 0x42, 0xf4, - 0xa5, 0x76, 0xb9, 0xe4, 0xc0, 0x07, 0x38, 0x56, 0x3f, 0x82, 0xa7, 0x62, 0x85, 0x46, - 0x7d, 0xa2, 0x95, 0xc2, 0x3b, 0xa1, 0xc5, 0x87, 0xeb, 0xef, 0xaf, 0x13, 0xcd, 0x4d, - 0x50, 0xf2, 0x3c, 0xa5, 0x74, 0x3c, 0x22, 0x5c, 0x38, 0x6d, 0x46, 0xd4, 0xac, 0x70, - 0x83, 0x79, 0xef, 0x99, 0x96, 0x74, 0x4b, 0x39, 0x12, 0x04, 0x4b, 0x35, 0x5f, 0x92, - 0x7a, 0x67, 0xaf, 0x1e, 0xf2, 0x6a, 0x71, 0x7f, 0xb5, 0xa8, 0x46, 0xac, 0x9d, 0xa1, - 0x5e, 0xa3, 0xf1, 0x8f, 0x8c, 0x36, 0x18, 0x3f, 0x87, 0x9b, 0xb9, 0xa3, 0xb2, 0x98, - 0xff, 0xf9, 0xa4, 0x89, 0x64, 0x6e, 0x77, 0x8e, 0x6d, 0x67, 0x01, 0xf9, 0xad, 0xac, - 0x7a, 0xe8, 0x82, 0x09, 0xa8, 0x43, 0xba, 0x8a, 0x55, 0xd1, 0x19, 0x2b, 0xbe, 0xef, - 0x31, 0xd0, 0x71, 0x45, 0x37, 0xf7, 0xa0, 0x35, 0xb0, 0x79, 0xc6, 0xad, 0xd4, 0xab, - 0x50, 0x61, 0x2d, 0x35, 0x89, 0x7a, 0x93, 0x3d, 0x49, 0xe8, 0xef, 0x08, 0x6c, 0xdf, - 0x96, 0xc8, 0x0d, 0x28, 0x56, 0xcc, 0xc7, 0xe4, 0x5f, 0xc4, 0xef, 0xd4, 0xbf, 0x1b, - 0x98, 0xab, 0x28, 0x89, 0x1b, 0x4a, 0xea, 0x7e, 0xf8, 0x4c, 0xf7, 0x36, 0x93, 0x5c, - 0x46, 0x6b, 0x24, 0x97, 0x4d, 0xf8, 0xf5, 0x35, 0x5b, 0x8b, 0xa3, 0x20, 0xac, 0x5f, - 0xbc, 0x47, 0x5a, 0xa2, 0xcf, 0x5a, 0xd3, 0x77, 0x80, 0xbd, 0x9f, 0x9d, 0x46, 0x42, - 0xcf, 0x6c, 0x2d, 0xc6, 0xb8, 0x2f, 0x91, 0x7d, 0x09, 0xc4, 0xf7, 0x28, 0x88, 0xf9, - 0x15, 0x53, 0x44, 0x7f, 0xc5, 0x70, 0x26, 0x6d, 0xaa, 0xfd, 0x4b, 0x96, 0xcf, 0xe2, - 0xa0, 0xb0, 0x67, 0x92, 0x46, 0x9a, 0x72, 0x7d, 0xbe, 0xd0, 0x55, 0x91, 0xea, 0x60, - 0x57, 0x32, 0x20, 0x5e, 0x26, 0x05, 0x97, 0x8a, 0x3a, 0x90, 0x2c, 0x3c, 0xd6, 0x5f, - 0x94, 0x83, 0x00, 0xf7, 0x37, 0x51, 0x88, 0x15, 0xf4, 0x63, 0xd3, 0xc6, 0x1a, 0x18, - 0x9b, 0xc3, 0xbc, 0x84, 0xb0, 0x22, 0xf6, 0x3d, 0x65, 0x4f, 0x52, 0x0e, 0x3a, 0x7a, - 0xd8, 0x8e, 0x5d, 0x8d, 0xa1, 0x50, 0x14, 0xbe, 0x4b, 0xb9, 0x67, 0x99, 0x27, 0xdc, - 0x7e, 0x0f, 0xba, 0xf0, 0x58, 0xd9, 0x3f, 0x37, 0xc7, 0x2b, 0x28, 0x6b, 0x02, 0xb7, - 0x5f, 0x3c, 0xdb, 0xfb, 0x85, 0x0e, 0xed, 0x90, 0xcb, 0x23, 0x39, 0x24, 0x32, 0xeb, - 0xc3, 0x6b, 0xd2, 0x47, 0x54, 0x46, 0x9c, 0x03, 0x73, 0x1a, 0x7e, 0xbb, 0xed, 0x28, - 0x57, 0x78, 0x49, 0x81, 0xa0, 0x71, 0x67, 0x05, 0xd9, 0xcb, 0x47, 0xd9, 0x87, 0xf8, - 0x3d, 0x34, 0x21, 0xb1, 0x07, 0xd1, 0x55, 0xdb, 0xb6, 0x61, 0xed, 0x08, 0xf2, 0xfc, - 0x2e, 0x6b, 0x4a, 0x5b, 0x09, 0x77, 0x64, 0x51, 0xd8, 0x73, 0xb2, 0xfc, 0x63, 0x68, - 0x1c, 0xe3, 0x08, 0xc8, 0x08, 0xf5, 0x38, 0x8c, 0xb1, 0xaa, 0x55, 0x89, 0xa1, 0x87, - 0x73, 0xdb, 0x39, 0x07, 0xa0, 0x6b, 0xef, 0x62, 0xd1, 0x29, 0x60, 0xaa, 0xe7, 0x2a, - 0x2b, 0x89, 0x7e, 0x26, 0xb5, 0x75, 0xfd, 0x04, 0x8a, 0x57, 0x22, 0x2c, 0x7c, 0x68, - 0x0d, 0x54, 0xdc, 0x73, 0x28, 0xd0, 0xf0, 0xf2, 0xd7, 0x0b, 0x43, 0x10, 0x8c, 0xb2, - 0x0c, 0x5c, 0x31, 0x16, 0x46, 0x31, 0xb0, 0xe5, 0xb3, 0xbd, 0x31, 0xb7, 0xdf, 0x8f, - 0x4c, 0x1f, 0xe1, 0x43, 0x4f, 0xa7, 0x47, 0x56, 0x70, 0x6f, 0x83, 0x10, 0x60, 0xa5, - 0xb7, 0x03, 0xdf, 0x9c, 0xd4, 0x2e, 0x24, 0x96, 0x0e, 0x50, 0x8a, 0x04, 0x36, 0x11, - 0x8d, 0x4a, 0x92, 0x07, 0xb6, 0xd8, 0x50, 0x59, 0x6d, 0xde, 0xbe, 0x30, 0xf9, 0x28, - 0xee, 0xea, 0xe7, 0x35, 0x98, 0xfb, 0x3d, 0x86, 0x9d, 0x2d, 0x18, 0x15, 0xa9, 0xe1, - 0x4d, 0x12, 0x79, 0xf7, 0xb4, 0xb6, 0x3f, 0x4b, 0xca, 0x0f, 0x56, 0x68, 0x9b, 0xf8, - 0x73, 0x3b, 0x03, 0x06, 0x49, 0x64, 0xa4, 0xb0, 0x20, 0xb0, 0x60, 0xdc, 0xf4, 0x54, - 0x71, 0xfa, 0x1d, 0x41, 0xe5, 0xee, 0x03, 0xf9, 0xbd, 0x90, 0x65, 0x2b, 0x53, 0x72, - 0x30, 0x3a, 0x3a, 0xb9, 0xbb, 0x2e, 0xe3, 0x79, 0xb9, 0xaf, 0xcd, 0x1f, 0x6a, 0x3c, - 0xb9, 0x00, 0x0b, 0xb1, 0x4e, - ], - script_code: Script(vec![0x53, 0x63, 0x63, 0xac, 0x63, 0x52]), - transparent_input: None, - hash_type: 1, - amount: 1152393991505765, - consensus_branch_id: consensus::BranchId::Sapling, - sighash: [ - 0x58, 0x11, 0x0e, 0x23, 0x19, 0xad, 0x85, 0x50, 0x4a, 0x69, 0x8f, 0x73, 0xe7, 0xac, - 0x31, 0xa7, 0x23, 0xa0, 0x29, 0xec, 0x07, 0xb7, 0x72, 0xfb, 0xb3, 0x2f, 0xba, 0x17, - 0xff, 0xe2, 0xcc, 0x8d, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0xb5, 0xcb, 0x96, 0x49, 0x97, - 0x9e, 0x3c, 0xcf, 0x75, 0xa8, 0xda, 0xd0, 0x54, 0x60, 0x26, 0x1f, 0xcd, 0xcb, 0x00, - 0x7a, 0xeb, 0xc1, 0x5e, 0x11, 0x67, 0x5c, 0x2d, 0xb4, 0xa6, 0xcb, 0x79, 0x38, 0xe1, - 0xfe, 0xb5, 0xcd, 0x04, 0x6a, 0x65, 0x00, 0x63, 0x44, 0x1e, 0x16, 0xc7, 0x07, 0xf0, - 0x97, 0x14, 0x47, 0x4c, 0x96, 0x16, 0x0a, 0xa6, 0x8e, 0xaa, 0x12, 0x31, 0x79, 0x06, - 0x9c, 0xd2, 0x20, 0x44, 0x06, 0x26, 0xcd, 0xfe, 0xed, 0x65, 0xf9, 0xfa, 0xbd, 0xaa, - 0x6d, 0xb1, 0x76, 0x0d, 0xa5, 0xd8, 0x06, 0x63, 0x00, 0x53, 0x6a, 0x65, 0x52, 0xfd, - 0xd0, 0xd2, 0xa9, 0x01, 0xfd, 0xc8, 0x17, 0x1c, 0x9b, 0x0e, 0x06, 0x00, 0x01, 0x65, - 0x26, 0x27, 0xba, 0x0e, 0x87, 0xb5, 0xcd, 0x0f, 0xc8, 0x7b, 0xa3, 0xa2, 0x3c, 0x78, - 0x02, 0x00, 0x00, 0x02, 0x59, 0xb1, 0xb2, 0x59, 0xc5, 0xa2, 0xd8, 0xb7, 0xa6, 0x03, - 0x9b, 0x0e, 0x12, 0xac, 0xd8, 0x89, 0xb5, 0x1b, 0x47, 0x2d, 0xd5, 0x33, 0xa4, 0x61, - 0xfb, 0x0c, 0x3f, 0x96, 0xa9, 0xc0, 0x0a, 0x0b, 0x38, 0x39, 0xfa, 0x89, 0x77, 0x6f, - 0xf0, 0x98, 0xae, 0xef, 0xc7, 0x40, 0x34, 0xff, 0x8c, 0x1f, 0x0d, 0xae, 0x63, 0x68, - 0x32, 0x4c, 0xe5, 0xda, 0x68, 0xd7, 0x71, 0x35, 0x08, 0xae, 0x6d, 0x01, 0x1a, 0xd0, - 0x5f, 0xea, 0xf2, 0x03, 0x56, 0x5c, 0x71, 0xa0, 0x48, 0x66, 0x21, 0xbd, 0xc4, 0x3c, - 0x2a, 0x8e, 0xbb, 0x82, 0x61, 0xd8, 0x47, 0x42, 0x4a, 0x4c, 0xfd, 0x0d, 0xad, 0xcf, - 0x95, 0x9d, 0xb4, 0x37, 0x2b, 0x58, 0xa0, 0xde, 0x19, 0x78, 0x9c, 0x91, 0xfc, 0x99, - 0x31, 0xec, 0xbc, 0xac, 0x64, 0x19, 0xca, 0x0e, 0x5d, 0x97, 0xa3, 0xb4, 0x1c, 0x76, - 0xc8, 0xa1, 0x96, 0xc7, 0xa3, 0xad, 0xf5, 0x5b, 0xdb, 0xe6, 0x0e, 0x85, 0x59, 0x26, - 0x4b, 0x6d, 0x8e, 0xf7, 0x5d, 0x26, 0xdc, 0x72, 0x0f, 0xe5, 0xec, 0x1f, 0x59, 0x66, - 0x2d, 0x95, 0xd0, 0x8e, 0x78, 0x9e, 0x3a, 0xd1, 0x82, 0x9e, 0x40, 0x11, 0x9a, 0xa7, - 0x89, 0x7d, 0x89, 0x40, 0x4d, 0xc4, 0x96, 0x60, 0x46, 0x68, 0xf5, 0x59, 0xca, 0x67, - 0x43, 0x7d, 0x2b, 0xfb, 0xb7, 0xf5, 0x1f, 0x36, 0xe0, 0xa5, 0xb7, 0x22, 0x8f, 0x05, - 0xb6, 0xec, 0x57, 0x89, 0xc1, 0x3f, 0xc2, 0x71, 0x95, 0x56, 0x15, 0x52, 0x63, 0x96, - 0x6e, 0x81, 0xf5, 0x21, 0x51, 0xe2, 0xf6, 0xe3, 0x68, 0x69, 0xd8, 0xa3, 0xc4, 0xc4, - 0x96, 0xa5, 0x13, 0x63, 0x2c, 0xaa, 0x8a, 0xbe, 0x1f, 0x27, 0x35, 0xeb, 0x60, 0xfc, - 0x12, 0x85, 0x82, 0x8e, 0xad, 0xdc, 0x54, 0x41, 0xa4, 0x02, 0xa3, 0xbf, 0x5b, 0xcd, - 0x22, 0x7c, 0xd8, 0x04, 0xe3, 0xc8, 0xca, 0x21, 0x24, 0x3c, 0xdf, 0xcd, 0x53, 0xd8, - 0x66, 0x05, 0xf3, 0xf8, 0xaf, 0x1a, 0x9c, 0xc5, 0x69, 0x33, 0x15, 0x53, 0x28, 0x28, - 0x01, 0x43, 0xfa, 0xdb, 0x3a, 0x1f, 0xc3, 0x3d, 0x76, 0x9f, 0x07, 0xff, 0xc0, 0x1e, - 0x35, 0x79, 0xe1, 0x18, 0x1f, 0x19, 0x15, 0xdb, 0x89, 0xd8, 0x2e, 0x50, 0xbd, 0x74, - 0x24, 0x08, 0x7c, 0x79, 0x7d, 0x9b, 0x7b, 0x3b, 0x7d, 0x2a, 0x53, 0xb8, 0xff, 0xf9, - 0xf2, 0xd9, 0x28, 0xab, 0x99, 0x6d, 0xce, 0x5e, 0xd2, 0x71, 0x58, 0x98, 0xe4, 0x85, - 0x8e, 0xec, 0x60, 0x78, 0xa9, 0x48, 0x8d, 0x2d, 0xa6, 0xd1, 0x73, 0x05, 0xd0, 0xa3, - 0x47, 0x18, 0x62, 0xa2, 0x22, 0x38, 0xb9, 0xbe, 0xc2, 0x3e, 0xf2, 0xe2, 0x04, 0x1d, - 0x50, 0x08, 0x73, 0x3e, 0x9e, 0xa5, 0x66, 0x2c, 0x9f, 0xea, 0x0e, 0x4a, 0xfd, 0xf3, - 0x27, 0x0c, 0x11, 0x32, 0x3b, 0xa4, 0x8b, 0x35, 0x50, 0x85, 0x74, 0x40, 0x97, 0xf3, - 0xf6, 0xc5, 0x2e, 0xe4, 0x04, 0x31, 0x73, 0x9c, 0x5c, 0xa8, 0xdb, 0x2b, 0xda, 0x13, - 0xda, 0x9b, 0x33, 0x0b, 0x62, 0x00, 0x0b, 0x79, 0xfd, 0x35, 0x44, 0xb1, 0x31, 0x83, - 0x15, 0x9d, 0x17, 0x4f, 0xfe, 0xd2, 0x54, 0x85, 0x40, 0xa5, 0x2e, 0xe4, 0xb6, 0x2d, - 0x35, 0xaa, 0x5a, 0x58, 0x63, 0xf2, 0xba, 0xa4, 0x47, 0x5f, 0x3e, 0xb6, 0xc7, 0x35, - 0x9d, 0xc8, 0x39, 0xdb, 0xc8, 0x68, 0x90, 0xd1, 0x99, 0xd8, 0xea, 0x6c, 0x9d, 0x97, - 0xf1, 0x9e, 0x79, 0x2c, 0x7b, 0xcb, 0x66, 0x25, 0xff, 0x32, 0xb7, 0x31, 0x57, 0x5f, - 0x62, 0xd9, 0x44, 0xc8, 0x06, 0xb3, 0xf9, 0x3c, 0x04, 0xb7, 0x3a, 0x98, 0xb2, 0x73, - 0x43, 0xeb, 0x25, 0xa0, 0x6c, 0x87, 0x53, 0x60, 0xde, 0x1a, 0x14, 0x38, 0x84, 0x0a, - 0xd0, 0x66, 0x1d, 0xeb, 0xdc, 0x9b, 0x82, 0x8a, 0xd0, 0xcb, 0xc0, 0x01, 0x1b, 0x32, - 0x35, 0xb2, 0xc7, 0x53, 0x77, 0x78, 0xf4, 0x58, 0x82, 0x1b, 0x83, 0xaa, 0x4c, 0xb3, - 0xe5, 0x4e, 0xd0, 0x61, 0x3e, 0x32, 0xe6, 0x3e, 0xf9, 0x85, 0xf9, 0x35, 0xbd, 0x7f, - 0xf8, 0xc7, 0x70, 0x5c, 0x89, 0xc0, 0xbb, 0xcc, 0xda, 0x9e, 0x66, 0x5e, 0x3b, 0x06, - 0xba, 0x87, 0x9f, 0xdd, 0xf3, 0x5e, 0x0b, 0x2f, 0x60, 0xc2, 0xa7, 0x0c, 0xb8, 0xeb, - 0x9d, 0xe2, 0xf5, 0xd7, 0x38, 0xc0, 0x5e, 0x34, 0xe5, 0x0f, 0x1f, 0x26, 0x19, 0x25, - 0x8b, 0x89, 0xe5, 0x73, 0xda, 0x55, 0x75, 0x46, 0x3d, 0x2e, 0x3b, 0xce, 0x39, 0xf7, - 0x0e, 0xb4, 0x55, 0x26, 0xcd, 0x99, 0xfa, 0xd9, 0x0f, 0x97, 0x92, 0xd0, 0xcd, 0x59, - 0x3b, 0xa8, 0x6a, 0xa1, 0xae, 0xa5, 0x03, 0xdd, 0xca, 0x5e, 0x3e, 0x57, 0x37, 0xe6, - 0xfc, 0x7b, 0xab, 0x27, 0x85, 0x12, 0x69, 0x20, 0xc4, 0x47, 0xd5, 0xe5, 0x6a, 0x75, - 0xdb, 0xe8, 0x9d, 0x68, 0x8b, 0xc0, 0xda, 0xa7, 0x9a, 0xa6, 0x2d, 0xe9, 0xea, 0x29, - 0x55, 0xf7, 0x1e, 0x1a, 0x61, 0x68, 0x2a, 0x61, 0x78, 0xf8, 0x0b, 0xca, 0xda, 0x3b, - 0x97, 0xae, 0xec, 0x77, 0xd9, 0xc8, 0x56, 0x3b, 0x06, 0x9e, 0xa0, 0x13, 0x2f, 0x72, - 0x3f, 0xbe, 0x75, 0x60, 0x2d, 0xd6, 0x29, 0xac, 0x48, 0x09, 0x93, 0xd3, 0x71, 0x4f, - 0xf0, 0x2c, 0x97, 0x0e, 0xbd, 0x83, 0xe6, 0xd6, 0xcb, 0xbe, 0x39, 0x08, 0x6b, 0x03, - 0x54, 0x20, 0xe0, 0xc2, 0x75, 0x62, 0x86, 0x58, 0xa3, 0xba, 0x92, 0x30, 0x5c, 0xc0, - 0x76, 0x98, 0xf1, 0x2e, 0xe1, 0xe4, 0x17, 0x13, 0x70, 0xac, 0x39, 0xdf, 0x0e, 0x46, - 0x6d, 0xc8, 0xec, 0xc3, 0x9d, 0xa5, 0xee, 0x47, 0xb6, 0x82, 0x9d, 0xbb, 0xa9, 0x97, - 0x0f, 0x03, 0x58, 0xed, 0x68, 0x26, 0x49, 0x60, 0x5c, 0x7b, 0xfe, 0xe6, 0x93, 0x1a, - 0x29, 0x5b, 0x14, 0xa3, 0x40, 0x76, 0x00, 0x07, 0x4e, 0xdc, 0x79, 0xfa, 0x61, 0xe6, - 0x80, 0x6f, 0x11, 0x08, 0xd3, 0x34, 0xb4, 0xa5, 0x90, 0xf7, 0xa0, 0x26, 0xb0, 0xeb, - 0x02, 0x80, 0x4d, 0x39, 0x17, 0x46, 0x6e, 0x99, 0x91, 0x20, 0x64, 0x1c, 0xe0, 0x7e, - 0xbc, 0xdc, 0x99, 0x42, 0x60, 0x82, 0xe0, 0x77, 0x1f, 0x15, 0x9c, 0x82, 0x6a, 0x9b, - 0xe6, 0xce, 0xd7, 0x2d, 0x0e, 0x9c, 0xfa, 0x5b, 0x4b, 0x8a, 0x86, 0x40, 0xca, 0x34, - 0x88, 0xa1, 0xeb, 0x2b, 0x6e, 0x37, 0x4e, 0x8c, 0x2e, 0x00, 0x3c, 0xdf, 0xa2, 0x32, - 0x10, 0x37, 0x48, 0xb5, 0xc9, 0xdc, 0x11, 0xbb, 0x30, 0xf6, 0x46, 0xb9, 0x73, 0xd7, - 0x83, 0xf5, 0x99, 0x14, 0x17, 0x4e, 0x48, 0xbd, 0x6a, 0x84, 0xfa, 0xd8, 0x9d, 0xbc, - 0xa5, 0xc7, 0x6d, 0x0a, 0xb4, 0x14, 0x5a, 0xbd, 0x08, 0xe4, 0xd0, 0xf2, 0xc7, 0x60, - 0x25, 0xfc, 0x85, 0xfc, 0x11, 0x6c, 0xca, 0x8d, 0x30, 0x2c, 0x8a, 0x3b, 0xeb, 0x26, - 0x60, 0x3a, 0x1a, 0xf1, 0xb5, 0x93, 0x91, 0xea, 0xf4, 0x71, 0x75, 0x9a, 0xdf, 0x19, - 0x4c, 0x40, 0xc2, 0x09, 0x29, 0x8c, 0xc0, 0x51, 0xfc, 0x79, 0x03, 0xfe, 0x40, 0x90, - 0x2c, 0x35, 0x6f, 0x28, 0x27, 0x9f, 0x27, 0x94, 0xbb, 0xb9, 0xe0, 0x0b, 0x1e, 0x22, - 0x1b, 0x0a, 0x26, 0x41, 0x06, 0xea, 0x50, 0x4f, 0xb8, 0x90, 0x6a, 0x20, 0x84, 0x5a, - 0x05, 0x9a, 0x60, 0x3b, 0x4f, 0x00, 0xe7, 0x83, 0x6d, 0x40, 0x67, 0xa6, 0x04, 0x19, - 0x5f, 0x24, 0x6a, 0x0f, 0x3b, 0x31, 0x82, 0x3f, 0xdf, 0x69, 0x57, 0x8c, 0x47, 0xdb, - 0x5b, 0x3d, 0xda, 0x86, 0xaa, 0xb1, 0xec, 0x9f, 0x58, 0xd9, 0x62, 0x26, 0xc6, 0xb9, - 0x1d, 0xc0, 0xf0, 0x3f, 0xe8, 0xd7, 0xdf, 0x23, 0xcf, 0x53, 0xca, 0x8e, 0xa2, 0xa9, - 0x09, 0x4f, 0xc0, 0x28, 0x65, 0x26, 0x7c, 0x88, 0xfa, 0x8c, 0x01, 0x0e, 0xb5, 0x66, - 0x13, 0x06, 0x6e, 0x50, 0xf1, 0x55, 0x4a, 0xa4, 0x10, 0x8e, 0x25, 0xa9, 0xe9, 0x67, - 0xd3, 0x4a, 0x9c, 0xf1, 0x02, 0x8c, 0x17, 0x05, 0xfa, 0x37, 0x67, 0xf4, 0x6d, 0x4b, - 0xab, 0x70, 0x28, 0xb0, 0x9b, 0x20, 0x38, 0xfc, 0x1b, 0x72, 0x7f, 0x61, 0x9e, 0x61, - 0xc4, 0xfc, 0x16, 0xbf, 0xfe, 0x65, 0x7e, 0x99, 0x12, 0x6a, 0xc5, 0x18, 0x4f, 0xc8, - 0x7f, 0x5e, 0x53, 0x01, 0x88, 0x64, 0x23, 0xb3, 0x56, 0x87, 0x59, 0x09, 0xec, 0x92, - 0xb3, 0x2d, 0x33, 0x08, 0x42, 0x53, 0xa1, 0xb9, 0x7c, 0x5d, 0x2e, 0xd6, 0x6c, 0x7e, - 0x22, 0xd1, 0x85, 0x58, 0xfe, 0x82, 0xb5, 0xec, 0x88, 0xc6, 0x07, 0x05, 0x82, 0xfa, - 0xcf, 0x75, 0x6d, 0x70, 0x32, 0x38, 0xd9, 0xaf, 0x94, 0x19, 0x96, 0x6b, 0xe4, 0x62, - 0xdf, 0xbd, 0x31, 0x5c, 0x5b, 0xfa, 0xf0, 0x44, 0xaa, 0x69, 0x5a, 0x05, 0xe6, 0x9d, - 0x3d, 0x41, 0xe7, 0x73, 0x78, 0x75, 0x1d, 0x4e, 0x02, 0xc2, 0x66, 0xdf, 0xb5, 0xcb, - 0x6a, 0x7c, 0x40, 0x08, 0xf9, 0x44, 0x88, 0x83, 0x11, 0xe6, 0xde, 0x37, 0xdc, 0x7b, - 0xdf, 0x65, 0xd7, 0x0c, 0xab, 0x3e, 0x07, 0x8a, 0xb4, 0x4e, 0x23, 0x2b, 0x41, 0x1c, - 0xaf, 0xb2, 0x88, 0x4e, 0x26, 0x45, 0x95, 0xbe, 0xed, 0xf9, 0xd4, 0x9a, 0x79, 0x36, - 0xbb, 0x28, 0x7f, 0xe2, 0x8e, 0x1c, 0x29, 0x63, 0x5e, 0xae, 0xca, 0x74, 0x7d, 0x06, - 0x87, 0xcf, 0x46, 0x59, 0x02, 0xd2, 0x5f, 0x5e, 0x51, 0x58, 0x48, 0x1d, 0xaa, 0xcd, - 0xd3, 0x00, 0xb4, 0x77, 0x40, 0xbc, 0x0c, 0x62, 0x77, 0xb4, 0x47, 0xcc, 0x26, 0x64, - 0x04, 0x42, 0x43, 0xdd, 0x48, 0x11, 0x40, 0x4e, 0xcb, 0xd7, 0xc7, 0xa6, 0x3c, 0x9f, - 0xb7, 0xd9, 0x37, 0xbc, 0xd8, 0x12, 0xc2, 0x34, 0x59, 0x23, 0xb5, 0x90, 0x26, 0x83, - 0xbd, 0x2e, 0xd5, 0x4c, 0x01, 0xae, 0x04, 0x19, 0xa7, 0xf5, 0x4e, 0x8a, 0x3a, 0x59, - 0xc6, 0xa6, 0xda, 0xcf, 0x89, 0xc7, 0x37, 0x0e, 0x79, 0xb5, 0x60, 0x13, 0x6a, 0x2b, - 0x00, 0xdd, 0xb6, 0x07, 0x4d, 0x74, 0xff, 0xc5, 0xc5, 0xdf, 0xd0, 0x6b, 0x6c, 0x51, - 0x9a, 0xbe, 0xc3, 0x59, 0x6a, 0x47, 0x61, 0x13, 0xbe, 0x41, 0x38, 0xee, 0xad, 0x5f, - 0xfd, 0xe8, 0x6b, 0x1e, 0x32, 0x40, 0x1f, 0xa3, 0x84, 0x62, 0x32, 0xd0, 0xb3, 0xc9, - 0xbd, 0x56, 0x88, 0xb6, 0x4a, 0x33, 0x09, 0x38, 0x16, 0x2a, 0x8b, 0x89, 0x29, 0xd7, - 0x0c, 0x1b, 0x67, 0x53, 0x62, 0xf4, 0xc2, 0xa9, 0xbb, 0x6b, 0x7f, 0x91, 0xeb, 0xd4, - 0x7d, 0x26, 0x3c, 0xf0, 0xa4, 0x05, 0xa2, 0x8b, 0xa7, 0x41, 0x56, 0x44, 0xf9, 0x3b, - 0x6c, 0xdf, 0xa3, 0xec, 0xeb, 0xb7, 0xb8, 0xd4, 0xee, 0x8b, 0x94, 0xb2, 0x7b, 0x61, - 0xe4, 0x03, 0x5e, 0xd6, 0xa4, 0x77, 0x46, 0x7f, 0x4a, 0x32, 0x0b, 0x8a, 0x4e, 0xba, - 0x0a, 0xb5, 0x6c, 0x26, 0x3e, 0x4b, 0xfb, 0xe2, 0x6a, 0x41, 0x8e, 0xd1, 0xcd, 0xe6, - 0x18, 0x4b, 0x89, 0x50, 0xfe, 0x7a, 0xac, 0x7f, 0x20, 0xa4, 0x7b, 0xa1, 0xbf, 0xf9, - 0x80, 0x4f, 0x53, 0xf6, 0x93, 0x23, 0xdb, 0x84, 0x75, 0x20, 0xa6, 0x58, 0x47, 0xb3, - 0x03, 0x4c, 0x4e, 0x08, 0x1b, 0xb4, 0xb8, 0x69, 0x26, 0x3b, 0x5f, 0x9b, 0x3a, 0x7a, - 0x83, 0x3b, 0x6e, 0x4c, 0xa7, 0x90, 0xcc, 0xf9, 0xfd, 0xae, 0x80, 0x79, 0xe5, 0x56, - 0x09, 0x27, 0x2c, 0x63, 0xb5, 0x49, 0xb0, 0xc8, 0x5f, 0x11, 0x0c, 0xc9, 0xc9, 0x58, - 0x68, 0x01, 0x14, 0xb3, 0x11, 0x74, 0x80, 0xaf, 0x57, 0xcb, 0x15, 0x9e, 0xdf, 0xbe, - 0x5c, 0xb9, 0xc6, 0x2b, 0xce, 0x2c, 0xf2, 0xab, 0x29, 0xb6, 0x67, 0x11, 0xac, 0x7a, - 0xa5, 0x3a, 0x74, 0x9f, 0xfa, 0x83, 0x90, 0x7e, 0xcb, 0x69, 0x12, 0xaa, 0x56, 0x96, - 0x38, 0xde, 0xa1, 0x9e, 0x54, 0x41, 0x61, 0x1e, 0xfc, 0xa3, 0x20, 0x99, 0x65, 0x3e, - 0x8a, 0x5c, 0xa1, 0xfb, 0xbd, 0xba, 0xb1, 0xd6, 0x44, 0x71, 0xec, 0x32, 0x0e, 0xc3, - 0x8e, 0xa4, 0x88, 0x40, 0x0c, 0x9b, 0x1f, 0x4e, 0x8c, 0xb5, 0x48, 0x0c, 0x0e, 0x92, - 0x42, 0xb0, 0x86, 0xa8, 0x0e, 0xee, 0xd4, 0x90, 0xae, 0x32, 0x00, 0x0c, 0x80, 0x09, - 0xec, 0xb7, 0x1f, 0xfa, 0x39, 0xf4, 0xf3, 0xb5, 0x74, 0x9c, 0xfd, 0x1b, 0xef, 0xe0, - 0xd9, 0x66, 0x7a, 0xb3, 0x02, 0x20, 0xc2, 0xdc, 0x04, 0x39, 0x36, 0x98, 0xb2, 0xcf, - 0xa2, 0x04, 0x92, 0xf2, 0x50, 0xce, 0x14, 0x32, 0x35, 0x81, 0x58, 0x70, 0x3d, 0xf7, - 0xb1, 0x39, 0xd7, 0x45, 0xce, 0x1f, 0xc3, 0x40, 0x78, 0x77, 0x01, 0xfb, 0x51, 0xdd, - 0x5e, 0x48, 0xb8, 0x95, 0x09, 0x41, 0x7d, 0x88, 0x89, 0x00, 0x80, 0x63, 0xf9, 0xba, - 0x01, 0x5a, 0x07, 0xd8, 0xd3, 0x9b, 0xbd, 0x00, 0x76, 0x2f, 0x59, 0x5a, 0xfa, 0xd8, - 0xd8, 0x59, 0xea, 0xab, 0xf0, 0xd8, 0x2d, 0x46, 0x33, 0xcf, 0x82, 0x98, 0xb0, 0x9b, - 0xea, 0x3f, 0x22, 0x28, 0x55, 0xa9, 0x2a, 0x08, 0x43, 0xf5, 0x2f, 0xa5, 0x8d, 0xb3, - 0xa1, 0x75, 0xc3, 0x0d, 0x2a, 0xbe, 0x64, 0x82, 0x64, 0x90, 0xcb, 0xe6, 0xca, 0x14, - 0x88, 0xfe, 0x3a, 0x01, 0x5a, 0x94, 0x6d, 0xc9, 0xc4, 0x5a, 0xc3, 0x09, 0x25, 0x72, - 0x7a, 0x13, 0xe0, 0x89, 0x78, 0xf7, 0x24, 0x03, 0x47, 0x20, 0x8a, 0x4d, 0x25, 0x38, - 0xc2, 0xd5, 0x61, 0x24, 0x37, 0x8c, 0x22, 0xc0, 0x4e, 0x23, 0xdc, 0x28, 0xb1, 0x50, - 0x19, 0xbe, 0x77, 0x6d, 0x70, 0xbf, 0xc1, 0xd2, 0x64, 0x5b, 0x5e, 0x80, 0xd1, 0xfd, - 0x84, 0x19, 0xdf, 0x72, 0x90, 0x43, 0x80, 0xe2, 0xe1, 0xfc, 0x4d, 0xd1, 0xdf, 0x1b, - 0xa3, 0xdf, 0xe4, 0x80, 0xcc, 0x84, 0x6d, 0x51, 0x51, 0x4a, 0x06, 0x5e, 0xd7, 0x62, - 0x78, 0x7a, 0xfd, 0x6e, 0xb9, 0x0b, 0xdf, 0x8f, 0xbb, 0xad, 0x5e, 0xb3, 0xd2, 0x3f, - 0xdc, 0x8c, 0x54, 0xcc, 0xa1, 0x0f, 0xa1, 0xfe, 0x54, 0x64, 0x82, 0xf5, 0xe1, 0x42, - 0x4b, 0xfd, 0xa8, 0x7a, 0xa7, 0xfb, 0x78, 0x6e, 0x26, 0x0f, 0x26, 0x14, 0xbe, 0x08, - 0x11, 0xee, 0x16, 0xb8, 0xd2, 0x9d, 0xf9, 0xa0, 0xf3, 0x30, 0xe9, 0x70, 0x9f, 0x63, - 0xc9, 0x50, 0xfb, 0xd9, 0x03, 0xff, 0x7d, 0x5b, 0x0c, 0xa2, 0x9f, 0xd6, 0x3b, 0x0f, - 0x97, 0x51, 0x77, 0x69, 0x02, 0x5c, 0xc3, 0x6a, 0x52, 0xe0, 0x00, 0x15, 0x93, 0x4a, - 0x3c, 0xa2, 0x58, 0xb8, 0xba, 0xb9, 0x00, 0x16, 0xa4, 0x01, 0xd5, 0xd8, 0xd7, 0xc3, - 0xb9, 0x44, 0x92, 0x5b, 0x35, 0xa9, 0x34, 0x9a, 0x1a, 0xc7, 0xd9, 0x85, 0x21, 0x61, - 0x0c, 0x2f, 0xad, 0x8b, 0x5c, 0x8b, 0x31, 0x9c, 0xd6, 0xe0, 0x5f, 0x9b, 0xbe, 0xd3, - 0x53, 0xf1, 0xd0, 0xc8, 0x65, 0xa9, 0x4a, 0xa4, 0x56, 0xdc, 0xd1, 0x8a, 0x39, 0xe2, - 0xf5, 0x85, 0xd9, 0xbe, 0xa8, - ], - script_code: Script(vec![0x63, 0x00, 0x6a, 0x53, 0x63, 0x6a, 0xac, 0x00]), - transparent_input: None, - hash_type: 1, - amount: 1788797765223798, - consensus_branch_id: consensus::BranchId::Sapling, - sighash: [ - 0xcb, 0xfa, 0x22, 0x69, 0x9b, 0x04, 0xbe, 0xb7, 0x67, 0x07, 0xb5, 0x1d, 0x62, 0x5e, - 0x94, 0xd2, 0x6c, 0x0d, 0xf8, 0xad, 0xa7, 0xcf, 0x68, 0xfc, 0xde, 0xd9, 0x60, 0x65, - 0x4b, 0x20, 0xf3, 0x60, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x00, 0x02, 0x12, 0x9a, 0x03, 0xd5, - 0x7d, 0x32, 0x07, 0x00, 0x07, 0x52, 0x51, 0xac, 0x51, 0x65, 0xac, 0x00, 0x91, 0xdb, - 0xbd, 0x6f, 0xf3, 0x8f, 0x01, 0x00, 0x05, 0x53, 0x6a, 0x63, 0x63, 0x53, 0x6f, 0x34, - 0xc4, 0x99, 0x32, 0x68, 0xc7, 0x09, 0xef, 0xf1, 0x20, 0x1b, 0x50, 0x92, 0x05, 0x00, - 0x02, 0x3b, 0x5c, 0x8b, 0x5b, 0x80, 0xe7, 0x7b, 0x87, 0xf1, 0xeb, 0x73, 0xaf, 0x77, - 0x60, 0xed, 0xae, 0x0e, 0x19, 0x3e, 0x38, 0x96, 0xb1, 0x5c, 0x55, 0x8f, 0x00, 0x4e, - 0x7c, 0x7d, 0x93, 0x24, 0xd3, 0x85, 0xb4, 0x50, 0xcd, 0x4b, 0x98, 0x2a, 0xba, 0x8d, - 0x2e, 0x91, 0xf4, 0x1f, 0x22, 0xee, 0xe7, 0xf3, 0x6d, 0x79, 0xcc, 0xa9, 0xc0, 0xe0, - 0x1b, 0x26, 0xc4, 0x65, 0x11, 0x18, 0xea, 0x77, 0x15, 0x14, 0xc7, 0x7e, 0xd6, 0x0c, - 0xd5, 0x24, 0x51, 0x94, 0x2d, 0xc8, 0x5b, 0x3f, 0xba, 0x44, 0x8b, 0x2d, 0x63, 0x10, - 0xf2, 0x77, 0x79, 0x42, 0x83, 0x2e, 0x21, 0xcf, 0x3d, 0x44, 0x87, 0x4f, 0x8d, 0xca, - 0x98, 0x2b, 0x68, 0x7c, 0x9e, 0xd7, 0xe0, 0xb2, 0x32, 0x77, 0x07, 0x3c, 0x19, 0x30, - 0xa4, 0x73, 0xd1, 0x66, 0x8e, 0xf2, 0xe9, 0xae, 0x96, 0x63, 0xcf, 0xf0, 0x58, 0x16, - 0x62, 0x6c, 0xd3, 0xc5, 0xbf, 0x77, 0x16, 0x53, 0xd7, 0x78, 0x51, 0x81, 0x35, 0x5c, - 0x05, 0xae, 0xd2, 0x4a, 0x99, 0xc4, 0xb6, 0x74, 0xd2, 0x4a, 0x0f, 0x08, 0xf4, 0xb0, - 0xcf, 0xbe, 0x90, 0xf2, 0xfd, 0xba, 0xb4, 0x24, 0x82, 0xe9, 0x8f, 0x13, 0xff, 0xfc, - 0xd1, 0xad, 0x33, 0xf4, 0xf4, 0xc0, 0x4d, 0xeb, 0xc8, 0x9f, 0x40, 0xb5, 0xdb, 0xf6, - 0x45, 0x46, 0xc5, 0x20, 0xdc, 0xa5, 0xd0, 0xec, 0xf3, 0xf6, 0x5d, 0x3a, 0x77, 0xd0, - 0x12, 0x9f, 0x60, 0x03, 0x71, 0x10, 0x8a, 0xac, 0x30, 0xa9, 0xec, 0xa8, 0xbe, 0xe5, - 0x52, 0x4f, 0xab, 0x67, 0x1f, 0xc0, 0x86, 0x58, 0x76, 0x2c, 0x87, 0x38, 0xab, 0xc9, - 0xfa, 0x76, 0x93, 0xe3, 0x9d, 0x39, 0xd7, 0x03, 0xd5, 0xcd, 0x94, 0x2b, 0x5a, 0x55, - 0xfe, 0xda, 0xfe, 0xcc, 0xae, 0xf7, 0x02, 0x17, 0x69, 0xe9, 0x2c, 0xc9, 0xd3, 0xac, - 0x7b, 0x4c, 0x23, 0xb3, 0x3f, 0xc2, 0x23, 0x21, 0x85, 0x4b, 0xa3, 0x3f, 0x49, 0xee, - 0xba, 0xdd, 0xca, 0x29, 0xb3, 0x56, 0x40, 0xe4, 0xf0, 0xc2, 0xfd, 0x8c, 0x12, 0xb9, - 0x84, 0x52, 0x97, 0x60, 0xe0, 0x65, 0xfe, 0xcb, 0xa1, 0x21, 0x86, 0xd2, 0x0a, 0xee, - 0xc3, 0xda, 0x58, 0xfc, 0x35, 0x9b, 0xa8, 0x25, 0xe5, 0xb8, 0xe2, 0xe1, 0x8f, 0x12, - 0xcf, 0x29, 0x49, 0xc3, 0x12, 0xf6, 0x3c, 0x4d, 0xd7, 0xa7, 0x9b, 0x0e, 0x66, 0xb9, - 0xc8, 0xb6, 0x6f, 0xe8, 0x9a, 0xd7, 0xed, 0xc6, 0x2a, 0xc4, 0xd2, 0x07, 0xe2, 0x77, - 0xb9, 0x33, 0xb0, 0xc2, 0x06, 0xdd, 0x7c, 0x22, 0xd2, 0xdb, 0x26, 0x33, 0xfc, 0x01, - 0xa8, 0x3c, 0x24, 0xfc, 0xad, 0x40, 0x9c, 0xee, 0xd5, 0x36, 0xa6, 0xd3, 0xe8, 0xe0, - 0x8d, 0x42, 0xb5, 0x13, 0x48, 0x97, 0xb4, 0x36, 0xbf, 0xf3, 0xa1, 0xbc, 0xef, 0xc5, - 0x3a, 0xec, 0x30, 0xed, 0x89, 0x11, 0x0f, 0x89, 0x60, 0x88, 0x8a, 0x1c, 0xf2, 0x41, - 0x5c, 0xc6, 0x93, 0xa8, 0x52, 0x97, 0xd6, 0xb7, 0x89, 0x14, 0x1e, 0x04, 0x1a, 0x3c, - 0x14, 0xa5, 0xf9, 0xc6, 0x46, 0x33, 0xbe, 0x06, 0x56, 0x45, 0xe9, 0xca, 0x36, 0x37, - 0xf3, 0x73, 0x83, 0x04, 0xec, 0x3b, 0x16, 0x51, 0x31, 0x46, 0x83, 0xa0, 0x27, 0x5e, - 0x73, 0x36, 0x79, 0x70, 0x01, 0x06, 0x78, 0x23, 0x17, 0x79, 0x3e, 0x86, 0x6c, 0xed, - 0x59, 0x89, 0x21, 0x3f, 0x3b, 0xac, 0xfc, 0xfd, 0x20, 0x02, 0xea, 0x86, 0x6f, 0x3f, - 0x17, 0x07, 0x35, 0x12, 0x64, 0xb6, 0x67, 0x88, 0xf4, 0xeb, 0x7f, 0x68, 0xc5, 0xa5, - 0x36, 0xfa, 0x9c, 0x13, 0x0d, 0x20, 0x26, 0xea, 0x80, 0x97, 0x94, 0xd3, 0xb7, 0x4d, - 0x78, 0x01, 0x7e, 0xe0, 0xfb, 0xca, 0x83, 0xcc, 0x7e, 0x5c, 0xbd, 0x52, 0x7a, 0xcd, - 0xe7, 0x46, 0x53, 0x73, 0x51, 0x2c, 0x07, 0x64, 0x6a, 0x62, 0xc6, 0x0f, 0x5c, 0x16, - 0xc2, 0xef, 0x9f, 0x41, 0x8d, 0x8c, 0x7d, 0x18, 0x8f, 0x7b, 0x13, 0xdd, 0x45, 0x38, - 0xa5, 0x5d, 0x18, 0x6a, 0xd6, 0x36, 0x2a, 0x58, 0x9a, 0x9f, 0x52, 0xb2, 0x5e, 0x61, - 0x6f, 0xb2, 0xa3, 0x57, 0xac, 0xca, 0xde, 0x63, 0x57, 0xfa, 0x5a, 0x42, 0xa7, 0x98, - 0xe4, 0x17, 0x13, 0x11, 0xad, 0xe9, 0xcc, 0xfd, 0x15, 0xf2, 0x7c, 0x8c, 0x19, 0x72, - 0x17, 0x9d, 0x26, 0x1f, 0xb9, 0xb0, 0x9b, 0xc7, 0xa0, 0x36, 0xc1, 0x05, 0x55, 0x9b, - 0x04, 0x38, 0x9d, 0xfd, 0x8a, 0x7b, 0xe2, 0xa3, 0xae, 0x2b, 0xba, 0x2a, 0xfb, 0xd1, - 0xe9, 0xbf, 0x90, 0x05, 0xc8, 0xb3, 0x66, 0x35, 0x4f, 0x90, 0x9b, 0xe7, 0x1e, 0x52, - 0xc0, 0x90, 0x80, 0xfb, 0xa7, 0x45, 0x23, 0x77, 0xe8, 0xf1, 0x2c, 0x18, 0x4f, 0xe7, - 0xed, 0x46, 0x5b, 0x32, 0xc9, 0xf9, 0xb2, 0x81, 0x9e, 0xa1, 0xd1, 0x19, 0xfc, 0x26, - 0x7c, 0x8a, 0x75, 0x33, 0x81, 0xeb, 0x51, 0xac, 0xf8, 0x54, 0xc1, 0x9e, 0x8d, 0x58, - 0xff, 0x42, 0x74, 0xeb, 0xa8, 0xc6, 0x3f, 0x0f, 0xa1, 0x70, 0xa6, 0x3c, 0xbf, 0xce, - 0x2c, 0xf8, 0x7b, 0xdc, 0xdf, 0x32, 0xb7, 0xe1, 0x98, 0x04, 0x54, 0x1c, 0x2c, 0x58, - 0x97, 0x24, 0xef, 0xc6, 0x9b, 0xc4, 0x65, 0xd0, 0x90, 0x8e, 0x09, 0xb8, 0x4d, 0x1f, - 0x50, 0x41, 0x2b, 0xb0, 0x7f, 0x47, 0xfb, 0x9f, 0x0d, 0x47, 0x29, 0x28, 0x16, 0x14, - 0xca, 0xca, 0xb6, 0x14, 0xef, 0x65, 0xce, 0xba, 0x13, 0x96, 0xb5, 0x24, 0x9d, 0x2c, - 0x61, 0x70, 0x4f, 0xb6, 0xf3, 0x48, 0x44, 0x71, 0x83, 0xf9, 0x88, 0x2a, 0x98, 0xae, - 0x9c, 0x71, 0xa7, 0x66, 0x33, 0xe0, 0x5b, 0x33, 0x3a, 0x1b, 0xce, 0xee, 0xc9, 0xbd, - 0x44, 0xb8, 0x87, 0x6f, 0xab, 0x6c, 0xd7, 0x2a, 0x5e, 0x33, 0x5c, 0x97, 0x7a, 0x04, - 0x55, 0xc5, 0x36, 0x5f, 0xe8, 0x7f, 0x17, 0xa0, 0x5c, 0x0f, 0x8c, 0x23, 0x3b, 0x97, - 0x29, 0xc1, 0x09, 0x3b, 0xae, 0xb8, 0x57, 0x5c, 0xe5, 0xfd, 0xfb, 0xfd, 0x6e, 0x6a, - 0x8e, 0xbf, 0x76, 0x46, 0x47, 0x81, 0xf9, 0xb2, 0x10, 0xed, 0xb3, 0x9d, 0x20, 0x6a, - 0x68, 0x5d, 0x0d, 0xc7, 0xec, 0x06, 0x8e, 0x3c, 0x6b, 0x13, 0xd2, 0xf2, 0xaa, 0x74, - 0x11, 0x92, 0xbc, 0x86, 0x25, 0xab, 0xd3, 0x0d, 0xb6, 0xe6, 0x64, 0xfb, 0x33, 0x30, - 0xf9, 0x5c, 0xb3, 0x1b, 0xa1, 0x29, 0x0b, 0xd7, 0xf8, 0x30, 0x31, 0xc7, 0x89, 0xc2, - 0x4f, 0xd5, 0x73, 0x93, 0x46, 0x90, 0xa7, 0x3b, 0x54, 0xa9, 0x05, 0xdf, 0x8e, 0x1d, - 0x59, 0x32, 0x2f, 0x26, 0x2b, 0xbf, 0xbe, 0x95, 0xcc, 0x5b, 0x9b, 0x1e, 0x20, 0x31, - 0x0b, 0x76, 0x35, 0x0b, 0x4d, 0x60, 0x4c, 0xd1, 0xa4, 0x58, 0x66, 0x1d, 0xc4, 0x74, - 0xfe, 0x4c, 0x58, 0x79, 0x04, 0xc0, 0x53, 0x47, 0x5e, 0x17, 0x61, 0xb8, 0x0a, 0x60, - 0xcc, 0x48, 0xed, 0xd9, 0x54, 0x34, 0xdf, 0x02, 0x3b, 0x94, 0xa5, 0x8a, 0x99, 0xd6, - 0x25, 0x66, 0xe0, 0x0f, 0x67, 0x77, 0x90, 0xdc, 0xa0, 0x76, 0xa4, 0xf1, 0x67, 0x47, - 0x0c, 0x43, 0xa8, 0x1e, 0x6c, 0x32, 0xf0, 0xd0, 0x0d, 0x23, 0x65, 0x6b, 0xa7, 0x48, - 0x28, 0xb8, 0xe4, 0xd4, 0x75, 0x38, 0xe5, 0x0c, 0x0e, 0xce, 0xe2, 0xcd, 0xfe, 0x0d, - 0x59, 0x43, 0xe2, 0x3e, 0x3f, 0x17, 0x33, 0x82, 0x9d, 0x3e, 0x1b, 0x80, 0x53, 0x93, - 0x30, 0xe0, 0x6c, 0x6a, 0xe3, 0xd0, 0xec, 0xe7, 0x38, 0xc0, 0xdd, 0x74, 0x2a, 0xa5, - 0x86, 0x0f, 0x43, 0xb5, 0x30, 0xf0, 0x3d, 0xc5, 0x5d, 0xeb, 0xf7, 0x20, 0x12, 0x3f, - 0x8f, 0xba, 0xf2, 0xe5, 0x68, 0x59, 0xa5, 0x34, 0x3d, 0x46, 0x12, 0xee, 0x21, 0x46, - 0x4d, 0xb2, 0x50, 0x1d, 0x4f, 0x35, 0x31, 0x47, 0xf3, 0xe1, 0xa5, 0xab, 0xb8, 0x93, - 0x85, 0x08, 0x16, 0xc8, 0x0a, 0xf2, 0x9d, 0x88, 0x92, 0x48, 0xc9, 0x2a, 0x72, 0x9a, - 0x0e, 0x2b, 0xe2, 0xb6, 0x6c, 0xc1, 0x3a, 0xc5, 0xd9, 0x96, 0xb2, 0x50, 0x14, 0x66, - 0x6d, 0xdc, 0x63, 0x8a, 0x1f, 0xd2, 0xa0, 0xaf, 0xee, 0x93, 0xd9, 0x8e, 0x31, 0xdc, - 0x1e, 0xa8, 0x58, 0xd7, 0x2b, 0x84, 0xbb, 0xd3, 0x2f, 0xc0, 0xc6, 0x16, 0xe7, 0xd4, - 0xab, 0xda, 0xf3, 0xc1, 0x8f, 0xf9, 0x60, 0x13, 0x24, 0x5d, 0x83, 0xb3, 0xbd, 0xf9, - 0x21, 0xf4, 0x03, 0xf1, 0xae, 0xcf, 0xdd, 0xd8, 0x85, 0xfd, 0xcf, 0xc7, 0x33, 0x87, - 0x0f, 0x76, 0x0c, 0xb8, 0x7e, 0xd4, 0xfc, 0xd9, 0xcc, 0xa9, 0x33, 0x2e, 0x8e, 0x1c, - 0x85, 0x62, 0x3b, 0x20, 0x66, 0x09, 0xf8, 0x87, 0xeb, 0xdb, 0xcf, 0x9d, 0xa1, 0x0f, - 0x38, 0x14, 0x19, 0x7a, 0x9f, 0x82, 0x07, 0x05, 0xea, 0xa1, 0x28, 0x3a, 0xc7, 0x93, - 0x16, 0x83, 0x08, 0x3f, 0x22, 0xfc, 0x4d, 0xc7, 0xff, 0x68, 0x1a, 0xb8, 0x46, 0x18, - 0x6f, 0x22, 0xd5, 0x73, 0x08, 0x43, 0xde, 0x71, 0x00, 0xf0, 0x31, 0x17, 0xa3, 0xbb, - 0xa0, 0x64, 0xca, 0x3c, 0xea, 0x93, 0xf3, 0xab, 0xd3, 0x0b, 0xe6, 0xdb, 0x09, 0x35, - 0x52, 0x9d, 0xed, 0x0b, 0x50, 0xec, 0xef, 0x9f, 0x59, 0x6d, 0xb0, 0x1a, 0x87, 0xa8, - 0xda, 0xdb, 0x82, 0x7a, 0x1b, 0xe8, 0xb5, 0x79, 0x9b, 0x33, 0xc9, 0x9a, 0x82, 0x2b, - 0x73, 0xf7, 0xe6, 0x62, 0xed, 0x6f, 0x86, 0x03, 0x45, 0xa2, 0x62, 0x83, 0xc1, 0xb4, - 0x08, 0x0e, 0xcd, 0xf5, 0x79, 0xd7, 0x0e, 0x7b, 0x0c, 0x0a, 0xb7, 0x1e, 0x11, 0x6e, - 0xe2, 0xd9, 0xda, 0x27, 0x46, 0x1e, 0x28, 0x12, 0x2a, 0x09, 0xca, 0x04, 0xde, 0x38, - 0x76, 0x50, 0x2f, 0xd2, 0x4d, 0xff, 0x92, 0x09, 0x55, 0x2f, 0x91, 0x13, 0x87, 0x70, - 0x78, 0xa0, 0x94, 0xe0, 0xe5, 0xf8, 0xce, 0xbb, 0x41, 0x54, 0xe0, 0x3a, 0x6b, 0x56, - 0xf6, 0x04, 0xdf, 0x98, 0x4b, 0xd2, 0x9e, 0xfd, 0x4f, 0x88, 0xc3, 0xf6, 0x29, 0xea, - 0x2b, 0xba, 0x91, 0x27, 0xea, 0x5a, 0x6c, 0xc5, 0xa3, 0x9d, 0x74, 0x1e, 0xdd, 0x71, - 0x1a, 0x24, 0x44, 0x7f, 0xe0, 0x6c, 0xf8, 0x45, 0x5a, 0x44, 0x06, 0x5e, 0x24, 0x52, - 0x76, 0x3b, 0x0d, 0x93, 0xf8, 0x6a, 0x31, 0x47, 0xbd, 0x08, 0x75, 0x7a, 0x4f, 0x7a, - 0xa7, 0x79, 0x3c, 0x97, 0x82, 0x1c, 0x2b, 0x57, 0x22, 0xc9, 0xdb, 0xad, 0x20, 0xf6, - 0xa1, 0xe7, 0xad, 0xf6, 0x8b, 0xf2, 0x22, 0x7b, 0xe5, 0x12, 0x04, 0xe9, 0xde, 0xca, - 0x8d, 0x9e, 0xb6, 0x26, 0x6f, 0x65, 0x9b, 0x33, 0x55, 0xc8, 0x97, 0x7e, 0xae, 0x7e, - 0x9e, 0xd5, 0x39, 0xd1, 0x79, 0x39, 0xf0, 0xc6, 0x16, 0x6b, 0x01, 0x13, 0x2d, 0xb0, - 0x01, 0x66, 0x25, 0x0e, 0xa9, 0x64, 0xe3, 0x9d, 0x9d, 0x55, 0xab, 0x43, 0x9a, 0x29, - 0xbb, 0x0b, 0xcf, 0xd3, 0xa9, 0x99, 0xb3, 0x1f, 0xe7, 0xa9, 0x51, 0x00, 0x2e, 0xe5, - 0xdc, 0x01, 0x27, 0x03, 0x24, 0xb1, 0x10, 0x10, 0x37, 0x89, 0x29, 0x42, 0x90, 0x7c, - 0x6e, 0x19, 0x50, 0x9a, 0x6c, 0x5f, 0x66, 0x59, 0xba, 0xf7, 0xf4, 0x36, 0x3c, 0x49, - 0x15, 0xe6, 0x1b, 0xda, 0x34, 0x06, 0x9b, 0xd9, 0x86, 0xb6, 0x37, 0x7f, 0xf6, 0x04, - 0xed, 0xe5, 0xa7, 0x42, 0x5d, 0xb2, 0x88, 0x86, 0xb1, 0xa2, 0x61, 0x36, 0x6d, 0xa8, - 0xa1, 0x39, 0x86, 0x65, 0xbe, 0xed, 0x3b, 0xe9, 0xbc, 0x2e, 0x05, 0x5e, 0x71, 0x1b, - 0x7d, 0x36, 0xdd, 0xbd, 0xd3, 0x65, 0xcc, 0xdc, 0xd7, 0xfc, 0xba, 0xfe, 0x71, 0x29, - 0x66, 0x95, 0x08, 0xda, 0xc0, 0xad, 0x2d, 0x55, 0xee, 0x7f, 0xc6, 0x0b, 0xce, 0x22, - 0x88, 0x50, 0xba, 0x7b, 0x94, 0x3a, 0x8d, 0x50, 0xff, 0xcb, 0x2a, 0x67, 0x06, 0x51, - 0xd3, 0x15, 0xd8, 0x71, 0x9c, 0x7b, 0x57, 0xf6, 0x37, 0xa3, 0x7e, 0xdd, 0x32, 0x6a, - 0xbc, 0x76, 0xf0, 0xa7, 0x69, 0x0c, 0x23, 0x68, 0x80, 0x16, 0x01, 0x07, 0xc2, 0xb4, - 0xc8, 0x5e, 0xcf, 0x2a, 0xd9, 0xf5, 0xdd, 0x26, 0x45, 0x62, 0x6e, 0x40, 0x90, 0xf1, - 0x00, 0x47, 0xcc, 0x13, 0x15, 0x40, 0xca, 0x58, 0x03, 0x04, 0x5a, 0x6a, 0xee, 0x91, - 0xea, 0x0b, 0x3f, 0x9b, 0x77, 0xc4, 0x43, 0x40, 0x69, 0xc5, 0x32, 0x0c, 0xf5, 0xb7, - 0x01, 0x82, 0xd9, 0xfb, 0xbf, 0x30, 0x98, 0x30, 0x60, 0x11, 0x75, 0x9d, 0x0d, 0x64, - 0xa8, 0x84, 0x14, 0x1e, 0xa0, 0x21, 0xcd, 0xd9, 0x5e, 0xfa, 0x32, 0x63, 0xa5, 0x05, - 0xb8, 0x52, 0x29, 0xd1, 0x54, 0xec, 0xaa, 0x23, 0x5e, 0x8f, 0xa1, 0x07, 0x95, 0xc9, - 0xda, 0x27, 0x41, 0xcd, 0x98, 0x71, 0x90, 0x16, 0xa9, 0x01, 0x17, 0xa7, 0x6f, 0x84, - 0xf0, 0x0b, 0x5c, 0x3d, 0x4b, 0xce, 0xd7, 0x9a, 0x73, 0xbf, 0xb3, 0xa1, 0xc7, 0x8a, - 0xd1, 0xad, 0xea, 0x50, 0x78, 0xf2, 0xf1, 0xb0, 0x0f, 0x81, 0x5b, 0xc7, 0xa3, 0x0e, - 0xf8, 0x58, 0x40, 0x07, 0x77, 0x32, 0xdc, 0xb1, 0xa6, 0x1e, 0xd4, 0xbc, 0xbd, 0x66, - 0x35, 0x28, 0x50, 0x29, 0x77, 0x94, 0xad, 0x67, 0xd2, 0x93, 0xdc, 0xe9, 0x10, 0x61, - 0x13, 0x0c, 0xa4, 0x8b, 0xab, 0xca, 0xaa, 0xd6, 0x0b, 0x1f, 0x7c, 0xed, 0x07, 0xac, - 0x3f, 0xf3, 0x32, 0xd5, 0xc8, 0xd3, 0x2b, 0xa2, 0xf1, 0xe7, 0x8a, 0x23, 0xb0, 0x66, - 0x29, 0xb8, 0x89, 0x06, 0x6f, 0x07, 0x9b, 0xcd, 0xa2, 0x9f, 0xb5, 0xc8, 0x3b, 0xbb, - 0xd3, 0x7e, 0xc6, 0x17, 0x3e, 0x8a, 0x74, 0x81, 0x22, 0x12, 0x86, 0x6b, 0xcb, 0x58, - 0x80, 0x5e, 0x9e, 0x70, 0x17, 0x96, 0xa7, 0x23, 0xd5, 0x15, 0xe6, 0x15, 0x33, 0x20, - 0x0b, 0xe0, 0x6b, 0x01, 0x5f, 0xa0, 0x22, 0x35, 0xc8, 0xcb, 0xc9, 0xf3, 0x61, 0x7e, - 0xe8, 0x19, 0x5f, 0xe1, 0xbc, 0xf5, 0xbb, 0x1b, 0x63, 0x4c, 0xd4, 0x3f, 0x62, 0xea, - 0x93, 0xa4, 0x6d, 0x88, 0xf2, 0xfc, 0xbc, 0x3e, 0x28, 0x40, 0x84, 0xe7, 0x04, 0xfb, - 0x1d, 0x7d, 0x0d, 0x9a, 0xcb, 0x91, 0x96, 0x1e, 0x2e, 0xeb, 0xe2, 0xdc, 0x9e, 0xbe, - 0x36, 0x5b, 0x25, 0xb5, 0x66, 0x75, 0x97, 0x3d, 0x0c, 0x38, 0xf4, 0x76, 0x30, 0x57, - 0x47, 0x23, 0xcd, 0x3e, 0xc6, 0x6c, 0x8f, 0x3b, 0x12, 0x82, 0x21, 0xa7, 0x90, 0xd9, - 0x2c, 0x89, 0x5b, 0x94, 0x27, 0x0f, 0xe9, 0x40, 0x51, 0xa1, 0x70, 0xe9, 0x5b, 0x8b, - 0xe7, 0x16, 0x34, 0x86, 0xec, 0x8c, 0x0b, 0xee, 0xbe, 0xf6, 0x5e, 0x16, 0x26, 0xb0, - 0x46, 0xd7, 0xe7, 0xf8, 0x26, 0x37, 0x2b, 0x6a, 0xa1, 0x0b, 0xae, 0xfb, 0x84, 0x8f, - 0xa1, 0xdf, 0x6b, 0xb1, 0xdc, 0x43, 0x95, 0x40, 0xf6, 0x3c, 0x9c, 0x7a, 0x9d, 0x5f, - 0x88, 0x13, 0x40, 0x29, 0x62, 0x65, 0x1e, 0xe9, 0x84, 0x39, 0x02, 0xb6, 0xc3, 0x98, - 0x2d, 0xce, 0x50, 0xa6, 0x17, 0x8a, 0x55, 0xa1, 0xad, 0xc0, 0x1c, 0xe7, 0xdc, 0x6c, - 0x83, 0x38, 0xe1, 0xa9, 0xce, 0xef, 0xc1, 0x78, 0xdc, 0x43, 0x14, 0xf6, 0x74, 0x9a, - 0x81, 0xa7, 0x31, 0xee, 0x3c, 0x7f, 0xc0, 0xc3, 0x5d, 0x1c, 0xe3, 0x63, 0xce, 0xf1, - 0x13, 0x28, 0xf3, 0x87, 0xc4, 0x01, 0xfe, 0xf2, 0x7a, 0x67, 0xa6, 0x29, 0x2f, 0x6f, - 0x72, 0xb0, 0xa1, 0xd6, 0xc3, 0x89, 0x16, 0x2d, 0x16, 0x2e, 0xf0, 0x50, 0xae, 0x5f, - 0x3d, 0xdb, 0xb5, 0x5c, 0xaa, 0xbc, 0xa9, 0xa1, 0xbe, 0x89, 0xb4, 0x63, 0x49, 0x4d, - 0x74, 0x39, 0xfb, 0x56, 0x47, 0xa9, 0x18, 0x12, 0x8b, 0x96, 0x25, 0xd3, 0x3e, 0xac, - 0xa6, 0x19, 0xd5, 0x2f, 0x03, 0x5f, 0xe6, 0x08, 0x9c, 0xe8, 0xd8, 0xb9, 0x0f, 0xe3, - 0x67, 0x0d, 0x8c, 0x5a, 0x2e, 0x3e, 0x05, 0x49, 0x69, 0xa3, 0xd9, 0x7e, 0x61, 0xb5, - 0xe6, 0x30, 0x67, 0x4f, 0xc7, 0x08, 0x57, 0xf1, 0xbb, 0xf1, 0x0f, 0xdc, 0x40, 0x49, - 0xef, 0xf5, 0x60, 0xeb, 0xa5, 0xf2, 0x2a, 0xcc, 0x8d, 0x77, 0xdb, 0xee, 0x0b, 0x20, - 0x55, 0x7f, 0xa4, 0xd0, 0x33, 0x31, 0x72, 0xcb, 0xb5, 0xcb, 0xcc, 0x2b, 0x13, 0x5f, - 0x2c, 0xcd, 0xe0, 0x14, 0xe6, 0x3e, 0xbe, 0x4e, 0xdf, 0x92, 0x5e, 0x61, 0xba, 0x2a, - 0x32, 0x0c, 0xd3, 0x99, 0x91, 0x5a, 0xdd, 0xfc, 0xeb, 0x1a, 0xd0, 0x69, 0xa9, 0xfd, - 0x5b, 0x62, 0x10, 0xa4, 0xb6, 0xe5, 0x04, 0x52, 0xb1, 0xf9, 0x06, 0xdd, 0x16, 0xf0, - 0x16, 0x68, 0xf0, 0xaf, 0x56, 0x6a, 0x28, 0x7c, 0xce, 0xfc, 0xd8, 0x94, 0x73, 0x41, - 0x85, 0x9a, 0xe7, 0xdc, 0x3a, 0x06, 0xf6, 0xbf, 0x15, 0x74, 0xfe, 0xb9, 0x31, 0xf9, - 0x27, 0xe2, 0xd5, 0x05, 0xf6, 0x08, 0x59, 0x9e, 0x23, 0xb0, 0x5a, 0xf7, 0xc3, 0x23, - 0x69, 0x83, 0x97, 0xa8, 0x01, 0xdc, 0x7f, 0x78, 0x82, 0x5c, 0xc7, 0xeb, 0x9f, 0xcc, - 0xe6, 0xc6, 0xc4, 0xf8, 0xf6, 0x88, 0x39, 0xd3, 0x0a, 0xc5, 0x67, 0x14, 0x8e, 0x70, - 0x84, 0xdb, 0x2b, 0x37, 0x58, 0x30, 0xa0, 0x7b, 0x30, 0x5f, 0xed, 0xd6, 0x07, 0xa3, - 0x47, 0xfa, 0x65, 0xde, 0xf0, 0x1d, 0x4e, 0x1f, 0xd6, 0xc1, 0x6b, 0x4b, 0x47, 0xf5, - 0xb0, 0x1b, 0x43, 0x65, 0xb7, 0x72, 0x26, 0xe6, 0x0f, 0xdd, 0x40, 0xf2, 0x2a, 0x39, - 0x5a, 0xa2, 0x35, 0xf0, 0xdf, 0xda, 0x8f, 0xb4, 0xd3, 0xde, 0x65, 0xb0, 0xcf, 0x4f, - 0x4c, 0x22, 0x0b, 0x3b, 0x4a, 0x9e, 0x32, 0xbc, 0x0d, 0xb6, 0x4f, 0x16, 0x2c, 0x07, - 0xdf, 0x42, 0xa1, 0x01, 0x99, 0x03, 0xa6, 0x7c, 0xda, 0x69, 0x3d, 0xde, 0xb5, 0xca, - 0x39, 0xa0, 0xfe, 0x50, 0x08, 0x50, 0xec, 0x7c, 0x06, 0xbe, 0xe7, 0x18, 0x66, 0xb3, - 0x55, 0xcc, 0xbc, 0x07, 0x8c, 0xd4, 0xdc, 0x03, 0x6f, 0xda, 0xa8, 0x1c, 0xb2, 0xde, - 0x99, 0xcc, 0x88, 0xf6, 0x0a, 0x49, 0x46, 0x42, 0x87, 0xf5, 0x9f, 0xc7, 0x14, 0x8b, - 0x1a, 0xfb, 0x4a, 0x2f, 0x9b, 0xb8, 0x97, 0x14, 0xe1, 0xeb, 0x8c, 0x03, 0x61, 0xe5, - 0x99, 0x2a, 0x5b, 0x79, 0xcd, 0xbb, 0x91, 0xd9, 0xbf, 0x29, 0xeb, 0x59, 0x8c, 0xbb, - 0x4b, 0xda, 0x92, 0x3d, 0x26, 0x7f, 0xea, 0xcb, 0x91, 0xce, 0x72, 0xd6, 0x1a, 0xb1, - 0xea, 0x00, 0xf5, 0x6a, 0xa6, 0x76, 0x6e, 0xab, 0xc4, 0x7d, 0xca, 0xa6, 0x9a, 0x02, - 0x4b, 0xbf, 0xf2, 0xf2, 0x96, 0x91, 0x7f, 0x17, 0xa3, 0xf8, 0xc9, 0x3e, 0x1b, 0xf2, - 0x9c, 0x3c, 0xfc, 0x99, 0x1a, 0x2b, 0xe8, 0xcf, 0xa7, 0x0e, 0x5d, 0xe3, 0xf2, 0xdd, - 0x52, 0xa7, 0x55, 0x01, 0x38, 0x68, 0x7a, 0xec, 0x28, 0x92, 0x6f, 0xa1, 0x68, 0xb1, - 0x81, 0xdb, 0x72, 0x82, 0xbd, 0x60, 0xda, 0xd3, 0x31, 0x0d, 0xfe, 0x54, 0x2c, 0xeb, - 0xe6, 0x94, 0x74, 0x00, 0x25, 0xc7, 0xec, 0x2a, 0x20, 0x43, 0xfe, 0xbb, 0x77, 0x9f, - 0x7f, 0x37, 0x89, 0xa5, 0xe2, 0x42, 0xdb, 0x48, 0x03, 0xee, 0x36, 0x72, 0x52, 0xc4, - 0x63, 0xc9, 0xa8, 0x8b, 0x41, 0x7b, 0x70, 0x86, 0x6d, 0x9a, 0xfb, 0x7a, 0x08, 0x27, - 0x68, 0x01, 0xf9, 0x22, 0x7c, 0x63, 0x81, 0xf1, 0x5c, 0xc0, 0x94, 0xac, 0x7b, 0xd1, - 0x54, 0xa4, 0xce, 0xf9, 0x0b, 0x48, 0x47, 0xdc, 0x16, 0x8a, 0x01, 0xf1, 0xe3, 0x1e, - 0xec, 0x74, 0xa7, 0xef, 0xce, 0xba, 0x11, 0xf5, 0x07, 0x69, 0xf5, 0xd8, 0xf5, 0x4d, - 0x36, 0x20, 0xc2, 0x3e, 0xc8, 0x99, 0x3f, 0x7a, 0xef, 0x27, 0xc1, 0xd3, 0x51, 0x96, - 0xb1, 0x02, 0xb3, 0xcf, 0x3f, 0xed, 0x8b, 0xf8, 0x5d, 0x8a, 0x45, 0xf6, 0x96, 0x83, - 0xec, 0xdd, 0x1a, 0x23, 0x44, 0xef, 0xb8, 0x48, 0x07, 0xd9, 0x0f, 0x18, 0x35, 0xb4, - 0xf2, 0xf2, 0x4d, 0x8f, 0xf8, 0x12, 0x30, 0x47, 0xeb, 0x9f, 0x7d, 0x30, 0x62, 0x3e, - 0x14, 0x29, 0x0d, 0x56, 0x17, 0x96, 0x3b, 0x42, 0x21, 0x40, 0x4a, 0xe7, 0x61, 0xc8, - 0x6b, 0xec, 0x7a, 0x07, 0xbf, 0x81, 0xa0, 0xb9, 0xa7, 0xf7, 0xd0, 0x87, 0xac, 0x26, - 0xce, 0x3d, 0xfa, 0x9c, 0x93, 0xfe, 0xea, 0xeb, 0xd1, 0x0d, 0xc1, 0x88, 0xc6, 0x27, - 0xd4, 0xb9, 0x1d, 0x2a, 0x79, 0x01, 0xee, 0x5a, 0x1b, 0x38, 0x4d, 0xa3, 0x6e, 0x78, - 0x95, 0xd5, 0xb7, 0x78, 0x21, 0xfe, 0x6b, 0xca, 0xa3, 0xaf, 0xe8, 0xf2, 0x3a, 0x96, - 0x8f, 0xc9, 0xab, 0xa3, 0x7b, 0x1a, 0x4e, 0x25, 0xf5, 0xdb, 0xa1, 0xd1, 0x42, 0xff, - 0x11, 0xff, 0xd7, 0xa1, 0xba, 0x41, 0xef, 0x82, 0xc6, 0x2a, 0x95, 0x94, 0x66, 0xe7, - 0x11, 0x2a, 0xf7, 0x79, 0x6d, 0x47, 0x67, 0x12, 0x69, 0xad, 0xd3, 0xee, 0x2b, 0x17, - 0x21, 0x3e, 0xc3, 0xbd, 0x51, 0x30, 0x24, 0x4c, 0xb9, 0x07, 0x0e, 0xa8, 0xcf, 0xa4, - 0x6d, 0x44, 0xf2, 0xfc, 0xd9, 0x64, 0x06, 0x37, 0xf7, 0xde, 0xfd, 0x50, 0xb6, 0xdc, - 0x93, 0x60, 0x19, 0x45, 0xb9, 0x31, 0xe8, 0xbb, 0x72, 0x67, 0x1f, 0xe4, 0xb4, 0xb5, - 0x88, 0xc9, 0x0a, 0xd5, 0xc0, 0x0b, 0x55, 0xdc, 0x8c, 0x8a, 0xf9, 0xb0, 0xf6, 0xa3, - 0xca, 0x1e, 0x07, 0xef, 0xf1, 0x58, 0x11, 0x39, 0x1c, 0x53, 0xf7, 0xe4, 0x3b, 0x1b, - 0x81, 0x16, 0xda, 0xdc, 0x01, 0x6d, 0x19, 0x26, 0xc8, 0x48, 0x0d, 0x4e, 0xe3, 0x4e, - 0x76, 0x19, 0x1b, 0x79, 0xbe, 0xd0, 0xce, 0x95, 0x97, 0x3a, 0x4c, 0x7c, 0xf2, 0xf0, - 0x57, 0xc7, 0x14, 0x7e, 0xdb, 0x01, 0x3d, 0x20, 0x5d, 0x81, 0xe2, 0x36, 0x08, 0x88, - 0xa2, 0xab, 0xdd, 0xcc, 0xf0, 0xf6, 0xf3, 0xd8, 0xf8, 0xba, 0x11, 0x1d, 0x64, 0x2c, - 0x52, 0xd0, 0x4e, 0xbd, 0x3c, 0xe1, 0x7c, 0x60, 0xd9, 0x22, 0x57, 0xea, 0x58, 0x69, - 0x09, 0x45, 0x01, 0xbb, 0x67, 0x12, 0x68, 0xb2, 0x24, 0x47, 0x7a, 0x8e, 0x01, 0x41, - 0xd6, 0xff, 0x37, 0xe2, 0x4f, 0xf1, 0xc7, 0x65, 0xe8, 0x4d, 0x26, 0x4d, 0xb8, 0x8f, - 0x00, 0x92, 0x8e, 0x64, 0xc4, 0x12, 0xbd, 0x59, 0x15, 0x1a, 0x65, 0x71, 0xc6, 0x67, - 0x09, 0x16, 0xb0, 0x70, 0x6b, 0x04, 0x4f, 0xc5, 0xc2, 0xbd, 0x93, 0xad, 0xe3, 0x96, - 0x79, 0x57, 0xcd, 0xb9, 0x41, 0x27, 0x4c, 0xc6, 0xbd, 0xb4, 0xe0, 0x36, 0xb7, 0x67, - 0xb9, 0x50, 0xc0, 0x9e, 0x46, 0x26, 0xa1, 0xd0, 0x05, 0xbc, 0xf4, 0x83, 0x6e, 0xf6, - 0xa1, 0xde, 0x48, 0x09, 0x5d, 0xcb, 0x46, 0x12, 0x78, 0xb1, 0x6c, 0x45, 0x68, 0x90, - 0xb2, 0x3d, 0x40, 0xbd, 0x36, 0x04, 0x10, 0xf0, 0x01, 0x0a, 0x55, 0xf5, 0x05, 0xfe, - 0x5e, 0x2d, 0xb2, 0x01, 0xc7, 0x52, 0xe9, 0xb5, 0xb1, 0x5b, 0xf8, 0xaa, 0x9e, 0x82, - 0xd6, 0x49, 0xab, 0x11, 0x73, 0xba, 0x2a, 0x51, 0x32, 0xe0, 0xcc, 0x50, 0x51, 0xcc, - 0xf7, 0x4c, 0x7a, 0x6a, 0x37, 0x07, 0xab, 0x59, 0x83, 0xf7, 0xcc, 0x27, 0x5c, 0x99, - 0x1a, 0xbe, 0x4d, 0x7c, 0xee, 0x5f, 0x28, 0x9e, 0xfe, 0x72, 0x7e, 0xb3, 0xda, 0x86, - 0xfa, 0x21, 0xa2, 0x8d, 0x6b, 0x8a, 0x2a, 0xff, 0xd4, 0x2d, 0xb9, 0x8b, 0xb2, 0xa4, - 0x6c, 0xd8, 0xa3, 0x29, 0x31, 0x2f, 0xa9, 0x45, 0x39, 0xd9, 0xcb, 0x35, 0xdc, 0xb6, - 0x04, 0x67, 0x8b, 0x63, 0x90, 0x64, 0xd9, 0x20, 0x05, 0xdf, 0x2d, 0x10, 0x68, 0x1c, - 0x64, 0xb9, 0xed, 0x8c, 0xe4, 0x7d, 0x7e, 0xba, 0x0f, 0x2b, 0x50, 0x2b, 0x20, 0x6a, - 0xd4, 0xb2, 0xe9, 0x2b, 0xbe, 0x45, 0x86, 0xf6, 0xd7, 0x50, 0x9e, 0x57, 0xa6, 0x37, - 0x7f, 0xea, 0xbe, 0x38, 0xb3, 0xcc, 0x6c, 0x95, 0x5d, 0x5e, 0x7b, 0xdf, 0x7e, 0xb1, - 0x32, 0xd8, 0x6b, 0xc0, 0x7a, 0x30, 0x98, 0xb4, 0x13, 0xe4, 0x40, 0x5d, 0xaa, 0xa2, - 0x55, 0x29, 0x1d, 0x55, 0x2b, 0x2c, 0x80, 0x07, 0xbe, 0xd4, 0x1e, 0x22, 0xf1, 0xcf, - 0x79, 0x11, 0x82, 0x12, 0x00, 0x55, 0x5e, 0x9c, 0x4f, 0xfb, 0x09, 0xef, 0xc1, 0x22, - 0x38, 0x11, 0x75, 0x03, 0x1c, 0x38, 0x28, 0x0b, 0x53, 0x26, 0xeb, 0xbe, 0xaf, 0x33, - 0x4f, 0xdc, 0xf0, 0xdc, 0x44, 0x4e, 0x62, 0x9f, 0x93, 0x95, 0x51, 0x54, 0x0b, 0xcb, - 0xbb, 0xb1, 0xab, 0x9c, 0x23, 0x1a, 0x86, 0x6b, 0x32, 0x9e, 0x85, 0x24, 0xab, 0x25, - 0xf9, 0x3e, 0x5e, 0x33, 0x4a, 0x05, 0x27, 0x2a, 0x3f, 0x82, 0x6f, 0x9d, 0x05, 0xa4, - 0x50, 0x58, 0xdf, 0xcd, 0xf6, 0x88, 0x43, 0xa8, 0xb9, 0x36, 0xa0, 0xcf, 0x5e, 0x6a, - 0xa8, 0xae, 0x1b, 0x80, 0xf6, 0x01, 0x61, 0xbf, 0x41, 0x4f, 0x28, 0x02, 0x11, 0x11, - 0x09, 0x21, 0xa9, 0xc8, 0x5f, 0x51, 0x04, 0xa0, 0x16, 0x8e, 0x8e, 0x72, 0xde, 0x4f, - 0x8a, 0xa0, 0x41, 0x32, 0xeb, 0x25, 0x88, 0x76, 0xf1, 0x9d, 0x7b, 0xe5, 0xf2, 0xdd, - 0x2b, 0x0b, 0x30, 0x4b, 0x92, 0x3b, 0x29, 0x52, 0xd9, 0x1f, 0xde, 0xe7, 0xe5, 0x52, - 0x05, 0xdb, 0xb1, 0x94, 0xeb, 0xba, 0x32, 0x2f, 0xdc, 0x67, 0xb2, 0x52, 0x2c, 0x92, - 0x61, 0x21, 0xc7, 0xfa, 0x1a, 0xf1, 0x7e, 0xd0, 0x6c, 0x47, 0x27, 0x8f, 0x96, 0x08, - 0x92, 0x96, 0x08, 0x7a, 0x70, 0x4b, 0x7d, 0x0f, 0x84, 0x7d, 0x51, 0xd6, 0xcc, 0x68, - 0xac, 0xc5, 0x22, 0x07, 0x74, 0x73, 0x41, 0xf6, 0xb9, 0x8c, 0xb1, 0xcd, 0x4f, 0xaf, - 0xcd, 0x2b, 0xb0, 0xd0, 0x5b, 0xc7, 0x9b, 0xb8, 0x0d, 0x7c, 0x4b, 0x8a, 0x1a, 0x11, - 0xbc, 0x0a, 0x3b, 0xde, 0xca, 0x45, 0x41, 0x86, 0x9b, 0x4d, 0xc9, 0xd6, 0xb4, 0x8c, - 0xd7, 0x86, 0x9b, 0xf7, 0x63, 0xb9, 0xdc, 0x42, 0x45, 0x27, 0x3c, 0x70, 0x4b, 0x0d, - 0x8d, 0xec, 0x4b, 0x85, 0xd1, 0x6d, 0xd4, 0x38, 0xce, 0xd6, 0x22, 0x0f, 0xa6, 0x69, - 0x26, 0x66, 0x3f, 0xcc, 0x22, 0x8f, 0xc6, 0xc4, 0xd2, 0x7e, 0x17, 0xe3, 0x27, 0x83, - 0x4b, 0x67, 0x57, 0x91, 0x4d, 0x1b, 0xcb, 0xf3, 0x4b, 0x65, 0xd8, 0x58, 0xab, 0x8b, - 0x5c, 0x12, 0x0c, 0xb0, 0x85, 0x05, 0x22, 0xf5, 0x42, 0x89, 0x3f, 0xdd, 0xb1, 0x79, - 0xe8, 0x7f, 0x83, 0x2d, 0xaa, 0xa1, 0x52, 0xc8, 0x31, 0xf1, 0x35, 0x64, 0x00, 0x9c, - 0x41, 0x81, 0x23, 0x53, 0x3d, 0xe2, 0xc6, 0x79, 0x49, 0xe3, 0xaf, 0x2d, 0xcb, 0x60, - 0xd6, 0xbd, 0xbd, 0xda, 0xda, 0x63, 0xa3, 0x0b, 0x4b, 0x54, 0xcd, 0x1c, 0xe5, 0xa5, - 0xa0, 0x0f, 0x8e, 0x85, 0x57, 0xeb, 0xa9, 0x23, 0x4e, 0x81, 0x17, 0x8d, 0x0f, 0xca, - 0xb5, 0x61, 0x0f, 0xba, 0x96, 0x69, 0xcf, 0xeb, 0x1b, 0xd0, 0x8c, 0xd9, 0x65, 0x33, - 0x49, 0x8b, 0x27, 0x2c, 0x57, 0x79, 0xa9, 0xf9, 0x39, 0x69, 0x1d, 0xe1, 0xad, 0x88, - 0x1c, 0x80, 0x87, 0x8d, 0x6c, 0x29, 0x42, 0x15, 0x23, 0x0b, 0xbb, 0x61, 0x90, 0x69, - 0xb4, 0xdc, 0x17, 0xb3, 0xe5, 0x9d, 0xbd, 0x24, 0x2c, 0xd8, 0x8e, 0xcc, 0x3b, 0xe3, - 0xa2, 0x69, 0x6b, 0xf7, 0xf2, 0xd9, 0xe5, 0xb8, 0xc1, 0x52, 0xcc, 0x0d, 0x99, 0xa0, - 0xa5, 0xe9, 0xa3, 0x8b, 0x1b, 0x8e, 0xb1, 0xa0, 0x13, 0xeb, 0x76, 0x51, 0x33, 0x37, - 0xa7, 0xb0, 0xda, 0xdb, 0x4e, 0x81, 0x7b, 0x6f, 0x49, 0x78, 0x02, 0xbd, 0x47, 0xe9, - 0x3a, 0x82, 0x0c, 0x4f, 0xad, 0x6c, 0x65, 0x09, 0x74, 0x42, 0xb9, 0xca, 0xc1, 0x61, - 0xb6, 0x4d, 0x0f, 0xcb, 0xfb, 0xf5, 0x4f, 0xc3, 0x04, 0xc9, 0xb7, 0x0c, 0x74, 0xfb, - 0xb0, 0xd7, 0x05, 0xc7, 0x4d, 0x56, 0xac, 0xb2, 0xfe, 0x6c, 0x91, 0x74, 0xcc, 0x00, - 0xea, 0xbe, 0xa0, 0xe5, 0x97, 0x0d, 0xff, 0xe3, 0x2c, 0xb6, 0x12, 0x92, 0x05, 0x3d, - 0xb8, 0x6d, 0x36, 0x6b, 0x7e, 0x6b, 0x30, 0x13, 0xd1, 0x4b, 0x20, 0x5f, 0xb4, 0x5d, - 0x06, 0x7e, 0x37, 0x50, 0x2e, 0x37, 0x9c, 0x4a, 0xa1, 0x38, 0xbe, 0xc2, 0xc6, 0xbd, - 0x33, 0x1f, 0x58, 0xe9, 0xaa, 0x10, 0x09, 0xb0, 0x66, 0xdc, 0xe9, 0x9a, 0xcc, 0x1d, - 0xc5, 0xa6, 0x3a, 0x8f, 0x75, 0xd1, 0x98, 0x22, 0x7c, 0x2f, 0xbd, 0x20, 0xd5, 0x34, - 0xf1, 0x20, 0x30, 0xc4, 0x00, 0x99, 0xd8, 0x77, 0xca, 0xbe, 0x81, 0xb0, 0x87, 0x50, - 0xe3, 0xfb, 0xfe, 0x63, 0x12, 0xf6, 0x38, 0x0b, 0x98, 0xfb, 0x85, 0x0a, 0x2a, 0x14, - 0x2b, 0x91, 0x4a, 0xdc, 0x71, 0x54, 0x47, 0xc5, 0x79, 0x1a, 0x1b, 0x67, 0xae, 0x65, - 0x6c, 0xad, 0xdd, 0x21, 0xe1, 0xb4, 0x6d, 0xc9, 0xa7, 0x64, 0x12, 0x7b, 0xc0, 0xa3, - 0x01, 0xb4, 0x80, 0x04, 0xa9, 0xc5, 0x27, 0x6b, 0xcf, 0x08, 0xe7, 0xfe, 0x4a, 0xe5, - 0x2d, 0x76, 0xe4, 0x31, 0x48, 0x8a, 0x5b, 0x9d, 0x43, 0x1f, 0xa1, 0x36, 0x34, 0x6e, - 0x5a, 0x53, 0xab, 0x3f, 0x68, 0x12, 0xf2, 0xd9, 0x70, 0xf7, 0xb3, 0x98, 0x98, 0xcf, - 0x8b, 0x62, 0xf2, 0xdb, 0xf6, 0x1e, 0x99, 0xa2, 0x91, 0x5d, 0xfb, 0x75, 0xae, 0x22, - 0xb7, 0x9f, 0x84, 0xcf, 0x25, 0x97, 0xeb, 0x34, 0xec, 0x3d, 0x29, 0x2e, 0x6b, 0x5d, - 0x84, 0xeb, 0xac, 0x4d, 0x92, 0xde, 0x52, 0xe1, 0xf8, 0xbf, 0x6b, 0xfd, 0xba, 0xda, - 0x63, 0x44, 0x09, 0xf2, 0x0e, 0xf2, 0xcc, 0x6e, 0x3c, 0x39, 0x0e, 0x43, 0x5f, 0x47, - 0xe3, 0x47, 0x23, 0x8d, 0xb4, 0x86, 0x90, 0x84, 0x04, 0x73, 0xb0, 0xa0, 0x83, 0x1a, - 0x5a, 0x8a, 0x58, 0xc4, 0xdc, 0xfc, 0x4e, 0xab, 0x7b, 0x41, 0x8c, 0xba, 0x2a, 0x41, - 0x4f, 0x95, 0x57, 0x71, 0x90, 0xff, 0x88, 0xd7, 0x27, 0xf7, 0x3e, 0x2f, 0xff, 0x97, - 0xaa, 0xbd, 0x11, 0x14, 0xb7, 0x64, 0xe3, 0xed, 0xbc, 0x18, 0x3e, 0x60, 0x3a, 0xcf, - 0xb7, 0xc0, 0x9b, 0xf1, 0x32, 0xbb, 0x01, 0xef, 0xc7, 0x17, 0x8d, 0x4f, 0x9a, 0x2d, - 0xba, 0xf4, 0x92, 0x4f, 0xd8, 0x0f, 0xbe, 0x0e, 0x60, 0x4f, 0x60, 0x39, 0x08, 0x32, - 0xeb, 0x98, 0x04, 0x79, 0xe0, 0x4e, 0x9c, 0x9a, 0x2b, 0xb2, 0xfb, 0x36, 0x84, 0xd8, - 0xf8, 0x06, 0x48, 0xd5, 0x80, 0x78, 0x38, 0x54, 0x58, 0x4f, 0x62, 0xbe, 0x0c, 0xc9, - 0x21, 0x88, 0x32, 0x38, 0x56, 0x10, 0xd9, 0x62, 0x36, 0x5f, 0x50, 0x71, 0xfa, 0x3d, - 0x36, 0x8f, 0xfb, 0x67, 0x1b, 0xa2, 0xc2, 0xf9, 0xa0, 0xfc, 0x68, 0xd8, 0x07, 0x22, - 0x19, 0xa7, 0x7b, 0xef, 0x2d, 0x6b, 0x4a, 0x19, 0xf1, 0x6d, 0xd5, 0x30, 0x74, 0x22, - 0x47, 0x46, 0xbb, 0xa5, 0xf1, 0x72, 0x82, 0x20, 0xb1, 0x96, 0xe4, 0x0f, 0x93, 0x7c, - 0x47, 0x05, 0x42, 0x9d, 0x04, 0xaa, 0x3c, 0x50, 0x5c, 0x95, 0x60, 0x3e, 0x05, 0xff, - 0x55, 0x2e, 0xc1, 0x86, 0x42, 0xd5, 0x67, 0x05, 0x02, 0x67, 0xb9, 0xf9, 0x92, 0x9c, - 0x2e, 0x13, 0x80, 0x14, 0xb5, 0xef, 0x1b, 0xa7, 0x1d, 0x9a, 0x71, 0x86, 0xe3, 0xd1, - 0x3c, 0x8a, 0x8e, 0x40, 0x8c, 0x2a, 0x9d, 0x12, 0x01, 0xa7, 0xfe, 0xbb, 0x83, 0x34, - 0x51, 0x2b, 0x44, 0xb8, 0x2b, 0xb2, 0x01, 0x78, 0x9f, 0x63, 0x58, 0x04, 0x89, 0x6e, - 0x3e, 0xb2, 0x1b, 0x5b, 0xd8, 0xc4, 0x21, 0xf0, 0xb4, 0xcf, 0xba, 0x04, 0xde, 0x92, - 0x52, 0x8f, 0x04, 0xfb, 0x4b, 0x52, 0x6b, 0x73, 0x7e, 0xe3, 0x2d, 0xa8, 0x63, 0xf5, - 0x98, 0x45, 0x61, 0x31, 0x98, 0x3a, 0x01, 0x35, 0x8f, 0xb0, 0x7d, 0xe6, 0x75, 0x21, - 0x11, 0x58, 0x5a, 0x86, 0x25, 0x6c, 0xe0, 0x34, 0xc0, 0xd8, 0x57, 0x5a, 0x42, 0x76, - 0x13, 0x61, 0xb1, 0x18, 0x77, 0x05, 0x0b, 0xc6, 0xaf, 0xc3, 0x16, 0x15, 0x64, 0xe9, - 0x6f, 0xd8, 0xcf, 0x04, 0x8f, 0xeb, 0xeb, 0x2a, 0x92, 0x20, 0x07, 0x1c, 0xff, 0x18, - 0x2d, 0x6c, 0xa0, 0x37, 0xce, 0x2c, 0x2d, 0xed, 0x91, 0x6b, 0xd7, 0xb8, 0x4d, 0xe2, - 0x8a, 0xc0, 0x17, 0x1d, 0x97, 0xfc, 0x24, 0x95, 0x6c, 0x26, 0x66, 0x69, 0xc1, 0x03, - 0x6b, 0x2b, 0x1a, 0x23, 0xda, 0xbc, 0xf3, 0x4e, 0x38, 0xf3, 0x51, 0x45, 0x12, 0xae, - 0x8a, 0x47, 0xb3, 0x53, 0xb4, 0x16, 0x69, 0x96, 0x75, 0xe4, 0xd3, 0x1a, 0x2f, 0xe0, - 0x34, 0x08, 0xe4, 0x24, 0xa7, 0x82, 0x9a, 0x06, 0xad, 0xe6, 0x36, 0x53, 0x61, 0xd8, - 0xa9, 0x61, 0x25, 0x7c, 0xbe, 0x25, 0xb0, 0xcd, 0xe3, 0x3e, 0x96, 0x48, 0x77, 0xdf, - 0x5e, 0x57, 0xc5, 0x3d, 0xb2, 0x83, 0x51, 0x77, 0x34, 0x3e, 0x2d, 0x87, 0x6d, 0x51, - 0x4c, 0x62, 0xfb, 0xb3, 0xb4, 0xa7, 0x08, 0xce, 0x62, 0x62, 0x05, 0xcc, 0xf9, 0x2f, - 0x24, 0x0d, 0x60, 0x2c, 0xdb, 0x5d, 0x68, 0x41, 0xfd, 0x29, 0xda, 0x63, 0x08, 0xb6, - 0xca, 0x40, 0x97, 0xd8, 0x52, 0x54, 0x10, 0x46, 0x54, 0x52, 0x23, 0x9b, 0x04, 0x51, - 0xa8, 0xdb, 0xed, 0xac, 0x1e, 0x41, 0xed, 0xdd, 0x0f, 0x6b, 0xe0, 0xe3, 0xd8, 0x89, - 0x69, 0x07, 0x03, 0xa3, 0x14, 0x57, 0x07, 0xe0, 0xb3, 0xf5, 0xdb, 0x91, 0xb8, 0x19, - 0x37, 0x56, 0xe0, 0xe3, 0x47, 0xb6, 0x64, 0xa1, 0xcc, 0xcb, 0xd7, 0x86, 0x9a, 0x40, - 0x22, 0xea, 0xdf, 0x3f, 0x87, 0x3c, 0x10, 0xec, 0xab, 0x9a, 0x93, 0xf2, 0xca, 0xdc, - 0xa7, 0xa3, 0x33, 0xb8, 0x1b, 0xb6, 0x10, 0x4e, 0x82, 0xea, 0x14, 0xfe, 0x74, 0x1e, - 0xb0, 0x62, 0x08, 0x0d, 0xc8, 0x5a, 0xcb, 0xc8, 0xcc, 0x3a, 0x9b, 0xc8, 0x0c, 0x03, - 0xd9, 0x1f, 0xfb, 0x3c, 0x25, 0xf9, 0xe4, 0x2b, 0xc2, 0x5c, 0xf7, 0x7d, 0x73, 0x90, - 0xc3, 0xab, 0xaf, 0x26, 0x10, 0xf4, 0xec, 0xdb, 0x01, 0x9b, 0x15, 0x8d, 0xa2, 0x15, - 0x5b, 0xef, 0xec, 0xb9, 0xc2, 0x29, 0x6d, 0x03, 0xf8, 0x23, 0xea, 0xac, 0x0c, 0x74, - 0x0d, 0x2a, 0x44, 0x89, 0xb8, 0x28, 0x4c, 0x7e, 0x7b, 0x3a, 0x72, 0x9a, 0xfb, 0x69, - 0xbd, 0x5b, 0xfa, 0x5f, 0x62, 0xf9, 0xb5, 0x27, 0x37, 0x97, 0xdd, 0x24, 0xa0, 0x18, - 0x30, 0x7f, 0xc6, 0x20, 0xe6, 0x42, 0xaa, 0x27, 0xe7, 0x50, 0x6e, 0x17, 0xb1, 0x98, - 0xdc, 0xa4, 0x79, 0x0e, 0x8d, 0xe1, 0xbf, 0xb6, 0x71, 0xd8, 0xdc, 0x75, 0x13, 0x91, - 0x0e, 0x95, 0x43, 0x10, 0x72, 0x1b, 0x4f, 0xb5, 0x37, 0x33, 0xc9, 0x18, 0xf0, 0xd1, - 0x89, 0x85, 0x18, 0x89, 0x62, 0x73, 0x22, 0xd5, 0x20, 0xca, 0xcc, 0x9d, 0xd7, 0x03, - 0x6b, 0xb4, 0x39, 0xa1, 0x69, 0xef, 0x2c, 0xdd, 0x6c, 0xdb, 0xae, 0xa5, 0xa9, 0x1b, - 0xc2, 0x4a, 0xb3, 0xfc, 0xa1, 0x57, 0x4c, 0x12, 0xc9, 0x31, 0xe7, 0xaa, 0x02, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xd3, 0xc6, 0x49, 0x66, 0xc0, 0x6b, 0x62, 0x2d, 0x23, 0xc8, 0x8d, 0xb2, 0xfd, - 0x4b, 0x8f, 0xa5, 0x0b, 0xe3, 0x61, 0x94, 0x3b, 0x79, 0x6d, 0x14, 0x85, 0x5f, 0x20, - 0x71, 0xd3, 0x20, 0xd4, 0x3d, 0x6c, 0x49, 0x4c, 0x9e, 0xda, 0x35, 0xcf, 0x9b, 0xf3, - 0x7d, 0xc5, 0x4b, 0x40, 0x2e, 0xb2, 0x87, 0x64, 0xa0, 0xb9, 0x17, 0x6c, 0xf9, 0x49, - 0xb2, 0xa7, 0x78, 0x64, 0x19, 0x83, 0x89, 0x2f, 0xfb, 0x5c, 0x7b, 0xfa, 0x68, 0xe6, - 0x36, 0xde, 0xfe, 0xfc, 0xb2, 0xfa, 0x07, 0x94, 0x45, 0xec, 0xd3, 0xad, 0xdf, 0x0c, - 0x22, 0xb2, 0x61, 0x72, 0x49, 0x92, 0xe2, 0xf0, 0xd2, 0x7c, 0xff, 0x23, 0xa6, 0x46, - 0x15, 0x30, 0xdc, 0x05, 0xf4, 0x9e, 0x97, 0x2d, 0xa3, 0x71, 0x6f, 0x41, 0x91, 0xbf, - 0xf4, 0xed, 0x29, 0x02, 0x67, 0x46, 0xf0, 0x9e, 0xfa, 0x9d, 0xfc, 0xbc, 0xde, 0xc5, - 0xa6, 0x95, 0xb1, 0xf7, 0x31, 0x36, 0x14, 0x64, 0xec, 0x42, 0xe3, 0xb5, 0x26, 0x7e, - 0xb6, 0x5f, 0x55, 0x6b, 0x26, 0x7a, 0xf3, 0x59, 0x71, 0xb4, 0x14, 0x9b, 0xb3, 0xe5, - 0xaa, 0x03, 0xa4, 0x95, 0xfb, 0xeb, 0x90, 0x15, 0xac, 0x3f, 0xf1, 0x3a, 0x5c, 0x1c, - 0x2a, 0x5f, 0x81, 0x96, 0x47, 0x3d, 0x5b, 0xfe, 0x70, 0x48, 0xdf, 0x27, 0x7f, 0x0b, - 0x5c, 0xf4, 0xe6, 0xc7, 0x1c, 0xa9, 0x36, 0x6e, 0xca, 0x3b, 0x9c, 0xf1, 0xe6, 0x06, - 0x9d, 0x53, 0x9e, 0x5c, 0xe4, 0x3f, 0xd9, 0xaa, 0x25, 0xc2, 0x11, 0xd3, 0x79, 0x92, - 0xc3, 0x40, 0xad, 0xea, 0x8b, 0x24, 0x9f, 0x28, 0xab, 0x23, 0x49, 0x39, 0x17, 0xc4, - 0x9d, 0xeb, 0x28, 0x3b, 0x4c, 0x8a, 0x64, 0x90, 0x41, 0x88, 0x7e, 0x66, 0x83, 0x8d, - 0x1c, 0x42, 0x9d, 0xec, 0xdb, 0x31, 0x59, 0xcb, 0x30, 0xaf, 0xe4, 0xfb, 0x31, 0x68, - 0xcc, 0xec, 0x44, 0x98, 0x2e, 0x05, 0xf8, 0x71, 0x13, 0x2e, 0xfa, 0x63, 0xd6, 0x5a, - 0x24, 0x93, 0xcd, 0xf2, 0x39, 0xe8, 0xb2, 0xc8, 0x09, 0x05, 0xe8, 0x04, 0xa8, 0x4d, - 0xd7, 0x6a, 0xfe, 0xaa, 0x68, 0x94, 0x79, 0x1d, 0x49, 0xb1, 0xe4, 0x00, 0xb3, 0xfc, - 0xaa, 0x82, 0x73, 0x99, 0x60, 0xad, 0xda, 0x36, 0x45, 0xbb, 0x85, 0x75, 0x6c, 0x63, - 0x00, 0x5c, 0x01, 0x6f, 0x65, 0x8b, 0xa6, 0xab, 0x52, 0x57, 0xc4, 0x86, 0xaf, 0x13, - 0xed, 0xc9, 0xb4, 0x6b, 0xf6, 0x29, 0x34, 0xaa, 0x71, 0x4f, 0x00, 0x36, 0x05, 0x96, - 0x5a, 0xc5, 0x4d, 0x82, 0x50, 0xa5, 0x53, 0x52, 0x00, 0xd1, 0x20, 0x2a, 0xcc, 0xca, - 0xaa, 0x9e, 0x42, 0xea, 0x98, 0x2a, 0x21, 0x61, 0x8e, 0xdb, 0xb1, 0x34, 0xc3, 0x3b, - 0xc8, 0x4e, 0x35, 0xfc, 0x76, 0x56, 0x05, 0x86, 0xa3, 0xc3, 0x43, 0x8e, 0x8f, 0x2b, - 0x0c, 0xe7, 0x0d, 0x86, 0x31, 0x71, 0xdf, 0x23, 0x8e, 0x12, 0x60, 0xd5, 0x9f, 0x82, - 0x40, 0x37, 0xa7, 0x71, 0x7b, 0x2e, 0x21, 0xa9, 0x6e, 0x4d, 0x79, 0x9b, 0x8e, 0xc4, - 0xc9, 0x8b, 0x8d, 0x16, 0x83, 0x6c, 0x18, 0x22, 0xb2, 0x45, 0x62, 0x66, 0x46, 0x59, - 0x86, 0x85, 0x0d, 0x23, 0x31, 0xc7, 0x29, 0x34, 0xbd, 0xb6, 0x71, 0x54, 0xab, 0xa0, - 0xad, 0x49, 0xbe, 0x0e, 0x52, 0xd8, 0xb0, 0x78, 0x41, 0x11, 0x7c, 0x0e, 0xb7, 0x6a, - 0x39, 0x54, 0x96, 0x39, 0xf7, 0xad, 0xe7, 0x6a, 0x90, 0x71, 0x0e, 0x79, 0x83, 0x97, - 0x8e, 0x9b, 0x23, 0x34, 0x9b, 0xee, 0x22, 0xcd, 0x0c, 0x71, 0xa1, 0xf0, 0x72, 0x70, - 0xe2, 0xce, 0x8b, 0x36, 0x05, 0x1b, 0x00, 0x55, 0xba, 0x97, 0x05, 0xab, 0x22, 0x2e, - 0x8e, 0x85, 0x8d, 0xc4, 0x5b, 0x66, 0xc1, 0xef, 0x3f, 0xe2, 0x66, 0x55, 0x03, 0xe7, - 0x8b, 0x30, 0x29, 0xef, 0xfb, 0xd5, 0xbb, 0x13, 0x9e, 0x85, 0x2c, 0x3b, 0xf9, 0x07, - 0x13, 0x2e, 0x54, 0xc3, 0xed, 0xad, 0x03, 0xf7, 0xe8, 0x68, 0xf5, 0x23, 0x15, 0x5f, - 0x9f, 0x6b, 0xce, 0xf4, 0x50, 0xbc, 0x9b, 0x56, 0x31, 0x0c, 0xda, 0x17, 0x3e, 0x50, - 0xe9, 0x5a, 0x6e, 0xe5, 0xf0, 0x68, 0xb2, 0x5e, 0x32, 0x9c, 0x35, 0x48, 0xfc, 0x24, - 0x99, 0x37, 0x3c, 0xde, 0x29, 0x36, 0x0f, 0xbb, 0xfa, 0x5b, 0x64, 0xb5, 0x74, 0x4a, - 0xb0, 0x3a, 0x4b, 0xd5, 0xd9, 0x48, 0xc1, 0xbe, 0xf8, 0xcf, 0x4e, 0x6b, 0xd9, 0x4c, - 0x32, 0x80, 0x9b, 0x18, 0xf1, 0x18, 0x9c, 0x32, 0xbb, 0x8f, 0xae, 0x27, 0x53, 0xe4, - 0x85, 0x1c, 0x31, 0x96, 0xf5, 0xbb, 0x1d, 0xa0, 0x78, 0x51, 0xb5, 0xd3, 0x1f, 0x20, - 0xa0, 0xfd, 0x3a, 0x7a, 0x4b, 0x45, 0x01, 0xf3, 0x18, 0x5d, 0x26, 0x7b, 0x1c, 0x8b, - 0xb3, 0x59, 0x5d, 0x85, 0xc5, 0x3c, 0xae, 0x18, 0x9e, 0xc9, 0xdb, 0x6f, 0x14, 0x53, - 0xb3, 0xc6, 0xad, 0x4f, 0x3b, 0x93, 0xdd, 0x10, 0x6a, 0x3a, 0x39, 0x0d, 0xb2, 0x7a, - 0x1a, 0x75, 0x0e, 0x7e, 0xd0, 0x89, 0x7e, 0xbb, 0x61, 0x98, 0x48, 0x4d, 0xcc, 0xdf, - 0xa7, 0xa7, 0xe1, 0xd8, 0xeb, 0x2f, 0x23, 0x66, 0x8d, 0x54, 0xe9, 0x8f, 0x9e, 0xd3, - 0xae, 0x90, 0xfe, 0x0c, 0x27, 0x5f, 0x17, 0x7e, 0xcf, 0x70, 0x1f, 0xd3, 0x0b, 0x92, - 0xf6, 0x1b, 0x3c, 0x12, 0x53, 0xcc, 0x31, 0x78, 0x95, 0xfe, 0x5e, 0x39, 0xc4, 0xea, - 0x03, 0x24, 0x8e, 0x83, 0x20, 0x2e, 0xa5, 0x89, 0xa0, 0xe8, 0xfc, 0xaf, 0xc4, 0x34, - 0x07, 0xb5, 0x71, 0x9c, 0x08, 0x6a, 0xc2, 0xf5, 0x8c, 0x1c, 0x4e, 0x05, 0x63, 0x69, - 0x56, 0xb6, 0x30, 0x4e, 0x31, 0x7f, 0x4f, 0x65, 0xb4, 0xe2, 0xb9, 0x9f, 0x25, 0xe8, - 0xd7, 0xbb, 0x53, 0x28, 0xea, 0x1f, 0x31, 0x13, 0x25, 0x6a, 0x45, 0x08, 0x01, 0x6a, - 0x3e, 0x9d, 0x01, 0x2e, 0xf8, 0x19, 0xfa, 0x36, 0xa5, 0xdb, 0xce, 0x7e, 0x3a, 0xff, - 0x47, 0x42, 0xc0, 0xcd, 0x3d, 0x5d, 0x9e, 0xb8, 0x40, 0x44, 0xa0, 0x03, 0x23, 0x39, - 0x40, 0x69, 0x9b, 0xc2, 0x79, 0x45, 0xb9, 0xac, 0x93, 0x82, 0x23, 0xc1, 0x17, 0x3f, - 0x34, 0xd1, 0x7e, 0x7e, 0x2e, 0x7b, 0xbc, 0xad, 0x2d, 0x91, 0x9d, 0x1a, 0xf5, 0x54, - 0x94, 0x0b, 0x68, 0xd7, 0x43, 0x3a, 0x6d, 0x67, 0xe8, 0x5c, 0xd3, 0x35, 0x66, 0xb0, - 0x60, 0xe4, 0x48, 0xb4, 0xa2, 0xa0, 0x52, 0xa8, 0xb7, 0x9e, 0x27, 0x57, 0x8d, 0xce, - 0x6e, 0x09, 0x88, 0x6e, 0xf0, 0x92, 0xef, 0x09, 0x67, 0x97, 0x47, 0x8b, 0xb5, 0x4b, - 0x9a, 0xbb, 0xa5, 0xae, 0x26, 0x79, 0x9b, 0x07, 0xcd, 0xc8, 0x8c, 0x80, 0x2e, 0x6a, - 0xf5, 0xcb, 0xfd, 0x41, 0x24, 0x29, 0x57, 0x00, 0xac, 0x12, 0xd9, 0x10, 0xa0, 0x2a, - 0x74, 0xc8, 0xab, 0xd2, 0x4d, 0x39, 0x88, 0x72, 0xdd, 0x9d, 0x3a, 0xb3, 0xc5, 0x4c, - 0x63, 0xa0, 0x9e, 0x51, 0xbb, 0x51, 0x62, 0x54, 0x01, 0x03, 0xab, 0x0c, 0xae, 0xfc, - 0x6e, 0x5b, 0x88, 0x05, 0x21, 0xf4, 0x9c, 0x55, 0x93, 0xa7, 0xec, 0xe1, 0xef, 0xdc, - 0x00, 0xad, 0x96, 0xc3, 0x82, 0xfe, 0xcf, 0x0f, 0x9c, 0x1c, 0x8e, 0xcd, 0xcb, 0xc2, - 0x2e, 0x89, 0x07, 0xce, 0x99, 0xdf, 0x99, 0x4a, 0x33, 0x0a, 0x90, 0x44, 0x6d, 0xae, - 0xec, 0xab, 0x71, 0xf0, 0x02, 0x35, 0xdd, 0x70, 0x23, 0x3c, 0x43, 0x17, 0xd6, 0x4e, - 0xf6, 0xba, 0x3f, 0x65, 0x76, 0x42, 0xba, 0xad, 0x97, 0x35, 0xe5, 0x48, 0x68, 0xc1, - 0x97, 0x54, 0x56, 0x89, 0xa0, 0x57, 0x0b, 0xd4, 0x58, 0x4a, 0xad, 0xe4, 0x1a, 0x59, - 0x08, 0xb8, 0xaa, 0x33, 0x54, 0x95, 0x72, 0xc7, 0x20, 0x9f, 0x63, 0xad, 0x0b, 0x80, - 0x4c, 0x76, 0x02, 0xf4, 0x8d, 0xed, 0x66, 0x8c, 0x31, 0xa0, 0x7d, 0x76, 0x02, 0xd6, - 0xf8, 0x24, 0x29, 0xc3, 0xd2, 0xde, 0xe9, 0x2f, 0x38, 0xdb, 0x5b, 0x92, 0x03, 0xac, - 0x84, 0xd0, 0xfe, 0x14, 0xba, 0x6a, 0xc1, 0x9a, 0xaf, 0x94, 0x00, 0xf2, 0xe3, 0x58, - 0x3f, 0xb1, 0x68, 0xd3, 0x03, 0xca, 0x7a, 0x88, 0x71, 0xdd, 0xd9, 0xa2, 0x95, 0x04, - 0x1b, 0x30, 0xb8, 0x1e, 0xea, 0x1e, 0x7d, 0x82, 0x24, 0x34, 0x4b, 0xd2, 0x68, 0xa9, - 0x4a, 0x11, 0x1e, 0xa7, 0xc9, 0xb0, 0x6e, 0xc5, 0x69, 0x12, 0x45, 0x2e, 0xeb, 0x01, - 0xcf, 0x88, 0x87, 0xa3, 0xe2, 0x6e, 0x14, 0x40, 0x6f, 0xfe, 0xec, 0x4b, 0xfd, 0x7a, - 0x9f, 0xd8, 0x77, 0xce, 0x52, 0x03, 0xfe, 0x6b, 0x05, 0x8d, 0x23, 0x1e, 0xc7, 0x1a, - 0xf9, 0xca, 0x18, 0xed, 0x5c, 0x73, 0x55, 0x06, 0xd7, 0xba, 0x28, 0xee, 0x68, 0xee, - 0x66, 0x58, 0x7c, 0x99, 0x8c, 0x8f, 0xec, 0xa7, 0xae, 0x06, 0x8c, 0x8e, 0xd0, 0x79, - 0xe5, 0xa9, 0xa4, 0x36, 0x72, 0x8c, 0xce, 0xe1, 0x0c, 0x8f, 0x12, 0x6f, 0x7b, 0x2f, - 0xa0, 0xd0, 0xff, 0x91, 0xcc, 0x41, 0xee, 0x28, 0xa1, 0x96, 0x23, 0x03, 0x37, 0xc6, - 0x1f, 0x42, 0xe9, 0x52, 0x2b, 0xf6, 0xde, 0x64, 0xfc, 0x5a, 0x57, 0xe3, 0x74, 0x77, - 0x06, 0x07, 0x63, 0x0b, 0xc1, 0x96, 0xed, 0x05, 0x2d, 0xff, 0x00, 0x83, 0x61, 0xfc, - 0x59, 0xfd, 0x9c, 0x48, 0xd2, 0x62, 0xb9, 0x3a, 0xee, 0x45, 0x65, 0x2c, 0x78, 0x78, - 0x05, 0xdf, 0xac, 0xe8, 0x3d, 0x04, 0xe5, 0x24, 0x40, 0x3a, 0x25, 0xa1, 0x66, 0xa1, - 0xf4, 0x8e, 0xcc, 0x8f, 0xff, 0x84, 0x4f, 0x09, 0xde, 0x67, 0x48, 0x04, 0x52, 0xa6, - 0x78, 0x9d, 0x48, 0xb7, 0xbd, 0xbd, 0x81, 0x1f, 0x0e, 0xda, 0xda, 0xa8, 0xee, 0x8e, - 0xb9, 0x16, 0x17, 0x99, 0x2e, 0xad, 0x6f, 0x8a, 0x8b, 0x9e, 0xf4, 0xc5, 0xad, 0xb6, - 0xf2, 0x52, 0x48, 0xb2, 0x13, 0xf3, 0xd6, 0x93, 0xf6, 0x3c, 0x0d, 0x5d, 0x15, 0xab, - 0x54, 0x32, 0x88, 0x07, 0x14, 0x27, 0x35, 0x79, 0x37, 0x3c, 0x49, 0xcb, 0xf1, 0x47, - 0xf9, 0x4a, 0x84, 0xad, 0xe6, 0x48, 0x49, 0xeb, 0x5a, 0x94, 0x04, 0x40, 0x13, 0x38, - 0x96, 0xa2, 0x45, 0x55, 0xe4, 0x01, 0x55, 0x99, 0xc0, 0x46, 0xdf, 0xa6, 0xf1, 0x4a, - 0x28, 0x70, 0x53, 0x3a, 0xe4, 0x7d, 0x33, 0xff, 0x81, 0x6b, 0x8e, 0x46, 0x63, 0xf0, - 0x70, 0xc8, 0x0d, 0x8d, 0xb0, 0x1b, 0x43, 0xc6, 0x0f, 0x5f, 0xc0, 0x2c, 0x85, 0xac, - 0xf5, 0xe1, 0x06, 0xd3, 0xba, 0x71, 0xea, 0x69, 0x3b, 0xa4, 0x65, 0xdd, 0x61, 0xff, - 0x1d, 0x80, 0xfe, 0xee, 0xa1, 0xb6, 0xd5, 0xa1, 0x63, 0xd0, 0xc9, 0x62, 0x43, 0x16, - 0x36, 0xe1, 0xed, 0x62, 0x19, 0x66, 0xfe, 0x28, 0x5b, 0xc9, 0x70, 0xa2, 0x66, 0xbb, - 0x40, 0x8d, 0x4d, 0x48, 0xd5, 0x5e, 0xf7, 0x17, 0x04, 0xf5, 0xb7, 0x98, 0x62, 0xbd, - 0x80, 0x6a, 0x6a, 0x33, 0xe1, 0x13, 0xb1, 0x88, 0x32, 0xb3, 0xd5, 0x9e, 0x3a, 0x69, - 0x84, 0xe1, 0x4f, 0xd5, 0x2a, 0xc9, 0xd2, 0xbe, 0x3a, 0xea, 0xaa, 0xbf, 0x38, 0x29, - 0xcb, 0xf4, 0xdf, 0xca, 0x68, 0x03, 0xaf, 0xcd, 0x1f, 0xc4, 0xcd, 0x02, 0x44, 0xd7, - 0xb6, 0x3b, 0x4c, 0x9d, 0x4a, 0xa1, 0xa2, 0x27, 0xad, 0xda, 0x80, 0x6a, 0x46, 0x24, - 0xa0, 0x79, 0x65, 0xb9, 0xfd, 0xa1, 0x73, 0xa2, 0xd9, 0x9a, 0x62, 0x4f, 0x4a, 0x78, - 0xe9, 0xc7, 0x17, 0x63, 0x01, 0x2b, 0x77, 0xaf, 0x32, 0x6c, 0x75, 0x22, 0x6b, 0x7d, - 0xe8, 0x29, 0x74, 0x4b, 0x6d, 0x39, 0x72, 0xe4, 0x7f, 0x6a, 0x14, 0x5b, 0x81, 0x34, - 0x0d, 0x27, 0x16, 0x20, 0x1e, 0x07, 0x1e, 0x47, 0x1a, 0x85, 0x5e, 0x9c, 0xc3, 0x6d, - 0x39, 0x49, 0x97, 0x15, 0x74, 0xbf, 0x3a, 0x06, 0x0f, 0xc0, 0xd8, 0x82, 0xd0, 0xa9, - 0x86, 0x5c, 0x24, 0xe0, 0x94, 0x03, 0x17, 0x30, 0xcb, 0xe1, 0x88, 0xe6, 0xfd, 0xaf, - 0xcb, 0xba, 0xf7, 0x51, 0xbe, 0x87, 0xaf, 0x96, 0x5c, 0xd9, 0x8d, 0x99, 0x31, 0x04, - 0xca, 0x6e, 0xdd, 0x29, 0x28, 0x0c, 0xda, 0x86, 0x55, 0x67, 0xbd, 0xd4, 0xb4, 0xba, - 0x47, 0x37, 0xe6, 0x1c, 0x3f, 0x0a, 0xd8, 0x75, 0xa8, 0xde, 0xe6, 0xe6, 0xcd, 0xff, - 0x26, 0x81, 0x88, 0x08, 0xff, 0x9b, 0x2d, 0x55, 0x87, 0x95, 0xd6, 0x5d, 0x2a, 0x95, - 0xb4, 0x56, 0x56, 0x19, 0xf7, 0xb2, 0x41, 0x62, 0xcc, 0x47, 0x59, 0x9a, 0x33, 0x13, - 0x06, 0xe3, 0x65, 0x2f, 0xfb, 0xc3, 0xb3, 0xfd, 0x06, 0xc1, 0x46, 0x0c, 0x80, 0x6f, - 0x4e, 0x61, 0xbe, 0xc2, 0xa2, 0xa7, 0xb6, 0xc7, 0x96, 0xf6, 0x5d, 0xcf, 0x36, 0xa4, - 0xaf, 0xc6, 0xd8, 0x10, 0x09, 0x35, 0x21, 0x0a, 0x86, 0x38, 0x9f, 0x24, 0x9e, 0x2f, - 0x82, 0x32, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x8b, 0x33, 0x6b, 0x5f, 0x55, 0x40, 0x0b, 0x06, - 0x79, 0xba, 0x0c, 0x1e, 0xf0, 0x20, 0xc9, 0x26, 0x85, 0xa4, 0x24, 0x91, 0x79, 0x95, - 0xea, 0x63, 0xad, 0x1d, 0x5e, 0x28, 0xdd, 0x63, 0x99, 0x83, 0x82, 0xc7, 0xb3, 0x9d, - 0x26, 0xdb, 0x80, 0xb4, 0x3e, 0x32, 0x4f, 0xaf, 0x5d, 0x63, 0x60, 0x4a, 0x84, 0xf2, - 0x13, 0x5c, 0xbf, 0xf5, 0x98, 0xeb, 0x50, 0xe1, 0xd3, 0xa4, 0xb9, 0x9c, 0xd6, 0x6c, - 0x7a, 0xfd, 0xe6, 0x7f, 0xac, 0x47, 0xf0, 0x35, 0x8e, 0xc7, 0x83, 0xbe, 0x35, 0x95, - 0x47, 0x96, 0xe5, 0x97, 0x3a, 0xcf, 0xf6, 0x31, 0x98, 0xa3, 0x55, 0x94, 0x18, 0x7e, - 0xf8, 0x17, 0x00, 0x0b, 0x08, 0x88, 0x1e, 0x70, 0xe0, 0xb2, 0xcd, 0xe2, 0x31, 0x51, - 0x79, 0xc0, 0x84, 0x15, 0x51, 0xe8, 0xbd, 0x92, 0x8e, 0xb6, 0x24, 0x87, 0x6e, 0x86, - 0xb0, 0xb3, 0x3a, 0xab, 0x0c, 0xde, 0x87, 0xeb, 0x8f, 0xd4, 0x78, 0x8d, 0xe9, 0xfb, - 0x37, 0xea, 0xb3, 0xb4, 0x7f, 0xd5, 0xdf, 0xe9, 0xb3, 0x7b, 0xcb, 0xb6, 0xe1, 0xf2, - 0x25, 0xfd, 0x29, 0xab, 0x07, 0xfc, 0x9f, 0xf5, 0xa0, 0x8f, 0x48, 0x66, 0x9e, 0x1c, - 0x99, 0x68, 0xf5, 0x21, 0x7a, 0xd3, 0x45, 0x2d, 0xad, 0x04, 0x78, 0x39, 0x07, 0x44, - 0xe9, 0xd1, 0x67, 0x85, 0xcd, 0x54, 0xa5, 0x03, 0x98, 0xb0, 0x14, 0xa0, 0x7b, 0x78, - 0x45, 0x99, 0x7a, 0x5b, 0x11, 0x6b, 0xb2, 0xc2, 0xf4, 0xc4, 0xe5, 0x64, 0x6e, 0x63, - 0x08, 0x2c, 0x5e, 0x3f, 0xee, 0x50, 0x92, 0xff, 0x2f, 0xa8, 0x9a, 0xe3, 0x2a, 0xd6, - 0x99, 0x07, 0x50, 0x4d, 0x68, 0x85, 0xb5, 0xbd, 0x72, 0xc8, 0x23, 0xd4, 0xc7, 0x0d, - 0x5e, 0xd4, 0x5c, 0xb0, 0x0c, 0x3e, 0x04, 0x05, 0x89, 0x2c, 0x88, 0x83, 0x74, 0x53, - 0xfe, 0xf2, 0xef, 0xb7, 0x51, 0x37, 0xf3, 0xc2, 0xab, 0xbc, 0x35, 0x47, 0xdf, 0x86, - 0xee, 0x01, 0x36, 0xb6, 0xe8, 0x5f, 0x33, 0xc5, 0x25, 0x58, 0x3f, 0xfe, 0x27, 0xe6, - 0xff, 0x48, 0xa8, 0x0d, 0x12, 0x4e, 0xf8, 0x01, 0xd3, 0x24, 0x75, 0x4e, 0x16, 0x1d, - 0x8b, 0xd6, 0x77, 0x44, 0xdf, 0x8a, 0xc5, 0x84, 0x9b, 0x65, 0x5a, 0xcf, 0x9f, 0xa7, - 0xb2, 0xea, 0x84, 0x62, 0x1d, 0x8e, 0x4d, 0xd8, 0x57, 0x6d, 0xa7, 0x5e, 0xd1, 0xb4, - 0x8a, 0xcb, 0x91, 0x08, 0x03, 0x27, 0x3e, 0x48, 0x37, 0x73, 0xa9, 0x9d, 0x58, 0xcb, - 0x70, 0x40, 0x8f, 0x3f, 0x23, 0xa3, 0xea, 0x71, 0xd6, 0x73, 0x23, 0xb8, 0xf9, 0xfd, - 0x51, 0x93, 0xb8, 0xdb, 0x90, 0x6a, 0x18, 0x86, 0xe4, 0x26, 0xd0, 0xd3, 0x21, 0x6e, - 0x7f, 0x0f, 0x42, 0xa9, 0xaa, 0xe0, 0x0f, 0xc3, 0x79, 0x12, 0x20, 0xdb, 0xb1, 0x03, - 0x15, 0x19, 0xbc, 0x1e, 0xcc, 0xf8, 0x29, 0x8a, 0x22, 0xab, 0x20, 0x92, 0x71, 0x65, - 0xaa, 0x95, 0xd5, 0x46, 0x88, 0x83, 0x48, 0x17, 0x58, 0x3c, 0x64, 0x90, 0x28, 0x77, - 0x34, 0xea, 0x30, 0x0c, 0x38, 0x94, 0xf9, 0x9b, 0xaa, 0x29, 0xee, 0x97, 0x50, 0x9d, - 0x1c, 0x10, 0x71, 0xf2, 0x17, 0x42, 0xba, 0x67, 0x13, 0xed, 0xa0, 0x20, 0x38, 0x1e, - 0x60, 0x98, 0xb0, 0x5a, 0xde, 0x28, 0x09, 0x63, 0xb3, 0x98, 0xc0, 0x3b, 0xf4, 0xc4, - 0xe1, 0xf1, 0x9a, 0xd1, 0xad, 0xf1, 0xf0, 0xd6, 0x1f, 0xac, 0xbf, 0x99, 0x66, 0xbd, - 0xb0, 0x1f, 0xd1, 0x84, 0xb2, 0x00, 0xf8, 0x66, 0xc5, 0xd1, 0x2e, 0x3d, 0xc5, 0x7e, - 0xcf, 0x4f, 0xcd, 0x60, 0xc4, 0xa7, 0x56, 0x19, 0x1d, 0xcf, 0x50, 0xbb, 0x0f, 0x97, - 0x6f, 0x00, 0xe4, 0x36, 0x36, 0xa6, 0x83, 0x08, 0x69, 0x2f, 0x40, 0x24, 0x4c, 0x39, - 0x15, 0x34, 0x4b, 0x6f, 0x1f, 0x5e, 0xe7, 0x0e, 0x51, 0xe1, 0x2b, 0x28, 0x53, 0x85, - 0x53, 0x40, 0x3b, 0xe1, 0x49, 0x8e, 0x00, 0x75, 0xdb, 0xda, 0x3e, 0x66, 0x6d, 0x9e, - 0xbd, 0x18, 0xa1, 0x27, 0x21, 0xc9, 0x73, 0x49, 0xac, 0x10, 0xe8, 0xfa, 0x2d, 0x6a, - 0x59, 0xb2, 0x23, 0x56, 0xa7, 0x71, 0x96, 0x18, 0xaa, 0xb5, 0xc7, 0x57, 0xf8, 0x82, - 0x1e, 0xfc, 0x3e, 0x07, 0x1b, 0x75, 0xf2, 0x15, 0xb2, 0x00, 0xb7, 0xd2, 0x99, 0x98, - 0xed, 0x7a, 0xe0, 0x05, 0x7f, 0xb2, 0x32, 0x9c, 0xa9, 0x13, 0x6d, 0xd2, 0xbc, 0x51, - 0xa6, 0x59, 0x01, 0x71, 0xdf, 0xca, 0x3b, 0xcb, 0x93, 0x6b, 0x11, 0xc6, 0x3c, 0x03, - 0xbb, 0x7f, 0xce, 0x30, 0xa0, 0x5f, 0x9b, 0x6f, 0x8f, 0xf3, 0x54, 0x06, 0x04, 0x50, - 0xa3, 0x45, 0x2d, 0xa1, 0x86, 0xe9, 0x3d, 0x6c, 0x32, 0xda, 0x62, 0x72, 0xb8, 0x9b, - 0xc4, 0xd6, 0xd5, 0xe8, 0x47, 0x8f, 0x29, 0x91, 0x01, 0x98, 0x97, 0x11, 0xa9, 0xd2, - 0x20, 0x97, 0xcd, 0xb7, 0x0c, 0x15, 0x0e, 0xd2, 0x6d, 0xf4, 0x7b, 0x0c, 0xdd, 0xee, - 0x52, 0x1b, 0x4f, 0x1e, 0x98, 0x96, 0xa1, 0xb6, 0x97, 0x86, 0x53, 0xa4, 0xe3, 0x8b, - 0x0d, 0x28, 0x52, 0x6e, 0x1e, 0x3a, 0x87, 0x43, 0x5a, 0xc4, 0xfd, 0x30, 0x97, 0xaf, - 0xe3, 0x21, 0xe7, 0x2d, 0x40, 0xc4, 0x70, 0xf3, 0xb5, 0x3f, 0x5c, 0x35, 0x8d, 0x2e, - 0x53, 0x69, 0x7c, 0xaf, 0x66, 0x9d, 0xea, 0xa1, 0x1d, 0xe7, 0x7c, 0x98, 0x4a, 0x73, - 0x0e, 0x5b, 0xf7, 0xb3, 0x8e, 0xf6, 0x58, 0x9a, 0x5a, 0xa7, 0x55, 0x81, 0xbf, 0xd3, - 0xc0, 0x07, 0x8a, 0x63, 0xa3, 0x92, 0x96, 0x0e, 0xc3, 0xf2, 0xa0, 0x5c, 0x08, 0x1a, - 0x48, 0x4e, 0xb4, 0xf4, 0x25, 0xb7, 0x08, 0x36, 0x0f, 0x82, 0x85, 0x3c, 0xfd, 0x50, - 0xa0, 0x27, 0xfa, 0x92, 0x51, 0x76, 0x86, 0x96, 0xf3, 0x73, 0x5c, 0xd9, 0xed, 0xf7, - 0x9e, 0xcd, 0x4b, 0xe0, 0x8c, 0x57, 0x85, 0xc8, 0xae, 0xe7, 0x9a, 0x13, 0x23, 0x87, - 0x09, 0x94, 0x2f, 0x2c, 0xfd, 0x0f, 0x80, 0x7d, 0xaa, 0xb5, 0x0c, 0xc6, 0x13, 0x1b, - 0xab, 0x91, 0x25, 0x67, 0x36, 0x27, 0xf5, 0xe9, 0xa3, 0xd5, 0x3d, 0x99, 0xfa, 0x02, - 0x5c, 0x39, 0xfa, 0xb0, 0x9e, 0x2a, 0x21, 0x34, 0x6d, 0xc7, 0xf8, 0x60, 0xa6, 0x2d, - 0xd2, 0x10, 0x8e, 0x04, 0x41, 0x17, 0x8e, 0xf9, 0x76, 0x21, 0xae, 0xfc, 0xe8, 0x97, - 0x28, 0x10, 0xa4, 0xc7, 0xfc, 0x1b, 0x3c, 0x7e, 0xaa, 0x83, 0xd4, 0xa6, 0x2b, 0xd7, - 0x10, 0x98, 0x96, 0x11, 0xdd, 0x7e, 0x2f, 0x4b, 0xdf, 0x15, 0xd8, 0x31, 0x00, 0x60, - 0x11, 0xb4, 0x4e, 0xd9, 0x59, 0xdc, 0x61, 0xd8, 0xde, 0x52, 0x74, 0x5e, 0x30, 0x67, - 0x9c, 0xef, 0x04, 0x01, 0x3a, 0xc6, 0x15, 0x4e, 0xf0, 0x64, 0x69, 0x82, 0x38, 0x74, - 0x25, 0x21, 0x62, 0x26, 0x3f, 0x3a, 0x4b, 0xa5, 0x65, 0x7b, 0x8d, 0x0e, 0xcf, 0x03, - 0x86, 0x44, 0x1f, 0x87, 0x30, 0xd0, 0xf1, 0x4e, 0x86, 0x8a, 0x32, 0x46, 0x37, 0xb0, - 0xd3, 0x4a, 0x9d, 0x1d, 0xd6, 0xc3, 0x9f, 0x28, 0xfd, 0x9a, 0xf3, 0x50, 0xdc, 0x23, - 0x93, 0x79, 0x29, 0xe3, 0x79, 0x70, 0xf8, 0x87, 0x37, 0x01, 0xd3, 0xfa, 0x47, 0x10, - 0x10, 0xa7, 0x21, 0x40, 0x68, 0xad, 0x1b, 0x89, 0x02, 0x52, 0x26, 0x1d, 0xd9, 0x0d, - 0x89, 0xc5, 0xa6, 0xf2, 0x90, 0x4b, 0xc6, 0x16, 0xb0, 0x27, 0xd7, 0xbe, 0xc8, 0x79, - 0xb7, 0xa1, 0x78, 0x25, 0x4f, 0xdc, 0xaa, 0x99, 0x1b, 0x42, 0x2b, 0x7a, 0x96, 0x93, - 0xe7, 0x64, 0xa1, 0x27, 0xb1, 0x72, 0xa0, 0xdc, 0xca, 0xc4, 0x4f, 0x15, 0x27, 0x08, - 0x6c, 0x48, 0x89, 0x85, 0xf9, 0x23, 0x5e, 0x28, 0x82, 0xb4, 0x78, 0x16, 0x44, 0xeb, - 0xa9, 0xed, 0x09, 0x61, 0xca, 0x7a, 0x68, 0x45, 0xb5, 0x73, 0x65, 0xd8, 0x75, 0x4b, - 0xdc, 0x79, 0x1f, 0x81, 0xc8, 0x09, 0xd0, 0x12, 0xbd, 0x32, 0x9b, 0x6a, 0x44, 0xbd, - 0x3d, 0xfa, 0x34, 0x73, 0x5c, 0xe4, 0xc7, 0x38, 0xed, 0xef, 0xa4, 0x2d, 0x3c, 0x74, - 0x09, 0x2b, 0x5c, 0xba, 0x9c, 0x35, 0x81, 0x57, 0xd2, 0xab, 0x8a, 0x68, 0x83, 0x04, - 0x0f, 0x40, 0xce, 0xc7, 0x98, 0xa6, 0x9d, 0x7e, 0x0e, 0xa3, 0xb4, 0x76, 0xd9, 0x93, - 0xd6, 0x96, 0xdb, 0x0a, 0xdd, 0xd5, 0x43, 0x3f, 0x9e, 0x7a, 0x0f, 0xfb, 0xe0, 0x24, - 0x26, 0x1e, 0x79, 0x8d, 0xad, 0x05, 0x8e, 0xc8, 0xde, 0x26, 0x7c, 0x94, 0x78, 0xc8, - 0x01, 0xff, 0x37, 0x1e, 0x41, 0xc0, 0xbc, 0x0c, 0xf4, 0x6a, 0x4a, 0x84, 0xd0, 0xac, - 0xa4, 0x73, 0xe8, 0x80, 0xde, 0x96, 0x29, 0x69, 0xe9, 0xde, 0x23, 0x99, 0xa2, 0x99, - 0x56, 0x80, 0xdd, 0x76, 0x8f, 0xd7, 0x6b, 0xc6, 0x89, 0x6f, 0xe0, 0x2a, 0xa4, 0x82, - 0xf7, 0x6c, 0x72, 0x52, 0xe6, 0x65, 0x04, 0xe8, 0x80, 0xd2, 0x76, 0xbf, 0x7d, 0x55, - 0x7b, 0x39, 0x6a, 0xde, 0x3b, 0xb4, 0x7a, 0x6b, 0x0e, 0x0d, 0xcf, 0x06, 0x3b, 0x1a, - 0xd8, 0x56, 0x69, 0x4f, 0x8e, 0xef, 0x54, 0xca, 0x7d, 0xf4, 0x2b, 0x41, 0xf9, 0xc6, - 0x15, 0x3e, 0xa7, 0x47, 0x1c, 0xd5, 0x4f, 0x90, 0x54, 0x7c, 0xc4, 0xd4, 0xef, 0x5f, - 0xb1, 0xbf, 0xe5, 0x82, 0x88, 0x22, 0x59, 0xc7, 0x77, 0xef, 0xc4, 0xeb, 0x8f, 0x5d, - 0x75, 0x53, 0x1c, 0x1b, 0x80, 0x1b, 0x72, 0x12, 0xc6, 0xf1, 0x45, 0x09, 0x78, 0x40, - 0x20, 0xcb, 0xc3, 0xb0, 0x0e, 0xb5, 0x31, 0xc5, 0x62, 0x44, 0x36, 0x89, 0x28, 0xa8, - 0x51, 0xae, 0x53, 0x7c, 0x74, 0x80, 0xee, 0x6e, 0x45, 0x1b, 0x29, 0x74, 0x32, 0xee, - 0x17, 0x58, 0x22, 0x99, 0x50, 0xcf, 0x78, 0x08, 0x49, 0x32, 0x6c, 0x3f, 0x28, 0xdd, - 0x53, 0xd6, 0x81, 0x19, 0xd2, 0x96, 0x95, 0x50, 0x12, 0xa2, 0x6f, 0x83, 0x3c, 0xdd, - 0x29, 0xc6, 0xf4, 0xc7, 0x16, 0xf1, 0xd3, 0x37, 0xd3, 0xf4, 0xd2, 0x1c, 0x7a, 0x63, - 0xf8, 0x54, 0xc9, 0xf4, 0xc1, 0xc4, 0xcc, 0xf1, 0x81, 0xad, 0x43, 0x16, 0xca, 0xb1, - 0x36, 0x46, 0x7c, 0x01, 0xd9, 0x6d, 0x36, 0xe2, 0x98, 0x1c, 0x86, 0xc4, 0x76, 0x56, - 0x7d, 0x83, 0x77, 0x6b, 0x73, 0x37, 0x35, 0xd5, 0x65, 0x8a, 0x48, 0xf9, 0x89, 0x7c, - 0xf1, 0xe5, 0x05, 0x2b, 0x37, 0xec, 0x1c, 0x88, 0x91, 0x47, 0x36, 0xd9, 0xf9, 0x7c, - 0x54, 0x99, 0xd7, 0x3d, 0x92, 0x3b, 0x45, 0x00, 0x69, 0x4f, 0xfa, 0x57, 0x35, 0xc9, - 0x3c, 0xdb, 0x87, 0xb3, 0x5d, 0x82, 0x95, 0x49, 0xb1, 0xc6, 0x38, 0x3e, 0x95, 0xfd, - 0x19, 0x02, 0xad, 0x29, 0x80, 0xf2, 0xa3, 0xa2, 0x48, 0x3a, 0xce, 0x74, 0xb7, 0x64, - 0x3d, 0x8e, 0xae, 0x8d, 0x07, 0x9a, 0xa0, 0x06, 0x75, 0x41, 0x00, 0x6b, 0x94, 0xa6, - 0xf9, 0x13, 0xdc, 0xff, 0x13, 0xd6, 0x7c, 0xd9, 0xa8, 0xcf, 0xdf, 0x30, 0xb0, 0xc3, - 0xd1, 0x5a, 0xaa, 0x47, 0x0b, 0x3f, 0x89, 0x56, 0x10, 0x51, 0x42, 0xfa, 0x26, 0x11, - 0xfe, 0xda, 0xa4, 0x3f, 0xac, 0xbb, 0x3f, 0x05, 0x96, 0xf6, 0x78, 0x87, 0xcd, 0xee, - 0x91, 0x42, 0xc5, 0x09, 0x0a, 0x84, 0xe6, 0x25, 0x29, 0x31, 0xff, 0xcf, 0x61, 0xa5, - 0x0a, 0x4b, 0x92, 0x85, 0x30, 0x60, 0xe8, 0xb8, 0x7e, 0x10, 0xce, 0xa8, 0xce, 0x00, - 0xe4, 0x66, 0x5e, 0x5f, 0x93, 0x1f, 0x0e, 0x08, 0xdc, 0x52, 0x47, 0xbe, 0x1a, 0xed, - 0xc7, 0x9e, 0xbb, 0x7c, 0x20, 0x16, 0x2f, 0xca, 0x7b, 0xf9, 0x0e, 0x58, 0x83, 0x02, - 0x5f, 0xc9, 0x24, 0x36, 0x8d, 0x42, 0x45, 0x0b, 0x4f, 0xb7, 0xa7, 0xe1, 0x91, 0x0e, - 0xdd, 0x8d, 0x29, 0x5f, 0x03, 0xd4, 0xde, 0x03, 0xde, 0x60, 0x51, 0xd1, 0xfc, 0xf2, - 0x87, 0xf5, 0x4f, 0x38, 0x24, 0x41, 0xdd, 0xe0, 0x0c, 0xb6, 0x83, 0xa4, 0x04, 0x8c, - 0xe5, 0x4d, 0x42, 0x20, 0x90, 0x57, 0x24, 0xb3, 0x09, 0xc7, 0x99, 0x92, 0x4b, 0x85, - 0x4a, 0xfa, 0x37, 0x7b, 0x80, 0x1a, 0x03, 0x52, 0xfc, 0x44, 0x50, 0xb3, 0x35, 0x27, - 0x7a, 0xda, 0xd7, 0x61, 0xe4, 0x8a, 0x1d, 0x1d, 0xd3, 0x78, 0x93, 0x6a, 0x49, 0x1e, - 0x28, 0x6c, 0xaf, 0xc7, 0x00, 0xb4, 0x8e, 0xdf, 0x15, 0xf1, 0xc2, 0xd6, 0xed, 0xf1, - 0xa2, 0x4e, 0x0e, 0x51, 0xb3, 0x98, 0x55, 0x64, 0xeb, 0xa9, 0x69, 0xcd, 0x6e, 0xe6, - 0x59, 0xba, 0xae, 0xf7, 0x46, 0xe1, 0x3a, 0xba, 0x64, 0xaf, 0xad, 0x58, 0xaf, 0x52, - 0xf4, 0x28, 0x17, 0x36, 0x45, 0x75, 0x7a, 0x40, 0x7e, 0x1f, 0xdf, 0xd9, 0x89, 0x38, - 0x0c, 0x02, 0xbc, 0xc3, 0xc3, 0x7f, 0x48, 0x90, 0xc0, 0x8e, 0xb9, 0x31, 0x62, 0xcf, - 0x78, 0xbc, 0x3c, 0x74, 0x53, 0xf3, 0xf9, 0x92, 0xa7, 0x94, 0x53, 0x4c, 0x07, 0xe3, - 0x96, 0x8d, 0x82, 0x70, 0xaa, 0x19, 0x1f, 0x67, 0x80, 0x0a, 0x0b, 0xb3, 0xe7, 0xbf, - 0xa5, 0x4b, 0x0f, 0x6f, 0xa5, 0x3e, 0xe8, 0xfb, 0x13, 0x69, 0x82, 0xce, 0x71, 0xf4, - 0x08, 0x64, 0xb5, 0x4d, 0x00, 0x45, 0x1a, 0xf3, 0xf5, 0x32, 0x74, 0x22, 0x42, 0x16, - 0x06, 0xea, 0x10, 0xc0, 0xd6, 0x12, 0x7c, 0x02, 0xf9, 0x1a, 0xd3, 0xae, 0xb9, 0xff, - 0xd6, 0x11, 0x12, 0x25, 0x14, 0x14, 0x48, 0xbe, 0x82, 0x40, 0xc4, 0x29, 0x73, 0xac, - 0x52, 0xd7, 0x1b, 0x01, 0x2f, 0xe8, 0xef, 0x41, 0xf0, 0x0e, 0xc1, 0x96, 0xc7, 0x57, - 0x89, 0x9e, 0xf8, 0xc0, 0x0e, 0xf8, 0xdf, 0x44, 0x5c, 0x56, 0x54, 0x69, 0xd8, 0x4b, - 0xd0, 0x2c, 0x7f, 0xc4, 0x1b, 0xfc, 0xdf, 0x98, 0x95, 0x1f, 0x50, 0xe8, 0x3f, 0x19, - 0xa0, 0x00, 0xa9, 0xe4, 0x53, 0xf6, 0x21, 0x67, 0xe7, 0x35, 0x0f, 0x92, 0x36, 0x08, - 0x31, 0xbd, 0x7c, 0x52, 0x22, 0xb6, 0x70, 0x61, 0x6e, 0x4b, 0x6c, 0xa8, 0xa2, 0x35, - 0x50, 0xca, 0xd8, 0xac, 0x0d, 0xdb, 0x76, 0x45, 0xe2, 0xb9, 0x71, 0x3b, 0xe7, - ], - script_code: Script(vec![0x6a, 0x00, 0x00, 0x65, 0x53, 0xac, 0x63, 0x53, 0x63]), - transparent_input: None, - hash_type: 1, - amount: 1871432121379810, - consensus_branch_id: consensus::BranchId::Sapling, - sighash: [ - 0x36, 0x77, 0xa9, 0x48, 0x4f, 0x04, 0x04, 0xfb, 0x50, 0x64, 0x58, 0x56, 0xf4, 0xd4, - 0xa7, 0x0b, 0x2e, 0x2b, 0x1c, 0x2d, 0x86, 0x2f, 0x1d, 0x4e, 0xf6, 0x8d, 0x52, 0x09, - 0x60, 0xa1, 0x2a, 0x2b, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0xa0, 0x1e, 0x64, 0x49, 0xae, - 0x43, 0x5c, 0x24, 0xbe, 0x7b, 0x9d, 0x28, 0x8a, 0xd7, 0x57, 0x12, 0xc9, 0x2a, 0xa5, - 0x06, 0x18, 0xdf, 0xba, 0x18, 0xe8, 0x4e, 0x88, 0xd4, 0x60, 0x68, 0xdf, 0x0b, 0x42, - 0xaf, 0x89, 0x29, 0x07, 0x00, 0x6a, 0x52, 0xac, 0x65, 0x51, 0x63, 0x6e, 0x99, 0x51, - 0xd0, 0x09, 0xa9, 0x39, 0xf7, 0x59, 0xa8, 0xa2, 0xc0, 0x49, 0xde, 0xf0, 0x97, 0x7f, - 0x61, 0xea, 0x11, 0x23, 0x14, 0x06, 0xcd, 0x10, 0x95, 0x6d, 0x16, 0x55, 0x78, 0xbb, - 0x29, 0xe4, 0x76, 0x96, 0x76, 0x9a, 0x58, 0x0e, 0x07, 0x01, 0x00, 0x15, 0xaf, 0x3b, - 0x50, 0x00, 0x13, 0x58, 0xd0, 0x37, 0xe5, 0x70, 0xfe, 0x0b, 0x50, 0x0e, 0xe2, 0x99, - 0x8c, 0xdf, 0x06, 0x00, 0x03, 0x7e, 0x28, 0x30, 0x34, 0x34, 0x96, 0x2f, 0x03, 0x92, - 0x48, 0x3d, 0xec, 0xad, 0x2f, 0x9f, 0x4e, 0xbc, 0x99, 0x05, 0x4b, 0xbc, 0xf1, 0x55, - 0xff, 0xae, 0x67, 0x76, 0x34, 0xc3, 0xfb, 0x98, 0x0d, 0xc5, 0xe8, 0xec, 0x67, 0xa4, - 0x65, 0x7e, 0x80, 0xa2, 0x9a, 0x79, 0x6f, 0x39, 0x62, 0xae, 0x0c, 0xb9, 0xc7, 0x86, - 0x82, 0xb3, 0xf4, 0xf9, 0x2e, 0x5a, 0x1e, 0xd1, 0xda, 0x2b, 0xbf, 0xc1, 0x71, 0x07, - 0x7e, 0xef, 0x83, 0x65, 0xbb, 0x38, 0xce, 0x94, 0xca, 0xb0, 0x28, 0x33, 0xce, 0x47, - 0xd4, 0xa0, 0x98, 0x65, 0x72, 0x94, 0xec, 0x10, 0xb2, 0x99, 0x74, 0x22, 0x22, 0xd0, - 0xbf, 0x74, 0x3f, 0x40, 0xc8, 0xea, 0x97, 0x14, 0x32, 0x5c, 0x8a, 0x37, 0x05, 0x08, - 0x24, 0xfa, 0x75, 0x62, 0xd2, 0xc9, 0x25, 0x2c, 0x34, 0xa9, 0x84, 0x50, 0x27, 0xd6, - 0x63, 0x90, 0xe9, 0x56, 0xb2, 0x5e, 0x16, 0x6c, 0x44, 0x95, 0xd3, 0xde, 0xd3, 0xf7, - 0xac, 0xcf, 0x74, 0x76, 0x38, 0x99, 0x47, 0x35, 0x11, 0x34, 0x12, 0x98, 0xfe, 0xb1, - 0x89, 0xb7, 0xed, 0x34, 0xe5, 0x67, 0xd7, 0x2f, 0x1d, 0xf4, 0xbf, 0x69, 0x7f, 0x71, - 0x46, 0x49, 0x3f, 0xa5, 0xc2, 0x36, 0x91, 0x22, 0x7b, 0x90, 0xb2, 0x51, 0x22, 0xc5, - 0x40, 0xdf, 0x0a, 0x6f, 0x2e, 0xc0, 0x6f, 0x9d, 0x89, 0xa3, 0xf7, 0x71, 0xe9, 0xb8, - 0xed, 0x74, 0x79, 0x40, 0x85, 0x51, 0x06, 0xd5, 0xea, 0x71, 0xba, 0x89, 0xe8, 0xf2, - 0x0c, 0xde, 0xa6, 0x9a, 0x77, 0x8a, 0x59, 0xe4, 0xdf, 0x79, 0x28, 0xc0, 0x35, 0x56, - 0x23, 0x31, 0xc8, 0xe1, 0x62, 0xb8, 0xfd, 0x5e, 0xbb, 0xd5, 0xe2, 0xb3, 0x7b, 0xea, - 0x7a, 0xf0, 0x69, 0x07, 0x10, 0x40, 0xc3, 0x7c, 0x1a, 0x1c, 0x37, 0xf0, 0x76, 0x0f, - 0xed, 0x7d, 0xb7, 0xfa, 0x70, 0xa9, 0x48, 0x94, 0x03, 0x00, 0x45, 0x76, 0xa2, 0xcc, - 0xe9, 0x0a, 0x39, 0x4b, 0x5e, 0xc5, 0x8b, 0x2e, 0x5d, 0x0e, 0x1a, 0xf8, 0xb0, 0x29, - 0x6d, 0x0b, 0xf0, 0x2c, 0x55, 0x97, 0xa4, 0x33, 0x54, 0x14, 0x43, 0x35, 0xe0, 0x6a, - 0x80, 0x1c, 0x6e, 0x7c, 0x73, 0x29, 0x7d, 0xfe, 0x0b, 0x32, 0xfc, 0xb8, 0x75, 0x33, - 0x81, 0x71, 0xdd, 0x1e, 0xeb, 0xeb, 0x12, 0x3f, 0xea, 0xfa, 0x32, 0xa5, 0xd8, 0xc7, - 0xce, 0x58, 0x39, 0x0e, 0xa2, 0xdf, 0x26, 0xc6, 0x88, 0x88, 0xda, 0xf3, 0x81, 0x6b, - 0x7d, 0x02, 0x97, 0xa1, 0x7b, 0x5f, 0x5d, 0x20, 0x8d, 0xe9, 0x22, 0xe7, 0x73, 0x97, - 0x2b, 0x95, 0xe6, 0x96, 0x5e, 0x58, 0xfb, 0xf6, 0x4f, 0xae, 0x06, 0xf0, 0xc3, 0x89, - 0x6e, 0x0b, 0x57, 0x89, 0x0d, 0xd7, 0xf3, 0xc6, 0x4c, 0x3d, 0x5c, 0xeb, 0xb6, 0xa7, - 0x44, 0xc5, 0x93, 0x38, 0x61, 0x22, 0x71, 0x82, 0x08, 0x04, 0x95, 0xce, 0x9a, 0xc2, - 0xe1, 0x73, 0x09, 0x9c, 0xdc, 0x35, 0x8d, 0xa8, 0x7d, 0xd7, 0x4a, 0x77, 0x34, 0xff, - 0xff, 0xc4, 0x5f, 0xb6, 0xad, 0x1f, 0x38, 0x9c, 0x6a, 0x4d, 0x49, 0x86, 0x62, 0x64, - 0x60, 0x56, 0x08, 0x4d, 0x09, 0xb7, 0x84, 0x88, 0xa3, 0xba, 0x1d, 0x8a, 0x3d, 0x6b, - 0x48, 0x9a, 0xfd, 0xf2, 0x32, 0xd6, 0xd0, 0x70, 0xa1, 0xb5, 0x06, 0x0c, 0xaa, 0x44, - 0x3d, 0x0c, 0x7e, 0xe5, 0x19, 0x04, 0x54, 0x7f, 0xaf, 0x53, 0x95, 0xcb, 0xd0, 0xba, - 0x99, 0x48, 0x0a, 0xd0, 0x4a, 0xe0, 0xe1, 0x91, 0x5b, 0xd7, 0x7f, 0xa2, 0x6d, 0x04, - 0x17, 0x5b, 0x00, 0xfd, 0xc8, 0x1e, 0xf6, 0xf3, 0x79, 0x23, 0x72, 0x49, 0x27, 0xf0, - 0x82, 0x66, 0xb6, 0x86, 0x40, 0x93, 0x13, 0xdc, 0x13, 0xbc, 0x39, 0x9d, 0x19, 0x77, - 0xb8, 0xf6, 0x58, 0x8c, 0x0e, 0x08, 0x72, 0x10, 0xf0, 0x51, 0xcf, 0x6e, 0x36, 0xe1, - 0x4e, 0x32, 0xaa, 0x23, 0xba, 0x6a, 0xe4, 0x33, 0x1f, 0x22, 0x39, 0xe7, 0x05, 0xf6, - 0x79, 0x54, 0x2f, 0xbd, 0x4e, 0xd2, 0xbf, 0x31, 0x91, 0x24, 0x36, 0x81, 0xf8, 0x27, - 0x89, 0x6b, 0x1b, 0xb1, 0xc4, 0xb7, 0x8b, 0x34, 0xc4, 0x87, 0xa4, 0xed, 0xfa, 0x97, - 0xd3, 0x6d, 0x62, 0xee, 0x32, 0x49, 0xef, 0xe0, 0x94, 0xc3, 0x87, 0x8a, 0xde, 0xdf, - 0x9f, 0x2b, 0x17, 0xd5, 0x11, 0x99, 0x80, 0x4f, 0x42, 0x9c, 0xd7, 0x04, 0xa7, 0xc8, - 0x6c, 0x85, 0x0c, 0xe1, 0x5d, 0x3c, 0x5f, 0x01, 0xd1, 0xad, 0x17, 0xeb, 0xb6, 0xc2, - 0x88, 0x3f, 0x28, 0xe8, 0x15, 0xbc, 0x45, 0x2a, 0x56, 0x07, 0x98, 0x05, 0xa5, 0xdd, - 0x69, 0x00, 0xe5, 0x5f, 0x47, 0x7e, 0xca, 0xc2, 0x14, 0x3f, 0x02, 0xee, 0x98, 0xc8, - 0xd9, 0xb1, 0xb7, 0x03, 0x93, 0xa1, 0x70, 0xba, 0x25, 0x48, 0x06, 0xb4, 0x08, 0x5b, - 0x8d, 0xf9, 0xca, 0x04, 0x07, 0x18, 0x42, 0xa3, 0xaf, 0x93, 0x33, 0x16, 0x83, 0x0d, - 0x53, 0xa7, 0xcb, 0x88, 0xd2, 0xa9, 0x82, 0x3b, 0xcd, 0xfb, 0xec, 0x8f, 0x18, 0xc8, - 0x6a, 0xc3, 0xdf, 0x89, 0x42, 0x38, 0x00, 0x1b, 0xa8, 0xfa, 0x31, 0x3f, 0x80, 0xcf, - 0xe7, 0x5f, 0x7c, 0xb5, 0xd9, 0x73, 0xcc, 0x77, 0xf3, 0x21, 0xf1, 0x95, 0x2f, 0x30, - 0x50, 0x18, 0xc0, 0xbf, 0x23, 0x8b, 0x80, 0xe3, 0x21, 0x19, 0x90, 0x60, 0x66, 0xf6, - 0x4e, 0x64, 0x5e, 0x2b, 0xca, 0xd7, 0xe4, 0xcd, 0xbe, 0xf0, 0x07, 0xf7, 0xe9, 0xad, - 0x8a, 0x31, 0x83, 0x8b, 0x9e, 0xae, 0xc3, 0x85, 0xe3, 0xf2, 0x5e, 0x16, 0x04, 0xa6, - 0xd4, 0x64, 0x99, 0x87, 0x5a, 0xc1, 0x4a, 0x6c, 0xb3, 0x55, 0xa3, 0xd4, 0x32, 0x91, - 0x45, 0x80, 0x3c, 0x6b, 0xfb, 0x82, 0xe2, 0x9a, 0xb0, 0x29, 0x9f, 0x91, 0x7a, 0x74, - 0x02, 0x81, 0x57, 0x71, 0x7c, 0x08, 0x48, 0x68, 0x63, 0x94, 0x5c, 0x5a, 0x02, 0x36, - 0x58, 0xee, 0xe4, 0xa8, 0xb2, 0x89, 0x56, 0x4c, 0x22, 0xa9, 0x67, 0x1c, 0x56, 0x91, - 0x33, 0x5e, 0xb1, 0x25, 0x89, 0x88, 0x51, 0x67, 0x8f, 0x54, 0x93, 0x45, 0x10, 0xbf, - 0x30, 0x91, 0xc6, 0x02, 0xe1, 0x2a, 0x32, 0x03, 0xa2, 0xf3, 0x2f, 0x34, 0x7d, 0x4b, - 0xdc, 0x9d, 0x44, 0x92, 0x4d, 0xc8, 0x67, 0x5c, 0x9f, 0x24, 0x06, 0x4d, 0x35, 0xb0, - 0x09, 0xb6, 0xdd, 0xbd, 0xb2, 0x37, 0x20, 0x75, 0x33, 0xd5, 0xbb, 0xad, 0x3b, 0xa1, - 0xa3, 0xd6, 0xb0, 0x89, 0x32, 0x9b, 0xe1, 0x47, 0x23, 0x4e, 0x75, 0x1a, 0x49, 0x27, - 0x9d, 0x74, 0xdb, 0x88, 0xdb, 0x5c, 0xa1, 0x02, 0xd5, 0xe0, 0xe1, 0xaa, 0xc7, 0xcc, - 0xf9, 0x66, 0xb0, 0xa8, 0x13, 0x67, 0x09, 0x5d, 0xa2, 0x1d, 0xc4, 0xb7, 0x36, 0x55, - 0x95, 0x30, 0x80, 0xe3, 0x54, 0xbd, 0x22, 0x09, 0xf2, 0x66, 0x82, 0x10, 0xe9, 0x47, - 0x41, 0x27, 0x31, 0x1d, 0x93, 0x45, 0xce, 0x1e, 0xbd, 0x3a, 0xe5, 0x24, 0x24, 0x5b, - 0xbb, 0x44, 0x7a, 0x44, 0x50, 0x80, 0xb5, 0xfa, 0x23, 0xcd, 0xfe, 0x98, 0xb3, 0xf6, - 0xf6, 0x3c, 0x44, 0xeb, 0xe7, 0x22, 0xb9, 0x7a, 0x79, 0x10, 0xdf, 0x7e, 0xa6, 0x22, - 0x5e, 0xd9, 0xdc, 0xb4, 0x49, 0x84, 0x93, 0xe8, 0xef, 0x55, 0x31, 0xf9, 0xf9, 0x77, - 0x31, 0x84, 0xd7, 0xb4, 0xf5, 0x36, 0x77, 0xb1, 0xd0, 0x44, 0xf6, 0xf1, 0x44, 0x07, - 0xde, 0x5d, 0x67, 0xe0, 0x77, 0xd2, 0x0f, 0x2e, 0x9d, 0x7f, 0xd7, 0x15, 0xbf, 0x9b, - 0x19, 0x9b, 0x93, 0xb9, 0x84, 0x02, 0x46, 0xef, 0x9c, 0x07, 0x35, 0xe4, 0x88, 0xff, - 0x7c, 0x80, 0xb9, 0x41, 0x78, 0xac, 0xa3, 0x1b, 0x13, 0xc3, 0x7c, 0x9a, 0xeb, 0x7f, - 0x62, 0xe2, 0xd8, 0x58, 0x97, 0xea, 0x2e, 0x2a, 0x23, 0x28, 0xee, 0x03, 0xc9, 0x7f, - 0x2f, 0x3f, 0x4d, 0x20, 0xa8, 0xe7, 0x30, 0x24, 0xc5, 0x50, 0x8e, 0xee, 0xbd, 0x3a, - 0x12, 0x67, 0x31, 0xcd, 0xbf, 0x21, 0xfd, 0xad, 0xb1, 0x4b, 0x4e, 0x59, 0x1c, 0xba, - 0xb1, 0x44, 0xbe, 0xc3, 0x5a, 0x72, 0xac, 0xbf, 0x94, 0x84, 0xf4, 0x7a, 0x10, 0xb9, - 0x1e, 0xfc, 0x04, 0x27, 0xfe, 0xcf, 0x3f, 0xfc, 0xf1, 0x69, 0xd7, 0x00, 0x59, 0xb4, - 0x02, 0x79, 0xff, 0xa0, 0x2c, 0x51, 0x06, 0x74, 0x27, 0xa0, 0xda, 0xea, 0xd6, 0xf9, - 0x4b, 0xaf, 0xe4, 0xc1, 0x23, 0x3a, 0x22, 0x25, 0xeb, 0x56, 0x00, 0x3f, 0xc3, 0x85, - 0x42, 0x0d, 0x5a, 0x9f, 0xf3, 0xd5, 0x91, 0x55, 0x23, 0xa0, 0x8c, 0x87, 0xeb, 0x2e, - 0xa6, 0x69, 0x17, 0x23, 0x3a, 0x73, 0x25, 0xfe, 0x79, 0x3f, 0x41, 0x07, 0x6d, 0x64, - 0x25, 0x5a, 0xbd, 0x15, 0x21, 0x47, 0x66, 0x60, 0xe9, 0x04, 0x91, 0x60, 0x2c, 0x69, - 0xa4, 0xab, 0xb1, 0x38, 0x84, 0x43, 0x10, 0x72, 0xef, 0x96, 0xa0, 0x95, 0xbe, 0x41, - 0x1f, 0xfc, 0xff, 0xb7, 0x86, 0x3f, 0xef, 0x7d, 0xab, 0x4d, 0x4a, 0x72, 0xa2, 0xd0, - 0xbb, 0xd3, 0x6f, 0x9f, 0xdf, 0x0b, 0x35, 0x38, 0xb3, 0x9c, 0xae, 0x5f, 0xf6, 0x0e, - 0x5a, 0xc6, 0xb6, 0x09, 0x70, 0x72, 0x43, 0x14, 0x6e, 0xb5, 0x36, 0x0a, 0xe7, 0xf9, - 0x3f, 0x79, 0x9b, 0x6c, 0x27, 0xe6, 0x5a, 0x0a, 0x06, 0x39, 0x87, 0x38, 0x66, 0x0f, - 0xda, 0xd2, 0xcf, 0xb3, 0x1a, 0xa5, 0x40, 0xd5, 0xe8, 0x90, 0x06, 0x78, 0xb9, 0xda, - 0xb5, 0x24, 0x79, 0xbd, 0x0c, 0xd6, 0xf1, 0xa5, 0x98, 0x67, 0x3e, 0xed, 0x9c, 0x76, - 0xe3, 0x38, 0x10, 0x49, 0x47, 0x18, 0xd0, 0x5d, 0xdf, 0xdc, 0x00, 0x7a, 0x54, 0xbc, - 0xd1, 0xcc, 0x4c, 0x97, 0x40, 0xf7, 0xe5, 0x3a, 0x31, 0x68, 0x1d, 0x2b, 0x2c, 0x6e, - 0xde, 0x79, 0x28, 0x11, 0x49, 0xea, 0xc3, 0x0f, 0x6e, 0xe5, 0x83, 0x60, 0x5a, 0xc2, - 0xff, 0xae, 0xc1, 0x55, 0x00, 0x35, 0xdc, 0x5a, 0xbb, 0x35, 0x89, 0x44, 0x68, 0xf1, - 0x2d, 0x5d, 0x08, 0xd7, 0x34, 0x36, 0xa8, 0x59, 0xe5, 0x50, 0x7f, 0xdd, 0x1a, 0x46, - 0x38, 0xfb, 0xe6, 0x81, 0xb0, 0xa0, 0xef, 0xfb, 0xbb, 0xf7, 0x4c, 0x99, 0x39, 0x9d, - 0xca, 0x69, 0x02, 0xa0, 0x74, 0xc8, 0x33, 0x35, 0x60, 0x7a, 0x0c, 0x0d, 0xb0, 0x1c, - 0xa3, 0xca, 0x2f, 0xa8, 0x18, 0x57, 0x24, 0x02, 0xe2, 0xfa, 0xef, 0xb3, 0x07, 0xbe, - 0x22, 0xc7, 0xd5, 0x61, 0x1f, 0xf6, 0xfb, 0x5a, 0x31, 0xb4, 0x62, 0x16, 0x59, 0xd8, - 0x4d, 0x8a, 0x7a, 0x1a, 0xdc, 0xa2, 0xfc, 0x4e, 0xb8, 0xb8, 0x97, 0x04, 0x43, 0x93, - 0x27, 0x64, 0x46, 0x31, 0xa7, 0xbb, 0xc1, 0xa8, 0x41, 0xf3, 0x65, 0x83, 0x0d, 0x27, - 0xc8, 0xaa, 0x4d, 0x75, 0xc8, 0x07, 0x87, 0xbd, 0x10, 0xb7, 0x14, 0xcb, 0x97, 0x9c, - 0x1b, 0x0f, 0x3f, 0x0b, 0x41, 0xee, 0x94, 0x22, 0x94, 0x24, 0x8c, 0x48, 0x5c, 0xf9, - 0x9c, 0x6b, 0xc4, 0x63, 0x20, 0x7a, 0xf3, 0x83, 0x61, 0x97, 0x83, 0x57, 0x41, 0x41, - 0x5d, 0xe6, 0x1f, 0xf2, 0x9f, 0xad, 0x30, 0x01, 0x82, 0x71, 0x4c, 0x20, 0xca, 0x34, - 0x04, 0x7b, 0xcc, 0xb7, 0x05, 0x81, 0x0f, 0xfa, 0xe5, 0x3a, 0x34, 0x16, 0xa5, 0x3f, - 0x28, 0xaf, 0xc0, 0x08, 0xe8, 0xbf, 0xf9, 0x49, 0xe4, 0x3a, 0x54, 0x10, 0xe6, 0xad, - 0xb6, 0x65, 0xf9, 0x9f, 0xa4, 0xca, 0xfa, 0xc2, 0xe0, 0xf2, 0xc0, 0xf1, 0x34, 0xbd, - 0xba, 0x83, 0x81, 0xc2, 0xbb, 0xac, 0x43, 0x33, 0x2a, 0xcd, 0xcb, 0x10, 0x08, 0x2e, - 0xf3, 0x43, 0xa3, 0x5a, 0xc6, 0x4f, 0x4b, 0xa1, 0x6e, 0x49, 0x57, 0xc7, 0x1e, 0x9a, - 0x2b, 0xd9, 0xa5, 0xcd, 0x6a, 0x92, 0x25, 0x8a, 0x9e, 0x58, 0x8e, 0x02, 0x1a, 0x06, - 0x65, 0x09, 0x04, 0x67, 0x0d, 0xa2, 0xc0, 0xe5, 0x2c, 0x52, 0x4f, 0x6e, 0x5c, 0xe3, - 0xee, 0x27, 0x5a, 0x0a, 0x63, 0x10, 0x3b, 0x5f, 0x92, 0x64, 0x16, 0xc0, 0xbd, 0x5d, - 0xa1, 0xae, 0x65, 0x69, 0xd3, 0xa4, 0xee, 0x4d, 0xbc, 0x5e, 0xc0, 0x8b, 0x29, 0x72, - 0x02, 0xc9, 0xd7, 0x13, 0xab, 0xc3, 0x47, 0x4d, 0xe4, 0x94, 0x0f, 0x59, 0xb1, 0xf3, - 0xfe, 0x0e, 0x92, 0x76, 0xa1, 0x76, 0x3b, 0x2d, 0xea, 0x39, 0x40, 0xb0, 0xc1, 0xf7, - 0xab, 0x5d, 0xa3, 0xf4, 0x55, 0x62, 0x3e, 0x04, 0x96, 0x82, 0xd0, 0x92, 0x18, 0x9c, - 0xb7, 0x9e, 0xcf, 0xd4, 0x3c, 0x3b, 0xf1, 0x0e, 0x7f, 0x2c, 0x8d, 0x4d, 0xe3, 0xa7, - 0x36, 0xf8, 0x69, 0xf0, 0x87, 0x03, 0xc4, 0xe5, 0x9f, 0x57, 0x4f, 0x77, 0xaa, 0x86, - 0x1c, 0xbf, 0xdd, 0xd0, 0x7f, 0x77, 0xdc, 0x24, 0xa9, 0x74, 0x10, 0xaf, 0xc7, 0xcf, - 0xbe, 0x3c, 0xe1, 0xff, 0xd2, 0x24, 0x53, 0x5c, 0xf3, 0x05, 0xce, 0xcc, 0x78, 0x56, - 0xa4, 0xd4, 0x8a, 0x6d, 0xec, 0x17, 0xa2, 0x4b, 0x6d, 0x27, 0xfe, 0x26, 0x64, 0xbc, - 0x2b, 0x2b, 0x71, 0x1d, 0x67, 0x13, 0x90, 0x6c, 0xed, 0x8a, 0x80, 0x66, 0x62, 0x18, - 0x40, 0xd9, 0x0c, 0x23, 0xae, 0x33, 0x77, 0x30, 0x67, 0x9d, 0x2c, 0xde, 0x32, 0x69, - 0xab, 0x1f, 0x42, 0xac, 0x03, 0xff, 0xdb, 0xa0, 0x32, 0xd3, 0x2c, 0xa8, 0x79, 0x63, - 0x82, 0x56, 0x56, 0x5d, 0xe1, 0xd2, 0xde, 0x39, 0xf5, 0x6f, 0x94, 0x57, 0x95, 0xd6, - 0xe9, 0x58, 0xe6, 0x93, 0xdc, 0x8c, 0xbf, 0x6d, 0x04, 0x30, 0x00, 0xcc, 0x7a, 0x40, - 0x15, 0xf0, 0x2d, 0x0f, 0xe3, 0x97, 0xec, 0x57, 0xf8, 0xfe, 0x29, 0x2e, 0x85, 0x14, - 0x24, 0xe8, 0x40, 0x6d, 0x38, 0xdd, 0xb8, 0xd1, 0xde, 0x9d, 0xef, 0x67, 0x2e, 0x92, - 0x7d, 0x3d, 0xc1, 0xf4, 0x11, 0xdc, 0x78, 0xad, 0xa7, 0x61, 0x00, 0x91, 0xbf, 0xe2, - 0x63, 0xcd, 0x79, 0x96, 0xd1, 0x80, 0x5e, 0xe4, 0x91, 0xe9, 0x95, 0x91, 0xd6, 0xef, - 0xdb, 0x2e, 0x3c, 0x79, 0x71, 0x57, 0x41, 0xd0, 0xd4, 0x72, 0xac, 0x11, 0xdb, 0x78, - 0x64, 0x4f, 0x3d, 0x23, 0xe5, 0x8f, 0x0b, 0x01, 0xa8, 0x61, 0xe0, 0x85, 0x65, 0x53, - 0x52, 0x07, 0xcd, 0x5e, 0x71, 0x0f, 0xc3, 0x3e, 0xb2, 0xf8, 0x92, 0x8b, 0xc7, 0xd4, - 0x01, 0x7e, 0x4e, 0x56, 0xc0, 0xc2, 0xeb, 0x95, 0x85, 0xd6, 0x99, 0x74, 0x5e, 0x3b, - 0xb9, 0x61, 0x8b, 0x2c, 0x1b, 0x90, 0xf2, 0x35, 0x1b, 0xaf, 0x27, 0x6a, 0x70, 0x17, - 0xb0, 0xfc, 0xfa, 0xcb, 0x52, 0xea, 0x27, 0x31, 0x95, 0xa8, 0xde, 0xe1, 0x67, 0x79, - 0x13, 0xc7, 0x86, 0xcc, 0x3a, 0xcb, 0x06, 0xa9, 0xec, 0x7a, 0x37, 0xb0, 0x58, 0x98, - 0x0c, 0xeb, 0x3c, 0x82, 0xaa, 0xb0, 0x3e, 0xaf, 0xc1, 0xbb, 0x88, 0xcf, 0x7a, 0xb7, - 0x98, 0xf1, 0x65, 0x1d, 0x67, 0xbf, 0x22, 0x30, 0xd5, 0x34, 0xec, 0x55, 0x23, 0x1d, - 0x21, 0x31, 0x7b, 0x1c, 0xb3, 0x0b, 0x3c, 0x38, 0xff, 0x8d, 0x21, 0x1b, 0x76, 0x36, - 0x70, 0x2a, 0x25, 0xca, 0x7c, 0xa1, 0xbf, 0xf1, 0xf2, 0xc1, 0x58, 0xc6, 0xef, 0x22, - 0x13, 0xff, 0xab, 0xb9, 0xc0, 0x9f, 0x5c, 0x47, 0xe7, 0x3b, 0xbe, 0xbb, 0xd3, 0x7f, - 0x3d, 0x3e, 0xbc, 0x24, 0xa6, 0x65, 0xb2, 0x9f, 0x10, 0xde, 0x8b, 0x9c, 0xf1, 0x94, - 0x2d, 0x90, 0xb4, 0xc3, 0x1d, 0x89, 0xa9, 0x88, 0x3b, 0xf5, 0xa0, 0x27, 0xe9, 0x20, - 0xd1, 0xb8, 0x51, 0x19, 0xf2, 0xf2, 0xf9, 0x5f, 0xd5, 0x5e, 0xda, 0x85, 0x75, 0xa4, - 0xdb, 0x62, 0x69, 0x05, 0x68, 0x1c, 0x29, 0xe8, 0xd8, 0xe7, 0x41, 0xd4, 0x20, 0xa8, - 0x34, 0x42, 0xa9, 0xd3, 0x8a, 0xf4, 0x19, 0x9e, 0xf9, 0x5c, 0xb3, 0x0b, 0xc4, 0x4e, - 0x93, 0xfe, 0x4d, 0x0e, 0xb7, 0x42, 0x22, 0xfc, 0x10, 0xac, 0x8d, 0x40, 0x0e, 0x10, - 0xed, 0x4e, 0x56, 0xfa, 0x39, 0xda, 0x01, 0x2a, 0xc1, 0x8d, 0xee, 0x4d, 0x99, 0x42, - 0x5c, 0x8f, 0x71, 0x4c, 0x51, 0xac, 0x1b, 0xa5, 0x6e, 0x0e, 0x81, 0x47, 0x4b, 0xad, - 0x3e, 0x74, 0x18, 0xed, 0x4c, 0x82, 0xb4, 0xd7, 0x75, 0x12, 0x0b, 0x19, 0x3e, 0xdc, - 0x66, 0x76, 0x30, 0x32, 0x66, 0xe3, 0x1e, 0xcf, 0x55, 0x1e, 0xb9, 0x13, 0xa6, 0x41, - 0x15, 0xbc, 0xcb, 0xbb, 0x2e, 0xcc, 0x89, 0x81, 0x55, 0x21, 0xe5, 0x6e, 0x07, 0xc8, - 0x8b, 0xbb, 0x4a, 0x55, 0xe9, 0x94, 0x5d, 0x03, 0xdb, 0x2d, 0xa0, 0xfc, 0xae, 0x3c, - 0x08, 0xf1, 0xd7, 0x7c, 0x57, 0x26, 0x1e, 0x98, 0x23, 0x66, 0x03, 0xa8, 0xc5, 0x2c, - 0x6c, 0x27, 0x98, 0xb5, 0x45, 0x61, 0xaf, 0xfe, 0x07, 0x61, 0xe6, 0xab, 0x24, 0x72, - 0x07, 0xad, 0xfc, 0x3c, 0x43, 0x22, 0xbe, 0x0f, 0xb2, 0x49, 0xbf, 0xd3, 0xc5, 0xe7, - 0xfb, 0x38, 0x37, 0xe9, 0xff, 0x21, 0x35, 0x07, 0x3a, 0xe1, 0x36, 0x0d, 0xcf, 0xaf, - 0x5f, 0xb6, 0x78, 0x56, 0x8f, 0xd8, 0x4d, 0x99, 0xa5, 0x1f, 0x32, 0xeb, 0x94, 0xcc, - 0xf5, 0xf2, 0x39, 0x02, 0x5b, 0x2b, 0x97, 0xbe, 0xf6, 0x25, 0xdb, 0xb6, 0x7f, 0x20, - 0xc3, 0xe0, 0xd9, 0x51, 0x73, 0x12, 0x9c, 0x06, 0x37, 0x50, 0x39, 0x52, 0x13, 0x41, - 0x49, 0x24, 0xe0, 0xa3, 0xfd, 0xd3, 0x66, 0xff, 0xd4, 0x69, 0xc9, 0xeb, 0xea, 0x79, - 0xfb, 0x76, 0xaf, 0x10, 0xea, 0x45, 0xb5, 0x66, 0xf1, 0xfc, 0x92, 0xaf, 0x48, 0xce, - 0xe2, 0x11, 0xf8, 0xe1, 0xb0, 0x58, 0xfb, 0x72, 0x1a, 0x8b, 0x22, 0xce, 0x43, 0x0c, - 0x54, 0x94, 0x0e, 0x24, 0xb3, 0x30, 0x8e, 0x57, 0x0a, 0xb8, 0x57, 0x25, 0x0d, 0x10, - 0xcd, 0xec, 0xe1, 0x05, 0x07, 0x1b, 0xc8, 0x66, 0xea, 0x4d, 0x6d, 0x5c, 0x69, 0xf9, - 0x59, 0x28, 0xf3, 0x9f, 0x7f, 0x1f, 0xcd, 0xf1, 0x5a, 0xcd, 0xbb, 0xec, 0x67, 0xd8, - 0x48, 0xf7, 0xc1, 0xb2, 0xef, 0x57, 0x7f, 0x48, 0xa7, 0x0b, 0x4b, 0xf3, 0xd8, 0xa7, - 0x88, 0x14, 0x31, 0x6b, 0x3d, 0x7f, 0xa3, 0xe3, 0xc9, 0x8c, 0xdf, 0xa1, 0x78, 0xb9, - 0x89, 0xbc, 0x78, 0xde, 0x8d, 0x24, 0xc1, 0xbb, 0xc0, 0x9d, 0x20, 0x7e, 0x11, 0x18, - 0x1e, 0x59, 0x1a, 0x60, 0x9a, 0xbf, 0xf9, 0xa2, 0x00, 0xd3, 0x4e, 0x1a, 0xc6, 0x3a, - 0x38, 0xf0, 0x40, 0x05, 0x3a, 0x32, 0x01, 0x68, 0xb8, 0x23, 0xac, 0x76, 0x6e, 0x02, - 0x6c, 0xbe, 0x1a, 0xbf, 0x27, 0x55, 0xbe, 0x0c, 0x73, 0xc8, 0xfd, 0x98, 0x62, 0x55, - 0x56, 0x40, 0x6c, 0x14, 0x99, 0x3f, 0x6a, 0x28, 0xae, 0x4b, 0xb3, 0xa4, 0x73, 0xa1, - 0x8d, 0xd3, 0x74, 0x3d, 0x88, 0x7e, 0xac, 0x54, 0x8e, 0xb7, 0xca, 0x4d, 0x46, 0x15, - 0x7c, 0x62, 0xb7, 0x29, 0xf3, 0x66, 0xa9, 0x56, 0x02, 0x28, 0x7c, 0x8c, 0x56, 0x33, - 0x5b, 0x78, 0xbc, 0x68, 0x9f, 0xc5, 0x38, 0x9c, 0x39, 0x79, 0xb8, 0xe7, 0x5d, 0xaf, - 0x31, 0xbd, 0x60, 0xa9, 0xcc, 0x2a, 0x92, 0x0d, 0xbc, 0xc6, 0x71, 0xdd, 0xe2, 0x7e, - 0xb4, 0x60, 0x0f, 0x12, 0xdc, 0x2a, 0xb3, 0x94, 0x4a, 0xa1, 0x9c, 0x71, 0xa9, 0x87, - 0xd8, 0x71, 0x3d, 0x99, 0xa4, 0xba, 0x9b, 0x9a, 0x19, 0xa9, 0x21, 0x60, 0x6c, 0x56, - 0x20, 0xc1, 0x67, 0xd4, 0xc7, 0xf4, 0xa2, 0x8a, 0x46, 0x4a, 0x9d, 0x16, 0xc4, 0xb0, - 0xd7, 0x4e, 0x0e, 0x75, 0xdf, 0x6d, 0xba, 0x0e, 0x1d, 0xfe, 0x60, 0x1c, 0x04, 0xc8, - 0xeb, 0x37, 0x01, 0x0e, 0x13, 0x92, 0x1d, 0x5b, 0x6c, 0x93, 0xb9, 0xf0, 0xc3, 0xdd, - 0xd3, 0x2f, 0x7b, 0xec, 0xb2, 0xd7, 0x7d, 0x79, 0xa1, 0x61, 0x8a, 0x79, 0xf7, 0x3c, - 0x45, 0x9b, 0x0d, 0xf5, 0x29, 0x7f, 0x8e, 0xab, 0xd6, 0xed, 0x06, 0xfd, 0x23, 0x40, - 0xe8, 0x60, 0x0a, 0x95, 0xd7, 0x2c, 0xef, 0xd1, 0x2e, 0x62, 0x2c, 0x57, 0xb4, 0x57, - 0xa4, 0xe8, 0x39, 0x75, 0x93, 0x74, 0x6a, 0x6b, 0xcf, 0x04, 0xc4, 0x9c, 0x6d, 0xd4, - 0xa3, 0x36, 0x68, 0xda, 0x53, 0x8d, 0x90, 0x93, 0xa4, 0x50, 0xa4, 0xd8, 0x24, 0x51, - 0xb6, 0x12, 0xff, 0x54, 0x70, 0x73, 0x8e, 0x62, 0xbf, 0xdf, 0xc7, 0x9b, 0x3e, 0x31, - 0xbb, 0x47, 0xfc, 0xa1, 0xe9, 0x87, 0x22, 0xa5, 0x98, 0x3a, 0xff, 0xe5, 0xf6, 0x32, - 0x84, 0x0b, 0x92, 0x3a, 0xb5, 0x6b, 0x1d, 0xa1, 0x53, 0xd3, 0x5d, 0x82, 0x23, 0x24, - 0xe7, 0xd5, 0x6d, 0x61, 0x3c, 0x73, 0xeb, 0xc6, 0x34, 0x1e, 0xa0, 0x3b, 0xee, 0x3a, - 0xb9, 0x73, 0xe8, 0x4d, 0x8f, 0xfc, 0x4a, 0x7c, 0x58, 0x13, 0x83, 0xe2, 0x14, 0x2d, - 0x29, 0x2a, 0x58, 0x0b, 0x6d, 0x30, 0x83, 0x43, 0xdc, 0xf1, 0xef, 0x49, 0x29, 0xa9, - 0xe3, 0xe6, 0x15, 0x32, 0xfc, 0xff, 0xb7, 0x4d, 0x30, 0x19, 0xf4, 0xe2, 0xd6, 0xd3, - 0x11, 0x78, 0x57, 0x5a, 0xca, 0x94, 0x12, 0x99, 0x22, 0x50, 0x44, 0xe1, 0xd3, 0x7b, - 0xab, 0x9f, 0x10, 0xe2, 0x9f, 0xd9, 0x6f, 0x9c, 0xf6, 0x84, 0xaf, 0x98, 0xed, 0x64, - 0x8b, 0x83, 0xd6, 0x1e, 0x52, 0x5b, 0xe3, 0x2c, 0xdb, 0x45, 0x3d, 0x2d, 0x38, 0x93, - 0x5f, 0xee, 0xb3, 0x22, 0xce, 0xb9, 0xd2, 0xa2, 0xe9, 0x5e, 0xb7, 0xfc, 0x61, 0x2d, - 0x89, 0xf4, 0xcf, 0xe8, 0x93, 0x22, 0x8e, 0x88, 0x28, 0xb1, 0x89, 0x00, 0x90, 0x45, - 0x62, 0x90, 0x75, 0xc0, 0xc2, 0x03, 0x9d, 0x5a, 0x73, 0x32, 0xfd, 0xbc, 0xd7, 0xc7, - 0xb0, 0x91, 0x01, 0x5c, 0x45, 0x69, 0xa3, 0x00, 0x53, 0x23, 0x56, 0xbb, 0xad, 0x08, - 0xff, 0xa3, 0xbb, 0x16, 0x7a, 0x3e, 0xbe, 0xb4, 0x62, 0x66, 0xb7, 0x06, 0x06, 0x49, - 0x4a, 0xda, 0xe9, 0x14, 0x9e, 0x1a, 0x64, 0xc0, 0xa0, 0xaa, 0x5d, 0xaa, 0x53, 0x62, - 0xd3, 0xc7, 0xa8, 0x96, 0xfd, 0x52, 0x78, 0x08, 0xd0, 0xa3, 0xc1, 0xcf, 0x70, 0x61, - 0xba, 0x67, 0x89, 0x39, 0x80, 0x78, 0x85, 0x0b, 0xe4, 0xb9, 0x94, 0x0e, 0x01, 0xae, - 0xbb, 0x93, 0x6d, 0xd8, 0x1a, 0x31, 0x82, 0x04, 0x28, 0x1d, 0x43, 0x97, 0x6f, 0x4e, - 0x0f, 0xa2, 0x07, 0xe4, 0xbe, 0x1f, 0xb8, 0x2c, 0x91, 0xbb, 0x26, 0x42, 0xf7, 0x36, - 0x85, 0x6d, 0xcd, 0x5a, 0xeb, 0x75, 0xc5, 0x0a, 0xf2, 0x00, 0xe1, 0x4b, 0xe5, 0xb7, - 0x8c, 0xe6, 0x9a, 0x88, 0x51, 0x54, 0xef, 0xe3, 0x0e, 0xdd, 0x09, 0xae, 0x8c, 0x5e, - 0xb5, 0x3f, 0x4b, 0x8b, 0x7c, 0x75, 0x35, 0x37, 0x3c, 0x0f, 0xe6, 0xcf, 0xe4, 0x48, - 0xa9, 0xb9, 0xf4, 0xd9, 0xe3, 0x10, 0x93, 0x03, 0xd6, 0xce, 0xe9, 0x10, 0x6a, 0xa2, - 0x2b, 0xd5, 0x9a, 0xe0, 0xe0, 0x27, 0xd3, 0x25, 0x6a, 0x75, 0xb9, 0xc5, 0xd6, 0x07, - 0x09, 0x09, 0x97, 0x53, 0xce, 0x57, 0x2c, 0x9e, 0x29, 0xdc, 0x92, 0x56, 0x2d, 0x1c, - 0x3f, 0x4a, 0x0b, 0x4d, 0x36, 0xa6, 0xfe, 0xc2, 0x1b, 0xa4, 0x94, 0x17, 0x3e, 0x44, - 0xd7, 0x9b, 0xc2, 0x34, 0x18, 0x95, 0xbd, 0x0c, 0x70, 0x96, 0xf0, 0x97, 0x4f, 0x12, - 0x67, 0xfe, 0xf6, 0x72, 0x1d, 0x58, 0xb8, 0xc4, 0xe3, 0x34, 0xf1, 0x4d, 0x86, 0xc0, - 0xee, 0x3b, 0x1a, 0xb5, 0x88, 0x0c, 0xa4, 0x29, 0x8d, 0x7f, 0x84, 0x76, 0x3b, 0xdc, - 0x71, 0x09, 0xbc, 0x82, 0x0f, 0x45, 0xc5, 0x04, 0x53, 0xe3, 0x3d, 0x96, 0x8e, 0xf9, - 0xd8, 0x6c, 0xd6, 0xeb, 0xe7, 0x15, 0xe8, 0x9d, 0x5d, 0xe3, 0x24, 0x09, 0x10, 0xc5, - 0x9c, 0x36, 0xec, 0x8f, 0xe9, 0x9b, 0x32, 0x49, 0x16, 0x30, 0xab, 0x35, 0xb1, 0x24, - 0x53, 0x1d, 0x9c, 0x29, 0xe0, 0x46, 0xc4, 0x78, 0xe6, 0x2a, 0xd1, 0x8b, 0x25, 0x39, - 0xa5, 0x09, 0x6e, 0xe2, 0x9a, 0x4d, 0x4b, 0x4b, 0x53, 0xa1, 0xcf, 0xfa, 0x93, 0x23, - 0xbc, 0x73, 0x21, 0x81, 0x7d, 0x96, 0xfd, 0x02, 0x05, 0xea, 0x9c, 0xbc, 0x4e, 0x15, - 0x88, 0xb7, 0x61, 0x3d, 0x4c, 0x39, 0x3c, 0xac, 0x21, 0x05, 0xb2, 0x8f, 0xd0, 0x46, - 0x7a, 0x0b, 0xf0, 0x23, 0xf0, 0x0d, 0x1a, 0x17, 0xf6, 0x53, 0xcd, 0xb6, 0xb5, 0xa8, - 0x3e, 0x4c, 0xf1, 0x5c, 0x34, 0x7b, 0x34, 0xb9, 0x7f, 0xbf, 0xe6, 0xea, 0xee, 0x13, - 0xbb, 0x90, 0x15, 0x3a, 0xfd, 0xc9, 0x11, 0x26, 0x37, 0xfa, 0xd1, 0xcf, 0xe1, 0x7e, - 0xdd, 0xcb, 0x0c, 0x81, 0x9e, 0x60, 0xd3, 0x50, 0x39, 0x34, 0x9b, 0x69, 0xf7, 0xca, - 0x9b, 0xa6, 0x4d, 0xf9, 0xf5, 0xe4, 0x71, 0x11, 0x5c, 0xd6, 0x79, 0x26, 0xbd, 0xf1, - 0x6e, 0x30, 0x12, 0x39, 0x8d, 0xae, 0x59, 0x5b, 0xfd, 0x25, 0xf3, 0xae, 0xe5, 0x8a, - 0xcf, 0xfe, 0x2f, 0x3e, 0xd7, 0x48, 0xfd, 0xf9, 0x3a, 0x6e, 0xd2, 0x1e, 0x87, 0x2d, - 0x94, 0x97, 0xa9, 0xf3, 0xb7, 0xb1, 0x6b, 0x7e, 0xa9, 0xea, 0x19, 0xf2, 0x47, 0x9e, - 0x4f, 0x8b, 0x6d, 0x42, 0x3f, 0xa1, 0x5f, 0xbc, 0xdf, 0xa3, 0xc9, 0x9b, 0x9a, 0x39, - 0x70, 0xee, 0x74, 0xa8, 0xd8, 0x5e, 0xc2, 0x15, 0x96, 0x52, 0xda, 0xa7, 0x67, 0x03, - 0x12, 0x63, 0xbb, 0x4b, 0x49, 0x28, 0x5d, 0x70, 0x5e, 0x24, 0xe8, 0x19, 0x26, 0x86, - 0xeb, 0xc8, 0xff, 0x85, 0x98, 0xd2, 0x4b, 0x51, 0x23, 0x2a, 0x99, 0x38, 0x56, 0x5d, - 0x0f, 0x68, 0xbe, 0x7f, 0x3a, 0x53, 0x36, 0x4a, 0xcc, 0x69, 0x21, 0xa3, 0x5b, 0xc5, - 0x99, 0x10, 0xbb, 0x71, 0xfb, 0x58, 0xb8, 0x67, 0x37, 0x3c, 0xe9, 0x5f, 0x19, 0x84, - 0x09, 0xaa, 0xef, 0x97, 0xf4, 0x01, 0xe4, 0x33, 0x00, 0x4b, 0x99, 0x19, 0x04, 0x9f, - 0x93, 0x7f, 0xd7, 0x76, 0xc4, 0xb6, 0x31, 0xa5, 0x91, 0x2a, 0x08, 0xd4, 0x9f, 0xdf, - 0x65, 0x28, 0xf8, 0x1a, 0x6f, 0x32, 0x00, 0x09, 0x37, 0x67, 0xbb, 0x77, 0x89, 0xd9, - 0x5a, 0x75, 0x03, 0x0a, 0xc1, 0xd2, 0x4c, 0x2c, 0x75, 0xbd, 0x60, 0x38, 0x25, 0x52, - 0x86, 0x3f, 0x09, 0x8d, 0x36, 0xbd, 0x48, 0x33, 0x28, 0x3d, 0x3a, 0x2d, 0x21, 0x5d, - 0x10, 0xc7, 0xff, 0xe9, 0xc8, 0x40, 0x37, 0x23, 0x14, 0x45, 0x58, 0x33, 0x29, 0x26, - 0x16, 0x74, 0x19, 0x3b, 0xdd, 0x1c, 0x64, 0x81, 0xbe, 0xf9, 0xf2, 0x26, 0xe1, 0xe6, - 0x0b, 0xb1, 0xc7, 0x76, 0xa4, 0xbe, 0x7d, 0xc6, 0x9b, 0x44, 0x30, 0xa7, 0x5a, 0x0c, - 0xbd, 0x55, 0x86, 0x7a, 0x6f, 0x46, 0xff, 0x93, 0x03, 0xf9, 0xa2, 0x9b, 0x6f, 0x3f, - 0x7c, 0x7a, 0x9c, 0x9f, 0xbc, 0xf7, 0x47, 0xb2, 0x3f, 0x86, 0x45, 0xf4, 0xda, 0x3d, - 0x9f, 0x72, 0xd0, 0xd8, 0x76, 0xa7, 0x5e, 0x54, 0x8a, 0x49, 0xdb, 0x37, 0x5b, 0x40, - 0xeb, 0xe1, 0xbb, 0xe0, 0x81, 0x7a, 0x99, 0x49, 0xde, 0xc1, 0x15, 0x7d, 0x62, 0xa7, - 0x1d, 0xbf, 0xbd, 0x9b, 0xb1, 0xd6, 0x55, 0x17, 0x53, 0xdf, 0xf5, 0xbb, 0x7f, 0xc9, - 0x36, 0x48, 0xd4, 0xeb, 0x6c, 0xad, 0x41, 0x67, 0x33, 0xad, 0xfd, 0xcc, 0x87, 0x08, - 0xdd, 0xe8, 0xbe, 0x87, 0x34, 0xd0, 0x5d, 0xec, 0x9e, 0x45, 0xdf, 0x3f, 0xa4, 0x5a, - 0xda, 0xc4, 0x1a, 0x6d, 0x23, 0xa2, 0x24, 0xa0, 0x4f, 0xdc, 0x0d, 0x96, 0x73, 0x87, - 0x98, 0x0f, 0x95, 0xe6, 0x27, 0xe6, 0xb3, 0xdc, 0xe1, 0x9c, 0xaf, 0x01, 0x09, 0x84, - 0x8c, 0xa9, 0xda, 0xea, 0x2e, 0x24, 0x6e, 0x62, 0xc2, 0x85, 0x07, 0xd2, 0x56, 0xeb, - 0xab, 0xe1, 0x18, 0xf1, 0xf6, 0xef, 0x97, 0x6e, 0x4a, 0x31, 0xa0, 0xe4, 0x14, 0x3c, - 0x43, 0x60, 0xd8, 0xb1, 0x79, 0xb3, 0x0e, 0x4b, 0xfa, 0x7e, 0x16, 0x1b, 0x1e, 0x6c, - 0x70, 0x7d, 0x8e, 0xae, 0x76, 0x28, 0x71, 0x59, 0x21, 0x94, 0x1e, 0x78, 0x54, 0xe1, - 0x0d, 0x11, 0x99, 0x12, 0x58, 0xc4, 0x3f, 0xe6, 0xc4, 0x45, 0x29, 0xf6, 0x61, 0x4b, - 0x58, 0x41, 0x61, 0x5d, 0x3e, 0x4e, 0x77, 0xfb, 0x09, 0xa6, 0xf0, 0x20, 0xe0, 0xb8, - 0x32, 0x28, 0xac, 0x17, 0x55, 0xad, 0x47, 0x71, 0x16, 0xde, 0xca, 0xac, 0x51, 0x7b, - 0xfb, 0xcf, 0x67, 0x37, 0xf5, 0xbb, 0x99, 0xe0, 0x07, 0xeb, 0x64, 0x00, 0x76, 0x6b, - 0x6c, 0xfd, 0xd7, 0x37, 0xe2, 0x08, 0x57, 0xdf, 0x3c, 0x85, 0xca, 0x16, 0xab, 0x21, - 0x17, 0x7b, 0x53, 0x1e, 0x55, 0x32, 0xc4, 0x45, 0xde, 0xd0, 0x0c, 0x1e, 0x96, 0x63, - 0x5e, 0x9f, 0x50, 0x0b, 0xa8, 0x76, 0x44, 0xb8, 0xc1, 0xd5, 0x33, 0x25, 0x37, 0xab, - 0xf2, 0x9f, 0xcc, 0xab, 0x8a, 0xe3, 0xe3, 0x88, 0x27, 0x18, 0x82, 0x6b, 0xdb, 0x8d, - 0xbd, 0xb8, 0x51, 0xa4, 0x77, 0x05, 0xeb, 0x0d, 0xec, 0x2d, 0x5e, 0xe9, 0x39, 0xdc, - 0x79, 0x87, 0x25, 0x6f, 0xee, 0xe6, 0x7f, 0x09, 0x90, 0x28, 0xf1, 0x45, 0xe2, 0x0b, - 0xf4, 0x88, 0x94, 0x98, 0x24, 0x30, 0x14, 0x35, 0x13, 0x73, 0xfd, 0xf6, 0x33, 0x01, - 0x8d, 0x21, 0x7c, 0x58, 0x8c, 0x52, 0x98, 0x6f, 0xc5, 0x24, 0xe7, 0x97, 0x97, 0xab, - 0x65, 0x58, 0x43, 0xc2, 0x61, 0xae, 0x7f, 0xc9, 0xcc, 0x3f, 0x47, 0x05, 0x46, 0x00, - 0xe4, 0xcd, 0x38, 0x5c, 0x46, 0x7a, 0x78, 0x8a, 0x9f, 0xff, 0xc3, 0x7e, 0x9d, 0xdb, - 0xb5, 0xd3, 0xe8, 0xa4, 0xbd, 0x0c, 0x4e, 0x8f, 0x56, 0xe5, 0x69, 0x5a, 0xfa, 0x90, - 0xfe, 0x50, 0xce, 0x0a, 0x30, 0x04, 0xfe, 0xd7, 0x12, 0xb4, 0xde, 0x15, 0xad, 0x5f, - 0x01, 0x71, 0xad, 0x51, 0xed, 0xfa, 0x54, 0xdb, 0xd4, 0x8b, 0x1f, 0xcc, 0x5e, 0xf6, - 0xac, 0x73, 0xcf, 0x0a, 0x28, 0xe9, 0xd9, 0x3e, 0x0c, 0xaf, 0xad, 0x88, 0x16, 0x76, - 0x1b, 0x3b, 0xe6, 0x38, 0x39, 0x8c, 0x00, 0x14, 0x33, 0x38, 0xea, 0x27, 0xa9, 0xff, - 0xf2, 0x2e, 0xc4, 0x73, 0x16, 0x36, 0x96, 0x12, 0x25, 0xca, 0x49, 0xe0, 0x13, 0xa6, - 0xdc, 0x80, 0x2b, 0xc7, 0xfb, 0x77, 0xca, 0xd1, 0x0a, 0xca, 0xfe, 0xfc, 0xe5, 0xfa, - 0x9a, 0x37, 0x35, 0x63, 0xb3, 0x91, 0x7a, 0x3a, 0x37, 0x39, 0xcc, 0x97, 0x80, 0xea, - 0x81, 0x50, 0x73, 0xde, 0x8e, 0xb4, 0x2e, 0x3f, 0x66, 0x93, 0xe8, 0x52, 0xbe, 0xfd, - 0xde, 0xdd, 0x61, 0x91, 0x29, 0xd0, 0xaa, 0x13, 0xc4, 0xbd, 0x83, 0x86, 0x22, 0xb5, - 0xe3, 0x28, 0x56, 0x35, 0x8e, 0x6d, 0x82, 0x78, 0x78, 0x95, 0x7e, 0x5d, 0xc8, 0x2c, - 0xd4, 0x37, 0x0b, 0x66, 0x10, 0x84, 0x9e, 0x95, 0x6d, 0x0a, 0x7c, 0xdf, 0xf5, 0x61, - 0x8f, 0x5c, 0x2c, 0xea, 0x61, 0x23, 0x0b, 0x47, 0x00, 0x1c, 0x30, 0xe5, 0xa8, 0xf9, - 0x37, 0xca, 0x7f, 0x9f, 0x9e, 0x66, 0x0f, 0xfa, 0xa7, 0x71, 0x80, 0xcb, 0xa2, 0x6f, - 0x90, 0xda, 0x00, 0x7c, 0xda, 0x40, 0x57, 0xa6, 0xce, 0xa2, 0xe2, 0x6b, 0xfd, 0xe5, - 0x0c, 0x7f, 0x90, 0x79, 0x88, 0x00, 0x53, 0xd0, 0x5d, 0xaa, 0xaa, 0xb3, 0xd7, 0xe4, - 0xdc, 0x9d, 0x81, 0xd0, 0x99, 0x0d, 0x2b, 0xc3, 0x69, 0xa6, 0x6b, 0x55, 0xac, 0x8b, - 0x63, 0x97, 0xbd, 0x47, 0xdb, 0x42, 0x89, 0xc5, 0x45, 0x22, 0x85, 0x55, 0x1a, 0xaa, - 0x7f, 0xa6, 0x7b, 0x01, 0x36, 0xcd, 0x11, 0x9f, 0x87, 0xd8, 0x21, 0x9e, 0x00, 0x02, - 0x97, 0xf0, 0x2c, 0x0c, 0xe6, 0xe3, 0x7b, 0x62, 0x0f, 0x5e, 0x47, 0xfc, 0xa0, 0x3a, - 0xcd, 0xd6, 0x54, 0x4a, 0x47, 0xf4, 0xde, 0xef, 0x19, 0x4f, 0x95, 0x9a, 0xdc, 0x36, - 0x8b, 0x3b, 0x5d, 0x27, 0xd3, 0x83, 0xfe, 0x2f, 0x2b, 0x52, 0x5d, 0xae, 0x04, 0x50, - 0x55, 0x06, 0x35, 0xaa, 0x21, 0x58, 0x18, 0xf7, 0xf5, 0x03, 0x78, 0x90, 0xf0, 0x53, - 0x23, 0x3f, 0x9a, 0xa5, 0x0a, 0xe2, 0x9c, 0x05, 0x56, 0xc3, 0x6d, 0x67, 0xb2, 0x64, - 0x7e, 0x54, 0xeb, 0xe7, 0x58, 0x8e, 0x1f, 0x02, 0xb3, 0xc7, 0x17, 0xdf, 0x02, 0x98, - 0x43, 0x0e, 0xc9, 0xd2, 0xbb, 0x11, 0x4b, 0x35, 0x42, 0xb7, 0x5d, 0x01, 0x0d, 0x93, - 0x4e, 0x58, 0x96, 0xe1, 0xd2, 0xd1, 0x0a, 0x09, 0x20, 0x11, 0x9d, 0xf7, 0x29, 0x2c, - 0x8c, 0x28, 0x47, 0x65, 0x0f, 0xbf, 0x42, 0x80, 0x57, 0x12, 0x8a, 0x02, 0x04, 0x0e, - 0xb3, 0xe3, 0x2d, 0xb5, 0x0c, 0xa7, 0xd8, 0xda, 0x7f, 0xf4, 0xc4, 0xa7, 0xa0, 0xe9, - 0xcf, 0x4b, 0x65, 0x2b, 0x65, 0x3d, 0x42, 0x8f, 0x83, 0xf4, 0x85, 0x33, 0x57, 0x84, - 0x1b, 0x28, 0x13, 0x80, 0x55, 0xb9, 0x13, 0x81, 0x17, 0x79, 0x0a, 0x91, 0xe2, 0x8f, - 0xaa, 0x41, 0x2f, 0xd7, 0xd0, 0x73, 0x32, 0x56, 0x73, 0x44, 0x85, 0xd1, 0xd6, 0xd1, - 0xa9, 0x8c, 0xc2, 0xd7, 0xc8, 0x2b, 0x37, 0x9e, 0x60, 0x72, 0x5d, 0x31, 0x8c, 0x14, - 0x77, 0xce, 0x49, 0x6c, 0x95, 0x86, 0x31, 0x08, 0xa1, 0xc7, 0xe4, 0xf0, 0x20, 0x0b, - 0x7a, 0x3c, 0x08, 0x8d, 0xe7, 0x7e, 0xb4, 0xbc, 0x95, 0xa1, 0xc6, 0xc8, 0x39, 0xd7, - 0x5f, 0xab, 0x59, 0x40, 0xd3, 0x07, 0x94, 0x24, 0xd5, 0x23, 0xd6, 0xd9, 0xa4, 0x6b, - 0xe5, 0x4e, 0x18, 0xf5, 0x29, 0xdc, 0x9e, 0x56, 0x77, 0x6c, 0x5e, 0xc4, 0x51, 0xce, - 0x28, 0x07, 0x9d, 0x37, 0x82, 0x6a, 0xec, 0x40, 0x97, 0xca, 0x7a, 0xee, 0xc8, 0x08, - 0x3f, 0xf5, 0xc4, 0x29, 0x56, 0x9f, 0x91, 0x53, 0xf6, 0x96, 0xbe, 0x62, 0xbd, 0x38, - 0xa3, 0xe7, 0x27, 0xa6, 0x8a, 0xcc, 0xdf, 0xab, 0x02, 0x9b, 0x0b, 0x21, 0xe6, 0xd0, - 0xcd, 0x46, 0x0a, 0x57, 0xd5, 0xf9, 0x03, 0xda, 0x18, 0xa6, 0x07, 0x86, 0xb3, 0x91, - 0xdd, 0x1f, 0x5b, 0xe9, 0x49, 0x82, 0x7e, 0x0c, 0xe7, 0xdf, 0xd1, 0xe0, 0x84, 0x27, - 0xf0, 0xd3, 0xc2, 0x86, 0x53, 0x78, 0xc7, 0x3d, 0x46, 0xa7, 0x3c, 0x55, 0x4a, 0x12, - 0x99, 0x86, 0x02, 0x2a, 0x4f, 0x38, 0x36, 0x0c, 0x39, 0xeb, 0x9c, 0xdd, 0x05, 0x0f, - 0x56, 0xec, 0x05, 0x95, 0x68, 0x65, 0x3c, 0x78, 0x29, 0xe0, 0xa4, 0x4f, 0x2c, 0x70, - 0x10, 0xad, 0xb6, 0x73, 0xe8, 0xde, 0x77, 0x04, 0xe5, 0x4c, 0x03, 0xa7, 0x7a, 0xb7, - 0x8e, 0x85, 0xb6, 0x3f, 0x2b, 0x91, 0x18, 0x5c, 0xa5, 0xda, 0x67, 0xd3, 0x28, 0x30, - 0x65, 0x8b, 0x54, 0xbb, 0x33, 0x58, 0x75, 0x13, 0xc4, 0x2e, 0x03, 0xb5, 0x2c, 0xeb, - 0x9a, 0x19, 0x57, 0xa9, 0xe9, 0x05, 0x84, 0x72, 0x37, 0xce, 0x44, 0x56, 0xe5, 0x33, - 0x50, 0x68, 0x26, 0x49, 0x0e, 0xc5, 0x55, 0x2b, 0x39, 0x12, 0xdb, 0x1c, 0x88, 0x0e, - 0xd4, 0x71, 0xb1, 0x09, 0x29, 0x98, 0xdc, 0xc1, 0x6f, 0xa9, 0x8d, 0x5a, 0xe9, 0xe7, - 0x6f, 0xd2, 0x9d, 0x17, 0x9f, 0xd7, 0x36, 0x59, 0x78, 0xc0, 0x80, 0x44, 0x51, 0x18, - 0x80, 0x1a, 0xc1, 0x0d, 0xc0, 0xf5, 0x78, 0x8f, 0x47, 0x86, 0x69, 0x34, 0xb9, 0x8a, - 0xad, 0xb9, 0xc6, 0x8d, 0xd8, 0x84, 0x83, 0xc1, 0x5d, 0x47, 0xaf, 0x8f, 0xf4, 0x2e, - 0x6b, 0xfb, 0xb8, 0xe0, 0xe5, 0x3a, 0x04, 0x7e, 0x58, 0xe5, 0xba, 0x90, 0xd1, 0xdb, - 0x1e, 0xa1, 0x26, 0x01, 0x7c, 0x65, 0x6d, 0x01, 0x1c, 0x68, 0x7b, 0xb0, 0x4f, 0x47, - 0xa5, 0x60, 0xef, 0x7c, 0xed, 0x23, 0x1b, 0x24, 0x38, 0x7f, 0xf4, 0x01, 0x90, 0x43, - 0xcf, 0xfd, 0x67, 0xfb, 0x9d, 0x89, 0x20, 0x06, 0xc3, 0x91, 0x7f, 0xd7, 0xa9, 0x6f, - 0xe0, 0x3d, 0x7b, 0xea, 0xa2, 0x17, 0x12, 0x8d, 0x71, 0xf0, 0xa2, 0x8a, 0x83, 0x78, - 0x7a, 0x86, 0xcf, 0xc9, 0x33, 0x69, 0xd0, 0xdd, 0x54, 0x65, 0x32, 0x7f, 0xc4, 0x29, - 0x4d, 0xae, 0x81, 0xc4, 0x35, 0x1c, 0x42, 0xa6, 0xf0, 0xa8, 0x0e, 0xef, 0xa6, 0x1d, - 0xb6, 0xa4, 0x0b, 0xb6, 0x81, 0xf5, 0x58, 0xf8, 0x1b, 0x10, 0x1e, 0xb6, 0x57, 0xf6, - 0x57, 0x27, 0xd6, 0x17, 0x69, 0x1b, 0x8b, 0xee, 0x3a, 0xa7, 0xe5, 0x75, 0xb4, 0x11, - 0xa0, 0x12, 0x8a, 0x3f, 0x24, 0x75, 0x3e, 0x52, 0xee, 0x34, 0x90, 0x04, 0xcf, 0x6d, - 0x25, 0xfa, 0xd6, 0xc4, 0x68, 0x1b, 0x02, 0xa2, 0xe1, 0x96, 0x14, 0xe8, 0x0c, 0x95, - 0x83, 0x81, 0x36, 0x2a, 0x91, 0xd3, 0xcd, 0x3b, 0x4e, 0x76, 0x58, 0x32, 0x94, 0x31, - 0x0c, 0x82, 0x41, 0x11, 0x29, 0xac, 0x97, 0xf2, 0xad, 0x5a, 0x5b, 0x9f, 0xa8, 0x64, - 0xa9, 0xc5, 0xd0, 0x2d, 0x8c, 0x92, 0xd6, 0x42, 0x44, 0xfa, 0x6c, 0x40, 0x9c, 0x21, - 0x69, 0x48, 0x62, 0xc4, 0x42, 0x7d, 0xc5, 0x1a, 0xec, 0x57, 0x7f, 0x6e, 0xa3, 0x38, - 0x05, 0x03, 0x13, 0x99, 0x91, 0xe6, 0xe8, 0x89, 0x09, 0x87, 0x64, 0x9f, 0xa7, 0xc4, - 0x3a, 0xc8, 0x03, 0xf6, 0x89, 0xb6, 0x9d, 0x70, 0xab, 0xd7, 0xef, 0xa7, 0x1c, 0xf9, - 0xa0, 0xf2, 0xa4, 0x1d, 0xf9, 0x41, 0x89, 0x76, 0xa4, 0xff, 0xa4, 0x4f, 0x43, 0x75, - 0x92, 0xf1, 0x9c, 0x09, 0xcb, 0x49, 0x31, 0xb3, 0xd3, 0xcd, 0x01, 0x59, 0x31, 0xcf, - 0xfa, 0xe1, 0x71, 0xe0, 0x8a, 0xc5, 0x92, 0x88, 0x61, 0xfc, 0xc3, 0x2e, 0x08, 0x81, - 0x15, 0x59, 0x76, 0x49, 0x66, 0xbe, 0xbc, 0x14, 0x14, 0x36, 0xb9, 0x17, 0xc5, 0x27, - 0x1b, 0x2c, 0x68, 0x0c, 0xdc, 0x50, 0x2c, 0xba, 0xd5, 0x27, 0xac, 0x08, 0x7b, 0x34, - 0x65, 0x6f, 0x75, 0x5d, 0xfb, 0xf0, 0xae, 0x5a, 0xed, 0xc8, 0x09, 0x85, 0xf6, 0x3d, - 0x0c, 0xa4, 0x4a, 0x76, 0x2f, 0x9b, 0x31, 0x1f, 0x15, 0x6d, 0xe6, 0x27, 0x74, 0x19, - 0x19, 0x99, 0x8e, 0x67, 0x44, 0x66, 0xc7, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x04, 0xc4, - 0x9e, 0xb1, 0x87, 0xfb, 0xf7, 0x5e, 0x5f, 0x7c, 0xee, 0x26, 0x1e, 0x30, 0x75, 0xc2, - 0xb2, 0xc2, 0x81, 0x2f, 0xe8, 0x32, 0x32, 0xc4, 0x1a, 0x5f, 0x10, 0xf4, 0x0b, 0x91, - 0x1e, 0xbc, 0xeb, 0xb7, 0x8c, 0x91, 0xc2, 0x0b, 0x82, 0xc0, 0x05, 0x0f, 0xe2, 0xee, - 0x10, 0x4b, 0x39, 0x20, 0xed, 0x0a, 0x05, 0xd1, 0x7b, 0x06, 0x0d, 0x99, 0xd5, 0x87, - 0x01, 0x98, 0xe6, 0x3c, 0xcf, 0x51, 0xb1, 0x5d, 0xf8, 0x0e, 0x87, 0xac, 0xbd, 0x30, - 0x12, 0x6c, 0xda, 0x2a, 0xff, 0xb8, 0xf1, 0xce, 0xcb, 0x1b, 0xaa, 0x6a, 0x91, 0x9e, - 0x0a, 0x97, 0x87, 0x91, 0x39, 0x69, 0x04, 0x44, 0x9a, 0xde, 0x4b, 0x0b, 0x02, 0x92, - 0x0f, 0xb8, 0xc0, 0xbf, 0x7f, 0xc0, 0x82, 0xeb, 0x74, 0x98, 0x73, 0xc1, 0x0d, 0x17, - 0xdb, 0xd9, 0x1f, 0xfe, 0xa9, 0x36, 0x10, 0xee, 0xea, 0x62, 0x57, 0x90, 0xad, 0xa2, - 0x8e, 0x3a, 0x2c, 0xf2, 0x2c, 0x0d, 0x4e, 0xa2, 0xb9, 0x26, 0x41, 0xf2, 0x16, 0xd3, - 0x92, 0x2c, 0x1f, 0xc3, 0x2d, 0xbc, 0x1e, 0x0e, 0x99, 0x00, 0x38, 0x6c, 0xf8, 0x98, - 0xcb, 0x8e, 0xd5, 0x6c, 0x06, 0x4e, 0x5b, 0x12, 0xb0, 0x26, 0xbf, 0x03, 0x5d, 0xfb, - 0xc4, 0xeb, 0x92, 0xce, 0x33, 0xf8, 0x2b, 0xbe, 0x48, 0xca, 0x94, 0x5f, 0x12, 0x44, - 0x83, 0x10, 0xd7, 0xb9, 0xdb, 0x85, 0xf1, 0xb0, 0x46, 0xdc, 0x9c, 0x56, 0x51, 0x2f, - 0x61, 0xe0, 0xa3, 0x96, 0x6f, 0xa4, 0xab, 0x71, 0xd1, 0x5f, 0x4e, 0x23, 0xe4, 0xe3, - 0x1c, 0xb9, 0x62, 0x10, 0x60, 0x14, 0xc4, 0xc2, 0x9e, 0xc3, 0xb9, 0x10, 0xe0, 0x72, - 0x2d, 0xac, 0x38, 0xaa, 0x4d, 0xc8, 0x1e, 0x17, 0x6d, 0x72, 0xfe, 0xaf, 0x2f, 0x93, - 0xf9, 0xec, 0xd5, 0x04, 0xcb, 0xaf, 0x95, 0x59, 0x83, 0x30, 0x09, 0xd9, 0x2c, 0x9d, - 0x2f, 0x81, 0x68, 0x7b, 0xf5, 0x89, 0xa4, 0x93, 0x66, 0xcd, 0x0a, 0xba, 0xe7, 0xa1, - 0x74, 0xa4, 0x8f, 0xf7, 0x6c, 0xd7, 0x2f, 0x02, 0xb1, 0x8a, 0xf8, 0x18, 0x75, 0x26, - 0xd4, 0x70, 0x94, 0x9c, 0xb8, 0xd9, 0x3e, 0xfe, 0x6c, 0x5b, 0xc7, 0x91, 0xca, 0x93, - 0xb1, 0x10, 0xc1, 0x82, 0x5b, 0x6a, 0xfb, 0x04, 0x5d, 0x9d, 0x8c, 0xa3, 0x51, 0xf7, - 0xad, 0xa3, 0x28, 0xfd, 0xd5, 0x2a, 0xec, 0x29, 0x77, 0xd2, 0x94, 0x0e, 0x2c, 0xdc, - 0xb2, 0x66, 0x4d, 0x78, 0xb7, 0x6a, 0xc0, 0xe0, 0x6d, 0x78, 0x8e, 0x57, 0xf8, 0x24, - 0x4f, 0x44, 0x2c, 0x88, 0x6a, 0x8f, 0x31, 0x13, 0x7c, 0xd7, 0xf1, 0x9e, 0x82, 0x21, - 0xa3, 0x85, 0xcb, 0xfb, 0x3f, 0x7f, 0x2a, 0x1e, 0x79, 0x50, 0x4b, 0xcf, 0x1a, 0xe0, - 0x83, 0xb1, 0x29, 0x02, 0xa5, 0x01, 0x2c, 0xd5, 0xea, 0x2f, 0xc8, 0x56, 0x43, 0xdd, - 0xec, 0xee, 0xf4, 0xab, 0x95, 0x93, 0x43, 0x21, 0x9b, 0x0c, 0x63, 0xdd, 0x0a, 0x8b, - 0x0e, 0x23, 0x3e, 0xfc, 0x68, 0xfc, 0x63, 0x30, 0x73, 0xe6, 0x6c, 0x59, 0x97, 0x5f, - 0x23, 0x52, 0x4b, 0x6a, 0xa1, 0xab, 0x9a, 0xe7, 0xb1, 0x33, 0xd5, 0xf3, 0x0c, 0xf9, - 0xe1, 0xd0, 0xf9, 0xba, 0xd7, 0x1f, 0x67, 0x3f, 0x5b, 0x75, 0x4c, 0xf4, 0x00, 0x99, - 0x77, 0x57, 0xa6, 0x45, 0x8a, 0xd3, 0xb9, 0xdc, 0x8e, 0xc0, 0xc6, 0x9c, 0x66, 0x09, - 0x66, 0x3b, 0x42, 0xbb, 0xb0, 0xca, 0x1a, 0x55, 0x73, 0x37, 0x42, 0x81, 0x1f, 0x0d, - 0x71, 0x30, 0xe0, 0x13, 0xfe, 0x2f, 0x88, 0x05, 0x8e, 0xe8, 0x9b, 0x90, 0xa7, 0x5c, - 0xd0, 0x69, 0xda, 0xf1, 0x00, 0x37, 0x25, 0x4d, 0x10, 0x16, 0xd3, 0xac, 0xf7, 0xe6, - 0x2f, 0x18, 0x3b, 0x2c, 0x55, 0x1a, 0x59, 0x90, 0xe4, 0xed, 0x73, 0xdc, 0xd8, 0x94, - 0xf7, 0x85, 0x70, 0xfd, 0x19, 0x56, 0xcb, 0x22, 0x7c, 0x65, 0x00, 0x01, 0xf2, 0x7f, - 0x94, 0x23, 0xf4, 0xed, 0x12, 0x56, 0x0b, 0x2e, 0x1c, 0x8d, 0xbc, 0xb4, 0xc3, 0x02, - 0x15, 0xb2, 0x16, 0x7f, 0x02, 0xef, 0xeb, 0x70, 0x7a, 0xf1, 0xb5, 0xc7, 0x84, 0xb7, - 0xf5, 0x8b, 0x2e, 0x51, 0x73, 0x03, 0xf3, 0xaf, 0x71, 0xb1, 0xee, 0x39, 0xa9, 0xae, - 0x06, 0xb9, 0x77, 0x28, 0xe6, 0x4f, 0x67, 0x6d, 0xed, 0x50, 0xa3, 0xf5, 0x1b, 0xc9, - 0xe0, 0x17, 0x07, 0xbf, 0x57, 0x95, 0x6f, 0x01, 0xb7, 0xda, 0x7c, 0x23, 0xe6, 0x93, - 0x52, 0x06, 0x57, 0x28, 0x6f, 0xe7, 0x3e, 0xee, 0x9e, 0xb1, 0xd5, 0x83, 0x75, 0x22, - 0x03, 0xf3, 0xd9, 0x2b, 0xd4, 0x04, 0x7b, 0x83, 0xfd, 0x38, 0xf5, 0x66, 0xdd, 0x25, - 0xb9, 0x6d, 0x11, 0xb7, 0x22, 0x2b, 0x67, 0x82, 0xda, 0xde, 0xf5, 0xee, 0x78, 0x82, - 0x14, 0x7c, 0xbb, 0x4f, 0xcf, 0xe7, 0x0d, 0x2c, 0xa7, 0xf3, 0x9a, 0x29, 0x7b, 0x21, - 0xd5, 0x6d, 0x66, 0x10, 0xe9, 0xda, 0x9d, 0x8e, 0xef, 0xdc, 0x69, 0x9e, 0x4a, 0x30, - 0x06, 0x8a, 0x14, 0x57, 0xcf, 0x5e, 0xaf, 0x69, 0x87, 0x78, 0x21, 0xd3, 0x9e, 0xa0, - 0x85, 0x94, 0xc2, 0xfb, 0x9e, 0xb9, 0xd8, 0x04, 0x64, 0x50, 0xe4, 0x13, 0x03, 0xf1, - 0x95, 0xbd, 0xc9, 0x05, 0xe4, 0xf2, 0x58, 0x3c, 0x6a, 0xe3, 0x86, 0x1b, 0x87, 0x19, - 0xbb, 0xce, 0xd1, 0xce, 0x58, 0xc4, 0x68, 0x81, 0x6d, 0x45, 0x15, 0xe6, 0x09, 0x7b, - 0x3e, 0x2e, 0x81, 0x82, 0x21, 0x0f, 0x6c, 0x1b, 0xb3, 0xaa, 0xa6, 0x2a, 0xe0, 0xf6, - 0x9f, 0x79, 0xfc, 0xc5, 0x47, 0xba, 0xab, 0x31, 0x1d, 0x99, 0x7c, 0x84, 0x95, 0xd6, - 0xab, 0xe3, 0xa5, 0x1f, 0x56, 0x53, 0xf3, 0x1c, 0x5a, 0x2e, 0xea, 0x8d, 0x31, 0x90, - 0x97, 0xf3, 0x04, 0x5e, 0x6c, 0x3c, 0x3d, 0x8c, 0x87, 0xc9, 0xbd, 0x55, 0xb4, 0x19, - 0x2e, 0xbf, 0x00, 0xff, 0x8f, 0xc7, 0xf4, 0x1e, 0x18, 0x93, 0x0a, 0x99, 0x72, 0xa3, - 0x4d, 0x9e, 0x6a, 0xa9, 0xd9, 0x1d, 0x2e, 0x28, 0x17, 0xeb, 0x6d, 0xe9, 0xba, 0x38, - 0x9e, 0x69, 0xaa, 0x51, 0x2f, 0x3f, 0xb4, 0xdf, 0xf8, 0xca, 0x1c, 0xe7, 0xc9, 0xca, - 0x39, 0x6e, 0x8a, 0x9d, 0x99, 0xd4, 0x96, 0x51, 0xb0, 0x58, 0x2f, 0xc5, 0x86, 0xce, - 0x92, 0x7e, 0xa2, 0x64, 0x5b, 0xda, 0xa3, 0x79, 0x28, 0x6f, 0x95, 0xd3, 0x9b, 0x95, - 0x81, 0xde, 0xb2, 0xc5, 0x37, 0x75, 0xae, 0xef, 0x20, 0xe7, 0xbd, 0xbc, 0x3b, 0x19, - 0xd8, 0x9b, 0xac, 0xee, 0xa1, 0x3b, 0x74, 0xe6, 0xc7, 0xf5, 0x20, 0x89, 0x39, 0x7d, - 0x11, 0x6e, 0xbf, 0xac, 0x6a, 0x30, 0xed, 0x27, 0xd6, 0x27, 0x81, 0xa0, 0x3b, 0x66, - 0xb0, 0x52, 0xf7, 0x51, 0xfb, 0x36, 0x88, 0x2b, 0x9a, 0x14, 0x34, 0x23, 0xad, 0x02, - 0xf3, 0x36, 0x0a, 0xfa, 0x54, 0xc4, 0xcf, 0x23, 0x53, 0x0c, 0x68, 0xd6, 0x0e, 0x99, - 0x56, 0x1c, 0xce, 0x0d, 0x6a, 0x9c, 0x32, 0xef, 0xc7, 0x1f, 0xef, 0xaf, 0x23, 0x57, - 0x86, 0x3f, 0xa0, 0xb9, 0xf7, 0xbe, 0x76, 0xc2, 0xd1, 0xd3, 0x88, 0x49, 0xa0, 0x0a, - 0xb0, 0x41, 0xf1, 0x82, 0xad, 0x63, 0x35, 0xe9, 0x55, 0xcc, 0x65, 0xcd, 0xfd, 0x3b, - 0x69, 0x1a, 0x3d, 0x96, 0xc4, 0xbd, 0x56, 0xf5, 0x25, 0xce, 0xdb, 0x7f, 0xdc, 0xb7, - 0x33, 0xe7, 0x67, 0x06, 0x2f, 0xd8, 0xa4, 0xef, 0x1a, 0x4b, 0x71, 0x5e, 0x5e, 0xdf, - 0x76, 0x26, 0x14, 0x4e, 0x28, 0x5f, 0x2b, 0x3c, 0x4e, 0x2c, 0xb4, 0x1b, 0x7d, 0xb9, - 0x66, 0x35, 0x82, 0xad, 0x65, 0xa5, 0x41, 0x6e, 0x57, 0xf7, 0x48, 0x5f, 0x39, 0xc0, - 0x5e, 0x8e, 0x7a, 0xf9, 0x6b, 0x36, 0x78, 0xc8, 0x0a, 0x8d, 0x4b, 0xa2, 0xf9, 0x5d, - 0x5f, 0xeb, 0x0c, 0xcb, 0x0f, 0x71, 0x7b, 0x9d, 0xb7, 0x24, 0xab, 0xf4, 0xcc, 0xd4, - 0x10, 0x49, 0x00, 0x18, 0x6f, 0x4a, 0x93, 0x0d, 0x4b, 0x2a, 0xcb, 0x9f, 0x9a, 0x16, - 0xaf, 0x89, 0x77, 0x27, 0x7d, 0x6f, 0x0b, 0xc9, 0x0a, 0xb8, 0x59, 0xc3, 0x33, 0x3b, - 0x3d, 0xe8, 0x6f, 0x41, 0xfa, 0x85, 0xd5, 0x70, 0xf1, 0x6c, 0x74, 0x82, 0x0a, 0x70, - 0x41, 0xfe, 0xa1, 0x5e, 0xe9, 0x50, 0xc3, 0x30, 0xac, 0xa3, 0xf1, 0xe5, 0x1c, 0x69, - 0x44, 0x74, 0x72, 0xf2, 0x6a, 0x3d, 0x67, 0x41, 0xbc, 0x67, 0xe9, 0x2e, 0x00, 0xa0, - 0x83, 0xb6, 0x95, 0x33, 0x03, 0xb3, 0x73, 0x1c, 0xf2, 0x84, 0x8d, 0x81, 0x7c, 0xeb, - 0x77, 0xf1, 0xcc, 0xa7, 0x1e, 0xc9, 0x13, 0x91, 0x20, 0x2b, 0x73, 0x4d, 0x54, 0x8f, - 0xa3, 0x14, 0x2c, 0x37, 0xe6, 0xfc, 0xac, 0x51, 0x92, 0xfc, 0xa2, 0x8d, 0x63, 0x98, - 0x1f, 0x67, 0xdd, 0xdc, 0x28, 0xb3, 0x1f, 0xd0, 0xb9, 0x3a, 0x7f, 0x21, 0x88, 0xc1, - 0xec, 0xa2, 0xc1, 0xef, 0xa4, 0x61, 0xd2, 0xdd, 0x73, 0x38, 0xdf, 0x07, 0x05, 0xae, - 0x70, 0x10, 0x62, 0xfb, 0xcd, 0x8d, 0x50, 0x29, 0x98, 0x85, 0xd8, 0xe3, 0xd4, 0xfb, - 0xd6, 0xa4, 0xf2, 0x15, 0x5d, 0xc8, 0xd8, 0xfd, 0x0b, 0x05, 0x8f, 0x3c, 0x77, 0x50, - 0x83, 0xf5, 0x96, 0x12, 0xac, 0x66, 0x02, 0xd9, 0xad, 0xfa, 0x49, 0xe2, 0x60, 0x2a, - 0x12, 0xf2, 0x90, 0x0d, 0x22, 0xb9, 0x9c, 0x0b, 0x8a, 0x32, 0x68, 0xa0, 0x19, 0xc0, - 0xdd, 0xf3, 0x14, 0x3e, 0x8a, 0xf4, 0x13, 0x07, 0xd9, 0x26, 0x74, 0x02, 0x13, 0x08, - 0x59, 0xee, 0x92, 0x43, 0x4d, 0x23, 0x79, 0xe9, 0x4b, 0xcb, 0xbe, 0x56, 0x1d, 0xe0, - 0x42, 0x92, 0xb5, 0x32, 0xab, 0xc3, 0x5d, 0xde, 0x53, 0xd2, 0xad, 0x86, 0x7f, 0x7a, - 0xd9, 0x42, 0x00, 0xe4, 0x8e, 0x50, 0x3e, 0x7d, 0x41, 0x6b, 0xcf, 0x98, 0x29, 0x9f, - 0x82, 0xfc, 0xba, 0xe2, 0xdc, 0x42, 0xae, 0xc1, 0x8a, 0x29, 0x3b, 0x63, 0x79, 0x5b, - 0x68, 0x63, 0xf3, 0x22, 0x49, 0xcd, 0x20, 0x5e, 0x54, 0xd7, 0xcb, 0x7c, 0x82, 0x3b, - 0x00, 0x74, 0x77, 0x35, 0x96, 0xc1, 0xc5, 0x33, 0x92, 0x1d, 0x3b, 0xae, 0x11, 0xfe, - 0x1c, 0x6b, 0xfb, 0x77, 0x74, 0xe1, 0x49, 0x88, 0x64, 0xf3, 0xb6, 0x26, 0xd4, 0xcb, - 0x14, 0x47, 0x95, 0xd8, 0xf3, 0x59, 0xf5, 0xc5, 0x5d, 0xa3, 0xd7, 0x11, 0x70, 0x4e, - 0x74, 0x29, 0x58, 0x95, 0x5e, 0xaf, 0xa4, 0xb7, 0xd0, 0x31, 0xb2, 0xd6, 0xda, 0x0c, - 0x52, 0x9d, 0x41, 0xf3, 0x16, 0x93, 0xe4, 0xe5, 0x10, 0xb6, 0xb1, 0xe4, 0xab, 0xb6, - 0x01, 0x5f, 0x0d, 0x6d, 0x12, 0x61, 0x5e, 0xc1, 0xea, 0xf2, 0x75, 0xd4, 0x62, 0x96, - 0x2f, 0x17, 0x68, 0x4a, 0x7a, 0x25, 0x30, 0x1a, 0x99, 0x55, 0x5d, 0xef, 0x47, 0x15, - 0xff, 0x62, 0xce, 0x3c, 0xa6, 0x2f, 0x82, 0xe1, 0xf0, 0xec, 0x3b, 0x76, 0xd9, 0xea, - 0x82, 0x5a, 0xbc, 0x46, 0xfa, 0x2c, 0xf2, 0xb7, 0xa9, 0x64, 0x3e, 0xf2, 0x11, 0x0d, - 0x16, 0xef, 0x7a, 0x37, 0x0a, 0x5a, 0x99, 0xc0, 0xf7, 0x3d, 0xd2, 0x07, 0xb7, 0xba, - 0xc5, 0x2f, 0x36, 0x7d, 0xc4, 0xba, 0x9f, 0x52, 0x1c, 0x2d, 0x48, 0x77, 0xba, 0x68, - 0x98, 0xb8, 0xc9, 0x0c, 0x6d, 0xa7, 0x33, 0x64, 0x5c, 0xfb, 0x78, 0xc6, 0xf4, 0x09, - 0x92, 0xc7, 0x20, 0x96, 0x8f, 0xe4, 0x3c, 0x32, 0xbb, 0x59, 0x39, 0x9b, 0xa8, 0x82, - 0x36, 0x06, 0x4a, 0xa0, 0xa6, 0x8f, 0x1a, 0x5a, 0xfa, 0xae, 0xd0, 0xf5, 0x39, 0xc2, - 0x4e, 0xf9, 0xe6, 0x9d, 0x37, 0xdd, 0xba, 0x2d, 0x15, 0x86, 0xc0, 0x3b, 0x52, 0x45, - 0x48, 0xd8, 0x20, 0x7d, 0xa9, 0x58, 0x92, 0xc0, 0x0a, 0xcf, 0xee, 0x51, 0xb2, 0x42, - 0x4c, 0x2d, 0x1a, 0x4d, 0x7d, 0x4d, 0xd9, 0x8a, 0x1c, 0x6f, 0x2a, 0x5f, 0x6b, 0x39, - 0x20, 0x64, 0x30, 0xf1, 0x84, 0x37, 0x3a, 0x96, 0xc6, 0xaa, 0x58, 0xcc, 0xe2, 0xe1, - 0xc5, 0x04, 0xd4, 0x0e, 0xe9, 0xef, 0xda, 0x58, 0x8d, 0x43, 0xef, 0xb1, 0xda, 0x53, - 0xc7, 0x3d, 0x53, 0x0f, 0xa7, 0x6b, 0x11, 0x2f, 0x33, 0xb4, 0xaf, 0xa9, 0x41, 0xcd, - 0x1e, 0x20, 0x5a, 0xcd, 0x72, 0xca, 0x86, 0x84, 0xad, 0xe8, 0x33, 0x3d, 0x46, 0x32, - 0xab, 0x94, 0x3d, 0x69, 0x0f, 0x13, 0x2b, 0xc9, 0x9f, 0x5c, 0x5a, 0x1d, 0x3e, 0xa4, - 0xe0, 0xca, 0x8f, 0x43, 0x23, 0x8c, 0xd9, 0xeb, 0x09, 0xc8, 0xbf, 0x11, 0xe9, 0x18, - 0xa9, 0xc7, 0xf8, 0x83, 0xbe, 0x94, 0x89, 0x06, 0x56, 0x33, 0x66, 0x67, 0x95, 0x4a, - 0x51, 0xa8, 0xae, 0xcd, 0xc4, 0xcb, 0xd3, 0x9a, 0xca, 0xc7, 0x52, 0x05, 0x6e, 0x71, - 0xcc, 0x96, 0x91, 0x55, 0xdd, 0x65, 0x6d, 0x79, 0x59, 0x00, 0x8c, 0x0e, 0xcf, 0x61, - 0x83, 0x2a, 0x5c, 0x44, 0xe2, 0xe0, 0xde, 0x68, 0xf5, 0x04, 0xc1, 0x77, 0xdf, 0x68, - 0x8b, 0xee, 0x55, 0x8c, 0x6f, 0x4e, 0x5e, 0xa5, 0xf9, 0xad, 0x78, 0x26, 0x73, 0x40, - 0xe2, 0xc8, 0x35, 0xb9, 0x74, 0xdd, 0x12, 0xcd, 0xb9, 0x05, 0x08, 0x87, 0x60, 0x34, - 0xdd, 0xde, 0x0d, 0x97, 0xea, 0xfa, 0xf9, 0x70, 0x18, 0x34, 0x90, 0xcd, 0x22, 0xea, - 0x57, 0xb9, 0x8a, 0xbd, 0x1a, 0x7f, 0x79, 0xe2, 0xcf, 0x23, 0xcf, 0x8d, 0x1b, 0x0e, - 0x9b, 0x7c, 0x93, 0x8a, 0xcc, 0x6b, 0x14, 0x4b, 0x54, 0x13, 0xd3, 0x2f, 0x50, 0xcd, - 0x09, 0x61, 0x8f, 0xa9, 0x74, 0x10, 0x3a, 0x72, 0x8e, 0x2b, 0x71, 0x76, 0x63, 0xd4, - 0xbd, 0x9b, 0x07, 0x20, 0xb7, 0x75, 0xf5, 0xee, 0x25, 0xa6, 0xd7, 0x4d, 0x12, 0x8c, - 0x49, 0xb4, 0x0a, 0x19, 0x74, 0x1c, 0x37, 0xdd, 0x34, 0x61, 0x6d, 0xb3, 0x1e, 0xac, - 0x0b, 0xe7, 0xf5, 0x3f, 0xfa, 0x61, 0x9f, 0x45, 0x18, 0x1f, 0x5a, 0x4d, 0xbe, 0x5b, - 0x1b, 0x48, 0x09, 0x8e, 0xba, 0x2c, 0x2e, 0xc2, 0x0a, 0x0a, 0xc0, 0x44, 0x3b, 0xa8, - 0xe9, 0x48, 0x7b, 0xcf, 0x7d, - ], - script_code: Script(vec![0xac, 0x53, 0x63, 0x52, 0x6a, 0x51, 0xac]), - transparent_input: None, - hash_type: 1, - amount: 1501997449504444, - consensus_branch_id: consensus::BranchId::Sapling, - sighash: [ - 0xa1, 0xcf, 0x50, 0xcf, 0xfe, 0x59, 0xbe, 0x5f, 0x31, 0x5f, 0xfe, 0x51, 0x6e, 0x28, - 0x9e, 0xe8, 0x02, 0x5e, 0x59, 0x38, 0xf1, 0xe8, 0xe1, 0x88, 0x53, 0x7f, 0xf1, 0xa8, - 0x93, 0xac, 0x71, 0x14, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0x88, 0x1d, 0xdf, 0x4f, 0x95, - 0x78, 0x97, 0x34, 0xfc, 0xc1, 0x65, 0xee, 0x1e, 0x04, 0x40, 0x85, 0xb6, 0xe7, 0xa1, - 0x77, 0x50, 0x8c, 0x29, 0xda, 0x0c, 0xe7, 0x7d, 0xed, 0x75, 0x08, 0x98, 0xde, 0x89, - 0xd2, 0x60, 0xd3, 0x02, 0x63, 0x52, 0x44, 0xcc, 0x75, 0xe1, 0x98, 0x34, 0x52, 0x5f, - 0xba, 0x56, 0x90, 0x0d, 0xe9, 0x93, 0x85, 0x44, 0x2e, 0xb9, 0xec, 0x9a, 0x5f, 0x18, - 0x2b, 0x87, 0x5d, 0x70, 0xb5, 0xb1, 0x53, 0x79, 0x0a, 0x1e, 0xe7, 0x9c, 0x0e, 0x86, - 0x78, 0x37, 0x95, 0xfa, 0x06, 0x6a, 0x00, 0x63, 0x00, 0x00, 0x63, 0xfc, 0x92, 0x29, - 0x92, 0x00, 0x83, 0x64, 0xff, 0xfc, 0x7c, 0x00, 0xc0, 0x0e, 0x0f, 0x99, 0xde, 0x47, - 0x42, 0x89, 0x06, 0x00, 0x01, 0x39, 0x21, 0x97, 0xd6, 0x23, 0xf7, 0xeb, 0xda, 0x07, - 0xcd, 0x00, 0x58, 0xd9, 0xa1, 0xd1, 0x72, 0x04, 0x3c, 0x2f, 0xc9, 0x4f, 0x14, 0x19, - 0x3e, 0x27, 0x0e, 0xef, 0xe8, 0x3c, 0x3f, 0x01, 0xb2, 0x65, 0x05, 0x4c, 0x3f, 0x6a, - 0x60, 0xe2, 0xb7, 0x6e, 0x17, 0x56, 0x08, 0x8b, 0x87, 0xda, 0x83, 0x9f, 0x77, 0x2c, - 0xbd, 0x0f, 0x27, 0x5c, 0x92, 0x28, 0x38, 0x5a, 0x04, 0xbb, 0x50, 0xec, 0x3c, 0xfa, - 0x9e, 0xe2, 0xe1, 0x5b, 0x15, 0x3d, 0x4c, 0x85, 0xfe, 0x50, 0xb6, 0x00, 0x62, 0x58, - 0xe9, 0xe8, 0xc2, 0x52, 0x99, 0xc0, 0x9d, 0xf8, 0xb4, 0x55, 0x46, 0x6b, 0xa2, 0x5f, - 0x7e, 0x4c, 0x8f, 0xe7, 0xe2, 0x50, 0xed, 0xba, 0x60, 0x69, 0x5d, 0xa4, 0x7f, 0xaa, - 0xfd, 0xd6, 0x26, 0xba, 0x7e, 0x9d, 0x48, 0x96, 0xe4, 0xb8, 0xa8, 0xa1, 0xa1, 0xdc, - 0x21, 0x5b, 0x0a, 0x25, 0xee, 0xb0, 0x4e, 0xd1, 0xbe, 0xfb, 0x5b, 0x31, 0x38, 0xc6, - 0x9f, 0xe5, 0x28, 0xe7, 0x29, 0x11, 0x23, 0xfc, 0xdf, 0x8a, 0x36, 0x6c, 0x25, 0x7d, - 0x32, 0x95, 0x38, 0x25, 0x0a, 0x0c, 0xb7, 0xf5, 0x4e, 0x1c, 0x01, 0x6c, 0xe1, 0xc6, - 0x23, 0xb2, 0xe2, 0x76, 0xa5, 0x2c, 0x6e, 0x41, 0x24, 0x1b, 0x2a, 0xc5, 0x09, 0x37, - 0x3c, 0x18, 0x81, 0x40, 0xe8, 0x36, 0x5c, 0x94, 0xf5, 0x8c, 0x63, 0xf2, 0x7f, 0xf8, - 0xe6, 0xe8, 0x69, 0xa9, 0x85, 0xaf, 0xb6, 0x1e, 0x97, 0xd8, 0xce, 0xec, 0x2a, 0x78, - 0x24, 0xa5, 0xc1, 0x07, 0xb0, 0xba, 0xa4, 0xd6, 0xe7, 0x9a, 0x6c, 0x71, 0x87, 0x2a, - 0x7b, 0x3b, 0x17, 0xef, 0x91, 0x8a, 0xe4, 0xe2, 0x5f, 0x98, 0xa7, 0x2d, 0xb5, 0x3b, - 0xa7, 0xf2, 0x6e, 0x40, 0x8b, 0xd4, 0xd1, 0xf9, 0xe3, 0x47, 0x4d, 0xdc, 0xa5, 0x83, - 0x3f, 0xf5, 0xff, 0x8d, 0x11, 0xb1, 0xbf, 0x1e, 0x2b, 0xb4, 0xd1, 0x96, 0x8a, 0x82, - 0x38, 0x88, 0xbd, 0x91, 0xa2, 0x1a, 0x76, 0x79, 0x6b, 0xca, 0x44, 0x53, 0xe2, 0x89, - 0x2d, 0x1b, 0x6e, 0x13, 0x63, 0xed, 0x10, 0x7a, 0x9e, 0x7e, 0xd9, 0x3f, 0xb1, 0xda, - 0x99, 0x4a, 0x9d, 0x4e, 0x7e, 0xc9, 0x2e, 0x29, 0xa6, 0x87, 0xf2, 0x18, 0xd2, 0x8a, - 0x76, 0x46, 0x06, 0x9b, 0xca, 0xcb, 0x4d, 0xa7, 0xba, 0xdf, 0x4e, 0xb1, 0x33, 0x1a, - 0xab, 0x21, 0x2b, 0x92, 0xc6, 0xea, 0x64, 0x76, 0xa0, 0xa0, 0x9d, 0x6b, 0xd2, 0xe0, - 0xf7, 0x6f, 0xa8, 0x73, 0x79, 0xab, 0xfd, 0x17, 0x58, 0x2f, 0x3e, 0xb2, 0x3b, 0x86, - 0xc9, 0x66, 0x9f, 0x86, 0x73, 0x70, 0x48, 0xd7, 0x71, 0x84, 0x9b, 0x8f, 0x70, 0xbd, - 0x87, 0x99, 0x01, 0x3b, 0xe0, 0xbf, 0xbd, 0x7b, 0x57, 0xbe, 0xa1, 0xa4, 0x9a, 0x4a, - 0x39, 0x14, 0x79, 0x12, 0xd7, 0xba, 0xf6, 0x80, 0x04, 0xd4, 0x15, 0x02, 0x6b, 0xbc, - 0x6f, 0x69, 0x32, 0x5f, 0x4f, 0xf7, 0x87, 0x28, 0x77, 0x5a, 0x67, 0xaa, 0xdd, 0x72, - 0x2c, 0x73, 0x31, 0x1d, 0xba, 0x5c, 0x2c, 0xf1, 0x4c, 0xcb, 0xd5, 0x7e, 0xab, 0xed, - 0x71, 0x92, 0x0f, 0xf9, 0x62, 0x32, 0x89, 0xbb, 0x76, 0x05, 0x1c, 0x73, 0xa2, 0x06, - 0xa3, 0xc2, 0xb4, 0x0c, 0xac, 0x01, 0xd5, 0xf1, 0x1f, 0xa6, 0x4c, 0x1b, 0x7d, 0xed, - 0x70, 0xea, 0x17, 0x42, 0x9c, 0x66, 0x21, 0xca, 0x9b, 0x92, 0x3c, 0x48, 0x11, 0x85, - 0x0c, 0x3d, 0xf4, 0x01, 0x3d, 0x17, 0xbd, 0xc5, 0x10, 0x1c, 0x8d, 0x80, 0xb3, 0xa0, - 0x4a, 0x4c, 0xc2, 0x3d, 0x13, 0xfe, 0x31, 0x84, 0xe8, 0xb1, 0xad, 0xe6, 0x35, 0x17, - 0x59, 0x3f, 0x7b, 0xe6, 0x69, 0x48, 0xc0, 0x85, 0x7a, 0xec, 0xe0, 0x1b, 0xc2, 0x72, - 0x29, 0x5e, 0x60, 0xb1, 0x80, 0x69, 0x46, 0xc9, 0x3b, 0xc8, 0xc7, 0xd2, 0xa2, 0xed, - 0xc3, 0x7f, 0xa3, 0x7c, 0x47, 0x7a, 0x69, 0xa9, 0x0b, 0x59, 0xb4, 0xc6, 0x91, 0x2e, - 0x91, 0x3a, 0x57, 0xef, 0xa9, 0xd5, 0x4c, 0x7e, 0x80, 0xd5, 0xac, 0x8a, 0x42, 0x94, - 0xd0, 0xfd, 0x31, 0xa4, 0x02, 0xe4, 0xb4, 0x7e, 0xc7, 0xbf, 0x03, 0x31, 0xb2, 0xc9, - 0xa4, 0x8f, 0x44, 0x57, 0x3f, 0xc7, 0xe7, 0xf1, 0x02, 0xed, 0x48, 0xc9, 0x75, 0x08, - 0xcb, 0xe4, 0x30, 0x65, 0xa9, 0xe9, 0x9f, 0xb4, 0xce, 0x13, 0x62, 0xbb, 0x8a, 0x76, - 0xb1, 0x41, 0x9d, 0x95, 0x03, 0x0e, 0x9c, 0x24, 0xee, 0xba, 0x9f, 0xf8, 0xcf, 0xda, - 0x95, 0x7b, 0x17, 0x09, 0x8c, 0xdf, 0x8c, 0x9a, 0x91, 0x9e, 0x47, 0xa1, 0x3a, 0x5b, - 0x33, 0x46, 0xe3, 0x7e, 0x82, 0x7c, 0xc8, 0x3b, 0x3c, 0x9a, 0xab, 0xf2, 0xd0, 0xba, - 0x17, 0xff, 0x3d, 0x9e, 0x0d, 0x22, 0x3c, 0x41, 0xc8, 0x8e, 0xc2, 0x39, 0x1c, 0x76, - 0x62, 0x2d, 0x7b, 0xd6, 0x21, 0x17, 0x33, 0x1e, 0x21, 0xff, 0xec, 0x32, 0x72, 0xc1, - 0xe1, 0x42, 0x39, 0x82, 0xc6, 0xb6, 0x3a, 0xec, 0x8d, 0xbf, 0x5c, 0xa2, 0xdd, 0x15, - 0x81, 0x0f, 0x53, 0x42, 0xaf, 0x49, 0xfa, 0xd2, 0x79, 0xb7, 0xca, 0x23, 0xde, 0xd3, - 0x08, 0x24, 0x79, 0x96, 0x30, 0xde, 0xdc, 0x6d, 0xb7, 0x24, 0xbc, 0xe1, 0x11, 0x36, - 0x21, 0xc4, 0xa6, 0x47, 0x9d, 0xd5, 0x55, 0xf4, 0x85, 0x21, 0x7c, 0xb5, 0x67, 0x13, - 0x9e, 0xea, 0xdd, 0x7e, 0xe8, 0xdc, 0x5b, 0x26, 0x62, 0xf1, 0x06, 0x6a, 0x7c, 0x60, - 0xde, 0xe0, 0x09, 0x3c, 0x92, 0x46, 0xde, 0x7a, 0x05, 0xe8, 0xb0, 0xf6, 0xbe, 0xf0, - 0x03, 0x3d, 0xde, 0x2e, 0x87, 0xcb, 0xa6, 0x8d, 0x23, 0x6e, 0xf6, 0x6a, 0x23, 0xd5, - 0x5e, 0x7b, 0xd2, 0x8d, 0x02, 0x59, 0x9c, 0xca, 0x0d, 0xf7, 0xa9, 0x00, 0x63, 0x7b, - 0xb3, 0x46, 0x4d, 0x62, 0x2b, 0x7c, 0x9c, 0x9c, 0x8c, 0x91, 0x46, 0x89, 0x74, 0x88, - 0x01, 0x64, 0xde, 0xf7, 0x99, 0x90, 0x8a, 0x11, 0xa5, 0x91, 0xab, 0xb3, 0xc8, 0xd8, - 0xbd, 0x9c, 0x12, 0xb1, 0xf6, 0xf3, 0xcd, 0xc9, 0xed, 0x8e, 0x16, 0xe5, 0x7d, 0x23, - 0x34, 0xb2, 0x17, 0x79, 0x7d, 0xf1, 0x90, 0x52, 0xfe, 0xeb, 0xed, 0x6c, 0xdb, 0x99, - 0xac, 0x44, 0xea, 0x13, 0xaf, 0xea, 0xc4, 0x37, 0x7d, 0x0f, 0xa3, 0x7e, 0xf5, 0x16, - 0xdd, 0xac, 0xea, 0xb0, 0xd9, 0x39, 0x5b, 0xd4, 0x40, 0x46, 0x0e, 0x28, 0xb5, 0xf5, - 0x7a, 0x6e, 0xfd, 0x37, 0xd2, 0x68, 0xa8, 0x64, 0xcb, 0x5c, 0xa3, 0x4b, 0xe2, 0x87, - 0xe1, 0x04, 0x8e, 0xfc, 0x1e, 0x40, 0xcd, 0xf4, 0xfc, 0xfc, 0x02, 0x4c, 0xf1, 0x82, - 0x03, 0x8b, 0x9d, 0x80, 0xed, 0x1c, 0x07, 0x63, 0x62, 0x00, 0xc8, 0x19, 0xa7, 0xe7, - 0xc2, 0x40, 0xc3, 0xc4, 0xf7, 0xa9, 0x17, 0x32, 0xe3, 0xff, 0x13, 0xe2, 0xa5, 0x6a, - 0x64, 0x66, 0x66, 0x10, 0xca, 0xd9, 0x84, 0x1c, 0x1a, 0x93, 0x4f, 0xe9, 0x33, 0xb0, - 0xf1, 0x9f, 0xb7, 0x1d, 0x06, 0x1c, 0x58, 0xf2, 0x1a, 0x49, 0x81, 0xce, 0x3e, 0x68, - 0xc5, 0x02, 0x39, 0x03, 0x60, 0x8d, 0xe5, 0x83, 0x02, 0xc6, 0xc8, 0xde, 0xf4, 0xe5, - 0x61, 0x9e, 0xc0, 0xd9, 0x1c, 0xf9, 0x35, 0x44, 0x75, 0x97, 0x2b, 0xfe, 0x0d, 0x75, - 0x75, 0x60, 0x2a, 0xaf, 0x0e, 0x9e, 0x88, 0x5c, 0x6b, 0xaf, 0x9d, 0x56, 0x7b, 0x1f, - 0xcb, 0x63, 0x19, 0x0c, 0xb7, 0x92, 0xf1, 0xd8, 0x71, 0x61, 0x1a, 0xdb, 0x4f, 0x3d, - 0x1e, 0xd3, 0x28, 0x02, 0x69, 0x18, 0xe2, 0x8d, 0x2f, 0xd4, 0x5a, 0xb9, 0xd3, 0x70, - 0xe7, 0x29, 0x2e, 0xd7, 0x54, 0xce, 0x29, 0xfb, 0x78, 0x7f, 0xd5, 0xd0, 0x9e, 0x6d, - 0x47, 0xcb, 0xc8, 0x00, 0x21, 0xab, 0xf7, 0xd2, 0xef, 0xeb, 0xdb, 0xe0, 0xad, 0xd8, - 0x70, 0x16, 0x8f, 0x51, 0xdc, 0xc4, 0x09, 0x57, 0xa4, 0xa3, 0xc8, 0xe1, 0x92, 0x60, - 0x13, 0x83, 0xb7, 0x68, 0x41, 0x36, 0xdc, 0xa2, 0x82, 0x62, 0x3f, 0x31, 0xba, 0x7a, - 0xe5, 0x36, 0x6b, 0x45, 0x3c, 0x6a, 0x26, 0xf6, 0x8a, 0x14, 0xdb, 0x65, 0x59, 0xbc, - 0xb1, 0x02, 0x37, 0x37, 0x9a, 0x27, 0xa9, 0x50, 0x2f, 0xf9, 0xd6, 0x4a, 0x33, 0x83, - 0x20, 0x75, 0x15, 0x30, 0xf1, 0xf8, 0x92, 0xa6, 0xd4, 0x6f, 0x50, 0x31, 0x1b, 0x5e, - 0x18, 0xf0, 0x33, 0x6f, 0xc4, 0x77, 0x21, 0x56, 0x66, 0xe1, 0x88, 0x93, 0x3c, 0x69, - 0x39, 0x98, 0x9f, 0x6e, 0x6a, 0x3a, 0xdb, 0xa2, 0x29, 0x96, 0xaa, 0xe6, 0xa0, 0xfe, - 0x1b, 0xdd, 0xcb, 0xe1, 0x49, 0x6d, 0x96, 0x8d, 0xe0, 0x93, 0xdf, 0x44, 0xa3, 0x30, - 0x0f, 0x75, 0x15, 0xa1, 0x2c, 0x9d, 0x82, 0x22, 0x6d, 0x6b, 0x4d, 0x62, 0xc4, 0x6a, - 0x21, 0x3d, 0x5f, 0x01, 0x07, 0x10, 0x6f, 0xd2, 0xa2, 0x2d, 0x3b, 0x59, 0x86, 0x13, - 0xdb, 0x49, 0x1f, 0x70, 0xcc, 0xb1, 0xf0, 0x3b, 0x86, 0x59, 0x66, 0x9e, 0xd7, 0x44, - 0x34, 0xe4, 0x3b, 0x77, 0x1f, 0x22, 0x78, 0x07, 0x10, 0xfb, 0xd8, 0xf2, 0xf2, 0x0e, - 0x98, 0x97, 0xdf, 0x5c, 0xc2, 0x35, 0x48, 0x77, 0x9c, 0x6c, 0x08, 0x30, 0x83, 0x9d, - 0x23, 0x1c, 0x3f, 0xf9, 0xac, 0x54, 0x40, 0x7d, 0xfd, 0xfc, 0xc5, 0x90, 0x14, 0xbf, - 0x67, 0xd9, 0x68, 0x57, 0x06, 0xa5, 0x62, 0x2e, 0x38, 0xf7, 0xa9, 0x33, 0xc3, 0x4a, - 0xfb, 0xb6, 0xaa, 0x8c, 0xdf, 0xd9, 0x3b, 0xd2, 0xec, 0x91, 0xad, 0x37, 0x90, 0x4c, - 0xe1, 0x3b, 0x8a, 0xb8, 0xef, 0x77, 0x23, 0x66, 0xfa, 0xd3, 0xc3, 0xeb, 0xee, 0x8f, - 0x26, 0x11, 0xee, 0x7b, 0x6c, 0x2a, 0xf7, 0xe6, 0x53, 0xef, 0xbe, 0xc4, 0xdc, 0x4c, - 0xbf, 0x13, 0xac, 0xf3, 0x7e, 0x39, 0x9e, 0x2b, 0x0b, 0x05, 0xb6, 0x1c, 0xb7, 0xe1, - 0x7b, 0x15, 0x62, 0x7b, 0x62, 0x96, 0x2e, 0x21, 0x00, 0xb1, 0x95, 0xfe, 0xfe, 0x94, - 0xbc, 0x48, 0x4e, 0x88, 0x13, 0x97, 0x00, 0x73, 0x7d, 0xe1, 0xa5, 0xec, 0x7d, 0x9c, - 0xc8, 0x5d, 0x53, 0x3b, 0x61, 0xec, 0xad, 0x86, 0x53, 0xce, 0xdb, 0xb7, 0x71, 0xf6, - 0x75, 0xaf, 0x61, 0xe4, 0xc6, 0xf7, 0xef, 0xaa, 0xcc, 0x9f, 0x7e, 0x42, 0x4c, 0x16, - 0x71, 0x5b, 0x0a, 0x98, 0xc4, 0x46, 0x05, 0x9a, 0x27, 0x1a, 0x27, 0xbd, 0x56, 0x9d, - 0x1b, 0x5d, 0xbf, 0xae, 0x8f, 0x53, 0x89, 0x85, 0x24, 0xca, 0xe8, 0x70, 0x59, 0xff, - 0x34, 0xfb, 0x2a, 0x53, 0x32, 0x26, 0xbd, 0x29, 0xa0, 0xba, 0x6f, 0x8d, 0x08, 0x36, - 0xfd, 0x0a, 0x4c, 0x0d, 0x60, 0x9a, 0x72, 0xe1, 0x05, 0x39, 0xa4, 0x4f, 0x8c, 0x39, - 0xf6, 0x27, 0x9b, 0xe3, 0x96, 0xe4, 0x1c, 0xa9, 0xf2, 0x9a, 0x28, 0xce, 0x9f, 0xa0, - 0xdd, 0x51, 0xa3, 0x02, 0xe7, 0x70, 0xe1, 0xe3, 0xdb, 0x70, 0x6a, 0x34, 0xcb, 0x90, - 0x4e, 0xf0, 0x8d, 0x9c, 0x82, 0xc5, 0x5b, 0xc7, 0x28, 0xc9, 0x55, 0xb1, 0x20, 0xbb, - 0x2e, 0xc3, 0x73, 0xfc, 0xff, 0xff, 0x3c, 0x46, 0xd6, 0x03, 0xab, 0x38, 0x78, 0x96, - 0xd4, 0x9c, 0xd2, 0x1b, 0x2f, 0x77, 0xec, 0xfb, 0xbb, 0x02, 0xa5, 0xe1, 0x53, 0xb1, - 0x71, 0xaf, 0xed, 0x98, 0x6c, 0x15, 0xda, 0x6f, 0x2d, 0x4c, 0xf7, 0x45, 0xd1, 0x99, - 0x5f, 0x51, 0x36, 0xe1, 0xb3, 0xe6, 0x8a, 0x67, 0xa8, 0x99, 0x6f, 0xe7, 0x65, 0x61, - 0x6d, 0x8a, 0xa1, 0x1b, 0xcd, 0x9f, 0x8b, 0x59, 0x1d, 0xb8, 0x7e, 0xfc, 0xda, 0xaf, - 0xfd, 0x41, 0x00, 0x3e, 0xc7, 0x29, 0x36, 0x05, 0x42, 0x62, 0x08, 0x54, 0xfb, 0x04, - 0xb8, 0x0c, 0xb8, 0x61, 0xa6, 0x36, 0xa4, 0x71, 0x7d, 0x66, 0x68, 0x94, 0xc3, 0x2f, - 0x1f, 0x2b, 0xf2, 0x24, 0x7c, 0xc4, 0x15, 0xde, 0x1d, 0x0c, 0x4e, 0x71, 0x2b, 0x95, - 0x88, 0x42, 0xd6, 0xa4, 0xb2, 0x76, 0xde, 0xa5, 0xdb, 0x88, 0x42, 0x3f, 0x2b, 0x4c, - 0x66, 0x4b, 0x1d, 0x2b, 0x18, 0x77, 0xba, 0xf3, 0x37, 0x47, 0x34, 0x36, 0x14, 0xe5, - 0xeb, 0xe9, 0xb7, 0xe1, 0x2e, 0xd0, 0x15, 0x3f, 0x9c, 0xa7, 0x45, 0x8e, 0x4d, 0xa4, - 0x97, 0x63, 0x9d, 0xff, 0x13, 0x52, 0xff, 0x0e, 0xfa, 0xe0, 0x1d, 0x14, 0x03, 0x21, - 0xc2, 0x8d, 0xd0, 0xb6, 0x7b, 0x06, 0x98, 0x90, 0xf6, 0x13, 0x0f, 0x82, 0x46, 0xab, - 0x85, 0x44, 0x71, 0x75, 0x32, 0xd3, 0xa5, 0xf6, 0x36, 0x39, 0xa9, 0x9d, 0x7f, 0x8e, - 0x98, 0x31, 0xc6, 0x48, 0x51, 0xb7, 0xef, 0x68, 0x93, 0xb3, 0xc9, 0x74, 0x0f, 0x98, - 0x44, 0xd1, 0x8a, 0x61, 0x3b, 0x5f, 0x9a, 0x6a, 0xb4, 0xbd, 0x6e, 0x6a, 0x93, 0xe8, - 0xe4, 0xbe, 0xa5, 0x57, 0x5d, 0x2c, 0xb4, 0x33, 0x0c, 0x0a, 0xf8, 0x55, 0x83, 0x19, - 0xa9, 0x09, 0xa5, 0x98, 0x8a, 0x99, 0x2e, 0x40, 0x63, 0x43, 0xdd, 0x1c, 0x74, 0x2d, - 0x64, 0xcd, 0x4a, 0x17, 0xa2, 0xf3, 0x79, 0x5e, 0x8d, 0xb4, 0xd3, 0x0c, 0xcd, 0xf4, - 0x41, 0x56, 0x55, 0xed, 0xa7, 0xb4, 0x37, 0xe3, 0x39, 0x73, 0x23, 0x89, 0x6b, 0x11, - 0xb1, 0xbe, 0xd7, 0x2d, 0x63, 0xe3, 0x10, 0xaa, 0x49, 0x67, 0x1d, 0x85, 0x53, 0x4f, - 0x6d, 0xbc, 0x18, 0x1f, 0xeb, 0xb5, 0xbd, 0xc0, 0x8a, 0xc0, 0xd1, 0x23, 0x82, 0x9d, - 0x10, 0x8c, 0xd2, 0x69, 0xf3, 0xb0, 0xa3, 0x96, 0xf4, 0x24, 0x1e, 0x7d, 0xda, 0x72, - 0xf5, 0x48, 0x62, 0xbe, 0xde, 0xf0, 0x1c, 0x12, 0xe3, 0xc6, 0xcf, 0xdf, 0x75, 0xf6, - 0x76, 0xc2, 0xdd, 0xef, 0x91, 0xaf, 0x7f, 0x8a, 0x8a, 0x76, 0x9c, 0x25, 0xe1, 0x77, - 0xcd, 0x43, 0x0b, 0xed, 0xe7, 0x4b, 0x57, 0x69, 0x05, 0x19, 0xa9, 0x8d, 0xb1, 0xfb, - 0x5c, 0x36, 0x12, 0x80, 0xf7, 0x54, 0x0a, 0xc8, 0x27, 0xa9, 0x1b, 0x2d, 0x08, 0x75, - 0x2d, 0xec, 0xfb, 0x71, 0x56, 0xfc, 0xdb, 0x61, 0x75, 0x78, 0xb0, 0x53, 0xee, 0xe4, - 0x1f, 0x66, 0xa6, 0x0e, 0x04, 0x5c, 0x3a, 0x56, 0x9f, 0x3f, 0x7e, 0xdb, 0x76, 0x31, - 0x68, 0x2f, 0xde, 0x9e, 0xf9, 0x1e, 0xa8, 0x81, 0x1f, 0xc2, 0xc7, 0x8f, 0x64, 0x6a, - 0xf6, 0xb4, 0x71, 0x0e, 0xdb, 0xb8, 0xbf, 0x23, 0x28, 0xbd, 0x32, 0x73, 0xa2, 0xcb, - 0x72, 0xff, 0xcc, 0xa7, 0xc2, 0x17, 0xb8, 0x27, 0x19, 0x2d, 0xd2, 0xea, 0x92, 0x9e, - 0x97, 0x6d, 0x13, 0x1c, 0x9d, 0x20, 0x2e, 0xc5, 0x06, 0xa3, 0x5d, 0x93, 0xab, 0x21, - 0x6f, 0x64, 0xbd, 0x73, 0xfe, 0x5d, 0x8a, 0xba, 0xe4, 0x57, 0x1f, 0x85, 0xbe, 0xb8, - 0x4a, 0x7f, 0x93, 0xa3, 0xde, 0x37, 0xa4, 0x51, 0xf3, 0x08, 0xf7, 0xde, 0x6c, 0xcd, - 0x1a, 0x6e, 0xef, 0xef, 0x24, 0x69, 0x9f, 0x21, 0x58, 0xd1, 0x26, 0x1f, 0xe2, 0x51, - 0x82, 0xb5, 0x02, 0xda, 0x3e, 0x74, 0x61, 0x1a, 0x61, 0x16, 0xfc, 0x30, 0x64, 0xfa, - 0x72, 0x3c, 0x5a, 0x81, 0xad, 0xc0, 0xa3, 0x2f, 0x1e, 0xd6, 0x29, 0x91, 0x57, 0xd1, - 0xc1, 0x1c, 0x0a, 0xd9, 0x90, 0x41, 0x89, 0x46, 0x96, 0x30, 0x1d, 0x5b, 0x3f, 0x1b, - 0xf4, 0x32, 0x05, 0xd7, 0xdc, 0xcf, 0xa6, 0x8b, 0xbb, 0x4a, 0x1f, 0x5e, 0x24, 0x2b, - 0x3e, 0x69, 0x0b, 0xfc, 0x97, 0xb9, 0x43, 0x66, 0xa3, 0x43, 0xf5, 0xdd, 0x16, 0xdf, - 0x67, 0xb2, 0xed, 0x2b, 0xe2, 0x1c, 0x74, 0x71, 0x18, 0x87, 0x2b, 0x46, 0x2e, 0xe2, - 0x0c, 0x77, 0x8c, 0xed, 0x85, 0x6f, 0xa9, 0x80, 0x40, 0x3f, 0xb2, 0x4b, 0x78, 0x61, - 0x37, 0xd0, 0xef, 0x02, 0x78, 0x53, 0x9b, 0x00, 0xce, 0x6e, 0x23, 0xc0, 0x7e, 0xf2, - 0xa0, 0x7c, 0xb2, 0x4c, 0x51, 0xc5, 0xb4, 0x85, 0xe4, 0x54, 0xed, 0xf6, 0x61, 0xdb, - 0x4b, 0x93, 0x1a, 0xb8, 0xcb, 0x49, 0x4e, 0xb3, 0x94, 0xfd, 0x13, 0xc1, 0xb3, 0x20, - 0x85, 0xf2, 0x7b, 0x20, 0x4a, 0x4b, 0x87, 0xee, 0x6c, 0x80, 0x63, 0x45, 0xd7, 0x58, - 0x4c, 0xb1, 0x61, 0x00, 0x6a, 0xd9, 0x84, 0x8a, 0x24, 0xa2, 0x2a, 0x57, 0x71, 0xe3, - 0xa2, 0xab, 0x65, 0x46, 0x3f, 0x55, 0x3d, 0x52, 0xcd, 0x53, 0x5e, 0xf1, 0x0b, 0xdd, - 0x40, 0xd8, 0x87, 0x73, 0x72, 0xa5, 0x32, 0xe3, 0x73, 0x1b, 0x0e, 0xe9, 0x0c, 0x04, - 0xe8, 0xe4, 0x37, 0x47, 0xcc, 0x3e, 0xb9, 0x6b, 0xb8, 0x79, 0xbd, 0x94, 0xd7, 0x01, - 0x2a, 0xf4, 0x6a, 0x93, 0xba, 0x17, 0x70, 0x37, 0xf0, 0x62, 0x74, 0x4d, 0x3f, 0xdf, - 0xcc, 0xd3, 0x6a, 0xab, 0xe0, 0xf8, 0xcc, 0xca, 0x19, 0xdc, 0xf7, 0x84, 0x1b, 0x1e, - 0xe2, 0xf4, 0xfe, 0xb1, 0x80, 0x0e, 0x75, 0x44, 0x1c, 0x51, 0xe9, 0x5c, 0xce, 0x94, - 0xce, 0xee, 0xcd, 0x85, 0x87, 0xfb, 0xf5, 0x74, 0x30, 0x8d, 0xd7, 0x63, 0x63, 0x1b, - 0x73, 0x35, 0x78, 0x30, 0x91, 0xf4, 0xc8, 0xb3, 0xc8, 0xfb, 0x3c, 0xd9, 0x39, 0x70, - 0xce, 0xf0, 0xed, 0xa4, 0xca, 0x08, 0x44, 0x75, 0x68, 0x23, 0x9c, 0x02, 0xfe, 0x8f, - 0x67, 0x5e, 0x15, 0xc4, 0x9b, 0x51, 0x21, 0xb1, 0x00, 0xcc, 0x19, 0xfc, 0xc2, 0xb2, - 0x91, 0x3d, 0xf7, 0x4f, 0x75, 0x8f, 0x70, 0xbd, 0x6e, 0xeb, 0x73, 0x39, 0x51, 0x6e, - 0x5f, 0x1e, 0xff, 0x97, 0x00, 0xf8, 0xee, 0x13, 0x0e, 0x5c, 0x84, 0xce, 0xd7, 0xb1, - 0xce, 0xd6, 0x6b, 0xe9, 0xa0, 0x55, 0x96, 0xbe, 0x8e, 0x55, 0xf6, 0xd9, 0xfd, 0xf7, - 0xcf, 0x0f, 0xa6, 0x22, 0x90, 0xec, 0x67, 0x0b, 0x6b, 0xdd, 0x67, 0x38, 0xbb, 0x5c, - 0xfb, 0x34, 0x1e, 0xf5, 0xff, 0xb4, 0x2b, 0xc2, 0xab, 0xc5, 0x08, 0xff, 0x23, 0x12, - 0x48, 0xf2, 0xc2, 0xdc, 0x15, 0x77, 0x0d, 0x33, 0x72, 0x2b, 0x9c, 0x9d, 0xae, - ], - script_code: Script(vec![0xac, 0x65]), - transparent_input: Some(0), - hash_type: 3, - amount: 391892287957268, - consensus_branch_id: consensus::BranchId::Sapling, - sighash: [ - 0x6a, 0x3b, 0x2b, 0xcc, 0x15, 0x57, 0x89, 0xa2, 0x74, 0x39, 0xaa, 0x27, 0x5c, 0xa9, - 0x9e, 0xc6, 0x48, 0xdd, 0xd5, 0x88, 0xe8, 0x2e, 0xfa, 0xe4, 0xac, 0x46, 0xba, 0x3f, - 0xd0, 0xe3, 0xbb, 0xa0, - ], - }, - ]; - - for tv in test_vectors { + for tv in self::data::zip_0243::make_test_vectors() { let tx = Transaction::read(&tv.tx[..]).unwrap(); let transparent_input = if let Some(n) = tv.transparent_input { Some(( @@ -5407,7 +107,7 @@ fn zip_0243() { }; assert_eq!( - signature_hash(&tx, tv.consensus_branch_id, tv.hash_type, transparent_input,), + signature_hash(&tx, tv.consensus_branch_id, tv.hash_type, transparent_input), tv.sighash ); } diff --git a/zcash_primitives/src/transaction/tests/data.rs b/zcash_primitives/src/transaction/tests/data.rs new file mode 100644 index 0000000..28dd054 --- /dev/null +++ b/zcash_primitives/src/transaction/tests/data.rs @@ -0,0 +1,5686 @@ +pub mod tx_read_write { + // TxID: 64f0bd7fe30ce23753358fe3a2dc835b8fba9c0274c4e2c54a6f73114cb55639 + // From testnet block 280003. + pub const TX_READ_WRITE: [u8; 2005] = [ + 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x01, 0x8f, 0x64, 0x29, 0x96, 0xdf, 0x1e, + 0x93, 0xa6, 0xd7, 0x9a, 0xe5, 0xba, 0xae, 0x34, 0x93, 0xf4, 0x23, 0xca, 0x6c, 0x82, 0xe9, + 0x9f, 0x3e, 0x8d, 0x95, 0x24, 0xfa, 0x78, 0xbc, 0xf1, 0x61, 0x67, 0x00, 0x00, 0x00, 0x00, + 0x6b, 0x48, 0x30, 0x45, 0x02, 0x21, 0x00, 0xb6, 0x5e, 0x37, 0x22, 0x97, 0x07, 0xd9, 0xcd, + 0x48, 0x39, 0x40, 0xd2, 0xab, 0x8b, 0xdc, 0x0b, 0x74, 0xb1, 0x2d, 0xda, 0x66, 0xd0, 0x2d, + 0xbd, 0xf3, 0x6f, 0xd3, 0x83, 0xb9, 0x60, 0x2a, 0x51, 0x02, 0x20, 0x4b, 0xe7, 0xfd, 0x7a, + 0x39, 0xa4, 0xa4, 0x2d, 0xff, 0x07, 0x1a, 0x5a, 0x2b, 0xc5, 0x1b, 0x49, 0x2d, 0x33, 0xf0, + 0xbc, 0x39, 0x4b, 0xc8, 0x78, 0x61, 0xe1, 0xbc, 0xaa, 0xf2, 0xba, 0xc9, 0x3b, 0x01, 0x21, + 0x02, 0x48, 0xe7, 0x8b, 0xdc, 0x18, 0xf1, 0xa8, 0x31, 0x10, 0xc1, 0x2e, 0x40, 0x08, 0xb7, + 0x64, 0x02, 0x69, 0x61, 0xb1, 0x68, 0xfe, 0x8d, 0x5a, 0x8d, 0x94, 0x7e, 0xfe, 0x6a, 0xf8, + 0x3c, 0xc8, 0x8e, 0xff, 0xff, 0xff, 0xff, 0x01, 0xf0, 0xf2, 0x70, 0x18, 0x02, 0x00, 0x00, + 0x00, 0x19, 0x76, 0xa9, 0x14, 0xa2, 0x84, 0xd0, 0x51, 0x1d, 0x0e, 0x52, 0x0d, 0x36, 0xf4, + 0x44, 0xa3, 0x6c, 0x10, 0xbf, 0x54, 0xb4, 0xb0, 0x17, 0xcd, 0x88, 0xac, 0x00, 0x00, 0x00, + 0x00, 0xd7, 0x45, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0xca, 0x9a, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x13, 0x31, 0xa3, 0x05, 0x9e, 0x66, 0xaa, 0x6c, 0xa9, 0x7a, 0x62, 0xf5, 0x6e, + 0xa2, 0x34, 0x20, 0x75, 0x68, 0x56, 0x6f, 0x69, 0x71, 0xb3, 0x72, 0x2a, 0xe0, 0xdd, 0x82, + 0xc0, 0x03, 0x99, 0x69, 0x2a, 0xac, 0xb5, 0xfb, 0x12, 0xac, 0x58, 0x0a, 0xc2, 0x66, 0x24, + 0xa8, 0xcf, 0x0a, 0x90, 0x4c, 0xd6, 0xf4, 0xbf, 0xea, 0x55, 0x62, 0x52, 0x05, 0xcb, 0x58, + 0xf0, 0x6b, 0x1c, 0x19, 0x74, 0x23, 0x28, 0x0d, 0xea, 0xc7, 0x4e, 0xea, 0x97, 0x59, 0x8c, + 0x43, 0x14, 0xd8, 0x99, 0xa4, 0xfd, 0x85, 0x31, 0x1e, 0x04, 0x62, 0x57, 0xd2, 0xd4, 0xc2, + 0x97, 0xf1, 0x40, 0x6c, 0xf7, 0x09, 0xd9, 0x2a, 0x86, 0x07, 0xf7, 0x69, 0x8d, 0x45, 0xfe, + 0x9f, 0x41, 0xde, 0xa3, 0xa0, 0x57, 0x1c, 0x5d, 0xa5, 0xcf, 0xa7, 0x8e, 0x18, 0xeb, 0xf5, + 0x80, 0xc3, 0x61, 0x79, 0xd9, 0xd6, 0xe6, 0x32, 0x0a, 0x34, 0x8f, 0x14, 0x6c, 0x40, 0x7a, + 0xda, 0xb4, 0xcb, 0x31, 0x03, 0x92, 0xa5, 0xf5, 0xb5, 0xab, 0x28, 0x3b, 0x78, 0x34, 0x3b, + 0xa9, 0x1a, 0xbc, 0x7c, 0x4b, 0xfe, 0x23, 0xa3, 0xdb, 0xaf, 0x80, 0x37, 0xc6, 0x76, 0xe5, + 0x95, 0xa2, 0x65, 0x74, 0xb1, 0x81, 0x3b, 0xc2, 0xbf, 0x2d, 0x2e, 0x91, 0x1f, 0x6f, 0x3a, + 0xbb, 0x0b, 0xa6, 0xbc, 0xac, 0x7a, 0x29, 0x01, 0xfb, 0xdc, 0xe6, 0x5f, 0xb0, 0x7b, 0x56, + 0x36, 0x01, 0x7e, 0xf1, 0x4d, 0xff, 0x44, 0xcd, 0xee, 0xa7, 0x30, 0x47, 0x72, 0x94, 0xf2, + 0xf8, 0x61, 0x9b, 0xd3, 0xd5, 0xe6, 0xbe, 0x48, 0x98, 0xbf, 0x8d, 0x39, 0xc0, 0xe0, 0xea, + 0xe5, 0xa3, 0x68, 0x64, 0x62, 0x52, 0x06, 0xb9, 0xa8, 0xf9, 0x94, 0x0b, 0xf1, 0x66, 0x50, + 0xde, 0xf7, 0x92, 0x6e, 0xb0, 0xdb, 0x43, 0xb7, 0xd7, 0x61, 0x5e, 0x47, 0x74, 0xcf, 0x10, + 0x94, 0x82, 0xf2, 0xe8, 0x07, 0xfe, 0xe6, 0xc0, 0xc8, 0x84, 0xe8, 0x31, 0x4c, 0x67, 0xc5, + 0xd8, 0x5f, 0x4c, 0x22, 0x9c, 0xde, 0xab, 0x1e, 0x96, 0x4c, 0xf0, 0xc1, 0xad, 0xcb, 0x47, + 0xce, 0xbf, 0xc7, 0xc0, 0x67, 0xa0, 0xf3, 0xc8, 0x06, 0x81, 0x4a, 0x28, 0x5e, 0xdb, 0xb6, + 0x24, 0xf4, 0x71, 0x06, 0x29, 0x09, 0x89, 0x44, 0xac, 0x75, 0xe7, 0xc9, 0xcb, 0xc5, 0x6b, + 0xd0, 0xa0, 0x29, 0xe1, 0x11, 0x0e, 0xac, 0x60, 0xcb, 0x40, 0x77, 0xeb, 0xf1, 0x08, 0xfe, + 0x3e, 0x67, 0xcd, 0x06, 0x13, 0x91, 0xe5, 0xd6, 0x91, 0x6d, 0x5f, 0x41, 0xc0, 0x2b, 0x89, + 0x14, 0xc1, 0x2c, 0xf6, 0x05, 0xdb, 0x7d, 0x95, 0x92, 0x26, 0xe2, 0xe8, 0xff, 0x71, 0x26, + 0x3b, 0x9a, 0xf4, 0xc5, 0x9b, 0x0f, 0x4d, 0xb3, 0x15, 0xb7, 0x4c, 0xa2, 0xb0, 0xb7, 0xd2, + 0x52, 0x13, 0xd5, 0x29, 0x39, 0x54, 0xc3, 0xe5, 0x11, 0x72, 0x37, 0x0f, 0xb6, 0xc3, 0x5a, + 0xbe, 0x9c, 0xe3, 0x6e, 0xf2, 0x53, 0xe3, 0xa7, 0x2e, 0x19, 0xda, 0xc9, 0xbd, 0x73, 0x62, + 0xc4, 0x49, 0x92, 0x97, 0x42, 0x15, 0xc8, 0x2c, 0xb9, 0x0c, 0x99, 0x48, 0x8d, 0xbd, 0xe1, + 0x19, 0x63, 0xe8, 0x57, 0xce, 0xa6, 0xb8, 0x1b, 0x8e, 0xaa, 0xe3, 0x4b, 0x7c, 0xf5, 0xa9, + 0x7d, 0x6b, 0x60, 0xd4, 0x9f, 0xdf, 0xa2, 0x0f, 0x5f, 0x3c, 0x12, 0x0e, 0xf3, 0x82, 0xca, + 0x24, 0x69, 0x60, 0x4f, 0xb0, 0xc6, 0x84, 0x2c, 0x6d, 0x4f, 0xae, 0x96, 0x61, 0x66, 0x5b, + 0x5c, 0xbc, 0x61, 0x2c, 0xef, 0x13, 0x2f, 0x88, 0xfb, 0x7d, 0xa3, 0x93, 0xf3, 0x56, 0xe3, + 0xad, 0x13, 0xfc, 0x35, 0x57, 0x98, 0x0a, 0x77, 0x34, 0x23, 0x14, 0x53, 0xe4, 0x40, 0x79, + 0x04, 0x2f, 0xb4, 0x32, 0xf5, 0x5e, 0x75, 0x14, 0x84, 0xd5, 0xd6, 0xd3, 0x0f, 0xbc, 0x4f, + 0x99, 0x90, 0x13, 0xd5, 0xd4, 0xf2, 0xfb, 0x62, 0xf7, 0x14, 0x4e, 0x8d, 0xcd, 0x2a, 0xe5, + 0x95, 0x46, 0xcc, 0x43, 0x79, 0xad, 0x9f, 0x18, 0x59, 0xef, 0x80, 0xde, 0xc6, 0x6b, 0x1a, + 0x9b, 0x0b, 0x7f, 0xd2, 0xc4, 0x7b, 0xd3, 0x83, 0x02, 0xd2, 0x9c, 0x31, 0x99, 0x03, 0x29, + 0xa8, 0x95, 0x87, 0x6e, 0xd1, 0xd8, 0x4d, 0xb7, 0x57, 0x85, 0x6e, 0x75, 0xce, 0x9a, 0x1d, + 0xc7, 0xc7, 0x47, 0x2b, 0xc2, 0x18, 0xfb, 0x8d, 0x7c, 0x7d, 0x02, 0x8b, 0xb0, 0x2f, 0x10, + 0xef, 0xe7, 0xfe, 0x6a, 0x8c, 0x9c, 0xe0, 0x34, 0xfe, 0xa6, 0x6b, 0x90, 0x9c, 0x8d, 0x41, + 0x26, 0x25, 0x1c, 0x7d, 0x6e, 0x54, 0xf4, 0xcf, 0xc7, 0x78, 0xcd, 0x4f, 0x0e, 0x0b, 0xad, + 0x10, 0x96, 0x17, 0x6f, 0x2d, 0xd4, 0x5c, 0x45, 0xcb, 0xe1, 0x5e, 0x11, 0x8f, 0x90, 0xff, + 0x25, 0x45, 0xf8, 0x32, 0xf2, 0x36, 0x98, 0xf2, 0xc9, 0x53, 0x1b, 0x52, 0x65, 0x5a, 0x4c, + 0x0c, 0x89, 0x53, 0x55, 0x99, 0x28, 0xee, 0xdf, 0xc7, 0x56, 0xc3, 0x65, 0xcf, 0x92, 0x9b, + 0x84, 0x47, 0xdc, 0xdc, 0x7d, 0x82, 0x38, 0x49, 0xe0, 0x2f, 0xf6, 0x8b, 0x62, 0x78, 0xd7, + 0x54, 0x2c, 0xe0, 0xf1, 0x07, 0x0b, 0xb1, 0xad, 0x91, 0x3c, 0x1a, 0x35, 0x36, 0x25, 0xf5, + 0xd3, 0x5b, 0x14, 0xcf, 0xec, 0x84, 0xa6, 0x33, 0xd7, 0xfe, 0x25, 0x25, 0x6d, 0xcf, 0xfe, + 0x92, 0xf9, 0xa6, 0xf0, 0xfe, 0x00, 0xca, 0xaa, 0xa5, 0xb3, 0x9c, 0xc2, 0xab, 0x06, 0x76, + 0x8a, 0x42, 0xa5, 0xb4, 0x00, 0x83, 0xce, 0xa0, 0x1c, 0x96, 0xb3, 0xe6, 0x8d, 0x0f, 0x6a, + 0x58, 0x7e, 0xaf, 0x2d, 0xa6, 0xfd, 0xad, 0xc8, 0x25, 0x27, 0xf1, 0x86, 0xa6, 0x04, 0x71, + 0xce, 0x98, 0xe2, 0x7d, 0x2b, 0x11, 0xef, 0xc4, 0x79, 0x98, 0xf3, 0x03, 0x0a, 0x7a, 0x2e, + 0x5d, 0x0b, 0x0a, 0x7e, 0xb8, 0x0f, 0x6b, 0xd0, 0xe4, 0xb9, 0xc8, 0x36, 0x7c, 0x6c, 0x52, + 0x2d, 0x94, 0x15, 0xf8, 0xca, 0xec, 0x7b, 0x0a, 0x73, 0x18, 0xd5, 0x3d, 0xce, 0x39, 0x1c, + 0xf7, 0xe7, 0x38, 0x9c, 0x9a, 0x74, 0xaa, 0x6a, 0x4c, 0x21, 0x7c, 0x28, 0x85, 0x19, 0xaf, + 0x81, 0xba, 0x21, 0x22, 0xca, 0x0c, 0x58, 0x40, 0xcc, 0x02, 0xcf, 0x1b, 0xcf, 0x15, 0x0c, + 0xd3, 0xdf, 0x33, 0xc0, 0xac, 0xfd, 0x00, 0x53, 0xe6, 0x68, 0xb9, 0x26, 0x56, 0x1b, 0x92, + 0x40, 0x98, 0xd9, 0x7a, 0xaa, 0xb5, 0x7e, 0xe1, 0x11, 0x3d, 0xf9, 0x66, 0xa4, 0x22, 0xef, + 0x9b, 0x01, 0x46, 0x17, 0xbc, 0xee, 0xf0, 0x5f, 0xb6, 0x46, 0x8e, 0x33, 0x0e, 0x2d, 0xec, + 0xe3, 0xf3, 0x75, 0xe9, 0x8e, 0xf0, 0x3e, 0x5b, 0x18, 0xa9, 0x53, 0xe2, 0x30, 0x1f, 0xcc, + 0xec, 0x86, 0x20, 0x0a, 0xe4, 0x32, 0xc9, 0xc1, 0x2c, 0x30, 0x77, 0x54, 0x37, 0xf3, 0x62, + 0x97, 0x14, 0xa9, 0xfa, 0xbe, 0xb5, 0x32, 0x89, 0x40, 0x2b, 0x7f, 0xd3, 0x86, 0xce, 0xf2, + 0xb1, 0x14, 0x67, 0x23, 0xa8, 0x9d, 0x0f, 0x81, 0x65, 0x1e, 0x00, 0xca, 0xea, 0x2f, 0x3a, + 0xc9, 0xee, 0xfe, 0xfb, 0x86, 0x8d, 0x85, 0xed, 0x23, 0x54, 0xf5, 0x30, 0xfe, 0x38, 0xfe, + 0x3a, 0x3a, 0x6a, 0xab, 0x47, 0xd4, 0x2d, 0xc2, 0x13, 0x29, 0xe3, 0xad, 0x1b, 0x9d, 0x06, + 0xc0, 0xc8, 0xd6, 0x53, 0x74, 0x56, 0xf5, 0x4a, 0xd0, 0x45, 0x3f, 0x44, 0x41, 0x75, 0xd8, + 0x7e, 0xf5, 0xcd, 0xd1, 0x69, 0x46, 0x62, 0xe0, 0xa1, 0xe6, 0xe3, 0x63, 0x2e, 0xd7, 0xa8, + 0xe7, 0x6b, 0xc7, 0xb1, 0xb5, 0xa4, 0x18, 0xf0, 0x86, 0xd3, 0x40, 0x81, 0x5e, 0xc3, 0x98, + 0xf0, 0x92, 0xe9, 0x78, 0x69, 0xf5, 0xe2, 0x01, 0xc2, 0x2c, 0x87, 0x91, 0x8f, 0x76, 0x6a, + 0x35, 0x32, 0xeb, 0x9a, 0x4f, 0xc9, 0xac, 0xf1, 0x96, 0xcb, 0xc2, 0xd0, 0x28, 0x51, 0x19, + 0xa4, 0x21, 0x6d, 0x25, 0x81, 0xcd, 0x2d, 0x91, 0xbc, 0xdc, 0xe8, 0x68, 0xc4, 0x68, 0xf6, + 0xf3, 0x4c, 0xf4, 0x9e, 0x3a, 0x56, 0xce, 0x24, 0x9a, 0x2f, 0xd8, 0xcf, 0x36, 0xb0, 0x1b, + 0x0f, 0x77, 0xde, 0x72, 0x2b, 0xbc, 0xe2, 0x67, 0xe3, 0xe5, 0x52, 0x16, 0x88, 0xe6, 0x52, + 0x22, 0x23, 0x5c, 0x91, 0xc2, 0x63, 0xd8, 0x0e, 0x28, 0x29, 0x7e, 0x92, 0x9d, 0x88, 0x5b, + 0x7b, 0x9c, 0x1a, 0x16, 0x54, 0xb2, 0xd0, 0xb8, 0x75, 0x77, 0xc9, 0xa1, 0xc7, 0x25, 0xf5, + 0x44, 0x15, 0xdc, 0x5f, 0x52, 0xdd, 0xe0, 0x69, 0x5f, 0x9f, 0x6d, 0xcb, 0x4b, 0x6e, 0xe3, + 0xe3, 0xea, 0x70, 0x29, 0x04, 0xc1, 0x1f, 0xf9, 0x2f, 0x55, 0x53, 0x4c, 0x7e, 0xf9, 0x8c, + 0xe7, 0x93, 0xd7, 0x47, 0x56, 0xa4, 0x5d, 0x4e, 0x32, 0x0a, 0x42, 0x5e, 0x98, 0x2d, 0x5b, + 0x37, 0x2d, 0x6a, 0x8d, 0x41, 0xfb, 0x86, 0xba, 0x51, 0x64, 0x81, 0x68, 0x32, 0xa4, 0x81, + 0x82, 0x5c, 0x8c, 0x6a, 0xd7, 0x27, 0x09, 0x69, 0x85, 0x9e, 0x55, 0xd2, 0x36, 0x75, 0x35, + 0x06, 0x0f, 0x99, 0x85, 0x70, 0x65, 0x17, 0x04, 0x66, 0xbd, 0xb7, 0x0c, 0xb9, 0x3a, 0xb2, + 0xf9, 0xc0, 0xe2, 0x93, 0xa0, 0xa9, 0x19, 0x84, 0x3b, 0xbf, 0x34, 0xc2, 0xfe, 0x61, 0xb0, + 0xc3, 0xe3, 0x2a, 0xa7, 0x07, 0x8e, 0x83, 0xd4, 0xc1, 0x92, 0x9e, 0x1e, 0x1d, 0x86, 0x14, + 0x1c, 0xde, 0xb1, 0x89, 0x20, 0x91, 0x09, 0x75, 0xdb, 0x3a, 0x76, 0x26, 0x82, 0x05, 0x99, + 0x63, 0x0c, 0x42, 0x3a, 0xde, 0x23, 0x3d, 0x5d, 0x60, 0x68, 0x55, 0x24, 0xe8, 0xd8, 0x03, + 0x2b, 0x86, 0x1b, 0x4a, 0xad, 0x20, 0x02, 0xa8, 0xfd, 0x17, 0xc9, 0x28, 0x2b, 0x82, 0x5f, + 0x02, 0xd3, 0x53, 0xe2, 0x91, 0x37, 0x9c, 0xed, 0x00, 0xeb, 0xaa, 0x3c, 0x03, 0xe0, 0x1d, + 0x9c, 0x59, 0xf4, 0x05, 0x09, 0x9d, 0x1c, 0x34, 0x32, 0xba, 0xd0, 0x63, 0x58, 0xd6, 0xb1, + 0x94, 0x2f, 0x0b, 0xaf, 0x71, 0x09, 0x98, 0xd1, 0x0a, 0x22, 0xd1, 0x55, 0xb0, 0xfe, 0x84, + 0x99, 0x52, 0x89, 0x31, 0x26, 0x94, 0x9f, 0xf9, 0x2d, 0xe3, 0xa4, 0xc2, 0xee, 0xaf, 0xdf, + 0x68, 0x84, 0x35, 0xe3, 0x25, 0xd8, 0x1c, 0x2c, 0xe0, 0x08, 0xcf, 0x6c, 0x76, 0x03, 0x0d, + 0x4d, 0x46, 0x34, 0x2a, 0xc3, 0x37, 0x2c, 0x73, 0x98, 0x65, 0x60, 0xc4, 0xec, 0x35, 0xa6, + 0xf6, 0x49, 0xef, 0x02, 0xc1, 0x19, 0x36, 0xb7, 0x03, 0x9b, 0xc6, 0xf5, 0xd0, 0x94, 0x38, + 0xdb, 0xe4, 0x76, 0x25, 0x1b, 0x59, 0x64, 0xb6, 0x8f, 0x02, 0xee, 0xdf, 0xf7, 0xa9, 0xe0, + 0xed, 0x3e, 0x30, 0x90, 0x96, 0x5a, 0x22, 0xf2, 0xc5, 0x52, 0xce, 0x3b, 0x2b, 0x47, 0x4f, + 0xd2, 0xfc, 0x06, 0xb5, 0x09, 0x27, 0x83, 0x0a, 0x05, 0xa3, 0x03, 0xfa, 0xff, 0xd6, 0x84, + 0x82, 0xd7, 0xb7, 0x85, 0x38, 0x43, 0x25, 0x40, 0xdd, 0x32, 0x61, 0xab, 0x75, 0x9b, 0x65, + 0x82, 0x12, 0x9a, 0x7f, 0x18, 0xd8, 0x01, 0xc5, 0x43, 0x19, 0xca, 0x52, 0xa3, 0xc6, 0xa3, + 0xdb, 0x63, 0x50, 0x44, 0xd6, 0x25, 0xe2, 0x40, 0x38, 0xad, 0x42, 0x77, 0xf8, 0xd5, 0xbf, + 0x01, 0x60, 0x35, 0x16, 0x5f, 0x21, 0xb0, 0x70, 0xe8, 0x16, 0x9d, 0x65, 0x7d, 0x6e, 0xd1, + 0xfa, 0x7f, 0x8e, 0xd0, 0x9b, 0x4e, 0x1d, 0x9c, 0xa2, 0xe5, 0x1a, 0x24, 0xda, 0x55, 0xe4, + 0x3b, 0x3f, 0xca, 0x98, 0x59, 0xb2, 0x40, 0x8c, 0x26, 0xaa, 0xcb, 0xad, 0x74, 0x9e, 0xbe, + 0x88, 0x2c, 0x31, 0xe7, 0x20, 0x5e, 0x63, 0x8b, 0xb7, 0xe2, 0xbf, 0xc8, 0xa3, 0xf1, 0xc0, + 0x2c, 0x0c, 0xa7, 0xbb, 0x9d, 0xaa, 0xab, 0x7f, 0xcb, 0xf8, 0x45, 0xd8, 0x00, 0x2c, 0x3d, + 0xe7, 0x99, 0x24, 0xdc, 0xaa, 0xdc, 0x24, 0xbd, 0xc0, 0x08, 0x2f, 0x4a, 0x6b, 0x61, 0x87, + 0x6f, 0x31, 0x92, 0xa8, 0x81, 0xf5, 0x9a, 0x68, 0x2d, 0x27, 0x36, 0x85, 0xd4, 0x79, 0x5c, + 0x9b, 0xd7, 0xcc, 0xcf, 0x49, 0xde, 0x34, 0x44, 0x3a, 0x9f, 0x9c, 0xb3, 0x5b, 0xbf, 0x25, + 0x4c, 0x50, 0x61, 0x1b, 0x7c, 0x13, 0x24, 0xb1, 0x10, 0x94, 0x66, 0x7b, 0x6b, 0x60, 0x8c, + 0x39, 0xd1, 0x25, 0x2c, 0xeb, 0xcc, 0x48, 0x77, 0xce, 0xea, 0x76, 0xe1, 0x9b, 0x84, 0x2b, + 0x67, 0xf6, 0x26, 0x74, 0x3f, 0xab, 0x29, 0x77, 0x76, 0xcc, 0x9c, 0xf7, 0x9e, 0x90, 0xe8, + 0xfc, 0xe1, 0x00, 0x17, 0x90, 0xc2, 0xe7, 0xd5, 0xc9, 0x58, 0x64, 0x7c, 0xca, 0x5d, 0x33, + 0x97, 0xd2, 0x0a, 0xfc, 0xf2, 0x9b, 0xa4, 0x4f, 0x62, 0xa7, 0xc6, 0x2e, 0x90, 0x8d, 0x84, + 0x8d, 0x81, 0xa7, 0x9f, 0xad, 0xbb, 0x37, 0x0a, 0xba, 0x93, 0xb0, 0x3e, 0x41, 0xd4, 0xbc, + 0x49, 0xe2, 0x99, 0xd6, 0xd3, 0x3f, 0xaf, 0x86, 0x9f, 0x36, 0x37, 0x14, 0x14, 0xce, 0x64, + 0x6f, 0xc2, 0xca, 0x6d, 0xcf, 0xf5, 0x5a, 0x6e, 0x06, 0x39, 0xd5, 0x0c, 0xae, 0xb1, 0x14, + 0xc4, 0x18, 0xc6, 0x26, 0xb8, 0x67, 0x15, 0x43, 0x64, 0x81, 0xd1, 0x92, 0x8d, 0x55, 0xa7, + 0x56, 0xa6, 0x03, 0xe7, 0x11, 0x0c, 0x3a, 0xfe, 0x96, 0x3c, 0x2b, 0x29, 0xa4, 0x78, 0xf9, + 0xd4, 0x39, 0x7b, 0x88, 0x5a, 0x67, 0xb0, 0x93, 0xa3, 0x45, 0x79, 0x62, 0x19, 0xc1, 0x11, + 0xb7, 0xe9, 0x4d, 0xb3, 0x90, 0xaa, 0x4b, 0xb7, 0x6b, 0x66, 0xa5, 0x34, 0xe5, 0xe2, 0x67, + 0x9b, 0x27, 0xdb, 0x5f, 0x95, 0xfd, 0x09, 0xa3, 0x6b, 0x05, + ]; +} + +pub mod zip_0143 { + use crate::{consensus, legacy::Script}; + + pub struct Test0143Vector { + pub tx: Vec, + pub script_code: Script, + pub transparent_input: Option, + pub hash_type: u32, + pub amount: i64, + pub consensus_branch_id: consensus::BranchId, + pub sighash: [u8; 32], + } + + pub fn make_test_vectors() -> Vec { + // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0143.py + vec![ + Test0143Vector { + tx: vec![ + 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x00, 0x02, 0xe7, 0x71, 0x98, + 0x11, 0x89, 0x3e, 0x00, 0x00, 0x09, 0x52, 0x00, 0xac, 0x65, 0x51, 0xac, 0x63, + 0x65, 0x65, 0xb2, 0x83, 0x5a, 0x08, 0x05, 0x75, 0x02, 0x00, 0x02, 0x51, 0x51, + 0x48, 0x1c, 0xdd, 0x86, 0xb3, 0xcc, 0x43, 0x18, 0x00, + ], + script_code: Script(vec![0x6a, 0x00, 0x00, 0x00, 0x63, 0xac, 0x53]), + transparent_input: None, + hash_type: 1, + amount: 1672704339313879, + consensus_branch_id: consensus::BranchId::Overwinter, + sighash: [ + 0xa1, 0xf1, 0xa4, 0xe5, 0xcd, 0x9b, 0xd5, 0x22, 0x32, 0x2d, 0x66, 0x1e, 0xdd, + 0x2a, 0xf1, 0xbf, 0x2a, 0x70, 0x19, 0xcf, 0xab, 0x94, 0xec, 0xe1, 0x8f, 0x4b, + 0xa9, 0x35, 0xb0, 0xa1, 0x90, 0x73, + ], + }, + Test0143Vector { + tx: vec![ + 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x42, 0x01, 0xcf, 0xb1, + 0xcd, 0x8d, 0xbf, 0x69, 0xb8, 0x25, 0x0c, 0x18, 0xef, 0x41, 0x29, 0x4c, 0xa9, + 0x79, 0x93, 0xdb, 0x54, 0x6c, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, + 0xa5, 0xe2, 0x9d, 0x4e, 0x30, 0xa7, 0x03, 0xac, 0x6a, 0x00, 0x98, 0x42, 0x1c, + 0x69, 0x37, 0x8a, 0xf1, 0xe4, 0x0f, 0x64, 0xe1, 0x25, 0x94, 0x6f, 0x62, 0xc2, + 0xfa, 0x7b, 0x2f, 0xec, 0xbc, 0xb6, 0x4b, 0x69, 0x68, 0x91, 0x2a, 0x63, 0x81, + 0xce, 0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x05, 0x63, + 0x63, 0x63, 0x53, 0x53, 0xe8, 0xc7, 0x20, 0x3d, 0x02, 0xd2, 0xda, 0x86, 0x38, + 0x7a, 0xe6, 0x01, 0x00, 0x08, 0x00, 0x63, 0x65, 0x6a, 0x63, 0xac, 0x52, 0x00, + 0xa7, 0x62, 0x29, 0x97, 0xf4, 0xff, 0x04, 0x00, 0x07, 0x51, 0x51, 0x00, 0x53, + 0x53, 0x65, 0x65, 0x97, 0xb0, 0xe4, 0xe4, 0xc7, 0x05, 0xfc, 0x05, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x76, 0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, 0xfa, + 0x3d, 0x5a, 0x57, 0xef, 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, + 0xfb, 0x1a, 0x38, 0xe0, 0x1d, 0x94, 0x90, 0x3d, 0x3c, 0x3e, 0x0a, 0xd3, 0x36, + 0x0c, 0x1d, 0x37, 0x10, 0xac, 0xd2, 0x0b, 0x18, 0x3e, 0x31, 0xd4, 0x9f, 0x25, + 0xc9, 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, + 0x98, 0x51, 0xa7, 0xaf, 0x9d, 0xb6, 0x99, 0x0e, 0xd8, 0x3d, 0xd6, 0x4a, 0xf3, + 0x59, 0x7c, 0x04, 0x32, 0x3e, 0xa5, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, + 0xb9, 0xda, 0x94, 0x8d, 0x32, 0x0d, 0xad, 0xd6, 0x4f, 0x54, 0x31, 0xe6, 0x1d, + 0xdf, 0x65, 0x8d, 0x24, 0xae, 0x67, 0xc2, 0x2c, 0x8d, 0x13, 0x09, 0x13, 0x1f, + 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, 0x42, 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, + 0x91, 0xe0, 0x0c, 0x7a, 0x1d, 0x48, 0xaf, 0x04, 0x68, 0x27, 0x59, 0x1e, 0x97, + 0x33, 0xa9, 0x7f, 0xa6, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, 0x85, + 0xed, 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0xfc, 0x1b, 0xe4, 0xaa, 0xc0, 0x0f, 0xf2, + 0x71, 0x1e, 0xbd, 0x93, 0x1d, 0xe5, 0x18, 0x85, 0x68, 0x78, 0xf7, 0x34, 0x76, + 0xf2, 0x1a, 0x48, 0x2e, 0xc9, 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, 0x3c, 0x94, + 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, 0x79, + 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, 0x32, 0xb4, + 0xf4, 0x73, 0xf4, 0x68, 0xa0, 0x08, 0xe7, 0x23, 0x89, 0xfc, 0x03, 0x88, 0x0d, + 0x78, 0x0c, 0xb0, 0x7f, 0xcf, 0xaa, 0xbe, 0x3f, 0x1a, 0x84, 0xb2, 0x7d, 0xb5, + 0x9a, 0x4a, 0x15, 0x3d, 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x55, 0xed, + 0x94, 0x94, 0xc6, 0xac, 0x89, 0x3c, 0x49, 0x72, 0x38, 0x33, 0xec, 0x89, 0x26, + 0xc1, 0x03, 0x95, 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, 0x73, 0x1e, 0x98, + 0x5d, 0x99, 0x58, 0x9c, 0x03, 0xb8, 0x38, 0xe8, 0xaa, 0xf7, 0x45, 0x53, 0x3e, + 0xd9, 0xe8, 0xae, 0x3a, 0x1c, 0xd0, 0x74, 0xa5, 0x1a, 0x20, 0xda, 0x8a, 0xba, + 0x18, 0xd1, 0xdb, 0xeb, 0xbc, 0x86, 0x2d, 0xed, 0x42, 0x43, 0x5e, 0x02, 0x47, + 0x69, 0x30, 0xd0, 0x69, 0x89, 0x6c, 0xff, 0x30, 0xeb, 0x41, 0x4f, 0x72, 0x7b, + 0x89, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, 0x6d, 0x75, 0xa4, 0xa6, + 0xf2, 0x65, 0x72, 0x50, 0x4b, 0x0b, 0x22, 0x32, 0xec, 0xb9, 0xf0, 0xc0, 0x24, + 0x11, 0xe5, 0x25, 0x96, 0xbc, 0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, 0xff, + 0xed, 0xbd, 0x12, 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, 0x7d, 0x41, 0x7a, + 0xdb, 0x3d, 0x15, 0xcc, 0x54, 0xdc, 0xb1, 0xfc, 0xe4, 0x67, 0x50, 0x0c, 0x6b, + 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, 0x82, 0x85, 0x7d, 0xee, 0xcc, + 0x40, 0xa9, 0x8d, 0x5f, 0x29, 0x03, 0x39, 0x5e, 0xe4, 0x76, 0x2d, 0xd2, 0x1a, + 0xfd, 0xbb, 0x5d, 0x47, 0xfa, 0x9a, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, + 0x57, 0xb9, 0x27, 0xb7, 0xfa, 0xe2, 0xdb, 0x58, 0x71, 0x05, 0x41, 0x5d, 0x02, + 0x42, 0x78, 0x9d, 0x38, 0xf5, 0x0b, 0x8d, 0xbc, 0xc1, 0x29, 0xca, 0xb3, 0xd1, + 0x7d, 0x19, 0xf3, 0x35, 0x5b, 0xcf, 0x73, 0xce, 0xcb, 0x8c, 0xb8, 0xa5, 0xda, + 0x01, 0x30, 0x71, 0x52, 0xf1, 0x39, 0x02, 0xa2, 0x70, 0x57, 0x26, 0x70, 0xdc, + 0x82, 0xd3, 0x90, 0x26, 0xc6, 0xcb, 0x4c, 0xd4, 0xb0, 0xf7, 0xf5, 0xaa, 0x2a, + 0x4f, 0x5a, 0x53, 0x41, 0xec, 0x5d, 0xd7, 0x15, 0x40, 0x6f, 0x2f, 0xdd, 0x2a, + 0x02, 0x73, 0x3f, 0x5f, 0x64, 0x1c, 0x8c, 0x21, 0x86, 0x2a, 0x1b, 0xaf, 0xce, + 0x26, 0x09, 0xd9, 0xee, 0xcf, 0xa1, 0x58, 0xcf, 0xb5, 0xcd, 0x79, 0xf8, 0x80, + 0x08, 0xe3, 0x15, 0xdc, 0x7d, 0x83, 0x88, 0x03, 0x6c, 0x17, 0x82, 0xfd, 0x27, + 0x95, 0xd1, 0x8a, 0x76, 0x36, 0x24, 0xc2, 0x5f, 0xa9, 0x59, 0xcc, 0x97, 0x48, + 0x9c, 0xe7, 0x57, 0x45, 0x82, 0x4b, 0x77, 0x86, 0x8c, 0x53, 0x23, 0x9c, 0xfb, + 0xdf, 0x73, 0xca, 0xec, 0x65, 0x60, 0x40, 0x37, 0x31, 0x4f, 0xaa, 0xce, 0xb5, + 0x62, 0x18, 0xc6, 0xbd, 0x30, 0xf8, 0x37, 0x4a, 0xc1, 0x33, 0x86, 0x79, 0x3f, + 0x21, 0xa9, 0xfb, 0x80, 0xad, 0x03, 0xbc, 0x0c, 0xda, 0x4a, 0x44, 0x94, 0x6c, + 0x00, 0xe1, 0xb1, 0xa1, 0xdf, 0x0e, 0x5b, 0x87, 0xb5, 0xbe, 0xce, 0x47, 0x7a, + 0x70, 0x96, 0x49, 0xe9, 0x50, 0x06, 0x05, 0x91, 0x39, 0x48, 0x12, 0x95, 0x1e, + 0x1f, 0xe3, 0x89, 0x5b, 0x8c, 0xc3, 0xd1, 0x4d, 0x2c, 0xf6, 0x55, 0x6d, 0xf6, + 0xed, 0x4b, 0x4d, 0xdd, 0x3d, 0x9a, 0x69, 0xf5, 0x33, 0x57, 0xd7, 0x76, 0x7f, + 0x4f, 0x5c, 0xcb, 0xdb, 0xc5, 0x96, 0x63, 0x12, 0x77, 0xf8, 0xfe, 0xcd, 0x08, + 0xcb, 0x05, 0x6b, 0x95, 0xe3, 0x02, 0x5b, 0x97, 0x92, 0xff, 0xf7, 0xf2, 0x44, + 0xfc, 0x71, 0x62, 0x69, 0xb9, 0x26, 0xd6, 0x2e, 0x95, 0x96, 0xfa, 0x82, 0x5c, + 0x6b, 0xf2, 0x1a, 0xff, 0x9e, 0x68, 0x62, 0x5a, 0x19, 0x24, 0x40, 0xea, 0x06, + 0x82, 0x81, 0x23, 0xd9, 0x78, 0x84, 0x80, 0x6f, 0x15, 0xfa, 0x08, 0xda, 0x52, + 0x75, 0x4a, 0x10, 0x95, 0xe3, 0xff, 0x1a, 0xbd, 0x5c, 0xe4, 0xfd, 0xdf, 0xcc, + 0xfc, 0x3a, 0x61, 0x28, 0xae, 0xf7, 0x84, 0xa6, 0x46, 0x10, 0xa8, 0x9d, 0x1a, + 0x70, 0x99, 0x21, 0x6d, 0x08, 0x14, 0xd3, 0xa2, 0xd4, 0x52, 0x43, 0x1c, 0x32, + 0xd4, 0x11, 0xac, 0x1c, 0xce, 0x82, 0xad, 0x02, 0x29, 0x40, 0x7b, 0xbc, 0x48, + 0x98, 0x56, 0x75, 0xe3, 0xf8, 0x74, 0xa4, 0x53, 0x3f, 0x1d, 0x63, 0xa8, 0x4d, + 0xfa, 0x3e, 0x0f, 0x46, 0x0f, 0xe2, 0xf5, 0x7e, 0x34, 0xfb, 0xc7, 0x54, 0x23, + 0xc3, 0x73, 0x7f, 0x5b, 0x2a, 0x06, 0x15, 0xf5, 0x72, 0x2d, 0xb0, 0x41, 0xa3, + 0xef, 0x66, 0xfa, 0x48, 0x3a, 0xfd, 0x3c, 0x2e, 0x19, 0xe5, 0x94, 0x44, 0xa6, + 0x4a, 0xdd, 0x6d, 0xf1, 0xd9, 0x63, 0xf5, 0xdd, 0x5b, 0x50, 0x10, 0xd3, 0xd0, + 0x25, 0xf0, 0x28, 0x7c, 0x4c, 0xf1, 0x9c, 0x75, 0xf3, 0x3d, 0x51, 0xdd, 0xdd, + 0xba, 0x5d, 0x65, 0x7b, 0x43, 0xee, 0x8d, 0xa6, 0x45, 0x44, 0x38, 0x14, 0xcc, + 0x73, 0x29, 0xf3, 0xe9, 0xb4, 0xe5, 0x4c, 0x23, 0x6c, 0x29, 0xaf, 0x39, 0x23, + 0x10, 0x17, 0x56, 0xd9, 0xfa, 0x4b, 0xd0, 0xf7, 0xd2, 0xdd, 0xaa, 0xcb, 0x6b, + 0x0f, 0x86, 0xa2, 0x65, 0x8e, 0x0a, 0x07, 0xa0, 0x5a, 0xc5, 0xb9, 0x50, 0x05, + 0x1c, 0xd2, 0x4c, 0x47, 0xa8, 0x8d, 0x13, 0xd6, 0x59, 0xba, 0x2a, 0x46, 0xca, + 0x18, 0x30, 0x81, 0x6d, 0x09, 0xcd, 0x76, 0x46, 0xf7, 0x6f, 0x71, 0x6a, 0xbe, + 0xc5, 0xde, 0x07, 0xfe, 0x9b, 0x52, 0x34, 0x10, 0x80, 0x6e, 0xa6, 0xf2, 0x88, + 0xf8, 0x73, 0x6c, 0x23, 0x35, 0x7c, 0x85, 0xf4, 0x57, 0x91, 0xe1, 0x70, 0x80, + 0x29, 0xd9, 0x82, 0x4d, 0x90, 0x70, 0x46, 0x07, 0xf3, 0x87, 0xa0, 0x3e, 0x49, + 0xbf, 0x98, 0x36, 0x57, 0x44, 0x31, 0x34, 0x5a, 0x78, 0x77, 0xef, 0xaa, 0x8a, + 0x08, 0xe7, 0x30, 0x81, 0xef, 0x8d, 0x62, 0xcb, 0x78, 0x0a, 0xb6, 0x88, 0x3a, + 0x50, 0xa0, 0xd4, 0x70, 0x19, 0x0d, 0xfb, 0xa1, 0x0a, 0x85, 0x7f, 0x82, 0x84, + 0x2d, 0x38, 0x25, 0xb3, 0xd6, 0xda, 0x05, 0x73, 0xd3, 0x16, 0xeb, 0x16, 0x0d, + 0xc0, 0xb7, 0x16, 0xc4, 0x8f, 0xbd, 0x46, 0x7f, 0x75, 0xb7, 0x80, 0x14, 0x9a, + 0xe8, 0x80, 0x8f, 0x4e, 0x68, 0xf5, 0x0c, 0x05, 0x36, 0xac, 0xdd, 0xf6, 0xf1, + 0xae, 0xab, 0x01, 0x6b, 0x6b, 0xc1, 0xec, 0x14, 0x4b, 0x4e, 0x55, 0x3a, 0xcf, + 0xd6, 0x70, 0xf7, 0x7e, 0x75, 0x5f, 0xc8, 0x8e, 0x06, 0x77, 0xe3, 0x1b, 0xa4, + 0x59, 0xb4, 0x4e, 0x30, 0x77, 0x68, 0x95, 0x8f, 0xe3, 0x78, 0x9d, 0x41, 0xc2, + 0xb1, 0xff, 0x43, 0x4c, 0xb3, 0x0e, 0x15, 0x91, 0x4f, 0x01, 0xbc, 0x6b, 0xc2, + 0x30, 0x7b, 0x48, 0x8d, 0x25, 0x56, 0xd7, 0xb7, 0x38, 0x0e, 0xa4, 0xff, 0xd7, + 0x12, 0xf6, 0xb0, 0x2f, 0xe8, 0x06, 0xb9, 0x45, 0x69, 0xcd, 0x40, 0x59, 0xf3, + 0x96, 0xbf, 0x29, 0xb9, 0x9d, 0x0a, 0x40, 0xe5, 0xe1, 0x71, 0x1c, 0xa9, 0x44, + 0xf7, 0x2d, 0x43, 0x6a, 0x10, 0x2f, 0xca, 0x4b, 0x97, 0x69, 0x3d, 0xa0, 0xb0, + 0x86, 0xfe, 0x9d, 0x2e, 0x71, 0x62, 0x47, 0x0d, 0x02, 0xe0, 0xf0, 0x5d, 0x4b, + 0xec, 0x95, 0x12, 0xbf, 0xb3, 0xf3, 0x83, 0x27, 0x29, 0x6e, 0xfa, 0xa7, 0x43, + 0x28, 0xb1, 0x18, 0xc2, 0x74, 0x02, 0xc7, 0x0c, 0x3a, 0x90, 0xb4, 0x9a, 0xd4, + 0xbb, 0xc6, 0x8e, 0x37, 0xc0, 0xaa, 0x7d, 0x9b, 0x3f, 0xe1, 0x77, 0x99, 0xd7, + 0x3b, 0x84, 0x1e, 0x75, 0x17, 0x13, 0xa0, 0x29, 0x43, 0x90, 0x5a, 0xae, 0x08, + 0x03, 0xfd, 0x69, 0x44, 0x2e, 0xb7, 0x68, 0x1e, 0xc2, 0xa0, 0x56, 0x00, 0x05, + 0x4e, 0x92, 0xee, 0xd5, 0x55, 0x02, 0x8f, 0x21, 0xb6, 0xa1, 0x55, 0x26, 0x8a, + 0x2d, 0xd6, 0x64, 0x0a, 0x69, 0x30, 0x1a, 0x52, 0xa3, 0x8d, 0x4d, 0x9f, 0x9f, + 0x95, 0x7a, 0xe3, 0x5a, 0xf7, 0x16, 0x71, 0x18, 0x14, 0x1c, 0xe4, 0xc9, 0xbe, + 0x0a, 0x6a, 0x49, 0x2f, 0xe7, 0x9f, 0x15, 0x81, 0xa1, 0x55, 0xfa, 0x3a, 0x2b, + 0x9d, 0xaf, 0xd8, 0x2e, 0x65, 0x0b, 0x38, 0x6a, 0xd3, 0xa0, 0x8c, 0xb6, 0xb8, + 0x31, 0x31, 0xac, 0x30, 0x0b, 0x08, 0x46, 0x35, 0x4a, 0x7e, 0xef, 0x9c, 0x41, + 0x0e, 0x4b, 0x62, 0xc4, 0x7c, 0x54, 0x26, 0x90, 0x7d, 0xfc, 0x66, 0x85, 0xc5, + 0xc9, 0x9b, 0x71, 0x41, 0xac, 0x62, 0x6a, 0xb4, 0x76, 0x1f, 0xd3, 0xf4, 0x1e, + 0x72, 0x8e, 0x1a, 0x28, 0xf8, 0x9d, 0xb8, 0x9f, 0xfd, 0xec, 0xa3, 0x64, 0xdd, + 0x2f, 0x0f, 0x07, 0x39, 0xf0, 0x53, 0x45, 0x56, 0x48, 0x31, 0x99, 0xc7, 0x1f, + 0x18, 0x93, 0x41, 0xac, 0x9b, 0x78, 0xa2, 0x69, 0x16, 0x42, 0x06, 0xa0, 0xea, + 0x1c, 0xe7, 0x3b, 0xfb, 0x2a, 0x94, 0x2e, 0x73, 0x70, 0xb2, 0x47, 0xc0, 0x46, + 0xf8, 0xe7, 0x5e, 0xf8, 0xe3, 0xf8, 0xbd, 0x82, 0x1c, 0xf5, 0x77, 0x49, 0x18, + 0x64, 0xe2, 0x0e, 0x6d, 0x08, 0xfd, 0x2e, 0x32, 0xb5, 0x55, 0xc9, 0x2c, 0x66, + 0x1f, 0x19, 0x58, 0x8b, 0x72, 0xa8, 0x95, 0x99, 0x71, 0x0a, 0x88, 0x06, 0x12, + 0x53, 0xca, 0x28, 0x5b, 0x63, 0x04, 0xb3, 0x7d, 0xa2, 0xb5, 0x29, 0x4f, 0x5c, + 0xb3, 0x54, 0xa8, 0x94, 0x32, 0x28, 0x48, 0xcc, 0xbd, 0xc7, 0xc2, 0x54, 0x5b, + 0x7d, 0xa5, 0x68, 0xaf, 0xac, 0x87, 0xff, 0xa0, 0x05, 0xc3, 0x12, 0x24, 0x1c, + 0x2d, 0x57, 0xf4, 0xb4, 0x5d, 0x64, 0x19, 0xf0, 0xd2, 0xe2, 0xc5, 0xaf, 0x33, + 0xae, 0x24, 0x37, 0x85, 0xb3, 0x25, 0xcd, 0xab, 0x95, 0x40, 0x4f, 0xc7, 0xae, + 0xd7, 0x05, 0x25, 0xcd, 0xdb, 0x41, 0x87, 0x2c, 0xfc, 0xc2, 0x14, 0xb1, 0x32, + 0x32, 0xed, 0xc7, 0x86, 0x09, 0x75, 0x3d, 0xbf, 0xf9, 0x30, 0xeb, 0x0d, 0xc1, + 0x56, 0x61, 0x2b, 0x9c, 0xb4, 0x34, 0xbc, 0x4b, 0x69, 0x33, 0x92, 0xde, 0xb8, + 0x7c, 0x53, 0x04, 0x35, 0x31, 0x2e, 0xdc, 0xed, 0xc6, 0xa9, 0x61, 0x13, 0x33, + 0x38, 0xd7, 0x86, 0xc4, 0xa3, 0xe1, 0x03, 0xf6, 0x01, 0x10, 0xa1, 0x6b, 0x13, + 0x37, 0x12, 0x97, 0x04, 0xbf, 0x47, 0x54, 0xff, 0x6b, 0xa9, 0xfb, 0xe6, 0x59, + 0x51, 0xe6, 0x10, 0x62, 0x0f, 0x71, 0xcd, 0xa8, 0xfc, 0x87, 0x76, 0x25, 0xf2, + 0xc5, 0xbb, 0x04, 0xcb, 0xe1, 0x22, 0x8b, 0x1e, 0x88, 0x6f, 0x40, 0x50, 0xaf, + 0xd8, 0xfe, 0x94, 0xe9, 0x7d, 0x2e, 0x9e, 0x85, 0xc6, 0xbb, 0x74, 0x8c, 0x00, + 0x42, 0xd3, 0x24, 0x9a, 0xbb, 0x13, 0x42, 0xbb, 0x0e, 0xeb, 0xf6, 0x20, 0x58, + 0xbf, 0x3d, 0xe0, 0x80, 0xd9, 0x46, 0x11, 0xa3, 0x75, 0x09, 0x15, 0xb5, 0xdc, + 0x6c, 0x0b, 0x38, 0x99, 0xd4, 0x12, 0x22, 0xba, 0xce, 0x76, 0x0e, 0xe9, 0xc8, + 0x81, 0x8d, 0xed, 0x59, 0x9e, 0x34, 0xc5, 0x6d, 0x73, 0x72, 0xaf, 0x1e, 0xb8, + 0x68, 0x52, 0xf2, 0xa7, 0x32, 0x10, 0x4b, 0xdb, 0x75, 0x07, 0x39, 0xde, 0x6c, + 0x2c, 0x6e, 0x0f, 0x9e, 0xb7, 0xcb, 0x17, 0xf1, 0x94, 0x2b, 0xfc, 0x9f, 0x4f, + 0xd6, 0xeb, 0xb6, 0xb4, 0xcd, 0xd4, 0xda, 0x2b, 0xca, 0x26, 0xfa, 0xc4, 0x57, + 0x8e, 0x9f, 0x54, 0x34, 0x05, 0xac, 0xc7, 0xd8, 0x6f, 0xf5, 0x91, 0x58, 0xbd, + 0x0c, 0xba, 0x3a, 0xef, 0x6f, 0x4a, 0x84, 0x72, 0xd1, 0x44, 0xd9, 0x9f, 0x8b, + 0x8d, 0x1d, 0xed, 0xaa, 0x90, 0x77, 0xd4, 0xf0, 0x1d, 0x4b, 0xb2, 0x7b, 0xbe, + 0x31, 0xd8, 0x8f, 0xbe, 0xfa, 0xc3, 0xdc, 0xd4, 0x79, 0x75, 0x63, 0xa2, 0x6b, + 0x1d, 0x61, 0xfc, 0xd9, 0xa4, 0x64, 0xab, 0x21, 0xed, 0x55, 0x0f, 0xe6, 0xfa, + 0x09, 0x69, 0x5b, 0xa0, 0xb2, 0xf1, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x64, 0x68, + 0xcc, 0x6e, 0x20, 0xa6, 0x6f, 0x82, 0x6e, 0x3d, 0x14, 0xc5, 0x00, 0x6f, 0x05, + 0x63, 0x88, 0x7f, 0x5e, 0x12, 0x89, 0xbe, 0x1b, 0x20, 0x04, 0xca, 0xca, 0x8d, + 0x3f, 0x34, 0xd6, 0xe8, 0x4b, 0xf5, 0x9c, 0x1e, 0x04, 0x61, 0x9a, 0x7c, 0x23, + 0xa9, 0x96, 0x94, 0x1d, 0x88, 0x9e, 0x46, 0x22, 0xa9, 0xb9, 0xb1, 0xd5, 0x9d, + 0x5e, 0x31, 0x90, 0x94, 0x31, 0x8c, 0xd4, 0x05, 0xba, 0x27, 0xb7, 0xe2, 0xc0, + 0x84, 0x76, 0x2d, 0x31, 0x45, 0x3e, 0xc4, 0x54, 0x9a, 0x4d, 0x97, 0x72, 0x9d, + 0x03, 0x34, 0x60, 0xfc, 0xf8, 0x9d, 0x64, 0x94, 0xf2, 0xff, 0xd7, 0x89, 0xe9, + 0x80, 0x82, 0xea, 0x5c, 0xe9, 0x53, 0x4b, 0x3a, 0xcd, 0x60, 0xfe, 0x49, 0xe3, + 0x7e, 0x4f, 0x66, 0x69, 0x31, 0x67, 0x73, 0x19, 0xed, 0x89, 0xf8, 0x55, 0x88, + 0x74, 0x1b, 0x31, 0x28, 0x90, 0x1a, 0x93, 0xbd, 0x78, 0xe4, 0xbe, 0x02, 0x25, + 0xa9, 0xe2, 0x69, 0x2c, 0x77, 0xc9, 0x69, 0xed, 0x01, 0x76, 0xbd, 0xf9, 0x55, + 0x59, 0x48, 0xcb, 0xd5, 0xa3, 0x32, 0xd0, 0x45, 0xde, 0x6b, 0xa6, 0xbf, 0x44, + 0x90, 0xad, 0xfe, 0x74, 0x44, 0xcd, 0x46, 0x7a, 0x09, 0x07, 0x54, 0x17, 0xfc, + 0xc0, 0x06, 0x2e, 0x49, 0xf0, 0x08, 0xc5, 0x1a, 0xd4, 0x22, 0x74, 0x39, 0xc1, + 0xb4, 0x47, 0x6c, 0xcd, 0x8e, 0x97, 0x86, 0x2d, 0xab, 0x7b, 0xe1, 0xe8, 0xd3, + 0x99, 0xc0, 0x5e, 0xf2, 0x7c, 0x6e, 0x22, 0xee, 0x27, 0x3e, 0x15, 0x78, 0x6e, + 0x39, 0x4c, 0x8f, 0x1b, 0xe3, 0x16, 0x82, 0xa3, 0x01, 0x47, 0x96, 0x3a, 0xc8, + 0xda, 0x8d, 0x41, 0xd8, 0x04, 0x25, 0x84, 0x26, 0xa3, 0xf7, 0x02, 0x89, 0xb8, + 0xad, 0x19, 0xd8, 0xde, 0x13, 0xbe, 0x4e, 0xeb, 0xe3, 0xbd, 0x4c, 0x8a, 0x6f, + 0x55, 0xd6, 0xe0, 0xc3, 0x73, 0xd4, 0x56, 0x85, 0x18, 0x79, 0xf5, 0xfb, 0xc2, + 0x82, 0xdb, 0x9e, 0x13, 0x48, 0x06, 0xbf, 0xf7, 0x1e, 0x11, 0xbc, 0x33, 0xab, + 0x75, 0xdd, 0x6c, 0xa0, 0x67, 0xfb, 0x73, 0xa0, 0x43, 0xb6, 0x46, 0xa7, 0x03, + 0x39, 0xca, 0xb4, 0x92, 0x83, 0x86, 0x78, 0x6d, 0x2f, 0x24, 0x14, 0x1e, 0xe1, + 0x20, 0xfd, 0xc3, 0x4d, 0x67, 0x64, 0xea, 0xfc, 0x66, 0x88, 0x0e, 0xe0, 0x20, + 0x4f, 0x53, 0xcc, 0x11, 0x67, 0xed, 0x02, 0xb4, 0x3a, 0x52, 0xde, 0xa3, 0xca, + 0x7c, 0xff, 0x8e, 0xf3, 0x5c, 0xd8, 0xe6, 0xd7, 0xc1, 0x11, 0xa6, 0x8e, 0xf4, + 0x4b, 0xcd, 0x0c, 0x15, 0x13, 0xad, 0x47, 0xca, 0x61, 0xc6, 0x59, 0xcc, 0x5d, + 0x0a, 0x5b, 0x44, 0x0f, 0x6b, 0x9f, 0x59, 0xaf, 0xf6, 0x68, 0x79, 0xbb, 0x66, + 0x88, 0xfd, 0x28, 0x59, 0x36, 0x2b, 0x18, 0x2f, 0x20, 0x7b, 0x31, 0x75, 0x96, + 0x1f, 0x64, 0x11, 0xa4, 0x93, 0xbf, 0xfd, 0x04, 0x8e, 0x7d, 0x0d, 0x87, 0xd8, + 0x2f, 0xe6, 0xf9, 0x90, 0xa2, 0xb0, 0xa2, 0x5f, 0x5a, 0xa0, 0x11, 0x1a, 0x6e, + 0x68, 0xf3, 0x7b, 0xf6, 0xf3, 0xac, 0x2d, 0x26, 0xb8, 0x46, 0x86, 0xe5, 0x69, + 0x03, 0x8d, 0x99, 0xc1, 0x38, 0x35, 0x97, 0xfa, 0xd8, 0x11, 0x93, 0xc4, 0xc1, + 0xb1, 0x6e, 0x6a, 0x90, 0xe2, 0xd5, 0x07, 0xcd, 0xfe, 0x6f, 0xbd, 0xaa, 0x86, + 0x16, 0x3e, 0x9c, 0xf5, 0xde, 0x31, 0x00, 0x03, 0xca, 0x7e, 0x8d, 0xa0, 0x47, + 0xb0, 0x90, 0xdb, 0x9f, 0x37, 0x95, 0x2f, 0xbf, 0xee, 0x76, 0xaf, 0x61, 0x66, + 0x81, 0x90, 0xbd, 0x52, 0xed, 0x49, 0x0e, 0x67, 0x7b, 0x51, 0x5d, 0x01, 0x43, + 0x84, 0x03, 0x07, 0x21, 0x9c, 0x7c, 0x0e, 0xe7, 0xfc, 0x7b, 0xfc, 0x79, 0xf3, + 0x25, 0x64, 0x4e, 0x4d, 0xf4, 0xc0, 0xd7, 0xdb, 0x08, 0xe9, 0xf0, 0xbd, 0x02, + 0x49, 0x43, 0xc7, 0x05, 0xab, 0xff, 0x89, 0x94, 0x03, 0xa6, 0x05, 0xcf, 0xbc, + 0x7e, 0xd7, 0x46, 0xa7, 0xd3, 0xf7, 0xc3, 0x7d, 0x9e, 0x8b, 0xdc, 0x43, 0x3b, + 0x7d, 0x79, 0xe0, 0x8a, 0x12, 0xf7, 0x38, 0xa8, 0xf0, 0xdb, 0xdd, 0xfe, 0xf2, + 0xf2, 0x65, 0x02, 0xf3, 0xe4, 0x7d, 0x1b, 0x0f, 0xd1, 0x1e, 0x6a, 0x13, 0x31, + 0x1f, 0xb7, 0x99, 0xc7, 0x9c, 0x64, 0x1d, 0x9d, 0xa4, 0x3b, 0x33, 0xe7, 0xad, + 0x01, 0x2e, 0x28, 0x25, 0x53, 0x98, 0x78, 0x92, 0x62, 0x27, 0x5f, 0x11, 0x75, + 0xbe, 0x84, 0x62, 0xc0, 0x14, 0x91, 0xc4, 0xd8, 0x42, 0x40, 0x6d, 0x0e, 0xc4, + 0x28, 0x2c, 0x95, 0x26, 0x17, 0x4a, 0x09, 0x87, 0x8f, 0xe8, 0xfd, 0xde, 0x33, + 0xa2, 0x96, 0x04, 0xe5, 0xe5, 0xe7, 0xb2, 0xa0, 0x25, 0xd6, 0x65, 0x0b, 0x97, + 0xdb, 0xb5, 0x2b, 0xef, 0xb5, 0x9b, 0x1d, 0x30, 0xa5, 0x74, 0x33, 0xb0, 0xa3, + 0x51, 0x47, 0x44, 0x44, 0x09, 0x9d, 0xaa, 0x37, 0x10, 0x46, 0x61, 0x32, 0x60, + 0xcf, 0x33, 0x54, 0xcf, 0xcd, 0xad, 0xa6, 0x63, 0xec, 0xe8, 0x24, 0xff, 0xd7, + 0xe4, 0x43, 0x93, 0x88, 0x6a, 0x86, 0x16, 0x5d, 0xdd, 0xdf, 0x2b, 0x4c, 0x41, + 0x77, 0x35, 0x54, 0xc8, 0x69, 0x95, 0x26, 0x94, 0x08, 0xb1, 0x1e, 0x67, 0x37, + 0xa4, 0xc4, 0x47, 0x58, 0x6f, 0x69, 0x17, 0x34, 0x46, 0xd8, 0xe4, 0x8b, 0xf8, + 0x4c, 0xbc, 0x00, 0x0a, 0x80, 0x78, 0x99, 0x97, 0x3e, 0xb9, 0x3c, 0x5e, 0x81, + 0x9a, 0xad, 0x66, 0x94, 0x13, 0xf8, 0x38, 0x79, 0x33, 0xad, 0x15, 0x84, 0xaa, + 0x35, 0xe4, 0x3f, 0x4e, 0xcd, 0x1e, 0x2d, 0x04, 0x07, 0xc0, 0xb1, 0xb8, 0x99, + 0x20, 0xff, 0xdf, 0xdb, 0x9b, 0xea, 0x51, 0xac, 0x95, 0xb5, 0x57, 0xaf, 0x71, + 0xb8, 0x9f, 0x90, 0x3f, 0x5d, 0x98, 0x48, 0xf1, 0x4f, 0xcb, 0xeb, 0x18, 0x37, + 0x57, 0x0f, 0x54, 0x4d, 0x63, 0x59, 0xeb, 0x23, 0xfa, 0xf3, 0x8a, 0x08, 0x22, + 0xda, 0x36, 0xce, 0x42, 0x6c, 0x4a, 0x2f, 0xbe, 0xff, 0xeb, 0x0a, 0x8a, 0x2e, + 0x29, 0x7a, 0x9d, 0x19, 0xba, 0x15, 0x02, 0x45, 0x90, 0xe3, 0x32, 0x9d, 0x9f, + 0xa9, 0x26, 0x1f, 0x99, 0x38, 0xa4, 0x03, 0x2d, 0xd3, 0x46, 0x06, 0xc9, 0xcf, + 0x9f, 0x3d, 0xd3, 0x3e, 0x57, 0x6f, 0x05, 0xcd, 0x1d, 0xd6, 0x81, 0x1c, 0x62, + 0x98, 0x75, 0x7d, 0x77, 0xd9, 0xe8, 0x10, 0xab, 0xdb, 0x22, 0x6a, 0xfc, 0xaa, + 0x43, 0x46, 0xa6, 0x56, 0x0f, 0x89, 0x32, 0xb3, 0x18, 0x1f, 0xd3, 0x55, 0xd5, + 0xd3, 0x91, 0x97, 0x61, 0x83, 0xf8, 0xd9, 0x93, 0x88, 0x83, 0x96, 0x32, 0xd6, + 0x35, 0x4f, 0x66, 0x6d, 0x09, 0xd3, 0xe5, 0x62, 0x9e, 0xa1, 0x97, 0x37, 0x38, + 0x86, 0x13, 0xd3, 0x8a, 0x34, 0xfd, 0x0f, 0x6e, 0x50, 0xee, 0x5a, 0x0c, 0xc9, + 0x67, 0x71, 0x77, 0xf5, 0x00, 0x28, 0xc1, 0x41, 0x37, 0x81, 0x87, 0xbd, 0x28, + 0x19, 0x40, 0x3f, 0xc5, 0x34, 0xf8, 0x00, 0x76, 0xe9, 0x38, 0x0c, 0xb4, 0x96, + 0x4d, 0x3b, 0x6b, 0x45, 0x81, 0x9d, 0x3b, 0x8e, 0x9c, 0xaf, 0x54, 0xf0, 0x51, + 0x85, 0x2d, 0x67, 0x1b, 0xf8, 0xc1, 0xff, 0xde, 0x2d, 0x15, 0x10, 0x75, 0x64, + 0x18, 0xcb, 0x48, 0x10, 0x93, 0x6a, 0xa5, 0x7e, 0x69, 0x65, 0xd6, 0xfb, 0x65, + 0x6a, 0x76, 0x0b, 0x7f, 0x19, 0xad, 0xf9, 0x6c, 0x17, 0x34, 0x88, 0x55, 0x21, + 0x93, 0xb1, 0x47, 0xee, 0x58, 0x85, 0x80, 0x33, 0xda, 0xc7, 0xcd, 0x0e, 0xb2, + 0x04, 0xc0, 0x64, 0x90, 0xbb, 0xde, 0xdf, 0x5f, 0x75, 0x71, 0xac, 0xb2, 0xeb, + 0xe7, 0x6a, 0xce, 0xf3, 0xf2, 0xa0, 0x1e, 0xe9, 0x87, 0x48, 0x6d, 0xfe, 0x6c, + 0x3f, 0x0a, 0x5e, 0x23, 0x4c, 0x12, 0x72, 0x58, 0xf9, 0x7a, 0x28, 0xfb, 0x5d, + 0x16, 0x4a, 0x81, 0x76, 0xbe, 0x94, 0x6b, 0x80, 0x97, 0xd0, 0xe3, 0x17, 0x28, + 0x7f, 0x33, 0xbf, 0x9c, 0x16, 0xf9, 0xa5, 0x45, 0x40, 0x9c, 0xe2, 0x9b, 0x1f, + 0x42, 0x73, 0x72, 0x5f, 0xc0, 0xdf, 0x02, 0xa0, 0x4e, 0xba, 0xe1, 0x78, 0xb3, + 0x41, 0x4f, 0xb0, 0xa8, 0x2d, 0x50, 0xde, 0xb0, 0x9f, 0xcf, 0x4e, 0x6e, 0xe9, + 0xd1, 0x80, 0xff, 0x4f, 0x56, 0xff, 0x3b, 0xc1, 0xd3, 0x60, 0x1f, 0xc2, 0xdc, + 0x90, 0xd8, 0x14, 0xc3, 0x25, 0x6f, 0x49, 0x67, 0xd3, 0xa8, 0xd6, 0x4c, 0x83, + 0xfe, 0xa3, 0x39, 0xc5, 0x1f, 0x5a, 0x8e, 0x58, 0x01, 0xfb, 0xb9, 0x78, 0x35, + 0x58, 0x1b, 0x60, 0x24, 0x65, 0xde, 0xe0, 0x4b, 0x59, 0x22, 0xc2, 0x76, 0x1b, + 0x54, 0x24, 0x5b, 0xec, 0x0c, 0x9e, 0xef, 0x2d, 0xb9, 0x7d, 0x22, 0xb2, 0xb3, + 0x55, 0x6c, 0xc9, 0x69, 0xfb, 0xb1, 0x3d, 0x06, 0x50, 0x97, 0x65, 0xa5, 0x2b, + 0x3f, 0xac, 0x54, 0xb9, 0x3f, 0x42, 0x1b, 0xf0, 0x8e, 0x18, 0xd5, 0x2d, 0xdd, + 0x52, 0xcc, 0x1c, 0x8c, 0xa8, 0xad, 0xfa, 0xcc, 0xab, 0x7e, 0x5c, 0xc2, 0xf4, + 0x57, 0x3f, 0xbb, 0xf8, 0x23, 0x9b, 0xb0, 0xb8, 0xae, 0xdb, 0xf8, 0xda, 0xd1, + 0x62, 0x82, 0xda, 0x5c, 0x91, 0x25, 0xdb, 0xa1, 0xc0, 0x59, 0xd0, 0xdf, 0x8a, + 0xbf, 0x62, 0x10, 0x78, 0xf0, 0x2d, 0x6c, 0x4b, 0xc8, 0x6d, 0x40, 0x84, 0x5a, + 0xc1, 0xd5, 0x97, 0x10, 0xc4, 0x5f, 0x07, 0xd5, 0x85, 0xeb, 0x48, 0xb3, 0x2f, + 0xc0, 0x16, 0x7b, 0xa2, 0x56, 0xe7, 0x3c, 0xa3, 0xb9, 0x31, 0x1c, 0x62, 0xd1, + 0x09, 0x49, 0x79, 0x57, 0xd8, 0xdb, 0xe1, 0x0a, 0xa3, 0xe8, 0x66, 0xb4, 0x0c, + 0x0b, 0xaa, 0x2b, 0xc4, 0x92, 0xc1, 0x9a, 0xd1, 0xe6, 0x37, 0x2d, 0x96, 0x22, + 0xbf, 0x16, 0x3f, 0xbf, 0xfe, 0xae, 0xee, 0x79, 0x6a, 0x3c, 0xd9, 0xb6, 0xfb, + 0xbf, 0xa4, 0xd7, 0x92, 0xf3, 0x4d, 0x7f, 0xd6, 0xe7, 0x63, 0xcd, 0x58, 0x59, + 0xdd, 0x26, 0x83, 0x3d, 0x21, 0xd9, 0xbc, 0x54, 0x52, 0xbd, 0x19, 0x51, 0x5d, + 0xff, 0x9f, 0x49, 0x95, 0xb3, 0x5b, 0xc0, 0xc1, 0xf8, 0x76, 0xe6, 0xad, 0x11, + 0xf2, 0x45, 0x2d, 0xc9, 0xae, 0x85, 0xae, 0xc0, 0x1f, 0xc5, 0x6f, 0x8c, 0xbf, + 0xda, 0x75, 0xa7, 0x72, 0x7b, 0x75, 0xeb, 0xbd, 0x6b, 0xbf, 0xfb, 0x43, 0xb6, + 0x3a, 0x3b, 0x1b, 0x67, 0x1e, 0x40, 0xfe, 0xb0, 0xdb, 0x00, 0x29, 0x74, 0xa3, + 0xc3, 0xb1, 0xa7, 0x88, 0x56, 0x72, 0x31, 0xbf, 0x63, 0x99, 0xff, 0x89, 0x23, + 0x69, 0x81, 0x14, 0x9d, 0x42, 0x38, 0x02, 0xd2, 0x34, 0x1a, 0x3b, 0xed, 0xb9, + 0xdd, 0xcb, 0xac, 0x1f, 0xe7, 0xb6, 0x43, 0x5e, 0x14, 0x79, 0xc7, 0x2e, 0x70, + 0x89, 0xd0, 0x29, 0xe7, 0xfb, 0xba, 0xf3, 0xcf, 0x37, 0xe9, 0xb9, 0xa6, 0xb7, + 0x76, 0x79, 0x1e, 0x4c, 0x5e, 0x6f, 0xda, 0x57, 0xe8, 0xd5, 0xf1, 0x4c, 0x8c, + 0x35, 0xa2, 0xd2, 0x70, 0x84, 0x6b, 0x9d, 0xbe, 0x00, 0x5c, 0xda, 0x16, 0xaf, + 0x44, 0x08, 0xf3, 0xab, 0x06, 0xa9, 0x16, 0xee, 0xeb, 0x9c, 0x95, 0x94, 0xb7, + 0x04, 0x24, 0xa4, 0xc1, 0xd1, 0x71, 0x29, 0x5b, 0x67, 0x63, 0xb2, 0x2f, 0x47, + 0xf8, 0x0b, 0x53, 0xcc, 0xbb, 0x90, 0x4b, 0xd6, 0x8f, 0xd6, 0x5f, 0xbd, 0x3f, + 0xbd, 0xea, 0x10, 0x35, 0xe9, 0x8c, 0x21, 0xa7, 0xdb, 0xc9, 0x1a, 0x9b, 0x5b, + 0xc7, 0x69, 0x0f, 0x05, 0xec, 0x31, 0x7c, 0x97, 0xf8, 0x76, 0x4e, 0xb4, 0x8e, + 0x91, 0x1d, 0x42, 0x8e, 0xc8, 0xd8, 0x61, 0xb7, 0x08, 0xe8, 0x29, 0x8a, 0xcb, + 0x62, 0x15, 0x51, 0x45, 0x15, 0x5a, 0xe9, 0x5f, 0x0a, 0x1d, 0x15, 0x01, 0x03, + 0x47, 0x53, 0x14, 0x6e, 0x22, 0xd0, 0x5f, 0x58, 0x6d, 0x7f, 0x6b, 0x4f, 0xe1, + 0x2d, 0xad, 0x9a, 0x17, 0xf5, 0xdb, 0x70, 0xb1, 0xdb, 0x96, 0xb8, 0xd9, 0xa8, + 0x3e, 0xda, 0xdc, 0x96, 0x6c, 0x8a, 0x54, 0x66, 0xb6, 0x1f, 0xc9, 0x98, 0xc3, + 0x1f, 0x10, 0x70, 0xd9, 0xa5, 0xc9, 0xa6, 0xd2, 0x68, 0xd3, 0x04, 0xfe, 0x6b, + 0x8f, 0xd3, 0xb4, 0x01, 0x03, 0x48, 0x61, 0x1a, 0xbd, 0xcb, 0xd4, 0x9f, 0xe4, + 0xf8, 0x5b, 0x62, 0x3c, 0x78, 0x28, 0xc7, 0x13, 0x82, 0xe1, 0x03, 0x4e, 0xa6, + 0x7b, 0xc8, 0xae, 0x97, 0x40, 0x4b, 0x0c, 0x50, 0xb2, 0xa0, 0x4f, 0x55, 0x9e, + 0x49, 0x95, 0x0a, 0xfc, 0xb0, 0xef, 0x46, 0x2a, 0x2a, 0xe0, 0x24, 0xb0, 0xf0, + 0x22, 0x4d, 0xfd, 0x73, 0x68, 0x4b, 0x88, 0xc7, 0xfb, 0xe9, 0x2d, 0x02, 0xb6, + 0x8f, 0x75, 0x9c, 0x47, 0x52, 0x66, 0x3c, 0xd7, 0xb9, 0x7a, 0x14, 0x94, 0x36, + 0x49, 0x30, 0x55, 0x21, 0x32, 0x6b, 0xde, 0x08, 0x56, 0x30, 0x86, 0x46, 0x29, + 0x29, 0x1b, 0xae, 0x25, 0xff, 0x88, 0x22, 0xa1, 0x4c, 0x4b, 0x66, 0x6a, 0x92, + 0x59, 0xad, 0x0d, 0xc4, 0x2a, 0x82, 0x90, 0xac, 0x7b, 0xc7, 0xf5, 0x3a, 0x16, + 0xf3, 0x79, 0xf7, 0x58, 0xe5, 0xde, 0x75, 0x0f, 0x04, 0xfd, 0x7c, 0xad, 0x47, + 0x70, 0x1c, 0x85, 0x97, 0xf9, 0x78, 0x88, 0xbe, 0xa6, 0xfa, 0x0b, 0xf2, 0x99, + 0x99, 0x56, 0xfb, 0xfd, 0x0e, 0xe6, 0x8e, 0xc3, 0x6e, 0x46, 0x88, 0x80, 0x9a, + 0xe2, 0x31, 0xeb, 0x8b, 0xc4, 0x36, 0x9f, 0x5f, 0xe1, 0x57, 0x3f, 0x57, 0xe0, + 0x99, 0xd9, 0xc0, 0x99, 0x01, 0xbf, 0x39, 0xca, 0xac, 0x48, 0xdc, 0x11, 0x95, + 0x6a, 0x8a, 0xe9, 0x05, 0xea, 0xd8, 0x69, 0x54, 0x54, 0x7c, 0x44, 0x8a, 0xe4, + 0x3d, 0x31, 0x5e, 0x66, 0x9c, 0x42, 0x42, 0xda, 0x56, 0x59, 0x38, 0xf4, 0x17, + 0xbf, 0x43, 0xce, 0x7b, 0x2b, 0x30, 0xb1, 0xcd, 0x40, 0x18, 0x38, 0x8e, 0x1a, + 0x91, 0x0f, 0x0f, 0xc4, 0x1f, 0xb0, 0x87, 0x7a, 0x59, 0x25, 0xe4, 0x66, 0x81, + 0x9d, 0x37, 0x5b, 0x0a, 0x91, 0x2d, 0x4f, 0xe8, 0x43, 0xb7, 0x6e, 0xf6, 0xf2, + 0x23, 0xf0, 0xf7, 0xc8, 0x94, 0xf3, 0x8f, 0x7a, 0xb7, 0x80, 0xdf, 0xd7, 0x5f, + 0x66, 0x9c, 0x8c, 0x06, 0xcf, 0xfa, 0x43, 0xeb, 0x47, 0x56, 0x5a, 0x50, 0xe3, + 0xb1, 0xfa, 0x45, 0xad, 0x61, 0xce, 0x9a, 0x1c, 0x47, 0x27, 0xb7, 0xaa, 0xa5, + 0x35, 0x62, 0xf5, 0x23, 0xe7, 0x39, 0x52, + ], + script_code: Script(vec![0x53]), + transparent_input: Some(1), + hash_type: 3, + amount: 365293780364847, + consensus_branch_id: consensus::BranchId::Overwinter, + sighash: [ + 0x23, 0x65, 0x2e, 0x76, 0xcb, 0x13, 0xb8, 0x5a, 0x0e, 0x33, 0x63, 0xbb, 0x5f, + 0xca, 0x06, 0x1f, 0xa7, 0x91, 0xc4, 0x0c, 0x53, 0x3e, 0xcc, 0xee, 0x89, 0x93, + 0x64, 0xe6, 0xe6, 0x0b, 0xb4, 0xf7, + ], + }, + Test0143Vector { + tx: vec![ + 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x99, 0xa6, 0x9f, 0xdf, + 0x1c, 0x5a, 0xc7, 0x73, 0x21, 0x46, 0xee, 0x5e, 0x1d, 0x6b, 0x6c, 0xa9, 0xb9, + 0x18, 0x0f, 0x96, 0x4c, 0xc9, 0xd0, 0x87, 0x8a, 0xe1, 0x37, 0x35, 0x24, 0xd7, + 0xd5, 0x10, 0xe5, 0x82, 0x27, 0xdf, 0x09, 0x51, 0x53, 0x63, 0x6a, 0x00, 0x6a, + 0xac, 0x51, 0x6a, 0xb0, 0xf1, 0x85, 0x6e, 0x28, 0xd5, 0xc8, 0xaf, 0xb0, 0x95, + 0xef, 0x61, 0x84, 0xfe, 0xd6, 0x51, 0x58, 0x90, 0x22, 0xee, 0xae, 0xa4, 0xc0, + 0xce, 0x1f, 0xa6, 0xf0, 0x85, 0x09, 0x2b, 0x04, 0x97, 0x94, 0x89, 0x17, 0x2b, + 0x3e, 0xf8, 0x19, 0x4a, 0x01, 0x63, 0xf5, 0x72, 0x4d, 0x6b, 0x02, 0xde, 0xe1, + 0x36, 0xf3, 0xa9, 0xaa, 0x02, 0x00, 0x03, 0x52, 0x52, 0xac, 0x17, 0xb7, 0x3f, + 0x8d, 0x38, 0x3e, 0x00, 0x00, 0x06, 0xac, 0x63, 0x00, 0x53, 0xac, 0x51, 0x04, + 0xb4, 0x75, 0x56, 0xaf, 0x73, 0xb6, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x32, + 0x1d, 0x14, 0x60, 0x71, 0x78, 0x9d, 0x23, 0x35, 0x93, 0x4a, 0x68, 0x06, 0x14, + 0xe8, 0x35, 0x62, 0xf8, 0x2d, 0xfd, 0x40, 0x5b, 0x54, 0xa4, 0x5e, 0xb3, 0x2c, + 0x16, 0x54, 0x48, 0xd4, 0xd5, 0xd6, 0x1c, 0xa2, 0x85, 0x95, 0x85, 0x36, 0x9f, + 0x53, 0xf1, 0xa1, 0x37, 0xe9, 0xe8, 0x2b, 0x67, 0xb8, 0xfd, 0xaf, 0x01, 0xbd, + 0xa5, 0x4a, 0x31, 0x73, 0x11, 0x89, 0x6a, 0xe1, 0x02, 0x80, 0xa0, 0x32, 0x44, + 0x0c, 0x42, 0x0a, 0x42, 0x1e, 0x94, 0x4d, 0x1e, 0x95, 0x2b, 0x70, 0xd5, 0x82, + 0x6c, 0xd3, 0xb0, 0x8b, 0x7d, 0xb9, 0x63, 0x0f, 0xe4, 0xfd, 0x5f, 0x22, 0x12, + 0x5d, 0xe8, 0x40, 0xfc, 0xc4, 0x0b, 0x98, 0x03, 0x8a, 0xf1, 0x1d, 0x55, 0xbe, + 0x25, 0x43, 0x25, 0x97, 0xb4, 0xb6, 0x5b, 0x9e, 0xc1, 0xc7, 0xa8, 0xbb, 0xfd, + 0x05, 0x2c, 0xbf, 0x7e, 0x1c, 0x17, 0x85, 0x31, 0x49, 0x34, 0xb2, 0x62, 0xd5, + 0x85, 0x37, 0x54, 0xf1, 0xf1, 0x77, 0x71, 0xcf, 0xb7, 0x50, 0x30, 0x72, 0x65, + 0x57, 0x53, 0xfa, 0x3f, 0x54, 0xec, 0xc5, 0x87, 0xe9, 0xf8, 0x3b, 0x58, 0x19, + 0x16, 0x09, 0x2d, 0xf2, 0x6e, 0x63, 0xe1, 0x89, 0x94, 0xcb, 0x0d, 0xb9, 0x1a, + 0x0b, 0xbd, 0xc7, 0xb6, 0x11, 0x9b, 0x32, 0x22, 0x2a, 0xdf, 0x5e, 0x61, 0xd8, + 0xd8, 0xae, 0x89, 0xda, 0xe4, 0x95, 0x4b, 0x54, 0x81, 0x3b, 0xb3, 0x3f, 0x08, + 0xd5, 0x62, 0xba, 0x51, 0x3f, 0xee, 0x1b, 0x09, 0xc0, 0xfc, 0xd5, 0x16, 0x05, + 0x54, 0x19, 0x47, 0x4d, 0xd7, 0xfd, 0xa0, 0x38, 0xa8, 0x9c, 0x84, 0xea, 0x7b, + 0x94, 0x68, 0x28, 0x7f, 0x0e, 0xb0, 0xc1, 0x0c, 0x4b, 0x13, 0x25, 0x20, 0x19, + 0x4d, 0x3d, 0x8d, 0x53, 0x51, 0xfc, 0x10, 0xd0, 0x9c, 0x15, 0xc8, 0xcc, 0x10, + 0x1a, 0xa1, 0x66, 0x3b, 0xbf, 0x17, 0xb8, 0x41, 0x11, 0xf3, 0x8b, 0xb4, 0x39, + 0xf0, 0x73, 0x53, 0xbd, 0xea, 0x35, 0x96, 0xd1, 0x5e, 0x71, 0x3e, 0x1e, 0x2e, + 0x7d, 0x3f, 0x1c, 0x38, 0x31, 0x35, 0xb4, 0x7f, 0xa7, 0xf8, 0x1f, 0x46, 0xdf, + 0x02, 0x90, 0x2a, 0x40, 0x46, 0x99, 0xec, 0x91, 0x2f, 0x56, 0x56, 0xc3, 0x5b, + 0x85, 0x76, 0x3e, 0x4d, 0xe5, 0x83, 0xae, 0xca, 0xa1, 0xdf, 0xd5, 0xd2, 0x67, + 0x7d, 0x9c, 0x8f, 0xfe, 0xe8, 0x77, 0xf6, 0x03, 0x40, 0xa5, 0xca, 0x0d, 0x67, + 0xf6, 0xe5, 0x54, 0x12, 0x47, 0x39, 0xf8, 0x05, 0xaf, 0x87, 0x6a, 0xee, 0xde, + 0x53, 0xaa, 0x8b, 0x0f, 0x8e, 0x56, 0x04, 0xa7, 0x3c, 0x30, 0xcb, 0xd0, 0x9d, + 0xad, 0x0a, 0x3d, 0x6f, 0x8a, 0x5d, 0xcc, 0x40, 0xde, 0xf4, 0x07, 0x97, 0x34, + 0x21, 0x13, 0xba, 0x20, 0x6f, 0xae, 0x8e, 0xbe, 0x4f, 0x3b, 0xc3, 0xca, 0xf6, + 0x92, 0x59, 0xe4, 0x62, 0xef, 0xf9, 0xba, 0x8b, 0x3f, 0x4b, 0xfa, 0xa1, 0x30, + 0x0c, 0x26, 0x92, 0x5a, 0x87, 0x29, 0xcd, 0x32, 0x91, 0x5b, 0xfc, 0x96, 0x60, + 0x86, 0xf0, 0xd5, 0x56, 0x0b, 0xbe, 0x32, 0xa5, 0x98, 0xc2, 0x2a, 0xdf, 0xb4, + 0x8c, 0x03, 0x72, 0xba, 0x5d, 0x42, 0x87, 0xc0, 0xce, 0xfb, 0xac, 0xfd, 0x8c, + 0xe1, 0x95, 0xb4, 0x96, 0x3c, 0x34, 0xa9, 0x4b, 0xba, 0x7a, 0x17, 0x5d, 0xae, + 0x4b, 0xbe, 0x3e, 0xf4, 0x86, 0x3d, 0x53, 0x70, 0x03, 0x15, 0x09, 0x0f, 0x47, + 0xa0, 0x68, 0xe2, 0x27, 0x43, 0x3f, 0x9e, 0x49, 0xd3, 0xaa, 0x09, 0xe3, 0x56, + 0xd8, 0xd6, 0x6d, 0x0c, 0x01, 0x21, 0xe9, 0x1a, 0x3c, 0x4a, 0xa3, 0xf2, 0x7f, + 0xa1, 0xb6, 0x03, 0x96, 0xe2, 0xb4, 0x1d, 0xb9, 0x08, 0xfd, 0xab, 0x8b, 0x18, + 0xcc, 0x73, 0x04, 0xe9, 0x4e, 0x97, 0x05, 0x68, 0xf9, 0x42, 0x1c, 0x0d, 0xbb, + 0xba, 0xf8, 0x45, 0x98, 0xd9, 0x72, 0xb0, 0x53, 0x4f, 0x02, 0xa5, 0xe5, 0x26, + 0x70, 0x43, 0x6a, 0xaa, 0x77, 0x6e, 0xd2, 0x48, 0x2a, 0xd7, 0x03, 0x43, 0x02, + 0x01, 0xe5, 0x34, 0x43, 0xc3, 0x6d, 0xcf, 0xd3, 0x4a, 0x0c, 0xb6, 0x63, 0x78, + 0x76, 0x10, 0x5e, 0x03, 0xbf, 0x3b, 0xd5, 0x8e, 0xc1, 0x48, 0xcb, 0x64, 0x97, + 0x0e, 0x32, 0x23, 0xa9, 0x1f, 0x71, 0xdf, 0xcf, 0xd5, 0xa0, 0x4b, 0x66, 0x7f, + 0xba, 0xf3, 0xd4, 0xb3, 0xb9, 0x08, 0xb9, 0x82, 0x88, 0x20, 0xdf, 0xec, 0xdd, + 0x75, 0x37, 0x50, 0xb5, 0xf9, 0xd2, 0x21, 0x6e, 0x56, 0xc6, 0x15, 0x27, 0x2f, + 0x85, 0x44, 0x64, 0xc0, 0xca, 0x4b, 0x1e, 0x85, 0xae, 0xdd, 0x03, 0x82, 0x92, + 0xc4, 0xe1, 0xa5, 0x77, 0x44, 0xeb, 0xba, 0x01, 0x0b, 0x9e, 0xbf, 0xbb, 0x01, + 0x1b, 0xd6, 0xf0, 0xb7, 0x88, 0x05, 0x02, 0x5d, 0x27, 0xf3, 0xc1, 0x77, 0x46, + 0xba, 0xe1, 0x16, 0xc1, 0x5d, 0x9f, 0x47, 0x1f, 0x0f, 0x62, 0x88, 0xa1, 0x50, + 0x64, 0x7b, 0x2a, 0xfe, 0x9d, 0xf7, 0xcc, 0xcf, 0x01, 0xf5, 0xcd, 0xe5, 0xf0, + 0x46, 0x80, 0xbb, 0xfe, 0xd8, 0x7f, 0x6c, 0xf4, 0x29, 0xfb, 0x27, 0xad, 0x6b, + 0xab, 0xe7, 0x91, 0x76, 0x66, 0x11, 0xcf, 0x5b, 0xc2, 0x0e, 0x48, 0xbe, 0xf1, + 0x19, 0x25, 0x9b, 0x9b, 0x8a, 0x0e, 0x39, 0xc3, 0xdf, 0x28, 0xcb, 0x95, 0x82, + 0xea, 0x33, 0x86, 0x01, 0xcd, 0xc4, 0x81, 0xb3, 0x2f, 0xb8, 0x2a, 0xde, 0xeb, + 0xb3, 0xda, 0xde, 0x25, 0xd1, 0xa3, 0xdf, 0x20, 0xc3, 0x7e, 0x71, 0x25, 0x06, + 0xb5, 0xd9, 0x96, 0xc4, 0x9a, 0x9f, 0x0f, 0x30, 0xdd, 0xcb, 0x91, 0xfe, 0x90, + 0x04, 0xe1, 0xe8, 0x32, 0x94, 0xa6, 0xc9, 0x20, 0x3d, 0x94, 0xe8, 0xdc, 0x2c, + 0xbb, 0x44, 0x9d, 0xe4, 0x15, 0x50, 0x32, 0x60, 0x4e, 0x47, 0x99, 0x70, 0x16, + 0xb3, 0x04, 0xfd, 0x43, 0x7d, 0x82, 0x35, 0x04, 0x5e, 0x25, 0x5a, 0x19, 0xb7, + 0x43, 0xa0, 0xa9, 0xf2, 0xe3, 0x36, 0xb4, 0x4c, 0xae, 0x30, 0x7b, 0xb3, 0x98, + 0x7b, 0xd3, 0xe4, 0xe7, 0x77, 0xfb, 0xb3, 0x4c, 0x0a, 0xb8, 0xcc, 0x3d, 0x67, + 0x46, 0x6c, 0x0a, 0x88, 0xdd, 0x4c, 0xca, 0xd1, 0x8a, 0x07, 0xa8, 0xd1, 0x06, + 0x8d, 0xf5, 0xb6, 0x29, 0xe5, 0x71, 0x8d, 0x0f, 0x6d, 0xf5, 0xc9, 0x57, 0xcf, + 0x71, 0xbb, 0x00, 0xa5, 0x17, 0x8f, 0x17, 0x5c, 0xac, 0xa9, 0x44, 0xe6, 0x35, + 0xc5, 0x15, 0x9f, 0x73, 0x8e, 0x24, 0x02, 0xa2, 0xd2, 0x1a, 0xa0, 0x81, 0xe1, + 0x0e, 0x45, 0x6a, 0xfb, 0x00, 0xb9, 0xf6, 0x24, 0x16, 0xc8, 0xb9, 0xc0, 0xf7, + 0x22, 0x8f, 0x51, 0x07, 0x29, 0xe0, 0xbe, 0x3f, 0x30, 0x53, 0x13, 0xd7, 0x7f, + 0x73, 0x79, 0xdc, 0x2a, 0xf2, 0x48, 0x69, 0xc6, 0xc7, 0x4e, 0xe4, 0x47, 0x14, + 0x98, 0x86, 0x1d, 0x19, 0x2f, 0x0f, 0xf0, 0xf5, 0x08, 0x28, 0x5d, 0xab, 0x6b, + 0x6a, 0x36, 0xcc, 0xf7, 0xd1, 0x22, 0x56, 0xcc, 0x76, 0xb9, 0x55, 0x03, 0x72, + 0x0a, 0xc6, 0x72, 0xd0, 0x82, 0x68, 0xd2, 0xcf, 0x77, 0x73, 0xb6, 0xba, 0x2a, + 0x5f, 0x66, 0x48, 0x47, 0xbf, 0x70, 0x7f, 0x2f, 0xc1, 0x0c, 0x98, 0xf2, 0xf0, + 0x06, 0xec, 0x22, 0xcc, 0xb5, 0xa8, 0xc8, 0xb7, 0xc4, 0x0c, 0x7c, 0x2d, 0x49, + 0xa6, 0x63, 0x9b, 0x9f, 0x2c, 0xe3, 0x3c, 0x25, 0xc0, 0x4b, 0xc4, 0x61, 0xe7, + 0x44, 0xdf, 0xa5, 0x36, 0xb0, 0x0d, 0x94, 0xba, 0xdd, 0xf4, 0xf4, 0xd1, 0x40, + 0x44, 0xc6, 0x95, 0xa3, 0x38, 0x81, 0x47, 0x7d, 0xf1, 0x24, 0xf0, 0xfc, 0xf2, + 0x06, 0xa9, 0xfb, 0x2e, 0x65, 0xe3, 0x04, 0xcd, 0xbf, 0x0c, 0x4d, 0x23, 0x90, + 0x17, 0x0c, 0x13, 0x0a, 0xb8, 0x49, 0xc2, 0xf2, 0x2b, 0x5c, 0xdd, 0x39, 0x21, + 0x64, 0x0c, 0x8c, 0xf1, 0x97, 0x6a, 0xe1, 0x01, 0x0b, 0x0d, 0xfd, 0x9c, 0xb2, + 0x54, 0x3e, 0x45, 0xf9, 0x97, 0x49, 0xcc, 0x4d, 0x61, 0xf2, 0xe8, 0xaa, 0xbf, + 0xe9, 0x8b, 0xd9, 0x05, 0xfa, 0x39, 0x95, 0x1b, 0x33, 0xea, 0x76, 0x9c, 0x45, + 0xab, 0x95, 0x31, 0xc5, 0x72, 0x09, 0x86, 0x2a, 0xd1, 0x2f, 0xd7, 0x6b, 0xa4, + 0x80, 0x7e, 0x65, 0x41, 0x7b, 0x6c, 0xd1, 0x2f, 0xa8, 0xec, 0x91, 0x6f, 0x01, + 0x3e, 0xbb, 0x87, 0x06, 0xa9, 0x6e, 0xff, 0xed, 0xa0, 0x6c, 0x4b, 0xe2, 0x4b, + 0x04, 0x84, 0x63, 0x92, 0xe9, 0xd1, 0xe6, 0x93, 0x0e, 0xae, 0x01, 0xfa, 0x21, + 0xfb, 0xd7, 0x00, 0x58, 0x3f, 0xb5, 0x98, 0xb9, 0x2c, 0x8f, 0x4e, 0xb8, 0xa6, + 0x1a, 0xa6, 0x23, 0x5d, 0xb6, 0x0f, 0x28, 0x41, 0xcf, 0x3a, 0x1c, 0x6a, 0xb5, + 0x4c, 0x67, 0x06, 0x68, 0x44, 0x71, 0x1d, 0x09, 0x1e, 0xb9, 0x31, 0xa1, 0xbd, + 0x62, 0x81, 0xae, 0xdf, 0x2a, 0x0e, 0x8f, 0xab, 0x18, 0x81, 0x72, 0x02, 0xa9, + 0xbe, 0x06, 0x40, 0x2e, 0xd9, 0xcc, 0x72, 0x0c, 0x16, 0xbf, 0xe8, 0x81, 0xe4, + 0xdf, 0x42, 0x55, 0xe8, 0x7a, 0xfb, 0x7f, 0xc6, 0x2f, 0x38, 0x11, 0x6b, 0xbe, + 0x03, 0xcd, 0x8a, 0x3c, 0xb1, 0x1a, 0x27, 0xd5, 0x68, 0x41, 0x47, 0x82, 0xf4, + 0x7b, 0x1a, 0x44, 0xc9, 0x7c, 0x68, 0x04, 0x67, 0x69, 0x4b, 0xc9, 0x70, 0x9d, + 0x32, 0x91, 0x6c, 0x97, 0xe8, 0x00, 0x6c, 0xbb, 0x07, 0xba, 0x0e, 0x41, 0x80, + 0xa3, 0x73, 0x80, 0x38, 0xc3, 0x74, 0xc4, 0xcc, 0xe8, 0xf3, 0x29, 0x59, 0xaf, + 0xb2, 0x5f, 0x30, 0x3f, 0x58, 0x15, 0xc4, 0x53, 0x31, 0x24, 0xac, 0xf9, 0xd1, + 0x89, 0x40, 0xe7, 0x75, 0x22, 0xac, 0x5d, 0xc4, 0xb9, 0x57, 0x0a, 0xae, 0x8f, + 0x47, 0xb7, 0xf5, 0x7f, 0xd8, 0x76, 0x7b, 0xea, 0x1a, 0x24, 0xae, 0x7b, 0xed, + 0x65, 0xb4, 0xaf, 0xdc, 0x8f, 0x12, 0x78, 0xc3, 0x0e, 0x2d, 0xb9, 0x8f, 0xd1, + 0x72, 0x73, 0x0a, 0xc6, 0xbb, 0xed, 0x4f, 0x11, 0x27, 0xcd, 0x32, 0xb0, 0x4a, + 0x95, 0xb2, 0x05, 0x52, 0x6c, 0xfc, 0xb4, 0xc4, 0xe1, 0xcc, 0x95, 0x51, 0x75, + 0xb3, 0xe8, 0xde, 0x1f, 0x5d, 0x81, 0xb1, 0x86, 0x69, 0x69, 0x23, 0x50, 0xaa, + 0xa1, 0xa1, 0xd7, 0x97, 0x61, 0x75, 0x82, 0xe5, 0x4d, 0x7a, 0x5b, 0x57, 0xa6, + 0x83, 0xb3, 0x2f, 0xb1, 0x09, 0x80, 0x62, 0xda, 0xd7, 0xb0, 0xc2, 0xeb, 0x51, + 0x8f, 0x68, 0x62, 0xe8, 0x3d, 0xb2, 0x5e, 0x3d, 0xba, 0xf7, 0xae, 0xd5, 0x04, + 0xde, 0x93, 0x2a, 0xcb, 0x99, 0xd7, 0x35, 0x99, 0x2c, 0xe6, 0x2b, 0xae, 0x9e, + 0xf8, 0x93, 0xff, 0x6a, 0xcc, 0x0f, 0xfc, 0xf8, 0xe3, 0x48, 0x3e, 0x14, 0x6b, + 0x9d, 0x49, 0xdd, 0x8c, 0x78, 0x35, 0xf4, 0x3a, 0x37, 0xdc, 0xa0, 0x78, 0x7e, + 0x3e, 0xc9, 0xf6, 0x60, 0x52, 0x23, 0xd5, 0xba, 0x7a, 0xe0, 0xab, 0x90, 0x25, + 0xb7, 0x3b, 0xc0, 0x3f, 0x7f, 0xac, 0x36, 0xc0, 0x09, 0xa5, 0x6d, 0x4d, 0x95, + 0xd1, 0xe8, 0x1d, 0x3b, 0x3e, 0xbc, 0xa7, 0xe5, 0x4c, 0xc1, 0xa1, 0x2d, 0x12, + 0x7b, 0x57, 0xc8, 0x13, 0x89, 0x76, 0xe7, 0x91, 0x01, 0x3b, 0x01, 0x5f, 0x06, + 0xa6, 0x24, 0xf5, 0x21, 0xb6, 0xee, 0x04, 0xec, 0x98, 0x08, 0x93, 0xc7, 0xe5, + 0xe0, 0x1a, 0x33, 0x62, 0x03, 0x59, 0x40, 0x94, 0xf8, 0x28, 0x33, 0xd7, 0x44, + 0x5f, 0xe2, 0xd0, 0x91, 0x30, 0xf6, 0x35, 0x11, 0xda, 0x54, 0x83, 0x2d, 0xe9, + 0x13, 0x6b, 0x39, 0xf4, 0x59, 0x9f, 0x5a, 0xa5, 0xdf, 0xbb, 0x45, 0xda, 0x60, + 0xcd, 0xce, 0xab, 0x7e, 0xef, 0xde, 0x89, 0xbe, 0x63, 0xf3, 0xf7, 0xc0, 0xd2, + 0x32, 0x48, 0x47, 0xcc, 0xe1, 0x40, 0x5d, 0xef, 0x7c, 0x46, 0x9b, 0x0e, 0x27, + 0x24, 0x94, 0xe5, 0xdf, 0x54, 0xf5, 0x68, 0x65, 0x6c, 0xb9, 0xc8, 0x81, 0x8d, + 0x92, 0xb7, 0x2b, 0x8b, 0xc3, 0x4d, 0xb7, 0xbb, 0x31, 0x12, 0x48, 0x7e, 0x74, + 0x6e, 0xef, 0xe4, 0xe8, 0x08, 0xbb, 0xb2, 0x87, 0xd9, 0x9b, 0xf0, 0x7d, 0x00, + 0xda, 0xbe, 0xde, 0xdc, 0x5e, 0x5f, 0x07, 0x4f, 0xfe, 0xae, 0x0c, 0xba, 0x7d, + 0xa3, 0xa5, 0x16, 0xc1, 0x73, 0xbe, 0x1c, 0x51, 0x33, 0x23, 0xe1, 0x19, 0xf6, + 0x35, 0xe8, 0x20, 0x9a, 0x07, 0x4b, 0x21, 0x6b, 0x70, 0x23, 0xfa, 0xdc, 0x2d, + 0x25, 0x94, 0x9c, 0x90, 0x03, 0x7e, 0x71, 0xe3, 0xe5, 0x50, 0x72, 0x6d, 0x21, + 0x0a, 0x2c, 0x68, 0x83, 0x42, 0xe5, 0x24, 0x40, 0x63, 0x5e, 0x9c, 0xc1, 0x4a, + 0xfe, 0x10, 0x10, 0x26, 0x21, 0xa9, 0xc9, 0xac, 0xcb, 0x78, 0x2e, 0x9e, 0x4a, + 0x5f, 0xa8, 0x7f, 0x0a, 0x95, 0x6f, 0x5b, 0x85, 0x50, 0x99, 0x60, 0x28, 0x5c, + 0x22, 0x62, 0x7c, 0x59, 0x48, 0x3a, 0x5a, 0x4c, 0x28, 0xcc, 0xe4, 0xb1, 0x56, + 0xe5, 0x51, 0x40, 0x6a, 0x7e, 0xe8, 0x35, 0x56, 0x56, 0xa2, 0x1e, 0x43, 0xe3, + 0x8c, 0xe1, 0x29, 0xfd, 0xad, 0xb7, 0x59, 0xed, 0xdf, 0xa0, 0x8f, 0x00, 0xfc, + 0x8e, 0x56, 0x7c, 0xef, 0x93, 0xc6, 0x79, 0x2d, 0x01, 0xdf, 0x05, 0xe6, 0xd5, + 0x80, 0xf4, 0xd5, 0xd4, 0x8d, 0xf0, 0x42, 0x45, 0x1a, 0x33, 0x59, 0x0d, 0x3e, + 0x8c, 0xf4, 0x9b, 0x26, 0x27, 0x21, 0x8f, 0x0c, 0x29, 0x2f, 0xa6, 0x6a, 0xda, + 0x94, 0x5f, 0xa5, 0x5b, 0xb2, 0x35, 0x48, 0xe3, 0x3a, 0x83, 0xa5, 0x62, 0x95, + 0x7a, 0x31, 0x49, 0xa9, 0x93, 0xcc, 0x47, 0x23, 0x62, 0x29, 0x87, 0x36, 0xa8, + 0xb7, 0x78, 0xd9, 0x7c, 0xe4, 0x23, 0x01, 0x3d, 0x64, 0xb3, 0x2c, 0xd1, 0x72, + 0xef, 0xa5, 0x51, 0xbf, 0x7f, 0x36, 0x8f, 0x04, 0xbd, 0xae, 0xc6, 0x09, 0x1a, + 0x30, 0x04, 0xa7, 0x57, 0x59, 0x8b, 0x80, 0x1d, 0xcf, 0x67, 0x5c, 0xb8, 0x3e, + 0x43, 0xa5, 0x3a, 0xe8, 0xb2, 0x54, 0xd3, 0x33, 0xbc, 0xda, 0x20, 0xd4, 0x81, + 0x7d, 0x34, 0x77, 0xab, 0xfb, 0xa2, 0x5b, 0xb8, 0x3d, 0xf5, 0x94, 0x9c, 0x12, + 0x6f, 0x14, 0x9b, 0x1d, 0x99, 0x34, 0x1e, 0x4e, 0x6f, 0x91, 0x20, 0xf4, 0xd4, + 0x1e, 0x62, 0x91, 0x85, 0x00, 0x2c, 0x72, 0xc0, 0x12, 0xc4, 0x14, 0xd2, 0x38, + 0x2a, 0x6d, 0x47, 0xc7, 0xb3, 0xde, 0xab, 0xa7, + ], + script_code: Script(vec![0xac, 0x00]), + transparent_input: Some(0), + hash_type: 3, + amount: 711752082734717, + consensus_branch_id: consensus::BranchId::Overwinter, + sighash: [ + 0xb3, 0x8e, 0x31, 0x70, 0x8c, 0xb7, 0x8e, 0xee, 0xc7, 0x66, 0x3e, 0xca, 0x1e, + 0x01, 0xb7, 0x53, 0x9e, 0x26, 0xb7, 0x30, 0xcf, 0x44, 0x6d, 0x3b, 0xf5, 0x7a, + 0x99, 0x8e, 0x9e, 0xd9, 0x2b, 0x47, + ], + }, + Test0143Vector { + tx: vec![ + 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x00, 0x02, 0x0d, 0x38, 0x6a, + 0xe3, 0x0d, 0xd3, 0x01, 0x00, 0x07, 0x00, 0x65, 0x51, 0x65, 0x53, 0x53, 0x6a, + 0xd5, 0x09, 0x42, 0xf7, 0x69, 0x67, 0x02, 0x00, 0x05, 0xac, 0x65, 0x63, 0x65, + 0xac, 0x61, 0xa7, 0xb8, 0xb9, 0xf6, 0x99, 0xd6, 0x01, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x49, 0x23, 0x2f, 0x32, 0x9f, 0xef, 0x95, 0xc7, 0xaf, 0x37, 0x00, 0x98, + 0xff, 0xe4, 0x91, 0x8e, 0x0c, 0xa1, 0xdf, 0x47, 0xf2, 0x75, 0x86, 0x7b, 0x73, + 0x9e, 0x0a, 0x51, 0x4d, 0x32, 0x09, 0x32, 0x5e, 0x21, 0x70, 0x45, 0x92, 0x7b, + 0x47, 0x9c, 0x1c, 0xe2, 0xe5, 0xd5, 0x4f, 0x25, 0x48, 0x8c, 0xad, 0x15, 0x13, + 0xe3, 0xf4, 0x4a, 0x21, 0x26, 0x6c, 0xfd, 0x84, 0x16, 0x33, 0x32, 0x7d, 0xee, + 0x6c, 0xf8, 0x10, 0xfb, 0xf7, 0x39, 0x3e, 0x31, 0x7d, 0x9e, 0x53, 0xd1, 0xbe, + 0x1d, 0x5a, 0xe7, 0x83, 0x9b, 0x66, 0xb9, 0x43, 0xb9, 0xed, 0x18, 0xf2, 0xc5, + 0x30, 0xe9, 0x75, 0x42, 0x23, 0x32, 0xc3, 0x43, 0x9c, 0xce, 0x49, 0xa2, 0x9f, + 0x2a, 0x33, 0x6a, 0x48, 0x51, 0x26, 0x3c, 0x5e, 0x9b, 0xd1, 0x3d, 0x73, 0x11, + 0x09, 0xe8, 0x44, 0xb7, 0xf8, 0xc3, 0x92, 0xa5, 0xc1, 0xdc, 0xaa, 0x2a, 0xe5, + 0xf5, 0x0f, 0xf6, 0x3f, 0xab, 0x97, 0x65, 0xe0, 0x16, 0x70, 0x2c, 0x35, 0xa6, + 0x7c, 0xd7, 0x36, 0x4d, 0x3f, 0xab, 0x55, 0x2f, 0xb3, 0x49, 0xe3, 0x5c, 0x15, + 0xc5, 0x02, 0x50, 0x45, 0x3f, 0xd1, 0x8f, 0x7b, 0x85, 0x59, 0x92, 0x63, 0x2e, + 0x2c, 0x76, 0xc0, 0xfb, 0xf1, 0xef, 0x96, 0x3e, 0xa8, 0x0e, 0x32, 0x23, 0xde, + 0x32, 0x77, 0xbc, 0x55, 0x92, 0x51, 0x72, 0x58, 0x29, 0xec, 0x03, 0xf2, 0x13, + 0xba, 0x89, 0x55, 0xca, 0xb2, 0x82, 0x2f, 0xf2, 0x1a, 0x9b, 0x0a, 0x49, 0x04, + 0xd6, 0x68, 0xfc, 0xd7, 0x72, 0x24, 0xbd, 0xe3, 0xdd, 0x01, 0xf6, 0xff, 0xc4, + 0x82, 0x8f, 0x6b, 0x64, 0x23, 0x0b, 0x35, 0xc6, 0xa0, 0x49, 0x87, 0x34, 0x94, + 0x27, 0x6e, 0xa1, 0xd7, 0xed, 0x5e, 0x92, 0xcb, 0x4f, 0x90, 0xba, 0x83, 0xa9, + 0xe4, 0x96, 0x01, 0xb1, 0x94, 0x04, 0x2f, 0x29, 0x00, 0xd9, 0x9d, 0x31, 0x2d, + 0x7b, 0x70, 0x50, 0x8c, 0xf1, 0x76, 0x06, 0x6d, 0x15, 0x4d, 0xbe, 0x96, 0xef, + 0x9d, 0x43, 0x67, 0xe4, 0xc8, 0x40, 0xe4, 0xa1, 0x7b, 0x5e, 0x51, 0x22, 0xe8, + 0xeb, 0xe2, 0x03, 0x8a, 0x3c, 0x5f, 0x4c, 0xba, 0xe2, 0x1e, 0xa3, 0xfa, 0x1a, + 0xe6, 0xc2, 0x5a, 0x94, 0x62, 0xeb, 0xcb, 0xb0, 0xfd, 0x5f, 0x14, 0x55, 0x4b, + 0xc9, 0x77, 0x47, 0xc3, 0x3e, 0x34, 0xda, 0x90, 0xc8, 0x02, 0xd8, 0xd0, 0xd5, + 0x0b, 0xfe, 0x37, 0x61, 0x8c, 0x58, 0x12, 0x89, 0x14, 0x84, 0xfa, 0x25, 0x93, + 0x22, 0xc1, 0x50, 0x92, 0xd4, 0x15, 0x5d, 0x86, 0x96, 0xd6, 0xf1, 0x2f, 0x24, + 0xfd, 0x36, 0x44, 0x0a, 0xb3, 0xbe, 0x08, 0x71, 0xca, 0x3d, 0xd9, 0x62, 0x53, + 0x48, 0xa6, 0x14, 0xb5, 0x9b, 0xde, 0x45, 0x88, 0x56, 0x49, 0xba, 0xe3, 0x6d, + 0xe3, 0x4d, 0xef, 0x8f, 0xce, 0xc8, 0x53, 0x43, 0x47, 0x5d, 0x97, 0x6a, 0xe1, + 0xe9, 0xb2, 0x78, 0x29, 0xce, 0x2a, 0xc5, 0xef, 0xd0, 0xb3, 0x99, 0xa8, 0xb4, + 0x48, 0xbe, 0x65, 0x04, 0x29, 0x4e, 0xe6, 0xb3, 0xc1, 0xc6, 0xa5, 0x34, 0x2d, + 0x7c, 0x01, 0xae, 0x03, 0x8a, 0xd3, 0x07, 0x0c, 0x2b, 0x1a, 0x91, 0x57, 0x3a, + 0xf5, 0xe0, 0xc5, 0xe4, 0xcb, 0xbf, 0x4a, 0xcd, 0xc6, 0xb5, 0x4c, 0x92, 0x72, + 0x20, 0x0d, 0x99, 0x70, 0x25, 0x0c, 0x17, 0xc1, 0x03, 0x6f, 0x02, 0x08, 0x5c, + 0x41, 0x85, 0x8e, 0xd3, 0xa0, 0xc4, 0x81, 0x50, 0xbc, 0x69, 0x7e, 0x4a, 0x69, + 0x5f, 0xef, 0x33, 0x5f, 0x7a, 0xd0, 0x7e, 0x1a, 0x46, 0xdc, 0x76, 0x7f, 0xf8, + 0x22, 0xdb, 0x70, 0xe6, 0x02, 0x90, 0x80, 0xb9, 0x81, 0x6b, 0x22, 0x32, 0xc8, + 0x1a, 0x4c, 0x66, 0xcc, 0x58, 0x6a, 0xbf, 0xe1, 0xea, 0xa8, 0xca, 0x6c, 0xf4, + 0x1f, 0xc3, 0xc3, 0xe6, 0xc7, 0xb8, 0x86, 0xfb, 0x6d, 0xac, 0x9f, 0x02, 0x22, + 0xb4, 0xfc, 0x6f, 0xff, 0x9d, 0x05, 0x13, 0xd6, 0x1a, 0x21, 0xc8, 0x0a, 0x37, + 0x76, 0x71, 0xd1, 0x35, 0xa6, 0x68, 0xa0, 0xae, 0x2b, 0xb9, 0x34, 0xc8, 0x2c, + 0x41, 0x42, 0xda, 0x69, 0xd1, 0x02, 0xa7, 0xde, 0x9a, 0x7d, 0xf7, 0x06, 0x40, + 0x0e, 0xc7, 0x98, 0x78, 0xd8, 0x68, 0xe1, 0x7e, 0x8f, 0x71, 0xea, 0x31, 0x49, + 0x5a, 0xf8, 0x19, 0xa0, 0x16, 0xcc, 0x41, 0x9e, 0x07, 0xc5, 0x01, 0xaa, 0x83, + 0x09, 0xb2, 0xe6, 0xc8, 0x5b, 0x79, 0xb2, 0x76, 0x37, 0x33, 0xa3, 0x7b, 0xbc, + 0x04, 0x20, 0xd4, 0x25, 0x37, 0xb8, 0x71, 0xb4, 0x29, 0x4a, 0x65, 0xd3, 0xe0, + 0x55, 0xff, 0x71, 0x8d, 0xd9, 0xdc, 0x8c, 0x75, 0xe7, 0xe5, 0xb2, 0xef, 0xe4, + 0x42, 0x63, 0x73, 0x71, 0xb7, 0xc4, 0x8f, 0x6e, 0xe9, 0x9e, 0x3e, 0xa3, 0x8a, + 0x4b, 0x0f, 0x2f, 0x67, 0xfc, 0x2b, 0x90, 0x8c, 0xda, 0x65, 0x7e, 0xae, 0x75, + 0x4e, 0x03, 0x7e, 0x26, 0x2e, 0x9a, 0x9f, 0x9b, 0xd7, 0xec, 0x42, 0x67, 0xed, + 0x8e, 0x96, 0x93, 0x0e, 0x10, 0x84, 0x78, 0x3c, 0x37, 0xd6, 0xf9, 0xdd, 0x15, + 0xfd, 0x29, 0xf4, 0xcc, 0x47, 0x7e, 0x66, 0xf1, 0x30, 0xd6, 0x30, 0x43, 0x0d, + 0xcc, 0x01, 0x04, 0x89, 0x9b, 0x4f, 0x9f, 0x46, 0xeb, 0x09, 0x0e, 0xf7, 0xfc, + 0x90, 0xb4, 0x79, 0xab, 0xf6, 0x1f, 0x93, 0x95, 0x5e, 0xe0, 0x0e, 0x6a, 0x18, + 0x48, 0xf1, 0xab, 0x14, 0xad, 0x33, 0x4f, 0x2b, 0x68, 0x03, 0x58, 0x08, 0xcd, + 0xf1, 0xbb, 0x9e, 0x9d, 0x9a, 0x81, 0x6b, 0xaf, 0x72, 0x8a, 0x95, 0x5b, 0x96, + 0x0b, 0x77, 0x01, 0xfa, 0x62, 0x66, 0x87, 0xdc, 0x3c, 0x9c, 0xba, 0x64, 0x63, + 0x37, 0xb5, 0x3e, 0x29, 0x81, 0x6e, 0x94, 0x82, 0xdd, 0xf5, 0x57, 0x8a, 0x87, + 0x68, 0xaa, 0xe4, 0x77, 0xfc, 0xe4, 0x10, 0xac, 0x2d, 0x5d, 0xe6, 0x09, 0x58, + 0x61, 0xc1, 0x11, 0xd7, 0xfe, 0xb3, 0xe6, 0xbb, 0x4f, 0xbb, 0x5a, 0x54, 0x95, + 0x54, 0x95, 0x97, 0x27, 0x98, 0x35, 0x0a, 0x25, 0x3f, 0x05, 0xf6, 0x6c, 0x2e, + 0xcf, 0xcb, 0xc0, 0xed, 0x43, 0xf5, 0xec, 0x2e, 0x6d, 0x8d, 0xba, 0x15, 0xa5, + 0x12, 0x54, 0xd9, 0x7b, 0x18, 0x21, 0x10, 0x7c, 0x07, 0xdd, 0x9a, 0x16, 0xef, + 0x84, 0x06, 0xf9, 0x43, 0xe2, 0x82, 0xb9, 0x5d, 0x4b, 0x36, 0x25, 0x30, 0xc9, + 0x13, 0xd6, 0xba, 0x42, 0x1d, 0xf6, 0x02, 0x7d, 0xe5, 0xaf, 0x1e, 0x47, 0x45, + 0xd5, 0x86, 0x81, 0x06, 0x95, 0x4b, 0xe6, 0xc1, 0x96, 0x27, 0x80, 0xa2, 0x94, + 0x10, 0x72, 0xe9, 0x51, 0x31, 0xb1, 0x67, 0x9d, 0xf0, 0x63, 0x76, 0x25, 0x04, + 0x2c, 0x37, 0xd4, 0x8f, 0xfb, 0x15, 0x2e, 0x5e, 0xbc, 0x18, 0x5c, 0x8a, 0x2b, + 0x7d, 0x43, 0x85, 0xf1, 0xc9, 0x5a, 0xf9, 0x37, 0xdf, 0x78, 0xdf, 0xd8, 0x75, + 0x7f, 0xab, 0x43, 0x49, 0x68, 0xb0, 0xb5, 0x7c, 0x66, 0x57, 0x44, 0x68, 0xf1, + 0x60, 0xb4, 0x47, 0xac, 0x82, 0x21, 0xe5, 0x06, 0x06, 0x76, 0xa8, 0x42, 0xa1, + 0xc6, 0xb7, 0x17, 0x2d, 0xd3, 0x34, 0x0f, 0x76, 0x40, 0x70, 0xab, 0x1f, 0xe0, + 0x91, 0xc5, 0xc7, 0x4c, 0x95, 0xa5, 0xdc, 0x04, 0x33, 0x90, 0x72, 0x3a, 0x4c, + 0x12, 0x7d, 0xa1, 0x4c, 0xdd, 0xe1, 0xdc, 0x26, 0x75, 0xa6, 0x23, 0x40, 0xb3, + 0xe6, 0xaf, 0xd0, 0x52, 0x2a, 0x31, 0xde, 0x26, 0xe7, 0xd1, 0xec, 0x3a, 0x9c, + 0x8a, 0x09, 0x1f, 0xfd, 0xc7, 0x5b, 0x7e, 0xcf, 0xdc, 0x7c, 0x12, 0x99, 0x5a, + 0x5e, 0x37, 0xce, 0x34, 0x88, 0xbd, 0x29, 0xf8, 0x62, 0x9d, 0x68, 0xf6, 0x96, + 0x49, 0x24, 0x48, 0xdd, 0x52, 0x66, 0x97, 0x47, 0x6d, 0xc0, 0x61, 0x34, 0x6e, + 0xbe, 0x3f, 0x67, 0x72, 0x17, 0xff, 0x9c, 0x60, 0xef, 0xce, 0x94, 0x3a, 0xf2, + 0x8d, 0xfd, 0x3f, 0x9e, 0x59, 0x69, 0x25, 0x98, 0xa6, 0x04, 0x7c, 0x23, 0xc4, + 0xc0, 0x14, 0x00, 0xf1, 0xab, 0x57, 0x30, 0xea, 0xc0, 0xae, 0x8d, 0x58, 0x43, + 0xd5, 0x05, 0x1c, 0x37, 0x62, 0x40, 0x17, 0x2a, 0xf2, 0x18, 0xd7, 0xa1, 0xec, + 0xfe, 0x65, 0xb4, 0xf7, 0x51, 0x00, 0x63, 0x89, 0x83, 0xc1, 0x4d, 0xe4, 0x97, + 0x47, 0x55, 0xda, 0xde, 0x80, 0x18, 0xc9, 0xb8, 0xf4, 0x54, 0x3f, 0xb0, 0x95, + 0x96, 0x15, 0x13, 0xe6, 0x7c, 0x61, 0xdb, 0xc5, 0x9c, 0x60, 0x7f, 0x9b, 0x51, + 0xf8, 0xd0, 0x9b, 0xdc, 0xad, 0x28, 0xbc, 0xfb, 0x9e, 0x5d, 0x27, 0x44, 0xea, + 0x88, 0x48, 0xb2, 0x62, 0x3a, 0xc0, 0x7f, 0x8e, 0xf6, 0x1a, 0x81, 0xa3, 0x59, + 0x10, 0xb8, 0xa1, 0xba, 0xf3, 0x9a, 0x91, 0x9a, 0x7b, 0x60, 0xbc, 0x60, 0x4d, + 0x63, 0x18, 0x5f, 0x75, 0x92, 0x21, 0xd8, 0x47, 0xcc, 0x54, 0xa2, 0x27, 0x65, + 0xa4, 0xc3, 0x34, 0x75, 0xb5, 0x79, 0x1e, 0x9a, 0xf3, 0x27, 0x1f, 0xc8, 0xd9, + 0x35, 0x06, 0x67, 0x09, 0x0d, 0x81, 0x84, 0xec, 0x50, 0x52, 0x2d, 0x80, 0x4f, + 0x23, 0xc4, 0xfb, 0x44, 0xff, 0xa4, 0x81, 0xbc, 0x92, 0xae, 0x40, 0x8d, 0x1b, + 0x9f, 0x2b, 0x13, 0x19, 0x04, 0xf9, 0x70, 0x5c, 0x59, 0xe2, 0xf4, 0xbd, 0xe7, + 0xa3, 0xb2, 0xc0, 0x85, 0xd9, 0x3f, 0xd2, 0xab, 0xc5, 0xe1, 0x4d, 0x16, 0x30, + 0x01, 0xa1, 0x2f, 0x51, 0x93, 0x8d, 0x02, 0x1a, 0xfa, 0x92, 0x23, 0x9b, 0x87, + 0x3d, 0xc6, 0xc3, 0x57, 0xea, 0xa8, 0xaf, 0x4e, 0xe6, 0xd0, 0x05, 0x40, 0x65, + 0x7f, 0xe3, 0x29, 0x14, 0x10, 0x3b, 0x5d, 0x98, 0xf6, 0x8b, 0xd3, 0xe2, 0xb5, + 0x35, 0x9f, 0x08, 0xcc, 0xd8, 0x8d, 0x0c, 0x81, 0x1e, 0x4c, 0x31, 0xfb, 0xb4, + 0x9f, 0x3a, 0x90, 0xbb, 0xd0, 0x5d, 0xce, 0x62, 0xf3, 0x44, 0xe7, 0x07, 0x75, + 0x93, 0x15, 0x9a, 0xe3, 0x50, 0x50, 0xb0, 0x4c, 0x9e, 0x6b, 0x86, 0xbc, 0x43, + 0x2d, 0xc8, 0xb0, 0x48, 0xc7, 0x3c, 0x00, 0x18, 0xca, 0x5b, 0x69, 0x41, 0x12, + 0x97, 0x73, 0x2a, 0x4e, 0x1a, 0xa9, 0x9a, 0x92, 0x8c, 0x71, 0xe7, 0xa2, 0x4f, + 0xd2, 0x77, 0x85, 0x6a, 0xa4, 0x25, 0x01, 0xe5, 0x1b, 0x01, 0x2a, 0xea, 0x94, + 0x46, 0xa2, 0x10, 0x4e, 0x93, 0xf8, 0x15, 0xa0, 0xb3, 0xa2, 0x9b, 0x45, 0x83, + 0x14, 0xf3, 0xd8, 0xbe, 0x2b, 0x98, 0x23, 0xd3, 0x42, 0xf4, 0x62, 0x13, 0xe9, + 0x42, 0xa7, 0xe1, 0x9a, 0x46, 0xe9, 0x70, 0xb5, 0xc5, 0x06, 0x70, 0x84, 0x30, + 0x31, 0x7b, 0x1b, 0xb3, 0xb3, 0x5d, 0xf6, 0x8a, 0xe3, 0x3a, 0x49, 0x26, 0xa0, + 0x3e, 0x6b, 0xfe, 0xb5, 0x51, 0x04, 0x16, 0xfc, 0xbb, 0x05, 0x24, 0xc9, 0xca, + 0x50, 0x74, 0x15, 0x6c, 0xc5, 0xa5, 0xd6, 0xfe, 0x1c, 0x99, 0x5e, 0xdc, 0x60, + 0xa2, 0xf5, 0x50, 0x41, 0x1a, 0xa4, 0x1e, 0x3d, 0xa3, 0xbd, 0xcf, 0x64, 0xbc, + 0xf0, 0x4a, 0x05, 0x10, 0x57, 0x1b, 0x93, 0x6d, 0x47, 0xe5, 0x5c, 0xec, 0x03, + 0x30, 0xee, 0x8d, 0xfe, 0x73, 0x56, 0x34, 0x04, 0xf0, 0x47, 0xd7, 0xf3, 0xa8, + 0xa3, 0xd7, 0x74, 0x3b, 0xc5, 0x54, 0x95, 0x52, 0x10, 0xf1, 0xeb, 0x0d, 0x08, + 0x59, 0x9e, 0xa7, 0x7d, 0x5f, 0x97, 0x4d, 0x87, 0x17, 0x6d, 0x37, 0xd9, 0x8b, + 0x9c, 0x0a, 0xd4, 0x40, 0x40, 0x72, 0x09, 0xed, 0x6a, 0x9f, 0x08, 0x46, 0x4d, + 0x56, 0x55, 0x93, 0xe1, 0xa6, 0x3b, 0x93, 0x85, 0x36, 0xb4, 0x92, 0x44, 0xe9, + 0x7d, 0x88, 0x01, 0x73, 0xb6, 0x40, 0xf2, 0xdd, 0xb7, 0x4d, 0x06, 0x8e, 0xcb, + 0x46, 0xcf, 0x28, 0x9b, 0x7d, 0x89, 0x13, 0x07, 0xbb, 0xa3, 0x70, 0x54, 0xcf, + 0x91, 0xb3, 0x1f, 0xc8, 0x2f, 0x74, 0xd5, 0xfc, 0xc0, 0x00, 0x94, 0x2e, 0xde, + 0x91, 0x18, 0x25, 0xf5, 0x3f, 0xe6, 0x09, 0x68, 0x6f, 0x46, 0x32, 0x23, 0xb1, + 0xe9, 0xbc, 0x03, 0xbd, 0xe8, 0x95, 0xd1, 0x23, 0x8f, 0xad, 0x04, 0xa3, 0xbf, + 0xce, 0x68, 0xa0, 0x75, 0xe8, 0xa3, 0x7c, 0x0e, 0x87, 0xbf, 0x46, 0xdd, 0x01, + 0x55, 0x45, 0xf9, 0xb4, 0xfb, 0x0e, 0xec, 0x64, 0x5f, 0xfc, 0xbb, 0xe0, 0xca, + 0x5f, 0x8c, 0x56, 0x1b, 0x25, 0x7d, 0x52, 0xd6, 0x02, 0xd8, 0xc9, 0x4c, 0x50, + 0x28, 0x73, 0xa0, 0x1d, 0x92, 0x51, 0xd8, 0xc8, 0x60, 0xc0, 0x41, 0x52, 0x5b, + 0x3b, 0xf4, 0xe3, 0xa2, 0xeb, 0x92, 0x72, 0x81, 0x5c, 0x75, 0x86, 0x76, 0x84, + 0x28, 0xb4, 0xc2, 0xb2, 0x5e, 0x37, 0x45, 0xf0, 0x09, 0xc5, 0xdc, 0xe2, 0x0b, + 0x69, 0xd5, 0xd7, 0xc4, 0x3c, 0xeb, 0x73, 0x6b, 0x68, 0x31, 0xe8, 0xc1, 0x10, + 0xf1, 0x6c, 0xfd, 0xb3, 0xa4, 0x67, 0xe9, 0x41, 0x4c, 0x00, 0xec, 0xf1, 0x37, + 0x31, 0x50, 0x08, 0x94, 0x55, 0x56, 0x78, 0xc4, 0x97, 0xfa, 0xba, 0x9a, 0x95, + 0xd0, 0x1c, 0xc4, 0x64, 0x39, 0x0f, 0xc4, 0xa7, 0x6b, 0xfa, 0x8b, 0x0e, 0x1c, + 0x68, 0xa5, 0x25, 0xd7, 0x06, 0xd6, 0x60, 0x4b, 0x23, 0x30, 0xb6, 0xb3, 0x48, + 0x52, 0x15, 0xf6, 0x06, 0xf1, 0x88, 0x3a, 0x75, 0x15, 0x88, 0xc7, 0xef, 0xa5, + 0x06, 0xc3, 0xe8, 0xd0, 0xc6, 0x01, 0x92, 0xe8, 0x47, 0x6b, 0xd1, 0x17, 0x5d, + 0x95, 0x62, 0x08, 0x7b, 0xdb, 0x81, 0x8e, 0x66, 0x21, 0x62, 0x86, 0xba, 0xfe, + 0x47, 0xff, 0x4d, 0xbc, 0xce, 0xd5, 0x14, 0x44, 0x48, 0x0a, 0x9a, 0x56, 0x73, + 0xec, 0xe7, 0xfa, 0xc7, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xd4, 0x1a, 0xb0, 0x05, + 0x17, 0x53, 0xa7, 0xca, 0xa8, 0x9b, 0xe3, 0x13, 0x9a, 0xfd, 0x97, 0x93, 0xb3, + 0xe0, 0x2f, 0x27, 0xf0, 0x40, 0x04, 0x65, 0x95, 0xac, 0xd4, 0x7b, 0xf1, 0x3f, + 0xd0, 0xda, 0x27, 0xf0, 0x9e, 0xda, 0x48, 0x03, 0x6d, 0x3e, 0xe4, 0x37, 0xf2, + 0xee, 0x8f, 0x86, 0x06, 0xea, 0x97, 0x34, 0x3c, 0x33, 0x58, 0x46, 0x57, 0xf4, + 0x6d, 0xba, 0x99, 0xdb, 0x5c, 0xfe, 0x6c, 0xa1, 0x76, 0xfa, 0xb7, 0xb0, 0xf3, + 0xbf, 0xa0, 0xab, 0x61, 0xe3, 0x40, 0xc3, 0x4e, 0xb9, 0xf1, 0x7c, 0x7e, 0xc2, + 0xbe, 0x03, 0xb1, 0x80, 0xf0, 0xbb, 0x6f, 0x43, 0x4c, 0x2a, 0x65, 0x42, 0xe0, + 0x0e, 0x84, 0x37, 0x3f, 0x4f, 0x46, 0x49, 0xcd, 0xa3, 0x2b, 0xf6, 0x86, 0x66, + 0x61, 0x43, 0xf6, 0x22, 0xaa, 0x48, 0x04, 0x60, 0xb5, 0xaf, 0xac, 0x51, 0x86, + 0x07, 0xcd, 0x9a, 0xf8, 0xbc, 0xd6, 0xb5, 0x8c, 0x30, 0x12, 0x73, 0x16, 0xb2, + 0x5d, 0x5e, 0xa7, 0xbf, 0x6b, 0x0c, 0xab, 0x85, 0x42, 0xff, 0x69, 0xd9, 0xb2, + 0xf1, 0x80, 0xbe, 0x12, 0xed, 0x75, 0x34, 0x4a, 0x39, 0x5a, 0xa1, 0x0f, 0x85, + 0x2f, 0x08, 0x3a, 0xd6, 0x4e, 0xf4, 0x0e, 0x9c, 0x03, 0x09, 0xe9, 0xbb, 0xa5, + 0x4b, 0x8c, 0xb3, 0x3c, 0x95, 0x49, 0x8a, 0x69, 0x53, 0x8d, 0x3a, 0xe5, 0xb2, + 0x5e, 0x24, 0x70, 0x98, 0x30, 0x6f, 0xa8, 0xc7, 0x4a, 0x8e, 0xe5, 0xbc, 0xa9, + 0x41, 0x53, 0x1d, 0x61, 0xaa, 0xc2, 0x7a, 0xab, 0x3d, 0xc5, 0x61, 0x7d, 0x56, + 0x06, 0xc9, 0x57, 0x7a, 0x2a, 0x83, 0x46, 0xe8, 0xd8, 0x5b, 0x32, 0xb8, 0x50, + 0x57, 0x75, 0x10, 0x8d, 0xc8, 0x5e, 0x2a, 0xde, 0x2e, 0xac, 0x1e, 0x63, 0x6e, + 0x1a, 0xf4, 0x05, 0x4c, 0x8b, 0x6f, 0x57, 0x63, 0x2d, 0xf2, 0x69, 0xc3, 0x72, + 0x3b, 0x32, 0x08, 0x72, 0xe4, 0xc5, 0x7b, 0x21, 0x83, 0x58, 0xdc, 0x7e, 0x99, + 0x05, 0xbb, 0x04, 0xed, 0xf9, 0x2e, 0xdf, 0x0d, 0xf6, 0x35, 0xf3, 0xbf, 0x36, + 0x1e, 0x57, 0xa1, 0x32, 0x96, 0xe1, 0x44, 0x7a, 0xf5, 0x08, 0x02, 0x72, 0xd6, + 0x36, 0xe2, 0x75, 0x18, 0xa9, 0x87, 0x6e, 0x15, 0xeb, 0x01, 0xf5, 0xe8, 0xde, + 0xd8, 0x18, 0x92, 0x51, 0x1c, 0xc2, 0x85, 0x1b, 0x00, 0xb8, 0x32, 0x71, 0x2a, + 0x6d, 0x3b, 0xa5, 0x66, 0x03, 0x17, 0xbc, 0xd3, 0x56, 0x76, 0x21, 0xa7, 0xcf, + 0x84, 0x45, 0x58, 0x96, 0x53, 0x26, 0x20, 0x20, 0xc3, 0x3b, 0xf7, 0x80, 0x31, + 0xb8, 0xee, 0x07, 0x07, 0xde, 0x07, 0x20, 0x68, 0xc1, 0x70, 0x57, 0x0b, 0x27, + 0xe6, 0xd9, 0xf5, 0xc6, 0xdd, 0xc3, 0x35, 0x40, 0x2e, 0xfc, 0x54, 0x88, 0x62, + 0xf5, 0xa0, 0x70, 0x94, 0xfd, 0x42, 0x8a, 0x7b, 0xbc, 0x15, 0xd7, 0xb3, 0x8d, + 0x05, 0x36, 0x2c, 0x9c, 0xa9, 0x85, 0xf5, 0x8a, 0x76, 0x64, 0x7d, 0x2b, 0xe4, + 0xc2, 0xcd, 0x6b, 0x3d, 0x17, 0xd6, 0x87, 0x09, 0x71, 0xd7, 0xa0, 0x98, 0xba, + 0xf7, 0x2c, 0x6f, 0x6f, 0x12, 0x14, 0xcf, 0x1f, 0xaa, 0xe4, 0x88, 0x03, 0x7d, + 0xe2, 0x59, 0xd3, 0x41, 0x5c, 0x2f, 0x0d, 0xde, 0xc7, 0x45, 0x70, 0x04, 0xf3, + 0x57, 0x08, 0xd1, 0xec, 0xcc, 0xcc, 0x0d, 0xf6, 0x5a, 0x04, 0x94, 0x3a, 0xd5, + 0xcb, 0xc1, 0x3f, 0x29, 0x5f, 0x02, 0x0f, 0xe0, 0x56, 0xc4, 0x0b, 0x2d, 0x88, + 0xf2, 0x7d, 0xc3, 0x4c, 0xfe, 0xb8, 0x03, 0xbe, 0x34, 0x83, 0xa9, 0xeb, 0xf9, + 0xb5, 0xa9, 0x02, 0x60, 0x57, 0x72, 0x5d, 0x63, 0xea, 0xd2, 0xc0, 0xc0, 0x03, + 0x1f, 0xe2, 0x6a, 0xc1, 0xe7, 0xbd, 0xfc, 0xd6, 0xfa, 0xd8, 0x75, 0x84, 0x2d, + 0x19, 0x4f, 0x33, 0x17, 0x50, 0x46, 0x2c, 0x06, 0xb8, 0xd7, 0x98, 0x2d, 0x67, + 0x99, 0x5e, 0xd5, 0xd3, 0xae, 0x96, 0x02, 0x5a, 0xe0, 0x06, 0x7f, 0x4e, 0xb1, + 0xc7, 0xc9, 0x32, 0x31, 0xbd, 0x39, 0x77, 0x3c, 0xbe, 0x0a, 0x9d, 0x66, 0xb0, + 0xc9, 0xaa, 0x8c, 0xff, 0x6a, 0x37, 0x6e, 0x1f, 0x37, 0x2e, 0xac, 0x6a, 0xc4, + 0x02, 0x6c, 0xc0, 0x94, 0x22, 0x45, 0xd4, 0xc2, 0xdc, 0xf0, 0x2d, 0x76, 0x40, + 0xff, 0xcc, 0x5a, 0x6a, 0xc3, 0xa8, 0x7f, 0x5c, 0x41, 0x15, 0x51, 0xbc, 0xc2, + 0xf2, 0x6c, 0xb9, 0x49, 0x61, 0xd5, 0x3f, 0x95, 0xdd, 0xb1, 0x9a, 0xe9, 0x30, + 0xc8, 0xd7, 0x0f, 0x03, 0x1b, 0x29, 0xa5, 0xdf, 0x99, 0xff, 0x36, 0x69, 0x5e, + 0x80, 0x2c, 0xbc, 0xb6, 0xb5, 0x8c, 0x1b, 0xa7, 0xed, 0x5e, 0xac, 0xfa, 0x76, + 0x41, 0x4a, 0x41, 0xad, 0x4a, 0x44, 0xf7, 0x1f, 0x1b, 0x58, 0x0d, 0x34, 0xc3, + 0xa9, 0x52, 0x92, 0x0b, 0x25, 0x4a, 0x14, 0x5f, 0xea, 0x51, 0x7f, 0x5b, 0x42, + 0xb2, 0xf6, 0x5e, 0xcd, 0x0f, 0x82, 0x59, 0x54, 0x78, 0xd8, 0x0a, 0xe5, 0xc8, + 0xce, 0xea, 0x12, 0xa1, 0x61, 0xcc, 0xbb, 0x5e, 0xac, 0x09, 0x99, 0x0f, 0xc6, + 0x19, 0xa4, 0x60, 0x80, 0x43, 0x6d, 0xbd, 0x08, 0xd7, 0x47, 0x84, 0xaf, 0x00, + 0x2d, 0x58, 0xe0, 0x6f, 0xaf, 0x7f, 0x3c, 0xea, 0xe7, 0xd3, 0x41, 0x9b, 0x1f, + 0xca, 0x26, 0x5a, 0x55, 0x59, 0xcf, 0x9e, 0x2d, 0x3b, 0x60, 0x97, 0x8d, 0x81, + 0xa6, 0x78, 0xb9, 0xed, 0x8e, 0x44, 0x86, 0xb4, 0xd1, 0x46, 0x09, 0xd6, 0xc1, + 0x27, 0xc0, 0xc2, 0xfb, 0xff, 0xe3, 0x0a, 0x60, 0xf7, 0xbf, 0xf1, 0xd9, 0xfb, + 0x83, 0x00, 0xed, 0x00, 0x92, 0x53, 0xba, 0x9b, 0x99, 0x6f, 0xa0, 0x52, 0x41, + 0xb1, 0x0f, 0x5a, 0xc9, 0xa8, 0x40, 0x8e, 0x92, 0x5b, 0x62, 0x6b, 0xb2, 0x1a, + 0x47, 0x1f, 0xe3, 0xbe, 0xde, 0x52, 0xbb, 0xa0, 0x97, 0xb2, 0xa9, 0x9a, 0x9b, + 0xa5, 0xa8, 0x66, 0x58, 0xc3, 0xfd, 0x9e, 0xc5, 0x5b, 0xfa, 0x9b, 0x32, 0x85, + 0x67, 0x25, 0x4a, 0xb3, 0x6d, 0x2c, 0x7f, 0x44, 0xd2, 0xc7, 0xe1, 0x3e, 0xb5, + 0x4b, 0xeb, 0x70, 0xea, 0x8f, 0xa9, 0x4b, 0x6c, 0x6e, 0x01, 0x2d, 0x79, 0xe3, + 0xf5, 0x36, 0x89, 0xc2, 0xb1, 0xa1, 0x8e, 0xaf, 0x2d, 0x47, 0x1d, 0x13, 0xc1, + 0xab, 0x39, 0xd9, 0x19, 0x4a, 0xe8, 0x43, 0xab, 0x1d, 0x28, 0xff, 0xa8, 0xf6, + 0x9d, 0xc7, 0xe1, 0x5c, 0xc3, 0x8b, 0x12, 0xe8, 0xfc, 0xd7, 0x92, 0x55, 0xb7, + 0x21, 0x60, 0x56, 0xd9, 0xed, 0xb7, 0x48, 0x2f, 0xb9, 0x8a, 0xa0, 0x33, 0xb6, + 0x5e, 0x51, 0xc1, 0xa0, 0x8b, 0x8a, 0x11, 0xd8, 0x4d, 0x04, 0x09, 0xb7, 0x34, + 0xf4, 0x52, 0xaa, 0xf0, 0xd6, 0xb1, 0x8f, 0x50, 0x25, 0x86, 0x83, 0xd3, 0xf9, + 0xa7, 0x6d, 0x39, 0x9f, 0xd0, 0x47, 0xee, 0xe2, 0x88, 0xbb, 0x45, 0x85, 0x85, + 0x1d, 0xc9, 0x3e, 0xcc, 0xc6, 0x23, 0x22, 0x92, 0x4c, 0xd1, 0x3b, 0x5d, 0xd4, + 0xee, 0xd6, 0x6e, 0xd8, 0xd9, 0x97, 0x2d, 0x77, 0x26, 0x29, 0xea, 0x64, 0x74, + 0x2e, 0x54, 0x73, 0x39, 0x81, 0xb0, 0x06, 0xc0, 0x62, 0x46, 0x8e, 0x4b, 0xd8, + 0xf7, 0xdd, 0x9a, 0xf6, 0x98, 0xf5, 0x2a, 0xe8, 0x14, 0x63, 0x4e, 0x81, 0xd7, + 0xf3, 0xe0, 0xc4, 0x20, 0x31, 0x7c, 0xac, 0xa9, 0xae, 0x48, 0x11, 0xc6, 0xaf, + 0x06, 0xfe, 0x80, 0xa8, 0xc0, 0x2a, 0xb7, 0xa0, 0x0e, 0x18, 0xe4, 0xa6, 0xaa, + 0x1e, 0xa1, 0xb7, 0x69, 0x45, 0xd2, 0x61, 0x5d, 0x43, 0xac, 0x11, 0x8b, 0x56, + 0xc2, 0xf2, 0x96, 0x0f, 0xe9, 0x3a, 0x02, 0x5f, 0x13, 0xec, 0x91, 0xff, 0xc6, + 0xd2, 0xc3, 0x53, 0x69, 0x9a, 0xbb, 0x09, 0x2d, 0xed, 0xc0, 0x65, 0xdb, 0x8f, + 0xa2, 0x14, 0xdb, 0xc4, 0x64, 0x66, 0xf8, 0x97, 0xb8, 0x8c, 0x58, 0xb3, 0x01, + 0x52, 0x13, 0x3a, 0xa3, 0x83, 0x1a, 0xf3, 0x7c, 0x74, 0xd9, 0x9e, 0x9e, 0x36, + 0xff, 0x70, 0x11, 0xd3, 0x23, 0x83, 0x05, 0x69, 0x15, 0x08, 0xa2, 0xc3, 0xa4, + 0x3e, 0x75, 0x5d, 0xc0, 0x81, 0xb5, 0x11, 0xd6, 0x48, 0x2a, 0x7d, 0xb6, 0x5f, + 0xa9, 0x69, 0x9e, 0xa8, 0x7f, 0xf4, 0x70, 0x99, 0xed, 0x36, 0x37, 0xdb, 0xb0, + 0xa3, 0xd0, 0xef, 0x79, 0x79, 0x6a, 0x8e, 0xf1, 0xe4, 0xd9, 0x4d, 0x42, 0xb4, + 0xbc, 0x2b, 0x4a, 0x03, 0x8a, 0xe6, 0xe4, 0x6b, 0x24, 0xcf, 0xc8, 0x41, 0x53, + 0xd3, 0x1e, 0xaf, 0x89, 0x50, 0x63, 0xa5, 0xca, 0x95, 0x9b, 0xe6, 0x3f, 0x37, + 0xf2, 0xba, 0x0d, 0x43, 0x23, 0x66, 0x73, 0x6d, 0x86, 0x32, 0xfc, 0xe0, 0x72, + 0xb6, 0xae, 0x5b, 0x6f, 0x3f, 0xd5, 0x9d, 0x3f, 0xaf, 0xf6, 0x38, 0x27, 0x5a, + 0x99, 0x2f, 0xef, 0xc8, 0x7e, 0x60, 0xd4, 0x4c, 0x2c, 0xad, 0xc2, 0xb5, 0xc4, + 0x94, 0xe3, 0xe7, 0x2e, 0xb4, 0x59, 0x7c, 0x96, 0xb4, 0x01, 0x67, 0x79, 0x9a, + 0x90, 0x01, 0xa2, 0xed, 0x36, 0x76, 0xa8, 0xb4, 0x03, 0xae, 0x25, 0xff, 0xd7, + 0x72, 0xf7, 0x08, 0x1e, 0x9a, 0x32, 0xbc, 0xc1, 0xc5, 0xe2, 0xed, 0xd4, 0xe2, + 0xa6, 0x57, 0x6b, 0x78, 0x3c, 0xce, 0x3a, 0xae, 0x11, 0xfa, 0x43, 0x22, 0x62, + 0x54, 0x88, 0x56, 0x18, 0x3e, 0xe6, 0x82, 0xd5, 0xdc, 0x31, 0xbe, 0xb3, 0x8f, + 0x06, 0x1c, 0xbd, 0xec, 0xa7, 0x02, 0x1a, 0x44, 0x4e, 0x2d, 0xd4, 0x17, 0xdf, + 0x26, 0xdc, 0xd2, 0x20, 0xf2, 0xb7, 0x31, 0x77, 0x2b, 0x43, 0x9e, 0x96, 0xd6, + 0x14, 0xe1, 0xfa, 0xcb, 0x48, 0x6c, 0x7a, 0x7d, 0x51, 0x71, 0xb1, 0xde, 0x35, + 0x9f, 0x6a, 0xd3, 0xa9, 0x6f, 0x64, 0x9c, 0x96, 0x91, 0x02, 0xa1, 0x96, 0x4f, + 0xb4, 0xb4, 0xa1, 0xa4, 0x27, 0x9c, 0x68, 0xe6, 0xc3, 0x72, 0xe4, 0x21, 0x87, + 0xd7, 0x54, 0xe8, 0x04, 0xa6, 0x16, 0x53, 0x09, 0x20, 0x69, 0xfb, 0x9b, 0x6d, + 0x25, 0x26, 0x68, 0x90, 0x80, 0x8b, 0x01, 0x5d, 0xf2, 0x8c, 0x80, 0x10, 0x65, + 0xda, 0x6f, 0xeb, 0xdc, 0x1a, 0x56, 0xbf, 0xd0, 0x02, 0x62, 0x5a, 0xcf, 0xaa, + 0x53, 0x73, 0xfd, 0xe1, 0x49, 0xc1, 0xcf, 0xc3, 0x64, 0x9b, 0x48, 0x69, 0x69, + 0x6d, 0x44, 0xec, 0xb1, 0x24, 0x79, 0xc5, 0xeb, 0xef, 0x99, 0x5f, 0x10, 0x02, + 0x9f, 0x8b, 0x53, 0x0e, 0xeb, 0x3f, 0xdc, 0x2e, 0x50, 0xe8, 0x75, 0x7f, 0xc0, + 0xbb, 0x9e, 0x26, 0x30, 0x23, 0xdb, 0x82, 0xf8, 0x78, 0xd9, 0xac, 0x7f, 0xfb, + 0x0b, 0xd4, 0x39, 0x1d, 0xf1, 0xd8, 0x79, 0x89, 0x9a, 0x3e, 0xf5, 0x7b, 0xfd, + 0x0d, 0x1f, 0x77, 0x55, 0x64, 0x8e, 0xdd, 0x85, 0xbb, 0x05, 0x2a, 0x6e, 0xdf, + 0x71, 0xcd, 0x26, 0x28, 0xc9, 0x87, 0x42, 0x9f, 0x36, 0xdc, 0x50, 0x5c, 0xcc, + 0x43, 0xf3, 0x0e, 0x7a, 0x86, 0x9c, 0x9e, 0x25, 0x5e, 0x2a, 0xf9, 0xfc, 0xf3, + 0x0c, 0x12, 0x17, 0x96, 0xd1, 0x90, 0x00, 0x09, 0x60, 0xcb, 0x6f, 0xe2, 0xf1, + 0xbf, 0x24, 0x61, 0x18, 0xb4, 0x98, 0xf3, 0x24, 0x7f, 0x9d, 0x48, 0x4c, 0x73, + 0xcf, 0x09, 0x39, 0x30, 0x39, 0xe4, 0x53, 0x26, 0xb8, 0xff, 0xff, 0xb3, 0xe7, + 0xe6, 0x15, 0x9c, 0x46, 0x69, 0x9f, 0x10, 0x07, 0x92, 0xd4, 0x67, 0x29, 0x50, + 0x34, 0x8a, 0x90, 0x55, 0x2e, 0x45, 0x94, 0x3b, 0xee, 0xac, 0xf0, 0x3f, 0x32, + 0x16, 0xf9, 0x4e, 0x27, 0x4d, 0x63, 0xd6, 0x37, 0xd9, 0xf1, 0x90, 0xe8, 0xa2, + 0x66, 0xcd, 0xee, 0xf1, 0x53, 0x53, 0x0b, 0xee, 0x5c, 0xb8, 0x35, 0x52, 0x60, + 0x50, 0x5c, 0x2c, 0x2e, 0x5d, 0x99, 0x0f, 0xff, 0xdc, 0x34, 0xec, 0x0f, 0xf7, + 0xf1, 0xaf, 0x81, 0xb2, 0x4c, 0xed, 0x0e, 0xfa, 0x62, 0x13, 0xda, 0x6c, 0x7c, + 0x60, 0xc4, 0x87, 0xf5, 0xf7, 0xb0, 0x3f, 0x81, 0x60, 0xa0, 0x57, 0xf4, 0x6d, + 0x05, 0xbf, 0x82, 0x18, 0xb3, 0xad, 0xd9, 0xc0, 0x68, 0x93, 0xbd, 0x02, 0xdb, + 0x9b, 0x61, 0x19, 0x1d, 0xfb, 0x13, 0x3b, 0xfa, 0xbe, 0x48, 0x58, 0xe4, 0x7a, + 0x4c, 0xc3, 0x2e, 0x41, 0x6e, 0xc0, 0x8b, 0x8a, 0xc7, 0x91, 0x5a, 0x43, 0x73, + 0x3f, 0x44, 0x06, 0xe9, 0xd9, 0x67, 0xc5, 0x60, 0xf3, 0x44, 0xd7, 0xe9, 0x04, + 0xa2, 0x80, 0x45, 0xd9, 0x9f, 0x3a, 0xf8, 0xc8, 0x2e, 0x97, 0xe1, 0xb9, 0xc1, + 0xb2, 0x05, 0xe5, 0x85, 0xfb, 0xeb, 0xb4, 0x8f, 0xaf, 0x58, 0xf1, 0xb6, 0x5d, + 0xca, 0x24, 0x97, 0xe0, 0x9a, 0x70, 0xaa, 0xd4, 0x86, 0x5f, 0x85, 0x71, 0x5a, + 0x28, 0x0e, 0x18, 0x6f, 0x3f, 0xc1, 0x74, 0x0d, 0x81, 0x84, 0xd3, 0x3e, 0x83, + 0x22, 0x16, 0x95, 0x21, 0xcd, 0xc1, 0x32, 0x21, 0x29, 0x39, 0xc8, 0x4a, 0x10, + 0x89, 0x64, 0xe2, 0xde, 0x74, 0xb6, 0xea, 0x55, 0xb4, 0xcb, 0x8f, 0x6f, 0x9b, + 0xee, 0x98, 0xb1, 0x0d, 0x41, 0x51, 0x09, 0x45, 0x5f, 0x48, 0xb7, 0x76, 0x08, + 0x2d, 0xc3, 0x0b, 0x4b, 0xc7, 0x34, 0x77, 0x07, 0x55, 0x11, 0x70, 0x03, 0x08, + 0x15, 0x8c, 0xe2, 0xf2, 0xf9, 0xbf, 0x0f, 0x69, 0x1b, 0x2c, 0xe5, 0x3e, 0x61, + 0x14, 0x2c, 0xb7, 0x40, 0xc1, 0x5b, 0x7b, 0x62, 0x3c, 0xf4, 0x8b, 0x3f, 0x7b, + 0xfe, 0xfa, 0x31, 0xbc, 0xdc, 0x66, 0x5c, 0x6d, 0x71, 0x23, 0xe9, 0x53, 0x50, + 0x81, 0x13, 0x75, 0x94, 0x7b, 0x05, 0x5a, 0x43, 0xdb, 0x07, 0xe0, 0x3f, 0x33, + 0x62, 0x7d, 0xf5, 0xc6, 0x38, 0xbf, 0xad, 0x95, 0x6d, 0xdc, 0x1e, 0xa7, 0xd7, + 0x62, 0x0a, 0x20, 0xf2, 0x79, 0x2f, 0x63, 0x81, 0x7a, 0x1c, 0xf3, 0x25, 0x80, + 0xd0, 0x42, 0x74, 0x23, 0x4a, 0xf2, 0xa5, 0x1b, 0x56, 0xbb, 0x68, 0xa2, 0x9e, + 0x43, 0xa9, 0x54, 0x14, 0x2b, 0xa4, 0xca, 0x68, 0x23, 0xbd, 0xe9, 0x05, 0x3d, + 0x72, 0xfd, 0xad, 0xbc, 0x61, 0xad, 0x59, 0x36, 0xc5, 0x3f, 0xdd, 0x75, 0x79, + 0x44, 0x6d, 0x11, 0xc4, 0x46, 0x07, 0xf4, 0x16, 0x30, 0xe4, 0xc0, 0x89, 0x15, + 0xe6, 0x31, 0x77, 0x15, 0x50, 0xe9, 0xce, 0x1f, 0xca, 0x2c, 0x63, 0xfe, 0x06, + 0xb7, 0x98, 0x9d, 0x58, 0x4f, 0xa7, 0xd7, 0x82, 0xa8, 0x8c, 0x1e, 0x7d, 0x64, + 0xb6, 0xfb, 0xf5, 0x5e, 0x35, + ], + script_code: Script(vec![0x6a, 0x53, 0x53, 0x63]), + transparent_input: None, + hash_type: 1, + amount: 379068098637835, + consensus_branch_id: consensus::BranchId::Overwinter, + sighash: [ + 0x92, 0xe7, 0xb4, 0x8f, 0x32, 0x81, 0x87, 0x71, 0x26, 0x87, 0xaf, 0x4d, 0xc1, + 0x7a, 0x73, 0xfe, 0x0a, 0x70, 0xac, 0x07, 0x8d, 0x24, 0xcd, 0xcd, 0xd4, 0x58, + 0xa3, 0xd6, 0x86, 0x61, 0xec, 0x0a, + ], + }, + Test0143Vector { + tx: vec![ + 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x24, 0x9d, 0xf0, 0x57, + 0x01, 0xda, 0xb0, 0x31, 0xc4, 0xba, 0xc1, 0xea, 0x26, 0x7a, 0x29, 0x96, 0xa2, + 0x02, 0x8d, 0x1e, 0x6a, 0x0f, 0x80, 0xa3, 0x84, 0x7c, 0x53, 0x1d, 0xba, 0x96, + 0xee, 0x65, 0xa2, 0x41, 0x89, 0xbd, 0x09, 0x52, 0xac, 0x65, 0x63, 0x65, 0xac, + 0x00, 0x65, 0x00, 0xb2, 0xa4, 0xf9, 0x51, 0xef, 0x8f, 0x49, 0x7d, 0xff, 0xf2, + 0xf2, 0xf2, 0x71, 0xea, 0xb8, 0x9c, 0x62, 0x8e, 0x18, 0xb5, 0xfc, 0xb4, 0x38, + 0x82, 0x53, 0x7e, 0xaf, 0x6a, 0xd2, 0xa6, 0xb1, 0x75, 0x46, 0x33, 0xca, 0xa8, + 0x6b, 0xf2, 0xc7, 0x6f, 0x07, 0x53, 0x63, 0x6a, 0x6a, 0x65, 0x6a, 0x53, 0xa2, + 0x21, 0x0c, 0x27, 0x01, 0xea, 0x6c, 0x54, 0x2c, 0xc8, 0xc7, 0x06, 0x00, 0x00, + 0xe0, 0x11, 0x29, 0xf0, 0x3a, 0x1e, 0x9c, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, + 0x07, 0x62, 0xc0, 0xb1, 0xc6, 0x58, 0x55, 0xde, 0xba, 0x84, 0x22, 0xca, 0x4b, + 0x88, 0xab, 0xee, 0xa6, 0xa4, 0x38, 0x2c, 0xf1, 0x6c, 0xcd, 0x6d, 0xc7, 0xc3, + 0x7c, 0x44, 0xe5, 0x49, 0xc4, 0x53, 0x48, 0x19, 0xac, 0xd8, 0xbb, 0x0a, 0x02, + 0xa5, 0xfa, 0x7a, 0x1c, 0x1d, 0x38, 0x06, 0xfb, 0xc3, 0x40, 0x7f, 0xd7, 0xda, + 0x93, 0xfd, 0x0d, 0xe6, 0x40, 0x0d, 0x3a, 0xb8, 0x97, 0x74, 0x85, 0xcd, 0xdf, + 0xbe, 0xd5, 0x93, 0x2f, 0x50, 0x7b, 0x79, 0x94, 0x7a, 0xdb, 0x2f, 0xad, 0x37, + 0x61, 0x5a, 0xa7, 0x17, 0xdb, 0x5f, 0x29, 0x80, 0x99, 0xf2, 0x0f, 0x26, 0x3b, + 0x35, 0x9a, 0x11, 0x51, 0xa6, 0xb7, 0x5c, 0x01, 0x36, 0x5e, 0xb1, 0x54, 0xae, + 0x42, 0x14, 0x0d, 0x6e, 0x10, 0x34, 0x2f, 0x14, 0xf3, 0x4d, 0xc3, 0x3e, 0x07, + 0xff, 0x0e, 0x4d, 0x1a, 0x6b, 0xe3, 0x75, 0xb3, 0x2f, 0x84, 0xb9, 0x2e, 0x5d, + 0x81, 0xeb, 0xb6, 0x39, 0xc4, 0xf2, 0x7e, 0x71, 0x5a, 0xa4, 0x2c, 0xc7, 0x57, + 0x07, 0xd4, 0xeb, 0xd1, 0xbb, 0xfb, 0xe8, 0xf9, 0x0f, 0xc7, 0xc9, 0x53, 0xe7, + 0xa9, 0x71, 0x5e, 0x65, 0xaf, 0x82, 0x67, 0x37, 0x3d, 0x34, 0x51, 0x67, 0x4f, + 0xf0, 0x84, 0xef, 0xd9, 0x2c, 0xcf, 0x3b, 0xcc, 0x7a, 0xca, 0x14, 0x67, 0xb6, + 0x32, 0x7e, 0x4f, 0x95, 0x22, 0xb2, 0xcc, 0x57, 0x9a, 0x7a, 0x8f, 0xff, 0x7c, + 0xa7, 0xcf, 0x14, 0x5d, 0xfc, 0x13, 0xea, 0xfc, 0x34, 0x15, 0x3b, 0x2c, 0x3e, + 0x8a, 0xfb, 0xe5, 0x34, 0x44, 0xd0, 0xc7, 0x3b, 0x3b, 0xd5, 0xbc, 0x87, 0x0b, + 0x01, 0xcd, 0x45, 0x79, 0x11, 0xe3, 0x56, 0x31, 0x3f, 0xd1, 0xda, 0xfb, 0x4c, + 0x81, 0x51, 0x63, 0x4a, 0x01, 0xaf, 0xf7, 0xcf, 0x11, 0x6d, 0x43, 0x3c, 0x3d, + 0x2b, 0x3a, 0xdd, 0xa9, 0xce, 0xbe, 0x18, 0xf7, 0xd1, 0x72, 0x44, 0x3e, 0x5e, + 0x7b, 0x5a, 0xc9, 0xab, 0xe8, 0xdb, 0x22, 0x56, 0xd7, 0xeb, 0xe2, 0xff, 0x28, + 0x02, 0x09, 0x39, 0x50, 0x38, 0x70, 0x59, 0x7b, 0x9a, 0x95, 0x58, 0x92, 0xc7, + 0x38, 0x02, 0x50, 0xa2, 0xd4, 0x2e, 0xc9, 0x2b, 0xe7, 0x23, 0xfe, 0xdf, 0x2f, + 0x2e, 0xde, 0x5a, 0x47, 0x2a, 0xa1, 0xe7, 0x4f, 0x33, 0xad, 0x41, 0x90, 0x15, + 0x44, 0xed, 0xbb, 0xe3, 0xac, 0x46, 0x4c, 0xf4, 0x03, 0x19, 0x60, 0x15, 0xf4, + 0xf2, 0x2a, 0xc2, 0xb8, 0xfc, 0x01, 0x49, 0x6b, 0xea, 0xb4, 0xd4, 0x59, 0x07, + 0xf4, 0x79, 0x81, 0x2a, 0x25, 0x94, 0x31, 0xa2, 0xcb, 0xc9, 0x3d, 0x4f, 0x3b, + 0x84, 0xe4, 0x0b, 0x36, 0x60, 0x20, 0x27, 0x3a, 0x67, 0x52, 0xe5, 0x01, 0xaf, + 0x6f, 0xf1, 0xb7, 0x8d, 0xdc, 0x81, 0x7e, 0x6e, 0xa3, 0x51, 0xd6, 0x00, 0x6b, + 0xec, 0xf8, 0xd2, 0xff, 0xb0, 0x39, 0x90, 0xf6, 0x77, 0x74, 0xa8, 0x1e, 0x05, + 0xb7, 0xf4, 0xbb, 0xad, 0x85, 0x77, 0xfa, 0x27, 0xc9, 0xde, 0x64, 0xe1, 0xb1, + 0x1d, 0xcf, 0x38, 0x4f, 0x59, 0x56, 0x44, 0x37, 0x48, 0x75, 0x5a, 0x9f, 0xc6, + 0xf2, 0xa0, 0x03, 0x10, 0xc3, 0x65, 0x7e, 0xba, 0xc0, 0x3b, 0xfc, 0x0b, 0x58, + 0x7b, 0xef, 0x2f, 0x45, 0xec, 0x8a, 0xcd, 0xaa, 0x51, 0xc1, 0x43, 0xb0, 0xcb, + 0x25, 0xb9, 0x14, 0x2c, 0x61, 0xbd, 0x79, 0x0a, 0x80, 0x03, 0xc2, 0x3f, 0x90, + 0xcc, 0x03, 0x49, 0x5b, 0x51, 0xe4, 0xd2, 0x84, 0x3e, 0x55, 0x7f, 0x9e, 0x25, + 0x45, 0x10, 0x8c, 0x6c, 0x6f, 0xae, 0x35, 0x9f, 0x64, 0x5c, 0x27, 0x68, 0x91, + 0xc0, 0xdc, 0xab, 0x03, 0xaf, 0x18, 0x77, 0x00, 0xc0, 0x82, 0xdc, 0x47, 0x77, + 0x40, 0xfb, 0x3f, 0x2c, 0xd7, 0xbb, 0x59, 0xfb, 0x35, 0x85, 0x54, 0xe9, 0x4c, + 0x7e, 0x67, 0x8c, 0xe0, 0x1a, 0xeb, 0xf9, 0x4e, 0x51, 0x5e, 0x03, 0x72, 0x29, + 0x67, 0x99, 0x5a, 0xea, 0x85, 0x8d, 0x64, 0xe7, 0x78, 0x9f, 0xf3, 0x06, 0x36, + 0x95, 0x77, 0x22, 0x81, 0x80, 0x32, 0x6a, 0x5b, 0x0a, 0xf4, 0x75, 0xe2, 0x7a, + 0x54, 0xb2, 0x07, 0xb4, 0x03, 0x92, 0xe3, 0x76, 0x17, 0x0e, 0x3f, 0xb0, 0x05, + 0x02, 0x82, 0x61, 0xc9, 0x9c, 0x2d, 0xbd, 0x0e, 0xed, 0xee, 0x87, 0x1c, 0x1c, + 0x0f, 0x48, 0xb8, 0xe9, 0xb8, 0xe4, 0xbe, 0x77, 0xd1, 0xb7, 0x37, 0xfe, 0x21, + 0xf0, 0xfa, 0x5a, 0x18, 0xeb, 0xb5, 0x27, 0x55, 0xb5, 0xa6, 0xcf, 0x61, 0x30, + 0xfb, 0x56, 0x94, 0x4c, 0xfa, 0xb8, 0x75, 0x27, 0xc2, 0x50, 0xd1, 0x13, 0xb2, + 0x9b, 0xca, 0xc9, 0xaa, 0xa1, 0x0c, 0x2e, 0x7d, 0xe4, 0x15, 0xed, 0xb0, 0x80, + 0x6c, 0x6d, 0xa0, 0x30, 0x20, 0xa1, 0x34, 0xca, 0x7e, 0xcd, 0xc8, 0xda, 0x1b, + 0xd5, 0x7a, 0x37, 0xf5, 0x5a, 0x46, 0x94, 0x0b, 0x45, 0xb2, 0x41, 0xb1, 0xc1, + 0x6e, 0xe1, 0x00, 0x92, 0x7d, 0x1b, 0xd8, 0x60, 0xd4, 0x45, 0xa9, 0xde, 0x50, + 0xd4, 0xc3, 0x84, 0xd6, 0xe1, 0xd0, 0x01, 0x08, 0x02, 0x6c, 0x0e, 0xa5, 0xeb, + 0xbf, 0x0b, 0x72, 0xfb, 0xf5, 0xc3, 0x70, 0xbc, 0xe1, 0x8d, 0x3a, 0xcb, 0xc4, + 0x65, 0x99, 0x09, 0x9b, 0xaa, 0xe1, 0xd8, 0x02, 0xf7, 0x73, 0x33, 0x49, 0x4a, + 0x7a, 0xe1, 0x30, 0xfe, 0x86, 0xe8, 0xf8, 0x18, 0xf9, 0x26, 0x1a, 0x2d, 0xad, + 0xb4, 0x12, 0x52, 0x29, 0xba, 0x0f, 0xfc, 0x0e, 0x70, 0x90, 0x32, 0x44, 0x30, + 0xb5, 0x21, 0xa9, 0x0d, 0x22, 0x4a, 0xb7, 0xa1, 0x02, 0x4e, 0x1d, 0x89, 0x3e, + 0x74, 0x04, 0xfe, 0xdb, 0x34, 0x8e, 0x4d, 0x5e, 0x22, 0x35, 0xc5, 0x9a, 0x78, + 0x76, 0xa0, 0xfc, 0x60, 0x14, 0x5c, 0x6a, 0x00, 0x96, 0x87, 0x68, 0x44, 0x60, + 0x27, 0x1e, 0xe1, 0x33, 0xa4, 0x37, 0xfe, 0x52, 0xfb, 0x6c, 0xfb, 0xa9, 0x7f, + 0xce, 0xc1, 0x61, 0xdf, 0x51, 0x5d, 0xde, 0x90, 0x5a, 0x24, 0xda, 0x6d, 0x37, + 0xbd, 0xc3, 0x40, 0x44, 0xa9, 0x55, 0xe6, 0x82, 0xb4, 0x74, 0x71, 0xca, 0x1e, + 0x8c, 0x78, 0xc5, 0x1e, 0xd3, 0x77, 0xcd, 0x4a, 0xfa, 0x89, 0x4b, 0xd9, 0xbd, + 0x12, 0xe7, 0x07, 0x15, 0x6d, 0xa0, 0x72, 0x6f, 0x7c, 0xf5, 0x72, 0x9f, 0xab, + 0xe3, 0x72, 0x16, 0x04, 0x63, 0xfe, 0x04, 0x29, 0x24, 0x4d, 0x06, 0x74, 0x89, + 0xba, 0x5d, 0x09, 0x47, 0x2e, 0xcd, 0x9b, 0xcd, 0xc4, 0xd5, 0xe4, 0xdf, 0x10, + 0x1e, 0x18, 0x9d, 0xb8, 0x46, 0x3e, 0xb5, 0x38, 0x30, 0x7b, 0x58, 0x7d, 0xef, + 0xf7, 0x8d, 0xe9, 0xc7, 0x3a, 0xf2, 0x80, 0x80, 0xb2, 0xfd, 0x05, 0x00, 0x3e, + 0x11, 0xd3, 0xe1, 0xb3, 0x29, 0x9d, 0xc9, 0x52, 0x1f, 0x8b, 0x51, 0x3b, 0xad, + 0xb0, 0x10, 0xe9, 0x1b, 0xfe, 0xb9, 0x1b, 0x0b, 0x2a, 0x6c, 0xb1, 0x29, 0xc2, + 0xe8, 0x25, 0xa5, 0x97, 0xb8, 0xfb, 0x75, 0xbc, 0x56, 0x2d, 0x65, 0x4d, 0x62, + 0x10, 0x46, 0x40, 0xdd, 0x74, 0xe5, 0x6c, 0xd1, 0x4b, 0xaa, 0xba, 0x56, 0x5b, + 0x84, 0xb8, 0x45, 0xe1, 0x63, 0xd1, 0xca, 0xef, 0x25, 0x33, 0xc3, 0x98, 0x16, + 0x37, 0x20, 0x4f, 0x96, 0xa5, 0x9c, 0x8e, 0x80, 0x24, 0xd9, 0x04, 0x1b, 0x20, + 0x29, 0xe9, 0x4c, 0x15, 0x24, 0x5f, 0x1a, 0x95, 0x88, 0x40, 0xba, 0x3f, 0x38, + 0x0a, 0x4d, 0x20, 0xf1, 0x18, 0x4e, 0x77, 0x82, 0x7d, 0xe3, 0xff, 0x8f, 0x3d, + 0x73, 0x45, 0x9a, 0xfe, 0x24, 0x1f, 0x72, 0x3c, 0x08, 0x48, 0x23, 0x23, 0x0e, + 0x00, 0x3d, 0x3d, 0x21, 0xe5, 0x35, 0x01, 0xec, 0x04, 0x99, 0xb0, 0x83, 0xa7, + 0xda, 0xd6, 0x85, 0xc5, 0x71, 0x27, 0xf4, 0xde, 0x64, 0x73, 0x3a, 0x88, 0x0c, + 0x2d, 0xb2, 0x8f, 0xda, 0xab, 0xf1, 0xb5, 0x42, 0xd2, 0x05, 0xf6, 0x64, 0xa3, + 0x51, 0x35, 0x71, 0x27, 0x11, 0xdc, 0xcc, 0xd9, 0x31, 0xa5, 0x0b, 0x9c, 0x56, + 0x61, 0x88, 0x23, 0x60, 0xd4, 0xca, 0xc0, 0x04, 0x76, 0x81, 0xbc, 0x2e, 0x2b, + 0x3b, 0xf6, 0xc9, 0x97, 0x60, 0xd7, 0xcf, 0xb4, 0xfa, 0x21, 0x39, 0x43, 0x77, + 0xa4, 0x55, 0x1c, 0x76, 0xd1, 0xf7, 0x5a, 0xc0, 0x3c, 0x26, 0x20, 0x54, 0xdf, + 0xfd, 0x79, 0xa9, 0xde, 0xd0, 0x5e, 0x88, 0x89, 0x58, 0x19, 0x9e, 0xea, 0x45, + 0x01, 0xe2, 0x99, 0x0a, 0x53, 0xa5, 0xcd, 0x2a, 0x46, 0xa4, 0x01, 0x57, 0x65, + 0x88, 0xfd, 0x7d, 0x05, 0x8a, 0x26, 0xf2, 0x84, 0x38, 0xe5, 0x78, 0x2f, 0x45, + 0xac, 0x1d, 0x07, 0xf6, 0xf6, 0xf5, 0xed, 0x73, 0x74, 0x1d, 0x57, 0x85, 0x83, + 0x7a, 0x6b, 0x84, 0x4b, 0x47, 0x47, 0x75, 0x71, 0x8c, 0x29, 0xdd, 0x99, 0x08, + 0x4e, 0x9f, 0x88, 0xef, 0x15, 0x3a, 0x83, 0x29, 0xf5, 0x32, 0xa6, 0x90, 0x17, + 0xdc, 0x3a, 0x97, 0xed, 0x75, 0x43, 0x67, 0x72, 0x30, 0x98, 0xe5, 0x76, 0x58, + 0x40, 0xb0, 0x22, 0x89, 0x72, 0x44, 0x74, 0x5f, 0xbb, 0xbb, 0x30, 0xa7, 0xcb, + 0x54, 0xfa, 0x05, 0x11, 0x16, 0x6e, 0x95, 0x44, 0x12, 0x20, 0x00, 0x61, 0x0b, + 0xd2, 0xaa, 0xcb, 0xd8, 0x23, 0x25, 0xa5, 0x9b, 0x95, 0x15, 0x4e, 0xcd, 0x82, + 0xc8, 0x8d, 0x23, 0xab, 0xd1, 0xe2, 0x07, 0x70, 0xff, 0xb8, 0xaa, 0xbf, 0x83, + 0xfc, 0x07, 0x34, 0x96, 0x4c, 0xcd, 0x41, 0x1d, 0x1c, 0x93, 0x57, 0x14, 0xe2, + 0x4a, 0xab, 0x56, 0x6f, 0x4f, 0x08, 0x42, 0x40, 0x14, 0xc4, 0xec, 0xa9, 0x1b, + 0x59, 0x0f, 0x08, 0x2b, 0x47, 0x3f, 0x36, 0x1c, 0x87, 0x41, 0x5d, 0x37, 0xbd, + 0x20, 0xd7, 0x0f, 0xd0, 0xb5, 0x2b, 0x6d, 0xdf, 0x18, 0x65, 0xf7, 0x66, 0x70, + 0x2e, 0x32, 0xb0, 0x5b, 0x3c, 0xf1, 0x63, 0x0e, 0xe8, 0x59, 0x7a, 0xae, 0x19, + 0x63, 0x3f, 0x35, 0x16, 0xa8, 0x55, 0x5a, 0xc5, 0xbe, 0x32, 0xc6, 0x75, 0xbe, + 0x18, 0x17, 0xef, 0xbf, 0xfd, 0x93, 0x69, 0x04, 0x1a, 0x08, 0x9c, 0x28, 0x3f, + 0x19, 0x64, 0x99, 0x68, 0xc2, 0x49, 0x8c, 0xde, 0x56, 0xf5, 0x00, 0x43, 0x4f, + 0x28, 0x0d, 0x77, 0xa9, 0xc6, 0x2e, 0x43, 0xcb, 0xd3, 0xf1, 0x36, 0xa4, 0xc6, + 0xa0, 0x0a, 0x43, 0xe6, 0xed, 0x53, 0x0c, 0xb2, 0xe8, 0xae, 0x83, 0x88, 0x60, + 0xad, 0xc8, 0x8a, 0xac, 0xc7, 0xbd, 0x6a, 0x00, 0xae, 0x0c, 0x19, 0xff, 0x45, + 0x33, 0xa4, 0x85, 0xef, 0xde, 0x08, 0x2b, 0x5f, 0x4d, 0x1f, 0x7a, 0x8e, 0xbe, + 0x7e, 0xd8, 0x2b, 0x7b, 0x05, 0xa8, 0xcf, 0xe1, 0xe3, 0x73, 0x45, 0x9f, 0x1b, + 0xdc, 0xbf, 0x95, 0x25, 0x74, 0x7e, 0x8c, 0x95, 0x08, 0xa5, 0x55, 0xfa, 0xcb, + 0x79, 0x87, 0x40, 0xe0, 0xbd, 0xf9, 0x94, 0xd9, 0x73, 0x9b, 0xbe, 0x55, 0x38, + 0xa0, 0xae, 0x0f, 0x07, 0x6c, 0x58, 0x2c, 0x0f, 0x5b, 0xa8, 0x78, 0xb9, 0x9b, + 0x82, 0x49, 0xdb, 0x1d, 0x7e, 0x95, 0x05, 0x6c, 0x98, 0xaf, 0x08, 0x3d, 0x98, + 0xcb, 0x0e, 0xd9, 0xe3, 0xf7, 0x43, 0x6e, 0x1c, 0x76, 0x43, 0x76, 0x6f, 0x96, + 0x6b, 0x83, 0xe9, 0x99, 0x20, 0x6e, 0xbd, 0x13, 0x93, 0xb9, 0xb2, 0xa7, 0xf4, + 0x14, 0x48, 0x0f, 0xa0, 0x17, 0x48, 0x00, 0x69, 0xf8, 0x5c, 0x77, 0x49, 0xc4, + 0x35, 0xae, 0x2f, 0xba, 0x2d, 0xdc, 0x10, 0x38, 0xd5, 0x47, 0xd8, 0x48, 0x54, + 0x81, 0x7e, 0xf3, 0x96, 0x35, 0xc2, 0x98, 0x27, 0xaa, 0xd8, 0x67, 0x26, 0xc9, + 0xad, 0xe3, 0xb2, 0x65, 0xb9, 0x08, 0x6c, 0x8b, 0x5b, 0x75, 0xef, 0x56, 0xfe, + 0x4b, 0xd8, 0xb4, 0xd6, 0x28, 0x93, 0x89, 0x5b, 0x3f, 0xd2, 0x73, 0x4f, 0xda, + 0xc4, 0x64, 0x15, 0x6d, 0x7e, 0x5e, 0xbc, 0x7e, 0xcf, 0x1d, 0x83, 0xb8, 0x6f, + 0x65, 0x96, 0x37, 0xe3, 0xb1, 0x42, 0xc1, 0x64, 0x96, 0x3b, 0x8c, 0xdc, 0xf4, + 0xba, 0x4f, 0x40, 0x35, 0xdf, 0xfc, 0x5a, 0x78, 0x94, 0x58, 0x84, 0x77, 0x81, + 0x91, 0x8a, 0xc7, 0x2f, 0xc1, 0x8b, 0xbb, 0xf5, 0x11, 0x00, 0x32, 0xe6, 0x6d, + 0x75, 0xb3, 0x17, 0x1e, 0xf4, 0xb5, 0x13, 0x29, 0x01, 0x64, 0xa7, 0x7b, 0x42, + 0xb0, 0xa4, 0xcf, 0xb8, 0x96, 0x39, 0xab, 0x23, 0x84, 0x5e, 0x1a, 0xa2, 0xa4, + 0x52, 0xf3, 0x73, 0x1c, 0x8c, 0xb6, 0x50, 0x82, 0xa6, 0x22, 0xa7, 0xc2, 0xe0, + 0x01, 0x3e, 0xa4, 0x7d, 0x0b, 0xdd, 0x42, 0xd6, 0x99, 0x04, 0x66, 0x64, 0x9a, + 0x90, 0x5c, 0x68, 0x4c, 0x32, 0x51, 0x71, 0x6d, 0x61, 0xf7, 0x60, 0xd5, 0x3d, + 0xe6, 0xe3, 0xf7, 0x90, 0xfb, 0xa7, 0xf5, 0xf1, 0xf4, 0xde, 0x26, 0x71, 0x13, + 0xbd, 0xfc, 0xd7, 0x42, 0x28, 0x22, 0x33, 0x0b, 0x32, 0xd5, 0x8e, 0x67, 0x77, + 0x76, 0x5f, 0x22, 0xa4, 0x11, 0x63, 0x44, 0xee, 0xb6, 0x5b, 0x2e, 0xc5, 0x16, + 0x39, 0x3a, 0xb3, 0x75, 0x1b, 0x53, 0x56, 0xd2, 0xb0, 0xc9, 0x50, 0x0c, 0x0f, + 0x3e, 0x46, 0x91, 0x81, 0x03, 0x5b, 0xc3, 0x66, 0x0f, 0x0b, 0x8f, 0x9f, 0xbe, + 0x6e, 0x40, 0xb5, 0xe8, 0x9c, 0xb7, 0x9b, 0x06, 0x37, 0x14, 0xca, 0x75, 0xe7, + 0x2e, 0x2e, 0x10, 0x0a, 0x10, 0xd6, 0x3b, 0xf7, 0x84, 0xdf, 0x08, 0x20, 0xef, + 0x25, 0xf8, 0xef, 0x40, 0xfe, 0x5f, 0x05, 0xfb, 0x95, 0x68, 0x3f, 0x91, 0x05, + 0xff, 0x3c, 0xb2, 0xd2, 0x19, 0xab, 0x76, 0x60, 0x5a, 0x06, 0x4f, 0x69, 0x21, + 0x9f, 0x1d, 0xc0, 0xd0, 0x0b, 0x3b, 0x48, 0x64, 0x2f, 0x97, 0x0d, 0xc0, 0x0c, + 0xca, 0x4b, 0x8b, 0x43, 0x30, 0x8b, 0xe1, 0x82, 0x86, 0xec, 0x5a, 0x42, 0x88, + 0xd6, 0x00, 0xa3, 0x78, 0x5c, 0xb6, 0x22, 0xd4, 0x68, 0xa4, 0xc6, 0x96, 0x9b, + 0x37, 0x92, 0xf2, 0x48, 0x50, 0x27, 0xd0, 0xad, 0x9a, 0xa4, 0xa9, 0xc2, 0xcc, + 0x97, 0x2f, 0x9e, 0xe5, 0x19, 0x0a, 0x95, 0xb1, 0xeb, 0x05, 0x8d, 0xdd, 0xd8, + 0xc0, 0x8e, 0x7d, 0x75, 0x3f, 0x5e, 0x01, 0x1b, 0x2b, 0xcf, 0xee, 0x1d, 0x52, + 0xc1, 0xc4, 0xf2, 0xca, 0xcd, 0xa3, 0x0b, 0xdb, 0x69, 0x30, 0x65, 0x3c, 0x0c, + 0xc4, 0x48, 0x6e, 0x60, 0xe8, 0x9f, 0xa8, 0x49, 0xb3, + ], + script_code: Script(vec![0x53, 0x52]), + transparent_input: Some(0), + hash_type: 3, + amount: 1437866676382615, + consensus_branch_id: consensus::BranchId::Overwinter, + sighash: [ + 0xd8, 0xe9, 0xb9, 0x72, 0xb2, 0x89, 0x8e, 0xfc, 0xca, 0x8e, 0x96, 0xbc, 0x98, + 0x70, 0x00, 0x8c, 0xdb, 0xc1, 0x9d, 0x45, 0xb7, 0x8d, 0x09, 0xef, 0xb1, 0x02, + 0xf2, 0xd7, 0x0d, 0xba, 0x01, 0xad, + ], + }, + Test0143Vector { + tx: vec![ + 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x01, 0x87, 0xda, 0xa7, 0x31, + 0xf5, 0x70, 0xa7, 0xa4, 0x06, 0x0a, 0xf0, 0xce, 0x70, 0x0d, 0x31, 0xbc, 0xa7, + 0xe7, 0x4b, 0x3e, 0x3b, 0xa3, 0xd0, 0xe8, 0xa6, 0x39, 0x2a, 0x06, 0x2b, 0x8e, + 0x86, 0xd9, 0xd7, 0xd0, 0x0b, 0x21, 0x02, 0x65, 0x53, 0x06, 0x2e, 0x06, 0xb1, + 0x01, 0x30, 0x11, 0xff, 0x08, 0xf0, 0x83, 0x05, 0x00, 0x09, 0x63, 0x6a, 0x52, + 0x63, 0x51, 0x63, 0x00, 0x6a, 0xac, 0x9a, 0xbc, 0xef, 0x2a, 0x99, 0x08, 0x73, + 0x19, 0x00, + ], + script_code: Script(vec![0x63]), + transparent_input: None, + hash_type: 1, + amount: 1993227025071196, + consensus_branch_id: consensus::BranchId::Overwinter, + sighash: [ + 0x2b, 0x62, 0xff, 0x0c, 0x8d, 0xec, 0x4d, 0xf1, 0x8b, 0x99, 0x56, 0x61, 0x5b, + 0x57, 0x4d, 0xda, 0x39, 0x42, 0xfe, 0x45, 0x2d, 0x91, 0x78, 0xb0, 0xbb, 0xb2, + 0xea, 0xee, 0x4d, 0xe4, 0x4a, 0x8c, + ], + }, + Test0143Vector { + tx: vec![ + 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x7c, 0x82, 0x97, 0x7c, + 0x0f, 0xf7, 0x97, 0x09, 0x3e, 0x2c, 0x1f, 0x3a, 0xe8, 0x55, 0xf6, 0x5a, 0xea, + 0x91, 0xe1, 0x31, 0x2f, 0xc6, 0xb8, 0xa4, 0x35, 0x1a, 0x2e, 0xc0, 0x3e, 0x02, + 0xe5, 0xd0, 0x2f, 0x53, 0x35, 0x4b, 0x05, 0x6a, 0x53, 0x52, 0x63, 0x6a, 0x82, + 0xcd, 0x1f, 0x55, 0xeb, 0xca, 0x57, 0xb6, 0x33, 0x7c, 0x85, 0x93, 0x8a, 0x79, + 0x81, 0x3d, 0x20, 0x21, 0xd6, 0x09, 0x4c, 0x68, 0xb3, 0x75, 0xe9, 0x84, 0xf6, + 0x83, 0x93, 0x30, 0x08, 0x71, 0xe3, 0x48, 0xfc, 0x52, 0x36, 0xcc, 0xa6, 0x33, + 0x05, 0xac, 0x63, 0x65, 0x51, 0x63, 0x41, 0x87, 0x01, 0xff, 0x01, 0x86, 0xd2, + 0x6f, 0xee, 0x28, 0xca, 0x06, 0x00, 0x01, 0xac, 0x5a, 0xa7, 0x27, 0xab, 0x79, + 0x85, 0xda, 0x0e, 0x00, + ], + script_code: Script(vec![0x65, 0x53, 0x51]), + transparent_input: Some(1), + hash_type: 130, + amount: 449567650863240, + consensus_branch_id: consensus::BranchId::Overwinter, + sighash: [ + 0x49, 0x3d, 0x49, 0xc3, 0xe2, 0x22, 0x5d, 0x11, 0xc4, 0x64, 0x05, 0x18, 0x20, + 0x14, 0x76, 0x25, 0xf3, 0x90, 0x9f, 0xa7, 0x18, 0x9f, 0x61, 0xc7, 0xea, 0xec, + 0xfc, 0x6d, 0xad, 0x2e, 0x82, 0x03, + ], + }, + Test0143Vector { + tx: vec![ + 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x00, 0x02, 0xe9, 0x6a, 0xa7, + 0x3c, 0xd9, 0xd1, 0x04, 0x00, 0x02, 0x00, 0x53, 0x06, 0xf6, 0x99, 0xe0, 0xb1, + 0x9a, 0x04, 0x00, 0x06, 0xac, 0x65, 0x65, 0x51, 0xac, 0x51, 0x0e, 0x68, 0xae, + 0x38, 0x75, 0x05, 0x51, 0x13, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x92, 0xf1, 0x35, + 0xbf, 0x5f, 0x68, 0x78, 0x7d, 0x37, 0x0c, 0xa8, 0xc4, 0xc4, 0x07, 0x4d, 0xc5, + 0xd6, 0x01, 0xae, 0x90, 0x49, 0x54, 0x37, 0xc3, 0xc2, 0xd4, 0x8a, 0x3d, 0x96, + 0x66, 0x83, 0xac, 0x05, 0x16, 0x0b, 0x7a, 0x84, 0xea, 0xa7, 0xaa, 0xb7, 0x40, + 0x09, 0xe5, 0x7a, 0x85, 0xf7, 0xbf, 0x68, 0xa2, 0xe4, 0x82, 0x00, 0x0f, 0x82, + 0x9c, 0x54, 0x50, 0x73, 0xa1, 0x5d, 0x5c, 0xd0, 0xfc, 0xc5, 0x74, 0x39, 0xa4, + 0x35, 0x0e, 0xaf, 0x09, 0x8d, 0xfb, 0x82, 0xa0, 0x85, 0xea, 0x8a, 0x4a, 0xf6, + 0xfa, 0x83, 0x81, 0xf0, 0x65, 0x88, 0x19, 0xea, 0xb4, 0x83, 0xf6, 0x5b, 0x32, + 0x5d, 0x5a, 0xed, 0xa1, 0x52, 0x32, 0xcf, 0xad, 0xec, 0x75, 0xab, 0x18, 0x66, + 0xe4, 0xc0, 0x15, 0x5a, 0x9c, 0x74, 0xa7, 0xa5, 0x7c, 0xcf, 0x34, 0xc4, 0x83, + 0xac, 0x7d, 0xa1, 0x58, 0x8a, 0x1b, 0x6b, 0x99, 0x41, 0xf1, 0x10, 0x40, 0xf9, + 0x4c, 0xf7, 0x8f, 0xad, 0x89, 0xbf, 0x11, 0xfe, 0xd6, 0x9a, 0xa0, 0xd8, 0x31, + 0x05, 0xad, 0xac, 0xdd, 0x4e, 0x5f, 0x04, 0xa6, 0x24, 0x24, 0x02, 0x3c, 0x9b, + 0x9e, 0x33, 0xc4, 0xfb, 0x7f, 0x12, 0xbd, 0xf2, 0x1f, 0x07, 0xf2, 0x65, 0xc5, + 0x37, 0xd5, 0x1c, 0x65, 0x51, 0xf4, 0x61, 0x7b, 0x91, 0x5d, 0x21, 0x99, 0x18, + 0x39, 0xc3, 0xd0, 0xd3, 0x63, 0x93, 0xd6, 0x46, 0xe0, 0xa8, 0xa4, 0x15, 0x09, + 0x21, 0x7d, 0x0e, 0x7d, 0x2c, 0xa1, 0xa0, 0xa0, 0xd6, 0x77, 0xa3, 0xea, 0xca, + 0x23, 0xed, 0xeb, 0x07, 0xb7, 0x4e, 0x65, 0x2a, 0x0b, 0xc5, 0x0c, 0x6c, 0x08, + 0x3a, 0x55, 0xd6, 0xc7, 0x30, 0x6e, 0x74, 0x08, 0x6f, 0x47, 0x68, 0x93, 0x3a, + 0xa2, 0x48, 0x73, 0x68, 0x18, 0x67, 0xa7, 0x89, 0x3d, 0x77, 0xcb, 0x7f, 0x29, + 0xb8, 0xc8, 0x47, 0xc5, 0x83, 0xf2, 0xd0, 0x71, 0xa6, 0x86, 0x61, 0x6e, 0x20, + 0x67, 0x19, 0xf7, 0x61, 0xae, 0x39, 0xc1, 0x10, 0x44, 0x2e, 0x06, 0x16, 0x3d, + 0x2b, 0x84, 0x59, 0x03, 0x60, 0x69, 0x5d, 0x4e, 0x19, 0x84, 0x9e, 0x03, 0x4f, + 0x24, 0xd9, 0xad, 0x39, 0x6c, 0x19, 0xff, 0x83, 0xce, 0x74, 0xf4, 0x6e, 0x64, + 0x5f, 0x93, 0x2e, 0x14, 0x1a, 0x41, 0x19, 0x59, 0x36, 0xc8, 0x5d, 0x51, 0x44, + 0x14, 0xf1, 0x12, 0xe6, 0x0b, 0x02, 0x25, 0x37, 0xc3, 0x8d, 0x6d, 0xc6, 0xc4, + 0x63, 0x83, 0x05, 0xc9, 0xbd, 0x6c, 0x62, 0xe3, 0x66, 0xbc, 0x63, 0x12, 0x3e, + 0x3e, 0x6d, 0xd3, 0x6e, 0xed, 0xd3, 0x13, 0x6f, 0xce, 0x8d, 0xee, 0xca, 0x0a, + 0xa0, 0x9a, 0x32, 0x98, 0xa3, 0x9d, 0x83, 0x85, 0x9e, 0xfc, 0x9b, 0x2b, 0x69, + 0xcf, 0x9a, 0x7d, 0xee, 0x08, 0xa9, 0x8e, 0x4b, 0xe5, 0x58, 0xac, 0x79, 0x12, + 0xfd, 0xcb, 0x42, 0x20, 0x90, 0x75, 0x42, 0x02, 0x60, 0xf7, 0xca, 0xd0, 0xf2, + 0xc0, 0x1f, 0x2a, 0xfe, 0x33, 0x07, 0x3f, 0x26, 0x24, 0x9d, 0x94, 0x4f, 0x7a, + 0x50, 0xdd, 0x84, 0x83, 0x9b, 0xc3, 0xea, 0x7f, 0xde, 0xe4, 0xed, 0x71, 0x02, + 0x9c, 0xf0, 0x75, 0x33, 0xd2, 0x6e, 0x1e, 0x27, 0xa3, 0xef, 0xb0, 0x32, 0xc3, + 0xa3, 0xb3, 0x4b, 0xd3, 0x09, 0x26, 0x22, 0xd2, 0x06, 0x2a, 0xe5, 0x36, 0xef, + 0x51, 0x49, 0xc4, 0x9b, 0x5b, 0xc9, 0x03, 0x5e, 0xaf, 0xab, 0x6e, 0x67, 0x57, + 0x61, 0x00, 0x8b, 0x0d, 0xad, 0xde, 0xec, 0xaa, 0x60, 0x44, 0x70, 0xbb, 0xe0, + 0xfa, 0xda, 0x25, 0x5d, 0x29, 0x0e, 0x92, 0xb1, 0x90, 0xc2, 0xc2, 0xd8, 0xc2, + 0x02, 0xe5, 0x45, 0x5d, 0x1f, 0xa9, 0xa9, 0xf3, 0xdb, 0x77, 0x79, 0xb5, 0x84, + 0x64, 0x34, 0x64, 0xaa, 0x80, 0x14, 0xba, 0x66, 0x99, 0x4d, 0xe2, 0x55, 0x17, + 0xf8, 0x39, 0x80, 0xe6, 0x6e, 0xe4, 0xf6, 0x03, 0x14, 0xae, 0x6d, 0xbe, 0xf4, + 0x52, 0xd5, 0xd3, 0x8b, 0x0a, 0x16, 0xf3, 0x99, 0x1f, 0x36, 0xd8, 0xa8, 0xb3, + 0x9d, 0xdc, 0x0d, 0x55, 0x95, 0xee, 0xd9, 0x87, 0x62, 0x87, 0x8c, 0xdf, 0x3f, + 0x4a, 0x02, 0xdc, 0x5c, 0xda, 0x77, 0xd5, 0xfe, 0x4f, 0xaf, 0x63, 0xa1, 0x5f, + 0x56, 0x8a, 0x54, 0x0d, 0xa5, 0x7d, 0xd9, 0xbe, 0xb6, 0xfb, 0x1a, 0x97, 0x7c, + 0xcb, 0x91, 0xb4, 0xd7, 0x9c, 0xb3, 0x9b, 0x28, 0x91, 0x1a, 0x29, 0xe7, 0xbf, + 0x02, 0x8a, 0xc6, 0x10, 0x37, 0x96, 0xdf, 0xb6, 0xb2, 0x09, 0x67, 0x23, 0x9a, + 0xd3, 0x73, 0xc3, 0x8c, 0x53, 0xf6, 0xdf, 0x18, 0x23, 0xd4, 0x95, 0x0a, 0x02, + 0x83, 0xe9, 0x9b, 0x9c, 0x06, 0xab, 0x29, 0x66, 0x66, 0x7c, 0x9d, 0xf6, 0x77, + 0x71, 0x6b, 0x0c, 0xad, 0xed, 0x81, 0x8d, 0xf9, 0xe4, 0x49, 0xc0, 0x72, 0xe2, + 0x2f, 0x9d, 0x98, 0xbb, 0x0f, 0x9b, 0x03, 0xbd, 0x5f, 0xd0, 0x13, 0xfc, 0xef, + 0x3e, 0xd6, 0xa4, 0x9a, 0xeb, 0x98, 0x72, 0x02, 0x54, 0x08, 0x7e, 0xf7, 0x28, + 0xe3, 0x19, 0x47, 0xff, 0xe8, 0xf7, 0x66, 0xe6, 0x3e, 0xe4, 0x6f, 0xf2, 0x08, + 0x16, 0xd5, 0xfa, 0x8f, 0xf5, 0x5a, 0x26, 0x39, 0x89, 0x61, 0x49, 0x0a, 0xb9, + 0xae, 0x36, 0x6f, 0xc5, 0xa2, 0xd1, 0x99, 0x6e, 0xd6, 0x93, 0xcc, 0xca, 0x82, + 0x35, 0x6f, 0x60, 0x0a, 0xb0, 0x99, 0xf6, 0xec, 0xa8, 0xbf, 0xe6, 0x45, 0x27, + 0x0d, 0x3f, 0x95, 0xed, 0xba, 0x5b, 0x0d, 0xe7, 0xa3, 0x28, 0x19, 0x23, 0x3b, + 0xcc, 0x75, 0x4a, 0x5c, 0xe2, 0xe5, 0xea, 0x07, 0x84, 0x2e, 0x5f, 0xf2, 0xce, + 0xbe, 0x62, 0xad, 0x76, 0xe8, 0xef, 0xf8, 0xd1, 0x5e, 0xa4, 0xc2, 0x4a, 0x5f, + 0x20, 0x78, 0x68, 0x31, 0x9a, 0x5a, 0xf6, 0xb0, 0x35, 0xbe, 0x3f, 0x44, 0xf4, + 0x34, 0x09, 0x4f, 0x6e, 0x52, 0x5b, 0xe6, 0x14, 0xda, 0xc9, 0x20, 0xa3, 0x30, + 0xbd, 0xfb, 0x26, 0xd7, 0x5f, 0xe7, 0xb4, 0xb3, 0x65, 0xd0, 0x94, 0x45, 0x92, + 0x50, 0xaa, 0xa5, 0x54, 0x44, 0x89, 0xfb, 0x1d, 0x99, 0x25, 0x81, 0x80, 0x0a, + 0x77, 0xb8, 0x91, 0x21, 0x57, 0xfc, 0x97, 0x13, 0xaa, 0xac, 0x25, 0xb4, 0xc2, + 0x6e, 0xb0, 0x3f, 0x71, 0x66, 0x46, 0x61, 0x9a, 0xf0, 0x24, 0x56, 0xae, 0x69, + 0x59, 0x62, 0xfe, 0x5e, 0x93, 0x1a, 0x63, 0xb5, 0xc7, 0x90, 0x52, 0xec, 0xd3, + 0x33, 0xe1, 0x84, 0x12, 0xdb, 0x91, 0xe1, 0x5f, 0x7c, 0xbc, 0x70, 0xb4, 0xcd, + 0x7e, 0x8e, 0x3c, 0x95, 0x1f, 0x35, 0x85, 0x72, 0xe3, 0x77, 0x67, 0xe7, 0xd5, + 0x27, 0x04, 0xa6, 0x72, 0x1b, 0x30, 0xef, 0xc4, 0x10, 0x17, 0xae, 0x4d, 0x23, + 0x15, 0x58, 0xc5, 0xc8, 0x2c, 0xc7, 0xdd, 0x7e, 0x33, 0x56, 0xc0, 0x9d, 0xc2, + 0x49, 0x06, 0xf0, 0x43, 0x8d, 0xfc, 0xc3, 0x00, 0x85, 0x6a, 0xc2, 0xce, 0xd8, + 0xf7, 0x7f, 0xa8, 0x01, 0x57, 0x36, 0xc6, 0x61, 0xe8, 0x02, 0x48, 0xae, 0xeb, + 0x77, 0x48, 0x74, 0xaa, 0x79, 0xd2, 0x90, 0xb8, 0xf5, 0x02, 0x7a, 0x0a, 0x50, + 0x95, 0x37, 0xfc, 0x7c, 0x68, 0x9b, 0x7a, 0xd8, 0x61, 0x16, 0xcf, 0xec, 0x26, + 0x47, 0xcc, 0xaa, 0xe1, 0xc7, 0x4b, 0x41, 0x6f, 0x3e, 0x6a, 0xe8, 0xf7, 0xcc, + 0x60, 0xea, 0xaf, 0x7b, 0x6a, 0x59, 0x0d, 0x51, 0x54, 0x41, 0x38, 0xe1, 0x73, + 0x29, 0x45, 0x60, 0x3a, 0x53, 0x46, 0x2c, 0x60, 0xe1, 0xf6, 0xcb, 0x0c, 0x9c, + 0xa0, 0x39, 0x0c, 0x48, 0x82, 0x24, 0xc3, 0x13, 0x26, 0x9f, 0xcd, 0x59, 0xfc, + 0xb6, 0x11, 0xfb, 0x2d, 0x9b, 0x4c, 0x8f, 0xa6, 0x01, 0xbb, 0x1c, 0xb8, 0xd0, + 0x7d, 0x79, 0x7b, 0xf5, 0xde, 0x52, 0xbc, 0xee, 0xb0, 0x23, 0x01, 0xc8, 0x96, + 0x2a, 0xc1, 0xfc, 0x04, 0x91, 0xdc, 0x81, 0xaf, 0xfd, 0x6c, 0x1e, 0xbf, 0x89, + 0xa1, 0x3d, 0x6f, 0x29, 0x0e, 0xda, 0x5d, 0x5c, 0xef, 0x38, 0x22, 0x15, 0xc5, + 0xe9, 0x51, 0xd7, 0x13, 0x05, 0xef, 0x33, 0xd9, 0x73, 0x71, 0x26, 0xd0, 0xe6, + 0x62, 0x90, 0x5f, 0x12, 0x50, 0x92, 0x6f, 0x6a, 0x22, 0x99, 0x90, 0xe3, 0x8f, + 0x69, 0xad, 0x9a, 0x91, 0x92, 0xb3, 0x02, 0xf2, 0x6b, 0xdd, 0xa4, 0x65, 0xd9, + 0x0b, 0x94, 0xb1, 0x2c, 0x57, 0xfa, 0x3f, 0xd6, 0x93, 0x00, 0x83, 0xf1, 0x84, + 0x43, 0x8d, 0x8a, 0x88, 0x9d, 0x3f, 0x5e, 0xce, 0xa2, 0xc6, 0xd2, 0x3d, 0x67, + 0x36, 0xf2, 0xa0, 0xf1, 0x8e, 0x26, 0xf4, 0xfa, 0x45, 0xd1, 0xbe, 0x8f, 0x3d, + 0xc4, 0xa7, 0x07, 0x13, 0x7e, 0x95, 0xd2, 0xad, 0x59, 0x4f, 0x6c, 0x03, 0xd2, + 0x49, 0x23, 0x06, 0x7a, 0xe4, 0x7f, 0xd6, 0x42, 0x5e, 0xfb, 0x9c, 0x1d, 0x50, + 0x4e, 0x6f, 0xd5, 0x57, 0x53, 0x40, 0x94, 0x56, 0x01, 0xfe, 0x80, 0x6f, 0x57, + 0x56, 0xac, 0xb5, 0x62, 0xf1, 0x3c, 0x0c, 0xa1, 0xd8, 0x03, 0xa1, 0x95, 0xc2, + 0xeb, 0xb2, 0xef, 0x02, 0xac, 0x33, 0xe6, 0xa8, 0x8d, 0xea, 0x07, 0x5b, 0xa9, + 0x96, 0xd3, 0xc3, 0x36, 0x64, 0x8e, 0x86, 0x94, 0xd3, 0xa1, 0x9d, 0x3d, 0xca, + 0x53, 0x1b, 0xeb, 0x50, 0xd4, 0x32, 0x7c, 0x5c, 0x0c, 0x23, 0xcb, 0x7c, 0xfd, + 0xb0, 0x8c, 0xa7, 0xcf, 0x2c, 0xac, 0x6b, 0xc1, 0x39, 0xd0, 0x74, 0x14, 0x73, + 0xd3, 0x76, 0x02, 0x9c, 0xb4, 0xab, 0x6b, 0xf0, 0x54, 0x55, 0x7c, 0xe2, 0x94, + 0xc7, 0x28, 0xa4, 0x68, 0x7d, 0x57, 0xec, 0x89, 0x09, 0xff, 0x51, 0xa4, 0xd0, + 0x2f, 0x9d, 0xcd, 0x11, 0x19, 0x3d, 0x7d, 0x1c, 0x9f, 0xda, 0xe6, 0xa1, 0x73, + 0x96, 0xa1, 0xbf, 0x57, 0xa9, 0x94, 0x93, 0x4f, 0x5e, 0x7a, 0x59, 0xf0, 0x45, + 0xde, 0xbe, 0xaf, 0xf6, 0x2e, 0xf3, 0x26, 0xb9, 0x47, 0xf2, 0xa8, 0xb4, 0x95, + 0x55, 0xe4, 0xd9, 0x9b, 0x3b, 0xf5, 0xc8, 0x1f, 0xf9, 0xfe, 0x31, 0x4e, 0x04, + 0x7a, 0xf1, 0x52, 0x50, 0x8f, 0x57, 0x01, 0x5c, 0xa4, 0x02, 0xc6, 0x7d, 0x92, + 0x5c, 0x99, 0xac, 0xea, 0x3e, 0xe8, 0xcc, 0x4b, 0x00, 0x8c, 0x5c, 0xb4, 0x39, + 0x66, 0xe7, 0x14, 0xef, 0x48, 0x0f, 0xd0, 0x5e, 0x07, 0xc7, 0xb2, 0xdd, 0xa9, + 0xaa, 0x39, 0x66, 0x11, 0x3e, 0xaa, 0x29, 0x3d, 0x3f, 0x62, 0x2b, 0x30, 0x9d, + 0x64, 0x80, 0x3c, 0xe1, 0xe6, 0x37, 0x8b, 0x6a, 0xac, 0x4f, 0xab, 0x52, 0x7c, + 0x43, 0xcd, 0x45, 0xed, 0x0a, 0x3c, 0x1a, 0x4b, 0x9f, 0xb1, 0x8d, 0xcc, 0xcf, + 0xcd, 0xb6, 0xac, 0x0c, 0x24, 0x21, 0x63, 0x9c, 0xda, 0x00, 0x75, 0xa2, 0x0d, + 0xc5, 0x11, 0x1b, 0x8d, 0x3d, 0x31, 0x99, 0x49, 0x5b, 0xd9, 0x13, 0x3d, 0xba, + 0xb9, 0x45, 0x41, 0x41, 0x0e, 0x4f, 0xba, 0x92, 0xc7, 0xb6, 0x06, 0xa5, 0xcb, + 0x12, 0x2f, 0x14, 0x0c, 0xf1, 0xa3, 0x59, 0x6f, 0x27, 0x88, 0xf3, 0xc8, 0xb9, + 0x26, 0x60, 0xf1, 0x4c, 0xb6, 0x5a, 0xf5, 0xdd, 0x23, 0xdf, 0xdb, 0xac, 0x13, + 0x71, 0xec, 0xf4, 0xb3, 0x37, 0x12, 0xfe, 0xd2, 0x29, 0x2c, 0x44, 0xf7, 0x08, + 0x34, 0xcf, 0x96, 0xc0, 0x5d, 0x58, 0x82, 0x7e, 0x69, 0xbf, 0xc2, 0xe6, 0x96, + 0xfa, 0x08, 0x74, 0x86, 0x9c, 0x02, 0xf3, 0xdc, 0xa1, 0x1c, 0x3b, 0x90, 0xcb, + 0x21, 0x4e, 0x68, 0xbc, 0x1c, 0xae, 0x03, 0x9d, 0x7a, 0x14, 0x6c, 0xdc, 0x1d, + 0x60, 0x9d, 0x7a, 0x6b, 0x3f, 0xd5, 0xd4, 0x61, 0xb0, 0x95, 0x1c, 0x82, 0xcf, + 0xb3, 0xe7, 0x63, 0xfa, 0xd2, 0xd1, 0xbc, 0x76, 0x78, 0xcd, 0xf8, 0x27, 0x79, + 0xf8, 0xfd, 0x5a, 0x1c, 0xe2, 0x2a, 0x8d, 0x3c, 0x45, 0x47, 0xab, 0xd9, 0x59, + 0x83, 0x8a, 0x46, 0xfb, 0x80, 0xaf, 0xe0, 0x1f, 0x8e, 0xcc, 0x99, 0x31, 0x51, + 0x3b, 0x19, 0x62, 0xec, 0x54, 0x08, 0x56, 0xcb, 0x18, 0x93, 0x87, 0xcf, 0xbf, + 0xcc, 0x0f, 0x7c, 0x68, 0x22, 0x3c, 0xba, 0x47, 0xfb, 0x0c, 0x9b, 0x48, 0x6e, + 0x4d, 0x99, 0x17, 0x19, 0x41, 0xf7, 0x67, 0x5a, 0x8b, 0x46, 0x32, 0x8a, 0x3b, + 0xc1, 0x09, 0xbf, 0x07, 0xc6, 0x6d, 0x5e, 0xde, 0x77, 0x1c, 0xc4, 0xc7, 0x4c, + 0xe8, 0x03, 0x33, 0x82, 0x91, 0x91, 0xee, 0xdc, 0x49, 0x35, 0x08, 0xa6, 0x44, + 0x53, 0x0a, 0x61, 0x44, 0xf2, 0x2d, 0xcf, 0x97, 0x52, 0x5a, 0x4c, 0xdc, 0xa1, + 0xad, 0x71, 0x07, 0x3b, 0x08, 0x0b, 0x73, 0xea, 0x45, 0x49, 0xf5, 0x40, 0x1b, + 0xff, 0x43, 0x18, 0x26, 0x8e, 0x6a, 0xd6, 0x37, 0x36, 0x31, 0x57, 0xa1, 0x9a, + 0x53, 0xf1, 0x23, 0xa0, 0xb0, 0xe1, 0x6d, 0x0b, 0x77, 0xf0, 0x20, 0x28, 0xda, + 0x46, 0x41, 0x00, 0xfd, 0xe7, 0x6d, 0x83, 0xdd, 0x0b, 0xb2, 0x24, 0xf7, 0xb5, + 0x7a, 0x00, 0xc0, 0x2f, 0x68, 0xae, 0x64, 0x8f, 0xdc, 0x52, 0x99, 0x57, 0xa1, + 0x04, 0x90, 0xdc, 0xe1, 0xfd, 0xdb, 0xb0, 0x90, 0x4f, 0x0d, 0x51, 0x8b, 0xb3, + 0x87, 0x54, 0x40, 0x19, 0x98, 0x3b, 0x61, 0x69, 0x75, 0xa7, 0x8e, 0x74, 0xd8, + 0x54, 0xfd, 0xdc, 0x49, 0xb2, 0x55, 0x16, 0x7b, 0x55, 0xef, 0x4b, 0xee, 0x46, + 0x56, 0x68, 0xb2, 0x0e, 0xa4, 0x11, 0x8c, 0xa5, 0x69, 0xae, 0x48, 0x0e, 0x0f, + 0x6e, 0x5e, 0x04, 0x3a, 0x35, 0x7b, 0x36, 0xd3, 0xab, 0x36, 0xc8, 0x61, 0xf2, + 0x27, 0x83, 0x01, 0xdc, 0xe5, 0x76, 0x74, 0xd5, 0x07, 0x3b, 0x3a, 0x6f, 0x51, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa0, 0x79, 0x3a, 0xf1, 0xb7, 0xd4, 0x6f, 0x95, 0x7e, + 0x22, 0xd8, 0xd2, 0x58, 0x3b, 0xf1, 0x81, 0x83, 0x6c, 0x3b, 0xe9, 0x93, 0x0b, + 0xac, 0x8f, 0xa4, 0x60, 0xe9, 0x68, 0xaa, 0x71, 0x09, 0x87, 0x0b, 0xbe, 0xd1, + 0x7d, 0xf5, 0xf8, 0x88, 0xc8, 0xca, 0x14, 0x67, 0xae, 0x17, 0xdb, 0xbc, 0xde, + 0x31, 0xc1, 0x10, 0x5c, 0xb5, 0xbd, 0xa8, 0x8a, 0xc6, 0xc6, 0x27, 0x00, 0x2c, + 0xe2, 0x1c, 0x02, 0x14, 0x0f, 0xfe, 0x81, 0xec, 0x58, 0xbf, 0x1e, 0x6d, 0x1b, + 0xb7, 0xaa, 0xad, 0xa4, 0x1f, 0xba, 0x0b, 0xb5, 0x88, 0x77, 0x8a, 0x7f, 0x65, + 0x20, 0x2a, 0xd8, 0x11, 0xea, 0x73, 0xd2, 0x6c, 0x74, 0x55, 0x03, 0x95, 0xaf, + 0xf7, 0x53, 0x25, 0x10, 0x7c, 0x9b, 0x3f, 0x9a, 0xe9, 0xdc, 0xdc, 0xd8, 0x6e, + 0xd0, 0x81, 0xa2, 0xe7, 0x42, 0x47, 0x19, 0xa3, 0xd1, 0x85, 0xb7, 0xe0, 0xa4, + 0x3a, 0x47, 0x2e, 0x29, 0x8a, 0xc0, 0xaf, 0xdc, 0x52, 0x87, 0xd7, 0xad, 0x12, + 0x4c, 0xd9, 0x40, 0x5a, 0x62, 0xcd, 0x1c, 0xa0, 0x8b, 0x28, 0x2e, 0xfe, 0xf7, + 0xf9, 0x28, 0xdf, 0x76, 0xe2, 0x82, 0x1a, 0x41, 0x84, 0x13, 0xeb, 0x7c, 0xea, + 0xa5, 0xff, 0x12, 0x90, 0xb0, 0x3e, 0xc9, 0x1c, 0xe6, 0xdd, 0x28, 0x13, 0x0c, + 0x3a, 0xb0, 0xb2, 0x3b, 0x60, 0x2b, 0xd5, 0xbe, 0x5d, 0xc2, 0x60, 0x03, 0xaa, + 0xe0, 0x4b, 0x33, 0xd7, 0xbd, 0x25, 0x90, 0xe9, 0x0c, 0x8c, 0x38, 0x8e, 0xa7, + 0x95, 0x51, 0x22, 0xdb, 0xac, 0xa6, 0x7b, 0x30, 0x39, 0x5a, 0x92, 0x8b, 0x57, + 0xb8, 0x57, 0x51, 0x23, 0x20, 0x5a, 0xe1, 0x91, 0x52, 0xe4, 0x1e, 0x00, 0x29, + 0x31, 0xb4, 0x57, 0x46, 0x19, 0x8e, 0x5d, 0xd9, 0x57, 0x1a, 0x56, 0xa7, 0xe0, + 0xd4, 0x23, 0xff, 0x27, 0x98, 0x9d, 0x3e, 0xb4, 0x17, 0xec, 0xd3, 0xc3, 0x09, + 0x3f, 0xb8, 0x2c, 0x56, 0x58, 0xe2, 0x96, 0x24, 0xc5, 0x32, 0x19, 0xa6, 0x0c, + 0xd0, 0xa8, 0xc4, 0xda, 0x36, 0x7e, 0x29, 0xa7, 0x17, 0x79, 0xa7, 0x30, 0x32, + 0x98, 0x5a, 0x3d, 0x1f, 0xd0, 0x3d, 0x02, 0xd0, 0x6e, 0x05, 0x56, 0x6f, 0x3b, + 0x84, 0x36, 0x7c, 0xf0, 0xfa, 0xee, 0x9b, 0xc3, 0xbd, 0x7a, 0x3a, 0x60, 0x6a, + 0x9f, 0xdb, 0x84, 0x9c, 0x5d, 0x82, 0xd0, 0xa6, 0x19, 0x23, 0xc2, 0xe5, 0xd8, + 0x02, 0x63, 0xa8, 0xa5, 0x0c, 0x38, 0xbd, 0x03, 0x87, 0x72, 0xc4, 0x14, 0x3d, + 0x8b, 0x7a, 0xcf, 0xd7, 0x4e, 0x72, 0xc0, 0x4d, 0x89, 0x24, 0x8d, 0xff, 0x20, + 0xfe, 0x8d, 0xc5, 0xec, 0x21, 0x49, 0x05, 0x0a, 0xa2, 0x41, 0x64, 0xe8, 0x5f, + 0x67, 0x44, 0xad, 0x0c, 0xac, 0xf1, 0xa8, 0xb7, 0x01, 0x26, 0xf4, 0x82, 0xc0, + 0x92, 0xed, 0x9f, 0x61, 0x27, 0xd2, 0x05, 0x0d, 0x12, 0xe8, 0x78, 0xa7, 0x96, + 0x53, 0xa1, 0xe8, 0x4d, 0xae, 0xc3, 0xeb, 0xe6, 0x2d, 0x5f, 0x6c, 0x4a, 0xbe, + 0x5c, 0xe9, 0x0a, 0x7f, 0xe2, 0xe5, 0x2a, 0x8d, 0x78, 0x46, 0xe8, 0xed, 0xf2, + 0xf2, 0xbc, 0xe0, 0x5a, 0x03, 0x7c, 0x82, 0x03, 0x22, 0xca, 0xad, 0x12, 0x61, + 0x46, 0x7d, 0xcf, 0xb7, 0xd6, 0xb6, 0x13, 0x3d, 0xc2, 0x1e, 0x80, 0x96, 0xc7, + 0xe9, 0xf8, 0xe9, 0xe1, 0x0c, 0x1e, 0x3f, 0xac, 0x40, 0x58, 0xb6, 0x82, 0xc6, + 0x8e, 0x02, 0xfa, 0xca, 0xe0, 0xf9, 0xc2, 0xdd, 0x4d, 0x64, 0xd9, 0x04, 0x61, + 0x52, 0xb4, 0x76, 0x23, 0x32, 0x93, 0x9f, 0x17, 0xe6, 0xaa, 0xf7, 0xd8, 0xb9, + 0xd3, 0x58, 0xe2, 0x21, 0x8d, 0x4e, 0x0d, 0x69, 0x02, 0xf1, 0x19, 0xe1, 0xc6, + 0x4e, 0xec, 0x4c, 0x8b, 0x53, 0x28, 0x09, 0x70, 0x71, 0x31, 0xf0, 0x1f, 0x55, + 0xc7, 0xad, 0x04, 0xcf, 0xb6, 0x3f, 0x7c, 0x4a, 0x3d, 0x0a, 0x2b, 0x0f, 0xfb, + 0x0b, 0x05, 0x02, 0xbe, 0x05, 0x5b, 0x8c, 0x94, 0xca, 0x80, 0xbb, 0x0a, 0x1d, + 0x13, 0xcd, 0x4c, 0xd6, 0x9a, 0xb9, 0x83, 0x04, 0xae, 0x25, 0x15, 0xd5, 0xf7, + 0x69, 0x9d, 0x4a, 0xbe, 0xe5, 0xc2, 0x0b, 0xe6, 0x09, 0x02, 0x73, 0x51, 0x10, + 0x12, 0xf2, 0x34, 0xbd, 0x85, 0xa7, 0xef, 0xf5, 0xfb, 0x63, 0x4c, 0xff, 0x26, + 0x58, 0xba, 0x65, 0x16, 0x04, 0x85, 0x63, 0x09, 0x5e, 0xce, 0xfb, 0x30, 0x15, + 0xee, 0x3f, 0x03, 0xca, 0x52, 0xa1, 0x77, 0xf2, 0x61, 0xec, 0xdc, 0x26, 0xbc, + 0x08, 0x9d, 0x34, 0xc6, 0x40, 0x48, 0x46, 0xe9, 0xc6, 0x47, 0xfc, 0xfe, 0x98, + 0xcc, 0x6a, 0xcd, 0xbb, 0x46, 0x4f, 0x64, 0x27, 0x8a, 0xd8, 0xce, 0x9d, 0x1a, + 0xe0, 0xd4, 0x15, 0xbc, 0x0c, 0x05, 0x24, 0x5f, 0xdd, 0xaf, 0x4e, 0xbc, 0x8d, + 0xc7, 0x03, 0xa8, 0x5c, 0xb2, 0x70, 0xf7, 0x96, 0xad, 0x2d, 0x93, 0x7e, 0x2a, + 0xc0, 0xd5, 0xe0, 0xa3, 0x48, 0x21, 0x75, 0x80, 0x00, 0xaa, 0x59, 0xc9, 0xd4, + 0x65, 0x24, 0x85, 0x29, 0x4e, 0xe0, 0xab, 0x29, 0x69, 0x6b, 0x21, 0x43, 0x0f, + 0xa5, 0x4d, 0xcf, 0xbf, 0x2b, 0x9c, 0x49, 0xd1, 0x42, 0x06, 0x42, 0x09, 0xee, + 0xee, 0xd4, 0xd4, 0x71, 0xff, 0xc0, 0x17, 0xd4, 0xe2, 0x0a, 0x79, 0x6b, 0x09, + 0x27, 0x80, 0x4c, 0x06, 0x1b, 0x9f, 0x4a, 0x70, 0x91, 0xfe, 0x01, 0x5a, 0xda, + 0x68, 0xfd, 0x84, 0x42, 0xe0, 0x18, 0x25, 0xc8, 0x8d, 0xfe, 0x55, 0xcf, 0x5d, + 0xe3, 0x89, 0x36, 0xf7, 0xce, 0x25, 0x31, 0x1b, 0x90, 0x2b, 0xa9, 0x7a, 0x3c, + 0x12, 0xa9, 0x5c, 0xfa, 0x1c, 0x3a, 0x59, 0x1b, 0x81, 0x8f, 0x60, 0x83, 0x27, + 0x09, 0xd9, 0xe4, 0x83, 0x9e, 0x41, 0x0f, 0xb3, 0x6b, 0x84, 0xf3, 0xac, 0x4f, + 0x07, 0x0f, 0xc3, 0x5e, 0x16, 0x19, 0x78, 0x25, 0x9e, 0x5b, 0x8e, 0xdc, 0x74, + 0x4d, 0x90, 0x91, 0x9a, 0xa7, 0x70, 0xbb, 0x36, 0x21, 0x51, 0x28, 0xe5, 0x82, + 0xb5, 0x96, 0x41, 0xe2, 0x38, 0x52, 0xe9, 0x58, 0xeb, 0x8f, 0xc3, 0xc0, 0xaa, + 0x96, 0x15, 0x2b, 0xa4, 0xf7, 0x7f, 0x13, 0x8d, 0x6a, 0x67, 0x12, 0xa3, 0xae, + 0x32, 0x26, 0x01, 0x58, 0x83, 0xf8, 0x1d, 0xb2, 0x3e, 0x58, 0x3c, 0x86, 0x9c, + 0x4c, 0x71, 0x14, 0x3a, 0x6f, 0xff, 0xd6, 0x5e, 0x8d, 0xfd, 0xc5, 0x0c, 0x99, + 0xa2, 0xf1, 0xf3, 0x14, 0xcd, 0xcc, 0x71, 0x35, 0x9e, 0x23, 0x5f, 0x1d, 0x7d, + 0xc2, 0xb5, 0xf3, 0x8e, 0xf7, 0xb9, 0x70, 0x84, 0x31, 0x63, 0xc0, 0x3f, 0x9d, + 0xd4, 0x0a, 0x80, 0x15, 0xef, 0xdc, 0x87, 0x91, 0x95, 0x6a, 0x3f, 0x3c, 0xed, + 0xd9, 0xea, 0x64, 0xf8, 0xef, 0xa7, 0xa0, 0x81, 0x5a, 0x70, 0x38, 0x1d, 0x71, + 0x46, 0x78, 0x17, 0xbd, 0x04, 0xca, 0x52, 0x9a, 0xed, 0xe0, 0x7f, 0xf6, 0x0d, + 0x17, 0x6a, 0xed, 0x0f, 0x85, 0x5a, 0x2e, 0xae, 0xa8, 0x9e, 0xae, 0xac, 0xa8, + 0x93, 0x58, 0xc0, 0x81, 0x82, 0x6a, 0x08, 0x12, 0xa5, 0xbc, 0xa2, 0x8b, 0xe1, + 0x37, 0x3f, 0x08, 0x6d, 0xbd, 0xba, 0x7e, 0x43, 0xe2, 0x03, 0x21, 0x2c, 0x9f, + 0xed, 0x21, 0x47, 0x4b, 0xa1, 0x9a, 0x05, 0x5f, 0xfc, 0xc1, 0x79, 0x41, 0x2e, + 0x89, 0x3a, 0x74, 0x48, 0x32, 0x29, 0x8c, 0x5f, 0xe2, 0x4c, 0xc6, 0xb1, 0x86, + 0x67, 0xf4, 0x9b, 0x34, 0xdf, 0xb1, 0x23, 0x79, 0x26, 0x74, 0x19, 0xa9, 0xcb, + 0x94, 0x03, 0xd8, 0x16, 0x7d, 0x8d, 0x1e, 0x91, 0xd2, 0x81, 0x1a, 0x04, 0x3b, + 0x29, 0x24, 0x3b, 0x06, 0x9b, 0x37, 0x58, 0x78, 0x47, 0xdc, 0x6f, 0xcd, 0xdb, + 0x18, 0x31, 0xbd, 0x1c, 0xc2, 0x56, 0x7c, 0xa0, 0x33, 0xac, 0x40, 0xf7, 0x4a, + 0xb6, 0x95, 0x5f, 0x68, 0x3b, 0x12, 0xe4, 0xe8, 0x25, 0x4e, 0x4e, 0xa7, 0x60, + 0xd3, 0x8b, 0x3f, 0x46, 0x79, 0x1c, 0x5c, 0x4c, 0xb1, 0x2b, 0xc7, 0xcc, 0xb0, + 0xed, 0x18, 0x65, 0xf2, 0x5d, 0x60, 0x1c, 0x30, 0x3f, 0x81, 0xfb, 0x1f, 0xa1, + 0xdb, 0x48, 0x53, 0x3d, 0x3d, 0x6b, 0x28, 0x8e, 0x4d, 0x9a, 0x4d, 0xff, 0x8e, + 0xc2, 0x1c, 0x96, 0xf5, 0x78, 0x39, 0x97, 0x10, 0xc8, 0x25, 0xfe, 0x7e, 0x32, + 0xf9, 0x3a, 0x8c, 0x07, 0x43, 0xf9, 0xeb, 0xd5, 0x4c, 0xc1, 0x51, 0xc7, 0x61, + 0x03, 0x37, 0xae, 0xbf, 0x7e, 0x9b, 0x91, 0x57, 0x20, 0xa5, 0x43, 0x51, 0xd4, + 0x9a, 0xb8, 0xc2, 0x2f, 0xa3, 0x49, 0x98, 0xdc, 0xf5, 0x83, 0xd4, 0x38, 0x73, + 0x61, 0xef, 0x3f, 0xf8, 0x6f, 0x50, 0xec, 0x53, 0xf4, 0x92, 0x49, 0xe4, 0xad, + 0x34, 0x96, 0x03, 0x06, 0x6f, 0xc9, 0xc6, 0x61, 0xd6, 0x9f, 0x91, 0x1d, 0xfa, + 0x72, 0x41, 0xc8, 0xd5, 0x79, 0x2d, 0x43, 0xc4, 0x57, 0xd5, 0xde, 0x96, 0x52, + 0x3a, 0x53, 0xd6, 0x67, 0xec, 0x5c, 0x4e, 0xf9, 0xd5, 0x02, 0xa1, 0x6f, 0x15, + 0x22, 0x47, 0x58, 0x96, 0xd7, 0x9b, 0xc5, 0x78, 0x33, 0xe9, 0x77, 0x17, 0x1c, + 0x32, 0x4d, 0xce, 0x2a, 0x1e, 0xa1, 0xe4, 0x30, 0x4f, 0x49, 0xe4, 0x3a, 0xe0, + 0x65, 0xe3, 0xfb, 0x19, 0x6f, 0x76, 0xd9, 0xb8, 0x79, 0xc7, 0x20, 0x08, 0x62, + 0xea, 0xd1, 0x8d, 0xea, 0x5f, 0xb6, 0xa1, 0x7a, 0xce, 0xa3, 0x33, 0x86, 0xeb, + 0x4c, 0xa1, 0xb5, 0x14, 0x86, 0xa9, 0x14, 0x8f, 0xbd, 0xf9, 0xa9, 0x53, 0x32, + 0xaa, 0x60, 0x5c, 0x5d, 0x54, 0x83, 0xce, 0x4b, 0xa8, 0xec, 0xe0, 0x1a, 0x8f, + 0xf2, 0xb7, 0xef, 0x82, 0xd0, 0x5c, 0x0b, 0x6e, 0x86, 0x1b, 0x91, 0x5f, 0x13, + 0xca, 0x0e, 0xb3, 0xea, 0x13, 0xd5, 0x07, 0x08, 0x07, 0xa2, 0xcb, 0x66, 0x80, + 0xa2, 0x49, 0xea, 0x9c, 0x72, 0x24, 0x39, 0x2c, 0xbc, 0x8a, 0xb8, 0x25, 0x01, + 0xb2, 0x6f, 0x11, 0x2a, 0xc7, 0x89, 0xa1, 0x2a, 0x31, 0xad, 0x13, 0x14, 0xe2, + 0xed, 0xe0, 0x8f, 0xad, 0x31, 0x43, 0xaf, 0x30, 0xc2, 0x7f, 0x40, 0x3b, 0xc8, + 0x66, 0xc7, 0x55, 0x17, 0x78, 0x52, 0xaf, 0xd0, 0xab, 0xb9, 0x0a, 0xde, 0x1d, + 0x68, 0x27, 0x26, 0xf4, 0x20, 0x08, 0xb4, 0x6a, 0xd7, 0xf8, 0xab, 0xdb, 0x18, + 0x11, 0x7f, 0x72, 0x64, 0x13, 0x90, 0xf0, 0x86, 0xb6, 0xe1, 0x49, 0x8b, 0xe6, + 0x95, 0x48, 0x52, 0x7e, 0x6a, 0xda, 0x2b, 0x38, 0xb9, 0xfe, 0x12, 0x1e, 0xf6, + 0x70, 0xaf, 0x74, 0x37, 0xd3, 0x25, 0x36, 0xd5, 0xcf, 0x5c, 0x4a, 0xb1, 0x9d, + 0xd9, 0x97, 0x71, 0x58, 0x2d, 0x03, 0x81, 0x04, 0xb7, 0xe0, 0x39, 0xa3, 0x76, + 0xf7, 0xac, 0xbb, 0xea, 0xdb, 0x34, 0xf9, 0x45, 0xbe, 0xb9, 0xd7, 0xca, 0x0e, + 0x4e, 0x3d, 0x5c, 0x5e, 0x4e, 0xb1, 0xd8, 0x52, 0x6e, 0xbd, 0x13, 0xda, 0xcb, + 0x1b, 0xa3, 0x57, 0x35, 0xc6, 0xd0, 0x4a, 0x45, 0x55, 0xac, 0xf4, 0xbf, 0x11, + 0x76, 0x26, 0x50, 0x0d, 0x77, 0xb3, 0x81, 0x89, 0xdd, 0x48, 0x88, 0x04, 0x12, + 0x25, 0xac, 0xbe, 0x38, 0x74, 0xa4, 0xc0, 0xf6, 0x07, 0xfe, 0x67, 0x45, 0xf9, + 0x35, 0x5b, 0x3f, 0xa1, 0x88, 0xf1, 0xd6, 0x5c, 0x09, 0xf3, 0x89, 0xaf, 0x1b, + 0x9d, 0x62, 0x32, 0xaa, 0x79, 0x44, 0x79, 0x19, 0xc5, 0x50, 0xf6, 0xf3, 0x1f, + 0xec, 0x35, 0x48, 0x1c, 0xb9, 0x22, 0xde, 0x2d, 0xb5, 0xb4, 0xda, 0x2f, 0x81, + 0x94, 0x86, 0x17, 0x02, 0x8e, 0x32, 0x17, 0x06, 0xa3, 0xa7, 0x78, 0xc1, 0x93, + 0x8c, 0x44, 0x3b, 0xb0, 0x0e, 0x5b, 0x0f, 0xf0, 0x6a, 0xd8, 0xab, 0x9b, 0x1a, + 0xb0, 0xc1, 0x14, 0x77, 0x67, 0x3f, 0x85, 0xdf, 0x95, 0x61, 0xdb, 0xea, 0x45, + 0xd5, 0xf9, 0x78, 0x1e, 0xbe, 0x31, 0x7a, 0x07, 0x10, 0xae, 0x54, 0x61, 0xe3, + 0x4f, 0xe6, 0xf1, 0xb1, 0xaa, 0x9b, 0x4e, 0x67, 0xb1, 0x49, 0x10, 0x98, 0x48, + 0x02, 0xc2, 0xa7, 0xe3, 0x81, 0x93, 0xbc, 0x7b, 0xdc, 0x8b, 0xa3, 0xe4, 0xe3, + 0xd1, 0xd9, 0x33, 0xbf, 0xb5, 0x80, 0xf5, 0xb3, 0xe8, 0x7a, 0x2a, 0x06, 0x51, + 0x70, 0x51, 0x41, 0x0f, 0xe1, 0xb4, 0xff, 0x1e, 0xa0, 0xad, 0xe8, 0x24, 0xf3, + 0x38, 0x51, 0x54, 0x56, 0xa5, 0x7c, 0x7a, 0x91, 0x6a, 0x74, 0x38, 0x8e, 0xe8, + 0xf1, 0x28, 0x1f, 0x9a, 0xde, 0x0a, 0xe2, 0xa2, 0x61, 0x3a, 0x06, 0x12, 0xc4, + 0x69, 0xdf, 0x79, 0x2b, 0x8d, 0xf4, 0xca, 0xe4, 0xfc, 0x25, 0xc1, 0xca, 0xdb, + 0xa9, 0x5a, 0x80, 0x7c, 0xe6, 0x1e, 0x5a, 0x53, 0x03, 0xfa, 0xaf, 0x9e, 0x14, + 0x65, 0x39, 0x96, 0xb5, 0xa8, 0xad, 0xc3, 0x4f, 0xd4, 0x75, 0xef, 0x14, 0x99, + 0x09, 0x4b, 0xab, 0xaf, 0x1f, 0x3f, 0x07, 0xda, 0x9a, 0x39, 0x0b, 0x1d, 0x9f, + 0xc9, 0xa0, 0x83, 0x27, 0x98, 0x7a, 0xdf, 0xe9, 0x56, 0x48, 0x63, 0xfb, 0xdf, + 0xa8, 0xf6, 0xb4, 0x6a, 0x88, 0x41, 0x58, 0x30, 0x99, 0xaf, 0xb7, 0x87, 0x01, + 0x18, 0xfa, 0xce, 0x76, 0x34, 0x7e, 0x40, 0xb6, 0xfd, 0x8c, 0xd1, 0x55, 0x82, + 0xae, 0x8e, 0x23, 0xbe, 0x9a, 0x02, 0x19, 0xbc, 0x3e, 0x4e, 0x45, 0x46, 0xa3, + 0x0d, 0x3b, 0xbb, 0xbd, 0x16, 0x86, 0x08, 0x68, 0x76, 0xbe, 0x0e, 0x4c, 0x85, + 0x9b, 0xe7, 0x1f, 0xb5, 0x8f, 0x4f, 0xab, 0x3d, 0x28, 0xc0, 0xb4, 0xf7, 0xe7, + 0x5a, 0xd1, 0xed, 0xb7, 0xf8, 0x89, 0x46, 0xfb, 0x40, 0xcf, 0xa5, 0x78, 0x6a, + 0x0f, 0xcb, 0xa1, 0x30, 0x3c, 0x83, 0x47, 0xec, 0xee, 0x93, 0xd4, 0x6d, 0x14, + 0x0b, 0xb5, 0xf6, 0x95, 0x31, 0xd6, 0x66, 0x54, 0x8b, 0x10, 0x9c, 0xe7, 0x64, + 0xbe, 0xad, 0x7c, 0x87, 0xbd, 0x4c, 0x87, 0x64, 0x94, 0xde, 0x82, 0xdb, 0x6e, + 0x50, 0x73, 0xa6, 0xc9, 0x4f, 0x7c, 0x09, 0x9a, 0x40, 0xd7, 0xa3, 0x1c, 0x4a, + 0x04, 0xb6, 0x9c, 0x9f, 0xcc, 0xf3, 0xc7, 0xdd, 0x56, 0xf5, 0x54, 0x47, 0x76, + 0xc5, 0x3b, 0x4d, 0xf7, 0x95, 0x39, 0x81, 0xd5, 0x5a, 0x96, 0xa6, 0xdc, 0xff, + 0x99, 0x04, 0xa9, 0x08, 0x42, 0xe5, 0xba, 0xfe, 0xc8, 0x84, 0x0c, 0x2d, 0x25, + 0x5b, 0xf5, 0xad, 0x61, 0xc4, 0x60, 0xf9, 0x8f, 0xeb, 0x82, 0xa1, 0x0f, 0xa1, + 0xc0, + ], + script_code: Script(vec![0x65, 0x6a, 0x65, 0x51, 0x52, 0x65, 0x63]), + transparent_input: None, + hash_type: 1, + amount: 1712463999734827, + consensus_branch_id: consensus::BranchId::Overwinter, + sighash: [ + 0xbb, 0x10, 0x30, 0x0e, 0x4d, 0xaf, 0xe3, 0x0c, 0x3f, 0xf0, 0x26, 0x34, 0xd0, + 0xe0, 0x03, 0x2f, 0x17, 0x15, 0xb0, 0x0c, 0xbc, 0x77, 0x3d, 0xf6, 0xb0, 0x9e, + 0x00, 0x43, 0x38, 0x6a, 0x14, 0x18, + ], + }, + Test0143Vector { + tx: vec![ + 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x13, 0xe5, 0x6c, 0x77, + 0x2f, 0x2c, 0x3b, 0x86, 0x0e, 0xa5, 0xb0, 0x3a, 0x88, 0x54, 0xbc, 0x6e, 0x65, + 0x90, 0xd6, 0x3c, 0xc0, 0xea, 0x54, 0xf1, 0x0b, 0x73, 0xba, 0x24, 0x1b, 0xf7, + 0x4b, 0x63, 0x55, 0x51, 0xa2, 0xaa, 0x06, 0x65, 0x6a, 0xac, 0x52, 0x51, 0x63, + 0x36, 0x8b, 0x26, 0xd7, 0x0a, 0x73, 0x7f, 0x26, 0x76, 0x85, 0x99, 0x8a, 0x3f, + 0x7d, 0x26, 0x37, 0x91, 0x49, 0x09, 0xc7, 0x46, 0x49, 0x5d, 0x24, 0xc4, 0x98, + 0x63, 0x5e, 0xf9, 0x7a, 0xc6, 0x6a, 0x40, 0x08, 0x94, 0xc0, 0x9f, 0x73, 0x48, + 0x8e, 0x07, 0x6a, 0x53, 0x65, 0x52, 0x51, 0x65, 0x52, 0x05, 0xf9, 0x1a, 0xd7, + 0x00, 0x79, 0x65, 0xc2, 0x99, 0x36, 0x1d, 0x60, 0x0d, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x89, 0xee, 0x09, 0x62, 0xf5, 0x8c, 0x05, 0x1d, 0x11, 0xd0, 0x55, 0xfc, + 0xe2, 0x04, 0xa5, 0x62, 0xde, 0x68, 0x08, 0x8a, 0x1b, 0x26, 0x48, 0xb8, 0x17, + 0x4c, 0xbc, 0xfc, 0x8b, 0x5b, 0x5c, 0xd0, 0x77, 0x11, 0x5a, 0xfd, 0xe1, 0x84, + 0x05, 0x05, 0x4e, 0x5d, 0xa9, 0xa0, 0x43, 0x10, 0x34, 0x2c, 0x5d, 0x3b, 0x52, + 0x6e, 0x0b, 0x02, 0xc5, 0xca, 0x17, 0x22, 0xba, 0xde, 0xee, 0x23, 0xd1, 0x45, + 0xe8, 0xeb, 0x22, 0x13, 0xfc, 0x4a, 0xf1, 0xe4, 0x50, 0xe4, 0xd5, 0x21, 0x7c, + 0x66, 0x17, 0x00, 0x8c, 0x78, 0xf4, 0xfb, 0x11, 0x12, 0xf4, 0x02, 0x8a, 0x70, + 0x4f, 0xc5, 0xa9, 0x38, 0x2c, 0x6b, 0x03, 0xe7, 0xd8, 0x08, 0x5e, 0x90, 0x6c, + 0xf8, 0x4c, 0xa2, 0xc1, 0x20, 0x7c, 0x87, 0xa2, 0xbc, 0xe2, 0x08, 0x0a, 0x98, + 0x91, 0x66, 0x8d, 0x69, 0xb0, 0x44, 0xbe, 0xce, 0xd6, 0xcd, 0xa3, 0x2c, 0x22, + 0x9c, 0x91, 0x17, 0x91, 0x7a, 0xa0, 0x7d, 0xdf, 0xfc, 0xd3, 0x77, 0x39, 0x5c, + 0xba, 0x61, 0x6d, 0x63, 0xc0, 0xb6, 0x9c, 0x01, 0xfc, 0xc4, 0x53, 0x91, 0xfd, + 0x5b, 0x87, 0x63, 0xfb, 0x96, 0xd7, 0xca, 0x33, 0x3a, 0x12, 0xde, 0x3c, 0xef, + 0xa9, 0x1c, 0x6c, 0x98, 0xf9, 0x47, 0x3b, 0x8e, 0x10, 0x4a, 0x71, 0x29, 0x3e, + 0x46, 0x37, 0x47, 0x05, 0xba, 0xf6, 0x5f, 0xa4, 0x13, 0x84, 0xba, 0x5c, 0x8e, + 0x0c, 0x88, 0xa3, 0xeb, 0x07, 0xe0, 0xbe, 0x34, 0xda, 0xdd, 0xfa, 0xbb, 0x7b, + 0x65, 0x54, 0x3b, 0x5f, 0x39, 0xcb, 0x20, 0x23, 0xd4, 0x67, 0x89, 0xeb, 0x7d, + 0x98, 0x9a, 0xf7, 0x79, 0xe5, 0xb8, 0xd2, 0x83, 0x85, 0xa8, 0x5b, 0x0d, 0xa2, + 0xab, 0xe0, 0x7f, 0x0c, 0x2b, 0xb4, 0x25, 0x5f, 0xce, 0xa0, 0x31, 0x88, 0x52, + 0x7a, 0x30, 0x7d, 0x40, 0x91, 0x59, 0xe9, 0x01, 0x66, 0xfa, 0xc6, 0xa0, 0x70, + 0xba, 0x05, 0xb3, 0xe4, 0xdb, 0xfd, 0x3a, 0x2b, 0xfc, 0xc9, 0xee, 0x6e, 0xd0, + 0x16, 0xc0, 0xf6, 0x65, 0xbe, 0x81, 0x33, 0xb7, 0xdc, 0x1d, 0x86, 0x04, 0x4d, + 0xb0, 0xf9, 0x03, 0x40, 0xfb, 0x0e, 0x9f, 0x8b, 0xc2, 0xe4, 0xdb, 0x53, 0x82, + 0xa8, 0xb4, 0xf8, 0x15, 0xb4, 0xe8, 0x43, 0x4a, 0xd0, 0xdf, 0xbc, 0x51, 0xa5, + 0xe9, 0xb1, 0x45, 0xe1, 0x59, 0x6c, 0xbf, 0x46, 0x70, 0x03, 0xe0, 0x5d, 0xfd, + 0xaf, 0xbb, 0x0c, 0xf3, 0xdd, 0xee, 0x28, 0xd7, 0x6a, 0x82, 0x42, 0x8e, 0x8a, + 0xba, 0x43, 0x64, 0xe8, 0x4b, 0xac, 0x37, 0x92, 0x98, 0xdf, 0x29, 0x32, 0xe6, + 0x9b, 0xb5, 0xd0, 0x0b, 0x51, 0x6e, 0xfc, 0x33, 0xae, 0x6c, 0xc3, 0x94, 0x7c, + 0xeb, 0x09, 0xed, 0x37, 0x16, 0x67, 0x21, 0x2a, 0x83, 0x1b, 0x54, 0x85, 0xea, + 0xfc, 0xe8, 0x48, 0x81, 0x88, 0xea, 0x4e, 0x27, 0xd0, 0xcd, 0xf7, 0xdd, 0xd3, + 0x48, 0xab, 0xff, 0x77, 0x7f, 0x4a, 0x13, 0xbb, 0xc7, 0x16, 0xb6, 0xa5, 0x94, + 0x4e, 0xe7, 0x27, 0x96, 0x56, 0x90, 0xe2, 0x09, 0xb4, 0x9e, 0xb9, 0x62, 0xc0, + 0x39, 0x97, 0x5f, 0x03, 0x9e, 0xd5, 0xc6, 0xe4, 0xc4, 0x00, 0xd8, 0x87, 0x75, + 0x94, 0x33, 0xd3, 0xad, 0x71, 0x6d, 0xa0, 0xcb, 0x44, 0x61, 0x13, 0xc7, 0x72, + 0x7a, 0x64, 0xb5, 0x8c, 0x3f, 0x8a, 0x0f, 0x81, 0x18, 0x9f, 0x02, 0x00, 0x52, + 0x33, 0xa8, 0x13, 0x66, 0xae, 0xe7, 0x3c, 0xec, 0x85, 0x22, 0x8e, 0xbc, 0xfd, + 0x5e, 0xe3, 0xc3, 0xfb, 0x44, 0xdb, 0x76, 0xba, 0x24, 0x3f, 0x28, 0x42, 0xb7, + 0xb5, 0xfc, 0x74, 0x6a, 0x03, 0x1b, 0x0b, 0xc4, 0xbd, 0x4f, 0xc9, 0xfd, 0x83, + 0x35, 0x65, 0xea, 0x85, 0x2b, 0x92, 0xb2, 0x24, 0xf6, 0x99, 0x03, 0x18, 0xad, + 0x8c, 0x7d, 0x94, 0x37, 0xe2, 0x0e, 0x2a, 0x1f, 0x20, 0xe8, 0x18, 0x03, 0x05, + 0x7c, 0x5a, 0xba, 0xaa, 0x2e, 0x5c, 0x15, 0xb9, 0x49, 0x45, 0xcd, 0x42, 0x4c, + 0x28, 0xa5, 0xfa, 0x38, 0x5d, 0xad, 0xfe, 0x49, 0x07, 0xb2, 0x74, 0xd8, 0x42, + 0x70, 0x7d, 0xb3, 0x69, 0x7a, 0x02, 0xe6, 0xc8, 0xf5, 0x42, 0xe5, 0xec, 0xc0, + 0x7f, 0xe4, 0x73, 0x50, 0xd1, 0x01, 0x46, 0x70, 0x21, 0x2e, 0xfe, 0x81, 0xfb, + 0x7c, 0x73, 0xe8, 0x45, 0x0d, 0xf8, 0x14, 0xef, 0x62, 0x32, 0xf7, 0x49, 0x0f, + 0x63, 0xcc, 0xf0, 0x74, 0x80, 0xf8, 0x84, 0xa6, 0x6e, 0xaf, 0xfc, 0x28, 0xfe, + 0xa4, 0x48, 0xd7, 0xb4, 0x01, 0xcd, 0xae, 0x10, 0xe7, 0xc0, 0xc7, 0xf9, 0xa7, + 0xb1, 0x53, 0x31, 0x96, 0x9f, 0xc8, 0xcb, 0x36, 0x39, 0x67, 0x73, 0xde, 0x19, + 0x19, 0x31, 0xc7, 0x50, 0xf6, 0xce, 0x5c, 0xaa, 0xf2, 0x97, 0x68, 0xeb, 0xb2, + 0x7d, 0xac, 0xc7, 0x38, 0x05, 0x6a, 0x81, 0x25, 0xb4, 0x77, 0x2b, 0xf8, 0x7a, + 0xe1, 0x0a, 0x8a, 0x30, 0x9b, 0x9b, 0xd6, 0x55, 0x04, 0x3c, 0xfc, 0x31, 0x59, + 0x49, 0x43, 0x68, 0xc5, 0xab, 0x8c, 0xad, 0xb7, 0xf6, 0x71, 0xe9, 0x62, 0x6b, + 0xd2, 0x63, 0xe3, 0x11, 0x81, 0xa6, 0x04, 0xb5, 0x06, 0xa0, 0x3b, 0x43, 0x9a, + 0x7f, 0xfe, 0x43, 0x55, 0x89, 0x24, 0x77, 0xe2, 0xbd, 0xf3, 0x38, 0xc6, 0x2c, + 0x39, 0x22, 0xf7, 0xd3, 0xc9, 0xa5, 0x6c, 0x71, 0x03, 0xd9, 0x11, 0x94, 0x8a, + 0x84, 0xb5, 0xae, 0x2d, 0xbb, 0x16, 0xa3, 0x76, 0x1a, 0xdd, 0x05, 0x3a, 0x0f, + 0x96, 0x7e, 0x6b, 0x5b, 0xc9, 0x42, 0x11, 0xb6, 0x54, 0x71, 0x53, 0x26, 0x7c, + 0x6e, 0xe1, 0xca, 0xd0, 0xd9, 0x74, 0xa7, 0x10, 0x88, 0x58, 0x37, 0x35, 0xe4, + 0xf6, 0x3d, 0x33, 0x15, 0x6d, 0xad, 0xd5, 0x4c, 0x2f, 0xaf, 0x89, 0x11, 0x4a, + 0x12, 0x7b, 0x97, 0xb9, 0x4c, 0xc2, 0xa2, 0x2e, 0xf3, 0x03, 0xf4, 0x59, 0xd0, + 0x4f, 0xc0, 0xb5, 0x3a, 0xce, 0x59, 0x18, 0xd4, 0x7f, 0xf3, 0x3a, 0x55, 0x8b, + 0xd7, 0x1a, 0x75, 0xf3, 0x55, 0xfb, 0xd0, 0x6b, 0xbc, 0xcf, 0x4e, 0x02, 0xc3, + 0xc0, 0xa4, 0xb6, 0x3d, 0x0c, 0xc9, 0x49, 0x80, 0x1d, 0x63, 0xa6, 0x4c, 0xb2, + 0xd3, 0x23, 0x73, 0xb2, 0xc7, 0xb2, 0x74, 0xab, 0x2d, 0xb4, 0x68, 0x21, 0x42, + 0xc8, 0xb2, 0x1d, 0x84, 0xc4, 0x81, 0xf5, 0xef, 0x21, 0xe4, 0xb5, 0xe3, 0x60, + 0x34, 0x51, 0xbf, 0x94, 0x77, 0x4d, 0x0e, 0xf4, 0x7f, 0x63, 0xfa, 0x6a, 0xbb, + 0x78, 0xd2, 0x1c, 0x19, 0x3c, 0xbe, 0x65, 0xb6, 0x95, 0xfe, 0x67, 0x42, 0x3c, + 0x1e, 0x2d, 0x31, 0x2e, 0x27, 0x76, 0xfa, 0x24, 0xec, 0xe8, 0x46, 0x83, 0xe7, + 0x48, 0x76, 0xc5, 0x5e, 0xa0, 0x36, 0x9e, 0x4e, 0xa0, 0xe8, 0x64, 0x94, 0xe0, + 0x0d, 0xde, 0x23, 0x6a, 0x16, 0x89, 0x73, 0x1f, 0x0a, 0x5d, 0x82, 0x03, 0xaf, + 0xde, 0x5c, 0x42, 0x36, 0x40, 0xb8, 0x1e, 0x4f, 0x63, 0x1c, 0x98, 0x1c, 0x11, + 0xa2, 0xe1, 0xd1, 0x84, 0xc6, 0x7c, 0x52, 0x8d, 0xf9, 0x2d, 0x53, 0xae, 0xc4, + 0x4a, 0x40, 0xa4, 0xea, 0x2a, 0x13, 0x1b, 0x47, 0x33, 0xcf, 0xe4, 0x5c, 0x6b, + 0x00, 0x12, 0xc3, 0xe9, 0xe2, 0x09, 0x75, 0xba, 0xae, 0xcb, 0x02, 0x32, 0xdf, + 0x88, 0x0b, 0xd7, 0xd1, 0xde, 0x13, 0xe1, 0x34, 0x94, 0x62, 0xec, 0x8d, 0x5d, + 0xf3, 0xe7, 0x80, 0xff, 0xa7, 0x2e, 0xba, 0x8a, 0x8d, 0xf7, 0xfc, 0xf3, 0x98, + 0xec, 0x23, 0x05, 0x13, 0xca, 0x9d, 0x61, 0x23, 0xf8, 0xb9, 0xd8, 0x17, 0x85, + 0x60, 0xda, 0xf9, 0x75, 0x11, 0x19, 0x55, 0xa2, 0xbc, 0xa3, 0x42, 0x3e, 0xee, + 0xfc, 0x52, 0x7b, 0xe3, 0xa8, 0x54, 0x3e, 0xb9, 0x0a, 0x5e, 0xc0, 0x2f, 0x35, + 0xa7, 0xc6, 0x4b, 0x7d, 0xd5, 0x9a, 0x72, 0xda, 0x00, 0x74, 0x63, 0x4e, 0x01, + 0xd2, 0xab, 0xf3, 0x63, 0x7a, 0xdd, 0x77, 0xc7, 0x35, 0x0f, 0x12, 0xb0, 0x11, + 0xb2, 0x94, 0x16, 0x8e, 0xc7, 0x55, 0x76, 0xe4, 0x7d, 0x16, 0x9e, 0x39, 0x38, + 0xbf, 0x6a, 0xe2, 0xaa, 0x8f, 0xf7, 0xcf, 0xba, 0x7c, 0xac, 0xb1, 0xf9, 0x2b, + 0x6e, 0x4c, 0x24, 0x97, 0xbf, 0xfa, 0x9f, 0x17, 0xca, 0xd2, 0x42, 0xfa, 0x9c, + 0x31, 0x79, 0xc1, 0xa3, 0xaa, 0x81, 0xf7, 0x36, 0x16, 0x49, 0x57, 0x2c, 0x71, + 0x5c, 0x25, 0xa1, 0xf6, 0xcd, 0x5a, 0xce, 0x82, 0xc0, 0x0a, 0xb2, 0x34, 0x2b, + 0x9c, 0x3c, 0xb4, 0xff, 0xfd, 0xda, 0x16, 0x0c, 0xa5, 0xab, 0x9e, 0x9b, 0xaf, + 0x21, 0x39, 0xef, 0x9a, 0xfb, 0xe1, 0xb1, 0xf3, 0x09, 0x46, 0x2a, 0xfc, 0xe4, + 0x62, 0xa7, 0x9b, 0xb9, 0x69, 0x8e, 0x22, 0xc9, 0x57, 0xc5, 0x90, 0xa7, 0x53, + 0xa7, 0x6b, 0x87, 0xe0, 0x09, 0x12, 0x1e, 0x06, 0xf6, 0xa1, 0xbf, 0x62, 0xa0, + 0x8b, 0xf4, 0x35, 0xd9, 0x2e, 0x2f, 0xff, 0xe8, 0x6e, 0x2a, 0x9c, 0xbb, 0xa9, + 0x13, 0x3a, 0x68, 0xe4, 0xae, 0xbf, 0x33, 0xc3, 0x84, 0x36, 0xf2, 0x54, 0x5f, + 0xc2, 0xd5, 0x28, 0x32, 0xd1, 0x65, 0xaf, 0x41, 0x5b, 0x24, 0x4a, 0xdc, 0x5f, + 0x57, 0x37, 0x7d, 0xee, 0xdf, 0x46, 0x0a, 0xa3, 0xbe, 0xb4, 0x34, 0x19, 0xc6, + 0xb0, 0x82, 0xe8, 0x35, 0xce, 0x84, 0xca, 0x13, 0xb6, 0x90, 0x8a, 0x88, 0x13, + 0xc0, 0x21, 0xde, 0x9f, 0xa9, 0xa4, 0x4e, 0x4c, 0x18, 0xdc, 0xb3, 0xd2, 0x1f, + 0xaa, 0xbd, 0xb4, 0x19, 0x31, 0xb2, 0xfd, 0x49, 0x76, 0x44, 0xdc, 0x3a, 0x15, + 0x07, 0xfa, 0x5a, 0xc7, 0xc7, 0x6b, 0xee, 0xbb, 0xdb, 0xd1, 0xd4, 0x92, 0x99, + 0xa5, 0x5b, 0xd4, 0x99, 0x27, 0xe9, 0xd7, 0xf4, 0x88, 0x4e, 0x6e, 0xd3, 0xfd, + 0x5e, 0x4b, 0x7c, 0xb8, 0x35, 0xb8, 0x33, 0x08, 0x96, 0x4e, 0x3c, 0x46, 0x87, + 0x3f, 0xd6, 0x13, 0x31, 0x7b, 0x91, 0xd2, 0x92, 0x36, 0xea, 0x90, 0xe3, 0x65, + 0xd1, 0x62, 0xcc, 0x05, 0x1c, 0x84, 0x6d, 0x24, 0x21, 0x76, 0xda, 0xf6, 0xd2, + 0x86, 0x18, 0xae, 0x31, 0xfb, 0xaa, 0xe9, 0x99, 0xa9, 0x3f, 0x17, 0x5c, 0x69, + 0x38, 0xe6, 0x31, 0xa0, 0x81, 0xf2, 0xc1, 0xf3, 0xfd, 0x78, 0x25, 0x49, 0xd3, + 0xf3, 0x24, 0x57, 0x59, 0x60, 0x6d, 0x9f, 0x92, 0xd5, 0x54, 0x8a, 0xcf, 0xea, + 0xdb, 0xaf, 0x9c, 0xaa, 0x6b, 0x93, 0xdc, 0x08, 0x82, 0x8d, 0x74, 0xf6, 0xd5, + 0xfd, 0xd8, 0x33, 0x31, 0xf0, 0x96, 0x91, 0x45, 0x95, 0x52, 0x97, 0xe6, 0x9f, + 0x00, 0xfd, 0x29, 0x87, 0xf2, 0xda, 0x2b, 0x94, 0xb9, 0x95, 0xfe, 0xcb, 0xe6, + 0x22, 0xa7, 0x35, 0xef, 0x7f, 0x12, 0x07, 0xf6, 0x71, 0x62, 0x94, 0x89, 0x20, + 0x2b, 0xea, 0x0b, 0x47, 0x5e, 0x51, 0x68, 0x1a, 0xa1, 0x67, 0x78, 0xb3, 0x9b, + 0xd9, 0x23, 0xc9, 0x8d, 0xc6, 0xff, 0x83, 0x73, 0xc7, 0x9b, 0xb1, 0x70, 0x30, + 0x41, 0x7b, 0xc2, 0x00, 0xc8, 0xf0, 0xb8, 0x55, 0xac, 0xfe, 0xc1, 0x79, 0xf7, + 0x67, 0x4c, 0xec, 0x27, 0x21, 0xa1, 0x0f, 0xca, 0x69, 0x3d, 0x83, 0xcf, 0xe5, + 0xb8, 0xcd, 0xcc, 0x18, 0xf8, 0x1a, 0xd6, 0x17, 0xfa, 0x26, 0xf0, 0xdf, 0xb8, + 0x36, 0x55, 0xb8, 0xa2, 0x9a, 0x7f, 0x83, 0x42, 0x32, 0x42, 0x5e, 0x8c, 0x47, + 0x45, 0x88, 0xf1, 0x8d, 0xd3, 0x26, 0xaa, 0x39, 0x6c, 0x3e, 0x47, 0x75, 0xe0, + 0x02, 0x05, 0xfc, 0x9e, 0x45, 0xf7, 0xb7, 0xd2, 0xe6, 0xd5, 0x5d, 0xcb, 0x90, + 0xe2, 0x3f, 0xf6, 0xb5, 0x08, 0x45, 0x9a, 0xa6, 0x99, 0xbf, 0xcb, 0xd5, 0x6f, + 0x10, 0x99, 0x77, 0x64, 0xd0, 0x87, 0x40, 0x89, 0x86, 0xe7, 0x3d, 0x6e, 0x28, + 0x4f, 0xea, 0x9a, 0x23, 0xc3, 0x93, 0x11, 0x78, 0x2f, 0x86, 0xca, 0xbf, 0xf9, + 0x45, 0x5e, 0x4c, 0xf6, 0x99, 0xe5, 0xf5, 0xd4, 0xbc, 0x0b, 0x39, 0x05, 0xa4, + 0xe3, 0xbd, 0x01, 0xc5, 0x4d, 0xf8, 0x64, 0x34, 0x43, 0xbe, 0x0f, 0x88, 0x90, + 0x32, 0xea, 0x32, 0x5b, 0xf0, 0x71, 0x07, 0xfd, 0x41, 0xd6, 0x73, 0xee, 0xba, + 0xe6, 0xfa, 0x63, 0x7b, 0x70, 0xcc, 0x0e, 0xd3, 0xf0, 0x09, 0x58, 0xdf, 0xb8, + 0xdc, 0xf0, 0x0e, 0x85, 0xa1, 0xd0, 0xa6, 0xa8, 0x90, 0x81, 0x40, 0xc2, 0xf4, + 0x34, 0xc2, 0xe2, 0x60, 0xef, 0xb0, 0xbc, 0xa2, 0x00, 0x35, 0x04, 0xc9, 0x99, + 0x93, 0xa9, 0xe1, 0xc0, 0xff, 0x9c, 0xef, 0xe6, 0xa6, 0x65, 0xd7, 0x91, 0x42, + 0x86, 0x90, 0xe4, 0x7e, 0xf8, 0xc1, 0x31, 0xa8, 0xe9, 0xbf, 0xb4, 0xc3, 0x08, + 0x02, 0x35, 0x03, 0x2d, 0x73, 0x1b, 0x0d, 0x38, 0x41, 0x22, 0x5f, 0x1c, 0x11, + 0xe2, 0xc2, 0x8e, 0xe8, 0x4d, 0x35, 0xf9, 0x22, 0x61, 0x00, 0x56, 0x59, 0x72, + 0xeb, 0x26, 0x9d, 0x27, 0x8e, 0xf6, 0x49, 0x79, 0xbf, 0x65, 0x15, 0xed, 0x4a, + 0x68, 0x40, 0xb0, 0x88, 0x3a, 0x9e, 0x6e, 0xf6, 0x4a, 0x0e, 0xfc, 0xae, 0x1c, + 0xf2, 0x1d, 0xfe, 0x74, 0x85, 0x4e, 0x84, 0xc2, 0x74, 0x9f, 0xac, 0x03, 0x82, + 0x52, 0x75, 0xc9, 0xb6, 0x30, 0x21, 0x84, 0xc7, 0x2d, 0xf4, 0xc4, 0xbb, 0x28, + 0x62, 0xe4, 0xe8, 0xa7, 0xd9, 0xa4, 0xa2, 0x82, 0x86, 0x6f, 0x9a, 0x7b, 0x2c, + 0xfc, 0x9a, 0x56, 0x31, 0x3d, 0xa0, 0xc4, 0x7a, 0x34, 0xb7, 0xb9, 0xcd, 0xa3, + 0xac, 0xe8, 0x18, 0x5f, 0x07, 0xdf, 0x36, 0xe4, 0x48, 0xa7, 0x6a, 0xa4, 0x77, + 0xf2, 0x24, 0xd8, 0x7a, 0x07, 0x4f, 0x43, 0xaf, 0x5d, 0x5f, 0x79, 0xb3, 0xab, + 0x11, 0x28, 0xf0, 0x81, 0x91, 0x44, 0x7f, 0xa6, 0x46, 0xbf, 0xdd, 0xe5, 0xb5, + 0x1e, 0x23, 0x3c, 0xa6, 0x15, 0x5d, 0x10, 0x15, 0x85, 0xbc, 0x2c, 0x40, 0x15, + 0x8a, 0xc2, 0x10, 0x6e, 0x66, 0xa2, 0x6e, 0x46, 0x42, 0x33, 0x70, 0x63, 0x68, + 0x76, 0xb4, 0x34, 0xa7, 0x4f, 0x8c, 0xe8, 0x06, 0x00, 0x50, 0xb0, 0x82, 0xa7, + 0x9b, 0x61, 0xbb, 0x5d, 0x34, 0x4e, 0xb5, 0xa1, 0x15, 0x83, 0x26, 0xce, 0xd9, + 0xa9, 0xd9, 0xf5, 0x4f, 0xb2, 0xfe, 0x8f, 0x9f, 0x05, 0xcd, 0x11, 0x1e, 0xe4, + 0x6c, 0x47, 0x10, 0xf6, 0xf6, 0x3a, 0x62, 0x69, 0x45, 0x57, + ], + script_code: Script(vec![0x53, 0x52, 0x00]), + transparent_input: Some(1), + hash_type: 1, + amount: 1564816348934332, + consensus_branch_id: consensus::BranchId::Overwinter, + sighash: [ + 0x21, 0x46, 0x62, 0xc6, 0x74, 0x50, 0x60, 0x3d, 0x8a, 0xa7, 0x3b, 0xea, 0xbb, + 0xf7, 0x51, 0x8d, 0x03, 0x6c, 0xe9, 0x1d, 0xc8, 0x7b, 0x01, 0x81, 0xe8, 0xa0, + 0xf3, 0xfa, 0x82, 0x2c, 0x7d, 0x8a, + ], + }, + Test0143Vector { + tx: vec![ + 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x01, 0x59, 0x07, 0x92, 0x9a, + 0x2f, 0x3f, 0xdb, 0x0d, 0x8f, 0x79, 0x14, 0xc4, 0x2d, 0xde, 0x2d, 0x20, 0x00, + 0xf5, 0xae, 0x02, 0xd4, 0x18, 0x21, 0xc8, 0xe1, 0xee, 0x01, 0x38, 0xeb, 0xcb, + 0x72, 0x8d, 0x7c, 0x6c, 0x3c, 0x80, 0x02, 0x65, 0x53, 0x75, 0x94, 0xc6, 0x70, + 0x00, 0x6f, 0x39, 0x08, 0x22, 0x2e, 0x89, 0xd1, 0x06, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf8, 0x27, 0x1a, 0xbe, 0x66, 0x0e, 0x39, 0xe0, 0x51, 0xaa, 0xa6, 0xfc, 0xa1, + 0x86, 0x22, 0x76, 0xe2, 0xba, 0xa0, 0xfe, 0x0b, 0x16, 0x2a, 0xeb, 0xcf, 0xe3, + 0xd9, 0x34, 0x9c, 0x8d, 0x15, 0x4b, 0xb7, 0xee, 0x28, 0x21, 0x2c, 0x1b, 0xaa, + 0x70, 0x5d, 0x82, 0x07, 0x0d, 0x70, 0x32, 0xf2, 0x69, 0x5d, 0x17, 0x96, 0x80, + 0x9f, 0xab, 0x41, 0x24, 0x69, 0x26, 0xaf, 0x99, 0x2b, 0x6e, 0xee, 0x95, 0xa9, + 0xa0, 0x6b, 0xc4, 0x56, 0x2c, 0x5f, 0x2f, 0x1b, 0x19, 0x54, 0x95, 0x00, 0x37, + 0x2e, 0x7a, 0xd5, 0x79, 0xa6, 0xd6, 0xd7, 0x8b, 0x33, 0x15, 0x31, 0x30, 0xfb, + 0x44, 0x8f, 0xb7, 0x9e, 0x8a, 0x66, 0x9d, 0xb8, 0xa0, 0xf3, 0x5c, 0xdf, 0x9a, + 0xe5, 0xd3, 0x2d, 0x73, 0x2f, 0xc7, 0x94, 0x18, 0xe2, 0x3b, 0x45, 0x1d, 0xdc, + 0x95, 0xa2, 0x2a, 0xba, 0xbb, 0x05, 0x6e, 0xc6, 0xb5, 0xe8, 0xba, 0x4f, 0x52, + 0x4d, 0xfa, 0xfe, 0x87, 0x52, 0x62, 0xdd, 0x7b, 0xe4, 0x1c, 0xbb, 0xc6, 0x24, + 0x20, 0xd4, 0xad, 0x6d, 0xf5, 0xc9, 0xb7, 0x13, 0x60, 0x4f, 0x65, 0x60, 0x88, + 0xa4, 0x48, 0x5e, 0x93, 0xbe, 0x19, 0x07, 0xd2, 0x7a, 0xc6, 0xec, 0x3c, 0x57, + 0x25, 0x9b, 0xd6, 0x98, 0x1d, 0x42, 0xc1, 0xb7, 0x8a, 0x29, 0xad, 0x96, 0x85, + 0xe6, 0x3c, 0x49, 0x4d, 0x41, 0x29, 0x62, 0x3e, 0xa1, 0xa7, 0xff, 0xec, 0x85, + 0xfa, 0x29, 0x41, 0x10, 0x73, 0xed, 0xb2, 0x97, 0x8e, 0xf4, 0xe4, 0x69, 0xdd, + 0xd5, 0xcd, 0xa9, 0x86, 0x18, 0x99, 0x95, 0xf8, 0x8d, 0x6a, 0xb3, 0x66, 0xdb, + 0x01, 0x90, 0x01, 0xf5, 0xb2, 0x52, 0x88, 0xcf, 0x86, 0x0f, 0xd9, 0x98, 0xee, + 0x57, 0x3c, 0x8c, 0xc4, 0x8a, 0xa9, 0xef, 0xcf, 0x9b, 0x61, 0x7e, 0x04, 0x3c, + 0x32, 0x9c, 0xd1, 0xaa, 0x1a, 0x0e, 0xd3, 0xa4, 0x02, 0xfb, 0x96, 0xe3, 0x36, + 0xc7, 0x19, 0xe6, 0x25, 0x3c, 0xb6, 0x91, 0xaa, 0x0d, 0xb5, 0x27, 0x36, 0x62, + 0x6e, 0xd1, 0x97, 0x88, 0x75, 0x88, 0x8e, 0xc7, 0x6c, 0x84, 0x6b, 0xc2, 0x27, + 0x27, 0x2a, 0x02, 0x53, 0x17, 0xdf, 0xf0, 0xb1, 0x14, 0x8d, 0x92, 0xd6, 0xf5, + 0xfb, 0x7d, 0x95, 0x33, 0x67, 0x70, 0xa7, 0xd1, 0x6f, 0xac, 0x1a, 0xdd, 0x86, + 0x07, 0x76, 0xcb, 0x48, 0x02, 0x21, 0xf8, 0xfb, 0x33, 0x03, 0xe4, 0xe9, 0xb0, + 0x79, 0x02, 0xd2, 0xff, 0x86, 0xfd, 0xac, 0x72, 0x09, 0x62, 0x34, 0xae, 0xd4, + 0x8d, 0xe8, 0x92, 0xff, 0x73, 0x55, 0x07, 0x3b, 0xbf, 0x06, 0x15, 0xf6, 0x7b, + 0x11, 0x00, 0xcc, 0x0a, 0xa3, 0xba, 0x3d, 0x6c, 0x1a, 0x1a, 0x90, 0x87, 0xb1, + 0x19, 0xba, 0xee, 0xbf, 0xa6, 0x2b, 0xc9, 0xf0, 0xec, 0x47, 0x9d, 0x99, 0xc1, + 0xa3, 0xb1, 0x58, 0xb5, 0x14, 0xd1, 0x62, 0x9d, 0xb3, 0x99, 0x3f, 0x11, 0x67, + 0x2a, 0x26, 0x70, 0x8e, 0x5a, 0xd8, 0x16, 0xb5, 0x47, 0xab, 0x7e, 0x82, 0x7d, + 0x07, 0x1b, 0xa7, 0x84, 0x2b, 0x3e, 0x90, 0x30, 0x53, 0x83, 0x89, 0x6e, 0xc4, + 0x90, 0x5f, 0x70, 0x03, 0x8b, 0x69, 0x4e, 0x6a, 0x5a, 0x3e, 0x43, 0x12, 0xcd, + 0x82, 0x08, 0x13, 0x2b, 0x84, 0x0f, 0x05, 0xc7, 0x14, 0x52, 0x3c, 0xa8, 0x19, + 0x72, 0x0a, 0xe2, 0x27, 0xfd, 0x1a, 0xcb, 0xa7, 0x14, 0xfa, 0x03, 0xc4, 0x5f, + 0xc5, 0x39, 0x88, 0x57, 0xb4, 0x0d, 0xc1, 0x48, 0x79, 0x85, 0x6f, 0x35, 0x4b, + 0xa4, 0xd2, 0x58, 0x1d, 0x0c, 0xda, 0x54, 0xb6, 0x38, 0xba, 0x9d, 0x76, 0xf9, + 0xb5, 0x2d, 0x17, 0xc8, 0x02, 0x8e, 0xe6, 0x3f, 0x58, 0x45, 0xb5, 0xdc, 0xef, + 0xa4, 0xc3, 0x47, 0x9b, 0xce, 0x9a, 0xca, 0xd1, 0x8b, 0x4a, 0xea, 0xe0, 0x3c, + 0x0e, 0xae, 0x22, 0x5d, 0x42, 0x84, 0x8b, 0xde, 0xaa, 0x53, 0x6d, 0x03, 0x8d, + 0xd3, 0xbc, 0x97, 0x9f, 0x06, 0x58, 0x66, 0x73, 0xbc, 0x6f, 0xf1, 0xc5, 0xd3, + 0xb3, 0x20, 0xf3, 0x49, 0xa5, 0xb3, 0xa8, 0xb3, 0x55, 0x59, 0x22, 0x96, 0xaa, + 0xf6, 0x1c, 0x5b, 0x72, 0x52, 0x03, 0x3e, 0xc0, 0xa9, 0x46, 0x6a, 0x1b, 0x85, + 0x76, 0x4f, 0xb0, 0x83, 0x1b, 0x4a, 0x1a, 0x36, 0x89, 0x0e, 0x22, 0x4c, 0x01, + 0xac, 0xfc, 0xe4, 0x8e, 0xe3, 0xed, 0x93, 0x87, 0x73, 0x98, 0xe0, 0x72, 0x6d, + 0x02, 0x93, 0x6d, 0x0d, 0x03, 0x2e, 0x18, 0xe3, 0x28, 0x8b, 0x26, 0x70, 0xe1, + 0x36, 0x2c, 0x32, 0xd6, 0xe4, 0x73, 0x3b, 0x9d, 0xd2, 0xd5, 0xf2, 0x6e, 0x1f, + 0xe3, 0x06, 0xf7, 0x3c, 0x00, 0x7f, 0xdd, 0xca, 0xe9, 0xd9, 0xc0, 0xaa, 0xf1, + 0x87, 0xd7, 0x42, 0x8b, 0x1e, 0x9d, 0x47, 0x9c, 0x18, 0x23, 0x7b, 0x98, 0x28, + 0xbc, 0xa8, 0xb9, 0x8c, 0x9d, 0x9b, 0xec, 0x7d, 0x82, 0x70, 0xb5, 0xd8, 0xee, + 0xc3, 0xcc, 0x4f, 0x43, 0xfa, 0x01, 0x88, 0x52, 0x1b, 0xc6, 0x1b, 0x21, 0xdd, + 0x04, 0xe3, 0x7a, 0x83, 0xec, 0xe6, 0x8c, 0xa7, 0xa2, 0xfa, 0x6c, 0x8f, 0x9e, + 0x34, 0xa6, 0x29, 0x03, 0x35, 0xaa, 0x1f, 0xbd, 0x83, 0xd5, 0x4a, 0xaf, 0x44, + 0x1e, 0x31, 0x9e, 0xa4, 0x7a, 0x86, 0x2a, 0xd0, 0x29, 0x3c, 0xed, 0xf5, 0xdd, + 0x9e, 0xda, 0xde, 0xee, 0x33, 0xcb, 0x52, 0x2c, 0xd0, 0x11, 0x8b, 0xbd, 0x81, + 0x1a, 0xce, 0x9a, 0x23, 0xbd, 0xa3, 0x9a, 0xba, 0x72, 0xf1, 0x56, 0x6f, 0xc1, + 0x68, 0x84, 0x97, 0xd2, 0xa7, 0x92, 0x8c, 0x36, 0x70, 0x15, 0x25, 0x67, 0x8b, + 0xc9, 0x72, 0x14, 0xb3, 0x1b, 0x37, 0xba, 0xb4, 0x6b, 0x88, 0xf2, 0x7f, 0x04, + 0x48, 0xde, 0xcb, 0x31, 0x62, 0x2d, 0x0f, 0x0f, 0x87, 0xa8, 0x55, 0xba, 0x54, + 0x00, 0x03, 0x32, 0x03, 0x1f, 0x73, 0xab, 0xff, 0xd4, 0x65, 0x91, 0xda, 0x0b, + 0x88, 0x72, 0x35, 0x04, 0xed, 0xb2, 0x33, 0x72, 0x30, 0xda, 0xd2, 0xac, 0xc0, + 0xd8, 0xbb, 0x68, 0xbc, 0x83, 0x7a, 0x2f, 0xf9, 0x30, 0xbf, 0xf0, 0x6f, 0xde, + 0x74, 0xeb, 0x90, 0xaa, 0xe4, 0xf6, 0x0d, 0xbb, 0x6e, 0xb8, 0x27, 0xea, 0x99, + 0x88, 0x4a, 0xcd, 0x62, 0x85, 0xa9, 0x88, 0x92, 0x80, 0x2c, 0xf5, 0x9d, 0x5d, + 0x60, 0xd0, 0x16, 0x63, 0x38, 0x7b, 0x3e, 0xd2, 0x72, 0x3b, 0xd6, 0x48, 0x9e, + 0x9c, 0x2c, 0x10, 0x6d, 0x4a, 0xa2, 0xde, 0x23, 0xce, 0xd1, 0x6c, 0x72, 0x04, + 0x29, 0xc7, 0x75, 0x3a, 0x77, 0x38, 0xec, 0x7d, 0x9d, 0xb8, 0x62, 0x42, 0x29, + 0xed, 0xd2, 0x17, 0xb8, 0x0d, 0x74, 0x87, 0x5a, 0x14, 0xca, 0xe4, 0x86, 0x3f, + 0x13, 0x9e, 0x9c, 0x0b, 0x13, 0x1b, 0x2a, 0x4c, 0x28, 0x07, 0x1a, 0x38, 0xec, + 0x61, 0xf6, 0x68, 0x01, 0xaa, 0x59, 0x56, 0xfc, 0xb2, 0xa4, 0x6b, 0x95, 0x87, + 0x66, 0x5b, 0x75, 0x71, 0xaa, 0x03, 0x48, 0x1f, 0xd8, 0xd9, 0xd5, 0x69, 0x8f, + 0x83, 0x6f, 0xc8, 0x63, 0x5e, 0x69, 0xe3, 0xbd, 0xe4, 0x2f, 0x4a, 0xc0, 0x71, + 0x32, 0x8b, 0x54, 0x09, 0xf6, 0xe4, 0x2d, 0x79, 0x0a, 0xed, 0xd7, 0x3b, 0xc1, + 0xa2, 0x35, 0x47, 0x23, 0xb3, 0xb8, 0x19, 0xd0, 0x63, 0x7a, 0x6f, 0xa4, 0x66, + 0x39, 0x46, 0xa3, 0x0a, 0xc5, 0xaf, 0xdd, 0x30, 0xce, 0x83, 0x0f, 0x67, 0x91, + 0xb4, 0x57, 0x52, 0x70, 0xa1, 0x72, 0x0f, 0x91, 0x86, 0x6e, 0x2b, 0x86, 0xf4, + 0x78, 0x88, 0x94, 0xc8, 0xda, 0x62, 0xd8, 0xb9, 0x1f, 0xaf, 0x52, 0x0e, 0x3b, + 0xed, 0xbc, 0x12, 0x06, 0xa5, 0xa5, 0xe6, 0xef, 0xd3, 0xdf, 0xde, 0x08, 0x43, + 0xc3, 0xb0, 0x67, 0x57, 0x64, 0x3f, 0xc0, 0x06, 0x00, 0x88, 0x38, 0xca, 0x47, + 0x30, 0x87, 0xf8, 0x97, 0x79, 0x18, 0xcc, 0x1b, 0x81, 0xc9, 0xe6, 0x8e, 0x3b, + 0x88, 0x8f, 0xe6, 0xf7, 0xc6, 0x30, 0xf1, 0xbc, 0x7a, 0xe1, 0x88, 0xf5, 0x12, + 0x84, 0x20, 0x41, 0xca, 0xda, 0x1e, 0x05, 0xf8, 0x66, 0xd2, 0x56, 0x2d, 0xbe, + 0x09, 0xc4, 0xb4, 0x30, 0x68, 0xf7, 0x54, 0xda, 0xd3, 0x4d, 0xf0, 0xfc, 0xfc, + 0x18, 0x1f, 0x31, 0x80, 0x1a, 0x79, 0x92, 0xd2, 0xf1, 0x6b, 0xe0, 0x21, 0x1b, + 0x4a, 0x22, 0xf6, 0x2a, 0xab, 0x64, 0x70, 0x1b, 0xf4, 0xa4, 0xe6, 0xd6, 0x66, + 0xfc, 0x30, 0x4a, 0x5c, 0x79, 0xc6, 0x09, 0xac, 0xc4, 0x3b, 0x00, 0xb4, 0x86, + 0x48, 0x93, 0xd3, 0x7d, 0x50, 0x07, 0xf0, 0xc3, 0x29, 0xa4, 0x75, 0x50, 0x52, + 0x57, 0x75, 0x70, 0xdd, 0x38, 0xfa, 0xc0, 0x43, 0xcd, 0x91, 0xc1, 0x2e, 0xe3, + 0x4e, 0x9c, 0xfa, 0xe3, 0x92, 0xa7, 0x8b, 0xda, 0xbd, 0x4e, 0xe3, 0x1d, 0xc0, + 0xde, 0xb0, 0x2f, 0xe7, 0xb1, 0xd8, 0xb0, 0x17, 0x8a, 0xc9, 0x51, 0x31, 0x05, + 0xfc, 0xc7, 0xe3, 0x0b, 0xa8, 0xe0, 0x16, 0xaa, 0x36, 0xa6, 0xb5, 0xdf, 0x5e, + 0x5a, 0x19, 0x09, 0xf6, 0x3a, 0xba, 0x09, 0x5d, 0x98, 0x77, 0xa8, 0xf2, 0xdc, + 0x53, 0xf4, 0x6f, 0x6c, 0x9b, 0x07, 0xad, 0xdf, 0x14, 0x6f, 0x4f, 0xfa, 0x50, + 0x1f, 0x9d, 0xd3, 0xcf, 0xf9, 0x24, 0xe3, 0x01, 0x0f, 0xaf, 0x50, 0x4e, 0x2b, + 0x8a, 0xca, 0x73, 0x57, 0xac, 0xbf, 0xfe, 0xc7, 0x3a, 0xc3, 0x4c, 0x1a, 0x73, + 0x16, 0x0f, 0x2c, 0xea, 0x1e, 0x05, 0x10, 0xf8, 0x4d, 0x2f, 0xe2, 0xf7, 0x3b, + 0x6e, 0x92, 0x19, 0x07, 0xa1, 0xb7, 0xb3, 0x75, 0x12, 0x13, 0x24, 0x1b, 0x2c, + 0xfa, 0xa5, 0x5a, 0x5e, 0xa4, 0xdd, 0x51, 0x7e, 0x7b, 0x49, 0xd2, 0xde, 0x8c, + 0x09, 0x08, 0x43, 0x73, 0x0d, 0x24, 0x08, 0xa2, 0xa3, 0x04, 0xaa, 0x1e, 0x2e, + 0x13, 0x70, 0xa6, 0xbf, 0x6c, 0x2b, 0xc7, 0x3f, 0xf0, 0x0d, 0x89, 0x3b, 0xc1, + 0x28, 0x5e, 0xfc, 0xa8, 0x25, 0x99, 0xd1, 0x81, 0xf1, 0x23, 0x51, 0xf9, 0x39, + 0xa9, 0x4e, 0xa8, 0xb9, 0x75, 0xc0, 0x65, 0xa9, 0x1f, 0xf2, 0x57, 0xca, 0xc7, + 0xa9, 0x23, 0x85, 0xfc, 0x8f, 0xa9, 0x21, 0xb1, 0x06, 0xba, 0x86, 0x60, 0xc6, + 0x0a, 0xc8, 0xba, 0x5e, 0xce, 0x45, 0x60, 0x6f, 0x04, 0xf3, 0x6a, 0x3a, 0x90, + 0xbb, 0x38, 0x38, 0xc4, 0x2a, 0xbf, 0x62, 0xdd, 0x2d, 0x84, 0xba, 0xbe, 0xf3, + 0xe1, 0x88, 0xe9, 0x17, 0x1a, 0xff, 0x9b, 0xc1, 0x16, 0x66, 0x90, 0x09, 0xd8, + 0x87, 0x13, 0x0a, 0xc9, 0xf7, 0x39, 0x6a, 0x62, 0x7a, 0x84, 0x74, 0xc1, 0x81, + 0x1b, 0x69, 0x6f, 0x99, 0x55, 0x2b, 0x14, 0xc4, 0x84, 0xdf, 0xe4, 0x2c, 0x24, + 0xd5, 0x7c, 0x3a, 0x9c, 0x3f, 0xea, 0x13, 0x76, 0xcd, 0xcb, 0x63, 0x42, 0x1c, + 0x31, 0x4a, 0x62, 0x2a, 0x9a, 0xef, 0x0b, 0xc0, 0x57, 0xcb, 0x11, 0xbc, 0x5e, + 0x30, 0x66, 0xe3, 0x3a, 0x3b, 0x9b, 0x31, 0xdf, 0x25, 0x75, 0xcd, 0x51, 0x85, + 0xa4, 0xf3, 0xfc, 0x4e, 0x4c, 0x3d, 0x40, 0x2e, 0xd4, 0x20, 0x46, 0xf8, 0x1f, + 0x97, 0x48, 0x16, 0xd2, 0x79, 0xb1, 0x51, 0x3a, 0xb8, 0x1d, 0x3f, 0x0a, 0x3c, + 0x7f, 0x7f, 0xcf, 0x2f, 0xbb, 0x4e, 0x26, 0x32, 0x19, 0x93, 0xa5, 0x13, 0xad, + 0x3d, 0x7f, 0x4a, 0xfe, 0x6c, 0x1b, 0xbd, 0xc6, 0x57, 0x58, 0x50, 0x80, 0xbb, + 0x5a, 0x0f, 0x25, 0x97, 0x3d, 0x63, 0xeb, 0x20, 0xad, 0xa0, 0x16, 0x6b, 0xbd, + 0x8a, 0x39, 0xff, 0x93, 0x24, 0x6f, 0x27, 0x89, 0x73, 0x2a, 0xd0, 0x55, 0x87, + 0xf8, 0xdb, 0x7b, 0xc8, 0x7c, 0x24, 0x2c, 0xfd, 0x36, 0xce, 0x68, 0x5a, 0x4b, + 0x65, 0x69, 0x86, 0xc3, 0x9f, 0xd7, 0xfc, 0xb2, 0x3c, 0x91, 0x91, 0x3e, 0x46, + 0x11, 0x19, 0x1e, 0xdc, 0xc8, 0x8b, 0x78, 0xf1, 0x45, 0xea, 0x29, 0xd2, 0x71, + 0xb9, 0x40, 0xc6, 0x99, 0x41, 0xe4, 0xc3, 0xfd, 0x2d, 0x71, 0xf3, 0xb1, 0x90, + 0x69, 0x0e, 0xe1, 0x6f, 0x5d, 0x14, 0xac, 0x22, 0x24, 0xe6, 0xfc, 0x89, 0x59, + 0x76, 0x54, 0x52, 0x7d, 0xab, 0xe7, 0x2e, 0x75, 0xd2, 0xd2, 0xa1, 0x3a, 0x9f, + 0xba, 0xa6, 0x37, 0x8e, 0x8a, 0x26, 0x43, 0x21, 0x08, 0x7a, 0x19, 0x00, 0xef, + 0xe3, 0xca, 0xd1, 0x4a, 0x57, 0x96, 0x86, 0xaa, 0x36, 0x36, 0xbd, 0x37, 0x5b, + 0xd3, 0x13, 0x6b, 0xee, 0x0b, 0xda, 0xab, 0xcf, 0xac, 0x88, 0x1b, 0xc7, 0x01, + 0x81, 0x27, 0x21, 0xe6, 0xfb, 0x75, 0xaa, 0x07, 0x2d, 0x2d, 0x18, 0x7e, 0x62, + 0x25, 0x8d, 0x65, 0xa1, 0x92, 0x15, 0x7c, 0xdf, 0x2e, 0xc3, 0x21, 0x40, 0x7f, + 0x68, 0x2f, 0x5e, 0xec, 0x6a, 0x32, 0x97, 0xab, 0x20, 0xb7, 0x06, 0x1c, 0x62, + 0x24, 0x57, 0x16, 0xa4, 0x4f, 0x71, 0xfb, 0xfc, 0x34, 0xc7, 0x9b, 0x44, 0xe0, + 0x9e, 0x42, 0x12, 0xac, 0x26, 0x53, 0xf6, 0xc4, 0x03, 0x64, 0x3e, 0x1c, 0x5b, + 0x9a, 0xd1, 0x34, 0xd8, 0x9c, 0x68, 0x0b, 0x70, 0x72, 0x83, 0xaf, 0x54, 0x32, + 0x6f, 0xc4, 0xf8, 0x4d, 0x6a, 0x58, 0x29, 0xa0, 0xad, 0x48, 0x30, 0x80, 0x6c, + 0x05, 0x75, 0x84, 0x92, 0xcd, 0x6a, 0xc4, 0x6b, 0xa0, 0x1a, 0x2b, 0x37, 0x22, + 0xb5, 0xe4, 0xcd, 0xaf, 0xbb, 0x3f, 0x36, 0x78, 0x5f, 0x42, 0x4a, 0xf0, 0x44, + 0xda, 0xc5, 0xdb, 0x5f, 0x7d, 0xf8, 0x39, 0xeb, 0x63, 0xc0, 0xc1, 0x7d, 0x8b, + 0x0c, 0x79, 0xdb, 0x86, 0x30, 0x94, 0x20, 0x15, 0xbe, 0x13, 0xf7, 0x9a, 0xf6, + 0xf4, 0x3e, 0x5a, 0xb0, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x14, 0x79, 0x8f, 0x44, + 0x22, 0x58, 0xee, 0xdc, 0x43, 0x6f, 0xcc, 0x38, 0x6b, 0x36, 0xb5, 0x7e, 0x19, + 0x17, 0xd7, 0x20, 0x17, 0x73, 0x66, 0xf4, 0x24, 0xb0, 0xa5, 0x4b, 0x0b, 0x60, + 0xf4, 0xfb, 0x13, 0x58, 0xc2, 0x0a, 0xa4, 0x1d, 0xc5, 0x02, 0xe1, 0xdd, 0x8a, + 0x16, 0x33, 0xf3, 0xd8, 0xe3, 0x27, 0x6b, 0x59, 0xe7, 0xd2, 0xc4, 0xe6, 0x24, + 0xa6, 0xf5, 0x36, 0x95, 0xbc, 0xaf, 0x24, 0x7e, 0x36, 0x48, 0x3f, 0x13, 0xb2, + 0x04, 0x42, 0x22, 0x37, 0xfc, 0x6a, 0xb3, 0xeb, 0xa0, 0x2f, 0xc4, 0x14, 0x2b, + 0x42, 0x97, 0xeb, 0xb5, 0x68, 0x3d, 0xb8, 0xd2, 0x43, 0x19, 0x70, 0x6a, 0xd2, + 0x6a, 0xaf, 0xd8, 0x1c, 0x53, 0xb7, 0x40, 0xf3, 0x45, 0x43, 0xa6, 0xb3, 0xe9, + 0xf5, 0xbb, 0x7d, 0x5c, 0x49, 0xe8, 0xc3, 0x7f, 0x61, 0x49, 0x21, 0x25, 0x4f, + 0x32, 0x12, 0x39, 0x4c, 0x79, 0x7d, 0x1c, 0xee, 0x78, 0x99, 0xb7, 0xb4, 0xb6, + 0x5b, 0x59, 0xb7, 0x34, 0x2f, 0x92, 0x53, 0x1c, 0x1d, 0x59, 0xe1, 0x79, 0x70, + 0xb7, 0x31, 0x74, 0x14, 0x43, 0x8c, 0xd8, 0x0b, 0xd0, 0xf9, 0xa6, 0x7c, 0x9b, + 0x9e, 0x55, 0x2f, 0x01, 0x3c, 0x11, 0x5a, 0x95, 0x4f, 0x35, 0xe0, 0x61, 0x6c, + 0x68, 0xd4, 0x31, 0x63, 0xd3, 0x34, 0xda, 0xc3, 0x82, 0x70, 0x33, 0xe5, 0xad, + 0x84, 0x88, 0xbf, 0xd9, 0xc4, 0xbb, 0xbe, 0x8f, 0x59, 0x35, 0xc6, 0xc5, 0xea, + 0x04, 0xc3, 0xad, 0x49, 0xc7, 0x47, 0xa9, 0xe7, 0x23, 0x1b, 0xcd, 0x7d, 0x16, + 0x21, 0x5e, 0x6e, 0x80, 0x73, 0x7d, 0x6b, 0x54, 0xfe, 0xc8, 0xb8, 0x84, 0x02, + 0xf0, 0x47, 0x52, 0x45, 0xe1, 0x74, 0xa7, 0x45, 0xb8, 0x31, 0xf8, 0xfe, 0x03, + 0xa7, 0x6f, 0xb9, 0xce, 0xca, 0x4d, 0x22, 0xb7, 0x83, 0xc3, 0x28, 0xc6, 0x91, + 0x5c, 0x43, 0x40, 0x50, 0x64, 0xae, 0x56, 0xbc, 0x89, 0xe6, 0x4d, 0x15, 0x78, + 0xe4, 0xd3, 0xa3, 0x4b, 0xb9, 0x55, 0x91, 0xea, 0xf1, 0xd3, 0xda, 0x02, 0xa4, + 0x54, 0x9f, 0xa8, 0x0d, 0xb0, 0xff, 0x7c, 0xb0, 0x39, 0x93, 0x02, 0x8a, 0xe1, + 0x5a, 0x30, 0xe8, 0x79, 0x49, 0xaa, 0x08, 0x0e, 0x94, 0xab, 0xde, 0x68, 0x89, + 0x8c, 0x33, 0x92, 0xa2, 0x17, 0xd6, 0x49, 0x61, 0x6b, 0xbe, 0x73, 0x9b, 0x13, + 0xd1, 0x4d, 0xf0, 0x3f, 0x02, 0x76, 0x71, 0x48, 0x9b, 0xe0, 0xb4, 0xbe, 0xba, + 0xaf, 0xa7, 0xd1, 0xe6, 0x39, 0xd5, 0xb3, 0xe9, 0x94, 0xff, 0xb6, 0xb7, 0xa2, + 0x09, 0xf6, 0xad, 0xfe, 0x8d, 0x1e, 0x5c, 0xcf, 0x01, 0x0c, 0x19, 0x0a, 0x8a, + 0xeb, 0x18, 0xaa, 0x9d, 0x68, 0x7e, 0x24, 0xad, 0xc0, 0xb1, 0x13, 0x5c, 0x70, + 0xc9, 0x70, 0xe0, 0x90, 0x3a, 0xf6, 0xe1, 0x70, 0x81, 0xd5, 0x81, 0x8e, 0x88, + 0xb1, 0x4e, 0x4f, 0x60, 0x1b, 0x8c, 0x06, 0x3e, 0x3f, 0x43, 0x87, 0xff, 0xa2, + 0x32, 0x2a, 0x51, 0x81, 0x90, 0x9f, 0x09, 0x80, 0xd6, 0x89, 0xde, 0x7f, 0x8e, + 0x6a, 0x5c, 0x62, 0xa7, 0x77, 0xd1, 0x75, 0x00, 0x2a, 0x13, 0x7d, 0x02, 0x5b, + 0x88, 0x88, 0x92, 0x91, 0x98, 0x11, 0x7a, 0xa5, 0xd6, 0x19, 0x93, 0xe1, 0xdc, + 0xf7, 0x58, 0x76, 0xdc, 0xa6, 0x09, 0xf9, 0xd2, 0x84, 0x71, 0xf9, 0x97, 0xfa, + 0x11, 0xf9, 0x9d, 0x42, 0x3f, 0x02, 0xf1, 0x73, 0x4b, 0xe8, 0xa5, 0xff, 0x99, + 0x7d, 0x45, 0x1e, 0xb3, 0xcf, 0x4b, 0x3d, 0xfd, 0xd9, 0xd4, 0x54, 0x5c, 0x35, + 0xb2, 0xb5, 0xa7, 0xdc, 0x17, 0xa8, 0x36, 0xb1, 0x2b, 0x43, 0xbe, 0xfc, 0x03, + 0xe0, 0xa1, 0xbd, 0x36, 0x97, 0x72, 0x33, 0x80, 0x78, 0xb4, 0xff, 0x7d, 0x8e, + 0x2d, 0x97, 0x9a, 0x34, 0x41, 0xe1, 0xc8, 0xf5, 0xaf, 0xe4, 0x7b, 0x1e, 0x7d, + 0xa5, 0x6c, 0xf0, 0x06, 0x02, 0xd0, 0x03, 0x11, 0x0c, 0x05, 0xcf, 0x48, 0xfd, + 0xa3, 0xe6, 0xcc, 0xe3, 0x2a, 0x04, 0x40, 0x00, 0xf4, 0x5c, 0x6d, 0x1e, 0x69, + 0x6d, 0x24, 0x5c, 0xbd, 0x31, 0x2b, 0xdc, 0x3a, 0x3a, 0x21, 0xc9, 0x92, 0xd0, + 0x03, 0xc8, 0xcc, 0x8f, 0xa6, 0x30, 0x6d, 0x7e, 0x13, 0x0a, 0x2b, 0xa4, 0x20, + 0x18, 0xfe, 0x59, 0x69, 0x49, 0xfd, 0x82, 0x26, 0x7b, 0xcc, 0x59, 0xdd, 0x46, + 0x26, 0xef, 0xc3, 0xea, 0x74, 0x38, 0xd0, 0x5c, 0x91, 0xb0, 0xf8, 0xe0, 0x92, + 0x55, 0x0d, 0x2d, 0x39, 0xa0, 0x1e, 0xb4, 0x5e, 0xe8, 0xf7, 0xd0, 0x9b, 0x03, + 0x8d, 0x83, 0x83, 0xe1, 0x9b, 0xc3, 0x0e, 0x64, 0x03, 0x82, 0x8c, 0xdb, 0x65, + 0x2a, 0x55, 0x6b, 0x12, 0x04, 0x09, 0x31, 0x40, 0x2a, 0xa6, 0xac, 0x34, 0xfc, + 0x19, 0xfd, 0xc0, 0x6e, 0x2e, 0x77, 0x87, 0xf5, 0xb7, 0x7b, 0x04, 0x5f, 0xd0, + 0x98, 0xc0, 0x31, 0xbd, 0xbd, 0x46, 0x27, 0x76, 0x09, 0xd8, 0x42, 0xf4, 0x84, + 0x24, 0xed, 0xa3, 0x1e, 0x3c, 0xf2, 0xcd, 0xd6, 0x43, 0x85, 0xba, 0xd3, 0x11, + 0x88, 0x58, 0xd1, 0x42, 0xd9, 0x06, 0xea, 0xdb, 0x75, 0x90, 0xc9, 0x41, 0x36, + 0xda, 0x6a, 0x06, 0x35, 0x14, 0xd6, 0xa2, 0x5f, 0x7b, 0x37, 0xd7, 0x66, 0x4f, + 0x9b, 0x97, 0x09, 0x43, 0x3e, 0x6e, 0x70, 0x21, 0x18, 0xa4, 0xab, 0x9e, 0x7a, + 0x7a, 0x3e, 0x62, 0x59, 0x12, 0x99, 0x37, 0xd2, 0x9d, 0x0d, 0xb2, 0x60, 0x70, + 0x52, 0x3e, 0x8b, 0x06, 0x43, 0x13, 0x0a, 0xbe, 0xfe, 0x94, 0x3b, 0x40, 0x12, + 0x98, 0xae, 0x01, 0xa3, 0xab, 0x00, 0xab, 0xbc, 0x60, 0xd7, 0xdb, 0x93, 0x3c, + 0x7f, 0x07, 0xa8, 0xbf, 0x0f, 0x7c, 0xe1, 0x66, 0x0b, 0xcc, 0xb4, 0x5e, 0x04, + 0x2b, 0x45, 0x1b, 0x93, 0x50, 0x02, 0xce, 0xce, 0x27, 0xf3, 0x6a, 0xba, 0x56, + 0x47, 0xac, 0x28, 0xd8, 0x18, 0x6c, 0xdd, 0x1f, 0xb9, 0x5d, 0xc1, 0x35, 0xd4, + 0x89, 0x92, 0xf6, 0x8d, 0xa1, 0x2a, 0xd6, 0x1a, 0xc7, 0x56, 0x68, 0x0d, 0xd7, + 0xf8, 0xd0, 0x77, 0x4a, 0xbd, 0x6c, 0xfd, 0xa2, 0xf0, 0x32, 0xaf, 0x3b, 0xe1, + 0x39, 0xa6, 0x33, 0xd6, 0x73, 0x3c, 0x75, 0xd1, 0xab, 0xa8, 0x90, 0x18, 0xc8, + 0x57, 0x2b, 0x99, 0xcd, 0x30, 0xc5, 0x37, 0x06, 0x79, 0x41, 0xdf, 0x1c, 0x4b, + 0xc1, 0xfd, 0x57, 0x0f, 0x7b, 0x4d, 0xdc, 0x97, 0x51, 0x86, 0x23, 0xe3, 0xae, + 0x4a, 0x87, 0xbd, 0xb9, 0x66, 0xc9, 0x4d, 0x86, 0x1e, 0x80, 0xde, 0x88, 0xc2, + 0x92, 0xae, 0xe9, 0x38, 0x71, 0x94, 0xe2, 0x56, 0xc6, 0x70, 0x07, 0x52, 0x30, + 0x1c, 0x73, 0xfc, 0x95, 0x65, 0xa4, 0x04, 0x80, 0xd8, 0x12, 0x6e, 0x9d, 0x08, + 0x58, 0x79, 0xe2, 0x4b, 0x16, 0xe9, 0xc4, 0x85, 0xd8, 0xf0, 0xd6, 0x18, 0xca, + 0x0d, 0xd1, 0x21, 0xb5, 0x1a, 0x7c, 0xab, 0x23, 0x0c, 0x5b, 0x45, 0x67, 0x2b, + 0xdb, 0x8e, 0xa3, 0xa0, 0x40, 0xf7, 0xaa, 0xa0, 0x98, 0xba, 0x26, 0x02, 0x5d, + 0x2e, 0xab, 0x79, 0x48, 0x69, 0x3d, 0xd5, 0xf6, 0xd3, 0x09, 0x65, 0x01, 0xe9, + 0xe0, 0x71, 0x25, 0xd7, 0xeb, 0x29, 0x3b, 0x3a, 0xba, 0xd5, 0x7f, 0xd5, 0xf0, + 0x11, 0x64, 0x70, 0x2d, 0xae, 0x64, 0xbd, 0xba, 0x8c, 0x92, 0x4f, 0xb0, 0x79, + 0x96, 0x79, 0xd7, 0x7f, 0x98, 0xd3, 0x03, 0x91, 0x9f, 0xb4, 0xa7, 0xff, 0x26, + 0xa9, 0x6f, 0x13, 0x7a, 0x5e, 0x5c, 0xb9, 0x5b, 0xc4, 0xc6, 0xff, 0x99, 0x93, + 0x52, 0x6b, 0xda, 0x15, 0x03, 0x16, 0x8a, 0xb4, 0x8c, 0xbd, 0x45, 0x15, 0x39, + 0x27, 0xd3, 0x04, 0x30, 0x42, 0x3d, 0xbd, 0xf0, 0x66, 0x05, 0xf5, 0xb5, 0x4b, + 0x80, 0x8f, 0xeb, 0x22, 0xb2, 0x08, 0xb0, 0x64, 0x58, 0x18, 0x47, 0xb2, 0xf6, + 0x4c, 0xa6, 0x48, 0x37, 0x00, 0x72, 0x16, 0xde, 0x6e, 0xca, 0xff, 0xeb, 0x4b, + 0x69, 0xe6, 0x33, 0x47, 0xf8, 0x4a, 0xbc, 0xad, 0x8f, 0x2e, 0x75, 0x7d, 0x58, + 0x61, 0xce, 0x77, 0xee, 0x46, 0x51, 0x3d, 0xa7, 0x41, 0x68, 0x37, 0xdc, 0xb2, + 0x3d, 0x33, 0xea, 0x72, 0xaf, 0x23, 0xd0, 0xad, 0x8c, 0x93, 0x07, 0xd0, 0xb5, + 0x85, 0x8d, 0xa9, 0x5b, 0x77, 0xff, 0xf9, 0x02, 0x7b, 0x88, 0x59, 0xe1, 0x1d, + 0xcb, 0xd5, 0x98, 0x35, 0x0e, 0xee, 0x50, 0x93, 0x94, 0x81, 0x70, 0x8e, 0xa7, + 0x08, 0xeb, 0x9f, 0x66, 0x43, 0x88, 0xb9, 0xc6, 0x4d, 0x6a, 0xf0, 0xf9, 0x66, + 0x90, 0x34, 0x24, 0x00, 0x34, 0x8e, 0x92, 0x9e, 0x07, 0x46, 0x02, 0x53, 0xf3, + 0x83, 0x90, 0xf8, 0x7b, 0xd6, 0xc0, 0x53, 0x08, 0xc3, 0xbd, 0xe2, 0x52, 0x28, + 0xe0, 0xfa, 0x08, 0x80, 0xb0, 0x8e, 0xf3, 0x4a, 0x5a, 0x9c, 0xc0, 0xea, 0x0a, + 0x67, 0xca, 0x65, 0xb6, 0xff, 0xd0, 0x05, 0x57, 0x29, 0x09, 0xf1, 0xc4, 0x2d, + 0xd7, 0x45, 0xee, 0xee, 0x9d, 0xd6, 0xb4, 0x43, 0x9c, 0x9f, 0x3f, 0x98, 0xa1, + 0x18, 0xfe, 0x16, 0x69, 0x8e, 0x9c, 0xef, 0xf5, 0x58, 0xf1, 0x60, 0x66, 0x97, + 0x5f, 0xe3, 0x95, 0x83, 0xe9, 0xb5, 0x85, 0x3b, 0x13, 0x11, 0x39, 0x15, 0x80, + 0x01, 0x9f, 0xe5, 0x5d, 0x59, 0xd1, 0xc8, 0x28, 0xd3, 0xfe, 0xb6, 0xa3, 0xb9, + 0xce, 0x92, 0xd0, 0x89, 0xae, 0x4b, 0x40, 0x8e, 0x23, 0xd6, 0xa4, 0x37, 0xd4, + 0x98, 0x9b, 0x51, 0x9b, 0x7a, 0x9e, 0xb0, 0x8a, 0xe6, 0xd4, 0x48, 0xa7, 0xa1, + 0x6e, 0x8a, 0xed, 0x26, 0xa2, 0xec, 0xd0, 0xca, 0xd8, 0x08, 0x44, 0xfd, 0x06, + 0x50, 0xd8, 0xc4, 0xe4, 0xd2, 0xaf, 0x90, 0x65, 0x67, 0x48, 0xd8, 0x09, 0x9a, + 0x0c, 0x75, 0x6f, 0xc1, 0x6c, 0xca, 0x06, 0xa3, 0x34, 0x43, 0x07, 0x02, 0xae, + 0x19, 0x61, 0x66, 0x5b, 0x48, 0x45, 0xac, 0xd1, 0xa8, 0xe3, 0x41, 0x01, 0xe6, + 0x8b, 0xb6, 0x44, 0xac, 0x03, 0x4d, 0xc6, 0x3e, 0x6e, 0x34, 0x4c, 0x3d, 0x63, + 0x76, 0x2a, 0x7a, 0x5b, 0xf5, 0x9f, 0x13, 0x09, 0x54, 0x10, 0x98, 0x1d, 0x6b, + 0x6b, 0x16, 0xbc, 0xd4, 0xc9, 0xfa, 0x68, 0xaf, 0x6e, 0x53, 0x65, 0xe9, 0x4e, + 0xcb, 0xe7, 0xab, 0x8b, 0x80, 0x43, 0xdf, 0xba, 0xcb, 0x23, 0xc8, 0x4d, 0x71, + 0xa8, 0xfe, 0x5d, 0x9a, 0xc5, 0x50, 0x2c, 0xe9, 0xf7, 0x3f, 0x40, 0x8e, 0x14, + 0x37, 0x6d, 0xb8, 0x6e, 0xf5, 0x7c, 0xc3, 0x7d, 0x09, 0x89, 0x6f, 0xa9, 0x06, + 0x97, 0x2e, 0x55, 0x71, 0x80, 0xa4, 0xab, 0x5a, 0xd0, 0x9d, 0x88, 0x46, 0xdd, + 0x6d, 0xa7, 0x48, 0x76, 0x54, 0x36, 0xe0, 0x16, 0x02, 0x40, 0xf8, 0xd4, 0x1c, + 0x0a, 0xc7, 0x83, 0xf9, 0x39, 0xf2, 0xd0, 0xed, 0x26, 0x2c, 0xe8, 0x59, 0xc1, + 0x31, 0xeb, 0xc9, 0x3f, 0xf2, 0xe6, 0xe4, 0x07, 0xd4, 0xe2, 0x43, 0xe1, 0xe9, + 0x31, 0xd5, 0x3a, 0x45, 0x43, 0xb6, 0xe2, 0x6d, 0x82, 0x59, 0x6f, 0xc5, 0x3b, + 0x52, 0x31, 0x2c, 0x77, 0x6d, 0x12, 0xeb, 0x2b, 0x65, 0x9b, 0x4f, 0xb0, 0x98, + 0xdf, 0x87, 0xd6, 0x83, 0xcf, 0x9e, 0x54, 0x12, 0xee, 0x56, 0xc3, 0xfe, 0x98, + 0x41, 0xd7, 0x3f, 0xd0, 0x70, 0xdf, 0xa5, 0x1f, 0x5b, 0xaf, 0xed, 0xf2, 0x06, + 0xf1, 0x3c, 0x52, 0x4e, 0x5c, 0x50, 0xca, 0xc9, 0x90, 0x6e, 0xfa, 0x39, 0x32, + 0x90, 0x04, 0x2e, 0x3b, 0xc5, 0x9f, 0x96, 0x0b, 0x7d, 0x24, 0x0a, 0xe4, 0x43, + 0xfc, 0x49, 0x26, 0x9c, 0xe0, 0x00, 0x61, 0xe6, 0x5c, 0x6d, 0x74, 0x81, 0x2a, + 0x30, 0xdd, 0x5f, 0x5f, 0xe7, 0x4e, 0xff, 0x61, 0xe0, 0xcb, 0xab, 0x3c, 0xec, + 0x75, 0xd0, 0xae, 0xf9, 0x50, 0x83, 0x18, 0x94, 0x52, 0xdd, 0x3d, 0x9e, 0xdf, + 0x44, 0x87, 0xbc, 0x73, 0x4c, 0x8b, 0x24, 0xf2, 0x12, 0x96, 0xe4, 0xe9, 0xef, + 0x11, 0x7d, 0x7f, 0xb9, 0x77, 0xe3, 0xb0, 0xe6, 0x40, 0x6e, 0x63, 0x08, 0x59, + 0x06, 0x33, 0x1a, 0x93, 0x03, 0x3d, 0x1c, 0xb8, 0x36, 0x0f, 0xe6, 0xfe, 0xa6, + 0x1a, 0x68, 0x26, 0xdf, 0x36, 0x25, 0x57, 0x89, 0xf9, 0x2e, 0x40, 0xba, 0xfc, + 0xb2, 0xeb, 0xcb, 0x9e, 0x55, 0x6f, 0x6c, 0x0c, 0xca, 0xdc, 0x6a, 0xf0, 0x8e, + 0x31, 0xec, 0x4a, 0xd5, 0x28, 0x80, 0x34, 0xe1, 0x6d, 0x15, 0x5c, 0xfd, 0xca, + 0xda, 0x7b, 0xab, 0x59, 0x9c, 0x2f, 0xa4, 0xad, 0x2e, 0x62, 0x93, 0xf9, 0xfe, + 0x09, 0x71, 0x69, 0x14, 0x82, 0x76, 0xb6, 0xa9, 0xea, 0xa7, 0x2f, 0x14, 0x8b, + 0x0c, 0x95, 0x65, 0xc3, 0xc2, 0xdd, 0x63, 0x12, 0x5e, 0x0f, 0xa5, 0x30, 0x86, + 0x1a, 0x71, 0x0d, 0xf8, 0xe4, 0x81, 0xf2, 0x71, 0x29, 0x20, 0xf8, 0x78, 0x7e, + 0x0a, 0xed, 0xfe, 0x61, 0x8a, 0xff, 0x50, 0xa3, 0xb5, 0x62, 0x13, 0x88, 0x4d, + 0x62, 0x62, 0xc1, 0x1d, 0xeb, 0xf2, 0xba, 0x7e, 0x8a, 0xd6, 0x69, 0x2c, 0xb1, + 0x70, 0x78, 0x33, 0x14, 0x18, 0xda, 0x4b, 0xe0, 0x64, 0xff, 0x52, 0x70, 0x07, + 0x39, 0x34, 0xab, 0xcd, 0x2a, 0xb0, 0x46, 0x9e, 0xca, 0xf7, 0x27, 0x5b, 0x4b, + 0xd7, 0x2b, 0xc6, 0xed, 0x34, 0x47, 0x8e, 0xa4, 0x08, 0x9b, 0x73, 0x6a, 0x16, + 0xdd, 0x90, 0x6d, 0x49, 0xf2, 0x5c, 0x33, 0x82, 0x7c, 0x57, 0x1c, 0xe0, 0xb5, + 0xd7, 0x21, 0x77, 0xaa, 0x35, 0x08, 0x80, 0x4b, 0xc0, 0xf8, 0xfa, 0xa9, 0x47, + 0x12, 0x22, 0x31, 0x40, 0x2d, 0x2f, 0x5c, 0xc9, 0xa0, 0xeb, 0x0e, 0x09, 0xd4, + 0x27, 0xb4, 0x27, 0x28, 0x8d, 0x93, 0x7d, 0x9d, 0x72, 0xb7, 0x74, 0x56, 0xf8, + 0x86, 0x59, 0x4c, 0xd8, 0xc6, 0xa4, 0x62, 0xf7, 0x7f, 0xd8, 0x30, 0x76, 0x46, + 0x9c, 0xc0, 0xec, 0xba, 0x3c, 0xc4, 0x0c, 0xad, 0x69, 0xe5, 0xb5, 0x41, 0x12, + 0xea, 0xb3, 0x33, 0x96, 0xae, 0xcf, 0xbc, 0x21, 0x1f, 0x1f, 0x79, 0xcf, 0x33, + 0x10, 0x8e, 0x93, 0xd9, 0x53, 0x78, 0xba, 0xe6, 0x95, 0x82, 0x74, 0xb3, 0x10, + 0x88, 0xfb, 0xd8, 0xb3, 0xa3, 0xa0, 0xd1, 0x54, 0xa7, 0x89, 0x73, 0x5b, 0x03, + 0x49, 0xc4, 0xd5, 0x1c, 0x88, 0x9d, 0x08, 0x95, 0x2d, 0xdd, 0x54, 0x88, 0xbe, + 0x95, 0x56, 0x05, 0x94, 0xe6, + ], + script_code: Script(vec![0x52, 0x63, 0x53, 0x51, 0x65]), + transparent_input: Some(0), + hash_type: 2, + amount: 483959951916902, + consensus_branch_id: consensus::BranchId::Overwinter, + sighash: [ + 0x29, 0x6f, 0xd7, 0x63, 0xf2, 0x54, 0x5e, 0x64, 0xfb, 0x5d, 0x7d, 0x49, 0xc0, + 0x00, 0xd2, 0xb4, 0x18, 0xb9, 0x3b, 0xde, 0x22, 0x34, 0xf8, 0x74, 0x29, 0x11, + 0xe8, 0xaf, 0xef, 0xd0, 0x6d, 0x57, + ], + }, + ] + } +} + +pub mod zip_0243 { + use crate::{consensus, legacy::Script}; + + pub struct Test0243Vector { + pub tx: Vec, + pub script_code: Script, + pub transparent_input: Option, + pub hash_type: u32, + pub amount: i64, + pub consensus_branch_id: consensus::BranchId, + pub sighash: [u8; 32], + } + pub fn make_test_vectors() -> Vec { + // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0243.py + vec![ + Test0243Vector { + tx: vec![ + 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x00, 0x02, 0xe7, 0x71, 0x98, + 0x11, 0x89, 0x3e, 0x00, 0x00, 0x09, 0x52, 0x00, 0xac, 0x65, 0x51, 0xac, 0x63, + 0x65, 0x65, 0xb2, 0x83, 0x5a, 0x08, 0x05, 0x75, 0x02, 0x00, 0x02, 0x51, 0x51, + 0x48, 0x1c, 0xdd, 0x86, 0xb3, 0xcc, 0x43, 0x18, 0x44, 0x21, 0x17, 0x62, 0x3c, + 0xeb, 0x05, 0x00, 0x03, 0x1b, 0x3d, 0x1a, 0x02, 0x7c, 0x2c, 0x40, 0x59, 0x09, + 0x58, 0xb7, 0xeb, 0x13, 0xd7, 0x42, 0xa9, 0x97, 0x73, 0x8c, 0x46, 0xa4, 0x58, + 0x96, 0x5b, 0xaf, 0x27, 0x6b, 0xa9, 0x2f, 0x27, 0x2c, 0x72, 0x1f, 0xe0, 0x1f, + 0x7e, 0x9c, 0x8e, 0x36, 0xd6, 0xa5, 0xe2, 0x9d, 0x4e, 0x30, 0xa7, 0x35, 0x94, + 0xbf, 0x50, 0x98, 0x42, 0x1c, 0x69, 0x37, 0x8a, 0xf1, 0xe4, 0x0f, 0x64, 0xe1, + 0x25, 0x94, 0x6f, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, 0xb6, 0x4b, 0x69, + 0x68, 0x91, 0x2a, 0x63, 0x81, 0xce, 0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, + 0xf5, 0xa8, 0xd7, 0x55, 0x1d, 0xb5, 0xfd, 0x93, 0x13, 0x25, 0xc9, 0xa1, 0x38, + 0xf4, 0x9b, 0x1a, 0x53, 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x51, 0xa7, + 0xaf, 0x9d, 0xb6, 0x99, 0x0e, 0xd8, 0x3d, 0xd6, 0x4a, 0xf3, 0x59, 0x7c, 0x04, + 0x32, 0x3e, 0xa5, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, 0xb9, 0xda, 0x94, + 0x8d, 0x32, 0x0d, 0xad, 0xd6, 0x4f, 0x54, 0x31, 0xe6, 0x1d, 0xdf, 0x65, 0x8d, + 0x24, 0xae, 0x67, 0xc2, 0x2c, 0x8d, 0x13, 0x09, 0x13, 0x1f, 0xc0, 0x0f, 0xe7, + 0xf2, 0x35, 0x73, 0x42, 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x91, 0xe0, 0x0c, + 0x7a, 0x1d, 0x48, 0xaf, 0x04, 0x68, 0x27, 0x59, 0x1e, 0x97, 0x33, 0xa9, 0x7f, + 0xa6, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, 0x85, 0xed, 0xcb, 0xda, + 0xe6, 0x9c, 0xe8, 0xfc, 0x1b, 0xe4, 0xaa, 0xc0, 0x0f, 0xf2, 0x71, 0x1e, 0xbd, + 0x93, 0x1d, 0xe5, 0x18, 0x85, 0x68, 0x78, 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, + 0x2e, 0xc9, 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, 0x3c, 0x94, 0xe2, 0x88, 0x53, + 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, 0x79, 0x0f, 0xe5, 0x3e, + 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, 0x32, 0xb4, 0xf4, 0x73, 0xf4, + 0x68, 0xa0, 0x08, 0xe7, 0x23, 0x89, 0xfc, 0x03, 0x88, 0x0d, 0x78, 0x0c, 0xb0, + 0x7f, 0xcf, 0xaa, 0xbe, 0x3f, 0x1a, 0x84, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, + 0x3d, 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x55, 0xed, 0x94, 0x94, 0xc6, + 0xac, 0x89, 0x3c, 0x49, 0x72, 0x38, 0x33, 0xec, 0x89, 0x26, 0xc1, 0x03, 0x95, + 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, 0x73, 0x1e, 0x98, 0x5d, 0x99, 0x58, + 0x9c, 0x8b, 0xb8, 0x38, 0xe8, 0xaa, 0xf7, 0x45, 0x53, 0x3e, 0xd9, 0xe8, 0xae, + 0x3a, 0x1c, 0xd0, 0x74, 0xa5, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, + 0xeb, 0xbc, 0x86, 0x2d, 0xed, 0x42, 0x43, 0x5e, 0x92, 0x47, 0x69, 0x30, 0xd0, + 0x69, 0x89, 0x6c, 0xff, 0x30, 0xeb, 0x41, 0x4f, 0x72, 0x7b, 0x89, 0x5a, 0x4b, + 0x7b, 0xe1, 0x76, 0x93, 0x67, 0xe1, 0xfe, 0x8a, 0xd1, 0x8d, 0xe1, 0x1e, 0x58, + 0xd8, 0x8a, 0x0a, 0xd5, 0x51, 0x1d, 0x35, 0x25, 0x12, 0x2b, 0x7b, 0x0a, 0x6f, + 0x25, 0xd2, 0x8b, 0x16, 0x45, 0x7e, 0x74, 0x59, 0x39, 0xff, 0xed, 0xbd, 0x12, + 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, 0x7d, 0x41, 0x7a, 0xdb, 0x3d, 0x15, + 0xcc, 0x54, 0xdc, 0xb1, 0xfc, 0xe4, 0x67, 0x50, 0x0c, 0x6b, 0x8f, 0xb8, 0x6b, + 0x12, 0xb5, 0x6d, 0xa9, 0xc3, 0x82, 0x85, 0x7d, 0xee, 0xcc, 0x40, 0xa9, 0x8d, + 0x5f, 0x29, 0x35, 0x39, 0x5e, 0xe4, 0x76, 0x2d, 0xd2, 0x1a, 0xfd, 0xbb, 0x5d, + 0x47, 0xfa, 0x9a, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, 0xb9, 0x27, + 0xb7, 0xfa, 0xe2, 0xdb, 0x58, 0x71, 0x05, 0x41, 0x5d, 0x46, 0x42, 0x78, 0x9d, + 0x38, 0xf5, 0x0b, 0x8d, 0xbc, 0xc1, 0x29, 0xca, 0xb3, 0xd1, 0x7d, 0x19, 0xf3, + 0x35, 0x5b, 0xcf, 0x73, 0xce, 0xcb, 0x8c, 0xb8, 0xa5, 0xda, 0x01, 0x30, 0x71, + 0x52, 0xf1, 0x39, 0x36, 0xa2, 0x70, 0x57, 0x26, 0x70, 0xdc, 0x82, 0xd3, 0x90, + 0x26, 0xc6, 0xcb, 0x4c, 0xd4, 0xb0, 0xf7, 0xf5, 0xaa, 0x2a, 0x4f, 0x5a, 0x53, + 0x41, 0xec, 0x5d, 0xd7, 0x15, 0x40, 0x6f, 0x2f, 0xdd, 0x2a, 0xfa, 0x73, 0x3f, + 0x5f, 0x64, 0x1c, 0x8c, 0x21, 0x86, 0x2a, 0x1b, 0xaf, 0xce, 0x26, 0x09, 0xd9, + 0xee, 0xcf, 0xa1, 0x58, 0xcf, 0xb5, 0xcd, 0x79, 0xf8, 0x80, 0x08, 0xe3, 0x15, + 0xdc, 0x7d, 0x83, 0x88, 0xe7, 0x6c, 0x17, 0x82, 0xfd, 0x27, 0x95, 0xd1, 0x8a, + 0x76, 0x36, 0x24, 0xc2, 0x5f, 0xa9, 0x59, 0xcc, 0x97, 0x48, 0x9c, 0xe7, 0x57, + 0x45, 0x82, 0x4b, 0x77, 0x86, 0x8c, 0x53, 0x23, 0x9c, 0xfb, 0xdf, 0x73, 0xca, + 0xec, 0x65, 0x60, 0x40, 0x37, 0x31, 0x4f, 0xaa, 0xce, 0xb5, 0x62, 0x18, 0xc6, + 0xbd, 0x30, 0xf8, 0x37, 0x4a, 0xc1, 0x33, 0x86, 0x79, 0x3f, 0x21, 0xa9, 0xfb, + 0x80, 0xad, 0x03, 0xbc, 0x0c, 0xda, 0x4a, 0x44, 0x94, 0x6c, 0x00, 0xe1, 0xb1, + 0xa1, 0xdf, 0x0e, 0x5b, 0x87, 0xb5, 0xbe, 0xce, 0x47, 0x7a, 0x70, 0x96, 0x49, + 0xe9, 0x50, 0x06, 0x05, 0x91, 0x39, 0x48, 0x12, 0x95, 0x1e, 0x1f, 0xe3, 0x89, + 0x5b, 0x8c, 0xc3, 0xd1, 0x4d, 0x2c, 0xf6, 0x55, 0x6d, 0xf6, 0xed, 0x4b, 0x4d, + 0xdd, 0x3d, 0x9a, 0x69, 0xf5, 0x33, 0x57, 0xd7, 0x76, 0x7f, 0x4f, 0x5c, 0xcb, + 0xdb, 0xc5, 0x96, 0x63, 0x12, 0x77, 0xf8, 0xfe, 0xcd, 0x08, 0xcb, 0x05, 0x6b, + 0x95, 0xe3, 0x02, 0x5b, 0x97, 0x92, 0xff, 0xf7, 0xf2, 0x44, 0xfc, 0x71, 0x62, + 0x69, 0xb9, 0x26, 0xd6, 0x2e, 0x95, 0x96, 0xfa, 0x82, 0x5c, 0x6b, 0xf2, 0x1a, + 0xff, 0x9e, 0x68, 0x62, 0x5a, 0x6b, 0x4c, 0xbc, 0x4b, 0x70, 0x0a, 0x36, 0x4f, + 0xa7, 0x6b, 0xd8, 0x29, 0x8b, 0xc3, 0xec, 0x60, 0x8d, 0x4c, 0xf7, 0xf3, 0x56, + 0x66, 0x58, 0xd5, 0x58, 0x87, 0x14, 0xec, 0x94, 0x48, 0xb0, 0xf0, 0x39, 0x61, + 0x28, 0xae, 0xf8, 0x84, 0xa6, 0x46, 0x11, 0x4c, 0x9f, 0x1a, 0x6d, 0xf5, 0x63, + 0x19, 0x03, 0x3c, 0x31, 0x99, 0xcc, 0x7a, 0x09, 0xe9, 0xe9, 0x56, 0x74, 0x82, + 0xc9, 0x26, 0x95, 0x39, 0x02, 0x29, 0x40, 0x7b, 0xbc, 0x48, 0x98, 0x56, 0x75, + 0xe3, 0xf8, 0x74, 0xa4, 0x53, 0x3f, 0x1d, 0x63, 0xa8, 0x4d, 0xfa, 0x3e, 0x0f, + 0x46, 0x0f, 0xe2, 0xf5, 0x7e, 0x34, 0xfb, 0xc7, 0x54, 0x23, 0xb6, 0x88, 0x3a, + 0x50, 0xa0, 0xd4, 0x70, 0x19, 0x0d, 0xfb, 0xa1, 0x0a, 0x85, 0x7f, 0x82, 0x84, + 0x2d, 0x38, 0x25, 0xb3, 0xd6, 0xda, 0x05, 0x73, 0xd3, 0x16, 0xeb, 0x16, 0x0d, + 0xc0, 0xb7, 0x16, 0xc4, 0x8f, 0xbd, 0x46, 0x7f, 0x75, 0xb7, 0x80, 0x14, 0x9a, + 0xe8, 0x80, 0x8f, 0x4e, 0x68, 0xf5, 0x0c, 0x05, 0x36, 0xac, 0xdd, 0xf6, 0xf1, + 0xae, 0xab, 0x01, 0x6b, 0x6b, 0xc1, 0xec, 0x14, 0x4b, 0x4e, 0x55, 0x3a, 0xcf, + 0xd6, 0x70, 0xf7, 0x7e, 0x75, 0x5f, 0xc8, 0x8e, 0x06, 0x77, 0xe3, 0x1b, 0xa4, + 0x59, 0xb4, 0x4e, 0x30, 0x77, 0x68, 0x95, 0x8f, 0xe3, 0x78, 0x9d, 0x41, 0xc2, + 0xb1, 0xff, 0x43, 0x4c, 0xb3, 0x0e, 0x15, 0x91, 0x4f, 0x01, 0xbc, 0x6b, 0xc2, + 0x30, 0x7b, 0x48, 0x8d, 0x25, 0x56, 0xd7, 0xb7, 0x38, 0x0e, 0xa4, 0xff, 0xd7, + 0x12, 0xf6, 0xb0, 0x2f, 0xe8, 0x06, 0xb9, 0x45, 0x69, 0xcd, 0x40, 0x59, 0xf3, + 0x96, 0xbf, 0x29, 0xb9, 0x9d, 0x0a, 0x40, 0xe5, 0xe1, 0x71, 0x1c, 0xa9, 0x44, + 0xf7, 0x2d, 0x43, 0x6a, 0x10, 0x2f, 0xca, 0x4b, 0x97, 0x69, 0x3d, 0xa0, 0xb0, + 0x86, 0xfe, 0x9d, 0x2e, 0x71, 0x62, 0x47, 0x0d, 0x02, 0xe0, 0xf0, 0x5d, 0x4b, + 0xec, 0x95, 0x12, 0xbf, 0xb3, 0xf3, 0x83, 0x27, 0x29, 0x6e, 0xfa, 0xa7, 0x43, + 0x28, 0xb1, 0x18, 0xc2, 0x74, 0x02, 0xc7, 0x0c, 0x3a, 0x90, 0xb4, 0x9a, 0xd4, + 0xbb, 0xc6, 0x8e, 0x37, 0xc0, 0xaa, 0x7d, 0x9b, 0x3f, 0xe1, 0x77, 0x99, 0xd7, + 0x3b, 0x84, 0x1e, 0x75, 0x17, 0x13, 0xa0, 0x29, 0x43, 0x90, 0x5a, 0xae, 0x08, + 0x03, 0xfd, 0x69, 0x44, 0x2e, 0xb7, 0x68, 0x1e, 0xc2, 0xa0, 0x56, 0x00, 0x05, + 0x4e, 0x92, 0xee, 0xd5, 0x55, 0x02, 0x8f, 0x21, 0xb6, 0xa1, 0x55, 0x26, 0x8a, + 0x2d, 0xd6, 0x64, 0x0a, 0x69, 0x30, 0x1a, 0x52, 0xa3, 0x8d, 0x4d, 0x9f, 0x9f, + 0x95, 0x7a, 0xe3, 0x5a, 0xf7, 0x16, 0x71, 0x18, 0x14, 0x1c, 0xe4, 0xc9, 0xbe, + 0x0a, 0x6a, 0x49, 0x2f, 0xe7, 0x9f, 0x15, 0x81, 0xa1, 0x55, 0xfa, 0x3a, 0x03, + 0x49, 0x99, 0xc5, 0x38, 0xf7, 0xa7, 0x58, 0xbb, 0x5b, 0x1d, 0x28, 0xfd, 0x21, + 0x8f, 0xba, 0x19, 0x38, 0x74, 0x4b, 0xdb, 0x77, 0xb4, 0xa4, 0xdf, 0xa7, 0xa5, + 0xfa, 0xe9, 0x6e, 0x8c, 0xd4, 0x9b, 0x26, 0x90, 0x7d, 0xfc, 0x66, 0x85, 0xc5, + 0xc9, 0x9b, 0x71, 0x41, 0xac, 0x62, 0x6a, 0xb4, 0x76, 0x1f, 0xd3, 0xf4, 0x1e, + 0x72, 0x8e, 0x1a, 0x28, 0xf8, 0x9d, 0xb8, 0x9f, 0xfd, 0xec, 0xa3, 0x64, 0xe4, + 0xb2, 0x2d, 0x81, 0xd9, 0x96, 0x8d, 0x01, 0x19, 0xe4, 0xc7, 0xa1, 0x89, 0xad, + 0xf2, 0x2a, 0xd9, 0x68, 0x30, 0xa5, 0x4e, 0x40, 0xdc, 0x73, 0xea, 0xba, 0x6b, + 0x2a, 0xaf, 0x14, 0xf7, 0xca, 0x94, 0x2e, 0x73, 0x70, 0xb2, 0x47, 0xc0, 0x46, + 0xf8, 0xe7, 0x5e, 0xf8, 0xe3, 0xf8, 0xbd, 0x82, 0x1c, 0xf5, 0x77, 0x49, 0x18, + 0x64, 0xe2, 0x0e, 0x6d, 0x08, 0xfd, 0x2e, 0x32, 0xb5, 0x55, 0xc9, 0x2c, 0x66, + 0x1f, 0x19, 0x58, 0x8b, 0x72, 0xa8, 0x95, 0x99, 0x71, 0x0a, 0x88, 0x06, 0x12, + 0x53, 0xca, 0x28, 0x5b, 0x63, 0x04, 0xb3, 0x7d, 0xa2, 0xb5, 0x29, 0x4f, 0x5c, + 0xb3, 0x54, 0xa8, 0x94, 0x32, 0x28, 0x48, 0xcc, 0xbd, 0xc7, 0xc2, 0x54, 0x5b, + 0x7d, 0xa5, 0x68, 0xaf, 0xac, 0x87, 0xff, 0xa0, 0x05, 0xc3, 0x12, 0x24, 0x1c, + 0x2d, 0x57, 0xf4, 0xb4, 0x5d, 0x64, 0x19, 0xf0, 0xd2, 0xe2, 0xc5, 0xaf, 0x33, + 0xae, 0x24, 0x37, 0x85, 0xb3, 0x25, 0xcd, 0xab, 0x95, 0x40, 0x4f, 0xc7, 0xae, + 0xd7, 0x05, 0x25, 0xcd, 0xdb, 0x41, 0x87, 0x2c, 0xfc, 0xc2, 0x14, 0xb1, 0x32, + 0x32, 0xed, 0xc7, 0x86, 0x09, 0x75, 0x3d, 0xbf, 0xf9, 0x30, 0xeb, 0x0d, 0xc1, + 0x56, 0x61, 0x2b, 0x9c, 0xb4, 0x34, 0xbc, 0x4b, 0x69, 0x33, 0x92, 0xde, 0xb8, + 0x7c, 0x53, 0x04, 0x35, 0x31, 0x2e, 0xdc, 0xed, 0xc6, 0xa9, 0x61, 0x13, 0x33, + 0x38, 0xd7, 0x86, 0xc4, 0xa3, 0xe1, 0x03, 0xf6, 0x01, 0x10, 0xa1, 0x6b, 0x13, + 0x37, 0x12, 0x97, 0x04, 0xbf, 0x47, 0x54, 0xff, 0x6b, 0xa9, 0xfb, 0xe6, 0x59, + 0x51, 0xe6, 0x10, 0x62, 0x0f, 0x71, 0xcd, 0xa8, 0xfc, 0x87, 0x76, 0x25, 0xf2, + 0xc5, 0xbb, 0x04, 0xcb, 0xe1, 0x22, 0x8b, 0x1e, 0x88, 0x6f, 0x40, 0x50, 0xaf, + 0xd8, 0xfe, 0x94, 0xe9, 0x7d, 0x2e, 0x9e, 0x85, 0xc6, 0xbb, 0x74, 0x8c, 0x00, + 0x42, 0xd3, 0x24, 0x9a, 0xbb, 0x13, 0x42, 0xbb, 0x0e, 0xeb, 0xf6, 0x20, 0x58, + 0xbf, 0x3d, 0xe0, 0x80, 0xd9, 0x46, 0x11, 0xa3, 0x75, 0x09, 0x15, 0xb5, 0xdc, + 0x6c, 0x0b, 0x38, 0x99, 0xd4, 0x12, 0x22, 0xba, 0xce, 0x76, 0x0e, 0xe9, 0xc8, + 0x81, 0x8d, 0xed, 0x59, 0x9e, 0x34, 0xc5, 0x6d, 0x73, 0x72, 0xaf, 0x1e, 0xb8, + 0x68, 0x52, 0xf2, 0xa7, 0x32, 0x10, 0x4b, 0xdb, 0x75, 0x07, 0x39, 0xde, 0x6c, + 0x2c, 0x6e, 0x0f, 0x9e, 0xb7, 0xcb, 0x17, 0xf1, 0x94, 0x2b, 0xfc, 0x9f, 0x4f, + 0xd6, 0xeb, 0xb6, 0xb4, 0xcd, 0xd4, 0xda, 0x2b, 0xca, 0x26, 0xfa, 0xc4, 0x57, + 0x8e, 0x9f, 0x54, 0x34, 0x05, 0xac, 0xc7, 0xd8, 0x6f, 0xf5, 0x91, 0x58, 0xbd, + 0x0c, 0xba, 0x3a, 0xef, 0x6f, 0x4a, 0x84, 0x72, 0xd1, 0x44, 0xd9, 0x9f, 0x8b, + 0x8d, 0x1d, 0xed, 0xaa, 0x90, 0x77, 0xd4, 0xf0, 0x1d, 0x4b, 0xb2, 0x7b, 0xbe, + 0x31, 0xd8, 0x8f, 0xbe, 0xfa, 0xc3, 0xdc, 0xd4, 0x79, 0x75, 0x63, 0xa2, 0x6b, + 0x1d, 0x61, 0xfc, 0xd9, 0xa4, 0x64, 0xab, 0x21, 0xed, 0x55, 0x0f, 0xe6, 0xfa, + 0x09, 0x69, 0x5b, 0xa0, 0xb2, 0xf1, 0x0e, 0xea, 0x64, 0x68, 0xcc, 0x6e, 0x20, + 0xa6, 0x6f, 0x82, 0x6e, 0x3d, 0x14, 0xc5, 0x00, 0x6f, 0x05, 0x63, 0x88, 0x7f, + 0x5e, 0x12, 0x89, 0xbe, 0x1b, 0x20, 0x04, 0xca, 0xca, 0x8d, 0x3f, 0x34, 0xd6, + 0xe8, 0x4b, 0xf5, 0x9c, 0x1e, 0x04, 0x61, 0x9a, 0x7c, 0x23, 0xa9, 0x96, 0x94, + 0x1d, 0x88, 0x9e, 0x46, 0x22, 0xa9, 0xb9, 0xb1, 0xd5, 0x9d, 0x5e, 0x31, 0x90, + 0x94, 0x31, 0x8c, 0xd4, 0x05, 0xba, 0x27, 0xb7, 0xe2, 0xc0, 0x84, 0x76, 0x2d, + 0x31, 0x45, 0x3e, 0xc4, 0x54, 0x9a, 0x4d, 0x97, 0x72, 0x9d, 0x03, 0x34, 0x60, + 0xfc, 0xf8, 0x9d, 0x64, 0x94, 0xf2, 0xff, 0xd7, 0x89, 0xe9, 0x80, 0x82, 0xea, + 0x5c, 0xe9, 0x53, 0x4b, 0x3a, 0xcd, 0x60, 0xfe, 0x49, 0xe3, 0x7e, 0x4f, 0x66, + 0x69, 0x31, 0x67, 0x73, 0x19, 0xed, 0x89, 0xf8, 0x55, 0x88, 0x74, 0x1b, 0x31, + 0x28, 0x90, 0x1a, 0x93, 0xbd, 0x78, 0xe4, 0xbe, 0x02, 0x25, 0xa9, 0xe2, 0x69, + 0x2c, 0x77, 0xc9, 0x69, 0xed, 0x01, 0x76, 0xbd, 0xf9, 0x55, 0x59, 0x48, 0xcb, + 0xd5, 0xa3, 0x32, 0xd0, 0x45, 0xde, 0x6b, 0xa6, 0xbf, 0x44, 0x90, 0xad, 0xfe, + 0x74, 0x44, 0xcd, 0x46, 0x7a, 0x09, 0x07, 0x54, 0x17, 0xfc, 0xc0, 0x06, 0x2e, + 0x49, 0xf0, 0x08, 0xc5, 0x1a, 0xd4, 0x22, 0x74, 0x39, 0xc1, 0xb4, 0x47, 0x6c, + 0xcd, 0x8e, 0x97, 0x86, 0x2d, 0xab, 0x7b, 0xe1, 0xe8, 0xd3, 0x99, 0xc0, 0x5e, + 0xf2, 0x7c, 0x6e, 0x22, 0xee, 0x27, 0x3e, 0x15, 0x78, 0x6e, 0x39, 0x4c, 0x8f, + 0x1b, 0xe3, 0x16, 0x82, 0xa3, 0x01, 0x47, 0x96, 0x3a, 0xc8, 0xda, 0x8d, 0x41, + 0xd8, 0x04, 0x25, 0x84, 0x26, 0xa3, 0xf7, 0x02, 0x89, 0xb8, 0xad, 0x19, 0xd8, + 0xde, 0x13, 0xbe, 0x4e, 0xeb, 0xe3, 0xbd, 0x4c, 0x8a, 0x6f, 0x55, 0xd6, 0xe0, + 0xc3, 0x73, 0xd4, 0x56, 0x85, 0x18, 0x79, 0xf5, 0xfb, 0xc2, 0x82, 0xdb, 0x9e, + 0x13, 0x48, 0x06, 0xbf, 0xf7, 0x1e, 0x11, 0xbc, 0x33, 0xab, 0x75, 0xdd, 0x6c, + 0xa0, 0x67, 0xfb, 0x73, 0xa0, 0x43, 0xb6, 0x46, 0xa7, 0xcf, 0x39, 0xca, 0xb4, + 0x92, 0x83, 0x86, 0x78, 0x6d, 0x2f, 0x24, 0x14, 0x1e, 0xe1, 0x20, 0xfd, 0xc3, + 0x4d, 0x67, 0x64, 0xea, 0xfc, 0x66, 0x88, 0x0e, 0xe0, 0x20, 0x4f, 0x53, 0xcc, + 0x11, 0x67, 0xed, 0x20, 0xb4, 0x3a, 0x52, 0xde, 0xa3, 0xca, 0x7c, 0xff, 0x8e, + 0xf3, 0x5c, 0xd8, 0xe6, 0xd7, 0xc1, 0x11, 0xa6, 0x8e, 0xf4, 0x4b, 0xcd, 0x0c, + 0x15, 0x13, 0xad, 0x47, 0xca, 0x61, 0xc6, 0x59, 0xcc, 0x5d, 0x32, 0x5b, 0x44, + 0x0f, 0x6b, 0x9f, 0x59, 0xaf, 0xf6, 0x68, 0x79, 0xbb, 0x66, 0x88, 0xfd, 0x28, + 0x59, 0x36, 0x2b, 0x18, 0x2f, 0x20, 0x7b, 0x31, 0x75, 0x96, 0x1f, 0x64, 0x11, + 0xa4, 0x93, 0xbf, 0xfd, 0x04, 0x8e, 0x7d, 0x0d, 0x87, 0xd8, 0x2f, 0xe6, 0xf9, + 0x90, 0xa2, 0xb0, 0xa2, 0x5f, 0x5a, 0xa0, 0x11, 0x1a, 0x6e, 0x68, 0xf3, 0x7b, + 0xf6, 0xf3, 0xac, 0x2d, 0x26, 0xb8, 0x46, 0x86, 0xe5, 0x69, 0xd5, 0x8d, 0x99, + 0xc1, 0x38, 0x35, 0x97, 0xfa, 0xd8, 0x11, 0x93, 0xc4, 0xc1, 0xb1, 0x6e, 0x6a, + 0x90, 0xe2, 0xd5, 0x07, 0xcd, 0xfe, 0x6f, 0xbd, 0xaa, 0x86, 0x16, 0x3e, 0x9c, + 0xf5, 0xde, 0x31, 0x00, 0xfb, 0xca, 0x7e, 0x8d, 0xa0, 0x47, 0xb0, 0x90, 0x79, + 0x36, 0x2d, 0x77, 0x92, 0xde, 0xb3, 0xca, 0x9d, 0xc1, 0x56, 0x1b, 0x87, 0xc8, + 0x2e, 0x3c, 0xb9, 0x9e, 0xb5, 0x83, 0x73, 0x19, 0x58, 0x22, 0x16, 0xa3, 0x22, + 0x67, 0x74, 0xef, 0xa9, 0x0e, 0xfb, 0x7b, 0xfc, 0x79, 0xf4, 0x25, 0x64, 0x4e, + 0x4e, 0x98, 0xc2, 0xd7, 0xd8, 0x64, 0x2b, 0x9d, 0xb8, 0x2a, 0xa7, 0x39, 0xbf, + 0x2d, 0x71, 0xcc, 0x41, 0x17, 0x22, 0x7d, 0xb2, 0x27, 0xcf, 0x0a, 0x05, 0xad, + 0x9a, 0x95, 0x83, 0x2e, 0x23, 0xc9, 0x4f, 0x27, 0x1c, 0xa0, 0xe4, 0x69, 0x4f, + 0xac, 0x63, 0x22, 0x28, 0x2e, 0xba, 0xc6, 0x98, 0x6b, 0x8f, 0xdc, 0x8a, 0xd8, + 0x63, 0x08, 0x4f, 0xf1, 0x0f, 0xd1, 0x1e, 0x6a, 0x13, 0x31, 0x1f, 0xb7, 0x99, + 0xc7, 0x9c, 0x64, 0x1d, 0x9d, 0xa4, 0x3b, 0x33, 0xe7, 0xad, 0x01, 0x2e, 0x28, + 0x25, 0x53, 0x98, 0x78, 0x92, 0x62, 0x27, 0x5f, 0x11, 0x75, 0xbe, 0x84, 0x62, + 0xc0, 0x14, 0x91, 0xc4, 0xd8, 0x42, 0x40, 0x6d, 0x0e, 0xc4, 0x28, 0x2c, 0x95, + 0x26, 0x17, 0x4a, 0x09, 0x87, 0x8f, 0xe8, 0xfd, 0xde, 0x33, 0xa2, 0x96, 0x04, + 0xe5, 0xe5, 0xe7, 0xb2, 0xa0, 0x25, 0xd6, 0x65, 0x0b, 0x97, 0xdb, 0xb5, 0x2b, + 0xef, 0xb5, 0x9b, 0x1d, 0x30, 0xa5, 0x74, 0x33, 0xb0, 0xa3, 0x51, 0x47, 0x44, + 0x44, 0x09, 0x9d, 0xaa, 0x37, 0x10, 0x46, 0x61, 0x32, 0x60, 0xcf, 0x33, 0x54, + 0xcf, 0xcd, 0xad, 0xa6, 0x63, 0xec, 0xe8, 0x24, 0xff, 0xd7, 0xe4, 0x43, 0x93, + 0x88, 0x6a, 0x86, 0x16, 0x5d, 0xdd, 0xdf, 0x2b, 0x4c, 0x41, 0x77, 0x35, 0x54, + 0xc8, 0x69, 0x95, 0x26, 0x94, 0x08, 0xb1, 0x1e, 0x67, 0x37, 0xa4, 0xc4, 0x47, + 0x58, 0x6f, 0x69, 0x17, 0x34, 0x46, 0xd8, 0xe4, 0x8b, 0xf8, 0x4c, 0xbc, 0x00, + 0x0a, 0x80, 0x78, 0x99, 0x97, 0x3e, 0xb9, 0x3c, 0x5e, 0x81, 0x9a, 0xad, 0x66, + 0x94, 0x13, 0xf8, 0x38, 0x79, 0x33, 0xad, 0x15, 0x84, 0xaa, 0x35, 0xe4, 0x3f, + 0x4e, 0xcd, 0x1e, 0x2d, 0x04, 0x07, 0xc0, 0xb1, 0xb8, 0x99, 0x20, 0xff, 0xdf, + 0xdb, 0x9b, 0xea, 0x51, 0xac, 0x95, 0xb5, 0x57, 0xaf, 0x71, 0xb8, 0x9f, 0x90, + 0x3f, 0x5d, 0x98, 0x48, 0xf1, 0x4f, 0xcb, 0xeb, 0x18, 0x37, 0x57, 0x0f, 0x54, + 0x4d, 0x63, 0x59, 0xeb, 0x23, 0xfa, 0xf3, 0x8a, 0x08, 0x22, 0xda, 0x36, 0xce, + 0x42, 0x6c, 0x4a, 0x2f, 0xbe, 0xff, 0xeb, 0x0a, 0x8a, 0x2e, 0x29, 0x7a, 0x9d, + 0x19, 0xba, 0x15, 0x02, 0x45, 0x90, 0xe3, 0x32, 0x9d, 0x9f, 0xa9, 0x26, 0x1f, + 0x99, 0x38, 0xa4, 0x03, 0x2d, 0xd3, 0x46, 0x06, 0xc9, 0xcf, 0x9f, 0x3d, 0xd3, + 0x3e, 0x57, 0x6f, 0x05, 0xcd, 0x1d, 0xd6, 0x81, 0x1c, 0x62, 0x98, 0x75, 0x7d, + 0x77, 0xd9, 0xe8, 0x10, 0xab, 0xdb, 0x22, 0x6a, 0xfc, 0xaa, 0x43, 0x46, 0xa6, + 0x56, 0x0f, 0x89, 0x32, 0xb3, 0x18, 0x1f, 0xd3, 0x55, 0xd5, 0xd3, 0x91, 0x97, + 0x61, 0x83, 0xf8, 0xd9, 0x93, 0x88, 0x83, 0x96, 0x32, 0xd6, 0x35, 0x4f, 0x66, + 0x6d, 0x09, 0xd3, 0xe5, 0x62, 0x9e, 0xa1, 0x97, 0x37, 0x38, 0x86, 0x13, 0xd3, + 0x8a, 0x34, 0xfd, 0x0f, 0x6e, 0x50, 0xee, 0x5a, 0x0c, 0xc9, 0x67, 0x71, 0x77, + 0xf5, 0x00, 0x28, 0xc1, 0x41, 0x37, 0x81, 0x87, 0xbd, 0x28, 0x19, 0x40, 0x3f, + 0xc5, 0x34, 0xf8, 0x00, 0x76, 0xe9, 0x38, 0x0c, 0xb4, 0x96, 0x4d, 0x3b, 0x6b, + 0x45, 0x81, 0x9d, 0x3b, 0x8e, 0x9c, 0xaf, 0x54, 0xf0, 0x51, 0x85, 0x2d, 0x67, + 0x1b, 0xf8, 0xc1, 0xff, 0xde, 0x2d, 0x15, 0x10, 0x75, 0x64, 0x18, 0xcb, 0x48, + 0x10, 0x93, 0x6a, 0xa5, 0x7e, 0x69, 0x65, 0xd6, 0xfb, 0x65, 0x6a, 0x76, 0x0b, + 0x7f, 0x19, 0xad, 0xf9, 0x6c, 0x17, 0x34, 0x88, 0x55, 0x21, 0x93, 0xb1, 0x47, + 0xee, 0x58, 0x85, 0x80, 0x33, 0xda, 0xc7, 0xcd, 0x0e, 0xb2, 0x04, 0xc0, 0x64, + 0x90, 0xbb, 0xde, 0xdf, 0x5f, 0x75, 0x71, 0xac, 0xb2, 0xeb, 0xe7, 0x6a, 0xce, + 0xf3, 0xf2, 0xa0, 0x1e, 0xe9, 0x87, 0x48, 0x6d, 0xfe, 0x6c, 0x3f, 0x0a, 0x5e, + 0x23, 0x4c, 0x12, 0x72, 0x58, 0xf9, 0x7a, 0x28, 0xfb, 0x5d, 0x16, 0x4a, 0x81, + 0x76, 0xbe, 0x94, 0x6b, 0x80, 0x97, 0xd0, 0xe3, 0x17, 0x28, 0x7f, 0x33, 0xbf, + 0x9c, 0x16, 0xf9, 0xa5, 0x45, 0x40, 0x9c, 0xe2, 0x9b, 0x1f, 0x42, 0x73, 0x72, + 0x5f, 0xc0, 0xdf, 0x02, 0xa0, 0x4e, 0xba, 0xe1, 0x78, 0xb3, 0x41, 0x4f, 0xb0, + 0xa8, 0x2d, 0x50, 0xde, 0xb0, 0x9f, 0xcf, 0x4e, 0x6e, 0xe9, 0xd1, 0x80, 0xff, + 0x4f, 0x56, 0xff, 0x3b, 0xc1, 0xd3, 0x60, 0x1f, 0xc2, 0xdc, 0x90, 0xd8, 0x14, + 0xc3, 0x25, 0x6f, 0x49, 0x67, 0xd3, 0xa8, 0xd6, 0x4c, 0x83, 0xfe, 0xa3, 0x39, + 0xc5, 0x1f, 0x5a, 0x8e, 0x58, 0x01, 0xfb, 0xb9, 0x78, 0x35, 0x58, 0x1b, 0x60, + 0x24, 0x65, 0xde, 0xe0, 0x4b, 0x59, 0x22, 0xc2, 0x76, 0x1b, 0x54, 0x24, 0x5b, + 0xec, 0x0c, 0x9e, 0xef, 0x2d, 0xb9, 0x7d, 0x22, 0xb2, 0xb3, 0x55, 0x6c, 0xc9, + 0x69, 0xfb, 0xb1, 0x3d, 0x06, 0x50, 0x97, 0x65, 0xa5, 0x2b, 0x3f, 0xac, 0x54, + 0xb9, 0x3f, 0x42, 0x1b, 0xf0, 0x8e, 0x18, 0xd5, 0x2d, 0xdd, 0x52, 0xcc, 0x1c, + 0x8c, 0xa8, 0xad, 0xfa, 0xcc, 0xab, 0x7e, 0x5c, 0xc2, 0xf4, 0x57, 0x3f, 0xbb, + 0xf8, 0x23, 0x9b, 0xb0, 0xb8, 0xae, 0xdb, 0xf8, 0xda, 0xd1, 0x62, 0x82, 0xda, + 0x5c, 0x91, 0x25, 0xdb, 0xa1, 0xc0, 0x59, 0xd0, 0xdf, 0x8a, 0xbf, 0x62, 0x10, + 0x78, 0xf0, 0x2d, 0x6c, 0x4b, 0xc8, 0x6d, 0x40, 0x84, 0x5a, 0xc1, 0xd5, 0x97, + 0x10, 0xc4, 0x5f, 0x07, 0xd5, 0x85, 0xeb, 0x48, 0xb3, 0x2f, 0xc0, 0x16, 0x7b, + 0xa2, 0x56, 0xe7, 0x3c, 0xa3, 0xb9, 0x31, 0x1c, 0x62, 0xd1, 0x09, 0x49, 0x79, + 0x57, 0xd8, 0xdb, 0xe1, 0x0a, 0xa3, 0xe8, 0x66, 0xb4, 0x0c, 0x0b, 0xaa, 0x2b, + 0xc4, 0x92, 0xc1, 0x9a, 0xd1, 0xe6, 0x37, 0x2d, 0x96, 0x22, 0xbf, 0x16, 0x3f, + 0xbf, 0xfe, 0xae, 0xee, 0x79, 0x6a, 0x3c, 0xd9, 0xb6, 0xfb, 0xbf, 0xa4, 0xd7, + 0x92, 0xf3, 0x4d, 0x7f, 0xd6, 0xe7, 0x63, 0xcd, 0x58, 0x59, 0xdd, 0x26, 0x83, + 0x3d, 0x21, 0xd9, 0xbc, 0x54, 0x52, 0xbd, 0x19, 0x51, 0x5d, 0xff, 0x9f, 0x49, + 0x95, 0xb3, 0x5b, 0xc0, 0xc1, 0xf8, 0x76, 0xe6, 0xad, 0x11, 0xf2, 0x45, 0x2d, + 0xc9, 0xae, 0x85, 0xae, 0xc0, 0x1f, 0xc5, 0x6f, 0x8c, 0xbf, 0xda, 0x75, 0xa7, + 0x72, 0x7b, 0x75, 0xeb, 0xbd, 0x6b, 0xbf, 0xfb, 0x43, 0xb6, 0x3a, 0x3b, 0x1b, + 0x67, 0x1e, 0x40, 0xfe, 0xb0, 0xdb, 0x00, 0x29, 0x74, 0xa3, 0xc3, 0xb1, 0xa7, + 0x88, 0x56, 0x72, 0x31, 0xbf, 0x63, 0x99, 0xff, 0x89, 0x23, 0x69, 0x81, 0x14, + 0x9d, 0x42, 0x38, 0x02, 0xd2, 0x34, 0x1a, 0x3b, 0xed, 0xb9, 0xdd, 0xcb, 0xac, + 0x1f, 0xe7, 0xb6, 0x43, 0x5e, 0x14, 0x79, 0xc7, 0x2e, 0x70, 0x89, 0xb5, 0x1b, + 0xfe, 0x2f, 0xf3, 0x45, 0x85, 0x7d, 0xa9, 0xb5, 0x45, 0xe8, 0x8e, 0x32, 0x21, + 0xf3, 0xf5, 0xf7, 0x2d, 0x1e, 0x06, 0x9c, 0x9a, 0x85, 0xdd, 0x22, 0x36, 0xd3, + 0x90, 0x98, 0x95, 0x87, 0xbe, 0x00, 0x5c, 0xda, 0x16, 0xaf, 0x44, 0x08, 0xf3, + 0xab, 0x06, 0xa9, 0x16, 0xee, 0xeb, 0x9c, 0x95, 0x94, 0xb7, 0x04, 0x24, 0xa4, + 0xc1, 0xd1, 0x71, 0x29, 0x5b, 0x67, 0x63, 0xb2, 0x2f, 0x47, 0x12, 0xba, 0x7b, + 0xef, 0xf0, 0xff, 0x27, 0x88, 0x3a, 0xfa, 0xff, 0x26, 0x03, 0x4b, 0x89, 0x57, + 0x35, 0x70, 0x9c, 0xf9, 0x37, 0xbd, 0x22, 0x31, 0x89, 0x1e, 0x70, 0xeb, 0x27, + 0x71, 0xe9, 0x92, 0x7c, 0x97, 0xf8, 0x76, 0x4e, 0xb4, 0x8e, 0x91, 0x1d, 0x42, + 0x8e, 0xc8, 0xd8, 0x61, 0xb7, 0x08, 0xe8, 0x29, 0x8a, 0xcb, 0x62, 0x15, 0x51, + 0x45, 0x15, 0x5a, 0xe9, 0x5f, 0x0a, 0x1d, 0x15, 0x01, 0x03, 0x47, 0x53, 0x14, + 0x6e, 0x22, 0xd0, 0x5f, 0x58, 0x6d, 0x7f, 0x6b, 0x4f, 0xe1, 0x2d, 0xad, 0x9a, + 0x17, 0xf5, 0xdb, 0x70, 0xb1, 0xdb, 0x96, 0xb8, 0xd9, 0xa8, 0x3e, 0xda, 0xdc, + 0x96, 0x6c, 0x8a, 0x54, 0x66, 0xb6, 0x1f, 0xc9, 0x98, 0xc3, 0x1f, 0x10, 0x70, + 0xd9, 0xa5, 0xc9, 0xa6, 0xd2, 0x68, 0xd3, 0x04, 0xfe, 0x6b, 0x8f, 0xd3, 0xb4, + 0x01, 0x03, 0x48, 0x61, 0x1a, 0xbd, 0xcb, 0xd4, 0x9f, 0xe4, 0xf8, 0x5b, 0x62, + 0x3c, 0x78, 0x28, 0xc7, 0x13, 0x82, 0xe1, 0x03, 0x4e, 0xa6, 0x7b, 0xc8, 0xae, + 0x97, 0x40, 0x4b, 0x0c, 0x50, 0xb2, 0xa0, 0x4f, 0x55, 0x9e, 0x49, 0x95, 0x0a, + 0xfc, 0xb0, 0xef, 0x46, 0x2a, 0x2a, 0xe0, 0x24, 0xb0, 0xf0, 0x22, 0x4d, 0xfd, + 0x73, 0x68, 0x4b, 0x88, 0xc7, 0xfb, 0xe9, 0x2d, 0x02, 0xb6, 0x8f, 0x75, 0x9c, + 0x47, 0x52, 0x66, 0x3c, 0xd7, 0xb9, 0x7a, 0x14, 0x94, 0x36, 0x49, 0x30, 0x55, + 0x21, 0x32, 0x6b, 0xde, 0x08, 0x56, 0x30, 0x86, 0x46, 0x29, 0x29, 0x1b, 0xae, + 0x25, 0xff, 0x88, 0x22, 0xa1, 0x4c, 0x4b, 0x66, 0x6a, 0x92, 0x59, 0xad, 0x0d, + 0xc4, 0x2a, 0x82, 0x90, 0xac, 0x7b, 0xc7, 0xf5, 0x3a, 0x16, 0xf3, 0x79, 0xf7, + 0x58, 0xe5, 0xde, 0x75, 0x0f, 0x04, 0xfd, 0x7c, 0xad, 0x47, 0x70, 0x1c, 0x85, + 0x97, 0xf9, 0x78, 0x88, 0xbe, 0xa6, 0xfa, 0x0b, 0xf2, 0x99, 0x99, 0x56, 0xfb, + 0xfd, 0x0e, 0xe6, 0x8e, 0xc3, 0x6e, 0x46, 0x88, 0x80, 0x9a, 0xe2, 0x31, 0xeb, + 0x8b, 0xc4, 0x36, 0x9f, 0x5f, 0xe1, 0x57, 0x3f, 0x57, 0xe0, 0x99, 0xd9, 0xc0, + 0x99, 0x01, 0xbf, 0x39, 0xca, 0xac, 0x48, 0xdc, 0x11, 0x95, 0x6a, 0x8a, 0xe9, + 0x05, 0xea, 0xd8, 0x69, 0x54, 0x54, 0x7c, 0x44, 0x8a, 0xe4, 0x3d, 0x31, 0x5e, + 0x66, 0x9c, 0x42, 0x42, 0xda, 0x56, 0x59, 0x38, 0xf4, 0x17, 0xbf, 0x43, 0xce, + 0x7b, 0x2b, 0x30, 0xb1, 0xcd, 0x40, 0x18, 0x38, 0x8e, 0x1a, 0x91, 0x0f, 0x0f, + 0xc4, 0x1f, 0xb0, 0x87, 0x7a, 0x59, 0x25, 0xe4, 0x66, 0x81, 0x9d, 0x37, 0x5b, + 0x0a, 0x91, 0x2d, 0x4f, 0xe8, 0x43, 0xb7, 0x6e, 0xf6, 0xf2, 0x23, 0xf0, 0xf7, + 0xc8, 0x94, 0xf3, 0x8f, 0x7a, 0xb7, 0x80, 0xdf, 0xd7, 0x5f, 0x66, 0x9c, 0x8c, + 0x06, 0xcf, 0xfa, 0x43, 0xeb, 0x47, 0x56, 0x5a, 0x50, 0xe3, 0xb1, 0xfa, 0x45, + 0xad, 0x61, 0xce, 0x9a, 0x1c, 0x47, 0x27, 0xb7, 0xaa, 0xa5, 0x35, 0x62, 0xf5, + 0x23, 0xe7, 0x39, 0x52, 0xbb, 0xf3, 0x3d, 0x8a, 0x41, 0x04, 0x07, 0x8a, 0xde, + 0x3e, 0xaa, 0xa4, 0x96, 0x99, 0xa6, 0x9f, 0xdf, 0x1c, 0x5a, 0xc7, 0x73, 0x21, + 0x46, 0xee, 0x5e, 0x1d, 0x6b, 0x6c, 0xa9, 0xb9, 0x18, 0x0f, 0x96, 0x4c, 0xc9, + 0xd0, 0x87, 0x8a, 0xe1, 0x37, 0x35, 0x24, 0xd7, 0xd5, 0x10, 0xe5, 0x82, 0x27, + 0xdf, 0x6d, 0xe9, 0xd3, 0x0d, 0x27, 0x18, 0x67, 0x64, 0x01, 0x77, 0xb0, 0xf1, + 0x85, 0x6e, 0x28, 0xd5, 0xc8, 0xaf, 0xb0, 0x95, 0xef, 0x61, 0x84, 0xfe, 0xd6, + 0x51, 0x58, 0x90, 0x22, 0xee, 0xae, 0xa4, 0xc0, 0xce, 0x1f, 0xa6, 0xf0, 0x85, + 0x09, 0x2b, 0x04, 0x97, 0x94, 0x89, 0x17, 0x2b, 0x3e, 0xf8, 0x19, 0x4a, 0x79, + 0x8d, 0xf5, 0x72, 0x4d, 0x6b, 0x05, 0xf1, 0xae, 0x00, 0x00, 0x13, 0xa0, 0x8d, + 0x61, 0x2b, 0xca, 0x8a, 0x8c, 0x31, 0x44, 0x3c, 0x10, 0x34, 0x6d, 0xbf, 0x61, + 0xde, 0x84, 0x75, 0xc0, 0xbb, 0xec, 0x51, 0x04, 0xb4, 0x75, 0x56, 0xaf, 0x3d, + 0x51, 0x44, 0x58, 0xe2, 0x32, 0x1d, 0x14, 0x60, 0x71, 0x78, 0x9d, 0x23, 0x35, + 0x93, 0x4a, 0x68, 0x06, 0x14, 0xe8, 0x35, 0x62, 0xf8, 0x2d, 0xfd, 0x40, 0x5b, + 0x54, 0xa4, 0x5e, 0xb3, 0x2c, 0x16, 0x54, 0x48, 0xd4, 0xd5, 0xd6, 0x1c, 0xa2, + 0x85, 0x95, 0x85, 0x36, 0x9f, 0x53, 0xf1, 0xa1, 0x37, 0xe9, 0xe8, 0x2b, 0x67, + 0xb8, 0xfd, 0xaf, 0x01, 0xbd, 0xa5, 0x4a, 0x31, 0x73, 0x11, 0x89, 0x6a, 0xe1, + 0x02, 0x80, 0xa0, 0x32, 0x44, 0x0c, 0x42, 0x0a, 0x42, 0x1e, 0x94, 0x4d, 0x1e, + 0x95, 0x2b, 0x70, 0xd5, 0x82, 0x6c, 0xd3, 0xb0, 0x8b, 0x7d, 0xb9, 0x63, 0x0f, + 0xe4, 0xfd, 0x5f, 0x22, 0x12, 0x5d, 0xe8, 0x40, 0xfc, 0xc4, 0x0b, 0x98, 0x03, + 0x8a, 0xf1, 0x1d, 0x55, 0xbe, 0x25, 0x43, 0x25, 0x97, 0xb4, 0xb6, 0x5b, 0x9e, + 0xc1, 0xc7, 0xa8, 0xbb, 0xfd, 0x05, 0x2c, 0xbf, 0x7e, 0x1c, 0x17, 0x85, 0x31, + 0x49, 0x34, 0xb2, 0x62, 0xd5, 0x85, 0x37, 0x54, 0xf1, 0xf1, 0x77, 0x71, 0xcf, + 0xb7, 0x50, 0x30, 0x72, 0x65, 0x57, 0x53, 0xfa, 0x3f, 0x54, 0xec, 0xc5, 0x87, + 0xe9, 0xf8, 0x3b, 0x58, 0x19, 0x16, 0x09, 0x2d, 0xf2, 0x6e, 0x63, 0xe1, 0x89, + 0x94, 0xcb, 0x0d, 0xb9, 0x1a, 0x0b, 0xbd, 0xc7, 0xb6, 0x11, 0x9b, 0x32, 0x22, + 0x2a, 0xdf, 0x5e, 0x61, 0xd8, 0xd8, 0xae, 0x89, 0xda, 0xe4, 0x95, 0x4b, 0x54, + 0x81, 0x3b, 0xb3, 0x3f, 0x08, 0xd5, 0x62, 0xba, 0x51, 0x3f, 0xee, 0x1b, 0x09, + 0xc0, 0xfc, 0xd5, 0x16, 0x05, 0x54, 0x19, 0x47, 0x4d, 0xd7, 0xfd, 0xa0, 0x38, + 0xa8, 0x9c, 0x84, 0xea, 0x7b, 0x94, 0x68, 0x28, 0x7f, 0x0e, 0xb0, 0xc1, 0x0c, + 0x4b, 0x13, 0x25, 0x20, 0x19, 0x4d, 0x3d, 0x8d, 0x53, 0x51, 0xfc, 0x10, 0xd0, + 0x9c, 0x15, 0xc8, 0xcc, 0x10, 0x1a, 0xa1, 0x66, 0x3b, 0xbf, 0x17, 0xb8, 0x41, + 0x11, 0xf3, 0x8b, 0xb4, 0x39, 0xf0, 0x73, 0x53, 0xbd, 0xea, 0x35, 0x96, 0xd1, + 0x5e, 0x71, 0x3e, 0x1e, 0x2e, 0x7d, 0x3f, 0x1c, 0x38, 0x31, 0x35, 0xb4, 0x7f, + 0xa7, 0xf8, 0x1f, 0x46, 0xdf, 0x7a, 0x90, 0x2a, 0x40, 0x46, 0x99, 0xec, 0x91, + 0x2f, 0x56, 0x56, 0xc3, 0x5b, 0x85, 0x76, 0x3e, 0x4d, 0xe5, 0x83, 0xae, 0xca, + 0xa1, 0xdf, 0xd5, 0xd2, 0x67, 0x7d, 0x9c, 0x8f, 0xfe, 0xe8, 0x77, 0xf6, 0x3f, + 0x40, 0xa5, 0xca, 0x0d, 0x67, 0xf6, 0xe5, 0x54, 0x12, 0x47, 0x00, 0xf8, 0x05, + 0xaf, 0x87, 0x6a, 0xee, 0xde, 0x53, 0xaa, 0x8b, 0x0f, 0x8e, 0x56, 0x04, 0xa7, + 0x3c, 0x30, 0xcb, 0xd0, 0x9d, 0xad, 0x96, 0x3d, 0x6f, 0x8a, 0x5d, 0xcc, 0x40, + 0xde, 0xf4, 0x07, 0x97, 0x34, 0x21, 0x13, 0xba, 0x20, 0x6f, 0xae, 0x8e, 0xbe, + 0x4f, 0x3b, 0xc3, 0xca, 0xf6, 0x92, 0x59, 0xe4, 0x62, 0xef, 0xf9, 0xba, 0x8b, + 0x3f, 0x4b, 0xfa, 0xa1, 0x30, 0x0c, 0x26, 0x92, 0x5a, 0x87, + ], + script_code: Script(vec![0x63]), + transparent_input: None, + hash_type: 1, + amount: 1969273897303781, + consensus_branch_id: consensus::BranchId::Sapling, + sighash: [ + 0x63, 0xd1, 0x85, 0x34, 0xde, 0x5f, 0x2d, 0x1c, 0x9e, 0x16, 0x9b, 0x73, 0xf9, + 0xc7, 0x83, 0x71, 0x8a, 0xdb, 0xef, 0x5c, 0x8a, 0x7d, 0x55, 0xb5, 0xe7, 0xa3, + 0x7a, 0xff, 0xa1, 0xdd, 0x3f, 0xf3, + ], + }, + Test0243Vector { + tx: vec![ + 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0x0b, 0xbe, 0x32, 0xa5, + 0x98, 0xc2, 0x2a, 0xdf, 0xb4, 0x8c, 0xef, 0x72, 0xba, 0x5d, 0x42, 0x87, 0xc0, + 0xce, 0xfb, 0xac, 0xfd, 0x8c, 0xe1, 0x95, 0xb4, 0x96, 0x3c, 0x34, 0xa9, 0x4b, + 0xba, 0x7a, 0x17, 0x5d, 0xae, 0x4b, 0x04, 0x65, 0xac, 0x65, 0x63, 0x53, 0x70, + 0x89, 0x15, 0x09, 0x0f, 0x47, 0xa0, 0x68, 0xe2, 0x27, 0x43, 0x3f, 0x9e, 0x49, + 0xd3, 0xaa, 0x09, 0xe3, 0x56, 0xd8, 0xd6, 0x6d, 0x0c, 0x01, 0x21, 0xe9, 0x1a, + 0x3c, 0x4a, 0xa3, 0xf2, 0x7f, 0xa1, 0xb6, 0x33, 0x96, 0xe2, 0xb4, 0x1d, 0x09, + 0x00, 0x63, 0x53, 0x53, 0x00, 0xac, 0x53, 0xac, 0x51, 0x4e, 0x97, 0x05, 0x68, + 0x02, 0xda, 0x07, 0x1b, 0x97, 0x0d, 0x48, 0x07, 0x00, 0x01, 0x52, 0xa8, 0x44, + 0x55, 0x0b, 0xdc, 0x20, 0x02, 0x00, 0x07, 0x52, 0x52, 0x6a, 0x65, 0x52, 0x00, + 0x52, 0xd7, 0x03, 0x43, 0x02, 0x01, 0x1b, 0x9a, 0x07, 0x66, 0x20, 0xed, 0xc0, + 0x67, 0xff, 0x02, 0x00, 0x00, 0x03, 0x53, 0xe3, 0xb8, 0xa7, 0x1f, 0xac, 0xe1, + 0xc9, 0xf3, 0x77, 0x45, 0xed, 0x36, 0x88, 0x35, 0x29, 0x30, 0x4b, 0xfd, 0x5a, + 0x39, 0x0b, 0x37, 0xbc, 0x5a, 0x34, 0x45, 0x24, 0x1f, 0x03, 0xf6, 0x4a, 0x81, + 0x88, 0x20, 0xdf, 0xed, 0xdd, 0x75, 0x37, 0x51, 0x59, 0xfb, 0xd2, 0x1e, 0xca, + 0x98, 0x72, 0x10, 0x4f, 0x8d, 0x7b, 0x3c, 0x8c, 0x86, 0x97, 0x03, 0xa1, 0xe7, + 0x84, 0x8a, 0x5c, 0x94, 0x1e, 0x45, 0xa9, 0xc7, 0x94, 0x34, 0x46, 0xd0, 0xdc, + 0x96, 0x27, 0xcb, 0x31, 0xf8, 0x0e, 0x7a, 0xa5, 0x96, 0xd4, 0x82, 0x1d, 0xc9, + 0x9a, 0x7d, 0x77, 0x7c, 0xd5, 0x7e, 0x19, 0x48, 0x42, 0xa0, 0x23, 0x47, 0x1f, + 0x0f, 0x62, 0x88, 0xa1, 0x50, 0x64, 0x7b, 0x2a, 0xfe, 0x9d, 0xf7, 0xcc, 0xcf, + 0x01, 0xf5, 0xcd, 0xe5, 0xf0, 0x46, 0x80, 0xbb, 0xfe, 0xd8, 0x7f, 0x6c, 0xf4, + 0x29, 0xfb, 0x27, 0xad, 0x6b, 0xab, 0xe7, 0x91, 0x76, 0x66, 0x11, 0xcf, 0x5b, + 0xc2, 0x0e, 0x48, 0xbe, 0xf1, 0x19, 0x25, 0x9b, 0x9b, 0x8a, 0x0e, 0x39, 0xc3, + 0xdf, 0x28, 0xcb, 0x95, 0x82, 0xea, 0x33, 0x86, 0x01, 0xcd, 0xc4, 0x81, 0xb3, + 0x2f, 0xb8, 0x2a, 0xde, 0xeb, 0xb3, 0xda, 0xde, 0x25, 0xd1, 0xa3, 0xdf, 0x20, + 0xc3, 0x7e, 0x71, 0x25, 0x06, 0xb5, 0xd9, 0x96, 0xc4, 0x9a, 0x9f, 0x0f, 0x30, + 0xdd, 0xcb, 0x91, 0xfe, 0x90, 0x04, 0xe1, 0xe8, 0x32, 0x94, 0xa6, 0xc9, 0x20, + 0x3d, 0x94, 0xe8, 0xdc, 0x2c, 0xbb, 0x44, 0x9d, 0xe4, 0x15, 0x50, 0x32, 0x60, + 0x4e, 0x47, 0x99, 0x70, 0x16, 0xb3, 0x04, 0xfd, 0x43, 0x7d, 0x82, 0x35, 0x04, + 0x5e, 0x25, 0x5a, 0x19, 0xb7, 0x43, 0xa0, 0xa9, 0xf2, 0xe3, 0x36, 0xb4, 0x4c, + 0xae, 0x30, 0x7b, 0xb3, 0x98, 0x7b, 0xd3, 0xe4, 0xe7, 0x77, 0xfb, 0xb3, 0x4c, + 0x0a, 0xb8, 0xcc, 0x3d, 0x67, 0x46, 0x6c, 0x0a, 0x88, 0xdd, 0x4c, 0xca, 0xd1, + 0x8a, 0x07, 0xa8, 0xd1, 0x06, 0x8d, 0xf5, 0xb6, 0x29, 0xe5, 0x71, 0x8d, 0x0f, + 0x6d, 0xf5, 0xc9, 0x57, 0xcf, 0x71, 0xbb, 0x00, 0xa5, 0x17, 0x8f, 0x17, 0x5c, + 0xac, 0xa9, 0x44, 0xe6, 0x35, 0xc5, 0x15, 0x9f, 0x73, 0x8e, 0x24, 0x02, 0xa2, + 0xd2, 0x1a, 0xa0, 0x81, 0xe1, 0x0e, 0x45, 0x6a, 0xfb, 0x00, 0xb9, 0xf6, 0x24, + 0x16, 0xc8, 0xb9, 0xc0, 0xf7, 0x22, 0x8f, 0x51, 0x07, 0x29, 0xe0, 0xbe, 0x3f, + 0x30, 0x53, 0x13, 0xd7, 0x7f, 0x73, 0x79, 0xdc, 0x2a, 0xf2, 0x48, 0x69, 0xc6, + 0xc7, 0x4e, 0xe4, 0x47, 0x14, 0x98, 0x86, 0x1d, 0x19, 0x2f, 0x0f, 0xf0, 0xf5, + 0x08, 0x28, 0x5d, 0xab, 0x6b, 0x6a, 0x36, 0xcc, 0xf7, 0xd1, 0x22, 0x56, 0xcc, + 0x76, 0xb9, 0x55, 0x03, 0x72, 0x0a, 0xc6, 0x72, 0xd0, 0x82, 0x68, 0xd2, 0xcf, + 0x77, 0x73, 0xb6, 0xba, 0x2a, 0x5f, 0x66, 0x48, 0x47, 0xbf, 0x70, 0x7f, 0x2f, + 0xc1, 0x0c, 0x98, 0xf2, 0xf0, 0x06, 0xec, 0x22, 0xcc, 0xb5, 0xa8, 0xc8, 0xb7, + 0xc4, 0x0c, 0x7c, 0x2d, 0x49, 0xa6, 0x63, 0x9b, 0x9f, 0x2c, 0xe3, 0x3c, 0x25, + 0xc0, 0x4b, 0xc4, 0x61, 0xe7, 0x44, 0xdf, 0xa5, 0x36, 0xb0, 0x0d, 0x94, 0xba, + 0xdd, 0xf4, 0xf4, 0xd1, 0x40, 0x44, 0xc6, 0x95, 0xa3, 0x38, 0x81, 0x47, 0x7d, + 0xf1, 0x24, 0xf0, 0xfc, 0xf2, 0x06, 0xa9, 0xfb, 0x2e, 0x65, 0xe3, 0x04, 0xcd, + 0xbf, 0x0c, 0x4d, 0x23, 0x90, 0x17, 0x0c, 0x13, 0x0a, 0xb8, 0x49, 0xc2, 0xf2, + 0x2b, 0x5c, 0xdd, 0x39, 0x21, 0x64, 0x0c, 0x8c, 0xf1, 0x97, 0x6a, 0xe1, 0x01, + 0x0b, 0x0d, 0xfd, 0x9c, 0xb2, 0x54, 0x3e, 0x45, 0xf9, 0x97, 0x49, 0xcc, 0x4d, + 0x61, 0xf2, 0xe8, 0xaa, 0xbf, 0xe9, 0x8b, 0xd9, 0x05, 0xfa, 0x39, 0x95, 0x1b, + 0x33, 0xea, 0x76, 0x9c, 0x45, 0xab, 0x95, 0x31, 0xc5, 0x72, 0x09, 0x86, 0x2a, + 0xd1, 0x2f, 0xd7, 0x6b, 0xa4, 0x80, 0x7e, 0x65, 0x41, 0x7b, 0x6c, 0xd1, 0x2f, + 0xa8, 0xec, 0x91, 0x6f, 0x01, 0x3e, 0xbb, 0x87, 0x06, 0xa9, 0x6e, 0xff, 0xed, + 0xa0, 0x6c, 0x4b, 0xe2, 0x4b, 0x04, 0x84, 0x63, 0x92, 0xe9, 0xd1, 0xe6, 0x93, + 0x0e, 0xae, 0x01, 0xfa, 0x21, 0xfb, 0xd7, 0x00, 0x58, 0x3f, 0xb5, 0x98, 0xb9, + 0x2c, 0x8f, 0x4e, 0xb8, 0xa6, 0x1a, 0xa6, 0x23, 0x5d, 0xb6, 0x0f, 0x28, 0x41, + 0xcf, 0x3a, 0x1c, 0x6a, 0xb5, 0x4c, 0x67, 0x06, 0x68, 0x44, 0x71, 0x1d, 0x09, + 0x1e, 0xb9, 0x31, 0xa1, 0xbd, 0x62, 0x81, 0xae, 0xdf, 0x2a, 0x0e, 0x8f, 0xab, + 0x18, 0x81, 0x72, 0x02, 0xa9, 0xbe, 0x06, 0x40, 0x2e, 0xd9, 0xcc, 0x72, 0x0c, + 0x16, 0xbf, 0xe8, 0x81, 0xe4, 0xdf, 0x42, 0x55, 0xe8, 0x7a, 0xfb, 0x7f, 0xc6, + 0x2f, 0x38, 0x11, 0x6b, 0xbe, 0x03, 0xcd, 0x8a, 0x3c, 0xb1, 0x1a, 0x27, 0xd5, + 0x68, 0x41, 0x47, 0x82, 0xf4, 0x7b, 0x1a, 0x44, 0xc9, 0x7c, 0x68, 0x04, 0x67, + 0x69, 0x4b, 0xc9, 0x70, 0x9d, 0x32, 0x91, 0x6c, 0x97, 0xe8, 0x00, 0x6c, 0xbb, + 0x07, 0xba, 0x0e, 0x41, 0x80, 0xa3, 0x73, 0x80, 0x38, 0xc3, 0x74, 0xc4, 0xcc, + 0xe8, 0xf3, 0x29, 0x59, 0xaf, 0xb2, 0x5f, 0x30, 0x3f, 0x58, 0x15, 0xc4, 0x53, + 0x31, 0x24, 0xac, 0xf9, 0xd1, 0x89, 0x40, 0xe7, 0x75, 0x22, 0xac, 0x5d, 0xc4, + 0xb9, 0x57, 0x0a, 0xae, 0x8f, 0x47, 0xb7, 0xf5, 0x7f, 0xd8, 0x76, 0x7b, 0xea, + 0x1a, 0x24, 0xae, 0x7b, 0xed, 0x65, 0xb4, 0xaf, 0xdc, 0x8f, 0x12, 0x78, 0xc3, + 0x0e, 0x2d, 0xb9, 0x8f, 0xd1, 0x72, 0x73, 0x0a, 0xc6, 0xbb, 0xed, 0x4f, 0x11, + 0x27, 0xcd, 0x32, 0xb0, 0x4a, 0x95, 0xb2, 0x05, 0x52, 0x6c, 0xfc, 0xb4, 0xc4, + 0xe1, 0xcc, 0x95, 0x51, 0x75, 0xb3, 0xe8, 0xde, 0x1f, 0x5d, 0x81, 0xb1, 0x86, + 0x69, 0x69, 0x23, 0x50, 0xaa, 0xa1, 0xa1, 0xd7, 0x97, 0x61, 0x75, 0x82, 0xe5, + 0x4d, 0x7a, 0x5b, 0x57, 0xa6, 0x83, 0xb3, 0x2f, 0xb1, 0x09, 0x80, 0x62, 0xda, + 0xd7, 0xb0, 0xc2, 0xeb, 0x51, 0x8f, 0x68, 0x62, 0xe8, 0x3d, 0xb2, 0x5e, 0x3d, + 0xba, 0xf7, 0xae, 0xd5, 0x04, 0xde, 0x93, 0x2a, 0xcb, 0x99, 0xd7, 0x35, 0x99, + 0x2c, 0xe6, 0x2b, 0xae, 0x9e, 0xf8, 0x93, 0xff, 0x6a, 0xcc, 0x0f, 0xfc, 0xf8, + 0xe3, 0x48, 0x3e, 0x14, 0x6b, 0x9d, 0x49, 0xdd, 0x8c, 0x78, 0x35, 0xf4, 0x3a, + 0x37, 0xdc, 0xa0, 0x78, 0x7e, 0x3e, 0xc9, 0xf6, 0x60, 0x52, 0x23, 0xd5, 0xba, + 0x7a, 0xe0, 0xab, 0x90, 0x25, 0xb7, 0x3b, 0xc0, 0x3f, 0x7f, 0xac, 0x36, 0xc0, + 0x09, 0xa5, 0x6d, 0x4d, 0x95, 0xd1, 0xe8, 0x1d, 0x3b, 0x3e, 0xbc, 0xa7, 0xe5, + 0x4c, 0xc1, 0xa1, 0x2d, 0x12, 0x7b, 0x57, 0xc8, 0x13, 0x89, 0x76, 0xe7, 0x91, + 0x01, 0x3b, 0x01, 0x5f, 0x06, 0xa6, 0x24, 0xf5, 0x21, 0xb6, 0xee, 0x04, 0xec, + 0x98, 0x08, 0x93, 0xc7, 0xe5, 0xe0, 0x1a, 0x33, 0x62, 0x03, 0x59, 0x40, 0x94, + 0xf8, 0x28, 0x33, 0xd7, 0x44, 0x27, 0x88, 0x00, 0x84, 0xd3, 0x58, 0x63, 0xc8, + 0xe7, 0xeb, 0xb5, 0xc9, 0xee, 0xd9, 0x8e, 0x72, 0x57, 0x2e, 0xc4, 0x0c, 0x79, + 0xb2, 0x66, 0x23, 0xb5, 0x80, 0x22, 0xf4, 0x89, 0xb0, 0x89, 0x3d, 0x88, 0xbe, + 0x63, 0xf3, 0xf8, 0xc0, 0xd2, 0x32, 0x49, 0xeb, 0xcd, 0xe1, 0x3d, 0xb9, 0x31, + 0x29, 0x41, 0xc3, 0x6c, 0x1d, 0x1c, 0xbc, 0xab, 0xac, 0x0c, 0x78, 0xcb, 0x3b, + 0x19, 0x12, 0xdb, 0x0d, 0xcb, 0xfe, 0x18, 0x93, 0xd9, 0xb5, 0x1b, 0xe4, 0xaf, + 0x1d, 0x00, 0x0b, 0xac, 0x1a, 0xd0, 0xa3, 0xae, 0x2c, 0xe1, 0xe7, 0x32, 0x25, + 0xfb, 0x11, 0x4d, 0x05, 0xaf, 0x4c, 0xef, 0xc0, 0x6e, 0x87, 0x5f, 0x07, 0x4f, + 0xfe, 0xae, 0x0c, 0xba, 0x7d, 0xa3, 0xa5, 0x16, 0xc1, 0x73, 0xbe, 0x1c, 0x51, + 0x33, 0x23, 0xe1, 0x19, 0xf6, 0x35, 0xe8, 0x20, 0x9a, 0x07, 0x4b, 0x21, 0x6b, + 0x70, 0x23, 0xfa, 0xdc, 0x2d, 0x25, 0x94, 0x9c, 0x90, 0x03, 0x7e, 0x71, 0xe3, + 0xe5, 0x50, 0x72, 0x6d, 0x21, 0x0a, 0x2c, 0x68, 0x83, 0x42, 0xe5, 0x24, 0x40, + 0x63, 0x5e, 0x9c, 0xc1, 0x4a, 0xfe, 0x10, 0x10, 0x26, 0x21, 0xa9, 0xc9, 0xac, + 0xcb, 0x78, 0x2e, 0x9e, 0x4a, 0x5f, 0xa8, 0x7f, 0x0a, 0x95, 0x6f, 0x5b, 0x85, + 0x50, 0x99, 0x60, 0x28, 0x5c, 0x22, 0x62, 0x7c, 0x59, 0x48, 0x3a, 0x5a, 0x4c, + 0x28, 0xcc, 0xe4, 0xb1, 0x56, 0xe5, 0x51, 0x40, 0x6a, 0x7e, 0xe8, 0x35, 0x56, + 0x56, 0xa2, 0x1e, 0x43, 0xe3, 0x8c, 0xe1, 0x29, 0xfd, 0xad, 0xb7, 0x59, 0xed, + 0xdf, 0xa0, 0x8f, 0x00, 0xfc, 0x8e, 0x56, 0x7c, 0xef, 0x93, 0xc6, 0x79, 0x2d, + 0x01, 0xdf, 0x05, 0xe6, 0xd5, 0x80, 0xf4, 0xd5, 0xd4, 0x8d, 0xf0, 0x42, 0x45, + 0x1a, 0x33, 0x59, 0x0d, 0x3e, 0x8c, 0xf4, 0x9b, 0x26, 0x27, 0x21, 0x8f, 0x0c, + 0x29, 0x2f, 0xa6, 0x6a, 0xda, 0x94, 0x5f, 0xa5, 0x5b, 0xb2, 0x35, 0x48, 0xe3, + 0x3a, 0x83, 0xa5, 0x62, 0x95, 0x7a, 0x31, 0x49, 0xa9, 0x93, 0xcc, 0x47, 0x23, + 0x62, 0x29, 0x87, 0x36, 0xa8, 0xb7, 0x78, 0xd9, 0x7c, 0xe4, 0x23, 0x01, 0x3d, + 0x64, 0xb3, 0x2c, 0xd1, 0x72, 0xef, 0xa5, 0x51, 0xbf, 0x7f, 0x36, 0x8f, 0x04, + 0xbd, 0xae, 0xc6, 0x09, 0x1a, 0x30, 0x04, 0xa7, 0x57, 0x59, 0x8b, 0x80, 0x1d, + 0xcf, 0x67, 0x5c, 0xb8, 0x3e, 0x43, 0xa5, 0x3a, 0xe8, 0xb2, 0x54, 0xd3, 0x33, + 0xbc, 0xda, 0x20, 0xd4, 0x81, 0x7d, 0x34, 0x77, 0xab, 0xfb, 0xa2, 0x5b, 0xb8, + 0x3d, 0xf5, 0x94, 0x9c, 0x12, 0x6f, 0x14, 0x9b, 0x1d, 0x99, 0x34, 0x1e, 0x4e, + 0x6f, 0x91, 0x20, 0xf4, 0xd4, 0x1e, 0x62, 0x91, 0x85, 0x00, 0x2c, 0x72, 0xc0, + 0x12, 0xc4, 0x14, 0xd2, 0x38, 0x2a, 0x6d, 0x47, 0xc7, 0xb3, 0xde, 0xab, 0xa7, + 0x70, 0xc4, 0x00, 0xca, 0x96, 0xb2, 0x81, 0x4f, 0x6b, 0x26, 0xc3, 0xef, 0x17, + 0x42, 0x9f, 0x1a, 0x98, 0xc8, 0x5d, 0x83, 0xdb, 0x20, 0xef, 0xad, 0x48, 0xbe, + 0x89, 0x96, 0xfb, 0x1b, 0xff, 0x59, 0x1e, 0xff, 0xf3, 0x60, 0xfe, 0x11, 0x99, + 0x05, 0x6c, 0x56, 0xe5, 0xfe, 0xec, 0x61, 0xa7, 0xb8, 0xb9, 0xf6, 0x99, 0xd6, + 0x01, 0x2c, 0x28, 0x49, 0x23, 0x2f, 0x32, 0x9f, 0xef, 0x95, 0xc7, 0xaf, 0x37, + 0x00, 0x98, 0xff, 0xe4, 0x91, 0x8e, 0x0c, 0xa1, 0xdf, 0x47, 0xf2, 0x75, 0x86, + 0x7b, 0x73, 0x9e, 0x0a, 0x51, 0x4d, 0x32, 0x09, 0x32, 0x5e, 0x21, 0x70, 0x45, + 0x92, 0x7b, 0x47, 0x9c, 0x1c, 0xe2, 0xe5, 0xd5, 0x4f, 0x25, 0x48, 0x8c, 0xad, + 0x15, 0x13, 0xe3, 0xf4, 0x4a, 0x21, 0x26, 0x6c, 0xfd, 0x84, 0x16, 0x33, 0x32, + 0x7d, 0xee, 0x6c, 0xf8, 0x10, 0xfb, 0xf7, 0x39, 0x3e, 0x31, 0x7d, 0x9e, 0x53, + 0xd1, 0xbe, 0x1d, 0x5a, 0xe7, 0x83, 0x9b, 0x66, 0xb9, 0x43, 0xb9, 0xed, 0x18, + 0xf2, 0xc5, 0x30, 0xe9, 0x75, 0x42, 0x23, 0x32, 0xc3, 0x43, 0x9c, 0xce, 0x49, + 0xa2, 0x9f, 0x2a, 0x33, 0x6a, 0x48, 0x51, 0x26, 0x3c, 0x5e, 0x9b, 0xd1, 0x3d, + 0x73, 0x11, 0x09, 0xe8, 0x44, 0xb7, 0xf8, 0xc3, 0x92, 0xa5, 0xc1, 0xdc, 0xaa, + 0x2a, 0xe5, 0xf5, 0x0f, 0xf6, 0x3f, 0xab, 0x97, 0x65, 0xe0, 0x16, 0x70, 0x2c, + 0x35, 0xa6, 0x7c, 0xd7, 0x36, 0x4d, 0x3f, 0xab, 0x55, 0x2f, 0xb3, 0x49, 0xe3, + 0x5c, 0x15, 0xc5, 0x02, 0x50, 0x45, 0x3f, 0xd1, 0x8f, 0x7b, 0x85, 0x59, 0x92, + 0x63, 0x2e, 0x2c, 0x76, 0xc0, 0xfb, 0xf1, 0xef, 0x96, 0x3e, 0xa8, 0x0e, 0x32, + 0x23, 0xde, 0x32, 0x77, 0xbc, 0x55, 0x92, 0x51, 0x72, 0x58, 0x29, 0xec, 0x03, + 0xf2, 0x13, 0xba, 0x89, 0x55, 0xca, 0xb2, 0x82, 0x2f, 0xf2, 0x1a, 0x9b, 0x0a, + 0x49, 0x04, 0xd6, 0x68, 0xfc, 0xd7, 0x72, 0x24, 0xbd, 0xe3, 0xdd, 0x01, 0xf6, + 0xff, 0xc4, 0x82, 0x8f, 0x6b, 0x64, 0x23, 0x0b, 0x35, 0xc6, 0xa0, 0x49, 0x87, + 0x34, 0x94, 0x27, 0x6e, 0xa1, 0xd7, 0xed, 0x5e, 0x92, 0xcb, 0x4f, 0x90, 0xba, + 0x83, 0xa9, 0xe4, 0x96, 0x01, 0xb1, 0x94, 0x04, 0x2f, 0x29, 0x00, 0xd9, 0x9d, + 0x31, 0x2d, 0x7b, 0x70, 0x50, 0x8c, 0xf1, 0x76, 0x06, 0x6d, 0x15, 0x4d, 0xbe, + 0x96, 0xef, 0x9d, 0x43, 0x67, 0xe4, 0xc8, 0x40, 0xe4, 0xa1, 0x7b, 0x5e, 0x51, + 0x22, 0xe8, 0xeb, 0xe2, 0x15, 0x8a, 0x3c, 0x5f, 0x4c, 0xba, 0xe2, 0x1e, 0xa3, + 0xfa, 0x1a, 0xe6, 0xc2, 0x5a, 0x94, 0x62, 0xeb, 0xcb, 0xb0, 0xfd, 0x5f, 0x14, + 0x55, 0x4b, 0xc9, 0x77, 0x47, 0xc3, 0x3e, 0x34, 0xda, 0x90, 0xc8, 0x16, 0xd8, + 0xd0, 0xd5, 0x0b, 0xfe, 0x37, 0x61, 0x8c, 0x58, 0x12, 0x89, 0x14, 0x84, 0xfa, + 0x25, 0x93, 0x22, 0xc1, 0x50, 0x92, 0xd4, 0x15, 0x5d, 0x86, 0x96, 0xd6, 0xf1, + 0x2f, 0x24, 0xfd, 0x36, 0x44, 0x96, 0xb3, 0xbe, 0x08, 0x71, 0xca, 0x3d, 0xd9, + 0x62, 0x53, 0x48, 0xa6, 0x14, 0xb5, 0x9b, 0xde, 0x45, 0x88, 0x56, 0x49, 0xba, + 0xe3, 0x6d, 0xe3, 0x4d, 0xef, 0x8f, 0xce, 0xc8, 0x53, 0x43, 0x47, 0x5d, 0x97, + 0x6a, 0xe1, 0xe9, 0xb2, 0x78, 0x29, 0xce, 0x2a, 0xc5, 0xef, 0xd0, 0xb3, 0x99, + 0xa8, 0xb4, 0x48, 0xbe, 0x65, 0x04, 0x29, 0x4e, 0xe6, 0xb3, 0xc1, 0xc6, 0xa5, + 0x34, 0x2d, 0x7c, 0x01, 0xae, 0x9d, 0x8a, 0xd3, 0x07, 0x0c, 0x2b, 0x1a, 0x91, + 0x57, 0x3a, 0xf5, 0xe0, 0xc5, 0xe4, 0xcb, 0xbf, 0x4a, 0xcd, 0xc6, 0xb5, 0x4c, + 0x92, 0x72, 0x20, 0x0d, 0x99, 0x70, 0x25, 0x0c, 0x17, 0xc1, 0x03, 0x6f, 0x06, + 0x08, 0x5c, 0x41, 0x85, 0x8e, 0xd3, 0xa0, 0xc4, 0x81, 0x50, 0xbc, 0x69, 0x7e, + 0x4a, 0x69, 0x5f, 0xef, 0x33, 0x5f, 0x7a, 0xd0, 0x7e, 0x1a, 0x46, 0xdc, 0x76, + 0x7f, 0xf8, 0x22, 0xdb, 0x70, 0xe6, 0x66, 0x90, 0x80, 0xb9, 0x81, 0x6b, 0x22, + 0x32, 0xc8, 0x1a, 0x4c, 0x66, 0xcc, 0x58, 0x6a, 0xbf, 0xe1, 0xea, 0xa8, 0xca, + 0x6c, 0xf4, 0x1f, 0xc3, 0x0e, 0xb8, 0xdc, 0x57, 0xc3, 0x7a, 0x3c, 0x39, 0xc5, + 0x9c, 0x94, 0x23, 0x2d, 0xf9, 0xd3, 0x88, 0xdb, 0xfa, 0x35, 0xc2, 0xcd, 0x5c, + 0x75, 0xf3, 0x28, 0xe9, 0xfe, 0xa7, 0x8f, 0x65, 0x56, 0x8f, 0x2b, 0xb9, 0x34, + 0xc8, 0x2c, 0x41, 0x42, 0xda, 0x69, 0xd1, 0x2c, 0xa7, 0xde, 0x9a, 0x7d, 0xf7, + 0x06, 0x40, 0x0e, 0xc7, 0x98, 0x78, 0xd8, 0x68, 0xe1, 0x7e, 0x8f, 0x71, 0xea, + 0x31, 0x49, 0x5a, 0x8b, 0xae, 0x7b, 0xdc, 0x2e, 0x48, 0xb5, 0x11, 0x87, 0x71, + 0xc2, 0xfc, 0xa0, 0x78, 0xcc, 0xa1, 0xfc, 0xe0, 0xd7, 0xef, 0x0a, 0xf3, 0x47, + 0x8c, 0xf3, 0x6f, 0x69, 0xe8, 0x5a, 0x41, 0xdd, 0x29, 0xb4, 0x29, 0x4a, 0x65, + 0xd3, 0xe0, 0x55, 0xff, 0x71, 0x8d, 0xd9, 0xdc, 0x8c, 0x75, 0xe7, 0xe5, 0xb2, + 0xef, 0xe4, 0x42, 0x63, 0x73, 0x71, 0xb7, 0xc4, 0x8f, 0x6e, 0xe9, 0x9e, 0x3e, + 0xa3, 0x8a, 0x4b, 0x0f, 0x2f, 0x67, 0xfc, 0x2b, 0x90, 0x8c, 0xda, 0x65, 0x7e, + 0xae, 0x75, 0x4e, 0x03, 0x7e, 0x26, 0x2e, 0x9a, 0x9f, 0x9b, 0xd7, 0xec, 0x42, + 0x67, 0xed, 0x8e, 0x96, 0x93, 0x0e, 0x10, 0x84, 0x78, 0x3c, 0x37, 0xd6, 0xf9, + 0xdd, 0x15, 0xfd, 0x29, 0xf4, 0xcc, 0x47, 0x7e, 0x66, 0xf1, 0x30, 0xd6, 0x30, + 0x43, 0x0d, 0xcc, 0x01, 0x04, 0x89, 0x9b, 0x4f, 0x9f, 0x46, 0xeb, 0x09, 0x0e, + 0xf7, 0xfc, 0x90, 0xb4, 0x79, 0xab, 0xf6, 0x1f, 0x93, 0x95, 0x5e, 0xe0, 0x0e, + 0x6a, 0x18, 0x48, 0xf1, 0xab, 0x14, 0xad, 0x33, 0x4f, 0x2b, 0x68, 0x03, 0x58, + 0x08, 0xcd, 0xf1, 0xbb, 0x9e, 0x9d, 0x9a, 0x81, 0x6b, 0xaf, 0x72, 0x8a, 0x95, + 0x5b, 0x96, 0x0b, 0x77, 0x01, 0xfa, 0x62, 0x66, 0x87, 0xdc, 0x3c, 0x9c, 0xba, + 0x64, 0x63, 0x37, 0xb5, 0x3e, 0x29, 0x81, 0x6e, 0x94, 0x82, 0xdd, 0xf5, 0x57, + 0x8a, 0x87, 0x68, 0xaa, 0xe4, 0x77, 0xfc, 0xe4, 0x10, 0xac, 0x2d, 0x5d, 0xe6, + 0x09, 0x58, 0x61, 0xc1, 0x11, 0xd7, 0xfe, 0xb3, 0xe6, 0xbb, 0x4f, 0xbb, 0x5a, + 0x54, 0x95, 0x54, 0x95, 0x97, 0x27, 0x98, 0x35, 0x0a, 0x25, 0x3f, 0x05, 0xf6, + 0x6c, 0x2e, 0xcf, 0xcb, 0xc0, 0xed, 0x43, 0xf5, 0xec, 0x2e, 0x6d, 0x8d, 0xba, + 0x15, 0xa5, 0x12, 0x54, 0xd9, 0x7b, 0x18, 0x21, 0x10, 0x7c, 0x07, 0xdd, 0x9a, + 0x16, 0xef, 0x84, 0x06, 0xf9, 0x43, 0xe2, 0x82, 0xb9, 0x5d, 0x4b, 0x36, 0x25, + 0x30, 0xc9, 0x13, 0xd6, 0xba, 0x42, 0x1d, 0xf6, 0x02, 0x7d, 0xe5, 0xaf, 0x1e, + 0x47, 0x45, 0xd5, 0x86, 0x81, 0x06, 0x95, 0x4b, 0xe6, 0xc1, 0x96, 0x27, 0x80, + 0xa2, 0x94, 0x10, 0x72, 0xe9, 0x51, 0x31, 0xb1, 0x67, 0x9d, 0xf0, 0x63, 0x76, + 0x25, 0x04, 0x2c, 0x37, 0xd4, 0x8f, 0xfb, 0x15, 0x2e, 0x5e, 0xbc, 0x18, 0x5c, + 0x8a, 0x2b, 0x7d, 0x43, 0x85, 0xf1, 0xc9, 0x5a, 0xf9, 0x37, 0xdf, 0x78, 0xdf, + 0xd8, 0x75, 0x7f, 0xab, 0x43, 0x49, 0x68, 0xb0, 0xb5, 0x7c, 0x66, 0x57, 0x44, + 0x68, 0xf1, 0x60, 0xb4, 0x47, 0xac, 0x82, 0x21, 0xe5, 0x06, 0x06, 0x76, 0xa8, + 0x42, 0xa1, 0xc6, 0xb7, 0x17, 0x2d, 0xd3, 0x34, 0x0f, 0x76, 0x40, 0x70, 0xab, + 0x1f, 0xe0, 0x91, 0xc5, 0xc7, 0x4c, 0x95, 0xa5, 0xdc, 0x04, 0x33, 0x90, 0x72, + 0x3a, 0x4c, 0x12, 0x7d, 0xa1, 0x4c, 0xdd, 0xe1, 0xdc, 0x26, 0x75, 0xa6, 0x23, + 0x40, 0xb3, 0xe6, 0xaf, 0xd0, 0x52, 0x2a, 0x31, 0xde, 0x26, 0xe7, 0xd1, 0xec, + 0x3a, 0x9c, 0x8a, 0x09, 0x1f, 0xfd, 0xc7, 0x5b, 0x7e, 0xcf, 0xdc, 0x7c, 0x12, + 0x99, 0x5a, 0x5e, 0x37, 0xce, 0x34, 0x88, 0xbd, 0x29, 0xf8, 0x62, 0x9d, 0x68, + 0xf6, 0x96, 0x49, 0x24, 0x48, 0xdd, 0x52, 0x66, 0x97, 0x47, 0x6d, 0xc0, 0x61, + 0x34, 0x6e, 0xbe, 0x3f, 0x67, 0x72, 0x17, 0xff, 0x9c, 0x60, 0xef, 0xce, 0x94, + 0x3a, 0xf2, 0x8d, 0xfd, 0x3f, 0x9e, 0x59, 0x69, 0x25, 0x98, 0xa6, 0x04, 0x7c, + 0x23, 0xc4, 0xc0, 0x14, 0x00, 0xf1, 0xab, 0x57, 0x30, 0xea, 0xc0, 0xae, 0x8d, + 0x58, 0x43, 0xd5, 0x05, 0x1c, 0x37, 0x62, 0x40, 0x17, 0x2a, 0xf2, 0x18, 0xd7, + 0xa1, 0xec, 0xfe, 0x65, 0xb4, 0xf7, 0x51, 0x00, 0x63, 0x89, 0x83, 0xc1, 0x4d, + 0xe4, 0x97, 0x47, 0x55, 0xda, 0xde, 0x80, 0x18, 0xc9, 0xb8, 0xf4, 0x54, 0x3f, + 0xb0, 0x95, 0x96, 0x15, 0x13, 0xe6, 0x7c, 0x61, 0xdb, 0xc5, 0x9c, 0x60, 0x7f, + 0x9b, 0x51, 0xf8, 0xd0, 0x9b, 0xdc, 0xad, 0x28, 0xbc, 0xfb, 0x9e, 0x5d, 0x27, + 0x44, 0xea, 0x88, 0x48, 0xb2, 0x62, 0x3a, 0xc0, 0x7f, 0x8e, 0xf6, 0x1a, 0x81, + 0xa3, 0x59, 0x10, 0xb8, 0xa1, 0xba, 0xf3, 0x9a, 0x91, 0x9a, 0x7b, 0x60, 0xbc, + 0x60, 0x4d, 0x63, 0x18, 0x5f, 0x75, 0x92, 0x21, 0xd8, 0x47, 0xcc, 0x54, 0xa2, + 0x27, 0x65, 0xa4, 0xc3, 0x34, 0x75, 0xb5, 0x79, 0x1e, 0x9a, 0xf3, 0x27, 0x1f, + 0xc8, 0xd9, 0x35, 0x06, 0x67, 0x09, 0x0d, 0x81, 0x84, 0xec, 0x50, 0x52, 0x2d, + 0x80, 0x4f, 0x23, 0xc4, 0xfb, 0x44, 0xff, 0xa4, 0x81, 0xbc, 0x92, 0xae, 0x40, + 0x8d, 0x1b, 0x9f, 0x2b, 0x13, 0x19, 0x04, 0xf9, 0x70, 0x5c, 0x59, 0xe2, 0xf4, + 0xbd, 0xe7, 0xa3, 0xb2, 0xc0, 0x85, 0xd9, 0x3f, 0xd2, 0xab, 0xc5, 0xe1, 0x4d, + 0x16, 0x30, 0x01, 0xa1, 0x2f, 0x51, 0x93, 0x8d, 0x02, 0x1a, 0xfa, 0x92, 0x23, + 0x9b, 0x87, 0x3d, 0xc6, 0xc3, 0x57, 0xea, 0xa8, 0xaf, 0x4e, 0xe6, 0xd0, 0x05, + 0x40, 0x65, 0x7f, 0xe3, 0x29, 0x14, 0x10, 0x3b, 0x5d, 0x98, 0xf6, 0x8b, 0xd3, + 0xe2, 0xb5, 0x35, 0x9f, 0x08, 0xcc, 0xd8, 0x8d, 0x0c, 0x81, 0x1e, 0x4c, 0x31, + 0xfb, 0xb4, 0x9f, 0x3a, 0x90, 0xbb, 0xd0, 0x5d, 0xce, 0x62, 0xf3, 0x44, 0xe7, + 0x07, 0x75, 0x93, 0x15, 0x9a, 0xe3, 0x50, 0x50, 0xb0, 0x4c, 0x9e, 0x6b, 0x86, + 0xbc, 0x43, 0x2d, 0xc8, 0xb0, 0x48, 0xc7, 0x3c, 0x00, 0x18, 0xca, 0x5b, 0x69, + 0x41, 0x12, 0x97, 0x73, 0x2a, 0x4e, 0x1a, 0xa9, 0x9a, 0x92, 0x8c, 0x71, 0xe7, + 0xa2, 0x4f, 0xd2, 0x77, 0x85, 0x6a, 0xa4, 0x25, 0x01, 0xe5, 0x1b, 0x01, 0x2a, + 0xea, 0x94, 0x46, 0xa2, 0x10, 0x4e, 0x93, 0xf8, 0x15, 0xa0, 0xb3, 0xa2, 0x9b, + 0x45, 0x83, 0x14, 0xf3, 0xd8, 0xbe, 0x2b, 0x98, 0x23, 0xd3, 0x42, 0xf4, 0x62, + 0x13, 0xe9, 0x42, 0xa7, 0xe1, 0x9a, 0x46, 0xe9, 0x70, 0xb5, 0xc5, 0x06, 0x70, + 0x84, 0x30, 0x31, 0x7b, 0x1b, 0xb3, 0xb3, 0x5d, 0xf6, 0x8a, 0xe3, 0x3a, 0x49, + 0x26, 0xa0, 0x3e, 0x6b, 0xfe, 0xb5, 0x51, 0x04, 0x16, 0xfc, 0xbb, 0x05, 0x24, + 0xc9, 0xca, 0x50, 0x74, 0x15, 0x6c, 0xc5, 0xa5, 0xd6, 0xfe, 0x1c, 0x99, 0x5e, + 0xdc, 0x60, 0xa2, 0xf5, 0x50, 0x41, 0x1a, 0xa4, 0x1e, 0x3d, 0xa3, 0xbd, 0xcf, + 0x64, 0xbc, 0xf0, 0x4a, 0x05, 0x10, 0x57, 0x1b, 0x93, 0x6d, 0x47, 0xe5, 0x5c, + 0xec, 0x03, 0x30, 0x00, 0x8d, 0xfe, 0x73, 0x56, 0x34, 0x04, 0xf0, 0x47, 0xd7, + 0xf3, 0xa8, 0xa3, 0xd7, 0x74, 0x3b, 0xc5, 0x54, 0x95, 0x52, 0x10, 0xf1, 0xeb, + 0x0d, 0x08, 0x59, 0x9e, 0xa7, 0x7d, 0x5f, 0x97, 0x4d, 0x87, 0x17, 0x6d, 0x37, + 0xd9, 0x8b, 0x9c, 0x0a, 0xd4, 0x40, 0x40, 0x72, 0x09, 0xed, 0x6a, 0x9f, 0x08, + 0x46, 0x4d, 0x56, 0x55, 0x93, 0xe1, 0xa6, 0x3b, 0x93, 0x85, 0x36, 0xb4, 0x92, + 0x44, 0xe9, 0x7d, + ], + script_code: Script(vec![]), + transparent_input: Some(1), + hash_type: 2, + amount: 652655344020909, + consensus_branch_id: consensus::BranchId::Sapling, + sighash: [ + 0xbb, 0xe6, 0xd8, 0x4f, 0x57, 0xc5, 0x6b, 0x29, 0xb9, 0x14, 0xc6, 0x94, 0xba, + 0xac, 0xcb, 0x89, 0x12, 0x97, 0xe9, 0x61, 0xde, 0x3e, 0xb4, 0x6c, 0x68, 0xe3, + 0xc8, 0x9c, 0x47, 0xb1, 0xa1, 0xdb, + ], + }, + Test0243Vector { + tx: vec![ + 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x01, 0x46, 0xcf, 0x28, 0x9b, + 0x7d, 0x89, 0x13, 0x07, 0xbb, 0xa3, 0x70, 0x54, 0xcf, 0x91, 0xb3, 0x1f, 0xc8, + 0x2f, 0x74, 0xd5, 0xfc, 0xc0, 0x00, 0x94, 0x2e, 0xde, 0x91, 0x18, 0x25, 0xf5, + 0x3f, 0xe6, 0x09, 0x68, 0x6f, 0x46, 0x00, 0x23, 0xb1, 0xe9, 0xbc, 0x00, 0xbd, + 0xe8, 0x95, 0xd1, 0x23, 0x8f, 0xad, 0x04, 0xab, 0xa9, 0x88, 0x99, 0x66, 0x7d, + 0x01, 0x00, 0x04, 0xea, 0x42, 0x71, 0x76, 0x09, 0x84, 0x13, 0x90, 0x59, 0x18, + 0xee, 0x21, 0x3d, 0x4e, 0xc1, 0x27, 0x94, 0x74, 0x2d, 0x19, 0xf6, 0x7d, 0x6f, + 0x86, 0xce, 0xf7, 0xe6, 0x98, 0x2e, 0x88, 0x41, 0x71, 0x28, 0x73, 0xa0, 0x1d, + 0x92, 0x51, 0xd8, 0xc8, 0x60, 0xc0, 0x41, 0x52, 0x5b, 0x3b, 0xf4, 0xe3, 0xa2, + 0xeb, 0x92, 0x72, 0x81, 0x5c, 0x75, 0x86, 0x76, 0x84, 0x28, 0xb4, 0xc2, 0xb2, + 0x5e, 0x37, 0x45, 0xf0, 0x09, 0xc5, 0xdc, 0xe2, 0x0b, 0x69, 0xd5, 0xd7, 0xc4, + 0x3c, 0xeb, 0x73, 0x6b, 0x68, 0x31, 0xe8, 0xc1, 0x10, 0xf1, 0x6c, 0xfd, 0xb3, + 0xa4, 0x67, 0xe9, 0x41, 0x4c, 0x00, 0xec, 0xf1, 0x37, 0x31, 0x50, 0x08, 0x94, + 0x55, 0x56, 0x78, 0xc4, 0x97, 0xfa, 0xba, 0x9a, 0x95, 0xd0, 0x1c, 0xc4, 0x64, + 0x39, 0x0f, 0xc4, 0xa7, 0x6b, 0xfa, 0x8b, 0x0e, 0x1c, 0x68, 0xa5, 0x25, 0xd7, + 0x06, 0xd6, 0x60, 0x4b, 0x23, 0x30, 0xb6, 0xb3, 0x48, 0x52, 0x15, 0xf6, 0x06, + 0xf1, 0x88, 0x3a, 0x75, 0x15, 0x88, 0xc7, 0xef, 0xa5, 0x06, 0xc3, 0xe8, 0xd0, + 0xc6, 0x01, 0x92, 0xe8, 0x47, 0x6b, 0xd1, 0x17, 0x5d, 0x95, 0x62, 0x08, 0x7b, + 0xdb, 0x81, 0x8e, 0x66, 0x21, 0x62, 0x86, 0xba, 0xfe, 0x47, 0xff, 0x4d, 0xbc, + 0xce, 0xd5, 0x14, 0x44, 0x48, 0x0a, 0x9a, 0x56, 0x73, 0xec, 0xe7, 0xfa, 0xc7, + 0x3a, 0x0e, 0xd4, 0x1a, 0xb0, 0x05, 0x17, 0x53, 0xa7, 0xca, 0xa8, 0x9b, 0xe3, + 0x13, 0x9a, 0xfd, 0x97, 0x93, 0xb3, 0xe0, 0x2f, 0x27, 0xf0, 0x40, 0x04, 0x65, + 0x95, 0xac, 0xd4, 0x7b, 0xf1, 0x3f, 0xd0, 0xda, 0x27, 0xf0, 0x9e, 0xda, 0x48, + 0x03, 0x6d, 0x3e, 0xe4, 0x37, 0xf2, 0xee, 0x8f, 0x86, 0x06, 0xea, 0x97, 0x34, + 0x3c, 0x33, 0x58, 0x46, 0x57, 0xf4, 0x6d, 0xba, 0x99, 0xdb, 0x5c, 0xfe, 0x6c, + 0xa1, 0x76, 0xfa, 0xb7, 0xb0, 0xf3, 0xbf, 0xa0, 0xab, 0x61, 0xe3, 0x40, 0xc3, + 0x4e, 0xb9, 0xf1, 0x7c, 0x7e, 0xc2, 0xbe, 0x03, 0xb1, 0x80, 0xf0, 0xbb, 0x6f, + 0x43, 0x4c, 0x2a, 0x65, 0x42, 0xe0, 0x0e, 0x84, 0x37, 0x3f, 0x4f, 0x46, 0x49, + 0xcd, 0xa3, 0x2b, 0xf6, 0x86, 0x66, 0x61, 0x43, 0xf6, 0x22, 0xaa, 0x48, 0x04, + 0x60, 0xb5, 0xaf, 0xac, 0x51, 0x86, 0x07, 0xcd, 0x9a, 0xf8, 0xbc, 0xd6, 0xb5, + 0x8c, 0x30, 0x12, 0x73, 0x16, 0xb2, 0x5d, 0x5e, 0xa7, 0xbf, 0x6b, 0x0c, 0xab, + 0x85, 0x42, 0xff, 0x69, 0xd9, 0xb2, 0xf1, 0x80, 0xbe, 0x12, 0xed, 0x75, 0x34, + 0x4a, 0x39, 0x5a, 0xa1, 0x0f, 0x85, 0x2f, 0x08, 0x3a, 0xd6, 0x4e, 0xf4, 0x0e, + 0x9c, 0x03, 0x09, 0xe9, 0xbb, 0xa5, 0x4b, 0x8c, 0xb3, 0x3c, 0x95, 0x49, 0x8a, + 0x69, 0x53, 0x8d, 0x3a, 0xe5, 0xb2, 0x5e, 0x24, 0x70, 0x98, 0xe1, 0x11, 0x7c, + 0x91, 0x8a, 0xaa, 0xae, 0x9c, 0xb6, 0xef, 0x77, 0xab, 0xd1, 0xe0, 0x1c, 0xc7, + 0x43, 0xd0, 0xdd, 0xd0, 0x22, 0x75, 0x95, 0x1b, 0x92, 0x49, 0x95, 0x65, 0xce, + 0x83, 0x1f, 0x30, 0x32, 0xb8, 0x50, 0x57, 0x75, 0x10, 0x8d, 0xc8, 0x5e, 0x2a, + 0xde, 0x2e, 0xac, 0x1e, 0x63, 0x6e, 0x1a, 0xf4, 0x05, 0x4c, 0x8b, 0x6f, 0x57, + 0x63, 0x2d, 0xf2, 0x69, 0xc3, 0x72, 0x3b, 0x32, 0x08, 0x72, 0xe4, 0xc5, 0x7b, + 0x21, 0x83, 0x58, 0xdc, 0x7e, 0x99, 0x05, 0xbb, 0x04, 0xed, 0xf9, 0x2e, 0xdf, + 0x0d, 0xf6, 0x35, 0xf3, 0xbf, 0x36, 0x1e, 0x57, 0xa1, 0x32, 0x96, 0xe1, 0x44, + 0x7a, 0xf5, 0xa5, 0x66, 0x65, 0x17, 0xbc, 0xd3, 0x56, 0x76, 0x21, 0xa7, 0xcf, + 0x84, 0x45, 0x58, 0x96, 0x53, 0x26, 0x20, 0x20, 0xc3, 0x3b, 0xf7, 0x80, 0x31, + 0xb8, 0xee, 0x07, 0x07, 0xde, 0x07, 0x20, 0x68, 0xc1, 0x70, 0x57, 0x03, 0x27, + 0xe6, 0xd9, 0xf5, 0xc6, 0xdd, 0xc3, 0x35, 0x40, 0x2e, 0xfc, 0x54, 0x88, 0x62, + 0xf5, 0xa0, 0x70, 0x94, 0xfd, 0x42, 0x8a, 0x7b, 0xbc, 0x15, 0xd7, 0xb3, 0x8d, + 0x05, 0x36, 0x2c, 0x9c, 0xa9, 0x85, 0xf5, 0x8a, 0x76, 0x64, 0x7d, 0x2b, 0xe4, + 0xc2, 0xcd, 0x6b, 0x3d, 0x17, 0xd6, 0x87, 0x09, 0x71, 0xd7, 0xa0, 0x98, 0xba, + 0xf7, 0x2c, 0x6f, 0x6f, 0x12, 0x14, 0xcf, 0x1f, 0xaa, 0xe4, 0x88, 0xbd, 0x7d, + 0xe2, 0x59, 0xd3, 0x41, 0x5c, 0x2f, 0x0d, 0xde, 0xc7, 0x45, 0x70, 0x04, 0xf3, + 0x57, 0x08, 0xd1, 0xec, 0xcc, 0xcc, 0x0d, 0xf6, 0x5a, 0x04, 0x94, 0x3a, 0xd5, + 0xcb, 0xc1, 0x3f, 0x29, 0x5f, 0x00, 0x0f, 0xe0, 0x56, 0xc4, 0x0b, 0x2d, 0x88, + 0xf2, 0x7d, 0xc3, 0x4c, 0xfe, 0xb8, 0x03, 0xbe, 0x34, 0x83, 0xa9, 0xeb, 0xf9, + 0xb5, 0xa9, 0x02, 0x60, 0x57, 0x72, 0x5d, 0x63, 0xea, 0xd2, 0xc0, 0xc0, 0xff, + 0x1f, 0xe2, 0x6a, 0xc1, 0xe7, 0xbd, 0xfc, 0xd6, 0xfa, 0xd8, 0x75, 0x84, 0x2d, + 0x19, 0x4f, 0x33, 0x17, 0x50, 0x46, 0x2c, 0x06, 0xb8, 0xd7, 0x98, 0x2d, 0x67, + 0x99, 0x5e, 0xd5, 0xd3, 0xae, 0x96, 0xa0, 0x5a, 0xe0, 0x06, 0x7f, 0x4e, 0xb1, + 0xc7, 0xc9, 0x32, 0x31, 0xbd, 0x39, 0x77, 0x3c, 0xbe, 0x0a, 0x9d, 0x66, 0xb0, + 0xc9, 0xaa, 0x8c, 0xff, 0x6a, 0x37, 0x6e, 0x1f, 0x37, 0x2e, 0xac, 0x6a, 0xc4, + 0xe4, 0x6c, 0xc0, 0x94, 0x22, 0x45, 0xd4, 0xc2, 0xdc, 0xf0, 0x2d, 0x76, 0x40, + 0xff, 0xcc, 0x5a, 0x6a, 0xc3, 0xa8, 0x7f, 0x5c, 0x41, 0x15, 0x51, 0xbc, 0xc2, + 0xf2, 0x6c, 0xb9, 0x49, 0x61, 0xd5, 0x3f, 0x95, 0xdd, 0xb1, 0x9a, 0xe9, 0x30, + 0xc8, 0xd7, 0x0f, 0x03, 0x1b, 0x29, 0xa5, 0xdf, 0x99, 0xff, 0x36, 0x69, 0x5e, + 0x80, 0x2c, 0xbc, 0xb6, 0xb1, 0xcf, 0x7d, 0xc9, 0x7a, 0xbb, 0x3b, 0x25, 0x27, + 0x64, 0xc0, 0x1a, 0x62, 0x2d, 0xfb, 0x2e, 0xcb, 0x49, 0xce, 0x71, 0xf7, 0x38, + 0x6e, 0x23, 0x89, 0x5b, 0x5a, 0xfe, 0x16, 0x61, 0x98, 0xb6, 0x7f, 0x5b, 0x42, + 0xb2, 0xf6, 0x5e, 0xcd, 0x0f, 0x82, 0x59, 0x54, 0x78, 0xd8, 0x0a, 0xe5, 0xc8, + 0xce, 0xea, 0x12, 0xa1, 0x61, 0xcc, 0xbb, 0x5e, 0xac, 0x09, 0x99, 0x0f, 0xc6, + 0x19, 0xa4, 0x60, 0x80, 0x43, 0x6d, 0xbd, 0x08, 0xd7, 0x47, 0x84, 0xaf, 0x00, + 0x2d, 0x58, 0xe0, 0x6f, 0xaf, 0x7f, 0x3c, 0xea, 0xe7, 0xd3, 0x41, 0x9b, 0x1f, + 0xca, 0x26, 0x5a, 0x55, 0x59, 0xcf, 0x9e, 0x2d, 0x3b, 0x97, 0xb2, 0xa9, 0x9a, + 0x9b, 0xa5, 0xa8, 0x66, 0x58, 0xc3, 0xfd, 0x9e, 0xc5, 0x5b, 0xfa, 0x9b, 0x32, + 0x85, 0x67, 0x25, 0x4a, 0xb3, 0x6d, 0x2c, 0x7f, 0x44, 0xd2, 0xc7, 0xe1, 0x3e, + 0xb5, 0x4b, 0xeb, 0x70, 0xea, 0x8f, 0xa9, 0x4b, 0x6c, 0x6e, 0x01, 0x2d, 0x79, + 0xe3, 0xf5, 0x36, 0x89, 0xc2, 0xb1, 0xa1, 0x8e, 0xaf, 0x2d, 0x47, 0x1d, 0x13, + 0xc1, 0xab, 0x39, 0xd9, 0x19, 0x4a, 0xe8, 0x43, 0xab, 0x1d, 0x28, 0xff, 0xa8, + 0xf6, 0x9d, 0xc7, 0xe1, 0x5c, 0xc3, 0x8b, 0x12, 0xe8, 0xfc, 0xd7, 0x92, 0x55, + 0xb7, 0x21, 0x60, 0x56, 0xd9, 0xed, 0xb7, 0x48, 0x2f, 0xb9, 0x8a, 0xa0, 0x33, + 0xb6, 0x5e, 0x51, 0xc1, 0xa0, 0x8b, 0x8a, 0x11, 0xd8, 0x4d, 0x04, 0x09, 0xb7, + 0x34, 0xf4, 0x52, 0xaa, 0xf0, 0xd6, 0xb1, 0x8f, 0x50, 0x25, 0x86, 0x83, 0xd3, + 0xf9, 0xa7, 0x6d, 0x39, 0x9f, 0xd0, 0x47, 0xee, 0xe2, 0x88, 0xbb, 0x45, 0x85, + 0x85, 0x1d, 0xc9, 0x3e, 0xcc, 0xc6, 0x23, 0x22, 0x92, 0x4c, 0xd1, 0x3b, 0x5d, + 0xd4, 0xee, 0xd6, 0x6e, 0xd8, 0xd9, 0x97, 0x2d, 0x77, 0x26, 0x29, 0xea, 0x64, + 0x74, 0x2e, 0x54, 0x73, 0x39, 0x81, 0xb0, 0x06, 0xc0, 0x62, 0x46, 0x8e, 0x4b, + 0xd8, 0xf7, 0xdd, 0x9a, 0xf6, 0x98, 0xf5, 0x2a, 0xe8, 0x14, 0x63, 0x4e, 0x81, + 0xd7, 0xf3, 0xe0, 0xc4, 0x20, 0x31, 0x7c, 0xac, 0xa9, 0xae, 0x48, 0x11, 0xc6, + 0xaf, 0x06, 0xfe, 0x80, 0xa8, 0xc0, 0x2a, 0xb7, 0xa0, 0x0e, 0x18, 0xe4, 0xa6, + 0xaa, 0x1e, 0xa1, 0xb7, 0x69, 0x45, 0xd2, 0x61, 0x5d, 0x43, 0xac, 0x11, 0x8b, + 0x56, 0xc2, 0xf2, 0x96, 0x0f, 0xe9, 0x3a, 0x02, 0x5f, 0x13, 0xec, 0x91, 0xff, + 0xc6, 0xd2, 0xc3, 0x53, 0x69, 0x9a, 0xbb, 0x09, 0x2d, 0xed, 0xc0, 0x65, 0xdb, + 0x8f, 0xa2, 0x14, 0xdb, 0xc4, 0x64, 0x66, 0xf8, 0x97, 0xb8, 0x8c, 0x58, 0xb3, + 0x01, 0x52, 0x13, 0x3a, 0xa3, 0x83, 0x1a, 0xf3, 0x7c, 0x74, 0xd9, 0x9e, 0x9e, + 0x36, 0xff, 0x70, 0x11, 0xd3, 0x23, 0x83, 0x05, 0x69, 0x15, 0x08, 0xd0, 0xf1, + 0xf6, 0xaa, 0xaa, 0xa4, 0x25, 0x12, 0x30, 0xc6, 0xcc, 0xc4, 0x66, 0x68, 0xbb, + 0xcf, 0x35, 0xe5, 0xa5, 0xef, 0x2f, 0x86, 0xe6, 0x65, 0xd8, 0xcf, 0xac, 0x74, + 0x76, 0xec, 0xb2, 0x43, 0x78, 0x79, 0x6a, 0x8e, 0xf2, 0xe4, 0xd9, 0x4d, 0x43, + 0x58, 0xbe, 0x2b, 0x47, 0x5f, 0xcc, 0x92, 0xdf, 0x93, 0x82, 0xc5, 0xc0, 0x69, + 0x19, 0xa0, 0xd6, 0x31, 0xec, 0x26, 0x10, 0xfe, 0xdc, 0x21, 0x9b, 0xe6, 0x3f, + 0x37, 0xf2, 0xba, 0x0d, 0x43, 0x23, 0x66, 0x73, 0x6d, 0x86, 0x32, 0xfc, 0xe0, + 0x72, 0xb6, 0xae, 0x5b, 0x6f, 0x3f, 0xd5, 0x9d, 0x3f, 0xaf, 0xf6, 0x38, 0x27, + 0x5a, 0x99, 0x2f, 0xef, 0xc8, 0x7e, 0x60, 0xd4, 0x4c, 0x2c, 0xad, 0xc2, 0xb5, + 0xc4, 0x94, 0xe3, 0xe7, 0x2e, 0xb4, 0x59, 0x7c, 0x96, 0xb4, 0x01, 0x67, 0x79, + 0x9a, 0x90, 0x01, 0xa2, 0xed, 0x36, 0x76, 0xa8, 0xb4, 0x03, 0xae, 0x25, 0xff, + 0xd7, 0x72, 0xf7, 0x08, 0x1e, 0x9a, 0x32, 0xbc, 0xc1, 0xc5, 0xe2, 0xed, 0xd4, + 0xe2, 0xa6, 0x57, 0x6b, 0x78, 0x3c, 0xce, 0x3a, 0xae, 0x11, 0xfa, 0x43, 0x22, + 0x62, 0x54, 0x88, 0x56, 0x18, 0x3e, 0xe6, 0x82, 0xd5, 0xdc, 0x31, 0xbe, 0xb3, + 0x8f, 0x06, 0x1c, 0xbd, 0xec, 0xa7, 0x02, 0x1a, 0x44, 0x4e, 0x2d, 0xd4, 0x17, + 0xdf, 0x26, 0xdc, 0xd2, 0x20, 0xf2, 0xb7, 0x31, 0x77, 0x2b, 0x43, 0x9e, 0x96, + 0xd6, 0x14, 0xe1, 0xfa, 0xcb, 0x48, 0x6c, 0x7a, 0x7d, 0x51, 0x71, 0xb1, 0xde, + 0x35, 0x9f, 0x6a, 0xd3, 0xa9, 0x6f, 0x64, 0x9c, 0x96, 0x91, 0x02, 0xa1, 0x96, + 0x4f, 0xb4, 0xb4, 0xa1, 0xa4, 0x27, 0x9c, 0x68, 0xe6, 0xc3, 0x72, 0xe4, 0x21, + 0x87, 0xd7, 0x54, 0xe8, 0x04, 0xa6, 0x16, 0x53, 0x09, 0x20, 0x69, 0xfb, 0x9b, + 0x6d, 0x25, 0x26, 0x68, 0x90, 0x80, 0x8b, 0x01, 0x5d, 0xf2, 0x8c, 0x80, 0x10, + 0x65, 0xda, 0x6f, 0xeb, 0xdc, 0x1a, 0x56, 0xbf, 0xd0, 0x02, 0x62, 0x5a, 0xcf, + 0xaa, 0x53, 0x73, 0xfd, 0xe1, 0x49, 0xc1, 0xcf, 0xc3, 0x64, 0x9b, 0x48, 0x69, + 0x69, 0x6d, 0x44, 0xec, 0xb1, 0x24, 0x79, 0xc5, 0xeb, 0xef, 0x99, 0x5f, 0x10, + 0x02, 0x9f, 0x8b, 0x53, 0x0e, 0xeb, 0x3f, 0xdc, 0x2e, 0x50, 0xe8, 0x75, 0x7f, + 0xc0, 0xbb, 0x9e, 0x26, 0x30, 0x23, 0xdb, 0x82, 0xf8, 0x78, 0xd9, 0xac, 0x7f, + 0xfb, 0x0b, 0xd4, 0x39, 0x1d, 0xf1, 0xd8, 0x79, 0x89, 0x9a, 0x3e, 0xf5, 0x7b, + 0xfd, 0x0d, 0x1f, 0x77, 0x55, 0x64, 0x8e, 0xdd, 0x85, 0xbb, 0x05, 0x2a, 0x6e, + 0xdf, 0x71, 0xcd, 0x26, 0x28, 0xc9, 0x87, 0x42, 0x9f, 0x36, 0xdc, 0x50, 0x5c, + 0xcc, 0x43, 0xf3, 0x0e, 0x7a, 0x86, 0x9c, 0x9e, 0x25, 0x5e, 0x2a, 0xf9, 0xfc, + 0xf3, 0x0c, 0x12, 0x17, 0x96, 0x03, 0xae, 0x17, 0x57, 0x55, 0x3b, 0x5c, 0x94, + 0x60, 0x7e, 0x00, 0xd0, 0x32, 0xfb, 0xbe, 0xd2, 0x3c, 0x4c, 0xba, 0xbf, 0x74, + 0x1d, 0x68, 0xaa, 0xb3, 0x0e, 0x0b, 0x8f, 0x15, 0xf4, 0x44, 0xd5, 0x86, 0xb3, + 0xe7, 0xe6, 0x15, 0x9c, 0x46, 0x69, 0x9f, 0x10, 0x07, 0x92, 0xd4, 0x67, 0x29, + 0x50, 0x34, 0x8a, 0x90, 0x55, 0x2e, 0x45, 0x94, 0x3b, 0xee, 0xac, 0xf0, 0x3f, + 0x32, 0x16, 0xf9, 0x4e, 0x27, 0x90, 0x6e, 0xdc, 0x63, 0x23, 0x19, 0xad, 0x8d, + 0x37, 0x44, 0x7f, 0x5c, 0x59, 0xcc, 0xde, 0x35, 0x4f, 0x99, 0xff, 0x6c, 0x7a, + 0x76, 0x23, 0xf6, 0xd4, 0x15, 0x25, 0xa8, 0x09, 0xce, 0x2f, 0x41, 0xec, 0x0f, + 0xf7, 0xf1, 0xaf, 0x81, 0xb2, 0x4c, 0xed, 0x0e, 0xfa, 0x62, 0x13, 0xda, 0x6c, + 0x7c, 0x60, 0xc4, 0x87, 0xf5, 0xf7, 0xb0, 0x3f, 0x81, 0x60, 0xa0, 0x57, 0xf4, + 0x6d, 0x05, 0xbf, 0x82, 0x18, 0xb3, 0xad, 0xd9, 0xc0, 0x68, 0x93, 0xbd, 0x02, + 0xdb, 0x9b, 0x61, 0x19, 0x1d, 0xfb, 0x13, 0x3b, 0xfa, 0xbe, 0x48, 0x58, 0xe4, + 0x7a, 0x4c, 0xc3, 0x2e, 0x41, 0x6e, 0xc0, 0x8b, 0x8a, 0xc7, 0x91, 0x5a, 0x43, + 0x73, 0x3f, 0x44, 0x06, 0xe9, 0xd9, 0x67, 0xc5, 0x60, 0xf3, 0x44, 0xd7, 0xe9, + 0x04, 0xa2, 0x80, 0x45, 0xd9, 0x9f, 0x3a, 0xf8, 0xc8, 0x2e, 0x97, 0xe1, 0xb9, + 0xc1, 0xb2, 0x05, 0xe5, 0x85, 0xfb, 0xeb, 0xb4, 0x8f, 0xaf, 0x58, 0xf1, 0xb6, + 0x5d, 0xca, 0x24, 0x97, 0xe0, 0x9a, 0x70, 0xaa, 0xd4, 0x86, 0x5f, 0x85, 0x71, + 0x5a, 0x28, 0x0e, 0x18, 0x6f, 0x3f, 0xc1, 0x74, 0x0d, 0x81, 0x84, 0xd3, 0x3e, + 0x83, 0x22, 0x16, 0x95, 0x21, 0xcd, 0xc1, 0x32, 0x21, 0x29, 0x39, 0xc8, 0x4a, + 0x10, 0x89, 0x64, 0xe2, 0xde, 0x74, 0xb6, 0xea, 0x55, 0xb4, 0xcb, 0x8f, 0x6f, + 0x9b, 0xee, 0x98, 0xb1, 0x0d, 0x41, 0x51, 0x09, 0x45, 0x5f, 0x48, 0xb7, 0x76, + 0x08, 0x2d, 0xc3, 0x0b, 0x4b, 0xc7, 0x34, 0x77, 0x07, 0x55, 0x11, 0x70, 0x03, + 0x08, 0x15, 0x8c, 0xe2, 0xf2, 0xf9, 0xbf, 0x0f, 0x69, 0x1b, 0x2c, 0xe5, 0x3e, + 0x61, 0x14, 0x2c, 0xb7, 0x40, 0xc1, 0x5b, 0x7b, 0x62, 0x3c, 0xf4, 0x8b, 0x3f, + 0x7b, 0xfe, 0xfa, 0x31, 0xbc, 0xdc, 0x66, 0x5c, 0x6d, 0x71, 0x23, 0xe9, 0x53, + 0x50, 0x81, 0x13, 0x75, 0x94, 0x7b, 0x05, 0x5a, 0x43, 0xdb, 0x07, 0xe0, 0x3f, + 0x33, 0x62, 0x7d, 0xf5, 0xc6, 0x38, 0xbf, 0xad, 0x95, 0x6d, 0xdc, 0x1e, 0xa7, + 0xd7, 0x62, 0x0a, 0x20, 0xf2, 0x79, 0x2f, 0x63, 0x81, 0x7a, 0x1c, 0xf3, 0x25, + 0x80, 0xd0, 0x42, 0x74, 0x23, 0x4a, 0xf2, 0xa5, 0x1b, 0x56, 0xbb, 0x68, 0xa2, + 0x9e, 0x43, 0xa9, 0x54, 0x14, 0x2b, 0xa4, 0xca, 0x68, 0x23, 0xbd, 0xe9, 0x05, + 0x3d, 0x72, 0xfd, 0xad, 0xbc, 0x61, 0xad, 0x59, 0x36, 0xc5, 0x3f, 0xdd, 0x75, + 0x79, 0x44, 0x6d, 0x11, 0xc4, 0x46, 0x07, 0xf4, 0x16, 0x30, 0xe4, 0xc0, 0x89, + 0x15, 0xe6, 0x31, 0x77, 0x15, 0x50, 0xe9, 0xce, 0x1f, 0xca, 0x2c, 0x63, 0xfe, + 0x06, 0xb7, 0x98, 0x9d, 0x58, 0x4f, 0xa7, 0xd7, 0x82, 0xa8, 0x8c, 0x1e, 0x7d, + 0x64, 0xb6, 0xfb, 0xf5, 0x5e, 0x35, 0x96, 0xaf, 0x9b, 0xcb, 0x75, 0x85, 0xf8, + 0xc7, 0xd3, 0xaa, 0x5c, 0x20, 0x82, 0xb2, 0x65, 0x24, 0x9d, 0xf0, 0x57, 0x01, + 0xda, 0xb0, 0x31, 0xc4, 0xba, 0xc1, 0xea, 0x26, 0x7a, 0x29, 0x96, 0xa2, 0x02, + 0x8d, 0x1e, 0x6a, 0x0f, 0x80, 0xa3, 0x84, 0x7c, 0x53, 0x1d, 0xba, 0x96, 0xee, + 0x65, 0xa2, 0x41, 0x89, 0xbd, 0x27, 0x12, 0xe4, 0x0e, 0x95, 0x96, 0x64, 0x98, + 0x1e, 0x58, 0xb2, 0xa4, 0xf9, 0x51, 0xef, 0x8f, 0x49, 0x7d, 0xff, 0xf2, 0xf2, + 0xf2, 0x71, 0xea, 0xb8, 0x9c, 0x62, 0x8e, 0x18, 0xb5, 0xfc, 0xb4, 0x38, 0x82, + 0x53, 0x7e, 0xaf, 0x6a, 0xd2, 0xa6, 0xb1, 0x75, 0x46, 0x33, 0xca, 0xa8, 0x6b, + 0xf2, 0xc7, 0x6f, 0x39, 0x93, 0x15, 0x4f, 0xc7, 0x3e, 0x6f, 0xbb, 0xa2, 0x21, + 0x0c, 0x27, 0x43, 0xf5, 0x30, 0xa4, 0x27, 0x84, 0x9a, 0x30, 0x1e, 0x00, 0xe0, + 0x11, 0x29, 0xf0, 0x3a, 0x46, 0x07, 0xf8, 0x7c, 0xbe, 0x07, 0x62, 0xc0, 0xb1, + 0xc6, 0x58, 0x55, 0xde, 0xba, 0x84, 0x22, 0xca, 0x4b, 0x88, 0xab, 0xee, 0xa6, + 0xa4, 0x38, 0x2c, 0xf1, 0x6c, 0xcd, 0x6d, 0xc7, 0xc3, 0x7c, 0x44, 0xe5, 0x49, + 0xc4, 0x53, 0x48, 0x19, 0xac, 0xd8, 0xbb, 0x0a, 0x02, 0xa5, 0xfa, 0x7a, 0x1c, + 0x1d, 0x38, 0x06, 0xfb, 0xc3, 0x40, 0x7f, 0xd7, 0xda, 0x93, 0xfd, 0x0d, 0xe6, + 0x40, 0x0d, 0x3a, 0xb8, 0x97, 0x74, 0x85, 0xcd, 0xdf, 0xbe, 0xd5, 0x93, 0x2f, + 0x50, 0x7b, 0x79, 0x94, 0x7a, 0xdb, 0x2f, 0xad, 0x37, 0x61, 0x5a, 0xa7, 0x17, + 0xdb, 0x5f, 0x29, 0x80, 0x99, 0xf2, 0x0f, 0x26, 0x3b, 0x35, 0x9a, 0x11, 0x51, + 0xa6, 0xb7, 0x5c, 0x01, 0x36, 0x5e, 0xb1, 0x54, 0xae, 0x42, 0x14, 0x0d, 0x6e, + 0x10, 0x34, 0x2f, 0x14, 0xf3, 0x4d, 0xc3, 0x3e, 0x07, 0xff, 0x0e, 0x4d, 0x1a, + 0x6b, 0xe3, 0x75, 0xb3, 0x2f, 0x84, 0xb9, 0x2e, 0x5d, 0x81, 0xeb, 0xb6, 0x39, + 0xc4, 0xf2, 0x7e, 0x71, 0x5a, 0xa4, 0x2c, 0xc7, 0x57, 0x07, 0xd4, 0xeb, 0xd1, + 0xbb, 0xfb, 0xe8, 0xf9, 0x0f, 0xc7, 0xc9, 0x53, 0xe7, 0xa9, 0x71, 0x5e, 0x65, + 0xaf, 0x82, 0x67, 0x37, 0x3d, 0x34, 0x51, 0x67, 0x4f, 0xf0, 0x84, 0xef, 0xd9, + 0x2c, 0xcf, 0x3b, 0xcc, 0x7a, 0xca, 0x14, 0x67, 0xb6, 0x32, 0x7e, 0x4f, 0x95, + 0x22, 0xb2, 0xcc, 0x57, 0x9a, 0x7a, 0x8f, 0xff, 0x7c, 0xa7, 0xcf, 0x14, 0x5d, + 0xfc, 0x13, 0xea, 0xfc, 0x34, 0x15, 0x3b, 0x2c, 0x3e, 0x8a, 0xfb, 0xe5, 0x34, + 0x44, 0xd0, 0xc7, 0x3b, 0x3b, 0xd5, 0xbc, 0x87, 0x0b, 0x01, 0xcd, 0x45, 0x79, + 0x11, 0xe3, 0x56, 0x31, 0x3f, 0xd1, 0xda, 0xfb, 0x4c, 0x81, 0x51, 0x63, 0x4a, + 0x01, 0xaf, 0xf7, 0xcf, 0x11, 0x6d, 0x43, 0x3c, 0x3d, 0x2b, 0x3a, 0xdd, 0xa9, + 0xce, 0xbe, 0x18, 0xf7, 0xd1, 0x72, 0x44, 0x3e, 0x5e, 0x7b, 0x5a, 0xc9, 0xab, + 0xe8, 0xdb, 0x22, 0x56, 0xd7, 0xeb, 0xe2, 0xff, 0x28, 0x02, 0x09, 0x39, 0x50, + 0x38, 0x70, 0x59, 0x7b, 0x9a, 0x95, 0x58, 0x92, 0xc7, 0x38, 0x96, 0x50, 0xa2, + 0xd4, 0x2e, 0xc9, 0x2b, 0xe7, 0x23, 0xfe, 0xdf, 0x2f, 0x2e, 0xde, 0x5a, 0x47, + 0x2a, 0xa1, 0xe7, 0x4f, 0x33, 0xad, 0x41, 0x90, 0x15, 0x44, 0xed, 0xbb, 0xe3, + 0xac, 0x46, 0x4c, 0xf4, 0x39, 0x19, 0x60, 0x15, 0xf4, 0xf2, 0x2a, 0xc2, 0xb8, + 0xfc, 0x01, 0x49, 0x6b, 0xea, 0xb4, 0xd4, 0x59, 0x07, 0xf4, 0x79, 0x81, 0x2a, + 0x25, 0x94, 0x31, 0xa2, 0xcb, 0xc9, 0x3d, 0x4f, 0x3b, 0x84, 0xe4, 0xdd, 0x36, + 0x60, 0x20, 0x27, 0x3a, 0x67, 0x52, 0xe5, 0x01, 0xaf, 0x6f, 0xf1, 0xb7, 0x8d, + 0xdc, 0x81, 0x7e, 0x6e, 0xa3, 0xe5, 0x37, 0x5c, 0xa3, 0xfe, 0x2f, 0xb1, 0xd1, + 0xa9, 0x37, 0x15, 0xdf, 0xf9, 0x29, 0x93, 0xcc, 0xc6, 0x50, 0x4f, 0x64, 0xfc, + 0xbf, 0x22, 0x17, 0x30, 0xd9, 0xef, 0xf4, 0xf3, 0x27, 0xe0, 0xad, 0x37, 0x4f, + 0x59, 0x56, 0x45, 0x37, 0x48, 0x75, 0x5b, 0x43, 0xc8, 0xf2, 0x9d, 0x67, 0x52, + 0x6f, 0x60, 0xa6, 0x18, 0xb7, 0x33, 0x24, 0xd2, 0x24, 0x33, 0x72, 0x92, 0x1b, + 0x99, 0xe3, 0xdf, 0x36, 0x85, 0x0c, 0x60, 0xd5, 0xd9, 0x34, 0x3a, 0x48, 0x70, + 0xa0, 0xe7, 0x52, 0x8c, 0x65, 0x13, 0xc2, 0x7c, 0x56, 0x43, 0x90, 0x93, 0xf9, + 0x33, 0x68, 0x1d, 0x93, 0xa4, 0xd4, 0xbc, 0xee, 0xac, 0x2b, 0x10, 0x8c, 0x6c, + 0x6f, 0xae, 0x35, 0x9f, 0x64, 0x5c, 0x27, 0x68, 0x91, 0xc0, 0xdc, 0xab, 0x3f, + 0xaf, 0x18, 0x77, 0x00, 0xc0, 0x82, 0xdc, 0x47, 0x77, 0x40, 0xfb, 0x3f, 0x2c, + 0xd7, 0xbb, 0x59, 0xfb, 0x35, 0x85, 0x54, 0xe9, 0x4c, 0x7e, 0x67, 0x8c, 0xe0, + 0x1a, 0xeb, 0xf9, 0x4e, 0x51, 0x5e, 0x49, 0x72, 0x29, 0x67, 0x99, 0x5a, 0xea, + 0x85, 0x8d, 0x64, 0xe7, 0x78, 0x9f, 0xf3, 0x06, 0x36, 0x95, 0x77, 0x22, 0x81, + 0x80, 0x32, 0x6a, 0x5b, 0x0a, 0xf4, 0x75, 0xe2, 0x7a, 0x54, 0xb2, 0x07, 0xb4, + 0x1f, 0x92, 0xe3, 0x76, 0x17, 0x0e, 0x3f, 0xb0, 0x05, 0x02, 0x82, 0x61, 0xc9, + 0x9c, 0x2d, 0xbd, 0x0e, 0xed, 0xee, 0x87, 0x1c, 0x1c, 0x0f, 0x48, 0xb8, 0xe9, + 0xb8, 0xe4, 0xbe, 0x77, 0xd1, 0xb7, 0x37, 0xfe, 0x21, 0xf0, 0xfa, 0x5a, 0x18, + 0xeb, 0xb5, 0x27, 0x55, 0xb5, 0xa6, 0xcf, 0x61, 0x30, 0xfb, 0x56, 0x94, 0x4c, + 0xfa, 0xb8, 0x75, 0x27, 0xc2, 0x50, 0xd1, 0x13, 0xb2, 0x9b, 0xca, 0xc9, 0xaa, + 0xa1, 0x0c, 0x2e, 0x7d, 0xe4, 0x15, 0xed, 0xb0, 0x80, 0x6c, 0x6d, 0xa0, 0x30, + 0x20, 0xa1, 0x34, 0xca, 0x7e, 0xcd, 0xc8, 0xda, 0x1b, 0xd5, 0x7a, 0x37, 0xf5, + 0x5a, 0x46, 0x94, 0x0b, 0x45, 0xb2, 0x41, 0xb1, 0xc1, 0x6e, 0xe1, 0x00, 0x92, + 0x7d, 0x1b, 0xd8, 0x60, 0xd4, 0x45, 0xa9, 0xde, 0x50, 0xd4, 0xc3, 0x84, 0xd6, + 0xe1, 0xd0, 0x01, 0x08, 0x02, 0x6c, 0x0e, 0xa5, 0xeb, 0xbf, 0x0b, 0x72, 0xfb, + 0xf5, 0xc3, 0x70, 0xbc, 0xe1, 0x8d, 0x3a, 0xcb, 0xc4, 0x65, 0x99, 0x09, 0x9b, + 0xaa, 0xe1, 0xd8, 0x02, 0xf7, 0x73, 0x33, 0x49, 0x4a, 0x7a, 0xe1, 0x30, 0xfe, + 0x86, 0xe8, 0xf8, 0x18, 0xf9, 0x26, 0x1a, 0x2d, 0xad, 0xb4, 0x12, 0x52, 0x29, + 0xba, 0x0f, 0xfc, 0x0e, 0x70, 0x90, 0x32, 0x44, 0x30, 0xb5, 0x21, 0xa9, 0x0d, + 0x22, 0x4a, 0xb7, 0xa1, 0x02, 0x4e, 0x1d, 0x89, 0x3e, 0x74, 0x04, 0xfe, 0xdb, + 0x34, 0x8e, 0x4d, 0x5e, 0x22, 0x35, 0xc5, 0x9a, 0x78, 0x76, 0xa0, 0xfc, 0x60, + 0x14, 0x5c, 0x6a, 0x00, 0x96, 0x87, 0x68, 0x44, 0x60, 0x27, 0x1e, 0xe1, 0x33, + 0xa4, 0x37, 0xfe, 0x52, 0xfb, 0x6c, 0xfb, 0xa9, 0x7f, 0xce, 0xc1, 0x61, 0xdf, + 0x51, 0x5d, 0xde, 0x90, 0x5a, 0x24, 0xda, 0x6d, 0x37, 0xbd, 0xc3, 0x40, 0x44, + 0xa9, 0x55, 0xe6, 0x82, 0xb4, 0x74, 0x71, 0xca, 0x1e, 0x8c, 0x78, 0xc5, 0x1e, + 0xd3, 0x77, 0xcd, 0x4a, 0xfa, 0x89, 0x4b, 0xd9, 0xbd, 0x12, 0xe7, 0x07, 0x15, + 0x6d, 0xa0, 0x72, 0x6f, 0x7c, 0xf5, 0x72, 0x9f, 0xab, 0xe3, 0x72, 0x16, 0x04, + 0x63, 0xfe, 0x04, 0x29, 0x24, 0x4d, 0x06, 0x74, 0x89, 0xba, 0x5d, 0x09, 0x47, + 0x2e, 0xcd, 0x9b, 0xcd, 0xc4, 0xd5, 0xe4, 0xdf, 0x10, 0x1e, 0x18, 0x9d, 0xb8, + 0x46, 0x3e, 0xb5, 0x38, 0x30, 0x7b, 0x58, 0x7d, 0xef, 0xf7, 0x8d, 0xe9, 0xc7, + 0x3a, 0xf2, 0x80, 0x80, 0xb2, 0xfd, 0x05, 0x00, 0x3e, 0x11, 0xd3, 0xe1, 0xb3, + 0x29, 0x9d, 0xc9, 0x52, 0x1f, 0x8b, 0x51, 0x3b, 0xad, 0xb0, 0x10, 0xe9, 0x1b, + 0xfe, 0xb9, 0x1b, 0x0b, 0x2a, 0x6c, 0xb1, 0x29, 0xc2, 0xe8, 0x25, 0xa5, 0x97, + 0xb8, 0xfb, 0x75, 0xbc, 0x56, 0x2d, 0x65, 0x4d, 0x62, 0x10, 0x46, 0x40, 0xdd, + 0x74, 0xe5, 0x6c, 0xd1, 0x4b, 0xaa, 0xba, 0x56, 0x5b, 0x84, 0xb8, 0x45, 0xe1, + 0x63, 0xd1, 0xca, 0xef, 0x25, 0x33, 0xc3, 0x98, 0x16, 0x37, 0x20, 0x4f, 0x96, + 0xa5, 0x9c, 0x8e, 0x80, 0x24, 0xd9, 0x04, 0x1b, 0x20, 0x29, 0xe9, 0x4c, 0x15, + 0x24, 0x5f, 0x1a, 0x95, 0x88, 0x40, 0xba, 0x3f, 0x38, 0x0a, 0x4d, 0x20, 0xf1, + 0x18, 0x4e, 0x77, 0x82, 0x7d, 0xe3, 0xff, 0x8f, 0x3d, 0x73, 0x45, 0x9a, 0xfe, + 0x24, 0x1f, 0x72, 0x3c, 0x08, 0x48, 0x23, 0x23, 0x0e, 0x00, 0x3d, 0x3d, 0x21, + 0xe5, 0x35, 0x01, 0xec, 0x04, 0x99, 0xb0, 0x83, 0xa7, 0xda, 0xd6, 0x85, 0xc5, + 0x71, 0x27, 0xf4, 0xde, 0x64, 0x73, 0x3a, 0x88, 0x0c, 0x2d, 0xb2, 0x8f, 0xda, + 0xab, 0xf1, 0xb5, 0x42, 0xd2, 0x05, 0xf6, 0x64, 0xa3, 0x51, 0x35, 0x71, 0x27, + 0x11, 0xdc, 0xcc, 0xd9, 0x31, 0xa5, 0x0b, 0x9c, 0x56, 0x61, 0x88, 0x23, 0x60, + 0xd4, 0xca, 0xc0, 0x04, 0x76, 0x81, 0xbc, 0x2e, 0x2b, 0x3b, 0xf6, 0xc9, 0x97, + 0x60, 0xd7, 0xcf, 0xb4, 0xfa, 0x21, 0x39, 0x43, 0x77, 0xa4, 0x55, 0x1c, 0x76, + 0xd1, 0xf7, 0x5a, 0xc0, 0x3c, 0x26, 0x20, 0x54, 0xdf, 0xfd, 0x79, 0xa9, 0xde, + 0xd0, 0x5e, 0x88, 0x89, 0x58, 0x19, 0x9e, 0xea, 0x45, 0x01, 0xe2, 0x99, 0x0a, + 0x53, 0xa5, 0xcd, 0x2a, 0x46, 0xa4, 0x01, 0x57, 0x65, 0x88, 0xfd, 0x7d, 0x05, + 0x8a, 0x26, 0xf2, 0x84, 0x38, 0xe5, 0x78, 0x2f, 0x45, 0xac, 0x1d, 0x07, 0xf6, + 0xf6, 0xf5, 0xed, 0x73, 0x74, 0x1d, 0x57, 0x85, 0x83, 0x7a, 0x6b, 0x84, 0x4b, + 0x47, 0x47, 0x75, 0x71, 0x8c, 0x29, 0xdd, 0x99, 0x08, 0x4e, 0x9f, 0x88, 0xef, + 0x15, 0x3a, 0x83, 0x29, 0xf5, 0x32, 0xa6, 0x90, 0x17, 0xdc, 0x3a, 0x97, 0xed, + 0x75, 0x43, 0x67, 0x72, 0x30, 0x98, 0xe5, 0x76, 0x58, 0x40, 0xb0, 0x22, 0x89, + 0x72, 0x44, 0x74, 0x5f, 0xbb, 0xbb, 0x30, 0xa7, 0xcb, 0x54, 0xfa, 0x05, 0x11, + 0x16, 0x6e, 0x95, 0x44, 0x12, 0x20, 0x00, 0x61, 0x0b, 0xd2, 0xaa, 0xcb, 0xd8, + 0x23, 0x25, 0xa5, 0x9b, 0x95, 0x15, 0x4e, 0xcd, 0x82, 0xc8, 0x8d, 0x23, 0xab, + 0xd1, 0xe2, 0x07, 0x70, 0xff, 0xb8, 0xaa, 0xbf, 0x83, 0xfc, 0x07, 0x34, 0x96, + 0x4c, 0xcd, 0x41, 0x1d, 0x1c, 0x93, 0x57, 0x14, 0xe2, 0x4a, 0xab, 0x56, 0x6f, + 0x4f, 0x08, 0x42, 0x40, 0x14, 0xc4, 0xec, 0xa9, 0x1b, 0x59, 0x0f, 0x08, 0x2b, + 0x47, 0x3f, 0x36, 0x1c, 0x87, 0x41, 0x5d, 0x37, 0xbd, 0x20, 0xd7, 0x0f, 0xd0, + 0xb5, 0x2b, 0x6d, 0xdf, 0x18, 0x65, 0xf7, 0x66, 0x70, 0x2e, 0x32, 0xb0, 0x5b, + 0x3c, 0xf1, 0x63, 0x0e, 0xe8, 0x59, 0x7a, 0xae, 0x19, 0x63, 0x3f, 0x35, 0x16, + 0xa8, 0x55, 0x5a, 0xc5, 0xbe, 0x32, 0xc6, 0x75, 0xbe, 0x18, 0x17, 0xef, 0xbf, + 0xfd, 0x93, 0x69, 0x04, 0xbd, 0x73, 0x4d, 0x97, 0x23, 0x3a, 0xaa, 0x38, 0x3b, + 0x41, 0xba, 0x6d, 0x27, 0xf6, 0x42, 0x84, 0x7d, 0x1e, 0xda, 0xcb, 0x4b, 0xf8, + 0x22, 0xe6, 0x70, 0x80, 0x86, 0x75, 0x18, 0xae, 0x5a, 0x8f, 0x0a, 0x43, 0xe6, + 0xed, 0x53, 0x0c, 0xb2, 0xe8, 0xae, 0x83, 0x88, 0x60, 0xad, 0xc8, 0x8a, 0xac, + 0xc7, 0xbd, 0x6a, 0x00, 0xae, 0x0c, 0x19, 0xff, 0x45, 0x33, 0xa4, 0x85, 0xef, + 0xde, 0x08, 0x2b, 0xc5, 0x21, 0x40, 0x18, 0x2b, 0x23, 0x4d, 0x1a, 0x0d, 0x0e, + 0xeb, 0xdf, 0xb9, 0x87, 0x75, 0x98, 0xe0, 0x34, 0x7f, 0xb1, 0x00, 0x1e, 0x15, + 0xb5, 0xd4, 0x44, 0x6e, 0x76, 0x6c, 0xde, 0x25, 0xef, 0x79, 0x87, 0x40, 0xe0, + 0xbd, 0xf9, 0x94, 0xd9, 0x73, 0x9b, 0xbe, 0x55, 0x38, 0xa0, 0xae, 0x0f, 0x07, + 0x6c, 0x58, 0x2c, 0x0f, 0x5b, 0xa8, 0x78, 0xb9, 0x9b, 0x82, 0x49, 0xdb, 0x1d, + 0x7e, 0x95, 0x05, 0x6c, 0x98, 0xaf, 0x08, 0x3d, 0x98, 0xcb, 0x0e, 0xd9, 0xe3, + 0xf7, 0x43, 0x6e, 0x1c, 0x76, 0x43, 0x76, 0x6f, 0x96, 0x6b, 0x83, 0xe9, 0x99, + 0x20, 0x6e, 0xbd, 0x13, 0x93, 0xb9, 0xb2, 0xa7, 0xf4, 0x14, 0x48, 0x0f, 0xa0, + 0x17, 0x48, 0x00, 0x69, 0xf8, 0x5c, 0x77, 0x49, 0xc4, 0x35, 0xae, 0x2f, 0xba, + 0x2d, 0xdc, 0x10, 0x38, 0xd5, 0x47, 0xd8, 0x48, 0x54, 0x81, 0x7e, 0xf3, 0x96, + 0x35, 0xc2, 0x98, 0x27, 0xaa, 0xd8, 0x67, 0x26, 0xc9, 0xad, 0xe3, 0xb2, 0x65, + 0xb9, 0x08, 0x6c, 0x8b, 0x5b, 0x75, 0xef, 0x56, 0xfe, 0x4b, 0xd8, 0xb4, 0xd6, + 0x28, 0x93, 0x89, 0x5b, 0x3f, 0xd2, 0x73, 0x4f, 0xda, 0xc4, 0x64, 0x15, 0x6d, + 0x7e, 0x5e, 0xbc, 0x7e, 0xcf, 0x1d, 0x83, 0xb8, 0x6f, 0x65, 0x96, 0x37, 0xe3, + 0xb1, 0x42, 0xc1, 0x64, 0x96, 0x3b, 0x8c, 0xdc, 0xf4, 0xba, 0x4f, 0x40, 0x35, + 0xdf, 0xfc, 0x5a, 0x78, 0x94, 0x58, 0x84, 0x77, 0x81, 0x91, 0x8a, 0xc7, 0x2f, + 0xc1, 0x8b, 0xbb, 0xf5, 0x11, 0x00, 0x32, 0xe6, 0x6d, 0x75, 0xb3, 0x17, 0x1e, + 0xf4, 0xb5, 0x13, 0x29, 0x01, 0x64, 0xa7, 0x7b, 0x42, 0xb0, 0xa4, 0xcf, 0xb8, + 0x96, 0x39, 0xab, 0x23, 0x84, 0x5e, 0x1a, 0xa2, 0xa4, 0x52, 0xf3, 0x73, 0x1c, + 0x8c, 0xb6, 0x50, 0x82, 0xa6, 0x22, 0xa7, 0xc2, 0xe0, 0x01, 0x3e, 0xa4, 0x7d, + 0x0b, 0xdd, 0x42, 0xd6, 0x99, 0x04, 0x66, 0x64, 0x9a, 0x90, 0x5c, 0x68, 0x4c, + 0x32, 0x51, 0x71, 0x6d, 0x61, 0xf7, 0x60, 0xd5, 0x3d, 0xe6, 0xe3, 0xf7, 0x90, + 0xfb, 0xa7, 0xf5, 0xf1, 0xf4, 0xde, 0x26, 0x71, 0x13, 0xbd, 0xfc, 0xd7, 0x42, + 0x28, 0x22, 0x33, 0x0b, 0x32, 0xd5, 0x8e, 0x67, 0x77, 0x76, 0x5f, 0x22, 0xa4, + 0x11, 0x63, 0x44, 0xee, 0xb6, 0x5b, 0x2e, 0xc5, 0x16, 0x39, 0x3a, 0xb3, 0x75, + 0x1b, 0x53, 0x56, 0xd2, 0xb0, 0xc9, 0x50, 0x0c, 0x0f, 0x3e, 0x46, 0x91, 0x81, + 0x03, 0x5b, 0xc3, 0x66, 0x0f, 0x0b, 0x8f, 0x9f, 0xbe, 0x6e, 0x40, 0xb5, 0xe8, + 0x9c, 0xb7, 0x9b, 0x06, 0x37, 0x14, 0xca, 0x75, 0xe7, 0x2e, 0x2e, 0x10, 0x0a, + 0x10, 0xd6, 0x3b, 0xf7, 0x84, 0xdf, 0x08, 0x20, 0xef, 0x25, 0xf8, 0xef, 0x40, + 0xfe, 0x5f, 0x05, 0xfb, 0x95, 0x68, 0x3f, 0x91, 0x05, 0xff, 0x3c, 0xb2, 0xd2, + 0x19, 0xab, 0x76, 0x60, 0x5a, 0x06, 0x4f, 0x69, 0x21, 0x9f, 0x1d, 0xc0, 0xd0, + 0x0b, 0x3b, 0x48, 0x64, 0x2f, 0x97, 0x0d, 0xc0, 0x0c, 0xca, 0x4b, 0x8b, 0x43, + 0x30, 0x8b, 0xe1, 0x82, 0x86, 0xec, 0x5a, 0x42, 0x88, 0xd6, 0x00, 0xa3, 0x78, + 0x5c, 0xb6, 0x22, 0xd4, 0x68, 0xa4, 0xc6, 0x96, 0x9b, 0x37, 0x92, 0xf2, 0x48, + 0x50, 0x27, 0xd0, 0xad, 0x9a, 0xa4, 0xa9, 0xc2, 0xcc, 0x97, 0x2f, 0x9e, 0xe5, + 0x19, 0x0a, 0x95, 0xb1, 0xeb, 0x05, 0x8d, 0xdd, 0xd8, 0xc0, 0x8e, 0x7d, 0x75, + 0x3f, 0x5e, 0x01, 0x1b, 0x2b, 0xcf, 0xee, 0x1d, 0x52, 0xc1, 0xc4, 0xf2, 0xca, + 0xcd, 0xa3, 0x0b, 0xdb, 0x69, 0x30, 0x65, 0x3c, 0x0c, 0xc4, 0x48, 0x6e, 0x60, + 0xe8, 0x9f, 0xa8, 0x49, 0xb3, 0x20, 0x83, 0xba, 0x9d, 0xb4, 0x53, 0xfb, 0x8d, + 0xf6, 0x83, 0xcd, 0x68, 0x75, 0x4c, 0x87, 0xda, 0xa7, 0x31, 0xf5, 0x70, 0xa7, + 0xa4, 0x06, 0x0a, 0xf0, 0xce, 0x70, 0x0d, 0x31, 0xbc, 0xa7, 0xe7, 0x4b, 0x3e, + 0x3b, 0xa3, 0xd0, 0xe8, 0xa6, 0x39, 0x2a, 0x06, 0x2b, 0x8e, 0x86, 0xd9, 0xd7, + 0xd0, 0x0b, 0x21, 0x70, 0x1e, 0x7b, 0x06, 0x2e, 0x06, 0xb1, 0xbc, 0xd8, 0x2a, + 0x01, 0xd3, 0x75, 0x62, 0x6f, 0xbf, 0x87, 0x2d, 0x27, 0xfa, 0x45, 0x11, 0xf5, + 0xf8, 0xcf, 0x8c, 0x9a, 0xbc, 0xef, 0x2a, 0x99, 0x01, 0x76, 0xae, 0x33, 0x93, + 0x25, 0xd5, 0xa5, 0x88, 0xda, 0x57, 0x96, 0xfa, 0xae, 0x5b, 0xab, 0x7c, 0x82, + 0x97, 0x7c, 0x0f, 0xf7, 0x97, 0x09, 0x3e, 0x2c, 0x1f, 0x3a, 0xe8, 0x55, 0xf6, + 0x5a, 0xea, 0x91, 0xe1, 0x31, 0x2f, 0xc6, 0xb8, 0xa4, 0x35, 0x1a, 0x2e, 0xc0, + 0x3e, 0x02, 0xe5, 0xd0, 0x2f, 0x53, 0x35, 0x4b, 0x05, 0x2f, 0xd3, 0xda, 0x0d, + 0xff, 0x82, 0xcd, 0x1f, 0x55, 0xeb, 0xca, 0x57, 0xb6, 0x33, 0x7c, 0x85, 0x93, + 0x8a, 0x79, 0x81, 0x3d, 0x20, 0x21, 0xd6, 0x09, 0x4c, 0x68, 0xb3, 0x75, 0xe9, + 0x84, 0xf6, 0x83, 0x93, 0x30, 0x08, 0x71, 0xe3, 0x48, 0xfc, 0x52, 0x36, 0xcc, + 0xa6, 0x33, 0x05, 0x44, 0xe5, 0x46, 0x39, 0xb5, 0x41, 0x87, 0x01, 0xff, 0x4c, + 0xc4, 0x5a, 0x31, 0xf6, 0x2e, 0xdd, 0x84, 0x3d, 0xbb, 0xdc, 0x5a, 0xa7, 0x27, + 0xab, 0x79, 0xb4, 0x42, 0x68, 0x3c, 0x49, 0x56, 0xbb, 0xb1, 0x95, 0xa4, 0xfa, + 0x66, 0xdc, 0x9c, 0xd5, 0x42, 0xc7, 0x6b, 0x91, 0x50, 0xc8, 0x4b, 0xf8, 0x90, + 0x78, 0x99, 0x42, 0xf5, 0x5c, 0x20, 0x0b, 0x77, 0x3e, 0xcd, 0xd7, 0x99, 0x2c, + 0xff, 0x3e, 0xca, 0x24, 0xde, 0x3e, 0x09, 0x84, 0xe1, 0x0e, 0x68, 0xae, 0x38, + 0x75, 0x34, 0xb9, 0x6c, 0xde, 0x37, 0x92, 0xf1, 0x35, 0xbf, 0x5f, 0x68, 0x78, + 0x7d, 0x37, 0x0c, 0xa8, 0xc4, 0xc4, 0x07, 0x4d, 0xc5, 0xd6, 0x01, 0xae, 0x90, + 0x49, 0x54, 0x37, 0xc3, 0xc2, 0xd4, 0x8a, 0x3d, 0x96, 0x66, 0x83, 0xac, 0x05, + 0x16, 0x0b, 0x7a, 0x84, 0xea, 0xa7, 0xaa, 0xb7, 0x40, 0x09, 0xe5, 0x7a, 0x85, + 0xf7, 0xbf, 0x68, 0xa2, 0xe4, 0x82, 0x00, 0x0f, 0x82, 0x9c, 0x54, 0x50, 0x73, + 0xa1, 0x5d, 0x5c, 0xd0, 0xfc, 0xc5, 0x74, 0x39, 0xa4, 0x35, 0x0e, 0xaf, 0x09, + 0x8d, 0xfb, 0x82, 0xa0, 0x85, 0xea, 0x8a, 0x4a, 0xf6, 0xfa, 0x83, 0x81, 0xf0, + 0x65, 0x88, 0x19, 0xea, 0xb4, 0x83, 0xf6, 0x5b, 0x32, 0x5d, 0x5a, 0xed, 0xa1, + 0x52, 0x32, 0xcf, 0xad, 0xec, 0x75, 0xab, 0x18, 0x66, 0xe4, 0xc0, 0x15, 0x5a, + 0x9c, 0x74, 0xa7, 0xa5, 0x7c, 0xcf, 0x34, 0xc4, 0x83, 0xac, 0x7d, 0xa1, 0x58, + 0x8a, 0x1b, 0x6b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0xf1, 0x10, 0x40, 0xf9, 0x4c, + 0xf7, 0x8f, 0xad, 0x89, 0xbf, 0x11, 0xfe, 0xd6, 0x9a, 0xa0, 0xd8, 0x31, 0x05, + 0xad, 0xac, 0xdd, 0x4e, 0x5f, 0x04, 0xa6, 0x24, 0x24, 0x02, 0x3c, 0x9b, 0x9e, + 0x33, 0xc4, 0xfb, 0x7f, 0x12, 0xbd, 0xf2, 0x1f, 0x07, 0xf2, 0x65, 0xc5, 0x37, + 0xd5, 0x1c, 0x65, 0x51, 0xf4, 0x61, 0x7b, 0x91, 0x5d, 0x21, 0x99, 0x18, 0x39, + 0xc3, 0xd0, 0xd3, 0x63, 0x93, 0xd6, 0x46, 0xe0, 0xa8, 0xa4, 0x15, 0x09, 0x21, + 0x7d, 0x0e, 0x7d, 0x2c, 0xa1, 0xa0, 0xa0, 0xd6, 0x77, 0xa3, 0xea, 0xca, 0x23, + 0xed, 0xeb, 0x07, 0xb7, 0x4e, 0x65, 0x2a, 0x0b, 0xc5, 0x0c, 0x6c, 0x08, 0x3a, + 0x55, 0xd6, 0xc7, 0x30, 0x6e, 0x74, 0x08, 0x6f, 0x47, 0x68, 0x93, 0x3a, 0xa2, + 0x48, 0x73, 0x68, 0x18, 0x67, 0xa7, 0x89, 0x3d, 0x77, 0xcb, 0x7f, 0x29, 0xb8, + 0xc8, 0x47, 0xc5, 0x83, 0xf2, 0xd0, 0x71, 0xa6, 0x86, 0x61, 0x6e, 0x20, 0x67, + 0x19, 0xf7, 0x61, 0xae, 0x39, 0xc1, 0x10, 0x44, 0x2e, 0x06, 0x16, 0x3d, 0x2b, + 0x84, 0x59, 0x03, 0x60, 0x69, 0x5d, 0x4e, 0x19, 0x84, 0x9e, 0x63, 0x4f, 0x24, + 0xd9, 0xad, 0x39, 0x6c, 0x19, 0xff, 0x83, 0xce, 0x74, 0xf4, 0x6e, 0x64, 0x5f, + 0x93, 0x2e, 0x14, 0x1a, 0x41, 0x19, 0x59, 0x36, 0xc8, 0x5d, 0x51, 0x44, 0x14, + 0xf1, 0x12, 0xe6, 0x0b, 0x1a, 0x25, 0x37, 0xc3, 0x8d, 0x6d, 0xc6, 0xc4, 0x63, + 0x83, 0x05, 0xc9, 0xbd, 0x6c, 0x62, 0xe3, 0x66, 0xbc, 0x63, 0x12, 0x3e, 0x3e, + 0x6d, 0xd3, 0x6e, 0xed, 0xd3, 0x13, 0x6f, 0xce, 0x8d, 0xee, 0xca, 0x2a, 0xa0, + 0x9a, 0x32, 0x98, 0xa3, 0x9d, 0x83, 0x85, 0x9e, 0xfc, 0x9b, 0x2b, 0x69, 0xcf, + 0x9a, 0x7d, 0xee, 0x08, 0xa9, 0x8e, 0x4b, 0xe5, 0x58, 0xac, 0x79, 0x12, 0xfd, + 0xcb, 0x42, 0x20, 0x90, 0x75, 0x42, 0x02, 0x60, 0xf7, 0xca, 0xd0, 0xf2, 0xc0, + 0x1f, 0x2a, 0xfe, 0x33, 0x07, 0x3f, 0x26, 0x24, 0x9d, 0x94, 0x4f, 0x7a, 0x50, + 0xdd, 0x84, 0x83, 0x9b, 0xc3, 0xea, 0x7f, 0xde, 0xe4, 0xed, 0x71, 0x44, 0x9c, + 0xf0, 0x75, 0x33, 0xd2, 0x6e, 0x1e, 0x27, 0xa3, 0xef, 0xb0, 0x32, 0xc3, 0xa3, + 0xb3, 0x4b, 0xd3, 0x09, 0x26, 0x22, 0xd2, 0x06, 0x2a, 0xe5, 0x36, 0xef, 0x51, + 0x49, 0xc4, 0x9b, 0x5b, 0xc9, 0x47, 0x5e, 0xaf, 0xab, 0x6e, 0x67, 0x57, 0x61, + 0x00, 0x8b, 0x0d, 0xad, 0xde, 0xec, 0xaa, 0x60, 0x44, 0x70, 0xbb, 0xe0, 0xfa, + 0xda, 0x25, 0x5d, 0x29, 0x0e, 0x92, 0xb1, 0x90, 0xc2, 0xc2, 0xd8, 0xc2, 0xde, + 0xe5, 0x45, 0x5d, 0x1f, 0xa9, 0xa9, 0xf3, 0xdb, 0x77, 0x79, 0xb5, 0x84, 0x64, + 0x34, 0x64, 0xaa, 0x80, 0x14, 0xba, 0x66, 0x99, 0x4d, 0xe2, 0x55, 0x17, 0xf8, + 0x39, 0x80, 0xe6, 0x6e, 0xe4, 0xf6, 0x23, 0x14, 0xae, 0x6d, 0xbe, 0xf4, 0x52, + 0xd5, 0xd3, 0x8b, 0x0a, 0x16, 0xf3, 0x99, 0x1f, 0x36, 0xd8, 0xa8, 0xb3, 0x9d, + 0xdc, 0x0d, 0x55, 0x95, 0xee, 0xd9, 0x87, 0x62, 0x87, 0x8c, 0xdf, 0x3f, 0x4a, + 0x2e, 0xdc, 0x5c, 0xda, 0x77, 0xd5, 0xfe, 0x4f, 0xaf, 0x63, 0xa1, 0x5f, 0x56, + 0x8a, 0x54, 0x0d, 0xa5, 0x7d, 0xd9, 0xbe, 0xb6, 0xfb, 0x1a, 0x97, 0x7c, 0xcb, + 0x91, 0xb4, 0xd7, 0x9c, 0xb3, 0x9b, 0x28, 0x91, 0x1a, 0x29, 0xe7, 0xbf, 0x02, + 0x8a, 0xc6, 0x10, 0x37, 0x96, 0xdf, 0xb6, 0xb2, 0x09, 0x67, 0x23, 0x9a, 0xd3, + 0x73, 0xc3, 0x8c, 0x53, 0xf6, 0xdf, 0x18, 0x23, 0xd4, 0x95, 0x0a, 0x02, 0x83, + 0xe9, 0x9b, 0x9c, 0x06, 0xab, 0x29, 0x66, 0x66, 0x7c, 0x9d, 0xf6, 0x77, 0x71, + 0x6b, 0x0c, 0xad, 0xed, 0x81, 0x8d, 0xf9, 0xe4, 0x49, 0xc0, 0x72, 0xe2, 0x2f, + 0x9d, 0x98, 0xbb, 0x0f, 0x9b, 0x03, 0xbd, 0x5f, 0xd0, 0x13, 0xfc, 0xef, 0x3e, + 0xd6, 0xa4, 0x9a, 0xeb, 0x98, 0x72, 0x02, 0x54, 0x08, 0x7e, 0xf7, 0x28, 0xe3, + 0x19, 0x47, 0xff, 0xe8, 0xf7, 0x66, 0xe6, 0x3e, 0xe4, 0x6f, 0xf2, 0x08, 0x16, + 0xd5, 0xfa, 0x8f, 0xf5, 0x5a, 0x26, 0x39, 0x89, 0x61, 0x49, 0x0a, 0xb9, 0xae, + 0x36, 0x6f, 0xc5, 0xa2, 0xd1, 0x99, 0x6e, 0xd6, 0x93, 0xcc, 0xca, 0x82, 0x35, + 0x6f, 0x60, 0x0a, 0xb0, 0x99, 0xf6, 0xec, 0xa8, 0xbf, 0xe6, 0x45, 0x27, 0x0d, + 0x3f, 0x95, 0xed, 0xba, 0x5b, 0x0d, 0xe7, 0xa3, 0x28, 0x19, 0x23, 0x3b, 0xcc, + 0x75, 0x4a, 0x5c, 0xe2, 0xe5, 0xea, 0x07, 0x84, 0x2e, 0x5f, 0xf2, 0xce, 0xbe, + 0x62, 0xad, 0x76, 0xe8, 0xef, 0xf8, 0xd1, 0x5e, 0xa4, 0xc2, 0x4a, 0x5f, 0x20, + 0x78, 0x68, 0x31, 0x9a, 0x5a, 0xf6, 0xb0, 0x35, 0xbe, 0x3f, 0x44, 0xf4, 0x34, + 0x09, 0x4f, 0x6e, 0x52, 0x5b, 0xe6, 0x14, 0xda, 0xc9, 0x20, 0xa3, 0x30, 0xbd, + 0xfb, 0x26, 0xd7, 0x5f, 0xe7, 0xb4, 0xb3, 0x65, 0xd0, 0x94, 0x45, 0x92, 0x50, + 0xaa, 0xa5, 0x54, 0x44, 0x89, 0xfb, 0x1d, 0x99, 0x25, 0x81, 0x80, 0x0a, 0x77, + 0xb8, 0x91, 0x21, 0x57, 0xfc, 0x97, 0x13, 0xaa, 0xac, 0x25, 0xb4, 0xc2, 0x6e, + 0xb0, 0x3f, 0x71, 0x66, 0x46, 0x61, 0x9a, 0xf0, 0x24, 0x56, 0xae, 0x69, 0x59, + 0x62, 0xfe, 0x5e, 0x93, 0x1a, 0x63, 0xb5, 0xc7, 0x90, 0x52, 0xec, 0xd3, 0x33, + 0xe1, 0x84, 0x12, 0xdb, 0x91, 0xe1, 0x5f, 0x7c, 0xbc, 0x70, 0xb4, 0xcd, 0x7e, + 0x8e, 0x3c, 0x95, 0x1f, 0x35, 0x85, 0x72, 0xe3, 0x77, 0x67, 0xe7, 0xd5, 0x27, + 0x04, 0xa6, 0x72, 0x1b, 0x30, 0xef, 0xc4, 0x10, 0x17, 0xae, 0x4d, 0x23, 0x15, + 0x58, 0xc5, 0xc8, 0x2c, 0xc7, 0xdd, 0x7e, 0x33, 0x56, 0xc0, 0x9d, 0xc2, 0x49, + 0x06, 0xf0, 0x43, 0x8d, 0xfc, 0xc3, 0x00, 0x85, 0x6a, 0xc2, 0xce, 0xd8, 0xf7, + 0x7f, 0xa8, 0x01, 0x57, 0x36, 0xc6, 0x61, 0xe8, 0x02, 0x48, 0xae, 0xeb, 0x77, + 0x48, 0x74, 0xaa, 0x79, 0xd2, 0x90, 0xb8, 0xf5, 0x02, 0x7a, 0x0a, 0x50, 0x95, + 0x37, 0xfc, 0x7c, 0x68, 0x9b, 0x7a, 0xd8, 0x61, 0x16, 0xcf, 0xec, 0x26, 0x47, + 0xcc, 0xaa, 0xe1, 0xc7, 0x4b, 0x41, 0x6f, 0x3e, 0x6a, 0xe8, 0xf7, 0xcc, 0x60, + 0xea, 0xaf, 0x7b, 0x6a, 0x59, 0x0d, 0x51, 0x54, 0x41, 0x38, 0xe1, 0x73, 0x29, + 0x45, 0x60, 0x3a, 0x53, 0x46, 0x2c, 0x60, 0xe1, 0xf6, 0xcb, 0x0c, 0x9c, 0xa0, + 0x39, 0x0c, 0x48, 0x82, 0x24, 0xc3, 0x13, 0x26, 0x9f, 0xcd, 0x59, 0xfc, 0xb6, + 0x11, 0xfb, 0x2d, 0x9b, 0x4c, 0x8f, 0xa6, 0x01, 0xbb, 0x1c, 0xb8, 0xd0, 0x7d, + 0x79, 0x7b, 0xf5, 0xde, 0x52, 0xbc, 0xee, 0xb0, 0x23, 0x01, 0xc8, 0x96, 0x2a, + 0xc1, 0xfc, 0x04, 0x91, 0xdc, 0x81, 0xaf, 0xfd, 0x6c, 0x1e, 0xbf, 0x89, 0xa1, + 0x3d, 0x6f, 0x29, 0x0e, 0xda, 0x5d, 0x5c, 0xef, 0x38, 0x22, 0x15, 0xc5, 0xe9, + 0x51, 0xd7, 0x13, 0x05, 0xef, 0x33, 0xd9, 0x73, 0x71, 0x26, 0xd0, 0xe6, 0x62, + 0x90, 0x5f, 0x12, 0x50, 0x92, 0x6f, 0x6a, 0x22, 0x99, 0x90, 0xe3, 0x8f, 0x69, + 0xad, 0x9a, 0x91, 0x92, 0xb3, 0x02, 0xf2, 0x6b, 0xdd, 0xa4, 0x65, 0xd9, 0x0b, + 0x94, 0xb1, 0x2c, 0x57, 0xfa, 0x3f, 0xd6, 0x93, 0x00, 0x83, 0xf1, 0x84, 0x43, + 0x8d, 0x8a, 0x88, 0x9d, 0x3f, 0x5e, 0xce, 0xa2, 0xc6, 0xd2, 0x3d, 0x67, 0x36, + 0xf2, 0xa0, 0xf1, 0x8e, 0x26, 0xf4, 0xfa, 0x45, 0xd1, 0xbe, 0x8f, 0x3d, 0xc4, + 0xa7, 0x07, 0x13, 0x7e, 0x95, 0xd2, 0xad, 0x59, 0x4f, 0x6c, 0x03, 0xd2, 0x49, + 0x23, 0x06, 0x7a, 0xe4, 0x7f, 0xd6, 0x42, 0x5e, 0xfb, 0x9c, 0x1d, 0x50, 0x4e, + 0x6f, 0xd5, 0x57, 0x53, 0x40, 0x94, 0x56, 0x01, 0xfe, 0x80, 0x6f, 0x57, 0x56, + 0xac, 0xb5, 0x62, 0xf1, 0x3c, 0x0c, 0xa1, 0xd8, 0x03, 0xa1, 0x95, 0xc2, 0xeb, + 0xb2, 0xef, 0x02, 0xac, 0x33, 0xe6, 0xa8, 0x8d, 0xea, 0x07, 0x5b, 0xa9, 0x96, + 0xd3, 0xc3, 0x36, 0x64, 0x8e, 0x86, 0x94, 0xd3, 0xa1, 0x9d, 0x3d, 0xca, 0x53, + 0x1b, 0xeb, 0x50, 0xd4, 0x32, 0x7c, 0x5c, 0x0c, 0x23, 0xcb, 0x7c, 0xfd, 0xb0, + 0x8c, 0xa7, 0xcf, 0x2c, 0xac, 0x6b, 0xc1, 0x39, 0xd0, 0x74, 0x14, 0x73, 0xd3, + 0x76, 0x02, 0x9c, 0xb4, 0xab, 0x6b, 0xf0, 0x54, 0x55, 0x7c, 0xe2, 0x94, 0xc7, + 0x28, 0xa4, 0x68, 0x7d, 0x57, 0xec, 0x89, 0x09, 0xff, 0x51, 0xa4, 0xd0, 0x2f, + 0x9d, 0xcd, 0x11, 0x19, 0x3d, 0x7d, 0x1c, 0x9f, 0xda, 0xe6, 0xa1, 0x73, 0x96, + 0xa1, 0xbf, 0x57, 0xa9, 0x94, 0x93, 0x4f, 0x5e, 0x7a, 0x59, 0xf0, 0x45, 0xde, + 0xbe, 0xaf, 0xf6, 0x2e, 0xf3, 0x26, 0xb9, 0x47, 0xf2, 0xa8, 0xb4, 0x95, 0x55, + 0xe4, 0xd9, 0x9b, 0x3b, 0xf5, 0xc8, 0x1f, 0xf9, 0xfe, 0x31, 0x4e, 0x04, 0x7a, + 0xf1, 0x52, 0x50, 0x8f, 0x57, 0x01, 0x5c, 0xa4, 0x02, 0xc6, 0x7d, 0x92, 0x5c, + 0x99, 0xac, 0xea, 0x3e, 0xe8, 0xcc, 0x4b, 0x00, 0x8c, 0x5c, 0xb4, 0x39, 0x66, + 0xe7, 0x14, 0xef, 0x48, 0x0f, 0xd0, 0x5e, 0x07, 0xc7, 0xb2, 0xdd, 0xa9, 0xaa, + 0x39, 0x66, 0x11, 0x3e, 0xaa, 0x29, 0x3d, 0x3f, 0x62, 0x2b, 0x30, 0x9d, 0x64, + 0x80, 0x3c, 0xe1, 0xe6, 0x37, 0x8b, 0x6a, 0xac, 0x4f, 0xab, 0x52, 0x7c, 0x43, + 0xcd, 0x45, 0xed, 0x0a, 0x3c, 0x1a, 0x4b, 0x9f, 0xb1, 0x8d, 0xcc, 0xcf, 0xcd, + 0xb6, 0xac, 0x0c, 0x24, 0x21, 0x63, 0x9c, 0xda, 0x00, 0x75, 0xa2, 0x0d, 0xc5, + 0x11, 0x1b, 0x8d, 0x3d, 0x31, 0x99, 0x49, 0x5b, 0xd9, 0x13, 0x3d, 0xba, 0xb9, + 0x45, 0x41, 0x41, 0x0e, 0x4f, 0xba, 0x92, 0xc7, 0xb6, 0x06, 0xa5, 0xcb, 0x12, + 0x2f, 0x14, 0x0c, 0xf1, 0xa3, 0x59, 0x6f, 0x27, 0x88, 0xf3, 0xc8, 0xb9, 0x26, + 0x60, 0xf1, 0x4c, 0xb6, 0x5a, 0xf5, 0xdd, 0x23, 0xdf, 0xdb, 0xac, 0x13, 0x71, + 0xec, 0xf4, 0xb3, 0x37, 0x12, 0xfe, 0xd2, 0x29, 0x2c, 0x44, 0xf7, 0x08, 0x34, + 0xcf, 0x96, 0xc0, 0x5d, 0x58, 0x82, 0x7e, 0x69, 0xbf, 0xc2, 0xe6, 0x96, 0xfa, + 0x08, 0x74, 0x86, 0x9c, 0x02, 0xf3, 0xdc, 0xa1, 0x1c, 0x3b, 0x90, 0xcb, 0x21, + 0x4e, 0x68, 0xbc, 0x1c, 0xae, 0x03, 0x9d, 0x7a, 0x14, 0x6c, 0xdc, 0x1d, 0x60, + 0x9d, 0x7a, 0x6b, 0x3f, 0xd5, 0xd4, 0x61, 0xb0, 0x95, 0x1c, 0x82, 0xcf, 0xb3, + 0xe7, 0x63, 0xfa, 0xd2, 0xd1, 0xbc, 0x76, 0x78, 0xcd, 0xf8, 0x27, 0x79, 0xf8, + 0xfd, 0x5a, 0x1c, 0xe2, 0x2a, 0x8d, 0x3c, 0x45, 0x47, 0xab, 0xd9, 0x59, 0x83, + 0x8a, 0x46, 0xfb, 0x80, 0xaf, 0xe0, 0x1f, 0x8e, 0xcc, 0x99, 0x31, 0x51, 0x3b, + 0x19, 0x62, 0xec, 0x54, 0x08, 0x56, 0xcb, 0x18, 0x93, 0x87, 0xcf, 0xbf, 0xcc, + 0x0f, 0x7c, 0x68, 0x22, 0x3c, 0xba, 0x47, 0xfb, 0x0c, 0x9b, 0x48, 0x6e, 0x4d, + 0x99, 0x17, 0x19, 0x41, 0xf7, 0x67, 0x5a, 0x8b, 0x46, 0x32, 0x8a, 0x3b, 0xc1, + 0x09, 0xbf, 0x07, 0xc6, 0x6d, 0x5e, 0xde, 0x77, 0x1c, 0xc4, 0xc7, 0x4c, 0xe8, + 0x03, 0x33, 0x82, 0x91, 0x91, 0xee, 0xdc, 0x49, 0x35, 0x08, 0xa6, 0x44, 0x53, + 0x0a, 0x61, 0x44, 0xf2, 0x2d, 0xcf, 0x97, 0x52, 0x5a, 0x4c, 0xdc, 0xa1, 0xad, + 0x71, 0x07, 0x3b, 0x08, 0x0b, 0x73, 0xea, 0x45, 0x49, 0xf5, 0x40, 0x1b, 0xff, + 0x43, 0x18, 0x26, 0x8e, 0x6a, 0xd6, 0x37, 0x36, 0x31, 0x57, 0xa1, 0x9a, 0x53, + 0xf1, 0x23, 0xa0, 0xb0, 0xe1, 0x6d, 0x0b, 0x77, 0xf0, 0x20, 0x28, 0xda, 0x46, + 0x41, 0x00, 0xfd, 0xe7, 0x6d, 0x83, 0xdd, 0x0b, 0xb2, 0x24, 0xf7, 0xb5, 0x7a, + 0x00, 0xc0, 0x2f, 0x68, 0xae, 0x64, 0x8f, 0xdc, 0x52, 0x99, 0x57, 0xa1, 0x04, + 0x90, 0xdc, 0xe1, 0xfd, 0xdb, 0xb0, 0x90, 0x4f, 0x0d, 0x51, 0x8b, 0xb3, 0x87, + 0x54, 0x40, 0x19, 0x98, 0x3b, 0x61, 0x69, 0x75, 0xa7, 0x8e, 0x74, 0xd8, 0x54, + 0xfd, 0xdc, 0x49, 0xb2, 0x55, 0x16, 0x7b, 0x55, 0xef, 0x4b, 0xee, 0x46, 0x56, + 0x68, 0xb2, 0x0e, 0xa4, 0x11, 0x8c, 0xa5, 0x69, 0xae, 0x48, 0x0e, 0x0f, 0x6e, + 0x5e, 0x04, 0x3a, 0x35, 0x7b, 0x36, 0xd3, 0xab, 0x36, 0xc8, 0x61, 0xf2, 0x27, + 0x83, 0x01, 0xdc, 0xe5, 0x76, 0x74, 0xd5, 0x07, 0x3b, 0x3a, 0x6f, 0x51, 0x03, + 0xa0, 0x79, 0x3a, 0xf1, 0xb7, 0xd4, 0x6f, 0x95, 0x7e, 0x22, 0xd8, 0xd2, 0x58, + 0x3b, 0xf1, 0x81, 0x83, 0x6c, 0x3b, 0xe9, 0x93, 0x0b, 0xac, 0x8f, 0xa4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x60, 0xe9, 0x68, 0xaa, 0x71, 0x09, 0x87, 0x0b, 0xbe, 0xd1, 0x7d, + 0xf5, 0xf8, 0x88, 0xc8, 0xca, 0x14, 0x67, 0xae, 0x17, 0xdb, 0xbc, 0xde, 0x31, + 0xc1, 0x10, 0x5c, 0xb5, 0xbd, 0xa8, 0x8a, 0xc6, 0xc6, 0x27, 0x00, 0x2c, 0xe2, + 0x1c, 0x02, 0x14, 0x0f, 0xfe, 0x81, 0xec, 0x58, 0xbf, 0x1e, 0x6d, 0x1b, 0xb7, + 0xaa, 0xad, 0xa4, 0x1f, 0xba, 0x0b, 0xb5, 0x88, 0x77, 0x8a, 0x7f, 0x65, 0x20, + 0x2a, 0xd8, 0x11, 0xea, 0x73, 0xd2, 0x6c, 0x74, 0x55, 0x03, 0x95, 0xaf, 0xf7, + 0x53, 0x25, 0x10, 0x7c, 0x9b, 0x3f, 0x9a, 0xe9, 0xdc, 0xdc, 0xd8, 0x6e, 0xd0, + 0x81, 0xa2, 0xe7, 0x42, 0x47, 0x19, 0xa3, 0xd1, 0x85, 0xb7, 0xe0, 0xa4, 0x3a, + 0x47, 0x2e, 0x29, 0x8a, 0xc0, 0xaf, 0xdc, 0x52, 0x87, 0xd7, 0xad, 0x12, 0x4c, + 0xd9, 0x40, 0x5a, 0x62, 0xcd, 0x1c, 0xa0, 0x8b, 0x28, 0x2e, 0xfe, 0xf7, 0xf9, + 0x28, 0xdf, 0x76, 0xe2, 0x82, 0x1a, 0x41, 0x84, 0x13, 0xeb, 0x7c, 0xea, 0xa5, + 0xff, 0x12, 0x90, 0xb0, 0x3e, 0xc9, 0x1c, 0xe6, 0xdd, 0x28, 0x13, 0x0c, 0x3a, + 0xb0, 0xb2, 0x3b, 0x60, 0x2b, 0xd5, 0xbe, 0x5d, 0xc2, 0x60, 0x03, 0xaa, 0xe0, + 0x4b, 0x33, 0xd7, 0xbd, 0x25, 0x90, 0xe9, 0x0c, 0x8c, 0x38, 0x8e, 0xa7, 0x95, + 0x51, 0x22, 0xdb, 0xac, 0xa6, 0x7b, 0x30, 0x39, 0x5a, 0x92, 0x8b, 0x57, 0xb8, + 0x57, 0x51, 0x23, 0x20, 0x5a, 0xe1, 0x91, 0x52, 0xe4, 0x1e, 0x00, 0x29, 0x31, + 0xb4, 0x57, 0x46, 0x19, 0x8e, 0x5d, 0xd9, 0x57, 0x1a, 0x56, 0xa7, 0xe0, 0xd4, + 0x23, 0xff, 0x27, 0x98, 0x9d, 0x3e, 0xb4, 0x17, 0xec, 0xd3, 0xc3, 0x09, 0x3f, + 0xb8, 0x2c, 0x56, 0x58, 0xe2, 0x96, 0x24, 0xc5, 0x32, 0x19, 0xa6, 0x0c, 0xd0, + 0xa8, 0xc4, 0xda, 0x36, 0x7e, 0x29, 0xa7, 0x17, 0x79, 0xa7, 0x30, 0x32, 0x98, + 0x5a, 0x3d, 0x1f, 0xd0, 0x3d, 0xd4, 0xd0, 0x6e, 0x05, 0x56, 0x6f, 0x3b, 0x84, + 0x36, 0x7c, 0xf0, 0xfa, 0xee, 0x9b, 0xc3, 0xbd, 0x7a, 0x3a, 0x60, 0x6a, 0x9f, + 0xdb, 0x84, 0x9c, 0x5d, 0x82, 0xd0, 0xa6, 0x19, 0x23, 0xc2, 0xe5, 0xd8, 0xaa, + 0x63, 0xa8, 0xa5, 0x0c, 0x38, 0xbd, 0x03, 0x87, 0x72, 0xc4, 0x14, 0x3d, 0x8b, + 0x7a, 0xcf, 0xd7, 0x4e, 0x72, 0xc0, 0x4d, 0x89, 0x24, 0x8d, 0xff, 0x20, 0xfe, + 0x8d, 0xc5, 0xec, 0x21, 0x49, 0x05, 0x4e, 0xa2, 0x41, 0x64, 0xe8, 0x5f, 0x67, + 0x44, 0xad, 0x0c, 0xac, 0xf1, 0xa8, 0xb7, 0x01, 0x26, 0xf4, 0x82, 0xc0, 0x92, + 0xed, 0x9f, 0x61, 0x27, 0xd2, 0x05, 0x0d, 0x12, 0xe8, 0x78, 0xa7, 0x96, 0x53, + 0xa1, 0xe8, 0x4d, 0xae, 0xc3, 0xeb, 0xe6, 0x2d, 0x5f, 0x6c, 0x4a, 0xbe, 0x5c, + 0xe9, 0x0a, 0x7f, 0xe2, 0xe5, 0x2a, 0x8d, 0x78, 0x46, 0xe8, 0xed, 0xf2, 0xf2, + 0xbc, 0xe0, 0x5a, 0x03, 0x7c, 0x82, 0x6f, 0x22, 0xca, 0xad, 0x12, 0x61, 0x46, + 0x7d, 0xcf, 0xb7, 0xd6, 0xb6, 0x13, 0x3d, 0xc2, 0x1e, 0x80, 0x96, 0xc7, 0xe9, + 0xf8, 0xe9, 0xe1, 0x0c, 0x1e, 0x3f, 0xac, 0x40, 0x58, 0xb6, 0x82, 0xc6, 0x8e, + 0x54, 0xfa, 0xca, 0xe0, 0xf9, 0xc2, 0xdd, 0x4d, 0x64, 0xd9, 0x04, 0x61, 0x52, + 0xb4, 0x76, 0x23, 0x32, 0x93, 0x9f, 0x17, 0xe6, 0xaa, 0xf7, 0xd8, 0xb9, 0xd3, + 0x58, 0xe2, 0x21, 0x8d, 0x4e, 0x0d, 0x69, 0xa4, 0xf1, 0x19, 0xe1, 0xc6, 0x4e, + 0xec, 0x4c, 0x8b, 0x53, 0x28, 0x09, 0x70, 0x71, 0x31, 0xf0, 0x1f, 0x55, 0xc7, + 0xad, 0x04, 0xcf, 0xb6, 0x3f, 0x7c, 0x4a, 0x3d, 0x0a, 0x2b, 0x0f, 0xfb, 0x0b, + 0x05, 0xa6, 0xbe, 0x05, 0x5b, 0x8c, 0x94, 0xca, 0x80, 0xbb, 0x0a, 0x1d, 0x13, + 0xcd, 0x4c, 0xd6, 0x9a, 0xb9, 0x83, 0x04, 0xae, 0x25, 0x15, 0xd5, 0xf7, 0x69, + 0x9d, 0x4a, 0xbe, 0xe5, 0xc2, 0x0b, 0xe6, 0x09, 0xd8, 0x73, 0x51, 0x10, 0x12, + 0xf2, 0x34, 0xbd, 0x85, 0xa7, 0xef, 0xf5, 0xfb, 0x63, 0x4c, 0xff, 0x26, 0x58, + 0xba, 0x65, 0x16, 0x04, 0x85, 0x63, 0x09, 0x5e, 0xce, 0xfb, 0x30, 0x15, 0xee, + 0x3f, 0x03, 0xca, 0x52, 0xa1, 0x77, 0xf2, 0x61, 0xec, 0xdc, 0x26, 0xbc, 0x08, + 0x9d, 0x34, 0xc6, 0x40, 0x48, 0x46, 0xe9, 0xc6, 0x47, 0xfc, 0xfe, 0x98, 0xcc, + 0x6a, 0xcd, 0xbb, 0x46, 0x4f, 0x64, 0x27, 0x8a, 0xd8, 0xce, 0x9d, 0x1a, 0xe0, + 0xd4, 0x15, 0xbc, 0x0c, 0x05, 0x24, 0x5f, 0xdd, 0xaf, 0x4e, 0xbc, 0x8d, 0xc7, + 0x03, 0xa8, 0x5c, 0xb2, 0x70, 0xf7, 0x96, 0xad, 0x2d, 0x93, 0x7e, 0x2a, 0xc0, + 0xd5, 0xe0, 0xa3, 0x48, 0x21, 0x75, 0x80, 0x00, 0xaa, 0x59, 0xc9, 0xd4, 0x65, + 0x24, 0x85, 0x29, 0x4e, 0xe0, 0xab, 0x29, 0x69, 0x6b, 0x21, 0x43, 0x0f, 0xa5, + 0x4d, 0xcf, 0xbf, 0x2b, 0x9c, 0x49, 0xd1, 0x42, 0x06, 0x42, 0x09, 0xee, 0xee, + 0xd4, 0xd4, 0x71, 0xff, 0xc0, 0x17, 0xd4, 0xe2, 0x0a, 0x79, 0x6b, 0x09, 0x27, + 0x80, 0x4c, 0x06, 0x1b, 0x9f, 0x4a, 0x70, 0x91, 0xfe, 0x01, 0x5a, 0xda, 0x68, + 0xfd, 0x84, 0x42, 0xe0, 0x18, 0x25, 0xc8, 0x8d, 0xfe, 0x55, 0xcf, 0x5d, 0xe3, + 0x89, 0x36, 0xf7, 0xce, 0x25, 0x31, 0x1b, 0x90, 0x2b, 0xa9, 0x7a, 0x3c, 0x12, + 0xa9, 0x5c, 0xfa, 0x1c, 0x3a, 0x59, 0x1b, 0x81, 0x8f, 0x60, 0x83, 0x27, 0x09, + 0xd9, 0xe4, 0x83, 0x9e, 0x41, 0x0f, 0xb3, 0x6b, 0x84, 0xf3, 0xac, 0x4f, 0x07, + 0x0f, 0xc3, 0x5e, 0x16, 0x19, 0x78, 0x25, 0x9e, 0x5b, 0x8e, 0xdc, 0x74, 0x4d, + 0x90, 0x91, 0x9a, 0xa7, 0x70, 0xbb, 0x36, 0x21, 0x51, 0x28, 0xe5, 0x82, 0xb5, + 0x96, 0x41, 0xe2, 0x38, 0x52, 0xe9, 0x58, 0xeb, 0x8f, 0xc3, 0xc0, 0xaa, 0x96, + 0x15, 0x2b, 0xa4, 0xf7, 0x7f, 0x13, 0x8d, 0x6a, 0x67, 0x12, 0xa3, 0xae, 0x32, + 0x26, 0x01, 0x58, 0x83, 0xf8, 0x1d, 0xb2, 0x3e, 0x58, 0x3c, 0x86, 0x9c, 0x4c, + 0x71, 0x14, 0x3a, 0x6f, 0xff, 0xd6, 0x5e, 0x8d, 0xfd, 0xc5, 0x0c, 0x99, 0xa2, + 0xf1, 0xf3, 0x14, 0xcd, 0xcc, 0x71, 0x35, 0x9e, 0x23, 0x5f, 0x1d, 0x7d, 0xc2, + 0xb5, 0xf3, 0x8e, 0xf7, 0xb9, 0x70, 0x84, 0x31, 0x63, 0xc0, 0x3f, 0x9d, 0xd4, + 0x0a, 0x80, 0x15, 0xef, 0xdc, 0x87, 0x91, 0x95, 0x6a, 0x3f, 0x3c, 0xed, 0xd9, + 0xea, 0x64, 0xf8, 0xef, 0xa7, 0xa0, 0x81, 0x5a, 0x70, 0x38, 0x1d, 0x71, 0x46, + 0x78, 0x17, 0xbd, 0x04, 0xca, 0x52, 0x9a, 0xed, 0xe0, 0x7f, 0xf6, 0x0d, 0x17, + 0x6a, 0xed, 0x0f, 0x85, 0x5a, 0x2e, 0xae, 0xa8, 0x9e, 0xae, 0xac, 0xa8, 0x93, + 0x58, 0xc0, 0x81, 0x82, 0x6a, 0x08, 0x12, 0xa5, 0xbc, 0xa2, 0x8b, 0xe1, 0x37, + 0x3f, 0x08, 0x6d, 0xbd, 0xba, 0x7e, 0x43, 0xe2, 0x03, 0x21, 0x2c, 0x9f, 0xed, + 0x21, 0x47, 0x4b, 0xa1, 0x9a, 0x05, 0x5f, 0xfc, 0xc1, 0x79, 0x41, 0x2e, 0x89, + 0x3a, 0x74, 0x48, 0x32, 0x29, 0x8c, 0x5f, 0xe2, 0x4c, 0xc6, 0xb1, 0x86, 0x67, + 0xf4, 0x9b, 0x34, 0xdf, 0xb1, 0x23, 0x79, 0x26, 0x74, 0x19, 0xa9, 0xcb, 0x94, + 0x03, 0xd8, 0x16, 0x7d, 0x8d, 0x1e, 0x91, 0xd2, 0x81, 0x1a, 0x04, 0x3b, 0x29, + 0x24, 0x3b, 0x06, 0x9b, 0x37, 0x58, 0x78, 0x47, 0xdc, 0x6f, 0xcd, 0xdb, 0x18, + 0x31, 0xbd, 0x1c, 0xc2, 0x56, 0x7c, 0xa0, 0x33, 0xac, 0x40, 0xf7, 0x4a, 0xb6, + 0x95, 0x5f, 0x68, 0x3b, 0x12, 0xe4, 0xe8, 0x25, 0x4e, 0x4e, 0xa7, 0x60, 0xd3, + 0x8b, 0x3f, 0x46, 0x79, 0x1c, 0x5c, 0x4c, 0xb1, 0x2b, 0xc7, 0xcc, 0xb0, 0xed, + 0x18, 0x65, 0xf2, 0x5d, 0x60, 0x1c, 0x30, 0x3f, 0x81, 0xfb, 0x1f, 0xa1, 0xdb, + 0x48, 0x53, 0x3d, 0x3d, 0x6b, 0x28, 0x8e, 0x4d, 0x9a, 0x4d, 0xff, 0x8e, 0xc2, + 0x1c, 0x96, 0xf5, 0x78, 0x39, 0x97, 0x10, 0xc8, 0x25, 0xfe, 0x7e, 0x32, 0xf9, + 0x3a, 0x8c, 0x07, 0x43, 0xf9, 0xeb, 0xd5, 0x4c, 0xc1, 0x51, 0xc7, 0x61, 0x03, + 0x37, 0xae, 0xbf, 0x7e, 0x9b, 0x91, 0x57, 0x20, 0xa5, 0x43, 0x51, 0xd4, 0x9a, + 0xb8, 0xc2, 0x2f, 0xa3, 0x49, 0x98, 0xdc, 0xf5, 0x83, 0xd4, 0x38, 0x73, 0x61, + 0xef, 0x3f, 0xf8, 0x6f, 0x50, 0xec, 0x53, 0xf4, 0x92, 0x49, 0xe4, 0xad, 0x34, + 0x96, 0x03, 0x06, 0x6f, 0xc9, 0xc6, 0x61, 0xd6, 0x9f, 0x91, 0x1d, 0xfa, 0x72, + 0x41, 0xc8, 0xd5, 0x79, 0x2d, 0x43, 0xc4, 0x57, 0xd5, 0xde, 0x96, 0x52, 0x3a, + 0x53, 0xd6, 0x67, 0xec, 0x5c, 0x4e, 0xf9, 0xd5, 0x02, 0xa1, 0x6f, 0x15, 0x22, + 0x47, 0x58, 0x96, 0xd7, 0x9b, 0xc5, 0x78, 0x33, 0xe9, 0x77, 0x17, 0x1c, 0x32, + 0x4d, 0xce, 0x2a, 0x1e, 0xa1, 0xe4, 0x30, 0x4f, 0x49, 0xe4, 0x3a, 0xe0, 0x65, + 0xe3, 0xfb, 0x19, 0x6f, 0x76, 0xd9, 0xb8, 0x79, 0xc7, 0x20, 0x08, 0x62, 0xea, + 0xd1, 0x8d, 0xea, 0x5f, 0xb6, 0xa1, 0x7a, 0xce, 0xa3, 0x33, 0x86, 0xeb, 0x4c, + 0xa1, 0xb5, 0x14, 0x86, 0xa9, 0x14, 0x8f, 0xbd, 0xf9, 0xa9, 0x53, 0x32, 0xaa, + 0x60, 0x5c, 0x5d, 0x54, 0x83, 0xce, 0x4b, 0xa8, 0xec, 0xe0, 0x1a, 0x8f, 0xf2, + 0xb7, 0xef, 0x82, 0xd0, 0x5c, 0x0b, 0x6e, 0x86, 0x1b, 0x91, 0x5f, 0x13, 0xca, + 0x0e, 0xb3, 0xea, 0x13, 0xd5, 0x07, 0x08, 0x07, 0xa2, 0xcb, 0x66, 0x80, 0xa2, + 0x49, 0xea, 0x9c, 0x72, 0x24, 0x39, 0x2c, 0xbc, 0x8a, 0xb8, 0x25, 0x01, 0xb2, + 0x6f, 0x11, 0x2a, 0xc7, 0x89, 0xa1, 0x2a, 0x31, 0xad, 0x13, 0x14, 0xe2, 0xed, + 0xe0, 0x8f, 0xad, 0x31, 0x43, 0xaf, 0x30, 0xc2, 0x7f, 0x40, 0x3b, 0xc8, 0x66, + 0xc7, 0x55, 0x17, 0x78, 0x52, 0xaf, 0xd0, 0xab, 0xb9, 0x0a, 0xde, 0x1d, 0x68, + 0x27, 0x26, 0xf4, 0x20, 0x08, 0xb4, 0x6a, 0xd7, 0xf8, 0xab, 0xdb, 0x18, 0x11, + 0x7f, 0x72, 0x64, 0x13, 0x90, 0xf0, 0x86, 0xb6, 0xe1, 0x49, 0x8b, 0xe6, 0x95, + 0x48, 0x52, 0x7e, 0x6a, 0xda, 0x2b, 0x38, 0xb9, 0xfe, 0x12, 0x1e, 0xf6, 0x70, + 0xaf, 0x74, 0x37, 0xd3, 0x25, 0x36, 0xd5, 0xcf, 0x5c, 0x4a, 0xb1, 0x9d, 0xd9, + 0x97, 0x71, 0x58, 0x2d, 0x03, 0x81, 0x04, 0xb7, 0xe0, 0x39, 0xa3, 0x76, 0xf7, + 0xac, 0xbb, 0xea, 0xdb, 0x34, 0xf9, 0x45, 0xbe, 0xb9, 0xd7, 0xca, 0x0e, 0x4e, + 0x3d, 0x5c, 0x5e, 0x4e, 0xb1, 0xd8, 0x52, 0x6e, 0xbd, 0x13, 0xda, 0xcb, 0x1b, + 0xa3, 0x57, 0x35, 0xc6, 0xd0, 0x4a, 0x45, 0x55, 0xac, 0xf4, 0xbf, 0x11, 0x76, + 0x26, 0x50, 0x0d, 0x77, 0xb3, 0x81, 0x89, 0xdd, 0x48, 0x88, 0x04, 0x12, 0x25, + 0xac, 0xbe, 0x38, 0x74, 0xa4, 0xc0, 0xf6, 0x07, 0xfe, 0x67, 0x45, 0xf9, 0x35, + 0x5b, 0x3f, 0xa1, 0x88, 0xf1, 0xd6, 0x5c, 0x09, 0xf3, 0x89, 0xaf, 0x1b, 0x9d, + 0x62, 0x32, 0xaa, 0x79, 0x44, 0x79, 0x19, 0xc5, 0x50, 0xf6, 0xf3, 0x1f, 0xec, + 0x35, 0x48, 0x1c, 0xb9, 0x22, 0xde, 0x2d, 0xb5, 0xb4, 0xda, 0x2f, 0x81, 0x94, + 0x86, 0x17, 0x02, 0x8e, 0x32, 0x17, 0x06, 0xa3, 0xa7, 0x78, 0xc1, 0x93, 0x8c, + 0x44, 0x3b, 0xb0, 0x0e, 0x5b, 0x0f, 0xf0, 0x6a, 0xd8, 0xab, 0x9b, 0x1a, 0xb0, + 0xc1, 0x14, 0x77, 0x67, 0x3f, 0x85, 0xdf, 0x95, 0x61, 0xdb, 0xea, 0x45, 0xd5, + 0xf9, 0x78, 0x1e, 0xbe, 0x31, 0x7a, 0x07, 0x10, 0xae, 0x54, 0x61, 0xe3, 0x4f, + 0xe6, 0xf1, 0xb1, 0xaa, 0x9b, 0x4e, 0x67, 0xb1, 0x49, 0x10, 0x98, 0x48, 0x02, + 0xc2, 0xa7, 0xe3, 0x81, 0x93, 0xbc, 0x7b, 0xdc, 0x8b, 0xa3, 0xe4, 0xe3, 0xd1, + 0xd9, 0x33, 0xbf, 0xb5, 0x80, 0xf5, 0xb3, 0xe8, 0x7a, 0x2a, 0x06, 0x51, 0x70, + 0x51, 0x41, 0x0f, 0xe1, 0xb4, 0xff, 0x1e, 0xa0, 0xad, 0xe8, 0x24, 0xf3, 0x38, + 0x51, 0x54, 0x56, 0xa5, 0x7c, 0x7a, 0x91, 0x6a, 0x74, 0x38, 0x8e, 0xe8, 0xf1, + 0x28, 0x1f, 0x9a, 0xde, 0x0a, 0xe2, 0xa2, 0x61, 0x3a, 0x06, 0x12, 0xc4, 0x69, + 0xdf, 0x79, 0x2b, 0x8d, 0xf4, 0xca, 0xe4, 0xfc, 0x25, 0xc1, 0xca, 0xdb, 0xa9, + 0x5a, 0x80, 0x7c, 0xe6, 0x1e, 0x5a, 0x53, 0x03, 0xfa, 0xaf, 0x9e, 0x14, 0x65, + 0x39, 0x96, 0xb5, 0xa8, 0xad, 0xc3, 0x4f, 0xd4, 0x75, 0xef, 0x14, 0x99, 0x09, + 0x4b, 0xab, 0xaf, 0x1f, 0x3f, 0x07, 0xda, 0x9a, 0x39, 0x0b, 0x1d, 0x9f, 0xc9, + 0xa0, 0x83, 0x27, 0x98, 0x7a, 0xdf, 0xe9, 0x56, 0x48, 0x63, 0xfb, 0xdf, 0xa8, + 0xf6, 0xb4, 0x6a, 0x88, 0x41, 0x58, 0x30, 0x99, 0xaf, 0xb7, 0x87, 0x01, 0x18, + 0xfa, 0xce, 0x76, 0x34, 0x7e, 0x40, 0xb6, 0xfd, 0x8c, 0xd1, 0x55, 0x82, 0xae, + 0x8e, 0x23, 0xbe, 0x9a, 0x02, 0x19, 0xbc, 0x3e, 0x4e, 0x45, 0x46, 0xa3, 0x0d, + 0x3b, 0xbb, 0xbd, 0x16, 0x86, 0x08, 0x68, 0x76, 0xbe, 0x0e, 0x4c, 0x85, 0x9b, + 0xe7, 0x1f, 0xb5, 0x8f, 0x4f, 0xab, 0x3d, 0x28, 0xc0, 0xb4, 0xf7, 0xe7, 0x5a, + 0xd1, 0xed, 0xb7, 0xf8, 0x89, 0x46, 0xfb, 0x40, 0xcf, 0xa5, 0x78, 0x6a, 0x0f, + 0xcb, 0xa1, 0x30, 0x3c, 0x83, 0x47, 0xec, 0xee, 0x93, 0xd4, 0x6d, 0x14, 0x0b, + 0xb5, 0xf6, 0x95, 0x31, 0xd6, 0x66, 0x54, 0x8b, 0x10, 0x9c, 0xe7, 0x64, 0xbe, + 0xad, 0x7c, 0x87, 0xbd, 0x4c, 0x87, 0x64, 0x94, 0xde, 0x82, 0xdb, 0x6e, 0x50, + 0x73, 0xa6, 0xc9, 0x4f, 0x7c, 0x09, 0x9a, 0x40, 0xd7, 0xa3, 0x1c, 0x4a, 0x04, + 0xb6, 0x9c, 0x9f, 0xcc, 0xf3, 0xc7, 0xdd, 0x56, 0xf5, 0x54, 0x47, 0x76, 0xc5, + 0x3b, 0x4d, 0xf7, 0x95, 0x39, 0x81, 0xd5, 0x5a, 0x96, 0xa6, 0xdc, 0xff, 0x99, + 0x04, 0xa9, 0x08, 0x42, 0xe5, 0xba, 0xfe, 0xc8, 0x84, 0x0c, 0x2d, + ], + script_code: Script(vec![0x53, 0x63, 0x63, 0x51, 0xac, 0x00, 0x51]), + transparent_input: None, + hash_type: 1, + amount: 1345602751504862, + consensus_branch_id: consensus::BranchId::Sapling, + sighash: [ + 0x15, 0x53, 0xd4, 0xf1, 0x07, 0x45, 0x10, 0x71, 0x81, 0x99, 0x00, 0x5f, 0xef, + 0xaa, 0xa8, 0x3e, 0x29, 0xd1, 0x63, 0xee, 0xbd, 0xf3, 0xc0, 0x33, 0x82, 0x79, + 0x08, 0xac, 0xb4, 0x6f, 0xa2, 0x4b, + ], + }, + Test0243Vector { + tx: vec![ + 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x00, 0x01, 0x13, 0xf9, 0x12, + 0xa5, 0xdc, 0x0e, 0x00, 0x00, 0x09, 0x53, 0x53, 0xac, 0x63, 0x6a, 0x53, 0x63, + 0xac, 0x6a, 0x2f, 0x2c, 0x3b, 0x86, 0x0e, 0x40, 0xe3, 0x1c, 0x61, 0x8c, 0xa1, + 0x7d, 0xf7, 0x15, 0x04, 0x00, 0x01, 0x21, 0xbf, 0x07, 0x11, 0x5b, 0x3a, 0x39, + 0xbb, 0x87, 0xf7, 0x23, 0x91, 0x52, 0x4b, 0x82, 0x0e, 0xf3, 0x5c, 0xfc, 0x09, + 0x58, 0xd4, 0x19, 0x2f, 0x49, 0x59, 0xef, 0xe4, 0xb9, 0xa7, 0xb5, 0x29, 0x98, + 0x8a, 0x3f, 0x7d, 0x27, 0x37, 0x91, 0x49, 0x0a, 0x6b, 0x48, 0x49, 0x5a, 0x80, + 0x06, 0x45, 0x5e, 0x86, 0x57, 0x71, 0xbe, 0x92, 0x06, 0xd5, 0x4b, 0x43, 0x02, + 0x4a, 0xf5, 0xe6, 0xc9, 0x5b, 0x33, 0xf6, 0xda, 0xd1, 0x66, 0x6a, 0x05, 0xf9, + 0x1a, 0xd7, 0x75, 0x79, 0x65, 0xc2, 0x99, 0x36, 0xe7, 0xfa, 0x48, 0xd7, 0x7e, + 0x89, 0xee, 0x09, 0x62, 0xf5, 0x8c, 0x05, 0x1d, 0x11, 0xd0, 0x55, 0xfc, 0xe2, + 0x04, 0xa5, 0x62, 0xde, 0x68, 0x08, 0x8a, 0x1b, 0x26, 0x48, 0xb8, 0x17, 0x4c, + 0xbc, 0xfc, 0x8b, 0x5b, 0x5c, 0xd0, 0x77, 0x11, 0x5a, 0xfd, 0xe1, 0x84, 0x05, + 0x05, 0x4e, 0x5d, 0xa9, 0xa0, 0x43, 0x10, 0x34, 0x2c, 0x5d, 0x3b, 0x52, 0x6e, + 0x0b, 0x02, 0xc5, 0xca, 0x17, 0x22, 0xba, 0xde, 0xee, 0x23, 0xd1, 0x45, 0xe8, + 0xeb, 0x22, 0x13, 0xfc, 0x4a, 0xf1, 0xe4, 0x50, 0xe4, 0xd5, 0x21, 0x7c, 0x66, + 0x17, 0x00, 0x8c, 0x78, 0xf4, 0xfb, 0x11, 0x12, 0xf4, 0x02, 0x8a, 0x70, 0x4f, + 0xc5, 0xa9, 0x38, 0x2c, 0x6b, 0x03, 0xe7, 0xd8, 0x08, 0x5e, 0x90, 0x6c, 0xf8, + 0x4c, 0xa2, 0xc1, 0x20, 0x7c, 0x87, 0xa2, 0xbc, 0xe2, 0x08, 0x0a, 0x98, 0x91, + 0x66, 0x8d, 0x69, 0xb0, 0x44, 0xbe, 0xce, 0xd6, 0xcd, 0xa3, 0x2c, 0x22, 0x9c, + 0x91, 0x17, 0x91, 0x7a, 0xa0, 0x7d, 0xdf, 0xfc, 0xd3, 0x77, 0x39, 0x5c, 0xba, + 0x61, 0x6d, 0x63, 0xc0, 0xb6, 0x9c, 0x01, 0xfc, 0xc4, 0x53, 0x91, 0xfd, 0x5b, + 0x87, 0x63, 0xfb, 0x96, 0xd7, 0xca, 0x33, 0x3a, 0x12, 0xde, 0x3c, 0xef, 0xa9, + 0x1c, 0x6c, 0x98, 0xf9, 0x47, 0x3b, 0x8e, 0x10, 0x4a, 0x71, 0x29, 0x3e, 0x46, + 0x37, 0x47, 0x05, 0xba, 0xf6, 0x5f, 0xa4, 0x13, 0x84, 0xba, 0x5c, 0x8e, 0x0c, + 0x88, 0xa3, 0xeb, 0x07, 0xe0, 0xbe, 0x34, 0xda, 0xdd, 0xfa, 0xbb, 0x7b, 0x65, + 0x54, 0x3b, 0x5f, 0x39, 0xcb, 0x20, 0x23, 0xd4, 0x67, 0x89, 0xeb, 0x7d, 0x98, + 0x9a, 0xf7, 0x79, 0xe5, 0xb8, 0xd2, 0x83, 0x85, 0xa8, 0x5b, 0x0d, 0xa2, 0xab, + 0xe0, 0x7f, 0x0c, 0x2b, 0xb4, 0x25, 0x5f, 0xce, 0xa0, 0x31, 0x88, 0x52, 0x7a, + 0x30, 0x7d, 0x40, 0x91, 0x59, 0xe9, 0x01, 0x66, 0xfa, 0xc6, 0xa0, 0x70, 0xba, + 0x05, 0xb3, 0xe4, 0xdb, 0xfd, 0x3a, 0x2b, 0xfc, 0xc9, 0xee, 0x6e, 0xd0, 0x16, + 0xc0, 0xf6, 0x65, 0xbe, 0x81, 0x33, 0xb7, 0xdc, 0x1d, 0x86, 0x04, 0x4d, 0xb0, + 0xf9, 0xdb, 0x40, 0xfb, 0x0e, 0x9f, 0x8b, 0xc2, 0xe4, 0xdb, 0x53, 0x82, 0xa8, + 0x04, 0x53, 0xfd, 0xd8, 0x8f, 0x52, 0xb0, 0x59, 0xc7, 0x96, 0x49, 0x43, 0xc1, + 0xc0, 0xdf, 0x3b, 0x6b, 0x64, 0x10, 0xf9, 0x5d, 0xef, 0x5c, 0x04, 0x78, 0xf6, + 0x85, 0xc6, 0xb3, 0x3a, 0xa0, 0xc8, 0x8e, 0x68, 0x82, 0x42, 0x8e, 0x8c, 0xba, + 0x43, 0x64, 0xea, 0x93, 0xaf, 0x37, 0x8c, 0x50, 0x64, 0x82, 0x27, 0x36, 0x58, + 0xa2, 0xc0, 0x95, 0xdd, 0x07, 0x6c, 0x39, 0x73, 0x19, 0x1d, 0x46, 0xa1, 0x03, + 0x9e, 0x5d, 0x6b, 0x7d, 0x9c, 0x08, 0x6b, 0x25, 0x85, 0x90, 0xd3, 0x2d, 0x76, + 0xe3, 0xd4, 0x20, 0x38, 0x43, 0x57, 0x0e, 0xfe, 0xed, 0x97, 0x1c, 0x14, 0x12, + 0x2f, 0x5b, 0x21, 0x5b, 0x0f, 0x38, 0xbb, 0xc7, 0x16, 0xb6, 0xa5, 0x94, 0x4e, + 0xe7, 0x27, 0x96, 0x56, 0x90, 0xe2, 0x09, 0xb4, 0x9e, 0xb9, 0x62, 0xc0, 0x39, + 0x97, 0x5f, 0x93, 0x9e, 0xd5, 0xc6, 0xe4, 0xc4, 0x00, 0xd8, 0x87, 0x75, 0x94, + 0x33, 0xd3, 0xad, 0x71, 0x6d, 0xa0, 0xcb, 0x44, 0x61, 0x13, 0xc7, 0x72, 0x7a, + 0x64, 0xb5, 0x8c, 0x3f, 0x8a, 0x0f, 0x81, 0x18, 0x9f, 0x98, 0x00, 0x52, 0x33, + 0xa8, 0x13, 0x66, 0xae, 0xe7, 0x3c, 0xec, 0x85, 0x22, 0x8e, 0xbc, 0xfd, 0x5e, + 0xe3, 0xc3, 0xfb, 0x44, 0xdb, 0x76, 0xba, 0x24, 0x3f, 0x28, 0x42, 0xb7, 0xb5, + 0xfc, 0x74, 0x6a, 0xe5, 0x1b, 0x0b, 0xc4, 0xbd, 0x4f, 0xc9, 0xfd, 0x83, 0x35, + 0x65, 0xea, 0x85, 0x2b, 0x92, 0xb2, 0x24, 0xf6, 0x99, 0x03, 0x18, 0xad, 0x8c, + 0x7d, 0x94, 0x37, 0xe2, 0x0e, 0x2a, 0x1f, 0x20, 0xe8, 0x18, 0xf9, 0x05, 0x7c, + 0x5a, 0xba, 0xaa, 0x2e, 0x5c, 0x15, 0xb9, 0x49, 0x45, 0xcd, 0x42, 0x4c, 0x28, + 0xa5, 0xfa, 0x38, 0x5d, 0xad, 0xfe, 0x49, 0x07, 0xb2, 0x74, 0xd8, 0x42, 0x70, + 0x7d, 0xb3, 0x69, 0x7a, 0x5a, 0xe6, 0xc8, 0xf5, 0x42, 0xe5, 0xec, 0xc0, 0x7f, + 0xe4, 0x73, 0x50, 0xd1, 0x01, 0x46, 0x70, 0x21, 0x2e, 0xfe, 0x81, 0xfb, 0x7c, + 0x73, 0xe8, 0x45, 0x0d, 0xf8, 0x14, 0xef, 0x62, 0x32, 0xf7, 0x49, 0x0f, 0x63, + 0xcc, 0xf0, 0x74, 0x80, 0xf8, 0x84, 0xa6, 0x6e, 0xaf, 0xfc, 0x28, 0xfe, 0xa4, + 0x48, 0xd7, 0xb4, 0x01, 0xcd, 0xae, 0x10, 0xe7, 0xc0, 0xc7, 0xf9, 0xa7, 0xb1, + 0x53, 0x31, 0x96, 0x9f, 0xc8, 0xcb, 0x36, 0x39, 0x67, 0x73, 0xde, 0x19, 0x19, + 0x31, 0xc7, 0x50, 0xf6, 0xce, 0x5c, 0xaa, 0xf2, 0x97, 0x68, 0xeb, 0xb2, 0x7d, + 0xac, 0xc7, 0x38, 0x05, 0x6a, 0x81, 0x25, 0xb4, 0x77, 0x2b, 0xf8, 0x7a, 0xe1, + 0x0a, 0x8a, 0x30, 0x9b, 0x9b, 0xd6, 0x55, 0x04, 0x3c, 0xfc, 0x31, 0x59, 0x49, + 0x43, 0x68, 0xc5, 0xab, 0x8c, 0xad, 0xb7, 0xf6, 0x71, 0xe9, 0x62, 0x6b, 0xd2, + 0x63, 0xe3, 0x11, 0x81, 0xa6, 0x04, 0xb5, 0x06, 0xa0, 0x3b, 0x43, 0x9a, 0x7f, + 0xfe, 0x43, 0x55, 0x89, 0x24, 0x77, 0xe2, 0xbd, 0xf3, 0x38, 0xc6, 0x2c, 0x39, + 0x22, 0xf7, 0xd3, 0xc9, 0xa5, 0x6c, 0x71, 0x03, 0xd9, 0x11, 0x94, 0x8a, 0x84, + 0xb5, 0xae, 0x2d, 0xbb, 0x16, 0xa3, 0x76, 0x1a, 0xdd, 0x05, 0x3a, 0x0f, 0x96, + 0x7e, 0x6b, 0x5b, 0xc9, 0x42, 0x11, 0xb6, 0x54, 0x71, 0x53, 0x26, 0x7c, 0x6e, + 0xe1, 0xca, 0xd0, 0xd9, 0x74, 0xa7, 0x10, 0x88, 0x58, 0x37, 0x35, 0xe4, 0xf6, + 0x3d, 0x33, 0x15, 0x6d, 0xad, 0xd5, 0x4c, 0x2f, 0xaf, 0x89, 0x11, 0x4a, 0x12, + 0x7b, 0x97, 0xb9, 0x4c, 0xc2, 0xa2, 0x2e, 0xf3, 0x03, 0xf4, 0x59, 0xd0, 0x4f, + 0xc0, 0xb5, 0x3a, 0xce, 0x59, 0x18, 0xd4, 0x7f, 0xf3, 0x3a, 0x55, 0x8b, 0xd7, + 0x1a, 0x75, 0xf3, 0x55, 0xfb, 0xd0, 0x6b, 0xbc, 0xcf, 0x4e, 0x02, 0xc3, 0xc0, + 0xa4, 0xb6, 0x3d, 0x0c, 0xc9, 0x49, 0x80, 0x1d, 0x63, 0xa6, 0x4c, 0xb2, 0xd3, + 0x23, 0x73, 0xb2, 0xc7, 0xb2, 0x74, 0xab, 0x2d, 0xb4, 0x68, 0x21, 0x42, 0xc8, + 0xb2, 0x1d, 0x84, 0xc4, 0x81, 0xf5, 0xef, 0x21, 0xe4, 0xb5, 0xe3, 0x60, 0x34, + 0x51, 0xbf, 0x94, 0x77, 0x4d, 0x0e, 0xf4, 0x7f, 0x63, 0xfa, 0x6a, 0xbb, 0x78, + 0xd2, 0x1c, 0x19, 0x3c, 0xbe, 0x65, 0xb6, 0x95, 0xfe, 0x67, 0x42, 0x3c, 0x1e, + 0x2d, 0x31, 0x2e, 0x27, 0x76, 0xfa, 0x24, 0xec, 0xe8, 0x46, 0x83, 0xe7, 0x48, + 0x76, 0xc5, 0x5e, 0xa0, 0x36, 0x9e, 0x4e, 0xa0, 0xe8, 0x64, 0x94, 0xe0, 0x0d, + 0xde, 0x23, 0x6a, 0x16, 0x89, 0x73, 0x1f, 0x0a, 0x5d, 0x82, 0x03, 0xaf, 0xde, + 0x5c, 0x42, 0x36, 0x40, 0xb8, 0x1e, 0x4f, 0x63, 0x1c, 0x98, 0x1c, 0x11, 0xa2, + 0xe1, 0xd1, 0x84, 0xc6, 0x7c, 0x52, 0x8d, 0xf9, 0x2d, 0x53, 0xae, 0xc4, 0x4a, + 0x40, 0xa4, 0xea, 0x2a, 0x13, 0x1b, 0x47, 0x33, 0xcf, 0xe4, 0x5c, 0x6b, 0x00, + 0x12, 0xc3, 0xe9, 0xe2, 0x09, 0x75, 0xba, 0xae, 0xcb, 0x02, 0x32, 0xdf, 0x88, + 0x0b, 0xd7, 0xd1, 0xde, 0x13, 0xe1, 0x34, 0x94, 0x62, 0xec, 0x8d, 0x5d, 0xf3, + 0xe7, 0x80, 0xff, 0xa7, 0x2e, 0xba, 0x8a, 0x8d, 0xf7, 0xfc, 0xf3, 0x98, 0xec, + 0x23, 0x05, 0x13, 0xca, 0x9d, 0x61, 0x23, 0xf8, 0xb9, 0xd8, 0x17, 0x85, 0x60, + 0xda, 0xf9, 0x75, 0x11, 0x19, 0x55, 0xa2, 0xbc, 0xa3, 0x42, 0x3e, 0xee, 0xfc, + 0x52, 0x7b, 0xe3, 0xa8, 0x54, 0x3e, 0xb9, 0x0a, 0x5e, 0xc0, 0x2f, 0x35, 0xa7, + 0xc6, 0x4b, 0x7d, 0xd5, 0x9a, 0x72, 0xda, 0x00, 0x74, 0x63, 0x4e, 0x01, 0xd2, + 0xab, 0xf3, 0x63, 0x7a, 0xdd, 0x77, 0xc7, 0x35, 0x0f, 0x12, 0xb0, 0x11, 0xb2, + 0x94, 0x16, 0x8e, 0xc7, 0x55, 0x76, 0xe4, 0x7d, 0x16, 0x9e, 0x39, 0x38, 0xbf, + 0x6a, 0xe2, 0xaa, 0x8f, 0xf7, 0xcf, 0xba, 0x7c, 0xac, 0xb1, 0xf9, 0x2b, 0x6e, + 0x4c, 0x24, 0x97, 0xbf, 0xfa, 0x9f, 0x17, 0xca, 0xd2, 0x42, 0xfa, 0x9c, 0x31, + 0x79, 0xc1, 0xa3, 0xaa, 0x81, 0xf7, 0x36, 0x16, 0x49, 0x57, 0x2c, 0x71, 0x5c, + 0x25, 0xa1, 0xf6, 0xcd, 0x5a, 0xce, 0x82, 0xc0, 0x0a, 0xb2, 0x34, 0x2b, 0x9c, + 0x3c, 0xb4, 0xff, 0xfd, 0xda, 0x16, 0x0c, 0xa5, 0xab, 0x9e, 0x9b, 0xaf, 0x21, + 0x39, 0xef, 0x9a, 0xfb, 0xe1, 0xb1, 0xf3, 0x09, 0x46, 0x2a, 0xfc, 0xe4, 0x62, + 0xa7, 0x9b, 0xb9, 0x69, 0x8e, 0x22, 0xc9, 0x57, 0xc5, 0x90, 0xa7, 0x53, 0xa7, + 0x6b, 0x87, 0xe0, 0x09, 0x12, 0x1e, 0x06, 0xf6, 0xa1, 0xbf, 0x62, 0xa0, 0x8b, + 0xf4, 0x35, 0xd9, 0x2e, 0x2f, 0xff, 0xe8, 0x6e, 0x2a, 0x9c, 0xbb, 0xa9, 0x13, + 0x3a, 0x68, 0xe4, 0xae, 0xbf, 0x33, 0xc3, 0x84, 0x36, 0xf2, 0x54, 0x5f, 0xc2, + 0xd5, 0x28, 0x32, 0xd1, 0x65, 0xaf, 0x41, 0x5b, 0x24, 0x4a, 0xdc, 0x5f, 0x57, + 0x37, 0x7d, 0xee, 0xdf, 0x46, 0x0a, 0xa3, 0xbe, 0xb4, 0x34, 0x19, 0xc6, 0xb0, + 0x82, 0xe8, 0x35, 0xce, 0x84, 0xca, 0x13, 0xb6, 0x90, 0x8a, 0x88, 0x13, 0xc0, + 0x21, 0xde, 0x9f, 0xa9, 0xa4, 0x4e, 0x4c, 0x18, 0xdc, 0xb3, 0xd2, 0x1f, 0xaa, + 0x8b, 0x86, 0xc8, 0x70, 0x28, 0xd0, 0xb5, 0x53, 0x21, 0x07, 0xf9, 0xf6, 0xfd, + 0x49, 0x00, 0x22, 0x7d, 0x0d, 0x8f, 0xf2, 0xbf, 0x9d, 0x28, 0xcb, 0xcc, 0x99, + 0x6c, 0x47, 0x3c, 0xe6, 0x16, 0x41, 0xf4, 0x88, 0x4e, 0x6e, 0xd3, 0xfd, 0x5e, + 0x4b, 0x7c, 0xb8, 0x35, 0xb8, 0x33, 0x08, 0x96, 0x4e, 0x3c, 0x46, 0x87, 0x3f, + 0xd6, 0x13, 0x31, 0x7b, 0x91, 0xd2, 0x92, 0x36, 0xea, 0x90, 0xe3, 0x65, 0x32, + 0xec, 0x5d, 0x6b, 0x42, 0x32, 0xe8, 0xbc, 0xcc, 0x36, 0x75, 0xb9, 0x8b, 0x35, + 0xf8, 0xde, 0x4d, 0x08, 0x88, 0x84, 0x14, 0x6f, 0x3d, 0xb8, 0x97, 0x0b, 0x38, + 0xd1, 0xe5, 0x01, 0xae, 0xe9, 0xc1, 0xf3, 0xfd, 0x78, 0x25, 0x49, 0xd3, 0xf3, + 0x24, 0x57, 0x59, 0x60, 0x6d, 0x9f, 0x92, 0xd5, 0x54, 0x8a, 0xcf, 0xea, 0xdb, + 0xaf, 0x9c, 0xaa, 0x6b, 0x93, 0xdc, 0x08, 0x82, 0x8d, 0x74, 0xf6, 0xd5, 0xfd, + 0xd8, 0x33, 0x31, 0xf0, 0x96, 0x91, 0x45, 0x95, 0x52, 0x97, 0xe6, 0x9f, 0x00, + 0xfd, 0x29, 0x87, 0xf2, 0xda, 0x2b, 0x94, 0xb9, 0x95, 0xfe, 0xcb, 0xe6, 0x22, + 0xa7, 0x35, 0xef, 0x7f, 0x12, 0x07, 0xf6, 0x71, 0x62, 0x94, 0x89, 0x20, 0x2b, + 0xea, 0x0b, 0x47, 0x5e, 0x51, 0x68, 0x1a, 0xa1, 0x67, 0x78, 0xb3, 0x9b, 0xd9, + 0x23, 0xc9, 0x8d, 0xc6, 0xff, 0x83, 0x73, 0xc7, 0x9b, 0xb1, 0x70, 0x30, 0x41, + 0x7b, 0xc2, 0x00, 0xc8, 0xf0, 0xb8, 0x55, 0xac, 0xfe, 0xc1, 0x79, 0xf7, 0x67, + 0x4c, 0xec, 0x27, 0x21, 0xa1, 0x0f, 0xca, 0x69, 0x3d, 0x83, 0xcf, 0xe5, 0xb8, + 0xcd, 0xcc, 0x18, 0xf8, 0x1a, 0xd6, 0x17, 0xfa, 0x26, 0xf0, 0xdf, 0xb8, 0x36, + 0x55, 0xb8, 0xa2, 0x9a, 0x7f, 0x83, 0x42, 0x32, 0x42, 0x5e, 0x8c, 0x47, 0x45, + 0x88, 0xf1, 0x8d, 0xd3, 0x26, 0xaa, 0x39, 0x6c, 0x3e, 0x47, 0x75, 0xe0, 0x02, + 0x05, 0xfc, 0x9e, 0x45, 0xf7, 0xb7, 0xd2, 0xe6, 0xd5, 0x5d, 0xcb, 0x90, 0xe2, + 0x3f, 0xf6, 0xb5, 0x08, 0x45, 0x9a, 0xa6, 0x99, 0xbf, 0xcb, 0xd5, 0x6f, 0x10, + 0x99, 0x77, 0x64, 0xd0, 0x87, 0x40, 0x89, 0x86, 0xe7, 0x3d, 0x6e, 0x28, 0x4f, + 0xea, 0x9a, 0x23, 0xc3, 0x93, 0x11, 0x78, 0x2f, 0x86, 0xca, 0xbf, 0xf9, 0x45, + 0x5e, 0x4c, 0xf6, 0x99, 0xe5, 0xf5, 0xd4, 0xbc, 0x0b, 0x39, 0x05, 0xa4, 0xe3, + 0xbd, 0x01, 0xc5, 0x4d, 0xf8, 0x64, 0x34, 0x43, 0xbe, 0x0f, 0x88, 0x90, 0x32, + 0xea, 0x32, 0x5b, 0xf0, 0x71, 0x07, 0xfd, 0x41, 0xd6, 0x73, 0xee, 0xba, 0xe6, + 0xfa, 0x63, 0x7b, 0x70, 0xcc, 0x0e, 0xd3, 0xf0, 0x09, 0x58, 0xdf, 0xb8, 0xdc, + 0xf0, 0x0e, 0x85, 0xa1, 0xd0, 0xa6, 0xa8, 0x90, 0x81, 0x40, 0xc2, 0xf4, 0x34, + 0xc2, 0xe2, 0x60, 0xef, 0xb0, 0xbc, 0xa2, 0x00, 0x35, 0x04, 0xc9, 0x99, 0x93, + 0xa9, 0xe1, 0xc0, 0xff, 0x9c, 0xef, 0xe6, 0xa6, 0x65, 0xd7, 0x91, 0x42, 0x86, + 0x90, 0xe4, 0x7e, 0xf8, 0xc1, 0x31, 0xa8, 0xe9, 0xbf, 0xb4, 0xc3, 0x08, 0x02, + 0x35, 0x03, 0x2d, 0x73, 0x1b, 0x0d, 0x38, 0x41, 0x22, 0x5f, 0x1c, 0x11, 0xe2, + 0xc2, 0x8e, 0xe8, 0x4d, 0x35, 0xf9, 0x22, 0x61, 0x00, 0x56, 0x59, 0x72, 0xeb, + 0x26, 0x9d, 0x27, 0x8e, 0xf6, 0x49, 0x79, 0xbf, 0x65, 0x15, 0xed, 0x4a, 0x68, + 0x40, 0xb0, 0x88, 0x3a, 0x9e, 0x6e, 0xf6, 0x4a, 0x0e, 0xfc, 0xae, 0x1c, 0xf2, + 0x1d, 0xfe, 0x74, 0x85, 0x4e, 0x84, 0xc2, 0x74, 0x9f, 0xac, 0x03, 0x82, 0x52, + 0x75, 0xc9, 0xb6, 0x30, 0x21, 0x84, 0xc7, 0x2d, 0xf4, 0xc4, 0xbb, 0x28, 0x62, + 0xe4, 0xe8, 0xa7, 0xd9, 0xa4, 0xa2, 0x82, 0x86, 0x6f, 0x9a, 0x7b, 0x2c, 0xfc, + 0x9a, 0x56, 0x31, 0x3d, 0xa0, 0xc4, 0x7a, 0x34, 0xb7, 0xb9, 0xcd, 0xa3, 0xac, + 0xe8, 0x18, 0x5f, 0x07, 0xdf, 0x36, 0xe4, 0x48, 0xa7, 0x6a, 0xa4, 0x77, 0xf2, + 0x24, 0xd8, 0x7a, 0x07, 0x4f, 0x43, 0xaf, 0x5d, 0x5f, 0x79, 0xb3, 0xab, 0x11, + 0x28, 0xf0, 0x81, 0x91, 0x44, 0x7f, 0xa6, 0x46, 0xbf, 0xdd, 0xe5, 0xb5, 0x1e, + 0x23, 0x3c, 0xa6, 0x15, 0x5d, 0x10, 0x15, 0x85, 0xbc, 0x2c, 0x40, 0x15, 0x8a, + 0xc2, 0x10, 0x6e, 0x66, 0xa2, 0x6e, 0x46, 0x42, 0x33, 0x70, 0x63, 0x68, 0x76, + 0xb4, 0x34, 0xa7, 0x4f, 0x8c, 0xe8, 0x06, 0x00, 0x50, 0xb0, 0x82, 0xa7, 0x9b, + 0x61, 0xbb, 0x5d, 0x34, 0x4e, 0xb5, 0xa1, 0x15, 0x83, 0x26, 0xce, 0xd9, 0xa9, + 0xd9, 0xf5, 0x4f, 0xb2, 0xfe, 0x8f, 0x9f, 0x05, 0xcd, 0x11, 0x1e, 0xe4, 0x6c, + 0x47, 0x10, 0xf6, 0xf6, 0x3a, 0x62, 0x69, 0x45, 0x57, 0xef, 0x1b, 0x12, 0xc8, + 0x80, 0x06, 0xb6, 0x78, 0x72, 0x50, 0x5f, 0x4e, 0x88, 0x3b, 0x58, 0x59, 0x07, + 0x92, 0x9a, 0x2f, 0x3f, 0xdb, 0x0d, 0x8f, 0x79, 0x14, 0xc4, 0x2d, 0xde, 0x2d, + 0x20, 0x00, 0xf5, 0xae, 0x02, 0xd4, 0x18, 0x21, 0xc8, 0xe1, 0xee, 0x01, 0x38, + 0xeb, 0xcb, 0x72, 0x8d, 0x7c, 0x6c, 0x3c, 0x80, 0x02, 0x7e, 0x43, 0x75, 0x94, + 0xc6, 0x70, 0xfd, 0x6f, 0x39, 0x08, 0x22, 0x2e, 0xe7, 0xa1, 0xb9, 0x17, 0xf8, + 0x27, 0x1a, 0xbe, 0x66, 0x0e, 0x39, 0xe0, 0x51, 0xaa, 0xa6, 0xfc, 0xa1, 0x86, + 0x22, 0x76, 0xe2, 0xba, 0xa0, 0xfe, 0x0b, 0x16, 0x2a, 0xeb, 0xcf, 0xe3, 0xd9, + 0x34, 0x9c, 0x8d, 0x15, 0x4b, 0xb7, 0xee, 0x28, 0x21, 0x2c, 0x1b, 0xaa, 0x70, + 0x5d, 0x82, 0x07, 0x0d, 0x70, 0x32, 0xf2, 0x69, 0x5d, 0x17, 0x96, 0x80, 0x9f, + 0xab, 0x41, 0x24, 0x69, 0x26, 0xaf, 0x99, 0x2b, 0x6e, 0xee, 0x95, 0xa9, 0xa0, + 0x6b, 0xc4, 0x56, 0x2c, 0x5f, 0x2f, 0x1b, 0x19, 0x54, 0x95, 0x00, 0x37, 0x2e, + 0x7a, 0xd5, 0x79, 0xa6, 0xd6, 0xd7, 0x8b, 0x33, 0x15, 0x31, 0x30, 0xfb, 0x44, + 0x8f, 0xb7, 0x9e, 0x8a, 0x66, 0x9d, 0xb8, 0xa0, 0xf3, 0x5c, 0xdf, 0x9a, 0xe5, + 0xd3, 0x2d, 0x73, 0x2f, 0xc7, 0x94, 0x18, 0xe2, 0x3b, 0x45, 0x1d, 0xdc, 0x95, + 0xa2, 0x2a, 0xba, 0xbb, 0x05, 0x6e, 0xc6, 0xb5, 0xe8, 0xba, 0x4f, 0x52, 0x4d, + 0xfa, 0xfe, 0x87, 0x52, 0x62, 0xdd, 0x7b, 0xe4, 0x1c, 0xbb, 0xc6, 0x24, 0x20, + 0xd4, 0xad, 0x6d, 0xf5, 0xc9, 0xb7, 0x13, 0x60, 0x4f, 0x65, 0x60, 0x88, 0xa4, + 0x48, 0x5e, 0x93, 0xbe, 0x19, 0x07, 0xd2, 0x7a, 0xc6, 0xec, 0x3c, 0x57, 0x25, + 0x9b, 0xd6, 0x98, 0x1d, 0x42, 0xc1, 0xb7, 0x8a, 0x29, 0xad, 0x96, 0x85, 0xe6, + 0x3c, 0x49, 0x4d, 0x41, 0x29, 0x62, 0x3e, 0xa1, 0xa7, 0xff, 0xec, 0x85, 0xfa, + 0x29, 0x41, 0x10, 0x73, 0xed, 0xb2, 0x97, 0x8e, 0xf4, 0xe4, 0x69, 0xdd, 0xd5, + 0xcd, 0xa9, 0x86, 0x18, 0x99, 0x95, 0xf8, 0x8d, 0x6a, 0xb3, 0x66, 0xdb, 0x01, + 0x90, 0x01, 0xf5, 0xb2, 0x52, 0x88, 0xcf, 0x86, 0x0f, 0xd9, 0x98, 0xee, 0x57, + 0x3c, 0x8c, 0xc4, 0x8a, 0xa9, 0xef, 0xcf, 0x9b, 0x61, 0x7e, 0x04, 0x3c, 0x99, + 0x00, 0x8e, 0x35, 0x00, 0x96, 0xfd, 0xa4, 0xeb, 0x24, 0xc2, 0x0f, 0x46, 0x90, + 0xf1, 0xe2, 0xc5, 0xef, 0x86, 0x6c, 0x0e, 0xe5, 0xdd, 0xa1, 0x19, 0xee, 0xea, + 0xf1, 0x19, 0xdb, 0xdc, 0xae, 0x8d, 0xc7, 0x6c, 0x84, 0x6c, 0xc2, 0x27, 0x27, + 0x2b, 0xfc, 0x54, 0x17, 0xdc, 0x4c, 0xf4, 0xc0, 0x87, 0xba, 0x34, 0xec, 0xf3, + 0xa5, 0x5b, 0x00, 0x1f, 0xf3, 0x09, 0xa8, 0x1c, 0x05, 0x2d, 0x69, 0x26, 0xa9, + 0xdd, 0xf0, 0xf7, 0x8c, 0x5f, 0xc0, 0x64, 0xc6, 0xa6, 0x40, 0x16, 0x21, 0xb3, + 0x8a, 0xa5, 0x49, 0x44, 0x19, 0x81, 0x99, 0x21, 0x0d, 0x2b, 0x42, 0xe6, 0x1d, + 0xde, 0x1d, 0x08, 0xaf, 0x55, 0x07, 0x3b, 0xbf, 0x06, 0x15, 0xf6, 0x7b, 0x11, + 0x00, 0xcc, 0x2e, 0xa3, 0xba, 0x3d, 0x6c, 0x1a, 0x1a, 0x90, 0x87, 0xb1, 0x19, + 0xba, 0xee, 0xbf, 0xa6, 0x2b, 0xc9, 0xf0, 0xec, 0x47, 0x9d, 0x99, 0xc1, 0xa3, + 0xb1, 0x58, 0xb5, 0x14, 0xd1, 0x62, 0x9d, 0xb3, 0x99, 0x3f, 0x11, 0x67, 0x2a, + 0x26, 0x70, 0x8e, 0x5a, 0xd8, 0x16, 0xb5, 0x47, 0xab, 0x7e, 0x82, 0x7d, 0x07, + 0x1b, 0xa7, 0x84, 0x2b, 0x3e, 0x90, 0x30, 0x53, 0x83, 0x89, 0x6e, 0xc4, 0x90, + 0x5f, 0x70, 0xc7, 0x8b, 0x69, 0x4e, 0x6a, 0x5a, 0x3e, 0x43, 0x12, 0xcd, 0x82, + 0x08, 0x13, 0x2b, 0x84, 0x0f, 0x05, 0xc7, 0x14, 0x52, 0x3c, 0xa8, 0x19, 0x72, + 0x0a, 0xe2, 0x27, 0xfd, 0x1a, 0xcb, 0xa7, 0x14, 0xfa, 0x4f, 0xc4, 0x5f, 0xc5, + 0x39, 0x88, 0x57, 0xb4, 0x0d, 0xc1, 0x48, 0x79, 0x85, 0x6f, 0x35, 0x4b, 0xa4, + 0xd2, 0x58, 0x1d, 0x0c, 0xda, 0x54, 0xb6, 0x38, 0xba, 0x9d, 0x76, 0xf9, 0xb5, + 0x2d, 0x17, 0xc8, 0xf8, 0x8e, 0xe6, 0x3f, 0x58, 0x45, 0xb5, 0xdc, 0xef, 0xa4, + 0xc3, 0x47, 0x9b, 0xce, 0x9a, 0xca, 0xd1, 0x8b, 0x4a, 0xea, 0xe0, 0x3c, 0x0e, + 0xae, 0x22, 0x5d, 0x42, 0x84, 0x8b, 0xde, 0xaa, 0x53, 0x6d, 0x7d, 0x8d, 0xd3, + 0xbc, 0x97, 0x9f, 0x06, 0x58, 0x66, 0x73, 0xbc, 0x6f, 0xf1, 0xc5, 0xd3, 0xb3, + 0x20, 0xf3, 0x49, 0xa5, 0xb3, 0xa8, 0xb3, 0x55, 0x59, 0x22, 0x96, 0xaa, 0xf6, + 0x1c, 0x5b, 0x72, 0x52, 0xf7, 0x3e, 0xc0, 0xa9, 0x46, 0x6a, 0x1b, 0x85, 0x76, + 0x4f, 0xb0, 0x83, 0x1b, 0x4a, 0x1a, 0x36, 0x89, 0x0e, 0x22, 0x4c, 0x01, 0xac, + 0xfc, 0xe4, 0x8e, 0xe3, 0xed, 0x93, 0x87, 0x73, 0x98, 0xe0, 0x72, 0x6d, 0x02, + 0x93, 0x6d, 0x0d, 0x03, 0x2e, 0x18, 0xe3, 0x28, 0x8b, 0x26, 0x70, 0xe1, 0x36, + 0x2c, 0x32, 0xd6, 0xe4, 0x73, 0x3b, 0x9d, 0xd2, 0xd5, 0xf2, 0x6e, 0x1f, 0xe3, + 0x06, 0xf7, 0x3c, 0x00, 0x7f, 0xdd, 0xca, 0xe9, 0xd9, 0xc0, 0xaa, 0xf1, 0x87, + 0xd7, 0x42, 0x8b, 0x1e, 0x9d, 0x47, 0x9c, 0x18, 0x23, 0x7b, 0x98, 0x28, 0xbc, + 0xa8, 0xb9, 0x8c, 0x9d, 0x9b, 0xec, 0x7d, 0x82, 0x70, 0xb5, 0xd8, 0xee, 0xc3, + 0xcc, 0x4f, 0x43, 0xfa, 0x01, 0x88, 0x52, 0x1b, 0xc6, 0x1b, 0x21, 0xdd, 0x04, + 0xe3, 0x7a, 0x83, 0xec, 0xe6, 0x8c, 0xa7, 0xa2, 0xfa, 0x6c, 0x8f, 0x9e, 0x34, + 0xa6, 0x29, 0x03, 0x35, 0xaa, 0x1f, 0xbd, 0x83, 0xd5, 0x4a, 0xaf, 0x44, 0x1e, + 0x31, 0x9e, 0xa4, 0x7a, 0x86, 0x2a, 0xd0, 0x29, 0x3c, 0xed, 0xf5, 0xdd, 0x9e, + 0xda, 0xde, 0xee, 0x33, 0xcb, 0x52, 0x2c, 0xd0, 0x11, 0x8b, 0xbd, 0x81, 0x1a, + 0xce, 0x9a, 0x23, 0xbd, 0xa3, 0x9a, 0xba, 0x72, 0xf1, 0x56, 0x6f, 0xc1, 0x68, + 0x84, 0x97, 0xd2, 0xa7, 0x92, 0x8c, 0x36, 0x70, 0x15, 0x25, 0x67, 0x8b, 0xc9, + 0x72, 0x14, 0xb3, 0x1b, 0x37, 0xba, 0xb4, 0x6b, 0x88, 0xf2, 0x7f, 0x04, 0x48, + 0xde, 0xcb, 0x31, 0x62, 0x2d, 0x0f, 0x0f, 0x87, 0xa8, 0x55, 0xba, 0x54, 0x00, + 0x03, 0x32, 0x03, 0x1f, 0x73, 0xab, 0xff, 0xd4, 0x65, 0x91, 0xda, 0x0b, 0x88, + 0x72, 0x35, 0x04, 0xed, 0xb2, 0x33, 0x72, 0x30, 0xda, 0xd2, 0xac, 0xc0, 0xd8, + 0xbb, 0x68, 0xbc, 0x83, 0x7a, 0x2f, 0xf9, 0x30, 0xbf, 0xf0, 0x6f, 0xde, 0x74, + 0xeb, 0x90, 0xaa, 0xe4, 0xf6, 0x0d, 0xbb, 0x6e, 0xb8, 0x27, 0xea, 0x99, 0x88, + 0x4a, 0xcd, 0x62, 0x85, 0xa9, 0x88, 0x92, 0x80, 0x2c, 0xf5, 0x9d, 0x5d, 0x60, + 0xd0, 0x16, 0x63, 0x38, 0x7b, 0x3e, 0xd2, 0x72, 0x3b, 0xd6, 0x48, 0x9e, 0x9c, + 0x2c, 0x10, 0x6d, 0x4a, 0xa2, 0xde, 0x23, 0xce, 0xd1, 0x6c, 0x72, 0x04, 0x29, + 0xc7, 0x75, 0x3a, 0x77, 0x38, 0xec, 0x7d, 0x9d, 0xb8, 0x62, 0x42, 0x29, 0xed, + 0xd2, 0x17, 0xb8, 0x0d, 0x74, 0x87, 0x5a, 0x14, 0xca, 0xe4, 0x86, 0x3f, 0x13, + 0x9e, 0x9c, 0x0b, 0x13, 0x1b, 0x2a, 0x4c, 0x28, 0x07, 0x1a, 0x38, 0xec, 0x61, + 0xf6, 0x68, 0x01, 0xaa, 0x59, 0x56, 0xfc, 0xb2, 0xa4, 0x6b, 0x95, 0x87, 0x66, + 0x5b, 0x75, 0x71, 0xaa, 0x03, 0x48, 0x1f, 0xd8, 0xd9, 0xd5, 0x69, 0x8f, 0x83, + 0x6f, 0xc8, 0x63, 0x5e, 0x69, 0xe3, 0xbd, 0xe4, 0x2f, 0x4a, 0xc0, 0x71, 0x32, + 0x8b, 0x54, 0x09, 0xf6, 0xe4, 0x2d, 0x79, 0x0a, 0xed, 0xd7, 0x3b, 0xc1, 0xa2, + 0x35, 0x47, 0x23, 0xb3, 0xb8, 0x19, 0xd0, 0x63, 0x7a, 0x6f, 0xa4, 0x66, 0x39, + 0x46, 0xa3, 0x0a, 0xc5, 0xaf, 0xdd, 0x30, 0xce, 0x83, 0x0f, 0x67, 0x91, 0xb4, + 0x57, 0x52, 0x70, 0xa1, 0x72, 0x0f, 0x91, 0x86, 0x6e, 0x2b, 0x86, 0xf4, 0x78, + 0x88, 0x94, 0xc8, 0xda, 0x62, 0xd8, 0xb9, 0x1f, 0xaf, 0x52, 0x0e, 0x3b, 0xed, + 0xbc, 0x12, 0x06, 0xa5, 0xa5, 0xe6, 0xef, 0xd3, 0xdf, 0xde, 0x08, 0x43, 0xc3, + 0xb0, 0x67, 0x57, 0x64, 0x3f, 0xc0, 0x06, 0x00, 0x88, 0x38, 0xca, 0x47, 0x30, + 0x87, 0xf8, 0x97, 0x79, 0x18, 0xcc, 0x1b, 0x81, 0xc9, 0xe6, 0x8e, 0x3b, 0x88, + 0x8f, 0xe6, 0xf7, 0xc6, 0x30, 0xf1, 0xbc, 0x7a, 0xe1, 0x88, 0xf5, 0x12, 0x84, + 0x20, 0x41, 0xca, 0xda, 0x1e, 0x05, 0xf8, 0x66, 0xd2, 0x56, 0x2d, 0xbe, 0x09, + 0xc4, 0xb4, 0x30, 0x68, 0xf7, 0x54, 0xda, 0xd3, 0x4d, 0xf0, 0xfc, 0xfc, 0x18, + 0x1f, 0x31, 0x80, 0x1a, 0x79, 0x92, 0xd2, 0xf1, 0x6b, 0xe0, 0x21, 0x1b, 0x4a, + 0x22, 0xf6, 0x2a, 0xab, 0x64, 0x70, 0x1b, 0xf4, 0xa4, 0xe6, 0xd6, 0x66, 0xfc, + 0x30, 0x4a, 0x5c, 0x79, 0xc6, 0x09, 0xac, 0xc4, 0x3b, 0x00, 0xb4, 0x86, 0x48, + 0x93, 0xd3, 0x7d, 0x50, 0x07, 0xf0, 0xc3, 0x29, 0xa4, 0x75, 0x50, 0x52, 0x57, + 0x75, 0x70, 0xdd, 0x38, 0xfa, 0xc0, 0x43, 0xcd, 0x91, 0xc1, 0x2e, 0xe3, 0x4e, + 0x9c, 0xfa, 0xe3, 0x92, 0xa7, 0x8b, 0xda, 0xbd, 0x4e, 0xe3, 0x1d, 0xc0, 0xde, + 0xb0, 0x2f, 0xe7, 0xb1, 0xd8, 0xb0, 0x17, 0x8a, 0xc9, 0x51, 0x31, 0x05, 0xfc, + 0xc7, 0xe3, 0x0b, 0xa8, 0xe0, 0x16, 0xaa, 0x36, 0xa6, 0xb5, 0xdf, 0x5e, 0x5a, + 0x19, 0x09, 0xf6, 0x3a, 0xba, 0x09, 0x5d, 0x98, 0x77, 0xa8, 0xf2, 0x6e, 0x40, + 0x3d, 0xc2, 0x54, 0x76, 0xad, 0xd8, 0x3d, 0xb1, 0xca, 0x15, 0x8f, 0x0b, 0x42, + 0x2b, 0x5f, 0xf4, 0xdb, 0x69, 0xb1, 0x24, 0x4b, 0xc0, 0x90, 0x2e, 0xd0, 0x30, + 0x3f, 0xec, 0x73, 0xa5, 0xbf, 0xfe, 0xc7, 0x3a, 0xc3, 0x4c, 0x1a, 0x73, 0x16, + 0x0f, 0x2c, 0xea, 0x1e, 0x05, 0x10, 0xf8, 0x4d, 0x2f, 0xe2, 0xf7, 0x3b, 0x6e, + 0x92, 0x19, 0x07, 0xa1, 0xb7, 0xb3, 0x75, 0x12, 0x13, 0x24, 0x30, 0x11, 0x76, + 0xb0, 0x9b, 0xc0, 0x41, 0xe4, 0x68, 0x42, 0x3e, 0x93, 0xd5, 0xdc, 0xa3, 0x3e, + 0x67, 0x1a, 0x78, 0x6d, 0x23, 0x1f, 0x16, 0x43, 0xea, 0x66, 0x43, 0x8b, 0xa7, + 0x85, 0xb8, 0x1e, 0x6c, 0x2b, 0xc7, 0x3f, 0xf0, 0x0d, 0x89, 0x3b, 0xc1, 0x28, + 0x5e, 0xfc, 0xa8, 0x25, 0x99, 0xd1, 0x81, 0xf1, 0x23, 0x51, 0xf9, 0x39, 0xa9, + 0x4e, 0xa8, 0xb9, 0x75, 0xc0, 0x65, 0xa9, 0x1f, 0xf2, 0x57, 0xca, 0xc7, 0xa9, + 0x23, 0x85, 0xfc, 0x8f, 0xa9, 0x21, 0xb1, 0x06, 0xba, 0x86, 0x60, 0xc6, 0x0a, + 0xc8, 0xba, 0x5e, 0xce, 0x45, 0x60, 0x6f, 0x04, 0xf3, 0x6a, 0x3a, 0x90, 0xbb, + 0x38, 0x38, 0xc4, 0x2a, 0xbf, 0x62, 0xdd, 0x2d, 0x84, 0xba, 0xbe, 0xf3, 0xe1, + 0x88, 0xe9, 0x17, 0x1a, 0xff, 0x9b, 0xc1, 0x16, 0x66, 0x90, 0x09, 0xd8, 0x87, + 0x13, 0x0a, 0xc9, 0xf7, 0x39, 0x6a, 0x62, 0x7a, 0x84, 0x74, 0xc1, 0x81, 0x1b, + 0x69, 0x6f, 0x99, 0x55, 0x2b, 0x14, 0xc4, 0x84, 0xdf, 0xe4, 0x2c, 0x24, 0xd5, + 0x7c, 0x3a, 0x9c, 0x3f, 0xea, 0x13, 0x76, 0xcd, 0xcb, 0x63, 0x42, 0x1c, 0x31, + 0x4a, 0x62, 0x2a, 0x9a, 0xef, 0x0b, 0xc0, 0x57, 0xcb, 0x11, 0xbc, 0x5e, 0x30, + 0x66, 0xe3, 0x3a, 0x3b, 0x9b, 0x31, 0xdf, 0x25, 0x75, 0xcd, 0x51, 0x85, 0xa4, + 0xf3, 0xfc, 0x4e, 0x4c, 0x3d, 0x40, 0x2e, 0xd4, 0x20, 0x46, 0xf8, 0x1f, 0x97, + 0x48, 0x16, 0xd2, 0x79, 0xb1, 0x51, 0x3a, 0xb8, 0x1d, 0x3f, 0x0a, 0x3c, 0x7f, + 0x7f, 0xcf, 0x2f, 0xbb, 0x4e, 0x26, 0x32, 0x19, 0x93, 0xa5, 0x13, 0xad, 0x3d, + 0x7f, 0x4a, 0xfe, 0x6c, 0x1b, 0xbd, 0xc6, 0x57, 0x58, 0x50, 0x80, 0xbb, 0x5a, + 0x0f, 0x25, 0x97, 0x3d, 0x63, 0xeb, 0x20, 0xad, 0xa0, 0x16, 0x6b, 0xbd, 0x8a, + 0x39, 0xff, 0x93, 0x24, 0x6f, 0x27, 0x89, 0x73, 0x2a, 0xd0, 0x55, 0x87, 0xf8, + 0xdb, 0x7b, 0xc8, 0x7c, 0x24, 0x2c, 0xfd, 0x36, 0xce, 0x68, 0x5a, 0x4b, 0x65, + 0x69, 0x86, 0xc3, 0x9f, 0xd7, 0xfc, 0xb2, 0x3c, 0x91, 0x91, 0x3e, 0x46, 0x11, + 0x19, 0x1e, 0xdc, 0xc8, 0x8b, 0x78, 0xf1, 0x45, 0xea, 0x29, 0xd2, 0x71, 0xb9, + 0x40, 0xc6, 0x99, 0x41, 0xe4, 0xc3, 0xfd, 0x2d, 0x71, 0xf3, 0xb1, 0x90, 0x69, + 0x0e, 0xe1, 0x6f, 0x5d, 0x14, 0xac, 0x22, 0x24, 0xe6, 0xfc, 0x89, 0x59, 0x76, + 0x54, 0x52, 0x7d, 0xab, 0xe7, 0x2e, 0x75, 0xd2, 0xd2, 0xa1, 0x3a, 0x9f, 0xba, + 0xa6, 0x37, 0x8e, 0x8a, 0x26, 0x43, 0x21, 0x08, 0x7a, 0x19, 0x00, 0xef, 0xe3, + 0xca, 0xd1, 0x4a, 0x57, 0x96, 0x86, 0xaa, 0x36, 0x36, 0xbd, 0x37, 0x5b, 0xd3, + 0x13, 0x6b, 0xee, 0x0b, 0xda, 0xab, 0xcf, 0xac, 0x88, 0x1b, 0xc7, 0x01, 0x81, + 0x27, 0x21, 0xe6, 0xfb, 0x75, 0xaa, 0x07, 0x2d, 0x2d, 0x18, 0x7e, 0x62, 0x25, + 0x8d, 0x65, 0xa1, 0x92, 0x15, 0x7c, 0xdf, 0x2e, 0xc3, 0x21, 0x40, 0x7f, 0x68, + 0x2f, 0x5e, 0xec, 0x6a, 0x32, 0x97, 0xab, 0x20, 0xb7, 0x06, 0x1c, 0x62, 0x24, + 0x57, 0x16, 0xa4, 0x4f, 0x71, 0xfb, 0xfc, 0x34, 0xc7, 0x9b, 0x44, 0xe0, 0x9e, + 0x42, 0x12, 0xac, 0x26, 0x53, 0xf6, 0xc4, 0x03, 0x64, 0x3e, 0x1c, 0x5b, 0x9a, + 0xd1, 0x34, 0xd8, 0x9c, 0x68, 0x0b, 0x70, 0x72, 0x83, 0xaf, 0x54, 0x32, 0x6f, + 0xc4, 0xf8, 0x4d, 0x6a, 0x58, 0x29, 0xa0, 0xad, 0x48, 0x30, 0x80, 0x6c, 0x05, + 0x75, 0x84, 0x92, 0xcd, 0x6a, 0xc4, 0x6b, 0xa0, 0x1a, 0x2b, 0x37, 0x22, 0xb5, + 0xe4, 0xcd, 0xaf, 0xbb, 0x3f, 0x36, 0x78, 0x5f, 0x42, 0x4a, 0xf0, 0x44, 0xda, + 0xc5, 0xdb, 0x5f, 0x7d, 0xf8, 0x39, 0xeb, 0x63, 0xc0, 0xc1, 0x7d, 0x8b, 0x0c, + 0x79, 0xdb, 0x86, 0x30, 0x94, 0x20, 0x15, 0xbe, 0x13, 0xf7, 0x9a, 0xf6, 0xf4, + 0x3e, 0x5a, 0xb0, 0x77, 0x81, 0x14, 0x79, 0x8f, 0x44, 0x22, 0x58, 0xee, 0xdc, + 0x43, 0x6f, 0xcc, 0x38, 0x6b, 0x36, 0xb5, 0x7e, 0x19, 0x17, 0xd7, 0x20, 0x17, + 0x73, 0x66, 0xf4, 0x24, 0xb0, 0xa5, 0x4b, 0x0b, 0x60, 0xf4, 0xfb, 0x13, 0x58, + 0xc2, 0x0a, 0xa4, 0x1d, 0xc5, 0x02, 0xe1, 0xdd, 0x8a, 0x16, 0x33, 0xf3, 0xd8, + 0xe3, 0x27, 0x6b, 0x59, 0xe7, 0xd2, 0xc4, 0xe6, 0x24, 0xa6, 0xf5, 0x36, 0x95, + 0xbc, 0xaf, 0x24, 0x7e, 0x36, 0x48, 0x3f, 0x13, 0xb2, 0x04, 0x42, 0x22, 0x37, + 0xfc, 0x6a, 0xb3, 0xeb, 0xa0, 0x2f, 0xc4, 0x14, 0x2b, 0x42, 0x97, 0xeb, 0xb5, + 0x68, 0x3d, 0xb8, 0xd2, 0x43, 0x19, 0x70, 0x6a, 0xd2, 0x6a, 0xaf, 0xd8, 0x1c, + 0x53, 0xb7, 0x40, 0xf3, 0x45, 0x43, 0xa6, 0xb3, 0xe9, 0xf5, 0xbb, 0x7d, 0x5c, + 0x49, 0xe8, 0xc3, 0x7f, 0x61, 0x49, 0x21, 0x25, 0x4f, 0x32, 0x12, 0x39, 0x4c, + 0x79, 0x7d, 0x1c, 0xee, 0x78, 0x99, 0xb7, 0xb4, 0xb6, 0x5b, 0x59, 0xb7, 0x34, + 0x2f, 0x92, 0x53, 0x1c, 0x1d, 0x59, 0xe1, 0x79, 0x70, 0xb7, 0x31, 0x74, 0x14, + 0x43, 0x8c, 0xd8, 0x0b, 0xd0, 0xf9, 0xa6, 0x7c, 0x9b, 0x9e, 0x55, 0x2f, 0x01, + 0x3c, 0x11, 0x5a, 0x95, 0x4f, 0x35, 0xe0, 0x61, 0x6c, 0x68, 0xd4, 0x31, 0x63, + 0xd3, 0x34, 0xda, 0xc3, 0x82, 0x70, 0x33, 0xe5, 0xad, 0x84, 0x88, 0xbf, 0xd9, + 0xc4, 0xbb, 0xbe, 0x8f, 0x59, 0x35, 0xc6, 0xc5, 0xea, 0x04, 0xc3, 0xad, 0x49, + 0xc7, 0x47, 0xa9, 0xe7, 0x23, 0x1b, 0xcd, 0x7d, 0x16, 0x21, 0x5e, 0x6e, 0x80, + 0x73, 0x7d, 0x6b, 0x54, 0xfe, 0xc8, 0xb8, 0x84, 0x02, 0xf0, 0x47, 0x52, 0x45, + 0xe1, 0x74, 0xa7, 0x45, 0xb8, 0x31, 0xf8, 0xfe, 0x03, 0xa7, 0x6f, 0xb9, 0xce, + 0xca, 0x4d, 0x22, 0xb7, 0x83, 0xc3, 0x28, 0xc6, 0x91, 0x5c, 0x43, 0x40, 0x50, + 0x64, 0xae, 0x56, 0xbc, 0x89, 0xe6, 0x4d, 0x15, 0x78, 0xe4, 0xd3, 0xa3, 0x4b, + 0xb9, 0x55, 0x91, 0xea, 0xf1, 0xd3, 0xda, 0x02, 0xa4, 0x54, 0x9f, 0xa8, 0x0d, + 0xb0, 0xff, 0x7c, 0xb0, 0x39, 0x93, 0xb6, 0x8a, 0xe1, 0x5a, 0x30, 0xe8, 0x79, + 0x49, 0xaa, 0x08, 0x0e, 0x94, 0xab, 0xde, 0x68, 0x89, 0x8c, 0x33, 0x92, 0xa2, + 0x17, 0xd6, 0x49, 0x61, 0x6b, 0xbe, 0x73, 0x9b, 0x13, 0xd1, 0x4d, 0xf0, 0x3f, + 0xf2, 0x76, 0x71, 0x48, 0x9b, 0xe0, 0xb4, 0xbe, 0xba, 0xaf, 0xa7, 0xd1, 0xe6, + 0x39, 0xd5, 0xb3, 0xe9, 0x94, 0xff, 0xb6, 0xb7, 0xa2, 0x09, 0xf6, 0xad, 0xfe, + 0x8d, 0x1e, 0x5c, 0xcf, 0x01, 0x0c, 0x19, 0x16, 0x8a, 0xeb, 0x00, 0xaa, 0x9d, + 0x68, 0x7e, 0x24, 0xad, 0xc0, 0xb1, 0x13, 0x5c, 0x70, 0xc9, 0x70, 0xe0, 0x90, + 0x3a, 0xf6, 0xe1, 0x70, 0x81, 0xd5, 0x81, 0x8e, 0x88, 0xb1, 0x4e, 0x4f, 0x60, + 0x1b, 0x8c, 0x06, 0x3e, 0x3f, 0x43, 0x87, 0xff, 0xa2, 0x32, 0x2a, 0x51, 0x81, + 0x90, 0x9f, 0x09, 0x80, 0xd6, 0x89, 0xde, 0x7f, 0x8e, 0x6a, 0x5c, 0x62, 0xa7, + 0x77, 0xd1, 0x75, 0x00, 0x2a, 0x13, 0x7d, 0xe8, 0x5b, 0x88, + ], + script_code: Script(vec![]), + transparent_input: None, + hash_type: 1, + amount: 1039204199089370, + consensus_branch_id: consensus::BranchId::Sapling, + sighash: [ + 0x6c, 0x4e, 0x32, 0x44, 0xc2, 0xd2, 0xbf, 0xb8, 0xd6, 0xf6, 0x69, 0x97, 0x77, + 0xa1, 0x1a, 0x64, 0xad, 0xfe, 0xe4, 0x9b, 0x2f, 0xc7, 0x81, 0xe6, 0x95, 0x15, + 0x34, 0xf9, 0x73, 0x44, 0x0d, 0xdb, + ], + }, + Test0243Vector { + tx: vec![ + 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0xdc, 0xf7, 0x58, 0x76, + 0xdc, 0xa6, 0x09, 0xf9, 0xd2, 0x84, 0x71, 0xf9, 0x97, 0xfa, 0x11, 0xf9, 0x9d, + 0x42, 0x3f, 0x9c, 0xf1, 0x73, 0x4b, 0xe8, 0xa5, 0xff, 0x99, 0x7d, 0x45, 0x1e, + 0xb3, 0xcf, 0x4b, 0x3d, 0xfd, 0xd9, 0x06, 0xac, 0xac, 0x63, 0x52, 0x63, 0x6a, + 0xdc, 0x17, 0xa8, 0x36, 0xb1, 0x2b, 0x43, 0xbe, 0xfc, 0x0b, 0xe0, 0xa1, 0xbd, + 0x36, 0x97, 0x72, 0x33, 0x80, 0x78, 0xb4, 0xff, 0x7d, 0x8e, 0x2d, 0x97, 0x9a, + 0x34, 0x41, 0xe1, 0xc8, 0xf5, 0xaf, 0xe4, 0x7b, 0x1e, 0x7d, 0xa5, 0x6c, 0xf0, + 0x06, 0x02, 0x00, 0x53, 0x11, 0x0c, 0x05, 0xcf, 0x00, 0xfd, 0xa3, 0xe6, 0xcc, + 0xe3, 0x60, 0x69, 0x04, 0x1f, 0xaf, 0xfd, 0x2f, 0x77, 0xff, 0x06, 0x00, 0x02, + 0xef, 0x12, 0xc3, 0x67, 0xf2, 0x1d, 0xea, 0x65, 0xc6, 0xea, 0xaf, 0xb8, 0xaf, + 0x58, 0x42, 0x8f, 0x6c, 0x54, 0x8e, 0x50, 0x17, 0x0f, 0x9e, 0x6f, 0xcd, 0xdf, + 0xe7, 0x51, 0xe0, 0xb6, 0x80, 0x12, 0xcb, 0x59, 0xdd, 0x46, 0x27, 0xef, 0xc3, + 0xea, 0x75, 0xdc, 0xd1, 0x5c, 0x8e, 0x0c, 0x3b, 0x8d, 0x8d, 0x7d, 0x6b, 0x23, + 0x31, 0xc8, 0xe4, 0x80, 0x16, 0x6b, 0x5a, 0xa7, 0x48, 0x5c, 0x9f, 0x0f, 0x83, + 0xe1, 0x9b, 0xc3, 0x0e, 0x64, 0x03, 0x82, 0x8c, 0xdb, 0x65, 0x2a, 0x55, 0x6b, + 0x12, 0x04, 0x09, 0x31, 0x40, 0x2a, 0xa6, 0xac, 0x34, 0xfc, 0x19, 0xfd, 0xc0, + 0x6e, 0x2e, 0x77, 0x87, 0xf5, 0x58, 0xd1, 0x42, 0xd9, 0x06, 0xea, 0xdb, 0x75, + 0x90, 0xc9, 0x41, 0x36, 0xda, 0x6a, 0x06, 0x35, 0x14, 0xd6, 0xa2, 0x5f, 0x7b, + 0x37, 0xd7, 0x66, 0x4f, 0x9b, 0x97, 0x09, 0x43, 0x3e, 0x6e, 0x70, 0x21, 0x18, + 0xa4, 0xab, 0x9e, 0x7a, 0x7a, 0x3e, 0x62, 0x59, 0x12, 0x99, 0x37, 0xd2, 0x9d, + 0x0d, 0xb2, 0x60, 0x70, 0x52, 0x3e, 0x8b, 0x06, 0x43, 0x13, 0x0a, 0xbe, 0xfe, + 0x94, 0x3b, 0x40, 0x12, 0x98, 0xae, 0x01, 0xa3, 0xab, 0x00, 0xab, 0xbc, 0x60, + 0xd7, 0xdb, 0x93, 0x3c, 0x7f, 0x07, 0xa8, 0xbf, 0x0f, 0x7c, 0xe1, 0x66, 0x0b, + 0xcc, 0xb4, 0x5e, 0x04, 0x2b, 0x45, 0x1b, 0x93, 0x50, 0x02, 0xce, 0xce, 0x27, + 0xf3, 0x6a, 0xba, 0x56, 0x47, 0xac, 0x28, 0xd8, 0x18, 0x6c, 0xdd, 0x1f, 0xb9, + 0x5d, 0xc1, 0x35, 0xd4, 0x89, 0x92, 0xf6, 0x8d, 0xa1, 0x2a, 0xd6, 0x1a, 0xc7, + 0x56, 0x68, 0x0d, 0xd7, 0xf8, 0xd0, 0x77, 0x4a, 0xbd, 0x6c, 0xfd, 0xa2, 0xf0, + 0x32, 0xaf, 0x3b, 0xe1, 0x39, 0xa6, 0x33, 0xd6, 0x73, 0x3c, 0x75, 0xd1, 0xab, + 0xa8, 0x90, 0x18, 0xc8, 0x57, 0x2b, 0x99, 0xcd, 0x30, 0xc5, 0x37, 0x06, 0x79, + 0x41, 0xdf, 0x1c, 0x4b, 0xc1, 0xfd, 0x57, 0x0f, 0x7b, 0x4d, 0xdc, 0x97, 0x51, + 0x86, 0x23, 0xe3, 0xae, 0x4a, 0x87, 0xbd, 0xb9, 0x66, 0xc9, 0x4d, 0x86, 0x1e, + 0x80, 0xde, 0x88, 0xc2, 0x92, 0xae, 0xe9, 0x38, 0x71, 0x94, 0xe2, 0x56, 0xc6, + 0x70, 0x07, 0x52, 0x30, 0x1c, 0x73, 0xfc, 0x95, 0x65, 0xa4, 0x04, 0x80, 0xd8, + 0x12, 0x6e, 0x9d, 0x08, 0x58, 0x79, 0xe2, 0x4b, 0x16, 0xe9, 0xc4, 0x85, 0xd8, + 0xf0, 0xd6, 0x18, 0xca, 0x0d, 0xd1, 0x21, 0xb5, 0x1a, 0x7c, 0xab, 0x23, 0x0c, + 0x5b, 0x45, 0x67, 0x2b, 0xdb, 0x8e, 0xa3, 0xa0, 0x40, 0xf7, 0xaa, 0xa0, 0x98, + 0xba, 0x26, 0x02, 0x5d, 0x2e, 0xab, 0x79, 0x48, 0x69, 0x3d, 0xd5, 0xf6, 0xd3, + 0x09, 0x65, 0x01, 0xe9, 0xe0, 0x71, 0x25, 0xd7, 0xeb, 0x29, 0x3b, 0x3a, 0xba, + 0xd5, 0x7f, 0xd5, 0xf0, 0x11, 0x64, 0x70, 0x02, 0xd6, 0x26, 0xae, 0x88, 0xdc, + 0x61, 0xe6, 0x47, 0xff, 0x46, 0x8d, 0xfa, 0x7a, 0x03, 0x07, 0x72, 0x78, 0x79, + 0x32, 0x75, 0xf1, 0x95, 0xa9, 0x75, 0x30, 0x28, 0x91, 0x78, 0x51, 0x61, 0x80, + 0xc5, 0xff, 0x99, 0x93, 0x53, 0x6b, 0xda, 0x15, 0x04, 0xba, 0x8b, 0xb4, 0x89, + 0x19, 0x88, 0xc1, 0x33, 0x4f, 0x31, 0xfb, 0x27, 0x6a, 0x03, 0x8a, 0xa8, 0xe9, + 0x67, 0xcb, 0x62, 0xa4, 0x92, 0x1b, 0xeb, 0x22, 0xb2, 0x08, 0xb0, 0x64, 0x58, + 0x18, 0x47, 0xb2, 0xf6, 0x4c, 0xa6, 0x48, 0x37, 0x00, 0x72, 0x16, 0xde, 0x6e, + 0xca, 0xff, 0xeb, 0x4b, 0x69, 0xe6, 0x33, 0x47, 0xf8, 0x4a, 0xbc, 0xad, 0x8f, + 0x2e, 0x75, 0x7d, 0x58, 0x61, 0xce, 0x77, 0xee, 0x46, 0x51, 0x3d, 0xa7, 0x41, + 0x68, 0x37, 0xdc, 0xb2, 0x3d, 0x33, 0xea, 0x72, 0xaf, 0x23, 0xd0, 0xad, 0x8c, + 0x93, 0x07, 0xd0, 0xb5, 0x85, 0x8d, 0xa9, 0x5b, 0x77, 0xff, 0xf9, 0x02, 0x7b, + 0x88, 0x59, 0xe1, 0x1d, 0xcb, 0xd5, 0x98, 0x35, 0x0e, 0xee, 0x50, 0x93, 0x94, + 0x81, 0x70, 0x8e, 0xa7, 0x08, 0xeb, 0x9f, 0x66, 0x43, 0x88, 0xb9, 0xc6, 0x4d, + 0x6a, 0xf0, 0xf9, 0x66, 0x90, 0x34, 0x24, 0x00, 0x34, 0x8e, 0x92, 0x9e, 0x07, + 0x46, 0x02, 0x53, 0xf3, 0x83, 0x90, 0xf8, 0x7b, 0xd6, 0xc0, 0x53, 0x08, 0xc3, + 0xbd, 0xe2, 0x52, 0x28, 0xe0, 0xfa, 0x08, 0x80, 0xb0, 0x8e, 0xf3, 0x4a, 0x5a, + 0x9c, 0xc0, 0xea, 0x0a, 0x67, 0xca, 0x65, 0xb6, 0xff, 0xd0, 0x05, 0x57, 0x29, + 0x09, 0xf1, 0xc4, 0x2d, 0xd7, 0x45, 0xee, 0xee, 0x9d, 0xd6, 0xb4, 0x43, 0x9c, + 0x9f, 0x3f, 0x98, 0xa1, 0x18, 0xfe, 0x16, 0x69, 0x8e, 0x9c, 0xef, 0xf5, 0x58, + 0xf1, 0x60, 0x66, 0x97, 0x5f, 0xe3, 0x95, 0x83, 0xe9, 0xb5, 0x85, 0x3b, 0x13, + 0x11, 0x39, 0x15, 0x80, 0x01, 0x9f, 0xe5, 0x5d, 0x59, 0xd1, 0xc8, 0x28, 0xd3, + 0xfe, 0xb6, 0xa3, 0xb9, 0xce, 0x92, 0xd0, 0x89, 0xae, 0x4b, 0x40, 0x8e, 0x23, + 0xd6, 0xa4, 0x37, 0xd4, 0x98, 0x9b, 0x51, 0x9b, 0x7a, 0x9e, 0xb0, 0x8a, 0xe6, + 0xd4, 0x48, 0xa7, 0xa1, 0x6e, 0x8a, 0xed, 0x26, 0xa2, 0xec, 0xd0, 0xca, 0xd8, + 0x08, 0x44, 0xfd, 0x06, 0x50, 0xd8, 0xc4, 0xe4, 0xd2, 0xaf, 0x90, 0x65, 0x67, + 0x48, 0xd8, 0x09, 0x9a, 0x0c, 0x75, 0x6f, 0xc1, 0x6c, 0xca, 0x06, 0xa3, 0x34, + 0x43, 0x07, 0x02, 0xae, 0x19, 0x61, 0x66, 0x5b, 0x48, 0x45, 0xac, 0xd1, 0xa8, + 0xe3, 0x41, 0x01, 0xe6, 0x8b, 0xb6, 0x44, 0xac, 0x03, 0x4d, 0xc6, 0x3e, 0x6e, + 0x34, 0x4c, 0x3d, 0x63, 0x76, 0x2a, 0x7a, 0x5b, 0xf5, 0x9f, 0x13, 0x09, 0x54, + 0x10, 0x98, 0x1d, 0x6b, 0x6b, 0x16, 0xbc, 0xd4, 0xc9, 0xfa, 0x68, 0xaf, 0x6e, + 0x53, 0x01, 0xef, 0x19, 0xbf, 0x3a, 0x43, 0x2e, 0x40, 0x6f, 0x85, 0x67, 0xeb, + 0xd9, 0x77, 0x2e, 0x92, 0xb5, 0xca, 0x5a, 0x59, 0x96, 0x71, 0xcb, 0xfd, 0x7d, + 0xdf, 0xa3, 0x63, 0xa5, 0x36, 0xb7, 0xac, 0x45, 0xf5, 0x7c, 0xc3, 0x7d, 0x09, + 0x89, 0x6f, 0xa9, 0x06, 0x97, 0x2e, 0x55, 0x71, 0x80, 0xa4, 0xab, 0x5a, 0xd0, + 0x9d, 0x88, 0x46, 0xdd, 0x6d, 0xa7, 0x48, 0x76, 0x54, 0x36, 0xe0, 0x16, 0x02, + 0x40, 0xbd, 0x5c, 0x92, 0x16, 0x66, 0xa1, 0xee, 0xaa, 0xce, 0x04, 0xa7, 0x1b, + 0x50, 0x3a, 0x1c, 0xad, 0xf8, 0x0b, 0x39, 0x24, 0x26, 0x6c, 0x59, 0x50, 0x4f, + 0x8f, 0x21, 0x5f, 0x61, 0x8b, 0x05, 0xd5, 0x45, 0x43, 0xb6, 0xe2, 0x6d, 0x82, + 0x59, 0x6f, 0xc5, 0x3b, 0x52, 0x31, 0x2c, 0x77, 0x6d, 0x12, 0xeb, 0x2b, 0x65, + 0x9b, 0x4f, 0xb0, 0x98, 0xdf, 0x87, 0xd6, 0x83, 0xcf, 0x9e, 0x54, 0x12, 0xee, + 0x56, 0xc3, 0xfe, 0x98, 0x41, 0xd7, 0x3f, 0xd0, 0x70, 0xdf, 0xa5, 0x1f, 0x5b, + 0xaf, 0xed, 0xf2, 0x06, 0xf1, 0x3c, 0x52, 0x4e, 0x5c, 0x50, 0xca, 0xc9, 0x90, + 0x6e, 0xfa, 0x39, 0x32, 0x90, 0x04, 0x2e, 0x3b, 0xc5, 0x9f, 0x96, 0x0b, 0x7d, + 0x24, 0x0a, 0xe4, 0x43, 0xfc, 0x49, 0x26, 0x9c, 0xe0, 0x00, 0x61, 0xe6, 0x5c, + 0x6d, 0x74, 0x81, 0x2a, 0x30, 0xdd, 0x5f, 0x5f, 0xe7, 0x4e, 0xff, 0x61, 0xe0, + 0xcb, 0xab, 0x3c, 0xec, 0x75, 0xd0, 0xae, 0xf9, 0x50, 0x83, 0x18, 0x94, 0x52, + 0xdd, 0x3d, 0x9e, 0xdf, 0x44, 0x87, 0xbc, 0x73, 0x4c, 0x8b, 0x24, 0xf2, 0x12, + 0x96, 0xe4, 0xe9, 0xef, 0x11, 0x7d, 0x7f, 0xb9, 0x77, 0xe3, 0xb0, 0xe6, 0x40, + 0x6e, 0x63, 0x08, 0x59, 0x06, 0x33, 0x1a, 0x93, 0x03, 0x3d, 0x1c, 0xb8, 0x36, + 0x0f, 0xe6, 0xfe, 0xa6, 0x1a, 0x68, 0x26, 0xdf, 0x36, 0x25, 0x57, 0x89, 0xf9, + 0x2e, 0x40, 0xba, 0xfc, 0xb2, 0xeb, 0xcb, 0x9e, 0x55, 0x6f, 0x6c, 0x0c, 0xca, + 0xdc, 0x6a, 0xf0, 0x8e, 0x31, 0xec, 0x4a, 0xd5, 0x28, 0x80, 0x34, 0xe1, 0x6d, + 0x15, 0x5c, 0xfd, 0xca, 0xda, 0x7b, 0xab, 0x59, 0x9c, 0x2f, 0xa4, 0xad, 0x2e, + 0x62, 0x93, 0xf9, 0xfe, 0x09, 0x71, 0x69, 0x14, 0x82, 0x76, 0xb6, 0xa9, 0xea, + 0xa7, 0x2f, 0x14, 0x8b, 0x0c, 0x95, 0x65, 0xc3, 0xc2, 0xdd, 0x63, 0x12, 0x5e, + 0x0f, 0xa5, 0x30, 0x86, 0x1a, 0x71, 0x0d, 0xf8, 0xe4, 0x81, 0xf2, 0x71, 0x29, + 0x20, 0xf8, 0x78, 0x7e, 0x0a, 0xed, 0xfe, 0x61, 0x8a, 0xff, 0x50, 0xa3, 0xb5, + 0x62, 0x13, 0x88, 0x4d, 0x62, 0x62, 0xc1, 0x1d, 0xeb, 0xf2, 0xba, 0x7e, 0x8a, + 0xd6, 0x69, 0x2c, 0xb1, 0x70, 0x78, 0x33, 0x14, 0x18, 0xda, 0x4b, 0xe0, 0x64, + 0xff, 0x52, 0x70, 0x07, 0x39, 0x34, 0xab, 0xcd, 0x2a, 0xb0, 0x46, 0x9e, 0xca, + 0xf7, 0x27, 0x5b, 0x4b, 0xd7, 0x2b, 0xc6, 0xed, 0x34, 0x47, 0x8e, 0xa4, 0x08, + 0x9b, 0x73, 0x6a, 0x16, 0xdd, 0x90, 0x6d, 0x49, 0xf2, 0x5c, 0x33, 0x82, 0x7c, + 0x57, 0x1c, 0xe0, 0xb5, 0xd7, 0x21, 0x77, 0xaa, 0x35, 0x08, 0x80, 0x4b, 0xc0, + 0xf8, 0xfa, 0xa9, 0x47, 0x12, 0x22, 0x31, 0x40, 0x2d, 0x2f, 0x5c, 0xc9, 0xa0, + 0xeb, 0x0e, 0x09, 0xd4, 0x27, 0xb4, 0x27, 0x28, 0x8d, 0x93, 0x7d, 0x9d, 0x72, + 0xb7, 0x74, 0x56, 0xf8, 0x86, 0x59, 0x4c, 0xd8, 0xc6, 0xa4, 0x62, 0xf7, 0x7f, + 0xd8, 0x30, 0x76, 0x46, 0x9c, 0xc0, 0xec, 0xba, 0x3c, 0xc4, 0x0c, 0xad, 0x69, + 0xe5, 0xb5, 0x41, 0x12, 0xea, 0xb3, 0x33, 0x96, 0xae, 0xcf, 0xbc, 0x21, 0x1f, + 0x1f, 0x79, 0xcf, 0x33, 0x10, 0x8e, 0x93, 0xd9, 0x53, 0x78, 0xba, 0xe6, 0x95, + 0x82, 0x74, 0xb3, 0x10, 0x88, 0xfb, 0xd8, 0xb3, 0xa3, 0xa0, 0xd1, 0x54, 0xa7, + 0x89, 0x73, 0x5b, 0x03, 0x49, 0xc4, 0xd5, 0x1c, 0x88, 0x9d, 0x08, 0x95, 0x2d, + 0xdd, 0x54, 0x88, 0xbe, 0x95, 0x56, 0x05, 0x94, 0xe6, 0x73, 0xfa, 0x05, 0x1b, + 0xf9, 0xb6, 0x14, 0xa1, 0x5e, 0x10, 0x0b, 0x60, 0xa0, 0xfe, 0x9a, 0x7e, 0x12, + 0xa9, 0xb2, 0x56, 0xdf, 0x58, 0x9b, 0x3e, 0x48, 0xe5, 0xb8, 0x0f, 0xb8, 0xcf, + 0xf0, 0x3e, 0x86, 0xf6, 0x0c, 0xc0, 0x70, 0xfb, 0x23, 0xc9, 0x7d, 0x4c, 0x14, + 0xfa, 0x3a, 0x73, 0x46, 0xff, 0x55, 0x6b, 0xc6, 0x85, 0x5a, 0x5f, 0x83, 0xe3, + 0xdc, 0xd9, 0xf6, 0xea, 0xb3, 0xda, 0xbc, 0xd4, 0x77, 0x50, 0xe3, 0x4e, 0x7c, + 0x09, 0x38, 0xf6, 0x4d, 0x45, 0x1e, 0x39, 0x50, 0x9e, 0x90, 0x27, 0x47, 0xa7, + 0x07, 0x55, 0x12, 0x20, 0x95, 0x08, 0x2a, 0xb7, 0x98, 0x59, 0x19, 0x07, 0x31, + 0x41, 0xb6, 0xd3, 0x70, 0x20, 0x91, 0xab, 0x71, 0x72, 0x80, 0xbd, 0xc5, 0x5e, + 0x79, 0x9c, 0x01, 0xad, 0x86, 0x41, 0x90, 0x4e, 0x3b, 0x1d, 0xd2, 0x9e, 0x1a, + 0x96, 0x4c, 0x73, 0x7d, 0x3c, 0x15, 0x5a, 0xfb, 0x30, 0x7b, 0x74, 0x8e, 0x41, + 0x12, 0xb4, 0x8b, 0x77, 0xd5, 0xed, 0x57, 0x00, 0xe6, 0x00, 0x2b, 0x18, 0xb0, + 0xfe, 0xd2, 0xcf, 0xfd, 0xf6, 0x1f, 0xd9, 0x93, 0x4b, 0x60, 0x73, 0x2f, 0x4d, + 0x37, 0x81, 0x0a, 0x91, 0xac, 0xef, 0x1e, 0x03, 0x8b, 0x81, 0xd7, 0x36, 0xd9, + 0x8e, 0xad, 0xa9, 0xcd, 0x7e, 0x0c, 0x2b, 0xe2, 0x7a, 0xb8, 0x50, 0x32, 0x06, + 0x60, 0x91, 0x22, 0x4e, 0xdf, 0x87, 0x2f, 0x79, 0x63, 0x7d, 0xda, 0x39, 0x16, + 0x79, 0x6a, 0x5c, 0x62, 0xf5, 0x7f, 0x1d, 0xe3, 0x76, 0x78, 0xb6, 0xde, 0xa0, + 0x08, 0x69, 0x93, 0x36, 0x74, 0xf8, 0x8e, 0x41, 0xa9, 0x18, 0x08, 0x07, 0x3b, + 0x0f, 0x43, 0x6e, 0xbe, 0x25, 0xa5, 0xf4, 0x4a, 0x60, 0x10, 0x33, 0xe2, 0x18, + 0x4b, 0x88, 0xdb, 0x79, 0xe9, 0x68, 0xca, 0x6d, 0x89, 0xb7, 0x49, 0x01, 0xbe, + 0x6c, 0x6d, 0xb3, 0x63, 0x65, 0x80, 0x18, 0x2e, 0x65, 0x8d, 0xfc, 0x68, 0x67, + 0x67, 0xd6, 0xd8, 0x19, 0xfa, 0x92, 0x3e, 0x0c, 0xdf, 0x3e, 0xa3, 0x65, 0x76, + 0xf8, 0x52, 0xbc, 0xd4, 0xe1, 0x96, 0xa7, 0x1a, 0x13, 0x29, 0xf6, 0xc3, 0xff, + 0x8e, 0x42, 0xe3, 0x09, 0x5a, 0xbd, 0x8e, 0xc1, 0x97, 0x99, 0x07, 0x13, 0xee, + 0x89, 0x39, 0x4c, 0x57, 0x19, 0xb2, 0x76, 0xde, 0x8f, 0x81, 0x8a, 0x34, 0xa7, + 0xbe, 0xc1, 0xf2, 0x68, 0x68, 0x2e, 0x91, 0x42, 0xc7, 0xd3, 0x87, 0x89, 0xf6, + 0x76, 0xcc, 0x12, 0xb7, 0x1a, 0xb6, 0x66, 0x35, 0xc5, 0x02, 0xe6, 0x9d, 0x05, + 0xb9, 0xc7, 0xef, 0x01, 0x52, 0x97, 0x75, 0xc6, 0x23, 0xa4, 0x8e, 0x4c, 0xc5, + 0xc4, 0x15, 0xc9, 0xfd, 0x56, 0x53, 0x65, 0xa4, 0x16, 0x37, 0x68, 0x78, 0x51, + 0x53, 0x88, 0x7f, 0xb5, 0xf9, 0x63, 0xe7, 0xac, 0xc1, 0x62, 0xf2, 0x80, 0x5f, + 0x45, 0xf4, 0x44, 0x87, 0xf8, 0x5e, 0x19, 0x9c, 0x1d, 0xf4, 0xa0, 0xfc, 0xa4, + 0xd4, 0x4b, 0xaa, 0x62, 0xda, 0x7a, 0xf5, 0xed, 0x69, 0x68, 0x41, 0x12, 0xd3, + 0x5f, 0x00, 0x73, 0x73, 0x2f, 0x5a, 0x1a, 0xc3, 0xe4, 0xf0, 0x21, 0xba, 0x5c, + 0x2c, 0x32, 0xf0, 0x6e, 0x6b, 0x90, 0xfa, 0xe2, 0xd2, 0x54, 0xcf, 0x09, 0xe7, + 0x69, 0x0c, 0xf4, 0xe3, 0xaa, 0x70, 0x30, 0x98, 0x74, 0x48, 0xe1, 0x47, 0xf9, + 0x43, 0xba, 0xb5, 0xca, 0xb5, 0x58, 0x02, 0x9a, 0x36, 0x02, 0x4d, 0x2e, 0x79, + 0x0f, 0xc6, 0xfd, 0x66, 0x7f, 0x17, 0x6e, 0x0a, 0xa9, 0x9d, 0xd1, 0xd7, 0x2b, + 0x57, + ], + script_code: Script(vec![0x6a, 0x51, 0x65, 0xac]), + transparent_input: None, + hash_type: 1, + amount: 691732482992802, + consensus_branch_id: consensus::BranchId::Sapling, + sighash: [ + 0x5d, 0x40, 0x5a, 0x1c, 0x4d, 0xed, 0x19, 0x87, 0x98, 0x8a, 0x10, 0x03, 0x64, + 0xa3, 0xcd, 0x6f, 0xe0, 0xba, 0x22, 0x20, 0xa6, 0xab, 0xce, 0x08, 0xc5, 0x17, + 0x13, 0x59, 0x55, 0x30, 0x65, 0xe9, + ], + }, + Test0243Vector { + tx: vec![ + 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x01, 0xa4, 0x96, 0x69, 0x60, + 0x21, 0x82, 0x08, 0x46, 0x69, 0x61, 0x12, 0x94, 0x90, 0xa7, 0xd8, 0xb6, 0x5c, + 0x14, 0x70, 0xba, 0xd8, 0xdb, 0x08, 0x28, 0xef, 0x06, 0xc1, 0xcb, 0x55, 0x70, + 0x0e, 0x85, 0xe2, 0x4f, 0xde, 0xa9, 0x08, 0x52, 0x00, 0x65, 0x63, 0x52, 0x51, + 0xac, 0x51, 0x87, 0x1f, 0x88, 0xfb, 0x02, 0x57, 0x2c, 0x4f, 0x50, 0xa0, 0xf8, + 0x01, 0x00, 0x06, 0x63, 0x00, 0x63, 0x63, 0x51, 0xac, 0xcb, 0x37, 0x9c, 0x68, + 0xc8, 0x7d, 0x04, 0x00, 0x03, 0x00, 0x6a, 0x63, 0x53, 0x3c, 0x92, 0xcf, 0x4c, + 0x1c, 0xac, 0x18, 0x99, 0x41, 0x99, 0xa8, 0xec, 0x8e, 0x01, 0x00, 0x04, 0x1b, + 0x31, 0xeb, 0xfb, 0xf8, 0x18, 0xa3, 0x99, 0x2b, 0xf3, 0x68, 0xc2, 0x4e, 0x9a, + 0xcc, 0x83, 0x14, 0x2b, 0x24, 0x0f, 0xec, 0x55, 0x4c, 0xed, 0xa1, 0xd3, 0xfc, + 0x04, 0x32, 0xc5, 0x72, 0x51, 0x34, 0x19, 0xaf, 0x1d, 0xe6, 0x56, 0xfd, 0xd0, + 0x39, 0x07, 0x22, 0xa7, 0xf4, 0x6a, 0x1f, 0xc0, 0x56, 0x3f, 0x0a, 0xda, 0xb8, + 0xbc, 0xbb, 0xb0, 0xd1, 0xb2, 0x29, 0xf5, 0xa5, 0xb9, 0x23, 0x03, 0x77, 0x5a, + 0x90, 0x4d, 0xec, 0x82, 0x7f, 0xd8, 0x7a, 0x18, 0x86, 0x0d, 0x6e, 0x8a, 0x4a, + 0x52, 0xb5, 0xcf, 0x44, 0xbe, 0x28, 0xa6, 0x2d, 0x41, 0x59, 0x02, 0x09, 0x3a, + 0x0c, 0x36, 0x5d, 0x29, 0x24, 0x12, 0x01, 0xb8, 0x26, 0x1a, 0x49, 0xd4, 0x91, + 0xaf, 0x04, 0x9b, 0x39, 0xe2, 0x6d, 0x13, 0x57, 0xc3, 0x06, 0x92, 0x64, 0x16, + 0x77, 0x6d, 0x7d, 0x13, 0xf8, 0x40, 0xbd, 0x82, 0xac, 0xa0, 0x1c, 0x83, 0x1c, + 0x98, 0x3f, 0x19, 0x85, 0xee, 0x0a, 0xda, 0xe8, 0xdb, 0x84, 0x47, 0xc0, 0xe5, + 0x1c, 0x09, 0xdf, 0xe3, 0xde, 0xe3, 0x88, 0x0a, 0x97, 0x13, 0xce, 0xb7, 0x45, + 0xab, 0xfd, 0xd9, 0xf1, 0xc7, 0xea, 0xd7, 0x63, 0x08, 0xcd, 0xee, 0xa2, 0x1c, + 0x8b, 0x09, 0x57, 0x02, 0x7c, 0x5d, 0x00, 0xe5, 0x0a, 0x43, 0x88, 0xc7, 0xaf, + 0x2b, 0xd6, 0x43, 0xcb, 0x5e, 0xae, 0x49, 0x27, 0x4d, 0x12, 0x30, 0xa4, 0xcd, + 0x49, 0x23, 0x7a, 0xe3, 0x7b, 0x38, 0x10, 0xc2, 0xc3, 0x95, 0x8a, 0x7d, 0xee, + 0x02, 0x34, 0x30, 0x1b, 0x89, 0xa2, 0xdf, 0x2a, 0x78, 0xef, 0x0b, 0xfb, 0x4b, + 0xf6, 0xb3, 0x87, 0xdf, 0x2c, 0x6c, 0x86, 0xe6, 0x1c, 0xd1, 0x0c, 0xa1, 0x1f, + 0x81, 0x13, 0x01, 0x26, 0x07, 0xf1, 0x5b, 0x28, 0x56, 0x24, 0x0f, 0xdc, 0x52, + 0x06, 0x5a, 0x10, 0x28, 0xc8, 0xa2, 0xdd, 0xfd, 0xd1, 0x5c, 0xf5, 0x26, 0x5f, + 0x87, 0x38, 0x8a, 0xb9, 0xbf, 0x21, 0xc9, 0xa7, 0x8c, 0x59, 0x03, 0x8a, 0x98, + 0xab, 0x64, 0xfd, 0x67, 0x10, 0x77, 0xd4, 0x72, 0xc2, 0x09, 0xdd, 0x72, 0x9b, + 0xd7, 0xf8, 0x48, 0x09, 0x45, 0xfb, 0xa7, 0x52, 0x09, 0x8a, 0x94, 0xcc, 0xb2, + 0x4c, 0xf3, 0xbc, 0x09, 0x2d, 0x42, 0x36, 0x46, 0x11, 0xa2, 0x93, 0xaf, 0xf3, + 0xc5, 0x79, 0x37, 0x2c, 0x12, 0xe1, 0x50, 0x90, 0xaa, 0x27, 0x23, 0x20, 0x57, + 0xf2, 0xed, 0xde, 0x4e, 0x1d, 0xb2, 0x92, 0xf7, 0xb1, 0x86, 0x47, 0x22, 0x67, + 0x35, 0x17, 0x6d, 0x90, 0xf1, 0x26, 0x5b, 0x37, 0x98, 0xcc, 0xab, 0xac, 0x0b, + 0x8d, 0x79, 0xb1, 0x77, 0x20, 0xb2, 0xba, 0x71, 0xd7, 0x85, 0x0c, 0xc2, 0xa0, + 0x87, 0x2b, 0xf0, 0xf4, 0xb8, 0x14, 0x36, 0x78, 0x59, 0xf8, 0x99, 0x48, 0xf0, + 0xa1, 0xa3, 0x83, 0x60, 0x4b, 0x9e, 0x1a, 0xa4, 0xc7, 0xea, 0x28, 0x92, 0x05, + 0x6f, 0x81, 0x28, 0x5b, 0xc2, 0x6f, 0x30, 0x08, 0x5d, 0xd0, 0xef, 0x3b, 0x14, + 0xd1, 0x7d, 0xda, 0x57, 0x30, 0x6a, 0xe4, 0xf6, 0x6c, 0x45, 0x9a, 0xee, 0x8a, + 0x4e, 0xd9, 0x02, 0xc6, 0x6e, 0x49, 0x18, 0xfa, 0xee, 0x8d, 0xc0, 0x06, 0x72, + 0x46, 0x96, 0x0d, 0xb1, 0xf8, 0xcd, 0x07, 0xbf, 0x90, 0xd7, 0x53, 0x7c, 0xc2, + 0x7b, 0xbb, 0x8c, 0x9d, 0x5b, 0x29, 0x62, 0xc4, 0x7e, 0xd1, 0x82, 0xa2, 0xfc, + 0xe0, 0x5f, 0x8e, 0x03, 0xc4, 0xe2, 0x5e, 0x49, 0x6d, 0xd5, 0x7d, 0x6a, 0xb3, + 0x45, 0x8f, 0xac, 0xbd, 0x91, 0xea, 0x22, 0x72, 0xff, 0xda, 0x47, 0xbf, 0xd0, + 0x17, 0x39, 0x20, 0xd7, 0x17, 0x51, 0x30, 0xf0, 0xe4, 0xd0, 0x93, 0x74, 0x41, + 0xbc, 0xe9, 0x8c, 0xfa, 0x5b, 0x33, 0x3b, 0x66, 0x19, 0x0f, 0x2b, 0x44, 0x71, + 0x38, 0xe8, 0xc2, 0x6d, 0x84, 0x12, 0xca, 0xc8, 0x20, 0x86, 0xd6, 0x1b, 0x5d, + 0x2c, 0x8c, 0xf0, 0xbb, 0xeb, 0xac, 0x5b, 0x89, 0xbf, 0xe8, 0x2b, 0x58, 0x91, + 0x76, 0x64, 0xba, 0xb9, 0x1c, 0xe2, 0xec, 0xe2, 0x90, 0xb2, 0x7b, 0x60, 0x52, + 0xd4, 0xbf, 0x99, 0x1a, 0x33, 0xf4, 0x58, 0x1a, 0x63, 0x36, 0x25, 0x78, 0x79, + 0x58, 0x89, 0x7f, 0xca, 0x4b, 0x98, 0xb7, 0xe7, 0x27, 0x7c, 0x5e, 0x6a, 0x1d, + 0x88, 0x59, 0x48, 0xc9, 0xd4, 0x84, 0xdd, 0x0c, 0xef, 0xef, 0x85, 0x4e, 0x81, + 0x76, 0xc3, 0x97, 0xdc, 0xfa, 0x77, 0x2e, 0x71, 0x14, 0x72, 0xe7, 0x90, 0xba, + 0x8d, 0x39, 0x35, 0xd5, 0x7c, 0xa3, 0x13, 0x49, 0x37, 0x9e, 0x62, 0x83, 0xa6, + 0xaa, 0x8f, 0xc9, 0x91, 0xef, 0xc7, 0xd3, 0xb7, 0xef, 0x66, 0xb9, 0x2f, 0xe0, + 0x9d, 0x35, 0x16, 0x27, 0x0a, 0xe1, 0x9a, 0x99, 0x92, 0x16, 0xee, 0xae, 0x16, + 0x21, 0x44, 0xac, 0xea, 0x56, 0x0d, 0x17, 0x72, 0x05, 0xf2, 0x6c, 0x97, 0x03, + 0xb5, 0x4e, 0x80, 0xaf, 0x1a, 0x87, 0x94, 0xd6, 0xd3, 0xf1, 0xc5, 0xee, 0xad, + 0x22, 0x0b, 0x11, 0x9f, 0x06, 0xb2, 0x00, 0x98, 0x6c, 0x91, 0x21, 0x32, 0xcb, + 0x08, 0xa9, 0x8e, 0x0f, 0xee, 0x35, 0xe7, 0xf7, 0x7f, 0xc8, 0x52, 0x1d, 0x38, + 0x77, 0x3e, 0x61, 0x4e, 0xee, 0xb8, 0xa3, 0xea, 0xd8, 0x6a, 0x02, 0x48, 0x32, + 0xe6, 0x4a, 0x4c, 0x75, 0x72, 0x0c, 0xdc, 0xdd, 0xf9, 0xd0, 0x77, 0x09, 0xa1, + 0x68, 0xd0, 0x10, 0x12, 0xc2, 0xe4, 0xf3, 0x34, 0x30, 0xf2, 0x99, 0x70, 0xc6, + 0x0b, 0xe8, 0xc5, 0xe2, 0xc8, 0xcc, 0x8a, 0x86, 0xed, 0xcd, 0x51, 0x2d, 0xa7, + 0x0d, 0xd7, 0xbb, 0x40, 0xe2, 0x7b, 0x32, 0xdf, 0x3d, 0x77, 0x6a, 0x4a, 0x7b, + 0x00, 0xe3, 0xbd, 0x8f, 0x69, 0x7f, 0x1f, 0x4e, 0x5c, 0x9f, 0xbe, 0xbe, 0xb4, + 0xe6, 0xfa, 0xd9, 0x1e, 0x09, 0x3d, 0xd5, 0xba, 0xc9, 0x92, 0xac, 0xbc, 0xb8, + 0x38, 0x3f, 0x9a, 0x8d, 0x8c, 0x04, 0xea, 0x6e, 0x2e, 0x0d, 0x03, 0xa2, 0xdf, + 0x83, 0xd4, 0xf4, 0x94, 0x59, 0x5b, 0x2c, 0xa1, 0x0b, 0x70, 0x79, 0x25, 0x9c, + 0x50, 0x7d, 0xf1, 0xec, 0xe4, 0x4d, 0xea, 0x4e, 0x9a, 0x4a, 0xe4, 0x0e, 0xc8, + 0x33, 0x1e, 0xeb, 0x03, 0x94, 0x73, 0xbd, 0x39, 0xc0, 0x9d, 0x01, 0x4b, 0x0d, + 0x7b, 0xb9, 0x01, 0x61, 0x66, 0x55, 0x4f, 0xf3, 0x8a, 0x1d, 0x77, 0xf2, 0xfd, + 0xa4, 0xe7, 0xeb, 0xa7, 0xa7, 0x8a, 0xb3, 0x1f, 0x38, 0x29, 0x42, 0x52, 0xa2, + 0xb1, 0x0f, 0xd2, 0x86, 0x5b, 0x57, 0x05, 0x05, 0x5d, 0xfe, 0x9b, 0x3e, 0x9e, + 0x8f, 0x7a, 0xd5, 0xf4, 0x00, 0x7d, 0xbe, 0x42, 0x2b, 0x3a, 0xa0, 0xbe, 0xb9, + 0xd1, 0xc8, 0x9d, 0x37, 0x46, 0x08, 0x54, 0xff, 0x6e, 0x5f, 0x03, 0xe5, 0xff, + 0x3d, 0x4f, 0x18, 0x48, 0xf4, 0xcc, 0x64, 0x21, 0x8a, 0x01, 0xf2, 0x47, 0x2b, + 0xb0, 0x55, 0x80, 0x2f, 0x97, 0xf3, 0x20, 0x41, 0xa7, 0x92, 0x79, 0x0b, 0x7c, + 0x22, 0x6b, 0x04, 0xa6, 0xea, 0xe8, 0x5f, 0x1b, 0x71, 0xca, 0x19, 0xa1, 0x71, + 0x89, 0x02, 0xb4, 0xc3, 0xa3, 0xb5, 0x06, 0xd8, 0xc1, 0xb7, 0xae, 0x72, 0x8c, + 0x9b, 0x6c, 0xc3, 0x17, 0xe5, 0xe0, 0xde, 0xe5, 0x33, 0xe2, 0xe9, 0x99, 0x73, + 0xd8, 0x83, 0xa4, 0x0c, 0x6e, 0x68, 0xf2, 0x31, 0xd2, 0xcb, 0x01, 0x2f, 0x60, + 0xc1, 0x43, 0xcc, 0xab, 0xdd, 0x40, 0x45, 0x59, 0x0d, 0x9e, 0x43, 0xfb, 0xa3, + 0x6f, 0xe4, 0xcf, 0xd9, 0x7b, 0x4b, 0xdd, 0x0c, 0x4d, 0x2c, 0x93, 0xc5, 0x72, + 0x8b, 0x12, 0x87, 0xfd, 0x25, 0x41, 0x72, 0x2c, 0x69, 0x9b, 0xc1, 0xa0, 0x05, + 0x83, 0xdb, 0xc9, 0x48, 0xd5, 0x32, 0x4a, 0xc5, 0xbd, 0x7a, 0x68, 0x09, 0x64, + 0x67, 0x3e, 0xdf, 0x2c, 0x6d, 0xeb, 0xb1, 0xc8, 0xe1, 0xd0, 0x24, 0x16, 0xe6, + 0xbd, 0xb2, 0xa7, 0x68, 0x1b, 0xf4, 0x29, 0x92, 0x25, 0xc2, 0x1b, 0x5d, 0xb6, + 0xa8, 0x45, 0xad, 0x10, 0x4d, 0x34, 0x29, 0xcd, 0xc5, 0x9e, 0x3b, 0xca, 0xcf, + 0x6d, 0xbc, 0x88, 0xaf, 0x0f, 0x67, 0xdc, 0xbd, 0xf3, 0xa0, 0x72, 0x3e, 0x4d, + 0x4b, 0xce, 0x32, 0x85, 0x1b, 0xb5, 0x19, 0x7a, 0x8f, 0x43, 0x30, 0xb2, 0x72, + 0x27, 0xf0, 0xb7, 0x71, 0xd0, 0xaf, 0x17, 0x5e, 0x9c, 0x3f, 0x6e, 0x1f, 0x68, + 0x46, 0x2e, 0xe7, 0xfe, 0x17, 0x97, 0xd9, 0x28, 0x40, 0x6f, 0x92, 0x38, 0xa3, + 0xf3, 0xfd, 0x83, 0x6a, 0x27, 0x56, 0xdd, 0x0a, 0x11, 0xe1, 0xab, 0x94, 0x9d, + 0x5e, 0x30, 0x89, 0x4f, 0x56, 0x29, 0x95, 0x25, 0xe6, 0x5d, 0x95, 0x0f, 0x2e, + 0xb5, 0x0b, 0x3a, 0x8e, 0xa7, 0xac, 0xad, 0x82, 0xde, 0x26, 0x2f, 0xa3, 0x44, + 0x80, 0xa2, 0x9c, 0x26, 0x19, 0xba, 0x45, 0x90, 0x3d, 0xf9, 0xa7, 0xf9, 0x86, + 0x2d, 0xc0, 0x49, 0xce, 0xf3, 0x97, 0xf7, 0x73, 0xbe, 0xed, 0xd3, 0x22, 0x6a, + 0x8c, 0xab, 0x1c, 0x86, 0x4d, 0x00, 0xb8, 0xfd, 0x37, 0xea, 0xf1, 0xd5, 0x93, + 0x5a, 0x5b, 0xbb, 0x6a, 0xd9, 0xf2, 0x7a, 0x1d, 0x8b, 0xaf, 0xc0, 0xac, 0x5f, + 0x58, 0x02, 0x36, 0x93, 0x82, 0x2a, 0x1d, 0xd4, 0xa7, 0xca, 0x1c, 0x49, 0xec, + 0x81, 0x4e, 0x8f, 0xe6, 0xe0, 0xe0, 0xde, 0x54, 0x6a, 0x4f, 0xbe, 0x7d, 0x25, + 0x67, 0x0b, 0x2f, 0xc6, 0x8a, 0x8f, 0xb2, 0xc4, 0xa6, 0x3d, 0xef, 0xec, 0x79, + 0xc9, 0x0c, 0x63, 0xff, 0x96, 0xe5, 0x40, 0xb7, 0x61, 0x5d, 0x43, 0xa6, 0x26, + 0x1d, 0x57, 0x73, 0x03, 0x06, 0xb6, 0x63, 0x2c, 0x8e, 0xe6, 0x1b, 0xaa, 0x4a, + 0xb4, 0xd3, 0x08, 0x4d, 0x65, 0x9c, 0xab, 0xcf, 0xc4, 0x06, 0x4c, 0x09, 0xd2, + 0x42, 0x69, 0xb3, 0x03, 0x17, 0x10, 0xb6, 0x7d, 0x3b, 0x0b, 0x73, 0x6f, 0xac, + 0xbc, 0x18, 0x1e, 0xb1, 0xdc, 0x8c, 0x49, 0x3f, 0x10, 0xdb, 0xe6, 0xfe, 0x45, + 0xfd, 0xd4, 0xab, 0x60, 0x22, 0xfa, 0xbd, 0xd3, 0x4c, 0x09, 0xf7, 0x51, 0x04, + 0xc3, 0x85, 0xc9, 0x26, 0x83, 0x41, 0xc1, 0x6e, 0xbe, 0x80, 0xf8, 0xc8, 0x0e, + 0x8e, 0x06, 0x23, 0x06, 0x03, 0x99, 0x5a, 0xde, 0x55, 0x61, 0xfe, 0xd4, 0x5c, + 0xf8, 0xd1, 0x14, 0xd4, 0xcf, 0x02, 0x42, 0x0c, 0x4b, 0x96, 0x2d, 0xc2, 0x02, + 0xf8, 0xa5, 0x07, 0xf3, 0xd8, 0xe8, 0xa3, 0x44, 0xfb, 0xa1, 0x0a, 0x32, 0x7f, + 0xf2, 0x22, 0x54, 0xf6, 0xc3, 0xac, 0x8f, 0x3c, 0xf9, 0x70, 0x0b, 0x1f, 0xd2, + 0xec, 0xbe, 0x9f, 0x4e, 0x91, 0xe4, 0x3a, 0x65, 0x4f, 0xff, 0x02, 0x7c, 0xd9, + 0x17, 0x4b, 0x63, 0x8e, 0x6e, 0xfe, 0xc4, 0xab, 0xfb, 0xa1, 0x87, 0xf8, 0xf3, + 0xdb, 0xa0, 0x45, 0x9d, 0xa6, 0xc3, 0xf8, 0x00, 0xcb, 0x6b, 0x61, 0x33, 0xa8, + 0xb4, 0xac, 0x1e, 0xf6, 0x58, 0xd1, 0x11, 0xc0, 0x3f, 0x07, 0x22, 0x08, 0xdc, + 0xc2, 0x07, 0xa2, 0x22, 0x3a, 0x70, 0x22, 0x92, 0x43, 0x2e, 0x83, 0x06, 0xfc, + 0x03, 0x04, 0x63, 0xe7, 0x54, 0xff, 0x0f, 0x15, 0x3d, 0x97, 0xbc, 0x9c, 0xe9, + 0x6d, 0xff, 0x4b, 0xed, 0x2f, 0x1e, 0xa5, 0xb8, 0xea, 0x87, 0x6d, 0x2e, 0xe4, + 0xe4, 0xf6, 0xe4, 0x9a, 0x4a, 0x85, 0xa9, 0xcf, 0x4a, 0x33, 0xdc, 0xd9, 0x36, + 0x60, 0xa4, 0x25, 0x43, 0xe5, 0x34, 0x22, 0x39, 0x0d, 0x66, 0x5b, 0xdd, 0x30, + 0x24, 0x78, 0xb3, 0x3c, 0x8d, 0x57, 0x47, 0x92, 0x41, 0x4c, 0x5f, 0xe5, 0xb7, + 0x4f, 0xe1, 0xd1, 0x69, 0x52, 0x5c, 0x99, 0x30, 0x1a, 0x3a, 0x68, 0xa0, 0xc8, + 0x5f, 0x02, 0x0f, 0xd5, 0x8f, 0x6d, 0x9f, 0x3a, 0xcb, 0x13, 0x9c, 0x96, 0x65, + 0x38, 0x56, 0xa3, 0x2e, 0x21, 0x02, 0x7a, 0xa2, 0xba, 0x18, 0x60, 0x10, 0xd5, + 0x3c, 0xdd, 0x4c, 0x41, 0x50, 0xcb, 0x2b, 0xb2, 0x42, 0x44, 0x65, 0x42, 0xb0, + 0x17, 0x84, 0x40, 0x1f, 0xa2, 0xcb, 0xf1, 0x22, 0xc9, 0xf1, 0x1d, 0x8c, 0x81, + 0x36, 0x98, 0x7b, 0x67, 0x86, 0x29, 0x93, 0x84, 0x58, 0x5f, 0x9c, 0xa2, 0x93, + 0x53, 0x7b, 0x4b, 0xe5, 0x72, 0x6f, 0x94, 0xd4, 0x77, 0x60, 0x5a, 0x8a, 0x6c, + 0x53, 0x06, 0x02, 0xbb, 0x46, 0xc4, 0xde, 0x20, 0x7f, 0xc5, 0x9e, 0x91, 0xe4, + 0xa9, 0x0a, 0x91, 0x11, 0x77, 0x74, 0x69, 0xf1, 0xe2, 0x87, 0x82, 0x76, 0x7d, + 0x9d, 0xe5, 0x7d, 0xea, 0xde, 0xad, 0xcb, 0x4a, 0xf5, 0x19, 0x3e, 0x09, 0xc9, + 0xbb, 0x74, 0x73, 0x77, 0x3a, 0x8c, 0xa5, 0x6d, 0x76, 0x51, 0x1d, 0x65, 0x99, + 0x20, 0xdb, 0x99, 0x64, 0xd3, 0x2b, 0xad, 0xb6, 0x1f, 0x4c, 0xf6, 0xb0, 0x22, + 0xd7, 0xc1, 0x53, 0x93, 0x18, 0x49, 0x64, 0x3e, 0x8b, 0x99, 0xea, 0xe0, 0x28, + 0x4f, 0x8b, 0x01, 0x15, 0xb4, 0x23, 0x7a, 0x7c, 0x5d, 0x81, 0x97, 0x0f, 0xe8, + 0x7c, 0x6f, 0x84, 0xb6, 0x68, 0x6c, 0x46, 0x25, 0xdb, 0xdd, 0x9d, 0x79, 0xd2, + 0xc5, 0x55, 0xdd, 0x4f, 0xce, 0xed, 0x2c, 0x5e, 0x5e, 0x89, 0x6f, 0x63, 0x1a, + 0xe4, 0x59, 0x7e, 0x9c, 0xc0, 0xbe, 0xe7, 0xb3, 0x02, 0x5f, 0x95, 0x56, 0x10, + 0x6a, 0x84, 0x3a, 0x18, 0x22, 0x7f, 0x5a, 0xb9, 0x61, 0x7d, 0x7b, 0xcb, 0x1a, + 0xf5, 0x28, 0xfa, 0xa7, 0xa0, 0x52, 0xea, 0x4f, 0x52, 0xca, 0x59, 0x45, 0x57, + 0xfd, 0xad, 0x33, 0x05, 0x2b, 0xc8, 0x2b, 0x39, 0xc6, 0xa6, 0x09, 0xa0, 0x70, + 0x75, 0x3d, 0x78, 0x8b, 0x2c, 0x4a, 0x2c, 0xae, 0xbb, 0xe7, 0x9f, 0xf0, 0x12, + 0x07, 0x1c, 0x07, 0x08, 0x10, 0x94, 0xad, 0x60, 0x59, 0xc2, 0x8f, 0x48, 0xe5, + 0x56, 0xc4, 0xe8, 0xd8, 0xc5, 0x37, 0x8b, 0xc2, 0x93, 0x07, 0x6b, 0xb4, 0x97, + 0x07, 0x5f, 0x9c, 0xa0, 0xba, 0x13, 0x11, 0x55, 0x0f, 0xa2, 0x17, 0x3d, 0x0e, + 0xb1, 0xf0, 0xbd, 0xdd, 0xf3, 0xb3, 0xd5, 0xc2, 0x43, 0xff, 0xea, 0xbe, 0xe8, + 0x23, 0xcd, 0x63, 0xb4, 0x39, 0x39, 0xce, 0x95, 0x46, 0xed, 0x4c, 0x41, 0xe6, + 0x0c, 0xcc, 0x7e, 0x1c, 0x54, 0x3c, 0xb3, 0xe2, 0xd3, 0x50, 0xe2, 0xe2, 0xe9, + 0x74, 0x21, 0x5c, 0xf7, 0xaa, 0x96, 0x9b, 0x66, 0x81, 0x14, 0xac, 0xdb, 0x29, + 0xf4, 0xcd, 0xcf, 0xdc, 0xec, 0x2a, 0x8c, 0xe4, 0xf5, 0x95, 0xf4, 0xff, 0x5f, + 0x70, 0x7e, 0x7f, 0xa4, 0xde, 0xe8, 0xbf, 0x8f, 0x39, 0x52, 0xae, 0x32, 0xe7, + 0x7f, 0x34, 0xf8, 0xb3, 0xab, 0xaa, 0xe9, 0x69, 0x28, 0xba, 0x4a, 0x6c, 0x0f, + 0xbf, 0x5b, 0x29, 0x19, 0x2d, 0xae, 0x80, 0x0d, 0xfa, 0x79, 0x57, 0x0c, 0xaf, + 0x0b, 0xb8, 0x33, 0xbd, 0x37, 0xa3, 0xd4, 0xbe, 0xaf, 0x09, 0x1f, 0x6b, 0x3e, + 0x55, 0xaa, 0xe5, 0x25, 0xf4, 0x13, 0xac, 0x80, 0x4c, 0x34, 0x7d, 0x54, 0x1d, + 0x2c, 0x09, 0xec, 0x6e, 0x54, 0x03, 0x5d, 0xf1, 0xd8, 0x30, 0x28, 0x4d, 0x9b, + 0x46, 0xff, 0xd2, 0xb2, 0xeb, 0x04, 0x0b, 0x61, 0x77, 0xd0, 0xa0, 0x9c, 0x16, + 0x60, 0x34, 0xa9, 0x57, 0xb1, 0x8f, 0xf6, 0x2e, 0x43, 0x4a, 0x3e, 0xc7, 0x32, + 0x62, 0xe4, 0xb2, 0x3f, 0xec, 0x9d, 0x29, 0x0a, 0x81, 0xc5, 0xb1, 0xf7, 0x3c, + 0xb4, 0xcd, 0x1c, 0x47, 0x2b, 0x86, 0xe5, 0x34, 0xab, 0x9e, 0x65, 0x53, 0x29, + 0x5d, 0xb0, 0xcf, 0x34, 0xe1, 0x39, 0x2a, 0xad, 0x5a, 0xbc, 0xf3, 0x98, 0x64, + 0x16, 0xa7, 0x0a, 0x9d, 0xbe, 0x59, 0xbb, 0x95, 0x8e, 0xbc, 0x71, 0x1c, 0x3a, + 0xe0, 0x8c, 0xaf, 0x52, 0xec, 0xa9, 0xcb, 0x54, 0xc4, 0x58, 0xbe, 0x7f, 0x5e, + 0x62, 0x14, 0xec, 0xa0, 0xf0, 0xa3, 0x81, 0x52, 0x62, 0x20, 0x01, 0x32, 0xe6, + 0x14, 0x54, 0x37, 0xec, 0xd2, 0x1f, 0xc8, 0x03, 0x6c, 0xb0, 0x0a, 0x49, 0x13, + 0x84, 0xc3, 0x41, 0xd8, 0x72, 0xdc, 0xda, 0x31, 0xb1, 0x42, 0x96, 0x73, 0xd9, + 0xc4, 0xf5, 0x7b, 0x81, 0xa0, 0x23, 0x6d, 0xa5, 0xec, 0x55, 0x02, 0xee, 0x29, + 0x63, 0x15, 0x0a, 0x00, 0x26, 0xbd, 0x63, 0xef, 0x67, 0x9e, 0x8c, 0x25, 0xb8, + 0xec, 0xee, 0x06, 0x56, 0x4a, 0xf3, 0xb0, 0x2d, 0xea, 0xb1, 0x06, 0x97, 0xa2, + 0x4d, 0xe6, 0x7d, 0x4f, 0x65, 0x04, 0xae, 0x27, 0x37, 0xb8, 0xe1, 0x73, 0x25, + 0xc2, 0xff, 0x15, 0x0c, 0x62, 0xe3, 0x79, 0x83, 0x44, 0xa1, 0xad, 0x3c, 0xbb, + 0x75, 0xb7, 0xf2, 0xa1, 0x57, 0x38, 0xf6, 0x01, 0xcf, 0x00, 0xf7, 0xe8, 0xbc, + 0x08, 0xb6, 0x89, 0x56, 0x7e, 0x4c, 0x7c, 0x01, 0x05, 0x8b, 0xee, 0xc2, 0x90, + 0x3c, 0x5c, 0xa6, 0xb4, 0xc4, 0xa5, 0x71, 0xf4, 0x60, 0xd6, 0x05, 0x87, 0x36, + 0x29, 0x96, 0xc6, 0xe1, 0x25, 0x54, 0xe8, 0xe3, 0x4e, 0x68, 0x3a, 0x27, 0xf8, + 0xa5, 0xff, 0x97, 0x1d, 0x5a, 0x0d, 0xc2, 0xf3, 0xef, 0xd3, 0x88, 0x99, 0x87, + 0xc1, 0xcc, 0x39, 0xce, 0x5d, 0x4b, 0x6b, 0x54, 0x4c, 0xe0, 0x4c, 0x71, 0xee, + 0x4b, 0xfa, 0xe5, 0x04, 0x0d, 0x61, 0xf0, 0x57, 0xe4, 0xf7, 0x70, 0x17, 0x28, + 0xf1, 0x20, 0x04, 0xa7, 0xf7, 0xed, 0xeb, 0x3a, 0xb2, 0x26, 0x09, 0xed, 0x33, + 0xb0, 0xab, 0x5d, 0x69, 0xb1, 0x2d, 0x45, 0x76, 0x57, 0x77, 0x14, 0xdf, 0xc6, + 0xdd, 0xa7, 0x1f, 0xf6, 0x01, 0x7b, 0x55, 0xb3, 0x35, 0x4d, 0x11, 0xe9, 0x21, + 0x67, 0x92, 0xe5, 0x60, 0x9f, 0xc0, 0x67, 0x88, 0xec, 0x66, 0x8e, 0xef, 0x64, + 0x5e, 0x63, 0xb3, 0x7e, 0x2d, 0x0c, 0xd2, 0x63, 0x04, 0x08, 0x00, 0xbc, 0x8a, + 0xa2, 0x80, 0x15, 0x6a, 0x79, 0x4f, 0x62, 0xa5, 0xf6, 0x93, 0xeb, 0xd9, 0x07, + 0x4b, 0x5d, 0x35, 0x4a, 0x71, 0xc8, 0xe3, 0x36, 0xde, 0x04, 0x08, 0xac, 0x70, + 0x80, 0xa2, 0xae, 0xee, 0x36, 0x6c, 0x58, 0x14, 0x6f, 0x32, 0xe3, 0x49, 0xa9, + 0xbc, 0x65, 0x7e, 0xc9, 0xe5, 0x7a, 0x89, 0xa0, 0x4c, 0xce, 0xee, 0x21, 0xbd, + 0xf3, 0x79, 0x3e, 0x49, 0xa5, 0xcf, 0x71, 0x3a, 0x42, 0xd0, 0x29, 0xdd, 0xdb, + 0x3d, 0xb4, 0x95, 0x09, 0x2c, 0x37, 0xce, 0x81, 0x4b, 0xe7, 0x3e, 0xf4, 0xec, + 0x8d, 0x70, 0xe8, 0x69, 0xbd, 0x2b, 0x78, 0x8f, 0x15, 0x00, 0xfe, 0x5e, 0xe5, + 0x6c, 0x0c, 0xe7, 0x04, 0xeb, 0xa2, 0xc1, 0xa3, 0xa3, 0x29, 0x0d, 0xe6, 0xec, + 0x68, 0xcc, 0xb5, 0xef, 0x7c, 0xd0, 0x21, 0x2a, 0x3f, 0x09, 0x96, 0x92, 0xcf, + 0x00, 0x04, 0x8d, 0xe5, 0x01, 0x26, 0x19, 0xe7, 0x41, 0x69, 0x2b, 0xfc, 0x74, + 0x05, 0xba, 0x3e, 0x87, 0x5e, 0x98, 0xb7, 0xca, 0x31, 0xe9, 0x65, 0xa1, 0x6f, + 0xdd, 0xb5, 0xb0, 0xb7, 0x72, 0xa3, 0xf5, 0xd0, 0x50, 0xd8, 0xad, 0x7f, 0x60, + 0x7f, 0x55, 0xc0, 0xdc, 0x52, 0xb4, 0x8f, 0xb0, 0x2a, 0x8b, 0x1d, 0xef, 0xc6, + 0xc3, 0x10, 0xb2, 0x47, 0x55, 0x59, 0xb4, 0x7e, 0x84, 0x4e, 0xd3, 0x77, 0x60, + 0xd7, 0xd1, 0x6f, 0x27, 0xcb, 0x48, 0xbf, 0x36, 0x16, 0xc4, 0x6f, 0xb0, 0xcf, + 0x3c, 0x8c, 0x28, 0xb9, 0x39, 0x27, 0x80, 0x0a, 0x29, 0x16, 0xa4, 0x07, 0xa6, + 0x0d, 0x68, 0x99, 0x7b, 0x10, 0x50, 0x51, 0x32, 0xad, 0x33, 0xf9, 0xce, 0x26, + 0xb4, 0xac, 0xba, 0x27, 0xa2, 0xa0, 0xc2, 0x18, 0xdb, 0x15, 0xa5, 0xd7, 0xaa, + 0xed, 0x4f, 0x6a, 0x72, 0x00, 0x36, 0x72, 0xca, 0x70, 0x49, 0x8b, 0x05, 0x49, + 0x4a, 0x93, 0x34, 0x1f, 0xcf, 0x96, 0xc0, 0x99, 0x4e, 0x42, 0x7b, 0xeb, 0xd3, + 0x56, 0xe4, 0x17, 0x6d, 0xec, 0x83, 0xe6, 0xfe, 0x80, 0x02, 0x9c, 0xfc, 0x47, + 0x8b, 0x88, 0xb6, 0xfd, 0x38, 0xc0, 0x39, 0xe0, 0x8b, 0x6f, 0xd9, 0x5d, 0xab, + 0xcf, 0xb2, 0x5f, 0x23, 0x8b, 0x26, 0x62, 0x06, 0xb0, 0xa2, 0xf9, 0xa2, 0xee, + 0xa1, 0xc0, 0x83, 0xfa, 0xc8, 0x08, 0xaa, 0xfa, 0x03, 0x65, 0x66, 0xcc, 0xd2, + 0x02, 0xbc, 0xfa, 0x41, 0x4e, 0x71, 0xc8, 0xb4, 0x89, 0x33, 0xc8, 0xed, 0x45, + 0x28, 0x7e, 0x1b, 0x43, 0x9b, 0x61, 0x06, 0xa5, 0x50, 0x94, 0x73, 0xf5, 0x7b, + 0x87, 0x88, 0xaf, 0x52, 0x7c, 0xf9, 0xa7, 0xab, 0xa5, 0x93, 0xdc, 0x9f, 0x5e, + 0x5a, 0xca, 0x1a, 0x64, 0x8e, 0xe4, 0x88, 0xf3, 0x6d, 0xeb, 0x4a, 0x3f, 0xdb, + 0x0f, 0xf6, 0xf5, 0xa3, 0x04, 0x4a, 0x63, 0xe1, 0x7f, 0x70, 0xa4, 0x30, 0x38, + 0x24, 0x60, 0x3a, 0xb5, 0x0e, 0x9b, 0xf7, 0x5b, 0xae, 0xb5, 0x7b, 0xfd, 0xc8, + 0x9b, 0xfd, 0xbc, 0x27, 0x27, 0x9d, 0x10, 0x73, 0xbf, 0x7f, 0x95, 0x05, 0xfb, + 0x31, 0x68, 0xd2, 0x06, 0xe2, 0xbf, 0x41, 0x02, 0xbf, 0x15, 0x9c, 0xff, 0x61, + 0xe6, 0xd6, 0x6c, 0x80, 0x37, 0x50, 0xda, 0x25, 0x4c, 0xd6, 0xb8, 0x1a, 0xed, + 0x42, 0x09, 0x97, 0x94, 0xb8, 0x4e, 0xce, 0x90, 0x42, 0x18, 0xe6, 0xf6, 0x6e, + 0xc6, 0x34, 0xe9, 0x2e, 0xef, 0xf4, 0x5f, 0x52, 0xe0, 0x4b, 0x4b, 0x79, 0x5a, + 0x15, 0x25, 0xaa, 0xf9, 0xc5, 0x1d, 0x62, 0x60, 0xfb, 0xd6, 0x4e, 0x8d, 0x8a, + 0xc2, 0x66, 0xdc, 0x6e, 0x7d, 0xf6, 0x15, 0x3a, 0xd9, 0x73, 0x55, 0x83, 0x79, + 0x28, 0x40, 0x4c, 0xd5, 0x81, 0xbc, 0x9c, 0xf9, 0xdc, 0xd6, 0x67, 0x47, 0xdc, + 0x97, 0x0a, 0x9f, 0x00, 0xde, 0xb4, 0x4b, 0xd6, 0x34, 0xab, 0x04, 0x2e, 0x01, + 0x04, 0xc1, 0xce, 0x74, 0x7f, 0x53, 0x75, 0x1b, 0xc3, 0x3e, 0x38, 0x4c, 0x6b, + 0x55, 0x76, 0x39, 0x9e, 0x16, 0xf8, 0xf0, 0xcb, 0x08, 0xde, 0x35, 0x08, 0x37, + 0x33, 0x95, 0x45, 0x87, 0xc1, 0xc2, 0x4d, 0xf2, 0xae, 0x66, 0x30, 0xff, 0xfe, + 0x99, 0x62, 0x15, 0xef, 0xe4, 0xd2, 0x62, 0x6d, 0xeb, 0x20, 0x56, 0x6a, 0x8f, + 0x5e, 0xad, 0x2f, 0x04, 0xdb, 0x5d, 0x08, 0x77, 0x9c, 0x9c, 0x65, 0x9e, 0xa3, + 0x43, 0xcd, 0x78, 0x46, 0x34, 0xc9, 0x9d, 0x8c, 0x8b, 0xad, 0xa9, 0x3b, 0xe8, + 0xe6, 0xda, 0x84, 0x15, 0x94, 0xba, 0xcf, 0x7c, 0xb3, 0xe6, 0x92, 0xc7, 0x4b, + 0x5f, 0xfe, 0x95, 0x78, 0x73, 0x11, 0x3a, 0x1a, 0xb0, 0x64, 0x02, 0x6f, 0x6d, + 0xee, 0x8b, 0x48, 0xa3, 0x84, 0xa1, 0x33, 0x83, 0x18, 0x36, 0x07, 0x86, 0x50, + 0x27, 0x84, 0xd1, 0x7d, 0x40, 0x0c, 0xe3, 0xd7, 0x21, 0x78, 0x7e, 0xdc, 0x4c, + 0x6b, 0x39, 0x35, 0x66, 0x25, 0x10, 0x77, 0x10, 0x00, 0x68, 0x0d, 0x78, 0xbb, + 0x49, 0xc5, 0x66, 0xef, 0x27, 0xdf, 0x61, 0xc9, 0xfe, 0xb9, 0x2c, 0x08, 0x97, + 0x59, 0x44, 0x87, 0x27, 0xa9, 0x34, 0xe3, 0x57, 0x95, 0x3d, 0xe1, 0xe9, 0xe9, + 0x0f, 0xd8, 0xdf, 0xfe, 0x40, 0xb8, 0x73, 0xbc, 0xd5, 0xb9, 0x82, 0x08, 0xdf, + 0x4b, 0x2c, 0xa2, 0x89, 0x7a, 0xf9, 0x0d, 0x8c, 0x8a, 0x23, 0x62, 0x30, 0x02, + 0xa9, 0xd8, 0xbc, 0x02, 0xe8, 0x06, 0x25, 0x4f, 0x41, 0x0e, 0x3b, 0x02, 0x40, + 0x9c, 0xbe, 0xbf, 0xce, 0x8a, 0xcf, 0x65, 0xcf, 0x39, 0x42, 0x6b, 0x64, 0xa6, + 0xba, 0x93, 0x74, 0xa1, 0x3d, 0x72, 0x59, 0x62, 0x3f, 0x65, 0xe9, 0x3e, 0x10, + 0xbf, 0x1f, 0x16, 0xba, 0x7a, 0xe0, 0x7d, 0xa9, 0x20, 0x58, 0x1c, 0x70, 0x40, + 0x9e, 0xdc, 0x7b, 0x9e, 0x21, 0x4e, 0x95, 0x91, 0x92, 0x82, 0x4c, 0x1d, 0xa6, + 0x5d, 0x33, 0x7b, 0x73, 0x75, 0xf5, 0x03, 0x2f, 0xea, 0xd3, 0xb4, 0xf3, 0x28, + 0x48, 0x11, 0x95, 0x0c, 0x7a, 0x90, 0xae, 0xc9, 0x75, 0xd4, 0xe3, 0x62, 0x9f, + 0x52, 0xd1, 0x9a, 0x16, 0x4e, 0x51, 0x16, 0xef, 0x3a, 0xd0, 0x22, 0x44, 0x2d, + 0x1e, 0xec, 0x76, 0xb8, 0x88, 0x73, 0x8b, 0x53, 0xe5, 0x05, 0x58, 0xa7, 0x0f, + 0x20, 0xc8, 0xac, 0xb5, 0x8d, 0xee, 0x63, 0x27, 0x15, 0xe4, 0x78, 0xe2, 0xbc, + 0x21, 0xbc, 0xfb, 0xe3, 0x15, 0x59, 0x96, 0xca, 0xe7, 0xbd, 0x97, 0xf0, 0x2b, + 0x51, 0x6d, 0x32, 0x00, 0xfb, 0x3c, 0x17, 0x39, 0x7c, 0xc1, 0x2b, 0xb7, 0xa1, + 0x9f, 0xd4, 0x36, 0xe6, 0x7a, 0xbc, 0xe6, 0x6d, 0x30, 0xfe, 0xc0, 0x47, 0xfb, + 0x27, 0x70, 0x82, 0x0e, 0x47, 0x6f, 0x3e, 0x32, 0xbc, 0x48, 0x3b, 0xf5, 0x31, + 0x64, 0xae, 0x49, 0x70, 0xf1, 0x1b, 0x9c, 0xae, 0xe4, 0xed, 0x6c, 0xb8, 0xd2, + 0xd7, 0x0f, 0x69, 0x13, 0xd8, 0xe0, 0x2a, 0xf8, 0xfb, 0xb1, 0xe4, 0x09, 0xb4, + 0xef, 0x08, 0x04, 0x48, 0xe5, 0x3b, 0xe6, 0xe5, 0xe6, 0x05, 0x75, 0xdf, 0xde, + 0x94, 0x28, 0xb0, 0x06, 0x96, 0x61, 0x1a, 0x2f, 0x72, 0x33, 0x2a, 0xe2, 0x90, + 0x23, 0xdd, 0x88, 0xae, 0x77, 0xf1, 0x5b, 0x8a, 0xe2, 0xc2, 0x4b, 0x86, 0xcf, + 0x3d, 0x57, 0x43, 0x9c, 0xaf, 0x17, 0xf2, 0x8e, 0xda, 0x94, 0x93, 0x2e, 0xef, + 0x28, 0x53, 0x4e, 0x16, 0x49, 0xce, 0xf8, 0x85, 0x40, 0xfc, 0xb1, 0xa6, 0x3e, + 0x11, 0x5c, 0x58, 0x22, 0xaf, 0xa4, 0x40, 0xc8, 0xd7, 0x9d, 0x66, 0xf9, 0xbb, + 0x1f, 0x48, 0xe1, 0x14, 0x0b, 0x06, 0xec, 0x87, 0x18, 0x3c, 0xbc, 0x6e, 0x95, + 0xf6, 0xcd, 0x5f, 0x7e, 0xbc, 0xad, 0xb8, 0x97, 0xc7, 0x7b, 0x4a, 0xfb, 0x36, + 0x7b, 0x95, 0x2d, 0xbb, 0x71, 0x7f, 0x75, 0x18, 0x90, 0xc8, 0xac, 0x30, 0x36, + 0xda, 0xcd, 0xbd, 0x78, 0x4a, 0x0d, 0x83, 0xab, 0xb8, 0x44, 0x6b, 0x3f, 0x93, + 0x96, 0x33, 0x5f, 0xbf, 0x0b, 0x44, 0xed, 0xc9, 0x9e, 0x1c, 0x67, 0xc5, 0xc3, + 0x81, 0x6a, 0xce, 0x76, 0x29, 0xe6, 0xe7, 0xb0, 0x28, 0xd6, 0xc8, 0x62, 0x74, + 0x9e, 0x86, 0xeb, 0xc5, 0x11, 0x7e, 0x21, 0xf4, 0x23, 0xe1, 0x8d, 0x09, 0x76, + 0xa1, 0xf5, 0x1d, 0x45, 0x47, 0x6d, 0xa5, 0x60, 0xff, 0x23, 0x15, 0x42, 0xbb, + 0x21, 0xc3, 0xde, 0xd2, 0xf2, 0x3b, 0x2a, 0x50, 0xe0, 0xb8, 0x22, 0x56, 0x90, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5d, 0x1d, 0x11, 0x65, 0xd7, 0x60, 0x70, 0x2e, 0xf1, + 0x03, 0xd2, 0x23, 0x67, 0x26, 0x90, 0x23, 0x59, 0xbe, 0x8d, 0x79, 0x73, 0x52, + 0xf9, 0x6d, 0x22, 0x46, 0xa2, 0xee, 0x0a, 0xf8, 0x0a, 0x2a, 0x2d, 0x89, 0xa5, + 0x85, 0x30, 0xd6, 0xe3, 0x6b, 0xd3, 0x3a, 0x00, 0xc1, 0xb8, 0x93, 0xd6, 0xff, + 0x8f, 0x90, 0x01, 0x44, 0x15, 0x1b, 0xee, 0x34, 0xc7, 0x94, 0x4b, 0x99, 0xed, + 0x6e, 0x79, 0x45, 0xe7, 0xf0, 0xde, 0x87, 0x26, 0x3d, 0x0b, 0xba, 0x6e, 0x55, + 0xac, 0x96, 0xa9, 0x6d, 0x49, 0x95, 0x12, 0x9b, 0xcf, 0xa9, 0xd9, 0xda, 0x6d, + 0xe6, 0xdd, 0x48, 0x26, 0x39, 0x15, 0x3a, 0x81, 0x69, 0xa4, 0xab, 0x46, 0x4e, + 0x39, 0x0b, 0x7f, 0x0a, 0x96, 0xd1, 0x4a, 0x73, 0xf7, 0x69, 0x7f, 0x7e, 0xce, + 0x3c, 0xd7, 0x81, 0xd3, 0x5d, 0xd2, 0x2a, 0xdd, 0xdd, 0x2f, 0x5d, 0x34, 0x52, + 0x04, 0xe4, 0xbb, 0x55, 0x7e, 0x88, 0x45, 0x3f, 0x18, 0x8c, 0xac, 0xbe, 0x92, + 0x29, 0x87, 0xbb, 0xe3, 0xb3, 0xd9, 0x76, 0x82, 0x61, 0x35, 0xc1, 0x03, 0xb6, + 0xca, 0x18, 0x2b, 0x63, 0xe9, 0xe6, 0x7f, 0x83, 0xdc, 0x9f, 0x48, 0x93, 0x33, + 0xd5, 0x2a, 0x7f, 0xd7, 0x68, 0x8a, 0x58, 0xd6, 0x62, 0x0b, 0x67, 0xe9, 0xc7, + 0xb0, 0x91, 0x6f, 0xef, 0x90, 0xf1, 0x5d, 0x8e, 0x4e, 0xb8, 0x0c, 0xf5, 0x99, + 0x68, 0x2f, 0x95, 0x4f, 0xf4, 0xe0, 0xb3, 0x71, 0x83, 0x13, 0x0c, 0xa2, 0xee, + 0xd0, 0x91, 0x3f, 0x46, 0xa4, 0xdb, 0x99, 0x2a, 0x1c, 0x3b, 0xf3, 0x19, 0xdc, + 0x86, 0x75, 0x94, 0x01, 0x01, 0x53, 0x7c, 0xff, 0xc4, 0xa8, 0x2d, 0x59, 0x9b, + 0xbe, 0xa0, 0xd4, 0x7e, 0x7a, 0xbf, 0xa9, 0x92, 0xb4, 0x99, 0x8c, 0xb2, 0x50, + 0x09, 0x55, 0xe6, 0x1c, 0x0d, 0x46, 0xb3, 0x21, 0x17, 0xfb, 0xb9, 0x7f, 0x7a, + 0x76, 0x32, 0xd8, 0x72, 0x4b, 0x5d, 0xff, 0x67, 0xf7, 0x5e, 0x2d, 0x31, 0x74, + 0x06, 0xa0, 0xce, 0xc2, 0x89, 0xed, 0x08, 0x3b, 0x7c, 0x58, 0x19, 0x81, 0x8c, + 0x50, 0x47, 0x93, 0xde, 0x53, 0xb6, 0xbf, 0xdb, 0x51, 0x0e, 0x7c, 0xa7, 0x29, + 0xba, 0x74, 0x3d, 0x10, 0xb3, 0xe9, 0x95, 0x7e, 0xfa, 0x84, 0x20, 0x13, 0x39, + 0x47, 0x7c, 0xf3, 0x5f, 0xbb, 0x6a, 0x27, 0x9b, 0xad, 0x9e, 0x8f, 0x42, 0xb9, + 0xb3, 0xfd, 0x6f, 0x3b, 0xc7, 0x70, 0x67, 0x1d, 0x9c, 0x19, 0x12, 0x2f, 0xa3, + 0x25, 0x6d, 0x09, 0x07, 0x36, 0xb6, 0xd6, 0x4e, 0xb9, 0xcc, 0x03, 0x20, 0xf1, + 0xea, 0xaa, 0x27, 0x1b, 0xa2, 0x86, 0x1e, 0xc4, 0xb3, 0xf3, 0xf6, 0xc8, 0x40, + 0xb6, 0x19, 0xff, 0x38, 0x8d, 0x81, 0xfc, 0x40, 0x44, 0xa0, 0xd5, 0x31, 0xa4, + 0xbb, 0x44, 0xc9, 0x3d, 0x09, 0x9d, 0xb0, 0x8a, 0x9b, 0xc3, 0x46, 0xa0, 0xb6, + 0x2f, 0x16, 0x8f, 0xfb, 0xdb, 0x73, 0x93, 0x66, 0xbb, 0x53, 0x5d, 0xde, 0x66, + 0xc2, 0xc1, 0x28, 0x7b, 0x3b, 0x27, 0x85, 0xae, 0xd6, 0x4c, 0xc4, 0x0c, 0xbc, + 0x7d, 0x33, 0xcb, 0xa4, 0xa9, 0xf3, 0xfc, 0xf5, 0xf8, 0x31, 0x36, 0xa4, 0x39, + 0x2d, 0x21, 0xa7, 0xf9, 0xeb, 0x1c, 0xe4, 0xb6, 0xe1, 0x7e, 0x6f, 0x4a, 0x85, + 0xa5, 0x79, 0x66, 0x9e, 0xfd, 0x0f, 0xb0, 0x98, 0x78, 0xe0, 0x88, 0xe3, 0x22, + 0xe9, 0x06, 0xe8, 0x0d, 0x27, 0xf8, 0xd0, 0xca, 0x7e, 0x79, 0x15, 0xab, 0x40, + 0x96, 0x59, 0xa6, 0xd8, 0x0f, 0xde, 0xd1, 0x0a, 0xff, 0x9f, 0xb7, 0x73, 0x74, + 0x9d, 0x79, 0x28, 0x57, 0xf6, 0x8c, 0x7e, 0x8c, 0xf5, 0x18, 0x26, 0x0a, 0x61, + 0x08, 0x6d, 0xe3, 0x2f, 0xff, 0x82, 0x39, 0xf4, 0x53, 0x61, 0x7a, 0x19, 0xf6, + 0xfe, 0xc2, 0x20, 0x67, 0x60, 0x65, 0xeb, 0xe2, 0x75, 0x7e, 0xfc, 0xac, 0xcb, + 0x77, 0xfc, 0x61, 0xe5, 0x9b, 0x97, 0x63, 0x7e, 0x92, 0x0d, 0xee, 0x5e, 0x7e, + 0x7a, 0x12, 0xe9, 0xd6, 0xd2, 0x28, 0xb2, 0x6b, 0x2f, 0xa8, 0x36, 0xf4, 0x72, + 0x83, 0x69, 0xad, 0xcd, 0xfc, 0xd0, 0x04, 0xdc, 0xf1, 0x9e, 0x27, 0xc0, 0xc0, + 0x84, 0x44, 0xd2, 0x9a, 0x12, 0x2b, 0x23, 0x09, 0xf7, 0x16, 0x3c, 0x99, 0x0e, + 0xb9, 0x26, 0x1f, 0xd4, 0x15, 0xc0, 0x45, 0x4a, 0x56, 0xaa, 0x3e, 0xaf, 0x9c, + 0x1f, 0x9b, 0xff, 0xf6, 0x04, 0x77, 0x6a, 0x4d, 0x25, 0xe7, 0xd3, 0xcd, 0xc5, + 0xc5, 0xf1, 0x9c, 0xd2, 0xa8, 0x79, 0x4a, 0x4f, 0x57, 0x16, 0x7f, 0xbc, 0x7e, + 0xaa, 0x06, 0x16, 0x4d, 0x51, 0xc4, 0x53, 0x06, 0x14, 0xbc, 0xf5, 0x20, 0xb2, + 0x63, 0x82, 0x0a, 0xa1, 0x7b, 0x20, 0xb4, 0x8c, 0xbf, 0x59, 0xd8, 0xe3, 0x09, + 0x32, 0x2e, 0xbe, 0x56, 0x6f, 0xbe, 0x46, 0xe0, 0xaa, 0x29, 0x76, 0x6a, 0xdf, + 0xdf, 0x01, 0x7a, 0x71, 0x05, 0x10, 0x3c, 0x7f, 0xca, 0xb7, 0xb0, 0x76, 0x48, + 0xc7, 0xc1, 0x16, 0x04, 0x84, 0xf7, 0x7a, 0x6c, 0x70, 0xa5, 0x38, 0x1b, 0x82, + 0x56, 0x40, 0xa1, 0xbe, 0x48, 0xe4, 0x15, 0xa1, 0xe6, 0xa2, 0x7d, 0x78, 0x02, + 0x2a, 0x8a, 0x2f, 0xf0, 0x70, 0xab, 0xf1, 0x23, 0x94, 0xe3, 0xae, 0x5a, 0x8c, + 0x23, 0xe3, 0x73, 0x3e, 0xa4, 0x7a, 0x44, 0xcb, 0x2c, 0x96, 0x8b, 0xca, 0x24, + 0x98, 0x37, 0xde, 0x1d, 0x39, 0xa5, 0xa1, 0xdc, 0xae, 0x71, 0x0c, 0xe0, 0x43, + 0x01, 0x69, 0xbd, 0x6e, 0x9f, 0x64, 0xab, 0xf1, 0xe6, 0x4e, 0xc4, 0x9e, 0xd0, + 0x80, 0x4e, 0xb6, 0x47, 0x74, 0x3a, 0xce, 0xa9, 0x29, 0xed, 0x0f, 0x7c, 0x90, + 0x15, 0xb0, 0xe8, 0x1e, 0x21, 0x29, 0xdb, 0x05, 0x0d, 0x5e, 0x78, 0xe6, 0x82, + 0xc8, 0x19, 0x93, 0xea, 0x87, 0x53, 0xc9, 0x91, 0xb0, 0x2e, 0x61, 0x81, 0x0e, + 0x74, 0x61, 0xed, 0x87, 0xb3, 0x80, 0xdb, 0x96, 0xab, 0xe3, 0xbe, 0xad, 0x0f, + 0x4b, 0x22, 0x12, 0xdb, 0x65, 0x8c, 0x11, 0xb8, 0x3f, 0x53, 0x11, 0x47, 0x85, + 0x27, 0x65, 0x98, 0xb0, 0x19, 0x7a, 0x7f, 0x1c, 0x25, 0x62, 0x7d, 0x79, 0x62, + 0x4d, 0xac, 0xee, 0x97, 0x7d, 0x9f, 0x4e, 0x1a, 0x35, 0xed, 0x2e, 0xaa, 0xd3, + 0xcb, 0x68, 0x25, 0x0a, 0xa9, 0xb3, 0xab, 0x1a, 0x83, 0x45, 0x72, 0x8e, 0x7d, + 0x1a, 0x78, 0xbe, 0x1f, 0xe4, 0x62, 0xce, 0x8e, 0xad, 0x52, 0x8f, 0x7c, 0x05, + 0x0f, 0x1f, 0x6e, 0x02, 0x2b, 0xa8, 0xb0, 0xce, 0xdf, 0x6e, 0x29, 0x7a, 0xb5, + 0x64, 0xca, 0x1a, 0x1f, 0xaa, 0xf4, 0xcf, 0xf1, 0xe4, 0x20, 0x32, 0xfb, 0xbb, + 0x38, 0x9d, 0x3f, 0x66, 0xd5, 0x75, 0x55, 0xef, 0x3f, 0x3e, 0x9e, 0x49, 0xc2, + 0xac, 0x4e, 0x85, 0xbb, 0x75, 0x1d, 0x62, 0x66, 0xc9, 0x03, 0x5b, 0x77, 0x9d, + 0x76, 0x9d, 0x49, 0x5c, 0x91, 0x8a, 0x05, 0x5e, 0x77, 0x67, 0xfb, 0xb4, 0xbb, + 0xac, 0x3f, 0x96, 0x3d, 0xe9, 0x97, 0x46, 0xec, 0x4d, 0xfb, 0x64, 0x2d, 0x9c, + 0x2b, 0x86, 0x38, 0xe1, 0x6c, 0x16, 0xe7, 0x27, 0x70, 0x79, 0x3b, 0x7e, 0xa1, + 0xd0, 0x70, 0xc4, 0xe1, 0x1c, 0xbc, 0x20, 0xd8, 0xff, 0x3b, 0xea, 0xd1, 0x0d, + 0xb9, 0xc9, 0x4a, 0xe0, 0x48, 0x27, 0x21, 0xe1, 0xf2, 0x2c, 0xef, 0xe0, 0xdf, + 0x7c, 0x57, 0x7a, 0xa3, 0x8e, 0xc0, 0xe6, 0xc7, 0x8c, 0x9b, 0xa1, 0x64, 0xe9, + 0xdd, 0x00, 0x55, 0xdd, 0xe8, 0x3e, 0x8a, 0xd2, 0x40, 0xe6, 0xdf, 0xdb, 0xfb, + 0xe1, 0x76, 0xe4, 0x55, 0x1f, 0xdd, 0xe9, 0x2d, 0xb1, 0x67, 0x27, 0x42, 0x04, + 0x41, 0x70, 0x06, 0x58, 0xb5, 0x0e, 0xbb, 0x5a, 0x16, 0x13, 0x26, 0x7e, 0xac, + 0x51, 0xc8, 0x0b, 0x19, 0xec, 0xb7, 0x86, 0xab, 0x3b, 0xb9, 0x37, 0xf0, 0xd9, + 0x8e, 0x08, 0xb9, 0xc9, 0xcd, 0x4d, 0xf1, 0x53, 0x4e, 0xfe, 0xe3, 0x8a, 0x8f, + 0x87, 0x8c, 0x9f, 0x3b, 0xdc, 0x7e, 0xfb, 0x2d, 0x53, 0xff, 0x84, 0xfb, 0x83, + 0xea, 0xe7, 0xc9, 0x9e, 0xff, 0xa6, 0x3c, 0x96, 0x49, 0xa1, 0xf1, 0x70, 0xd2, + 0x9a, 0xf0, 0x3a, 0x3b, 0x45, 0x58, 0x9f, 0xae, 0x81, 0xeb, 0x0b, 0x5d, 0x8e, + 0x0d, 0x38, 0x02, 0x1d, 0x3b, 0x5f, 0x07, 0xe8, 0x8c, 0x99, 0x04, 0x37, 0x6d, + 0x27, 0xf1, 0x3e, 0x44, 0x41, 0xd5, 0x38, 0x74, 0x42, 0xc5, 0xea, 0x0a, 0xf5, + 0xa2, 0x0a, 0x38, 0x32, 0xbc, 0x3b, 0x9c, 0x59, 0xb8, 0x4b, 0xca, 0x39, 0xb5, + 0x2c, 0xd6, 0xb1, 0xfa, 0x29, 0x32, 0xba, 0x9d, 0x66, 0xc4, 0x12, 0xf5, 0xcd, + 0x39, 0x35, 0x1e, 0x13, 0x33, 0xef, 0x85, 0xd0, 0xee, 0xe5, 0x45, 0xa7, 0xe4, + 0x06, 0xf6, 0xeb, 0x3b, 0xf8, 0x93, 0xf3, 0xed, 0xac, 0x94, 0x64, 0x33, 0x92, + 0xa2, 0x8b, 0x0e, 0x49, 0x0c, 0x51, 0xe4, 0xb7, 0x16, 0x3c, 0x1c, 0xf7, 0x57, + 0xd2, 0x24, 0x18, 0xdd, 0x63, 0x38, 0x1b, 0xa2, 0xf2, 0x98, 0x28, 0x83, 0x6f, + 0xe9, 0x78, 0xda, 0xb5, 0x20, 0x1b, 0x2d, 0xb0, 0x8c, 0x3b, 0x38, 0x9b, 0xa4, + 0xb6, 0xac, 0xf7, 0x78, 0xc2, 0xbf, 0x91, 0x02, 0xbe, 0x0c, 0x3e, 0x12, 0xd7, + 0x7a, 0xea, 0x6d, 0xf7, 0x53, 0x8e, 0x8c, 0xf3, 0x62, 0xba, 0xaa, 0xad, 0x1d, + 0xc5, 0x60, 0x42, 0xc6, 0xf2, 0x4c, 0xaf, 0x46, 0xbe, 0xd6, 0x6a, 0xbf, 0x4c, + 0x40, 0x2a, 0x74, 0x92, 0x4e, 0xcf, 0xd0, 0xa0, 0x8d, 0xed, 0xee, 0xa0, 0xef, + 0xce, 0xcd, 0x35, 0x2c, 0x27, 0x5f, 0x13, 0xed, 0x20, 0x76, 0x03, 0x82, 0x2b, + 0x1e, 0xf9, 0x97, 0xb7, 0xed, 0x42, 0xf4, 0xa5, 0x76, 0xb9, 0xe4, 0xc0, 0x07, + 0x38, 0x56, 0x3f, 0x82, 0xa7, 0x62, 0x85, 0x46, 0x7d, 0xa2, 0x95, 0xc2, 0x3b, + 0xa1, 0xc5, 0x87, 0xeb, 0xef, 0xaf, 0x13, 0xcd, 0x4d, 0x50, 0xf2, 0x3c, 0xa5, + 0x74, 0x3c, 0x22, 0x5c, 0x38, 0x6d, 0x46, 0xd4, 0xac, 0x70, 0x83, 0x79, 0xef, + 0x99, 0x96, 0x74, 0x4b, 0x39, 0x12, 0x04, 0x4b, 0x35, 0x5f, 0x92, 0x7a, 0x67, + 0xaf, 0x1e, 0xf2, 0x6a, 0x71, 0x7f, 0xb5, 0xa8, 0x46, 0xac, 0x9d, 0xa1, 0x5e, + 0xa3, 0xf1, 0x8f, 0x8c, 0x36, 0x18, 0x3f, 0x87, 0x9b, 0xb9, 0xa3, 0xb2, 0x98, + 0xff, 0xf9, 0xa4, 0x89, 0x64, 0x6e, 0x77, 0x8e, 0x6d, 0x67, 0x01, 0xf9, 0xad, + 0xac, 0x7a, 0xe8, 0x82, 0x09, 0xa8, 0x43, 0xba, 0x8a, 0x55, 0xd1, 0x19, 0x2b, + 0xbe, 0xef, 0x31, 0xd0, 0x71, 0x45, 0x37, 0xf7, 0xa0, 0x35, 0xb0, 0x79, 0xc6, + 0xad, 0xd4, 0xab, 0x50, 0x61, 0x2d, 0x35, 0x89, 0x7a, 0x93, 0x3d, 0x49, 0xe8, + 0xef, 0x08, 0x6c, 0xdf, 0x96, 0xc8, 0x0d, 0x28, 0x56, 0xcc, 0xc7, 0xe4, 0x5f, + 0xc4, 0xef, 0xd4, 0xbf, 0x1b, 0x98, 0xab, 0x28, 0x89, 0x1b, 0x4a, 0xea, 0x7e, + 0xf8, 0x4c, 0xf7, 0x36, 0x93, 0x5c, 0x46, 0x6b, 0x24, 0x97, 0x4d, 0xf8, 0xf5, + 0x35, 0x5b, 0x8b, 0xa3, 0x20, 0xac, 0x5f, 0xbc, 0x47, 0x5a, 0xa2, 0xcf, 0x5a, + 0xd3, 0x77, 0x80, 0xbd, 0x9f, 0x9d, 0x46, 0x42, 0xcf, 0x6c, 0x2d, 0xc6, 0xb8, + 0x2f, 0x91, 0x7d, 0x09, 0xc4, 0xf7, 0x28, 0x88, 0xf9, 0x15, 0x53, 0x44, 0x7f, + 0xc5, 0x70, 0x26, 0x6d, 0xaa, 0xfd, 0x4b, 0x96, 0xcf, 0xe2, 0xa0, 0xb0, 0x67, + 0x92, 0x46, 0x9a, 0x72, 0x7d, 0xbe, 0xd0, 0x55, 0x91, 0xea, 0x60, 0x57, 0x32, + 0x20, 0x5e, 0x26, 0x05, 0x97, 0x8a, 0x3a, 0x90, 0x2c, 0x3c, 0xd6, 0x5f, 0x94, + 0x83, 0x00, 0xf7, 0x37, 0x51, 0x88, 0x15, 0xf4, 0x63, 0xd3, 0xc6, 0x1a, 0x18, + 0x9b, 0xc3, 0xbc, 0x84, 0xb0, 0x22, 0xf6, 0x3d, 0x65, 0x4f, 0x52, 0x0e, 0x3a, + 0x7a, 0xd8, 0x8e, 0x5d, 0x8d, 0xa1, 0x50, 0x14, 0xbe, 0x4b, 0xb9, 0x67, 0x99, + 0x27, 0xdc, 0x7e, 0x0f, 0xba, 0xf0, 0x58, 0xd9, 0x3f, 0x37, 0xc7, 0x2b, 0x28, + 0x6b, 0x02, 0xb7, 0x5f, 0x3c, 0xdb, 0xfb, 0x85, 0x0e, 0xed, 0x90, 0xcb, 0x23, + 0x39, 0x24, 0x32, 0xeb, 0xc3, 0x6b, 0xd2, 0x47, 0x54, 0x46, 0x9c, 0x03, 0x73, + 0x1a, 0x7e, 0xbb, 0xed, 0x28, 0x57, 0x78, 0x49, 0x81, 0xa0, 0x71, 0x67, 0x05, + 0xd9, 0xcb, 0x47, 0xd9, 0x87, 0xf8, 0x3d, 0x34, 0x21, 0xb1, 0x07, 0xd1, 0x55, + 0xdb, 0xb6, 0x61, 0xed, 0x08, 0xf2, 0xfc, 0x2e, 0x6b, 0x4a, 0x5b, 0x09, 0x77, + 0x64, 0x51, 0xd8, 0x73, 0xb2, 0xfc, 0x63, 0x68, 0x1c, 0xe3, 0x08, 0xc8, 0x08, + 0xf5, 0x38, 0x8c, 0xb1, 0xaa, 0x55, 0x89, 0xa1, 0x87, 0x73, 0xdb, 0x39, 0x07, + 0xa0, 0x6b, 0xef, 0x62, 0xd1, 0x29, 0x60, 0xaa, 0xe7, 0x2a, 0x2b, 0x89, 0x7e, + 0x26, 0xb5, 0x75, 0xfd, 0x04, 0x8a, 0x57, 0x22, 0x2c, 0x7c, 0x68, 0x0d, 0x54, + 0xdc, 0x73, 0x28, 0xd0, 0xf0, 0xf2, 0xd7, 0x0b, 0x43, 0x10, 0x8c, 0xb2, 0x0c, + 0x5c, 0x31, 0x16, 0x46, 0x31, 0xb0, 0xe5, 0xb3, 0xbd, 0x31, 0xb7, 0xdf, 0x8f, + 0x4c, 0x1f, 0xe1, 0x43, 0x4f, 0xa7, 0x47, 0x56, 0x70, 0x6f, 0x83, 0x10, 0x60, + 0xa5, 0xb7, 0x03, 0xdf, 0x9c, 0xd4, 0x2e, 0x24, 0x96, 0x0e, 0x50, 0x8a, 0x04, + 0x36, 0x11, 0x8d, 0x4a, 0x92, 0x07, 0xb6, 0xd8, 0x50, 0x59, 0x6d, 0xde, 0xbe, + 0x30, 0xf9, 0x28, 0xee, 0xea, 0xe7, 0x35, 0x98, 0xfb, 0x3d, 0x86, 0x9d, 0x2d, + 0x18, 0x15, 0xa9, 0xe1, 0x4d, 0x12, 0x79, 0xf7, 0xb4, 0xb6, 0x3f, 0x4b, 0xca, + 0x0f, 0x56, 0x68, 0x9b, 0xf8, 0x73, 0x3b, 0x03, 0x06, 0x49, 0x64, 0xa4, 0xb0, + 0x20, 0xb0, 0x60, 0xdc, 0xf4, 0x54, 0x71, 0xfa, 0x1d, 0x41, 0xe5, 0xee, 0x03, + 0xf9, 0xbd, 0x90, 0x65, 0x2b, 0x53, 0x72, 0x30, 0x3a, 0x3a, 0xb9, 0xbb, 0x2e, + 0xe3, 0x79, 0xb9, 0xaf, 0xcd, 0x1f, 0x6a, 0x3c, 0xb9, 0x00, 0x0b, 0xb1, 0x4e, + ], + script_code: Script(vec![0x53, 0x63, 0x63, 0xac, 0x63, 0x52]), + transparent_input: None, + hash_type: 1, + amount: 1152393991505765, + consensus_branch_id: consensus::BranchId::Sapling, + sighash: [ + 0x58, 0x11, 0x0e, 0x23, 0x19, 0xad, 0x85, 0x50, 0x4a, 0x69, 0x8f, 0x73, 0xe7, + 0xac, 0x31, 0xa7, 0x23, 0xa0, 0x29, 0xec, 0x07, 0xb7, 0x72, 0xfb, 0xb3, 0x2f, + 0xba, 0x17, 0xff, 0xe2, 0xcc, 0x8d, + ], + }, + Test0243Vector { + tx: vec![ + 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0xb5, 0xcb, 0x96, 0x49, + 0x97, 0x9e, 0x3c, 0xcf, 0x75, 0xa8, 0xda, 0xd0, 0x54, 0x60, 0x26, 0x1f, 0xcd, + 0xcb, 0x00, 0x7a, 0xeb, 0xc1, 0x5e, 0x11, 0x67, 0x5c, 0x2d, 0xb4, 0xa6, 0xcb, + 0x79, 0x38, 0xe1, 0xfe, 0xb5, 0xcd, 0x04, 0x6a, 0x65, 0x00, 0x63, 0x44, 0x1e, + 0x16, 0xc7, 0x07, 0xf0, 0x97, 0x14, 0x47, 0x4c, 0x96, 0x16, 0x0a, 0xa6, 0x8e, + 0xaa, 0x12, 0x31, 0x79, 0x06, 0x9c, 0xd2, 0x20, 0x44, 0x06, 0x26, 0xcd, 0xfe, + 0xed, 0x65, 0xf9, 0xfa, 0xbd, 0xaa, 0x6d, 0xb1, 0x76, 0x0d, 0xa5, 0xd8, 0x06, + 0x63, 0x00, 0x53, 0x6a, 0x65, 0x52, 0xfd, 0xd0, 0xd2, 0xa9, 0x01, 0xfd, 0xc8, + 0x17, 0x1c, 0x9b, 0x0e, 0x06, 0x00, 0x01, 0x65, 0x26, 0x27, 0xba, 0x0e, 0x87, + 0xb5, 0xcd, 0x0f, 0xc8, 0x7b, 0xa3, 0xa2, 0x3c, 0x78, 0x02, 0x00, 0x00, 0x02, + 0x59, 0xb1, 0xb2, 0x59, 0xc5, 0xa2, 0xd8, 0xb7, 0xa6, 0x03, 0x9b, 0x0e, 0x12, + 0xac, 0xd8, 0x89, 0xb5, 0x1b, 0x47, 0x2d, 0xd5, 0x33, 0xa4, 0x61, 0xfb, 0x0c, + 0x3f, 0x96, 0xa9, 0xc0, 0x0a, 0x0b, 0x38, 0x39, 0xfa, 0x89, 0x77, 0x6f, 0xf0, + 0x98, 0xae, 0xef, 0xc7, 0x40, 0x34, 0xff, 0x8c, 0x1f, 0x0d, 0xae, 0x63, 0x68, + 0x32, 0x4c, 0xe5, 0xda, 0x68, 0xd7, 0x71, 0x35, 0x08, 0xae, 0x6d, 0x01, 0x1a, + 0xd0, 0x5f, 0xea, 0xf2, 0x03, 0x56, 0x5c, 0x71, 0xa0, 0x48, 0x66, 0x21, 0xbd, + 0xc4, 0x3c, 0x2a, 0x8e, 0xbb, 0x82, 0x61, 0xd8, 0x47, 0x42, 0x4a, 0x4c, 0xfd, + 0x0d, 0xad, 0xcf, 0x95, 0x9d, 0xb4, 0x37, 0x2b, 0x58, 0xa0, 0xde, 0x19, 0x78, + 0x9c, 0x91, 0xfc, 0x99, 0x31, 0xec, 0xbc, 0xac, 0x64, 0x19, 0xca, 0x0e, 0x5d, + 0x97, 0xa3, 0xb4, 0x1c, 0x76, 0xc8, 0xa1, 0x96, 0xc7, 0xa3, 0xad, 0xf5, 0x5b, + 0xdb, 0xe6, 0x0e, 0x85, 0x59, 0x26, 0x4b, 0x6d, 0x8e, 0xf7, 0x5d, 0x26, 0xdc, + 0x72, 0x0f, 0xe5, 0xec, 0x1f, 0x59, 0x66, 0x2d, 0x95, 0xd0, 0x8e, 0x78, 0x9e, + 0x3a, 0xd1, 0x82, 0x9e, 0x40, 0x11, 0x9a, 0xa7, 0x89, 0x7d, 0x89, 0x40, 0x4d, + 0xc4, 0x96, 0x60, 0x46, 0x68, 0xf5, 0x59, 0xca, 0x67, 0x43, 0x7d, 0x2b, 0xfb, + 0xb7, 0xf5, 0x1f, 0x36, 0xe0, 0xa5, 0xb7, 0x22, 0x8f, 0x05, 0xb6, 0xec, 0x57, + 0x89, 0xc1, 0x3f, 0xc2, 0x71, 0x95, 0x56, 0x15, 0x52, 0x63, 0x96, 0x6e, 0x81, + 0xf5, 0x21, 0x51, 0xe2, 0xf6, 0xe3, 0x68, 0x69, 0xd8, 0xa3, 0xc4, 0xc4, 0x96, + 0xa5, 0x13, 0x63, 0x2c, 0xaa, 0x8a, 0xbe, 0x1f, 0x27, 0x35, 0xeb, 0x60, 0xfc, + 0x12, 0x85, 0x82, 0x8e, 0xad, 0xdc, 0x54, 0x41, 0xa4, 0x02, 0xa3, 0xbf, 0x5b, + 0xcd, 0x22, 0x7c, 0xd8, 0x04, 0xe3, 0xc8, 0xca, 0x21, 0x24, 0x3c, 0xdf, 0xcd, + 0x53, 0xd8, 0x66, 0x05, 0xf3, 0xf8, 0xaf, 0x1a, 0x9c, 0xc5, 0x69, 0x33, 0x15, + 0x53, 0x28, 0x28, 0x01, 0x43, 0xfa, 0xdb, 0x3a, 0x1f, 0xc3, 0x3d, 0x76, 0x9f, + 0x07, 0xff, 0xc0, 0x1e, 0x35, 0x79, 0xe1, 0x18, 0x1f, 0x19, 0x15, 0xdb, 0x89, + 0xd8, 0x2e, 0x50, 0xbd, 0x74, 0x24, 0x08, 0x7c, 0x79, 0x7d, 0x9b, 0x7b, 0x3b, + 0x7d, 0x2a, 0x53, 0xb8, 0xff, 0xf9, 0xf2, 0xd9, 0x28, 0xab, 0x99, 0x6d, 0xce, + 0x5e, 0xd2, 0x71, 0x58, 0x98, 0xe4, 0x85, 0x8e, 0xec, 0x60, 0x78, 0xa9, 0x48, + 0x8d, 0x2d, 0xa6, 0xd1, 0x73, 0x05, 0xd0, 0xa3, 0x47, 0x18, 0x62, 0xa2, 0x22, + 0x38, 0xb9, 0xbe, 0xc2, 0x3e, 0xf2, 0xe2, 0x04, 0x1d, 0x50, 0x08, 0x73, 0x3e, + 0x9e, 0xa5, 0x66, 0x2c, 0x9f, 0xea, 0x0e, 0x4a, 0xfd, 0xf3, 0x27, 0x0c, 0x11, + 0x32, 0x3b, 0xa4, 0x8b, 0x35, 0x50, 0x85, 0x74, 0x40, 0x97, 0xf3, 0xf6, 0xc5, + 0x2e, 0xe4, 0x04, 0x31, 0x73, 0x9c, 0x5c, 0xa8, 0xdb, 0x2b, 0xda, 0x13, 0xda, + 0x9b, 0x33, 0x0b, 0x62, 0x00, 0x0b, 0x79, 0xfd, 0x35, 0x44, 0xb1, 0x31, 0x83, + 0x15, 0x9d, 0x17, 0x4f, 0xfe, 0xd2, 0x54, 0x85, 0x40, 0xa5, 0x2e, 0xe4, 0xb6, + 0x2d, 0x35, 0xaa, 0x5a, 0x58, 0x63, 0xf2, 0xba, 0xa4, 0x47, 0x5f, 0x3e, 0xb6, + 0xc7, 0x35, 0x9d, 0xc8, 0x39, 0xdb, 0xc8, 0x68, 0x90, 0xd1, 0x99, 0xd8, 0xea, + 0x6c, 0x9d, 0x97, 0xf1, 0x9e, 0x79, 0x2c, 0x7b, 0xcb, 0x66, 0x25, 0xff, 0x32, + 0xb7, 0x31, 0x57, 0x5f, 0x62, 0xd9, 0x44, 0xc8, 0x06, 0xb3, 0xf9, 0x3c, 0x04, + 0xb7, 0x3a, 0x98, 0xb2, 0x73, 0x43, 0xeb, 0x25, 0xa0, 0x6c, 0x87, 0x53, 0x60, + 0xde, 0x1a, 0x14, 0x38, 0x84, 0x0a, 0xd0, 0x66, 0x1d, 0xeb, 0xdc, 0x9b, 0x82, + 0x8a, 0xd0, 0xcb, 0xc0, 0x01, 0x1b, 0x32, 0x35, 0xb2, 0xc7, 0x53, 0x77, 0x78, + 0xf4, 0x58, 0x82, 0x1b, 0x83, 0xaa, 0x4c, 0xb3, 0xe5, 0x4e, 0xd0, 0x61, 0x3e, + 0x32, 0xe6, 0x3e, 0xf9, 0x85, 0xf9, 0x35, 0xbd, 0x7f, 0xf8, 0xc7, 0x70, 0x5c, + 0x89, 0xc0, 0xbb, 0xcc, 0xda, 0x9e, 0x66, 0x5e, 0x3b, 0x06, 0xba, 0x87, 0x9f, + 0xdd, 0xf3, 0x5e, 0x0b, 0x2f, 0x60, 0xc2, 0xa7, 0x0c, 0xb8, 0xeb, 0x9d, 0xe2, + 0xf5, 0xd7, 0x38, 0xc0, 0x5e, 0x34, 0xe5, 0x0f, 0x1f, 0x26, 0x19, 0x25, 0x8b, + 0x89, 0xe5, 0x73, 0xda, 0x55, 0x75, 0x46, 0x3d, 0x2e, 0x3b, 0xce, 0x39, 0xf7, + 0x0e, 0xb4, 0x55, 0x26, 0xcd, 0x99, 0xfa, 0xd9, 0x0f, 0x97, 0x92, 0xd0, 0xcd, + 0x59, 0x3b, 0xa8, 0x6a, 0xa1, 0xae, 0xa5, 0x03, 0xdd, 0xca, 0x5e, 0x3e, 0x57, + 0x37, 0xe6, 0xfc, 0x7b, 0xab, 0x27, 0x85, 0x12, 0x69, 0x20, 0xc4, 0x47, 0xd5, + 0xe5, 0x6a, 0x75, 0xdb, 0xe8, 0x9d, 0x68, 0x8b, 0xc0, 0xda, 0xa7, 0x9a, 0xa6, + 0x2d, 0xe9, 0xea, 0x29, 0x55, 0xf7, 0x1e, 0x1a, 0x61, 0x68, 0x2a, 0x61, 0x78, + 0xf8, 0x0b, 0xca, 0xda, 0x3b, 0x97, 0xae, 0xec, 0x77, 0xd9, 0xc8, 0x56, 0x3b, + 0x06, 0x9e, 0xa0, 0x13, 0x2f, 0x72, 0x3f, 0xbe, 0x75, 0x60, 0x2d, 0xd6, 0x29, + 0xac, 0x48, 0x09, 0x93, 0xd3, 0x71, 0x4f, 0xf0, 0x2c, 0x97, 0x0e, 0xbd, 0x83, + 0xe6, 0xd6, 0xcb, 0xbe, 0x39, 0x08, 0x6b, 0x03, 0x54, 0x20, 0xe0, 0xc2, 0x75, + 0x62, 0x86, 0x58, 0xa3, 0xba, 0x92, 0x30, 0x5c, 0xc0, 0x76, 0x98, 0xf1, 0x2e, + 0xe1, 0xe4, 0x17, 0x13, 0x70, 0xac, 0x39, 0xdf, 0x0e, 0x46, 0x6d, 0xc8, 0xec, + 0xc3, 0x9d, 0xa5, 0xee, 0x47, 0xb6, 0x82, 0x9d, 0xbb, 0xa9, 0x97, 0x0f, 0x03, + 0x58, 0xed, 0x68, 0x26, 0x49, 0x60, 0x5c, 0x7b, 0xfe, 0xe6, 0x93, 0x1a, 0x29, + 0x5b, 0x14, 0xa3, 0x40, 0x76, 0x00, 0x07, 0x4e, 0xdc, 0x79, 0xfa, 0x61, 0xe6, + 0x80, 0x6f, 0x11, 0x08, 0xd3, 0x34, 0xb4, 0xa5, 0x90, 0xf7, 0xa0, 0x26, 0xb0, + 0xeb, 0x02, 0x80, 0x4d, 0x39, 0x17, 0x46, 0x6e, 0x99, 0x91, 0x20, 0x64, 0x1c, + 0xe0, 0x7e, 0xbc, 0xdc, 0x99, 0x42, 0x60, 0x82, 0xe0, 0x77, 0x1f, 0x15, 0x9c, + 0x82, 0x6a, 0x9b, 0xe6, 0xce, 0xd7, 0x2d, 0x0e, 0x9c, 0xfa, 0x5b, 0x4b, 0x8a, + 0x86, 0x40, 0xca, 0x34, 0x88, 0xa1, 0xeb, 0x2b, 0x6e, 0x37, 0x4e, 0x8c, 0x2e, + 0x00, 0x3c, 0xdf, 0xa2, 0x32, 0x10, 0x37, 0x48, 0xb5, 0xc9, 0xdc, 0x11, 0xbb, + 0x30, 0xf6, 0x46, 0xb9, 0x73, 0xd7, 0x83, 0xf5, 0x99, 0x14, 0x17, 0x4e, 0x48, + 0xbd, 0x6a, 0x84, 0xfa, 0xd8, 0x9d, 0xbc, 0xa5, 0xc7, 0x6d, 0x0a, 0xb4, 0x14, + 0x5a, 0xbd, 0x08, 0xe4, 0xd0, 0xf2, 0xc7, 0x60, 0x25, 0xfc, 0x85, 0xfc, 0x11, + 0x6c, 0xca, 0x8d, 0x30, 0x2c, 0x8a, 0x3b, 0xeb, 0x26, 0x60, 0x3a, 0x1a, 0xf1, + 0xb5, 0x93, 0x91, 0xea, 0xf4, 0x71, 0x75, 0x9a, 0xdf, 0x19, 0x4c, 0x40, 0xc2, + 0x09, 0x29, 0x8c, 0xc0, 0x51, 0xfc, 0x79, 0x03, 0xfe, 0x40, 0x90, 0x2c, 0x35, + 0x6f, 0x28, 0x27, 0x9f, 0x27, 0x94, 0xbb, 0xb9, 0xe0, 0x0b, 0x1e, 0x22, 0x1b, + 0x0a, 0x26, 0x41, 0x06, 0xea, 0x50, 0x4f, 0xb8, 0x90, 0x6a, 0x20, 0x84, 0x5a, + 0x05, 0x9a, 0x60, 0x3b, 0x4f, 0x00, 0xe7, 0x83, 0x6d, 0x40, 0x67, 0xa6, 0x04, + 0x19, 0x5f, 0x24, 0x6a, 0x0f, 0x3b, 0x31, 0x82, 0x3f, 0xdf, 0x69, 0x57, 0x8c, + 0x47, 0xdb, 0x5b, 0x3d, 0xda, 0x86, 0xaa, 0xb1, 0xec, 0x9f, 0x58, 0xd9, 0x62, + 0x26, 0xc6, 0xb9, 0x1d, 0xc0, 0xf0, 0x3f, 0xe8, 0xd7, 0xdf, 0x23, 0xcf, 0x53, + 0xca, 0x8e, 0xa2, 0xa9, 0x09, 0x4f, 0xc0, 0x28, 0x65, 0x26, 0x7c, 0x88, 0xfa, + 0x8c, 0x01, 0x0e, 0xb5, 0x66, 0x13, 0x06, 0x6e, 0x50, 0xf1, 0x55, 0x4a, 0xa4, + 0x10, 0x8e, 0x25, 0xa9, 0xe9, 0x67, 0xd3, 0x4a, 0x9c, 0xf1, 0x02, 0x8c, 0x17, + 0x05, 0xfa, 0x37, 0x67, 0xf4, 0x6d, 0x4b, 0xab, 0x70, 0x28, 0xb0, 0x9b, 0x20, + 0x38, 0xfc, 0x1b, 0x72, 0x7f, 0x61, 0x9e, 0x61, 0xc4, 0xfc, 0x16, 0xbf, 0xfe, + 0x65, 0x7e, 0x99, 0x12, 0x6a, 0xc5, 0x18, 0x4f, 0xc8, 0x7f, 0x5e, 0x53, 0x01, + 0x88, 0x64, 0x23, 0xb3, 0x56, 0x87, 0x59, 0x09, 0xec, 0x92, 0xb3, 0x2d, 0x33, + 0x08, 0x42, 0x53, 0xa1, 0xb9, 0x7c, 0x5d, 0x2e, 0xd6, 0x6c, 0x7e, 0x22, 0xd1, + 0x85, 0x58, 0xfe, 0x82, 0xb5, 0xec, 0x88, 0xc6, 0x07, 0x05, 0x82, 0xfa, 0xcf, + 0x75, 0x6d, 0x70, 0x32, 0x38, 0xd9, 0xaf, 0x94, 0x19, 0x96, 0x6b, 0xe4, 0x62, + 0xdf, 0xbd, 0x31, 0x5c, 0x5b, 0xfa, 0xf0, 0x44, 0xaa, 0x69, 0x5a, 0x05, 0xe6, + 0x9d, 0x3d, 0x41, 0xe7, 0x73, 0x78, 0x75, 0x1d, 0x4e, 0x02, 0xc2, 0x66, 0xdf, + 0xb5, 0xcb, 0x6a, 0x7c, 0x40, 0x08, 0xf9, 0x44, 0x88, 0x83, 0x11, 0xe6, 0xde, + 0x37, 0xdc, 0x7b, 0xdf, 0x65, 0xd7, 0x0c, 0xab, 0x3e, 0x07, 0x8a, 0xb4, 0x4e, + 0x23, 0x2b, 0x41, 0x1c, 0xaf, 0xb2, 0x88, 0x4e, 0x26, 0x45, 0x95, 0xbe, 0xed, + 0xf9, 0xd4, 0x9a, 0x79, 0x36, 0xbb, 0x28, 0x7f, 0xe2, 0x8e, 0x1c, 0x29, 0x63, + 0x5e, 0xae, 0xca, 0x74, 0x7d, 0x06, 0x87, 0xcf, 0x46, 0x59, 0x02, 0xd2, 0x5f, + 0x5e, 0x51, 0x58, 0x48, 0x1d, 0xaa, 0xcd, 0xd3, 0x00, 0xb4, 0x77, 0x40, 0xbc, + 0x0c, 0x62, 0x77, 0xb4, 0x47, 0xcc, 0x26, 0x64, 0x04, 0x42, 0x43, 0xdd, 0x48, + 0x11, 0x40, 0x4e, 0xcb, 0xd7, 0xc7, 0xa6, 0x3c, 0x9f, 0xb7, 0xd9, 0x37, 0xbc, + 0xd8, 0x12, 0xc2, 0x34, 0x59, 0x23, 0xb5, 0x90, 0x26, 0x83, 0xbd, 0x2e, 0xd5, + 0x4c, 0x01, 0xae, 0x04, 0x19, 0xa7, 0xf5, 0x4e, 0x8a, 0x3a, 0x59, 0xc6, 0xa6, + 0xda, 0xcf, 0x89, 0xc7, 0x37, 0x0e, 0x79, 0xb5, 0x60, 0x13, 0x6a, 0x2b, 0x00, + 0xdd, 0xb6, 0x07, 0x4d, 0x74, 0xff, 0xc5, 0xc5, 0xdf, 0xd0, 0x6b, 0x6c, 0x51, + 0x9a, 0xbe, 0xc3, 0x59, 0x6a, 0x47, 0x61, 0x13, 0xbe, 0x41, 0x38, 0xee, 0xad, + 0x5f, 0xfd, 0xe8, 0x6b, 0x1e, 0x32, 0x40, 0x1f, 0xa3, 0x84, 0x62, 0x32, 0xd0, + 0xb3, 0xc9, 0xbd, 0x56, 0x88, 0xb6, 0x4a, 0x33, 0x09, 0x38, 0x16, 0x2a, 0x8b, + 0x89, 0x29, 0xd7, 0x0c, 0x1b, 0x67, 0x53, 0x62, 0xf4, 0xc2, 0xa9, 0xbb, 0x6b, + 0x7f, 0x91, 0xeb, 0xd4, 0x7d, 0x26, 0x3c, 0xf0, 0xa4, 0x05, 0xa2, 0x8b, 0xa7, + 0x41, 0x56, 0x44, 0xf9, 0x3b, 0x6c, 0xdf, 0xa3, 0xec, 0xeb, 0xb7, 0xb8, 0xd4, + 0xee, 0x8b, 0x94, 0xb2, 0x7b, 0x61, 0xe4, 0x03, 0x5e, 0xd6, 0xa4, 0x77, 0x46, + 0x7f, 0x4a, 0x32, 0x0b, 0x8a, 0x4e, 0xba, 0x0a, 0xb5, 0x6c, 0x26, 0x3e, 0x4b, + 0xfb, 0xe2, 0x6a, 0x41, 0x8e, 0xd1, 0xcd, 0xe6, 0x18, 0x4b, 0x89, 0x50, 0xfe, + 0x7a, 0xac, 0x7f, 0x20, 0xa4, 0x7b, 0xa1, 0xbf, 0xf9, 0x80, 0x4f, 0x53, 0xf6, + 0x93, 0x23, 0xdb, 0x84, 0x75, 0x20, 0xa6, 0x58, 0x47, 0xb3, 0x03, 0x4c, 0x4e, + 0x08, 0x1b, 0xb4, 0xb8, 0x69, 0x26, 0x3b, 0x5f, 0x9b, 0x3a, 0x7a, 0x83, 0x3b, + 0x6e, 0x4c, 0xa7, 0x90, 0xcc, 0xf9, 0xfd, 0xae, 0x80, 0x79, 0xe5, 0x56, 0x09, + 0x27, 0x2c, 0x63, 0xb5, 0x49, 0xb0, 0xc8, 0x5f, 0x11, 0x0c, 0xc9, 0xc9, 0x58, + 0x68, 0x01, 0x14, 0xb3, 0x11, 0x74, 0x80, 0xaf, 0x57, 0xcb, 0x15, 0x9e, 0xdf, + 0xbe, 0x5c, 0xb9, 0xc6, 0x2b, 0xce, 0x2c, 0xf2, 0xab, 0x29, 0xb6, 0x67, 0x11, + 0xac, 0x7a, 0xa5, 0x3a, 0x74, 0x9f, 0xfa, 0x83, 0x90, 0x7e, 0xcb, 0x69, 0x12, + 0xaa, 0x56, 0x96, 0x38, 0xde, 0xa1, 0x9e, 0x54, 0x41, 0x61, 0x1e, 0xfc, 0xa3, + 0x20, 0x99, 0x65, 0x3e, 0x8a, 0x5c, 0xa1, 0xfb, 0xbd, 0xba, 0xb1, 0xd6, 0x44, + 0x71, 0xec, 0x32, 0x0e, 0xc3, 0x8e, 0xa4, 0x88, 0x40, 0x0c, 0x9b, 0x1f, 0x4e, + 0x8c, 0xb5, 0x48, 0x0c, 0x0e, 0x92, 0x42, 0xb0, 0x86, 0xa8, 0x0e, 0xee, 0xd4, + 0x90, 0xae, 0x32, 0x00, 0x0c, 0x80, 0x09, 0xec, 0xb7, 0x1f, 0xfa, 0x39, 0xf4, + 0xf3, 0xb5, 0x74, 0x9c, 0xfd, 0x1b, 0xef, 0xe0, 0xd9, 0x66, 0x7a, 0xb3, 0x02, + 0x20, 0xc2, 0xdc, 0x04, 0x39, 0x36, 0x98, 0xb2, 0xcf, 0xa2, 0x04, 0x92, 0xf2, + 0x50, 0xce, 0x14, 0x32, 0x35, 0x81, 0x58, 0x70, 0x3d, 0xf7, 0xb1, 0x39, 0xd7, + 0x45, 0xce, 0x1f, 0xc3, 0x40, 0x78, 0x77, 0x01, 0xfb, 0x51, 0xdd, 0x5e, 0x48, + 0xb8, 0x95, 0x09, 0x41, 0x7d, 0x88, 0x89, 0x00, 0x80, 0x63, 0xf9, 0xba, 0x01, + 0x5a, 0x07, 0xd8, 0xd3, 0x9b, 0xbd, 0x00, 0x76, 0x2f, 0x59, 0x5a, 0xfa, 0xd8, + 0xd8, 0x59, 0xea, 0xab, 0xf0, 0xd8, 0x2d, 0x46, 0x33, 0xcf, 0x82, 0x98, 0xb0, + 0x9b, 0xea, 0x3f, 0x22, 0x28, 0x55, 0xa9, 0x2a, 0x08, 0x43, 0xf5, 0x2f, 0xa5, + 0x8d, 0xb3, 0xa1, 0x75, 0xc3, 0x0d, 0x2a, 0xbe, 0x64, 0x82, 0x64, 0x90, 0xcb, + 0xe6, 0xca, 0x14, 0x88, 0xfe, 0x3a, 0x01, 0x5a, 0x94, 0x6d, 0xc9, 0xc4, 0x5a, + 0xc3, 0x09, 0x25, 0x72, 0x7a, 0x13, 0xe0, 0x89, 0x78, 0xf7, 0x24, 0x03, 0x47, + 0x20, 0x8a, 0x4d, 0x25, 0x38, 0xc2, 0xd5, 0x61, 0x24, 0x37, 0x8c, 0x22, 0xc0, + 0x4e, 0x23, 0xdc, 0x28, 0xb1, 0x50, 0x19, 0xbe, 0x77, 0x6d, 0x70, 0xbf, 0xc1, + 0xd2, 0x64, 0x5b, 0x5e, 0x80, 0xd1, 0xfd, 0x84, 0x19, 0xdf, 0x72, 0x90, 0x43, + 0x80, 0xe2, 0xe1, 0xfc, 0x4d, 0xd1, 0xdf, 0x1b, 0xa3, 0xdf, 0xe4, 0x80, 0xcc, + 0x84, 0x6d, 0x51, 0x51, 0x4a, 0x06, 0x5e, 0xd7, 0x62, 0x78, 0x7a, 0xfd, 0x6e, + 0xb9, 0x0b, 0xdf, 0x8f, 0xbb, 0xad, 0x5e, 0xb3, 0xd2, 0x3f, 0xdc, 0x8c, 0x54, + 0xcc, 0xa1, 0x0f, 0xa1, 0xfe, 0x54, 0x64, 0x82, 0xf5, 0xe1, 0x42, 0x4b, 0xfd, + 0xa8, 0x7a, 0xa7, 0xfb, 0x78, 0x6e, 0x26, 0x0f, 0x26, 0x14, 0xbe, 0x08, 0x11, + 0xee, 0x16, 0xb8, 0xd2, 0x9d, 0xf9, 0xa0, 0xf3, 0x30, 0xe9, 0x70, 0x9f, 0x63, + 0xc9, 0x50, 0xfb, 0xd9, 0x03, 0xff, 0x7d, 0x5b, 0x0c, 0xa2, 0x9f, 0xd6, 0x3b, + 0x0f, 0x97, 0x51, 0x77, 0x69, 0x02, 0x5c, 0xc3, 0x6a, 0x52, 0xe0, 0x00, 0x15, + 0x93, 0x4a, 0x3c, 0xa2, 0x58, 0xb8, 0xba, 0xb9, 0x00, 0x16, 0xa4, 0x01, 0xd5, + 0xd8, 0xd7, 0xc3, 0xb9, 0x44, 0x92, 0x5b, 0x35, 0xa9, 0x34, 0x9a, 0x1a, 0xc7, + 0xd9, 0x85, 0x21, 0x61, 0x0c, 0x2f, 0xad, 0x8b, 0x5c, 0x8b, 0x31, 0x9c, 0xd6, + 0xe0, 0x5f, 0x9b, 0xbe, 0xd3, 0x53, 0xf1, 0xd0, 0xc8, 0x65, 0xa9, 0x4a, 0xa4, + 0x56, 0xdc, 0xd1, 0x8a, 0x39, 0xe2, 0xf5, 0x85, 0xd9, 0xbe, 0xa8, + ], + script_code: Script(vec![0x63, 0x00, 0x6a, 0x53, 0x63, 0x6a, 0xac, 0x00]), + transparent_input: None, + hash_type: 1, + amount: 1788797765223798, + consensus_branch_id: consensus::BranchId::Sapling, + sighash: [ + 0xcb, 0xfa, 0x22, 0x69, 0x9b, 0x04, 0xbe, 0xb7, 0x67, 0x07, 0xb5, 0x1d, 0x62, + 0x5e, 0x94, 0xd2, 0x6c, 0x0d, 0xf8, 0xad, 0xa7, 0xcf, 0x68, 0xfc, 0xde, 0xd9, + 0x60, 0x65, 0x4b, 0x20, 0xf3, 0x60, + ], + }, + Test0243Vector { + tx: vec![ + 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x00, 0x02, 0x12, 0x9a, 0x03, + 0xd5, 0x7d, 0x32, 0x07, 0x00, 0x07, 0x52, 0x51, 0xac, 0x51, 0x65, 0xac, 0x00, + 0x91, 0xdb, 0xbd, 0x6f, 0xf3, 0x8f, 0x01, 0x00, 0x05, 0x53, 0x6a, 0x63, 0x63, + 0x53, 0x6f, 0x34, 0xc4, 0x99, 0x32, 0x68, 0xc7, 0x09, 0xef, 0xf1, 0x20, 0x1b, + 0x50, 0x92, 0x05, 0x00, 0x02, 0x3b, 0x5c, 0x8b, 0x5b, 0x80, 0xe7, 0x7b, 0x87, + 0xf1, 0xeb, 0x73, 0xaf, 0x77, 0x60, 0xed, 0xae, 0x0e, 0x19, 0x3e, 0x38, 0x96, + 0xb1, 0x5c, 0x55, 0x8f, 0x00, 0x4e, 0x7c, 0x7d, 0x93, 0x24, 0xd3, 0x85, 0xb4, + 0x50, 0xcd, 0x4b, 0x98, 0x2a, 0xba, 0x8d, 0x2e, 0x91, 0xf4, 0x1f, 0x22, 0xee, + 0xe7, 0xf3, 0x6d, 0x79, 0xcc, 0xa9, 0xc0, 0xe0, 0x1b, 0x26, 0xc4, 0x65, 0x11, + 0x18, 0xea, 0x77, 0x15, 0x14, 0xc7, 0x7e, 0xd6, 0x0c, 0xd5, 0x24, 0x51, 0x94, + 0x2d, 0xc8, 0x5b, 0x3f, 0xba, 0x44, 0x8b, 0x2d, 0x63, 0x10, 0xf2, 0x77, 0x79, + 0x42, 0x83, 0x2e, 0x21, 0xcf, 0x3d, 0x44, 0x87, 0x4f, 0x8d, 0xca, 0x98, 0x2b, + 0x68, 0x7c, 0x9e, 0xd7, 0xe0, 0xb2, 0x32, 0x77, 0x07, 0x3c, 0x19, 0x30, 0xa4, + 0x73, 0xd1, 0x66, 0x8e, 0xf2, 0xe9, 0xae, 0x96, 0x63, 0xcf, 0xf0, 0x58, 0x16, + 0x62, 0x6c, 0xd3, 0xc5, 0xbf, 0x77, 0x16, 0x53, 0xd7, 0x78, 0x51, 0x81, 0x35, + 0x5c, 0x05, 0xae, 0xd2, 0x4a, 0x99, 0xc4, 0xb6, 0x74, 0xd2, 0x4a, 0x0f, 0x08, + 0xf4, 0xb0, 0xcf, 0xbe, 0x90, 0xf2, 0xfd, 0xba, 0xb4, 0x24, 0x82, 0xe9, 0x8f, + 0x13, 0xff, 0xfc, 0xd1, 0xad, 0x33, 0xf4, 0xf4, 0xc0, 0x4d, 0xeb, 0xc8, 0x9f, + 0x40, 0xb5, 0xdb, 0xf6, 0x45, 0x46, 0xc5, 0x20, 0xdc, 0xa5, 0xd0, 0xec, 0xf3, + 0xf6, 0x5d, 0x3a, 0x77, 0xd0, 0x12, 0x9f, 0x60, 0x03, 0x71, 0x10, 0x8a, 0xac, + 0x30, 0xa9, 0xec, 0xa8, 0xbe, 0xe5, 0x52, 0x4f, 0xab, 0x67, 0x1f, 0xc0, 0x86, + 0x58, 0x76, 0x2c, 0x87, 0x38, 0xab, 0xc9, 0xfa, 0x76, 0x93, 0xe3, 0x9d, 0x39, + 0xd7, 0x03, 0xd5, 0xcd, 0x94, 0x2b, 0x5a, 0x55, 0xfe, 0xda, 0xfe, 0xcc, 0xae, + 0xf7, 0x02, 0x17, 0x69, 0xe9, 0x2c, 0xc9, 0xd3, 0xac, 0x7b, 0x4c, 0x23, 0xb3, + 0x3f, 0xc2, 0x23, 0x21, 0x85, 0x4b, 0xa3, 0x3f, 0x49, 0xee, 0xba, 0xdd, 0xca, + 0x29, 0xb3, 0x56, 0x40, 0xe4, 0xf0, 0xc2, 0xfd, 0x8c, 0x12, 0xb9, 0x84, 0x52, + 0x97, 0x60, 0xe0, 0x65, 0xfe, 0xcb, 0xa1, 0x21, 0x86, 0xd2, 0x0a, 0xee, 0xc3, + 0xda, 0x58, 0xfc, 0x35, 0x9b, 0xa8, 0x25, 0xe5, 0xb8, 0xe2, 0xe1, 0x8f, 0x12, + 0xcf, 0x29, 0x49, 0xc3, 0x12, 0xf6, 0x3c, 0x4d, 0xd7, 0xa7, 0x9b, 0x0e, 0x66, + 0xb9, 0xc8, 0xb6, 0x6f, 0xe8, 0x9a, 0xd7, 0xed, 0xc6, 0x2a, 0xc4, 0xd2, 0x07, + 0xe2, 0x77, 0xb9, 0x33, 0xb0, 0xc2, 0x06, 0xdd, 0x7c, 0x22, 0xd2, 0xdb, 0x26, + 0x33, 0xfc, 0x01, 0xa8, 0x3c, 0x24, 0xfc, 0xad, 0x40, 0x9c, 0xee, 0xd5, 0x36, + 0xa6, 0xd3, 0xe8, 0xe0, 0x8d, 0x42, 0xb5, 0x13, 0x48, 0x97, 0xb4, 0x36, 0xbf, + 0xf3, 0xa1, 0xbc, 0xef, 0xc5, 0x3a, 0xec, 0x30, 0xed, 0x89, 0x11, 0x0f, 0x89, + 0x60, 0x88, 0x8a, 0x1c, 0xf2, 0x41, 0x5c, 0xc6, 0x93, 0xa8, 0x52, 0x97, 0xd6, + 0xb7, 0x89, 0x14, 0x1e, 0x04, 0x1a, 0x3c, 0x14, 0xa5, 0xf9, 0xc6, 0x46, 0x33, + 0xbe, 0x06, 0x56, 0x45, 0xe9, 0xca, 0x36, 0x37, 0xf3, 0x73, 0x83, 0x04, 0xec, + 0x3b, 0x16, 0x51, 0x31, 0x46, 0x83, 0xa0, 0x27, 0x5e, 0x73, 0x36, 0x79, 0x70, + 0x01, 0x06, 0x78, 0x23, 0x17, 0x79, 0x3e, 0x86, 0x6c, 0xed, 0x59, 0x89, 0x21, + 0x3f, 0x3b, 0xac, 0xfc, 0xfd, 0x20, 0x02, 0xea, 0x86, 0x6f, 0x3f, 0x17, 0x07, + 0x35, 0x12, 0x64, 0xb6, 0x67, 0x88, 0xf4, 0xeb, 0x7f, 0x68, 0xc5, 0xa5, 0x36, + 0xfa, 0x9c, 0x13, 0x0d, 0x20, 0x26, 0xea, 0x80, 0x97, 0x94, 0xd3, 0xb7, 0x4d, + 0x78, 0x01, 0x7e, 0xe0, 0xfb, 0xca, 0x83, 0xcc, 0x7e, 0x5c, 0xbd, 0x52, 0x7a, + 0xcd, 0xe7, 0x46, 0x53, 0x73, 0x51, 0x2c, 0x07, 0x64, 0x6a, 0x62, 0xc6, 0x0f, + 0x5c, 0x16, 0xc2, 0xef, 0x9f, 0x41, 0x8d, 0x8c, 0x7d, 0x18, 0x8f, 0x7b, 0x13, + 0xdd, 0x45, 0x38, 0xa5, 0x5d, 0x18, 0x6a, 0xd6, 0x36, 0x2a, 0x58, 0x9a, 0x9f, + 0x52, 0xb2, 0x5e, 0x61, 0x6f, 0xb2, 0xa3, 0x57, 0xac, 0xca, 0xde, 0x63, 0x57, + 0xfa, 0x5a, 0x42, 0xa7, 0x98, 0xe4, 0x17, 0x13, 0x11, 0xad, 0xe9, 0xcc, 0xfd, + 0x15, 0xf2, 0x7c, 0x8c, 0x19, 0x72, 0x17, 0x9d, 0x26, 0x1f, 0xb9, 0xb0, 0x9b, + 0xc7, 0xa0, 0x36, 0xc1, 0x05, 0x55, 0x9b, 0x04, 0x38, 0x9d, 0xfd, 0x8a, 0x7b, + 0xe2, 0xa3, 0xae, 0x2b, 0xba, 0x2a, 0xfb, 0xd1, 0xe9, 0xbf, 0x90, 0x05, 0xc8, + 0xb3, 0x66, 0x35, 0x4f, 0x90, 0x9b, 0xe7, 0x1e, 0x52, 0xc0, 0x90, 0x80, 0xfb, + 0xa7, 0x45, 0x23, 0x77, 0xe8, 0xf1, 0x2c, 0x18, 0x4f, 0xe7, 0xed, 0x46, 0x5b, + 0x32, 0xc9, 0xf9, 0xb2, 0x81, 0x9e, 0xa1, 0xd1, 0x19, 0xfc, 0x26, 0x7c, 0x8a, + 0x75, 0x33, 0x81, 0xeb, 0x51, 0xac, 0xf8, 0x54, 0xc1, 0x9e, 0x8d, 0x58, 0xff, + 0x42, 0x74, 0xeb, 0xa8, 0xc6, 0x3f, 0x0f, 0xa1, 0x70, 0xa6, 0x3c, 0xbf, 0xce, + 0x2c, 0xf8, 0x7b, 0xdc, 0xdf, 0x32, 0xb7, 0xe1, 0x98, 0x04, 0x54, 0x1c, 0x2c, + 0x58, 0x97, 0x24, 0xef, 0xc6, 0x9b, 0xc4, 0x65, 0xd0, 0x90, 0x8e, 0x09, 0xb8, + 0x4d, 0x1f, 0x50, 0x41, 0x2b, 0xb0, 0x7f, 0x47, 0xfb, 0x9f, 0x0d, 0x47, 0x29, + 0x28, 0x16, 0x14, 0xca, 0xca, 0xb6, 0x14, 0xef, 0x65, 0xce, 0xba, 0x13, 0x96, + 0xb5, 0x24, 0x9d, 0x2c, 0x61, 0x70, 0x4f, 0xb6, 0xf3, 0x48, 0x44, 0x71, 0x83, + 0xf9, 0x88, 0x2a, 0x98, 0xae, 0x9c, 0x71, 0xa7, 0x66, 0x33, 0xe0, 0x5b, 0x33, + 0x3a, 0x1b, 0xce, 0xee, 0xc9, 0xbd, 0x44, 0xb8, 0x87, 0x6f, 0xab, 0x6c, 0xd7, + 0x2a, 0x5e, 0x33, 0x5c, 0x97, 0x7a, 0x04, 0x55, 0xc5, 0x36, 0x5f, 0xe8, 0x7f, + 0x17, 0xa0, 0x5c, 0x0f, 0x8c, 0x23, 0x3b, 0x97, 0x29, 0xc1, 0x09, 0x3b, 0xae, + 0xb8, 0x57, 0x5c, 0xe5, 0xfd, 0xfb, 0xfd, 0x6e, 0x6a, 0x8e, 0xbf, 0x76, 0x46, + 0x47, 0x81, 0xf9, 0xb2, 0x10, 0xed, 0xb3, 0x9d, 0x20, 0x6a, 0x68, 0x5d, 0x0d, + 0xc7, 0xec, 0x06, 0x8e, 0x3c, 0x6b, 0x13, 0xd2, 0xf2, 0xaa, 0x74, 0x11, 0x92, + 0xbc, 0x86, 0x25, 0xab, 0xd3, 0x0d, 0xb6, 0xe6, 0x64, 0xfb, 0x33, 0x30, 0xf9, + 0x5c, 0xb3, 0x1b, 0xa1, 0x29, 0x0b, 0xd7, 0xf8, 0x30, 0x31, 0xc7, 0x89, 0xc2, + 0x4f, 0xd5, 0x73, 0x93, 0x46, 0x90, 0xa7, 0x3b, 0x54, 0xa9, 0x05, 0xdf, 0x8e, + 0x1d, 0x59, 0x32, 0x2f, 0x26, 0x2b, 0xbf, 0xbe, 0x95, 0xcc, 0x5b, 0x9b, 0x1e, + 0x20, 0x31, 0x0b, 0x76, 0x35, 0x0b, 0x4d, 0x60, 0x4c, 0xd1, 0xa4, 0x58, 0x66, + 0x1d, 0xc4, 0x74, 0xfe, 0x4c, 0x58, 0x79, 0x04, 0xc0, 0x53, 0x47, 0x5e, 0x17, + 0x61, 0xb8, 0x0a, 0x60, 0xcc, 0x48, 0xed, 0xd9, 0x54, 0x34, 0xdf, 0x02, 0x3b, + 0x94, 0xa5, 0x8a, 0x99, 0xd6, 0x25, 0x66, 0xe0, 0x0f, 0x67, 0x77, 0x90, 0xdc, + 0xa0, 0x76, 0xa4, 0xf1, 0x67, 0x47, 0x0c, 0x43, 0xa8, 0x1e, 0x6c, 0x32, 0xf0, + 0xd0, 0x0d, 0x23, 0x65, 0x6b, 0xa7, 0x48, 0x28, 0xb8, 0xe4, 0xd4, 0x75, 0x38, + 0xe5, 0x0c, 0x0e, 0xce, 0xe2, 0xcd, 0xfe, 0x0d, 0x59, 0x43, 0xe2, 0x3e, 0x3f, + 0x17, 0x33, 0x82, 0x9d, 0x3e, 0x1b, 0x80, 0x53, 0x93, 0x30, 0xe0, 0x6c, 0x6a, + 0xe3, 0xd0, 0xec, 0xe7, 0x38, 0xc0, 0xdd, 0x74, 0x2a, 0xa5, 0x86, 0x0f, 0x43, + 0xb5, 0x30, 0xf0, 0x3d, 0xc5, 0x5d, 0xeb, 0xf7, 0x20, 0x12, 0x3f, 0x8f, 0xba, + 0xf2, 0xe5, 0x68, 0x59, 0xa5, 0x34, 0x3d, 0x46, 0x12, 0xee, 0x21, 0x46, 0x4d, + 0xb2, 0x50, 0x1d, 0x4f, 0x35, 0x31, 0x47, 0xf3, 0xe1, 0xa5, 0xab, 0xb8, 0x93, + 0x85, 0x08, 0x16, 0xc8, 0x0a, 0xf2, 0x9d, 0x88, 0x92, 0x48, 0xc9, 0x2a, 0x72, + 0x9a, 0x0e, 0x2b, 0xe2, 0xb6, 0x6c, 0xc1, 0x3a, 0xc5, 0xd9, 0x96, 0xb2, 0x50, + 0x14, 0x66, 0x6d, 0xdc, 0x63, 0x8a, 0x1f, 0xd2, 0xa0, 0xaf, 0xee, 0x93, 0xd9, + 0x8e, 0x31, 0xdc, 0x1e, 0xa8, 0x58, 0xd7, 0x2b, 0x84, 0xbb, 0xd3, 0x2f, 0xc0, + 0xc6, 0x16, 0xe7, 0xd4, 0xab, 0xda, 0xf3, 0xc1, 0x8f, 0xf9, 0x60, 0x13, 0x24, + 0x5d, 0x83, 0xb3, 0xbd, 0xf9, 0x21, 0xf4, 0x03, 0xf1, 0xae, 0xcf, 0xdd, 0xd8, + 0x85, 0xfd, 0xcf, 0xc7, 0x33, 0x87, 0x0f, 0x76, 0x0c, 0xb8, 0x7e, 0xd4, 0xfc, + 0xd9, 0xcc, 0xa9, 0x33, 0x2e, 0x8e, 0x1c, 0x85, 0x62, 0x3b, 0x20, 0x66, 0x09, + 0xf8, 0x87, 0xeb, 0xdb, 0xcf, 0x9d, 0xa1, 0x0f, 0x38, 0x14, 0x19, 0x7a, 0x9f, + 0x82, 0x07, 0x05, 0xea, 0xa1, 0x28, 0x3a, 0xc7, 0x93, 0x16, 0x83, 0x08, 0x3f, + 0x22, 0xfc, 0x4d, 0xc7, 0xff, 0x68, 0x1a, 0xb8, 0x46, 0x18, 0x6f, 0x22, 0xd5, + 0x73, 0x08, 0x43, 0xde, 0x71, 0x00, 0xf0, 0x31, 0x17, 0xa3, 0xbb, 0xa0, 0x64, + 0xca, 0x3c, 0xea, 0x93, 0xf3, 0xab, 0xd3, 0x0b, 0xe6, 0xdb, 0x09, 0x35, 0x52, + 0x9d, 0xed, 0x0b, 0x50, 0xec, 0xef, 0x9f, 0x59, 0x6d, 0xb0, 0x1a, 0x87, 0xa8, + 0xda, 0xdb, 0x82, 0x7a, 0x1b, 0xe8, 0xb5, 0x79, 0x9b, 0x33, 0xc9, 0x9a, 0x82, + 0x2b, 0x73, 0xf7, 0xe6, 0x62, 0xed, 0x6f, 0x86, 0x03, 0x45, 0xa2, 0x62, 0x83, + 0xc1, 0xb4, 0x08, 0x0e, 0xcd, 0xf5, 0x79, 0xd7, 0x0e, 0x7b, 0x0c, 0x0a, 0xb7, + 0x1e, 0x11, 0x6e, 0xe2, 0xd9, 0xda, 0x27, 0x46, 0x1e, 0x28, 0x12, 0x2a, 0x09, + 0xca, 0x04, 0xde, 0x38, 0x76, 0x50, 0x2f, 0xd2, 0x4d, 0xff, 0x92, 0x09, 0x55, + 0x2f, 0x91, 0x13, 0x87, 0x70, 0x78, 0xa0, 0x94, 0xe0, 0xe5, 0xf8, 0xce, 0xbb, + 0x41, 0x54, 0xe0, 0x3a, 0x6b, 0x56, 0xf6, 0x04, 0xdf, 0x98, 0x4b, 0xd2, 0x9e, + 0xfd, 0x4f, 0x88, 0xc3, 0xf6, 0x29, 0xea, 0x2b, 0xba, 0x91, 0x27, 0xea, 0x5a, + 0x6c, 0xc5, 0xa3, 0x9d, 0x74, 0x1e, 0xdd, 0x71, 0x1a, 0x24, 0x44, 0x7f, 0xe0, + 0x6c, 0xf8, 0x45, 0x5a, 0x44, 0x06, 0x5e, 0x24, 0x52, 0x76, 0x3b, 0x0d, 0x93, + 0xf8, 0x6a, 0x31, 0x47, 0xbd, 0x08, 0x75, 0x7a, 0x4f, 0x7a, 0xa7, 0x79, 0x3c, + 0x97, 0x82, 0x1c, 0x2b, 0x57, 0x22, 0xc9, 0xdb, 0xad, 0x20, 0xf6, 0xa1, 0xe7, + 0xad, 0xf6, 0x8b, 0xf2, 0x22, 0x7b, 0xe5, 0x12, 0x04, 0xe9, 0xde, 0xca, 0x8d, + 0x9e, 0xb6, 0x26, 0x6f, 0x65, 0x9b, 0x33, 0x55, 0xc8, 0x97, 0x7e, 0xae, 0x7e, + 0x9e, 0xd5, 0x39, 0xd1, 0x79, 0x39, 0xf0, 0xc6, 0x16, 0x6b, 0x01, 0x13, 0x2d, + 0xb0, 0x01, 0x66, 0x25, 0x0e, 0xa9, 0x64, 0xe3, 0x9d, 0x9d, 0x55, 0xab, 0x43, + 0x9a, 0x29, 0xbb, 0x0b, 0xcf, 0xd3, 0xa9, 0x99, 0xb3, 0x1f, 0xe7, 0xa9, 0x51, + 0x00, 0x2e, 0xe5, 0xdc, 0x01, 0x27, 0x03, 0x24, 0xb1, 0x10, 0x10, 0x37, 0x89, + 0x29, 0x42, 0x90, 0x7c, 0x6e, 0x19, 0x50, 0x9a, 0x6c, 0x5f, 0x66, 0x59, 0xba, + 0xf7, 0xf4, 0x36, 0x3c, 0x49, 0x15, 0xe6, 0x1b, 0xda, 0x34, 0x06, 0x9b, 0xd9, + 0x86, 0xb6, 0x37, 0x7f, 0xf6, 0x04, 0xed, 0xe5, 0xa7, 0x42, 0x5d, 0xb2, 0x88, + 0x86, 0xb1, 0xa2, 0x61, 0x36, 0x6d, 0xa8, 0xa1, 0x39, 0x86, 0x65, 0xbe, 0xed, + 0x3b, 0xe9, 0xbc, 0x2e, 0x05, 0x5e, 0x71, 0x1b, 0x7d, 0x36, 0xdd, 0xbd, 0xd3, + 0x65, 0xcc, 0xdc, 0xd7, 0xfc, 0xba, 0xfe, 0x71, 0x29, 0x66, 0x95, 0x08, 0xda, + 0xc0, 0xad, 0x2d, 0x55, 0xee, 0x7f, 0xc6, 0x0b, 0xce, 0x22, 0x88, 0x50, 0xba, + 0x7b, 0x94, 0x3a, 0x8d, 0x50, 0xff, 0xcb, 0x2a, 0x67, 0x06, 0x51, 0xd3, 0x15, + 0xd8, 0x71, 0x9c, 0x7b, 0x57, 0xf6, 0x37, 0xa3, 0x7e, 0xdd, 0x32, 0x6a, 0xbc, + 0x76, 0xf0, 0xa7, 0x69, 0x0c, 0x23, 0x68, 0x80, 0x16, 0x01, 0x07, 0xc2, 0xb4, + 0xc8, 0x5e, 0xcf, 0x2a, 0xd9, 0xf5, 0xdd, 0x26, 0x45, 0x62, 0x6e, 0x40, 0x90, + 0xf1, 0x00, 0x47, 0xcc, 0x13, 0x15, 0x40, 0xca, 0x58, 0x03, 0x04, 0x5a, 0x6a, + 0xee, 0x91, 0xea, 0x0b, 0x3f, 0x9b, 0x77, 0xc4, 0x43, 0x40, 0x69, 0xc5, 0x32, + 0x0c, 0xf5, 0xb7, 0x01, 0x82, 0xd9, 0xfb, 0xbf, 0x30, 0x98, 0x30, 0x60, 0x11, + 0x75, 0x9d, 0x0d, 0x64, 0xa8, 0x84, 0x14, 0x1e, 0xa0, 0x21, 0xcd, 0xd9, 0x5e, + 0xfa, 0x32, 0x63, 0xa5, 0x05, 0xb8, 0x52, 0x29, 0xd1, 0x54, 0xec, 0xaa, 0x23, + 0x5e, 0x8f, 0xa1, 0x07, 0x95, 0xc9, 0xda, 0x27, 0x41, 0xcd, 0x98, 0x71, 0x90, + 0x16, 0xa9, 0x01, 0x17, 0xa7, 0x6f, 0x84, 0xf0, 0x0b, 0x5c, 0x3d, 0x4b, 0xce, + 0xd7, 0x9a, 0x73, 0xbf, 0xb3, 0xa1, 0xc7, 0x8a, 0xd1, 0xad, 0xea, 0x50, 0x78, + 0xf2, 0xf1, 0xb0, 0x0f, 0x81, 0x5b, 0xc7, 0xa3, 0x0e, 0xf8, 0x58, 0x40, 0x07, + 0x77, 0x32, 0xdc, 0xb1, 0xa6, 0x1e, 0xd4, 0xbc, 0xbd, 0x66, 0x35, 0x28, 0x50, + 0x29, 0x77, 0x94, 0xad, 0x67, 0xd2, 0x93, 0xdc, 0xe9, 0x10, 0x61, 0x13, 0x0c, + 0xa4, 0x8b, 0xab, 0xca, 0xaa, 0xd6, 0x0b, 0x1f, 0x7c, 0xed, 0x07, 0xac, 0x3f, + 0xf3, 0x32, 0xd5, 0xc8, 0xd3, 0x2b, 0xa2, 0xf1, 0xe7, 0x8a, 0x23, 0xb0, 0x66, + 0x29, 0xb8, 0x89, 0x06, 0x6f, 0x07, 0x9b, 0xcd, 0xa2, 0x9f, 0xb5, 0xc8, 0x3b, + 0xbb, 0xd3, 0x7e, 0xc6, 0x17, 0x3e, 0x8a, 0x74, 0x81, 0x22, 0x12, 0x86, 0x6b, + 0xcb, 0x58, 0x80, 0x5e, 0x9e, 0x70, 0x17, 0x96, 0xa7, 0x23, 0xd5, 0x15, 0xe6, + 0x15, 0x33, 0x20, 0x0b, 0xe0, 0x6b, 0x01, 0x5f, 0xa0, 0x22, 0x35, 0xc8, 0xcb, + 0xc9, 0xf3, 0x61, 0x7e, 0xe8, 0x19, 0x5f, 0xe1, 0xbc, 0xf5, 0xbb, 0x1b, 0x63, + 0x4c, 0xd4, 0x3f, 0x62, 0xea, 0x93, 0xa4, 0x6d, 0x88, 0xf2, 0xfc, 0xbc, 0x3e, + 0x28, 0x40, 0x84, 0xe7, 0x04, 0xfb, 0x1d, 0x7d, 0x0d, 0x9a, 0xcb, 0x91, 0x96, + 0x1e, 0x2e, 0xeb, 0xe2, 0xdc, 0x9e, 0xbe, 0x36, 0x5b, 0x25, 0xb5, 0x66, 0x75, + 0x97, 0x3d, 0x0c, 0x38, 0xf4, 0x76, 0x30, 0x57, 0x47, 0x23, 0xcd, 0x3e, 0xc6, + 0x6c, 0x8f, 0x3b, 0x12, 0x82, 0x21, 0xa7, 0x90, 0xd9, 0x2c, 0x89, 0x5b, 0x94, + 0x27, 0x0f, 0xe9, 0x40, 0x51, 0xa1, 0x70, 0xe9, 0x5b, 0x8b, 0xe7, 0x16, 0x34, + 0x86, 0xec, 0x8c, 0x0b, 0xee, 0xbe, 0xf6, 0x5e, 0x16, 0x26, 0xb0, 0x46, 0xd7, + 0xe7, 0xf8, 0x26, 0x37, 0x2b, 0x6a, 0xa1, 0x0b, 0xae, 0xfb, 0x84, 0x8f, 0xa1, + 0xdf, 0x6b, 0xb1, 0xdc, 0x43, 0x95, 0x40, 0xf6, 0x3c, 0x9c, 0x7a, 0x9d, 0x5f, + 0x88, 0x13, 0x40, 0x29, 0x62, 0x65, 0x1e, 0xe9, 0x84, 0x39, 0x02, 0xb6, 0xc3, + 0x98, 0x2d, 0xce, 0x50, 0xa6, 0x17, 0x8a, 0x55, 0xa1, 0xad, 0xc0, 0x1c, 0xe7, + 0xdc, 0x6c, 0x83, 0x38, 0xe1, 0xa9, 0xce, 0xef, 0xc1, 0x78, 0xdc, 0x43, 0x14, + 0xf6, 0x74, 0x9a, 0x81, 0xa7, 0x31, 0xee, 0x3c, 0x7f, 0xc0, 0xc3, 0x5d, 0x1c, + 0xe3, 0x63, 0xce, 0xf1, 0x13, 0x28, 0xf3, 0x87, 0xc4, 0x01, 0xfe, 0xf2, 0x7a, + 0x67, 0xa6, 0x29, 0x2f, 0x6f, 0x72, 0xb0, 0xa1, 0xd6, 0xc3, 0x89, 0x16, 0x2d, + 0x16, 0x2e, 0xf0, 0x50, 0xae, 0x5f, 0x3d, 0xdb, 0xb5, 0x5c, 0xaa, 0xbc, 0xa9, + 0xa1, 0xbe, 0x89, 0xb4, 0x63, 0x49, 0x4d, 0x74, 0x39, 0xfb, 0x56, 0x47, 0xa9, + 0x18, 0x12, 0x8b, 0x96, 0x25, 0xd3, 0x3e, 0xac, 0xa6, 0x19, 0xd5, 0x2f, 0x03, + 0x5f, 0xe6, 0x08, 0x9c, 0xe8, 0xd8, 0xb9, 0x0f, 0xe3, 0x67, 0x0d, 0x8c, 0x5a, + 0x2e, 0x3e, 0x05, 0x49, 0x69, 0xa3, 0xd9, 0x7e, 0x61, 0xb5, 0xe6, 0x30, 0x67, + 0x4f, 0xc7, 0x08, 0x57, 0xf1, 0xbb, 0xf1, 0x0f, 0xdc, 0x40, 0x49, 0xef, 0xf5, + 0x60, 0xeb, 0xa5, 0xf2, 0x2a, 0xcc, 0x8d, 0x77, 0xdb, 0xee, 0x0b, 0x20, 0x55, + 0x7f, 0xa4, 0xd0, 0x33, 0x31, 0x72, 0xcb, 0xb5, 0xcb, 0xcc, 0x2b, 0x13, 0x5f, + 0x2c, 0xcd, 0xe0, 0x14, 0xe6, 0x3e, 0xbe, 0x4e, 0xdf, 0x92, 0x5e, 0x61, 0xba, + 0x2a, 0x32, 0x0c, 0xd3, 0x99, 0x91, 0x5a, 0xdd, 0xfc, 0xeb, 0x1a, 0xd0, 0x69, + 0xa9, 0xfd, 0x5b, 0x62, 0x10, 0xa4, 0xb6, 0xe5, 0x04, 0x52, 0xb1, 0xf9, 0x06, + 0xdd, 0x16, 0xf0, 0x16, 0x68, 0xf0, 0xaf, 0x56, 0x6a, 0x28, 0x7c, 0xce, 0xfc, + 0xd8, 0x94, 0x73, 0x41, 0x85, 0x9a, 0xe7, 0xdc, 0x3a, 0x06, 0xf6, 0xbf, 0x15, + 0x74, 0xfe, 0xb9, 0x31, 0xf9, 0x27, 0xe2, 0xd5, 0x05, 0xf6, 0x08, 0x59, 0x9e, + 0x23, 0xb0, 0x5a, 0xf7, 0xc3, 0x23, 0x69, 0x83, 0x97, 0xa8, 0x01, 0xdc, 0x7f, + 0x78, 0x82, 0x5c, 0xc7, 0xeb, 0x9f, 0xcc, 0xe6, 0xc6, 0xc4, 0xf8, 0xf6, 0x88, + 0x39, 0xd3, 0x0a, 0xc5, 0x67, 0x14, 0x8e, 0x70, 0x84, 0xdb, 0x2b, 0x37, 0x58, + 0x30, 0xa0, 0x7b, 0x30, 0x5f, 0xed, 0xd6, 0x07, 0xa3, 0x47, 0xfa, 0x65, 0xde, + 0xf0, 0x1d, 0x4e, 0x1f, 0xd6, 0xc1, 0x6b, 0x4b, 0x47, 0xf5, 0xb0, 0x1b, 0x43, + 0x65, 0xb7, 0x72, 0x26, 0xe6, 0x0f, 0xdd, 0x40, 0xf2, 0x2a, 0x39, 0x5a, 0xa2, + 0x35, 0xf0, 0xdf, 0xda, 0x8f, 0xb4, 0xd3, 0xde, 0x65, 0xb0, 0xcf, 0x4f, 0x4c, + 0x22, 0x0b, 0x3b, 0x4a, 0x9e, 0x32, 0xbc, 0x0d, 0xb6, 0x4f, 0x16, 0x2c, 0x07, + 0xdf, 0x42, 0xa1, 0x01, 0x99, 0x03, 0xa6, 0x7c, 0xda, 0x69, 0x3d, 0xde, 0xb5, + 0xca, 0x39, 0xa0, 0xfe, 0x50, 0x08, 0x50, 0xec, 0x7c, 0x06, 0xbe, 0xe7, 0x18, + 0x66, 0xb3, 0x55, 0xcc, 0xbc, 0x07, 0x8c, 0xd4, 0xdc, 0x03, 0x6f, 0xda, 0xa8, + 0x1c, 0xb2, 0xde, 0x99, 0xcc, 0x88, 0xf6, 0x0a, 0x49, 0x46, 0x42, 0x87, 0xf5, + 0x9f, 0xc7, 0x14, 0x8b, 0x1a, 0xfb, 0x4a, 0x2f, 0x9b, 0xb8, 0x97, 0x14, 0xe1, + 0xeb, 0x8c, 0x03, 0x61, 0xe5, 0x99, 0x2a, 0x5b, 0x79, 0xcd, 0xbb, 0x91, 0xd9, + 0xbf, 0x29, 0xeb, 0x59, 0x8c, 0xbb, 0x4b, 0xda, 0x92, 0x3d, 0x26, 0x7f, 0xea, + 0xcb, 0x91, 0xce, 0x72, 0xd6, 0x1a, 0xb1, 0xea, 0x00, 0xf5, 0x6a, 0xa6, 0x76, + 0x6e, 0xab, 0xc4, 0x7d, 0xca, 0xa6, 0x9a, 0x02, 0x4b, 0xbf, 0xf2, 0xf2, 0x96, + 0x91, 0x7f, 0x17, 0xa3, 0xf8, 0xc9, 0x3e, 0x1b, 0xf2, 0x9c, 0x3c, 0xfc, 0x99, + 0x1a, 0x2b, 0xe8, 0xcf, 0xa7, 0x0e, 0x5d, 0xe3, 0xf2, 0xdd, 0x52, 0xa7, 0x55, + 0x01, 0x38, 0x68, 0x7a, 0xec, 0x28, 0x92, 0x6f, 0xa1, 0x68, 0xb1, 0x81, 0xdb, + 0x72, 0x82, 0xbd, 0x60, 0xda, 0xd3, 0x31, 0x0d, 0xfe, 0x54, 0x2c, 0xeb, 0xe6, + 0x94, 0x74, 0x00, 0x25, 0xc7, 0xec, 0x2a, 0x20, 0x43, 0xfe, 0xbb, 0x77, 0x9f, + 0x7f, 0x37, 0x89, 0xa5, 0xe2, 0x42, 0xdb, 0x48, 0x03, 0xee, 0x36, 0x72, 0x52, + 0xc4, 0x63, 0xc9, 0xa8, 0x8b, 0x41, 0x7b, 0x70, 0x86, 0x6d, 0x9a, 0xfb, 0x7a, + 0x08, 0x27, 0x68, 0x01, 0xf9, 0x22, 0x7c, 0x63, 0x81, 0xf1, 0x5c, 0xc0, 0x94, + 0xac, 0x7b, 0xd1, 0x54, 0xa4, 0xce, 0xf9, 0x0b, 0x48, 0x47, 0xdc, 0x16, 0x8a, + 0x01, 0xf1, 0xe3, 0x1e, 0xec, 0x74, 0xa7, 0xef, 0xce, 0xba, 0x11, 0xf5, 0x07, + 0x69, 0xf5, 0xd8, 0xf5, 0x4d, 0x36, 0x20, 0xc2, 0x3e, 0xc8, 0x99, 0x3f, 0x7a, + 0xef, 0x27, 0xc1, 0xd3, 0x51, 0x96, 0xb1, 0x02, 0xb3, 0xcf, 0x3f, 0xed, 0x8b, + 0xf8, 0x5d, 0x8a, 0x45, 0xf6, 0x96, 0x83, 0xec, 0xdd, 0x1a, 0x23, 0x44, 0xef, + 0xb8, 0x48, 0x07, 0xd9, 0x0f, 0x18, 0x35, 0xb4, 0xf2, 0xf2, 0x4d, 0x8f, 0xf8, + 0x12, 0x30, 0x47, 0xeb, 0x9f, 0x7d, 0x30, 0x62, 0x3e, 0x14, 0x29, 0x0d, 0x56, + 0x17, 0x96, 0x3b, 0x42, 0x21, 0x40, 0x4a, 0xe7, 0x61, 0xc8, 0x6b, 0xec, 0x7a, + 0x07, 0xbf, 0x81, 0xa0, 0xb9, 0xa7, 0xf7, 0xd0, 0x87, 0xac, 0x26, 0xce, 0x3d, + 0xfa, 0x9c, 0x93, 0xfe, 0xea, 0xeb, 0xd1, 0x0d, 0xc1, 0x88, 0xc6, 0x27, 0xd4, + 0xb9, 0x1d, 0x2a, 0x79, 0x01, 0xee, 0x5a, 0x1b, 0x38, 0x4d, 0xa3, 0x6e, 0x78, + 0x95, 0xd5, 0xb7, 0x78, 0x21, 0xfe, 0x6b, 0xca, 0xa3, 0xaf, 0xe8, 0xf2, 0x3a, + 0x96, 0x8f, 0xc9, 0xab, 0xa3, 0x7b, 0x1a, 0x4e, 0x25, 0xf5, 0xdb, 0xa1, 0xd1, + 0x42, 0xff, 0x11, 0xff, 0xd7, 0xa1, 0xba, 0x41, 0xef, 0x82, 0xc6, 0x2a, 0x95, + 0x94, 0x66, 0xe7, 0x11, 0x2a, 0xf7, 0x79, 0x6d, 0x47, 0x67, 0x12, 0x69, 0xad, + 0xd3, 0xee, 0x2b, 0x17, 0x21, 0x3e, 0xc3, 0xbd, 0x51, 0x30, 0x24, 0x4c, 0xb9, + 0x07, 0x0e, 0xa8, 0xcf, 0xa4, 0x6d, 0x44, 0xf2, 0xfc, 0xd9, 0x64, 0x06, 0x37, + 0xf7, 0xde, 0xfd, 0x50, 0xb6, 0xdc, 0x93, 0x60, 0x19, 0x45, 0xb9, 0x31, 0xe8, + 0xbb, 0x72, 0x67, 0x1f, 0xe4, 0xb4, 0xb5, 0x88, 0xc9, 0x0a, 0xd5, 0xc0, 0x0b, + 0x55, 0xdc, 0x8c, 0x8a, 0xf9, 0xb0, 0xf6, 0xa3, 0xca, 0x1e, 0x07, 0xef, 0xf1, + 0x58, 0x11, 0x39, 0x1c, 0x53, 0xf7, 0xe4, 0x3b, 0x1b, 0x81, 0x16, 0xda, 0xdc, + 0x01, 0x6d, 0x19, 0x26, 0xc8, 0x48, 0x0d, 0x4e, 0xe3, 0x4e, 0x76, 0x19, 0x1b, + 0x79, 0xbe, 0xd0, 0xce, 0x95, 0x97, 0x3a, 0x4c, 0x7c, 0xf2, 0xf0, 0x57, 0xc7, + 0x14, 0x7e, 0xdb, 0x01, 0x3d, 0x20, 0x5d, 0x81, 0xe2, 0x36, 0x08, 0x88, 0xa2, + 0xab, 0xdd, 0xcc, 0xf0, 0xf6, 0xf3, 0xd8, 0xf8, 0xba, 0x11, 0x1d, 0x64, 0x2c, + 0x52, 0xd0, 0x4e, 0xbd, 0x3c, 0xe1, 0x7c, 0x60, 0xd9, 0x22, 0x57, 0xea, 0x58, + 0x69, 0x09, 0x45, 0x01, 0xbb, 0x67, 0x12, 0x68, 0xb2, 0x24, 0x47, 0x7a, 0x8e, + 0x01, 0x41, 0xd6, 0xff, 0x37, 0xe2, 0x4f, 0xf1, 0xc7, 0x65, 0xe8, 0x4d, 0x26, + 0x4d, 0xb8, 0x8f, 0x00, 0x92, 0x8e, 0x64, 0xc4, 0x12, 0xbd, 0x59, 0x15, 0x1a, + 0x65, 0x71, 0xc6, 0x67, 0x09, 0x16, 0xb0, 0x70, 0x6b, 0x04, 0x4f, 0xc5, 0xc2, + 0xbd, 0x93, 0xad, 0xe3, 0x96, 0x79, 0x57, 0xcd, 0xb9, 0x41, 0x27, 0x4c, 0xc6, + 0xbd, 0xb4, 0xe0, 0x36, 0xb7, 0x67, 0xb9, 0x50, 0xc0, 0x9e, 0x46, 0x26, 0xa1, + 0xd0, 0x05, 0xbc, 0xf4, 0x83, 0x6e, 0xf6, 0xa1, 0xde, 0x48, 0x09, 0x5d, 0xcb, + 0x46, 0x12, 0x78, 0xb1, 0x6c, 0x45, 0x68, 0x90, 0xb2, 0x3d, 0x40, 0xbd, 0x36, + 0x04, 0x10, 0xf0, 0x01, 0x0a, 0x55, 0xf5, 0x05, 0xfe, 0x5e, 0x2d, 0xb2, 0x01, + 0xc7, 0x52, 0xe9, 0xb5, 0xb1, 0x5b, 0xf8, 0xaa, 0x9e, 0x82, 0xd6, 0x49, 0xab, + 0x11, 0x73, 0xba, 0x2a, 0x51, 0x32, 0xe0, 0xcc, 0x50, 0x51, 0xcc, 0xf7, 0x4c, + 0x7a, 0x6a, 0x37, 0x07, 0xab, 0x59, 0x83, 0xf7, 0xcc, 0x27, 0x5c, 0x99, 0x1a, + 0xbe, 0x4d, 0x7c, 0xee, 0x5f, 0x28, 0x9e, 0xfe, 0x72, 0x7e, 0xb3, 0xda, 0x86, + 0xfa, 0x21, 0xa2, 0x8d, 0x6b, 0x8a, 0x2a, 0xff, 0xd4, 0x2d, 0xb9, 0x8b, 0xb2, + 0xa4, 0x6c, 0xd8, 0xa3, 0x29, 0x31, 0x2f, 0xa9, 0x45, 0x39, 0xd9, 0xcb, 0x35, + 0xdc, 0xb6, 0x04, 0x67, 0x8b, 0x63, 0x90, 0x64, 0xd9, 0x20, 0x05, 0xdf, 0x2d, + 0x10, 0x68, 0x1c, 0x64, 0xb9, 0xed, 0x8c, 0xe4, 0x7d, 0x7e, 0xba, 0x0f, 0x2b, + 0x50, 0x2b, 0x20, 0x6a, 0xd4, 0xb2, 0xe9, 0x2b, 0xbe, 0x45, 0x86, 0xf6, 0xd7, + 0x50, 0x9e, 0x57, 0xa6, 0x37, 0x7f, 0xea, 0xbe, 0x38, 0xb3, 0xcc, 0x6c, 0x95, + 0x5d, 0x5e, 0x7b, 0xdf, 0x7e, 0xb1, 0x32, 0xd8, 0x6b, 0xc0, 0x7a, 0x30, 0x98, + 0xb4, 0x13, 0xe4, 0x40, 0x5d, 0xaa, 0xa2, 0x55, 0x29, 0x1d, 0x55, 0x2b, 0x2c, + 0x80, 0x07, 0xbe, 0xd4, 0x1e, 0x22, 0xf1, 0xcf, 0x79, 0x11, 0x82, 0x12, 0x00, + 0x55, 0x5e, 0x9c, 0x4f, 0xfb, 0x09, 0xef, 0xc1, 0x22, 0x38, 0x11, 0x75, 0x03, + 0x1c, 0x38, 0x28, 0x0b, 0x53, 0x26, 0xeb, 0xbe, 0xaf, 0x33, 0x4f, 0xdc, 0xf0, + 0xdc, 0x44, 0x4e, 0x62, 0x9f, 0x93, 0x95, 0x51, 0x54, 0x0b, 0xcb, 0xbb, 0xb1, + 0xab, 0x9c, 0x23, 0x1a, 0x86, 0x6b, 0x32, 0x9e, 0x85, 0x24, 0xab, 0x25, 0xf9, + 0x3e, 0x5e, 0x33, 0x4a, 0x05, 0x27, 0x2a, 0x3f, 0x82, 0x6f, 0x9d, 0x05, 0xa4, + 0x50, 0x58, 0xdf, 0xcd, 0xf6, 0x88, 0x43, 0xa8, 0xb9, 0x36, 0xa0, 0xcf, 0x5e, + 0x6a, 0xa8, 0xae, 0x1b, 0x80, 0xf6, 0x01, 0x61, 0xbf, 0x41, 0x4f, 0x28, 0x02, + 0x11, 0x11, 0x09, 0x21, 0xa9, 0xc8, 0x5f, 0x51, 0x04, 0xa0, 0x16, 0x8e, 0x8e, + 0x72, 0xde, 0x4f, 0x8a, 0xa0, 0x41, 0x32, 0xeb, 0x25, 0x88, 0x76, 0xf1, 0x9d, + 0x7b, 0xe5, 0xf2, 0xdd, 0x2b, 0x0b, 0x30, 0x4b, 0x92, 0x3b, 0x29, 0x52, 0xd9, + 0x1f, 0xde, 0xe7, 0xe5, 0x52, 0x05, 0xdb, 0xb1, 0x94, 0xeb, 0xba, 0x32, 0x2f, + 0xdc, 0x67, 0xb2, 0x52, 0x2c, 0x92, 0x61, 0x21, 0xc7, 0xfa, 0x1a, 0xf1, 0x7e, + 0xd0, 0x6c, 0x47, 0x27, 0x8f, 0x96, 0x08, 0x92, 0x96, 0x08, 0x7a, 0x70, 0x4b, + 0x7d, 0x0f, 0x84, 0x7d, 0x51, 0xd6, 0xcc, 0x68, 0xac, 0xc5, 0x22, 0x07, 0x74, + 0x73, 0x41, 0xf6, 0xb9, 0x8c, 0xb1, 0xcd, 0x4f, 0xaf, 0xcd, 0x2b, 0xb0, 0xd0, + 0x5b, 0xc7, 0x9b, 0xb8, 0x0d, 0x7c, 0x4b, 0x8a, 0x1a, 0x11, 0xbc, 0x0a, 0x3b, + 0xde, 0xca, 0x45, 0x41, 0x86, 0x9b, 0x4d, 0xc9, 0xd6, 0xb4, 0x8c, 0xd7, 0x86, + 0x9b, 0xf7, 0x63, 0xb9, 0xdc, 0x42, 0x45, 0x27, 0x3c, 0x70, 0x4b, 0x0d, 0x8d, + 0xec, 0x4b, 0x85, 0xd1, 0x6d, 0xd4, 0x38, 0xce, 0xd6, 0x22, 0x0f, 0xa6, 0x69, + 0x26, 0x66, 0x3f, 0xcc, 0x22, 0x8f, 0xc6, 0xc4, 0xd2, 0x7e, 0x17, 0xe3, 0x27, + 0x83, 0x4b, 0x67, 0x57, 0x91, 0x4d, 0x1b, 0xcb, 0xf3, 0x4b, 0x65, 0xd8, 0x58, + 0xab, 0x8b, 0x5c, 0x12, 0x0c, 0xb0, 0x85, 0x05, 0x22, 0xf5, 0x42, 0x89, 0x3f, + 0xdd, 0xb1, 0x79, 0xe8, 0x7f, 0x83, 0x2d, 0xaa, 0xa1, 0x52, 0xc8, 0x31, 0xf1, + 0x35, 0x64, 0x00, 0x9c, 0x41, 0x81, 0x23, 0x53, 0x3d, 0xe2, 0xc6, 0x79, 0x49, + 0xe3, 0xaf, 0x2d, 0xcb, 0x60, 0xd6, 0xbd, 0xbd, 0xda, 0xda, 0x63, 0xa3, 0x0b, + 0x4b, 0x54, 0xcd, 0x1c, 0xe5, 0xa5, 0xa0, 0x0f, 0x8e, 0x85, 0x57, 0xeb, 0xa9, + 0x23, 0x4e, 0x81, 0x17, 0x8d, 0x0f, 0xca, 0xb5, 0x61, 0x0f, 0xba, 0x96, 0x69, + 0xcf, 0xeb, 0x1b, 0xd0, 0x8c, 0xd9, 0x65, 0x33, 0x49, 0x8b, 0x27, 0x2c, 0x57, + 0x79, 0xa9, 0xf9, 0x39, 0x69, 0x1d, 0xe1, 0xad, 0x88, 0x1c, 0x80, 0x87, 0x8d, + 0x6c, 0x29, 0x42, 0x15, 0x23, 0x0b, 0xbb, 0x61, 0x90, 0x69, 0xb4, 0xdc, 0x17, + 0xb3, 0xe5, 0x9d, 0xbd, 0x24, 0x2c, 0xd8, 0x8e, 0xcc, 0x3b, 0xe3, 0xa2, 0x69, + 0x6b, 0xf7, 0xf2, 0xd9, 0xe5, 0xb8, 0xc1, 0x52, 0xcc, 0x0d, 0x99, 0xa0, 0xa5, + 0xe9, 0xa3, 0x8b, 0x1b, 0x8e, 0xb1, 0xa0, 0x13, 0xeb, 0x76, 0x51, 0x33, 0x37, + 0xa7, 0xb0, 0xda, 0xdb, 0x4e, 0x81, 0x7b, 0x6f, 0x49, 0x78, 0x02, 0xbd, 0x47, + 0xe9, 0x3a, 0x82, 0x0c, 0x4f, 0xad, 0x6c, 0x65, 0x09, 0x74, 0x42, 0xb9, 0xca, + 0xc1, 0x61, 0xb6, 0x4d, 0x0f, 0xcb, 0xfb, 0xf5, 0x4f, 0xc3, 0x04, 0xc9, 0xb7, + 0x0c, 0x74, 0xfb, 0xb0, 0xd7, 0x05, 0xc7, 0x4d, 0x56, 0xac, 0xb2, 0xfe, 0x6c, + 0x91, 0x74, 0xcc, 0x00, 0xea, 0xbe, 0xa0, 0xe5, 0x97, 0x0d, 0xff, 0xe3, 0x2c, + 0xb6, 0x12, 0x92, 0x05, 0x3d, 0xb8, 0x6d, 0x36, 0x6b, 0x7e, 0x6b, 0x30, 0x13, + 0xd1, 0x4b, 0x20, 0x5f, 0xb4, 0x5d, 0x06, 0x7e, 0x37, 0x50, 0x2e, 0x37, 0x9c, + 0x4a, 0xa1, 0x38, 0xbe, 0xc2, 0xc6, 0xbd, 0x33, 0x1f, 0x58, 0xe9, 0xaa, 0x10, + 0x09, 0xb0, 0x66, 0xdc, 0xe9, 0x9a, 0xcc, 0x1d, 0xc5, 0xa6, 0x3a, 0x8f, 0x75, + 0xd1, 0x98, 0x22, 0x7c, 0x2f, 0xbd, 0x20, 0xd5, 0x34, 0xf1, 0x20, 0x30, 0xc4, + 0x00, 0x99, 0xd8, 0x77, 0xca, 0xbe, 0x81, 0xb0, 0x87, 0x50, 0xe3, 0xfb, 0xfe, + 0x63, 0x12, 0xf6, 0x38, 0x0b, 0x98, 0xfb, 0x85, 0x0a, 0x2a, 0x14, 0x2b, 0x91, + 0x4a, 0xdc, 0x71, 0x54, 0x47, 0xc5, 0x79, 0x1a, 0x1b, 0x67, 0xae, 0x65, 0x6c, + 0xad, 0xdd, 0x21, 0xe1, 0xb4, 0x6d, 0xc9, 0xa7, 0x64, 0x12, 0x7b, 0xc0, 0xa3, + 0x01, 0xb4, 0x80, 0x04, 0xa9, 0xc5, 0x27, 0x6b, 0xcf, 0x08, 0xe7, 0xfe, 0x4a, + 0xe5, 0x2d, 0x76, 0xe4, 0x31, 0x48, 0x8a, 0x5b, 0x9d, 0x43, 0x1f, 0xa1, 0x36, + 0x34, 0x6e, 0x5a, 0x53, 0xab, 0x3f, 0x68, 0x12, 0xf2, 0xd9, 0x70, 0xf7, 0xb3, + 0x98, 0x98, 0xcf, 0x8b, 0x62, 0xf2, 0xdb, 0xf6, 0x1e, 0x99, 0xa2, 0x91, 0x5d, + 0xfb, 0x75, 0xae, 0x22, 0xb7, 0x9f, 0x84, 0xcf, 0x25, 0x97, 0xeb, 0x34, 0xec, + 0x3d, 0x29, 0x2e, 0x6b, 0x5d, 0x84, 0xeb, 0xac, 0x4d, 0x92, 0xde, 0x52, 0xe1, + 0xf8, 0xbf, 0x6b, 0xfd, 0xba, 0xda, 0x63, 0x44, 0x09, 0xf2, 0x0e, 0xf2, 0xcc, + 0x6e, 0x3c, 0x39, 0x0e, 0x43, 0x5f, 0x47, 0xe3, 0x47, 0x23, 0x8d, 0xb4, 0x86, + 0x90, 0x84, 0x04, 0x73, 0xb0, 0xa0, 0x83, 0x1a, 0x5a, 0x8a, 0x58, 0xc4, 0xdc, + 0xfc, 0x4e, 0xab, 0x7b, 0x41, 0x8c, 0xba, 0x2a, 0x41, 0x4f, 0x95, 0x57, 0x71, + 0x90, 0xff, 0x88, 0xd7, 0x27, 0xf7, 0x3e, 0x2f, 0xff, 0x97, 0xaa, 0xbd, 0x11, + 0x14, 0xb7, 0x64, 0xe3, 0xed, 0xbc, 0x18, 0x3e, 0x60, 0x3a, 0xcf, 0xb7, 0xc0, + 0x9b, 0xf1, 0x32, 0xbb, 0x01, 0xef, 0xc7, 0x17, 0x8d, 0x4f, 0x9a, 0x2d, 0xba, + 0xf4, 0x92, 0x4f, 0xd8, 0x0f, 0xbe, 0x0e, 0x60, 0x4f, 0x60, 0x39, 0x08, 0x32, + 0xeb, 0x98, 0x04, 0x79, 0xe0, 0x4e, 0x9c, 0x9a, 0x2b, 0xb2, 0xfb, 0x36, 0x84, + 0xd8, 0xf8, 0x06, 0x48, 0xd5, 0x80, 0x78, 0x38, 0x54, 0x58, 0x4f, 0x62, 0xbe, + 0x0c, 0xc9, 0x21, 0x88, 0x32, 0x38, 0x56, 0x10, 0xd9, 0x62, 0x36, 0x5f, 0x50, + 0x71, 0xfa, 0x3d, 0x36, 0x8f, 0xfb, 0x67, 0x1b, 0xa2, 0xc2, 0xf9, 0xa0, 0xfc, + 0x68, 0xd8, 0x07, 0x22, 0x19, 0xa7, 0x7b, 0xef, 0x2d, 0x6b, 0x4a, 0x19, 0xf1, + 0x6d, 0xd5, 0x30, 0x74, 0x22, 0x47, 0x46, 0xbb, 0xa5, 0xf1, 0x72, 0x82, 0x20, + 0xb1, 0x96, 0xe4, 0x0f, 0x93, 0x7c, 0x47, 0x05, 0x42, 0x9d, 0x04, 0xaa, 0x3c, + 0x50, 0x5c, 0x95, 0x60, 0x3e, 0x05, 0xff, 0x55, 0x2e, 0xc1, 0x86, 0x42, 0xd5, + 0x67, 0x05, 0x02, 0x67, 0xb9, 0xf9, 0x92, 0x9c, 0x2e, 0x13, 0x80, 0x14, 0xb5, + 0xef, 0x1b, 0xa7, 0x1d, 0x9a, 0x71, 0x86, 0xe3, 0xd1, 0x3c, 0x8a, 0x8e, 0x40, + 0x8c, 0x2a, 0x9d, 0x12, 0x01, 0xa7, 0xfe, 0xbb, 0x83, 0x34, 0x51, 0x2b, 0x44, + 0xb8, 0x2b, 0xb2, 0x01, 0x78, 0x9f, 0x63, 0x58, 0x04, 0x89, 0x6e, 0x3e, 0xb2, + 0x1b, 0x5b, 0xd8, 0xc4, 0x21, 0xf0, 0xb4, 0xcf, 0xba, 0x04, 0xde, 0x92, 0x52, + 0x8f, 0x04, 0xfb, 0x4b, 0x52, 0x6b, 0x73, 0x7e, 0xe3, 0x2d, 0xa8, 0x63, 0xf5, + 0x98, 0x45, 0x61, 0x31, 0x98, 0x3a, 0x01, 0x35, 0x8f, 0xb0, 0x7d, 0xe6, 0x75, + 0x21, 0x11, 0x58, 0x5a, 0x86, 0x25, 0x6c, 0xe0, 0x34, 0xc0, 0xd8, 0x57, 0x5a, + 0x42, 0x76, 0x13, 0x61, 0xb1, 0x18, 0x77, 0x05, 0x0b, 0xc6, 0xaf, 0xc3, 0x16, + 0x15, 0x64, 0xe9, 0x6f, 0xd8, 0xcf, 0x04, 0x8f, 0xeb, 0xeb, 0x2a, 0x92, 0x20, + 0x07, 0x1c, 0xff, 0x18, 0x2d, 0x6c, 0xa0, 0x37, 0xce, 0x2c, 0x2d, 0xed, 0x91, + 0x6b, 0xd7, 0xb8, 0x4d, 0xe2, 0x8a, 0xc0, 0x17, 0x1d, 0x97, 0xfc, 0x24, 0x95, + 0x6c, 0x26, 0x66, 0x69, 0xc1, 0x03, 0x6b, 0x2b, 0x1a, 0x23, 0xda, 0xbc, 0xf3, + 0x4e, 0x38, 0xf3, 0x51, 0x45, 0x12, 0xae, 0x8a, 0x47, 0xb3, 0x53, 0xb4, 0x16, + 0x69, 0x96, 0x75, 0xe4, 0xd3, 0x1a, 0x2f, 0xe0, 0x34, 0x08, 0xe4, 0x24, 0xa7, + 0x82, 0x9a, 0x06, 0xad, 0xe6, 0x36, 0x53, 0x61, 0xd8, 0xa9, 0x61, 0x25, 0x7c, + 0xbe, 0x25, 0xb0, 0xcd, 0xe3, 0x3e, 0x96, 0x48, 0x77, 0xdf, 0x5e, 0x57, 0xc5, + 0x3d, 0xb2, 0x83, 0x51, 0x77, 0x34, 0x3e, 0x2d, 0x87, 0x6d, 0x51, 0x4c, 0x62, + 0xfb, 0xb3, 0xb4, 0xa7, 0x08, 0xce, 0x62, 0x62, 0x05, 0xcc, 0xf9, 0x2f, 0x24, + 0x0d, 0x60, 0x2c, 0xdb, 0x5d, 0x68, 0x41, 0xfd, 0x29, 0xda, 0x63, 0x08, 0xb6, + 0xca, 0x40, 0x97, 0xd8, 0x52, 0x54, 0x10, 0x46, 0x54, 0x52, 0x23, 0x9b, 0x04, + 0x51, 0xa8, 0xdb, 0xed, 0xac, 0x1e, 0x41, 0xed, 0xdd, 0x0f, 0x6b, 0xe0, 0xe3, + 0xd8, 0x89, 0x69, 0x07, 0x03, 0xa3, 0x14, 0x57, 0x07, 0xe0, 0xb3, 0xf5, 0xdb, + 0x91, 0xb8, 0x19, 0x37, 0x56, 0xe0, 0xe3, 0x47, 0xb6, 0x64, 0xa1, 0xcc, 0xcb, + 0xd7, 0x86, 0x9a, 0x40, 0x22, 0xea, 0xdf, 0x3f, 0x87, 0x3c, 0x10, 0xec, 0xab, + 0x9a, 0x93, 0xf2, 0xca, 0xdc, 0xa7, 0xa3, 0x33, 0xb8, 0x1b, 0xb6, 0x10, 0x4e, + 0x82, 0xea, 0x14, 0xfe, 0x74, 0x1e, 0xb0, 0x62, 0x08, 0x0d, 0xc8, 0x5a, 0xcb, + 0xc8, 0xcc, 0x3a, 0x9b, 0xc8, 0x0c, 0x03, 0xd9, 0x1f, 0xfb, 0x3c, 0x25, 0xf9, + 0xe4, 0x2b, 0xc2, 0x5c, 0xf7, 0x7d, 0x73, 0x90, 0xc3, 0xab, 0xaf, 0x26, 0x10, + 0xf4, 0xec, 0xdb, 0x01, 0x9b, 0x15, 0x8d, 0xa2, 0x15, 0x5b, 0xef, 0xec, 0xb9, + 0xc2, 0x29, 0x6d, 0x03, 0xf8, 0x23, 0xea, 0xac, 0x0c, 0x74, 0x0d, 0x2a, 0x44, + 0x89, 0xb8, 0x28, 0x4c, 0x7e, 0x7b, 0x3a, 0x72, 0x9a, 0xfb, 0x69, 0xbd, 0x5b, + 0xfa, 0x5f, 0x62, 0xf9, 0xb5, 0x27, 0x37, 0x97, 0xdd, 0x24, 0xa0, 0x18, 0x30, + 0x7f, 0xc6, 0x20, 0xe6, 0x42, 0xaa, 0x27, 0xe7, 0x50, 0x6e, 0x17, 0xb1, 0x98, + 0xdc, 0xa4, 0x79, 0x0e, 0x8d, 0xe1, 0xbf, 0xb6, 0x71, 0xd8, 0xdc, 0x75, 0x13, + 0x91, 0x0e, 0x95, 0x43, 0x10, 0x72, 0x1b, 0x4f, 0xb5, 0x37, 0x33, 0xc9, 0x18, + 0xf0, 0xd1, 0x89, 0x85, 0x18, 0x89, 0x62, 0x73, 0x22, 0xd5, 0x20, 0xca, 0xcc, + 0x9d, 0xd7, 0x03, 0x6b, 0xb4, 0x39, 0xa1, 0x69, 0xef, 0x2c, 0xdd, 0x6c, 0xdb, + 0xae, 0xa5, 0xa9, 0x1b, 0xc2, 0x4a, 0xb3, 0xfc, 0xa1, 0x57, 0x4c, 0x12, 0xc9, + 0x31, 0xe7, 0xaa, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd3, 0xc6, 0x49, 0x66, 0xc0, 0x6b, + 0x62, 0x2d, 0x23, 0xc8, 0x8d, 0xb2, 0xfd, 0x4b, 0x8f, 0xa5, 0x0b, 0xe3, 0x61, + 0x94, 0x3b, 0x79, 0x6d, 0x14, 0x85, 0x5f, 0x20, 0x71, 0xd3, 0x20, 0xd4, 0x3d, + 0x6c, 0x49, 0x4c, 0x9e, 0xda, 0x35, 0xcf, 0x9b, 0xf3, 0x7d, 0xc5, 0x4b, 0x40, + 0x2e, 0xb2, 0x87, 0x64, 0xa0, 0xb9, 0x17, 0x6c, 0xf9, 0x49, 0xb2, 0xa7, 0x78, + 0x64, 0x19, 0x83, 0x89, 0x2f, 0xfb, 0x5c, 0x7b, 0xfa, 0x68, 0xe6, 0x36, 0xde, + 0xfe, 0xfc, 0xb2, 0xfa, 0x07, 0x94, 0x45, 0xec, 0xd3, 0xad, 0xdf, 0x0c, 0x22, + 0xb2, 0x61, 0x72, 0x49, 0x92, 0xe2, 0xf0, 0xd2, 0x7c, 0xff, 0x23, 0xa6, 0x46, + 0x15, 0x30, 0xdc, 0x05, 0xf4, 0x9e, 0x97, 0x2d, 0xa3, 0x71, 0x6f, 0x41, 0x91, + 0xbf, 0xf4, 0xed, 0x29, 0x02, 0x67, 0x46, 0xf0, 0x9e, 0xfa, 0x9d, 0xfc, 0xbc, + 0xde, 0xc5, 0xa6, 0x95, 0xb1, 0xf7, 0x31, 0x36, 0x14, 0x64, 0xec, 0x42, 0xe3, + 0xb5, 0x26, 0x7e, 0xb6, 0x5f, 0x55, 0x6b, 0x26, 0x7a, 0xf3, 0x59, 0x71, 0xb4, + 0x14, 0x9b, 0xb3, 0xe5, 0xaa, 0x03, 0xa4, 0x95, 0xfb, 0xeb, 0x90, 0x15, 0xac, + 0x3f, 0xf1, 0x3a, 0x5c, 0x1c, 0x2a, 0x5f, 0x81, 0x96, 0x47, 0x3d, 0x5b, 0xfe, + 0x70, 0x48, 0xdf, 0x27, 0x7f, 0x0b, 0x5c, 0xf4, 0xe6, 0xc7, 0x1c, 0xa9, 0x36, + 0x6e, 0xca, 0x3b, 0x9c, 0xf1, 0xe6, 0x06, 0x9d, 0x53, 0x9e, 0x5c, 0xe4, 0x3f, + 0xd9, 0xaa, 0x25, 0xc2, 0x11, 0xd3, 0x79, 0x92, 0xc3, 0x40, 0xad, 0xea, 0x8b, + 0x24, 0x9f, 0x28, 0xab, 0x23, 0x49, 0x39, 0x17, 0xc4, 0x9d, 0xeb, 0x28, 0x3b, + 0x4c, 0x8a, 0x64, 0x90, 0x41, 0x88, 0x7e, 0x66, 0x83, 0x8d, 0x1c, 0x42, 0x9d, + 0xec, 0xdb, 0x31, 0x59, 0xcb, 0x30, 0xaf, 0xe4, 0xfb, 0x31, 0x68, 0xcc, 0xec, + 0x44, 0x98, 0x2e, 0x05, 0xf8, 0x71, 0x13, 0x2e, 0xfa, 0x63, 0xd6, 0x5a, 0x24, + 0x93, 0xcd, 0xf2, 0x39, 0xe8, 0xb2, 0xc8, 0x09, 0x05, 0xe8, 0x04, 0xa8, 0x4d, + 0xd7, 0x6a, 0xfe, 0xaa, 0x68, 0x94, 0x79, 0x1d, 0x49, 0xb1, 0xe4, 0x00, 0xb3, + 0xfc, 0xaa, 0x82, 0x73, 0x99, 0x60, 0xad, 0xda, 0x36, 0x45, 0xbb, 0x85, 0x75, + 0x6c, 0x63, 0x00, 0x5c, 0x01, 0x6f, 0x65, 0x8b, 0xa6, 0xab, 0x52, 0x57, 0xc4, + 0x86, 0xaf, 0x13, 0xed, 0xc9, 0xb4, 0x6b, 0xf6, 0x29, 0x34, 0xaa, 0x71, 0x4f, + 0x00, 0x36, 0x05, 0x96, 0x5a, 0xc5, 0x4d, 0x82, 0x50, 0xa5, 0x53, 0x52, 0x00, + 0xd1, 0x20, 0x2a, 0xcc, 0xca, 0xaa, 0x9e, 0x42, 0xea, 0x98, 0x2a, 0x21, 0x61, + 0x8e, 0xdb, 0xb1, 0x34, 0xc3, 0x3b, 0xc8, 0x4e, 0x35, 0xfc, 0x76, 0x56, 0x05, + 0x86, 0xa3, 0xc3, 0x43, 0x8e, 0x8f, 0x2b, 0x0c, 0xe7, 0x0d, 0x86, 0x31, 0x71, + 0xdf, 0x23, 0x8e, 0x12, 0x60, 0xd5, 0x9f, 0x82, 0x40, 0x37, 0xa7, 0x71, 0x7b, + 0x2e, 0x21, 0xa9, 0x6e, 0x4d, 0x79, 0x9b, 0x8e, 0xc4, 0xc9, 0x8b, 0x8d, 0x16, + 0x83, 0x6c, 0x18, 0x22, 0xb2, 0x45, 0x62, 0x66, 0x46, 0x59, 0x86, 0x85, 0x0d, + 0x23, 0x31, 0xc7, 0x29, 0x34, 0xbd, 0xb6, 0x71, 0x54, 0xab, 0xa0, 0xad, 0x49, + 0xbe, 0x0e, 0x52, 0xd8, 0xb0, 0x78, 0x41, 0x11, 0x7c, 0x0e, 0xb7, 0x6a, 0x39, + 0x54, 0x96, 0x39, 0xf7, 0xad, 0xe7, 0x6a, 0x90, 0x71, 0x0e, 0x79, 0x83, 0x97, + 0x8e, 0x9b, 0x23, 0x34, 0x9b, 0xee, 0x22, 0xcd, 0x0c, 0x71, 0xa1, 0xf0, 0x72, + 0x70, 0xe2, 0xce, 0x8b, 0x36, 0x05, 0x1b, 0x00, 0x55, 0xba, 0x97, 0x05, 0xab, + 0x22, 0x2e, 0x8e, 0x85, 0x8d, 0xc4, 0x5b, 0x66, 0xc1, 0xef, 0x3f, 0xe2, 0x66, + 0x55, 0x03, 0xe7, 0x8b, 0x30, 0x29, 0xef, 0xfb, 0xd5, 0xbb, 0x13, 0x9e, 0x85, + 0x2c, 0x3b, 0xf9, 0x07, 0x13, 0x2e, 0x54, 0xc3, 0xed, 0xad, 0x03, 0xf7, 0xe8, + 0x68, 0xf5, 0x23, 0x15, 0x5f, 0x9f, 0x6b, 0xce, 0xf4, 0x50, 0xbc, 0x9b, 0x56, + 0x31, 0x0c, 0xda, 0x17, 0x3e, 0x50, 0xe9, 0x5a, 0x6e, 0xe5, 0xf0, 0x68, 0xb2, + 0x5e, 0x32, 0x9c, 0x35, 0x48, 0xfc, 0x24, 0x99, 0x37, 0x3c, 0xde, 0x29, 0x36, + 0x0f, 0xbb, 0xfa, 0x5b, 0x64, 0xb5, 0x74, 0x4a, 0xb0, 0x3a, 0x4b, 0xd5, 0xd9, + 0x48, 0xc1, 0xbe, 0xf8, 0xcf, 0x4e, 0x6b, 0xd9, 0x4c, 0x32, 0x80, 0x9b, 0x18, + 0xf1, 0x18, 0x9c, 0x32, 0xbb, 0x8f, 0xae, 0x27, 0x53, 0xe4, 0x85, 0x1c, 0x31, + 0x96, 0xf5, 0xbb, 0x1d, 0xa0, 0x78, 0x51, 0xb5, 0xd3, 0x1f, 0x20, 0xa0, 0xfd, + 0x3a, 0x7a, 0x4b, 0x45, 0x01, 0xf3, 0x18, 0x5d, 0x26, 0x7b, 0x1c, 0x8b, 0xb3, + 0x59, 0x5d, 0x85, 0xc5, 0x3c, 0xae, 0x18, 0x9e, 0xc9, 0xdb, 0x6f, 0x14, 0x53, + 0xb3, 0xc6, 0xad, 0x4f, 0x3b, 0x93, 0xdd, 0x10, 0x6a, 0x3a, 0x39, 0x0d, 0xb2, + 0x7a, 0x1a, 0x75, 0x0e, 0x7e, 0xd0, 0x89, 0x7e, 0xbb, 0x61, 0x98, 0x48, 0x4d, + 0xcc, 0xdf, 0xa7, 0xa7, 0xe1, 0xd8, 0xeb, 0x2f, 0x23, 0x66, 0x8d, 0x54, 0xe9, + 0x8f, 0x9e, 0xd3, 0xae, 0x90, 0xfe, 0x0c, 0x27, 0x5f, 0x17, 0x7e, 0xcf, 0x70, + 0x1f, 0xd3, 0x0b, 0x92, 0xf6, 0x1b, 0x3c, 0x12, 0x53, 0xcc, 0x31, 0x78, 0x95, + 0xfe, 0x5e, 0x39, 0xc4, 0xea, 0x03, 0x24, 0x8e, 0x83, 0x20, 0x2e, 0xa5, 0x89, + 0xa0, 0xe8, 0xfc, 0xaf, 0xc4, 0x34, 0x07, 0xb5, 0x71, 0x9c, 0x08, 0x6a, 0xc2, + 0xf5, 0x8c, 0x1c, 0x4e, 0x05, 0x63, 0x69, 0x56, 0xb6, 0x30, 0x4e, 0x31, 0x7f, + 0x4f, 0x65, 0xb4, 0xe2, 0xb9, 0x9f, 0x25, 0xe8, 0xd7, 0xbb, 0x53, 0x28, 0xea, + 0x1f, 0x31, 0x13, 0x25, 0x6a, 0x45, 0x08, 0x01, 0x6a, 0x3e, 0x9d, 0x01, 0x2e, + 0xf8, 0x19, 0xfa, 0x36, 0xa5, 0xdb, 0xce, 0x7e, 0x3a, 0xff, 0x47, 0x42, 0xc0, + 0xcd, 0x3d, 0x5d, 0x9e, 0xb8, 0x40, 0x44, 0xa0, 0x03, 0x23, 0x39, 0x40, 0x69, + 0x9b, 0xc2, 0x79, 0x45, 0xb9, 0xac, 0x93, 0x82, 0x23, 0xc1, 0x17, 0x3f, 0x34, + 0xd1, 0x7e, 0x7e, 0x2e, 0x7b, 0xbc, 0xad, 0x2d, 0x91, 0x9d, 0x1a, 0xf5, 0x54, + 0x94, 0x0b, 0x68, 0xd7, 0x43, 0x3a, 0x6d, 0x67, 0xe8, 0x5c, 0xd3, 0x35, 0x66, + 0xb0, 0x60, 0xe4, 0x48, 0xb4, 0xa2, 0xa0, 0x52, 0xa8, 0xb7, 0x9e, 0x27, 0x57, + 0x8d, 0xce, 0x6e, 0x09, 0x88, 0x6e, 0xf0, 0x92, 0xef, 0x09, 0x67, 0x97, 0x47, + 0x8b, 0xb5, 0x4b, 0x9a, 0xbb, 0xa5, 0xae, 0x26, 0x79, 0x9b, 0x07, 0xcd, 0xc8, + 0x8c, 0x80, 0x2e, 0x6a, 0xf5, 0xcb, 0xfd, 0x41, 0x24, 0x29, 0x57, 0x00, 0xac, + 0x12, 0xd9, 0x10, 0xa0, 0x2a, 0x74, 0xc8, 0xab, 0xd2, 0x4d, 0x39, 0x88, 0x72, + 0xdd, 0x9d, 0x3a, 0xb3, 0xc5, 0x4c, 0x63, 0xa0, 0x9e, 0x51, 0xbb, 0x51, 0x62, + 0x54, 0x01, 0x03, 0xab, 0x0c, 0xae, 0xfc, 0x6e, 0x5b, 0x88, 0x05, 0x21, 0xf4, + 0x9c, 0x55, 0x93, 0xa7, 0xec, 0xe1, 0xef, 0xdc, 0x00, 0xad, 0x96, 0xc3, 0x82, + 0xfe, 0xcf, 0x0f, 0x9c, 0x1c, 0x8e, 0xcd, 0xcb, 0xc2, 0x2e, 0x89, 0x07, 0xce, + 0x99, 0xdf, 0x99, 0x4a, 0x33, 0x0a, 0x90, 0x44, 0x6d, 0xae, 0xec, 0xab, 0x71, + 0xf0, 0x02, 0x35, 0xdd, 0x70, 0x23, 0x3c, 0x43, 0x17, 0xd6, 0x4e, 0xf6, 0xba, + 0x3f, 0x65, 0x76, 0x42, 0xba, 0xad, 0x97, 0x35, 0xe5, 0x48, 0x68, 0xc1, 0x97, + 0x54, 0x56, 0x89, 0xa0, 0x57, 0x0b, 0xd4, 0x58, 0x4a, 0xad, 0xe4, 0x1a, 0x59, + 0x08, 0xb8, 0xaa, 0x33, 0x54, 0x95, 0x72, 0xc7, 0x20, 0x9f, 0x63, 0xad, 0x0b, + 0x80, 0x4c, 0x76, 0x02, 0xf4, 0x8d, 0xed, 0x66, 0x8c, 0x31, 0xa0, 0x7d, 0x76, + 0x02, 0xd6, 0xf8, 0x24, 0x29, 0xc3, 0xd2, 0xde, 0xe9, 0x2f, 0x38, 0xdb, 0x5b, + 0x92, 0x03, 0xac, 0x84, 0xd0, 0xfe, 0x14, 0xba, 0x6a, 0xc1, 0x9a, 0xaf, 0x94, + 0x00, 0xf2, 0xe3, 0x58, 0x3f, 0xb1, 0x68, 0xd3, 0x03, 0xca, 0x7a, 0x88, 0x71, + 0xdd, 0xd9, 0xa2, 0x95, 0x04, 0x1b, 0x30, 0xb8, 0x1e, 0xea, 0x1e, 0x7d, 0x82, + 0x24, 0x34, 0x4b, 0xd2, 0x68, 0xa9, 0x4a, 0x11, 0x1e, 0xa7, 0xc9, 0xb0, 0x6e, + 0xc5, 0x69, 0x12, 0x45, 0x2e, 0xeb, 0x01, 0xcf, 0x88, 0x87, 0xa3, 0xe2, 0x6e, + 0x14, 0x40, 0x6f, 0xfe, 0xec, 0x4b, 0xfd, 0x7a, 0x9f, 0xd8, 0x77, 0xce, 0x52, + 0x03, 0xfe, 0x6b, 0x05, 0x8d, 0x23, 0x1e, 0xc7, 0x1a, 0xf9, 0xca, 0x18, 0xed, + 0x5c, 0x73, 0x55, 0x06, 0xd7, 0xba, 0x28, 0xee, 0x68, 0xee, 0x66, 0x58, 0x7c, + 0x99, 0x8c, 0x8f, 0xec, 0xa7, 0xae, 0x06, 0x8c, 0x8e, 0xd0, 0x79, 0xe5, 0xa9, + 0xa4, 0x36, 0x72, 0x8c, 0xce, 0xe1, 0x0c, 0x8f, 0x12, 0x6f, 0x7b, 0x2f, 0xa0, + 0xd0, 0xff, 0x91, 0xcc, 0x41, 0xee, 0x28, 0xa1, 0x96, 0x23, 0x03, 0x37, 0xc6, + 0x1f, 0x42, 0xe9, 0x52, 0x2b, 0xf6, 0xde, 0x64, 0xfc, 0x5a, 0x57, 0xe3, 0x74, + 0x77, 0x06, 0x07, 0x63, 0x0b, 0xc1, 0x96, 0xed, 0x05, 0x2d, 0xff, 0x00, 0x83, + 0x61, 0xfc, 0x59, 0xfd, 0x9c, 0x48, 0xd2, 0x62, 0xb9, 0x3a, 0xee, 0x45, 0x65, + 0x2c, 0x78, 0x78, 0x05, 0xdf, 0xac, 0xe8, 0x3d, 0x04, 0xe5, 0x24, 0x40, 0x3a, + 0x25, 0xa1, 0x66, 0xa1, 0xf4, 0x8e, 0xcc, 0x8f, 0xff, 0x84, 0x4f, 0x09, 0xde, + 0x67, 0x48, 0x04, 0x52, 0xa6, 0x78, 0x9d, 0x48, 0xb7, 0xbd, 0xbd, 0x81, 0x1f, + 0x0e, 0xda, 0xda, 0xa8, 0xee, 0x8e, 0xb9, 0x16, 0x17, 0x99, 0x2e, 0xad, 0x6f, + 0x8a, 0x8b, 0x9e, 0xf4, 0xc5, 0xad, 0xb6, 0xf2, 0x52, 0x48, 0xb2, 0x13, 0xf3, + 0xd6, 0x93, 0xf6, 0x3c, 0x0d, 0x5d, 0x15, 0xab, 0x54, 0x32, 0x88, 0x07, 0x14, + 0x27, 0x35, 0x79, 0x37, 0x3c, 0x49, 0xcb, 0xf1, 0x47, 0xf9, 0x4a, 0x84, 0xad, + 0xe6, 0x48, 0x49, 0xeb, 0x5a, 0x94, 0x04, 0x40, 0x13, 0x38, 0x96, 0xa2, 0x45, + 0x55, 0xe4, 0x01, 0x55, 0x99, 0xc0, 0x46, 0xdf, 0xa6, 0xf1, 0x4a, 0x28, 0x70, + 0x53, 0x3a, 0xe4, 0x7d, 0x33, 0xff, 0x81, 0x6b, 0x8e, 0x46, 0x63, 0xf0, 0x70, + 0xc8, 0x0d, 0x8d, 0xb0, 0x1b, 0x43, 0xc6, 0x0f, 0x5f, 0xc0, 0x2c, 0x85, 0xac, + 0xf5, 0xe1, 0x06, 0xd3, 0xba, 0x71, 0xea, 0x69, 0x3b, 0xa4, 0x65, 0xdd, 0x61, + 0xff, 0x1d, 0x80, 0xfe, 0xee, 0xa1, 0xb6, 0xd5, 0xa1, 0x63, 0xd0, 0xc9, 0x62, + 0x43, 0x16, 0x36, 0xe1, 0xed, 0x62, 0x19, 0x66, 0xfe, 0x28, 0x5b, 0xc9, 0x70, + 0xa2, 0x66, 0xbb, 0x40, 0x8d, 0x4d, 0x48, 0xd5, 0x5e, 0xf7, 0x17, 0x04, 0xf5, + 0xb7, 0x98, 0x62, 0xbd, 0x80, 0x6a, 0x6a, 0x33, 0xe1, 0x13, 0xb1, 0x88, 0x32, + 0xb3, 0xd5, 0x9e, 0x3a, 0x69, 0x84, 0xe1, 0x4f, 0xd5, 0x2a, 0xc9, 0xd2, 0xbe, + 0x3a, 0xea, 0xaa, 0xbf, 0x38, 0x29, 0xcb, 0xf4, 0xdf, 0xca, 0x68, 0x03, 0xaf, + 0xcd, 0x1f, 0xc4, 0xcd, 0x02, 0x44, 0xd7, 0xb6, 0x3b, 0x4c, 0x9d, 0x4a, 0xa1, + 0xa2, 0x27, 0xad, 0xda, 0x80, 0x6a, 0x46, 0x24, 0xa0, 0x79, 0x65, 0xb9, 0xfd, + 0xa1, 0x73, 0xa2, 0xd9, 0x9a, 0x62, 0x4f, 0x4a, 0x78, 0xe9, 0xc7, 0x17, 0x63, + 0x01, 0x2b, 0x77, 0xaf, 0x32, 0x6c, 0x75, 0x22, 0x6b, 0x7d, 0xe8, 0x29, 0x74, + 0x4b, 0x6d, 0x39, 0x72, 0xe4, 0x7f, 0x6a, 0x14, 0x5b, 0x81, 0x34, 0x0d, 0x27, + 0x16, 0x20, 0x1e, 0x07, 0x1e, 0x47, 0x1a, 0x85, 0x5e, 0x9c, 0xc3, 0x6d, 0x39, + 0x49, 0x97, 0x15, 0x74, 0xbf, 0x3a, 0x06, 0x0f, 0xc0, 0xd8, 0x82, 0xd0, 0xa9, + 0x86, 0x5c, 0x24, 0xe0, 0x94, 0x03, 0x17, 0x30, 0xcb, 0xe1, 0x88, 0xe6, 0xfd, + 0xaf, 0xcb, 0xba, 0xf7, 0x51, 0xbe, 0x87, 0xaf, 0x96, 0x5c, 0xd9, 0x8d, 0x99, + 0x31, 0x04, 0xca, 0x6e, 0xdd, 0x29, 0x28, 0x0c, 0xda, 0x86, 0x55, 0x67, 0xbd, + 0xd4, 0xb4, 0xba, 0x47, 0x37, 0xe6, 0x1c, 0x3f, 0x0a, 0xd8, 0x75, 0xa8, 0xde, + 0xe6, 0xe6, 0xcd, 0xff, 0x26, 0x81, 0x88, 0x08, 0xff, 0x9b, 0x2d, 0x55, 0x87, + 0x95, 0xd6, 0x5d, 0x2a, 0x95, 0xb4, 0x56, 0x56, 0x19, 0xf7, 0xb2, 0x41, 0x62, + 0xcc, 0x47, 0x59, 0x9a, 0x33, 0x13, 0x06, 0xe3, 0x65, 0x2f, 0xfb, 0xc3, 0xb3, + 0xfd, 0x06, 0xc1, 0x46, 0x0c, 0x80, 0x6f, 0x4e, 0x61, 0xbe, 0xc2, 0xa2, 0xa7, + 0xb6, 0xc7, 0x96, 0xf6, 0x5d, 0xcf, 0x36, 0xa4, 0xaf, 0xc6, 0xd8, 0x10, 0x09, + 0x35, 0x21, 0x0a, 0x86, 0x38, 0x9f, 0x24, 0x9e, 0x2f, 0x82, 0x32, 0x73, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7b, 0x8b, 0x33, 0x6b, 0x5f, 0x55, 0x40, 0x0b, 0x06, 0x79, 0xba, + 0x0c, 0x1e, 0xf0, 0x20, 0xc9, 0x26, 0x85, 0xa4, 0x24, 0x91, 0x79, 0x95, 0xea, + 0x63, 0xad, 0x1d, 0x5e, 0x28, 0xdd, 0x63, 0x99, 0x83, 0x82, 0xc7, 0xb3, 0x9d, + 0x26, 0xdb, 0x80, 0xb4, 0x3e, 0x32, 0x4f, 0xaf, 0x5d, 0x63, 0x60, 0x4a, 0x84, + 0xf2, 0x13, 0x5c, 0xbf, 0xf5, 0x98, 0xeb, 0x50, 0xe1, 0xd3, 0xa4, 0xb9, 0x9c, + 0xd6, 0x6c, 0x7a, 0xfd, 0xe6, 0x7f, 0xac, 0x47, 0xf0, 0x35, 0x8e, 0xc7, 0x83, + 0xbe, 0x35, 0x95, 0x47, 0x96, 0xe5, 0x97, 0x3a, 0xcf, 0xf6, 0x31, 0x98, 0xa3, + 0x55, 0x94, 0x18, 0x7e, 0xf8, 0x17, 0x00, 0x0b, 0x08, 0x88, 0x1e, 0x70, 0xe0, + 0xb2, 0xcd, 0xe2, 0x31, 0x51, 0x79, 0xc0, 0x84, 0x15, 0x51, 0xe8, 0xbd, 0x92, + 0x8e, 0xb6, 0x24, 0x87, 0x6e, 0x86, 0xb0, 0xb3, 0x3a, 0xab, 0x0c, 0xde, 0x87, + 0xeb, 0x8f, 0xd4, 0x78, 0x8d, 0xe9, 0xfb, 0x37, 0xea, 0xb3, 0xb4, 0x7f, 0xd5, + 0xdf, 0xe9, 0xb3, 0x7b, 0xcb, 0xb6, 0xe1, 0xf2, 0x25, 0xfd, 0x29, 0xab, 0x07, + 0xfc, 0x9f, 0xf5, 0xa0, 0x8f, 0x48, 0x66, 0x9e, 0x1c, 0x99, 0x68, 0xf5, 0x21, + 0x7a, 0xd3, 0x45, 0x2d, 0xad, 0x04, 0x78, 0x39, 0x07, 0x44, 0xe9, 0xd1, 0x67, + 0x85, 0xcd, 0x54, 0xa5, 0x03, 0x98, 0xb0, 0x14, 0xa0, 0x7b, 0x78, 0x45, 0x99, + 0x7a, 0x5b, 0x11, 0x6b, 0xb2, 0xc2, 0xf4, 0xc4, 0xe5, 0x64, 0x6e, 0x63, 0x08, + 0x2c, 0x5e, 0x3f, 0xee, 0x50, 0x92, 0xff, 0x2f, 0xa8, 0x9a, 0xe3, 0x2a, 0xd6, + 0x99, 0x07, 0x50, 0x4d, 0x68, 0x85, 0xb5, 0xbd, 0x72, 0xc8, 0x23, 0xd4, 0xc7, + 0x0d, 0x5e, 0xd4, 0x5c, 0xb0, 0x0c, 0x3e, 0x04, 0x05, 0x89, 0x2c, 0x88, 0x83, + 0x74, 0x53, 0xfe, 0xf2, 0xef, 0xb7, 0x51, 0x37, 0xf3, 0xc2, 0xab, 0xbc, 0x35, + 0x47, 0xdf, 0x86, 0xee, 0x01, 0x36, 0xb6, 0xe8, 0x5f, 0x33, 0xc5, 0x25, 0x58, + 0x3f, 0xfe, 0x27, 0xe6, 0xff, 0x48, 0xa8, 0x0d, 0x12, 0x4e, 0xf8, 0x01, 0xd3, + 0x24, 0x75, 0x4e, 0x16, 0x1d, 0x8b, 0xd6, 0x77, 0x44, 0xdf, 0x8a, 0xc5, 0x84, + 0x9b, 0x65, 0x5a, 0xcf, 0x9f, 0xa7, 0xb2, 0xea, 0x84, 0x62, 0x1d, 0x8e, 0x4d, + 0xd8, 0x57, 0x6d, 0xa7, 0x5e, 0xd1, 0xb4, 0x8a, 0xcb, 0x91, 0x08, 0x03, 0x27, + 0x3e, 0x48, 0x37, 0x73, 0xa9, 0x9d, 0x58, 0xcb, 0x70, 0x40, 0x8f, 0x3f, 0x23, + 0xa3, 0xea, 0x71, 0xd6, 0x73, 0x23, 0xb8, 0xf9, 0xfd, 0x51, 0x93, 0xb8, 0xdb, + 0x90, 0x6a, 0x18, 0x86, 0xe4, 0x26, 0xd0, 0xd3, 0x21, 0x6e, 0x7f, 0x0f, 0x42, + 0xa9, 0xaa, 0xe0, 0x0f, 0xc3, 0x79, 0x12, 0x20, 0xdb, 0xb1, 0x03, 0x15, 0x19, + 0xbc, 0x1e, 0xcc, 0xf8, 0x29, 0x8a, 0x22, 0xab, 0x20, 0x92, 0x71, 0x65, 0xaa, + 0x95, 0xd5, 0x46, 0x88, 0x83, 0x48, 0x17, 0x58, 0x3c, 0x64, 0x90, 0x28, 0x77, + 0x34, 0xea, 0x30, 0x0c, 0x38, 0x94, 0xf9, 0x9b, 0xaa, 0x29, 0xee, 0x97, 0x50, + 0x9d, 0x1c, 0x10, 0x71, 0xf2, 0x17, 0x42, 0xba, 0x67, 0x13, 0xed, 0xa0, 0x20, + 0x38, 0x1e, 0x60, 0x98, 0xb0, 0x5a, 0xde, 0x28, 0x09, 0x63, 0xb3, 0x98, 0xc0, + 0x3b, 0xf4, 0xc4, 0xe1, 0xf1, 0x9a, 0xd1, 0xad, 0xf1, 0xf0, 0xd6, 0x1f, 0xac, + 0xbf, 0x99, 0x66, 0xbd, 0xb0, 0x1f, 0xd1, 0x84, 0xb2, 0x00, 0xf8, 0x66, 0xc5, + 0xd1, 0x2e, 0x3d, 0xc5, 0x7e, 0xcf, 0x4f, 0xcd, 0x60, 0xc4, 0xa7, 0x56, 0x19, + 0x1d, 0xcf, 0x50, 0xbb, 0x0f, 0x97, 0x6f, 0x00, 0xe4, 0x36, 0x36, 0xa6, 0x83, + 0x08, 0x69, 0x2f, 0x40, 0x24, 0x4c, 0x39, 0x15, 0x34, 0x4b, 0x6f, 0x1f, 0x5e, + 0xe7, 0x0e, 0x51, 0xe1, 0x2b, 0x28, 0x53, 0x85, 0x53, 0x40, 0x3b, 0xe1, 0x49, + 0x8e, 0x00, 0x75, 0xdb, 0xda, 0x3e, 0x66, 0x6d, 0x9e, 0xbd, 0x18, 0xa1, 0x27, + 0x21, 0xc9, 0x73, 0x49, 0xac, 0x10, 0xe8, 0xfa, 0x2d, 0x6a, 0x59, 0xb2, 0x23, + 0x56, 0xa7, 0x71, 0x96, 0x18, 0xaa, 0xb5, 0xc7, 0x57, 0xf8, 0x82, 0x1e, 0xfc, + 0x3e, 0x07, 0x1b, 0x75, 0xf2, 0x15, 0xb2, 0x00, 0xb7, 0xd2, 0x99, 0x98, 0xed, + 0x7a, 0xe0, 0x05, 0x7f, 0xb2, 0x32, 0x9c, 0xa9, 0x13, 0x6d, 0xd2, 0xbc, 0x51, + 0xa6, 0x59, 0x01, 0x71, 0xdf, 0xca, 0x3b, 0xcb, 0x93, 0x6b, 0x11, 0xc6, 0x3c, + 0x03, 0xbb, 0x7f, 0xce, 0x30, 0xa0, 0x5f, 0x9b, 0x6f, 0x8f, 0xf3, 0x54, 0x06, + 0x04, 0x50, 0xa3, 0x45, 0x2d, 0xa1, 0x86, 0xe9, 0x3d, 0x6c, 0x32, 0xda, 0x62, + 0x72, 0xb8, 0x9b, 0xc4, 0xd6, 0xd5, 0xe8, 0x47, 0x8f, 0x29, 0x91, 0x01, 0x98, + 0x97, 0x11, 0xa9, 0xd2, 0x20, 0x97, 0xcd, 0xb7, 0x0c, 0x15, 0x0e, 0xd2, 0x6d, + 0xf4, 0x7b, 0x0c, 0xdd, 0xee, 0x52, 0x1b, 0x4f, 0x1e, 0x98, 0x96, 0xa1, 0xb6, + 0x97, 0x86, 0x53, 0xa4, 0xe3, 0x8b, 0x0d, 0x28, 0x52, 0x6e, 0x1e, 0x3a, 0x87, + 0x43, 0x5a, 0xc4, 0xfd, 0x30, 0x97, 0xaf, 0xe3, 0x21, 0xe7, 0x2d, 0x40, 0xc4, + 0x70, 0xf3, 0xb5, 0x3f, 0x5c, 0x35, 0x8d, 0x2e, 0x53, 0x69, 0x7c, 0xaf, 0x66, + 0x9d, 0xea, 0xa1, 0x1d, 0xe7, 0x7c, 0x98, 0x4a, 0x73, 0x0e, 0x5b, 0xf7, 0xb3, + 0x8e, 0xf6, 0x58, 0x9a, 0x5a, 0xa7, 0x55, 0x81, 0xbf, 0xd3, 0xc0, 0x07, 0x8a, + 0x63, 0xa3, 0x92, 0x96, 0x0e, 0xc3, 0xf2, 0xa0, 0x5c, 0x08, 0x1a, 0x48, 0x4e, + 0xb4, 0xf4, 0x25, 0xb7, 0x08, 0x36, 0x0f, 0x82, 0x85, 0x3c, 0xfd, 0x50, 0xa0, + 0x27, 0xfa, 0x92, 0x51, 0x76, 0x86, 0x96, 0xf3, 0x73, 0x5c, 0xd9, 0xed, 0xf7, + 0x9e, 0xcd, 0x4b, 0xe0, 0x8c, 0x57, 0x85, 0xc8, 0xae, 0xe7, 0x9a, 0x13, 0x23, + 0x87, 0x09, 0x94, 0x2f, 0x2c, 0xfd, 0x0f, 0x80, 0x7d, 0xaa, 0xb5, 0x0c, 0xc6, + 0x13, 0x1b, 0xab, 0x91, 0x25, 0x67, 0x36, 0x27, 0xf5, 0xe9, 0xa3, 0xd5, 0x3d, + 0x99, 0xfa, 0x02, 0x5c, 0x39, 0xfa, 0xb0, 0x9e, 0x2a, 0x21, 0x34, 0x6d, 0xc7, + 0xf8, 0x60, 0xa6, 0x2d, 0xd2, 0x10, 0x8e, 0x04, 0x41, 0x17, 0x8e, 0xf9, 0x76, + 0x21, 0xae, 0xfc, 0xe8, 0x97, 0x28, 0x10, 0xa4, 0xc7, 0xfc, 0x1b, 0x3c, 0x7e, + 0xaa, 0x83, 0xd4, 0xa6, 0x2b, 0xd7, 0x10, 0x98, 0x96, 0x11, 0xdd, 0x7e, 0x2f, + 0x4b, 0xdf, 0x15, 0xd8, 0x31, 0x00, 0x60, 0x11, 0xb4, 0x4e, 0xd9, 0x59, 0xdc, + 0x61, 0xd8, 0xde, 0x52, 0x74, 0x5e, 0x30, 0x67, 0x9c, 0xef, 0x04, 0x01, 0x3a, + 0xc6, 0x15, 0x4e, 0xf0, 0x64, 0x69, 0x82, 0x38, 0x74, 0x25, 0x21, 0x62, 0x26, + 0x3f, 0x3a, 0x4b, 0xa5, 0x65, 0x7b, 0x8d, 0x0e, 0xcf, 0x03, 0x86, 0x44, 0x1f, + 0x87, 0x30, 0xd0, 0xf1, 0x4e, 0x86, 0x8a, 0x32, 0x46, 0x37, 0xb0, 0xd3, 0x4a, + 0x9d, 0x1d, 0xd6, 0xc3, 0x9f, 0x28, 0xfd, 0x9a, 0xf3, 0x50, 0xdc, 0x23, 0x93, + 0x79, 0x29, 0xe3, 0x79, 0x70, 0xf8, 0x87, 0x37, 0x01, 0xd3, 0xfa, 0x47, 0x10, + 0x10, 0xa7, 0x21, 0x40, 0x68, 0xad, 0x1b, 0x89, 0x02, 0x52, 0x26, 0x1d, 0xd9, + 0x0d, 0x89, 0xc5, 0xa6, 0xf2, 0x90, 0x4b, 0xc6, 0x16, 0xb0, 0x27, 0xd7, 0xbe, + 0xc8, 0x79, 0xb7, 0xa1, 0x78, 0x25, 0x4f, 0xdc, 0xaa, 0x99, 0x1b, 0x42, 0x2b, + 0x7a, 0x96, 0x93, 0xe7, 0x64, 0xa1, 0x27, 0xb1, 0x72, 0xa0, 0xdc, 0xca, 0xc4, + 0x4f, 0x15, 0x27, 0x08, 0x6c, 0x48, 0x89, 0x85, 0xf9, 0x23, 0x5e, 0x28, 0x82, + 0xb4, 0x78, 0x16, 0x44, 0xeb, 0xa9, 0xed, 0x09, 0x61, 0xca, 0x7a, 0x68, 0x45, + 0xb5, 0x73, 0x65, 0xd8, 0x75, 0x4b, 0xdc, 0x79, 0x1f, 0x81, 0xc8, 0x09, 0xd0, + 0x12, 0xbd, 0x32, 0x9b, 0x6a, 0x44, 0xbd, 0x3d, 0xfa, 0x34, 0x73, 0x5c, 0xe4, + 0xc7, 0x38, 0xed, 0xef, 0xa4, 0x2d, 0x3c, 0x74, 0x09, 0x2b, 0x5c, 0xba, 0x9c, + 0x35, 0x81, 0x57, 0xd2, 0xab, 0x8a, 0x68, 0x83, 0x04, 0x0f, 0x40, 0xce, 0xc7, + 0x98, 0xa6, 0x9d, 0x7e, 0x0e, 0xa3, 0xb4, 0x76, 0xd9, 0x93, 0xd6, 0x96, 0xdb, + 0x0a, 0xdd, 0xd5, 0x43, 0x3f, 0x9e, 0x7a, 0x0f, 0xfb, 0xe0, 0x24, 0x26, 0x1e, + 0x79, 0x8d, 0xad, 0x05, 0x8e, 0xc8, 0xde, 0x26, 0x7c, 0x94, 0x78, 0xc8, 0x01, + 0xff, 0x37, 0x1e, 0x41, 0xc0, 0xbc, 0x0c, 0xf4, 0x6a, 0x4a, 0x84, 0xd0, 0xac, + 0xa4, 0x73, 0xe8, 0x80, 0xde, 0x96, 0x29, 0x69, 0xe9, 0xde, 0x23, 0x99, 0xa2, + 0x99, 0x56, 0x80, 0xdd, 0x76, 0x8f, 0xd7, 0x6b, 0xc6, 0x89, 0x6f, 0xe0, 0x2a, + 0xa4, 0x82, 0xf7, 0x6c, 0x72, 0x52, 0xe6, 0x65, 0x04, 0xe8, 0x80, 0xd2, 0x76, + 0xbf, 0x7d, 0x55, 0x7b, 0x39, 0x6a, 0xde, 0x3b, 0xb4, 0x7a, 0x6b, 0x0e, 0x0d, + 0xcf, 0x06, 0x3b, 0x1a, 0xd8, 0x56, 0x69, 0x4f, 0x8e, 0xef, 0x54, 0xca, 0x7d, + 0xf4, 0x2b, 0x41, 0xf9, 0xc6, 0x15, 0x3e, 0xa7, 0x47, 0x1c, 0xd5, 0x4f, 0x90, + 0x54, 0x7c, 0xc4, 0xd4, 0xef, 0x5f, 0xb1, 0xbf, 0xe5, 0x82, 0x88, 0x22, 0x59, + 0xc7, 0x77, 0xef, 0xc4, 0xeb, 0x8f, 0x5d, 0x75, 0x53, 0x1c, 0x1b, 0x80, 0x1b, + 0x72, 0x12, 0xc6, 0xf1, 0x45, 0x09, 0x78, 0x40, 0x20, 0xcb, 0xc3, 0xb0, 0x0e, + 0xb5, 0x31, 0xc5, 0x62, 0x44, 0x36, 0x89, 0x28, 0xa8, 0x51, 0xae, 0x53, 0x7c, + 0x74, 0x80, 0xee, 0x6e, 0x45, 0x1b, 0x29, 0x74, 0x32, 0xee, 0x17, 0x58, 0x22, + 0x99, 0x50, 0xcf, 0x78, 0x08, 0x49, 0x32, 0x6c, 0x3f, 0x28, 0xdd, 0x53, 0xd6, + 0x81, 0x19, 0xd2, 0x96, 0x95, 0x50, 0x12, 0xa2, 0x6f, 0x83, 0x3c, 0xdd, 0x29, + 0xc6, 0xf4, 0xc7, 0x16, 0xf1, 0xd3, 0x37, 0xd3, 0xf4, 0xd2, 0x1c, 0x7a, 0x63, + 0xf8, 0x54, 0xc9, 0xf4, 0xc1, 0xc4, 0xcc, 0xf1, 0x81, 0xad, 0x43, 0x16, 0xca, + 0xb1, 0x36, 0x46, 0x7c, 0x01, 0xd9, 0x6d, 0x36, 0xe2, 0x98, 0x1c, 0x86, 0xc4, + 0x76, 0x56, 0x7d, 0x83, 0x77, 0x6b, 0x73, 0x37, 0x35, 0xd5, 0x65, 0x8a, 0x48, + 0xf9, 0x89, 0x7c, 0xf1, 0xe5, 0x05, 0x2b, 0x37, 0xec, 0x1c, 0x88, 0x91, 0x47, + 0x36, 0xd9, 0xf9, 0x7c, 0x54, 0x99, 0xd7, 0x3d, 0x92, 0x3b, 0x45, 0x00, 0x69, + 0x4f, 0xfa, 0x57, 0x35, 0xc9, 0x3c, 0xdb, 0x87, 0xb3, 0x5d, 0x82, 0x95, 0x49, + 0xb1, 0xc6, 0x38, 0x3e, 0x95, 0xfd, 0x19, 0x02, 0xad, 0x29, 0x80, 0xf2, 0xa3, + 0xa2, 0x48, 0x3a, 0xce, 0x74, 0xb7, 0x64, 0x3d, 0x8e, 0xae, 0x8d, 0x07, 0x9a, + 0xa0, 0x06, 0x75, 0x41, 0x00, 0x6b, 0x94, 0xa6, 0xf9, 0x13, 0xdc, 0xff, 0x13, + 0xd6, 0x7c, 0xd9, 0xa8, 0xcf, 0xdf, 0x30, 0xb0, 0xc3, 0xd1, 0x5a, 0xaa, 0x47, + 0x0b, 0x3f, 0x89, 0x56, 0x10, 0x51, 0x42, 0xfa, 0x26, 0x11, 0xfe, 0xda, 0xa4, + 0x3f, 0xac, 0xbb, 0x3f, 0x05, 0x96, 0xf6, 0x78, 0x87, 0xcd, 0xee, 0x91, 0x42, + 0xc5, 0x09, 0x0a, 0x84, 0xe6, 0x25, 0x29, 0x31, 0xff, 0xcf, 0x61, 0xa5, 0x0a, + 0x4b, 0x92, 0x85, 0x30, 0x60, 0xe8, 0xb8, 0x7e, 0x10, 0xce, 0xa8, 0xce, 0x00, + 0xe4, 0x66, 0x5e, 0x5f, 0x93, 0x1f, 0x0e, 0x08, 0xdc, 0x52, 0x47, 0xbe, 0x1a, + 0xed, 0xc7, 0x9e, 0xbb, 0x7c, 0x20, 0x16, 0x2f, 0xca, 0x7b, 0xf9, 0x0e, 0x58, + 0x83, 0x02, 0x5f, 0xc9, 0x24, 0x36, 0x8d, 0x42, 0x45, 0x0b, 0x4f, 0xb7, 0xa7, + 0xe1, 0x91, 0x0e, 0xdd, 0x8d, 0x29, 0x5f, 0x03, 0xd4, 0xde, 0x03, 0xde, 0x60, + 0x51, 0xd1, 0xfc, 0xf2, 0x87, 0xf5, 0x4f, 0x38, 0x24, 0x41, 0xdd, 0xe0, 0x0c, + 0xb6, 0x83, 0xa4, 0x04, 0x8c, 0xe5, 0x4d, 0x42, 0x20, 0x90, 0x57, 0x24, 0xb3, + 0x09, 0xc7, 0x99, 0x92, 0x4b, 0x85, 0x4a, 0xfa, 0x37, 0x7b, 0x80, 0x1a, 0x03, + 0x52, 0xfc, 0x44, 0x50, 0xb3, 0x35, 0x27, 0x7a, 0xda, 0xd7, 0x61, 0xe4, 0x8a, + 0x1d, 0x1d, 0xd3, 0x78, 0x93, 0x6a, 0x49, 0x1e, 0x28, 0x6c, 0xaf, 0xc7, 0x00, + 0xb4, 0x8e, 0xdf, 0x15, 0xf1, 0xc2, 0xd6, 0xed, 0xf1, 0xa2, 0x4e, 0x0e, 0x51, + 0xb3, 0x98, 0x55, 0x64, 0xeb, 0xa9, 0x69, 0xcd, 0x6e, 0xe6, 0x59, 0xba, 0xae, + 0xf7, 0x46, 0xe1, 0x3a, 0xba, 0x64, 0xaf, 0xad, 0x58, 0xaf, 0x52, 0xf4, 0x28, + 0x17, 0x36, 0x45, 0x75, 0x7a, 0x40, 0x7e, 0x1f, 0xdf, 0xd9, 0x89, 0x38, 0x0c, + 0x02, 0xbc, 0xc3, 0xc3, 0x7f, 0x48, 0x90, 0xc0, 0x8e, 0xb9, 0x31, 0x62, 0xcf, + 0x78, 0xbc, 0x3c, 0x74, 0x53, 0xf3, 0xf9, 0x92, 0xa7, 0x94, 0x53, 0x4c, 0x07, + 0xe3, 0x96, 0x8d, 0x82, 0x70, 0xaa, 0x19, 0x1f, 0x67, 0x80, 0x0a, 0x0b, 0xb3, + 0xe7, 0xbf, 0xa5, 0x4b, 0x0f, 0x6f, 0xa5, 0x3e, 0xe8, 0xfb, 0x13, 0x69, 0x82, + 0xce, 0x71, 0xf4, 0x08, 0x64, 0xb5, 0x4d, 0x00, 0x45, 0x1a, 0xf3, 0xf5, 0x32, + 0x74, 0x22, 0x42, 0x16, 0x06, 0xea, 0x10, 0xc0, 0xd6, 0x12, 0x7c, 0x02, 0xf9, + 0x1a, 0xd3, 0xae, 0xb9, 0xff, 0xd6, 0x11, 0x12, 0x25, 0x14, 0x14, 0x48, 0xbe, + 0x82, 0x40, 0xc4, 0x29, 0x73, 0xac, 0x52, 0xd7, 0x1b, 0x01, 0x2f, 0xe8, 0xef, + 0x41, 0xf0, 0x0e, 0xc1, 0x96, 0xc7, 0x57, 0x89, 0x9e, 0xf8, 0xc0, 0x0e, 0xf8, + 0xdf, 0x44, 0x5c, 0x56, 0x54, 0x69, 0xd8, 0x4b, 0xd0, 0x2c, 0x7f, 0xc4, 0x1b, + 0xfc, 0xdf, 0x98, 0x95, 0x1f, 0x50, 0xe8, 0x3f, 0x19, 0xa0, 0x00, 0xa9, 0xe4, + 0x53, 0xf6, 0x21, 0x67, 0xe7, 0x35, 0x0f, 0x92, 0x36, 0x08, 0x31, 0xbd, 0x7c, + 0x52, 0x22, 0xb6, 0x70, 0x61, 0x6e, 0x4b, 0x6c, 0xa8, 0xa2, 0x35, 0x50, 0xca, + 0xd8, 0xac, 0x0d, 0xdb, 0x76, 0x45, 0xe2, 0xb9, 0x71, 0x3b, 0xe7, + ], + script_code: Script(vec![0x6a, 0x00, 0x00, 0x65, 0x53, 0xac, 0x63, 0x53, 0x63]), + transparent_input: None, + hash_type: 1, + amount: 1871432121379810, + consensus_branch_id: consensus::BranchId::Sapling, + sighash: [ + 0x36, 0x77, 0xa9, 0x48, 0x4f, 0x04, 0x04, 0xfb, 0x50, 0x64, 0x58, 0x56, 0xf4, + 0xd4, 0xa7, 0x0b, 0x2e, 0x2b, 0x1c, 0x2d, 0x86, 0x2f, 0x1d, 0x4e, 0xf6, 0x8d, + 0x52, 0x09, 0x60, 0xa1, 0x2a, 0x2b, + ], + }, + Test0243Vector { + tx: vec![ + 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0xa0, 0x1e, 0x64, 0x49, + 0xae, 0x43, 0x5c, 0x24, 0xbe, 0x7b, 0x9d, 0x28, 0x8a, 0xd7, 0x57, 0x12, 0xc9, + 0x2a, 0xa5, 0x06, 0x18, 0xdf, 0xba, 0x18, 0xe8, 0x4e, 0x88, 0xd4, 0x60, 0x68, + 0xdf, 0x0b, 0x42, 0xaf, 0x89, 0x29, 0x07, 0x00, 0x6a, 0x52, 0xac, 0x65, 0x51, + 0x63, 0x6e, 0x99, 0x51, 0xd0, 0x09, 0xa9, 0x39, 0xf7, 0x59, 0xa8, 0xa2, 0xc0, + 0x49, 0xde, 0xf0, 0x97, 0x7f, 0x61, 0xea, 0x11, 0x23, 0x14, 0x06, 0xcd, 0x10, + 0x95, 0x6d, 0x16, 0x55, 0x78, 0xbb, 0x29, 0xe4, 0x76, 0x96, 0x76, 0x9a, 0x58, + 0x0e, 0x07, 0x01, 0x00, 0x15, 0xaf, 0x3b, 0x50, 0x00, 0x13, 0x58, 0xd0, 0x37, + 0xe5, 0x70, 0xfe, 0x0b, 0x50, 0x0e, 0xe2, 0x99, 0x8c, 0xdf, 0x06, 0x00, 0x03, + 0x7e, 0x28, 0x30, 0x34, 0x34, 0x96, 0x2f, 0x03, 0x92, 0x48, 0x3d, 0xec, 0xad, + 0x2f, 0x9f, 0x4e, 0xbc, 0x99, 0x05, 0x4b, 0xbc, 0xf1, 0x55, 0xff, 0xae, 0x67, + 0x76, 0x34, 0xc3, 0xfb, 0x98, 0x0d, 0xc5, 0xe8, 0xec, 0x67, 0xa4, 0x65, 0x7e, + 0x80, 0xa2, 0x9a, 0x79, 0x6f, 0x39, 0x62, 0xae, 0x0c, 0xb9, 0xc7, 0x86, 0x82, + 0xb3, 0xf4, 0xf9, 0x2e, 0x5a, 0x1e, 0xd1, 0xda, 0x2b, 0xbf, 0xc1, 0x71, 0x07, + 0x7e, 0xef, 0x83, 0x65, 0xbb, 0x38, 0xce, 0x94, 0xca, 0xb0, 0x28, 0x33, 0xce, + 0x47, 0xd4, 0xa0, 0x98, 0x65, 0x72, 0x94, 0xec, 0x10, 0xb2, 0x99, 0x74, 0x22, + 0x22, 0xd0, 0xbf, 0x74, 0x3f, 0x40, 0xc8, 0xea, 0x97, 0x14, 0x32, 0x5c, 0x8a, + 0x37, 0x05, 0x08, 0x24, 0xfa, 0x75, 0x62, 0xd2, 0xc9, 0x25, 0x2c, 0x34, 0xa9, + 0x84, 0x50, 0x27, 0xd6, 0x63, 0x90, 0xe9, 0x56, 0xb2, 0x5e, 0x16, 0x6c, 0x44, + 0x95, 0xd3, 0xde, 0xd3, 0xf7, 0xac, 0xcf, 0x74, 0x76, 0x38, 0x99, 0x47, 0x35, + 0x11, 0x34, 0x12, 0x98, 0xfe, 0xb1, 0x89, 0xb7, 0xed, 0x34, 0xe5, 0x67, 0xd7, + 0x2f, 0x1d, 0xf4, 0xbf, 0x69, 0x7f, 0x71, 0x46, 0x49, 0x3f, 0xa5, 0xc2, 0x36, + 0x91, 0x22, 0x7b, 0x90, 0xb2, 0x51, 0x22, 0xc5, 0x40, 0xdf, 0x0a, 0x6f, 0x2e, + 0xc0, 0x6f, 0x9d, 0x89, 0xa3, 0xf7, 0x71, 0xe9, 0xb8, 0xed, 0x74, 0x79, 0x40, + 0x85, 0x51, 0x06, 0xd5, 0xea, 0x71, 0xba, 0x89, 0xe8, 0xf2, 0x0c, 0xde, 0xa6, + 0x9a, 0x77, 0x8a, 0x59, 0xe4, 0xdf, 0x79, 0x28, 0xc0, 0x35, 0x56, 0x23, 0x31, + 0xc8, 0xe1, 0x62, 0xb8, 0xfd, 0x5e, 0xbb, 0xd5, 0xe2, 0xb3, 0x7b, 0xea, 0x7a, + 0xf0, 0x69, 0x07, 0x10, 0x40, 0xc3, 0x7c, 0x1a, 0x1c, 0x37, 0xf0, 0x76, 0x0f, + 0xed, 0x7d, 0xb7, 0xfa, 0x70, 0xa9, 0x48, 0x94, 0x03, 0x00, 0x45, 0x76, 0xa2, + 0xcc, 0xe9, 0x0a, 0x39, 0x4b, 0x5e, 0xc5, 0x8b, 0x2e, 0x5d, 0x0e, 0x1a, 0xf8, + 0xb0, 0x29, 0x6d, 0x0b, 0xf0, 0x2c, 0x55, 0x97, 0xa4, 0x33, 0x54, 0x14, 0x43, + 0x35, 0xe0, 0x6a, 0x80, 0x1c, 0x6e, 0x7c, 0x73, 0x29, 0x7d, 0xfe, 0x0b, 0x32, + 0xfc, 0xb8, 0x75, 0x33, 0x81, 0x71, 0xdd, 0x1e, 0xeb, 0xeb, 0x12, 0x3f, 0xea, + 0xfa, 0x32, 0xa5, 0xd8, 0xc7, 0xce, 0x58, 0x39, 0x0e, 0xa2, 0xdf, 0x26, 0xc6, + 0x88, 0x88, 0xda, 0xf3, 0x81, 0x6b, 0x7d, 0x02, 0x97, 0xa1, 0x7b, 0x5f, 0x5d, + 0x20, 0x8d, 0xe9, 0x22, 0xe7, 0x73, 0x97, 0x2b, 0x95, 0xe6, 0x96, 0x5e, 0x58, + 0xfb, 0xf6, 0x4f, 0xae, 0x06, 0xf0, 0xc3, 0x89, 0x6e, 0x0b, 0x57, 0x89, 0x0d, + 0xd7, 0xf3, 0xc6, 0x4c, 0x3d, 0x5c, 0xeb, 0xb6, 0xa7, 0x44, 0xc5, 0x93, 0x38, + 0x61, 0x22, 0x71, 0x82, 0x08, 0x04, 0x95, 0xce, 0x9a, 0xc2, 0xe1, 0x73, 0x09, + 0x9c, 0xdc, 0x35, 0x8d, 0xa8, 0x7d, 0xd7, 0x4a, 0x77, 0x34, 0xff, 0xff, 0xc4, + 0x5f, 0xb6, 0xad, 0x1f, 0x38, 0x9c, 0x6a, 0x4d, 0x49, 0x86, 0x62, 0x64, 0x60, + 0x56, 0x08, 0x4d, 0x09, 0xb7, 0x84, 0x88, 0xa3, 0xba, 0x1d, 0x8a, 0x3d, 0x6b, + 0x48, 0x9a, 0xfd, 0xf2, 0x32, 0xd6, 0xd0, 0x70, 0xa1, 0xb5, 0x06, 0x0c, 0xaa, + 0x44, 0x3d, 0x0c, 0x7e, 0xe5, 0x19, 0x04, 0x54, 0x7f, 0xaf, 0x53, 0x95, 0xcb, + 0xd0, 0xba, 0x99, 0x48, 0x0a, 0xd0, 0x4a, 0xe0, 0xe1, 0x91, 0x5b, 0xd7, 0x7f, + 0xa2, 0x6d, 0x04, 0x17, 0x5b, 0x00, 0xfd, 0xc8, 0x1e, 0xf6, 0xf3, 0x79, 0x23, + 0x72, 0x49, 0x27, 0xf0, 0x82, 0x66, 0xb6, 0x86, 0x40, 0x93, 0x13, 0xdc, 0x13, + 0xbc, 0x39, 0x9d, 0x19, 0x77, 0xb8, 0xf6, 0x58, 0x8c, 0x0e, 0x08, 0x72, 0x10, + 0xf0, 0x51, 0xcf, 0x6e, 0x36, 0xe1, 0x4e, 0x32, 0xaa, 0x23, 0xba, 0x6a, 0xe4, + 0x33, 0x1f, 0x22, 0x39, 0xe7, 0x05, 0xf6, 0x79, 0x54, 0x2f, 0xbd, 0x4e, 0xd2, + 0xbf, 0x31, 0x91, 0x24, 0x36, 0x81, 0xf8, 0x27, 0x89, 0x6b, 0x1b, 0xb1, 0xc4, + 0xb7, 0x8b, 0x34, 0xc4, 0x87, 0xa4, 0xed, 0xfa, 0x97, 0xd3, 0x6d, 0x62, 0xee, + 0x32, 0x49, 0xef, 0xe0, 0x94, 0xc3, 0x87, 0x8a, 0xde, 0xdf, 0x9f, 0x2b, 0x17, + 0xd5, 0x11, 0x99, 0x80, 0x4f, 0x42, 0x9c, 0xd7, 0x04, 0xa7, 0xc8, 0x6c, 0x85, + 0x0c, 0xe1, 0x5d, 0x3c, 0x5f, 0x01, 0xd1, 0xad, 0x17, 0xeb, 0xb6, 0xc2, 0x88, + 0x3f, 0x28, 0xe8, 0x15, 0xbc, 0x45, 0x2a, 0x56, 0x07, 0x98, 0x05, 0xa5, 0xdd, + 0x69, 0x00, 0xe5, 0x5f, 0x47, 0x7e, 0xca, 0xc2, 0x14, 0x3f, 0x02, 0xee, 0x98, + 0xc8, 0xd9, 0xb1, 0xb7, 0x03, 0x93, 0xa1, 0x70, 0xba, 0x25, 0x48, 0x06, 0xb4, + 0x08, 0x5b, 0x8d, 0xf9, 0xca, 0x04, 0x07, 0x18, 0x42, 0xa3, 0xaf, 0x93, 0x33, + 0x16, 0x83, 0x0d, 0x53, 0xa7, 0xcb, 0x88, 0xd2, 0xa9, 0x82, 0x3b, 0xcd, 0xfb, + 0xec, 0x8f, 0x18, 0xc8, 0x6a, 0xc3, 0xdf, 0x89, 0x42, 0x38, 0x00, 0x1b, 0xa8, + 0xfa, 0x31, 0x3f, 0x80, 0xcf, 0xe7, 0x5f, 0x7c, 0xb5, 0xd9, 0x73, 0xcc, 0x77, + 0xf3, 0x21, 0xf1, 0x95, 0x2f, 0x30, 0x50, 0x18, 0xc0, 0xbf, 0x23, 0x8b, 0x80, + 0xe3, 0x21, 0x19, 0x90, 0x60, 0x66, 0xf6, 0x4e, 0x64, 0x5e, 0x2b, 0xca, 0xd7, + 0xe4, 0xcd, 0xbe, 0xf0, 0x07, 0xf7, 0xe9, 0xad, 0x8a, 0x31, 0x83, 0x8b, 0x9e, + 0xae, 0xc3, 0x85, 0xe3, 0xf2, 0x5e, 0x16, 0x04, 0xa6, 0xd4, 0x64, 0x99, 0x87, + 0x5a, 0xc1, 0x4a, 0x6c, 0xb3, 0x55, 0xa3, 0xd4, 0x32, 0x91, 0x45, 0x80, 0x3c, + 0x6b, 0xfb, 0x82, 0xe2, 0x9a, 0xb0, 0x29, 0x9f, 0x91, 0x7a, 0x74, 0x02, 0x81, + 0x57, 0x71, 0x7c, 0x08, 0x48, 0x68, 0x63, 0x94, 0x5c, 0x5a, 0x02, 0x36, 0x58, + 0xee, 0xe4, 0xa8, 0xb2, 0x89, 0x56, 0x4c, 0x22, 0xa9, 0x67, 0x1c, 0x56, 0x91, + 0x33, 0x5e, 0xb1, 0x25, 0x89, 0x88, 0x51, 0x67, 0x8f, 0x54, 0x93, 0x45, 0x10, + 0xbf, 0x30, 0x91, 0xc6, 0x02, 0xe1, 0x2a, 0x32, 0x03, 0xa2, 0xf3, 0x2f, 0x34, + 0x7d, 0x4b, 0xdc, 0x9d, 0x44, 0x92, 0x4d, 0xc8, 0x67, 0x5c, 0x9f, 0x24, 0x06, + 0x4d, 0x35, 0xb0, 0x09, 0xb6, 0xdd, 0xbd, 0xb2, 0x37, 0x20, 0x75, 0x33, 0xd5, + 0xbb, 0xad, 0x3b, 0xa1, 0xa3, 0xd6, 0xb0, 0x89, 0x32, 0x9b, 0xe1, 0x47, 0x23, + 0x4e, 0x75, 0x1a, 0x49, 0x27, 0x9d, 0x74, 0xdb, 0x88, 0xdb, 0x5c, 0xa1, 0x02, + 0xd5, 0xe0, 0xe1, 0xaa, 0xc7, 0xcc, 0xf9, 0x66, 0xb0, 0xa8, 0x13, 0x67, 0x09, + 0x5d, 0xa2, 0x1d, 0xc4, 0xb7, 0x36, 0x55, 0x95, 0x30, 0x80, 0xe3, 0x54, 0xbd, + 0x22, 0x09, 0xf2, 0x66, 0x82, 0x10, 0xe9, 0x47, 0x41, 0x27, 0x31, 0x1d, 0x93, + 0x45, 0xce, 0x1e, 0xbd, 0x3a, 0xe5, 0x24, 0x24, 0x5b, 0xbb, 0x44, 0x7a, 0x44, + 0x50, 0x80, 0xb5, 0xfa, 0x23, 0xcd, 0xfe, 0x98, 0xb3, 0xf6, 0xf6, 0x3c, 0x44, + 0xeb, 0xe7, 0x22, 0xb9, 0x7a, 0x79, 0x10, 0xdf, 0x7e, 0xa6, 0x22, 0x5e, 0xd9, + 0xdc, 0xb4, 0x49, 0x84, 0x93, 0xe8, 0xef, 0x55, 0x31, 0xf9, 0xf9, 0x77, 0x31, + 0x84, 0xd7, 0xb4, 0xf5, 0x36, 0x77, 0xb1, 0xd0, 0x44, 0xf6, 0xf1, 0x44, 0x07, + 0xde, 0x5d, 0x67, 0xe0, 0x77, 0xd2, 0x0f, 0x2e, 0x9d, 0x7f, 0xd7, 0x15, 0xbf, + 0x9b, 0x19, 0x9b, 0x93, 0xb9, 0x84, 0x02, 0x46, 0xef, 0x9c, 0x07, 0x35, 0xe4, + 0x88, 0xff, 0x7c, 0x80, 0xb9, 0x41, 0x78, 0xac, 0xa3, 0x1b, 0x13, 0xc3, 0x7c, + 0x9a, 0xeb, 0x7f, 0x62, 0xe2, 0xd8, 0x58, 0x97, 0xea, 0x2e, 0x2a, 0x23, 0x28, + 0xee, 0x03, 0xc9, 0x7f, 0x2f, 0x3f, 0x4d, 0x20, 0xa8, 0xe7, 0x30, 0x24, 0xc5, + 0x50, 0x8e, 0xee, 0xbd, 0x3a, 0x12, 0x67, 0x31, 0xcd, 0xbf, 0x21, 0xfd, 0xad, + 0xb1, 0x4b, 0x4e, 0x59, 0x1c, 0xba, 0xb1, 0x44, 0xbe, 0xc3, 0x5a, 0x72, 0xac, + 0xbf, 0x94, 0x84, 0xf4, 0x7a, 0x10, 0xb9, 0x1e, 0xfc, 0x04, 0x27, 0xfe, 0xcf, + 0x3f, 0xfc, 0xf1, 0x69, 0xd7, 0x00, 0x59, 0xb4, 0x02, 0x79, 0xff, 0xa0, 0x2c, + 0x51, 0x06, 0x74, 0x27, 0xa0, 0xda, 0xea, 0xd6, 0xf9, 0x4b, 0xaf, 0xe4, 0xc1, + 0x23, 0x3a, 0x22, 0x25, 0xeb, 0x56, 0x00, 0x3f, 0xc3, 0x85, 0x42, 0x0d, 0x5a, + 0x9f, 0xf3, 0xd5, 0x91, 0x55, 0x23, 0xa0, 0x8c, 0x87, 0xeb, 0x2e, 0xa6, 0x69, + 0x17, 0x23, 0x3a, 0x73, 0x25, 0xfe, 0x79, 0x3f, 0x41, 0x07, 0x6d, 0x64, 0x25, + 0x5a, 0xbd, 0x15, 0x21, 0x47, 0x66, 0x60, 0xe9, 0x04, 0x91, 0x60, 0x2c, 0x69, + 0xa4, 0xab, 0xb1, 0x38, 0x84, 0x43, 0x10, 0x72, 0xef, 0x96, 0xa0, 0x95, 0xbe, + 0x41, 0x1f, 0xfc, 0xff, 0xb7, 0x86, 0x3f, 0xef, 0x7d, 0xab, 0x4d, 0x4a, 0x72, + 0xa2, 0xd0, 0xbb, 0xd3, 0x6f, 0x9f, 0xdf, 0x0b, 0x35, 0x38, 0xb3, 0x9c, 0xae, + 0x5f, 0xf6, 0x0e, 0x5a, 0xc6, 0xb6, 0x09, 0x70, 0x72, 0x43, 0x14, 0x6e, 0xb5, + 0x36, 0x0a, 0xe7, 0xf9, 0x3f, 0x79, 0x9b, 0x6c, 0x27, 0xe6, 0x5a, 0x0a, 0x06, + 0x39, 0x87, 0x38, 0x66, 0x0f, 0xda, 0xd2, 0xcf, 0xb3, 0x1a, 0xa5, 0x40, 0xd5, + 0xe8, 0x90, 0x06, 0x78, 0xb9, 0xda, 0xb5, 0x24, 0x79, 0xbd, 0x0c, 0xd6, 0xf1, + 0xa5, 0x98, 0x67, 0x3e, 0xed, 0x9c, 0x76, 0xe3, 0x38, 0x10, 0x49, 0x47, 0x18, + 0xd0, 0x5d, 0xdf, 0xdc, 0x00, 0x7a, 0x54, 0xbc, 0xd1, 0xcc, 0x4c, 0x97, 0x40, + 0xf7, 0xe5, 0x3a, 0x31, 0x68, 0x1d, 0x2b, 0x2c, 0x6e, 0xde, 0x79, 0x28, 0x11, + 0x49, 0xea, 0xc3, 0x0f, 0x6e, 0xe5, 0x83, 0x60, 0x5a, 0xc2, 0xff, 0xae, 0xc1, + 0x55, 0x00, 0x35, 0xdc, 0x5a, 0xbb, 0x35, 0x89, 0x44, 0x68, 0xf1, 0x2d, 0x5d, + 0x08, 0xd7, 0x34, 0x36, 0xa8, 0x59, 0xe5, 0x50, 0x7f, 0xdd, 0x1a, 0x46, 0x38, + 0xfb, 0xe6, 0x81, 0xb0, 0xa0, 0xef, 0xfb, 0xbb, 0xf7, 0x4c, 0x99, 0x39, 0x9d, + 0xca, 0x69, 0x02, 0xa0, 0x74, 0xc8, 0x33, 0x35, 0x60, 0x7a, 0x0c, 0x0d, 0xb0, + 0x1c, 0xa3, 0xca, 0x2f, 0xa8, 0x18, 0x57, 0x24, 0x02, 0xe2, 0xfa, 0xef, 0xb3, + 0x07, 0xbe, 0x22, 0xc7, 0xd5, 0x61, 0x1f, 0xf6, 0xfb, 0x5a, 0x31, 0xb4, 0x62, + 0x16, 0x59, 0xd8, 0x4d, 0x8a, 0x7a, 0x1a, 0xdc, 0xa2, 0xfc, 0x4e, 0xb8, 0xb8, + 0x97, 0x04, 0x43, 0x93, 0x27, 0x64, 0x46, 0x31, 0xa7, 0xbb, 0xc1, 0xa8, 0x41, + 0xf3, 0x65, 0x83, 0x0d, 0x27, 0xc8, 0xaa, 0x4d, 0x75, 0xc8, 0x07, 0x87, 0xbd, + 0x10, 0xb7, 0x14, 0xcb, 0x97, 0x9c, 0x1b, 0x0f, 0x3f, 0x0b, 0x41, 0xee, 0x94, + 0x22, 0x94, 0x24, 0x8c, 0x48, 0x5c, 0xf9, 0x9c, 0x6b, 0xc4, 0x63, 0x20, 0x7a, + 0xf3, 0x83, 0x61, 0x97, 0x83, 0x57, 0x41, 0x41, 0x5d, 0xe6, 0x1f, 0xf2, 0x9f, + 0xad, 0x30, 0x01, 0x82, 0x71, 0x4c, 0x20, 0xca, 0x34, 0x04, 0x7b, 0xcc, 0xb7, + 0x05, 0x81, 0x0f, 0xfa, 0xe5, 0x3a, 0x34, 0x16, 0xa5, 0x3f, 0x28, 0xaf, 0xc0, + 0x08, 0xe8, 0xbf, 0xf9, 0x49, 0xe4, 0x3a, 0x54, 0x10, 0xe6, 0xad, 0xb6, 0x65, + 0xf9, 0x9f, 0xa4, 0xca, 0xfa, 0xc2, 0xe0, 0xf2, 0xc0, 0xf1, 0x34, 0xbd, 0xba, + 0x83, 0x81, 0xc2, 0xbb, 0xac, 0x43, 0x33, 0x2a, 0xcd, 0xcb, 0x10, 0x08, 0x2e, + 0xf3, 0x43, 0xa3, 0x5a, 0xc6, 0x4f, 0x4b, 0xa1, 0x6e, 0x49, 0x57, 0xc7, 0x1e, + 0x9a, 0x2b, 0xd9, 0xa5, 0xcd, 0x6a, 0x92, 0x25, 0x8a, 0x9e, 0x58, 0x8e, 0x02, + 0x1a, 0x06, 0x65, 0x09, 0x04, 0x67, 0x0d, 0xa2, 0xc0, 0xe5, 0x2c, 0x52, 0x4f, + 0x6e, 0x5c, 0xe3, 0xee, 0x27, 0x5a, 0x0a, 0x63, 0x10, 0x3b, 0x5f, 0x92, 0x64, + 0x16, 0xc0, 0xbd, 0x5d, 0xa1, 0xae, 0x65, 0x69, 0xd3, 0xa4, 0xee, 0x4d, 0xbc, + 0x5e, 0xc0, 0x8b, 0x29, 0x72, 0x02, 0xc9, 0xd7, 0x13, 0xab, 0xc3, 0x47, 0x4d, + 0xe4, 0x94, 0x0f, 0x59, 0xb1, 0xf3, 0xfe, 0x0e, 0x92, 0x76, 0xa1, 0x76, 0x3b, + 0x2d, 0xea, 0x39, 0x40, 0xb0, 0xc1, 0xf7, 0xab, 0x5d, 0xa3, 0xf4, 0x55, 0x62, + 0x3e, 0x04, 0x96, 0x82, 0xd0, 0x92, 0x18, 0x9c, 0xb7, 0x9e, 0xcf, 0xd4, 0x3c, + 0x3b, 0xf1, 0x0e, 0x7f, 0x2c, 0x8d, 0x4d, 0xe3, 0xa7, 0x36, 0xf8, 0x69, 0xf0, + 0x87, 0x03, 0xc4, 0xe5, 0x9f, 0x57, 0x4f, 0x77, 0xaa, 0x86, 0x1c, 0xbf, 0xdd, + 0xd0, 0x7f, 0x77, 0xdc, 0x24, 0xa9, 0x74, 0x10, 0xaf, 0xc7, 0xcf, 0xbe, 0x3c, + 0xe1, 0xff, 0xd2, 0x24, 0x53, 0x5c, 0xf3, 0x05, 0xce, 0xcc, 0x78, 0x56, 0xa4, + 0xd4, 0x8a, 0x6d, 0xec, 0x17, 0xa2, 0x4b, 0x6d, 0x27, 0xfe, 0x26, 0x64, 0xbc, + 0x2b, 0x2b, 0x71, 0x1d, 0x67, 0x13, 0x90, 0x6c, 0xed, 0x8a, 0x80, 0x66, 0x62, + 0x18, 0x40, 0xd9, 0x0c, 0x23, 0xae, 0x33, 0x77, 0x30, 0x67, 0x9d, 0x2c, 0xde, + 0x32, 0x69, 0xab, 0x1f, 0x42, 0xac, 0x03, 0xff, 0xdb, 0xa0, 0x32, 0xd3, 0x2c, + 0xa8, 0x79, 0x63, 0x82, 0x56, 0x56, 0x5d, 0xe1, 0xd2, 0xde, 0x39, 0xf5, 0x6f, + 0x94, 0x57, 0x95, 0xd6, 0xe9, 0x58, 0xe6, 0x93, 0xdc, 0x8c, 0xbf, 0x6d, 0x04, + 0x30, 0x00, 0xcc, 0x7a, 0x40, 0x15, 0xf0, 0x2d, 0x0f, 0xe3, 0x97, 0xec, 0x57, + 0xf8, 0xfe, 0x29, 0x2e, 0x85, 0x14, 0x24, 0xe8, 0x40, 0x6d, 0x38, 0xdd, 0xb8, + 0xd1, 0xde, 0x9d, 0xef, 0x67, 0x2e, 0x92, 0x7d, 0x3d, 0xc1, 0xf4, 0x11, 0xdc, + 0x78, 0xad, 0xa7, 0x61, 0x00, 0x91, 0xbf, 0xe2, 0x63, 0xcd, 0x79, 0x96, 0xd1, + 0x80, 0x5e, 0xe4, 0x91, 0xe9, 0x95, 0x91, 0xd6, 0xef, 0xdb, 0x2e, 0x3c, 0x79, + 0x71, 0x57, 0x41, 0xd0, 0xd4, 0x72, 0xac, 0x11, 0xdb, 0x78, 0x64, 0x4f, 0x3d, + 0x23, 0xe5, 0x8f, 0x0b, 0x01, 0xa8, 0x61, 0xe0, 0x85, 0x65, 0x53, 0x52, 0x07, + 0xcd, 0x5e, 0x71, 0x0f, 0xc3, 0x3e, 0xb2, 0xf8, 0x92, 0x8b, 0xc7, 0xd4, 0x01, + 0x7e, 0x4e, 0x56, 0xc0, 0xc2, 0xeb, 0x95, 0x85, 0xd6, 0x99, 0x74, 0x5e, 0x3b, + 0xb9, 0x61, 0x8b, 0x2c, 0x1b, 0x90, 0xf2, 0x35, 0x1b, 0xaf, 0x27, 0x6a, 0x70, + 0x17, 0xb0, 0xfc, 0xfa, 0xcb, 0x52, 0xea, 0x27, 0x31, 0x95, 0xa8, 0xde, 0xe1, + 0x67, 0x79, 0x13, 0xc7, 0x86, 0xcc, 0x3a, 0xcb, 0x06, 0xa9, 0xec, 0x7a, 0x37, + 0xb0, 0x58, 0x98, 0x0c, 0xeb, 0x3c, 0x82, 0xaa, 0xb0, 0x3e, 0xaf, 0xc1, 0xbb, + 0x88, 0xcf, 0x7a, 0xb7, 0x98, 0xf1, 0x65, 0x1d, 0x67, 0xbf, 0x22, 0x30, 0xd5, + 0x34, 0xec, 0x55, 0x23, 0x1d, 0x21, 0x31, 0x7b, 0x1c, 0xb3, 0x0b, 0x3c, 0x38, + 0xff, 0x8d, 0x21, 0x1b, 0x76, 0x36, 0x70, 0x2a, 0x25, 0xca, 0x7c, 0xa1, 0xbf, + 0xf1, 0xf2, 0xc1, 0x58, 0xc6, 0xef, 0x22, 0x13, 0xff, 0xab, 0xb9, 0xc0, 0x9f, + 0x5c, 0x47, 0xe7, 0x3b, 0xbe, 0xbb, 0xd3, 0x7f, 0x3d, 0x3e, 0xbc, 0x24, 0xa6, + 0x65, 0xb2, 0x9f, 0x10, 0xde, 0x8b, 0x9c, 0xf1, 0x94, 0x2d, 0x90, 0xb4, 0xc3, + 0x1d, 0x89, 0xa9, 0x88, 0x3b, 0xf5, 0xa0, 0x27, 0xe9, 0x20, 0xd1, 0xb8, 0x51, + 0x19, 0xf2, 0xf2, 0xf9, 0x5f, 0xd5, 0x5e, 0xda, 0x85, 0x75, 0xa4, 0xdb, 0x62, + 0x69, 0x05, 0x68, 0x1c, 0x29, 0xe8, 0xd8, 0xe7, 0x41, 0xd4, 0x20, 0xa8, 0x34, + 0x42, 0xa9, 0xd3, 0x8a, 0xf4, 0x19, 0x9e, 0xf9, 0x5c, 0xb3, 0x0b, 0xc4, 0x4e, + 0x93, 0xfe, 0x4d, 0x0e, 0xb7, 0x42, 0x22, 0xfc, 0x10, 0xac, 0x8d, 0x40, 0x0e, + 0x10, 0xed, 0x4e, 0x56, 0xfa, 0x39, 0xda, 0x01, 0x2a, 0xc1, 0x8d, 0xee, 0x4d, + 0x99, 0x42, 0x5c, 0x8f, 0x71, 0x4c, 0x51, 0xac, 0x1b, 0xa5, 0x6e, 0x0e, 0x81, + 0x47, 0x4b, 0xad, 0x3e, 0x74, 0x18, 0xed, 0x4c, 0x82, 0xb4, 0xd7, 0x75, 0x12, + 0x0b, 0x19, 0x3e, 0xdc, 0x66, 0x76, 0x30, 0x32, 0x66, 0xe3, 0x1e, 0xcf, 0x55, + 0x1e, 0xb9, 0x13, 0xa6, 0x41, 0x15, 0xbc, 0xcb, 0xbb, 0x2e, 0xcc, 0x89, 0x81, + 0x55, 0x21, 0xe5, 0x6e, 0x07, 0xc8, 0x8b, 0xbb, 0x4a, 0x55, 0xe9, 0x94, 0x5d, + 0x03, 0xdb, 0x2d, 0xa0, 0xfc, 0xae, 0x3c, 0x08, 0xf1, 0xd7, 0x7c, 0x57, 0x26, + 0x1e, 0x98, 0x23, 0x66, 0x03, 0xa8, 0xc5, 0x2c, 0x6c, 0x27, 0x98, 0xb5, 0x45, + 0x61, 0xaf, 0xfe, 0x07, 0x61, 0xe6, 0xab, 0x24, 0x72, 0x07, 0xad, 0xfc, 0x3c, + 0x43, 0x22, 0xbe, 0x0f, 0xb2, 0x49, 0xbf, 0xd3, 0xc5, 0xe7, 0xfb, 0x38, 0x37, + 0xe9, 0xff, 0x21, 0x35, 0x07, 0x3a, 0xe1, 0x36, 0x0d, 0xcf, 0xaf, 0x5f, 0xb6, + 0x78, 0x56, 0x8f, 0xd8, 0x4d, 0x99, 0xa5, 0x1f, 0x32, 0xeb, 0x94, 0xcc, 0xf5, + 0xf2, 0x39, 0x02, 0x5b, 0x2b, 0x97, 0xbe, 0xf6, 0x25, 0xdb, 0xb6, 0x7f, 0x20, + 0xc3, 0xe0, 0xd9, 0x51, 0x73, 0x12, 0x9c, 0x06, 0x37, 0x50, 0x39, 0x52, 0x13, + 0x41, 0x49, 0x24, 0xe0, 0xa3, 0xfd, 0xd3, 0x66, 0xff, 0xd4, 0x69, 0xc9, 0xeb, + 0xea, 0x79, 0xfb, 0x76, 0xaf, 0x10, 0xea, 0x45, 0xb5, 0x66, 0xf1, 0xfc, 0x92, + 0xaf, 0x48, 0xce, 0xe2, 0x11, 0xf8, 0xe1, 0xb0, 0x58, 0xfb, 0x72, 0x1a, 0x8b, + 0x22, 0xce, 0x43, 0x0c, 0x54, 0x94, 0x0e, 0x24, 0xb3, 0x30, 0x8e, 0x57, 0x0a, + 0xb8, 0x57, 0x25, 0x0d, 0x10, 0xcd, 0xec, 0xe1, 0x05, 0x07, 0x1b, 0xc8, 0x66, + 0xea, 0x4d, 0x6d, 0x5c, 0x69, 0xf9, 0x59, 0x28, 0xf3, 0x9f, 0x7f, 0x1f, 0xcd, + 0xf1, 0x5a, 0xcd, 0xbb, 0xec, 0x67, 0xd8, 0x48, 0xf7, 0xc1, 0xb2, 0xef, 0x57, + 0x7f, 0x48, 0xa7, 0x0b, 0x4b, 0xf3, 0xd8, 0xa7, 0x88, 0x14, 0x31, 0x6b, 0x3d, + 0x7f, 0xa3, 0xe3, 0xc9, 0x8c, 0xdf, 0xa1, 0x78, 0xb9, 0x89, 0xbc, 0x78, 0xde, + 0x8d, 0x24, 0xc1, 0xbb, 0xc0, 0x9d, 0x20, 0x7e, 0x11, 0x18, 0x1e, 0x59, 0x1a, + 0x60, 0x9a, 0xbf, 0xf9, 0xa2, 0x00, 0xd3, 0x4e, 0x1a, 0xc6, 0x3a, 0x38, 0xf0, + 0x40, 0x05, 0x3a, 0x32, 0x01, 0x68, 0xb8, 0x23, 0xac, 0x76, 0x6e, 0x02, 0x6c, + 0xbe, 0x1a, 0xbf, 0x27, 0x55, 0xbe, 0x0c, 0x73, 0xc8, 0xfd, 0x98, 0x62, 0x55, + 0x56, 0x40, 0x6c, 0x14, 0x99, 0x3f, 0x6a, 0x28, 0xae, 0x4b, 0xb3, 0xa4, 0x73, + 0xa1, 0x8d, 0xd3, 0x74, 0x3d, 0x88, 0x7e, 0xac, 0x54, 0x8e, 0xb7, 0xca, 0x4d, + 0x46, 0x15, 0x7c, 0x62, 0xb7, 0x29, 0xf3, 0x66, 0xa9, 0x56, 0x02, 0x28, 0x7c, + 0x8c, 0x56, 0x33, 0x5b, 0x78, 0xbc, 0x68, 0x9f, 0xc5, 0x38, 0x9c, 0x39, 0x79, + 0xb8, 0xe7, 0x5d, 0xaf, 0x31, 0xbd, 0x60, 0xa9, 0xcc, 0x2a, 0x92, 0x0d, 0xbc, + 0xc6, 0x71, 0xdd, 0xe2, 0x7e, 0xb4, 0x60, 0x0f, 0x12, 0xdc, 0x2a, 0xb3, 0x94, + 0x4a, 0xa1, 0x9c, 0x71, 0xa9, 0x87, 0xd8, 0x71, 0x3d, 0x99, 0xa4, 0xba, 0x9b, + 0x9a, 0x19, 0xa9, 0x21, 0x60, 0x6c, 0x56, 0x20, 0xc1, 0x67, 0xd4, 0xc7, 0xf4, + 0xa2, 0x8a, 0x46, 0x4a, 0x9d, 0x16, 0xc4, 0xb0, 0xd7, 0x4e, 0x0e, 0x75, 0xdf, + 0x6d, 0xba, 0x0e, 0x1d, 0xfe, 0x60, 0x1c, 0x04, 0xc8, 0xeb, 0x37, 0x01, 0x0e, + 0x13, 0x92, 0x1d, 0x5b, 0x6c, 0x93, 0xb9, 0xf0, 0xc3, 0xdd, 0xd3, 0x2f, 0x7b, + 0xec, 0xb2, 0xd7, 0x7d, 0x79, 0xa1, 0x61, 0x8a, 0x79, 0xf7, 0x3c, 0x45, 0x9b, + 0x0d, 0xf5, 0x29, 0x7f, 0x8e, 0xab, 0xd6, 0xed, 0x06, 0xfd, 0x23, 0x40, 0xe8, + 0x60, 0x0a, 0x95, 0xd7, 0x2c, 0xef, 0xd1, 0x2e, 0x62, 0x2c, 0x57, 0xb4, 0x57, + 0xa4, 0xe8, 0x39, 0x75, 0x93, 0x74, 0x6a, 0x6b, 0xcf, 0x04, 0xc4, 0x9c, 0x6d, + 0xd4, 0xa3, 0x36, 0x68, 0xda, 0x53, 0x8d, 0x90, 0x93, 0xa4, 0x50, 0xa4, 0xd8, + 0x24, 0x51, 0xb6, 0x12, 0xff, 0x54, 0x70, 0x73, 0x8e, 0x62, 0xbf, 0xdf, 0xc7, + 0x9b, 0x3e, 0x31, 0xbb, 0x47, 0xfc, 0xa1, 0xe9, 0x87, 0x22, 0xa5, 0x98, 0x3a, + 0xff, 0xe5, 0xf6, 0x32, 0x84, 0x0b, 0x92, 0x3a, 0xb5, 0x6b, 0x1d, 0xa1, 0x53, + 0xd3, 0x5d, 0x82, 0x23, 0x24, 0xe7, 0xd5, 0x6d, 0x61, 0x3c, 0x73, 0xeb, 0xc6, + 0x34, 0x1e, 0xa0, 0x3b, 0xee, 0x3a, 0xb9, 0x73, 0xe8, 0x4d, 0x8f, 0xfc, 0x4a, + 0x7c, 0x58, 0x13, 0x83, 0xe2, 0x14, 0x2d, 0x29, 0x2a, 0x58, 0x0b, 0x6d, 0x30, + 0x83, 0x43, 0xdc, 0xf1, 0xef, 0x49, 0x29, 0xa9, 0xe3, 0xe6, 0x15, 0x32, 0xfc, + 0xff, 0xb7, 0x4d, 0x30, 0x19, 0xf4, 0xe2, 0xd6, 0xd3, 0x11, 0x78, 0x57, 0x5a, + 0xca, 0x94, 0x12, 0x99, 0x22, 0x50, 0x44, 0xe1, 0xd3, 0x7b, 0xab, 0x9f, 0x10, + 0xe2, 0x9f, 0xd9, 0x6f, 0x9c, 0xf6, 0x84, 0xaf, 0x98, 0xed, 0x64, 0x8b, 0x83, + 0xd6, 0x1e, 0x52, 0x5b, 0xe3, 0x2c, 0xdb, 0x45, 0x3d, 0x2d, 0x38, 0x93, 0x5f, + 0xee, 0xb3, 0x22, 0xce, 0xb9, 0xd2, 0xa2, 0xe9, 0x5e, 0xb7, 0xfc, 0x61, 0x2d, + 0x89, 0xf4, 0xcf, 0xe8, 0x93, 0x22, 0x8e, 0x88, 0x28, 0xb1, 0x89, 0x00, 0x90, + 0x45, 0x62, 0x90, 0x75, 0xc0, 0xc2, 0x03, 0x9d, 0x5a, 0x73, 0x32, 0xfd, 0xbc, + 0xd7, 0xc7, 0xb0, 0x91, 0x01, 0x5c, 0x45, 0x69, 0xa3, 0x00, 0x53, 0x23, 0x56, + 0xbb, 0xad, 0x08, 0xff, 0xa3, 0xbb, 0x16, 0x7a, 0x3e, 0xbe, 0xb4, 0x62, 0x66, + 0xb7, 0x06, 0x06, 0x49, 0x4a, 0xda, 0xe9, 0x14, 0x9e, 0x1a, 0x64, 0xc0, 0xa0, + 0xaa, 0x5d, 0xaa, 0x53, 0x62, 0xd3, 0xc7, 0xa8, 0x96, 0xfd, 0x52, 0x78, 0x08, + 0xd0, 0xa3, 0xc1, 0xcf, 0x70, 0x61, 0xba, 0x67, 0x89, 0x39, 0x80, 0x78, 0x85, + 0x0b, 0xe4, 0xb9, 0x94, 0x0e, 0x01, 0xae, 0xbb, 0x93, 0x6d, 0xd8, 0x1a, 0x31, + 0x82, 0x04, 0x28, 0x1d, 0x43, 0x97, 0x6f, 0x4e, 0x0f, 0xa2, 0x07, 0xe4, 0xbe, + 0x1f, 0xb8, 0x2c, 0x91, 0xbb, 0x26, 0x42, 0xf7, 0x36, 0x85, 0x6d, 0xcd, 0x5a, + 0xeb, 0x75, 0xc5, 0x0a, 0xf2, 0x00, 0xe1, 0x4b, 0xe5, 0xb7, 0x8c, 0xe6, 0x9a, + 0x88, 0x51, 0x54, 0xef, 0xe3, 0x0e, 0xdd, 0x09, 0xae, 0x8c, 0x5e, 0xb5, 0x3f, + 0x4b, 0x8b, 0x7c, 0x75, 0x35, 0x37, 0x3c, 0x0f, 0xe6, 0xcf, 0xe4, 0x48, 0xa9, + 0xb9, 0xf4, 0xd9, 0xe3, 0x10, 0x93, 0x03, 0xd6, 0xce, 0xe9, 0x10, 0x6a, 0xa2, + 0x2b, 0xd5, 0x9a, 0xe0, 0xe0, 0x27, 0xd3, 0x25, 0x6a, 0x75, 0xb9, 0xc5, 0xd6, + 0x07, 0x09, 0x09, 0x97, 0x53, 0xce, 0x57, 0x2c, 0x9e, 0x29, 0xdc, 0x92, 0x56, + 0x2d, 0x1c, 0x3f, 0x4a, 0x0b, 0x4d, 0x36, 0xa6, 0xfe, 0xc2, 0x1b, 0xa4, 0x94, + 0x17, 0x3e, 0x44, 0xd7, 0x9b, 0xc2, 0x34, 0x18, 0x95, 0xbd, 0x0c, 0x70, 0x96, + 0xf0, 0x97, 0x4f, 0x12, 0x67, 0xfe, 0xf6, 0x72, 0x1d, 0x58, 0xb8, 0xc4, 0xe3, + 0x34, 0xf1, 0x4d, 0x86, 0xc0, 0xee, 0x3b, 0x1a, 0xb5, 0x88, 0x0c, 0xa4, 0x29, + 0x8d, 0x7f, 0x84, 0x76, 0x3b, 0xdc, 0x71, 0x09, 0xbc, 0x82, 0x0f, 0x45, 0xc5, + 0x04, 0x53, 0xe3, 0x3d, 0x96, 0x8e, 0xf9, 0xd8, 0x6c, 0xd6, 0xeb, 0xe7, 0x15, + 0xe8, 0x9d, 0x5d, 0xe3, 0x24, 0x09, 0x10, 0xc5, 0x9c, 0x36, 0xec, 0x8f, 0xe9, + 0x9b, 0x32, 0x49, 0x16, 0x30, 0xab, 0x35, 0xb1, 0x24, 0x53, 0x1d, 0x9c, 0x29, + 0xe0, 0x46, 0xc4, 0x78, 0xe6, 0x2a, 0xd1, 0x8b, 0x25, 0x39, 0xa5, 0x09, 0x6e, + 0xe2, 0x9a, 0x4d, 0x4b, 0x4b, 0x53, 0xa1, 0xcf, 0xfa, 0x93, 0x23, 0xbc, 0x73, + 0x21, 0x81, 0x7d, 0x96, 0xfd, 0x02, 0x05, 0xea, 0x9c, 0xbc, 0x4e, 0x15, 0x88, + 0xb7, 0x61, 0x3d, 0x4c, 0x39, 0x3c, 0xac, 0x21, 0x05, 0xb2, 0x8f, 0xd0, 0x46, + 0x7a, 0x0b, 0xf0, 0x23, 0xf0, 0x0d, 0x1a, 0x17, 0xf6, 0x53, 0xcd, 0xb6, 0xb5, + 0xa8, 0x3e, 0x4c, 0xf1, 0x5c, 0x34, 0x7b, 0x34, 0xb9, 0x7f, 0xbf, 0xe6, 0xea, + 0xee, 0x13, 0xbb, 0x90, 0x15, 0x3a, 0xfd, 0xc9, 0x11, 0x26, 0x37, 0xfa, 0xd1, + 0xcf, 0xe1, 0x7e, 0xdd, 0xcb, 0x0c, 0x81, 0x9e, 0x60, 0xd3, 0x50, 0x39, 0x34, + 0x9b, 0x69, 0xf7, 0xca, 0x9b, 0xa6, 0x4d, 0xf9, 0xf5, 0xe4, 0x71, 0x11, 0x5c, + 0xd6, 0x79, 0x26, 0xbd, 0xf1, 0x6e, 0x30, 0x12, 0x39, 0x8d, 0xae, 0x59, 0x5b, + 0xfd, 0x25, 0xf3, 0xae, 0xe5, 0x8a, 0xcf, 0xfe, 0x2f, 0x3e, 0xd7, 0x48, 0xfd, + 0xf9, 0x3a, 0x6e, 0xd2, 0x1e, 0x87, 0x2d, 0x94, 0x97, 0xa9, 0xf3, 0xb7, 0xb1, + 0x6b, 0x7e, 0xa9, 0xea, 0x19, 0xf2, 0x47, 0x9e, 0x4f, 0x8b, 0x6d, 0x42, 0x3f, + 0xa1, 0x5f, 0xbc, 0xdf, 0xa3, 0xc9, 0x9b, 0x9a, 0x39, 0x70, 0xee, 0x74, 0xa8, + 0xd8, 0x5e, 0xc2, 0x15, 0x96, 0x52, 0xda, 0xa7, 0x67, 0x03, 0x12, 0x63, 0xbb, + 0x4b, 0x49, 0x28, 0x5d, 0x70, 0x5e, 0x24, 0xe8, 0x19, 0x26, 0x86, 0xeb, 0xc8, + 0xff, 0x85, 0x98, 0xd2, 0x4b, 0x51, 0x23, 0x2a, 0x99, 0x38, 0x56, 0x5d, 0x0f, + 0x68, 0xbe, 0x7f, 0x3a, 0x53, 0x36, 0x4a, 0xcc, 0x69, 0x21, 0xa3, 0x5b, 0xc5, + 0x99, 0x10, 0xbb, 0x71, 0xfb, 0x58, 0xb8, 0x67, 0x37, 0x3c, 0xe9, 0x5f, 0x19, + 0x84, 0x09, 0xaa, 0xef, 0x97, 0xf4, 0x01, 0xe4, 0x33, 0x00, 0x4b, 0x99, 0x19, + 0x04, 0x9f, 0x93, 0x7f, 0xd7, 0x76, 0xc4, 0xb6, 0x31, 0xa5, 0x91, 0x2a, 0x08, + 0xd4, 0x9f, 0xdf, 0x65, 0x28, 0xf8, 0x1a, 0x6f, 0x32, 0x00, 0x09, 0x37, 0x67, + 0xbb, 0x77, 0x89, 0xd9, 0x5a, 0x75, 0x03, 0x0a, 0xc1, 0xd2, 0x4c, 0x2c, 0x75, + 0xbd, 0x60, 0x38, 0x25, 0x52, 0x86, 0x3f, 0x09, 0x8d, 0x36, 0xbd, 0x48, 0x33, + 0x28, 0x3d, 0x3a, 0x2d, 0x21, 0x5d, 0x10, 0xc7, 0xff, 0xe9, 0xc8, 0x40, 0x37, + 0x23, 0x14, 0x45, 0x58, 0x33, 0x29, 0x26, 0x16, 0x74, 0x19, 0x3b, 0xdd, 0x1c, + 0x64, 0x81, 0xbe, 0xf9, 0xf2, 0x26, 0xe1, 0xe6, 0x0b, 0xb1, 0xc7, 0x76, 0xa4, + 0xbe, 0x7d, 0xc6, 0x9b, 0x44, 0x30, 0xa7, 0x5a, 0x0c, 0xbd, 0x55, 0x86, 0x7a, + 0x6f, 0x46, 0xff, 0x93, 0x03, 0xf9, 0xa2, 0x9b, 0x6f, 0x3f, 0x7c, 0x7a, 0x9c, + 0x9f, 0xbc, 0xf7, 0x47, 0xb2, 0x3f, 0x86, 0x45, 0xf4, 0xda, 0x3d, 0x9f, 0x72, + 0xd0, 0xd8, 0x76, 0xa7, 0x5e, 0x54, 0x8a, 0x49, 0xdb, 0x37, 0x5b, 0x40, 0xeb, + 0xe1, 0xbb, 0xe0, 0x81, 0x7a, 0x99, 0x49, 0xde, 0xc1, 0x15, 0x7d, 0x62, 0xa7, + 0x1d, 0xbf, 0xbd, 0x9b, 0xb1, 0xd6, 0x55, 0x17, 0x53, 0xdf, 0xf5, 0xbb, 0x7f, + 0xc9, 0x36, 0x48, 0xd4, 0xeb, 0x6c, 0xad, 0x41, 0x67, 0x33, 0xad, 0xfd, 0xcc, + 0x87, 0x08, 0xdd, 0xe8, 0xbe, 0x87, 0x34, 0xd0, 0x5d, 0xec, 0x9e, 0x45, 0xdf, + 0x3f, 0xa4, 0x5a, 0xda, 0xc4, 0x1a, 0x6d, 0x23, 0xa2, 0x24, 0xa0, 0x4f, 0xdc, + 0x0d, 0x96, 0x73, 0x87, 0x98, 0x0f, 0x95, 0xe6, 0x27, 0xe6, 0xb3, 0xdc, 0xe1, + 0x9c, 0xaf, 0x01, 0x09, 0x84, 0x8c, 0xa9, 0xda, 0xea, 0x2e, 0x24, 0x6e, 0x62, + 0xc2, 0x85, 0x07, 0xd2, 0x56, 0xeb, 0xab, 0xe1, 0x18, 0xf1, 0xf6, 0xef, 0x97, + 0x6e, 0x4a, 0x31, 0xa0, 0xe4, 0x14, 0x3c, 0x43, 0x60, 0xd8, 0xb1, 0x79, 0xb3, + 0x0e, 0x4b, 0xfa, 0x7e, 0x16, 0x1b, 0x1e, 0x6c, 0x70, 0x7d, 0x8e, 0xae, 0x76, + 0x28, 0x71, 0x59, 0x21, 0x94, 0x1e, 0x78, 0x54, 0xe1, 0x0d, 0x11, 0x99, 0x12, + 0x58, 0xc4, 0x3f, 0xe6, 0xc4, 0x45, 0x29, 0xf6, 0x61, 0x4b, 0x58, 0x41, 0x61, + 0x5d, 0x3e, 0x4e, 0x77, 0xfb, 0x09, 0xa6, 0xf0, 0x20, 0xe0, 0xb8, 0x32, 0x28, + 0xac, 0x17, 0x55, 0xad, 0x47, 0x71, 0x16, 0xde, 0xca, 0xac, 0x51, 0x7b, 0xfb, + 0xcf, 0x67, 0x37, 0xf5, 0xbb, 0x99, 0xe0, 0x07, 0xeb, 0x64, 0x00, 0x76, 0x6b, + 0x6c, 0xfd, 0xd7, 0x37, 0xe2, 0x08, 0x57, 0xdf, 0x3c, 0x85, 0xca, 0x16, 0xab, + 0x21, 0x17, 0x7b, 0x53, 0x1e, 0x55, 0x32, 0xc4, 0x45, 0xde, 0xd0, 0x0c, 0x1e, + 0x96, 0x63, 0x5e, 0x9f, 0x50, 0x0b, 0xa8, 0x76, 0x44, 0xb8, 0xc1, 0xd5, 0x33, + 0x25, 0x37, 0xab, 0xf2, 0x9f, 0xcc, 0xab, 0x8a, 0xe3, 0xe3, 0x88, 0x27, 0x18, + 0x82, 0x6b, 0xdb, 0x8d, 0xbd, 0xb8, 0x51, 0xa4, 0x77, 0x05, 0xeb, 0x0d, 0xec, + 0x2d, 0x5e, 0xe9, 0x39, 0xdc, 0x79, 0x87, 0x25, 0x6f, 0xee, 0xe6, 0x7f, 0x09, + 0x90, 0x28, 0xf1, 0x45, 0xe2, 0x0b, 0xf4, 0x88, 0x94, 0x98, 0x24, 0x30, 0x14, + 0x35, 0x13, 0x73, 0xfd, 0xf6, 0x33, 0x01, 0x8d, 0x21, 0x7c, 0x58, 0x8c, 0x52, + 0x98, 0x6f, 0xc5, 0x24, 0xe7, 0x97, 0x97, 0xab, 0x65, 0x58, 0x43, 0xc2, 0x61, + 0xae, 0x7f, 0xc9, 0xcc, 0x3f, 0x47, 0x05, 0x46, 0x00, 0xe4, 0xcd, 0x38, 0x5c, + 0x46, 0x7a, 0x78, 0x8a, 0x9f, 0xff, 0xc3, 0x7e, 0x9d, 0xdb, 0xb5, 0xd3, 0xe8, + 0xa4, 0xbd, 0x0c, 0x4e, 0x8f, 0x56, 0xe5, 0x69, 0x5a, 0xfa, 0x90, 0xfe, 0x50, + 0xce, 0x0a, 0x30, 0x04, 0xfe, 0xd7, 0x12, 0xb4, 0xde, 0x15, 0xad, 0x5f, 0x01, + 0x71, 0xad, 0x51, 0xed, 0xfa, 0x54, 0xdb, 0xd4, 0x8b, 0x1f, 0xcc, 0x5e, 0xf6, + 0xac, 0x73, 0xcf, 0x0a, 0x28, 0xe9, 0xd9, 0x3e, 0x0c, 0xaf, 0xad, 0x88, 0x16, + 0x76, 0x1b, 0x3b, 0xe6, 0x38, 0x39, 0x8c, 0x00, 0x14, 0x33, 0x38, 0xea, 0x27, + 0xa9, 0xff, 0xf2, 0x2e, 0xc4, 0x73, 0x16, 0x36, 0x96, 0x12, 0x25, 0xca, 0x49, + 0xe0, 0x13, 0xa6, 0xdc, 0x80, 0x2b, 0xc7, 0xfb, 0x77, 0xca, 0xd1, 0x0a, 0xca, + 0xfe, 0xfc, 0xe5, 0xfa, 0x9a, 0x37, 0x35, 0x63, 0xb3, 0x91, 0x7a, 0x3a, 0x37, + 0x39, 0xcc, 0x97, 0x80, 0xea, 0x81, 0x50, 0x73, 0xde, 0x8e, 0xb4, 0x2e, 0x3f, + 0x66, 0x93, 0xe8, 0x52, 0xbe, 0xfd, 0xde, 0xdd, 0x61, 0x91, 0x29, 0xd0, 0xaa, + 0x13, 0xc4, 0xbd, 0x83, 0x86, 0x22, 0xb5, 0xe3, 0x28, 0x56, 0x35, 0x8e, 0x6d, + 0x82, 0x78, 0x78, 0x95, 0x7e, 0x5d, 0xc8, 0x2c, 0xd4, 0x37, 0x0b, 0x66, 0x10, + 0x84, 0x9e, 0x95, 0x6d, 0x0a, 0x7c, 0xdf, 0xf5, 0x61, 0x8f, 0x5c, 0x2c, 0xea, + 0x61, 0x23, 0x0b, 0x47, 0x00, 0x1c, 0x30, 0xe5, 0xa8, 0xf9, 0x37, 0xca, 0x7f, + 0x9f, 0x9e, 0x66, 0x0f, 0xfa, 0xa7, 0x71, 0x80, 0xcb, 0xa2, 0x6f, 0x90, 0xda, + 0x00, 0x7c, 0xda, 0x40, 0x57, 0xa6, 0xce, 0xa2, 0xe2, 0x6b, 0xfd, 0xe5, 0x0c, + 0x7f, 0x90, 0x79, 0x88, 0x00, 0x53, 0xd0, 0x5d, 0xaa, 0xaa, 0xb3, 0xd7, 0xe4, + 0xdc, 0x9d, 0x81, 0xd0, 0x99, 0x0d, 0x2b, 0xc3, 0x69, 0xa6, 0x6b, 0x55, 0xac, + 0x8b, 0x63, 0x97, 0xbd, 0x47, 0xdb, 0x42, 0x89, 0xc5, 0x45, 0x22, 0x85, 0x55, + 0x1a, 0xaa, 0x7f, 0xa6, 0x7b, 0x01, 0x36, 0xcd, 0x11, 0x9f, 0x87, 0xd8, 0x21, + 0x9e, 0x00, 0x02, 0x97, 0xf0, 0x2c, 0x0c, 0xe6, 0xe3, 0x7b, 0x62, 0x0f, 0x5e, + 0x47, 0xfc, 0xa0, 0x3a, 0xcd, 0xd6, 0x54, 0x4a, 0x47, 0xf4, 0xde, 0xef, 0x19, + 0x4f, 0x95, 0x9a, 0xdc, 0x36, 0x8b, 0x3b, 0x5d, 0x27, 0xd3, 0x83, 0xfe, 0x2f, + 0x2b, 0x52, 0x5d, 0xae, 0x04, 0x50, 0x55, 0x06, 0x35, 0xaa, 0x21, 0x58, 0x18, + 0xf7, 0xf5, 0x03, 0x78, 0x90, 0xf0, 0x53, 0x23, 0x3f, 0x9a, 0xa5, 0x0a, 0xe2, + 0x9c, 0x05, 0x56, 0xc3, 0x6d, 0x67, 0xb2, 0x64, 0x7e, 0x54, 0xeb, 0xe7, 0x58, + 0x8e, 0x1f, 0x02, 0xb3, 0xc7, 0x17, 0xdf, 0x02, 0x98, 0x43, 0x0e, 0xc9, 0xd2, + 0xbb, 0x11, 0x4b, 0x35, 0x42, 0xb7, 0x5d, 0x01, 0x0d, 0x93, 0x4e, 0x58, 0x96, + 0xe1, 0xd2, 0xd1, 0x0a, 0x09, 0x20, 0x11, 0x9d, 0xf7, 0x29, 0x2c, 0x8c, 0x28, + 0x47, 0x65, 0x0f, 0xbf, 0x42, 0x80, 0x57, 0x12, 0x8a, 0x02, 0x04, 0x0e, 0xb3, + 0xe3, 0x2d, 0xb5, 0x0c, 0xa7, 0xd8, 0xda, 0x7f, 0xf4, 0xc4, 0xa7, 0xa0, 0xe9, + 0xcf, 0x4b, 0x65, 0x2b, 0x65, 0x3d, 0x42, 0x8f, 0x83, 0xf4, 0x85, 0x33, 0x57, + 0x84, 0x1b, 0x28, 0x13, 0x80, 0x55, 0xb9, 0x13, 0x81, 0x17, 0x79, 0x0a, 0x91, + 0xe2, 0x8f, 0xaa, 0x41, 0x2f, 0xd7, 0xd0, 0x73, 0x32, 0x56, 0x73, 0x44, 0x85, + 0xd1, 0xd6, 0xd1, 0xa9, 0x8c, 0xc2, 0xd7, 0xc8, 0x2b, 0x37, 0x9e, 0x60, 0x72, + 0x5d, 0x31, 0x8c, 0x14, 0x77, 0xce, 0x49, 0x6c, 0x95, 0x86, 0x31, 0x08, 0xa1, + 0xc7, 0xe4, 0xf0, 0x20, 0x0b, 0x7a, 0x3c, 0x08, 0x8d, 0xe7, 0x7e, 0xb4, 0xbc, + 0x95, 0xa1, 0xc6, 0xc8, 0x39, 0xd7, 0x5f, 0xab, 0x59, 0x40, 0xd3, 0x07, 0x94, + 0x24, 0xd5, 0x23, 0xd6, 0xd9, 0xa4, 0x6b, 0xe5, 0x4e, 0x18, 0xf5, 0x29, 0xdc, + 0x9e, 0x56, 0x77, 0x6c, 0x5e, 0xc4, 0x51, 0xce, 0x28, 0x07, 0x9d, 0x37, 0x82, + 0x6a, 0xec, 0x40, 0x97, 0xca, 0x7a, 0xee, 0xc8, 0x08, 0x3f, 0xf5, 0xc4, 0x29, + 0x56, 0x9f, 0x91, 0x53, 0xf6, 0x96, 0xbe, 0x62, 0xbd, 0x38, 0xa3, 0xe7, 0x27, + 0xa6, 0x8a, 0xcc, 0xdf, 0xab, 0x02, 0x9b, 0x0b, 0x21, 0xe6, 0xd0, 0xcd, 0x46, + 0x0a, 0x57, 0xd5, 0xf9, 0x03, 0xda, 0x18, 0xa6, 0x07, 0x86, 0xb3, 0x91, 0xdd, + 0x1f, 0x5b, 0xe9, 0x49, 0x82, 0x7e, 0x0c, 0xe7, 0xdf, 0xd1, 0xe0, 0x84, 0x27, + 0xf0, 0xd3, 0xc2, 0x86, 0x53, 0x78, 0xc7, 0x3d, 0x46, 0xa7, 0x3c, 0x55, 0x4a, + 0x12, 0x99, 0x86, 0x02, 0x2a, 0x4f, 0x38, 0x36, 0x0c, 0x39, 0xeb, 0x9c, 0xdd, + 0x05, 0x0f, 0x56, 0xec, 0x05, 0x95, 0x68, 0x65, 0x3c, 0x78, 0x29, 0xe0, 0xa4, + 0x4f, 0x2c, 0x70, 0x10, 0xad, 0xb6, 0x73, 0xe8, 0xde, 0x77, 0x04, 0xe5, 0x4c, + 0x03, 0xa7, 0x7a, 0xb7, 0x8e, 0x85, 0xb6, 0x3f, 0x2b, 0x91, 0x18, 0x5c, 0xa5, + 0xda, 0x67, 0xd3, 0x28, 0x30, 0x65, 0x8b, 0x54, 0xbb, 0x33, 0x58, 0x75, 0x13, + 0xc4, 0x2e, 0x03, 0xb5, 0x2c, 0xeb, 0x9a, 0x19, 0x57, 0xa9, 0xe9, 0x05, 0x84, + 0x72, 0x37, 0xce, 0x44, 0x56, 0xe5, 0x33, 0x50, 0x68, 0x26, 0x49, 0x0e, 0xc5, + 0x55, 0x2b, 0x39, 0x12, 0xdb, 0x1c, 0x88, 0x0e, 0xd4, 0x71, 0xb1, 0x09, 0x29, + 0x98, 0xdc, 0xc1, 0x6f, 0xa9, 0x8d, 0x5a, 0xe9, 0xe7, 0x6f, 0xd2, 0x9d, 0x17, + 0x9f, 0xd7, 0x36, 0x59, 0x78, 0xc0, 0x80, 0x44, 0x51, 0x18, 0x80, 0x1a, 0xc1, + 0x0d, 0xc0, 0xf5, 0x78, 0x8f, 0x47, 0x86, 0x69, 0x34, 0xb9, 0x8a, 0xad, 0xb9, + 0xc6, 0x8d, 0xd8, 0x84, 0x83, 0xc1, 0x5d, 0x47, 0xaf, 0x8f, 0xf4, 0x2e, 0x6b, + 0xfb, 0xb8, 0xe0, 0xe5, 0x3a, 0x04, 0x7e, 0x58, 0xe5, 0xba, 0x90, 0xd1, 0xdb, + 0x1e, 0xa1, 0x26, 0x01, 0x7c, 0x65, 0x6d, 0x01, 0x1c, 0x68, 0x7b, 0xb0, 0x4f, + 0x47, 0xa5, 0x60, 0xef, 0x7c, 0xed, 0x23, 0x1b, 0x24, 0x38, 0x7f, 0xf4, 0x01, + 0x90, 0x43, 0xcf, 0xfd, 0x67, 0xfb, 0x9d, 0x89, 0x20, 0x06, 0xc3, 0x91, 0x7f, + 0xd7, 0xa9, 0x6f, 0xe0, 0x3d, 0x7b, 0xea, 0xa2, 0x17, 0x12, 0x8d, 0x71, 0xf0, + 0xa2, 0x8a, 0x83, 0x78, 0x7a, 0x86, 0xcf, 0xc9, 0x33, 0x69, 0xd0, 0xdd, 0x54, + 0x65, 0x32, 0x7f, 0xc4, 0x29, 0x4d, 0xae, 0x81, 0xc4, 0x35, 0x1c, 0x42, 0xa6, + 0xf0, 0xa8, 0x0e, 0xef, 0xa6, 0x1d, 0xb6, 0xa4, 0x0b, 0xb6, 0x81, 0xf5, 0x58, + 0xf8, 0x1b, 0x10, 0x1e, 0xb6, 0x57, 0xf6, 0x57, 0x27, 0xd6, 0x17, 0x69, 0x1b, + 0x8b, 0xee, 0x3a, 0xa7, 0xe5, 0x75, 0xb4, 0x11, 0xa0, 0x12, 0x8a, 0x3f, 0x24, + 0x75, 0x3e, 0x52, 0xee, 0x34, 0x90, 0x04, 0xcf, 0x6d, 0x25, 0xfa, 0xd6, 0xc4, + 0x68, 0x1b, 0x02, 0xa2, 0xe1, 0x96, 0x14, 0xe8, 0x0c, 0x95, 0x83, 0x81, 0x36, + 0x2a, 0x91, 0xd3, 0xcd, 0x3b, 0x4e, 0x76, 0x58, 0x32, 0x94, 0x31, 0x0c, 0x82, + 0x41, 0x11, 0x29, 0xac, 0x97, 0xf2, 0xad, 0x5a, 0x5b, 0x9f, 0xa8, 0x64, 0xa9, + 0xc5, 0xd0, 0x2d, 0x8c, 0x92, 0xd6, 0x42, 0x44, 0xfa, 0x6c, 0x40, 0x9c, 0x21, + 0x69, 0x48, 0x62, 0xc4, 0x42, 0x7d, 0xc5, 0x1a, 0xec, 0x57, 0x7f, 0x6e, 0xa3, + 0x38, 0x05, 0x03, 0x13, 0x99, 0x91, 0xe6, 0xe8, 0x89, 0x09, 0x87, 0x64, 0x9f, + 0xa7, 0xc4, 0x3a, 0xc8, 0x03, 0xf6, 0x89, 0xb6, 0x9d, 0x70, 0xab, 0xd7, 0xef, + 0xa7, 0x1c, 0xf9, 0xa0, 0xf2, 0xa4, 0x1d, 0xf9, 0x41, 0x89, 0x76, 0xa4, 0xff, + 0xa4, 0x4f, 0x43, 0x75, 0x92, 0xf1, 0x9c, 0x09, 0xcb, 0x49, 0x31, 0xb3, 0xd3, + 0xcd, 0x01, 0x59, 0x31, 0xcf, 0xfa, 0xe1, 0x71, 0xe0, 0x8a, 0xc5, 0x92, 0x88, + 0x61, 0xfc, 0xc3, 0x2e, 0x08, 0x81, 0x15, 0x59, 0x76, 0x49, 0x66, 0xbe, 0xbc, + 0x14, 0x14, 0x36, 0xb9, 0x17, 0xc5, 0x27, 0x1b, 0x2c, 0x68, 0x0c, 0xdc, 0x50, + 0x2c, 0xba, 0xd5, 0x27, 0xac, 0x08, 0x7b, 0x34, 0x65, 0x6f, 0x75, 0x5d, 0xfb, + 0xf0, 0xae, 0x5a, 0xed, 0xc8, 0x09, 0x85, 0xf6, 0x3d, 0x0c, 0xa4, 0x4a, 0x76, + 0x2f, 0x9b, 0x31, 0x1f, 0x15, 0x6d, 0xe6, 0x27, 0x74, 0x19, 0x19, 0x99, 0x8e, + 0x67, 0x44, 0x66, 0xc7, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x04, 0xc4, 0x9e, + 0xb1, 0x87, 0xfb, 0xf7, 0x5e, 0x5f, 0x7c, 0xee, 0x26, 0x1e, 0x30, 0x75, 0xc2, + 0xb2, 0xc2, 0x81, 0x2f, 0xe8, 0x32, 0x32, 0xc4, 0x1a, 0x5f, 0x10, 0xf4, 0x0b, + 0x91, 0x1e, 0xbc, 0xeb, 0xb7, 0x8c, 0x91, 0xc2, 0x0b, 0x82, 0xc0, 0x05, 0x0f, + 0xe2, 0xee, 0x10, 0x4b, 0x39, 0x20, 0xed, 0x0a, 0x05, 0xd1, 0x7b, 0x06, 0x0d, + 0x99, 0xd5, 0x87, 0x01, 0x98, 0xe6, 0x3c, 0xcf, 0x51, 0xb1, 0x5d, 0xf8, 0x0e, + 0x87, 0xac, 0xbd, 0x30, 0x12, 0x6c, 0xda, 0x2a, 0xff, 0xb8, 0xf1, 0xce, 0xcb, + 0x1b, 0xaa, 0x6a, 0x91, 0x9e, 0x0a, 0x97, 0x87, 0x91, 0x39, 0x69, 0x04, 0x44, + 0x9a, 0xde, 0x4b, 0x0b, 0x02, 0x92, 0x0f, 0xb8, 0xc0, 0xbf, 0x7f, 0xc0, 0x82, + 0xeb, 0x74, 0x98, 0x73, 0xc1, 0x0d, 0x17, 0xdb, 0xd9, 0x1f, 0xfe, 0xa9, 0x36, + 0x10, 0xee, 0xea, 0x62, 0x57, 0x90, 0xad, 0xa2, 0x8e, 0x3a, 0x2c, 0xf2, 0x2c, + 0x0d, 0x4e, 0xa2, 0xb9, 0x26, 0x41, 0xf2, 0x16, 0xd3, 0x92, 0x2c, 0x1f, 0xc3, + 0x2d, 0xbc, 0x1e, 0x0e, 0x99, 0x00, 0x38, 0x6c, 0xf8, 0x98, 0xcb, 0x8e, 0xd5, + 0x6c, 0x06, 0x4e, 0x5b, 0x12, 0xb0, 0x26, 0xbf, 0x03, 0x5d, 0xfb, 0xc4, 0xeb, + 0x92, 0xce, 0x33, 0xf8, 0x2b, 0xbe, 0x48, 0xca, 0x94, 0x5f, 0x12, 0x44, 0x83, + 0x10, 0xd7, 0xb9, 0xdb, 0x85, 0xf1, 0xb0, 0x46, 0xdc, 0x9c, 0x56, 0x51, 0x2f, + 0x61, 0xe0, 0xa3, 0x96, 0x6f, 0xa4, 0xab, 0x71, 0xd1, 0x5f, 0x4e, 0x23, 0xe4, + 0xe3, 0x1c, 0xb9, 0x62, 0x10, 0x60, 0x14, 0xc4, 0xc2, 0x9e, 0xc3, 0xb9, 0x10, + 0xe0, 0x72, 0x2d, 0xac, 0x38, 0xaa, 0x4d, 0xc8, 0x1e, 0x17, 0x6d, 0x72, 0xfe, + 0xaf, 0x2f, 0x93, 0xf9, 0xec, 0xd5, 0x04, 0xcb, 0xaf, 0x95, 0x59, 0x83, 0x30, + 0x09, 0xd9, 0x2c, 0x9d, 0x2f, 0x81, 0x68, 0x7b, 0xf5, 0x89, 0xa4, 0x93, 0x66, + 0xcd, 0x0a, 0xba, 0xe7, 0xa1, 0x74, 0xa4, 0x8f, 0xf7, 0x6c, 0xd7, 0x2f, 0x02, + 0xb1, 0x8a, 0xf8, 0x18, 0x75, 0x26, 0xd4, 0x70, 0x94, 0x9c, 0xb8, 0xd9, 0x3e, + 0xfe, 0x6c, 0x5b, 0xc7, 0x91, 0xca, 0x93, 0xb1, 0x10, 0xc1, 0x82, 0x5b, 0x6a, + 0xfb, 0x04, 0x5d, 0x9d, 0x8c, 0xa3, 0x51, 0xf7, 0xad, 0xa3, 0x28, 0xfd, 0xd5, + 0x2a, 0xec, 0x29, 0x77, 0xd2, 0x94, 0x0e, 0x2c, 0xdc, 0xb2, 0x66, 0x4d, 0x78, + 0xb7, 0x6a, 0xc0, 0xe0, 0x6d, 0x78, 0x8e, 0x57, 0xf8, 0x24, 0x4f, 0x44, 0x2c, + 0x88, 0x6a, 0x8f, 0x31, 0x13, 0x7c, 0xd7, 0xf1, 0x9e, 0x82, 0x21, 0xa3, 0x85, + 0xcb, 0xfb, 0x3f, 0x7f, 0x2a, 0x1e, 0x79, 0x50, 0x4b, 0xcf, 0x1a, 0xe0, 0x83, + 0xb1, 0x29, 0x02, 0xa5, 0x01, 0x2c, 0xd5, 0xea, 0x2f, 0xc8, 0x56, 0x43, 0xdd, + 0xec, 0xee, 0xf4, 0xab, 0x95, 0x93, 0x43, 0x21, 0x9b, 0x0c, 0x63, 0xdd, 0x0a, + 0x8b, 0x0e, 0x23, 0x3e, 0xfc, 0x68, 0xfc, 0x63, 0x30, 0x73, 0xe6, 0x6c, 0x59, + 0x97, 0x5f, 0x23, 0x52, 0x4b, 0x6a, 0xa1, 0xab, 0x9a, 0xe7, 0xb1, 0x33, 0xd5, + 0xf3, 0x0c, 0xf9, 0xe1, 0xd0, 0xf9, 0xba, 0xd7, 0x1f, 0x67, 0x3f, 0x5b, 0x75, + 0x4c, 0xf4, 0x00, 0x99, 0x77, 0x57, 0xa6, 0x45, 0x8a, 0xd3, 0xb9, 0xdc, 0x8e, + 0xc0, 0xc6, 0x9c, 0x66, 0x09, 0x66, 0x3b, 0x42, 0xbb, 0xb0, 0xca, 0x1a, 0x55, + 0x73, 0x37, 0x42, 0x81, 0x1f, 0x0d, 0x71, 0x30, 0xe0, 0x13, 0xfe, 0x2f, 0x88, + 0x05, 0x8e, 0xe8, 0x9b, 0x90, 0xa7, 0x5c, 0xd0, 0x69, 0xda, 0xf1, 0x00, 0x37, + 0x25, 0x4d, 0x10, 0x16, 0xd3, 0xac, 0xf7, 0xe6, 0x2f, 0x18, 0x3b, 0x2c, 0x55, + 0x1a, 0x59, 0x90, 0xe4, 0xed, 0x73, 0xdc, 0xd8, 0x94, 0xf7, 0x85, 0x70, 0xfd, + 0x19, 0x56, 0xcb, 0x22, 0x7c, 0x65, 0x00, 0x01, 0xf2, 0x7f, 0x94, 0x23, 0xf4, + 0xed, 0x12, 0x56, 0x0b, 0x2e, 0x1c, 0x8d, 0xbc, 0xb4, 0xc3, 0x02, 0x15, 0xb2, + 0x16, 0x7f, 0x02, 0xef, 0xeb, 0x70, 0x7a, 0xf1, 0xb5, 0xc7, 0x84, 0xb7, 0xf5, + 0x8b, 0x2e, 0x51, 0x73, 0x03, 0xf3, 0xaf, 0x71, 0xb1, 0xee, 0x39, 0xa9, 0xae, + 0x06, 0xb9, 0x77, 0x28, 0xe6, 0x4f, 0x67, 0x6d, 0xed, 0x50, 0xa3, 0xf5, 0x1b, + 0xc9, 0xe0, 0x17, 0x07, 0xbf, 0x57, 0x95, 0x6f, 0x01, 0xb7, 0xda, 0x7c, 0x23, + 0xe6, 0x93, 0x52, 0x06, 0x57, 0x28, 0x6f, 0xe7, 0x3e, 0xee, 0x9e, 0xb1, 0xd5, + 0x83, 0x75, 0x22, 0x03, 0xf3, 0xd9, 0x2b, 0xd4, 0x04, 0x7b, 0x83, 0xfd, 0x38, + 0xf5, 0x66, 0xdd, 0x25, 0xb9, 0x6d, 0x11, 0xb7, 0x22, 0x2b, 0x67, 0x82, 0xda, + 0xde, 0xf5, 0xee, 0x78, 0x82, 0x14, 0x7c, 0xbb, 0x4f, 0xcf, 0xe7, 0x0d, 0x2c, + 0xa7, 0xf3, 0x9a, 0x29, 0x7b, 0x21, 0xd5, 0x6d, 0x66, 0x10, 0xe9, 0xda, 0x9d, + 0x8e, 0xef, 0xdc, 0x69, 0x9e, 0x4a, 0x30, 0x06, 0x8a, 0x14, 0x57, 0xcf, 0x5e, + 0xaf, 0x69, 0x87, 0x78, 0x21, 0xd3, 0x9e, 0xa0, 0x85, 0x94, 0xc2, 0xfb, 0x9e, + 0xb9, 0xd8, 0x04, 0x64, 0x50, 0xe4, 0x13, 0x03, 0xf1, 0x95, 0xbd, 0xc9, 0x05, + 0xe4, 0xf2, 0x58, 0x3c, 0x6a, 0xe3, 0x86, 0x1b, 0x87, 0x19, 0xbb, 0xce, 0xd1, + 0xce, 0x58, 0xc4, 0x68, 0x81, 0x6d, 0x45, 0x15, 0xe6, 0x09, 0x7b, 0x3e, 0x2e, + 0x81, 0x82, 0x21, 0x0f, 0x6c, 0x1b, 0xb3, 0xaa, 0xa6, 0x2a, 0xe0, 0xf6, 0x9f, + 0x79, 0xfc, 0xc5, 0x47, 0xba, 0xab, 0x31, 0x1d, 0x99, 0x7c, 0x84, 0x95, 0xd6, + 0xab, 0xe3, 0xa5, 0x1f, 0x56, 0x53, 0xf3, 0x1c, 0x5a, 0x2e, 0xea, 0x8d, 0x31, + 0x90, 0x97, 0xf3, 0x04, 0x5e, 0x6c, 0x3c, 0x3d, 0x8c, 0x87, 0xc9, 0xbd, 0x55, + 0xb4, 0x19, 0x2e, 0xbf, 0x00, 0xff, 0x8f, 0xc7, 0xf4, 0x1e, 0x18, 0x93, 0x0a, + 0x99, 0x72, 0xa3, 0x4d, 0x9e, 0x6a, 0xa9, 0xd9, 0x1d, 0x2e, 0x28, 0x17, 0xeb, + 0x6d, 0xe9, 0xba, 0x38, 0x9e, 0x69, 0xaa, 0x51, 0x2f, 0x3f, 0xb4, 0xdf, 0xf8, + 0xca, 0x1c, 0xe7, 0xc9, 0xca, 0x39, 0x6e, 0x8a, 0x9d, 0x99, 0xd4, 0x96, 0x51, + 0xb0, 0x58, 0x2f, 0xc5, 0x86, 0xce, 0x92, 0x7e, 0xa2, 0x64, 0x5b, 0xda, 0xa3, + 0x79, 0x28, 0x6f, 0x95, 0xd3, 0x9b, 0x95, 0x81, 0xde, 0xb2, 0xc5, 0x37, 0x75, + 0xae, 0xef, 0x20, 0xe7, 0xbd, 0xbc, 0x3b, 0x19, 0xd8, 0x9b, 0xac, 0xee, 0xa1, + 0x3b, 0x74, 0xe6, 0xc7, 0xf5, 0x20, 0x89, 0x39, 0x7d, 0x11, 0x6e, 0xbf, 0xac, + 0x6a, 0x30, 0xed, 0x27, 0xd6, 0x27, 0x81, 0xa0, 0x3b, 0x66, 0xb0, 0x52, 0xf7, + 0x51, 0xfb, 0x36, 0x88, 0x2b, 0x9a, 0x14, 0x34, 0x23, 0xad, 0x02, 0xf3, 0x36, + 0x0a, 0xfa, 0x54, 0xc4, 0xcf, 0x23, 0x53, 0x0c, 0x68, 0xd6, 0x0e, 0x99, 0x56, + 0x1c, 0xce, 0x0d, 0x6a, 0x9c, 0x32, 0xef, 0xc7, 0x1f, 0xef, 0xaf, 0x23, 0x57, + 0x86, 0x3f, 0xa0, 0xb9, 0xf7, 0xbe, 0x76, 0xc2, 0xd1, 0xd3, 0x88, 0x49, 0xa0, + 0x0a, 0xb0, 0x41, 0xf1, 0x82, 0xad, 0x63, 0x35, 0xe9, 0x55, 0xcc, 0x65, 0xcd, + 0xfd, 0x3b, 0x69, 0x1a, 0x3d, 0x96, 0xc4, 0xbd, 0x56, 0xf5, 0x25, 0xce, 0xdb, + 0x7f, 0xdc, 0xb7, 0x33, 0xe7, 0x67, 0x06, 0x2f, 0xd8, 0xa4, 0xef, 0x1a, 0x4b, + 0x71, 0x5e, 0x5e, 0xdf, 0x76, 0x26, 0x14, 0x4e, 0x28, 0x5f, 0x2b, 0x3c, 0x4e, + 0x2c, 0xb4, 0x1b, 0x7d, 0xb9, 0x66, 0x35, 0x82, 0xad, 0x65, 0xa5, 0x41, 0x6e, + 0x57, 0xf7, 0x48, 0x5f, 0x39, 0xc0, 0x5e, 0x8e, 0x7a, 0xf9, 0x6b, 0x36, 0x78, + 0xc8, 0x0a, 0x8d, 0x4b, 0xa2, 0xf9, 0x5d, 0x5f, 0xeb, 0x0c, 0xcb, 0x0f, 0x71, + 0x7b, 0x9d, 0xb7, 0x24, 0xab, 0xf4, 0xcc, 0xd4, 0x10, 0x49, 0x00, 0x18, 0x6f, + 0x4a, 0x93, 0x0d, 0x4b, 0x2a, 0xcb, 0x9f, 0x9a, 0x16, 0xaf, 0x89, 0x77, 0x27, + 0x7d, 0x6f, 0x0b, 0xc9, 0x0a, 0xb8, 0x59, 0xc3, 0x33, 0x3b, 0x3d, 0xe8, 0x6f, + 0x41, 0xfa, 0x85, 0xd5, 0x70, 0xf1, 0x6c, 0x74, 0x82, 0x0a, 0x70, 0x41, 0xfe, + 0xa1, 0x5e, 0xe9, 0x50, 0xc3, 0x30, 0xac, 0xa3, 0xf1, 0xe5, 0x1c, 0x69, 0x44, + 0x74, 0x72, 0xf2, 0x6a, 0x3d, 0x67, 0x41, 0xbc, 0x67, 0xe9, 0x2e, 0x00, 0xa0, + 0x83, 0xb6, 0x95, 0x33, 0x03, 0xb3, 0x73, 0x1c, 0xf2, 0x84, 0x8d, 0x81, 0x7c, + 0xeb, 0x77, 0xf1, 0xcc, 0xa7, 0x1e, 0xc9, 0x13, 0x91, 0x20, 0x2b, 0x73, 0x4d, + 0x54, 0x8f, 0xa3, 0x14, 0x2c, 0x37, 0xe6, 0xfc, 0xac, 0x51, 0x92, 0xfc, 0xa2, + 0x8d, 0x63, 0x98, 0x1f, 0x67, 0xdd, 0xdc, 0x28, 0xb3, 0x1f, 0xd0, 0xb9, 0x3a, + 0x7f, 0x21, 0x88, 0xc1, 0xec, 0xa2, 0xc1, 0xef, 0xa4, 0x61, 0xd2, 0xdd, 0x73, + 0x38, 0xdf, 0x07, 0x05, 0xae, 0x70, 0x10, 0x62, 0xfb, 0xcd, 0x8d, 0x50, 0x29, + 0x98, 0x85, 0xd8, 0xe3, 0xd4, 0xfb, 0xd6, 0xa4, 0xf2, 0x15, 0x5d, 0xc8, 0xd8, + 0xfd, 0x0b, 0x05, 0x8f, 0x3c, 0x77, 0x50, 0x83, 0xf5, 0x96, 0x12, 0xac, 0x66, + 0x02, 0xd9, 0xad, 0xfa, 0x49, 0xe2, 0x60, 0x2a, 0x12, 0xf2, 0x90, 0x0d, 0x22, + 0xb9, 0x9c, 0x0b, 0x8a, 0x32, 0x68, 0xa0, 0x19, 0xc0, 0xdd, 0xf3, 0x14, 0x3e, + 0x8a, 0xf4, 0x13, 0x07, 0xd9, 0x26, 0x74, 0x02, 0x13, 0x08, 0x59, 0xee, 0x92, + 0x43, 0x4d, 0x23, 0x79, 0xe9, 0x4b, 0xcb, 0xbe, 0x56, 0x1d, 0xe0, 0x42, 0x92, + 0xb5, 0x32, 0xab, 0xc3, 0x5d, 0xde, 0x53, 0xd2, 0xad, 0x86, 0x7f, 0x7a, 0xd9, + 0x42, 0x00, 0xe4, 0x8e, 0x50, 0x3e, 0x7d, 0x41, 0x6b, 0xcf, 0x98, 0x29, 0x9f, + 0x82, 0xfc, 0xba, 0xe2, 0xdc, 0x42, 0xae, 0xc1, 0x8a, 0x29, 0x3b, 0x63, 0x79, + 0x5b, 0x68, 0x63, 0xf3, 0x22, 0x49, 0xcd, 0x20, 0x5e, 0x54, 0xd7, 0xcb, 0x7c, + 0x82, 0x3b, 0x00, 0x74, 0x77, 0x35, 0x96, 0xc1, 0xc5, 0x33, 0x92, 0x1d, 0x3b, + 0xae, 0x11, 0xfe, 0x1c, 0x6b, 0xfb, 0x77, 0x74, 0xe1, 0x49, 0x88, 0x64, 0xf3, + 0xb6, 0x26, 0xd4, 0xcb, 0x14, 0x47, 0x95, 0xd8, 0xf3, 0x59, 0xf5, 0xc5, 0x5d, + 0xa3, 0xd7, 0x11, 0x70, 0x4e, 0x74, 0x29, 0x58, 0x95, 0x5e, 0xaf, 0xa4, 0xb7, + 0xd0, 0x31, 0xb2, 0xd6, 0xda, 0x0c, 0x52, 0x9d, 0x41, 0xf3, 0x16, 0x93, 0xe4, + 0xe5, 0x10, 0xb6, 0xb1, 0xe4, 0xab, 0xb6, 0x01, 0x5f, 0x0d, 0x6d, 0x12, 0x61, + 0x5e, 0xc1, 0xea, 0xf2, 0x75, 0xd4, 0x62, 0x96, 0x2f, 0x17, 0x68, 0x4a, 0x7a, + 0x25, 0x30, 0x1a, 0x99, 0x55, 0x5d, 0xef, 0x47, 0x15, 0xff, 0x62, 0xce, 0x3c, + 0xa6, 0x2f, 0x82, 0xe1, 0xf0, 0xec, 0x3b, 0x76, 0xd9, 0xea, 0x82, 0x5a, 0xbc, + 0x46, 0xfa, 0x2c, 0xf2, 0xb7, 0xa9, 0x64, 0x3e, 0xf2, 0x11, 0x0d, 0x16, 0xef, + 0x7a, 0x37, 0x0a, 0x5a, 0x99, 0xc0, 0xf7, 0x3d, 0xd2, 0x07, 0xb7, 0xba, 0xc5, + 0x2f, 0x36, 0x7d, 0xc4, 0xba, 0x9f, 0x52, 0x1c, 0x2d, 0x48, 0x77, 0xba, 0x68, + 0x98, 0xb8, 0xc9, 0x0c, 0x6d, 0xa7, 0x33, 0x64, 0x5c, 0xfb, 0x78, 0xc6, 0xf4, + 0x09, 0x92, 0xc7, 0x20, 0x96, 0x8f, 0xe4, 0x3c, 0x32, 0xbb, 0x59, 0x39, 0x9b, + 0xa8, 0x82, 0x36, 0x06, 0x4a, 0xa0, 0xa6, 0x8f, 0x1a, 0x5a, 0xfa, 0xae, 0xd0, + 0xf5, 0x39, 0xc2, 0x4e, 0xf9, 0xe6, 0x9d, 0x37, 0xdd, 0xba, 0x2d, 0x15, 0x86, + 0xc0, 0x3b, 0x52, 0x45, 0x48, 0xd8, 0x20, 0x7d, 0xa9, 0x58, 0x92, 0xc0, 0x0a, + 0xcf, 0xee, 0x51, 0xb2, 0x42, 0x4c, 0x2d, 0x1a, 0x4d, 0x7d, 0x4d, 0xd9, 0x8a, + 0x1c, 0x6f, 0x2a, 0x5f, 0x6b, 0x39, 0x20, 0x64, 0x30, 0xf1, 0x84, 0x37, 0x3a, + 0x96, 0xc6, 0xaa, 0x58, 0xcc, 0xe2, 0xe1, 0xc5, 0x04, 0xd4, 0x0e, 0xe9, 0xef, + 0xda, 0x58, 0x8d, 0x43, 0xef, 0xb1, 0xda, 0x53, 0xc7, 0x3d, 0x53, 0x0f, 0xa7, + 0x6b, 0x11, 0x2f, 0x33, 0xb4, 0xaf, 0xa9, 0x41, 0xcd, 0x1e, 0x20, 0x5a, 0xcd, + 0x72, 0xca, 0x86, 0x84, 0xad, 0xe8, 0x33, 0x3d, 0x46, 0x32, 0xab, 0x94, 0x3d, + 0x69, 0x0f, 0x13, 0x2b, 0xc9, 0x9f, 0x5c, 0x5a, 0x1d, 0x3e, 0xa4, 0xe0, 0xca, + 0x8f, 0x43, 0x23, 0x8c, 0xd9, 0xeb, 0x09, 0xc8, 0xbf, 0x11, 0xe9, 0x18, 0xa9, + 0xc7, 0xf8, 0x83, 0xbe, 0x94, 0x89, 0x06, 0x56, 0x33, 0x66, 0x67, 0x95, 0x4a, + 0x51, 0xa8, 0xae, 0xcd, 0xc4, 0xcb, 0xd3, 0x9a, 0xca, 0xc7, 0x52, 0x05, 0x6e, + 0x71, 0xcc, 0x96, 0x91, 0x55, 0xdd, 0x65, 0x6d, 0x79, 0x59, 0x00, 0x8c, 0x0e, + 0xcf, 0x61, 0x83, 0x2a, 0x5c, 0x44, 0xe2, 0xe0, 0xde, 0x68, 0xf5, 0x04, 0xc1, + 0x77, 0xdf, 0x68, 0x8b, 0xee, 0x55, 0x8c, 0x6f, 0x4e, 0x5e, 0xa5, 0xf9, 0xad, + 0x78, 0x26, 0x73, 0x40, 0xe2, 0xc8, 0x35, 0xb9, 0x74, 0xdd, 0x12, 0xcd, 0xb9, + 0x05, 0x08, 0x87, 0x60, 0x34, 0xdd, 0xde, 0x0d, 0x97, 0xea, 0xfa, 0xf9, 0x70, + 0x18, 0x34, 0x90, 0xcd, 0x22, 0xea, 0x57, 0xb9, 0x8a, 0xbd, 0x1a, 0x7f, 0x79, + 0xe2, 0xcf, 0x23, 0xcf, 0x8d, 0x1b, 0x0e, 0x9b, 0x7c, 0x93, 0x8a, 0xcc, 0x6b, + 0x14, 0x4b, 0x54, 0x13, 0xd3, 0x2f, 0x50, 0xcd, 0x09, 0x61, 0x8f, 0xa9, 0x74, + 0x10, 0x3a, 0x72, 0x8e, 0x2b, 0x71, 0x76, 0x63, 0xd4, 0xbd, 0x9b, 0x07, 0x20, + 0xb7, 0x75, 0xf5, 0xee, 0x25, 0xa6, 0xd7, 0x4d, 0x12, 0x8c, 0x49, 0xb4, 0x0a, + 0x19, 0x74, 0x1c, 0x37, 0xdd, 0x34, 0x61, 0x6d, 0xb3, 0x1e, 0xac, 0x0b, 0xe7, + 0xf5, 0x3f, 0xfa, 0x61, 0x9f, 0x45, 0x18, 0x1f, 0x5a, 0x4d, 0xbe, 0x5b, 0x1b, + 0x48, 0x09, 0x8e, 0xba, 0x2c, 0x2e, 0xc2, 0x0a, 0x0a, 0xc0, 0x44, 0x3b, 0xa8, + 0xe9, 0x48, 0x7b, 0xcf, 0x7d, + ], + script_code: Script(vec![0xac, 0x53, 0x63, 0x52, 0x6a, 0x51, 0xac]), + transparent_input: None, + hash_type: 1, + amount: 1501997449504444, + consensus_branch_id: consensus::BranchId::Sapling, + sighash: [ + 0xa1, 0xcf, 0x50, 0xcf, 0xfe, 0x59, 0xbe, 0x5f, 0x31, 0x5f, 0xfe, 0x51, 0x6e, + 0x28, 0x9e, 0xe8, 0x02, 0x5e, 0x59, 0x38, 0xf1, 0xe8, 0xe1, 0x88, 0x53, 0x7f, + 0xf1, 0xa8, 0x93, 0xac, 0x71, 0x14, + ], + }, + Test0243Vector { + tx: vec![ + 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0x88, 0x1d, 0xdf, 0x4f, + 0x95, 0x78, 0x97, 0x34, 0xfc, 0xc1, 0x65, 0xee, 0x1e, 0x04, 0x40, 0x85, 0xb6, + 0xe7, 0xa1, 0x77, 0x50, 0x8c, 0x29, 0xda, 0x0c, 0xe7, 0x7d, 0xed, 0x75, 0x08, + 0x98, 0xde, 0x89, 0xd2, 0x60, 0xd3, 0x02, 0x63, 0x52, 0x44, 0xcc, 0x75, 0xe1, + 0x98, 0x34, 0x52, 0x5f, 0xba, 0x56, 0x90, 0x0d, 0xe9, 0x93, 0x85, 0x44, 0x2e, + 0xb9, 0xec, 0x9a, 0x5f, 0x18, 0x2b, 0x87, 0x5d, 0x70, 0xb5, 0xb1, 0x53, 0x79, + 0x0a, 0x1e, 0xe7, 0x9c, 0x0e, 0x86, 0x78, 0x37, 0x95, 0xfa, 0x06, 0x6a, 0x00, + 0x63, 0x00, 0x00, 0x63, 0xfc, 0x92, 0x29, 0x92, 0x00, 0x83, 0x64, 0xff, 0xfc, + 0x7c, 0x00, 0xc0, 0x0e, 0x0f, 0x99, 0xde, 0x47, 0x42, 0x89, 0x06, 0x00, 0x01, + 0x39, 0x21, 0x97, 0xd6, 0x23, 0xf7, 0xeb, 0xda, 0x07, 0xcd, 0x00, 0x58, 0xd9, + 0xa1, 0xd1, 0x72, 0x04, 0x3c, 0x2f, 0xc9, 0x4f, 0x14, 0x19, 0x3e, 0x27, 0x0e, + 0xef, 0xe8, 0x3c, 0x3f, 0x01, 0xb2, 0x65, 0x05, 0x4c, 0x3f, 0x6a, 0x60, 0xe2, + 0xb7, 0x6e, 0x17, 0x56, 0x08, 0x8b, 0x87, 0xda, 0x83, 0x9f, 0x77, 0x2c, 0xbd, + 0x0f, 0x27, 0x5c, 0x92, 0x28, 0x38, 0x5a, 0x04, 0xbb, 0x50, 0xec, 0x3c, 0xfa, + 0x9e, 0xe2, 0xe1, 0x5b, 0x15, 0x3d, 0x4c, 0x85, 0xfe, 0x50, 0xb6, 0x00, 0x62, + 0x58, 0xe9, 0xe8, 0xc2, 0x52, 0x99, 0xc0, 0x9d, 0xf8, 0xb4, 0x55, 0x46, 0x6b, + 0xa2, 0x5f, 0x7e, 0x4c, 0x8f, 0xe7, 0xe2, 0x50, 0xed, 0xba, 0x60, 0x69, 0x5d, + 0xa4, 0x7f, 0xaa, 0xfd, 0xd6, 0x26, 0xba, 0x7e, 0x9d, 0x48, 0x96, 0xe4, 0xb8, + 0xa8, 0xa1, 0xa1, 0xdc, 0x21, 0x5b, 0x0a, 0x25, 0xee, 0xb0, 0x4e, 0xd1, 0xbe, + 0xfb, 0x5b, 0x31, 0x38, 0xc6, 0x9f, 0xe5, 0x28, 0xe7, 0x29, 0x11, 0x23, 0xfc, + 0xdf, 0x8a, 0x36, 0x6c, 0x25, 0x7d, 0x32, 0x95, 0x38, 0x25, 0x0a, 0x0c, 0xb7, + 0xf5, 0x4e, 0x1c, 0x01, 0x6c, 0xe1, 0xc6, 0x23, 0xb2, 0xe2, 0x76, 0xa5, 0x2c, + 0x6e, 0x41, 0x24, 0x1b, 0x2a, 0xc5, 0x09, 0x37, 0x3c, 0x18, 0x81, 0x40, 0xe8, + 0x36, 0x5c, 0x94, 0xf5, 0x8c, 0x63, 0xf2, 0x7f, 0xf8, 0xe6, 0xe8, 0x69, 0xa9, + 0x85, 0xaf, 0xb6, 0x1e, 0x97, 0xd8, 0xce, 0xec, 0x2a, 0x78, 0x24, 0xa5, 0xc1, + 0x07, 0xb0, 0xba, 0xa4, 0xd6, 0xe7, 0x9a, 0x6c, 0x71, 0x87, 0x2a, 0x7b, 0x3b, + 0x17, 0xef, 0x91, 0x8a, 0xe4, 0xe2, 0x5f, 0x98, 0xa7, 0x2d, 0xb5, 0x3b, 0xa7, + 0xf2, 0x6e, 0x40, 0x8b, 0xd4, 0xd1, 0xf9, 0xe3, 0x47, 0x4d, 0xdc, 0xa5, 0x83, + 0x3f, 0xf5, 0xff, 0x8d, 0x11, 0xb1, 0xbf, 0x1e, 0x2b, 0xb4, 0xd1, 0x96, 0x8a, + 0x82, 0x38, 0x88, 0xbd, 0x91, 0xa2, 0x1a, 0x76, 0x79, 0x6b, 0xca, 0x44, 0x53, + 0xe2, 0x89, 0x2d, 0x1b, 0x6e, 0x13, 0x63, 0xed, 0x10, 0x7a, 0x9e, 0x7e, 0xd9, + 0x3f, 0xb1, 0xda, 0x99, 0x4a, 0x9d, 0x4e, 0x7e, 0xc9, 0x2e, 0x29, 0xa6, 0x87, + 0xf2, 0x18, 0xd2, 0x8a, 0x76, 0x46, 0x06, 0x9b, 0xca, 0xcb, 0x4d, 0xa7, 0xba, + 0xdf, 0x4e, 0xb1, 0x33, 0x1a, 0xab, 0x21, 0x2b, 0x92, 0xc6, 0xea, 0x64, 0x76, + 0xa0, 0xa0, 0x9d, 0x6b, 0xd2, 0xe0, 0xf7, 0x6f, 0xa8, 0x73, 0x79, 0xab, 0xfd, + 0x17, 0x58, 0x2f, 0x3e, 0xb2, 0x3b, 0x86, 0xc9, 0x66, 0x9f, 0x86, 0x73, 0x70, + 0x48, 0xd7, 0x71, 0x84, 0x9b, 0x8f, 0x70, 0xbd, 0x87, 0x99, 0x01, 0x3b, 0xe0, + 0xbf, 0xbd, 0x7b, 0x57, 0xbe, 0xa1, 0xa4, 0x9a, 0x4a, 0x39, 0x14, 0x79, 0x12, + 0xd7, 0xba, 0xf6, 0x80, 0x04, 0xd4, 0x15, 0x02, 0x6b, 0xbc, 0x6f, 0x69, 0x32, + 0x5f, 0x4f, 0xf7, 0x87, 0x28, 0x77, 0x5a, 0x67, 0xaa, 0xdd, 0x72, 0x2c, 0x73, + 0x31, 0x1d, 0xba, 0x5c, 0x2c, 0xf1, 0x4c, 0xcb, 0xd5, 0x7e, 0xab, 0xed, 0x71, + 0x92, 0x0f, 0xf9, 0x62, 0x32, 0x89, 0xbb, 0x76, 0x05, 0x1c, 0x73, 0xa2, 0x06, + 0xa3, 0xc2, 0xb4, 0x0c, 0xac, 0x01, 0xd5, 0xf1, 0x1f, 0xa6, 0x4c, 0x1b, 0x7d, + 0xed, 0x70, 0xea, 0x17, 0x42, 0x9c, 0x66, 0x21, 0xca, 0x9b, 0x92, 0x3c, 0x48, + 0x11, 0x85, 0x0c, 0x3d, 0xf4, 0x01, 0x3d, 0x17, 0xbd, 0xc5, 0x10, 0x1c, 0x8d, + 0x80, 0xb3, 0xa0, 0x4a, 0x4c, 0xc2, 0x3d, 0x13, 0xfe, 0x31, 0x84, 0xe8, 0xb1, + 0xad, 0xe6, 0x35, 0x17, 0x59, 0x3f, 0x7b, 0xe6, 0x69, 0x48, 0xc0, 0x85, 0x7a, + 0xec, 0xe0, 0x1b, 0xc2, 0x72, 0x29, 0x5e, 0x60, 0xb1, 0x80, 0x69, 0x46, 0xc9, + 0x3b, 0xc8, 0xc7, 0xd2, 0xa2, 0xed, 0xc3, 0x7f, 0xa3, 0x7c, 0x47, 0x7a, 0x69, + 0xa9, 0x0b, 0x59, 0xb4, 0xc6, 0x91, 0x2e, 0x91, 0x3a, 0x57, 0xef, 0xa9, 0xd5, + 0x4c, 0x7e, 0x80, 0xd5, 0xac, 0x8a, 0x42, 0x94, 0xd0, 0xfd, 0x31, 0xa4, 0x02, + 0xe4, 0xb4, 0x7e, 0xc7, 0xbf, 0x03, 0x31, 0xb2, 0xc9, 0xa4, 0x8f, 0x44, 0x57, + 0x3f, 0xc7, 0xe7, 0xf1, 0x02, 0xed, 0x48, 0xc9, 0x75, 0x08, 0xcb, 0xe4, 0x30, + 0x65, 0xa9, 0xe9, 0x9f, 0xb4, 0xce, 0x13, 0x62, 0xbb, 0x8a, 0x76, 0xb1, 0x41, + 0x9d, 0x95, 0x03, 0x0e, 0x9c, 0x24, 0xee, 0xba, 0x9f, 0xf8, 0xcf, 0xda, 0x95, + 0x7b, 0x17, 0x09, 0x8c, 0xdf, 0x8c, 0x9a, 0x91, 0x9e, 0x47, 0xa1, 0x3a, 0x5b, + 0x33, 0x46, 0xe3, 0x7e, 0x82, 0x7c, 0xc8, 0x3b, 0x3c, 0x9a, 0xab, 0xf2, 0xd0, + 0xba, 0x17, 0xff, 0x3d, 0x9e, 0x0d, 0x22, 0x3c, 0x41, 0xc8, 0x8e, 0xc2, 0x39, + 0x1c, 0x76, 0x62, 0x2d, 0x7b, 0xd6, 0x21, 0x17, 0x33, 0x1e, 0x21, 0xff, 0xec, + 0x32, 0x72, 0xc1, 0xe1, 0x42, 0x39, 0x82, 0xc6, 0xb6, 0x3a, 0xec, 0x8d, 0xbf, + 0x5c, 0xa2, 0xdd, 0x15, 0x81, 0x0f, 0x53, 0x42, 0xaf, 0x49, 0xfa, 0xd2, 0x79, + 0xb7, 0xca, 0x23, 0xde, 0xd3, 0x08, 0x24, 0x79, 0x96, 0x30, 0xde, 0xdc, 0x6d, + 0xb7, 0x24, 0xbc, 0xe1, 0x11, 0x36, 0x21, 0xc4, 0xa6, 0x47, 0x9d, 0xd5, 0x55, + 0xf4, 0x85, 0x21, 0x7c, 0xb5, 0x67, 0x13, 0x9e, 0xea, 0xdd, 0x7e, 0xe8, 0xdc, + 0x5b, 0x26, 0x62, 0xf1, 0x06, 0x6a, 0x7c, 0x60, 0xde, 0xe0, 0x09, 0x3c, 0x92, + 0x46, 0xde, 0x7a, 0x05, 0xe8, 0xb0, 0xf6, 0xbe, 0xf0, 0x03, 0x3d, 0xde, 0x2e, + 0x87, 0xcb, 0xa6, 0x8d, 0x23, 0x6e, 0xf6, 0x6a, 0x23, 0xd5, 0x5e, 0x7b, 0xd2, + 0x8d, 0x02, 0x59, 0x9c, 0xca, 0x0d, 0xf7, 0xa9, 0x00, 0x63, 0x7b, 0xb3, 0x46, + 0x4d, 0x62, 0x2b, 0x7c, 0x9c, 0x9c, 0x8c, 0x91, 0x46, 0x89, 0x74, 0x88, 0x01, + 0x64, 0xde, 0xf7, 0x99, 0x90, 0x8a, 0x11, 0xa5, 0x91, 0xab, 0xb3, 0xc8, 0xd8, + 0xbd, 0x9c, 0x12, 0xb1, 0xf6, 0xf3, 0xcd, 0xc9, 0xed, 0x8e, 0x16, 0xe5, 0x7d, + 0x23, 0x34, 0xb2, 0x17, 0x79, 0x7d, 0xf1, 0x90, 0x52, 0xfe, 0xeb, 0xed, 0x6c, + 0xdb, 0x99, 0xac, 0x44, 0xea, 0x13, 0xaf, 0xea, 0xc4, 0x37, 0x7d, 0x0f, 0xa3, + 0x7e, 0xf5, 0x16, 0xdd, 0xac, 0xea, 0xb0, 0xd9, 0x39, 0x5b, 0xd4, 0x40, 0x46, + 0x0e, 0x28, 0xb5, 0xf5, 0x7a, 0x6e, 0xfd, 0x37, 0xd2, 0x68, 0xa8, 0x64, 0xcb, + 0x5c, 0xa3, 0x4b, 0xe2, 0x87, 0xe1, 0x04, 0x8e, 0xfc, 0x1e, 0x40, 0xcd, 0xf4, + 0xfc, 0xfc, 0x02, 0x4c, 0xf1, 0x82, 0x03, 0x8b, 0x9d, 0x80, 0xed, 0x1c, 0x07, + 0x63, 0x62, 0x00, 0xc8, 0x19, 0xa7, 0xe7, 0xc2, 0x40, 0xc3, 0xc4, 0xf7, 0xa9, + 0x17, 0x32, 0xe3, 0xff, 0x13, 0xe2, 0xa5, 0x6a, 0x64, 0x66, 0x66, 0x10, 0xca, + 0xd9, 0x84, 0x1c, 0x1a, 0x93, 0x4f, 0xe9, 0x33, 0xb0, 0xf1, 0x9f, 0xb7, 0x1d, + 0x06, 0x1c, 0x58, 0xf2, 0x1a, 0x49, 0x81, 0xce, 0x3e, 0x68, 0xc5, 0x02, 0x39, + 0x03, 0x60, 0x8d, 0xe5, 0x83, 0x02, 0xc6, 0xc8, 0xde, 0xf4, 0xe5, 0x61, 0x9e, + 0xc0, 0xd9, 0x1c, 0xf9, 0x35, 0x44, 0x75, 0x97, 0x2b, 0xfe, 0x0d, 0x75, 0x75, + 0x60, 0x2a, 0xaf, 0x0e, 0x9e, 0x88, 0x5c, 0x6b, 0xaf, 0x9d, 0x56, 0x7b, 0x1f, + 0xcb, 0x63, 0x19, 0x0c, 0xb7, 0x92, 0xf1, 0xd8, 0x71, 0x61, 0x1a, 0xdb, 0x4f, + 0x3d, 0x1e, 0xd3, 0x28, 0x02, 0x69, 0x18, 0xe2, 0x8d, 0x2f, 0xd4, 0x5a, 0xb9, + 0xd3, 0x70, 0xe7, 0x29, 0x2e, 0xd7, 0x54, 0xce, 0x29, 0xfb, 0x78, 0x7f, 0xd5, + 0xd0, 0x9e, 0x6d, 0x47, 0xcb, 0xc8, 0x00, 0x21, 0xab, 0xf7, 0xd2, 0xef, 0xeb, + 0xdb, 0xe0, 0xad, 0xd8, 0x70, 0x16, 0x8f, 0x51, 0xdc, 0xc4, 0x09, 0x57, 0xa4, + 0xa3, 0xc8, 0xe1, 0x92, 0x60, 0x13, 0x83, 0xb7, 0x68, 0x41, 0x36, 0xdc, 0xa2, + 0x82, 0x62, 0x3f, 0x31, 0xba, 0x7a, 0xe5, 0x36, 0x6b, 0x45, 0x3c, 0x6a, 0x26, + 0xf6, 0x8a, 0x14, 0xdb, 0x65, 0x59, 0xbc, 0xb1, 0x02, 0x37, 0x37, 0x9a, 0x27, + 0xa9, 0x50, 0x2f, 0xf9, 0xd6, 0x4a, 0x33, 0x83, 0x20, 0x75, 0x15, 0x30, 0xf1, + 0xf8, 0x92, 0xa6, 0xd4, 0x6f, 0x50, 0x31, 0x1b, 0x5e, 0x18, 0xf0, 0x33, 0x6f, + 0xc4, 0x77, 0x21, 0x56, 0x66, 0xe1, 0x88, 0x93, 0x3c, 0x69, 0x39, 0x98, 0x9f, + 0x6e, 0x6a, 0x3a, 0xdb, 0xa2, 0x29, 0x96, 0xaa, 0xe6, 0xa0, 0xfe, 0x1b, 0xdd, + 0xcb, 0xe1, 0x49, 0x6d, 0x96, 0x8d, 0xe0, 0x93, 0xdf, 0x44, 0xa3, 0x30, 0x0f, + 0x75, 0x15, 0xa1, 0x2c, 0x9d, 0x82, 0x22, 0x6d, 0x6b, 0x4d, 0x62, 0xc4, 0x6a, + 0x21, 0x3d, 0x5f, 0x01, 0x07, 0x10, 0x6f, 0xd2, 0xa2, 0x2d, 0x3b, 0x59, 0x86, + 0x13, 0xdb, 0x49, 0x1f, 0x70, 0xcc, 0xb1, 0xf0, 0x3b, 0x86, 0x59, 0x66, 0x9e, + 0xd7, 0x44, 0x34, 0xe4, 0x3b, 0x77, 0x1f, 0x22, 0x78, 0x07, 0x10, 0xfb, 0xd8, + 0xf2, 0xf2, 0x0e, 0x98, 0x97, 0xdf, 0x5c, 0xc2, 0x35, 0x48, 0x77, 0x9c, 0x6c, + 0x08, 0x30, 0x83, 0x9d, 0x23, 0x1c, 0x3f, 0xf9, 0xac, 0x54, 0x40, 0x7d, 0xfd, + 0xfc, 0xc5, 0x90, 0x14, 0xbf, 0x67, 0xd9, 0x68, 0x57, 0x06, 0xa5, 0x62, 0x2e, + 0x38, 0xf7, 0xa9, 0x33, 0xc3, 0x4a, 0xfb, 0xb6, 0xaa, 0x8c, 0xdf, 0xd9, 0x3b, + 0xd2, 0xec, 0x91, 0xad, 0x37, 0x90, 0x4c, 0xe1, 0x3b, 0x8a, 0xb8, 0xef, 0x77, + 0x23, 0x66, 0xfa, 0xd3, 0xc3, 0xeb, 0xee, 0x8f, 0x26, 0x11, 0xee, 0x7b, 0x6c, + 0x2a, 0xf7, 0xe6, 0x53, 0xef, 0xbe, 0xc4, 0xdc, 0x4c, 0xbf, 0x13, 0xac, 0xf3, + 0x7e, 0x39, 0x9e, 0x2b, 0x0b, 0x05, 0xb6, 0x1c, 0xb7, 0xe1, 0x7b, 0x15, 0x62, + 0x7b, 0x62, 0x96, 0x2e, 0x21, 0x00, 0xb1, 0x95, 0xfe, 0xfe, 0x94, 0xbc, 0x48, + 0x4e, 0x88, 0x13, 0x97, 0x00, 0x73, 0x7d, 0xe1, 0xa5, 0xec, 0x7d, 0x9c, 0xc8, + 0x5d, 0x53, 0x3b, 0x61, 0xec, 0xad, 0x86, 0x53, 0xce, 0xdb, 0xb7, 0x71, 0xf6, + 0x75, 0xaf, 0x61, 0xe4, 0xc6, 0xf7, 0xef, 0xaa, 0xcc, 0x9f, 0x7e, 0x42, 0x4c, + 0x16, 0x71, 0x5b, 0x0a, 0x98, 0xc4, 0x46, 0x05, 0x9a, 0x27, 0x1a, 0x27, 0xbd, + 0x56, 0x9d, 0x1b, 0x5d, 0xbf, 0xae, 0x8f, 0x53, 0x89, 0x85, 0x24, 0xca, 0xe8, + 0x70, 0x59, 0xff, 0x34, 0xfb, 0x2a, 0x53, 0x32, 0x26, 0xbd, 0x29, 0xa0, 0xba, + 0x6f, 0x8d, 0x08, 0x36, 0xfd, 0x0a, 0x4c, 0x0d, 0x60, 0x9a, 0x72, 0xe1, 0x05, + 0x39, 0xa4, 0x4f, 0x8c, 0x39, 0xf6, 0x27, 0x9b, 0xe3, 0x96, 0xe4, 0x1c, 0xa9, + 0xf2, 0x9a, 0x28, 0xce, 0x9f, 0xa0, 0xdd, 0x51, 0xa3, 0x02, 0xe7, 0x70, 0xe1, + 0xe3, 0xdb, 0x70, 0x6a, 0x34, 0xcb, 0x90, 0x4e, 0xf0, 0x8d, 0x9c, 0x82, 0xc5, + 0x5b, 0xc7, 0x28, 0xc9, 0x55, 0xb1, 0x20, 0xbb, 0x2e, 0xc3, 0x73, 0xfc, 0xff, + 0xff, 0x3c, 0x46, 0xd6, 0x03, 0xab, 0x38, 0x78, 0x96, 0xd4, 0x9c, 0xd2, 0x1b, + 0x2f, 0x77, 0xec, 0xfb, 0xbb, 0x02, 0xa5, 0xe1, 0x53, 0xb1, 0x71, 0xaf, 0xed, + 0x98, 0x6c, 0x15, 0xda, 0x6f, 0x2d, 0x4c, 0xf7, 0x45, 0xd1, 0x99, 0x5f, 0x51, + 0x36, 0xe1, 0xb3, 0xe6, 0x8a, 0x67, 0xa8, 0x99, 0x6f, 0xe7, 0x65, 0x61, 0x6d, + 0x8a, 0xa1, 0x1b, 0xcd, 0x9f, 0x8b, 0x59, 0x1d, 0xb8, 0x7e, 0xfc, 0xda, 0xaf, + 0xfd, 0x41, 0x00, 0x3e, 0xc7, 0x29, 0x36, 0x05, 0x42, 0x62, 0x08, 0x54, 0xfb, + 0x04, 0xb8, 0x0c, 0xb8, 0x61, 0xa6, 0x36, 0xa4, 0x71, 0x7d, 0x66, 0x68, 0x94, + 0xc3, 0x2f, 0x1f, 0x2b, 0xf2, 0x24, 0x7c, 0xc4, 0x15, 0xde, 0x1d, 0x0c, 0x4e, + 0x71, 0x2b, 0x95, 0x88, 0x42, 0xd6, 0xa4, 0xb2, 0x76, 0xde, 0xa5, 0xdb, 0x88, + 0x42, 0x3f, 0x2b, 0x4c, 0x66, 0x4b, 0x1d, 0x2b, 0x18, 0x77, 0xba, 0xf3, 0x37, + 0x47, 0x34, 0x36, 0x14, 0xe5, 0xeb, 0xe9, 0xb7, 0xe1, 0x2e, 0xd0, 0x15, 0x3f, + 0x9c, 0xa7, 0x45, 0x8e, 0x4d, 0xa4, 0x97, 0x63, 0x9d, 0xff, 0x13, 0x52, 0xff, + 0x0e, 0xfa, 0xe0, 0x1d, 0x14, 0x03, 0x21, 0xc2, 0x8d, 0xd0, 0xb6, 0x7b, 0x06, + 0x98, 0x90, 0xf6, 0x13, 0x0f, 0x82, 0x46, 0xab, 0x85, 0x44, 0x71, 0x75, 0x32, + 0xd3, 0xa5, 0xf6, 0x36, 0x39, 0xa9, 0x9d, 0x7f, 0x8e, 0x98, 0x31, 0xc6, 0x48, + 0x51, 0xb7, 0xef, 0x68, 0x93, 0xb3, 0xc9, 0x74, 0x0f, 0x98, 0x44, 0xd1, 0x8a, + 0x61, 0x3b, 0x5f, 0x9a, 0x6a, 0xb4, 0xbd, 0x6e, 0x6a, 0x93, 0xe8, 0xe4, 0xbe, + 0xa5, 0x57, 0x5d, 0x2c, 0xb4, 0x33, 0x0c, 0x0a, 0xf8, 0x55, 0x83, 0x19, 0xa9, + 0x09, 0xa5, 0x98, 0x8a, 0x99, 0x2e, 0x40, 0x63, 0x43, 0xdd, 0x1c, 0x74, 0x2d, + 0x64, 0xcd, 0x4a, 0x17, 0xa2, 0xf3, 0x79, 0x5e, 0x8d, 0xb4, 0xd3, 0x0c, 0xcd, + 0xf4, 0x41, 0x56, 0x55, 0xed, 0xa7, 0xb4, 0x37, 0xe3, 0x39, 0x73, 0x23, 0x89, + 0x6b, 0x11, 0xb1, 0xbe, 0xd7, 0x2d, 0x63, 0xe3, 0x10, 0xaa, 0x49, 0x67, 0x1d, + 0x85, 0x53, 0x4f, 0x6d, 0xbc, 0x18, 0x1f, 0xeb, 0xb5, 0xbd, 0xc0, 0x8a, 0xc0, + 0xd1, 0x23, 0x82, 0x9d, 0x10, 0x8c, 0xd2, 0x69, 0xf3, 0xb0, 0xa3, 0x96, 0xf4, + 0x24, 0x1e, 0x7d, 0xda, 0x72, 0xf5, 0x48, 0x62, 0xbe, 0xde, 0xf0, 0x1c, 0x12, + 0xe3, 0xc6, 0xcf, 0xdf, 0x75, 0xf6, 0x76, 0xc2, 0xdd, 0xef, 0x91, 0xaf, 0x7f, + 0x8a, 0x8a, 0x76, 0x9c, 0x25, 0xe1, 0x77, 0xcd, 0x43, 0x0b, 0xed, 0xe7, 0x4b, + 0x57, 0x69, 0x05, 0x19, 0xa9, 0x8d, 0xb1, 0xfb, 0x5c, 0x36, 0x12, 0x80, 0xf7, + 0x54, 0x0a, 0xc8, 0x27, 0xa9, 0x1b, 0x2d, 0x08, 0x75, 0x2d, 0xec, 0xfb, 0x71, + 0x56, 0xfc, 0xdb, 0x61, 0x75, 0x78, 0xb0, 0x53, 0xee, 0xe4, 0x1f, 0x66, 0xa6, + 0x0e, 0x04, 0x5c, 0x3a, 0x56, 0x9f, 0x3f, 0x7e, 0xdb, 0x76, 0x31, 0x68, 0x2f, + 0xde, 0x9e, 0xf9, 0x1e, 0xa8, 0x81, 0x1f, 0xc2, 0xc7, 0x8f, 0x64, 0x6a, 0xf6, + 0xb4, 0x71, 0x0e, 0xdb, 0xb8, 0xbf, 0x23, 0x28, 0xbd, 0x32, 0x73, 0xa2, 0xcb, + 0x72, 0xff, 0xcc, 0xa7, 0xc2, 0x17, 0xb8, 0x27, 0x19, 0x2d, 0xd2, 0xea, 0x92, + 0x9e, 0x97, 0x6d, 0x13, 0x1c, 0x9d, 0x20, 0x2e, 0xc5, 0x06, 0xa3, 0x5d, 0x93, + 0xab, 0x21, 0x6f, 0x64, 0xbd, 0x73, 0xfe, 0x5d, 0x8a, 0xba, 0xe4, 0x57, 0x1f, + 0x85, 0xbe, 0xb8, 0x4a, 0x7f, 0x93, 0xa3, 0xde, 0x37, 0xa4, 0x51, 0xf3, 0x08, + 0xf7, 0xde, 0x6c, 0xcd, 0x1a, 0x6e, 0xef, 0xef, 0x24, 0x69, 0x9f, 0x21, 0x58, + 0xd1, 0x26, 0x1f, 0xe2, 0x51, 0x82, 0xb5, 0x02, 0xda, 0x3e, 0x74, 0x61, 0x1a, + 0x61, 0x16, 0xfc, 0x30, 0x64, 0xfa, 0x72, 0x3c, 0x5a, 0x81, 0xad, 0xc0, 0xa3, + 0x2f, 0x1e, 0xd6, 0x29, 0x91, 0x57, 0xd1, 0xc1, 0x1c, 0x0a, 0xd9, 0x90, 0x41, + 0x89, 0x46, 0x96, 0x30, 0x1d, 0x5b, 0x3f, 0x1b, 0xf4, 0x32, 0x05, 0xd7, 0xdc, + 0xcf, 0xa6, 0x8b, 0xbb, 0x4a, 0x1f, 0x5e, 0x24, 0x2b, 0x3e, 0x69, 0x0b, 0xfc, + 0x97, 0xb9, 0x43, 0x66, 0xa3, 0x43, 0xf5, 0xdd, 0x16, 0xdf, 0x67, 0xb2, 0xed, + 0x2b, 0xe2, 0x1c, 0x74, 0x71, 0x18, 0x87, 0x2b, 0x46, 0x2e, 0xe2, 0x0c, 0x77, + 0x8c, 0xed, 0x85, 0x6f, 0xa9, 0x80, 0x40, 0x3f, 0xb2, 0x4b, 0x78, 0x61, 0x37, + 0xd0, 0xef, 0x02, 0x78, 0x53, 0x9b, 0x00, 0xce, 0x6e, 0x23, 0xc0, 0x7e, 0xf2, + 0xa0, 0x7c, 0xb2, 0x4c, 0x51, 0xc5, 0xb4, 0x85, 0xe4, 0x54, 0xed, 0xf6, 0x61, + 0xdb, 0x4b, 0x93, 0x1a, 0xb8, 0xcb, 0x49, 0x4e, 0xb3, 0x94, 0xfd, 0x13, 0xc1, + 0xb3, 0x20, 0x85, 0xf2, 0x7b, 0x20, 0x4a, 0x4b, 0x87, 0xee, 0x6c, 0x80, 0x63, + 0x45, 0xd7, 0x58, 0x4c, 0xb1, 0x61, 0x00, 0x6a, 0xd9, 0x84, 0x8a, 0x24, 0xa2, + 0x2a, 0x57, 0x71, 0xe3, 0xa2, 0xab, 0x65, 0x46, 0x3f, 0x55, 0x3d, 0x52, 0xcd, + 0x53, 0x5e, 0xf1, 0x0b, 0xdd, 0x40, 0xd8, 0x87, 0x73, 0x72, 0xa5, 0x32, 0xe3, + 0x73, 0x1b, 0x0e, 0xe9, 0x0c, 0x04, 0xe8, 0xe4, 0x37, 0x47, 0xcc, 0x3e, 0xb9, + 0x6b, 0xb8, 0x79, 0xbd, 0x94, 0xd7, 0x01, 0x2a, 0xf4, 0x6a, 0x93, 0xba, 0x17, + 0x70, 0x37, 0xf0, 0x62, 0x74, 0x4d, 0x3f, 0xdf, 0xcc, 0xd3, 0x6a, 0xab, 0xe0, + 0xf8, 0xcc, 0xca, 0x19, 0xdc, 0xf7, 0x84, 0x1b, 0x1e, 0xe2, 0xf4, 0xfe, 0xb1, + 0x80, 0x0e, 0x75, 0x44, 0x1c, 0x51, 0xe9, 0x5c, 0xce, 0x94, 0xce, 0xee, 0xcd, + 0x85, 0x87, 0xfb, 0xf5, 0x74, 0x30, 0x8d, 0xd7, 0x63, 0x63, 0x1b, 0x73, 0x35, + 0x78, 0x30, 0x91, 0xf4, 0xc8, 0xb3, 0xc8, 0xfb, 0x3c, 0xd9, 0x39, 0x70, 0xce, + 0xf0, 0xed, 0xa4, 0xca, 0x08, 0x44, 0x75, 0x68, 0x23, 0x9c, 0x02, 0xfe, 0x8f, + 0x67, 0x5e, 0x15, 0xc4, 0x9b, 0x51, 0x21, 0xb1, 0x00, 0xcc, 0x19, 0xfc, 0xc2, + 0xb2, 0x91, 0x3d, 0xf7, 0x4f, 0x75, 0x8f, 0x70, 0xbd, 0x6e, 0xeb, 0x73, 0x39, + 0x51, 0x6e, 0x5f, 0x1e, 0xff, 0x97, 0x00, 0xf8, 0xee, 0x13, 0x0e, 0x5c, 0x84, + 0xce, 0xd7, 0xb1, 0xce, 0xd6, 0x6b, 0xe9, 0xa0, 0x55, 0x96, 0xbe, 0x8e, 0x55, + 0xf6, 0xd9, 0xfd, 0xf7, 0xcf, 0x0f, 0xa6, 0x22, 0x90, 0xec, 0x67, 0x0b, 0x6b, + 0xdd, 0x67, 0x38, 0xbb, 0x5c, 0xfb, 0x34, 0x1e, 0xf5, 0xff, 0xb4, 0x2b, 0xc2, + 0xab, 0xc5, 0x08, 0xff, 0x23, 0x12, 0x48, 0xf2, 0xc2, 0xdc, 0x15, 0x77, 0x0d, + 0x33, 0x72, 0x2b, 0x9c, 0x9d, 0xae, + ], + script_code: Script(vec![0xac, 0x65]), + transparent_input: Some(0), + hash_type: 3, + amount: 391892287957268, + consensus_branch_id: consensus::BranchId::Sapling, + sighash: [ + 0x6a, 0x3b, 0x2b, 0xcc, 0x15, 0x57, 0x89, 0xa2, 0x74, 0x39, 0xaa, 0x27, 0x5c, + 0xa9, 0x9e, 0xc6, 0x48, 0xdd, 0xd5, 0x88, 0xe8, 0x2e, 0xfa, 0xe4, 0xac, 0x46, + 0xba, 0x3f, 0xd0, 0xe3, 0xbb, 0xa0, + ], + }, + ] + } +} From 865275e2a2f8a116cfba9666876d7c63d92df160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Thu, 16 Jan 2020 07:36:29 -0800 Subject: [PATCH 314/330] Correcting some trivial Rust option/iterator warts --- bellman/src/gadgets/blake2s.rs | 4 ++-- librustzcash/src/rustzcash.rs | 21 +++++---------------- zcash_client_backend/src/welding_rig.rs | 3 +-- zcash_primitives/src/block/equihash.rs | 22 +++++++++++----------- zcash_primitives/src/jubjub/edwards.rs | 6 ++---- zcash_primitives/src/merkle_tree.rs | 10 ++-------- zcash_primitives/src/redjubjub.rs | 9 ++------- zcash_primitives/src/transaction/tests.rs | 20 ++++++++------------ zcash_proofs/src/sapling/prover.rs | 12 ++++-------- 9 files changed, 37 insertions(+), 70 deletions(-) diff --git a/bellman/src/gadgets/blake2s.rs b/bellman/src/gadgets/blake2s.rs index 8b1ff54..79c42e4 100644 --- a/bellman/src/gadgets/blake2s.rs +++ b/bellman/src/gadgets/blake2s.rs @@ -582,7 +582,7 @@ mod test { let expected = hex!("0af5695115ced92c8a0341e43869209636e9aa6472e4576f0f2b996cf812b30e"); let mut out = r.into_iter(); - for b in expected.into_iter() { + for b in expected.iter() { for i in 0..8 { let c = out.next().unwrap().get_value().unwrap(); @@ -619,7 +619,7 @@ mod test { let expected = hex!("2ab8f0683167ba220eef19dccf4f9b1a8193cc09b35e0235842323950530f18a"); let mut out = r.into_iter(); - for b in expected.into_iter() { + for b in expected.iter() { for i in 0..8 { let c = out.next().unwrap().get_value().unwrap(); diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 6dadf67..9878bec 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -402,26 +402,15 @@ fn priv_get_note( r: *const [c_uchar; 32], ) -> Result, ()> { let diversifier = Diversifier(unsafe { *diversifier }); - let g_d = match diversifier.g_d::(&JUBJUB) { - Some(g_d) => g_d, - None => return Err(()), - }; + let g_d = diversifier.g_d::(&JUBJUB).ok_or(())?; - let pk_d = match edwards::Point::::read(&(unsafe { &*pk_d })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return Err(()), - }; + let pk_d = edwards::Point::::read(&(unsafe { &*pk_d })[..], &JUBJUB) + .map_err(|_| ())?; - let pk_d = match pk_d.as_prime_order(&JUBJUB) { - Some(pk_d) => pk_d, - None => return Err(()), - }; + let pk_d = pk_d.as_prime_order(&JUBJUB).ok_or(())?; // Deserialize randomness - let r = match Fs::from_repr(read_fs(unsafe { &*r })) { - Ok(r) => r, - Err(_) => return Err(()), - }; + let r = Fs::from_repr(read_fs(unsafe { &*r })).map_err(|_| ())?; let note = Note { value, diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs index 75ed47f..14939d7 100644 --- a/zcash_client_backend/src/welding_rig.rs +++ b/zcash_client_backend/src/welding_rig.rs @@ -134,12 +134,11 @@ pub fn scan_block( // mutable references to wtxs for too long. let mut block_witnesses: Vec<_> = wtxs .iter_mut() - .map(|tx| { + .flat_map(|tx| { tx.shielded_outputs .iter_mut() .map(|output| &mut output.witness) }) - .flatten() .collect(); for to_scan in tx.outputs.into_iter().enumerate() { diff --git a/zcash_primitives/src/block/equihash.rs b/zcash_primitives/src/block/equihash.rs index 5d40465..38518ba 100644 --- a/zcash_primitives/src/block/equihash.rs +++ b/zcash_primitives/src/block/equihash.rs @@ -255,18 +255,18 @@ fn tree_validator(p: &Params, state: &Blake2bState, indices: &[u32]) -> Option 1 { let end = indices.len(); let mid = end / 2; - match tree_validator(p, state, &indices[0..mid]) { - Some(a) => match tree_validator(p, state, &indices[mid..end]) { - Some(b) => { - if validate_subtrees(p, &a, &b) { - Some(Node::from_children(a, b, p.collision_byte_length())) - } else { - None - } + match ( + tree_validator(p, state, &indices[0..mid]), + tree_validator(p, state, &indices[mid..end]), + ) { + (Some(a), Some(b)) => { + if validate_subtrees(p, &a, &b) { + Some(Node::from_children(a, b, p.collision_byte_length())) + } else { + None } - None => None, - }, - None => None, + } + _ => None, } } else { Some(Node::new(&p, &state, indices[0])) diff --git a/zcash_primitives/src/jubjub/edwards.rs b/zcash_primitives/src/jubjub/edwards.rs index 9902d80..7e46912 100644 --- a/zcash_primitives/src/jubjub/edwards.rs +++ b/zcash_primitives/src/jubjub/edwards.rs @@ -89,10 +89,8 @@ impl Point { y_repr.as_mut()[3] &= 0x7fffffffffffffff; match E::Fr::from_repr(y_repr) { - Ok(y) => match Self::get_for_y(y, x_sign, params) { - Some(p) => Ok(p), - None => Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve")), - }, + Ok(y) => Self::get_for_y(y, x_sign, params) + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "not on curve")), Err(_) => Err(io::Error::new( io::ErrorKind::InvalidInput, "y is not in field", diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index b8abf11..d41f05c 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -164,14 +164,8 @@ impl CommitmentTree { // - Empty leaves are used as needed. let leaf_root = Node::combine( 0, - &match self.left { - Some(node) => node, - None => filler.next(0), - }, - &match self.right { - Some(node) => node, - None => filler.next(0), - }, + &self.left.unwrap_or_else(|| filler.next(0)), + &self.right.unwrap_or_else(|| filler.next(0)), ); // 2) Hash in parents up to the currently-filled depth. diff --git a/zcash_primitives/src/redjubjub.rs b/zcash_primitives/src/redjubjub.rs index 187ebd3..505d6cc 100644 --- a/zcash_primitives/src/redjubjub.rs +++ b/zcash_primitives/src/redjubjub.rs @@ -14,13 +14,8 @@ fn read_scalar(reader: R) -> io::Result { let mut s_repr = ::Repr::default(); s_repr.read_le(reader)?; - match E::Fs::from_repr(s_repr) { - Ok(s) => Ok(s), - Err(_) => Err(io::Error::new( - io::ErrorKind::InvalidInput, - "scalar is not in field", - )), - } + E::Fs::from_repr(s_repr) + .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "scalar is not in field")) } fn write_scalar(s: &E::Fs, writer: W) -> io::Result<()> { diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs index 392144b..2fc267c 100644 --- a/zcash_primitives/src/transaction/tests.rs +++ b/zcash_primitives/src/transaction/tests.rs @@ -75,15 +75,13 @@ mod data; fn zip_0143() { for tv in self::data::zip_0143::make_test_vectors() { let tx = Transaction::read(&tv.tx[..]).unwrap(); - let transparent_input = if let Some(n) = tv.transparent_input { - Some(( + let transparent_input = tv.transparent_input.map(|n| { + ( n as usize, &tv.script_code, Amount::from_nonnegative_i64(tv.amount).unwrap(), - )) - } else { - None - }; + ) + }); assert_eq!( signature_hash(&tx, tv.consensus_branch_id, tv.hash_type, transparent_input), @@ -96,15 +94,13 @@ fn zip_0143() { fn zip_0243() { for tv in self::data::zip_0243::make_test_vectors() { let tx = Transaction::read(&tv.tx[..]).unwrap(); - let transparent_input = if let Some(n) = tv.transparent_input { - Some(( + let transparent_input = tv.transparent_input.map(|n| { + ( n as usize, &tv.script_code, Amount::from_nonnegative_i64(tv.amount).unwrap(), - )) - } else { - None - }; + ) + }); assert_eq!( signature_hash(&tx, tv.consensus_branch_id, tv.hash_type, transparent_input), diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index 8067069..be73ded 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -83,10 +83,9 @@ impl SaplingProvingContext { let viewing_key = proof_generation_key.to_viewing_key(params); // Construct the payment address with the viewing key / diversifier - let payment_address = match viewing_key.to_payment_address(diversifier, params) { - Some(p) => p, - None => return Err(()), - }; + let payment_address = viewing_key + .to_payment_address(diversifier, params) + .ok_or(())?; // This is the result of the re-randomization, we compute it for the caller let rk = PublicKey::(proof_generation_key.ak.clone().into()).randomize( @@ -266,10 +265,7 @@ impl SaplingProvingContext { // against our derived bvk. { // Compute value balance - let mut value_balance = match compute_value_balance(value_balance, params) { - Some(a) => a, - None => return Err(()), - }; + let mut value_balance = compute_value_balance(value_balance, params).ok_or(())?; // Subtract value_balance from cv_sum to get final bvk value_balance = value_balance.negate(); From 1f38523fffe859f89d59adacfb91957c8b2cb32f Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Mon, 3 Feb 2020 18:08:56 +0000 Subject: [PATCH 315/330] CI: Use stable Rust release for code coverage Fixes an issue where cargo-tarpaulin failed to build the crate on 1.37.0, but the crate itself builds fine with that version. --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a76eb46..1ada7e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,9 +69,10 @@ jobs: steps: - uses: actions/checkout@v1 + # Use stable for this to ensure that cargo-tarpaulin can be built. - uses: actions-rs/toolchain@v1 with: - toolchain: 1.37.0 + toolchain: stable override: true - name: Install cargo-tarpaulin uses: actions-rs/cargo@v1 From 2064d1c8014e1d68f6273f27e87b710c462fed91 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 7 Feb 2020 00:06:57 +0000 Subject: [PATCH 316/330] Refactor zcash_primitives::merkle_tree::CommitmentTreeWitness - The internal Option wrapper was an unnecessary leftover from when this code was directly inside the prover, where Some(x) represents an assigned variable. - CommitmentTreeWitness::from_slice_with_depth is more idiomatic Rust. --- zcash_primitives/src/merkle_tree.rs | 71 +++++++++++++---------------- zcash_proofs/src/sapling/prover.rs | 2 +- 2 files changed, 33 insertions(+), 40 deletions(-) diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index d41f05c..8b2b370 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -385,9 +385,9 @@ impl IncrementalWitness { if let Some(node) = self.tree.left { if self.tree.right.is_some() { - auth_path.push(Some((node, true))); + auth_path.push((node, true)); } else { - auth_path.push(Some((filler.next(0), false))); + auth_path.push((filler.next(0), false)); } } else { // Can't create an authentication path for the beginning of the tree @@ -396,13 +396,13 @@ impl IncrementalWitness { for (i, p) in self.tree.parents.iter().enumerate() { auth_path.push(match p { - Some(node) => Some((*node, true)), - None => Some((filler.next(i + 1), false)), + Some(node) => (*node, true), + None => (filler.next(i + 1), false), }); } for i in self.tree.parents.len()..(depth - 1) { - auth_path.push(Some((filler.next(i + 1), false))); + auth_path.push((filler.next(i + 1), false)); } assert_eq!(auth_path.len(), depth); @@ -417,13 +417,13 @@ impl IncrementalWitness { /// that tree. #[derive(Clone, Debug, PartialEq)] pub struct CommitmentTreeWitness { - pub auth_path: Vec>, + pub auth_path: Vec<(Node, bool)>, pub position: u64, } impl CommitmentTreeWitness { /// Constructs a witness directly from its path and position. - pub fn from_path(auth_path: Vec>, position: u64) -> Self { + pub fn from_path(auth_path: Vec<(Node, bool)>, position: u64) -> Self { CommitmentTreeWitness { auth_path, position, @@ -444,48 +444,41 @@ impl CommitmentTreeWitness { witness = &witness[1..]; // Begin to construct the authentication path - let mut auth_path = vec![None; depth]; + let iter = witness.chunks_exact(33); + witness = iter.remainder(); // The vector works in reverse - for i in (0..depth).rev() { - // skip length of inner vector - if witness[0] != 32 { - // the length of a pedersen hash - return Err(()); - } - witness = &witness[1..]; - - // Grab the sibling node at this depth in the tree - let mut sibling = [0u8; 32]; - sibling.copy_from_slice(&witness[0..32]); - witness = &witness[32..]; - - // Sibling node should be an element of Fr - let sibling = match Node::read(&sibling[..]) { - Ok(p) => p, - Err(_) => return Err(()), - }; - - // Set the value in the auth path; we put false here - // for now (signifying the position bit) which we'll - // fill in later. - auth_path[i] = Some((sibling, false)); + let mut auth_path = iter + .rev() + .map(|bytes| { + // Length of inner vector should be the length of a Pedersen hash + if bytes[0] == 32 { + // Sibling node should be an element of Fr + Node::read(&bytes[1..]) + .map(|sibling| { + // Set the value in the auth path; we put false here + // for now (signifying the position bit) which we'll + // fill in later. + (sibling, false) + }) + .map_err(|_| ()) + } else { + Err(()) + } + }) + .collect::, _>>()?; + if auth_path.len() != depth { + return Err(()); } // Read the position from the witness - let position = match witness.read_u64::() { - Ok(pos) => pos, - Err(_) => return Err(()), - }; + let position = witness.read_u64::().map_err(|_| ())?; // Given the position, let's finish constructing the authentication // path let mut tmp = position; for entry in auth_path.iter_mut() { - if let Some(p) = entry { - p.1 = (tmp & 1) == 1; - } - + entry.1 = (tmp & 1) == 1; tmp >>= 1; } diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index be73ded..6bf43d3 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -117,7 +117,7 @@ impl SaplingProvingContext { auth_path: witness .auth_path .iter() - .map(|n| n.map(|(node, b)| (node.into(), b))) + .map(|(node, b)| Some(((*node).into(), *b))) .collect(), anchor: Some(anchor), }; From 8a210ec271a479fe23cb62a55c7377bc54ae1d1b Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 7 Feb 2020 17:21:59 +0000 Subject: [PATCH 317/330] CommitmentTreeWitness::root(leaf) --- zcash_primitives/src/merkle_tree.rs | 34 +++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 8b2b370..016f2a3 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -494,6 +494,20 @@ impl CommitmentTreeWitness { Err(()) } } + + /// Returns the root of the tree corresponding to the witness. + pub fn root(&self, leaf: Node) -> Node { + self.auth_path + .iter() + .enumerate() + .fold( + leaf, + |root, (i, (p, leaf_is_on_right))| match leaf_is_on_right { + false => Node::combine(i, &root, p), + true => Node::combine(i, p, &root), + }, + ) + } } #[cfg(test)] @@ -1002,6 +1016,7 @@ mod tests { assert_eq!(tree.size(), 0); let mut witnesses = vec![]; + let mut last_cm = None; let mut paths_i = 0; let mut witness_ser_i = 0; for i in 0..16 { @@ -1012,7 +1027,7 @@ mod tests { let cm = Node::new(cm); // Witness here - witnesses.push(TestIncrementalWitness::from_tree(&tree)); + witnesses.push((TestIncrementalWitness::from_tree(&tree), last_cm)); // Now append a commitment to the tree assert!(tree.append(cm).is_ok()); @@ -1026,14 +1041,11 @@ mod tests { // Check serialization of tree assert_tree_ser_eq(&tree, tree_ser[i]); - let mut first = true; // The first witness can never form a path - for witness in witnesses.as_mut_slice() { + for (witness, leaf) in witnesses.as_mut_slice() { // Append the same commitment to all the witnesses assert!(witness.append(cm).is_ok()); - if first { - assert!(witness.path().is_none()); - } else { + if let Some(leaf) = leaf { let path = witness.path().expect("should be able to create a path"); let expected = CommitmentTreeWitness::from_slice_with_depth( &mut hex::decode(paths[paths_i]).unwrap(), @@ -1041,7 +1053,11 @@ mod tests { ) .unwrap(); assert_eq!(path, expected); + assert_eq!(path.root(*leaf), witness.root()); paths_i += 1; + } else { + // The first witness can never form a path + assert!(witness.path().is_none()); } // Check witness serialization @@ -1049,15 +1065,15 @@ mod tests { witness_ser_i += 1; assert_eq!(witness.root(), tree.root()); - - first = false; } + + last_cm = Some(cm); } // Tree should be full now let node = Node::blank(); assert!(tree.append(node).is_err()); - for witness in witnesses.as_mut_slice() { + for (witness, _) in witnesses.as_mut_slice() { assert!(witness.append(node).is_err()); } } From 3a3008caf9b6e43800f9a7ab5a6b224f7b9de6d7 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 7 Feb 2020 17:31:38 +0000 Subject: [PATCH 318/330] Pass CommitmentTreeWitness directly into Builder::add_sapling_spend This is more likely to be the data that the caller has available, and is all we need now that a CommitmentTreeWitness can compute its root. --- zcash_primitives/src/transaction/builder.rs | 22 ++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index ce0bfe9..4a6246c 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -13,7 +13,7 @@ use crate::{ consensus, keys::OutgoingViewingKey, legacy::TransparentAddress, - merkle_tree::{CommitmentTreeWitness, IncrementalWitness}, + merkle_tree::CommitmentTreeWitness, note_encryption::{generate_esk, Memo, SaplingNoteEncryption}, prover::TxProver, redjubjub::PrivateKey, @@ -44,7 +44,6 @@ pub enum Error { ChangeIsNegative(Amount), InvalidAddress, InvalidAmount, - InvalidWitness, NoChangeAddress, SpendProof, } @@ -342,18 +341,18 @@ impl Builder { extsk: ExtendedSpendingKey, diversifier: Diversifier, note: Note, - witness: IncrementalWitness, + witness: CommitmentTreeWitness, ) -> Result<(), Error> { // Consistency check: all anchors must equal the first one + let cm = Node::new(note.cm(&JUBJUB).into()); if let Some(anchor) = self.anchor { - let witness_root: Fr = witness.root().into(); + let witness_root: Fr = witness.root(cm).into(); if witness_root != anchor { return Err(Error::AnchorMismatch); } } else { - self.anchor = Some(witness.root().into()) + self.anchor = Some(witness.root(cm).into()) } - let witness = witness.path().ok_or(Error::InvalidWitness)?; let alpha = Fs::random(&mut self.rng); @@ -779,7 +778,7 @@ mod tests { extsk.clone(), *to.diversifier(), note1.clone(), - witness1.clone(), + witness1.path().unwrap(), ) .unwrap(); builder @@ -816,10 +815,15 @@ mod tests { { let mut builder = Builder::new(0); builder - .add_sapling_spend(extsk.clone(), *to.diversifier(), note1, witness1) + .add_sapling_spend( + extsk.clone(), + *to.diversifier(), + note1, + witness1.path().unwrap(), + ) .unwrap(); builder - .add_sapling_spend(extsk, *to.diversifier(), note2, witness2) + .add_sapling_spend(extsk, *to.diversifier(), note2, witness2.path().unwrap()) .unwrap(); builder .add_sapling_output(ovk, to, Amount::from_u64(30000).unwrap(), None) From 76e0f658c1b80e4c2dbe632a5252dbea0a29c377 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 8 Feb 2020 00:25:24 +0000 Subject: [PATCH 319/330] Rename CommitmentTreeWitness -> MerklePath --- librustzcash/src/rustzcash.rs | 11 ++++--- zcash_primitives/src/merkle_tree.rs | 32 +++++++++------------ zcash_primitives/src/prover.rs | 8 +++--- zcash_primitives/src/transaction/builder.rs | 22 +++++++------- zcash_proofs/src/prover.rs | 6 ++-- zcash_proofs/src/sapling/prover.rs | 8 +++--- 6 files changed, 41 insertions(+), 46 deletions(-) diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 9878bec..084d5b0 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -50,7 +50,7 @@ use zcash_primitives::{ fs::{Fs, FsRepr}, FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder, ToUniform, Unknown, }, - merkle_tree::CommitmentTreeWitness, + merkle_tree::MerklePath, note_encryption::sapling_ka_agree, primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ViewingKey}, redjubjub::{self, Signature}, @@ -980,7 +980,7 @@ pub extern "C" fn librustzcash_sapling_spend_proof( ar: *const [c_uchar; 32], value: u64, anchor: *const [c_uchar; 32], - witness: *const [c_uchar; 1 + 33 * SAPLING_TREE_DEPTH + 8], + merkle_path: *const [c_uchar; 1 + 33 * SAPLING_TREE_DEPTH + 8], cv: *mut [c_uchar; 32], rk_out: *mut [c_uchar; 32], zkproof: *mut [c_uchar; GROTH_PROOF_SIZE], @@ -1030,9 +1030,8 @@ pub extern "C" fn librustzcash_sapling_spend_proof( Err(_) => return false, }; - // The witness contains the incremental tree witness information, in a - // weird serialized format. - let witness = match CommitmentTreeWitness::from_slice(unsafe { &(&*witness)[..] }) { + // Parse the Merkle path from the caller + let merkle_path = match MerklePath::from_slice(unsafe { &(&*merkle_path)[..] }) { Ok(w) => w, Err(_) => return false, }; @@ -1046,7 +1045,7 @@ pub extern "C" fn librustzcash_sapling_spend_proof( ar, value, anchor, - witness, + merkle_path, unsafe { SAPLING_SPEND_PARAMS.as_ref() }.unwrap(), unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap(), &JUBJUB, diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs index 016f2a3..53600e5 100644 --- a/zcash_primitives/src/merkle_tree.rs +++ b/zcash_primitives/src/merkle_tree.rs @@ -375,11 +375,11 @@ impl IncrementalWitness { } /// Returns the current witness, or None if the tree is empty. - pub fn path(&self) -> Option> { + pub fn path(&self) -> Option> { self.path_inner(SAPLING_COMMITMENT_TREE_DEPTH) } - fn path_inner(&self, depth: usize) -> Option> { + fn path_inner(&self, depth: usize) -> Option> { let mut filler = self.filler(); let mut auth_path = Vec::new(); @@ -406,31 +406,27 @@ impl IncrementalWitness { } assert_eq!(auth_path.len(), depth); - Some(CommitmentTreeWitness::from_path( - auth_path, - self.position() as u64, - )) + Some(MerklePath::from_path(auth_path, self.position() as u64)) } } -/// A witness to a path from a position in a particular commitment tree to the root of -/// that tree. +/// A path from a position in a particular commitment tree to the root of that tree. #[derive(Clone, Debug, PartialEq)] -pub struct CommitmentTreeWitness { +pub struct MerklePath { pub auth_path: Vec<(Node, bool)>, pub position: u64, } -impl CommitmentTreeWitness { - /// Constructs a witness directly from its path and position. +impl MerklePath { + /// Constructs a Merkle path directly from a path and position. pub fn from_path(auth_path: Vec<(Node, bool)>, position: u64) -> Self { - CommitmentTreeWitness { + MerklePath { auth_path, position, } } - /// Reads a witness from its serialized form. + /// Reads a Merkle path from its serialized form. pub fn from_slice(witness: &[u8]) -> Result { Self::from_slice_with_depth(witness, SAPLING_COMMITMENT_TREE_DEPTH) } @@ -486,7 +482,7 @@ impl CommitmentTreeWitness { // have provided more information than they should have, indicating // a bug downstream if witness.is_empty() { - Ok(CommitmentTreeWitness { + Ok(MerklePath { auth_path, position, }) @@ -495,7 +491,7 @@ impl CommitmentTreeWitness { } } - /// Returns the root of the tree corresponding to the witness. + /// Returns the root of the tree corresponding to this path applied to `leaf`. pub fn root(&self, leaf: Node) -> Node { self.auth_path .iter() @@ -512,7 +508,7 @@ impl CommitmentTreeWitness { #[cfg(test)] mod tests { - use super::{CommitmentTree, CommitmentTreeWitness, Hashable, IncrementalWitness, PathFiller}; + use super::{CommitmentTree, Hashable, IncrementalWitness, MerklePath, PathFiller}; use crate::sapling::Node; use ff::PrimeFieldRepr; @@ -611,7 +607,7 @@ mod tests { self.0.root_inner(TESTING_DEPTH) } - fn path(&self) -> Option> { + fn path(&self) -> Option> { self.0.path_inner(TESTING_DEPTH) } } @@ -1047,7 +1043,7 @@ mod tests { if let Some(leaf) = leaf { let path = witness.path().expect("should be able to create a path"); - let expected = CommitmentTreeWitness::from_slice_with_depth( + let expected = MerklePath::from_slice_with_depth( &mut hex::decode(paths[paths_i]).unwrap(), TESTING_DEPTH, ) diff --git a/zcash_primitives/src/prover.rs b/zcash_primitives/src/prover.rs index d071816..932573d 100644 --- a/zcash_primitives/src/prover.rs +++ b/zcash_primitives/src/prover.rs @@ -7,7 +7,7 @@ use crate::{ use pairing::bls12_381::{Bls12, Fr}; use crate::{ - merkle_tree::CommitmentTreeWitness, + merkle_tree::MerklePath, redjubjub::{PublicKey, Signature}, sapling::Node, transaction::components::{Amount, GROTH_PROOF_SIZE}, @@ -35,7 +35,7 @@ pub trait TxProver { ar: Fs, value: u64, anchor: Fr, - witness: CommitmentTreeWitness, + merkle_path: MerklePath, ) -> Result< ( [u8; GROTH_PROOF_SIZE], @@ -82,7 +82,7 @@ pub(crate) mod mock { }; use crate::{ - merkle_tree::CommitmentTreeWitness, + merkle_tree::MerklePath, redjubjub::{PublicKey, Signature}, sapling::Node, transaction::components::{Amount, GROTH_PROOF_SIZE}, @@ -108,7 +108,7 @@ pub(crate) mod mock { ar: Fs, value: u64, _anchor: Fr, - _witness: CommitmentTreeWitness, + _merkle_path: MerklePath, ) -> Result< ( [u8; GROTH_PROOF_SIZE], diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index 4a6246c..ba2be5b 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -13,7 +13,7 @@ use crate::{ consensus, keys::OutgoingViewingKey, legacy::TransparentAddress, - merkle_tree::CommitmentTreeWitness, + merkle_tree::MerklePath, note_encryption::{generate_esk, Memo, SaplingNoteEncryption}, prover::TxProver, redjubjub::PrivateKey, @@ -53,7 +53,7 @@ struct SpendDescriptionInfo { diversifier: Diversifier, note: Note, alpha: Fs, - witness: CommitmentTreeWitness, + merkle_path: MerklePath, } pub struct SaplingOutput { @@ -334,24 +334,24 @@ impl Builder { /// Adds a Sapling note to be spent in this transaction. /// - /// Returns an error if the given witness does not have the same anchor as previous - /// witnesses, or has no path. + /// Returns an error if the given Merkle path does not have the same anchor as the + /// paths for previous Sapling notes. pub fn add_sapling_spend( &mut self, extsk: ExtendedSpendingKey, diversifier: Diversifier, note: Note, - witness: CommitmentTreeWitness, + merkle_path: MerklePath, ) -> Result<(), Error> { // Consistency check: all anchors must equal the first one let cm = Node::new(note.cm(&JUBJUB).into()); if let Some(anchor) = self.anchor { - let witness_root: Fr = witness.root(cm).into(); - if witness_root != anchor { + let path_root: Fr = merkle_path.root(cm).into(); + if path_root != anchor { return Err(Error::AnchorMismatch); } } else { - self.anchor = Some(witness.root(cm).into()) + self.anchor = Some(merkle_path.root(cm).into()) } let alpha = Fs::random(&mut self.rng); @@ -363,7 +363,7 @@ impl Builder { diversifier, note, alpha, - witness, + merkle_path, }); Ok(()) @@ -521,7 +521,7 @@ impl Builder { let mut nullifier = [0u8; 32]; nullifier.copy_from_slice(&spend.note.nf( &proof_generation_key.to_viewing_key(&JUBJUB), - spend.witness.position, + spend.merkle_path.position, &JUBJUB, )); @@ -534,7 +534,7 @@ impl Builder { spend.alpha, spend.note.value, anchor, - spend.witness.clone(), + spend.merkle_path.clone(), ) .map_err(|()| Error::SpendProof)?; diff --git a/zcash_proofs/src/prover.rs b/zcash_proofs/src/prover.rs index 6dd5767..c4608f7 100644 --- a/zcash_proofs/src/prover.rs +++ b/zcash_proofs/src/prover.rs @@ -9,7 +9,7 @@ use zcash_primitives::{ primitives::{Diversifier, PaymentAddress, ProofGenerationKey}, }; use zcash_primitives::{ - merkle_tree::CommitmentTreeWitness, + merkle_tree::MerklePath, prover::TxProver, redjubjub::{PublicKey, Signature}, sapling::Node, @@ -127,7 +127,7 @@ impl TxProver for LocalTxProver { ar: Fs, value: u64, anchor: Fr, - witness: CommitmentTreeWitness, + merkle_path: MerklePath, ) -> Result< ( [u8; GROTH_PROOF_SIZE], @@ -143,7 +143,7 @@ impl TxProver for LocalTxProver { ar, value, anchor, - witness, + merkle_path, &self.spend_params, &self.spend_vk, &JUBJUB, diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs index 6bf43d3..32e4229 100644 --- a/zcash_proofs/src/sapling/prover.rs +++ b/zcash_proofs/src/sapling/prover.rs @@ -10,7 +10,7 @@ use zcash_primitives::{ primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, }; use zcash_primitives::{ - merkle_tree::CommitmentTreeWitness, + merkle_tree::MerklePath, redjubjub::{PrivateKey, PublicKey, Signature}, sapling::Node, transaction::components::Amount, @@ -46,7 +46,7 @@ impl SaplingProvingContext { ar: Fs, value: u64, anchor: Fr, - witness: CommitmentTreeWitness, + merkle_path: MerklePath, proving_key: &Parameters, verifying_key: &PreparedVerifyingKey, params: &JubjubBls12, @@ -104,7 +104,7 @@ impl SaplingProvingContext { r: rcm, }; - let nullifier = note.nf(&viewing_key, witness.position, params); + let nullifier = note.nf(&viewing_key, merkle_path.position, params); // We now have the full witness for our circuit let instance = Spend { @@ -114,7 +114,7 @@ impl SaplingProvingContext { payment_address: Some(payment_address), commitment_randomness: Some(rcm), ar: Some(ar), - auth_path: witness + auth_path: merkle_path .auth_path .iter() .map(|(node, b)| Some(((*node).into(), *b))) From 2d30c29d0651556f9be8fbe08414e7b51fa529bf Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 8 Feb 2020 00:37:31 +0000 Subject: [PATCH 320/330] Pass &impl TxProver to Builder::build This allows the caller to build multiple transactions with a single proving backend. --- zcash_primitives/src/transaction/builder.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/zcash_primitives/src/transaction/builder.rs b/zcash_primitives/src/transaction/builder.rs index ba2be5b..9acb996 100644 --- a/zcash_primitives/src/transaction/builder.rs +++ b/zcash_primitives/src/transaction/builder.rs @@ -435,7 +435,7 @@ impl Builder { pub fn build( mut self, consensus_branch_id: consensus::BranchId, - prover: impl TxProver, + prover: &impl TxProver, ) -> Result<(Transaction, TransactionMetadata), Error> { let mut tx_metadata = TransactionMetadata::new(); @@ -558,7 +558,7 @@ impl Builder { // Record the post-randomized output location tx_metadata.output_indices[pos] = i; - output.build(&prover, &mut ctx, &mut self.rng) + output.build(prover, &mut ctx, &mut self.rng) } else { // This is a dummy output let (dummy_to, dummy_note) = { @@ -718,7 +718,7 @@ mod tests { { let builder = Builder::new(0); assert_eq!( - builder.build(consensus::BranchId::Sapling, MockTxProver), + builder.build(consensus::BranchId::Sapling, &MockTxProver), Err(Error::ChangeIsNegative(Amount::from_i64(-10000).unwrap())) ); } @@ -740,7 +740,7 @@ mod tests { ) .unwrap(); assert_eq!( - builder.build(consensus::BranchId::Sapling, MockTxProver), + builder.build(consensus::BranchId::Sapling, &MockTxProver), Err(Error::ChangeIsNegative(Amount::from_i64(-60000).unwrap())) ); } @@ -756,7 +756,7 @@ mod tests { ) .unwrap(); assert_eq!( - builder.build(consensus::BranchId::Sapling, MockTxProver), + builder.build(consensus::BranchId::Sapling, &MockTxProver), Err(Error::ChangeIsNegative(Amount::from_i64(-60000).unwrap())) ); } @@ -796,7 +796,7 @@ mod tests { ) .unwrap(); assert_eq!( - builder.build(consensus::BranchId::Sapling, MockTxProver), + builder.build(consensus::BranchId::Sapling, &MockTxProver), Err(Error::ChangeIsNegative(Amount::from_i64(-1).unwrap())) ); } @@ -835,7 +835,7 @@ mod tests { ) .unwrap(); assert_eq!( - builder.build(consensus::BranchId::Sapling, MockTxProver), + builder.build(consensus::BranchId::Sapling, &MockTxProver), Err(Error::BindingSig) ) } From d7f78db121ee6f720e97401ded0c9c597d1a4857 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 3 Mar 2020 17:43:16 -0700 Subject: [PATCH 321/330] Squashed 'ff/' changes from 661558e..ddff465 ddff465 Bump version and dependency on ff_derive 25d11d6 Bump version 95e2723 Bump version to 0.5.1 f76872a Add ?Sized to RngCore trait bounds (#14) 09a32b1 ff 0.5.0 32543ab Crate docs 22031dc Update READMEs 658fe6d CI: Check intra-doc links 35f5026 Add READMEs to Cargo.toml files 6804225 Migrate ff_derive to proc-macro2 1.0 b9a79ce cargo fmt 82574c2 cargo fix --edition-idioms for ff 3b0cf72 Add edition = 2018 8a2b51b Replace try! macro 40fc9ba cargo fix --edition for ff 22c67f3 cargo fmt 312141c Clarify masking of bits in Field::random impls 89a68e1 Migrate to rand 0.7 58415fb Migrate ff, group, pairing, and bellman to rand 0.6 8b6e6b1 Migrate ff to rand_core 0.3 (used by rand 0.5) git-subtree-dir: ff git-subtree-split: ddff4658ddd7496bb29cc636c391b7aaaca24673 --- Cargo.toml | 11 ++- README.md | 17 ++-- ff_derive/Cargo.toml | 12 ++- ff_derive/src/lib.rs | 182 +++++++++++++++++++++---------------------- src/lib.rs | 18 +++-- 5 files changed, 129 insertions(+), 111 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 22db67a..94480b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,18 +1,23 @@ [package] name = "ff" -version = "0.4.0" +version = "0.5.2" authors = ["Sean Bowe "] description = "Library for building and interfacing with finite fields" +readme = "README.md" documentation = "https://docs.rs/ff/" homepage = "https://github.com/ebfull/ff" license = "MIT/Apache-2.0" repository = "https://github.com/ebfull/ff" +edition = "2018" [dependencies] byteorder = "1" -rand = "0.4" -ff_derive = { version = "0.3.0", path = "ff_derive", optional = true } +ff_derive = { version = "^0.4.1", path = "ff_derive", optional = true } +rand_core = "0.5" [features] default = [] derive = ["ff_derive"] + +[badges] +maintenance = { status = "actively-developed" } diff --git a/README.md b/README.md index 3efef94..57ef693 100644 --- a/README.md +++ b/README.md @@ -12,14 +12,18 @@ Add the `ff` crate to your `Cargo.toml`: ```toml [dependencies] -ff = "0.4" +ff = "0.5" ``` -The `ff` crate contains `Field`, `PrimeField`, `PrimeFieldRepr` and `SqrtField` traits. See the **[documentation](https://docs.rs/ff/0.4.0/ff/)** for more. +The `ff` crate contains `Field`, `PrimeField`, `PrimeFieldRepr` and `SqrtField` traits. +See the **[documentation](https://docs.rs/ff/)** for more. ### #![derive(PrimeField)] -If you need an implementation of a prime field, this library also provides a procedural macro that will expand into an efficient implementation of a prime field when supplied with the modulus. `PrimeFieldGenerator` must be an element of Fp of p-1 order, that is also quadratic nonresidue. +If you need an implementation of a prime field, this library also provides a procedural +macro that will expand into an efficient implementation of a prime field when supplied +with the modulus. `PrimeFieldGenerator` must be an element of Fp of p-1 order, that is +also quadratic nonresidue. First, enable the `derive` crate feature: @@ -41,13 +45,16 @@ extern crate ff; struct Fp(FpRepr); ``` -And that's it! `Fp` now implements `Field` and `PrimeField`. `Fp` will also implement `SqrtField` if supported. The library implements `FpRepr` itself and derives `PrimeFieldRepr` for it. +And that's it! `Fp` now implements `Field` and `PrimeField`. `Fp` will also implement +`SqrtField` if supported. The library implements `FpRepr` itself and derives +`PrimeFieldRepr` for it. ## License Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. diff --git a/ff_derive/Cargo.toml b/ff_derive/Cargo.toml index 914e392..04a9bc2 100644 --- a/ff_derive/Cargo.toml +++ b/ff_derive/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "ff_derive" -version = "0.3.0" +version = "0.4.1" authors = ["Sean Bowe "] description = "Procedural macro library used to build custom prime field implementations" documentation = "https://docs.rs/ff/" homepage = "https://github.com/ebfull/ff" license = "MIT/Apache-2.0" repository = "https://github.com/ebfull/ff" +edition = "2018" [lib] proc-macro = true @@ -15,6 +16,9 @@ proc-macro = true num-bigint = "0.2" num-traits = "0.2" num-integer = "0.1" -proc-macro2 = "0.4" -quote = "0.6" -syn = "0.14" +proc-macro2 = "1" +quote = "1" +syn = "1" + +[badges] +maintenance = { status = "passively-maintained" } diff --git a/ff_derive/src/lib.rs b/ff_derive/src/lib.rs index 45d3445..5e56e74 100644 --- a/ff_derive/src/lib.rs +++ b/ff_derive/src/lib.rs @@ -52,13 +52,8 @@ pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let mut gen = proc_macro2::TokenStream::new(); - let (constants_impl, sqrt_impl) = prime_field_constants_and_sqrt( - &ast.ident, - &repr_ident, - modulus, - limbs, - generator, - ); + let (constants_impl, sqrt_impl) = + prime_field_constants_and_sqrt(&ast.ident, &repr_ident, modulus, limbs, generator); gen.extend(constants_impl); gen.extend(prime_field_repr_impl(&repr_ident, limbs)); @@ -96,10 +91,10 @@ fn fetch_wrapped_ident(body: &syn::Data) -> Option { /// Fetch an attribute string from the derived struct. fn fetch_attr(name: &str, attrs: &[syn::Attribute]) -> Option { for attr in attrs { - if let Some(meta) = attr.interpret_meta() { + if let Ok(meta) = attr.parse_meta() { match meta { syn::Meta::NameValue(nv) => { - if nv.ident.to_string() == name { + if nv.path.get_ident().map(|i| i.to_string()) == Some(name.to_string()) { match nv.lit { syn::Lit::Str(ref s) => return Some(s.value()), _ => { @@ -127,27 +122,20 @@ fn prime_field_repr_impl(repr: &syn::Ident, limbs: usize) -> proc_macro2::TokenS impl ::std::fmt::Debug for #repr { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - try!(write!(f, "0x")); + write!(f, "0x")?; for i in self.0.iter().rev() { - try!(write!(f, "{:016x}", *i)); + write!(f, "{:016x}", *i)?; } Ok(()) } } - impl ::rand::Rand for #repr { - #[inline(always)] - fn rand(rng: &mut R) -> Self { - #repr(rng.gen()) - } - } - impl ::std::fmt::Display for #repr { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - try!(write!(f, "0x")); + write!(f, "0x")?; for i in self.0.iter().rev() { - try!(write!(f, "{:016x}", *i)); + write!(f, "{:016x}", *i)?; } Ok(()) @@ -366,7 +354,8 @@ fn biguint_num_bits(mut v: BigUint) -> u32 { fn exp(base: BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint { let mut ret = BigUint::one(); - for i in exp.to_bytes_be() + for i in exp + .to_bytes_be() .into_iter() .flat_map(|x| (0..8).rev().map(move |i| (x >> i).is_odd())) { @@ -387,11 +376,13 @@ fn test_exp() { &BigUint::from_str("5489673498567349856734895").unwrap(), &BigUint::from_str( "52435875175126190479447740508185965837690552500527637822603658699938581184513" - ).unwrap() + ) + .unwrap() ), BigUint::from_str( "4371221214068404307866768905142520595925044802278091865033317963560480051536" - ).unwrap() + ) + .unwrap() ); } @@ -430,7 +421,7 @@ fn prime_field_constants_and_sqrt( let mod_minus_1_over_2 = biguint_to_u64_vec((&modulus - BigUint::from_str("1").unwrap()) >> 1, limbs); - let legendre_impl = quote!{ + let legendre_impl = quote! { fn legendre(&self) -> ::ff::LegendreSymbol { // s = self^((modulus - 1) // 2) let s = self.pow(#mod_minus_1_over_2); @@ -452,7 +443,7 @@ fn prime_field_constants_and_sqrt( // Compute -R as (m - r) let rneg = biguint_to_u64_vec(&modulus - &r, limbs); - quote!{ + quote! { impl ::ff::SqrtField for #name { #legendre_impl @@ -479,7 +470,7 @@ fn prime_field_constants_and_sqrt( let t_plus_1_over_2 = biguint_to_u64_vec((&t + BigUint::one()) >> 1, limbs); let t = biguint_to_u64_vec(t.clone(), limbs); - quote!{ + quote! { impl ::ff::SqrtField for #name { #legendre_impl @@ -526,7 +517,7 @@ fn prime_field_constants_and_sqrt( } } } else { - quote!{} + quote! {} }; // Compute R^2 mod m @@ -543,36 +534,39 @@ fn prime_field_constants_and_sqrt( } inv = inv.wrapping_neg(); - (quote! { - /// This is the modulus m of the prime field - const MODULUS: #repr = #repr([#(#modulus,)*]); + ( + quote! { + /// This is the modulus m of the prime field + const MODULUS: #repr = #repr([#(#modulus,)*]); - /// The number of bits needed to represent the modulus. - const MODULUS_BITS: u32 = #modulus_num_bits; + /// The number of bits needed to represent the modulus. + const MODULUS_BITS: u32 = #modulus_num_bits; - /// The number of bits that must be shaved from the beginning of - /// the representation when randomly sampling. - const REPR_SHAVE_BITS: u32 = #repr_shave_bits; + /// The number of bits that must be shaved from the beginning of + /// the representation when randomly sampling. + const REPR_SHAVE_BITS: u32 = #repr_shave_bits; - /// 2^{limbs*64} mod m - const R: #repr = #repr(#r); + /// 2^{limbs*64} mod m + const R: #repr = #repr(#r); - /// 2^{limbs*64*2} mod m - const R2: #repr = #repr(#r2); + /// 2^{limbs*64*2} mod m + const R2: #repr = #repr(#r2); - /// -(m^{-1} mod m) mod m - const INV: u64 = #inv; + /// -(m^{-1} mod m) mod m + const INV: u64 = #inv; - /// Multiplicative generator of `MODULUS` - 1 order, also quadratic - /// nonresidue. - const GENERATOR: #repr = #repr(#generator); + /// Multiplicative generator of `MODULUS` - 1 order, also quadratic + /// nonresidue. + const GENERATOR: #repr = #repr(#generator); - /// 2^s * t = MODULUS - 1 with t odd - const S: u32 = #s; + /// 2^s * t = MODULUS - 1 with t odd + const S: u32 = #s; - /// 2^s root of unity computed by GENERATOR^t - const ROOT_OF_UNITY: #repr = #repr(#root_of_unity); - }, sqrt_impl) + /// 2^s root of unity computed by GENERATOR^t + const ROOT_OF_UNITY: #repr = #repr(#root_of_unity); + }, + sqrt_impl, + ) } /// Implement PrimeField for the derived type. @@ -592,9 +586,9 @@ fn prime_field_impl( mont_paramlist.append_separated( (0..(limbs * 2)).map(|i| (i, get_temp(i))).map(|(i, x)| { if i != 0 { - quote!{mut #x: u64} + quote! {mut #x: u64} } else { - quote!{#x: u64} + quote! {#x: u64} } }), proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), @@ -607,7 +601,7 @@ fn prime_field_impl( for i in 0..limbs { { let temp = get_temp(i); - gen.extend(quote!{ + gen.extend(quote! { let k = #temp.wrapping_mul(INV); let mut carry = 0; ::ff::mac_with_carry(#temp, k, MODULUS.0[0], &mut carry); @@ -616,7 +610,7 @@ fn prime_field_impl( for j in 1..limbs { let temp = get_temp(i + j); - gen.extend(quote!{ + gen.extend(quote! { #temp = ::ff::mac_with_carry(#temp, k, MODULUS.0[#j], &mut carry); }); } @@ -624,17 +618,17 @@ fn prime_field_impl( let temp = get_temp(i + limbs); if i == 0 { - gen.extend(quote!{ + gen.extend(quote! { #temp = ::ff::adc(#temp, 0, &mut carry); }); } else { - gen.extend(quote!{ + gen.extend(quote! { #temp = ::ff::adc(#temp, carry2, &mut carry); }); } if i != (limbs - 1) { - gen.extend(quote!{ + gen.extend(quote! { let carry2 = carry; }); } @@ -643,7 +637,7 @@ fn prime_field_impl( for i in 0..limbs { let temp = get_temp(limbs + i); - gen.extend(quote!{ + gen.extend(quote! { (self.0).0[#i] = #temp; }); } @@ -655,14 +649,14 @@ fn prime_field_impl( let mut gen = proc_macro2::TokenStream::new(); for i in 0..(limbs - 1) { - gen.extend(quote!{ + gen.extend(quote! { let mut carry = 0; }); for j in (i + 1)..limbs { let temp = get_temp(i + j); if i == 0 { - gen.extend(quote!{ + gen.extend(quote! { let #temp = ::ff::mac_with_carry(0, (#a.0).0[#i], (#a.0).0[#j], &mut carry); }); } else { @@ -674,7 +668,7 @@ fn prime_field_impl( let temp = get_temp(i + limbs); - gen.extend(quote!{ + gen.extend(quote! { let #temp = carry; }); } @@ -684,21 +678,21 @@ fn prime_field_impl( let temp1 = get_temp(limbs * 2 - i - 1); if i == 1 { - gen.extend(quote!{ + gen.extend(quote! { let #temp0 = #temp1 >> 63; }); } else if i == (limbs * 2 - 1) { - gen.extend(quote!{ + gen.extend(quote! { let #temp0 = #temp0 << 1; }); } else { - gen.extend(quote!{ + gen.extend(quote! { let #temp0 = (#temp0 << 1) | (#temp1 >> 63); }); } } - gen.extend(quote!{ + gen.extend(quote! { let mut carry = 0; }); @@ -706,7 +700,7 @@ fn prime_field_impl( let temp0 = get_temp(i * 2); let temp1 = get_temp(i * 2 + 1); if i == 0 { - gen.extend(quote!{ + gen.extend(quote! { let #temp0 = ::ff::mac_with_carry(0, (#a.0).0[#i], (#a.0).0[#i], &mut carry); }); } else { @@ -715,7 +709,7 @@ fn prime_field_impl( }); } - gen.extend(quote!{ + gen.extend(quote! { let #temp1 = ::ff::adc(#temp1, 0, &mut carry); }); } @@ -726,7 +720,7 @@ fn prime_field_impl( proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), ); - gen.extend(quote!{ + gen.extend(quote! { self.mont_reduce(#mont_calling); }); @@ -741,7 +735,7 @@ fn prime_field_impl( let mut gen = proc_macro2::TokenStream::new(); for i in 0..limbs { - gen.extend(quote!{ + gen.extend(quote! { let mut carry = 0; }); @@ -749,7 +743,7 @@ fn prime_field_impl( let temp = get_temp(i + j); if i == 0 { - gen.extend(quote!{ + gen.extend(quote! { let #temp = ::ff::mac_with_carry(0, (#a.0).0[#i], (#b.0).0[#j], &mut carry); }); } else { @@ -761,7 +755,7 @@ fn prime_field_impl( let temp = get_temp(i + limbs); - gen.extend(quote!{ + gen.extend(quote! { let #temp = carry; }); } @@ -772,29 +766,29 @@ fn prime_field_impl( proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), ); - gen.extend(quote!{ + gen.extend(quote! { self.mont_reduce(#mont_calling); }); gen } - let squaring_impl = sqr_impl(quote!{self}, limbs); - let multiply_impl = mul_impl(quote!{self}, quote!{other}, limbs); + let squaring_impl = sqr_impl(quote! {self}, limbs); + let multiply_impl = mul_impl(quote! {self}, quote! {other}, limbs); let montgomery_impl = mont_impl(limbs); // (self.0).0[0], (self.0).0[1], ..., 0, 0, 0, 0, ... let mut into_repr_params = proc_macro2::TokenStream::new(); into_repr_params.append_separated( (0..limbs) - .map(|i| quote!{ (self.0).0[#i] }) - .chain((0..limbs).map(|_| quote!{0})), + .map(|i| quote! { (self.0).0[#i] }) + .chain((0..limbs).map(|_| quote! {0})), proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone), ); let top_limb_index = limbs - 1; - quote!{ + quote! { impl ::std::marker::Copy for #name { } impl ::std::clone::Clone for #name { @@ -839,22 +833,6 @@ fn prime_field_impl( } } - impl ::rand::Rand for #name { - /// Computes a uniformly random element using rejection sampling. - fn rand(rng: &mut R) -> Self { - loop { - let mut tmp = #name(#repr::rand(rng)); - - // Mask away the unused bits at the beginning. - tmp.0.as_mut()[#top_limb_index] &= 0xffffffffffffffff >> REPR_SHAVE_BITS; - - if tmp.is_valid() { - return tmp - } - } - } - } - impl From<#name> for #repr { fn from(e: #name) -> #repr { e.into_repr() @@ -904,6 +882,26 @@ fn prime_field_impl( } impl ::ff::Field for #name { + /// Computes a uniformly random element using rejection sampling. + fn random(rng: &mut R) -> Self { + loop { + let mut tmp = { + let mut repr = [0u64; #limbs]; + for i in 0..#limbs { + repr[i] = rng.next_u64(); + } + #name(#repr(repr)) + }; + + // Mask away the unused most-significant bits. + tmp.0.as_mut()[#top_limb_index] &= 0xffffffffffffffff >> REPR_SHAVE_BITS; + + if tmp.is_valid() { + return tmp + } + } + } + #[inline] fn zero() -> Self { #name(#repr::from(0)) diff --git a/src/lib.rs b/src/lib.rs index a9d117f..c66163d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,8 @@ -#![allow(unused_imports)] +//! This crate provides traits for working with finite fields. -extern crate byteorder; -extern crate rand; +// Catch documentation errors caused by code changes. +#![deny(intra_doc_link_resolution_failure)] +#![allow(unused_imports)] #[cfg(feature = "derive")] #[macro_use] @@ -10,14 +11,18 @@ extern crate ff_derive; #[cfg(feature = "derive")] pub use ff_derive::*; +use rand_core::RngCore; use std::error::Error; use std::fmt; use std::io::{self, Read, Write}; /// This trait represents an element of a field. pub trait Field: - Sized + Eq + Copy + Clone + Send + Sync + fmt::Debug + fmt::Display + 'static + rand::Rand + Sized + Eq + Copy + Clone + Send + Sync + fmt::Debug + fmt::Display + 'static { + /// Returns an element chosen uniformly at random using a user-provided RNG. + fn random(rng: &mut R) -> Self; + /// Returns the zero element of the field, the additive identity. fn zero() -> Self; @@ -100,7 +105,6 @@ pub trait PrimeFieldRepr: + fmt::Debug + fmt::Display + 'static - + rand::Rand + AsRef<[u64]> + AsMut<[u64]> + From @@ -207,7 +211,7 @@ impl Error for PrimeFieldDecodingError { } impl fmt::Display for PrimeFieldDecodingError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match *self { PrimeFieldDecodingError::NotInField(ref repr) => { write!(f, "{} is not an element of the field", repr) @@ -263,7 +267,7 @@ pub trait PrimeField: Field { } /// Convert this prime field element into a biginteger representation. - fn from_repr(Self::Repr) -> Result; + fn from_repr(_: Self::Repr) -> Result; /// Convert a biginteger representation into a prime field element, if /// the number is an element of the field. From 05a9f3360f7fbd298f3e6f8f7e55e9426d04f2f0 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 3 Mar 2020 17:44:53 -0700 Subject: [PATCH 322/330] Squashed 'pairing/' changes from 3d41ee5..3870f11 3870f11 Bump version and ff dependency e8657fa Merge pull request #108 from kigawas/fix-rngcore-sized 7fddfc7 Update Cargo.toml df0217c bump group version cbc1917 bump version 98133d9 fix RngCore Sized 583c744 pairing 0.15.0 0de7279 Fix pairing benchmarks dd2fbb3 Crate docs 97c45f2 Update READMEs 9aef129 CI: Check intra-doc links f552b49 Add READMEs to Cargo.toml files 8c59b4a cargo fmt 33993f4 cargo fix --edition-idioms for pairing 36788f3 Add edition = 2018 df88a3f cargo fmt d9a1288 cargo fix --edition for pairing 013fd03 cargo fmt pairing 5635612 Fix clippy linter errors in pairing crate ba40e2f Use modern clippy linter syntax fa4eaeb Migrate to rand 0.7 1d00588 Migrate ff, group, pairing, and bellman to rand 0.6 95a749b Migrate pairing to rand 0.5 01e7212 Add ff and group crates to Cargo workspace git-subtree-dir: pairing git-subtree-split: 3870f1172f33aa85c49426fec6c6e7040b4889f9 --- .gitignore | 4 +- .gitlab-ci.yml | 66 - .travis.yml | 8 - pairing/COPYRIGHT => COPYRIGHT | 0 Cargo.lock | 508 -- Cargo.toml | 48 +- LICENSE-APACHE | 1 - LICENSE-MIT | 40 +- README.md | 27 +- bellman/.gitignore | 2 - bellman/COPYRIGHT | 14 - bellman/Cargo.toml | 22 - bellman/LICENSE-APACHE | 201 - bellman/LICENSE-MIT | 23 - bellman/README.md | 19 - bellman/src/domain.rs | 494 -- bellman/src/groth16/generator.rs | 482 -- bellman/src/groth16/mod.rs | 576 -- bellman/src/groth16/prover.rs | 334 - bellman/src/groth16/tests/dummy_engine.rs | 451 -- bellman/src/groth16/tests/mod.rs | 400 -- bellman/src/groth16/verifier.rs | 66 - bellman/src/lib.rs | 424 -- bellman/src/multicore.rs | 106 - bellman/src/multiexp.rs | 303 - bellman/tests/mimc.rs | 251 - {pairing/benches => benches}/bls12_381/ec.rs | 50 +- {pairing/benches => benches}/bls12_381/fq.rs | 109 +- .../benches => benches}/bls12_381/fq12.rs | 38 +- {pairing/benches => benches}/bls12_381/fq2.rs | 45 +- {pairing/benches => benches}/bls12_381/fr.rs | 109 +- {pairing/benches => benches}/bls12_381/mod.rs | 43 +- .../benches => benches}/pairing_benches.rs | 3 +- librustzcash/Cargo.toml | 29 - librustzcash/README.md | 20 - librustzcash/include/librustzcash.h | 313 - librustzcash/src/equihash.rs | 467 -- librustzcash/src/hashreader.rs | 42 - librustzcash/src/rustzcash.rs | 1315 ---- librustzcash/src/tests/key_agreement.rs | 74 - librustzcash/src/tests/key_components.rs | 666 -- librustzcash/src/tests/mod.rs | 96 - librustzcash/src/tests/notes.rs | 673 -- librustzcash/src/tests/signatures.rs | 515 -- pairing/.gitignore | 3 - pairing/Cargo.toml | 26 - pairing/LICENSE-APACHE | 201 - pairing/LICENSE-MIT | 23 - pairing/README.md | 27 - sapling-crypto/.gitignore | 3 - sapling-crypto/COPYRIGHT | 14 - sapling-crypto/Cargo.toml | 27 - sapling-crypto/LICENSE-APACHE | 201 - sapling-crypto/LICENSE-MIT | 23 - sapling-crypto/README.md | 23 - sapling-crypto/benches/pedersen_hash.rs | 23 - sapling-crypto/examples/bench.rs | 102 - sapling-crypto/src/circuit/blake2s.rs | 438 -- sapling-crypto/src/circuit/boolean.rs | 1582 ----- sapling-crypto/src/circuit/ecc.rs | 1213 ---- sapling-crypto/src/circuit/lookup.rs | 307 - sapling-crypto/src/circuit/mod.rs | 39 - sapling-crypto/src/circuit/multieq.rs | 137 - sapling-crypto/src/circuit/multipack.rs | 113 - sapling-crypto/src/circuit/num.rs | 622 -- sapling-crypto/src/circuit/pedersen_hash.rs | 194 - sapling-crypto/src/circuit/sapling/mod.rs | 817 --- sapling-crypto/src/circuit/sha256.rs | 417 -- .../src/circuit/sprout/commitment.rs | 42 - sapling-crypto/src/circuit/sprout/input.rs | 226 - sapling-crypto/src/circuit/sprout/mod.rs | 488 -- sapling-crypto/src/circuit/sprout/output.rs | 54 - sapling-crypto/src/circuit/sprout/prfs.rs | 79 - .../src/circuit/sprout/test_vectors.dat | Bin 10864 -> 0 bytes sapling-crypto/src/circuit/test/mod.rs | 492 -- sapling-crypto/src/circuit/uint32.rs | 755 --- sapling-crypto/src/constants.rs | 40 - sapling-crypto/src/group_hash.rs | 46 - sapling-crypto/src/jubjub/edwards.rs | 523 -- sapling-crypto/src/jubjub/fs.rs | 1232 ---- sapling-crypto/src/jubjub/mod.rs | 435 -- sapling-crypto/src/jubjub/montgomery.rs | 358 -- sapling-crypto/src/jubjub/tests.rs | 416 -- sapling-crypto/src/lib.rs | 22 - sapling-crypto/src/pedersen_hash.rs | 103 - sapling-crypto/src/primitives/mod.rs | 258 - sapling-crypto/src/redjubjub.rs | 343 -- sapling-crypto/src/util.rs | 11 - {pairing/src => src}/bls12_381/README.md | 0 {pairing/src => src}/bls12_381/ec.rs | 287 +- {pairing/src => src}/bls12_381/fq.rs | 191 +- {pairing/src => src}/bls12_381/fq12.rs | 45 +- {pairing/src => src}/bls12_381/fq2.rs | 202 +- {pairing/src => src}/bls12_381/fq6.rs | 63 +- {pairing/src => src}/bls12_381/fr.rs | 185 +- {pairing/src => src}/bls12_381/mod.rs | 9 +- .../g1_compressed_valid_test_vectors.dat | Bin .../g1_uncompressed_invalid_test_vectors.dat | 0 .../g1_uncompressed_valid_test_vectors.dat | Bin .../g2_compressed_valid_test_vectors.dat | Bin .../g2_uncompressed_valid_test_vectors.dat | Bin {pairing/src => src}/bls12_381/tests/mod.rs | 2 +- {pairing/src => src}/lib.rs | 41 +- {pairing/src => src}/tests/engine.rs | 52 +- {pairing/src => src}/tests/field.rs | 81 +- {pairing/src => src}/tests/mod.rs | 0 {pairing/src => src}/tests/repr.rs | 48 +- zcash_primitives/Cargo.toml | 17 - zcash_primitives/LICENSE-APACHE | 202 - zcash_primitives/LICENSE-MIT | 21 - zcash_primitives/README.md | 20 - zcash_primitives/src/lib.rs | 17 - zcash_primitives/src/serialize.rs | 156 - .../src/transaction/components.rs | 432 -- zcash_primitives/src/transaction/mod.rs | 257 - zcash_primitives/src/transaction/sighash.rs | 234 - zcash_primitives/src/transaction/tests.rs | 5422 ----------------- zcash_proofs/Cargo.toml | 13 - zcash_proofs/LICENSE-APACHE | 202 - zcash_proofs/LICENSE-MIT | 21 - zcash_proofs/README.md | 21 - zcash_proofs/src/lib.rs | 7 - zcash_proofs/src/sapling/mod.rs | 39 - zcash_proofs/src/sapling/prover.rs | 365 -- zcash_proofs/src/sapling/verifier.rs | 207 - zcash_wallet/Cargo.toml | 8 - zcash_wallet/LICENSE-APACHE | 202 - zcash_wallet/LICENSE-MIT | 21 - zcash_wallet/README.md | 20 - zcash_wallet/src/lib.rs | 7 - zip32/.gitignore | 3 - zip32/COPYRIGHT | 14 - zip32/Cargo.toml | 24 - zip32/LICENSE-APACHE | 201 - zip32/LICENSE-MIT | 23 - zip32/README.md | 17 - zip32/src/lib.rs | 1233 ---- 137 files changed, 1079 insertions(+), 31528 deletions(-) delete mode 100644 .gitlab-ci.yml delete mode 100644 .travis.yml rename pairing/COPYRIGHT => COPYRIGHT (100%) delete mode 100644 Cargo.lock delete mode 100644 bellman/.gitignore delete mode 100644 bellman/COPYRIGHT delete mode 100644 bellman/Cargo.toml delete mode 100644 bellman/LICENSE-APACHE delete mode 100644 bellman/LICENSE-MIT delete mode 100644 bellman/README.md delete mode 100644 bellman/src/domain.rs delete mode 100644 bellman/src/groth16/generator.rs delete mode 100644 bellman/src/groth16/mod.rs delete mode 100644 bellman/src/groth16/prover.rs delete mode 100644 bellman/src/groth16/tests/dummy_engine.rs delete mode 100644 bellman/src/groth16/tests/mod.rs delete mode 100644 bellman/src/groth16/verifier.rs delete mode 100644 bellman/src/lib.rs delete mode 100644 bellman/src/multicore.rs delete mode 100644 bellman/src/multiexp.rs delete mode 100644 bellman/tests/mimc.rs rename {pairing/benches => benches}/bls12_381/ec.rs (59%) rename {pairing/benches => benches}/bls12_381/fq.rs (56%) rename {pairing/benches => benches}/bls12_381/fq12.rs (55%) rename {pairing/benches => benches}/bls12_381/fq2.rs (54%) rename {pairing/benches => benches}/bls12_381/fr.rs (56%) rename {pairing/benches => benches}/bls12_381/mod.rs (56%) rename {pairing/benches => benches}/pairing_benches.rs (68%) delete mode 100644 librustzcash/Cargo.toml delete mode 100644 librustzcash/README.md delete mode 100644 librustzcash/include/librustzcash.h delete mode 100644 librustzcash/src/equihash.rs delete mode 100644 librustzcash/src/hashreader.rs delete mode 100644 librustzcash/src/rustzcash.rs delete mode 100644 librustzcash/src/tests/key_agreement.rs delete mode 100644 librustzcash/src/tests/key_components.rs delete mode 100644 librustzcash/src/tests/mod.rs delete mode 100644 librustzcash/src/tests/notes.rs delete mode 100644 librustzcash/src/tests/signatures.rs delete mode 100644 pairing/.gitignore delete mode 100644 pairing/Cargo.toml delete mode 100644 pairing/LICENSE-APACHE delete mode 100644 pairing/LICENSE-MIT delete mode 100644 pairing/README.md delete mode 100644 sapling-crypto/.gitignore delete mode 100644 sapling-crypto/COPYRIGHT delete mode 100644 sapling-crypto/Cargo.toml delete mode 100644 sapling-crypto/LICENSE-APACHE delete mode 100644 sapling-crypto/LICENSE-MIT delete mode 100644 sapling-crypto/README.md delete mode 100644 sapling-crypto/benches/pedersen_hash.rs delete mode 100644 sapling-crypto/examples/bench.rs delete mode 100644 sapling-crypto/src/circuit/blake2s.rs delete mode 100644 sapling-crypto/src/circuit/boolean.rs delete mode 100644 sapling-crypto/src/circuit/ecc.rs delete mode 100644 sapling-crypto/src/circuit/lookup.rs delete mode 100644 sapling-crypto/src/circuit/mod.rs delete mode 100644 sapling-crypto/src/circuit/multieq.rs delete mode 100644 sapling-crypto/src/circuit/multipack.rs delete mode 100644 sapling-crypto/src/circuit/num.rs delete mode 100644 sapling-crypto/src/circuit/pedersen_hash.rs delete mode 100644 sapling-crypto/src/circuit/sapling/mod.rs delete mode 100644 sapling-crypto/src/circuit/sha256.rs delete mode 100644 sapling-crypto/src/circuit/sprout/commitment.rs delete mode 100644 sapling-crypto/src/circuit/sprout/input.rs delete mode 100644 sapling-crypto/src/circuit/sprout/mod.rs delete mode 100644 sapling-crypto/src/circuit/sprout/output.rs delete mode 100644 sapling-crypto/src/circuit/sprout/prfs.rs delete mode 100644 sapling-crypto/src/circuit/sprout/test_vectors.dat delete mode 100644 sapling-crypto/src/circuit/test/mod.rs delete mode 100644 sapling-crypto/src/circuit/uint32.rs delete mode 100644 sapling-crypto/src/constants.rs delete mode 100644 sapling-crypto/src/group_hash.rs delete mode 100644 sapling-crypto/src/jubjub/edwards.rs delete mode 100644 sapling-crypto/src/jubjub/fs.rs delete mode 100644 sapling-crypto/src/jubjub/mod.rs delete mode 100644 sapling-crypto/src/jubjub/montgomery.rs delete mode 100644 sapling-crypto/src/jubjub/tests.rs delete mode 100644 sapling-crypto/src/lib.rs delete mode 100644 sapling-crypto/src/pedersen_hash.rs delete mode 100644 sapling-crypto/src/primitives/mod.rs delete mode 100644 sapling-crypto/src/redjubjub.rs delete mode 100644 sapling-crypto/src/util.rs rename {pairing/src => src}/bls12_381/README.md (100%) rename {pairing/src => src}/bls12_381/ec.rs (92%) rename {pairing/src => src}/bls12_381/fq.rs (93%) rename {pairing/src => src}/bls12_381/fq12.rs (82%) rename {pairing/src => src}/bls12_381/fq2.rs (88%) rename {pairing/src => src}/bls12_381/fq6.rs (85%) rename {pairing/src => src}/bls12_381/fr.rs (83%) rename {pairing/src => src}/bls12_381/mod.rs (97%) rename {pairing/src => src}/bls12_381/tests/g1_compressed_valid_test_vectors.dat (100%) rename {pairing/src => src}/bls12_381/tests/g1_uncompressed_invalid_test_vectors.dat (100%) rename {pairing/src => src}/bls12_381/tests/g1_uncompressed_valid_test_vectors.dat (100%) rename {pairing/src => src}/bls12_381/tests/g2_compressed_valid_test_vectors.dat (100%) rename {pairing/src => src}/bls12_381/tests/g2_uncompressed_valid_test_vectors.dat (100%) rename {pairing/src => src}/bls12_381/tests/mod.rs (99%) rename {pairing/src => src}/lib.rs (78%) rename {pairing/src => src}/tests/engine.rs (64%) rename {pairing/src => src}/tests/field.rs (72%) rename {pairing/src => src}/tests/mod.rs (100%) rename {pairing/src => src}/tests/repr.rs (54%) delete mode 100644 zcash_primitives/Cargo.toml delete mode 100644 zcash_primitives/LICENSE-APACHE delete mode 100644 zcash_primitives/LICENSE-MIT delete mode 100644 zcash_primitives/README.md delete mode 100644 zcash_primitives/src/lib.rs delete mode 100644 zcash_primitives/src/serialize.rs delete mode 100644 zcash_primitives/src/transaction/components.rs delete mode 100644 zcash_primitives/src/transaction/mod.rs delete mode 100644 zcash_primitives/src/transaction/sighash.rs delete mode 100644 zcash_primitives/src/transaction/tests.rs delete mode 100644 zcash_proofs/Cargo.toml delete mode 100644 zcash_proofs/LICENSE-APACHE delete mode 100644 zcash_proofs/LICENSE-MIT delete mode 100644 zcash_proofs/README.md delete mode 100644 zcash_proofs/src/lib.rs delete mode 100644 zcash_proofs/src/sapling/mod.rs delete mode 100644 zcash_proofs/src/sapling/prover.rs delete mode 100644 zcash_proofs/src/sapling/verifier.rs delete mode 100644 zcash_wallet/Cargo.toml delete mode 100644 zcash_wallet/LICENSE-APACHE delete mode 100644 zcash_wallet/LICENSE-MIT delete mode 100644 zcash_wallet/README.md delete mode 100644 zcash_wallet/src/lib.rs delete mode 100644 zip32/.gitignore delete mode 100644 zip32/COPYRIGHT delete mode 100644 zip32/Cargo.toml delete mode 100644 zip32/LICENSE-APACHE delete mode 100644 zip32/LICENSE-MIT delete mode 100644 zip32/README.md delete mode 100644 zip32/src/lib.rs diff --git a/.gitignore b/.gitignore index eb5a316..4308d82 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -target +target/ +**/*.rs.bk +Cargo.lock diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 001f415..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,66 +0,0 @@ - -# /************************************************************************ - # File: .gitlab-ci.yml - # Author: mdr0id - # Date: 9/10/2018 - # Description: Used to setup runners/jobs for librustzcash - # Usage: Commit source and the pipeline will trigger the according jobs. - # For now the build and test are done in the same jobs. - # - # Known bugs/missing features: - # - # ************************************************************************/ - -stages: - - build - - test - - deploy - -rust-latest: - stage: build - image: rust:latest - script: - - cargo --verbose --version - - time cargo build --verbose - -rust-nightly: - stage: build - image: rustlang/rust:nightly - script: - - cargo --verbose --version - - cargo build --verbose - allow_failure: true - -librustzcash-test-latest: - stage: test - image: rust:latest - script: - - cargo --verbose --version - - time cargo test --release --verbose - -librustzcash-test-rust-nightly: - stage: test - image: rustlang/rust:nightly - script: - - cargo --verbose --version - - cargo test --release --verbose - allow_failure: true - -#used to manually deploy a given release -librustzcash-rust-rc: - stage: deploy - image: rust:latest - script: - - cargo --verbose --version - - time cargo build --release --verbose - when: manual - -#used to manually deploy a given release -librustzcash-rust-nightly-rc: - stage: deploy - image: rustlang/rust:nightly - script: - - cargo --verbose --version - - cargo build --release --verbose - allow_failure: true - when: manual diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index eea30a2..0000000 --- a/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: rust -rust: - - 1.31.0 - -cache: cargo - -script: - - cargo test --verbose --release --all diff --git a/pairing/COPYRIGHT b/COPYRIGHT similarity index 100% rename from pairing/COPYRIGHT rename to COPYRIGHT diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index e9452e1..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,508 +0,0 @@ -[[package]] -name = "aes" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aes-soft" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aesni" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "arrayvec" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bellman" -version = "0.1.0" -dependencies = [ - "bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bit-vec" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "blake2-rfc" -version = "0.2.18" -source = "git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9#7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" -dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-cipher-trait" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "byte-tools" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byteorder" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "constant_time_eq" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crossbeam" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "digest" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ff" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ff_derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fpe" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures-cpupool" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gcc" -version = "0.3.54" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "generic-array" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hex-literal" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hex-literal-impl" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lazy_static" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.40" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "librustzcash" -version = "0.1.0" -dependencies = [ - "bellman 0.1.0", - "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sapling-crypto 0.0.1", - "zcash_proofs 0.0.0", - "zip32 0.0.0", -] - -[[package]] -name = "nodrop" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "num-bigint" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-integer" -version = "0.1.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "num_cpus" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "opaque-debug" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "pairing" -version = "0.14.2" -dependencies = [ - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-hack" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-hack-impl" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "proc-macro2" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quote" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "redox_syscall" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rust-crypto" -version = "0.2.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "sapling-crypto" -version = "0.0.1" -dependencies = [ - "bellman 0.1.0", - "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "stream-cipher" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syn" -version = "0.14.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "time" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "typenum" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "zcash_primitives" -version = "0.0.0" -dependencies = [ - "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sapling-crypto 0.0.1", -] - -[[package]] -name = "zcash_proofs" -version = "0.0.0" -dependencies = [ - "bellman 0.1.0", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sapling-crypto 0.0.1", -] - -[[package]] -name = "zcash_wallet" -version = "0.0.0" - -[[package]] -name = "zip32" -version = "0.0.0" -dependencies = [ - "aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", - "sapling-crypto 0.0.1", -] - -[metadata] -"checksum aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6fb1737cdc8da3db76e90ca817a194249a38fcb500c2e6ecec39b29448aa873" -"checksum aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67cc03b0a090a05cb01e96998a01905d7ceedce1bc23b756c0bb7faa0682ccb1" -"checksum aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6810b7fb9f2bb4f76f05ac1c170b8dde285b6308955dc3afd89710268c958d9e" -"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" -"checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" -"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" -"checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)" = "" -"checksum block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "370424437b9459f3dfd68428ed9376ddfe03d8b70ede29cc533b3557df186ab4" -"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" -"checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87" -"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" -"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" -"checksum digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603" -"checksum ff 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eec81e2e423086589b224dbcfbab70e3732913de25479d05165b20d4aaed05f4" -"checksum ff_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70335090ee115d5716416ca38980cce7752f40923f41d22cf5a69a6269f9e2a2" -"checksum fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce3371c82bfbd984f624cab093f55e7336f5a6e589f8518e1258f54f011b89ad" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" -"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" -"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" -"checksum hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4da5f0e01bd8a71a224a4eedecaacfcabda388dbb7a80faf04d3514287572d95" -"checksum hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d340b6514f232f6db1bd16db65302a5278a04fef9ce867cb932e7e5fa21130a" -"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" -"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" -"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" -"checksum num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3eceac7784c5dc97c2d6edf30259b4e153e6e2b42b3c85e9a6e9f45d06caef6e" -"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" -"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" -"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d620c9c26834b34f039489ac0dfdb12c7ac15ccaf818350a64c9b5334a452ad7" -"checksum proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ba8d4f9257b85eb6cdf13f055cea3190520aab1409ca2ab43493ea4820c25f0" -"checksum proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5cb6f960ad471404618e9817c0e5d10b1ae74cfdf01fab89ea0641fe7fb2892" -"checksum proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b331c6ad3411474cd55540398dc7ad89fc41488e64ec71fdecc9c9b86de96fb0" -"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" -"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" -"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" -"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" -"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" -"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "30dc6118470d69ce0fdcf7e6f95e95853f7f4f72f80d835d4519577c323814ab" -"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" -"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" -"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 3d1363d..d46fad7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,34 @@ -[workspace] -members = [ - "bellman", - "librustzcash", - "pairing", - "sapling-crypto", - "zcash_primitives", - "zcash_proofs", - "zcash_wallet", - "zip32", -] +[package] +name = "pairing" -[profile.release] -lto = true -panic = 'abort' -codegen-units = 1 +# Remember to change version string in README.md. +version = "0.15.1" +authors = [ + "Sean Bowe ", + "Jack Grigg ", +] +readme = "README.md" +license = "MIT/Apache-2.0" + +description = "Pairing-friendly elliptic curve library" +documentation = "https://docs.rs/pairing/" +homepage = "https://github.com/ebfull/pairing" +repository = "https://github.com/ebfull/pairing" +edition ="2018" + +[dependencies] +byteorder = "1" +ff = { version = "^0.5.2", path = "../ff", features = ["derive"] } +group = { version = "0.2.0", path = "../group" } +rand_core = "0.5" + +[dev-dependencies] +rand_xorshift = "0.2" + +[features] +unstable-features = ["expose-arith"] +expose-arith = [] +default = [] + +[badges] +maintenance = { status = "actively-developed" } diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 1e5006d..16fe87b 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -199,4 +199,3 @@ 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. - diff --git a/LICENSE-MIT b/LICENSE-MIT index 5b7be8e..31aa793 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,21 +1,23 @@ -The MIT License (MIT) +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: -Copyright (c) 2017 Zcash Company +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 3df799f..47a25dc 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,32 @@ -# Zcash Rust crates +# pairing [![Crates.io](https://img.shields.io/crates/v/pairing.svg)](https://crates.io/crates/pairing) # -This repository contains a (work-in-progress) set of Rust crates for -working with Zcash. +`pairing` is a crate for using pairing-friendly elliptic curves. + +Currently, only the [BLS12-381](https://z.cash/blog/new-snark-curve.html) +construction is implemented. + +## Roadmap + +`pairing` is being refactored into a generic library for working with +pairing-friendly curves. After the refactor, `pairing` will provide basic traits +for pairing-friendly elliptic curve constructions, while specific curves will be +in separate crates. + +## [Documentation](https://docs.rs/pairing/) + +Bring the `pairing` crate into your project just as you normally would. ## Security Warnings -These libraries are currently under development and have not been fully-reviewed. +This library does not make any guarantees about constant-time operations, memory +access patterns, or resistance to side-channel attacks. ## License -All code in this workspace is licensed under either of +Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. diff --git a/bellman/.gitignore b/bellman/.gitignore deleted file mode 100644 index a9d37c5..0000000 --- a/bellman/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target -Cargo.lock diff --git a/bellman/COPYRIGHT b/bellman/COPYRIGHT deleted file mode 100644 index 8b5f8cf..0000000 --- a/bellman/COPYRIGHT +++ /dev/null @@ -1,14 +0,0 @@ -Copyrights in the "bellman" library are retained by their contributors. No -copyright assignment is required to contribute to the "bellman" library. - -The "bellman" library is licensed under either of - - * Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT) - -at your option. - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/bellman/Cargo.toml b/bellman/Cargo.toml deleted file mode 100644 index b7699cf..0000000 --- a/bellman/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -authors = ["Sean Bowe "] -description = "zk-SNARK library" -documentation = "https://github.com/ebfull/bellman" -homepage = "https://github.com/ebfull/bellman" -license = "MIT/Apache-2.0" -name = "bellman" -repository = "https://github.com/ebfull/bellman" -version = "0.1.0" - -[dependencies] -rand = "0.4" -bit-vec = "0.4.4" -futures = "0.1" -futures-cpupool = "0.1" -num_cpus = "1" -crossbeam = "0.3" -pairing = { path = "../pairing" } -byteorder = "1" - -[features] -default = [] diff --git a/bellman/LICENSE-APACHE b/bellman/LICENSE-APACHE deleted file mode 100644 index 16fe87b..0000000 --- a/bellman/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. diff --git a/bellman/LICENSE-MIT b/bellman/LICENSE-MIT deleted file mode 100644 index 31aa793..0000000 --- a/bellman/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/bellman/README.md b/bellman/README.md deleted file mode 100644 index 659a81c..0000000 --- a/bellman/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# bellman [![Crates.io](https://img.shields.io/crates/v/bellman.svg)](https://crates.io/crates/bellman) # - -This is a research project being built for [Zcash](https://z.cash/). - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/bellman/src/domain.rs b/bellman/src/domain.rs deleted file mode 100644 index ff626e5..0000000 --- a/bellman/src/domain.rs +++ /dev/null @@ -1,494 +0,0 @@ -//! This module contains an `EvaluationDomain` abstraction for -//! performing various kinds of polynomial arithmetic on top of -//! the scalar field. -//! -//! In pairing-based SNARKs like Groth16, we need to calculate -//! a quotient polynomial over a target polynomial with roots -//! at distinct points associated with each constraint of the -//! constraint system. In order to be efficient, we choose these -//! roots to be the powers of a 2^n root of unity in the field. -//! This allows us to perform polynomial operations in O(n) -//! by performing an O(n log n) FFT over such a domain. - -use pairing::{ - Engine, - Field, - PrimeField, - CurveProjective -}; - -use super::{ - SynthesisError -}; - -use super::multicore::Worker; - -pub struct EvaluationDomain> { - coeffs: Vec, - exp: u32, - omega: E::Fr, - omegainv: E::Fr, - geninv: E::Fr, - minv: E::Fr -} - -impl> EvaluationDomain { - pub fn as_ref(&self) -> &[G] { - &self.coeffs - } - - pub fn as_mut(&mut self) -> &mut [G] { - &mut self.coeffs - } - - pub fn into_coeffs(self) -> Vec { - self.coeffs - } - - pub fn from_coeffs(mut coeffs: Vec) -> Result, SynthesisError> - { - // Compute the size of our evaluation domain - let mut m = 1; - let mut exp = 0; - while m < coeffs.len() { - m *= 2; - exp += 1; - - // The pairing-friendly curve may not be able to support - // large enough (radix2) evaluation domains. - if exp >= E::Fr::S { - return Err(SynthesisError::PolynomialDegreeTooLarge) - } - } - - // Compute omega, the 2^exp primitive root of unity - let mut omega = E::Fr::root_of_unity(); - for _ in exp..E::Fr::S { - omega.square(); - } - - // Extend the coeffs vector with zeroes if necessary - coeffs.resize(m, G::group_zero()); - - Ok(EvaluationDomain { - coeffs: coeffs, - exp: exp, - omega: omega, - omegainv: omega.inverse().unwrap(), - geninv: E::Fr::multiplicative_generator().inverse().unwrap(), - minv: E::Fr::from_str(&format!("{}", m)).unwrap().inverse().unwrap() - }) - } - - pub fn fft(&mut self, worker: &Worker) - { - best_fft(&mut self.coeffs, worker, &self.omega, self.exp); - } - - pub fn ifft(&mut self, worker: &Worker) - { - best_fft(&mut self.coeffs, worker, &self.omegainv, self.exp); - - worker.scope(self.coeffs.len(), |scope, chunk| { - let minv = self.minv; - - for v in self.coeffs.chunks_mut(chunk) { - scope.spawn(move || { - for v in v { - v.group_mul_assign(&minv); - } - }); - } - }); - } - - pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr) - { - worker.scope(self.coeffs.len(), |scope, chunk| { - for (i, v) in self.coeffs.chunks_mut(chunk).enumerate() { - scope.spawn(move || { - let mut u = g.pow(&[(i * chunk) as u64]); - for v in v.iter_mut() { - v.group_mul_assign(&u); - u.mul_assign(&g); - } - }); - } - }); - } - - pub fn coset_fft(&mut self, worker: &Worker) - { - self.distribute_powers(worker, E::Fr::multiplicative_generator()); - self.fft(worker); - } - - pub fn icoset_fft(&mut self, worker: &Worker) - { - let geninv = self.geninv; - - self.ifft(worker); - self.distribute_powers(worker, geninv); - } - - /// This evaluates t(tau) for this domain, which is - /// tau^m - 1 for these radix-2 domains. - pub fn z(&self, tau: &E::Fr) -> E::Fr { - let mut tmp = tau.pow(&[self.coeffs.len() as u64]); - tmp.sub_assign(&E::Fr::one()); - - tmp - } - - /// The target polynomial is the zero polynomial in our - /// evaluation domain, so we must perform division over - /// a coset. - pub fn divide_by_z_on_coset(&mut self, worker: &Worker) - { - let i = self.z(&E::Fr::multiplicative_generator()).inverse().unwrap(); - - worker.scope(self.coeffs.len(), |scope, chunk| { - for v in self.coeffs.chunks_mut(chunk) { - scope.spawn(move || { - for v in v { - v.group_mul_assign(&i); - } - }); - } - }); - } - - /// Perform O(n) multiplication of two polynomials in the domain. - pub fn mul_assign(&mut self, worker: &Worker, other: &EvaluationDomain>) { - assert_eq!(self.coeffs.len(), other.coeffs.len()); - - worker.scope(self.coeffs.len(), |scope, chunk| { - for (a, b) in self.coeffs.chunks_mut(chunk).zip(other.coeffs.chunks(chunk)) { - scope.spawn(move || { - for (a, b) in a.iter_mut().zip(b.iter()) { - a.group_mul_assign(&b.0); - } - }); - } - }); - } - - /// Perform O(n) subtraction of one polynomial from another in the domain. - pub fn sub_assign(&mut self, worker: &Worker, other: &EvaluationDomain) { - assert_eq!(self.coeffs.len(), other.coeffs.len()); - - worker.scope(self.coeffs.len(), |scope, chunk| { - for (a, b) in self.coeffs.chunks_mut(chunk).zip(other.coeffs.chunks(chunk)) { - scope.spawn(move || { - for (a, b) in a.iter_mut().zip(b.iter()) { - a.group_sub_assign(&b); - } - }); - } - }); - } -} - -pub trait Group: Sized + Copy + Clone + Send + Sync { - fn group_zero() -> Self; - fn group_mul_assign(&mut self, by: &E::Fr); - fn group_add_assign(&mut self, other: &Self); - fn group_sub_assign(&mut self, other: &Self); -} - -pub struct Point(pub G); - -impl PartialEq for Point { - fn eq(&self, other: &Point) -> bool { - self.0 == other.0 - } -} - -impl Copy for Point { } - -impl Clone for Point { - fn clone(&self) -> Point { - *self - } -} - -impl Group for Point { - fn group_zero() -> Self { - Point(G::zero()) - } - fn group_mul_assign(&mut self, by: &G::Scalar) { - self.0.mul_assign(by.into_repr()); - } - fn group_add_assign(&mut self, other: &Self) { - self.0.add_assign(&other.0); - } - fn group_sub_assign(&mut self, other: &Self) { - self.0.sub_assign(&other.0); - } -} - -pub struct Scalar(pub E::Fr); - -impl PartialEq for Scalar { - fn eq(&self, other: &Scalar) -> bool { - self.0 == other.0 - } -} - -impl Copy for Scalar { } - -impl Clone for Scalar { - fn clone(&self) -> Scalar { - *self - } -} - -impl Group for Scalar { - fn group_zero() -> Self { - Scalar(E::Fr::zero()) - } - fn group_mul_assign(&mut self, by: &E::Fr) { - self.0.mul_assign(by); - } - fn group_add_assign(&mut self, other: &Self) { - self.0.add_assign(&other.0); - } - fn group_sub_assign(&mut self, other: &Self) { - self.0.sub_assign(&other.0); - } -} - -fn best_fft>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32) -{ - let log_cpus = worker.log_num_cpus(); - - if log_n <= log_cpus { - serial_fft(a, omega, log_n); - } else { - parallel_fft(a, worker, omega, log_n, log_cpus); - } -} - -fn serial_fft>(a: &mut [T], omega: &E::Fr, log_n: u32) -{ - fn bitreverse(mut n: u32, l: u32) -> u32 { - let mut r = 0; - for _ in 0..l { - r = (r << 1) | (n & 1); - n >>= 1; - } - r - } - - let n = a.len() as u32; - assert_eq!(n, 1 << log_n); - - for k in 0..n { - let rk = bitreverse(k, log_n); - if k < rk { - a.swap(rk as usize, k as usize); - } - } - - let mut m = 1; - for _ in 0..log_n { - let w_m = omega.pow(&[(n / (2*m)) as u64]); - - let mut k = 0; - while k < n { - let mut w = E::Fr::one(); - for j in 0..m { - let mut t = a[(k+j+m) as usize]; - t.group_mul_assign(&w); - let mut tmp = a[(k+j) as usize]; - tmp.group_sub_assign(&t); - a[(k+j+m) as usize] = tmp; - a[(k+j) as usize].group_add_assign(&t); - w.mul_assign(&w_m); - } - - k += 2*m; - } - - m *= 2; - } -} - -fn parallel_fft>( - a: &mut [T], - worker: &Worker, - omega: &E::Fr, - log_n: u32, - log_cpus: u32 -) -{ - assert!(log_n >= log_cpus); - - let num_cpus = 1 << log_cpus; - let log_new_n = log_n - log_cpus; - let mut tmp = vec![vec![T::group_zero(); 1 << log_new_n]; num_cpus]; - let new_omega = omega.pow(&[num_cpus as u64]); - - worker.scope(0, |scope, _| { - let a = &*a; - - for (j, tmp) in tmp.iter_mut().enumerate() { - scope.spawn(move || { - // Shuffle into a sub-FFT - let omega_j = omega.pow(&[j as u64]); - let omega_step = omega.pow(&[(j as u64) << log_new_n]); - - let mut elt = E::Fr::one(); - for i in 0..(1 << log_new_n) { - for s in 0..num_cpus { - let idx = (i + (s << log_new_n)) % (1 << log_n); - let mut t = a[idx]; - t.group_mul_assign(&elt); - tmp[i].group_add_assign(&t); - elt.mul_assign(&omega_step); - } - elt.mul_assign(&omega_j); - } - - // Perform sub-FFT - serial_fft(tmp, &new_omega, log_new_n); - }); - } - }); - - // TODO: does this hurt or help? - worker.scope(a.len(), |scope, chunk| { - let tmp = &tmp; - - for (idx, a) in a.chunks_mut(chunk).enumerate() { - scope.spawn(move || { - let mut idx = idx * chunk; - let mask = (1 << log_cpus) - 1; - for a in a { - *a = tmp[idx & mask][idx >> log_cpus]; - idx += 1; - } - }); - } - }); -} - -// Test multiplying various (low degree) polynomials together and -// comparing with naive evaluations. -#[test] -fn polynomial_arith() { - use pairing::bls12_381::Bls12; - use rand::{self, Rand}; - - fn test_mul(rng: &mut R) - { - let worker = Worker::new(); - - for coeffs_a in 0..70 { - for coeffs_b in 0..70 { - let mut a: Vec<_> = (0..coeffs_a).map(|_| Scalar::(E::Fr::rand(rng))).collect(); - let mut b: Vec<_> = (0..coeffs_b).map(|_| Scalar::(E::Fr::rand(rng))).collect(); - - // naive evaluation - let mut naive = vec![Scalar(E::Fr::zero()); coeffs_a + coeffs_b]; - for (i1, a) in a.iter().enumerate() { - for (i2, b) in b.iter().enumerate() { - let mut prod = *a; - prod.group_mul_assign(&b.0); - naive[i1 + i2].group_add_assign(&prod); - } - } - - a.resize(coeffs_a + coeffs_b, Scalar(E::Fr::zero())); - b.resize(coeffs_a + coeffs_b, Scalar(E::Fr::zero())); - - let mut a = EvaluationDomain::from_coeffs(a).unwrap(); - let mut b = EvaluationDomain::from_coeffs(b).unwrap(); - - a.fft(&worker); - b.fft(&worker); - a.mul_assign(&worker, &b); - a.ifft(&worker); - - for (naive, fft) in naive.iter().zip(a.coeffs.iter()) { - assert!(naive == fft); - } - } - } - } - - let rng = &mut rand::thread_rng(); - - test_mul::(rng); -} - -#[test] -fn fft_composition() { - use pairing::bls12_381::Bls12; - use rand; - - fn test_comp(rng: &mut R) - { - let worker = Worker::new(); - - for coeffs in 0..10 { - let coeffs = 1 << coeffs; - - let mut v = vec![]; - for _ in 0..coeffs { - v.push(Scalar::(rng.gen())); - } - - let mut domain = EvaluationDomain::from_coeffs(v.clone()).unwrap(); - domain.ifft(&worker); - domain.fft(&worker); - assert!(v == domain.coeffs); - domain.fft(&worker); - domain.ifft(&worker); - assert!(v == domain.coeffs); - domain.icoset_fft(&worker); - domain.coset_fft(&worker); - assert!(v == domain.coeffs); - domain.coset_fft(&worker); - domain.icoset_fft(&worker); - assert!(v == domain.coeffs); - } - } - - let rng = &mut rand::thread_rng(); - - test_comp::(rng); -} - -#[test] -fn parallel_fft_consistency() { - use pairing::bls12_381::Bls12; - use rand::{self, Rand}; - use std::cmp::min; - - fn test_consistency(rng: &mut R) - { - let worker = Worker::new(); - - for _ in 0..5 { - for log_d in 0..10 { - let d = 1 << log_d; - - let v1 = (0..d).map(|_| Scalar::(E::Fr::rand(rng))).collect::>(); - let mut v1 = EvaluationDomain::from_coeffs(v1).unwrap(); - let mut v2 = EvaluationDomain::from_coeffs(v1.coeffs.clone()).unwrap(); - - for log_cpus in log_d..min(log_d+1, 3) { - parallel_fft(&mut v1.coeffs, &worker, &v1.omega, log_d, log_cpus); - serial_fft(&mut v2.coeffs, &v2.omega, log_d); - - assert!(v1.coeffs == v2.coeffs); - } - } - } - } - - let rng = &mut rand::thread_rng(); - - test_consistency::(rng); -} diff --git a/bellman/src/groth16/generator.rs b/bellman/src/groth16/generator.rs deleted file mode 100644 index 1eed62d..0000000 --- a/bellman/src/groth16/generator.rs +++ /dev/null @@ -1,482 +0,0 @@ -use rand::Rng; - -use std::sync::Arc; - -use pairing::{ - Engine, - PrimeField, - Field, - Wnaf, - CurveProjective, - CurveAffine -}; - -use super::{ - Parameters, - VerifyingKey -}; - -use ::{ - SynthesisError, - Circuit, - ConstraintSystem, - LinearCombination, - Variable, - Index -}; - -use ::domain::{ - EvaluationDomain, - Scalar -}; - -use ::multicore::{ - Worker -}; - -/// Generates a random common reference string for -/// a circuit. -pub fn generate_random_parameters( - circuit: C, - rng: &mut R -) -> Result, SynthesisError> - where E: Engine, C: Circuit, R: Rng -{ - let g1 = rng.gen(); - let g2 = rng.gen(); - let alpha = rng.gen(); - let beta = rng.gen(); - let gamma = rng.gen(); - let delta = rng.gen(); - let tau = rng.gen(); - - generate_parameters::( - circuit, - g1, - g2, - alpha, - beta, - gamma, - delta, - tau - ) -} - -/// This is our assembly structure that we'll use to synthesize the -/// circuit into a QAP. -struct KeypairAssembly { - num_inputs: usize, - num_aux: usize, - num_constraints: usize, - at_inputs: Vec>, - bt_inputs: Vec>, - ct_inputs: Vec>, - at_aux: Vec>, - bt_aux: Vec>, - ct_aux: Vec> -} - -impl ConstraintSystem for KeypairAssembly { - type Root = Self; - - fn alloc( - &mut self, - _: A, - _: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into - { - // There is no assignment, so we don't even invoke the - // function for obtaining one. - - let index = self.num_aux; - self.num_aux += 1; - - self.at_aux.push(vec![]); - self.bt_aux.push(vec![]); - self.ct_aux.push(vec![]); - - Ok(Variable(Index::Aux(index))) - } - - fn alloc_input( - &mut self, - _: A, - _: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into - { - // There is no assignment, so we don't even invoke the - // function for obtaining one. - - let index = self.num_inputs; - self.num_inputs += 1; - - self.at_inputs.push(vec![]); - self.bt_inputs.push(vec![]); - self.ct_inputs.push(vec![]); - - Ok(Variable(Index::Input(index))) - } - - fn enforce( - &mut self, - _: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination - { - fn eval( - l: LinearCombination, - inputs: &mut [Vec<(E::Fr, usize)>], - aux: &mut [Vec<(E::Fr, usize)>], - this_constraint: usize - ) - { - for (index, coeff) in l.0 { - match index { - Variable(Index::Input(id)) => inputs[id].push((coeff, this_constraint)), - Variable(Index::Aux(id)) => aux[id].push((coeff, this_constraint)) - } - } - } - - eval(a(LinearCombination::zero()), &mut self.at_inputs, &mut self.at_aux, self.num_constraints); - eval(b(LinearCombination::zero()), &mut self.bt_inputs, &mut self.bt_aux, self.num_constraints); - eval(c(LinearCombination::zero()), &mut self.ct_inputs, &mut self.ct_aux, self.num_constraints); - - self.num_constraints += 1; - } - - fn push_namespace(&mut self, _: N) - where NR: Into, N: FnOnce() -> NR - { - // Do nothing; we don't care about namespaces in this context. - } - - fn pop_namespace(&mut self) - { - // Do nothing; we don't care about namespaces in this context. - } - - fn get_root(&mut self) -> &mut Self::Root { - self - } -} - -/// Create parameters for a circuit, given some toxic waste. -pub fn generate_parameters( - circuit: C, - g1: E::G1, - g2: E::G2, - alpha: E::Fr, - beta: E::Fr, - gamma: E::Fr, - delta: E::Fr, - tau: E::Fr -) -> Result, SynthesisError> - where E: Engine, C: Circuit -{ - let mut assembly = KeypairAssembly { - num_inputs: 0, - num_aux: 0, - num_constraints: 0, - at_inputs: vec![], - bt_inputs: vec![], - ct_inputs: vec![], - at_aux: vec![], - bt_aux: vec![], - ct_aux: vec![] - }; - - // Allocate the "one" input variable - assembly.alloc_input(|| "", || Ok(E::Fr::one()))?; - - // Synthesize the circuit. - circuit.synthesize(&mut assembly)?; - - // Input constraints to ensure full density of IC query - // x * 0 = 0 - for i in 0..assembly.num_inputs { - assembly.enforce(|| "", - |lc| lc + Variable(Index::Input(i)), - |lc| lc, - |lc| lc, - ); - } - - // Create bases for blind evaluation of polynomials at tau - let powers_of_tau = vec![Scalar::(E::Fr::zero()); assembly.num_constraints]; - let mut powers_of_tau = EvaluationDomain::from_coeffs(powers_of_tau)?; - - // Compute G1 window table - let mut g1_wnaf = Wnaf::new(); - let g1_wnaf = g1_wnaf.base(g1, { - // H query - (powers_of_tau.as_ref().len() - 1) - // IC/L queries - + assembly.num_inputs + assembly.num_aux - // A query - + assembly.num_inputs + assembly.num_aux - // B query - + assembly.num_inputs + assembly.num_aux - }); - - // Compute G2 window table - let mut g2_wnaf = Wnaf::new(); - let g2_wnaf = g2_wnaf.base(g2, { - // B query - assembly.num_inputs + assembly.num_aux - }); - - let gamma_inverse = gamma.inverse().ok_or(SynthesisError::UnexpectedIdentity)?; - let delta_inverse = delta.inverse().ok_or(SynthesisError::UnexpectedIdentity)?; - - let worker = Worker::new(); - - let mut h = vec![E::G1::zero(); powers_of_tau.as_ref().len() - 1]; - { - // Compute powers of tau - { - let powers_of_tau = powers_of_tau.as_mut(); - worker.scope(powers_of_tau.len(), |scope, chunk| { - for (i, powers_of_tau) in powers_of_tau.chunks_mut(chunk).enumerate() - { - scope.spawn(move || { - let mut current_tau_power = tau.pow(&[(i*chunk) as u64]); - - for p in powers_of_tau { - p.0 = current_tau_power; - current_tau_power.mul_assign(&tau); - } - }); - } - }); - } - - // coeff = t(x) / delta - let mut coeff = powers_of_tau.z(&tau); - coeff.mul_assign(&delta_inverse); - - // Compute the H query with multiple threads - worker.scope(h.len(), |scope, chunk| { - for (h, p) in h.chunks_mut(chunk).zip(powers_of_tau.as_ref().chunks(chunk)) - { - let mut g1_wnaf = g1_wnaf.shared(); - - scope.spawn(move || { - // Set values of the H query to g1^{(tau^i * t(tau)) / delta} - for (h, p) in h.iter_mut().zip(p.iter()) - { - // Compute final exponent - let mut exp = p.0; - exp.mul_assign(&coeff); - - // Exponentiate - *h = g1_wnaf.scalar(exp.into_repr()); - } - - // Batch normalize - E::G1::batch_normalization(h); - }); - } - }); - } - - // Use inverse FFT to convert powers of tau to Lagrange coefficients - powers_of_tau.ifft(&worker); - let powers_of_tau = powers_of_tau.into_coeffs(); - - let mut a = vec![E::G1::zero(); assembly.num_inputs + assembly.num_aux]; - let mut b_g1 = vec![E::G1::zero(); assembly.num_inputs + assembly.num_aux]; - let mut b_g2 = vec![E::G2::zero(); assembly.num_inputs + assembly.num_aux]; - let mut ic = vec![E::G1::zero(); assembly.num_inputs]; - let mut l = vec![E::G1::zero(); assembly.num_aux]; - - fn eval( - // wNAF window tables - g1_wnaf: &Wnaf>, - g2_wnaf: &Wnaf>, - - // Lagrange coefficients for tau - powers_of_tau: &[Scalar], - - // QAP polynomials - at: &[Vec<(E::Fr, usize)>], - bt: &[Vec<(E::Fr, usize)>], - ct: &[Vec<(E::Fr, usize)>], - - // Resulting evaluated QAP polynomials - a: &mut [E::G1], - b_g1: &mut [E::G1], - b_g2: &mut [E::G2], - ext: &mut [E::G1], - - // Inverse coefficient for ext elements - inv: &E::Fr, - - // Trapdoors - alpha: &E::Fr, - beta: &E::Fr, - - // Worker - worker: &Worker - ) - { - // Sanity check - assert_eq!(a.len(), at.len()); - assert_eq!(a.len(), bt.len()); - assert_eq!(a.len(), ct.len()); - assert_eq!(a.len(), b_g1.len()); - assert_eq!(a.len(), b_g2.len()); - assert_eq!(a.len(), ext.len()); - - // Evaluate polynomials in multiple threads - worker.scope(a.len(), |scope, chunk| { - for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a.chunks_mut(chunk) - .zip(b_g1.chunks_mut(chunk)) - .zip(b_g2.chunks_mut(chunk)) - .zip(ext.chunks_mut(chunk)) - .zip(at.chunks(chunk)) - .zip(bt.chunks(chunk)) - .zip(ct.chunks(chunk)) - { - let mut g1_wnaf = g1_wnaf.shared(); - let mut g2_wnaf = g2_wnaf.shared(); - - scope.spawn(move || { - for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a.iter_mut() - .zip(b_g1.iter_mut()) - .zip(b_g2.iter_mut()) - .zip(ext.iter_mut()) - .zip(at.iter()) - .zip(bt.iter()) - .zip(ct.iter()) - { - fn eval_at_tau( - powers_of_tau: &[Scalar], - p: &[(E::Fr, usize)] - ) -> E::Fr - { - let mut acc = E::Fr::zero(); - - for &(ref coeff, index) in p { - let mut n = powers_of_tau[index].0; - n.mul_assign(coeff); - acc.add_assign(&n); - } - - acc - } - - // Evaluate QAP polynomials at tau - let mut at = eval_at_tau(powers_of_tau, at); - let mut bt = eval_at_tau(powers_of_tau, bt); - let ct = eval_at_tau(powers_of_tau, ct); - - // Compute A query (in G1) - if !at.is_zero() { - *a = g1_wnaf.scalar(at.into_repr()); - } - - // Compute B query (in G1/G2) - if !bt.is_zero() { - let bt_repr = bt.into_repr(); - *b_g1 = g1_wnaf.scalar(bt_repr); - *b_g2 = g2_wnaf.scalar(bt_repr); - } - - at.mul_assign(&beta); - bt.mul_assign(&alpha); - - let mut e = at; - e.add_assign(&bt); - e.add_assign(&ct); - e.mul_assign(inv); - - *ext = g1_wnaf.scalar(e.into_repr()); - } - - // Batch normalize - E::G1::batch_normalization(a); - E::G1::batch_normalization(b_g1); - E::G2::batch_normalization(b_g2); - E::G1::batch_normalization(ext); - }); - } - }); - } - - // Evaluate for inputs. - eval( - &g1_wnaf, - &g2_wnaf, - &powers_of_tau, - &assembly.at_inputs, - &assembly.bt_inputs, - &assembly.ct_inputs, - &mut a[0..assembly.num_inputs], - &mut b_g1[0..assembly.num_inputs], - &mut b_g2[0..assembly.num_inputs], - &mut ic, - &gamma_inverse, - &alpha, - &beta, - &worker - ); - - // Evaluate for auxillary variables. - eval( - &g1_wnaf, - &g2_wnaf, - &powers_of_tau, - &assembly.at_aux, - &assembly.bt_aux, - &assembly.ct_aux, - &mut a[assembly.num_inputs..], - &mut b_g1[assembly.num_inputs..], - &mut b_g2[assembly.num_inputs..], - &mut l, - &delta_inverse, - &alpha, - &beta, - &worker - ); - - // Don't allow any elements be unconstrained, so that - // the L query is always fully dense. - for e in l.iter() { - if e.is_zero() { - return Err(SynthesisError::UnconstrainedVariable); - } - } - - let g1 = g1.into_affine(); - let g2 = g2.into_affine(); - - let vk = VerifyingKey:: { - alpha_g1: g1.mul(alpha).into_affine(), - beta_g1: g1.mul(beta).into_affine(), - beta_g2: g2.mul(beta).into_affine(), - gamma_g2: g2.mul(gamma).into_affine(), - delta_g1: g1.mul(delta).into_affine(), - delta_g2: g2.mul(delta).into_affine(), - ic: ic.into_iter().map(|e| e.into_affine()).collect() - }; - - Ok(Parameters { - vk: vk, - h: Arc::new(h.into_iter().map(|e| e.into_affine()).collect()), - l: Arc::new(l.into_iter().map(|e| e.into_affine()).collect()), - - // Filter points at infinity away from A/B queries - a: Arc::new(a.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()), - b_g1: Arc::new(b_g1.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()), - b_g2: Arc::new(b_g2.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()) - }) -} diff --git a/bellman/src/groth16/mod.rs b/bellman/src/groth16/mod.rs deleted file mode 100644 index 3b8d671..0000000 --- a/bellman/src/groth16/mod.rs +++ /dev/null @@ -1,576 +0,0 @@ -use pairing::{ - Engine, - CurveAffine, - EncodedPoint -}; - -use ::{ - SynthesisError -}; - -use multiexp::SourceBuilder; -use std::io::{self, Read, Write}; -use std::sync::Arc; -use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; - -#[cfg(test)] -mod tests; - -mod generator; -mod prover; -mod verifier; - -pub use self::generator::*; -pub use self::prover::*; -pub use self::verifier::*; - -#[derive(Clone)] -pub struct Proof { - pub a: E::G1Affine, - pub b: E::G2Affine, - pub c: E::G1Affine -} - -impl PartialEq for Proof { - fn eq(&self, other: &Self) -> bool { - self.a == other.a && - self.b == other.b && - self.c == other.c - } -} - -impl Proof { - pub fn write( - &self, - mut writer: W - ) -> io::Result<()> - { - writer.write_all(self.a.into_compressed().as_ref())?; - writer.write_all(self.b.into_compressed().as_ref())?; - writer.write_all(self.c.into_compressed().as_ref())?; - - Ok(()) - } - - pub fn read( - mut reader: R - ) -> io::Result - { - let mut g1_repr = ::Compressed::empty(); - let mut g2_repr = ::Compressed::empty(); - - reader.read_exact(g1_repr.as_mut())?; - let a = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) - })?; - - reader.read_exact(g2_repr.as_mut())?; - let b = g2_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) - })?; - - reader.read_exact(g1_repr.as_mut())?; - let c = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) - })?; - - Ok(Proof { - a: a, - b: b, - c: c - }) - } -} - -#[derive(Clone)] -pub struct VerifyingKey { - // alpha in g1 for verifying and for creating A/C elements of - // proof. Never the point at infinity. - pub alpha_g1: E::G1Affine, - - // beta in g1 and g2 for verifying and for creating B/C elements - // of proof. Never the point at infinity. - pub beta_g1: E::G1Affine, - pub beta_g2: E::G2Affine, - - // gamma in g2 for verifying. Never the point at infinity. - pub gamma_g2: E::G2Affine, - - // delta in g1/g2 for verifying and proving, essentially the magic - // trapdoor that forces the prover to evaluate the C element of the - // proof with only components from the CRS. Never the point at - // infinity. - pub delta_g1: E::G1Affine, - pub delta_g2: E::G2Affine, - - // Elements of the form (beta * u_i(tau) + alpha v_i(tau) + w_i(tau)) / gamma - // for all public inputs. Because all public inputs have a dummy constraint, - // this is the same size as the number of inputs, and never contains points - // at infinity. - pub ic: Vec -} - -impl PartialEq for VerifyingKey { - fn eq(&self, other: &Self) -> bool { - self.alpha_g1 == other.alpha_g1 && - self.beta_g1 == other.beta_g1 && - self.beta_g2 == other.beta_g2 && - self.gamma_g2 == other.gamma_g2 && - self.delta_g1 == other.delta_g1 && - self.delta_g2 == other.delta_g2 && - self.ic == other.ic - } -} - -impl VerifyingKey { - pub fn write( - &self, - mut writer: W - ) -> io::Result<()> - { - writer.write_all(self.alpha_g1.into_uncompressed().as_ref())?; - writer.write_all(self.beta_g1.into_uncompressed().as_ref())?; - writer.write_all(self.beta_g2.into_uncompressed().as_ref())?; - writer.write_all(self.gamma_g2.into_uncompressed().as_ref())?; - writer.write_all(self.delta_g1.into_uncompressed().as_ref())?; - writer.write_all(self.delta_g2.into_uncompressed().as_ref())?; - writer.write_u32::(self.ic.len() as u32)?; - for ic in &self.ic { - writer.write_all(ic.into_uncompressed().as_ref())?; - } - - Ok(()) - } - - pub fn read( - mut reader: R - ) -> io::Result - { - let mut g1_repr = ::Uncompressed::empty(); - let mut g2_repr = ::Uncompressed::empty(); - - reader.read_exact(g1_repr.as_mut())?; - let alpha_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - - reader.read_exact(g1_repr.as_mut())?; - let beta_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - - reader.read_exact(g2_repr.as_mut())?; - let beta_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - - reader.read_exact(g2_repr.as_mut())?; - let gamma_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - - reader.read_exact(g1_repr.as_mut())?; - let delta_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - - reader.read_exact(g2_repr.as_mut())?; - let delta_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - - let ic_len = reader.read_u32::()? as usize; - - let mut ic = vec![]; - - for _ in 0..ic_len { - reader.read_exact(g1_repr.as_mut())?; - let g1 = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) - })?; - - ic.push(g1); - } - - Ok(VerifyingKey { - alpha_g1: alpha_g1, - beta_g1: beta_g1, - beta_g2: beta_g2, - gamma_g2: gamma_g2, - delta_g1: delta_g1, - delta_g2: delta_g2, - ic: ic - }) - } -} - -#[derive(Clone)] -pub struct Parameters { - pub vk: VerifyingKey, - - // Elements of the form ((tau^i * t(tau)) / delta) for i between 0 and - // m-2 inclusive. Never contains points at infinity. - pub h: Arc>, - - // Elements of the form (beta * u_i(tau) + alpha v_i(tau) + w_i(tau)) / delta - // for all auxillary inputs. Variables can never be unconstrained, so this - // never contains points at infinity. - pub l: Arc>, - - // QAP "A" polynomials evaluated at tau in the Lagrange basis. Never contains - // points at infinity: polynomials that evaluate to zero are omitted from - // the CRS and the prover can deterministically skip their evaluation. - pub a: Arc>, - - // QAP "B" polynomials evaluated at tau in the Lagrange basis. Needed in - // G1 and G2 for C/B queries, respectively. Never contains points at - // infinity for the same reason as the "A" polynomials. - pub b_g1: Arc>, - pub b_g2: Arc> -} - -impl PartialEq for Parameters { - fn eq(&self, other: &Self) -> bool { - self.vk == other.vk && - self.h == other.h && - self.l == other.l && - self.a == other.a && - self.b_g1 == other.b_g1 && - self.b_g2 == other.b_g2 - } -} - -impl Parameters { - pub fn write( - &self, - mut writer: W - ) -> io::Result<()> - { - self.vk.write(&mut writer)?; - - writer.write_u32::(self.h.len() as u32)?; - for g in &self.h[..] { - writer.write_all(g.into_uncompressed().as_ref())?; - } - - writer.write_u32::(self.l.len() as u32)?; - for g in &self.l[..] { - writer.write_all(g.into_uncompressed().as_ref())?; - } - - writer.write_u32::(self.a.len() as u32)?; - for g in &self.a[..] { - writer.write_all(g.into_uncompressed().as_ref())?; - } - - writer.write_u32::(self.b_g1.len() as u32)?; - for g in &self.b_g1[..] { - writer.write_all(g.into_uncompressed().as_ref())?; - } - - writer.write_u32::(self.b_g2.len() as u32)?; - for g in &self.b_g2[..] { - writer.write_all(g.into_uncompressed().as_ref())?; - } - - Ok(()) - } - - pub fn read( - mut reader: R, - checked: bool - ) -> io::Result - { - let read_g1 = |reader: &mut R| -> io::Result { - let mut repr = ::Uncompressed::empty(); - reader.read_exact(repr.as_mut())?; - - if checked { - repr - .into_affine() - } else { - repr - .into_affine_unchecked() - } - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) - }) - }; - - let read_g2 = |reader: &mut R| -> io::Result { - let mut repr = ::Uncompressed::empty(); - reader.read_exact(repr.as_mut())?; - - if checked { - repr - .into_affine() - } else { - repr - .into_affine_unchecked() - } - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) - }) - }; - - let vk = VerifyingKey::::read(&mut reader)?; - - let mut h = vec![]; - let mut l = vec![]; - let mut a = vec![]; - let mut b_g1 = vec![]; - let mut b_g2 = vec![]; - - { - let len = reader.read_u32::()? as usize; - for _ in 0..len { - h.push(read_g1(&mut reader)?); - } - } - - { - let len = reader.read_u32::()? as usize; - for _ in 0..len { - l.push(read_g1(&mut reader)?); - } - } - - { - let len = reader.read_u32::()? as usize; - for _ in 0..len { - a.push(read_g1(&mut reader)?); - } - } - - { - let len = reader.read_u32::()? as usize; - for _ in 0..len { - b_g1.push(read_g1(&mut reader)?); - } - } - - { - let len = reader.read_u32::()? as usize; - for _ in 0..len { - b_g2.push(read_g2(&mut reader)?); - } - } - - Ok(Parameters { - vk: vk, - h: Arc::new(h), - l: Arc::new(l), - a: Arc::new(a), - b_g1: Arc::new(b_g1), - b_g2: Arc::new(b_g2) - }) - } -} - -pub struct PreparedVerifyingKey { - /// Pairing result of alpha*beta - alpha_g1_beta_g2: E::Fqk, - /// -gamma in G2 - neg_gamma_g2: ::Prepared, - /// -delta in G2 - neg_delta_g2: ::Prepared, - /// Copy of IC from `VerifiyingKey`. - ic: Vec -} - -pub trait ParameterSource { - type G1Builder: SourceBuilder; - type G2Builder: SourceBuilder; - - fn get_vk( - &mut self, - num_ic: usize - ) -> Result, SynthesisError>; - fn get_h( - &mut self, - num_h: usize - ) -> Result; - fn get_l( - &mut self, - num_l: usize - ) -> Result; - fn get_a( - &mut self, - num_inputs: usize, - num_aux: usize - ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>; - fn get_b_g1( - &mut self, - num_inputs: usize, - num_aux: usize - ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>; - fn get_b_g2( - &mut self, - num_inputs: usize, - num_aux: usize - ) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError>; -} - -impl<'a, E: Engine> ParameterSource for &'a Parameters { - type G1Builder = (Arc>, usize); - type G2Builder = (Arc>, usize); - - fn get_vk( - &mut self, - _: usize - ) -> Result, SynthesisError> - { - Ok(self.vk.clone()) - } - - fn get_h( - &mut self, - _: usize - ) -> Result - { - Ok((self.h.clone(), 0)) - } - - fn get_l( - &mut self, - _: usize - ) -> Result - { - Ok((self.l.clone(), 0)) - } - - fn get_a( - &mut self, - num_inputs: usize, - _: usize - ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> - { - Ok(((self.a.clone(), 0), (self.a.clone(), num_inputs))) - } - - fn get_b_g1( - &mut self, - num_inputs: usize, - _: usize - ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> - { - Ok(((self.b_g1.clone(), 0), (self.b_g1.clone(), num_inputs))) - } - - fn get_b_g2( - &mut self, - num_inputs: usize, - _: usize - ) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError> - { - Ok(((self.b_g2.clone(), 0), (self.b_g2.clone(), num_inputs))) - } -} - -#[cfg(test)] -mod test_with_bls12_381 { - use super::*; - use {Circuit, SynthesisError, ConstraintSystem}; - - use rand::{Rand, thread_rng}; - use pairing::{Field}; - use pairing::bls12_381::{Bls12, Fr}; - - #[test] - fn serialization() { - struct MySillyCircuit { - a: Option, - b: Option - } - - impl Circuit for MySillyCircuit { - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { - let a = cs.alloc(|| "a", || self.a.ok_or(SynthesisError::AssignmentMissing))?; - let b = cs.alloc(|| "b", || self.b.ok_or(SynthesisError::AssignmentMissing))?; - let c = cs.alloc_input(|| "c", || { - let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?; - let b = self.b.ok_or(SynthesisError::AssignmentMissing)?; - - a.mul_assign(&b); - Ok(a) - })?; - - cs.enforce( - || "a*b=c", - |lc| lc + a, - |lc| lc + b, - |lc| lc + c - ); - - Ok(()) - } - } - - let rng = &mut thread_rng(); - - let params = generate_random_parameters::( - MySillyCircuit { a: None, b: None }, - rng - ).unwrap(); - - { - let mut v = vec![]; - - params.write(&mut v).unwrap(); - assert_eq!(v.len(), 2136); - - let de_params = Parameters::read(&v[..], true).unwrap(); - assert!(params == de_params); - - let de_params = Parameters::read(&v[..], false).unwrap(); - assert!(params == de_params); - } - - let pvk = prepare_verifying_key::(¶ms.vk); - - for _ in 0..100 { - let a = Fr::rand(rng); - let b = Fr::rand(rng); - let mut c = a; - c.mul_assign(&b); - - let proof = create_random_proof( - MySillyCircuit { - a: Some(a), - b: Some(b) - }, - ¶ms, - rng - ).unwrap(); - - let mut v = vec![]; - proof.write(&mut v).unwrap(); - - assert_eq!(v.len(), 192); - - let de_proof = Proof::read(&v[..]).unwrap(); - assert!(proof == de_proof); - - assert!(verify_proof(&pvk, &proof, &[c]).unwrap()); - assert!(!verify_proof(&pvk, &proof, &[a]).unwrap()); - } - } -} diff --git a/bellman/src/groth16/prover.rs b/bellman/src/groth16/prover.rs deleted file mode 100644 index f21fcce..0000000 --- a/bellman/src/groth16/prover.rs +++ /dev/null @@ -1,334 +0,0 @@ -use rand::Rng; - -use std::sync::Arc; - -use futures::Future; - -use pairing::{ - Engine, - PrimeField, - Field, - CurveProjective, - CurveAffine -}; - -use super::{ - ParameterSource, - Proof -}; - -use ::{ - SynthesisError, - Circuit, - ConstraintSystem, - LinearCombination, - Variable, - Index -}; - -use ::domain::{ - EvaluationDomain, - Scalar -}; - -use ::multiexp::{ - DensityTracker, - FullDensity, - multiexp -}; - -use ::multicore::{ - Worker -}; - -fn eval( - lc: &LinearCombination, - mut input_density: Option<&mut DensityTracker>, - mut aux_density: Option<&mut DensityTracker>, - input_assignment: &[E::Fr], - aux_assignment: &[E::Fr] -) -> E::Fr -{ - let mut acc = E::Fr::zero(); - - for &(index, coeff) in lc.0.iter() { - let mut tmp; - - match index { - Variable(Index::Input(i)) => { - tmp = input_assignment[i]; - if let Some(ref mut v) = input_density { - v.inc(i); - } - }, - Variable(Index::Aux(i)) => { - tmp = aux_assignment[i]; - if let Some(ref mut v) = aux_density { - v.inc(i); - } - } - } - - if coeff == E::Fr::one() { - acc.add_assign(&tmp); - } else { - tmp.mul_assign(&coeff); - acc.add_assign(&tmp); - } - } - - acc -} - -struct ProvingAssignment { - // Density of queries - a_aux_density: DensityTracker, - b_input_density: DensityTracker, - b_aux_density: DensityTracker, - - // Evaluations of A, B, C polynomials - a: Vec>, - b: Vec>, - c: Vec>, - - // Assignments of variables - input_assignment: Vec, - aux_assignment: Vec -} - -impl ConstraintSystem for ProvingAssignment { - type Root = Self; - - fn alloc( - &mut self, - _: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into - { - self.aux_assignment.push(f()?); - self.a_aux_density.add_element(); - self.b_aux_density.add_element(); - - Ok(Variable(Index::Aux(self.aux_assignment.len() - 1))) - } - - fn alloc_input( - &mut self, - _: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into - { - self.input_assignment.push(f()?); - self.b_input_density.add_element(); - - Ok(Variable(Index::Input(self.input_assignment.len() - 1))) - } - - fn enforce( - &mut self, - _: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination - { - let a = a(LinearCombination::zero()); - let b = b(LinearCombination::zero()); - let c = c(LinearCombination::zero()); - - self.a.push(Scalar(eval( - &a, - // Inputs have full density in the A query - // because there are constraints of the - // form x * 0 = 0 for each input. - None, - Some(&mut self.a_aux_density), - &self.input_assignment, - &self.aux_assignment - ))); - self.b.push(Scalar(eval( - &b, - Some(&mut self.b_input_density), - Some(&mut self.b_aux_density), - &self.input_assignment, - &self.aux_assignment - ))); - self.c.push(Scalar(eval( - &c, - // There is no C polynomial query, - // though there is an (beta)A + (alpha)B + C - // query for all aux variables. - // However, that query has full density. - None, - None, - &self.input_assignment, - &self.aux_assignment - ))); - } - - fn push_namespace(&mut self, _: N) - where NR: Into, N: FnOnce() -> NR - { - // Do nothing; we don't care about namespaces in this context. - } - - fn pop_namespace(&mut self) - { - // Do nothing; we don't care about namespaces in this context. - } - - fn get_root(&mut self) -> &mut Self::Root { - self - } -} - -pub fn create_random_proof>( - circuit: C, - params: P, - rng: &mut R -) -> Result, SynthesisError> - where E: Engine, C: Circuit, R: Rng -{ - let r = rng.gen(); - let s = rng.gen(); - - create_proof::(circuit, params, r, s) -} - -pub fn create_proof>( - circuit: C, - mut params: P, - r: E::Fr, - s: E::Fr -) -> Result, SynthesisError> - where E: Engine, C: Circuit -{ - let mut prover = ProvingAssignment { - a_aux_density: DensityTracker::new(), - b_input_density: DensityTracker::new(), - b_aux_density: DensityTracker::new(), - a: vec![], - b: vec![], - c: vec![], - input_assignment: vec![], - aux_assignment: vec![] - }; - - prover.alloc_input(|| "", || Ok(E::Fr::one()))?; - - circuit.synthesize(&mut prover)?; - - for i in 0..prover.input_assignment.len() { - prover.enforce(|| "", - |lc| lc + Variable(Index::Input(i)), - |lc| lc, - |lc| lc, - ); - } - - let worker = Worker::new(); - - let vk = params.get_vk(prover.input_assignment.len())?; - - let h = { - let mut a = EvaluationDomain::from_coeffs(prover.a)?; - let mut b = EvaluationDomain::from_coeffs(prover.b)?; - let mut c = EvaluationDomain::from_coeffs(prover.c)?; - a.ifft(&worker); - a.coset_fft(&worker); - b.ifft(&worker); - b.coset_fft(&worker); - c.ifft(&worker); - c.coset_fft(&worker); - - a.mul_assign(&worker, &b); - drop(b); - a.sub_assign(&worker, &c); - drop(c); - a.divide_by_z_on_coset(&worker); - a.icoset_fft(&worker); - let mut a = a.into_coeffs(); - let a_len = a.len() - 1; - a.truncate(a_len); - // TODO: parallelize if it's even helpful - let a = Arc::new(a.into_iter().map(|s| s.0.into_repr()).collect::>()); - - multiexp(&worker, params.get_h(a.len())?, FullDensity, a) - }; - - // TODO: parallelize if it's even helpful - let input_assignment = Arc::new(prover.input_assignment.into_iter().map(|s| s.into_repr()).collect::>()); - let aux_assignment = Arc::new(prover.aux_assignment.into_iter().map(|s| s.into_repr()).collect::>()); - - let l = multiexp(&worker, params.get_l(aux_assignment.len())?, FullDensity, aux_assignment.clone()); - - let a_aux_density_total = prover.a_aux_density.get_total_density(); - - let (a_inputs_source, a_aux_source) = params.get_a(input_assignment.len(), a_aux_density_total)?; - - let a_inputs = multiexp(&worker, a_inputs_source, FullDensity, input_assignment.clone()); - let a_aux = multiexp(&worker, a_aux_source, Arc::new(prover.a_aux_density), aux_assignment.clone()); - - let b_input_density = Arc::new(prover.b_input_density); - let b_input_density_total = b_input_density.get_total_density(); - let b_aux_density = Arc::new(prover.b_aux_density); - let b_aux_density_total = b_aux_density.get_total_density(); - - let (b_g1_inputs_source, b_g1_aux_source) = params.get_b_g1(b_input_density_total, b_aux_density_total)?; - - let b_g1_inputs = multiexp(&worker, b_g1_inputs_source, b_input_density.clone(), input_assignment.clone()); - let b_g1_aux = multiexp(&worker, b_g1_aux_source, b_aux_density.clone(), aux_assignment.clone()); - - let (b_g2_inputs_source, b_g2_aux_source) = params.get_b_g2(b_input_density_total, b_aux_density_total)?; - - let b_g2_inputs = multiexp(&worker, b_g2_inputs_source, b_input_density, input_assignment); - let b_g2_aux = multiexp(&worker, b_g2_aux_source, b_aux_density, aux_assignment); - - if vk.delta_g1.is_zero() || vk.delta_g2.is_zero() { - // If this element is zero, someone is trying to perform a - // subversion-CRS attack. - return Err(SynthesisError::UnexpectedIdentity); - } - - let mut g_a = vk.delta_g1.mul(r); - g_a.add_assign_mixed(&vk.alpha_g1); - let mut g_b = vk.delta_g2.mul(s); - g_b.add_assign_mixed(&vk.beta_g2); - let mut g_c; - { - let mut rs = r; - rs.mul_assign(&s); - - g_c = vk.delta_g1.mul(rs); - g_c.add_assign(&vk.alpha_g1.mul(s)); - g_c.add_assign(&vk.beta_g1.mul(r)); - } - let mut a_answer = a_inputs.wait()?; - a_answer.add_assign(&a_aux.wait()?); - g_a.add_assign(&a_answer); - a_answer.mul_assign(s); - g_c.add_assign(&a_answer); - - let mut b1_answer = b_g1_inputs.wait()?; - b1_answer.add_assign(&b_g1_aux.wait()?); - let mut b2_answer = b_g2_inputs.wait()?; - b2_answer.add_assign(&b_g2_aux.wait()?); - - g_b.add_assign(&b2_answer); - b1_answer.mul_assign(r); - g_c.add_assign(&b1_answer); - g_c.add_assign(&h.wait()?); - g_c.add_assign(&l.wait()?); - - Ok(Proof { - a: g_a.into_affine(), - b: g_b.into_affine(), - c: g_c.into_affine() - }) -} diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs deleted file mode 100644 index 26c8996..0000000 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ /dev/null @@ -1,451 +0,0 @@ -use pairing::{ - Engine, - PrimeField, - PrimeFieldRepr, - Field, - SqrtField, - LegendreSymbol, - CurveProjective, - CurveAffine, - PrimeFieldDecodingError, - GroupDecodingError, - EncodedPoint -}; - -use std::cmp::Ordering; -use std::fmt; -use rand::{Rand, Rng}; -use std::num::Wrapping; - -const MODULUS_R: Wrapping = Wrapping(64513); - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct Fr(Wrapping); - -impl fmt::Display for Fr { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(f, "{}", (self.0).0) - } -} - -impl Rand for Fr { - fn rand(rng: &mut R) -> Self { - Fr(Wrapping(rng.gen()) % MODULUS_R) - } -} - -impl Field for Fr { - fn zero() -> Self { - Fr(Wrapping(0)) - } - - fn one() -> Self { - Fr(Wrapping(1)) - } - - fn is_zero(&self) -> bool { - (self.0).0 == 0 - } - - fn square(&mut self) { - self.0 = (self.0 * self.0) % MODULUS_R; - } - - fn double(&mut self) { - self.0 = (self.0 << 1) % MODULUS_R; - } - - fn negate(&mut self) { - if !::is_zero(self) { - self.0 = MODULUS_R - self.0; - } - } - - fn add_assign(&mut self, other: &Self) { - self.0 = (self.0 + other.0) % MODULUS_R; - } - - fn sub_assign(&mut self, other: &Self) { - self.0 = ((MODULUS_R + self.0) - other.0) % MODULUS_R; - } - - fn mul_assign(&mut self, other: &Self) { - self.0 = (self.0 * other.0) % MODULUS_R; - } - - fn inverse(&self) -> Option { - if ::is_zero(self) { - None - } else { - Some(self.pow(&[(MODULUS_R.0 as u64) - 2])) - } - } - - fn frobenius_map(&mut self, _: usize) { - // identity - } -} - -impl SqrtField for Fr { - fn legendre(&self) -> LegendreSymbol { - // s = self^((r - 1) // 2) - let s = self.pow([32256]); - if s == ::zero() { LegendreSymbol::Zero } - else if s == ::one() { LegendreSymbol::QuadraticResidue } - else { LegendreSymbol::QuadraticNonResidue } - } - - fn sqrt(&self) -> Option { - // Tonelli-Shank's algorithm for q mod 16 = 1 - // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) - match self.legendre() { - LegendreSymbol::Zero => Some(*self), - LegendreSymbol::QuadraticNonResidue => None, - LegendreSymbol::QuadraticResidue => { - let mut c = Fr::root_of_unity(); - // r = self^((t + 1) // 2) - let mut r = self.pow([32]); - // t = self^t - let mut t = self.pow([63]); - let mut m = Fr::S; - - while t != ::one() { - let mut i = 1; - { - let mut t2i = t; - t2i.square(); - loop { - if t2i == ::one() { - break; - } - t2i.square(); - i += 1; - } - } - - for _ in 0..(m - i - 1) { - c.square(); - } - ::mul_assign(&mut r, &c); - c.square(); - ::mul_assign(&mut t, &c); - m = i; - } - - Some(r) - } - } - } -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct FrRepr([u64; 1]); - -impl Ord for FrRepr { - fn cmp(&self, other: &FrRepr) -> Ordering { - (self.0)[0].cmp(&(other.0)[0]) - } -} - -impl PartialOrd for FrRepr { - fn partial_cmp(&self, other: &FrRepr) -> Option { - Some(self.cmp(other)) - } -} - -impl Rand for FrRepr { - fn rand(rng: &mut R) -> Self { - FrRepr([rng.gen()]) - } -} - -impl fmt::Display for FrRepr { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(f, "{}", (self.0)[0]) - } -} - -impl From for FrRepr { - fn from(v: u64) -> FrRepr { - FrRepr([v]) - } -} - -impl From for FrRepr { - fn from(v: Fr) -> FrRepr { - FrRepr([(v.0).0 as u64]) - } -} - -impl AsMut<[u64]> for FrRepr { - fn as_mut(&mut self) -> &mut [u64] { - &mut self.0[..] - } -} - -impl AsRef<[u64]> for FrRepr { - fn as_ref(&self) -> &[u64] { - &self.0[..] - } -} - -impl Default for FrRepr { - fn default() -> FrRepr { - FrRepr::from(0u64) - } -} - -impl PrimeFieldRepr for FrRepr { - fn sub_noborrow(&mut self, other: &Self) { - self.0[0] = self.0[0].wrapping_sub(other.0[0]); - } - fn add_nocarry(&mut self, other: &Self) { - self.0[0] = self.0[0].wrapping_add(other.0[0]); - } - fn num_bits(&self) -> u32 { - 64 - self.0[0].leading_zeros() - } - fn is_zero(&self) -> bool { - self.0[0] == 0 - } - fn is_odd(&self) -> bool { - !self.is_even() - } - fn is_even(&self) -> bool { - self.0[0] % 2 == 0 - } - fn div2(&mut self) { - self.shr(1) - } - fn shr(&mut self, amt: u32) { - self.0[0] >>= amt; - } - fn mul2(&mut self) { - self.shl(1) - } - fn shl(&mut self, amt: u32) { - self.0[0] <<= amt; - } -} - -impl PrimeField for Fr { - type Repr = FrRepr; - - const NUM_BITS: u32 = 16; - const CAPACITY: u32 = 15; - const S: u32 = 10; - - fn from_repr(repr: FrRepr) -> Result { - if repr.0[0] >= (MODULUS_R.0 as u64) { - Err(PrimeFieldDecodingError::NotInField(format!("{}", repr))) - } else { - Ok(Fr(Wrapping(repr.0[0] as u32))) - } - } - - fn into_repr(&self) -> FrRepr { - FrRepr::from(*self) - } - - fn char() -> FrRepr { - Fr(MODULUS_R).into() - } - - fn multiplicative_generator() -> Fr { - Fr(Wrapping(5)) - } - - fn root_of_unity() -> Fr { - Fr(Wrapping(57751)) - } -} - -#[derive(Clone)] -pub struct DummyEngine; - -impl Engine for DummyEngine { - type Fr = Fr; - type G1 = Fr; - type G1Affine = Fr; - type G2 = Fr; - type G2Affine = Fr; - type Fq = Fr; - type Fqe = Fr; - - // TODO: This should be F_645131 or something. Doesn't matter for now. - type Fqk = Fr; - - fn miller_loop<'a, I>(i: I) -> Self::Fqk - where I: IntoIterator::Prepared, - &'a ::Prepared - )> - { - let mut acc = ::zero(); - - for &(a, b) in i { - let mut tmp = *a; - ::mul_assign(&mut tmp, b); - ::add_assign(&mut acc, &tmp); - } - - acc - } - - /// Perform final exponentiation of the result of a miller loop. - fn final_exponentiation(this: &Self::Fqk) -> Option - { - Some(*this) - } -} - -impl CurveProjective for Fr { - type Affine = Fr; - type Base = Fr; - type Scalar = Fr; - type Engine = DummyEngine; - - fn zero() -> Self { - ::zero() - } - - fn one() -> Self { - ::one() - } - - fn is_zero(&self) -> bool { - ::is_zero(self) - } - - fn batch_normalization(_: &mut [Self]) { - - } - - fn is_normalized(&self) -> bool { - true - } - - fn double(&mut self) { - ::double(self); - } - - fn add_assign(&mut self, other: &Self) { - ::add_assign(self, other); - } - - fn add_assign_mixed(&mut self, other: &Self) { - ::add_assign(self, other); - } - - fn negate(&mut self) { - ::negate(self); - } - - fn mul_assign::Repr>>(&mut self, other: S) - { - let tmp = Fr::from_repr(other.into()).unwrap(); - - ::mul_assign(self, &tmp); - } - - fn into_affine(&self) -> Fr { - *self - } - - fn recommended_wnaf_for_scalar(_: ::Repr) -> usize { - 3 - } - - fn recommended_wnaf_for_num_scalars(_: usize) -> usize { - 3 - } -} - -#[derive(Copy, Clone)] -pub struct FakePoint; - -impl AsMut<[u8]> for FakePoint { - fn as_mut(&mut self) -> &mut [u8] { - unimplemented!() - } -} - -impl AsRef<[u8]> for FakePoint { - fn as_ref(&self) -> &[u8] { - unimplemented!() - } -} - -impl EncodedPoint for FakePoint { - type Affine = Fr; - - fn empty() -> Self { - unimplemented!() - } - - fn size() -> usize { - unimplemented!() - } - - fn into_affine(&self) -> Result { - unimplemented!() - } - - fn into_affine_unchecked(&self) -> Result { - unimplemented!() - } - - fn from_affine(_: Self::Affine) -> Self { - unimplemented!() - } -} - -impl CurveAffine for Fr { - type Pair = Fr; - type PairingResult = Fr; - type Compressed = FakePoint; - type Uncompressed = FakePoint; - type Prepared = Fr; - type Projective = Fr; - type Base = Fr; - type Scalar = Fr; - type Engine = DummyEngine; - - fn zero() -> Self { - ::zero() - } - - fn one() -> Self { - ::one() - } - - fn is_zero(&self) -> bool { - ::is_zero(self) - } - - fn negate(&mut self) { - ::negate(self); - } - - fn mul::Repr>>(&self, other: S) -> Self::Projective - { - let mut res = *self; - let tmp = Fr::from_repr(other.into()).unwrap(); - - ::mul_assign(&mut res, &tmp); - - res - } - - fn prepare(&self) -> Self::Prepared { - *self - } - - fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult { - self.mul(*other) - } - - fn into_projective(&self) -> Self::Projective { - *self - } -} diff --git a/bellman/src/groth16/tests/mod.rs b/bellman/src/groth16/tests/mod.rs deleted file mode 100644 index a8e2914..0000000 --- a/bellman/src/groth16/tests/mod.rs +++ /dev/null @@ -1,400 +0,0 @@ -use pairing::{ - Engine, - Field, - PrimeField -}; - -mod dummy_engine; -use self::dummy_engine::*; - -use std::marker::PhantomData; - -use ::{ - Circuit, - ConstraintSystem, - SynthesisError -}; - -use super::{ - generate_parameters, - prepare_verifying_key, - create_proof, - verify_proof -}; - -struct XORDemo { - a: Option, - b: Option, - _marker: PhantomData -} - -impl Circuit for XORDemo { - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { - let a_var = cs.alloc(|| "a", || { - if self.a.is_some() { - if self.a.unwrap() { - Ok(E::Fr::one()) - } else { - Ok(E::Fr::zero()) - } - } else { - Err(SynthesisError::AssignmentMissing) - } - })?; - - cs.enforce( - || "a_boolean_constraint", - |lc| lc + CS::one() - a_var, - |lc| lc + a_var, - |lc| lc - ); - - let b_var = cs.alloc(|| "b", || { - if self.b.is_some() { - if self.b.unwrap() { - Ok(E::Fr::one()) - } else { - Ok(E::Fr::zero()) - } - } else { - Err(SynthesisError::AssignmentMissing) - } - })?; - - cs.enforce( - || "b_boolean_constraint", - |lc| lc + CS::one() - b_var, - |lc| lc + b_var, - |lc| lc - ); - - let c_var = cs.alloc_input(|| "c", || { - if self.a.is_some() && self.b.is_some() { - if self.a.unwrap() ^ self.b.unwrap() { - Ok(E::Fr::one()) - } else { - Ok(E::Fr::zero()) - } - } else { - Err(SynthesisError::AssignmentMissing) - } - })?; - - cs.enforce( - || "c_xor_constraint", - |lc| lc + a_var + a_var, - |lc| lc + b_var, - |lc| lc + a_var + b_var - c_var - ); - - Ok(()) - } -} - -#[test] -fn test_xordemo() { - let g1 = Fr::one(); - let g2 = Fr::one(); - let alpha = Fr::from_str("48577").unwrap(); - let beta = Fr::from_str("22580").unwrap(); - let gamma = Fr::from_str("53332").unwrap(); - let delta = Fr::from_str("5481").unwrap(); - let tau = Fr::from_str("3673").unwrap(); - - let params = { - let c = XORDemo:: { - a: None, - b: None, - _marker: PhantomData - }; - - generate_parameters( - c, - g1, - g2, - alpha, - beta, - gamma, - delta, - tau - ).unwrap() - }; - - // This will synthesize the constraint system: - // - // public inputs: a_0 = 1, a_1 = c - // aux inputs: a_2 = a, a_3 = b - // constraints: - // (a_0 - a_2) * (a_2) = 0 - // (a_0 - a_3) * (a_3) = 0 - // (a_2 + a_2) * (a_3) = (a_2 + a_3 - a_1) - // (a_0) * 0 = 0 - // (a_1) * 0 = 0 - - // The evaluation domain is 8. The H query should - // have 7 elements (it's a quotient polynomial) - assert_eq!(7, params.h.len()); - - let mut root_of_unity = Fr::root_of_unity(); - - // We expect this to be a 2^10 root of unity - assert_eq!(Fr::one(), root_of_unity.pow(&[1 << 10])); - - // Let's turn it into a 2^3 root of unity. - root_of_unity = root_of_unity.pow(&[1 << 7]); - assert_eq!(Fr::one(), root_of_unity.pow(&[1 << 3])); - assert_eq!(Fr::from_str("20201").unwrap(), root_of_unity); - - // Let's compute all the points in our evaluation domain. - let mut points = Vec::with_capacity(8); - for i in 0..8 { - points.push(root_of_unity.pow(&[i])); - } - - // Let's compute t(tau) = (tau - p_0)(tau - p_1)... - // = tau^8 - 1 - let mut t_at_tau = tau.pow(&[8]); - t_at_tau.sub_assign(&Fr::one()); - { - let mut tmp = Fr::one(); - for p in &points { - let mut term = tau; - term.sub_assign(p); - tmp.mul_assign(&term); - } - assert_eq!(tmp, t_at_tau); - } - - // We expect our H query to be 7 elements of the form... - // {tau^i t(tau) / delta} - let delta_inverse = delta.inverse().unwrap(); - let gamma_inverse = gamma.inverse().unwrap(); - { - let mut coeff = delta_inverse; - coeff.mul_assign(&t_at_tau); - - let mut cur = Fr::one(); - for h in params.h.iter() { - let mut tmp = cur; - tmp.mul_assign(&coeff); - - assert_eq!(*h, tmp); - - cur.mul_assign(&tau); - } - } - - // The density of the IC query is 2 (2 inputs) - assert_eq!(2, params.vk.ic.len()); - - // The density of the L query is 2 (2 aux variables) - assert_eq!(2, params.l.len()); - - // The density of the A query is 4 (each variable is in at least one A term) - assert_eq!(4, params.a.len()); - - // The density of the B query is 2 (two variables are in at least one B term) - assert_eq!(2, params.b_g1.len()); - assert_eq!(2, params.b_g2.len()); - - /* - Lagrange interpolation polynomials in our evaluation domain: - - ,-------------------------------. ,-------------------------------. ,-------------------------------. - | A TERM | | B TERM | | C TERM | - `-------------------------------. `-------------------------------' `-------------------------------' - | a_0 | a_1 | a_2 | a_3 | | a_0 | a_1 | a_2 | a_3 | | a_0 | a_1 | a_2 | a_3 | - | 1 | 0 | 64512 | 0 | | 0 | 0 | 1 | 0 | | 0 | 0 | 0 | 0 | - | 1 | 0 | 0 | 64512 | | 0 | 0 | 0 | 1 | | 0 | 0 | 0 | 0 | - | 0 | 0 | 2 | 0 | | 0 | 0 | 0 | 1 | | 0 | 64512 | 1 | 1 | - | 1 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | - | 0 | 1 | 0 | 0 | | 0 | 0 | 0 | 0 | | 0 | 0 | 0 | 0 | - `-------'-------'-------'-------' `-------'-------'-------'-------' `-------'-------'-------'-------' - - Example for u_0: - - sage: r = 64513 - sage: Fr = GF(r) - sage: omega = (Fr(5)^63)^(2^7) - sage: tau = Fr(3673) - sage: R. = PolynomialRing(Fr, 'x') - sage: def eval(tau, c0, c1, c2, c3, c4): - ....: p = R.lagrange_polynomial([(omega^0, c0), (omega^1, c1), (omega^2, c2), (omega^3, c3), (omega^4, c4), (omega^5, 0), (omega^6, 0), (omega^7, 0)]) - ....: return p.substitute(tau) - sage: eval(tau, 1, 1, 0, 1, 0) - 59158 - */ - - let u_i = [59158, 48317, 21767, 10402].iter().map(|e| { - Fr::from_str(&format!("{}", e)).unwrap() - }).collect::>(); - let v_i = [0, 0, 60619, 30791].iter().map(|e| { - Fr::from_str(&format!("{}", e)).unwrap() - }).collect::>(); - let w_i = [0, 23320, 41193, 41193].iter().map(|e| { - Fr::from_str(&format!("{}", e)).unwrap() - }).collect::>(); - - for (u, a) in u_i.iter() - .zip(¶ms.a[..]) - { - assert_eq!(u, a); - } - - for (v, b) in v_i.iter() - .filter(|&&e| e != Fr::zero()) - .zip(¶ms.b_g1[..]) - { - assert_eq!(v, b); - } - - for (v, b) in v_i.iter() - .filter(|&&e| e != Fr::zero()) - .zip(¶ms.b_g2[..]) - { - assert_eq!(v, b); - } - - for i in 0..4 { - let mut tmp1 = beta; - tmp1.mul_assign(&u_i[i]); - - let mut tmp2 = alpha; - tmp2.mul_assign(&v_i[i]); - - tmp1.add_assign(&tmp2); - tmp1.add_assign(&w_i[i]); - - if i < 2 { - // Check the correctness of the IC query elements - tmp1.mul_assign(&gamma_inverse); - - assert_eq!(tmp1, params.vk.ic[i]); - } else { - // Check the correctness of the L query elements - tmp1.mul_assign(&delta_inverse); - - assert_eq!(tmp1, params.l[i - 2]); - } - } - - // Check consistency of the other elements - assert_eq!(alpha, params.vk.alpha_g1); - assert_eq!(beta, params.vk.beta_g1); - assert_eq!(beta, params.vk.beta_g2); - assert_eq!(gamma, params.vk.gamma_g2); - assert_eq!(delta, params.vk.delta_g1); - assert_eq!(delta, params.vk.delta_g2); - - let pvk = prepare_verifying_key(¶ms.vk); - - let r = Fr::from_str("27134").unwrap(); - let s = Fr::from_str("17146").unwrap(); - - let proof = { - let c = XORDemo { - a: Some(true), - b: Some(false), - _marker: PhantomData - }; - - create_proof( - c, - ¶ms, - r, - s - ).unwrap() - }; - - // A(x) = - // a_0 * (44865*x^7 + 56449*x^6 + 44865*x^5 + 8064*x^4 + 3520*x^3 + 56449*x^2 + 3520*x + 40321) + - // a_1 * (8064*x^7 + 56449*x^6 + 8064*x^5 + 56449*x^4 + 8064*x^3 + 56449*x^2 + 8064*x + 56449) + - // a_2 * (16983*x^7 + 24192*x^6 + 63658*x^5 + 56449*x^4 + 16983*x^3 + 24192*x^2 + 63658*x + 56449) + - // a_3 * (5539*x^7 + 27797*x^6 + 6045*x^5 + 56449*x^4 + 58974*x^3 + 36716*x^2 + 58468*x + 8064) + - { - // proof A = alpha + A(tau) + delta * r - let mut expected_a = delta; - expected_a.mul_assign(&r); - expected_a.add_assign(&alpha); - expected_a.add_assign(&u_i[0]); // a_0 = 1 - expected_a.add_assign(&u_i[1]); // a_1 = 1 - expected_a.add_assign(&u_i[2]); // a_2 = 1 - // a_3 = 0 - assert_eq!(proof.a, expected_a); - } - - // B(x) = - // a_0 * (0) + - // a_1 * (0) + - // a_2 * (56449*x^7 + 56449*x^6 + 56449*x^5 + 56449*x^4 + 56449*x^3 + 56449*x^2 + 56449*x + 56449) + - // a_3 * (31177*x^7 + 44780*x^6 + 21752*x^5 + 42255*x^3 + 35861*x^2 + 33842*x + 48385) - { - // proof B = beta + B(tau) + delta * s - let mut expected_b = delta; - expected_b.mul_assign(&s); - expected_b.add_assign(&beta); - expected_b.add_assign(&v_i[0]); // a_0 = 1 - expected_b.add_assign(&v_i[1]); // a_1 = 1 - expected_b.add_assign(&v_i[2]); // a_2 = 1 - // a_3 = 0 - assert_eq!(proof.b, expected_b); - } - - // C(x) = - // a_0 * (0) + - // a_1 * (27797*x^7 + 56449*x^6 + 36716*x^5 + 8064*x^4 + 27797*x^3 + 56449*x^2 + 36716*x + 8064) + - // a_2 * (36716*x^7 + 8064*x^6 + 27797*x^5 + 56449*x^4 + 36716*x^3 + 8064*x^2 + 27797*x + 56449) + - // a_3 * (36716*x^7 + 8064*x^6 + 27797*x^5 + 56449*x^4 + 36716*x^3 + 8064*x^2 + 27797*x + 56449) - // - // If A * B = C at each point in the domain, then the following polynomial... - // P(x) = A(x) * B(x) - C(x) - // = 49752*x^14 + 13914*x^13 + 29243*x^12 + 27227*x^11 + 62362*x^10 + 35703*x^9 + 4032*x^8 + 14761*x^6 + 50599*x^5 + 35270*x^4 + 37286*x^3 + 2151*x^2 + 28810*x + 60481 - // - // ... should be divisible by t(x), producing the quotient polynomial: - // h(x) = P(x) / t(x) - // = 49752*x^6 + 13914*x^5 + 29243*x^4 + 27227*x^3 + 62362*x^2 + 35703*x + 4032 - { - let mut expected_c = Fr::zero(); - - // A * s - let mut tmp = proof.a; - tmp.mul_assign(&s); - expected_c.add_assign(&tmp); - - // B * r - let mut tmp = proof.b; - tmp.mul_assign(&r); - expected_c.add_assign(&tmp); - - // delta * r * s - let mut tmp = delta; - tmp.mul_assign(&r); - tmp.mul_assign(&s); - expected_c.sub_assign(&tmp); - - // L query answer - // a_2 = 1, a_3 = 0 - expected_c.add_assign(¶ms.l[0]); - - // H query answer - for (i, coeff) in [5040, 11763, 10755, 63633, 128, 9747, 8739].iter().enumerate() { - let coeff = Fr::from_str(&format!("{}", coeff)).unwrap(); - - let mut tmp = params.h[i]; - tmp.mul_assign(&coeff); - expected_c.add_assign(&tmp); - } - - assert_eq!(expected_c, proof.c); - } - - assert!(verify_proof( - &pvk, - &proof, - &[Fr::one()] - ).unwrap()); -} diff --git a/bellman/src/groth16/verifier.rs b/bellman/src/groth16/verifier.rs deleted file mode 100644 index 083e1d0..0000000 --- a/bellman/src/groth16/verifier.rs +++ /dev/null @@ -1,66 +0,0 @@ -use pairing::{ - Engine, - CurveProjective, - CurveAffine, - PrimeField -}; - -use super::{ - Proof, - VerifyingKey, - PreparedVerifyingKey -}; - -use ::{ - SynthesisError -}; - -pub fn prepare_verifying_key( - vk: &VerifyingKey -) -> PreparedVerifyingKey -{ - let mut gamma = vk.gamma_g2; - gamma.negate(); - let mut delta = vk.delta_g2; - delta.negate(); - - PreparedVerifyingKey { - alpha_g1_beta_g2: E::pairing(vk.alpha_g1, vk.beta_g2), - neg_gamma_g2: gamma.prepare(), - neg_delta_g2: delta.prepare(), - ic: vk.ic.clone() - } -} - -pub fn verify_proof<'a, E: Engine>( - pvk: &'a PreparedVerifyingKey, - proof: &Proof, - public_inputs: &[E::Fr] -) -> Result -{ - if (public_inputs.len() + 1) != pvk.ic.len() { - return Err(SynthesisError::MalformedVerifyingKey); - } - - let mut acc = pvk.ic[0].into_projective(); - - for (i, b) in public_inputs.iter().zip(pvk.ic.iter().skip(1)) { - acc.add_assign(&b.mul(i.into_repr())); - } - - // The original verification equation is: - // A * B = alpha * beta + inputs * gamma + C * delta - // ... however, we rearrange it so that it is: - // A * B - inputs * gamma - C * delta = alpha * beta - // or equivalently: - // A * B + inputs * (-gamma) + C * (-delta) = alpha * beta - // which allows us to do a single final exponentiation. - - Ok(E::final_exponentiation( - &E::miller_loop([ - (&proof.a.prepare(), &proof.b.prepare()), - (&acc.into_affine().prepare(), &pvk.neg_gamma_g2), - (&proof.c.prepare(), &pvk.neg_delta_g2) - ].into_iter()) - ).unwrap() == pvk.alpha_g1_beta_g2) -} diff --git a/bellman/src/lib.rs b/bellman/src/lib.rs deleted file mode 100644 index fb8d043..0000000 --- a/bellman/src/lib.rs +++ /dev/null @@ -1,424 +0,0 @@ -extern crate pairing; -extern crate rand; -extern crate num_cpus; -extern crate futures; -extern crate futures_cpupool; -extern crate bit_vec; -extern crate crossbeam; -extern crate byteorder; - -pub mod multicore; -mod multiexp; -pub mod domain; -pub mod groth16; - -use pairing::{Engine, Field}; - -use std::ops::{Add, Sub}; -use std::fmt; -use std::error::Error; -use std::io; -use std::marker::PhantomData; - -/// Computations are expressed in terms of arithmetic circuits, in particular -/// rank-1 quadratic constraint systems. The `Circuit` trait represents a -/// circuit that can be synthesized. The `synthesize` method is called during -/// CRS generation and during proving. -pub trait Circuit { - /// Synthesize the circuit into a rank-1 quadratic constraint system - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError>; -} - -/// Represents a variable in our constraint system. -#[derive(Copy, Clone, Debug)] -pub struct Variable(Index); - -impl Variable { - /// This constructs a variable with an arbitrary index. - /// Circuit implementations are not recommended to use this. - pub fn new_unchecked(idx: Index) -> Variable { - Variable(idx) - } - - /// This returns the index underlying the variable. - /// Circuit implementations are not recommended to use this. - pub fn get_unchecked(&self) -> Index { - self.0 - } -} - -/// Represents the index of either an input variable or -/// auxillary variable. -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum Index { - Input(usize), - Aux(usize) -} - -/// This represents a linear combination of some variables, with coefficients -/// in the scalar field of a pairing-friendly elliptic curve group. -#[derive(Clone)] -pub struct LinearCombination(Vec<(Variable, E::Fr)>); - -impl AsRef<[(Variable, E::Fr)]> for LinearCombination { - fn as_ref(&self) -> &[(Variable, E::Fr)] { - &self.0 - } -} - -impl LinearCombination { - pub fn zero() -> LinearCombination { - LinearCombination(vec![]) - } -} - -impl Add<(E::Fr, Variable)> for LinearCombination { - type Output = LinearCombination; - - fn add(mut self, (coeff, var): (E::Fr, Variable)) -> LinearCombination { - self.0.push((var, coeff)); - - self - } -} - -impl Sub<(E::Fr, Variable)> for LinearCombination { - type Output = LinearCombination; - - fn sub(self, (mut coeff, var): (E::Fr, Variable)) -> LinearCombination { - coeff.negate(); - - self + (coeff, var) - } -} - -impl Add for LinearCombination { - type Output = LinearCombination; - - fn add(self, other: Variable) -> LinearCombination { - self + (E::Fr::one(), other) - } -} - -impl Sub for LinearCombination { - type Output = LinearCombination; - - fn sub(self, other: Variable) -> LinearCombination { - self - (E::Fr::one(), other) - } -} - -impl<'a, E: Engine> Add<&'a LinearCombination> for LinearCombination { - type Output = LinearCombination; - - fn add(mut self, other: &'a LinearCombination) -> LinearCombination { - for s in &other.0 { - self = self + (s.1, s.0); - } - - self - } -} - -impl<'a, E: Engine> Sub<&'a LinearCombination> for LinearCombination { - type Output = LinearCombination; - - fn sub(mut self, other: &'a LinearCombination) -> LinearCombination { - for s in &other.0 { - self = self - (s.1, s.0); - } - - self - } -} - -impl<'a, E: Engine> Add<(E::Fr, &'a LinearCombination)> for LinearCombination { - type Output = LinearCombination; - - fn add(mut self, (coeff, other): (E::Fr, &'a LinearCombination)) -> LinearCombination { - for s in &other.0 { - let mut tmp = s.1; - tmp.mul_assign(&coeff); - self = self + (tmp, s.0); - } - - self - } -} - -impl<'a, E: Engine> Sub<(E::Fr, &'a LinearCombination)> for LinearCombination { - type Output = LinearCombination; - - fn sub(mut self, (coeff, other): (E::Fr, &'a LinearCombination)) -> LinearCombination { - for s in &other.0 { - let mut tmp = s.1; - tmp.mul_assign(&coeff); - self = self - (tmp, s.0); - } - - self - } -} - -/// This is an error that could occur during circuit synthesis contexts, -/// such as CRS generation, proving or verification. -#[derive(Debug)] -pub enum SynthesisError { - /// During synthesis, we lacked knowledge of a variable assignment. - AssignmentMissing, - /// During synthesis, we divided by zero. - DivisionByZero, - /// During synthesis, we constructed an unsatisfiable constraint system. - Unsatisfiable, - /// During synthesis, our polynomials ended up being too high of degree - PolynomialDegreeTooLarge, - /// During proof generation, we encountered an identity in the CRS - UnexpectedIdentity, - /// During proof generation, we encountered an I/O error with the CRS - IoError(io::Error), - /// During verification, our verifying key was malformed. - MalformedVerifyingKey, - /// During CRS generation, we observed an unconstrained auxillary variable - UnconstrainedVariable -} - -impl From for SynthesisError { - fn from(e: io::Error) -> SynthesisError { - SynthesisError::IoError(e) - } -} - -impl Error for SynthesisError { - fn description(&self) -> &str { - match *self { - SynthesisError::AssignmentMissing => "an assignment for a variable could not be computed", - SynthesisError::DivisionByZero => "division by zero", - SynthesisError::Unsatisfiable => "unsatisfiable constraint system", - SynthesisError::PolynomialDegreeTooLarge => "polynomial degree is too large", - SynthesisError::UnexpectedIdentity => "encountered an identity element in the CRS", - SynthesisError::IoError(_) => "encountered an I/O error", - SynthesisError::MalformedVerifyingKey => "malformed verifying key", - SynthesisError::UnconstrainedVariable => "auxillary variable was unconstrained" - } - } -} - -impl fmt::Display for SynthesisError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - if let &SynthesisError::IoError(ref e) = self { - write!(f, "I/O error: ")?; - e.fmt(f) - } else { - write!(f, "{}", self.description()) - } - } -} - -/// Represents a constraint system which can have new variables -/// allocated and constrains between them formed. -pub trait ConstraintSystem: Sized { - /// Represents the type of the "root" of this constraint system - /// so that nested namespaces can minimize indirection. - type Root: ConstraintSystem; - - /// Return the "one" input variable - fn one() -> Variable { - Variable::new_unchecked(Index::Input(0)) - } - - /// Allocate a private variable in the constraint system. The provided function is used to - /// determine the assignment of the variable. The given `annotation` function is invoked - /// in testing contexts in order to derive a unique name for this variable in the current - /// namespace. - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into; - - /// Allocate a public variable in the constraint system. The provided function is used to - /// determine the assignment of the variable. - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into; - - /// Enforce that `A` * `B` = `C`. The `annotation` function is invoked in testing contexts - /// in order to derive a unique name for the constraint in the current namespace. - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination; - - /// Create a new (sub)namespace and enter into it. Not intended - /// for downstream use; use `namespace` instead. - fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR; - - /// Exit out of the existing namespace. Not intended for - /// downstream use; use `namespace` instead. - fn pop_namespace(&mut self); - - /// Gets the "root" constraint system, bypassing the namespacing. - /// Not intended for downstream use; use `namespace` instead. - fn get_root(&mut self) -> &mut Self::Root; - - /// Begin a namespace for this constraint system. - fn namespace<'a, NR, N>( - &'a mut self, - name_fn: N - ) -> Namespace<'a, E, Self::Root> - where NR: Into, N: FnOnce() -> NR - { - self.get_root().push_namespace(name_fn); - - Namespace(self.get_root(), PhantomData) - } -} - -/// This is a "namespaced" constraint system which borrows a constraint system (pushing -/// a namespace context) and, when dropped, pops out of the namespace context. -pub struct Namespace<'a, E: Engine, CS: ConstraintSystem + 'a>(&'a mut CS, PhantomData); - -impl<'cs, E: Engine, CS: ConstraintSystem> ConstraintSystem for Namespace<'cs, E, CS> { - type Root = CS::Root; - - fn one() -> Variable { - CS::one() - } - - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into - { - self.0.alloc(annotation, f) - } - - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into - { - self.0.alloc_input(annotation, f) - } - - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination - { - self.0.enforce(annotation, a, b, c) - } - - // Downstream users who use `namespace` will never interact with these - // functions and they will never be invoked because the namespace is - // never a root constraint system. - - fn push_namespace(&mut self, _: N) - where NR: Into, N: FnOnce() -> NR - { - panic!("only the root's push_namespace should be called"); - } - - fn pop_namespace(&mut self) - { - panic!("only the root's pop_namespace should be called"); - } - - fn get_root(&mut self) -> &mut Self::Root - { - self.0.get_root() - } -} - -impl<'a, E: Engine, CS: ConstraintSystem> Drop for Namespace<'a, E, CS> { - fn drop(&mut self) { - self.get_root().pop_namespace() - } -} - -/// Convenience implementation of ConstraintSystem for mutable references to -/// constraint systems. -impl<'cs, E: Engine, CS: ConstraintSystem> ConstraintSystem for &'cs mut CS { - type Root = CS::Root; - - fn one() -> Variable { - CS::one() - } - - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into - { - (**self).alloc(annotation, f) - } - - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into - { - (**self).alloc_input(annotation, f) - } - - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination - { - (**self).enforce(annotation, a, b, c) - } - - fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR - { - (**self).push_namespace(name_fn) - } - - fn pop_namespace(&mut self) - { - (**self).pop_namespace() - } - - fn get_root(&mut self) -> &mut Self::Root - { - (**self).get_root() - } -} diff --git a/bellman/src/multicore.rs b/bellman/src/multicore.rs deleted file mode 100644 index c0062fc..0000000 --- a/bellman/src/multicore.rs +++ /dev/null @@ -1,106 +0,0 @@ -//! This is an interface for dealing with the kinds of -//! parallel computations involved in bellman. It's -//! currently just a thin wrapper around CpuPool and -//! crossbeam but may be extended in the future to -//! allow for various parallelism strategies. - -use num_cpus; -use futures::{Future, IntoFuture, Poll}; -use futures_cpupool::{CpuPool, CpuFuture}; -use crossbeam::{self, Scope}; - -#[derive(Clone)] -pub struct Worker { - cpus: usize, - pool: CpuPool -} - -impl Worker { - // We don't expose this outside the library so that - // all `Worker` instances have the same number of - // CPUs configured. - pub(crate) fn new_with_cpus(cpus: usize) -> Worker { - Worker { - cpus: cpus, - pool: CpuPool::new(cpus) - } - } - - pub fn new() -> Worker { - Self::new_with_cpus(num_cpus::get()) - } - - pub fn log_num_cpus(&self) -> u32 { - log2_floor(self.cpus) - } - - pub fn compute( - &self, f: F - ) -> WorkerFuture - where F: FnOnce() -> R + Send + 'static, - R: IntoFuture + 'static, - R::Future: Send + 'static, - R::Item: Send + 'static, - R::Error: Send + 'static - { - WorkerFuture { - future: self.pool.spawn_fn(f) - } - } - - pub fn scope<'a, F, R>( - &self, - elements: usize, - f: F - ) -> R - where F: FnOnce(&Scope<'a>, usize) -> R - { - let chunk_size = if elements < self.cpus { - 1 - } else { - elements / self.cpus - }; - - crossbeam::scope(|scope| { - f(scope, chunk_size) - }) - } -} - -pub struct WorkerFuture { - future: CpuFuture -} - -impl Future for WorkerFuture { - type Item = T; - type Error = E; - - fn poll(&mut self) -> Poll - { - self.future.poll() - } -} - -fn log2_floor(num: usize) -> u32 { - assert!(num > 0); - - let mut pow = 0; - - while (1 << (pow+1)) <= num { - pow += 1; - } - - pow -} - -#[test] -fn test_log2_floor() { - assert_eq!(log2_floor(1), 0); - assert_eq!(log2_floor(2), 1); - assert_eq!(log2_floor(3), 1); - assert_eq!(log2_floor(4), 2); - assert_eq!(log2_floor(5), 2); - assert_eq!(log2_floor(6), 2); - assert_eq!(log2_floor(7), 2); - assert_eq!(log2_floor(8), 3); -} diff --git a/bellman/src/multiexp.rs b/bellman/src/multiexp.rs deleted file mode 100644 index b1dc1f1..0000000 --- a/bellman/src/multiexp.rs +++ /dev/null @@ -1,303 +0,0 @@ -use pairing::{ - CurveAffine, - CurveProjective, - Engine, - PrimeField, - Field, - PrimeFieldRepr -}; -use std::sync::Arc; -use std::io; -use bit_vec::{self, BitVec}; -use std::iter; -use futures::{Future}; -use super::multicore::Worker; - -use super::SynthesisError; - -/// An object that builds a source of bases. -pub trait SourceBuilder: Send + Sync + 'static + Clone { - type Source: Source; - - fn new(self) -> Self::Source; -} - -/// A source of bases, like an iterator. -pub trait Source { - /// Parses the element from the source. Fails if the point is at infinity. - fn add_assign_mixed(&mut self, to: &mut ::Projective) -> Result<(), SynthesisError>; - - /// Skips `amt` elements from the source, avoiding deserialization. - fn skip(&mut self, amt: usize) -> Result<(), SynthesisError>; -} - -impl SourceBuilder for (Arc>, usize) { - type Source = (Arc>, usize); - - fn new(self) -> (Arc>, usize) { - (self.0.clone(), self.1) - } -} - -impl Source for (Arc>, usize) { - fn add_assign_mixed(&mut self, to: &mut ::Projective) -> Result<(), SynthesisError> { - if self.0.len() <= self.1 { - return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into()); - } - - if self.0[self.1].is_zero() { - return Err(SynthesisError::UnexpectedIdentity) - } - - to.add_assign_mixed(&self.0[self.1]); - - self.1 += 1; - - Ok(()) - } - - fn skip(&mut self, amt: usize) -> Result<(), SynthesisError> { - if self.0.len() <= self.1 { - return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into()); - } - - self.1 += amt; - - Ok(()) - } -} - -pub trait QueryDensity { - /// Returns whether the base exists. - type Iter: Iterator; - - fn iter(self) -> Self::Iter; - fn get_query_size(self) -> Option; -} - -#[derive(Clone)] -pub struct FullDensity; - -impl AsRef for FullDensity { - fn as_ref(&self) -> &FullDensity { - self - } -} - -impl<'a> QueryDensity for &'a FullDensity { - type Iter = iter::Repeat; - - fn iter(self) -> Self::Iter { - iter::repeat(true) - } - - fn get_query_size(self) -> Option { - None - } -} - -pub struct DensityTracker { - bv: BitVec, - total_density: usize -} - -impl<'a> QueryDensity for &'a DensityTracker { - type Iter = bit_vec::Iter<'a>; - - fn iter(self) -> Self::Iter { - self.bv.iter() - } - - fn get_query_size(self) -> Option { - Some(self.bv.len()) - } -} - -impl DensityTracker { - pub fn new() -> DensityTracker { - DensityTracker { - bv: BitVec::new(), - total_density: 0 - } - } - - pub fn add_element(&mut self) { - self.bv.push(false); - } - - pub fn inc(&mut self, idx: usize) { - if !self.bv.get(idx).unwrap() { - self.bv.set(idx, true); - self.total_density += 1; - } - } - - pub fn get_total_density(&self) -> usize { - self.total_density - } -} - -fn multiexp_inner( - pool: &Worker, - bases: S, - density_map: D, - exponents: Arc::Fr as PrimeField>::Repr>>, - mut skip: u32, - c: u32, - handle_trivial: bool -) -> Box::Projective, Error=SynthesisError>> - where for<'a> &'a Q: QueryDensity, - D: Send + Sync + 'static + Clone + AsRef, - G: CurveAffine, - S: SourceBuilder -{ - // Perform this region of the multiexp - let this = { - let bases = bases.clone(); - let exponents = exponents.clone(); - let density_map = density_map.clone(); - - pool.compute(move || { - // Accumulate the result - let mut acc = G::Projective::zero(); - - // Build a source for the bases - let mut bases = bases.new(); - - // Create space for the buckets - let mut buckets = vec![::Projective::zero(); (1 << c) - 1]; - - let zero = ::Fr::zero().into_repr(); - let one = ::Fr::one().into_repr(); - - // Sort the bases into buckets - for (&exp, density) in exponents.iter().zip(density_map.as_ref().iter()) { - if density { - if exp == zero { - bases.skip(1)?; - } else if exp == one { - if handle_trivial { - bases.add_assign_mixed(&mut acc)?; - } else { - bases.skip(1)?; - } - } else { - let mut exp = exp; - exp.shr(skip); - let exp = exp.as_ref()[0] % (1 << c); - - if exp != 0 { - bases.add_assign_mixed(&mut buckets[(exp - 1) as usize])?; - } else { - bases.skip(1)?; - } - } - } - } - - // Summation by parts - // e.g. 3a + 2b + 1c = a + - // (a) + b + - // ((a) + b) + c - let mut running_sum = G::Projective::zero(); - for exp in buckets.into_iter().rev() { - running_sum.add_assign(&exp); - acc.add_assign(&running_sum); - } - - Ok(acc) - }) - }; - - skip += c; - - if skip >= ::Fr::NUM_BITS { - // There isn't another region. - Box::new(this) - } else { - // There's another region more significant. Calculate and join it with - // this region recursively. - Box::new( - this.join(multiexp_inner(pool, bases, density_map, exponents, skip, c, false)) - .map(move |(this, mut higher)| { - for _ in 0..c { - higher.double(); - } - - higher.add_assign(&this); - - higher - }) - ) - } -} - -/// Perform multi-exponentiation. The caller is responsible for ensuring the -/// query size is the same as the number of exponents. -pub fn multiexp( - pool: &Worker, - bases: S, - density_map: D, - exponents: Arc::Fr as PrimeField>::Repr>> -) -> Box::Projective, Error=SynthesisError>> - where for<'a> &'a Q: QueryDensity, - D: Send + Sync + 'static + Clone + AsRef, - G: CurveAffine, - S: SourceBuilder -{ - let c = if exponents.len() < 32 { - 3u32 - } else { - (f64::from(exponents.len() as u32)).ln().ceil() as u32 - }; - - if let Some(query_size) = density_map.as_ref().get_query_size() { - // If the density map has a known query size, it should not be - // inconsistent with the number of exponents. - - assert!(query_size == exponents.len()); - } - - multiexp_inner(pool, bases, density_map, exponents, 0, c, true) -} - -#[test] -fn test_with_bls12() { - fn naive_multiexp( - bases: Arc>, - exponents: Arc::Repr>> - ) -> G::Projective - { - assert_eq!(bases.len(), exponents.len()); - - let mut acc = G::Projective::zero(); - - for (base, exp) in bases.iter().zip(exponents.iter()) { - acc.add_assign(&base.mul(*exp)); - } - - acc - } - - use rand::{self, Rand}; - use pairing::bls12_381::Bls12; - - const SAMPLES: usize = 1 << 14; - - let rng = &mut rand::thread_rng(); - let v = Arc::new((0..SAMPLES).map(|_| ::Fr::rand(rng).into_repr()).collect::>()); - let g = Arc::new((0..SAMPLES).map(|_| ::G1::rand(rng).into_affine()).collect::>()); - - let naive = naive_multiexp(g.clone(), v.clone()); - - let pool = Worker::new(); - - let fast = multiexp( - &pool, - (g, 0), - FullDensity, - v - ).wait().unwrap(); - - assert_eq!(naive, fast); -} diff --git a/bellman/tests/mimc.rs b/bellman/tests/mimc.rs deleted file mode 100644 index d6ff72b..0000000 --- a/bellman/tests/mimc.rs +++ /dev/null @@ -1,251 +0,0 @@ -extern crate bellman; -extern crate pairing; -extern crate rand; - -// For randomness (during paramgen and proof generation) -use rand::{thread_rng, Rng}; - -// For benchmarking -use std::time::{Duration, Instant}; - -// Bring in some tools for using pairing-friendly curves -use pairing::{ - Engine, - Field -}; - -// We're going to use the BLS12-381 pairing-friendly elliptic curve. -use pairing::bls12_381::{ - Bls12 -}; - -// We'll use these interfaces to construct our circuit. -use bellman::{ - Circuit, - ConstraintSystem, - SynthesisError -}; - -// We're going to use the Groth16 proving system. -use bellman::groth16::{ - Proof, - generate_random_parameters, - prepare_verifying_key, - create_random_proof, - verify_proof, -}; - -const MIMC_ROUNDS: usize = 322; - -/// This is an implementation of MiMC, specifically a -/// variant named `LongsightF322p3` for BLS12-381. -/// See http://eprint.iacr.org/2016/492 for more -/// information about this construction. -/// -/// ``` -/// function LongsightF322p3(xL ⦂ Fp, xR ⦂ Fp) { -/// for i from 0 up to 321 { -/// xL, xR := xR + (xL + Ci)^3, xL -/// } -/// return xL -/// } -/// ``` -fn mimc( - mut xl: E::Fr, - mut xr: E::Fr, - constants: &[E::Fr] -) -> E::Fr -{ - assert_eq!(constants.len(), MIMC_ROUNDS); - - for i in 0..MIMC_ROUNDS { - let mut tmp1 = xl; - tmp1.add_assign(&constants[i]); - let mut tmp2 = tmp1; - tmp2.square(); - tmp2.mul_assign(&tmp1); - tmp2.add_assign(&xr); - xr = xl; - xl = tmp2; - } - - xl -} - -/// This is our demo circuit for proving knowledge of the -/// preimage of a MiMC hash invocation. -struct MiMCDemo<'a, E: Engine> { - xl: Option, - xr: Option, - constants: &'a [E::Fr] -} - -/// Our demo circuit implements this `Circuit` trait which -/// is used during paramgen and proving in order to -/// synthesize the constraint system. -impl<'a, E: Engine> Circuit for MiMCDemo<'a, E> { - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { - assert_eq!(self.constants.len(), MIMC_ROUNDS); - - // Allocate the first component of the preimage. - let mut xl_value = self.xl; - let mut xl = cs.alloc(|| "preimage xl", || { - xl_value.ok_or(SynthesisError::AssignmentMissing) - })?; - - // Allocate the second component of the preimage. - let mut xr_value = self.xr; - let mut xr = cs.alloc(|| "preimage xr", || { - xr_value.ok_or(SynthesisError::AssignmentMissing) - })?; - - for i in 0..MIMC_ROUNDS { - // xL, xR := xR + (xL + Ci)^3, xL - let cs = &mut cs.namespace(|| format!("round {}", i)); - - // tmp = (xL + Ci)^2 - let mut tmp_value = xl_value.map(|mut e| { - e.add_assign(&self.constants[i]); - e.square(); - e - }); - let mut tmp = cs.alloc(|| "tmp", || { - tmp_value.ok_or(SynthesisError::AssignmentMissing) - })?; - - cs.enforce( - || "tmp = (xL + Ci)^2", - |lc| lc + xl + (self.constants[i], CS::one()), - |lc| lc + xl + (self.constants[i], CS::one()), - |lc| lc + tmp - ); - - // new_xL = xR + (xL + Ci)^3 - // new_xL = xR + tmp * (xL + Ci) - // new_xL - xR = tmp * (xL + Ci) - let mut new_xl_value = xl_value.map(|mut e| { - e.add_assign(&self.constants[i]); - e.mul_assign(&tmp_value.unwrap()); - e.add_assign(&xr_value.unwrap()); - e - }); - - let mut new_xl = if i == (MIMC_ROUNDS-1) { - // This is the last round, xL is our image and so - // we allocate a public input. - cs.alloc_input(|| "image", || { - new_xl_value.ok_or(SynthesisError::AssignmentMissing) - })? - } else { - cs.alloc(|| "new_xl", || { - new_xl_value.ok_or(SynthesisError::AssignmentMissing) - })? - }; - - cs.enforce( - || "new_xL = xR + (xL + Ci)^3", - |lc| lc + tmp, - |lc| lc + xl + (self.constants[i], CS::one()), - |lc| lc + new_xl - xr - ); - - // xR = xL - xr = xl; - xr_value = xl_value; - - // xL = new_xL - xl = new_xl; - xl_value = new_xl_value; - } - - Ok(()) - } -} - -#[test] -fn test_mimc() { - // This may not be cryptographically safe, use - // `OsRng` (for example) in production software. - let rng = &mut thread_rng(); - - // Generate the MiMC round constants - let constants = (0..MIMC_ROUNDS).map(|_| rng.gen()).collect::>(); - - println!("Creating parameters..."); - - // Create parameters for our circuit - let params = { - let c = MiMCDemo:: { - xl: None, - xr: None, - constants: &constants - }; - - generate_random_parameters(c, rng).unwrap() - }; - - // Prepare the verification key (for proof verification) - let pvk = prepare_verifying_key(¶ms.vk); - - println!("Creating proofs..."); - - // Let's benchmark stuff! - const SAMPLES: u32 = 50; - let mut total_proving = Duration::new(0, 0); - let mut total_verifying = Duration::new(0, 0); - - // Just a place to put the proof data, so we can - // benchmark deserialization. - let mut proof_vec = vec![]; - - for _ in 0..SAMPLES { - // Generate a random preimage and compute the image - let xl = rng.gen(); - let xr = rng.gen(); - let image = mimc::(xl, xr, &constants); - - proof_vec.truncate(0); - - let start = Instant::now(); - { - // Create an instance of our circuit (with the - // witness) - let c = MiMCDemo { - xl: Some(xl), - xr: Some(xr), - constants: &constants - }; - - // Create a groth16 proof with our parameters. - let proof = create_random_proof(c, ¶ms, rng).unwrap(); - - proof.write(&mut proof_vec).unwrap(); - } - - total_proving += start.elapsed(); - - let start = Instant::now(); - let proof = Proof::read(&proof_vec[..]).unwrap(); - // Check the proof - assert!(verify_proof( - &pvk, - &proof, - &[image] - ).unwrap()); - total_verifying += start.elapsed(); - } - let proving_avg = total_proving / SAMPLES; - let proving_avg = proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 - + (proving_avg.as_secs() as f64); - - let verifying_avg = total_verifying / SAMPLES; - let verifying_avg = verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 - + (verifying_avg.as_secs() as f64); - - println!("Average proving time: {:?} seconds", proving_avg); - println!("Average verifying time: {:?} seconds", verifying_avg); -} diff --git a/pairing/benches/bls12_381/ec.rs b/benches/bls12_381/ec.rs similarity index 59% rename from pairing/benches/bls12_381/ec.rs rename to benches/bls12_381/ec.rs index d8f6618..04bed0d 100644 --- a/pairing/benches/bls12_381/ec.rs +++ b/benches/bls12_381/ec.rs @@ -1,6 +1,8 @@ mod g1 { - use rand::{Rand, SeedableRng, XorShiftRng}; + use rand_core::SeedableRng; + use rand_xorshift::XorShiftRng; + use ff::Field; use group::CurveProjective; use pairing::bls12_381::*; @@ -8,10 +10,13 @@ mod g1 { fn bench_g1_mul_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let v: Vec<(G1, Fr)> = (0..SAMPLES) - .map(|_| (G1::rand(&mut rng), Fr::rand(&mut rng))) + .map(|_| (G1::random(&mut rng), Fr::random(&mut rng))) .collect(); let mut count = 0; @@ -27,10 +32,13 @@ mod g1 { fn bench_g1_add_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let v: Vec<(G1, G1)> = (0..SAMPLES) - .map(|_| (G1::rand(&mut rng), G1::rand(&mut rng))) + .map(|_| (G1::random(&mut rng), G1::random(&mut rng))) .collect(); let mut count = 0; @@ -46,10 +54,13 @@ mod g1 { fn bench_g1_add_assign_mixed(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let v: Vec<(G1, G1Affine)> = (0..SAMPLES) - .map(|_| (G1::rand(&mut rng), G1::rand(&mut rng).into())) + .map(|_| (G1::random(&mut rng), G1::random(&mut rng).into())) .collect(); let mut count = 0; @@ -63,8 +74,10 @@ mod g1 { } mod g2 { - use rand::{Rand, SeedableRng, XorShiftRng}; + use rand_core::SeedableRng; + use rand_xorshift::XorShiftRng; + use ff::Field; use group::CurveProjective; use pairing::bls12_381::*; @@ -72,10 +85,13 @@ mod g2 { fn bench_g2_mul_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let v: Vec<(G2, Fr)> = (0..SAMPLES) - .map(|_| (G2::rand(&mut rng), Fr::rand(&mut rng))) + .map(|_| (G2::random(&mut rng), Fr::random(&mut rng))) .collect(); let mut count = 0; @@ -91,10 +107,13 @@ mod g2 { fn bench_g2_add_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let v: Vec<(G2, G2)> = (0..SAMPLES) - .map(|_| (G2::rand(&mut rng), G2::rand(&mut rng))) + .map(|_| (G2::random(&mut rng), G2::random(&mut rng))) .collect(); let mut count = 0; @@ -110,10 +129,13 @@ mod g2 { fn bench_g2_add_assign_mixed(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let v: Vec<(G2, G2Affine)> = (0..SAMPLES) - .map(|_| (G2::rand(&mut rng), G2::rand(&mut rng).into())) + .map(|_| (G2::random(&mut rng), G2::random(&mut rng).into())) .collect(); let mut count = 0; diff --git a/pairing/benches/bls12_381/fq.rs b/benches/bls12_381/fq.rs similarity index 56% rename from pairing/benches/bls12_381/fq.rs rename to benches/bls12_381/fq.rs index 053a10c..b663322 100644 --- a/pairing/benches/bls12_381/fq.rs +++ b/benches/bls12_381/fq.rs @@ -1,4 +1,5 @@ -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +use rand_xorshift::XorShiftRng; use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField}; use pairing::bls12_381::*; @@ -7,12 +8,15 @@ use pairing::bls12_381::*; fn bench_fq_repr_add_nocarry(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES) .map(|_| { - let mut tmp1 = FqRepr::rand(&mut rng); - let mut tmp2 = FqRepr::rand(&mut rng); + let mut tmp1 = Fq::random(&mut rng).into_repr(); + let mut tmp2 = Fq::random(&mut rng).into_repr(); // Shave a few bits off to avoid overflow. for _ in 0..3 { tmp1.div2(); @@ -35,11 +39,14 @@ fn bench_fq_repr_add_nocarry(b: &mut ::test::Bencher) { fn bench_fq_repr_sub_noborrow(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES) .map(|_| { - let tmp1 = FqRepr::rand(&mut rng); + let tmp1 = Fq::random(&mut rng).into_repr(); let mut tmp2 = tmp1; // Ensure tmp2 is smaller than tmp1. for _ in 0..10 { @@ -62,9 +69,14 @@ fn bench_fq_repr_sub_noborrow(b: &mut ::test::Bencher) { fn bench_fq_repr_num_bits(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES) + .map(|_| Fq::random(&mut rng).into_repr()) + .collect(); let mut count = 0; b.iter(|| { @@ -78,9 +90,14 @@ fn bench_fq_repr_num_bits(b: &mut ::test::Bencher) { fn bench_fq_repr_mul2(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES) + .map(|_| Fq::random(&mut rng).into_repr()) + .collect(); let mut count = 0; b.iter(|| { @@ -95,9 +112,14 @@ fn bench_fq_repr_mul2(b: &mut ::test::Bencher) { fn bench_fq_repr_div2(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES) + .map(|_| Fq::random(&mut rng).into_repr()) + .collect(); let mut count = 0; b.iter(|| { @@ -112,10 +134,13 @@ fn bench_fq_repr_div2(b: &mut ::test::Bencher) { fn bench_fq_add_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq, Fq)> = (0..SAMPLES) - .map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng))) + .map(|_| (Fq::random(&mut rng), Fq::random(&mut rng))) .collect(); let mut count = 0; @@ -131,10 +156,13 @@ fn bench_fq_add_assign(b: &mut ::test::Bencher) { fn bench_fq_sub_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq, Fq)> = (0..SAMPLES) - .map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng))) + .map(|_| (Fq::random(&mut rng), Fq::random(&mut rng))) .collect(); let mut count = 0; @@ -150,10 +178,13 @@ fn bench_fq_sub_assign(b: &mut ::test::Bencher) { fn bench_fq_mul_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq, Fq)> = (0..SAMPLES) - .map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng))) + .map(|_| (Fq::random(&mut rng), Fq::random(&mut rng))) .collect(); let mut count = 0; @@ -169,9 +200,12 @@ fn bench_fq_mul_assign(b: &mut ::test::Bencher) { fn bench_fq_square(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -186,9 +220,12 @@ fn bench_fq_square(b: &mut ::test::Bencher) { fn bench_fq_inverse(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -201,9 +238,12 @@ fn bench_fq_inverse(b: &mut ::test::Bencher) { fn bench_fq_negate(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -218,11 +258,14 @@ fn bench_fq_negate(b: &mut ::test::Bencher) { fn bench_fq_sqrt(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec = (0..SAMPLES) .map(|_| { - let mut tmp = Fq::rand(&mut rng); + let mut tmp = Fq::random(&mut rng); tmp.square(); tmp }) @@ -239,9 +282,12 @@ fn bench_fq_sqrt(b: &mut ::test::Bencher) { fn bench_fq_into_repr(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -254,10 +300,13 @@ fn bench_fq_into_repr(b: &mut ::test::Bencher) { fn bench_fq_from_repr(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec = (0..SAMPLES) - .map(|_| Fq::rand(&mut rng).into_repr()) + .map(|_| Fq::random(&mut rng).into_repr()) .collect(); let mut count = 0; diff --git a/pairing/benches/bls12_381/fq12.rs b/benches/bls12_381/fq12.rs similarity index 55% rename from pairing/benches/bls12_381/fq12.rs rename to benches/bls12_381/fq12.rs index 84daca2..8bf0392 100644 --- a/pairing/benches/bls12_381/fq12.rs +++ b/benches/bls12_381/fq12.rs @@ -1,4 +1,5 @@ -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +use rand_xorshift::XorShiftRng; use ff::Field; use pairing::bls12_381::*; @@ -7,10 +8,13 @@ use pairing::bls12_381::*; fn bench_fq12_add_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq12, Fq12)> = (0..SAMPLES) - .map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng))) + .map(|_| (Fq12::random(&mut rng), Fq12::random(&mut rng))) .collect(); let mut count = 0; @@ -26,10 +30,13 @@ fn bench_fq12_add_assign(b: &mut ::test::Bencher) { fn bench_fq12_sub_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq12, Fq12)> = (0..SAMPLES) - .map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng))) + .map(|_| (Fq12::random(&mut rng), Fq12::random(&mut rng))) .collect(); let mut count = 0; @@ -45,10 +52,13 @@ fn bench_fq12_sub_assign(b: &mut ::test::Bencher) { fn bench_fq12_mul_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq12, Fq12)> = (0..SAMPLES) - .map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng))) + .map(|_| (Fq12::random(&mut rng), Fq12::random(&mut rng))) .collect(); let mut count = 0; @@ -64,9 +74,12 @@ fn bench_fq12_mul_assign(b: &mut ::test::Bencher) { fn bench_fq12_squaring(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq12::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq12::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -81,9 +94,12 @@ fn bench_fq12_squaring(b: &mut ::test::Bencher) { fn bench_fq12_inverse(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq12::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq12::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { diff --git a/pairing/benches/bls12_381/fq2.rs b/benches/bls12_381/fq2.rs similarity index 54% rename from pairing/benches/bls12_381/fq2.rs rename to benches/bls12_381/fq2.rs index 521b6ab..028c42e 100644 --- a/pairing/benches/bls12_381/fq2.rs +++ b/benches/bls12_381/fq2.rs @@ -1,4 +1,5 @@ -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +use rand_xorshift::XorShiftRng; use ff::{Field, SqrtField}; use pairing::bls12_381::*; @@ -7,10 +8,13 @@ use pairing::bls12_381::*; fn bench_fq2_add_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq2, Fq2)> = (0..SAMPLES) - .map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng))) + .map(|_| (Fq2::random(&mut rng), Fq2::random(&mut rng))) .collect(); let mut count = 0; @@ -26,10 +30,13 @@ fn bench_fq2_add_assign(b: &mut ::test::Bencher) { fn bench_fq2_sub_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq2, Fq2)> = (0..SAMPLES) - .map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng))) + .map(|_| (Fq2::random(&mut rng), Fq2::random(&mut rng))) .collect(); let mut count = 0; @@ -45,10 +52,13 @@ fn bench_fq2_sub_assign(b: &mut ::test::Bencher) { fn bench_fq2_mul_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fq2, Fq2)> = (0..SAMPLES) - .map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng))) + .map(|_| (Fq2::random(&mut rng), Fq2::random(&mut rng))) .collect(); let mut count = 0; @@ -64,9 +74,12 @@ fn bench_fq2_mul_assign(b: &mut ::test::Bencher) { fn bench_fq2_squaring(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq2::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -81,9 +94,12 @@ fn bench_fq2_squaring(b: &mut ::test::Bencher) { fn bench_fq2_inverse(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq2::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -97,9 +113,12 @@ fn bench_fq2_inverse(b: &mut ::test::Bencher) { fn bench_fq2_sqrt(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fq2::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { diff --git a/pairing/benches/bls12_381/fr.rs b/benches/bls12_381/fr.rs similarity index 56% rename from pairing/benches/bls12_381/fr.rs rename to benches/bls12_381/fr.rs index 13b0d0e..9e767d8 100644 --- a/pairing/benches/bls12_381/fr.rs +++ b/benches/bls12_381/fr.rs @@ -1,4 +1,5 @@ -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +use rand_xorshift::XorShiftRng; use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField}; use pairing::bls12_381::*; @@ -7,12 +8,15 @@ use pairing::bls12_381::*; fn bench_fr_repr_add_nocarry(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES) .map(|_| { - let mut tmp1 = FrRepr::rand(&mut rng); - let mut tmp2 = FrRepr::rand(&mut rng); + let mut tmp1 = Fr::random(&mut rng).into_repr(); + let mut tmp2 = Fr::random(&mut rng).into_repr(); // Shave a few bits off to avoid overflow. for _ in 0..3 { tmp1.div2(); @@ -35,11 +39,14 @@ fn bench_fr_repr_add_nocarry(b: &mut ::test::Bencher) { fn bench_fr_repr_sub_noborrow(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES) .map(|_| { - let tmp1 = FrRepr::rand(&mut rng); + let tmp1 = Fr::random(&mut rng).into_repr(); let mut tmp2 = tmp1; // Ensure tmp2 is smaller than tmp1. for _ in 0..10 { @@ -62,9 +69,14 @@ fn bench_fr_repr_sub_noborrow(b: &mut ::test::Bencher) { fn bench_fr_repr_num_bits(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES) + .map(|_| Fr::random(&mut rng).into_repr()) + .collect(); let mut count = 0; b.iter(|| { @@ -78,9 +90,14 @@ fn bench_fr_repr_num_bits(b: &mut ::test::Bencher) { fn bench_fr_repr_mul2(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES) + .map(|_| Fr::random(&mut rng).into_repr()) + .collect(); let mut count = 0; b.iter(|| { @@ -95,9 +112,14 @@ fn bench_fr_repr_mul2(b: &mut ::test::Bencher) { fn bench_fr_repr_div2(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES) + .map(|_| Fr::random(&mut rng).into_repr()) + .collect(); let mut count = 0; b.iter(|| { @@ -112,10 +134,13 @@ fn bench_fr_repr_div2(b: &mut ::test::Bencher) { fn bench_fr_add_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fr, Fr)> = (0..SAMPLES) - .map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng))) + .map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))) .collect(); let mut count = 0; @@ -131,10 +156,13 @@ fn bench_fr_add_assign(b: &mut ::test::Bencher) { fn bench_fr_sub_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fr, Fr)> = (0..SAMPLES) - .map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng))) + .map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))) .collect(); let mut count = 0; @@ -150,10 +178,13 @@ fn bench_fr_sub_assign(b: &mut ::test::Bencher) { fn bench_fr_mul_assign(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(Fr, Fr)> = (0..SAMPLES) - .map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng))) + .map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))) .collect(); let mut count = 0; @@ -169,9 +200,12 @@ fn bench_fr_mul_assign(b: &mut ::test::Bencher) { fn bench_fr_square(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -186,9 +220,12 @@ fn bench_fr_square(b: &mut ::test::Bencher) { fn bench_fr_inverse(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -201,9 +238,12 @@ fn bench_fr_inverse(b: &mut ::test::Bencher) { fn bench_fr_negate(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -218,11 +258,14 @@ fn bench_fr_negate(b: &mut ::test::Bencher) { fn bench_fr_sqrt(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec = (0..SAMPLES) .map(|_| { - let mut tmp = Fr::rand(&mut rng); + let mut tmp = Fr::random(&mut rng); tmp.square(); tmp }) @@ -239,9 +282,12 @@ fn bench_fr_sqrt(b: &mut ::test::Bencher) { fn bench_fr_into_repr(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -254,10 +300,13 @@ fn bench_fr_into_repr(b: &mut ::test::Bencher) { fn bench_fr_from_repr(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec = (0..SAMPLES) - .map(|_| Fr::rand(&mut rng).into_repr()) + .map(|_| Fr::random(&mut rng).into_repr()) .collect(); let mut count = 0; diff --git a/pairing/benches/bls12_381/mod.rs b/benches/bls12_381/mod.rs similarity index 56% rename from pairing/benches/bls12_381/mod.rs rename to benches/bls12_381/mod.rs index 96bcdd5..2c23c2a 100644 --- a/pairing/benches/bls12_381/mod.rs +++ b/benches/bls12_381/mod.rs @@ -4,8 +4,10 @@ mod fq12; mod fq2; mod fr; -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +use rand_xorshift::XorShiftRng; +use group::CurveProjective; use pairing::bls12_381::*; use pairing::{Engine, PairingCurveAffine}; @@ -13,9 +15,12 @@ use pairing::{Engine, PairingCurveAffine}; fn bench_pairing_g1_preparation(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| G1::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| G1::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -29,9 +34,12 @@ fn bench_pairing_g1_preparation(b: &mut ::test::Bencher) { fn bench_pairing_g2_preparation(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); - let v: Vec = (0..SAMPLES).map(|_| G2::rand(&mut rng)).collect(); + let v: Vec = (0..SAMPLES).map(|_| G2::random(&mut rng)).collect(); let mut count = 0; b.iter(|| { @@ -45,13 +53,16 @@ fn bench_pairing_g2_preparation(b: &mut ::test::Bencher) { fn bench_pairing_miller_loop(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(G1Prepared, G2Prepared)> = (0..SAMPLES) .map(|_| { ( - G1Affine::from(G1::rand(&mut rng)).prepare(), - G2Affine::from(G2::rand(&mut rng)).prepare(), + G1Affine::from(G1::random(&mut rng)).prepare(), + G2Affine::from(G2::random(&mut rng)).prepare(), ) }) .collect(); @@ -68,13 +79,16 @@ fn bench_pairing_miller_loop(b: &mut ::test::Bencher) { fn bench_pairing_final_exponentiation(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec = (0..SAMPLES) .map(|_| { ( - G1Affine::from(G1::rand(&mut rng)).prepare(), - G2Affine::from(G2::rand(&mut rng)).prepare(), + G1Affine::from(G1::random(&mut rng)).prepare(), + G2Affine::from(G2::random(&mut rng)).prepare(), ) }) .map(|(ref p, ref q)| Bls12::miller_loop(&[(p, q)])) @@ -92,10 +106,13 @@ fn bench_pairing_final_exponentiation(b: &mut ::test::Bencher) { fn bench_pairing_full(b: &mut ::test::Bencher) { const SAMPLES: usize = 1000; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let v: Vec<(G1, G2)> = (0..SAMPLES) - .map(|_| (G1::rand(&mut rng), G2::rand(&mut rng))) + .map(|_| (G1::random(&mut rng), G2::random(&mut rng))) .collect(); let mut count = 0; diff --git a/pairing/benches/pairing_benches.rs b/benches/pairing_benches.rs similarity index 68% rename from pairing/benches/pairing_benches.rs rename to benches/pairing_benches.rs index d76e50b..b083b42 100644 --- a/pairing/benches/pairing_benches.rs +++ b/benches/pairing_benches.rs @@ -3,7 +3,8 @@ extern crate ff; extern crate group; extern crate pairing; -extern crate rand; +extern crate rand_core; +extern crate rand_xorshift; extern crate test; mod bls12_381; diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml deleted file mode 100644 index bb42b6c..0000000 --- a/librustzcash/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "librustzcash" -version = "0.1.0" -authors = [ - "Sean Bowe ", - "Jack Grigg ", - "Jay Graber ", - "Simon Liu " - ] - -[lib] -name = "rustzcash" -path = "src/rustzcash.rs" -crate-type = ["staticlib"] - -[dependencies] -bellman = { path = "../bellman" } -libc = "0.2" -pairing = { path = "../pairing" } -lazy_static = "1" -byteorder = "1" -rand = "0.4" -sapling-crypto = { path = "../sapling-crypto" } -zcash_proofs = { path = "../zcash_proofs" } -zip32 = { path = "../zip32" } - -[dependencies.blake2-rfc] -git = "https://github.com/gtank/blake2-rfc" -rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" diff --git a/librustzcash/README.md b/librustzcash/README.md deleted file mode 100644 index c21ca8e..0000000 --- a/librustzcash/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# librustzcash - -This repository contains librustzcash, a static library for Zcash code assets written in Rust. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. - diff --git a/librustzcash/include/librustzcash.h b/librustzcash/include/librustzcash.h deleted file mode 100644 index 4efb544..0000000 --- a/librustzcash/include/librustzcash.h +++ /dev/null @@ -1,313 +0,0 @@ -#ifndef LIBRUSTZCASH_INCLUDE_H_ -#define LIBRUSTZCASH_INCLUDE_H_ - -#include - -extern "C" { -#ifdef WIN32 - typedef uint16_t codeunit; -#else - typedef uint8_t codeunit; -#endif - - void librustzcash_to_scalar(const unsigned char *input, unsigned char *result); - - void librustzcash_ask_to_ak(const unsigned char *ask, unsigned char *result); - - void librustzcash_nsk_to_nk(const unsigned char *nsk, unsigned char *result); - - void librustzcash_crh_ivk(const unsigned char *ak, const unsigned char *nk, unsigned char *result); - - bool librustzcash_check_diversifier(const unsigned char *diversifier); - - bool librustzcash_ivk_to_pkd(const unsigned char *ivk, const unsigned char *diversifier, unsigned char *result); - - /// Loads the zk-SNARK parameters into memory and saves - /// paths as necessary. Only called once. - void librustzcash_init_zksnark_params( - const codeunit* spend_path, - size_t spend_path_len, - const char* spend_hash, - const codeunit* output_path, - size_t output_path_len, - const char* output_hash, - const codeunit* sprout_path, - size_t sprout_path_len, - const char* sprout_hash - ); - - /// Validates the provided Equihash solution against - /// the given parameters, input and nonce. - bool librustzcash_eh_isvalid( - uint32_t n, - uint32_t k, - const unsigned char* input, - size_t input_len, - const unsigned char* nonce, - size_t nonce_len, - const unsigned char* soln, - size_t soln_len - ); - - /// Writes the "uncommitted" note value for empty leaves - /// of the merkle tree. `result` must be a valid pointer - /// to 32 bytes which will be written. - void librustzcash_tree_uncommitted( - unsigned char *result - ); - - /// Computes a merkle tree hash for a given depth. - /// The `depth` parameter should not be larger than - /// 62. - /// - /// `a` and `b` each must be of length 32, and must each - /// be scalars of BLS12-381. - /// - /// The result of the merkle tree hash is placed in - /// `result`, which must also be of length 32. - void librustzcash_merkle_hash( - size_t depth, - const unsigned char *a, - const unsigned char *b, - unsigned char *result - ); - - /// Computes the signature for each Spend description, given the key - /// `ask`, the re-randomization `ar`, the 32-byte sighash `sighash`, - /// and an output `result` buffer of 64-bytes for the signature. - /// - /// This function will fail if the provided `ask` or `ar` are invalid. - bool librustzcash_sapling_spend_sig( - const unsigned char *ask, - const unsigned char *ar, - const unsigned char *sighash, - unsigned char *result - ); - - /// Creates a Sapling proving context. Please free this when you're done. - void * librustzcash_sapling_proving_ctx_init(); - - /// This function (using the proving context) constructs a Spend proof - /// given the necessary witness information. It outputs `cv` (the value - /// commitment) and `rk` (so that you don't have to compute it) along - /// with the proof. - bool librustzcash_sapling_spend_proof( - void *ctx, - const unsigned char *ak, - const unsigned char *nsk, - const unsigned char *diversifier, - const unsigned char *rcm, - const unsigned char *ar, - const uint64_t value, - const unsigned char *anchor, - const unsigned char *witness, - unsigned char *cv, - unsigned char *rk, - unsigned char *zkproof - ); - - /// This function (using the proving context) constructs an Output - /// proof given the necessary witness information. It outputs `cv` - /// and the `zkproof`. - bool librustzcash_sapling_output_proof( - void *ctx, - const unsigned char *esk, - const unsigned char *diversifier, - const unsigned char *pk_d, - const unsigned char *rcm, - const uint64_t value, - unsigned char *cv, - unsigned char *zkproof - ); - - /// This function (using the proving context) constructs a binding - /// signature. You must provide the intended valueBalance so that - /// we can internally check consistency. - bool librustzcash_sapling_binding_sig( - const void *ctx, - int64_t valueBalance, - const unsigned char *sighash, - unsigned char *result - ); - - /// Frees a Sapling proving context returned from - /// `librustzcash_sapling_proving_ctx_init`. - void librustzcash_sapling_proving_ctx_free(void *); - - /// Creates a Sapling verification context. Please free this - /// when you're done. - void * librustzcash_sapling_verification_ctx_init(); - - /// Check the validity of a Sapling Spend description, - /// accumulating the value commitment into the context. - bool librustzcash_sapling_check_spend( - void *ctx, - const unsigned char *cv, - const unsigned char *anchor, - const unsigned char *nullifier, - const unsigned char *rk, - const unsigned char *zkproof, - const unsigned char *spendAuthSig, - const unsigned char *sighashValue - ); - - /// Check the validity of a Sapling Output description, - /// accumulating the value commitment into the context. - bool librustzcash_sapling_check_output( - void *ctx, - const unsigned char *cv, - const unsigned char *cm, - const unsigned char *ephemeralKey, - const unsigned char *zkproof - ); - - /// Finally checks the validity of the entire Sapling - /// transaction given valueBalance and the binding signature. - bool librustzcash_sapling_final_check( - void *ctx, - int64_t valueBalance, - const unsigned char *bindingSig, - const unsigned char *sighashValue - ); - - /// Frees a Sapling verification context returned from - /// `librustzcash_sapling_verification_ctx_init`. - void librustzcash_sapling_verification_ctx_free(void *); - - /// Compute a Sapling nullifier. - /// - /// The `diversifier` parameter must be 11 bytes in length. - /// The `pk_d`, `r`, `ak` and `nk` parameters must be of length 32. - /// The result is also of length 32 and placed in `result`. - /// Returns false if the diversifier or pk_d is not valid - bool librustzcash_sapling_compute_nf( - const unsigned char *diversifier, - const unsigned char *pk_d, - const uint64_t value, - const unsigned char *r, - const unsigned char *ak, - const unsigned char *nk, - const uint64_t position, - unsigned char *result - ); - - /// Compute a Sapling commitment. - /// - /// The `diversifier` parameter must be 11 bytes in length. - /// The `pk_d` and `r` parameters must be of length 32. - /// The result is also of length 32 and placed in `result`. - /// Returns false if the diversifier or pk_d is not valid - bool librustzcash_sapling_compute_cm( - const unsigned char *diversifier, - const unsigned char *pk_d, - const uint64_t value, - const unsigned char *r, - unsigned char *result - ); - - /// Compute [sk] [8] P for some 32-byte - /// point P, and 32-byte Fs. If P or sk - /// are invalid, returns false. Otherwise, - /// the result is written to the 32-byte - /// `result` buffer. - bool librustzcash_sapling_ka_agree( - const unsigned char *p, - const unsigned char *sk, - unsigned char *result - ); - - /// Compute g_d = GH(diversifier) and returns - /// false if the diversifier is invalid. - /// Computes [esk] g_d and writes the result - /// to the 32-byte `result` buffer. Returns - /// false if `esk` is not a valid scalar. - bool librustzcash_sapling_ka_derivepublic( - const unsigned char *diversifier, - const unsigned char *esk, - unsigned char *result - ); - - /// Generate uniformly random scalar in Jubjub. - /// The result is of length 32. - void librustzcash_sapling_generate_r( - unsigned char *result - ); - - /// Sprout JoinSplit proof generation. - void librustzcash_sprout_prove( - unsigned char *proof_out, - - const unsigned char *phi, - const unsigned char *rt, - const unsigned char *h_sig, - - const unsigned char *in_sk1, - uint64_t in_value1, - const unsigned char *in_rho1, - const unsigned char *in_r1, - const unsigned char *in_auth1, - - const unsigned char *in_sk2, - uint64_t in_value2, - const unsigned char *in_rho2, - const unsigned char *in_r2, - const unsigned char *in_auth2, - - const unsigned char *out_pk1, - uint64_t out_value1, - const unsigned char *out_r1, - - const unsigned char *out_pk2, - uint64_t out_value2, - const unsigned char *out_r2, - - uint64_t vpub_old, - uint64_t vpub_new - ); - - /// Sprout JoinSplit proof verification. - bool librustzcash_sprout_verify( - const unsigned char *proof, - const unsigned char *rt, - const unsigned char *h_sig, - const unsigned char *mac1, - const unsigned char *mac2, - const unsigned char *nf1, - const unsigned char *nf2, - const unsigned char *cm1, - const unsigned char *cm2, - uint64_t vpub_old, - uint64_t vpub_new - ); - - /// Derive the master ExtendedSpendingKey from a seed. - void librustzcash_zip32_xsk_master( - const unsigned char *seed, - size_t seedlen, - unsigned char *xsk_master - ); - - /// Derive a child ExtendedSpendingKey from a parent. - void librustzcash_zip32_xsk_derive( - const unsigned char *xsk_parent, - uint32_t i, - unsigned char *xsk_i - ); - - /// Derive a child ExtendedFullViewingKey from a parent. - bool librustzcash_zip32_xfvk_derive( - const unsigned char *xfvk_parent, - uint32_t i, - unsigned char *xfvk_i - ); - - /// Derive a PaymentAddress from an ExtendedFullViewingKey. - bool librustzcash_zip32_xfvk_address( - const unsigned char *xfvk, - const unsigned char *j, - unsigned char *j_ret, - unsigned char *addr_ret - ); -} - -#endif // LIBRUSTZCASH_INCLUDE_H_ diff --git a/librustzcash/src/equihash.rs b/librustzcash/src/equihash.rs deleted file mode 100644 index da2693b..0000000 --- a/librustzcash/src/equihash.rs +++ /dev/null @@ -1,467 +0,0 @@ -use blake2_rfc::blake2b::{Blake2b, Blake2bResult}; -use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; -use std::io::Cursor; -use std::mem::size_of; - -struct Params { - n: u32, - k: u32, -} - -#[derive(Clone)] -struct Node { - hash: Vec, - indices: Vec, -} - -impl Params { - fn indices_per_hash_output(&self) -> u32 { - 512 / self.n - } - fn hash_output(&self) -> u8 { - (self.indices_per_hash_output() * self.n / 8) as u8 - } - fn collision_bit_length(&self) -> usize { - (self.n / (self.k + 1)) as usize - } - fn collision_byte_length(&self) -> usize { - (self.collision_bit_length() + 7) / 8 - } - fn hash_length(&self) -> usize { - ((self.k as usize) + 1) * self.collision_byte_length() - } -} - -impl Node { - fn new(p: &Params, state: &Blake2b, i: u32) -> Self { - let hash = generate_hash(state, i / p.indices_per_hash_output()); - let start = ((i % p.indices_per_hash_output()) * p.n / 8) as usize; - let end = start + (p.n as usize) / 8; - Node { - hash: expand_array(&hash.as_bytes()[start..end], p.collision_bit_length(), 0), - indices: vec![i], - } - } - - fn from_children(a: Node, b: Node, trim: usize) -> Self { - let hash: Vec<_> = a - .hash - .iter() - .zip(b.hash.iter()) - .skip(trim) - .map(|(a, b)| a ^ b) - .collect(); - let indices = if a.indices_before(&b) { - let mut indices = a.indices; - indices.extend(b.indices.iter()); - indices - } else { - let mut indices = b.indices; - indices.extend(a.indices.iter()); - indices - }; - Node { - hash: hash, - indices: indices, - } - } - - fn from_children_ref(a: &Node, b: &Node, trim: usize) -> Self { - let hash: Vec<_> = a - .hash - .iter() - .zip(b.hash.iter()) - .skip(trim) - .map(|(a, b)| a ^ b) - .collect(); - let mut indices = Vec::with_capacity(a.indices.len() + b.indices.len()); - if a.indices_before(b) { - indices.extend(a.indices.iter()); - indices.extend(b.indices.iter()); - } else { - indices.extend(b.indices.iter()); - indices.extend(a.indices.iter()); - } - Node { - hash: hash, - indices: indices, - } - } - - fn indices_before(&self, other: &Node) -> bool { - // Indices are serialized in big-endian so that integer - // comparison is equivalent to array comparison - self.indices[0] < other.indices[0] - } - - fn is_zero(&self, len: usize) -> bool { - self.hash.iter().take(len).all(|v| *v == 0) - } -} - -fn initialise_state(n: u32, k: u32, digest_len: u8) -> Blake2b { - let mut personalization: Vec = Vec::from("ZcashPoW"); - personalization.write_u32::(n).unwrap(); - personalization.write_u32::(k).unwrap(); - - Blake2b::with_params(digest_len as usize, &[], &[], &personalization) -} - -fn generate_hash(base_state: &Blake2b, i: u32) -> Blake2bResult { - let mut lei = [0u8; 4]; - (&mut lei[..]).write_u32::(i).unwrap(); - - let mut state = base_state.clone(); - state.update(&lei); - state.finalize() -} - -fn expand_array(vin: &[u8], bit_len: usize, byte_pad: usize) -> Vec { - assert!(bit_len >= 8); - assert!(8 * size_of::() >= 7 + bit_len); - - let out_width = (bit_len + 7) / 8 + byte_pad; - let out_len = 8 * out_width * vin.len() / bit_len; - - // Shortcut for parameters where expansion is a no-op - if out_len == vin.len() { - return vin.to_vec(); - } - - let mut vout: Vec = vec![0; out_len]; - let bit_len_mask: u32 = (1 << bit_len) - 1; - - // The acc_bits least-significant bits of acc_value represent a bit sequence - // in big-endian order. - let mut acc_bits = 0; - let mut acc_value: u32 = 0; - - let mut j = 0; - for b in vin { - acc_value = (acc_value << 8) | *b as u32; - acc_bits += 8; - - // When we have bit_len or more bits in the accumulator, write the next - // output element. - if acc_bits >= bit_len { - acc_bits -= bit_len; - for x in byte_pad..out_width { - vout[j + x] = (( - // Big-endian - acc_value >> (acc_bits + (8 * (out_width - x - 1))) - ) & ( - // Apply bit_len_mask across byte boundaries - (bit_len_mask >> (8 * (out_width - x - 1))) & 0xFF - )) as u8; - } - j += out_width; - } - } - - vout -} - -fn indices_from_minimal(minimal: &[u8], c_bit_len: usize) -> Vec { - assert!(((c_bit_len + 1) + 7) / 8 <= size_of::()); - let len_indices = 8 * size_of::() * minimal.len() / (c_bit_len + 1); - let byte_pad = size_of::() - ((c_bit_len + 1) + 7) / 8; - - let mut csr = Cursor::new(expand_array(minimal, c_bit_len + 1, byte_pad)); - let mut ret = Vec::with_capacity(len_indices); - - // Big-endian so that lexicographic array comparison is equivalent to integer - // comparison - while let Ok(i) = csr.read_u32::() { - ret.push(i); - } - - ret -} - -fn has_collision(a: &Node, b: &Node, len: usize) -> bool { - a.hash - .iter() - .zip(b.hash.iter()) - .take(len) - .all(|(a, b)| a == b) -} - -fn distinct_indices(a: &Node, b: &Node) -> bool { - for i in &(a.indices) { - for j in &(b.indices) { - if i == j { - return false; - } - } - } - return true; -} - -fn validate_subtrees(p: &Params, a: &Node, b: &Node) -> bool { - if !has_collision(a, b, p.collision_byte_length()) { - // error!("Invalid solution: invalid collision length between StepRows"); - false - } else if b.indices_before(a) { - // error!("Invalid solution: Index tree incorrectly ordered"); - false - } else if !distinct_indices(a, b) { - // error!("Invalid solution: duplicate indices"); - false - } else { - true - } -} - -pub fn is_valid_solution_iterative( - n: u32, - k: u32, - input: &[u8], - nonce: &[u8], - indices: &[u32], -) -> bool { - let p = Params { n: n, k: k }; - - let mut state = initialise_state(p.n, p.k, p.hash_output()); - state.update(input); - state.update(nonce); - - let mut rows = Vec::new(); - for i in indices { - rows.push(Node::new(&p, &state, *i)); - } - - let mut hash_len = p.hash_length(); - while rows.len() > 1 { - let mut cur_rows = Vec::new(); - for pair in rows.chunks(2) { - let a = &pair[0]; - let b = &pair[1]; - if !validate_subtrees(&p, a, b) { - return false; - } - cur_rows.push(Node::from_children_ref(a, b, p.collision_byte_length())); - } - rows = cur_rows; - hash_len -= p.collision_byte_length(); - } - - assert!(rows.len() == 1); - return rows[0].is_zero(hash_len); -} - -fn tree_validator(p: &Params, state: &Blake2b, indices: &[u32]) -> Option { - if indices.len() > 1 { - let end = indices.len(); - let mid = end / 2; - match tree_validator(p, state, &indices[0..mid]) { - Some(a) => match tree_validator(p, state, &indices[mid..end]) { - Some(b) => { - if validate_subtrees(p, &a, &b) { - Some(Node::from_children(a, b, p.collision_byte_length())) - } else { - None - } - } - None => None, - }, - None => None, - } - } else { - Some(Node::new(&p, &state, indices[0])) - } -} - -pub fn is_valid_solution_recursive( - n: u32, - k: u32, - input: &[u8], - nonce: &[u8], - indices: &[u32], -) -> bool { - let p = Params { n: n, k: k }; - - let mut state = initialise_state(p.n, p.k, p.hash_output()); - state.update(input); - state.update(nonce); - - match tree_validator(&p, &state, indices) { - Some(root) => { - // Hashes were trimmed, so only need to check remaining length - root.is_zero(p.collision_byte_length()) - } - None => false, - } -} - -pub fn is_valid_solution(n: u32, k: u32, input: &[u8], nonce: &[u8], soln: &[u8]) -> bool { - let p = Params { n: n, k: k }; - let indices = indices_from_minimal(soln, p.collision_bit_length()); - - // Recursive validation is faster - is_valid_solution_recursive(n, k, input, nonce, &indices) -} - -#[cfg(test)] -mod tests { - use super::is_valid_solution_iterative; - use super::is_valid_solution_recursive; - - fn is_valid_solution(n: u32, k: u32, input: &[u8], nonce: &[u8], indices: &[u32]) -> bool { - let a = is_valid_solution_iterative(n, k, input, nonce, indices); - let b = is_valid_solution_recursive(n, k, input, nonce, indices); - assert!(a == b); - a - } - - #[test] - fn equihash_test_cases() { - let input = b"block header"; - let mut nonce = [0 as u8; 32]; - let mut indices = vec![ - 976, 126621, 100174, 123328, 38477, 105390, 38834, 90500, 6411, 116489, 51107, 129167, - 25557, 92292, 38525, 56514, 1110, 98024, 15426, 74455, 3185, 84007, 24328, 36473, - 17427, 129451, 27556, 119967, 31704, 62448, 110460, 117894, - ]; - assert!(is_valid_solution(96, 5, input, &nonce, &indices)); - - indices = vec![ - 1008, 18280, 34711, 57439, 3903, 104059, 81195, 95931, 58336, 118687, 67931, 123026, - 64235, 95595, 84355, 122946, 8131, 88988, 45130, 58986, 59899, 78278, 94769, 118158, - 25569, 106598, 44224, 96285, 54009, 67246, 85039, 127667, - ]; - assert!(is_valid_solution(96, 5, input, &nonce, &indices)); - - indices = vec![ - 4313, 223176, 448870, 1692641, 214911, 551567, 1696002, 1768726, 500589, 938660, - 724628, 1319625, 632093, 1474613, 665376, 1222606, 244013, 528281, 1741992, 1779660, - 313314, 996273, 435612, 1270863, 337273, 1385279, 1031587, 1147423, 349396, 734528, - 902268, 1678799, 10902, 1231236, 1454381, 1873452, 120530, 2034017, 948243, 1160178, - 198008, 1704079, 1087419, 1734550, 457535, 698704, 649903, 1029510, 75564, 1860165, - 1057819, 1609847, 449808, 527480, 1106201, 1252890, 207200, 390061, 1557573, 1711408, - 396772, 1026145, 652307, 1712346, 10680, 1027631, 232412, 974380, 457702, 1827006, - 1316524, 1400456, 91745, 2032682, 192412, 710106, 556298, 1963798, 1329079, 1504143, - 102455, 974420, 639216, 1647860, 223846, 529637, 425255, 680712, 154734, 541808, - 443572, 798134, 322981, 1728849, 1306504, 1696726, 57884, 913814, 607595, 1882692, - 236616, 1439683, 420968, 943170, 1014827, 1446980, 1468636, 1559477, 1203395, 1760681, - 1439278, 1628494, 195166, 198686, 349906, 1208465, 917335, 1361918, 937682, 1885495, - 494922, 1745948, 1320024, 1826734, 847745, 894084, 1484918, 1523367, 7981, 1450024, - 861459, 1250305, 226676, 329669, 339783, 1935047, 369590, 1564617, 939034, 1908111, - 1147449, 1315880, 1276715, 1428599, 168956, 1442649, 766023, 1171907, 273361, 1902110, - 1169410, 1786006, 413021, 1465354, 707998, 1134076, 977854, 1604295, 1369720, 1486036, - 330340, 1587177, 502224, 1313997, 400402, 1667228, 889478, 946451, 470672, 2019542, - 1023489, 2067426, 658974, 876859, 794443, 1667524, 440815, 1099076, 897391, 1214133, - 953386, 1932936, 1100512, 1362504, 874364, 975669, 1277680, 1412800, 1227580, 1857265, - 1312477, 1514298, 12478, 219890, 534265, 1351062, 65060, 651682, 627900, 1331192, - 123915, 865936, 1218072, 1732445, 429968, 1097946, 947293, 1323447, 157573, 1212459, - 923792, 1943189, 488881, 1697044, 915443, 2095861, 333566, 732311, 336101, 1600549, - 575434, 1978648, 1071114, 1473446, 50017, 54713, 367891, 2055483, 561571, 1714951, - 715652, 1347279, 584549, 1642138, 1002587, 1125289, 1364767, 1382627, 1387373, 2054399, - 97237, 1677265, 707752, 1265819, 121088, 1810711, 1755448, 1858538, 444653, 1130822, - 514258, 1669752, 578843, 729315, 1164894, 1691366, 15609, 1917824, 173620, 587765, - 122779, 2024998, 804857, 1619761, 110829, 1514369, 410197, 493788, 637666, 1765683, - 782619, 1186388, 494761, 1536166, 1582152, 1868968, 825150, 1709404, 1273757, 1657222, - 817285, 1955796, 1014018, 1961262, 873632, 1689675, 985486, 1008905, 130394, 897076, - 419669, 535509, 980696, 1557389, 1244581, 1738170, 197814, 1879515, 297204, 1165124, - 883018, 1677146, 1545438, 2017790, 345577, 1821269, 761785, 1014134, 746829, 751041, - 930466, 1627114, 507500, 588000, 1216514, 1501422, 991142, 1378804, 1797181, 1976685, - 60742, 780804, 383613, 645316, 770302, 952908, 1105447, 1878268, 504292, 1961414, - 693833, 1198221, 906863, 1733938, 1315563, 2049718, 230826, 2064804, 1224594, 1434135, - 897097, 1961763, 993758, 1733428, 306643, 1402222, 532661, 627295, 453009, 973231, - 1746809, 1857154, 263652, 1683026, 1082106, 1840879, 768542, 1056514, 888164, 1529401, - 327387, 1708909, 961310, 1453127, 375204, 878797, 1311831, 1969930, 451358, 1229838, - 583937, 1537472, 467427, 1305086, 812115, 1065593, 532687, 1656280, 954202, 1318066, - 1164182, 1963300, 1232462, 1722064, 17572, 923473, 1715089, 2079204, 761569, 1557392, - 1133336, 1183431, 175157, 1560762, 418801, 927810, 734183, 825783, 1844176, 1951050, - 317246, 336419, 711727, 1630506, 634967, 1595955, 683333, 1461390, 458765, 1834140, - 1114189, 1761250, 459168, 1897513, 1403594, 1478683, 29456, 1420249, 877950, 1371156, - 767300, 1848863, 1607180, 1819984, 96859, 1601334, 171532, 2068307, 980009, 2083421, - 1329455, 2030243, 69434, 1965626, 804515, 1339113, 396271, 1252075, 619032, 2080090, - 84140, 658024, 507836, 772757, 154310, 1580686, 706815, 1024831, 66704, 614858, 256342, - 957013, 1488503, 1615769, 1515550, 1888497, 245610, 1333432, 302279, 776959, 263110, - 1523487, 623933, 2013452, 68977, 122033, 680726, 1849411, 426308, 1292824, 460128, - 1613657, 234271, 971899, 1320730, 1559313, 1312540, 1837403, 1690310, 2040071, 149918, - 380012, 785058, 1675320, 267071, 1095925, 1149690, 1318422, 361557, 1376579, 1587551, - 1715060, 1224593, 1581980, 1354420, 1850496, 151947, 748306, 1987121, 2070676, 273794, - 981619, 683206, 1485056, 766481, 2047708, 930443, 2040726, 1136227, 1945705, 1722044, - 1971986, - ]; - assert!(!is_valid_solution(96, 5, input, &nonce, &indices)); - assert!(is_valid_solution(200, 9, input, &nonce, &indices)); - - nonce[0] = 1; - assert!(!is_valid_solution(96, 5, input, &nonce, &indices)); - assert!(!is_valid_solution(200, 9, input, &nonce, &indices)); - - indices = vec![ - 1911, 96020, 94086, 96830, 7895, 51522, 56142, 62444, 15441, 100732, 48983, 64776, - 27781, 85932, 101138, 114362, 4497, 14199, 36249, 41817, 23995, 93888, 35798, 96337, - 5530, 82377, 66438, 85247, 39332, 78978, 83015, 123505, - ]; - assert!(is_valid_solution(96, 5, input, &nonce, &indices)); - - indices = vec![ - 1505, 1380774, 200806, 1787044, 101056, 1697952, 281464, 374899, 263712, 1532496, - 264180, 637056, 734225, 1882676, 1112004, 2093109, 193394, 1459136, 525171, 657480, - 214528, 1221365, 574444, 594726, 501919, 1309358, 1740268, 1989610, 654491, 1068055, - 919416, 1993208, 17599, 1858176, 1315176, 1901532, 108258, 109600, 1117445, 1936058, - 70247, 1036984, 628234, 1800109, 149791, 365740, 345683, 563554, 21678, 822781, - 1423722, 1644228, 792912, 1409641, 805060, 2041985, 453824, 1003179, 934427, 1068834, - 629003, 1456111, 670049, 1558594, 19016, 1343657, 1698188, 1865216, 45723, 1820952, - 1160970, 1585983, 422549, 1973097, 1296271, 2006382, 650084, 809838, 871727, 1080419, - 28500, 1471829, 384406, 619459, 212041, 1466258, 481435, 866461, 145340, 1403843, - 1339592, 1405761, 163425, 1073771, 285027, 1488210, 167744, 1182267, 1354059, 2089602, - 921700, 2059931, 1704721, 1853088, 585171, 739246, 747551, 1520527, 590255, 1175747, - 705292, 998433, 522014, 1931179, 1629531, 1692879, 588830, 1799457, 963672, 1664237, - 775408, 1926741, 907030, 1466738, 784179, 1972599, 1494787, 1598114, 1736, 1039487, - 88704, 1302687, 579526, 1476728, 1677992, 1854526, 432470, 2062305, 1471132, 1747579, - 1521894, 1917599, 1590975, 1936227, 151871, 1999775, 224664, 461809, 704084, 1306665, - 1316156, 1529628, 876811, 2086004, 1986383, 2012147, 1039505, 1637502, 1432721, - 1565477, 110385, 342650, 659137, 1285167, 367416, 2007586, 445677, 2084877, 285692, - 1144365, 988840, 1990372, 748425, 1617758, 1267712, 1510433, 152291, 1256291, 1722179, - 1995439, 864844, 1623380, 1071853, 1731862, 699978, 1407662, 1048047, 1849702, 962900, - 1083340, 1378752, 1534902, 11843, 115329, 454796, 548919, 148184, 1686936, 862432, - 873854, 60753, 999864, 385959, 1528101, 534420, 678401, 590419, 1962518, 54984, - 1141820, 243305, 1349970, 599681, 1817233, 1632537, 1698724, 580004, 673073, 1403350, - 2026104, 758881, 970056, 1717966, 2062827, 19624, 148580, 609748, 1588928, 456321, - 834920, 700532, 1682606, 20012, 441139, 1591072, 1923394, 194034, 1741063, 1156906, - 1983067, 20703, 1939972, 604581, 963600, 128170, 731716, 606773, 1626824, 139460, - 1386775, 521911, 2043473, 392180, 449532, 895678, 1453340, 7085, 598416, 1514260, - 2061068, 279532, 678363, 943255, 1405306, 119114, 2075865, 592839, 1972064, 254647, - 2078288, 946282, 1567138, 120422, 767626, 213242, 448366, 438457, 1768467, 853790, - 1509505, 735780, 1979631, 1461410, 1462050, 739008, 1572606, 920754, 1507358, 12883, - 1681167, 1308399, 1839490, 85599, 1387522, 703262, 1949514, 18523, 1236125, 669105, - 1464132, 68670, 2085647, 333393, 1731573, 21714, 637827, 985912, 2091029, 84065, - 1688993, 1574405, 1899543, 134032, 179206, 671016, 1118310, 288960, 861994, 622074, - 1738892, 10936, 343910, 598016, 1741971, 586348, 1956071, 851053, 1715626, 531385, - 1213667, 1093995, 1863757, 630365, 1851894, 1328101, 1770446, 31900, 734027, 1078651, - 1701535, 123276, 1916343, 581822, 1681706, 573135, 818091, 1454710, 2052521, 1150284, - 1451159, 1482280, 1811430, 26321, 785837, 877980, 2073103, 107324, 727248, 1785460, - 1840517, 184560, 185640, 364103, 1878753, 518459, 1984029, 964109, 1884200, 74003, - 527272, 516232, 711247, 148582, 209254, 634610, 1534140, 376714, 1573267, 421225, - 1265101, 1078858, 1374310, 1806283, 2091298, 23392, 389637, 413663, 1066737, 226164, - 762552, 1048220, 1583397, 40092, 277435, 775449, 1533894, 202582, 390703, 346741, - 1027320, 523034, 809424, 584882, 1296934, 528062, 733331, 1212771, 1958651, 653372, - 1313962, 1366332, 1784489, 1542466, 1580386, 1628948, 2000957, 57069, 1398636, 1250431, - 1698486, 57289, 596009, 582428, 966130, 167657, 1025537, 1227498, 1630134, 234060, - 1285209, 265623, 1165779, 68485, 632055, 96019, 1854676, 98410, 158575, 168035, - 1296171, 158847, 1243959, 977212, 1113647, 363568, 891940, 954593, 1987111, 90101, - 133251, 1136222, 1255117, 543075, 732768, 749576, 1174878, 422226, 1854657, 1143029, - 1457135, 927105, 1137382, 1566306, 1661926, 103057, 425126, 698089, 1774942, 911019, - 1793511, 1623559, 2002409, 457796, 1196971, 724257, 1811147, 956269, 1165590, 1137531, - 1381215, 201063, 1938529, 986021, 1297857, 921334, 1259083, 1440074, 1939366, 232907, - 747213, 1349009, 1945364, 689906, 1116453, 1904207, 1916192, 229793, 1576982, 1420059, - 1644978, 278248, 2024807, 297914, 419798, 555747, 712605, 1012424, 1428921, 890113, - 1822645, 1082368, 1392894, - ]; - assert!(!is_valid_solution(96, 5, input, &nonce, &indices)); - assert!(is_valid_solution(200, 9, input, &nonce, &indices)); - - let input2 = b"Equihash is an asymmetric PoW based on the Generalised Birthday problem."; - indices = vec![ - 2261, 15185, 36112, 104243, 23779, 118390, 118332, 130041, 32642, 69878, 76925, 80080, - 45858, 116805, 92842, 111026, 15972, 115059, 85191, 90330, 68190, 122819, 81830, 91132, - 23460, 49807, 52426, 80391, 69567, 114474, 104973, 122568, - ]; - assert!(is_valid_solution(96, 5, input2, &nonce, &indices)); - } -} diff --git a/librustzcash/src/hashreader.rs b/librustzcash/src/hashreader.rs deleted file mode 100644 index a422d52..0000000 --- a/librustzcash/src/hashreader.rs +++ /dev/null @@ -1,42 +0,0 @@ -use blake2_rfc::blake2b::Blake2b; -use std::io::{self, Read}; - -/// Abstraction over a reader which hashes the data being read. -pub struct HashReader { - reader: R, - hasher: Blake2b, -} - -impl HashReader { - /// Construct a new `HashReader` given an existing `reader` by value. - pub fn new(reader: R) -> Self { - HashReader { - reader: reader, - hasher: Blake2b::new(64), - } - } - - /// Destroy this reader and return the hash of what was read. - pub fn into_hash(self) -> String { - let hash = self.hasher.finalize(); - - let mut s = String::new(); - for c in hash.as_bytes().iter() { - s += &format!("{:02x}", c); - } - - s - } -} - -impl Read for HashReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let bytes = self.reader.read(buf)?; - - if bytes > 0 { - self.hasher.update(&buf[0..bytes]); - } - - Ok(bytes) - } -} diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs deleted file mode 100644 index b77b6b2..0000000 --- a/librustzcash/src/rustzcash.rs +++ /dev/null @@ -1,1315 +0,0 @@ -extern crate bellman; -extern crate blake2_rfc; -extern crate byteorder; -extern crate libc; -extern crate pairing; -extern crate rand; -extern crate sapling_crypto; -extern crate zcash_proofs; -extern crate zip32; - -mod hashreader; - -#[macro_use] -extern crate lazy_static; - -use pairing::{ - bls12_381::{Bls12, Fr, FrRepr}, - BitIterator, PrimeField, PrimeFieldRepr, -}; - -use sapling_crypto::{ - circuit::multipack, - constants::CRH_IVK_PERSONALIZATION, - jubjub::{ - edwards, - fs::{Fs, FsRepr}, - FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, PrimeOrder, ToUniform, Unknown, - }, - pedersen_hash::{pedersen_hash, Personalization}, - redjubjub::{self, Signature}, -}; - -use sapling_crypto::circuit::sapling::TREE_DEPTH as SAPLING_TREE_DEPTH; -use sapling_crypto::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH}; - -use bellman::groth16::{ - create_random_proof, prepare_verifying_key, verify_proof, Parameters, PreparedVerifyingKey, - Proof, VerifyingKey, -}; - -use blake2_rfc::blake2s::Blake2s; - -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; - -use rand::{OsRng, Rng}; -use std::io::{self, BufReader}; - -use libc::{c_char, c_uchar, int64_t, size_t, uint32_t, uint64_t}; -use std::ffi::CStr; -use std::fs::File; -use std::path::{Path, PathBuf}; -use std::slice; - -#[cfg(not(target_os = "windows"))] -use std::ffi::OsStr; -#[cfg(not(target_os = "windows"))] -use std::os::unix::ffi::OsStrExt; - -#[cfg(target_os = "windows")] -use std::ffi::OsString; -#[cfg(target_os = "windows")] -use std::os::windows::ffi::OsStringExt; - -use sapling_crypto::primitives::{ProofGenerationKey, ViewingKey}; -use zcash_proofs::sapling::{ - CommitmentTreeWitness, SaplingProvingContext, SaplingVerificationContext, -}; - -pub mod equihash; - -#[cfg(test)] -mod tests; - -lazy_static! { - static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() }; -} - -static mut SAPLING_SPEND_VK: Option> = None; -static mut SAPLING_OUTPUT_VK: Option> = None; -static mut SPROUT_GROTH16_VK: Option> = None; - -static mut SAPLING_SPEND_PARAMS: Option> = None; -static mut SAPLING_OUTPUT_PARAMS: Option> = None; -static mut SPROUT_GROTH16_PARAMS_PATH: Option = None; - -/// Writes an FrRepr to [u8] of length 32 -fn write_le(f: FrRepr, to: &mut [u8]) { - assert_eq!(to.len(), 32); - - f.write_le(to).expect("length is 32 bytes"); -} - -/// Reads an FrRepr from a [u8] of length 32. -/// This will panic (abort) if length provided is -/// not correct. -fn read_le(from: &[u8]) -> FrRepr { - assert_eq!(from.len(), 32); - - let mut f = FrRepr::default(); - f.read_le(from).expect("length is 32 bytes"); - - f -} - -/// Reads an FsRepr from [u8] of length 32 -/// This will panic (abort) if length provided is -/// not correct -fn read_fs(from: &[u8]) -> FsRepr { - assert_eq!(from.len(), 32); - - let mut f = <::Fs as PrimeField>::Repr::default(); - f.read_le(from).expect("length is 32 bytes"); - - f -} - -/// Reads an FsRepr from [u8] of length 32 -/// and multiplies it by the given base. -/// This will panic (abort) if length provided is -/// not correct -fn fixed_scalar_mult(from: &[u8], p_g: FixedGenerators) -> edwards::Point { - let f = read_fs(from); - - JUBJUB.generator(p_g).mul(f, &JUBJUB) -} - -#[cfg(not(target_os = "windows"))] -#[no_mangle] -pub extern "system" fn librustzcash_init_zksnark_params( - spend_path: *const u8, - spend_path_len: usize, - spend_hash: *const c_char, - output_path: *const u8, - output_path_len: usize, - output_hash: *const c_char, - sprout_path: *const u8, - sprout_path_len: usize, - sprout_hash: *const c_char, -) { - let spend_path = Path::new(OsStr::from_bytes(unsafe { - slice::from_raw_parts(spend_path, spend_path_len) - })); - let output_path = Path::new(OsStr::from_bytes(unsafe { - slice::from_raw_parts(output_path, output_path_len) - })); - let sprout_path = Path::new(OsStr::from_bytes(unsafe { - slice::from_raw_parts(sprout_path, sprout_path_len) - })); - - init_zksnark_params( - spend_path, - spend_hash, - output_path, - output_hash, - sprout_path, - sprout_hash, - ) -} - -#[cfg(target_os = "windows")] -#[no_mangle] -pub extern "system" fn librustzcash_init_zksnark_params( - spend_path: *const u16, - spend_path_len: usize, - spend_hash: *const c_char, - output_path: *const u16, - output_path_len: usize, - output_hash: *const c_char, - sprout_path: *const u16, - sprout_path_len: usize, - sprout_hash: *const c_char, -) { - let spend_path = - OsString::from_wide(unsafe { slice::from_raw_parts(spend_path, spend_path_len) }); - let output_path = - OsString::from_wide(unsafe { slice::from_raw_parts(output_path, output_path_len) }); - let sprout_path = - OsString::from_wide(unsafe { slice::from_raw_parts(sprout_path, sprout_path_len) }); - - init_zksnark_params( - Path::new(&spend_path), - spend_hash, - Path::new(&output_path), - output_hash, - Path::new(&sprout_path), - sprout_hash, - ) -} - -fn init_zksnark_params( - spend_path: &Path, - spend_hash: *const c_char, - output_path: &Path, - output_hash: *const c_char, - sprout_path: &Path, - sprout_hash: *const c_char, -) { - // Initialize jubjub parameters here - lazy_static::initialize(&JUBJUB); - - let spend_hash = unsafe { CStr::from_ptr(spend_hash) } - .to_str() - .expect("hash should be a valid string") - .to_string(); - - let output_hash = unsafe { CStr::from_ptr(output_hash) } - .to_str() - .expect("hash should be a valid string") - .to_string(); - - let sprout_hash = unsafe { CStr::from_ptr(sprout_hash) } - .to_str() - .expect("hash should be a valid string") - .to_string(); - - // Load from each of the paths - let spend_fs = File::open(spend_path).expect("couldn't load Sapling spend parameters file"); - let output_fs = File::open(output_path).expect("couldn't load Sapling output parameters file"); - let sprout_fs = File::open(sprout_path).expect("couldn't load Sprout groth16 parameters file"); - - let mut spend_fs = hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, spend_fs)); - let mut output_fs = - hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, output_fs)); - let mut sprout_fs = - hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, sprout_fs)); - - // Deserialize params - let spend_params = Parameters::::read(&mut spend_fs, false) - .expect("couldn't deserialize Sapling spend parameters file"); - let output_params = Parameters::::read(&mut output_fs, false) - .expect("couldn't deserialize Sapling spend parameters file"); - - // We only deserialize the verifying key for the Sprout parameters, which - // appears at the beginning of the parameter file. The rest is loaded - // during proving time. - let sprout_vk = VerifyingKey::::read(&mut sprout_fs) - .expect("couldn't deserialize Sprout Groth16 verifying key"); - - // There is extra stuff (the transcript) at the end of the parameter file which is - // used to verify the parameter validity, but we're not interested in that. We do - // want to read it, though, so that the BLAKE2b computed afterward is consistent - // with `b2sum` on the files. - let mut sink = io::sink(); - io::copy(&mut spend_fs, &mut sink) - .expect("couldn't finish reading Sapling spend parameter file"); - io::copy(&mut output_fs, &mut sink) - .expect("couldn't finish reading Sapling output parameter file"); - io::copy(&mut sprout_fs, &mut sink) - .expect("couldn't finish reading Sprout groth16 parameter file"); - - if spend_fs.into_hash() != spend_hash { - panic!("Sapling spend parameter file is not correct, please clean your `~/.zcash-params/` and re-run `fetch-params`."); - } - - if output_fs.into_hash() != output_hash { - panic!("Sapling output parameter file is not correct, please clean your `~/.zcash-params/` and re-run `fetch-params`."); - } - - if sprout_fs.into_hash() != sprout_hash { - panic!("Sprout groth16 parameter file is not correct, please clean your `~/.zcash-params/` and re-run `fetch-params`."); - } - - // Prepare verifying keys - let spend_vk = prepare_verifying_key(&spend_params.vk); - let output_vk = prepare_verifying_key(&output_params.vk); - let sprout_vk = prepare_verifying_key(&sprout_vk); - - // Caller is responsible for calling this function once, so - // these global mutations are safe. - unsafe { - SAPLING_SPEND_PARAMS = Some(spend_params); - SAPLING_OUTPUT_PARAMS = Some(output_params); - SPROUT_GROTH16_PARAMS_PATH = Some(sprout_path.to_owned()); - - SAPLING_SPEND_VK = Some(spend_vk); - SAPLING_OUTPUT_VK = Some(output_vk); - SPROUT_GROTH16_VK = Some(sprout_vk); - } -} - -#[no_mangle] -pub extern "system" fn librustzcash_tree_uncommitted(result: *mut [c_uchar; 32]) { - let tmp = sapling_crypto::primitives::Note::::uncommitted().into_repr(); - - // Should be okay, caller is responsible for ensuring the pointer - // is a valid pointer to 32 bytes that can be mutated. - let result = unsafe { &mut *result }; - - write_le(tmp, &mut result[..]); -} - -#[no_mangle] -pub extern "system" fn librustzcash_merkle_hash( - depth: size_t, - a: *const [c_uchar; 32], - b: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) { - // Should be okay, because caller is responsible for ensuring - // the pointer is a valid pointer to 32 bytes, and that is the - // size of the representation - let a_repr = read_le(unsafe { &(&*a)[..] }); - - // Should be okay, because caller is responsible for ensuring - // the pointer is a valid pointer to 32 bytes, and that is the - // size of the representation - let b_repr = read_le(unsafe { &(&*b)[..] }); - - let mut lhs = [false; 256]; - let mut rhs = [false; 256]; - - for (a, b) in lhs.iter_mut().rev().zip(BitIterator::new(a_repr)) { - *a = b; - } - - for (a, b) in rhs.iter_mut().rev().zip(BitIterator::new(b_repr)) { - *a = b; - } - - let tmp = pedersen_hash::( - Personalization::MerkleTree(depth), - lhs.iter() - .map(|&x| x) - .take(Fr::NUM_BITS as usize) - .chain(rhs.iter().map(|&x| x).take(Fr::NUM_BITS as usize)), - &JUBJUB, - ) - .into_xy() - .0 - .into_repr(); - - // Should be okay, caller is responsible for ensuring the pointer - // is a valid pointer to 32 bytes that can be mutated. - let result = unsafe { &mut *result }; - - write_le(tmp, &mut result[..]); -} - -#[no_mangle] // ToScalar -pub extern "system" fn librustzcash_to_scalar( - input: *const [c_uchar; 64], - result: *mut [c_uchar; 32], -) { - // Should be okay, because caller is responsible for ensuring - // the pointer is a valid pointer to 32 bytes, and that is the - // size of the representation - let scalar = ::Fs::to_uniform(unsafe { &(&*input)[..] }).into_repr(); - - let result = unsafe { &mut *result }; - - scalar - .write_le(&mut result[..]) - .expect("length is 32 bytes"); -} - -#[no_mangle] -pub extern "system" fn librustzcash_ask_to_ak( - ask: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) { - let ask = unsafe { &*ask }; - let ak = fixed_scalar_mult(ask, FixedGenerators::SpendingKeyGenerator); - - let result = unsafe { &mut *result }; - - ak.write(&mut result[..]).expect("length is 32 bytes"); -} - -#[no_mangle] -pub extern "system" fn librustzcash_nsk_to_nk( - nsk: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) { - let nsk = unsafe { &*nsk }; - let nk = fixed_scalar_mult(nsk, FixedGenerators::ProofGenerationKey); - - let result = unsafe { &mut *result }; - - nk.write(&mut result[..]).expect("length is 32 bytes"); -} - -#[no_mangle] -pub extern "system" fn librustzcash_crh_ivk( - ak: *const [c_uchar; 32], - nk: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) { - let ak = unsafe { &*ak }; - let nk = unsafe { &*nk }; - - let mut h = Blake2s::with_params(32, &[], &[], CRH_IVK_PERSONALIZATION); - h.update(ak); - h.update(nk); - let mut h = h.finalize().as_ref().to_vec(); - - // Drop the last five bits, so it can be interpreted as a scalar. - h[31] &= 0b0000_0111; - - let result = unsafe { &mut *result }; - - result.copy_from_slice(&h); -} - -#[no_mangle] -pub extern "system" fn librustzcash_check_diversifier(diversifier: *const [c_uchar; 11]) -> bool { - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); - diversifier.g_d::(&JUBJUB).is_some() -} - -#[no_mangle] -pub extern "system" fn librustzcash_ivk_to_pkd( - ivk: *const [c_uchar; 32], - diversifier: *const [c_uchar; 11], - result: *mut [c_uchar; 32], -) -> bool { - let ivk = read_fs(unsafe { &*ivk }); - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); - if let Some(g_d) = diversifier.g_d::(&JUBJUB) { - let pk_d = g_d.mul(ivk, &JUBJUB); - - let result = unsafe { &mut *result }; - - pk_d.write(&mut result[..]).expect("length is 32 bytes"); - - true - } else { - false - } -} - -/// Test generation of commitment randomness -#[test] -fn test_gen_r() { - let mut r1 = [0u8; 32]; - let mut r2 = [0u8; 32]; - - // Verify different r values are generated - librustzcash_sapling_generate_r(&mut r1); - librustzcash_sapling_generate_r(&mut r2); - assert_ne!(r1, r2); - - // Verify r values are valid in the field - let mut repr = FsRepr::default(); - repr.read_le(&r1[..]).expect("length is not 32 bytes"); - let _ = Fs::from_repr(repr).unwrap(); - repr.read_le(&r2[..]).expect("length is not 32 bytes"); - let _ = Fs::from_repr(repr).unwrap(); -} - -/// Return 32 byte random scalar, uniformly. -#[no_mangle] -pub extern "system" fn librustzcash_sapling_generate_r(result: *mut [c_uchar; 32]) { - // create random 64 byte buffer - let mut rng = OsRng::new().expect("should be able to construct RNG"); - let mut buffer = [0u8; 64]; - for i in 0..buffer.len() { - buffer[i] = rng.gen(); - } - - // reduce to uniform value - let r = ::Fs::to_uniform(&buffer[..]); - let result = unsafe { &mut *result }; - r.into_repr() - .write_le(&mut result[..]) - .expect("result must be 32 bytes"); -} - -// Private utility function to get Note from C parameters -fn priv_get_note( - diversifier: *const [c_uchar; 11], - pk_d: *const [c_uchar; 32], - value: uint64_t, - r: *const [c_uchar; 32], -) -> Result, ()> { - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); - let g_d = match diversifier.g_d::(&JUBJUB) { - Some(g_d) => g_d, - None => return Err(()), - }; - - let pk_d = match edwards::Point::::read(&(unsafe { &*pk_d })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return Err(()), - }; - - let pk_d = match pk_d.as_prime_order(&JUBJUB) { - Some(pk_d) => pk_d, - None => return Err(()), - }; - - // Deserialize randomness - let r = match Fs::from_repr(read_fs(&(unsafe { &*r })[..])) { - Ok(r) => r, - Err(_) => return Err(()), - }; - - let note = sapling_crypto::primitives::Note { - value, - g_d, - pk_d, - r, - }; - - Ok(note) -} - -/// Compute Sapling note nullifier. -#[no_mangle] -pub extern "system" fn librustzcash_sapling_compute_nf( - diversifier: *const [c_uchar; 11], - pk_d: *const [c_uchar; 32], - value: uint64_t, - r: *const [c_uchar; 32], - ak: *const [c_uchar; 32], - nk: *const [c_uchar; 32], - position: uint64_t, - result: *mut [c_uchar; 32], -) -> bool { - let note = match priv_get_note(diversifier, pk_d, value, r) { - Ok(p) => p, - Err(_) => return false, - }; - - let ak = match edwards::Point::::read(&(unsafe { &*ak })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - let ak = match ak.as_prime_order(&JUBJUB) { - Some(ak) => ak, - None => return false, - }; - - let nk = match edwards::Point::::read(&(unsafe { &*nk })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - let nk = match nk.as_prime_order(&JUBJUB) { - Some(nk) => nk, - None => return false, - }; - - let vk = ViewingKey { ak, nk }; - let nf = note.nf(&vk, position, &JUBJUB); - let result = unsafe { &mut *result }; - result.copy_from_slice(&nf); - - true -} - -/// Compute Sapling note commitment. -#[no_mangle] -pub extern "system" fn librustzcash_sapling_compute_cm( - diversifier: *const [c_uchar; 11], - pk_d: *const [c_uchar; 32], - value: uint64_t, - r: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) -> bool { - let note = match priv_get_note(diversifier, pk_d, value, r) { - Ok(p) => p, - Err(_) => return false, - }; - - let result = unsafe { &mut *result }; - write_le(note.cm(&JUBJUB).into_repr(), &mut result[..]); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_ka_agree( - p: *const [c_uchar; 32], - sk: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) -> bool { - // Deserialize p - let p = match edwards::Point::::read(&(unsafe { &*p })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - // Deserialize sk - let sk = match Fs::from_repr(read_fs(&(unsafe { &*sk })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - // Multiply by 8 - let p = p.mul_by_cofactor(&JUBJUB); - - // Multiply by sk - let p = p.mul(sk, &JUBJUB); - - // Produce result - let result = unsafe { &mut *result }; - p.write(&mut result[..]).expect("length is not 32 bytes"); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_ka_derivepublic( - diversifier: *const [c_uchar; 11], - esk: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) -> bool { - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); - - // Compute g_d from the diversifier - let g_d = match diversifier.g_d::(&JUBJUB) { - Some(g) => g, - None => return false, - }; - - // Deserialize esk - let esk = match Fs::from_repr(read_fs(&(unsafe { &*esk })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - let p = g_d.mul(esk, &JUBJUB); - - let result = unsafe { &mut *result }; - p.write(&mut result[..]).expect("length is not 32 bytes"); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_eh_isvalid( - n: uint32_t, - k: uint32_t, - input: *const c_uchar, - input_len: size_t, - nonce: *const c_uchar, - nonce_len: size_t, - soln: *const c_uchar, - soln_len: size_t, -) -> bool { - if (k >= n) || (n % 8 != 0) || (soln_len != (1 << k) * ((n / (k + 1)) as usize + 1) / 8) { - return false; - } - let rs_input = unsafe { slice::from_raw_parts(input, input_len) }; - let rs_nonce = unsafe { slice::from_raw_parts(nonce, nonce_len) }; - let rs_soln = unsafe { slice::from_raw_parts(soln, soln_len) }; - equihash::is_valid_solution(n, k, rs_input, rs_nonce, rs_soln) -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_verification_ctx_init( -) -> *mut SaplingVerificationContext { - let ctx = Box::new(SaplingVerificationContext::new()); - - Box::into_raw(ctx) -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_verification_ctx_free( - ctx: *mut SaplingVerificationContext, -) { - drop(unsafe { Box::from_raw(ctx) }); -} - -const GROTH_PROOF_SIZE: usize = 48 // π_A - + 96 // π_B - + 48; // π_C - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_check_spend( - ctx: *mut SaplingVerificationContext, - cv: *const [c_uchar; 32], - anchor: *const [c_uchar; 32], - nullifier: *const [c_uchar; 32], - rk: *const [c_uchar; 32], - zkproof: *const [c_uchar; GROTH_PROOF_SIZE], - spend_auth_sig: *const [c_uchar; 64], - sighash_value: *const [c_uchar; 32], -) -> bool { - // Deserialize the value commitment - let cv = match edwards::Point::::read(&(unsafe { &*cv })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - // Deserialize the anchor, which should be an element - // of Fr. - let anchor = match Fr::from_repr(read_le(&(unsafe { &*anchor })[..])) { - Ok(a) => a, - Err(_) => return false, - }; - - // Deserialize rk - let rk = match redjubjub::PublicKey::::read(&(unsafe { &*rk })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - // Deserialize the signature - let spend_auth_sig = match Signature::read(&(unsafe { &*spend_auth_sig })[..]) { - Ok(sig) => sig, - Err(_) => return false, - }; - - // Deserialize the proof - let zkproof = match Proof::::read(&(unsafe { &*zkproof })[..]) { - Ok(p) => p, - Err(_) => return false, - }; - - unsafe { &mut *ctx }.check_spend( - cv, - anchor, - unsafe { &*nullifier }, - rk, - unsafe { &*sighash_value }, - spend_auth_sig, - zkproof, - unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap(), - &JUBJUB, - ) -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_check_output( - ctx: *mut SaplingVerificationContext, - cv: *const [c_uchar; 32], - cm: *const [c_uchar; 32], - epk: *const [c_uchar; 32], - zkproof: *const [c_uchar; GROTH_PROOF_SIZE], -) -> bool { - // Deserialize the value commitment - let cv = match edwards::Point::::read(&(unsafe { &*cv })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - // Deserialize the commitment, which should be an element - // of Fr. - let cm = match Fr::from_repr(read_le(&(unsafe { &*cm })[..])) { - Ok(a) => a, - Err(_) => return false, - }; - - // Deserialize the ephemeral key - let epk = match edwards::Point::::read(&(unsafe { &*epk })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - // Deserialize the proof - let zkproof = match Proof::::read(&(unsafe { &*zkproof })[..]) { - Ok(p) => p, - Err(_) => return false, - }; - - unsafe { &mut *ctx }.check_output( - cv, - cm, - epk, - zkproof, - unsafe { SAPLING_OUTPUT_VK.as_ref() }.unwrap(), - &JUBJUB, - ) -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_final_check( - ctx: *mut SaplingVerificationContext, - value_balance: int64_t, - binding_sig: *const [c_uchar; 64], - sighash_value: *const [c_uchar; 32], -) -> bool { - // Deserialize the signature - let binding_sig = match Signature::read(&(unsafe { &*binding_sig })[..]) { - Ok(sig) => sig, - Err(_) => return false, - }; - - unsafe { &*ctx }.final_check( - value_balance, - unsafe { &*sighash_value }, - binding_sig, - &JUBJUB, - ) -} - -#[no_mangle] -pub extern "system" fn librustzcash_sprout_prove( - proof_out: *mut [c_uchar; GROTH_PROOF_SIZE], - - phi: *const [c_uchar; 32], - rt: *const [c_uchar; 32], - h_sig: *const [c_uchar; 32], - - // First input - in_sk1: *const [c_uchar; 32], - in_value1: uint64_t, - in_rho1: *const [c_uchar; 32], - in_r1: *const [c_uchar; 32], - in_auth1: *const [c_uchar; 1 + 33 * SPROUT_TREE_DEPTH + 8], - - // Second input - in_sk2: *const [c_uchar; 32], - in_value2: uint64_t, - in_rho2: *const [c_uchar; 32], - in_r2: *const [c_uchar; 32], - in_auth2: *const [c_uchar; 1 + 33 * SPROUT_TREE_DEPTH + 8], - - // First output - out_pk1: *const [c_uchar; 32], - out_value1: uint64_t, - out_r1: *const [c_uchar; 32], - - // Second output - out_pk2: *const [c_uchar; 32], - out_value2: uint64_t, - out_r2: *const [c_uchar; 32], - - // Public value - vpub_old: uint64_t, - vpub_new: uint64_t, -) { - let phi = unsafe { *phi }; - let rt = unsafe { *rt }; - let h_sig = unsafe { *h_sig }; - let in_sk1 = unsafe { *in_sk1 }; - let in_rho1 = unsafe { *in_rho1 }; - let in_r1 = unsafe { *in_r1 }; - let in_auth1 = unsafe { *in_auth1 }; - let in_sk2 = unsafe { *in_sk2 }; - let in_rho2 = unsafe { *in_rho2 }; - let in_r2 = unsafe { *in_r2 }; - let in_auth2 = unsafe { *in_auth2 }; - let out_pk1 = unsafe { *out_pk1 }; - let out_r1 = unsafe { *out_r1 }; - let out_pk2 = unsafe { *out_pk2 }; - let out_r2 = unsafe { *out_r2 }; - - let mut inputs = Vec::with_capacity(2); - { - let mut handle_input = |sk, value, rho, r, mut auth: &[u8]| { - let value = Some(value); - let rho = Some(sprout::UniqueRandomness(rho)); - let r = Some(sprout::CommitmentRandomness(r)); - let a_sk = Some(sprout::SpendingKey(sk)); - - // skip the first byte - assert_eq!(auth[0], SPROUT_TREE_DEPTH as u8); - auth = &auth[1..]; - - let mut auth_path = [None; SPROUT_TREE_DEPTH]; - for i in (0..SPROUT_TREE_DEPTH).rev() { - // skip length of inner vector - assert_eq!(auth[0], 32); - auth = &auth[1..]; - - let mut sibling = [0u8; 32]; - sibling.copy_from_slice(&auth[0..32]); - auth = &auth[32..]; - - auth_path[i] = Some((sibling, false)); - } - - let mut position = auth - .read_u64::() - .expect("should have had index at the end"); - - for i in 0..SPROUT_TREE_DEPTH { - auth_path[i].as_mut().map(|p| p.1 = (position & 1) == 1); - - position >>= 1; - } - - inputs.push(sprout::JSInput { - value: value, - a_sk: a_sk, - rho: rho, - r: r, - auth_path: auth_path, - }); - }; - - handle_input(in_sk1, in_value1, in_rho1, in_r1, &in_auth1[..]); - handle_input(in_sk2, in_value2, in_rho2, in_r2, &in_auth2[..]); - } - - let mut outputs = Vec::with_capacity(2); - { - let mut handle_output = |a_pk, value, r| { - outputs.push(sprout::JSOutput { - value: Some(value), - a_pk: Some(sprout::PayingKey(a_pk)), - r: Some(sprout::CommitmentRandomness(r)), - }); - }; - - handle_output(out_pk1, out_value1, out_r1); - handle_output(out_pk2, out_value2, out_r2); - } - - let js = sprout::JoinSplit { - vpub_old: Some(vpub_old), - vpub_new: Some(vpub_new), - h_sig: Some(h_sig), - phi: Some(phi), - inputs: inputs, - outputs: outputs, - rt: Some(rt), - }; - - // Load parameters from disk - let sprout_fs = File::open( - unsafe { &SPROUT_GROTH16_PARAMS_PATH } - .as_ref() - .expect("parameters should have been initialized"), - ) - .expect("couldn't load Sprout groth16 parameters file"); - - let mut sprout_fs = BufReader::with_capacity(1024 * 1024, sprout_fs); - - let params = Parameters::::read(&mut sprout_fs, false) - .expect("couldn't deserialize Sprout JoinSplit parameters file"); - - drop(sprout_fs); - - // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); - - let proof = create_random_proof(js, ¶ms, &mut rng).expect("proving should not fail"); - - proof - .write(&mut (unsafe { &mut *proof_out })[..]) - .expect("should be able to serialize a proof"); -} - -#[no_mangle] -pub extern "system" fn librustzcash_sprout_verify( - proof: *const [c_uchar; GROTH_PROOF_SIZE], - rt: *const [c_uchar; 32], - h_sig: *const [c_uchar; 32], - mac1: *const [c_uchar; 32], - mac2: *const [c_uchar; 32], - nf1: *const [c_uchar; 32], - nf2: *const [c_uchar; 32], - cm1: *const [c_uchar; 32], - cm2: *const [c_uchar; 32], - vpub_old: uint64_t, - vpub_new: uint64_t, -) -> bool { - // Prepare the public input for the verifier - let mut public_input = Vec::with_capacity((32 * 8) + (8 * 2)); - public_input.extend(unsafe { &(&*rt)[..] }); - public_input.extend(unsafe { &(&*h_sig)[..] }); - public_input.extend(unsafe { &(&*nf1)[..] }); - public_input.extend(unsafe { &(&*mac1)[..] }); - public_input.extend(unsafe { &(&*nf2)[..] }); - public_input.extend(unsafe { &(&*mac2)[..] }); - public_input.extend(unsafe { &(&*cm1)[..] }); - public_input.extend(unsafe { &(&*cm2)[..] }); - public_input.write_u64::(vpub_old).unwrap(); - public_input.write_u64::(vpub_new).unwrap(); - - let public_input = multipack::bytes_to_bits(&public_input); - let public_input = multipack::compute_multipacking::(&public_input); - - let proof = match Proof::read(unsafe { &(&*proof)[..] }) { - Ok(p) => p, - Err(_) => return false, - }; - - // Verify the proof - match verify_proof( - unsafe { SPROUT_GROTH16_VK.as_ref() }.expect("parameters should have been initialized"), - &proof, - &public_input[..], - ) { - // No error, and proof verification successful - Ok(true) => true, - - // Any other case - _ => false, - } -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_output_proof( - ctx: *mut SaplingProvingContext, - esk: *const [c_uchar; 32], - diversifier: *const [c_uchar; 11], - pk_d: *const [c_uchar; 32], - rcm: *const [c_uchar; 32], - value: uint64_t, - cv: *mut [c_uchar; 32], - zkproof: *mut [c_uchar; GROTH_PROOF_SIZE], -) -> bool { - // Grab `esk`, which the caller should have constructed for the DH key exchange. - let esk = match Fs::from_repr(read_fs(&(unsafe { &*esk })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - // Grab the diversifier from the caller. - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); - - // Grab pk_d from the caller. - let pk_d = match edwards::Point::::read(&(unsafe { &*pk_d })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - // pk_d should be prime order. - let pk_d = match pk_d.as_prime_order(&JUBJUB) { - Some(p) => p, - None => return false, - }; - - // Construct a payment address - let payment_address = sapling_crypto::primitives::PaymentAddress { - pk_d: pk_d, - diversifier: diversifier, - }; - - // The caller provides the commitment randomness for the output note - let rcm = match Fs::from_repr(read_fs(&(unsafe { &*rcm })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - // Create proof - let (proof, value_commitment) = unsafe { &mut *ctx }.output_proof( - esk, - payment_address, - rcm, - value, - unsafe { SAPLING_OUTPUT_PARAMS.as_ref() }.unwrap(), - &JUBJUB, - ); - - // Write the proof out to the caller - proof - .write(&mut (unsafe { &mut *zkproof })[..]) - .expect("should be able to serialize a proof"); - - // Write the value commitment to the caller - value_commitment - .write(&mut (unsafe { &mut *cv })[..]) - .expect("should be able to serialize rcv"); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_spend_sig( - ask: *const [c_uchar; 32], - ar: *const [c_uchar; 32], - sighash: *const [c_uchar; 32], - result: *mut [c_uchar; 64], -) -> bool { - // The caller provides the re-randomization of `ak`. - let ar = match Fs::from_repr(read_fs(&(unsafe { &*ar })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - // The caller provides `ask`, the spend authorizing key. - let ask = match redjubjub::PrivateKey::::read(&(unsafe { &*ask })[..]) { - Ok(p) => p, - Err(_) => return false, - }; - - // We compute `rsk`... - let rsk = ask.randomize(ar); - - // We compute `rk` from there (needed for key prefixing) - let rk = - redjubjub::PublicKey::from_private(&rsk, FixedGenerators::SpendingKeyGenerator, &JUBJUB); - - // Compute the signature's message for rk/spend_auth_sig - let mut data_to_be_signed = [0u8; 64]; - rk.0.write(&mut data_to_be_signed[0..32]) - .expect("message buffer should be 32 bytes"); - (&mut data_to_be_signed[32..64]).copy_from_slice(&(unsafe { &*sighash })[..]); - - // Do the signing - let mut rng = OsRng::new().expect("should be able to construct RNG"); - let sig = rsk.sign( - &data_to_be_signed, - &mut rng, - FixedGenerators::SpendingKeyGenerator, - &JUBJUB, - ); - - // Write out the signature - sig.write(&mut (unsafe { &mut *result })[..]) - .expect("result should be 64 bytes"); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_binding_sig( - ctx: *const SaplingProvingContext, - value_balance: int64_t, - sighash: *const [c_uchar; 32], - result: *mut [c_uchar; 64], -) -> bool { - // Sign - let sig = match unsafe { &*ctx }.binding_sig(value_balance, unsafe { &*sighash }, &JUBJUB) { - Ok(s) => s, - Err(_) => return false, - }; - - // Write out signature - sig.write(&mut (unsafe { &mut *result })[..]) - .expect("result should be 64 bytes"); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_spend_proof( - ctx: *mut SaplingProvingContext, - ak: *const [c_uchar; 32], - nsk: *const [c_uchar; 32], - diversifier: *const [c_uchar; 11], - rcm: *const [c_uchar; 32], - ar: *const [c_uchar; 32], - value: uint64_t, - anchor: *const [c_uchar; 32], - witness: *const [c_uchar; 1 + 33 * SAPLING_TREE_DEPTH + 8], - cv: *mut [c_uchar; 32], - rk_out: *mut [c_uchar; 32], - zkproof: *mut [c_uchar; GROTH_PROOF_SIZE], -) -> bool { - // Grab `ak` from the caller, which should be a point. - let ak = match edwards::Point::::read(&(unsafe { &*ak })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - // `ak` should be prime order. - let ak = match ak.as_prime_order(&JUBJUB) { - Some(p) => p, - None => return false, - }; - - // Grab `nsk` from the caller - let nsk = match Fs::from_repr(read_fs(&(unsafe { &*nsk })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - // Construct the proof generation key - let proof_generation_key = ProofGenerationKey { - ak: ak.clone(), - nsk, - }; - - // Grab the diversifier from the caller - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); - - // The caller chooses the note randomness - let rcm = match Fs::from_repr(read_fs(&(unsafe { &*rcm })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - // The caller also chooses the re-randomization of ak - let ar = match Fs::from_repr(read_fs(&(unsafe { &*ar })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - // We need to compute the anchor of the Spend. - let anchor = match Fr::from_repr(read_le(unsafe { &(&*anchor)[..] })) { - Ok(p) => p, - Err(_) => return false, - }; - - // The witness contains the incremental tree witness information, in a - // weird serialized format. - let witness = match CommitmentTreeWitness::from_slice(unsafe { &(&*witness)[..] }) { - Ok(w) => w, - Err(_) => return false, - }; - - // Create proof - let (proof, value_commitment, rk) = unsafe { &mut *ctx } - .spend_proof( - proof_generation_key, - diversifier, - rcm, - ar, - value, - anchor, - witness, - unsafe { SAPLING_SPEND_PARAMS.as_ref() }.unwrap(), - unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap(), - &JUBJUB, - ) - .expect("proving should not fail"); - - // Write value commitment to caller - value_commitment - .write(&mut unsafe { &mut *cv }[..]) - .expect("should be able to serialize cv"); - - // Write proof out to caller - proof - .write(&mut (unsafe { &mut *zkproof })[..]) - .expect("should be able to serialize a proof"); - - // Write out `rk` to the caller - rk.write(&mut unsafe { &mut *rk_out }[..]) - .expect("should be able to write to rk_out"); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_proving_ctx_init() -> *mut SaplingProvingContext { - let ctx = Box::new(SaplingProvingContext::new()); - - Box::into_raw(ctx) -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_proving_ctx_free(ctx: *mut SaplingProvingContext) { - drop(unsafe { Box::from_raw(ctx) }); -} - -#[no_mangle] -pub extern "system" fn librustzcash_zip32_xsk_master( - seed: *const c_uchar, - seedlen: size_t, - xsk_master: *mut [c_uchar; 169], -) { - let seed = unsafe { std::slice::from_raw_parts(seed, seedlen) }; - - let xsk = zip32::ExtendedSpendingKey::master(seed); - - xsk.write(&mut (unsafe { &mut *xsk_master })[..]) - .expect("should be able to serialize an ExtendedSpendingKey"); -} - -#[no_mangle] -pub extern "system" fn librustzcash_zip32_xsk_derive( - xsk_parent: *const [c_uchar; 169], - i: uint32_t, - xsk_i: *mut [c_uchar; 169], -) { - let xsk_parent = zip32::ExtendedSpendingKey::read(&unsafe { *xsk_parent }[..]) - .expect("valid ExtendedSpendingKey"); - let i = zip32::ChildIndex::from_index(i); - - let xsk = xsk_parent.derive_child(i); - - xsk.write(&mut (unsafe { &mut *xsk_i })[..]) - .expect("should be able to serialize an ExtendedSpendingKey"); -} - -#[no_mangle] -pub extern "system" fn librustzcash_zip32_xfvk_derive( - xfvk_parent: *const [c_uchar; 169], - i: uint32_t, - xfvk_i: *mut [c_uchar; 169], -) -> bool { - let xfvk_parent = zip32::ExtendedFullViewingKey::read(&unsafe { *xfvk_parent }[..]) - .expect("valid ExtendedFullViewingKey"); - let i = zip32::ChildIndex::from_index(i); - - let xfvk = match xfvk_parent.derive_child(i) { - Ok(xfvk) => xfvk, - Err(_) => return false, - }; - - xfvk.write(&mut (unsafe { &mut *xfvk_i })[..]) - .expect("should be able to serialize an ExtendedFullViewingKey"); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_zip32_xfvk_address( - xfvk: *const [c_uchar; 169], - j: *const [c_uchar; 11], - j_ret: *mut [c_uchar; 11], - addr_ret: *mut [c_uchar; 43], -) -> bool { - let xfvk = zip32::ExtendedFullViewingKey::read(&unsafe { *xfvk }[..]) - .expect("valid ExtendedFullViewingKey"); - let j = zip32::DiversifierIndex(unsafe { *j }); - - let addr = match xfvk.address(j) { - Ok(addr) => addr, - Err(_) => return false, - }; - - let j_ret = unsafe { &mut *j_ret }; - let addr_ret = unsafe { &mut *addr_ret }; - - j_ret.copy_from_slice(&(addr.0).0); - addr_ret - .get_mut(..11) - .unwrap() - .copy_from_slice(&addr.1.diversifier.0); - addr.1 - .pk_d - .write(addr_ret.get_mut(11..).unwrap()) - .expect("should be able to serialize a PaymentAddress"); - - true -} diff --git a/librustzcash/src/tests/key_agreement.rs b/librustzcash/src/tests/key_agreement.rs deleted file mode 100644 index 01657d1..0000000 --- a/librustzcash/src/tests/key_agreement.rs +++ /dev/null @@ -1,74 +0,0 @@ -use pairing::bls12_381::Bls12; -use pairing::{PrimeField, PrimeFieldRepr}; -use rand::{OsRng, Rng}; -use sapling_crypto::jubjub::{edwards, JubjubBls12}; -use sapling_crypto::primitives::{Diversifier, ViewingKey}; - -use { - librustzcash_sapling_generate_r, librustzcash_sapling_ka_agree, - librustzcash_sapling_ka_derivepublic, -}; - -#[test] -fn test_key_agreement() { - let params = JubjubBls12::new(); - let mut rng = OsRng::new().unwrap(); - - // Create random viewing key - let vk = ViewingKey:: { - ak: edwards::Point::rand(&mut rng, ¶ms).mul_by_cofactor(¶ms), - nk: edwards::Point::rand(&mut rng, ¶ms).mul_by_cofactor(¶ms), - }; - - // Create a random address with the viewing key - let addr = loop { - match vk.into_payment_address(Diversifier(rng.gen()), ¶ms) { - Some(a) => break a, - None => {} - } - }; - - // Grab ivk from our viewing key in serialized form - let ivk = vk.ivk(); - let mut ivk_serialized = [0u8; 32]; - ivk.into_repr().write_le(&mut ivk_serialized[..]).unwrap(); - - // Create random esk - let mut esk = [0u8; 32]; - librustzcash_sapling_generate_r(&mut esk); - - // The sender will create a shared secret with the recipient - // by multiplying the pk_d from their address with the esk - // we randomly generated - let mut shared_secret_sender = [0u8; 32]; - - // Serialize pk_d for the call to librustzcash_sapling_ka_agree - let mut addr_pk_d = [0u8; 32]; - addr.pk_d.write(&mut addr_pk_d[..]).unwrap(); - - assert!(librustzcash_sapling_ka_agree( - &addr_pk_d, - &esk, - &mut shared_secret_sender - )); - - // Create epk for the recipient, placed in the transaction. Computed - // using the diversifier and esk. - let mut epk = [0u8; 32]; - assert!(librustzcash_sapling_ka_derivepublic( - &addr.diversifier.0, - &esk, - &mut epk - )); - - // Create sharedSecret with ephemeral key - let mut shared_secret_recipient = [0u8; 32]; - assert!(librustzcash_sapling_ka_agree( - &epk, - &ivk_serialized, - &mut shared_secret_recipient - )); - - assert!(!shared_secret_sender.iter().all(|&v| v == 0)); - assert_eq!(shared_secret_sender, shared_secret_recipient); -} diff --git a/librustzcash/src/tests/key_components.rs b/librustzcash/src/tests/key_components.rs deleted file mode 100644 index d63c4d4..0000000 --- a/librustzcash/src/tests/key_components.rs +++ /dev/null @@ -1,666 +0,0 @@ -use pairing::{bls12_381::Bls12, PrimeField, PrimeFieldRepr}; -use sapling_crypto::{ - jubjub::{fs::FsRepr, FixedGenerators, JubjubEngine, JubjubParams}, - primitives::{Diversifier, ProofGenerationKey}, -}; - -use super::JUBJUB; - -use { - librustzcash_ask_to_ak, librustzcash_check_diversifier, librustzcash_crh_ivk, - librustzcash_ivk_to_pkd, librustzcash_nsk_to_nk, -}; - -#[test] -fn key_components() { - #![allow(dead_code)] - struct TestVector { - sk: [u8; 32], - ask: [u8; 32], - nsk: [u8; 32], - ovk: [u8; 32], - ak: [u8; 32], - nk: [u8; 32], - ivk: [u8; 32], - default_d: [u8; 11], - default_pk_d: [u8; 32], - note_v: u64, - note_r: [u8; 32], - note_cm: [u8; 32], - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_key_components.py - let test_vectors = vec![ - TestVector { - sk: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - ask: [ - 0x85, 0x48, 0xa1, 0x4a, 0x47, 0x3e, 0xa5, 0x47, 0xaa, 0x23, 0x78, 0x40, 0x20, 0x44, - 0xf8, 0x18, 0xcf, 0x19, 0x11, 0xcf, 0x5d, 0xd2, 0x05, 0x4f, 0x67, 0x83, 0x45, 0xf0, - 0x0d, 0x0e, 0x88, 0x06, - ], - nsk: [ - 0x30, 0x11, 0x4e, 0xa0, 0xdd, 0x0b, 0xb6, 0x1c, 0xf0, 0xea, 0xea, 0xb6, 0xec, 0x33, - 0x31, 0xf5, 0x81, 0xb0, 0x42, 0x5e, 0x27, 0x33, 0x85, 0x01, 0x26, 0x2d, 0x7e, 0xac, - 0x74, 0x5e, 0x6e, 0x05, - ], - ovk: [ - 0x98, 0xd1, 0x69, 0x13, 0xd9, 0x9b, 0x04, 0x17, 0x7c, 0xab, 0xa4, 0x4f, 0x6e, 0x4d, - 0x22, 0x4e, 0x03, 0xb5, 0xac, 0x03, 0x1d, 0x7c, 0xe4, 0x5e, 0x86, 0x51, 0x38, 0xe1, - 0xb9, 0x96, 0xd6, 0x3b, - ], - ak: [ - 0xf3, 0x44, 0xec, 0x38, 0x0f, 0xe1, 0x27, 0x3e, 0x30, 0x98, 0xc2, 0x58, 0x8c, 0x5d, - 0x3a, 0x79, 0x1f, 0xd7, 0xba, 0x95, 0x80, 0x32, 0x76, 0x07, 0x77, 0xfd, 0x0e, 0xfa, - 0x8e, 0xf1, 0x16, 0x20, - ], - nk: [ - 0xf7, 0xcf, 0x9e, 0x77, 0xf2, 0xe5, 0x86, 0x83, 0x38, 0x3c, 0x15, 0x19, 0xac, 0x7b, - 0x06, 0x2d, 0x30, 0x04, 0x0e, 0x27, 0xa7, 0x25, 0xfb, 0x88, 0xfb, 0x19, 0xa9, 0x78, - 0xbd, 0x3f, 0xd6, 0xba, - ], - ivk: [ - 0xb7, 0x0b, 0x7c, 0xd0, 0xed, 0x03, 0xcb, 0xdf, 0xd7, 0xad, 0xa9, 0x50, 0x2e, 0xe2, - 0x45, 0xb1, 0x3e, 0x56, 0x9d, 0x54, 0xa5, 0x71, 0x9d, 0x2d, 0xaa, 0x0f, 0x5f, 0x14, - 0x51, 0x47, 0x92, 0x04, - ], - default_d: [ - 0xf1, 0x9d, 0x9b, 0x79, 0x7e, 0x39, 0xf3, 0x37, 0x44, 0x58, 0x39, - ], - default_pk_d: [ - 0xdb, 0x4c, 0xd2, 0xb0, 0xaa, 0xc4, 0xf7, 0xeb, 0x8c, 0xa1, 0x31, 0xf1, 0x65, 0x67, - 0xc4, 0x45, 0xa9, 0x55, 0x51, 0x26, 0xd3, 0xc2, 0x9f, 0x14, 0xe3, 0xd7, 0x76, 0xe8, - 0x41, 0xae, 0x74, 0x15, - ], - note_v: 0, - note_r: [ - 0x39, 0x17, 0x6d, 0xac, 0x39, 0xac, 0xe4, 0x98, 0x0e, 0xcc, 0x8d, 0x77, 0x8e, 0x89, - 0x86, 0x02, 0x55, 0xec, 0x36, 0x15, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - note_cm: [ - 0xcb, 0x3c, 0xf9, 0x15, 0x32, 0x70, 0xd5, 0x7e, 0xb9, 0x14, 0xc6, 0xc2, 0xbc, 0xc0, - 0x18, 0x50, 0xc9, 0xfe, 0xd4, 0x4f, 0xce, 0x08, 0x06, 0x27, 0x8f, 0x08, 0x3e, 0xf2, - 0xdd, 0x07, 0x64, 0x39, - ], - }, - TestVector { - sk: [ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, - ], - ask: [ - 0xc9, 0x43, 0x56, 0x29, 0xbf, 0x8b, 0xff, 0xe5, 0x5e, 0x73, 0x35, 0xec, 0x07, 0x77, - 0x18, 0xba, 0x60, 0xba, 0x28, 0xd7, 0xac, 0x37, 0x94, 0xb7, 0x4f, 0x51, 0x2c, 0x31, - 0xaf, 0x0a, 0x53, 0x04, - ], - nsk: [ - 0x11, 0xac, 0xc2, 0xea, 0xd0, 0x7b, 0x5f, 0x00, 0x8c, 0x1f, 0x0f, 0x09, 0x0c, 0xc8, - 0xdd, 0xf3, 0x35, 0x23, 0x6f, 0xf4, 0xb2, 0x53, 0xc6, 0x49, 0x56, 0x95, 0xe9, 0xd6, - 0x39, 0xda, 0xcd, 0x08, - ], - ovk: [ - 0x3b, 0x94, 0x62, 0x10, 0xce, 0x6d, 0x1b, 0x16, 0x92, 0xd7, 0x39, 0x2a, 0xc8, 0x4a, - 0x8b, 0xc8, 0xf0, 0x3b, 0x72, 0x72, 0x3c, 0x7d, 0x36, 0x72, 0x1b, 0x80, 0x9a, 0x79, - 0xc9, 0xd6, 0xe4, 0x5b, - ], - ak: [ - 0x82, 0xff, 0x5e, 0xff, 0xc5, 0x27, 0xae, 0x84, 0x02, 0x0b, 0xf2, 0xd3, 0x52, 0x01, - 0xc1, 0x02, 0x19, 0x13, 0x19, 0x47, 0xff, 0x4b, 0x96, 0xf8, 0x81, 0xa4, 0x5f, 0x2e, - 0x8a, 0xe3, 0x05, 0x18, - ], - nk: [ - 0xc4, 0x53, 0x4d, 0x84, 0x8b, 0xb9, 0x18, 0xcf, 0x4a, 0x7f, 0x8b, 0x98, 0x74, 0x0a, - 0xb3, 0xcc, 0xee, 0x58, 0x67, 0x95, 0xff, 0x4d, 0xf6, 0x45, 0x47, 0xa8, 0x88, 0x8a, - 0x6c, 0x74, 0x15, 0xd2, - ], - ivk: [ - 0xc5, 0x18, 0x38, 0x44, 0x66, 0xb2, 0x69, 0x88, 0xb5, 0x10, 0x90, 0x67, 0x41, 0x8d, - 0x19, 0x2d, 0x9d, 0x6b, 0xd0, 0xd9, 0x23, 0x22, 0x05, 0xd7, 0x74, 0x18, 0xc2, 0x40, - 0xfc, 0x68, 0xa4, 0x06, - ], - default_d: [ - 0xae, 0xf1, 0x80, 0xf6, 0xe3, 0x4e, 0x35, 0x4b, 0x88, 0x8f, 0x81, - ], - default_pk_d: [ - 0xa6, 0xb1, 0x3e, 0xa3, 0x36, 0xdd, 0xb7, 0xa6, 0x7b, 0xb0, 0x9a, 0x0e, 0x68, 0xe9, - 0xd3, 0xcf, 0xb3, 0x92, 0x10, 0x83, 0x1e, 0xa3, 0xa2, 0x96, 0xba, 0x09, 0xa9, 0x22, - 0x06, 0x0f, 0xd3, 0x8b, - ], - note_v: 12227227834928555328, - note_r: [ - 0x47, 0x8b, 0xa0, 0xee, 0x6e, 0x1a, 0x75, 0xb6, 0x00, 0x03, 0x6f, 0x26, 0xf1, 0x8b, - 0x70, 0x15, 0xab, 0x55, 0x6b, 0xed, 0xdf, 0x8b, 0x96, 0x02, 0x38, 0x86, 0x9f, 0x89, - 0xdd, 0x80, 0x4e, 0x06, - ], - note_cm: [ - 0xb5, 0x78, 0x93, 0x50, 0x0b, 0xfb, 0x85, 0xdf, 0x2e, 0x8b, 0x01, 0xac, 0x45, 0x2f, - 0x89, 0xe1, 0x0e, 0x26, 0x6b, 0xcf, 0xa3, 0x1c, 0x31, 0xb2, 0x9a, 0x53, 0xae, 0x72, - 0xca, 0xd4, 0x69, 0x50, - ], - }, - TestVector { - sk: [ - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, - ], - ask: [ - 0xee, 0x1c, 0x3d, 0x7e, 0xfe, 0x0a, 0x78, 0x06, 0x3d, 0x6a, 0xf3, 0xd9, 0xd8, 0x12, - 0x12, 0xaf, 0x47, 0xb7, 0xc1, 0xb7, 0x61, 0xf8, 0x5c, 0xcb, 0x06, 0x6f, 0xc1, 0x1a, - 0x6a, 0x42, 0x17, 0x03, - ], - nsk: [ - 0x1d, 0x3b, 0x71, 0x37, 0x55, 0xd7, 0x48, 0x75, 0xe8, 0xea, 0x38, 0xfd, 0x16, 0x6e, - 0x76, 0xc6, 0x2a, 0x42, 0x50, 0x21, 0x6e, 0x6b, 0xbf, 0xe4, 0x8a, 0x5e, 0x2e, 0xab, - 0xad, 0x11, 0x7f, 0x0b, - ], - ovk: [ - 0x8b, 0xf4, 0x39, 0x0e, 0x28, 0xdd, 0xc9, 0x5b, 0x83, 0x02, 0xc3, 0x81, 0xd5, 0x81, - 0x0b, 0x84, 0xba, 0x8e, 0x60, 0x96, 0xe5, 0xa7, 0x68, 0x22, 0x77, 0x4f, 0xd4, 0x9f, - 0x49, 0x1e, 0x8f, 0x49, - ], - ak: [ - 0xab, 0x83, 0x57, 0x4e, 0xb5, 0xde, 0x85, 0x9a, 0x0a, 0xb8, 0x62, 0x9d, 0xec, 0x34, - 0xc7, 0xbe, 0xe8, 0xc3, 0xfc, 0x74, 0xdf, 0xa0, 0xb1, 0x9a, 0x3a, 0x74, 0x68, 0xd1, - 0x5d, 0xca, 0x64, 0xc6, - ], - nk: [ - 0x95, 0xd5, 0x80, 0x53, 0xe0, 0x59, 0x2e, 0x4a, 0x16, 0x9c, 0xc0, 0xb7, 0x92, 0x8a, - 0xaa, 0xc3, 0xde, 0x24, 0xef, 0x15, 0x31, 0xaa, 0x9e, 0xb6, 0xf4, 0xab, 0x93, 0x91, - 0x4d, 0xa8, 0xa0, 0x6e, - ], - ivk: [ - 0x47, 0x1c, 0x24, 0xa3, 0xdc, 0x87, 0x30, 0xe7, 0x50, 0x36, 0xc0, 0xa9, 0x5f, 0x3e, - 0x2f, 0x7d, 0xd1, 0xbe, 0x6f, 0xb9, 0x3a, 0xd2, 0x95, 0x92, 0x20, 0x3d, 0xef, 0x30, - 0x41, 0x95, 0x45, 0x05, - ], - default_d: [ - 0x75, 0x99, 0xf0, 0xbf, 0x9b, 0x57, 0xcd, 0x2d, 0xc2, 0x99, 0xb6, - ], - default_pk_d: [ - 0x66, 0x14, 0x17, 0x39, 0x51, 0x4b, 0x28, 0xf0, 0x5d, 0xef, 0x8a, 0x18, 0xee, 0xee, - 0x5e, 0xed, 0x4d, 0x44, 0xc6, 0x22, 0x5c, 0x3c, 0x65, 0xd8, 0x8d, 0xd9, 0x90, 0x77, - 0x08, 0x01, 0x2f, 0x5a, - ], - note_v: 6007711596147559040, - note_r: [ - 0x14, 0x7c, 0xf2, 0xb5, 0x1b, 0x4c, 0x7c, 0x63, 0xcb, 0x77, 0xb9, 0x9e, 0x8b, 0x78, - 0x3e, 0x5b, 0x51, 0x11, 0xdb, 0x0a, 0x7c, 0xa0, 0x4d, 0x6c, 0x01, 0x4a, 0x1d, 0x7d, - 0xa8, 0x3b, 0xae, 0x0a, - ], - note_cm: [ - 0xdb, 0x85, 0xa7, 0x0a, 0x98, 0x43, 0x7f, 0x73, 0x16, 0x7f, 0xc3, 0x32, 0xd5, 0xb7, - 0xb7, 0x40, 0x82, 0x96, 0x66, 0x17, 0x70, 0xb1, 0x01, 0xb0, 0xaa, 0x87, 0x83, 0x9f, - 0x4e, 0x55, 0xf1, 0x51, - ], - }, - TestVector { - sk: [ - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, - ], - ask: [ - 0x00, 0xc3, 0xa1, 0xe1, 0xca, 0x8f, 0x4e, 0x04, 0x80, 0xee, 0x1e, 0xe9, 0x0c, 0xa7, - 0x51, 0x78, 0x79, 0xd3, 0xfc, 0x5c, 0x81, 0x5c, 0x09, 0x03, 0xe5, 0xee, 0xbc, 0x94, - 0xbb, 0x80, 0x95, 0x03, - ], - nsk: [ - 0xe6, 0x62, 0x85, 0xa5, 0xe9, 0xb6, 0x5e, 0x15, 0x7a, 0xd2, 0xfc, 0xd5, 0x43, 0xda, - 0xd9, 0x8c, 0x67, 0xa5, 0x8a, 0xbd, 0xf2, 0x87, 0xe0, 0x55, 0x06, 0xbd, 0x1c, 0x2e, - 0x59, 0xb0, 0x72, 0x0b, - ], - ovk: [ - 0x14, 0x76, 0x78, 0xe0, 0x55, 0x3b, 0x97, 0x82, 0x93, 0x47, 0x64, 0x7c, 0x5b, 0xc7, - 0xda, 0xb4, 0xcc, 0x22, 0x02, 0xb5, 0x4e, 0xc2, 0x9f, 0xd3, 0x1a, 0x3d, 0xe6, 0xbe, - 0x08, 0x25, 0xfc, 0x5e, - ], - ak: [ - 0x3c, 0x9c, 0xde, 0x7e, 0x5d, 0x0d, 0x38, 0xa8, 0x61, 0x0f, 0xaa, 0xdb, 0xcf, 0x4c, - 0x34, 0x3f, 0x5d, 0x3c, 0xfa, 0x31, 0x55, 0xa5, 0xb9, 0x46, 0x61, 0xa6, 0x75, 0x3e, - 0x96, 0xe8, 0x84, 0xea, - ], - nk: [ - 0xb7, 0x7d, 0x36, 0xf5, 0x08, 0x94, 0x1d, 0xbd, 0x61, 0xcf, 0xd0, 0xf1, 0x59, 0xee, - 0x05, 0xcf, 0xaa, 0x78, 0xa2, 0x6c, 0x94, 0x92, 0x90, 0x38, 0x06, 0xd8, 0x3b, 0x59, - 0x8d, 0x3c, 0x1c, 0x2a, - ], - ivk: [ - 0x63, 0x6a, 0xa9, 0x64, 0xbf, 0xc2, 0x3c, 0xe4, 0xb1, 0xfc, 0xf7, 0xdf, 0xc9, 0x91, - 0x79, 0xdd, 0xc4, 0x06, 0xff, 0x55, 0x40, 0x0c, 0x92, 0x95, 0xac, 0xfc, 0x14, 0xf0, - 0x31, 0xc7, 0x26, 0x00, - ], - default_d: [ - 0x1b, 0x81, 0x61, 0x4f, 0x1d, 0xad, 0xea, 0x0f, 0x8d, 0x0a, 0x58, - ], - default_pk_d: [ - 0x25, 0xeb, 0x55, 0xfc, 0xcf, 0x76, 0x1f, 0xc6, 0x4e, 0x85, 0xa5, 0x88, 0xef, 0xe6, - 0xea, 0xd7, 0x83, 0x2f, 0xb1, 0xf0, 0xf7, 0xa8, 0x31, 0x65, 0x89, 0x5b, 0xdf, 0xf9, - 0x42, 0x92, 0x5f, 0x5c, - ], - note_v: 18234939431076114368, - note_r: [ - 0x34, 0xa4, 0xb2, 0xa9, 0x14, 0x4f, 0xf5, 0xea, 0x54, 0xef, 0xee, 0x87, 0xcf, 0x90, - 0x1b, 0x5b, 0xed, 0x5e, 0x35, 0xd2, 0x1f, 0xbb, 0xd7, 0x88, 0xd5, 0xbd, 0x9d, 0x83, - 0x3e, 0x11, 0x28, 0x04, - ], - note_cm: [ - 0xe0, 0x8c, 0xe4, 0x82, 0xb3, 0xa8, 0xfb, 0x3b, 0x35, 0xcc, 0xdb, 0xe3, 0x43, 0x37, - 0xbd, 0x10, 0x5d, 0x88, 0x39, 0x21, 0x2e, 0x0d, 0x16, 0x44, 0xb9, 0xd5, 0x5c, 0xaa, - 0x60, 0xd1, 0x9b, 0x6c, - ], - }, - TestVector { - sk: [ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, - ], - ask: [ - 0x82, 0x36, 0xd1, 0x9d, 0x32, 0x05, 0xd8, 0x55, 0x43, 0xa0, 0x68, 0x11, 0x34, 0x3f, - 0x82, 0x7b, 0x65, 0x63, 0x77, 0x0a, 0x49, 0xaa, 0x4d, 0x0c, 0xa0, 0x08, 0x18, 0x05, - 0xd4, 0xc8, 0xea, 0x0d, - ], - nsk: [ - 0x7e, 0xc1, 0xef, 0x0b, 0xed, 0x82, 0x71, 0x82, 0x72, 0xf0, 0xf4, 0x4f, 0x01, 0x7c, - 0x48, 0x41, 0x74, 0x51, 0x3d, 0x66, 0x1d, 0xd1, 0x68, 0xaf, 0x02, 0xd2, 0x09, 0x2a, - 0x1d, 0x8a, 0x05, 0x07, - ], - ovk: [ - 0x1b, 0x6e, 0x75, 0xec, 0xe3, 0xac, 0xe8, 0xdb, 0xa6, 0xa5, 0x41, 0x0d, 0x9a, 0xd4, - 0x75, 0x56, 0x68, 0xe4, 0xb3, 0x95, 0x85, 0xd6, 0x35, 0xec, 0x1d, 0xa7, 0xc8, 0xdc, - 0xfd, 0x5f, 0xc4, 0xed, - ], - ak: [ - 0x55, 0xe8, 0x83, 0x89, 0xbb, 0x7e, 0x41, 0xde, 0x13, 0x0c, 0xfa, 0x51, 0xa8, 0x71, - 0x5f, 0xde, 0x01, 0xff, 0x9c, 0x68, 0x76, 0x64, 0x7f, 0x01, 0x75, 0xad, 0x34, 0xf0, - 0x58, 0xdd, 0xe0, 0x1a, - ], - nk: [ - 0x72, 0x5d, 0x4a, 0xd6, 0xa1, 0x50, 0x21, 0xcd, 0x1c, 0x48, 0xc5, 0xee, 0x19, 0xde, - 0x6c, 0x1e, 0x76, 0x8a, 0x2c, 0xc0, 0xa9, 0xa7, 0x30, 0xa0, 0x1b, 0xb2, 0x1c, 0x95, - 0xe3, 0xd9, 0xe4, 0x3c, - ], - ivk: [ - 0x67, 0xfa, 0x2b, 0xf7, 0xc6, 0x7d, 0x46, 0x58, 0x24, 0x3c, 0x31, 0x7c, 0x0c, 0xb4, - 0x1f, 0xd3, 0x20, 0x64, 0xdf, 0xd3, 0x70, 0x9f, 0xe0, 0xdc, 0xb7, 0x24, 0xf1, 0x4b, - 0xb0, 0x1a, 0x1d, 0x04, - ], - default_d: [ - 0xfc, 0xfb, 0x68, 0xa4, 0x0d, 0x4b, 0xc6, 0xa0, 0x4b, 0x09, 0xc4, - ], - default_pk_d: [ - 0x8b, 0x2a, 0x33, 0x7f, 0x03, 0x62, 0x2c, 0x24, 0xff, 0x38, 0x1d, 0x4c, 0x54, 0x6f, - 0x69, 0x77, 0xf9, 0x05, 0x22, 0xe9, 0x2f, 0xde, 0x44, 0xc9, 0xd1, 0xbb, 0x09, 0x97, - 0x14, 0xb9, 0xdb, 0x2b, - ], - note_v: 12015423192295118080, - note_r: [ - 0xe5, 0x57, 0x85, 0x13, 0x55, 0x74, 0x7c, 0x09, 0xac, 0x59, 0x01, 0x3c, 0xbd, 0xe8, - 0x59, 0x80, 0x96, 0x4e, 0xc1, 0x84, 0x4d, 0x9c, 0x69, 0x67, 0xca, 0x0c, 0x02, 0x9c, - 0x84, 0x57, 0xbb, 0x04, - ], - note_cm: [ - 0xbd, 0xc8, 0x54, 0xbf, 0x3e, 0x7b, 0x00, 0x82, 0x1f, 0x3b, 0x8b, 0x85, 0x23, 0x8c, - 0xcf, 0x1e, 0x67, 0x15, 0xbf, 0xe7, 0x0b, 0x63, 0x2d, 0x04, 0x4b, 0x26, 0xfb, 0x2b, - 0xc7, 0x1b, 0x7f, 0x36, - ], - }, - TestVector { - sk: [ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, - ], - ask: [ - 0xea, 0xe6, 0x88, 0x4d, 0x76, 0x4a, 0x05, 0x40, 0x61, 0xa8, 0xf1, 0xc0, 0x07, 0x6c, - 0x62, 0x4d, 0xcb, 0x73, 0x87, 0x89, 0xf7, 0xad, 0x1e, 0x74, 0x08, 0xe3, 0x1f, 0x24, - 0xdf, 0xc8, 0x26, 0x07, - ], - nsk: [ - 0xfb, 0xe6, 0x10, 0xf4, 0x2a, 0x41, 0x74, 0x9f, 0x9b, 0x6e, 0x6e, 0x4a, 0x54, 0xb5, - 0xa3, 0x2e, 0xbf, 0xe8, 0xf4, 0x38, 0x00, 0x88, 0x1b, 0xa6, 0xcd, 0x13, 0xed, 0x0b, - 0x05, 0x29, 0x46, 0x01, - ], - ovk: [ - 0xc6, 0xbc, 0x1f, 0x39, 0xf0, 0xd7, 0x86, 0x31, 0x4c, 0xb2, 0x0b, 0xf9, 0xab, 0x22, - 0x85, 0x40, 0x91, 0x35, 0x55, 0xf9, 0x70, 0x69, 0x6b, 0x6d, 0x7c, 0x77, 0xbb, 0x33, - 0x23, 0x28, 0x37, 0x2a, - ], - ak: [ - 0xe6, 0x82, 0x76, 0x59, 0x14, 0xe3, 0x86, 0x4c, 0x33, 0x9e, 0x57, 0x82, 0xb8, 0x55, - 0xc0, 0xfd, 0xf4, 0x0e, 0x0d, 0xfc, 0xed, 0xb9, 0xe7, 0xb4, 0x7b, 0xc9, 0x4b, 0x90, - 0xb3, 0xa4, 0xc9, 0x88, - ], - nk: [ - 0x82, 0x25, 0x6b, 0x95, 0x62, 0x3c, 0x67, 0x02, 0x4b, 0x44, 0x24, 0xd9, 0x14, 0x00, - 0xa3, 0x70, 0xe7, 0xac, 0x8e, 0x4d, 0x15, 0x48, 0x2a, 0x37, 0x59, 0xe0, 0x0d, 0x21, - 0x97, 0x49, 0xda, 0xee, - ], - ivk: [ - 0xea, 0x3f, 0x1d, 0x80, 0xe4, 0x30, 0x7c, 0xa7, 0x3b, 0x9f, 0x37, 0x80, 0x1f, 0x91, - 0xfb, 0xa8, 0x10, 0xcc, 0x41, 0xd2, 0x79, 0xfc, 0x29, 0xf5, 0x64, 0x23, 0x56, 0x54, - 0xa2, 0x17, 0x8e, 0x03, - ], - default_d: [ - 0xeb, 0x51, 0x98, 0x82, 0xad, 0x1e, 0x5c, 0xc6, 0x54, 0xcd, 0x59, - ], - default_pk_d: [ - 0x6b, 0x27, 0xda, 0xcc, 0xb5, 0xa8, 0x20, 0x7f, 0x53, 0x2d, 0x10, 0xca, 0x23, 0x8f, - 0x97, 0x86, 0x64, 0x8a, 0x11, 0xb5, 0x96, 0x6e, 0x51, 0xa2, 0xf7, 0xd8, 0x9e, 0x15, - 0xd2, 0x9b, 0x8f, 0xdf, - ], - note_v: 5795906953514121792, - note_r: [ - 0x68, 0xf0, 0x61, 0x04, 0x60, 0x6b, 0x0c, 0x54, 0x49, 0x84, 0x5f, 0xf4, 0xc6, 0x5f, - 0x73, 0xe9, 0x0f, 0x45, 0xef, 0x5a, 0x43, 0xc9, 0xd7, 0x4c, 0xb2, 0xc8, 0x5c, 0xf5, - 0x6c, 0x94, 0xc0, 0x02, - ], - note_cm: [ - 0xe8, 0x26, 0x7d, 0x30, 0xac, 0x11, 0xc1, 0x00, 0xbc, 0x7a, 0x0f, 0xdf, 0x91, 0xf7, - 0x1d, 0x74, 0xc5, 0xbc, 0xf2, 0xe1, 0xef, 0x95, 0x66, 0x90, 0x44, 0x73, 0x01, 0x69, - 0xde, 0x1a, 0x5b, 0x4c, - ], - }, - TestVector { - sk: [ - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, - ], - ask: [ - 0xe8, 0xf8, 0x16, 0xb4, 0xbc, 0x08, 0xa7, 0xe5, 0x66, 0x75, 0x0c, 0xc2, 0x8a, 0xfe, - 0x82, 0xa4, 0xce, 0xa9, 0xc2, 0xbe, 0xf2, 0x44, 0xfa, 0x4b, 0x13, 0xc4, 0x73, 0x9b, - 0x28, 0x07, 0x4c, 0x0d, - ], - nsk: [ - 0x32, 0x61, 0x5b, 0x13, 0x7f, 0x28, 0x01, 0xed, 0x44, 0x6e, 0x48, 0x78, 0x1a, 0xb0, - 0x63, 0x45, 0x72, 0xe1, 0x8c, 0xfb, 0x06, 0x93, 0x72, 0x1b, 0x88, 0x03, 0xc0, 0x5b, - 0x82, 0x27, 0xd1, 0x07, - ], - ovk: [ - 0xf6, 0x2c, 0x05, 0xe8, 0x48, 0xa8, 0x73, 0xef, 0x88, 0x5e, 0x12, 0xb0, 0x8c, 0x5e, - 0x7c, 0xa2, 0xf3, 0x24, 0x24, 0xba, 0xcc, 0x75, 0x4c, 0xb6, 0x97, 0x50, 0x44, 0x4d, - 0x35, 0x5f, 0x51, 0x06, - ], - ak: [ - 0xff, 0x27, 0xdb, 0x07, 0x51, 0x94, 0x5d, 0x3e, 0xe4, 0xbe, 0x9c, 0xf1, 0x5c, 0x2e, - 0xa2, 0x11, 0xb2, 0x4b, 0x16, 0x4d, 0x5f, 0x2d, 0x7d, 0xdf, 0xf5, 0xe4, 0xa0, 0x70, - 0x8f, 0x10, 0xb9, 0x5e, - ], - nk: [ - 0x94, 0x38, 0x85, 0x95, 0x9d, 0x4e, 0xf8, 0xa9, 0xcf, 0xca, 0x07, 0xc4, 0x57, 0xf0, - 0x9e, 0xc7, 0x4b, 0x96, 0xf9, 0x93, 0xd8, 0xe0, 0xfa, 0x32, 0xb1, 0x9c, 0x03, 0xe3, - 0xb0, 0x7a, 0x42, 0x0f, - ], - ivk: [ - 0xb5, 0xc5, 0x89, 0x49, 0x43, 0x95, 0x69, 0x33, 0xc0, 0xe5, 0xc1, 0x2d, 0x31, 0x1f, - 0xc1, 0x2c, 0xba, 0x58, 0x35, 0x4b, 0x5c, 0x38, 0x9e, 0xdc, 0x03, 0xda, 0x55, 0x08, - 0x4f, 0x74, 0xc2, 0x05, - ], - default_d: [ - 0xbe, 0xbb, 0x0f, 0xb4, 0x6b, 0x8a, 0xaf, 0xf8, 0x90, 0x40, 0xf6, - ], - default_pk_d: [ - 0xd1, 0x1d, 0xa0, 0x1f, 0x0b, 0x43, 0xbd, 0xd5, 0x28, 0x8d, 0x32, 0x38, 0x5b, 0x87, - 0x71, 0xd2, 0x23, 0x49, 0x3c, 0x69, 0x80, 0x25, 0x44, 0x04, 0x3f, 0x77, 0xcf, 0x1d, - 0x71, 0xc1, 0xcb, 0x8c, - ], - note_v: 18023134788442677120, - note_r: [ - 0x49, 0xf9, 0x0b, 0x47, 0xfd, 0x52, 0xfe, 0xe7, 0xc1, 0xc8, 0x1f, 0x0d, 0xcb, 0x5b, - 0x74, 0xc3, 0xfb, 0x9b, 0x3e, 0x03, 0x97, 0x6f, 0x8b, 0x75, 0x24, 0xea, 0xba, 0xd0, - 0x08, 0x89, 0x21, 0x07, - ], - note_cm: [ - 0x57, 0x2b, 0xa2, 0x05, 0x25, 0xb0, 0xac, 0x4d, 0x6d, 0xc0, 0x1a, 0xc2, 0xea, 0x10, - 0x90, 0xb6, 0xe0, 0xf2, 0xf4, 0xbf, 0x4e, 0xc4, 0xa0, 0xdb, 0x5b, 0xbc, 0xcb, 0x5b, - 0x78, 0x3a, 0x1e, 0x55, - ], - }, - TestVector { - sk: [ - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, - ], - ask: [ - 0x74, 0xb4, 0x4a, 0x37, 0xf1, 0x50, 0x23, 0xc0, 0x60, 0x42, 0x7e, 0x1d, 0xae, 0xa3, - 0xf6, 0x43, 0x12, 0xdd, 0x8f, 0xeb, 0x7b, 0x2c, 0xed, 0xf0, 0xdd, 0x55, 0x44, 0x49, - 0x3f, 0x87, 0x2c, 0x06, - ], - nsk: [ - 0x07, 0x5c, 0x35, 0xdb, 0x8b, 0x1b, 0x25, 0x75, 0x42, 0x23, 0xec, 0xee, 0x34, 0xab, - 0x73, 0x0d, 0xdd, 0xd1, 0xf1, 0x4a, 0x6a, 0x54, 0xf4, 0xc6, 0xf4, 0x68, 0x45, 0x3c, - 0x3c, 0x6e, 0xd6, 0x0b, - ], - ovk: [ - 0xe9, 0xe0, 0xdc, 0x1e, 0xd3, 0x11, 0xda, 0xed, 0x64, 0xbd, 0x74, 0xda, 0x5d, 0x94, - 0xfe, 0x88, 0xa6, 0xea, 0x41, 0x4b, 0x73, 0x12, 0xde, 0x3d, 0x2a, 0x78, 0xf6, 0x46, - 0x32, 0xbb, 0xe3, 0x73, - ], - ak: [ - 0x28, 0x3f, 0x9a, 0xaf, 0xa9, 0xbc, 0xb3, 0xe6, 0xce, 0x17, 0xe6, 0x32, 0x12, 0x63, - 0x4c, 0xb3, 0xee, 0x55, 0x0c, 0x47, 0x6b, 0x67, 0x6b, 0xd3, 0x56, 0xa6, 0xdf, 0x8a, - 0xdf, 0x51, 0xd2, 0x5e, - ], - nk: [ - 0xdc, 0x4c, 0x67, 0xb1, 0x0d, 0x4b, 0x0a, 0x21, 0x8d, 0xc6, 0xe1, 0x48, 0x70, 0x66, - 0x74, 0x0a, 0x40, 0x93, 0x17, 0x86, 0x6c, 0x32, 0xe6, 0x64, 0xb5, 0x0e, 0x39, 0x7a, - 0xa8, 0x03, 0x89, 0xd4, - ], - ivk: [ - 0x87, 0x16, 0xc8, 0x28, 0x80, 0xe1, 0x36, 0x83, 0xe1, 0xbb, 0x05, 0x9d, 0xd0, 0x6c, - 0x80, 0xc9, 0x01, 0x34, 0xa9, 0x6d, 0x5a, 0xfc, 0xa8, 0xaa, 0xc2, 0xbb, 0xf6, 0x8b, - 0xb0, 0x5f, 0x84, 0x02, - ], - default_d: [ - 0xad, 0x6e, 0x2e, 0x18, 0x5a, 0x31, 0x00, 0xe3, 0xa6, 0xa8, 0xb3, - ], - default_pk_d: [ - 0x32, 0xcb, 0x28, 0x06, 0xb8, 0x82, 0xf1, 0x36, 0x8b, 0x0d, 0x4a, 0x89, 0x8f, 0x72, - 0xc4, 0xc8, 0xf7, 0x28, 0x13, 0x2c, 0xc1, 0x24, 0x56, 0x94, 0x6e, 0x7f, 0x4c, 0xb0, - 0xfb, 0x05, 0x8d, 0xa9, - ], - note_v: 11803618549661680832, - note_r: [ - 0x51, 0x65, 0xaf, 0xf2, 0x2d, 0xd4, 0xed, 0x56, 0xb4, 0xd8, 0x1d, 0x1f, 0x17, 0x1c, - 0xc3, 0xd6, 0x43, 0x2f, 0xed, 0x1b, 0xeb, 0xf2, 0x0a, 0x7b, 0xea, 0xb1, 0x2d, 0xb1, - 0x42, 0xf9, 0x4a, 0x0c, - ], - note_cm: [ - 0xab, 0x7f, 0xc5, 0x66, 0x87, 0x3c, 0xcd, 0xe6, 0x71, 0xf5, 0x98, 0x27, 0x67, 0x85, - 0x60, 0xa0, 0x06, 0xf8, 0x2b, 0xb7, 0xad, 0xcd, 0x75, 0x22, 0x3f, 0xa8, 0x59, 0x36, - 0xf7, 0x8c, 0x2b, 0x23, - ], - }, - TestVector { - sk: [ - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, - ], - ask: [ - 0x03, 0x9d, 0xd9, 0x3d, 0xf3, 0x11, 0xff, 0x8f, 0xba, 0xb3, 0xfe, 0x23, 0x02, 0x19, - 0xcd, 0x42, 0xac, 0x87, 0x94, 0x84, 0xf3, 0x0b, 0x90, 0x3a, 0x3c, 0x1e, 0x67, 0xcc, - 0xca, 0x5a, 0x7b, 0x0d, - ], - nsk: [ - 0x04, 0x9f, 0xa1, 0x4f, 0x48, 0x6c, 0x75, 0xb9, 0xfa, 0xd7, 0xe3, 0xb6, 0x73, 0xa4, - 0x43, 0xdd, 0x07, 0x4e, 0xaa, 0x96, 0xed, 0xcb, 0x2a, 0x53, 0xea, 0xaa, 0xbd, 0xaf, - 0x70, 0xff, 0xbb, 0x08, - ], - ovk: [ - 0x14, 0x7d, 0xd1, 0x1d, 0x77, 0xeb, 0xa1, 0xb1, 0x63, 0x6f, 0xd6, 0x19, 0x0c, 0x62, - 0xb9, 0xa5, 0xd0, 0x48, 0x1b, 0xee, 0x7e, 0x91, 0x7f, 0xab, 0x02, 0xe2, 0x18, 0x58, - 0x06, 0x3a, 0xb5, 0x04, - ], - ak: [ - 0x36, 0x40, 0x48, 0xee, 0xdb, 0xe8, 0xca, 0x20, 0x5e, 0xb7, 0xe7, 0xba, 0x0a, 0x90, - 0x12, 0x16, 0x6c, 0x7c, 0x7b, 0xd9, 0xeb, 0x22, 0x8e, 0x08, 0x48, 0x14, 0x48, 0xc4, - 0x88, 0xaa, 0x21, 0xd2, - ], - nk: [ - 0xed, 0x60, 0xaf, 0x1c, 0xe7, 0xdf, 0x38, 0x07, 0x0d, 0x38, 0x51, 0x43, 0x2a, 0x96, - 0x48, 0x0d, 0xb0, 0xb4, 0x17, 0xc3, 0x68, 0x2a, 0x1d, 0x68, 0xe3, 0xe8, 0x93, 0x34, - 0x23, 0x5c, 0x0b, 0xdf, - ], - ivk: [ - 0x99, 0xc9, 0xb4, 0xb8, 0x4f, 0x4b, 0x4e, 0x35, 0x0f, 0x78, 0x7d, 0x1c, 0xf7, 0x05, - 0x1d, 0x50, 0xec, 0xc3, 0x4b, 0x1a, 0x5b, 0x20, 0xd2, 0xd2, 0x13, 0x9b, 0x4a, 0xf1, - 0xf1, 0x60, 0xe0, 0x01, - ], - default_d: [ - 0x21, 0xc9, 0x0e, 0x1c, 0x65, 0x8b, 0x3e, 0xfe, 0x86, 0xaf, 0x58, - ], - default_pk_d: [ - 0x9e, 0x64, 0x17, 0x4b, 0x4a, 0xb9, 0x81, 0x40, 0x5c, 0x32, 0x3b, 0x5e, 0x12, 0x47, - 0x59, 0x45, 0xa4, 0x6d, 0x4f, 0xed, 0xf8, 0x06, 0x08, 0x28, 0x04, 0x1c, 0xd2, 0x0e, - 0x62, 0xfd, 0x2c, 0xef, - ], - note_v: 5584102310880684544, - note_r: [ - 0x8c, 0x3e, 0x56, 0x44, 0x9d, 0xc8, 0x63, 0x54, 0xd3, 0x3b, 0x02, 0x5e, 0xf2, 0x79, - 0x34, 0x60, 0xbc, 0xb1, 0x69, 0xf3, 0x32, 0x4e, 0x4a, 0x6b, 0x64, 0xba, 0xa6, 0x08, - 0x32, 0x31, 0x57, 0x04, - ], - note_cm: [ - 0x7b, 0x48, 0xa8, 0x37, 0x5d, 0x3e, 0xbd, 0x56, 0xbc, 0x64, 0x9b, 0xb5, 0xb5, 0x24, - 0x23, 0x36, 0xc2, 0xa0, 0x5a, 0x08, 0x03, 0x23, 0x9b, 0x5b, 0x88, 0xfd, 0x92, 0x07, - 0x8f, 0xea, 0x4d, 0x04, - ], - }, - TestVector { - sk: [ - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, - ], - ask: [ - 0xeb, 0xbb, 0x40, 0xa9, 0x80, 0xba, 0x3b, 0x88, 0x60, 0x94, 0x8d, 0x01, 0x1e, 0x1b, - 0xfb, 0x4a, 0xff, 0xe1, 0x6c, 0x65, 0x2e, 0x90, 0xe9, 0x82, 0x58, 0x30, 0x2f, 0x44, - 0x64, 0xc9, 0x1e, 0x0c, - ], - nsk: [ - 0x68, 0x43, 0x1b, 0x19, 0x91, 0x04, 0x21, 0x52, 0x00, 0xb9, 0x5e, 0xe5, 0xcb, 0x71, - 0xbf, 0x8b, 0x88, 0x3a, 0x3e, 0x95, 0xb7, 0x98, 0x9c, 0xad, 0x19, 0x70, 0x63, 0x14, - 0x1e, 0xbb, 0xfd, 0x00, - ], - ovk: [ - 0x57, 0x34, 0x67, 0xa7, 0xb3, 0x0e, 0xad, 0x6c, 0xcc, 0x50, 0x47, 0x44, 0xca, 0x9e, - 0x1a, 0x28, 0x1a, 0x0d, 0x1a, 0x08, 0x73, 0x8b, 0x06, 0xa0, 0x68, 0x4f, 0xea, 0xcd, - 0x1e, 0x9d, 0x12, 0x6d, - ], - ak: [ - 0x71, 0xc3, 0x52, 0x3e, 0xec, 0xa3, 0x53, 0x11, 0xfb, 0xd5, 0xd7, 0xe7, 0xd7, 0x0b, - 0x70, 0x9d, 0x6c, 0x35, 0xa2, 0x4f, 0x26, 0x2b, 0x34, 0xbf, 0x64, 0x05, 0x9b, 0xf2, - 0xc0, 0x2e, 0x0b, 0xa8, - ], - nk: [ - 0x62, 0x44, 0x00, 0x10, 0x3b, 0x65, 0x69, 0xb7, 0x35, 0x8f, 0xe8, 0x0f, 0x6f, 0x6c, - 0xad, 0x43, 0x25, 0xde, 0xfd, 0xa9, 0xd9, 0x49, 0x9c, 0x2b, 0x8f, 0x88, 0x6a, 0x62, - 0x69, 0xa2, 0xaa, 0x52, - ], - ivk: [ - 0xdb, 0x95, 0xea, 0x8b, 0xd9, 0xf9, 0x3d, 0x41, 0xb5, 0xab, 0x2b, 0xeb, 0xc9, 0x1a, - 0x38, 0xed, 0xd5, 0x27, 0x08, 0x3e, 0x2a, 0x6e, 0xf9, 0xf3, 0xc2, 0x97, 0x02, 0xd5, - 0xff, 0x89, 0xed, 0x00, - ], - default_d: [ - 0x23, 0x3c, 0x4a, 0xb8, 0x86, 0xa5, 0x5e, 0x3b, 0xa3, 0x74, 0xc0, - ], - default_pk_d: [ - 0xb6, 0x8e, 0x9e, 0xe0, 0xc0, 0x67, 0x8d, 0x7b, 0x30, 0x36, 0x93, 0x1c, 0x83, 0x1a, - 0x25, 0x25, 0x5f, 0x7e, 0xe4, 0x87, 0x38, 0x5a, 0x30, 0x31, 0x6e, 0x15, 0xf6, 0x48, - 0x2b, 0x87, 0x4f, 0xda, - ], - note_v: 17811330145809239872, - note_r: [ - 0x6e, 0xbb, 0xed, 0x74, 0x36, 0x19, 0xa2, 0x56, 0xf9, 0xad, 0x2e, 0x85, 0x88, 0x0c, - 0xfa, 0xa9, 0x09, 0x8a, 0x5f, 0xdb, 0x16, 0x29, 0x99, 0x0d, 0x9a, 0x7d, 0x3b, 0xb9, - 0x3f, 0xc9, 0x00, 0x03, - ], - note_cm: [ - 0xd3, 0x76, 0xa7, 0xbe, 0xe8, 0xce, 0x67, 0xf4, 0xef, 0xde, 0x56, 0xaa, 0x77, 0xcf, - 0x64, 0x41, 0x9b, 0x0e, 0x55, 0x0a, 0xbb, 0xcb, 0x8e, 0x2b, 0xcb, 0xda, 0x8b, 0x63, - 0xe4, 0x1d, 0xeb, 0x37, - ], - }, - ]; - - for tv in test_vectors { - let mut ask_repr = FsRepr::default(); - let mut nsk_repr = FsRepr::default(); - ask_repr.read_le(&tv.ask[..]).unwrap(); - nsk_repr.read_le(&tv.nsk[..]).unwrap(); - let nsk = ::Fs::from_repr(nsk_repr).unwrap(); - - let ak = JUBJUB - .generator(FixedGenerators::SpendingKeyGenerator) - .mul(ask_repr.clone(), &JUBJUB); - { - let mut vec = Vec::new(); - ak.write(&mut vec).unwrap(); - assert_eq!(&vec, &tv.ak); - } - { - let mut ak = [0u8; 32]; - librustzcash_ask_to_ak(&tv.ask, &mut ak); - assert_eq!(&ak, &tv.ak); - } - - let pgk = ProofGenerationKey { ak, nsk }; - let fvk = pgk.into_viewing_key(&JUBJUB); - { - let mut vec = Vec::new(); - fvk.nk.write(&mut vec).unwrap(); - assert_eq!(&vec, &tv.nk); - } - { - let mut nk = [0u8; 32]; - librustzcash_nsk_to_nk(&tv.nsk, &mut nk); - assert_eq!(&nk, &tv.nk); - } - - { - let mut vec = Vec::new(); - fvk.ivk().into_repr().write_le(&mut vec).unwrap(); - assert_eq!(&vec, &tv.ivk); - } - { - let mut ivk = [0u8; 32]; - librustzcash_crh_ivk(&tv.ak, &tv.nk, &mut ivk); - assert_eq!(&ivk, &tv.ivk); - } - - let diversifier = Diversifier(tv.default_d); - assert!(librustzcash_check_diversifier(&tv.default_d)); - - let addr = fvk.into_payment_address(diversifier, &JUBJUB).unwrap(); - { - let mut vec = Vec::new(); - addr.pk_d.write(&mut vec).unwrap(); - assert_eq!(&vec, &tv.default_pk_d); - } - { - let mut default_pk_d = [0u8; 32]; - librustzcash_ivk_to_pkd(&tv.ivk, &tv.default_d, &mut default_pk_d); - assert_eq!(&default_pk_d, &tv.default_pk_d); - } - - let mut note_r_repr = FsRepr::default(); - note_r_repr.read_le(&tv.note_r[..]).unwrap(); - let note_r = ::Fs::from_repr(note_r_repr).unwrap(); - let note = addr.create_note(tv.note_v, note_r, &JUBJUB).unwrap(); - { - let mut vec = Vec::new(); - note.cm(&JUBJUB).into_repr().write_le(&mut vec).unwrap(); - assert_eq!(&vec, &tv.note_cm); - } - } -} diff --git a/librustzcash/src/tests/mod.rs b/librustzcash/src/tests/mod.rs deleted file mode 100644 index a8cdcb7..0000000 --- a/librustzcash/src/tests/mod.rs +++ /dev/null @@ -1,96 +0,0 @@ -use sapling_crypto::jubjub::{FixedGenerators, JubjubParams}; - -use super::JUBJUB; - -mod key_agreement; -mod key_components; -mod notes; -mod signatures; - -#[test] -fn sapling_generators() { - struct SaplingGenerators { - skb: [u8; 32], - pkb: [u8; 32], - npb: [u8; 32], - wprb: [u8; 32], - vcvb: [u8; 32], - vcrb: [u8; 32], - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_generators.py - let sapling_generators = SaplingGenerators { - skb: [ - 0x30, 0xb5, 0xf2, 0xaa, 0xad, 0x32, 0x56, 0x30, 0xbc, 0xdd, 0xdb, 0xce, 0x4d, 0x67, - 0x65, 0x6d, 0x05, 0xfd, 0x1c, 0xc2, 0xd0, 0x37, 0xbb, 0x53, 0x75, 0xb6, 0xe9, 0x6d, - 0x9e, 0x01, 0xa1, 0xd7, - ], - pkb: [ - 0xe7, 0xe8, 0x5d, 0xe0, 0xf7, 0xf9, 0x7a, 0x46, 0xd2, 0x49, 0xa1, 0xf5, 0xea, 0x51, - 0xdf, 0x50, 0xcc, 0x48, 0x49, 0x0f, 0x84, 0x01, 0xc9, 0xde, 0x7a, 0x2a, 0xdf, 0x18, - 0x07, 0xd1, 0xb6, 0xd4, - ], - npb: [ - 0x65, 0x00, 0x2b, 0xc7, 0x36, 0xfa, 0xf7, 0xa3, 0x42, 0x2e, 0xff, 0xff, 0xe8, 0xb8, - 0x55, 0xe1, 0x8f, 0xba, 0x96, 0xa0, 0x15, 0x8a, 0x9e, 0xfc, 0xa5, 0x84, 0xbf, 0x40, - 0x54, 0x9d, 0x36, 0xe1, - ], - wprb: [ - 0xac, 0x77, 0x6c, 0x79, 0x65, 0x63, 0xfc, 0xd4, 0x4c, 0xc4, 0x9c, 0xfa, 0xea, 0x8b, - 0xb7, 0x96, 0x95, 0x2c, 0x26, 0x6e, 0x47, 0x77, 0x9d, 0x94, 0x57, 0x4c, 0x10, 0xad, - 0x01, 0x75, 0x4b, 0x11, - ], - vcvb: [ - 0xd7, 0xc8, 0x67, 0x06, 0xf5, 0x81, 0x7a, 0xa7, 0x18, 0xcd, 0x1c, 0xfa, 0xd0, 0x32, - 0x33, 0xbc, 0xd6, 0x4a, 0x77, 0x89, 0xfd, 0x94, 0x22, 0xd3, 0xb1, 0x7a, 0xf6, 0x82, - 0x3a, 0x7e, 0x6a, 0xc6, - ], - vcrb: [ - 0x8b, 0x6a, 0x0b, 0x38, 0xb9, 0xfa, 0xae, 0x3c, 0x3b, 0x80, 0x3b, 0x47, 0xb0, 0xf1, - 0x46, 0xad, 0x50, 0xab, 0x22, 0x1e, 0x6e, 0x2a, 0xfb, 0xe6, 0xdb, 0xde, 0x45, 0xcb, - 0xa9, 0xd3, 0x81, 0xed, - ], - }; - - { - let mut vec = Vec::new(); - let p = JUBJUB.generator(FixedGenerators::SpendingKeyGenerator); - p.write(&mut vec).unwrap(); - assert_eq!(&vec, &sapling_generators.skb); - } - - { - let mut vec = Vec::new(); - let p = JUBJUB.generator(FixedGenerators::ProofGenerationKey); - p.write(&mut vec).unwrap(); - assert_eq!(&vec, &sapling_generators.pkb); - } - - { - let mut vec = Vec::new(); - let p = JUBJUB.generator(FixedGenerators::NullifierPosition); - p.write(&mut vec).unwrap(); - assert_eq!(&vec, &sapling_generators.npb); - } - - { - let mut vec = Vec::new(); - let p = JUBJUB.generator(FixedGenerators::NoteCommitmentRandomness); - p.write(&mut vec).unwrap(); - assert_eq!(&vec, &sapling_generators.wprb); - } - - { - let mut vec = Vec::new(); - let p = JUBJUB.generator(FixedGenerators::ValueCommitmentValue); - p.write(&mut vec).unwrap(); - assert_eq!(&vec, &sapling_generators.vcvb); - } - - { - let mut vec = Vec::new(); - let p = JUBJUB.generator(FixedGenerators::ValueCommitmentRandomness); - p.write(&mut vec).unwrap(); - assert_eq!(&vec, &sapling_generators.vcrb); - } -} diff --git a/librustzcash/src/tests/notes.rs b/librustzcash/src/tests/notes.rs deleted file mode 100644 index 6f8c0f5..0000000 --- a/librustzcash/src/tests/notes.rs +++ /dev/null @@ -1,673 +0,0 @@ -use librustzcash_sapling_compute_cm; -use librustzcash_sapling_compute_nf; - -#[test] -fn notes() { - #![allow(dead_code)] - struct TestVector { - sk: [u8; 32], - ask: [u8; 32], - nsk: [u8; 32], - ovk: [u8; 32], - ak: [u8; 32], - nk: [u8; 32], - ivk: [u8; 32], - default_d: [u8; 11], - default_pk_d: [u8; 32], - note_v: u64, - note_r: [u8; 32], - note_cm: [u8; 32], - note_pos: u64, - note_nf: [u8; 32], - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_key_components.py - let test_vectors = vec![ - TestVector { - sk: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - ask: [ - 0x85, 0x48, 0xa1, 0x4a, 0x47, 0x3e, 0xa5, 0x47, 0xaa, 0x23, 0x78, 0x40, 0x20, 0x44, - 0xf8, 0x18, 0xcf, 0x19, 0x11, 0xcf, 0x5d, 0xd2, 0x05, 0x4f, 0x67, 0x83, 0x45, 0xf0, - 0x0d, 0x0e, 0x88, 0x06, - ], - nsk: [ - 0x30, 0x11, 0x4e, 0xa0, 0xdd, 0x0b, 0xb6, 0x1c, 0xf0, 0xea, 0xea, 0xb6, 0xec, 0x33, - 0x31, 0xf5, 0x81, 0xb0, 0x42, 0x5e, 0x27, 0x33, 0x85, 0x01, 0x26, 0x2d, 0x7e, 0xac, - 0x74, 0x5e, 0x6e, 0x05, - ], - ovk: [ - 0x98, 0xd1, 0x69, 0x13, 0xd9, 0x9b, 0x04, 0x17, 0x7c, 0xab, 0xa4, 0x4f, 0x6e, 0x4d, - 0x22, 0x4e, 0x03, 0xb5, 0xac, 0x03, 0x1d, 0x7c, 0xe4, 0x5e, 0x86, 0x51, 0x38, 0xe1, - 0xb9, 0x96, 0xd6, 0x3b, - ], - ak: [ - 0xf3, 0x44, 0xec, 0x38, 0x0f, 0xe1, 0x27, 0x3e, 0x30, 0x98, 0xc2, 0x58, 0x8c, 0x5d, - 0x3a, 0x79, 0x1f, 0xd7, 0xba, 0x95, 0x80, 0x32, 0x76, 0x07, 0x77, 0xfd, 0x0e, 0xfa, - 0x8e, 0xf1, 0x16, 0x20, - ], - nk: [ - 0xf7, 0xcf, 0x9e, 0x77, 0xf2, 0xe5, 0x86, 0x83, 0x38, 0x3c, 0x15, 0x19, 0xac, 0x7b, - 0x06, 0x2d, 0x30, 0x04, 0x0e, 0x27, 0xa7, 0x25, 0xfb, 0x88, 0xfb, 0x19, 0xa9, 0x78, - 0xbd, 0x3f, 0xd6, 0xba, - ], - ivk: [ - 0xb7, 0x0b, 0x7c, 0xd0, 0xed, 0x03, 0xcb, 0xdf, 0xd7, 0xad, 0xa9, 0x50, 0x2e, 0xe2, - 0x45, 0xb1, 0x3e, 0x56, 0x9d, 0x54, 0xa5, 0x71, 0x9d, 0x2d, 0xaa, 0x0f, 0x5f, 0x14, - 0x51, 0x47, 0x92, 0x04, - ], - default_d: [ - 0xf1, 0x9d, 0x9b, 0x79, 0x7e, 0x39, 0xf3, 0x37, 0x44, 0x58, 0x39, - ], - default_pk_d: [ - 0xdb, 0x4c, 0xd2, 0xb0, 0xaa, 0xc4, 0xf7, 0xeb, 0x8c, 0xa1, 0x31, 0xf1, 0x65, 0x67, - 0xc4, 0x45, 0xa9, 0x55, 0x51, 0x26, 0xd3, 0xc2, 0x9f, 0x14, 0xe3, 0xd7, 0x76, 0xe8, - 0x41, 0xae, 0x74, 0x15, - ], - note_v: 0, - note_r: [ - 0x39, 0x17, 0x6d, 0xac, 0x39, 0xac, 0xe4, 0x98, 0x0e, 0xcc, 0x8d, 0x77, 0x8e, 0x89, - 0x86, 0x02, 0x55, 0xec, 0x36, 0x15, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - note_cm: [ - 0xcb, 0x3c, 0xf9, 0x15, 0x32, 0x70, 0xd5, 0x7e, 0xb9, 0x14, 0xc6, 0xc2, 0xbc, 0xc0, - 0x18, 0x50, 0xc9, 0xfe, 0xd4, 0x4f, 0xce, 0x08, 0x06, 0x27, 0x8f, 0x08, 0x3e, 0xf2, - 0xdd, 0x07, 0x64, 0x39, - ], - note_pos: 0, - note_nf: [ - 0x44, 0xfa, 0xd6, 0x56, 0x4f, 0xfd, 0xec, 0x9f, 0xa1, 0x9c, 0x43, 0xa2, 0x8f, 0x86, - 0x1d, 0x5e, 0xbf, 0x60, 0x23, 0x46, 0x00, 0x7d, 0xe7, 0x62, 0x67, 0xd9, 0x75, 0x27, - 0x47, 0xab, 0x40, 0x63, - ], - }, - TestVector { - sk: [ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, - ], - ask: [ - 0xc9, 0x43, 0x56, 0x29, 0xbf, 0x8b, 0xff, 0xe5, 0x5e, 0x73, 0x35, 0xec, 0x07, 0x77, - 0x18, 0xba, 0x60, 0xba, 0x28, 0xd7, 0xac, 0x37, 0x94, 0xb7, 0x4f, 0x51, 0x2c, 0x31, - 0xaf, 0x0a, 0x53, 0x04, - ], - nsk: [ - 0x11, 0xac, 0xc2, 0xea, 0xd0, 0x7b, 0x5f, 0x00, 0x8c, 0x1f, 0x0f, 0x09, 0x0c, 0xc8, - 0xdd, 0xf3, 0x35, 0x23, 0x6f, 0xf4, 0xb2, 0x53, 0xc6, 0x49, 0x56, 0x95, 0xe9, 0xd6, - 0x39, 0xda, 0xcd, 0x08, - ], - ovk: [ - 0x3b, 0x94, 0x62, 0x10, 0xce, 0x6d, 0x1b, 0x16, 0x92, 0xd7, 0x39, 0x2a, 0xc8, 0x4a, - 0x8b, 0xc8, 0xf0, 0x3b, 0x72, 0x72, 0x3c, 0x7d, 0x36, 0x72, 0x1b, 0x80, 0x9a, 0x79, - 0xc9, 0xd6, 0xe4, 0x5b, - ], - ak: [ - 0x82, 0xff, 0x5e, 0xff, 0xc5, 0x27, 0xae, 0x84, 0x02, 0x0b, 0xf2, 0xd3, 0x52, 0x01, - 0xc1, 0x02, 0x19, 0x13, 0x19, 0x47, 0xff, 0x4b, 0x96, 0xf8, 0x81, 0xa4, 0x5f, 0x2e, - 0x8a, 0xe3, 0x05, 0x18, - ], - nk: [ - 0xc4, 0x53, 0x4d, 0x84, 0x8b, 0xb9, 0x18, 0xcf, 0x4a, 0x7f, 0x8b, 0x98, 0x74, 0x0a, - 0xb3, 0xcc, 0xee, 0x58, 0x67, 0x95, 0xff, 0x4d, 0xf6, 0x45, 0x47, 0xa8, 0x88, 0x8a, - 0x6c, 0x74, 0x15, 0xd2, - ], - ivk: [ - 0xc5, 0x18, 0x38, 0x44, 0x66, 0xb2, 0x69, 0x88, 0xb5, 0x10, 0x90, 0x67, 0x41, 0x8d, - 0x19, 0x2d, 0x9d, 0x6b, 0xd0, 0xd9, 0x23, 0x22, 0x05, 0xd7, 0x74, 0x18, 0xc2, 0x40, - 0xfc, 0x68, 0xa4, 0x06, - ], - default_d: [ - 0xae, 0xf1, 0x80, 0xf6, 0xe3, 0x4e, 0x35, 0x4b, 0x88, 0x8f, 0x81, - ], - default_pk_d: [ - 0xa6, 0xb1, 0x3e, 0xa3, 0x36, 0xdd, 0xb7, 0xa6, 0x7b, 0xb0, 0x9a, 0x0e, 0x68, 0xe9, - 0xd3, 0xcf, 0xb3, 0x92, 0x10, 0x83, 0x1e, 0xa3, 0xa2, 0x96, 0xba, 0x09, 0xa9, 0x22, - 0x06, 0x0f, 0xd3, 0x8b, - ], - note_v: 12227227834928555328, - note_r: [ - 0x47, 0x8b, 0xa0, 0xee, 0x6e, 0x1a, 0x75, 0xb6, 0x00, 0x03, 0x6f, 0x26, 0xf1, 0x8b, - 0x70, 0x15, 0xab, 0x55, 0x6b, 0xed, 0xdf, 0x8b, 0x96, 0x02, 0x38, 0x86, 0x9f, 0x89, - 0xdd, 0x80, 0x4e, 0x06, - ], - note_cm: [ - 0xb5, 0x78, 0x93, 0x50, 0x0b, 0xfb, 0x85, 0xdf, 0x2e, 0x8b, 0x01, 0xac, 0x45, 0x2f, - 0x89, 0xe1, 0x0e, 0x26, 0x6b, 0xcf, 0xa3, 0x1c, 0x31, 0xb2, 0x9a, 0x53, 0xae, 0x72, - 0xca, 0xd4, 0x69, 0x50, - ], - note_pos: 763714296, - note_nf: [ - 0x67, 0x9e, 0xb0, 0xc3, 0xa7, 0x57, 0xe2, 0xae, 0x83, 0xcd, 0xb4, 0x2a, 0x1a, 0xb2, - 0x59, 0xd7, 0x83, 0x88, 0x31, 0x54, 0x19, 0xad, 0xc7, 0x1d, 0x2e, 0x37, 0x63, 0x17, - 0x4c, 0x2e, 0x9d, 0x93, - ], - }, - TestVector { - sk: [ - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, - ], - ask: [ - 0xee, 0x1c, 0x3d, 0x7e, 0xfe, 0x0a, 0x78, 0x06, 0x3d, 0x6a, 0xf3, 0xd9, 0xd8, 0x12, - 0x12, 0xaf, 0x47, 0xb7, 0xc1, 0xb7, 0x61, 0xf8, 0x5c, 0xcb, 0x06, 0x6f, 0xc1, 0x1a, - 0x6a, 0x42, 0x17, 0x03, - ], - nsk: [ - 0x1d, 0x3b, 0x71, 0x37, 0x55, 0xd7, 0x48, 0x75, 0xe8, 0xea, 0x38, 0xfd, 0x16, 0x6e, - 0x76, 0xc6, 0x2a, 0x42, 0x50, 0x21, 0x6e, 0x6b, 0xbf, 0xe4, 0x8a, 0x5e, 0x2e, 0xab, - 0xad, 0x11, 0x7f, 0x0b, - ], - ovk: [ - 0x8b, 0xf4, 0x39, 0x0e, 0x28, 0xdd, 0xc9, 0x5b, 0x83, 0x02, 0xc3, 0x81, 0xd5, 0x81, - 0x0b, 0x84, 0xba, 0x8e, 0x60, 0x96, 0xe5, 0xa7, 0x68, 0x22, 0x77, 0x4f, 0xd4, 0x9f, - 0x49, 0x1e, 0x8f, 0x49, - ], - ak: [ - 0xab, 0x83, 0x57, 0x4e, 0xb5, 0xde, 0x85, 0x9a, 0x0a, 0xb8, 0x62, 0x9d, 0xec, 0x34, - 0xc7, 0xbe, 0xe8, 0xc3, 0xfc, 0x74, 0xdf, 0xa0, 0xb1, 0x9a, 0x3a, 0x74, 0x68, 0xd1, - 0x5d, 0xca, 0x64, 0xc6, - ], - nk: [ - 0x95, 0xd5, 0x80, 0x53, 0xe0, 0x59, 0x2e, 0x4a, 0x16, 0x9c, 0xc0, 0xb7, 0x92, 0x8a, - 0xaa, 0xc3, 0xde, 0x24, 0xef, 0x15, 0x31, 0xaa, 0x9e, 0xb6, 0xf4, 0xab, 0x93, 0x91, - 0x4d, 0xa8, 0xa0, 0x6e, - ], - ivk: [ - 0x47, 0x1c, 0x24, 0xa3, 0xdc, 0x87, 0x30, 0xe7, 0x50, 0x36, 0xc0, 0xa9, 0x5f, 0x3e, - 0x2f, 0x7d, 0xd1, 0xbe, 0x6f, 0xb9, 0x3a, 0xd2, 0x95, 0x92, 0x20, 0x3d, 0xef, 0x30, - 0x41, 0x95, 0x45, 0x05, - ], - default_d: [ - 0x75, 0x99, 0xf0, 0xbf, 0x9b, 0x57, 0xcd, 0x2d, 0xc2, 0x99, 0xb6, - ], - default_pk_d: [ - 0x66, 0x14, 0x17, 0x39, 0x51, 0x4b, 0x28, 0xf0, 0x5d, 0xef, 0x8a, 0x18, 0xee, 0xee, - 0x5e, 0xed, 0x4d, 0x44, 0xc6, 0x22, 0x5c, 0x3c, 0x65, 0xd8, 0x8d, 0xd9, 0x90, 0x77, - 0x08, 0x01, 0x2f, 0x5a, - ], - note_v: 6007711596147559040, - note_r: [ - 0x14, 0x7c, 0xf2, 0xb5, 0x1b, 0x4c, 0x7c, 0x63, 0xcb, 0x77, 0xb9, 0x9e, 0x8b, 0x78, - 0x3e, 0x5b, 0x51, 0x11, 0xdb, 0x0a, 0x7c, 0xa0, 0x4d, 0x6c, 0x01, 0x4a, 0x1d, 0x7d, - 0xa8, 0x3b, 0xae, 0x0a, - ], - note_cm: [ - 0xdb, 0x85, 0xa7, 0x0a, 0x98, 0x43, 0x7f, 0x73, 0x16, 0x7f, 0xc3, 0x32, 0xd5, 0xb7, - 0xb7, 0x40, 0x82, 0x96, 0x66, 0x17, 0x70, 0xb1, 0x01, 0xb0, 0xaa, 0x87, 0x83, 0x9f, - 0x4e, 0x55, 0xf1, 0x51, - ], - note_pos: 1527428592, - note_nf: [ - 0xe9, 0x8f, 0x6a, 0x8f, 0x34, 0xff, 0x49, 0x80, 0x59, 0xb3, 0xc7, 0x31, 0xb9, 0x1f, - 0x45, 0x11, 0x08, 0xc4, 0x95, 0x4d, 0x91, 0x94, 0x84, 0x36, 0x1c, 0xf9, 0xb4, 0x8f, - 0x59, 0xae, 0x1d, 0x14, - ], - }, - TestVector { - sk: [ - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, - ], - ask: [ - 0x00, 0xc3, 0xa1, 0xe1, 0xca, 0x8f, 0x4e, 0x04, 0x80, 0xee, 0x1e, 0xe9, 0x0c, 0xa7, - 0x51, 0x78, 0x79, 0xd3, 0xfc, 0x5c, 0x81, 0x5c, 0x09, 0x03, 0xe5, 0xee, 0xbc, 0x94, - 0xbb, 0x80, 0x95, 0x03, - ], - nsk: [ - 0xe6, 0x62, 0x85, 0xa5, 0xe9, 0xb6, 0x5e, 0x15, 0x7a, 0xd2, 0xfc, 0xd5, 0x43, 0xda, - 0xd9, 0x8c, 0x67, 0xa5, 0x8a, 0xbd, 0xf2, 0x87, 0xe0, 0x55, 0x06, 0xbd, 0x1c, 0x2e, - 0x59, 0xb0, 0x72, 0x0b, - ], - ovk: [ - 0x14, 0x76, 0x78, 0xe0, 0x55, 0x3b, 0x97, 0x82, 0x93, 0x47, 0x64, 0x7c, 0x5b, 0xc7, - 0xda, 0xb4, 0xcc, 0x22, 0x02, 0xb5, 0x4e, 0xc2, 0x9f, 0xd3, 0x1a, 0x3d, 0xe6, 0xbe, - 0x08, 0x25, 0xfc, 0x5e, - ], - ak: [ - 0x3c, 0x9c, 0xde, 0x7e, 0x5d, 0x0d, 0x38, 0xa8, 0x61, 0x0f, 0xaa, 0xdb, 0xcf, 0x4c, - 0x34, 0x3f, 0x5d, 0x3c, 0xfa, 0x31, 0x55, 0xa5, 0xb9, 0x46, 0x61, 0xa6, 0x75, 0x3e, - 0x96, 0xe8, 0x84, 0xea, - ], - nk: [ - 0xb7, 0x7d, 0x36, 0xf5, 0x08, 0x94, 0x1d, 0xbd, 0x61, 0xcf, 0xd0, 0xf1, 0x59, 0xee, - 0x05, 0xcf, 0xaa, 0x78, 0xa2, 0x6c, 0x94, 0x92, 0x90, 0x38, 0x06, 0xd8, 0x3b, 0x59, - 0x8d, 0x3c, 0x1c, 0x2a, - ], - ivk: [ - 0x63, 0x6a, 0xa9, 0x64, 0xbf, 0xc2, 0x3c, 0xe4, 0xb1, 0xfc, 0xf7, 0xdf, 0xc9, 0x91, - 0x79, 0xdd, 0xc4, 0x06, 0xff, 0x55, 0x40, 0x0c, 0x92, 0x95, 0xac, 0xfc, 0x14, 0xf0, - 0x31, 0xc7, 0x26, 0x00, - ], - default_d: [ - 0x1b, 0x81, 0x61, 0x4f, 0x1d, 0xad, 0xea, 0x0f, 0x8d, 0x0a, 0x58, - ], - default_pk_d: [ - 0x25, 0xeb, 0x55, 0xfc, 0xcf, 0x76, 0x1f, 0xc6, 0x4e, 0x85, 0xa5, 0x88, 0xef, 0xe6, - 0xea, 0xd7, 0x83, 0x2f, 0xb1, 0xf0, 0xf7, 0xa8, 0x31, 0x65, 0x89, 0x5b, 0xdf, 0xf9, - 0x42, 0x92, 0x5f, 0x5c, - ], - note_v: 18234939431076114368, - note_r: [ - 0x34, 0xa4, 0xb2, 0xa9, 0x14, 0x4f, 0xf5, 0xea, 0x54, 0xef, 0xee, 0x87, 0xcf, 0x90, - 0x1b, 0x5b, 0xed, 0x5e, 0x35, 0xd2, 0x1f, 0xbb, 0xd7, 0x88, 0xd5, 0xbd, 0x9d, 0x83, - 0x3e, 0x11, 0x28, 0x04, - ], - note_cm: [ - 0xe0, 0x8c, 0xe4, 0x82, 0xb3, 0xa8, 0xfb, 0x3b, 0x35, 0xcc, 0xdb, 0xe3, 0x43, 0x37, - 0xbd, 0x10, 0x5d, 0x88, 0x39, 0x21, 0x2e, 0x0d, 0x16, 0x44, 0xb9, 0xd5, 0x5c, 0xaa, - 0x60, 0xd1, 0x9b, 0x6c, - ], - note_pos: 2291142888, - note_nf: [ - 0x55, 0x47, 0xaa, 0x12, 0xff, 0x80, 0xa6, 0xb3, 0x30, 0x4e, 0x3b, 0x05, 0x86, 0x56, - 0x47, 0x2a, 0xbd, 0x2c, 0x81, 0x83, 0xb5, 0x9d, 0x07, 0x37, 0xb9, 0x3c, 0xee, 0x75, - 0x8b, 0xec, 0x47, 0xa1, - ], - }, - TestVector { - sk: [ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, - ], - ask: [ - 0x82, 0x36, 0xd1, 0x9d, 0x32, 0x05, 0xd8, 0x55, 0x43, 0xa0, 0x68, 0x11, 0x34, 0x3f, - 0x82, 0x7b, 0x65, 0x63, 0x77, 0x0a, 0x49, 0xaa, 0x4d, 0x0c, 0xa0, 0x08, 0x18, 0x05, - 0xd4, 0xc8, 0xea, 0x0d, - ], - nsk: [ - 0x7e, 0xc1, 0xef, 0x0b, 0xed, 0x82, 0x71, 0x82, 0x72, 0xf0, 0xf4, 0x4f, 0x01, 0x7c, - 0x48, 0x41, 0x74, 0x51, 0x3d, 0x66, 0x1d, 0xd1, 0x68, 0xaf, 0x02, 0xd2, 0x09, 0x2a, - 0x1d, 0x8a, 0x05, 0x07, - ], - ovk: [ - 0x1b, 0x6e, 0x75, 0xec, 0xe3, 0xac, 0xe8, 0xdb, 0xa6, 0xa5, 0x41, 0x0d, 0x9a, 0xd4, - 0x75, 0x56, 0x68, 0xe4, 0xb3, 0x95, 0x85, 0xd6, 0x35, 0xec, 0x1d, 0xa7, 0xc8, 0xdc, - 0xfd, 0x5f, 0xc4, 0xed, - ], - ak: [ - 0x55, 0xe8, 0x83, 0x89, 0xbb, 0x7e, 0x41, 0xde, 0x13, 0x0c, 0xfa, 0x51, 0xa8, 0x71, - 0x5f, 0xde, 0x01, 0xff, 0x9c, 0x68, 0x76, 0x64, 0x7f, 0x01, 0x75, 0xad, 0x34, 0xf0, - 0x58, 0xdd, 0xe0, 0x1a, - ], - nk: [ - 0x72, 0x5d, 0x4a, 0xd6, 0xa1, 0x50, 0x21, 0xcd, 0x1c, 0x48, 0xc5, 0xee, 0x19, 0xde, - 0x6c, 0x1e, 0x76, 0x8a, 0x2c, 0xc0, 0xa9, 0xa7, 0x30, 0xa0, 0x1b, 0xb2, 0x1c, 0x95, - 0xe3, 0xd9, 0xe4, 0x3c, - ], - ivk: [ - 0x67, 0xfa, 0x2b, 0xf7, 0xc6, 0x7d, 0x46, 0x58, 0x24, 0x3c, 0x31, 0x7c, 0x0c, 0xb4, - 0x1f, 0xd3, 0x20, 0x64, 0xdf, 0xd3, 0x70, 0x9f, 0xe0, 0xdc, 0xb7, 0x24, 0xf1, 0x4b, - 0xb0, 0x1a, 0x1d, 0x04, - ], - default_d: [ - 0xfc, 0xfb, 0x68, 0xa4, 0x0d, 0x4b, 0xc6, 0xa0, 0x4b, 0x09, 0xc4, - ], - default_pk_d: [ - 0x8b, 0x2a, 0x33, 0x7f, 0x03, 0x62, 0x2c, 0x24, 0xff, 0x38, 0x1d, 0x4c, 0x54, 0x6f, - 0x69, 0x77, 0xf9, 0x05, 0x22, 0xe9, 0x2f, 0xde, 0x44, 0xc9, 0xd1, 0xbb, 0x09, 0x97, - 0x14, 0xb9, 0xdb, 0x2b, - ], - note_v: 12015423192295118080, - note_r: [ - 0xe5, 0x57, 0x85, 0x13, 0x55, 0x74, 0x7c, 0x09, 0xac, 0x59, 0x01, 0x3c, 0xbd, 0xe8, - 0x59, 0x80, 0x96, 0x4e, 0xc1, 0x84, 0x4d, 0x9c, 0x69, 0x67, 0xca, 0x0c, 0x02, 0x9c, - 0x84, 0x57, 0xbb, 0x04, - ], - note_cm: [ - 0xbd, 0xc8, 0x54, 0xbf, 0x3e, 0x7b, 0x00, 0x82, 0x1f, 0x3b, 0x8b, 0x85, 0x23, 0x8c, - 0xcf, 0x1e, 0x67, 0x15, 0xbf, 0xe7, 0x0b, 0x63, 0x2d, 0x04, 0x4b, 0x26, 0xfb, 0x2b, - 0xc7, 0x1b, 0x7f, 0x36, - ], - note_pos: 3054857184, - note_nf: [ - 0x8a, 0x9a, 0xbd, 0xa3, 0xd4, 0xef, 0x85, 0xca, 0xf2, 0x2b, 0xfa, 0xf2, 0xc4, 0x8f, - 0x62, 0x38, 0x2a, 0x73, 0xa1, 0x62, 0x4e, 0xb8, 0xeb, 0x2b, 0xd0, 0x0d, 0x27, 0x03, - 0x01, 0xbf, 0x3d, 0x13, - ], - }, - TestVector { - sk: [ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, - ], - ask: [ - 0xea, 0xe6, 0x88, 0x4d, 0x76, 0x4a, 0x05, 0x40, 0x61, 0xa8, 0xf1, 0xc0, 0x07, 0x6c, - 0x62, 0x4d, 0xcb, 0x73, 0x87, 0x89, 0xf7, 0xad, 0x1e, 0x74, 0x08, 0xe3, 0x1f, 0x24, - 0xdf, 0xc8, 0x26, 0x07, - ], - nsk: [ - 0xfb, 0xe6, 0x10, 0xf4, 0x2a, 0x41, 0x74, 0x9f, 0x9b, 0x6e, 0x6e, 0x4a, 0x54, 0xb5, - 0xa3, 0x2e, 0xbf, 0xe8, 0xf4, 0x38, 0x00, 0x88, 0x1b, 0xa6, 0xcd, 0x13, 0xed, 0x0b, - 0x05, 0x29, 0x46, 0x01, - ], - ovk: [ - 0xc6, 0xbc, 0x1f, 0x39, 0xf0, 0xd7, 0x86, 0x31, 0x4c, 0xb2, 0x0b, 0xf9, 0xab, 0x22, - 0x85, 0x40, 0x91, 0x35, 0x55, 0xf9, 0x70, 0x69, 0x6b, 0x6d, 0x7c, 0x77, 0xbb, 0x33, - 0x23, 0x28, 0x37, 0x2a, - ], - ak: [ - 0xe6, 0x82, 0x76, 0x59, 0x14, 0xe3, 0x86, 0x4c, 0x33, 0x9e, 0x57, 0x82, 0xb8, 0x55, - 0xc0, 0xfd, 0xf4, 0x0e, 0x0d, 0xfc, 0xed, 0xb9, 0xe7, 0xb4, 0x7b, 0xc9, 0x4b, 0x90, - 0xb3, 0xa4, 0xc9, 0x88, - ], - nk: [ - 0x82, 0x25, 0x6b, 0x95, 0x62, 0x3c, 0x67, 0x02, 0x4b, 0x44, 0x24, 0xd9, 0x14, 0x00, - 0xa3, 0x70, 0xe7, 0xac, 0x8e, 0x4d, 0x15, 0x48, 0x2a, 0x37, 0x59, 0xe0, 0x0d, 0x21, - 0x97, 0x49, 0xda, 0xee, - ], - ivk: [ - 0xea, 0x3f, 0x1d, 0x80, 0xe4, 0x30, 0x7c, 0xa7, 0x3b, 0x9f, 0x37, 0x80, 0x1f, 0x91, - 0xfb, 0xa8, 0x10, 0xcc, 0x41, 0xd2, 0x79, 0xfc, 0x29, 0xf5, 0x64, 0x23, 0x56, 0x54, - 0xa2, 0x17, 0x8e, 0x03, - ], - default_d: [ - 0xeb, 0x51, 0x98, 0x82, 0xad, 0x1e, 0x5c, 0xc6, 0x54, 0xcd, 0x59, - ], - default_pk_d: [ - 0x6b, 0x27, 0xda, 0xcc, 0xb5, 0xa8, 0x20, 0x7f, 0x53, 0x2d, 0x10, 0xca, 0x23, 0x8f, - 0x97, 0x86, 0x64, 0x8a, 0x11, 0xb5, 0x96, 0x6e, 0x51, 0xa2, 0xf7, 0xd8, 0x9e, 0x15, - 0xd2, 0x9b, 0x8f, 0xdf, - ], - note_v: 5795906953514121792, - note_r: [ - 0x68, 0xf0, 0x61, 0x04, 0x60, 0x6b, 0x0c, 0x54, 0x49, 0x84, 0x5f, 0xf4, 0xc6, 0x5f, - 0x73, 0xe9, 0x0f, 0x45, 0xef, 0x5a, 0x43, 0xc9, 0xd7, 0x4c, 0xb2, 0xc8, 0x5c, 0xf5, - 0x6c, 0x94, 0xc0, 0x02, - ], - note_cm: [ - 0xe8, 0x26, 0x7d, 0x30, 0xac, 0x11, 0xc1, 0x00, 0xbc, 0x7a, 0x0f, 0xdf, 0x91, 0xf7, - 0x1d, 0x74, 0xc5, 0xbc, 0xf2, 0xe1, 0xef, 0x95, 0x66, 0x90, 0x44, 0x73, 0x01, 0x69, - 0xde, 0x1a, 0x5b, 0x4c, - ], - note_pos: 3818571480, - note_nf: [ - 0x33, 0x2a, 0xd9, 0x9e, 0xb9, 0xe9, 0x77, 0xeb, 0x62, 0x7a, 0x12, 0x2d, 0xbf, 0xb2, - 0xf2, 0x5f, 0xe5, 0x88, 0xe5, 0x97, 0x75, 0x3e, 0xc5, 0x58, 0x0f, 0xf2, 0xbe, 0x20, - 0xb6, 0xc9, 0xa7, 0xe1, - ], - }, - TestVector { - sk: [ - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, - ], - ask: [ - 0xe8, 0xf8, 0x16, 0xb4, 0xbc, 0x08, 0xa7, 0xe5, 0x66, 0x75, 0x0c, 0xc2, 0x8a, 0xfe, - 0x82, 0xa4, 0xce, 0xa9, 0xc2, 0xbe, 0xf2, 0x44, 0xfa, 0x4b, 0x13, 0xc4, 0x73, 0x9b, - 0x28, 0x07, 0x4c, 0x0d, - ], - nsk: [ - 0x32, 0x61, 0x5b, 0x13, 0x7f, 0x28, 0x01, 0xed, 0x44, 0x6e, 0x48, 0x78, 0x1a, 0xb0, - 0x63, 0x45, 0x72, 0xe1, 0x8c, 0xfb, 0x06, 0x93, 0x72, 0x1b, 0x88, 0x03, 0xc0, 0x5b, - 0x82, 0x27, 0xd1, 0x07, - ], - ovk: [ - 0xf6, 0x2c, 0x05, 0xe8, 0x48, 0xa8, 0x73, 0xef, 0x88, 0x5e, 0x12, 0xb0, 0x8c, 0x5e, - 0x7c, 0xa2, 0xf3, 0x24, 0x24, 0xba, 0xcc, 0x75, 0x4c, 0xb6, 0x97, 0x50, 0x44, 0x4d, - 0x35, 0x5f, 0x51, 0x06, - ], - ak: [ - 0xff, 0x27, 0xdb, 0x07, 0x51, 0x94, 0x5d, 0x3e, 0xe4, 0xbe, 0x9c, 0xf1, 0x5c, 0x2e, - 0xa2, 0x11, 0xb2, 0x4b, 0x16, 0x4d, 0x5f, 0x2d, 0x7d, 0xdf, 0xf5, 0xe4, 0xa0, 0x70, - 0x8f, 0x10, 0xb9, 0x5e, - ], - nk: [ - 0x94, 0x38, 0x85, 0x95, 0x9d, 0x4e, 0xf8, 0xa9, 0xcf, 0xca, 0x07, 0xc4, 0x57, 0xf0, - 0x9e, 0xc7, 0x4b, 0x96, 0xf9, 0x93, 0xd8, 0xe0, 0xfa, 0x32, 0xb1, 0x9c, 0x03, 0xe3, - 0xb0, 0x7a, 0x42, 0x0f, - ], - ivk: [ - 0xb5, 0xc5, 0x89, 0x49, 0x43, 0x95, 0x69, 0x33, 0xc0, 0xe5, 0xc1, 0x2d, 0x31, 0x1f, - 0xc1, 0x2c, 0xba, 0x58, 0x35, 0x4b, 0x5c, 0x38, 0x9e, 0xdc, 0x03, 0xda, 0x55, 0x08, - 0x4f, 0x74, 0xc2, 0x05, - ], - default_d: [ - 0xbe, 0xbb, 0x0f, 0xb4, 0x6b, 0x8a, 0xaf, 0xf8, 0x90, 0x40, 0xf6, - ], - default_pk_d: [ - 0xd1, 0x1d, 0xa0, 0x1f, 0x0b, 0x43, 0xbd, 0xd5, 0x28, 0x8d, 0x32, 0x38, 0x5b, 0x87, - 0x71, 0xd2, 0x23, 0x49, 0x3c, 0x69, 0x80, 0x25, 0x44, 0x04, 0x3f, 0x77, 0xcf, 0x1d, - 0x71, 0xc1, 0xcb, 0x8c, - ], - note_v: 18023134788442677120, - note_r: [ - 0x49, 0xf9, 0x0b, 0x47, 0xfd, 0x52, 0xfe, 0xe7, 0xc1, 0xc8, 0x1f, 0x0d, 0xcb, 0x5b, - 0x74, 0xc3, 0xfb, 0x9b, 0x3e, 0x03, 0x97, 0x6f, 0x8b, 0x75, 0x24, 0xea, 0xba, 0xd0, - 0x08, 0x89, 0x21, 0x07, - ], - note_cm: [ - 0x57, 0x2b, 0xa2, 0x05, 0x25, 0xb0, 0xac, 0x4d, 0x6d, 0xc0, 0x1a, 0xc2, 0xea, 0x10, - 0x90, 0xb6, 0xe0, 0xf2, 0xf4, 0xbf, 0x4e, 0xc4, 0xa0, 0xdb, 0x5b, 0xbc, 0xcb, 0x5b, - 0x78, 0x3a, 0x1e, 0x55, - ], - note_pos: 287318480, - note_nf: [ - 0xfc, 0x74, 0xcd, 0x0e, 0x4b, 0xe0, 0x49, 0x57, 0xb1, 0x96, 0xcf, 0x87, 0x34, 0xae, - 0x99, 0x23, 0x96, 0xaf, 0x4c, 0xfa, 0x8f, 0xec, 0xbb, 0x86, 0xf9, 0x61, 0xe6, 0xb4, - 0x07, 0xd5, 0x1e, 0x11, - ], - }, - TestVector { - sk: [ - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, - ], - ask: [ - 0x74, 0xb4, 0x4a, 0x37, 0xf1, 0x50, 0x23, 0xc0, 0x60, 0x42, 0x7e, 0x1d, 0xae, 0xa3, - 0xf6, 0x43, 0x12, 0xdd, 0x8f, 0xeb, 0x7b, 0x2c, 0xed, 0xf0, 0xdd, 0x55, 0x44, 0x49, - 0x3f, 0x87, 0x2c, 0x06, - ], - nsk: [ - 0x07, 0x5c, 0x35, 0xdb, 0x8b, 0x1b, 0x25, 0x75, 0x42, 0x23, 0xec, 0xee, 0x34, 0xab, - 0x73, 0x0d, 0xdd, 0xd1, 0xf1, 0x4a, 0x6a, 0x54, 0xf4, 0xc6, 0xf4, 0x68, 0x45, 0x3c, - 0x3c, 0x6e, 0xd6, 0x0b, - ], - ovk: [ - 0xe9, 0xe0, 0xdc, 0x1e, 0xd3, 0x11, 0xda, 0xed, 0x64, 0xbd, 0x74, 0xda, 0x5d, 0x94, - 0xfe, 0x88, 0xa6, 0xea, 0x41, 0x4b, 0x73, 0x12, 0xde, 0x3d, 0x2a, 0x78, 0xf6, 0x46, - 0x32, 0xbb, 0xe3, 0x73, - ], - ak: [ - 0x28, 0x3f, 0x9a, 0xaf, 0xa9, 0xbc, 0xb3, 0xe6, 0xce, 0x17, 0xe6, 0x32, 0x12, 0x63, - 0x4c, 0xb3, 0xee, 0x55, 0x0c, 0x47, 0x6b, 0x67, 0x6b, 0xd3, 0x56, 0xa6, 0xdf, 0x8a, - 0xdf, 0x51, 0xd2, 0x5e, - ], - nk: [ - 0xdc, 0x4c, 0x67, 0xb1, 0x0d, 0x4b, 0x0a, 0x21, 0x8d, 0xc6, 0xe1, 0x48, 0x70, 0x66, - 0x74, 0x0a, 0x40, 0x93, 0x17, 0x86, 0x6c, 0x32, 0xe6, 0x64, 0xb5, 0x0e, 0x39, 0x7a, - 0xa8, 0x03, 0x89, 0xd4, - ], - ivk: [ - 0x87, 0x16, 0xc8, 0x28, 0x80, 0xe1, 0x36, 0x83, 0xe1, 0xbb, 0x05, 0x9d, 0xd0, 0x6c, - 0x80, 0xc9, 0x01, 0x34, 0xa9, 0x6d, 0x5a, 0xfc, 0xa8, 0xaa, 0xc2, 0xbb, 0xf6, 0x8b, - 0xb0, 0x5f, 0x84, 0x02, - ], - default_d: [ - 0xad, 0x6e, 0x2e, 0x18, 0x5a, 0x31, 0x00, 0xe3, 0xa6, 0xa8, 0xb3, - ], - default_pk_d: [ - 0x32, 0xcb, 0x28, 0x06, 0xb8, 0x82, 0xf1, 0x36, 0x8b, 0x0d, 0x4a, 0x89, 0x8f, 0x72, - 0xc4, 0xc8, 0xf7, 0x28, 0x13, 0x2c, 0xc1, 0x24, 0x56, 0x94, 0x6e, 0x7f, 0x4c, 0xb0, - 0xfb, 0x05, 0x8d, 0xa9, - ], - note_v: 11803618549661680832, - note_r: [ - 0x51, 0x65, 0xaf, 0xf2, 0x2d, 0xd4, 0xed, 0x56, 0xb4, 0xd8, 0x1d, 0x1f, 0x17, 0x1c, - 0xc3, 0xd6, 0x43, 0x2f, 0xed, 0x1b, 0xeb, 0xf2, 0x0a, 0x7b, 0xea, 0xb1, 0x2d, 0xb1, - 0x42, 0xf9, 0x4a, 0x0c, - ], - note_cm: [ - 0xab, 0x7f, 0xc5, 0x66, 0x87, 0x3c, 0xcd, 0xe6, 0x71, 0xf5, 0x98, 0x27, 0x67, 0x85, - 0x60, 0xa0, 0x06, 0xf8, 0x2b, 0xb7, 0xad, 0xcd, 0x75, 0x22, 0x3f, 0xa8, 0x59, 0x36, - 0xf7, 0x8c, 0x2b, 0x23, - ], - note_pos: 1051032776, - note_nf: [ - 0xd2, 0xe8, 0x87, 0xbd, 0x85, 0x4a, 0x80, 0x2b, 0xce, 0x85, 0x70, 0x53, 0x02, 0x0f, - 0x5d, 0x3e, 0x7c, 0x8a, 0xe5, 0x26, 0x7c, 0x5b, 0x65, 0x83, 0xb3, 0xd2, 0x12, 0xcc, - 0x8b, 0xb6, 0x98, 0x90, - ], - }, - TestVector { - sk: [ - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, - ], - ask: [ - 0x03, 0x9d, 0xd9, 0x3d, 0xf3, 0x11, 0xff, 0x8f, 0xba, 0xb3, 0xfe, 0x23, 0x02, 0x19, - 0xcd, 0x42, 0xac, 0x87, 0x94, 0x84, 0xf3, 0x0b, 0x90, 0x3a, 0x3c, 0x1e, 0x67, 0xcc, - 0xca, 0x5a, 0x7b, 0x0d, - ], - nsk: [ - 0x04, 0x9f, 0xa1, 0x4f, 0x48, 0x6c, 0x75, 0xb9, 0xfa, 0xd7, 0xe3, 0xb6, 0x73, 0xa4, - 0x43, 0xdd, 0x07, 0x4e, 0xaa, 0x96, 0xed, 0xcb, 0x2a, 0x53, 0xea, 0xaa, 0xbd, 0xaf, - 0x70, 0xff, 0xbb, 0x08, - ], - ovk: [ - 0x14, 0x7d, 0xd1, 0x1d, 0x77, 0xeb, 0xa1, 0xb1, 0x63, 0x6f, 0xd6, 0x19, 0x0c, 0x62, - 0xb9, 0xa5, 0xd0, 0x48, 0x1b, 0xee, 0x7e, 0x91, 0x7f, 0xab, 0x02, 0xe2, 0x18, 0x58, - 0x06, 0x3a, 0xb5, 0x04, - ], - ak: [ - 0x36, 0x40, 0x48, 0xee, 0xdb, 0xe8, 0xca, 0x20, 0x5e, 0xb7, 0xe7, 0xba, 0x0a, 0x90, - 0x12, 0x16, 0x6c, 0x7c, 0x7b, 0xd9, 0xeb, 0x22, 0x8e, 0x08, 0x48, 0x14, 0x48, 0xc4, - 0x88, 0xaa, 0x21, 0xd2, - ], - nk: [ - 0xed, 0x60, 0xaf, 0x1c, 0xe7, 0xdf, 0x38, 0x07, 0x0d, 0x38, 0x51, 0x43, 0x2a, 0x96, - 0x48, 0x0d, 0xb0, 0xb4, 0x17, 0xc3, 0x68, 0x2a, 0x1d, 0x68, 0xe3, 0xe8, 0x93, 0x34, - 0x23, 0x5c, 0x0b, 0xdf, - ], - ivk: [ - 0x99, 0xc9, 0xb4, 0xb8, 0x4f, 0x4b, 0x4e, 0x35, 0x0f, 0x78, 0x7d, 0x1c, 0xf7, 0x05, - 0x1d, 0x50, 0xec, 0xc3, 0x4b, 0x1a, 0x5b, 0x20, 0xd2, 0xd2, 0x13, 0x9b, 0x4a, 0xf1, - 0xf1, 0x60, 0xe0, 0x01, - ], - default_d: [ - 0x21, 0xc9, 0x0e, 0x1c, 0x65, 0x8b, 0x3e, 0xfe, 0x86, 0xaf, 0x58, - ], - default_pk_d: [ - 0x9e, 0x64, 0x17, 0x4b, 0x4a, 0xb9, 0x81, 0x40, 0x5c, 0x32, 0x3b, 0x5e, 0x12, 0x47, - 0x59, 0x45, 0xa4, 0x6d, 0x4f, 0xed, 0xf8, 0x06, 0x08, 0x28, 0x04, 0x1c, 0xd2, 0x0e, - 0x62, 0xfd, 0x2c, 0xef, - ], - note_v: 5584102310880684544, - note_r: [ - 0x8c, 0x3e, 0x56, 0x44, 0x9d, 0xc8, 0x63, 0x54, 0xd3, 0x3b, 0x02, 0x5e, 0xf2, 0x79, - 0x34, 0x60, 0xbc, 0xb1, 0x69, 0xf3, 0x32, 0x4e, 0x4a, 0x6b, 0x64, 0xba, 0xa6, 0x08, - 0x32, 0x31, 0x57, 0x04, - ], - note_cm: [ - 0x7b, 0x48, 0xa8, 0x37, 0x5d, 0x3e, 0xbd, 0x56, 0xbc, 0x64, 0x9b, 0xb5, 0xb5, 0x24, - 0x23, 0x36, 0xc2, 0xa0, 0x5a, 0x08, 0x03, 0x23, 0x9b, 0x5b, 0x88, 0xfd, 0x92, 0x07, - 0x8f, 0xea, 0x4d, 0x04, - ], - note_pos: 1814747072, - note_nf: [ - 0xa8, 0x2f, 0x17, 0x50, 0xcc, 0x5b, 0x2b, 0xee, 0x64, 0x9a, 0x36, 0x5c, 0x04, 0x20, - 0xed, 0x87, 0x07, 0x5b, 0x88, 0x71, 0xfd, 0xa4, 0xa7, 0xf5, 0x84, 0x0d, 0x6b, 0xbe, - 0xb1, 0x7c, 0xd6, 0x20, - ], - }, - TestVector { - sk: [ - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, - ], - ask: [ - 0xeb, 0xbb, 0x40, 0xa9, 0x80, 0xba, 0x3b, 0x88, 0x60, 0x94, 0x8d, 0x01, 0x1e, 0x1b, - 0xfb, 0x4a, 0xff, 0xe1, 0x6c, 0x65, 0x2e, 0x90, 0xe9, 0x82, 0x58, 0x30, 0x2f, 0x44, - 0x64, 0xc9, 0x1e, 0x0c, - ], - nsk: [ - 0x68, 0x43, 0x1b, 0x19, 0x91, 0x04, 0x21, 0x52, 0x00, 0xb9, 0x5e, 0xe5, 0xcb, 0x71, - 0xbf, 0x8b, 0x88, 0x3a, 0x3e, 0x95, 0xb7, 0x98, 0x9c, 0xad, 0x19, 0x70, 0x63, 0x14, - 0x1e, 0xbb, 0xfd, 0x00, - ], - ovk: [ - 0x57, 0x34, 0x67, 0xa7, 0xb3, 0x0e, 0xad, 0x6c, 0xcc, 0x50, 0x47, 0x44, 0xca, 0x9e, - 0x1a, 0x28, 0x1a, 0x0d, 0x1a, 0x08, 0x73, 0x8b, 0x06, 0xa0, 0x68, 0x4f, 0xea, 0xcd, - 0x1e, 0x9d, 0x12, 0x6d, - ], - ak: [ - 0x71, 0xc3, 0x52, 0x3e, 0xec, 0xa3, 0x53, 0x11, 0xfb, 0xd5, 0xd7, 0xe7, 0xd7, 0x0b, - 0x70, 0x9d, 0x6c, 0x35, 0xa2, 0x4f, 0x26, 0x2b, 0x34, 0xbf, 0x64, 0x05, 0x9b, 0xf2, - 0xc0, 0x2e, 0x0b, 0xa8, - ], - nk: [ - 0x62, 0x44, 0x00, 0x10, 0x3b, 0x65, 0x69, 0xb7, 0x35, 0x8f, 0xe8, 0x0f, 0x6f, 0x6c, - 0xad, 0x43, 0x25, 0xde, 0xfd, 0xa9, 0xd9, 0x49, 0x9c, 0x2b, 0x8f, 0x88, 0x6a, 0x62, - 0x69, 0xa2, 0xaa, 0x52, - ], - ivk: [ - 0xdb, 0x95, 0xea, 0x8b, 0xd9, 0xf9, 0x3d, 0x41, 0xb5, 0xab, 0x2b, 0xeb, 0xc9, 0x1a, - 0x38, 0xed, 0xd5, 0x27, 0x08, 0x3e, 0x2a, 0x6e, 0xf9, 0xf3, 0xc2, 0x97, 0x02, 0xd5, - 0xff, 0x89, 0xed, 0x00, - ], - default_d: [ - 0x23, 0x3c, 0x4a, 0xb8, 0x86, 0xa5, 0x5e, 0x3b, 0xa3, 0x74, 0xc0, - ], - default_pk_d: [ - 0xb6, 0x8e, 0x9e, 0xe0, 0xc0, 0x67, 0x8d, 0x7b, 0x30, 0x36, 0x93, 0x1c, 0x83, 0x1a, - 0x25, 0x25, 0x5f, 0x7e, 0xe4, 0x87, 0x38, 0x5a, 0x30, 0x31, 0x6e, 0x15, 0xf6, 0x48, - 0x2b, 0x87, 0x4f, 0xda, - ], - note_v: 17811330145809239872, - note_r: [ - 0x6e, 0xbb, 0xed, 0x74, 0x36, 0x19, 0xa2, 0x56, 0xf9, 0xad, 0x2e, 0x85, 0x88, 0x0c, - 0xfa, 0xa9, 0x09, 0x8a, 0x5f, 0xdb, 0x16, 0x29, 0x99, 0x0d, 0x9a, 0x7d, 0x3b, 0xb9, - 0x3f, 0xc9, 0x00, 0x03, - ], - note_cm: [ - 0xd3, 0x76, 0xa7, 0xbe, 0xe8, 0xce, 0x67, 0xf4, 0xef, 0xde, 0x56, 0xaa, 0x77, 0xcf, - 0x64, 0x41, 0x9b, 0x0e, 0x55, 0x0a, 0xbb, 0xcb, 0x8e, 0x2b, 0xcb, 0xda, 0x8b, 0x63, - 0xe4, 0x1d, 0xeb, 0x37, - ], - note_pos: 2578461368, - note_nf: [ - 0x65, 0x36, 0x74, 0x87, 0x3b, 0x3c, 0x67, 0x0c, 0x58, 0x85, 0x84, 0x73, 0xe7, 0xfe, - 0x72, 0x19, 0x72, 0xfb, 0x96, 0xe2, 0x15, 0xb8, 0x73, 0x77, 0xa1, 0x7c, 0xa3, 0x71, - 0x0d, 0x93, 0xc9, 0xe9, - ], - }, - ]; - - for tv in test_vectors { - // Compute commitment and compare with test vector - let mut result = [0u8; 32]; - assert!(librustzcash_sapling_compute_cm( - &tv.default_d, - &tv.default_pk_d, - tv.note_v, - &tv.note_r, - &mut result - )); - assert_eq!(&result, &tv.note_cm); - - // Compute nullifier and compare with test vector - assert!(librustzcash_sapling_compute_nf( - &tv.default_d, - &tv.default_pk_d, - tv.note_v, - &tv.note_r, - &tv.ak, - &tv.nk, - tv.note_pos, - &mut result - )); - assert_eq!(&result, &tv.note_nf); - } -} diff --git a/librustzcash/src/tests/signatures.rs b/librustzcash/src/tests/signatures.rs deleted file mode 100644 index 23fc75b..0000000 --- a/librustzcash/src/tests/signatures.rs +++ /dev/null @@ -1,515 +0,0 @@ -use pairing::{bls12_381::Bls12, PrimeField, PrimeFieldRepr}; -use sapling_crypto::{ - jubjub::{FixedGenerators, JubjubEngine}, - redjubjub::{PrivateKey, PublicKey, Signature}, -}; - -use super::JUBJUB; - -#[test] -fn redjubjub_signatures() { - struct TestVector { - sk: [u8; 32], - vk: [u8; 32], - alpha: [u8; 32], - rsk: [u8; 32], - rvk: [u8; 32], - m: [u8; 32], - sig: [u8; 64], - rsig: [u8; 64], - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_signatures.py - let test_vectors = vec![ - TestVector { - sk: [ - 0x18, 0xe2, 0x8d, 0xea, 0x5c, 0x11, 0x81, 0x7a, 0xee, 0xb2, 0x1a, 0x19, 0x98, 0x1d, - 0x28, 0x36, 0x8e, 0xc4, 0x38, 0xaf, 0xc2, 0x5a, 0x8d, 0xb9, 0x4e, 0xbe, 0x08, 0xd7, - 0xa0, 0x28, 0x8e, 0x09, - ], - vk: [ - 0x9b, 0x01, 0x53, 0xb0, 0x3d, 0x32, 0x0f, 0xe2, 0x3e, 0x28, 0x34, 0xd5, 0xd6, 0x1d, - 0xbb, 0x1f, 0x51, 0x9b, 0x3f, 0x41, 0xf8, 0xf9, 0x46, 0x15, 0x2b, 0xf0, 0xc3, 0xf2, - 0x47, 0xd1, 0x18, 0x07, - ], - alpha: [ - 0xff, 0xd1, 0xa1, 0x27, 0x32, 0x52, 0xb1, 0x87, 0xf4, 0xed, 0x32, 0x6d, 0xfc, 0x98, - 0x85, 0x3e, 0x29, 0x17, 0xc2, 0xb3, 0x63, 0x79, 0xb1, 0x75, 0xda, 0x63, 0xb9, 0xef, - 0x6d, 0xda, 0x6c, 0x08, - ], - rsk: [ - 0x60, 0x87, 0x38, 0x3b, 0x30, 0x55, 0x9b, 0x31, 0x60, 0x90, 0x85, 0xb9, 0x00, 0x96, - 0x45, 0xce, 0xb6, 0xa0, 0xc6, 0x61, 0x25, 0x99, 0xd7, 0x28, 0x80, 0x72, 0x8e, 0x61, - 0x24, 0x4e, 0x7d, 0x03, - ], - rvk: [ - 0xc1, 0xba, 0xbc, 0xb6, 0xea, 0xe2, 0xb9, 0x94, 0xee, 0x6d, 0x65, 0xc1, 0x0b, 0x9d, - 0xad, 0x59, 0x40, 0xdc, 0x73, 0x5b, 0x07, 0x50, 0x4d, 0xae, 0xd1, 0xe4, 0x6b, 0x07, - 0x09, 0xb4, 0x51, 0x36, - ], - m: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - sig: [ - 0xea, 0xa0, 0x57, 0x47, 0x6b, 0x4a, 0xb4, 0x82, 0x28, 0x8b, 0x93, 0xdf, 0x8f, 0xe0, - 0xc5, 0xce, 0x9d, 0x78, 0x83, 0x67, 0xf2, 0xbe, 0x55, 0x1b, 0x7f, 0x7a, 0x82, 0xa6, - 0xdb, 0x36, 0x04, 0x68, 0xde, 0xb9, 0xa7, 0xb7, 0xaf, 0xaa, 0xdf, 0xec, 0xa6, 0xf4, - 0x81, 0x19, 0x3d, 0xc6, 0x57, 0x57, 0x47, 0xf6, 0x0a, 0x1a, 0x8a, 0x48, 0xff, 0x0a, - 0xd7, 0x0c, 0xf8, 0xcb, 0x8d, 0x52, 0x8e, 0x08, - ], - rsig: [ - 0xd5, 0x6f, 0x0d, 0x91, 0xaf, 0x42, 0x4e, 0x1f, 0x1c, 0x7f, 0xb8, 0x6b, 0xa4, 0xee, - 0xd1, 0x43, 0xcc, 0x16, 0x66, 0x0c, 0x5f, 0xe8, 0xd7, 0xdc, 0x0d, 0x28, 0x4b, 0xcf, - 0x65, 0xa0, 0x89, 0xe9, 0x8b, 0x56, 0x1f, 0x9f, 0x20, 0x1a, 0x63, 0x3d, 0x70, 0x0c, - 0xd3, 0x98, 0x1e, 0x8c, 0xac, 0x07, 0xb5, 0xa8, 0x7e, 0xfa, 0x61, 0x86, 0x06, 0x2d, - 0xd8, 0xe5, 0xd6, 0x32, 0x5e, 0x7b, 0x82, 0x02, - ], - }, - TestVector { - sk: [ - 0x05, 0x96, 0x54, 0xf9, 0x61, 0x27, 0x3d, 0xaf, 0xda, 0x3b, 0x26, 0x77, 0xb3, 0x5c, - 0x18, 0xaf, 0x6b, 0x11, 0xad, 0xfb, 0x9e, 0xe9, 0x0b, 0x48, 0x93, 0x5e, 0x55, 0x7c, - 0x8d, 0x5d, 0x9c, 0x04, - ], - vk: [ - 0xfa, 0xf6, 0xc3, 0xb7, 0x37, 0xe8, 0xe6, 0x11, 0xaa, 0xfe, 0xa5, 0x2f, 0x03, 0xbb, - 0x27, 0x86, 0xe1, 0x83, 0x53, 0xeb, 0xe0, 0xd3, 0x13, 0x9e, 0x3c, 0x54, 0x49, 0x87, - 0x80, 0xc8, 0xc1, 0x99, - ], - alpha: [ - 0xc3, 0x0b, 0x96, 0x20, 0x8d, 0xa8, 0x00, 0xe1, 0x0a, 0xf0, 0x25, 0x42, 0xce, 0x69, - 0x4b, 0x7e, 0xd7, 0x6a, 0x28, 0x29, 0x9f, 0x85, 0x99, 0x8e, 0x5d, 0x61, 0x08, 0x12, - 0x68, 0x1b, 0xf0, 0x03, - ], - rsk: [ - 0xc8, 0xa1, 0xea, 0x19, 0xef, 0xcf, 0x3d, 0x90, 0xe5, 0x2b, 0x4c, 0xb9, 0x81, 0xc6, - 0x63, 0x2d, 0x43, 0x7c, 0xd5, 0x24, 0x3e, 0x6f, 0xa5, 0xd6, 0xf0, 0xbf, 0x5d, 0x8e, - 0xf5, 0x78, 0x8c, 0x08, - ], - rvk: [ - 0xd5, 0x24, 0xdc, 0xe7, 0x73, 0x40, 0x69, 0x75, 0x8a, 0x91, 0xf0, 0x07, 0xa8, 0x69, - 0x50, 0x5d, 0xfc, 0x4a, 0xba, 0x17, 0x20, 0x59, 0x4d, 0x4d, 0x74, 0xf0, 0x07, 0x70, - 0x0e, 0x62, 0xee, 0x00, - ], - m: [ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, - ], - sig: [ - 0x22, 0x35, 0x54, 0x94, 0xa8, 0x31, 0x6a, 0xb1, 0x34, 0x73, 0xf5, 0x5e, 0x62, 0x66, - 0xb2, 0xfb, 0x41, 0x97, 0x31, 0x5e, 0xac, 0x62, 0xf8, 0x2c, 0xc7, 0x3d, 0xca, 0xca, - 0x19, 0x90, 0x90, 0xf1, 0x5b, 0xe1, 0x98, 0xce, 0x7d, 0x3f, 0x9f, 0xc8, 0xff, 0xf5, - 0x50, 0xe1, 0x08, 0x81, 0xec, 0x49, 0xff, 0x27, 0x36, 0x9e, 0x7d, 0x4f, 0xd9, 0x64, - 0x01, 0x53, 0x49, 0x2a, 0x0a, 0x06, 0x25, 0x08, - ], - rsig: [ - 0xf4, 0xb8, 0x94, 0xba, 0x84, 0xce, 0x1e, 0xc3, 0x8a, 0x63, 0x15, 0x2f, 0xc4, 0x09, - 0xf9, 0x47, 0xd6, 0x1a, 0xbb, 0x1f, 0x48, 0x91, 0x63, 0x6b, 0xc3, 0xee, 0x19, 0xef, - 0x6d, 0x4b, 0x30, 0xc0, 0xfd, 0x22, 0x86, 0x6b, 0x84, 0xff, 0xbc, 0x7e, 0x2a, 0x78, - 0xc4, 0x3f, 0x57, 0x83, 0xd2, 0xd2, 0xea, 0xd0, 0x78, 0x59, 0x55, 0x03, 0x74, 0x43, - 0xc2, 0xf4, 0xd5, 0x2f, 0x78, 0x5e, 0xee, 0x07, - ], - }, - TestVector { - sk: [ - 0xad, 0xe7, 0xab, 0xb5, 0x51, 0xc7, 0x9d, 0x0f, 0x0e, 0x42, 0xef, 0x7f, 0x12, 0x06, - 0xb8, 0x77, 0x12, 0xa8, 0x4a, 0x61, 0xde, 0xa3, 0xf3, 0x7b, 0x42, 0x49, 0x6d, 0x7e, - 0xfd, 0x12, 0x52, 0x0c, - ], - vk: [ - 0x36, 0x9e, 0xa7, 0x51, 0x76, 0x2f, 0x83, 0x9d, 0x25, 0x70, 0x1a, 0x5e, 0xeb, 0x55, - 0x1e, 0xc4, 0xf0, 0x6c, 0x12, 0x90, 0xb3, 0xb9, 0xc3, 0xa7, 0x24, 0x40, 0x2d, 0xec, - 0x02, 0x73, 0x92, 0x21, - ], - alpha: [ - 0x81, 0x92, 0x25, 0x29, 0xa6, 0x3e, 0xe7, 0x43, 0xfc, 0x4f, 0xbb, 0xac, 0x45, 0xc4, - 0x98, 0x83, 0x16, 0xbc, 0x9b, 0x6e, 0x42, 0x8b, 0x01, 0xa8, 0xd3, 0x1f, 0xc1, 0xc2, - 0xa6, 0xca, 0x62, 0x05, - ], - rsk: [ - 0x77, 0x4d, 0xda, 0x07, 0x99, 0xf7, 0xed, 0x82, 0x87, 0x81, 0xe2, 0x5f, 0xc4, 0xa9, - 0xe8, 0x54, 0x28, 0x29, 0xb2, 0xce, 0x1f, 0xf4, 0x8d, 0x1d, 0x6d, 0xb9, 0xfa, 0xdb, - 0xb9, 0x28, 0x37, 0x03, - ], - rvk: [ - 0x0d, 0x92, 0xad, 0x6d, 0x46, 0xed, 0xac, 0xd0, 0x23, 0xd4, 0xd2, 0xef, 0x70, 0x3a, - 0x6c, 0xa0, 0xa7, 0x92, 0xcf, 0xc4, 0xb7, 0xda, 0x11, 0xc2, 0x35, 0x3b, 0xc8, 0x45, - 0xa2, 0x7a, 0x97, 0x4d, - ], - m: [ - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, - ], - sig: [ - 0xdd, 0x65, 0x21, 0x01, 0x4d, 0xff, 0x70, 0x6e, 0x3a, 0x38, 0x52, 0x7a, 0x86, 0xb6, - 0xc1, 0x6e, 0x94, 0x14, 0x80, 0xe7, 0x33, 0xef, 0xf7, 0x9e, 0xbe, 0x0c, 0x43, 0x03, - 0x79, 0xd7, 0x57, 0x04, 0x9d, 0xb7, 0x90, 0xcd, 0x5e, 0x14, 0x44, 0x7c, 0x38, 0x6f, - 0x5f, 0xcb, 0x41, 0x9f, 0x27, 0xc4, 0x41, 0x3f, 0x35, 0x88, 0xfa, 0x21, 0x42, 0xd2, - 0xcf, 0xba, 0xed, 0x08, 0x2c, 0xc6, 0xdb, 0x07, - ], - rsig: [ - 0xd8, 0x94, 0x45, 0xcb, 0x9b, 0xd1, 0x03, 0x35, 0x69, 0x23, 0x1d, 0xd6, 0x28, 0xaa, - 0x62, 0x81, 0x09, 0xfe, 0x93, 0x50, 0x2b, 0xf2, 0x2f, 0x9a, 0x5f, 0x37, 0xb1, 0x4e, - 0x51, 0x7f, 0x9a, 0x20, 0x54, 0xae, 0xe3, 0xc8, 0x1b, 0x60, 0xb3, 0xf0, 0x55, 0x1e, - 0x32, 0xf7, 0x93, 0x5a, 0xbc, 0x2f, 0x37, 0xb9, 0x9a, 0xb3, 0xec, 0x99, 0x68, 0x02, - 0xef, 0xd6, 0x50, 0x69, 0xe1, 0x28, 0x12, 0x08, - ], - }, - TestVector { - sk: [ - 0xc9, 0xd2, 0xae, 0x1f, 0x6d, 0x32, 0xa6, 0x75, 0xd0, 0x9e, 0xb0, 0x82, 0x3f, 0x46, - 0x7f, 0xa9, 0x21, 0xb3, 0x28, 0x4a, 0xcb, 0x35, 0xfa, 0xbd, 0xfc, 0x99, 0x4d, 0xe5, - 0x49, 0xb8, 0x59, 0x0d, - ], - vk: [ - 0x2d, 0x2f, 0x31, 0x6e, 0x5c, 0x36, 0x9a, 0xe4, 0xdd, 0x2c, 0x82, 0x5f, 0x3d, 0x86, - 0x46, 0x00, 0x58, 0x40, 0x71, 0x84, 0x60, 0x3b, 0x21, 0x2c, 0xf3, 0x45, 0x9f, 0x36, - 0xc8, 0x69, 0x7f, 0xd8, - ], - alpha: [ - 0xeb, 0xbc, 0x89, 0x03, 0x11, 0x07, 0xc4, 0x4f, 0x47, 0x88, 0x9e, 0xd4, 0xd4, 0x37, - 0x5a, 0x41, 0x14, 0xcf, 0x8a, 0x75, 0xdd, 0x33, 0xb9, 0x62, 0xf2, 0xd7, 0x59, 0xd3, - 0xf4, 0xc6, 0xdf, 0x06, - ], - rsk: [ - 0xfd, 0x62, 0x41, 0x4c, 0x1f, 0x2b, 0xd3, 0xf4, 0x94, 0x16, 0x87, 0x8a, 0x80, 0x5d, - 0x71, 0x44, 0x35, 0x47, 0x7f, 0xbe, 0xa7, 0x2e, 0x4c, 0x1a, 0x46, 0xc2, 0x73, 0x53, - 0x54, 0xca, 0xbb, 0x05, - ], - rvk: [ - 0xf0, 0x43, 0x0e, 0x95, 0x3b, 0xe6, 0x0b, 0xf4, 0x38, 0xdb, 0xdc, 0xc2, 0x30, 0x3f, - 0x0e, 0x32, 0xa6, 0xf7, 0xce, 0x2f, 0xbe, 0xdf, 0xb1, 0x3a, 0xc5, 0x18, 0xf7, 0x5a, - 0x3f, 0xd1, 0x0e, 0xb5, - ], - m: [ - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, - ], - sig: [ - 0x72, 0x79, 0xa7, 0x5c, 0x01, 0x36, 0x75, 0xb3, 0x29, 0x84, 0xe5, 0xc7, 0x3a, 0x98, - 0x91, 0xeb, 0xf0, 0xb2, 0x29, 0xb1, 0x6e, 0x62, 0x35, 0xba, 0x36, 0xdf, 0xa1, 0xb5, - 0xa1, 0x0c, 0x5e, 0x44, 0x57, 0x81, 0x91, 0x89, 0x7c, 0x06, 0xb8, 0x52, 0x4a, 0x26, - 0x74, 0xaa, 0x7a, 0x0c, 0x8c, 0x23, 0x5f, 0x52, 0xd3, 0x3a, 0xc9, 0x2c, 0x70, 0x56, - 0xb2, 0xbe, 0x95, 0x3c, 0x3f, 0xaa, 0x3d, 0x07, - ], - rsig: [ - 0xaa, 0xd4, 0x82, 0x8c, 0xb3, 0x42, 0xcf, 0x09, 0xb0, 0x0e, 0x30, 0x2c, 0xbb, 0xe7, - 0xcc, 0x3e, 0x95, 0xfe, 0x1f, 0xf8, 0x28, 0x74, 0x8e, 0x5f, 0x5b, 0xc6, 0x9c, 0xbf, - 0xde, 0x6e, 0x27, 0x22, 0xd7, 0x64, 0x35, 0x68, 0x7e, 0x85, 0x0c, 0xd3, 0x07, 0xa9, - 0xc1, 0x82, 0xec, 0x10, 0xe6, 0x88, 0x1d, 0xd6, 0x5e, 0xed, 0xc1, 0x1f, 0xa7, 0xb4, - 0x6d, 0xe3, 0xa7, 0x19, 0x59, 0xce, 0xc0, 0x02, - ], - }, - TestVector { - sk: [ - 0x33, 0xbc, 0xd2, 0x86, 0x45, 0x41, 0xb8, 0xbb, 0x7f, 0xdc, 0x77, 0xa1, 0x9d, 0x97, - 0x0f, 0x92, 0x4e, 0xae, 0xec, 0xf4, 0x10, 0x3c, 0x38, 0xc8, 0xd2, 0xb0, 0x66, 0x81, - 0x42, 0xf2, 0x7d, 0x09, - ], - vk: [ - 0x74, 0x17, 0x94, 0xe6, 0x2c, 0xf9, 0x32, 0x0c, 0x58, 0xba, 0xc5, 0x94, 0xa2, 0xb9, - 0x0e, 0x34, 0x0a, 0x6d, 0x8a, 0x68, 0x05, 0x6f, 0x6e, 0xd5, 0xc7, 0x86, 0x8c, 0x5f, - 0xf3, 0xe4, 0xd6, 0x16, - ], - alpha: [ - 0x7c, 0xe7, 0x25, 0xa5, 0xfe, 0xf6, 0x1b, 0xd4, 0xa1, 0xe9, 0xc7, 0x73, 0x28, 0xe8, - 0x21, 0x0e, 0xb7, 0x29, 0x2d, 0x95, 0x4c, 0x64, 0xe9, 0x9e, 0x8b, 0xed, 0xd0, 0x7a, - 0xb3, 0xab, 0x0e, 0x0d, - ], - rsk: [ - 0xf8, 0x76, 0x01, 0x55, 0xe5, 0x29, 0x3d, 0xbf, 0x9e, 0xb5, 0x77, 0x48, 0x32, 0x5f, - 0xc9, 0xf9, 0x04, 0x9d, 0xe5, 0x88, 0x5c, 0x65, 0xba, 0x60, 0xb5, 0xee, 0x03, 0x97, - 0x0b, 0xe9, 0x0e, 0x08, - ], - rvk: [ - 0x66, 0x62, 0xba, 0x09, 0x95, 0x0a, 0xcc, 0xd2, 0xce, 0xa3, 0xc7, 0xa8, 0x12, 0x90, - 0xcd, 0x59, 0x78, 0xa6, 0x2b, 0x5a, 0xc5, 0xbb, 0xc4, 0x8d, 0x9f, 0x58, 0x19, 0xcd, - 0xc9, 0x64, 0x6f, 0x0a, - ], - m: [ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, - ], - sig: [ - 0x51, 0x23, 0xb3, 0x1f, 0x84, 0xaf, 0x0c, 0x35, 0x5e, 0x13, 0xe7, 0x8a, 0x64, 0xd7, - 0xa3, 0xcd, 0xfd, 0x6b, 0xdf, 0xfd, 0xc7, 0x33, 0x38, 0xd9, 0x31, 0x7f, 0x73, 0x43, - 0x91, 0xa5, 0x5a, 0xe6, 0x25, 0x8f, 0x69, 0x80, 0xb9, 0xc7, 0xd1, 0x90, 0xcf, 0xa3, - 0x65, 0x81, 0xa9, 0xa4, 0x7a, 0x86, 0x3f, 0xd3, 0xbf, 0x76, 0x59, 0x42, 0x22, 0x95, - 0xb7, 0x5f, 0xd1, 0x22, 0xc3, 0xdd, 0x8a, 0x05, - ], - rsig: [ - 0x5b, 0xae, 0x25, 0x4f, 0xbd, 0xed, 0x60, 0x7a, 0x5c, 0x48, 0xb5, 0x30, 0x29, 0xf5, - 0x9b, 0xa7, 0x06, 0x32, 0x48, 0x79, 0xaa, 0x18, 0xd9, 0xc4, 0x73, 0x19, 0x00, 0x4b, - 0xe0, 0x2c, 0xec, 0xe0, 0xb8, 0xbb, 0x02, 0x4a, 0x7a, 0xab, 0xaa, 0x0a, 0x64, 0x0f, - 0x3a, 0x54, 0xdc, 0xda, 0xf2, 0x11, 0x31, 0x46, 0x9a, 0x50, 0x06, 0xbe, 0x27, 0x81, - 0xa5, 0x67, 0xff, 0xa6, 0x50, 0x3a, 0x35, 0x03, - ], - }, - TestVector { - sk: [ - 0xca, 0x35, 0x06, 0xd6, 0xaf, 0x77, 0x67, 0xb5, 0x79, 0x0e, 0xf0, 0xc5, 0x19, 0x0f, - 0xb3, 0xf3, 0x87, 0x7c, 0x4a, 0xab, 0x40, 0xe0, 0xdd, 0x65, 0x1a, 0xbb, 0xda, 0xcb, - 0x54, 0x4e, 0xd0, 0x05, - ], - vk: [ - 0xba, 0xb6, 0xcf, 0xb5, 0xc8, 0xea, 0x34, 0x91, 0x25, 0x1b, 0x46, 0xd5, 0x2a, 0xca, - 0x25, 0xd9, 0xe9, 0xaf, 0x69, 0xfa, 0xa9, 0xb4, 0xe4, 0x0b, 0x03, 0xad, 0x00, 0x86, - 0xde, 0x59, 0xb5, 0x1f, - ], - alpha: [ - 0xbe, 0xa3, 0x87, 0x20, 0x3f, 0x43, 0x76, 0x0a, 0xd3, 0x7d, 0x61, 0xde, 0x0e, 0xb5, - 0x9f, 0xca, 0x6c, 0xab, 0x75, 0x60, 0xdf, 0x64, 0xfa, 0xbb, 0x95, 0x11, 0x57, 0x9f, - 0x6f, 0x68, 0x26, 0x06, - ], - rsk: [ - 0x88, 0xd9, 0x8d, 0xf6, 0xee, 0xba, 0xdd, 0xbf, 0x4c, 0x8c, 0x51, 0xa4, 0x28, 0xc4, - 0x52, 0xbe, 0xf4, 0x27, 0xc0, 0x0b, 0x20, 0x45, 0xd8, 0x21, 0xb0, 0xcc, 0x31, 0x6b, - 0xc4, 0xb6, 0xf6, 0x0b, - ], - rvk: [ - 0x11, 0x26, 0x7d, 0x14, 0xd5, 0xe0, 0xb2, 0xbb, 0x3c, 0xe0, 0x99, 0xe8, 0xef, 0x84, - 0x49, 0x47, 0x1c, 0xbc, 0xfc, 0x69, 0x39, 0xa4, 0xb3, 0x48, 0xde, 0xa2, 0xc1, 0x73, - 0x56, 0xa1, 0xe8, 0xdd, - ], - m: [ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, - ], - sig: [ - 0xdc, 0x18, 0xc8, 0x8d, 0x96, 0x44, 0x42, 0x40, 0x6d, 0x65, 0x0a, 0xa2, 0xff, 0xbd, - 0x83, 0xd1, 0x13, 0xbf, 0x6a, 0x19, 0xda, 0x78, 0xf2, 0x66, 0x5b, 0x29, 0x4f, 0xa5, - 0xfa, 0x45, 0x0b, 0x92, 0x81, 0xa0, 0x7e, 0x32, 0x0c, 0x1a, 0xa3, 0x1d, 0x32, 0x44, - 0x9e, 0x00, 0xc5, 0xc3, 0x2d, 0xb2, 0xf4, 0x13, 0xdf, 0x0b, 0x63, 0xd0, 0x72, 0x8f, - 0xa4, 0x09, 0x41, 0xa8, 0xda, 0x02, 0x4f, 0x01, - ], - rsig: [ - 0x59, 0xe2, 0xe8, 0x18, 0x76, 0x6c, 0x50, 0xfc, 0x8f, 0x38, 0x40, 0xb2, 0x72, 0xaf, - 0x9a, 0xd9, 0x47, 0x56, 0xc8, 0x41, 0x32, 0x95, 0xfc, 0x79, 0x5f, 0xaf, 0xbc, 0xc0, - 0x71, 0x8e, 0x6c, 0x08, 0x16, 0x9a, 0x00, 0xd5, 0x83, 0x02, 0x77, 0x2a, 0x28, 0x28, - 0x43, 0xe8, 0x88, 0xd9, 0x81, 0xfa, 0x04, 0x79, 0x5d, 0x01, 0x4c, 0xf9, 0xc8, 0xcd, - 0xb9, 0x07, 0xff, 0x1b, 0x43, 0x0d, 0x92, 0x00, - ], - }, - TestVector { - sk: [ - 0xbc, 0x27, 0x83, 0x8d, 0xe2, 0xa6, 0x14, 0xcf, 0xba, 0x6c, 0x3e, 0x92, 0x2a, 0x8f, - 0x84, 0x24, 0xd9, 0x85, 0x6f, 0x68, 0x16, 0xf3, 0xbc, 0x61, 0x02, 0x31, 0x3b, 0x7f, - 0xaf, 0x5c, 0x3a, 0x0c, - ], - vk: [ - 0xd7, 0x9b, 0xe9, 0xff, 0x22, 0x9a, 0x2e, 0x35, 0xf5, 0xbc, 0xa4, 0x48, 0xe5, 0xeb, - 0x4a, 0x8a, 0xa9, 0x7f, 0xb4, 0x18, 0x02, 0x91, 0x25, 0xcf, 0xba, 0xa7, 0x8a, 0x91, - 0xa3, 0x82, 0xb0, 0x94, - ], - alpha: [ - 0x21, 0xa7, 0x15, 0x0e, 0x19, 0x4f, 0xed, 0xfe, 0xf9, 0x0c, 0x5d, 0x10, 0xe4, 0x20, - 0x85, 0x8b, 0xca, 0x40, 0x04, 0x04, 0x0e, 0xb6, 0x81, 0xd1, 0x4e, 0x75, 0xc4, 0x47, - 0x13, 0x51, 0xcb, 0x02, - ], - rsk: [ - 0x26, 0xa2, 0xa1, 0xc4, 0x9c, 0xe7, 0x6a, 0xfd, 0x31, 0x69, 0xd3, 0xd5, 0x7a, 0x8f, - 0xa1, 0x09, 0xa3, 0x8b, 0x3f, 0x6b, 0x23, 0x6e, 0xd7, 0x2c, 0xa8, 0xf6, 0xcb, 0x61, - 0xd8, 0xf8, 0x87, 0x00, - ], - rvk: [ - 0x54, 0xbf, 0x1b, 0xe7, 0x2e, 0x6d, 0x41, 0x20, 0x8b, 0x8a, 0xec, 0x11, 0x61, 0xd3, - 0xba, 0x59, 0x51, 0x9f, 0xb9, 0x3d, 0xa0, 0x1a, 0x55, 0xe6, 0x78, 0xe2, 0x75, 0x20, - 0x06, 0x60, 0x36, 0xc9, - ], - m: [ - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, - ], - sig: [ - 0x9a, 0xf6, 0xf2, 0x80, 0x0f, 0x4b, 0x80, 0xf7, 0x93, 0xbe, 0x64, 0x8a, 0x43, 0x9f, - 0x86, 0xe5, 0x7d, 0xa1, 0xb9, 0x19, 0x99, 0x9e, 0x41, 0x91, 0x09, 0x99, 0xd4, 0x2e, - 0xd0, 0xf3, 0x89, 0x6d, 0xb7, 0x6e, 0x06, 0x38, 0x8b, 0x27, 0x2c, 0x99, 0x85, 0x8b, - 0x55, 0x04, 0xd0, 0x2e, 0xc6, 0xb4, 0xd5, 0x25, 0xb8, 0x71, 0x38, 0x10, 0x50, 0x5f, - 0x4f, 0xc0, 0x31, 0x08, 0x3a, 0x14, 0xbf, 0x09, - ], - rsig: [ - 0x3f, 0x7d, 0x50, 0x71, 0xb8, 0x76, 0x17, 0x49, 0x05, 0x71, 0xa8, 0xbe, 0x91, 0x74, - 0x9e, 0x69, 0xf6, 0xbc, 0xba, 0x5a, 0xb6, 0x26, 0xe4, 0x2f, 0xf9, 0x2d, 0x0d, 0x7d, - 0xab, 0x73, 0xf3, 0x03, 0x61, 0xe5, 0xa2, 0x24, 0x99, 0x8e, 0x1f, 0x5e, 0xa1, 0xe5, - 0xf8, 0x68, 0x9a, 0x06, 0xa2, 0x77, 0x48, 0xbf, 0x74, 0x19, 0x63, 0xef, 0x51, 0x33, - 0x22, 0xf4, 0xa1, 0xba, 0x99, 0xaa, 0x36, 0x03, - ], - }, - TestVector { - sk: [ - 0xb2, 0x08, 0x59, 0xb8, 0x8e, 0xe3, 0x33, 0x8a, 0x64, 0x95, 0x4f, 0x8a, 0x9e, 0x8e, - 0x9b, 0xf3, 0xe7, 0x11, 0x5a, 0xcf, 0x7c, 0x6e, 0x7f, 0x01, 0x43, 0x2c, 0x5f, 0x76, - 0x96, 0xd2, 0xd0, 0x05, - ], - vk: [ - 0xa8, 0x1f, 0xe6, 0x84, 0x6d, 0xbe, 0x0a, 0x75, 0xc0, 0xf4, 0x9b, 0x21, 0x32, 0x32, - 0xbe, 0xad, 0xd1, 0xf9, 0xa5, 0x64, 0x67, 0x3d, 0x25, 0xb9, 0x1e, 0xe0, 0xf1, 0x7c, - 0xe9, 0xca, 0xa3, 0x63, - ], - alpha: [ - 0x44, 0xd9, 0x08, 0xe1, 0xc1, 0x5e, 0x6b, 0xd9, 0x38, 0x0a, 0x8b, 0x23, 0x5a, 0xce, - 0x02, 0xfa, 0xc1, 0xc0, 0x87, 0x94, 0x45, 0x4b, 0xcd, 0xb4, 0xa6, 0xf4, 0x8c, 0xea, - 0x78, 0xa7, 0x4a, 0x04, - ], - rsk: [ - 0xf6, 0xe1, 0x61, 0x99, 0x50, 0x42, 0x9f, 0x63, 0x9d, 0x9f, 0xda, 0xad, 0xf8, 0x5c, - 0x9e, 0xed, 0xa9, 0xd2, 0xe1, 0x63, 0xc2, 0xb9, 0x4c, 0xb6, 0xe9, 0x20, 0xec, 0x60, - 0x0f, 0x7a, 0x1b, 0x0a, - ], - rvk: [ - 0x0b, 0x68, 0xd5, 0x0f, 0x91, 0x3c, 0xd1, 0xb7, 0x8b, 0x59, 0x92, 0x1e, 0x16, 0x56, - 0xd5, 0x76, 0xb0, 0xeb, 0x17, 0x1e, 0xd3, 0x87, 0x0d, 0x39, 0xfe, 0xc6, 0x94, 0x41, - 0xb3, 0x4b, 0x25, 0x38, - ], - m: [ - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, - ], - sig: [ - 0x64, 0x59, 0x67, 0x6a, 0x94, 0x16, 0x34, 0xec, 0xb6, 0x1e, 0x59, 0xb7, 0x9a, 0x98, - 0xab, 0xe5, 0x87, 0x6f, 0x35, 0x6f, 0x72, 0x8a, 0xa0, 0x9e, 0x0c, 0xca, 0x9e, 0xfe, - 0x05, 0x76, 0x1a, 0x33, 0x09, 0xaa, 0x88, 0xb2, 0xfa, 0x0e, 0xe2, 0xd0, 0x4c, 0x1c, - 0x46, 0xe9, 0xf2, 0xa0, 0x48, 0xd5, 0x9d, 0x55, 0x65, 0xaf, 0xa6, 0xc3, 0xf1, 0x5b, - 0xce, 0x70, 0x8d, 0xaa, 0xab, 0x7b, 0x34, 0x0e, - ], - rsig: [ - 0xc9, 0x66, 0x84, 0xec, 0x7e, 0xa6, 0x0b, 0xde, 0x87, 0x88, 0x22, 0xdd, 0xca, 0xf6, - 0xb8, 0xb0, 0xbd, 0x31, 0x98, 0x51, 0x54, 0xdf, 0x9a, 0xd4, 0xf6, 0x90, 0x7d, 0xf8, - 0xfe, 0xd9, 0x5c, 0x1d, 0x84, 0xfe, 0x67, 0xe6, 0x78, 0x75, 0xa5, 0x39, 0x55, 0x0e, - 0xb2, 0x51, 0x4f, 0x19, 0x3b, 0x8e, 0xd4, 0x57, 0x25, 0x6c, 0x8d, 0x30, 0x28, 0x1d, - 0x6f, 0x8b, 0xb9, 0x54, 0x49, 0x24, 0xca, 0x0c, - ], - }, - TestVector { - sk: [ - 0x32, 0x16, 0xae, 0x47, 0xe9, 0xf5, 0x3e, 0x8a, 0x52, 0x79, 0x6f, 0x24, 0xb6, 0x24, - 0x60, 0x77, 0x6b, 0xd5, 0xf2, 0x05, 0xa7, 0x8e, 0x15, 0x95, 0xbc, 0x8e, 0xfe, 0xdc, - 0x51, 0x9d, 0x36, 0x0b, - ], - vk: [ - 0xdf, 0x74, 0xbf, 0x04, 0x79, 0x61, 0xcc, 0x5c, 0xda, 0xc8, 0x28, 0x90, 0xc7, 0x6e, - 0xc6, 0x75, 0xbd, 0x4e, 0x89, 0xea, 0xd2, 0x80, 0xc9, 0x52, 0xd7, 0xc3, 0x3e, 0xea, - 0xf2, 0xb5, 0xa6, 0x6b, - ], - alpha: [ - 0xc9, 0x61, 0xf2, 0xdd, 0x93, 0x68, 0x2a, 0xdb, 0x93, 0xf5, 0xc0, 0x5a, 0x73, 0xfd, - 0xbc, 0x6d, 0x43, 0xc7, 0x0e, 0x1b, 0x15, 0xe8, 0xd5, 0x3e, 0x3f, 0x17, 0xa8, 0x24, - 0x94, 0xe3, 0xf2, 0x09, - ], - rsk: [ - 0x44, 0x4b, 0xa9, 0x4e, 0x1e, 0x50, 0xd2, 0x94, 0x63, 0x5e, 0x68, 0xb2, 0x95, 0x01, - 0xb5, 0x3e, 0xae, 0x61, 0xcd, 0x1f, 0xbb, 0x3b, 0x84, 0xcd, 0x52, 0xf6, 0x72, 0x9c, - 0xfb, 0xcb, 0xab, 0x06, - ], - rvk: [ - 0x0a, 0xfb, 0xe4, 0x06, 0xa8, 0x91, 0xc3, 0xb8, 0xc3, 0x10, 0xc2, 0x15, 0xbc, 0x68, - 0xa9, 0x13, 0xde, 0x7c, 0xda, 0x06, 0xaf, 0x29, 0x42, 0x00, 0x56, 0x46, 0x8d, 0x0c, - 0x08, 0x85, 0x5b, 0x28, - ], - m: [ - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, - ], - sig: [ - 0x24, 0x93, 0x2c, 0x1f, 0xaa, 0x01, 0x63, 0xca, 0x9a, 0x7f, 0xcd, 0xe4, 0x76, 0x11, - 0x29, 0xd2, 0xe5, 0xe9, 0x9c, 0xf5, 0xef, 0xa2, 0x5d, 0x27, 0x04, 0x58, 0x8e, 0x1c, - 0x75, 0x67, 0x7b, 0x5e, 0xeb, 0xe4, 0x55, 0x04, 0x8d, 0x7c, 0xe1, 0xb0, 0xd2, 0x01, - 0x27, 0x53, 0xf7, 0x1b, 0x27, 0x25, 0x01, 0x2e, 0xe1, 0x85, 0x49, 0x28, 0x73, 0x18, - 0xf9, 0xcd, 0x73, 0xf0, 0x7f, 0x0f, 0xb5, 0x02, - ], - rsig: [ - 0xf7, 0xfa, 0x26, 0xca, 0x22, 0xf3, 0x86, 0xc4, 0x3c, 0x19, 0x1a, 0x0b, 0x3e, 0xa6, - 0x57, 0x7e, 0x8e, 0xea, 0xa3, 0xf3, 0x6b, 0x9b, 0xd1, 0xa3, 0xac, 0x3d, 0xf6, 0xf8, - 0x83, 0xa3, 0xff, 0xdb, 0x31, 0x32, 0x0b, 0xde, 0x62, 0x7f, 0xf4, 0x6f, 0xc2, 0x26, - 0x4a, 0x32, 0x63, 0xb9, 0xab, 0x67, 0x12, 0x3b, 0xa5, 0xe1, 0x08, 0x43, 0x20, 0xd9, - 0x10, 0xb3, 0x94, 0xef, 0x8c, 0x65, 0xba, 0x09, - ], - }, - TestVector { - sk: [ - 0x85, 0x83, 0x6f, 0x98, 0x32, 0xb2, 0x8d, 0xe7, 0xc6, 0x36, 0x13, 0xe2, 0xa6, 0xed, - 0x36, 0xfb, 0x1a, 0xb4, 0x4f, 0xb0, 0xc1, 0x3f, 0xa8, 0x79, 0x8c, 0xd9, 0xcd, 0x30, - 0x30, 0xd4, 0x55, 0x03, - ], - vk: [ - 0xbf, 0xd5, 0xbc, 0x00, 0xc7, 0xc0, 0x22, 0xaa, 0x89, 0x01, 0xae, 0x08, 0x3c, 0x12, - 0xd5, 0x4b, 0x82, 0xf0, 0xdd, 0xff, 0x8e, 0xd6, 0xdb, 0x9a, 0x12, 0xd5, 0x9a, 0x5e, - 0xf6, 0xa5, 0xa2, 0xe0, - ], - alpha: [ - 0xa2, 0xe8, 0xb9, 0xe1, 0x6d, 0x6f, 0xf3, 0xca, 0x6c, 0x53, 0xd4, 0xe8, 0x8a, 0xbb, - 0xb9, 0x9b, 0xe7, 0xaf, 0x7e, 0x36, 0x59, 0x63, 0x1f, 0x1e, 0xae, 0x1e, 0xff, 0x23, - 0x87, 0x4d, 0x8e, 0x0c, - ], - rsk: [ - 0x70, 0x3f, 0x32, 0xa3, 0x41, 0x13, 0xea, 0xe1, 0xb0, 0x79, 0x1f, 0xfe, 0x9d, 0x88, - 0x88, 0xf0, 0x01, 0x29, 0x9a, 0xe5, 0x19, 0x68, 0x60, 0x91, 0x91, 0x48, 0x99, 0xef, - 0xcc, 0x6c, 0x66, 0x01, - ], - rvk: [ - 0xeb, 0x92, 0x97, 0x03, 0x6c, 0xf5, 0x17, 0xe1, 0x5e, 0x9e, 0xfe, 0x39, 0x75, 0x32, - 0x8d, 0xb4, 0x8e, 0xe7, 0xc2, 0x69, 0x4e, 0x94, 0x6d, 0xb2, 0x5f, 0x52, 0x87, 0x88, - 0xf6, 0xa1, 0xdb, 0x14, - ], - m: [ - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, - ], - sig: [ - 0x64, 0xab, 0xd1, 0x25, 0xbf, 0xc4, 0xc6, 0x54, 0xfa, 0xf2, 0xb6, 0xdd, 0x75, 0x3e, - 0xc6, 0x90, 0x22, 0x4d, 0xbc, 0xab, 0x8c, 0xd6, 0x32, 0xdd, 0x59, 0x3c, 0x91, 0xce, - 0x3a, 0xb0, 0xbc, 0xad, 0xca, 0x92, 0x76, 0x34, 0x02, 0x1c, 0x31, 0x47, 0x6c, 0x78, - 0xc5, 0xac, 0x7c, 0xcc, 0xab, 0xbd, 0x6f, 0x92, 0x7d, 0xf2, 0x05, 0xea, 0xa7, 0x07, - 0xcc, 0x00, 0xd4, 0x7d, 0x39, 0xf3, 0xe4, 0x0c, - ], - rsig: [ - 0xeb, 0x7a, 0x06, 0x5d, 0x75, 0xf8, 0x45, 0xdc, 0x09, 0x41, 0xb7, 0x09, 0xc0, 0xb1, - 0x49, 0xea, 0xfd, 0x80, 0x5e, 0xa5, 0x8f, 0x38, 0x0b, 0x92, 0xb9, 0xd3, 0x10, 0x8a, - 0x56, 0x1b, 0xda, 0x17, 0x85, 0xdf, 0x8f, 0x10, 0x1e, 0x0e, 0x14, 0x0f, 0xca, 0xee, - 0x99, 0xb7, 0xdb, 0xb7, 0xdf, 0xbf, 0x7e, 0x61, 0xf3, 0xa1, 0x2f, 0x46, 0x09, 0x50, - 0x69, 0xe0, 0x6e, 0x88, 0x96, 0xa9, 0xe4, 0x04, - ], - }, - ]; - - for tv in test_vectors { - let sk = PrivateKey::::read(&tv.sk[..]).unwrap(); - let vk = PublicKey::::read(&tv.vk[..], &JUBJUB).unwrap(); - let rvk = PublicKey::::read(&tv.rvk[..], &JUBJUB).unwrap(); - let sig = Signature::read(&tv.sig[..]).unwrap(); - let rsig = Signature::read(&tv.rsig[..]).unwrap(); - - let mut alpha_repr = <::Fs as PrimeField>::Repr::default(); - alpha_repr.read_le(&tv.alpha[..]).unwrap(); - let alpha = ::Fs::from_repr(alpha_repr).unwrap(); - - { - let mut vec = Vec::new(); - sk.randomize(alpha.clone()).write(&mut vec).unwrap(); - assert_eq!(&vec, &tv.rsk); - } - { - let mut vec = Vec::new(); - vk.randomize(alpha, FixedGenerators::SpendingKeyGenerator, &JUBJUB) - .write(&mut vec) - .unwrap(); - assert_eq!(&vec, &tv.rvk); - } - - assert!(vk.verify(&tv.m, &sig, FixedGenerators::SpendingKeyGenerator, &JUBJUB)); - assert!(rvk.verify(&tv.m, &rsig, FixedGenerators::SpendingKeyGenerator, &JUBJUB)); - assert!(!vk.verify(&tv.m, &rsig, FixedGenerators::SpendingKeyGenerator, &JUBJUB)); - assert!(!rvk.verify(&tv.m, &sig, FixedGenerators::SpendingKeyGenerator, &JUBJUB)); - } -} diff --git a/pairing/.gitignore b/pairing/.gitignore deleted file mode 100644 index 4308d82..0000000 --- a/pairing/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -target/ -**/*.rs.bk -Cargo.lock diff --git a/pairing/Cargo.toml b/pairing/Cargo.toml deleted file mode 100644 index 68971c3..0000000 --- a/pairing/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "pairing" - -# Remember to change version string in README.md. -version = "0.14.2" -authors = [ - "Sean Bowe ", - "Jack Grigg ", -] -license = "MIT/Apache-2.0" - -description = "Pairing-friendly elliptic curve library" -documentation = "https://docs.rs/pairing/" -homepage = "https://github.com/ebfull/pairing" -repository = "https://github.com/ebfull/pairing" - -[dependencies] -rand = "0.4" -byteorder = "1" -ff = { version = "0.4", features = ["derive"] } -group = "0.1" - -[features] -unstable-features = ["expose-arith"] -expose-arith = [] -default = [] diff --git a/pairing/LICENSE-APACHE b/pairing/LICENSE-APACHE deleted file mode 100644 index 16fe87b..0000000 --- a/pairing/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. diff --git a/pairing/LICENSE-MIT b/pairing/LICENSE-MIT deleted file mode 100644 index 31aa793..0000000 --- a/pairing/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/pairing/README.md b/pairing/README.md deleted file mode 100644 index bf386de..0000000 --- a/pairing/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# pairing [![Crates.io](https://img.shields.io/crates/v/pairing.svg)](https://crates.io/crates/pairing) # - -This is a Rust crate for using pairing-friendly elliptic curves. Currently, only the [BLS12-381](https://z.cash/blog/new-snark-curve.html) construction is implemented. - -## [Documentation](https://docs.rs/pairing/) - -Bring the `pairing` crate into your project just as you normally would. - -## Security Warnings - -This library does not make any guarantees about constant-time operations, memory access patterns, or resistance to side-channel attacks. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/sapling-crypto/.gitignore b/sapling-crypto/.gitignore deleted file mode 100644 index 6aa1064..0000000 --- a/sapling-crypto/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target/ -**/*.rs.bk -Cargo.lock diff --git a/sapling-crypto/COPYRIGHT b/sapling-crypto/COPYRIGHT deleted file mode 100644 index f2c6a3b..0000000 --- a/sapling-crypto/COPYRIGHT +++ /dev/null @@ -1,14 +0,0 @@ -Copyrights in the "sapling-crypto" library are retained by their contributors. No -copyright assignment is required to contribute to the "sapling-crypto" library. - -The "sapling-crypto" library is licensed under either of - - * Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT) - -at your option. - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/sapling-crypto/Cargo.toml b/sapling-crypto/Cargo.toml deleted file mode 100644 index 393c01f..0000000 --- a/sapling-crypto/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -authors = ["Sean Bowe "] -description = "Cryptographic library for Zcash Sapling" -documentation = "https://github.com/zcash-hackworks/sapling" -homepage = "https://github.com/zcash-hackworks/sapling" -license = "MIT/Apache-2.0" -name = "sapling-crypto" -repository = "https://github.com/zcash-hackworks/sapling" -version = "0.0.1" - -[dependencies.pairing] -path = "../pairing" -features = ["expose-arith"] - -[dependencies] -bellman = { path = "../bellman" } -rand = "0.4" -digest = "0.7" -byteorder = "1" - -[dependencies.blake2-rfc] -git = "https://github.com/gtank/blake2-rfc" -rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" - -[dev-dependencies] -hex-literal = "0.1" -rust-crypto = "0.2" diff --git a/sapling-crypto/LICENSE-APACHE b/sapling-crypto/LICENSE-APACHE deleted file mode 100644 index 16fe87b..0000000 --- a/sapling-crypto/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. diff --git a/sapling-crypto/LICENSE-MIT b/sapling-crypto/LICENSE-MIT deleted file mode 100644 index 31aa793..0000000 --- a/sapling-crypto/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/sapling-crypto/README.md b/sapling-crypto/README.md deleted file mode 100644 index f5d3bce..0000000 --- a/sapling-crypto/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# sapling-crypto - -This repository contains a (work-in-progress) implementation of Zcash's "Sapling" cryptography. - -## Security Warnings - -This library is currently under development and has not been reviewed. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/sapling-crypto/benches/pedersen_hash.rs b/sapling-crypto/benches/pedersen_hash.rs deleted file mode 100644 index c5968de..0000000 --- a/sapling-crypto/benches/pedersen_hash.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![feature(test)] - -extern crate rand; -extern crate test; -extern crate pairing; -extern crate sapling_crypto; - -use rand::{Rand, thread_rng}; -use pairing::bls12_381::Bls12; -use sapling_crypto::jubjub::JubjubBls12; -use sapling_crypto::pedersen_hash::{pedersen_hash, Personalization}; - -#[bench] -fn bench_pedersen_hash(b: &mut test::Bencher) { - let params = JubjubBls12::new(); - let rng = &mut thread_rng(); - let bits = (0..510).map(|_| bool::rand(rng)).collect::>(); - let personalization = Personalization::MerkleTree(31); - - b.iter(|| { - pedersen_hash::(personalization, bits.clone(), ¶ms) - }); -} diff --git a/sapling-crypto/examples/bench.rs b/sapling-crypto/examples/bench.rs deleted file mode 100644 index 4b7a707..0000000 --- a/sapling-crypto/examples/bench.rs +++ /dev/null @@ -1,102 +0,0 @@ -extern crate sapling_crypto; -extern crate bellman; -extern crate rand; -extern crate pairing; - -use std::time::{Duration, Instant}; -use sapling_crypto::jubjub::{ - JubjubBls12, - edwards, - fs, -}; -use sapling_crypto::circuit::sapling::{ - Spend -}; -use sapling_crypto::primitives::{ - Diversifier, - ProofGenerationKey, - ValueCommitment -}; -use bellman::groth16::*; -use rand::{XorShiftRng, SeedableRng, Rng}; -use pairing::bls12_381::{Bls12, Fr}; - -const TREE_DEPTH: usize = 32; - -fn main() { - let jubjub_params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - println!("Creating sample parameters..."); - let groth_params = generate_random_parameters::( - Spend { - params: jubjub_params, - value_commitment: None, - proof_generation_key: None, - payment_address: None, - commitment_randomness: None, - ar: None, - auth_path: vec![None; TREE_DEPTH], - anchor: None - }, - rng - ).unwrap(); - - const SAMPLES: u32 = 50; - - let mut total_time = Duration::new(0, 0); - for _ in 0..SAMPLES { - let value_commitment = ValueCommitment { - value: 1, - randomness: rng.gen() - }; - - let nsk: fs::Fs = rng.gen(); - let ak = edwards::Point::rand(rng, jubjub_params).mul_by_cofactor(jubjub_params); - - let proof_generation_key = ProofGenerationKey { - ak: ak.clone(), - nsk: nsk.clone() - }; - - let viewing_key = proof_generation_key.into_viewing_key(jubjub_params); - - let payment_address; - - loop { - let diversifier = Diversifier(rng.gen()); - - if let Some(p) = viewing_key.into_payment_address( - diversifier, - jubjub_params - ) - { - payment_address = p; - break; - } - } - - let commitment_randomness: fs::Fs = rng.gen(); - let auth_path = vec![Some((rng.gen(), rng.gen())); TREE_DEPTH]; - let ar: fs::Fs = rng.gen(); - let anchor: Fr = rng.gen(); - - let start = Instant::now(); - let _ = create_random_proof(Spend { - params: jubjub_params, - value_commitment: Some(value_commitment), - proof_generation_key: Some(proof_generation_key), - payment_address: Some(payment_address), - commitment_randomness: Some(commitment_randomness), - ar: Some(ar), - auth_path: auth_path, - anchor: Some(anchor) - }, &groth_params, rng).unwrap(); - total_time += start.elapsed(); - } - let avg = total_time / SAMPLES; - let avg = avg.subsec_nanos() as f64 / 1_000_000_000f64 - + (avg.as_secs() as f64); - - println!("Average proving time (in seconds): {}", avg); -} diff --git a/sapling-crypto/src/circuit/blake2s.rs b/sapling-crypto/src/circuit/blake2s.rs deleted file mode 100644 index 93af806..0000000 --- a/sapling-crypto/src/circuit/blake2s.rs +++ /dev/null @@ -1,438 +0,0 @@ -use pairing::{ - Engine, -}; - -use bellman::{ - SynthesisError, - ConstraintSystem -}; - -use super::boolean::{ - Boolean -}; - -use super::uint32::{ - UInt32 -}; - -use super::multieq::MultiEq; - -/* -2.1. Parameters - The following table summarizes various parameters and their ranges: - | BLAKE2b | BLAKE2s | - --------------+------------------+------------------+ - Bits in word | w = 64 | w = 32 | - Rounds in F | r = 12 | r = 10 | - Block bytes | bb = 128 | bb = 64 | - Hash bytes | 1 <= nn <= 64 | 1 <= nn <= 32 | - Key bytes | 0 <= kk <= 64 | 0 <= kk <= 32 | - Input bytes | 0 <= ll < 2**128 | 0 <= ll < 2**64 | - --------------+------------------+------------------+ - G Rotation | (R1, R2, R3, R4) | (R1, R2, R3, R4) | - constants = | (32, 24, 16, 63) | (16, 12, 8, 7) | - --------------+------------------+------------------+ -*/ - -const R1: usize = 16; -const R2: usize = 12; -const R3: usize = 8; -const R4: usize = 7; - -/* - Round | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | - ----------+-------------------------------------------------+ - SIGMA[0] | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | - SIGMA[1] | 14 10 4 8 9 15 13 6 1 12 0 2 11 7 5 3 | - SIGMA[2] | 11 8 12 0 5 2 15 13 10 14 3 6 7 1 9 4 | - SIGMA[3] | 7 9 3 1 13 12 11 14 2 6 5 10 4 0 15 8 | - SIGMA[4] | 9 0 5 7 2 4 10 15 14 1 11 12 6 8 3 13 | - SIGMA[5] | 2 12 6 10 0 11 8 3 4 13 7 5 15 14 1 9 | - SIGMA[6] | 12 5 1 15 14 13 4 10 0 7 6 3 9 2 8 11 | - SIGMA[7] | 13 11 7 14 12 1 3 9 5 0 15 4 8 6 2 10 | - SIGMA[8] | 6 15 14 9 11 3 0 8 12 2 13 7 1 4 10 5 | - SIGMA[9] | 10 2 8 4 7 6 1 5 15 11 9 14 3 12 13 0 | - ----------+-------------------------------------------------+ -*/ - -const SIGMA: [[usize; 16]; 10] = [ - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], - [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], - [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], - [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], - [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], - [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], - [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], - [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], - [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0] -]; - -/* -3.1. Mixing Function G - The G primitive function mixes two input words, "x" and "y", into - four words indexed by "a", "b", "c", and "d" in the working vector - v[0..15]. The full modified vector is returned. The rotation - constants (R1, R2, R3, R4) are given in Section 2.1. - FUNCTION G( v[0..15], a, b, c, d, x, y ) - | - | v[a] := (v[a] + v[b] + x) mod 2**w - | v[d] := (v[d] ^ v[a]) >>> R1 - | v[c] := (v[c] + v[d]) mod 2**w - | v[b] := (v[b] ^ v[c]) >>> R2 - | v[a] := (v[a] + v[b] + y) mod 2**w - | v[d] := (v[d] ^ v[a]) >>> R3 - | v[c] := (v[c] + v[d]) mod 2**w - | v[b] := (v[b] ^ v[c]) >>> R4 - | - | RETURN v[0..15] - | - END FUNCTION. -*/ - -fn mixing_g, M>( - mut cs: M, - v: &mut [UInt32], - a: usize, - b: usize, - c: usize, - d: usize, - x: &UInt32, - y: &UInt32 -) -> Result<(), SynthesisError> - where M: ConstraintSystem> -{ - v[a] = UInt32::addmany(cs.namespace(|| "mixing step 1"), &[v[a].clone(), v[b].clone(), x.clone()])?; - v[d] = v[d].xor(cs.namespace(|| "mixing step 2"), &v[a])?.rotr(R1); - v[c] = UInt32::addmany(cs.namespace(|| "mixing step 3"), &[v[c].clone(), v[d].clone()])?; - v[b] = v[b].xor(cs.namespace(|| "mixing step 4"), &v[c])?.rotr(R2); - v[a] = UInt32::addmany(cs.namespace(|| "mixing step 5"), &[v[a].clone(), v[b].clone(), y.clone()])?; - v[d] = v[d].xor(cs.namespace(|| "mixing step 6"), &v[a])?.rotr(R3); - v[c] = UInt32::addmany(cs.namespace(|| "mixing step 7"), &[v[c].clone(), v[d].clone()])?; - v[b] = v[b].xor(cs.namespace(|| "mixing step 8"), &v[c])?.rotr(R4); - - Ok(()) -} - -/* -3.2. Compression Function F - Compression function F takes as an argument the state vector "h", - message block vector "m" (last block is padded with zeros to full - block size, if required), 2w-bit offset counter "t", and final block - indicator flag "f". Local vector v[0..15] is used in processing. F - returns a new state vector. The number of rounds, "r", is 12 for - BLAKE2b and 10 for BLAKE2s. Rounds are numbered from 0 to r - 1. - FUNCTION F( h[0..7], m[0..15], t, f ) - | - | // Initialize local work vector v[0..15] - | v[0..7] := h[0..7] // First half from state. - | v[8..15] := IV[0..7] // Second half from IV. - | - | v[12] := v[12] ^ (t mod 2**w) // Low word of the offset. - | v[13] := v[13] ^ (t >> w) // High word. - | - | IF f = TRUE THEN // last block flag? - | | v[14] := v[14] ^ 0xFF..FF // Invert all bits. - | END IF. - | - | // Cryptographic mixing - | FOR i = 0 TO r - 1 DO // Ten or twelve rounds. - | | - | | // Message word selection permutation for this round. - | | s[0..15] := SIGMA[i mod 10][0..15] - | | - | | v := G( v, 0, 4, 8, 12, m[s[ 0]], m[s[ 1]] ) - | | v := G( v, 1, 5, 9, 13, m[s[ 2]], m[s[ 3]] ) - | | v := G( v, 2, 6, 10, 14, m[s[ 4]], m[s[ 5]] ) - | | v := G( v, 3, 7, 11, 15, m[s[ 6]], m[s[ 7]] ) - | | - | | v := G( v, 0, 5, 10, 15, m[s[ 8]], m[s[ 9]] ) - | | v := G( v, 1, 6, 11, 12, m[s[10]], m[s[11]] ) - | | v := G( v, 2, 7, 8, 13, m[s[12]], m[s[13]] ) - | | v := G( v, 3, 4, 9, 14, m[s[14]], m[s[15]] ) - | | - | END FOR - | - | FOR i = 0 TO 7 DO // XOR the two halves. - | | h[i] := h[i] ^ v[i] ^ v[i + 8] - | END FOR. - | - | RETURN h[0..7] // New state. - | - END FUNCTION. -*/ - - -fn blake2s_compression>( - mut cs: CS, - h: &mut [UInt32], - m: &[UInt32], - t: u64, - f: bool -) -> Result<(), SynthesisError> -{ - assert_eq!(h.len(), 8); - assert_eq!(m.len(), 16); - - /* - static const uint32_t blake2s_iv[8] = - { - 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, - 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 - }; - */ - - let mut v = Vec::with_capacity(16); - v.extend_from_slice(h); - v.push(UInt32::constant(0x6A09E667)); - v.push(UInt32::constant(0xBB67AE85)); - v.push(UInt32::constant(0x3C6EF372)); - v.push(UInt32::constant(0xA54FF53A)); - v.push(UInt32::constant(0x510E527F)); - v.push(UInt32::constant(0x9B05688C)); - v.push(UInt32::constant(0x1F83D9AB)); - v.push(UInt32::constant(0x5BE0CD19)); - - assert_eq!(v.len(), 16); - - v[12] = v[12].xor(cs.namespace(|| "first xor"), &UInt32::constant(t as u32))?; - v[13] = v[13].xor(cs.namespace(|| "second xor"), &UInt32::constant((t >> 32) as u32))?; - - if f { - v[14] = v[14].xor(cs.namespace(|| "third xor"), &UInt32::constant(u32::max_value()))?; - } - - { - let mut cs = MultiEq::new(&mut cs); - - for i in 0..10 { - let mut cs = cs.namespace(|| format!("round {}", i)); - - let s = SIGMA[i % 10]; - - mixing_g(cs.namespace(|| "mixing invocation 1"), &mut v, 0, 4, 8, 12, &m[s[ 0]], &m[s[ 1]])?; - mixing_g(cs.namespace(|| "mixing invocation 2"), &mut v, 1, 5, 9, 13, &m[s[ 2]], &m[s[ 3]])?; - mixing_g(cs.namespace(|| "mixing invocation 3"), &mut v, 2, 6, 10, 14, &m[s[ 4]], &m[s[ 5]])?; - mixing_g(cs.namespace(|| "mixing invocation 4"), &mut v, 3, 7, 11, 15, &m[s[ 6]], &m[s[ 7]])?; - - mixing_g(cs.namespace(|| "mixing invocation 5"), &mut v, 0, 5, 10, 15, &m[s[ 8]], &m[s[ 9]])?; - mixing_g(cs.namespace(|| "mixing invocation 6"), &mut v, 1, 6, 11, 12, &m[s[10]], &m[s[11]])?; - mixing_g(cs.namespace(|| "mixing invocation 7"), &mut v, 2, 7, 8, 13, &m[s[12]], &m[s[13]])?; - mixing_g(cs.namespace(|| "mixing invocation 8"), &mut v, 3, 4, 9, 14, &m[s[14]], &m[s[15]])?; - } - } - - for i in 0..8 { - let mut cs = cs.namespace(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i=i)); - - h[i] = h[i].xor(cs.namespace(|| "first xor"), &v[i])?; - h[i] = h[i].xor(cs.namespace(|| "second xor"), &v[i + 8])?; - } - - Ok(()) -} - -/* - FUNCTION BLAKE2( d[0..dd-1], ll, kk, nn ) - | - | h[0..7] := IV[0..7] // Initialization Vector. - | - | // Parameter block p[0] - | h[0] := h[0] ^ 0x01010000 ^ (kk << 8) ^ nn - | - | // Process padded key and data blocks - | IF dd > 1 THEN - | | FOR i = 0 TO dd - 2 DO - | | | h := F( h, d[i], (i + 1) * bb, FALSE ) - | | END FOR. - | END IF. - | - | // Final block. - | IF kk = 0 THEN - | | h := F( h, d[dd - 1], ll, TRUE ) - | ELSE - | | h := F( h, d[dd - 1], ll + bb, TRUE ) - | END IF. - | - | RETURN first "nn" bytes from little-endian word array h[]. - | - END FUNCTION. -*/ - -pub fn blake2s>( - mut cs: CS, - input: &[Boolean], - personalization: &[u8] -) -> Result, SynthesisError> -{ - use byteorder::{ByteOrder, LittleEndian}; - - assert_eq!(personalization.len(), 8); - assert!(input.len() % 8 == 0); - - let mut h = Vec::with_capacity(8); - h.push(UInt32::constant(0x6A09E667 ^ 0x01010000 ^ 32)); - h.push(UInt32::constant(0xBB67AE85)); - h.push(UInt32::constant(0x3C6EF372)); - h.push(UInt32::constant(0xA54FF53A)); - h.push(UInt32::constant(0x510E527F)); - h.push(UInt32::constant(0x9B05688C)); - - // Personalization is stored here - h.push(UInt32::constant(0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4]))); - h.push(UInt32::constant(0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8]))); - - let mut blocks: Vec> = vec![]; - - for block in input.chunks(512) { - let mut this_block = Vec::with_capacity(16); - for word in block.chunks(32) { - let mut tmp = word.to_vec(); - while tmp.len() < 32 { - tmp.push(Boolean::constant(false)); - } - this_block.push(UInt32::from_bits(&tmp)); - } - while this_block.len() < 16 { - this_block.push(UInt32::constant(0)); - } - blocks.push(this_block); - } - - if blocks.len() == 0 { - blocks.push((0..16).map(|_| UInt32::constant(0)).collect()); - } - - for (i, block) in blocks[0..blocks.len() - 1].iter().enumerate() { - let cs = cs.namespace(|| format!("block {}", i)); - - blake2s_compression(cs, &mut h, block, ((i as u64) + 1) * 64, false)?; - } - - { - let cs = cs.namespace(|| "final block"); - - blake2s_compression(cs, &mut h, &blocks[blocks.len() - 1], (input.len() / 8) as u64, true)?; - } - - Ok(h.iter().flat_map(|b| b.into_bits()).collect()) -} - -#[cfg(test)] -mod test { - use rand::{XorShiftRng, SeedableRng, Rng}; - use pairing::bls12_381::{Bls12}; - use ::circuit::boolean::{Boolean, AllocatedBit}; - use ::circuit::test::TestConstraintSystem; - use super::blake2s; - use bellman::{ConstraintSystem}; - use blake2_rfc::blake2s::Blake2s; - - #[test] - fn test_blank_hash() { - let mut cs = TestConstraintSystem::::new(); - let input_bits = vec![]; - let out = blake2s(&mut cs, &input_bits, b"12345678").unwrap(); - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 0); - - // >>> import blake2s from hashlib - // >>> h = blake2s(digest_size=32, person=b'12345678') - // >>> h.hexdigest() - let expected = hex!("c59f682376d137f3f255e671e207d1f2374ebe504e9314208a52d9f88d69e8c8"); - - let mut out = out.into_iter(); - for b in expected.into_iter() { - for i in 0..8 { - let c = out.next().unwrap().get_value().unwrap(); - - assert_eq!(c, (b >> i) & 1u8 == 1u8); - } - } - } - - #[test] - fn test_blake2s_constraints() { - let mut cs = TestConstraintSystem::::new(); - let input_bits: Vec<_> = (0..512).map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into()).collect(); - blake2s(&mut cs, &input_bits, b"12345678").unwrap(); - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 21518); - } - - #[test] - fn test_blake2s_precomp_constraints() { - // Test that 512 fixed leading bits (constants) - // doesn't result in more constraints. - - let mut cs = TestConstraintSystem::::new(); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - let input_bits: Vec<_> = (0..512) - .map(|_| Boolean::constant(rng.gen())) - .chain((0..512) - .map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into())) - .collect(); - blake2s(&mut cs, &input_bits, b"12345678").unwrap(); - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 21518); - } - - #[test] - fn test_blake2s_constant_constraints() { - let mut cs = TestConstraintSystem::::new(); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - let input_bits: Vec<_> = (0..512).map(|_| Boolean::constant(rng.gen())).collect(); - blake2s(&mut cs, &input_bits, b"12345678").unwrap(); - assert_eq!(cs.num_constraints(), 0); - } - - #[test] - fn test_blake2s() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) - { - let mut h = Blake2s::with_params(32, &[], &[], b"12345678"); - - let data: Vec = (0..input_len).map(|_| rng.gen()).collect(); - - h.update(&data); - - let hash_result = h.finalize(); - - let mut cs = TestConstraintSystem::::new(); - - let mut input_bits = vec![]; - - for (byte_i, input_byte) in data.into_iter().enumerate() { - for bit_i in 0..8 { - let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i)); - - input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into()); - } - } - - let r = blake2s(&mut cs, &input_bits, b"12345678").unwrap(); - - assert!(cs.is_satisfied()); - - let mut s = hash_result.as_ref().iter() - .flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8)); - - for b in r { - match b { - Boolean::Is(b) => { - assert!(s.next().unwrap() == b.get_value().unwrap()); - }, - Boolean::Not(b) => { - assert!(s.next().unwrap() != b.get_value().unwrap()); - }, - Boolean::Constant(b) => { - assert!(input_len == 0); - assert!(s.next().unwrap() == b); - } - } - } - } - } -} diff --git a/sapling-crypto/src/circuit/boolean.rs b/sapling-crypto/src/circuit/boolean.rs deleted file mode 100644 index 08f407e..0000000 --- a/sapling-crypto/src/circuit/boolean.rs +++ /dev/null @@ -1,1582 +0,0 @@ -use pairing::{ - Engine, - Field, - PrimeField, - BitIterator -}; - -use bellman::{ - ConstraintSystem, - SynthesisError, - LinearCombination, - Variable -}; - -use super::{ - Assignment -}; - -/// Represents a variable in the constraint system which is guaranteed -/// to be either zero or one. -#[derive(Clone)] -pub struct AllocatedBit { - variable: Variable, - value: Option -} - -impl AllocatedBit { - pub fn get_value(&self) -> Option { - self.value - } - - pub fn get_variable(&self) -> Variable { - self.variable - } - - /// Allocate a variable in the constraint system which can only be a - /// boolean value. Further, constrain that the boolean is false - /// unless the condition is false. - pub fn alloc_conditionally( - mut cs: CS, - value: Option, - must_be_false: &AllocatedBit - ) -> Result - where E: Engine, - CS: ConstraintSystem - { - let var = cs.alloc(|| "boolean", || { - if *value.get()? { - Ok(E::Fr::one()) - } else { - Ok(E::Fr::zero()) - } - })?; - - // Constrain: (1 - must_be_false - a) * a = 0 - // if must_be_false is true, the equation - // reduces to -a * a = 0, which implies a = 0. - // if must_be_false is false, the equation - // reduces to (1 - a) * a = 0, which is a - // traditional boolean constraint. - cs.enforce( - || "boolean constraint", - |lc| lc + CS::one() - must_be_false.variable - var, - |lc| lc + var, - |lc| lc - ); - - Ok(AllocatedBit { - variable: var, - value: value - }) - } - - /// Allocate a variable in the constraint system which can only be a - /// boolean value. - pub fn alloc( - mut cs: CS, - value: Option, - ) -> Result - where E: Engine, - CS: ConstraintSystem - { - let var = cs.alloc(|| "boolean", || { - if *value.get()? { - Ok(E::Fr::one()) - } else { - Ok(E::Fr::zero()) - } - })?; - - // Constrain: (1 - a) * a = 0 - // This constrains a to be either 0 or 1. - cs.enforce( - || "boolean constraint", - |lc| lc + CS::one() - var, - |lc| lc + var, - |lc| lc - ); - - Ok(AllocatedBit { - variable: var, - value: value - }) - } - - /// Performs an XOR operation over the two operands, returning - /// an `AllocatedBit`. - pub fn xor( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem - { - let mut result_value = None; - - let result_var = cs.alloc(|| "xor result", || { - if *a.value.get()? ^ *b.value.get()? { - result_value = Some(true); - - Ok(E::Fr::one()) - } else { - result_value = Some(false); - - Ok(E::Fr::zero()) - } - })?; - - // Constrain (a + a) * (b) = (a + b - c) - // Given that a and b are boolean constrained, if they - // are equal, the only solution for c is 0, and if they - // are different, the only solution for c is 1. - // - // ¬(a ∧ b) ∧ ¬(¬a ∧ ¬b) = c - // (1 - (a * b)) * (1 - ((1 - a) * (1 - b))) = c - // (1 - ab) * (1 - (1 - a - b + ab)) = c - // (1 - ab) * (a + b - ab) = c - // a + b - ab - (a^2)b - (b^2)a + (a^2)(b^2) = c - // a + b - ab - ab - ab + ab = c - // a + b - 2ab = c - // -2a * b = c - a - b - // 2a * b = a + b - c - // (a + a) * b = a + b - c - cs.enforce( - || "xor constraint", - |lc| lc + a.variable + a.variable, - |lc| lc + b.variable, - |lc| lc + a.variable + b.variable - result_var - ); - - Ok(AllocatedBit { - variable: result_var, - value: result_value - }) - } - - /// Performs an AND operation over the two operands, returning - /// an `AllocatedBit`. - pub fn and( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem - { - let mut result_value = None; - - let result_var = cs.alloc(|| "and result", || { - if *a.value.get()? & *b.value.get()? { - result_value = Some(true); - - Ok(E::Fr::one()) - } else { - result_value = Some(false); - - Ok(E::Fr::zero()) - } - })?; - - // Constrain (a) * (b) = (c), ensuring c is 1 iff - // a AND b are both 1. - cs.enforce( - || "and constraint", - |lc| lc + a.variable, - |lc| lc + b.variable, - |lc| lc + result_var - ); - - Ok(AllocatedBit { - variable: result_var, - value: result_value - }) - } - - /// Calculates `a AND (NOT b)`. - pub fn and_not( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem - { - let mut result_value = None; - - let result_var = cs.alloc(|| "and not result", || { - if *a.value.get()? & !*b.value.get()? { - result_value = Some(true); - - Ok(E::Fr::one()) - } else { - result_value = Some(false); - - Ok(E::Fr::zero()) - } - })?; - - // Constrain (a) * (1 - b) = (c), ensuring c is 1 iff - // a is true and b is false, and otherwise c is 0. - cs.enforce( - || "and not constraint", - |lc| lc + a.variable, - |lc| lc + CS::one() - b.variable, - |lc| lc + result_var - ); - - Ok(AllocatedBit { - variable: result_var, - value: result_value - }) - } - - /// Calculates `(NOT a) AND (NOT b)`. - pub fn nor( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem - { - let mut result_value = None; - - let result_var = cs.alloc(|| "nor result", || { - if !*a.value.get()? & !*b.value.get()? { - result_value = Some(true); - - Ok(E::Fr::one()) - } else { - result_value = Some(false); - - Ok(E::Fr::zero()) - } - })?; - - // Constrain (1 - a) * (1 - b) = (c), ensuring c is 1 iff - // a and b are both false, and otherwise c is 0. - cs.enforce( - || "nor constraint", - |lc| lc + CS::one() - a.variable, - |lc| lc + CS::one() - b.variable, - |lc| lc + result_var - ); - - Ok(AllocatedBit { - variable: result_var, - value: result_value - }) - } -} - -pub fn u64_into_boolean_vec_le>( - mut cs: CS, - value: Option -) -> Result, SynthesisError> -{ - let values = match value { - Some(ref value) => { - let mut tmp = Vec::with_capacity(64); - - for i in 0..64 { - tmp.push(Some(*value >> i & 1 == 1)); - } - - tmp - }, - None => { - vec![None; 64] - } - }; - - let bits = values.into_iter().enumerate().map(|(i, b)| { - Ok(Boolean::from(AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - b - )?)) - }).collect::, SynthesisError>>()?; - - Ok(bits) -} - -pub fn field_into_boolean_vec_le, F: PrimeField>( - cs: CS, - value: Option -) -> Result, SynthesisError> -{ - let v = field_into_allocated_bits_le::(cs, value)?; - - Ok(v.into_iter().map(|e| Boolean::from(e)).collect()) -} - -pub fn field_into_allocated_bits_le, F: PrimeField>( - mut cs: CS, - value: Option -) -> Result, SynthesisError> -{ - // Deconstruct in big-endian bit order - let values = match value { - Some(ref value) => { - let mut field_char = BitIterator::new(F::char()); - - let mut tmp = Vec::with_capacity(F::NUM_BITS as usize); - - let mut found_one = false; - for b in BitIterator::new(value.into_repr()) { - // Skip leading bits - found_one |= field_char.next().unwrap(); - if !found_one { - continue; - } - - tmp.push(Some(b)); - } - - assert_eq!(tmp.len(), F::NUM_BITS as usize); - - tmp - }, - None => { - vec![None; F::NUM_BITS as usize] - } - }; - - // Allocate in little-endian order - let bits = values.into_iter().rev().enumerate().map(|(i, b)| { - AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - b - ) - }).collect::, SynthesisError>>()?; - - Ok(bits) -} - -/// This is a boolean value which may be either a constant or -/// an interpretation of an `AllocatedBit`. -#[derive(Clone)] -pub enum Boolean { - /// Existential view of the boolean variable - Is(AllocatedBit), - /// Negated view of the boolean variable - Not(AllocatedBit), - /// Constant (not an allocated variable) - Constant(bool) -} - -impl Boolean { - pub fn is_constant(&self) -> bool { - match *self { - Boolean::Constant(_) => true, - _ => false - } - } - - pub fn enforce_equal( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result<(), SynthesisError> - where E: Engine, - CS: ConstraintSystem - { - match (a, b) { - (&Boolean::Constant(a), &Boolean::Constant(b)) => { - if a == b { - Ok(()) - } else { - Err(SynthesisError::Unsatisfiable) - } - }, - (&Boolean::Constant(true), a) | (a, &Boolean::Constant(true)) => { - cs.enforce( - || "enforce equal to one", - |lc| lc, - |lc| lc, - |lc| lc + CS::one() - &a.lc(CS::one(), E::Fr::one()) - ); - - Ok(()) - }, - (&Boolean::Constant(false), a) | (a, &Boolean::Constant(false)) => { - cs.enforce( - || "enforce equal to zero", - |lc| lc, - |lc| lc, - |_| a.lc(CS::one(), E::Fr::one()) - ); - - Ok(()) - }, - (a, b) => { - cs.enforce( - || "enforce equal", - |lc| lc, - |lc| lc, - |_| a.lc(CS::one(), E::Fr::one()) - &b.lc(CS::one(), E::Fr::one()) - ); - - Ok(()) - } - } - } - - pub fn get_value(&self) -> Option { - match self { - &Boolean::Constant(c) => Some(c), - &Boolean::Is(ref v) => v.get_value(), - &Boolean::Not(ref v) => v.get_value().map(|b| !b) - } - } - - pub fn lc( - &self, - one: Variable, - coeff: E::Fr - ) -> LinearCombination - { - match self { - &Boolean::Constant(c) => { - if c { - LinearCombination::::zero() + (coeff, one) - } else { - LinearCombination::::zero() - } - }, - &Boolean::Is(ref v) => { - LinearCombination::::zero() + (coeff, v.get_variable()) - }, - &Boolean::Not(ref v) => { - LinearCombination::::zero() + (coeff, one) - (coeff, v.get_variable()) - } - } - } - - /// Construct a boolean from a known constant - pub fn constant(b: bool) -> Self { - Boolean::Constant(b) - } - - /// Return a negated interpretation of this boolean. - pub fn not(&self) -> Self { - match self { - &Boolean::Constant(c) => Boolean::Constant(!c), - &Boolean::Is(ref v) => Boolean::Not(v.clone()), - &Boolean::Not(ref v) => Boolean::Is(v.clone()) - } - } - - /// Perform XOR over two boolean operands - pub fn xor<'a, E, CS>( - cs: CS, - a: &'a Self, - b: &'a Self - ) -> Result - where E: Engine, - CS: ConstraintSystem - { - match (a, b) { - (&Boolean::Constant(false), x) | (x, &Boolean::Constant(false)) => Ok(x.clone()), - (&Boolean::Constant(true), x) | (x, &Boolean::Constant(true)) => Ok(x.not()), - // a XOR (NOT b) = NOT(a XOR b) - (is @ &Boolean::Is(_), not @ &Boolean::Not(_)) | (not @ &Boolean::Not(_), is @ &Boolean::Is(_)) => { - Ok(Boolean::xor( - cs, - is, - ¬.not() - )?.not()) - }, - // a XOR b = (NOT a) XOR (NOT b) - (&Boolean::Is(ref a), &Boolean::Is(ref b)) | (&Boolean::Not(ref a), &Boolean::Not(ref b)) => { - Ok(Boolean::Is(AllocatedBit::xor(cs, a, b)?)) - } - } - } - - /// Perform AND over two boolean operands - pub fn and<'a, E, CS>( - cs: CS, - a: &'a Self, - b: &'a Self - ) -> Result - where E: Engine, - CS: ConstraintSystem - { - match (a, b) { - // false AND x is always false - (&Boolean::Constant(false), _) | (_, &Boolean::Constant(false)) => Ok(Boolean::Constant(false)), - // true AND x is always x - (&Boolean::Constant(true), x) | (x, &Boolean::Constant(true)) => Ok(x.clone()), - // a AND (NOT b) - (&Boolean::Is(ref is), &Boolean::Not(ref not)) | (&Boolean::Not(ref not), &Boolean::Is(ref is)) => { - Ok(Boolean::Is(AllocatedBit::and_not(cs, is, not)?)) - }, - // (NOT a) AND (NOT b) = a NOR b - (&Boolean::Not(ref a), &Boolean::Not(ref b)) => { - Ok(Boolean::Is(AllocatedBit::nor(cs, a, b)?)) - }, - // a AND b - (&Boolean::Is(ref a), &Boolean::Is(ref b)) => { - Ok(Boolean::Is(AllocatedBit::and(cs, a, b)?)) - } - } - } - - /// Computes (a and b) xor ((not a) and c) - pub fn sha256_ch<'a, E, CS>( - mut cs: CS, - a: &'a Self, - b: &'a Self, - c: &'a Self - ) -> Result - where E: Engine, - CS: ConstraintSystem - { - let ch_value = match (a.get_value(), b.get_value(), c.get_value()) { - (Some(a), Some(b), Some(c)) => { - // (a and b) xor ((not a) and c) - Some((a & b) ^ ((!a) & c)) - }, - _ => None - }; - - match (a, b, c) { - (&Boolean::Constant(_), - &Boolean::Constant(_), - &Boolean::Constant(_)) => { - // They're all constants, so we can just compute the value. - - return Ok(Boolean::Constant(ch_value.expect("they're all constants"))); - }, - (&Boolean::Constant(false), _, c) => { - // If a is false - // (a and b) xor ((not a) and c) - // equals - // (false) xor (c) - // equals - // c - return Ok(c.clone()); - }, - (a, &Boolean::Constant(false), c) => { - // If b is false - // (a and b) xor ((not a) and c) - // equals - // ((not a) and c) - return Boolean::and( - cs, - &a.not(), - &c - ); - }, - (a, b, &Boolean::Constant(false)) => { - // If c is false - // (a and b) xor ((not a) and c) - // equals - // (a and b) - return Boolean::and( - cs, - &a, - &b - ); - }, - (a, b, &Boolean::Constant(true)) => { - // If c is true - // (a and b) xor ((not a) and c) - // equals - // (a and b) xor (not a) - // equals - // not (a and (not b)) - return Ok(Boolean::and( - cs, - &a, - &b.not() - )?.not()); - }, - (a, &Boolean::Constant(true), c) => { - // If b is true - // (a and b) xor ((not a) and c) - // equals - // a xor ((not a) and c) - // equals - // not ((not a) and (not c)) - return Ok(Boolean::and( - cs, - &a.not(), - &c.not() - )?.not()); - }, - (&Boolean::Constant(true), _, _) => { - // If a is true - // (a and b) xor ((not a) and c) - // equals - // b xor ((not a) and c) - // So we just continue! - }, - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_)) - => {} - } - - let ch = cs.alloc(|| "ch", || { - ch_value.get().map(|v| { - if *v { - E::Fr::one() - } else { - E::Fr::zero() - } - }) - })?; - - // a(b - c) = ch - c - cs.enforce( - || "ch computation", - |_| b.lc(CS::one(), E::Fr::one()) - - &c.lc(CS::one(), E::Fr::one()), - |_| a.lc(CS::one(), E::Fr::one()), - |lc| lc + ch - &c.lc(CS::one(), E::Fr::one()) - ); - - Ok(AllocatedBit { - value: ch_value, - variable: ch - }.into()) - } - - /// Computes (a and b) xor (a and c) xor (b and c) - pub fn sha256_maj<'a, E, CS>( - mut cs: CS, - a: &'a Self, - b: &'a Self, - c: &'a Self, - ) -> Result - where E: Engine, - CS: ConstraintSystem - { - let maj_value = match (a.get_value(), b.get_value(), c.get_value()) { - (Some(a), Some(b), Some(c)) => { - // (a and b) xor (a and c) xor (b and c) - Some((a & b) ^ (a & c) ^ (b & c)) - }, - _ => None - }; - - match (a, b, c) { - (&Boolean::Constant(_), - &Boolean::Constant(_), - &Boolean::Constant(_)) => { - // They're all constants, so we can just compute the value. - - return Ok(Boolean::Constant(maj_value.expect("they're all constants"))); - }, - (&Boolean::Constant(false), b, c) => { - // If a is false, - // (a and b) xor (a and c) xor (b and c) - // equals - // (b and c) - return Boolean::and( - cs, - b, - c - ); - }, - (a, &Boolean::Constant(false), c) => { - // If b is false, - // (a and b) xor (a and c) xor (b and c) - // equals - // (a and c) - return Boolean::and( - cs, - a, - c - ); - }, - (a, b, &Boolean::Constant(false)) => { - // If c is false, - // (a and b) xor (a and c) xor (b and c) - // equals - // (a and b) - return Boolean::and( - cs, - a, - b - ); - }, - (a, b, &Boolean::Constant(true)) => { - // If c is true, - // (a and b) xor (a and c) xor (b and c) - // equals - // (a and b) xor (a) xor (b) - // equals - // not ((not a) and (not b)) - return Ok(Boolean::and( - cs, - &a.not(), - &b.not() - )?.not()); - }, - (a, &Boolean::Constant(true), c) => { - // If b is true, - // (a and b) xor (a and c) xor (b and c) - // equals - // (a) xor (a and c) xor (c) - return Ok(Boolean::and( - cs, - &a.not(), - &c.not() - )?.not()); - }, - (&Boolean::Constant(true), b, c) => { - // If a is true, - // (a and b) xor (a and c) xor (b and c) - // equals - // (b) xor (c) xor (b and c) - return Ok(Boolean::and( - cs, - &b.not(), - &c.not() - )?.not()); - }, - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_)) - => {} - } - - let maj = cs.alloc(|| "maj", || { - maj_value.get().map(|v| { - if *v { - E::Fr::one() - } else { - E::Fr::zero() - } - }) - })?; - - // ¬(¬a ∧ ¬b) ∧ ¬(¬a ∧ ¬c) ∧ ¬(¬b ∧ ¬c) - // (1 - ((1 - a) * (1 - b))) * (1 - ((1 - a) * (1 - c))) * (1 - ((1 - b) * (1 - c))) - // (a + b - ab) * (a + c - ac) * (b + c - bc) - // -2abc + ab + ac + bc - // a (-2bc + b + c) + bc - // - // (b) * (c) = (bc) - // (2bc - b - c) * (a) = bc - maj - - let bc = Self::and( - cs.namespace(|| "b and c"), - b, - c - )?; - - cs.enforce( - || "maj computation", - |_| bc.lc(CS::one(), E::Fr::one()) - + &bc.lc(CS::one(), E::Fr::one()) - - &b.lc(CS::one(), E::Fr::one()) - - &c.lc(CS::one(), E::Fr::one()), - |_| a.lc(CS::one(), E::Fr::one()), - |_| bc.lc(CS::one(), E::Fr::one()) - maj - ); - - Ok(AllocatedBit { - value: maj_value, - variable: maj - }.into()) - } -} - -impl From for Boolean { - fn from(b: AllocatedBit) -> Boolean { - Boolean::Is(b) - } -} - -#[cfg(test)] -mod test { - use bellman::{ConstraintSystem}; - use pairing::bls12_381::{Bls12, Fr}; - use pairing::{Field, PrimeField}; - use ::circuit::test::*; - use super::{ - AllocatedBit, - Boolean, - field_into_allocated_bits_le, - u64_into_boolean_vec_le - }; - - #[test] - fn test_allocated_bit() { - let mut cs = TestConstraintSystem::::new(); - - AllocatedBit::alloc(&mut cs, Some(true)).unwrap(); - assert!(cs.get("boolean") == Fr::one()); - assert!(cs.is_satisfied()); - cs.set("boolean", Fr::zero()); - assert!(cs.is_satisfied()); - cs.set("boolean", Fr::from_str("2").unwrap()); - assert!(!cs.is_satisfied()); - assert!(cs.which_is_unsatisfied() == Some("boolean constraint")); - } - - #[test] - fn test_xor() { - for a_val in [false, true].iter() { - for b_val in [false, true].iter() { - let mut cs = TestConstraintSystem::::new(); - let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap(); - let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap(); - let c = AllocatedBit::xor(&mut cs, &a, &b).unwrap(); - assert_eq!(c.value.unwrap(), *a_val ^ *b_val); - - assert!(cs.is_satisfied()); - assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); - assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("xor result") == if *a_val ^ *b_val { Field::one() } else { Field::zero() }); - - // Invert the result and check if the constraint system is still satisfied - cs.set("xor result", if *a_val ^ *b_val { Field::zero() } else { Field::one() }); - assert!(!cs.is_satisfied()); - } - } - } - - #[test] - fn test_and() { - for a_val in [false, true].iter() { - for b_val in [false, true].iter() { - let mut cs = TestConstraintSystem::::new(); - let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap(); - let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap(); - let c = AllocatedBit::and(&mut cs, &a, &b).unwrap(); - assert_eq!(c.value.unwrap(), *a_val & *b_val); - - assert!(cs.is_satisfied()); - assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); - assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("and result") == if *a_val & *b_val { Field::one() } else { Field::zero() }); - - // Invert the result and check if the constraint system is still satisfied - cs.set("and result", if *a_val & *b_val { Field::zero() } else { Field::one() }); - assert!(!cs.is_satisfied()); - } - } - } - - #[test] - fn test_and_not() { - for a_val in [false, true].iter() { - for b_val in [false, true].iter() { - let mut cs = TestConstraintSystem::::new(); - let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap(); - let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap(); - let c = AllocatedBit::and_not(&mut cs, &a, &b).unwrap(); - assert_eq!(c.value.unwrap(), *a_val & !*b_val); - - assert!(cs.is_satisfied()); - assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); - assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("and not result") == if *a_val & !*b_val { Field::one() } else { Field::zero() }); - - // Invert the result and check if the constraint system is still satisfied - cs.set("and not result", if *a_val & !*b_val { Field::zero() } else { Field::one() }); - assert!(!cs.is_satisfied()); - } - } - } - - #[test] - fn test_nor() { - for a_val in [false, true].iter() { - for b_val in [false, true].iter() { - let mut cs = TestConstraintSystem::::new(); - let a = AllocatedBit::alloc(cs.namespace(|| "a"), Some(*a_val)).unwrap(); - let b = AllocatedBit::alloc(cs.namespace(|| "b"), Some(*b_val)).unwrap(); - let c = AllocatedBit::nor(&mut cs, &a, &b).unwrap(); - assert_eq!(c.value.unwrap(), !*a_val & !*b_val); - - assert!(cs.is_satisfied()); - assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); - assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("nor result") == if !*a_val & !*b_val { Field::one() } else { Field::zero() }); - - // Invert the result and check if the constraint system is still satisfied - cs.set("nor result", if !*a_val & !*b_val { Field::zero() } else { Field::one() }); - assert!(!cs.is_satisfied()); - } - } - } - - #[test] - fn test_enforce_equal() { - for a_bool in [false, true].iter().cloned() { - for b_bool in [false, true].iter().cloned() { - for a_neg in [false, true].iter().cloned() { - for b_neg in [false, true].iter().cloned() { - { - let mut cs = TestConstraintSystem::::new(); - - let mut a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap()); - let mut b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap()); - - if a_neg { - a = a.not(); - } - if b_neg { - b = b.not(); - } - - Boolean::enforce_equal(&mut cs, &a, &b).unwrap(); - - assert_eq!( - cs.is_satisfied(), - (a_bool ^ a_neg) == (b_bool ^ b_neg) - ); - } - { - let mut cs = TestConstraintSystem::::new(); - - let mut a = Boolean::Constant(a_bool); - let mut b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap()); - - if a_neg { - a = a.not(); - } - if b_neg { - b = b.not(); - } - - Boolean::enforce_equal(&mut cs, &a, &b).unwrap(); - - assert_eq!( - cs.is_satisfied(), - (a_bool ^ a_neg) == (b_bool ^ b_neg) - ); - } - { - let mut cs = TestConstraintSystem::::new(); - - let mut a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap()); - let mut b = Boolean::Constant(b_bool); - - if a_neg { - a = a.not(); - } - if b_neg { - b = b.not(); - } - - Boolean::enforce_equal(&mut cs, &a, &b).unwrap(); - - assert_eq!( - cs.is_satisfied(), - (a_bool ^ a_neg) == (b_bool ^ b_neg) - ); - } - { - let mut cs = TestConstraintSystem::::new(); - - let mut a = Boolean::Constant(a_bool); - let mut b = Boolean::Constant(b_bool); - - if a_neg { - a = a.not(); - } - if b_neg { - b = b.not(); - } - - let result = Boolean::enforce_equal(&mut cs, &a, &b); - - if (a_bool ^ a_neg) == (b_bool ^ b_neg) { - assert!(result.is_ok()); - assert!(cs.is_satisfied()); - } else { - assert!(result.is_err()); - } - } - } - } - } - } - } - - #[test] - fn test_boolean_negation() { - let mut cs = TestConstraintSystem::::new(); - - let mut b = Boolean::from(AllocatedBit::alloc(&mut cs, Some(true)).unwrap()); - - match b { - Boolean::Is(_) => {}, - _ => panic!("unexpected value") - } - - b = b.not(); - - match b { - Boolean::Not(_) => {}, - _ => panic!("unexpected value") - } - - b = b.not(); - - match b { - Boolean::Is(_) => {}, - _ => panic!("unexpected value") - } - - b = Boolean::constant(true); - - match b { - Boolean::Constant(true) => {}, - _ => panic!("unexpected value") - } - - b = b.not(); - - match b { - Boolean::Constant(false) => {}, - _ => panic!("unexpected value") - } - - b = b.not(); - - match b { - Boolean::Constant(true) => {}, - _ => panic!("unexpected value") - } - } - - #[derive(Copy, Clone, Debug)] - enum OperandType { - True, - False, - AllocatedTrue, - AllocatedFalse, - NegatedAllocatedTrue, - NegatedAllocatedFalse - } - - impl OperandType { - fn is_constant(&self) -> bool { - match *self { - OperandType::True => true, - OperandType::False => true, - OperandType::AllocatedTrue => false, - OperandType::AllocatedFalse => false, - OperandType::NegatedAllocatedTrue => false, - OperandType::NegatedAllocatedFalse => false - } - } - - fn val(&self) -> bool { - match *self { - OperandType::True => true, - OperandType::False => false, - OperandType::AllocatedTrue => true, - OperandType::AllocatedFalse => false, - OperandType::NegatedAllocatedTrue => false, - OperandType::NegatedAllocatedFalse => true - } - } - } - - - #[test] - fn test_boolean_xor() { - let variants = [ - OperandType::True, - OperandType::False, - OperandType::AllocatedTrue, - OperandType::AllocatedFalse, - OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse - ]; - - for first_operand in variants.iter().cloned() { - for second_operand in variants.iter().cloned() { - let mut cs = TestConstraintSystem::::new(); - - let a; - let b; - - { - let mut dyn_construct = |operand, name| { - let cs = cs.namespace(|| name); - - match operand { - OperandType::True => Boolean::constant(true), - OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), - } - }; - - a = dyn_construct(first_operand, "a"); - b = dyn_construct(second_operand, "b"); - } - - let c = Boolean::xor(&mut cs, &a, &b).unwrap(); - - assert!(cs.is_satisfied()); - - match (first_operand, second_operand, c) { - (OperandType::True, OperandType::True, Boolean::Constant(false)) => {}, - (OperandType::True, OperandType::False, Boolean::Constant(true)) => {}, - (OperandType::True, OperandType::AllocatedTrue, Boolean::Not(_)) => {}, - (OperandType::True, OperandType::AllocatedFalse, Boolean::Not(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Is(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Is(_)) => {}, - - (OperandType::False, OperandType::True, Boolean::Constant(true)) => {}, - (OperandType::False, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::AllocatedTrue, Boolean::Is(_)) => {}, - (OperandType::False, OperandType::AllocatedFalse, Boolean::Is(_)) => {}, - (OperandType::False, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {}, - (OperandType::False, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {}, - - (OperandType::AllocatedTrue, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::AllocatedTrue, OperandType::False, Boolean::Is(_)) => {}, - (OperandType::AllocatedTrue, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { - assert!(cs.get("xor result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { - assert!(cs.get("xor result") == Field::one()); - assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Not(ref v)) => { - assert!(cs.get("xor result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Not(ref v)) => { - assert!(cs.get("xor result") == Field::one()); - assert_eq!(v.value, Some(true)); - }, - - (OperandType::AllocatedFalse, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::AllocatedFalse, OperandType::False, Boolean::Is(_)) => {}, - (OperandType::AllocatedFalse, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { - assert!(cs.get("xor result") == Field::one()); - assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedFalse, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { - assert!(cs.get("xor result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Not(ref v)) => { - assert!(cs.get("xor result") == Field::one()); - assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Not(ref v)) => { - assert!(cs.get("xor result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - - (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::False, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedTrue, Boolean::Not(ref v)) => { - assert!(cs.get("xor result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedFalse, Boolean::Not(ref v)) => { - assert!(cs.get("xor result") == Field::one()); - assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { - assert!(cs.get("xor result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { - assert!(cs.get("xor result") == Field::one()); - assert_eq!(v.value, Some(true)); - }, - - (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::False, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedTrue, Boolean::Not(ref v)) => { - assert!(cs.get("xor result") == Field::one()); - assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedFalse, Boolean::Not(ref v)) => { - assert!(cs.get("xor result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { - assert!(cs.get("xor result") == Field::one()); - assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { - assert!(cs.get("xor result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - - _ => panic!("this should never be encountered") - } - } - } - } - - #[test] - fn test_boolean_and() { - let variants = [ - OperandType::True, - OperandType::False, - OperandType::AllocatedTrue, - OperandType::AllocatedFalse, - OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse - ]; - - for first_operand in variants.iter().cloned() { - for second_operand in variants.iter().cloned() { - let mut cs = TestConstraintSystem::::new(); - - let a; - let b; - - { - let mut dyn_construct = |operand, name| { - let cs = cs.namespace(|| name); - - match operand { - OperandType::True => Boolean::constant(true), - OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), - } - }; - - a = dyn_construct(first_operand, "a"); - b = dyn_construct(second_operand, "b"); - } - - let c = Boolean::and(&mut cs, &a, &b).unwrap(); - - assert!(cs.is_satisfied()); - - match (first_operand, second_operand, c) { - (OperandType::True, OperandType::True, Boolean::Constant(true)) => {}, - (OperandType::True, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::True, OperandType::AllocatedTrue, Boolean::Is(_)) => {}, - (OperandType::True, OperandType::AllocatedFalse, Boolean::Is(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {}, - - (OperandType::False, OperandType::True, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::AllocatedTrue, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::AllocatedFalse, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::NegatedAllocatedTrue, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::NegatedAllocatedFalse, Boolean::Constant(false)) => {}, - - (OperandType::AllocatedTrue, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::AllocatedTrue, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::AllocatedTrue, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { - assert!(cs.get("and result") == Field::one()); - assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedTrue, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { - assert!(cs.get("and result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { - assert!(cs.get("and not result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { - assert!(cs.get("and not result") == Field::one()); - assert_eq!(v.value, Some(true)); - }, - - (OperandType::AllocatedFalse, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::AllocatedFalse, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::AllocatedFalse, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { - assert!(cs.get("and result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { - assert!(cs.get("and result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { - assert!(cs.get("and not result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { - assert!(cs.get("and not result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - - (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { - assert!(cs.get("and not result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { - assert!(cs.get("and not result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { - assert!(cs.get("nor result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { - assert!(cs.get("nor result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - - (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { - assert!(cs.get("and not result") == Field::one()); - assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { - assert!(cs.get("and not result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { - assert!(cs.get("nor result") == Field::zero()); - assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { - assert!(cs.get("nor result") == Field::one()); - assert_eq!(v.value, Some(true)); - }, - - _ => { - panic!("unexpected behavior at {:?} AND {:?}", first_operand, second_operand); - } - } - } - } - } - - #[test] - fn test_u64_into_boolean_vec_le() { - let mut cs = TestConstraintSystem::::new(); - - let bits = u64_into_boolean_vec_le(&mut cs, Some(17234652694787248421)).unwrap(); - - assert!(cs.is_satisfied()); - - assert_eq!(bits.len(), 64); - - assert_eq!(bits[63 - 0].get_value().unwrap(), true); - assert_eq!(bits[63 - 1].get_value().unwrap(), true); - assert_eq!(bits[63 - 2].get_value().unwrap(), true); - assert_eq!(bits[63 - 3].get_value().unwrap(), false); - assert_eq!(bits[63 - 4].get_value().unwrap(), true); - assert_eq!(bits[63 - 5].get_value().unwrap(), true); - assert_eq!(bits[63 - 20].get_value().unwrap(), true); - assert_eq!(bits[63 - 21].get_value().unwrap(), false); - assert_eq!(bits[63 - 22].get_value().unwrap(), false); - } - - #[test] - fn test_field_into_allocated_bits_le() { - let mut cs = TestConstraintSystem::::new(); - - let r = Fr::from_str("9147677615426976802526883532204139322118074541891858454835346926874644257775").unwrap(); - - let bits = field_into_allocated_bits_le(&mut cs, Some(r)).unwrap(); - - assert!(cs.is_satisfied()); - - assert_eq!(bits.len(), 255); - - assert_eq!(bits[254 - 0].value.unwrap(), false); - assert_eq!(bits[254 - 1].value.unwrap(), false); - assert_eq!(bits[254 - 2].value.unwrap(), true); - assert_eq!(bits[254 - 3].value.unwrap(), false); - assert_eq!(bits[254 - 4].value.unwrap(), true); - assert_eq!(bits[254 - 5].value.unwrap(), false); - assert_eq!(bits[254 - 20].value.unwrap(), true); - assert_eq!(bits[254 - 23].value.unwrap(), true); - } - - #[test] - fn test_boolean_sha256_ch() { - let variants = [ - OperandType::True, - OperandType::False, - OperandType::AllocatedTrue, - OperandType::AllocatedFalse, - OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse - ]; - - for first_operand in variants.iter().cloned() { - for second_operand in variants.iter().cloned() { - for third_operand in variants.iter().cloned() { - let mut cs = TestConstraintSystem::::new(); - - let a; - let b; - let c; - - // ch = (a and b) xor ((not a) and c) - let expected = (first_operand.val() & second_operand.val()) ^ - ((!first_operand.val()) & third_operand.val()); - - { - let mut dyn_construct = |operand, name| { - let cs = cs.namespace(|| name); - - match operand { - OperandType::True => Boolean::constant(true), - OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), - } - }; - - a = dyn_construct(first_operand, "a"); - b = dyn_construct(second_operand, "b"); - c = dyn_construct(third_operand, "c"); - } - - let maj = Boolean::sha256_ch(&mut cs, &a, &b, &c).unwrap(); - - assert!(cs.is_satisfied()); - - assert_eq!(maj.get_value().unwrap(), expected); - - if first_operand.is_constant() || - second_operand.is_constant() || - third_operand.is_constant() - { - if first_operand.is_constant() && - second_operand.is_constant() && - third_operand.is_constant() - { - assert_eq!(cs.num_constraints(), 0); - } - } - else - { - assert_eq!(cs.get("ch"), { - if expected { - Fr::one() - } else { - Fr::zero() - } - }); - cs.set("ch", { - if expected { - Fr::zero() - } else { - Fr::one() - } - }); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "ch computation"); - } - } - } - } - } - - #[test] - fn test_boolean_sha256_maj() { - let variants = [ - OperandType::True, - OperandType::False, - OperandType::AllocatedTrue, - OperandType::AllocatedFalse, - OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse - ]; - - for first_operand in variants.iter().cloned() { - for second_operand in variants.iter().cloned() { - for third_operand in variants.iter().cloned() { - let mut cs = TestConstraintSystem::::new(); - - let a; - let b; - let c; - - // maj = (a and b) xor (a and c) xor (b and c) - let expected = (first_operand.val() & second_operand.val()) ^ - (first_operand.val() & third_operand.val()) ^ - (second_operand.val() & third_operand.val()); - - { - let mut dyn_construct = |operand, name| { - let cs = cs.namespace(|| name); - - match operand { - OperandType::True => Boolean::constant(true), - OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), - } - }; - - a = dyn_construct(first_operand, "a"); - b = dyn_construct(second_operand, "b"); - c = dyn_construct(third_operand, "c"); - } - - let maj = Boolean::sha256_maj(&mut cs, &a, &b, &c).unwrap(); - - assert!(cs.is_satisfied()); - - assert_eq!(maj.get_value().unwrap(), expected); - - if first_operand.is_constant() || - second_operand.is_constant() || - third_operand.is_constant() - { - if first_operand.is_constant() && - second_operand.is_constant() && - third_operand.is_constant() - { - assert_eq!(cs.num_constraints(), 0); - } - } - else - { - assert_eq!(cs.get("maj"), { - if expected { - Fr::one() - } else { - Fr::zero() - } - }); - cs.set("maj", { - if expected { - Fr::zero() - } else { - Fr::one() - } - }); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "maj computation"); - } - } - } - } - } -} diff --git a/sapling-crypto/src/circuit/ecc.rs b/sapling-crypto/src/circuit/ecc.rs deleted file mode 100644 index 71f1caa..0000000 --- a/sapling-crypto/src/circuit/ecc.rs +++ /dev/null @@ -1,1213 +0,0 @@ -use pairing::{ - Engine, - Field -}; - -use bellman::{ - SynthesisError, - ConstraintSystem -}; - -use super::{ - Assignment -}; - -use super::num::{ - AllocatedNum, - Num -}; - -use ::jubjub::{ - edwards, - JubjubEngine, - JubjubParams, - FixedGenerators -}; - -use super::lookup::{ - lookup3_xy -}; - -use super::boolean::Boolean; - -#[derive(Clone)] -pub struct EdwardsPoint { - x: AllocatedNum, - y: AllocatedNum -} - -/// Perform a fixed-base scalar multiplication with -/// `by` being in little-endian bit order. -pub fn fixed_base_multiplication( - mut cs: CS, - base: FixedGenerators, - by: &[Boolean], - params: &E::Params -) -> Result, SynthesisError> - where CS: ConstraintSystem, - E: JubjubEngine -{ - // Represents the result of the multiplication - let mut result = None; - - for (i, (chunk, window)) in by.chunks(3) - .zip(params.circuit_generators(base).iter()) - .enumerate() - { - let chunk_a = chunk.get(0).map(|e| e.clone()).unwrap_or(Boolean::constant(false)); - let chunk_b = chunk.get(1).map(|e| e.clone()).unwrap_or(Boolean::constant(false)); - let chunk_c = chunk.get(2).map(|e| e.clone()).unwrap_or(Boolean::constant(false)); - - let (x, y) = lookup3_xy( - cs.namespace(|| format!("window table lookup {}", i)), - &[chunk_a, chunk_b, chunk_c], - window - )?; - - let p = EdwardsPoint { - x: x, - y: y - }; - - if result.is_none() { - result = Some(p); - } else { - result = Some(result.unwrap().add( - cs.namespace(|| format!("addition {}", i)), - &p, - params - )?); - } - } - - Ok(result.get()?.clone()) -} - -impl EdwardsPoint { - pub fn get_x(&self) -> &AllocatedNum { - &self.x - } - - pub fn get_y(&self) -> &AllocatedNum { - &self.y - } - - pub fn assert_not_small_order( - &self, - mut cs: CS, - params: &E::Params - ) -> Result<(), SynthesisError> - where CS: ConstraintSystem - { - let tmp = self.double( - cs.namespace(|| "first doubling"), - params - )?; - let tmp = tmp.double( - cs.namespace(|| "second doubling"), - params - )?; - let tmp = tmp.double( - cs.namespace(|| "third doubling"), - params - )?; - - // (0, -1) is a small order point, but won't ever appear here - // because cofactor is 2^3, and we performed three doublings. - // (0, 1) is the neutral element, so checking if x is nonzero - // is sufficient to prevent small order points here. - tmp.x.assert_nonzero(cs.namespace(|| "check x != 0"))?; - - Ok(()) - } - - pub fn inputize( - &self, - mut cs: CS - ) -> Result<(), SynthesisError> - where CS: ConstraintSystem - { - self.x.inputize(cs.namespace(|| "x"))?; - self.y.inputize(cs.namespace(|| "y"))?; - - Ok(()) - } - - /// This converts the point into a representation. - pub fn repr( - &self, - mut cs: CS - ) -> Result, SynthesisError> - where CS: ConstraintSystem - { - let mut tmp = vec![]; - - let x = self.x.into_bits_le_strict( - cs.namespace(|| "unpack x") - )?; - - let y = self.y.into_bits_le_strict( - cs.namespace(|| "unpack y") - )?; - - tmp.extend(y); - tmp.push(x[0].clone()); - - Ok(tmp) - } - - /// This 'witnesses' a point inside the constraint system. - /// It guarantees the point is on the curve. - pub fn witness( - mut cs: CS, - p: Option>, - params: &E::Params - ) -> Result - where CS: ConstraintSystem - { - let p = p.map(|p| p.into_xy()); - - // Allocate x - let x = AllocatedNum::alloc( - cs.namespace(|| "x"), - || { - Ok(p.get()?.0) - } - )?; - - // Allocate y - let y = AllocatedNum::alloc( - cs.namespace(|| "y"), - || { - Ok(p.get()?.1) - } - )?; - - Self::interpret( - cs.namespace(|| "point interpretation"), - &x, - &y, - params - ) - } - - /// Returns `self` if condition is true, and the neutral - /// element (0, 1) otherwise. - pub fn conditionally_select( - &self, - mut cs: CS, - condition: &Boolean - ) -> Result - where CS: ConstraintSystem - { - // Compute x' = self.x if condition, and 0 otherwise - let x_prime = AllocatedNum::alloc(cs.namespace(|| "x'"), || { - if *condition.get_value().get()? { - Ok(*self.x.get_value().get()?) - } else { - Ok(E::Fr::zero()) - } - })?; - - // condition * x = x' - // if condition is 0, x' must be 0 - // if condition is 1, x' must be x - let one = CS::one(); - cs.enforce( - || "x' computation", - |lc| lc + self.x.get_variable(), - |_| condition.lc(one, E::Fr::one()), - |lc| lc + x_prime.get_variable() - ); - - // Compute y' = self.y if condition, and 1 otherwise - let y_prime = AllocatedNum::alloc(cs.namespace(|| "y'"), || { - if *condition.get_value().get()? { - Ok(*self.y.get_value().get()?) - } else { - Ok(E::Fr::one()) - } - })?; - - // condition * y = y' - (1 - condition) - // if condition is 0, y' must be 1 - // if condition is 1, y' must be y - cs.enforce( - || "y' computation", - |lc| lc + self.y.get_variable(), - |_| condition.lc(one, E::Fr::one()), - |lc| lc + y_prime.get_variable() - - &condition.not().lc(one, E::Fr::one()) - ); - - Ok(EdwardsPoint { - x: x_prime, - y: y_prime - }) - } - - /// Performs a scalar multiplication of this twisted Edwards - /// point by a scalar represented as a sequence of booleans - /// in little-endian bit order. - pub fn mul( - &self, - mut cs: CS, - by: &[Boolean], - params: &E::Params - ) -> Result - where CS: ConstraintSystem - { - // Represents the current "magnitude" of the base - // that we're operating over. Starts at self, - // then 2*self, then 4*self, ... - let mut curbase = None; - - // Represents the result of the multiplication - let mut result = None; - - for (i, bit) in by.iter().enumerate() { - if curbase.is_none() { - curbase = Some(self.clone()); - } else { - // Double the previous value - curbase = Some( - curbase.unwrap() - .double(cs.namespace(|| format!("doubling {}", i)), params)? - ); - } - - // Represents the select base. If the bit for this magnitude - // is true, this will return `curbase`. Otherwise it will - // return the neutral element, which will have no effect on - // the result. - let thisbase = curbase.as_ref() - .unwrap() - .conditionally_select( - cs.namespace(|| format!("selection {}", i)), - bit - )?; - - if result.is_none() { - result = Some(thisbase); - } else { - result = Some(result.unwrap().add( - cs.namespace(|| format!("addition {}", i)), - &thisbase, - params - )?); - } - } - - Ok(result.get()?.clone()) - } - - pub fn interpret( - mut cs: CS, - x: &AllocatedNum, - y: &AllocatedNum, - params: &E::Params - ) -> Result - where CS: ConstraintSystem - { - // -x^2 + y^2 = 1 + dx^2y^2 - - let x2 = x.square(cs.namespace(|| "x^2"))?; - let y2 = y.square(cs.namespace(|| "y^2"))?; - let x2y2 = x2.mul(cs.namespace(|| "x^2 y^2"), &y2)?; - - let one = CS::one(); - cs.enforce( - || "on curve check", - |lc| lc - x2.get_variable() - + y2.get_variable(), - |lc| lc + one, - |lc| lc + one - + (*params.edwards_d(), x2y2.get_variable()) - ); - - Ok(EdwardsPoint { - x: x.clone(), - y: y.clone() - }) - } - - pub fn double( - &self, - mut cs: CS, - params: &E::Params - ) -> Result - where CS: ConstraintSystem - { - // Compute T = (x1 + y1) * (x1 + y1) - let t = AllocatedNum::alloc(cs.namespace(|| "T"), || { - let mut t0 = *self.x.get_value().get()?; - t0.add_assign(self.y.get_value().get()?); - - let mut t1 = *self.x.get_value().get()?; - t1.add_assign(self.y.get_value().get()?); - - t0.mul_assign(&t1); - - Ok(t0) - })?; - - cs.enforce( - || "T computation", - |lc| lc + self.x.get_variable() - + self.y.get_variable(), - |lc| lc + self.x.get_variable() - + self.y.get_variable(), - |lc| lc + t.get_variable() - ); - - // Compute A = x1 * y1 - let a = self.x.mul(cs.namespace(|| "A computation"), &self.y)?; - - // Compute C = d*A*A - let c = AllocatedNum::alloc(cs.namespace(|| "C"), || { - let mut t0 = *a.get_value().get()?; - t0.square(); - t0.mul_assign(params.edwards_d()); - - Ok(t0) - })?; - - cs.enforce( - || "C computation", - |lc| lc + (*params.edwards_d(), a.get_variable()), - |lc| lc + a.get_variable(), - |lc| lc + c.get_variable() - ); - - // Compute x3 = (2.A) / (1 + C) - let x3 = AllocatedNum::alloc(cs.namespace(|| "x3"), || { - let mut t0 = *a.get_value().get()?; - t0.double(); - - let mut t1 = E::Fr::one(); - t1.add_assign(c.get_value().get()?); - - match t1.inverse() { - Some(t1) => { - t0.mul_assign(&t1); - - Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) - } - } - })?; - - let one = CS::one(); - cs.enforce( - || "x3 computation", - |lc| lc + one + c.get_variable(), - |lc| lc + x3.get_variable(), - |lc| lc + a.get_variable() - + a.get_variable() - ); - - // Compute y3 = (U - 2.A) / (1 - C) - let y3 = AllocatedNum::alloc(cs.namespace(|| "y3"), || { - let mut t0 = *a.get_value().get()?; - t0.double(); - t0.negate(); - t0.add_assign(t.get_value().get()?); - - let mut t1 = E::Fr::one(); - t1.sub_assign(c.get_value().get()?); - - match t1.inverse() { - Some(t1) => { - t0.mul_assign(&t1); - - Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) - } - } - })?; - - cs.enforce( - || "y3 computation", - |lc| lc + one - c.get_variable(), - |lc| lc + y3.get_variable(), - |lc| lc + t.get_variable() - - a.get_variable() - - a.get_variable() - ); - - Ok(EdwardsPoint { - x: x3, - y: y3 - }) - } - - /// Perform addition between any two points - pub fn add( - &self, - mut cs: CS, - other: &Self, - params: &E::Params - ) -> Result - where CS: ConstraintSystem - { - // Compute U = (x1 + y1) * (x2 + y2) - let u = AllocatedNum::alloc(cs.namespace(|| "U"), || { - let mut t0 = *self.x.get_value().get()?; - t0.add_assign(self.y.get_value().get()?); - - let mut t1 = *other.x.get_value().get()?; - t1.add_assign(other.y.get_value().get()?); - - t0.mul_assign(&t1); - - Ok(t0) - })?; - - cs.enforce( - || "U computation", - |lc| lc + self.x.get_variable() - + self.y.get_variable(), - |lc| lc + other.x.get_variable() - + other.y.get_variable(), - |lc| lc + u.get_variable() - ); - - // Compute A = y2 * x1 - let a = other.y.mul(cs.namespace(|| "A computation"), &self.x)?; - - // Compute B = x2 * y1 - let b = other.x.mul(cs.namespace(|| "B computation"), &self.y)?; - - // Compute C = d*A*B - let c = AllocatedNum::alloc(cs.namespace(|| "C"), || { - let mut t0 = *a.get_value().get()?; - t0.mul_assign(b.get_value().get()?); - t0.mul_assign(params.edwards_d()); - - Ok(t0) - })?; - - cs.enforce( - || "C computation", - |lc| lc + (*params.edwards_d(), a.get_variable()), - |lc| lc + b.get_variable(), - |lc| lc + c.get_variable() - ); - - // Compute x3 = (A + B) / (1 + C) - let x3 = AllocatedNum::alloc(cs.namespace(|| "x3"), || { - let mut t0 = *a.get_value().get()?; - t0.add_assign(b.get_value().get()?); - - let mut t1 = E::Fr::one(); - t1.add_assign(c.get_value().get()?); - - match t1.inverse() { - Some(t1) => { - t0.mul_assign(&t1); - - Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) - } - } - })?; - - let one = CS::one(); - cs.enforce( - || "x3 computation", - |lc| lc + one + c.get_variable(), - |lc| lc + x3.get_variable(), - |lc| lc + a.get_variable() - + b.get_variable() - ); - - // Compute y3 = (U - A - B) / (1 - C) - let y3 = AllocatedNum::alloc(cs.namespace(|| "y3"), || { - let mut t0 = *u.get_value().get()?; - t0.sub_assign(a.get_value().get()?); - t0.sub_assign(b.get_value().get()?); - - let mut t1 = E::Fr::one(); - t1.sub_assign(c.get_value().get()?); - - match t1.inverse() { - Some(t1) => { - t0.mul_assign(&t1); - - Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) - } - } - })?; - - cs.enforce( - || "y3 computation", - |lc| lc + one - c.get_variable(), - |lc| lc + y3.get_variable(), - |lc| lc + u.get_variable() - - a.get_variable() - - b.get_variable() - ); - - Ok(EdwardsPoint { - x: x3, - y: y3 - }) - } -} - -pub struct MontgomeryPoint { - x: Num, - y: Num -} - -impl MontgomeryPoint { - /// Converts an element in the prime order subgroup into - /// a point in the birationally equivalent twisted - /// Edwards curve. - pub fn into_edwards( - &self, - mut cs: CS, - params: &E::Params - ) -> Result, SynthesisError> - where CS: ConstraintSystem - { - // Compute u = (scale*x) / y - let u = AllocatedNum::alloc(cs.namespace(|| "u"), || { - let mut t0 = *self.x.get_value().get()?; - t0.mul_assign(params.scale()); - - match self.y.get_value().get()?.inverse() { - Some(invy) => { - t0.mul_assign(&invy); - - Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) - } - } - })?; - - cs.enforce( - || "u computation", - |lc| lc + &self.y.lc(E::Fr::one()), - |lc| lc + u.get_variable(), - |lc| lc + &self.x.lc(*params.scale()) - ); - - // Compute v = (x - 1) / (x + 1) - let v = AllocatedNum::alloc(cs.namespace(|| "v"), || { - let mut t0 = *self.x.get_value().get()?; - let mut t1 = t0; - t0.sub_assign(&E::Fr::one()); - t1.add_assign(&E::Fr::one()); - - match t1.inverse() { - Some(t1) => { - t0.mul_assign(&t1); - - Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) - } - } - })?; - - let one = CS::one(); - cs.enforce( - || "v computation", - |lc| lc + &self.x.lc(E::Fr::one()) - + one, - |lc| lc + v.get_variable(), - |lc| lc + &self.x.lc(E::Fr::one()) - - one, - ); - - Ok(EdwardsPoint { - x: u, - y: v - }) - } - - /// Interprets an (x, y) pair as a point - /// in Montgomery, does not check that it's - /// on the curve. Useful for constants and - /// window table lookups. - pub fn interpret_unchecked( - x: Num, - y: Num - ) -> Self - { - MontgomeryPoint { - x: x, - y: y - } - } - - /// Performs an affine point addition, not defined for - /// coincident points. - pub fn add( - &self, - mut cs: CS, - other: &Self, - params: &E::Params - ) -> Result - where CS: ConstraintSystem - { - // Compute lambda = (y' - y) / (x' - x) - let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || { - let mut n = *other.y.get_value().get()?; - n.sub_assign(self.y.get_value().get()?); - - let mut d = *other.x.get_value().get()?; - d.sub_assign(self.x.get_value().get()?); - - match d.inverse() { - Some(d) => { - n.mul_assign(&d); - Ok(n) - }, - None => { - Err(SynthesisError::DivisionByZero) - } - } - })?; - - cs.enforce( - || "evaluate lambda", - |lc| lc + &other.x.lc(E::Fr::one()) - - &self.x.lc(E::Fr::one()), - - |lc| lc + lambda.get_variable(), - - |lc| lc + &other.y.lc(E::Fr::one()) - - &self.y.lc(E::Fr::one()) - ); - - // Compute x'' = lambda^2 - A - x - x' - let xprime = AllocatedNum::alloc(cs.namespace(|| "xprime"), || { - let mut t0 = *lambda.get_value().get()?; - t0.square(); - t0.sub_assign(params.montgomery_a()); - t0.sub_assign(self.x.get_value().get()?); - t0.sub_assign(other.x.get_value().get()?); - - Ok(t0) - })?; - - // (lambda) * (lambda) = (A + x + x' + x'') - let one = CS::one(); - cs.enforce( - || "evaluate xprime", - |lc| lc + lambda.get_variable(), - |lc| lc + lambda.get_variable(), - |lc| lc + (*params.montgomery_a(), one) - + &self.x.lc(E::Fr::one()) - + &other.x.lc(E::Fr::one()) - + xprime.get_variable() - ); - - // Compute y' = -(y + lambda(x' - x)) - let yprime = AllocatedNum::alloc(cs.namespace(|| "yprime"), || { - let mut t0 = *xprime.get_value().get()?; - t0.sub_assign(self.x.get_value().get()?); - t0.mul_assign(lambda.get_value().get()?); - t0.add_assign(self.y.get_value().get()?); - t0.negate(); - - Ok(t0) - })?; - - // y' + y = lambda(x - x') - cs.enforce( - || "evaluate yprime", - |lc| lc + &self.x.lc(E::Fr::one()) - - xprime.get_variable(), - - |lc| lc + lambda.get_variable(), - - |lc| lc + yprime.get_variable() - + &self.y.lc(E::Fr::one()) - ); - - Ok(MontgomeryPoint { - x: xprime.into(), - y: yprime.into() - }) - } -} - -#[cfg(test)] -mod test { - use bellman::{ConstraintSystem}; - use rand::{XorShiftRng, SeedableRng, Rand, Rng}; - use pairing::bls12_381::{Bls12, Fr}; - use pairing::{BitIterator, Field, PrimeField}; - use ::circuit::test::*; - use ::jubjub::{ - montgomery, - edwards, - JubjubBls12, - JubjubParams, - FixedGenerators - }; - use ::jubjub::fs::Fs; - use super::{ - MontgomeryPoint, - EdwardsPoint, - AllocatedNum, - fixed_base_multiplication - }; - use super::super::boolean::{ - Boolean, - AllocatedBit - }; - - #[test] - fn test_into_edwards() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let mut cs = TestConstraintSystem::::new(); - - let p = montgomery::Point::::rand(rng, params); - let (u, v) = edwards::Point::from_montgomery(&p, params).into_xy(); - let (x, y) = p.into_xy().unwrap(); - - let numx = AllocatedNum::alloc(cs.namespace(|| "mont x"), || { - Ok(x) - }).unwrap(); - let numy = AllocatedNum::alloc(cs.namespace(|| "mont y"), || { - Ok(y) - }).unwrap(); - - let p = MontgomeryPoint::interpret_unchecked(numx.into(), numy.into()); - - let q = p.into_edwards(&mut cs, params).unwrap(); - - assert!(cs.is_satisfied()); - assert!(q.x.get_value().unwrap() == u); - assert!(q.y.get_value().unwrap() == v); - - cs.set("u/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "u computation"); - cs.set("u/num", u); - assert!(cs.is_satisfied()); - - cs.set("v/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "v computation"); - cs.set("v/num", v); - assert!(cs.is_satisfied()); - } - } - - #[test] - fn test_interpret() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let p = edwards::Point::::rand(rng, ¶ms); - - let mut cs = TestConstraintSystem::::new(); - let q = EdwardsPoint::witness( - &mut cs, - Some(p.clone()), - ¶ms - ).unwrap(); - - let p = p.into_xy(); - - assert!(cs.is_satisfied()); - assert_eq!(q.x.get_value().unwrap(), p.0); - assert_eq!(q.y.get_value().unwrap(), p.1); - } - - for _ in 0..100 { - let p = edwards::Point::::rand(rng, ¶ms); - let (x, y) = p.into_xy(); - - let mut cs = TestConstraintSystem::::new(); - let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || { - Ok(x) - }).unwrap(); - let numy = AllocatedNum::alloc(cs.namespace(|| "y"), || { - Ok(y) - }).unwrap(); - - let p = EdwardsPoint::interpret(&mut cs, &numx, &numy, ¶ms).unwrap(); - - assert!(cs.is_satisfied()); - assert_eq!(p.x.get_value().unwrap(), x); - assert_eq!(p.y.get_value().unwrap(), y); - } - - // Random (x, y) are unlikely to be on the curve. - for _ in 0..100 { - let x = rng.gen(); - let y = rng.gen(); - - let mut cs = TestConstraintSystem::::new(); - let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || { - Ok(x) - }).unwrap(); - let numy = AllocatedNum::alloc(cs.namespace(|| "y"), || { - Ok(y) - }).unwrap(); - - EdwardsPoint::interpret(&mut cs, &numx, &numy, ¶ms).unwrap(); - - assert_eq!(cs.which_is_unsatisfied().unwrap(), "on curve check"); - } - } - - #[test] - fn test_edwards_fixed_base_multiplication() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let mut cs = TestConstraintSystem::::new(); - - let p = params.generator(FixedGenerators::NoteCommitmentRandomness); - let s = Fs::rand(rng); - let q = p.mul(s, params); - let (x1, y1) = q.into_xy(); - - let mut s_bits = BitIterator::new(s.into_repr()).collect::>(); - s_bits.reverse(); - s_bits.truncate(Fs::NUM_BITS as usize); - - let s_bits = s_bits.into_iter() - .enumerate() - .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("scalar bit {}", i)), Some(b)).unwrap()) - .map(|v| Boolean::from(v)) - .collect::>(); - - let q = fixed_base_multiplication( - cs.namespace(|| "multiplication"), - FixedGenerators::NoteCommitmentRandomness, - &s_bits, - params - ).unwrap(); - - assert_eq!(q.x.get_value().unwrap(), x1); - assert_eq!(q.y.get_value().unwrap(), y1); - } - } - - #[test] - fn test_edwards_multiplication() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let mut cs = TestConstraintSystem::::new(); - - let p = edwards::Point::::rand(rng, params); - let s = Fs::rand(rng); - let q = p.mul(s, params); - - let (x0, y0) = p.into_xy(); - let (x1, y1) = q.into_xy(); - - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || { - Ok(x0) - }).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || { - Ok(y0) - }).unwrap(); - - let p = EdwardsPoint { - x: num_x0, - y: num_y0 - }; - - let mut s_bits = BitIterator::new(s.into_repr()).collect::>(); - s_bits.reverse(); - s_bits.truncate(Fs::NUM_BITS as usize); - - let s_bits = s_bits.into_iter() - .enumerate() - .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("scalar bit {}", i)), Some(b)).unwrap()) - .map(|v| Boolean::from(v)) - .collect::>(); - - let q = p.mul( - cs.namespace(|| "scalar mul"), - &s_bits, - params - ).unwrap(); - - assert!(cs.is_satisfied()); - - assert_eq!( - q.x.get_value().unwrap(), - x1 - ); - - assert_eq!( - q.y.get_value().unwrap(), - y1 - ); - } - } - - #[test] - fn test_conditionally_select() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let mut cs = TestConstraintSystem::::new(); - - let p = edwards::Point::::rand(rng, params); - - let (x0, y0) = p.into_xy(); - - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || { - Ok(x0) - }).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || { - Ok(y0) - }).unwrap(); - - let p = EdwardsPoint { - x: num_x0, - y: num_y0 - }; - - let mut should_we_select = rng.gen(); - - // Conditionally allocate - let mut b = if rng.gen() { - Boolean::from(AllocatedBit::alloc( - cs.namespace(|| "condition"), - Some(should_we_select) - ).unwrap()) - } else { - Boolean::constant(should_we_select) - }; - - // Conditionally negate - if rng.gen() { - b = b.not(); - should_we_select = !should_we_select; - } - - let q = p.conditionally_select(cs.namespace(|| "select"), &b).unwrap(); - - assert!(cs.is_satisfied()); - - if should_we_select { - assert_eq!(q.x.get_value().unwrap(), x0); - assert_eq!(q.y.get_value().unwrap(), y0); - - cs.set("select/y'/num", Fr::one()); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/y' computation"); - cs.set("select/x'/num", Fr::zero()); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/x' computation"); - } else { - assert_eq!(q.x.get_value().unwrap(), Fr::zero()); - assert_eq!(q.y.get_value().unwrap(), Fr::one()); - - cs.set("select/y'/num", x0); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/y' computation"); - cs.set("select/x'/num", y0); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/x' computation"); - } - } - } - - #[test] - fn test_edwards_addition() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let p1 = edwards::Point::::rand(rng, params); - let p2 = edwards::Point::::rand(rng, params); - - let p3 = p1.add(&p2, params); - - let (x0, y0) = p1.into_xy(); - let (x1, y1) = p2.into_xy(); - let (x2, y2) = p3.into_xy(); - - let mut cs = TestConstraintSystem::::new(); - - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || { - Ok(x0) - }).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || { - Ok(y0) - }).unwrap(); - - let num_x1 = AllocatedNum::alloc(cs.namespace(|| "x1"), || { - Ok(x1) - }).unwrap(); - let num_y1 = AllocatedNum::alloc(cs.namespace(|| "y1"), || { - Ok(y1) - }).unwrap(); - - let p1 = EdwardsPoint { - x: num_x0, - y: num_y0 - }; - - let p2 = EdwardsPoint { - x: num_x1, - y: num_y1 - }; - - let p3 = p1.add(cs.namespace(|| "addition"), &p2, params).unwrap(); - - assert!(cs.is_satisfied()); - - assert!(p3.x.get_value().unwrap() == x2); - assert!(p3.y.get_value().unwrap() == y2); - - let u = cs.get("addition/U/num"); - cs.set("addition/U/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/U computation")); - cs.set("addition/U/num", u); - assert!(cs.is_satisfied()); - - let x3 = cs.get("addition/x3/num"); - cs.set("addition/x3/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/x3 computation")); - cs.set("addition/x3/num", x3); - assert!(cs.is_satisfied()); - - let y3 = cs.get("addition/y3/num"); - cs.set("addition/y3/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/y3 computation")); - cs.set("addition/y3/num", y3); - assert!(cs.is_satisfied()); - } - } - - #[test] - fn test_edwards_doubling() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let p1 = edwards::Point::::rand(rng, params); - let p2 = p1.double(params); - - let (x0, y0) = p1.into_xy(); - let (x1, y1) = p2.into_xy(); - - let mut cs = TestConstraintSystem::::new(); - - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || { - Ok(x0) - }).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || { - Ok(y0) - }).unwrap(); - - let p1 = EdwardsPoint { - x: num_x0, - y: num_y0 - }; - - let p2 = p1.double(cs.namespace(|| "doubling"), params).unwrap(); - - assert!(cs.is_satisfied()); - - assert!(p2.x.get_value().unwrap() == x1); - assert!(p2.y.get_value().unwrap() == y1); - } - } - - #[test] - fn test_montgomery_addition() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let p1 = loop { - let x: Fr = rng.gen(); - let s: bool = rng.gen(); - - if let Some(p) = montgomery::Point::::get_for_x(x, s, params) { - break p; - } - }; - - let p2 = loop { - let x: Fr = rng.gen(); - let s: bool = rng.gen(); - - if let Some(p) = montgomery::Point::::get_for_x(x, s, params) { - break p; - } - }; - - let p3 = p1.add(&p2, params); - - let (x0, y0) = p1.into_xy().unwrap(); - let (x1, y1) = p2.into_xy().unwrap(); - let (x2, y2) = p3.into_xy().unwrap(); - - let mut cs = TestConstraintSystem::::new(); - - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || { - Ok(x0) - }).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || { - Ok(y0) - }).unwrap(); - - let num_x1 = AllocatedNum::alloc(cs.namespace(|| "x1"), || { - Ok(x1) - }).unwrap(); - let num_y1 = AllocatedNum::alloc(cs.namespace(|| "y1"), || { - Ok(y1) - }).unwrap(); - - let p1 = MontgomeryPoint { - x: num_x0.into(), - y: num_y0.into() - }; - - let p2 = MontgomeryPoint { - x: num_x1.into(), - y: num_y1.into() - }; - - let p3 = p1.add(cs.namespace(|| "addition"), &p2, params).unwrap(); - - assert!(cs.is_satisfied()); - - assert!(p3.x.get_value().unwrap() == x2); - assert!(p3.y.get_value().unwrap() == y2); - - cs.set("addition/yprime/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate yprime")); - cs.set("addition/yprime/num", y2); - assert!(cs.is_satisfied()); - - cs.set("addition/xprime/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate xprime")); - cs.set("addition/xprime/num", x2); - assert!(cs.is_satisfied()); - - cs.set("addition/lambda/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate lambda")); - } - } -} diff --git a/sapling-crypto/src/circuit/lookup.rs b/sapling-crypto/src/circuit/lookup.rs deleted file mode 100644 index 1ffc7f7..0000000 --- a/sapling-crypto/src/circuit/lookup.rs +++ /dev/null @@ -1,307 +0,0 @@ -use pairing::{Engine, Field}; -use super::*; -use super::num::{ - AllocatedNum, - Num -}; -use super::boolean::Boolean; -use bellman::{ - ConstraintSystem -}; - -// Synthesize the constants for each base pattern. -fn synth<'a, E: Engine, I>( - window_size: usize, - constants: I, - assignment: &mut [E::Fr] -) - where I: IntoIterator -{ - assert_eq!(assignment.len(), 1 << window_size); - - for (i, constant) in constants.into_iter().enumerate() { - let mut cur = assignment[i]; - cur.negate(); - cur.add_assign(constant); - assignment[i] = cur; - for (j, eval) in assignment.iter_mut().enumerate().skip(i + 1) { - if j & i == i { - eval.add_assign(&cur); - } - } - } -} - -/// Performs a 3-bit window table lookup. `bits` is in -/// little-endian order. -pub fn lookup3_xy( - mut cs: CS, - bits: &[Boolean], - coords: &[(E::Fr, E::Fr)] -) -> Result<(AllocatedNum, AllocatedNum), SynthesisError> - where CS: ConstraintSystem -{ - assert_eq!(bits.len(), 3); - assert_eq!(coords.len(), 8); - - // Calculate the index into `coords` - let i = - match (bits[0].get_value(), bits[1].get_value(), bits[2].get_value()) { - (Some(a_value), Some(b_value), Some(c_value)) => { - let mut tmp = 0; - if a_value { - tmp += 1; - } - if b_value { - tmp += 2; - } - if c_value { - tmp += 4; - } - Some(tmp) - }, - _ => None - }; - - // Allocate the x-coordinate resulting from the lookup - let res_x = AllocatedNum::alloc( - cs.namespace(|| "x"), - || { - Ok(coords[*i.get()?].0) - } - )?; - - // Allocate the y-coordinate resulting from the lookup - let res_y = AllocatedNum::alloc( - cs.namespace(|| "y"), - || { - Ok(coords[*i.get()?].1) - } - )?; - - // Compute the coefficients for the lookup constraints - let mut x_coeffs = [E::Fr::zero(); 8]; - let mut y_coeffs = [E::Fr::zero(); 8]; - synth::(3, coords.iter().map(|c| &c.0), &mut x_coeffs); - synth::(3, coords.iter().map(|c| &c.1), &mut y_coeffs); - - let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[1], &bits[2])?; - - let one = CS::one(); - - cs.enforce( - || "x-coordinate lookup", - |lc| lc + (x_coeffs[0b001], one) - + &bits[1].lc::(one, x_coeffs[0b011]) - + &bits[2].lc::(one, x_coeffs[0b101]) - + &precomp.lc::(one, x_coeffs[0b111]), - |lc| lc + &bits[0].lc::(one, E::Fr::one()), - |lc| lc + res_x.get_variable() - - (x_coeffs[0b000], one) - - &bits[1].lc::(one, x_coeffs[0b010]) - - &bits[2].lc::(one, x_coeffs[0b100]) - - &precomp.lc::(one, x_coeffs[0b110]), - ); - - cs.enforce( - || "y-coordinate lookup", - |lc| lc + (y_coeffs[0b001], one) - + &bits[1].lc::(one, y_coeffs[0b011]) - + &bits[2].lc::(one, y_coeffs[0b101]) - + &precomp.lc::(one, y_coeffs[0b111]), - |lc| lc + &bits[0].lc::(one, E::Fr::one()), - |lc| lc + res_y.get_variable() - - (y_coeffs[0b000], one) - - &bits[1].lc::(one, y_coeffs[0b010]) - - &bits[2].lc::(one, y_coeffs[0b100]) - - &precomp.lc::(one, y_coeffs[0b110]), - ); - - Ok((res_x, res_y)) -} - -/// Performs a 3-bit window table lookup, where -/// one of the bits is a sign bit. -pub fn lookup3_xy_with_conditional_negation( - mut cs: CS, - bits: &[Boolean], - coords: &[(E::Fr, E::Fr)] -) -> Result<(Num, Num), SynthesisError> - where CS: ConstraintSystem -{ - assert_eq!(bits.len(), 3); - assert_eq!(coords.len(), 4); - - // Calculate the index into `coords` - let i = - match (bits[0].get_value(), bits[1].get_value()) { - (Some(a_value), Some(b_value)) => { - let mut tmp = 0; - if a_value { - tmp += 1; - } - if b_value { - tmp += 2; - } - Some(tmp) - }, - _ => None - }; - - // Allocate the y-coordinate resulting from the lookup - // and conditional negation - let y = AllocatedNum::alloc( - cs.namespace(|| "y"), - || { - let mut tmp = coords[*i.get()?].1; - if *bits[2].get_value().get()? { - tmp.negate(); - } - Ok(tmp) - } - )?; - - let one = CS::one(); - - // Compute the coefficients for the lookup constraints - let mut x_coeffs = [E::Fr::zero(); 4]; - let mut y_coeffs = [E::Fr::zero(); 4]; - synth::(2, coords.iter().map(|c| &c.0), &mut x_coeffs); - synth::(2, coords.iter().map(|c| &c.1), &mut y_coeffs); - - let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[0], &bits[1])?; - - let x = Num::zero() - .add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00]) - .add_bool_with_coeff(one, &bits[0], x_coeffs[0b01]) - .add_bool_with_coeff(one, &bits[1], x_coeffs[0b10]) - .add_bool_with_coeff(one, &precomp, x_coeffs[0b11]); - - let y_lc = precomp.lc::(one, y_coeffs[0b11]) + - &bits[1].lc::(one, y_coeffs[0b10]) + - &bits[0].lc::(one, y_coeffs[0b01]) + - (y_coeffs[0b00], one); - - cs.enforce( - || "y-coordinate lookup", - |lc| lc + &y_lc + &y_lc, - |lc| lc + &bits[2].lc::(one, E::Fr::one()), - |lc| lc + &y_lc - y.get_variable() - ); - - Ok((x, y.into())) -} - -#[cfg(test)] -mod test { - use rand::{SeedableRng, Rand, Rng, XorShiftRng}; - use super::*; - use ::circuit::test::*; - use ::circuit::boolean::{Boolean, AllocatedBit}; - use pairing::bls12_381::{Bls12, Fr}; - - #[test] - fn test_lookup3_xy() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0656]); - - for _ in 0..100 { - let mut cs = TestConstraintSystem::::new(); - - let a_val = rng.gen(); - let a = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap() - ); - - let b_val = rng.gen(); - let b = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap() - ); - - let c_val = rng.gen(); - let c = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap() - ); - - let bits = vec![a, b, c]; - - let points: Vec<(Fr, Fr)> = (0..8).map(|_| (rng.gen(), rng.gen())).collect(); - - let res = lookup3_xy(&mut cs, &bits, &points).unwrap(); - - assert!(cs.is_satisfied()); - - let mut index = 0; - if a_val { index += 1 } - if b_val { index += 2 } - if c_val { index += 4 } - - assert_eq!(res.0.get_value().unwrap(), points[index].0); - assert_eq!(res.1.get_value().unwrap(), points[index].1); - } - } - - #[test] - fn test_lookup3_xy_with_conditional_negation() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let mut cs = TestConstraintSystem::::new(); - - let a_val = rng.gen(); - let a = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap() - ); - - let b_val = rng.gen(); - let b = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap() - ); - - let c_val = rng.gen(); - let c = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap() - ); - - let bits = vec![a, b, c]; - - let points: Vec<(Fr, Fr)> = (0..4).map(|_| (rng.gen(), rng.gen())).collect(); - - let res = lookup3_xy_with_conditional_negation(&mut cs, &bits, &points).unwrap(); - - assert!(cs.is_satisfied()); - - let mut index = 0; - if a_val { index += 1 } - if b_val { index += 2 } - - assert_eq!(res.0.get_value().unwrap(), points[index].0); - let mut tmp = points[index].1; - if c_val { tmp.negate() } - assert_eq!(res.1.get_value().unwrap(), tmp); - } - } - - #[test] - fn test_synth() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let window_size = 4; - - let mut assignment = vec![Fr::zero(); 1 << window_size]; - let constants: Vec<_> = (0..(1 << window_size)).map(|_| Fr::rand(&mut rng)).collect(); - - synth::(window_size, &constants, &mut assignment); - - for b in 0..(1 << window_size) { - let mut acc = Fr::zero(); - - for j in 0..(1 << window_size) { - if j & b == j { - acc.add_assign(&assignment[j]); - } - } - - assert_eq!(acc, constants[b]); - } - } -} diff --git a/sapling-crypto/src/circuit/mod.rs b/sapling-crypto/src/circuit/mod.rs deleted file mode 100644 index fe0fe50..0000000 --- a/sapling-crypto/src/circuit/mod.rs +++ /dev/null @@ -1,39 +0,0 @@ -#[cfg(test)] -pub mod test; - -pub mod boolean; -pub mod multieq; -pub mod uint32; -pub mod blake2s; -pub mod num; -pub mod lookup; -pub mod ecc; -pub mod pedersen_hash; -pub mod multipack; -pub mod sha256; - -pub mod sapling; -pub mod sprout; - -use bellman::{ - SynthesisError -}; - -// TODO: This should probably be removed and we -// should use existing helper methods on `Option` -// for mapping with an error. -/// This basically is just an extension to `Option` -/// which allows for a convenient mapping to an -/// error on `None`. -trait Assignment { - fn get(&self) -> Result<&T, SynthesisError>; -} - -impl Assignment for Option { - fn get(&self) -> Result<&T, SynthesisError> { - match *self { - Some(ref v) => Ok(v), - None => Err(SynthesisError::AssignmentMissing) - } - } -} diff --git a/sapling-crypto/src/circuit/multieq.rs b/sapling-crypto/src/circuit/multieq.rs deleted file mode 100644 index 0f9c755..0000000 --- a/sapling-crypto/src/circuit/multieq.rs +++ /dev/null @@ -1,137 +0,0 @@ -use pairing::{ - Engine, - Field, - PrimeField -}; - -use bellman::{ - SynthesisError, - ConstraintSystem, - LinearCombination, - Variable -}; - -pub struct MultiEq>{ - cs: CS, - ops: usize, - bits_used: usize, - lhs: LinearCombination, - rhs: LinearCombination, -} - -impl> MultiEq { - pub fn new(cs: CS) -> Self { - MultiEq { - cs: cs, - ops: 0, - bits_used: 0, - lhs: LinearCombination::zero(), - rhs: LinearCombination::zero() - } - } - - fn accumulate(&mut self) - { - let ops = self.ops; - let lhs = self.lhs.clone(); - let rhs = self.rhs.clone(); - self.cs.enforce( - || format!("multieq {}", ops), - |_| lhs, - |lc| lc + CS::one(), - |_| rhs - ); - self.lhs = LinearCombination::zero(); - self.rhs = LinearCombination::zero(); - self.bits_used = 0; - self.ops += 1; - } - - pub fn enforce_equal( - &mut self, - num_bits: usize, - lhs: &LinearCombination, - rhs: &LinearCombination - ) - { - // Check if we will exceed the capacity - if (E::Fr::CAPACITY as usize) <= (self.bits_used + num_bits) { - self.accumulate(); - } - - assert!((E::Fr::CAPACITY as usize) > (self.bits_used + num_bits)); - - let coeff = E::Fr::from_str("2").unwrap().pow(&[self.bits_used as u64]); - self.lhs = self.lhs.clone() + (coeff, lhs); - self.rhs = self.rhs.clone() + (coeff, rhs); - self.bits_used += num_bits; - } -} - -impl> Drop for MultiEq { - fn drop(&mut self) { - if self.bits_used > 0 { - self.accumulate(); - } - } -} - -impl> ConstraintSystem for MultiEq -{ - type Root = Self; - - fn one() -> Variable { - CS::one() - } - - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into - { - self.cs.alloc(annotation, f) - } - - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into - { - self.cs.alloc_input(annotation, f) - } - - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination - { - self.cs.enforce(annotation, a, b, c) - } - - fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR - { - self.cs.get_root().push_namespace(name_fn) - } - - fn pop_namespace(&mut self) - { - self.cs.get_root().pop_namespace() - } - - fn get_root(&mut self) -> &mut Self::Root - { - self - } -} diff --git a/sapling-crypto/src/circuit/multipack.rs b/sapling-crypto/src/circuit/multipack.rs deleted file mode 100644 index 54d4138..0000000 --- a/sapling-crypto/src/circuit/multipack.rs +++ /dev/null @@ -1,113 +0,0 @@ -use pairing::{Engine, Field, PrimeField}; -use bellman::{ConstraintSystem, SynthesisError}; -use super::boolean::{Boolean}; -use super::num::Num; -use super::Assignment; - -/// Takes a sequence of booleans and exposes them as compact -/// public inputs -pub fn pack_into_inputs( - mut cs: CS, - bits: &[Boolean] -) -> Result<(), SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() - { - let mut num = Num::::zero(); - let mut coeff = E::Fr::one(); - for bit in bits { - num = num.add_bool_with_coeff(CS::one(), bit, coeff); - - coeff.double(); - } - - let input = cs.alloc_input(|| format!("input {}", i), || { - Ok(*num.get_value().get()?) - })?; - - // num * 1 = input - cs.enforce( - || format!("packing constraint {}", i), - |_| num.lc(E::Fr::one()), - |lc| lc + CS::one(), - |lc| lc + input - ); - } - - Ok(()) -} - -pub fn bytes_to_bits(bytes: &[u8]) -> Vec -{ - bytes.iter() - .flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1)) - .collect() -} - -pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec -{ - bytes.iter() - .flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1)) - .collect() -} - -pub fn compute_multipacking( - bits: &[bool] -) -> Vec -{ - let mut result = vec![]; - - for bits in bits.chunks(E::Fr::CAPACITY as usize) - { - let mut cur = E::Fr::zero(); - let mut coeff = E::Fr::one(); - - for bit in bits { - if *bit { - cur.add_assign(&coeff); - } - - coeff.double(); - } - - result.push(cur); - } - - result -} - -#[test] -fn test_multipacking() { - use rand::{SeedableRng, Rng, XorShiftRng}; - use bellman::{ConstraintSystem}; - use pairing::bls12_381::{Bls12}; - use ::circuit::test::*; - use super::boolean::{AllocatedBit, Boolean}; - - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for num_bits in 0..1500 { - let mut cs = TestConstraintSystem::::new(); - - let bits: Vec = (0..num_bits).map(|_| rng.gen()).collect(); - - let circuit_bits = bits.iter().enumerate() - .map(|(i, &b)| { - Boolean::from( - AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - Some(b) - ).unwrap() - ) - }) - .collect::>(); - - let expected_inputs = compute_multipacking::(&bits); - - pack_into_inputs(cs.namespace(|| "pack"), &circuit_bits).unwrap(); - - assert!(cs.is_satisfied()); - assert!(cs.verify(&expected_inputs)); - } -} diff --git a/sapling-crypto/src/circuit/num.rs b/sapling-crypto/src/circuit/num.rs deleted file mode 100644 index 53a2f6c..0000000 --- a/sapling-crypto/src/circuit/num.rs +++ /dev/null @@ -1,622 +0,0 @@ -use pairing::{ - Engine, - Field, - PrimeField, - PrimeFieldRepr, - BitIterator -}; - -use bellman::{ - SynthesisError, - ConstraintSystem, - LinearCombination, - Variable -}; - -use super::{ - Assignment -}; - -use super::boolean::{ - self, - Boolean, - AllocatedBit -}; - -pub struct AllocatedNum { - value: Option, - variable: Variable -} - -impl Clone for AllocatedNum { - fn clone(&self) -> Self { - AllocatedNum { - value: self.value, - variable: self.variable - } - } -} - -impl AllocatedNum { - pub fn alloc( - mut cs: CS, - value: F, - ) -> Result - where CS: ConstraintSystem, - F: FnOnce() -> Result - { - let mut new_value = None; - let var = cs.alloc(|| "num", || { - let tmp = value()?; - - new_value = Some(tmp); - - Ok(tmp) - })?; - - Ok(AllocatedNum { - value: new_value, - variable: var - }) - } - - pub fn inputize( - &self, - mut cs: CS - ) -> Result<(), SynthesisError> - where CS: ConstraintSystem - { - let input = cs.alloc_input( - || "input variable", - || { - Ok(*self.value.get()?) - } - )?; - - cs.enforce( - || "enforce input is correct", - |lc| lc + input, - |lc| lc + CS::one(), - |lc| lc + self.variable - ); - - Ok(()) - } - - /// Deconstructs this allocated number into its - /// boolean representation in little-endian bit - /// order, requiring that the representation - /// strictly exists "in the field" (i.e., a - /// congruency is not allowed.) - pub fn into_bits_le_strict( - &self, - mut cs: CS - ) -> Result, SynthesisError> - where CS: ConstraintSystem - { - pub fn kary_and( - mut cs: CS, - v: &[AllocatedBit] - ) -> Result - where E: Engine, - CS: ConstraintSystem - { - assert!(v.len() > 0); - - // Let's keep this simple for now and just AND them all - // manually - let mut cur = None; - - for (i, v) in v.iter().enumerate() { - if cur.is_none() { - cur = Some(v.clone()); - } else { - cur = Some(AllocatedBit::and( - cs.namespace(|| format!("and {}", i)), - cur.as_ref().unwrap(), - v - )?); - } - } - - Ok(cur.expect("v.len() > 0")) - } - - // We want to ensure that the bit representation of a is - // less than or equal to r - 1. - let mut a = self.value.map(|e| BitIterator::new(e.into_repr())); - let mut b = E::Fr::char(); - b.sub_noborrow(&1.into()); - - let mut result = vec![]; - - // Runs of ones in r - let mut last_run = None; - let mut current_run = vec![]; - - let mut found_one = false; - let mut i = 0; - for b in BitIterator::new(b) { - let a_bit = a.as_mut().map(|e| e.next().unwrap()); - - // Skip over unset bits at the beginning - found_one |= b; - if !found_one { - // a_bit should also be false - a_bit.map(|e| assert!(!e)); - continue; - } - - if b { - // This is part of a run of ones. Let's just - // allocate the boolean with the expected value. - let a_bit = AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - a_bit - )?; - // ... and add it to the current run of ones. - current_run.push(a_bit.clone()); - result.push(a_bit); - } else { - if current_run.len() > 0 { - // This is the start of a run of zeros, but we need - // to k-ary AND against `last_run` first. - - if last_run.is_some() { - current_run.push(last_run.clone().unwrap()); - } - last_run = Some(kary_and( - cs.namespace(|| format!("run ending at {}", i)), - ¤t_run - )?); - current_run.truncate(0); - } - - // If `last_run` is true, `a` must be false, or it would - // not be in the field. - // - // If `last_run` is false, `a` can be true or false. - - let a_bit = AllocatedBit::alloc_conditionally( - cs.namespace(|| format!("bit {}", i)), - a_bit, - &last_run.as_ref().expect("char always starts with a one") - )?; - result.push(a_bit); - } - - i += 1; - } - - // char is prime, so we'll always end on - // a run of zeros. - assert_eq!(current_run.len(), 0); - - // Now, we have `result` in big-endian order. - // However, now we have to unpack self! - - let mut lc = LinearCombination::zero(); - let mut coeff = E::Fr::one(); - - for bit in result.iter().rev() { - lc = lc + (coeff, bit.get_variable()); - - coeff.double(); - } - - lc = lc - self.variable; - - cs.enforce( - || "unpacking constraint", - |lc| lc, - |lc| lc, - |_| lc - ); - - // Convert into booleans, and reverse for little-endian bit order - Ok(result.into_iter().map(|b| Boolean::from(b)).rev().collect()) - } - - /// Convert the allocated number into its little-endian representation. - /// Note that this does not strongly enforce that the commitment is - /// "in the field." - pub fn into_bits_le( - &self, - mut cs: CS - ) -> Result, SynthesisError> - where CS: ConstraintSystem - { - let bits = boolean::field_into_allocated_bits_le( - &mut cs, - self.value - )?; - - let mut lc = LinearCombination::zero(); - let mut coeff = E::Fr::one(); - - for bit in bits.iter() { - lc = lc + (coeff, bit.get_variable()); - - coeff.double(); - } - - lc = lc - self.variable; - - cs.enforce( - || "unpacking constraint", - |lc| lc, - |lc| lc, - |_| lc - ); - - Ok(bits.into_iter().map(|b| Boolean::from(b)).collect()) - } - - pub fn mul( - &self, - mut cs: CS, - other: &Self - ) -> Result - where CS: ConstraintSystem - { - let mut value = None; - - let var = cs.alloc(|| "product num", || { - let mut tmp = *self.value.get()?; - tmp.mul_assign(other.value.get()?); - - value = Some(tmp); - - Ok(tmp) - })?; - - // Constrain: a * b = ab - cs.enforce( - || "multiplication constraint", - |lc| lc + self.variable, - |lc| lc + other.variable, - |lc| lc + var - ); - - Ok(AllocatedNum { - value: value, - variable: var - }) - } - - pub fn square( - &self, - mut cs: CS - ) -> Result - where CS: ConstraintSystem - { - let mut value = None; - - let var = cs.alloc(|| "squared num", || { - let mut tmp = *self.value.get()?; - tmp.square(); - - value = Some(tmp); - - Ok(tmp) - })?; - - // Constrain: a * a = aa - cs.enforce( - || "squaring constraint", - |lc| lc + self.variable, - |lc| lc + self.variable, - |lc| lc + var - ); - - Ok(AllocatedNum { - value: value, - variable: var - }) - } - - pub fn assert_nonzero( - &self, - mut cs: CS - ) -> Result<(), SynthesisError> - where CS: ConstraintSystem - { - let inv = cs.alloc(|| "ephemeral inverse", || { - let tmp = *self.value.get()?; - - if tmp.is_zero() { - Err(SynthesisError::DivisionByZero) - } else { - Ok(tmp.inverse().unwrap()) - } - })?; - - // Constrain a * inv = 1, which is only valid - // iff a has a multiplicative inverse, untrue - // for zero. - cs.enforce( - || "nonzero assertion constraint", - |lc| lc + self.variable, - |lc| lc + inv, - |lc| lc + CS::one() - ); - - Ok(()) - } - - /// Takes two allocated numbers (a, b) and returns - /// (b, a) if the condition is true, and (a, b) - /// otherwise. - pub fn conditionally_reverse( - mut cs: CS, - a: &Self, - b: &Self, - condition: &Boolean - ) -> Result<(Self, Self), SynthesisError> - where CS: ConstraintSystem - { - let c = Self::alloc( - cs.namespace(|| "conditional reversal result 1"), - || { - if *condition.get_value().get()? { - Ok(*b.value.get()?) - } else { - Ok(*a.value.get()?) - } - } - )?; - - cs.enforce( - || "first conditional reversal", - |lc| lc + a.variable - b.variable, - |_| condition.lc(CS::one(), E::Fr::one()), - |lc| lc + a.variable - c.variable - ); - - let d = Self::alloc( - cs.namespace(|| "conditional reversal result 2"), - || { - if *condition.get_value().get()? { - Ok(*a.value.get()?) - } else { - Ok(*b.value.get()?) - } - } - )?; - - cs.enforce( - || "second conditional reversal", - |lc| lc + b.variable - a.variable, - |_| condition.lc(CS::one(), E::Fr::one()), - |lc| lc + b.variable - d.variable - ); - - Ok((c, d)) - } - - pub fn get_value(&self) -> Option { - self.value - } - - pub fn get_variable(&self) -> Variable { - self.variable - } -} - -pub struct Num { - value: Option, - lc: LinearCombination -} - -impl From> for Num { - fn from(num: AllocatedNum) -> Num { - Num { - value: num.value, - lc: LinearCombination::::zero() + num.variable - } - } -} - -impl Num { - pub fn zero() -> Self { - Num { - value: Some(E::Fr::zero()), - lc: LinearCombination::zero() - } - } - - pub fn get_value(&self) -> Option { - self.value - } - - pub fn lc(&self, coeff: E::Fr) -> LinearCombination { - LinearCombination::zero() + (coeff, &self.lc) - } - - pub fn add_bool_with_coeff( - self, - one: Variable, - bit: &Boolean, - coeff: E::Fr - ) -> Self - { - let newval = match (self.value, bit.get_value()) { - (Some(mut curval), Some(bval)) => { - if bval { - curval.add_assign(&coeff); - } - - Some(curval) - }, - _ => None - }; - - Num { - value: newval, - lc: self.lc + &bit.lc(one, coeff) - } - } -} - -#[cfg(test)] -mod test { - use rand::{SeedableRng, Rand, Rng, XorShiftRng}; - use bellman::{ConstraintSystem}; - use pairing::bls12_381::{Bls12, Fr}; - use pairing::{Field, PrimeField, BitIterator}; - use ::circuit::test::*; - use super::{AllocatedNum, Boolean}; - - #[test] - fn test_allocated_num() { - let mut cs = TestConstraintSystem::::new(); - - AllocatedNum::alloc(&mut cs, || Ok(Fr::one())).unwrap(); - - assert!(cs.get("num") == Fr::one()); - } - - #[test] - fn test_num_squaring() { - let mut cs = TestConstraintSystem::::new(); - - let n = AllocatedNum::alloc(&mut cs, || Ok(Fr::from_str("3").unwrap())).unwrap(); - let n2 = n.square(&mut cs).unwrap(); - - assert!(cs.is_satisfied()); - assert!(cs.get("squared num") == Fr::from_str("9").unwrap()); - assert!(n2.value.unwrap() == Fr::from_str("9").unwrap()); - cs.set("squared num", Fr::from_str("10").unwrap()); - assert!(!cs.is_satisfied()); - } - - #[test] - fn test_num_multiplication() { - let mut cs = TestConstraintSystem::::new(); - - let n = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap(); - let n2 = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap(); - let n3 = n.mul(&mut cs, &n2).unwrap(); - - assert!(cs.is_satisfied()); - assert!(cs.get("product num") == Fr::from_str("120").unwrap()); - assert!(n3.value.unwrap() == Fr::from_str("120").unwrap()); - cs.set("product num", Fr::from_str("121").unwrap()); - assert!(!cs.is_satisfied()); - } - - #[test] - fn test_num_conditional_reversal() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - { - let mut cs = TestConstraintSystem::::new(); - - let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(rng.gen())).unwrap(); - let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(rng.gen())).unwrap(); - let condition = Boolean::constant(false); - let (c, d) = AllocatedNum::conditionally_reverse(&mut cs, &a, &b, &condition).unwrap(); - - assert!(cs.is_satisfied()); - - assert_eq!(a.value.unwrap(), c.value.unwrap()); - assert_eq!(b.value.unwrap(), d.value.unwrap()); - } - - { - let mut cs = TestConstraintSystem::::new(); - - let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(rng.gen())).unwrap(); - let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(rng.gen())).unwrap(); - let condition = Boolean::constant(true); - let (c, d) = AllocatedNum::conditionally_reverse(&mut cs, &a, &b, &condition).unwrap(); - - assert!(cs.is_satisfied()); - - assert_eq!(a.value.unwrap(), d.value.unwrap()); - assert_eq!(b.value.unwrap(), c.value.unwrap()); - } - } - - #[test] - fn test_num_nonzero() { - { - let mut cs = TestConstraintSystem::::new(); - - let n = AllocatedNum::alloc(&mut cs, || Ok(Fr::from_str("3").unwrap())).unwrap(); - n.assert_nonzero(&mut cs).unwrap(); - - assert!(cs.is_satisfied()); - cs.set("ephemeral inverse", Fr::from_str("3").unwrap()); - assert!(cs.which_is_unsatisfied() == Some("nonzero assertion constraint")); - } - { - let mut cs = TestConstraintSystem::::new(); - - let n = AllocatedNum::alloc(&mut cs, || Ok(Fr::zero())).unwrap(); - assert!(n.assert_nonzero(&mut cs).is_err()); - } - } - - #[test] - fn test_into_bits_strict() { - let mut negone = Fr::one(); - negone.negate(); - - let mut cs = TestConstraintSystem::::new(); - - let n = AllocatedNum::alloc(&mut cs, || Ok(negone)).unwrap(); - n.into_bits_le_strict(&mut cs).unwrap(); - - assert!(cs.is_satisfied()); - - // make the bit representation the characteristic - cs.set("bit 254/boolean", Fr::one()); - - // this makes the conditional boolean constraint fail - assert_eq!(cs.which_is_unsatisfied().unwrap(), "bit 254/boolean constraint"); - } - - #[test] - fn test_into_bits() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for i in 0..200 { - let r = Fr::rand(&mut rng); - let mut cs = TestConstraintSystem::::new(); - - let n = AllocatedNum::alloc(&mut cs, || Ok(r)).unwrap(); - - let bits = if i % 2 == 0 { - n.into_bits_le(&mut cs).unwrap() - } else { - n.into_bits_le_strict(&mut cs).unwrap() - }; - - assert!(cs.is_satisfied()); - - for (b, a) in BitIterator::new(r.into_repr()).skip(1).zip(bits.iter().rev()) { - if let &Boolean::Is(ref a) = a { - assert_eq!(b, a.get_value().unwrap()); - } else { - unreachable!() - } - } - - cs.set("num", Fr::rand(&mut rng)); - assert!(!cs.is_satisfied()); - cs.set("num", r); - assert!(cs.is_satisfied()); - - for i in 0..Fr::NUM_BITS { - let name = format!("bit {}/boolean", i); - let cur = cs.get(&name); - let mut tmp = Fr::one(); - tmp.sub_assign(&cur); - cs.set(&name, tmp); - assert!(!cs.is_satisfied()); - cs.set(&name, cur); - assert!(cs.is_satisfied()); - } - } - } -} diff --git a/sapling-crypto/src/circuit/pedersen_hash.rs b/sapling-crypto/src/circuit/pedersen_hash.rs deleted file mode 100644 index eb1745f..0000000 --- a/sapling-crypto/src/circuit/pedersen_hash.rs +++ /dev/null @@ -1,194 +0,0 @@ -use super::*; -use super::ecc::{ - MontgomeryPoint, - EdwardsPoint -}; -use super::boolean::Boolean; -use ::jubjub::*; -use bellman::{ - ConstraintSystem -}; -use super::lookup::*; -pub use pedersen_hash::Personalization; - -impl Personalization { - fn get_constant_bools(&self) -> Vec { - self.get_bits() - .into_iter() - .map(|e| Boolean::constant(e)) - .collect() - } -} - -pub fn pedersen_hash( - mut cs: CS, - personalization: Personalization, - bits: &[Boolean], - params: &E::Params -) -> Result, SynthesisError> - where CS: ConstraintSystem -{ - let personalization = personalization.get_constant_bools(); - assert_eq!(personalization.len(), 6); - - let mut edwards_result = None; - let mut bits = personalization.iter().chain(bits.iter()); - let mut segment_generators = params.pedersen_circuit_generators().iter(); - let boolean_false = Boolean::constant(false); - - let mut segment_i = 0; - loop { - let mut segment_result = None; - let mut segment_windows = &segment_generators.next() - .expect("enough segments")[..]; - - let mut window_i = 0; - while let Some(a) = bits.next() { - let b = bits.next().unwrap_or(&boolean_false); - let c = bits.next().unwrap_or(&boolean_false); - - let tmp = lookup3_xy_with_conditional_negation( - cs.namespace(|| format!("segment {}, window {}", segment_i, window_i)), - &[a.clone(), b.clone(), c.clone()], - &segment_windows[0] - )?; - - let tmp = MontgomeryPoint::interpret_unchecked(tmp.0, tmp.1); - - match segment_result { - None => { - segment_result = Some(tmp); - }, - Some(ref mut segment_result) => { - *segment_result = tmp.add( - cs.namespace(|| format!("addition of segment {}, window {}", segment_i, window_i)), - segment_result, - params - )?; - } - } - - segment_windows = &segment_windows[1..]; - - if segment_windows.len() == 0 { - break; - } - - window_i += 1; - } - - match segment_result { - Some(segment_result) => { - // Convert this segment into twisted Edwards form. - let segment_result = segment_result.into_edwards( - cs.namespace(|| format!("conversion of segment {} into edwards", segment_i)), - params - )?; - - match edwards_result { - Some(ref mut edwards_result) => { - *edwards_result = segment_result.add( - cs.namespace(|| format!("addition of segment {} to accumulator", segment_i)), - edwards_result, - params - )?; - }, - None => { - edwards_result = Some(segment_result); - } - } - }, - None => { - // We didn't process any new bits. - break; - } - } - - segment_i += 1; - } - - Ok(edwards_result.unwrap()) -} - -#[cfg(test)] -mod test { - use rand::{SeedableRng, Rng, XorShiftRng}; - use super::*; - use ::circuit::test::*; - use ::circuit::boolean::{Boolean, AllocatedBit}; - use pairing::bls12_381::{Bls12, Fr}; - use pairing::PrimeField; - - #[test] - fn test_pedersen_hash_constraints() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - let params = &JubjubBls12::new(); - let mut cs = TestConstraintSystem::::new(); - - let input: Vec = (0..(Fr::NUM_BITS * 2)).map(|_| rng.gen()).collect(); - - let input_bools: Vec = input.iter().enumerate().map(|(i, b)| { - Boolean::from( - AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap() - ) - }).collect(); - - pedersen_hash( - cs.namespace(|| "pedersen hash"), - Personalization::NoteCommitment, - &input_bools, - params - ).unwrap(); - - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 1377); - } - - #[test] - fn test_pedersen_hash() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - let params = &JubjubBls12::new(); - - for length in 0..751 { - for _ in 0..5 { - let mut input: Vec = (0..length).map(|_| rng.gen()).collect(); - - let mut cs = TestConstraintSystem::::new(); - - let input_bools: Vec = input.iter().enumerate().map(|(i, b)| { - Boolean::from( - AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap() - ) - }).collect(); - - let res = pedersen_hash( - cs.namespace(|| "pedersen hash"), - Personalization::MerkleTree(1), - &input_bools, - params - ).unwrap(); - - assert!(cs.is_satisfied()); - - let expected = ::pedersen_hash::pedersen_hash::( - Personalization::MerkleTree(1), - input.clone().into_iter(), - params - ).into_xy(); - - assert_eq!(res.get_x().get_value().unwrap(), expected.0); - assert_eq!(res.get_y().get_value().unwrap(), expected.1); - - // Test against the output of a different personalization - let unexpected = ::pedersen_hash::pedersen_hash::( - Personalization::MerkleTree(0), - input.into_iter(), - params - ).into_xy(); - - assert!(res.get_x().get_value().unwrap() != unexpected.0); - assert!(res.get_y().get_value().unwrap() != unexpected.1); - } - } - } -} diff --git a/sapling-crypto/src/circuit/sapling/mod.rs b/sapling-crypto/src/circuit/sapling/mod.rs deleted file mode 100644 index 650e162..0000000 --- a/sapling-crypto/src/circuit/sapling/mod.rs +++ /dev/null @@ -1,817 +0,0 @@ -use pairing::{ - PrimeField, - PrimeFieldRepr, - Field, -}; - -use bellman::{ - SynthesisError, - ConstraintSystem, - Circuit -}; - -use jubjub::{ - JubjubEngine, - FixedGenerators -}; - -use constants; - -use primitives::{ - ValueCommitment, - ProofGenerationKey, - PaymentAddress -}; - -use super::Assignment; -use super::boolean; -use super::ecc; -use super::pedersen_hash; -use super::blake2s; -use super::num; -use super::multipack; - -pub const TREE_DEPTH: usize = 32; - -/// This is an instance of the `Spend` circuit. -pub struct Spend<'a, E: JubjubEngine> { - pub params: &'a E::Params, - - /// Pedersen commitment to the value being spent - pub value_commitment: Option>, - - /// Key required to construct proofs for spending notes - /// for a particular spending key - pub proof_generation_key: Option>, - - /// The payment address associated with the note - pub payment_address: Option>, - - /// The randomness of the note commitment - pub commitment_randomness: Option, - - /// Re-randomization of the public key - pub ar: Option, - - /// The authentication path of the commitment in the tree - pub auth_path: Vec>, - - /// The anchor; the root of the tree. If the note being - /// spent is zero-value, this can be anything. - pub anchor: Option -} - -/// This is an output circuit instance. -pub struct Output<'a, E: JubjubEngine> { - pub params: &'a E::Params, - - /// Pedersen commitment to the value being spent - pub value_commitment: Option>, - - /// The payment address of the recipient - pub payment_address: Option>, - - /// The randomness used to hide the note commitment data - pub commitment_randomness: Option, - - /// The ephemeral secret key for DH with recipient - pub esk: Option -} - -/// Exposes a Pedersen commitment to the value as an -/// input to the circuit -fn expose_value_commitment( - mut cs: CS, - value_commitment: Option>, - params: &E::Params -) -> Result, SynthesisError> - where E: JubjubEngine, - CS: ConstraintSystem -{ - // Booleanize the value into little-endian bit order - let value_bits = boolean::u64_into_boolean_vec_le( - cs.namespace(|| "value"), - value_commitment.as_ref().map(|c| c.value) - )?; - - // Compute the note value in the exponent - let value = ecc::fixed_base_multiplication( - cs.namespace(|| "compute the value in the exponent"), - FixedGenerators::ValueCommitmentValue, - &value_bits, - params - )?; - - // Booleanize the randomness. This does not ensure - // the bit representation is "in the field" because - // it doesn't matter for security. - let rcv = boolean::field_into_boolean_vec_le( - cs.namespace(|| "rcv"), - value_commitment.as_ref().map(|c| c.randomness) - )?; - - // Compute the randomness in the exponent - let rcv = ecc::fixed_base_multiplication( - cs.namespace(|| "computation of rcv"), - FixedGenerators::ValueCommitmentRandomness, - &rcv, - params - )?; - - // Compute the Pedersen commitment to the value - let cv = value.add( - cs.namespace(|| "computation of cv"), - &rcv, - params - )?; - - // Expose the commitment as an input to the circuit - cv.inputize(cs.namespace(|| "commitment point"))?; - - Ok(value_bits) -} - -impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { - fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> - { - // Prover witnesses ak (ensures that it's on the curve) - let ak = ecc::EdwardsPoint::witness( - cs.namespace(|| "ak"), - self.proof_generation_key.as_ref().map(|k| k.ak.clone()), - self.params - )?; - - // There are no sensible attacks on small order points - // of ak (that we're aware of!) but it's a cheap check, - // so we do it. - ak.assert_not_small_order( - cs.namespace(|| "ak not small order"), - self.params - )?; - - // Rerandomize ak and expose it as an input to the circuit - { - let ar = boolean::field_into_boolean_vec_le( - cs.namespace(|| "ar"), - self.ar - )?; - - // Compute the randomness in the exponent - let ar = ecc::fixed_base_multiplication( - cs.namespace(|| "computation of randomization for the signing key"), - FixedGenerators::SpendingKeyGenerator, - &ar, - self.params - )?; - - let rk = ak.add( - cs.namespace(|| "computation of rk"), - &ar, - self.params - )?; - - rk.inputize(cs.namespace(|| "rk"))?; - } - - // Compute nk = [nsk] ProofGenerationKey - let nk; - { - // Witness nsk as bits - let nsk = boolean::field_into_boolean_vec_le( - cs.namespace(|| "nsk"), - self.proof_generation_key.as_ref().map(|k| k.nsk.clone()) - )?; - - // NB: We don't ensure that the bit representation of nsk - // is "in the field" (Fs) because it's not used except to - // demonstrate the prover knows it. If they know a - // congruency then that's equivalent. - - // Compute nk = [nsk] ProvingPublicKey - nk = ecc::fixed_base_multiplication( - cs.namespace(|| "computation of nk"), - FixedGenerators::ProofGenerationKey, - &nsk, - self.params - )?; - } - - // This is the "viewing key" preimage for CRH^ivk - let mut ivk_preimage = vec![]; - - // Place ak in the preimage for CRH^ivk - ivk_preimage.extend( - ak.repr(cs.namespace(|| "representation of ak"))? - ); - - // This is the nullifier preimage for PRF^nf - let mut nf_preimage = vec![]; - - // Extend ivk and nf preimages with the representation of - // nk. - { - let repr_nk = nk.repr( - cs.namespace(|| "representation of nk") - )?; - - ivk_preimage.extend(repr_nk.iter().cloned()); - nf_preimage.extend(repr_nk); - } - - assert_eq!(ivk_preimage.len(), 512); - assert_eq!(nf_preimage.len(), 256); - - // Compute the incoming viewing key ivk - let mut ivk = blake2s::blake2s( - cs.namespace(|| "computation of ivk"), - &ivk_preimage, - constants::CRH_IVK_PERSONALIZATION - )?; - - // drop_5 to ensure it's in the field - ivk.truncate(E::Fs::CAPACITY as usize); - - // Witness g_d, checking that it's on the curve. - let g_d = { - // This binding is to avoid a weird edge case in Rust's - // ownership/borrowing rules. self is partially moved - // above, but the closure for and_then will have to - // move self (or a reference to self) to reference - // self.params, so we have to copy self.params here. - let params = self.params; - - ecc::EdwardsPoint::witness( - cs.namespace(|| "witness g_d"), - self.payment_address.as_ref().and_then(|a| a.g_d(params)), - self.params - )? - }; - - // Check that g_d is not small order. Technically, this check - // is already done in the Output circuit, and this proof ensures - // g_d is bound to a product of that check, but for defense in - // depth let's check it anyway. It's cheap. - g_d.assert_not_small_order( - cs.namespace(|| "g_d not small order"), - self.params - )?; - - // Compute pk_d = g_d^ivk - let pk_d = g_d.mul( - cs.namespace(|| "compute pk_d"), - &ivk, - self.params - )?; - - // Compute note contents: - // value (in big endian) followed by g_d and pk_d - let mut note_contents = vec![]; - - // Handle the value; we'll need it later for the - // dummy input check. - let mut value_num = num::Num::zero(); - { - // Get the value in little-endian bit order - let value_bits = expose_value_commitment( - cs.namespace(|| "value commitment"), - self.value_commitment, - self.params - )?; - - // Compute the note's value as a linear combination - // of the bits. - let mut coeff = E::Fr::one(); - for bit in &value_bits { - value_num = value_num.add_bool_with_coeff( - CS::one(), - bit, - coeff - ); - coeff.double(); - } - - // Place the value in the note - note_contents.extend(value_bits); - } - - // Place g_d in the note - note_contents.extend( - g_d.repr(cs.namespace(|| "representation of g_d"))? - ); - - // Place pk_d in the note - note_contents.extend( - pk_d.repr(cs.namespace(|| "representation of pk_d"))? - ); - - assert_eq!( - note_contents.len(), - 64 + // value - 256 + // g_d - 256 // p_d - ); - - // Compute the hash of the note contents - let mut cm = pedersen_hash::pedersen_hash( - cs.namespace(|| "note content hash"), - pedersen_hash::Personalization::NoteCommitment, - ¬e_contents, - self.params - )?; - - { - // Booleanize the randomness for the note commitment - let rcm = boolean::field_into_boolean_vec_le( - cs.namespace(|| "rcm"), - self.commitment_randomness - )?; - - // Compute the note commitment randomness in the exponent - let rcm = ecc::fixed_base_multiplication( - cs.namespace(|| "computation of commitment randomness"), - FixedGenerators::NoteCommitmentRandomness, - &rcm, - self.params - )?; - - // Randomize the note commitment. Pedersen hashes are not - // themselves hiding commitments. - cm = cm.add( - cs.namespace(|| "randomization of note commitment"), - &rcm, - self.params - )?; - } - - // This will store (least significant bit first) - // the position of the note in the tree, for use - // in nullifier computation. - let mut position_bits = vec![]; - - // This is an injective encoding, as cur is a - // point in the prime order subgroup. - let mut cur = cm.get_x().clone(); - - // Ascend the merkle tree authentication path - for (i, e) in self.auth_path.into_iter().enumerate() { - let cs = &mut cs.namespace(|| format!("merkle tree hash {}", i)); - - // Determines if the current subtree is the "right" leaf at this - // depth of the tree. - let cur_is_right = boolean::Boolean::from(boolean::AllocatedBit::alloc( - cs.namespace(|| "position bit"), - e.map(|e| e.1) - )?); - - // Push this boolean for nullifier computation later - position_bits.push(cur_is_right.clone()); - - // Witness the authentication path element adjacent - // at this depth. - let path_element = num::AllocatedNum::alloc( - cs.namespace(|| "path element"), - || { - Ok(e.get()?.0) - } - )?; - - // Swap the two if the current subtree is on the right - let (xl, xr) = num::AllocatedNum::conditionally_reverse( - cs.namespace(|| "conditional reversal of preimage"), - &cur, - &path_element, - &cur_is_right - )?; - - // We don't need to be strict, because the function is - // collision-resistant. If the prover witnesses a congruency, - // they will be unable to find an authentication path in the - // tree with high probability. - let mut preimage = vec![]; - preimage.extend(xl.into_bits_le(cs.namespace(|| "xl into bits"))?); - preimage.extend(xr.into_bits_le(cs.namespace(|| "xr into bits"))?); - - // Compute the new subtree value - cur = pedersen_hash::pedersen_hash( - cs.namespace(|| "computation of pedersen hash"), - pedersen_hash::Personalization::MerkleTree(i), - &preimage, - self.params - )?.get_x().clone(); // Injective encoding - } - - { - let real_anchor_value = self.anchor; - - // Allocate the "real" anchor that will be exposed. - let rt = num::AllocatedNum::alloc( - cs.namespace(|| "conditional anchor"), - || { - Ok(*real_anchor_value.get()?) - } - )?; - - // (cur - rt) * value = 0 - // if value is zero, cur and rt can be different - // if value is nonzero, they must be equal - cs.enforce( - || "conditionally enforce correct root", - |lc| lc + cur.get_variable() - rt.get_variable(), - |lc| lc + &value_num.lc(E::Fr::one()), - |lc| lc - ); - - // Expose the anchor - rt.inputize(cs.namespace(|| "anchor"))?; - } - - // Compute the cm + g^position for preventing - // faerie gold attacks - let mut rho = cm; - { - // Compute the position in the exponent - let position = ecc::fixed_base_multiplication( - cs.namespace(|| "g^position"), - FixedGenerators::NullifierPosition, - &position_bits, - self.params - )?; - - // Add the position to the commitment - rho = rho.add( - cs.namespace(|| "faerie gold prevention"), - &position, - self.params - )?; - } - - // Let's compute nf = BLAKE2s(nk || rho) - nf_preimage.extend( - rho.repr(cs.namespace(|| "representation of rho"))? - ); - - assert_eq!(nf_preimage.len(), 512); - - // Compute nf - let nf = blake2s::blake2s( - cs.namespace(|| "nf computation"), - &nf_preimage, - constants::PRF_NF_PERSONALIZATION - )?; - - multipack::pack_into_inputs(cs.namespace(|| "pack nullifier"), &nf) - } -} - -impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { - fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> - { - // Let's start to construct our note, which contains - // value (big endian) - let mut note_contents = vec![]; - - // Expose the value commitment and place the value - // in the note. - note_contents.extend(expose_value_commitment( - cs.namespace(|| "value commitment"), - self.value_commitment, - self.params - )?); - - // Let's deal with g_d - { - let params = self.params; - - // Prover witnesses g_d, ensuring it's on the - // curve. - let g_d = ecc::EdwardsPoint::witness( - cs.namespace(|| "witness g_d"), - self.payment_address.as_ref().and_then(|a| a.g_d(params)), - self.params - )?; - - // g_d is ensured to be large order. The relationship - // between g_d and pk_d ultimately binds ivk to the - // note. If this were a small order point, it would - // not do this correctly, and the prover could - // double-spend by finding random ivk's that satisfy - // the relationship. - // - // Further, if it were small order, epk would be - // small order too! - g_d.assert_not_small_order( - cs.namespace(|| "g_d not small order"), - self.params - )?; - - // Extend our note contents with the representation of - // g_d. - note_contents.extend( - g_d.repr(cs.namespace(|| "representation of g_d"))? - ); - - // Booleanize our ephemeral secret key - let esk = boolean::field_into_boolean_vec_le( - cs.namespace(|| "esk"), - self.esk - )?; - - // Create the ephemeral public key from g_d. - let epk = g_d.mul( - cs.namespace(|| "epk computation"), - &esk, - self.params - )?; - - // Expose epk publicly. - epk.inputize(cs.namespace(|| "epk"))?; - } - - // Now let's deal with pk_d. We don't do any checks and - // essentially allow the prover to witness any 256 bits - // they would like. - { - // Just grab pk_d from the witness - let pk_d = self.payment_address.as_ref().map(|e| e.pk_d.into_xy()); - - // Witness the y-coordinate, encoded as little - // endian bits (to match the representation) - let y_contents = boolean::field_into_boolean_vec_le( - cs.namespace(|| "pk_d bits of y"), - pk_d.map(|e| e.1) - )?; - - // Witness the sign bit - let sign_bit = boolean::Boolean::from(boolean::AllocatedBit::alloc( - cs.namespace(|| "pk_d bit of x"), - pk_d.map(|e| e.0.into_repr().is_odd()) - )?); - - // Extend the note with pk_d representation - note_contents.extend(y_contents); - note_contents.push(sign_bit); - } - - assert_eq!( - note_contents.len(), - 64 + // value - 256 + // g_d - 256 // pk_d - ); - - // Compute the hash of the note contents - let mut cm = pedersen_hash::pedersen_hash( - cs.namespace(|| "note content hash"), - pedersen_hash::Personalization::NoteCommitment, - ¬e_contents, - self.params - )?; - - { - // Booleanize the randomness - let rcm = boolean::field_into_boolean_vec_le( - cs.namespace(|| "rcm"), - self.commitment_randomness - )?; - - // Compute the note commitment randomness in the exponent - let rcm = ecc::fixed_base_multiplication( - cs.namespace(|| "computation of commitment randomness"), - FixedGenerators::NoteCommitmentRandomness, - &rcm, - self.params - )?; - - // Randomize our note commitment - cm = cm.add( - cs.namespace(|| "randomization of note commitment"), - &rcm, - self.params - )?; - } - - // Only the x-coordinate of the output is revealed, - // since we know it is prime order, and we know that - // the x-coordinate is an injective encoding for - // prime-order elements. - cm.get_x().inputize(cs.namespace(|| "commitment"))?; - - Ok(()) - } -} - -#[test] -fn test_input_circuit_with_bls12_381() { - use pairing::{Field, BitIterator}; - use pairing::bls12_381::*; - use rand::{SeedableRng, Rng, XorShiftRng}; - use ::circuit::test::*; - use jubjub::{JubjubBls12, fs, edwards}; - - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let tree_depth = 32; - - for _ in 0..10 { - let value_commitment = ValueCommitment { - value: rng.gen(), - randomness: rng.gen() - }; - - let nsk: fs::Fs = rng.gen(); - let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params); - - let proof_generation_key = ::primitives::ProofGenerationKey { - ak: ak.clone(), - nsk: nsk.clone() - }; - - let viewing_key = proof_generation_key.into_viewing_key(params); - - let payment_address; - - loop { - let diversifier = ::primitives::Diversifier(rng.gen()); - - if let Some(p) = viewing_key.into_payment_address( - diversifier, - params - ) - { - payment_address = p; - break; - } - } - - let g_d = payment_address.diversifier.g_d(params).unwrap(); - let commitment_randomness: fs::Fs = rng.gen(); - let auth_path = vec![Some((rng.gen(), rng.gen())); tree_depth]; - let ar: fs::Fs = rng.gen(); - - { - let rk = viewing_key.rk(ar, params).into_xy(); - let expected_value_cm = value_commitment.cm(params).into_xy(); - let note = ::primitives::Note { - value: value_commitment.value, - g_d: g_d.clone(), - pk_d: payment_address.pk_d.clone(), - r: commitment_randomness.clone() - }; - - let mut position = 0u64; - let cm: Fr = note.cm(params); - let mut cur = cm.clone(); - - for (i, val) in auth_path.clone().into_iter().enumerate() - { - let (uncle, b) = val.unwrap(); - - let mut lhs = cur; - let mut rhs = uncle; - - if b { - ::std::mem::swap(&mut lhs, &mut rhs); - } - - let mut lhs: Vec = BitIterator::new(lhs.into_repr()).collect(); - let mut rhs: Vec = BitIterator::new(rhs.into_repr()).collect(); - - lhs.reverse(); - rhs.reverse(); - - cur = ::pedersen_hash::pedersen_hash::( - ::pedersen_hash::Personalization::MerkleTree(i), - lhs.into_iter() - .take(Fr::NUM_BITS as usize) - .chain(rhs.into_iter().take(Fr::NUM_BITS as usize)), - params - ).into_xy().0; - - if b { - position |= 1 << i; - } - } - - let expected_nf = note.nf(&viewing_key, position, params); - let expected_nf = multipack::bytes_to_bits_le(&expected_nf); - let expected_nf = multipack::compute_multipacking::(&expected_nf); - assert_eq!(expected_nf.len(), 2); - - let mut cs = TestConstraintSystem::::new(); - - let instance = Spend { - params: params, - value_commitment: Some(value_commitment.clone()), - proof_generation_key: Some(proof_generation_key.clone()), - payment_address: Some(payment_address.clone()), - commitment_randomness: Some(commitment_randomness), - ar: Some(ar), - auth_path: auth_path.clone(), - anchor: Some(cur) - }; - - instance.synthesize(&mut cs).unwrap(); - - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 98777); - assert_eq!(cs.hash(), "d37c738e83df5d9b0bb6495ac96abf21bcb2697477e2c15c2c7916ff7a3b6a89"); - - assert_eq!(cs.get("randomization of note commitment/x3/num"), cm); - - assert_eq!(cs.num_inputs(), 8); - assert_eq!(cs.get_input(0, "ONE"), Fr::one()); - assert_eq!(cs.get_input(1, "rk/x/input variable"), rk.0); - assert_eq!(cs.get_input(2, "rk/y/input variable"), rk.1); - assert_eq!(cs.get_input(3, "value commitment/commitment point/x/input variable"), expected_value_cm.0); - assert_eq!(cs.get_input(4, "value commitment/commitment point/y/input variable"), expected_value_cm.1); - assert_eq!(cs.get_input(5, "anchor/input variable"), cur); - assert_eq!(cs.get_input(6, "pack nullifier/input 0"), expected_nf[0]); - assert_eq!(cs.get_input(7, "pack nullifier/input 1"), expected_nf[1]); - } - } -} - -#[test] -fn test_output_circuit_with_bls12_381() { - use pairing::{Field}; - use pairing::bls12_381::*; - use rand::{SeedableRng, Rng, XorShiftRng}; - use ::circuit::test::*; - use jubjub::{JubjubBls12, fs, edwards}; - - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let value_commitment = ValueCommitment { - value: rng.gen(), - randomness: rng.gen() - }; - - let nsk: fs::Fs = rng.gen(); - let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params); - - let proof_generation_key = ::primitives::ProofGenerationKey { - ak: ak.clone(), - nsk: nsk.clone() - }; - - let viewing_key = proof_generation_key.into_viewing_key(params); - - let payment_address; - - loop { - let diversifier = ::primitives::Diversifier(rng.gen()); - - if let Some(p) = viewing_key.into_payment_address( - diversifier, - params - ) - { - payment_address = p; - break; - } - } - - let commitment_randomness: fs::Fs = rng.gen(); - let esk: fs::Fs = rng.gen(); - - { - let mut cs = TestConstraintSystem::::new(); - - let instance = Output { - params: params, - value_commitment: Some(value_commitment.clone()), - payment_address: Some(payment_address.clone()), - commitment_randomness: Some(commitment_randomness), - esk: Some(esk.clone()) - }; - - instance.synthesize(&mut cs).unwrap(); - - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 7827); - assert_eq!(cs.hash(), "c26d5cdfe6ccd65c03390902c02e11393ea6bb96aae32a7f2ecb12eb9103faee"); - - let expected_cm = payment_address.create_note( - value_commitment.value, - commitment_randomness, - params - ).expect("should be valid").cm(params); - - let expected_value_cm = value_commitment.cm(params).into_xy(); - - let expected_epk = payment_address.g_d(params).expect("should be valid").mul(esk, params); - let expected_epk_xy = expected_epk.into_xy(); - - assert_eq!(cs.num_inputs(), 6); - assert_eq!(cs.get_input(0, "ONE"), Fr::one()); - assert_eq!(cs.get_input(1, "value commitment/commitment point/x/input variable"), expected_value_cm.0); - assert_eq!(cs.get_input(2, "value commitment/commitment point/y/input variable"), expected_value_cm.1); - assert_eq!(cs.get_input(3, "epk/x/input variable"), expected_epk_xy.0); - assert_eq!(cs.get_input(4, "epk/y/input variable"), expected_epk_xy.1); - assert_eq!(cs.get_input(5, "commitment/input variable"), expected_cm); - } - } -} diff --git a/sapling-crypto/src/circuit/sha256.rs b/sapling-crypto/src/circuit/sha256.rs deleted file mode 100644 index 7b55fc8..0000000 --- a/sapling-crypto/src/circuit/sha256.rs +++ /dev/null @@ -1,417 +0,0 @@ -use super::uint32::UInt32; -use super::multieq::MultiEq; -use super::boolean::Boolean; -use bellman::{ConstraintSystem, SynthesisError}; -use pairing::Engine; - -const ROUND_CONSTANTS: [u32; 64] = [ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -]; - -const IV: [u32; 8] = [ - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, - 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 -]; - -pub fn sha256_block_no_padding( - mut cs: CS, - input: &[Boolean] -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - assert_eq!(input.len(), 512); - - Ok(sha256_compression_function( - &mut cs, - &input, - &get_sha256_iv() - )? - .into_iter() - .flat_map(|e| e.into_bits_be()) - .collect()) -} - -pub fn sha256( - mut cs: CS, - input: &[Boolean] -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - assert!(input.len() % 8 == 0); - - let mut padded = input.to_vec(); - let plen = padded.len() as u64; - // append a single '1' bit - padded.push(Boolean::constant(true)); - // append K '0' bits, where K is the minimum number >= 0 such that L + 1 + K + 64 is a multiple of 512 - while (padded.len() + 64) % 512 != 0 { - padded.push(Boolean::constant(false)); - } - // append L as a 64-bit big-endian integer, making the total post-processed length a multiple of 512 bits - for b in (0..64).rev().map(|i| (plen >> i) & 1 == 1) { - padded.push(Boolean::constant(b)); - } - assert!(padded.len() % 512 == 0); - - let mut cur = get_sha256_iv(); - for (i, block) in padded.chunks(512).enumerate() { - cur = sha256_compression_function( - cs.namespace(|| format!("block {}", i)), - block, - &cur - )?; - } - - Ok(cur.into_iter() - .flat_map(|e| e.into_bits_be()) - .collect()) -} - -fn get_sha256_iv() -> Vec { - IV.iter().map(|&v| UInt32::constant(v)).collect() -} - -fn sha256_compression_function( - cs: CS, - input: &[Boolean], - current_hash_value: &[UInt32] -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - assert_eq!(input.len(), 512); - assert_eq!(current_hash_value.len(), 8); - - let mut w = input.chunks(32) - .map(|e| UInt32::from_bits_be(e)) - .collect::>(); - - // We can save some constraints by combining some of - // the constraints in different u32 additions - let mut cs = MultiEq::new(cs); - - for i in 16..64 { - let cs = &mut cs.namespace(|| format!("w extension {}", i)); - - // s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3) - let mut s0 = w[i-15].rotr(7); - s0 = s0.xor( - cs.namespace(|| "first xor for s0"), - &w[i-15].rotr(18) - )?; - s0 = s0.xor( - cs.namespace(|| "second xor for s0"), - &w[i-15].shr(3) - )?; - - // s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10) - let mut s1 = w[i-2].rotr(17); - s1 = s1.xor( - cs.namespace(|| "first xor for s1"), - &w[i-2].rotr(19) - )?; - s1 = s1.xor( - cs.namespace(|| "second xor for s1"), - &w[i-2].shr(10) - )?; - - let tmp = UInt32::addmany( - cs.namespace(|| "computation of w[i]"), - &[w[i-16].clone(), s0, w[i-7].clone(), s1] - )?; - - // w[i] := w[i-16] + s0 + w[i-7] + s1 - w.push(tmp); - } - - assert_eq!(w.len(), 64); - - enum Maybe { - Deferred(Vec), - Concrete(UInt32) - } - - impl Maybe { - fn compute( - self, - cs: M, - others: &[UInt32] - ) -> Result - where E: Engine, - CS: ConstraintSystem, - M: ConstraintSystem> - { - Ok(match self { - Maybe::Concrete(ref v) => { - return Ok(v.clone()) - }, - Maybe::Deferred(mut v) => { - v.extend(others.into_iter().cloned()); - UInt32::addmany( - cs, - &v - )? - } - }) - } - } - - let mut a = Maybe::Concrete(current_hash_value[0].clone()); - let mut b = current_hash_value[1].clone(); - let mut c = current_hash_value[2].clone(); - let mut d = current_hash_value[3].clone(); - let mut e = Maybe::Concrete(current_hash_value[4].clone()); - let mut f = current_hash_value[5].clone(); - let mut g = current_hash_value[6].clone(); - let mut h = current_hash_value[7].clone(); - - for i in 0..64 { - let cs = &mut cs.namespace(|| format!("compression round {}", i)); - - // S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25) - let new_e = e.compute(cs.namespace(|| "deferred e computation"), &[])?; - let mut s1 = new_e.rotr(6); - s1 = s1.xor( - cs.namespace(|| "first xor for s1"), - &new_e.rotr(11) - )?; - s1 = s1.xor( - cs.namespace(|| "second xor for s1"), - &new_e.rotr(25) - )?; - - // ch := (e and f) xor ((not e) and g) - let ch = UInt32::sha256_ch( - cs.namespace(|| "ch"), - &new_e, - &f, - &g - )?; - - // temp1 := h + S1 + ch + k[i] + w[i] - let temp1 = vec![ - h.clone(), - s1, - ch, - UInt32::constant(ROUND_CONSTANTS[i]), - w[i].clone() - ]; - - // S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22) - let new_a = a.compute(cs.namespace(|| "deferred a computation"), &[])?; - let mut s0 = new_a.rotr(2); - s0 = s0.xor( - cs.namespace(|| "first xor for s0"), - &new_a.rotr(13) - )?; - s0 = s0.xor( - cs.namespace(|| "second xor for s0"), - &new_a.rotr(22) - )?; - - // maj := (a and b) xor (a and c) xor (b and c) - let maj = UInt32::sha256_maj( - cs.namespace(|| "maj"), - &new_a, - &b, - &c - )?; - - // temp2 := S0 + maj - let temp2 = vec![s0, maj]; - - /* - h := g - g := f - f := e - e := d + temp1 - d := c - c := b - b := a - a := temp1 + temp2 - */ - - h = g; - g = f; - f = new_e; - e = Maybe::Deferred(temp1.iter().cloned().chain(Some(d)).collect::>()); - d = c; - c = b; - b = new_a; - a = Maybe::Deferred(temp1.iter().cloned().chain(temp2.iter().cloned()).collect::>()); - } - - /* - Add the compressed chunk to the current hash value: - h0 := h0 + a - h1 := h1 + b - h2 := h2 + c - h3 := h3 + d - h4 := h4 + e - h5 := h5 + f - h6 := h6 + g - h7 := h7 + h - */ - - let h0 = a.compute( - cs.namespace(|| "deferred h0 computation"), - &[current_hash_value[0].clone()] - )?; - - let h1 = UInt32::addmany( - cs.namespace(|| "new h1"), - &[current_hash_value[1].clone(), b] - )?; - - let h2 = UInt32::addmany( - cs.namespace(|| "new h2"), - &[current_hash_value[2].clone(), c] - )?; - - let h3 = UInt32::addmany( - cs.namespace(|| "new h3"), - &[current_hash_value[3].clone(), d] - )?; - - let h4 = e.compute( - cs.namespace(|| "deferred h4 computation"), - &[current_hash_value[4].clone()] - )?; - - let h5 = UInt32::addmany( - cs.namespace(|| "new h5"), - &[current_hash_value[5].clone(), f] - )?; - - let h6 = UInt32::addmany( - cs.namespace(|| "new h6"), - &[current_hash_value[6].clone(), g] - )?; - - let h7 = UInt32::addmany( - cs.namespace(|| "new h7"), - &[current_hash_value[7].clone(), h] - )?; - - Ok(vec![h0, h1, h2, h3, h4, h5, h6, h7]) -} - -#[cfg(test)] -mod test { - use super::*; - use circuit::boolean::AllocatedBit; - use pairing::bls12_381::Bls12; - use circuit::test::TestConstraintSystem; - use rand::{XorShiftRng, SeedableRng, Rng}; - - #[test] - fn test_blank_hash() { - let iv = get_sha256_iv(); - - let mut cs = TestConstraintSystem::::new(); - let mut input_bits: Vec<_> = (0..512).map(|_| Boolean::Constant(false)).collect(); - input_bits[0] = Boolean::Constant(true); - let out = sha256_compression_function( - &mut cs, - &input_bits, - &iv - ).unwrap(); - let out_bits: Vec<_> = out.into_iter().flat_map(|e| e.into_bits_be()).collect(); - - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 0); - - let expected = hex!("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); - - let mut out = out_bits.into_iter(); - for b in expected.into_iter() { - for i in (0..8).rev() { - let c = out.next().unwrap().get_value().unwrap(); - - assert_eq!(c, (b >> i) & 1u8 == 1u8); - } - } - } - - #[test] - fn test_full_block() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let iv = get_sha256_iv(); - - let mut cs = TestConstraintSystem::::new(); - let input_bits: Vec<_> = (0..512).map(|i| { - Boolean::from( - AllocatedBit::alloc( - cs.namespace(|| format!("input bit {}", i)), - Some(rng.gen()) - ).unwrap() - ) - }).collect(); - - sha256_compression_function( - cs.namespace(|| "sha256"), - &input_bits, - &iv - ).unwrap(); - - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints() - 512, 25840); - } - - #[test] - fn test_against_vectors() { - use crypto::sha2::Sha256; - use crypto::digest::Digest; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) - { - let mut h = Sha256::new(); - let data: Vec = (0..input_len).map(|_| rng.gen()).collect(); - h.input(&data); - let mut hash_result = [0u8; 32]; - h.result(&mut hash_result[..]); - - let mut cs = TestConstraintSystem::::new(); - let mut input_bits = vec![]; - - for (byte_i, input_byte) in data.into_iter().enumerate() { - for bit_i in (0..8).rev() { - let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i)); - - input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into()); - } - } - - let r = sha256(&mut cs, &input_bits).unwrap(); - - assert!(cs.is_satisfied()); - - let mut s = hash_result.as_ref().iter() - .flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8)); - - for b in r { - match b { - Boolean::Is(b) => { - assert!(s.next().unwrap() == b.get_value().unwrap()); - }, - Boolean::Not(b) => { - assert!(s.next().unwrap() != b.get_value().unwrap()); - }, - Boolean::Constant(b) => { - assert!(input_len == 0); - assert!(s.next().unwrap() == b); - } - } - } - } - } -} diff --git a/sapling-crypto/src/circuit/sprout/commitment.rs b/sapling-crypto/src/circuit/sprout/commitment.rs deleted file mode 100644 index a32f05c..0000000 --- a/sapling-crypto/src/circuit/sprout/commitment.rs +++ /dev/null @@ -1,42 +0,0 @@ -use pairing::{Engine}; -use bellman::{ConstraintSystem, SynthesisError}; -use circuit::sha256::{ - sha256 -}; -use circuit::boolean::{ - Boolean -}; - -pub fn note_comm( - cs: CS, - a_pk: &[Boolean], - value: &[Boolean], - rho: &[Boolean], - r: &[Boolean] -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - assert_eq!(a_pk.len(), 256); - assert_eq!(value.len(), 64); - assert_eq!(rho.len(), 256); - assert_eq!(r.len(), 256); - - let mut image = vec![]; - image.push(Boolean::constant(true)); - image.push(Boolean::constant(false)); - image.push(Boolean::constant(true)); - image.push(Boolean::constant(true)); - image.push(Boolean::constant(false)); - image.push(Boolean::constant(false)); - image.push(Boolean::constant(false)); - image.push(Boolean::constant(false)); - image.extend(a_pk.iter().cloned()); - image.extend(value.iter().cloned()); - image.extend(rho.iter().cloned()); - image.extend(r.iter().cloned()); - - sha256( - cs, - &image - ) -} diff --git a/sapling-crypto/src/circuit/sprout/input.rs b/sapling-crypto/src/circuit/sprout/input.rs deleted file mode 100644 index ce69bc0..0000000 --- a/sapling-crypto/src/circuit/sprout/input.rs +++ /dev/null @@ -1,226 +0,0 @@ -use pairing::{Engine}; -use bellman::{ConstraintSystem, SynthesisError}; -use circuit::sha256::{ - sha256_block_no_padding -}; -use circuit::boolean::{ - AllocatedBit, - Boolean -}; - -use super::*; -use super::prfs::*; -use super::commitment::note_comm; - -pub struct InputNote { - pub nf: Vec, - pub mac: Vec, -} - -impl InputNote { - pub fn compute( - mut cs: CS, - a_sk: Option, - rho: Option, - r: Option, - value: &NoteValue, - h_sig: &[Boolean], - nonce: bool, - auth_path: [Option<([u8; 32], bool)>; TREE_DEPTH], - rt: &[Boolean] - ) -> Result - where E: Engine, CS: ConstraintSystem - { - let a_sk = witness_u252( - cs.namespace(|| "a_sk"), - a_sk.as_ref().map(|a_sk| &a_sk.0[..]) - )?; - - let rho = witness_u256( - cs.namespace(|| "rho"), - rho.as_ref().map(|rho| &rho.0[..]) - )?; - - let r = witness_u256( - cs.namespace(|| "r"), - r.as_ref().map(|r| &r.0[..]) - )?; - - let a_pk = prf_a_pk( - cs.namespace(|| "a_pk computation"), - &a_sk - )?; - - let nf = prf_nf( - cs.namespace(|| "nf computation"), - &a_sk, - &rho - )?; - - let mac = prf_pk( - cs.namespace(|| "mac computation"), - &a_sk, - h_sig, - nonce - )?; - - let cm = note_comm( - cs.namespace(|| "cm computation"), - &a_pk, - &value.bits_le(), - &rho, - &r - )?; - - // Witness into the merkle tree - let mut cur = cm.clone(); - - for (i, layer) in auth_path.into_iter().enumerate() { - let cs = &mut cs.namespace(|| format!("layer {}", i)); - - let cur_is_right = AllocatedBit::alloc( - cs.namespace(|| "cur is right"), - layer.as_ref().map(|&(_, p)| p) - )?; - - let lhs = cur; - let rhs = witness_u256( - cs.namespace(|| "sibling"), - layer.as_ref().map(|&(ref sibling, _)| &sibling[..]) - )?; - - // Conditionally swap if cur is right - let preimage = conditionally_swap_u256( - cs.namespace(|| "conditional swap"), - &lhs[..], - &rhs[..], - &cur_is_right - )?; - - cur = sha256_block_no_padding( - cs.namespace(|| "hash of this layer"), - &preimage - )?; - } - - // enforce must be true if the value is nonzero - let enforce = AllocatedBit::alloc( - cs.namespace(|| "enforce"), - value.get_value().map(|n| n != 0) - )?; - - // value * (1 - enforce) = 0 - // If `value` is zero, `enforce` _can_ be zero. - // If `value` is nonzero, `enforce` _must_ be one. - cs.enforce( - || "enforce validity", - |_| value.lc(), - |lc| lc + CS::one() - enforce.get_variable(), - |lc| lc - ); - - assert_eq!(cur.len(), rt.len()); - - // Check that the anchor (exposed as a public input) - // is equal to the merkle tree root that we calculated - // for this note - for (i, (cur, rt)) in cur.into_iter().zip(rt.iter()).enumerate() { - // (cur - rt) * enforce = 0 - // if enforce is zero, cur and rt can be different - // if enforce is one, they must be equal - cs.enforce( - || format!("conditionally enforce correct root for bit {}", i), - |_| cur.lc(CS::one(), E::Fr::one()) - &rt.lc(CS::one(), E::Fr::one()), - |lc| lc + enforce.get_variable(), - |lc| lc - ); - } - - Ok(InputNote { - mac: mac, - nf: nf - }) - } -} - -/// Swaps two 256-bit blobs conditionally, returning the -/// 512-bit concatenation. -pub fn conditionally_swap_u256( - mut cs: CS, - lhs: &[Boolean], - rhs: &[Boolean], - condition: &AllocatedBit -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem, -{ - assert_eq!(lhs.len(), 256); - assert_eq!(rhs.len(), 256); - - let mut new_lhs = vec![]; - let mut new_rhs = vec![]; - - for (i, (lhs, rhs)) in lhs.iter().zip(rhs.iter()).enumerate() { - let cs = &mut cs.namespace(|| format!("bit {}", i)); - - let x = Boolean::from(AllocatedBit::alloc( - cs.namespace(|| "x"), - condition.get_value().and_then(|v| { - if v { - rhs.get_value() - } else { - lhs.get_value() - } - }) - )?); - - // x = (1-condition)lhs + (condition)rhs - // x = lhs - lhs(condition) + rhs(condition) - // x - lhs = condition (rhs - lhs) - // if condition is zero, we don't swap, so - // x - lhs = 0 - // x = lhs - // if condition is one, we do swap, so - // x - lhs = rhs - lhs - // x = rhs - cs.enforce( - || "conditional swap for x", - |lc| lc + &rhs.lc(CS::one(), E::Fr::one()) - - &lhs.lc(CS::one(), E::Fr::one()), - |lc| lc + condition.get_variable(), - |lc| lc + &x.lc(CS::one(), E::Fr::one()) - - &lhs.lc(CS::one(), E::Fr::one()) - ); - - let y = Boolean::from(AllocatedBit::alloc( - cs.namespace(|| "y"), - condition.get_value().and_then(|v| { - if v { - lhs.get_value() - } else { - rhs.get_value() - } - }) - )?); - - // y = (1-condition)rhs + (condition)lhs - // y - rhs = condition (lhs - rhs) - cs.enforce( - || "conditional swap for y", - |lc| lc + &lhs.lc(CS::one(), E::Fr::one()) - - &rhs.lc(CS::one(), E::Fr::one()), - |lc| lc + condition.get_variable(), - |lc| lc + &y.lc(CS::one(), E::Fr::one()) - - &rhs.lc(CS::one(), E::Fr::one()) - ); - - new_lhs.push(x); - new_rhs.push(y); - } - - let mut f = new_lhs; - f.extend(new_rhs); - - assert_eq!(f.len(), 512); - - Ok(f) -} diff --git a/sapling-crypto/src/circuit/sprout/mod.rs b/sapling-crypto/src/circuit/sprout/mod.rs deleted file mode 100644 index 586de8c..0000000 --- a/sapling-crypto/src/circuit/sprout/mod.rs +++ /dev/null @@ -1,488 +0,0 @@ -use pairing::{Engine, Field}; -use bellman::{ConstraintSystem, SynthesisError, Circuit, LinearCombination}; -use circuit::boolean::{ - AllocatedBit, - Boolean -}; -use circuit::multipack::pack_into_inputs; - -mod prfs; -mod commitment; -mod input; -mod output; - -use self::input::*; -use self::output::*; - -pub const TREE_DEPTH: usize = 29; - -pub struct SpendingKey(pub [u8; 32]); -pub struct PayingKey(pub [u8; 32]); -pub struct UniqueRandomness(pub [u8; 32]); -pub struct CommitmentRandomness(pub [u8; 32]); - -pub struct JoinSplit { - pub vpub_old: Option, - pub vpub_new: Option, - pub h_sig: Option<[u8; 32]>, - pub phi: Option<[u8; 32]>, - pub inputs: Vec, - pub outputs: Vec, - pub rt: Option<[u8; 32]>, -} - -pub struct JSInput { - pub value: Option, - pub a_sk: Option, - pub rho: Option, - pub r: Option, - pub auth_path: [Option<([u8; 32], bool)>; TREE_DEPTH] -} - -pub struct JSOutput { - pub value: Option, - pub a_pk: Option, - pub r: Option -} - -impl Circuit for JoinSplit { - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { - assert_eq!(self.inputs.len(), 2); - assert_eq!(self.outputs.len(), 2); - - // vpub_old is the value entering the - // JoinSplit from the "outside" value - // pool - let vpub_old = NoteValue::new( - cs.namespace(|| "vpub_old"), - self.vpub_old - )?; - - // vpub_new is the value leaving the - // JoinSplit into the "outside" value - // pool - let vpub_new = NoteValue::new( - cs.namespace(|| "vpub_new"), - self.vpub_new - )?; - - // The left hand side of the balance equation - // vpub_old + inputs[0].value + inputs[1].value - let mut lhs = vpub_old.lc(); - - // The right hand side of the balance equation - // vpub_old + inputs[0].value + inputs[1].value - let mut rhs = vpub_new.lc(); - - // Witness rt (merkle tree root) - let rt = witness_u256( - cs.namespace(|| "rt"), - self.rt.as_ref().map(|v| &v[..]) - ).unwrap(); - - // Witness h_sig - let h_sig = witness_u256( - cs.namespace(|| "h_sig"), - self.h_sig.as_ref().map(|v| &v[..]) - ).unwrap(); - - // Witness phi - let phi = witness_u252( - cs.namespace(|| "phi"), - self.phi.as_ref().map(|v| &v[..]) - ).unwrap(); - - let mut input_notes = vec![]; - let mut lhs_total = self.vpub_old; - - // Iterate over the JoinSplit inputs - for (i, input) in self.inputs.into_iter().enumerate() { - let cs = &mut cs.namespace(|| format!("input {}", i)); - - // Accumulate the value of the left hand side - if let Some(value) = input.value { - lhs_total = lhs_total.map(|v| v.wrapping_add(value)); - } - - // Allocate the value of the note - let value = NoteValue::new( - cs.namespace(|| "value"), - input.value - )?; - - // Compute the nonce (for PRF inputs) which is false - // for the first input, and true for the second input. - let nonce = match i { - 0 => false, - 1 => true, - _ => unreachable!() - }; - - // Perform input note computations - input_notes.push(InputNote::compute( - cs.namespace(|| "note"), - input.a_sk, - input.rho, - input.r, - &value, - &h_sig, - nonce, - input.auth_path, - &rt - )?); - - // Add the note value to the left hand side of - // the balance equation - lhs = lhs + &value.lc(); - } - - // Rebind lhs so that it isn't mutable anymore - let lhs = lhs; - - // See zcash/zcash/issues/854 - { - // Expected sum of the left hand side of the balance - // equation, expressed as a 64-bit unsigned integer - let lhs_total = NoteValue::new( - cs.namespace(|| "total value of left hand side"), - lhs_total - )?; - - // Enforce that the left hand side can be expressed as a 64-bit - // integer - cs.enforce( - || "left hand side can be expressed as a 64-bit unsigned integer", - |_| lhs.clone(), - |lc| lc + CS::one(), - |_| lhs_total.lc() - ); - } - - let mut output_notes = vec![]; - - // Iterate over the JoinSplit outputs - for (i, output) in self.outputs.into_iter().enumerate() { - let cs = &mut cs.namespace(|| format!("output {}", i)); - - let value = NoteValue::new( - cs.namespace(|| "value"), - output.value - )?; - - // Compute the nonce (for PRF inputs) which is false - // for the first output, and true for the second output. - let nonce = match i { - 0 => false, - 1 => true, - _ => unreachable!() - }; - - // Perform output note computations - output_notes.push(OutputNote::compute( - cs.namespace(|| "note"), - output.a_pk, - &value, - output.r, - &phi, - &h_sig, - nonce - )?); - - // Add the note value to the right hand side of - // the balance equation - rhs = rhs + &value.lc(); - } - - // Enforce that balance is equal - cs.enforce( - || "balance equation", - |_| lhs.clone(), - |lc| lc + CS::one(), - |_| rhs - ); - - let mut public_inputs = vec![]; - public_inputs.extend(rt); - public_inputs.extend(h_sig); - - for note in input_notes { - public_inputs.extend(note.nf); - public_inputs.extend(note.mac); - } - - for note in output_notes { - public_inputs.extend(note.cm); - } - - public_inputs.extend(vpub_old.bits_le()); - public_inputs.extend(vpub_new.bits_le()); - - pack_into_inputs(cs.namespace(|| "input packing"), &public_inputs) - } -} - -pub struct NoteValue { - value: Option, - // Least significant digit first - bits: Vec -} - -impl NoteValue { - fn new( - mut cs: CS, - value: Option - ) -> Result - where E: Engine, CS: ConstraintSystem, - { - let mut values; - match value { - Some(mut val) => { - values = vec![]; - for _ in 0..64 { - values.push(Some(val & 1 == 1)); - val >>= 1; - } - }, - None => { - values = vec![None; 64]; - } - } - - let mut bits = vec![]; - for (i, value) in values.into_iter().enumerate() { - bits.push( - AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - value - )? - ); - } - - Ok(NoteValue { - value: value, - bits: bits - }) - } - - /// Encodes the bits of the value into little-endian - /// byte order. - fn bits_le(&self) -> Vec { - self.bits.chunks(8) - .flat_map(|v| v.iter().rev()) - .cloned() - .map(|e| Boolean::from(e)) - .collect() - } - - /// Computes this value as a linear combination of - /// its bits. - fn lc(&self) -> LinearCombination { - let mut tmp = LinearCombination::zero(); - - let mut coeff = E::Fr::one(); - for b in &self.bits { - tmp = tmp + (coeff, b.get_variable()); - coeff.double(); - } - - tmp - } - - fn get_value(&self) -> Option { - self.value - } -} - -/// Witnesses some bytes in the constraint system, -/// skipping the first `skip_bits`. -fn witness_bits( - mut cs: CS, - value: Option<&[u8]>, - num_bits: usize, - skip_bits: usize -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem, -{ - let bit_values = if let Some(value) = value { - let mut tmp = vec![]; - for b in value.iter() - .flat_map(|&m| (0..8).rev().map(move |i| m >> i & 1 == 1)) - .skip(skip_bits) - { - tmp.push(Some(b)); - } - tmp - } else { - vec![None; num_bits] - }; - assert_eq!(bit_values.len(), num_bits); - - let mut bits = vec![]; - - for (i, value) in bit_values.into_iter().enumerate() { - bits.push(Boolean::from(AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - value - )?)); - } - - Ok(bits) -} - -fn witness_u256( - cs: CS, - value: Option<&[u8]>, -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem, -{ - witness_bits(cs, value, 256, 0) -} - -fn witness_u252( - cs: CS, - value: Option<&[u8]>, -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem, -{ - witness_bits(cs, value, 252, 4) -} - -#[test] -fn test_sprout_constraints() { - use pairing::bls12_381::{Bls12}; - use ::circuit::test::*; - - use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian}; - - let test_vector = include_bytes!("test_vectors.dat"); - let mut test_vector = &test_vector[..]; - - fn get_u256(mut reader: R) -> [u8; 32] { - let mut result = [0u8; 32]; - - for i in 0..32 { - result[i] = reader.read_u8().unwrap(); - } - - result - } - - while test_vector.len() != 0 { - let mut cs = TestConstraintSystem::::new(); - - let phi = Some(get_u256(&mut test_vector)); - let rt = Some(get_u256(&mut test_vector)); - let h_sig = Some(get_u256(&mut test_vector)); - - let mut inputs = vec![]; - for _ in 0..2 { - test_vector.read_u8().unwrap(); - - let mut auth_path = [None; TREE_DEPTH]; - for i in (0..TREE_DEPTH).rev() { - test_vector.read_u8().unwrap(); - - let sibling = get_u256(&mut test_vector); - - auth_path[i] = Some((sibling, false)); - } - let mut position = test_vector.read_u64::().unwrap(); - for i in 0..TREE_DEPTH { - auth_path[i].as_mut().map(|p| { - p.1 = (position & 1) == 1 - }); - - position >>= 1; - } - - // a_pk - let _ = Some(SpendingKey(get_u256(&mut test_vector))); - let value = Some(test_vector.read_u64::().unwrap()); - let rho = Some(UniqueRandomness(get_u256(&mut test_vector))); - let r = Some(CommitmentRandomness(get_u256(&mut test_vector))); - let a_sk = Some(SpendingKey(get_u256(&mut test_vector))); - - inputs.push( - JSInput { - value: value, - a_sk: a_sk, - rho: rho, - r: r, - auth_path: auth_path - } - ); - } - - let mut outputs = vec![]; - - for _ in 0..2 { - let a_pk = Some(PayingKey(get_u256(&mut test_vector))); - let value = Some(test_vector.read_u64::().unwrap()); - get_u256(&mut test_vector); - let r = Some(CommitmentRandomness(get_u256(&mut test_vector))); - - outputs.push( - JSOutput { - value: value, - a_pk: a_pk, - r: r - } - ); - } - - let vpub_old = Some(test_vector.read_u64::().unwrap()); - let vpub_new = Some(test_vector.read_u64::().unwrap()); - - let nf1 = get_u256(&mut test_vector); - let nf2 = get_u256(&mut test_vector); - - let cm1 = get_u256(&mut test_vector); - let cm2 = get_u256(&mut test_vector); - - let mac1 = get_u256(&mut test_vector); - let mac2 = get_u256(&mut test_vector); - - let js = JoinSplit { - vpub_old: vpub_old, - vpub_new: vpub_new, - h_sig: h_sig, - phi: phi, - inputs: inputs, - outputs: outputs, - rt: rt - }; - - js.synthesize(&mut cs).unwrap(); - - if let Some(s) = cs.which_is_unsatisfied() { - panic!("{:?}", s); - } - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 1989085); - assert_eq!(cs.num_inputs(), 10); - assert_eq!(cs.hash(), "1a228d3c6377130d1778c7885811dc8b8864049cb5af8aff7e6cd46c5bc4b84c"); - - let mut expected_inputs = vec![]; - expected_inputs.extend(rt.unwrap().to_vec()); - expected_inputs.extend(h_sig.unwrap().to_vec()); - expected_inputs.extend(nf1.to_vec()); - expected_inputs.extend(mac1.to_vec()); - expected_inputs.extend(nf2.to_vec()); - expected_inputs.extend(mac2.to_vec()); - expected_inputs.extend(cm1.to_vec()); - expected_inputs.extend(cm2.to_vec()); - expected_inputs.write_u64::(vpub_old.unwrap()).unwrap(); - expected_inputs.write_u64::(vpub_new.unwrap()).unwrap(); - - use circuit::multipack; - - let expected_inputs = multipack::bytes_to_bits(&expected_inputs); - let expected_inputs = multipack::compute_multipacking::(&expected_inputs); - - assert!(cs.verify(&expected_inputs)); - } -} diff --git a/sapling-crypto/src/circuit/sprout/output.rs b/sapling-crypto/src/circuit/sprout/output.rs deleted file mode 100644 index 9cdbf52..0000000 --- a/sapling-crypto/src/circuit/sprout/output.rs +++ /dev/null @@ -1,54 +0,0 @@ -use pairing::{Engine}; -use bellman::{ConstraintSystem, SynthesisError}; -use circuit::boolean::{Boolean}; - -use super::*; -use super::prfs::*; -use super::commitment::note_comm; - -pub struct OutputNote { - pub cm: Vec -} - -impl OutputNote { - pub fn compute<'a, E, CS>( - mut cs: CS, - a_pk: Option, - value: &NoteValue, - r: Option, - phi: &[Boolean], - h_sig: &[Boolean], - nonce: bool - ) -> Result - where E: Engine, CS: ConstraintSystem, - { - let rho = prf_rho( - cs.namespace(|| "rho"), - phi, - h_sig, - nonce - )?; - - let a_pk = witness_u256( - cs.namespace(|| "a_pk"), - a_pk.as_ref().map(|a_pk| &a_pk.0[..]) - )?; - - let r = witness_u256( - cs.namespace(|| "r"), - r.as_ref().map(|r| &r.0[..]) - )?; - - let cm = note_comm( - cs.namespace(|| "cm computation"), - &a_pk, - &value.bits_le(), - &rho, - &r - )?; - - Ok(OutputNote { - cm: cm - }) - } -} diff --git a/sapling-crypto/src/circuit/sprout/prfs.rs b/sapling-crypto/src/circuit/sprout/prfs.rs deleted file mode 100644 index fff8648..0000000 --- a/sapling-crypto/src/circuit/sprout/prfs.rs +++ /dev/null @@ -1,79 +0,0 @@ -use pairing::{Engine}; -use bellman::{ConstraintSystem, SynthesisError}; -use circuit::sha256::{ - sha256_block_no_padding -}; -use circuit::boolean::{ - Boolean -}; - -fn prf( - cs: CS, - a: bool, - b: bool, - c: bool, - d: bool, - x: &[Boolean], - y: &[Boolean] -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - assert_eq!(x.len(), 252); - assert_eq!(y.len(), 256); - - let mut image = vec![]; - image.push(Boolean::constant(a)); - image.push(Boolean::constant(b)); - image.push(Boolean::constant(c)); - image.push(Boolean::constant(d)); - image.extend(x.iter().cloned()); - image.extend(y.iter().cloned()); - - assert_eq!(image.len(), 512); - - sha256_block_no_padding( - cs, - &image - ) -} - -pub fn prf_a_pk( - cs: CS, - a_sk: &[Boolean] -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - prf(cs, true, true, false, false, a_sk, &(0..256).map(|_| Boolean::constant(false)).collect::>()) -} - -pub fn prf_nf( - cs: CS, - a_sk: &[Boolean], - rho: &[Boolean] -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - prf(cs, true, true, true, false, a_sk, rho) -} - -pub fn prf_pk( - cs: CS, - a_sk: &[Boolean], - h_sig: &[Boolean], - nonce: bool -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - prf(cs, false, nonce, false, false, a_sk, h_sig) -} - -pub fn prf_rho( - cs: CS, - phi: &[Boolean], - h_sig: &[Boolean], - nonce: bool -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - prf(cs, false, nonce, true, false, phi, h_sig) -} diff --git a/sapling-crypto/src/circuit/sprout/test_vectors.dat b/sapling-crypto/src/circuit/sprout/test_vectors.dat deleted file mode 100644 index 1316955771eb17e9a3e11352f1252b6591c151da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10864 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 E1!z(1KmY&$ diff --git a/sapling-crypto/src/circuit/test/mod.rs b/sapling-crypto/src/circuit/test/mod.rs deleted file mode 100644 index 12fe0ca..0000000 --- a/sapling-crypto/src/circuit/test/mod.rs +++ /dev/null @@ -1,492 +0,0 @@ -use pairing::{ - Engine, - Field, - PrimeField, - PrimeFieldRepr -}; - -use bellman::{ - LinearCombination, - SynthesisError, - ConstraintSystem, - Variable, - Index -}; - -use std::collections::HashMap; -use std::fmt::Write; - -use byteorder::{BigEndian, ByteOrder}; -use std::cmp::Ordering; -use std::collections::BTreeMap; - -use blake2_rfc::blake2s::Blake2s; - -#[derive(Debug)] -enum NamedObject { - Constraint(usize), - Var(Variable), - Namespace -} - -/// Constraint system for testing purposes. -pub struct TestConstraintSystem { - named_objects: HashMap, - current_namespace: Vec, - constraints: Vec<( - LinearCombination, - LinearCombination, - LinearCombination, - String - )>, - inputs: Vec<(E::Fr, String)>, - aux: Vec<(E::Fr, String)> -} - -#[derive(Clone, Copy)] -struct OrderedVariable(Variable); - -impl Eq for OrderedVariable {} -impl PartialEq for OrderedVariable { - fn eq(&self, other: &OrderedVariable) -> bool { - match (self.0.get_unchecked(), other.0.get_unchecked()) { - (Index::Input(ref a), Index::Input(ref b)) => a == b, - (Index::Aux(ref a), Index::Aux(ref b)) => a == b, - _ => false - } - } -} -impl PartialOrd for OrderedVariable { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} -impl Ord for OrderedVariable { - fn cmp(&self, other: &Self) -> Ordering { - match (self.0.get_unchecked(), other.0.get_unchecked()) { - (Index::Input(ref a), Index::Input(ref b)) => a.cmp(b), - (Index::Aux(ref a), Index::Aux(ref b)) => a.cmp(b), - (Index::Input(_), Index::Aux(_)) => Ordering::Less, - (Index::Aux(_), Index::Input(_)) => Ordering::Greater - } - } -} - -fn proc_lc( - terms: &[(Variable, E::Fr)], -) -> BTreeMap -{ - let mut map = BTreeMap::new(); - for &(var, coeff) in terms { - map.entry(OrderedVariable(var)) - .or_insert(E::Fr::zero()) - .add_assign(&coeff); - } - - // Remove terms that have a zero coefficient to normalize - let mut to_remove = vec![]; - for (var, coeff) in map.iter() { - if coeff.is_zero() { - to_remove.push(var.clone()) - } - } - - for var in to_remove { - map.remove(&var); - } - - map -} - -fn hash_lc( - terms: &[(Variable, E::Fr)], - h: &mut Blake2s -) -{ - let map = proc_lc::(terms); - - let mut buf = [0u8; 9 + 32]; - BigEndian::write_u64(&mut buf[0..8], map.len() as u64); - h.update(&buf[0..8]); - - for (var, coeff) in map { - match var.0.get_unchecked() { - Index::Input(i) => { - buf[0] = b'I'; - BigEndian::write_u64(&mut buf[1..9], i as u64); - }, - Index::Aux(i) => { - buf[0] = b'A'; - BigEndian::write_u64(&mut buf[1..9], i as u64); - } - } - - coeff.into_repr().write_be(&mut buf[9..]).unwrap(); - - h.update(&buf); - } -} - -fn eval_lc( - terms: &[(Variable, E::Fr)], - inputs: &[(E::Fr, String)], - aux: &[(E::Fr, String)] -) -> E::Fr -{ - let mut acc = E::Fr::zero(); - - for &(var, ref coeff) in terms { - let mut tmp = match var.get_unchecked() { - Index::Input(index) => inputs[index].0, - Index::Aux(index) => aux[index].0 - }; - - tmp.mul_assign(&coeff); - acc.add_assign(&tmp); - } - - acc -} - -impl TestConstraintSystem { - pub fn new() -> TestConstraintSystem { - let mut map = HashMap::new(); - map.insert("ONE".into(), NamedObject::Var(TestConstraintSystem::::one())); - - TestConstraintSystem { - named_objects: map, - current_namespace: vec![], - constraints: vec![], - inputs: vec![(E::Fr::one(), "ONE".into())], - aux: vec![] - } - } - - pub fn pretty_print(&self) -> String { - let mut s = String::new(); - - let negone = { - let mut tmp = E::Fr::one(); - tmp.negate(); - tmp - }; - - let powers_of_two = (0..E::Fr::NUM_BITS).map(|i| { - E::Fr::from_str("2").unwrap().pow(&[i as u64]) - }).collect::>(); - - let pp = |s: &mut String, lc: &LinearCombination| { - write!(s, "(").unwrap(); - let mut is_first = true; - for (var, coeff) in proc_lc::(lc.as_ref()) { - if coeff == negone { - write!(s, " - ").unwrap(); - } else if !is_first { - write!(s, " + ").unwrap(); - } - is_first = false; - - if coeff != E::Fr::one() && coeff != negone { - for (i, x) in powers_of_two.iter().enumerate() { - if x == &coeff { - write!(s, "2^{} . ", i).unwrap(); - break; - } - } - - write!(s, "{} . ", coeff).unwrap(); - } - - match var.0.get_unchecked() { - Index::Input(i) => { - write!(s, "`{}`", &self.inputs[i].1).unwrap(); - }, - Index::Aux(i) => { - write!(s, "`{}`", &self.aux[i].1).unwrap(); - } - } - } - if is_first { - // Nothing was visited, print 0. - write!(s, "0").unwrap(); - } - write!(s, ")").unwrap(); - }; - - for &(ref a, ref b, ref c, ref name) in &self.constraints { - write!(&mut s, "\n").unwrap(); - - write!(&mut s, "{}: ", name).unwrap(); - pp(&mut s, a); - write!(&mut s, " * ").unwrap(); - pp(&mut s, b); - write!(&mut s, " = ").unwrap(); - pp(&mut s, c); - } - - write!(&mut s, "\n").unwrap(); - - s - } - - pub fn hash(&self) -> String { - let mut h = Blake2s::new(32); - { - let mut buf = [0u8; 24]; - - BigEndian::write_u64(&mut buf[0..8], self.inputs.len() as u64); - BigEndian::write_u64(&mut buf[8..16], self.aux.len() as u64); - BigEndian::write_u64(&mut buf[16..24], self.constraints.len() as u64); - h.update(&buf); - } - - for constraint in &self.constraints { - hash_lc::(constraint.0.as_ref(), &mut h); - hash_lc::(constraint.1.as_ref(), &mut h); - hash_lc::(constraint.2.as_ref(), &mut h); - } - - let mut s = String::new(); - for b in h.finalize().as_ref() { - s += &format!("{:02x}", b); - } - - s - } - - pub fn which_is_unsatisfied(&self) -> Option<&str> { - for &(ref a, ref b, ref c, ref path) in &self.constraints { - let mut a = eval_lc::(a.as_ref(), &self.inputs, &self.aux); - let b = eval_lc::(b.as_ref(), &self.inputs, &self.aux); - let c = eval_lc::(c.as_ref(), &self.inputs, &self.aux); - - a.mul_assign(&b); - - if a != c { - return Some(&*path) - } - } - - None - } - - pub fn is_satisfied(&self) -> bool - { - self.which_is_unsatisfied().is_none() - } - - pub fn num_constraints(&self) -> usize - { - self.constraints.len() - } - - pub fn set(&mut self, path: &str, to: E::Fr) - { - match self.named_objects.get(path) { - Some(&NamedObject::Var(ref v)) => { - match v.get_unchecked() { - Index::Input(index) => self.inputs[index].0 = to, - Index::Aux(index) => self.aux[index].0 = to - } - } - Some(e) => panic!("tried to set path `{}` to value, but `{:?}` already exists there.", path, e), - _ => panic!("no variable exists at path: {}", path) - } - } - - pub fn verify(&self, expected: &[E::Fr]) -> bool - { - assert_eq!(expected.len() + 1, self.inputs.len()); - - for (a, b) in self.inputs.iter().skip(1).zip(expected.iter()) - { - if &a.0 != b { - return false - } - } - - return true; - } - - pub fn num_inputs(&self) -> usize { - self.inputs.len() - } - - pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr - { - let (assignment, name) = self.inputs[index].clone(); - - assert_eq!(path, name); - - assignment - } - - pub fn get(&mut self, path: &str) -> E::Fr - { - match self.named_objects.get(path) { - Some(&NamedObject::Var(ref v)) => { - match v.get_unchecked() { - Index::Input(index) => self.inputs[index].0, - Index::Aux(index) => self.aux[index].0 - } - } - Some(e) => panic!("tried to get value of path `{}`, but `{:?}` exists there (not a variable)", path, e), - _ => panic!("no variable exists at path: {}", path) - } - } - - fn set_named_obj(&mut self, path: String, to: NamedObject) { - if self.named_objects.contains_key(&path) { - panic!("tried to create object at existing path: {}", path); - } - - self.named_objects.insert(path, to); - } -} - -fn compute_path(ns: &[String], this: String) -> String { - if this.chars().any(|a| a == '/') { - panic!("'/' is not allowed in names"); - } - - let mut name = String::new(); - - let mut needs_separation = false; - for ns in ns.iter().chain(Some(&this).into_iter()) - { - if needs_separation { - name += "/"; - } - - name += ns; - needs_separation = true; - } - - name -} - -impl ConstraintSystem for TestConstraintSystem { - type Root = Self; - - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into - { - let index = self.aux.len(); - let path = compute_path(&self.current_namespace, annotation().into()); - self.aux.push((f()?, path.clone())); - let var = Variable::new_unchecked(Index::Aux(index)); - self.set_named_obj(path, NamedObject::Var(var)); - - Ok(var) - } - - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into - { - let index = self.inputs.len(); - let path = compute_path(&self.current_namespace, annotation().into()); - self.inputs.push((f()?, path.clone())); - let var = Variable::new_unchecked(Index::Input(index)); - self.set_named_obj(path, NamedObject::Var(var)); - - Ok(var) - } - - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination - { - let path = compute_path(&self.current_namespace, annotation().into()); - let index = self.constraints.len(); - self.set_named_obj(path.clone(), NamedObject::Constraint(index)); - - let a = a(LinearCombination::zero()); - let b = b(LinearCombination::zero()); - let c = c(LinearCombination::zero()); - - self.constraints.push((a, b, c, path)); - } - - fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR - { - let name = name_fn().into(); - let path = compute_path(&self.current_namespace, name.clone()); - self.set_named_obj(path.clone(), NamedObject::Namespace); - self.current_namespace.push(name); - } - - fn pop_namespace(&mut self) - { - assert!(self.current_namespace.pop().is_some()); - } - - fn get_root(&mut self) -> &mut Self::Root - { - self - } -} - -#[test] -fn test_cs() { - use pairing::bls12_381::{Bls12, Fr}; - use pairing::PrimeField; - - let mut cs = TestConstraintSystem::::new(); - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 0); - let a = cs.namespace(|| "a").alloc(|| "var", || Ok(Fr::from_str("10").unwrap())).unwrap(); - let b = cs.namespace(|| "b").alloc(|| "var", || Ok(Fr::from_str("4").unwrap())).unwrap(); - let c = cs.alloc(|| "product", || Ok(Fr::from_str("40").unwrap())).unwrap(); - - cs.enforce( - || "mult", - |lc| lc + a, - |lc| lc + b, - |lc| lc + c - ); - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 1); - - cs.set("a/var", Fr::from_str("4").unwrap()); - - let one = TestConstraintSystem::::one(); - cs.enforce( - || "eq", - |lc| lc + a, - |lc| lc + one, - |lc| lc + b - ); - - assert!(!cs.is_satisfied()); - assert!(cs.which_is_unsatisfied() == Some("mult")); - - assert!(cs.get("product") == Fr::from_str("40").unwrap()); - - cs.set("product", Fr::from_str("16").unwrap()); - assert!(cs.is_satisfied()); - - { - let mut cs = cs.namespace(|| "test1"); - let mut cs = cs.namespace(|| "test2"); - cs.alloc(|| "hehe", || Ok(Fr::one())).unwrap(); - } - - assert!(cs.get("test1/test2/hehe") == Fr::one()); -} diff --git a/sapling-crypto/src/circuit/uint32.rs b/sapling-crypto/src/circuit/uint32.rs deleted file mode 100644 index fb0bfa9..0000000 --- a/sapling-crypto/src/circuit/uint32.rs +++ /dev/null @@ -1,755 +0,0 @@ -use pairing::{ - Engine, - Field, - PrimeField -}; - -use bellman::{ - SynthesisError, - ConstraintSystem, - LinearCombination -}; - -use super::boolean::{ - Boolean, - AllocatedBit -}; - -use super::multieq::MultiEq; - -/// Represents an interpretation of 32 `Boolean` objects as an -/// unsigned integer. -#[derive(Clone)] -pub struct UInt32 { - // Least significant bit first - bits: Vec, - value: Option -} - -impl UInt32 { - /// Construct a constant `UInt32` from a `u32` - pub fn constant(value: u32) -> Self - { - let mut bits = Vec::with_capacity(32); - - let mut tmp = value; - for _ in 0..32 { - if tmp & 1 == 1 { - bits.push(Boolean::constant(true)) - } else { - bits.push(Boolean::constant(false)) - } - - tmp >>= 1; - } - - UInt32 { - bits: bits, - value: Some(value) - } - } - - /// Allocate a `UInt32` in the constraint system - pub fn alloc( - mut cs: CS, - value: Option - ) -> Result - where E: Engine, - CS: ConstraintSystem - { - let values = match value { - Some(mut val) => { - let mut v = Vec::with_capacity(32); - - for _ in 0..32 { - v.push(Some(val & 1 == 1)); - val >>= 1; - } - - v - }, - None => vec![None; 32] - }; - - let bits = values.into_iter() - .enumerate() - .map(|(i, v)| { - Ok(Boolean::from(AllocatedBit::alloc( - cs.namespace(|| format!("allocated bit {}", i)), - v - )?)) - }) - .collect::, SynthesisError>>()?; - - Ok(UInt32 { - bits: bits, - value: value - }) - } - - pub fn into_bits_be(&self) -> Vec { - self.bits.iter().rev().cloned().collect() - } - - pub fn from_bits_be(bits: &[Boolean]) -> Self { - assert_eq!(bits.len(), 32); - - let mut value = Some(0u32); - for b in bits { - value.as_mut().map(|v| *v <<= 1); - - match b.get_value() { - Some(true) => { value.as_mut().map(|v| *v |= 1); }, - Some(false) => {}, - None => { value = None; } - } - } - - UInt32 { - value: value, - bits: bits.iter().rev().cloned().collect() - } - } - - - /// Turns this `UInt32` into its little-endian byte order representation. - pub fn into_bits(&self) -> Vec { - self.bits.clone() - } - - /// Converts a little-endian byte order representation of bits into a - /// `UInt32`. - pub fn from_bits(bits: &[Boolean]) -> Self - { - assert_eq!(bits.len(), 32); - - let new_bits = bits.to_vec(); - - let mut value = Some(0u32); - for b in new_bits.iter().rev() { - value.as_mut().map(|v| *v <<= 1); - - match b { - &Boolean::Constant(b) => { - if b { - value.as_mut().map(|v| *v |= 1); - } - }, - &Boolean::Is(ref b) => { - match b.get_value() { - Some(true) => { value.as_mut().map(|v| *v |= 1); }, - Some(false) => {}, - None => { value = None } - } - }, - &Boolean::Not(ref b) => { - match b.get_value() { - Some(false) => { value.as_mut().map(|v| *v |= 1); }, - Some(true) => {}, - None => { value = None } - } - } - } - } - - UInt32 { - value: value, - bits: new_bits - } - } - - pub fn rotr(&self, by: usize) -> Self { - let by = by % 32; - - let new_bits = self.bits.iter() - .skip(by) - .chain(self.bits.iter()) - .take(32) - .cloned() - .collect(); - - UInt32 { - bits: new_bits, - value: self.value.map(|v| v.rotate_right(by as u32)) - } - } - - pub fn shr(&self, by: usize) -> Self { - let by = by % 32; - - let fill = Boolean::constant(false); - - let new_bits = self.bits - .iter() // The bits are least significant first - .skip(by) // Skip the bits that will be lost during the shift - .chain(Some(&fill).into_iter().cycle()) // Rest will be zeros - .take(32) // Only 32 bits needed! - .cloned() - .collect(); - - UInt32 { - bits: new_bits, - value: self.value.map(|v| v >> by as u32) - } - } - - fn triop( - mut cs: CS, - a: &Self, - b: &Self, - c: &Self, - tri_fn: F, - circuit_fn: U - ) -> Result - where E: Engine, - CS: ConstraintSystem, - F: Fn(u32, u32, u32) -> u32, - U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result - { - let new_value = match (a.value, b.value, c.value) { - (Some(a), Some(b), Some(c)) => { - Some(tri_fn(a, b, c)) - }, - _ => None - }; - - let bits = a.bits.iter() - .zip(b.bits.iter()) - .zip(c.bits.iter()) - .enumerate() - .map(|(i, ((a, b), c))| circuit_fn(&mut cs, i, a, b, c)) - .collect::>()?; - - Ok(UInt32 { - bits: bits, - value: new_value - }) - } - - /// Compute the `maj` value (a and b) xor (a and c) xor (b and c) - /// during SHA256. - pub fn sha256_maj( - cs: CS, - a: &Self, - b: &Self, - c: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem - { - Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ (a & c) ^ (b & c), - |cs, i, a, b, c| { - Boolean::sha256_maj( - cs.namespace(|| format!("maj {}", i)), - a, - b, - c - ) - } - ) - } - - /// Compute the `ch` value `(a and b) xor ((not a) and c)` - /// during SHA256. - pub fn sha256_ch( - cs: CS, - a: &Self, - b: &Self, - c: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem - { - Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ ((!a) & c), - |cs, i, a, b, c| { - Boolean::sha256_ch( - cs.namespace(|| format!("ch {}", i)), - a, - b, - c - ) - } - ) - } - - /// XOR this `UInt32` with another `UInt32` - pub fn xor( - &self, - mut cs: CS, - other: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem - { - let new_value = match (self.value, other.value) { - (Some(a), Some(b)) => { - Some(a ^ b) - }, - _ => None - }; - - let bits = self.bits.iter() - .zip(other.bits.iter()) - .enumerate() - .map(|(i, (a, b))| { - Boolean::xor( - cs.namespace(|| format!("xor of bit {}", i)), - a, - b - ) - }) - .collect::>()?; - - Ok(UInt32 { - bits: bits, - value: new_value - }) - } - - /// Perform modular addition of several `UInt32` objects. - pub fn addmany( - mut cs: M, - operands: &[Self] - ) -> Result - where E: Engine, - CS: ConstraintSystem, - M: ConstraintSystem> - { - // Make some arbitrary bounds for ourselves to avoid overflows - // in the scalar field - assert!(E::Fr::NUM_BITS >= 64); - assert!(operands.len() >= 2); // Weird trivial cases that should never happen - assert!(operands.len() <= 10); - - // Compute the maximum value of the sum so we allocate enough bits for - // the result - let mut max_value = (operands.len() as u64) * (u32::max_value() as u64); - - // Keep track of the resulting value - let mut result_value = Some(0u64); - - // This is a linear combination that we will enforce to equal the - // output - let mut lc = LinearCombination::zero(); - - let mut all_constants = true; - - // Iterate over the operands - for op in operands { - // Accumulate the value - match op.value { - Some(val) => { - result_value.as_mut().map(|v| *v += val as u64); - }, - None => { - // If any of our operands have unknown value, we won't - // know the value of the result - result_value = None; - } - } - - // Iterate over each bit of the operand and add the operand to - // the linear combination - let mut coeff = E::Fr::one(); - for bit in &op.bits { - lc = lc + &bit.lc(CS::one(), coeff); - - all_constants &= bit.is_constant(); - - coeff.double(); - } - } - - // The value of the actual result is modulo 2^32 - let modular_value = result_value.map(|v| v as u32); - - if all_constants && modular_value.is_some() { - // We can just return a constant, rather than - // unpacking the result into allocated bits. - - return Ok(UInt32::constant(modular_value.unwrap())); - } - - // Storage area for the resulting bits - let mut result_bits = vec![]; - - // Linear combination representing the output, - // for comparison with the sum of the operands - let mut result_lc = LinearCombination::zero(); - - // Allocate each bit of the result - let mut coeff = E::Fr::one(); - let mut i = 0; - while max_value != 0 { - // Allocate the bit - let b = AllocatedBit::alloc( - cs.namespace(|| format!("result bit {}", i)), - result_value.map(|v| (v >> i) & 1 == 1) - )?; - - // Add this bit to the result combination - result_lc = result_lc + (coeff, b.get_variable()); - - result_bits.push(b.into()); - - max_value >>= 1; - i += 1; - coeff.double(); - } - - // Enforce equality between the sum and result - cs.get_root().enforce_equal(i, &lc, &result_lc); - - // Discard carry bits that we don't care about - result_bits.truncate(32); - - Ok(UInt32 { - bits: result_bits, - value: modular_value - }) - } -} - -#[cfg(test)] -mod test { - use rand::{XorShiftRng, SeedableRng, Rng}; - use ::circuit::boolean::{Boolean}; - use super::{UInt32}; - use pairing::bls12_381::{Bls12}; - use pairing::{Field}; - use ::circuit::test::*; - use bellman::{ConstraintSystem}; - use circuit::multieq::MultiEq; - - #[test] - fn test_uint32_from_bits_be() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); - - for _ in 0..1000 { - let mut v = (0..32).map(|_| Boolean::constant(rng.gen())).collect::>(); - - let b = UInt32::from_bits_be(&v); - - for (i, bit) in b.bits.iter().enumerate() { - match bit { - &Boolean::Constant(bit) => { - assert!(bit == ((b.value.unwrap() >> i) & 1 == 1)); - }, - _ => unreachable!() - } - } - - let expected_to_be_same = b.into_bits_be(); - - for x in v.iter().zip(expected_to_be_same.iter()) - { - match x { - (&Boolean::Constant(true), &Boolean::Constant(true)) => {}, - (&Boolean::Constant(false), &Boolean::Constant(false)) => {}, - _ => unreachable!() - } - } - } - } - - #[test] - fn test_uint32_from_bits() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); - - for _ in 0..1000 { - let mut v = (0..32).map(|_| Boolean::constant(rng.gen())).collect::>(); - - let b = UInt32::from_bits(&v); - - for (i, bit) in b.bits.iter().enumerate() { - match bit { - &Boolean::Constant(bit) => { - assert!(bit == ((b.value.unwrap() >> i) & 1 == 1)); - }, - _ => unreachable!() - } - } - - let expected_to_be_same = b.into_bits(); - - for x in v.iter().zip(expected_to_be_same.iter()) - { - match x { - (&Boolean::Constant(true), &Boolean::Constant(true)) => {}, - (&Boolean::Constant(false), &Boolean::Constant(false)) => {}, - _ => unreachable!() - } - } - } - } - - #[test] - fn test_uint32_xor() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); - - for _ in 0..1000 { - let mut cs = TestConstraintSystem::::new(); - - let a: u32 = rng.gen(); - let b: u32 = rng.gen(); - let c: u32 = rng.gen(); - - let mut expected = a ^ b ^ c; - - let a_bit = UInt32::alloc(cs.namespace(|| "a_bit"), Some(a)).unwrap(); - let b_bit = UInt32::constant(b); - let c_bit = UInt32::alloc(cs.namespace(|| "c_bit"), Some(c)).unwrap(); - - let r = a_bit.xor(cs.namespace(|| "first xor"), &b_bit).unwrap(); - let r = r.xor(cs.namespace(|| "second xor"), &c_bit).unwrap(); - - assert!(cs.is_satisfied()); - - assert!(r.value == Some(expected)); - - for b in r.bits.iter() { - match b { - &Boolean::Is(ref b) => { - assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, - &Boolean::Not(ref b) => { - assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, - &Boolean::Constant(b) => { - assert!(b == (expected & 1 == 1)); - } - } - - expected >>= 1; - } - } - } - - #[test] - fn test_uint32_addmany_constants() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let mut cs = TestConstraintSystem::::new(); - - let a: u32 = rng.gen(); - let b: u32 = rng.gen(); - let c: u32 = rng.gen(); - - let a_bit = UInt32::constant(a); - let b_bit = UInt32::constant(b); - let c_bit = UInt32::constant(c); - - let mut expected = a.wrapping_add(b).wrapping_add(c); - - let r = { - let mut cs = MultiEq::new(&mut cs); - let r = UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap(); - r - }; - - assert!(r.value == Some(expected)); - - for b in r.bits.iter() { - match b { - &Boolean::Is(_) => panic!(), - &Boolean::Not(_) => panic!(), - &Boolean::Constant(b) => { - assert!(b == (expected & 1 == 1)); - } - } - - expected >>= 1; - } - } - } - - #[test] - fn test_uint32_addmany() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let mut cs = TestConstraintSystem::::new(); - - let a: u32 = rng.gen(); - let b: u32 = rng.gen(); - let c: u32 = rng.gen(); - let d: u32 = rng.gen(); - - let mut expected = (a ^ b).wrapping_add(c).wrapping_add(d); - - let a_bit = UInt32::alloc(cs.namespace(|| "a_bit"), Some(a)).unwrap(); - let b_bit = UInt32::constant(b); - let c_bit = UInt32::constant(c); - let d_bit = UInt32::alloc(cs.namespace(|| "d_bit"), Some(d)).unwrap(); - - let r = a_bit.xor(cs.namespace(|| "xor"), &b_bit).unwrap(); - let r = { - let mut cs = MultiEq::new(&mut cs); - let r = UInt32::addmany(cs.namespace(|| "addition"), &[r, c_bit, d_bit]).unwrap(); - r - }; - - assert!(cs.is_satisfied()); - - assert!(r.value == Some(expected)); - - for b in r.bits.iter() { - match b { - &Boolean::Is(ref b) => { - assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, - &Boolean::Not(ref b) => { - assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, - &Boolean::Constant(_) => { - unreachable!() - } - } - - expected >>= 1; - } - - // Flip a bit and see if the addition constraint still works - if cs.get("addition/result bit 0/boolean").is_zero() { - cs.set("addition/result bit 0/boolean", Field::one()); - } else { - cs.set("addition/result bit 0/boolean", Field::zero()); - } - - assert!(!cs.is_satisfied()); - } - } - - #[test] - fn test_uint32_rotr() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let mut num = rng.gen(); - - let a = UInt32::constant(num); - - for i in 0..32 { - let b = a.rotr(i); - assert_eq!(a.bits.len(), b.bits.len()); - - assert!(b.value.unwrap() == num); - - let mut tmp = num; - for b in &b.bits { - match b { - &Boolean::Constant(b) => { - assert_eq!(b, tmp & 1 == 1); - }, - _ => unreachable!() - } - - tmp >>= 1; - } - - num = num.rotate_right(1); - } - } - - #[test] - fn test_uint32_shr() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..50 { - for i in 0..60 { - let num = rng.gen(); - let a = UInt32::constant(num).shr(i); - let b = UInt32::constant(num >> i); - - assert_eq!(a.value.unwrap(), num >> i); - - assert_eq!(a.bits.len(), b.bits.len()); - for (a, b) in a.bits.iter().zip(b.bits.iter()) { - assert_eq!(a.get_value().unwrap(), b.get_value().unwrap()); - } - } - } - } - - #[test] - fn test_uint32_sha256_maj() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); - - for _ in 0..1000 { - let mut cs = TestConstraintSystem::::new(); - - let a: u32 = rng.gen(); - let b: u32 = rng.gen(); - let c: u32 = rng.gen(); - - let mut expected = (a & b) ^ (a & c) ^ (b & c); - - let a_bit = UInt32::alloc(cs.namespace(|| "a_bit"), Some(a)).unwrap(); - let b_bit = UInt32::constant(b); - let c_bit = UInt32::alloc(cs.namespace(|| "c_bit"), Some(c)).unwrap(); - - let r = UInt32::sha256_maj(&mut cs, &a_bit, &b_bit, &c_bit).unwrap(); - - assert!(cs.is_satisfied()); - - assert!(r.value == Some(expected)); - - for b in r.bits.iter() { - match b { - &Boolean::Is(ref b) => { - assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, - &Boolean::Not(ref b) => { - assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, - &Boolean::Constant(b) => { - assert!(b == (expected & 1 == 1)); - } - } - - expected >>= 1; - } - } - } - - #[test] - fn test_uint32_sha256_ch() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); - - for _ in 0..1000 { - let mut cs = TestConstraintSystem::::new(); - - let a: u32 = rng.gen(); - let b: u32 = rng.gen(); - let c: u32 = rng.gen(); - - let mut expected = (a & b) ^ ((!a) & c); - - let a_bit = UInt32::alloc(cs.namespace(|| "a_bit"), Some(a)).unwrap(); - let b_bit = UInt32::constant(b); - let c_bit = UInt32::alloc(cs.namespace(|| "c_bit"), Some(c)).unwrap(); - - let r = UInt32::sha256_ch(&mut cs, &a_bit, &b_bit, &c_bit).unwrap(); - - assert!(cs.is_satisfied()); - - assert!(r.value == Some(expected)); - - for b in r.bits.iter() { - match b { - &Boolean::Is(ref b) => { - assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, - &Boolean::Not(ref b) => { - assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, - &Boolean::Constant(b) => { - assert!(b == (expected & 1 == 1)); - } - } - - expected >>= 1; - } - } - } -} diff --git a/sapling-crypto/src/constants.rs b/sapling-crypto/src/constants.rs deleted file mode 100644 index dfdd36f..0000000 --- a/sapling-crypto/src/constants.rs +++ /dev/null @@ -1,40 +0,0 @@ -/// First 64 bytes of the BLAKE2s input during group hash. -/// This is chosen to be some random string that we couldn't have anticipated when we designed -/// the algorithm, for rigidity purposes. -/// We deliberately use an ASCII hex string of 32 bytes here. -pub const GH_FIRST_BLOCK: &'static [u8; 64] - = b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0"; - -// BLAKE2s invocation personalizations -/// BLAKE2s Personalization for CRH^ivk = BLAKE2s(ak | nk) -pub const CRH_IVK_PERSONALIZATION: &'static [u8; 8] - = b"Zcashivk"; - -/// BLAKE2s Personalization for PRF^nf = BLAKE2s(nk | rho) -pub const PRF_NF_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_nf"; - -// Group hash personalizations -/// BLAKE2s Personalization for Pedersen hash generators. -pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_PH"; - -/// BLAKE2s Personalization for the group hash for key diversification -pub const KEY_DIVERSIFICATION_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_gd"; - -/// BLAKE2s Personalization for the spending key base point -pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_G_"; - -/// BLAKE2s Personalization for the proof generation key base point -pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_H_"; - -/// BLAKE2s Personalization for the value commitment generator for the value -pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_cv"; - -/// BLAKE2s Personalization for the nullifier position generator (for computing rho) -pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_J_"; diff --git a/sapling-crypto/src/group_hash.rs b/sapling-crypto/src/group_hash.rs deleted file mode 100644 index 25e65f9..0000000 --- a/sapling-crypto/src/group_hash.rs +++ /dev/null @@ -1,46 +0,0 @@ -use jubjub::{ - JubjubEngine, - PrimeOrder, - edwards -}; - -use pairing::{ - PrimeField -}; - -use blake2_rfc::blake2s::Blake2s; -use constants; - -/// Produces a random point in the Jubjub curve. -/// The point is guaranteed to be prime order -/// and not the identity. -pub fn group_hash( - tag: &[u8], - personalization: &[u8], - params: &E::Params -) -> Option> -{ - assert_eq!(personalization.len(), 8); - - // Check to see that scalar field is 255 bits - assert!(E::Fr::NUM_BITS == 255); - - let mut h = Blake2s::with_params(32, &[], &[], personalization); - h.update(constants::GH_FIRST_BLOCK); - h.update(tag); - let h = h.finalize().as_ref().to_vec(); - assert!(h.len() == 32); - - match edwards::Point::::read(&h[..], params) { - Ok(p) => { - let p = p.mul_by_cofactor(params); - - if p != edwards::Point::zero() { - Some(p) - } else { - None - } - }, - Err(_) => None - } -} diff --git a/sapling-crypto/src/jubjub/edwards.rs b/sapling-crypto/src/jubjub/edwards.rs deleted file mode 100644 index e91455c..0000000 --- a/sapling-crypto/src/jubjub/edwards.rs +++ /dev/null @@ -1,523 +0,0 @@ -use pairing::{ - Field, - SqrtField, - PrimeField, - PrimeFieldRepr, - BitIterator -}; - -use super::{ - JubjubEngine, - JubjubParams, - Unknown, - PrimeOrder, - montgomery -}; - -use rand::{ - Rng -}; - -use std::marker::PhantomData; - -use std::io::{ - self, - Write, - Read -}; - -// Represents the affine point (X/Z, Y/Z) via the extended -// twisted Edwards coordinates. -// -// See "Twisted Edwards Curves Revisited" -// Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson -pub struct Point { - x: E::Fr, - y: E::Fr, - t: E::Fr, - z: E::Fr, - _marker: PhantomData -} - -fn convert_subgroup(from: &Point) -> Point -{ - Point { - x: from.x, - y: from.y, - t: from.t, - z: from.z, - _marker: PhantomData - } -} - -impl From> for Point -{ - fn from(p: Point) -> Point - { - convert_subgroup(&p) - } -} - -impl Clone for Point -{ - fn clone(&self) -> Self { - convert_subgroup(self) - } -} - -impl PartialEq for Point { - fn eq(&self, other: &Point) -> bool { - // p1 = (x1/z1, y1/z1) - // p2 = (x2/z2, y2/z2) - // Deciding that these two points are equal is a matter of - // determining that x1/z1 = x2/z2, or equivalently that - // x1*z2 = x2*z1, and similarly for y. - - let mut x1 = self.x; - x1.mul_assign(&other.z); - - let mut y1 = self.y; - y1.mul_assign(&other.z); - - let mut x2 = other.x; - x2.mul_assign(&self.z); - - let mut y2 = other.y; - y2.mul_assign(&self.z); - - x1 == x2 && y1 == y2 - } -} - -impl Point { - pub fn read( - reader: R, - params: &E::Params - ) -> io::Result - { - let mut y_repr = ::Repr::default(); - y_repr.read_le(reader)?; - - let x_sign = (y_repr.as_ref()[3] >> 63) == 1; - y_repr.as_mut()[3] &= 0x7fffffffffffffff; - - match E::Fr::from_repr(y_repr) { - Ok(y) => { - match Self::get_for_y(y, x_sign, params) { - Some(p) => Ok(p), - None => { - Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve")) - } - } - }, - Err(_) => { - Err(io::Error::new(io::ErrorKind::InvalidInput, "y is not in field")) - } - } - } - - pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> Option - { - // Given a y on the curve, x^2 = (y^2 - 1) / (dy^2 + 1) - // This is defined for all valid y-coordinates, - // as dy^2 + 1 = 0 has no solution in Fr. - - // tmp1 = y^2 - let mut tmp1 = y; - tmp1.square(); - - // tmp2 = (y^2 * d) + 1 - let mut tmp2 = tmp1; - tmp2.mul_assign(params.edwards_d()); - tmp2.add_assign(&E::Fr::one()); - - // tmp1 = y^2 - 1 - tmp1.sub_assign(&E::Fr::one()); - - match tmp2.inverse() { - Some(tmp2) => { - // tmp1 = (y^2 - 1) / (dy^2 + 1) - tmp1.mul_assign(&tmp2); - - match tmp1.sqrt() { - Some(mut x) => { - if x.into_repr().is_odd() != sign { - x.negate(); - } - - let mut t = x; - t.mul_assign(&y); - - Some(Point { - x: x, - y: y, - t: t, - z: E::Fr::one(), - _marker: PhantomData - }) - }, - None => None - } - }, - None => None - } - } - - /// This guarantees the point is in the prime order subgroup - #[must_use] - pub fn mul_by_cofactor(&self, params: &E::Params) -> Point - { - let tmp = self.double(params) - .double(params) - .double(params); - - convert_subgroup(&tmp) - } - - pub fn rand(rng: &mut R, params: &E::Params) -> Self - { - loop { - let y: E::Fr = rng.gen(); - - if let Some(p) = Self::get_for_y(y, rng.gen(), params) { - return p; - } - } - } -} - -impl Point { - pub fn write( - &self, - writer: W - ) -> io::Result<()> - { - let (x, y) = self.into_xy(); - - assert_eq!(E::Fr::NUM_BITS, 255); - - let x_repr = x.into_repr(); - let mut y_repr = y.into_repr(); - if x_repr.is_odd() { - y_repr.as_mut()[3] |= 0x8000000000000000u64; - } - - y_repr.write_le(writer) - } - - /// Convert from a Montgomery point - pub fn from_montgomery( - m: &montgomery::Point, - params: &E::Params - ) -> Self - { - match m.into_xy() { - None => { - // Map the point at infinity to the neutral element. - Point::zero() - }, - Some((x, y)) => { - // The map from a Montgomery curve is defined as: - // (x, y) -> (u, v) where - // u = x / y - // v = (x - 1) / (x + 1) - // - // This map is not defined for y = 0 and x = -1. - // - // y = 0 is a valid point only for x = 0: - // y^2 = x^3 + A.x^2 + x - // 0 = x^3 + A.x^2 + x - // 0 = x(x^2 + A.x + 1) - // We have: x = 0 OR x^2 + A.x + 1 = 0 - // x^2 + A.x + 1 = 0 - // (2.x + A)^2 = A^2 - 4 (Complete the square.) - // The left hand side is a square, and so if A^2 - 4 - // is nonsquare, there is no solution. Indeed, A^2 - 4 - // is nonsquare. - // - // (0, 0) is a point of order 2, and so we map it to - // (0, -1) in the twisted Edwards curve, which is the - // only point of order 2 that is not the neutral element. - if y.is_zero() { - // This must be the point (0, 0) as above. - let mut neg1 = E::Fr::one(); - neg1.negate(); - - Point { - x: E::Fr::zero(), - y: neg1, - t: E::Fr::zero(), - z: E::Fr::one(), - _marker: PhantomData - } - } else { - // Otherwise, as stated above, the mapping is still - // not defined at x = -1. However, x = -1 is not - // on the curve when A - 2 is nonsquare: - // y^2 = x^3 + A.x^2 + x - // y^2 = (-1) + A + (-1) - // y^2 = A - 2 - // Indeed, A - 2 is nonsquare. - // - // We need to map into (projective) extended twisted - // Edwards coordinates (X, Y, T, Z) which represents - // the point (X/Z, Y/Z) with Z nonzero and T = XY/Z. - // - // Thus, we compute... - // - // u = x(x + 1) - // v = y(x - 1) - // t = x(x - 1) - // z = y(x + 1) (Cannot be nonzero, as above.) - // - // ... which represents the point ( x / y , (x - 1) / (x + 1) ) - // as required by the mapping and preserves the property of - // the auxiliary coordinate t. - // - // We need to scale the coordinate, so u and t will have - // an extra factor s. - - // u = xs - let mut u = x; - u.mul_assign(params.scale()); - - // v = x - 1 - let mut v = x; - v.sub_assign(&E::Fr::one()); - - // t = xs(x - 1) - let mut t = u; - t.mul_assign(&v); - - // z = (x + 1) - let mut z = x; - z.add_assign(&E::Fr::one()); - - // u = xs(x + 1) - u.mul_assign(&z); - - // z = y(x + 1) - z.mul_assign(&y); - - // v = y(x - 1) - v.mul_assign(&y); - - Point { - x: u, - y: v, - t: t, - z: z, - _marker: PhantomData - } - } - } - } - } - - /// Attempts to cast this as a prime order element, failing if it's - /// not in the prime order subgroup. - pub fn as_prime_order(&self, params: &E::Params) -> Option> { - if self.mul(E::Fs::char(), params) == Point::zero() { - Some(convert_subgroup(self)) - } else { - None - } - } - - pub fn zero() -> Self { - Point { - x: E::Fr::zero(), - y: E::Fr::one(), - t: E::Fr::zero(), - z: E::Fr::one(), - _marker: PhantomData - } - } - - pub fn into_xy(&self) -> (E::Fr, E::Fr) - { - let zinv = self.z.inverse().unwrap(); - - let mut x = self.x; - x.mul_assign(&zinv); - - let mut y = self.y; - y.mul_assign(&zinv); - - (x, y) - } - - #[must_use] - pub fn negate(&self) -> Self { - let mut p = self.clone(); - - p.x.negate(); - p.t.negate(); - - p - } - - #[must_use] - pub fn double(&self, _: &E::Params) -> Self { - // See "Twisted Edwards Curves Revisited" - // Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson - // Section 3.3 - // http://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd - - // A = X1^2 - let mut a = self.x; - a.square(); - - // B = Y1^2 - let mut b = self.y; - b.square(); - - // C = 2*Z1^2 - let mut c = self.z; - c.square(); - c.double(); - - // D = a*A - // = -A - let mut d = a; - d.negate(); - - // E = (X1+Y1)^2 - A - B - let mut e = self.x; - e.add_assign(&self.y); - e.square(); - e.add_assign(&d); // -A = D - e.sub_assign(&b); - - // G = D+B - let mut g = d; - g.add_assign(&b); - - // F = G-C - let mut f = g; - f.sub_assign(&c); - - // H = D-B - let mut h = d; - h.sub_assign(&b); - - // X3 = E*F - let mut x3 = e; - x3.mul_assign(&f); - - // Y3 = G*H - let mut y3 = g; - y3.mul_assign(&h); - - // T3 = E*H - let mut t3 = e; - t3.mul_assign(&h); - - // Z3 = F*G - let mut z3 = f; - z3.mul_assign(&g); - - Point { - x: x3, - y: y3, - t: t3, - z: z3, - _marker: PhantomData - } - } - - #[must_use] - pub fn add(&self, other: &Self, params: &E::Params) -> Self - { - // See "Twisted Edwards Curves Revisited" - // Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson - // 3.1 Unified Addition in E^e - - // A = x1 * x2 - let mut a = self.x; - a.mul_assign(&other.x); - - // B = y1 * y2 - let mut b = self.y; - b.mul_assign(&other.y); - - // C = d * t1 * t2 - let mut c = params.edwards_d().clone(); - c.mul_assign(&self.t); - c.mul_assign(&other.t); - - // D = z1 * z2 - let mut d = self.z; - d.mul_assign(&other.z); - - // H = B - aA - // = B + A - let mut h = b; - h.add_assign(&a); - - // E = (x1 + y1) * (x2 + y2) - A - B - // = (x1 + y1) * (x2 + y2) - H - let mut e = self.x; - e.add_assign(&self.y); - { - let mut tmp = other.x; - tmp.add_assign(&other.y); - e.mul_assign(&tmp); - } - e.sub_assign(&h); - - // F = D - C - let mut f = d; - f.sub_assign(&c); - - // G = D + C - let mut g = d; - g.add_assign(&c); - - // x3 = E * F - let mut x3 = e; - x3.mul_assign(&f); - - // y3 = G * H - let mut y3 = g; - y3.mul_assign(&h); - - // t3 = E * H - let mut t3 = e; - t3.mul_assign(&h); - - // z3 = F * G - let mut z3 = f; - z3.mul_assign(&g); - - Point { - x: x3, - y: y3, - t: t3, - z: z3, - _marker: PhantomData - } - } - - #[must_use] - pub fn mul::Repr>>( - &self, - scalar: S, - params: &E::Params - ) -> Self - { - // Standard double-and-add scalar multiplication - - let mut res = Self::zero(); - - for b in BitIterator::new(scalar.into()) { - res = res.double(params); - - if b { - res = res.add(self, params); - } - } - - res - } -} diff --git a/sapling-crypto/src/jubjub/fs.rs b/sapling-crypto/src/jubjub/fs.rs deleted file mode 100644 index eb10e65..0000000 --- a/sapling-crypto/src/jubjub/fs.rs +++ /dev/null @@ -1,1232 +0,0 @@ -use byteorder::{ByteOrder, LittleEndian}; -use pairing::{BitIterator, Field, PrimeField, SqrtField, PrimeFieldRepr, PrimeFieldDecodingError, LegendreSymbol}; -use pairing::LegendreSymbol::*; -use pairing::{adc, sbb, mac_with_carry}; - -use super::ToUniform; - -// s = 6554484396890773809930967563523245729705921265872317281365359162392183254199 -const MODULUS: FsRepr = FsRepr([0xd0970e5ed6f72cb7, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9]); - -// The number of bits needed to represent the modulus. -const MODULUS_BITS: u32 = 252; - -// The number of bits that must be shaved from the beginning of -// the representation when randomly sampling. -const REPR_SHAVE_BITS: u32 = 4; - -// R = 2**256 % s -const R: FsRepr = FsRepr([0x25f80bb3b99607d9, 0xf315d62f66b6e750, 0x932514eeeb8814f4, 0x9a6fc6f479155c6]); - -// R2 = R^2 % s -const R2: FsRepr = FsRepr([0x67719aa495e57731, 0x51b0cef09ce3fc26, 0x69dab7fac026e9a5, 0x4f6547b8d127688]); - -// INV = -(s^{-1} mod 2^64) mod s -const INV: u64 = 0x1ba3a358ef788ef9; - -// GENERATOR = 6 (multiplicative generator of r-1 order, that is also quadratic nonresidue) -const GENERATOR: FsRepr = FsRepr([0x720b1b19d49ea8f1, 0xbf4aa36101f13a58, 0x5fa8cc968193ccbb, 0xe70cbdc7dccf3ac]); - -// 2^S * t = MODULUS - 1 with t odd -const S: u32 = 1; - -// 2^S root of unity computed by GENERATOR^t -const ROOT_OF_UNITY: FsRepr = FsRepr([0xaa9f02ab1d6124de, 0xb3524a6466112932, 0x7342261215ac260b, 0x4d6b87b1da259e2]); - -// -((2**256) mod s) mod s -const NEGATIVE_ONE: Fs = Fs(FsRepr([0xaa9f02ab1d6124de, 0xb3524a6466112932, 0x7342261215ac260b, 0x4d6b87b1da259e2])); - -/// This is the underlying representation of an element of `Fs`. -#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)] -pub struct FsRepr(pub [u64; 4]); - -impl ::rand::Rand for FsRepr { - #[inline(always)] - fn rand(rng: &mut R) -> Self { - FsRepr(rng.gen()) - } -} - -impl ::std::fmt::Display for FsRepr -{ - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - try!(write!(f, "0x")); - for i in self.0.iter().rev() { - try!(write!(f, "{:016x}", *i)); - } - - Ok(()) - } -} - -impl AsRef<[u64]> for FsRepr { - #[inline(always)] - fn as_ref(&self) -> &[u64] { - &self.0 - } -} - -impl AsMut<[u64]> for FsRepr { - #[inline(always)] - fn as_mut(&mut self) -> &mut [u64] { - &mut self.0 - } -} - -impl From for FsRepr { - #[inline(always)] - fn from(val: u64) -> FsRepr { - let mut repr = Self::default(); - repr.0[0] = val; - repr - } -} - -impl Ord for FsRepr { - #[inline(always)] - fn cmp(&self, other: &FsRepr) -> ::std::cmp::Ordering { - for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) { - if a < b { - return ::std::cmp::Ordering::Less - } else if a > b { - return ::std::cmp::Ordering::Greater - } - } - - ::std::cmp::Ordering::Equal - } -} - -impl PartialOrd for FsRepr { - #[inline(always)] - fn partial_cmp(&self, other: &FsRepr) -> Option<::std::cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl PrimeFieldRepr for FsRepr { - #[inline(always)] - fn is_odd(&self) -> bool { - self.0[0] & 1 == 1 - } - - #[inline(always)] - fn is_even(&self) -> bool { - !self.is_odd() - } - - #[inline(always)] - fn is_zero(&self) -> bool { - self.0.iter().all(|&e| e == 0) - } - - #[inline(always)] - fn shr(&mut self, mut n: u32) { - if n >= 64 * 4 { - *self = Self::from(0); - return; - } - - while n >= 64 { - let mut t = 0; - for i in self.0.iter_mut().rev() { - ::std::mem::swap(&mut t, i); - } - n -= 64; - } - - if n > 0 { - let mut t = 0; - for i in self.0.iter_mut().rev() { - let t2 = *i << (64 - n); - *i >>= n; - *i |= t; - t = t2; - } - } - } - - #[inline(always)] - fn div2(&mut self) { - let mut t = 0; - for i in self.0.iter_mut().rev() { - let t2 = *i << 63; - *i >>= 1; - *i |= t; - t = t2; - } - } - - #[inline(always)] - fn mul2(&mut self) { - let mut last = 0; - for i in &mut self.0 { - let tmp = *i >> 63; - *i <<= 1; - *i |= last; - last = tmp; - } - } - - #[inline(always)] - fn shl(&mut self, mut n: u32) { - if n >= 64 * 4 { - *self = Self::from(0); - return; - } - - while n >= 64 { - let mut t = 0; - for i in &mut self.0 { - ::std::mem::swap(&mut t, i); - } - n -= 64; - } - - if n > 0 { - let mut t = 0; - for i in &mut self.0 { - let t2 = *i >> (64 - n); - *i <<= n; - *i |= t; - t = t2; - } - } - } - - #[inline(always)] - fn num_bits(&self) -> u32 { - let mut ret = (4 as u32) * 64; - for i in self.0.iter().rev() { - let leading = i.leading_zeros(); - ret -= leading; - if leading != 64 { - break; - } - } - - ret - } - - #[inline(always)] - fn add_nocarry(&mut self, other: &FsRepr) { - let mut carry = 0; - - for (a, b) in self.0.iter_mut().zip(other.0.iter()) { - *a = adc(*a, *b, &mut carry); - } - } - - #[inline(always)] - fn sub_noborrow(&mut self, other: &FsRepr) { - let mut borrow = 0; - - for (a, b) in self.0.iter_mut().zip(other.0.iter()) { - *a = sbb(*a, *b, &mut borrow); - } - } -} - -/// This is an element of the scalar field of the Jubjub curve. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Fs(FsRepr); - -impl ::std::fmt::Display for Fs -{ - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "Fs({})", self.into_repr()) - } -} - -impl ::rand::Rand for Fs { - fn rand(rng: &mut R) -> Self { - loop { - let mut tmp = Fs(FsRepr::rand(rng)); - - // Mask away the unused bits at the beginning. - tmp.0.as_mut()[3] &= 0xffffffffffffffff >> REPR_SHAVE_BITS; - - if tmp.is_valid() { - return tmp - } - } - } -} - -impl From for FsRepr { - fn from(e: Fs) -> FsRepr { - e.into_repr() - } -} - -impl PrimeField for Fs { - type Repr = FsRepr; - - fn from_repr(r: FsRepr) -> Result { - let mut r = Fs(r); - if r.is_valid() { - r.mul_assign(&Fs(R2)); - - Ok(r) - } else { - Err(PrimeFieldDecodingError::NotInField(format!("{}", r.0))) - } - } - - fn into_repr(&self) -> FsRepr { - let mut r = *self; - r.mont_reduce((self.0).0[0], (self.0).0[1], - (self.0).0[2], (self.0).0[3], - 0, 0, 0, 0); - r.0 - } - - fn char() -> FsRepr { - MODULUS - } - - const NUM_BITS: u32 = MODULUS_BITS; - - const CAPACITY: u32 = Self::NUM_BITS - 1; - - fn multiplicative_generator() -> Self { - Fs(GENERATOR) - } - - const S: u32 = S; - - fn root_of_unity() -> Self { - Fs(ROOT_OF_UNITY) - } -} - -impl Field for Fs { - #[inline] - fn zero() -> Self { - Fs(FsRepr::from(0)) - } - - #[inline] - fn one() -> Self { - Fs(R) - } - - #[inline] - fn is_zero(&self) -> bool { - self.0.is_zero() - } - - #[inline] - fn add_assign(&mut self, other: &Fs) { - // This cannot exceed the backing capacity. - self.0.add_nocarry(&other.0); - - // However, it may need to be reduced. - self.reduce(); - } - - #[inline] - fn double(&mut self) { - // This cannot exceed the backing capacity. - self.0.mul2(); - - // However, it may need to be reduced. - self.reduce(); - } - - #[inline] - fn sub_assign(&mut self, other: &Fs) { - // If `other` is larger than `self`, we'll need to add the modulus to self first. - if other.0 > self.0 { - self.0.add_nocarry(&MODULUS); - } - - self.0.sub_noborrow(&other.0); - } - - #[inline] - fn negate(&mut self) { - if !self.is_zero() { - let mut tmp = MODULUS; - tmp.sub_noborrow(&self.0); - self.0 = tmp; - } - } - - fn inverse(&self) -> Option { - if self.is_zero() { - None - } else { - // Guajardo Kumar Paar Pelzl - // Efficient Software-Implementation of Finite Fields with Applications to Cryptography - // Algorithm 16 (BEA for Inversion in Fp) - - let one = FsRepr::from(1); - - let mut u = self.0; - let mut v = MODULUS; - let mut b = Fs(R2); // Avoids unnecessary reduction step. - let mut c = Self::zero(); - - while u != one && v != one { - while u.is_even() { - u.div2(); - - if b.0.is_even() { - b.0.div2(); - } else { - b.0.add_nocarry(&MODULUS); - b.0.div2(); - } - } - - while v.is_even() { - v.div2(); - - if c.0.is_even() { - c.0.div2(); - } else { - c.0.add_nocarry(&MODULUS); - c.0.div2(); - } - } - - if v < u { - u.sub_noborrow(&v); - b.sub_assign(&c); - } else { - v.sub_noborrow(&u); - c.sub_assign(&b); - } - } - - if u == one { - Some(b) - } else { - Some(c) - } - } - } - - #[inline(always)] - fn frobenius_map(&mut self, _: usize) { - // This has no effect in a prime field. - } - - #[inline] - fn mul_assign(&mut self, other: &Fs) - { - let mut carry = 0; - let r0 = mac_with_carry(0, (self.0).0[0], (other.0).0[0], &mut carry); - let r1 = mac_with_carry(0, (self.0).0[0], (other.0).0[1], &mut carry); - let r2 = mac_with_carry(0, (self.0).0[0], (other.0).0[2], &mut carry); - let r3 = mac_with_carry(0, (self.0).0[0], (other.0).0[3], &mut carry); - let r4 = carry; - let mut carry = 0; - let r1 = mac_with_carry(r1, (self.0).0[1], (other.0).0[0], &mut carry); - let r2 = mac_with_carry(r2, (self.0).0[1], (other.0).0[1], &mut carry); - let r3 = mac_with_carry(r3, (self.0).0[1], (other.0).0[2], &mut carry); - let r4 = mac_with_carry(r4, (self.0).0[1], (other.0).0[3], &mut carry); - let r5 = carry; - let mut carry = 0; - let r2 = mac_with_carry(r2, (self.0).0[2], (other.0).0[0], &mut carry); - let r3 = mac_with_carry(r3, (self.0).0[2], (other.0).0[1], &mut carry); - let r4 = mac_with_carry(r4, (self.0).0[2], (other.0).0[2], &mut carry); - let r5 = mac_with_carry(r5, (self.0).0[2], (other.0).0[3], &mut carry); - let r6 = carry; - let mut carry = 0; - let r3 = mac_with_carry(r3, (self.0).0[3], (other.0).0[0], &mut carry); - let r4 = mac_with_carry(r4, (self.0).0[3], (other.0).0[1], &mut carry); - let r5 = mac_with_carry(r5, (self.0).0[3], (other.0).0[2], &mut carry); - let r6 = mac_with_carry(r6, (self.0).0[3], (other.0).0[3], &mut carry); - let r7 = carry; - self.mont_reduce(r0, r1, r2, r3, r4, r5, r6, r7); - } - - #[inline] - fn square(&mut self) - { - let mut carry = 0; - let r1 = mac_with_carry(0, (self.0).0[0], (self.0).0[1], &mut carry); - let r2 = mac_with_carry(0, (self.0).0[0], (self.0).0[2], &mut carry); - let r3 = mac_with_carry(0, (self.0).0[0], (self.0).0[3], &mut carry); - let r4 = carry; - let mut carry = 0; - let r3 = mac_with_carry(r3, (self.0).0[1], (self.0).0[2], &mut carry); - let r4 = mac_with_carry(r4, (self.0).0[1], (self.0).0[3], &mut carry); - let r5 = carry; - let mut carry = 0; - let r5 = mac_with_carry(r5, (self.0).0[2], (self.0).0[3], &mut carry); - let r6 = carry; - - let r7 = r6 >> 63; - let r6 = (r6 << 1) | (r5 >> 63); - let r5 = (r5 << 1) | (r4 >> 63); - let r4 = (r4 << 1) | (r3 >> 63); - let r3 = (r3 << 1) | (r2 >> 63); - let r2 = (r2 << 1) | (r1 >> 63); - let r1 = r1 << 1; - - let mut carry = 0; - let r0 = mac_with_carry(0, (self.0).0[0], (self.0).0[0], &mut carry); - let r1 = adc(r1, 0, &mut carry); - let r2 = mac_with_carry(r2, (self.0).0[1], (self.0).0[1], &mut carry); - let r3 = adc(r3, 0, &mut carry); - let r4 = mac_with_carry(r4, (self.0).0[2], (self.0).0[2], &mut carry); - let r5 = adc(r5, 0, &mut carry); - let r6 = mac_with_carry(r6, (self.0).0[3], (self.0).0[3], &mut carry); - let r7 = adc(r7, 0, &mut carry); - self.mont_reduce(r0, r1, r2, r3, r4, r5, r6, r7); - } -} - -impl Fs { - /// Determines if the element is really in the field. This is only used - /// internally. - #[inline(always)] - fn is_valid(&self) -> bool { - self.0 < MODULUS - } - - /// Subtracts the modulus from this element if this element is not in the - /// field. Only used internally. - #[inline(always)] - fn reduce(&mut self) { - if !self.is_valid() { - self.0.sub_noborrow(&MODULUS); - } - } - - #[inline(always)] - fn mont_reduce( - &mut self, - r0: u64, - mut r1: u64, - mut r2: u64, - mut r3: u64, - mut r4: u64, - mut r5: u64, - mut r6: u64, - mut r7: u64 - ) - { - // The Montgomery reduction here is based on Algorithm 14.32 in - // Handbook of Applied Cryptography - // . - - let k = r0.wrapping_mul(INV); - let mut carry = 0; - mac_with_carry(r0, k, MODULUS.0[0], &mut carry); - r1 = mac_with_carry(r1, k, MODULUS.0[1], &mut carry); - r2 = mac_with_carry(r2, k, MODULUS.0[2], &mut carry); - r3 = mac_with_carry(r3, k, MODULUS.0[3], &mut carry); - r4 = adc(r4, 0, &mut carry); - let carry2 = carry; - let k = r1.wrapping_mul(INV); - let mut carry = 0; - mac_with_carry(r1, k, MODULUS.0[0], &mut carry); - r2 = mac_with_carry(r2, k, MODULUS.0[1], &mut carry); - r3 = mac_with_carry(r3, k, MODULUS.0[2], &mut carry); - r4 = mac_with_carry(r4, k, MODULUS.0[3], &mut carry); - r5 = adc(r5, carry2, &mut carry); - let carry2 = carry; - let k = r2.wrapping_mul(INV); - let mut carry = 0; - mac_with_carry(r2, k, MODULUS.0[0], &mut carry); - r3 = mac_with_carry(r3, k, MODULUS.0[1], &mut carry); - r4 = mac_with_carry(r4, k, MODULUS.0[2], &mut carry); - r5 = mac_with_carry(r5, k, MODULUS.0[3], &mut carry); - r6 = adc(r6, carry2, &mut carry); - let carry2 = carry; - let k = r3.wrapping_mul(INV); - let mut carry = 0; - mac_with_carry(r3, k, MODULUS.0[0], &mut carry); - r4 = mac_with_carry(r4, k, MODULUS.0[1], &mut carry); - r5 = mac_with_carry(r5, k, MODULUS.0[2], &mut carry); - r6 = mac_with_carry(r6, k, MODULUS.0[3], &mut carry); - r7 = adc(r7, carry2, &mut carry); - (self.0).0[0] = r4; - (self.0).0[1] = r5; - (self.0).0[2] = r6; - (self.0).0[3] = r7; - self.reduce(); - } - - fn mul_bits>(&self, bits: BitIterator) -> Self { - let mut res = Self::zero(); - for bit in bits { - res.double(); - - if bit { - res.add_assign(self) - } - } - res - } -} - -impl ToUniform for Fs { - /// Convert a little endian byte string into a uniform - /// field element. The number is reduced mod s. The caller - /// is responsible for ensuring the input is 64 bytes of - /// Random Oracle output. - fn to_uniform(digest: &[u8]) -> Self { - assert_eq!(digest.len(), 64); - let mut repr: [u64; 8] = [0; 8]; - LittleEndian::read_u64_into(digest, &mut repr); - Self::one().mul_bits(BitIterator::new(repr)) - } -} - -impl SqrtField for Fs { - - fn legendre(&self) -> LegendreSymbol { - // s = self^((s - 1) // 2) - let s = self.pow([0x684b872f6b7b965b, 0x53341049e6640841, 0x83339d80809a1d80, 0x73eda753299d7d4]); - if s == Self::zero() { Zero } - else if s == Self::one() { QuadraticResidue } - else { QuadraticNonResidue } - } - - fn sqrt(&self) -> Option { - // Shank's algorithm for s mod 4 = 3 - // https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2) - - // a1 = self^((s - 3) // 4) - let mut a1 = self.pow([0xb425c397b5bdcb2d, 0x299a0824f3320420, 0x4199cec0404d0ec0, 0x39f6d3a994cebea]); - let mut a0 = a1; - a0.square(); - a0.mul_assign(self); - - if a0 == NEGATIVE_ONE - { - None - } - else - { - a1.mul_assign(self); - Some(a1) - } - } -} - - -#[test] -fn test_neg_one() { - let mut o = Fs::one(); - o.negate(); - - assert_eq!(NEGATIVE_ONE, o); -} - -#[cfg(test)] -use rand::{SeedableRng, XorShiftRng, Rand}; - -#[test] -fn test_fs_repr_ordering() { - fn assert_equality(a: FsRepr, b: FsRepr) { - assert_eq!(a, b); - assert!(a.cmp(&b) == ::std::cmp::Ordering::Equal); - } - - fn assert_lt(a: FsRepr, b: FsRepr) { - assert!(a < b); - assert!(b > a); - } - - assert_equality(FsRepr([9999, 9999, 9999, 9999]), FsRepr([9999, 9999, 9999, 9999])); - assert_equality(FsRepr([9999, 9998, 9999, 9999]), FsRepr([9999, 9998, 9999, 9999])); - assert_equality(FsRepr([9999, 9999, 9999, 9997]), FsRepr([9999, 9999, 9999, 9997])); - assert_lt(FsRepr([9999, 9997, 9999, 9998]), FsRepr([9999, 9997, 9999, 9999])); - assert_lt(FsRepr([9999, 9997, 9998, 9999]), FsRepr([9999, 9997, 9999, 9999])); - assert_lt(FsRepr([9, 9999, 9999, 9997]), FsRepr([9999, 9999, 9999, 9997])); -} - -#[test] -fn test_fs_repr_from() { - assert_eq!(FsRepr::from(100), FsRepr([100, 0, 0, 0])); -} - -#[test] -fn test_fs_repr_is_odd() { - assert!(!FsRepr::from(0).is_odd()); - assert!(FsRepr::from(0).is_even()); - assert!(FsRepr::from(1).is_odd()); - assert!(!FsRepr::from(1).is_even()); - assert!(!FsRepr::from(324834872).is_odd()); - assert!(FsRepr::from(324834872).is_even()); - assert!(FsRepr::from(324834873).is_odd()); - assert!(!FsRepr::from(324834873).is_even()); -} - -#[test] -fn test_fs_repr_is_zero() { - assert!(FsRepr::from(0).is_zero()); - assert!(!FsRepr::from(1).is_zero()); - assert!(!FsRepr([0, 0, 1, 0]).is_zero()); -} - -#[test] -fn test_fs_repr_div2() { - let mut a = FsRepr([0xbd2920b19c972321, 0x174ed0466a3be37e, 0xd468d5e3b551f0b5, 0xcb67c072733beefc]); - a.div2(); - assert_eq!(a, FsRepr([0x5e949058ce4b9190, 0x8ba76823351df1bf, 0x6a346af1daa8f85a, 0x65b3e039399df77e])); - for _ in 0..10 { - a.div2(); - } - assert_eq!(a, FsRepr([0x6fd7a524163392e4, 0x16a2e9da08cd477c, 0xdf9a8d1abc76aa3e, 0x196cf80e4e677d])); - for _ in 0..200 { - a.div2(); - } - assert_eq!(a, FsRepr([0x196cf80e4e67, 0x0, 0x0, 0x0])); - for _ in 0..40 { - a.div2(); - } - assert_eq!(a, FsRepr([0x19, 0x0, 0x0, 0x0])); - for _ in 0..4 { - a.div2(); - } - assert_eq!(a, FsRepr([0x1, 0x0, 0x0, 0x0])); - a.div2(); - assert!(a.is_zero()); -} - -#[test] -fn test_fs_repr_shr() { - let mut a = FsRepr([0xb33fbaec482a283f, 0x997de0d3a88cb3df, 0x9af62d2a9a0e5525, 0x36003ab08de70da1]); - a.shr(0); - assert_eq!( - a, - FsRepr([0xb33fbaec482a283f, 0x997de0d3a88cb3df, 0x9af62d2a9a0e5525, 0x36003ab08de70da1]) - ); - a.shr(1); - assert_eq!( - a, - FsRepr([0xd99fdd762415141f, 0xccbef069d44659ef, 0xcd7b16954d072a92, 0x1b001d5846f386d0]) - ); - a.shr(50); - assert_eq!( - a, - FsRepr([0xbc1a7511967bf667, 0xc5a55341caa4b32f, 0x75611bce1b4335e, 0x6c0]) - ); - a.shr(130); - assert_eq!( - a, - FsRepr([0x1d5846f386d0cd7, 0x1b0, 0x0, 0x0]) - ); - a.shr(64); - assert_eq!( - a, - FsRepr([0x1b0, 0x0, 0x0, 0x0]) - ); -} - -#[test] -fn test_fs_repr_mul2() { - let mut a = FsRepr::from(23712937547); - a.mul2(); - assert_eq!(a, FsRepr([0xb0acd6c96, 0x0, 0x0, 0x0])); - for _ in 0..60 { - a.mul2(); - } - assert_eq!(a, FsRepr([0x6000000000000000, 0xb0acd6c9, 0x0, 0x0])); - for _ in 0..128 { - a.mul2(); - } - assert_eq!(a, FsRepr([0x0, 0x0, 0x6000000000000000, 0xb0acd6c9])); - for _ in 0..60 { - a.mul2(); - } - assert_eq!(a, FsRepr([0x0, 0x0, 0x0, 0x9600000000000000])); - for _ in 0..7 { - a.mul2(); - } - assert!(a.is_zero()); -} - -#[test] -fn test_fs_repr_num_bits() { - let mut a = FsRepr::from(0); - assert_eq!(0, a.num_bits()); - a = FsRepr::from(1); - for i in 1..257 { - assert_eq!(i, a.num_bits()); - a.mul2(); - } - assert_eq!(0, a.num_bits()); -} - -#[test] -fn test_fs_repr_sub_noborrow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let mut t = FsRepr([0x8e62a7e85264e2c3, 0xb23d34c1941d3ca, 0x5976930b7502dd15, 0x600f3fb517bf5495]); - t.sub_noborrow(&FsRepr([0xd64f669809cbc6a4, 0xfa76cb9d90cf7637, 0xfefb0df9038d43b3, 0x298a30c744b31acf])); - assert!(t == FsRepr([0xb813415048991c1f, 0x10ad07ae88725d92, 0x5a7b851271759961, 0x36850eedd30c39c5])); - - for _ in 0..1000 { - let mut a = FsRepr::rand(&mut rng); - a.0[3] >>= 30; - let mut b = a; - for _ in 0..10 { - b.mul2(); - } - let mut c = b; - for _ in 0..10 { - c.mul2(); - } - - assert!(a < b); - assert!(b < c); - - let mut csub_ba = c; - csub_ba.sub_noborrow(&b); - csub_ba.sub_noborrow(&a); - - let mut csub_ab = c; - csub_ab.sub_noborrow(&a); - csub_ab.sub_noborrow(&b); - - assert_eq!(csub_ab, csub_ba); - } -} - -#[test] -fn test_fs_legendre() { - assert_eq!(QuadraticResidue, Fs::one().legendre()); - assert_eq!(Zero, Fs::zero().legendre()); - - let e = FsRepr([0x8385eec23df1f88e, 0x9a01fb412b2dba16, 0x4c928edcdd6c22f, 0x9f2df7ef69ecef9]); - assert_eq!(QuadraticResidue, Fs::from_repr(e).unwrap().legendre()); - let e = FsRepr([0xe8ed9f299da78568, 0x35efdebc88b2209, 0xc82125cb1f916dbe, 0x6813d2b38c39bd0]); - assert_eq!(QuadraticNonResidue, Fs::from_repr(e).unwrap().legendre()); -} - -#[test] -fn test_fr_repr_add_nocarry() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let mut t = FsRepr([0xd64f669809cbc6a4, 0xfa76cb9d90cf7637, 0xfefb0df9038d43b3, 0x298a30c744b31acf]); - t.add_nocarry(&FsRepr([0x8e62a7e85264e2c3, 0xb23d34c1941d3ca, 0x5976930b7502dd15, 0x600f3fb517bf5495])); - assert_eq!(t, FsRepr([0x64b20e805c30a967, 0x59a9ee9aa114a02, 0x5871a104789020c9, 0x8999707c5c726f65])); - - // Test for the associativity of addition. - for _ in 0..1000 { - let mut a = FsRepr::rand(&mut rng); - let mut b = FsRepr::rand(&mut rng); - let mut c = FsRepr::rand(&mut rng); - - // Unset the first few bits, so that overflow won't occur. - a.0[3] >>= 3; - b.0[3] >>= 3; - c.0[3] >>= 3; - - let mut abc = a; - abc.add_nocarry(&b); - abc.add_nocarry(&c); - - let mut acb = a; - acb.add_nocarry(&c); - acb.add_nocarry(&b); - - let mut bac = b; - bac.add_nocarry(&a); - bac.add_nocarry(&c); - - let mut bca = b; - bca.add_nocarry(&c); - bca.add_nocarry(&a); - - let mut cab = c; - cab.add_nocarry(&a); - cab.add_nocarry(&b); - - let mut cba = c; - cba.add_nocarry(&b); - cba.add_nocarry(&a); - - assert_eq!(abc, acb); - assert_eq!(abc, bac); - assert_eq!(abc, bca); - assert_eq!(abc, cab); - assert_eq!(abc, cba); - } -} - -#[test] -fn test_fs_is_valid() { - let mut a = Fs(MODULUS); - assert!(!a.is_valid()); - a.0.sub_noborrow(&FsRepr::from(1)); - assert!(a.is_valid()); - assert!(Fs(FsRepr::from(0)).is_valid()); - assert!(Fs(FsRepr([0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9])).is_valid()); - assert!(!Fs(FsRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])).is_valid()); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let a = Fs::rand(&mut rng); - assert!(a.is_valid()); - } -} - -#[test] -fn test_fs_add_assign() { - { - // Random number - let mut tmp = Fs::from_str("4577408157467272683998459759522778614363623736323078995109579213719612604198").unwrap(); - assert!(tmp.is_valid()); - // Test that adding zero has no effect. - tmp.add_assign(&Fs(FsRepr::from(0))); - assert_eq!(tmp, Fs(FsRepr([0x8e6bfff4722d6e67, 0x5643da5c892044f9, 0x9465f4b281921a69, 0x25f752d3edd7162]))); - // Add one and test for the result. - tmp.add_assign(&Fs(FsRepr::from(1))); - assert_eq!(tmp, Fs(FsRepr([0x8e6bfff4722d6e68, 0x5643da5c892044f9, 0x9465f4b281921a69, 0x25f752d3edd7162]))); - // Add another random number that exercises the reduction. - tmp.add_assign(&Fs(FsRepr([0xb634d07bc42d4a70, 0xf724f0c008411f5f, 0x456d4053d865af34, 0x24ce814e8c63027]))); - assert_eq!(tmp, Fs(FsRepr([0x44a0d070365ab8d8, 0x4d68cb1c91616459, 0xd9d3350659f7c99e, 0x4ac5d4227a3a189]))); - // Add one to (s - 1) and test for the result. - tmp = Fs(FsRepr([0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9])); - tmp.add_assign(&Fs(FsRepr::from(1))); - assert!(tmp.0.is_zero()); - // Add a random number to another one such that the result is s - 1 - tmp = Fs(FsRepr([0xa11fda5950ce3636, 0x922e0dbccfe0ca0e, 0xacebb6e215b82d4a, 0x97ffb8cdc3aee93])); - tmp.add_assign(&Fs(FsRepr([0x2f7734058628f680, 0x143a12d6fce74674, 0x597b841eeb7c0db6, 0x4fdb95d88f8c115]))); - assert_eq!(tmp, Fs(FsRepr([0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9]))); - // Add one to the result and test for it. - tmp.add_assign(&Fs(FsRepr::from(1))); - assert!(tmp.0.is_zero()); - } - - // Test associativity - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Generate a, b, c and ensure (a + b) + c == a + (b + c). - let a = Fs::rand(&mut rng); - let b = Fs::rand(&mut rng); - let c = Fs::rand(&mut rng); - - let mut tmp1 = a; - tmp1.add_assign(&b); - tmp1.add_assign(&c); - - let mut tmp2 = b; - tmp2.add_assign(&c); - tmp2.add_assign(&a); - - assert!(tmp1.is_valid()); - assert!(tmp2.is_valid()); - assert_eq!(tmp1, tmp2); - } -} - -#[test] -fn test_fs_sub_assign() { - { - // Test arbitrary subtraction that tests reduction. - let mut tmp = Fs(FsRepr([0xb384d9f6877afd99, 0x4442513958e1a1c1, 0x352c4b8a95eccc3f, 0x2db62dee4b0f2])); - tmp.sub_assign(&Fs(FsRepr([0xec5bd2d13ed6b05a, 0x2adc0ab3a39b5fa, 0x82d3360a493e637e, 0x53ccff4a64d6679]))); - assert_eq!(tmp, Fs(FsRepr([0x97c015841f9b79f6, 0xe7fcb121eb6ffc49, 0xb8c050814de2a3c1, 0x943c0589dcafa21]))); - - // Test the opposite subtraction which doesn't test reduction. - tmp = Fs(FsRepr([0xec5bd2d13ed6b05a, 0x2adc0ab3a39b5fa, 0x82d3360a493e637e, 0x53ccff4a64d6679])); - tmp.sub_assign(&Fs(FsRepr([0xb384d9f6877afd99, 0x4442513958e1a1c1, 0x352c4b8a95eccc3f, 0x2db62dee4b0f2]))); - assert_eq!(tmp, Fs(FsRepr([0x38d6f8dab75bb2c1, 0xbe6b6f71e1581439, 0x4da6ea7fb351973e, 0x539f491c768b587]))); - - // Test for sensible results with zero - tmp = Fs(FsRepr::from(0)); - tmp.sub_assign(&Fs(FsRepr::from(0))); - assert!(tmp.is_zero()); - - tmp = Fs(FsRepr([0x361e16aef5cce835, 0x55bbde2536e274c1, 0x4dc77a63fd15ee75, 0x1e14bb37c14f230])); - tmp.sub_assign(&Fs(FsRepr::from(0))); - assert_eq!(tmp, Fs(FsRepr([0x361e16aef5cce835, 0x55bbde2536e274c1, 0x4dc77a63fd15ee75, 0x1e14bb37c14f230]))); - } - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Ensure that (a - b) + (b - a) = 0. - let a = Fs::rand(&mut rng); - let b = Fs::rand(&mut rng); - - let mut tmp1 = a; - tmp1.sub_assign(&b); - - let mut tmp2 = b; - tmp2.sub_assign(&a); - - tmp1.add_assign(&tmp2); - assert!(tmp1.is_zero()); - } -} - -#[test] -fn test_fs_mul_assign() { - let mut tmp = Fs(FsRepr([0xb433b01287f71744, 0x4eafb86728c4d108, 0xfdd52c14b9dfbe65, 0x2ff1f3434821118])); - tmp.mul_assign(&Fs(FsRepr([0xdae00fc63c9fa90f, 0x5a5ed89b96ce21ce, 0x913cd26101bd6f58, 0x3f0822831697fe9]))); - assert!(tmp == Fs(FsRepr([0xb68ecb61d54d2992, 0x5ff95874defce6a6, 0x3590eb053894657d, 0x53823a118515933]))); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000000 { - // Ensure that (a * b) * c = a * (b * c) - let a = Fs::rand(&mut rng); - let b = Fs::rand(&mut rng); - let c = Fs::rand(&mut rng); - - let mut tmp1 = a; - tmp1.mul_assign(&b); - tmp1.mul_assign(&c); - - let mut tmp2 = b; - tmp2.mul_assign(&c); - tmp2.mul_assign(&a); - - assert_eq!(tmp1, tmp2); - } - - for _ in 0..1000000 { - // Ensure that r * (a + b + c) = r*a + r*b + r*c - - let r = Fs::rand(&mut rng); - let mut a = Fs::rand(&mut rng); - let mut b = Fs::rand(&mut rng); - let mut c = Fs::rand(&mut rng); - - let mut tmp1 = a; - tmp1.add_assign(&b); - tmp1.add_assign(&c); - tmp1.mul_assign(&r); - - a.mul_assign(&r); - b.mul_assign(&r); - c.mul_assign(&r); - - a.add_assign(&b); - a.add_assign(&c); - - assert_eq!(tmp1, a); - } -} - -#[test] -fn test_fr_squaring() { - let mut a = Fs(FsRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xe7db4ea6533afa8])); - assert!(a.is_valid()); - a.square(); - assert_eq!(a, Fs::from_repr(FsRepr([0x12c7f55cbc52fbaa, 0xdedc98a0b5e6ce9e, 0xad2892726a5396a, 0x9fe82af8fee77b3])).unwrap()); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000000 { - // Ensure that (a * a) = a^2 - let a = Fs::rand(&mut rng); - - let mut tmp = a; - tmp.square(); - - let mut tmp2 = a; - tmp2.mul_assign(&a); - - assert_eq!(tmp, tmp2); - } -} - -#[test] -fn test_fs_inverse() { - assert!(Fs::zero().inverse().is_none()); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let one = Fs::one(); - - for _ in 0..1000 { - // Ensure that a * a^-1 = 1 - let mut a = Fs::rand(&mut rng); - let ainv = a.inverse().unwrap(); - a.mul_assign(&ainv); - assert_eq!(a, one); - } -} - -#[test] -fn test_fs_double() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Ensure doubling a is equivalent to adding a to itself. - let mut a = Fs::rand(&mut rng); - let mut b = a; - b.add_assign(&a); - a.double(); - assert_eq!(a, b); - } -} - -#[test] -fn test_fs_negate() { - { - let mut a = Fs::zero(); - a.negate(); - - assert!(a.is_zero()); - } - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Ensure (a - (-a)) = 0. - let mut a = Fs::rand(&mut rng); - let mut b = a; - b.negate(); - a.add_assign(&b); - - assert!(a.is_zero()); - } -} - -#[test] -fn test_fs_pow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for i in 0..1000 { - // Exponentiate by various small numbers and ensure it consists with repeated - // multiplication. - let a = Fs::rand(&mut rng); - let target = a.pow(&[i]); - let mut c = Fs::one(); - for _ in 0..i { - c.mul_assign(&a); - } - assert_eq!(c, target); - } - - for _ in 0..1000 { - // Exponentiating by the modulus should have no effect in a prime field. - let a = Fs::rand(&mut rng); - - assert_eq!(a, a.pow(Fs::char())); - } -} - -#[test] -fn test_fs_sqrt() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - assert_eq!(Fs::zero().sqrt().unwrap(), Fs::zero()); - - for _ in 0..1000 { - // Ensure sqrt(a^2) = a or -a - let a = Fs::rand(&mut rng); - let mut nega = a; - nega.negate(); - let mut b = a; - b.square(); - - let b = b.sqrt().unwrap(); - - assert!(a == b || nega == b); - } - - for _ in 0..1000 { - // Ensure sqrt(a)^2 = a for random a - let a = Fs::rand(&mut rng); - - if let Some(mut tmp) = a.sqrt() { - tmp.square(); - - assert_eq!(a, tmp); - } - } -} - -#[test] -fn test_fs_from_into_repr() { - // r + 1 should not be in the field - assert!(Fs::from_repr(FsRepr([0xd0970e5ed6f72cb8, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9])).is_err()); - - // r should not be in the field - assert!(Fs::from_repr(Fs::char()).is_err()); - - // Multiply some arbitrary representations to see if the result is as expected. - let a = FsRepr([0x5f2d0c05d0337b71, 0xa1df2b0f8a20479, 0xad73785e71bb863, 0x504a00480c9acec]); - let mut a_fs = Fs::from_repr(a).unwrap(); - let b = FsRepr([0x66356ff51e477562, 0x60a92ab55cf7603, 0x8e4273c7364dd192, 0x36df8844a344dc5]); - let b_fs = Fs::from_repr(b).unwrap(); - let c = FsRepr([0x7eef61708f4f2868, 0x747a7e6cf52946fb, 0x83dd75d7c9120017, 0x762f5177f0f3df7]); - a_fs.mul_assign(&b_fs); - assert_eq!(a_fs.into_repr(), c); - - // Zero should be in the field. - assert!(Fs::from_repr(FsRepr::from(0)).unwrap().is_zero()); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Try to turn Fs elements into representations and back again, and compare. - let a = Fs::rand(&mut rng); - let a_repr = a.into_repr(); - let b_repr = FsRepr::from(a); - assert_eq!(a_repr, b_repr); - let a_again = Fs::from_repr(a_repr).unwrap(); - - assert_eq!(a, a_again); - } -} - -#[test] -fn test_fs_repr_display() { - assert_eq!( - format!("{}", FsRepr([0xa296db59787359df, 0x8d3e33077430d318, 0xd1abf5c606102eb7, 0xcbc33ee28108f0])), - "0x00cbc33ee28108f0d1abf5c606102eb78d3e33077430d318a296db59787359df".to_string() - ); - assert_eq!( - format!("{}", FsRepr([0x14cb03535054a620, 0x312aa2bf2d1dff52, 0x970fe98746ab9361, 0xc1e18acf82711e6])), - "0x0c1e18acf82711e6970fe98746ab9361312aa2bf2d1dff5214cb03535054a620".to_string() - ); - assert_eq!( - format!("{}", FsRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])), - "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string() - ); - assert_eq!( - format!("{}", FsRepr([0, 0, 0, 0])), - "0x0000000000000000000000000000000000000000000000000000000000000000".to_string() - ); -} - -#[test] -fn test_fs_display() { - assert_eq!( - format!("{}", Fs::from_repr(FsRepr([0x5528efb9998a01a3, 0x5bd2add5cb357089, 0xc061fa6adb491f98, 0x70db9d143db03d9])).unwrap()), - "Fs(0x070db9d143db03d9c061fa6adb491f985bd2add5cb3570895528efb9998a01a3)".to_string() - ); - assert_eq!( - format!("{}", Fs::from_repr(FsRepr([0xd674745e2717999e, 0xbeb1f52d3e96f338, 0x9c7ae147549482b9, 0x999706024530d22])).unwrap()), - "Fs(0x0999706024530d229c7ae147549482b9beb1f52d3e96f338d674745e2717999e)".to_string() - ); -} - -#[test] -fn test_fs_num_bits() { - assert_eq!(Fs::NUM_BITS, 252); - assert_eq!(Fs::CAPACITY, 251); -} - -#[test] -fn test_fs_root_of_unity() { - assert_eq!(Fs::S, 1); - assert_eq!(Fs::multiplicative_generator(), Fs::from_repr(FsRepr::from(6)).unwrap()); - assert_eq!( - Fs::multiplicative_generator().pow([0x684b872f6b7b965b, 0x53341049e6640841, 0x83339d80809a1d80, 0x73eda753299d7d4]), - Fs::root_of_unity() - ); - assert_eq!( - Fs::root_of_unity().pow([1 << Fs::S]), - Fs::one() - ); - assert!(Fs::multiplicative_generator().sqrt().is_none()); -} diff --git a/sapling-crypto/src/jubjub/mod.rs b/sapling-crypto/src/jubjub/mod.rs deleted file mode 100644 index 51a000a..0000000 --- a/sapling-crypto/src/jubjub/mod.rs +++ /dev/null @@ -1,435 +0,0 @@ -//! Jubjub is a twisted Edwards curve defined over the BLS12-381 scalar -//! field, Fr. It takes the form `-x^2 + y^2 = 1 + dx^2y^2` with -//! `d = -(10240/10241)`. It is birationally equivalent to a Montgomery -//! curve of the form `y^2 = x^3 + Ax^2 + x` with `A = 40962`. This -//! value `A` is the smallest integer choice such that: -//! -//! * `(A - 2) / 4` is a small integer (`10240`). -//! * `A^2 - 4` is quadratic nonresidue. -//! * The group order of the curve and its quadratic twist has a large -//! prime factor. -//! -//! Jubjub has `s = 0x0e7db4ea6533afa906673b0101343b00a6682093ccc81082d0970e5ed6f72cb7` -//! as the prime subgroup order, with cofactor 8. (The twist has -//! cofactor 4.) -//! -//! It is a complete twisted Edwards curve, so the equivalence with -//! the Montgomery curve forms a group isomorphism, allowing points -//! to be freely converted between the two forms. - -use pairing::{ - Engine, - Field, - PrimeField, - SqrtField -}; - -use group_hash::group_hash; - -use constants; - -use pairing::bls12_381::{ - Bls12, - Fr -}; - -/// This is an implementation of the twisted Edwards Jubjub curve. -pub mod edwards; - -/// This is an implementation of the birationally equivalent -/// Montgomery curve. -pub mod montgomery; - -/// This is an implementation of the scalar field for Jubjub. -pub mod fs; - -#[cfg(test)] -pub mod tests; - -/// Point of unknown order. -pub enum Unknown { } - -/// Point of prime order. -pub enum PrimeOrder { } - -/// Fixed generators of the Jubjub curve of unknown -/// exponent. -#[derive(Copy, Clone)] -pub enum FixedGenerators { - /// The prover will demonstrate knowledge of discrete log - /// with respect to this base when they are constructing - /// a proof, in order to authorize proof construction. - ProofGenerationKey = 0, - - /// The note commitment is randomized over this generator. - NoteCommitmentRandomness = 1, - - /// The node commitment is randomized again by the position - /// in order to supply the nullifier computation with a - /// unique input w.r.t. the note being spent, to prevent - /// Faerie gold attacks. - NullifierPosition = 2, - - /// The value commitment is used to check balance between - /// inputs and outputs. The value is placed over this - /// generator. - ValueCommitmentValue = 3, - /// The value commitment is randomized over this generator, - /// for privacy. - ValueCommitmentRandomness = 4, - - /// The spender proves discrete log with respect to this - /// base at spend time. - SpendingKeyGenerator = 5, - - Max = 6 -} - -pub trait ToUniform { - fn to_uniform(digest: &[u8]) -> Self; -} - -/// This is an extension to the pairing Engine trait which -/// offers a scalar field for the embedded curve (Jubjub) -/// and some pre-computed parameters. -pub trait JubjubEngine: Engine { - /// The scalar field of the Jubjub curve - type Fs: PrimeField + SqrtField + ToUniform; - /// The parameters of Jubjub and the Sapling protocol - type Params: JubjubParams; -} - -/// The pre-computed parameters for Jubjub, including curve -/// constants and various limits and window tables. -pub trait JubjubParams: Sized { - /// The `d` constant of the twisted Edwards curve. - fn edwards_d(&self) -> &E::Fr; - /// The `A` constant of the birationally equivalent Montgomery curve. - fn montgomery_a(&self) -> &E::Fr; - /// The `A` constant, doubled. - fn montgomery_2a(&self) -> &E::Fr; - /// The scaling factor used for conversion from the Montgomery form. - fn scale(&self) -> &E::Fr; - /// Returns the generators (for each segment) used in all Pedersen commitments. - fn pedersen_hash_generators(&self) -> &[edwards::Point]; - /// Returns the exp table for Pedersen hashes. - fn pedersen_hash_exp_table(&self) -> &[Vec>>]; - /// Returns the maximum number of chunks per segment of the Pedersen hash. - fn pedersen_hash_chunks_per_generator(&self) -> usize; - /// Returns the pre-computed window tables [-4, 3, 2, 1, 1, 2, 3, 4] of different - /// magnitudes of the Pedersen hash segment generators. - fn pedersen_circuit_generators(&self) -> &[Vec>]; - - /// Returns the number of chunks needed to represent a full scalar during fixed-base - /// exponentiation. - fn fixed_base_chunks_per_generator(&self) -> usize; - /// Returns a fixed generator. - fn generator(&self, base: FixedGenerators) -> &edwards::Point; - /// Returns a window table [0, 1, ..., 8] for different magnitudes of some - /// fixed generator. - fn circuit_generators(&self, FixedGenerators) -> &[Vec<(E::Fr, E::Fr)>]; - /// Returns the window size for exponentiation of Pedersen hash generators - /// outside the circuit - fn pedersen_hash_exp_window_size() -> u32; -} - -impl JubjubEngine for Bls12 { - type Fs = self::fs::Fs; - type Params = JubjubBls12; -} - -pub struct JubjubBls12 { - edwards_d: Fr, - montgomery_a: Fr, - montgomery_2a: Fr, - scale: Fr, - - pedersen_hash_generators: Vec>, - pedersen_hash_exp: Vec>>>, - pedersen_circuit_generators: Vec>>, - - fixed_base_generators: Vec>, - fixed_base_circuit_generators: Vec>>, -} - -impl JubjubParams for JubjubBls12 { - fn edwards_d(&self) -> &Fr { &self.edwards_d } - fn montgomery_a(&self) -> &Fr { &self.montgomery_a } - fn montgomery_2a(&self) -> &Fr { &self.montgomery_2a } - fn scale(&self) -> &Fr { &self.scale } - fn pedersen_hash_generators(&self) -> &[edwards::Point] { - &self.pedersen_hash_generators - } - fn pedersen_hash_exp_table(&self) -> &[Vec>>] { - &self.pedersen_hash_exp - } - fn pedersen_hash_chunks_per_generator(&self) -> usize { - 63 - } - fn fixed_base_chunks_per_generator(&self) -> usize { - 84 - } - fn pedersen_circuit_generators(&self) -> &[Vec>] { - &self.pedersen_circuit_generators - } - fn generator(&self, base: FixedGenerators) -> &edwards::Point - { - &self.fixed_base_generators[base as usize] - } - fn circuit_generators(&self, base: FixedGenerators) -> &[Vec<(Fr, Fr)>] - { - &self.fixed_base_circuit_generators[base as usize][..] - } - fn pedersen_hash_exp_window_size() -> u32 { - 8 - } -} - -impl JubjubBls12 { - pub fn new() -> Self { - let montgomery_a = Fr::from_str("40962").unwrap(); - let mut montgomery_2a = montgomery_a; - montgomery_2a.double(); - - let mut tmp_params = JubjubBls12 { - // d = -(10240/10241) - edwards_d: Fr::from_str("19257038036680949359750312669786877991949435402254120286184196891950884077233").unwrap(), - // A = 40962 - montgomery_a: montgomery_a, - // 2A = 2.A - montgomery_2a: montgomery_2a, - // scaling factor = sqrt(4 / (a - d)) - scale: Fr::from_str("17814886934372412843466061268024708274627479829237077604635722030778476050649").unwrap(), - - // We'll initialize these below - pedersen_hash_generators: vec![], - pedersen_hash_exp: vec![], - pedersen_circuit_generators: vec![], - fixed_base_generators: vec![], - fixed_base_circuit_generators: vec![], - }; - - fn find_group_hash( - m: &[u8], - personalization: &[u8; 8], - params: &E::Params - ) -> edwards::Point - { - let mut tag = m.to_vec(); - let i = tag.len(); - tag.push(0u8); - - loop { - let gh = group_hash( - &tag, - personalization, - params - ); - - // We don't want to overflow and start reusing generators - assert!(tag[i] != u8::max_value()); - tag[i] += 1; - - if let Some(gh) = gh { - break gh; - } - } - } - - // Create the bases for the Pedersen hashes - { - let mut pedersen_hash_generators = vec![]; - - for m in 0..5 { - use byteorder::{WriteBytesExt, LittleEndian}; - - let mut segment_number = [0u8; 4]; - (&mut segment_number[0..4]).write_u32::(m).unwrap(); - - pedersen_hash_generators.push( - find_group_hash( - &segment_number, - constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, - &tmp_params - ) - ); - } - - // Check for duplicates, far worse than spec inconsistencies! - for (i, p1) in pedersen_hash_generators.iter().enumerate() { - if p1 == &edwards::Point::zero() { - panic!("Neutral element!"); - } - - for p2 in pedersen_hash_generators.iter().skip(i+1) { - if p1 == p2 { - panic!("Duplicate generator!"); - } - } - } - - tmp_params.pedersen_hash_generators = pedersen_hash_generators; - } - - // Create the exp table for the Pedersen hash generators - { - let mut pedersen_hash_exp = vec![]; - - for g in &tmp_params.pedersen_hash_generators { - let mut g = g.clone(); - - let window = JubjubBls12::pedersen_hash_exp_window_size(); - - let mut tables = vec![]; - - let mut num_bits = 0; - while num_bits <= fs::Fs::NUM_BITS { - let mut table = Vec::with_capacity(1 << window); - - let mut base = edwards::Point::zero(); - - for _ in 0..(1 << window) { - table.push(base.clone()); - base = base.add(&g, &tmp_params); - } - - tables.push(table); - num_bits += window; - - for _ in 0..window { - g = g.double(&tmp_params); - } - } - - pedersen_hash_exp.push(tables); - } - - tmp_params.pedersen_hash_exp = pedersen_hash_exp; - } - - // Create the bases for other parts of the protocol - { - let mut fixed_base_generators = vec![edwards::Point::zero(); FixedGenerators::Max as usize]; - - fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] = - find_group_hash(&[], constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION, &tmp_params); - - fixed_base_generators[FixedGenerators::NoteCommitmentRandomness as usize] = - find_group_hash(b"r", constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, &tmp_params); - - fixed_base_generators[FixedGenerators::NullifierPosition as usize] = - find_group_hash(&[], constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION, &tmp_params); - - fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] = - find_group_hash(b"v", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params); - - fixed_base_generators[FixedGenerators::ValueCommitmentRandomness as usize] = - find_group_hash(b"r", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params); - - fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] = - find_group_hash(&[], constants::SPENDING_KEY_GENERATOR_PERSONALIZATION, &tmp_params); - - // Check for duplicates, far worse than spec inconsistencies! - for (i, p1) in fixed_base_generators.iter().enumerate() { - if p1 == &edwards::Point::zero() { - panic!("Neutral element!"); - } - - for p2 in fixed_base_generators.iter().skip(i+1) { - if p1 == p2 { - panic!("Duplicate generator!"); - } - } - } - - tmp_params.fixed_base_generators = fixed_base_generators; - } - - // Create the 2-bit window table lookups for each 4-bit - // "chunk" in each segment of the Pedersen hash - { - let mut pedersen_circuit_generators = vec![]; - - // Process each segment - for mut gen in tmp_params.pedersen_hash_generators.iter().cloned() { - let mut gen = montgomery::Point::from_edwards(&gen, &tmp_params); - let mut windows = vec![]; - for _ in 0..tmp_params.pedersen_hash_chunks_per_generator() { - // Create (x, y) coeffs for this chunk - let mut coeffs = vec![]; - let mut g = gen.clone(); - - // coeffs = g, g*2, g*3, g*4 - for _ in 0..4 { - coeffs.push(g.into_xy().expect("cannot produce O")); - g = g.add(&gen, &tmp_params); - } - windows.push(coeffs); - - // Our chunks are separated by 2 bits to prevent overlap. - for _ in 0..4 { - gen = gen.double(&tmp_params); - } - } - pedersen_circuit_generators.push(windows); - } - - tmp_params.pedersen_circuit_generators = pedersen_circuit_generators; - } - - // Create the 3-bit window table lookups for fixed-base - // exp of each base in the protocol. - { - let mut fixed_base_circuit_generators = vec![]; - - for mut gen in tmp_params.fixed_base_generators.iter().cloned() { - let mut windows = vec![]; - for _ in 0..tmp_params.fixed_base_chunks_per_generator() { - let mut coeffs = vec![(Fr::zero(), Fr::one())]; - let mut g = gen.clone(); - for _ in 0..7 { - coeffs.push(g.into_xy()); - g = g.add(&gen, &tmp_params); - } - windows.push(coeffs); - - // gen = gen * 8 - gen = g; - } - fixed_base_circuit_generators.push(windows); - } - - tmp_params.fixed_base_circuit_generators = fixed_base_circuit_generators; - } - - tmp_params - } -} - -#[test] -fn test_jubjub_bls12() { - let params = JubjubBls12::new(); - - tests::test_suite::(¶ms); - - let test_repr = hex!("9d12b88b08dcbef8a11ee0712d94cb236ee2f4ca17317075bfafc82ce3139d31"); - let p = edwards::Point::::read(&test_repr[..], ¶ms).unwrap(); - let q = edwards::Point::::get_for_y( - Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(), - false, - ¶ms - ).unwrap(); - - assert!(p == q); - - // Same thing, but sign bit set - let test_repr = hex!("9d12b88b08dcbef8a11ee0712d94cb236ee2f4ca17317075bfafc82ce3139db1"); - let p = edwards::Point::::read(&test_repr[..], ¶ms).unwrap(); - let q = edwards::Point::::get_for_y( - Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(), - true, - ¶ms - ).unwrap(); - - assert!(p == q); -} diff --git a/sapling-crypto/src/jubjub/montgomery.rs b/sapling-crypto/src/jubjub/montgomery.rs deleted file mode 100644 index 18d0fcb..0000000 --- a/sapling-crypto/src/jubjub/montgomery.rs +++ /dev/null @@ -1,358 +0,0 @@ -use pairing::{ - Field, - SqrtField, - PrimeField, - PrimeFieldRepr, - BitIterator -}; - -use super::{ - JubjubEngine, - JubjubParams, - Unknown, - PrimeOrder, - edwards -}; - -use rand::{ - Rng -}; - -use std::marker::PhantomData; - -// Represents the affine point (X, Y) -pub struct Point { - x: E::Fr, - y: E::Fr, - infinity: bool, - _marker: PhantomData -} - -fn convert_subgroup(from: &Point) -> Point -{ - Point { - x: from.x, - y: from.y, - infinity: from.infinity, - _marker: PhantomData - } -} - -impl From> for Point -{ - fn from(p: Point) -> Point - { - convert_subgroup(&p) - } -} - -impl Clone for Point -{ - fn clone(&self) -> Self { - convert_subgroup(self) - } -} - -impl PartialEq for Point { - fn eq(&self, other: &Point) -> bool { - match (self.infinity, other.infinity) { - (true, true) => true, - (true, false) | (false, true) => false, - (false, false) => { - self.x == other.x && self.y == other.y - } - } - } -} - -impl Point { - pub fn get_for_x(x: E::Fr, sign: bool, params: &E::Params) -> Option - { - // Given an x on the curve, y = sqrt(x^3 + A*x^2 + x) - - let mut x2 = x; - x2.square(); - - let mut rhs = x2; - rhs.mul_assign(params.montgomery_a()); - rhs.add_assign(&x); - x2.mul_assign(&x); - rhs.add_assign(&x2); - - match rhs.sqrt() { - Some(mut y) => { - if y.into_repr().is_odd() != sign { - y.negate(); - } - - return Some(Point { - x: x, - y: y, - infinity: false, - _marker: PhantomData - }) - }, - None => None - } - } - - /// This guarantees the point is in the prime order subgroup - #[must_use] - pub fn mul_by_cofactor(&self, params: &E::Params) -> Point - { - let tmp = self.double(params) - .double(params) - .double(params); - - convert_subgroup(&tmp) - } - - pub fn rand(rng: &mut R, params: &E::Params) -> Self - { - loop { - let x: E::Fr = rng.gen(); - - match Self::get_for_x(x, rng.gen(), params) { - Some(p) => { - return p - }, - None => {} - } - } - } -} - -impl Point { - /// Convert from an Edwards point - pub fn from_edwards( - e: &edwards::Point, - params: &E::Params - ) -> Self - { - let (x, y) = e.into_xy(); - - if y == E::Fr::one() { - // The only solution for y = 1 is x = 0. (0, 1) is - // the neutral element, so we map this to the point - // at infinity. - - Point::zero() - } else { - // The map from a twisted Edwards curve is defined as - // (x, y) -> (u, v) where - // u = (1 + y) / (1 - y) - // v = u / x - // - // This mapping is not defined for y = 1 and for x = 0. - // - // We have that y != 1 above. If x = 0, the only - // solutions for y are 1 (contradiction) or -1. - if x.is_zero() { - // (0, -1) is the point of order two which is not - // the neutral element, so we map it to (0, 0) which is - // the only affine point of order 2. - - Point { - x: E::Fr::zero(), - y: E::Fr::zero(), - infinity: false, - _marker: PhantomData - } - } else { - // The mapping is defined as above. - // - // (x, y) -> (u, v) where - // u = (1 + y) / (1 - y) - // v = u / x - - let mut u = E::Fr::one(); - u.add_assign(&y); - { - let mut tmp = E::Fr::one(); - tmp.sub_assign(&y); - u.mul_assign(&tmp.inverse().unwrap()) - } - - let mut v = u; - v.mul_assign(&x.inverse().unwrap()); - - // Scale it into the correct curve constants - v.mul_assign(params.scale()); - - Point { - x: u, - y: v, - infinity: false, - _marker: PhantomData - } - } - } - } - - /// Attempts to cast this as a prime order element, failing if it's - /// not in the prime order subgroup. - pub fn as_prime_order(&self, params: &E::Params) -> Option> { - if self.mul(E::Fs::char(), params) == Point::zero() { - Some(convert_subgroup(self)) - } else { - None - } - } - - pub fn zero() -> Self { - Point { - x: E::Fr::zero(), - y: E::Fr::zero(), - infinity: true, - _marker: PhantomData - } - } - - pub fn into_xy(&self) -> Option<(E::Fr, E::Fr)> - { - if self.infinity { - None - } else { - Some((self.x, self.y)) - } - } - - #[must_use] - pub fn negate(&self) -> Self { - let mut p = self.clone(); - - p.y.negate(); - - p - } - - #[must_use] - pub fn double(&self, params: &E::Params) -> Self { - if self.infinity { - return Point::zero(); - } - - // (0, 0) is the point of order 2. Doubling - // produces the point at infinity. - if self.y == E::Fr::zero() { - return Point::zero(); - } - - // This is a standard affine point doubling formula - // See 4.3.2 The group law for Weierstrass curves - // Montgomery curves and the Montgomery Ladder - // Daniel J. Bernstein and Tanja Lange - - let mut delta = E::Fr::one(); - { - let mut tmp = params.montgomery_a().clone(); - tmp.mul_assign(&self.x); - tmp.double(); - delta.add_assign(&tmp); - } - { - let mut tmp = self.x; - tmp.square(); - delta.add_assign(&tmp); - tmp.double(); - delta.add_assign(&tmp); - } - { - let mut tmp = self.y; - tmp.double(); - delta.mul_assign(&tmp.inverse().expect("y is nonzero so this must be nonzero")); - } - - let mut x3 = delta; - x3.square(); - x3.sub_assign(params.montgomery_a()); - x3.sub_assign(&self.x); - x3.sub_assign(&self.x); - - let mut y3 = x3; - y3.sub_assign(&self.x); - y3.mul_assign(&delta); - y3.add_assign(&self.y); - y3.negate(); - - Point { - x: x3, - y: y3, - infinity: false, - _marker: PhantomData - } - } - - #[must_use] - pub fn add(&self, other: &Self, params: &E::Params) -> Self - { - // This is a standard affine point addition formula - // See 4.3.2 The group law for Weierstrass curves - // Montgomery curves and the Montgomery Ladder - // Daniel J. Bernstein and Tanja Lange - - match (self.infinity, other.infinity) { - (true, true) => Point::zero(), - (true, false) => other.clone(), - (false, true) => self.clone(), - (false, false) => { - if self.x == other.x { - if self.y == other.y { - self.double(params) - } else { - Point::zero() - } - } else { - let mut delta = other.y; - delta.sub_assign(&self.y); - { - let mut tmp = other.x; - tmp.sub_assign(&self.x); - delta.mul_assign(&tmp.inverse().expect("self.x != other.x, so this must be nonzero")); - } - - let mut x3 = delta; - x3.square(); - x3.sub_assign(params.montgomery_a()); - x3.sub_assign(&self.x); - x3.sub_assign(&other.x); - - let mut y3 = x3; - y3.sub_assign(&self.x); - y3.mul_assign(&delta); - y3.add_assign(&self.y); - y3.negate(); - - Point { - x: x3, - y: y3, - infinity: false, - _marker: PhantomData - } - } - } - } - } - - #[must_use] - pub fn mul::Repr>>( - &self, - scalar: S, - params: &E::Params - ) -> Self - { - // Standard double-and-add scalar multiplication - - let mut res = Self::zero(); - - for b in BitIterator::new(scalar.into()) { - res = res.double(params); - - if b { - res = res.add(self, params); - } - } - - res - } -} diff --git a/sapling-crypto/src/jubjub/tests.rs b/sapling-crypto/src/jubjub/tests.rs deleted file mode 100644 index 421a8f7..0000000 --- a/sapling-crypto/src/jubjub/tests.rs +++ /dev/null @@ -1,416 +0,0 @@ -use super::{ - JubjubEngine, - JubjubParams, - PrimeOrder, - montgomery, - edwards -}; - -use pairing::{ - Field, - PrimeField, - PrimeFieldRepr, - SqrtField, - LegendreSymbol -}; - -use rand::{XorShiftRng, SeedableRng, Rand}; - -pub fn test_suite(params: &E::Params) { - test_back_and_forth::(params); - test_jubjub_params::(params); - test_rand::(params); - test_get_for::(params); - test_identities::(params); - test_addition_associativity::(params); - test_order::(params); - test_mul_associativity::(params); - test_loworder::(params); - test_read_write::(params); -} - -fn is_on_mont_curve>( - x: E::Fr, - y: E::Fr, - params: &P -) -> bool -{ - let mut lhs = y; - lhs.square(); - - let mut x2 = x; - x2.square(); - - let mut x3 = x2; - x3.mul_assign(&x); - - let mut rhs = x2; - rhs.mul_assign(params.montgomery_a()); - rhs.add_assign(&x); - rhs.add_assign(&x3); - - lhs == rhs -} - -fn is_on_twisted_edwards_curve>( - x: E::Fr, - y: E::Fr, - params: &P -) -> bool -{ - let mut x2 = x; - x2.square(); - - let mut y2 = y; - y2.square(); - - // -x^2 + y^2 - let mut lhs = y2; - lhs.sub_assign(&x2); - - // 1 + d x^2 y^2 - let mut rhs = y2; - rhs.mul_assign(&x2); - rhs.mul_assign(params.edwards_d()); - rhs.add_assign(&E::Fr::one()); - - lhs == rhs -} - -fn test_loworder(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - let inf = montgomery::Point::zero(); - - // try to find a point of order 8 - let p = loop { - let r = montgomery::Point::::rand(rng, params).mul(E::Fs::char(), params); - - let r2 = r.double(params); - let r4 = r2.double(params); - let r8 = r4.double(params); - - if r2 != inf && r4 != inf && r8 == inf { - break r; - } - }; - - let mut loworder_points = vec![]; - { - let mut tmp = p.clone(); - - for _ in 0..8 { - assert!(!loworder_points.contains(&tmp)); - loworder_points.push(tmp.clone()); - tmp = tmp.add(&p, params); - } - } - assert!(loworder_points[7] == inf); -} - -fn test_mul_associativity(params: &E::Params) { - use self::edwards::Point; - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - // Pick a random point and multiply it by the cofactor - let base = Point::::rand(rng, params).mul_by_cofactor(params); - - let mut a = E::Fs::rand(rng); - let b = E::Fs::rand(rng); - let c = E::Fs::rand(rng); - - let res1 = base.mul(a, params).mul(b, params).mul(c, params); - let res2 = base.mul(b, params).mul(c, params).mul(a, params); - let res3 = base.mul(c, params).mul(a, params).mul(b, params); - a.mul_assign(&b); - a.mul_assign(&c); - let res4 = base.mul(a, params); - - assert!(res1 == res2); - assert!(res2 == res3); - assert!(res3 == res4); - - let (x, y) = res1.into_xy(); - assert!(is_on_twisted_edwards_curve(x, y, params)); - - let (x, y) = res2.into_xy(); - assert!(is_on_twisted_edwards_curve(x, y, params)); - - let (x, y) = res3.into_xy(); - assert!(is_on_twisted_edwards_curve(x, y, params)); - } -} - -fn test_order(params: &E::Params) { - use self::edwards::Point; - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - // The neutral element is in the prime order subgroup. - assert!(Point::::zero().as_prime_order(params).is_some()); - - for _ in 0..50 { - // Pick a random point and multiply it by the cofactor - let base = Point::::rand(rng, params).mul_by_cofactor(params); - - // Any point multiplied by the cofactor will be in the prime - // order subgroup - assert!(base.as_prime_order(params).is_some()); - } - - // It's very likely that at least one out of 50 random points on the curve - // is not in the prime order subgroup. - let mut at_least_one_not_in_prime_order_subgroup = false; - for _ in 0..50 { - // Pick a random point. - let base = Point::::rand(rng, params); - - at_least_one_not_in_prime_order_subgroup |= base.as_prime_order(params).is_none(); - } - assert!(at_least_one_not_in_prime_order_subgroup); -} - -fn test_addition_associativity(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - use self::montgomery::Point; - - let a = Point::::rand(rng, params); - let b = Point::::rand(rng, params); - let c = Point::::rand(rng, params); - - assert!(a.add(&b, ¶ms).add(&c, ¶ms) == c.add(&a, ¶ms).add(&b, ¶ms)); - } - - for _ in 0..1000 { - use self::edwards::Point; - - let a = Point::::rand(rng, params); - let b = Point::::rand(rng, params); - let c = Point::::rand(rng, params); - - assert!(a.add(&b, ¶ms).add(&c, ¶ms) == c.add(&a, ¶ms).add(&b, ¶ms)); - } -} - -fn test_identities(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - { - use self::edwards::Point; - - let z = Point::::zero(); - assert!(z.double(¶ms) == z); - assert!(z.negate() == z); - - for _ in 0..100 { - let r = Point::::rand(rng, params); - - assert!(r.add(&Point::zero(), ¶ms) == r); - assert!(r.add(&r.negate(), ¶ms) == Point::zero()); - } - } - - { - use self::montgomery::Point; - - let z = Point::::zero(); - assert!(z.double(¶ms) == z); - assert!(z.negate() == z); - - for _ in 0..100 { - let r = Point::::rand(rng, params); - - assert!(r.add(&Point::zero(), ¶ms) == r); - assert!(r.add(&r.negate(), ¶ms) == Point::zero()); - } - } -} - -fn test_get_for(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let y = E::Fr::rand(rng); - let sign = bool::rand(rng); - - if let Some(mut p) = edwards::Point::::get_for_y(y, sign, params) { - assert!(p.into_xy().0.into_repr().is_odd() == sign); - p = p.negate(); - assert!( - edwards::Point::::get_for_y(y, !sign, params).unwrap() - == - p - ); - } - } -} - -fn test_read_write(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let e = edwards::Point::::rand(rng, params); - - let mut v = vec![]; - e.write(&mut v).unwrap(); - - let e2 = edwards::Point::read(&v[..], params).unwrap(); - - assert!(e == e2); - } -} - -fn test_rand(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let p = montgomery::Point::::rand(rng, params); - let e = edwards::Point::::rand(rng, params); - - { - let (x, y) = p.into_xy().unwrap(); - assert!(is_on_mont_curve(x, y, params)); - } - - { - let (x, y) = e.into_xy(); - assert!(is_on_twisted_edwards_curve(x, y, params)); - } - } -} - -fn test_back_and_forth(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let s = E::Fs::rand(rng); - let edwards_p1 = edwards::Point::::rand(rng, params); - let mont_p1 = montgomery::Point::from_edwards(&edwards_p1, params); - let mont_p2 = montgomery::Point::::rand(rng, params); - let edwards_p2 = edwards::Point::from_montgomery(&mont_p2, params); - - let mont = mont_p1.add(&mont_p2, params).mul(s, params); - let edwards = edwards_p1.add(&edwards_p2, params).mul(s, params); - - assert!( - montgomery::Point::from_edwards(&edwards, params) == mont - ); - - assert!( - edwards::Point::from_montgomery(&mont, params) == edwards - ); - } -} - -fn test_jubjub_params(params: &E::Params) { - // a = -1 - let mut a = E::Fr::one(); - a.negate(); - - { - // Check that 2A is consistent with A - let mut tmp = *params.montgomery_a(); - tmp.double(); - - assert_eq!(&tmp, params.montgomery_2a()); - } - - { - // The twisted Edwards addition law is complete when d is nonsquare - // and a is square. - - assert!(params.edwards_d().legendre() == LegendreSymbol::QuadraticNonResidue); - assert!(a.legendre() == LegendreSymbol::QuadraticResidue); - } - - { - // Other convenient sanity checks regarding d - - // tmp = d - let mut tmp = *params.edwards_d(); - - // 1 / d is nonsquare - assert!(tmp.inverse().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue); - - // tmp = -d - tmp.negate(); - - // -d is nonsquare - assert!(tmp.legendre() == LegendreSymbol::QuadraticNonResidue); - - // 1 / -d is nonsquare - assert!(tmp.inverse().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue); - } - - { - // Check that A^2 - 4 is nonsquare: - let mut tmp = params.montgomery_a().clone(); - tmp.square(); - tmp.sub_assign(&E::Fr::from_str("4").unwrap()); - assert!(tmp.legendre() == LegendreSymbol::QuadraticNonResidue); - } - - { - // Check that A - 2 is nonsquare: - let mut tmp = params.montgomery_a().clone(); - tmp.sub_assign(&E::Fr::from_str("2").unwrap()); - assert!(tmp.legendre() == LegendreSymbol::QuadraticNonResidue); - } - - { - // Check the validity of the scaling factor - let mut tmp = a; - tmp.sub_assign(¶ms.edwards_d()); - tmp = tmp.inverse().unwrap(); - tmp.mul_assign(&E::Fr::from_str("4").unwrap()); - tmp = tmp.sqrt().unwrap(); - assert_eq!(&tmp, params.scale()); - } - - { - // Check that the number of windows per generator - // in the Pedersen hash does not allow for collisions - - let mut cur = E::Fs::one().into_repr(); - - let mut max = E::Fs::char(); - { - max.sub_noborrow(&E::Fs::one().into_repr()); - max.div2(); - } - - let mut pacc = E::Fs::zero().into_repr(); - let mut nacc = E::Fs::char(); - - for _ in 0..params.pedersen_hash_chunks_per_generator() - { - // tmp = cur * 4 - let mut tmp = cur; - tmp.mul2(); - tmp.mul2(); - - pacc.add_nocarry(&tmp); - nacc.sub_noborrow(&tmp); - - assert!(pacc < max); - assert!(pacc < nacc); - - // cur = cur * 16 - for _ in 0..4 { - cur.mul2(); - } - } - } - - { - // Check that the number of windows for fixed-base - // scalar multiplication is sufficient for all scalars. - - assert!(params.fixed_base_chunks_per_generator() * 3 >= E::Fs::NUM_BITS as usize); - - // ... and that it's *just* efficient enough. - - assert!((params.fixed_base_chunks_per_generator() - 1) * 3 < E::Fs::NUM_BITS as usize); - } -} diff --git a/sapling-crypto/src/lib.rs b/sapling-crypto/src/lib.rs deleted file mode 100644 index 27d306c..0000000 --- a/sapling-crypto/src/lib.rs +++ /dev/null @@ -1,22 +0,0 @@ -extern crate pairing; -extern crate bellman; -extern crate blake2_rfc; -extern crate digest; -extern crate rand; -extern crate byteorder; - -#[cfg(test)] -#[macro_use] -extern crate hex_literal; - -#[cfg(test)] -extern crate crypto; - -pub mod jubjub; -pub mod group_hash; -pub mod circuit; -pub mod pedersen_hash; -pub mod primitives; -pub mod constants; -pub mod redjubjub; -pub mod util; diff --git a/sapling-crypto/src/pedersen_hash.rs b/sapling-crypto/src/pedersen_hash.rs deleted file mode 100644 index 0590a5c..0000000 --- a/sapling-crypto/src/pedersen_hash.rs +++ /dev/null @@ -1,103 +0,0 @@ -use jubjub::*; -use pairing::*; - -#[derive(Copy, Clone)] -pub enum Personalization { - NoteCommitment, - MerkleTree(usize) -} - -impl Personalization { - pub fn get_bits(&self) -> Vec { - match *self { - Personalization::NoteCommitment => - vec![true, true, true, true, true, true], - Personalization::MerkleTree(num) => { - assert!(num < 63); - - (0..6).map(|i| (num >> i) & 1 == 1).collect() - } - } - } -} - -pub fn pedersen_hash( - personalization: Personalization, - bits: I, - params: &E::Params -) -> edwards::Point - where I: IntoIterator, - E: JubjubEngine -{ - let mut bits = personalization.get_bits().into_iter().chain(bits.into_iter()); - - let mut result = edwards::Point::zero(); - let mut generators = params.pedersen_hash_exp_table().iter(); - - loop { - let mut acc = E::Fs::zero(); - let mut cur = E::Fs::one(); - let mut chunks_remaining = params.pedersen_hash_chunks_per_generator(); - let mut encountered_bits = false; - - // Grab three bits from the input - while let Some(a) = bits.next() { - encountered_bits = true; - - let b = bits.next().unwrap_or(false); - let c = bits.next().unwrap_or(false); - - // Start computing this portion of the scalar - let mut tmp = cur; - if a { - tmp.add_assign(&cur); - } - cur.double(); // 2^1 * cur - if b { - tmp.add_assign(&cur); - } - - // conditionally negate - if c { - tmp.negate(); - } - - acc.add_assign(&tmp); - - chunks_remaining -= 1; - - if chunks_remaining == 0 { - break; - } else { - cur.double(); // 2^2 * cur - cur.double(); // 2^3 * cur - cur.double(); // 2^4 * cur - } - } - - if !encountered_bits { - break; - } - - let mut table: &[Vec>] = &generators.next().expect("we don't have enough generators"); - let window = JubjubBls12::pedersen_hash_exp_window_size(); - let window_mask = (1 << window) - 1; - - let mut acc = acc.into_repr(); - - let mut tmp = edwards::Point::zero(); - - while !acc.is_zero() { - let i = (acc.as_ref()[0] & window_mask) as usize; - - tmp = tmp.add(&table[0][i], params); - - acc.shr(window); - table = &table[1..]; - } - - result = result.add(&tmp, params); - } - - result -} diff --git a/sapling-crypto/src/primitives/mod.rs b/sapling-crypto/src/primitives/mod.rs deleted file mode 100644 index 26dafab..0000000 --- a/sapling-crypto/src/primitives/mod.rs +++ /dev/null @@ -1,258 +0,0 @@ -use pairing::{ - Field, - PrimeField, - PrimeFieldRepr -}; - -use constants; - -use group_hash::group_hash; - -use pedersen_hash::{ - pedersen_hash, - Personalization -}; - -use byteorder::{ - LittleEndian, - WriteBytesExt -}; - -use jubjub::{ - JubjubEngine, - JubjubParams, - edwards, - PrimeOrder, - FixedGenerators -}; - -use blake2_rfc::blake2s::Blake2s; - -#[derive(Clone)] -pub struct ValueCommitment { - pub value: u64, - pub randomness: E::Fs -} - -impl ValueCommitment { - pub fn cm( - &self, - params: &E::Params - ) -> edwards::Point - { - params.generator(FixedGenerators::ValueCommitmentValue) - .mul(self.value, params) - .add( - ¶ms.generator(FixedGenerators::ValueCommitmentRandomness) - .mul(self.randomness, params), - params - ) - } -} - -#[derive(Clone)] -pub struct ProofGenerationKey { - pub ak: edwards::Point, - pub nsk: E::Fs -} - -impl ProofGenerationKey { - pub fn into_viewing_key(&self, params: &E::Params) -> ViewingKey { - ViewingKey { - ak: self.ak.clone(), - nk: params.generator(FixedGenerators::ProofGenerationKey) - .mul(self.nsk, params) - } - } -} - -pub struct ViewingKey { - pub ak: edwards::Point, - pub nk: edwards::Point -} - -impl ViewingKey { - pub fn rk( - &self, - ar: E::Fs, - params: &E::Params - ) -> edwards::Point { - self.ak.add( - ¶ms.generator(FixedGenerators::SpendingKeyGenerator) - .mul(ar, params), - params - ) - } - - pub fn ivk(&self) -> E::Fs { - let mut preimage = [0; 64]; - - self.ak.write(&mut preimage[0..32]).unwrap(); - self.nk.write(&mut preimage[32..64]).unwrap(); - - let mut h = Blake2s::with_params(32, &[], &[], constants::CRH_IVK_PERSONALIZATION); - h.update(&preimage); - let mut h = h.finalize().as_ref().to_vec(); - - // Drop the most significant five bits, so it can be interpreted as a scalar. - h[31] &= 0b0000_0111; - - let mut e = ::Repr::default(); - e.read_le(&h[..]).unwrap(); - - E::Fs::from_repr(e).expect("should be a valid scalar") - } - - pub fn into_payment_address( - &self, - diversifier: Diversifier, - params: &E::Params - ) -> Option> - { - diversifier.g_d(params).map(|g_d| { - let pk_d = g_d.mul(self.ivk(), params); - - PaymentAddress { - pk_d: pk_d, - diversifier: diversifier - } - }) - } -} - -#[derive(Copy, Clone)] -pub struct Diversifier(pub [u8; 11]); - -impl Diversifier { - pub fn g_d( - &self, - params: &E::Params - ) -> Option> - { - group_hash::(&self.0, constants::KEY_DIVERSIFICATION_PERSONALIZATION, params) - } -} - -#[derive(Clone)] -pub struct PaymentAddress { - pub pk_d: edwards::Point, - pub diversifier: Diversifier -} - -impl PaymentAddress { - pub fn g_d( - &self, - params: &E::Params - ) -> Option> - { - self.diversifier.g_d(params) - } - - pub fn create_note( - &self, - value: u64, - randomness: E::Fs, - params: &E::Params - ) -> Option> - { - self.g_d(params).map(|g_d| { - Note { - value: value, - r: randomness, - g_d: g_d, - pk_d: self.pk_d.clone() - } - }) - } -} - -pub struct Note { - /// The value of the note - pub value: u64, - /// The diversified base of the address, GH(d) - pub g_d: edwards::Point, - /// The public key of the address, g_d^ivk - pub pk_d: edwards::Point, - /// The commitment randomness - pub r: E::Fs -} - -impl Note { - pub fn uncommitted() -> E::Fr { - // The smallest u-coordinate that is not on the curve - // is one. - // TODO: This should be relocated to JubjubEngine as - // it's specific to the curve we're using, not all - // twisted edwards curves. - E::Fr::one() - } - - /// Computes the note commitment, returning the full point. - fn cm_full_point(&self, params: &E::Params) -> edwards::Point - { - // Calculate the note contents, as bytes - let mut note_contents = vec![]; - - // Writing the value in little endian - (&mut note_contents).write_u64::(self.value).unwrap(); - - // Write g_d - self.g_d.write(&mut note_contents).unwrap(); - - // Write pk_d - self.pk_d.write(&mut note_contents).unwrap(); - - assert_eq!(note_contents.len(), 32 + 32 + 8); - - // Compute the Pedersen hash of the note contents - let hash_of_contents = pedersen_hash( - Personalization::NoteCommitment, - note_contents.into_iter() - .flat_map(|byte| { - (0..8).map(move |i| ((byte >> i) & 1) == 1) - }), - params - ); - - // Compute final commitment - params.generator(FixedGenerators::NoteCommitmentRandomness) - .mul(self.r, params) - .add(&hash_of_contents, params) - } - - /// Computes the nullifier given the viewing key and - /// note position - pub fn nf( - &self, - viewing_key: &ViewingKey, - position: u64, - params: &E::Params - ) -> Vec - { - // Compute rho = cm + position.G - let rho = self - .cm_full_point(params) - .add( - ¶ms.generator(FixedGenerators::NullifierPosition) - .mul(position, params), - params - ); - - // Compute nf = BLAKE2s(nk | rho) - let mut nf_preimage = [0u8; 64]; - viewing_key.nk.write(&mut nf_preimage[0..32]).unwrap(); - rho.write(&mut nf_preimage[32..64]).unwrap(); - let mut h = Blake2s::with_params(32, &[], &[], constants::PRF_NF_PERSONALIZATION); - h.update(&nf_preimage); - - h.finalize().as_ref().to_vec() - } - - /// Computes the note commitment - pub fn cm(&self, params: &E::Params) -> E::Fr - { - // The commitment is in the prime order subgroup, so mapping the - // commitment to the x-coordinate is an injective encoding. - self.cm_full_point(params).into_xy().0 - } -} diff --git a/sapling-crypto/src/redjubjub.rs b/sapling-crypto/src/redjubjub.rs deleted file mode 100644 index dfae28c..0000000 --- a/sapling-crypto/src/redjubjub.rs +++ /dev/null @@ -1,343 +0,0 @@ -//! Implementation of RedJubjub, a specialization of RedDSA to the Jubjub curve. -//! See section 5.4.6 of the Sapling protocol specification. - -use pairing::{Field, PrimeField, PrimeFieldRepr}; -use rand::{Rng, Rand}; -use std::io::{self, Read, Write}; - -use jubjub::{FixedGenerators, JubjubEngine, JubjubParams, Unknown, edwards::Point}; -use util::{hash_to_scalar}; - -fn read_scalar(reader: R) -> io::Result { - let mut s_repr = ::Repr::default(); - s_repr.read_le(reader)?; - - match E::Fs::from_repr(s_repr) { - Ok(s) => Ok(s), - Err(_) => Err(io::Error::new( - io::ErrorKind::InvalidInput, - "scalar is not in field", - )), - } -} - -fn write_scalar(s: &E::Fs, writer: W) -> io::Result<()> { - s.into_repr().write_le(writer) -} - -fn h_star(a: &[u8], b: &[u8]) -> E::Fs { - hash_to_scalar::(b"Zcash_RedJubjubH", a, b) -} - -#[derive(Copy, Clone)] -pub struct Signature { - rbar: [u8; 32], - sbar: [u8; 32], -} - -pub struct PrivateKey(pub E::Fs); - -pub struct PublicKey(pub Point); - -impl Signature { - pub fn read(mut reader: R) -> io::Result { - let mut rbar = [0u8; 32]; - let mut sbar = [0u8; 32]; - reader.read_exact(&mut rbar)?; - reader.read_exact(&mut sbar)?; - Ok(Signature { rbar, sbar }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_all(&self.rbar)?; - writer.write_all(&self.sbar) - } -} - -impl PrivateKey { - pub fn randomize(&self, alpha: E::Fs) -> Self { - let mut tmp = self.0; - tmp.add_assign(&alpha); - PrivateKey(tmp) - } - - pub fn read(reader: R) -> io::Result { - let pk = read_scalar::(reader)?; - Ok(PrivateKey(pk)) - } - - pub fn write(&self, writer: W) -> io::Result<()> { - write_scalar::(&self.0, writer) - } - - pub fn sign( - &self, - msg: &[u8], - rng: &mut R, - p_g: FixedGenerators, - params: &E::Params, - ) -> Signature { - // T = (l_H + 128) bits of randomness - // For H*, l_H = 512 bits - let mut t = [0u8; 80]; - rng.fill_bytes(&mut t[..]); - - // r = H*(T || M) - let r = h_star::(&t[..], msg); - - // R = r . P_G - let r_g = params.generator(p_g).mul(r, params); - let mut rbar = [0u8; 32]; - r_g.write(&mut rbar[..]) - .expect("Jubjub points should serialize to 32 bytes"); - - // S = r + H*(Rbar || M) . sk - let mut s = h_star::(&rbar[..], msg); - s.mul_assign(&self.0); - s.add_assign(&r); - let mut sbar = [0u8; 32]; - write_scalar::(&s, &mut sbar[..]) - .expect("Jubjub scalars should serialize to 32 bytes"); - - Signature { rbar, sbar } - } -} - -impl PublicKey { - pub fn from_private(privkey: &PrivateKey, p_g: FixedGenerators, params: &E::Params) -> Self { - let res = params.generator(p_g).mul(privkey.0, params).into(); - PublicKey(res) - } - - pub fn randomize(&self, alpha: E::Fs, p_g: FixedGenerators, params: &E::Params) -> Self { - let res: Point = params.generator(p_g).mul(alpha, params).into(); - let res = res.add(&self.0, params); - PublicKey(res) - } - - pub fn read(reader: R, params: &E::Params) -> io::Result { - let p = Point::read(reader, params)?; - Ok(PublicKey(p)) - } - - pub fn write(&self, writer: W) -> io::Result<()> { - self.0.write(writer) - } - - pub fn verify( - &self, - msg: &[u8], - sig: &Signature, - p_g: FixedGenerators, - params: &E::Params, - ) -> bool { - // c = H*(Rbar || M) - let c = h_star::(&sig.rbar[..], msg); - - // Signature checks: - // R != invalid - let r = match Point::read(&sig.rbar[..], params) { - Ok(r) => r, - Err(_) => return false, - }; - // S < order(G) - // (E::Fs guarantees its representation is in the field) - let s = match read_scalar::(&sig.sbar[..]) { - Ok(s) => s, - Err(_) => return false, - }; - // 0 = h_G(-S . P_G + R + c . vk) - self.0.mul(c, params).add(&r, params).add( - ¶ms.generator(p_g).mul(s, params).negate().into(), - params - ).mul_by_cofactor(params).eq(&Point::zero()) - } -} - -pub struct BatchEntry<'a, E: JubjubEngine> { - vk: PublicKey, - msg: &'a [u8], - sig: Signature, -} - -// TODO: #82: This is a naive implementation currently, -// and doesn't use multiexp. -pub fn batch_verify<'a, E: JubjubEngine, R: Rng>( - rng: &mut R, - batch: &[BatchEntry<'a, E>], - p_g: FixedGenerators, - params: &E::Params, -) -> bool -{ - let mut acc = Point::::zero(); - - for entry in batch { - let mut r = match Point::::read(&entry.sig.rbar[..], params) { - Ok(r) => r, - Err(_) => return false, - }; - let mut s = match read_scalar::(&entry.sig.sbar[..]) { - Ok(s) => s, - Err(_) => return false, - }; - - let mut c = h_star::(&entry.sig.rbar[..], entry.msg); - - let z = E::Fs::rand(rng); - - s.mul_assign(&z); - s.negate(); - - r = r.mul(z, params); - - c.mul_assign(&z); - - acc = acc.add(&r, params); - acc = acc.add(&entry.vk.0.mul(c, params), params); - acc = acc.add(¶ms.generator(p_g).mul(s, params).into(), params); - } - - acc = acc.mul_by_cofactor(params).into(); - - acc.eq(&Point::zero()) -} - -#[cfg(test)] -mod tests { - use pairing::bls12_381::Bls12; - use rand::thread_rng; - - use jubjub::{JubjubBls12, fs::Fs, edwards}; - - use super::*; - - #[test] - fn test_batch_verify() { - let rng = &mut thread_rng(); - let params = &JubjubBls12::new(); - let p_g = FixedGenerators::SpendingKeyGenerator; - - let sk1 = PrivateKey::(rng.gen()); - let vk1 = PublicKey::from_private(&sk1, p_g, params); - let msg1 = b"Foo bar"; - let sig1 = sk1.sign(msg1, rng, p_g, params); - assert!(vk1.verify(msg1, &sig1, p_g, params)); - - let sk2 = PrivateKey::(rng.gen()); - let vk2 = PublicKey::from_private(&sk2, p_g, params); - let msg2 = b"Foo bar"; - let sig2 = sk2.sign(msg2, rng, p_g, params); - assert!(vk2.verify(msg2, &sig2, p_g, params)); - - let mut batch = vec![ - BatchEntry { vk: vk1, msg: msg1, sig: sig1 }, - BatchEntry { vk: vk2, msg: msg2, sig: sig2 } - ]; - - assert!(batch_verify(rng, &batch, p_g, params)); - - batch[0].sig = sig2; - - assert!(!batch_verify(rng, &batch, p_g, params)); - } - - #[test] - fn cofactor_check() { - let rng = &mut thread_rng(); - let params = &JubjubBls12::new(); - let zero = edwards::Point::zero(); - let p_g = FixedGenerators::SpendingKeyGenerator; - - // Get a point of order 8 - let p8 = loop { - let r = edwards::Point::::rand(rng, params).mul(Fs::char(), params); - - let r2 = r.double(params); - let r4 = r2.double(params); - let r8 = r4.double(params); - - if r2 != zero && r4 != zero && r8 == zero { - break r; - } - }; - - let sk = PrivateKey::(rng.gen()); - let vk = PublicKey::from_private(&sk, p_g, params); - - // TODO: This test will need to change when #77 is fixed - let msg = b"Foo bar"; - let sig = sk.sign(msg, rng, p_g, params); - assert!(vk.verify(msg, &sig, p_g, params)); - - let vktorsion = PublicKey(vk.0.add(&p8, params)); - assert!(vktorsion.verify(msg, &sig, p_g, params)); - } - - #[test] - fn round_trip_serialization() { - let rng = &mut thread_rng(); - let p_g = FixedGenerators::SpendingKeyGenerator; - let params = &JubjubBls12::new(); - - for _ in 0..1000 { - let sk = PrivateKey::(rng.gen()); - let vk = PublicKey::from_private(&sk, p_g, params); - let msg = b"Foo bar"; - let sig = sk.sign(msg, rng, p_g, params); - - let mut sk_bytes = [0u8; 32]; - let mut vk_bytes = [0u8; 32]; - let mut sig_bytes = [0u8; 64]; - sk.write(&mut sk_bytes[..]).unwrap(); - vk.write(&mut vk_bytes[..]).unwrap(); - sig.write(&mut sig_bytes[..]).unwrap(); - - let sk_2 = PrivateKey::::read(&sk_bytes[..]).unwrap(); - let vk_2 = PublicKey::from_private(&sk_2, p_g, params); - let mut vk_2_bytes = [0u8; 32]; - vk_2.write(&mut vk_2_bytes[..]).unwrap(); - assert!(vk_bytes == vk_2_bytes); - - let vk_2 = PublicKey::::read(&vk_bytes[..], params).unwrap(); - let sig_2 = Signature::read(&sig_bytes[..]).unwrap(); - assert!(vk.verify(msg, &sig_2, p_g, params)); - assert!(vk_2.verify(msg, &sig, p_g, params)); - assert!(vk_2.verify(msg, &sig_2, p_g, params)); - } - } - - #[test] - fn random_signatures() { - let rng = &mut thread_rng(); - let p_g = FixedGenerators::SpendingKeyGenerator; - let params = &JubjubBls12::new(); - - for _ in 0..1000 { - let sk = PrivateKey::(rng.gen()); - let vk = PublicKey::from_private(&sk, p_g, params); - - let msg1 = b"Foo bar"; - let msg2 = b"Spam eggs"; - - let sig1 = sk.sign(msg1, rng, p_g, params); - let sig2 = sk.sign(msg2, rng, p_g, params); - - assert!(vk.verify(msg1, &sig1, p_g, params)); - assert!(vk.verify(msg2, &sig2, p_g, params)); - assert!(!vk.verify(msg1, &sig2, p_g, params)); - assert!(!vk.verify(msg2, &sig1, p_g, params)); - - let alpha = rng.gen(); - let rsk = sk.randomize(alpha); - let rvk = vk.randomize(alpha, p_g, params); - - let sig1 = rsk.sign(msg1, rng, p_g, params); - let sig2 = rsk.sign(msg2, rng, p_g, params); - - assert!(rvk.verify(msg1, &sig1, p_g, params)); - assert!(rvk.verify(msg2, &sig2, p_g, params)); - assert!(!rvk.verify(msg1, &sig2, p_g, params)); - assert!(!rvk.verify(msg2, &sig1, p_g, params)); - } - } -} diff --git a/sapling-crypto/src/util.rs b/sapling-crypto/src/util.rs deleted file mode 100644 index e67e660..0000000 --- a/sapling-crypto/src/util.rs +++ /dev/null @@ -1,11 +0,0 @@ -use blake2_rfc::blake2b::Blake2b; - -use jubjub::{JubjubEngine, ToUniform}; - -pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> E::Fs { - let mut hasher = Blake2b::with_params(64, &[], &[], persona); - hasher.update(a); - hasher.update(b); - let ret = hasher.finalize(); - E::Fs::to_uniform(ret.as_ref()) -} diff --git a/pairing/src/bls12_381/README.md b/src/bls12_381/README.md similarity index 100% rename from pairing/src/bls12_381/README.md rename to src/bls12_381/README.md diff --git a/pairing/src/bls12_381/ec.rs b/src/bls12_381/ec.rs similarity index 92% rename from pairing/src/bls12_381/ec.rs rename to src/bls12_381/ec.rs index f5a6d8f..019b19a 100644 --- a/pairing/src/bls12_381/ec.rs +++ b/src/bls12_381/ec.rs @@ -14,12 +14,11 @@ macro_rules! curve_impl { pub struct $affine { pub(crate) x: $basefield, pub(crate) y: $basefield, - pub(crate) infinity: bool + pub(crate) infinity: bool, } - impl ::std::fmt::Display for $affine - { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + impl ::std::fmt::Display for $affine { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { if self.infinity { write!(f, "{}(Infinity)", $name) } else { @@ -30,14 +29,13 @@ macro_rules! curve_impl { #[derive(Copy, Clone, Debug, Eq)] pub struct $projective { - pub(crate) x: $basefield, - pub(crate) y: $basefield, - pub(crate) z: $basefield + pub(crate) x: $basefield, + pub(crate) y: $basefield, + pub(crate) z: $basefield, } - impl ::std::fmt::Display for $projective - { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + impl ::std::fmt::Display for $projective { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "{}", self.into_affine()) } } @@ -89,7 +87,9 @@ macro_rules! curve_impl { let mut res = $projective::zero(); for i in bits { res.double(); - if i { res.add_assign_mixed(self) } + if i { + res.add_assign_mixed(self) + } } res } @@ -112,12 +112,8 @@ macro_rules! curve_impl { $affine { x: x, - y: if (y < negy) ^ greatest { - y - } else { - negy - }, - infinity: false + y: if (y < negy) ^ greatest { y } else { negy }, + infinity: false, } }) } @@ -156,7 +152,7 @@ macro_rules! curve_impl { $affine { x: $basefield::zero(), y: $basefield::one(), - infinity: true + infinity: true, } } @@ -182,7 +178,6 @@ macro_rules! curve_impl { fn into_projective(&self) -> $projective { (*self).into() } - } impl PairingCurveAffine for $affine { @@ -197,14 +192,18 @@ macro_rules! curve_impl { fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult { self.perform_pairing(other) } - } - impl Rand for $projective { - fn rand(rng: &mut R) -> Self { + impl CurveProjective for $projective { + type Engine = Bls12; + type Scalar = $scalarfield; + type Base = $basefield; + type Affine = $affine; + + fn random(rng: &mut R) -> Self { loop { - let x = rng.gen(); - let greatest = rng.gen(); + let x = $basefield::random(rng); + let greatest = rng.next_u32() % 2 != 0; if let Some(p) = $affine::get_point_from_x(x, greatest) { let p = p.scale_by_cofactor(); @@ -215,13 +214,6 @@ macro_rules! curve_impl { } } } - } - - impl CurveProjective for $projective { - type Engine = Bls12; - type Scalar = $scalarfield; - type Base = $basefield; - type Affine = $affine; // The point at infinity is always represented by // Z = 0. @@ -229,7 +221,7 @@ macro_rules! curve_impl { $projective { x: $basefield::zero(), y: $basefield::one(), - z: $basefield::zero() + z: $basefield::zero(), } } @@ -247,8 +239,7 @@ macro_rules! curve_impl { self.is_zero() || self.z == $basefield::one() } - fn batch_normalization(v: &mut [Self]) - { + fn batch_normalization(v: &mut [Self]) { // Montgomery’s Trick and Fast Implementation of Masked AES // Genelle, Prouff and Quisquater // Section 3.2 @@ -256,9 +247,10 @@ macro_rules! curve_impl { // First pass: compute [a, ab, abc, ...] let mut prod = Vec::with_capacity(v.len()); let mut tmp = $basefield::one(); - for g in v.iter_mut() - // Ignore normalized elements - .filter(|g| !g.is_normalized()) + for g in v + .iter_mut() + // Ignore normalized elements + .filter(|g| !g.is_normalized()) { tmp.mul_assign(&g.z); prod.push(tmp); @@ -268,13 +260,19 @@ macro_rules! curve_impl { tmp = tmp.inverse().unwrap(); // Guaranteed to be nonzero. // Second pass: iterate backwards to compute inverses - for (g, s) in v.iter_mut() - // Backwards - .rev() - // Ignore normalized elements - .filter(|g| !g.is_normalized()) - // Backwards, skip last element, fill in one for last term. - .zip(prod.into_iter().rev().skip(1).chain(Some($basefield::one()))) + for (g, s) in v + .iter_mut() + // Backwards + .rev() + // Ignore normalized elements + .filter(|g| !g.is_normalized()) + // Backwards, skip last element, fill in one for last term. + .zip( + prod.into_iter() + .rev() + .skip(1) + .chain(Some($basefield::one())), + ) { // tmp := tmp * g.z; g.z := tmp * s = 1/z let mut newtmp = tmp; @@ -285,9 +283,7 @@ macro_rules! curve_impl { } // Perform affine transformations - for g in v.iter_mut() - .filter(|g| !g.is_normalized()) - { + for g in v.iter_mut().filter(|g| !g.is_normalized()) { let mut z = g.z; // 1/z z.square(); // 1/z^2 g.x.mul_assign(&z); // x/z^2 @@ -540,8 +536,7 @@ macro_rules! curve_impl { let mut found_one = false; - for i in BitIterator::new(other.into()) - { + for i in BitIterator::new(other.into()) { if found_one { res.double(); } else { @@ -579,7 +574,7 @@ macro_rules! curve_impl { $projective { x: p.x, y: p.y, - z: $basefield::one() + z: $basefield::one(), } } } @@ -596,7 +591,7 @@ macro_rules! curve_impl { $affine { x: p.x, y: p.y, - infinity: false + infinity: false, } } else { // Z is nonzero, so it must have an inverse in a field. @@ -616,22 +611,22 @@ macro_rules! curve_impl { $affine { x: x, y: y, - infinity: false + infinity: false, } } } } - } + }; } pub mod g1 { use super::super::{Bls12, Fq, Fq12, FqRepr, Fr, FrRepr}; use super::g2::G2Affine; + use crate::{Engine, PairingCurveAffine}; use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; - use rand::{Rand, Rng}; + use rand_core::RngCore; use std::fmt; - use {Engine, PairingCurveAffine}; curve_impl!( "G1", @@ -661,7 +656,7 @@ pub mod g1 { } impl fmt::Debug for G1Uncompressed { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.0[..].fmt(formatter) } } @@ -771,7 +766,7 @@ pub mod g1 { } impl fmt::Debug for G1Compressed { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.0[..].fmt(formatter) } } @@ -939,7 +934,7 @@ pub mod g1 { #[test] fn g1_generator() { - use SqrtField; + use crate::SqrtField; let mut x = Fq::zero(); let mut i = 0; @@ -957,7 +952,7 @@ pub mod g1 { let negyrepr = negy.into_repr(); let p = G1Affine { - x: x, + x, y: if yrepr < negyrepr { y } else { negy }, infinity: false, }; @@ -992,7 +987,8 @@ pub mod g1 { 0x9fe83b1b4a5d648d, 0xf583cc5a508f6a40, 0xc3ad2aefde0bb13, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0x60aa6f9552f03aae, 0xecd01d5181300d35, @@ -1000,7 +996,8 @@ pub mod g1 { 0xe760f57922998c9d, 0x953703f5795a39e5, 0xfe3ae0922df702c, - ])).unwrap(), + ])) + .unwrap(), infinity: false, }; assert!(!p.is_on_curve()); @@ -1017,7 +1014,8 @@ pub mod g1 { 0xea034ee2928b30a8, 0xbd8833dc7c79a7f7, 0xe45c9f0c0438675, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0x3b450eb1ab7b5dad, 0xa65cb81e975e8675, @@ -1025,7 +1023,8 @@ pub mod g1 { 0x753ddf21a2601d20, 0x532d0b640bd3ff8b, 0x118d2c543f031102, - ])).unwrap(), + ])) + .unwrap(), infinity: false, }; assert!(!p.is_on_curve()); @@ -1043,7 +1042,8 @@ pub mod g1 { 0xf35de9ce0d6b4e84, 0x265bddd23d1dec54, 0x12a8778088458308, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0x8a22defa0d526256, 0xc57ca55456fcb9ae, @@ -1051,7 +1051,8 @@ pub mod g1 { 0x921beef89d4f29df, 0x5b6fda44ad85fa78, 0xed74ab9f302cbe0, - ])).unwrap(), + ])) + .unwrap(), infinity: false, }; assert!(p.is_on_curve()); @@ -1069,7 +1070,8 @@ pub mod g1 { 0x485e77d50a5df10d, 0x4c6fcac4b55fd479, 0x86ed4d9906fb064, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0xd25ee6461538c65, 0x9f3bbb2ecd3719b9, @@ -1077,7 +1079,8 @@ pub mod g1 { 0xcefca68333c35288, 0x570c8005f8573fa6, 0x152ca696fe034442, - ])).unwrap(), + ])) + .unwrap(), z: Fq::one(), }; @@ -1089,7 +1092,8 @@ pub mod g1 { 0x5f44314ec5e3fb03, 0x24e8538737c6e675, 0x8abd623a594fba8, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0x6b0528f088bb7044, 0x2fdeb5c82917ff9e, @@ -1097,7 +1101,8 @@ pub mod g1 { 0xd65104c6f95a872a, 0x1f2998a5a9c61253, 0xe74846154a9e44, - ])).unwrap(), + ])) + .unwrap(), z: Fq::one(), }); @@ -1113,7 +1118,8 @@ pub mod g1 { 0xc4f9a52a428e23bb, 0xd178b28dd4f407ef, 0x17fb8905e9183c69 - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0xd0de9d65292b7710, 0xf6a05f2bcf1d9ca7, @@ -1121,7 +1127,8 @@ pub mod g1 { 0xeec8d1a5b7466c58, 0x4bc362649dce6376, 0x430cbdc5455b00a - ])).unwrap(), + ])) + .unwrap(), infinity: false, } ); @@ -1137,7 +1144,8 @@ pub mod g1 { 0x485e77d50a5df10d, 0x4c6fcac4b55fd479, 0x86ed4d9906fb064, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0xd25ee6461538c65, 0x9f3bbb2ecd3719b9, @@ -1145,7 +1153,8 @@ pub mod g1 { 0xcefca68333c35288, 0x570c8005f8573fa6, 0x152ca696fe034442, - ])).unwrap(), + ])) + .unwrap(), z: Fq::one(), }; @@ -1163,7 +1172,8 @@ pub mod g1 { 0x4b914c16687dcde0, 0x66c8baf177d20533, 0xaf960cff3d83833 - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0x3f0675695f5177a8, 0x2b6d82ae178a1ba0, @@ -1171,7 +1181,8 @@ pub mod g1 { 0x1771a65b60572f4e, 0x8b547c1313b27555, 0x135075589a687b1e - ])).unwrap(), + ])) + .unwrap(), infinity: false, } ); @@ -1194,7 +1205,8 @@ pub mod g1 { 0x71ffa8021531705, 0x7418d484386d267, 0xd5108d8ff1fbd6, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0xa776ccbfe9981766, 0x255632964ff40f4a, @@ -1202,7 +1214,8 @@ pub mod g1 { 0x520f74773e74c8c3, 0x484c8fc982008f0, 0xee2c3d922008cc6, - ])).unwrap(), + ])) + .unwrap(), infinity: false, }; @@ -1214,7 +1227,8 @@ pub mod g1 { 0xc6e05201e5f83991, 0xf7c75910816f207c, 0x18d4043e78103106, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0xa776ccbfe9981766, 0x255632964ff40f4a, @@ -1222,7 +1236,8 @@ pub mod g1 { 0x520f74773e74c8c3, 0x484c8fc982008f0, 0xee2c3d922008cc6, - ])).unwrap(), + ])) + .unwrap(), infinity: false, }; @@ -1237,7 +1252,8 @@ pub mod g1 { 0x9676ff02ec39c227, 0x4c12c15d7e55b9f3, 0x57fd1e317db9bd, - ])).unwrap(), + ])) + .unwrap(), y: Fq::from_repr(FqRepr([ 0x1288334016679345, 0xf955cd68615ff0b5, @@ -1245,7 +1261,8 @@ pub mod g1 { 0x1267d70db51049fb, 0x4696deb9ab2ba3e7, 0xb1e4e11177f59d4, - ])).unwrap(), + ])) + .unwrap(), infinity: false, }; @@ -1274,11 +1291,11 @@ pub mod g1 { pub mod g2 { use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr, FrRepr}; use super::g1::G1Affine; + use crate::{Engine, PairingCurveAffine}; use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; - use rand::{Rand, Rng}; + use rand_core::RngCore; use std::fmt; - use {Engine, PairingCurveAffine}; curve_impl!( "G2", @@ -1308,7 +1325,7 @@ pub mod g2 { } impl fmt::Debug for G2Uncompressed { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.0[..].fmt(formatter) } } @@ -1434,7 +1451,7 @@ pub mod g2 { } impl fmt::Debug for G2Compressed { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.0[..].fmt(formatter) } } @@ -1623,7 +1640,7 @@ pub mod g2 { #[test] fn g2_generator() { - use SqrtField; + use crate::SqrtField; let mut x = Fq2::zero(); let mut i = 0; @@ -1639,7 +1656,7 @@ pub mod g2 { negy.negate(); let p = G2Affine { - x: x, + x, y: if y < negy { y } else { negy }, infinity: false, }; @@ -1675,7 +1692,8 @@ pub mod g2 { 0x7a17a004747e3dbe, 0xcc65406a7c2e5a73, 0x10b8c03d64db4d0c, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xd30e70fe2f029778, 0xda30772df0f5212e, @@ -1683,7 +1701,8 @@ pub mod g2 { 0xfb777e5b9b568608, 0x789bac1fec71a2b9, 0x1342f02e2da54405, - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -1693,7 +1712,8 @@ pub mod g2 { 0x663015d9410eb608, 0x78e82a79d829a544, 0x40a00545bb3c1e, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x4709802348e79377, 0xb5ac4dc9204bcfbd, @@ -1701,7 +1721,8 @@ pub mod g2 { 0x15008b1dc399e8df, 0x68128fd0548a3829, 0x16a613db5c873aaa, - ])).unwrap(), + ])) + .unwrap(), }, infinity: false, }; @@ -1720,7 +1741,8 @@ pub mod g2 { 0x41abba710d6c692c, 0xffcc4b2b62ce8484, 0x6993ec01b8934ed, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xb94e92d5f874e26, 0x44516408bc115d95, @@ -1728,7 +1750,8 @@ pub mod g2 { 0xa5a0c2b7131f3555, 0x83800965822367e7, 0x10cf1d3ad8d90bfa, - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -1738,7 +1761,8 @@ pub mod g2 { 0x5a9171720e73eb51, 0x38eb4fd8d658adb7, 0xb649051bbc1164d, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x9225814253d7df75, 0xc196c2513477f887, @@ -1746,7 +1770,8 @@ pub mod g2 { 0x55f2b8efad953e04, 0x7379345eda55265e, 0x377f2e6208fd4cb, - ])).unwrap(), + ])) + .unwrap(), }, infinity: false, }; @@ -1766,7 +1791,8 @@ pub mod g2 { 0x2199bc19c48c393d, 0x4a151b732a6075bf, 0x17762a3b9108c4a7, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x26f461e944bbd3d1, 0x298f3189a9cf6ed6, @@ -1774,7 +1800,8 @@ pub mod g2 { 0x7e147f3f9e6e241, 0x72a9b63583963fff, 0x158b0083c000462, - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -1784,7 +1811,8 @@ pub mod g2 { 0x68cad19430706b4d, 0x3ccfb97b924dcea8, 0x1660f93434588f8d, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xaaed3985b6dcb9c7, 0xc1e985d6d898d9f4, @@ -1792,7 +1820,8 @@ pub mod g2 { 0x3940a2dbb914b529, 0xbeb88137cf34f3e7, 0x1699ee577c61b694, - ])).unwrap(), + ])) + .unwrap(), }, infinity: false, }; @@ -1812,7 +1841,8 @@ pub mod g2 { 0x72556c999f3707ac, 0x4617f2e6774e9711, 0x100b2fe5bffe030b, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x7a33555977ec608, 0xe23039d1fe9c0881, @@ -1820,7 +1850,8 @@ pub mod g2 { 0x4637c4f417667e2e, 0x93ebe7c3e41f6acc, 0xde884f89a9a371b, - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -1830,7 +1861,8 @@ pub mod g2 { 0x25fd427b4122f231, 0xd83112aace35cae, 0x191b2432407cbb7f, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xf68ae82fe97662f5, 0xe986057068b50b7d, @@ -1838,7 +1870,8 @@ pub mod g2 { 0x9eaa6d19de569196, 0xf6a03d31e2ec2183, 0x3bdafaf7ca9b39b, - ])).unwrap(), + ])) + .unwrap(), }, z: Fq2::one(), }; @@ -1852,7 +1885,8 @@ pub mod g2 { 0x8e73a96b329ad190, 0x27c546f75ee1f3ab, 0xa33d27add5e7e82, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x93b1ebcd54870dfe, 0xf1578300e1342e11, @@ -1860,7 +1894,8 @@ pub mod g2 { 0x2089faf462438296, 0x828e5848cd48ea66, 0x141ecbac1deb038b, - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -1870,7 +1905,8 @@ pub mod g2 { 0x2767032fc37cc31d, 0xd5ee2aba84fd10fe, 0x16576ccd3dd0a4e8, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x4da9b6f6a96d1dd2, 0x9657f7da77f1650e, @@ -1878,7 +1914,8 @@ pub mod g2 { 0x31898db63f87363a, 0xabab040ddbd097cc, 0x11ad236b9ba02990, - ])).unwrap(), + ])) + .unwrap(), }, z: Fq2::one(), }); @@ -1896,7 +1933,8 @@ pub mod g2 { 0xf1273e6406eef9cc, 0xababd760ff05cb92, 0xd7c20456617e89 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xd1a50b8572cbd2b8, 0x238f0ac6119d07df, @@ -1904,7 +1942,8 @@ pub mod g2 { 0x8b203284c51edf6b, 0xc8a0b730bbb21f5e, 0x1a3b59d29a31274 - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -1914,7 +1953,8 @@ pub mod g2 { 0x64528ab3863633dc, 0x159384333d7cba97, 0x4cb84741f3cafe8 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x242af0dc3640e1a4, 0xe90a73ad65c66919, @@ -1922,7 +1962,8 @@ pub mod g2 { 0x38528f92b689644d, 0xb6884deec59fb21f, 0x3c075d3ec52ba90 - ])).unwrap(), + ])) + .unwrap(), }, infinity: false, } @@ -1940,7 +1981,8 @@ pub mod g2 { 0x72556c999f3707ac, 0x4617f2e6774e9711, 0x100b2fe5bffe030b, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x7a33555977ec608, 0xe23039d1fe9c0881, @@ -1948,7 +1990,8 @@ pub mod g2 { 0x4637c4f417667e2e, 0x93ebe7c3e41f6acc, 0xde884f89a9a371b, - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -1958,7 +2001,8 @@ pub mod g2 { 0x25fd427b4122f231, 0xd83112aace35cae, 0x191b2432407cbb7f, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xf68ae82fe97662f5, 0xe986057068b50b7d, @@ -1966,7 +2010,8 @@ pub mod g2 { 0x9eaa6d19de569196, 0xf6a03d31e2ec2183, 0x3bdafaf7ca9b39b, - ])).unwrap(), + ])) + .unwrap(), }, z: Fq2::one(), }; @@ -1986,7 +2031,8 @@ pub mod g2 { 0xbcedcfce1e52d986, 0x9755d4a3926e9862, 0x18bab73760fd8024 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x4e7c5e0a2ae5b99e, 0x96e582a27f028961, @@ -1994,7 +2040,8 @@ pub mod g2 { 0xeb0cf5e610ef4fe7, 0x7b4c2bae8db6e70b, 0xf136e43909fca0 - ])).unwrap(), + ])) + .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ @@ -2004,7 +2051,8 @@ pub mod g2 { 0xa5a2a51f7fde787b, 0x8b92866bc6384188, 0x81a53fe531d64ef - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x4c5d607666239b34, 0xeddb5f48304d14b3, @@ -2012,7 +2060,8 @@ pub mod g2 { 0xb271f52f12ead742, 0x244e6c2015c83348, 0x19e2deae6eb9b441 - ])).unwrap(), + ])) + .unwrap(), }, infinity: false, } diff --git a/pairing/src/bls12_381/fq.rs b/src/bls12_381/fq.rs similarity index 93% rename from pairing/src/bls12_381/fq.rs rename to src/bls12_381/fq.rs index fd0d416..08135e3 100644 --- a/pairing/src/bls12_381/fq.rs +++ b/src/bls12_381/fq.rs @@ -1173,7 +1173,9 @@ fn test_neg_one() { } #[cfg(test)] -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +#[cfg(test)] +use rand_xorshift::XorShiftRng; #[test] fn test_fq_repr_ordering() { @@ -1396,7 +1398,10 @@ fn test_fq_repr_num_bits() { #[test] fn test_fq_repr_sub_noborrow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let mut t = FqRepr([ 0x827a4a08041ebd9, @@ -1426,7 +1431,7 @@ fn test_fq_repr_sub_noborrow() { ); for _ in 0..1000 { - let mut a = FqRepr::rand(&mut rng); + let mut a = Fq::random(&mut rng).into_repr(); a.0[5] >>= 30; let mut b = a; for _ in 0..10 { @@ -1483,7 +1488,10 @@ fn test_fq_repr_sub_noborrow() { #[test] fn test_fq_repr_add_nocarry() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let mut t = FqRepr([ 0x827a4a08041ebd9, @@ -1514,9 +1522,9 @@ fn test_fq_repr_add_nocarry() { // Test for the associativity of addition. for _ in 0..1000 { - let mut a = FqRepr::rand(&mut rng); - let mut b = FqRepr::rand(&mut rng); - let mut c = FqRepr::rand(&mut rng); + let mut a = Fq::random(&mut rng).into_repr(); + let mut b = Fq::random(&mut rng).into_repr(); + let mut c = Fq::random(&mut rng).into_repr(); // Unset the first few bits, so that overflow won't occur. a.0[5] >>= 3; @@ -1574,31 +1582,32 @@ fn test_fq_is_valid() { a.0.sub_noborrow(&FqRepr::from(1)); assert!(a.is_valid()); assert!(Fq(FqRepr::from(0)).is_valid()); - assert!( - Fq(FqRepr([ - 0xdf4671abd14dab3e, - 0xe2dc0c9f534fbd33, - 0x31ca6c880cc444a6, - 0x257a67e70ef33359, - 0xf9b29e493f899b36, - 0x17c8be1800b9f059 - ])).is_valid() - ); - assert!( - !Fq(FqRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff - ])).is_valid() - ); + assert!(Fq(FqRepr([ + 0xdf4671abd14dab3e, + 0xe2dc0c9f534fbd33, + 0x31ca6c880cc444a6, + 0x257a67e70ef33359, + 0xf9b29e493f899b36, + 0x17c8be1800b9f059 + ])) + .is_valid()); + assert!(!Fq(FqRepr([ + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff + ])) + .is_valid()); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let a = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); assert!(a.is_valid()); } } @@ -1708,13 +1717,16 @@ fn test_fq_add_assign() { // Test associativity - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Generate a, b, c and ensure (a + b) + c == a + (b + c). - let a = Fq::rand(&mut rng); - let b = Fq::rand(&mut rng); - let c = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); + let b = Fq::random(&mut rng); + let c = Fq::random(&mut rng); let mut tmp1 = a; tmp1.add_assign(&b); @@ -1818,12 +1830,15 @@ fn test_fq_sub_assign() { ); } - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Ensure that (a - b) + (b - a) = 0. - let a = Fq::rand(&mut rng); - let b = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); + let b = Fq::random(&mut rng); let mut tmp1 = a; tmp1.sub_assign(&b); @@ -1865,13 +1880,16 @@ fn test_fq_mul_assign() { ])) ); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000000 { // Ensure that (a * b) * c = a * (b * c) - let a = Fq::rand(&mut rng); - let b = Fq::rand(&mut rng); - let c = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); + let b = Fq::random(&mut rng); + let c = Fq::random(&mut rng); let mut tmp1 = a; tmp1.mul_assign(&b); @@ -1887,10 +1905,10 @@ fn test_fq_mul_assign() { for _ in 0..1000000 { // Ensure that r * (a + b + c) = r*a + r*b + r*c - let r = Fq::rand(&mut rng); - let mut a = Fq::rand(&mut rng); - let mut b = Fq::rand(&mut rng); - let mut c = Fq::rand(&mut rng); + let r = Fq::random(&mut rng); + let mut a = Fq::random(&mut rng); + let mut b = Fq::random(&mut rng); + let mut c = Fq::random(&mut rng); let mut tmp1 = a; tmp1.add_assign(&b); @@ -1929,14 +1947,18 @@ fn test_fq_squaring() { 0xdc05c659b4e15b27, 0x79361e5a802c6a23, 0x24bcbe5d51b9a6f - ])).unwrap() + ])) + .unwrap() ); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000000 { // Ensure that (a * a) = a^2 - let a = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); let mut tmp = a; tmp.square(); @@ -1952,13 +1974,16 @@ fn test_fq_squaring() { fn test_fq_inverse() { assert!(Fq::zero().inverse().is_none()); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let one = Fq::one(); for _ in 0..1000 { // Ensure that a * a^-1 = 1 - let mut a = Fq::rand(&mut rng); + let mut a = Fq::random(&mut rng); let ainv = a.inverse().unwrap(); a.mul_assign(&ainv); assert_eq!(a, one); @@ -1967,11 +1992,14 @@ fn test_fq_inverse() { #[test] fn test_fq_double() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Ensure doubling a is equivalent to adding a to itself. - let mut a = Fq::rand(&mut rng); + let mut a = Fq::random(&mut rng); let mut b = a; b.add_assign(&a); a.double(); @@ -1988,11 +2016,14 @@ fn test_fq_negate() { assert!(a.is_zero()); } - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Ensure (a - (-a)) = 0. - let mut a = Fq::rand(&mut rng); + let mut a = Fq::random(&mut rng); let mut b = a; b.negate(); a.add_assign(&b); @@ -2003,12 +2034,15 @@ fn test_fq_negate() { #[test] fn test_fq_pow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for i in 0..1000 { // Exponentiate by various small numbers and ensure it consists with repeated // multiplication. - let a = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); let target = a.pow(&[i]); let mut c = Fq::one(); for _ in 0..i { @@ -2019,7 +2053,7 @@ fn test_fq_pow() { for _ in 0..1000 { // Exponentiating by the modulus should have no effect in a prime field. - let a = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); assert_eq!(a, a.pow(Fq::char())); } @@ -2029,13 +2063,16 @@ fn test_fq_pow() { fn test_fq_sqrt() { use ff::SqrtField; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); assert_eq!(Fq::zero().sqrt().unwrap(), Fq::zero()); for _ in 0..1000 { // Ensure sqrt(a^2) = a or -a - let a = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); let mut nega = a; nega.negate(); let mut b = a; @@ -2048,7 +2085,7 @@ fn test_fq_sqrt() { for _ in 0..1000 { // Ensure sqrt(a)^2 = a for random a - let a = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); if let Some(mut tmp) = a.sqrt() { tmp.square(); @@ -2061,16 +2098,15 @@ fn test_fq_sqrt() { #[test] fn test_fq_from_into_repr() { // q + 1 should not be in the field - assert!( - Fq::from_repr(FqRepr([ - 0xb9feffffffffaaac, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a - ])).is_err() - ); + assert!(Fq::from_repr(FqRepr([ + 0xb9feffffffffaaac, + 0x1eabfffeb153ffff, + 0x6730d2a0f6b0f624, + 0x64774b84f38512bf, + 0x4b1ba7b6434bacd7, + 0x1a0111ea397fe69a + ])) + .is_err()); // q should not be in the field assert!(Fq::from_repr(Fq::char()).is_err()); @@ -2108,11 +2144,14 @@ fn test_fq_from_into_repr() { // Zero should be in the field. assert!(Fq::from_repr(FqRepr::from(0)).unwrap().is_zero()); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Try to turn Fq elements into representations and back again, and compare. - let a = Fq::rand(&mut rng); + let a = Fq::random(&mut rng); let a_repr = a.into_repr(); let b_repr = FqRepr::from(a); assert_eq!(a_repr, b_repr); @@ -2186,10 +2225,10 @@ fn test_fq_root_of_unity() { #[test] fn fq_field_tests() { - ::tests::field::random_field_tests::(); - ::tests::field::random_sqrt_tests::(); - ::tests::field::random_frobenius_tests::(Fq::char(), 13); - ::tests::field::from_str_tests::(); + crate::tests::field::random_field_tests::(); + crate::tests::field::random_sqrt_tests::(); + crate::tests::field::random_frobenius_tests::(Fq::char(), 13); + crate::tests::field::from_str_tests::(); } #[test] @@ -2205,7 +2244,7 @@ fn test_fq_ordering() { #[test] fn fq_repr_tests() { - ::tests::repr::random_repr_tests::(); + crate::tests::repr::random_repr_tests::(); } #[test] diff --git a/pairing/src/bls12_381/fq12.rs b/src/bls12_381/fq12.rs similarity index 82% rename from pairing/src/bls12_381/fq12.rs rename to src/bls12_381/fq12.rs index b24fcaa..17ae390 100644 --- a/pairing/src/bls12_381/fq12.rs +++ b/src/bls12_381/fq12.rs @@ -2,7 +2,7 @@ use super::fq::FROBENIUS_COEFF_FQ12_C1; use super::fq2::Fq2; use super::fq6::Fq6; use ff::Field; -use rand::{Rand, Rng}; +use rand_core::RngCore; /// An element of Fq12, represented by c0 + c1 * w. #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -12,20 +12,11 @@ pub struct Fq12 { } impl ::std::fmt::Display for Fq12 { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "Fq12({} + {} * w)", self.c0, self.c1) } } -impl Rand for Fq12 { - fn rand(rng: &mut R) -> Self { - Fq12 { - c0: rng.gen(), - c1: rng.gen(), - } - } -} - impl Fq12 { pub fn conjugate(&mut self) { self.c1.negate(); @@ -49,6 +40,13 @@ impl Fq12 { } impl Field for Fq12 { + fn random(rng: &mut R) -> Self { + Fq12 { + c0: Fq6::random(rng), + c1: Fq6::random(rng), + } + } + fn zero() -> Self { Fq12 { c0: Fq6::zero(), @@ -149,24 +147,29 @@ impl Field for Fq12 { } #[cfg(test)] -use rand::{SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +#[cfg(test)] +use rand_xorshift::XorShiftRng; #[test] fn test_fq12_mul_by_014() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let c0 = Fq2::rand(&mut rng); - let c1 = Fq2::rand(&mut rng); - let c5 = Fq2::rand(&mut rng); - let mut a = Fq12::rand(&mut rng); + let c0 = Fq2::random(&mut rng); + let c1 = Fq2::random(&mut rng); + let c5 = Fq2::random(&mut rng); + let mut a = Fq12::random(&mut rng); let mut b = a; a.mul_by_014(&c0, &c1, &c5); b.mul_assign(&Fq12 { c0: Fq6 { - c0: c0, - c1: c1, + c0, + c1, c2: Fq2::zero(), }, c1: Fq6 { @@ -184,6 +187,6 @@ fn test_fq12_mul_by_014() { fn fq12_field_tests() { use ff::PrimeField; - ::tests::field::random_field_tests::(); - ::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); + crate::tests::field::random_field_tests::(); + crate::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); } diff --git a/pairing/src/bls12_381/fq2.rs b/src/bls12_381/fq2.rs similarity index 88% rename from pairing/src/bls12_381/fq2.rs rename to src/bls12_381/fq2.rs index 363439a..4fd391b 100644 --- a/pairing/src/bls12_381/fq2.rs +++ b/src/bls12_381/fq2.rs @@ -1,6 +1,6 @@ -use super::fq::{FROBENIUS_COEFF_FQ2_C1, Fq, NEGATIVE_ONE}; +use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE}; use ff::{Field, SqrtField}; -use rand::{Rand, Rng}; +use rand_core::RngCore; use std::cmp::Ordering; @@ -12,7 +12,7 @@ pub struct Fq2 { } impl ::std::fmt::Display for Fq2 { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "Fq2({} + {} * u)", self.c0, self.c1) } } @@ -56,16 +56,14 @@ impl Fq2 { } } -impl Rand for Fq2 { - fn rand(rng: &mut R) -> Self { +impl Field for Fq2 { + fn random(rng: &mut R) -> Self { Fq2 { - c0: rng.gen(), - c1: rng.gen(), + c0: Fq::random(rng), + c1: Fq::random(rng), } } -} -impl Field for Fq2 { fn zero() -> Self { Fq2 { c0: Fq::zero(), @@ -263,12 +261,11 @@ fn test_fq2_basics() { ); assert!(Fq2::zero().is_zero()); assert!(!Fq2::one().is_zero()); - assert!( - !Fq2 { - c0: Fq::zero(), - c1: Fq::one(), - }.is_zero() - ); + assert!(!Fq2 { + c0: Fq::zero(), + c1: Fq::one(), + } + .is_zero()); } #[test] @@ -311,7 +308,8 @@ fn test_fq2_squaring() { 0xf7f295a94e58ae7c, 0x41b76dcc1c3fbe5e, 0x7080c5fa1d8e042, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x38f473b3c870a4ab, 0x6ad3291177c8c7e5, @@ -319,7 +317,8 @@ fn test_fq2_squaring() { 0xbfb99020604137a0, 0xfc58a7b7be815407, 0x10d1615e75250a21, - ])).unwrap(), + ])) + .unwrap(), }; a.square(); assert_eq!( @@ -332,7 +331,8 @@ fn test_fq2_squaring() { 0xcb674157618da176, 0x4cf17b5893c3d327, 0x7eac81369c43361 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xc1579cf58e980cf8, 0xa23eb7e12dd54d98, @@ -340,7 +340,8 @@ fn test_fq2_squaring() { 0x38d0d7275a9689e1, 0x739c983042779a65, 0x1542a61c8a8db994 - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -358,7 +359,8 @@ fn test_fq2_mul() { 0x9ee53e7e84d7532e, 0x1c202d8ed97afb45, 0x51d3f9253e2516f, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xa7348a8b511aedcf, 0x143c215d8176b319, @@ -366,7 +368,8 @@ fn test_fq2_mul() { 0x9533e4a9a5158be, 0x7a5e1ecb676d65f9, 0x180c3ee46656b008, - ])).unwrap(), + ])) + .unwrap(), }; a.mul_assign(&Fq2 { c0: Fq::from_repr(FqRepr([ @@ -376,7 +379,8 @@ fn test_fq2_mul() { 0xcd460f9f0c23e430, 0x6c9110292bfa409, 0x2c93a72eb8af83e, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x4b1c3f936d8992d4, 0x1d2a72916dba4c8a, @@ -384,7 +388,8 @@ fn test_fq2_mul() { 0x57a06d3135a752ae, 0x634cd3c6c565096d, 0x19e17334d4e93558, - ])).unwrap(), + ])) + .unwrap(), }); assert_eq!( a, @@ -396,7 +401,8 @@ fn test_fq2_mul() { 0x5511fe4d84ee5f78, 0x5310a202d92f9963, 0x1751afbe166e5399 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x84af0e1bd630117a, 0x6c63cd4da2c2aa7, @@ -404,7 +410,8 @@ fn test_fq2_mul() { 0xc975106579c275ee, 0x33a9ac82ce4c5083, 0x1ef1a36c201589d - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -424,7 +431,8 @@ fn test_fq2_inverse() { 0x9ee53e7e84d7532e, 0x1c202d8ed97afb45, 0x51d3f9253e2516f, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xa7348a8b511aedcf, 0x143c215d8176b319, @@ -432,7 +440,8 @@ fn test_fq2_inverse() { 0x9533e4a9a5158be, 0x7a5e1ecb676d65f9, 0x180c3ee46656b008, - ])).unwrap(), + ])) + .unwrap(), }; let a = a.inverse().unwrap(); assert_eq!( @@ -445,7 +454,8 @@ fn test_fq2_inverse() { 0xdfba703293941c30, 0xa6c3d8f9586f2636, 0x1351ef01941b70c4 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x8c39fd76a8312cb4, 0x15d7b6b95defbff0, @@ -453,7 +463,8 @@ fn test_fq2_inverse() { 0xcbf651a0f367afb2, 0xdf4e54f0d3ef15a6, 0x103bdf241afb0019 - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -471,7 +482,8 @@ fn test_fq2_addition() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -479,7 +491,8 @@ fn test_fq2_addition() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837, - ])).unwrap(), + ])) + .unwrap(), }; a.add_assign(&Fq2 { c0: Fq::from_repr(FqRepr([ @@ -489,7 +502,8 @@ fn test_fq2_addition() { 0x3b88899a42a6318f, 0x986a4a62fa82a49d, 0x13ce433fa26027f5, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x66323bf80b58b9b9, 0xa1379b6facf6e596, @@ -497,7 +511,8 @@ fn test_fq2_addition() { 0x2236f55246d0d44d, 0x4c8c1800eb104566, 0x11d6e20e986c2085, - ])).unwrap(), + ])) + .unwrap(), }); assert_eq!( a, @@ -509,7 +524,8 @@ fn test_fq2_addition() { 0xf4ef57d604b6bca2, 0x65309427b3d5d090, 0x14c715d5553f01d2 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xfdb032e7d9079a94, 0x35a2809d15468d83, @@ -517,7 +533,8 @@ fn test_fq2_addition() { 0xd62fa51334f560fa, 0x9ad265eb46e01984, 0x1303f3465112c8bc - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -535,7 +552,8 @@ fn test_fq2_subtraction() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -543,7 +561,8 @@ fn test_fq2_subtraction() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837, - ])).unwrap(), + ])) + .unwrap(), }; a.sub_assign(&Fq2 { c0: Fq::from_repr(FqRepr([ @@ -553,7 +572,8 @@ fn test_fq2_subtraction() { 0x3b88899a42a6318f, 0x986a4a62fa82a49d, 0x13ce433fa26027f5, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x66323bf80b58b9b9, 0xa1379b6facf6e596, @@ -561,7 +581,8 @@ fn test_fq2_subtraction() { 0x2236f55246d0d44d, 0x4c8c1800eb104566, 0x11d6e20e986c2085, - ])).unwrap(), + ])) + .unwrap(), }); assert_eq!( a, @@ -573,7 +594,8 @@ fn test_fq2_subtraction() { 0xe255902672ef6c43, 0x7f77a718021c342d, 0x72ba14049fe9881 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xeb4abaf7c255d1cd, 0x11df49bc6cacc256, @@ -581,7 +603,8 @@ fn test_fq2_subtraction() { 0xf63905f39ad8cb1f, 0x4cd5dd9fb40b3b8f, 0x957411359ba6e4c - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -599,7 +622,8 @@ fn test_fq2_negation() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -607,7 +631,8 @@ fn test_fq2_negation() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837, - ])).unwrap(), + ])) + .unwrap(), }; a.negate(); assert_eq!( @@ -620,7 +645,8 @@ fn test_fq2_negation() { 0xab107d49317487ab, 0x7e555df189f880e3, 0x19083f5486a10cbd - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x228109103250c9d0, 0x8a411ad149045812, @@ -628,7 +654,8 @@ fn test_fq2_negation() { 0xb07e9bc405608611, 0xfcd559cbe77bd8b8, 0x18d400b280d93e62 - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -646,7 +673,8 @@ fn test_fq2_doubling() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -654,7 +682,8 @@ fn test_fq2_doubling() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837, - ])).unwrap(), + ])) + .unwrap(), }; a.double(); assert_eq!( @@ -667,7 +696,8 @@ fn test_fq2_doubling() { 0x72cd9c7784211627, 0x998c938972a657e7, 0x1f1a52b65bdb3b9 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x2efbeddf9b5dc1b6, 0x28d5ca5ad09f4fdb, @@ -675,7 +705,8 @@ fn test_fq2_doubling() { 0x67f15f81dc49195b, 0x9c8c9bd4b79fa83d, 0x25a226f714d506e - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -693,7 +724,8 @@ fn test_fq2_frobenius_map() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc, - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -701,7 +733,8 @@ fn test_fq2_frobenius_map() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837, - ])).unwrap(), + ])) + .unwrap(), }; a.frobenius_map(0); assert_eq!( @@ -714,7 +747,8 @@ fn test_fq2_frobenius_map() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -722,7 +756,8 @@ fn test_fq2_frobenius_map() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837 - ])).unwrap(), + ])) + .unwrap(), } ); a.frobenius_map(1); @@ -736,7 +771,8 @@ fn test_fq2_frobenius_map() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x228109103250c9d0, 0x8a411ad149045812, @@ -744,7 +780,8 @@ fn test_fq2_frobenius_map() { 0xb07e9bc405608611, 0xfcd559cbe77bd8b8, 0x18d400b280d93e62 - ])).unwrap(), + ])) + .unwrap(), } ); a.frobenius_map(1); @@ -758,7 +795,8 @@ fn test_fq2_frobenius_map() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -766,7 +804,8 @@ fn test_fq2_frobenius_map() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837 - ])).unwrap(), + ])) + .unwrap(), } ); a.frobenius_map(2); @@ -780,7 +819,8 @@ fn test_fq2_frobenius_map() { 0xb966ce3bc2108b13, 0xccc649c4b9532bf3, 0xf8d295b2ded9dc - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0x977df6efcdaee0db, 0x946ae52d684fa7ed, @@ -788,7 +828,8 @@ fn test_fq2_frobenius_map() { 0xb3f8afc0ee248cad, 0x4e464dea5bcfd41e, 0x12d1137b8a6a837 - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -807,7 +848,8 @@ fn test_fq2_sqrt() { 0xdb4a116b5bf74aa1, 0x1e58b2159dfe10e2, 0x7ca7da1f13606ac - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xfa8de88b7516d2c3, 0x371a75ed14f41629, @@ -815,9 +857,11 @@ fn test_fq2_sqrt() { 0x212611bca4e99121, 0x8ee5394d77afb3d, 0xec92336650e49d5 - ])).unwrap(), - }.sqrt() + ])) .unwrap(), + } + .sqrt() + .unwrap(), Fq2 { c0: Fq::from_repr(FqRepr([ 0x40b299b2704258c5, @@ -826,7 +870,8 @@ fn test_fq2_sqrt() { 0x8d7f1f723d02c1d3, 0x881b3e01b611c070, 0x10f6963bbad2ebc5 - ])).unwrap(), + ])) + .unwrap(), c1: Fq::from_repr(FqRepr([ 0xc099534fc209e752, 0x7670594665676447, @@ -834,7 +879,8 @@ fn test_fq2_sqrt() { 0x6b852aeaf2afcb1b, 0xa4c93b08105d71a9, 0x8d7cfff94216330 - ])).unwrap(), + ])) + .unwrap(), } ); @@ -847,10 +893,12 @@ fn test_fq2_sqrt() { 0x64774b84f38512bf, 0x4b1ba7b6434bacd7, 0x1a0111ea397fe69a - ])).unwrap(), - c1: Fq::zero(), - }.sqrt() + ])) .unwrap(), + c1: Fq::zero(), + } + .sqrt() + .unwrap(), Fq2 { c0: Fq::zero(), c1: Fq::from_repr(FqRepr([ @@ -860,7 +908,8 @@ fn test_fq2_sqrt() { 0x64774b84f38512bf, 0x4b1ba7b6434bacd7, 0x1a0111ea397fe69a - ])).unwrap(), + ])) + .unwrap(), } ); } @@ -879,11 +928,16 @@ fn test_fq2_legendre() { } #[cfg(test)] -use rand::{SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +#[cfg(test)] +use rand_xorshift::XorShiftRng; #[test] fn test_fq2_mul_nonresidue() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let nqr = Fq2 { c0: Fq::one(), @@ -891,7 +945,7 @@ fn test_fq2_mul_nonresidue() { }; for _ in 0..1000 { - let mut a = Fq2::rand(&mut rng); + let mut a = Fq2::random(&mut rng); let mut b = a; a.mul_by_nonresidue(); b.mul_assign(&nqr); @@ -904,7 +958,7 @@ fn test_fq2_mul_nonresidue() { fn fq2_field_tests() { use ff::PrimeField; - ::tests::field::random_field_tests::(); - ::tests::field::random_sqrt_tests::(); - ::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); + crate::tests::field::random_field_tests::(); + crate::tests::field::random_sqrt_tests::(); + crate::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); } diff --git a/pairing/src/bls12_381/fq6.rs b/src/bls12_381/fq6.rs similarity index 85% rename from pairing/src/bls12_381/fq6.rs rename to src/bls12_381/fq6.rs index 36c6e28..92128ca 100644 --- a/pairing/src/bls12_381/fq6.rs +++ b/src/bls12_381/fq6.rs @@ -1,7 +1,7 @@ use super::fq::{FROBENIUS_COEFF_FQ6_C1, FROBENIUS_COEFF_FQ6_C2}; use super::fq2::Fq2; use ff::Field; -use rand::{Rand, Rng}; +use rand_core::RngCore; /// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2). #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -12,21 +12,11 @@ pub struct Fq6 { } impl ::std::fmt::Display for Fq6 { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "Fq6({} + {} * v, {} * v^2)", self.c0, self.c1, self.c2) } } -impl Rand for Fq6 { - fn rand(rng: &mut R) -> Self { - Fq6 { - c0: rng.gen(), - c1: rng.gen(), - c2: rng.gen(), - } - } -} - impl Fq6 { /// Multiply by quadratic nonresidue v. pub fn mul_by_nonresidue(&mut self) { @@ -110,6 +100,14 @@ impl Fq6 { } impl Field for Fq6 { + fn random(rng: &mut R) -> Self { + Fq6 { + c0: Fq2::random(rng), + c1: Fq2::random(rng), + c2: Fq2::random(rng), + } + } + fn zero() -> Self { Fq6 { c0: Fq2::zero(), @@ -302,11 +300,16 @@ impl Field for Fq6 { } #[cfg(test)] -use rand::{SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +#[cfg(test)] +use rand_xorshift::XorShiftRng; #[test] fn test_fq6_mul_nonresidue() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let nqr = Fq6 { c0: Fq2::zero(), @@ -315,7 +318,7 @@ fn test_fq6_mul_nonresidue() { }; for _ in 0..1000 { - let mut a = Fq6::rand(&mut rng); + let mut a = Fq6::random(&mut rng); let mut b = a; a.mul_by_nonresidue(); b.mul_assign(&nqr); @@ -326,17 +329,20 @@ fn test_fq6_mul_nonresidue() { #[test] fn test_fq6_mul_by_1() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let c1 = Fq2::rand(&mut rng); - let mut a = Fq6::rand(&mut rng); + let c1 = Fq2::random(&mut rng); + let mut a = Fq6::random(&mut rng); let mut b = a; a.mul_by_1(&c1); b.mul_assign(&Fq6 { c0: Fq2::zero(), - c1: c1, + c1, c2: Fq2::zero(), }); @@ -346,18 +352,21 @@ fn test_fq6_mul_by_1() { #[test] fn test_fq6_mul_by_01() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let c0 = Fq2::rand(&mut rng); - let c1 = Fq2::rand(&mut rng); - let mut a = Fq6::rand(&mut rng); + let c0 = Fq2::random(&mut rng); + let c1 = Fq2::random(&mut rng); + let mut a = Fq6::random(&mut rng); let mut b = a; a.mul_by_01(&c0, &c1); b.mul_assign(&Fq6 { - c0: c0, - c1: c1, + c0, + c1, c2: Fq2::zero(), }); @@ -369,6 +378,6 @@ fn test_fq6_mul_by_01() { fn fq6_field_tests() { use ff::PrimeField; - ::tests::field::random_field_tests::(); - ::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); + crate::tests::field::random_field_tests::(); + crate::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); } diff --git a/pairing/src/bls12_381/fr.rs b/src/bls12_381/fr.rs similarity index 83% rename from pairing/src/bls12_381/fr.rs rename to src/bls12_381/fr.rs index 5e57631..76f3ffe 100644 --- a/pairing/src/bls12_381/fr.rs +++ b/src/bls12_381/fr.rs @@ -6,7 +6,9 @@ use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr}; pub struct Fr(FrRepr); #[cfg(test)] -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +#[cfg(test)] +use rand_xorshift::XorShiftRng; #[test] fn test_fr_repr_ordering() { @@ -197,7 +199,10 @@ fn test_fr_repr_num_bits() { #[test] fn test_fr_repr_sub_noborrow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let mut t = FrRepr([ 0x8e62a7e85264e2c3, @@ -221,7 +226,7 @@ fn test_fr_repr_sub_noborrow() { ); for _ in 0..1000 { - let mut a = FrRepr::rand(&mut rng); + let mut a = Fr::random(&mut rng).into_repr(); a.0[3] >>= 30; let mut b = a; for _ in 0..10 { @@ -296,7 +301,10 @@ fn test_fr_legendre() { #[test] fn test_fr_repr_add_nocarry() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let mut t = FrRepr([ 0xd64f669809cbc6a4, @@ -322,9 +330,9 @@ fn test_fr_repr_add_nocarry() { // Test for the associativity of addition. for _ in 0..1000 { - let mut a = FrRepr::rand(&mut rng); - let mut b = FrRepr::rand(&mut rng); - let mut c = FrRepr::rand(&mut rng); + let mut a = Fr::random(&mut rng).into_repr(); + let mut b = Fr::random(&mut rng).into_repr(); + let mut c = Fr::random(&mut rng).into_repr(); // Unset the first few bits, so that overflow won't occur. a.0[3] >>= 3; @@ -380,27 +388,28 @@ fn test_fr_is_valid() { a.0.sub_noborrow(&FrRepr::from(1)); assert!(a.is_valid()); assert!(Fr(FrRepr::from(0)).is_valid()); - assert!( - Fr(FrRepr([ - 0xffffffff00000000, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48 - ])).is_valid() - ); - assert!( - !Fr(FrRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff - ])).is_valid() - ); + assert!(Fr(FrRepr([ + 0xffffffff00000000, + 0x53bda402fffe5bfe, + 0x3339d80809a1d805, + 0x73eda753299d7d48 + ])) + .is_valid()); + assert!(!Fr(FrRepr([ + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff + ])) + .is_valid()); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let a = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); assert!(a.is_valid()); } } @@ -492,13 +501,16 @@ fn test_fr_add_assign() { // Test associativity - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Generate a, b, c and ensure (a + b) + c == a + (b + c). - let a = Fr::rand(&mut rng); - let b = Fr::rand(&mut rng); - let c = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); + let b = Fr::random(&mut rng); + let c = Fr::random(&mut rng); let mut tmp1 = a; tmp1.add_assign(&b); @@ -586,12 +598,15 @@ fn test_fr_sub_assign() { ); } - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Ensure that (a - b) + (b - a) = 0. - let a = Fr::rand(&mut rng); - let b = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); + let b = Fr::random(&mut rng); let mut tmp1 = a; tmp1.sub_assign(&b); @@ -627,13 +642,16 @@ fn test_fr_mul_assign() { ])) ); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000000 { // Ensure that (a * b) * c = a * (b * c) - let a = Fr::rand(&mut rng); - let b = Fr::rand(&mut rng); - let c = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); + let b = Fr::random(&mut rng); + let c = Fr::random(&mut rng); let mut tmp1 = a; tmp1.mul_assign(&b); @@ -649,10 +667,10 @@ fn test_fr_mul_assign() { for _ in 0..1000000 { // Ensure that r * (a + b + c) = r*a + r*b + r*c - let r = Fr::rand(&mut rng); - let mut a = Fr::rand(&mut rng); - let mut b = Fr::rand(&mut rng); - let mut c = Fr::rand(&mut rng); + let r = Fr::random(&mut rng); + let mut a = Fr::random(&mut rng); + let mut b = Fr::random(&mut rng); + let mut c = Fr::random(&mut rng); let mut tmp1 = a; tmp1.add_assign(&b); @@ -687,14 +705,18 @@ fn test_fr_squaring() { 0xb79a310579e76ec2, 0xac1da8d0a9af4e5f, 0x13f629c49bf23e97 - ])).unwrap() + ])) + .unwrap() ); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000000 { // Ensure that (a * a) = a^2 - let a = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); let mut tmp = a; tmp.square(); @@ -710,13 +732,16 @@ fn test_fr_squaring() { fn test_fr_inverse() { assert!(Fr::zero().inverse().is_none()); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); let one = Fr::one(); for _ in 0..1000 { // Ensure that a * a^-1 = 1 - let mut a = Fr::rand(&mut rng); + let mut a = Fr::random(&mut rng); let ainv = a.inverse().unwrap(); a.mul_assign(&ainv); assert_eq!(a, one); @@ -725,11 +750,14 @@ fn test_fr_inverse() { #[test] fn test_fr_double() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Ensure doubling a is equivalent to adding a to itself. - let mut a = Fr::rand(&mut rng); + let mut a = Fr::random(&mut rng); let mut b = a; b.add_assign(&a); a.double(); @@ -746,11 +774,14 @@ fn test_fr_negate() { assert!(a.is_zero()); } - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Ensure (a - (-a)) = 0. - let mut a = Fr::rand(&mut rng); + let mut a = Fr::random(&mut rng); let mut b = a; b.negate(); a.add_assign(&b); @@ -761,12 +792,15 @@ fn test_fr_negate() { #[test] fn test_fr_pow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for i in 0..1000 { // Exponentiate by various small numbers and ensure it consists with repeated // multiplication. - let a = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); let target = a.pow(&[i]); let mut c = Fr::one(); for _ in 0..i { @@ -777,7 +811,7 @@ fn test_fr_pow() { for _ in 0..1000 { // Exponentiating by the modulus should have no effect in a prime field. - let a = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); assert_eq!(a, a.pow(Fr::char())); } @@ -787,13 +821,16 @@ fn test_fr_pow() { fn test_fr_sqrt() { use ff::SqrtField; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); assert_eq!(Fr::zero().sqrt().unwrap(), Fr::zero()); for _ in 0..1000 { // Ensure sqrt(a^2) = a or -a - let a = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); let mut nega = a; nega.negate(); let mut b = a; @@ -806,7 +843,7 @@ fn test_fr_sqrt() { for _ in 0..1000 { // Ensure sqrt(a)^2 = a for random a - let a = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); if let Some(mut tmp) = a.sqrt() { tmp.square(); @@ -819,14 +856,13 @@ fn test_fr_sqrt() { #[test] fn test_fr_from_into_repr() { // r + 1 should not be in the field - assert!( - Fr::from_repr(FrRepr([ - 0xffffffff00000002, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48 - ])).is_err() - ); + assert!(Fr::from_repr(FrRepr([ + 0xffffffff00000002, + 0x53bda402fffe5bfe, + 0x3339d80809a1d805, + 0x73eda753299d7d48 + ])) + .is_err()); // r should not be in the field assert!(Fr::from_repr(Fr::char()).is_err()); @@ -858,11 +894,14 @@ fn test_fr_from_into_repr() { // Zero should be in the field. assert!(Fr::from_repr(FrRepr::from(0)).unwrap().is_zero()); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { // Try to turn Fr elements into representations and back again, and compare. - let a = Fr::rand(&mut rng); + let a = Fr::random(&mut rng); let a_repr = a.into_repr(); let b_repr = FrRepr::from(a); assert_eq!(a_repr, b_repr); @@ -926,7 +965,8 @@ fn test_fr_display() { 0x185ec8eb3f5b5aee, 0x684499ffe4b9dd99, 0x7c9bba7afb68faa - ])).unwrap() + ])) + .unwrap() ), "Fr(0x07c9bba7afb68faa684499ffe4b9dd99185ec8eb3f5b5aeec3cae746a3b5ecc7)".to_string() ); @@ -938,7 +978,8 @@ fn test_fr_display() { 0xb0ad10817df79b6a, 0xd034a80a2b74132b, 0x41cf9a1336f50719 - ])).unwrap() + ])) + .unwrap() ), "Fr(0x41cf9a1336f50719d034a80a2b74132bb0ad10817df79b6a44c71298ff198106)".to_string() ); @@ -974,13 +1015,13 @@ fn test_fr_root_of_unity() { #[test] fn fr_field_tests() { - ::tests::field::random_field_tests::(); - ::tests::field::random_sqrt_tests::(); - ::tests::field::random_frobenius_tests::(Fr::char(), 13); - ::tests::field::from_str_tests::(); + crate::tests::field::random_field_tests::(); + crate::tests::field::random_sqrt_tests::(); + crate::tests::field::random_frobenius_tests::(Fr::char(), 13); + crate::tests::field::from_str_tests::(); } #[test] fn fr_repr_tests() { - ::tests::repr::random_repr_tests::(); + crate::tests::repr::random_repr_tests::(); } diff --git a/pairing/src/bls12_381/mod.rs b/src/bls12_381/mod.rs similarity index 97% rename from pairing/src/bls12_381/mod.rs rename to src/bls12_381/mod.rs index 7bc03c6..e6e88dd 100644 --- a/pairing/src/bls12_381/mod.rs +++ b/src/bls12_381/mod.rs @@ -1,3 +1,6 @@ +//! An implementation of the BLS12-381 pairing-friendly elliptic curve +//! construction. + mod ec; mod fq; mod fq12; @@ -9,8 +12,8 @@ mod fr; mod tests; pub use self::ec::{ - G1, G1Affine, G1Compressed, G1Prepared, G1Uncompressed, G2, G2Affine, G2Compressed, G2Prepared, - G2Uncompressed, + G1Affine, G1Compressed, G1Prepared, G1Uncompressed, G2Affine, G2Compressed, G2Prepared, + G2Uncompressed, G1, G2, }; pub use self::fq::{Fq, FqRepr}; pub use self::fq12::Fq12; @@ -366,5 +369,5 @@ impl G2Prepared { #[test] fn bls12_engine_tests() { - ::tests::engine::engine_tests::(); + crate::tests::engine::engine_tests::(); } diff --git a/pairing/src/bls12_381/tests/g1_compressed_valid_test_vectors.dat b/src/bls12_381/tests/g1_compressed_valid_test_vectors.dat similarity index 100% rename from pairing/src/bls12_381/tests/g1_compressed_valid_test_vectors.dat rename to src/bls12_381/tests/g1_compressed_valid_test_vectors.dat diff --git a/pairing/src/bls12_381/tests/g1_uncompressed_invalid_test_vectors.dat b/src/bls12_381/tests/g1_uncompressed_invalid_test_vectors.dat similarity index 100% rename from pairing/src/bls12_381/tests/g1_uncompressed_invalid_test_vectors.dat rename to src/bls12_381/tests/g1_uncompressed_invalid_test_vectors.dat diff --git a/pairing/src/bls12_381/tests/g1_uncompressed_valid_test_vectors.dat b/src/bls12_381/tests/g1_uncompressed_valid_test_vectors.dat similarity index 100% rename from pairing/src/bls12_381/tests/g1_uncompressed_valid_test_vectors.dat rename to src/bls12_381/tests/g1_uncompressed_valid_test_vectors.dat diff --git a/pairing/src/bls12_381/tests/g2_compressed_valid_test_vectors.dat b/src/bls12_381/tests/g2_compressed_valid_test_vectors.dat similarity index 100% rename from pairing/src/bls12_381/tests/g2_compressed_valid_test_vectors.dat rename to src/bls12_381/tests/g2_compressed_valid_test_vectors.dat diff --git a/pairing/src/bls12_381/tests/g2_uncompressed_valid_test_vectors.dat b/src/bls12_381/tests/g2_uncompressed_valid_test_vectors.dat similarity index 100% rename from pairing/src/bls12_381/tests/g2_uncompressed_valid_test_vectors.dat rename to src/bls12_381/tests/g2_uncompressed_valid_test_vectors.dat diff --git a/pairing/src/bls12_381/tests/mod.rs b/src/bls12_381/tests/mod.rs similarity index 99% rename from pairing/src/bls12_381/tests/mod.rs rename to src/bls12_381/tests/mod.rs index b5b75a3..636fcfe 100644 --- a/pairing/src/bls12_381/tests/mod.rs +++ b/src/bls12_381/tests/mod.rs @@ -2,7 +2,7 @@ use ff::PrimeFieldRepr; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use super::*; -use *; +use crate::*; #[test] fn test_pairing_result_against_relic() { diff --git a/pairing/src/lib.rs b/src/lib.rs similarity index 78% rename from pairing/src/lib.rs rename to src/lib.rs index adabcce..89e5873 100644 --- a/pairing/src/lib.rs +++ b/src/lib.rs @@ -1,22 +1,20 @@ +//! A library for working with pairing-friendly curves. + // `clippy` is a code linting tool for improving code quality by catching // common mistakes or strange code patterns. If the `cargo-clippy` feature // is provided, all compiler warnings are prohibited. #![cfg_attr(feature = "cargo-clippy", deny(warnings))] -#![cfg_attr(feature = "cargo-clippy", allow(inline_always))] -#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] -#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] -#![cfg_attr(feature = "cargo-clippy", allow(many_single_char_names))] -#![cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))] -#![cfg_attr(feature = "cargo-clippy", allow(write_literal))] +#![cfg_attr(feature = "cargo-clippy", allow(clippy::inline_always))] +#![cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))] +#![cfg_attr(feature = "cargo-clippy", allow(clippy::unreadable_literal))] +#![cfg_attr(feature = "cargo-clippy", allow(clippy::many_single_char_names))] +#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))] +#![cfg_attr(feature = "cargo-clippy", allow(clippy::write_literal))] +// Catch documentation errors caused by code changes. +#![deny(intra_doc_link_resolution_failure)] // Force public structures to implement Debug #![deny(missing_debug_implementations)] -extern crate byteorder; -#[macro_use] -extern crate ff; -extern crate group; -extern crate rand; - #[cfg(test)] pub mod tests; @@ -35,8 +33,7 @@ pub trait Engine: ScalarEngine { Base = Self::Fq, Scalar = Self::Fr, Affine = Self::G1Affine, - > - + From; + > + From; /// The affine representation of an element in G1. type G1Affine: PairingCurveAffine< @@ -46,8 +43,7 @@ pub trait Engine: ScalarEngine { Projective = Self::G1, Pair = Self::G2Affine, PairingResult = Self::Fqk, - > - + From; + > + From; /// The projective representation of an element in G2. type G2: CurveProjective< @@ -55,8 +51,7 @@ pub trait Engine: ScalarEngine { Base = Self::Fqe, Scalar = Self::Fr, Affine = Self::G2Affine, - > - + From; + > + From; /// The affine representation of an element in G2. type G2Affine: PairingCurveAffine< @@ -66,8 +61,7 @@ pub trait Engine: ScalarEngine { Projective = Self::G2, Pair = Self::G1Affine, PairingResult = Self::Fqk, - > - + From; + > + From; /// The base field that hosts G1. type Fq: PrimeField + SqrtField; @@ -89,7 +83,7 @@ pub trait Engine: ScalarEngine { >; /// Perform final exponentiation of the result of a miller loop. - fn final_exponentiation(&Self::Fqk) -> Option; + fn final_exponentiation(_: &Self::Fqk) -> Option; /// Performs a complete pairing operation `(p, q)`. fn pairing(p: G1, q: G2) -> Self::Fqk @@ -98,8 +92,9 @@ pub trait Engine: ScalarEngine { G2: Into, { Self::final_exponentiation(&Self::miller_loop( - [(&(p.into().prepare()), &(q.into().prepare()))].into_iter(), - )).unwrap() + [(&(p.into().prepare()), &(q.into().prepare()))].iter(), + )) + .unwrap() } } diff --git a/pairing/src/tests/engine.rs b/src/tests/engine.rs similarity index 64% rename from pairing/src/tests/engine.rs rename to src/tests/engine.rs index 7b1944d..b6ae50e 100644 --- a/pairing/src/tests/engine.rs +++ b/src/tests/engine.rs @@ -1,14 +1,18 @@ use group::{CurveAffine, CurveProjective}; -use rand::{Rand, SeedableRng, XorShiftRng}; +use rand_core::SeedableRng; +use rand_xorshift::XorShiftRng; -use {Engine, Field, PairingCurveAffine, PrimeField}; +use crate::{Engine, Field, PairingCurveAffine, PrimeField}; pub fn engine_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..10 { - let a = E::G1::rand(&mut rng).into_affine(); - let b = E::G2::rand(&mut rng).into_affine(); + let a = E::G1::random(&mut rng).into_affine(); + let b = E::G2::random(&mut rng).into_affine(); assert!(a.pairing_with(&b) == b.pairing_with(&a)); assert!(a.pairing_with(&b) == E::pairing(a, b)); @@ -18,10 +22,10 @@ pub fn engine_tests() { let z1 = E::G1Affine::zero().prepare(); let z2 = E::G2Affine::zero().prepare(); - let a = E::G1::rand(&mut rng).into_affine().prepare(); - let b = E::G2::rand(&mut rng).into_affine().prepare(); - let c = E::G1::rand(&mut rng).into_affine().prepare(); - let d = E::G2::rand(&mut rng).into_affine().prepare(); + let a = E::G1::random(&mut rng).into_affine().prepare(); + let b = E::G2::random(&mut rng).into_affine().prepare(); + let c = E::G1::random(&mut rng).into_affine().prepare(); + let d = E::G2::random(&mut rng).into_affine().prepare(); assert_eq!( E::Fqk::one(), @@ -49,12 +53,15 @@ pub fn engine_tests() { } fn random_miller_loop_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); // Exercise the miller loop for a reduced pairing for _ in 0..1000 { - let a = E::G1::rand(&mut rng); - let b = E::G2::rand(&mut rng); + let a = E::G1::random(&mut rng); + let b = E::G2::random(&mut rng); let p2 = E::pairing(a, b); @@ -68,10 +75,10 @@ fn random_miller_loop_tests() { // Exercise a double miller loop for _ in 0..1000 { - let a = E::G1::rand(&mut rng); - let b = E::G2::rand(&mut rng); - let c = E::G1::rand(&mut rng); - let d = E::G2::rand(&mut rng); + let a = E::G1::random(&mut rng); + let b = E::G2::random(&mut rng); + let c = E::G1::random(&mut rng); + let d = E::G2::random(&mut rng); let ab = E::pairing(a, b); let cd = E::pairing(c, d); @@ -92,14 +99,17 @@ fn random_miller_loop_tests() { } fn random_bilinearity_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let a = E::G1::rand(&mut rng); - let b = E::G2::rand(&mut rng); + let a = E::G1::random(&mut rng); + let b = E::G2::random(&mut rng); - let c = E::Fr::rand(&mut rng); - let d = E::Fr::rand(&mut rng); + let c = E::Fr::random(&mut rng); + let d = E::Fr::random(&mut rng); let mut ac = a; ac.mul_assign(c); diff --git a/pairing/src/tests/field.rs b/src/tests/field.rs similarity index 72% rename from pairing/src/tests/field.rs rename to src/tests/field.rs index 55396a7..8f3d8d9 100644 --- a/pairing/src/tests/field.rs +++ b/src/tests/field.rs @@ -1,12 +1,16 @@ use ff::{Field, LegendreSymbol, PrimeField, SqrtField}; -use rand::{Rng, SeedableRng, XorShiftRng}; +use rand_core::{RngCore, SeedableRng}; +use rand_xorshift::XorShiftRng; pub fn random_frobenius_tests>(characteristic: C, maxpower: usize) { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { for i in 0..(maxpower + 1) { - let mut a = F::rand(&mut rng); + let mut a = F::random(&mut rng); let mut b = a; for _ in 0..i { @@ -20,10 +24,13 @@ pub fn random_frobenius_tests>(characteristic: C, maxp } pub fn random_sqrt_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..10000 { - let a = F::rand(&mut rng); + let a = F::random(&mut rng); let mut b = a; b.square(); assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); @@ -54,7 +61,10 @@ pub fn random_sqrt_tests() { } pub fn random_field_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); random_multiplication_tests::(&mut rng); random_addition_tests::(&mut rng); @@ -76,14 +86,14 @@ pub fn random_field_tests() { // Multiplication by zero { - let mut a = F::rand(&mut rng); + let mut a = F::random(&mut rng); a.mul_assign(&F::zero()); assert!(a.is_zero()); } // Addition by zero { - let mut a = F::rand(&mut rng); + let mut a = F::random(&mut rng); let copy = a; a.add_assign(&F::zero()); assert_eq!(a, copy); @@ -106,10 +116,13 @@ pub fn from_str_tests() { } { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); for _ in 0..1000 { - let n: u64 = rng.gen(); + let n = rng.next_u64(); let a = F::from_str(&format!("{}", n)).unwrap(); let b = F::from_repr(n.into()).unwrap(); @@ -124,11 +137,11 @@ pub fn from_str_tests() { assert!(F::from_str("00000000000").is_none()); } -fn random_multiplication_tests(rng: &mut R) { +fn random_multiplication_tests(rng: &mut R) { for _ in 0..10000 { - let a = F::rand(rng); - let b = F::rand(rng); - let c = F::rand(rng); + let a = F::random(rng); + let b = F::random(rng); + let c = F::random(rng); let mut t0 = a; // (a * b) * c t0.mul_assign(&b); @@ -147,11 +160,11 @@ fn random_multiplication_tests(rng: &mut R) { } } -fn random_addition_tests(rng: &mut R) { +fn random_addition_tests(rng: &mut R) { for _ in 0..10000 { - let a = F::rand(rng); - let b = F::rand(rng); - let c = F::rand(rng); + let a = F::random(rng); + let b = F::random(rng); + let c = F::random(rng); let mut t0 = a; // (a + b) + c t0.add_assign(&b); @@ -170,10 +183,10 @@ fn random_addition_tests(rng: &mut R) { } } -fn random_subtraction_tests(rng: &mut R) { +fn random_subtraction_tests(rng: &mut R) { for _ in 0..10000 { - let a = F::rand(rng); - let b = F::rand(rng); + let b = F::random(rng); + let a = F::random(rng); let mut t0 = a; // (a - b) t0.sub_assign(&b); @@ -188,9 +201,9 @@ fn random_subtraction_tests(rng: &mut R) { } } -fn random_negation_tests(rng: &mut R) { +fn random_negation_tests(rng: &mut R) { for _ in 0..10000 { - let a = F::rand(rng); + let a = F::random(rng); let mut b = a; b.negate(); b.add_assign(&a); @@ -199,9 +212,9 @@ fn random_negation_tests(rng: &mut R) { } } -fn random_doubling_tests(rng: &mut R) { +fn random_doubling_tests(rng: &mut R) { for _ in 0..10000 { - let mut a = F::rand(rng); + let mut a = F::random(rng); let mut b = a; a.add_assign(&b); b.double(); @@ -210,9 +223,9 @@ fn random_doubling_tests(rng: &mut R) { } } -fn random_squaring_tests(rng: &mut R) { +fn random_squaring_tests(rng: &mut R) { for _ in 0..10000 { - let mut a = F::rand(rng); + let mut a = F::random(rng); let mut b = a; a.mul_assign(&b); b.square(); @@ -221,11 +234,11 @@ fn random_squaring_tests(rng: &mut R) { } } -fn random_inversion_tests(rng: &mut R) { +fn random_inversion_tests(rng: &mut R) { assert!(F::zero().inverse().is_none()); for _ in 0..10000 { - let mut a = F::rand(rng); + let mut a = F::random(rng); let b = a.inverse().unwrap(); // probablistically nonzero a.mul_assign(&b); @@ -233,14 +246,14 @@ fn random_inversion_tests(rng: &mut R) { } } -fn random_expansion_tests(rng: &mut R) { +fn random_expansion_tests(rng: &mut R) { for _ in 0..10000 { // Compare (a + b)(c + d) and (a*c + b*c + a*d + b*d) - let a = F::rand(rng); - let b = F::rand(rng); - let c = F::rand(rng); - let d = F::rand(rng); + let a = F::random(rng); + let b = F::random(rng); + let c = F::random(rng); + let d = F::random(rng); let mut t0 = a; t0.add_assign(&b); diff --git a/pairing/src/tests/mod.rs b/src/tests/mod.rs similarity index 100% rename from pairing/src/tests/mod.rs rename to src/tests/mod.rs diff --git a/pairing/src/tests/repr.rs b/src/tests/repr.rs similarity index 54% rename from pairing/src/tests/repr.rs rename to src/tests/repr.rs index 09dd441..67badd8 100644 --- a/pairing/src/tests/repr.rs +++ b/src/tests/repr.rs @@ -1,21 +1,25 @@ -use ff::PrimeFieldRepr; -use rand::{SeedableRng, XorShiftRng}; +use ff::{PrimeField, PrimeFieldRepr}; +use rand_core::SeedableRng; +use rand_xorshift::XorShiftRng; -pub fn random_repr_tests() { - random_encoding_tests::(); - random_shl_tests::(); - random_shr_tests::(); +pub fn random_repr_tests() { + random_encoding_tests::

(); + random_shl_tests::

(); + random_shr_tests::

(); } -fn random_encoding_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); +fn random_encoding_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..1000 { - let r = R::rand(&mut rng); + let r = P::random(&mut rng).into_repr(); // Big endian { - let mut rdecoded = R::default(); + let mut rdecoded =

::Repr::default(); let mut v: Vec = vec![]; r.write_be(&mut v).unwrap(); @@ -26,7 +30,7 @@ fn random_encoding_tests() { // Little endian { - let mut rdecoded = R::default(); + let mut rdecoded =

::Repr::default(); let mut v: Vec = vec![]; r.write_le(&mut v).unwrap(); @@ -36,8 +40,8 @@ fn random_encoding_tests() { } { - let mut rdecoded_le = R::default(); - let mut rdecoded_be_flip = R::default(); + let mut rdecoded_le =

::Repr::default(); + let mut rdecoded_be_flip =

::Repr::default(); let mut v: Vec = vec![]; r.write_le(&mut v).unwrap(); @@ -55,11 +59,14 @@ fn random_encoding_tests() { } } -fn random_shl_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); +fn random_shl_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { - let r = R::rand(&mut rng); + let r = P::random(&mut rng).into_repr(); for shift in 0..(r.num_bits() + 1) { let mut r1 = r; @@ -76,11 +83,14 @@ fn random_shl_tests() { } } -fn random_shr_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); +fn random_shr_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); for _ in 0..100 { - let r = R::rand(&mut rng); + let r = P::random(&mut rng).into_repr(); for shift in 0..(r.num_bits() + 1) { let mut r1 = r; diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml deleted file mode 100644 index bf6c03f..0000000 --- a/zcash_primitives/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "zcash_primitives" -version = "0.0.0" -authors = [ - "Jack Grigg ", -] - -[dependencies] -byteorder = "1" -lazy_static = "1" -pairing = { path = "../pairing" } -rand = "0.4" -sapling-crypto = { path = "../sapling-crypto" } - -[dependencies.blake2-rfc] -git = "https://github.com/gtank/blake2-rfc" -rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" diff --git a/zcash_primitives/LICENSE-APACHE b/zcash_primitives/LICENSE-APACHE deleted file mode 100644 index 1e5006d..0000000 --- a/zcash_primitives/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. - diff --git a/zcash_primitives/LICENSE-MIT b/zcash_primitives/LICENSE-MIT deleted file mode 100644 index 5b7be8e..0000000 --- a/zcash_primitives/LICENSE-MIT +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017 Zcash Company - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/zcash_primitives/README.md b/zcash_primitives/README.md deleted file mode 100644 index b284820..0000000 --- a/zcash_primitives/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# zcash_primitives - -This library contains Rust implementations of the Zcash primitives. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. - diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs deleted file mode 100644 index 5f4dd05..0000000 --- a/zcash_primitives/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -#[macro_use] -extern crate lazy_static; - -extern crate blake2_rfc; -extern crate byteorder; -extern crate pairing; -extern crate rand; -extern crate sapling_crypto; - -use sapling_crypto::jubjub::JubjubBls12; - -mod serialize; -pub mod transaction; - -lazy_static! { - static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() }; -} diff --git a/zcash_primitives/src/serialize.rs b/zcash_primitives/src/serialize.rs deleted file mode 100644 index f142943..0000000 --- a/zcash_primitives/src/serialize.rs +++ /dev/null @@ -1,156 +0,0 @@ -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use std::io::{self, Read, Write}; - -const MAX_SIZE: usize = 0x02000000; - -struct CompactSize; - -impl CompactSize { - fn read(mut reader: R) -> io::Result { - let flag = reader.read_u8()?; - match if flag < 253 { - Ok(flag as usize) - } else if flag == 253 { - match reader.read_u16::()? { - n if n < 253 => Err(io::Error::new( - io::ErrorKind::InvalidInput, - "non-canonical CompactSize", - )), - n => Ok(n as usize), - } - } else if flag == 254 { - match reader.read_u32::()? { - n if n < 0x10000 => Err(io::Error::new( - io::ErrorKind::InvalidInput, - "non-canonical CompactSize", - )), - n => Ok(n as usize), - } - } else { - match reader.read_u64::()? { - n if n < 0x100000000 => Err(io::Error::new( - io::ErrorKind::InvalidInput, - "non-canonical CompactSize", - )), - n => Ok(n as usize), - } - }? { - s if s > MAX_SIZE => Err(io::Error::new( - io::ErrorKind::InvalidInput, - "CompactSize too large", - )), - s => Ok(s), - } - } - - fn write(mut writer: W, size: usize) -> io::Result<()> { - match size { - s if s < 253 => writer.write_u8(s as u8), - s if s <= 0xFFFF => { - writer.write_u8(253)?; - writer.write_u16::(s as u16) - } - s if s <= 0xFFFFFFFF => { - writer.write_u8(254)?; - writer.write_u32::(s as u32) - } - s => { - writer.write_u8(255)?; - writer.write_u64::(s as u64) - } - } - } -} - -pub struct Vector; - -impl Vector { - pub fn read(mut reader: R, func: F) -> io::Result> - where - F: Fn(&mut R) -> io::Result, - { - let count = CompactSize::read(&mut reader)?; - (0..count).into_iter().map(|_| func(&mut reader)).collect() - } - - pub fn write(mut writer: W, vec: &[E], func: F) -> io::Result<()> - where - F: Fn(&mut W, &E) -> io::Result<()>, - { - CompactSize::write(&mut writer, vec.len())?; - vec.iter().map(|e| func(&mut writer, e)).collect() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn compact_size() { - macro_rules! eval { - ($value:expr, $expected:expr) => { - let mut data = vec![]; - CompactSize::write(&mut data, $value).unwrap(); - assert_eq!(&data[..], &$expected[..]); - match CompactSize::read(&data[..]) { - Ok(n) => assert_eq!(n, $value), - Err(e) => panic!("Unexpected error: {:?}", e), - } - }; - } - - eval!(0, [0]); - eval!(1, [1]); - eval!(252, [252]); - eval!(253, [253, 253, 0]); - eval!(254, [253, 254, 0]); - eval!(255, [253, 255, 0]); - eval!(256, [253, 0, 1]); - eval!(256, [253, 0, 1]); - eval!(65535, [253, 255, 255]); - eval!(65536, [254, 0, 0, 1, 0]); - eval!(65537, [254, 1, 0, 1, 0]); - - eval!(33554432, [254, 0, 0, 0, 2]); - - { - let value = 33554433; - let encoded = &[254, 1, 0, 0, 2][..]; - let mut data = vec![]; - CompactSize::write(&mut data, value).unwrap(); - assert_eq!(&data[..], encoded); - assert!(CompactSize::read(encoded).is_err()); - } - } - - #[test] - fn vector() { - macro_rules! eval { - ($value:expr, $expected:expr) => { - let mut data = vec![]; - Vector::write(&mut data, &$value, |w, e| w.write_u8(*e)).unwrap(); - assert_eq!(&data[..], &$expected[..]); - match Vector::read(&data[..], |r| r.read_u8()) { - Ok(v) => assert_eq!(v, $value), - Err(e) => panic!("Unexpected error: {:?}", e), - } - }; - } - - eval!(vec![], [0]); - eval!(vec![0], [1, 0]); - eval!(vec![1], [1, 1]); - eval!(vec![5; 8], [8, 5, 5, 5, 5, 5, 5, 5, 5]); - - { - // expected = [253, 4, 1, 7, 7, 7, ...] - let mut expected = vec![7; 263]; - expected[0] = 253; - expected[1] = 4; - expected[2] = 1; - - eval!(vec![7; 260], expected); - } - } -} diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs deleted file mode 100644 index 21dbd46..0000000 --- a/zcash_primitives/src/transaction/components.rs +++ /dev/null @@ -1,432 +0,0 @@ -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use pairing::{ - bls12_381::{Bls12, Fr, FrRepr}, - PrimeField, PrimeFieldRepr, -}; -use sapling_crypto::{ - jubjub::{edwards, Unknown}, - redjubjub::{PublicKey, Signature}, -}; -use std::io::{self, Read, Write}; - -use serialize::Vector; -use JUBJUB; - -// π_A + π_B + π_C -const GROTH_PROOF_SIZE: usize = (48 + 96 + 48); -// π_A + π_A' + π_B + π_B' + π_C + π_C' + π_K + π_H -const PHGR_PROOF_SIZE: usize = (33 + 33 + 65 + 33 + 33 + 33 + 33 + 33); - -const ZC_NUM_JS_INPUTS: usize = 2; -const ZC_NUM_JS_OUTPUTS: usize = 2; - -const COIN: i64 = 1_0000_0000; -const MAX_MONEY: i64 = 21_000_000 * COIN; - -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Amount(pub i64); - -impl Amount { - // Read an Amount from a signed 64-bit little-endian integer. - pub fn read_i64(mut reader: R, allow_negative: bool) -> io::Result { - let amount = reader.read_i64::()?; - if 0 <= amount && amount <= MAX_MONEY { - Ok(Amount(amount)) - } else if allow_negative && -MAX_MONEY <= amount && amount < 0 { - Ok(Amount(amount)) - } else { - Err(io::Error::new( - io::ErrorKind::InvalidData, - if allow_negative { - "Amount not in {-MAX_MONEY..MAX_MONEY}" - } else { - "Amount not in {0..MAX_MONEY}" - }, - )) - } - } - - // Read an Amount from an unsigned 64-bit little-endian integer. - pub fn read_u64(mut reader: R) -> io::Result { - let amount = reader.read_u64::()?; - if amount <= MAX_MONEY as u64 { - Ok(Amount(amount as i64)) - } else { - Err(io::Error::new( - io::ErrorKind::InvalidData, - "Amount not in {0..MAX_MONEY}", - )) - } - } -} - -pub struct Script(pub Vec); - -impl Script { - pub fn read(mut reader: R) -> io::Result { - let script = Vector::read(&mut reader, |r| r.read_u8())?; - Ok(Script(script)) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - Vector::write(&mut writer, &self.0, |w, e| w.write_u8(*e)) - } -} - -pub struct OutPoint { - hash: [u8; 32], - n: u32, -} - -impl OutPoint { - pub fn read(mut reader: R) -> io::Result { - let mut hash = [0; 32]; - reader.read_exact(&mut hash)?; - let n = reader.read_u32::()?; - Ok(OutPoint { hash, n }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_all(&self.hash)?; - writer.write_u32::(self.n) - } -} - -pub struct TxIn { - pub prevout: OutPoint, - script_sig: Script, - pub sequence: u32, -} - -impl TxIn { - pub fn read(mut reader: &mut R) -> io::Result { - let prevout = OutPoint::read(&mut reader)?; - let script_sig = Script::read(&mut reader)?; - let sequence = reader.read_u32::()?; - - Ok(TxIn { - prevout, - script_sig, - sequence, - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - self.prevout.write(&mut writer)?; - self.script_sig.write(&mut writer)?; - writer.write_u32::(self.sequence) - } -} - -pub struct TxOut { - value: Amount, - script_pubkey: Script, -} - -impl TxOut { - pub fn read(mut reader: &mut R) -> io::Result { - let value = Amount::read_i64(&mut reader, false)?; - let script_pubkey = Script::read(&mut reader)?; - - Ok(TxOut { - value, - script_pubkey, - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_i64::(self.value.0)?; - self.script_pubkey.write(&mut writer) - } -} - -pub struct SpendDescription { - pub cv: edwards::Point, - pub anchor: Fr, - pub nullifier: [u8; 32], - pub rk: PublicKey, - pub zkproof: [u8; GROTH_PROOF_SIZE], - pub spend_auth_sig: Signature, -} - -impl SpendDescription { - pub fn read(mut reader: &mut R) -> io::Result { - // Consensus rules (§4.4): - // - Canonical encoding is enforced here. - // - "Not small order" is enforced in SaplingVerificationContext::check_spend() - // (located in zcash_proofs::sapling::verifier). - let cv = edwards::Point::::read(&mut reader, &JUBJUB)?; - - // Consensus rule (§7.3): Canonical encoding is enforced here - let anchor = { - let mut f = FrRepr::default(); - f.read_le(&mut reader)?; - Fr::from_repr(f).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))? - }; - - let mut nullifier = [0; 32]; - reader.read_exact(&mut nullifier)?; - - // Consensus rules (§4.4): - // - Canonical encoding is enforced here. - // - "Not small order" is enforced in SaplingVerificationContext::check_spend() - let rk = PublicKey::::read(&mut reader, &JUBJUB)?; - - // Consensus rules (§4.4): - // - Canonical encoding is enforced by the API of SaplingVerificationContext::check_spend() - // due to the need to parse this into a bellman::groth16::Proof. - // - Proof validity is enforced in SaplingVerificationContext::check_spend() - let mut zkproof = [0; GROTH_PROOF_SIZE]; - reader.read_exact(&mut zkproof)?; - - // Consensus rules (§4.4): - // - Canonical encoding is enforced here. - // - Signature validity is enforced in SaplingVerificationContext::check_spend() - let spend_auth_sig = Signature::read(&mut reader)?; - - Ok(SpendDescription { - cv, - anchor, - nullifier, - rk, - zkproof, - spend_auth_sig, - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - self.cv.write(&mut writer)?; - self.anchor.into_repr().write_le(&mut writer)?; - writer.write_all(&self.nullifier)?; - self.rk.write(&mut writer)?; - writer.write_all(&self.zkproof)?; - self.spend_auth_sig.write(&mut writer) - } -} - -pub struct OutputDescription { - pub cv: edwards::Point, - pub cmu: Fr, - pub ephemeral_key: edwards::Point, - pub enc_ciphertext: [u8; 580], - pub out_ciphertext: [u8; 80], - pub zkproof: [u8; GROTH_PROOF_SIZE], -} - -impl OutputDescription { - pub fn read(mut reader: &mut R) -> io::Result { - // Consensus rules (§4.5): - // - Canonical encoding is enforced here. - // - "Not small order" is enforced in SaplingVerificationContext::check_output() - // (located in zcash_proofs::sapling::verifier). - let cv = edwards::Point::::read(&mut reader, &JUBJUB)?; - - // Consensus rule (§7.4): Canonical encoding is enforced here - let cmu = { - let mut f = FrRepr::default(); - f.read_le(&mut reader)?; - Fr::from_repr(f).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))? - }; - - // Consensus rules (§4.5): - // - Canonical encoding is enforced here. - // - "Not small order" is enforced in SaplingVerificationContext::check_output() - let ephemeral_key = edwards::Point::::read(&mut reader, &JUBJUB)?; - - let mut enc_ciphertext = [0; 580]; - let mut out_ciphertext = [0; 80]; - reader.read_exact(&mut enc_ciphertext)?; - reader.read_exact(&mut out_ciphertext)?; - - // Consensus rules (§4.5): - // - Canonical encoding is enforced by the API of SaplingVerificationContext::check_output() - // due to the need to parse this into a bellman::groth16::Proof. - // - Proof validity is enforced in SaplingVerificationContext::check_output() - let mut zkproof = [0; GROTH_PROOF_SIZE]; - reader.read_exact(&mut zkproof)?; - - Ok(OutputDescription { - cv, - cmu, - ephemeral_key, - enc_ciphertext, - out_ciphertext, - zkproof, - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - self.cv.write(&mut writer)?; - self.cmu.into_repr().write_le(&mut writer)?; - self.ephemeral_key.write(&mut writer)?; - writer.write_all(&self.enc_ciphertext)?; - writer.write_all(&self.out_ciphertext)?; - writer.write_all(&self.zkproof) - } -} - -enum SproutProof { - Groth([u8; GROTH_PROOF_SIZE]), - PHGR([u8; PHGR_PROOF_SIZE]), -} - -pub struct JSDescription { - vpub_old: Amount, - vpub_new: Amount, - anchor: [u8; 32], - nullifiers: [[u8; 32]; ZC_NUM_JS_INPUTS], - commitments: [[u8; 32]; ZC_NUM_JS_OUTPUTS], - ephemeral_key: [u8; 32], - random_seed: [u8; 32], - macs: [[u8; 32]; ZC_NUM_JS_INPUTS], - proof: SproutProof, - ciphertexts: [[u8; 601]; ZC_NUM_JS_OUTPUTS], -} - -impl JSDescription { - pub fn read(mut reader: R, use_groth: bool) -> io::Result { - // Consensus rule (§4.3): Canonical encoding is enforced here - let vpub_old = Amount::read_u64(&mut reader)?; - - // Consensus rule (§4.3): Canonical encoding is enforced here - let vpub_new = Amount::read_u64(&mut reader)?; - - // Consensus rule (§4.3): One of vpub_old and vpub_new being zero is - // enforced by CheckTransactionWithoutProofVerification() in zcashd. - - let mut anchor = [0; 32]; - reader.read_exact(&mut anchor)?; - - let mut nullifiers = [[0; 32]; ZC_NUM_JS_INPUTS]; - nullifiers - .iter_mut() - .map(|nf| reader.read_exact(nf)) - .collect::>()?; - - let mut commitments = [[0; 32]; ZC_NUM_JS_OUTPUTS]; - commitments - .iter_mut() - .map(|cm| reader.read_exact(cm)) - .collect::>()?; - - // Consensus rule (§4.3): Canonical encoding is enforced by - // ZCNoteDecryption::decrypt() in zcashd - let mut ephemeral_key = [0; 32]; - reader.read_exact(&mut ephemeral_key)?; - - let mut random_seed = [0; 32]; - reader.read_exact(&mut random_seed)?; - - let mut macs = [[0; 32]; ZC_NUM_JS_INPUTS]; - macs.iter_mut() - .map(|mac| reader.read_exact(mac)) - .collect::>()?; - - let proof = match use_groth { - true => { - // Consensus rules (§4.3): - // - Canonical encoding is enforced in librustzcash_sprout_verify() - // - Proof validity is enforced in librustzcash_sprout_verify() - let mut proof = [0; GROTH_PROOF_SIZE]; - reader.read_exact(&mut proof)?; - SproutProof::Groth(proof) - } - false => { - // Consensus rules (§4.3): - // - Canonical encoding is enforced by PHGRProof in zcashd - // - Proof validity is enforced by JSDescription::Verify() in zcashd - let mut proof = [0; PHGR_PROOF_SIZE]; - reader.read_exact(&mut proof)?; - SproutProof::PHGR(proof) - } - }; - - let mut ciphertexts = [[0; 601]; ZC_NUM_JS_OUTPUTS]; - ciphertexts - .iter_mut() - .map(|ct| reader.read_exact(ct)) - .collect::>()?; - - Ok(JSDescription { - vpub_old, - vpub_new, - anchor, - nullifiers, - commitments, - ephemeral_key, - random_seed, - macs, - proof, - ciphertexts, - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_i64::(self.vpub_old.0)?; - writer.write_i64::(self.vpub_new.0)?; - writer.write_all(&self.anchor)?; - writer.write_all(&self.nullifiers[0])?; - writer.write_all(&self.nullifiers[1])?; - writer.write_all(&self.commitments[0])?; - writer.write_all(&self.commitments[1])?; - writer.write_all(&self.ephemeral_key)?; - writer.write_all(&self.random_seed)?; - writer.write_all(&self.macs[0])?; - writer.write_all(&self.macs[1])?; - - match &self.proof { - SproutProof::Groth(p) => writer.write_all(p)?, - SproutProof::PHGR(p) => writer.write_all(p)?, - } - - writer.write_all(&self.ciphertexts[0])?; - writer.write_all(&self.ciphertexts[1]) - } -} - -#[cfg(test)] -mod tests { - use super::{Amount, MAX_MONEY}; - - #[test] - fn amount_in_range() { - let zero = b"\x00\x00\x00\x00\x00\x00\x00\x00"; - assert_eq!(Amount::read_u64(&zero[..]).unwrap(), Amount(0)); - assert_eq!(Amount::read_i64(&zero[..], false).unwrap(), Amount(0)); - assert_eq!(Amount::read_i64(&zero[..], true).unwrap(), Amount(0)); - - let neg_one = b"\xff\xff\xff\xff\xff\xff\xff\xff"; - assert!(Amount::read_u64(&neg_one[..]).is_err()); - assert!(Amount::read_i64(&neg_one[..], false).is_err()); - assert_eq!(Amount::read_i64(&neg_one[..], true).unwrap(), Amount(-1)); - - let max_money = b"\x00\x40\x07\x5a\xf0\x75\x07\x00"; - assert_eq!(Amount::read_u64(&max_money[..]).unwrap(), Amount(MAX_MONEY)); - assert_eq!( - Amount::read_i64(&max_money[..], false).unwrap(), - Amount(MAX_MONEY) - ); - assert_eq!( - Amount::read_i64(&max_money[..], true).unwrap(), - Amount(MAX_MONEY) - ); - - let max_money_p1 = b"\x01\x40\x07\x5a\xf0\x75\x07\x00"; - assert!(Amount::read_u64(&max_money_p1[..]).is_err()); - assert!(Amount::read_i64(&max_money_p1[..], false).is_err()); - assert!(Amount::read_i64(&max_money_p1[..], true).is_err()); - - let neg_max_money = b"\x00\xc0\xf8\xa5\x0f\x8a\xf8\xff"; - assert!(Amount::read_u64(&neg_max_money[..]).is_err()); - assert!(Amount::read_i64(&neg_max_money[..], false).is_err()); - assert_eq!( - Amount::read_i64(&neg_max_money[..], true).unwrap(), - Amount(-MAX_MONEY) - ); - - let neg_max_money_m1 = b"\xff\xbf\xf8\xa5\x0f\x8a\xf8\xff"; - assert!(Amount::read_u64(&neg_max_money_m1[..]).is_err()); - assert!(Amount::read_i64(&neg_max_money_m1[..], false).is_err()); - assert!(Amount::read_i64(&neg_max_money_m1[..], true).is_err()); - } -} diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs deleted file mode 100644 index 787c01d..0000000 --- a/zcash_primitives/src/transaction/mod.rs +++ /dev/null @@ -1,257 +0,0 @@ -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use sapling_crypto::redjubjub::Signature; -use std::io::{self, Read, Write}; -use std::ops::Deref; - -use serialize::Vector; - -pub mod components; -mod sighash; - -#[cfg(test)] -mod tests; - -pub use self::sighash::{signature_hash, signature_hash_data, SIGHASH_ALL}; - -use self::components::{Amount, JSDescription, OutputDescription, SpendDescription, TxIn, TxOut}; - -const OVERWINTER_VERSION_GROUP_ID: u32 = 0x03C48270; -const OVERWINTER_TX_VERSION: u32 = 3; -const SAPLING_VERSION_GROUP_ID: u32 = 0x892F2085; -const SAPLING_TX_VERSION: u32 = 4; - -/// A Zcash transaction. -pub struct Transaction(TransactionData); - -impl Deref for Transaction { - type Target = TransactionData; - - fn deref(&self) -> &TransactionData { - &self.0 - } -} - -pub struct TransactionData { - pub overwintered: bool, - pub version: u32, - pub version_group_id: u32, - pub vin: Vec, - pub vout: Vec, - pub lock_time: u32, - pub expiry_height: u32, - pub value_balance: Amount, - pub shielded_spends: Vec, - pub shielded_outputs: Vec, - pub joinsplits: Vec, - pub joinsplit_pubkey: Option<[u8; 32]>, - pub joinsplit_sig: Option<[u8; 64]>, - pub binding_sig: Option, -} - -impl TransactionData { - pub fn new() -> Self { - TransactionData { - overwintered: true, - version: SAPLING_TX_VERSION, - version_group_id: SAPLING_VERSION_GROUP_ID, - vin: vec![], - vout: vec![], - lock_time: 0, - expiry_height: 0, - value_balance: Amount(0), - shielded_spends: vec![], - shielded_outputs: vec![], - joinsplits: vec![], - joinsplit_pubkey: None, - joinsplit_sig: None, - binding_sig: None, - } - } - - fn header(&self) -> u32 { - let mut header = self.version; - if self.overwintered { - header |= 1 << 31; - } - header - } - - pub fn freeze(self) -> Transaction { - Transaction(self) - } -} - -impl Transaction { - pub fn read(mut reader: R) -> io::Result { - let header = reader.read_u32::()?; - let overwintered = (header >> 31) == 1; - let version = header & 0x7FFFFFFF; - - let version_group_id = match overwintered { - true => reader.read_u32::()?, - false => 0, - }; - - let is_overwinter_v3 = overwintered - && version_group_id == OVERWINTER_VERSION_GROUP_ID - && version == OVERWINTER_TX_VERSION; - let is_sapling_v4 = overwintered - && version_group_id == SAPLING_VERSION_GROUP_ID - && version == SAPLING_TX_VERSION; - if overwintered && !(is_overwinter_v3 || is_sapling_v4) { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Unknown transaction format", - )); - } - - let vin = Vector::read(&mut reader, TxIn::read)?; - let vout = Vector::read(&mut reader, TxOut::read)?; - let lock_time = reader.read_u32::()?; - let expiry_height = match is_overwinter_v3 || is_sapling_v4 { - true => reader.read_u32::()?, - false => 0, - }; - - let (value_balance, shielded_spends, shielded_outputs) = if is_sapling_v4 { - let vb = Amount::read_i64(&mut reader, true)?; - let ss = Vector::read(&mut reader, SpendDescription::read)?; - let so = Vector::read(&mut reader, OutputDescription::read)?; - (vb, ss, so) - } else { - (Amount(0), vec![], vec![]) - }; - - let (joinsplits, joinsplit_pubkey, joinsplit_sig) = if version >= 2 { - let jss = Vector::read(&mut reader, |r| { - JSDescription::read(r, overwintered && version >= SAPLING_TX_VERSION) - })?; - let (pubkey, sig) = if !jss.is_empty() { - let mut joinsplit_pubkey = [0; 32]; - let mut joinsplit_sig = [0; 64]; - reader.read_exact(&mut joinsplit_pubkey)?; - reader.read_exact(&mut joinsplit_sig)?; - (Some(joinsplit_pubkey), Some(joinsplit_sig)) - } else { - (None, None) - }; - (jss, pubkey, sig) - } else { - (vec![], None, None) - }; - - let binding_sig = - match is_sapling_v4 && !(shielded_spends.is_empty() && shielded_outputs.is_empty()) { - true => Some(Signature::read(&mut reader)?), - false => None, - }; - - Ok(Transaction(TransactionData { - overwintered, - version, - version_group_id, - vin, - vout, - lock_time, - expiry_height, - value_balance, - shielded_spends, - shielded_outputs, - joinsplits, - joinsplit_pubkey, - joinsplit_sig, - binding_sig, - })) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_u32::(self.header())?; - if self.overwintered { - writer.write_u32::(self.version_group_id)?; - } - - let is_overwinter_v3 = self.overwintered - && self.version_group_id == OVERWINTER_VERSION_GROUP_ID - && self.version == OVERWINTER_TX_VERSION; - let is_sapling_v4 = self.overwintered - && self.version_group_id == SAPLING_VERSION_GROUP_ID - && self.version == SAPLING_TX_VERSION; - if self.overwintered && !(is_overwinter_v3 || is_sapling_v4) { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Unknown transaction format", - )); - } - - Vector::write(&mut writer, &self.vin, |w, e| e.write(w))?; - Vector::write(&mut writer, &self.vout, |w, e| e.write(w))?; - writer.write_u32::(self.lock_time)?; - if is_overwinter_v3 || is_sapling_v4 { - writer.write_u32::(self.expiry_height)?; - } - - if is_sapling_v4 { - writer.write_i64::(self.value_balance.0)?; - Vector::write(&mut writer, &self.shielded_spends, |w, e| e.write(w))?; - Vector::write(&mut writer, &self.shielded_outputs, |w, e| e.write(w))?; - } - - if self.version >= 2 { - Vector::write(&mut writer, &self.joinsplits, |w, e| e.write(w))?; - if !self.joinsplits.is_empty() { - match self.joinsplit_pubkey { - Some(pubkey) => writer.write_all(&pubkey)?, - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Missing JoinSplit pubkey", - )) - } - } - match self.joinsplit_sig { - Some(sig) => writer.write_all(&sig)?, - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Missing JoinSplit signature", - )) - } - } - } - } - - if self.version < 2 || self.joinsplits.is_empty() { - if self.joinsplit_pubkey.is_some() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "JoinSplit pubkey should not be present", - )); - } - if self.joinsplit_sig.is_some() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "JoinSplit signature should not be present", - )); - } - } - - if is_sapling_v4 && !(self.shielded_spends.is_empty() && self.shielded_outputs.is_empty()) { - match self.binding_sig { - Some(sig) => sig.write(&mut writer)?, - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Missing binding signature", - )) - } - } - } else if self.binding_sig.is_some() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Binding signature should not be present", - )); - } - - Ok(()) - } -} diff --git a/zcash_primitives/src/transaction/sighash.rs b/zcash_primitives/src/transaction/sighash.rs deleted file mode 100644 index e5dcde0..0000000 --- a/zcash_primitives/src/transaction/sighash.rs +++ /dev/null @@ -1,234 +0,0 @@ -use blake2_rfc::blake2b::Blake2b; -use byteorder::{LittleEndian, WriteBytesExt}; -use pairing::{PrimeField, PrimeFieldRepr}; - -use super::{ - components::{Amount, Script, TxOut}, - Transaction, TransactionData, OVERWINTER_VERSION_GROUP_ID, SAPLING_TX_VERSION, - SAPLING_VERSION_GROUP_ID, -}; - -const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &'static [u8; 12] = b"ZcashSigHash"; -const ZCASH_PREVOUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashPrevoutHash"; -const ZCASH_SEQUENCE_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSequencHash"; -const ZCASH_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashOutputsHash"; -const ZCASH_JOINSPLITS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashJSplitsHash"; -const ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSSpendsHash"; -const ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSOutputHash"; - -pub const SIGHASH_ALL: u32 = 1; -const SIGHASH_NONE: u32 = 2; -const SIGHASH_SINGLE: u32 = 3; -const SIGHASH_MASK: u32 = 0x1f; -const SIGHASH_ANYONECANPAY: u32 = 0x80; - -macro_rules! update_u32 { - ($h:expr, $value:expr, $tmp:expr) => { - (&mut $tmp[..4]).write_u32::($value).unwrap(); - $h.update(&$tmp[..4]); - }; -} - -macro_rules! update_i64 { - ($h:expr, $value:expr, $tmp:expr) => { - (&mut $tmp[..8]).write_i64::($value).unwrap(); - $h.update(&$tmp[..8]); - }; -} - -macro_rules! update_hash { - ($h:expr, $cond:expr, $value:expr) => { - if $cond { - $h.update(&$value); - } else { - $h.update(&[0; 32]); - } - }; -} - -#[derive(PartialEq)] -enum SigHashVersion { - Sprout, - Overwinter, - Sapling, -} - -impl SigHashVersion { - fn from_tx(tx: &TransactionData) -> Self { - if tx.overwintered { - match tx.version_group_id { - OVERWINTER_VERSION_GROUP_ID => SigHashVersion::Overwinter, - SAPLING_VERSION_GROUP_ID => SigHashVersion::Sapling, - _ => unimplemented!(), - } - } else { - SigHashVersion::Sprout - } - } -} - -fn prevout_hash(tx: &TransactionData) -> Vec { - let mut data = Vec::with_capacity(tx.vin.len() * 36); - for t_in in &tx.vin { - t_in.prevout.write(&mut data).unwrap(); - } - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_PREVOUTS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() -} - -fn sequence_hash(tx: &TransactionData) -> Vec { - let mut data = Vec::with_capacity(tx.vin.len() * 4); - for t_in in &tx.vin { - (&mut data) - .write_u32::(t_in.sequence) - .unwrap(); - } - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SEQUENCE_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() -} - -fn outputs_hash(tx: &TransactionData) -> Vec { - let mut data = Vec::with_capacity(tx.vout.len() * (4 + 1)); - for t_out in &tx.vout { - t_out.write(&mut data).unwrap(); - } - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_OUTPUTS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() -} - -fn single_output_hash(tx_out: &TxOut) -> Vec { - let mut data = vec![]; - tx_out.write(&mut data).unwrap(); - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_OUTPUTS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() -} - -fn joinsplits_hash(tx: &TransactionData) -> Vec { - let mut data = Vec::with_capacity( - tx.joinsplits.len() - * if tx.version < SAPLING_TX_VERSION { - 1802 // JSDescription with PHGR13 proof - } else { - 1698 // JSDescription with Groth16 proof - }, - ); - for js in &tx.joinsplits { - js.write(&mut data).unwrap(); - } - data.extend_from_slice(&tx.joinsplit_pubkey.unwrap()); - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_JOINSPLITS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() -} - -fn shielded_spends_hash(tx: &TransactionData) -> Vec { - let mut data = Vec::with_capacity(tx.shielded_spends.len() * 384); - for s_spend in &tx.shielded_spends { - s_spend.cv.write(&mut data).unwrap(); - s_spend.anchor.into_repr().write_le(&mut data).unwrap(); - data.extend_from_slice(&s_spend.nullifier); - s_spend.rk.write(&mut data).unwrap(); - data.extend_from_slice(&s_spend.zkproof); - } - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() -} - -fn shielded_outputs_hash(tx: &TransactionData) -> Vec { - let mut data = Vec::with_capacity(tx.shielded_outputs.len() * 948); - for s_out in &tx.shielded_outputs { - s_out.write(&mut data).unwrap(); - } - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() -} - -pub fn signature_hash_data( - tx: &TransactionData, - consensus_branch_id: u32, - hash_type: u32, - transparent_input: Option<(usize, Script, Amount)>, -) -> Vec { - let sigversion = SigHashVersion::from_tx(tx); - match sigversion { - SigHashVersion::Overwinter | SigHashVersion::Sapling => { - let hash_outputs = if (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE - && (hash_type & SIGHASH_MASK) != SIGHASH_NONE - { - outputs_hash(tx) - } else if (hash_type & SIGHASH_MASK) == SIGHASH_SINGLE - && transparent_input.is_some() - && transparent_input.as_ref().unwrap().0 < tx.vout.len() - { - single_output_hash(&tx.vout[transparent_input.as_ref().unwrap().0]) - } else { - vec![0; 32] - }; - - let mut personal = [0; 16]; - (&mut personal[..12]).copy_from_slice(ZCASH_SIGHASH_PERSONALIZATION_PREFIX); - (&mut personal[12..]) - .write_u32::(consensus_branch_id) - .unwrap(); - - let mut h = Blake2b::with_params(32, &[], &[], &personal); - let mut tmp = [0; 8]; - - update_u32!(h, tx.header(), tmp); - update_u32!(h, tx.version_group_id, tmp); - update_hash!(h, hash_type & SIGHASH_ANYONECANPAY == 0, prevout_hash(tx)); - update_hash!( - h, - hash_type & SIGHASH_ANYONECANPAY == 0 - && (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE - && (hash_type & SIGHASH_MASK) != SIGHASH_NONE, - sequence_hash(tx) - ); - h.update(&hash_outputs); - update_hash!(h, !tx.joinsplits.is_empty(), joinsplits_hash(tx)); - if sigversion == SigHashVersion::Sapling { - update_hash!(h, !tx.shielded_spends.is_empty(), shielded_spends_hash(tx)); - update_hash!( - h, - !tx.shielded_outputs.is_empty(), - shielded_outputs_hash(tx) - ); - } - update_u32!(h, tx.lock_time, tmp); - update_u32!(h, tx.expiry_height, tmp); - if sigversion == SigHashVersion::Sapling { - update_i64!(h, tx.value_balance.0, tmp); - } - update_u32!(h, hash_type, tmp); - - if let Some((n, script_code, amount)) = transparent_input { - let mut data = vec![]; - tx.vin[n].prevout.write(&mut data).unwrap(); - script_code.write(&mut data).unwrap(); - (&mut data).write_i64::(amount.0).unwrap(); - (&mut data) - .write_u32::(tx.vin[n].sequence) - .unwrap(); - h.update(&data); - } - - h.finalize().as_ref().to_vec() - } - SigHashVersion::Sprout => unimplemented!(), - } -} - -pub fn signature_hash( - tx: &Transaction, - consensus_branch_id: u32, - hash_type: u32, - transparent_input: Option<(usize, Script, Amount)>, -) -> Vec { - signature_hash_data(tx, consensus_branch_id, hash_type, transparent_input) -} diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs deleted file mode 100644 index db3a4df..0000000 --- a/zcash_primitives/src/transaction/tests.rs +++ /dev/null @@ -1,5422 +0,0 @@ -use pairing::bls12_381::Bls12; -use rand::{thread_rng, Rng}; -use sapling_crypto::{jubjub::FixedGenerators, redjubjub::PrivateKey}; - -use super::{ - components::{Amount, Script}, - sighash::signature_hash, - Transaction, TransactionData, -}; -use JUBJUB; - -#[test] -fn tx_read_write() { - // TxID: 64f0bd7fe30ce23753358fe3a2dc835b8fba9c0274c4e2c54a6f73114cb55639 - // From testnet block 280003. - let data = [ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x01, 0x8f, 0x64, 0x29, 0x96, 0xdf, 0x1e, - 0x93, 0xa6, 0xd7, 0x9a, 0xe5, 0xba, 0xae, 0x34, 0x93, 0xf4, 0x23, 0xca, 0x6c, 0x82, 0xe9, - 0x9f, 0x3e, 0x8d, 0x95, 0x24, 0xfa, 0x78, 0xbc, 0xf1, 0x61, 0x67, 0x00, 0x00, 0x00, 0x00, - 0x6b, 0x48, 0x30, 0x45, 0x02, 0x21, 0x00, 0xb6, 0x5e, 0x37, 0x22, 0x97, 0x07, 0xd9, 0xcd, - 0x48, 0x39, 0x40, 0xd2, 0xab, 0x8b, 0xdc, 0x0b, 0x74, 0xb1, 0x2d, 0xda, 0x66, 0xd0, 0x2d, - 0xbd, 0xf3, 0x6f, 0xd3, 0x83, 0xb9, 0x60, 0x2a, 0x51, 0x02, 0x20, 0x4b, 0xe7, 0xfd, 0x7a, - 0x39, 0xa4, 0xa4, 0x2d, 0xff, 0x07, 0x1a, 0x5a, 0x2b, 0xc5, 0x1b, 0x49, 0x2d, 0x33, 0xf0, - 0xbc, 0x39, 0x4b, 0xc8, 0x78, 0x61, 0xe1, 0xbc, 0xaa, 0xf2, 0xba, 0xc9, 0x3b, 0x01, 0x21, - 0x02, 0x48, 0xe7, 0x8b, 0xdc, 0x18, 0xf1, 0xa8, 0x31, 0x10, 0xc1, 0x2e, 0x40, 0x08, 0xb7, - 0x64, 0x02, 0x69, 0x61, 0xb1, 0x68, 0xfe, 0x8d, 0x5a, 0x8d, 0x94, 0x7e, 0xfe, 0x6a, 0xf8, - 0x3c, 0xc8, 0x8e, 0xff, 0xff, 0xff, 0xff, 0x01, 0xf0, 0xf2, 0x70, 0x18, 0x02, 0x00, 0x00, - 0x00, 0x19, 0x76, 0xa9, 0x14, 0xa2, 0x84, 0xd0, 0x51, 0x1d, 0x0e, 0x52, 0x0d, 0x36, 0xf4, - 0x44, 0xa3, 0x6c, 0x10, 0xbf, 0x54, 0xb4, 0xb0, 0x17, 0xcd, 0x88, 0xac, 0x00, 0x00, 0x00, - 0x00, 0xd7, 0x45, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0xca, 0x9a, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x13, 0x31, 0xa3, 0x05, 0x9e, 0x66, 0xaa, 0x6c, 0xa9, 0x7a, 0x62, 0xf5, 0x6e, - 0xa2, 0x34, 0x20, 0x75, 0x68, 0x56, 0x6f, 0x69, 0x71, 0xb3, 0x72, 0x2a, 0xe0, 0xdd, 0x82, - 0xc0, 0x03, 0x99, 0x69, 0x2a, 0xac, 0xb5, 0xfb, 0x12, 0xac, 0x58, 0x0a, 0xc2, 0x66, 0x24, - 0xa8, 0xcf, 0x0a, 0x90, 0x4c, 0xd6, 0xf4, 0xbf, 0xea, 0x55, 0x62, 0x52, 0x05, 0xcb, 0x58, - 0xf0, 0x6b, 0x1c, 0x19, 0x74, 0x23, 0x28, 0x0d, 0xea, 0xc7, 0x4e, 0xea, 0x97, 0x59, 0x8c, - 0x43, 0x14, 0xd8, 0x99, 0xa4, 0xfd, 0x85, 0x31, 0x1e, 0x04, 0x62, 0x57, 0xd2, 0xd4, 0xc2, - 0x97, 0xf1, 0x40, 0x6c, 0xf7, 0x09, 0xd9, 0x2a, 0x86, 0x07, 0xf7, 0x69, 0x8d, 0x45, 0xfe, - 0x9f, 0x41, 0xde, 0xa3, 0xa0, 0x57, 0x1c, 0x5d, 0xa5, 0xcf, 0xa7, 0x8e, 0x18, 0xeb, 0xf5, - 0x80, 0xc3, 0x61, 0x79, 0xd9, 0xd6, 0xe6, 0x32, 0x0a, 0x34, 0x8f, 0x14, 0x6c, 0x40, 0x7a, - 0xda, 0xb4, 0xcb, 0x31, 0x03, 0x92, 0xa5, 0xf5, 0xb5, 0xab, 0x28, 0x3b, 0x78, 0x34, 0x3b, - 0xa9, 0x1a, 0xbc, 0x7c, 0x4b, 0xfe, 0x23, 0xa3, 0xdb, 0xaf, 0x80, 0x37, 0xc6, 0x76, 0xe5, - 0x95, 0xa2, 0x65, 0x74, 0xb1, 0x81, 0x3b, 0xc2, 0xbf, 0x2d, 0x2e, 0x91, 0x1f, 0x6f, 0x3a, - 0xbb, 0x0b, 0xa6, 0xbc, 0xac, 0x7a, 0x29, 0x01, 0xfb, 0xdc, 0xe6, 0x5f, 0xb0, 0x7b, 0x56, - 0x36, 0x01, 0x7e, 0xf1, 0x4d, 0xff, 0x44, 0xcd, 0xee, 0xa7, 0x30, 0x47, 0x72, 0x94, 0xf2, - 0xf8, 0x61, 0x9b, 0xd3, 0xd5, 0xe6, 0xbe, 0x48, 0x98, 0xbf, 0x8d, 0x39, 0xc0, 0xe0, 0xea, - 0xe5, 0xa3, 0x68, 0x64, 0x62, 0x52, 0x06, 0xb9, 0xa8, 0xf9, 0x94, 0x0b, 0xf1, 0x66, 0x50, - 0xde, 0xf7, 0x92, 0x6e, 0xb0, 0xdb, 0x43, 0xb7, 0xd7, 0x61, 0x5e, 0x47, 0x74, 0xcf, 0x10, - 0x94, 0x82, 0xf2, 0xe8, 0x07, 0xfe, 0xe6, 0xc0, 0xc8, 0x84, 0xe8, 0x31, 0x4c, 0x67, 0xc5, - 0xd8, 0x5f, 0x4c, 0x22, 0x9c, 0xde, 0xab, 0x1e, 0x96, 0x4c, 0xf0, 0xc1, 0xad, 0xcb, 0x47, - 0xce, 0xbf, 0xc7, 0xc0, 0x67, 0xa0, 0xf3, 0xc8, 0x06, 0x81, 0x4a, 0x28, 0x5e, 0xdb, 0xb6, - 0x24, 0xf4, 0x71, 0x06, 0x29, 0x09, 0x89, 0x44, 0xac, 0x75, 0xe7, 0xc9, 0xcb, 0xc5, 0x6b, - 0xd0, 0xa0, 0x29, 0xe1, 0x11, 0x0e, 0xac, 0x60, 0xcb, 0x40, 0x77, 0xeb, 0xf1, 0x08, 0xfe, - 0x3e, 0x67, 0xcd, 0x06, 0x13, 0x91, 0xe5, 0xd6, 0x91, 0x6d, 0x5f, 0x41, 0xc0, 0x2b, 0x89, - 0x14, 0xc1, 0x2c, 0xf6, 0x05, 0xdb, 0x7d, 0x95, 0x92, 0x26, 0xe2, 0xe8, 0xff, 0x71, 0x26, - 0x3b, 0x9a, 0xf4, 0xc5, 0x9b, 0x0f, 0x4d, 0xb3, 0x15, 0xb7, 0x4c, 0xa2, 0xb0, 0xb7, 0xd2, - 0x52, 0x13, 0xd5, 0x29, 0x39, 0x54, 0xc3, 0xe5, 0x11, 0x72, 0x37, 0x0f, 0xb6, 0xc3, 0x5a, - 0xbe, 0x9c, 0xe3, 0x6e, 0xf2, 0x53, 0xe3, 0xa7, 0x2e, 0x19, 0xda, 0xc9, 0xbd, 0x73, 0x62, - 0xc4, 0x49, 0x92, 0x97, 0x42, 0x15, 0xc8, 0x2c, 0xb9, 0x0c, 0x99, 0x48, 0x8d, 0xbd, 0xe1, - 0x19, 0x63, 0xe8, 0x57, 0xce, 0xa6, 0xb8, 0x1b, 0x8e, 0xaa, 0xe3, 0x4b, 0x7c, 0xf5, 0xa9, - 0x7d, 0x6b, 0x60, 0xd4, 0x9f, 0xdf, 0xa2, 0x0f, 0x5f, 0x3c, 0x12, 0x0e, 0xf3, 0x82, 0xca, - 0x24, 0x69, 0x60, 0x4f, 0xb0, 0xc6, 0x84, 0x2c, 0x6d, 0x4f, 0xae, 0x96, 0x61, 0x66, 0x5b, - 0x5c, 0xbc, 0x61, 0x2c, 0xef, 0x13, 0x2f, 0x88, 0xfb, 0x7d, 0xa3, 0x93, 0xf3, 0x56, 0xe3, - 0xad, 0x13, 0xfc, 0x35, 0x57, 0x98, 0x0a, 0x77, 0x34, 0x23, 0x14, 0x53, 0xe4, 0x40, 0x79, - 0x04, 0x2f, 0xb4, 0x32, 0xf5, 0x5e, 0x75, 0x14, 0x84, 0xd5, 0xd6, 0xd3, 0x0f, 0xbc, 0x4f, - 0x99, 0x90, 0x13, 0xd5, 0xd4, 0xf2, 0xfb, 0x62, 0xf7, 0x14, 0x4e, 0x8d, 0xcd, 0x2a, 0xe5, - 0x95, 0x46, 0xcc, 0x43, 0x79, 0xad, 0x9f, 0x18, 0x59, 0xef, 0x80, 0xde, 0xc6, 0x6b, 0x1a, - 0x9b, 0x0b, 0x7f, 0xd2, 0xc4, 0x7b, 0xd3, 0x83, 0x02, 0xd2, 0x9c, 0x31, 0x99, 0x03, 0x29, - 0xa8, 0x95, 0x87, 0x6e, 0xd1, 0xd8, 0x4d, 0xb7, 0x57, 0x85, 0x6e, 0x75, 0xce, 0x9a, 0x1d, - 0xc7, 0xc7, 0x47, 0x2b, 0xc2, 0x18, 0xfb, 0x8d, 0x7c, 0x7d, 0x02, 0x8b, 0xb0, 0x2f, 0x10, - 0xef, 0xe7, 0xfe, 0x6a, 0x8c, 0x9c, 0xe0, 0x34, 0xfe, 0xa6, 0x6b, 0x90, 0x9c, 0x8d, 0x41, - 0x26, 0x25, 0x1c, 0x7d, 0x6e, 0x54, 0xf4, 0xcf, 0xc7, 0x78, 0xcd, 0x4f, 0x0e, 0x0b, 0xad, - 0x10, 0x96, 0x17, 0x6f, 0x2d, 0xd4, 0x5c, 0x45, 0xcb, 0xe1, 0x5e, 0x11, 0x8f, 0x90, 0xff, - 0x25, 0x45, 0xf8, 0x32, 0xf2, 0x36, 0x98, 0xf2, 0xc9, 0x53, 0x1b, 0x52, 0x65, 0x5a, 0x4c, - 0x0c, 0x89, 0x53, 0x55, 0x99, 0x28, 0xee, 0xdf, 0xc7, 0x56, 0xc3, 0x65, 0xcf, 0x92, 0x9b, - 0x84, 0x47, 0xdc, 0xdc, 0x7d, 0x82, 0x38, 0x49, 0xe0, 0x2f, 0xf6, 0x8b, 0x62, 0x78, 0xd7, - 0x54, 0x2c, 0xe0, 0xf1, 0x07, 0x0b, 0xb1, 0xad, 0x91, 0x3c, 0x1a, 0x35, 0x36, 0x25, 0xf5, - 0xd3, 0x5b, 0x14, 0xcf, 0xec, 0x84, 0xa6, 0x33, 0xd7, 0xfe, 0x25, 0x25, 0x6d, 0xcf, 0xfe, - 0x92, 0xf9, 0xa6, 0xf0, 0xfe, 0x00, 0xca, 0xaa, 0xa5, 0xb3, 0x9c, 0xc2, 0xab, 0x06, 0x76, - 0x8a, 0x42, 0xa5, 0xb4, 0x00, 0x83, 0xce, 0xa0, 0x1c, 0x96, 0xb3, 0xe6, 0x8d, 0x0f, 0x6a, - 0x58, 0x7e, 0xaf, 0x2d, 0xa6, 0xfd, 0xad, 0xc8, 0x25, 0x27, 0xf1, 0x86, 0xa6, 0x04, 0x71, - 0xce, 0x98, 0xe2, 0x7d, 0x2b, 0x11, 0xef, 0xc4, 0x79, 0x98, 0xf3, 0x03, 0x0a, 0x7a, 0x2e, - 0x5d, 0x0b, 0x0a, 0x7e, 0xb8, 0x0f, 0x6b, 0xd0, 0xe4, 0xb9, 0xc8, 0x36, 0x7c, 0x6c, 0x52, - 0x2d, 0x94, 0x15, 0xf8, 0xca, 0xec, 0x7b, 0x0a, 0x73, 0x18, 0xd5, 0x3d, 0xce, 0x39, 0x1c, - 0xf7, 0xe7, 0x38, 0x9c, 0x9a, 0x74, 0xaa, 0x6a, 0x4c, 0x21, 0x7c, 0x28, 0x85, 0x19, 0xaf, - 0x81, 0xba, 0x21, 0x22, 0xca, 0x0c, 0x58, 0x40, 0xcc, 0x02, 0xcf, 0x1b, 0xcf, 0x15, 0x0c, - 0xd3, 0xdf, 0x33, 0xc0, 0xac, 0xfd, 0x00, 0x53, 0xe6, 0x68, 0xb9, 0x26, 0x56, 0x1b, 0x92, - 0x40, 0x98, 0xd9, 0x7a, 0xaa, 0xb5, 0x7e, 0xe1, 0x11, 0x3d, 0xf9, 0x66, 0xa4, 0x22, 0xef, - 0x9b, 0x01, 0x46, 0x17, 0xbc, 0xee, 0xf0, 0x5f, 0xb6, 0x46, 0x8e, 0x33, 0x0e, 0x2d, 0xec, - 0xe3, 0xf3, 0x75, 0xe9, 0x8e, 0xf0, 0x3e, 0x5b, 0x18, 0xa9, 0x53, 0xe2, 0x30, 0x1f, 0xcc, - 0xec, 0x86, 0x20, 0x0a, 0xe4, 0x32, 0xc9, 0xc1, 0x2c, 0x30, 0x77, 0x54, 0x37, 0xf3, 0x62, - 0x97, 0x14, 0xa9, 0xfa, 0xbe, 0xb5, 0x32, 0x89, 0x40, 0x2b, 0x7f, 0xd3, 0x86, 0xce, 0xf2, - 0xb1, 0x14, 0x67, 0x23, 0xa8, 0x9d, 0x0f, 0x81, 0x65, 0x1e, 0x00, 0xca, 0xea, 0x2f, 0x3a, - 0xc9, 0xee, 0xfe, 0xfb, 0x86, 0x8d, 0x85, 0xed, 0x23, 0x54, 0xf5, 0x30, 0xfe, 0x38, 0xfe, - 0x3a, 0x3a, 0x6a, 0xab, 0x47, 0xd4, 0x2d, 0xc2, 0x13, 0x29, 0xe3, 0xad, 0x1b, 0x9d, 0x06, - 0xc0, 0xc8, 0xd6, 0x53, 0x74, 0x56, 0xf5, 0x4a, 0xd0, 0x45, 0x3f, 0x44, 0x41, 0x75, 0xd8, - 0x7e, 0xf5, 0xcd, 0xd1, 0x69, 0x46, 0x62, 0xe0, 0xa1, 0xe6, 0xe3, 0x63, 0x2e, 0xd7, 0xa8, - 0xe7, 0x6b, 0xc7, 0xb1, 0xb5, 0xa4, 0x18, 0xf0, 0x86, 0xd3, 0x40, 0x81, 0x5e, 0xc3, 0x98, - 0xf0, 0x92, 0xe9, 0x78, 0x69, 0xf5, 0xe2, 0x01, 0xc2, 0x2c, 0x87, 0x91, 0x8f, 0x76, 0x6a, - 0x35, 0x32, 0xeb, 0x9a, 0x4f, 0xc9, 0xac, 0xf1, 0x96, 0xcb, 0xc2, 0xd0, 0x28, 0x51, 0x19, - 0xa4, 0x21, 0x6d, 0x25, 0x81, 0xcd, 0x2d, 0x91, 0xbc, 0xdc, 0xe8, 0x68, 0xc4, 0x68, 0xf6, - 0xf3, 0x4c, 0xf4, 0x9e, 0x3a, 0x56, 0xce, 0x24, 0x9a, 0x2f, 0xd8, 0xcf, 0x36, 0xb0, 0x1b, - 0x0f, 0x77, 0xde, 0x72, 0x2b, 0xbc, 0xe2, 0x67, 0xe3, 0xe5, 0x52, 0x16, 0x88, 0xe6, 0x52, - 0x22, 0x23, 0x5c, 0x91, 0xc2, 0x63, 0xd8, 0x0e, 0x28, 0x29, 0x7e, 0x92, 0x9d, 0x88, 0x5b, - 0x7b, 0x9c, 0x1a, 0x16, 0x54, 0xb2, 0xd0, 0xb8, 0x75, 0x77, 0xc9, 0xa1, 0xc7, 0x25, 0xf5, - 0x44, 0x15, 0xdc, 0x5f, 0x52, 0xdd, 0xe0, 0x69, 0x5f, 0x9f, 0x6d, 0xcb, 0x4b, 0x6e, 0xe3, - 0xe3, 0xea, 0x70, 0x29, 0x04, 0xc1, 0x1f, 0xf9, 0x2f, 0x55, 0x53, 0x4c, 0x7e, 0xf9, 0x8c, - 0xe7, 0x93, 0xd7, 0x47, 0x56, 0xa4, 0x5d, 0x4e, 0x32, 0x0a, 0x42, 0x5e, 0x98, 0x2d, 0x5b, - 0x37, 0x2d, 0x6a, 0x8d, 0x41, 0xfb, 0x86, 0xba, 0x51, 0x64, 0x81, 0x68, 0x32, 0xa4, 0x81, - 0x82, 0x5c, 0x8c, 0x6a, 0xd7, 0x27, 0x09, 0x69, 0x85, 0x9e, 0x55, 0xd2, 0x36, 0x75, 0x35, - 0x06, 0x0f, 0x99, 0x85, 0x70, 0x65, 0x17, 0x04, 0x66, 0xbd, 0xb7, 0x0c, 0xb9, 0x3a, 0xb2, - 0xf9, 0xc0, 0xe2, 0x93, 0xa0, 0xa9, 0x19, 0x84, 0x3b, 0xbf, 0x34, 0xc2, 0xfe, 0x61, 0xb0, - 0xc3, 0xe3, 0x2a, 0xa7, 0x07, 0x8e, 0x83, 0xd4, 0xc1, 0x92, 0x9e, 0x1e, 0x1d, 0x86, 0x14, - 0x1c, 0xde, 0xb1, 0x89, 0x20, 0x91, 0x09, 0x75, 0xdb, 0x3a, 0x76, 0x26, 0x82, 0x05, 0x99, - 0x63, 0x0c, 0x42, 0x3a, 0xde, 0x23, 0x3d, 0x5d, 0x60, 0x68, 0x55, 0x24, 0xe8, 0xd8, 0x03, - 0x2b, 0x86, 0x1b, 0x4a, 0xad, 0x20, 0x02, 0xa8, 0xfd, 0x17, 0xc9, 0x28, 0x2b, 0x82, 0x5f, - 0x02, 0xd3, 0x53, 0xe2, 0x91, 0x37, 0x9c, 0xed, 0x00, 0xeb, 0xaa, 0x3c, 0x03, 0xe0, 0x1d, - 0x9c, 0x59, 0xf4, 0x05, 0x09, 0x9d, 0x1c, 0x34, 0x32, 0xba, 0xd0, 0x63, 0x58, 0xd6, 0xb1, - 0x94, 0x2f, 0x0b, 0xaf, 0x71, 0x09, 0x98, 0xd1, 0x0a, 0x22, 0xd1, 0x55, 0xb0, 0xfe, 0x84, - 0x99, 0x52, 0x89, 0x31, 0x26, 0x94, 0x9f, 0xf9, 0x2d, 0xe3, 0xa4, 0xc2, 0xee, 0xaf, 0xdf, - 0x68, 0x84, 0x35, 0xe3, 0x25, 0xd8, 0x1c, 0x2c, 0xe0, 0x08, 0xcf, 0x6c, 0x76, 0x03, 0x0d, - 0x4d, 0x46, 0x34, 0x2a, 0xc3, 0x37, 0x2c, 0x73, 0x98, 0x65, 0x60, 0xc4, 0xec, 0x35, 0xa6, - 0xf6, 0x49, 0xef, 0x02, 0xc1, 0x19, 0x36, 0xb7, 0x03, 0x9b, 0xc6, 0xf5, 0xd0, 0x94, 0x38, - 0xdb, 0xe4, 0x76, 0x25, 0x1b, 0x59, 0x64, 0xb6, 0x8f, 0x02, 0xee, 0xdf, 0xf7, 0xa9, 0xe0, - 0xed, 0x3e, 0x30, 0x90, 0x96, 0x5a, 0x22, 0xf2, 0xc5, 0x52, 0xce, 0x3b, 0x2b, 0x47, 0x4f, - 0xd2, 0xfc, 0x06, 0xb5, 0x09, 0x27, 0x83, 0x0a, 0x05, 0xa3, 0x03, 0xfa, 0xff, 0xd6, 0x84, - 0x82, 0xd7, 0xb7, 0x85, 0x38, 0x43, 0x25, 0x40, 0xdd, 0x32, 0x61, 0xab, 0x75, 0x9b, 0x65, - 0x82, 0x12, 0x9a, 0x7f, 0x18, 0xd8, 0x01, 0xc5, 0x43, 0x19, 0xca, 0x52, 0xa3, 0xc6, 0xa3, - 0xdb, 0x63, 0x50, 0x44, 0xd6, 0x25, 0xe2, 0x40, 0x38, 0xad, 0x42, 0x77, 0xf8, 0xd5, 0xbf, - 0x01, 0x60, 0x35, 0x16, 0x5f, 0x21, 0xb0, 0x70, 0xe8, 0x16, 0x9d, 0x65, 0x7d, 0x6e, 0xd1, - 0xfa, 0x7f, 0x8e, 0xd0, 0x9b, 0x4e, 0x1d, 0x9c, 0xa2, 0xe5, 0x1a, 0x24, 0xda, 0x55, 0xe4, - 0x3b, 0x3f, 0xca, 0x98, 0x59, 0xb2, 0x40, 0x8c, 0x26, 0xaa, 0xcb, 0xad, 0x74, 0x9e, 0xbe, - 0x88, 0x2c, 0x31, 0xe7, 0x20, 0x5e, 0x63, 0x8b, 0xb7, 0xe2, 0xbf, 0xc8, 0xa3, 0xf1, 0xc0, - 0x2c, 0x0c, 0xa7, 0xbb, 0x9d, 0xaa, 0xab, 0x7f, 0xcb, 0xf8, 0x45, 0xd8, 0x00, 0x2c, 0x3d, - 0xe7, 0x99, 0x24, 0xdc, 0xaa, 0xdc, 0x24, 0xbd, 0xc0, 0x08, 0x2f, 0x4a, 0x6b, 0x61, 0x87, - 0x6f, 0x31, 0x92, 0xa8, 0x81, 0xf5, 0x9a, 0x68, 0x2d, 0x27, 0x36, 0x85, 0xd4, 0x79, 0x5c, - 0x9b, 0xd7, 0xcc, 0xcf, 0x49, 0xde, 0x34, 0x44, 0x3a, 0x9f, 0x9c, 0xb3, 0x5b, 0xbf, 0x25, - 0x4c, 0x50, 0x61, 0x1b, 0x7c, 0x13, 0x24, 0xb1, 0x10, 0x94, 0x66, 0x7b, 0x6b, 0x60, 0x8c, - 0x39, 0xd1, 0x25, 0x2c, 0xeb, 0xcc, 0x48, 0x77, 0xce, 0xea, 0x76, 0xe1, 0x9b, 0x84, 0x2b, - 0x67, 0xf6, 0x26, 0x74, 0x3f, 0xab, 0x29, 0x77, 0x76, 0xcc, 0x9c, 0xf7, 0x9e, 0x90, 0xe8, - 0xfc, 0xe1, 0x00, 0x17, 0x90, 0xc2, 0xe7, 0xd5, 0xc9, 0x58, 0x64, 0x7c, 0xca, 0x5d, 0x33, - 0x97, 0xd2, 0x0a, 0xfc, 0xf2, 0x9b, 0xa4, 0x4f, 0x62, 0xa7, 0xc6, 0x2e, 0x90, 0x8d, 0x84, - 0x8d, 0x81, 0xa7, 0x9f, 0xad, 0xbb, 0x37, 0x0a, 0xba, 0x93, 0xb0, 0x3e, 0x41, 0xd4, 0xbc, - 0x49, 0xe2, 0x99, 0xd6, 0xd3, 0x3f, 0xaf, 0x86, 0x9f, 0x36, 0x37, 0x14, 0x14, 0xce, 0x64, - 0x6f, 0xc2, 0xca, 0x6d, 0xcf, 0xf5, 0x5a, 0x6e, 0x06, 0x39, 0xd5, 0x0c, 0xae, 0xb1, 0x14, - 0xc4, 0x18, 0xc6, 0x26, 0xb8, 0x67, 0x15, 0x43, 0x64, 0x81, 0xd1, 0x92, 0x8d, 0x55, 0xa7, - 0x56, 0xa6, 0x03, 0xe7, 0x11, 0x0c, 0x3a, 0xfe, 0x96, 0x3c, 0x2b, 0x29, 0xa4, 0x78, 0xf9, - 0xd4, 0x39, 0x7b, 0x88, 0x5a, 0x67, 0xb0, 0x93, 0xa3, 0x45, 0x79, 0x62, 0x19, 0xc1, 0x11, - 0xb7, 0xe9, 0x4d, 0xb3, 0x90, 0xaa, 0x4b, 0xb7, 0x6b, 0x66, 0xa5, 0x34, 0xe5, 0xe2, 0x67, - 0x9b, 0x27, 0xdb, 0x5f, 0x95, 0xfd, 0x09, 0xa3, 0x6b, 0x05, - ]; - let tx = Transaction::read(&data[..]).unwrap(); - - let mut encoded = Vec::with_capacity(data.len()); - tx.write(&mut encoded).unwrap(); - assert_eq!(&data[..], &encoded[..]); -} - -#[test] -fn tx_write_rejects_unexpected_joinsplit_pubkey() { - // Succeeds without a JoinSplit pubkey - { - let tx = TransactionData::new().freeze(); - let mut encoded = Vec::new(); - assert!(tx.write(&mut encoded).is_ok()); - } - - // Fails with an unexpected JoinSplit pubkey - { - let mut tx = TransactionData::new(); - tx.joinsplit_pubkey = Some([0; 32]); - let tx = tx.freeze(); - - let mut encoded = Vec::new(); - assert!(tx.write(&mut encoded).is_err()); - } -} - -#[test] -fn tx_write_rejects_unexpected_joinsplit_sig() { - // Succeeds without a JoinSplit signature - { - let tx = TransactionData::new().freeze(); - let mut encoded = Vec::new(); - assert!(tx.write(&mut encoded).is_ok()); - } - - // Fails with an unexpected JoinSplit signature - { - let mut tx = TransactionData::new(); - tx.joinsplit_sig = Some([0; 64]); - let tx = tx.freeze(); - - let mut encoded = Vec::new(); - assert!(tx.write(&mut encoded).is_err()); - } -} - -#[test] -fn tx_write_rejects_unexpected_binding_sig() { - // Succeeds without a binding signature - { - let tx = TransactionData::new().freeze(); - let mut encoded = Vec::new(); - assert!(tx.write(&mut encoded).is_ok()); - } - - // Fails with an unexpected binding signature - { - let rng = &mut thread_rng(); - let sk = PrivateKey::(rng.gen()); - let sig = sk.sign( - b"Foo bar", - rng, - FixedGenerators::SpendingKeyGenerator, - &JUBJUB, - ); - - let mut tx = TransactionData::new(); - tx.binding_sig = Some(sig); - let tx = tx.freeze(); - - let mut encoded = Vec::new(); - assert!(tx.write(&mut encoded).is_err()); - } -} - -#[test] -fn zip_0143() { - struct TestVector { - tx: Vec, - script_code: Vec, - transparent_input: Option, - hash_type: u32, - amount: i64, - consensus_branch_id: u32, - sighash: [u8; 32], - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0143.py - let test_vectors = vec![ - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x00, 0x02, 0xe7, 0x71, 0x98, 0x11, - 0x89, 0x3e, 0x00, 0x00, 0x09, 0x52, 0x00, 0xac, 0x65, 0x51, 0xac, 0x63, 0x65, 0x65, - 0xb2, 0x83, 0x5a, 0x08, 0x05, 0x75, 0x02, 0x00, 0x02, 0x51, 0x51, 0x48, 0x1c, 0xdd, - 0x86, 0xb3, 0xcc, 0x43, 0x18, 0x00, - ], - script_code: vec![0x6a, 0x00, 0x00, 0x00, 0x63, 0xac, 0x53], - transparent_input: None, - hash_type: 1, - amount: 1672704339313879, - consensus_branch_id: 1537743641, - sighash: [ - 0xa1, 0xf1, 0xa4, 0xe5, 0xcd, 0x9b, 0xd5, 0x22, 0x32, 0x2d, 0x66, 0x1e, 0xdd, 0x2a, - 0xf1, 0xbf, 0x2a, 0x70, 0x19, 0xcf, 0xab, 0x94, 0xec, 0xe1, 0x8f, 0x4b, 0xa9, 0x35, - 0xb0, 0xa1, 0x90, 0x73, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x42, 0x01, 0xcf, 0xb1, 0xcd, - 0x8d, 0xbf, 0x69, 0xb8, 0x25, 0x0c, 0x18, 0xef, 0x41, 0x29, 0x4c, 0xa9, 0x79, 0x93, - 0xdb, 0x54, 0x6c, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, 0xa5, 0xe2, 0x9d, - 0x4e, 0x30, 0xa7, 0x03, 0xac, 0x6a, 0x00, 0x98, 0x42, 0x1c, 0x69, 0x37, 0x8a, 0xf1, - 0xe4, 0x0f, 0x64, 0xe1, 0x25, 0x94, 0x6f, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, - 0xb6, 0x4b, 0x69, 0x68, 0x91, 0x2a, 0x63, 0x81, 0xce, 0x3d, 0xc1, 0x66, 0xd5, 0x6a, - 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x05, 0x63, 0x63, 0x63, 0x53, 0x53, 0xe8, 0xc7, 0x20, - 0x3d, 0x02, 0xd2, 0xda, 0x86, 0x38, 0x7a, 0xe6, 0x01, 0x00, 0x08, 0x00, 0x63, 0x65, - 0x6a, 0x63, 0xac, 0x52, 0x00, 0xa7, 0x62, 0x29, 0x97, 0xf4, 0xff, 0x04, 0x00, 0x07, - 0x51, 0x51, 0x00, 0x53, 0x53, 0x65, 0x65, 0x97, 0xb0, 0xe4, 0xe4, 0xc7, 0x05, 0xfc, - 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x76, 0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, - 0xfa, 0x3d, 0x5a, 0x57, 0xef, 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, - 0xfb, 0x1a, 0x38, 0xe0, 0x1d, 0x94, 0x90, 0x3d, 0x3c, 0x3e, 0x0a, 0xd3, 0x36, 0x0c, - 0x1d, 0x37, 0x10, 0xac, 0xd2, 0x0b, 0x18, 0x3e, 0x31, 0xd4, 0x9f, 0x25, 0xc9, 0xa1, - 0x38, 0xf4, 0x9b, 0x1a, 0x53, 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x51, 0xa7, - 0xaf, 0x9d, 0xb6, 0x99, 0x0e, 0xd8, 0x3d, 0xd6, 0x4a, 0xf3, 0x59, 0x7c, 0x04, 0x32, - 0x3e, 0xa5, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, 0xb9, 0xda, 0x94, 0x8d, 0x32, - 0x0d, 0xad, 0xd6, 0x4f, 0x54, 0x31, 0xe6, 0x1d, 0xdf, 0x65, 0x8d, 0x24, 0xae, 0x67, - 0xc2, 0x2c, 0x8d, 0x13, 0x09, 0x13, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, 0x42, - 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x91, 0xe0, 0x0c, 0x7a, 0x1d, 0x48, 0xaf, 0x04, - 0x68, 0x27, 0x59, 0x1e, 0x97, 0x33, 0xa9, 0x7f, 0xa6, 0xb6, 0x79, 0xf3, 0xdc, 0x60, - 0x1d, 0x00, 0x82, 0x85, 0xed, 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0xfc, 0x1b, 0xe4, 0xaa, - 0xc0, 0x0f, 0xf2, 0x71, 0x1e, 0xbd, 0x93, 0x1d, 0xe5, 0x18, 0x85, 0x68, 0x78, 0xf7, - 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, 0x3c, - 0x94, 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, 0x79, - 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, 0x32, 0xb4, 0xf4, - 0x73, 0xf4, 0x68, 0xa0, 0x08, 0xe7, 0x23, 0x89, 0xfc, 0x03, 0x88, 0x0d, 0x78, 0x0c, - 0xb0, 0x7f, 0xcf, 0xaa, 0xbe, 0x3f, 0x1a, 0x84, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, - 0x3d, 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x55, 0xed, 0x94, 0x94, 0xc6, 0xac, - 0x89, 0x3c, 0x49, 0x72, 0x38, 0x33, 0xec, 0x89, 0x26, 0xc1, 0x03, 0x95, 0x86, 0xa7, - 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, 0x73, 0x1e, 0x98, 0x5d, 0x99, 0x58, 0x9c, 0x03, 0xb8, - 0x38, 0xe8, 0xaa, 0xf7, 0x45, 0x53, 0x3e, 0xd9, 0xe8, 0xae, 0x3a, 0x1c, 0xd0, 0x74, - 0xa5, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, 0xeb, 0xbc, 0x86, 0x2d, 0xed, - 0x42, 0x43, 0x5e, 0x02, 0x47, 0x69, 0x30, 0xd0, 0x69, 0x89, 0x6c, 0xff, 0x30, 0xeb, - 0x41, 0x4f, 0x72, 0x7b, 0x89, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, 0x6d, - 0x75, 0xa4, 0xa6, 0xf2, 0x65, 0x72, 0x50, 0x4b, 0x0b, 0x22, 0x32, 0xec, 0xb9, 0xf0, - 0xc0, 0x24, 0x11, 0xe5, 0x25, 0x96, 0xbc, 0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, - 0xff, 0xed, 0xbd, 0x12, 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, 0x7d, 0x41, 0x7a, - 0xdb, 0x3d, 0x15, 0xcc, 0x54, 0xdc, 0xb1, 0xfc, 0xe4, 0x67, 0x50, 0x0c, 0x6b, 0x8f, - 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, 0x82, 0x85, 0x7d, 0xee, 0xcc, 0x40, 0xa9, - 0x8d, 0x5f, 0x29, 0x03, 0x39, 0x5e, 0xe4, 0x76, 0x2d, 0xd2, 0x1a, 0xfd, 0xbb, 0x5d, - 0x47, 0xfa, 0x9a, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, 0xb9, 0x27, 0xb7, - 0xfa, 0xe2, 0xdb, 0x58, 0x71, 0x05, 0x41, 0x5d, 0x02, 0x42, 0x78, 0x9d, 0x38, 0xf5, - 0x0b, 0x8d, 0xbc, 0xc1, 0x29, 0xca, 0xb3, 0xd1, 0x7d, 0x19, 0xf3, 0x35, 0x5b, 0xcf, - 0x73, 0xce, 0xcb, 0x8c, 0xb8, 0xa5, 0xda, 0x01, 0x30, 0x71, 0x52, 0xf1, 0x39, 0x02, - 0xa2, 0x70, 0x57, 0x26, 0x70, 0xdc, 0x82, 0xd3, 0x90, 0x26, 0xc6, 0xcb, 0x4c, 0xd4, - 0xb0, 0xf7, 0xf5, 0xaa, 0x2a, 0x4f, 0x5a, 0x53, 0x41, 0xec, 0x5d, 0xd7, 0x15, 0x40, - 0x6f, 0x2f, 0xdd, 0x2a, 0x02, 0x73, 0x3f, 0x5f, 0x64, 0x1c, 0x8c, 0x21, 0x86, 0x2a, - 0x1b, 0xaf, 0xce, 0x26, 0x09, 0xd9, 0xee, 0xcf, 0xa1, 0x58, 0xcf, 0xb5, 0xcd, 0x79, - 0xf8, 0x80, 0x08, 0xe3, 0x15, 0xdc, 0x7d, 0x83, 0x88, 0x03, 0x6c, 0x17, 0x82, 0xfd, - 0x27, 0x95, 0xd1, 0x8a, 0x76, 0x36, 0x24, 0xc2, 0x5f, 0xa9, 0x59, 0xcc, 0x97, 0x48, - 0x9c, 0xe7, 0x57, 0x45, 0x82, 0x4b, 0x77, 0x86, 0x8c, 0x53, 0x23, 0x9c, 0xfb, 0xdf, - 0x73, 0xca, 0xec, 0x65, 0x60, 0x40, 0x37, 0x31, 0x4f, 0xaa, 0xce, 0xb5, 0x62, 0x18, - 0xc6, 0xbd, 0x30, 0xf8, 0x37, 0x4a, 0xc1, 0x33, 0x86, 0x79, 0x3f, 0x21, 0xa9, 0xfb, - 0x80, 0xad, 0x03, 0xbc, 0x0c, 0xda, 0x4a, 0x44, 0x94, 0x6c, 0x00, 0xe1, 0xb1, 0xa1, - 0xdf, 0x0e, 0x5b, 0x87, 0xb5, 0xbe, 0xce, 0x47, 0x7a, 0x70, 0x96, 0x49, 0xe9, 0x50, - 0x06, 0x05, 0x91, 0x39, 0x48, 0x12, 0x95, 0x1e, 0x1f, 0xe3, 0x89, 0x5b, 0x8c, 0xc3, - 0xd1, 0x4d, 0x2c, 0xf6, 0x55, 0x6d, 0xf6, 0xed, 0x4b, 0x4d, 0xdd, 0x3d, 0x9a, 0x69, - 0xf5, 0x33, 0x57, 0xd7, 0x76, 0x7f, 0x4f, 0x5c, 0xcb, 0xdb, 0xc5, 0x96, 0x63, 0x12, - 0x77, 0xf8, 0xfe, 0xcd, 0x08, 0xcb, 0x05, 0x6b, 0x95, 0xe3, 0x02, 0x5b, 0x97, 0x92, - 0xff, 0xf7, 0xf2, 0x44, 0xfc, 0x71, 0x62, 0x69, 0xb9, 0x26, 0xd6, 0x2e, 0x95, 0x96, - 0xfa, 0x82, 0x5c, 0x6b, 0xf2, 0x1a, 0xff, 0x9e, 0x68, 0x62, 0x5a, 0x19, 0x24, 0x40, - 0xea, 0x06, 0x82, 0x81, 0x23, 0xd9, 0x78, 0x84, 0x80, 0x6f, 0x15, 0xfa, 0x08, 0xda, - 0x52, 0x75, 0x4a, 0x10, 0x95, 0xe3, 0xff, 0x1a, 0xbd, 0x5c, 0xe4, 0xfd, 0xdf, 0xcc, - 0xfc, 0x3a, 0x61, 0x28, 0xae, 0xf7, 0x84, 0xa6, 0x46, 0x10, 0xa8, 0x9d, 0x1a, 0x70, - 0x99, 0x21, 0x6d, 0x08, 0x14, 0xd3, 0xa2, 0xd4, 0x52, 0x43, 0x1c, 0x32, 0xd4, 0x11, - 0xac, 0x1c, 0xce, 0x82, 0xad, 0x02, 0x29, 0x40, 0x7b, 0xbc, 0x48, 0x98, 0x56, 0x75, - 0xe3, 0xf8, 0x74, 0xa4, 0x53, 0x3f, 0x1d, 0x63, 0xa8, 0x4d, 0xfa, 0x3e, 0x0f, 0x46, - 0x0f, 0xe2, 0xf5, 0x7e, 0x34, 0xfb, 0xc7, 0x54, 0x23, 0xc3, 0x73, 0x7f, 0x5b, 0x2a, - 0x06, 0x15, 0xf5, 0x72, 0x2d, 0xb0, 0x41, 0xa3, 0xef, 0x66, 0xfa, 0x48, 0x3a, 0xfd, - 0x3c, 0x2e, 0x19, 0xe5, 0x94, 0x44, 0xa6, 0x4a, 0xdd, 0x6d, 0xf1, 0xd9, 0x63, 0xf5, - 0xdd, 0x5b, 0x50, 0x10, 0xd3, 0xd0, 0x25, 0xf0, 0x28, 0x7c, 0x4c, 0xf1, 0x9c, 0x75, - 0xf3, 0x3d, 0x51, 0xdd, 0xdd, 0xba, 0x5d, 0x65, 0x7b, 0x43, 0xee, 0x8d, 0xa6, 0x45, - 0x44, 0x38, 0x14, 0xcc, 0x73, 0x29, 0xf3, 0xe9, 0xb4, 0xe5, 0x4c, 0x23, 0x6c, 0x29, - 0xaf, 0x39, 0x23, 0x10, 0x17, 0x56, 0xd9, 0xfa, 0x4b, 0xd0, 0xf7, 0xd2, 0xdd, 0xaa, - 0xcb, 0x6b, 0x0f, 0x86, 0xa2, 0x65, 0x8e, 0x0a, 0x07, 0xa0, 0x5a, 0xc5, 0xb9, 0x50, - 0x05, 0x1c, 0xd2, 0x4c, 0x47, 0xa8, 0x8d, 0x13, 0xd6, 0x59, 0xba, 0x2a, 0x46, 0xca, - 0x18, 0x30, 0x81, 0x6d, 0x09, 0xcd, 0x76, 0x46, 0xf7, 0x6f, 0x71, 0x6a, 0xbe, 0xc5, - 0xde, 0x07, 0xfe, 0x9b, 0x52, 0x34, 0x10, 0x80, 0x6e, 0xa6, 0xf2, 0x88, 0xf8, 0x73, - 0x6c, 0x23, 0x35, 0x7c, 0x85, 0xf4, 0x57, 0x91, 0xe1, 0x70, 0x80, 0x29, 0xd9, 0x82, - 0x4d, 0x90, 0x70, 0x46, 0x07, 0xf3, 0x87, 0xa0, 0x3e, 0x49, 0xbf, 0x98, 0x36, 0x57, - 0x44, 0x31, 0x34, 0x5a, 0x78, 0x77, 0xef, 0xaa, 0x8a, 0x08, 0xe7, 0x30, 0x81, 0xef, - 0x8d, 0x62, 0xcb, 0x78, 0x0a, 0xb6, 0x88, 0x3a, 0x50, 0xa0, 0xd4, 0x70, 0x19, 0x0d, - 0xfb, 0xa1, 0x0a, 0x85, 0x7f, 0x82, 0x84, 0x2d, 0x38, 0x25, 0xb3, 0xd6, 0xda, 0x05, - 0x73, 0xd3, 0x16, 0xeb, 0x16, 0x0d, 0xc0, 0xb7, 0x16, 0xc4, 0x8f, 0xbd, 0x46, 0x7f, - 0x75, 0xb7, 0x80, 0x14, 0x9a, 0xe8, 0x80, 0x8f, 0x4e, 0x68, 0xf5, 0x0c, 0x05, 0x36, - 0xac, 0xdd, 0xf6, 0xf1, 0xae, 0xab, 0x01, 0x6b, 0x6b, 0xc1, 0xec, 0x14, 0x4b, 0x4e, - 0x55, 0x3a, 0xcf, 0xd6, 0x70, 0xf7, 0x7e, 0x75, 0x5f, 0xc8, 0x8e, 0x06, 0x77, 0xe3, - 0x1b, 0xa4, 0x59, 0xb4, 0x4e, 0x30, 0x77, 0x68, 0x95, 0x8f, 0xe3, 0x78, 0x9d, 0x41, - 0xc2, 0xb1, 0xff, 0x43, 0x4c, 0xb3, 0x0e, 0x15, 0x91, 0x4f, 0x01, 0xbc, 0x6b, 0xc2, - 0x30, 0x7b, 0x48, 0x8d, 0x25, 0x56, 0xd7, 0xb7, 0x38, 0x0e, 0xa4, 0xff, 0xd7, 0x12, - 0xf6, 0xb0, 0x2f, 0xe8, 0x06, 0xb9, 0x45, 0x69, 0xcd, 0x40, 0x59, 0xf3, 0x96, 0xbf, - 0x29, 0xb9, 0x9d, 0x0a, 0x40, 0xe5, 0xe1, 0x71, 0x1c, 0xa9, 0x44, 0xf7, 0x2d, 0x43, - 0x6a, 0x10, 0x2f, 0xca, 0x4b, 0x97, 0x69, 0x3d, 0xa0, 0xb0, 0x86, 0xfe, 0x9d, 0x2e, - 0x71, 0x62, 0x47, 0x0d, 0x02, 0xe0, 0xf0, 0x5d, 0x4b, 0xec, 0x95, 0x12, 0xbf, 0xb3, - 0xf3, 0x83, 0x27, 0x29, 0x6e, 0xfa, 0xa7, 0x43, 0x28, 0xb1, 0x18, 0xc2, 0x74, 0x02, - 0xc7, 0x0c, 0x3a, 0x90, 0xb4, 0x9a, 0xd4, 0xbb, 0xc6, 0x8e, 0x37, 0xc0, 0xaa, 0x7d, - 0x9b, 0x3f, 0xe1, 0x77, 0x99, 0xd7, 0x3b, 0x84, 0x1e, 0x75, 0x17, 0x13, 0xa0, 0x29, - 0x43, 0x90, 0x5a, 0xae, 0x08, 0x03, 0xfd, 0x69, 0x44, 0x2e, 0xb7, 0x68, 0x1e, 0xc2, - 0xa0, 0x56, 0x00, 0x05, 0x4e, 0x92, 0xee, 0xd5, 0x55, 0x02, 0x8f, 0x21, 0xb6, 0xa1, - 0x55, 0x26, 0x8a, 0x2d, 0xd6, 0x64, 0x0a, 0x69, 0x30, 0x1a, 0x52, 0xa3, 0x8d, 0x4d, - 0x9f, 0x9f, 0x95, 0x7a, 0xe3, 0x5a, 0xf7, 0x16, 0x71, 0x18, 0x14, 0x1c, 0xe4, 0xc9, - 0xbe, 0x0a, 0x6a, 0x49, 0x2f, 0xe7, 0x9f, 0x15, 0x81, 0xa1, 0x55, 0xfa, 0x3a, 0x2b, - 0x9d, 0xaf, 0xd8, 0x2e, 0x65, 0x0b, 0x38, 0x6a, 0xd3, 0xa0, 0x8c, 0xb6, 0xb8, 0x31, - 0x31, 0xac, 0x30, 0x0b, 0x08, 0x46, 0x35, 0x4a, 0x7e, 0xef, 0x9c, 0x41, 0x0e, 0x4b, - 0x62, 0xc4, 0x7c, 0x54, 0x26, 0x90, 0x7d, 0xfc, 0x66, 0x85, 0xc5, 0xc9, 0x9b, 0x71, - 0x41, 0xac, 0x62, 0x6a, 0xb4, 0x76, 0x1f, 0xd3, 0xf4, 0x1e, 0x72, 0x8e, 0x1a, 0x28, - 0xf8, 0x9d, 0xb8, 0x9f, 0xfd, 0xec, 0xa3, 0x64, 0xdd, 0x2f, 0x0f, 0x07, 0x39, 0xf0, - 0x53, 0x45, 0x56, 0x48, 0x31, 0x99, 0xc7, 0x1f, 0x18, 0x93, 0x41, 0xac, 0x9b, 0x78, - 0xa2, 0x69, 0x16, 0x42, 0x06, 0xa0, 0xea, 0x1c, 0xe7, 0x3b, 0xfb, 0x2a, 0x94, 0x2e, - 0x73, 0x70, 0xb2, 0x47, 0xc0, 0x46, 0xf8, 0xe7, 0x5e, 0xf8, 0xe3, 0xf8, 0xbd, 0x82, - 0x1c, 0xf5, 0x77, 0x49, 0x18, 0x64, 0xe2, 0x0e, 0x6d, 0x08, 0xfd, 0x2e, 0x32, 0xb5, - 0x55, 0xc9, 0x2c, 0x66, 0x1f, 0x19, 0x58, 0x8b, 0x72, 0xa8, 0x95, 0x99, 0x71, 0x0a, - 0x88, 0x06, 0x12, 0x53, 0xca, 0x28, 0x5b, 0x63, 0x04, 0xb3, 0x7d, 0xa2, 0xb5, 0x29, - 0x4f, 0x5c, 0xb3, 0x54, 0xa8, 0x94, 0x32, 0x28, 0x48, 0xcc, 0xbd, 0xc7, 0xc2, 0x54, - 0x5b, 0x7d, 0xa5, 0x68, 0xaf, 0xac, 0x87, 0xff, 0xa0, 0x05, 0xc3, 0x12, 0x24, 0x1c, - 0x2d, 0x57, 0xf4, 0xb4, 0x5d, 0x64, 0x19, 0xf0, 0xd2, 0xe2, 0xc5, 0xaf, 0x33, 0xae, - 0x24, 0x37, 0x85, 0xb3, 0x25, 0xcd, 0xab, 0x95, 0x40, 0x4f, 0xc7, 0xae, 0xd7, 0x05, - 0x25, 0xcd, 0xdb, 0x41, 0x87, 0x2c, 0xfc, 0xc2, 0x14, 0xb1, 0x32, 0x32, 0xed, 0xc7, - 0x86, 0x09, 0x75, 0x3d, 0xbf, 0xf9, 0x30, 0xeb, 0x0d, 0xc1, 0x56, 0x61, 0x2b, 0x9c, - 0xb4, 0x34, 0xbc, 0x4b, 0x69, 0x33, 0x92, 0xde, 0xb8, 0x7c, 0x53, 0x04, 0x35, 0x31, - 0x2e, 0xdc, 0xed, 0xc6, 0xa9, 0x61, 0x13, 0x33, 0x38, 0xd7, 0x86, 0xc4, 0xa3, 0xe1, - 0x03, 0xf6, 0x01, 0x10, 0xa1, 0x6b, 0x13, 0x37, 0x12, 0x97, 0x04, 0xbf, 0x47, 0x54, - 0xff, 0x6b, 0xa9, 0xfb, 0xe6, 0x59, 0x51, 0xe6, 0x10, 0x62, 0x0f, 0x71, 0xcd, 0xa8, - 0xfc, 0x87, 0x76, 0x25, 0xf2, 0xc5, 0xbb, 0x04, 0xcb, 0xe1, 0x22, 0x8b, 0x1e, 0x88, - 0x6f, 0x40, 0x50, 0xaf, 0xd8, 0xfe, 0x94, 0xe9, 0x7d, 0x2e, 0x9e, 0x85, 0xc6, 0xbb, - 0x74, 0x8c, 0x00, 0x42, 0xd3, 0x24, 0x9a, 0xbb, 0x13, 0x42, 0xbb, 0x0e, 0xeb, 0xf6, - 0x20, 0x58, 0xbf, 0x3d, 0xe0, 0x80, 0xd9, 0x46, 0x11, 0xa3, 0x75, 0x09, 0x15, 0xb5, - 0xdc, 0x6c, 0x0b, 0x38, 0x99, 0xd4, 0x12, 0x22, 0xba, 0xce, 0x76, 0x0e, 0xe9, 0xc8, - 0x81, 0x8d, 0xed, 0x59, 0x9e, 0x34, 0xc5, 0x6d, 0x73, 0x72, 0xaf, 0x1e, 0xb8, 0x68, - 0x52, 0xf2, 0xa7, 0x32, 0x10, 0x4b, 0xdb, 0x75, 0x07, 0x39, 0xde, 0x6c, 0x2c, 0x6e, - 0x0f, 0x9e, 0xb7, 0xcb, 0x17, 0xf1, 0x94, 0x2b, 0xfc, 0x9f, 0x4f, 0xd6, 0xeb, 0xb6, - 0xb4, 0xcd, 0xd4, 0xda, 0x2b, 0xca, 0x26, 0xfa, 0xc4, 0x57, 0x8e, 0x9f, 0x54, 0x34, - 0x05, 0xac, 0xc7, 0xd8, 0x6f, 0xf5, 0x91, 0x58, 0xbd, 0x0c, 0xba, 0x3a, 0xef, 0x6f, - 0x4a, 0x84, 0x72, 0xd1, 0x44, 0xd9, 0x9f, 0x8b, 0x8d, 0x1d, 0xed, 0xaa, 0x90, 0x77, - 0xd4, 0xf0, 0x1d, 0x4b, 0xb2, 0x7b, 0xbe, 0x31, 0xd8, 0x8f, 0xbe, 0xfa, 0xc3, 0xdc, - 0xd4, 0x79, 0x75, 0x63, 0xa2, 0x6b, 0x1d, 0x61, 0xfc, 0xd9, 0xa4, 0x64, 0xab, 0x21, - 0xed, 0x55, 0x0f, 0xe6, 0xfa, 0x09, 0x69, 0x5b, 0xa0, 0xb2, 0xf1, 0x0e, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xea, 0x64, 0x68, 0xcc, 0x6e, 0x20, 0xa6, 0x6f, 0x82, 0x6e, 0x3d, 0x14, 0xc5, 0x00, - 0x6f, 0x05, 0x63, 0x88, 0x7f, 0x5e, 0x12, 0x89, 0xbe, 0x1b, 0x20, 0x04, 0xca, 0xca, - 0x8d, 0x3f, 0x34, 0xd6, 0xe8, 0x4b, 0xf5, 0x9c, 0x1e, 0x04, 0x61, 0x9a, 0x7c, 0x23, - 0xa9, 0x96, 0x94, 0x1d, 0x88, 0x9e, 0x46, 0x22, 0xa9, 0xb9, 0xb1, 0xd5, 0x9d, 0x5e, - 0x31, 0x90, 0x94, 0x31, 0x8c, 0xd4, 0x05, 0xba, 0x27, 0xb7, 0xe2, 0xc0, 0x84, 0x76, - 0x2d, 0x31, 0x45, 0x3e, 0xc4, 0x54, 0x9a, 0x4d, 0x97, 0x72, 0x9d, 0x03, 0x34, 0x60, - 0xfc, 0xf8, 0x9d, 0x64, 0x94, 0xf2, 0xff, 0xd7, 0x89, 0xe9, 0x80, 0x82, 0xea, 0x5c, - 0xe9, 0x53, 0x4b, 0x3a, 0xcd, 0x60, 0xfe, 0x49, 0xe3, 0x7e, 0x4f, 0x66, 0x69, 0x31, - 0x67, 0x73, 0x19, 0xed, 0x89, 0xf8, 0x55, 0x88, 0x74, 0x1b, 0x31, 0x28, 0x90, 0x1a, - 0x93, 0xbd, 0x78, 0xe4, 0xbe, 0x02, 0x25, 0xa9, 0xe2, 0x69, 0x2c, 0x77, 0xc9, 0x69, - 0xed, 0x01, 0x76, 0xbd, 0xf9, 0x55, 0x59, 0x48, 0xcb, 0xd5, 0xa3, 0x32, 0xd0, 0x45, - 0xde, 0x6b, 0xa6, 0xbf, 0x44, 0x90, 0xad, 0xfe, 0x74, 0x44, 0xcd, 0x46, 0x7a, 0x09, - 0x07, 0x54, 0x17, 0xfc, 0xc0, 0x06, 0x2e, 0x49, 0xf0, 0x08, 0xc5, 0x1a, 0xd4, 0x22, - 0x74, 0x39, 0xc1, 0xb4, 0x47, 0x6c, 0xcd, 0x8e, 0x97, 0x86, 0x2d, 0xab, 0x7b, 0xe1, - 0xe8, 0xd3, 0x99, 0xc0, 0x5e, 0xf2, 0x7c, 0x6e, 0x22, 0xee, 0x27, 0x3e, 0x15, 0x78, - 0x6e, 0x39, 0x4c, 0x8f, 0x1b, 0xe3, 0x16, 0x82, 0xa3, 0x01, 0x47, 0x96, 0x3a, 0xc8, - 0xda, 0x8d, 0x41, 0xd8, 0x04, 0x25, 0x84, 0x26, 0xa3, 0xf7, 0x02, 0x89, 0xb8, 0xad, - 0x19, 0xd8, 0xde, 0x13, 0xbe, 0x4e, 0xeb, 0xe3, 0xbd, 0x4c, 0x8a, 0x6f, 0x55, 0xd6, - 0xe0, 0xc3, 0x73, 0xd4, 0x56, 0x85, 0x18, 0x79, 0xf5, 0xfb, 0xc2, 0x82, 0xdb, 0x9e, - 0x13, 0x48, 0x06, 0xbf, 0xf7, 0x1e, 0x11, 0xbc, 0x33, 0xab, 0x75, 0xdd, 0x6c, 0xa0, - 0x67, 0xfb, 0x73, 0xa0, 0x43, 0xb6, 0x46, 0xa7, 0x03, 0x39, 0xca, 0xb4, 0x92, 0x83, - 0x86, 0x78, 0x6d, 0x2f, 0x24, 0x14, 0x1e, 0xe1, 0x20, 0xfd, 0xc3, 0x4d, 0x67, 0x64, - 0xea, 0xfc, 0x66, 0x88, 0x0e, 0xe0, 0x20, 0x4f, 0x53, 0xcc, 0x11, 0x67, 0xed, 0x02, - 0xb4, 0x3a, 0x52, 0xde, 0xa3, 0xca, 0x7c, 0xff, 0x8e, 0xf3, 0x5c, 0xd8, 0xe6, 0xd7, - 0xc1, 0x11, 0xa6, 0x8e, 0xf4, 0x4b, 0xcd, 0x0c, 0x15, 0x13, 0xad, 0x47, 0xca, 0x61, - 0xc6, 0x59, 0xcc, 0x5d, 0x0a, 0x5b, 0x44, 0x0f, 0x6b, 0x9f, 0x59, 0xaf, 0xf6, 0x68, - 0x79, 0xbb, 0x66, 0x88, 0xfd, 0x28, 0x59, 0x36, 0x2b, 0x18, 0x2f, 0x20, 0x7b, 0x31, - 0x75, 0x96, 0x1f, 0x64, 0x11, 0xa4, 0x93, 0xbf, 0xfd, 0x04, 0x8e, 0x7d, 0x0d, 0x87, - 0xd8, 0x2f, 0xe6, 0xf9, 0x90, 0xa2, 0xb0, 0xa2, 0x5f, 0x5a, 0xa0, 0x11, 0x1a, 0x6e, - 0x68, 0xf3, 0x7b, 0xf6, 0xf3, 0xac, 0x2d, 0x26, 0xb8, 0x46, 0x86, 0xe5, 0x69, 0x03, - 0x8d, 0x99, 0xc1, 0x38, 0x35, 0x97, 0xfa, 0xd8, 0x11, 0x93, 0xc4, 0xc1, 0xb1, 0x6e, - 0x6a, 0x90, 0xe2, 0xd5, 0x07, 0xcd, 0xfe, 0x6f, 0xbd, 0xaa, 0x86, 0x16, 0x3e, 0x9c, - 0xf5, 0xde, 0x31, 0x00, 0x03, 0xca, 0x7e, 0x8d, 0xa0, 0x47, 0xb0, 0x90, 0xdb, 0x9f, - 0x37, 0x95, 0x2f, 0xbf, 0xee, 0x76, 0xaf, 0x61, 0x66, 0x81, 0x90, 0xbd, 0x52, 0xed, - 0x49, 0x0e, 0x67, 0x7b, 0x51, 0x5d, 0x01, 0x43, 0x84, 0x03, 0x07, 0x21, 0x9c, 0x7c, - 0x0e, 0xe7, 0xfc, 0x7b, 0xfc, 0x79, 0xf3, 0x25, 0x64, 0x4e, 0x4d, 0xf4, 0xc0, 0xd7, - 0xdb, 0x08, 0xe9, 0xf0, 0xbd, 0x02, 0x49, 0x43, 0xc7, 0x05, 0xab, 0xff, 0x89, 0x94, - 0x03, 0xa6, 0x05, 0xcf, 0xbc, 0x7e, 0xd7, 0x46, 0xa7, 0xd3, 0xf7, 0xc3, 0x7d, 0x9e, - 0x8b, 0xdc, 0x43, 0x3b, 0x7d, 0x79, 0xe0, 0x8a, 0x12, 0xf7, 0x38, 0xa8, 0xf0, 0xdb, - 0xdd, 0xfe, 0xf2, 0xf2, 0x65, 0x02, 0xf3, 0xe4, 0x7d, 0x1b, 0x0f, 0xd1, 0x1e, 0x6a, - 0x13, 0x31, 0x1f, 0xb7, 0x99, 0xc7, 0x9c, 0x64, 0x1d, 0x9d, 0xa4, 0x3b, 0x33, 0xe7, - 0xad, 0x01, 0x2e, 0x28, 0x25, 0x53, 0x98, 0x78, 0x92, 0x62, 0x27, 0x5f, 0x11, 0x75, - 0xbe, 0x84, 0x62, 0xc0, 0x14, 0x91, 0xc4, 0xd8, 0x42, 0x40, 0x6d, 0x0e, 0xc4, 0x28, - 0x2c, 0x95, 0x26, 0x17, 0x4a, 0x09, 0x87, 0x8f, 0xe8, 0xfd, 0xde, 0x33, 0xa2, 0x96, - 0x04, 0xe5, 0xe5, 0xe7, 0xb2, 0xa0, 0x25, 0xd6, 0x65, 0x0b, 0x97, 0xdb, 0xb5, 0x2b, - 0xef, 0xb5, 0x9b, 0x1d, 0x30, 0xa5, 0x74, 0x33, 0xb0, 0xa3, 0x51, 0x47, 0x44, 0x44, - 0x09, 0x9d, 0xaa, 0x37, 0x10, 0x46, 0x61, 0x32, 0x60, 0xcf, 0x33, 0x54, 0xcf, 0xcd, - 0xad, 0xa6, 0x63, 0xec, 0xe8, 0x24, 0xff, 0xd7, 0xe4, 0x43, 0x93, 0x88, 0x6a, 0x86, - 0x16, 0x5d, 0xdd, 0xdf, 0x2b, 0x4c, 0x41, 0x77, 0x35, 0x54, 0xc8, 0x69, 0x95, 0x26, - 0x94, 0x08, 0xb1, 0x1e, 0x67, 0x37, 0xa4, 0xc4, 0x47, 0x58, 0x6f, 0x69, 0x17, 0x34, - 0x46, 0xd8, 0xe4, 0x8b, 0xf8, 0x4c, 0xbc, 0x00, 0x0a, 0x80, 0x78, 0x99, 0x97, 0x3e, - 0xb9, 0x3c, 0x5e, 0x81, 0x9a, 0xad, 0x66, 0x94, 0x13, 0xf8, 0x38, 0x79, 0x33, 0xad, - 0x15, 0x84, 0xaa, 0x35, 0xe4, 0x3f, 0x4e, 0xcd, 0x1e, 0x2d, 0x04, 0x07, 0xc0, 0xb1, - 0xb8, 0x99, 0x20, 0xff, 0xdf, 0xdb, 0x9b, 0xea, 0x51, 0xac, 0x95, 0xb5, 0x57, 0xaf, - 0x71, 0xb8, 0x9f, 0x90, 0x3f, 0x5d, 0x98, 0x48, 0xf1, 0x4f, 0xcb, 0xeb, 0x18, 0x37, - 0x57, 0x0f, 0x54, 0x4d, 0x63, 0x59, 0xeb, 0x23, 0xfa, 0xf3, 0x8a, 0x08, 0x22, 0xda, - 0x36, 0xce, 0x42, 0x6c, 0x4a, 0x2f, 0xbe, 0xff, 0xeb, 0x0a, 0x8a, 0x2e, 0x29, 0x7a, - 0x9d, 0x19, 0xba, 0x15, 0x02, 0x45, 0x90, 0xe3, 0x32, 0x9d, 0x9f, 0xa9, 0x26, 0x1f, - 0x99, 0x38, 0xa4, 0x03, 0x2d, 0xd3, 0x46, 0x06, 0xc9, 0xcf, 0x9f, 0x3d, 0xd3, 0x3e, - 0x57, 0x6f, 0x05, 0xcd, 0x1d, 0xd6, 0x81, 0x1c, 0x62, 0x98, 0x75, 0x7d, 0x77, 0xd9, - 0xe8, 0x10, 0xab, 0xdb, 0x22, 0x6a, 0xfc, 0xaa, 0x43, 0x46, 0xa6, 0x56, 0x0f, 0x89, - 0x32, 0xb3, 0x18, 0x1f, 0xd3, 0x55, 0xd5, 0xd3, 0x91, 0x97, 0x61, 0x83, 0xf8, 0xd9, - 0x93, 0x88, 0x83, 0x96, 0x32, 0xd6, 0x35, 0x4f, 0x66, 0x6d, 0x09, 0xd3, 0xe5, 0x62, - 0x9e, 0xa1, 0x97, 0x37, 0x38, 0x86, 0x13, 0xd3, 0x8a, 0x34, 0xfd, 0x0f, 0x6e, 0x50, - 0xee, 0x5a, 0x0c, 0xc9, 0x67, 0x71, 0x77, 0xf5, 0x00, 0x28, 0xc1, 0x41, 0x37, 0x81, - 0x87, 0xbd, 0x28, 0x19, 0x40, 0x3f, 0xc5, 0x34, 0xf8, 0x00, 0x76, 0xe9, 0x38, 0x0c, - 0xb4, 0x96, 0x4d, 0x3b, 0x6b, 0x45, 0x81, 0x9d, 0x3b, 0x8e, 0x9c, 0xaf, 0x54, 0xf0, - 0x51, 0x85, 0x2d, 0x67, 0x1b, 0xf8, 0xc1, 0xff, 0xde, 0x2d, 0x15, 0x10, 0x75, 0x64, - 0x18, 0xcb, 0x48, 0x10, 0x93, 0x6a, 0xa5, 0x7e, 0x69, 0x65, 0xd6, 0xfb, 0x65, 0x6a, - 0x76, 0x0b, 0x7f, 0x19, 0xad, 0xf9, 0x6c, 0x17, 0x34, 0x88, 0x55, 0x21, 0x93, 0xb1, - 0x47, 0xee, 0x58, 0x85, 0x80, 0x33, 0xda, 0xc7, 0xcd, 0x0e, 0xb2, 0x04, 0xc0, 0x64, - 0x90, 0xbb, 0xde, 0xdf, 0x5f, 0x75, 0x71, 0xac, 0xb2, 0xeb, 0xe7, 0x6a, 0xce, 0xf3, - 0xf2, 0xa0, 0x1e, 0xe9, 0x87, 0x48, 0x6d, 0xfe, 0x6c, 0x3f, 0x0a, 0x5e, 0x23, 0x4c, - 0x12, 0x72, 0x58, 0xf9, 0x7a, 0x28, 0xfb, 0x5d, 0x16, 0x4a, 0x81, 0x76, 0xbe, 0x94, - 0x6b, 0x80, 0x97, 0xd0, 0xe3, 0x17, 0x28, 0x7f, 0x33, 0xbf, 0x9c, 0x16, 0xf9, 0xa5, - 0x45, 0x40, 0x9c, 0xe2, 0x9b, 0x1f, 0x42, 0x73, 0x72, 0x5f, 0xc0, 0xdf, 0x02, 0xa0, - 0x4e, 0xba, 0xe1, 0x78, 0xb3, 0x41, 0x4f, 0xb0, 0xa8, 0x2d, 0x50, 0xde, 0xb0, 0x9f, - 0xcf, 0x4e, 0x6e, 0xe9, 0xd1, 0x80, 0xff, 0x4f, 0x56, 0xff, 0x3b, 0xc1, 0xd3, 0x60, - 0x1f, 0xc2, 0xdc, 0x90, 0xd8, 0x14, 0xc3, 0x25, 0x6f, 0x49, 0x67, 0xd3, 0xa8, 0xd6, - 0x4c, 0x83, 0xfe, 0xa3, 0x39, 0xc5, 0x1f, 0x5a, 0x8e, 0x58, 0x01, 0xfb, 0xb9, 0x78, - 0x35, 0x58, 0x1b, 0x60, 0x24, 0x65, 0xde, 0xe0, 0x4b, 0x59, 0x22, 0xc2, 0x76, 0x1b, - 0x54, 0x24, 0x5b, 0xec, 0x0c, 0x9e, 0xef, 0x2d, 0xb9, 0x7d, 0x22, 0xb2, 0xb3, 0x55, - 0x6c, 0xc9, 0x69, 0xfb, 0xb1, 0x3d, 0x06, 0x50, 0x97, 0x65, 0xa5, 0x2b, 0x3f, 0xac, - 0x54, 0xb9, 0x3f, 0x42, 0x1b, 0xf0, 0x8e, 0x18, 0xd5, 0x2d, 0xdd, 0x52, 0xcc, 0x1c, - 0x8c, 0xa8, 0xad, 0xfa, 0xcc, 0xab, 0x7e, 0x5c, 0xc2, 0xf4, 0x57, 0x3f, 0xbb, 0xf8, - 0x23, 0x9b, 0xb0, 0xb8, 0xae, 0xdb, 0xf8, 0xda, 0xd1, 0x62, 0x82, 0xda, 0x5c, 0x91, - 0x25, 0xdb, 0xa1, 0xc0, 0x59, 0xd0, 0xdf, 0x8a, 0xbf, 0x62, 0x10, 0x78, 0xf0, 0x2d, - 0x6c, 0x4b, 0xc8, 0x6d, 0x40, 0x84, 0x5a, 0xc1, 0xd5, 0x97, 0x10, 0xc4, 0x5f, 0x07, - 0xd5, 0x85, 0xeb, 0x48, 0xb3, 0x2f, 0xc0, 0x16, 0x7b, 0xa2, 0x56, 0xe7, 0x3c, 0xa3, - 0xb9, 0x31, 0x1c, 0x62, 0xd1, 0x09, 0x49, 0x79, 0x57, 0xd8, 0xdb, 0xe1, 0x0a, 0xa3, - 0xe8, 0x66, 0xb4, 0x0c, 0x0b, 0xaa, 0x2b, 0xc4, 0x92, 0xc1, 0x9a, 0xd1, 0xe6, 0x37, - 0x2d, 0x96, 0x22, 0xbf, 0x16, 0x3f, 0xbf, 0xfe, 0xae, 0xee, 0x79, 0x6a, 0x3c, 0xd9, - 0xb6, 0xfb, 0xbf, 0xa4, 0xd7, 0x92, 0xf3, 0x4d, 0x7f, 0xd6, 0xe7, 0x63, 0xcd, 0x58, - 0x59, 0xdd, 0x26, 0x83, 0x3d, 0x21, 0xd9, 0xbc, 0x54, 0x52, 0xbd, 0x19, 0x51, 0x5d, - 0xff, 0x9f, 0x49, 0x95, 0xb3, 0x5b, 0xc0, 0xc1, 0xf8, 0x76, 0xe6, 0xad, 0x11, 0xf2, - 0x45, 0x2d, 0xc9, 0xae, 0x85, 0xae, 0xc0, 0x1f, 0xc5, 0x6f, 0x8c, 0xbf, 0xda, 0x75, - 0xa7, 0x72, 0x7b, 0x75, 0xeb, 0xbd, 0x6b, 0xbf, 0xfb, 0x43, 0xb6, 0x3a, 0x3b, 0x1b, - 0x67, 0x1e, 0x40, 0xfe, 0xb0, 0xdb, 0x00, 0x29, 0x74, 0xa3, 0xc3, 0xb1, 0xa7, 0x88, - 0x56, 0x72, 0x31, 0xbf, 0x63, 0x99, 0xff, 0x89, 0x23, 0x69, 0x81, 0x14, 0x9d, 0x42, - 0x38, 0x02, 0xd2, 0x34, 0x1a, 0x3b, 0xed, 0xb9, 0xdd, 0xcb, 0xac, 0x1f, 0xe7, 0xb6, - 0x43, 0x5e, 0x14, 0x79, 0xc7, 0x2e, 0x70, 0x89, 0xd0, 0x29, 0xe7, 0xfb, 0xba, 0xf3, - 0xcf, 0x37, 0xe9, 0xb9, 0xa6, 0xb7, 0x76, 0x79, 0x1e, 0x4c, 0x5e, 0x6f, 0xda, 0x57, - 0xe8, 0xd5, 0xf1, 0x4c, 0x8c, 0x35, 0xa2, 0xd2, 0x70, 0x84, 0x6b, 0x9d, 0xbe, 0x00, - 0x5c, 0xda, 0x16, 0xaf, 0x44, 0x08, 0xf3, 0xab, 0x06, 0xa9, 0x16, 0xee, 0xeb, 0x9c, - 0x95, 0x94, 0xb7, 0x04, 0x24, 0xa4, 0xc1, 0xd1, 0x71, 0x29, 0x5b, 0x67, 0x63, 0xb2, - 0x2f, 0x47, 0xf8, 0x0b, 0x53, 0xcc, 0xbb, 0x90, 0x4b, 0xd6, 0x8f, 0xd6, 0x5f, 0xbd, - 0x3f, 0xbd, 0xea, 0x10, 0x35, 0xe9, 0x8c, 0x21, 0xa7, 0xdb, 0xc9, 0x1a, 0x9b, 0x5b, - 0xc7, 0x69, 0x0f, 0x05, 0xec, 0x31, 0x7c, 0x97, 0xf8, 0x76, 0x4e, 0xb4, 0x8e, 0x91, - 0x1d, 0x42, 0x8e, 0xc8, 0xd8, 0x61, 0xb7, 0x08, 0xe8, 0x29, 0x8a, 0xcb, 0x62, 0x15, - 0x51, 0x45, 0x15, 0x5a, 0xe9, 0x5f, 0x0a, 0x1d, 0x15, 0x01, 0x03, 0x47, 0x53, 0x14, - 0x6e, 0x22, 0xd0, 0x5f, 0x58, 0x6d, 0x7f, 0x6b, 0x4f, 0xe1, 0x2d, 0xad, 0x9a, 0x17, - 0xf5, 0xdb, 0x70, 0xb1, 0xdb, 0x96, 0xb8, 0xd9, 0xa8, 0x3e, 0xda, 0xdc, 0x96, 0x6c, - 0x8a, 0x54, 0x66, 0xb6, 0x1f, 0xc9, 0x98, 0xc3, 0x1f, 0x10, 0x70, 0xd9, 0xa5, 0xc9, - 0xa6, 0xd2, 0x68, 0xd3, 0x04, 0xfe, 0x6b, 0x8f, 0xd3, 0xb4, 0x01, 0x03, 0x48, 0x61, - 0x1a, 0xbd, 0xcb, 0xd4, 0x9f, 0xe4, 0xf8, 0x5b, 0x62, 0x3c, 0x78, 0x28, 0xc7, 0x13, - 0x82, 0xe1, 0x03, 0x4e, 0xa6, 0x7b, 0xc8, 0xae, 0x97, 0x40, 0x4b, 0x0c, 0x50, 0xb2, - 0xa0, 0x4f, 0x55, 0x9e, 0x49, 0x95, 0x0a, 0xfc, 0xb0, 0xef, 0x46, 0x2a, 0x2a, 0xe0, - 0x24, 0xb0, 0xf0, 0x22, 0x4d, 0xfd, 0x73, 0x68, 0x4b, 0x88, 0xc7, 0xfb, 0xe9, 0x2d, - 0x02, 0xb6, 0x8f, 0x75, 0x9c, 0x47, 0x52, 0x66, 0x3c, 0xd7, 0xb9, 0x7a, 0x14, 0x94, - 0x36, 0x49, 0x30, 0x55, 0x21, 0x32, 0x6b, 0xde, 0x08, 0x56, 0x30, 0x86, 0x46, 0x29, - 0x29, 0x1b, 0xae, 0x25, 0xff, 0x88, 0x22, 0xa1, 0x4c, 0x4b, 0x66, 0x6a, 0x92, 0x59, - 0xad, 0x0d, 0xc4, 0x2a, 0x82, 0x90, 0xac, 0x7b, 0xc7, 0xf5, 0x3a, 0x16, 0xf3, 0x79, - 0xf7, 0x58, 0xe5, 0xde, 0x75, 0x0f, 0x04, 0xfd, 0x7c, 0xad, 0x47, 0x70, 0x1c, 0x85, - 0x97, 0xf9, 0x78, 0x88, 0xbe, 0xa6, 0xfa, 0x0b, 0xf2, 0x99, 0x99, 0x56, 0xfb, 0xfd, - 0x0e, 0xe6, 0x8e, 0xc3, 0x6e, 0x46, 0x88, 0x80, 0x9a, 0xe2, 0x31, 0xeb, 0x8b, 0xc4, - 0x36, 0x9f, 0x5f, 0xe1, 0x57, 0x3f, 0x57, 0xe0, 0x99, 0xd9, 0xc0, 0x99, 0x01, 0xbf, - 0x39, 0xca, 0xac, 0x48, 0xdc, 0x11, 0x95, 0x6a, 0x8a, 0xe9, 0x05, 0xea, 0xd8, 0x69, - 0x54, 0x54, 0x7c, 0x44, 0x8a, 0xe4, 0x3d, 0x31, 0x5e, 0x66, 0x9c, 0x42, 0x42, 0xda, - 0x56, 0x59, 0x38, 0xf4, 0x17, 0xbf, 0x43, 0xce, 0x7b, 0x2b, 0x30, 0xb1, 0xcd, 0x40, - 0x18, 0x38, 0x8e, 0x1a, 0x91, 0x0f, 0x0f, 0xc4, 0x1f, 0xb0, 0x87, 0x7a, 0x59, 0x25, - 0xe4, 0x66, 0x81, 0x9d, 0x37, 0x5b, 0x0a, 0x91, 0x2d, 0x4f, 0xe8, 0x43, 0xb7, 0x6e, - 0xf6, 0xf2, 0x23, 0xf0, 0xf7, 0xc8, 0x94, 0xf3, 0x8f, 0x7a, 0xb7, 0x80, 0xdf, 0xd7, - 0x5f, 0x66, 0x9c, 0x8c, 0x06, 0xcf, 0xfa, 0x43, 0xeb, 0x47, 0x56, 0x5a, 0x50, 0xe3, - 0xb1, 0xfa, 0x45, 0xad, 0x61, 0xce, 0x9a, 0x1c, 0x47, 0x27, 0xb7, 0xaa, 0xa5, 0x35, - 0x62, 0xf5, 0x23, 0xe7, 0x39, 0x52, - ], - script_code: vec![0x53], - transparent_input: Some(1), - hash_type: 3, - amount: 365293780364847, - consensus_branch_id: 1537743641, - sighash: [ - 0x23, 0x65, 0x2e, 0x76, 0xcb, 0x13, 0xb8, 0x5a, 0x0e, 0x33, 0x63, 0xbb, 0x5f, 0xca, - 0x06, 0x1f, 0xa7, 0x91, 0xc4, 0x0c, 0x53, 0x3e, 0xcc, 0xee, 0x89, 0x93, 0x64, 0xe6, - 0xe6, 0x0b, 0xb4, 0xf7, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x99, 0xa6, 0x9f, 0xdf, 0x1c, - 0x5a, 0xc7, 0x73, 0x21, 0x46, 0xee, 0x5e, 0x1d, 0x6b, 0x6c, 0xa9, 0xb9, 0x18, 0x0f, - 0x96, 0x4c, 0xc9, 0xd0, 0x87, 0x8a, 0xe1, 0x37, 0x35, 0x24, 0xd7, 0xd5, 0x10, 0xe5, - 0x82, 0x27, 0xdf, 0x09, 0x51, 0x53, 0x63, 0x6a, 0x00, 0x6a, 0xac, 0x51, 0x6a, 0xb0, - 0xf1, 0x85, 0x6e, 0x28, 0xd5, 0xc8, 0xaf, 0xb0, 0x95, 0xef, 0x61, 0x84, 0xfe, 0xd6, - 0x51, 0x58, 0x90, 0x22, 0xee, 0xae, 0xa4, 0xc0, 0xce, 0x1f, 0xa6, 0xf0, 0x85, 0x09, - 0x2b, 0x04, 0x97, 0x94, 0x89, 0x17, 0x2b, 0x3e, 0xf8, 0x19, 0x4a, 0x01, 0x63, 0xf5, - 0x72, 0x4d, 0x6b, 0x02, 0xde, 0xe1, 0x36, 0xf3, 0xa9, 0xaa, 0x02, 0x00, 0x03, 0x52, - 0x52, 0xac, 0x17, 0xb7, 0x3f, 0x8d, 0x38, 0x3e, 0x00, 0x00, 0x06, 0xac, 0x63, 0x00, - 0x53, 0xac, 0x51, 0x04, 0xb4, 0x75, 0x56, 0xaf, 0x73, 0xb6, 0x08, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xe2, 0x32, 0x1d, 0x14, 0x60, 0x71, 0x78, 0x9d, 0x23, 0x35, 0x93, 0x4a, 0x68, 0x06, - 0x14, 0xe8, 0x35, 0x62, 0xf8, 0x2d, 0xfd, 0x40, 0x5b, 0x54, 0xa4, 0x5e, 0xb3, 0x2c, - 0x16, 0x54, 0x48, 0xd4, 0xd5, 0xd6, 0x1c, 0xa2, 0x85, 0x95, 0x85, 0x36, 0x9f, 0x53, - 0xf1, 0xa1, 0x37, 0xe9, 0xe8, 0x2b, 0x67, 0xb8, 0xfd, 0xaf, 0x01, 0xbd, 0xa5, 0x4a, - 0x31, 0x73, 0x11, 0x89, 0x6a, 0xe1, 0x02, 0x80, 0xa0, 0x32, 0x44, 0x0c, 0x42, 0x0a, - 0x42, 0x1e, 0x94, 0x4d, 0x1e, 0x95, 0x2b, 0x70, 0xd5, 0x82, 0x6c, 0xd3, 0xb0, 0x8b, - 0x7d, 0xb9, 0x63, 0x0f, 0xe4, 0xfd, 0x5f, 0x22, 0x12, 0x5d, 0xe8, 0x40, 0xfc, 0xc4, - 0x0b, 0x98, 0x03, 0x8a, 0xf1, 0x1d, 0x55, 0xbe, 0x25, 0x43, 0x25, 0x97, 0xb4, 0xb6, - 0x5b, 0x9e, 0xc1, 0xc7, 0xa8, 0xbb, 0xfd, 0x05, 0x2c, 0xbf, 0x7e, 0x1c, 0x17, 0x85, - 0x31, 0x49, 0x34, 0xb2, 0x62, 0xd5, 0x85, 0x37, 0x54, 0xf1, 0xf1, 0x77, 0x71, 0xcf, - 0xb7, 0x50, 0x30, 0x72, 0x65, 0x57, 0x53, 0xfa, 0x3f, 0x54, 0xec, 0xc5, 0x87, 0xe9, - 0xf8, 0x3b, 0x58, 0x19, 0x16, 0x09, 0x2d, 0xf2, 0x6e, 0x63, 0xe1, 0x89, 0x94, 0xcb, - 0x0d, 0xb9, 0x1a, 0x0b, 0xbd, 0xc7, 0xb6, 0x11, 0x9b, 0x32, 0x22, 0x2a, 0xdf, 0x5e, - 0x61, 0xd8, 0xd8, 0xae, 0x89, 0xda, 0xe4, 0x95, 0x4b, 0x54, 0x81, 0x3b, 0xb3, 0x3f, - 0x08, 0xd5, 0x62, 0xba, 0x51, 0x3f, 0xee, 0x1b, 0x09, 0xc0, 0xfc, 0xd5, 0x16, 0x05, - 0x54, 0x19, 0x47, 0x4d, 0xd7, 0xfd, 0xa0, 0x38, 0xa8, 0x9c, 0x84, 0xea, 0x7b, 0x94, - 0x68, 0x28, 0x7f, 0x0e, 0xb0, 0xc1, 0x0c, 0x4b, 0x13, 0x25, 0x20, 0x19, 0x4d, 0x3d, - 0x8d, 0x53, 0x51, 0xfc, 0x10, 0xd0, 0x9c, 0x15, 0xc8, 0xcc, 0x10, 0x1a, 0xa1, 0x66, - 0x3b, 0xbf, 0x17, 0xb8, 0x41, 0x11, 0xf3, 0x8b, 0xb4, 0x39, 0xf0, 0x73, 0x53, 0xbd, - 0xea, 0x35, 0x96, 0xd1, 0x5e, 0x71, 0x3e, 0x1e, 0x2e, 0x7d, 0x3f, 0x1c, 0x38, 0x31, - 0x35, 0xb4, 0x7f, 0xa7, 0xf8, 0x1f, 0x46, 0xdf, 0x02, 0x90, 0x2a, 0x40, 0x46, 0x99, - 0xec, 0x91, 0x2f, 0x56, 0x56, 0xc3, 0x5b, 0x85, 0x76, 0x3e, 0x4d, 0xe5, 0x83, 0xae, - 0xca, 0xa1, 0xdf, 0xd5, 0xd2, 0x67, 0x7d, 0x9c, 0x8f, 0xfe, 0xe8, 0x77, 0xf6, 0x03, - 0x40, 0xa5, 0xca, 0x0d, 0x67, 0xf6, 0xe5, 0x54, 0x12, 0x47, 0x39, 0xf8, 0x05, 0xaf, - 0x87, 0x6a, 0xee, 0xde, 0x53, 0xaa, 0x8b, 0x0f, 0x8e, 0x56, 0x04, 0xa7, 0x3c, 0x30, - 0xcb, 0xd0, 0x9d, 0xad, 0x0a, 0x3d, 0x6f, 0x8a, 0x5d, 0xcc, 0x40, 0xde, 0xf4, 0x07, - 0x97, 0x34, 0x21, 0x13, 0xba, 0x20, 0x6f, 0xae, 0x8e, 0xbe, 0x4f, 0x3b, 0xc3, 0xca, - 0xf6, 0x92, 0x59, 0xe4, 0x62, 0xef, 0xf9, 0xba, 0x8b, 0x3f, 0x4b, 0xfa, 0xa1, 0x30, - 0x0c, 0x26, 0x92, 0x5a, 0x87, 0x29, 0xcd, 0x32, 0x91, 0x5b, 0xfc, 0x96, 0x60, 0x86, - 0xf0, 0xd5, 0x56, 0x0b, 0xbe, 0x32, 0xa5, 0x98, 0xc2, 0x2a, 0xdf, 0xb4, 0x8c, 0x03, - 0x72, 0xba, 0x5d, 0x42, 0x87, 0xc0, 0xce, 0xfb, 0xac, 0xfd, 0x8c, 0xe1, 0x95, 0xb4, - 0x96, 0x3c, 0x34, 0xa9, 0x4b, 0xba, 0x7a, 0x17, 0x5d, 0xae, 0x4b, 0xbe, 0x3e, 0xf4, - 0x86, 0x3d, 0x53, 0x70, 0x03, 0x15, 0x09, 0x0f, 0x47, 0xa0, 0x68, 0xe2, 0x27, 0x43, - 0x3f, 0x9e, 0x49, 0xd3, 0xaa, 0x09, 0xe3, 0x56, 0xd8, 0xd6, 0x6d, 0x0c, 0x01, 0x21, - 0xe9, 0x1a, 0x3c, 0x4a, 0xa3, 0xf2, 0x7f, 0xa1, 0xb6, 0x03, 0x96, 0xe2, 0xb4, 0x1d, - 0xb9, 0x08, 0xfd, 0xab, 0x8b, 0x18, 0xcc, 0x73, 0x04, 0xe9, 0x4e, 0x97, 0x05, 0x68, - 0xf9, 0x42, 0x1c, 0x0d, 0xbb, 0xba, 0xf8, 0x45, 0x98, 0xd9, 0x72, 0xb0, 0x53, 0x4f, - 0x02, 0xa5, 0xe5, 0x26, 0x70, 0x43, 0x6a, 0xaa, 0x77, 0x6e, 0xd2, 0x48, 0x2a, 0xd7, - 0x03, 0x43, 0x02, 0x01, 0xe5, 0x34, 0x43, 0xc3, 0x6d, 0xcf, 0xd3, 0x4a, 0x0c, 0xb6, - 0x63, 0x78, 0x76, 0x10, 0x5e, 0x03, 0xbf, 0x3b, 0xd5, 0x8e, 0xc1, 0x48, 0xcb, 0x64, - 0x97, 0x0e, 0x32, 0x23, 0xa9, 0x1f, 0x71, 0xdf, 0xcf, 0xd5, 0xa0, 0x4b, 0x66, 0x7f, - 0xba, 0xf3, 0xd4, 0xb3, 0xb9, 0x08, 0xb9, 0x82, 0x88, 0x20, 0xdf, 0xec, 0xdd, 0x75, - 0x37, 0x50, 0xb5, 0xf9, 0xd2, 0x21, 0x6e, 0x56, 0xc6, 0x15, 0x27, 0x2f, 0x85, 0x44, - 0x64, 0xc0, 0xca, 0x4b, 0x1e, 0x85, 0xae, 0xdd, 0x03, 0x82, 0x92, 0xc4, 0xe1, 0xa5, - 0x77, 0x44, 0xeb, 0xba, 0x01, 0x0b, 0x9e, 0xbf, 0xbb, 0x01, 0x1b, 0xd6, 0xf0, 0xb7, - 0x88, 0x05, 0x02, 0x5d, 0x27, 0xf3, 0xc1, 0x77, 0x46, 0xba, 0xe1, 0x16, 0xc1, 0x5d, - 0x9f, 0x47, 0x1f, 0x0f, 0x62, 0x88, 0xa1, 0x50, 0x64, 0x7b, 0x2a, 0xfe, 0x9d, 0xf7, - 0xcc, 0xcf, 0x01, 0xf5, 0xcd, 0xe5, 0xf0, 0x46, 0x80, 0xbb, 0xfe, 0xd8, 0x7f, 0x6c, - 0xf4, 0x29, 0xfb, 0x27, 0xad, 0x6b, 0xab, 0xe7, 0x91, 0x76, 0x66, 0x11, 0xcf, 0x5b, - 0xc2, 0x0e, 0x48, 0xbe, 0xf1, 0x19, 0x25, 0x9b, 0x9b, 0x8a, 0x0e, 0x39, 0xc3, 0xdf, - 0x28, 0xcb, 0x95, 0x82, 0xea, 0x33, 0x86, 0x01, 0xcd, 0xc4, 0x81, 0xb3, 0x2f, 0xb8, - 0x2a, 0xde, 0xeb, 0xb3, 0xda, 0xde, 0x25, 0xd1, 0xa3, 0xdf, 0x20, 0xc3, 0x7e, 0x71, - 0x25, 0x06, 0xb5, 0xd9, 0x96, 0xc4, 0x9a, 0x9f, 0x0f, 0x30, 0xdd, 0xcb, 0x91, 0xfe, - 0x90, 0x04, 0xe1, 0xe8, 0x32, 0x94, 0xa6, 0xc9, 0x20, 0x3d, 0x94, 0xe8, 0xdc, 0x2c, - 0xbb, 0x44, 0x9d, 0xe4, 0x15, 0x50, 0x32, 0x60, 0x4e, 0x47, 0x99, 0x70, 0x16, 0xb3, - 0x04, 0xfd, 0x43, 0x7d, 0x82, 0x35, 0x04, 0x5e, 0x25, 0x5a, 0x19, 0xb7, 0x43, 0xa0, - 0xa9, 0xf2, 0xe3, 0x36, 0xb4, 0x4c, 0xae, 0x30, 0x7b, 0xb3, 0x98, 0x7b, 0xd3, 0xe4, - 0xe7, 0x77, 0xfb, 0xb3, 0x4c, 0x0a, 0xb8, 0xcc, 0x3d, 0x67, 0x46, 0x6c, 0x0a, 0x88, - 0xdd, 0x4c, 0xca, 0xd1, 0x8a, 0x07, 0xa8, 0xd1, 0x06, 0x8d, 0xf5, 0xb6, 0x29, 0xe5, - 0x71, 0x8d, 0x0f, 0x6d, 0xf5, 0xc9, 0x57, 0xcf, 0x71, 0xbb, 0x00, 0xa5, 0x17, 0x8f, - 0x17, 0x5c, 0xac, 0xa9, 0x44, 0xe6, 0x35, 0xc5, 0x15, 0x9f, 0x73, 0x8e, 0x24, 0x02, - 0xa2, 0xd2, 0x1a, 0xa0, 0x81, 0xe1, 0x0e, 0x45, 0x6a, 0xfb, 0x00, 0xb9, 0xf6, 0x24, - 0x16, 0xc8, 0xb9, 0xc0, 0xf7, 0x22, 0x8f, 0x51, 0x07, 0x29, 0xe0, 0xbe, 0x3f, 0x30, - 0x53, 0x13, 0xd7, 0x7f, 0x73, 0x79, 0xdc, 0x2a, 0xf2, 0x48, 0x69, 0xc6, 0xc7, 0x4e, - 0xe4, 0x47, 0x14, 0x98, 0x86, 0x1d, 0x19, 0x2f, 0x0f, 0xf0, 0xf5, 0x08, 0x28, 0x5d, - 0xab, 0x6b, 0x6a, 0x36, 0xcc, 0xf7, 0xd1, 0x22, 0x56, 0xcc, 0x76, 0xb9, 0x55, 0x03, - 0x72, 0x0a, 0xc6, 0x72, 0xd0, 0x82, 0x68, 0xd2, 0xcf, 0x77, 0x73, 0xb6, 0xba, 0x2a, - 0x5f, 0x66, 0x48, 0x47, 0xbf, 0x70, 0x7f, 0x2f, 0xc1, 0x0c, 0x98, 0xf2, 0xf0, 0x06, - 0xec, 0x22, 0xcc, 0xb5, 0xa8, 0xc8, 0xb7, 0xc4, 0x0c, 0x7c, 0x2d, 0x49, 0xa6, 0x63, - 0x9b, 0x9f, 0x2c, 0xe3, 0x3c, 0x25, 0xc0, 0x4b, 0xc4, 0x61, 0xe7, 0x44, 0xdf, 0xa5, - 0x36, 0xb0, 0x0d, 0x94, 0xba, 0xdd, 0xf4, 0xf4, 0xd1, 0x40, 0x44, 0xc6, 0x95, 0xa3, - 0x38, 0x81, 0x47, 0x7d, 0xf1, 0x24, 0xf0, 0xfc, 0xf2, 0x06, 0xa9, 0xfb, 0x2e, 0x65, - 0xe3, 0x04, 0xcd, 0xbf, 0x0c, 0x4d, 0x23, 0x90, 0x17, 0x0c, 0x13, 0x0a, 0xb8, 0x49, - 0xc2, 0xf2, 0x2b, 0x5c, 0xdd, 0x39, 0x21, 0x64, 0x0c, 0x8c, 0xf1, 0x97, 0x6a, 0xe1, - 0x01, 0x0b, 0x0d, 0xfd, 0x9c, 0xb2, 0x54, 0x3e, 0x45, 0xf9, 0x97, 0x49, 0xcc, 0x4d, - 0x61, 0xf2, 0xe8, 0xaa, 0xbf, 0xe9, 0x8b, 0xd9, 0x05, 0xfa, 0x39, 0x95, 0x1b, 0x33, - 0xea, 0x76, 0x9c, 0x45, 0xab, 0x95, 0x31, 0xc5, 0x72, 0x09, 0x86, 0x2a, 0xd1, 0x2f, - 0xd7, 0x6b, 0xa4, 0x80, 0x7e, 0x65, 0x41, 0x7b, 0x6c, 0xd1, 0x2f, 0xa8, 0xec, 0x91, - 0x6f, 0x01, 0x3e, 0xbb, 0x87, 0x06, 0xa9, 0x6e, 0xff, 0xed, 0xa0, 0x6c, 0x4b, 0xe2, - 0x4b, 0x04, 0x84, 0x63, 0x92, 0xe9, 0xd1, 0xe6, 0x93, 0x0e, 0xae, 0x01, 0xfa, 0x21, - 0xfb, 0xd7, 0x00, 0x58, 0x3f, 0xb5, 0x98, 0xb9, 0x2c, 0x8f, 0x4e, 0xb8, 0xa6, 0x1a, - 0xa6, 0x23, 0x5d, 0xb6, 0x0f, 0x28, 0x41, 0xcf, 0x3a, 0x1c, 0x6a, 0xb5, 0x4c, 0x67, - 0x06, 0x68, 0x44, 0x71, 0x1d, 0x09, 0x1e, 0xb9, 0x31, 0xa1, 0xbd, 0x62, 0x81, 0xae, - 0xdf, 0x2a, 0x0e, 0x8f, 0xab, 0x18, 0x81, 0x72, 0x02, 0xa9, 0xbe, 0x06, 0x40, 0x2e, - 0xd9, 0xcc, 0x72, 0x0c, 0x16, 0xbf, 0xe8, 0x81, 0xe4, 0xdf, 0x42, 0x55, 0xe8, 0x7a, - 0xfb, 0x7f, 0xc6, 0x2f, 0x38, 0x11, 0x6b, 0xbe, 0x03, 0xcd, 0x8a, 0x3c, 0xb1, 0x1a, - 0x27, 0xd5, 0x68, 0x41, 0x47, 0x82, 0xf4, 0x7b, 0x1a, 0x44, 0xc9, 0x7c, 0x68, 0x04, - 0x67, 0x69, 0x4b, 0xc9, 0x70, 0x9d, 0x32, 0x91, 0x6c, 0x97, 0xe8, 0x00, 0x6c, 0xbb, - 0x07, 0xba, 0x0e, 0x41, 0x80, 0xa3, 0x73, 0x80, 0x38, 0xc3, 0x74, 0xc4, 0xcc, 0xe8, - 0xf3, 0x29, 0x59, 0xaf, 0xb2, 0x5f, 0x30, 0x3f, 0x58, 0x15, 0xc4, 0x53, 0x31, 0x24, - 0xac, 0xf9, 0xd1, 0x89, 0x40, 0xe7, 0x75, 0x22, 0xac, 0x5d, 0xc4, 0xb9, 0x57, 0x0a, - 0xae, 0x8f, 0x47, 0xb7, 0xf5, 0x7f, 0xd8, 0x76, 0x7b, 0xea, 0x1a, 0x24, 0xae, 0x7b, - 0xed, 0x65, 0xb4, 0xaf, 0xdc, 0x8f, 0x12, 0x78, 0xc3, 0x0e, 0x2d, 0xb9, 0x8f, 0xd1, - 0x72, 0x73, 0x0a, 0xc6, 0xbb, 0xed, 0x4f, 0x11, 0x27, 0xcd, 0x32, 0xb0, 0x4a, 0x95, - 0xb2, 0x05, 0x52, 0x6c, 0xfc, 0xb4, 0xc4, 0xe1, 0xcc, 0x95, 0x51, 0x75, 0xb3, 0xe8, - 0xde, 0x1f, 0x5d, 0x81, 0xb1, 0x86, 0x69, 0x69, 0x23, 0x50, 0xaa, 0xa1, 0xa1, 0xd7, - 0x97, 0x61, 0x75, 0x82, 0xe5, 0x4d, 0x7a, 0x5b, 0x57, 0xa6, 0x83, 0xb3, 0x2f, 0xb1, - 0x09, 0x80, 0x62, 0xda, 0xd7, 0xb0, 0xc2, 0xeb, 0x51, 0x8f, 0x68, 0x62, 0xe8, 0x3d, - 0xb2, 0x5e, 0x3d, 0xba, 0xf7, 0xae, 0xd5, 0x04, 0xde, 0x93, 0x2a, 0xcb, 0x99, 0xd7, - 0x35, 0x99, 0x2c, 0xe6, 0x2b, 0xae, 0x9e, 0xf8, 0x93, 0xff, 0x6a, 0xcc, 0x0f, 0xfc, - 0xf8, 0xe3, 0x48, 0x3e, 0x14, 0x6b, 0x9d, 0x49, 0xdd, 0x8c, 0x78, 0x35, 0xf4, 0x3a, - 0x37, 0xdc, 0xa0, 0x78, 0x7e, 0x3e, 0xc9, 0xf6, 0x60, 0x52, 0x23, 0xd5, 0xba, 0x7a, - 0xe0, 0xab, 0x90, 0x25, 0xb7, 0x3b, 0xc0, 0x3f, 0x7f, 0xac, 0x36, 0xc0, 0x09, 0xa5, - 0x6d, 0x4d, 0x95, 0xd1, 0xe8, 0x1d, 0x3b, 0x3e, 0xbc, 0xa7, 0xe5, 0x4c, 0xc1, 0xa1, - 0x2d, 0x12, 0x7b, 0x57, 0xc8, 0x13, 0x89, 0x76, 0xe7, 0x91, 0x01, 0x3b, 0x01, 0x5f, - 0x06, 0xa6, 0x24, 0xf5, 0x21, 0xb6, 0xee, 0x04, 0xec, 0x98, 0x08, 0x93, 0xc7, 0xe5, - 0xe0, 0x1a, 0x33, 0x62, 0x03, 0x59, 0x40, 0x94, 0xf8, 0x28, 0x33, 0xd7, 0x44, 0x5f, - 0xe2, 0xd0, 0x91, 0x30, 0xf6, 0x35, 0x11, 0xda, 0x54, 0x83, 0x2d, 0xe9, 0x13, 0x6b, - 0x39, 0xf4, 0x59, 0x9f, 0x5a, 0xa5, 0xdf, 0xbb, 0x45, 0xda, 0x60, 0xcd, 0xce, 0xab, - 0x7e, 0xef, 0xde, 0x89, 0xbe, 0x63, 0xf3, 0xf7, 0xc0, 0xd2, 0x32, 0x48, 0x47, 0xcc, - 0xe1, 0x40, 0x5d, 0xef, 0x7c, 0x46, 0x9b, 0x0e, 0x27, 0x24, 0x94, 0xe5, 0xdf, 0x54, - 0xf5, 0x68, 0x65, 0x6c, 0xb9, 0xc8, 0x81, 0x8d, 0x92, 0xb7, 0x2b, 0x8b, 0xc3, 0x4d, - 0xb7, 0xbb, 0x31, 0x12, 0x48, 0x7e, 0x74, 0x6e, 0xef, 0xe4, 0xe8, 0x08, 0xbb, 0xb2, - 0x87, 0xd9, 0x9b, 0xf0, 0x7d, 0x00, 0xda, 0xbe, 0xde, 0xdc, 0x5e, 0x5f, 0x07, 0x4f, - 0xfe, 0xae, 0x0c, 0xba, 0x7d, 0xa3, 0xa5, 0x16, 0xc1, 0x73, 0xbe, 0x1c, 0x51, 0x33, - 0x23, 0xe1, 0x19, 0xf6, 0x35, 0xe8, 0x20, 0x9a, 0x07, 0x4b, 0x21, 0x6b, 0x70, 0x23, - 0xfa, 0xdc, 0x2d, 0x25, 0x94, 0x9c, 0x90, 0x03, 0x7e, 0x71, 0xe3, 0xe5, 0x50, 0x72, - 0x6d, 0x21, 0x0a, 0x2c, 0x68, 0x83, 0x42, 0xe5, 0x24, 0x40, 0x63, 0x5e, 0x9c, 0xc1, - 0x4a, 0xfe, 0x10, 0x10, 0x26, 0x21, 0xa9, 0xc9, 0xac, 0xcb, 0x78, 0x2e, 0x9e, 0x4a, - 0x5f, 0xa8, 0x7f, 0x0a, 0x95, 0x6f, 0x5b, 0x85, 0x50, 0x99, 0x60, 0x28, 0x5c, 0x22, - 0x62, 0x7c, 0x59, 0x48, 0x3a, 0x5a, 0x4c, 0x28, 0xcc, 0xe4, 0xb1, 0x56, 0xe5, 0x51, - 0x40, 0x6a, 0x7e, 0xe8, 0x35, 0x56, 0x56, 0xa2, 0x1e, 0x43, 0xe3, 0x8c, 0xe1, 0x29, - 0xfd, 0xad, 0xb7, 0x59, 0xed, 0xdf, 0xa0, 0x8f, 0x00, 0xfc, 0x8e, 0x56, 0x7c, 0xef, - 0x93, 0xc6, 0x79, 0x2d, 0x01, 0xdf, 0x05, 0xe6, 0xd5, 0x80, 0xf4, 0xd5, 0xd4, 0x8d, - 0xf0, 0x42, 0x45, 0x1a, 0x33, 0x59, 0x0d, 0x3e, 0x8c, 0xf4, 0x9b, 0x26, 0x27, 0x21, - 0x8f, 0x0c, 0x29, 0x2f, 0xa6, 0x6a, 0xda, 0x94, 0x5f, 0xa5, 0x5b, 0xb2, 0x35, 0x48, - 0xe3, 0x3a, 0x83, 0xa5, 0x62, 0x95, 0x7a, 0x31, 0x49, 0xa9, 0x93, 0xcc, 0x47, 0x23, - 0x62, 0x29, 0x87, 0x36, 0xa8, 0xb7, 0x78, 0xd9, 0x7c, 0xe4, 0x23, 0x01, 0x3d, 0x64, - 0xb3, 0x2c, 0xd1, 0x72, 0xef, 0xa5, 0x51, 0xbf, 0x7f, 0x36, 0x8f, 0x04, 0xbd, 0xae, - 0xc6, 0x09, 0x1a, 0x30, 0x04, 0xa7, 0x57, 0x59, 0x8b, 0x80, 0x1d, 0xcf, 0x67, 0x5c, - 0xb8, 0x3e, 0x43, 0xa5, 0x3a, 0xe8, 0xb2, 0x54, 0xd3, 0x33, 0xbc, 0xda, 0x20, 0xd4, - 0x81, 0x7d, 0x34, 0x77, 0xab, 0xfb, 0xa2, 0x5b, 0xb8, 0x3d, 0xf5, 0x94, 0x9c, 0x12, - 0x6f, 0x14, 0x9b, 0x1d, 0x99, 0x34, 0x1e, 0x4e, 0x6f, 0x91, 0x20, 0xf4, 0xd4, 0x1e, - 0x62, 0x91, 0x85, 0x00, 0x2c, 0x72, 0xc0, 0x12, 0xc4, 0x14, 0xd2, 0x38, 0x2a, 0x6d, - 0x47, 0xc7, 0xb3, 0xde, 0xab, 0xa7, - ], - script_code: vec![0xac, 0x00], - transparent_input: Some(0), - hash_type: 3, - amount: 711752082734717, - consensus_branch_id: 1537743641, - sighash: [ - 0xb3, 0x8e, 0x31, 0x70, 0x8c, 0xb7, 0x8e, 0xee, 0xc7, 0x66, 0x3e, 0xca, 0x1e, 0x01, - 0xb7, 0x53, 0x9e, 0x26, 0xb7, 0x30, 0xcf, 0x44, 0x6d, 0x3b, 0xf5, 0x7a, 0x99, 0x8e, - 0x9e, 0xd9, 0x2b, 0x47, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x00, 0x02, 0x0d, 0x38, 0x6a, 0xe3, - 0x0d, 0xd3, 0x01, 0x00, 0x07, 0x00, 0x65, 0x51, 0x65, 0x53, 0x53, 0x6a, 0xd5, 0x09, - 0x42, 0xf7, 0x69, 0x67, 0x02, 0x00, 0x05, 0xac, 0x65, 0x63, 0x65, 0xac, 0x61, 0xa7, - 0xb8, 0xb9, 0xf6, 0x99, 0xd6, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x49, 0x23, 0x2f, 0x32, - 0x9f, 0xef, 0x95, 0xc7, 0xaf, 0x37, 0x00, 0x98, 0xff, 0xe4, 0x91, 0x8e, 0x0c, 0xa1, - 0xdf, 0x47, 0xf2, 0x75, 0x86, 0x7b, 0x73, 0x9e, 0x0a, 0x51, 0x4d, 0x32, 0x09, 0x32, - 0x5e, 0x21, 0x70, 0x45, 0x92, 0x7b, 0x47, 0x9c, 0x1c, 0xe2, 0xe5, 0xd5, 0x4f, 0x25, - 0x48, 0x8c, 0xad, 0x15, 0x13, 0xe3, 0xf4, 0x4a, 0x21, 0x26, 0x6c, 0xfd, 0x84, 0x16, - 0x33, 0x32, 0x7d, 0xee, 0x6c, 0xf8, 0x10, 0xfb, 0xf7, 0x39, 0x3e, 0x31, 0x7d, 0x9e, - 0x53, 0xd1, 0xbe, 0x1d, 0x5a, 0xe7, 0x83, 0x9b, 0x66, 0xb9, 0x43, 0xb9, 0xed, 0x18, - 0xf2, 0xc5, 0x30, 0xe9, 0x75, 0x42, 0x23, 0x32, 0xc3, 0x43, 0x9c, 0xce, 0x49, 0xa2, - 0x9f, 0x2a, 0x33, 0x6a, 0x48, 0x51, 0x26, 0x3c, 0x5e, 0x9b, 0xd1, 0x3d, 0x73, 0x11, - 0x09, 0xe8, 0x44, 0xb7, 0xf8, 0xc3, 0x92, 0xa5, 0xc1, 0xdc, 0xaa, 0x2a, 0xe5, 0xf5, - 0x0f, 0xf6, 0x3f, 0xab, 0x97, 0x65, 0xe0, 0x16, 0x70, 0x2c, 0x35, 0xa6, 0x7c, 0xd7, - 0x36, 0x4d, 0x3f, 0xab, 0x55, 0x2f, 0xb3, 0x49, 0xe3, 0x5c, 0x15, 0xc5, 0x02, 0x50, - 0x45, 0x3f, 0xd1, 0x8f, 0x7b, 0x85, 0x59, 0x92, 0x63, 0x2e, 0x2c, 0x76, 0xc0, 0xfb, - 0xf1, 0xef, 0x96, 0x3e, 0xa8, 0x0e, 0x32, 0x23, 0xde, 0x32, 0x77, 0xbc, 0x55, 0x92, - 0x51, 0x72, 0x58, 0x29, 0xec, 0x03, 0xf2, 0x13, 0xba, 0x89, 0x55, 0xca, 0xb2, 0x82, - 0x2f, 0xf2, 0x1a, 0x9b, 0x0a, 0x49, 0x04, 0xd6, 0x68, 0xfc, 0xd7, 0x72, 0x24, 0xbd, - 0xe3, 0xdd, 0x01, 0xf6, 0xff, 0xc4, 0x82, 0x8f, 0x6b, 0x64, 0x23, 0x0b, 0x35, 0xc6, - 0xa0, 0x49, 0x87, 0x34, 0x94, 0x27, 0x6e, 0xa1, 0xd7, 0xed, 0x5e, 0x92, 0xcb, 0x4f, - 0x90, 0xba, 0x83, 0xa9, 0xe4, 0x96, 0x01, 0xb1, 0x94, 0x04, 0x2f, 0x29, 0x00, 0xd9, - 0x9d, 0x31, 0x2d, 0x7b, 0x70, 0x50, 0x8c, 0xf1, 0x76, 0x06, 0x6d, 0x15, 0x4d, 0xbe, - 0x96, 0xef, 0x9d, 0x43, 0x67, 0xe4, 0xc8, 0x40, 0xe4, 0xa1, 0x7b, 0x5e, 0x51, 0x22, - 0xe8, 0xeb, 0xe2, 0x03, 0x8a, 0x3c, 0x5f, 0x4c, 0xba, 0xe2, 0x1e, 0xa3, 0xfa, 0x1a, - 0xe6, 0xc2, 0x5a, 0x94, 0x62, 0xeb, 0xcb, 0xb0, 0xfd, 0x5f, 0x14, 0x55, 0x4b, 0xc9, - 0x77, 0x47, 0xc3, 0x3e, 0x34, 0xda, 0x90, 0xc8, 0x02, 0xd8, 0xd0, 0xd5, 0x0b, 0xfe, - 0x37, 0x61, 0x8c, 0x58, 0x12, 0x89, 0x14, 0x84, 0xfa, 0x25, 0x93, 0x22, 0xc1, 0x50, - 0x92, 0xd4, 0x15, 0x5d, 0x86, 0x96, 0xd6, 0xf1, 0x2f, 0x24, 0xfd, 0x36, 0x44, 0x0a, - 0xb3, 0xbe, 0x08, 0x71, 0xca, 0x3d, 0xd9, 0x62, 0x53, 0x48, 0xa6, 0x14, 0xb5, 0x9b, - 0xde, 0x45, 0x88, 0x56, 0x49, 0xba, 0xe3, 0x6d, 0xe3, 0x4d, 0xef, 0x8f, 0xce, 0xc8, - 0x53, 0x43, 0x47, 0x5d, 0x97, 0x6a, 0xe1, 0xe9, 0xb2, 0x78, 0x29, 0xce, 0x2a, 0xc5, - 0xef, 0xd0, 0xb3, 0x99, 0xa8, 0xb4, 0x48, 0xbe, 0x65, 0x04, 0x29, 0x4e, 0xe6, 0xb3, - 0xc1, 0xc6, 0xa5, 0x34, 0x2d, 0x7c, 0x01, 0xae, 0x03, 0x8a, 0xd3, 0x07, 0x0c, 0x2b, - 0x1a, 0x91, 0x57, 0x3a, 0xf5, 0xe0, 0xc5, 0xe4, 0xcb, 0xbf, 0x4a, 0xcd, 0xc6, 0xb5, - 0x4c, 0x92, 0x72, 0x20, 0x0d, 0x99, 0x70, 0x25, 0x0c, 0x17, 0xc1, 0x03, 0x6f, 0x02, - 0x08, 0x5c, 0x41, 0x85, 0x8e, 0xd3, 0xa0, 0xc4, 0x81, 0x50, 0xbc, 0x69, 0x7e, 0x4a, - 0x69, 0x5f, 0xef, 0x33, 0x5f, 0x7a, 0xd0, 0x7e, 0x1a, 0x46, 0xdc, 0x76, 0x7f, 0xf8, - 0x22, 0xdb, 0x70, 0xe6, 0x02, 0x90, 0x80, 0xb9, 0x81, 0x6b, 0x22, 0x32, 0xc8, 0x1a, - 0x4c, 0x66, 0xcc, 0x58, 0x6a, 0xbf, 0xe1, 0xea, 0xa8, 0xca, 0x6c, 0xf4, 0x1f, 0xc3, - 0xc3, 0xe6, 0xc7, 0xb8, 0x86, 0xfb, 0x6d, 0xac, 0x9f, 0x02, 0x22, 0xb4, 0xfc, 0x6f, - 0xff, 0x9d, 0x05, 0x13, 0xd6, 0x1a, 0x21, 0xc8, 0x0a, 0x37, 0x76, 0x71, 0xd1, 0x35, - 0xa6, 0x68, 0xa0, 0xae, 0x2b, 0xb9, 0x34, 0xc8, 0x2c, 0x41, 0x42, 0xda, 0x69, 0xd1, - 0x02, 0xa7, 0xde, 0x9a, 0x7d, 0xf7, 0x06, 0x40, 0x0e, 0xc7, 0x98, 0x78, 0xd8, 0x68, - 0xe1, 0x7e, 0x8f, 0x71, 0xea, 0x31, 0x49, 0x5a, 0xf8, 0x19, 0xa0, 0x16, 0xcc, 0x41, - 0x9e, 0x07, 0xc5, 0x01, 0xaa, 0x83, 0x09, 0xb2, 0xe6, 0xc8, 0x5b, 0x79, 0xb2, 0x76, - 0x37, 0x33, 0xa3, 0x7b, 0xbc, 0x04, 0x20, 0xd4, 0x25, 0x37, 0xb8, 0x71, 0xb4, 0x29, - 0x4a, 0x65, 0xd3, 0xe0, 0x55, 0xff, 0x71, 0x8d, 0xd9, 0xdc, 0x8c, 0x75, 0xe7, 0xe5, - 0xb2, 0xef, 0xe4, 0x42, 0x63, 0x73, 0x71, 0xb7, 0xc4, 0x8f, 0x6e, 0xe9, 0x9e, 0x3e, - 0xa3, 0x8a, 0x4b, 0x0f, 0x2f, 0x67, 0xfc, 0x2b, 0x90, 0x8c, 0xda, 0x65, 0x7e, 0xae, - 0x75, 0x4e, 0x03, 0x7e, 0x26, 0x2e, 0x9a, 0x9f, 0x9b, 0xd7, 0xec, 0x42, 0x67, 0xed, - 0x8e, 0x96, 0x93, 0x0e, 0x10, 0x84, 0x78, 0x3c, 0x37, 0xd6, 0xf9, 0xdd, 0x15, 0xfd, - 0x29, 0xf4, 0xcc, 0x47, 0x7e, 0x66, 0xf1, 0x30, 0xd6, 0x30, 0x43, 0x0d, 0xcc, 0x01, - 0x04, 0x89, 0x9b, 0x4f, 0x9f, 0x46, 0xeb, 0x09, 0x0e, 0xf7, 0xfc, 0x90, 0xb4, 0x79, - 0xab, 0xf6, 0x1f, 0x93, 0x95, 0x5e, 0xe0, 0x0e, 0x6a, 0x18, 0x48, 0xf1, 0xab, 0x14, - 0xad, 0x33, 0x4f, 0x2b, 0x68, 0x03, 0x58, 0x08, 0xcd, 0xf1, 0xbb, 0x9e, 0x9d, 0x9a, - 0x81, 0x6b, 0xaf, 0x72, 0x8a, 0x95, 0x5b, 0x96, 0x0b, 0x77, 0x01, 0xfa, 0x62, 0x66, - 0x87, 0xdc, 0x3c, 0x9c, 0xba, 0x64, 0x63, 0x37, 0xb5, 0x3e, 0x29, 0x81, 0x6e, 0x94, - 0x82, 0xdd, 0xf5, 0x57, 0x8a, 0x87, 0x68, 0xaa, 0xe4, 0x77, 0xfc, 0xe4, 0x10, 0xac, - 0x2d, 0x5d, 0xe6, 0x09, 0x58, 0x61, 0xc1, 0x11, 0xd7, 0xfe, 0xb3, 0xe6, 0xbb, 0x4f, - 0xbb, 0x5a, 0x54, 0x95, 0x54, 0x95, 0x97, 0x27, 0x98, 0x35, 0x0a, 0x25, 0x3f, 0x05, - 0xf6, 0x6c, 0x2e, 0xcf, 0xcb, 0xc0, 0xed, 0x43, 0xf5, 0xec, 0x2e, 0x6d, 0x8d, 0xba, - 0x15, 0xa5, 0x12, 0x54, 0xd9, 0x7b, 0x18, 0x21, 0x10, 0x7c, 0x07, 0xdd, 0x9a, 0x16, - 0xef, 0x84, 0x06, 0xf9, 0x43, 0xe2, 0x82, 0xb9, 0x5d, 0x4b, 0x36, 0x25, 0x30, 0xc9, - 0x13, 0xd6, 0xba, 0x42, 0x1d, 0xf6, 0x02, 0x7d, 0xe5, 0xaf, 0x1e, 0x47, 0x45, 0xd5, - 0x86, 0x81, 0x06, 0x95, 0x4b, 0xe6, 0xc1, 0x96, 0x27, 0x80, 0xa2, 0x94, 0x10, 0x72, - 0xe9, 0x51, 0x31, 0xb1, 0x67, 0x9d, 0xf0, 0x63, 0x76, 0x25, 0x04, 0x2c, 0x37, 0xd4, - 0x8f, 0xfb, 0x15, 0x2e, 0x5e, 0xbc, 0x18, 0x5c, 0x8a, 0x2b, 0x7d, 0x43, 0x85, 0xf1, - 0xc9, 0x5a, 0xf9, 0x37, 0xdf, 0x78, 0xdf, 0xd8, 0x75, 0x7f, 0xab, 0x43, 0x49, 0x68, - 0xb0, 0xb5, 0x7c, 0x66, 0x57, 0x44, 0x68, 0xf1, 0x60, 0xb4, 0x47, 0xac, 0x82, 0x21, - 0xe5, 0x06, 0x06, 0x76, 0xa8, 0x42, 0xa1, 0xc6, 0xb7, 0x17, 0x2d, 0xd3, 0x34, 0x0f, - 0x76, 0x40, 0x70, 0xab, 0x1f, 0xe0, 0x91, 0xc5, 0xc7, 0x4c, 0x95, 0xa5, 0xdc, 0x04, - 0x33, 0x90, 0x72, 0x3a, 0x4c, 0x12, 0x7d, 0xa1, 0x4c, 0xdd, 0xe1, 0xdc, 0x26, 0x75, - 0xa6, 0x23, 0x40, 0xb3, 0xe6, 0xaf, 0xd0, 0x52, 0x2a, 0x31, 0xde, 0x26, 0xe7, 0xd1, - 0xec, 0x3a, 0x9c, 0x8a, 0x09, 0x1f, 0xfd, 0xc7, 0x5b, 0x7e, 0xcf, 0xdc, 0x7c, 0x12, - 0x99, 0x5a, 0x5e, 0x37, 0xce, 0x34, 0x88, 0xbd, 0x29, 0xf8, 0x62, 0x9d, 0x68, 0xf6, - 0x96, 0x49, 0x24, 0x48, 0xdd, 0x52, 0x66, 0x97, 0x47, 0x6d, 0xc0, 0x61, 0x34, 0x6e, - 0xbe, 0x3f, 0x67, 0x72, 0x17, 0xff, 0x9c, 0x60, 0xef, 0xce, 0x94, 0x3a, 0xf2, 0x8d, - 0xfd, 0x3f, 0x9e, 0x59, 0x69, 0x25, 0x98, 0xa6, 0x04, 0x7c, 0x23, 0xc4, 0xc0, 0x14, - 0x00, 0xf1, 0xab, 0x57, 0x30, 0xea, 0xc0, 0xae, 0x8d, 0x58, 0x43, 0xd5, 0x05, 0x1c, - 0x37, 0x62, 0x40, 0x17, 0x2a, 0xf2, 0x18, 0xd7, 0xa1, 0xec, 0xfe, 0x65, 0xb4, 0xf7, - 0x51, 0x00, 0x63, 0x89, 0x83, 0xc1, 0x4d, 0xe4, 0x97, 0x47, 0x55, 0xda, 0xde, 0x80, - 0x18, 0xc9, 0xb8, 0xf4, 0x54, 0x3f, 0xb0, 0x95, 0x96, 0x15, 0x13, 0xe6, 0x7c, 0x61, - 0xdb, 0xc5, 0x9c, 0x60, 0x7f, 0x9b, 0x51, 0xf8, 0xd0, 0x9b, 0xdc, 0xad, 0x28, 0xbc, - 0xfb, 0x9e, 0x5d, 0x27, 0x44, 0xea, 0x88, 0x48, 0xb2, 0x62, 0x3a, 0xc0, 0x7f, 0x8e, - 0xf6, 0x1a, 0x81, 0xa3, 0x59, 0x10, 0xb8, 0xa1, 0xba, 0xf3, 0x9a, 0x91, 0x9a, 0x7b, - 0x60, 0xbc, 0x60, 0x4d, 0x63, 0x18, 0x5f, 0x75, 0x92, 0x21, 0xd8, 0x47, 0xcc, 0x54, - 0xa2, 0x27, 0x65, 0xa4, 0xc3, 0x34, 0x75, 0xb5, 0x79, 0x1e, 0x9a, 0xf3, 0x27, 0x1f, - 0xc8, 0xd9, 0x35, 0x06, 0x67, 0x09, 0x0d, 0x81, 0x84, 0xec, 0x50, 0x52, 0x2d, 0x80, - 0x4f, 0x23, 0xc4, 0xfb, 0x44, 0xff, 0xa4, 0x81, 0xbc, 0x92, 0xae, 0x40, 0x8d, 0x1b, - 0x9f, 0x2b, 0x13, 0x19, 0x04, 0xf9, 0x70, 0x5c, 0x59, 0xe2, 0xf4, 0xbd, 0xe7, 0xa3, - 0xb2, 0xc0, 0x85, 0xd9, 0x3f, 0xd2, 0xab, 0xc5, 0xe1, 0x4d, 0x16, 0x30, 0x01, 0xa1, - 0x2f, 0x51, 0x93, 0x8d, 0x02, 0x1a, 0xfa, 0x92, 0x23, 0x9b, 0x87, 0x3d, 0xc6, 0xc3, - 0x57, 0xea, 0xa8, 0xaf, 0x4e, 0xe6, 0xd0, 0x05, 0x40, 0x65, 0x7f, 0xe3, 0x29, 0x14, - 0x10, 0x3b, 0x5d, 0x98, 0xf6, 0x8b, 0xd3, 0xe2, 0xb5, 0x35, 0x9f, 0x08, 0xcc, 0xd8, - 0x8d, 0x0c, 0x81, 0x1e, 0x4c, 0x31, 0xfb, 0xb4, 0x9f, 0x3a, 0x90, 0xbb, 0xd0, 0x5d, - 0xce, 0x62, 0xf3, 0x44, 0xe7, 0x07, 0x75, 0x93, 0x15, 0x9a, 0xe3, 0x50, 0x50, 0xb0, - 0x4c, 0x9e, 0x6b, 0x86, 0xbc, 0x43, 0x2d, 0xc8, 0xb0, 0x48, 0xc7, 0x3c, 0x00, 0x18, - 0xca, 0x5b, 0x69, 0x41, 0x12, 0x97, 0x73, 0x2a, 0x4e, 0x1a, 0xa9, 0x9a, 0x92, 0x8c, - 0x71, 0xe7, 0xa2, 0x4f, 0xd2, 0x77, 0x85, 0x6a, 0xa4, 0x25, 0x01, 0xe5, 0x1b, 0x01, - 0x2a, 0xea, 0x94, 0x46, 0xa2, 0x10, 0x4e, 0x93, 0xf8, 0x15, 0xa0, 0xb3, 0xa2, 0x9b, - 0x45, 0x83, 0x14, 0xf3, 0xd8, 0xbe, 0x2b, 0x98, 0x23, 0xd3, 0x42, 0xf4, 0x62, 0x13, - 0xe9, 0x42, 0xa7, 0xe1, 0x9a, 0x46, 0xe9, 0x70, 0xb5, 0xc5, 0x06, 0x70, 0x84, 0x30, - 0x31, 0x7b, 0x1b, 0xb3, 0xb3, 0x5d, 0xf6, 0x8a, 0xe3, 0x3a, 0x49, 0x26, 0xa0, 0x3e, - 0x6b, 0xfe, 0xb5, 0x51, 0x04, 0x16, 0xfc, 0xbb, 0x05, 0x24, 0xc9, 0xca, 0x50, 0x74, - 0x15, 0x6c, 0xc5, 0xa5, 0xd6, 0xfe, 0x1c, 0x99, 0x5e, 0xdc, 0x60, 0xa2, 0xf5, 0x50, - 0x41, 0x1a, 0xa4, 0x1e, 0x3d, 0xa3, 0xbd, 0xcf, 0x64, 0xbc, 0xf0, 0x4a, 0x05, 0x10, - 0x57, 0x1b, 0x93, 0x6d, 0x47, 0xe5, 0x5c, 0xec, 0x03, 0x30, 0xee, 0x8d, 0xfe, 0x73, - 0x56, 0x34, 0x04, 0xf0, 0x47, 0xd7, 0xf3, 0xa8, 0xa3, 0xd7, 0x74, 0x3b, 0xc5, 0x54, - 0x95, 0x52, 0x10, 0xf1, 0xeb, 0x0d, 0x08, 0x59, 0x9e, 0xa7, 0x7d, 0x5f, 0x97, 0x4d, - 0x87, 0x17, 0x6d, 0x37, 0xd9, 0x8b, 0x9c, 0x0a, 0xd4, 0x40, 0x40, 0x72, 0x09, 0xed, - 0x6a, 0x9f, 0x08, 0x46, 0x4d, 0x56, 0x55, 0x93, 0xe1, 0xa6, 0x3b, 0x93, 0x85, 0x36, - 0xb4, 0x92, 0x44, 0xe9, 0x7d, 0x88, 0x01, 0x73, 0xb6, 0x40, 0xf2, 0xdd, 0xb7, 0x4d, - 0x06, 0x8e, 0xcb, 0x46, 0xcf, 0x28, 0x9b, 0x7d, 0x89, 0x13, 0x07, 0xbb, 0xa3, 0x70, - 0x54, 0xcf, 0x91, 0xb3, 0x1f, 0xc8, 0x2f, 0x74, 0xd5, 0xfc, 0xc0, 0x00, 0x94, 0x2e, - 0xde, 0x91, 0x18, 0x25, 0xf5, 0x3f, 0xe6, 0x09, 0x68, 0x6f, 0x46, 0x32, 0x23, 0xb1, - 0xe9, 0xbc, 0x03, 0xbd, 0xe8, 0x95, 0xd1, 0x23, 0x8f, 0xad, 0x04, 0xa3, 0xbf, 0xce, - 0x68, 0xa0, 0x75, 0xe8, 0xa3, 0x7c, 0x0e, 0x87, 0xbf, 0x46, 0xdd, 0x01, 0x55, 0x45, - 0xf9, 0xb4, 0xfb, 0x0e, 0xec, 0x64, 0x5f, 0xfc, 0xbb, 0xe0, 0xca, 0x5f, 0x8c, 0x56, - 0x1b, 0x25, 0x7d, 0x52, 0xd6, 0x02, 0xd8, 0xc9, 0x4c, 0x50, 0x28, 0x73, 0xa0, 0x1d, - 0x92, 0x51, 0xd8, 0xc8, 0x60, 0xc0, 0x41, 0x52, 0x5b, 0x3b, 0xf4, 0xe3, 0xa2, 0xeb, - 0x92, 0x72, 0x81, 0x5c, 0x75, 0x86, 0x76, 0x84, 0x28, 0xb4, 0xc2, 0xb2, 0x5e, 0x37, - 0x45, 0xf0, 0x09, 0xc5, 0xdc, 0xe2, 0x0b, 0x69, 0xd5, 0xd7, 0xc4, 0x3c, 0xeb, 0x73, - 0x6b, 0x68, 0x31, 0xe8, 0xc1, 0x10, 0xf1, 0x6c, 0xfd, 0xb3, 0xa4, 0x67, 0xe9, 0x41, - 0x4c, 0x00, 0xec, 0xf1, 0x37, 0x31, 0x50, 0x08, 0x94, 0x55, 0x56, 0x78, 0xc4, 0x97, - 0xfa, 0xba, 0x9a, 0x95, 0xd0, 0x1c, 0xc4, 0x64, 0x39, 0x0f, 0xc4, 0xa7, 0x6b, 0xfa, - 0x8b, 0x0e, 0x1c, 0x68, 0xa5, 0x25, 0xd7, 0x06, 0xd6, 0x60, 0x4b, 0x23, 0x30, 0xb6, - 0xb3, 0x48, 0x52, 0x15, 0xf6, 0x06, 0xf1, 0x88, 0x3a, 0x75, 0x15, 0x88, 0xc7, 0xef, - 0xa5, 0x06, 0xc3, 0xe8, 0xd0, 0xc6, 0x01, 0x92, 0xe8, 0x47, 0x6b, 0xd1, 0x17, 0x5d, - 0x95, 0x62, 0x08, 0x7b, 0xdb, 0x81, 0x8e, 0x66, 0x21, 0x62, 0x86, 0xba, 0xfe, 0x47, - 0xff, 0x4d, 0xbc, 0xce, 0xd5, 0x14, 0x44, 0x48, 0x0a, 0x9a, 0x56, 0x73, 0xec, 0xe7, - 0xfa, 0xc7, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xd4, 0x1a, 0xb0, 0x05, 0x17, 0x53, 0xa7, 0xca, - 0xa8, 0x9b, 0xe3, 0x13, 0x9a, 0xfd, 0x97, 0x93, 0xb3, 0xe0, 0x2f, 0x27, 0xf0, 0x40, - 0x04, 0x65, 0x95, 0xac, 0xd4, 0x7b, 0xf1, 0x3f, 0xd0, 0xda, 0x27, 0xf0, 0x9e, 0xda, - 0x48, 0x03, 0x6d, 0x3e, 0xe4, 0x37, 0xf2, 0xee, 0x8f, 0x86, 0x06, 0xea, 0x97, 0x34, - 0x3c, 0x33, 0x58, 0x46, 0x57, 0xf4, 0x6d, 0xba, 0x99, 0xdb, 0x5c, 0xfe, 0x6c, 0xa1, - 0x76, 0xfa, 0xb7, 0xb0, 0xf3, 0xbf, 0xa0, 0xab, 0x61, 0xe3, 0x40, 0xc3, 0x4e, 0xb9, - 0xf1, 0x7c, 0x7e, 0xc2, 0xbe, 0x03, 0xb1, 0x80, 0xf0, 0xbb, 0x6f, 0x43, 0x4c, 0x2a, - 0x65, 0x42, 0xe0, 0x0e, 0x84, 0x37, 0x3f, 0x4f, 0x46, 0x49, 0xcd, 0xa3, 0x2b, 0xf6, - 0x86, 0x66, 0x61, 0x43, 0xf6, 0x22, 0xaa, 0x48, 0x04, 0x60, 0xb5, 0xaf, 0xac, 0x51, - 0x86, 0x07, 0xcd, 0x9a, 0xf8, 0xbc, 0xd6, 0xb5, 0x8c, 0x30, 0x12, 0x73, 0x16, 0xb2, - 0x5d, 0x5e, 0xa7, 0xbf, 0x6b, 0x0c, 0xab, 0x85, 0x42, 0xff, 0x69, 0xd9, 0xb2, 0xf1, - 0x80, 0xbe, 0x12, 0xed, 0x75, 0x34, 0x4a, 0x39, 0x5a, 0xa1, 0x0f, 0x85, 0x2f, 0x08, - 0x3a, 0xd6, 0x4e, 0xf4, 0x0e, 0x9c, 0x03, 0x09, 0xe9, 0xbb, 0xa5, 0x4b, 0x8c, 0xb3, - 0x3c, 0x95, 0x49, 0x8a, 0x69, 0x53, 0x8d, 0x3a, 0xe5, 0xb2, 0x5e, 0x24, 0x70, 0x98, - 0x30, 0x6f, 0xa8, 0xc7, 0x4a, 0x8e, 0xe5, 0xbc, 0xa9, 0x41, 0x53, 0x1d, 0x61, 0xaa, - 0xc2, 0x7a, 0xab, 0x3d, 0xc5, 0x61, 0x7d, 0x56, 0x06, 0xc9, 0x57, 0x7a, 0x2a, 0x83, - 0x46, 0xe8, 0xd8, 0x5b, 0x32, 0xb8, 0x50, 0x57, 0x75, 0x10, 0x8d, 0xc8, 0x5e, 0x2a, - 0xde, 0x2e, 0xac, 0x1e, 0x63, 0x6e, 0x1a, 0xf4, 0x05, 0x4c, 0x8b, 0x6f, 0x57, 0x63, - 0x2d, 0xf2, 0x69, 0xc3, 0x72, 0x3b, 0x32, 0x08, 0x72, 0xe4, 0xc5, 0x7b, 0x21, 0x83, - 0x58, 0xdc, 0x7e, 0x99, 0x05, 0xbb, 0x04, 0xed, 0xf9, 0x2e, 0xdf, 0x0d, 0xf6, 0x35, - 0xf3, 0xbf, 0x36, 0x1e, 0x57, 0xa1, 0x32, 0x96, 0xe1, 0x44, 0x7a, 0xf5, 0x08, 0x02, - 0x72, 0xd6, 0x36, 0xe2, 0x75, 0x18, 0xa9, 0x87, 0x6e, 0x15, 0xeb, 0x01, 0xf5, 0xe8, - 0xde, 0xd8, 0x18, 0x92, 0x51, 0x1c, 0xc2, 0x85, 0x1b, 0x00, 0xb8, 0x32, 0x71, 0x2a, - 0x6d, 0x3b, 0xa5, 0x66, 0x03, 0x17, 0xbc, 0xd3, 0x56, 0x76, 0x21, 0xa7, 0xcf, 0x84, - 0x45, 0x58, 0x96, 0x53, 0x26, 0x20, 0x20, 0xc3, 0x3b, 0xf7, 0x80, 0x31, 0xb8, 0xee, - 0x07, 0x07, 0xde, 0x07, 0x20, 0x68, 0xc1, 0x70, 0x57, 0x0b, 0x27, 0xe6, 0xd9, 0xf5, - 0xc6, 0xdd, 0xc3, 0x35, 0x40, 0x2e, 0xfc, 0x54, 0x88, 0x62, 0xf5, 0xa0, 0x70, 0x94, - 0xfd, 0x42, 0x8a, 0x7b, 0xbc, 0x15, 0xd7, 0xb3, 0x8d, 0x05, 0x36, 0x2c, 0x9c, 0xa9, - 0x85, 0xf5, 0x8a, 0x76, 0x64, 0x7d, 0x2b, 0xe4, 0xc2, 0xcd, 0x6b, 0x3d, 0x17, 0xd6, - 0x87, 0x09, 0x71, 0xd7, 0xa0, 0x98, 0xba, 0xf7, 0x2c, 0x6f, 0x6f, 0x12, 0x14, 0xcf, - 0x1f, 0xaa, 0xe4, 0x88, 0x03, 0x7d, 0xe2, 0x59, 0xd3, 0x41, 0x5c, 0x2f, 0x0d, 0xde, - 0xc7, 0x45, 0x70, 0x04, 0xf3, 0x57, 0x08, 0xd1, 0xec, 0xcc, 0xcc, 0x0d, 0xf6, 0x5a, - 0x04, 0x94, 0x3a, 0xd5, 0xcb, 0xc1, 0x3f, 0x29, 0x5f, 0x02, 0x0f, 0xe0, 0x56, 0xc4, - 0x0b, 0x2d, 0x88, 0xf2, 0x7d, 0xc3, 0x4c, 0xfe, 0xb8, 0x03, 0xbe, 0x34, 0x83, 0xa9, - 0xeb, 0xf9, 0xb5, 0xa9, 0x02, 0x60, 0x57, 0x72, 0x5d, 0x63, 0xea, 0xd2, 0xc0, 0xc0, - 0x03, 0x1f, 0xe2, 0x6a, 0xc1, 0xe7, 0xbd, 0xfc, 0xd6, 0xfa, 0xd8, 0x75, 0x84, 0x2d, - 0x19, 0x4f, 0x33, 0x17, 0x50, 0x46, 0x2c, 0x06, 0xb8, 0xd7, 0x98, 0x2d, 0x67, 0x99, - 0x5e, 0xd5, 0xd3, 0xae, 0x96, 0x02, 0x5a, 0xe0, 0x06, 0x7f, 0x4e, 0xb1, 0xc7, 0xc9, - 0x32, 0x31, 0xbd, 0x39, 0x77, 0x3c, 0xbe, 0x0a, 0x9d, 0x66, 0xb0, 0xc9, 0xaa, 0x8c, - 0xff, 0x6a, 0x37, 0x6e, 0x1f, 0x37, 0x2e, 0xac, 0x6a, 0xc4, 0x02, 0x6c, 0xc0, 0x94, - 0x22, 0x45, 0xd4, 0xc2, 0xdc, 0xf0, 0x2d, 0x76, 0x40, 0xff, 0xcc, 0x5a, 0x6a, 0xc3, - 0xa8, 0x7f, 0x5c, 0x41, 0x15, 0x51, 0xbc, 0xc2, 0xf2, 0x6c, 0xb9, 0x49, 0x61, 0xd5, - 0x3f, 0x95, 0xdd, 0xb1, 0x9a, 0xe9, 0x30, 0xc8, 0xd7, 0x0f, 0x03, 0x1b, 0x29, 0xa5, - 0xdf, 0x99, 0xff, 0x36, 0x69, 0x5e, 0x80, 0x2c, 0xbc, 0xb6, 0xb5, 0x8c, 0x1b, 0xa7, - 0xed, 0x5e, 0xac, 0xfa, 0x76, 0x41, 0x4a, 0x41, 0xad, 0x4a, 0x44, 0xf7, 0x1f, 0x1b, - 0x58, 0x0d, 0x34, 0xc3, 0xa9, 0x52, 0x92, 0x0b, 0x25, 0x4a, 0x14, 0x5f, 0xea, 0x51, - 0x7f, 0x5b, 0x42, 0xb2, 0xf6, 0x5e, 0xcd, 0x0f, 0x82, 0x59, 0x54, 0x78, 0xd8, 0x0a, - 0xe5, 0xc8, 0xce, 0xea, 0x12, 0xa1, 0x61, 0xcc, 0xbb, 0x5e, 0xac, 0x09, 0x99, 0x0f, - 0xc6, 0x19, 0xa4, 0x60, 0x80, 0x43, 0x6d, 0xbd, 0x08, 0xd7, 0x47, 0x84, 0xaf, 0x00, - 0x2d, 0x58, 0xe0, 0x6f, 0xaf, 0x7f, 0x3c, 0xea, 0xe7, 0xd3, 0x41, 0x9b, 0x1f, 0xca, - 0x26, 0x5a, 0x55, 0x59, 0xcf, 0x9e, 0x2d, 0x3b, 0x60, 0x97, 0x8d, 0x81, 0xa6, 0x78, - 0xb9, 0xed, 0x8e, 0x44, 0x86, 0xb4, 0xd1, 0x46, 0x09, 0xd6, 0xc1, 0x27, 0xc0, 0xc2, - 0xfb, 0xff, 0xe3, 0x0a, 0x60, 0xf7, 0xbf, 0xf1, 0xd9, 0xfb, 0x83, 0x00, 0xed, 0x00, - 0x92, 0x53, 0xba, 0x9b, 0x99, 0x6f, 0xa0, 0x52, 0x41, 0xb1, 0x0f, 0x5a, 0xc9, 0xa8, - 0x40, 0x8e, 0x92, 0x5b, 0x62, 0x6b, 0xb2, 0x1a, 0x47, 0x1f, 0xe3, 0xbe, 0xde, 0x52, - 0xbb, 0xa0, 0x97, 0xb2, 0xa9, 0x9a, 0x9b, 0xa5, 0xa8, 0x66, 0x58, 0xc3, 0xfd, 0x9e, - 0xc5, 0x5b, 0xfa, 0x9b, 0x32, 0x85, 0x67, 0x25, 0x4a, 0xb3, 0x6d, 0x2c, 0x7f, 0x44, - 0xd2, 0xc7, 0xe1, 0x3e, 0xb5, 0x4b, 0xeb, 0x70, 0xea, 0x8f, 0xa9, 0x4b, 0x6c, 0x6e, - 0x01, 0x2d, 0x79, 0xe3, 0xf5, 0x36, 0x89, 0xc2, 0xb1, 0xa1, 0x8e, 0xaf, 0x2d, 0x47, - 0x1d, 0x13, 0xc1, 0xab, 0x39, 0xd9, 0x19, 0x4a, 0xe8, 0x43, 0xab, 0x1d, 0x28, 0xff, - 0xa8, 0xf6, 0x9d, 0xc7, 0xe1, 0x5c, 0xc3, 0x8b, 0x12, 0xe8, 0xfc, 0xd7, 0x92, 0x55, - 0xb7, 0x21, 0x60, 0x56, 0xd9, 0xed, 0xb7, 0x48, 0x2f, 0xb9, 0x8a, 0xa0, 0x33, 0xb6, - 0x5e, 0x51, 0xc1, 0xa0, 0x8b, 0x8a, 0x11, 0xd8, 0x4d, 0x04, 0x09, 0xb7, 0x34, 0xf4, - 0x52, 0xaa, 0xf0, 0xd6, 0xb1, 0x8f, 0x50, 0x25, 0x86, 0x83, 0xd3, 0xf9, 0xa7, 0x6d, - 0x39, 0x9f, 0xd0, 0x47, 0xee, 0xe2, 0x88, 0xbb, 0x45, 0x85, 0x85, 0x1d, 0xc9, 0x3e, - 0xcc, 0xc6, 0x23, 0x22, 0x92, 0x4c, 0xd1, 0x3b, 0x5d, 0xd4, 0xee, 0xd6, 0x6e, 0xd8, - 0xd9, 0x97, 0x2d, 0x77, 0x26, 0x29, 0xea, 0x64, 0x74, 0x2e, 0x54, 0x73, 0x39, 0x81, - 0xb0, 0x06, 0xc0, 0x62, 0x46, 0x8e, 0x4b, 0xd8, 0xf7, 0xdd, 0x9a, 0xf6, 0x98, 0xf5, - 0x2a, 0xe8, 0x14, 0x63, 0x4e, 0x81, 0xd7, 0xf3, 0xe0, 0xc4, 0x20, 0x31, 0x7c, 0xac, - 0xa9, 0xae, 0x48, 0x11, 0xc6, 0xaf, 0x06, 0xfe, 0x80, 0xa8, 0xc0, 0x2a, 0xb7, 0xa0, - 0x0e, 0x18, 0xe4, 0xa6, 0xaa, 0x1e, 0xa1, 0xb7, 0x69, 0x45, 0xd2, 0x61, 0x5d, 0x43, - 0xac, 0x11, 0x8b, 0x56, 0xc2, 0xf2, 0x96, 0x0f, 0xe9, 0x3a, 0x02, 0x5f, 0x13, 0xec, - 0x91, 0xff, 0xc6, 0xd2, 0xc3, 0x53, 0x69, 0x9a, 0xbb, 0x09, 0x2d, 0xed, 0xc0, 0x65, - 0xdb, 0x8f, 0xa2, 0x14, 0xdb, 0xc4, 0x64, 0x66, 0xf8, 0x97, 0xb8, 0x8c, 0x58, 0xb3, - 0x01, 0x52, 0x13, 0x3a, 0xa3, 0x83, 0x1a, 0xf3, 0x7c, 0x74, 0xd9, 0x9e, 0x9e, 0x36, - 0xff, 0x70, 0x11, 0xd3, 0x23, 0x83, 0x05, 0x69, 0x15, 0x08, 0xa2, 0xc3, 0xa4, 0x3e, - 0x75, 0x5d, 0xc0, 0x81, 0xb5, 0x11, 0xd6, 0x48, 0x2a, 0x7d, 0xb6, 0x5f, 0xa9, 0x69, - 0x9e, 0xa8, 0x7f, 0xf4, 0x70, 0x99, 0xed, 0x36, 0x37, 0xdb, 0xb0, 0xa3, 0xd0, 0xef, - 0x79, 0x79, 0x6a, 0x8e, 0xf1, 0xe4, 0xd9, 0x4d, 0x42, 0xb4, 0xbc, 0x2b, 0x4a, 0x03, - 0x8a, 0xe6, 0xe4, 0x6b, 0x24, 0xcf, 0xc8, 0x41, 0x53, 0xd3, 0x1e, 0xaf, 0x89, 0x50, - 0x63, 0xa5, 0xca, 0x95, 0x9b, 0xe6, 0x3f, 0x37, 0xf2, 0xba, 0x0d, 0x43, 0x23, 0x66, - 0x73, 0x6d, 0x86, 0x32, 0xfc, 0xe0, 0x72, 0xb6, 0xae, 0x5b, 0x6f, 0x3f, 0xd5, 0x9d, - 0x3f, 0xaf, 0xf6, 0x38, 0x27, 0x5a, 0x99, 0x2f, 0xef, 0xc8, 0x7e, 0x60, 0xd4, 0x4c, - 0x2c, 0xad, 0xc2, 0xb5, 0xc4, 0x94, 0xe3, 0xe7, 0x2e, 0xb4, 0x59, 0x7c, 0x96, 0xb4, - 0x01, 0x67, 0x79, 0x9a, 0x90, 0x01, 0xa2, 0xed, 0x36, 0x76, 0xa8, 0xb4, 0x03, 0xae, - 0x25, 0xff, 0xd7, 0x72, 0xf7, 0x08, 0x1e, 0x9a, 0x32, 0xbc, 0xc1, 0xc5, 0xe2, 0xed, - 0xd4, 0xe2, 0xa6, 0x57, 0x6b, 0x78, 0x3c, 0xce, 0x3a, 0xae, 0x11, 0xfa, 0x43, 0x22, - 0x62, 0x54, 0x88, 0x56, 0x18, 0x3e, 0xe6, 0x82, 0xd5, 0xdc, 0x31, 0xbe, 0xb3, 0x8f, - 0x06, 0x1c, 0xbd, 0xec, 0xa7, 0x02, 0x1a, 0x44, 0x4e, 0x2d, 0xd4, 0x17, 0xdf, 0x26, - 0xdc, 0xd2, 0x20, 0xf2, 0xb7, 0x31, 0x77, 0x2b, 0x43, 0x9e, 0x96, 0xd6, 0x14, 0xe1, - 0xfa, 0xcb, 0x48, 0x6c, 0x7a, 0x7d, 0x51, 0x71, 0xb1, 0xde, 0x35, 0x9f, 0x6a, 0xd3, - 0xa9, 0x6f, 0x64, 0x9c, 0x96, 0x91, 0x02, 0xa1, 0x96, 0x4f, 0xb4, 0xb4, 0xa1, 0xa4, - 0x27, 0x9c, 0x68, 0xe6, 0xc3, 0x72, 0xe4, 0x21, 0x87, 0xd7, 0x54, 0xe8, 0x04, 0xa6, - 0x16, 0x53, 0x09, 0x20, 0x69, 0xfb, 0x9b, 0x6d, 0x25, 0x26, 0x68, 0x90, 0x80, 0x8b, - 0x01, 0x5d, 0xf2, 0x8c, 0x80, 0x10, 0x65, 0xda, 0x6f, 0xeb, 0xdc, 0x1a, 0x56, 0xbf, - 0xd0, 0x02, 0x62, 0x5a, 0xcf, 0xaa, 0x53, 0x73, 0xfd, 0xe1, 0x49, 0xc1, 0xcf, 0xc3, - 0x64, 0x9b, 0x48, 0x69, 0x69, 0x6d, 0x44, 0xec, 0xb1, 0x24, 0x79, 0xc5, 0xeb, 0xef, - 0x99, 0x5f, 0x10, 0x02, 0x9f, 0x8b, 0x53, 0x0e, 0xeb, 0x3f, 0xdc, 0x2e, 0x50, 0xe8, - 0x75, 0x7f, 0xc0, 0xbb, 0x9e, 0x26, 0x30, 0x23, 0xdb, 0x82, 0xf8, 0x78, 0xd9, 0xac, - 0x7f, 0xfb, 0x0b, 0xd4, 0x39, 0x1d, 0xf1, 0xd8, 0x79, 0x89, 0x9a, 0x3e, 0xf5, 0x7b, - 0xfd, 0x0d, 0x1f, 0x77, 0x55, 0x64, 0x8e, 0xdd, 0x85, 0xbb, 0x05, 0x2a, 0x6e, 0xdf, - 0x71, 0xcd, 0x26, 0x28, 0xc9, 0x87, 0x42, 0x9f, 0x36, 0xdc, 0x50, 0x5c, 0xcc, 0x43, - 0xf3, 0x0e, 0x7a, 0x86, 0x9c, 0x9e, 0x25, 0x5e, 0x2a, 0xf9, 0xfc, 0xf3, 0x0c, 0x12, - 0x17, 0x96, 0xd1, 0x90, 0x00, 0x09, 0x60, 0xcb, 0x6f, 0xe2, 0xf1, 0xbf, 0x24, 0x61, - 0x18, 0xb4, 0x98, 0xf3, 0x24, 0x7f, 0x9d, 0x48, 0x4c, 0x73, 0xcf, 0x09, 0x39, 0x30, - 0x39, 0xe4, 0x53, 0x26, 0xb8, 0xff, 0xff, 0xb3, 0xe7, 0xe6, 0x15, 0x9c, 0x46, 0x69, - 0x9f, 0x10, 0x07, 0x92, 0xd4, 0x67, 0x29, 0x50, 0x34, 0x8a, 0x90, 0x55, 0x2e, 0x45, - 0x94, 0x3b, 0xee, 0xac, 0xf0, 0x3f, 0x32, 0x16, 0xf9, 0x4e, 0x27, 0x4d, 0x63, 0xd6, - 0x37, 0xd9, 0xf1, 0x90, 0xe8, 0xa2, 0x66, 0xcd, 0xee, 0xf1, 0x53, 0x53, 0x0b, 0xee, - 0x5c, 0xb8, 0x35, 0x52, 0x60, 0x50, 0x5c, 0x2c, 0x2e, 0x5d, 0x99, 0x0f, 0xff, 0xdc, - 0x34, 0xec, 0x0f, 0xf7, 0xf1, 0xaf, 0x81, 0xb2, 0x4c, 0xed, 0x0e, 0xfa, 0x62, 0x13, - 0xda, 0x6c, 0x7c, 0x60, 0xc4, 0x87, 0xf5, 0xf7, 0xb0, 0x3f, 0x81, 0x60, 0xa0, 0x57, - 0xf4, 0x6d, 0x05, 0xbf, 0x82, 0x18, 0xb3, 0xad, 0xd9, 0xc0, 0x68, 0x93, 0xbd, 0x02, - 0xdb, 0x9b, 0x61, 0x19, 0x1d, 0xfb, 0x13, 0x3b, 0xfa, 0xbe, 0x48, 0x58, 0xe4, 0x7a, - 0x4c, 0xc3, 0x2e, 0x41, 0x6e, 0xc0, 0x8b, 0x8a, 0xc7, 0x91, 0x5a, 0x43, 0x73, 0x3f, - 0x44, 0x06, 0xe9, 0xd9, 0x67, 0xc5, 0x60, 0xf3, 0x44, 0xd7, 0xe9, 0x04, 0xa2, 0x80, - 0x45, 0xd9, 0x9f, 0x3a, 0xf8, 0xc8, 0x2e, 0x97, 0xe1, 0xb9, 0xc1, 0xb2, 0x05, 0xe5, - 0x85, 0xfb, 0xeb, 0xb4, 0x8f, 0xaf, 0x58, 0xf1, 0xb6, 0x5d, 0xca, 0x24, 0x97, 0xe0, - 0x9a, 0x70, 0xaa, 0xd4, 0x86, 0x5f, 0x85, 0x71, 0x5a, 0x28, 0x0e, 0x18, 0x6f, 0x3f, - 0xc1, 0x74, 0x0d, 0x81, 0x84, 0xd3, 0x3e, 0x83, 0x22, 0x16, 0x95, 0x21, 0xcd, 0xc1, - 0x32, 0x21, 0x29, 0x39, 0xc8, 0x4a, 0x10, 0x89, 0x64, 0xe2, 0xde, 0x74, 0xb6, 0xea, - 0x55, 0xb4, 0xcb, 0x8f, 0x6f, 0x9b, 0xee, 0x98, 0xb1, 0x0d, 0x41, 0x51, 0x09, 0x45, - 0x5f, 0x48, 0xb7, 0x76, 0x08, 0x2d, 0xc3, 0x0b, 0x4b, 0xc7, 0x34, 0x77, 0x07, 0x55, - 0x11, 0x70, 0x03, 0x08, 0x15, 0x8c, 0xe2, 0xf2, 0xf9, 0xbf, 0x0f, 0x69, 0x1b, 0x2c, - 0xe5, 0x3e, 0x61, 0x14, 0x2c, 0xb7, 0x40, 0xc1, 0x5b, 0x7b, 0x62, 0x3c, 0xf4, 0x8b, - 0x3f, 0x7b, 0xfe, 0xfa, 0x31, 0xbc, 0xdc, 0x66, 0x5c, 0x6d, 0x71, 0x23, 0xe9, 0x53, - 0x50, 0x81, 0x13, 0x75, 0x94, 0x7b, 0x05, 0x5a, 0x43, 0xdb, 0x07, 0xe0, 0x3f, 0x33, - 0x62, 0x7d, 0xf5, 0xc6, 0x38, 0xbf, 0xad, 0x95, 0x6d, 0xdc, 0x1e, 0xa7, 0xd7, 0x62, - 0x0a, 0x20, 0xf2, 0x79, 0x2f, 0x63, 0x81, 0x7a, 0x1c, 0xf3, 0x25, 0x80, 0xd0, 0x42, - 0x74, 0x23, 0x4a, 0xf2, 0xa5, 0x1b, 0x56, 0xbb, 0x68, 0xa2, 0x9e, 0x43, 0xa9, 0x54, - 0x14, 0x2b, 0xa4, 0xca, 0x68, 0x23, 0xbd, 0xe9, 0x05, 0x3d, 0x72, 0xfd, 0xad, 0xbc, - 0x61, 0xad, 0x59, 0x36, 0xc5, 0x3f, 0xdd, 0x75, 0x79, 0x44, 0x6d, 0x11, 0xc4, 0x46, - 0x07, 0xf4, 0x16, 0x30, 0xe4, 0xc0, 0x89, 0x15, 0xe6, 0x31, 0x77, 0x15, 0x50, 0xe9, - 0xce, 0x1f, 0xca, 0x2c, 0x63, 0xfe, 0x06, 0xb7, 0x98, 0x9d, 0x58, 0x4f, 0xa7, 0xd7, - 0x82, 0xa8, 0x8c, 0x1e, 0x7d, 0x64, 0xb6, 0xfb, 0xf5, 0x5e, 0x35, - ], - script_code: vec![0x6a, 0x53, 0x53, 0x63], - transparent_input: None, - hash_type: 1, - amount: 379068098637835, - consensus_branch_id: 1537743641, - sighash: [ - 0x92, 0xe7, 0xb4, 0x8f, 0x32, 0x81, 0x87, 0x71, 0x26, 0x87, 0xaf, 0x4d, 0xc1, 0x7a, - 0x73, 0xfe, 0x0a, 0x70, 0xac, 0x07, 0x8d, 0x24, 0xcd, 0xcd, 0xd4, 0x58, 0xa3, 0xd6, - 0x86, 0x61, 0xec, 0x0a, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x24, 0x9d, 0xf0, 0x57, 0x01, - 0xda, 0xb0, 0x31, 0xc4, 0xba, 0xc1, 0xea, 0x26, 0x7a, 0x29, 0x96, 0xa2, 0x02, 0x8d, - 0x1e, 0x6a, 0x0f, 0x80, 0xa3, 0x84, 0x7c, 0x53, 0x1d, 0xba, 0x96, 0xee, 0x65, 0xa2, - 0x41, 0x89, 0xbd, 0x09, 0x52, 0xac, 0x65, 0x63, 0x65, 0xac, 0x00, 0x65, 0x00, 0xb2, - 0xa4, 0xf9, 0x51, 0xef, 0x8f, 0x49, 0x7d, 0xff, 0xf2, 0xf2, 0xf2, 0x71, 0xea, 0xb8, - 0x9c, 0x62, 0x8e, 0x18, 0xb5, 0xfc, 0xb4, 0x38, 0x82, 0x53, 0x7e, 0xaf, 0x6a, 0xd2, - 0xa6, 0xb1, 0x75, 0x46, 0x33, 0xca, 0xa8, 0x6b, 0xf2, 0xc7, 0x6f, 0x07, 0x53, 0x63, - 0x6a, 0x6a, 0x65, 0x6a, 0x53, 0xa2, 0x21, 0x0c, 0x27, 0x01, 0xea, 0x6c, 0x54, 0x2c, - 0xc8, 0xc7, 0x06, 0x00, 0x00, 0xe0, 0x11, 0x29, 0xf0, 0x3a, 0x1e, 0x9c, 0x09, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xbe, 0x07, 0x62, 0xc0, 0xb1, 0xc6, 0x58, 0x55, 0xde, 0xba, 0x84, 0x22, - 0xca, 0x4b, 0x88, 0xab, 0xee, 0xa6, 0xa4, 0x38, 0x2c, 0xf1, 0x6c, 0xcd, 0x6d, 0xc7, - 0xc3, 0x7c, 0x44, 0xe5, 0x49, 0xc4, 0x53, 0x48, 0x19, 0xac, 0xd8, 0xbb, 0x0a, 0x02, - 0xa5, 0xfa, 0x7a, 0x1c, 0x1d, 0x38, 0x06, 0xfb, 0xc3, 0x40, 0x7f, 0xd7, 0xda, 0x93, - 0xfd, 0x0d, 0xe6, 0x40, 0x0d, 0x3a, 0xb8, 0x97, 0x74, 0x85, 0xcd, 0xdf, 0xbe, 0xd5, - 0x93, 0x2f, 0x50, 0x7b, 0x79, 0x94, 0x7a, 0xdb, 0x2f, 0xad, 0x37, 0x61, 0x5a, 0xa7, - 0x17, 0xdb, 0x5f, 0x29, 0x80, 0x99, 0xf2, 0x0f, 0x26, 0x3b, 0x35, 0x9a, 0x11, 0x51, - 0xa6, 0xb7, 0x5c, 0x01, 0x36, 0x5e, 0xb1, 0x54, 0xae, 0x42, 0x14, 0x0d, 0x6e, 0x10, - 0x34, 0x2f, 0x14, 0xf3, 0x4d, 0xc3, 0x3e, 0x07, 0xff, 0x0e, 0x4d, 0x1a, 0x6b, 0xe3, - 0x75, 0xb3, 0x2f, 0x84, 0xb9, 0x2e, 0x5d, 0x81, 0xeb, 0xb6, 0x39, 0xc4, 0xf2, 0x7e, - 0x71, 0x5a, 0xa4, 0x2c, 0xc7, 0x57, 0x07, 0xd4, 0xeb, 0xd1, 0xbb, 0xfb, 0xe8, 0xf9, - 0x0f, 0xc7, 0xc9, 0x53, 0xe7, 0xa9, 0x71, 0x5e, 0x65, 0xaf, 0x82, 0x67, 0x37, 0x3d, - 0x34, 0x51, 0x67, 0x4f, 0xf0, 0x84, 0xef, 0xd9, 0x2c, 0xcf, 0x3b, 0xcc, 0x7a, 0xca, - 0x14, 0x67, 0xb6, 0x32, 0x7e, 0x4f, 0x95, 0x22, 0xb2, 0xcc, 0x57, 0x9a, 0x7a, 0x8f, - 0xff, 0x7c, 0xa7, 0xcf, 0x14, 0x5d, 0xfc, 0x13, 0xea, 0xfc, 0x34, 0x15, 0x3b, 0x2c, - 0x3e, 0x8a, 0xfb, 0xe5, 0x34, 0x44, 0xd0, 0xc7, 0x3b, 0x3b, 0xd5, 0xbc, 0x87, 0x0b, - 0x01, 0xcd, 0x45, 0x79, 0x11, 0xe3, 0x56, 0x31, 0x3f, 0xd1, 0xda, 0xfb, 0x4c, 0x81, - 0x51, 0x63, 0x4a, 0x01, 0xaf, 0xf7, 0xcf, 0x11, 0x6d, 0x43, 0x3c, 0x3d, 0x2b, 0x3a, - 0xdd, 0xa9, 0xce, 0xbe, 0x18, 0xf7, 0xd1, 0x72, 0x44, 0x3e, 0x5e, 0x7b, 0x5a, 0xc9, - 0xab, 0xe8, 0xdb, 0x22, 0x56, 0xd7, 0xeb, 0xe2, 0xff, 0x28, 0x02, 0x09, 0x39, 0x50, - 0x38, 0x70, 0x59, 0x7b, 0x9a, 0x95, 0x58, 0x92, 0xc7, 0x38, 0x02, 0x50, 0xa2, 0xd4, - 0x2e, 0xc9, 0x2b, 0xe7, 0x23, 0xfe, 0xdf, 0x2f, 0x2e, 0xde, 0x5a, 0x47, 0x2a, 0xa1, - 0xe7, 0x4f, 0x33, 0xad, 0x41, 0x90, 0x15, 0x44, 0xed, 0xbb, 0xe3, 0xac, 0x46, 0x4c, - 0xf4, 0x03, 0x19, 0x60, 0x15, 0xf4, 0xf2, 0x2a, 0xc2, 0xb8, 0xfc, 0x01, 0x49, 0x6b, - 0xea, 0xb4, 0xd4, 0x59, 0x07, 0xf4, 0x79, 0x81, 0x2a, 0x25, 0x94, 0x31, 0xa2, 0xcb, - 0xc9, 0x3d, 0x4f, 0x3b, 0x84, 0xe4, 0x0b, 0x36, 0x60, 0x20, 0x27, 0x3a, 0x67, 0x52, - 0xe5, 0x01, 0xaf, 0x6f, 0xf1, 0xb7, 0x8d, 0xdc, 0x81, 0x7e, 0x6e, 0xa3, 0x51, 0xd6, - 0x00, 0x6b, 0xec, 0xf8, 0xd2, 0xff, 0xb0, 0x39, 0x90, 0xf6, 0x77, 0x74, 0xa8, 0x1e, - 0x05, 0xb7, 0xf4, 0xbb, 0xad, 0x85, 0x77, 0xfa, 0x27, 0xc9, 0xde, 0x64, 0xe1, 0xb1, - 0x1d, 0xcf, 0x38, 0x4f, 0x59, 0x56, 0x44, 0x37, 0x48, 0x75, 0x5a, 0x9f, 0xc6, 0xf2, - 0xa0, 0x03, 0x10, 0xc3, 0x65, 0x7e, 0xba, 0xc0, 0x3b, 0xfc, 0x0b, 0x58, 0x7b, 0xef, - 0x2f, 0x45, 0xec, 0x8a, 0xcd, 0xaa, 0x51, 0xc1, 0x43, 0xb0, 0xcb, 0x25, 0xb9, 0x14, - 0x2c, 0x61, 0xbd, 0x79, 0x0a, 0x80, 0x03, 0xc2, 0x3f, 0x90, 0xcc, 0x03, 0x49, 0x5b, - 0x51, 0xe4, 0xd2, 0x84, 0x3e, 0x55, 0x7f, 0x9e, 0x25, 0x45, 0x10, 0x8c, 0x6c, 0x6f, - 0xae, 0x35, 0x9f, 0x64, 0x5c, 0x27, 0x68, 0x91, 0xc0, 0xdc, 0xab, 0x03, 0xaf, 0x18, - 0x77, 0x00, 0xc0, 0x82, 0xdc, 0x47, 0x77, 0x40, 0xfb, 0x3f, 0x2c, 0xd7, 0xbb, 0x59, - 0xfb, 0x35, 0x85, 0x54, 0xe9, 0x4c, 0x7e, 0x67, 0x8c, 0xe0, 0x1a, 0xeb, 0xf9, 0x4e, - 0x51, 0x5e, 0x03, 0x72, 0x29, 0x67, 0x99, 0x5a, 0xea, 0x85, 0x8d, 0x64, 0xe7, 0x78, - 0x9f, 0xf3, 0x06, 0x36, 0x95, 0x77, 0x22, 0x81, 0x80, 0x32, 0x6a, 0x5b, 0x0a, 0xf4, - 0x75, 0xe2, 0x7a, 0x54, 0xb2, 0x07, 0xb4, 0x03, 0x92, 0xe3, 0x76, 0x17, 0x0e, 0x3f, - 0xb0, 0x05, 0x02, 0x82, 0x61, 0xc9, 0x9c, 0x2d, 0xbd, 0x0e, 0xed, 0xee, 0x87, 0x1c, - 0x1c, 0x0f, 0x48, 0xb8, 0xe9, 0xb8, 0xe4, 0xbe, 0x77, 0xd1, 0xb7, 0x37, 0xfe, 0x21, - 0xf0, 0xfa, 0x5a, 0x18, 0xeb, 0xb5, 0x27, 0x55, 0xb5, 0xa6, 0xcf, 0x61, 0x30, 0xfb, - 0x56, 0x94, 0x4c, 0xfa, 0xb8, 0x75, 0x27, 0xc2, 0x50, 0xd1, 0x13, 0xb2, 0x9b, 0xca, - 0xc9, 0xaa, 0xa1, 0x0c, 0x2e, 0x7d, 0xe4, 0x15, 0xed, 0xb0, 0x80, 0x6c, 0x6d, 0xa0, - 0x30, 0x20, 0xa1, 0x34, 0xca, 0x7e, 0xcd, 0xc8, 0xda, 0x1b, 0xd5, 0x7a, 0x37, 0xf5, - 0x5a, 0x46, 0x94, 0x0b, 0x45, 0xb2, 0x41, 0xb1, 0xc1, 0x6e, 0xe1, 0x00, 0x92, 0x7d, - 0x1b, 0xd8, 0x60, 0xd4, 0x45, 0xa9, 0xde, 0x50, 0xd4, 0xc3, 0x84, 0xd6, 0xe1, 0xd0, - 0x01, 0x08, 0x02, 0x6c, 0x0e, 0xa5, 0xeb, 0xbf, 0x0b, 0x72, 0xfb, 0xf5, 0xc3, 0x70, - 0xbc, 0xe1, 0x8d, 0x3a, 0xcb, 0xc4, 0x65, 0x99, 0x09, 0x9b, 0xaa, 0xe1, 0xd8, 0x02, - 0xf7, 0x73, 0x33, 0x49, 0x4a, 0x7a, 0xe1, 0x30, 0xfe, 0x86, 0xe8, 0xf8, 0x18, 0xf9, - 0x26, 0x1a, 0x2d, 0xad, 0xb4, 0x12, 0x52, 0x29, 0xba, 0x0f, 0xfc, 0x0e, 0x70, 0x90, - 0x32, 0x44, 0x30, 0xb5, 0x21, 0xa9, 0x0d, 0x22, 0x4a, 0xb7, 0xa1, 0x02, 0x4e, 0x1d, - 0x89, 0x3e, 0x74, 0x04, 0xfe, 0xdb, 0x34, 0x8e, 0x4d, 0x5e, 0x22, 0x35, 0xc5, 0x9a, - 0x78, 0x76, 0xa0, 0xfc, 0x60, 0x14, 0x5c, 0x6a, 0x00, 0x96, 0x87, 0x68, 0x44, 0x60, - 0x27, 0x1e, 0xe1, 0x33, 0xa4, 0x37, 0xfe, 0x52, 0xfb, 0x6c, 0xfb, 0xa9, 0x7f, 0xce, - 0xc1, 0x61, 0xdf, 0x51, 0x5d, 0xde, 0x90, 0x5a, 0x24, 0xda, 0x6d, 0x37, 0xbd, 0xc3, - 0x40, 0x44, 0xa9, 0x55, 0xe6, 0x82, 0xb4, 0x74, 0x71, 0xca, 0x1e, 0x8c, 0x78, 0xc5, - 0x1e, 0xd3, 0x77, 0xcd, 0x4a, 0xfa, 0x89, 0x4b, 0xd9, 0xbd, 0x12, 0xe7, 0x07, 0x15, - 0x6d, 0xa0, 0x72, 0x6f, 0x7c, 0xf5, 0x72, 0x9f, 0xab, 0xe3, 0x72, 0x16, 0x04, 0x63, - 0xfe, 0x04, 0x29, 0x24, 0x4d, 0x06, 0x74, 0x89, 0xba, 0x5d, 0x09, 0x47, 0x2e, 0xcd, - 0x9b, 0xcd, 0xc4, 0xd5, 0xe4, 0xdf, 0x10, 0x1e, 0x18, 0x9d, 0xb8, 0x46, 0x3e, 0xb5, - 0x38, 0x30, 0x7b, 0x58, 0x7d, 0xef, 0xf7, 0x8d, 0xe9, 0xc7, 0x3a, 0xf2, 0x80, 0x80, - 0xb2, 0xfd, 0x05, 0x00, 0x3e, 0x11, 0xd3, 0xe1, 0xb3, 0x29, 0x9d, 0xc9, 0x52, 0x1f, - 0x8b, 0x51, 0x3b, 0xad, 0xb0, 0x10, 0xe9, 0x1b, 0xfe, 0xb9, 0x1b, 0x0b, 0x2a, 0x6c, - 0xb1, 0x29, 0xc2, 0xe8, 0x25, 0xa5, 0x97, 0xb8, 0xfb, 0x75, 0xbc, 0x56, 0x2d, 0x65, - 0x4d, 0x62, 0x10, 0x46, 0x40, 0xdd, 0x74, 0xe5, 0x6c, 0xd1, 0x4b, 0xaa, 0xba, 0x56, - 0x5b, 0x84, 0xb8, 0x45, 0xe1, 0x63, 0xd1, 0xca, 0xef, 0x25, 0x33, 0xc3, 0x98, 0x16, - 0x37, 0x20, 0x4f, 0x96, 0xa5, 0x9c, 0x8e, 0x80, 0x24, 0xd9, 0x04, 0x1b, 0x20, 0x29, - 0xe9, 0x4c, 0x15, 0x24, 0x5f, 0x1a, 0x95, 0x88, 0x40, 0xba, 0x3f, 0x38, 0x0a, 0x4d, - 0x20, 0xf1, 0x18, 0x4e, 0x77, 0x82, 0x7d, 0xe3, 0xff, 0x8f, 0x3d, 0x73, 0x45, 0x9a, - 0xfe, 0x24, 0x1f, 0x72, 0x3c, 0x08, 0x48, 0x23, 0x23, 0x0e, 0x00, 0x3d, 0x3d, 0x21, - 0xe5, 0x35, 0x01, 0xec, 0x04, 0x99, 0xb0, 0x83, 0xa7, 0xda, 0xd6, 0x85, 0xc5, 0x71, - 0x27, 0xf4, 0xde, 0x64, 0x73, 0x3a, 0x88, 0x0c, 0x2d, 0xb2, 0x8f, 0xda, 0xab, 0xf1, - 0xb5, 0x42, 0xd2, 0x05, 0xf6, 0x64, 0xa3, 0x51, 0x35, 0x71, 0x27, 0x11, 0xdc, 0xcc, - 0xd9, 0x31, 0xa5, 0x0b, 0x9c, 0x56, 0x61, 0x88, 0x23, 0x60, 0xd4, 0xca, 0xc0, 0x04, - 0x76, 0x81, 0xbc, 0x2e, 0x2b, 0x3b, 0xf6, 0xc9, 0x97, 0x60, 0xd7, 0xcf, 0xb4, 0xfa, - 0x21, 0x39, 0x43, 0x77, 0xa4, 0x55, 0x1c, 0x76, 0xd1, 0xf7, 0x5a, 0xc0, 0x3c, 0x26, - 0x20, 0x54, 0xdf, 0xfd, 0x79, 0xa9, 0xde, 0xd0, 0x5e, 0x88, 0x89, 0x58, 0x19, 0x9e, - 0xea, 0x45, 0x01, 0xe2, 0x99, 0x0a, 0x53, 0xa5, 0xcd, 0x2a, 0x46, 0xa4, 0x01, 0x57, - 0x65, 0x88, 0xfd, 0x7d, 0x05, 0x8a, 0x26, 0xf2, 0x84, 0x38, 0xe5, 0x78, 0x2f, 0x45, - 0xac, 0x1d, 0x07, 0xf6, 0xf6, 0xf5, 0xed, 0x73, 0x74, 0x1d, 0x57, 0x85, 0x83, 0x7a, - 0x6b, 0x84, 0x4b, 0x47, 0x47, 0x75, 0x71, 0x8c, 0x29, 0xdd, 0x99, 0x08, 0x4e, 0x9f, - 0x88, 0xef, 0x15, 0x3a, 0x83, 0x29, 0xf5, 0x32, 0xa6, 0x90, 0x17, 0xdc, 0x3a, 0x97, - 0xed, 0x75, 0x43, 0x67, 0x72, 0x30, 0x98, 0xe5, 0x76, 0x58, 0x40, 0xb0, 0x22, 0x89, - 0x72, 0x44, 0x74, 0x5f, 0xbb, 0xbb, 0x30, 0xa7, 0xcb, 0x54, 0xfa, 0x05, 0x11, 0x16, - 0x6e, 0x95, 0x44, 0x12, 0x20, 0x00, 0x61, 0x0b, 0xd2, 0xaa, 0xcb, 0xd8, 0x23, 0x25, - 0xa5, 0x9b, 0x95, 0x15, 0x4e, 0xcd, 0x82, 0xc8, 0x8d, 0x23, 0xab, 0xd1, 0xe2, 0x07, - 0x70, 0xff, 0xb8, 0xaa, 0xbf, 0x83, 0xfc, 0x07, 0x34, 0x96, 0x4c, 0xcd, 0x41, 0x1d, - 0x1c, 0x93, 0x57, 0x14, 0xe2, 0x4a, 0xab, 0x56, 0x6f, 0x4f, 0x08, 0x42, 0x40, 0x14, - 0xc4, 0xec, 0xa9, 0x1b, 0x59, 0x0f, 0x08, 0x2b, 0x47, 0x3f, 0x36, 0x1c, 0x87, 0x41, - 0x5d, 0x37, 0xbd, 0x20, 0xd7, 0x0f, 0xd0, 0xb5, 0x2b, 0x6d, 0xdf, 0x18, 0x65, 0xf7, - 0x66, 0x70, 0x2e, 0x32, 0xb0, 0x5b, 0x3c, 0xf1, 0x63, 0x0e, 0xe8, 0x59, 0x7a, 0xae, - 0x19, 0x63, 0x3f, 0x35, 0x16, 0xa8, 0x55, 0x5a, 0xc5, 0xbe, 0x32, 0xc6, 0x75, 0xbe, - 0x18, 0x17, 0xef, 0xbf, 0xfd, 0x93, 0x69, 0x04, 0x1a, 0x08, 0x9c, 0x28, 0x3f, 0x19, - 0x64, 0x99, 0x68, 0xc2, 0x49, 0x8c, 0xde, 0x56, 0xf5, 0x00, 0x43, 0x4f, 0x28, 0x0d, - 0x77, 0xa9, 0xc6, 0x2e, 0x43, 0xcb, 0xd3, 0xf1, 0x36, 0xa4, 0xc6, 0xa0, 0x0a, 0x43, - 0xe6, 0xed, 0x53, 0x0c, 0xb2, 0xe8, 0xae, 0x83, 0x88, 0x60, 0xad, 0xc8, 0x8a, 0xac, - 0xc7, 0xbd, 0x6a, 0x00, 0xae, 0x0c, 0x19, 0xff, 0x45, 0x33, 0xa4, 0x85, 0xef, 0xde, - 0x08, 0x2b, 0x5f, 0x4d, 0x1f, 0x7a, 0x8e, 0xbe, 0x7e, 0xd8, 0x2b, 0x7b, 0x05, 0xa8, - 0xcf, 0xe1, 0xe3, 0x73, 0x45, 0x9f, 0x1b, 0xdc, 0xbf, 0x95, 0x25, 0x74, 0x7e, 0x8c, - 0x95, 0x08, 0xa5, 0x55, 0xfa, 0xcb, 0x79, 0x87, 0x40, 0xe0, 0xbd, 0xf9, 0x94, 0xd9, - 0x73, 0x9b, 0xbe, 0x55, 0x38, 0xa0, 0xae, 0x0f, 0x07, 0x6c, 0x58, 0x2c, 0x0f, 0x5b, - 0xa8, 0x78, 0xb9, 0x9b, 0x82, 0x49, 0xdb, 0x1d, 0x7e, 0x95, 0x05, 0x6c, 0x98, 0xaf, - 0x08, 0x3d, 0x98, 0xcb, 0x0e, 0xd9, 0xe3, 0xf7, 0x43, 0x6e, 0x1c, 0x76, 0x43, 0x76, - 0x6f, 0x96, 0x6b, 0x83, 0xe9, 0x99, 0x20, 0x6e, 0xbd, 0x13, 0x93, 0xb9, 0xb2, 0xa7, - 0xf4, 0x14, 0x48, 0x0f, 0xa0, 0x17, 0x48, 0x00, 0x69, 0xf8, 0x5c, 0x77, 0x49, 0xc4, - 0x35, 0xae, 0x2f, 0xba, 0x2d, 0xdc, 0x10, 0x38, 0xd5, 0x47, 0xd8, 0x48, 0x54, 0x81, - 0x7e, 0xf3, 0x96, 0x35, 0xc2, 0x98, 0x27, 0xaa, 0xd8, 0x67, 0x26, 0xc9, 0xad, 0xe3, - 0xb2, 0x65, 0xb9, 0x08, 0x6c, 0x8b, 0x5b, 0x75, 0xef, 0x56, 0xfe, 0x4b, 0xd8, 0xb4, - 0xd6, 0x28, 0x93, 0x89, 0x5b, 0x3f, 0xd2, 0x73, 0x4f, 0xda, 0xc4, 0x64, 0x15, 0x6d, - 0x7e, 0x5e, 0xbc, 0x7e, 0xcf, 0x1d, 0x83, 0xb8, 0x6f, 0x65, 0x96, 0x37, 0xe3, 0xb1, - 0x42, 0xc1, 0x64, 0x96, 0x3b, 0x8c, 0xdc, 0xf4, 0xba, 0x4f, 0x40, 0x35, 0xdf, 0xfc, - 0x5a, 0x78, 0x94, 0x58, 0x84, 0x77, 0x81, 0x91, 0x8a, 0xc7, 0x2f, 0xc1, 0x8b, 0xbb, - 0xf5, 0x11, 0x00, 0x32, 0xe6, 0x6d, 0x75, 0xb3, 0x17, 0x1e, 0xf4, 0xb5, 0x13, 0x29, - 0x01, 0x64, 0xa7, 0x7b, 0x42, 0xb0, 0xa4, 0xcf, 0xb8, 0x96, 0x39, 0xab, 0x23, 0x84, - 0x5e, 0x1a, 0xa2, 0xa4, 0x52, 0xf3, 0x73, 0x1c, 0x8c, 0xb6, 0x50, 0x82, 0xa6, 0x22, - 0xa7, 0xc2, 0xe0, 0x01, 0x3e, 0xa4, 0x7d, 0x0b, 0xdd, 0x42, 0xd6, 0x99, 0x04, 0x66, - 0x64, 0x9a, 0x90, 0x5c, 0x68, 0x4c, 0x32, 0x51, 0x71, 0x6d, 0x61, 0xf7, 0x60, 0xd5, - 0x3d, 0xe6, 0xe3, 0xf7, 0x90, 0xfb, 0xa7, 0xf5, 0xf1, 0xf4, 0xde, 0x26, 0x71, 0x13, - 0xbd, 0xfc, 0xd7, 0x42, 0x28, 0x22, 0x33, 0x0b, 0x32, 0xd5, 0x8e, 0x67, 0x77, 0x76, - 0x5f, 0x22, 0xa4, 0x11, 0x63, 0x44, 0xee, 0xb6, 0x5b, 0x2e, 0xc5, 0x16, 0x39, 0x3a, - 0xb3, 0x75, 0x1b, 0x53, 0x56, 0xd2, 0xb0, 0xc9, 0x50, 0x0c, 0x0f, 0x3e, 0x46, 0x91, - 0x81, 0x03, 0x5b, 0xc3, 0x66, 0x0f, 0x0b, 0x8f, 0x9f, 0xbe, 0x6e, 0x40, 0xb5, 0xe8, - 0x9c, 0xb7, 0x9b, 0x06, 0x37, 0x14, 0xca, 0x75, 0xe7, 0x2e, 0x2e, 0x10, 0x0a, 0x10, - 0xd6, 0x3b, 0xf7, 0x84, 0xdf, 0x08, 0x20, 0xef, 0x25, 0xf8, 0xef, 0x40, 0xfe, 0x5f, - 0x05, 0xfb, 0x95, 0x68, 0x3f, 0x91, 0x05, 0xff, 0x3c, 0xb2, 0xd2, 0x19, 0xab, 0x76, - 0x60, 0x5a, 0x06, 0x4f, 0x69, 0x21, 0x9f, 0x1d, 0xc0, 0xd0, 0x0b, 0x3b, 0x48, 0x64, - 0x2f, 0x97, 0x0d, 0xc0, 0x0c, 0xca, 0x4b, 0x8b, 0x43, 0x30, 0x8b, 0xe1, 0x82, 0x86, - 0xec, 0x5a, 0x42, 0x88, 0xd6, 0x00, 0xa3, 0x78, 0x5c, 0xb6, 0x22, 0xd4, 0x68, 0xa4, - 0xc6, 0x96, 0x9b, 0x37, 0x92, 0xf2, 0x48, 0x50, 0x27, 0xd0, 0xad, 0x9a, 0xa4, 0xa9, - 0xc2, 0xcc, 0x97, 0x2f, 0x9e, 0xe5, 0x19, 0x0a, 0x95, 0xb1, 0xeb, 0x05, 0x8d, 0xdd, - 0xd8, 0xc0, 0x8e, 0x7d, 0x75, 0x3f, 0x5e, 0x01, 0x1b, 0x2b, 0xcf, 0xee, 0x1d, 0x52, - 0xc1, 0xc4, 0xf2, 0xca, 0xcd, 0xa3, 0x0b, 0xdb, 0x69, 0x30, 0x65, 0x3c, 0x0c, 0xc4, - 0x48, 0x6e, 0x60, 0xe8, 0x9f, 0xa8, 0x49, 0xb3, - ], - script_code: vec![0x53, 0x52], - transparent_input: Some(0), - hash_type: 3, - amount: 1437866676382615, - consensus_branch_id: 1537743641, - sighash: [ - 0xd8, 0xe9, 0xb9, 0x72, 0xb2, 0x89, 0x8e, 0xfc, 0xca, 0x8e, 0x96, 0xbc, 0x98, 0x70, - 0x00, 0x8c, 0xdb, 0xc1, 0x9d, 0x45, 0xb7, 0x8d, 0x09, 0xef, 0xb1, 0x02, 0xf2, 0xd7, - 0x0d, 0xba, 0x01, 0xad, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x01, 0x87, 0xda, 0xa7, 0x31, 0xf5, - 0x70, 0xa7, 0xa4, 0x06, 0x0a, 0xf0, 0xce, 0x70, 0x0d, 0x31, 0xbc, 0xa7, 0xe7, 0x4b, - 0x3e, 0x3b, 0xa3, 0xd0, 0xe8, 0xa6, 0x39, 0x2a, 0x06, 0x2b, 0x8e, 0x86, 0xd9, 0xd7, - 0xd0, 0x0b, 0x21, 0x02, 0x65, 0x53, 0x06, 0x2e, 0x06, 0xb1, 0x01, 0x30, 0x11, 0xff, - 0x08, 0xf0, 0x83, 0x05, 0x00, 0x09, 0x63, 0x6a, 0x52, 0x63, 0x51, 0x63, 0x00, 0x6a, - 0xac, 0x9a, 0xbc, 0xef, 0x2a, 0x99, 0x08, 0x73, 0x19, 0x00, - ], - script_code: vec![0x63], - transparent_input: None, - hash_type: 1, - amount: 1993227025071196, - consensus_branch_id: 1537743641, - sighash: [ - 0x2b, 0x62, 0xff, 0x0c, 0x8d, 0xec, 0x4d, 0xf1, 0x8b, 0x99, 0x56, 0x61, 0x5b, 0x57, - 0x4d, 0xda, 0x39, 0x42, 0xfe, 0x45, 0x2d, 0x91, 0x78, 0xb0, 0xbb, 0xb2, 0xea, 0xee, - 0x4d, 0xe4, 0x4a, 0x8c, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x7c, 0x82, 0x97, 0x7c, 0x0f, - 0xf7, 0x97, 0x09, 0x3e, 0x2c, 0x1f, 0x3a, 0xe8, 0x55, 0xf6, 0x5a, 0xea, 0x91, 0xe1, - 0x31, 0x2f, 0xc6, 0xb8, 0xa4, 0x35, 0x1a, 0x2e, 0xc0, 0x3e, 0x02, 0xe5, 0xd0, 0x2f, - 0x53, 0x35, 0x4b, 0x05, 0x6a, 0x53, 0x52, 0x63, 0x6a, 0x82, 0xcd, 0x1f, 0x55, 0xeb, - 0xca, 0x57, 0xb6, 0x33, 0x7c, 0x85, 0x93, 0x8a, 0x79, 0x81, 0x3d, 0x20, 0x21, 0xd6, - 0x09, 0x4c, 0x68, 0xb3, 0x75, 0xe9, 0x84, 0xf6, 0x83, 0x93, 0x30, 0x08, 0x71, 0xe3, - 0x48, 0xfc, 0x52, 0x36, 0xcc, 0xa6, 0x33, 0x05, 0xac, 0x63, 0x65, 0x51, 0x63, 0x41, - 0x87, 0x01, 0xff, 0x01, 0x86, 0xd2, 0x6f, 0xee, 0x28, 0xca, 0x06, 0x00, 0x01, 0xac, - 0x5a, 0xa7, 0x27, 0xab, 0x79, 0x85, 0xda, 0x0e, 0x00, - ], - script_code: vec![0x65, 0x53, 0x51], - transparent_input: Some(1), - hash_type: 130, - amount: 449567650863240, - consensus_branch_id: 1537743641, - sighash: [ - 0x49, 0x3d, 0x49, 0xc3, 0xe2, 0x22, 0x5d, 0x11, 0xc4, 0x64, 0x05, 0x18, 0x20, 0x14, - 0x76, 0x25, 0xf3, 0x90, 0x9f, 0xa7, 0x18, 0x9f, 0x61, 0xc7, 0xea, 0xec, 0xfc, 0x6d, - 0xad, 0x2e, 0x82, 0x03, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x00, 0x02, 0xe9, 0x6a, 0xa7, 0x3c, - 0xd9, 0xd1, 0x04, 0x00, 0x02, 0x00, 0x53, 0x06, 0xf6, 0x99, 0xe0, 0xb1, 0x9a, 0x04, - 0x00, 0x06, 0xac, 0x65, 0x65, 0x51, 0xac, 0x51, 0x0e, 0x68, 0xae, 0x38, 0x75, 0x05, - 0x51, 0x13, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x92, 0xf1, 0x35, 0xbf, 0x5f, 0x68, 0x78, 0x7d, - 0x37, 0x0c, 0xa8, 0xc4, 0xc4, 0x07, 0x4d, 0xc5, 0xd6, 0x01, 0xae, 0x90, 0x49, 0x54, - 0x37, 0xc3, 0xc2, 0xd4, 0x8a, 0x3d, 0x96, 0x66, 0x83, 0xac, 0x05, 0x16, 0x0b, 0x7a, - 0x84, 0xea, 0xa7, 0xaa, 0xb7, 0x40, 0x09, 0xe5, 0x7a, 0x85, 0xf7, 0xbf, 0x68, 0xa2, - 0xe4, 0x82, 0x00, 0x0f, 0x82, 0x9c, 0x54, 0x50, 0x73, 0xa1, 0x5d, 0x5c, 0xd0, 0xfc, - 0xc5, 0x74, 0x39, 0xa4, 0x35, 0x0e, 0xaf, 0x09, 0x8d, 0xfb, 0x82, 0xa0, 0x85, 0xea, - 0x8a, 0x4a, 0xf6, 0xfa, 0x83, 0x81, 0xf0, 0x65, 0x88, 0x19, 0xea, 0xb4, 0x83, 0xf6, - 0x5b, 0x32, 0x5d, 0x5a, 0xed, 0xa1, 0x52, 0x32, 0xcf, 0xad, 0xec, 0x75, 0xab, 0x18, - 0x66, 0xe4, 0xc0, 0x15, 0x5a, 0x9c, 0x74, 0xa7, 0xa5, 0x7c, 0xcf, 0x34, 0xc4, 0x83, - 0xac, 0x7d, 0xa1, 0x58, 0x8a, 0x1b, 0x6b, 0x99, 0x41, 0xf1, 0x10, 0x40, 0xf9, 0x4c, - 0xf7, 0x8f, 0xad, 0x89, 0xbf, 0x11, 0xfe, 0xd6, 0x9a, 0xa0, 0xd8, 0x31, 0x05, 0xad, - 0xac, 0xdd, 0x4e, 0x5f, 0x04, 0xa6, 0x24, 0x24, 0x02, 0x3c, 0x9b, 0x9e, 0x33, 0xc4, - 0xfb, 0x7f, 0x12, 0xbd, 0xf2, 0x1f, 0x07, 0xf2, 0x65, 0xc5, 0x37, 0xd5, 0x1c, 0x65, - 0x51, 0xf4, 0x61, 0x7b, 0x91, 0x5d, 0x21, 0x99, 0x18, 0x39, 0xc3, 0xd0, 0xd3, 0x63, - 0x93, 0xd6, 0x46, 0xe0, 0xa8, 0xa4, 0x15, 0x09, 0x21, 0x7d, 0x0e, 0x7d, 0x2c, 0xa1, - 0xa0, 0xa0, 0xd6, 0x77, 0xa3, 0xea, 0xca, 0x23, 0xed, 0xeb, 0x07, 0xb7, 0x4e, 0x65, - 0x2a, 0x0b, 0xc5, 0x0c, 0x6c, 0x08, 0x3a, 0x55, 0xd6, 0xc7, 0x30, 0x6e, 0x74, 0x08, - 0x6f, 0x47, 0x68, 0x93, 0x3a, 0xa2, 0x48, 0x73, 0x68, 0x18, 0x67, 0xa7, 0x89, 0x3d, - 0x77, 0xcb, 0x7f, 0x29, 0xb8, 0xc8, 0x47, 0xc5, 0x83, 0xf2, 0xd0, 0x71, 0xa6, 0x86, - 0x61, 0x6e, 0x20, 0x67, 0x19, 0xf7, 0x61, 0xae, 0x39, 0xc1, 0x10, 0x44, 0x2e, 0x06, - 0x16, 0x3d, 0x2b, 0x84, 0x59, 0x03, 0x60, 0x69, 0x5d, 0x4e, 0x19, 0x84, 0x9e, 0x03, - 0x4f, 0x24, 0xd9, 0xad, 0x39, 0x6c, 0x19, 0xff, 0x83, 0xce, 0x74, 0xf4, 0x6e, 0x64, - 0x5f, 0x93, 0x2e, 0x14, 0x1a, 0x41, 0x19, 0x59, 0x36, 0xc8, 0x5d, 0x51, 0x44, 0x14, - 0xf1, 0x12, 0xe6, 0x0b, 0x02, 0x25, 0x37, 0xc3, 0x8d, 0x6d, 0xc6, 0xc4, 0x63, 0x83, - 0x05, 0xc9, 0xbd, 0x6c, 0x62, 0xe3, 0x66, 0xbc, 0x63, 0x12, 0x3e, 0x3e, 0x6d, 0xd3, - 0x6e, 0xed, 0xd3, 0x13, 0x6f, 0xce, 0x8d, 0xee, 0xca, 0x0a, 0xa0, 0x9a, 0x32, 0x98, - 0xa3, 0x9d, 0x83, 0x85, 0x9e, 0xfc, 0x9b, 0x2b, 0x69, 0xcf, 0x9a, 0x7d, 0xee, 0x08, - 0xa9, 0x8e, 0x4b, 0xe5, 0x58, 0xac, 0x79, 0x12, 0xfd, 0xcb, 0x42, 0x20, 0x90, 0x75, - 0x42, 0x02, 0x60, 0xf7, 0xca, 0xd0, 0xf2, 0xc0, 0x1f, 0x2a, 0xfe, 0x33, 0x07, 0x3f, - 0x26, 0x24, 0x9d, 0x94, 0x4f, 0x7a, 0x50, 0xdd, 0x84, 0x83, 0x9b, 0xc3, 0xea, 0x7f, - 0xde, 0xe4, 0xed, 0x71, 0x02, 0x9c, 0xf0, 0x75, 0x33, 0xd2, 0x6e, 0x1e, 0x27, 0xa3, - 0xef, 0xb0, 0x32, 0xc3, 0xa3, 0xb3, 0x4b, 0xd3, 0x09, 0x26, 0x22, 0xd2, 0x06, 0x2a, - 0xe5, 0x36, 0xef, 0x51, 0x49, 0xc4, 0x9b, 0x5b, 0xc9, 0x03, 0x5e, 0xaf, 0xab, 0x6e, - 0x67, 0x57, 0x61, 0x00, 0x8b, 0x0d, 0xad, 0xde, 0xec, 0xaa, 0x60, 0x44, 0x70, 0xbb, - 0xe0, 0xfa, 0xda, 0x25, 0x5d, 0x29, 0x0e, 0x92, 0xb1, 0x90, 0xc2, 0xc2, 0xd8, 0xc2, - 0x02, 0xe5, 0x45, 0x5d, 0x1f, 0xa9, 0xa9, 0xf3, 0xdb, 0x77, 0x79, 0xb5, 0x84, 0x64, - 0x34, 0x64, 0xaa, 0x80, 0x14, 0xba, 0x66, 0x99, 0x4d, 0xe2, 0x55, 0x17, 0xf8, 0x39, - 0x80, 0xe6, 0x6e, 0xe4, 0xf6, 0x03, 0x14, 0xae, 0x6d, 0xbe, 0xf4, 0x52, 0xd5, 0xd3, - 0x8b, 0x0a, 0x16, 0xf3, 0x99, 0x1f, 0x36, 0xd8, 0xa8, 0xb3, 0x9d, 0xdc, 0x0d, 0x55, - 0x95, 0xee, 0xd9, 0x87, 0x62, 0x87, 0x8c, 0xdf, 0x3f, 0x4a, 0x02, 0xdc, 0x5c, 0xda, - 0x77, 0xd5, 0xfe, 0x4f, 0xaf, 0x63, 0xa1, 0x5f, 0x56, 0x8a, 0x54, 0x0d, 0xa5, 0x7d, - 0xd9, 0xbe, 0xb6, 0xfb, 0x1a, 0x97, 0x7c, 0xcb, 0x91, 0xb4, 0xd7, 0x9c, 0xb3, 0x9b, - 0x28, 0x91, 0x1a, 0x29, 0xe7, 0xbf, 0x02, 0x8a, 0xc6, 0x10, 0x37, 0x96, 0xdf, 0xb6, - 0xb2, 0x09, 0x67, 0x23, 0x9a, 0xd3, 0x73, 0xc3, 0x8c, 0x53, 0xf6, 0xdf, 0x18, 0x23, - 0xd4, 0x95, 0x0a, 0x02, 0x83, 0xe9, 0x9b, 0x9c, 0x06, 0xab, 0x29, 0x66, 0x66, 0x7c, - 0x9d, 0xf6, 0x77, 0x71, 0x6b, 0x0c, 0xad, 0xed, 0x81, 0x8d, 0xf9, 0xe4, 0x49, 0xc0, - 0x72, 0xe2, 0x2f, 0x9d, 0x98, 0xbb, 0x0f, 0x9b, 0x03, 0xbd, 0x5f, 0xd0, 0x13, 0xfc, - 0xef, 0x3e, 0xd6, 0xa4, 0x9a, 0xeb, 0x98, 0x72, 0x02, 0x54, 0x08, 0x7e, 0xf7, 0x28, - 0xe3, 0x19, 0x47, 0xff, 0xe8, 0xf7, 0x66, 0xe6, 0x3e, 0xe4, 0x6f, 0xf2, 0x08, 0x16, - 0xd5, 0xfa, 0x8f, 0xf5, 0x5a, 0x26, 0x39, 0x89, 0x61, 0x49, 0x0a, 0xb9, 0xae, 0x36, - 0x6f, 0xc5, 0xa2, 0xd1, 0x99, 0x6e, 0xd6, 0x93, 0xcc, 0xca, 0x82, 0x35, 0x6f, 0x60, - 0x0a, 0xb0, 0x99, 0xf6, 0xec, 0xa8, 0xbf, 0xe6, 0x45, 0x27, 0x0d, 0x3f, 0x95, 0xed, - 0xba, 0x5b, 0x0d, 0xe7, 0xa3, 0x28, 0x19, 0x23, 0x3b, 0xcc, 0x75, 0x4a, 0x5c, 0xe2, - 0xe5, 0xea, 0x07, 0x84, 0x2e, 0x5f, 0xf2, 0xce, 0xbe, 0x62, 0xad, 0x76, 0xe8, 0xef, - 0xf8, 0xd1, 0x5e, 0xa4, 0xc2, 0x4a, 0x5f, 0x20, 0x78, 0x68, 0x31, 0x9a, 0x5a, 0xf6, - 0xb0, 0x35, 0xbe, 0x3f, 0x44, 0xf4, 0x34, 0x09, 0x4f, 0x6e, 0x52, 0x5b, 0xe6, 0x14, - 0xda, 0xc9, 0x20, 0xa3, 0x30, 0xbd, 0xfb, 0x26, 0xd7, 0x5f, 0xe7, 0xb4, 0xb3, 0x65, - 0xd0, 0x94, 0x45, 0x92, 0x50, 0xaa, 0xa5, 0x54, 0x44, 0x89, 0xfb, 0x1d, 0x99, 0x25, - 0x81, 0x80, 0x0a, 0x77, 0xb8, 0x91, 0x21, 0x57, 0xfc, 0x97, 0x13, 0xaa, 0xac, 0x25, - 0xb4, 0xc2, 0x6e, 0xb0, 0x3f, 0x71, 0x66, 0x46, 0x61, 0x9a, 0xf0, 0x24, 0x56, 0xae, - 0x69, 0x59, 0x62, 0xfe, 0x5e, 0x93, 0x1a, 0x63, 0xb5, 0xc7, 0x90, 0x52, 0xec, 0xd3, - 0x33, 0xe1, 0x84, 0x12, 0xdb, 0x91, 0xe1, 0x5f, 0x7c, 0xbc, 0x70, 0xb4, 0xcd, 0x7e, - 0x8e, 0x3c, 0x95, 0x1f, 0x35, 0x85, 0x72, 0xe3, 0x77, 0x67, 0xe7, 0xd5, 0x27, 0x04, - 0xa6, 0x72, 0x1b, 0x30, 0xef, 0xc4, 0x10, 0x17, 0xae, 0x4d, 0x23, 0x15, 0x58, 0xc5, - 0xc8, 0x2c, 0xc7, 0xdd, 0x7e, 0x33, 0x56, 0xc0, 0x9d, 0xc2, 0x49, 0x06, 0xf0, 0x43, - 0x8d, 0xfc, 0xc3, 0x00, 0x85, 0x6a, 0xc2, 0xce, 0xd8, 0xf7, 0x7f, 0xa8, 0x01, 0x57, - 0x36, 0xc6, 0x61, 0xe8, 0x02, 0x48, 0xae, 0xeb, 0x77, 0x48, 0x74, 0xaa, 0x79, 0xd2, - 0x90, 0xb8, 0xf5, 0x02, 0x7a, 0x0a, 0x50, 0x95, 0x37, 0xfc, 0x7c, 0x68, 0x9b, 0x7a, - 0xd8, 0x61, 0x16, 0xcf, 0xec, 0x26, 0x47, 0xcc, 0xaa, 0xe1, 0xc7, 0x4b, 0x41, 0x6f, - 0x3e, 0x6a, 0xe8, 0xf7, 0xcc, 0x60, 0xea, 0xaf, 0x7b, 0x6a, 0x59, 0x0d, 0x51, 0x54, - 0x41, 0x38, 0xe1, 0x73, 0x29, 0x45, 0x60, 0x3a, 0x53, 0x46, 0x2c, 0x60, 0xe1, 0xf6, - 0xcb, 0x0c, 0x9c, 0xa0, 0x39, 0x0c, 0x48, 0x82, 0x24, 0xc3, 0x13, 0x26, 0x9f, 0xcd, - 0x59, 0xfc, 0xb6, 0x11, 0xfb, 0x2d, 0x9b, 0x4c, 0x8f, 0xa6, 0x01, 0xbb, 0x1c, 0xb8, - 0xd0, 0x7d, 0x79, 0x7b, 0xf5, 0xde, 0x52, 0xbc, 0xee, 0xb0, 0x23, 0x01, 0xc8, 0x96, - 0x2a, 0xc1, 0xfc, 0x04, 0x91, 0xdc, 0x81, 0xaf, 0xfd, 0x6c, 0x1e, 0xbf, 0x89, 0xa1, - 0x3d, 0x6f, 0x29, 0x0e, 0xda, 0x5d, 0x5c, 0xef, 0x38, 0x22, 0x15, 0xc5, 0xe9, 0x51, - 0xd7, 0x13, 0x05, 0xef, 0x33, 0xd9, 0x73, 0x71, 0x26, 0xd0, 0xe6, 0x62, 0x90, 0x5f, - 0x12, 0x50, 0x92, 0x6f, 0x6a, 0x22, 0x99, 0x90, 0xe3, 0x8f, 0x69, 0xad, 0x9a, 0x91, - 0x92, 0xb3, 0x02, 0xf2, 0x6b, 0xdd, 0xa4, 0x65, 0xd9, 0x0b, 0x94, 0xb1, 0x2c, 0x57, - 0xfa, 0x3f, 0xd6, 0x93, 0x00, 0x83, 0xf1, 0x84, 0x43, 0x8d, 0x8a, 0x88, 0x9d, 0x3f, - 0x5e, 0xce, 0xa2, 0xc6, 0xd2, 0x3d, 0x67, 0x36, 0xf2, 0xa0, 0xf1, 0x8e, 0x26, 0xf4, - 0xfa, 0x45, 0xd1, 0xbe, 0x8f, 0x3d, 0xc4, 0xa7, 0x07, 0x13, 0x7e, 0x95, 0xd2, 0xad, - 0x59, 0x4f, 0x6c, 0x03, 0xd2, 0x49, 0x23, 0x06, 0x7a, 0xe4, 0x7f, 0xd6, 0x42, 0x5e, - 0xfb, 0x9c, 0x1d, 0x50, 0x4e, 0x6f, 0xd5, 0x57, 0x53, 0x40, 0x94, 0x56, 0x01, 0xfe, - 0x80, 0x6f, 0x57, 0x56, 0xac, 0xb5, 0x62, 0xf1, 0x3c, 0x0c, 0xa1, 0xd8, 0x03, 0xa1, - 0x95, 0xc2, 0xeb, 0xb2, 0xef, 0x02, 0xac, 0x33, 0xe6, 0xa8, 0x8d, 0xea, 0x07, 0x5b, - 0xa9, 0x96, 0xd3, 0xc3, 0x36, 0x64, 0x8e, 0x86, 0x94, 0xd3, 0xa1, 0x9d, 0x3d, 0xca, - 0x53, 0x1b, 0xeb, 0x50, 0xd4, 0x32, 0x7c, 0x5c, 0x0c, 0x23, 0xcb, 0x7c, 0xfd, 0xb0, - 0x8c, 0xa7, 0xcf, 0x2c, 0xac, 0x6b, 0xc1, 0x39, 0xd0, 0x74, 0x14, 0x73, 0xd3, 0x76, - 0x02, 0x9c, 0xb4, 0xab, 0x6b, 0xf0, 0x54, 0x55, 0x7c, 0xe2, 0x94, 0xc7, 0x28, 0xa4, - 0x68, 0x7d, 0x57, 0xec, 0x89, 0x09, 0xff, 0x51, 0xa4, 0xd0, 0x2f, 0x9d, 0xcd, 0x11, - 0x19, 0x3d, 0x7d, 0x1c, 0x9f, 0xda, 0xe6, 0xa1, 0x73, 0x96, 0xa1, 0xbf, 0x57, 0xa9, - 0x94, 0x93, 0x4f, 0x5e, 0x7a, 0x59, 0xf0, 0x45, 0xde, 0xbe, 0xaf, 0xf6, 0x2e, 0xf3, - 0x26, 0xb9, 0x47, 0xf2, 0xa8, 0xb4, 0x95, 0x55, 0xe4, 0xd9, 0x9b, 0x3b, 0xf5, 0xc8, - 0x1f, 0xf9, 0xfe, 0x31, 0x4e, 0x04, 0x7a, 0xf1, 0x52, 0x50, 0x8f, 0x57, 0x01, 0x5c, - 0xa4, 0x02, 0xc6, 0x7d, 0x92, 0x5c, 0x99, 0xac, 0xea, 0x3e, 0xe8, 0xcc, 0x4b, 0x00, - 0x8c, 0x5c, 0xb4, 0x39, 0x66, 0xe7, 0x14, 0xef, 0x48, 0x0f, 0xd0, 0x5e, 0x07, 0xc7, - 0xb2, 0xdd, 0xa9, 0xaa, 0x39, 0x66, 0x11, 0x3e, 0xaa, 0x29, 0x3d, 0x3f, 0x62, 0x2b, - 0x30, 0x9d, 0x64, 0x80, 0x3c, 0xe1, 0xe6, 0x37, 0x8b, 0x6a, 0xac, 0x4f, 0xab, 0x52, - 0x7c, 0x43, 0xcd, 0x45, 0xed, 0x0a, 0x3c, 0x1a, 0x4b, 0x9f, 0xb1, 0x8d, 0xcc, 0xcf, - 0xcd, 0xb6, 0xac, 0x0c, 0x24, 0x21, 0x63, 0x9c, 0xda, 0x00, 0x75, 0xa2, 0x0d, 0xc5, - 0x11, 0x1b, 0x8d, 0x3d, 0x31, 0x99, 0x49, 0x5b, 0xd9, 0x13, 0x3d, 0xba, 0xb9, 0x45, - 0x41, 0x41, 0x0e, 0x4f, 0xba, 0x92, 0xc7, 0xb6, 0x06, 0xa5, 0xcb, 0x12, 0x2f, 0x14, - 0x0c, 0xf1, 0xa3, 0x59, 0x6f, 0x27, 0x88, 0xf3, 0xc8, 0xb9, 0x26, 0x60, 0xf1, 0x4c, - 0xb6, 0x5a, 0xf5, 0xdd, 0x23, 0xdf, 0xdb, 0xac, 0x13, 0x71, 0xec, 0xf4, 0xb3, 0x37, - 0x12, 0xfe, 0xd2, 0x29, 0x2c, 0x44, 0xf7, 0x08, 0x34, 0xcf, 0x96, 0xc0, 0x5d, 0x58, - 0x82, 0x7e, 0x69, 0xbf, 0xc2, 0xe6, 0x96, 0xfa, 0x08, 0x74, 0x86, 0x9c, 0x02, 0xf3, - 0xdc, 0xa1, 0x1c, 0x3b, 0x90, 0xcb, 0x21, 0x4e, 0x68, 0xbc, 0x1c, 0xae, 0x03, 0x9d, - 0x7a, 0x14, 0x6c, 0xdc, 0x1d, 0x60, 0x9d, 0x7a, 0x6b, 0x3f, 0xd5, 0xd4, 0x61, 0xb0, - 0x95, 0x1c, 0x82, 0xcf, 0xb3, 0xe7, 0x63, 0xfa, 0xd2, 0xd1, 0xbc, 0x76, 0x78, 0xcd, - 0xf8, 0x27, 0x79, 0xf8, 0xfd, 0x5a, 0x1c, 0xe2, 0x2a, 0x8d, 0x3c, 0x45, 0x47, 0xab, - 0xd9, 0x59, 0x83, 0x8a, 0x46, 0xfb, 0x80, 0xaf, 0xe0, 0x1f, 0x8e, 0xcc, 0x99, 0x31, - 0x51, 0x3b, 0x19, 0x62, 0xec, 0x54, 0x08, 0x56, 0xcb, 0x18, 0x93, 0x87, 0xcf, 0xbf, - 0xcc, 0x0f, 0x7c, 0x68, 0x22, 0x3c, 0xba, 0x47, 0xfb, 0x0c, 0x9b, 0x48, 0x6e, 0x4d, - 0x99, 0x17, 0x19, 0x41, 0xf7, 0x67, 0x5a, 0x8b, 0x46, 0x32, 0x8a, 0x3b, 0xc1, 0x09, - 0xbf, 0x07, 0xc6, 0x6d, 0x5e, 0xde, 0x77, 0x1c, 0xc4, 0xc7, 0x4c, 0xe8, 0x03, 0x33, - 0x82, 0x91, 0x91, 0xee, 0xdc, 0x49, 0x35, 0x08, 0xa6, 0x44, 0x53, 0x0a, 0x61, 0x44, - 0xf2, 0x2d, 0xcf, 0x97, 0x52, 0x5a, 0x4c, 0xdc, 0xa1, 0xad, 0x71, 0x07, 0x3b, 0x08, - 0x0b, 0x73, 0xea, 0x45, 0x49, 0xf5, 0x40, 0x1b, 0xff, 0x43, 0x18, 0x26, 0x8e, 0x6a, - 0xd6, 0x37, 0x36, 0x31, 0x57, 0xa1, 0x9a, 0x53, 0xf1, 0x23, 0xa0, 0xb0, 0xe1, 0x6d, - 0x0b, 0x77, 0xf0, 0x20, 0x28, 0xda, 0x46, 0x41, 0x00, 0xfd, 0xe7, 0x6d, 0x83, 0xdd, - 0x0b, 0xb2, 0x24, 0xf7, 0xb5, 0x7a, 0x00, 0xc0, 0x2f, 0x68, 0xae, 0x64, 0x8f, 0xdc, - 0x52, 0x99, 0x57, 0xa1, 0x04, 0x90, 0xdc, 0xe1, 0xfd, 0xdb, 0xb0, 0x90, 0x4f, 0x0d, - 0x51, 0x8b, 0xb3, 0x87, 0x54, 0x40, 0x19, 0x98, 0x3b, 0x61, 0x69, 0x75, 0xa7, 0x8e, - 0x74, 0xd8, 0x54, 0xfd, 0xdc, 0x49, 0xb2, 0x55, 0x16, 0x7b, 0x55, 0xef, 0x4b, 0xee, - 0x46, 0x56, 0x68, 0xb2, 0x0e, 0xa4, 0x11, 0x8c, 0xa5, 0x69, 0xae, 0x48, 0x0e, 0x0f, - 0x6e, 0x5e, 0x04, 0x3a, 0x35, 0x7b, 0x36, 0xd3, 0xab, 0x36, 0xc8, 0x61, 0xf2, 0x27, - 0x83, 0x01, 0xdc, 0xe5, 0x76, 0x74, 0xd5, 0x07, 0x3b, 0x3a, 0x6f, 0x51, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xa0, 0x79, 0x3a, 0xf1, 0xb7, 0xd4, 0x6f, 0x95, 0x7e, 0x22, 0xd8, 0xd2, 0x58, - 0x3b, 0xf1, 0x81, 0x83, 0x6c, 0x3b, 0xe9, 0x93, 0x0b, 0xac, 0x8f, 0xa4, 0x60, 0xe9, - 0x68, 0xaa, 0x71, 0x09, 0x87, 0x0b, 0xbe, 0xd1, 0x7d, 0xf5, 0xf8, 0x88, 0xc8, 0xca, - 0x14, 0x67, 0xae, 0x17, 0xdb, 0xbc, 0xde, 0x31, 0xc1, 0x10, 0x5c, 0xb5, 0xbd, 0xa8, - 0x8a, 0xc6, 0xc6, 0x27, 0x00, 0x2c, 0xe2, 0x1c, 0x02, 0x14, 0x0f, 0xfe, 0x81, 0xec, - 0x58, 0xbf, 0x1e, 0x6d, 0x1b, 0xb7, 0xaa, 0xad, 0xa4, 0x1f, 0xba, 0x0b, 0xb5, 0x88, - 0x77, 0x8a, 0x7f, 0x65, 0x20, 0x2a, 0xd8, 0x11, 0xea, 0x73, 0xd2, 0x6c, 0x74, 0x55, - 0x03, 0x95, 0xaf, 0xf7, 0x53, 0x25, 0x10, 0x7c, 0x9b, 0x3f, 0x9a, 0xe9, 0xdc, 0xdc, - 0xd8, 0x6e, 0xd0, 0x81, 0xa2, 0xe7, 0x42, 0x47, 0x19, 0xa3, 0xd1, 0x85, 0xb7, 0xe0, - 0xa4, 0x3a, 0x47, 0x2e, 0x29, 0x8a, 0xc0, 0xaf, 0xdc, 0x52, 0x87, 0xd7, 0xad, 0x12, - 0x4c, 0xd9, 0x40, 0x5a, 0x62, 0xcd, 0x1c, 0xa0, 0x8b, 0x28, 0x2e, 0xfe, 0xf7, 0xf9, - 0x28, 0xdf, 0x76, 0xe2, 0x82, 0x1a, 0x41, 0x84, 0x13, 0xeb, 0x7c, 0xea, 0xa5, 0xff, - 0x12, 0x90, 0xb0, 0x3e, 0xc9, 0x1c, 0xe6, 0xdd, 0x28, 0x13, 0x0c, 0x3a, 0xb0, 0xb2, - 0x3b, 0x60, 0x2b, 0xd5, 0xbe, 0x5d, 0xc2, 0x60, 0x03, 0xaa, 0xe0, 0x4b, 0x33, 0xd7, - 0xbd, 0x25, 0x90, 0xe9, 0x0c, 0x8c, 0x38, 0x8e, 0xa7, 0x95, 0x51, 0x22, 0xdb, 0xac, - 0xa6, 0x7b, 0x30, 0x39, 0x5a, 0x92, 0x8b, 0x57, 0xb8, 0x57, 0x51, 0x23, 0x20, 0x5a, - 0xe1, 0x91, 0x52, 0xe4, 0x1e, 0x00, 0x29, 0x31, 0xb4, 0x57, 0x46, 0x19, 0x8e, 0x5d, - 0xd9, 0x57, 0x1a, 0x56, 0xa7, 0xe0, 0xd4, 0x23, 0xff, 0x27, 0x98, 0x9d, 0x3e, 0xb4, - 0x17, 0xec, 0xd3, 0xc3, 0x09, 0x3f, 0xb8, 0x2c, 0x56, 0x58, 0xe2, 0x96, 0x24, 0xc5, - 0x32, 0x19, 0xa6, 0x0c, 0xd0, 0xa8, 0xc4, 0xda, 0x36, 0x7e, 0x29, 0xa7, 0x17, 0x79, - 0xa7, 0x30, 0x32, 0x98, 0x5a, 0x3d, 0x1f, 0xd0, 0x3d, 0x02, 0xd0, 0x6e, 0x05, 0x56, - 0x6f, 0x3b, 0x84, 0x36, 0x7c, 0xf0, 0xfa, 0xee, 0x9b, 0xc3, 0xbd, 0x7a, 0x3a, 0x60, - 0x6a, 0x9f, 0xdb, 0x84, 0x9c, 0x5d, 0x82, 0xd0, 0xa6, 0x19, 0x23, 0xc2, 0xe5, 0xd8, - 0x02, 0x63, 0xa8, 0xa5, 0x0c, 0x38, 0xbd, 0x03, 0x87, 0x72, 0xc4, 0x14, 0x3d, 0x8b, - 0x7a, 0xcf, 0xd7, 0x4e, 0x72, 0xc0, 0x4d, 0x89, 0x24, 0x8d, 0xff, 0x20, 0xfe, 0x8d, - 0xc5, 0xec, 0x21, 0x49, 0x05, 0x0a, 0xa2, 0x41, 0x64, 0xe8, 0x5f, 0x67, 0x44, 0xad, - 0x0c, 0xac, 0xf1, 0xa8, 0xb7, 0x01, 0x26, 0xf4, 0x82, 0xc0, 0x92, 0xed, 0x9f, 0x61, - 0x27, 0xd2, 0x05, 0x0d, 0x12, 0xe8, 0x78, 0xa7, 0x96, 0x53, 0xa1, 0xe8, 0x4d, 0xae, - 0xc3, 0xeb, 0xe6, 0x2d, 0x5f, 0x6c, 0x4a, 0xbe, 0x5c, 0xe9, 0x0a, 0x7f, 0xe2, 0xe5, - 0x2a, 0x8d, 0x78, 0x46, 0xe8, 0xed, 0xf2, 0xf2, 0xbc, 0xe0, 0x5a, 0x03, 0x7c, 0x82, - 0x03, 0x22, 0xca, 0xad, 0x12, 0x61, 0x46, 0x7d, 0xcf, 0xb7, 0xd6, 0xb6, 0x13, 0x3d, - 0xc2, 0x1e, 0x80, 0x96, 0xc7, 0xe9, 0xf8, 0xe9, 0xe1, 0x0c, 0x1e, 0x3f, 0xac, 0x40, - 0x58, 0xb6, 0x82, 0xc6, 0x8e, 0x02, 0xfa, 0xca, 0xe0, 0xf9, 0xc2, 0xdd, 0x4d, 0x64, - 0xd9, 0x04, 0x61, 0x52, 0xb4, 0x76, 0x23, 0x32, 0x93, 0x9f, 0x17, 0xe6, 0xaa, 0xf7, - 0xd8, 0xb9, 0xd3, 0x58, 0xe2, 0x21, 0x8d, 0x4e, 0x0d, 0x69, 0x02, 0xf1, 0x19, 0xe1, - 0xc6, 0x4e, 0xec, 0x4c, 0x8b, 0x53, 0x28, 0x09, 0x70, 0x71, 0x31, 0xf0, 0x1f, 0x55, - 0xc7, 0xad, 0x04, 0xcf, 0xb6, 0x3f, 0x7c, 0x4a, 0x3d, 0x0a, 0x2b, 0x0f, 0xfb, 0x0b, - 0x05, 0x02, 0xbe, 0x05, 0x5b, 0x8c, 0x94, 0xca, 0x80, 0xbb, 0x0a, 0x1d, 0x13, 0xcd, - 0x4c, 0xd6, 0x9a, 0xb9, 0x83, 0x04, 0xae, 0x25, 0x15, 0xd5, 0xf7, 0x69, 0x9d, 0x4a, - 0xbe, 0xe5, 0xc2, 0x0b, 0xe6, 0x09, 0x02, 0x73, 0x51, 0x10, 0x12, 0xf2, 0x34, 0xbd, - 0x85, 0xa7, 0xef, 0xf5, 0xfb, 0x63, 0x4c, 0xff, 0x26, 0x58, 0xba, 0x65, 0x16, 0x04, - 0x85, 0x63, 0x09, 0x5e, 0xce, 0xfb, 0x30, 0x15, 0xee, 0x3f, 0x03, 0xca, 0x52, 0xa1, - 0x77, 0xf2, 0x61, 0xec, 0xdc, 0x26, 0xbc, 0x08, 0x9d, 0x34, 0xc6, 0x40, 0x48, 0x46, - 0xe9, 0xc6, 0x47, 0xfc, 0xfe, 0x98, 0xcc, 0x6a, 0xcd, 0xbb, 0x46, 0x4f, 0x64, 0x27, - 0x8a, 0xd8, 0xce, 0x9d, 0x1a, 0xe0, 0xd4, 0x15, 0xbc, 0x0c, 0x05, 0x24, 0x5f, 0xdd, - 0xaf, 0x4e, 0xbc, 0x8d, 0xc7, 0x03, 0xa8, 0x5c, 0xb2, 0x70, 0xf7, 0x96, 0xad, 0x2d, - 0x93, 0x7e, 0x2a, 0xc0, 0xd5, 0xe0, 0xa3, 0x48, 0x21, 0x75, 0x80, 0x00, 0xaa, 0x59, - 0xc9, 0xd4, 0x65, 0x24, 0x85, 0x29, 0x4e, 0xe0, 0xab, 0x29, 0x69, 0x6b, 0x21, 0x43, - 0x0f, 0xa5, 0x4d, 0xcf, 0xbf, 0x2b, 0x9c, 0x49, 0xd1, 0x42, 0x06, 0x42, 0x09, 0xee, - 0xee, 0xd4, 0xd4, 0x71, 0xff, 0xc0, 0x17, 0xd4, 0xe2, 0x0a, 0x79, 0x6b, 0x09, 0x27, - 0x80, 0x4c, 0x06, 0x1b, 0x9f, 0x4a, 0x70, 0x91, 0xfe, 0x01, 0x5a, 0xda, 0x68, 0xfd, - 0x84, 0x42, 0xe0, 0x18, 0x25, 0xc8, 0x8d, 0xfe, 0x55, 0xcf, 0x5d, 0xe3, 0x89, 0x36, - 0xf7, 0xce, 0x25, 0x31, 0x1b, 0x90, 0x2b, 0xa9, 0x7a, 0x3c, 0x12, 0xa9, 0x5c, 0xfa, - 0x1c, 0x3a, 0x59, 0x1b, 0x81, 0x8f, 0x60, 0x83, 0x27, 0x09, 0xd9, 0xe4, 0x83, 0x9e, - 0x41, 0x0f, 0xb3, 0x6b, 0x84, 0xf3, 0xac, 0x4f, 0x07, 0x0f, 0xc3, 0x5e, 0x16, 0x19, - 0x78, 0x25, 0x9e, 0x5b, 0x8e, 0xdc, 0x74, 0x4d, 0x90, 0x91, 0x9a, 0xa7, 0x70, 0xbb, - 0x36, 0x21, 0x51, 0x28, 0xe5, 0x82, 0xb5, 0x96, 0x41, 0xe2, 0x38, 0x52, 0xe9, 0x58, - 0xeb, 0x8f, 0xc3, 0xc0, 0xaa, 0x96, 0x15, 0x2b, 0xa4, 0xf7, 0x7f, 0x13, 0x8d, 0x6a, - 0x67, 0x12, 0xa3, 0xae, 0x32, 0x26, 0x01, 0x58, 0x83, 0xf8, 0x1d, 0xb2, 0x3e, 0x58, - 0x3c, 0x86, 0x9c, 0x4c, 0x71, 0x14, 0x3a, 0x6f, 0xff, 0xd6, 0x5e, 0x8d, 0xfd, 0xc5, - 0x0c, 0x99, 0xa2, 0xf1, 0xf3, 0x14, 0xcd, 0xcc, 0x71, 0x35, 0x9e, 0x23, 0x5f, 0x1d, - 0x7d, 0xc2, 0xb5, 0xf3, 0x8e, 0xf7, 0xb9, 0x70, 0x84, 0x31, 0x63, 0xc0, 0x3f, 0x9d, - 0xd4, 0x0a, 0x80, 0x15, 0xef, 0xdc, 0x87, 0x91, 0x95, 0x6a, 0x3f, 0x3c, 0xed, 0xd9, - 0xea, 0x64, 0xf8, 0xef, 0xa7, 0xa0, 0x81, 0x5a, 0x70, 0x38, 0x1d, 0x71, 0x46, 0x78, - 0x17, 0xbd, 0x04, 0xca, 0x52, 0x9a, 0xed, 0xe0, 0x7f, 0xf6, 0x0d, 0x17, 0x6a, 0xed, - 0x0f, 0x85, 0x5a, 0x2e, 0xae, 0xa8, 0x9e, 0xae, 0xac, 0xa8, 0x93, 0x58, 0xc0, 0x81, - 0x82, 0x6a, 0x08, 0x12, 0xa5, 0xbc, 0xa2, 0x8b, 0xe1, 0x37, 0x3f, 0x08, 0x6d, 0xbd, - 0xba, 0x7e, 0x43, 0xe2, 0x03, 0x21, 0x2c, 0x9f, 0xed, 0x21, 0x47, 0x4b, 0xa1, 0x9a, - 0x05, 0x5f, 0xfc, 0xc1, 0x79, 0x41, 0x2e, 0x89, 0x3a, 0x74, 0x48, 0x32, 0x29, 0x8c, - 0x5f, 0xe2, 0x4c, 0xc6, 0xb1, 0x86, 0x67, 0xf4, 0x9b, 0x34, 0xdf, 0xb1, 0x23, 0x79, - 0x26, 0x74, 0x19, 0xa9, 0xcb, 0x94, 0x03, 0xd8, 0x16, 0x7d, 0x8d, 0x1e, 0x91, 0xd2, - 0x81, 0x1a, 0x04, 0x3b, 0x29, 0x24, 0x3b, 0x06, 0x9b, 0x37, 0x58, 0x78, 0x47, 0xdc, - 0x6f, 0xcd, 0xdb, 0x18, 0x31, 0xbd, 0x1c, 0xc2, 0x56, 0x7c, 0xa0, 0x33, 0xac, 0x40, - 0xf7, 0x4a, 0xb6, 0x95, 0x5f, 0x68, 0x3b, 0x12, 0xe4, 0xe8, 0x25, 0x4e, 0x4e, 0xa7, - 0x60, 0xd3, 0x8b, 0x3f, 0x46, 0x79, 0x1c, 0x5c, 0x4c, 0xb1, 0x2b, 0xc7, 0xcc, 0xb0, - 0xed, 0x18, 0x65, 0xf2, 0x5d, 0x60, 0x1c, 0x30, 0x3f, 0x81, 0xfb, 0x1f, 0xa1, 0xdb, - 0x48, 0x53, 0x3d, 0x3d, 0x6b, 0x28, 0x8e, 0x4d, 0x9a, 0x4d, 0xff, 0x8e, 0xc2, 0x1c, - 0x96, 0xf5, 0x78, 0x39, 0x97, 0x10, 0xc8, 0x25, 0xfe, 0x7e, 0x32, 0xf9, 0x3a, 0x8c, - 0x07, 0x43, 0xf9, 0xeb, 0xd5, 0x4c, 0xc1, 0x51, 0xc7, 0x61, 0x03, 0x37, 0xae, 0xbf, - 0x7e, 0x9b, 0x91, 0x57, 0x20, 0xa5, 0x43, 0x51, 0xd4, 0x9a, 0xb8, 0xc2, 0x2f, 0xa3, - 0x49, 0x98, 0xdc, 0xf5, 0x83, 0xd4, 0x38, 0x73, 0x61, 0xef, 0x3f, 0xf8, 0x6f, 0x50, - 0xec, 0x53, 0xf4, 0x92, 0x49, 0xe4, 0xad, 0x34, 0x96, 0x03, 0x06, 0x6f, 0xc9, 0xc6, - 0x61, 0xd6, 0x9f, 0x91, 0x1d, 0xfa, 0x72, 0x41, 0xc8, 0xd5, 0x79, 0x2d, 0x43, 0xc4, - 0x57, 0xd5, 0xde, 0x96, 0x52, 0x3a, 0x53, 0xd6, 0x67, 0xec, 0x5c, 0x4e, 0xf9, 0xd5, - 0x02, 0xa1, 0x6f, 0x15, 0x22, 0x47, 0x58, 0x96, 0xd7, 0x9b, 0xc5, 0x78, 0x33, 0xe9, - 0x77, 0x17, 0x1c, 0x32, 0x4d, 0xce, 0x2a, 0x1e, 0xa1, 0xe4, 0x30, 0x4f, 0x49, 0xe4, - 0x3a, 0xe0, 0x65, 0xe3, 0xfb, 0x19, 0x6f, 0x76, 0xd9, 0xb8, 0x79, 0xc7, 0x20, 0x08, - 0x62, 0xea, 0xd1, 0x8d, 0xea, 0x5f, 0xb6, 0xa1, 0x7a, 0xce, 0xa3, 0x33, 0x86, 0xeb, - 0x4c, 0xa1, 0xb5, 0x14, 0x86, 0xa9, 0x14, 0x8f, 0xbd, 0xf9, 0xa9, 0x53, 0x32, 0xaa, - 0x60, 0x5c, 0x5d, 0x54, 0x83, 0xce, 0x4b, 0xa8, 0xec, 0xe0, 0x1a, 0x8f, 0xf2, 0xb7, - 0xef, 0x82, 0xd0, 0x5c, 0x0b, 0x6e, 0x86, 0x1b, 0x91, 0x5f, 0x13, 0xca, 0x0e, 0xb3, - 0xea, 0x13, 0xd5, 0x07, 0x08, 0x07, 0xa2, 0xcb, 0x66, 0x80, 0xa2, 0x49, 0xea, 0x9c, - 0x72, 0x24, 0x39, 0x2c, 0xbc, 0x8a, 0xb8, 0x25, 0x01, 0xb2, 0x6f, 0x11, 0x2a, 0xc7, - 0x89, 0xa1, 0x2a, 0x31, 0xad, 0x13, 0x14, 0xe2, 0xed, 0xe0, 0x8f, 0xad, 0x31, 0x43, - 0xaf, 0x30, 0xc2, 0x7f, 0x40, 0x3b, 0xc8, 0x66, 0xc7, 0x55, 0x17, 0x78, 0x52, 0xaf, - 0xd0, 0xab, 0xb9, 0x0a, 0xde, 0x1d, 0x68, 0x27, 0x26, 0xf4, 0x20, 0x08, 0xb4, 0x6a, - 0xd7, 0xf8, 0xab, 0xdb, 0x18, 0x11, 0x7f, 0x72, 0x64, 0x13, 0x90, 0xf0, 0x86, 0xb6, - 0xe1, 0x49, 0x8b, 0xe6, 0x95, 0x48, 0x52, 0x7e, 0x6a, 0xda, 0x2b, 0x38, 0xb9, 0xfe, - 0x12, 0x1e, 0xf6, 0x70, 0xaf, 0x74, 0x37, 0xd3, 0x25, 0x36, 0xd5, 0xcf, 0x5c, 0x4a, - 0xb1, 0x9d, 0xd9, 0x97, 0x71, 0x58, 0x2d, 0x03, 0x81, 0x04, 0xb7, 0xe0, 0x39, 0xa3, - 0x76, 0xf7, 0xac, 0xbb, 0xea, 0xdb, 0x34, 0xf9, 0x45, 0xbe, 0xb9, 0xd7, 0xca, 0x0e, - 0x4e, 0x3d, 0x5c, 0x5e, 0x4e, 0xb1, 0xd8, 0x52, 0x6e, 0xbd, 0x13, 0xda, 0xcb, 0x1b, - 0xa3, 0x57, 0x35, 0xc6, 0xd0, 0x4a, 0x45, 0x55, 0xac, 0xf4, 0xbf, 0x11, 0x76, 0x26, - 0x50, 0x0d, 0x77, 0xb3, 0x81, 0x89, 0xdd, 0x48, 0x88, 0x04, 0x12, 0x25, 0xac, 0xbe, - 0x38, 0x74, 0xa4, 0xc0, 0xf6, 0x07, 0xfe, 0x67, 0x45, 0xf9, 0x35, 0x5b, 0x3f, 0xa1, - 0x88, 0xf1, 0xd6, 0x5c, 0x09, 0xf3, 0x89, 0xaf, 0x1b, 0x9d, 0x62, 0x32, 0xaa, 0x79, - 0x44, 0x79, 0x19, 0xc5, 0x50, 0xf6, 0xf3, 0x1f, 0xec, 0x35, 0x48, 0x1c, 0xb9, 0x22, - 0xde, 0x2d, 0xb5, 0xb4, 0xda, 0x2f, 0x81, 0x94, 0x86, 0x17, 0x02, 0x8e, 0x32, 0x17, - 0x06, 0xa3, 0xa7, 0x78, 0xc1, 0x93, 0x8c, 0x44, 0x3b, 0xb0, 0x0e, 0x5b, 0x0f, 0xf0, - 0x6a, 0xd8, 0xab, 0x9b, 0x1a, 0xb0, 0xc1, 0x14, 0x77, 0x67, 0x3f, 0x85, 0xdf, 0x95, - 0x61, 0xdb, 0xea, 0x45, 0xd5, 0xf9, 0x78, 0x1e, 0xbe, 0x31, 0x7a, 0x07, 0x10, 0xae, - 0x54, 0x61, 0xe3, 0x4f, 0xe6, 0xf1, 0xb1, 0xaa, 0x9b, 0x4e, 0x67, 0xb1, 0x49, 0x10, - 0x98, 0x48, 0x02, 0xc2, 0xa7, 0xe3, 0x81, 0x93, 0xbc, 0x7b, 0xdc, 0x8b, 0xa3, 0xe4, - 0xe3, 0xd1, 0xd9, 0x33, 0xbf, 0xb5, 0x80, 0xf5, 0xb3, 0xe8, 0x7a, 0x2a, 0x06, 0x51, - 0x70, 0x51, 0x41, 0x0f, 0xe1, 0xb4, 0xff, 0x1e, 0xa0, 0xad, 0xe8, 0x24, 0xf3, 0x38, - 0x51, 0x54, 0x56, 0xa5, 0x7c, 0x7a, 0x91, 0x6a, 0x74, 0x38, 0x8e, 0xe8, 0xf1, 0x28, - 0x1f, 0x9a, 0xde, 0x0a, 0xe2, 0xa2, 0x61, 0x3a, 0x06, 0x12, 0xc4, 0x69, 0xdf, 0x79, - 0x2b, 0x8d, 0xf4, 0xca, 0xe4, 0xfc, 0x25, 0xc1, 0xca, 0xdb, 0xa9, 0x5a, 0x80, 0x7c, - 0xe6, 0x1e, 0x5a, 0x53, 0x03, 0xfa, 0xaf, 0x9e, 0x14, 0x65, 0x39, 0x96, 0xb5, 0xa8, - 0xad, 0xc3, 0x4f, 0xd4, 0x75, 0xef, 0x14, 0x99, 0x09, 0x4b, 0xab, 0xaf, 0x1f, 0x3f, - 0x07, 0xda, 0x9a, 0x39, 0x0b, 0x1d, 0x9f, 0xc9, 0xa0, 0x83, 0x27, 0x98, 0x7a, 0xdf, - 0xe9, 0x56, 0x48, 0x63, 0xfb, 0xdf, 0xa8, 0xf6, 0xb4, 0x6a, 0x88, 0x41, 0x58, 0x30, - 0x99, 0xaf, 0xb7, 0x87, 0x01, 0x18, 0xfa, 0xce, 0x76, 0x34, 0x7e, 0x40, 0xb6, 0xfd, - 0x8c, 0xd1, 0x55, 0x82, 0xae, 0x8e, 0x23, 0xbe, 0x9a, 0x02, 0x19, 0xbc, 0x3e, 0x4e, - 0x45, 0x46, 0xa3, 0x0d, 0x3b, 0xbb, 0xbd, 0x16, 0x86, 0x08, 0x68, 0x76, 0xbe, 0x0e, - 0x4c, 0x85, 0x9b, 0xe7, 0x1f, 0xb5, 0x8f, 0x4f, 0xab, 0x3d, 0x28, 0xc0, 0xb4, 0xf7, - 0xe7, 0x5a, 0xd1, 0xed, 0xb7, 0xf8, 0x89, 0x46, 0xfb, 0x40, 0xcf, 0xa5, 0x78, 0x6a, - 0x0f, 0xcb, 0xa1, 0x30, 0x3c, 0x83, 0x47, 0xec, 0xee, 0x93, 0xd4, 0x6d, 0x14, 0x0b, - 0xb5, 0xf6, 0x95, 0x31, 0xd6, 0x66, 0x54, 0x8b, 0x10, 0x9c, 0xe7, 0x64, 0xbe, 0xad, - 0x7c, 0x87, 0xbd, 0x4c, 0x87, 0x64, 0x94, 0xde, 0x82, 0xdb, 0x6e, 0x50, 0x73, 0xa6, - 0xc9, 0x4f, 0x7c, 0x09, 0x9a, 0x40, 0xd7, 0xa3, 0x1c, 0x4a, 0x04, 0xb6, 0x9c, 0x9f, - 0xcc, 0xf3, 0xc7, 0xdd, 0x56, 0xf5, 0x54, 0x47, 0x76, 0xc5, 0x3b, 0x4d, 0xf7, 0x95, - 0x39, 0x81, 0xd5, 0x5a, 0x96, 0xa6, 0xdc, 0xff, 0x99, 0x04, 0xa9, 0x08, 0x42, 0xe5, - 0xba, 0xfe, 0xc8, 0x84, 0x0c, 0x2d, 0x25, 0x5b, 0xf5, 0xad, 0x61, 0xc4, 0x60, 0xf9, - 0x8f, 0xeb, 0x82, 0xa1, 0x0f, 0xa1, 0xc0, - ], - script_code: vec![0x65, 0x6a, 0x65, 0x51, 0x52, 0x65, 0x63], - transparent_input: None, - hash_type: 1, - amount: 1712463999734827, - consensus_branch_id: 1537743641, - sighash: [ - 0xbb, 0x10, 0x30, 0x0e, 0x4d, 0xaf, 0xe3, 0x0c, 0x3f, 0xf0, 0x26, 0x34, 0xd0, 0xe0, - 0x03, 0x2f, 0x17, 0x15, 0xb0, 0x0c, 0xbc, 0x77, 0x3d, 0xf6, 0xb0, 0x9e, 0x00, 0x43, - 0x38, 0x6a, 0x14, 0x18, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x13, 0xe5, 0x6c, 0x77, 0x2f, - 0x2c, 0x3b, 0x86, 0x0e, 0xa5, 0xb0, 0x3a, 0x88, 0x54, 0xbc, 0x6e, 0x65, 0x90, 0xd6, - 0x3c, 0xc0, 0xea, 0x54, 0xf1, 0x0b, 0x73, 0xba, 0x24, 0x1b, 0xf7, 0x4b, 0x63, 0x55, - 0x51, 0xa2, 0xaa, 0x06, 0x65, 0x6a, 0xac, 0x52, 0x51, 0x63, 0x36, 0x8b, 0x26, 0xd7, - 0x0a, 0x73, 0x7f, 0x26, 0x76, 0x85, 0x99, 0x8a, 0x3f, 0x7d, 0x26, 0x37, 0x91, 0x49, - 0x09, 0xc7, 0x46, 0x49, 0x5d, 0x24, 0xc4, 0x98, 0x63, 0x5e, 0xf9, 0x7a, 0xc6, 0x6a, - 0x40, 0x08, 0x94, 0xc0, 0x9f, 0x73, 0x48, 0x8e, 0x07, 0x6a, 0x53, 0x65, 0x52, 0x51, - 0x65, 0x52, 0x05, 0xf9, 0x1a, 0xd7, 0x00, 0x79, 0x65, 0xc2, 0x99, 0x36, 0x1d, 0x60, - 0x0d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7e, 0x89, 0xee, 0x09, 0x62, 0xf5, 0x8c, 0x05, 0x1d, 0x11, - 0xd0, 0x55, 0xfc, 0xe2, 0x04, 0xa5, 0x62, 0xde, 0x68, 0x08, 0x8a, 0x1b, 0x26, 0x48, - 0xb8, 0x17, 0x4c, 0xbc, 0xfc, 0x8b, 0x5b, 0x5c, 0xd0, 0x77, 0x11, 0x5a, 0xfd, 0xe1, - 0x84, 0x05, 0x05, 0x4e, 0x5d, 0xa9, 0xa0, 0x43, 0x10, 0x34, 0x2c, 0x5d, 0x3b, 0x52, - 0x6e, 0x0b, 0x02, 0xc5, 0xca, 0x17, 0x22, 0xba, 0xde, 0xee, 0x23, 0xd1, 0x45, 0xe8, - 0xeb, 0x22, 0x13, 0xfc, 0x4a, 0xf1, 0xe4, 0x50, 0xe4, 0xd5, 0x21, 0x7c, 0x66, 0x17, - 0x00, 0x8c, 0x78, 0xf4, 0xfb, 0x11, 0x12, 0xf4, 0x02, 0x8a, 0x70, 0x4f, 0xc5, 0xa9, - 0x38, 0x2c, 0x6b, 0x03, 0xe7, 0xd8, 0x08, 0x5e, 0x90, 0x6c, 0xf8, 0x4c, 0xa2, 0xc1, - 0x20, 0x7c, 0x87, 0xa2, 0xbc, 0xe2, 0x08, 0x0a, 0x98, 0x91, 0x66, 0x8d, 0x69, 0xb0, - 0x44, 0xbe, 0xce, 0xd6, 0xcd, 0xa3, 0x2c, 0x22, 0x9c, 0x91, 0x17, 0x91, 0x7a, 0xa0, - 0x7d, 0xdf, 0xfc, 0xd3, 0x77, 0x39, 0x5c, 0xba, 0x61, 0x6d, 0x63, 0xc0, 0xb6, 0x9c, - 0x01, 0xfc, 0xc4, 0x53, 0x91, 0xfd, 0x5b, 0x87, 0x63, 0xfb, 0x96, 0xd7, 0xca, 0x33, - 0x3a, 0x12, 0xde, 0x3c, 0xef, 0xa9, 0x1c, 0x6c, 0x98, 0xf9, 0x47, 0x3b, 0x8e, 0x10, - 0x4a, 0x71, 0x29, 0x3e, 0x46, 0x37, 0x47, 0x05, 0xba, 0xf6, 0x5f, 0xa4, 0x13, 0x84, - 0xba, 0x5c, 0x8e, 0x0c, 0x88, 0xa3, 0xeb, 0x07, 0xe0, 0xbe, 0x34, 0xda, 0xdd, 0xfa, - 0xbb, 0x7b, 0x65, 0x54, 0x3b, 0x5f, 0x39, 0xcb, 0x20, 0x23, 0xd4, 0x67, 0x89, 0xeb, - 0x7d, 0x98, 0x9a, 0xf7, 0x79, 0xe5, 0xb8, 0xd2, 0x83, 0x85, 0xa8, 0x5b, 0x0d, 0xa2, - 0xab, 0xe0, 0x7f, 0x0c, 0x2b, 0xb4, 0x25, 0x5f, 0xce, 0xa0, 0x31, 0x88, 0x52, 0x7a, - 0x30, 0x7d, 0x40, 0x91, 0x59, 0xe9, 0x01, 0x66, 0xfa, 0xc6, 0xa0, 0x70, 0xba, 0x05, - 0xb3, 0xe4, 0xdb, 0xfd, 0x3a, 0x2b, 0xfc, 0xc9, 0xee, 0x6e, 0xd0, 0x16, 0xc0, 0xf6, - 0x65, 0xbe, 0x81, 0x33, 0xb7, 0xdc, 0x1d, 0x86, 0x04, 0x4d, 0xb0, 0xf9, 0x03, 0x40, - 0xfb, 0x0e, 0x9f, 0x8b, 0xc2, 0xe4, 0xdb, 0x53, 0x82, 0xa8, 0xb4, 0xf8, 0x15, 0xb4, - 0xe8, 0x43, 0x4a, 0xd0, 0xdf, 0xbc, 0x51, 0xa5, 0xe9, 0xb1, 0x45, 0xe1, 0x59, 0x6c, - 0xbf, 0x46, 0x70, 0x03, 0xe0, 0x5d, 0xfd, 0xaf, 0xbb, 0x0c, 0xf3, 0xdd, 0xee, 0x28, - 0xd7, 0x6a, 0x82, 0x42, 0x8e, 0x8a, 0xba, 0x43, 0x64, 0xe8, 0x4b, 0xac, 0x37, 0x92, - 0x98, 0xdf, 0x29, 0x32, 0xe6, 0x9b, 0xb5, 0xd0, 0x0b, 0x51, 0x6e, 0xfc, 0x33, 0xae, - 0x6c, 0xc3, 0x94, 0x7c, 0xeb, 0x09, 0xed, 0x37, 0x16, 0x67, 0x21, 0x2a, 0x83, 0x1b, - 0x54, 0x85, 0xea, 0xfc, 0xe8, 0x48, 0x81, 0x88, 0xea, 0x4e, 0x27, 0xd0, 0xcd, 0xf7, - 0xdd, 0xd3, 0x48, 0xab, 0xff, 0x77, 0x7f, 0x4a, 0x13, 0xbb, 0xc7, 0x16, 0xb6, 0xa5, - 0x94, 0x4e, 0xe7, 0x27, 0x96, 0x56, 0x90, 0xe2, 0x09, 0xb4, 0x9e, 0xb9, 0x62, 0xc0, - 0x39, 0x97, 0x5f, 0x03, 0x9e, 0xd5, 0xc6, 0xe4, 0xc4, 0x00, 0xd8, 0x87, 0x75, 0x94, - 0x33, 0xd3, 0xad, 0x71, 0x6d, 0xa0, 0xcb, 0x44, 0x61, 0x13, 0xc7, 0x72, 0x7a, 0x64, - 0xb5, 0x8c, 0x3f, 0x8a, 0x0f, 0x81, 0x18, 0x9f, 0x02, 0x00, 0x52, 0x33, 0xa8, 0x13, - 0x66, 0xae, 0xe7, 0x3c, 0xec, 0x85, 0x22, 0x8e, 0xbc, 0xfd, 0x5e, 0xe3, 0xc3, 0xfb, - 0x44, 0xdb, 0x76, 0xba, 0x24, 0x3f, 0x28, 0x42, 0xb7, 0xb5, 0xfc, 0x74, 0x6a, 0x03, - 0x1b, 0x0b, 0xc4, 0xbd, 0x4f, 0xc9, 0xfd, 0x83, 0x35, 0x65, 0xea, 0x85, 0x2b, 0x92, - 0xb2, 0x24, 0xf6, 0x99, 0x03, 0x18, 0xad, 0x8c, 0x7d, 0x94, 0x37, 0xe2, 0x0e, 0x2a, - 0x1f, 0x20, 0xe8, 0x18, 0x03, 0x05, 0x7c, 0x5a, 0xba, 0xaa, 0x2e, 0x5c, 0x15, 0xb9, - 0x49, 0x45, 0xcd, 0x42, 0x4c, 0x28, 0xa5, 0xfa, 0x38, 0x5d, 0xad, 0xfe, 0x49, 0x07, - 0xb2, 0x74, 0xd8, 0x42, 0x70, 0x7d, 0xb3, 0x69, 0x7a, 0x02, 0xe6, 0xc8, 0xf5, 0x42, - 0xe5, 0xec, 0xc0, 0x7f, 0xe4, 0x73, 0x50, 0xd1, 0x01, 0x46, 0x70, 0x21, 0x2e, 0xfe, - 0x81, 0xfb, 0x7c, 0x73, 0xe8, 0x45, 0x0d, 0xf8, 0x14, 0xef, 0x62, 0x32, 0xf7, 0x49, - 0x0f, 0x63, 0xcc, 0xf0, 0x74, 0x80, 0xf8, 0x84, 0xa6, 0x6e, 0xaf, 0xfc, 0x28, 0xfe, - 0xa4, 0x48, 0xd7, 0xb4, 0x01, 0xcd, 0xae, 0x10, 0xe7, 0xc0, 0xc7, 0xf9, 0xa7, 0xb1, - 0x53, 0x31, 0x96, 0x9f, 0xc8, 0xcb, 0x36, 0x39, 0x67, 0x73, 0xde, 0x19, 0x19, 0x31, - 0xc7, 0x50, 0xf6, 0xce, 0x5c, 0xaa, 0xf2, 0x97, 0x68, 0xeb, 0xb2, 0x7d, 0xac, 0xc7, - 0x38, 0x05, 0x6a, 0x81, 0x25, 0xb4, 0x77, 0x2b, 0xf8, 0x7a, 0xe1, 0x0a, 0x8a, 0x30, - 0x9b, 0x9b, 0xd6, 0x55, 0x04, 0x3c, 0xfc, 0x31, 0x59, 0x49, 0x43, 0x68, 0xc5, 0xab, - 0x8c, 0xad, 0xb7, 0xf6, 0x71, 0xe9, 0x62, 0x6b, 0xd2, 0x63, 0xe3, 0x11, 0x81, 0xa6, - 0x04, 0xb5, 0x06, 0xa0, 0x3b, 0x43, 0x9a, 0x7f, 0xfe, 0x43, 0x55, 0x89, 0x24, 0x77, - 0xe2, 0xbd, 0xf3, 0x38, 0xc6, 0x2c, 0x39, 0x22, 0xf7, 0xd3, 0xc9, 0xa5, 0x6c, 0x71, - 0x03, 0xd9, 0x11, 0x94, 0x8a, 0x84, 0xb5, 0xae, 0x2d, 0xbb, 0x16, 0xa3, 0x76, 0x1a, - 0xdd, 0x05, 0x3a, 0x0f, 0x96, 0x7e, 0x6b, 0x5b, 0xc9, 0x42, 0x11, 0xb6, 0x54, 0x71, - 0x53, 0x26, 0x7c, 0x6e, 0xe1, 0xca, 0xd0, 0xd9, 0x74, 0xa7, 0x10, 0x88, 0x58, 0x37, - 0x35, 0xe4, 0xf6, 0x3d, 0x33, 0x15, 0x6d, 0xad, 0xd5, 0x4c, 0x2f, 0xaf, 0x89, 0x11, - 0x4a, 0x12, 0x7b, 0x97, 0xb9, 0x4c, 0xc2, 0xa2, 0x2e, 0xf3, 0x03, 0xf4, 0x59, 0xd0, - 0x4f, 0xc0, 0xb5, 0x3a, 0xce, 0x59, 0x18, 0xd4, 0x7f, 0xf3, 0x3a, 0x55, 0x8b, 0xd7, - 0x1a, 0x75, 0xf3, 0x55, 0xfb, 0xd0, 0x6b, 0xbc, 0xcf, 0x4e, 0x02, 0xc3, 0xc0, 0xa4, - 0xb6, 0x3d, 0x0c, 0xc9, 0x49, 0x80, 0x1d, 0x63, 0xa6, 0x4c, 0xb2, 0xd3, 0x23, 0x73, - 0xb2, 0xc7, 0xb2, 0x74, 0xab, 0x2d, 0xb4, 0x68, 0x21, 0x42, 0xc8, 0xb2, 0x1d, 0x84, - 0xc4, 0x81, 0xf5, 0xef, 0x21, 0xe4, 0xb5, 0xe3, 0x60, 0x34, 0x51, 0xbf, 0x94, 0x77, - 0x4d, 0x0e, 0xf4, 0x7f, 0x63, 0xfa, 0x6a, 0xbb, 0x78, 0xd2, 0x1c, 0x19, 0x3c, 0xbe, - 0x65, 0xb6, 0x95, 0xfe, 0x67, 0x42, 0x3c, 0x1e, 0x2d, 0x31, 0x2e, 0x27, 0x76, 0xfa, - 0x24, 0xec, 0xe8, 0x46, 0x83, 0xe7, 0x48, 0x76, 0xc5, 0x5e, 0xa0, 0x36, 0x9e, 0x4e, - 0xa0, 0xe8, 0x64, 0x94, 0xe0, 0x0d, 0xde, 0x23, 0x6a, 0x16, 0x89, 0x73, 0x1f, 0x0a, - 0x5d, 0x82, 0x03, 0xaf, 0xde, 0x5c, 0x42, 0x36, 0x40, 0xb8, 0x1e, 0x4f, 0x63, 0x1c, - 0x98, 0x1c, 0x11, 0xa2, 0xe1, 0xd1, 0x84, 0xc6, 0x7c, 0x52, 0x8d, 0xf9, 0x2d, 0x53, - 0xae, 0xc4, 0x4a, 0x40, 0xa4, 0xea, 0x2a, 0x13, 0x1b, 0x47, 0x33, 0xcf, 0xe4, 0x5c, - 0x6b, 0x00, 0x12, 0xc3, 0xe9, 0xe2, 0x09, 0x75, 0xba, 0xae, 0xcb, 0x02, 0x32, 0xdf, - 0x88, 0x0b, 0xd7, 0xd1, 0xde, 0x13, 0xe1, 0x34, 0x94, 0x62, 0xec, 0x8d, 0x5d, 0xf3, - 0xe7, 0x80, 0xff, 0xa7, 0x2e, 0xba, 0x8a, 0x8d, 0xf7, 0xfc, 0xf3, 0x98, 0xec, 0x23, - 0x05, 0x13, 0xca, 0x9d, 0x61, 0x23, 0xf8, 0xb9, 0xd8, 0x17, 0x85, 0x60, 0xda, 0xf9, - 0x75, 0x11, 0x19, 0x55, 0xa2, 0xbc, 0xa3, 0x42, 0x3e, 0xee, 0xfc, 0x52, 0x7b, 0xe3, - 0xa8, 0x54, 0x3e, 0xb9, 0x0a, 0x5e, 0xc0, 0x2f, 0x35, 0xa7, 0xc6, 0x4b, 0x7d, 0xd5, - 0x9a, 0x72, 0xda, 0x00, 0x74, 0x63, 0x4e, 0x01, 0xd2, 0xab, 0xf3, 0x63, 0x7a, 0xdd, - 0x77, 0xc7, 0x35, 0x0f, 0x12, 0xb0, 0x11, 0xb2, 0x94, 0x16, 0x8e, 0xc7, 0x55, 0x76, - 0xe4, 0x7d, 0x16, 0x9e, 0x39, 0x38, 0xbf, 0x6a, 0xe2, 0xaa, 0x8f, 0xf7, 0xcf, 0xba, - 0x7c, 0xac, 0xb1, 0xf9, 0x2b, 0x6e, 0x4c, 0x24, 0x97, 0xbf, 0xfa, 0x9f, 0x17, 0xca, - 0xd2, 0x42, 0xfa, 0x9c, 0x31, 0x79, 0xc1, 0xa3, 0xaa, 0x81, 0xf7, 0x36, 0x16, 0x49, - 0x57, 0x2c, 0x71, 0x5c, 0x25, 0xa1, 0xf6, 0xcd, 0x5a, 0xce, 0x82, 0xc0, 0x0a, 0xb2, - 0x34, 0x2b, 0x9c, 0x3c, 0xb4, 0xff, 0xfd, 0xda, 0x16, 0x0c, 0xa5, 0xab, 0x9e, 0x9b, - 0xaf, 0x21, 0x39, 0xef, 0x9a, 0xfb, 0xe1, 0xb1, 0xf3, 0x09, 0x46, 0x2a, 0xfc, 0xe4, - 0x62, 0xa7, 0x9b, 0xb9, 0x69, 0x8e, 0x22, 0xc9, 0x57, 0xc5, 0x90, 0xa7, 0x53, 0xa7, - 0x6b, 0x87, 0xe0, 0x09, 0x12, 0x1e, 0x06, 0xf6, 0xa1, 0xbf, 0x62, 0xa0, 0x8b, 0xf4, - 0x35, 0xd9, 0x2e, 0x2f, 0xff, 0xe8, 0x6e, 0x2a, 0x9c, 0xbb, 0xa9, 0x13, 0x3a, 0x68, - 0xe4, 0xae, 0xbf, 0x33, 0xc3, 0x84, 0x36, 0xf2, 0x54, 0x5f, 0xc2, 0xd5, 0x28, 0x32, - 0xd1, 0x65, 0xaf, 0x41, 0x5b, 0x24, 0x4a, 0xdc, 0x5f, 0x57, 0x37, 0x7d, 0xee, 0xdf, - 0x46, 0x0a, 0xa3, 0xbe, 0xb4, 0x34, 0x19, 0xc6, 0xb0, 0x82, 0xe8, 0x35, 0xce, 0x84, - 0xca, 0x13, 0xb6, 0x90, 0x8a, 0x88, 0x13, 0xc0, 0x21, 0xde, 0x9f, 0xa9, 0xa4, 0x4e, - 0x4c, 0x18, 0xdc, 0xb3, 0xd2, 0x1f, 0xaa, 0xbd, 0xb4, 0x19, 0x31, 0xb2, 0xfd, 0x49, - 0x76, 0x44, 0xdc, 0x3a, 0x15, 0x07, 0xfa, 0x5a, 0xc7, 0xc7, 0x6b, 0xee, 0xbb, 0xdb, - 0xd1, 0xd4, 0x92, 0x99, 0xa5, 0x5b, 0xd4, 0x99, 0x27, 0xe9, 0xd7, 0xf4, 0x88, 0x4e, - 0x6e, 0xd3, 0xfd, 0x5e, 0x4b, 0x7c, 0xb8, 0x35, 0xb8, 0x33, 0x08, 0x96, 0x4e, 0x3c, - 0x46, 0x87, 0x3f, 0xd6, 0x13, 0x31, 0x7b, 0x91, 0xd2, 0x92, 0x36, 0xea, 0x90, 0xe3, - 0x65, 0xd1, 0x62, 0xcc, 0x05, 0x1c, 0x84, 0x6d, 0x24, 0x21, 0x76, 0xda, 0xf6, 0xd2, - 0x86, 0x18, 0xae, 0x31, 0xfb, 0xaa, 0xe9, 0x99, 0xa9, 0x3f, 0x17, 0x5c, 0x69, 0x38, - 0xe6, 0x31, 0xa0, 0x81, 0xf2, 0xc1, 0xf3, 0xfd, 0x78, 0x25, 0x49, 0xd3, 0xf3, 0x24, - 0x57, 0x59, 0x60, 0x6d, 0x9f, 0x92, 0xd5, 0x54, 0x8a, 0xcf, 0xea, 0xdb, 0xaf, 0x9c, - 0xaa, 0x6b, 0x93, 0xdc, 0x08, 0x82, 0x8d, 0x74, 0xf6, 0xd5, 0xfd, 0xd8, 0x33, 0x31, - 0xf0, 0x96, 0x91, 0x45, 0x95, 0x52, 0x97, 0xe6, 0x9f, 0x00, 0xfd, 0x29, 0x87, 0xf2, - 0xda, 0x2b, 0x94, 0xb9, 0x95, 0xfe, 0xcb, 0xe6, 0x22, 0xa7, 0x35, 0xef, 0x7f, 0x12, - 0x07, 0xf6, 0x71, 0x62, 0x94, 0x89, 0x20, 0x2b, 0xea, 0x0b, 0x47, 0x5e, 0x51, 0x68, - 0x1a, 0xa1, 0x67, 0x78, 0xb3, 0x9b, 0xd9, 0x23, 0xc9, 0x8d, 0xc6, 0xff, 0x83, 0x73, - 0xc7, 0x9b, 0xb1, 0x70, 0x30, 0x41, 0x7b, 0xc2, 0x00, 0xc8, 0xf0, 0xb8, 0x55, 0xac, - 0xfe, 0xc1, 0x79, 0xf7, 0x67, 0x4c, 0xec, 0x27, 0x21, 0xa1, 0x0f, 0xca, 0x69, 0x3d, - 0x83, 0xcf, 0xe5, 0xb8, 0xcd, 0xcc, 0x18, 0xf8, 0x1a, 0xd6, 0x17, 0xfa, 0x26, 0xf0, - 0xdf, 0xb8, 0x36, 0x55, 0xb8, 0xa2, 0x9a, 0x7f, 0x83, 0x42, 0x32, 0x42, 0x5e, 0x8c, - 0x47, 0x45, 0x88, 0xf1, 0x8d, 0xd3, 0x26, 0xaa, 0x39, 0x6c, 0x3e, 0x47, 0x75, 0xe0, - 0x02, 0x05, 0xfc, 0x9e, 0x45, 0xf7, 0xb7, 0xd2, 0xe6, 0xd5, 0x5d, 0xcb, 0x90, 0xe2, - 0x3f, 0xf6, 0xb5, 0x08, 0x45, 0x9a, 0xa6, 0x99, 0xbf, 0xcb, 0xd5, 0x6f, 0x10, 0x99, - 0x77, 0x64, 0xd0, 0x87, 0x40, 0x89, 0x86, 0xe7, 0x3d, 0x6e, 0x28, 0x4f, 0xea, 0x9a, - 0x23, 0xc3, 0x93, 0x11, 0x78, 0x2f, 0x86, 0xca, 0xbf, 0xf9, 0x45, 0x5e, 0x4c, 0xf6, - 0x99, 0xe5, 0xf5, 0xd4, 0xbc, 0x0b, 0x39, 0x05, 0xa4, 0xe3, 0xbd, 0x01, 0xc5, 0x4d, - 0xf8, 0x64, 0x34, 0x43, 0xbe, 0x0f, 0x88, 0x90, 0x32, 0xea, 0x32, 0x5b, 0xf0, 0x71, - 0x07, 0xfd, 0x41, 0xd6, 0x73, 0xee, 0xba, 0xe6, 0xfa, 0x63, 0x7b, 0x70, 0xcc, 0x0e, - 0xd3, 0xf0, 0x09, 0x58, 0xdf, 0xb8, 0xdc, 0xf0, 0x0e, 0x85, 0xa1, 0xd0, 0xa6, 0xa8, - 0x90, 0x81, 0x40, 0xc2, 0xf4, 0x34, 0xc2, 0xe2, 0x60, 0xef, 0xb0, 0xbc, 0xa2, 0x00, - 0x35, 0x04, 0xc9, 0x99, 0x93, 0xa9, 0xe1, 0xc0, 0xff, 0x9c, 0xef, 0xe6, 0xa6, 0x65, - 0xd7, 0x91, 0x42, 0x86, 0x90, 0xe4, 0x7e, 0xf8, 0xc1, 0x31, 0xa8, 0xe9, 0xbf, 0xb4, - 0xc3, 0x08, 0x02, 0x35, 0x03, 0x2d, 0x73, 0x1b, 0x0d, 0x38, 0x41, 0x22, 0x5f, 0x1c, - 0x11, 0xe2, 0xc2, 0x8e, 0xe8, 0x4d, 0x35, 0xf9, 0x22, 0x61, 0x00, 0x56, 0x59, 0x72, - 0xeb, 0x26, 0x9d, 0x27, 0x8e, 0xf6, 0x49, 0x79, 0xbf, 0x65, 0x15, 0xed, 0x4a, 0x68, - 0x40, 0xb0, 0x88, 0x3a, 0x9e, 0x6e, 0xf6, 0x4a, 0x0e, 0xfc, 0xae, 0x1c, 0xf2, 0x1d, - 0xfe, 0x74, 0x85, 0x4e, 0x84, 0xc2, 0x74, 0x9f, 0xac, 0x03, 0x82, 0x52, 0x75, 0xc9, - 0xb6, 0x30, 0x21, 0x84, 0xc7, 0x2d, 0xf4, 0xc4, 0xbb, 0x28, 0x62, 0xe4, 0xe8, 0xa7, - 0xd9, 0xa4, 0xa2, 0x82, 0x86, 0x6f, 0x9a, 0x7b, 0x2c, 0xfc, 0x9a, 0x56, 0x31, 0x3d, - 0xa0, 0xc4, 0x7a, 0x34, 0xb7, 0xb9, 0xcd, 0xa3, 0xac, 0xe8, 0x18, 0x5f, 0x07, 0xdf, - 0x36, 0xe4, 0x48, 0xa7, 0x6a, 0xa4, 0x77, 0xf2, 0x24, 0xd8, 0x7a, 0x07, 0x4f, 0x43, - 0xaf, 0x5d, 0x5f, 0x79, 0xb3, 0xab, 0x11, 0x28, 0xf0, 0x81, 0x91, 0x44, 0x7f, 0xa6, - 0x46, 0xbf, 0xdd, 0xe5, 0xb5, 0x1e, 0x23, 0x3c, 0xa6, 0x15, 0x5d, 0x10, 0x15, 0x85, - 0xbc, 0x2c, 0x40, 0x15, 0x8a, 0xc2, 0x10, 0x6e, 0x66, 0xa2, 0x6e, 0x46, 0x42, 0x33, - 0x70, 0x63, 0x68, 0x76, 0xb4, 0x34, 0xa7, 0x4f, 0x8c, 0xe8, 0x06, 0x00, 0x50, 0xb0, - 0x82, 0xa7, 0x9b, 0x61, 0xbb, 0x5d, 0x34, 0x4e, 0xb5, 0xa1, 0x15, 0x83, 0x26, 0xce, - 0xd9, 0xa9, 0xd9, 0xf5, 0x4f, 0xb2, 0xfe, 0x8f, 0x9f, 0x05, 0xcd, 0x11, 0x1e, 0xe4, - 0x6c, 0x47, 0x10, 0xf6, 0xf6, 0x3a, 0x62, 0x69, 0x45, 0x57, - ], - script_code: vec![0x53, 0x52, 0x00], - transparent_input: Some(1), - hash_type: 1, - amount: 1564816348934332, - consensus_branch_id: 1537743641, - sighash: [ - 0x21, 0x46, 0x62, 0xc6, 0x74, 0x50, 0x60, 0x3d, 0x8a, 0xa7, 0x3b, 0xea, 0xbb, 0xf7, - 0x51, 0x8d, 0x03, 0x6c, 0xe9, 0x1d, 0xc8, 0x7b, 0x01, 0x81, 0xe8, 0xa0, 0xf3, 0xfa, - 0x82, 0x2c, 0x7d, 0x8a, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x01, 0x59, 0x07, 0x92, 0x9a, 0x2f, - 0x3f, 0xdb, 0x0d, 0x8f, 0x79, 0x14, 0xc4, 0x2d, 0xde, 0x2d, 0x20, 0x00, 0xf5, 0xae, - 0x02, 0xd4, 0x18, 0x21, 0xc8, 0xe1, 0xee, 0x01, 0x38, 0xeb, 0xcb, 0x72, 0x8d, 0x7c, - 0x6c, 0x3c, 0x80, 0x02, 0x65, 0x53, 0x75, 0x94, 0xc6, 0x70, 0x00, 0x6f, 0x39, 0x08, - 0x22, 0x2e, 0x89, 0xd1, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x27, 0x1a, 0xbe, 0x66, 0x0e, - 0x39, 0xe0, 0x51, 0xaa, 0xa6, 0xfc, 0xa1, 0x86, 0x22, 0x76, 0xe2, 0xba, 0xa0, 0xfe, - 0x0b, 0x16, 0x2a, 0xeb, 0xcf, 0xe3, 0xd9, 0x34, 0x9c, 0x8d, 0x15, 0x4b, 0xb7, 0xee, - 0x28, 0x21, 0x2c, 0x1b, 0xaa, 0x70, 0x5d, 0x82, 0x07, 0x0d, 0x70, 0x32, 0xf2, 0x69, - 0x5d, 0x17, 0x96, 0x80, 0x9f, 0xab, 0x41, 0x24, 0x69, 0x26, 0xaf, 0x99, 0x2b, 0x6e, - 0xee, 0x95, 0xa9, 0xa0, 0x6b, 0xc4, 0x56, 0x2c, 0x5f, 0x2f, 0x1b, 0x19, 0x54, 0x95, - 0x00, 0x37, 0x2e, 0x7a, 0xd5, 0x79, 0xa6, 0xd6, 0xd7, 0x8b, 0x33, 0x15, 0x31, 0x30, - 0xfb, 0x44, 0x8f, 0xb7, 0x9e, 0x8a, 0x66, 0x9d, 0xb8, 0xa0, 0xf3, 0x5c, 0xdf, 0x9a, - 0xe5, 0xd3, 0x2d, 0x73, 0x2f, 0xc7, 0x94, 0x18, 0xe2, 0x3b, 0x45, 0x1d, 0xdc, 0x95, - 0xa2, 0x2a, 0xba, 0xbb, 0x05, 0x6e, 0xc6, 0xb5, 0xe8, 0xba, 0x4f, 0x52, 0x4d, 0xfa, - 0xfe, 0x87, 0x52, 0x62, 0xdd, 0x7b, 0xe4, 0x1c, 0xbb, 0xc6, 0x24, 0x20, 0xd4, 0xad, - 0x6d, 0xf5, 0xc9, 0xb7, 0x13, 0x60, 0x4f, 0x65, 0x60, 0x88, 0xa4, 0x48, 0x5e, 0x93, - 0xbe, 0x19, 0x07, 0xd2, 0x7a, 0xc6, 0xec, 0x3c, 0x57, 0x25, 0x9b, 0xd6, 0x98, 0x1d, - 0x42, 0xc1, 0xb7, 0x8a, 0x29, 0xad, 0x96, 0x85, 0xe6, 0x3c, 0x49, 0x4d, 0x41, 0x29, - 0x62, 0x3e, 0xa1, 0xa7, 0xff, 0xec, 0x85, 0xfa, 0x29, 0x41, 0x10, 0x73, 0xed, 0xb2, - 0x97, 0x8e, 0xf4, 0xe4, 0x69, 0xdd, 0xd5, 0xcd, 0xa9, 0x86, 0x18, 0x99, 0x95, 0xf8, - 0x8d, 0x6a, 0xb3, 0x66, 0xdb, 0x01, 0x90, 0x01, 0xf5, 0xb2, 0x52, 0x88, 0xcf, 0x86, - 0x0f, 0xd9, 0x98, 0xee, 0x57, 0x3c, 0x8c, 0xc4, 0x8a, 0xa9, 0xef, 0xcf, 0x9b, 0x61, - 0x7e, 0x04, 0x3c, 0x32, 0x9c, 0xd1, 0xaa, 0x1a, 0x0e, 0xd3, 0xa4, 0x02, 0xfb, 0x96, - 0xe3, 0x36, 0xc7, 0x19, 0xe6, 0x25, 0x3c, 0xb6, 0x91, 0xaa, 0x0d, 0xb5, 0x27, 0x36, - 0x62, 0x6e, 0xd1, 0x97, 0x88, 0x75, 0x88, 0x8e, 0xc7, 0x6c, 0x84, 0x6b, 0xc2, 0x27, - 0x27, 0x2a, 0x02, 0x53, 0x17, 0xdf, 0xf0, 0xb1, 0x14, 0x8d, 0x92, 0xd6, 0xf5, 0xfb, - 0x7d, 0x95, 0x33, 0x67, 0x70, 0xa7, 0xd1, 0x6f, 0xac, 0x1a, 0xdd, 0x86, 0x07, 0x76, - 0xcb, 0x48, 0x02, 0x21, 0xf8, 0xfb, 0x33, 0x03, 0xe4, 0xe9, 0xb0, 0x79, 0x02, 0xd2, - 0xff, 0x86, 0xfd, 0xac, 0x72, 0x09, 0x62, 0x34, 0xae, 0xd4, 0x8d, 0xe8, 0x92, 0xff, - 0x73, 0x55, 0x07, 0x3b, 0xbf, 0x06, 0x15, 0xf6, 0x7b, 0x11, 0x00, 0xcc, 0x0a, 0xa3, - 0xba, 0x3d, 0x6c, 0x1a, 0x1a, 0x90, 0x87, 0xb1, 0x19, 0xba, 0xee, 0xbf, 0xa6, 0x2b, - 0xc9, 0xf0, 0xec, 0x47, 0x9d, 0x99, 0xc1, 0xa3, 0xb1, 0x58, 0xb5, 0x14, 0xd1, 0x62, - 0x9d, 0xb3, 0x99, 0x3f, 0x11, 0x67, 0x2a, 0x26, 0x70, 0x8e, 0x5a, 0xd8, 0x16, 0xb5, - 0x47, 0xab, 0x7e, 0x82, 0x7d, 0x07, 0x1b, 0xa7, 0x84, 0x2b, 0x3e, 0x90, 0x30, 0x53, - 0x83, 0x89, 0x6e, 0xc4, 0x90, 0x5f, 0x70, 0x03, 0x8b, 0x69, 0x4e, 0x6a, 0x5a, 0x3e, - 0x43, 0x12, 0xcd, 0x82, 0x08, 0x13, 0x2b, 0x84, 0x0f, 0x05, 0xc7, 0x14, 0x52, 0x3c, - 0xa8, 0x19, 0x72, 0x0a, 0xe2, 0x27, 0xfd, 0x1a, 0xcb, 0xa7, 0x14, 0xfa, 0x03, 0xc4, - 0x5f, 0xc5, 0x39, 0x88, 0x57, 0xb4, 0x0d, 0xc1, 0x48, 0x79, 0x85, 0x6f, 0x35, 0x4b, - 0xa4, 0xd2, 0x58, 0x1d, 0x0c, 0xda, 0x54, 0xb6, 0x38, 0xba, 0x9d, 0x76, 0xf9, 0xb5, - 0x2d, 0x17, 0xc8, 0x02, 0x8e, 0xe6, 0x3f, 0x58, 0x45, 0xb5, 0xdc, 0xef, 0xa4, 0xc3, - 0x47, 0x9b, 0xce, 0x9a, 0xca, 0xd1, 0x8b, 0x4a, 0xea, 0xe0, 0x3c, 0x0e, 0xae, 0x22, - 0x5d, 0x42, 0x84, 0x8b, 0xde, 0xaa, 0x53, 0x6d, 0x03, 0x8d, 0xd3, 0xbc, 0x97, 0x9f, - 0x06, 0x58, 0x66, 0x73, 0xbc, 0x6f, 0xf1, 0xc5, 0xd3, 0xb3, 0x20, 0xf3, 0x49, 0xa5, - 0xb3, 0xa8, 0xb3, 0x55, 0x59, 0x22, 0x96, 0xaa, 0xf6, 0x1c, 0x5b, 0x72, 0x52, 0x03, - 0x3e, 0xc0, 0xa9, 0x46, 0x6a, 0x1b, 0x85, 0x76, 0x4f, 0xb0, 0x83, 0x1b, 0x4a, 0x1a, - 0x36, 0x89, 0x0e, 0x22, 0x4c, 0x01, 0xac, 0xfc, 0xe4, 0x8e, 0xe3, 0xed, 0x93, 0x87, - 0x73, 0x98, 0xe0, 0x72, 0x6d, 0x02, 0x93, 0x6d, 0x0d, 0x03, 0x2e, 0x18, 0xe3, 0x28, - 0x8b, 0x26, 0x70, 0xe1, 0x36, 0x2c, 0x32, 0xd6, 0xe4, 0x73, 0x3b, 0x9d, 0xd2, 0xd5, - 0xf2, 0x6e, 0x1f, 0xe3, 0x06, 0xf7, 0x3c, 0x00, 0x7f, 0xdd, 0xca, 0xe9, 0xd9, 0xc0, - 0xaa, 0xf1, 0x87, 0xd7, 0x42, 0x8b, 0x1e, 0x9d, 0x47, 0x9c, 0x18, 0x23, 0x7b, 0x98, - 0x28, 0xbc, 0xa8, 0xb9, 0x8c, 0x9d, 0x9b, 0xec, 0x7d, 0x82, 0x70, 0xb5, 0xd8, 0xee, - 0xc3, 0xcc, 0x4f, 0x43, 0xfa, 0x01, 0x88, 0x52, 0x1b, 0xc6, 0x1b, 0x21, 0xdd, 0x04, - 0xe3, 0x7a, 0x83, 0xec, 0xe6, 0x8c, 0xa7, 0xa2, 0xfa, 0x6c, 0x8f, 0x9e, 0x34, 0xa6, - 0x29, 0x03, 0x35, 0xaa, 0x1f, 0xbd, 0x83, 0xd5, 0x4a, 0xaf, 0x44, 0x1e, 0x31, 0x9e, - 0xa4, 0x7a, 0x86, 0x2a, 0xd0, 0x29, 0x3c, 0xed, 0xf5, 0xdd, 0x9e, 0xda, 0xde, 0xee, - 0x33, 0xcb, 0x52, 0x2c, 0xd0, 0x11, 0x8b, 0xbd, 0x81, 0x1a, 0xce, 0x9a, 0x23, 0xbd, - 0xa3, 0x9a, 0xba, 0x72, 0xf1, 0x56, 0x6f, 0xc1, 0x68, 0x84, 0x97, 0xd2, 0xa7, 0x92, - 0x8c, 0x36, 0x70, 0x15, 0x25, 0x67, 0x8b, 0xc9, 0x72, 0x14, 0xb3, 0x1b, 0x37, 0xba, - 0xb4, 0x6b, 0x88, 0xf2, 0x7f, 0x04, 0x48, 0xde, 0xcb, 0x31, 0x62, 0x2d, 0x0f, 0x0f, - 0x87, 0xa8, 0x55, 0xba, 0x54, 0x00, 0x03, 0x32, 0x03, 0x1f, 0x73, 0xab, 0xff, 0xd4, - 0x65, 0x91, 0xda, 0x0b, 0x88, 0x72, 0x35, 0x04, 0xed, 0xb2, 0x33, 0x72, 0x30, 0xda, - 0xd2, 0xac, 0xc0, 0xd8, 0xbb, 0x68, 0xbc, 0x83, 0x7a, 0x2f, 0xf9, 0x30, 0xbf, 0xf0, - 0x6f, 0xde, 0x74, 0xeb, 0x90, 0xaa, 0xe4, 0xf6, 0x0d, 0xbb, 0x6e, 0xb8, 0x27, 0xea, - 0x99, 0x88, 0x4a, 0xcd, 0x62, 0x85, 0xa9, 0x88, 0x92, 0x80, 0x2c, 0xf5, 0x9d, 0x5d, - 0x60, 0xd0, 0x16, 0x63, 0x38, 0x7b, 0x3e, 0xd2, 0x72, 0x3b, 0xd6, 0x48, 0x9e, 0x9c, - 0x2c, 0x10, 0x6d, 0x4a, 0xa2, 0xde, 0x23, 0xce, 0xd1, 0x6c, 0x72, 0x04, 0x29, 0xc7, - 0x75, 0x3a, 0x77, 0x38, 0xec, 0x7d, 0x9d, 0xb8, 0x62, 0x42, 0x29, 0xed, 0xd2, 0x17, - 0xb8, 0x0d, 0x74, 0x87, 0x5a, 0x14, 0xca, 0xe4, 0x86, 0x3f, 0x13, 0x9e, 0x9c, 0x0b, - 0x13, 0x1b, 0x2a, 0x4c, 0x28, 0x07, 0x1a, 0x38, 0xec, 0x61, 0xf6, 0x68, 0x01, 0xaa, - 0x59, 0x56, 0xfc, 0xb2, 0xa4, 0x6b, 0x95, 0x87, 0x66, 0x5b, 0x75, 0x71, 0xaa, 0x03, - 0x48, 0x1f, 0xd8, 0xd9, 0xd5, 0x69, 0x8f, 0x83, 0x6f, 0xc8, 0x63, 0x5e, 0x69, 0xe3, - 0xbd, 0xe4, 0x2f, 0x4a, 0xc0, 0x71, 0x32, 0x8b, 0x54, 0x09, 0xf6, 0xe4, 0x2d, 0x79, - 0x0a, 0xed, 0xd7, 0x3b, 0xc1, 0xa2, 0x35, 0x47, 0x23, 0xb3, 0xb8, 0x19, 0xd0, 0x63, - 0x7a, 0x6f, 0xa4, 0x66, 0x39, 0x46, 0xa3, 0x0a, 0xc5, 0xaf, 0xdd, 0x30, 0xce, 0x83, - 0x0f, 0x67, 0x91, 0xb4, 0x57, 0x52, 0x70, 0xa1, 0x72, 0x0f, 0x91, 0x86, 0x6e, 0x2b, - 0x86, 0xf4, 0x78, 0x88, 0x94, 0xc8, 0xda, 0x62, 0xd8, 0xb9, 0x1f, 0xaf, 0x52, 0x0e, - 0x3b, 0xed, 0xbc, 0x12, 0x06, 0xa5, 0xa5, 0xe6, 0xef, 0xd3, 0xdf, 0xde, 0x08, 0x43, - 0xc3, 0xb0, 0x67, 0x57, 0x64, 0x3f, 0xc0, 0x06, 0x00, 0x88, 0x38, 0xca, 0x47, 0x30, - 0x87, 0xf8, 0x97, 0x79, 0x18, 0xcc, 0x1b, 0x81, 0xc9, 0xe6, 0x8e, 0x3b, 0x88, 0x8f, - 0xe6, 0xf7, 0xc6, 0x30, 0xf1, 0xbc, 0x7a, 0xe1, 0x88, 0xf5, 0x12, 0x84, 0x20, 0x41, - 0xca, 0xda, 0x1e, 0x05, 0xf8, 0x66, 0xd2, 0x56, 0x2d, 0xbe, 0x09, 0xc4, 0xb4, 0x30, - 0x68, 0xf7, 0x54, 0xda, 0xd3, 0x4d, 0xf0, 0xfc, 0xfc, 0x18, 0x1f, 0x31, 0x80, 0x1a, - 0x79, 0x92, 0xd2, 0xf1, 0x6b, 0xe0, 0x21, 0x1b, 0x4a, 0x22, 0xf6, 0x2a, 0xab, 0x64, - 0x70, 0x1b, 0xf4, 0xa4, 0xe6, 0xd6, 0x66, 0xfc, 0x30, 0x4a, 0x5c, 0x79, 0xc6, 0x09, - 0xac, 0xc4, 0x3b, 0x00, 0xb4, 0x86, 0x48, 0x93, 0xd3, 0x7d, 0x50, 0x07, 0xf0, 0xc3, - 0x29, 0xa4, 0x75, 0x50, 0x52, 0x57, 0x75, 0x70, 0xdd, 0x38, 0xfa, 0xc0, 0x43, 0xcd, - 0x91, 0xc1, 0x2e, 0xe3, 0x4e, 0x9c, 0xfa, 0xe3, 0x92, 0xa7, 0x8b, 0xda, 0xbd, 0x4e, - 0xe3, 0x1d, 0xc0, 0xde, 0xb0, 0x2f, 0xe7, 0xb1, 0xd8, 0xb0, 0x17, 0x8a, 0xc9, 0x51, - 0x31, 0x05, 0xfc, 0xc7, 0xe3, 0x0b, 0xa8, 0xe0, 0x16, 0xaa, 0x36, 0xa6, 0xb5, 0xdf, - 0x5e, 0x5a, 0x19, 0x09, 0xf6, 0x3a, 0xba, 0x09, 0x5d, 0x98, 0x77, 0xa8, 0xf2, 0xdc, - 0x53, 0xf4, 0x6f, 0x6c, 0x9b, 0x07, 0xad, 0xdf, 0x14, 0x6f, 0x4f, 0xfa, 0x50, 0x1f, - 0x9d, 0xd3, 0xcf, 0xf9, 0x24, 0xe3, 0x01, 0x0f, 0xaf, 0x50, 0x4e, 0x2b, 0x8a, 0xca, - 0x73, 0x57, 0xac, 0xbf, 0xfe, 0xc7, 0x3a, 0xc3, 0x4c, 0x1a, 0x73, 0x16, 0x0f, 0x2c, - 0xea, 0x1e, 0x05, 0x10, 0xf8, 0x4d, 0x2f, 0xe2, 0xf7, 0x3b, 0x6e, 0x92, 0x19, 0x07, - 0xa1, 0xb7, 0xb3, 0x75, 0x12, 0x13, 0x24, 0x1b, 0x2c, 0xfa, 0xa5, 0x5a, 0x5e, 0xa4, - 0xdd, 0x51, 0x7e, 0x7b, 0x49, 0xd2, 0xde, 0x8c, 0x09, 0x08, 0x43, 0x73, 0x0d, 0x24, - 0x08, 0xa2, 0xa3, 0x04, 0xaa, 0x1e, 0x2e, 0x13, 0x70, 0xa6, 0xbf, 0x6c, 0x2b, 0xc7, - 0x3f, 0xf0, 0x0d, 0x89, 0x3b, 0xc1, 0x28, 0x5e, 0xfc, 0xa8, 0x25, 0x99, 0xd1, 0x81, - 0xf1, 0x23, 0x51, 0xf9, 0x39, 0xa9, 0x4e, 0xa8, 0xb9, 0x75, 0xc0, 0x65, 0xa9, 0x1f, - 0xf2, 0x57, 0xca, 0xc7, 0xa9, 0x23, 0x85, 0xfc, 0x8f, 0xa9, 0x21, 0xb1, 0x06, 0xba, - 0x86, 0x60, 0xc6, 0x0a, 0xc8, 0xba, 0x5e, 0xce, 0x45, 0x60, 0x6f, 0x04, 0xf3, 0x6a, - 0x3a, 0x90, 0xbb, 0x38, 0x38, 0xc4, 0x2a, 0xbf, 0x62, 0xdd, 0x2d, 0x84, 0xba, 0xbe, - 0xf3, 0xe1, 0x88, 0xe9, 0x17, 0x1a, 0xff, 0x9b, 0xc1, 0x16, 0x66, 0x90, 0x09, 0xd8, - 0x87, 0x13, 0x0a, 0xc9, 0xf7, 0x39, 0x6a, 0x62, 0x7a, 0x84, 0x74, 0xc1, 0x81, 0x1b, - 0x69, 0x6f, 0x99, 0x55, 0x2b, 0x14, 0xc4, 0x84, 0xdf, 0xe4, 0x2c, 0x24, 0xd5, 0x7c, - 0x3a, 0x9c, 0x3f, 0xea, 0x13, 0x76, 0xcd, 0xcb, 0x63, 0x42, 0x1c, 0x31, 0x4a, 0x62, - 0x2a, 0x9a, 0xef, 0x0b, 0xc0, 0x57, 0xcb, 0x11, 0xbc, 0x5e, 0x30, 0x66, 0xe3, 0x3a, - 0x3b, 0x9b, 0x31, 0xdf, 0x25, 0x75, 0xcd, 0x51, 0x85, 0xa4, 0xf3, 0xfc, 0x4e, 0x4c, - 0x3d, 0x40, 0x2e, 0xd4, 0x20, 0x46, 0xf8, 0x1f, 0x97, 0x48, 0x16, 0xd2, 0x79, 0xb1, - 0x51, 0x3a, 0xb8, 0x1d, 0x3f, 0x0a, 0x3c, 0x7f, 0x7f, 0xcf, 0x2f, 0xbb, 0x4e, 0x26, - 0x32, 0x19, 0x93, 0xa5, 0x13, 0xad, 0x3d, 0x7f, 0x4a, 0xfe, 0x6c, 0x1b, 0xbd, 0xc6, - 0x57, 0x58, 0x50, 0x80, 0xbb, 0x5a, 0x0f, 0x25, 0x97, 0x3d, 0x63, 0xeb, 0x20, 0xad, - 0xa0, 0x16, 0x6b, 0xbd, 0x8a, 0x39, 0xff, 0x93, 0x24, 0x6f, 0x27, 0x89, 0x73, 0x2a, - 0xd0, 0x55, 0x87, 0xf8, 0xdb, 0x7b, 0xc8, 0x7c, 0x24, 0x2c, 0xfd, 0x36, 0xce, 0x68, - 0x5a, 0x4b, 0x65, 0x69, 0x86, 0xc3, 0x9f, 0xd7, 0xfc, 0xb2, 0x3c, 0x91, 0x91, 0x3e, - 0x46, 0x11, 0x19, 0x1e, 0xdc, 0xc8, 0x8b, 0x78, 0xf1, 0x45, 0xea, 0x29, 0xd2, 0x71, - 0xb9, 0x40, 0xc6, 0x99, 0x41, 0xe4, 0xc3, 0xfd, 0x2d, 0x71, 0xf3, 0xb1, 0x90, 0x69, - 0x0e, 0xe1, 0x6f, 0x5d, 0x14, 0xac, 0x22, 0x24, 0xe6, 0xfc, 0x89, 0x59, 0x76, 0x54, - 0x52, 0x7d, 0xab, 0xe7, 0x2e, 0x75, 0xd2, 0xd2, 0xa1, 0x3a, 0x9f, 0xba, 0xa6, 0x37, - 0x8e, 0x8a, 0x26, 0x43, 0x21, 0x08, 0x7a, 0x19, 0x00, 0xef, 0xe3, 0xca, 0xd1, 0x4a, - 0x57, 0x96, 0x86, 0xaa, 0x36, 0x36, 0xbd, 0x37, 0x5b, 0xd3, 0x13, 0x6b, 0xee, 0x0b, - 0xda, 0xab, 0xcf, 0xac, 0x88, 0x1b, 0xc7, 0x01, 0x81, 0x27, 0x21, 0xe6, 0xfb, 0x75, - 0xaa, 0x07, 0x2d, 0x2d, 0x18, 0x7e, 0x62, 0x25, 0x8d, 0x65, 0xa1, 0x92, 0x15, 0x7c, - 0xdf, 0x2e, 0xc3, 0x21, 0x40, 0x7f, 0x68, 0x2f, 0x5e, 0xec, 0x6a, 0x32, 0x97, 0xab, - 0x20, 0xb7, 0x06, 0x1c, 0x62, 0x24, 0x57, 0x16, 0xa4, 0x4f, 0x71, 0xfb, 0xfc, 0x34, - 0xc7, 0x9b, 0x44, 0xe0, 0x9e, 0x42, 0x12, 0xac, 0x26, 0x53, 0xf6, 0xc4, 0x03, 0x64, - 0x3e, 0x1c, 0x5b, 0x9a, 0xd1, 0x34, 0xd8, 0x9c, 0x68, 0x0b, 0x70, 0x72, 0x83, 0xaf, - 0x54, 0x32, 0x6f, 0xc4, 0xf8, 0x4d, 0x6a, 0x58, 0x29, 0xa0, 0xad, 0x48, 0x30, 0x80, - 0x6c, 0x05, 0x75, 0x84, 0x92, 0xcd, 0x6a, 0xc4, 0x6b, 0xa0, 0x1a, 0x2b, 0x37, 0x22, - 0xb5, 0xe4, 0xcd, 0xaf, 0xbb, 0x3f, 0x36, 0x78, 0x5f, 0x42, 0x4a, 0xf0, 0x44, 0xda, - 0xc5, 0xdb, 0x5f, 0x7d, 0xf8, 0x39, 0xeb, 0x63, 0xc0, 0xc1, 0x7d, 0x8b, 0x0c, 0x79, - 0xdb, 0x86, 0x30, 0x94, 0x20, 0x15, 0xbe, 0x13, 0xf7, 0x9a, 0xf6, 0xf4, 0x3e, 0x5a, - 0xb0, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x81, 0x14, 0x79, 0x8f, 0x44, 0x22, 0x58, 0xee, 0xdc, 0x43, - 0x6f, 0xcc, 0x38, 0x6b, 0x36, 0xb5, 0x7e, 0x19, 0x17, 0xd7, 0x20, 0x17, 0x73, 0x66, - 0xf4, 0x24, 0xb0, 0xa5, 0x4b, 0x0b, 0x60, 0xf4, 0xfb, 0x13, 0x58, 0xc2, 0x0a, 0xa4, - 0x1d, 0xc5, 0x02, 0xe1, 0xdd, 0x8a, 0x16, 0x33, 0xf3, 0xd8, 0xe3, 0x27, 0x6b, 0x59, - 0xe7, 0xd2, 0xc4, 0xe6, 0x24, 0xa6, 0xf5, 0x36, 0x95, 0xbc, 0xaf, 0x24, 0x7e, 0x36, - 0x48, 0x3f, 0x13, 0xb2, 0x04, 0x42, 0x22, 0x37, 0xfc, 0x6a, 0xb3, 0xeb, 0xa0, 0x2f, - 0xc4, 0x14, 0x2b, 0x42, 0x97, 0xeb, 0xb5, 0x68, 0x3d, 0xb8, 0xd2, 0x43, 0x19, 0x70, - 0x6a, 0xd2, 0x6a, 0xaf, 0xd8, 0x1c, 0x53, 0xb7, 0x40, 0xf3, 0x45, 0x43, 0xa6, 0xb3, - 0xe9, 0xf5, 0xbb, 0x7d, 0x5c, 0x49, 0xe8, 0xc3, 0x7f, 0x61, 0x49, 0x21, 0x25, 0x4f, - 0x32, 0x12, 0x39, 0x4c, 0x79, 0x7d, 0x1c, 0xee, 0x78, 0x99, 0xb7, 0xb4, 0xb6, 0x5b, - 0x59, 0xb7, 0x34, 0x2f, 0x92, 0x53, 0x1c, 0x1d, 0x59, 0xe1, 0x79, 0x70, 0xb7, 0x31, - 0x74, 0x14, 0x43, 0x8c, 0xd8, 0x0b, 0xd0, 0xf9, 0xa6, 0x7c, 0x9b, 0x9e, 0x55, 0x2f, - 0x01, 0x3c, 0x11, 0x5a, 0x95, 0x4f, 0x35, 0xe0, 0x61, 0x6c, 0x68, 0xd4, 0x31, 0x63, - 0xd3, 0x34, 0xda, 0xc3, 0x82, 0x70, 0x33, 0xe5, 0xad, 0x84, 0x88, 0xbf, 0xd9, 0xc4, - 0xbb, 0xbe, 0x8f, 0x59, 0x35, 0xc6, 0xc5, 0xea, 0x04, 0xc3, 0xad, 0x49, 0xc7, 0x47, - 0xa9, 0xe7, 0x23, 0x1b, 0xcd, 0x7d, 0x16, 0x21, 0x5e, 0x6e, 0x80, 0x73, 0x7d, 0x6b, - 0x54, 0xfe, 0xc8, 0xb8, 0x84, 0x02, 0xf0, 0x47, 0x52, 0x45, 0xe1, 0x74, 0xa7, 0x45, - 0xb8, 0x31, 0xf8, 0xfe, 0x03, 0xa7, 0x6f, 0xb9, 0xce, 0xca, 0x4d, 0x22, 0xb7, 0x83, - 0xc3, 0x28, 0xc6, 0x91, 0x5c, 0x43, 0x40, 0x50, 0x64, 0xae, 0x56, 0xbc, 0x89, 0xe6, - 0x4d, 0x15, 0x78, 0xe4, 0xd3, 0xa3, 0x4b, 0xb9, 0x55, 0x91, 0xea, 0xf1, 0xd3, 0xda, - 0x02, 0xa4, 0x54, 0x9f, 0xa8, 0x0d, 0xb0, 0xff, 0x7c, 0xb0, 0x39, 0x93, 0x02, 0x8a, - 0xe1, 0x5a, 0x30, 0xe8, 0x79, 0x49, 0xaa, 0x08, 0x0e, 0x94, 0xab, 0xde, 0x68, 0x89, - 0x8c, 0x33, 0x92, 0xa2, 0x17, 0xd6, 0x49, 0x61, 0x6b, 0xbe, 0x73, 0x9b, 0x13, 0xd1, - 0x4d, 0xf0, 0x3f, 0x02, 0x76, 0x71, 0x48, 0x9b, 0xe0, 0xb4, 0xbe, 0xba, 0xaf, 0xa7, - 0xd1, 0xe6, 0x39, 0xd5, 0xb3, 0xe9, 0x94, 0xff, 0xb6, 0xb7, 0xa2, 0x09, 0xf6, 0xad, - 0xfe, 0x8d, 0x1e, 0x5c, 0xcf, 0x01, 0x0c, 0x19, 0x0a, 0x8a, 0xeb, 0x18, 0xaa, 0x9d, - 0x68, 0x7e, 0x24, 0xad, 0xc0, 0xb1, 0x13, 0x5c, 0x70, 0xc9, 0x70, 0xe0, 0x90, 0x3a, - 0xf6, 0xe1, 0x70, 0x81, 0xd5, 0x81, 0x8e, 0x88, 0xb1, 0x4e, 0x4f, 0x60, 0x1b, 0x8c, - 0x06, 0x3e, 0x3f, 0x43, 0x87, 0xff, 0xa2, 0x32, 0x2a, 0x51, 0x81, 0x90, 0x9f, 0x09, - 0x80, 0xd6, 0x89, 0xde, 0x7f, 0x8e, 0x6a, 0x5c, 0x62, 0xa7, 0x77, 0xd1, 0x75, 0x00, - 0x2a, 0x13, 0x7d, 0x02, 0x5b, 0x88, 0x88, 0x92, 0x91, 0x98, 0x11, 0x7a, 0xa5, 0xd6, - 0x19, 0x93, 0xe1, 0xdc, 0xf7, 0x58, 0x76, 0xdc, 0xa6, 0x09, 0xf9, 0xd2, 0x84, 0x71, - 0xf9, 0x97, 0xfa, 0x11, 0xf9, 0x9d, 0x42, 0x3f, 0x02, 0xf1, 0x73, 0x4b, 0xe8, 0xa5, - 0xff, 0x99, 0x7d, 0x45, 0x1e, 0xb3, 0xcf, 0x4b, 0x3d, 0xfd, 0xd9, 0xd4, 0x54, 0x5c, - 0x35, 0xb2, 0xb5, 0xa7, 0xdc, 0x17, 0xa8, 0x36, 0xb1, 0x2b, 0x43, 0xbe, 0xfc, 0x03, - 0xe0, 0xa1, 0xbd, 0x36, 0x97, 0x72, 0x33, 0x80, 0x78, 0xb4, 0xff, 0x7d, 0x8e, 0x2d, - 0x97, 0x9a, 0x34, 0x41, 0xe1, 0xc8, 0xf5, 0xaf, 0xe4, 0x7b, 0x1e, 0x7d, 0xa5, 0x6c, - 0xf0, 0x06, 0x02, 0xd0, 0x03, 0x11, 0x0c, 0x05, 0xcf, 0x48, 0xfd, 0xa3, 0xe6, 0xcc, - 0xe3, 0x2a, 0x04, 0x40, 0x00, 0xf4, 0x5c, 0x6d, 0x1e, 0x69, 0x6d, 0x24, 0x5c, 0xbd, - 0x31, 0x2b, 0xdc, 0x3a, 0x3a, 0x21, 0xc9, 0x92, 0xd0, 0x03, 0xc8, 0xcc, 0x8f, 0xa6, - 0x30, 0x6d, 0x7e, 0x13, 0x0a, 0x2b, 0xa4, 0x20, 0x18, 0xfe, 0x59, 0x69, 0x49, 0xfd, - 0x82, 0x26, 0x7b, 0xcc, 0x59, 0xdd, 0x46, 0x26, 0xef, 0xc3, 0xea, 0x74, 0x38, 0xd0, - 0x5c, 0x91, 0xb0, 0xf8, 0xe0, 0x92, 0x55, 0x0d, 0x2d, 0x39, 0xa0, 0x1e, 0xb4, 0x5e, - 0xe8, 0xf7, 0xd0, 0x9b, 0x03, 0x8d, 0x83, 0x83, 0xe1, 0x9b, 0xc3, 0x0e, 0x64, 0x03, - 0x82, 0x8c, 0xdb, 0x65, 0x2a, 0x55, 0x6b, 0x12, 0x04, 0x09, 0x31, 0x40, 0x2a, 0xa6, - 0xac, 0x34, 0xfc, 0x19, 0xfd, 0xc0, 0x6e, 0x2e, 0x77, 0x87, 0xf5, 0xb7, 0x7b, 0x04, - 0x5f, 0xd0, 0x98, 0xc0, 0x31, 0xbd, 0xbd, 0x46, 0x27, 0x76, 0x09, 0xd8, 0x42, 0xf4, - 0x84, 0x24, 0xed, 0xa3, 0x1e, 0x3c, 0xf2, 0xcd, 0xd6, 0x43, 0x85, 0xba, 0xd3, 0x11, - 0x88, 0x58, 0xd1, 0x42, 0xd9, 0x06, 0xea, 0xdb, 0x75, 0x90, 0xc9, 0x41, 0x36, 0xda, - 0x6a, 0x06, 0x35, 0x14, 0xd6, 0xa2, 0x5f, 0x7b, 0x37, 0xd7, 0x66, 0x4f, 0x9b, 0x97, - 0x09, 0x43, 0x3e, 0x6e, 0x70, 0x21, 0x18, 0xa4, 0xab, 0x9e, 0x7a, 0x7a, 0x3e, 0x62, - 0x59, 0x12, 0x99, 0x37, 0xd2, 0x9d, 0x0d, 0xb2, 0x60, 0x70, 0x52, 0x3e, 0x8b, 0x06, - 0x43, 0x13, 0x0a, 0xbe, 0xfe, 0x94, 0x3b, 0x40, 0x12, 0x98, 0xae, 0x01, 0xa3, 0xab, - 0x00, 0xab, 0xbc, 0x60, 0xd7, 0xdb, 0x93, 0x3c, 0x7f, 0x07, 0xa8, 0xbf, 0x0f, 0x7c, - 0xe1, 0x66, 0x0b, 0xcc, 0xb4, 0x5e, 0x04, 0x2b, 0x45, 0x1b, 0x93, 0x50, 0x02, 0xce, - 0xce, 0x27, 0xf3, 0x6a, 0xba, 0x56, 0x47, 0xac, 0x28, 0xd8, 0x18, 0x6c, 0xdd, 0x1f, - 0xb9, 0x5d, 0xc1, 0x35, 0xd4, 0x89, 0x92, 0xf6, 0x8d, 0xa1, 0x2a, 0xd6, 0x1a, 0xc7, - 0x56, 0x68, 0x0d, 0xd7, 0xf8, 0xd0, 0x77, 0x4a, 0xbd, 0x6c, 0xfd, 0xa2, 0xf0, 0x32, - 0xaf, 0x3b, 0xe1, 0x39, 0xa6, 0x33, 0xd6, 0x73, 0x3c, 0x75, 0xd1, 0xab, 0xa8, 0x90, - 0x18, 0xc8, 0x57, 0x2b, 0x99, 0xcd, 0x30, 0xc5, 0x37, 0x06, 0x79, 0x41, 0xdf, 0x1c, - 0x4b, 0xc1, 0xfd, 0x57, 0x0f, 0x7b, 0x4d, 0xdc, 0x97, 0x51, 0x86, 0x23, 0xe3, 0xae, - 0x4a, 0x87, 0xbd, 0xb9, 0x66, 0xc9, 0x4d, 0x86, 0x1e, 0x80, 0xde, 0x88, 0xc2, 0x92, - 0xae, 0xe9, 0x38, 0x71, 0x94, 0xe2, 0x56, 0xc6, 0x70, 0x07, 0x52, 0x30, 0x1c, 0x73, - 0xfc, 0x95, 0x65, 0xa4, 0x04, 0x80, 0xd8, 0x12, 0x6e, 0x9d, 0x08, 0x58, 0x79, 0xe2, - 0x4b, 0x16, 0xe9, 0xc4, 0x85, 0xd8, 0xf0, 0xd6, 0x18, 0xca, 0x0d, 0xd1, 0x21, 0xb5, - 0x1a, 0x7c, 0xab, 0x23, 0x0c, 0x5b, 0x45, 0x67, 0x2b, 0xdb, 0x8e, 0xa3, 0xa0, 0x40, - 0xf7, 0xaa, 0xa0, 0x98, 0xba, 0x26, 0x02, 0x5d, 0x2e, 0xab, 0x79, 0x48, 0x69, 0x3d, - 0xd5, 0xf6, 0xd3, 0x09, 0x65, 0x01, 0xe9, 0xe0, 0x71, 0x25, 0xd7, 0xeb, 0x29, 0x3b, - 0x3a, 0xba, 0xd5, 0x7f, 0xd5, 0xf0, 0x11, 0x64, 0x70, 0x2d, 0xae, 0x64, 0xbd, 0xba, - 0x8c, 0x92, 0x4f, 0xb0, 0x79, 0x96, 0x79, 0xd7, 0x7f, 0x98, 0xd3, 0x03, 0x91, 0x9f, - 0xb4, 0xa7, 0xff, 0x26, 0xa9, 0x6f, 0x13, 0x7a, 0x5e, 0x5c, 0xb9, 0x5b, 0xc4, 0xc6, - 0xff, 0x99, 0x93, 0x52, 0x6b, 0xda, 0x15, 0x03, 0x16, 0x8a, 0xb4, 0x8c, 0xbd, 0x45, - 0x15, 0x39, 0x27, 0xd3, 0x04, 0x30, 0x42, 0x3d, 0xbd, 0xf0, 0x66, 0x05, 0xf5, 0xb5, - 0x4b, 0x80, 0x8f, 0xeb, 0x22, 0xb2, 0x08, 0xb0, 0x64, 0x58, 0x18, 0x47, 0xb2, 0xf6, - 0x4c, 0xa6, 0x48, 0x37, 0x00, 0x72, 0x16, 0xde, 0x6e, 0xca, 0xff, 0xeb, 0x4b, 0x69, - 0xe6, 0x33, 0x47, 0xf8, 0x4a, 0xbc, 0xad, 0x8f, 0x2e, 0x75, 0x7d, 0x58, 0x61, 0xce, - 0x77, 0xee, 0x46, 0x51, 0x3d, 0xa7, 0x41, 0x68, 0x37, 0xdc, 0xb2, 0x3d, 0x33, 0xea, - 0x72, 0xaf, 0x23, 0xd0, 0xad, 0x8c, 0x93, 0x07, 0xd0, 0xb5, 0x85, 0x8d, 0xa9, 0x5b, - 0x77, 0xff, 0xf9, 0x02, 0x7b, 0x88, 0x59, 0xe1, 0x1d, 0xcb, 0xd5, 0x98, 0x35, 0x0e, - 0xee, 0x50, 0x93, 0x94, 0x81, 0x70, 0x8e, 0xa7, 0x08, 0xeb, 0x9f, 0x66, 0x43, 0x88, - 0xb9, 0xc6, 0x4d, 0x6a, 0xf0, 0xf9, 0x66, 0x90, 0x34, 0x24, 0x00, 0x34, 0x8e, 0x92, - 0x9e, 0x07, 0x46, 0x02, 0x53, 0xf3, 0x83, 0x90, 0xf8, 0x7b, 0xd6, 0xc0, 0x53, 0x08, - 0xc3, 0xbd, 0xe2, 0x52, 0x28, 0xe0, 0xfa, 0x08, 0x80, 0xb0, 0x8e, 0xf3, 0x4a, 0x5a, - 0x9c, 0xc0, 0xea, 0x0a, 0x67, 0xca, 0x65, 0xb6, 0xff, 0xd0, 0x05, 0x57, 0x29, 0x09, - 0xf1, 0xc4, 0x2d, 0xd7, 0x45, 0xee, 0xee, 0x9d, 0xd6, 0xb4, 0x43, 0x9c, 0x9f, 0x3f, - 0x98, 0xa1, 0x18, 0xfe, 0x16, 0x69, 0x8e, 0x9c, 0xef, 0xf5, 0x58, 0xf1, 0x60, 0x66, - 0x97, 0x5f, 0xe3, 0x95, 0x83, 0xe9, 0xb5, 0x85, 0x3b, 0x13, 0x11, 0x39, 0x15, 0x80, - 0x01, 0x9f, 0xe5, 0x5d, 0x59, 0xd1, 0xc8, 0x28, 0xd3, 0xfe, 0xb6, 0xa3, 0xb9, 0xce, - 0x92, 0xd0, 0x89, 0xae, 0x4b, 0x40, 0x8e, 0x23, 0xd6, 0xa4, 0x37, 0xd4, 0x98, 0x9b, - 0x51, 0x9b, 0x7a, 0x9e, 0xb0, 0x8a, 0xe6, 0xd4, 0x48, 0xa7, 0xa1, 0x6e, 0x8a, 0xed, - 0x26, 0xa2, 0xec, 0xd0, 0xca, 0xd8, 0x08, 0x44, 0xfd, 0x06, 0x50, 0xd8, 0xc4, 0xe4, - 0xd2, 0xaf, 0x90, 0x65, 0x67, 0x48, 0xd8, 0x09, 0x9a, 0x0c, 0x75, 0x6f, 0xc1, 0x6c, - 0xca, 0x06, 0xa3, 0x34, 0x43, 0x07, 0x02, 0xae, 0x19, 0x61, 0x66, 0x5b, 0x48, 0x45, - 0xac, 0xd1, 0xa8, 0xe3, 0x41, 0x01, 0xe6, 0x8b, 0xb6, 0x44, 0xac, 0x03, 0x4d, 0xc6, - 0x3e, 0x6e, 0x34, 0x4c, 0x3d, 0x63, 0x76, 0x2a, 0x7a, 0x5b, 0xf5, 0x9f, 0x13, 0x09, - 0x54, 0x10, 0x98, 0x1d, 0x6b, 0x6b, 0x16, 0xbc, 0xd4, 0xc9, 0xfa, 0x68, 0xaf, 0x6e, - 0x53, 0x65, 0xe9, 0x4e, 0xcb, 0xe7, 0xab, 0x8b, 0x80, 0x43, 0xdf, 0xba, 0xcb, 0x23, - 0xc8, 0x4d, 0x71, 0xa8, 0xfe, 0x5d, 0x9a, 0xc5, 0x50, 0x2c, 0xe9, 0xf7, 0x3f, 0x40, - 0x8e, 0x14, 0x37, 0x6d, 0xb8, 0x6e, 0xf5, 0x7c, 0xc3, 0x7d, 0x09, 0x89, 0x6f, 0xa9, - 0x06, 0x97, 0x2e, 0x55, 0x71, 0x80, 0xa4, 0xab, 0x5a, 0xd0, 0x9d, 0x88, 0x46, 0xdd, - 0x6d, 0xa7, 0x48, 0x76, 0x54, 0x36, 0xe0, 0x16, 0x02, 0x40, 0xf8, 0xd4, 0x1c, 0x0a, - 0xc7, 0x83, 0xf9, 0x39, 0xf2, 0xd0, 0xed, 0x26, 0x2c, 0xe8, 0x59, 0xc1, 0x31, 0xeb, - 0xc9, 0x3f, 0xf2, 0xe6, 0xe4, 0x07, 0xd4, 0xe2, 0x43, 0xe1, 0xe9, 0x31, 0xd5, 0x3a, - 0x45, 0x43, 0xb6, 0xe2, 0x6d, 0x82, 0x59, 0x6f, 0xc5, 0x3b, 0x52, 0x31, 0x2c, 0x77, - 0x6d, 0x12, 0xeb, 0x2b, 0x65, 0x9b, 0x4f, 0xb0, 0x98, 0xdf, 0x87, 0xd6, 0x83, 0xcf, - 0x9e, 0x54, 0x12, 0xee, 0x56, 0xc3, 0xfe, 0x98, 0x41, 0xd7, 0x3f, 0xd0, 0x70, 0xdf, - 0xa5, 0x1f, 0x5b, 0xaf, 0xed, 0xf2, 0x06, 0xf1, 0x3c, 0x52, 0x4e, 0x5c, 0x50, 0xca, - 0xc9, 0x90, 0x6e, 0xfa, 0x39, 0x32, 0x90, 0x04, 0x2e, 0x3b, 0xc5, 0x9f, 0x96, 0x0b, - 0x7d, 0x24, 0x0a, 0xe4, 0x43, 0xfc, 0x49, 0x26, 0x9c, 0xe0, 0x00, 0x61, 0xe6, 0x5c, - 0x6d, 0x74, 0x81, 0x2a, 0x30, 0xdd, 0x5f, 0x5f, 0xe7, 0x4e, 0xff, 0x61, 0xe0, 0xcb, - 0xab, 0x3c, 0xec, 0x75, 0xd0, 0xae, 0xf9, 0x50, 0x83, 0x18, 0x94, 0x52, 0xdd, 0x3d, - 0x9e, 0xdf, 0x44, 0x87, 0xbc, 0x73, 0x4c, 0x8b, 0x24, 0xf2, 0x12, 0x96, 0xe4, 0xe9, - 0xef, 0x11, 0x7d, 0x7f, 0xb9, 0x77, 0xe3, 0xb0, 0xe6, 0x40, 0x6e, 0x63, 0x08, 0x59, - 0x06, 0x33, 0x1a, 0x93, 0x03, 0x3d, 0x1c, 0xb8, 0x36, 0x0f, 0xe6, 0xfe, 0xa6, 0x1a, - 0x68, 0x26, 0xdf, 0x36, 0x25, 0x57, 0x89, 0xf9, 0x2e, 0x40, 0xba, 0xfc, 0xb2, 0xeb, - 0xcb, 0x9e, 0x55, 0x6f, 0x6c, 0x0c, 0xca, 0xdc, 0x6a, 0xf0, 0x8e, 0x31, 0xec, 0x4a, - 0xd5, 0x28, 0x80, 0x34, 0xe1, 0x6d, 0x15, 0x5c, 0xfd, 0xca, 0xda, 0x7b, 0xab, 0x59, - 0x9c, 0x2f, 0xa4, 0xad, 0x2e, 0x62, 0x93, 0xf9, 0xfe, 0x09, 0x71, 0x69, 0x14, 0x82, - 0x76, 0xb6, 0xa9, 0xea, 0xa7, 0x2f, 0x14, 0x8b, 0x0c, 0x95, 0x65, 0xc3, 0xc2, 0xdd, - 0x63, 0x12, 0x5e, 0x0f, 0xa5, 0x30, 0x86, 0x1a, 0x71, 0x0d, 0xf8, 0xe4, 0x81, 0xf2, - 0x71, 0x29, 0x20, 0xf8, 0x78, 0x7e, 0x0a, 0xed, 0xfe, 0x61, 0x8a, 0xff, 0x50, 0xa3, - 0xb5, 0x62, 0x13, 0x88, 0x4d, 0x62, 0x62, 0xc1, 0x1d, 0xeb, 0xf2, 0xba, 0x7e, 0x8a, - 0xd6, 0x69, 0x2c, 0xb1, 0x70, 0x78, 0x33, 0x14, 0x18, 0xda, 0x4b, 0xe0, 0x64, 0xff, - 0x52, 0x70, 0x07, 0x39, 0x34, 0xab, 0xcd, 0x2a, 0xb0, 0x46, 0x9e, 0xca, 0xf7, 0x27, - 0x5b, 0x4b, 0xd7, 0x2b, 0xc6, 0xed, 0x34, 0x47, 0x8e, 0xa4, 0x08, 0x9b, 0x73, 0x6a, - 0x16, 0xdd, 0x90, 0x6d, 0x49, 0xf2, 0x5c, 0x33, 0x82, 0x7c, 0x57, 0x1c, 0xe0, 0xb5, - 0xd7, 0x21, 0x77, 0xaa, 0x35, 0x08, 0x80, 0x4b, 0xc0, 0xf8, 0xfa, 0xa9, 0x47, 0x12, - 0x22, 0x31, 0x40, 0x2d, 0x2f, 0x5c, 0xc9, 0xa0, 0xeb, 0x0e, 0x09, 0xd4, 0x27, 0xb4, - 0x27, 0x28, 0x8d, 0x93, 0x7d, 0x9d, 0x72, 0xb7, 0x74, 0x56, 0xf8, 0x86, 0x59, 0x4c, - 0xd8, 0xc6, 0xa4, 0x62, 0xf7, 0x7f, 0xd8, 0x30, 0x76, 0x46, 0x9c, 0xc0, 0xec, 0xba, - 0x3c, 0xc4, 0x0c, 0xad, 0x69, 0xe5, 0xb5, 0x41, 0x12, 0xea, 0xb3, 0x33, 0x96, 0xae, - 0xcf, 0xbc, 0x21, 0x1f, 0x1f, 0x79, 0xcf, 0x33, 0x10, 0x8e, 0x93, 0xd9, 0x53, 0x78, - 0xba, 0xe6, 0x95, 0x82, 0x74, 0xb3, 0x10, 0x88, 0xfb, 0xd8, 0xb3, 0xa3, 0xa0, 0xd1, - 0x54, 0xa7, 0x89, 0x73, 0x5b, 0x03, 0x49, 0xc4, 0xd5, 0x1c, 0x88, 0x9d, 0x08, 0x95, - 0x2d, 0xdd, 0x54, 0x88, 0xbe, 0x95, 0x56, 0x05, 0x94, 0xe6, - ], - script_code: vec![0x52, 0x63, 0x53, 0x51, 0x65], - transparent_input: Some(0), - hash_type: 2, - amount: 483959951916902, - consensus_branch_id: 1537743641, - sighash: [ - 0x29, 0x6f, 0xd7, 0x63, 0xf2, 0x54, 0x5e, 0x64, 0xfb, 0x5d, 0x7d, 0x49, 0xc0, 0x00, - 0xd2, 0xb4, 0x18, 0xb9, 0x3b, 0xde, 0x22, 0x34, 0xf8, 0x74, 0x29, 0x11, 0xe8, 0xaf, - 0xef, 0xd0, 0x6d, 0x57, - ], - }, - ]; - - for tv in test_vectors { - let tx = Transaction::read(&tv.tx[..]).unwrap(); - let transparent_input = if let Some(n) = tv.transparent_input { - Some((n as usize, Script(tv.script_code), Amount(tv.amount))) - } else { - None - }; - - assert_eq!( - signature_hash(&tx, tv.consensus_branch_id, tv.hash_type, transparent_input,), - tv.sighash - ); - } -} - -#[test] -fn zip_0243() { - struct TestVector { - tx: Vec, - script_code: Vec, - transparent_input: Option, - hash_type: u32, - amount: i64, - consensus_branch_id: u32, - sighash: [u8; 32], - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0243.py - let test_vectors = vec![ - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x00, 0x02, 0xe7, 0x71, 0x98, 0x11, - 0x89, 0x3e, 0x00, 0x00, 0x09, 0x52, 0x00, 0xac, 0x65, 0x51, 0xac, 0x63, 0x65, 0x65, - 0xb2, 0x83, 0x5a, 0x08, 0x05, 0x75, 0x02, 0x00, 0x02, 0x51, 0x51, 0x48, 0x1c, 0xdd, - 0x86, 0xb3, 0xcc, 0x43, 0x18, 0x44, 0x21, 0x17, 0x62, 0x3c, 0xeb, 0x05, 0x00, 0x03, - 0x1b, 0x3d, 0x1a, 0x02, 0x7c, 0x2c, 0x40, 0x59, 0x09, 0x58, 0xb7, 0xeb, 0x13, 0xd7, - 0x42, 0xa9, 0x97, 0x73, 0x8c, 0x46, 0xa4, 0x58, 0x96, 0x5b, 0xaf, 0x27, 0x6b, 0xa9, - 0x2f, 0x27, 0x2c, 0x72, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, 0xa5, 0xe2, - 0x9d, 0x4e, 0x30, 0xa7, 0x35, 0x94, 0xbf, 0x50, 0x98, 0x42, 0x1c, 0x69, 0x37, 0x8a, - 0xf1, 0xe4, 0x0f, 0x64, 0xe1, 0x25, 0x94, 0x6f, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, - 0xbc, 0xb6, 0x4b, 0x69, 0x68, 0x91, 0x2a, 0x63, 0x81, 0xce, 0x3d, 0xc1, 0x66, 0xd5, - 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, 0xb5, 0xfd, 0x93, 0x13, 0x25, 0xc9, - 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x51, - 0xa7, 0xaf, 0x9d, 0xb6, 0x99, 0x0e, 0xd8, 0x3d, 0xd6, 0x4a, 0xf3, 0x59, 0x7c, 0x04, - 0x32, 0x3e, 0xa5, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, 0xb9, 0xda, 0x94, 0x8d, - 0x32, 0x0d, 0xad, 0xd6, 0x4f, 0x54, 0x31, 0xe6, 0x1d, 0xdf, 0x65, 0x8d, 0x24, 0xae, - 0x67, 0xc2, 0x2c, 0x8d, 0x13, 0x09, 0x13, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, - 0x42, 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x91, 0xe0, 0x0c, 0x7a, 0x1d, 0x48, 0xaf, - 0x04, 0x68, 0x27, 0x59, 0x1e, 0x97, 0x33, 0xa9, 0x7f, 0xa6, 0xb6, 0x79, 0xf3, 0xdc, - 0x60, 0x1d, 0x00, 0x82, 0x85, 0xed, 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0xfc, 0x1b, 0xe4, - 0xaa, 0xc0, 0x0f, 0xf2, 0x71, 0x1e, 0xbd, 0x93, 0x1d, 0xe5, 0x18, 0x85, 0x68, 0x78, - 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, - 0x3c, 0x94, 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, - 0x79, 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, 0x32, 0xb4, - 0xf4, 0x73, 0xf4, 0x68, 0xa0, 0x08, 0xe7, 0x23, 0x89, 0xfc, 0x03, 0x88, 0x0d, 0x78, - 0x0c, 0xb0, 0x7f, 0xcf, 0xaa, 0xbe, 0x3f, 0x1a, 0x84, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, - 0x15, 0x3d, 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x55, 0xed, 0x94, 0x94, 0xc6, - 0xac, 0x89, 0x3c, 0x49, 0x72, 0x38, 0x33, 0xec, 0x89, 0x26, 0xc1, 0x03, 0x95, 0x86, - 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, 0x73, 0x1e, 0x98, 0x5d, 0x99, 0x58, 0x9c, 0x8b, - 0xb8, 0x38, 0xe8, 0xaa, 0xf7, 0x45, 0x53, 0x3e, 0xd9, 0xe8, 0xae, 0x3a, 0x1c, 0xd0, - 0x74, 0xa5, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, 0xeb, 0xbc, 0x86, 0x2d, - 0xed, 0x42, 0x43, 0x5e, 0x92, 0x47, 0x69, 0x30, 0xd0, 0x69, 0x89, 0x6c, 0xff, 0x30, - 0xeb, 0x41, 0x4f, 0x72, 0x7b, 0x89, 0x5a, 0x4b, 0x7b, 0xe1, 0x76, 0x93, 0x67, 0xe1, - 0xfe, 0x8a, 0xd1, 0x8d, 0xe1, 0x1e, 0x58, 0xd8, 0x8a, 0x0a, 0xd5, 0x51, 0x1d, 0x35, - 0x25, 0x12, 0x2b, 0x7b, 0x0a, 0x6f, 0x25, 0xd2, 0x8b, 0x16, 0x45, 0x7e, 0x74, 0x59, - 0x39, 0xff, 0xed, 0xbd, 0x12, 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, 0x7d, 0x41, - 0x7a, 0xdb, 0x3d, 0x15, 0xcc, 0x54, 0xdc, 0xb1, 0xfc, 0xe4, 0x67, 0x50, 0x0c, 0x6b, - 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, 0x82, 0x85, 0x7d, 0xee, 0xcc, 0x40, - 0xa9, 0x8d, 0x5f, 0x29, 0x35, 0x39, 0x5e, 0xe4, 0x76, 0x2d, 0xd2, 0x1a, 0xfd, 0xbb, - 0x5d, 0x47, 0xfa, 0x9a, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, 0xb9, 0x27, - 0xb7, 0xfa, 0xe2, 0xdb, 0x58, 0x71, 0x05, 0x41, 0x5d, 0x46, 0x42, 0x78, 0x9d, 0x38, - 0xf5, 0x0b, 0x8d, 0xbc, 0xc1, 0x29, 0xca, 0xb3, 0xd1, 0x7d, 0x19, 0xf3, 0x35, 0x5b, - 0xcf, 0x73, 0xce, 0xcb, 0x8c, 0xb8, 0xa5, 0xda, 0x01, 0x30, 0x71, 0x52, 0xf1, 0x39, - 0x36, 0xa2, 0x70, 0x57, 0x26, 0x70, 0xdc, 0x82, 0xd3, 0x90, 0x26, 0xc6, 0xcb, 0x4c, - 0xd4, 0xb0, 0xf7, 0xf5, 0xaa, 0x2a, 0x4f, 0x5a, 0x53, 0x41, 0xec, 0x5d, 0xd7, 0x15, - 0x40, 0x6f, 0x2f, 0xdd, 0x2a, 0xfa, 0x73, 0x3f, 0x5f, 0x64, 0x1c, 0x8c, 0x21, 0x86, - 0x2a, 0x1b, 0xaf, 0xce, 0x26, 0x09, 0xd9, 0xee, 0xcf, 0xa1, 0x58, 0xcf, 0xb5, 0xcd, - 0x79, 0xf8, 0x80, 0x08, 0xe3, 0x15, 0xdc, 0x7d, 0x83, 0x88, 0xe7, 0x6c, 0x17, 0x82, - 0xfd, 0x27, 0x95, 0xd1, 0x8a, 0x76, 0x36, 0x24, 0xc2, 0x5f, 0xa9, 0x59, 0xcc, 0x97, - 0x48, 0x9c, 0xe7, 0x57, 0x45, 0x82, 0x4b, 0x77, 0x86, 0x8c, 0x53, 0x23, 0x9c, 0xfb, - 0xdf, 0x73, 0xca, 0xec, 0x65, 0x60, 0x40, 0x37, 0x31, 0x4f, 0xaa, 0xce, 0xb5, 0x62, - 0x18, 0xc6, 0xbd, 0x30, 0xf8, 0x37, 0x4a, 0xc1, 0x33, 0x86, 0x79, 0x3f, 0x21, 0xa9, - 0xfb, 0x80, 0xad, 0x03, 0xbc, 0x0c, 0xda, 0x4a, 0x44, 0x94, 0x6c, 0x00, 0xe1, 0xb1, - 0xa1, 0xdf, 0x0e, 0x5b, 0x87, 0xb5, 0xbe, 0xce, 0x47, 0x7a, 0x70, 0x96, 0x49, 0xe9, - 0x50, 0x06, 0x05, 0x91, 0x39, 0x48, 0x12, 0x95, 0x1e, 0x1f, 0xe3, 0x89, 0x5b, 0x8c, - 0xc3, 0xd1, 0x4d, 0x2c, 0xf6, 0x55, 0x6d, 0xf6, 0xed, 0x4b, 0x4d, 0xdd, 0x3d, 0x9a, - 0x69, 0xf5, 0x33, 0x57, 0xd7, 0x76, 0x7f, 0x4f, 0x5c, 0xcb, 0xdb, 0xc5, 0x96, 0x63, - 0x12, 0x77, 0xf8, 0xfe, 0xcd, 0x08, 0xcb, 0x05, 0x6b, 0x95, 0xe3, 0x02, 0x5b, 0x97, - 0x92, 0xff, 0xf7, 0xf2, 0x44, 0xfc, 0x71, 0x62, 0x69, 0xb9, 0x26, 0xd6, 0x2e, 0x95, - 0x96, 0xfa, 0x82, 0x5c, 0x6b, 0xf2, 0x1a, 0xff, 0x9e, 0x68, 0x62, 0x5a, 0x6b, 0x4c, - 0xbc, 0x4b, 0x70, 0x0a, 0x36, 0x4f, 0xa7, 0x6b, 0xd8, 0x29, 0x8b, 0xc3, 0xec, 0x60, - 0x8d, 0x4c, 0xf7, 0xf3, 0x56, 0x66, 0x58, 0xd5, 0x58, 0x87, 0x14, 0xec, 0x94, 0x48, - 0xb0, 0xf0, 0x39, 0x61, 0x28, 0xae, 0xf8, 0x84, 0xa6, 0x46, 0x11, 0x4c, 0x9f, 0x1a, - 0x6d, 0xf5, 0x63, 0x19, 0x03, 0x3c, 0x31, 0x99, 0xcc, 0x7a, 0x09, 0xe9, 0xe9, 0x56, - 0x74, 0x82, 0xc9, 0x26, 0x95, 0x39, 0x02, 0x29, 0x40, 0x7b, 0xbc, 0x48, 0x98, 0x56, - 0x75, 0xe3, 0xf8, 0x74, 0xa4, 0x53, 0x3f, 0x1d, 0x63, 0xa8, 0x4d, 0xfa, 0x3e, 0x0f, - 0x46, 0x0f, 0xe2, 0xf5, 0x7e, 0x34, 0xfb, 0xc7, 0x54, 0x23, 0xb6, 0x88, 0x3a, 0x50, - 0xa0, 0xd4, 0x70, 0x19, 0x0d, 0xfb, 0xa1, 0x0a, 0x85, 0x7f, 0x82, 0x84, 0x2d, 0x38, - 0x25, 0xb3, 0xd6, 0xda, 0x05, 0x73, 0xd3, 0x16, 0xeb, 0x16, 0x0d, 0xc0, 0xb7, 0x16, - 0xc4, 0x8f, 0xbd, 0x46, 0x7f, 0x75, 0xb7, 0x80, 0x14, 0x9a, 0xe8, 0x80, 0x8f, 0x4e, - 0x68, 0xf5, 0x0c, 0x05, 0x36, 0xac, 0xdd, 0xf6, 0xf1, 0xae, 0xab, 0x01, 0x6b, 0x6b, - 0xc1, 0xec, 0x14, 0x4b, 0x4e, 0x55, 0x3a, 0xcf, 0xd6, 0x70, 0xf7, 0x7e, 0x75, 0x5f, - 0xc8, 0x8e, 0x06, 0x77, 0xe3, 0x1b, 0xa4, 0x59, 0xb4, 0x4e, 0x30, 0x77, 0x68, 0x95, - 0x8f, 0xe3, 0x78, 0x9d, 0x41, 0xc2, 0xb1, 0xff, 0x43, 0x4c, 0xb3, 0x0e, 0x15, 0x91, - 0x4f, 0x01, 0xbc, 0x6b, 0xc2, 0x30, 0x7b, 0x48, 0x8d, 0x25, 0x56, 0xd7, 0xb7, 0x38, - 0x0e, 0xa4, 0xff, 0xd7, 0x12, 0xf6, 0xb0, 0x2f, 0xe8, 0x06, 0xb9, 0x45, 0x69, 0xcd, - 0x40, 0x59, 0xf3, 0x96, 0xbf, 0x29, 0xb9, 0x9d, 0x0a, 0x40, 0xe5, 0xe1, 0x71, 0x1c, - 0xa9, 0x44, 0xf7, 0x2d, 0x43, 0x6a, 0x10, 0x2f, 0xca, 0x4b, 0x97, 0x69, 0x3d, 0xa0, - 0xb0, 0x86, 0xfe, 0x9d, 0x2e, 0x71, 0x62, 0x47, 0x0d, 0x02, 0xe0, 0xf0, 0x5d, 0x4b, - 0xec, 0x95, 0x12, 0xbf, 0xb3, 0xf3, 0x83, 0x27, 0x29, 0x6e, 0xfa, 0xa7, 0x43, 0x28, - 0xb1, 0x18, 0xc2, 0x74, 0x02, 0xc7, 0x0c, 0x3a, 0x90, 0xb4, 0x9a, 0xd4, 0xbb, 0xc6, - 0x8e, 0x37, 0xc0, 0xaa, 0x7d, 0x9b, 0x3f, 0xe1, 0x77, 0x99, 0xd7, 0x3b, 0x84, 0x1e, - 0x75, 0x17, 0x13, 0xa0, 0x29, 0x43, 0x90, 0x5a, 0xae, 0x08, 0x03, 0xfd, 0x69, 0x44, - 0x2e, 0xb7, 0x68, 0x1e, 0xc2, 0xa0, 0x56, 0x00, 0x05, 0x4e, 0x92, 0xee, 0xd5, 0x55, - 0x02, 0x8f, 0x21, 0xb6, 0xa1, 0x55, 0x26, 0x8a, 0x2d, 0xd6, 0x64, 0x0a, 0x69, 0x30, - 0x1a, 0x52, 0xa3, 0x8d, 0x4d, 0x9f, 0x9f, 0x95, 0x7a, 0xe3, 0x5a, 0xf7, 0x16, 0x71, - 0x18, 0x14, 0x1c, 0xe4, 0xc9, 0xbe, 0x0a, 0x6a, 0x49, 0x2f, 0xe7, 0x9f, 0x15, 0x81, - 0xa1, 0x55, 0xfa, 0x3a, 0x03, 0x49, 0x99, 0xc5, 0x38, 0xf7, 0xa7, 0x58, 0xbb, 0x5b, - 0x1d, 0x28, 0xfd, 0x21, 0x8f, 0xba, 0x19, 0x38, 0x74, 0x4b, 0xdb, 0x77, 0xb4, 0xa4, - 0xdf, 0xa7, 0xa5, 0xfa, 0xe9, 0x6e, 0x8c, 0xd4, 0x9b, 0x26, 0x90, 0x7d, 0xfc, 0x66, - 0x85, 0xc5, 0xc9, 0x9b, 0x71, 0x41, 0xac, 0x62, 0x6a, 0xb4, 0x76, 0x1f, 0xd3, 0xf4, - 0x1e, 0x72, 0x8e, 0x1a, 0x28, 0xf8, 0x9d, 0xb8, 0x9f, 0xfd, 0xec, 0xa3, 0x64, 0xe4, - 0xb2, 0x2d, 0x81, 0xd9, 0x96, 0x8d, 0x01, 0x19, 0xe4, 0xc7, 0xa1, 0x89, 0xad, 0xf2, - 0x2a, 0xd9, 0x68, 0x30, 0xa5, 0x4e, 0x40, 0xdc, 0x73, 0xea, 0xba, 0x6b, 0x2a, 0xaf, - 0x14, 0xf7, 0xca, 0x94, 0x2e, 0x73, 0x70, 0xb2, 0x47, 0xc0, 0x46, 0xf8, 0xe7, 0x5e, - 0xf8, 0xe3, 0xf8, 0xbd, 0x82, 0x1c, 0xf5, 0x77, 0x49, 0x18, 0x64, 0xe2, 0x0e, 0x6d, - 0x08, 0xfd, 0x2e, 0x32, 0xb5, 0x55, 0xc9, 0x2c, 0x66, 0x1f, 0x19, 0x58, 0x8b, 0x72, - 0xa8, 0x95, 0x99, 0x71, 0x0a, 0x88, 0x06, 0x12, 0x53, 0xca, 0x28, 0x5b, 0x63, 0x04, - 0xb3, 0x7d, 0xa2, 0xb5, 0x29, 0x4f, 0x5c, 0xb3, 0x54, 0xa8, 0x94, 0x32, 0x28, 0x48, - 0xcc, 0xbd, 0xc7, 0xc2, 0x54, 0x5b, 0x7d, 0xa5, 0x68, 0xaf, 0xac, 0x87, 0xff, 0xa0, - 0x05, 0xc3, 0x12, 0x24, 0x1c, 0x2d, 0x57, 0xf4, 0xb4, 0x5d, 0x64, 0x19, 0xf0, 0xd2, - 0xe2, 0xc5, 0xaf, 0x33, 0xae, 0x24, 0x37, 0x85, 0xb3, 0x25, 0xcd, 0xab, 0x95, 0x40, - 0x4f, 0xc7, 0xae, 0xd7, 0x05, 0x25, 0xcd, 0xdb, 0x41, 0x87, 0x2c, 0xfc, 0xc2, 0x14, - 0xb1, 0x32, 0x32, 0xed, 0xc7, 0x86, 0x09, 0x75, 0x3d, 0xbf, 0xf9, 0x30, 0xeb, 0x0d, - 0xc1, 0x56, 0x61, 0x2b, 0x9c, 0xb4, 0x34, 0xbc, 0x4b, 0x69, 0x33, 0x92, 0xde, 0xb8, - 0x7c, 0x53, 0x04, 0x35, 0x31, 0x2e, 0xdc, 0xed, 0xc6, 0xa9, 0x61, 0x13, 0x33, 0x38, - 0xd7, 0x86, 0xc4, 0xa3, 0xe1, 0x03, 0xf6, 0x01, 0x10, 0xa1, 0x6b, 0x13, 0x37, 0x12, - 0x97, 0x04, 0xbf, 0x47, 0x54, 0xff, 0x6b, 0xa9, 0xfb, 0xe6, 0x59, 0x51, 0xe6, 0x10, - 0x62, 0x0f, 0x71, 0xcd, 0xa8, 0xfc, 0x87, 0x76, 0x25, 0xf2, 0xc5, 0xbb, 0x04, 0xcb, - 0xe1, 0x22, 0x8b, 0x1e, 0x88, 0x6f, 0x40, 0x50, 0xaf, 0xd8, 0xfe, 0x94, 0xe9, 0x7d, - 0x2e, 0x9e, 0x85, 0xc6, 0xbb, 0x74, 0x8c, 0x00, 0x42, 0xd3, 0x24, 0x9a, 0xbb, 0x13, - 0x42, 0xbb, 0x0e, 0xeb, 0xf6, 0x20, 0x58, 0xbf, 0x3d, 0xe0, 0x80, 0xd9, 0x46, 0x11, - 0xa3, 0x75, 0x09, 0x15, 0xb5, 0xdc, 0x6c, 0x0b, 0x38, 0x99, 0xd4, 0x12, 0x22, 0xba, - 0xce, 0x76, 0x0e, 0xe9, 0xc8, 0x81, 0x8d, 0xed, 0x59, 0x9e, 0x34, 0xc5, 0x6d, 0x73, - 0x72, 0xaf, 0x1e, 0xb8, 0x68, 0x52, 0xf2, 0xa7, 0x32, 0x10, 0x4b, 0xdb, 0x75, 0x07, - 0x39, 0xde, 0x6c, 0x2c, 0x6e, 0x0f, 0x9e, 0xb7, 0xcb, 0x17, 0xf1, 0x94, 0x2b, 0xfc, - 0x9f, 0x4f, 0xd6, 0xeb, 0xb6, 0xb4, 0xcd, 0xd4, 0xda, 0x2b, 0xca, 0x26, 0xfa, 0xc4, - 0x57, 0x8e, 0x9f, 0x54, 0x34, 0x05, 0xac, 0xc7, 0xd8, 0x6f, 0xf5, 0x91, 0x58, 0xbd, - 0x0c, 0xba, 0x3a, 0xef, 0x6f, 0x4a, 0x84, 0x72, 0xd1, 0x44, 0xd9, 0x9f, 0x8b, 0x8d, - 0x1d, 0xed, 0xaa, 0x90, 0x77, 0xd4, 0xf0, 0x1d, 0x4b, 0xb2, 0x7b, 0xbe, 0x31, 0xd8, - 0x8f, 0xbe, 0xfa, 0xc3, 0xdc, 0xd4, 0x79, 0x75, 0x63, 0xa2, 0x6b, 0x1d, 0x61, 0xfc, - 0xd9, 0xa4, 0x64, 0xab, 0x21, 0xed, 0x55, 0x0f, 0xe6, 0xfa, 0x09, 0x69, 0x5b, 0xa0, - 0xb2, 0xf1, 0x0e, 0xea, 0x64, 0x68, 0xcc, 0x6e, 0x20, 0xa6, 0x6f, 0x82, 0x6e, 0x3d, - 0x14, 0xc5, 0x00, 0x6f, 0x05, 0x63, 0x88, 0x7f, 0x5e, 0x12, 0x89, 0xbe, 0x1b, 0x20, - 0x04, 0xca, 0xca, 0x8d, 0x3f, 0x34, 0xd6, 0xe8, 0x4b, 0xf5, 0x9c, 0x1e, 0x04, 0x61, - 0x9a, 0x7c, 0x23, 0xa9, 0x96, 0x94, 0x1d, 0x88, 0x9e, 0x46, 0x22, 0xa9, 0xb9, 0xb1, - 0xd5, 0x9d, 0x5e, 0x31, 0x90, 0x94, 0x31, 0x8c, 0xd4, 0x05, 0xba, 0x27, 0xb7, 0xe2, - 0xc0, 0x84, 0x76, 0x2d, 0x31, 0x45, 0x3e, 0xc4, 0x54, 0x9a, 0x4d, 0x97, 0x72, 0x9d, - 0x03, 0x34, 0x60, 0xfc, 0xf8, 0x9d, 0x64, 0x94, 0xf2, 0xff, 0xd7, 0x89, 0xe9, 0x80, - 0x82, 0xea, 0x5c, 0xe9, 0x53, 0x4b, 0x3a, 0xcd, 0x60, 0xfe, 0x49, 0xe3, 0x7e, 0x4f, - 0x66, 0x69, 0x31, 0x67, 0x73, 0x19, 0xed, 0x89, 0xf8, 0x55, 0x88, 0x74, 0x1b, 0x31, - 0x28, 0x90, 0x1a, 0x93, 0xbd, 0x78, 0xe4, 0xbe, 0x02, 0x25, 0xa9, 0xe2, 0x69, 0x2c, - 0x77, 0xc9, 0x69, 0xed, 0x01, 0x76, 0xbd, 0xf9, 0x55, 0x59, 0x48, 0xcb, 0xd5, 0xa3, - 0x32, 0xd0, 0x45, 0xde, 0x6b, 0xa6, 0xbf, 0x44, 0x90, 0xad, 0xfe, 0x74, 0x44, 0xcd, - 0x46, 0x7a, 0x09, 0x07, 0x54, 0x17, 0xfc, 0xc0, 0x06, 0x2e, 0x49, 0xf0, 0x08, 0xc5, - 0x1a, 0xd4, 0x22, 0x74, 0x39, 0xc1, 0xb4, 0x47, 0x6c, 0xcd, 0x8e, 0x97, 0x86, 0x2d, - 0xab, 0x7b, 0xe1, 0xe8, 0xd3, 0x99, 0xc0, 0x5e, 0xf2, 0x7c, 0x6e, 0x22, 0xee, 0x27, - 0x3e, 0x15, 0x78, 0x6e, 0x39, 0x4c, 0x8f, 0x1b, 0xe3, 0x16, 0x82, 0xa3, 0x01, 0x47, - 0x96, 0x3a, 0xc8, 0xda, 0x8d, 0x41, 0xd8, 0x04, 0x25, 0x84, 0x26, 0xa3, 0xf7, 0x02, - 0x89, 0xb8, 0xad, 0x19, 0xd8, 0xde, 0x13, 0xbe, 0x4e, 0xeb, 0xe3, 0xbd, 0x4c, 0x8a, - 0x6f, 0x55, 0xd6, 0xe0, 0xc3, 0x73, 0xd4, 0x56, 0x85, 0x18, 0x79, 0xf5, 0xfb, 0xc2, - 0x82, 0xdb, 0x9e, 0x13, 0x48, 0x06, 0xbf, 0xf7, 0x1e, 0x11, 0xbc, 0x33, 0xab, 0x75, - 0xdd, 0x6c, 0xa0, 0x67, 0xfb, 0x73, 0xa0, 0x43, 0xb6, 0x46, 0xa7, 0xcf, 0x39, 0xca, - 0xb4, 0x92, 0x83, 0x86, 0x78, 0x6d, 0x2f, 0x24, 0x14, 0x1e, 0xe1, 0x20, 0xfd, 0xc3, - 0x4d, 0x67, 0x64, 0xea, 0xfc, 0x66, 0x88, 0x0e, 0xe0, 0x20, 0x4f, 0x53, 0xcc, 0x11, - 0x67, 0xed, 0x20, 0xb4, 0x3a, 0x52, 0xde, 0xa3, 0xca, 0x7c, 0xff, 0x8e, 0xf3, 0x5c, - 0xd8, 0xe6, 0xd7, 0xc1, 0x11, 0xa6, 0x8e, 0xf4, 0x4b, 0xcd, 0x0c, 0x15, 0x13, 0xad, - 0x47, 0xca, 0x61, 0xc6, 0x59, 0xcc, 0x5d, 0x32, 0x5b, 0x44, 0x0f, 0x6b, 0x9f, 0x59, - 0xaf, 0xf6, 0x68, 0x79, 0xbb, 0x66, 0x88, 0xfd, 0x28, 0x59, 0x36, 0x2b, 0x18, 0x2f, - 0x20, 0x7b, 0x31, 0x75, 0x96, 0x1f, 0x64, 0x11, 0xa4, 0x93, 0xbf, 0xfd, 0x04, 0x8e, - 0x7d, 0x0d, 0x87, 0xd8, 0x2f, 0xe6, 0xf9, 0x90, 0xa2, 0xb0, 0xa2, 0x5f, 0x5a, 0xa0, - 0x11, 0x1a, 0x6e, 0x68, 0xf3, 0x7b, 0xf6, 0xf3, 0xac, 0x2d, 0x26, 0xb8, 0x46, 0x86, - 0xe5, 0x69, 0xd5, 0x8d, 0x99, 0xc1, 0x38, 0x35, 0x97, 0xfa, 0xd8, 0x11, 0x93, 0xc4, - 0xc1, 0xb1, 0x6e, 0x6a, 0x90, 0xe2, 0xd5, 0x07, 0xcd, 0xfe, 0x6f, 0xbd, 0xaa, 0x86, - 0x16, 0x3e, 0x9c, 0xf5, 0xde, 0x31, 0x00, 0xfb, 0xca, 0x7e, 0x8d, 0xa0, 0x47, 0xb0, - 0x90, 0x79, 0x36, 0x2d, 0x77, 0x92, 0xde, 0xb3, 0xca, 0x9d, 0xc1, 0x56, 0x1b, 0x87, - 0xc8, 0x2e, 0x3c, 0xb9, 0x9e, 0xb5, 0x83, 0x73, 0x19, 0x58, 0x22, 0x16, 0xa3, 0x22, - 0x67, 0x74, 0xef, 0xa9, 0x0e, 0xfb, 0x7b, 0xfc, 0x79, 0xf4, 0x25, 0x64, 0x4e, 0x4e, - 0x98, 0xc2, 0xd7, 0xd8, 0x64, 0x2b, 0x9d, 0xb8, 0x2a, 0xa7, 0x39, 0xbf, 0x2d, 0x71, - 0xcc, 0x41, 0x17, 0x22, 0x7d, 0xb2, 0x27, 0xcf, 0x0a, 0x05, 0xad, 0x9a, 0x95, 0x83, - 0x2e, 0x23, 0xc9, 0x4f, 0x27, 0x1c, 0xa0, 0xe4, 0x69, 0x4f, 0xac, 0x63, 0x22, 0x28, - 0x2e, 0xba, 0xc6, 0x98, 0x6b, 0x8f, 0xdc, 0x8a, 0xd8, 0x63, 0x08, 0x4f, 0xf1, 0x0f, - 0xd1, 0x1e, 0x6a, 0x13, 0x31, 0x1f, 0xb7, 0x99, 0xc7, 0x9c, 0x64, 0x1d, 0x9d, 0xa4, - 0x3b, 0x33, 0xe7, 0xad, 0x01, 0x2e, 0x28, 0x25, 0x53, 0x98, 0x78, 0x92, 0x62, 0x27, - 0x5f, 0x11, 0x75, 0xbe, 0x84, 0x62, 0xc0, 0x14, 0x91, 0xc4, 0xd8, 0x42, 0x40, 0x6d, - 0x0e, 0xc4, 0x28, 0x2c, 0x95, 0x26, 0x17, 0x4a, 0x09, 0x87, 0x8f, 0xe8, 0xfd, 0xde, - 0x33, 0xa2, 0x96, 0x04, 0xe5, 0xe5, 0xe7, 0xb2, 0xa0, 0x25, 0xd6, 0x65, 0x0b, 0x97, - 0xdb, 0xb5, 0x2b, 0xef, 0xb5, 0x9b, 0x1d, 0x30, 0xa5, 0x74, 0x33, 0xb0, 0xa3, 0x51, - 0x47, 0x44, 0x44, 0x09, 0x9d, 0xaa, 0x37, 0x10, 0x46, 0x61, 0x32, 0x60, 0xcf, 0x33, - 0x54, 0xcf, 0xcd, 0xad, 0xa6, 0x63, 0xec, 0xe8, 0x24, 0xff, 0xd7, 0xe4, 0x43, 0x93, - 0x88, 0x6a, 0x86, 0x16, 0x5d, 0xdd, 0xdf, 0x2b, 0x4c, 0x41, 0x77, 0x35, 0x54, 0xc8, - 0x69, 0x95, 0x26, 0x94, 0x08, 0xb1, 0x1e, 0x67, 0x37, 0xa4, 0xc4, 0x47, 0x58, 0x6f, - 0x69, 0x17, 0x34, 0x46, 0xd8, 0xe4, 0x8b, 0xf8, 0x4c, 0xbc, 0x00, 0x0a, 0x80, 0x78, - 0x99, 0x97, 0x3e, 0xb9, 0x3c, 0x5e, 0x81, 0x9a, 0xad, 0x66, 0x94, 0x13, 0xf8, 0x38, - 0x79, 0x33, 0xad, 0x15, 0x84, 0xaa, 0x35, 0xe4, 0x3f, 0x4e, 0xcd, 0x1e, 0x2d, 0x04, - 0x07, 0xc0, 0xb1, 0xb8, 0x99, 0x20, 0xff, 0xdf, 0xdb, 0x9b, 0xea, 0x51, 0xac, 0x95, - 0xb5, 0x57, 0xaf, 0x71, 0xb8, 0x9f, 0x90, 0x3f, 0x5d, 0x98, 0x48, 0xf1, 0x4f, 0xcb, - 0xeb, 0x18, 0x37, 0x57, 0x0f, 0x54, 0x4d, 0x63, 0x59, 0xeb, 0x23, 0xfa, 0xf3, 0x8a, - 0x08, 0x22, 0xda, 0x36, 0xce, 0x42, 0x6c, 0x4a, 0x2f, 0xbe, 0xff, 0xeb, 0x0a, 0x8a, - 0x2e, 0x29, 0x7a, 0x9d, 0x19, 0xba, 0x15, 0x02, 0x45, 0x90, 0xe3, 0x32, 0x9d, 0x9f, - 0xa9, 0x26, 0x1f, 0x99, 0x38, 0xa4, 0x03, 0x2d, 0xd3, 0x46, 0x06, 0xc9, 0xcf, 0x9f, - 0x3d, 0xd3, 0x3e, 0x57, 0x6f, 0x05, 0xcd, 0x1d, 0xd6, 0x81, 0x1c, 0x62, 0x98, 0x75, - 0x7d, 0x77, 0xd9, 0xe8, 0x10, 0xab, 0xdb, 0x22, 0x6a, 0xfc, 0xaa, 0x43, 0x46, 0xa6, - 0x56, 0x0f, 0x89, 0x32, 0xb3, 0x18, 0x1f, 0xd3, 0x55, 0xd5, 0xd3, 0x91, 0x97, 0x61, - 0x83, 0xf8, 0xd9, 0x93, 0x88, 0x83, 0x96, 0x32, 0xd6, 0x35, 0x4f, 0x66, 0x6d, 0x09, - 0xd3, 0xe5, 0x62, 0x9e, 0xa1, 0x97, 0x37, 0x38, 0x86, 0x13, 0xd3, 0x8a, 0x34, 0xfd, - 0x0f, 0x6e, 0x50, 0xee, 0x5a, 0x0c, 0xc9, 0x67, 0x71, 0x77, 0xf5, 0x00, 0x28, 0xc1, - 0x41, 0x37, 0x81, 0x87, 0xbd, 0x28, 0x19, 0x40, 0x3f, 0xc5, 0x34, 0xf8, 0x00, 0x76, - 0xe9, 0x38, 0x0c, 0xb4, 0x96, 0x4d, 0x3b, 0x6b, 0x45, 0x81, 0x9d, 0x3b, 0x8e, 0x9c, - 0xaf, 0x54, 0xf0, 0x51, 0x85, 0x2d, 0x67, 0x1b, 0xf8, 0xc1, 0xff, 0xde, 0x2d, 0x15, - 0x10, 0x75, 0x64, 0x18, 0xcb, 0x48, 0x10, 0x93, 0x6a, 0xa5, 0x7e, 0x69, 0x65, 0xd6, - 0xfb, 0x65, 0x6a, 0x76, 0x0b, 0x7f, 0x19, 0xad, 0xf9, 0x6c, 0x17, 0x34, 0x88, 0x55, - 0x21, 0x93, 0xb1, 0x47, 0xee, 0x58, 0x85, 0x80, 0x33, 0xda, 0xc7, 0xcd, 0x0e, 0xb2, - 0x04, 0xc0, 0x64, 0x90, 0xbb, 0xde, 0xdf, 0x5f, 0x75, 0x71, 0xac, 0xb2, 0xeb, 0xe7, - 0x6a, 0xce, 0xf3, 0xf2, 0xa0, 0x1e, 0xe9, 0x87, 0x48, 0x6d, 0xfe, 0x6c, 0x3f, 0x0a, - 0x5e, 0x23, 0x4c, 0x12, 0x72, 0x58, 0xf9, 0x7a, 0x28, 0xfb, 0x5d, 0x16, 0x4a, 0x81, - 0x76, 0xbe, 0x94, 0x6b, 0x80, 0x97, 0xd0, 0xe3, 0x17, 0x28, 0x7f, 0x33, 0xbf, 0x9c, - 0x16, 0xf9, 0xa5, 0x45, 0x40, 0x9c, 0xe2, 0x9b, 0x1f, 0x42, 0x73, 0x72, 0x5f, 0xc0, - 0xdf, 0x02, 0xa0, 0x4e, 0xba, 0xe1, 0x78, 0xb3, 0x41, 0x4f, 0xb0, 0xa8, 0x2d, 0x50, - 0xde, 0xb0, 0x9f, 0xcf, 0x4e, 0x6e, 0xe9, 0xd1, 0x80, 0xff, 0x4f, 0x56, 0xff, 0x3b, - 0xc1, 0xd3, 0x60, 0x1f, 0xc2, 0xdc, 0x90, 0xd8, 0x14, 0xc3, 0x25, 0x6f, 0x49, 0x67, - 0xd3, 0xa8, 0xd6, 0x4c, 0x83, 0xfe, 0xa3, 0x39, 0xc5, 0x1f, 0x5a, 0x8e, 0x58, 0x01, - 0xfb, 0xb9, 0x78, 0x35, 0x58, 0x1b, 0x60, 0x24, 0x65, 0xde, 0xe0, 0x4b, 0x59, 0x22, - 0xc2, 0x76, 0x1b, 0x54, 0x24, 0x5b, 0xec, 0x0c, 0x9e, 0xef, 0x2d, 0xb9, 0x7d, 0x22, - 0xb2, 0xb3, 0x55, 0x6c, 0xc9, 0x69, 0xfb, 0xb1, 0x3d, 0x06, 0x50, 0x97, 0x65, 0xa5, - 0x2b, 0x3f, 0xac, 0x54, 0xb9, 0x3f, 0x42, 0x1b, 0xf0, 0x8e, 0x18, 0xd5, 0x2d, 0xdd, - 0x52, 0xcc, 0x1c, 0x8c, 0xa8, 0xad, 0xfa, 0xcc, 0xab, 0x7e, 0x5c, 0xc2, 0xf4, 0x57, - 0x3f, 0xbb, 0xf8, 0x23, 0x9b, 0xb0, 0xb8, 0xae, 0xdb, 0xf8, 0xda, 0xd1, 0x62, 0x82, - 0xda, 0x5c, 0x91, 0x25, 0xdb, 0xa1, 0xc0, 0x59, 0xd0, 0xdf, 0x8a, 0xbf, 0x62, 0x10, - 0x78, 0xf0, 0x2d, 0x6c, 0x4b, 0xc8, 0x6d, 0x40, 0x84, 0x5a, 0xc1, 0xd5, 0x97, 0x10, - 0xc4, 0x5f, 0x07, 0xd5, 0x85, 0xeb, 0x48, 0xb3, 0x2f, 0xc0, 0x16, 0x7b, 0xa2, 0x56, - 0xe7, 0x3c, 0xa3, 0xb9, 0x31, 0x1c, 0x62, 0xd1, 0x09, 0x49, 0x79, 0x57, 0xd8, 0xdb, - 0xe1, 0x0a, 0xa3, 0xe8, 0x66, 0xb4, 0x0c, 0x0b, 0xaa, 0x2b, 0xc4, 0x92, 0xc1, 0x9a, - 0xd1, 0xe6, 0x37, 0x2d, 0x96, 0x22, 0xbf, 0x16, 0x3f, 0xbf, 0xfe, 0xae, 0xee, 0x79, - 0x6a, 0x3c, 0xd9, 0xb6, 0xfb, 0xbf, 0xa4, 0xd7, 0x92, 0xf3, 0x4d, 0x7f, 0xd6, 0xe7, - 0x63, 0xcd, 0x58, 0x59, 0xdd, 0x26, 0x83, 0x3d, 0x21, 0xd9, 0xbc, 0x54, 0x52, 0xbd, - 0x19, 0x51, 0x5d, 0xff, 0x9f, 0x49, 0x95, 0xb3, 0x5b, 0xc0, 0xc1, 0xf8, 0x76, 0xe6, - 0xad, 0x11, 0xf2, 0x45, 0x2d, 0xc9, 0xae, 0x85, 0xae, 0xc0, 0x1f, 0xc5, 0x6f, 0x8c, - 0xbf, 0xda, 0x75, 0xa7, 0x72, 0x7b, 0x75, 0xeb, 0xbd, 0x6b, 0xbf, 0xfb, 0x43, 0xb6, - 0x3a, 0x3b, 0x1b, 0x67, 0x1e, 0x40, 0xfe, 0xb0, 0xdb, 0x00, 0x29, 0x74, 0xa3, 0xc3, - 0xb1, 0xa7, 0x88, 0x56, 0x72, 0x31, 0xbf, 0x63, 0x99, 0xff, 0x89, 0x23, 0x69, 0x81, - 0x14, 0x9d, 0x42, 0x38, 0x02, 0xd2, 0x34, 0x1a, 0x3b, 0xed, 0xb9, 0xdd, 0xcb, 0xac, - 0x1f, 0xe7, 0xb6, 0x43, 0x5e, 0x14, 0x79, 0xc7, 0x2e, 0x70, 0x89, 0xb5, 0x1b, 0xfe, - 0x2f, 0xf3, 0x45, 0x85, 0x7d, 0xa9, 0xb5, 0x45, 0xe8, 0x8e, 0x32, 0x21, 0xf3, 0xf5, - 0xf7, 0x2d, 0x1e, 0x06, 0x9c, 0x9a, 0x85, 0xdd, 0x22, 0x36, 0xd3, 0x90, 0x98, 0x95, - 0x87, 0xbe, 0x00, 0x5c, 0xda, 0x16, 0xaf, 0x44, 0x08, 0xf3, 0xab, 0x06, 0xa9, 0x16, - 0xee, 0xeb, 0x9c, 0x95, 0x94, 0xb7, 0x04, 0x24, 0xa4, 0xc1, 0xd1, 0x71, 0x29, 0x5b, - 0x67, 0x63, 0xb2, 0x2f, 0x47, 0x12, 0xba, 0x7b, 0xef, 0xf0, 0xff, 0x27, 0x88, 0x3a, - 0xfa, 0xff, 0x26, 0x03, 0x4b, 0x89, 0x57, 0x35, 0x70, 0x9c, 0xf9, 0x37, 0xbd, 0x22, - 0x31, 0x89, 0x1e, 0x70, 0xeb, 0x27, 0x71, 0xe9, 0x92, 0x7c, 0x97, 0xf8, 0x76, 0x4e, - 0xb4, 0x8e, 0x91, 0x1d, 0x42, 0x8e, 0xc8, 0xd8, 0x61, 0xb7, 0x08, 0xe8, 0x29, 0x8a, - 0xcb, 0x62, 0x15, 0x51, 0x45, 0x15, 0x5a, 0xe9, 0x5f, 0x0a, 0x1d, 0x15, 0x01, 0x03, - 0x47, 0x53, 0x14, 0x6e, 0x22, 0xd0, 0x5f, 0x58, 0x6d, 0x7f, 0x6b, 0x4f, 0xe1, 0x2d, - 0xad, 0x9a, 0x17, 0xf5, 0xdb, 0x70, 0xb1, 0xdb, 0x96, 0xb8, 0xd9, 0xa8, 0x3e, 0xda, - 0xdc, 0x96, 0x6c, 0x8a, 0x54, 0x66, 0xb6, 0x1f, 0xc9, 0x98, 0xc3, 0x1f, 0x10, 0x70, - 0xd9, 0xa5, 0xc9, 0xa6, 0xd2, 0x68, 0xd3, 0x04, 0xfe, 0x6b, 0x8f, 0xd3, 0xb4, 0x01, - 0x03, 0x48, 0x61, 0x1a, 0xbd, 0xcb, 0xd4, 0x9f, 0xe4, 0xf8, 0x5b, 0x62, 0x3c, 0x78, - 0x28, 0xc7, 0x13, 0x82, 0xe1, 0x03, 0x4e, 0xa6, 0x7b, 0xc8, 0xae, 0x97, 0x40, 0x4b, - 0x0c, 0x50, 0xb2, 0xa0, 0x4f, 0x55, 0x9e, 0x49, 0x95, 0x0a, 0xfc, 0xb0, 0xef, 0x46, - 0x2a, 0x2a, 0xe0, 0x24, 0xb0, 0xf0, 0x22, 0x4d, 0xfd, 0x73, 0x68, 0x4b, 0x88, 0xc7, - 0xfb, 0xe9, 0x2d, 0x02, 0xb6, 0x8f, 0x75, 0x9c, 0x47, 0x52, 0x66, 0x3c, 0xd7, 0xb9, - 0x7a, 0x14, 0x94, 0x36, 0x49, 0x30, 0x55, 0x21, 0x32, 0x6b, 0xde, 0x08, 0x56, 0x30, - 0x86, 0x46, 0x29, 0x29, 0x1b, 0xae, 0x25, 0xff, 0x88, 0x22, 0xa1, 0x4c, 0x4b, 0x66, - 0x6a, 0x92, 0x59, 0xad, 0x0d, 0xc4, 0x2a, 0x82, 0x90, 0xac, 0x7b, 0xc7, 0xf5, 0x3a, - 0x16, 0xf3, 0x79, 0xf7, 0x58, 0xe5, 0xde, 0x75, 0x0f, 0x04, 0xfd, 0x7c, 0xad, 0x47, - 0x70, 0x1c, 0x85, 0x97, 0xf9, 0x78, 0x88, 0xbe, 0xa6, 0xfa, 0x0b, 0xf2, 0x99, 0x99, - 0x56, 0xfb, 0xfd, 0x0e, 0xe6, 0x8e, 0xc3, 0x6e, 0x46, 0x88, 0x80, 0x9a, 0xe2, 0x31, - 0xeb, 0x8b, 0xc4, 0x36, 0x9f, 0x5f, 0xe1, 0x57, 0x3f, 0x57, 0xe0, 0x99, 0xd9, 0xc0, - 0x99, 0x01, 0xbf, 0x39, 0xca, 0xac, 0x48, 0xdc, 0x11, 0x95, 0x6a, 0x8a, 0xe9, 0x05, - 0xea, 0xd8, 0x69, 0x54, 0x54, 0x7c, 0x44, 0x8a, 0xe4, 0x3d, 0x31, 0x5e, 0x66, 0x9c, - 0x42, 0x42, 0xda, 0x56, 0x59, 0x38, 0xf4, 0x17, 0xbf, 0x43, 0xce, 0x7b, 0x2b, 0x30, - 0xb1, 0xcd, 0x40, 0x18, 0x38, 0x8e, 0x1a, 0x91, 0x0f, 0x0f, 0xc4, 0x1f, 0xb0, 0x87, - 0x7a, 0x59, 0x25, 0xe4, 0x66, 0x81, 0x9d, 0x37, 0x5b, 0x0a, 0x91, 0x2d, 0x4f, 0xe8, - 0x43, 0xb7, 0x6e, 0xf6, 0xf2, 0x23, 0xf0, 0xf7, 0xc8, 0x94, 0xf3, 0x8f, 0x7a, 0xb7, - 0x80, 0xdf, 0xd7, 0x5f, 0x66, 0x9c, 0x8c, 0x06, 0xcf, 0xfa, 0x43, 0xeb, 0x47, 0x56, - 0x5a, 0x50, 0xe3, 0xb1, 0xfa, 0x45, 0xad, 0x61, 0xce, 0x9a, 0x1c, 0x47, 0x27, 0xb7, - 0xaa, 0xa5, 0x35, 0x62, 0xf5, 0x23, 0xe7, 0x39, 0x52, 0xbb, 0xf3, 0x3d, 0x8a, 0x41, - 0x04, 0x07, 0x8a, 0xde, 0x3e, 0xaa, 0xa4, 0x96, 0x99, 0xa6, 0x9f, 0xdf, 0x1c, 0x5a, - 0xc7, 0x73, 0x21, 0x46, 0xee, 0x5e, 0x1d, 0x6b, 0x6c, 0xa9, 0xb9, 0x18, 0x0f, 0x96, - 0x4c, 0xc9, 0xd0, 0x87, 0x8a, 0xe1, 0x37, 0x35, 0x24, 0xd7, 0xd5, 0x10, 0xe5, 0x82, - 0x27, 0xdf, 0x6d, 0xe9, 0xd3, 0x0d, 0x27, 0x18, 0x67, 0x64, 0x01, 0x77, 0xb0, 0xf1, - 0x85, 0x6e, 0x28, 0xd5, 0xc8, 0xaf, 0xb0, 0x95, 0xef, 0x61, 0x84, 0xfe, 0xd6, 0x51, - 0x58, 0x90, 0x22, 0xee, 0xae, 0xa4, 0xc0, 0xce, 0x1f, 0xa6, 0xf0, 0x85, 0x09, 0x2b, - 0x04, 0x97, 0x94, 0x89, 0x17, 0x2b, 0x3e, 0xf8, 0x19, 0x4a, 0x79, 0x8d, 0xf5, 0x72, - 0x4d, 0x6b, 0x05, 0xf1, 0xae, 0x00, 0x00, 0x13, 0xa0, 0x8d, 0x61, 0x2b, 0xca, 0x8a, - 0x8c, 0x31, 0x44, 0x3c, 0x10, 0x34, 0x6d, 0xbf, 0x61, 0xde, 0x84, 0x75, 0xc0, 0xbb, - 0xec, 0x51, 0x04, 0xb4, 0x75, 0x56, 0xaf, 0x3d, 0x51, 0x44, 0x58, 0xe2, 0x32, 0x1d, - 0x14, 0x60, 0x71, 0x78, 0x9d, 0x23, 0x35, 0x93, 0x4a, 0x68, 0x06, 0x14, 0xe8, 0x35, - 0x62, 0xf8, 0x2d, 0xfd, 0x40, 0x5b, 0x54, 0xa4, 0x5e, 0xb3, 0x2c, 0x16, 0x54, 0x48, - 0xd4, 0xd5, 0xd6, 0x1c, 0xa2, 0x85, 0x95, 0x85, 0x36, 0x9f, 0x53, 0xf1, 0xa1, 0x37, - 0xe9, 0xe8, 0x2b, 0x67, 0xb8, 0xfd, 0xaf, 0x01, 0xbd, 0xa5, 0x4a, 0x31, 0x73, 0x11, - 0x89, 0x6a, 0xe1, 0x02, 0x80, 0xa0, 0x32, 0x44, 0x0c, 0x42, 0x0a, 0x42, 0x1e, 0x94, - 0x4d, 0x1e, 0x95, 0x2b, 0x70, 0xd5, 0x82, 0x6c, 0xd3, 0xb0, 0x8b, 0x7d, 0xb9, 0x63, - 0x0f, 0xe4, 0xfd, 0x5f, 0x22, 0x12, 0x5d, 0xe8, 0x40, 0xfc, 0xc4, 0x0b, 0x98, 0x03, - 0x8a, 0xf1, 0x1d, 0x55, 0xbe, 0x25, 0x43, 0x25, 0x97, 0xb4, 0xb6, 0x5b, 0x9e, 0xc1, - 0xc7, 0xa8, 0xbb, 0xfd, 0x05, 0x2c, 0xbf, 0x7e, 0x1c, 0x17, 0x85, 0x31, 0x49, 0x34, - 0xb2, 0x62, 0xd5, 0x85, 0x37, 0x54, 0xf1, 0xf1, 0x77, 0x71, 0xcf, 0xb7, 0x50, 0x30, - 0x72, 0x65, 0x57, 0x53, 0xfa, 0x3f, 0x54, 0xec, 0xc5, 0x87, 0xe9, 0xf8, 0x3b, 0x58, - 0x19, 0x16, 0x09, 0x2d, 0xf2, 0x6e, 0x63, 0xe1, 0x89, 0x94, 0xcb, 0x0d, 0xb9, 0x1a, - 0x0b, 0xbd, 0xc7, 0xb6, 0x11, 0x9b, 0x32, 0x22, 0x2a, 0xdf, 0x5e, 0x61, 0xd8, 0xd8, - 0xae, 0x89, 0xda, 0xe4, 0x95, 0x4b, 0x54, 0x81, 0x3b, 0xb3, 0x3f, 0x08, 0xd5, 0x62, - 0xba, 0x51, 0x3f, 0xee, 0x1b, 0x09, 0xc0, 0xfc, 0xd5, 0x16, 0x05, 0x54, 0x19, 0x47, - 0x4d, 0xd7, 0xfd, 0xa0, 0x38, 0xa8, 0x9c, 0x84, 0xea, 0x7b, 0x94, 0x68, 0x28, 0x7f, - 0x0e, 0xb0, 0xc1, 0x0c, 0x4b, 0x13, 0x25, 0x20, 0x19, 0x4d, 0x3d, 0x8d, 0x53, 0x51, - 0xfc, 0x10, 0xd0, 0x9c, 0x15, 0xc8, 0xcc, 0x10, 0x1a, 0xa1, 0x66, 0x3b, 0xbf, 0x17, - 0xb8, 0x41, 0x11, 0xf3, 0x8b, 0xb4, 0x39, 0xf0, 0x73, 0x53, 0xbd, 0xea, 0x35, 0x96, - 0xd1, 0x5e, 0x71, 0x3e, 0x1e, 0x2e, 0x7d, 0x3f, 0x1c, 0x38, 0x31, 0x35, 0xb4, 0x7f, - 0xa7, 0xf8, 0x1f, 0x46, 0xdf, 0x7a, 0x90, 0x2a, 0x40, 0x46, 0x99, 0xec, 0x91, 0x2f, - 0x56, 0x56, 0xc3, 0x5b, 0x85, 0x76, 0x3e, 0x4d, 0xe5, 0x83, 0xae, 0xca, 0xa1, 0xdf, - 0xd5, 0xd2, 0x67, 0x7d, 0x9c, 0x8f, 0xfe, 0xe8, 0x77, 0xf6, 0x3f, 0x40, 0xa5, 0xca, - 0x0d, 0x67, 0xf6, 0xe5, 0x54, 0x12, 0x47, 0x00, 0xf8, 0x05, 0xaf, 0x87, 0x6a, 0xee, - 0xde, 0x53, 0xaa, 0x8b, 0x0f, 0x8e, 0x56, 0x04, 0xa7, 0x3c, 0x30, 0xcb, 0xd0, 0x9d, - 0xad, 0x96, 0x3d, 0x6f, 0x8a, 0x5d, 0xcc, 0x40, 0xde, 0xf4, 0x07, 0x97, 0x34, 0x21, - 0x13, 0xba, 0x20, 0x6f, 0xae, 0x8e, 0xbe, 0x4f, 0x3b, 0xc3, 0xca, 0xf6, 0x92, 0x59, - 0xe4, 0x62, 0xef, 0xf9, 0xba, 0x8b, 0x3f, 0x4b, 0xfa, 0xa1, 0x30, 0x0c, 0x26, 0x92, - 0x5a, 0x87, - ], - script_code: vec![0x63], - transparent_input: None, - hash_type: 1, - amount: 1969273897303781, - consensus_branch_id: 1991772603, - sighash: [ - 0x63, 0xd1, 0x85, 0x34, 0xde, 0x5f, 0x2d, 0x1c, 0x9e, 0x16, 0x9b, 0x73, 0xf9, 0xc7, - 0x83, 0x71, 0x8a, 0xdb, 0xef, 0x5c, 0x8a, 0x7d, 0x55, 0xb5, 0xe7, 0xa3, 0x7a, 0xff, - 0xa1, 0xdd, 0x3f, 0xf3, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0x0b, 0xbe, 0x32, 0xa5, 0x98, - 0xc2, 0x2a, 0xdf, 0xb4, 0x8c, 0xef, 0x72, 0xba, 0x5d, 0x42, 0x87, 0xc0, 0xce, 0xfb, - 0xac, 0xfd, 0x8c, 0xe1, 0x95, 0xb4, 0x96, 0x3c, 0x34, 0xa9, 0x4b, 0xba, 0x7a, 0x17, - 0x5d, 0xae, 0x4b, 0x04, 0x65, 0xac, 0x65, 0x63, 0x53, 0x70, 0x89, 0x15, 0x09, 0x0f, - 0x47, 0xa0, 0x68, 0xe2, 0x27, 0x43, 0x3f, 0x9e, 0x49, 0xd3, 0xaa, 0x09, 0xe3, 0x56, - 0xd8, 0xd6, 0x6d, 0x0c, 0x01, 0x21, 0xe9, 0x1a, 0x3c, 0x4a, 0xa3, 0xf2, 0x7f, 0xa1, - 0xb6, 0x33, 0x96, 0xe2, 0xb4, 0x1d, 0x09, 0x00, 0x63, 0x53, 0x53, 0x00, 0xac, 0x53, - 0xac, 0x51, 0x4e, 0x97, 0x05, 0x68, 0x02, 0xda, 0x07, 0x1b, 0x97, 0x0d, 0x48, 0x07, - 0x00, 0x01, 0x52, 0xa8, 0x44, 0x55, 0x0b, 0xdc, 0x20, 0x02, 0x00, 0x07, 0x52, 0x52, - 0x6a, 0x65, 0x52, 0x00, 0x52, 0xd7, 0x03, 0x43, 0x02, 0x01, 0x1b, 0x9a, 0x07, 0x66, - 0x20, 0xed, 0xc0, 0x67, 0xff, 0x02, 0x00, 0x00, 0x03, 0x53, 0xe3, 0xb8, 0xa7, 0x1f, - 0xac, 0xe1, 0xc9, 0xf3, 0x77, 0x45, 0xed, 0x36, 0x88, 0x35, 0x29, 0x30, 0x4b, 0xfd, - 0x5a, 0x39, 0x0b, 0x37, 0xbc, 0x5a, 0x34, 0x45, 0x24, 0x1f, 0x03, 0xf6, 0x4a, 0x81, - 0x88, 0x20, 0xdf, 0xed, 0xdd, 0x75, 0x37, 0x51, 0x59, 0xfb, 0xd2, 0x1e, 0xca, 0x98, - 0x72, 0x10, 0x4f, 0x8d, 0x7b, 0x3c, 0x8c, 0x86, 0x97, 0x03, 0xa1, 0xe7, 0x84, 0x8a, - 0x5c, 0x94, 0x1e, 0x45, 0xa9, 0xc7, 0x94, 0x34, 0x46, 0xd0, 0xdc, 0x96, 0x27, 0xcb, - 0x31, 0xf8, 0x0e, 0x7a, 0xa5, 0x96, 0xd4, 0x82, 0x1d, 0xc9, 0x9a, 0x7d, 0x77, 0x7c, - 0xd5, 0x7e, 0x19, 0x48, 0x42, 0xa0, 0x23, 0x47, 0x1f, 0x0f, 0x62, 0x88, 0xa1, 0x50, - 0x64, 0x7b, 0x2a, 0xfe, 0x9d, 0xf7, 0xcc, 0xcf, 0x01, 0xf5, 0xcd, 0xe5, 0xf0, 0x46, - 0x80, 0xbb, 0xfe, 0xd8, 0x7f, 0x6c, 0xf4, 0x29, 0xfb, 0x27, 0xad, 0x6b, 0xab, 0xe7, - 0x91, 0x76, 0x66, 0x11, 0xcf, 0x5b, 0xc2, 0x0e, 0x48, 0xbe, 0xf1, 0x19, 0x25, 0x9b, - 0x9b, 0x8a, 0x0e, 0x39, 0xc3, 0xdf, 0x28, 0xcb, 0x95, 0x82, 0xea, 0x33, 0x86, 0x01, - 0xcd, 0xc4, 0x81, 0xb3, 0x2f, 0xb8, 0x2a, 0xde, 0xeb, 0xb3, 0xda, 0xde, 0x25, 0xd1, - 0xa3, 0xdf, 0x20, 0xc3, 0x7e, 0x71, 0x25, 0x06, 0xb5, 0xd9, 0x96, 0xc4, 0x9a, 0x9f, - 0x0f, 0x30, 0xdd, 0xcb, 0x91, 0xfe, 0x90, 0x04, 0xe1, 0xe8, 0x32, 0x94, 0xa6, 0xc9, - 0x20, 0x3d, 0x94, 0xe8, 0xdc, 0x2c, 0xbb, 0x44, 0x9d, 0xe4, 0x15, 0x50, 0x32, 0x60, - 0x4e, 0x47, 0x99, 0x70, 0x16, 0xb3, 0x04, 0xfd, 0x43, 0x7d, 0x82, 0x35, 0x04, 0x5e, - 0x25, 0x5a, 0x19, 0xb7, 0x43, 0xa0, 0xa9, 0xf2, 0xe3, 0x36, 0xb4, 0x4c, 0xae, 0x30, - 0x7b, 0xb3, 0x98, 0x7b, 0xd3, 0xe4, 0xe7, 0x77, 0xfb, 0xb3, 0x4c, 0x0a, 0xb8, 0xcc, - 0x3d, 0x67, 0x46, 0x6c, 0x0a, 0x88, 0xdd, 0x4c, 0xca, 0xd1, 0x8a, 0x07, 0xa8, 0xd1, - 0x06, 0x8d, 0xf5, 0xb6, 0x29, 0xe5, 0x71, 0x8d, 0x0f, 0x6d, 0xf5, 0xc9, 0x57, 0xcf, - 0x71, 0xbb, 0x00, 0xa5, 0x17, 0x8f, 0x17, 0x5c, 0xac, 0xa9, 0x44, 0xe6, 0x35, 0xc5, - 0x15, 0x9f, 0x73, 0x8e, 0x24, 0x02, 0xa2, 0xd2, 0x1a, 0xa0, 0x81, 0xe1, 0x0e, 0x45, - 0x6a, 0xfb, 0x00, 0xb9, 0xf6, 0x24, 0x16, 0xc8, 0xb9, 0xc0, 0xf7, 0x22, 0x8f, 0x51, - 0x07, 0x29, 0xe0, 0xbe, 0x3f, 0x30, 0x53, 0x13, 0xd7, 0x7f, 0x73, 0x79, 0xdc, 0x2a, - 0xf2, 0x48, 0x69, 0xc6, 0xc7, 0x4e, 0xe4, 0x47, 0x14, 0x98, 0x86, 0x1d, 0x19, 0x2f, - 0x0f, 0xf0, 0xf5, 0x08, 0x28, 0x5d, 0xab, 0x6b, 0x6a, 0x36, 0xcc, 0xf7, 0xd1, 0x22, - 0x56, 0xcc, 0x76, 0xb9, 0x55, 0x03, 0x72, 0x0a, 0xc6, 0x72, 0xd0, 0x82, 0x68, 0xd2, - 0xcf, 0x77, 0x73, 0xb6, 0xba, 0x2a, 0x5f, 0x66, 0x48, 0x47, 0xbf, 0x70, 0x7f, 0x2f, - 0xc1, 0x0c, 0x98, 0xf2, 0xf0, 0x06, 0xec, 0x22, 0xcc, 0xb5, 0xa8, 0xc8, 0xb7, 0xc4, - 0x0c, 0x7c, 0x2d, 0x49, 0xa6, 0x63, 0x9b, 0x9f, 0x2c, 0xe3, 0x3c, 0x25, 0xc0, 0x4b, - 0xc4, 0x61, 0xe7, 0x44, 0xdf, 0xa5, 0x36, 0xb0, 0x0d, 0x94, 0xba, 0xdd, 0xf4, 0xf4, - 0xd1, 0x40, 0x44, 0xc6, 0x95, 0xa3, 0x38, 0x81, 0x47, 0x7d, 0xf1, 0x24, 0xf0, 0xfc, - 0xf2, 0x06, 0xa9, 0xfb, 0x2e, 0x65, 0xe3, 0x04, 0xcd, 0xbf, 0x0c, 0x4d, 0x23, 0x90, - 0x17, 0x0c, 0x13, 0x0a, 0xb8, 0x49, 0xc2, 0xf2, 0x2b, 0x5c, 0xdd, 0x39, 0x21, 0x64, - 0x0c, 0x8c, 0xf1, 0x97, 0x6a, 0xe1, 0x01, 0x0b, 0x0d, 0xfd, 0x9c, 0xb2, 0x54, 0x3e, - 0x45, 0xf9, 0x97, 0x49, 0xcc, 0x4d, 0x61, 0xf2, 0xe8, 0xaa, 0xbf, 0xe9, 0x8b, 0xd9, - 0x05, 0xfa, 0x39, 0x95, 0x1b, 0x33, 0xea, 0x76, 0x9c, 0x45, 0xab, 0x95, 0x31, 0xc5, - 0x72, 0x09, 0x86, 0x2a, 0xd1, 0x2f, 0xd7, 0x6b, 0xa4, 0x80, 0x7e, 0x65, 0x41, 0x7b, - 0x6c, 0xd1, 0x2f, 0xa8, 0xec, 0x91, 0x6f, 0x01, 0x3e, 0xbb, 0x87, 0x06, 0xa9, 0x6e, - 0xff, 0xed, 0xa0, 0x6c, 0x4b, 0xe2, 0x4b, 0x04, 0x84, 0x63, 0x92, 0xe9, 0xd1, 0xe6, - 0x93, 0x0e, 0xae, 0x01, 0xfa, 0x21, 0xfb, 0xd7, 0x00, 0x58, 0x3f, 0xb5, 0x98, 0xb9, - 0x2c, 0x8f, 0x4e, 0xb8, 0xa6, 0x1a, 0xa6, 0x23, 0x5d, 0xb6, 0x0f, 0x28, 0x41, 0xcf, - 0x3a, 0x1c, 0x6a, 0xb5, 0x4c, 0x67, 0x06, 0x68, 0x44, 0x71, 0x1d, 0x09, 0x1e, 0xb9, - 0x31, 0xa1, 0xbd, 0x62, 0x81, 0xae, 0xdf, 0x2a, 0x0e, 0x8f, 0xab, 0x18, 0x81, 0x72, - 0x02, 0xa9, 0xbe, 0x06, 0x40, 0x2e, 0xd9, 0xcc, 0x72, 0x0c, 0x16, 0xbf, 0xe8, 0x81, - 0xe4, 0xdf, 0x42, 0x55, 0xe8, 0x7a, 0xfb, 0x7f, 0xc6, 0x2f, 0x38, 0x11, 0x6b, 0xbe, - 0x03, 0xcd, 0x8a, 0x3c, 0xb1, 0x1a, 0x27, 0xd5, 0x68, 0x41, 0x47, 0x82, 0xf4, 0x7b, - 0x1a, 0x44, 0xc9, 0x7c, 0x68, 0x04, 0x67, 0x69, 0x4b, 0xc9, 0x70, 0x9d, 0x32, 0x91, - 0x6c, 0x97, 0xe8, 0x00, 0x6c, 0xbb, 0x07, 0xba, 0x0e, 0x41, 0x80, 0xa3, 0x73, 0x80, - 0x38, 0xc3, 0x74, 0xc4, 0xcc, 0xe8, 0xf3, 0x29, 0x59, 0xaf, 0xb2, 0x5f, 0x30, 0x3f, - 0x58, 0x15, 0xc4, 0x53, 0x31, 0x24, 0xac, 0xf9, 0xd1, 0x89, 0x40, 0xe7, 0x75, 0x22, - 0xac, 0x5d, 0xc4, 0xb9, 0x57, 0x0a, 0xae, 0x8f, 0x47, 0xb7, 0xf5, 0x7f, 0xd8, 0x76, - 0x7b, 0xea, 0x1a, 0x24, 0xae, 0x7b, 0xed, 0x65, 0xb4, 0xaf, 0xdc, 0x8f, 0x12, 0x78, - 0xc3, 0x0e, 0x2d, 0xb9, 0x8f, 0xd1, 0x72, 0x73, 0x0a, 0xc6, 0xbb, 0xed, 0x4f, 0x11, - 0x27, 0xcd, 0x32, 0xb0, 0x4a, 0x95, 0xb2, 0x05, 0x52, 0x6c, 0xfc, 0xb4, 0xc4, 0xe1, - 0xcc, 0x95, 0x51, 0x75, 0xb3, 0xe8, 0xde, 0x1f, 0x5d, 0x81, 0xb1, 0x86, 0x69, 0x69, - 0x23, 0x50, 0xaa, 0xa1, 0xa1, 0xd7, 0x97, 0x61, 0x75, 0x82, 0xe5, 0x4d, 0x7a, 0x5b, - 0x57, 0xa6, 0x83, 0xb3, 0x2f, 0xb1, 0x09, 0x80, 0x62, 0xda, 0xd7, 0xb0, 0xc2, 0xeb, - 0x51, 0x8f, 0x68, 0x62, 0xe8, 0x3d, 0xb2, 0x5e, 0x3d, 0xba, 0xf7, 0xae, 0xd5, 0x04, - 0xde, 0x93, 0x2a, 0xcb, 0x99, 0xd7, 0x35, 0x99, 0x2c, 0xe6, 0x2b, 0xae, 0x9e, 0xf8, - 0x93, 0xff, 0x6a, 0xcc, 0x0f, 0xfc, 0xf8, 0xe3, 0x48, 0x3e, 0x14, 0x6b, 0x9d, 0x49, - 0xdd, 0x8c, 0x78, 0x35, 0xf4, 0x3a, 0x37, 0xdc, 0xa0, 0x78, 0x7e, 0x3e, 0xc9, 0xf6, - 0x60, 0x52, 0x23, 0xd5, 0xba, 0x7a, 0xe0, 0xab, 0x90, 0x25, 0xb7, 0x3b, 0xc0, 0x3f, - 0x7f, 0xac, 0x36, 0xc0, 0x09, 0xa5, 0x6d, 0x4d, 0x95, 0xd1, 0xe8, 0x1d, 0x3b, 0x3e, - 0xbc, 0xa7, 0xe5, 0x4c, 0xc1, 0xa1, 0x2d, 0x12, 0x7b, 0x57, 0xc8, 0x13, 0x89, 0x76, - 0xe7, 0x91, 0x01, 0x3b, 0x01, 0x5f, 0x06, 0xa6, 0x24, 0xf5, 0x21, 0xb6, 0xee, 0x04, - 0xec, 0x98, 0x08, 0x93, 0xc7, 0xe5, 0xe0, 0x1a, 0x33, 0x62, 0x03, 0x59, 0x40, 0x94, - 0xf8, 0x28, 0x33, 0xd7, 0x44, 0x27, 0x88, 0x00, 0x84, 0xd3, 0x58, 0x63, 0xc8, 0xe7, - 0xeb, 0xb5, 0xc9, 0xee, 0xd9, 0x8e, 0x72, 0x57, 0x2e, 0xc4, 0x0c, 0x79, 0xb2, 0x66, - 0x23, 0xb5, 0x80, 0x22, 0xf4, 0x89, 0xb0, 0x89, 0x3d, 0x88, 0xbe, 0x63, 0xf3, 0xf8, - 0xc0, 0xd2, 0x32, 0x49, 0xeb, 0xcd, 0xe1, 0x3d, 0xb9, 0x31, 0x29, 0x41, 0xc3, 0x6c, - 0x1d, 0x1c, 0xbc, 0xab, 0xac, 0x0c, 0x78, 0xcb, 0x3b, 0x19, 0x12, 0xdb, 0x0d, 0xcb, - 0xfe, 0x18, 0x93, 0xd9, 0xb5, 0x1b, 0xe4, 0xaf, 0x1d, 0x00, 0x0b, 0xac, 0x1a, 0xd0, - 0xa3, 0xae, 0x2c, 0xe1, 0xe7, 0x32, 0x25, 0xfb, 0x11, 0x4d, 0x05, 0xaf, 0x4c, 0xef, - 0xc0, 0x6e, 0x87, 0x5f, 0x07, 0x4f, 0xfe, 0xae, 0x0c, 0xba, 0x7d, 0xa3, 0xa5, 0x16, - 0xc1, 0x73, 0xbe, 0x1c, 0x51, 0x33, 0x23, 0xe1, 0x19, 0xf6, 0x35, 0xe8, 0x20, 0x9a, - 0x07, 0x4b, 0x21, 0x6b, 0x70, 0x23, 0xfa, 0xdc, 0x2d, 0x25, 0x94, 0x9c, 0x90, 0x03, - 0x7e, 0x71, 0xe3, 0xe5, 0x50, 0x72, 0x6d, 0x21, 0x0a, 0x2c, 0x68, 0x83, 0x42, 0xe5, - 0x24, 0x40, 0x63, 0x5e, 0x9c, 0xc1, 0x4a, 0xfe, 0x10, 0x10, 0x26, 0x21, 0xa9, 0xc9, - 0xac, 0xcb, 0x78, 0x2e, 0x9e, 0x4a, 0x5f, 0xa8, 0x7f, 0x0a, 0x95, 0x6f, 0x5b, 0x85, - 0x50, 0x99, 0x60, 0x28, 0x5c, 0x22, 0x62, 0x7c, 0x59, 0x48, 0x3a, 0x5a, 0x4c, 0x28, - 0xcc, 0xe4, 0xb1, 0x56, 0xe5, 0x51, 0x40, 0x6a, 0x7e, 0xe8, 0x35, 0x56, 0x56, 0xa2, - 0x1e, 0x43, 0xe3, 0x8c, 0xe1, 0x29, 0xfd, 0xad, 0xb7, 0x59, 0xed, 0xdf, 0xa0, 0x8f, - 0x00, 0xfc, 0x8e, 0x56, 0x7c, 0xef, 0x93, 0xc6, 0x79, 0x2d, 0x01, 0xdf, 0x05, 0xe6, - 0xd5, 0x80, 0xf4, 0xd5, 0xd4, 0x8d, 0xf0, 0x42, 0x45, 0x1a, 0x33, 0x59, 0x0d, 0x3e, - 0x8c, 0xf4, 0x9b, 0x26, 0x27, 0x21, 0x8f, 0x0c, 0x29, 0x2f, 0xa6, 0x6a, 0xda, 0x94, - 0x5f, 0xa5, 0x5b, 0xb2, 0x35, 0x48, 0xe3, 0x3a, 0x83, 0xa5, 0x62, 0x95, 0x7a, 0x31, - 0x49, 0xa9, 0x93, 0xcc, 0x47, 0x23, 0x62, 0x29, 0x87, 0x36, 0xa8, 0xb7, 0x78, 0xd9, - 0x7c, 0xe4, 0x23, 0x01, 0x3d, 0x64, 0xb3, 0x2c, 0xd1, 0x72, 0xef, 0xa5, 0x51, 0xbf, - 0x7f, 0x36, 0x8f, 0x04, 0xbd, 0xae, 0xc6, 0x09, 0x1a, 0x30, 0x04, 0xa7, 0x57, 0x59, - 0x8b, 0x80, 0x1d, 0xcf, 0x67, 0x5c, 0xb8, 0x3e, 0x43, 0xa5, 0x3a, 0xe8, 0xb2, 0x54, - 0xd3, 0x33, 0xbc, 0xda, 0x20, 0xd4, 0x81, 0x7d, 0x34, 0x77, 0xab, 0xfb, 0xa2, 0x5b, - 0xb8, 0x3d, 0xf5, 0x94, 0x9c, 0x12, 0x6f, 0x14, 0x9b, 0x1d, 0x99, 0x34, 0x1e, 0x4e, - 0x6f, 0x91, 0x20, 0xf4, 0xd4, 0x1e, 0x62, 0x91, 0x85, 0x00, 0x2c, 0x72, 0xc0, 0x12, - 0xc4, 0x14, 0xd2, 0x38, 0x2a, 0x6d, 0x47, 0xc7, 0xb3, 0xde, 0xab, 0xa7, 0x70, 0xc4, - 0x00, 0xca, 0x96, 0xb2, 0x81, 0x4f, 0x6b, 0x26, 0xc3, 0xef, 0x17, 0x42, 0x9f, 0x1a, - 0x98, 0xc8, 0x5d, 0x83, 0xdb, 0x20, 0xef, 0xad, 0x48, 0xbe, 0x89, 0x96, 0xfb, 0x1b, - 0xff, 0x59, 0x1e, 0xff, 0xf3, 0x60, 0xfe, 0x11, 0x99, 0x05, 0x6c, 0x56, 0xe5, 0xfe, - 0xec, 0x61, 0xa7, 0xb8, 0xb9, 0xf6, 0x99, 0xd6, 0x01, 0x2c, 0x28, 0x49, 0x23, 0x2f, - 0x32, 0x9f, 0xef, 0x95, 0xc7, 0xaf, 0x37, 0x00, 0x98, 0xff, 0xe4, 0x91, 0x8e, 0x0c, - 0xa1, 0xdf, 0x47, 0xf2, 0x75, 0x86, 0x7b, 0x73, 0x9e, 0x0a, 0x51, 0x4d, 0x32, 0x09, - 0x32, 0x5e, 0x21, 0x70, 0x45, 0x92, 0x7b, 0x47, 0x9c, 0x1c, 0xe2, 0xe5, 0xd5, 0x4f, - 0x25, 0x48, 0x8c, 0xad, 0x15, 0x13, 0xe3, 0xf4, 0x4a, 0x21, 0x26, 0x6c, 0xfd, 0x84, - 0x16, 0x33, 0x32, 0x7d, 0xee, 0x6c, 0xf8, 0x10, 0xfb, 0xf7, 0x39, 0x3e, 0x31, 0x7d, - 0x9e, 0x53, 0xd1, 0xbe, 0x1d, 0x5a, 0xe7, 0x83, 0x9b, 0x66, 0xb9, 0x43, 0xb9, 0xed, - 0x18, 0xf2, 0xc5, 0x30, 0xe9, 0x75, 0x42, 0x23, 0x32, 0xc3, 0x43, 0x9c, 0xce, 0x49, - 0xa2, 0x9f, 0x2a, 0x33, 0x6a, 0x48, 0x51, 0x26, 0x3c, 0x5e, 0x9b, 0xd1, 0x3d, 0x73, - 0x11, 0x09, 0xe8, 0x44, 0xb7, 0xf8, 0xc3, 0x92, 0xa5, 0xc1, 0xdc, 0xaa, 0x2a, 0xe5, - 0xf5, 0x0f, 0xf6, 0x3f, 0xab, 0x97, 0x65, 0xe0, 0x16, 0x70, 0x2c, 0x35, 0xa6, 0x7c, - 0xd7, 0x36, 0x4d, 0x3f, 0xab, 0x55, 0x2f, 0xb3, 0x49, 0xe3, 0x5c, 0x15, 0xc5, 0x02, - 0x50, 0x45, 0x3f, 0xd1, 0x8f, 0x7b, 0x85, 0x59, 0x92, 0x63, 0x2e, 0x2c, 0x76, 0xc0, - 0xfb, 0xf1, 0xef, 0x96, 0x3e, 0xa8, 0x0e, 0x32, 0x23, 0xde, 0x32, 0x77, 0xbc, 0x55, - 0x92, 0x51, 0x72, 0x58, 0x29, 0xec, 0x03, 0xf2, 0x13, 0xba, 0x89, 0x55, 0xca, 0xb2, - 0x82, 0x2f, 0xf2, 0x1a, 0x9b, 0x0a, 0x49, 0x04, 0xd6, 0x68, 0xfc, 0xd7, 0x72, 0x24, - 0xbd, 0xe3, 0xdd, 0x01, 0xf6, 0xff, 0xc4, 0x82, 0x8f, 0x6b, 0x64, 0x23, 0x0b, 0x35, - 0xc6, 0xa0, 0x49, 0x87, 0x34, 0x94, 0x27, 0x6e, 0xa1, 0xd7, 0xed, 0x5e, 0x92, 0xcb, - 0x4f, 0x90, 0xba, 0x83, 0xa9, 0xe4, 0x96, 0x01, 0xb1, 0x94, 0x04, 0x2f, 0x29, 0x00, - 0xd9, 0x9d, 0x31, 0x2d, 0x7b, 0x70, 0x50, 0x8c, 0xf1, 0x76, 0x06, 0x6d, 0x15, 0x4d, - 0xbe, 0x96, 0xef, 0x9d, 0x43, 0x67, 0xe4, 0xc8, 0x40, 0xe4, 0xa1, 0x7b, 0x5e, 0x51, - 0x22, 0xe8, 0xeb, 0xe2, 0x15, 0x8a, 0x3c, 0x5f, 0x4c, 0xba, 0xe2, 0x1e, 0xa3, 0xfa, - 0x1a, 0xe6, 0xc2, 0x5a, 0x94, 0x62, 0xeb, 0xcb, 0xb0, 0xfd, 0x5f, 0x14, 0x55, 0x4b, - 0xc9, 0x77, 0x47, 0xc3, 0x3e, 0x34, 0xda, 0x90, 0xc8, 0x16, 0xd8, 0xd0, 0xd5, 0x0b, - 0xfe, 0x37, 0x61, 0x8c, 0x58, 0x12, 0x89, 0x14, 0x84, 0xfa, 0x25, 0x93, 0x22, 0xc1, - 0x50, 0x92, 0xd4, 0x15, 0x5d, 0x86, 0x96, 0xd6, 0xf1, 0x2f, 0x24, 0xfd, 0x36, 0x44, - 0x96, 0xb3, 0xbe, 0x08, 0x71, 0xca, 0x3d, 0xd9, 0x62, 0x53, 0x48, 0xa6, 0x14, 0xb5, - 0x9b, 0xde, 0x45, 0x88, 0x56, 0x49, 0xba, 0xe3, 0x6d, 0xe3, 0x4d, 0xef, 0x8f, 0xce, - 0xc8, 0x53, 0x43, 0x47, 0x5d, 0x97, 0x6a, 0xe1, 0xe9, 0xb2, 0x78, 0x29, 0xce, 0x2a, - 0xc5, 0xef, 0xd0, 0xb3, 0x99, 0xa8, 0xb4, 0x48, 0xbe, 0x65, 0x04, 0x29, 0x4e, 0xe6, - 0xb3, 0xc1, 0xc6, 0xa5, 0x34, 0x2d, 0x7c, 0x01, 0xae, 0x9d, 0x8a, 0xd3, 0x07, 0x0c, - 0x2b, 0x1a, 0x91, 0x57, 0x3a, 0xf5, 0xe0, 0xc5, 0xe4, 0xcb, 0xbf, 0x4a, 0xcd, 0xc6, - 0xb5, 0x4c, 0x92, 0x72, 0x20, 0x0d, 0x99, 0x70, 0x25, 0x0c, 0x17, 0xc1, 0x03, 0x6f, - 0x06, 0x08, 0x5c, 0x41, 0x85, 0x8e, 0xd3, 0xa0, 0xc4, 0x81, 0x50, 0xbc, 0x69, 0x7e, - 0x4a, 0x69, 0x5f, 0xef, 0x33, 0x5f, 0x7a, 0xd0, 0x7e, 0x1a, 0x46, 0xdc, 0x76, 0x7f, - 0xf8, 0x22, 0xdb, 0x70, 0xe6, 0x66, 0x90, 0x80, 0xb9, 0x81, 0x6b, 0x22, 0x32, 0xc8, - 0x1a, 0x4c, 0x66, 0xcc, 0x58, 0x6a, 0xbf, 0xe1, 0xea, 0xa8, 0xca, 0x6c, 0xf4, 0x1f, - 0xc3, 0x0e, 0xb8, 0xdc, 0x57, 0xc3, 0x7a, 0x3c, 0x39, 0xc5, 0x9c, 0x94, 0x23, 0x2d, - 0xf9, 0xd3, 0x88, 0xdb, 0xfa, 0x35, 0xc2, 0xcd, 0x5c, 0x75, 0xf3, 0x28, 0xe9, 0xfe, - 0xa7, 0x8f, 0x65, 0x56, 0x8f, 0x2b, 0xb9, 0x34, 0xc8, 0x2c, 0x41, 0x42, 0xda, 0x69, - 0xd1, 0x2c, 0xa7, 0xde, 0x9a, 0x7d, 0xf7, 0x06, 0x40, 0x0e, 0xc7, 0x98, 0x78, 0xd8, - 0x68, 0xe1, 0x7e, 0x8f, 0x71, 0xea, 0x31, 0x49, 0x5a, 0x8b, 0xae, 0x7b, 0xdc, 0x2e, - 0x48, 0xb5, 0x11, 0x87, 0x71, 0xc2, 0xfc, 0xa0, 0x78, 0xcc, 0xa1, 0xfc, 0xe0, 0xd7, - 0xef, 0x0a, 0xf3, 0x47, 0x8c, 0xf3, 0x6f, 0x69, 0xe8, 0x5a, 0x41, 0xdd, 0x29, 0xb4, - 0x29, 0x4a, 0x65, 0xd3, 0xe0, 0x55, 0xff, 0x71, 0x8d, 0xd9, 0xdc, 0x8c, 0x75, 0xe7, - 0xe5, 0xb2, 0xef, 0xe4, 0x42, 0x63, 0x73, 0x71, 0xb7, 0xc4, 0x8f, 0x6e, 0xe9, 0x9e, - 0x3e, 0xa3, 0x8a, 0x4b, 0x0f, 0x2f, 0x67, 0xfc, 0x2b, 0x90, 0x8c, 0xda, 0x65, 0x7e, - 0xae, 0x75, 0x4e, 0x03, 0x7e, 0x26, 0x2e, 0x9a, 0x9f, 0x9b, 0xd7, 0xec, 0x42, 0x67, - 0xed, 0x8e, 0x96, 0x93, 0x0e, 0x10, 0x84, 0x78, 0x3c, 0x37, 0xd6, 0xf9, 0xdd, 0x15, - 0xfd, 0x29, 0xf4, 0xcc, 0x47, 0x7e, 0x66, 0xf1, 0x30, 0xd6, 0x30, 0x43, 0x0d, 0xcc, - 0x01, 0x04, 0x89, 0x9b, 0x4f, 0x9f, 0x46, 0xeb, 0x09, 0x0e, 0xf7, 0xfc, 0x90, 0xb4, - 0x79, 0xab, 0xf6, 0x1f, 0x93, 0x95, 0x5e, 0xe0, 0x0e, 0x6a, 0x18, 0x48, 0xf1, 0xab, - 0x14, 0xad, 0x33, 0x4f, 0x2b, 0x68, 0x03, 0x58, 0x08, 0xcd, 0xf1, 0xbb, 0x9e, 0x9d, - 0x9a, 0x81, 0x6b, 0xaf, 0x72, 0x8a, 0x95, 0x5b, 0x96, 0x0b, 0x77, 0x01, 0xfa, 0x62, - 0x66, 0x87, 0xdc, 0x3c, 0x9c, 0xba, 0x64, 0x63, 0x37, 0xb5, 0x3e, 0x29, 0x81, 0x6e, - 0x94, 0x82, 0xdd, 0xf5, 0x57, 0x8a, 0x87, 0x68, 0xaa, 0xe4, 0x77, 0xfc, 0xe4, 0x10, - 0xac, 0x2d, 0x5d, 0xe6, 0x09, 0x58, 0x61, 0xc1, 0x11, 0xd7, 0xfe, 0xb3, 0xe6, 0xbb, - 0x4f, 0xbb, 0x5a, 0x54, 0x95, 0x54, 0x95, 0x97, 0x27, 0x98, 0x35, 0x0a, 0x25, 0x3f, - 0x05, 0xf6, 0x6c, 0x2e, 0xcf, 0xcb, 0xc0, 0xed, 0x43, 0xf5, 0xec, 0x2e, 0x6d, 0x8d, - 0xba, 0x15, 0xa5, 0x12, 0x54, 0xd9, 0x7b, 0x18, 0x21, 0x10, 0x7c, 0x07, 0xdd, 0x9a, - 0x16, 0xef, 0x84, 0x06, 0xf9, 0x43, 0xe2, 0x82, 0xb9, 0x5d, 0x4b, 0x36, 0x25, 0x30, - 0xc9, 0x13, 0xd6, 0xba, 0x42, 0x1d, 0xf6, 0x02, 0x7d, 0xe5, 0xaf, 0x1e, 0x47, 0x45, - 0xd5, 0x86, 0x81, 0x06, 0x95, 0x4b, 0xe6, 0xc1, 0x96, 0x27, 0x80, 0xa2, 0x94, 0x10, - 0x72, 0xe9, 0x51, 0x31, 0xb1, 0x67, 0x9d, 0xf0, 0x63, 0x76, 0x25, 0x04, 0x2c, 0x37, - 0xd4, 0x8f, 0xfb, 0x15, 0x2e, 0x5e, 0xbc, 0x18, 0x5c, 0x8a, 0x2b, 0x7d, 0x43, 0x85, - 0xf1, 0xc9, 0x5a, 0xf9, 0x37, 0xdf, 0x78, 0xdf, 0xd8, 0x75, 0x7f, 0xab, 0x43, 0x49, - 0x68, 0xb0, 0xb5, 0x7c, 0x66, 0x57, 0x44, 0x68, 0xf1, 0x60, 0xb4, 0x47, 0xac, 0x82, - 0x21, 0xe5, 0x06, 0x06, 0x76, 0xa8, 0x42, 0xa1, 0xc6, 0xb7, 0x17, 0x2d, 0xd3, 0x34, - 0x0f, 0x76, 0x40, 0x70, 0xab, 0x1f, 0xe0, 0x91, 0xc5, 0xc7, 0x4c, 0x95, 0xa5, 0xdc, - 0x04, 0x33, 0x90, 0x72, 0x3a, 0x4c, 0x12, 0x7d, 0xa1, 0x4c, 0xdd, 0xe1, 0xdc, 0x26, - 0x75, 0xa6, 0x23, 0x40, 0xb3, 0xe6, 0xaf, 0xd0, 0x52, 0x2a, 0x31, 0xde, 0x26, 0xe7, - 0xd1, 0xec, 0x3a, 0x9c, 0x8a, 0x09, 0x1f, 0xfd, 0xc7, 0x5b, 0x7e, 0xcf, 0xdc, 0x7c, - 0x12, 0x99, 0x5a, 0x5e, 0x37, 0xce, 0x34, 0x88, 0xbd, 0x29, 0xf8, 0x62, 0x9d, 0x68, - 0xf6, 0x96, 0x49, 0x24, 0x48, 0xdd, 0x52, 0x66, 0x97, 0x47, 0x6d, 0xc0, 0x61, 0x34, - 0x6e, 0xbe, 0x3f, 0x67, 0x72, 0x17, 0xff, 0x9c, 0x60, 0xef, 0xce, 0x94, 0x3a, 0xf2, - 0x8d, 0xfd, 0x3f, 0x9e, 0x59, 0x69, 0x25, 0x98, 0xa6, 0x04, 0x7c, 0x23, 0xc4, 0xc0, - 0x14, 0x00, 0xf1, 0xab, 0x57, 0x30, 0xea, 0xc0, 0xae, 0x8d, 0x58, 0x43, 0xd5, 0x05, - 0x1c, 0x37, 0x62, 0x40, 0x17, 0x2a, 0xf2, 0x18, 0xd7, 0xa1, 0xec, 0xfe, 0x65, 0xb4, - 0xf7, 0x51, 0x00, 0x63, 0x89, 0x83, 0xc1, 0x4d, 0xe4, 0x97, 0x47, 0x55, 0xda, 0xde, - 0x80, 0x18, 0xc9, 0xb8, 0xf4, 0x54, 0x3f, 0xb0, 0x95, 0x96, 0x15, 0x13, 0xe6, 0x7c, - 0x61, 0xdb, 0xc5, 0x9c, 0x60, 0x7f, 0x9b, 0x51, 0xf8, 0xd0, 0x9b, 0xdc, 0xad, 0x28, - 0xbc, 0xfb, 0x9e, 0x5d, 0x27, 0x44, 0xea, 0x88, 0x48, 0xb2, 0x62, 0x3a, 0xc0, 0x7f, - 0x8e, 0xf6, 0x1a, 0x81, 0xa3, 0x59, 0x10, 0xb8, 0xa1, 0xba, 0xf3, 0x9a, 0x91, 0x9a, - 0x7b, 0x60, 0xbc, 0x60, 0x4d, 0x63, 0x18, 0x5f, 0x75, 0x92, 0x21, 0xd8, 0x47, 0xcc, - 0x54, 0xa2, 0x27, 0x65, 0xa4, 0xc3, 0x34, 0x75, 0xb5, 0x79, 0x1e, 0x9a, 0xf3, 0x27, - 0x1f, 0xc8, 0xd9, 0x35, 0x06, 0x67, 0x09, 0x0d, 0x81, 0x84, 0xec, 0x50, 0x52, 0x2d, - 0x80, 0x4f, 0x23, 0xc4, 0xfb, 0x44, 0xff, 0xa4, 0x81, 0xbc, 0x92, 0xae, 0x40, 0x8d, - 0x1b, 0x9f, 0x2b, 0x13, 0x19, 0x04, 0xf9, 0x70, 0x5c, 0x59, 0xe2, 0xf4, 0xbd, 0xe7, - 0xa3, 0xb2, 0xc0, 0x85, 0xd9, 0x3f, 0xd2, 0xab, 0xc5, 0xe1, 0x4d, 0x16, 0x30, 0x01, - 0xa1, 0x2f, 0x51, 0x93, 0x8d, 0x02, 0x1a, 0xfa, 0x92, 0x23, 0x9b, 0x87, 0x3d, 0xc6, - 0xc3, 0x57, 0xea, 0xa8, 0xaf, 0x4e, 0xe6, 0xd0, 0x05, 0x40, 0x65, 0x7f, 0xe3, 0x29, - 0x14, 0x10, 0x3b, 0x5d, 0x98, 0xf6, 0x8b, 0xd3, 0xe2, 0xb5, 0x35, 0x9f, 0x08, 0xcc, - 0xd8, 0x8d, 0x0c, 0x81, 0x1e, 0x4c, 0x31, 0xfb, 0xb4, 0x9f, 0x3a, 0x90, 0xbb, 0xd0, - 0x5d, 0xce, 0x62, 0xf3, 0x44, 0xe7, 0x07, 0x75, 0x93, 0x15, 0x9a, 0xe3, 0x50, 0x50, - 0xb0, 0x4c, 0x9e, 0x6b, 0x86, 0xbc, 0x43, 0x2d, 0xc8, 0xb0, 0x48, 0xc7, 0x3c, 0x00, - 0x18, 0xca, 0x5b, 0x69, 0x41, 0x12, 0x97, 0x73, 0x2a, 0x4e, 0x1a, 0xa9, 0x9a, 0x92, - 0x8c, 0x71, 0xe7, 0xa2, 0x4f, 0xd2, 0x77, 0x85, 0x6a, 0xa4, 0x25, 0x01, 0xe5, 0x1b, - 0x01, 0x2a, 0xea, 0x94, 0x46, 0xa2, 0x10, 0x4e, 0x93, 0xf8, 0x15, 0xa0, 0xb3, 0xa2, - 0x9b, 0x45, 0x83, 0x14, 0xf3, 0xd8, 0xbe, 0x2b, 0x98, 0x23, 0xd3, 0x42, 0xf4, 0x62, - 0x13, 0xe9, 0x42, 0xa7, 0xe1, 0x9a, 0x46, 0xe9, 0x70, 0xb5, 0xc5, 0x06, 0x70, 0x84, - 0x30, 0x31, 0x7b, 0x1b, 0xb3, 0xb3, 0x5d, 0xf6, 0x8a, 0xe3, 0x3a, 0x49, 0x26, 0xa0, - 0x3e, 0x6b, 0xfe, 0xb5, 0x51, 0x04, 0x16, 0xfc, 0xbb, 0x05, 0x24, 0xc9, 0xca, 0x50, - 0x74, 0x15, 0x6c, 0xc5, 0xa5, 0xd6, 0xfe, 0x1c, 0x99, 0x5e, 0xdc, 0x60, 0xa2, 0xf5, - 0x50, 0x41, 0x1a, 0xa4, 0x1e, 0x3d, 0xa3, 0xbd, 0xcf, 0x64, 0xbc, 0xf0, 0x4a, 0x05, - 0x10, 0x57, 0x1b, 0x93, 0x6d, 0x47, 0xe5, 0x5c, 0xec, 0x03, 0x30, 0x00, 0x8d, 0xfe, - 0x73, 0x56, 0x34, 0x04, 0xf0, 0x47, 0xd7, 0xf3, 0xa8, 0xa3, 0xd7, 0x74, 0x3b, 0xc5, - 0x54, 0x95, 0x52, 0x10, 0xf1, 0xeb, 0x0d, 0x08, 0x59, 0x9e, 0xa7, 0x7d, 0x5f, 0x97, - 0x4d, 0x87, 0x17, 0x6d, 0x37, 0xd9, 0x8b, 0x9c, 0x0a, 0xd4, 0x40, 0x40, 0x72, 0x09, - 0xed, 0x6a, 0x9f, 0x08, 0x46, 0x4d, 0x56, 0x55, 0x93, 0xe1, 0xa6, 0x3b, 0x93, 0x85, - 0x36, 0xb4, 0x92, 0x44, 0xe9, 0x7d, - ], - script_code: vec![], - transparent_input: Some(1), - hash_type: 2, - amount: 652655344020909, - consensus_branch_id: 1991772603, - sighash: [ - 0xbb, 0xe6, 0xd8, 0x4f, 0x57, 0xc5, 0x6b, 0x29, 0xb9, 0x14, 0xc6, 0x94, 0xba, 0xac, - 0xcb, 0x89, 0x12, 0x97, 0xe9, 0x61, 0xde, 0x3e, 0xb4, 0x6c, 0x68, 0xe3, 0xc8, 0x9c, - 0x47, 0xb1, 0xa1, 0xdb, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x01, 0x46, 0xcf, 0x28, 0x9b, 0x7d, - 0x89, 0x13, 0x07, 0xbb, 0xa3, 0x70, 0x54, 0xcf, 0x91, 0xb3, 0x1f, 0xc8, 0x2f, 0x74, - 0xd5, 0xfc, 0xc0, 0x00, 0x94, 0x2e, 0xde, 0x91, 0x18, 0x25, 0xf5, 0x3f, 0xe6, 0x09, - 0x68, 0x6f, 0x46, 0x00, 0x23, 0xb1, 0xe9, 0xbc, 0x00, 0xbd, 0xe8, 0x95, 0xd1, 0x23, - 0x8f, 0xad, 0x04, 0xab, 0xa9, 0x88, 0x99, 0x66, 0x7d, 0x01, 0x00, 0x04, 0xea, 0x42, - 0x71, 0x76, 0x09, 0x84, 0x13, 0x90, 0x59, 0x18, 0xee, 0x21, 0x3d, 0x4e, 0xc1, 0x27, - 0x94, 0x74, 0x2d, 0x19, 0xf6, 0x7d, 0x6f, 0x86, 0xce, 0xf7, 0xe6, 0x98, 0x2e, 0x88, - 0x41, 0x71, 0x28, 0x73, 0xa0, 0x1d, 0x92, 0x51, 0xd8, 0xc8, 0x60, 0xc0, 0x41, 0x52, - 0x5b, 0x3b, 0xf4, 0xe3, 0xa2, 0xeb, 0x92, 0x72, 0x81, 0x5c, 0x75, 0x86, 0x76, 0x84, - 0x28, 0xb4, 0xc2, 0xb2, 0x5e, 0x37, 0x45, 0xf0, 0x09, 0xc5, 0xdc, 0xe2, 0x0b, 0x69, - 0xd5, 0xd7, 0xc4, 0x3c, 0xeb, 0x73, 0x6b, 0x68, 0x31, 0xe8, 0xc1, 0x10, 0xf1, 0x6c, - 0xfd, 0xb3, 0xa4, 0x67, 0xe9, 0x41, 0x4c, 0x00, 0xec, 0xf1, 0x37, 0x31, 0x50, 0x08, - 0x94, 0x55, 0x56, 0x78, 0xc4, 0x97, 0xfa, 0xba, 0x9a, 0x95, 0xd0, 0x1c, 0xc4, 0x64, - 0x39, 0x0f, 0xc4, 0xa7, 0x6b, 0xfa, 0x8b, 0x0e, 0x1c, 0x68, 0xa5, 0x25, 0xd7, 0x06, - 0xd6, 0x60, 0x4b, 0x23, 0x30, 0xb6, 0xb3, 0x48, 0x52, 0x15, 0xf6, 0x06, 0xf1, 0x88, - 0x3a, 0x75, 0x15, 0x88, 0xc7, 0xef, 0xa5, 0x06, 0xc3, 0xe8, 0xd0, 0xc6, 0x01, 0x92, - 0xe8, 0x47, 0x6b, 0xd1, 0x17, 0x5d, 0x95, 0x62, 0x08, 0x7b, 0xdb, 0x81, 0x8e, 0x66, - 0x21, 0x62, 0x86, 0xba, 0xfe, 0x47, 0xff, 0x4d, 0xbc, 0xce, 0xd5, 0x14, 0x44, 0x48, - 0x0a, 0x9a, 0x56, 0x73, 0xec, 0xe7, 0xfa, 0xc7, 0x3a, 0x0e, 0xd4, 0x1a, 0xb0, 0x05, - 0x17, 0x53, 0xa7, 0xca, 0xa8, 0x9b, 0xe3, 0x13, 0x9a, 0xfd, 0x97, 0x93, 0xb3, 0xe0, - 0x2f, 0x27, 0xf0, 0x40, 0x04, 0x65, 0x95, 0xac, 0xd4, 0x7b, 0xf1, 0x3f, 0xd0, 0xda, - 0x27, 0xf0, 0x9e, 0xda, 0x48, 0x03, 0x6d, 0x3e, 0xe4, 0x37, 0xf2, 0xee, 0x8f, 0x86, - 0x06, 0xea, 0x97, 0x34, 0x3c, 0x33, 0x58, 0x46, 0x57, 0xf4, 0x6d, 0xba, 0x99, 0xdb, - 0x5c, 0xfe, 0x6c, 0xa1, 0x76, 0xfa, 0xb7, 0xb0, 0xf3, 0xbf, 0xa0, 0xab, 0x61, 0xe3, - 0x40, 0xc3, 0x4e, 0xb9, 0xf1, 0x7c, 0x7e, 0xc2, 0xbe, 0x03, 0xb1, 0x80, 0xf0, 0xbb, - 0x6f, 0x43, 0x4c, 0x2a, 0x65, 0x42, 0xe0, 0x0e, 0x84, 0x37, 0x3f, 0x4f, 0x46, 0x49, - 0xcd, 0xa3, 0x2b, 0xf6, 0x86, 0x66, 0x61, 0x43, 0xf6, 0x22, 0xaa, 0x48, 0x04, 0x60, - 0xb5, 0xaf, 0xac, 0x51, 0x86, 0x07, 0xcd, 0x9a, 0xf8, 0xbc, 0xd6, 0xb5, 0x8c, 0x30, - 0x12, 0x73, 0x16, 0xb2, 0x5d, 0x5e, 0xa7, 0xbf, 0x6b, 0x0c, 0xab, 0x85, 0x42, 0xff, - 0x69, 0xd9, 0xb2, 0xf1, 0x80, 0xbe, 0x12, 0xed, 0x75, 0x34, 0x4a, 0x39, 0x5a, 0xa1, - 0x0f, 0x85, 0x2f, 0x08, 0x3a, 0xd6, 0x4e, 0xf4, 0x0e, 0x9c, 0x03, 0x09, 0xe9, 0xbb, - 0xa5, 0x4b, 0x8c, 0xb3, 0x3c, 0x95, 0x49, 0x8a, 0x69, 0x53, 0x8d, 0x3a, 0xe5, 0xb2, - 0x5e, 0x24, 0x70, 0x98, 0xe1, 0x11, 0x7c, 0x91, 0x8a, 0xaa, 0xae, 0x9c, 0xb6, 0xef, - 0x77, 0xab, 0xd1, 0xe0, 0x1c, 0xc7, 0x43, 0xd0, 0xdd, 0xd0, 0x22, 0x75, 0x95, 0x1b, - 0x92, 0x49, 0x95, 0x65, 0xce, 0x83, 0x1f, 0x30, 0x32, 0xb8, 0x50, 0x57, 0x75, 0x10, - 0x8d, 0xc8, 0x5e, 0x2a, 0xde, 0x2e, 0xac, 0x1e, 0x63, 0x6e, 0x1a, 0xf4, 0x05, 0x4c, - 0x8b, 0x6f, 0x57, 0x63, 0x2d, 0xf2, 0x69, 0xc3, 0x72, 0x3b, 0x32, 0x08, 0x72, 0xe4, - 0xc5, 0x7b, 0x21, 0x83, 0x58, 0xdc, 0x7e, 0x99, 0x05, 0xbb, 0x04, 0xed, 0xf9, 0x2e, - 0xdf, 0x0d, 0xf6, 0x35, 0xf3, 0xbf, 0x36, 0x1e, 0x57, 0xa1, 0x32, 0x96, 0xe1, 0x44, - 0x7a, 0xf5, 0xa5, 0x66, 0x65, 0x17, 0xbc, 0xd3, 0x56, 0x76, 0x21, 0xa7, 0xcf, 0x84, - 0x45, 0x58, 0x96, 0x53, 0x26, 0x20, 0x20, 0xc3, 0x3b, 0xf7, 0x80, 0x31, 0xb8, 0xee, - 0x07, 0x07, 0xde, 0x07, 0x20, 0x68, 0xc1, 0x70, 0x57, 0x03, 0x27, 0xe6, 0xd9, 0xf5, - 0xc6, 0xdd, 0xc3, 0x35, 0x40, 0x2e, 0xfc, 0x54, 0x88, 0x62, 0xf5, 0xa0, 0x70, 0x94, - 0xfd, 0x42, 0x8a, 0x7b, 0xbc, 0x15, 0xd7, 0xb3, 0x8d, 0x05, 0x36, 0x2c, 0x9c, 0xa9, - 0x85, 0xf5, 0x8a, 0x76, 0x64, 0x7d, 0x2b, 0xe4, 0xc2, 0xcd, 0x6b, 0x3d, 0x17, 0xd6, - 0x87, 0x09, 0x71, 0xd7, 0xa0, 0x98, 0xba, 0xf7, 0x2c, 0x6f, 0x6f, 0x12, 0x14, 0xcf, - 0x1f, 0xaa, 0xe4, 0x88, 0xbd, 0x7d, 0xe2, 0x59, 0xd3, 0x41, 0x5c, 0x2f, 0x0d, 0xde, - 0xc7, 0x45, 0x70, 0x04, 0xf3, 0x57, 0x08, 0xd1, 0xec, 0xcc, 0xcc, 0x0d, 0xf6, 0x5a, - 0x04, 0x94, 0x3a, 0xd5, 0xcb, 0xc1, 0x3f, 0x29, 0x5f, 0x00, 0x0f, 0xe0, 0x56, 0xc4, - 0x0b, 0x2d, 0x88, 0xf2, 0x7d, 0xc3, 0x4c, 0xfe, 0xb8, 0x03, 0xbe, 0x34, 0x83, 0xa9, - 0xeb, 0xf9, 0xb5, 0xa9, 0x02, 0x60, 0x57, 0x72, 0x5d, 0x63, 0xea, 0xd2, 0xc0, 0xc0, - 0xff, 0x1f, 0xe2, 0x6a, 0xc1, 0xe7, 0xbd, 0xfc, 0xd6, 0xfa, 0xd8, 0x75, 0x84, 0x2d, - 0x19, 0x4f, 0x33, 0x17, 0x50, 0x46, 0x2c, 0x06, 0xb8, 0xd7, 0x98, 0x2d, 0x67, 0x99, - 0x5e, 0xd5, 0xd3, 0xae, 0x96, 0xa0, 0x5a, 0xe0, 0x06, 0x7f, 0x4e, 0xb1, 0xc7, 0xc9, - 0x32, 0x31, 0xbd, 0x39, 0x77, 0x3c, 0xbe, 0x0a, 0x9d, 0x66, 0xb0, 0xc9, 0xaa, 0x8c, - 0xff, 0x6a, 0x37, 0x6e, 0x1f, 0x37, 0x2e, 0xac, 0x6a, 0xc4, 0xe4, 0x6c, 0xc0, 0x94, - 0x22, 0x45, 0xd4, 0xc2, 0xdc, 0xf0, 0x2d, 0x76, 0x40, 0xff, 0xcc, 0x5a, 0x6a, 0xc3, - 0xa8, 0x7f, 0x5c, 0x41, 0x15, 0x51, 0xbc, 0xc2, 0xf2, 0x6c, 0xb9, 0x49, 0x61, 0xd5, - 0x3f, 0x95, 0xdd, 0xb1, 0x9a, 0xe9, 0x30, 0xc8, 0xd7, 0x0f, 0x03, 0x1b, 0x29, 0xa5, - 0xdf, 0x99, 0xff, 0x36, 0x69, 0x5e, 0x80, 0x2c, 0xbc, 0xb6, 0xb1, 0xcf, 0x7d, 0xc9, - 0x7a, 0xbb, 0x3b, 0x25, 0x27, 0x64, 0xc0, 0x1a, 0x62, 0x2d, 0xfb, 0x2e, 0xcb, 0x49, - 0xce, 0x71, 0xf7, 0x38, 0x6e, 0x23, 0x89, 0x5b, 0x5a, 0xfe, 0x16, 0x61, 0x98, 0xb6, - 0x7f, 0x5b, 0x42, 0xb2, 0xf6, 0x5e, 0xcd, 0x0f, 0x82, 0x59, 0x54, 0x78, 0xd8, 0x0a, - 0xe5, 0xc8, 0xce, 0xea, 0x12, 0xa1, 0x61, 0xcc, 0xbb, 0x5e, 0xac, 0x09, 0x99, 0x0f, - 0xc6, 0x19, 0xa4, 0x60, 0x80, 0x43, 0x6d, 0xbd, 0x08, 0xd7, 0x47, 0x84, 0xaf, 0x00, - 0x2d, 0x58, 0xe0, 0x6f, 0xaf, 0x7f, 0x3c, 0xea, 0xe7, 0xd3, 0x41, 0x9b, 0x1f, 0xca, - 0x26, 0x5a, 0x55, 0x59, 0xcf, 0x9e, 0x2d, 0x3b, 0x97, 0xb2, 0xa9, 0x9a, 0x9b, 0xa5, - 0xa8, 0x66, 0x58, 0xc3, 0xfd, 0x9e, 0xc5, 0x5b, 0xfa, 0x9b, 0x32, 0x85, 0x67, 0x25, - 0x4a, 0xb3, 0x6d, 0x2c, 0x7f, 0x44, 0xd2, 0xc7, 0xe1, 0x3e, 0xb5, 0x4b, 0xeb, 0x70, - 0xea, 0x8f, 0xa9, 0x4b, 0x6c, 0x6e, 0x01, 0x2d, 0x79, 0xe3, 0xf5, 0x36, 0x89, 0xc2, - 0xb1, 0xa1, 0x8e, 0xaf, 0x2d, 0x47, 0x1d, 0x13, 0xc1, 0xab, 0x39, 0xd9, 0x19, 0x4a, - 0xe8, 0x43, 0xab, 0x1d, 0x28, 0xff, 0xa8, 0xf6, 0x9d, 0xc7, 0xe1, 0x5c, 0xc3, 0x8b, - 0x12, 0xe8, 0xfc, 0xd7, 0x92, 0x55, 0xb7, 0x21, 0x60, 0x56, 0xd9, 0xed, 0xb7, 0x48, - 0x2f, 0xb9, 0x8a, 0xa0, 0x33, 0xb6, 0x5e, 0x51, 0xc1, 0xa0, 0x8b, 0x8a, 0x11, 0xd8, - 0x4d, 0x04, 0x09, 0xb7, 0x34, 0xf4, 0x52, 0xaa, 0xf0, 0xd6, 0xb1, 0x8f, 0x50, 0x25, - 0x86, 0x83, 0xd3, 0xf9, 0xa7, 0x6d, 0x39, 0x9f, 0xd0, 0x47, 0xee, 0xe2, 0x88, 0xbb, - 0x45, 0x85, 0x85, 0x1d, 0xc9, 0x3e, 0xcc, 0xc6, 0x23, 0x22, 0x92, 0x4c, 0xd1, 0x3b, - 0x5d, 0xd4, 0xee, 0xd6, 0x6e, 0xd8, 0xd9, 0x97, 0x2d, 0x77, 0x26, 0x29, 0xea, 0x64, - 0x74, 0x2e, 0x54, 0x73, 0x39, 0x81, 0xb0, 0x06, 0xc0, 0x62, 0x46, 0x8e, 0x4b, 0xd8, - 0xf7, 0xdd, 0x9a, 0xf6, 0x98, 0xf5, 0x2a, 0xe8, 0x14, 0x63, 0x4e, 0x81, 0xd7, 0xf3, - 0xe0, 0xc4, 0x20, 0x31, 0x7c, 0xac, 0xa9, 0xae, 0x48, 0x11, 0xc6, 0xaf, 0x06, 0xfe, - 0x80, 0xa8, 0xc0, 0x2a, 0xb7, 0xa0, 0x0e, 0x18, 0xe4, 0xa6, 0xaa, 0x1e, 0xa1, 0xb7, - 0x69, 0x45, 0xd2, 0x61, 0x5d, 0x43, 0xac, 0x11, 0x8b, 0x56, 0xc2, 0xf2, 0x96, 0x0f, - 0xe9, 0x3a, 0x02, 0x5f, 0x13, 0xec, 0x91, 0xff, 0xc6, 0xd2, 0xc3, 0x53, 0x69, 0x9a, - 0xbb, 0x09, 0x2d, 0xed, 0xc0, 0x65, 0xdb, 0x8f, 0xa2, 0x14, 0xdb, 0xc4, 0x64, 0x66, - 0xf8, 0x97, 0xb8, 0x8c, 0x58, 0xb3, 0x01, 0x52, 0x13, 0x3a, 0xa3, 0x83, 0x1a, 0xf3, - 0x7c, 0x74, 0xd9, 0x9e, 0x9e, 0x36, 0xff, 0x70, 0x11, 0xd3, 0x23, 0x83, 0x05, 0x69, - 0x15, 0x08, 0xd0, 0xf1, 0xf6, 0xaa, 0xaa, 0xa4, 0x25, 0x12, 0x30, 0xc6, 0xcc, 0xc4, - 0x66, 0x68, 0xbb, 0xcf, 0x35, 0xe5, 0xa5, 0xef, 0x2f, 0x86, 0xe6, 0x65, 0xd8, 0xcf, - 0xac, 0x74, 0x76, 0xec, 0xb2, 0x43, 0x78, 0x79, 0x6a, 0x8e, 0xf2, 0xe4, 0xd9, 0x4d, - 0x43, 0x58, 0xbe, 0x2b, 0x47, 0x5f, 0xcc, 0x92, 0xdf, 0x93, 0x82, 0xc5, 0xc0, 0x69, - 0x19, 0xa0, 0xd6, 0x31, 0xec, 0x26, 0x10, 0xfe, 0xdc, 0x21, 0x9b, 0xe6, 0x3f, 0x37, - 0xf2, 0xba, 0x0d, 0x43, 0x23, 0x66, 0x73, 0x6d, 0x86, 0x32, 0xfc, 0xe0, 0x72, 0xb6, - 0xae, 0x5b, 0x6f, 0x3f, 0xd5, 0x9d, 0x3f, 0xaf, 0xf6, 0x38, 0x27, 0x5a, 0x99, 0x2f, - 0xef, 0xc8, 0x7e, 0x60, 0xd4, 0x4c, 0x2c, 0xad, 0xc2, 0xb5, 0xc4, 0x94, 0xe3, 0xe7, - 0x2e, 0xb4, 0x59, 0x7c, 0x96, 0xb4, 0x01, 0x67, 0x79, 0x9a, 0x90, 0x01, 0xa2, 0xed, - 0x36, 0x76, 0xa8, 0xb4, 0x03, 0xae, 0x25, 0xff, 0xd7, 0x72, 0xf7, 0x08, 0x1e, 0x9a, - 0x32, 0xbc, 0xc1, 0xc5, 0xe2, 0xed, 0xd4, 0xe2, 0xa6, 0x57, 0x6b, 0x78, 0x3c, 0xce, - 0x3a, 0xae, 0x11, 0xfa, 0x43, 0x22, 0x62, 0x54, 0x88, 0x56, 0x18, 0x3e, 0xe6, 0x82, - 0xd5, 0xdc, 0x31, 0xbe, 0xb3, 0x8f, 0x06, 0x1c, 0xbd, 0xec, 0xa7, 0x02, 0x1a, 0x44, - 0x4e, 0x2d, 0xd4, 0x17, 0xdf, 0x26, 0xdc, 0xd2, 0x20, 0xf2, 0xb7, 0x31, 0x77, 0x2b, - 0x43, 0x9e, 0x96, 0xd6, 0x14, 0xe1, 0xfa, 0xcb, 0x48, 0x6c, 0x7a, 0x7d, 0x51, 0x71, - 0xb1, 0xde, 0x35, 0x9f, 0x6a, 0xd3, 0xa9, 0x6f, 0x64, 0x9c, 0x96, 0x91, 0x02, 0xa1, - 0x96, 0x4f, 0xb4, 0xb4, 0xa1, 0xa4, 0x27, 0x9c, 0x68, 0xe6, 0xc3, 0x72, 0xe4, 0x21, - 0x87, 0xd7, 0x54, 0xe8, 0x04, 0xa6, 0x16, 0x53, 0x09, 0x20, 0x69, 0xfb, 0x9b, 0x6d, - 0x25, 0x26, 0x68, 0x90, 0x80, 0x8b, 0x01, 0x5d, 0xf2, 0x8c, 0x80, 0x10, 0x65, 0xda, - 0x6f, 0xeb, 0xdc, 0x1a, 0x56, 0xbf, 0xd0, 0x02, 0x62, 0x5a, 0xcf, 0xaa, 0x53, 0x73, - 0xfd, 0xe1, 0x49, 0xc1, 0xcf, 0xc3, 0x64, 0x9b, 0x48, 0x69, 0x69, 0x6d, 0x44, 0xec, - 0xb1, 0x24, 0x79, 0xc5, 0xeb, 0xef, 0x99, 0x5f, 0x10, 0x02, 0x9f, 0x8b, 0x53, 0x0e, - 0xeb, 0x3f, 0xdc, 0x2e, 0x50, 0xe8, 0x75, 0x7f, 0xc0, 0xbb, 0x9e, 0x26, 0x30, 0x23, - 0xdb, 0x82, 0xf8, 0x78, 0xd9, 0xac, 0x7f, 0xfb, 0x0b, 0xd4, 0x39, 0x1d, 0xf1, 0xd8, - 0x79, 0x89, 0x9a, 0x3e, 0xf5, 0x7b, 0xfd, 0x0d, 0x1f, 0x77, 0x55, 0x64, 0x8e, 0xdd, - 0x85, 0xbb, 0x05, 0x2a, 0x6e, 0xdf, 0x71, 0xcd, 0x26, 0x28, 0xc9, 0x87, 0x42, 0x9f, - 0x36, 0xdc, 0x50, 0x5c, 0xcc, 0x43, 0xf3, 0x0e, 0x7a, 0x86, 0x9c, 0x9e, 0x25, 0x5e, - 0x2a, 0xf9, 0xfc, 0xf3, 0x0c, 0x12, 0x17, 0x96, 0x03, 0xae, 0x17, 0x57, 0x55, 0x3b, - 0x5c, 0x94, 0x60, 0x7e, 0x00, 0xd0, 0x32, 0xfb, 0xbe, 0xd2, 0x3c, 0x4c, 0xba, 0xbf, - 0x74, 0x1d, 0x68, 0xaa, 0xb3, 0x0e, 0x0b, 0x8f, 0x15, 0xf4, 0x44, 0xd5, 0x86, 0xb3, - 0xe7, 0xe6, 0x15, 0x9c, 0x46, 0x69, 0x9f, 0x10, 0x07, 0x92, 0xd4, 0x67, 0x29, 0x50, - 0x34, 0x8a, 0x90, 0x55, 0x2e, 0x45, 0x94, 0x3b, 0xee, 0xac, 0xf0, 0x3f, 0x32, 0x16, - 0xf9, 0x4e, 0x27, 0x90, 0x6e, 0xdc, 0x63, 0x23, 0x19, 0xad, 0x8d, 0x37, 0x44, 0x7f, - 0x5c, 0x59, 0xcc, 0xde, 0x35, 0x4f, 0x99, 0xff, 0x6c, 0x7a, 0x76, 0x23, 0xf6, 0xd4, - 0x15, 0x25, 0xa8, 0x09, 0xce, 0x2f, 0x41, 0xec, 0x0f, 0xf7, 0xf1, 0xaf, 0x81, 0xb2, - 0x4c, 0xed, 0x0e, 0xfa, 0x62, 0x13, 0xda, 0x6c, 0x7c, 0x60, 0xc4, 0x87, 0xf5, 0xf7, - 0xb0, 0x3f, 0x81, 0x60, 0xa0, 0x57, 0xf4, 0x6d, 0x05, 0xbf, 0x82, 0x18, 0xb3, 0xad, - 0xd9, 0xc0, 0x68, 0x93, 0xbd, 0x02, 0xdb, 0x9b, 0x61, 0x19, 0x1d, 0xfb, 0x13, 0x3b, - 0xfa, 0xbe, 0x48, 0x58, 0xe4, 0x7a, 0x4c, 0xc3, 0x2e, 0x41, 0x6e, 0xc0, 0x8b, 0x8a, - 0xc7, 0x91, 0x5a, 0x43, 0x73, 0x3f, 0x44, 0x06, 0xe9, 0xd9, 0x67, 0xc5, 0x60, 0xf3, - 0x44, 0xd7, 0xe9, 0x04, 0xa2, 0x80, 0x45, 0xd9, 0x9f, 0x3a, 0xf8, 0xc8, 0x2e, 0x97, - 0xe1, 0xb9, 0xc1, 0xb2, 0x05, 0xe5, 0x85, 0xfb, 0xeb, 0xb4, 0x8f, 0xaf, 0x58, 0xf1, - 0xb6, 0x5d, 0xca, 0x24, 0x97, 0xe0, 0x9a, 0x70, 0xaa, 0xd4, 0x86, 0x5f, 0x85, 0x71, - 0x5a, 0x28, 0x0e, 0x18, 0x6f, 0x3f, 0xc1, 0x74, 0x0d, 0x81, 0x84, 0xd3, 0x3e, 0x83, - 0x22, 0x16, 0x95, 0x21, 0xcd, 0xc1, 0x32, 0x21, 0x29, 0x39, 0xc8, 0x4a, 0x10, 0x89, - 0x64, 0xe2, 0xde, 0x74, 0xb6, 0xea, 0x55, 0xb4, 0xcb, 0x8f, 0x6f, 0x9b, 0xee, 0x98, - 0xb1, 0x0d, 0x41, 0x51, 0x09, 0x45, 0x5f, 0x48, 0xb7, 0x76, 0x08, 0x2d, 0xc3, 0x0b, - 0x4b, 0xc7, 0x34, 0x77, 0x07, 0x55, 0x11, 0x70, 0x03, 0x08, 0x15, 0x8c, 0xe2, 0xf2, - 0xf9, 0xbf, 0x0f, 0x69, 0x1b, 0x2c, 0xe5, 0x3e, 0x61, 0x14, 0x2c, 0xb7, 0x40, 0xc1, - 0x5b, 0x7b, 0x62, 0x3c, 0xf4, 0x8b, 0x3f, 0x7b, 0xfe, 0xfa, 0x31, 0xbc, 0xdc, 0x66, - 0x5c, 0x6d, 0x71, 0x23, 0xe9, 0x53, 0x50, 0x81, 0x13, 0x75, 0x94, 0x7b, 0x05, 0x5a, - 0x43, 0xdb, 0x07, 0xe0, 0x3f, 0x33, 0x62, 0x7d, 0xf5, 0xc6, 0x38, 0xbf, 0xad, 0x95, - 0x6d, 0xdc, 0x1e, 0xa7, 0xd7, 0x62, 0x0a, 0x20, 0xf2, 0x79, 0x2f, 0x63, 0x81, 0x7a, - 0x1c, 0xf3, 0x25, 0x80, 0xd0, 0x42, 0x74, 0x23, 0x4a, 0xf2, 0xa5, 0x1b, 0x56, 0xbb, - 0x68, 0xa2, 0x9e, 0x43, 0xa9, 0x54, 0x14, 0x2b, 0xa4, 0xca, 0x68, 0x23, 0xbd, 0xe9, - 0x05, 0x3d, 0x72, 0xfd, 0xad, 0xbc, 0x61, 0xad, 0x59, 0x36, 0xc5, 0x3f, 0xdd, 0x75, - 0x79, 0x44, 0x6d, 0x11, 0xc4, 0x46, 0x07, 0xf4, 0x16, 0x30, 0xe4, 0xc0, 0x89, 0x15, - 0xe6, 0x31, 0x77, 0x15, 0x50, 0xe9, 0xce, 0x1f, 0xca, 0x2c, 0x63, 0xfe, 0x06, 0xb7, - 0x98, 0x9d, 0x58, 0x4f, 0xa7, 0xd7, 0x82, 0xa8, 0x8c, 0x1e, 0x7d, 0x64, 0xb6, 0xfb, - 0xf5, 0x5e, 0x35, 0x96, 0xaf, 0x9b, 0xcb, 0x75, 0x85, 0xf8, 0xc7, 0xd3, 0xaa, 0x5c, - 0x20, 0x82, 0xb2, 0x65, 0x24, 0x9d, 0xf0, 0x57, 0x01, 0xda, 0xb0, 0x31, 0xc4, 0xba, - 0xc1, 0xea, 0x26, 0x7a, 0x29, 0x96, 0xa2, 0x02, 0x8d, 0x1e, 0x6a, 0x0f, 0x80, 0xa3, - 0x84, 0x7c, 0x53, 0x1d, 0xba, 0x96, 0xee, 0x65, 0xa2, 0x41, 0x89, 0xbd, 0x27, 0x12, - 0xe4, 0x0e, 0x95, 0x96, 0x64, 0x98, 0x1e, 0x58, 0xb2, 0xa4, 0xf9, 0x51, 0xef, 0x8f, - 0x49, 0x7d, 0xff, 0xf2, 0xf2, 0xf2, 0x71, 0xea, 0xb8, 0x9c, 0x62, 0x8e, 0x18, 0xb5, - 0xfc, 0xb4, 0x38, 0x82, 0x53, 0x7e, 0xaf, 0x6a, 0xd2, 0xa6, 0xb1, 0x75, 0x46, 0x33, - 0xca, 0xa8, 0x6b, 0xf2, 0xc7, 0x6f, 0x39, 0x93, 0x15, 0x4f, 0xc7, 0x3e, 0x6f, 0xbb, - 0xa2, 0x21, 0x0c, 0x27, 0x43, 0xf5, 0x30, 0xa4, 0x27, 0x84, 0x9a, 0x30, 0x1e, 0x00, - 0xe0, 0x11, 0x29, 0xf0, 0x3a, 0x46, 0x07, 0xf8, 0x7c, 0xbe, 0x07, 0x62, 0xc0, 0xb1, - 0xc6, 0x58, 0x55, 0xde, 0xba, 0x84, 0x22, 0xca, 0x4b, 0x88, 0xab, 0xee, 0xa6, 0xa4, - 0x38, 0x2c, 0xf1, 0x6c, 0xcd, 0x6d, 0xc7, 0xc3, 0x7c, 0x44, 0xe5, 0x49, 0xc4, 0x53, - 0x48, 0x19, 0xac, 0xd8, 0xbb, 0x0a, 0x02, 0xa5, 0xfa, 0x7a, 0x1c, 0x1d, 0x38, 0x06, - 0xfb, 0xc3, 0x40, 0x7f, 0xd7, 0xda, 0x93, 0xfd, 0x0d, 0xe6, 0x40, 0x0d, 0x3a, 0xb8, - 0x97, 0x74, 0x85, 0xcd, 0xdf, 0xbe, 0xd5, 0x93, 0x2f, 0x50, 0x7b, 0x79, 0x94, 0x7a, - 0xdb, 0x2f, 0xad, 0x37, 0x61, 0x5a, 0xa7, 0x17, 0xdb, 0x5f, 0x29, 0x80, 0x99, 0xf2, - 0x0f, 0x26, 0x3b, 0x35, 0x9a, 0x11, 0x51, 0xa6, 0xb7, 0x5c, 0x01, 0x36, 0x5e, 0xb1, - 0x54, 0xae, 0x42, 0x14, 0x0d, 0x6e, 0x10, 0x34, 0x2f, 0x14, 0xf3, 0x4d, 0xc3, 0x3e, - 0x07, 0xff, 0x0e, 0x4d, 0x1a, 0x6b, 0xe3, 0x75, 0xb3, 0x2f, 0x84, 0xb9, 0x2e, 0x5d, - 0x81, 0xeb, 0xb6, 0x39, 0xc4, 0xf2, 0x7e, 0x71, 0x5a, 0xa4, 0x2c, 0xc7, 0x57, 0x07, - 0xd4, 0xeb, 0xd1, 0xbb, 0xfb, 0xe8, 0xf9, 0x0f, 0xc7, 0xc9, 0x53, 0xe7, 0xa9, 0x71, - 0x5e, 0x65, 0xaf, 0x82, 0x67, 0x37, 0x3d, 0x34, 0x51, 0x67, 0x4f, 0xf0, 0x84, 0xef, - 0xd9, 0x2c, 0xcf, 0x3b, 0xcc, 0x7a, 0xca, 0x14, 0x67, 0xb6, 0x32, 0x7e, 0x4f, 0x95, - 0x22, 0xb2, 0xcc, 0x57, 0x9a, 0x7a, 0x8f, 0xff, 0x7c, 0xa7, 0xcf, 0x14, 0x5d, 0xfc, - 0x13, 0xea, 0xfc, 0x34, 0x15, 0x3b, 0x2c, 0x3e, 0x8a, 0xfb, 0xe5, 0x34, 0x44, 0xd0, - 0xc7, 0x3b, 0x3b, 0xd5, 0xbc, 0x87, 0x0b, 0x01, 0xcd, 0x45, 0x79, 0x11, 0xe3, 0x56, - 0x31, 0x3f, 0xd1, 0xda, 0xfb, 0x4c, 0x81, 0x51, 0x63, 0x4a, 0x01, 0xaf, 0xf7, 0xcf, - 0x11, 0x6d, 0x43, 0x3c, 0x3d, 0x2b, 0x3a, 0xdd, 0xa9, 0xce, 0xbe, 0x18, 0xf7, 0xd1, - 0x72, 0x44, 0x3e, 0x5e, 0x7b, 0x5a, 0xc9, 0xab, 0xe8, 0xdb, 0x22, 0x56, 0xd7, 0xeb, - 0xe2, 0xff, 0x28, 0x02, 0x09, 0x39, 0x50, 0x38, 0x70, 0x59, 0x7b, 0x9a, 0x95, 0x58, - 0x92, 0xc7, 0x38, 0x96, 0x50, 0xa2, 0xd4, 0x2e, 0xc9, 0x2b, 0xe7, 0x23, 0xfe, 0xdf, - 0x2f, 0x2e, 0xde, 0x5a, 0x47, 0x2a, 0xa1, 0xe7, 0x4f, 0x33, 0xad, 0x41, 0x90, 0x15, - 0x44, 0xed, 0xbb, 0xe3, 0xac, 0x46, 0x4c, 0xf4, 0x39, 0x19, 0x60, 0x15, 0xf4, 0xf2, - 0x2a, 0xc2, 0xb8, 0xfc, 0x01, 0x49, 0x6b, 0xea, 0xb4, 0xd4, 0x59, 0x07, 0xf4, 0x79, - 0x81, 0x2a, 0x25, 0x94, 0x31, 0xa2, 0xcb, 0xc9, 0x3d, 0x4f, 0x3b, 0x84, 0xe4, 0xdd, - 0x36, 0x60, 0x20, 0x27, 0x3a, 0x67, 0x52, 0xe5, 0x01, 0xaf, 0x6f, 0xf1, 0xb7, 0x8d, - 0xdc, 0x81, 0x7e, 0x6e, 0xa3, 0xe5, 0x37, 0x5c, 0xa3, 0xfe, 0x2f, 0xb1, 0xd1, 0xa9, - 0x37, 0x15, 0xdf, 0xf9, 0x29, 0x93, 0xcc, 0xc6, 0x50, 0x4f, 0x64, 0xfc, 0xbf, 0x22, - 0x17, 0x30, 0xd9, 0xef, 0xf4, 0xf3, 0x27, 0xe0, 0xad, 0x37, 0x4f, 0x59, 0x56, 0x45, - 0x37, 0x48, 0x75, 0x5b, 0x43, 0xc8, 0xf2, 0x9d, 0x67, 0x52, 0x6f, 0x60, 0xa6, 0x18, - 0xb7, 0x33, 0x24, 0xd2, 0x24, 0x33, 0x72, 0x92, 0x1b, 0x99, 0xe3, 0xdf, 0x36, 0x85, - 0x0c, 0x60, 0xd5, 0xd9, 0x34, 0x3a, 0x48, 0x70, 0xa0, 0xe7, 0x52, 0x8c, 0x65, 0x13, - 0xc2, 0x7c, 0x56, 0x43, 0x90, 0x93, 0xf9, 0x33, 0x68, 0x1d, 0x93, 0xa4, 0xd4, 0xbc, - 0xee, 0xac, 0x2b, 0x10, 0x8c, 0x6c, 0x6f, 0xae, 0x35, 0x9f, 0x64, 0x5c, 0x27, 0x68, - 0x91, 0xc0, 0xdc, 0xab, 0x3f, 0xaf, 0x18, 0x77, 0x00, 0xc0, 0x82, 0xdc, 0x47, 0x77, - 0x40, 0xfb, 0x3f, 0x2c, 0xd7, 0xbb, 0x59, 0xfb, 0x35, 0x85, 0x54, 0xe9, 0x4c, 0x7e, - 0x67, 0x8c, 0xe0, 0x1a, 0xeb, 0xf9, 0x4e, 0x51, 0x5e, 0x49, 0x72, 0x29, 0x67, 0x99, - 0x5a, 0xea, 0x85, 0x8d, 0x64, 0xe7, 0x78, 0x9f, 0xf3, 0x06, 0x36, 0x95, 0x77, 0x22, - 0x81, 0x80, 0x32, 0x6a, 0x5b, 0x0a, 0xf4, 0x75, 0xe2, 0x7a, 0x54, 0xb2, 0x07, 0xb4, - 0x1f, 0x92, 0xe3, 0x76, 0x17, 0x0e, 0x3f, 0xb0, 0x05, 0x02, 0x82, 0x61, 0xc9, 0x9c, - 0x2d, 0xbd, 0x0e, 0xed, 0xee, 0x87, 0x1c, 0x1c, 0x0f, 0x48, 0xb8, 0xe9, 0xb8, 0xe4, - 0xbe, 0x77, 0xd1, 0xb7, 0x37, 0xfe, 0x21, 0xf0, 0xfa, 0x5a, 0x18, 0xeb, 0xb5, 0x27, - 0x55, 0xb5, 0xa6, 0xcf, 0x61, 0x30, 0xfb, 0x56, 0x94, 0x4c, 0xfa, 0xb8, 0x75, 0x27, - 0xc2, 0x50, 0xd1, 0x13, 0xb2, 0x9b, 0xca, 0xc9, 0xaa, 0xa1, 0x0c, 0x2e, 0x7d, 0xe4, - 0x15, 0xed, 0xb0, 0x80, 0x6c, 0x6d, 0xa0, 0x30, 0x20, 0xa1, 0x34, 0xca, 0x7e, 0xcd, - 0xc8, 0xda, 0x1b, 0xd5, 0x7a, 0x37, 0xf5, 0x5a, 0x46, 0x94, 0x0b, 0x45, 0xb2, 0x41, - 0xb1, 0xc1, 0x6e, 0xe1, 0x00, 0x92, 0x7d, 0x1b, 0xd8, 0x60, 0xd4, 0x45, 0xa9, 0xde, - 0x50, 0xd4, 0xc3, 0x84, 0xd6, 0xe1, 0xd0, 0x01, 0x08, 0x02, 0x6c, 0x0e, 0xa5, 0xeb, - 0xbf, 0x0b, 0x72, 0xfb, 0xf5, 0xc3, 0x70, 0xbc, 0xe1, 0x8d, 0x3a, 0xcb, 0xc4, 0x65, - 0x99, 0x09, 0x9b, 0xaa, 0xe1, 0xd8, 0x02, 0xf7, 0x73, 0x33, 0x49, 0x4a, 0x7a, 0xe1, - 0x30, 0xfe, 0x86, 0xe8, 0xf8, 0x18, 0xf9, 0x26, 0x1a, 0x2d, 0xad, 0xb4, 0x12, 0x52, - 0x29, 0xba, 0x0f, 0xfc, 0x0e, 0x70, 0x90, 0x32, 0x44, 0x30, 0xb5, 0x21, 0xa9, 0x0d, - 0x22, 0x4a, 0xb7, 0xa1, 0x02, 0x4e, 0x1d, 0x89, 0x3e, 0x74, 0x04, 0xfe, 0xdb, 0x34, - 0x8e, 0x4d, 0x5e, 0x22, 0x35, 0xc5, 0x9a, 0x78, 0x76, 0xa0, 0xfc, 0x60, 0x14, 0x5c, - 0x6a, 0x00, 0x96, 0x87, 0x68, 0x44, 0x60, 0x27, 0x1e, 0xe1, 0x33, 0xa4, 0x37, 0xfe, - 0x52, 0xfb, 0x6c, 0xfb, 0xa9, 0x7f, 0xce, 0xc1, 0x61, 0xdf, 0x51, 0x5d, 0xde, 0x90, - 0x5a, 0x24, 0xda, 0x6d, 0x37, 0xbd, 0xc3, 0x40, 0x44, 0xa9, 0x55, 0xe6, 0x82, 0xb4, - 0x74, 0x71, 0xca, 0x1e, 0x8c, 0x78, 0xc5, 0x1e, 0xd3, 0x77, 0xcd, 0x4a, 0xfa, 0x89, - 0x4b, 0xd9, 0xbd, 0x12, 0xe7, 0x07, 0x15, 0x6d, 0xa0, 0x72, 0x6f, 0x7c, 0xf5, 0x72, - 0x9f, 0xab, 0xe3, 0x72, 0x16, 0x04, 0x63, 0xfe, 0x04, 0x29, 0x24, 0x4d, 0x06, 0x74, - 0x89, 0xba, 0x5d, 0x09, 0x47, 0x2e, 0xcd, 0x9b, 0xcd, 0xc4, 0xd5, 0xe4, 0xdf, 0x10, - 0x1e, 0x18, 0x9d, 0xb8, 0x46, 0x3e, 0xb5, 0x38, 0x30, 0x7b, 0x58, 0x7d, 0xef, 0xf7, - 0x8d, 0xe9, 0xc7, 0x3a, 0xf2, 0x80, 0x80, 0xb2, 0xfd, 0x05, 0x00, 0x3e, 0x11, 0xd3, - 0xe1, 0xb3, 0x29, 0x9d, 0xc9, 0x52, 0x1f, 0x8b, 0x51, 0x3b, 0xad, 0xb0, 0x10, 0xe9, - 0x1b, 0xfe, 0xb9, 0x1b, 0x0b, 0x2a, 0x6c, 0xb1, 0x29, 0xc2, 0xe8, 0x25, 0xa5, 0x97, - 0xb8, 0xfb, 0x75, 0xbc, 0x56, 0x2d, 0x65, 0x4d, 0x62, 0x10, 0x46, 0x40, 0xdd, 0x74, - 0xe5, 0x6c, 0xd1, 0x4b, 0xaa, 0xba, 0x56, 0x5b, 0x84, 0xb8, 0x45, 0xe1, 0x63, 0xd1, - 0xca, 0xef, 0x25, 0x33, 0xc3, 0x98, 0x16, 0x37, 0x20, 0x4f, 0x96, 0xa5, 0x9c, 0x8e, - 0x80, 0x24, 0xd9, 0x04, 0x1b, 0x20, 0x29, 0xe9, 0x4c, 0x15, 0x24, 0x5f, 0x1a, 0x95, - 0x88, 0x40, 0xba, 0x3f, 0x38, 0x0a, 0x4d, 0x20, 0xf1, 0x18, 0x4e, 0x77, 0x82, 0x7d, - 0xe3, 0xff, 0x8f, 0x3d, 0x73, 0x45, 0x9a, 0xfe, 0x24, 0x1f, 0x72, 0x3c, 0x08, 0x48, - 0x23, 0x23, 0x0e, 0x00, 0x3d, 0x3d, 0x21, 0xe5, 0x35, 0x01, 0xec, 0x04, 0x99, 0xb0, - 0x83, 0xa7, 0xda, 0xd6, 0x85, 0xc5, 0x71, 0x27, 0xf4, 0xde, 0x64, 0x73, 0x3a, 0x88, - 0x0c, 0x2d, 0xb2, 0x8f, 0xda, 0xab, 0xf1, 0xb5, 0x42, 0xd2, 0x05, 0xf6, 0x64, 0xa3, - 0x51, 0x35, 0x71, 0x27, 0x11, 0xdc, 0xcc, 0xd9, 0x31, 0xa5, 0x0b, 0x9c, 0x56, 0x61, - 0x88, 0x23, 0x60, 0xd4, 0xca, 0xc0, 0x04, 0x76, 0x81, 0xbc, 0x2e, 0x2b, 0x3b, 0xf6, - 0xc9, 0x97, 0x60, 0xd7, 0xcf, 0xb4, 0xfa, 0x21, 0x39, 0x43, 0x77, 0xa4, 0x55, 0x1c, - 0x76, 0xd1, 0xf7, 0x5a, 0xc0, 0x3c, 0x26, 0x20, 0x54, 0xdf, 0xfd, 0x79, 0xa9, 0xde, - 0xd0, 0x5e, 0x88, 0x89, 0x58, 0x19, 0x9e, 0xea, 0x45, 0x01, 0xe2, 0x99, 0x0a, 0x53, - 0xa5, 0xcd, 0x2a, 0x46, 0xa4, 0x01, 0x57, 0x65, 0x88, 0xfd, 0x7d, 0x05, 0x8a, 0x26, - 0xf2, 0x84, 0x38, 0xe5, 0x78, 0x2f, 0x45, 0xac, 0x1d, 0x07, 0xf6, 0xf6, 0xf5, 0xed, - 0x73, 0x74, 0x1d, 0x57, 0x85, 0x83, 0x7a, 0x6b, 0x84, 0x4b, 0x47, 0x47, 0x75, 0x71, - 0x8c, 0x29, 0xdd, 0x99, 0x08, 0x4e, 0x9f, 0x88, 0xef, 0x15, 0x3a, 0x83, 0x29, 0xf5, - 0x32, 0xa6, 0x90, 0x17, 0xdc, 0x3a, 0x97, 0xed, 0x75, 0x43, 0x67, 0x72, 0x30, 0x98, - 0xe5, 0x76, 0x58, 0x40, 0xb0, 0x22, 0x89, 0x72, 0x44, 0x74, 0x5f, 0xbb, 0xbb, 0x30, - 0xa7, 0xcb, 0x54, 0xfa, 0x05, 0x11, 0x16, 0x6e, 0x95, 0x44, 0x12, 0x20, 0x00, 0x61, - 0x0b, 0xd2, 0xaa, 0xcb, 0xd8, 0x23, 0x25, 0xa5, 0x9b, 0x95, 0x15, 0x4e, 0xcd, 0x82, - 0xc8, 0x8d, 0x23, 0xab, 0xd1, 0xe2, 0x07, 0x70, 0xff, 0xb8, 0xaa, 0xbf, 0x83, 0xfc, - 0x07, 0x34, 0x96, 0x4c, 0xcd, 0x41, 0x1d, 0x1c, 0x93, 0x57, 0x14, 0xe2, 0x4a, 0xab, - 0x56, 0x6f, 0x4f, 0x08, 0x42, 0x40, 0x14, 0xc4, 0xec, 0xa9, 0x1b, 0x59, 0x0f, 0x08, - 0x2b, 0x47, 0x3f, 0x36, 0x1c, 0x87, 0x41, 0x5d, 0x37, 0xbd, 0x20, 0xd7, 0x0f, 0xd0, - 0xb5, 0x2b, 0x6d, 0xdf, 0x18, 0x65, 0xf7, 0x66, 0x70, 0x2e, 0x32, 0xb0, 0x5b, 0x3c, - 0xf1, 0x63, 0x0e, 0xe8, 0x59, 0x7a, 0xae, 0x19, 0x63, 0x3f, 0x35, 0x16, 0xa8, 0x55, - 0x5a, 0xc5, 0xbe, 0x32, 0xc6, 0x75, 0xbe, 0x18, 0x17, 0xef, 0xbf, 0xfd, 0x93, 0x69, - 0x04, 0xbd, 0x73, 0x4d, 0x97, 0x23, 0x3a, 0xaa, 0x38, 0x3b, 0x41, 0xba, 0x6d, 0x27, - 0xf6, 0x42, 0x84, 0x7d, 0x1e, 0xda, 0xcb, 0x4b, 0xf8, 0x22, 0xe6, 0x70, 0x80, 0x86, - 0x75, 0x18, 0xae, 0x5a, 0x8f, 0x0a, 0x43, 0xe6, 0xed, 0x53, 0x0c, 0xb2, 0xe8, 0xae, - 0x83, 0x88, 0x60, 0xad, 0xc8, 0x8a, 0xac, 0xc7, 0xbd, 0x6a, 0x00, 0xae, 0x0c, 0x19, - 0xff, 0x45, 0x33, 0xa4, 0x85, 0xef, 0xde, 0x08, 0x2b, 0xc5, 0x21, 0x40, 0x18, 0x2b, - 0x23, 0x4d, 0x1a, 0x0d, 0x0e, 0xeb, 0xdf, 0xb9, 0x87, 0x75, 0x98, 0xe0, 0x34, 0x7f, - 0xb1, 0x00, 0x1e, 0x15, 0xb5, 0xd4, 0x44, 0x6e, 0x76, 0x6c, 0xde, 0x25, 0xef, 0x79, - 0x87, 0x40, 0xe0, 0xbd, 0xf9, 0x94, 0xd9, 0x73, 0x9b, 0xbe, 0x55, 0x38, 0xa0, 0xae, - 0x0f, 0x07, 0x6c, 0x58, 0x2c, 0x0f, 0x5b, 0xa8, 0x78, 0xb9, 0x9b, 0x82, 0x49, 0xdb, - 0x1d, 0x7e, 0x95, 0x05, 0x6c, 0x98, 0xaf, 0x08, 0x3d, 0x98, 0xcb, 0x0e, 0xd9, 0xe3, - 0xf7, 0x43, 0x6e, 0x1c, 0x76, 0x43, 0x76, 0x6f, 0x96, 0x6b, 0x83, 0xe9, 0x99, 0x20, - 0x6e, 0xbd, 0x13, 0x93, 0xb9, 0xb2, 0xa7, 0xf4, 0x14, 0x48, 0x0f, 0xa0, 0x17, 0x48, - 0x00, 0x69, 0xf8, 0x5c, 0x77, 0x49, 0xc4, 0x35, 0xae, 0x2f, 0xba, 0x2d, 0xdc, 0x10, - 0x38, 0xd5, 0x47, 0xd8, 0x48, 0x54, 0x81, 0x7e, 0xf3, 0x96, 0x35, 0xc2, 0x98, 0x27, - 0xaa, 0xd8, 0x67, 0x26, 0xc9, 0xad, 0xe3, 0xb2, 0x65, 0xb9, 0x08, 0x6c, 0x8b, 0x5b, - 0x75, 0xef, 0x56, 0xfe, 0x4b, 0xd8, 0xb4, 0xd6, 0x28, 0x93, 0x89, 0x5b, 0x3f, 0xd2, - 0x73, 0x4f, 0xda, 0xc4, 0x64, 0x15, 0x6d, 0x7e, 0x5e, 0xbc, 0x7e, 0xcf, 0x1d, 0x83, - 0xb8, 0x6f, 0x65, 0x96, 0x37, 0xe3, 0xb1, 0x42, 0xc1, 0x64, 0x96, 0x3b, 0x8c, 0xdc, - 0xf4, 0xba, 0x4f, 0x40, 0x35, 0xdf, 0xfc, 0x5a, 0x78, 0x94, 0x58, 0x84, 0x77, 0x81, - 0x91, 0x8a, 0xc7, 0x2f, 0xc1, 0x8b, 0xbb, 0xf5, 0x11, 0x00, 0x32, 0xe6, 0x6d, 0x75, - 0xb3, 0x17, 0x1e, 0xf4, 0xb5, 0x13, 0x29, 0x01, 0x64, 0xa7, 0x7b, 0x42, 0xb0, 0xa4, - 0xcf, 0xb8, 0x96, 0x39, 0xab, 0x23, 0x84, 0x5e, 0x1a, 0xa2, 0xa4, 0x52, 0xf3, 0x73, - 0x1c, 0x8c, 0xb6, 0x50, 0x82, 0xa6, 0x22, 0xa7, 0xc2, 0xe0, 0x01, 0x3e, 0xa4, 0x7d, - 0x0b, 0xdd, 0x42, 0xd6, 0x99, 0x04, 0x66, 0x64, 0x9a, 0x90, 0x5c, 0x68, 0x4c, 0x32, - 0x51, 0x71, 0x6d, 0x61, 0xf7, 0x60, 0xd5, 0x3d, 0xe6, 0xe3, 0xf7, 0x90, 0xfb, 0xa7, - 0xf5, 0xf1, 0xf4, 0xde, 0x26, 0x71, 0x13, 0xbd, 0xfc, 0xd7, 0x42, 0x28, 0x22, 0x33, - 0x0b, 0x32, 0xd5, 0x8e, 0x67, 0x77, 0x76, 0x5f, 0x22, 0xa4, 0x11, 0x63, 0x44, 0xee, - 0xb6, 0x5b, 0x2e, 0xc5, 0x16, 0x39, 0x3a, 0xb3, 0x75, 0x1b, 0x53, 0x56, 0xd2, 0xb0, - 0xc9, 0x50, 0x0c, 0x0f, 0x3e, 0x46, 0x91, 0x81, 0x03, 0x5b, 0xc3, 0x66, 0x0f, 0x0b, - 0x8f, 0x9f, 0xbe, 0x6e, 0x40, 0xb5, 0xe8, 0x9c, 0xb7, 0x9b, 0x06, 0x37, 0x14, 0xca, - 0x75, 0xe7, 0x2e, 0x2e, 0x10, 0x0a, 0x10, 0xd6, 0x3b, 0xf7, 0x84, 0xdf, 0x08, 0x20, - 0xef, 0x25, 0xf8, 0xef, 0x40, 0xfe, 0x5f, 0x05, 0xfb, 0x95, 0x68, 0x3f, 0x91, 0x05, - 0xff, 0x3c, 0xb2, 0xd2, 0x19, 0xab, 0x76, 0x60, 0x5a, 0x06, 0x4f, 0x69, 0x21, 0x9f, - 0x1d, 0xc0, 0xd0, 0x0b, 0x3b, 0x48, 0x64, 0x2f, 0x97, 0x0d, 0xc0, 0x0c, 0xca, 0x4b, - 0x8b, 0x43, 0x30, 0x8b, 0xe1, 0x82, 0x86, 0xec, 0x5a, 0x42, 0x88, 0xd6, 0x00, 0xa3, - 0x78, 0x5c, 0xb6, 0x22, 0xd4, 0x68, 0xa4, 0xc6, 0x96, 0x9b, 0x37, 0x92, 0xf2, 0x48, - 0x50, 0x27, 0xd0, 0xad, 0x9a, 0xa4, 0xa9, 0xc2, 0xcc, 0x97, 0x2f, 0x9e, 0xe5, 0x19, - 0x0a, 0x95, 0xb1, 0xeb, 0x05, 0x8d, 0xdd, 0xd8, 0xc0, 0x8e, 0x7d, 0x75, 0x3f, 0x5e, - 0x01, 0x1b, 0x2b, 0xcf, 0xee, 0x1d, 0x52, 0xc1, 0xc4, 0xf2, 0xca, 0xcd, 0xa3, 0x0b, - 0xdb, 0x69, 0x30, 0x65, 0x3c, 0x0c, 0xc4, 0x48, 0x6e, 0x60, 0xe8, 0x9f, 0xa8, 0x49, - 0xb3, 0x20, 0x83, 0xba, 0x9d, 0xb4, 0x53, 0xfb, 0x8d, 0xf6, 0x83, 0xcd, 0x68, 0x75, - 0x4c, 0x87, 0xda, 0xa7, 0x31, 0xf5, 0x70, 0xa7, 0xa4, 0x06, 0x0a, 0xf0, 0xce, 0x70, - 0x0d, 0x31, 0xbc, 0xa7, 0xe7, 0x4b, 0x3e, 0x3b, 0xa3, 0xd0, 0xe8, 0xa6, 0x39, 0x2a, - 0x06, 0x2b, 0x8e, 0x86, 0xd9, 0xd7, 0xd0, 0x0b, 0x21, 0x70, 0x1e, 0x7b, 0x06, 0x2e, - 0x06, 0xb1, 0xbc, 0xd8, 0x2a, 0x01, 0xd3, 0x75, 0x62, 0x6f, 0xbf, 0x87, 0x2d, 0x27, - 0xfa, 0x45, 0x11, 0xf5, 0xf8, 0xcf, 0x8c, 0x9a, 0xbc, 0xef, 0x2a, 0x99, 0x01, 0x76, - 0xae, 0x33, 0x93, 0x25, 0xd5, 0xa5, 0x88, 0xda, 0x57, 0x96, 0xfa, 0xae, 0x5b, 0xab, - 0x7c, 0x82, 0x97, 0x7c, 0x0f, 0xf7, 0x97, 0x09, 0x3e, 0x2c, 0x1f, 0x3a, 0xe8, 0x55, - 0xf6, 0x5a, 0xea, 0x91, 0xe1, 0x31, 0x2f, 0xc6, 0xb8, 0xa4, 0x35, 0x1a, 0x2e, 0xc0, - 0x3e, 0x02, 0xe5, 0xd0, 0x2f, 0x53, 0x35, 0x4b, 0x05, 0x2f, 0xd3, 0xda, 0x0d, 0xff, - 0x82, 0xcd, 0x1f, 0x55, 0xeb, 0xca, 0x57, 0xb6, 0x33, 0x7c, 0x85, 0x93, 0x8a, 0x79, - 0x81, 0x3d, 0x20, 0x21, 0xd6, 0x09, 0x4c, 0x68, 0xb3, 0x75, 0xe9, 0x84, 0xf6, 0x83, - 0x93, 0x30, 0x08, 0x71, 0xe3, 0x48, 0xfc, 0x52, 0x36, 0xcc, 0xa6, 0x33, 0x05, 0x44, - 0xe5, 0x46, 0x39, 0xb5, 0x41, 0x87, 0x01, 0xff, 0x4c, 0xc4, 0x5a, 0x31, 0xf6, 0x2e, - 0xdd, 0x84, 0x3d, 0xbb, 0xdc, 0x5a, 0xa7, 0x27, 0xab, 0x79, 0xb4, 0x42, 0x68, 0x3c, - 0x49, 0x56, 0xbb, 0xb1, 0x95, 0xa4, 0xfa, 0x66, 0xdc, 0x9c, 0xd5, 0x42, 0xc7, 0x6b, - 0x91, 0x50, 0xc8, 0x4b, 0xf8, 0x90, 0x78, 0x99, 0x42, 0xf5, 0x5c, 0x20, 0x0b, 0x77, - 0x3e, 0xcd, 0xd7, 0x99, 0x2c, 0xff, 0x3e, 0xca, 0x24, 0xde, 0x3e, 0x09, 0x84, 0xe1, - 0x0e, 0x68, 0xae, 0x38, 0x75, 0x34, 0xb9, 0x6c, 0xde, 0x37, 0x92, 0xf1, 0x35, 0xbf, - 0x5f, 0x68, 0x78, 0x7d, 0x37, 0x0c, 0xa8, 0xc4, 0xc4, 0x07, 0x4d, 0xc5, 0xd6, 0x01, - 0xae, 0x90, 0x49, 0x54, 0x37, 0xc3, 0xc2, 0xd4, 0x8a, 0x3d, 0x96, 0x66, 0x83, 0xac, - 0x05, 0x16, 0x0b, 0x7a, 0x84, 0xea, 0xa7, 0xaa, 0xb7, 0x40, 0x09, 0xe5, 0x7a, 0x85, - 0xf7, 0xbf, 0x68, 0xa2, 0xe4, 0x82, 0x00, 0x0f, 0x82, 0x9c, 0x54, 0x50, 0x73, 0xa1, - 0x5d, 0x5c, 0xd0, 0xfc, 0xc5, 0x74, 0x39, 0xa4, 0x35, 0x0e, 0xaf, 0x09, 0x8d, 0xfb, - 0x82, 0xa0, 0x85, 0xea, 0x8a, 0x4a, 0xf6, 0xfa, 0x83, 0x81, 0xf0, 0x65, 0x88, 0x19, - 0xea, 0xb4, 0x83, 0xf6, 0x5b, 0x32, 0x5d, 0x5a, 0xed, 0xa1, 0x52, 0x32, 0xcf, 0xad, - 0xec, 0x75, 0xab, 0x18, 0x66, 0xe4, 0xc0, 0x15, 0x5a, 0x9c, 0x74, 0xa7, 0xa5, 0x7c, - 0xcf, 0x34, 0xc4, 0x83, 0xac, 0x7d, 0xa1, 0x58, 0x8a, 0x1b, 0x6b, 0x02, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x41, 0xf1, 0x10, 0x40, 0xf9, 0x4c, 0xf7, 0x8f, 0xad, 0x89, 0xbf, 0x11, 0xfe, 0xd6, - 0x9a, 0xa0, 0xd8, 0x31, 0x05, 0xad, 0xac, 0xdd, 0x4e, 0x5f, 0x04, 0xa6, 0x24, 0x24, - 0x02, 0x3c, 0x9b, 0x9e, 0x33, 0xc4, 0xfb, 0x7f, 0x12, 0xbd, 0xf2, 0x1f, 0x07, 0xf2, - 0x65, 0xc5, 0x37, 0xd5, 0x1c, 0x65, 0x51, 0xf4, 0x61, 0x7b, 0x91, 0x5d, 0x21, 0x99, - 0x18, 0x39, 0xc3, 0xd0, 0xd3, 0x63, 0x93, 0xd6, 0x46, 0xe0, 0xa8, 0xa4, 0x15, 0x09, - 0x21, 0x7d, 0x0e, 0x7d, 0x2c, 0xa1, 0xa0, 0xa0, 0xd6, 0x77, 0xa3, 0xea, 0xca, 0x23, - 0xed, 0xeb, 0x07, 0xb7, 0x4e, 0x65, 0x2a, 0x0b, 0xc5, 0x0c, 0x6c, 0x08, 0x3a, 0x55, - 0xd6, 0xc7, 0x30, 0x6e, 0x74, 0x08, 0x6f, 0x47, 0x68, 0x93, 0x3a, 0xa2, 0x48, 0x73, - 0x68, 0x18, 0x67, 0xa7, 0x89, 0x3d, 0x77, 0xcb, 0x7f, 0x29, 0xb8, 0xc8, 0x47, 0xc5, - 0x83, 0xf2, 0xd0, 0x71, 0xa6, 0x86, 0x61, 0x6e, 0x20, 0x67, 0x19, 0xf7, 0x61, 0xae, - 0x39, 0xc1, 0x10, 0x44, 0x2e, 0x06, 0x16, 0x3d, 0x2b, 0x84, 0x59, 0x03, 0x60, 0x69, - 0x5d, 0x4e, 0x19, 0x84, 0x9e, 0x63, 0x4f, 0x24, 0xd9, 0xad, 0x39, 0x6c, 0x19, 0xff, - 0x83, 0xce, 0x74, 0xf4, 0x6e, 0x64, 0x5f, 0x93, 0x2e, 0x14, 0x1a, 0x41, 0x19, 0x59, - 0x36, 0xc8, 0x5d, 0x51, 0x44, 0x14, 0xf1, 0x12, 0xe6, 0x0b, 0x1a, 0x25, 0x37, 0xc3, - 0x8d, 0x6d, 0xc6, 0xc4, 0x63, 0x83, 0x05, 0xc9, 0xbd, 0x6c, 0x62, 0xe3, 0x66, 0xbc, - 0x63, 0x12, 0x3e, 0x3e, 0x6d, 0xd3, 0x6e, 0xed, 0xd3, 0x13, 0x6f, 0xce, 0x8d, 0xee, - 0xca, 0x2a, 0xa0, 0x9a, 0x32, 0x98, 0xa3, 0x9d, 0x83, 0x85, 0x9e, 0xfc, 0x9b, 0x2b, - 0x69, 0xcf, 0x9a, 0x7d, 0xee, 0x08, 0xa9, 0x8e, 0x4b, 0xe5, 0x58, 0xac, 0x79, 0x12, - 0xfd, 0xcb, 0x42, 0x20, 0x90, 0x75, 0x42, 0x02, 0x60, 0xf7, 0xca, 0xd0, 0xf2, 0xc0, - 0x1f, 0x2a, 0xfe, 0x33, 0x07, 0x3f, 0x26, 0x24, 0x9d, 0x94, 0x4f, 0x7a, 0x50, 0xdd, - 0x84, 0x83, 0x9b, 0xc3, 0xea, 0x7f, 0xde, 0xe4, 0xed, 0x71, 0x44, 0x9c, 0xf0, 0x75, - 0x33, 0xd2, 0x6e, 0x1e, 0x27, 0xa3, 0xef, 0xb0, 0x32, 0xc3, 0xa3, 0xb3, 0x4b, 0xd3, - 0x09, 0x26, 0x22, 0xd2, 0x06, 0x2a, 0xe5, 0x36, 0xef, 0x51, 0x49, 0xc4, 0x9b, 0x5b, - 0xc9, 0x47, 0x5e, 0xaf, 0xab, 0x6e, 0x67, 0x57, 0x61, 0x00, 0x8b, 0x0d, 0xad, 0xde, - 0xec, 0xaa, 0x60, 0x44, 0x70, 0xbb, 0xe0, 0xfa, 0xda, 0x25, 0x5d, 0x29, 0x0e, 0x92, - 0xb1, 0x90, 0xc2, 0xc2, 0xd8, 0xc2, 0xde, 0xe5, 0x45, 0x5d, 0x1f, 0xa9, 0xa9, 0xf3, - 0xdb, 0x77, 0x79, 0xb5, 0x84, 0x64, 0x34, 0x64, 0xaa, 0x80, 0x14, 0xba, 0x66, 0x99, - 0x4d, 0xe2, 0x55, 0x17, 0xf8, 0x39, 0x80, 0xe6, 0x6e, 0xe4, 0xf6, 0x23, 0x14, 0xae, - 0x6d, 0xbe, 0xf4, 0x52, 0xd5, 0xd3, 0x8b, 0x0a, 0x16, 0xf3, 0x99, 0x1f, 0x36, 0xd8, - 0xa8, 0xb3, 0x9d, 0xdc, 0x0d, 0x55, 0x95, 0xee, 0xd9, 0x87, 0x62, 0x87, 0x8c, 0xdf, - 0x3f, 0x4a, 0x2e, 0xdc, 0x5c, 0xda, 0x77, 0xd5, 0xfe, 0x4f, 0xaf, 0x63, 0xa1, 0x5f, - 0x56, 0x8a, 0x54, 0x0d, 0xa5, 0x7d, 0xd9, 0xbe, 0xb6, 0xfb, 0x1a, 0x97, 0x7c, 0xcb, - 0x91, 0xb4, 0xd7, 0x9c, 0xb3, 0x9b, 0x28, 0x91, 0x1a, 0x29, 0xe7, 0xbf, 0x02, 0x8a, - 0xc6, 0x10, 0x37, 0x96, 0xdf, 0xb6, 0xb2, 0x09, 0x67, 0x23, 0x9a, 0xd3, 0x73, 0xc3, - 0x8c, 0x53, 0xf6, 0xdf, 0x18, 0x23, 0xd4, 0x95, 0x0a, 0x02, 0x83, 0xe9, 0x9b, 0x9c, - 0x06, 0xab, 0x29, 0x66, 0x66, 0x7c, 0x9d, 0xf6, 0x77, 0x71, 0x6b, 0x0c, 0xad, 0xed, - 0x81, 0x8d, 0xf9, 0xe4, 0x49, 0xc0, 0x72, 0xe2, 0x2f, 0x9d, 0x98, 0xbb, 0x0f, 0x9b, - 0x03, 0xbd, 0x5f, 0xd0, 0x13, 0xfc, 0xef, 0x3e, 0xd6, 0xa4, 0x9a, 0xeb, 0x98, 0x72, - 0x02, 0x54, 0x08, 0x7e, 0xf7, 0x28, 0xe3, 0x19, 0x47, 0xff, 0xe8, 0xf7, 0x66, 0xe6, - 0x3e, 0xe4, 0x6f, 0xf2, 0x08, 0x16, 0xd5, 0xfa, 0x8f, 0xf5, 0x5a, 0x26, 0x39, 0x89, - 0x61, 0x49, 0x0a, 0xb9, 0xae, 0x36, 0x6f, 0xc5, 0xa2, 0xd1, 0x99, 0x6e, 0xd6, 0x93, - 0xcc, 0xca, 0x82, 0x35, 0x6f, 0x60, 0x0a, 0xb0, 0x99, 0xf6, 0xec, 0xa8, 0xbf, 0xe6, - 0x45, 0x27, 0x0d, 0x3f, 0x95, 0xed, 0xba, 0x5b, 0x0d, 0xe7, 0xa3, 0x28, 0x19, 0x23, - 0x3b, 0xcc, 0x75, 0x4a, 0x5c, 0xe2, 0xe5, 0xea, 0x07, 0x84, 0x2e, 0x5f, 0xf2, 0xce, - 0xbe, 0x62, 0xad, 0x76, 0xe8, 0xef, 0xf8, 0xd1, 0x5e, 0xa4, 0xc2, 0x4a, 0x5f, 0x20, - 0x78, 0x68, 0x31, 0x9a, 0x5a, 0xf6, 0xb0, 0x35, 0xbe, 0x3f, 0x44, 0xf4, 0x34, 0x09, - 0x4f, 0x6e, 0x52, 0x5b, 0xe6, 0x14, 0xda, 0xc9, 0x20, 0xa3, 0x30, 0xbd, 0xfb, 0x26, - 0xd7, 0x5f, 0xe7, 0xb4, 0xb3, 0x65, 0xd0, 0x94, 0x45, 0x92, 0x50, 0xaa, 0xa5, 0x54, - 0x44, 0x89, 0xfb, 0x1d, 0x99, 0x25, 0x81, 0x80, 0x0a, 0x77, 0xb8, 0x91, 0x21, 0x57, - 0xfc, 0x97, 0x13, 0xaa, 0xac, 0x25, 0xb4, 0xc2, 0x6e, 0xb0, 0x3f, 0x71, 0x66, 0x46, - 0x61, 0x9a, 0xf0, 0x24, 0x56, 0xae, 0x69, 0x59, 0x62, 0xfe, 0x5e, 0x93, 0x1a, 0x63, - 0xb5, 0xc7, 0x90, 0x52, 0xec, 0xd3, 0x33, 0xe1, 0x84, 0x12, 0xdb, 0x91, 0xe1, 0x5f, - 0x7c, 0xbc, 0x70, 0xb4, 0xcd, 0x7e, 0x8e, 0x3c, 0x95, 0x1f, 0x35, 0x85, 0x72, 0xe3, - 0x77, 0x67, 0xe7, 0xd5, 0x27, 0x04, 0xa6, 0x72, 0x1b, 0x30, 0xef, 0xc4, 0x10, 0x17, - 0xae, 0x4d, 0x23, 0x15, 0x58, 0xc5, 0xc8, 0x2c, 0xc7, 0xdd, 0x7e, 0x33, 0x56, 0xc0, - 0x9d, 0xc2, 0x49, 0x06, 0xf0, 0x43, 0x8d, 0xfc, 0xc3, 0x00, 0x85, 0x6a, 0xc2, 0xce, - 0xd8, 0xf7, 0x7f, 0xa8, 0x01, 0x57, 0x36, 0xc6, 0x61, 0xe8, 0x02, 0x48, 0xae, 0xeb, - 0x77, 0x48, 0x74, 0xaa, 0x79, 0xd2, 0x90, 0xb8, 0xf5, 0x02, 0x7a, 0x0a, 0x50, 0x95, - 0x37, 0xfc, 0x7c, 0x68, 0x9b, 0x7a, 0xd8, 0x61, 0x16, 0xcf, 0xec, 0x26, 0x47, 0xcc, - 0xaa, 0xe1, 0xc7, 0x4b, 0x41, 0x6f, 0x3e, 0x6a, 0xe8, 0xf7, 0xcc, 0x60, 0xea, 0xaf, - 0x7b, 0x6a, 0x59, 0x0d, 0x51, 0x54, 0x41, 0x38, 0xe1, 0x73, 0x29, 0x45, 0x60, 0x3a, - 0x53, 0x46, 0x2c, 0x60, 0xe1, 0xf6, 0xcb, 0x0c, 0x9c, 0xa0, 0x39, 0x0c, 0x48, 0x82, - 0x24, 0xc3, 0x13, 0x26, 0x9f, 0xcd, 0x59, 0xfc, 0xb6, 0x11, 0xfb, 0x2d, 0x9b, 0x4c, - 0x8f, 0xa6, 0x01, 0xbb, 0x1c, 0xb8, 0xd0, 0x7d, 0x79, 0x7b, 0xf5, 0xde, 0x52, 0xbc, - 0xee, 0xb0, 0x23, 0x01, 0xc8, 0x96, 0x2a, 0xc1, 0xfc, 0x04, 0x91, 0xdc, 0x81, 0xaf, - 0xfd, 0x6c, 0x1e, 0xbf, 0x89, 0xa1, 0x3d, 0x6f, 0x29, 0x0e, 0xda, 0x5d, 0x5c, 0xef, - 0x38, 0x22, 0x15, 0xc5, 0xe9, 0x51, 0xd7, 0x13, 0x05, 0xef, 0x33, 0xd9, 0x73, 0x71, - 0x26, 0xd0, 0xe6, 0x62, 0x90, 0x5f, 0x12, 0x50, 0x92, 0x6f, 0x6a, 0x22, 0x99, 0x90, - 0xe3, 0x8f, 0x69, 0xad, 0x9a, 0x91, 0x92, 0xb3, 0x02, 0xf2, 0x6b, 0xdd, 0xa4, 0x65, - 0xd9, 0x0b, 0x94, 0xb1, 0x2c, 0x57, 0xfa, 0x3f, 0xd6, 0x93, 0x00, 0x83, 0xf1, 0x84, - 0x43, 0x8d, 0x8a, 0x88, 0x9d, 0x3f, 0x5e, 0xce, 0xa2, 0xc6, 0xd2, 0x3d, 0x67, 0x36, - 0xf2, 0xa0, 0xf1, 0x8e, 0x26, 0xf4, 0xfa, 0x45, 0xd1, 0xbe, 0x8f, 0x3d, 0xc4, 0xa7, - 0x07, 0x13, 0x7e, 0x95, 0xd2, 0xad, 0x59, 0x4f, 0x6c, 0x03, 0xd2, 0x49, 0x23, 0x06, - 0x7a, 0xe4, 0x7f, 0xd6, 0x42, 0x5e, 0xfb, 0x9c, 0x1d, 0x50, 0x4e, 0x6f, 0xd5, 0x57, - 0x53, 0x40, 0x94, 0x56, 0x01, 0xfe, 0x80, 0x6f, 0x57, 0x56, 0xac, 0xb5, 0x62, 0xf1, - 0x3c, 0x0c, 0xa1, 0xd8, 0x03, 0xa1, 0x95, 0xc2, 0xeb, 0xb2, 0xef, 0x02, 0xac, 0x33, - 0xe6, 0xa8, 0x8d, 0xea, 0x07, 0x5b, 0xa9, 0x96, 0xd3, 0xc3, 0x36, 0x64, 0x8e, 0x86, - 0x94, 0xd3, 0xa1, 0x9d, 0x3d, 0xca, 0x53, 0x1b, 0xeb, 0x50, 0xd4, 0x32, 0x7c, 0x5c, - 0x0c, 0x23, 0xcb, 0x7c, 0xfd, 0xb0, 0x8c, 0xa7, 0xcf, 0x2c, 0xac, 0x6b, 0xc1, 0x39, - 0xd0, 0x74, 0x14, 0x73, 0xd3, 0x76, 0x02, 0x9c, 0xb4, 0xab, 0x6b, 0xf0, 0x54, 0x55, - 0x7c, 0xe2, 0x94, 0xc7, 0x28, 0xa4, 0x68, 0x7d, 0x57, 0xec, 0x89, 0x09, 0xff, 0x51, - 0xa4, 0xd0, 0x2f, 0x9d, 0xcd, 0x11, 0x19, 0x3d, 0x7d, 0x1c, 0x9f, 0xda, 0xe6, 0xa1, - 0x73, 0x96, 0xa1, 0xbf, 0x57, 0xa9, 0x94, 0x93, 0x4f, 0x5e, 0x7a, 0x59, 0xf0, 0x45, - 0xde, 0xbe, 0xaf, 0xf6, 0x2e, 0xf3, 0x26, 0xb9, 0x47, 0xf2, 0xa8, 0xb4, 0x95, 0x55, - 0xe4, 0xd9, 0x9b, 0x3b, 0xf5, 0xc8, 0x1f, 0xf9, 0xfe, 0x31, 0x4e, 0x04, 0x7a, 0xf1, - 0x52, 0x50, 0x8f, 0x57, 0x01, 0x5c, 0xa4, 0x02, 0xc6, 0x7d, 0x92, 0x5c, 0x99, 0xac, - 0xea, 0x3e, 0xe8, 0xcc, 0x4b, 0x00, 0x8c, 0x5c, 0xb4, 0x39, 0x66, 0xe7, 0x14, 0xef, - 0x48, 0x0f, 0xd0, 0x5e, 0x07, 0xc7, 0xb2, 0xdd, 0xa9, 0xaa, 0x39, 0x66, 0x11, 0x3e, - 0xaa, 0x29, 0x3d, 0x3f, 0x62, 0x2b, 0x30, 0x9d, 0x64, 0x80, 0x3c, 0xe1, 0xe6, 0x37, - 0x8b, 0x6a, 0xac, 0x4f, 0xab, 0x52, 0x7c, 0x43, 0xcd, 0x45, 0xed, 0x0a, 0x3c, 0x1a, - 0x4b, 0x9f, 0xb1, 0x8d, 0xcc, 0xcf, 0xcd, 0xb6, 0xac, 0x0c, 0x24, 0x21, 0x63, 0x9c, - 0xda, 0x00, 0x75, 0xa2, 0x0d, 0xc5, 0x11, 0x1b, 0x8d, 0x3d, 0x31, 0x99, 0x49, 0x5b, - 0xd9, 0x13, 0x3d, 0xba, 0xb9, 0x45, 0x41, 0x41, 0x0e, 0x4f, 0xba, 0x92, 0xc7, 0xb6, - 0x06, 0xa5, 0xcb, 0x12, 0x2f, 0x14, 0x0c, 0xf1, 0xa3, 0x59, 0x6f, 0x27, 0x88, 0xf3, - 0xc8, 0xb9, 0x26, 0x60, 0xf1, 0x4c, 0xb6, 0x5a, 0xf5, 0xdd, 0x23, 0xdf, 0xdb, 0xac, - 0x13, 0x71, 0xec, 0xf4, 0xb3, 0x37, 0x12, 0xfe, 0xd2, 0x29, 0x2c, 0x44, 0xf7, 0x08, - 0x34, 0xcf, 0x96, 0xc0, 0x5d, 0x58, 0x82, 0x7e, 0x69, 0xbf, 0xc2, 0xe6, 0x96, 0xfa, - 0x08, 0x74, 0x86, 0x9c, 0x02, 0xf3, 0xdc, 0xa1, 0x1c, 0x3b, 0x90, 0xcb, 0x21, 0x4e, - 0x68, 0xbc, 0x1c, 0xae, 0x03, 0x9d, 0x7a, 0x14, 0x6c, 0xdc, 0x1d, 0x60, 0x9d, 0x7a, - 0x6b, 0x3f, 0xd5, 0xd4, 0x61, 0xb0, 0x95, 0x1c, 0x82, 0xcf, 0xb3, 0xe7, 0x63, 0xfa, - 0xd2, 0xd1, 0xbc, 0x76, 0x78, 0xcd, 0xf8, 0x27, 0x79, 0xf8, 0xfd, 0x5a, 0x1c, 0xe2, - 0x2a, 0x8d, 0x3c, 0x45, 0x47, 0xab, 0xd9, 0x59, 0x83, 0x8a, 0x46, 0xfb, 0x80, 0xaf, - 0xe0, 0x1f, 0x8e, 0xcc, 0x99, 0x31, 0x51, 0x3b, 0x19, 0x62, 0xec, 0x54, 0x08, 0x56, - 0xcb, 0x18, 0x93, 0x87, 0xcf, 0xbf, 0xcc, 0x0f, 0x7c, 0x68, 0x22, 0x3c, 0xba, 0x47, - 0xfb, 0x0c, 0x9b, 0x48, 0x6e, 0x4d, 0x99, 0x17, 0x19, 0x41, 0xf7, 0x67, 0x5a, 0x8b, - 0x46, 0x32, 0x8a, 0x3b, 0xc1, 0x09, 0xbf, 0x07, 0xc6, 0x6d, 0x5e, 0xde, 0x77, 0x1c, - 0xc4, 0xc7, 0x4c, 0xe8, 0x03, 0x33, 0x82, 0x91, 0x91, 0xee, 0xdc, 0x49, 0x35, 0x08, - 0xa6, 0x44, 0x53, 0x0a, 0x61, 0x44, 0xf2, 0x2d, 0xcf, 0x97, 0x52, 0x5a, 0x4c, 0xdc, - 0xa1, 0xad, 0x71, 0x07, 0x3b, 0x08, 0x0b, 0x73, 0xea, 0x45, 0x49, 0xf5, 0x40, 0x1b, - 0xff, 0x43, 0x18, 0x26, 0x8e, 0x6a, 0xd6, 0x37, 0x36, 0x31, 0x57, 0xa1, 0x9a, 0x53, - 0xf1, 0x23, 0xa0, 0xb0, 0xe1, 0x6d, 0x0b, 0x77, 0xf0, 0x20, 0x28, 0xda, 0x46, 0x41, - 0x00, 0xfd, 0xe7, 0x6d, 0x83, 0xdd, 0x0b, 0xb2, 0x24, 0xf7, 0xb5, 0x7a, 0x00, 0xc0, - 0x2f, 0x68, 0xae, 0x64, 0x8f, 0xdc, 0x52, 0x99, 0x57, 0xa1, 0x04, 0x90, 0xdc, 0xe1, - 0xfd, 0xdb, 0xb0, 0x90, 0x4f, 0x0d, 0x51, 0x8b, 0xb3, 0x87, 0x54, 0x40, 0x19, 0x98, - 0x3b, 0x61, 0x69, 0x75, 0xa7, 0x8e, 0x74, 0xd8, 0x54, 0xfd, 0xdc, 0x49, 0xb2, 0x55, - 0x16, 0x7b, 0x55, 0xef, 0x4b, 0xee, 0x46, 0x56, 0x68, 0xb2, 0x0e, 0xa4, 0x11, 0x8c, - 0xa5, 0x69, 0xae, 0x48, 0x0e, 0x0f, 0x6e, 0x5e, 0x04, 0x3a, 0x35, 0x7b, 0x36, 0xd3, - 0xab, 0x36, 0xc8, 0x61, 0xf2, 0x27, 0x83, 0x01, 0xdc, 0xe5, 0x76, 0x74, 0xd5, 0x07, - 0x3b, 0x3a, 0x6f, 0x51, 0x03, 0xa0, 0x79, 0x3a, 0xf1, 0xb7, 0xd4, 0x6f, 0x95, 0x7e, - 0x22, 0xd8, 0xd2, 0x58, 0x3b, 0xf1, 0x81, 0x83, 0x6c, 0x3b, 0xe9, 0x93, 0x0b, 0xac, - 0x8f, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x60, 0xe9, 0x68, 0xaa, 0x71, 0x09, 0x87, 0x0b, 0xbe, 0xd1, - 0x7d, 0xf5, 0xf8, 0x88, 0xc8, 0xca, 0x14, 0x67, 0xae, 0x17, 0xdb, 0xbc, 0xde, 0x31, - 0xc1, 0x10, 0x5c, 0xb5, 0xbd, 0xa8, 0x8a, 0xc6, 0xc6, 0x27, 0x00, 0x2c, 0xe2, 0x1c, - 0x02, 0x14, 0x0f, 0xfe, 0x81, 0xec, 0x58, 0xbf, 0x1e, 0x6d, 0x1b, 0xb7, 0xaa, 0xad, - 0xa4, 0x1f, 0xba, 0x0b, 0xb5, 0x88, 0x77, 0x8a, 0x7f, 0x65, 0x20, 0x2a, 0xd8, 0x11, - 0xea, 0x73, 0xd2, 0x6c, 0x74, 0x55, 0x03, 0x95, 0xaf, 0xf7, 0x53, 0x25, 0x10, 0x7c, - 0x9b, 0x3f, 0x9a, 0xe9, 0xdc, 0xdc, 0xd8, 0x6e, 0xd0, 0x81, 0xa2, 0xe7, 0x42, 0x47, - 0x19, 0xa3, 0xd1, 0x85, 0xb7, 0xe0, 0xa4, 0x3a, 0x47, 0x2e, 0x29, 0x8a, 0xc0, 0xaf, - 0xdc, 0x52, 0x87, 0xd7, 0xad, 0x12, 0x4c, 0xd9, 0x40, 0x5a, 0x62, 0xcd, 0x1c, 0xa0, - 0x8b, 0x28, 0x2e, 0xfe, 0xf7, 0xf9, 0x28, 0xdf, 0x76, 0xe2, 0x82, 0x1a, 0x41, 0x84, - 0x13, 0xeb, 0x7c, 0xea, 0xa5, 0xff, 0x12, 0x90, 0xb0, 0x3e, 0xc9, 0x1c, 0xe6, 0xdd, - 0x28, 0x13, 0x0c, 0x3a, 0xb0, 0xb2, 0x3b, 0x60, 0x2b, 0xd5, 0xbe, 0x5d, 0xc2, 0x60, - 0x03, 0xaa, 0xe0, 0x4b, 0x33, 0xd7, 0xbd, 0x25, 0x90, 0xe9, 0x0c, 0x8c, 0x38, 0x8e, - 0xa7, 0x95, 0x51, 0x22, 0xdb, 0xac, 0xa6, 0x7b, 0x30, 0x39, 0x5a, 0x92, 0x8b, 0x57, - 0xb8, 0x57, 0x51, 0x23, 0x20, 0x5a, 0xe1, 0x91, 0x52, 0xe4, 0x1e, 0x00, 0x29, 0x31, - 0xb4, 0x57, 0x46, 0x19, 0x8e, 0x5d, 0xd9, 0x57, 0x1a, 0x56, 0xa7, 0xe0, 0xd4, 0x23, - 0xff, 0x27, 0x98, 0x9d, 0x3e, 0xb4, 0x17, 0xec, 0xd3, 0xc3, 0x09, 0x3f, 0xb8, 0x2c, - 0x56, 0x58, 0xe2, 0x96, 0x24, 0xc5, 0x32, 0x19, 0xa6, 0x0c, 0xd0, 0xa8, 0xc4, 0xda, - 0x36, 0x7e, 0x29, 0xa7, 0x17, 0x79, 0xa7, 0x30, 0x32, 0x98, 0x5a, 0x3d, 0x1f, 0xd0, - 0x3d, 0xd4, 0xd0, 0x6e, 0x05, 0x56, 0x6f, 0x3b, 0x84, 0x36, 0x7c, 0xf0, 0xfa, 0xee, - 0x9b, 0xc3, 0xbd, 0x7a, 0x3a, 0x60, 0x6a, 0x9f, 0xdb, 0x84, 0x9c, 0x5d, 0x82, 0xd0, - 0xa6, 0x19, 0x23, 0xc2, 0xe5, 0xd8, 0xaa, 0x63, 0xa8, 0xa5, 0x0c, 0x38, 0xbd, 0x03, - 0x87, 0x72, 0xc4, 0x14, 0x3d, 0x8b, 0x7a, 0xcf, 0xd7, 0x4e, 0x72, 0xc0, 0x4d, 0x89, - 0x24, 0x8d, 0xff, 0x20, 0xfe, 0x8d, 0xc5, 0xec, 0x21, 0x49, 0x05, 0x4e, 0xa2, 0x41, - 0x64, 0xe8, 0x5f, 0x67, 0x44, 0xad, 0x0c, 0xac, 0xf1, 0xa8, 0xb7, 0x01, 0x26, 0xf4, - 0x82, 0xc0, 0x92, 0xed, 0x9f, 0x61, 0x27, 0xd2, 0x05, 0x0d, 0x12, 0xe8, 0x78, 0xa7, - 0x96, 0x53, 0xa1, 0xe8, 0x4d, 0xae, 0xc3, 0xeb, 0xe6, 0x2d, 0x5f, 0x6c, 0x4a, 0xbe, - 0x5c, 0xe9, 0x0a, 0x7f, 0xe2, 0xe5, 0x2a, 0x8d, 0x78, 0x46, 0xe8, 0xed, 0xf2, 0xf2, - 0xbc, 0xe0, 0x5a, 0x03, 0x7c, 0x82, 0x6f, 0x22, 0xca, 0xad, 0x12, 0x61, 0x46, 0x7d, - 0xcf, 0xb7, 0xd6, 0xb6, 0x13, 0x3d, 0xc2, 0x1e, 0x80, 0x96, 0xc7, 0xe9, 0xf8, 0xe9, - 0xe1, 0x0c, 0x1e, 0x3f, 0xac, 0x40, 0x58, 0xb6, 0x82, 0xc6, 0x8e, 0x54, 0xfa, 0xca, - 0xe0, 0xf9, 0xc2, 0xdd, 0x4d, 0x64, 0xd9, 0x04, 0x61, 0x52, 0xb4, 0x76, 0x23, 0x32, - 0x93, 0x9f, 0x17, 0xe6, 0xaa, 0xf7, 0xd8, 0xb9, 0xd3, 0x58, 0xe2, 0x21, 0x8d, 0x4e, - 0x0d, 0x69, 0xa4, 0xf1, 0x19, 0xe1, 0xc6, 0x4e, 0xec, 0x4c, 0x8b, 0x53, 0x28, 0x09, - 0x70, 0x71, 0x31, 0xf0, 0x1f, 0x55, 0xc7, 0xad, 0x04, 0xcf, 0xb6, 0x3f, 0x7c, 0x4a, - 0x3d, 0x0a, 0x2b, 0x0f, 0xfb, 0x0b, 0x05, 0xa6, 0xbe, 0x05, 0x5b, 0x8c, 0x94, 0xca, - 0x80, 0xbb, 0x0a, 0x1d, 0x13, 0xcd, 0x4c, 0xd6, 0x9a, 0xb9, 0x83, 0x04, 0xae, 0x25, - 0x15, 0xd5, 0xf7, 0x69, 0x9d, 0x4a, 0xbe, 0xe5, 0xc2, 0x0b, 0xe6, 0x09, 0xd8, 0x73, - 0x51, 0x10, 0x12, 0xf2, 0x34, 0xbd, 0x85, 0xa7, 0xef, 0xf5, 0xfb, 0x63, 0x4c, 0xff, - 0x26, 0x58, 0xba, 0x65, 0x16, 0x04, 0x85, 0x63, 0x09, 0x5e, 0xce, 0xfb, 0x30, 0x15, - 0xee, 0x3f, 0x03, 0xca, 0x52, 0xa1, 0x77, 0xf2, 0x61, 0xec, 0xdc, 0x26, 0xbc, 0x08, - 0x9d, 0x34, 0xc6, 0x40, 0x48, 0x46, 0xe9, 0xc6, 0x47, 0xfc, 0xfe, 0x98, 0xcc, 0x6a, - 0xcd, 0xbb, 0x46, 0x4f, 0x64, 0x27, 0x8a, 0xd8, 0xce, 0x9d, 0x1a, 0xe0, 0xd4, 0x15, - 0xbc, 0x0c, 0x05, 0x24, 0x5f, 0xdd, 0xaf, 0x4e, 0xbc, 0x8d, 0xc7, 0x03, 0xa8, 0x5c, - 0xb2, 0x70, 0xf7, 0x96, 0xad, 0x2d, 0x93, 0x7e, 0x2a, 0xc0, 0xd5, 0xe0, 0xa3, 0x48, - 0x21, 0x75, 0x80, 0x00, 0xaa, 0x59, 0xc9, 0xd4, 0x65, 0x24, 0x85, 0x29, 0x4e, 0xe0, - 0xab, 0x29, 0x69, 0x6b, 0x21, 0x43, 0x0f, 0xa5, 0x4d, 0xcf, 0xbf, 0x2b, 0x9c, 0x49, - 0xd1, 0x42, 0x06, 0x42, 0x09, 0xee, 0xee, 0xd4, 0xd4, 0x71, 0xff, 0xc0, 0x17, 0xd4, - 0xe2, 0x0a, 0x79, 0x6b, 0x09, 0x27, 0x80, 0x4c, 0x06, 0x1b, 0x9f, 0x4a, 0x70, 0x91, - 0xfe, 0x01, 0x5a, 0xda, 0x68, 0xfd, 0x84, 0x42, 0xe0, 0x18, 0x25, 0xc8, 0x8d, 0xfe, - 0x55, 0xcf, 0x5d, 0xe3, 0x89, 0x36, 0xf7, 0xce, 0x25, 0x31, 0x1b, 0x90, 0x2b, 0xa9, - 0x7a, 0x3c, 0x12, 0xa9, 0x5c, 0xfa, 0x1c, 0x3a, 0x59, 0x1b, 0x81, 0x8f, 0x60, 0x83, - 0x27, 0x09, 0xd9, 0xe4, 0x83, 0x9e, 0x41, 0x0f, 0xb3, 0x6b, 0x84, 0xf3, 0xac, 0x4f, - 0x07, 0x0f, 0xc3, 0x5e, 0x16, 0x19, 0x78, 0x25, 0x9e, 0x5b, 0x8e, 0xdc, 0x74, 0x4d, - 0x90, 0x91, 0x9a, 0xa7, 0x70, 0xbb, 0x36, 0x21, 0x51, 0x28, 0xe5, 0x82, 0xb5, 0x96, - 0x41, 0xe2, 0x38, 0x52, 0xe9, 0x58, 0xeb, 0x8f, 0xc3, 0xc0, 0xaa, 0x96, 0x15, 0x2b, - 0xa4, 0xf7, 0x7f, 0x13, 0x8d, 0x6a, 0x67, 0x12, 0xa3, 0xae, 0x32, 0x26, 0x01, 0x58, - 0x83, 0xf8, 0x1d, 0xb2, 0x3e, 0x58, 0x3c, 0x86, 0x9c, 0x4c, 0x71, 0x14, 0x3a, 0x6f, - 0xff, 0xd6, 0x5e, 0x8d, 0xfd, 0xc5, 0x0c, 0x99, 0xa2, 0xf1, 0xf3, 0x14, 0xcd, 0xcc, - 0x71, 0x35, 0x9e, 0x23, 0x5f, 0x1d, 0x7d, 0xc2, 0xb5, 0xf3, 0x8e, 0xf7, 0xb9, 0x70, - 0x84, 0x31, 0x63, 0xc0, 0x3f, 0x9d, 0xd4, 0x0a, 0x80, 0x15, 0xef, 0xdc, 0x87, 0x91, - 0x95, 0x6a, 0x3f, 0x3c, 0xed, 0xd9, 0xea, 0x64, 0xf8, 0xef, 0xa7, 0xa0, 0x81, 0x5a, - 0x70, 0x38, 0x1d, 0x71, 0x46, 0x78, 0x17, 0xbd, 0x04, 0xca, 0x52, 0x9a, 0xed, 0xe0, - 0x7f, 0xf6, 0x0d, 0x17, 0x6a, 0xed, 0x0f, 0x85, 0x5a, 0x2e, 0xae, 0xa8, 0x9e, 0xae, - 0xac, 0xa8, 0x93, 0x58, 0xc0, 0x81, 0x82, 0x6a, 0x08, 0x12, 0xa5, 0xbc, 0xa2, 0x8b, - 0xe1, 0x37, 0x3f, 0x08, 0x6d, 0xbd, 0xba, 0x7e, 0x43, 0xe2, 0x03, 0x21, 0x2c, 0x9f, - 0xed, 0x21, 0x47, 0x4b, 0xa1, 0x9a, 0x05, 0x5f, 0xfc, 0xc1, 0x79, 0x41, 0x2e, 0x89, - 0x3a, 0x74, 0x48, 0x32, 0x29, 0x8c, 0x5f, 0xe2, 0x4c, 0xc6, 0xb1, 0x86, 0x67, 0xf4, - 0x9b, 0x34, 0xdf, 0xb1, 0x23, 0x79, 0x26, 0x74, 0x19, 0xa9, 0xcb, 0x94, 0x03, 0xd8, - 0x16, 0x7d, 0x8d, 0x1e, 0x91, 0xd2, 0x81, 0x1a, 0x04, 0x3b, 0x29, 0x24, 0x3b, 0x06, - 0x9b, 0x37, 0x58, 0x78, 0x47, 0xdc, 0x6f, 0xcd, 0xdb, 0x18, 0x31, 0xbd, 0x1c, 0xc2, - 0x56, 0x7c, 0xa0, 0x33, 0xac, 0x40, 0xf7, 0x4a, 0xb6, 0x95, 0x5f, 0x68, 0x3b, 0x12, - 0xe4, 0xe8, 0x25, 0x4e, 0x4e, 0xa7, 0x60, 0xd3, 0x8b, 0x3f, 0x46, 0x79, 0x1c, 0x5c, - 0x4c, 0xb1, 0x2b, 0xc7, 0xcc, 0xb0, 0xed, 0x18, 0x65, 0xf2, 0x5d, 0x60, 0x1c, 0x30, - 0x3f, 0x81, 0xfb, 0x1f, 0xa1, 0xdb, 0x48, 0x53, 0x3d, 0x3d, 0x6b, 0x28, 0x8e, 0x4d, - 0x9a, 0x4d, 0xff, 0x8e, 0xc2, 0x1c, 0x96, 0xf5, 0x78, 0x39, 0x97, 0x10, 0xc8, 0x25, - 0xfe, 0x7e, 0x32, 0xf9, 0x3a, 0x8c, 0x07, 0x43, 0xf9, 0xeb, 0xd5, 0x4c, 0xc1, 0x51, - 0xc7, 0x61, 0x03, 0x37, 0xae, 0xbf, 0x7e, 0x9b, 0x91, 0x57, 0x20, 0xa5, 0x43, 0x51, - 0xd4, 0x9a, 0xb8, 0xc2, 0x2f, 0xa3, 0x49, 0x98, 0xdc, 0xf5, 0x83, 0xd4, 0x38, 0x73, - 0x61, 0xef, 0x3f, 0xf8, 0x6f, 0x50, 0xec, 0x53, 0xf4, 0x92, 0x49, 0xe4, 0xad, 0x34, - 0x96, 0x03, 0x06, 0x6f, 0xc9, 0xc6, 0x61, 0xd6, 0x9f, 0x91, 0x1d, 0xfa, 0x72, 0x41, - 0xc8, 0xd5, 0x79, 0x2d, 0x43, 0xc4, 0x57, 0xd5, 0xde, 0x96, 0x52, 0x3a, 0x53, 0xd6, - 0x67, 0xec, 0x5c, 0x4e, 0xf9, 0xd5, 0x02, 0xa1, 0x6f, 0x15, 0x22, 0x47, 0x58, 0x96, - 0xd7, 0x9b, 0xc5, 0x78, 0x33, 0xe9, 0x77, 0x17, 0x1c, 0x32, 0x4d, 0xce, 0x2a, 0x1e, - 0xa1, 0xe4, 0x30, 0x4f, 0x49, 0xe4, 0x3a, 0xe0, 0x65, 0xe3, 0xfb, 0x19, 0x6f, 0x76, - 0xd9, 0xb8, 0x79, 0xc7, 0x20, 0x08, 0x62, 0xea, 0xd1, 0x8d, 0xea, 0x5f, 0xb6, 0xa1, - 0x7a, 0xce, 0xa3, 0x33, 0x86, 0xeb, 0x4c, 0xa1, 0xb5, 0x14, 0x86, 0xa9, 0x14, 0x8f, - 0xbd, 0xf9, 0xa9, 0x53, 0x32, 0xaa, 0x60, 0x5c, 0x5d, 0x54, 0x83, 0xce, 0x4b, 0xa8, - 0xec, 0xe0, 0x1a, 0x8f, 0xf2, 0xb7, 0xef, 0x82, 0xd0, 0x5c, 0x0b, 0x6e, 0x86, 0x1b, - 0x91, 0x5f, 0x13, 0xca, 0x0e, 0xb3, 0xea, 0x13, 0xd5, 0x07, 0x08, 0x07, 0xa2, 0xcb, - 0x66, 0x80, 0xa2, 0x49, 0xea, 0x9c, 0x72, 0x24, 0x39, 0x2c, 0xbc, 0x8a, 0xb8, 0x25, - 0x01, 0xb2, 0x6f, 0x11, 0x2a, 0xc7, 0x89, 0xa1, 0x2a, 0x31, 0xad, 0x13, 0x14, 0xe2, - 0xed, 0xe0, 0x8f, 0xad, 0x31, 0x43, 0xaf, 0x30, 0xc2, 0x7f, 0x40, 0x3b, 0xc8, 0x66, - 0xc7, 0x55, 0x17, 0x78, 0x52, 0xaf, 0xd0, 0xab, 0xb9, 0x0a, 0xde, 0x1d, 0x68, 0x27, - 0x26, 0xf4, 0x20, 0x08, 0xb4, 0x6a, 0xd7, 0xf8, 0xab, 0xdb, 0x18, 0x11, 0x7f, 0x72, - 0x64, 0x13, 0x90, 0xf0, 0x86, 0xb6, 0xe1, 0x49, 0x8b, 0xe6, 0x95, 0x48, 0x52, 0x7e, - 0x6a, 0xda, 0x2b, 0x38, 0xb9, 0xfe, 0x12, 0x1e, 0xf6, 0x70, 0xaf, 0x74, 0x37, 0xd3, - 0x25, 0x36, 0xd5, 0xcf, 0x5c, 0x4a, 0xb1, 0x9d, 0xd9, 0x97, 0x71, 0x58, 0x2d, 0x03, - 0x81, 0x04, 0xb7, 0xe0, 0x39, 0xa3, 0x76, 0xf7, 0xac, 0xbb, 0xea, 0xdb, 0x34, 0xf9, - 0x45, 0xbe, 0xb9, 0xd7, 0xca, 0x0e, 0x4e, 0x3d, 0x5c, 0x5e, 0x4e, 0xb1, 0xd8, 0x52, - 0x6e, 0xbd, 0x13, 0xda, 0xcb, 0x1b, 0xa3, 0x57, 0x35, 0xc6, 0xd0, 0x4a, 0x45, 0x55, - 0xac, 0xf4, 0xbf, 0x11, 0x76, 0x26, 0x50, 0x0d, 0x77, 0xb3, 0x81, 0x89, 0xdd, 0x48, - 0x88, 0x04, 0x12, 0x25, 0xac, 0xbe, 0x38, 0x74, 0xa4, 0xc0, 0xf6, 0x07, 0xfe, 0x67, - 0x45, 0xf9, 0x35, 0x5b, 0x3f, 0xa1, 0x88, 0xf1, 0xd6, 0x5c, 0x09, 0xf3, 0x89, 0xaf, - 0x1b, 0x9d, 0x62, 0x32, 0xaa, 0x79, 0x44, 0x79, 0x19, 0xc5, 0x50, 0xf6, 0xf3, 0x1f, - 0xec, 0x35, 0x48, 0x1c, 0xb9, 0x22, 0xde, 0x2d, 0xb5, 0xb4, 0xda, 0x2f, 0x81, 0x94, - 0x86, 0x17, 0x02, 0x8e, 0x32, 0x17, 0x06, 0xa3, 0xa7, 0x78, 0xc1, 0x93, 0x8c, 0x44, - 0x3b, 0xb0, 0x0e, 0x5b, 0x0f, 0xf0, 0x6a, 0xd8, 0xab, 0x9b, 0x1a, 0xb0, 0xc1, 0x14, - 0x77, 0x67, 0x3f, 0x85, 0xdf, 0x95, 0x61, 0xdb, 0xea, 0x45, 0xd5, 0xf9, 0x78, 0x1e, - 0xbe, 0x31, 0x7a, 0x07, 0x10, 0xae, 0x54, 0x61, 0xe3, 0x4f, 0xe6, 0xf1, 0xb1, 0xaa, - 0x9b, 0x4e, 0x67, 0xb1, 0x49, 0x10, 0x98, 0x48, 0x02, 0xc2, 0xa7, 0xe3, 0x81, 0x93, - 0xbc, 0x7b, 0xdc, 0x8b, 0xa3, 0xe4, 0xe3, 0xd1, 0xd9, 0x33, 0xbf, 0xb5, 0x80, 0xf5, - 0xb3, 0xe8, 0x7a, 0x2a, 0x06, 0x51, 0x70, 0x51, 0x41, 0x0f, 0xe1, 0xb4, 0xff, 0x1e, - 0xa0, 0xad, 0xe8, 0x24, 0xf3, 0x38, 0x51, 0x54, 0x56, 0xa5, 0x7c, 0x7a, 0x91, 0x6a, - 0x74, 0x38, 0x8e, 0xe8, 0xf1, 0x28, 0x1f, 0x9a, 0xde, 0x0a, 0xe2, 0xa2, 0x61, 0x3a, - 0x06, 0x12, 0xc4, 0x69, 0xdf, 0x79, 0x2b, 0x8d, 0xf4, 0xca, 0xe4, 0xfc, 0x25, 0xc1, - 0xca, 0xdb, 0xa9, 0x5a, 0x80, 0x7c, 0xe6, 0x1e, 0x5a, 0x53, 0x03, 0xfa, 0xaf, 0x9e, - 0x14, 0x65, 0x39, 0x96, 0xb5, 0xa8, 0xad, 0xc3, 0x4f, 0xd4, 0x75, 0xef, 0x14, 0x99, - 0x09, 0x4b, 0xab, 0xaf, 0x1f, 0x3f, 0x07, 0xda, 0x9a, 0x39, 0x0b, 0x1d, 0x9f, 0xc9, - 0xa0, 0x83, 0x27, 0x98, 0x7a, 0xdf, 0xe9, 0x56, 0x48, 0x63, 0xfb, 0xdf, 0xa8, 0xf6, - 0xb4, 0x6a, 0x88, 0x41, 0x58, 0x30, 0x99, 0xaf, 0xb7, 0x87, 0x01, 0x18, 0xfa, 0xce, - 0x76, 0x34, 0x7e, 0x40, 0xb6, 0xfd, 0x8c, 0xd1, 0x55, 0x82, 0xae, 0x8e, 0x23, 0xbe, - 0x9a, 0x02, 0x19, 0xbc, 0x3e, 0x4e, 0x45, 0x46, 0xa3, 0x0d, 0x3b, 0xbb, 0xbd, 0x16, - 0x86, 0x08, 0x68, 0x76, 0xbe, 0x0e, 0x4c, 0x85, 0x9b, 0xe7, 0x1f, 0xb5, 0x8f, 0x4f, - 0xab, 0x3d, 0x28, 0xc0, 0xb4, 0xf7, 0xe7, 0x5a, 0xd1, 0xed, 0xb7, 0xf8, 0x89, 0x46, - 0xfb, 0x40, 0xcf, 0xa5, 0x78, 0x6a, 0x0f, 0xcb, 0xa1, 0x30, 0x3c, 0x83, 0x47, 0xec, - 0xee, 0x93, 0xd4, 0x6d, 0x14, 0x0b, 0xb5, 0xf6, 0x95, 0x31, 0xd6, 0x66, 0x54, 0x8b, - 0x10, 0x9c, 0xe7, 0x64, 0xbe, 0xad, 0x7c, 0x87, 0xbd, 0x4c, 0x87, 0x64, 0x94, 0xde, - 0x82, 0xdb, 0x6e, 0x50, 0x73, 0xa6, 0xc9, 0x4f, 0x7c, 0x09, 0x9a, 0x40, 0xd7, 0xa3, - 0x1c, 0x4a, 0x04, 0xb6, 0x9c, 0x9f, 0xcc, 0xf3, 0xc7, 0xdd, 0x56, 0xf5, 0x54, 0x47, - 0x76, 0xc5, 0x3b, 0x4d, 0xf7, 0x95, 0x39, 0x81, 0xd5, 0x5a, 0x96, 0xa6, 0xdc, 0xff, - 0x99, 0x04, 0xa9, 0x08, 0x42, 0xe5, 0xba, 0xfe, 0xc8, 0x84, 0x0c, 0x2d, - ], - script_code: vec![0x53, 0x63, 0x63, 0x51, 0xac, 0x00, 0x51], - transparent_input: None, - hash_type: 1, - amount: 1345602751504862, - consensus_branch_id: 1991772603, - sighash: [ - 0x15, 0x53, 0xd4, 0xf1, 0x07, 0x45, 0x10, 0x71, 0x81, 0x99, 0x00, 0x5f, 0xef, 0xaa, - 0xa8, 0x3e, 0x29, 0xd1, 0x63, 0xee, 0xbd, 0xf3, 0xc0, 0x33, 0x82, 0x79, 0x08, 0xac, - 0xb4, 0x6f, 0xa2, 0x4b, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x00, 0x01, 0x13, 0xf9, 0x12, 0xa5, - 0xdc, 0x0e, 0x00, 0x00, 0x09, 0x53, 0x53, 0xac, 0x63, 0x6a, 0x53, 0x63, 0xac, 0x6a, - 0x2f, 0x2c, 0x3b, 0x86, 0x0e, 0x40, 0xe3, 0x1c, 0x61, 0x8c, 0xa1, 0x7d, 0xf7, 0x15, - 0x04, 0x00, 0x01, 0x21, 0xbf, 0x07, 0x11, 0x5b, 0x3a, 0x39, 0xbb, 0x87, 0xf7, 0x23, - 0x91, 0x52, 0x4b, 0x82, 0x0e, 0xf3, 0x5c, 0xfc, 0x09, 0x58, 0xd4, 0x19, 0x2f, 0x49, - 0x59, 0xef, 0xe4, 0xb9, 0xa7, 0xb5, 0x29, 0x98, 0x8a, 0x3f, 0x7d, 0x27, 0x37, 0x91, - 0x49, 0x0a, 0x6b, 0x48, 0x49, 0x5a, 0x80, 0x06, 0x45, 0x5e, 0x86, 0x57, 0x71, 0xbe, - 0x92, 0x06, 0xd5, 0x4b, 0x43, 0x02, 0x4a, 0xf5, 0xe6, 0xc9, 0x5b, 0x33, 0xf6, 0xda, - 0xd1, 0x66, 0x6a, 0x05, 0xf9, 0x1a, 0xd7, 0x75, 0x79, 0x65, 0xc2, 0x99, 0x36, 0xe7, - 0xfa, 0x48, 0xd7, 0x7e, 0x89, 0xee, 0x09, 0x62, 0xf5, 0x8c, 0x05, 0x1d, 0x11, 0xd0, - 0x55, 0xfc, 0xe2, 0x04, 0xa5, 0x62, 0xde, 0x68, 0x08, 0x8a, 0x1b, 0x26, 0x48, 0xb8, - 0x17, 0x4c, 0xbc, 0xfc, 0x8b, 0x5b, 0x5c, 0xd0, 0x77, 0x11, 0x5a, 0xfd, 0xe1, 0x84, - 0x05, 0x05, 0x4e, 0x5d, 0xa9, 0xa0, 0x43, 0x10, 0x34, 0x2c, 0x5d, 0x3b, 0x52, 0x6e, - 0x0b, 0x02, 0xc5, 0xca, 0x17, 0x22, 0xba, 0xde, 0xee, 0x23, 0xd1, 0x45, 0xe8, 0xeb, - 0x22, 0x13, 0xfc, 0x4a, 0xf1, 0xe4, 0x50, 0xe4, 0xd5, 0x21, 0x7c, 0x66, 0x17, 0x00, - 0x8c, 0x78, 0xf4, 0xfb, 0x11, 0x12, 0xf4, 0x02, 0x8a, 0x70, 0x4f, 0xc5, 0xa9, 0x38, - 0x2c, 0x6b, 0x03, 0xe7, 0xd8, 0x08, 0x5e, 0x90, 0x6c, 0xf8, 0x4c, 0xa2, 0xc1, 0x20, - 0x7c, 0x87, 0xa2, 0xbc, 0xe2, 0x08, 0x0a, 0x98, 0x91, 0x66, 0x8d, 0x69, 0xb0, 0x44, - 0xbe, 0xce, 0xd6, 0xcd, 0xa3, 0x2c, 0x22, 0x9c, 0x91, 0x17, 0x91, 0x7a, 0xa0, 0x7d, - 0xdf, 0xfc, 0xd3, 0x77, 0x39, 0x5c, 0xba, 0x61, 0x6d, 0x63, 0xc0, 0xb6, 0x9c, 0x01, - 0xfc, 0xc4, 0x53, 0x91, 0xfd, 0x5b, 0x87, 0x63, 0xfb, 0x96, 0xd7, 0xca, 0x33, 0x3a, - 0x12, 0xde, 0x3c, 0xef, 0xa9, 0x1c, 0x6c, 0x98, 0xf9, 0x47, 0x3b, 0x8e, 0x10, 0x4a, - 0x71, 0x29, 0x3e, 0x46, 0x37, 0x47, 0x05, 0xba, 0xf6, 0x5f, 0xa4, 0x13, 0x84, 0xba, - 0x5c, 0x8e, 0x0c, 0x88, 0xa3, 0xeb, 0x07, 0xe0, 0xbe, 0x34, 0xda, 0xdd, 0xfa, 0xbb, - 0x7b, 0x65, 0x54, 0x3b, 0x5f, 0x39, 0xcb, 0x20, 0x23, 0xd4, 0x67, 0x89, 0xeb, 0x7d, - 0x98, 0x9a, 0xf7, 0x79, 0xe5, 0xb8, 0xd2, 0x83, 0x85, 0xa8, 0x5b, 0x0d, 0xa2, 0xab, - 0xe0, 0x7f, 0x0c, 0x2b, 0xb4, 0x25, 0x5f, 0xce, 0xa0, 0x31, 0x88, 0x52, 0x7a, 0x30, - 0x7d, 0x40, 0x91, 0x59, 0xe9, 0x01, 0x66, 0xfa, 0xc6, 0xa0, 0x70, 0xba, 0x05, 0xb3, - 0xe4, 0xdb, 0xfd, 0x3a, 0x2b, 0xfc, 0xc9, 0xee, 0x6e, 0xd0, 0x16, 0xc0, 0xf6, 0x65, - 0xbe, 0x81, 0x33, 0xb7, 0xdc, 0x1d, 0x86, 0x04, 0x4d, 0xb0, 0xf9, 0xdb, 0x40, 0xfb, - 0x0e, 0x9f, 0x8b, 0xc2, 0xe4, 0xdb, 0x53, 0x82, 0xa8, 0x04, 0x53, 0xfd, 0xd8, 0x8f, - 0x52, 0xb0, 0x59, 0xc7, 0x96, 0x49, 0x43, 0xc1, 0xc0, 0xdf, 0x3b, 0x6b, 0x64, 0x10, - 0xf9, 0x5d, 0xef, 0x5c, 0x04, 0x78, 0xf6, 0x85, 0xc6, 0xb3, 0x3a, 0xa0, 0xc8, 0x8e, - 0x68, 0x82, 0x42, 0x8e, 0x8c, 0xba, 0x43, 0x64, 0xea, 0x93, 0xaf, 0x37, 0x8c, 0x50, - 0x64, 0x82, 0x27, 0x36, 0x58, 0xa2, 0xc0, 0x95, 0xdd, 0x07, 0x6c, 0x39, 0x73, 0x19, - 0x1d, 0x46, 0xa1, 0x03, 0x9e, 0x5d, 0x6b, 0x7d, 0x9c, 0x08, 0x6b, 0x25, 0x85, 0x90, - 0xd3, 0x2d, 0x76, 0xe3, 0xd4, 0x20, 0x38, 0x43, 0x57, 0x0e, 0xfe, 0xed, 0x97, 0x1c, - 0x14, 0x12, 0x2f, 0x5b, 0x21, 0x5b, 0x0f, 0x38, 0xbb, 0xc7, 0x16, 0xb6, 0xa5, 0x94, - 0x4e, 0xe7, 0x27, 0x96, 0x56, 0x90, 0xe2, 0x09, 0xb4, 0x9e, 0xb9, 0x62, 0xc0, 0x39, - 0x97, 0x5f, 0x93, 0x9e, 0xd5, 0xc6, 0xe4, 0xc4, 0x00, 0xd8, 0x87, 0x75, 0x94, 0x33, - 0xd3, 0xad, 0x71, 0x6d, 0xa0, 0xcb, 0x44, 0x61, 0x13, 0xc7, 0x72, 0x7a, 0x64, 0xb5, - 0x8c, 0x3f, 0x8a, 0x0f, 0x81, 0x18, 0x9f, 0x98, 0x00, 0x52, 0x33, 0xa8, 0x13, 0x66, - 0xae, 0xe7, 0x3c, 0xec, 0x85, 0x22, 0x8e, 0xbc, 0xfd, 0x5e, 0xe3, 0xc3, 0xfb, 0x44, - 0xdb, 0x76, 0xba, 0x24, 0x3f, 0x28, 0x42, 0xb7, 0xb5, 0xfc, 0x74, 0x6a, 0xe5, 0x1b, - 0x0b, 0xc4, 0xbd, 0x4f, 0xc9, 0xfd, 0x83, 0x35, 0x65, 0xea, 0x85, 0x2b, 0x92, 0xb2, - 0x24, 0xf6, 0x99, 0x03, 0x18, 0xad, 0x8c, 0x7d, 0x94, 0x37, 0xe2, 0x0e, 0x2a, 0x1f, - 0x20, 0xe8, 0x18, 0xf9, 0x05, 0x7c, 0x5a, 0xba, 0xaa, 0x2e, 0x5c, 0x15, 0xb9, 0x49, - 0x45, 0xcd, 0x42, 0x4c, 0x28, 0xa5, 0xfa, 0x38, 0x5d, 0xad, 0xfe, 0x49, 0x07, 0xb2, - 0x74, 0xd8, 0x42, 0x70, 0x7d, 0xb3, 0x69, 0x7a, 0x5a, 0xe6, 0xc8, 0xf5, 0x42, 0xe5, - 0xec, 0xc0, 0x7f, 0xe4, 0x73, 0x50, 0xd1, 0x01, 0x46, 0x70, 0x21, 0x2e, 0xfe, 0x81, - 0xfb, 0x7c, 0x73, 0xe8, 0x45, 0x0d, 0xf8, 0x14, 0xef, 0x62, 0x32, 0xf7, 0x49, 0x0f, - 0x63, 0xcc, 0xf0, 0x74, 0x80, 0xf8, 0x84, 0xa6, 0x6e, 0xaf, 0xfc, 0x28, 0xfe, 0xa4, - 0x48, 0xd7, 0xb4, 0x01, 0xcd, 0xae, 0x10, 0xe7, 0xc0, 0xc7, 0xf9, 0xa7, 0xb1, 0x53, - 0x31, 0x96, 0x9f, 0xc8, 0xcb, 0x36, 0x39, 0x67, 0x73, 0xde, 0x19, 0x19, 0x31, 0xc7, - 0x50, 0xf6, 0xce, 0x5c, 0xaa, 0xf2, 0x97, 0x68, 0xeb, 0xb2, 0x7d, 0xac, 0xc7, 0x38, - 0x05, 0x6a, 0x81, 0x25, 0xb4, 0x77, 0x2b, 0xf8, 0x7a, 0xe1, 0x0a, 0x8a, 0x30, 0x9b, - 0x9b, 0xd6, 0x55, 0x04, 0x3c, 0xfc, 0x31, 0x59, 0x49, 0x43, 0x68, 0xc5, 0xab, 0x8c, - 0xad, 0xb7, 0xf6, 0x71, 0xe9, 0x62, 0x6b, 0xd2, 0x63, 0xe3, 0x11, 0x81, 0xa6, 0x04, - 0xb5, 0x06, 0xa0, 0x3b, 0x43, 0x9a, 0x7f, 0xfe, 0x43, 0x55, 0x89, 0x24, 0x77, 0xe2, - 0xbd, 0xf3, 0x38, 0xc6, 0x2c, 0x39, 0x22, 0xf7, 0xd3, 0xc9, 0xa5, 0x6c, 0x71, 0x03, - 0xd9, 0x11, 0x94, 0x8a, 0x84, 0xb5, 0xae, 0x2d, 0xbb, 0x16, 0xa3, 0x76, 0x1a, 0xdd, - 0x05, 0x3a, 0x0f, 0x96, 0x7e, 0x6b, 0x5b, 0xc9, 0x42, 0x11, 0xb6, 0x54, 0x71, 0x53, - 0x26, 0x7c, 0x6e, 0xe1, 0xca, 0xd0, 0xd9, 0x74, 0xa7, 0x10, 0x88, 0x58, 0x37, 0x35, - 0xe4, 0xf6, 0x3d, 0x33, 0x15, 0x6d, 0xad, 0xd5, 0x4c, 0x2f, 0xaf, 0x89, 0x11, 0x4a, - 0x12, 0x7b, 0x97, 0xb9, 0x4c, 0xc2, 0xa2, 0x2e, 0xf3, 0x03, 0xf4, 0x59, 0xd0, 0x4f, - 0xc0, 0xb5, 0x3a, 0xce, 0x59, 0x18, 0xd4, 0x7f, 0xf3, 0x3a, 0x55, 0x8b, 0xd7, 0x1a, - 0x75, 0xf3, 0x55, 0xfb, 0xd0, 0x6b, 0xbc, 0xcf, 0x4e, 0x02, 0xc3, 0xc0, 0xa4, 0xb6, - 0x3d, 0x0c, 0xc9, 0x49, 0x80, 0x1d, 0x63, 0xa6, 0x4c, 0xb2, 0xd3, 0x23, 0x73, 0xb2, - 0xc7, 0xb2, 0x74, 0xab, 0x2d, 0xb4, 0x68, 0x21, 0x42, 0xc8, 0xb2, 0x1d, 0x84, 0xc4, - 0x81, 0xf5, 0xef, 0x21, 0xe4, 0xb5, 0xe3, 0x60, 0x34, 0x51, 0xbf, 0x94, 0x77, 0x4d, - 0x0e, 0xf4, 0x7f, 0x63, 0xfa, 0x6a, 0xbb, 0x78, 0xd2, 0x1c, 0x19, 0x3c, 0xbe, 0x65, - 0xb6, 0x95, 0xfe, 0x67, 0x42, 0x3c, 0x1e, 0x2d, 0x31, 0x2e, 0x27, 0x76, 0xfa, 0x24, - 0xec, 0xe8, 0x46, 0x83, 0xe7, 0x48, 0x76, 0xc5, 0x5e, 0xa0, 0x36, 0x9e, 0x4e, 0xa0, - 0xe8, 0x64, 0x94, 0xe0, 0x0d, 0xde, 0x23, 0x6a, 0x16, 0x89, 0x73, 0x1f, 0x0a, 0x5d, - 0x82, 0x03, 0xaf, 0xde, 0x5c, 0x42, 0x36, 0x40, 0xb8, 0x1e, 0x4f, 0x63, 0x1c, 0x98, - 0x1c, 0x11, 0xa2, 0xe1, 0xd1, 0x84, 0xc6, 0x7c, 0x52, 0x8d, 0xf9, 0x2d, 0x53, 0xae, - 0xc4, 0x4a, 0x40, 0xa4, 0xea, 0x2a, 0x13, 0x1b, 0x47, 0x33, 0xcf, 0xe4, 0x5c, 0x6b, - 0x00, 0x12, 0xc3, 0xe9, 0xe2, 0x09, 0x75, 0xba, 0xae, 0xcb, 0x02, 0x32, 0xdf, 0x88, - 0x0b, 0xd7, 0xd1, 0xde, 0x13, 0xe1, 0x34, 0x94, 0x62, 0xec, 0x8d, 0x5d, 0xf3, 0xe7, - 0x80, 0xff, 0xa7, 0x2e, 0xba, 0x8a, 0x8d, 0xf7, 0xfc, 0xf3, 0x98, 0xec, 0x23, 0x05, - 0x13, 0xca, 0x9d, 0x61, 0x23, 0xf8, 0xb9, 0xd8, 0x17, 0x85, 0x60, 0xda, 0xf9, 0x75, - 0x11, 0x19, 0x55, 0xa2, 0xbc, 0xa3, 0x42, 0x3e, 0xee, 0xfc, 0x52, 0x7b, 0xe3, 0xa8, - 0x54, 0x3e, 0xb9, 0x0a, 0x5e, 0xc0, 0x2f, 0x35, 0xa7, 0xc6, 0x4b, 0x7d, 0xd5, 0x9a, - 0x72, 0xda, 0x00, 0x74, 0x63, 0x4e, 0x01, 0xd2, 0xab, 0xf3, 0x63, 0x7a, 0xdd, 0x77, - 0xc7, 0x35, 0x0f, 0x12, 0xb0, 0x11, 0xb2, 0x94, 0x16, 0x8e, 0xc7, 0x55, 0x76, 0xe4, - 0x7d, 0x16, 0x9e, 0x39, 0x38, 0xbf, 0x6a, 0xe2, 0xaa, 0x8f, 0xf7, 0xcf, 0xba, 0x7c, - 0xac, 0xb1, 0xf9, 0x2b, 0x6e, 0x4c, 0x24, 0x97, 0xbf, 0xfa, 0x9f, 0x17, 0xca, 0xd2, - 0x42, 0xfa, 0x9c, 0x31, 0x79, 0xc1, 0xa3, 0xaa, 0x81, 0xf7, 0x36, 0x16, 0x49, 0x57, - 0x2c, 0x71, 0x5c, 0x25, 0xa1, 0xf6, 0xcd, 0x5a, 0xce, 0x82, 0xc0, 0x0a, 0xb2, 0x34, - 0x2b, 0x9c, 0x3c, 0xb4, 0xff, 0xfd, 0xda, 0x16, 0x0c, 0xa5, 0xab, 0x9e, 0x9b, 0xaf, - 0x21, 0x39, 0xef, 0x9a, 0xfb, 0xe1, 0xb1, 0xf3, 0x09, 0x46, 0x2a, 0xfc, 0xe4, 0x62, - 0xa7, 0x9b, 0xb9, 0x69, 0x8e, 0x22, 0xc9, 0x57, 0xc5, 0x90, 0xa7, 0x53, 0xa7, 0x6b, - 0x87, 0xe0, 0x09, 0x12, 0x1e, 0x06, 0xf6, 0xa1, 0xbf, 0x62, 0xa0, 0x8b, 0xf4, 0x35, - 0xd9, 0x2e, 0x2f, 0xff, 0xe8, 0x6e, 0x2a, 0x9c, 0xbb, 0xa9, 0x13, 0x3a, 0x68, 0xe4, - 0xae, 0xbf, 0x33, 0xc3, 0x84, 0x36, 0xf2, 0x54, 0x5f, 0xc2, 0xd5, 0x28, 0x32, 0xd1, - 0x65, 0xaf, 0x41, 0x5b, 0x24, 0x4a, 0xdc, 0x5f, 0x57, 0x37, 0x7d, 0xee, 0xdf, 0x46, - 0x0a, 0xa3, 0xbe, 0xb4, 0x34, 0x19, 0xc6, 0xb0, 0x82, 0xe8, 0x35, 0xce, 0x84, 0xca, - 0x13, 0xb6, 0x90, 0x8a, 0x88, 0x13, 0xc0, 0x21, 0xde, 0x9f, 0xa9, 0xa4, 0x4e, 0x4c, - 0x18, 0xdc, 0xb3, 0xd2, 0x1f, 0xaa, 0x8b, 0x86, 0xc8, 0x70, 0x28, 0xd0, 0xb5, 0x53, - 0x21, 0x07, 0xf9, 0xf6, 0xfd, 0x49, 0x00, 0x22, 0x7d, 0x0d, 0x8f, 0xf2, 0xbf, 0x9d, - 0x28, 0xcb, 0xcc, 0x99, 0x6c, 0x47, 0x3c, 0xe6, 0x16, 0x41, 0xf4, 0x88, 0x4e, 0x6e, - 0xd3, 0xfd, 0x5e, 0x4b, 0x7c, 0xb8, 0x35, 0xb8, 0x33, 0x08, 0x96, 0x4e, 0x3c, 0x46, - 0x87, 0x3f, 0xd6, 0x13, 0x31, 0x7b, 0x91, 0xd2, 0x92, 0x36, 0xea, 0x90, 0xe3, 0x65, - 0x32, 0xec, 0x5d, 0x6b, 0x42, 0x32, 0xe8, 0xbc, 0xcc, 0x36, 0x75, 0xb9, 0x8b, 0x35, - 0xf8, 0xde, 0x4d, 0x08, 0x88, 0x84, 0x14, 0x6f, 0x3d, 0xb8, 0x97, 0x0b, 0x38, 0xd1, - 0xe5, 0x01, 0xae, 0xe9, 0xc1, 0xf3, 0xfd, 0x78, 0x25, 0x49, 0xd3, 0xf3, 0x24, 0x57, - 0x59, 0x60, 0x6d, 0x9f, 0x92, 0xd5, 0x54, 0x8a, 0xcf, 0xea, 0xdb, 0xaf, 0x9c, 0xaa, - 0x6b, 0x93, 0xdc, 0x08, 0x82, 0x8d, 0x74, 0xf6, 0xd5, 0xfd, 0xd8, 0x33, 0x31, 0xf0, - 0x96, 0x91, 0x45, 0x95, 0x52, 0x97, 0xe6, 0x9f, 0x00, 0xfd, 0x29, 0x87, 0xf2, 0xda, - 0x2b, 0x94, 0xb9, 0x95, 0xfe, 0xcb, 0xe6, 0x22, 0xa7, 0x35, 0xef, 0x7f, 0x12, 0x07, - 0xf6, 0x71, 0x62, 0x94, 0x89, 0x20, 0x2b, 0xea, 0x0b, 0x47, 0x5e, 0x51, 0x68, 0x1a, - 0xa1, 0x67, 0x78, 0xb3, 0x9b, 0xd9, 0x23, 0xc9, 0x8d, 0xc6, 0xff, 0x83, 0x73, 0xc7, - 0x9b, 0xb1, 0x70, 0x30, 0x41, 0x7b, 0xc2, 0x00, 0xc8, 0xf0, 0xb8, 0x55, 0xac, 0xfe, - 0xc1, 0x79, 0xf7, 0x67, 0x4c, 0xec, 0x27, 0x21, 0xa1, 0x0f, 0xca, 0x69, 0x3d, 0x83, - 0xcf, 0xe5, 0xb8, 0xcd, 0xcc, 0x18, 0xf8, 0x1a, 0xd6, 0x17, 0xfa, 0x26, 0xf0, 0xdf, - 0xb8, 0x36, 0x55, 0xb8, 0xa2, 0x9a, 0x7f, 0x83, 0x42, 0x32, 0x42, 0x5e, 0x8c, 0x47, - 0x45, 0x88, 0xf1, 0x8d, 0xd3, 0x26, 0xaa, 0x39, 0x6c, 0x3e, 0x47, 0x75, 0xe0, 0x02, - 0x05, 0xfc, 0x9e, 0x45, 0xf7, 0xb7, 0xd2, 0xe6, 0xd5, 0x5d, 0xcb, 0x90, 0xe2, 0x3f, - 0xf6, 0xb5, 0x08, 0x45, 0x9a, 0xa6, 0x99, 0xbf, 0xcb, 0xd5, 0x6f, 0x10, 0x99, 0x77, - 0x64, 0xd0, 0x87, 0x40, 0x89, 0x86, 0xe7, 0x3d, 0x6e, 0x28, 0x4f, 0xea, 0x9a, 0x23, - 0xc3, 0x93, 0x11, 0x78, 0x2f, 0x86, 0xca, 0xbf, 0xf9, 0x45, 0x5e, 0x4c, 0xf6, 0x99, - 0xe5, 0xf5, 0xd4, 0xbc, 0x0b, 0x39, 0x05, 0xa4, 0xe3, 0xbd, 0x01, 0xc5, 0x4d, 0xf8, - 0x64, 0x34, 0x43, 0xbe, 0x0f, 0x88, 0x90, 0x32, 0xea, 0x32, 0x5b, 0xf0, 0x71, 0x07, - 0xfd, 0x41, 0xd6, 0x73, 0xee, 0xba, 0xe6, 0xfa, 0x63, 0x7b, 0x70, 0xcc, 0x0e, 0xd3, - 0xf0, 0x09, 0x58, 0xdf, 0xb8, 0xdc, 0xf0, 0x0e, 0x85, 0xa1, 0xd0, 0xa6, 0xa8, 0x90, - 0x81, 0x40, 0xc2, 0xf4, 0x34, 0xc2, 0xe2, 0x60, 0xef, 0xb0, 0xbc, 0xa2, 0x00, 0x35, - 0x04, 0xc9, 0x99, 0x93, 0xa9, 0xe1, 0xc0, 0xff, 0x9c, 0xef, 0xe6, 0xa6, 0x65, 0xd7, - 0x91, 0x42, 0x86, 0x90, 0xe4, 0x7e, 0xf8, 0xc1, 0x31, 0xa8, 0xe9, 0xbf, 0xb4, 0xc3, - 0x08, 0x02, 0x35, 0x03, 0x2d, 0x73, 0x1b, 0x0d, 0x38, 0x41, 0x22, 0x5f, 0x1c, 0x11, - 0xe2, 0xc2, 0x8e, 0xe8, 0x4d, 0x35, 0xf9, 0x22, 0x61, 0x00, 0x56, 0x59, 0x72, 0xeb, - 0x26, 0x9d, 0x27, 0x8e, 0xf6, 0x49, 0x79, 0xbf, 0x65, 0x15, 0xed, 0x4a, 0x68, 0x40, - 0xb0, 0x88, 0x3a, 0x9e, 0x6e, 0xf6, 0x4a, 0x0e, 0xfc, 0xae, 0x1c, 0xf2, 0x1d, 0xfe, - 0x74, 0x85, 0x4e, 0x84, 0xc2, 0x74, 0x9f, 0xac, 0x03, 0x82, 0x52, 0x75, 0xc9, 0xb6, - 0x30, 0x21, 0x84, 0xc7, 0x2d, 0xf4, 0xc4, 0xbb, 0x28, 0x62, 0xe4, 0xe8, 0xa7, 0xd9, - 0xa4, 0xa2, 0x82, 0x86, 0x6f, 0x9a, 0x7b, 0x2c, 0xfc, 0x9a, 0x56, 0x31, 0x3d, 0xa0, - 0xc4, 0x7a, 0x34, 0xb7, 0xb9, 0xcd, 0xa3, 0xac, 0xe8, 0x18, 0x5f, 0x07, 0xdf, 0x36, - 0xe4, 0x48, 0xa7, 0x6a, 0xa4, 0x77, 0xf2, 0x24, 0xd8, 0x7a, 0x07, 0x4f, 0x43, 0xaf, - 0x5d, 0x5f, 0x79, 0xb3, 0xab, 0x11, 0x28, 0xf0, 0x81, 0x91, 0x44, 0x7f, 0xa6, 0x46, - 0xbf, 0xdd, 0xe5, 0xb5, 0x1e, 0x23, 0x3c, 0xa6, 0x15, 0x5d, 0x10, 0x15, 0x85, 0xbc, - 0x2c, 0x40, 0x15, 0x8a, 0xc2, 0x10, 0x6e, 0x66, 0xa2, 0x6e, 0x46, 0x42, 0x33, 0x70, - 0x63, 0x68, 0x76, 0xb4, 0x34, 0xa7, 0x4f, 0x8c, 0xe8, 0x06, 0x00, 0x50, 0xb0, 0x82, - 0xa7, 0x9b, 0x61, 0xbb, 0x5d, 0x34, 0x4e, 0xb5, 0xa1, 0x15, 0x83, 0x26, 0xce, 0xd9, - 0xa9, 0xd9, 0xf5, 0x4f, 0xb2, 0xfe, 0x8f, 0x9f, 0x05, 0xcd, 0x11, 0x1e, 0xe4, 0x6c, - 0x47, 0x10, 0xf6, 0xf6, 0x3a, 0x62, 0x69, 0x45, 0x57, 0xef, 0x1b, 0x12, 0xc8, 0x80, - 0x06, 0xb6, 0x78, 0x72, 0x50, 0x5f, 0x4e, 0x88, 0x3b, 0x58, 0x59, 0x07, 0x92, 0x9a, - 0x2f, 0x3f, 0xdb, 0x0d, 0x8f, 0x79, 0x14, 0xc4, 0x2d, 0xde, 0x2d, 0x20, 0x00, 0xf5, - 0xae, 0x02, 0xd4, 0x18, 0x21, 0xc8, 0xe1, 0xee, 0x01, 0x38, 0xeb, 0xcb, 0x72, 0x8d, - 0x7c, 0x6c, 0x3c, 0x80, 0x02, 0x7e, 0x43, 0x75, 0x94, 0xc6, 0x70, 0xfd, 0x6f, 0x39, - 0x08, 0x22, 0x2e, 0xe7, 0xa1, 0xb9, 0x17, 0xf8, 0x27, 0x1a, 0xbe, 0x66, 0x0e, 0x39, - 0xe0, 0x51, 0xaa, 0xa6, 0xfc, 0xa1, 0x86, 0x22, 0x76, 0xe2, 0xba, 0xa0, 0xfe, 0x0b, - 0x16, 0x2a, 0xeb, 0xcf, 0xe3, 0xd9, 0x34, 0x9c, 0x8d, 0x15, 0x4b, 0xb7, 0xee, 0x28, - 0x21, 0x2c, 0x1b, 0xaa, 0x70, 0x5d, 0x82, 0x07, 0x0d, 0x70, 0x32, 0xf2, 0x69, 0x5d, - 0x17, 0x96, 0x80, 0x9f, 0xab, 0x41, 0x24, 0x69, 0x26, 0xaf, 0x99, 0x2b, 0x6e, 0xee, - 0x95, 0xa9, 0xa0, 0x6b, 0xc4, 0x56, 0x2c, 0x5f, 0x2f, 0x1b, 0x19, 0x54, 0x95, 0x00, - 0x37, 0x2e, 0x7a, 0xd5, 0x79, 0xa6, 0xd6, 0xd7, 0x8b, 0x33, 0x15, 0x31, 0x30, 0xfb, - 0x44, 0x8f, 0xb7, 0x9e, 0x8a, 0x66, 0x9d, 0xb8, 0xa0, 0xf3, 0x5c, 0xdf, 0x9a, 0xe5, - 0xd3, 0x2d, 0x73, 0x2f, 0xc7, 0x94, 0x18, 0xe2, 0x3b, 0x45, 0x1d, 0xdc, 0x95, 0xa2, - 0x2a, 0xba, 0xbb, 0x05, 0x6e, 0xc6, 0xb5, 0xe8, 0xba, 0x4f, 0x52, 0x4d, 0xfa, 0xfe, - 0x87, 0x52, 0x62, 0xdd, 0x7b, 0xe4, 0x1c, 0xbb, 0xc6, 0x24, 0x20, 0xd4, 0xad, 0x6d, - 0xf5, 0xc9, 0xb7, 0x13, 0x60, 0x4f, 0x65, 0x60, 0x88, 0xa4, 0x48, 0x5e, 0x93, 0xbe, - 0x19, 0x07, 0xd2, 0x7a, 0xc6, 0xec, 0x3c, 0x57, 0x25, 0x9b, 0xd6, 0x98, 0x1d, 0x42, - 0xc1, 0xb7, 0x8a, 0x29, 0xad, 0x96, 0x85, 0xe6, 0x3c, 0x49, 0x4d, 0x41, 0x29, 0x62, - 0x3e, 0xa1, 0xa7, 0xff, 0xec, 0x85, 0xfa, 0x29, 0x41, 0x10, 0x73, 0xed, 0xb2, 0x97, - 0x8e, 0xf4, 0xe4, 0x69, 0xdd, 0xd5, 0xcd, 0xa9, 0x86, 0x18, 0x99, 0x95, 0xf8, 0x8d, - 0x6a, 0xb3, 0x66, 0xdb, 0x01, 0x90, 0x01, 0xf5, 0xb2, 0x52, 0x88, 0xcf, 0x86, 0x0f, - 0xd9, 0x98, 0xee, 0x57, 0x3c, 0x8c, 0xc4, 0x8a, 0xa9, 0xef, 0xcf, 0x9b, 0x61, 0x7e, - 0x04, 0x3c, 0x99, 0x00, 0x8e, 0x35, 0x00, 0x96, 0xfd, 0xa4, 0xeb, 0x24, 0xc2, 0x0f, - 0x46, 0x90, 0xf1, 0xe2, 0xc5, 0xef, 0x86, 0x6c, 0x0e, 0xe5, 0xdd, 0xa1, 0x19, 0xee, - 0xea, 0xf1, 0x19, 0xdb, 0xdc, 0xae, 0x8d, 0xc7, 0x6c, 0x84, 0x6c, 0xc2, 0x27, 0x27, - 0x2b, 0xfc, 0x54, 0x17, 0xdc, 0x4c, 0xf4, 0xc0, 0x87, 0xba, 0x34, 0xec, 0xf3, 0xa5, - 0x5b, 0x00, 0x1f, 0xf3, 0x09, 0xa8, 0x1c, 0x05, 0x2d, 0x69, 0x26, 0xa9, 0xdd, 0xf0, - 0xf7, 0x8c, 0x5f, 0xc0, 0x64, 0xc6, 0xa6, 0x40, 0x16, 0x21, 0xb3, 0x8a, 0xa5, 0x49, - 0x44, 0x19, 0x81, 0x99, 0x21, 0x0d, 0x2b, 0x42, 0xe6, 0x1d, 0xde, 0x1d, 0x08, 0xaf, - 0x55, 0x07, 0x3b, 0xbf, 0x06, 0x15, 0xf6, 0x7b, 0x11, 0x00, 0xcc, 0x2e, 0xa3, 0xba, - 0x3d, 0x6c, 0x1a, 0x1a, 0x90, 0x87, 0xb1, 0x19, 0xba, 0xee, 0xbf, 0xa6, 0x2b, 0xc9, - 0xf0, 0xec, 0x47, 0x9d, 0x99, 0xc1, 0xa3, 0xb1, 0x58, 0xb5, 0x14, 0xd1, 0x62, 0x9d, - 0xb3, 0x99, 0x3f, 0x11, 0x67, 0x2a, 0x26, 0x70, 0x8e, 0x5a, 0xd8, 0x16, 0xb5, 0x47, - 0xab, 0x7e, 0x82, 0x7d, 0x07, 0x1b, 0xa7, 0x84, 0x2b, 0x3e, 0x90, 0x30, 0x53, 0x83, - 0x89, 0x6e, 0xc4, 0x90, 0x5f, 0x70, 0xc7, 0x8b, 0x69, 0x4e, 0x6a, 0x5a, 0x3e, 0x43, - 0x12, 0xcd, 0x82, 0x08, 0x13, 0x2b, 0x84, 0x0f, 0x05, 0xc7, 0x14, 0x52, 0x3c, 0xa8, - 0x19, 0x72, 0x0a, 0xe2, 0x27, 0xfd, 0x1a, 0xcb, 0xa7, 0x14, 0xfa, 0x4f, 0xc4, 0x5f, - 0xc5, 0x39, 0x88, 0x57, 0xb4, 0x0d, 0xc1, 0x48, 0x79, 0x85, 0x6f, 0x35, 0x4b, 0xa4, - 0xd2, 0x58, 0x1d, 0x0c, 0xda, 0x54, 0xb6, 0x38, 0xba, 0x9d, 0x76, 0xf9, 0xb5, 0x2d, - 0x17, 0xc8, 0xf8, 0x8e, 0xe6, 0x3f, 0x58, 0x45, 0xb5, 0xdc, 0xef, 0xa4, 0xc3, 0x47, - 0x9b, 0xce, 0x9a, 0xca, 0xd1, 0x8b, 0x4a, 0xea, 0xe0, 0x3c, 0x0e, 0xae, 0x22, 0x5d, - 0x42, 0x84, 0x8b, 0xde, 0xaa, 0x53, 0x6d, 0x7d, 0x8d, 0xd3, 0xbc, 0x97, 0x9f, 0x06, - 0x58, 0x66, 0x73, 0xbc, 0x6f, 0xf1, 0xc5, 0xd3, 0xb3, 0x20, 0xf3, 0x49, 0xa5, 0xb3, - 0xa8, 0xb3, 0x55, 0x59, 0x22, 0x96, 0xaa, 0xf6, 0x1c, 0x5b, 0x72, 0x52, 0xf7, 0x3e, - 0xc0, 0xa9, 0x46, 0x6a, 0x1b, 0x85, 0x76, 0x4f, 0xb0, 0x83, 0x1b, 0x4a, 0x1a, 0x36, - 0x89, 0x0e, 0x22, 0x4c, 0x01, 0xac, 0xfc, 0xe4, 0x8e, 0xe3, 0xed, 0x93, 0x87, 0x73, - 0x98, 0xe0, 0x72, 0x6d, 0x02, 0x93, 0x6d, 0x0d, 0x03, 0x2e, 0x18, 0xe3, 0x28, 0x8b, - 0x26, 0x70, 0xe1, 0x36, 0x2c, 0x32, 0xd6, 0xe4, 0x73, 0x3b, 0x9d, 0xd2, 0xd5, 0xf2, - 0x6e, 0x1f, 0xe3, 0x06, 0xf7, 0x3c, 0x00, 0x7f, 0xdd, 0xca, 0xe9, 0xd9, 0xc0, 0xaa, - 0xf1, 0x87, 0xd7, 0x42, 0x8b, 0x1e, 0x9d, 0x47, 0x9c, 0x18, 0x23, 0x7b, 0x98, 0x28, - 0xbc, 0xa8, 0xb9, 0x8c, 0x9d, 0x9b, 0xec, 0x7d, 0x82, 0x70, 0xb5, 0xd8, 0xee, 0xc3, - 0xcc, 0x4f, 0x43, 0xfa, 0x01, 0x88, 0x52, 0x1b, 0xc6, 0x1b, 0x21, 0xdd, 0x04, 0xe3, - 0x7a, 0x83, 0xec, 0xe6, 0x8c, 0xa7, 0xa2, 0xfa, 0x6c, 0x8f, 0x9e, 0x34, 0xa6, 0x29, - 0x03, 0x35, 0xaa, 0x1f, 0xbd, 0x83, 0xd5, 0x4a, 0xaf, 0x44, 0x1e, 0x31, 0x9e, 0xa4, - 0x7a, 0x86, 0x2a, 0xd0, 0x29, 0x3c, 0xed, 0xf5, 0xdd, 0x9e, 0xda, 0xde, 0xee, 0x33, - 0xcb, 0x52, 0x2c, 0xd0, 0x11, 0x8b, 0xbd, 0x81, 0x1a, 0xce, 0x9a, 0x23, 0xbd, 0xa3, - 0x9a, 0xba, 0x72, 0xf1, 0x56, 0x6f, 0xc1, 0x68, 0x84, 0x97, 0xd2, 0xa7, 0x92, 0x8c, - 0x36, 0x70, 0x15, 0x25, 0x67, 0x8b, 0xc9, 0x72, 0x14, 0xb3, 0x1b, 0x37, 0xba, 0xb4, - 0x6b, 0x88, 0xf2, 0x7f, 0x04, 0x48, 0xde, 0xcb, 0x31, 0x62, 0x2d, 0x0f, 0x0f, 0x87, - 0xa8, 0x55, 0xba, 0x54, 0x00, 0x03, 0x32, 0x03, 0x1f, 0x73, 0xab, 0xff, 0xd4, 0x65, - 0x91, 0xda, 0x0b, 0x88, 0x72, 0x35, 0x04, 0xed, 0xb2, 0x33, 0x72, 0x30, 0xda, 0xd2, - 0xac, 0xc0, 0xd8, 0xbb, 0x68, 0xbc, 0x83, 0x7a, 0x2f, 0xf9, 0x30, 0xbf, 0xf0, 0x6f, - 0xde, 0x74, 0xeb, 0x90, 0xaa, 0xe4, 0xf6, 0x0d, 0xbb, 0x6e, 0xb8, 0x27, 0xea, 0x99, - 0x88, 0x4a, 0xcd, 0x62, 0x85, 0xa9, 0x88, 0x92, 0x80, 0x2c, 0xf5, 0x9d, 0x5d, 0x60, - 0xd0, 0x16, 0x63, 0x38, 0x7b, 0x3e, 0xd2, 0x72, 0x3b, 0xd6, 0x48, 0x9e, 0x9c, 0x2c, - 0x10, 0x6d, 0x4a, 0xa2, 0xde, 0x23, 0xce, 0xd1, 0x6c, 0x72, 0x04, 0x29, 0xc7, 0x75, - 0x3a, 0x77, 0x38, 0xec, 0x7d, 0x9d, 0xb8, 0x62, 0x42, 0x29, 0xed, 0xd2, 0x17, 0xb8, - 0x0d, 0x74, 0x87, 0x5a, 0x14, 0xca, 0xe4, 0x86, 0x3f, 0x13, 0x9e, 0x9c, 0x0b, 0x13, - 0x1b, 0x2a, 0x4c, 0x28, 0x07, 0x1a, 0x38, 0xec, 0x61, 0xf6, 0x68, 0x01, 0xaa, 0x59, - 0x56, 0xfc, 0xb2, 0xa4, 0x6b, 0x95, 0x87, 0x66, 0x5b, 0x75, 0x71, 0xaa, 0x03, 0x48, - 0x1f, 0xd8, 0xd9, 0xd5, 0x69, 0x8f, 0x83, 0x6f, 0xc8, 0x63, 0x5e, 0x69, 0xe3, 0xbd, - 0xe4, 0x2f, 0x4a, 0xc0, 0x71, 0x32, 0x8b, 0x54, 0x09, 0xf6, 0xe4, 0x2d, 0x79, 0x0a, - 0xed, 0xd7, 0x3b, 0xc1, 0xa2, 0x35, 0x47, 0x23, 0xb3, 0xb8, 0x19, 0xd0, 0x63, 0x7a, - 0x6f, 0xa4, 0x66, 0x39, 0x46, 0xa3, 0x0a, 0xc5, 0xaf, 0xdd, 0x30, 0xce, 0x83, 0x0f, - 0x67, 0x91, 0xb4, 0x57, 0x52, 0x70, 0xa1, 0x72, 0x0f, 0x91, 0x86, 0x6e, 0x2b, 0x86, - 0xf4, 0x78, 0x88, 0x94, 0xc8, 0xda, 0x62, 0xd8, 0xb9, 0x1f, 0xaf, 0x52, 0x0e, 0x3b, - 0xed, 0xbc, 0x12, 0x06, 0xa5, 0xa5, 0xe6, 0xef, 0xd3, 0xdf, 0xde, 0x08, 0x43, 0xc3, - 0xb0, 0x67, 0x57, 0x64, 0x3f, 0xc0, 0x06, 0x00, 0x88, 0x38, 0xca, 0x47, 0x30, 0x87, - 0xf8, 0x97, 0x79, 0x18, 0xcc, 0x1b, 0x81, 0xc9, 0xe6, 0x8e, 0x3b, 0x88, 0x8f, 0xe6, - 0xf7, 0xc6, 0x30, 0xf1, 0xbc, 0x7a, 0xe1, 0x88, 0xf5, 0x12, 0x84, 0x20, 0x41, 0xca, - 0xda, 0x1e, 0x05, 0xf8, 0x66, 0xd2, 0x56, 0x2d, 0xbe, 0x09, 0xc4, 0xb4, 0x30, 0x68, - 0xf7, 0x54, 0xda, 0xd3, 0x4d, 0xf0, 0xfc, 0xfc, 0x18, 0x1f, 0x31, 0x80, 0x1a, 0x79, - 0x92, 0xd2, 0xf1, 0x6b, 0xe0, 0x21, 0x1b, 0x4a, 0x22, 0xf6, 0x2a, 0xab, 0x64, 0x70, - 0x1b, 0xf4, 0xa4, 0xe6, 0xd6, 0x66, 0xfc, 0x30, 0x4a, 0x5c, 0x79, 0xc6, 0x09, 0xac, - 0xc4, 0x3b, 0x00, 0xb4, 0x86, 0x48, 0x93, 0xd3, 0x7d, 0x50, 0x07, 0xf0, 0xc3, 0x29, - 0xa4, 0x75, 0x50, 0x52, 0x57, 0x75, 0x70, 0xdd, 0x38, 0xfa, 0xc0, 0x43, 0xcd, 0x91, - 0xc1, 0x2e, 0xe3, 0x4e, 0x9c, 0xfa, 0xe3, 0x92, 0xa7, 0x8b, 0xda, 0xbd, 0x4e, 0xe3, - 0x1d, 0xc0, 0xde, 0xb0, 0x2f, 0xe7, 0xb1, 0xd8, 0xb0, 0x17, 0x8a, 0xc9, 0x51, 0x31, - 0x05, 0xfc, 0xc7, 0xe3, 0x0b, 0xa8, 0xe0, 0x16, 0xaa, 0x36, 0xa6, 0xb5, 0xdf, 0x5e, - 0x5a, 0x19, 0x09, 0xf6, 0x3a, 0xba, 0x09, 0x5d, 0x98, 0x77, 0xa8, 0xf2, 0x6e, 0x40, - 0x3d, 0xc2, 0x54, 0x76, 0xad, 0xd8, 0x3d, 0xb1, 0xca, 0x15, 0x8f, 0x0b, 0x42, 0x2b, - 0x5f, 0xf4, 0xdb, 0x69, 0xb1, 0x24, 0x4b, 0xc0, 0x90, 0x2e, 0xd0, 0x30, 0x3f, 0xec, - 0x73, 0xa5, 0xbf, 0xfe, 0xc7, 0x3a, 0xc3, 0x4c, 0x1a, 0x73, 0x16, 0x0f, 0x2c, 0xea, - 0x1e, 0x05, 0x10, 0xf8, 0x4d, 0x2f, 0xe2, 0xf7, 0x3b, 0x6e, 0x92, 0x19, 0x07, 0xa1, - 0xb7, 0xb3, 0x75, 0x12, 0x13, 0x24, 0x30, 0x11, 0x76, 0xb0, 0x9b, 0xc0, 0x41, 0xe4, - 0x68, 0x42, 0x3e, 0x93, 0xd5, 0xdc, 0xa3, 0x3e, 0x67, 0x1a, 0x78, 0x6d, 0x23, 0x1f, - 0x16, 0x43, 0xea, 0x66, 0x43, 0x8b, 0xa7, 0x85, 0xb8, 0x1e, 0x6c, 0x2b, 0xc7, 0x3f, - 0xf0, 0x0d, 0x89, 0x3b, 0xc1, 0x28, 0x5e, 0xfc, 0xa8, 0x25, 0x99, 0xd1, 0x81, 0xf1, - 0x23, 0x51, 0xf9, 0x39, 0xa9, 0x4e, 0xa8, 0xb9, 0x75, 0xc0, 0x65, 0xa9, 0x1f, 0xf2, - 0x57, 0xca, 0xc7, 0xa9, 0x23, 0x85, 0xfc, 0x8f, 0xa9, 0x21, 0xb1, 0x06, 0xba, 0x86, - 0x60, 0xc6, 0x0a, 0xc8, 0xba, 0x5e, 0xce, 0x45, 0x60, 0x6f, 0x04, 0xf3, 0x6a, 0x3a, - 0x90, 0xbb, 0x38, 0x38, 0xc4, 0x2a, 0xbf, 0x62, 0xdd, 0x2d, 0x84, 0xba, 0xbe, 0xf3, - 0xe1, 0x88, 0xe9, 0x17, 0x1a, 0xff, 0x9b, 0xc1, 0x16, 0x66, 0x90, 0x09, 0xd8, 0x87, - 0x13, 0x0a, 0xc9, 0xf7, 0x39, 0x6a, 0x62, 0x7a, 0x84, 0x74, 0xc1, 0x81, 0x1b, 0x69, - 0x6f, 0x99, 0x55, 0x2b, 0x14, 0xc4, 0x84, 0xdf, 0xe4, 0x2c, 0x24, 0xd5, 0x7c, 0x3a, - 0x9c, 0x3f, 0xea, 0x13, 0x76, 0xcd, 0xcb, 0x63, 0x42, 0x1c, 0x31, 0x4a, 0x62, 0x2a, - 0x9a, 0xef, 0x0b, 0xc0, 0x57, 0xcb, 0x11, 0xbc, 0x5e, 0x30, 0x66, 0xe3, 0x3a, 0x3b, - 0x9b, 0x31, 0xdf, 0x25, 0x75, 0xcd, 0x51, 0x85, 0xa4, 0xf3, 0xfc, 0x4e, 0x4c, 0x3d, - 0x40, 0x2e, 0xd4, 0x20, 0x46, 0xf8, 0x1f, 0x97, 0x48, 0x16, 0xd2, 0x79, 0xb1, 0x51, - 0x3a, 0xb8, 0x1d, 0x3f, 0x0a, 0x3c, 0x7f, 0x7f, 0xcf, 0x2f, 0xbb, 0x4e, 0x26, 0x32, - 0x19, 0x93, 0xa5, 0x13, 0xad, 0x3d, 0x7f, 0x4a, 0xfe, 0x6c, 0x1b, 0xbd, 0xc6, 0x57, - 0x58, 0x50, 0x80, 0xbb, 0x5a, 0x0f, 0x25, 0x97, 0x3d, 0x63, 0xeb, 0x20, 0xad, 0xa0, - 0x16, 0x6b, 0xbd, 0x8a, 0x39, 0xff, 0x93, 0x24, 0x6f, 0x27, 0x89, 0x73, 0x2a, 0xd0, - 0x55, 0x87, 0xf8, 0xdb, 0x7b, 0xc8, 0x7c, 0x24, 0x2c, 0xfd, 0x36, 0xce, 0x68, 0x5a, - 0x4b, 0x65, 0x69, 0x86, 0xc3, 0x9f, 0xd7, 0xfc, 0xb2, 0x3c, 0x91, 0x91, 0x3e, 0x46, - 0x11, 0x19, 0x1e, 0xdc, 0xc8, 0x8b, 0x78, 0xf1, 0x45, 0xea, 0x29, 0xd2, 0x71, 0xb9, - 0x40, 0xc6, 0x99, 0x41, 0xe4, 0xc3, 0xfd, 0x2d, 0x71, 0xf3, 0xb1, 0x90, 0x69, 0x0e, - 0xe1, 0x6f, 0x5d, 0x14, 0xac, 0x22, 0x24, 0xe6, 0xfc, 0x89, 0x59, 0x76, 0x54, 0x52, - 0x7d, 0xab, 0xe7, 0x2e, 0x75, 0xd2, 0xd2, 0xa1, 0x3a, 0x9f, 0xba, 0xa6, 0x37, 0x8e, - 0x8a, 0x26, 0x43, 0x21, 0x08, 0x7a, 0x19, 0x00, 0xef, 0xe3, 0xca, 0xd1, 0x4a, 0x57, - 0x96, 0x86, 0xaa, 0x36, 0x36, 0xbd, 0x37, 0x5b, 0xd3, 0x13, 0x6b, 0xee, 0x0b, 0xda, - 0xab, 0xcf, 0xac, 0x88, 0x1b, 0xc7, 0x01, 0x81, 0x27, 0x21, 0xe6, 0xfb, 0x75, 0xaa, - 0x07, 0x2d, 0x2d, 0x18, 0x7e, 0x62, 0x25, 0x8d, 0x65, 0xa1, 0x92, 0x15, 0x7c, 0xdf, - 0x2e, 0xc3, 0x21, 0x40, 0x7f, 0x68, 0x2f, 0x5e, 0xec, 0x6a, 0x32, 0x97, 0xab, 0x20, - 0xb7, 0x06, 0x1c, 0x62, 0x24, 0x57, 0x16, 0xa4, 0x4f, 0x71, 0xfb, 0xfc, 0x34, 0xc7, - 0x9b, 0x44, 0xe0, 0x9e, 0x42, 0x12, 0xac, 0x26, 0x53, 0xf6, 0xc4, 0x03, 0x64, 0x3e, - 0x1c, 0x5b, 0x9a, 0xd1, 0x34, 0xd8, 0x9c, 0x68, 0x0b, 0x70, 0x72, 0x83, 0xaf, 0x54, - 0x32, 0x6f, 0xc4, 0xf8, 0x4d, 0x6a, 0x58, 0x29, 0xa0, 0xad, 0x48, 0x30, 0x80, 0x6c, - 0x05, 0x75, 0x84, 0x92, 0xcd, 0x6a, 0xc4, 0x6b, 0xa0, 0x1a, 0x2b, 0x37, 0x22, 0xb5, - 0xe4, 0xcd, 0xaf, 0xbb, 0x3f, 0x36, 0x78, 0x5f, 0x42, 0x4a, 0xf0, 0x44, 0xda, 0xc5, - 0xdb, 0x5f, 0x7d, 0xf8, 0x39, 0xeb, 0x63, 0xc0, 0xc1, 0x7d, 0x8b, 0x0c, 0x79, 0xdb, - 0x86, 0x30, 0x94, 0x20, 0x15, 0xbe, 0x13, 0xf7, 0x9a, 0xf6, 0xf4, 0x3e, 0x5a, 0xb0, - 0x77, 0x81, 0x14, 0x79, 0x8f, 0x44, 0x22, 0x58, 0xee, 0xdc, 0x43, 0x6f, 0xcc, 0x38, - 0x6b, 0x36, 0xb5, 0x7e, 0x19, 0x17, 0xd7, 0x20, 0x17, 0x73, 0x66, 0xf4, 0x24, 0xb0, - 0xa5, 0x4b, 0x0b, 0x60, 0xf4, 0xfb, 0x13, 0x58, 0xc2, 0x0a, 0xa4, 0x1d, 0xc5, 0x02, - 0xe1, 0xdd, 0x8a, 0x16, 0x33, 0xf3, 0xd8, 0xe3, 0x27, 0x6b, 0x59, 0xe7, 0xd2, 0xc4, - 0xe6, 0x24, 0xa6, 0xf5, 0x36, 0x95, 0xbc, 0xaf, 0x24, 0x7e, 0x36, 0x48, 0x3f, 0x13, - 0xb2, 0x04, 0x42, 0x22, 0x37, 0xfc, 0x6a, 0xb3, 0xeb, 0xa0, 0x2f, 0xc4, 0x14, 0x2b, - 0x42, 0x97, 0xeb, 0xb5, 0x68, 0x3d, 0xb8, 0xd2, 0x43, 0x19, 0x70, 0x6a, 0xd2, 0x6a, - 0xaf, 0xd8, 0x1c, 0x53, 0xb7, 0x40, 0xf3, 0x45, 0x43, 0xa6, 0xb3, 0xe9, 0xf5, 0xbb, - 0x7d, 0x5c, 0x49, 0xe8, 0xc3, 0x7f, 0x61, 0x49, 0x21, 0x25, 0x4f, 0x32, 0x12, 0x39, - 0x4c, 0x79, 0x7d, 0x1c, 0xee, 0x78, 0x99, 0xb7, 0xb4, 0xb6, 0x5b, 0x59, 0xb7, 0x34, - 0x2f, 0x92, 0x53, 0x1c, 0x1d, 0x59, 0xe1, 0x79, 0x70, 0xb7, 0x31, 0x74, 0x14, 0x43, - 0x8c, 0xd8, 0x0b, 0xd0, 0xf9, 0xa6, 0x7c, 0x9b, 0x9e, 0x55, 0x2f, 0x01, 0x3c, 0x11, - 0x5a, 0x95, 0x4f, 0x35, 0xe0, 0x61, 0x6c, 0x68, 0xd4, 0x31, 0x63, 0xd3, 0x34, 0xda, - 0xc3, 0x82, 0x70, 0x33, 0xe5, 0xad, 0x84, 0x88, 0xbf, 0xd9, 0xc4, 0xbb, 0xbe, 0x8f, - 0x59, 0x35, 0xc6, 0xc5, 0xea, 0x04, 0xc3, 0xad, 0x49, 0xc7, 0x47, 0xa9, 0xe7, 0x23, - 0x1b, 0xcd, 0x7d, 0x16, 0x21, 0x5e, 0x6e, 0x80, 0x73, 0x7d, 0x6b, 0x54, 0xfe, 0xc8, - 0xb8, 0x84, 0x02, 0xf0, 0x47, 0x52, 0x45, 0xe1, 0x74, 0xa7, 0x45, 0xb8, 0x31, 0xf8, - 0xfe, 0x03, 0xa7, 0x6f, 0xb9, 0xce, 0xca, 0x4d, 0x22, 0xb7, 0x83, 0xc3, 0x28, 0xc6, - 0x91, 0x5c, 0x43, 0x40, 0x50, 0x64, 0xae, 0x56, 0xbc, 0x89, 0xe6, 0x4d, 0x15, 0x78, - 0xe4, 0xd3, 0xa3, 0x4b, 0xb9, 0x55, 0x91, 0xea, 0xf1, 0xd3, 0xda, 0x02, 0xa4, 0x54, - 0x9f, 0xa8, 0x0d, 0xb0, 0xff, 0x7c, 0xb0, 0x39, 0x93, 0xb6, 0x8a, 0xe1, 0x5a, 0x30, - 0xe8, 0x79, 0x49, 0xaa, 0x08, 0x0e, 0x94, 0xab, 0xde, 0x68, 0x89, 0x8c, 0x33, 0x92, - 0xa2, 0x17, 0xd6, 0x49, 0x61, 0x6b, 0xbe, 0x73, 0x9b, 0x13, 0xd1, 0x4d, 0xf0, 0x3f, - 0xf2, 0x76, 0x71, 0x48, 0x9b, 0xe0, 0xb4, 0xbe, 0xba, 0xaf, 0xa7, 0xd1, 0xe6, 0x39, - 0xd5, 0xb3, 0xe9, 0x94, 0xff, 0xb6, 0xb7, 0xa2, 0x09, 0xf6, 0xad, 0xfe, 0x8d, 0x1e, - 0x5c, 0xcf, 0x01, 0x0c, 0x19, 0x16, 0x8a, 0xeb, 0x00, 0xaa, 0x9d, 0x68, 0x7e, 0x24, - 0xad, 0xc0, 0xb1, 0x13, 0x5c, 0x70, 0xc9, 0x70, 0xe0, 0x90, 0x3a, 0xf6, 0xe1, 0x70, - 0x81, 0xd5, 0x81, 0x8e, 0x88, 0xb1, 0x4e, 0x4f, 0x60, 0x1b, 0x8c, 0x06, 0x3e, 0x3f, - 0x43, 0x87, 0xff, 0xa2, 0x32, 0x2a, 0x51, 0x81, 0x90, 0x9f, 0x09, 0x80, 0xd6, 0x89, - 0xde, 0x7f, 0x8e, 0x6a, 0x5c, 0x62, 0xa7, 0x77, 0xd1, 0x75, 0x00, 0x2a, 0x13, 0x7d, - 0xe8, 0x5b, 0x88, - ], - script_code: vec![], - transparent_input: None, - hash_type: 1, - amount: 1039204199089370, - consensus_branch_id: 1991772603, - sighash: [ - 0x6c, 0x4e, 0x32, 0x44, 0xc2, 0xd2, 0xbf, 0xb8, 0xd6, 0xf6, 0x69, 0x97, 0x77, 0xa1, - 0x1a, 0x64, 0xad, 0xfe, 0xe4, 0x9b, 0x2f, 0xc7, 0x81, 0xe6, 0x95, 0x15, 0x34, 0xf9, - 0x73, 0x44, 0x0d, 0xdb, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0xdc, 0xf7, 0x58, 0x76, 0xdc, - 0xa6, 0x09, 0xf9, 0xd2, 0x84, 0x71, 0xf9, 0x97, 0xfa, 0x11, 0xf9, 0x9d, 0x42, 0x3f, - 0x9c, 0xf1, 0x73, 0x4b, 0xe8, 0xa5, 0xff, 0x99, 0x7d, 0x45, 0x1e, 0xb3, 0xcf, 0x4b, - 0x3d, 0xfd, 0xd9, 0x06, 0xac, 0xac, 0x63, 0x52, 0x63, 0x6a, 0xdc, 0x17, 0xa8, 0x36, - 0xb1, 0x2b, 0x43, 0xbe, 0xfc, 0x0b, 0xe0, 0xa1, 0xbd, 0x36, 0x97, 0x72, 0x33, 0x80, - 0x78, 0xb4, 0xff, 0x7d, 0x8e, 0x2d, 0x97, 0x9a, 0x34, 0x41, 0xe1, 0xc8, 0xf5, 0xaf, - 0xe4, 0x7b, 0x1e, 0x7d, 0xa5, 0x6c, 0xf0, 0x06, 0x02, 0x00, 0x53, 0x11, 0x0c, 0x05, - 0xcf, 0x00, 0xfd, 0xa3, 0xe6, 0xcc, 0xe3, 0x60, 0x69, 0x04, 0x1f, 0xaf, 0xfd, 0x2f, - 0x77, 0xff, 0x06, 0x00, 0x02, 0xef, 0x12, 0xc3, 0x67, 0xf2, 0x1d, 0xea, 0x65, 0xc6, - 0xea, 0xaf, 0xb8, 0xaf, 0x58, 0x42, 0x8f, 0x6c, 0x54, 0x8e, 0x50, 0x17, 0x0f, 0x9e, - 0x6f, 0xcd, 0xdf, 0xe7, 0x51, 0xe0, 0xb6, 0x80, 0x12, 0xcb, 0x59, 0xdd, 0x46, 0x27, - 0xef, 0xc3, 0xea, 0x75, 0xdc, 0xd1, 0x5c, 0x8e, 0x0c, 0x3b, 0x8d, 0x8d, 0x7d, 0x6b, - 0x23, 0x31, 0xc8, 0xe4, 0x80, 0x16, 0x6b, 0x5a, 0xa7, 0x48, 0x5c, 0x9f, 0x0f, 0x83, - 0xe1, 0x9b, 0xc3, 0x0e, 0x64, 0x03, 0x82, 0x8c, 0xdb, 0x65, 0x2a, 0x55, 0x6b, 0x12, - 0x04, 0x09, 0x31, 0x40, 0x2a, 0xa6, 0xac, 0x34, 0xfc, 0x19, 0xfd, 0xc0, 0x6e, 0x2e, - 0x77, 0x87, 0xf5, 0x58, 0xd1, 0x42, 0xd9, 0x06, 0xea, 0xdb, 0x75, 0x90, 0xc9, 0x41, - 0x36, 0xda, 0x6a, 0x06, 0x35, 0x14, 0xd6, 0xa2, 0x5f, 0x7b, 0x37, 0xd7, 0x66, 0x4f, - 0x9b, 0x97, 0x09, 0x43, 0x3e, 0x6e, 0x70, 0x21, 0x18, 0xa4, 0xab, 0x9e, 0x7a, 0x7a, - 0x3e, 0x62, 0x59, 0x12, 0x99, 0x37, 0xd2, 0x9d, 0x0d, 0xb2, 0x60, 0x70, 0x52, 0x3e, - 0x8b, 0x06, 0x43, 0x13, 0x0a, 0xbe, 0xfe, 0x94, 0x3b, 0x40, 0x12, 0x98, 0xae, 0x01, - 0xa3, 0xab, 0x00, 0xab, 0xbc, 0x60, 0xd7, 0xdb, 0x93, 0x3c, 0x7f, 0x07, 0xa8, 0xbf, - 0x0f, 0x7c, 0xe1, 0x66, 0x0b, 0xcc, 0xb4, 0x5e, 0x04, 0x2b, 0x45, 0x1b, 0x93, 0x50, - 0x02, 0xce, 0xce, 0x27, 0xf3, 0x6a, 0xba, 0x56, 0x47, 0xac, 0x28, 0xd8, 0x18, 0x6c, - 0xdd, 0x1f, 0xb9, 0x5d, 0xc1, 0x35, 0xd4, 0x89, 0x92, 0xf6, 0x8d, 0xa1, 0x2a, 0xd6, - 0x1a, 0xc7, 0x56, 0x68, 0x0d, 0xd7, 0xf8, 0xd0, 0x77, 0x4a, 0xbd, 0x6c, 0xfd, 0xa2, - 0xf0, 0x32, 0xaf, 0x3b, 0xe1, 0x39, 0xa6, 0x33, 0xd6, 0x73, 0x3c, 0x75, 0xd1, 0xab, - 0xa8, 0x90, 0x18, 0xc8, 0x57, 0x2b, 0x99, 0xcd, 0x30, 0xc5, 0x37, 0x06, 0x79, 0x41, - 0xdf, 0x1c, 0x4b, 0xc1, 0xfd, 0x57, 0x0f, 0x7b, 0x4d, 0xdc, 0x97, 0x51, 0x86, 0x23, - 0xe3, 0xae, 0x4a, 0x87, 0xbd, 0xb9, 0x66, 0xc9, 0x4d, 0x86, 0x1e, 0x80, 0xde, 0x88, - 0xc2, 0x92, 0xae, 0xe9, 0x38, 0x71, 0x94, 0xe2, 0x56, 0xc6, 0x70, 0x07, 0x52, 0x30, - 0x1c, 0x73, 0xfc, 0x95, 0x65, 0xa4, 0x04, 0x80, 0xd8, 0x12, 0x6e, 0x9d, 0x08, 0x58, - 0x79, 0xe2, 0x4b, 0x16, 0xe9, 0xc4, 0x85, 0xd8, 0xf0, 0xd6, 0x18, 0xca, 0x0d, 0xd1, - 0x21, 0xb5, 0x1a, 0x7c, 0xab, 0x23, 0x0c, 0x5b, 0x45, 0x67, 0x2b, 0xdb, 0x8e, 0xa3, - 0xa0, 0x40, 0xf7, 0xaa, 0xa0, 0x98, 0xba, 0x26, 0x02, 0x5d, 0x2e, 0xab, 0x79, 0x48, - 0x69, 0x3d, 0xd5, 0xf6, 0xd3, 0x09, 0x65, 0x01, 0xe9, 0xe0, 0x71, 0x25, 0xd7, 0xeb, - 0x29, 0x3b, 0x3a, 0xba, 0xd5, 0x7f, 0xd5, 0xf0, 0x11, 0x64, 0x70, 0x02, 0xd6, 0x26, - 0xae, 0x88, 0xdc, 0x61, 0xe6, 0x47, 0xff, 0x46, 0x8d, 0xfa, 0x7a, 0x03, 0x07, 0x72, - 0x78, 0x79, 0x32, 0x75, 0xf1, 0x95, 0xa9, 0x75, 0x30, 0x28, 0x91, 0x78, 0x51, 0x61, - 0x80, 0xc5, 0xff, 0x99, 0x93, 0x53, 0x6b, 0xda, 0x15, 0x04, 0xba, 0x8b, 0xb4, 0x89, - 0x19, 0x88, 0xc1, 0x33, 0x4f, 0x31, 0xfb, 0x27, 0x6a, 0x03, 0x8a, 0xa8, 0xe9, 0x67, - 0xcb, 0x62, 0xa4, 0x92, 0x1b, 0xeb, 0x22, 0xb2, 0x08, 0xb0, 0x64, 0x58, 0x18, 0x47, - 0xb2, 0xf6, 0x4c, 0xa6, 0x48, 0x37, 0x00, 0x72, 0x16, 0xde, 0x6e, 0xca, 0xff, 0xeb, - 0x4b, 0x69, 0xe6, 0x33, 0x47, 0xf8, 0x4a, 0xbc, 0xad, 0x8f, 0x2e, 0x75, 0x7d, 0x58, - 0x61, 0xce, 0x77, 0xee, 0x46, 0x51, 0x3d, 0xa7, 0x41, 0x68, 0x37, 0xdc, 0xb2, 0x3d, - 0x33, 0xea, 0x72, 0xaf, 0x23, 0xd0, 0xad, 0x8c, 0x93, 0x07, 0xd0, 0xb5, 0x85, 0x8d, - 0xa9, 0x5b, 0x77, 0xff, 0xf9, 0x02, 0x7b, 0x88, 0x59, 0xe1, 0x1d, 0xcb, 0xd5, 0x98, - 0x35, 0x0e, 0xee, 0x50, 0x93, 0x94, 0x81, 0x70, 0x8e, 0xa7, 0x08, 0xeb, 0x9f, 0x66, - 0x43, 0x88, 0xb9, 0xc6, 0x4d, 0x6a, 0xf0, 0xf9, 0x66, 0x90, 0x34, 0x24, 0x00, 0x34, - 0x8e, 0x92, 0x9e, 0x07, 0x46, 0x02, 0x53, 0xf3, 0x83, 0x90, 0xf8, 0x7b, 0xd6, 0xc0, - 0x53, 0x08, 0xc3, 0xbd, 0xe2, 0x52, 0x28, 0xe0, 0xfa, 0x08, 0x80, 0xb0, 0x8e, 0xf3, - 0x4a, 0x5a, 0x9c, 0xc0, 0xea, 0x0a, 0x67, 0xca, 0x65, 0xb6, 0xff, 0xd0, 0x05, 0x57, - 0x29, 0x09, 0xf1, 0xc4, 0x2d, 0xd7, 0x45, 0xee, 0xee, 0x9d, 0xd6, 0xb4, 0x43, 0x9c, - 0x9f, 0x3f, 0x98, 0xa1, 0x18, 0xfe, 0x16, 0x69, 0x8e, 0x9c, 0xef, 0xf5, 0x58, 0xf1, - 0x60, 0x66, 0x97, 0x5f, 0xe3, 0x95, 0x83, 0xe9, 0xb5, 0x85, 0x3b, 0x13, 0x11, 0x39, - 0x15, 0x80, 0x01, 0x9f, 0xe5, 0x5d, 0x59, 0xd1, 0xc8, 0x28, 0xd3, 0xfe, 0xb6, 0xa3, - 0xb9, 0xce, 0x92, 0xd0, 0x89, 0xae, 0x4b, 0x40, 0x8e, 0x23, 0xd6, 0xa4, 0x37, 0xd4, - 0x98, 0x9b, 0x51, 0x9b, 0x7a, 0x9e, 0xb0, 0x8a, 0xe6, 0xd4, 0x48, 0xa7, 0xa1, 0x6e, - 0x8a, 0xed, 0x26, 0xa2, 0xec, 0xd0, 0xca, 0xd8, 0x08, 0x44, 0xfd, 0x06, 0x50, 0xd8, - 0xc4, 0xe4, 0xd2, 0xaf, 0x90, 0x65, 0x67, 0x48, 0xd8, 0x09, 0x9a, 0x0c, 0x75, 0x6f, - 0xc1, 0x6c, 0xca, 0x06, 0xa3, 0x34, 0x43, 0x07, 0x02, 0xae, 0x19, 0x61, 0x66, 0x5b, - 0x48, 0x45, 0xac, 0xd1, 0xa8, 0xe3, 0x41, 0x01, 0xe6, 0x8b, 0xb6, 0x44, 0xac, 0x03, - 0x4d, 0xc6, 0x3e, 0x6e, 0x34, 0x4c, 0x3d, 0x63, 0x76, 0x2a, 0x7a, 0x5b, 0xf5, 0x9f, - 0x13, 0x09, 0x54, 0x10, 0x98, 0x1d, 0x6b, 0x6b, 0x16, 0xbc, 0xd4, 0xc9, 0xfa, 0x68, - 0xaf, 0x6e, 0x53, 0x01, 0xef, 0x19, 0xbf, 0x3a, 0x43, 0x2e, 0x40, 0x6f, 0x85, 0x67, - 0xeb, 0xd9, 0x77, 0x2e, 0x92, 0xb5, 0xca, 0x5a, 0x59, 0x96, 0x71, 0xcb, 0xfd, 0x7d, - 0xdf, 0xa3, 0x63, 0xa5, 0x36, 0xb7, 0xac, 0x45, 0xf5, 0x7c, 0xc3, 0x7d, 0x09, 0x89, - 0x6f, 0xa9, 0x06, 0x97, 0x2e, 0x55, 0x71, 0x80, 0xa4, 0xab, 0x5a, 0xd0, 0x9d, 0x88, - 0x46, 0xdd, 0x6d, 0xa7, 0x48, 0x76, 0x54, 0x36, 0xe0, 0x16, 0x02, 0x40, 0xbd, 0x5c, - 0x92, 0x16, 0x66, 0xa1, 0xee, 0xaa, 0xce, 0x04, 0xa7, 0x1b, 0x50, 0x3a, 0x1c, 0xad, - 0xf8, 0x0b, 0x39, 0x24, 0x26, 0x6c, 0x59, 0x50, 0x4f, 0x8f, 0x21, 0x5f, 0x61, 0x8b, - 0x05, 0xd5, 0x45, 0x43, 0xb6, 0xe2, 0x6d, 0x82, 0x59, 0x6f, 0xc5, 0x3b, 0x52, 0x31, - 0x2c, 0x77, 0x6d, 0x12, 0xeb, 0x2b, 0x65, 0x9b, 0x4f, 0xb0, 0x98, 0xdf, 0x87, 0xd6, - 0x83, 0xcf, 0x9e, 0x54, 0x12, 0xee, 0x56, 0xc3, 0xfe, 0x98, 0x41, 0xd7, 0x3f, 0xd0, - 0x70, 0xdf, 0xa5, 0x1f, 0x5b, 0xaf, 0xed, 0xf2, 0x06, 0xf1, 0x3c, 0x52, 0x4e, 0x5c, - 0x50, 0xca, 0xc9, 0x90, 0x6e, 0xfa, 0x39, 0x32, 0x90, 0x04, 0x2e, 0x3b, 0xc5, 0x9f, - 0x96, 0x0b, 0x7d, 0x24, 0x0a, 0xe4, 0x43, 0xfc, 0x49, 0x26, 0x9c, 0xe0, 0x00, 0x61, - 0xe6, 0x5c, 0x6d, 0x74, 0x81, 0x2a, 0x30, 0xdd, 0x5f, 0x5f, 0xe7, 0x4e, 0xff, 0x61, - 0xe0, 0xcb, 0xab, 0x3c, 0xec, 0x75, 0xd0, 0xae, 0xf9, 0x50, 0x83, 0x18, 0x94, 0x52, - 0xdd, 0x3d, 0x9e, 0xdf, 0x44, 0x87, 0xbc, 0x73, 0x4c, 0x8b, 0x24, 0xf2, 0x12, 0x96, - 0xe4, 0xe9, 0xef, 0x11, 0x7d, 0x7f, 0xb9, 0x77, 0xe3, 0xb0, 0xe6, 0x40, 0x6e, 0x63, - 0x08, 0x59, 0x06, 0x33, 0x1a, 0x93, 0x03, 0x3d, 0x1c, 0xb8, 0x36, 0x0f, 0xe6, 0xfe, - 0xa6, 0x1a, 0x68, 0x26, 0xdf, 0x36, 0x25, 0x57, 0x89, 0xf9, 0x2e, 0x40, 0xba, 0xfc, - 0xb2, 0xeb, 0xcb, 0x9e, 0x55, 0x6f, 0x6c, 0x0c, 0xca, 0xdc, 0x6a, 0xf0, 0x8e, 0x31, - 0xec, 0x4a, 0xd5, 0x28, 0x80, 0x34, 0xe1, 0x6d, 0x15, 0x5c, 0xfd, 0xca, 0xda, 0x7b, - 0xab, 0x59, 0x9c, 0x2f, 0xa4, 0xad, 0x2e, 0x62, 0x93, 0xf9, 0xfe, 0x09, 0x71, 0x69, - 0x14, 0x82, 0x76, 0xb6, 0xa9, 0xea, 0xa7, 0x2f, 0x14, 0x8b, 0x0c, 0x95, 0x65, 0xc3, - 0xc2, 0xdd, 0x63, 0x12, 0x5e, 0x0f, 0xa5, 0x30, 0x86, 0x1a, 0x71, 0x0d, 0xf8, 0xe4, - 0x81, 0xf2, 0x71, 0x29, 0x20, 0xf8, 0x78, 0x7e, 0x0a, 0xed, 0xfe, 0x61, 0x8a, 0xff, - 0x50, 0xa3, 0xb5, 0x62, 0x13, 0x88, 0x4d, 0x62, 0x62, 0xc1, 0x1d, 0xeb, 0xf2, 0xba, - 0x7e, 0x8a, 0xd6, 0x69, 0x2c, 0xb1, 0x70, 0x78, 0x33, 0x14, 0x18, 0xda, 0x4b, 0xe0, - 0x64, 0xff, 0x52, 0x70, 0x07, 0x39, 0x34, 0xab, 0xcd, 0x2a, 0xb0, 0x46, 0x9e, 0xca, - 0xf7, 0x27, 0x5b, 0x4b, 0xd7, 0x2b, 0xc6, 0xed, 0x34, 0x47, 0x8e, 0xa4, 0x08, 0x9b, - 0x73, 0x6a, 0x16, 0xdd, 0x90, 0x6d, 0x49, 0xf2, 0x5c, 0x33, 0x82, 0x7c, 0x57, 0x1c, - 0xe0, 0xb5, 0xd7, 0x21, 0x77, 0xaa, 0x35, 0x08, 0x80, 0x4b, 0xc0, 0xf8, 0xfa, 0xa9, - 0x47, 0x12, 0x22, 0x31, 0x40, 0x2d, 0x2f, 0x5c, 0xc9, 0xa0, 0xeb, 0x0e, 0x09, 0xd4, - 0x27, 0xb4, 0x27, 0x28, 0x8d, 0x93, 0x7d, 0x9d, 0x72, 0xb7, 0x74, 0x56, 0xf8, 0x86, - 0x59, 0x4c, 0xd8, 0xc6, 0xa4, 0x62, 0xf7, 0x7f, 0xd8, 0x30, 0x76, 0x46, 0x9c, 0xc0, - 0xec, 0xba, 0x3c, 0xc4, 0x0c, 0xad, 0x69, 0xe5, 0xb5, 0x41, 0x12, 0xea, 0xb3, 0x33, - 0x96, 0xae, 0xcf, 0xbc, 0x21, 0x1f, 0x1f, 0x79, 0xcf, 0x33, 0x10, 0x8e, 0x93, 0xd9, - 0x53, 0x78, 0xba, 0xe6, 0x95, 0x82, 0x74, 0xb3, 0x10, 0x88, 0xfb, 0xd8, 0xb3, 0xa3, - 0xa0, 0xd1, 0x54, 0xa7, 0x89, 0x73, 0x5b, 0x03, 0x49, 0xc4, 0xd5, 0x1c, 0x88, 0x9d, - 0x08, 0x95, 0x2d, 0xdd, 0x54, 0x88, 0xbe, 0x95, 0x56, 0x05, 0x94, 0xe6, 0x73, 0xfa, - 0x05, 0x1b, 0xf9, 0xb6, 0x14, 0xa1, 0x5e, 0x10, 0x0b, 0x60, 0xa0, 0xfe, 0x9a, 0x7e, - 0x12, 0xa9, 0xb2, 0x56, 0xdf, 0x58, 0x9b, 0x3e, 0x48, 0xe5, 0xb8, 0x0f, 0xb8, 0xcf, - 0xf0, 0x3e, 0x86, 0xf6, 0x0c, 0xc0, 0x70, 0xfb, 0x23, 0xc9, 0x7d, 0x4c, 0x14, 0xfa, - 0x3a, 0x73, 0x46, 0xff, 0x55, 0x6b, 0xc6, 0x85, 0x5a, 0x5f, 0x83, 0xe3, 0xdc, 0xd9, - 0xf6, 0xea, 0xb3, 0xda, 0xbc, 0xd4, 0x77, 0x50, 0xe3, 0x4e, 0x7c, 0x09, 0x38, 0xf6, - 0x4d, 0x45, 0x1e, 0x39, 0x50, 0x9e, 0x90, 0x27, 0x47, 0xa7, 0x07, 0x55, 0x12, 0x20, - 0x95, 0x08, 0x2a, 0xb7, 0x98, 0x59, 0x19, 0x07, 0x31, 0x41, 0xb6, 0xd3, 0x70, 0x20, - 0x91, 0xab, 0x71, 0x72, 0x80, 0xbd, 0xc5, 0x5e, 0x79, 0x9c, 0x01, 0xad, 0x86, 0x41, - 0x90, 0x4e, 0x3b, 0x1d, 0xd2, 0x9e, 0x1a, 0x96, 0x4c, 0x73, 0x7d, 0x3c, 0x15, 0x5a, - 0xfb, 0x30, 0x7b, 0x74, 0x8e, 0x41, 0x12, 0xb4, 0x8b, 0x77, 0xd5, 0xed, 0x57, 0x00, - 0xe6, 0x00, 0x2b, 0x18, 0xb0, 0xfe, 0xd2, 0xcf, 0xfd, 0xf6, 0x1f, 0xd9, 0x93, 0x4b, - 0x60, 0x73, 0x2f, 0x4d, 0x37, 0x81, 0x0a, 0x91, 0xac, 0xef, 0x1e, 0x03, 0x8b, 0x81, - 0xd7, 0x36, 0xd9, 0x8e, 0xad, 0xa9, 0xcd, 0x7e, 0x0c, 0x2b, 0xe2, 0x7a, 0xb8, 0x50, - 0x32, 0x06, 0x60, 0x91, 0x22, 0x4e, 0xdf, 0x87, 0x2f, 0x79, 0x63, 0x7d, 0xda, 0x39, - 0x16, 0x79, 0x6a, 0x5c, 0x62, 0xf5, 0x7f, 0x1d, 0xe3, 0x76, 0x78, 0xb6, 0xde, 0xa0, - 0x08, 0x69, 0x93, 0x36, 0x74, 0xf8, 0x8e, 0x41, 0xa9, 0x18, 0x08, 0x07, 0x3b, 0x0f, - 0x43, 0x6e, 0xbe, 0x25, 0xa5, 0xf4, 0x4a, 0x60, 0x10, 0x33, 0xe2, 0x18, 0x4b, 0x88, - 0xdb, 0x79, 0xe9, 0x68, 0xca, 0x6d, 0x89, 0xb7, 0x49, 0x01, 0xbe, 0x6c, 0x6d, 0xb3, - 0x63, 0x65, 0x80, 0x18, 0x2e, 0x65, 0x8d, 0xfc, 0x68, 0x67, 0x67, 0xd6, 0xd8, 0x19, - 0xfa, 0x92, 0x3e, 0x0c, 0xdf, 0x3e, 0xa3, 0x65, 0x76, 0xf8, 0x52, 0xbc, 0xd4, 0xe1, - 0x96, 0xa7, 0x1a, 0x13, 0x29, 0xf6, 0xc3, 0xff, 0x8e, 0x42, 0xe3, 0x09, 0x5a, 0xbd, - 0x8e, 0xc1, 0x97, 0x99, 0x07, 0x13, 0xee, 0x89, 0x39, 0x4c, 0x57, 0x19, 0xb2, 0x76, - 0xde, 0x8f, 0x81, 0x8a, 0x34, 0xa7, 0xbe, 0xc1, 0xf2, 0x68, 0x68, 0x2e, 0x91, 0x42, - 0xc7, 0xd3, 0x87, 0x89, 0xf6, 0x76, 0xcc, 0x12, 0xb7, 0x1a, 0xb6, 0x66, 0x35, 0xc5, - 0x02, 0xe6, 0x9d, 0x05, 0xb9, 0xc7, 0xef, 0x01, 0x52, 0x97, 0x75, 0xc6, 0x23, 0xa4, - 0x8e, 0x4c, 0xc5, 0xc4, 0x15, 0xc9, 0xfd, 0x56, 0x53, 0x65, 0xa4, 0x16, 0x37, 0x68, - 0x78, 0x51, 0x53, 0x88, 0x7f, 0xb5, 0xf9, 0x63, 0xe7, 0xac, 0xc1, 0x62, 0xf2, 0x80, - 0x5f, 0x45, 0xf4, 0x44, 0x87, 0xf8, 0x5e, 0x19, 0x9c, 0x1d, 0xf4, 0xa0, 0xfc, 0xa4, - 0xd4, 0x4b, 0xaa, 0x62, 0xda, 0x7a, 0xf5, 0xed, 0x69, 0x68, 0x41, 0x12, 0xd3, 0x5f, - 0x00, 0x73, 0x73, 0x2f, 0x5a, 0x1a, 0xc3, 0xe4, 0xf0, 0x21, 0xba, 0x5c, 0x2c, 0x32, - 0xf0, 0x6e, 0x6b, 0x90, 0xfa, 0xe2, 0xd2, 0x54, 0xcf, 0x09, 0xe7, 0x69, 0x0c, 0xf4, - 0xe3, 0xaa, 0x70, 0x30, 0x98, 0x74, 0x48, 0xe1, 0x47, 0xf9, 0x43, 0xba, 0xb5, 0xca, - 0xb5, 0x58, 0x02, 0x9a, 0x36, 0x02, 0x4d, 0x2e, 0x79, 0x0f, 0xc6, 0xfd, 0x66, 0x7f, - 0x17, 0x6e, 0x0a, 0xa9, 0x9d, 0xd1, 0xd7, 0x2b, 0x57, - ], - script_code: vec![0x6a, 0x51, 0x65, 0xac], - transparent_input: None, - hash_type: 1, - amount: 691732482992802, - consensus_branch_id: 1991772603, - sighash: [ - 0x5d, 0x40, 0x5a, 0x1c, 0x4d, 0xed, 0x19, 0x87, 0x98, 0x8a, 0x10, 0x03, 0x64, 0xa3, - 0xcd, 0x6f, 0xe0, 0xba, 0x22, 0x20, 0xa6, 0xab, 0xce, 0x08, 0xc5, 0x17, 0x13, 0x59, - 0x55, 0x30, 0x65, 0xe9, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x01, 0xa4, 0x96, 0x69, 0x60, 0x21, - 0x82, 0x08, 0x46, 0x69, 0x61, 0x12, 0x94, 0x90, 0xa7, 0xd8, 0xb6, 0x5c, 0x14, 0x70, - 0xba, 0xd8, 0xdb, 0x08, 0x28, 0xef, 0x06, 0xc1, 0xcb, 0x55, 0x70, 0x0e, 0x85, 0xe2, - 0x4f, 0xde, 0xa9, 0x08, 0x52, 0x00, 0x65, 0x63, 0x52, 0x51, 0xac, 0x51, 0x87, 0x1f, - 0x88, 0xfb, 0x02, 0x57, 0x2c, 0x4f, 0x50, 0xa0, 0xf8, 0x01, 0x00, 0x06, 0x63, 0x00, - 0x63, 0x63, 0x51, 0xac, 0xcb, 0x37, 0x9c, 0x68, 0xc8, 0x7d, 0x04, 0x00, 0x03, 0x00, - 0x6a, 0x63, 0x53, 0x3c, 0x92, 0xcf, 0x4c, 0x1c, 0xac, 0x18, 0x99, 0x41, 0x99, 0xa8, - 0xec, 0x8e, 0x01, 0x00, 0x04, 0x1b, 0x31, 0xeb, 0xfb, 0xf8, 0x18, 0xa3, 0x99, 0x2b, - 0xf3, 0x68, 0xc2, 0x4e, 0x9a, 0xcc, 0x83, 0x14, 0x2b, 0x24, 0x0f, 0xec, 0x55, 0x4c, - 0xed, 0xa1, 0xd3, 0xfc, 0x04, 0x32, 0xc5, 0x72, 0x51, 0x34, 0x19, 0xaf, 0x1d, 0xe6, - 0x56, 0xfd, 0xd0, 0x39, 0x07, 0x22, 0xa7, 0xf4, 0x6a, 0x1f, 0xc0, 0x56, 0x3f, 0x0a, - 0xda, 0xb8, 0xbc, 0xbb, 0xb0, 0xd1, 0xb2, 0x29, 0xf5, 0xa5, 0xb9, 0x23, 0x03, 0x77, - 0x5a, 0x90, 0x4d, 0xec, 0x82, 0x7f, 0xd8, 0x7a, 0x18, 0x86, 0x0d, 0x6e, 0x8a, 0x4a, - 0x52, 0xb5, 0xcf, 0x44, 0xbe, 0x28, 0xa6, 0x2d, 0x41, 0x59, 0x02, 0x09, 0x3a, 0x0c, - 0x36, 0x5d, 0x29, 0x24, 0x12, 0x01, 0xb8, 0x26, 0x1a, 0x49, 0xd4, 0x91, 0xaf, 0x04, - 0x9b, 0x39, 0xe2, 0x6d, 0x13, 0x57, 0xc3, 0x06, 0x92, 0x64, 0x16, 0x77, 0x6d, 0x7d, - 0x13, 0xf8, 0x40, 0xbd, 0x82, 0xac, 0xa0, 0x1c, 0x83, 0x1c, 0x98, 0x3f, 0x19, 0x85, - 0xee, 0x0a, 0xda, 0xe8, 0xdb, 0x84, 0x47, 0xc0, 0xe5, 0x1c, 0x09, 0xdf, 0xe3, 0xde, - 0xe3, 0x88, 0x0a, 0x97, 0x13, 0xce, 0xb7, 0x45, 0xab, 0xfd, 0xd9, 0xf1, 0xc7, 0xea, - 0xd7, 0x63, 0x08, 0xcd, 0xee, 0xa2, 0x1c, 0x8b, 0x09, 0x57, 0x02, 0x7c, 0x5d, 0x00, - 0xe5, 0x0a, 0x43, 0x88, 0xc7, 0xaf, 0x2b, 0xd6, 0x43, 0xcb, 0x5e, 0xae, 0x49, 0x27, - 0x4d, 0x12, 0x30, 0xa4, 0xcd, 0x49, 0x23, 0x7a, 0xe3, 0x7b, 0x38, 0x10, 0xc2, 0xc3, - 0x95, 0x8a, 0x7d, 0xee, 0x02, 0x34, 0x30, 0x1b, 0x89, 0xa2, 0xdf, 0x2a, 0x78, 0xef, - 0x0b, 0xfb, 0x4b, 0xf6, 0xb3, 0x87, 0xdf, 0x2c, 0x6c, 0x86, 0xe6, 0x1c, 0xd1, 0x0c, - 0xa1, 0x1f, 0x81, 0x13, 0x01, 0x26, 0x07, 0xf1, 0x5b, 0x28, 0x56, 0x24, 0x0f, 0xdc, - 0x52, 0x06, 0x5a, 0x10, 0x28, 0xc8, 0xa2, 0xdd, 0xfd, 0xd1, 0x5c, 0xf5, 0x26, 0x5f, - 0x87, 0x38, 0x8a, 0xb9, 0xbf, 0x21, 0xc9, 0xa7, 0x8c, 0x59, 0x03, 0x8a, 0x98, 0xab, - 0x64, 0xfd, 0x67, 0x10, 0x77, 0xd4, 0x72, 0xc2, 0x09, 0xdd, 0x72, 0x9b, 0xd7, 0xf8, - 0x48, 0x09, 0x45, 0xfb, 0xa7, 0x52, 0x09, 0x8a, 0x94, 0xcc, 0xb2, 0x4c, 0xf3, 0xbc, - 0x09, 0x2d, 0x42, 0x36, 0x46, 0x11, 0xa2, 0x93, 0xaf, 0xf3, 0xc5, 0x79, 0x37, 0x2c, - 0x12, 0xe1, 0x50, 0x90, 0xaa, 0x27, 0x23, 0x20, 0x57, 0xf2, 0xed, 0xde, 0x4e, 0x1d, - 0xb2, 0x92, 0xf7, 0xb1, 0x86, 0x47, 0x22, 0x67, 0x35, 0x17, 0x6d, 0x90, 0xf1, 0x26, - 0x5b, 0x37, 0x98, 0xcc, 0xab, 0xac, 0x0b, 0x8d, 0x79, 0xb1, 0x77, 0x20, 0xb2, 0xba, - 0x71, 0xd7, 0x85, 0x0c, 0xc2, 0xa0, 0x87, 0x2b, 0xf0, 0xf4, 0xb8, 0x14, 0x36, 0x78, - 0x59, 0xf8, 0x99, 0x48, 0xf0, 0xa1, 0xa3, 0x83, 0x60, 0x4b, 0x9e, 0x1a, 0xa4, 0xc7, - 0xea, 0x28, 0x92, 0x05, 0x6f, 0x81, 0x28, 0x5b, 0xc2, 0x6f, 0x30, 0x08, 0x5d, 0xd0, - 0xef, 0x3b, 0x14, 0xd1, 0x7d, 0xda, 0x57, 0x30, 0x6a, 0xe4, 0xf6, 0x6c, 0x45, 0x9a, - 0xee, 0x8a, 0x4e, 0xd9, 0x02, 0xc6, 0x6e, 0x49, 0x18, 0xfa, 0xee, 0x8d, 0xc0, 0x06, - 0x72, 0x46, 0x96, 0x0d, 0xb1, 0xf8, 0xcd, 0x07, 0xbf, 0x90, 0xd7, 0x53, 0x7c, 0xc2, - 0x7b, 0xbb, 0x8c, 0x9d, 0x5b, 0x29, 0x62, 0xc4, 0x7e, 0xd1, 0x82, 0xa2, 0xfc, 0xe0, - 0x5f, 0x8e, 0x03, 0xc4, 0xe2, 0x5e, 0x49, 0x6d, 0xd5, 0x7d, 0x6a, 0xb3, 0x45, 0x8f, - 0xac, 0xbd, 0x91, 0xea, 0x22, 0x72, 0xff, 0xda, 0x47, 0xbf, 0xd0, 0x17, 0x39, 0x20, - 0xd7, 0x17, 0x51, 0x30, 0xf0, 0xe4, 0xd0, 0x93, 0x74, 0x41, 0xbc, 0xe9, 0x8c, 0xfa, - 0x5b, 0x33, 0x3b, 0x66, 0x19, 0x0f, 0x2b, 0x44, 0x71, 0x38, 0xe8, 0xc2, 0x6d, 0x84, - 0x12, 0xca, 0xc8, 0x20, 0x86, 0xd6, 0x1b, 0x5d, 0x2c, 0x8c, 0xf0, 0xbb, 0xeb, 0xac, - 0x5b, 0x89, 0xbf, 0xe8, 0x2b, 0x58, 0x91, 0x76, 0x64, 0xba, 0xb9, 0x1c, 0xe2, 0xec, - 0xe2, 0x90, 0xb2, 0x7b, 0x60, 0x52, 0xd4, 0xbf, 0x99, 0x1a, 0x33, 0xf4, 0x58, 0x1a, - 0x63, 0x36, 0x25, 0x78, 0x79, 0x58, 0x89, 0x7f, 0xca, 0x4b, 0x98, 0xb7, 0xe7, 0x27, - 0x7c, 0x5e, 0x6a, 0x1d, 0x88, 0x59, 0x48, 0xc9, 0xd4, 0x84, 0xdd, 0x0c, 0xef, 0xef, - 0x85, 0x4e, 0x81, 0x76, 0xc3, 0x97, 0xdc, 0xfa, 0x77, 0x2e, 0x71, 0x14, 0x72, 0xe7, - 0x90, 0xba, 0x8d, 0x39, 0x35, 0xd5, 0x7c, 0xa3, 0x13, 0x49, 0x37, 0x9e, 0x62, 0x83, - 0xa6, 0xaa, 0x8f, 0xc9, 0x91, 0xef, 0xc7, 0xd3, 0xb7, 0xef, 0x66, 0xb9, 0x2f, 0xe0, - 0x9d, 0x35, 0x16, 0x27, 0x0a, 0xe1, 0x9a, 0x99, 0x92, 0x16, 0xee, 0xae, 0x16, 0x21, - 0x44, 0xac, 0xea, 0x56, 0x0d, 0x17, 0x72, 0x05, 0xf2, 0x6c, 0x97, 0x03, 0xb5, 0x4e, - 0x80, 0xaf, 0x1a, 0x87, 0x94, 0xd6, 0xd3, 0xf1, 0xc5, 0xee, 0xad, 0x22, 0x0b, 0x11, - 0x9f, 0x06, 0xb2, 0x00, 0x98, 0x6c, 0x91, 0x21, 0x32, 0xcb, 0x08, 0xa9, 0x8e, 0x0f, - 0xee, 0x35, 0xe7, 0xf7, 0x7f, 0xc8, 0x52, 0x1d, 0x38, 0x77, 0x3e, 0x61, 0x4e, 0xee, - 0xb8, 0xa3, 0xea, 0xd8, 0x6a, 0x02, 0x48, 0x32, 0xe6, 0x4a, 0x4c, 0x75, 0x72, 0x0c, - 0xdc, 0xdd, 0xf9, 0xd0, 0x77, 0x09, 0xa1, 0x68, 0xd0, 0x10, 0x12, 0xc2, 0xe4, 0xf3, - 0x34, 0x30, 0xf2, 0x99, 0x70, 0xc6, 0x0b, 0xe8, 0xc5, 0xe2, 0xc8, 0xcc, 0x8a, 0x86, - 0xed, 0xcd, 0x51, 0x2d, 0xa7, 0x0d, 0xd7, 0xbb, 0x40, 0xe2, 0x7b, 0x32, 0xdf, 0x3d, - 0x77, 0x6a, 0x4a, 0x7b, 0x00, 0xe3, 0xbd, 0x8f, 0x69, 0x7f, 0x1f, 0x4e, 0x5c, 0x9f, - 0xbe, 0xbe, 0xb4, 0xe6, 0xfa, 0xd9, 0x1e, 0x09, 0x3d, 0xd5, 0xba, 0xc9, 0x92, 0xac, - 0xbc, 0xb8, 0x38, 0x3f, 0x9a, 0x8d, 0x8c, 0x04, 0xea, 0x6e, 0x2e, 0x0d, 0x03, 0xa2, - 0xdf, 0x83, 0xd4, 0xf4, 0x94, 0x59, 0x5b, 0x2c, 0xa1, 0x0b, 0x70, 0x79, 0x25, 0x9c, - 0x50, 0x7d, 0xf1, 0xec, 0xe4, 0x4d, 0xea, 0x4e, 0x9a, 0x4a, 0xe4, 0x0e, 0xc8, 0x33, - 0x1e, 0xeb, 0x03, 0x94, 0x73, 0xbd, 0x39, 0xc0, 0x9d, 0x01, 0x4b, 0x0d, 0x7b, 0xb9, - 0x01, 0x61, 0x66, 0x55, 0x4f, 0xf3, 0x8a, 0x1d, 0x77, 0xf2, 0xfd, 0xa4, 0xe7, 0xeb, - 0xa7, 0xa7, 0x8a, 0xb3, 0x1f, 0x38, 0x29, 0x42, 0x52, 0xa2, 0xb1, 0x0f, 0xd2, 0x86, - 0x5b, 0x57, 0x05, 0x05, 0x5d, 0xfe, 0x9b, 0x3e, 0x9e, 0x8f, 0x7a, 0xd5, 0xf4, 0x00, - 0x7d, 0xbe, 0x42, 0x2b, 0x3a, 0xa0, 0xbe, 0xb9, 0xd1, 0xc8, 0x9d, 0x37, 0x46, 0x08, - 0x54, 0xff, 0x6e, 0x5f, 0x03, 0xe5, 0xff, 0x3d, 0x4f, 0x18, 0x48, 0xf4, 0xcc, 0x64, - 0x21, 0x8a, 0x01, 0xf2, 0x47, 0x2b, 0xb0, 0x55, 0x80, 0x2f, 0x97, 0xf3, 0x20, 0x41, - 0xa7, 0x92, 0x79, 0x0b, 0x7c, 0x22, 0x6b, 0x04, 0xa6, 0xea, 0xe8, 0x5f, 0x1b, 0x71, - 0xca, 0x19, 0xa1, 0x71, 0x89, 0x02, 0xb4, 0xc3, 0xa3, 0xb5, 0x06, 0xd8, 0xc1, 0xb7, - 0xae, 0x72, 0x8c, 0x9b, 0x6c, 0xc3, 0x17, 0xe5, 0xe0, 0xde, 0xe5, 0x33, 0xe2, 0xe9, - 0x99, 0x73, 0xd8, 0x83, 0xa4, 0x0c, 0x6e, 0x68, 0xf2, 0x31, 0xd2, 0xcb, 0x01, 0x2f, - 0x60, 0xc1, 0x43, 0xcc, 0xab, 0xdd, 0x40, 0x45, 0x59, 0x0d, 0x9e, 0x43, 0xfb, 0xa3, - 0x6f, 0xe4, 0xcf, 0xd9, 0x7b, 0x4b, 0xdd, 0x0c, 0x4d, 0x2c, 0x93, 0xc5, 0x72, 0x8b, - 0x12, 0x87, 0xfd, 0x25, 0x41, 0x72, 0x2c, 0x69, 0x9b, 0xc1, 0xa0, 0x05, 0x83, 0xdb, - 0xc9, 0x48, 0xd5, 0x32, 0x4a, 0xc5, 0xbd, 0x7a, 0x68, 0x09, 0x64, 0x67, 0x3e, 0xdf, - 0x2c, 0x6d, 0xeb, 0xb1, 0xc8, 0xe1, 0xd0, 0x24, 0x16, 0xe6, 0xbd, 0xb2, 0xa7, 0x68, - 0x1b, 0xf4, 0x29, 0x92, 0x25, 0xc2, 0x1b, 0x5d, 0xb6, 0xa8, 0x45, 0xad, 0x10, 0x4d, - 0x34, 0x29, 0xcd, 0xc5, 0x9e, 0x3b, 0xca, 0xcf, 0x6d, 0xbc, 0x88, 0xaf, 0x0f, 0x67, - 0xdc, 0xbd, 0xf3, 0xa0, 0x72, 0x3e, 0x4d, 0x4b, 0xce, 0x32, 0x85, 0x1b, 0xb5, 0x19, - 0x7a, 0x8f, 0x43, 0x30, 0xb2, 0x72, 0x27, 0xf0, 0xb7, 0x71, 0xd0, 0xaf, 0x17, 0x5e, - 0x9c, 0x3f, 0x6e, 0x1f, 0x68, 0x46, 0x2e, 0xe7, 0xfe, 0x17, 0x97, 0xd9, 0x28, 0x40, - 0x6f, 0x92, 0x38, 0xa3, 0xf3, 0xfd, 0x83, 0x6a, 0x27, 0x56, 0xdd, 0x0a, 0x11, 0xe1, - 0xab, 0x94, 0x9d, 0x5e, 0x30, 0x89, 0x4f, 0x56, 0x29, 0x95, 0x25, 0xe6, 0x5d, 0x95, - 0x0f, 0x2e, 0xb5, 0x0b, 0x3a, 0x8e, 0xa7, 0xac, 0xad, 0x82, 0xde, 0x26, 0x2f, 0xa3, - 0x44, 0x80, 0xa2, 0x9c, 0x26, 0x19, 0xba, 0x45, 0x90, 0x3d, 0xf9, 0xa7, 0xf9, 0x86, - 0x2d, 0xc0, 0x49, 0xce, 0xf3, 0x97, 0xf7, 0x73, 0xbe, 0xed, 0xd3, 0x22, 0x6a, 0x8c, - 0xab, 0x1c, 0x86, 0x4d, 0x00, 0xb8, 0xfd, 0x37, 0xea, 0xf1, 0xd5, 0x93, 0x5a, 0x5b, - 0xbb, 0x6a, 0xd9, 0xf2, 0x7a, 0x1d, 0x8b, 0xaf, 0xc0, 0xac, 0x5f, 0x58, 0x02, 0x36, - 0x93, 0x82, 0x2a, 0x1d, 0xd4, 0xa7, 0xca, 0x1c, 0x49, 0xec, 0x81, 0x4e, 0x8f, 0xe6, - 0xe0, 0xe0, 0xde, 0x54, 0x6a, 0x4f, 0xbe, 0x7d, 0x25, 0x67, 0x0b, 0x2f, 0xc6, 0x8a, - 0x8f, 0xb2, 0xc4, 0xa6, 0x3d, 0xef, 0xec, 0x79, 0xc9, 0x0c, 0x63, 0xff, 0x96, 0xe5, - 0x40, 0xb7, 0x61, 0x5d, 0x43, 0xa6, 0x26, 0x1d, 0x57, 0x73, 0x03, 0x06, 0xb6, 0x63, - 0x2c, 0x8e, 0xe6, 0x1b, 0xaa, 0x4a, 0xb4, 0xd3, 0x08, 0x4d, 0x65, 0x9c, 0xab, 0xcf, - 0xc4, 0x06, 0x4c, 0x09, 0xd2, 0x42, 0x69, 0xb3, 0x03, 0x17, 0x10, 0xb6, 0x7d, 0x3b, - 0x0b, 0x73, 0x6f, 0xac, 0xbc, 0x18, 0x1e, 0xb1, 0xdc, 0x8c, 0x49, 0x3f, 0x10, 0xdb, - 0xe6, 0xfe, 0x45, 0xfd, 0xd4, 0xab, 0x60, 0x22, 0xfa, 0xbd, 0xd3, 0x4c, 0x09, 0xf7, - 0x51, 0x04, 0xc3, 0x85, 0xc9, 0x26, 0x83, 0x41, 0xc1, 0x6e, 0xbe, 0x80, 0xf8, 0xc8, - 0x0e, 0x8e, 0x06, 0x23, 0x06, 0x03, 0x99, 0x5a, 0xde, 0x55, 0x61, 0xfe, 0xd4, 0x5c, - 0xf8, 0xd1, 0x14, 0xd4, 0xcf, 0x02, 0x42, 0x0c, 0x4b, 0x96, 0x2d, 0xc2, 0x02, 0xf8, - 0xa5, 0x07, 0xf3, 0xd8, 0xe8, 0xa3, 0x44, 0xfb, 0xa1, 0x0a, 0x32, 0x7f, 0xf2, 0x22, - 0x54, 0xf6, 0xc3, 0xac, 0x8f, 0x3c, 0xf9, 0x70, 0x0b, 0x1f, 0xd2, 0xec, 0xbe, 0x9f, - 0x4e, 0x91, 0xe4, 0x3a, 0x65, 0x4f, 0xff, 0x02, 0x7c, 0xd9, 0x17, 0x4b, 0x63, 0x8e, - 0x6e, 0xfe, 0xc4, 0xab, 0xfb, 0xa1, 0x87, 0xf8, 0xf3, 0xdb, 0xa0, 0x45, 0x9d, 0xa6, - 0xc3, 0xf8, 0x00, 0xcb, 0x6b, 0x61, 0x33, 0xa8, 0xb4, 0xac, 0x1e, 0xf6, 0x58, 0xd1, - 0x11, 0xc0, 0x3f, 0x07, 0x22, 0x08, 0xdc, 0xc2, 0x07, 0xa2, 0x22, 0x3a, 0x70, 0x22, - 0x92, 0x43, 0x2e, 0x83, 0x06, 0xfc, 0x03, 0x04, 0x63, 0xe7, 0x54, 0xff, 0x0f, 0x15, - 0x3d, 0x97, 0xbc, 0x9c, 0xe9, 0x6d, 0xff, 0x4b, 0xed, 0x2f, 0x1e, 0xa5, 0xb8, 0xea, - 0x87, 0x6d, 0x2e, 0xe4, 0xe4, 0xf6, 0xe4, 0x9a, 0x4a, 0x85, 0xa9, 0xcf, 0x4a, 0x33, - 0xdc, 0xd9, 0x36, 0x60, 0xa4, 0x25, 0x43, 0xe5, 0x34, 0x22, 0x39, 0x0d, 0x66, 0x5b, - 0xdd, 0x30, 0x24, 0x78, 0xb3, 0x3c, 0x8d, 0x57, 0x47, 0x92, 0x41, 0x4c, 0x5f, 0xe5, - 0xb7, 0x4f, 0xe1, 0xd1, 0x69, 0x52, 0x5c, 0x99, 0x30, 0x1a, 0x3a, 0x68, 0xa0, 0xc8, - 0x5f, 0x02, 0x0f, 0xd5, 0x8f, 0x6d, 0x9f, 0x3a, 0xcb, 0x13, 0x9c, 0x96, 0x65, 0x38, - 0x56, 0xa3, 0x2e, 0x21, 0x02, 0x7a, 0xa2, 0xba, 0x18, 0x60, 0x10, 0xd5, 0x3c, 0xdd, - 0x4c, 0x41, 0x50, 0xcb, 0x2b, 0xb2, 0x42, 0x44, 0x65, 0x42, 0xb0, 0x17, 0x84, 0x40, - 0x1f, 0xa2, 0xcb, 0xf1, 0x22, 0xc9, 0xf1, 0x1d, 0x8c, 0x81, 0x36, 0x98, 0x7b, 0x67, - 0x86, 0x29, 0x93, 0x84, 0x58, 0x5f, 0x9c, 0xa2, 0x93, 0x53, 0x7b, 0x4b, 0xe5, 0x72, - 0x6f, 0x94, 0xd4, 0x77, 0x60, 0x5a, 0x8a, 0x6c, 0x53, 0x06, 0x02, 0xbb, 0x46, 0xc4, - 0xde, 0x20, 0x7f, 0xc5, 0x9e, 0x91, 0xe4, 0xa9, 0x0a, 0x91, 0x11, 0x77, 0x74, 0x69, - 0xf1, 0xe2, 0x87, 0x82, 0x76, 0x7d, 0x9d, 0xe5, 0x7d, 0xea, 0xde, 0xad, 0xcb, 0x4a, - 0xf5, 0x19, 0x3e, 0x09, 0xc9, 0xbb, 0x74, 0x73, 0x77, 0x3a, 0x8c, 0xa5, 0x6d, 0x76, - 0x51, 0x1d, 0x65, 0x99, 0x20, 0xdb, 0x99, 0x64, 0xd3, 0x2b, 0xad, 0xb6, 0x1f, 0x4c, - 0xf6, 0xb0, 0x22, 0xd7, 0xc1, 0x53, 0x93, 0x18, 0x49, 0x64, 0x3e, 0x8b, 0x99, 0xea, - 0xe0, 0x28, 0x4f, 0x8b, 0x01, 0x15, 0xb4, 0x23, 0x7a, 0x7c, 0x5d, 0x81, 0x97, 0x0f, - 0xe8, 0x7c, 0x6f, 0x84, 0xb6, 0x68, 0x6c, 0x46, 0x25, 0xdb, 0xdd, 0x9d, 0x79, 0xd2, - 0xc5, 0x55, 0xdd, 0x4f, 0xce, 0xed, 0x2c, 0x5e, 0x5e, 0x89, 0x6f, 0x63, 0x1a, 0xe4, - 0x59, 0x7e, 0x9c, 0xc0, 0xbe, 0xe7, 0xb3, 0x02, 0x5f, 0x95, 0x56, 0x10, 0x6a, 0x84, - 0x3a, 0x18, 0x22, 0x7f, 0x5a, 0xb9, 0x61, 0x7d, 0x7b, 0xcb, 0x1a, 0xf5, 0x28, 0xfa, - 0xa7, 0xa0, 0x52, 0xea, 0x4f, 0x52, 0xca, 0x59, 0x45, 0x57, 0xfd, 0xad, 0x33, 0x05, - 0x2b, 0xc8, 0x2b, 0x39, 0xc6, 0xa6, 0x09, 0xa0, 0x70, 0x75, 0x3d, 0x78, 0x8b, 0x2c, - 0x4a, 0x2c, 0xae, 0xbb, 0xe7, 0x9f, 0xf0, 0x12, 0x07, 0x1c, 0x07, 0x08, 0x10, 0x94, - 0xad, 0x60, 0x59, 0xc2, 0x8f, 0x48, 0xe5, 0x56, 0xc4, 0xe8, 0xd8, 0xc5, 0x37, 0x8b, - 0xc2, 0x93, 0x07, 0x6b, 0xb4, 0x97, 0x07, 0x5f, 0x9c, 0xa0, 0xba, 0x13, 0x11, 0x55, - 0x0f, 0xa2, 0x17, 0x3d, 0x0e, 0xb1, 0xf0, 0xbd, 0xdd, 0xf3, 0xb3, 0xd5, 0xc2, 0x43, - 0xff, 0xea, 0xbe, 0xe8, 0x23, 0xcd, 0x63, 0xb4, 0x39, 0x39, 0xce, 0x95, 0x46, 0xed, - 0x4c, 0x41, 0xe6, 0x0c, 0xcc, 0x7e, 0x1c, 0x54, 0x3c, 0xb3, 0xe2, 0xd3, 0x50, 0xe2, - 0xe2, 0xe9, 0x74, 0x21, 0x5c, 0xf7, 0xaa, 0x96, 0x9b, 0x66, 0x81, 0x14, 0xac, 0xdb, - 0x29, 0xf4, 0xcd, 0xcf, 0xdc, 0xec, 0x2a, 0x8c, 0xe4, 0xf5, 0x95, 0xf4, 0xff, 0x5f, - 0x70, 0x7e, 0x7f, 0xa4, 0xde, 0xe8, 0xbf, 0x8f, 0x39, 0x52, 0xae, 0x32, 0xe7, 0x7f, - 0x34, 0xf8, 0xb3, 0xab, 0xaa, 0xe9, 0x69, 0x28, 0xba, 0x4a, 0x6c, 0x0f, 0xbf, 0x5b, - 0x29, 0x19, 0x2d, 0xae, 0x80, 0x0d, 0xfa, 0x79, 0x57, 0x0c, 0xaf, 0x0b, 0xb8, 0x33, - 0xbd, 0x37, 0xa3, 0xd4, 0xbe, 0xaf, 0x09, 0x1f, 0x6b, 0x3e, 0x55, 0xaa, 0xe5, 0x25, - 0xf4, 0x13, 0xac, 0x80, 0x4c, 0x34, 0x7d, 0x54, 0x1d, 0x2c, 0x09, 0xec, 0x6e, 0x54, - 0x03, 0x5d, 0xf1, 0xd8, 0x30, 0x28, 0x4d, 0x9b, 0x46, 0xff, 0xd2, 0xb2, 0xeb, 0x04, - 0x0b, 0x61, 0x77, 0xd0, 0xa0, 0x9c, 0x16, 0x60, 0x34, 0xa9, 0x57, 0xb1, 0x8f, 0xf6, - 0x2e, 0x43, 0x4a, 0x3e, 0xc7, 0x32, 0x62, 0xe4, 0xb2, 0x3f, 0xec, 0x9d, 0x29, 0x0a, - 0x81, 0xc5, 0xb1, 0xf7, 0x3c, 0xb4, 0xcd, 0x1c, 0x47, 0x2b, 0x86, 0xe5, 0x34, 0xab, - 0x9e, 0x65, 0x53, 0x29, 0x5d, 0xb0, 0xcf, 0x34, 0xe1, 0x39, 0x2a, 0xad, 0x5a, 0xbc, - 0xf3, 0x98, 0x64, 0x16, 0xa7, 0x0a, 0x9d, 0xbe, 0x59, 0xbb, 0x95, 0x8e, 0xbc, 0x71, - 0x1c, 0x3a, 0xe0, 0x8c, 0xaf, 0x52, 0xec, 0xa9, 0xcb, 0x54, 0xc4, 0x58, 0xbe, 0x7f, - 0x5e, 0x62, 0x14, 0xec, 0xa0, 0xf0, 0xa3, 0x81, 0x52, 0x62, 0x20, 0x01, 0x32, 0xe6, - 0x14, 0x54, 0x37, 0xec, 0xd2, 0x1f, 0xc8, 0x03, 0x6c, 0xb0, 0x0a, 0x49, 0x13, 0x84, - 0xc3, 0x41, 0xd8, 0x72, 0xdc, 0xda, 0x31, 0xb1, 0x42, 0x96, 0x73, 0xd9, 0xc4, 0xf5, - 0x7b, 0x81, 0xa0, 0x23, 0x6d, 0xa5, 0xec, 0x55, 0x02, 0xee, 0x29, 0x63, 0x15, 0x0a, - 0x00, 0x26, 0xbd, 0x63, 0xef, 0x67, 0x9e, 0x8c, 0x25, 0xb8, 0xec, 0xee, 0x06, 0x56, - 0x4a, 0xf3, 0xb0, 0x2d, 0xea, 0xb1, 0x06, 0x97, 0xa2, 0x4d, 0xe6, 0x7d, 0x4f, 0x65, - 0x04, 0xae, 0x27, 0x37, 0xb8, 0xe1, 0x73, 0x25, 0xc2, 0xff, 0x15, 0x0c, 0x62, 0xe3, - 0x79, 0x83, 0x44, 0xa1, 0xad, 0x3c, 0xbb, 0x75, 0xb7, 0xf2, 0xa1, 0x57, 0x38, 0xf6, - 0x01, 0xcf, 0x00, 0xf7, 0xe8, 0xbc, 0x08, 0xb6, 0x89, 0x56, 0x7e, 0x4c, 0x7c, 0x01, - 0x05, 0x8b, 0xee, 0xc2, 0x90, 0x3c, 0x5c, 0xa6, 0xb4, 0xc4, 0xa5, 0x71, 0xf4, 0x60, - 0xd6, 0x05, 0x87, 0x36, 0x29, 0x96, 0xc6, 0xe1, 0x25, 0x54, 0xe8, 0xe3, 0x4e, 0x68, - 0x3a, 0x27, 0xf8, 0xa5, 0xff, 0x97, 0x1d, 0x5a, 0x0d, 0xc2, 0xf3, 0xef, 0xd3, 0x88, - 0x99, 0x87, 0xc1, 0xcc, 0x39, 0xce, 0x5d, 0x4b, 0x6b, 0x54, 0x4c, 0xe0, 0x4c, 0x71, - 0xee, 0x4b, 0xfa, 0xe5, 0x04, 0x0d, 0x61, 0xf0, 0x57, 0xe4, 0xf7, 0x70, 0x17, 0x28, - 0xf1, 0x20, 0x04, 0xa7, 0xf7, 0xed, 0xeb, 0x3a, 0xb2, 0x26, 0x09, 0xed, 0x33, 0xb0, - 0xab, 0x5d, 0x69, 0xb1, 0x2d, 0x45, 0x76, 0x57, 0x77, 0x14, 0xdf, 0xc6, 0xdd, 0xa7, - 0x1f, 0xf6, 0x01, 0x7b, 0x55, 0xb3, 0x35, 0x4d, 0x11, 0xe9, 0x21, 0x67, 0x92, 0xe5, - 0x60, 0x9f, 0xc0, 0x67, 0x88, 0xec, 0x66, 0x8e, 0xef, 0x64, 0x5e, 0x63, 0xb3, 0x7e, - 0x2d, 0x0c, 0xd2, 0x63, 0x04, 0x08, 0x00, 0xbc, 0x8a, 0xa2, 0x80, 0x15, 0x6a, 0x79, - 0x4f, 0x62, 0xa5, 0xf6, 0x93, 0xeb, 0xd9, 0x07, 0x4b, 0x5d, 0x35, 0x4a, 0x71, 0xc8, - 0xe3, 0x36, 0xde, 0x04, 0x08, 0xac, 0x70, 0x80, 0xa2, 0xae, 0xee, 0x36, 0x6c, 0x58, - 0x14, 0x6f, 0x32, 0xe3, 0x49, 0xa9, 0xbc, 0x65, 0x7e, 0xc9, 0xe5, 0x7a, 0x89, 0xa0, - 0x4c, 0xce, 0xee, 0x21, 0xbd, 0xf3, 0x79, 0x3e, 0x49, 0xa5, 0xcf, 0x71, 0x3a, 0x42, - 0xd0, 0x29, 0xdd, 0xdb, 0x3d, 0xb4, 0x95, 0x09, 0x2c, 0x37, 0xce, 0x81, 0x4b, 0xe7, - 0x3e, 0xf4, 0xec, 0x8d, 0x70, 0xe8, 0x69, 0xbd, 0x2b, 0x78, 0x8f, 0x15, 0x00, 0xfe, - 0x5e, 0xe5, 0x6c, 0x0c, 0xe7, 0x04, 0xeb, 0xa2, 0xc1, 0xa3, 0xa3, 0x29, 0x0d, 0xe6, - 0xec, 0x68, 0xcc, 0xb5, 0xef, 0x7c, 0xd0, 0x21, 0x2a, 0x3f, 0x09, 0x96, 0x92, 0xcf, - 0x00, 0x04, 0x8d, 0xe5, 0x01, 0x26, 0x19, 0xe7, 0x41, 0x69, 0x2b, 0xfc, 0x74, 0x05, - 0xba, 0x3e, 0x87, 0x5e, 0x98, 0xb7, 0xca, 0x31, 0xe9, 0x65, 0xa1, 0x6f, 0xdd, 0xb5, - 0xb0, 0xb7, 0x72, 0xa3, 0xf5, 0xd0, 0x50, 0xd8, 0xad, 0x7f, 0x60, 0x7f, 0x55, 0xc0, - 0xdc, 0x52, 0xb4, 0x8f, 0xb0, 0x2a, 0x8b, 0x1d, 0xef, 0xc6, 0xc3, 0x10, 0xb2, 0x47, - 0x55, 0x59, 0xb4, 0x7e, 0x84, 0x4e, 0xd3, 0x77, 0x60, 0xd7, 0xd1, 0x6f, 0x27, 0xcb, - 0x48, 0xbf, 0x36, 0x16, 0xc4, 0x6f, 0xb0, 0xcf, 0x3c, 0x8c, 0x28, 0xb9, 0x39, 0x27, - 0x80, 0x0a, 0x29, 0x16, 0xa4, 0x07, 0xa6, 0x0d, 0x68, 0x99, 0x7b, 0x10, 0x50, 0x51, - 0x32, 0xad, 0x33, 0xf9, 0xce, 0x26, 0xb4, 0xac, 0xba, 0x27, 0xa2, 0xa0, 0xc2, 0x18, - 0xdb, 0x15, 0xa5, 0xd7, 0xaa, 0xed, 0x4f, 0x6a, 0x72, 0x00, 0x36, 0x72, 0xca, 0x70, - 0x49, 0x8b, 0x05, 0x49, 0x4a, 0x93, 0x34, 0x1f, 0xcf, 0x96, 0xc0, 0x99, 0x4e, 0x42, - 0x7b, 0xeb, 0xd3, 0x56, 0xe4, 0x17, 0x6d, 0xec, 0x83, 0xe6, 0xfe, 0x80, 0x02, 0x9c, - 0xfc, 0x47, 0x8b, 0x88, 0xb6, 0xfd, 0x38, 0xc0, 0x39, 0xe0, 0x8b, 0x6f, 0xd9, 0x5d, - 0xab, 0xcf, 0xb2, 0x5f, 0x23, 0x8b, 0x26, 0x62, 0x06, 0xb0, 0xa2, 0xf9, 0xa2, 0xee, - 0xa1, 0xc0, 0x83, 0xfa, 0xc8, 0x08, 0xaa, 0xfa, 0x03, 0x65, 0x66, 0xcc, 0xd2, 0x02, - 0xbc, 0xfa, 0x41, 0x4e, 0x71, 0xc8, 0xb4, 0x89, 0x33, 0xc8, 0xed, 0x45, 0x28, 0x7e, - 0x1b, 0x43, 0x9b, 0x61, 0x06, 0xa5, 0x50, 0x94, 0x73, 0xf5, 0x7b, 0x87, 0x88, 0xaf, - 0x52, 0x7c, 0xf9, 0xa7, 0xab, 0xa5, 0x93, 0xdc, 0x9f, 0x5e, 0x5a, 0xca, 0x1a, 0x64, - 0x8e, 0xe4, 0x88, 0xf3, 0x6d, 0xeb, 0x4a, 0x3f, 0xdb, 0x0f, 0xf6, 0xf5, 0xa3, 0x04, - 0x4a, 0x63, 0xe1, 0x7f, 0x70, 0xa4, 0x30, 0x38, 0x24, 0x60, 0x3a, 0xb5, 0x0e, 0x9b, - 0xf7, 0x5b, 0xae, 0xb5, 0x7b, 0xfd, 0xc8, 0x9b, 0xfd, 0xbc, 0x27, 0x27, 0x9d, 0x10, - 0x73, 0xbf, 0x7f, 0x95, 0x05, 0xfb, 0x31, 0x68, 0xd2, 0x06, 0xe2, 0xbf, 0x41, 0x02, - 0xbf, 0x15, 0x9c, 0xff, 0x61, 0xe6, 0xd6, 0x6c, 0x80, 0x37, 0x50, 0xda, 0x25, 0x4c, - 0xd6, 0xb8, 0x1a, 0xed, 0x42, 0x09, 0x97, 0x94, 0xb8, 0x4e, 0xce, 0x90, 0x42, 0x18, - 0xe6, 0xf6, 0x6e, 0xc6, 0x34, 0xe9, 0x2e, 0xef, 0xf4, 0x5f, 0x52, 0xe0, 0x4b, 0x4b, - 0x79, 0x5a, 0x15, 0x25, 0xaa, 0xf9, 0xc5, 0x1d, 0x62, 0x60, 0xfb, 0xd6, 0x4e, 0x8d, - 0x8a, 0xc2, 0x66, 0xdc, 0x6e, 0x7d, 0xf6, 0x15, 0x3a, 0xd9, 0x73, 0x55, 0x83, 0x79, - 0x28, 0x40, 0x4c, 0xd5, 0x81, 0xbc, 0x9c, 0xf9, 0xdc, 0xd6, 0x67, 0x47, 0xdc, 0x97, - 0x0a, 0x9f, 0x00, 0xde, 0xb4, 0x4b, 0xd6, 0x34, 0xab, 0x04, 0x2e, 0x01, 0x04, 0xc1, - 0xce, 0x74, 0x7f, 0x53, 0x75, 0x1b, 0xc3, 0x3e, 0x38, 0x4c, 0x6b, 0x55, 0x76, 0x39, - 0x9e, 0x16, 0xf8, 0xf0, 0xcb, 0x08, 0xde, 0x35, 0x08, 0x37, 0x33, 0x95, 0x45, 0x87, - 0xc1, 0xc2, 0x4d, 0xf2, 0xae, 0x66, 0x30, 0xff, 0xfe, 0x99, 0x62, 0x15, 0xef, 0xe4, - 0xd2, 0x62, 0x6d, 0xeb, 0x20, 0x56, 0x6a, 0x8f, 0x5e, 0xad, 0x2f, 0x04, 0xdb, 0x5d, - 0x08, 0x77, 0x9c, 0x9c, 0x65, 0x9e, 0xa3, 0x43, 0xcd, 0x78, 0x46, 0x34, 0xc9, 0x9d, - 0x8c, 0x8b, 0xad, 0xa9, 0x3b, 0xe8, 0xe6, 0xda, 0x84, 0x15, 0x94, 0xba, 0xcf, 0x7c, - 0xb3, 0xe6, 0x92, 0xc7, 0x4b, 0x5f, 0xfe, 0x95, 0x78, 0x73, 0x11, 0x3a, 0x1a, 0xb0, - 0x64, 0x02, 0x6f, 0x6d, 0xee, 0x8b, 0x48, 0xa3, 0x84, 0xa1, 0x33, 0x83, 0x18, 0x36, - 0x07, 0x86, 0x50, 0x27, 0x84, 0xd1, 0x7d, 0x40, 0x0c, 0xe3, 0xd7, 0x21, 0x78, 0x7e, - 0xdc, 0x4c, 0x6b, 0x39, 0x35, 0x66, 0x25, 0x10, 0x77, 0x10, 0x00, 0x68, 0x0d, 0x78, - 0xbb, 0x49, 0xc5, 0x66, 0xef, 0x27, 0xdf, 0x61, 0xc9, 0xfe, 0xb9, 0x2c, 0x08, 0x97, - 0x59, 0x44, 0x87, 0x27, 0xa9, 0x34, 0xe3, 0x57, 0x95, 0x3d, 0xe1, 0xe9, 0xe9, 0x0f, - 0xd8, 0xdf, 0xfe, 0x40, 0xb8, 0x73, 0xbc, 0xd5, 0xb9, 0x82, 0x08, 0xdf, 0x4b, 0x2c, - 0xa2, 0x89, 0x7a, 0xf9, 0x0d, 0x8c, 0x8a, 0x23, 0x62, 0x30, 0x02, 0xa9, 0xd8, 0xbc, - 0x02, 0xe8, 0x06, 0x25, 0x4f, 0x41, 0x0e, 0x3b, 0x02, 0x40, 0x9c, 0xbe, 0xbf, 0xce, - 0x8a, 0xcf, 0x65, 0xcf, 0x39, 0x42, 0x6b, 0x64, 0xa6, 0xba, 0x93, 0x74, 0xa1, 0x3d, - 0x72, 0x59, 0x62, 0x3f, 0x65, 0xe9, 0x3e, 0x10, 0xbf, 0x1f, 0x16, 0xba, 0x7a, 0xe0, - 0x7d, 0xa9, 0x20, 0x58, 0x1c, 0x70, 0x40, 0x9e, 0xdc, 0x7b, 0x9e, 0x21, 0x4e, 0x95, - 0x91, 0x92, 0x82, 0x4c, 0x1d, 0xa6, 0x5d, 0x33, 0x7b, 0x73, 0x75, 0xf5, 0x03, 0x2f, - 0xea, 0xd3, 0xb4, 0xf3, 0x28, 0x48, 0x11, 0x95, 0x0c, 0x7a, 0x90, 0xae, 0xc9, 0x75, - 0xd4, 0xe3, 0x62, 0x9f, 0x52, 0xd1, 0x9a, 0x16, 0x4e, 0x51, 0x16, 0xef, 0x3a, 0xd0, - 0x22, 0x44, 0x2d, 0x1e, 0xec, 0x76, 0xb8, 0x88, 0x73, 0x8b, 0x53, 0xe5, 0x05, 0x58, - 0xa7, 0x0f, 0x20, 0xc8, 0xac, 0xb5, 0x8d, 0xee, 0x63, 0x27, 0x15, 0xe4, 0x78, 0xe2, - 0xbc, 0x21, 0xbc, 0xfb, 0xe3, 0x15, 0x59, 0x96, 0xca, 0xe7, 0xbd, 0x97, 0xf0, 0x2b, - 0x51, 0x6d, 0x32, 0x00, 0xfb, 0x3c, 0x17, 0x39, 0x7c, 0xc1, 0x2b, 0xb7, 0xa1, 0x9f, - 0xd4, 0x36, 0xe6, 0x7a, 0xbc, 0xe6, 0x6d, 0x30, 0xfe, 0xc0, 0x47, 0xfb, 0x27, 0x70, - 0x82, 0x0e, 0x47, 0x6f, 0x3e, 0x32, 0xbc, 0x48, 0x3b, 0xf5, 0x31, 0x64, 0xae, 0x49, - 0x70, 0xf1, 0x1b, 0x9c, 0xae, 0xe4, 0xed, 0x6c, 0xb8, 0xd2, 0xd7, 0x0f, 0x69, 0x13, - 0xd8, 0xe0, 0x2a, 0xf8, 0xfb, 0xb1, 0xe4, 0x09, 0xb4, 0xef, 0x08, 0x04, 0x48, 0xe5, - 0x3b, 0xe6, 0xe5, 0xe6, 0x05, 0x75, 0xdf, 0xde, 0x94, 0x28, 0xb0, 0x06, 0x96, 0x61, - 0x1a, 0x2f, 0x72, 0x33, 0x2a, 0xe2, 0x90, 0x23, 0xdd, 0x88, 0xae, 0x77, 0xf1, 0x5b, - 0x8a, 0xe2, 0xc2, 0x4b, 0x86, 0xcf, 0x3d, 0x57, 0x43, 0x9c, 0xaf, 0x17, 0xf2, 0x8e, - 0xda, 0x94, 0x93, 0x2e, 0xef, 0x28, 0x53, 0x4e, 0x16, 0x49, 0xce, 0xf8, 0x85, 0x40, - 0xfc, 0xb1, 0xa6, 0x3e, 0x11, 0x5c, 0x58, 0x22, 0xaf, 0xa4, 0x40, 0xc8, 0xd7, 0x9d, - 0x66, 0xf9, 0xbb, 0x1f, 0x48, 0xe1, 0x14, 0x0b, 0x06, 0xec, 0x87, 0x18, 0x3c, 0xbc, - 0x6e, 0x95, 0xf6, 0xcd, 0x5f, 0x7e, 0xbc, 0xad, 0xb8, 0x97, 0xc7, 0x7b, 0x4a, 0xfb, - 0x36, 0x7b, 0x95, 0x2d, 0xbb, 0x71, 0x7f, 0x75, 0x18, 0x90, 0xc8, 0xac, 0x30, 0x36, - 0xda, 0xcd, 0xbd, 0x78, 0x4a, 0x0d, 0x83, 0xab, 0xb8, 0x44, 0x6b, 0x3f, 0x93, 0x96, - 0x33, 0x5f, 0xbf, 0x0b, 0x44, 0xed, 0xc9, 0x9e, 0x1c, 0x67, 0xc5, 0xc3, 0x81, 0x6a, - 0xce, 0x76, 0x29, 0xe6, 0xe7, 0xb0, 0x28, 0xd6, 0xc8, 0x62, 0x74, 0x9e, 0x86, 0xeb, - 0xc5, 0x11, 0x7e, 0x21, 0xf4, 0x23, 0xe1, 0x8d, 0x09, 0x76, 0xa1, 0xf5, 0x1d, 0x45, - 0x47, 0x6d, 0xa5, 0x60, 0xff, 0x23, 0x15, 0x42, 0xbb, 0x21, 0xc3, 0xde, 0xd2, 0xf2, - 0x3b, 0x2a, 0x50, 0xe0, 0xb8, 0x22, 0x56, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x1d, 0x11, - 0x65, 0xd7, 0x60, 0x70, 0x2e, 0xf1, 0x03, 0xd2, 0x23, 0x67, 0x26, 0x90, 0x23, 0x59, - 0xbe, 0x8d, 0x79, 0x73, 0x52, 0xf9, 0x6d, 0x22, 0x46, 0xa2, 0xee, 0x0a, 0xf8, 0x0a, - 0x2a, 0x2d, 0x89, 0xa5, 0x85, 0x30, 0xd6, 0xe3, 0x6b, 0xd3, 0x3a, 0x00, 0xc1, 0xb8, - 0x93, 0xd6, 0xff, 0x8f, 0x90, 0x01, 0x44, 0x15, 0x1b, 0xee, 0x34, 0xc7, 0x94, 0x4b, - 0x99, 0xed, 0x6e, 0x79, 0x45, 0xe7, 0xf0, 0xde, 0x87, 0x26, 0x3d, 0x0b, 0xba, 0x6e, - 0x55, 0xac, 0x96, 0xa9, 0x6d, 0x49, 0x95, 0x12, 0x9b, 0xcf, 0xa9, 0xd9, 0xda, 0x6d, - 0xe6, 0xdd, 0x48, 0x26, 0x39, 0x15, 0x3a, 0x81, 0x69, 0xa4, 0xab, 0x46, 0x4e, 0x39, - 0x0b, 0x7f, 0x0a, 0x96, 0xd1, 0x4a, 0x73, 0xf7, 0x69, 0x7f, 0x7e, 0xce, 0x3c, 0xd7, - 0x81, 0xd3, 0x5d, 0xd2, 0x2a, 0xdd, 0xdd, 0x2f, 0x5d, 0x34, 0x52, 0x04, 0xe4, 0xbb, - 0x55, 0x7e, 0x88, 0x45, 0x3f, 0x18, 0x8c, 0xac, 0xbe, 0x92, 0x29, 0x87, 0xbb, 0xe3, - 0xb3, 0xd9, 0x76, 0x82, 0x61, 0x35, 0xc1, 0x03, 0xb6, 0xca, 0x18, 0x2b, 0x63, 0xe9, - 0xe6, 0x7f, 0x83, 0xdc, 0x9f, 0x48, 0x93, 0x33, 0xd5, 0x2a, 0x7f, 0xd7, 0x68, 0x8a, - 0x58, 0xd6, 0x62, 0x0b, 0x67, 0xe9, 0xc7, 0xb0, 0x91, 0x6f, 0xef, 0x90, 0xf1, 0x5d, - 0x8e, 0x4e, 0xb8, 0x0c, 0xf5, 0x99, 0x68, 0x2f, 0x95, 0x4f, 0xf4, 0xe0, 0xb3, 0x71, - 0x83, 0x13, 0x0c, 0xa2, 0xee, 0xd0, 0x91, 0x3f, 0x46, 0xa4, 0xdb, 0x99, 0x2a, 0x1c, - 0x3b, 0xf3, 0x19, 0xdc, 0x86, 0x75, 0x94, 0x01, 0x01, 0x53, 0x7c, 0xff, 0xc4, 0xa8, - 0x2d, 0x59, 0x9b, 0xbe, 0xa0, 0xd4, 0x7e, 0x7a, 0xbf, 0xa9, 0x92, 0xb4, 0x99, 0x8c, - 0xb2, 0x50, 0x09, 0x55, 0xe6, 0x1c, 0x0d, 0x46, 0xb3, 0x21, 0x17, 0xfb, 0xb9, 0x7f, - 0x7a, 0x76, 0x32, 0xd8, 0x72, 0x4b, 0x5d, 0xff, 0x67, 0xf7, 0x5e, 0x2d, 0x31, 0x74, - 0x06, 0xa0, 0xce, 0xc2, 0x89, 0xed, 0x08, 0x3b, 0x7c, 0x58, 0x19, 0x81, 0x8c, 0x50, - 0x47, 0x93, 0xde, 0x53, 0xb6, 0xbf, 0xdb, 0x51, 0x0e, 0x7c, 0xa7, 0x29, 0xba, 0x74, - 0x3d, 0x10, 0xb3, 0xe9, 0x95, 0x7e, 0xfa, 0x84, 0x20, 0x13, 0x39, 0x47, 0x7c, 0xf3, - 0x5f, 0xbb, 0x6a, 0x27, 0x9b, 0xad, 0x9e, 0x8f, 0x42, 0xb9, 0xb3, 0xfd, 0x6f, 0x3b, - 0xc7, 0x70, 0x67, 0x1d, 0x9c, 0x19, 0x12, 0x2f, 0xa3, 0x25, 0x6d, 0x09, 0x07, 0x36, - 0xb6, 0xd6, 0x4e, 0xb9, 0xcc, 0x03, 0x20, 0xf1, 0xea, 0xaa, 0x27, 0x1b, 0xa2, 0x86, - 0x1e, 0xc4, 0xb3, 0xf3, 0xf6, 0xc8, 0x40, 0xb6, 0x19, 0xff, 0x38, 0x8d, 0x81, 0xfc, - 0x40, 0x44, 0xa0, 0xd5, 0x31, 0xa4, 0xbb, 0x44, 0xc9, 0x3d, 0x09, 0x9d, 0xb0, 0x8a, - 0x9b, 0xc3, 0x46, 0xa0, 0xb6, 0x2f, 0x16, 0x8f, 0xfb, 0xdb, 0x73, 0x93, 0x66, 0xbb, - 0x53, 0x5d, 0xde, 0x66, 0xc2, 0xc1, 0x28, 0x7b, 0x3b, 0x27, 0x85, 0xae, 0xd6, 0x4c, - 0xc4, 0x0c, 0xbc, 0x7d, 0x33, 0xcb, 0xa4, 0xa9, 0xf3, 0xfc, 0xf5, 0xf8, 0x31, 0x36, - 0xa4, 0x39, 0x2d, 0x21, 0xa7, 0xf9, 0xeb, 0x1c, 0xe4, 0xb6, 0xe1, 0x7e, 0x6f, 0x4a, - 0x85, 0xa5, 0x79, 0x66, 0x9e, 0xfd, 0x0f, 0xb0, 0x98, 0x78, 0xe0, 0x88, 0xe3, 0x22, - 0xe9, 0x06, 0xe8, 0x0d, 0x27, 0xf8, 0xd0, 0xca, 0x7e, 0x79, 0x15, 0xab, 0x40, 0x96, - 0x59, 0xa6, 0xd8, 0x0f, 0xde, 0xd1, 0x0a, 0xff, 0x9f, 0xb7, 0x73, 0x74, 0x9d, 0x79, - 0x28, 0x57, 0xf6, 0x8c, 0x7e, 0x8c, 0xf5, 0x18, 0x26, 0x0a, 0x61, 0x08, 0x6d, 0xe3, - 0x2f, 0xff, 0x82, 0x39, 0xf4, 0x53, 0x61, 0x7a, 0x19, 0xf6, 0xfe, 0xc2, 0x20, 0x67, - 0x60, 0x65, 0xeb, 0xe2, 0x75, 0x7e, 0xfc, 0xac, 0xcb, 0x77, 0xfc, 0x61, 0xe5, 0x9b, - 0x97, 0x63, 0x7e, 0x92, 0x0d, 0xee, 0x5e, 0x7e, 0x7a, 0x12, 0xe9, 0xd6, 0xd2, 0x28, - 0xb2, 0x6b, 0x2f, 0xa8, 0x36, 0xf4, 0x72, 0x83, 0x69, 0xad, 0xcd, 0xfc, 0xd0, 0x04, - 0xdc, 0xf1, 0x9e, 0x27, 0xc0, 0xc0, 0x84, 0x44, 0xd2, 0x9a, 0x12, 0x2b, 0x23, 0x09, - 0xf7, 0x16, 0x3c, 0x99, 0x0e, 0xb9, 0x26, 0x1f, 0xd4, 0x15, 0xc0, 0x45, 0x4a, 0x56, - 0xaa, 0x3e, 0xaf, 0x9c, 0x1f, 0x9b, 0xff, 0xf6, 0x04, 0x77, 0x6a, 0x4d, 0x25, 0xe7, - 0xd3, 0xcd, 0xc5, 0xc5, 0xf1, 0x9c, 0xd2, 0xa8, 0x79, 0x4a, 0x4f, 0x57, 0x16, 0x7f, - 0xbc, 0x7e, 0xaa, 0x06, 0x16, 0x4d, 0x51, 0xc4, 0x53, 0x06, 0x14, 0xbc, 0xf5, 0x20, - 0xb2, 0x63, 0x82, 0x0a, 0xa1, 0x7b, 0x20, 0xb4, 0x8c, 0xbf, 0x59, 0xd8, 0xe3, 0x09, - 0x32, 0x2e, 0xbe, 0x56, 0x6f, 0xbe, 0x46, 0xe0, 0xaa, 0x29, 0x76, 0x6a, 0xdf, 0xdf, - 0x01, 0x7a, 0x71, 0x05, 0x10, 0x3c, 0x7f, 0xca, 0xb7, 0xb0, 0x76, 0x48, 0xc7, 0xc1, - 0x16, 0x04, 0x84, 0xf7, 0x7a, 0x6c, 0x70, 0xa5, 0x38, 0x1b, 0x82, 0x56, 0x40, 0xa1, - 0xbe, 0x48, 0xe4, 0x15, 0xa1, 0xe6, 0xa2, 0x7d, 0x78, 0x02, 0x2a, 0x8a, 0x2f, 0xf0, - 0x70, 0xab, 0xf1, 0x23, 0x94, 0xe3, 0xae, 0x5a, 0x8c, 0x23, 0xe3, 0x73, 0x3e, 0xa4, - 0x7a, 0x44, 0xcb, 0x2c, 0x96, 0x8b, 0xca, 0x24, 0x98, 0x37, 0xde, 0x1d, 0x39, 0xa5, - 0xa1, 0xdc, 0xae, 0x71, 0x0c, 0xe0, 0x43, 0x01, 0x69, 0xbd, 0x6e, 0x9f, 0x64, 0xab, - 0xf1, 0xe6, 0x4e, 0xc4, 0x9e, 0xd0, 0x80, 0x4e, 0xb6, 0x47, 0x74, 0x3a, 0xce, 0xa9, - 0x29, 0xed, 0x0f, 0x7c, 0x90, 0x15, 0xb0, 0xe8, 0x1e, 0x21, 0x29, 0xdb, 0x05, 0x0d, - 0x5e, 0x78, 0xe6, 0x82, 0xc8, 0x19, 0x93, 0xea, 0x87, 0x53, 0xc9, 0x91, 0xb0, 0x2e, - 0x61, 0x81, 0x0e, 0x74, 0x61, 0xed, 0x87, 0xb3, 0x80, 0xdb, 0x96, 0xab, 0xe3, 0xbe, - 0xad, 0x0f, 0x4b, 0x22, 0x12, 0xdb, 0x65, 0x8c, 0x11, 0xb8, 0x3f, 0x53, 0x11, 0x47, - 0x85, 0x27, 0x65, 0x98, 0xb0, 0x19, 0x7a, 0x7f, 0x1c, 0x25, 0x62, 0x7d, 0x79, 0x62, - 0x4d, 0xac, 0xee, 0x97, 0x7d, 0x9f, 0x4e, 0x1a, 0x35, 0xed, 0x2e, 0xaa, 0xd3, 0xcb, - 0x68, 0x25, 0x0a, 0xa9, 0xb3, 0xab, 0x1a, 0x83, 0x45, 0x72, 0x8e, 0x7d, 0x1a, 0x78, - 0xbe, 0x1f, 0xe4, 0x62, 0xce, 0x8e, 0xad, 0x52, 0x8f, 0x7c, 0x05, 0x0f, 0x1f, 0x6e, - 0x02, 0x2b, 0xa8, 0xb0, 0xce, 0xdf, 0x6e, 0x29, 0x7a, 0xb5, 0x64, 0xca, 0x1a, 0x1f, - 0xaa, 0xf4, 0xcf, 0xf1, 0xe4, 0x20, 0x32, 0xfb, 0xbb, 0x38, 0x9d, 0x3f, 0x66, 0xd5, - 0x75, 0x55, 0xef, 0x3f, 0x3e, 0x9e, 0x49, 0xc2, 0xac, 0x4e, 0x85, 0xbb, 0x75, 0x1d, - 0x62, 0x66, 0xc9, 0x03, 0x5b, 0x77, 0x9d, 0x76, 0x9d, 0x49, 0x5c, 0x91, 0x8a, 0x05, - 0x5e, 0x77, 0x67, 0xfb, 0xb4, 0xbb, 0xac, 0x3f, 0x96, 0x3d, 0xe9, 0x97, 0x46, 0xec, - 0x4d, 0xfb, 0x64, 0x2d, 0x9c, 0x2b, 0x86, 0x38, 0xe1, 0x6c, 0x16, 0xe7, 0x27, 0x70, - 0x79, 0x3b, 0x7e, 0xa1, 0xd0, 0x70, 0xc4, 0xe1, 0x1c, 0xbc, 0x20, 0xd8, 0xff, 0x3b, - 0xea, 0xd1, 0x0d, 0xb9, 0xc9, 0x4a, 0xe0, 0x48, 0x27, 0x21, 0xe1, 0xf2, 0x2c, 0xef, - 0xe0, 0xdf, 0x7c, 0x57, 0x7a, 0xa3, 0x8e, 0xc0, 0xe6, 0xc7, 0x8c, 0x9b, 0xa1, 0x64, - 0xe9, 0xdd, 0x00, 0x55, 0xdd, 0xe8, 0x3e, 0x8a, 0xd2, 0x40, 0xe6, 0xdf, 0xdb, 0xfb, - 0xe1, 0x76, 0xe4, 0x55, 0x1f, 0xdd, 0xe9, 0x2d, 0xb1, 0x67, 0x27, 0x42, 0x04, 0x41, - 0x70, 0x06, 0x58, 0xb5, 0x0e, 0xbb, 0x5a, 0x16, 0x13, 0x26, 0x7e, 0xac, 0x51, 0xc8, - 0x0b, 0x19, 0xec, 0xb7, 0x86, 0xab, 0x3b, 0xb9, 0x37, 0xf0, 0xd9, 0x8e, 0x08, 0xb9, - 0xc9, 0xcd, 0x4d, 0xf1, 0x53, 0x4e, 0xfe, 0xe3, 0x8a, 0x8f, 0x87, 0x8c, 0x9f, 0x3b, - 0xdc, 0x7e, 0xfb, 0x2d, 0x53, 0xff, 0x84, 0xfb, 0x83, 0xea, 0xe7, 0xc9, 0x9e, 0xff, - 0xa6, 0x3c, 0x96, 0x49, 0xa1, 0xf1, 0x70, 0xd2, 0x9a, 0xf0, 0x3a, 0x3b, 0x45, 0x58, - 0x9f, 0xae, 0x81, 0xeb, 0x0b, 0x5d, 0x8e, 0x0d, 0x38, 0x02, 0x1d, 0x3b, 0x5f, 0x07, - 0xe8, 0x8c, 0x99, 0x04, 0x37, 0x6d, 0x27, 0xf1, 0x3e, 0x44, 0x41, 0xd5, 0x38, 0x74, - 0x42, 0xc5, 0xea, 0x0a, 0xf5, 0xa2, 0x0a, 0x38, 0x32, 0xbc, 0x3b, 0x9c, 0x59, 0xb8, - 0x4b, 0xca, 0x39, 0xb5, 0x2c, 0xd6, 0xb1, 0xfa, 0x29, 0x32, 0xba, 0x9d, 0x66, 0xc4, - 0x12, 0xf5, 0xcd, 0x39, 0x35, 0x1e, 0x13, 0x33, 0xef, 0x85, 0xd0, 0xee, 0xe5, 0x45, - 0xa7, 0xe4, 0x06, 0xf6, 0xeb, 0x3b, 0xf8, 0x93, 0xf3, 0xed, 0xac, 0x94, 0x64, 0x33, - 0x92, 0xa2, 0x8b, 0x0e, 0x49, 0x0c, 0x51, 0xe4, 0xb7, 0x16, 0x3c, 0x1c, 0xf7, 0x57, - 0xd2, 0x24, 0x18, 0xdd, 0x63, 0x38, 0x1b, 0xa2, 0xf2, 0x98, 0x28, 0x83, 0x6f, 0xe9, - 0x78, 0xda, 0xb5, 0x20, 0x1b, 0x2d, 0xb0, 0x8c, 0x3b, 0x38, 0x9b, 0xa4, 0xb6, 0xac, - 0xf7, 0x78, 0xc2, 0xbf, 0x91, 0x02, 0xbe, 0x0c, 0x3e, 0x12, 0xd7, 0x7a, 0xea, 0x6d, - 0xf7, 0x53, 0x8e, 0x8c, 0xf3, 0x62, 0xba, 0xaa, 0xad, 0x1d, 0xc5, 0x60, 0x42, 0xc6, - 0xf2, 0x4c, 0xaf, 0x46, 0xbe, 0xd6, 0x6a, 0xbf, 0x4c, 0x40, 0x2a, 0x74, 0x92, 0x4e, - 0xcf, 0xd0, 0xa0, 0x8d, 0xed, 0xee, 0xa0, 0xef, 0xce, 0xcd, 0x35, 0x2c, 0x27, 0x5f, - 0x13, 0xed, 0x20, 0x76, 0x03, 0x82, 0x2b, 0x1e, 0xf9, 0x97, 0xb7, 0xed, 0x42, 0xf4, - 0xa5, 0x76, 0xb9, 0xe4, 0xc0, 0x07, 0x38, 0x56, 0x3f, 0x82, 0xa7, 0x62, 0x85, 0x46, - 0x7d, 0xa2, 0x95, 0xc2, 0x3b, 0xa1, 0xc5, 0x87, 0xeb, 0xef, 0xaf, 0x13, 0xcd, 0x4d, - 0x50, 0xf2, 0x3c, 0xa5, 0x74, 0x3c, 0x22, 0x5c, 0x38, 0x6d, 0x46, 0xd4, 0xac, 0x70, - 0x83, 0x79, 0xef, 0x99, 0x96, 0x74, 0x4b, 0x39, 0x12, 0x04, 0x4b, 0x35, 0x5f, 0x92, - 0x7a, 0x67, 0xaf, 0x1e, 0xf2, 0x6a, 0x71, 0x7f, 0xb5, 0xa8, 0x46, 0xac, 0x9d, 0xa1, - 0x5e, 0xa3, 0xf1, 0x8f, 0x8c, 0x36, 0x18, 0x3f, 0x87, 0x9b, 0xb9, 0xa3, 0xb2, 0x98, - 0xff, 0xf9, 0xa4, 0x89, 0x64, 0x6e, 0x77, 0x8e, 0x6d, 0x67, 0x01, 0xf9, 0xad, 0xac, - 0x7a, 0xe8, 0x82, 0x09, 0xa8, 0x43, 0xba, 0x8a, 0x55, 0xd1, 0x19, 0x2b, 0xbe, 0xef, - 0x31, 0xd0, 0x71, 0x45, 0x37, 0xf7, 0xa0, 0x35, 0xb0, 0x79, 0xc6, 0xad, 0xd4, 0xab, - 0x50, 0x61, 0x2d, 0x35, 0x89, 0x7a, 0x93, 0x3d, 0x49, 0xe8, 0xef, 0x08, 0x6c, 0xdf, - 0x96, 0xc8, 0x0d, 0x28, 0x56, 0xcc, 0xc7, 0xe4, 0x5f, 0xc4, 0xef, 0xd4, 0xbf, 0x1b, - 0x98, 0xab, 0x28, 0x89, 0x1b, 0x4a, 0xea, 0x7e, 0xf8, 0x4c, 0xf7, 0x36, 0x93, 0x5c, - 0x46, 0x6b, 0x24, 0x97, 0x4d, 0xf8, 0xf5, 0x35, 0x5b, 0x8b, 0xa3, 0x20, 0xac, 0x5f, - 0xbc, 0x47, 0x5a, 0xa2, 0xcf, 0x5a, 0xd3, 0x77, 0x80, 0xbd, 0x9f, 0x9d, 0x46, 0x42, - 0xcf, 0x6c, 0x2d, 0xc6, 0xb8, 0x2f, 0x91, 0x7d, 0x09, 0xc4, 0xf7, 0x28, 0x88, 0xf9, - 0x15, 0x53, 0x44, 0x7f, 0xc5, 0x70, 0x26, 0x6d, 0xaa, 0xfd, 0x4b, 0x96, 0xcf, 0xe2, - 0xa0, 0xb0, 0x67, 0x92, 0x46, 0x9a, 0x72, 0x7d, 0xbe, 0xd0, 0x55, 0x91, 0xea, 0x60, - 0x57, 0x32, 0x20, 0x5e, 0x26, 0x05, 0x97, 0x8a, 0x3a, 0x90, 0x2c, 0x3c, 0xd6, 0x5f, - 0x94, 0x83, 0x00, 0xf7, 0x37, 0x51, 0x88, 0x15, 0xf4, 0x63, 0xd3, 0xc6, 0x1a, 0x18, - 0x9b, 0xc3, 0xbc, 0x84, 0xb0, 0x22, 0xf6, 0x3d, 0x65, 0x4f, 0x52, 0x0e, 0x3a, 0x7a, - 0xd8, 0x8e, 0x5d, 0x8d, 0xa1, 0x50, 0x14, 0xbe, 0x4b, 0xb9, 0x67, 0x99, 0x27, 0xdc, - 0x7e, 0x0f, 0xba, 0xf0, 0x58, 0xd9, 0x3f, 0x37, 0xc7, 0x2b, 0x28, 0x6b, 0x02, 0xb7, - 0x5f, 0x3c, 0xdb, 0xfb, 0x85, 0x0e, 0xed, 0x90, 0xcb, 0x23, 0x39, 0x24, 0x32, 0xeb, - 0xc3, 0x6b, 0xd2, 0x47, 0x54, 0x46, 0x9c, 0x03, 0x73, 0x1a, 0x7e, 0xbb, 0xed, 0x28, - 0x57, 0x78, 0x49, 0x81, 0xa0, 0x71, 0x67, 0x05, 0xd9, 0xcb, 0x47, 0xd9, 0x87, 0xf8, - 0x3d, 0x34, 0x21, 0xb1, 0x07, 0xd1, 0x55, 0xdb, 0xb6, 0x61, 0xed, 0x08, 0xf2, 0xfc, - 0x2e, 0x6b, 0x4a, 0x5b, 0x09, 0x77, 0x64, 0x51, 0xd8, 0x73, 0xb2, 0xfc, 0x63, 0x68, - 0x1c, 0xe3, 0x08, 0xc8, 0x08, 0xf5, 0x38, 0x8c, 0xb1, 0xaa, 0x55, 0x89, 0xa1, 0x87, - 0x73, 0xdb, 0x39, 0x07, 0xa0, 0x6b, 0xef, 0x62, 0xd1, 0x29, 0x60, 0xaa, 0xe7, 0x2a, - 0x2b, 0x89, 0x7e, 0x26, 0xb5, 0x75, 0xfd, 0x04, 0x8a, 0x57, 0x22, 0x2c, 0x7c, 0x68, - 0x0d, 0x54, 0xdc, 0x73, 0x28, 0xd0, 0xf0, 0xf2, 0xd7, 0x0b, 0x43, 0x10, 0x8c, 0xb2, - 0x0c, 0x5c, 0x31, 0x16, 0x46, 0x31, 0xb0, 0xe5, 0xb3, 0xbd, 0x31, 0xb7, 0xdf, 0x8f, - 0x4c, 0x1f, 0xe1, 0x43, 0x4f, 0xa7, 0x47, 0x56, 0x70, 0x6f, 0x83, 0x10, 0x60, 0xa5, - 0xb7, 0x03, 0xdf, 0x9c, 0xd4, 0x2e, 0x24, 0x96, 0x0e, 0x50, 0x8a, 0x04, 0x36, 0x11, - 0x8d, 0x4a, 0x92, 0x07, 0xb6, 0xd8, 0x50, 0x59, 0x6d, 0xde, 0xbe, 0x30, 0xf9, 0x28, - 0xee, 0xea, 0xe7, 0x35, 0x98, 0xfb, 0x3d, 0x86, 0x9d, 0x2d, 0x18, 0x15, 0xa9, 0xe1, - 0x4d, 0x12, 0x79, 0xf7, 0xb4, 0xb6, 0x3f, 0x4b, 0xca, 0x0f, 0x56, 0x68, 0x9b, 0xf8, - 0x73, 0x3b, 0x03, 0x06, 0x49, 0x64, 0xa4, 0xb0, 0x20, 0xb0, 0x60, 0xdc, 0xf4, 0x54, - 0x71, 0xfa, 0x1d, 0x41, 0xe5, 0xee, 0x03, 0xf9, 0xbd, 0x90, 0x65, 0x2b, 0x53, 0x72, - 0x30, 0x3a, 0x3a, 0xb9, 0xbb, 0x2e, 0xe3, 0x79, 0xb9, 0xaf, 0xcd, 0x1f, 0x6a, 0x3c, - 0xb9, 0x00, 0x0b, 0xb1, 0x4e, - ], - script_code: vec![0x53, 0x63, 0x63, 0xac, 0x63, 0x52], - transparent_input: None, - hash_type: 1, - amount: 1152393991505765, - consensus_branch_id: 1991772603, - sighash: [ - 0x58, 0x11, 0x0e, 0x23, 0x19, 0xad, 0x85, 0x50, 0x4a, 0x69, 0x8f, 0x73, 0xe7, 0xac, - 0x31, 0xa7, 0x23, 0xa0, 0x29, 0xec, 0x07, 0xb7, 0x72, 0xfb, 0xb3, 0x2f, 0xba, 0x17, - 0xff, 0xe2, 0xcc, 0x8d, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0xb5, 0xcb, 0x96, 0x49, 0x97, - 0x9e, 0x3c, 0xcf, 0x75, 0xa8, 0xda, 0xd0, 0x54, 0x60, 0x26, 0x1f, 0xcd, 0xcb, 0x00, - 0x7a, 0xeb, 0xc1, 0x5e, 0x11, 0x67, 0x5c, 0x2d, 0xb4, 0xa6, 0xcb, 0x79, 0x38, 0xe1, - 0xfe, 0xb5, 0xcd, 0x04, 0x6a, 0x65, 0x00, 0x63, 0x44, 0x1e, 0x16, 0xc7, 0x07, 0xf0, - 0x97, 0x14, 0x47, 0x4c, 0x96, 0x16, 0x0a, 0xa6, 0x8e, 0xaa, 0x12, 0x31, 0x79, 0x06, - 0x9c, 0xd2, 0x20, 0x44, 0x06, 0x26, 0xcd, 0xfe, 0xed, 0x65, 0xf9, 0xfa, 0xbd, 0xaa, - 0x6d, 0xb1, 0x76, 0x0d, 0xa5, 0xd8, 0x06, 0x63, 0x00, 0x53, 0x6a, 0x65, 0x52, 0xfd, - 0xd0, 0xd2, 0xa9, 0x01, 0xfd, 0xc8, 0x17, 0x1c, 0x9b, 0x0e, 0x06, 0x00, 0x01, 0x65, - 0x26, 0x27, 0xba, 0x0e, 0x87, 0xb5, 0xcd, 0x0f, 0xc8, 0x7b, 0xa3, 0xa2, 0x3c, 0x78, - 0x02, 0x00, 0x00, 0x02, 0x59, 0xb1, 0xb2, 0x59, 0xc5, 0xa2, 0xd8, 0xb7, 0xa6, 0x03, - 0x9b, 0x0e, 0x12, 0xac, 0xd8, 0x89, 0xb5, 0x1b, 0x47, 0x2d, 0xd5, 0x33, 0xa4, 0x61, - 0xfb, 0x0c, 0x3f, 0x96, 0xa9, 0xc0, 0x0a, 0x0b, 0x38, 0x39, 0xfa, 0x89, 0x77, 0x6f, - 0xf0, 0x98, 0xae, 0xef, 0xc7, 0x40, 0x34, 0xff, 0x8c, 0x1f, 0x0d, 0xae, 0x63, 0x68, - 0x32, 0x4c, 0xe5, 0xda, 0x68, 0xd7, 0x71, 0x35, 0x08, 0xae, 0x6d, 0x01, 0x1a, 0xd0, - 0x5f, 0xea, 0xf2, 0x03, 0x56, 0x5c, 0x71, 0xa0, 0x48, 0x66, 0x21, 0xbd, 0xc4, 0x3c, - 0x2a, 0x8e, 0xbb, 0x82, 0x61, 0xd8, 0x47, 0x42, 0x4a, 0x4c, 0xfd, 0x0d, 0xad, 0xcf, - 0x95, 0x9d, 0xb4, 0x37, 0x2b, 0x58, 0xa0, 0xde, 0x19, 0x78, 0x9c, 0x91, 0xfc, 0x99, - 0x31, 0xec, 0xbc, 0xac, 0x64, 0x19, 0xca, 0x0e, 0x5d, 0x97, 0xa3, 0xb4, 0x1c, 0x76, - 0xc8, 0xa1, 0x96, 0xc7, 0xa3, 0xad, 0xf5, 0x5b, 0xdb, 0xe6, 0x0e, 0x85, 0x59, 0x26, - 0x4b, 0x6d, 0x8e, 0xf7, 0x5d, 0x26, 0xdc, 0x72, 0x0f, 0xe5, 0xec, 0x1f, 0x59, 0x66, - 0x2d, 0x95, 0xd0, 0x8e, 0x78, 0x9e, 0x3a, 0xd1, 0x82, 0x9e, 0x40, 0x11, 0x9a, 0xa7, - 0x89, 0x7d, 0x89, 0x40, 0x4d, 0xc4, 0x96, 0x60, 0x46, 0x68, 0xf5, 0x59, 0xca, 0x67, - 0x43, 0x7d, 0x2b, 0xfb, 0xb7, 0xf5, 0x1f, 0x36, 0xe0, 0xa5, 0xb7, 0x22, 0x8f, 0x05, - 0xb6, 0xec, 0x57, 0x89, 0xc1, 0x3f, 0xc2, 0x71, 0x95, 0x56, 0x15, 0x52, 0x63, 0x96, - 0x6e, 0x81, 0xf5, 0x21, 0x51, 0xe2, 0xf6, 0xe3, 0x68, 0x69, 0xd8, 0xa3, 0xc4, 0xc4, - 0x96, 0xa5, 0x13, 0x63, 0x2c, 0xaa, 0x8a, 0xbe, 0x1f, 0x27, 0x35, 0xeb, 0x60, 0xfc, - 0x12, 0x85, 0x82, 0x8e, 0xad, 0xdc, 0x54, 0x41, 0xa4, 0x02, 0xa3, 0xbf, 0x5b, 0xcd, - 0x22, 0x7c, 0xd8, 0x04, 0xe3, 0xc8, 0xca, 0x21, 0x24, 0x3c, 0xdf, 0xcd, 0x53, 0xd8, - 0x66, 0x05, 0xf3, 0xf8, 0xaf, 0x1a, 0x9c, 0xc5, 0x69, 0x33, 0x15, 0x53, 0x28, 0x28, - 0x01, 0x43, 0xfa, 0xdb, 0x3a, 0x1f, 0xc3, 0x3d, 0x76, 0x9f, 0x07, 0xff, 0xc0, 0x1e, - 0x35, 0x79, 0xe1, 0x18, 0x1f, 0x19, 0x15, 0xdb, 0x89, 0xd8, 0x2e, 0x50, 0xbd, 0x74, - 0x24, 0x08, 0x7c, 0x79, 0x7d, 0x9b, 0x7b, 0x3b, 0x7d, 0x2a, 0x53, 0xb8, 0xff, 0xf9, - 0xf2, 0xd9, 0x28, 0xab, 0x99, 0x6d, 0xce, 0x5e, 0xd2, 0x71, 0x58, 0x98, 0xe4, 0x85, - 0x8e, 0xec, 0x60, 0x78, 0xa9, 0x48, 0x8d, 0x2d, 0xa6, 0xd1, 0x73, 0x05, 0xd0, 0xa3, - 0x47, 0x18, 0x62, 0xa2, 0x22, 0x38, 0xb9, 0xbe, 0xc2, 0x3e, 0xf2, 0xe2, 0x04, 0x1d, - 0x50, 0x08, 0x73, 0x3e, 0x9e, 0xa5, 0x66, 0x2c, 0x9f, 0xea, 0x0e, 0x4a, 0xfd, 0xf3, - 0x27, 0x0c, 0x11, 0x32, 0x3b, 0xa4, 0x8b, 0x35, 0x50, 0x85, 0x74, 0x40, 0x97, 0xf3, - 0xf6, 0xc5, 0x2e, 0xe4, 0x04, 0x31, 0x73, 0x9c, 0x5c, 0xa8, 0xdb, 0x2b, 0xda, 0x13, - 0xda, 0x9b, 0x33, 0x0b, 0x62, 0x00, 0x0b, 0x79, 0xfd, 0x35, 0x44, 0xb1, 0x31, 0x83, - 0x15, 0x9d, 0x17, 0x4f, 0xfe, 0xd2, 0x54, 0x85, 0x40, 0xa5, 0x2e, 0xe4, 0xb6, 0x2d, - 0x35, 0xaa, 0x5a, 0x58, 0x63, 0xf2, 0xba, 0xa4, 0x47, 0x5f, 0x3e, 0xb6, 0xc7, 0x35, - 0x9d, 0xc8, 0x39, 0xdb, 0xc8, 0x68, 0x90, 0xd1, 0x99, 0xd8, 0xea, 0x6c, 0x9d, 0x97, - 0xf1, 0x9e, 0x79, 0x2c, 0x7b, 0xcb, 0x66, 0x25, 0xff, 0x32, 0xb7, 0x31, 0x57, 0x5f, - 0x62, 0xd9, 0x44, 0xc8, 0x06, 0xb3, 0xf9, 0x3c, 0x04, 0xb7, 0x3a, 0x98, 0xb2, 0x73, - 0x43, 0xeb, 0x25, 0xa0, 0x6c, 0x87, 0x53, 0x60, 0xde, 0x1a, 0x14, 0x38, 0x84, 0x0a, - 0xd0, 0x66, 0x1d, 0xeb, 0xdc, 0x9b, 0x82, 0x8a, 0xd0, 0xcb, 0xc0, 0x01, 0x1b, 0x32, - 0x35, 0xb2, 0xc7, 0x53, 0x77, 0x78, 0xf4, 0x58, 0x82, 0x1b, 0x83, 0xaa, 0x4c, 0xb3, - 0xe5, 0x4e, 0xd0, 0x61, 0x3e, 0x32, 0xe6, 0x3e, 0xf9, 0x85, 0xf9, 0x35, 0xbd, 0x7f, - 0xf8, 0xc7, 0x70, 0x5c, 0x89, 0xc0, 0xbb, 0xcc, 0xda, 0x9e, 0x66, 0x5e, 0x3b, 0x06, - 0xba, 0x87, 0x9f, 0xdd, 0xf3, 0x5e, 0x0b, 0x2f, 0x60, 0xc2, 0xa7, 0x0c, 0xb8, 0xeb, - 0x9d, 0xe2, 0xf5, 0xd7, 0x38, 0xc0, 0x5e, 0x34, 0xe5, 0x0f, 0x1f, 0x26, 0x19, 0x25, - 0x8b, 0x89, 0xe5, 0x73, 0xda, 0x55, 0x75, 0x46, 0x3d, 0x2e, 0x3b, 0xce, 0x39, 0xf7, - 0x0e, 0xb4, 0x55, 0x26, 0xcd, 0x99, 0xfa, 0xd9, 0x0f, 0x97, 0x92, 0xd0, 0xcd, 0x59, - 0x3b, 0xa8, 0x6a, 0xa1, 0xae, 0xa5, 0x03, 0xdd, 0xca, 0x5e, 0x3e, 0x57, 0x37, 0xe6, - 0xfc, 0x7b, 0xab, 0x27, 0x85, 0x12, 0x69, 0x20, 0xc4, 0x47, 0xd5, 0xe5, 0x6a, 0x75, - 0xdb, 0xe8, 0x9d, 0x68, 0x8b, 0xc0, 0xda, 0xa7, 0x9a, 0xa6, 0x2d, 0xe9, 0xea, 0x29, - 0x55, 0xf7, 0x1e, 0x1a, 0x61, 0x68, 0x2a, 0x61, 0x78, 0xf8, 0x0b, 0xca, 0xda, 0x3b, - 0x97, 0xae, 0xec, 0x77, 0xd9, 0xc8, 0x56, 0x3b, 0x06, 0x9e, 0xa0, 0x13, 0x2f, 0x72, - 0x3f, 0xbe, 0x75, 0x60, 0x2d, 0xd6, 0x29, 0xac, 0x48, 0x09, 0x93, 0xd3, 0x71, 0x4f, - 0xf0, 0x2c, 0x97, 0x0e, 0xbd, 0x83, 0xe6, 0xd6, 0xcb, 0xbe, 0x39, 0x08, 0x6b, 0x03, - 0x54, 0x20, 0xe0, 0xc2, 0x75, 0x62, 0x86, 0x58, 0xa3, 0xba, 0x92, 0x30, 0x5c, 0xc0, - 0x76, 0x98, 0xf1, 0x2e, 0xe1, 0xe4, 0x17, 0x13, 0x70, 0xac, 0x39, 0xdf, 0x0e, 0x46, - 0x6d, 0xc8, 0xec, 0xc3, 0x9d, 0xa5, 0xee, 0x47, 0xb6, 0x82, 0x9d, 0xbb, 0xa9, 0x97, - 0x0f, 0x03, 0x58, 0xed, 0x68, 0x26, 0x49, 0x60, 0x5c, 0x7b, 0xfe, 0xe6, 0x93, 0x1a, - 0x29, 0x5b, 0x14, 0xa3, 0x40, 0x76, 0x00, 0x07, 0x4e, 0xdc, 0x79, 0xfa, 0x61, 0xe6, - 0x80, 0x6f, 0x11, 0x08, 0xd3, 0x34, 0xb4, 0xa5, 0x90, 0xf7, 0xa0, 0x26, 0xb0, 0xeb, - 0x02, 0x80, 0x4d, 0x39, 0x17, 0x46, 0x6e, 0x99, 0x91, 0x20, 0x64, 0x1c, 0xe0, 0x7e, - 0xbc, 0xdc, 0x99, 0x42, 0x60, 0x82, 0xe0, 0x77, 0x1f, 0x15, 0x9c, 0x82, 0x6a, 0x9b, - 0xe6, 0xce, 0xd7, 0x2d, 0x0e, 0x9c, 0xfa, 0x5b, 0x4b, 0x8a, 0x86, 0x40, 0xca, 0x34, - 0x88, 0xa1, 0xeb, 0x2b, 0x6e, 0x37, 0x4e, 0x8c, 0x2e, 0x00, 0x3c, 0xdf, 0xa2, 0x32, - 0x10, 0x37, 0x48, 0xb5, 0xc9, 0xdc, 0x11, 0xbb, 0x30, 0xf6, 0x46, 0xb9, 0x73, 0xd7, - 0x83, 0xf5, 0x99, 0x14, 0x17, 0x4e, 0x48, 0xbd, 0x6a, 0x84, 0xfa, 0xd8, 0x9d, 0xbc, - 0xa5, 0xc7, 0x6d, 0x0a, 0xb4, 0x14, 0x5a, 0xbd, 0x08, 0xe4, 0xd0, 0xf2, 0xc7, 0x60, - 0x25, 0xfc, 0x85, 0xfc, 0x11, 0x6c, 0xca, 0x8d, 0x30, 0x2c, 0x8a, 0x3b, 0xeb, 0x26, - 0x60, 0x3a, 0x1a, 0xf1, 0xb5, 0x93, 0x91, 0xea, 0xf4, 0x71, 0x75, 0x9a, 0xdf, 0x19, - 0x4c, 0x40, 0xc2, 0x09, 0x29, 0x8c, 0xc0, 0x51, 0xfc, 0x79, 0x03, 0xfe, 0x40, 0x90, - 0x2c, 0x35, 0x6f, 0x28, 0x27, 0x9f, 0x27, 0x94, 0xbb, 0xb9, 0xe0, 0x0b, 0x1e, 0x22, - 0x1b, 0x0a, 0x26, 0x41, 0x06, 0xea, 0x50, 0x4f, 0xb8, 0x90, 0x6a, 0x20, 0x84, 0x5a, - 0x05, 0x9a, 0x60, 0x3b, 0x4f, 0x00, 0xe7, 0x83, 0x6d, 0x40, 0x67, 0xa6, 0x04, 0x19, - 0x5f, 0x24, 0x6a, 0x0f, 0x3b, 0x31, 0x82, 0x3f, 0xdf, 0x69, 0x57, 0x8c, 0x47, 0xdb, - 0x5b, 0x3d, 0xda, 0x86, 0xaa, 0xb1, 0xec, 0x9f, 0x58, 0xd9, 0x62, 0x26, 0xc6, 0xb9, - 0x1d, 0xc0, 0xf0, 0x3f, 0xe8, 0xd7, 0xdf, 0x23, 0xcf, 0x53, 0xca, 0x8e, 0xa2, 0xa9, - 0x09, 0x4f, 0xc0, 0x28, 0x65, 0x26, 0x7c, 0x88, 0xfa, 0x8c, 0x01, 0x0e, 0xb5, 0x66, - 0x13, 0x06, 0x6e, 0x50, 0xf1, 0x55, 0x4a, 0xa4, 0x10, 0x8e, 0x25, 0xa9, 0xe9, 0x67, - 0xd3, 0x4a, 0x9c, 0xf1, 0x02, 0x8c, 0x17, 0x05, 0xfa, 0x37, 0x67, 0xf4, 0x6d, 0x4b, - 0xab, 0x70, 0x28, 0xb0, 0x9b, 0x20, 0x38, 0xfc, 0x1b, 0x72, 0x7f, 0x61, 0x9e, 0x61, - 0xc4, 0xfc, 0x16, 0xbf, 0xfe, 0x65, 0x7e, 0x99, 0x12, 0x6a, 0xc5, 0x18, 0x4f, 0xc8, - 0x7f, 0x5e, 0x53, 0x01, 0x88, 0x64, 0x23, 0xb3, 0x56, 0x87, 0x59, 0x09, 0xec, 0x92, - 0xb3, 0x2d, 0x33, 0x08, 0x42, 0x53, 0xa1, 0xb9, 0x7c, 0x5d, 0x2e, 0xd6, 0x6c, 0x7e, - 0x22, 0xd1, 0x85, 0x58, 0xfe, 0x82, 0xb5, 0xec, 0x88, 0xc6, 0x07, 0x05, 0x82, 0xfa, - 0xcf, 0x75, 0x6d, 0x70, 0x32, 0x38, 0xd9, 0xaf, 0x94, 0x19, 0x96, 0x6b, 0xe4, 0x62, - 0xdf, 0xbd, 0x31, 0x5c, 0x5b, 0xfa, 0xf0, 0x44, 0xaa, 0x69, 0x5a, 0x05, 0xe6, 0x9d, - 0x3d, 0x41, 0xe7, 0x73, 0x78, 0x75, 0x1d, 0x4e, 0x02, 0xc2, 0x66, 0xdf, 0xb5, 0xcb, - 0x6a, 0x7c, 0x40, 0x08, 0xf9, 0x44, 0x88, 0x83, 0x11, 0xe6, 0xde, 0x37, 0xdc, 0x7b, - 0xdf, 0x65, 0xd7, 0x0c, 0xab, 0x3e, 0x07, 0x8a, 0xb4, 0x4e, 0x23, 0x2b, 0x41, 0x1c, - 0xaf, 0xb2, 0x88, 0x4e, 0x26, 0x45, 0x95, 0xbe, 0xed, 0xf9, 0xd4, 0x9a, 0x79, 0x36, - 0xbb, 0x28, 0x7f, 0xe2, 0x8e, 0x1c, 0x29, 0x63, 0x5e, 0xae, 0xca, 0x74, 0x7d, 0x06, - 0x87, 0xcf, 0x46, 0x59, 0x02, 0xd2, 0x5f, 0x5e, 0x51, 0x58, 0x48, 0x1d, 0xaa, 0xcd, - 0xd3, 0x00, 0xb4, 0x77, 0x40, 0xbc, 0x0c, 0x62, 0x77, 0xb4, 0x47, 0xcc, 0x26, 0x64, - 0x04, 0x42, 0x43, 0xdd, 0x48, 0x11, 0x40, 0x4e, 0xcb, 0xd7, 0xc7, 0xa6, 0x3c, 0x9f, - 0xb7, 0xd9, 0x37, 0xbc, 0xd8, 0x12, 0xc2, 0x34, 0x59, 0x23, 0xb5, 0x90, 0x26, 0x83, - 0xbd, 0x2e, 0xd5, 0x4c, 0x01, 0xae, 0x04, 0x19, 0xa7, 0xf5, 0x4e, 0x8a, 0x3a, 0x59, - 0xc6, 0xa6, 0xda, 0xcf, 0x89, 0xc7, 0x37, 0x0e, 0x79, 0xb5, 0x60, 0x13, 0x6a, 0x2b, - 0x00, 0xdd, 0xb6, 0x07, 0x4d, 0x74, 0xff, 0xc5, 0xc5, 0xdf, 0xd0, 0x6b, 0x6c, 0x51, - 0x9a, 0xbe, 0xc3, 0x59, 0x6a, 0x47, 0x61, 0x13, 0xbe, 0x41, 0x38, 0xee, 0xad, 0x5f, - 0xfd, 0xe8, 0x6b, 0x1e, 0x32, 0x40, 0x1f, 0xa3, 0x84, 0x62, 0x32, 0xd0, 0xb3, 0xc9, - 0xbd, 0x56, 0x88, 0xb6, 0x4a, 0x33, 0x09, 0x38, 0x16, 0x2a, 0x8b, 0x89, 0x29, 0xd7, - 0x0c, 0x1b, 0x67, 0x53, 0x62, 0xf4, 0xc2, 0xa9, 0xbb, 0x6b, 0x7f, 0x91, 0xeb, 0xd4, - 0x7d, 0x26, 0x3c, 0xf0, 0xa4, 0x05, 0xa2, 0x8b, 0xa7, 0x41, 0x56, 0x44, 0xf9, 0x3b, - 0x6c, 0xdf, 0xa3, 0xec, 0xeb, 0xb7, 0xb8, 0xd4, 0xee, 0x8b, 0x94, 0xb2, 0x7b, 0x61, - 0xe4, 0x03, 0x5e, 0xd6, 0xa4, 0x77, 0x46, 0x7f, 0x4a, 0x32, 0x0b, 0x8a, 0x4e, 0xba, - 0x0a, 0xb5, 0x6c, 0x26, 0x3e, 0x4b, 0xfb, 0xe2, 0x6a, 0x41, 0x8e, 0xd1, 0xcd, 0xe6, - 0x18, 0x4b, 0x89, 0x50, 0xfe, 0x7a, 0xac, 0x7f, 0x20, 0xa4, 0x7b, 0xa1, 0xbf, 0xf9, - 0x80, 0x4f, 0x53, 0xf6, 0x93, 0x23, 0xdb, 0x84, 0x75, 0x20, 0xa6, 0x58, 0x47, 0xb3, - 0x03, 0x4c, 0x4e, 0x08, 0x1b, 0xb4, 0xb8, 0x69, 0x26, 0x3b, 0x5f, 0x9b, 0x3a, 0x7a, - 0x83, 0x3b, 0x6e, 0x4c, 0xa7, 0x90, 0xcc, 0xf9, 0xfd, 0xae, 0x80, 0x79, 0xe5, 0x56, - 0x09, 0x27, 0x2c, 0x63, 0xb5, 0x49, 0xb0, 0xc8, 0x5f, 0x11, 0x0c, 0xc9, 0xc9, 0x58, - 0x68, 0x01, 0x14, 0xb3, 0x11, 0x74, 0x80, 0xaf, 0x57, 0xcb, 0x15, 0x9e, 0xdf, 0xbe, - 0x5c, 0xb9, 0xc6, 0x2b, 0xce, 0x2c, 0xf2, 0xab, 0x29, 0xb6, 0x67, 0x11, 0xac, 0x7a, - 0xa5, 0x3a, 0x74, 0x9f, 0xfa, 0x83, 0x90, 0x7e, 0xcb, 0x69, 0x12, 0xaa, 0x56, 0x96, - 0x38, 0xde, 0xa1, 0x9e, 0x54, 0x41, 0x61, 0x1e, 0xfc, 0xa3, 0x20, 0x99, 0x65, 0x3e, - 0x8a, 0x5c, 0xa1, 0xfb, 0xbd, 0xba, 0xb1, 0xd6, 0x44, 0x71, 0xec, 0x32, 0x0e, 0xc3, - 0x8e, 0xa4, 0x88, 0x40, 0x0c, 0x9b, 0x1f, 0x4e, 0x8c, 0xb5, 0x48, 0x0c, 0x0e, 0x92, - 0x42, 0xb0, 0x86, 0xa8, 0x0e, 0xee, 0xd4, 0x90, 0xae, 0x32, 0x00, 0x0c, 0x80, 0x09, - 0xec, 0xb7, 0x1f, 0xfa, 0x39, 0xf4, 0xf3, 0xb5, 0x74, 0x9c, 0xfd, 0x1b, 0xef, 0xe0, - 0xd9, 0x66, 0x7a, 0xb3, 0x02, 0x20, 0xc2, 0xdc, 0x04, 0x39, 0x36, 0x98, 0xb2, 0xcf, - 0xa2, 0x04, 0x92, 0xf2, 0x50, 0xce, 0x14, 0x32, 0x35, 0x81, 0x58, 0x70, 0x3d, 0xf7, - 0xb1, 0x39, 0xd7, 0x45, 0xce, 0x1f, 0xc3, 0x40, 0x78, 0x77, 0x01, 0xfb, 0x51, 0xdd, - 0x5e, 0x48, 0xb8, 0x95, 0x09, 0x41, 0x7d, 0x88, 0x89, 0x00, 0x80, 0x63, 0xf9, 0xba, - 0x01, 0x5a, 0x07, 0xd8, 0xd3, 0x9b, 0xbd, 0x00, 0x76, 0x2f, 0x59, 0x5a, 0xfa, 0xd8, - 0xd8, 0x59, 0xea, 0xab, 0xf0, 0xd8, 0x2d, 0x46, 0x33, 0xcf, 0x82, 0x98, 0xb0, 0x9b, - 0xea, 0x3f, 0x22, 0x28, 0x55, 0xa9, 0x2a, 0x08, 0x43, 0xf5, 0x2f, 0xa5, 0x8d, 0xb3, - 0xa1, 0x75, 0xc3, 0x0d, 0x2a, 0xbe, 0x64, 0x82, 0x64, 0x90, 0xcb, 0xe6, 0xca, 0x14, - 0x88, 0xfe, 0x3a, 0x01, 0x5a, 0x94, 0x6d, 0xc9, 0xc4, 0x5a, 0xc3, 0x09, 0x25, 0x72, - 0x7a, 0x13, 0xe0, 0x89, 0x78, 0xf7, 0x24, 0x03, 0x47, 0x20, 0x8a, 0x4d, 0x25, 0x38, - 0xc2, 0xd5, 0x61, 0x24, 0x37, 0x8c, 0x22, 0xc0, 0x4e, 0x23, 0xdc, 0x28, 0xb1, 0x50, - 0x19, 0xbe, 0x77, 0x6d, 0x70, 0xbf, 0xc1, 0xd2, 0x64, 0x5b, 0x5e, 0x80, 0xd1, 0xfd, - 0x84, 0x19, 0xdf, 0x72, 0x90, 0x43, 0x80, 0xe2, 0xe1, 0xfc, 0x4d, 0xd1, 0xdf, 0x1b, - 0xa3, 0xdf, 0xe4, 0x80, 0xcc, 0x84, 0x6d, 0x51, 0x51, 0x4a, 0x06, 0x5e, 0xd7, 0x62, - 0x78, 0x7a, 0xfd, 0x6e, 0xb9, 0x0b, 0xdf, 0x8f, 0xbb, 0xad, 0x5e, 0xb3, 0xd2, 0x3f, - 0xdc, 0x8c, 0x54, 0xcc, 0xa1, 0x0f, 0xa1, 0xfe, 0x54, 0x64, 0x82, 0xf5, 0xe1, 0x42, - 0x4b, 0xfd, 0xa8, 0x7a, 0xa7, 0xfb, 0x78, 0x6e, 0x26, 0x0f, 0x26, 0x14, 0xbe, 0x08, - 0x11, 0xee, 0x16, 0xb8, 0xd2, 0x9d, 0xf9, 0xa0, 0xf3, 0x30, 0xe9, 0x70, 0x9f, 0x63, - 0xc9, 0x50, 0xfb, 0xd9, 0x03, 0xff, 0x7d, 0x5b, 0x0c, 0xa2, 0x9f, 0xd6, 0x3b, 0x0f, - 0x97, 0x51, 0x77, 0x69, 0x02, 0x5c, 0xc3, 0x6a, 0x52, 0xe0, 0x00, 0x15, 0x93, 0x4a, - 0x3c, 0xa2, 0x58, 0xb8, 0xba, 0xb9, 0x00, 0x16, 0xa4, 0x01, 0xd5, 0xd8, 0xd7, 0xc3, - 0xb9, 0x44, 0x92, 0x5b, 0x35, 0xa9, 0x34, 0x9a, 0x1a, 0xc7, 0xd9, 0x85, 0x21, 0x61, - 0x0c, 0x2f, 0xad, 0x8b, 0x5c, 0x8b, 0x31, 0x9c, 0xd6, 0xe0, 0x5f, 0x9b, 0xbe, 0xd3, - 0x53, 0xf1, 0xd0, 0xc8, 0x65, 0xa9, 0x4a, 0xa4, 0x56, 0xdc, 0xd1, 0x8a, 0x39, 0xe2, - 0xf5, 0x85, 0xd9, 0xbe, 0xa8, - ], - script_code: vec![0x63, 0x00, 0x6a, 0x53, 0x63, 0x6a, 0xac, 0x00], - transparent_input: None, - hash_type: 1, - amount: 1788797765223798, - consensus_branch_id: 1991772603, - sighash: [ - 0xcb, 0xfa, 0x22, 0x69, 0x9b, 0x04, 0xbe, 0xb7, 0x67, 0x07, 0xb5, 0x1d, 0x62, 0x5e, - 0x94, 0xd2, 0x6c, 0x0d, 0xf8, 0xad, 0xa7, 0xcf, 0x68, 0xfc, 0xde, 0xd9, 0x60, 0x65, - 0x4b, 0x20, 0xf3, 0x60, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x00, 0x02, 0x12, 0x9a, 0x03, 0xd5, - 0x7d, 0x32, 0x07, 0x00, 0x07, 0x52, 0x51, 0xac, 0x51, 0x65, 0xac, 0x00, 0x91, 0xdb, - 0xbd, 0x6f, 0xf3, 0x8f, 0x01, 0x00, 0x05, 0x53, 0x6a, 0x63, 0x63, 0x53, 0x6f, 0x34, - 0xc4, 0x99, 0x32, 0x68, 0xc7, 0x09, 0xef, 0xf1, 0x20, 0x1b, 0x50, 0x92, 0x05, 0x00, - 0x02, 0x3b, 0x5c, 0x8b, 0x5b, 0x80, 0xe7, 0x7b, 0x87, 0xf1, 0xeb, 0x73, 0xaf, 0x77, - 0x60, 0xed, 0xae, 0x0e, 0x19, 0x3e, 0x38, 0x96, 0xb1, 0x5c, 0x55, 0x8f, 0x00, 0x4e, - 0x7c, 0x7d, 0x93, 0x24, 0xd3, 0x85, 0xb4, 0x50, 0xcd, 0x4b, 0x98, 0x2a, 0xba, 0x8d, - 0x2e, 0x91, 0xf4, 0x1f, 0x22, 0xee, 0xe7, 0xf3, 0x6d, 0x79, 0xcc, 0xa9, 0xc0, 0xe0, - 0x1b, 0x26, 0xc4, 0x65, 0x11, 0x18, 0xea, 0x77, 0x15, 0x14, 0xc7, 0x7e, 0xd6, 0x0c, - 0xd5, 0x24, 0x51, 0x94, 0x2d, 0xc8, 0x5b, 0x3f, 0xba, 0x44, 0x8b, 0x2d, 0x63, 0x10, - 0xf2, 0x77, 0x79, 0x42, 0x83, 0x2e, 0x21, 0xcf, 0x3d, 0x44, 0x87, 0x4f, 0x8d, 0xca, - 0x98, 0x2b, 0x68, 0x7c, 0x9e, 0xd7, 0xe0, 0xb2, 0x32, 0x77, 0x07, 0x3c, 0x19, 0x30, - 0xa4, 0x73, 0xd1, 0x66, 0x8e, 0xf2, 0xe9, 0xae, 0x96, 0x63, 0xcf, 0xf0, 0x58, 0x16, - 0x62, 0x6c, 0xd3, 0xc5, 0xbf, 0x77, 0x16, 0x53, 0xd7, 0x78, 0x51, 0x81, 0x35, 0x5c, - 0x05, 0xae, 0xd2, 0x4a, 0x99, 0xc4, 0xb6, 0x74, 0xd2, 0x4a, 0x0f, 0x08, 0xf4, 0xb0, - 0xcf, 0xbe, 0x90, 0xf2, 0xfd, 0xba, 0xb4, 0x24, 0x82, 0xe9, 0x8f, 0x13, 0xff, 0xfc, - 0xd1, 0xad, 0x33, 0xf4, 0xf4, 0xc0, 0x4d, 0xeb, 0xc8, 0x9f, 0x40, 0xb5, 0xdb, 0xf6, - 0x45, 0x46, 0xc5, 0x20, 0xdc, 0xa5, 0xd0, 0xec, 0xf3, 0xf6, 0x5d, 0x3a, 0x77, 0xd0, - 0x12, 0x9f, 0x60, 0x03, 0x71, 0x10, 0x8a, 0xac, 0x30, 0xa9, 0xec, 0xa8, 0xbe, 0xe5, - 0x52, 0x4f, 0xab, 0x67, 0x1f, 0xc0, 0x86, 0x58, 0x76, 0x2c, 0x87, 0x38, 0xab, 0xc9, - 0xfa, 0x76, 0x93, 0xe3, 0x9d, 0x39, 0xd7, 0x03, 0xd5, 0xcd, 0x94, 0x2b, 0x5a, 0x55, - 0xfe, 0xda, 0xfe, 0xcc, 0xae, 0xf7, 0x02, 0x17, 0x69, 0xe9, 0x2c, 0xc9, 0xd3, 0xac, - 0x7b, 0x4c, 0x23, 0xb3, 0x3f, 0xc2, 0x23, 0x21, 0x85, 0x4b, 0xa3, 0x3f, 0x49, 0xee, - 0xba, 0xdd, 0xca, 0x29, 0xb3, 0x56, 0x40, 0xe4, 0xf0, 0xc2, 0xfd, 0x8c, 0x12, 0xb9, - 0x84, 0x52, 0x97, 0x60, 0xe0, 0x65, 0xfe, 0xcb, 0xa1, 0x21, 0x86, 0xd2, 0x0a, 0xee, - 0xc3, 0xda, 0x58, 0xfc, 0x35, 0x9b, 0xa8, 0x25, 0xe5, 0xb8, 0xe2, 0xe1, 0x8f, 0x12, - 0xcf, 0x29, 0x49, 0xc3, 0x12, 0xf6, 0x3c, 0x4d, 0xd7, 0xa7, 0x9b, 0x0e, 0x66, 0xb9, - 0xc8, 0xb6, 0x6f, 0xe8, 0x9a, 0xd7, 0xed, 0xc6, 0x2a, 0xc4, 0xd2, 0x07, 0xe2, 0x77, - 0xb9, 0x33, 0xb0, 0xc2, 0x06, 0xdd, 0x7c, 0x22, 0xd2, 0xdb, 0x26, 0x33, 0xfc, 0x01, - 0xa8, 0x3c, 0x24, 0xfc, 0xad, 0x40, 0x9c, 0xee, 0xd5, 0x36, 0xa6, 0xd3, 0xe8, 0xe0, - 0x8d, 0x42, 0xb5, 0x13, 0x48, 0x97, 0xb4, 0x36, 0xbf, 0xf3, 0xa1, 0xbc, 0xef, 0xc5, - 0x3a, 0xec, 0x30, 0xed, 0x89, 0x11, 0x0f, 0x89, 0x60, 0x88, 0x8a, 0x1c, 0xf2, 0x41, - 0x5c, 0xc6, 0x93, 0xa8, 0x52, 0x97, 0xd6, 0xb7, 0x89, 0x14, 0x1e, 0x04, 0x1a, 0x3c, - 0x14, 0xa5, 0xf9, 0xc6, 0x46, 0x33, 0xbe, 0x06, 0x56, 0x45, 0xe9, 0xca, 0x36, 0x37, - 0xf3, 0x73, 0x83, 0x04, 0xec, 0x3b, 0x16, 0x51, 0x31, 0x46, 0x83, 0xa0, 0x27, 0x5e, - 0x73, 0x36, 0x79, 0x70, 0x01, 0x06, 0x78, 0x23, 0x17, 0x79, 0x3e, 0x86, 0x6c, 0xed, - 0x59, 0x89, 0x21, 0x3f, 0x3b, 0xac, 0xfc, 0xfd, 0x20, 0x02, 0xea, 0x86, 0x6f, 0x3f, - 0x17, 0x07, 0x35, 0x12, 0x64, 0xb6, 0x67, 0x88, 0xf4, 0xeb, 0x7f, 0x68, 0xc5, 0xa5, - 0x36, 0xfa, 0x9c, 0x13, 0x0d, 0x20, 0x26, 0xea, 0x80, 0x97, 0x94, 0xd3, 0xb7, 0x4d, - 0x78, 0x01, 0x7e, 0xe0, 0xfb, 0xca, 0x83, 0xcc, 0x7e, 0x5c, 0xbd, 0x52, 0x7a, 0xcd, - 0xe7, 0x46, 0x53, 0x73, 0x51, 0x2c, 0x07, 0x64, 0x6a, 0x62, 0xc6, 0x0f, 0x5c, 0x16, - 0xc2, 0xef, 0x9f, 0x41, 0x8d, 0x8c, 0x7d, 0x18, 0x8f, 0x7b, 0x13, 0xdd, 0x45, 0x38, - 0xa5, 0x5d, 0x18, 0x6a, 0xd6, 0x36, 0x2a, 0x58, 0x9a, 0x9f, 0x52, 0xb2, 0x5e, 0x61, - 0x6f, 0xb2, 0xa3, 0x57, 0xac, 0xca, 0xde, 0x63, 0x57, 0xfa, 0x5a, 0x42, 0xa7, 0x98, - 0xe4, 0x17, 0x13, 0x11, 0xad, 0xe9, 0xcc, 0xfd, 0x15, 0xf2, 0x7c, 0x8c, 0x19, 0x72, - 0x17, 0x9d, 0x26, 0x1f, 0xb9, 0xb0, 0x9b, 0xc7, 0xa0, 0x36, 0xc1, 0x05, 0x55, 0x9b, - 0x04, 0x38, 0x9d, 0xfd, 0x8a, 0x7b, 0xe2, 0xa3, 0xae, 0x2b, 0xba, 0x2a, 0xfb, 0xd1, - 0xe9, 0xbf, 0x90, 0x05, 0xc8, 0xb3, 0x66, 0x35, 0x4f, 0x90, 0x9b, 0xe7, 0x1e, 0x52, - 0xc0, 0x90, 0x80, 0xfb, 0xa7, 0x45, 0x23, 0x77, 0xe8, 0xf1, 0x2c, 0x18, 0x4f, 0xe7, - 0xed, 0x46, 0x5b, 0x32, 0xc9, 0xf9, 0xb2, 0x81, 0x9e, 0xa1, 0xd1, 0x19, 0xfc, 0x26, - 0x7c, 0x8a, 0x75, 0x33, 0x81, 0xeb, 0x51, 0xac, 0xf8, 0x54, 0xc1, 0x9e, 0x8d, 0x58, - 0xff, 0x42, 0x74, 0xeb, 0xa8, 0xc6, 0x3f, 0x0f, 0xa1, 0x70, 0xa6, 0x3c, 0xbf, 0xce, - 0x2c, 0xf8, 0x7b, 0xdc, 0xdf, 0x32, 0xb7, 0xe1, 0x98, 0x04, 0x54, 0x1c, 0x2c, 0x58, - 0x97, 0x24, 0xef, 0xc6, 0x9b, 0xc4, 0x65, 0xd0, 0x90, 0x8e, 0x09, 0xb8, 0x4d, 0x1f, - 0x50, 0x41, 0x2b, 0xb0, 0x7f, 0x47, 0xfb, 0x9f, 0x0d, 0x47, 0x29, 0x28, 0x16, 0x14, - 0xca, 0xca, 0xb6, 0x14, 0xef, 0x65, 0xce, 0xba, 0x13, 0x96, 0xb5, 0x24, 0x9d, 0x2c, - 0x61, 0x70, 0x4f, 0xb6, 0xf3, 0x48, 0x44, 0x71, 0x83, 0xf9, 0x88, 0x2a, 0x98, 0xae, - 0x9c, 0x71, 0xa7, 0x66, 0x33, 0xe0, 0x5b, 0x33, 0x3a, 0x1b, 0xce, 0xee, 0xc9, 0xbd, - 0x44, 0xb8, 0x87, 0x6f, 0xab, 0x6c, 0xd7, 0x2a, 0x5e, 0x33, 0x5c, 0x97, 0x7a, 0x04, - 0x55, 0xc5, 0x36, 0x5f, 0xe8, 0x7f, 0x17, 0xa0, 0x5c, 0x0f, 0x8c, 0x23, 0x3b, 0x97, - 0x29, 0xc1, 0x09, 0x3b, 0xae, 0xb8, 0x57, 0x5c, 0xe5, 0xfd, 0xfb, 0xfd, 0x6e, 0x6a, - 0x8e, 0xbf, 0x76, 0x46, 0x47, 0x81, 0xf9, 0xb2, 0x10, 0xed, 0xb3, 0x9d, 0x20, 0x6a, - 0x68, 0x5d, 0x0d, 0xc7, 0xec, 0x06, 0x8e, 0x3c, 0x6b, 0x13, 0xd2, 0xf2, 0xaa, 0x74, - 0x11, 0x92, 0xbc, 0x86, 0x25, 0xab, 0xd3, 0x0d, 0xb6, 0xe6, 0x64, 0xfb, 0x33, 0x30, - 0xf9, 0x5c, 0xb3, 0x1b, 0xa1, 0x29, 0x0b, 0xd7, 0xf8, 0x30, 0x31, 0xc7, 0x89, 0xc2, - 0x4f, 0xd5, 0x73, 0x93, 0x46, 0x90, 0xa7, 0x3b, 0x54, 0xa9, 0x05, 0xdf, 0x8e, 0x1d, - 0x59, 0x32, 0x2f, 0x26, 0x2b, 0xbf, 0xbe, 0x95, 0xcc, 0x5b, 0x9b, 0x1e, 0x20, 0x31, - 0x0b, 0x76, 0x35, 0x0b, 0x4d, 0x60, 0x4c, 0xd1, 0xa4, 0x58, 0x66, 0x1d, 0xc4, 0x74, - 0xfe, 0x4c, 0x58, 0x79, 0x04, 0xc0, 0x53, 0x47, 0x5e, 0x17, 0x61, 0xb8, 0x0a, 0x60, - 0xcc, 0x48, 0xed, 0xd9, 0x54, 0x34, 0xdf, 0x02, 0x3b, 0x94, 0xa5, 0x8a, 0x99, 0xd6, - 0x25, 0x66, 0xe0, 0x0f, 0x67, 0x77, 0x90, 0xdc, 0xa0, 0x76, 0xa4, 0xf1, 0x67, 0x47, - 0x0c, 0x43, 0xa8, 0x1e, 0x6c, 0x32, 0xf0, 0xd0, 0x0d, 0x23, 0x65, 0x6b, 0xa7, 0x48, - 0x28, 0xb8, 0xe4, 0xd4, 0x75, 0x38, 0xe5, 0x0c, 0x0e, 0xce, 0xe2, 0xcd, 0xfe, 0x0d, - 0x59, 0x43, 0xe2, 0x3e, 0x3f, 0x17, 0x33, 0x82, 0x9d, 0x3e, 0x1b, 0x80, 0x53, 0x93, - 0x30, 0xe0, 0x6c, 0x6a, 0xe3, 0xd0, 0xec, 0xe7, 0x38, 0xc0, 0xdd, 0x74, 0x2a, 0xa5, - 0x86, 0x0f, 0x43, 0xb5, 0x30, 0xf0, 0x3d, 0xc5, 0x5d, 0xeb, 0xf7, 0x20, 0x12, 0x3f, - 0x8f, 0xba, 0xf2, 0xe5, 0x68, 0x59, 0xa5, 0x34, 0x3d, 0x46, 0x12, 0xee, 0x21, 0x46, - 0x4d, 0xb2, 0x50, 0x1d, 0x4f, 0x35, 0x31, 0x47, 0xf3, 0xe1, 0xa5, 0xab, 0xb8, 0x93, - 0x85, 0x08, 0x16, 0xc8, 0x0a, 0xf2, 0x9d, 0x88, 0x92, 0x48, 0xc9, 0x2a, 0x72, 0x9a, - 0x0e, 0x2b, 0xe2, 0xb6, 0x6c, 0xc1, 0x3a, 0xc5, 0xd9, 0x96, 0xb2, 0x50, 0x14, 0x66, - 0x6d, 0xdc, 0x63, 0x8a, 0x1f, 0xd2, 0xa0, 0xaf, 0xee, 0x93, 0xd9, 0x8e, 0x31, 0xdc, - 0x1e, 0xa8, 0x58, 0xd7, 0x2b, 0x84, 0xbb, 0xd3, 0x2f, 0xc0, 0xc6, 0x16, 0xe7, 0xd4, - 0xab, 0xda, 0xf3, 0xc1, 0x8f, 0xf9, 0x60, 0x13, 0x24, 0x5d, 0x83, 0xb3, 0xbd, 0xf9, - 0x21, 0xf4, 0x03, 0xf1, 0xae, 0xcf, 0xdd, 0xd8, 0x85, 0xfd, 0xcf, 0xc7, 0x33, 0x87, - 0x0f, 0x76, 0x0c, 0xb8, 0x7e, 0xd4, 0xfc, 0xd9, 0xcc, 0xa9, 0x33, 0x2e, 0x8e, 0x1c, - 0x85, 0x62, 0x3b, 0x20, 0x66, 0x09, 0xf8, 0x87, 0xeb, 0xdb, 0xcf, 0x9d, 0xa1, 0x0f, - 0x38, 0x14, 0x19, 0x7a, 0x9f, 0x82, 0x07, 0x05, 0xea, 0xa1, 0x28, 0x3a, 0xc7, 0x93, - 0x16, 0x83, 0x08, 0x3f, 0x22, 0xfc, 0x4d, 0xc7, 0xff, 0x68, 0x1a, 0xb8, 0x46, 0x18, - 0x6f, 0x22, 0xd5, 0x73, 0x08, 0x43, 0xde, 0x71, 0x00, 0xf0, 0x31, 0x17, 0xa3, 0xbb, - 0xa0, 0x64, 0xca, 0x3c, 0xea, 0x93, 0xf3, 0xab, 0xd3, 0x0b, 0xe6, 0xdb, 0x09, 0x35, - 0x52, 0x9d, 0xed, 0x0b, 0x50, 0xec, 0xef, 0x9f, 0x59, 0x6d, 0xb0, 0x1a, 0x87, 0xa8, - 0xda, 0xdb, 0x82, 0x7a, 0x1b, 0xe8, 0xb5, 0x79, 0x9b, 0x33, 0xc9, 0x9a, 0x82, 0x2b, - 0x73, 0xf7, 0xe6, 0x62, 0xed, 0x6f, 0x86, 0x03, 0x45, 0xa2, 0x62, 0x83, 0xc1, 0xb4, - 0x08, 0x0e, 0xcd, 0xf5, 0x79, 0xd7, 0x0e, 0x7b, 0x0c, 0x0a, 0xb7, 0x1e, 0x11, 0x6e, - 0xe2, 0xd9, 0xda, 0x27, 0x46, 0x1e, 0x28, 0x12, 0x2a, 0x09, 0xca, 0x04, 0xde, 0x38, - 0x76, 0x50, 0x2f, 0xd2, 0x4d, 0xff, 0x92, 0x09, 0x55, 0x2f, 0x91, 0x13, 0x87, 0x70, - 0x78, 0xa0, 0x94, 0xe0, 0xe5, 0xf8, 0xce, 0xbb, 0x41, 0x54, 0xe0, 0x3a, 0x6b, 0x56, - 0xf6, 0x04, 0xdf, 0x98, 0x4b, 0xd2, 0x9e, 0xfd, 0x4f, 0x88, 0xc3, 0xf6, 0x29, 0xea, - 0x2b, 0xba, 0x91, 0x27, 0xea, 0x5a, 0x6c, 0xc5, 0xa3, 0x9d, 0x74, 0x1e, 0xdd, 0x71, - 0x1a, 0x24, 0x44, 0x7f, 0xe0, 0x6c, 0xf8, 0x45, 0x5a, 0x44, 0x06, 0x5e, 0x24, 0x52, - 0x76, 0x3b, 0x0d, 0x93, 0xf8, 0x6a, 0x31, 0x47, 0xbd, 0x08, 0x75, 0x7a, 0x4f, 0x7a, - 0xa7, 0x79, 0x3c, 0x97, 0x82, 0x1c, 0x2b, 0x57, 0x22, 0xc9, 0xdb, 0xad, 0x20, 0xf6, - 0xa1, 0xe7, 0xad, 0xf6, 0x8b, 0xf2, 0x22, 0x7b, 0xe5, 0x12, 0x04, 0xe9, 0xde, 0xca, - 0x8d, 0x9e, 0xb6, 0x26, 0x6f, 0x65, 0x9b, 0x33, 0x55, 0xc8, 0x97, 0x7e, 0xae, 0x7e, - 0x9e, 0xd5, 0x39, 0xd1, 0x79, 0x39, 0xf0, 0xc6, 0x16, 0x6b, 0x01, 0x13, 0x2d, 0xb0, - 0x01, 0x66, 0x25, 0x0e, 0xa9, 0x64, 0xe3, 0x9d, 0x9d, 0x55, 0xab, 0x43, 0x9a, 0x29, - 0xbb, 0x0b, 0xcf, 0xd3, 0xa9, 0x99, 0xb3, 0x1f, 0xe7, 0xa9, 0x51, 0x00, 0x2e, 0xe5, - 0xdc, 0x01, 0x27, 0x03, 0x24, 0xb1, 0x10, 0x10, 0x37, 0x89, 0x29, 0x42, 0x90, 0x7c, - 0x6e, 0x19, 0x50, 0x9a, 0x6c, 0x5f, 0x66, 0x59, 0xba, 0xf7, 0xf4, 0x36, 0x3c, 0x49, - 0x15, 0xe6, 0x1b, 0xda, 0x34, 0x06, 0x9b, 0xd9, 0x86, 0xb6, 0x37, 0x7f, 0xf6, 0x04, - 0xed, 0xe5, 0xa7, 0x42, 0x5d, 0xb2, 0x88, 0x86, 0xb1, 0xa2, 0x61, 0x36, 0x6d, 0xa8, - 0xa1, 0x39, 0x86, 0x65, 0xbe, 0xed, 0x3b, 0xe9, 0xbc, 0x2e, 0x05, 0x5e, 0x71, 0x1b, - 0x7d, 0x36, 0xdd, 0xbd, 0xd3, 0x65, 0xcc, 0xdc, 0xd7, 0xfc, 0xba, 0xfe, 0x71, 0x29, - 0x66, 0x95, 0x08, 0xda, 0xc0, 0xad, 0x2d, 0x55, 0xee, 0x7f, 0xc6, 0x0b, 0xce, 0x22, - 0x88, 0x50, 0xba, 0x7b, 0x94, 0x3a, 0x8d, 0x50, 0xff, 0xcb, 0x2a, 0x67, 0x06, 0x51, - 0xd3, 0x15, 0xd8, 0x71, 0x9c, 0x7b, 0x57, 0xf6, 0x37, 0xa3, 0x7e, 0xdd, 0x32, 0x6a, - 0xbc, 0x76, 0xf0, 0xa7, 0x69, 0x0c, 0x23, 0x68, 0x80, 0x16, 0x01, 0x07, 0xc2, 0xb4, - 0xc8, 0x5e, 0xcf, 0x2a, 0xd9, 0xf5, 0xdd, 0x26, 0x45, 0x62, 0x6e, 0x40, 0x90, 0xf1, - 0x00, 0x47, 0xcc, 0x13, 0x15, 0x40, 0xca, 0x58, 0x03, 0x04, 0x5a, 0x6a, 0xee, 0x91, - 0xea, 0x0b, 0x3f, 0x9b, 0x77, 0xc4, 0x43, 0x40, 0x69, 0xc5, 0x32, 0x0c, 0xf5, 0xb7, - 0x01, 0x82, 0xd9, 0xfb, 0xbf, 0x30, 0x98, 0x30, 0x60, 0x11, 0x75, 0x9d, 0x0d, 0x64, - 0xa8, 0x84, 0x14, 0x1e, 0xa0, 0x21, 0xcd, 0xd9, 0x5e, 0xfa, 0x32, 0x63, 0xa5, 0x05, - 0xb8, 0x52, 0x29, 0xd1, 0x54, 0xec, 0xaa, 0x23, 0x5e, 0x8f, 0xa1, 0x07, 0x95, 0xc9, - 0xda, 0x27, 0x41, 0xcd, 0x98, 0x71, 0x90, 0x16, 0xa9, 0x01, 0x17, 0xa7, 0x6f, 0x84, - 0xf0, 0x0b, 0x5c, 0x3d, 0x4b, 0xce, 0xd7, 0x9a, 0x73, 0xbf, 0xb3, 0xa1, 0xc7, 0x8a, - 0xd1, 0xad, 0xea, 0x50, 0x78, 0xf2, 0xf1, 0xb0, 0x0f, 0x81, 0x5b, 0xc7, 0xa3, 0x0e, - 0xf8, 0x58, 0x40, 0x07, 0x77, 0x32, 0xdc, 0xb1, 0xa6, 0x1e, 0xd4, 0xbc, 0xbd, 0x66, - 0x35, 0x28, 0x50, 0x29, 0x77, 0x94, 0xad, 0x67, 0xd2, 0x93, 0xdc, 0xe9, 0x10, 0x61, - 0x13, 0x0c, 0xa4, 0x8b, 0xab, 0xca, 0xaa, 0xd6, 0x0b, 0x1f, 0x7c, 0xed, 0x07, 0xac, - 0x3f, 0xf3, 0x32, 0xd5, 0xc8, 0xd3, 0x2b, 0xa2, 0xf1, 0xe7, 0x8a, 0x23, 0xb0, 0x66, - 0x29, 0xb8, 0x89, 0x06, 0x6f, 0x07, 0x9b, 0xcd, 0xa2, 0x9f, 0xb5, 0xc8, 0x3b, 0xbb, - 0xd3, 0x7e, 0xc6, 0x17, 0x3e, 0x8a, 0x74, 0x81, 0x22, 0x12, 0x86, 0x6b, 0xcb, 0x58, - 0x80, 0x5e, 0x9e, 0x70, 0x17, 0x96, 0xa7, 0x23, 0xd5, 0x15, 0xe6, 0x15, 0x33, 0x20, - 0x0b, 0xe0, 0x6b, 0x01, 0x5f, 0xa0, 0x22, 0x35, 0xc8, 0xcb, 0xc9, 0xf3, 0x61, 0x7e, - 0xe8, 0x19, 0x5f, 0xe1, 0xbc, 0xf5, 0xbb, 0x1b, 0x63, 0x4c, 0xd4, 0x3f, 0x62, 0xea, - 0x93, 0xa4, 0x6d, 0x88, 0xf2, 0xfc, 0xbc, 0x3e, 0x28, 0x40, 0x84, 0xe7, 0x04, 0xfb, - 0x1d, 0x7d, 0x0d, 0x9a, 0xcb, 0x91, 0x96, 0x1e, 0x2e, 0xeb, 0xe2, 0xdc, 0x9e, 0xbe, - 0x36, 0x5b, 0x25, 0xb5, 0x66, 0x75, 0x97, 0x3d, 0x0c, 0x38, 0xf4, 0x76, 0x30, 0x57, - 0x47, 0x23, 0xcd, 0x3e, 0xc6, 0x6c, 0x8f, 0x3b, 0x12, 0x82, 0x21, 0xa7, 0x90, 0xd9, - 0x2c, 0x89, 0x5b, 0x94, 0x27, 0x0f, 0xe9, 0x40, 0x51, 0xa1, 0x70, 0xe9, 0x5b, 0x8b, - 0xe7, 0x16, 0x34, 0x86, 0xec, 0x8c, 0x0b, 0xee, 0xbe, 0xf6, 0x5e, 0x16, 0x26, 0xb0, - 0x46, 0xd7, 0xe7, 0xf8, 0x26, 0x37, 0x2b, 0x6a, 0xa1, 0x0b, 0xae, 0xfb, 0x84, 0x8f, - 0xa1, 0xdf, 0x6b, 0xb1, 0xdc, 0x43, 0x95, 0x40, 0xf6, 0x3c, 0x9c, 0x7a, 0x9d, 0x5f, - 0x88, 0x13, 0x40, 0x29, 0x62, 0x65, 0x1e, 0xe9, 0x84, 0x39, 0x02, 0xb6, 0xc3, 0x98, - 0x2d, 0xce, 0x50, 0xa6, 0x17, 0x8a, 0x55, 0xa1, 0xad, 0xc0, 0x1c, 0xe7, 0xdc, 0x6c, - 0x83, 0x38, 0xe1, 0xa9, 0xce, 0xef, 0xc1, 0x78, 0xdc, 0x43, 0x14, 0xf6, 0x74, 0x9a, - 0x81, 0xa7, 0x31, 0xee, 0x3c, 0x7f, 0xc0, 0xc3, 0x5d, 0x1c, 0xe3, 0x63, 0xce, 0xf1, - 0x13, 0x28, 0xf3, 0x87, 0xc4, 0x01, 0xfe, 0xf2, 0x7a, 0x67, 0xa6, 0x29, 0x2f, 0x6f, - 0x72, 0xb0, 0xa1, 0xd6, 0xc3, 0x89, 0x16, 0x2d, 0x16, 0x2e, 0xf0, 0x50, 0xae, 0x5f, - 0x3d, 0xdb, 0xb5, 0x5c, 0xaa, 0xbc, 0xa9, 0xa1, 0xbe, 0x89, 0xb4, 0x63, 0x49, 0x4d, - 0x74, 0x39, 0xfb, 0x56, 0x47, 0xa9, 0x18, 0x12, 0x8b, 0x96, 0x25, 0xd3, 0x3e, 0xac, - 0xa6, 0x19, 0xd5, 0x2f, 0x03, 0x5f, 0xe6, 0x08, 0x9c, 0xe8, 0xd8, 0xb9, 0x0f, 0xe3, - 0x67, 0x0d, 0x8c, 0x5a, 0x2e, 0x3e, 0x05, 0x49, 0x69, 0xa3, 0xd9, 0x7e, 0x61, 0xb5, - 0xe6, 0x30, 0x67, 0x4f, 0xc7, 0x08, 0x57, 0xf1, 0xbb, 0xf1, 0x0f, 0xdc, 0x40, 0x49, - 0xef, 0xf5, 0x60, 0xeb, 0xa5, 0xf2, 0x2a, 0xcc, 0x8d, 0x77, 0xdb, 0xee, 0x0b, 0x20, - 0x55, 0x7f, 0xa4, 0xd0, 0x33, 0x31, 0x72, 0xcb, 0xb5, 0xcb, 0xcc, 0x2b, 0x13, 0x5f, - 0x2c, 0xcd, 0xe0, 0x14, 0xe6, 0x3e, 0xbe, 0x4e, 0xdf, 0x92, 0x5e, 0x61, 0xba, 0x2a, - 0x32, 0x0c, 0xd3, 0x99, 0x91, 0x5a, 0xdd, 0xfc, 0xeb, 0x1a, 0xd0, 0x69, 0xa9, 0xfd, - 0x5b, 0x62, 0x10, 0xa4, 0xb6, 0xe5, 0x04, 0x52, 0xb1, 0xf9, 0x06, 0xdd, 0x16, 0xf0, - 0x16, 0x68, 0xf0, 0xaf, 0x56, 0x6a, 0x28, 0x7c, 0xce, 0xfc, 0xd8, 0x94, 0x73, 0x41, - 0x85, 0x9a, 0xe7, 0xdc, 0x3a, 0x06, 0xf6, 0xbf, 0x15, 0x74, 0xfe, 0xb9, 0x31, 0xf9, - 0x27, 0xe2, 0xd5, 0x05, 0xf6, 0x08, 0x59, 0x9e, 0x23, 0xb0, 0x5a, 0xf7, 0xc3, 0x23, - 0x69, 0x83, 0x97, 0xa8, 0x01, 0xdc, 0x7f, 0x78, 0x82, 0x5c, 0xc7, 0xeb, 0x9f, 0xcc, - 0xe6, 0xc6, 0xc4, 0xf8, 0xf6, 0x88, 0x39, 0xd3, 0x0a, 0xc5, 0x67, 0x14, 0x8e, 0x70, - 0x84, 0xdb, 0x2b, 0x37, 0x58, 0x30, 0xa0, 0x7b, 0x30, 0x5f, 0xed, 0xd6, 0x07, 0xa3, - 0x47, 0xfa, 0x65, 0xde, 0xf0, 0x1d, 0x4e, 0x1f, 0xd6, 0xc1, 0x6b, 0x4b, 0x47, 0xf5, - 0xb0, 0x1b, 0x43, 0x65, 0xb7, 0x72, 0x26, 0xe6, 0x0f, 0xdd, 0x40, 0xf2, 0x2a, 0x39, - 0x5a, 0xa2, 0x35, 0xf0, 0xdf, 0xda, 0x8f, 0xb4, 0xd3, 0xde, 0x65, 0xb0, 0xcf, 0x4f, - 0x4c, 0x22, 0x0b, 0x3b, 0x4a, 0x9e, 0x32, 0xbc, 0x0d, 0xb6, 0x4f, 0x16, 0x2c, 0x07, - 0xdf, 0x42, 0xa1, 0x01, 0x99, 0x03, 0xa6, 0x7c, 0xda, 0x69, 0x3d, 0xde, 0xb5, 0xca, - 0x39, 0xa0, 0xfe, 0x50, 0x08, 0x50, 0xec, 0x7c, 0x06, 0xbe, 0xe7, 0x18, 0x66, 0xb3, - 0x55, 0xcc, 0xbc, 0x07, 0x8c, 0xd4, 0xdc, 0x03, 0x6f, 0xda, 0xa8, 0x1c, 0xb2, 0xde, - 0x99, 0xcc, 0x88, 0xf6, 0x0a, 0x49, 0x46, 0x42, 0x87, 0xf5, 0x9f, 0xc7, 0x14, 0x8b, - 0x1a, 0xfb, 0x4a, 0x2f, 0x9b, 0xb8, 0x97, 0x14, 0xe1, 0xeb, 0x8c, 0x03, 0x61, 0xe5, - 0x99, 0x2a, 0x5b, 0x79, 0xcd, 0xbb, 0x91, 0xd9, 0xbf, 0x29, 0xeb, 0x59, 0x8c, 0xbb, - 0x4b, 0xda, 0x92, 0x3d, 0x26, 0x7f, 0xea, 0xcb, 0x91, 0xce, 0x72, 0xd6, 0x1a, 0xb1, - 0xea, 0x00, 0xf5, 0x6a, 0xa6, 0x76, 0x6e, 0xab, 0xc4, 0x7d, 0xca, 0xa6, 0x9a, 0x02, - 0x4b, 0xbf, 0xf2, 0xf2, 0x96, 0x91, 0x7f, 0x17, 0xa3, 0xf8, 0xc9, 0x3e, 0x1b, 0xf2, - 0x9c, 0x3c, 0xfc, 0x99, 0x1a, 0x2b, 0xe8, 0xcf, 0xa7, 0x0e, 0x5d, 0xe3, 0xf2, 0xdd, - 0x52, 0xa7, 0x55, 0x01, 0x38, 0x68, 0x7a, 0xec, 0x28, 0x92, 0x6f, 0xa1, 0x68, 0xb1, - 0x81, 0xdb, 0x72, 0x82, 0xbd, 0x60, 0xda, 0xd3, 0x31, 0x0d, 0xfe, 0x54, 0x2c, 0xeb, - 0xe6, 0x94, 0x74, 0x00, 0x25, 0xc7, 0xec, 0x2a, 0x20, 0x43, 0xfe, 0xbb, 0x77, 0x9f, - 0x7f, 0x37, 0x89, 0xa5, 0xe2, 0x42, 0xdb, 0x48, 0x03, 0xee, 0x36, 0x72, 0x52, 0xc4, - 0x63, 0xc9, 0xa8, 0x8b, 0x41, 0x7b, 0x70, 0x86, 0x6d, 0x9a, 0xfb, 0x7a, 0x08, 0x27, - 0x68, 0x01, 0xf9, 0x22, 0x7c, 0x63, 0x81, 0xf1, 0x5c, 0xc0, 0x94, 0xac, 0x7b, 0xd1, - 0x54, 0xa4, 0xce, 0xf9, 0x0b, 0x48, 0x47, 0xdc, 0x16, 0x8a, 0x01, 0xf1, 0xe3, 0x1e, - 0xec, 0x74, 0xa7, 0xef, 0xce, 0xba, 0x11, 0xf5, 0x07, 0x69, 0xf5, 0xd8, 0xf5, 0x4d, - 0x36, 0x20, 0xc2, 0x3e, 0xc8, 0x99, 0x3f, 0x7a, 0xef, 0x27, 0xc1, 0xd3, 0x51, 0x96, - 0xb1, 0x02, 0xb3, 0xcf, 0x3f, 0xed, 0x8b, 0xf8, 0x5d, 0x8a, 0x45, 0xf6, 0x96, 0x83, - 0xec, 0xdd, 0x1a, 0x23, 0x44, 0xef, 0xb8, 0x48, 0x07, 0xd9, 0x0f, 0x18, 0x35, 0xb4, - 0xf2, 0xf2, 0x4d, 0x8f, 0xf8, 0x12, 0x30, 0x47, 0xeb, 0x9f, 0x7d, 0x30, 0x62, 0x3e, - 0x14, 0x29, 0x0d, 0x56, 0x17, 0x96, 0x3b, 0x42, 0x21, 0x40, 0x4a, 0xe7, 0x61, 0xc8, - 0x6b, 0xec, 0x7a, 0x07, 0xbf, 0x81, 0xa0, 0xb9, 0xa7, 0xf7, 0xd0, 0x87, 0xac, 0x26, - 0xce, 0x3d, 0xfa, 0x9c, 0x93, 0xfe, 0xea, 0xeb, 0xd1, 0x0d, 0xc1, 0x88, 0xc6, 0x27, - 0xd4, 0xb9, 0x1d, 0x2a, 0x79, 0x01, 0xee, 0x5a, 0x1b, 0x38, 0x4d, 0xa3, 0x6e, 0x78, - 0x95, 0xd5, 0xb7, 0x78, 0x21, 0xfe, 0x6b, 0xca, 0xa3, 0xaf, 0xe8, 0xf2, 0x3a, 0x96, - 0x8f, 0xc9, 0xab, 0xa3, 0x7b, 0x1a, 0x4e, 0x25, 0xf5, 0xdb, 0xa1, 0xd1, 0x42, 0xff, - 0x11, 0xff, 0xd7, 0xa1, 0xba, 0x41, 0xef, 0x82, 0xc6, 0x2a, 0x95, 0x94, 0x66, 0xe7, - 0x11, 0x2a, 0xf7, 0x79, 0x6d, 0x47, 0x67, 0x12, 0x69, 0xad, 0xd3, 0xee, 0x2b, 0x17, - 0x21, 0x3e, 0xc3, 0xbd, 0x51, 0x30, 0x24, 0x4c, 0xb9, 0x07, 0x0e, 0xa8, 0xcf, 0xa4, - 0x6d, 0x44, 0xf2, 0xfc, 0xd9, 0x64, 0x06, 0x37, 0xf7, 0xde, 0xfd, 0x50, 0xb6, 0xdc, - 0x93, 0x60, 0x19, 0x45, 0xb9, 0x31, 0xe8, 0xbb, 0x72, 0x67, 0x1f, 0xe4, 0xb4, 0xb5, - 0x88, 0xc9, 0x0a, 0xd5, 0xc0, 0x0b, 0x55, 0xdc, 0x8c, 0x8a, 0xf9, 0xb0, 0xf6, 0xa3, - 0xca, 0x1e, 0x07, 0xef, 0xf1, 0x58, 0x11, 0x39, 0x1c, 0x53, 0xf7, 0xe4, 0x3b, 0x1b, - 0x81, 0x16, 0xda, 0xdc, 0x01, 0x6d, 0x19, 0x26, 0xc8, 0x48, 0x0d, 0x4e, 0xe3, 0x4e, - 0x76, 0x19, 0x1b, 0x79, 0xbe, 0xd0, 0xce, 0x95, 0x97, 0x3a, 0x4c, 0x7c, 0xf2, 0xf0, - 0x57, 0xc7, 0x14, 0x7e, 0xdb, 0x01, 0x3d, 0x20, 0x5d, 0x81, 0xe2, 0x36, 0x08, 0x88, - 0xa2, 0xab, 0xdd, 0xcc, 0xf0, 0xf6, 0xf3, 0xd8, 0xf8, 0xba, 0x11, 0x1d, 0x64, 0x2c, - 0x52, 0xd0, 0x4e, 0xbd, 0x3c, 0xe1, 0x7c, 0x60, 0xd9, 0x22, 0x57, 0xea, 0x58, 0x69, - 0x09, 0x45, 0x01, 0xbb, 0x67, 0x12, 0x68, 0xb2, 0x24, 0x47, 0x7a, 0x8e, 0x01, 0x41, - 0xd6, 0xff, 0x37, 0xe2, 0x4f, 0xf1, 0xc7, 0x65, 0xe8, 0x4d, 0x26, 0x4d, 0xb8, 0x8f, - 0x00, 0x92, 0x8e, 0x64, 0xc4, 0x12, 0xbd, 0x59, 0x15, 0x1a, 0x65, 0x71, 0xc6, 0x67, - 0x09, 0x16, 0xb0, 0x70, 0x6b, 0x04, 0x4f, 0xc5, 0xc2, 0xbd, 0x93, 0xad, 0xe3, 0x96, - 0x79, 0x57, 0xcd, 0xb9, 0x41, 0x27, 0x4c, 0xc6, 0xbd, 0xb4, 0xe0, 0x36, 0xb7, 0x67, - 0xb9, 0x50, 0xc0, 0x9e, 0x46, 0x26, 0xa1, 0xd0, 0x05, 0xbc, 0xf4, 0x83, 0x6e, 0xf6, - 0xa1, 0xde, 0x48, 0x09, 0x5d, 0xcb, 0x46, 0x12, 0x78, 0xb1, 0x6c, 0x45, 0x68, 0x90, - 0xb2, 0x3d, 0x40, 0xbd, 0x36, 0x04, 0x10, 0xf0, 0x01, 0x0a, 0x55, 0xf5, 0x05, 0xfe, - 0x5e, 0x2d, 0xb2, 0x01, 0xc7, 0x52, 0xe9, 0xb5, 0xb1, 0x5b, 0xf8, 0xaa, 0x9e, 0x82, - 0xd6, 0x49, 0xab, 0x11, 0x73, 0xba, 0x2a, 0x51, 0x32, 0xe0, 0xcc, 0x50, 0x51, 0xcc, - 0xf7, 0x4c, 0x7a, 0x6a, 0x37, 0x07, 0xab, 0x59, 0x83, 0xf7, 0xcc, 0x27, 0x5c, 0x99, - 0x1a, 0xbe, 0x4d, 0x7c, 0xee, 0x5f, 0x28, 0x9e, 0xfe, 0x72, 0x7e, 0xb3, 0xda, 0x86, - 0xfa, 0x21, 0xa2, 0x8d, 0x6b, 0x8a, 0x2a, 0xff, 0xd4, 0x2d, 0xb9, 0x8b, 0xb2, 0xa4, - 0x6c, 0xd8, 0xa3, 0x29, 0x31, 0x2f, 0xa9, 0x45, 0x39, 0xd9, 0xcb, 0x35, 0xdc, 0xb6, - 0x04, 0x67, 0x8b, 0x63, 0x90, 0x64, 0xd9, 0x20, 0x05, 0xdf, 0x2d, 0x10, 0x68, 0x1c, - 0x64, 0xb9, 0xed, 0x8c, 0xe4, 0x7d, 0x7e, 0xba, 0x0f, 0x2b, 0x50, 0x2b, 0x20, 0x6a, - 0xd4, 0xb2, 0xe9, 0x2b, 0xbe, 0x45, 0x86, 0xf6, 0xd7, 0x50, 0x9e, 0x57, 0xa6, 0x37, - 0x7f, 0xea, 0xbe, 0x38, 0xb3, 0xcc, 0x6c, 0x95, 0x5d, 0x5e, 0x7b, 0xdf, 0x7e, 0xb1, - 0x32, 0xd8, 0x6b, 0xc0, 0x7a, 0x30, 0x98, 0xb4, 0x13, 0xe4, 0x40, 0x5d, 0xaa, 0xa2, - 0x55, 0x29, 0x1d, 0x55, 0x2b, 0x2c, 0x80, 0x07, 0xbe, 0xd4, 0x1e, 0x22, 0xf1, 0xcf, - 0x79, 0x11, 0x82, 0x12, 0x00, 0x55, 0x5e, 0x9c, 0x4f, 0xfb, 0x09, 0xef, 0xc1, 0x22, - 0x38, 0x11, 0x75, 0x03, 0x1c, 0x38, 0x28, 0x0b, 0x53, 0x26, 0xeb, 0xbe, 0xaf, 0x33, - 0x4f, 0xdc, 0xf0, 0xdc, 0x44, 0x4e, 0x62, 0x9f, 0x93, 0x95, 0x51, 0x54, 0x0b, 0xcb, - 0xbb, 0xb1, 0xab, 0x9c, 0x23, 0x1a, 0x86, 0x6b, 0x32, 0x9e, 0x85, 0x24, 0xab, 0x25, - 0xf9, 0x3e, 0x5e, 0x33, 0x4a, 0x05, 0x27, 0x2a, 0x3f, 0x82, 0x6f, 0x9d, 0x05, 0xa4, - 0x50, 0x58, 0xdf, 0xcd, 0xf6, 0x88, 0x43, 0xa8, 0xb9, 0x36, 0xa0, 0xcf, 0x5e, 0x6a, - 0xa8, 0xae, 0x1b, 0x80, 0xf6, 0x01, 0x61, 0xbf, 0x41, 0x4f, 0x28, 0x02, 0x11, 0x11, - 0x09, 0x21, 0xa9, 0xc8, 0x5f, 0x51, 0x04, 0xa0, 0x16, 0x8e, 0x8e, 0x72, 0xde, 0x4f, - 0x8a, 0xa0, 0x41, 0x32, 0xeb, 0x25, 0x88, 0x76, 0xf1, 0x9d, 0x7b, 0xe5, 0xf2, 0xdd, - 0x2b, 0x0b, 0x30, 0x4b, 0x92, 0x3b, 0x29, 0x52, 0xd9, 0x1f, 0xde, 0xe7, 0xe5, 0x52, - 0x05, 0xdb, 0xb1, 0x94, 0xeb, 0xba, 0x32, 0x2f, 0xdc, 0x67, 0xb2, 0x52, 0x2c, 0x92, - 0x61, 0x21, 0xc7, 0xfa, 0x1a, 0xf1, 0x7e, 0xd0, 0x6c, 0x47, 0x27, 0x8f, 0x96, 0x08, - 0x92, 0x96, 0x08, 0x7a, 0x70, 0x4b, 0x7d, 0x0f, 0x84, 0x7d, 0x51, 0xd6, 0xcc, 0x68, - 0xac, 0xc5, 0x22, 0x07, 0x74, 0x73, 0x41, 0xf6, 0xb9, 0x8c, 0xb1, 0xcd, 0x4f, 0xaf, - 0xcd, 0x2b, 0xb0, 0xd0, 0x5b, 0xc7, 0x9b, 0xb8, 0x0d, 0x7c, 0x4b, 0x8a, 0x1a, 0x11, - 0xbc, 0x0a, 0x3b, 0xde, 0xca, 0x45, 0x41, 0x86, 0x9b, 0x4d, 0xc9, 0xd6, 0xb4, 0x8c, - 0xd7, 0x86, 0x9b, 0xf7, 0x63, 0xb9, 0xdc, 0x42, 0x45, 0x27, 0x3c, 0x70, 0x4b, 0x0d, - 0x8d, 0xec, 0x4b, 0x85, 0xd1, 0x6d, 0xd4, 0x38, 0xce, 0xd6, 0x22, 0x0f, 0xa6, 0x69, - 0x26, 0x66, 0x3f, 0xcc, 0x22, 0x8f, 0xc6, 0xc4, 0xd2, 0x7e, 0x17, 0xe3, 0x27, 0x83, - 0x4b, 0x67, 0x57, 0x91, 0x4d, 0x1b, 0xcb, 0xf3, 0x4b, 0x65, 0xd8, 0x58, 0xab, 0x8b, - 0x5c, 0x12, 0x0c, 0xb0, 0x85, 0x05, 0x22, 0xf5, 0x42, 0x89, 0x3f, 0xdd, 0xb1, 0x79, - 0xe8, 0x7f, 0x83, 0x2d, 0xaa, 0xa1, 0x52, 0xc8, 0x31, 0xf1, 0x35, 0x64, 0x00, 0x9c, - 0x41, 0x81, 0x23, 0x53, 0x3d, 0xe2, 0xc6, 0x79, 0x49, 0xe3, 0xaf, 0x2d, 0xcb, 0x60, - 0xd6, 0xbd, 0xbd, 0xda, 0xda, 0x63, 0xa3, 0x0b, 0x4b, 0x54, 0xcd, 0x1c, 0xe5, 0xa5, - 0xa0, 0x0f, 0x8e, 0x85, 0x57, 0xeb, 0xa9, 0x23, 0x4e, 0x81, 0x17, 0x8d, 0x0f, 0xca, - 0xb5, 0x61, 0x0f, 0xba, 0x96, 0x69, 0xcf, 0xeb, 0x1b, 0xd0, 0x8c, 0xd9, 0x65, 0x33, - 0x49, 0x8b, 0x27, 0x2c, 0x57, 0x79, 0xa9, 0xf9, 0x39, 0x69, 0x1d, 0xe1, 0xad, 0x88, - 0x1c, 0x80, 0x87, 0x8d, 0x6c, 0x29, 0x42, 0x15, 0x23, 0x0b, 0xbb, 0x61, 0x90, 0x69, - 0xb4, 0xdc, 0x17, 0xb3, 0xe5, 0x9d, 0xbd, 0x24, 0x2c, 0xd8, 0x8e, 0xcc, 0x3b, 0xe3, - 0xa2, 0x69, 0x6b, 0xf7, 0xf2, 0xd9, 0xe5, 0xb8, 0xc1, 0x52, 0xcc, 0x0d, 0x99, 0xa0, - 0xa5, 0xe9, 0xa3, 0x8b, 0x1b, 0x8e, 0xb1, 0xa0, 0x13, 0xeb, 0x76, 0x51, 0x33, 0x37, - 0xa7, 0xb0, 0xda, 0xdb, 0x4e, 0x81, 0x7b, 0x6f, 0x49, 0x78, 0x02, 0xbd, 0x47, 0xe9, - 0x3a, 0x82, 0x0c, 0x4f, 0xad, 0x6c, 0x65, 0x09, 0x74, 0x42, 0xb9, 0xca, 0xc1, 0x61, - 0xb6, 0x4d, 0x0f, 0xcb, 0xfb, 0xf5, 0x4f, 0xc3, 0x04, 0xc9, 0xb7, 0x0c, 0x74, 0xfb, - 0xb0, 0xd7, 0x05, 0xc7, 0x4d, 0x56, 0xac, 0xb2, 0xfe, 0x6c, 0x91, 0x74, 0xcc, 0x00, - 0xea, 0xbe, 0xa0, 0xe5, 0x97, 0x0d, 0xff, 0xe3, 0x2c, 0xb6, 0x12, 0x92, 0x05, 0x3d, - 0xb8, 0x6d, 0x36, 0x6b, 0x7e, 0x6b, 0x30, 0x13, 0xd1, 0x4b, 0x20, 0x5f, 0xb4, 0x5d, - 0x06, 0x7e, 0x37, 0x50, 0x2e, 0x37, 0x9c, 0x4a, 0xa1, 0x38, 0xbe, 0xc2, 0xc6, 0xbd, - 0x33, 0x1f, 0x58, 0xe9, 0xaa, 0x10, 0x09, 0xb0, 0x66, 0xdc, 0xe9, 0x9a, 0xcc, 0x1d, - 0xc5, 0xa6, 0x3a, 0x8f, 0x75, 0xd1, 0x98, 0x22, 0x7c, 0x2f, 0xbd, 0x20, 0xd5, 0x34, - 0xf1, 0x20, 0x30, 0xc4, 0x00, 0x99, 0xd8, 0x77, 0xca, 0xbe, 0x81, 0xb0, 0x87, 0x50, - 0xe3, 0xfb, 0xfe, 0x63, 0x12, 0xf6, 0x38, 0x0b, 0x98, 0xfb, 0x85, 0x0a, 0x2a, 0x14, - 0x2b, 0x91, 0x4a, 0xdc, 0x71, 0x54, 0x47, 0xc5, 0x79, 0x1a, 0x1b, 0x67, 0xae, 0x65, - 0x6c, 0xad, 0xdd, 0x21, 0xe1, 0xb4, 0x6d, 0xc9, 0xa7, 0x64, 0x12, 0x7b, 0xc0, 0xa3, - 0x01, 0xb4, 0x80, 0x04, 0xa9, 0xc5, 0x27, 0x6b, 0xcf, 0x08, 0xe7, 0xfe, 0x4a, 0xe5, - 0x2d, 0x76, 0xe4, 0x31, 0x48, 0x8a, 0x5b, 0x9d, 0x43, 0x1f, 0xa1, 0x36, 0x34, 0x6e, - 0x5a, 0x53, 0xab, 0x3f, 0x68, 0x12, 0xf2, 0xd9, 0x70, 0xf7, 0xb3, 0x98, 0x98, 0xcf, - 0x8b, 0x62, 0xf2, 0xdb, 0xf6, 0x1e, 0x99, 0xa2, 0x91, 0x5d, 0xfb, 0x75, 0xae, 0x22, - 0xb7, 0x9f, 0x84, 0xcf, 0x25, 0x97, 0xeb, 0x34, 0xec, 0x3d, 0x29, 0x2e, 0x6b, 0x5d, - 0x84, 0xeb, 0xac, 0x4d, 0x92, 0xde, 0x52, 0xe1, 0xf8, 0xbf, 0x6b, 0xfd, 0xba, 0xda, - 0x63, 0x44, 0x09, 0xf2, 0x0e, 0xf2, 0xcc, 0x6e, 0x3c, 0x39, 0x0e, 0x43, 0x5f, 0x47, - 0xe3, 0x47, 0x23, 0x8d, 0xb4, 0x86, 0x90, 0x84, 0x04, 0x73, 0xb0, 0xa0, 0x83, 0x1a, - 0x5a, 0x8a, 0x58, 0xc4, 0xdc, 0xfc, 0x4e, 0xab, 0x7b, 0x41, 0x8c, 0xba, 0x2a, 0x41, - 0x4f, 0x95, 0x57, 0x71, 0x90, 0xff, 0x88, 0xd7, 0x27, 0xf7, 0x3e, 0x2f, 0xff, 0x97, - 0xaa, 0xbd, 0x11, 0x14, 0xb7, 0x64, 0xe3, 0xed, 0xbc, 0x18, 0x3e, 0x60, 0x3a, 0xcf, - 0xb7, 0xc0, 0x9b, 0xf1, 0x32, 0xbb, 0x01, 0xef, 0xc7, 0x17, 0x8d, 0x4f, 0x9a, 0x2d, - 0xba, 0xf4, 0x92, 0x4f, 0xd8, 0x0f, 0xbe, 0x0e, 0x60, 0x4f, 0x60, 0x39, 0x08, 0x32, - 0xeb, 0x98, 0x04, 0x79, 0xe0, 0x4e, 0x9c, 0x9a, 0x2b, 0xb2, 0xfb, 0x36, 0x84, 0xd8, - 0xf8, 0x06, 0x48, 0xd5, 0x80, 0x78, 0x38, 0x54, 0x58, 0x4f, 0x62, 0xbe, 0x0c, 0xc9, - 0x21, 0x88, 0x32, 0x38, 0x56, 0x10, 0xd9, 0x62, 0x36, 0x5f, 0x50, 0x71, 0xfa, 0x3d, - 0x36, 0x8f, 0xfb, 0x67, 0x1b, 0xa2, 0xc2, 0xf9, 0xa0, 0xfc, 0x68, 0xd8, 0x07, 0x22, - 0x19, 0xa7, 0x7b, 0xef, 0x2d, 0x6b, 0x4a, 0x19, 0xf1, 0x6d, 0xd5, 0x30, 0x74, 0x22, - 0x47, 0x46, 0xbb, 0xa5, 0xf1, 0x72, 0x82, 0x20, 0xb1, 0x96, 0xe4, 0x0f, 0x93, 0x7c, - 0x47, 0x05, 0x42, 0x9d, 0x04, 0xaa, 0x3c, 0x50, 0x5c, 0x95, 0x60, 0x3e, 0x05, 0xff, - 0x55, 0x2e, 0xc1, 0x86, 0x42, 0xd5, 0x67, 0x05, 0x02, 0x67, 0xb9, 0xf9, 0x92, 0x9c, - 0x2e, 0x13, 0x80, 0x14, 0xb5, 0xef, 0x1b, 0xa7, 0x1d, 0x9a, 0x71, 0x86, 0xe3, 0xd1, - 0x3c, 0x8a, 0x8e, 0x40, 0x8c, 0x2a, 0x9d, 0x12, 0x01, 0xa7, 0xfe, 0xbb, 0x83, 0x34, - 0x51, 0x2b, 0x44, 0xb8, 0x2b, 0xb2, 0x01, 0x78, 0x9f, 0x63, 0x58, 0x04, 0x89, 0x6e, - 0x3e, 0xb2, 0x1b, 0x5b, 0xd8, 0xc4, 0x21, 0xf0, 0xb4, 0xcf, 0xba, 0x04, 0xde, 0x92, - 0x52, 0x8f, 0x04, 0xfb, 0x4b, 0x52, 0x6b, 0x73, 0x7e, 0xe3, 0x2d, 0xa8, 0x63, 0xf5, - 0x98, 0x45, 0x61, 0x31, 0x98, 0x3a, 0x01, 0x35, 0x8f, 0xb0, 0x7d, 0xe6, 0x75, 0x21, - 0x11, 0x58, 0x5a, 0x86, 0x25, 0x6c, 0xe0, 0x34, 0xc0, 0xd8, 0x57, 0x5a, 0x42, 0x76, - 0x13, 0x61, 0xb1, 0x18, 0x77, 0x05, 0x0b, 0xc6, 0xaf, 0xc3, 0x16, 0x15, 0x64, 0xe9, - 0x6f, 0xd8, 0xcf, 0x04, 0x8f, 0xeb, 0xeb, 0x2a, 0x92, 0x20, 0x07, 0x1c, 0xff, 0x18, - 0x2d, 0x6c, 0xa0, 0x37, 0xce, 0x2c, 0x2d, 0xed, 0x91, 0x6b, 0xd7, 0xb8, 0x4d, 0xe2, - 0x8a, 0xc0, 0x17, 0x1d, 0x97, 0xfc, 0x24, 0x95, 0x6c, 0x26, 0x66, 0x69, 0xc1, 0x03, - 0x6b, 0x2b, 0x1a, 0x23, 0xda, 0xbc, 0xf3, 0x4e, 0x38, 0xf3, 0x51, 0x45, 0x12, 0xae, - 0x8a, 0x47, 0xb3, 0x53, 0xb4, 0x16, 0x69, 0x96, 0x75, 0xe4, 0xd3, 0x1a, 0x2f, 0xe0, - 0x34, 0x08, 0xe4, 0x24, 0xa7, 0x82, 0x9a, 0x06, 0xad, 0xe6, 0x36, 0x53, 0x61, 0xd8, - 0xa9, 0x61, 0x25, 0x7c, 0xbe, 0x25, 0xb0, 0xcd, 0xe3, 0x3e, 0x96, 0x48, 0x77, 0xdf, - 0x5e, 0x57, 0xc5, 0x3d, 0xb2, 0x83, 0x51, 0x77, 0x34, 0x3e, 0x2d, 0x87, 0x6d, 0x51, - 0x4c, 0x62, 0xfb, 0xb3, 0xb4, 0xa7, 0x08, 0xce, 0x62, 0x62, 0x05, 0xcc, 0xf9, 0x2f, - 0x24, 0x0d, 0x60, 0x2c, 0xdb, 0x5d, 0x68, 0x41, 0xfd, 0x29, 0xda, 0x63, 0x08, 0xb6, - 0xca, 0x40, 0x97, 0xd8, 0x52, 0x54, 0x10, 0x46, 0x54, 0x52, 0x23, 0x9b, 0x04, 0x51, - 0xa8, 0xdb, 0xed, 0xac, 0x1e, 0x41, 0xed, 0xdd, 0x0f, 0x6b, 0xe0, 0xe3, 0xd8, 0x89, - 0x69, 0x07, 0x03, 0xa3, 0x14, 0x57, 0x07, 0xe0, 0xb3, 0xf5, 0xdb, 0x91, 0xb8, 0x19, - 0x37, 0x56, 0xe0, 0xe3, 0x47, 0xb6, 0x64, 0xa1, 0xcc, 0xcb, 0xd7, 0x86, 0x9a, 0x40, - 0x22, 0xea, 0xdf, 0x3f, 0x87, 0x3c, 0x10, 0xec, 0xab, 0x9a, 0x93, 0xf2, 0xca, 0xdc, - 0xa7, 0xa3, 0x33, 0xb8, 0x1b, 0xb6, 0x10, 0x4e, 0x82, 0xea, 0x14, 0xfe, 0x74, 0x1e, - 0xb0, 0x62, 0x08, 0x0d, 0xc8, 0x5a, 0xcb, 0xc8, 0xcc, 0x3a, 0x9b, 0xc8, 0x0c, 0x03, - 0xd9, 0x1f, 0xfb, 0x3c, 0x25, 0xf9, 0xe4, 0x2b, 0xc2, 0x5c, 0xf7, 0x7d, 0x73, 0x90, - 0xc3, 0xab, 0xaf, 0x26, 0x10, 0xf4, 0xec, 0xdb, 0x01, 0x9b, 0x15, 0x8d, 0xa2, 0x15, - 0x5b, 0xef, 0xec, 0xb9, 0xc2, 0x29, 0x6d, 0x03, 0xf8, 0x23, 0xea, 0xac, 0x0c, 0x74, - 0x0d, 0x2a, 0x44, 0x89, 0xb8, 0x28, 0x4c, 0x7e, 0x7b, 0x3a, 0x72, 0x9a, 0xfb, 0x69, - 0xbd, 0x5b, 0xfa, 0x5f, 0x62, 0xf9, 0xb5, 0x27, 0x37, 0x97, 0xdd, 0x24, 0xa0, 0x18, - 0x30, 0x7f, 0xc6, 0x20, 0xe6, 0x42, 0xaa, 0x27, 0xe7, 0x50, 0x6e, 0x17, 0xb1, 0x98, - 0xdc, 0xa4, 0x79, 0x0e, 0x8d, 0xe1, 0xbf, 0xb6, 0x71, 0xd8, 0xdc, 0x75, 0x13, 0x91, - 0x0e, 0x95, 0x43, 0x10, 0x72, 0x1b, 0x4f, 0xb5, 0x37, 0x33, 0xc9, 0x18, 0xf0, 0xd1, - 0x89, 0x85, 0x18, 0x89, 0x62, 0x73, 0x22, 0xd5, 0x20, 0xca, 0xcc, 0x9d, 0xd7, 0x03, - 0x6b, 0xb4, 0x39, 0xa1, 0x69, 0xef, 0x2c, 0xdd, 0x6c, 0xdb, 0xae, 0xa5, 0xa9, 0x1b, - 0xc2, 0x4a, 0xb3, 0xfc, 0xa1, 0x57, 0x4c, 0x12, 0xc9, 0x31, 0xe7, 0xaa, 0x02, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xd3, 0xc6, 0x49, 0x66, 0xc0, 0x6b, 0x62, 0x2d, 0x23, 0xc8, 0x8d, 0xb2, 0xfd, - 0x4b, 0x8f, 0xa5, 0x0b, 0xe3, 0x61, 0x94, 0x3b, 0x79, 0x6d, 0x14, 0x85, 0x5f, 0x20, - 0x71, 0xd3, 0x20, 0xd4, 0x3d, 0x6c, 0x49, 0x4c, 0x9e, 0xda, 0x35, 0xcf, 0x9b, 0xf3, - 0x7d, 0xc5, 0x4b, 0x40, 0x2e, 0xb2, 0x87, 0x64, 0xa0, 0xb9, 0x17, 0x6c, 0xf9, 0x49, - 0xb2, 0xa7, 0x78, 0x64, 0x19, 0x83, 0x89, 0x2f, 0xfb, 0x5c, 0x7b, 0xfa, 0x68, 0xe6, - 0x36, 0xde, 0xfe, 0xfc, 0xb2, 0xfa, 0x07, 0x94, 0x45, 0xec, 0xd3, 0xad, 0xdf, 0x0c, - 0x22, 0xb2, 0x61, 0x72, 0x49, 0x92, 0xe2, 0xf0, 0xd2, 0x7c, 0xff, 0x23, 0xa6, 0x46, - 0x15, 0x30, 0xdc, 0x05, 0xf4, 0x9e, 0x97, 0x2d, 0xa3, 0x71, 0x6f, 0x41, 0x91, 0xbf, - 0xf4, 0xed, 0x29, 0x02, 0x67, 0x46, 0xf0, 0x9e, 0xfa, 0x9d, 0xfc, 0xbc, 0xde, 0xc5, - 0xa6, 0x95, 0xb1, 0xf7, 0x31, 0x36, 0x14, 0x64, 0xec, 0x42, 0xe3, 0xb5, 0x26, 0x7e, - 0xb6, 0x5f, 0x55, 0x6b, 0x26, 0x7a, 0xf3, 0x59, 0x71, 0xb4, 0x14, 0x9b, 0xb3, 0xe5, - 0xaa, 0x03, 0xa4, 0x95, 0xfb, 0xeb, 0x90, 0x15, 0xac, 0x3f, 0xf1, 0x3a, 0x5c, 0x1c, - 0x2a, 0x5f, 0x81, 0x96, 0x47, 0x3d, 0x5b, 0xfe, 0x70, 0x48, 0xdf, 0x27, 0x7f, 0x0b, - 0x5c, 0xf4, 0xe6, 0xc7, 0x1c, 0xa9, 0x36, 0x6e, 0xca, 0x3b, 0x9c, 0xf1, 0xe6, 0x06, - 0x9d, 0x53, 0x9e, 0x5c, 0xe4, 0x3f, 0xd9, 0xaa, 0x25, 0xc2, 0x11, 0xd3, 0x79, 0x92, - 0xc3, 0x40, 0xad, 0xea, 0x8b, 0x24, 0x9f, 0x28, 0xab, 0x23, 0x49, 0x39, 0x17, 0xc4, - 0x9d, 0xeb, 0x28, 0x3b, 0x4c, 0x8a, 0x64, 0x90, 0x41, 0x88, 0x7e, 0x66, 0x83, 0x8d, - 0x1c, 0x42, 0x9d, 0xec, 0xdb, 0x31, 0x59, 0xcb, 0x30, 0xaf, 0xe4, 0xfb, 0x31, 0x68, - 0xcc, 0xec, 0x44, 0x98, 0x2e, 0x05, 0xf8, 0x71, 0x13, 0x2e, 0xfa, 0x63, 0xd6, 0x5a, - 0x24, 0x93, 0xcd, 0xf2, 0x39, 0xe8, 0xb2, 0xc8, 0x09, 0x05, 0xe8, 0x04, 0xa8, 0x4d, - 0xd7, 0x6a, 0xfe, 0xaa, 0x68, 0x94, 0x79, 0x1d, 0x49, 0xb1, 0xe4, 0x00, 0xb3, 0xfc, - 0xaa, 0x82, 0x73, 0x99, 0x60, 0xad, 0xda, 0x36, 0x45, 0xbb, 0x85, 0x75, 0x6c, 0x63, - 0x00, 0x5c, 0x01, 0x6f, 0x65, 0x8b, 0xa6, 0xab, 0x52, 0x57, 0xc4, 0x86, 0xaf, 0x13, - 0xed, 0xc9, 0xb4, 0x6b, 0xf6, 0x29, 0x34, 0xaa, 0x71, 0x4f, 0x00, 0x36, 0x05, 0x96, - 0x5a, 0xc5, 0x4d, 0x82, 0x50, 0xa5, 0x53, 0x52, 0x00, 0xd1, 0x20, 0x2a, 0xcc, 0xca, - 0xaa, 0x9e, 0x42, 0xea, 0x98, 0x2a, 0x21, 0x61, 0x8e, 0xdb, 0xb1, 0x34, 0xc3, 0x3b, - 0xc8, 0x4e, 0x35, 0xfc, 0x76, 0x56, 0x05, 0x86, 0xa3, 0xc3, 0x43, 0x8e, 0x8f, 0x2b, - 0x0c, 0xe7, 0x0d, 0x86, 0x31, 0x71, 0xdf, 0x23, 0x8e, 0x12, 0x60, 0xd5, 0x9f, 0x82, - 0x40, 0x37, 0xa7, 0x71, 0x7b, 0x2e, 0x21, 0xa9, 0x6e, 0x4d, 0x79, 0x9b, 0x8e, 0xc4, - 0xc9, 0x8b, 0x8d, 0x16, 0x83, 0x6c, 0x18, 0x22, 0xb2, 0x45, 0x62, 0x66, 0x46, 0x59, - 0x86, 0x85, 0x0d, 0x23, 0x31, 0xc7, 0x29, 0x34, 0xbd, 0xb6, 0x71, 0x54, 0xab, 0xa0, - 0xad, 0x49, 0xbe, 0x0e, 0x52, 0xd8, 0xb0, 0x78, 0x41, 0x11, 0x7c, 0x0e, 0xb7, 0x6a, - 0x39, 0x54, 0x96, 0x39, 0xf7, 0xad, 0xe7, 0x6a, 0x90, 0x71, 0x0e, 0x79, 0x83, 0x97, - 0x8e, 0x9b, 0x23, 0x34, 0x9b, 0xee, 0x22, 0xcd, 0x0c, 0x71, 0xa1, 0xf0, 0x72, 0x70, - 0xe2, 0xce, 0x8b, 0x36, 0x05, 0x1b, 0x00, 0x55, 0xba, 0x97, 0x05, 0xab, 0x22, 0x2e, - 0x8e, 0x85, 0x8d, 0xc4, 0x5b, 0x66, 0xc1, 0xef, 0x3f, 0xe2, 0x66, 0x55, 0x03, 0xe7, - 0x8b, 0x30, 0x29, 0xef, 0xfb, 0xd5, 0xbb, 0x13, 0x9e, 0x85, 0x2c, 0x3b, 0xf9, 0x07, - 0x13, 0x2e, 0x54, 0xc3, 0xed, 0xad, 0x03, 0xf7, 0xe8, 0x68, 0xf5, 0x23, 0x15, 0x5f, - 0x9f, 0x6b, 0xce, 0xf4, 0x50, 0xbc, 0x9b, 0x56, 0x31, 0x0c, 0xda, 0x17, 0x3e, 0x50, - 0xe9, 0x5a, 0x6e, 0xe5, 0xf0, 0x68, 0xb2, 0x5e, 0x32, 0x9c, 0x35, 0x48, 0xfc, 0x24, - 0x99, 0x37, 0x3c, 0xde, 0x29, 0x36, 0x0f, 0xbb, 0xfa, 0x5b, 0x64, 0xb5, 0x74, 0x4a, - 0xb0, 0x3a, 0x4b, 0xd5, 0xd9, 0x48, 0xc1, 0xbe, 0xf8, 0xcf, 0x4e, 0x6b, 0xd9, 0x4c, - 0x32, 0x80, 0x9b, 0x18, 0xf1, 0x18, 0x9c, 0x32, 0xbb, 0x8f, 0xae, 0x27, 0x53, 0xe4, - 0x85, 0x1c, 0x31, 0x96, 0xf5, 0xbb, 0x1d, 0xa0, 0x78, 0x51, 0xb5, 0xd3, 0x1f, 0x20, - 0xa0, 0xfd, 0x3a, 0x7a, 0x4b, 0x45, 0x01, 0xf3, 0x18, 0x5d, 0x26, 0x7b, 0x1c, 0x8b, - 0xb3, 0x59, 0x5d, 0x85, 0xc5, 0x3c, 0xae, 0x18, 0x9e, 0xc9, 0xdb, 0x6f, 0x14, 0x53, - 0xb3, 0xc6, 0xad, 0x4f, 0x3b, 0x93, 0xdd, 0x10, 0x6a, 0x3a, 0x39, 0x0d, 0xb2, 0x7a, - 0x1a, 0x75, 0x0e, 0x7e, 0xd0, 0x89, 0x7e, 0xbb, 0x61, 0x98, 0x48, 0x4d, 0xcc, 0xdf, - 0xa7, 0xa7, 0xe1, 0xd8, 0xeb, 0x2f, 0x23, 0x66, 0x8d, 0x54, 0xe9, 0x8f, 0x9e, 0xd3, - 0xae, 0x90, 0xfe, 0x0c, 0x27, 0x5f, 0x17, 0x7e, 0xcf, 0x70, 0x1f, 0xd3, 0x0b, 0x92, - 0xf6, 0x1b, 0x3c, 0x12, 0x53, 0xcc, 0x31, 0x78, 0x95, 0xfe, 0x5e, 0x39, 0xc4, 0xea, - 0x03, 0x24, 0x8e, 0x83, 0x20, 0x2e, 0xa5, 0x89, 0xa0, 0xe8, 0xfc, 0xaf, 0xc4, 0x34, - 0x07, 0xb5, 0x71, 0x9c, 0x08, 0x6a, 0xc2, 0xf5, 0x8c, 0x1c, 0x4e, 0x05, 0x63, 0x69, - 0x56, 0xb6, 0x30, 0x4e, 0x31, 0x7f, 0x4f, 0x65, 0xb4, 0xe2, 0xb9, 0x9f, 0x25, 0xe8, - 0xd7, 0xbb, 0x53, 0x28, 0xea, 0x1f, 0x31, 0x13, 0x25, 0x6a, 0x45, 0x08, 0x01, 0x6a, - 0x3e, 0x9d, 0x01, 0x2e, 0xf8, 0x19, 0xfa, 0x36, 0xa5, 0xdb, 0xce, 0x7e, 0x3a, 0xff, - 0x47, 0x42, 0xc0, 0xcd, 0x3d, 0x5d, 0x9e, 0xb8, 0x40, 0x44, 0xa0, 0x03, 0x23, 0x39, - 0x40, 0x69, 0x9b, 0xc2, 0x79, 0x45, 0xb9, 0xac, 0x93, 0x82, 0x23, 0xc1, 0x17, 0x3f, - 0x34, 0xd1, 0x7e, 0x7e, 0x2e, 0x7b, 0xbc, 0xad, 0x2d, 0x91, 0x9d, 0x1a, 0xf5, 0x54, - 0x94, 0x0b, 0x68, 0xd7, 0x43, 0x3a, 0x6d, 0x67, 0xe8, 0x5c, 0xd3, 0x35, 0x66, 0xb0, - 0x60, 0xe4, 0x48, 0xb4, 0xa2, 0xa0, 0x52, 0xa8, 0xb7, 0x9e, 0x27, 0x57, 0x8d, 0xce, - 0x6e, 0x09, 0x88, 0x6e, 0xf0, 0x92, 0xef, 0x09, 0x67, 0x97, 0x47, 0x8b, 0xb5, 0x4b, - 0x9a, 0xbb, 0xa5, 0xae, 0x26, 0x79, 0x9b, 0x07, 0xcd, 0xc8, 0x8c, 0x80, 0x2e, 0x6a, - 0xf5, 0xcb, 0xfd, 0x41, 0x24, 0x29, 0x57, 0x00, 0xac, 0x12, 0xd9, 0x10, 0xa0, 0x2a, - 0x74, 0xc8, 0xab, 0xd2, 0x4d, 0x39, 0x88, 0x72, 0xdd, 0x9d, 0x3a, 0xb3, 0xc5, 0x4c, - 0x63, 0xa0, 0x9e, 0x51, 0xbb, 0x51, 0x62, 0x54, 0x01, 0x03, 0xab, 0x0c, 0xae, 0xfc, - 0x6e, 0x5b, 0x88, 0x05, 0x21, 0xf4, 0x9c, 0x55, 0x93, 0xa7, 0xec, 0xe1, 0xef, 0xdc, - 0x00, 0xad, 0x96, 0xc3, 0x82, 0xfe, 0xcf, 0x0f, 0x9c, 0x1c, 0x8e, 0xcd, 0xcb, 0xc2, - 0x2e, 0x89, 0x07, 0xce, 0x99, 0xdf, 0x99, 0x4a, 0x33, 0x0a, 0x90, 0x44, 0x6d, 0xae, - 0xec, 0xab, 0x71, 0xf0, 0x02, 0x35, 0xdd, 0x70, 0x23, 0x3c, 0x43, 0x17, 0xd6, 0x4e, - 0xf6, 0xba, 0x3f, 0x65, 0x76, 0x42, 0xba, 0xad, 0x97, 0x35, 0xe5, 0x48, 0x68, 0xc1, - 0x97, 0x54, 0x56, 0x89, 0xa0, 0x57, 0x0b, 0xd4, 0x58, 0x4a, 0xad, 0xe4, 0x1a, 0x59, - 0x08, 0xb8, 0xaa, 0x33, 0x54, 0x95, 0x72, 0xc7, 0x20, 0x9f, 0x63, 0xad, 0x0b, 0x80, - 0x4c, 0x76, 0x02, 0xf4, 0x8d, 0xed, 0x66, 0x8c, 0x31, 0xa0, 0x7d, 0x76, 0x02, 0xd6, - 0xf8, 0x24, 0x29, 0xc3, 0xd2, 0xde, 0xe9, 0x2f, 0x38, 0xdb, 0x5b, 0x92, 0x03, 0xac, - 0x84, 0xd0, 0xfe, 0x14, 0xba, 0x6a, 0xc1, 0x9a, 0xaf, 0x94, 0x00, 0xf2, 0xe3, 0x58, - 0x3f, 0xb1, 0x68, 0xd3, 0x03, 0xca, 0x7a, 0x88, 0x71, 0xdd, 0xd9, 0xa2, 0x95, 0x04, - 0x1b, 0x30, 0xb8, 0x1e, 0xea, 0x1e, 0x7d, 0x82, 0x24, 0x34, 0x4b, 0xd2, 0x68, 0xa9, - 0x4a, 0x11, 0x1e, 0xa7, 0xc9, 0xb0, 0x6e, 0xc5, 0x69, 0x12, 0x45, 0x2e, 0xeb, 0x01, - 0xcf, 0x88, 0x87, 0xa3, 0xe2, 0x6e, 0x14, 0x40, 0x6f, 0xfe, 0xec, 0x4b, 0xfd, 0x7a, - 0x9f, 0xd8, 0x77, 0xce, 0x52, 0x03, 0xfe, 0x6b, 0x05, 0x8d, 0x23, 0x1e, 0xc7, 0x1a, - 0xf9, 0xca, 0x18, 0xed, 0x5c, 0x73, 0x55, 0x06, 0xd7, 0xba, 0x28, 0xee, 0x68, 0xee, - 0x66, 0x58, 0x7c, 0x99, 0x8c, 0x8f, 0xec, 0xa7, 0xae, 0x06, 0x8c, 0x8e, 0xd0, 0x79, - 0xe5, 0xa9, 0xa4, 0x36, 0x72, 0x8c, 0xce, 0xe1, 0x0c, 0x8f, 0x12, 0x6f, 0x7b, 0x2f, - 0xa0, 0xd0, 0xff, 0x91, 0xcc, 0x41, 0xee, 0x28, 0xa1, 0x96, 0x23, 0x03, 0x37, 0xc6, - 0x1f, 0x42, 0xe9, 0x52, 0x2b, 0xf6, 0xde, 0x64, 0xfc, 0x5a, 0x57, 0xe3, 0x74, 0x77, - 0x06, 0x07, 0x63, 0x0b, 0xc1, 0x96, 0xed, 0x05, 0x2d, 0xff, 0x00, 0x83, 0x61, 0xfc, - 0x59, 0xfd, 0x9c, 0x48, 0xd2, 0x62, 0xb9, 0x3a, 0xee, 0x45, 0x65, 0x2c, 0x78, 0x78, - 0x05, 0xdf, 0xac, 0xe8, 0x3d, 0x04, 0xe5, 0x24, 0x40, 0x3a, 0x25, 0xa1, 0x66, 0xa1, - 0xf4, 0x8e, 0xcc, 0x8f, 0xff, 0x84, 0x4f, 0x09, 0xde, 0x67, 0x48, 0x04, 0x52, 0xa6, - 0x78, 0x9d, 0x48, 0xb7, 0xbd, 0xbd, 0x81, 0x1f, 0x0e, 0xda, 0xda, 0xa8, 0xee, 0x8e, - 0xb9, 0x16, 0x17, 0x99, 0x2e, 0xad, 0x6f, 0x8a, 0x8b, 0x9e, 0xf4, 0xc5, 0xad, 0xb6, - 0xf2, 0x52, 0x48, 0xb2, 0x13, 0xf3, 0xd6, 0x93, 0xf6, 0x3c, 0x0d, 0x5d, 0x15, 0xab, - 0x54, 0x32, 0x88, 0x07, 0x14, 0x27, 0x35, 0x79, 0x37, 0x3c, 0x49, 0xcb, 0xf1, 0x47, - 0xf9, 0x4a, 0x84, 0xad, 0xe6, 0x48, 0x49, 0xeb, 0x5a, 0x94, 0x04, 0x40, 0x13, 0x38, - 0x96, 0xa2, 0x45, 0x55, 0xe4, 0x01, 0x55, 0x99, 0xc0, 0x46, 0xdf, 0xa6, 0xf1, 0x4a, - 0x28, 0x70, 0x53, 0x3a, 0xe4, 0x7d, 0x33, 0xff, 0x81, 0x6b, 0x8e, 0x46, 0x63, 0xf0, - 0x70, 0xc8, 0x0d, 0x8d, 0xb0, 0x1b, 0x43, 0xc6, 0x0f, 0x5f, 0xc0, 0x2c, 0x85, 0xac, - 0xf5, 0xe1, 0x06, 0xd3, 0xba, 0x71, 0xea, 0x69, 0x3b, 0xa4, 0x65, 0xdd, 0x61, 0xff, - 0x1d, 0x80, 0xfe, 0xee, 0xa1, 0xb6, 0xd5, 0xa1, 0x63, 0xd0, 0xc9, 0x62, 0x43, 0x16, - 0x36, 0xe1, 0xed, 0x62, 0x19, 0x66, 0xfe, 0x28, 0x5b, 0xc9, 0x70, 0xa2, 0x66, 0xbb, - 0x40, 0x8d, 0x4d, 0x48, 0xd5, 0x5e, 0xf7, 0x17, 0x04, 0xf5, 0xb7, 0x98, 0x62, 0xbd, - 0x80, 0x6a, 0x6a, 0x33, 0xe1, 0x13, 0xb1, 0x88, 0x32, 0xb3, 0xd5, 0x9e, 0x3a, 0x69, - 0x84, 0xe1, 0x4f, 0xd5, 0x2a, 0xc9, 0xd2, 0xbe, 0x3a, 0xea, 0xaa, 0xbf, 0x38, 0x29, - 0xcb, 0xf4, 0xdf, 0xca, 0x68, 0x03, 0xaf, 0xcd, 0x1f, 0xc4, 0xcd, 0x02, 0x44, 0xd7, - 0xb6, 0x3b, 0x4c, 0x9d, 0x4a, 0xa1, 0xa2, 0x27, 0xad, 0xda, 0x80, 0x6a, 0x46, 0x24, - 0xa0, 0x79, 0x65, 0xb9, 0xfd, 0xa1, 0x73, 0xa2, 0xd9, 0x9a, 0x62, 0x4f, 0x4a, 0x78, - 0xe9, 0xc7, 0x17, 0x63, 0x01, 0x2b, 0x77, 0xaf, 0x32, 0x6c, 0x75, 0x22, 0x6b, 0x7d, - 0xe8, 0x29, 0x74, 0x4b, 0x6d, 0x39, 0x72, 0xe4, 0x7f, 0x6a, 0x14, 0x5b, 0x81, 0x34, - 0x0d, 0x27, 0x16, 0x20, 0x1e, 0x07, 0x1e, 0x47, 0x1a, 0x85, 0x5e, 0x9c, 0xc3, 0x6d, - 0x39, 0x49, 0x97, 0x15, 0x74, 0xbf, 0x3a, 0x06, 0x0f, 0xc0, 0xd8, 0x82, 0xd0, 0xa9, - 0x86, 0x5c, 0x24, 0xe0, 0x94, 0x03, 0x17, 0x30, 0xcb, 0xe1, 0x88, 0xe6, 0xfd, 0xaf, - 0xcb, 0xba, 0xf7, 0x51, 0xbe, 0x87, 0xaf, 0x96, 0x5c, 0xd9, 0x8d, 0x99, 0x31, 0x04, - 0xca, 0x6e, 0xdd, 0x29, 0x28, 0x0c, 0xda, 0x86, 0x55, 0x67, 0xbd, 0xd4, 0xb4, 0xba, - 0x47, 0x37, 0xe6, 0x1c, 0x3f, 0x0a, 0xd8, 0x75, 0xa8, 0xde, 0xe6, 0xe6, 0xcd, 0xff, - 0x26, 0x81, 0x88, 0x08, 0xff, 0x9b, 0x2d, 0x55, 0x87, 0x95, 0xd6, 0x5d, 0x2a, 0x95, - 0xb4, 0x56, 0x56, 0x19, 0xf7, 0xb2, 0x41, 0x62, 0xcc, 0x47, 0x59, 0x9a, 0x33, 0x13, - 0x06, 0xe3, 0x65, 0x2f, 0xfb, 0xc3, 0xb3, 0xfd, 0x06, 0xc1, 0x46, 0x0c, 0x80, 0x6f, - 0x4e, 0x61, 0xbe, 0xc2, 0xa2, 0xa7, 0xb6, 0xc7, 0x96, 0xf6, 0x5d, 0xcf, 0x36, 0xa4, - 0xaf, 0xc6, 0xd8, 0x10, 0x09, 0x35, 0x21, 0x0a, 0x86, 0x38, 0x9f, 0x24, 0x9e, 0x2f, - 0x82, 0x32, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x8b, 0x33, 0x6b, 0x5f, 0x55, 0x40, 0x0b, 0x06, - 0x79, 0xba, 0x0c, 0x1e, 0xf0, 0x20, 0xc9, 0x26, 0x85, 0xa4, 0x24, 0x91, 0x79, 0x95, - 0xea, 0x63, 0xad, 0x1d, 0x5e, 0x28, 0xdd, 0x63, 0x99, 0x83, 0x82, 0xc7, 0xb3, 0x9d, - 0x26, 0xdb, 0x80, 0xb4, 0x3e, 0x32, 0x4f, 0xaf, 0x5d, 0x63, 0x60, 0x4a, 0x84, 0xf2, - 0x13, 0x5c, 0xbf, 0xf5, 0x98, 0xeb, 0x50, 0xe1, 0xd3, 0xa4, 0xb9, 0x9c, 0xd6, 0x6c, - 0x7a, 0xfd, 0xe6, 0x7f, 0xac, 0x47, 0xf0, 0x35, 0x8e, 0xc7, 0x83, 0xbe, 0x35, 0x95, - 0x47, 0x96, 0xe5, 0x97, 0x3a, 0xcf, 0xf6, 0x31, 0x98, 0xa3, 0x55, 0x94, 0x18, 0x7e, - 0xf8, 0x17, 0x00, 0x0b, 0x08, 0x88, 0x1e, 0x70, 0xe0, 0xb2, 0xcd, 0xe2, 0x31, 0x51, - 0x79, 0xc0, 0x84, 0x15, 0x51, 0xe8, 0xbd, 0x92, 0x8e, 0xb6, 0x24, 0x87, 0x6e, 0x86, - 0xb0, 0xb3, 0x3a, 0xab, 0x0c, 0xde, 0x87, 0xeb, 0x8f, 0xd4, 0x78, 0x8d, 0xe9, 0xfb, - 0x37, 0xea, 0xb3, 0xb4, 0x7f, 0xd5, 0xdf, 0xe9, 0xb3, 0x7b, 0xcb, 0xb6, 0xe1, 0xf2, - 0x25, 0xfd, 0x29, 0xab, 0x07, 0xfc, 0x9f, 0xf5, 0xa0, 0x8f, 0x48, 0x66, 0x9e, 0x1c, - 0x99, 0x68, 0xf5, 0x21, 0x7a, 0xd3, 0x45, 0x2d, 0xad, 0x04, 0x78, 0x39, 0x07, 0x44, - 0xe9, 0xd1, 0x67, 0x85, 0xcd, 0x54, 0xa5, 0x03, 0x98, 0xb0, 0x14, 0xa0, 0x7b, 0x78, - 0x45, 0x99, 0x7a, 0x5b, 0x11, 0x6b, 0xb2, 0xc2, 0xf4, 0xc4, 0xe5, 0x64, 0x6e, 0x63, - 0x08, 0x2c, 0x5e, 0x3f, 0xee, 0x50, 0x92, 0xff, 0x2f, 0xa8, 0x9a, 0xe3, 0x2a, 0xd6, - 0x99, 0x07, 0x50, 0x4d, 0x68, 0x85, 0xb5, 0xbd, 0x72, 0xc8, 0x23, 0xd4, 0xc7, 0x0d, - 0x5e, 0xd4, 0x5c, 0xb0, 0x0c, 0x3e, 0x04, 0x05, 0x89, 0x2c, 0x88, 0x83, 0x74, 0x53, - 0xfe, 0xf2, 0xef, 0xb7, 0x51, 0x37, 0xf3, 0xc2, 0xab, 0xbc, 0x35, 0x47, 0xdf, 0x86, - 0xee, 0x01, 0x36, 0xb6, 0xe8, 0x5f, 0x33, 0xc5, 0x25, 0x58, 0x3f, 0xfe, 0x27, 0xe6, - 0xff, 0x48, 0xa8, 0x0d, 0x12, 0x4e, 0xf8, 0x01, 0xd3, 0x24, 0x75, 0x4e, 0x16, 0x1d, - 0x8b, 0xd6, 0x77, 0x44, 0xdf, 0x8a, 0xc5, 0x84, 0x9b, 0x65, 0x5a, 0xcf, 0x9f, 0xa7, - 0xb2, 0xea, 0x84, 0x62, 0x1d, 0x8e, 0x4d, 0xd8, 0x57, 0x6d, 0xa7, 0x5e, 0xd1, 0xb4, - 0x8a, 0xcb, 0x91, 0x08, 0x03, 0x27, 0x3e, 0x48, 0x37, 0x73, 0xa9, 0x9d, 0x58, 0xcb, - 0x70, 0x40, 0x8f, 0x3f, 0x23, 0xa3, 0xea, 0x71, 0xd6, 0x73, 0x23, 0xb8, 0xf9, 0xfd, - 0x51, 0x93, 0xb8, 0xdb, 0x90, 0x6a, 0x18, 0x86, 0xe4, 0x26, 0xd0, 0xd3, 0x21, 0x6e, - 0x7f, 0x0f, 0x42, 0xa9, 0xaa, 0xe0, 0x0f, 0xc3, 0x79, 0x12, 0x20, 0xdb, 0xb1, 0x03, - 0x15, 0x19, 0xbc, 0x1e, 0xcc, 0xf8, 0x29, 0x8a, 0x22, 0xab, 0x20, 0x92, 0x71, 0x65, - 0xaa, 0x95, 0xd5, 0x46, 0x88, 0x83, 0x48, 0x17, 0x58, 0x3c, 0x64, 0x90, 0x28, 0x77, - 0x34, 0xea, 0x30, 0x0c, 0x38, 0x94, 0xf9, 0x9b, 0xaa, 0x29, 0xee, 0x97, 0x50, 0x9d, - 0x1c, 0x10, 0x71, 0xf2, 0x17, 0x42, 0xba, 0x67, 0x13, 0xed, 0xa0, 0x20, 0x38, 0x1e, - 0x60, 0x98, 0xb0, 0x5a, 0xde, 0x28, 0x09, 0x63, 0xb3, 0x98, 0xc0, 0x3b, 0xf4, 0xc4, - 0xe1, 0xf1, 0x9a, 0xd1, 0xad, 0xf1, 0xf0, 0xd6, 0x1f, 0xac, 0xbf, 0x99, 0x66, 0xbd, - 0xb0, 0x1f, 0xd1, 0x84, 0xb2, 0x00, 0xf8, 0x66, 0xc5, 0xd1, 0x2e, 0x3d, 0xc5, 0x7e, - 0xcf, 0x4f, 0xcd, 0x60, 0xc4, 0xa7, 0x56, 0x19, 0x1d, 0xcf, 0x50, 0xbb, 0x0f, 0x97, - 0x6f, 0x00, 0xe4, 0x36, 0x36, 0xa6, 0x83, 0x08, 0x69, 0x2f, 0x40, 0x24, 0x4c, 0x39, - 0x15, 0x34, 0x4b, 0x6f, 0x1f, 0x5e, 0xe7, 0x0e, 0x51, 0xe1, 0x2b, 0x28, 0x53, 0x85, - 0x53, 0x40, 0x3b, 0xe1, 0x49, 0x8e, 0x00, 0x75, 0xdb, 0xda, 0x3e, 0x66, 0x6d, 0x9e, - 0xbd, 0x18, 0xa1, 0x27, 0x21, 0xc9, 0x73, 0x49, 0xac, 0x10, 0xe8, 0xfa, 0x2d, 0x6a, - 0x59, 0xb2, 0x23, 0x56, 0xa7, 0x71, 0x96, 0x18, 0xaa, 0xb5, 0xc7, 0x57, 0xf8, 0x82, - 0x1e, 0xfc, 0x3e, 0x07, 0x1b, 0x75, 0xf2, 0x15, 0xb2, 0x00, 0xb7, 0xd2, 0x99, 0x98, - 0xed, 0x7a, 0xe0, 0x05, 0x7f, 0xb2, 0x32, 0x9c, 0xa9, 0x13, 0x6d, 0xd2, 0xbc, 0x51, - 0xa6, 0x59, 0x01, 0x71, 0xdf, 0xca, 0x3b, 0xcb, 0x93, 0x6b, 0x11, 0xc6, 0x3c, 0x03, - 0xbb, 0x7f, 0xce, 0x30, 0xa0, 0x5f, 0x9b, 0x6f, 0x8f, 0xf3, 0x54, 0x06, 0x04, 0x50, - 0xa3, 0x45, 0x2d, 0xa1, 0x86, 0xe9, 0x3d, 0x6c, 0x32, 0xda, 0x62, 0x72, 0xb8, 0x9b, - 0xc4, 0xd6, 0xd5, 0xe8, 0x47, 0x8f, 0x29, 0x91, 0x01, 0x98, 0x97, 0x11, 0xa9, 0xd2, - 0x20, 0x97, 0xcd, 0xb7, 0x0c, 0x15, 0x0e, 0xd2, 0x6d, 0xf4, 0x7b, 0x0c, 0xdd, 0xee, - 0x52, 0x1b, 0x4f, 0x1e, 0x98, 0x96, 0xa1, 0xb6, 0x97, 0x86, 0x53, 0xa4, 0xe3, 0x8b, - 0x0d, 0x28, 0x52, 0x6e, 0x1e, 0x3a, 0x87, 0x43, 0x5a, 0xc4, 0xfd, 0x30, 0x97, 0xaf, - 0xe3, 0x21, 0xe7, 0x2d, 0x40, 0xc4, 0x70, 0xf3, 0xb5, 0x3f, 0x5c, 0x35, 0x8d, 0x2e, - 0x53, 0x69, 0x7c, 0xaf, 0x66, 0x9d, 0xea, 0xa1, 0x1d, 0xe7, 0x7c, 0x98, 0x4a, 0x73, - 0x0e, 0x5b, 0xf7, 0xb3, 0x8e, 0xf6, 0x58, 0x9a, 0x5a, 0xa7, 0x55, 0x81, 0xbf, 0xd3, - 0xc0, 0x07, 0x8a, 0x63, 0xa3, 0x92, 0x96, 0x0e, 0xc3, 0xf2, 0xa0, 0x5c, 0x08, 0x1a, - 0x48, 0x4e, 0xb4, 0xf4, 0x25, 0xb7, 0x08, 0x36, 0x0f, 0x82, 0x85, 0x3c, 0xfd, 0x50, - 0xa0, 0x27, 0xfa, 0x92, 0x51, 0x76, 0x86, 0x96, 0xf3, 0x73, 0x5c, 0xd9, 0xed, 0xf7, - 0x9e, 0xcd, 0x4b, 0xe0, 0x8c, 0x57, 0x85, 0xc8, 0xae, 0xe7, 0x9a, 0x13, 0x23, 0x87, - 0x09, 0x94, 0x2f, 0x2c, 0xfd, 0x0f, 0x80, 0x7d, 0xaa, 0xb5, 0x0c, 0xc6, 0x13, 0x1b, - 0xab, 0x91, 0x25, 0x67, 0x36, 0x27, 0xf5, 0xe9, 0xa3, 0xd5, 0x3d, 0x99, 0xfa, 0x02, - 0x5c, 0x39, 0xfa, 0xb0, 0x9e, 0x2a, 0x21, 0x34, 0x6d, 0xc7, 0xf8, 0x60, 0xa6, 0x2d, - 0xd2, 0x10, 0x8e, 0x04, 0x41, 0x17, 0x8e, 0xf9, 0x76, 0x21, 0xae, 0xfc, 0xe8, 0x97, - 0x28, 0x10, 0xa4, 0xc7, 0xfc, 0x1b, 0x3c, 0x7e, 0xaa, 0x83, 0xd4, 0xa6, 0x2b, 0xd7, - 0x10, 0x98, 0x96, 0x11, 0xdd, 0x7e, 0x2f, 0x4b, 0xdf, 0x15, 0xd8, 0x31, 0x00, 0x60, - 0x11, 0xb4, 0x4e, 0xd9, 0x59, 0xdc, 0x61, 0xd8, 0xde, 0x52, 0x74, 0x5e, 0x30, 0x67, - 0x9c, 0xef, 0x04, 0x01, 0x3a, 0xc6, 0x15, 0x4e, 0xf0, 0x64, 0x69, 0x82, 0x38, 0x74, - 0x25, 0x21, 0x62, 0x26, 0x3f, 0x3a, 0x4b, 0xa5, 0x65, 0x7b, 0x8d, 0x0e, 0xcf, 0x03, - 0x86, 0x44, 0x1f, 0x87, 0x30, 0xd0, 0xf1, 0x4e, 0x86, 0x8a, 0x32, 0x46, 0x37, 0xb0, - 0xd3, 0x4a, 0x9d, 0x1d, 0xd6, 0xc3, 0x9f, 0x28, 0xfd, 0x9a, 0xf3, 0x50, 0xdc, 0x23, - 0x93, 0x79, 0x29, 0xe3, 0x79, 0x70, 0xf8, 0x87, 0x37, 0x01, 0xd3, 0xfa, 0x47, 0x10, - 0x10, 0xa7, 0x21, 0x40, 0x68, 0xad, 0x1b, 0x89, 0x02, 0x52, 0x26, 0x1d, 0xd9, 0x0d, - 0x89, 0xc5, 0xa6, 0xf2, 0x90, 0x4b, 0xc6, 0x16, 0xb0, 0x27, 0xd7, 0xbe, 0xc8, 0x79, - 0xb7, 0xa1, 0x78, 0x25, 0x4f, 0xdc, 0xaa, 0x99, 0x1b, 0x42, 0x2b, 0x7a, 0x96, 0x93, - 0xe7, 0x64, 0xa1, 0x27, 0xb1, 0x72, 0xa0, 0xdc, 0xca, 0xc4, 0x4f, 0x15, 0x27, 0x08, - 0x6c, 0x48, 0x89, 0x85, 0xf9, 0x23, 0x5e, 0x28, 0x82, 0xb4, 0x78, 0x16, 0x44, 0xeb, - 0xa9, 0xed, 0x09, 0x61, 0xca, 0x7a, 0x68, 0x45, 0xb5, 0x73, 0x65, 0xd8, 0x75, 0x4b, - 0xdc, 0x79, 0x1f, 0x81, 0xc8, 0x09, 0xd0, 0x12, 0xbd, 0x32, 0x9b, 0x6a, 0x44, 0xbd, - 0x3d, 0xfa, 0x34, 0x73, 0x5c, 0xe4, 0xc7, 0x38, 0xed, 0xef, 0xa4, 0x2d, 0x3c, 0x74, - 0x09, 0x2b, 0x5c, 0xba, 0x9c, 0x35, 0x81, 0x57, 0xd2, 0xab, 0x8a, 0x68, 0x83, 0x04, - 0x0f, 0x40, 0xce, 0xc7, 0x98, 0xa6, 0x9d, 0x7e, 0x0e, 0xa3, 0xb4, 0x76, 0xd9, 0x93, - 0xd6, 0x96, 0xdb, 0x0a, 0xdd, 0xd5, 0x43, 0x3f, 0x9e, 0x7a, 0x0f, 0xfb, 0xe0, 0x24, - 0x26, 0x1e, 0x79, 0x8d, 0xad, 0x05, 0x8e, 0xc8, 0xde, 0x26, 0x7c, 0x94, 0x78, 0xc8, - 0x01, 0xff, 0x37, 0x1e, 0x41, 0xc0, 0xbc, 0x0c, 0xf4, 0x6a, 0x4a, 0x84, 0xd0, 0xac, - 0xa4, 0x73, 0xe8, 0x80, 0xde, 0x96, 0x29, 0x69, 0xe9, 0xde, 0x23, 0x99, 0xa2, 0x99, - 0x56, 0x80, 0xdd, 0x76, 0x8f, 0xd7, 0x6b, 0xc6, 0x89, 0x6f, 0xe0, 0x2a, 0xa4, 0x82, - 0xf7, 0x6c, 0x72, 0x52, 0xe6, 0x65, 0x04, 0xe8, 0x80, 0xd2, 0x76, 0xbf, 0x7d, 0x55, - 0x7b, 0x39, 0x6a, 0xde, 0x3b, 0xb4, 0x7a, 0x6b, 0x0e, 0x0d, 0xcf, 0x06, 0x3b, 0x1a, - 0xd8, 0x56, 0x69, 0x4f, 0x8e, 0xef, 0x54, 0xca, 0x7d, 0xf4, 0x2b, 0x41, 0xf9, 0xc6, - 0x15, 0x3e, 0xa7, 0x47, 0x1c, 0xd5, 0x4f, 0x90, 0x54, 0x7c, 0xc4, 0xd4, 0xef, 0x5f, - 0xb1, 0xbf, 0xe5, 0x82, 0x88, 0x22, 0x59, 0xc7, 0x77, 0xef, 0xc4, 0xeb, 0x8f, 0x5d, - 0x75, 0x53, 0x1c, 0x1b, 0x80, 0x1b, 0x72, 0x12, 0xc6, 0xf1, 0x45, 0x09, 0x78, 0x40, - 0x20, 0xcb, 0xc3, 0xb0, 0x0e, 0xb5, 0x31, 0xc5, 0x62, 0x44, 0x36, 0x89, 0x28, 0xa8, - 0x51, 0xae, 0x53, 0x7c, 0x74, 0x80, 0xee, 0x6e, 0x45, 0x1b, 0x29, 0x74, 0x32, 0xee, - 0x17, 0x58, 0x22, 0x99, 0x50, 0xcf, 0x78, 0x08, 0x49, 0x32, 0x6c, 0x3f, 0x28, 0xdd, - 0x53, 0xd6, 0x81, 0x19, 0xd2, 0x96, 0x95, 0x50, 0x12, 0xa2, 0x6f, 0x83, 0x3c, 0xdd, - 0x29, 0xc6, 0xf4, 0xc7, 0x16, 0xf1, 0xd3, 0x37, 0xd3, 0xf4, 0xd2, 0x1c, 0x7a, 0x63, - 0xf8, 0x54, 0xc9, 0xf4, 0xc1, 0xc4, 0xcc, 0xf1, 0x81, 0xad, 0x43, 0x16, 0xca, 0xb1, - 0x36, 0x46, 0x7c, 0x01, 0xd9, 0x6d, 0x36, 0xe2, 0x98, 0x1c, 0x86, 0xc4, 0x76, 0x56, - 0x7d, 0x83, 0x77, 0x6b, 0x73, 0x37, 0x35, 0xd5, 0x65, 0x8a, 0x48, 0xf9, 0x89, 0x7c, - 0xf1, 0xe5, 0x05, 0x2b, 0x37, 0xec, 0x1c, 0x88, 0x91, 0x47, 0x36, 0xd9, 0xf9, 0x7c, - 0x54, 0x99, 0xd7, 0x3d, 0x92, 0x3b, 0x45, 0x00, 0x69, 0x4f, 0xfa, 0x57, 0x35, 0xc9, - 0x3c, 0xdb, 0x87, 0xb3, 0x5d, 0x82, 0x95, 0x49, 0xb1, 0xc6, 0x38, 0x3e, 0x95, 0xfd, - 0x19, 0x02, 0xad, 0x29, 0x80, 0xf2, 0xa3, 0xa2, 0x48, 0x3a, 0xce, 0x74, 0xb7, 0x64, - 0x3d, 0x8e, 0xae, 0x8d, 0x07, 0x9a, 0xa0, 0x06, 0x75, 0x41, 0x00, 0x6b, 0x94, 0xa6, - 0xf9, 0x13, 0xdc, 0xff, 0x13, 0xd6, 0x7c, 0xd9, 0xa8, 0xcf, 0xdf, 0x30, 0xb0, 0xc3, - 0xd1, 0x5a, 0xaa, 0x47, 0x0b, 0x3f, 0x89, 0x56, 0x10, 0x51, 0x42, 0xfa, 0x26, 0x11, - 0xfe, 0xda, 0xa4, 0x3f, 0xac, 0xbb, 0x3f, 0x05, 0x96, 0xf6, 0x78, 0x87, 0xcd, 0xee, - 0x91, 0x42, 0xc5, 0x09, 0x0a, 0x84, 0xe6, 0x25, 0x29, 0x31, 0xff, 0xcf, 0x61, 0xa5, - 0x0a, 0x4b, 0x92, 0x85, 0x30, 0x60, 0xe8, 0xb8, 0x7e, 0x10, 0xce, 0xa8, 0xce, 0x00, - 0xe4, 0x66, 0x5e, 0x5f, 0x93, 0x1f, 0x0e, 0x08, 0xdc, 0x52, 0x47, 0xbe, 0x1a, 0xed, - 0xc7, 0x9e, 0xbb, 0x7c, 0x20, 0x16, 0x2f, 0xca, 0x7b, 0xf9, 0x0e, 0x58, 0x83, 0x02, - 0x5f, 0xc9, 0x24, 0x36, 0x8d, 0x42, 0x45, 0x0b, 0x4f, 0xb7, 0xa7, 0xe1, 0x91, 0x0e, - 0xdd, 0x8d, 0x29, 0x5f, 0x03, 0xd4, 0xde, 0x03, 0xde, 0x60, 0x51, 0xd1, 0xfc, 0xf2, - 0x87, 0xf5, 0x4f, 0x38, 0x24, 0x41, 0xdd, 0xe0, 0x0c, 0xb6, 0x83, 0xa4, 0x04, 0x8c, - 0xe5, 0x4d, 0x42, 0x20, 0x90, 0x57, 0x24, 0xb3, 0x09, 0xc7, 0x99, 0x92, 0x4b, 0x85, - 0x4a, 0xfa, 0x37, 0x7b, 0x80, 0x1a, 0x03, 0x52, 0xfc, 0x44, 0x50, 0xb3, 0x35, 0x27, - 0x7a, 0xda, 0xd7, 0x61, 0xe4, 0x8a, 0x1d, 0x1d, 0xd3, 0x78, 0x93, 0x6a, 0x49, 0x1e, - 0x28, 0x6c, 0xaf, 0xc7, 0x00, 0xb4, 0x8e, 0xdf, 0x15, 0xf1, 0xc2, 0xd6, 0xed, 0xf1, - 0xa2, 0x4e, 0x0e, 0x51, 0xb3, 0x98, 0x55, 0x64, 0xeb, 0xa9, 0x69, 0xcd, 0x6e, 0xe6, - 0x59, 0xba, 0xae, 0xf7, 0x46, 0xe1, 0x3a, 0xba, 0x64, 0xaf, 0xad, 0x58, 0xaf, 0x52, - 0xf4, 0x28, 0x17, 0x36, 0x45, 0x75, 0x7a, 0x40, 0x7e, 0x1f, 0xdf, 0xd9, 0x89, 0x38, - 0x0c, 0x02, 0xbc, 0xc3, 0xc3, 0x7f, 0x48, 0x90, 0xc0, 0x8e, 0xb9, 0x31, 0x62, 0xcf, - 0x78, 0xbc, 0x3c, 0x74, 0x53, 0xf3, 0xf9, 0x92, 0xa7, 0x94, 0x53, 0x4c, 0x07, 0xe3, - 0x96, 0x8d, 0x82, 0x70, 0xaa, 0x19, 0x1f, 0x67, 0x80, 0x0a, 0x0b, 0xb3, 0xe7, 0xbf, - 0xa5, 0x4b, 0x0f, 0x6f, 0xa5, 0x3e, 0xe8, 0xfb, 0x13, 0x69, 0x82, 0xce, 0x71, 0xf4, - 0x08, 0x64, 0xb5, 0x4d, 0x00, 0x45, 0x1a, 0xf3, 0xf5, 0x32, 0x74, 0x22, 0x42, 0x16, - 0x06, 0xea, 0x10, 0xc0, 0xd6, 0x12, 0x7c, 0x02, 0xf9, 0x1a, 0xd3, 0xae, 0xb9, 0xff, - 0xd6, 0x11, 0x12, 0x25, 0x14, 0x14, 0x48, 0xbe, 0x82, 0x40, 0xc4, 0x29, 0x73, 0xac, - 0x52, 0xd7, 0x1b, 0x01, 0x2f, 0xe8, 0xef, 0x41, 0xf0, 0x0e, 0xc1, 0x96, 0xc7, 0x57, - 0x89, 0x9e, 0xf8, 0xc0, 0x0e, 0xf8, 0xdf, 0x44, 0x5c, 0x56, 0x54, 0x69, 0xd8, 0x4b, - 0xd0, 0x2c, 0x7f, 0xc4, 0x1b, 0xfc, 0xdf, 0x98, 0x95, 0x1f, 0x50, 0xe8, 0x3f, 0x19, - 0xa0, 0x00, 0xa9, 0xe4, 0x53, 0xf6, 0x21, 0x67, 0xe7, 0x35, 0x0f, 0x92, 0x36, 0x08, - 0x31, 0xbd, 0x7c, 0x52, 0x22, 0xb6, 0x70, 0x61, 0x6e, 0x4b, 0x6c, 0xa8, 0xa2, 0x35, - 0x50, 0xca, 0xd8, 0xac, 0x0d, 0xdb, 0x76, 0x45, 0xe2, 0xb9, 0x71, 0x3b, 0xe7, - ], - script_code: vec![0x6a, 0x00, 0x00, 0x65, 0x53, 0xac, 0x63, 0x53, 0x63], - transparent_input: None, - hash_type: 1, - amount: 1871432121379810, - consensus_branch_id: 1991772603, - sighash: [ - 0x36, 0x77, 0xa9, 0x48, 0x4f, 0x04, 0x04, 0xfb, 0x50, 0x64, 0x58, 0x56, 0xf4, 0xd4, - 0xa7, 0x0b, 0x2e, 0x2b, 0x1c, 0x2d, 0x86, 0x2f, 0x1d, 0x4e, 0xf6, 0x8d, 0x52, 0x09, - 0x60, 0xa1, 0x2a, 0x2b, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0xa0, 0x1e, 0x64, 0x49, 0xae, - 0x43, 0x5c, 0x24, 0xbe, 0x7b, 0x9d, 0x28, 0x8a, 0xd7, 0x57, 0x12, 0xc9, 0x2a, 0xa5, - 0x06, 0x18, 0xdf, 0xba, 0x18, 0xe8, 0x4e, 0x88, 0xd4, 0x60, 0x68, 0xdf, 0x0b, 0x42, - 0xaf, 0x89, 0x29, 0x07, 0x00, 0x6a, 0x52, 0xac, 0x65, 0x51, 0x63, 0x6e, 0x99, 0x51, - 0xd0, 0x09, 0xa9, 0x39, 0xf7, 0x59, 0xa8, 0xa2, 0xc0, 0x49, 0xde, 0xf0, 0x97, 0x7f, - 0x61, 0xea, 0x11, 0x23, 0x14, 0x06, 0xcd, 0x10, 0x95, 0x6d, 0x16, 0x55, 0x78, 0xbb, - 0x29, 0xe4, 0x76, 0x96, 0x76, 0x9a, 0x58, 0x0e, 0x07, 0x01, 0x00, 0x15, 0xaf, 0x3b, - 0x50, 0x00, 0x13, 0x58, 0xd0, 0x37, 0xe5, 0x70, 0xfe, 0x0b, 0x50, 0x0e, 0xe2, 0x99, - 0x8c, 0xdf, 0x06, 0x00, 0x03, 0x7e, 0x28, 0x30, 0x34, 0x34, 0x96, 0x2f, 0x03, 0x92, - 0x48, 0x3d, 0xec, 0xad, 0x2f, 0x9f, 0x4e, 0xbc, 0x99, 0x05, 0x4b, 0xbc, 0xf1, 0x55, - 0xff, 0xae, 0x67, 0x76, 0x34, 0xc3, 0xfb, 0x98, 0x0d, 0xc5, 0xe8, 0xec, 0x67, 0xa4, - 0x65, 0x7e, 0x80, 0xa2, 0x9a, 0x79, 0x6f, 0x39, 0x62, 0xae, 0x0c, 0xb9, 0xc7, 0x86, - 0x82, 0xb3, 0xf4, 0xf9, 0x2e, 0x5a, 0x1e, 0xd1, 0xda, 0x2b, 0xbf, 0xc1, 0x71, 0x07, - 0x7e, 0xef, 0x83, 0x65, 0xbb, 0x38, 0xce, 0x94, 0xca, 0xb0, 0x28, 0x33, 0xce, 0x47, - 0xd4, 0xa0, 0x98, 0x65, 0x72, 0x94, 0xec, 0x10, 0xb2, 0x99, 0x74, 0x22, 0x22, 0xd0, - 0xbf, 0x74, 0x3f, 0x40, 0xc8, 0xea, 0x97, 0x14, 0x32, 0x5c, 0x8a, 0x37, 0x05, 0x08, - 0x24, 0xfa, 0x75, 0x62, 0xd2, 0xc9, 0x25, 0x2c, 0x34, 0xa9, 0x84, 0x50, 0x27, 0xd6, - 0x63, 0x90, 0xe9, 0x56, 0xb2, 0x5e, 0x16, 0x6c, 0x44, 0x95, 0xd3, 0xde, 0xd3, 0xf7, - 0xac, 0xcf, 0x74, 0x76, 0x38, 0x99, 0x47, 0x35, 0x11, 0x34, 0x12, 0x98, 0xfe, 0xb1, - 0x89, 0xb7, 0xed, 0x34, 0xe5, 0x67, 0xd7, 0x2f, 0x1d, 0xf4, 0xbf, 0x69, 0x7f, 0x71, - 0x46, 0x49, 0x3f, 0xa5, 0xc2, 0x36, 0x91, 0x22, 0x7b, 0x90, 0xb2, 0x51, 0x22, 0xc5, - 0x40, 0xdf, 0x0a, 0x6f, 0x2e, 0xc0, 0x6f, 0x9d, 0x89, 0xa3, 0xf7, 0x71, 0xe9, 0xb8, - 0xed, 0x74, 0x79, 0x40, 0x85, 0x51, 0x06, 0xd5, 0xea, 0x71, 0xba, 0x89, 0xe8, 0xf2, - 0x0c, 0xde, 0xa6, 0x9a, 0x77, 0x8a, 0x59, 0xe4, 0xdf, 0x79, 0x28, 0xc0, 0x35, 0x56, - 0x23, 0x31, 0xc8, 0xe1, 0x62, 0xb8, 0xfd, 0x5e, 0xbb, 0xd5, 0xe2, 0xb3, 0x7b, 0xea, - 0x7a, 0xf0, 0x69, 0x07, 0x10, 0x40, 0xc3, 0x7c, 0x1a, 0x1c, 0x37, 0xf0, 0x76, 0x0f, - 0xed, 0x7d, 0xb7, 0xfa, 0x70, 0xa9, 0x48, 0x94, 0x03, 0x00, 0x45, 0x76, 0xa2, 0xcc, - 0xe9, 0x0a, 0x39, 0x4b, 0x5e, 0xc5, 0x8b, 0x2e, 0x5d, 0x0e, 0x1a, 0xf8, 0xb0, 0x29, - 0x6d, 0x0b, 0xf0, 0x2c, 0x55, 0x97, 0xa4, 0x33, 0x54, 0x14, 0x43, 0x35, 0xe0, 0x6a, - 0x80, 0x1c, 0x6e, 0x7c, 0x73, 0x29, 0x7d, 0xfe, 0x0b, 0x32, 0xfc, 0xb8, 0x75, 0x33, - 0x81, 0x71, 0xdd, 0x1e, 0xeb, 0xeb, 0x12, 0x3f, 0xea, 0xfa, 0x32, 0xa5, 0xd8, 0xc7, - 0xce, 0x58, 0x39, 0x0e, 0xa2, 0xdf, 0x26, 0xc6, 0x88, 0x88, 0xda, 0xf3, 0x81, 0x6b, - 0x7d, 0x02, 0x97, 0xa1, 0x7b, 0x5f, 0x5d, 0x20, 0x8d, 0xe9, 0x22, 0xe7, 0x73, 0x97, - 0x2b, 0x95, 0xe6, 0x96, 0x5e, 0x58, 0xfb, 0xf6, 0x4f, 0xae, 0x06, 0xf0, 0xc3, 0x89, - 0x6e, 0x0b, 0x57, 0x89, 0x0d, 0xd7, 0xf3, 0xc6, 0x4c, 0x3d, 0x5c, 0xeb, 0xb6, 0xa7, - 0x44, 0xc5, 0x93, 0x38, 0x61, 0x22, 0x71, 0x82, 0x08, 0x04, 0x95, 0xce, 0x9a, 0xc2, - 0xe1, 0x73, 0x09, 0x9c, 0xdc, 0x35, 0x8d, 0xa8, 0x7d, 0xd7, 0x4a, 0x77, 0x34, 0xff, - 0xff, 0xc4, 0x5f, 0xb6, 0xad, 0x1f, 0x38, 0x9c, 0x6a, 0x4d, 0x49, 0x86, 0x62, 0x64, - 0x60, 0x56, 0x08, 0x4d, 0x09, 0xb7, 0x84, 0x88, 0xa3, 0xba, 0x1d, 0x8a, 0x3d, 0x6b, - 0x48, 0x9a, 0xfd, 0xf2, 0x32, 0xd6, 0xd0, 0x70, 0xa1, 0xb5, 0x06, 0x0c, 0xaa, 0x44, - 0x3d, 0x0c, 0x7e, 0xe5, 0x19, 0x04, 0x54, 0x7f, 0xaf, 0x53, 0x95, 0xcb, 0xd0, 0xba, - 0x99, 0x48, 0x0a, 0xd0, 0x4a, 0xe0, 0xe1, 0x91, 0x5b, 0xd7, 0x7f, 0xa2, 0x6d, 0x04, - 0x17, 0x5b, 0x00, 0xfd, 0xc8, 0x1e, 0xf6, 0xf3, 0x79, 0x23, 0x72, 0x49, 0x27, 0xf0, - 0x82, 0x66, 0xb6, 0x86, 0x40, 0x93, 0x13, 0xdc, 0x13, 0xbc, 0x39, 0x9d, 0x19, 0x77, - 0xb8, 0xf6, 0x58, 0x8c, 0x0e, 0x08, 0x72, 0x10, 0xf0, 0x51, 0xcf, 0x6e, 0x36, 0xe1, - 0x4e, 0x32, 0xaa, 0x23, 0xba, 0x6a, 0xe4, 0x33, 0x1f, 0x22, 0x39, 0xe7, 0x05, 0xf6, - 0x79, 0x54, 0x2f, 0xbd, 0x4e, 0xd2, 0xbf, 0x31, 0x91, 0x24, 0x36, 0x81, 0xf8, 0x27, - 0x89, 0x6b, 0x1b, 0xb1, 0xc4, 0xb7, 0x8b, 0x34, 0xc4, 0x87, 0xa4, 0xed, 0xfa, 0x97, - 0xd3, 0x6d, 0x62, 0xee, 0x32, 0x49, 0xef, 0xe0, 0x94, 0xc3, 0x87, 0x8a, 0xde, 0xdf, - 0x9f, 0x2b, 0x17, 0xd5, 0x11, 0x99, 0x80, 0x4f, 0x42, 0x9c, 0xd7, 0x04, 0xa7, 0xc8, - 0x6c, 0x85, 0x0c, 0xe1, 0x5d, 0x3c, 0x5f, 0x01, 0xd1, 0xad, 0x17, 0xeb, 0xb6, 0xc2, - 0x88, 0x3f, 0x28, 0xe8, 0x15, 0xbc, 0x45, 0x2a, 0x56, 0x07, 0x98, 0x05, 0xa5, 0xdd, - 0x69, 0x00, 0xe5, 0x5f, 0x47, 0x7e, 0xca, 0xc2, 0x14, 0x3f, 0x02, 0xee, 0x98, 0xc8, - 0xd9, 0xb1, 0xb7, 0x03, 0x93, 0xa1, 0x70, 0xba, 0x25, 0x48, 0x06, 0xb4, 0x08, 0x5b, - 0x8d, 0xf9, 0xca, 0x04, 0x07, 0x18, 0x42, 0xa3, 0xaf, 0x93, 0x33, 0x16, 0x83, 0x0d, - 0x53, 0xa7, 0xcb, 0x88, 0xd2, 0xa9, 0x82, 0x3b, 0xcd, 0xfb, 0xec, 0x8f, 0x18, 0xc8, - 0x6a, 0xc3, 0xdf, 0x89, 0x42, 0x38, 0x00, 0x1b, 0xa8, 0xfa, 0x31, 0x3f, 0x80, 0xcf, - 0xe7, 0x5f, 0x7c, 0xb5, 0xd9, 0x73, 0xcc, 0x77, 0xf3, 0x21, 0xf1, 0x95, 0x2f, 0x30, - 0x50, 0x18, 0xc0, 0xbf, 0x23, 0x8b, 0x80, 0xe3, 0x21, 0x19, 0x90, 0x60, 0x66, 0xf6, - 0x4e, 0x64, 0x5e, 0x2b, 0xca, 0xd7, 0xe4, 0xcd, 0xbe, 0xf0, 0x07, 0xf7, 0xe9, 0xad, - 0x8a, 0x31, 0x83, 0x8b, 0x9e, 0xae, 0xc3, 0x85, 0xe3, 0xf2, 0x5e, 0x16, 0x04, 0xa6, - 0xd4, 0x64, 0x99, 0x87, 0x5a, 0xc1, 0x4a, 0x6c, 0xb3, 0x55, 0xa3, 0xd4, 0x32, 0x91, - 0x45, 0x80, 0x3c, 0x6b, 0xfb, 0x82, 0xe2, 0x9a, 0xb0, 0x29, 0x9f, 0x91, 0x7a, 0x74, - 0x02, 0x81, 0x57, 0x71, 0x7c, 0x08, 0x48, 0x68, 0x63, 0x94, 0x5c, 0x5a, 0x02, 0x36, - 0x58, 0xee, 0xe4, 0xa8, 0xb2, 0x89, 0x56, 0x4c, 0x22, 0xa9, 0x67, 0x1c, 0x56, 0x91, - 0x33, 0x5e, 0xb1, 0x25, 0x89, 0x88, 0x51, 0x67, 0x8f, 0x54, 0x93, 0x45, 0x10, 0xbf, - 0x30, 0x91, 0xc6, 0x02, 0xe1, 0x2a, 0x32, 0x03, 0xa2, 0xf3, 0x2f, 0x34, 0x7d, 0x4b, - 0xdc, 0x9d, 0x44, 0x92, 0x4d, 0xc8, 0x67, 0x5c, 0x9f, 0x24, 0x06, 0x4d, 0x35, 0xb0, - 0x09, 0xb6, 0xdd, 0xbd, 0xb2, 0x37, 0x20, 0x75, 0x33, 0xd5, 0xbb, 0xad, 0x3b, 0xa1, - 0xa3, 0xd6, 0xb0, 0x89, 0x32, 0x9b, 0xe1, 0x47, 0x23, 0x4e, 0x75, 0x1a, 0x49, 0x27, - 0x9d, 0x74, 0xdb, 0x88, 0xdb, 0x5c, 0xa1, 0x02, 0xd5, 0xe0, 0xe1, 0xaa, 0xc7, 0xcc, - 0xf9, 0x66, 0xb0, 0xa8, 0x13, 0x67, 0x09, 0x5d, 0xa2, 0x1d, 0xc4, 0xb7, 0x36, 0x55, - 0x95, 0x30, 0x80, 0xe3, 0x54, 0xbd, 0x22, 0x09, 0xf2, 0x66, 0x82, 0x10, 0xe9, 0x47, - 0x41, 0x27, 0x31, 0x1d, 0x93, 0x45, 0xce, 0x1e, 0xbd, 0x3a, 0xe5, 0x24, 0x24, 0x5b, - 0xbb, 0x44, 0x7a, 0x44, 0x50, 0x80, 0xb5, 0xfa, 0x23, 0xcd, 0xfe, 0x98, 0xb3, 0xf6, - 0xf6, 0x3c, 0x44, 0xeb, 0xe7, 0x22, 0xb9, 0x7a, 0x79, 0x10, 0xdf, 0x7e, 0xa6, 0x22, - 0x5e, 0xd9, 0xdc, 0xb4, 0x49, 0x84, 0x93, 0xe8, 0xef, 0x55, 0x31, 0xf9, 0xf9, 0x77, - 0x31, 0x84, 0xd7, 0xb4, 0xf5, 0x36, 0x77, 0xb1, 0xd0, 0x44, 0xf6, 0xf1, 0x44, 0x07, - 0xde, 0x5d, 0x67, 0xe0, 0x77, 0xd2, 0x0f, 0x2e, 0x9d, 0x7f, 0xd7, 0x15, 0xbf, 0x9b, - 0x19, 0x9b, 0x93, 0xb9, 0x84, 0x02, 0x46, 0xef, 0x9c, 0x07, 0x35, 0xe4, 0x88, 0xff, - 0x7c, 0x80, 0xb9, 0x41, 0x78, 0xac, 0xa3, 0x1b, 0x13, 0xc3, 0x7c, 0x9a, 0xeb, 0x7f, - 0x62, 0xe2, 0xd8, 0x58, 0x97, 0xea, 0x2e, 0x2a, 0x23, 0x28, 0xee, 0x03, 0xc9, 0x7f, - 0x2f, 0x3f, 0x4d, 0x20, 0xa8, 0xe7, 0x30, 0x24, 0xc5, 0x50, 0x8e, 0xee, 0xbd, 0x3a, - 0x12, 0x67, 0x31, 0xcd, 0xbf, 0x21, 0xfd, 0xad, 0xb1, 0x4b, 0x4e, 0x59, 0x1c, 0xba, - 0xb1, 0x44, 0xbe, 0xc3, 0x5a, 0x72, 0xac, 0xbf, 0x94, 0x84, 0xf4, 0x7a, 0x10, 0xb9, - 0x1e, 0xfc, 0x04, 0x27, 0xfe, 0xcf, 0x3f, 0xfc, 0xf1, 0x69, 0xd7, 0x00, 0x59, 0xb4, - 0x02, 0x79, 0xff, 0xa0, 0x2c, 0x51, 0x06, 0x74, 0x27, 0xa0, 0xda, 0xea, 0xd6, 0xf9, - 0x4b, 0xaf, 0xe4, 0xc1, 0x23, 0x3a, 0x22, 0x25, 0xeb, 0x56, 0x00, 0x3f, 0xc3, 0x85, - 0x42, 0x0d, 0x5a, 0x9f, 0xf3, 0xd5, 0x91, 0x55, 0x23, 0xa0, 0x8c, 0x87, 0xeb, 0x2e, - 0xa6, 0x69, 0x17, 0x23, 0x3a, 0x73, 0x25, 0xfe, 0x79, 0x3f, 0x41, 0x07, 0x6d, 0x64, - 0x25, 0x5a, 0xbd, 0x15, 0x21, 0x47, 0x66, 0x60, 0xe9, 0x04, 0x91, 0x60, 0x2c, 0x69, - 0xa4, 0xab, 0xb1, 0x38, 0x84, 0x43, 0x10, 0x72, 0xef, 0x96, 0xa0, 0x95, 0xbe, 0x41, - 0x1f, 0xfc, 0xff, 0xb7, 0x86, 0x3f, 0xef, 0x7d, 0xab, 0x4d, 0x4a, 0x72, 0xa2, 0xd0, - 0xbb, 0xd3, 0x6f, 0x9f, 0xdf, 0x0b, 0x35, 0x38, 0xb3, 0x9c, 0xae, 0x5f, 0xf6, 0x0e, - 0x5a, 0xc6, 0xb6, 0x09, 0x70, 0x72, 0x43, 0x14, 0x6e, 0xb5, 0x36, 0x0a, 0xe7, 0xf9, - 0x3f, 0x79, 0x9b, 0x6c, 0x27, 0xe6, 0x5a, 0x0a, 0x06, 0x39, 0x87, 0x38, 0x66, 0x0f, - 0xda, 0xd2, 0xcf, 0xb3, 0x1a, 0xa5, 0x40, 0xd5, 0xe8, 0x90, 0x06, 0x78, 0xb9, 0xda, - 0xb5, 0x24, 0x79, 0xbd, 0x0c, 0xd6, 0xf1, 0xa5, 0x98, 0x67, 0x3e, 0xed, 0x9c, 0x76, - 0xe3, 0x38, 0x10, 0x49, 0x47, 0x18, 0xd0, 0x5d, 0xdf, 0xdc, 0x00, 0x7a, 0x54, 0xbc, - 0xd1, 0xcc, 0x4c, 0x97, 0x40, 0xf7, 0xe5, 0x3a, 0x31, 0x68, 0x1d, 0x2b, 0x2c, 0x6e, - 0xde, 0x79, 0x28, 0x11, 0x49, 0xea, 0xc3, 0x0f, 0x6e, 0xe5, 0x83, 0x60, 0x5a, 0xc2, - 0xff, 0xae, 0xc1, 0x55, 0x00, 0x35, 0xdc, 0x5a, 0xbb, 0x35, 0x89, 0x44, 0x68, 0xf1, - 0x2d, 0x5d, 0x08, 0xd7, 0x34, 0x36, 0xa8, 0x59, 0xe5, 0x50, 0x7f, 0xdd, 0x1a, 0x46, - 0x38, 0xfb, 0xe6, 0x81, 0xb0, 0xa0, 0xef, 0xfb, 0xbb, 0xf7, 0x4c, 0x99, 0x39, 0x9d, - 0xca, 0x69, 0x02, 0xa0, 0x74, 0xc8, 0x33, 0x35, 0x60, 0x7a, 0x0c, 0x0d, 0xb0, 0x1c, - 0xa3, 0xca, 0x2f, 0xa8, 0x18, 0x57, 0x24, 0x02, 0xe2, 0xfa, 0xef, 0xb3, 0x07, 0xbe, - 0x22, 0xc7, 0xd5, 0x61, 0x1f, 0xf6, 0xfb, 0x5a, 0x31, 0xb4, 0x62, 0x16, 0x59, 0xd8, - 0x4d, 0x8a, 0x7a, 0x1a, 0xdc, 0xa2, 0xfc, 0x4e, 0xb8, 0xb8, 0x97, 0x04, 0x43, 0x93, - 0x27, 0x64, 0x46, 0x31, 0xa7, 0xbb, 0xc1, 0xa8, 0x41, 0xf3, 0x65, 0x83, 0x0d, 0x27, - 0xc8, 0xaa, 0x4d, 0x75, 0xc8, 0x07, 0x87, 0xbd, 0x10, 0xb7, 0x14, 0xcb, 0x97, 0x9c, - 0x1b, 0x0f, 0x3f, 0x0b, 0x41, 0xee, 0x94, 0x22, 0x94, 0x24, 0x8c, 0x48, 0x5c, 0xf9, - 0x9c, 0x6b, 0xc4, 0x63, 0x20, 0x7a, 0xf3, 0x83, 0x61, 0x97, 0x83, 0x57, 0x41, 0x41, - 0x5d, 0xe6, 0x1f, 0xf2, 0x9f, 0xad, 0x30, 0x01, 0x82, 0x71, 0x4c, 0x20, 0xca, 0x34, - 0x04, 0x7b, 0xcc, 0xb7, 0x05, 0x81, 0x0f, 0xfa, 0xe5, 0x3a, 0x34, 0x16, 0xa5, 0x3f, - 0x28, 0xaf, 0xc0, 0x08, 0xe8, 0xbf, 0xf9, 0x49, 0xe4, 0x3a, 0x54, 0x10, 0xe6, 0xad, - 0xb6, 0x65, 0xf9, 0x9f, 0xa4, 0xca, 0xfa, 0xc2, 0xe0, 0xf2, 0xc0, 0xf1, 0x34, 0xbd, - 0xba, 0x83, 0x81, 0xc2, 0xbb, 0xac, 0x43, 0x33, 0x2a, 0xcd, 0xcb, 0x10, 0x08, 0x2e, - 0xf3, 0x43, 0xa3, 0x5a, 0xc6, 0x4f, 0x4b, 0xa1, 0x6e, 0x49, 0x57, 0xc7, 0x1e, 0x9a, - 0x2b, 0xd9, 0xa5, 0xcd, 0x6a, 0x92, 0x25, 0x8a, 0x9e, 0x58, 0x8e, 0x02, 0x1a, 0x06, - 0x65, 0x09, 0x04, 0x67, 0x0d, 0xa2, 0xc0, 0xe5, 0x2c, 0x52, 0x4f, 0x6e, 0x5c, 0xe3, - 0xee, 0x27, 0x5a, 0x0a, 0x63, 0x10, 0x3b, 0x5f, 0x92, 0x64, 0x16, 0xc0, 0xbd, 0x5d, - 0xa1, 0xae, 0x65, 0x69, 0xd3, 0xa4, 0xee, 0x4d, 0xbc, 0x5e, 0xc0, 0x8b, 0x29, 0x72, - 0x02, 0xc9, 0xd7, 0x13, 0xab, 0xc3, 0x47, 0x4d, 0xe4, 0x94, 0x0f, 0x59, 0xb1, 0xf3, - 0xfe, 0x0e, 0x92, 0x76, 0xa1, 0x76, 0x3b, 0x2d, 0xea, 0x39, 0x40, 0xb0, 0xc1, 0xf7, - 0xab, 0x5d, 0xa3, 0xf4, 0x55, 0x62, 0x3e, 0x04, 0x96, 0x82, 0xd0, 0x92, 0x18, 0x9c, - 0xb7, 0x9e, 0xcf, 0xd4, 0x3c, 0x3b, 0xf1, 0x0e, 0x7f, 0x2c, 0x8d, 0x4d, 0xe3, 0xa7, - 0x36, 0xf8, 0x69, 0xf0, 0x87, 0x03, 0xc4, 0xe5, 0x9f, 0x57, 0x4f, 0x77, 0xaa, 0x86, - 0x1c, 0xbf, 0xdd, 0xd0, 0x7f, 0x77, 0xdc, 0x24, 0xa9, 0x74, 0x10, 0xaf, 0xc7, 0xcf, - 0xbe, 0x3c, 0xe1, 0xff, 0xd2, 0x24, 0x53, 0x5c, 0xf3, 0x05, 0xce, 0xcc, 0x78, 0x56, - 0xa4, 0xd4, 0x8a, 0x6d, 0xec, 0x17, 0xa2, 0x4b, 0x6d, 0x27, 0xfe, 0x26, 0x64, 0xbc, - 0x2b, 0x2b, 0x71, 0x1d, 0x67, 0x13, 0x90, 0x6c, 0xed, 0x8a, 0x80, 0x66, 0x62, 0x18, - 0x40, 0xd9, 0x0c, 0x23, 0xae, 0x33, 0x77, 0x30, 0x67, 0x9d, 0x2c, 0xde, 0x32, 0x69, - 0xab, 0x1f, 0x42, 0xac, 0x03, 0xff, 0xdb, 0xa0, 0x32, 0xd3, 0x2c, 0xa8, 0x79, 0x63, - 0x82, 0x56, 0x56, 0x5d, 0xe1, 0xd2, 0xde, 0x39, 0xf5, 0x6f, 0x94, 0x57, 0x95, 0xd6, - 0xe9, 0x58, 0xe6, 0x93, 0xdc, 0x8c, 0xbf, 0x6d, 0x04, 0x30, 0x00, 0xcc, 0x7a, 0x40, - 0x15, 0xf0, 0x2d, 0x0f, 0xe3, 0x97, 0xec, 0x57, 0xf8, 0xfe, 0x29, 0x2e, 0x85, 0x14, - 0x24, 0xe8, 0x40, 0x6d, 0x38, 0xdd, 0xb8, 0xd1, 0xde, 0x9d, 0xef, 0x67, 0x2e, 0x92, - 0x7d, 0x3d, 0xc1, 0xf4, 0x11, 0xdc, 0x78, 0xad, 0xa7, 0x61, 0x00, 0x91, 0xbf, 0xe2, - 0x63, 0xcd, 0x79, 0x96, 0xd1, 0x80, 0x5e, 0xe4, 0x91, 0xe9, 0x95, 0x91, 0xd6, 0xef, - 0xdb, 0x2e, 0x3c, 0x79, 0x71, 0x57, 0x41, 0xd0, 0xd4, 0x72, 0xac, 0x11, 0xdb, 0x78, - 0x64, 0x4f, 0x3d, 0x23, 0xe5, 0x8f, 0x0b, 0x01, 0xa8, 0x61, 0xe0, 0x85, 0x65, 0x53, - 0x52, 0x07, 0xcd, 0x5e, 0x71, 0x0f, 0xc3, 0x3e, 0xb2, 0xf8, 0x92, 0x8b, 0xc7, 0xd4, - 0x01, 0x7e, 0x4e, 0x56, 0xc0, 0xc2, 0xeb, 0x95, 0x85, 0xd6, 0x99, 0x74, 0x5e, 0x3b, - 0xb9, 0x61, 0x8b, 0x2c, 0x1b, 0x90, 0xf2, 0x35, 0x1b, 0xaf, 0x27, 0x6a, 0x70, 0x17, - 0xb0, 0xfc, 0xfa, 0xcb, 0x52, 0xea, 0x27, 0x31, 0x95, 0xa8, 0xde, 0xe1, 0x67, 0x79, - 0x13, 0xc7, 0x86, 0xcc, 0x3a, 0xcb, 0x06, 0xa9, 0xec, 0x7a, 0x37, 0xb0, 0x58, 0x98, - 0x0c, 0xeb, 0x3c, 0x82, 0xaa, 0xb0, 0x3e, 0xaf, 0xc1, 0xbb, 0x88, 0xcf, 0x7a, 0xb7, - 0x98, 0xf1, 0x65, 0x1d, 0x67, 0xbf, 0x22, 0x30, 0xd5, 0x34, 0xec, 0x55, 0x23, 0x1d, - 0x21, 0x31, 0x7b, 0x1c, 0xb3, 0x0b, 0x3c, 0x38, 0xff, 0x8d, 0x21, 0x1b, 0x76, 0x36, - 0x70, 0x2a, 0x25, 0xca, 0x7c, 0xa1, 0xbf, 0xf1, 0xf2, 0xc1, 0x58, 0xc6, 0xef, 0x22, - 0x13, 0xff, 0xab, 0xb9, 0xc0, 0x9f, 0x5c, 0x47, 0xe7, 0x3b, 0xbe, 0xbb, 0xd3, 0x7f, - 0x3d, 0x3e, 0xbc, 0x24, 0xa6, 0x65, 0xb2, 0x9f, 0x10, 0xde, 0x8b, 0x9c, 0xf1, 0x94, - 0x2d, 0x90, 0xb4, 0xc3, 0x1d, 0x89, 0xa9, 0x88, 0x3b, 0xf5, 0xa0, 0x27, 0xe9, 0x20, - 0xd1, 0xb8, 0x51, 0x19, 0xf2, 0xf2, 0xf9, 0x5f, 0xd5, 0x5e, 0xda, 0x85, 0x75, 0xa4, - 0xdb, 0x62, 0x69, 0x05, 0x68, 0x1c, 0x29, 0xe8, 0xd8, 0xe7, 0x41, 0xd4, 0x20, 0xa8, - 0x34, 0x42, 0xa9, 0xd3, 0x8a, 0xf4, 0x19, 0x9e, 0xf9, 0x5c, 0xb3, 0x0b, 0xc4, 0x4e, - 0x93, 0xfe, 0x4d, 0x0e, 0xb7, 0x42, 0x22, 0xfc, 0x10, 0xac, 0x8d, 0x40, 0x0e, 0x10, - 0xed, 0x4e, 0x56, 0xfa, 0x39, 0xda, 0x01, 0x2a, 0xc1, 0x8d, 0xee, 0x4d, 0x99, 0x42, - 0x5c, 0x8f, 0x71, 0x4c, 0x51, 0xac, 0x1b, 0xa5, 0x6e, 0x0e, 0x81, 0x47, 0x4b, 0xad, - 0x3e, 0x74, 0x18, 0xed, 0x4c, 0x82, 0xb4, 0xd7, 0x75, 0x12, 0x0b, 0x19, 0x3e, 0xdc, - 0x66, 0x76, 0x30, 0x32, 0x66, 0xe3, 0x1e, 0xcf, 0x55, 0x1e, 0xb9, 0x13, 0xa6, 0x41, - 0x15, 0xbc, 0xcb, 0xbb, 0x2e, 0xcc, 0x89, 0x81, 0x55, 0x21, 0xe5, 0x6e, 0x07, 0xc8, - 0x8b, 0xbb, 0x4a, 0x55, 0xe9, 0x94, 0x5d, 0x03, 0xdb, 0x2d, 0xa0, 0xfc, 0xae, 0x3c, - 0x08, 0xf1, 0xd7, 0x7c, 0x57, 0x26, 0x1e, 0x98, 0x23, 0x66, 0x03, 0xa8, 0xc5, 0x2c, - 0x6c, 0x27, 0x98, 0xb5, 0x45, 0x61, 0xaf, 0xfe, 0x07, 0x61, 0xe6, 0xab, 0x24, 0x72, - 0x07, 0xad, 0xfc, 0x3c, 0x43, 0x22, 0xbe, 0x0f, 0xb2, 0x49, 0xbf, 0xd3, 0xc5, 0xe7, - 0xfb, 0x38, 0x37, 0xe9, 0xff, 0x21, 0x35, 0x07, 0x3a, 0xe1, 0x36, 0x0d, 0xcf, 0xaf, - 0x5f, 0xb6, 0x78, 0x56, 0x8f, 0xd8, 0x4d, 0x99, 0xa5, 0x1f, 0x32, 0xeb, 0x94, 0xcc, - 0xf5, 0xf2, 0x39, 0x02, 0x5b, 0x2b, 0x97, 0xbe, 0xf6, 0x25, 0xdb, 0xb6, 0x7f, 0x20, - 0xc3, 0xe0, 0xd9, 0x51, 0x73, 0x12, 0x9c, 0x06, 0x37, 0x50, 0x39, 0x52, 0x13, 0x41, - 0x49, 0x24, 0xe0, 0xa3, 0xfd, 0xd3, 0x66, 0xff, 0xd4, 0x69, 0xc9, 0xeb, 0xea, 0x79, - 0xfb, 0x76, 0xaf, 0x10, 0xea, 0x45, 0xb5, 0x66, 0xf1, 0xfc, 0x92, 0xaf, 0x48, 0xce, - 0xe2, 0x11, 0xf8, 0xe1, 0xb0, 0x58, 0xfb, 0x72, 0x1a, 0x8b, 0x22, 0xce, 0x43, 0x0c, - 0x54, 0x94, 0x0e, 0x24, 0xb3, 0x30, 0x8e, 0x57, 0x0a, 0xb8, 0x57, 0x25, 0x0d, 0x10, - 0xcd, 0xec, 0xe1, 0x05, 0x07, 0x1b, 0xc8, 0x66, 0xea, 0x4d, 0x6d, 0x5c, 0x69, 0xf9, - 0x59, 0x28, 0xf3, 0x9f, 0x7f, 0x1f, 0xcd, 0xf1, 0x5a, 0xcd, 0xbb, 0xec, 0x67, 0xd8, - 0x48, 0xf7, 0xc1, 0xb2, 0xef, 0x57, 0x7f, 0x48, 0xa7, 0x0b, 0x4b, 0xf3, 0xd8, 0xa7, - 0x88, 0x14, 0x31, 0x6b, 0x3d, 0x7f, 0xa3, 0xe3, 0xc9, 0x8c, 0xdf, 0xa1, 0x78, 0xb9, - 0x89, 0xbc, 0x78, 0xde, 0x8d, 0x24, 0xc1, 0xbb, 0xc0, 0x9d, 0x20, 0x7e, 0x11, 0x18, - 0x1e, 0x59, 0x1a, 0x60, 0x9a, 0xbf, 0xf9, 0xa2, 0x00, 0xd3, 0x4e, 0x1a, 0xc6, 0x3a, - 0x38, 0xf0, 0x40, 0x05, 0x3a, 0x32, 0x01, 0x68, 0xb8, 0x23, 0xac, 0x76, 0x6e, 0x02, - 0x6c, 0xbe, 0x1a, 0xbf, 0x27, 0x55, 0xbe, 0x0c, 0x73, 0xc8, 0xfd, 0x98, 0x62, 0x55, - 0x56, 0x40, 0x6c, 0x14, 0x99, 0x3f, 0x6a, 0x28, 0xae, 0x4b, 0xb3, 0xa4, 0x73, 0xa1, - 0x8d, 0xd3, 0x74, 0x3d, 0x88, 0x7e, 0xac, 0x54, 0x8e, 0xb7, 0xca, 0x4d, 0x46, 0x15, - 0x7c, 0x62, 0xb7, 0x29, 0xf3, 0x66, 0xa9, 0x56, 0x02, 0x28, 0x7c, 0x8c, 0x56, 0x33, - 0x5b, 0x78, 0xbc, 0x68, 0x9f, 0xc5, 0x38, 0x9c, 0x39, 0x79, 0xb8, 0xe7, 0x5d, 0xaf, - 0x31, 0xbd, 0x60, 0xa9, 0xcc, 0x2a, 0x92, 0x0d, 0xbc, 0xc6, 0x71, 0xdd, 0xe2, 0x7e, - 0xb4, 0x60, 0x0f, 0x12, 0xdc, 0x2a, 0xb3, 0x94, 0x4a, 0xa1, 0x9c, 0x71, 0xa9, 0x87, - 0xd8, 0x71, 0x3d, 0x99, 0xa4, 0xba, 0x9b, 0x9a, 0x19, 0xa9, 0x21, 0x60, 0x6c, 0x56, - 0x20, 0xc1, 0x67, 0xd4, 0xc7, 0xf4, 0xa2, 0x8a, 0x46, 0x4a, 0x9d, 0x16, 0xc4, 0xb0, - 0xd7, 0x4e, 0x0e, 0x75, 0xdf, 0x6d, 0xba, 0x0e, 0x1d, 0xfe, 0x60, 0x1c, 0x04, 0xc8, - 0xeb, 0x37, 0x01, 0x0e, 0x13, 0x92, 0x1d, 0x5b, 0x6c, 0x93, 0xb9, 0xf0, 0xc3, 0xdd, - 0xd3, 0x2f, 0x7b, 0xec, 0xb2, 0xd7, 0x7d, 0x79, 0xa1, 0x61, 0x8a, 0x79, 0xf7, 0x3c, - 0x45, 0x9b, 0x0d, 0xf5, 0x29, 0x7f, 0x8e, 0xab, 0xd6, 0xed, 0x06, 0xfd, 0x23, 0x40, - 0xe8, 0x60, 0x0a, 0x95, 0xd7, 0x2c, 0xef, 0xd1, 0x2e, 0x62, 0x2c, 0x57, 0xb4, 0x57, - 0xa4, 0xe8, 0x39, 0x75, 0x93, 0x74, 0x6a, 0x6b, 0xcf, 0x04, 0xc4, 0x9c, 0x6d, 0xd4, - 0xa3, 0x36, 0x68, 0xda, 0x53, 0x8d, 0x90, 0x93, 0xa4, 0x50, 0xa4, 0xd8, 0x24, 0x51, - 0xb6, 0x12, 0xff, 0x54, 0x70, 0x73, 0x8e, 0x62, 0xbf, 0xdf, 0xc7, 0x9b, 0x3e, 0x31, - 0xbb, 0x47, 0xfc, 0xa1, 0xe9, 0x87, 0x22, 0xa5, 0x98, 0x3a, 0xff, 0xe5, 0xf6, 0x32, - 0x84, 0x0b, 0x92, 0x3a, 0xb5, 0x6b, 0x1d, 0xa1, 0x53, 0xd3, 0x5d, 0x82, 0x23, 0x24, - 0xe7, 0xd5, 0x6d, 0x61, 0x3c, 0x73, 0xeb, 0xc6, 0x34, 0x1e, 0xa0, 0x3b, 0xee, 0x3a, - 0xb9, 0x73, 0xe8, 0x4d, 0x8f, 0xfc, 0x4a, 0x7c, 0x58, 0x13, 0x83, 0xe2, 0x14, 0x2d, - 0x29, 0x2a, 0x58, 0x0b, 0x6d, 0x30, 0x83, 0x43, 0xdc, 0xf1, 0xef, 0x49, 0x29, 0xa9, - 0xe3, 0xe6, 0x15, 0x32, 0xfc, 0xff, 0xb7, 0x4d, 0x30, 0x19, 0xf4, 0xe2, 0xd6, 0xd3, - 0x11, 0x78, 0x57, 0x5a, 0xca, 0x94, 0x12, 0x99, 0x22, 0x50, 0x44, 0xe1, 0xd3, 0x7b, - 0xab, 0x9f, 0x10, 0xe2, 0x9f, 0xd9, 0x6f, 0x9c, 0xf6, 0x84, 0xaf, 0x98, 0xed, 0x64, - 0x8b, 0x83, 0xd6, 0x1e, 0x52, 0x5b, 0xe3, 0x2c, 0xdb, 0x45, 0x3d, 0x2d, 0x38, 0x93, - 0x5f, 0xee, 0xb3, 0x22, 0xce, 0xb9, 0xd2, 0xa2, 0xe9, 0x5e, 0xb7, 0xfc, 0x61, 0x2d, - 0x89, 0xf4, 0xcf, 0xe8, 0x93, 0x22, 0x8e, 0x88, 0x28, 0xb1, 0x89, 0x00, 0x90, 0x45, - 0x62, 0x90, 0x75, 0xc0, 0xc2, 0x03, 0x9d, 0x5a, 0x73, 0x32, 0xfd, 0xbc, 0xd7, 0xc7, - 0xb0, 0x91, 0x01, 0x5c, 0x45, 0x69, 0xa3, 0x00, 0x53, 0x23, 0x56, 0xbb, 0xad, 0x08, - 0xff, 0xa3, 0xbb, 0x16, 0x7a, 0x3e, 0xbe, 0xb4, 0x62, 0x66, 0xb7, 0x06, 0x06, 0x49, - 0x4a, 0xda, 0xe9, 0x14, 0x9e, 0x1a, 0x64, 0xc0, 0xa0, 0xaa, 0x5d, 0xaa, 0x53, 0x62, - 0xd3, 0xc7, 0xa8, 0x96, 0xfd, 0x52, 0x78, 0x08, 0xd0, 0xa3, 0xc1, 0xcf, 0x70, 0x61, - 0xba, 0x67, 0x89, 0x39, 0x80, 0x78, 0x85, 0x0b, 0xe4, 0xb9, 0x94, 0x0e, 0x01, 0xae, - 0xbb, 0x93, 0x6d, 0xd8, 0x1a, 0x31, 0x82, 0x04, 0x28, 0x1d, 0x43, 0x97, 0x6f, 0x4e, - 0x0f, 0xa2, 0x07, 0xe4, 0xbe, 0x1f, 0xb8, 0x2c, 0x91, 0xbb, 0x26, 0x42, 0xf7, 0x36, - 0x85, 0x6d, 0xcd, 0x5a, 0xeb, 0x75, 0xc5, 0x0a, 0xf2, 0x00, 0xe1, 0x4b, 0xe5, 0xb7, - 0x8c, 0xe6, 0x9a, 0x88, 0x51, 0x54, 0xef, 0xe3, 0x0e, 0xdd, 0x09, 0xae, 0x8c, 0x5e, - 0xb5, 0x3f, 0x4b, 0x8b, 0x7c, 0x75, 0x35, 0x37, 0x3c, 0x0f, 0xe6, 0xcf, 0xe4, 0x48, - 0xa9, 0xb9, 0xf4, 0xd9, 0xe3, 0x10, 0x93, 0x03, 0xd6, 0xce, 0xe9, 0x10, 0x6a, 0xa2, - 0x2b, 0xd5, 0x9a, 0xe0, 0xe0, 0x27, 0xd3, 0x25, 0x6a, 0x75, 0xb9, 0xc5, 0xd6, 0x07, - 0x09, 0x09, 0x97, 0x53, 0xce, 0x57, 0x2c, 0x9e, 0x29, 0xdc, 0x92, 0x56, 0x2d, 0x1c, - 0x3f, 0x4a, 0x0b, 0x4d, 0x36, 0xa6, 0xfe, 0xc2, 0x1b, 0xa4, 0x94, 0x17, 0x3e, 0x44, - 0xd7, 0x9b, 0xc2, 0x34, 0x18, 0x95, 0xbd, 0x0c, 0x70, 0x96, 0xf0, 0x97, 0x4f, 0x12, - 0x67, 0xfe, 0xf6, 0x72, 0x1d, 0x58, 0xb8, 0xc4, 0xe3, 0x34, 0xf1, 0x4d, 0x86, 0xc0, - 0xee, 0x3b, 0x1a, 0xb5, 0x88, 0x0c, 0xa4, 0x29, 0x8d, 0x7f, 0x84, 0x76, 0x3b, 0xdc, - 0x71, 0x09, 0xbc, 0x82, 0x0f, 0x45, 0xc5, 0x04, 0x53, 0xe3, 0x3d, 0x96, 0x8e, 0xf9, - 0xd8, 0x6c, 0xd6, 0xeb, 0xe7, 0x15, 0xe8, 0x9d, 0x5d, 0xe3, 0x24, 0x09, 0x10, 0xc5, - 0x9c, 0x36, 0xec, 0x8f, 0xe9, 0x9b, 0x32, 0x49, 0x16, 0x30, 0xab, 0x35, 0xb1, 0x24, - 0x53, 0x1d, 0x9c, 0x29, 0xe0, 0x46, 0xc4, 0x78, 0xe6, 0x2a, 0xd1, 0x8b, 0x25, 0x39, - 0xa5, 0x09, 0x6e, 0xe2, 0x9a, 0x4d, 0x4b, 0x4b, 0x53, 0xa1, 0xcf, 0xfa, 0x93, 0x23, - 0xbc, 0x73, 0x21, 0x81, 0x7d, 0x96, 0xfd, 0x02, 0x05, 0xea, 0x9c, 0xbc, 0x4e, 0x15, - 0x88, 0xb7, 0x61, 0x3d, 0x4c, 0x39, 0x3c, 0xac, 0x21, 0x05, 0xb2, 0x8f, 0xd0, 0x46, - 0x7a, 0x0b, 0xf0, 0x23, 0xf0, 0x0d, 0x1a, 0x17, 0xf6, 0x53, 0xcd, 0xb6, 0xb5, 0xa8, - 0x3e, 0x4c, 0xf1, 0x5c, 0x34, 0x7b, 0x34, 0xb9, 0x7f, 0xbf, 0xe6, 0xea, 0xee, 0x13, - 0xbb, 0x90, 0x15, 0x3a, 0xfd, 0xc9, 0x11, 0x26, 0x37, 0xfa, 0xd1, 0xcf, 0xe1, 0x7e, - 0xdd, 0xcb, 0x0c, 0x81, 0x9e, 0x60, 0xd3, 0x50, 0x39, 0x34, 0x9b, 0x69, 0xf7, 0xca, - 0x9b, 0xa6, 0x4d, 0xf9, 0xf5, 0xe4, 0x71, 0x11, 0x5c, 0xd6, 0x79, 0x26, 0xbd, 0xf1, - 0x6e, 0x30, 0x12, 0x39, 0x8d, 0xae, 0x59, 0x5b, 0xfd, 0x25, 0xf3, 0xae, 0xe5, 0x8a, - 0xcf, 0xfe, 0x2f, 0x3e, 0xd7, 0x48, 0xfd, 0xf9, 0x3a, 0x6e, 0xd2, 0x1e, 0x87, 0x2d, - 0x94, 0x97, 0xa9, 0xf3, 0xb7, 0xb1, 0x6b, 0x7e, 0xa9, 0xea, 0x19, 0xf2, 0x47, 0x9e, - 0x4f, 0x8b, 0x6d, 0x42, 0x3f, 0xa1, 0x5f, 0xbc, 0xdf, 0xa3, 0xc9, 0x9b, 0x9a, 0x39, - 0x70, 0xee, 0x74, 0xa8, 0xd8, 0x5e, 0xc2, 0x15, 0x96, 0x52, 0xda, 0xa7, 0x67, 0x03, - 0x12, 0x63, 0xbb, 0x4b, 0x49, 0x28, 0x5d, 0x70, 0x5e, 0x24, 0xe8, 0x19, 0x26, 0x86, - 0xeb, 0xc8, 0xff, 0x85, 0x98, 0xd2, 0x4b, 0x51, 0x23, 0x2a, 0x99, 0x38, 0x56, 0x5d, - 0x0f, 0x68, 0xbe, 0x7f, 0x3a, 0x53, 0x36, 0x4a, 0xcc, 0x69, 0x21, 0xa3, 0x5b, 0xc5, - 0x99, 0x10, 0xbb, 0x71, 0xfb, 0x58, 0xb8, 0x67, 0x37, 0x3c, 0xe9, 0x5f, 0x19, 0x84, - 0x09, 0xaa, 0xef, 0x97, 0xf4, 0x01, 0xe4, 0x33, 0x00, 0x4b, 0x99, 0x19, 0x04, 0x9f, - 0x93, 0x7f, 0xd7, 0x76, 0xc4, 0xb6, 0x31, 0xa5, 0x91, 0x2a, 0x08, 0xd4, 0x9f, 0xdf, - 0x65, 0x28, 0xf8, 0x1a, 0x6f, 0x32, 0x00, 0x09, 0x37, 0x67, 0xbb, 0x77, 0x89, 0xd9, - 0x5a, 0x75, 0x03, 0x0a, 0xc1, 0xd2, 0x4c, 0x2c, 0x75, 0xbd, 0x60, 0x38, 0x25, 0x52, - 0x86, 0x3f, 0x09, 0x8d, 0x36, 0xbd, 0x48, 0x33, 0x28, 0x3d, 0x3a, 0x2d, 0x21, 0x5d, - 0x10, 0xc7, 0xff, 0xe9, 0xc8, 0x40, 0x37, 0x23, 0x14, 0x45, 0x58, 0x33, 0x29, 0x26, - 0x16, 0x74, 0x19, 0x3b, 0xdd, 0x1c, 0x64, 0x81, 0xbe, 0xf9, 0xf2, 0x26, 0xe1, 0xe6, - 0x0b, 0xb1, 0xc7, 0x76, 0xa4, 0xbe, 0x7d, 0xc6, 0x9b, 0x44, 0x30, 0xa7, 0x5a, 0x0c, - 0xbd, 0x55, 0x86, 0x7a, 0x6f, 0x46, 0xff, 0x93, 0x03, 0xf9, 0xa2, 0x9b, 0x6f, 0x3f, - 0x7c, 0x7a, 0x9c, 0x9f, 0xbc, 0xf7, 0x47, 0xb2, 0x3f, 0x86, 0x45, 0xf4, 0xda, 0x3d, - 0x9f, 0x72, 0xd0, 0xd8, 0x76, 0xa7, 0x5e, 0x54, 0x8a, 0x49, 0xdb, 0x37, 0x5b, 0x40, - 0xeb, 0xe1, 0xbb, 0xe0, 0x81, 0x7a, 0x99, 0x49, 0xde, 0xc1, 0x15, 0x7d, 0x62, 0xa7, - 0x1d, 0xbf, 0xbd, 0x9b, 0xb1, 0xd6, 0x55, 0x17, 0x53, 0xdf, 0xf5, 0xbb, 0x7f, 0xc9, - 0x36, 0x48, 0xd4, 0xeb, 0x6c, 0xad, 0x41, 0x67, 0x33, 0xad, 0xfd, 0xcc, 0x87, 0x08, - 0xdd, 0xe8, 0xbe, 0x87, 0x34, 0xd0, 0x5d, 0xec, 0x9e, 0x45, 0xdf, 0x3f, 0xa4, 0x5a, - 0xda, 0xc4, 0x1a, 0x6d, 0x23, 0xa2, 0x24, 0xa0, 0x4f, 0xdc, 0x0d, 0x96, 0x73, 0x87, - 0x98, 0x0f, 0x95, 0xe6, 0x27, 0xe6, 0xb3, 0xdc, 0xe1, 0x9c, 0xaf, 0x01, 0x09, 0x84, - 0x8c, 0xa9, 0xda, 0xea, 0x2e, 0x24, 0x6e, 0x62, 0xc2, 0x85, 0x07, 0xd2, 0x56, 0xeb, - 0xab, 0xe1, 0x18, 0xf1, 0xf6, 0xef, 0x97, 0x6e, 0x4a, 0x31, 0xa0, 0xe4, 0x14, 0x3c, - 0x43, 0x60, 0xd8, 0xb1, 0x79, 0xb3, 0x0e, 0x4b, 0xfa, 0x7e, 0x16, 0x1b, 0x1e, 0x6c, - 0x70, 0x7d, 0x8e, 0xae, 0x76, 0x28, 0x71, 0x59, 0x21, 0x94, 0x1e, 0x78, 0x54, 0xe1, - 0x0d, 0x11, 0x99, 0x12, 0x58, 0xc4, 0x3f, 0xe6, 0xc4, 0x45, 0x29, 0xf6, 0x61, 0x4b, - 0x58, 0x41, 0x61, 0x5d, 0x3e, 0x4e, 0x77, 0xfb, 0x09, 0xa6, 0xf0, 0x20, 0xe0, 0xb8, - 0x32, 0x28, 0xac, 0x17, 0x55, 0xad, 0x47, 0x71, 0x16, 0xde, 0xca, 0xac, 0x51, 0x7b, - 0xfb, 0xcf, 0x67, 0x37, 0xf5, 0xbb, 0x99, 0xe0, 0x07, 0xeb, 0x64, 0x00, 0x76, 0x6b, - 0x6c, 0xfd, 0xd7, 0x37, 0xe2, 0x08, 0x57, 0xdf, 0x3c, 0x85, 0xca, 0x16, 0xab, 0x21, - 0x17, 0x7b, 0x53, 0x1e, 0x55, 0x32, 0xc4, 0x45, 0xde, 0xd0, 0x0c, 0x1e, 0x96, 0x63, - 0x5e, 0x9f, 0x50, 0x0b, 0xa8, 0x76, 0x44, 0xb8, 0xc1, 0xd5, 0x33, 0x25, 0x37, 0xab, - 0xf2, 0x9f, 0xcc, 0xab, 0x8a, 0xe3, 0xe3, 0x88, 0x27, 0x18, 0x82, 0x6b, 0xdb, 0x8d, - 0xbd, 0xb8, 0x51, 0xa4, 0x77, 0x05, 0xeb, 0x0d, 0xec, 0x2d, 0x5e, 0xe9, 0x39, 0xdc, - 0x79, 0x87, 0x25, 0x6f, 0xee, 0xe6, 0x7f, 0x09, 0x90, 0x28, 0xf1, 0x45, 0xe2, 0x0b, - 0xf4, 0x88, 0x94, 0x98, 0x24, 0x30, 0x14, 0x35, 0x13, 0x73, 0xfd, 0xf6, 0x33, 0x01, - 0x8d, 0x21, 0x7c, 0x58, 0x8c, 0x52, 0x98, 0x6f, 0xc5, 0x24, 0xe7, 0x97, 0x97, 0xab, - 0x65, 0x58, 0x43, 0xc2, 0x61, 0xae, 0x7f, 0xc9, 0xcc, 0x3f, 0x47, 0x05, 0x46, 0x00, - 0xe4, 0xcd, 0x38, 0x5c, 0x46, 0x7a, 0x78, 0x8a, 0x9f, 0xff, 0xc3, 0x7e, 0x9d, 0xdb, - 0xb5, 0xd3, 0xe8, 0xa4, 0xbd, 0x0c, 0x4e, 0x8f, 0x56, 0xe5, 0x69, 0x5a, 0xfa, 0x90, - 0xfe, 0x50, 0xce, 0x0a, 0x30, 0x04, 0xfe, 0xd7, 0x12, 0xb4, 0xde, 0x15, 0xad, 0x5f, - 0x01, 0x71, 0xad, 0x51, 0xed, 0xfa, 0x54, 0xdb, 0xd4, 0x8b, 0x1f, 0xcc, 0x5e, 0xf6, - 0xac, 0x73, 0xcf, 0x0a, 0x28, 0xe9, 0xd9, 0x3e, 0x0c, 0xaf, 0xad, 0x88, 0x16, 0x76, - 0x1b, 0x3b, 0xe6, 0x38, 0x39, 0x8c, 0x00, 0x14, 0x33, 0x38, 0xea, 0x27, 0xa9, 0xff, - 0xf2, 0x2e, 0xc4, 0x73, 0x16, 0x36, 0x96, 0x12, 0x25, 0xca, 0x49, 0xe0, 0x13, 0xa6, - 0xdc, 0x80, 0x2b, 0xc7, 0xfb, 0x77, 0xca, 0xd1, 0x0a, 0xca, 0xfe, 0xfc, 0xe5, 0xfa, - 0x9a, 0x37, 0x35, 0x63, 0xb3, 0x91, 0x7a, 0x3a, 0x37, 0x39, 0xcc, 0x97, 0x80, 0xea, - 0x81, 0x50, 0x73, 0xde, 0x8e, 0xb4, 0x2e, 0x3f, 0x66, 0x93, 0xe8, 0x52, 0xbe, 0xfd, - 0xde, 0xdd, 0x61, 0x91, 0x29, 0xd0, 0xaa, 0x13, 0xc4, 0xbd, 0x83, 0x86, 0x22, 0xb5, - 0xe3, 0x28, 0x56, 0x35, 0x8e, 0x6d, 0x82, 0x78, 0x78, 0x95, 0x7e, 0x5d, 0xc8, 0x2c, - 0xd4, 0x37, 0x0b, 0x66, 0x10, 0x84, 0x9e, 0x95, 0x6d, 0x0a, 0x7c, 0xdf, 0xf5, 0x61, - 0x8f, 0x5c, 0x2c, 0xea, 0x61, 0x23, 0x0b, 0x47, 0x00, 0x1c, 0x30, 0xe5, 0xa8, 0xf9, - 0x37, 0xca, 0x7f, 0x9f, 0x9e, 0x66, 0x0f, 0xfa, 0xa7, 0x71, 0x80, 0xcb, 0xa2, 0x6f, - 0x90, 0xda, 0x00, 0x7c, 0xda, 0x40, 0x57, 0xa6, 0xce, 0xa2, 0xe2, 0x6b, 0xfd, 0xe5, - 0x0c, 0x7f, 0x90, 0x79, 0x88, 0x00, 0x53, 0xd0, 0x5d, 0xaa, 0xaa, 0xb3, 0xd7, 0xe4, - 0xdc, 0x9d, 0x81, 0xd0, 0x99, 0x0d, 0x2b, 0xc3, 0x69, 0xa6, 0x6b, 0x55, 0xac, 0x8b, - 0x63, 0x97, 0xbd, 0x47, 0xdb, 0x42, 0x89, 0xc5, 0x45, 0x22, 0x85, 0x55, 0x1a, 0xaa, - 0x7f, 0xa6, 0x7b, 0x01, 0x36, 0xcd, 0x11, 0x9f, 0x87, 0xd8, 0x21, 0x9e, 0x00, 0x02, - 0x97, 0xf0, 0x2c, 0x0c, 0xe6, 0xe3, 0x7b, 0x62, 0x0f, 0x5e, 0x47, 0xfc, 0xa0, 0x3a, - 0xcd, 0xd6, 0x54, 0x4a, 0x47, 0xf4, 0xde, 0xef, 0x19, 0x4f, 0x95, 0x9a, 0xdc, 0x36, - 0x8b, 0x3b, 0x5d, 0x27, 0xd3, 0x83, 0xfe, 0x2f, 0x2b, 0x52, 0x5d, 0xae, 0x04, 0x50, - 0x55, 0x06, 0x35, 0xaa, 0x21, 0x58, 0x18, 0xf7, 0xf5, 0x03, 0x78, 0x90, 0xf0, 0x53, - 0x23, 0x3f, 0x9a, 0xa5, 0x0a, 0xe2, 0x9c, 0x05, 0x56, 0xc3, 0x6d, 0x67, 0xb2, 0x64, - 0x7e, 0x54, 0xeb, 0xe7, 0x58, 0x8e, 0x1f, 0x02, 0xb3, 0xc7, 0x17, 0xdf, 0x02, 0x98, - 0x43, 0x0e, 0xc9, 0xd2, 0xbb, 0x11, 0x4b, 0x35, 0x42, 0xb7, 0x5d, 0x01, 0x0d, 0x93, - 0x4e, 0x58, 0x96, 0xe1, 0xd2, 0xd1, 0x0a, 0x09, 0x20, 0x11, 0x9d, 0xf7, 0x29, 0x2c, - 0x8c, 0x28, 0x47, 0x65, 0x0f, 0xbf, 0x42, 0x80, 0x57, 0x12, 0x8a, 0x02, 0x04, 0x0e, - 0xb3, 0xe3, 0x2d, 0xb5, 0x0c, 0xa7, 0xd8, 0xda, 0x7f, 0xf4, 0xc4, 0xa7, 0xa0, 0xe9, - 0xcf, 0x4b, 0x65, 0x2b, 0x65, 0x3d, 0x42, 0x8f, 0x83, 0xf4, 0x85, 0x33, 0x57, 0x84, - 0x1b, 0x28, 0x13, 0x80, 0x55, 0xb9, 0x13, 0x81, 0x17, 0x79, 0x0a, 0x91, 0xe2, 0x8f, - 0xaa, 0x41, 0x2f, 0xd7, 0xd0, 0x73, 0x32, 0x56, 0x73, 0x44, 0x85, 0xd1, 0xd6, 0xd1, - 0xa9, 0x8c, 0xc2, 0xd7, 0xc8, 0x2b, 0x37, 0x9e, 0x60, 0x72, 0x5d, 0x31, 0x8c, 0x14, - 0x77, 0xce, 0x49, 0x6c, 0x95, 0x86, 0x31, 0x08, 0xa1, 0xc7, 0xe4, 0xf0, 0x20, 0x0b, - 0x7a, 0x3c, 0x08, 0x8d, 0xe7, 0x7e, 0xb4, 0xbc, 0x95, 0xa1, 0xc6, 0xc8, 0x39, 0xd7, - 0x5f, 0xab, 0x59, 0x40, 0xd3, 0x07, 0x94, 0x24, 0xd5, 0x23, 0xd6, 0xd9, 0xa4, 0x6b, - 0xe5, 0x4e, 0x18, 0xf5, 0x29, 0xdc, 0x9e, 0x56, 0x77, 0x6c, 0x5e, 0xc4, 0x51, 0xce, - 0x28, 0x07, 0x9d, 0x37, 0x82, 0x6a, 0xec, 0x40, 0x97, 0xca, 0x7a, 0xee, 0xc8, 0x08, - 0x3f, 0xf5, 0xc4, 0x29, 0x56, 0x9f, 0x91, 0x53, 0xf6, 0x96, 0xbe, 0x62, 0xbd, 0x38, - 0xa3, 0xe7, 0x27, 0xa6, 0x8a, 0xcc, 0xdf, 0xab, 0x02, 0x9b, 0x0b, 0x21, 0xe6, 0xd0, - 0xcd, 0x46, 0x0a, 0x57, 0xd5, 0xf9, 0x03, 0xda, 0x18, 0xa6, 0x07, 0x86, 0xb3, 0x91, - 0xdd, 0x1f, 0x5b, 0xe9, 0x49, 0x82, 0x7e, 0x0c, 0xe7, 0xdf, 0xd1, 0xe0, 0x84, 0x27, - 0xf0, 0xd3, 0xc2, 0x86, 0x53, 0x78, 0xc7, 0x3d, 0x46, 0xa7, 0x3c, 0x55, 0x4a, 0x12, - 0x99, 0x86, 0x02, 0x2a, 0x4f, 0x38, 0x36, 0x0c, 0x39, 0xeb, 0x9c, 0xdd, 0x05, 0x0f, - 0x56, 0xec, 0x05, 0x95, 0x68, 0x65, 0x3c, 0x78, 0x29, 0xe0, 0xa4, 0x4f, 0x2c, 0x70, - 0x10, 0xad, 0xb6, 0x73, 0xe8, 0xde, 0x77, 0x04, 0xe5, 0x4c, 0x03, 0xa7, 0x7a, 0xb7, - 0x8e, 0x85, 0xb6, 0x3f, 0x2b, 0x91, 0x18, 0x5c, 0xa5, 0xda, 0x67, 0xd3, 0x28, 0x30, - 0x65, 0x8b, 0x54, 0xbb, 0x33, 0x58, 0x75, 0x13, 0xc4, 0x2e, 0x03, 0xb5, 0x2c, 0xeb, - 0x9a, 0x19, 0x57, 0xa9, 0xe9, 0x05, 0x84, 0x72, 0x37, 0xce, 0x44, 0x56, 0xe5, 0x33, - 0x50, 0x68, 0x26, 0x49, 0x0e, 0xc5, 0x55, 0x2b, 0x39, 0x12, 0xdb, 0x1c, 0x88, 0x0e, - 0xd4, 0x71, 0xb1, 0x09, 0x29, 0x98, 0xdc, 0xc1, 0x6f, 0xa9, 0x8d, 0x5a, 0xe9, 0xe7, - 0x6f, 0xd2, 0x9d, 0x17, 0x9f, 0xd7, 0x36, 0x59, 0x78, 0xc0, 0x80, 0x44, 0x51, 0x18, - 0x80, 0x1a, 0xc1, 0x0d, 0xc0, 0xf5, 0x78, 0x8f, 0x47, 0x86, 0x69, 0x34, 0xb9, 0x8a, - 0xad, 0xb9, 0xc6, 0x8d, 0xd8, 0x84, 0x83, 0xc1, 0x5d, 0x47, 0xaf, 0x8f, 0xf4, 0x2e, - 0x6b, 0xfb, 0xb8, 0xe0, 0xe5, 0x3a, 0x04, 0x7e, 0x58, 0xe5, 0xba, 0x90, 0xd1, 0xdb, - 0x1e, 0xa1, 0x26, 0x01, 0x7c, 0x65, 0x6d, 0x01, 0x1c, 0x68, 0x7b, 0xb0, 0x4f, 0x47, - 0xa5, 0x60, 0xef, 0x7c, 0xed, 0x23, 0x1b, 0x24, 0x38, 0x7f, 0xf4, 0x01, 0x90, 0x43, - 0xcf, 0xfd, 0x67, 0xfb, 0x9d, 0x89, 0x20, 0x06, 0xc3, 0x91, 0x7f, 0xd7, 0xa9, 0x6f, - 0xe0, 0x3d, 0x7b, 0xea, 0xa2, 0x17, 0x12, 0x8d, 0x71, 0xf0, 0xa2, 0x8a, 0x83, 0x78, - 0x7a, 0x86, 0xcf, 0xc9, 0x33, 0x69, 0xd0, 0xdd, 0x54, 0x65, 0x32, 0x7f, 0xc4, 0x29, - 0x4d, 0xae, 0x81, 0xc4, 0x35, 0x1c, 0x42, 0xa6, 0xf0, 0xa8, 0x0e, 0xef, 0xa6, 0x1d, - 0xb6, 0xa4, 0x0b, 0xb6, 0x81, 0xf5, 0x58, 0xf8, 0x1b, 0x10, 0x1e, 0xb6, 0x57, 0xf6, - 0x57, 0x27, 0xd6, 0x17, 0x69, 0x1b, 0x8b, 0xee, 0x3a, 0xa7, 0xe5, 0x75, 0xb4, 0x11, - 0xa0, 0x12, 0x8a, 0x3f, 0x24, 0x75, 0x3e, 0x52, 0xee, 0x34, 0x90, 0x04, 0xcf, 0x6d, - 0x25, 0xfa, 0xd6, 0xc4, 0x68, 0x1b, 0x02, 0xa2, 0xe1, 0x96, 0x14, 0xe8, 0x0c, 0x95, - 0x83, 0x81, 0x36, 0x2a, 0x91, 0xd3, 0xcd, 0x3b, 0x4e, 0x76, 0x58, 0x32, 0x94, 0x31, - 0x0c, 0x82, 0x41, 0x11, 0x29, 0xac, 0x97, 0xf2, 0xad, 0x5a, 0x5b, 0x9f, 0xa8, 0x64, - 0xa9, 0xc5, 0xd0, 0x2d, 0x8c, 0x92, 0xd6, 0x42, 0x44, 0xfa, 0x6c, 0x40, 0x9c, 0x21, - 0x69, 0x48, 0x62, 0xc4, 0x42, 0x7d, 0xc5, 0x1a, 0xec, 0x57, 0x7f, 0x6e, 0xa3, 0x38, - 0x05, 0x03, 0x13, 0x99, 0x91, 0xe6, 0xe8, 0x89, 0x09, 0x87, 0x64, 0x9f, 0xa7, 0xc4, - 0x3a, 0xc8, 0x03, 0xf6, 0x89, 0xb6, 0x9d, 0x70, 0xab, 0xd7, 0xef, 0xa7, 0x1c, 0xf9, - 0xa0, 0xf2, 0xa4, 0x1d, 0xf9, 0x41, 0x89, 0x76, 0xa4, 0xff, 0xa4, 0x4f, 0x43, 0x75, - 0x92, 0xf1, 0x9c, 0x09, 0xcb, 0x49, 0x31, 0xb3, 0xd3, 0xcd, 0x01, 0x59, 0x31, 0xcf, - 0xfa, 0xe1, 0x71, 0xe0, 0x8a, 0xc5, 0x92, 0x88, 0x61, 0xfc, 0xc3, 0x2e, 0x08, 0x81, - 0x15, 0x59, 0x76, 0x49, 0x66, 0xbe, 0xbc, 0x14, 0x14, 0x36, 0xb9, 0x17, 0xc5, 0x27, - 0x1b, 0x2c, 0x68, 0x0c, 0xdc, 0x50, 0x2c, 0xba, 0xd5, 0x27, 0xac, 0x08, 0x7b, 0x34, - 0x65, 0x6f, 0x75, 0x5d, 0xfb, 0xf0, 0xae, 0x5a, 0xed, 0xc8, 0x09, 0x85, 0xf6, 0x3d, - 0x0c, 0xa4, 0x4a, 0x76, 0x2f, 0x9b, 0x31, 0x1f, 0x15, 0x6d, 0xe6, 0x27, 0x74, 0x19, - 0x19, 0x99, 0x8e, 0x67, 0x44, 0x66, 0xc7, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x04, 0xc4, - 0x9e, 0xb1, 0x87, 0xfb, 0xf7, 0x5e, 0x5f, 0x7c, 0xee, 0x26, 0x1e, 0x30, 0x75, 0xc2, - 0xb2, 0xc2, 0x81, 0x2f, 0xe8, 0x32, 0x32, 0xc4, 0x1a, 0x5f, 0x10, 0xf4, 0x0b, 0x91, - 0x1e, 0xbc, 0xeb, 0xb7, 0x8c, 0x91, 0xc2, 0x0b, 0x82, 0xc0, 0x05, 0x0f, 0xe2, 0xee, - 0x10, 0x4b, 0x39, 0x20, 0xed, 0x0a, 0x05, 0xd1, 0x7b, 0x06, 0x0d, 0x99, 0xd5, 0x87, - 0x01, 0x98, 0xe6, 0x3c, 0xcf, 0x51, 0xb1, 0x5d, 0xf8, 0x0e, 0x87, 0xac, 0xbd, 0x30, - 0x12, 0x6c, 0xda, 0x2a, 0xff, 0xb8, 0xf1, 0xce, 0xcb, 0x1b, 0xaa, 0x6a, 0x91, 0x9e, - 0x0a, 0x97, 0x87, 0x91, 0x39, 0x69, 0x04, 0x44, 0x9a, 0xde, 0x4b, 0x0b, 0x02, 0x92, - 0x0f, 0xb8, 0xc0, 0xbf, 0x7f, 0xc0, 0x82, 0xeb, 0x74, 0x98, 0x73, 0xc1, 0x0d, 0x17, - 0xdb, 0xd9, 0x1f, 0xfe, 0xa9, 0x36, 0x10, 0xee, 0xea, 0x62, 0x57, 0x90, 0xad, 0xa2, - 0x8e, 0x3a, 0x2c, 0xf2, 0x2c, 0x0d, 0x4e, 0xa2, 0xb9, 0x26, 0x41, 0xf2, 0x16, 0xd3, - 0x92, 0x2c, 0x1f, 0xc3, 0x2d, 0xbc, 0x1e, 0x0e, 0x99, 0x00, 0x38, 0x6c, 0xf8, 0x98, - 0xcb, 0x8e, 0xd5, 0x6c, 0x06, 0x4e, 0x5b, 0x12, 0xb0, 0x26, 0xbf, 0x03, 0x5d, 0xfb, - 0xc4, 0xeb, 0x92, 0xce, 0x33, 0xf8, 0x2b, 0xbe, 0x48, 0xca, 0x94, 0x5f, 0x12, 0x44, - 0x83, 0x10, 0xd7, 0xb9, 0xdb, 0x85, 0xf1, 0xb0, 0x46, 0xdc, 0x9c, 0x56, 0x51, 0x2f, - 0x61, 0xe0, 0xa3, 0x96, 0x6f, 0xa4, 0xab, 0x71, 0xd1, 0x5f, 0x4e, 0x23, 0xe4, 0xe3, - 0x1c, 0xb9, 0x62, 0x10, 0x60, 0x14, 0xc4, 0xc2, 0x9e, 0xc3, 0xb9, 0x10, 0xe0, 0x72, - 0x2d, 0xac, 0x38, 0xaa, 0x4d, 0xc8, 0x1e, 0x17, 0x6d, 0x72, 0xfe, 0xaf, 0x2f, 0x93, - 0xf9, 0xec, 0xd5, 0x04, 0xcb, 0xaf, 0x95, 0x59, 0x83, 0x30, 0x09, 0xd9, 0x2c, 0x9d, - 0x2f, 0x81, 0x68, 0x7b, 0xf5, 0x89, 0xa4, 0x93, 0x66, 0xcd, 0x0a, 0xba, 0xe7, 0xa1, - 0x74, 0xa4, 0x8f, 0xf7, 0x6c, 0xd7, 0x2f, 0x02, 0xb1, 0x8a, 0xf8, 0x18, 0x75, 0x26, - 0xd4, 0x70, 0x94, 0x9c, 0xb8, 0xd9, 0x3e, 0xfe, 0x6c, 0x5b, 0xc7, 0x91, 0xca, 0x93, - 0xb1, 0x10, 0xc1, 0x82, 0x5b, 0x6a, 0xfb, 0x04, 0x5d, 0x9d, 0x8c, 0xa3, 0x51, 0xf7, - 0xad, 0xa3, 0x28, 0xfd, 0xd5, 0x2a, 0xec, 0x29, 0x77, 0xd2, 0x94, 0x0e, 0x2c, 0xdc, - 0xb2, 0x66, 0x4d, 0x78, 0xb7, 0x6a, 0xc0, 0xe0, 0x6d, 0x78, 0x8e, 0x57, 0xf8, 0x24, - 0x4f, 0x44, 0x2c, 0x88, 0x6a, 0x8f, 0x31, 0x13, 0x7c, 0xd7, 0xf1, 0x9e, 0x82, 0x21, - 0xa3, 0x85, 0xcb, 0xfb, 0x3f, 0x7f, 0x2a, 0x1e, 0x79, 0x50, 0x4b, 0xcf, 0x1a, 0xe0, - 0x83, 0xb1, 0x29, 0x02, 0xa5, 0x01, 0x2c, 0xd5, 0xea, 0x2f, 0xc8, 0x56, 0x43, 0xdd, - 0xec, 0xee, 0xf4, 0xab, 0x95, 0x93, 0x43, 0x21, 0x9b, 0x0c, 0x63, 0xdd, 0x0a, 0x8b, - 0x0e, 0x23, 0x3e, 0xfc, 0x68, 0xfc, 0x63, 0x30, 0x73, 0xe6, 0x6c, 0x59, 0x97, 0x5f, - 0x23, 0x52, 0x4b, 0x6a, 0xa1, 0xab, 0x9a, 0xe7, 0xb1, 0x33, 0xd5, 0xf3, 0x0c, 0xf9, - 0xe1, 0xd0, 0xf9, 0xba, 0xd7, 0x1f, 0x67, 0x3f, 0x5b, 0x75, 0x4c, 0xf4, 0x00, 0x99, - 0x77, 0x57, 0xa6, 0x45, 0x8a, 0xd3, 0xb9, 0xdc, 0x8e, 0xc0, 0xc6, 0x9c, 0x66, 0x09, - 0x66, 0x3b, 0x42, 0xbb, 0xb0, 0xca, 0x1a, 0x55, 0x73, 0x37, 0x42, 0x81, 0x1f, 0x0d, - 0x71, 0x30, 0xe0, 0x13, 0xfe, 0x2f, 0x88, 0x05, 0x8e, 0xe8, 0x9b, 0x90, 0xa7, 0x5c, - 0xd0, 0x69, 0xda, 0xf1, 0x00, 0x37, 0x25, 0x4d, 0x10, 0x16, 0xd3, 0xac, 0xf7, 0xe6, - 0x2f, 0x18, 0x3b, 0x2c, 0x55, 0x1a, 0x59, 0x90, 0xe4, 0xed, 0x73, 0xdc, 0xd8, 0x94, - 0xf7, 0x85, 0x70, 0xfd, 0x19, 0x56, 0xcb, 0x22, 0x7c, 0x65, 0x00, 0x01, 0xf2, 0x7f, - 0x94, 0x23, 0xf4, 0xed, 0x12, 0x56, 0x0b, 0x2e, 0x1c, 0x8d, 0xbc, 0xb4, 0xc3, 0x02, - 0x15, 0xb2, 0x16, 0x7f, 0x02, 0xef, 0xeb, 0x70, 0x7a, 0xf1, 0xb5, 0xc7, 0x84, 0xb7, - 0xf5, 0x8b, 0x2e, 0x51, 0x73, 0x03, 0xf3, 0xaf, 0x71, 0xb1, 0xee, 0x39, 0xa9, 0xae, - 0x06, 0xb9, 0x77, 0x28, 0xe6, 0x4f, 0x67, 0x6d, 0xed, 0x50, 0xa3, 0xf5, 0x1b, 0xc9, - 0xe0, 0x17, 0x07, 0xbf, 0x57, 0x95, 0x6f, 0x01, 0xb7, 0xda, 0x7c, 0x23, 0xe6, 0x93, - 0x52, 0x06, 0x57, 0x28, 0x6f, 0xe7, 0x3e, 0xee, 0x9e, 0xb1, 0xd5, 0x83, 0x75, 0x22, - 0x03, 0xf3, 0xd9, 0x2b, 0xd4, 0x04, 0x7b, 0x83, 0xfd, 0x38, 0xf5, 0x66, 0xdd, 0x25, - 0xb9, 0x6d, 0x11, 0xb7, 0x22, 0x2b, 0x67, 0x82, 0xda, 0xde, 0xf5, 0xee, 0x78, 0x82, - 0x14, 0x7c, 0xbb, 0x4f, 0xcf, 0xe7, 0x0d, 0x2c, 0xa7, 0xf3, 0x9a, 0x29, 0x7b, 0x21, - 0xd5, 0x6d, 0x66, 0x10, 0xe9, 0xda, 0x9d, 0x8e, 0xef, 0xdc, 0x69, 0x9e, 0x4a, 0x30, - 0x06, 0x8a, 0x14, 0x57, 0xcf, 0x5e, 0xaf, 0x69, 0x87, 0x78, 0x21, 0xd3, 0x9e, 0xa0, - 0x85, 0x94, 0xc2, 0xfb, 0x9e, 0xb9, 0xd8, 0x04, 0x64, 0x50, 0xe4, 0x13, 0x03, 0xf1, - 0x95, 0xbd, 0xc9, 0x05, 0xe4, 0xf2, 0x58, 0x3c, 0x6a, 0xe3, 0x86, 0x1b, 0x87, 0x19, - 0xbb, 0xce, 0xd1, 0xce, 0x58, 0xc4, 0x68, 0x81, 0x6d, 0x45, 0x15, 0xe6, 0x09, 0x7b, - 0x3e, 0x2e, 0x81, 0x82, 0x21, 0x0f, 0x6c, 0x1b, 0xb3, 0xaa, 0xa6, 0x2a, 0xe0, 0xf6, - 0x9f, 0x79, 0xfc, 0xc5, 0x47, 0xba, 0xab, 0x31, 0x1d, 0x99, 0x7c, 0x84, 0x95, 0xd6, - 0xab, 0xe3, 0xa5, 0x1f, 0x56, 0x53, 0xf3, 0x1c, 0x5a, 0x2e, 0xea, 0x8d, 0x31, 0x90, - 0x97, 0xf3, 0x04, 0x5e, 0x6c, 0x3c, 0x3d, 0x8c, 0x87, 0xc9, 0xbd, 0x55, 0xb4, 0x19, - 0x2e, 0xbf, 0x00, 0xff, 0x8f, 0xc7, 0xf4, 0x1e, 0x18, 0x93, 0x0a, 0x99, 0x72, 0xa3, - 0x4d, 0x9e, 0x6a, 0xa9, 0xd9, 0x1d, 0x2e, 0x28, 0x17, 0xeb, 0x6d, 0xe9, 0xba, 0x38, - 0x9e, 0x69, 0xaa, 0x51, 0x2f, 0x3f, 0xb4, 0xdf, 0xf8, 0xca, 0x1c, 0xe7, 0xc9, 0xca, - 0x39, 0x6e, 0x8a, 0x9d, 0x99, 0xd4, 0x96, 0x51, 0xb0, 0x58, 0x2f, 0xc5, 0x86, 0xce, - 0x92, 0x7e, 0xa2, 0x64, 0x5b, 0xda, 0xa3, 0x79, 0x28, 0x6f, 0x95, 0xd3, 0x9b, 0x95, - 0x81, 0xde, 0xb2, 0xc5, 0x37, 0x75, 0xae, 0xef, 0x20, 0xe7, 0xbd, 0xbc, 0x3b, 0x19, - 0xd8, 0x9b, 0xac, 0xee, 0xa1, 0x3b, 0x74, 0xe6, 0xc7, 0xf5, 0x20, 0x89, 0x39, 0x7d, - 0x11, 0x6e, 0xbf, 0xac, 0x6a, 0x30, 0xed, 0x27, 0xd6, 0x27, 0x81, 0xa0, 0x3b, 0x66, - 0xb0, 0x52, 0xf7, 0x51, 0xfb, 0x36, 0x88, 0x2b, 0x9a, 0x14, 0x34, 0x23, 0xad, 0x02, - 0xf3, 0x36, 0x0a, 0xfa, 0x54, 0xc4, 0xcf, 0x23, 0x53, 0x0c, 0x68, 0xd6, 0x0e, 0x99, - 0x56, 0x1c, 0xce, 0x0d, 0x6a, 0x9c, 0x32, 0xef, 0xc7, 0x1f, 0xef, 0xaf, 0x23, 0x57, - 0x86, 0x3f, 0xa0, 0xb9, 0xf7, 0xbe, 0x76, 0xc2, 0xd1, 0xd3, 0x88, 0x49, 0xa0, 0x0a, - 0xb0, 0x41, 0xf1, 0x82, 0xad, 0x63, 0x35, 0xe9, 0x55, 0xcc, 0x65, 0xcd, 0xfd, 0x3b, - 0x69, 0x1a, 0x3d, 0x96, 0xc4, 0xbd, 0x56, 0xf5, 0x25, 0xce, 0xdb, 0x7f, 0xdc, 0xb7, - 0x33, 0xe7, 0x67, 0x06, 0x2f, 0xd8, 0xa4, 0xef, 0x1a, 0x4b, 0x71, 0x5e, 0x5e, 0xdf, - 0x76, 0x26, 0x14, 0x4e, 0x28, 0x5f, 0x2b, 0x3c, 0x4e, 0x2c, 0xb4, 0x1b, 0x7d, 0xb9, - 0x66, 0x35, 0x82, 0xad, 0x65, 0xa5, 0x41, 0x6e, 0x57, 0xf7, 0x48, 0x5f, 0x39, 0xc0, - 0x5e, 0x8e, 0x7a, 0xf9, 0x6b, 0x36, 0x78, 0xc8, 0x0a, 0x8d, 0x4b, 0xa2, 0xf9, 0x5d, - 0x5f, 0xeb, 0x0c, 0xcb, 0x0f, 0x71, 0x7b, 0x9d, 0xb7, 0x24, 0xab, 0xf4, 0xcc, 0xd4, - 0x10, 0x49, 0x00, 0x18, 0x6f, 0x4a, 0x93, 0x0d, 0x4b, 0x2a, 0xcb, 0x9f, 0x9a, 0x16, - 0xaf, 0x89, 0x77, 0x27, 0x7d, 0x6f, 0x0b, 0xc9, 0x0a, 0xb8, 0x59, 0xc3, 0x33, 0x3b, - 0x3d, 0xe8, 0x6f, 0x41, 0xfa, 0x85, 0xd5, 0x70, 0xf1, 0x6c, 0x74, 0x82, 0x0a, 0x70, - 0x41, 0xfe, 0xa1, 0x5e, 0xe9, 0x50, 0xc3, 0x30, 0xac, 0xa3, 0xf1, 0xe5, 0x1c, 0x69, - 0x44, 0x74, 0x72, 0xf2, 0x6a, 0x3d, 0x67, 0x41, 0xbc, 0x67, 0xe9, 0x2e, 0x00, 0xa0, - 0x83, 0xb6, 0x95, 0x33, 0x03, 0xb3, 0x73, 0x1c, 0xf2, 0x84, 0x8d, 0x81, 0x7c, 0xeb, - 0x77, 0xf1, 0xcc, 0xa7, 0x1e, 0xc9, 0x13, 0x91, 0x20, 0x2b, 0x73, 0x4d, 0x54, 0x8f, - 0xa3, 0x14, 0x2c, 0x37, 0xe6, 0xfc, 0xac, 0x51, 0x92, 0xfc, 0xa2, 0x8d, 0x63, 0x98, - 0x1f, 0x67, 0xdd, 0xdc, 0x28, 0xb3, 0x1f, 0xd0, 0xb9, 0x3a, 0x7f, 0x21, 0x88, 0xc1, - 0xec, 0xa2, 0xc1, 0xef, 0xa4, 0x61, 0xd2, 0xdd, 0x73, 0x38, 0xdf, 0x07, 0x05, 0xae, - 0x70, 0x10, 0x62, 0xfb, 0xcd, 0x8d, 0x50, 0x29, 0x98, 0x85, 0xd8, 0xe3, 0xd4, 0xfb, - 0xd6, 0xa4, 0xf2, 0x15, 0x5d, 0xc8, 0xd8, 0xfd, 0x0b, 0x05, 0x8f, 0x3c, 0x77, 0x50, - 0x83, 0xf5, 0x96, 0x12, 0xac, 0x66, 0x02, 0xd9, 0xad, 0xfa, 0x49, 0xe2, 0x60, 0x2a, - 0x12, 0xf2, 0x90, 0x0d, 0x22, 0xb9, 0x9c, 0x0b, 0x8a, 0x32, 0x68, 0xa0, 0x19, 0xc0, - 0xdd, 0xf3, 0x14, 0x3e, 0x8a, 0xf4, 0x13, 0x07, 0xd9, 0x26, 0x74, 0x02, 0x13, 0x08, - 0x59, 0xee, 0x92, 0x43, 0x4d, 0x23, 0x79, 0xe9, 0x4b, 0xcb, 0xbe, 0x56, 0x1d, 0xe0, - 0x42, 0x92, 0xb5, 0x32, 0xab, 0xc3, 0x5d, 0xde, 0x53, 0xd2, 0xad, 0x86, 0x7f, 0x7a, - 0xd9, 0x42, 0x00, 0xe4, 0x8e, 0x50, 0x3e, 0x7d, 0x41, 0x6b, 0xcf, 0x98, 0x29, 0x9f, - 0x82, 0xfc, 0xba, 0xe2, 0xdc, 0x42, 0xae, 0xc1, 0x8a, 0x29, 0x3b, 0x63, 0x79, 0x5b, - 0x68, 0x63, 0xf3, 0x22, 0x49, 0xcd, 0x20, 0x5e, 0x54, 0xd7, 0xcb, 0x7c, 0x82, 0x3b, - 0x00, 0x74, 0x77, 0x35, 0x96, 0xc1, 0xc5, 0x33, 0x92, 0x1d, 0x3b, 0xae, 0x11, 0xfe, - 0x1c, 0x6b, 0xfb, 0x77, 0x74, 0xe1, 0x49, 0x88, 0x64, 0xf3, 0xb6, 0x26, 0xd4, 0xcb, - 0x14, 0x47, 0x95, 0xd8, 0xf3, 0x59, 0xf5, 0xc5, 0x5d, 0xa3, 0xd7, 0x11, 0x70, 0x4e, - 0x74, 0x29, 0x58, 0x95, 0x5e, 0xaf, 0xa4, 0xb7, 0xd0, 0x31, 0xb2, 0xd6, 0xda, 0x0c, - 0x52, 0x9d, 0x41, 0xf3, 0x16, 0x93, 0xe4, 0xe5, 0x10, 0xb6, 0xb1, 0xe4, 0xab, 0xb6, - 0x01, 0x5f, 0x0d, 0x6d, 0x12, 0x61, 0x5e, 0xc1, 0xea, 0xf2, 0x75, 0xd4, 0x62, 0x96, - 0x2f, 0x17, 0x68, 0x4a, 0x7a, 0x25, 0x30, 0x1a, 0x99, 0x55, 0x5d, 0xef, 0x47, 0x15, - 0xff, 0x62, 0xce, 0x3c, 0xa6, 0x2f, 0x82, 0xe1, 0xf0, 0xec, 0x3b, 0x76, 0xd9, 0xea, - 0x82, 0x5a, 0xbc, 0x46, 0xfa, 0x2c, 0xf2, 0xb7, 0xa9, 0x64, 0x3e, 0xf2, 0x11, 0x0d, - 0x16, 0xef, 0x7a, 0x37, 0x0a, 0x5a, 0x99, 0xc0, 0xf7, 0x3d, 0xd2, 0x07, 0xb7, 0xba, - 0xc5, 0x2f, 0x36, 0x7d, 0xc4, 0xba, 0x9f, 0x52, 0x1c, 0x2d, 0x48, 0x77, 0xba, 0x68, - 0x98, 0xb8, 0xc9, 0x0c, 0x6d, 0xa7, 0x33, 0x64, 0x5c, 0xfb, 0x78, 0xc6, 0xf4, 0x09, - 0x92, 0xc7, 0x20, 0x96, 0x8f, 0xe4, 0x3c, 0x32, 0xbb, 0x59, 0x39, 0x9b, 0xa8, 0x82, - 0x36, 0x06, 0x4a, 0xa0, 0xa6, 0x8f, 0x1a, 0x5a, 0xfa, 0xae, 0xd0, 0xf5, 0x39, 0xc2, - 0x4e, 0xf9, 0xe6, 0x9d, 0x37, 0xdd, 0xba, 0x2d, 0x15, 0x86, 0xc0, 0x3b, 0x52, 0x45, - 0x48, 0xd8, 0x20, 0x7d, 0xa9, 0x58, 0x92, 0xc0, 0x0a, 0xcf, 0xee, 0x51, 0xb2, 0x42, - 0x4c, 0x2d, 0x1a, 0x4d, 0x7d, 0x4d, 0xd9, 0x8a, 0x1c, 0x6f, 0x2a, 0x5f, 0x6b, 0x39, - 0x20, 0x64, 0x30, 0xf1, 0x84, 0x37, 0x3a, 0x96, 0xc6, 0xaa, 0x58, 0xcc, 0xe2, 0xe1, - 0xc5, 0x04, 0xd4, 0x0e, 0xe9, 0xef, 0xda, 0x58, 0x8d, 0x43, 0xef, 0xb1, 0xda, 0x53, - 0xc7, 0x3d, 0x53, 0x0f, 0xa7, 0x6b, 0x11, 0x2f, 0x33, 0xb4, 0xaf, 0xa9, 0x41, 0xcd, - 0x1e, 0x20, 0x5a, 0xcd, 0x72, 0xca, 0x86, 0x84, 0xad, 0xe8, 0x33, 0x3d, 0x46, 0x32, - 0xab, 0x94, 0x3d, 0x69, 0x0f, 0x13, 0x2b, 0xc9, 0x9f, 0x5c, 0x5a, 0x1d, 0x3e, 0xa4, - 0xe0, 0xca, 0x8f, 0x43, 0x23, 0x8c, 0xd9, 0xeb, 0x09, 0xc8, 0xbf, 0x11, 0xe9, 0x18, - 0xa9, 0xc7, 0xf8, 0x83, 0xbe, 0x94, 0x89, 0x06, 0x56, 0x33, 0x66, 0x67, 0x95, 0x4a, - 0x51, 0xa8, 0xae, 0xcd, 0xc4, 0xcb, 0xd3, 0x9a, 0xca, 0xc7, 0x52, 0x05, 0x6e, 0x71, - 0xcc, 0x96, 0x91, 0x55, 0xdd, 0x65, 0x6d, 0x79, 0x59, 0x00, 0x8c, 0x0e, 0xcf, 0x61, - 0x83, 0x2a, 0x5c, 0x44, 0xe2, 0xe0, 0xde, 0x68, 0xf5, 0x04, 0xc1, 0x77, 0xdf, 0x68, - 0x8b, 0xee, 0x55, 0x8c, 0x6f, 0x4e, 0x5e, 0xa5, 0xf9, 0xad, 0x78, 0x26, 0x73, 0x40, - 0xe2, 0xc8, 0x35, 0xb9, 0x74, 0xdd, 0x12, 0xcd, 0xb9, 0x05, 0x08, 0x87, 0x60, 0x34, - 0xdd, 0xde, 0x0d, 0x97, 0xea, 0xfa, 0xf9, 0x70, 0x18, 0x34, 0x90, 0xcd, 0x22, 0xea, - 0x57, 0xb9, 0x8a, 0xbd, 0x1a, 0x7f, 0x79, 0xe2, 0xcf, 0x23, 0xcf, 0x8d, 0x1b, 0x0e, - 0x9b, 0x7c, 0x93, 0x8a, 0xcc, 0x6b, 0x14, 0x4b, 0x54, 0x13, 0xd3, 0x2f, 0x50, 0xcd, - 0x09, 0x61, 0x8f, 0xa9, 0x74, 0x10, 0x3a, 0x72, 0x8e, 0x2b, 0x71, 0x76, 0x63, 0xd4, - 0xbd, 0x9b, 0x07, 0x20, 0xb7, 0x75, 0xf5, 0xee, 0x25, 0xa6, 0xd7, 0x4d, 0x12, 0x8c, - 0x49, 0xb4, 0x0a, 0x19, 0x74, 0x1c, 0x37, 0xdd, 0x34, 0x61, 0x6d, 0xb3, 0x1e, 0xac, - 0x0b, 0xe7, 0xf5, 0x3f, 0xfa, 0x61, 0x9f, 0x45, 0x18, 0x1f, 0x5a, 0x4d, 0xbe, 0x5b, - 0x1b, 0x48, 0x09, 0x8e, 0xba, 0x2c, 0x2e, 0xc2, 0x0a, 0x0a, 0xc0, 0x44, 0x3b, 0xa8, - 0xe9, 0x48, 0x7b, 0xcf, 0x7d, - ], - script_code: vec![0xac, 0x53, 0x63, 0x52, 0x6a, 0x51, 0xac], - transparent_input: None, - hash_type: 1, - amount: 1501997449504444, - consensus_branch_id: 1991772603, - sighash: [ - 0xa1, 0xcf, 0x50, 0xcf, 0xfe, 0x59, 0xbe, 0x5f, 0x31, 0x5f, 0xfe, 0x51, 0x6e, 0x28, - 0x9e, 0xe8, 0x02, 0x5e, 0x59, 0x38, 0xf1, 0xe8, 0xe1, 0x88, 0x53, 0x7f, 0xf1, 0xa8, - 0x93, 0xac, 0x71, 0x14, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0x88, 0x1d, 0xdf, 0x4f, 0x95, - 0x78, 0x97, 0x34, 0xfc, 0xc1, 0x65, 0xee, 0x1e, 0x04, 0x40, 0x85, 0xb6, 0xe7, 0xa1, - 0x77, 0x50, 0x8c, 0x29, 0xda, 0x0c, 0xe7, 0x7d, 0xed, 0x75, 0x08, 0x98, 0xde, 0x89, - 0xd2, 0x60, 0xd3, 0x02, 0x63, 0x52, 0x44, 0xcc, 0x75, 0xe1, 0x98, 0x34, 0x52, 0x5f, - 0xba, 0x56, 0x90, 0x0d, 0xe9, 0x93, 0x85, 0x44, 0x2e, 0xb9, 0xec, 0x9a, 0x5f, 0x18, - 0x2b, 0x87, 0x5d, 0x70, 0xb5, 0xb1, 0x53, 0x79, 0x0a, 0x1e, 0xe7, 0x9c, 0x0e, 0x86, - 0x78, 0x37, 0x95, 0xfa, 0x06, 0x6a, 0x00, 0x63, 0x00, 0x00, 0x63, 0xfc, 0x92, 0x29, - 0x92, 0x00, 0x83, 0x64, 0xff, 0xfc, 0x7c, 0x00, 0xc0, 0x0e, 0x0f, 0x99, 0xde, 0x47, - 0x42, 0x89, 0x06, 0x00, 0x01, 0x39, 0x21, 0x97, 0xd6, 0x23, 0xf7, 0xeb, 0xda, 0x07, - 0xcd, 0x00, 0x58, 0xd9, 0xa1, 0xd1, 0x72, 0x04, 0x3c, 0x2f, 0xc9, 0x4f, 0x14, 0x19, - 0x3e, 0x27, 0x0e, 0xef, 0xe8, 0x3c, 0x3f, 0x01, 0xb2, 0x65, 0x05, 0x4c, 0x3f, 0x6a, - 0x60, 0xe2, 0xb7, 0x6e, 0x17, 0x56, 0x08, 0x8b, 0x87, 0xda, 0x83, 0x9f, 0x77, 0x2c, - 0xbd, 0x0f, 0x27, 0x5c, 0x92, 0x28, 0x38, 0x5a, 0x04, 0xbb, 0x50, 0xec, 0x3c, 0xfa, - 0x9e, 0xe2, 0xe1, 0x5b, 0x15, 0x3d, 0x4c, 0x85, 0xfe, 0x50, 0xb6, 0x00, 0x62, 0x58, - 0xe9, 0xe8, 0xc2, 0x52, 0x99, 0xc0, 0x9d, 0xf8, 0xb4, 0x55, 0x46, 0x6b, 0xa2, 0x5f, - 0x7e, 0x4c, 0x8f, 0xe7, 0xe2, 0x50, 0xed, 0xba, 0x60, 0x69, 0x5d, 0xa4, 0x7f, 0xaa, - 0xfd, 0xd6, 0x26, 0xba, 0x7e, 0x9d, 0x48, 0x96, 0xe4, 0xb8, 0xa8, 0xa1, 0xa1, 0xdc, - 0x21, 0x5b, 0x0a, 0x25, 0xee, 0xb0, 0x4e, 0xd1, 0xbe, 0xfb, 0x5b, 0x31, 0x38, 0xc6, - 0x9f, 0xe5, 0x28, 0xe7, 0x29, 0x11, 0x23, 0xfc, 0xdf, 0x8a, 0x36, 0x6c, 0x25, 0x7d, - 0x32, 0x95, 0x38, 0x25, 0x0a, 0x0c, 0xb7, 0xf5, 0x4e, 0x1c, 0x01, 0x6c, 0xe1, 0xc6, - 0x23, 0xb2, 0xe2, 0x76, 0xa5, 0x2c, 0x6e, 0x41, 0x24, 0x1b, 0x2a, 0xc5, 0x09, 0x37, - 0x3c, 0x18, 0x81, 0x40, 0xe8, 0x36, 0x5c, 0x94, 0xf5, 0x8c, 0x63, 0xf2, 0x7f, 0xf8, - 0xe6, 0xe8, 0x69, 0xa9, 0x85, 0xaf, 0xb6, 0x1e, 0x97, 0xd8, 0xce, 0xec, 0x2a, 0x78, - 0x24, 0xa5, 0xc1, 0x07, 0xb0, 0xba, 0xa4, 0xd6, 0xe7, 0x9a, 0x6c, 0x71, 0x87, 0x2a, - 0x7b, 0x3b, 0x17, 0xef, 0x91, 0x8a, 0xe4, 0xe2, 0x5f, 0x98, 0xa7, 0x2d, 0xb5, 0x3b, - 0xa7, 0xf2, 0x6e, 0x40, 0x8b, 0xd4, 0xd1, 0xf9, 0xe3, 0x47, 0x4d, 0xdc, 0xa5, 0x83, - 0x3f, 0xf5, 0xff, 0x8d, 0x11, 0xb1, 0xbf, 0x1e, 0x2b, 0xb4, 0xd1, 0x96, 0x8a, 0x82, - 0x38, 0x88, 0xbd, 0x91, 0xa2, 0x1a, 0x76, 0x79, 0x6b, 0xca, 0x44, 0x53, 0xe2, 0x89, - 0x2d, 0x1b, 0x6e, 0x13, 0x63, 0xed, 0x10, 0x7a, 0x9e, 0x7e, 0xd9, 0x3f, 0xb1, 0xda, - 0x99, 0x4a, 0x9d, 0x4e, 0x7e, 0xc9, 0x2e, 0x29, 0xa6, 0x87, 0xf2, 0x18, 0xd2, 0x8a, - 0x76, 0x46, 0x06, 0x9b, 0xca, 0xcb, 0x4d, 0xa7, 0xba, 0xdf, 0x4e, 0xb1, 0x33, 0x1a, - 0xab, 0x21, 0x2b, 0x92, 0xc6, 0xea, 0x64, 0x76, 0xa0, 0xa0, 0x9d, 0x6b, 0xd2, 0xe0, - 0xf7, 0x6f, 0xa8, 0x73, 0x79, 0xab, 0xfd, 0x17, 0x58, 0x2f, 0x3e, 0xb2, 0x3b, 0x86, - 0xc9, 0x66, 0x9f, 0x86, 0x73, 0x70, 0x48, 0xd7, 0x71, 0x84, 0x9b, 0x8f, 0x70, 0xbd, - 0x87, 0x99, 0x01, 0x3b, 0xe0, 0xbf, 0xbd, 0x7b, 0x57, 0xbe, 0xa1, 0xa4, 0x9a, 0x4a, - 0x39, 0x14, 0x79, 0x12, 0xd7, 0xba, 0xf6, 0x80, 0x04, 0xd4, 0x15, 0x02, 0x6b, 0xbc, - 0x6f, 0x69, 0x32, 0x5f, 0x4f, 0xf7, 0x87, 0x28, 0x77, 0x5a, 0x67, 0xaa, 0xdd, 0x72, - 0x2c, 0x73, 0x31, 0x1d, 0xba, 0x5c, 0x2c, 0xf1, 0x4c, 0xcb, 0xd5, 0x7e, 0xab, 0xed, - 0x71, 0x92, 0x0f, 0xf9, 0x62, 0x32, 0x89, 0xbb, 0x76, 0x05, 0x1c, 0x73, 0xa2, 0x06, - 0xa3, 0xc2, 0xb4, 0x0c, 0xac, 0x01, 0xd5, 0xf1, 0x1f, 0xa6, 0x4c, 0x1b, 0x7d, 0xed, - 0x70, 0xea, 0x17, 0x42, 0x9c, 0x66, 0x21, 0xca, 0x9b, 0x92, 0x3c, 0x48, 0x11, 0x85, - 0x0c, 0x3d, 0xf4, 0x01, 0x3d, 0x17, 0xbd, 0xc5, 0x10, 0x1c, 0x8d, 0x80, 0xb3, 0xa0, - 0x4a, 0x4c, 0xc2, 0x3d, 0x13, 0xfe, 0x31, 0x84, 0xe8, 0xb1, 0xad, 0xe6, 0x35, 0x17, - 0x59, 0x3f, 0x7b, 0xe6, 0x69, 0x48, 0xc0, 0x85, 0x7a, 0xec, 0xe0, 0x1b, 0xc2, 0x72, - 0x29, 0x5e, 0x60, 0xb1, 0x80, 0x69, 0x46, 0xc9, 0x3b, 0xc8, 0xc7, 0xd2, 0xa2, 0xed, - 0xc3, 0x7f, 0xa3, 0x7c, 0x47, 0x7a, 0x69, 0xa9, 0x0b, 0x59, 0xb4, 0xc6, 0x91, 0x2e, - 0x91, 0x3a, 0x57, 0xef, 0xa9, 0xd5, 0x4c, 0x7e, 0x80, 0xd5, 0xac, 0x8a, 0x42, 0x94, - 0xd0, 0xfd, 0x31, 0xa4, 0x02, 0xe4, 0xb4, 0x7e, 0xc7, 0xbf, 0x03, 0x31, 0xb2, 0xc9, - 0xa4, 0x8f, 0x44, 0x57, 0x3f, 0xc7, 0xe7, 0xf1, 0x02, 0xed, 0x48, 0xc9, 0x75, 0x08, - 0xcb, 0xe4, 0x30, 0x65, 0xa9, 0xe9, 0x9f, 0xb4, 0xce, 0x13, 0x62, 0xbb, 0x8a, 0x76, - 0xb1, 0x41, 0x9d, 0x95, 0x03, 0x0e, 0x9c, 0x24, 0xee, 0xba, 0x9f, 0xf8, 0xcf, 0xda, - 0x95, 0x7b, 0x17, 0x09, 0x8c, 0xdf, 0x8c, 0x9a, 0x91, 0x9e, 0x47, 0xa1, 0x3a, 0x5b, - 0x33, 0x46, 0xe3, 0x7e, 0x82, 0x7c, 0xc8, 0x3b, 0x3c, 0x9a, 0xab, 0xf2, 0xd0, 0xba, - 0x17, 0xff, 0x3d, 0x9e, 0x0d, 0x22, 0x3c, 0x41, 0xc8, 0x8e, 0xc2, 0x39, 0x1c, 0x76, - 0x62, 0x2d, 0x7b, 0xd6, 0x21, 0x17, 0x33, 0x1e, 0x21, 0xff, 0xec, 0x32, 0x72, 0xc1, - 0xe1, 0x42, 0x39, 0x82, 0xc6, 0xb6, 0x3a, 0xec, 0x8d, 0xbf, 0x5c, 0xa2, 0xdd, 0x15, - 0x81, 0x0f, 0x53, 0x42, 0xaf, 0x49, 0xfa, 0xd2, 0x79, 0xb7, 0xca, 0x23, 0xde, 0xd3, - 0x08, 0x24, 0x79, 0x96, 0x30, 0xde, 0xdc, 0x6d, 0xb7, 0x24, 0xbc, 0xe1, 0x11, 0x36, - 0x21, 0xc4, 0xa6, 0x47, 0x9d, 0xd5, 0x55, 0xf4, 0x85, 0x21, 0x7c, 0xb5, 0x67, 0x13, - 0x9e, 0xea, 0xdd, 0x7e, 0xe8, 0xdc, 0x5b, 0x26, 0x62, 0xf1, 0x06, 0x6a, 0x7c, 0x60, - 0xde, 0xe0, 0x09, 0x3c, 0x92, 0x46, 0xde, 0x7a, 0x05, 0xe8, 0xb0, 0xf6, 0xbe, 0xf0, - 0x03, 0x3d, 0xde, 0x2e, 0x87, 0xcb, 0xa6, 0x8d, 0x23, 0x6e, 0xf6, 0x6a, 0x23, 0xd5, - 0x5e, 0x7b, 0xd2, 0x8d, 0x02, 0x59, 0x9c, 0xca, 0x0d, 0xf7, 0xa9, 0x00, 0x63, 0x7b, - 0xb3, 0x46, 0x4d, 0x62, 0x2b, 0x7c, 0x9c, 0x9c, 0x8c, 0x91, 0x46, 0x89, 0x74, 0x88, - 0x01, 0x64, 0xde, 0xf7, 0x99, 0x90, 0x8a, 0x11, 0xa5, 0x91, 0xab, 0xb3, 0xc8, 0xd8, - 0xbd, 0x9c, 0x12, 0xb1, 0xf6, 0xf3, 0xcd, 0xc9, 0xed, 0x8e, 0x16, 0xe5, 0x7d, 0x23, - 0x34, 0xb2, 0x17, 0x79, 0x7d, 0xf1, 0x90, 0x52, 0xfe, 0xeb, 0xed, 0x6c, 0xdb, 0x99, - 0xac, 0x44, 0xea, 0x13, 0xaf, 0xea, 0xc4, 0x37, 0x7d, 0x0f, 0xa3, 0x7e, 0xf5, 0x16, - 0xdd, 0xac, 0xea, 0xb0, 0xd9, 0x39, 0x5b, 0xd4, 0x40, 0x46, 0x0e, 0x28, 0xb5, 0xf5, - 0x7a, 0x6e, 0xfd, 0x37, 0xd2, 0x68, 0xa8, 0x64, 0xcb, 0x5c, 0xa3, 0x4b, 0xe2, 0x87, - 0xe1, 0x04, 0x8e, 0xfc, 0x1e, 0x40, 0xcd, 0xf4, 0xfc, 0xfc, 0x02, 0x4c, 0xf1, 0x82, - 0x03, 0x8b, 0x9d, 0x80, 0xed, 0x1c, 0x07, 0x63, 0x62, 0x00, 0xc8, 0x19, 0xa7, 0xe7, - 0xc2, 0x40, 0xc3, 0xc4, 0xf7, 0xa9, 0x17, 0x32, 0xe3, 0xff, 0x13, 0xe2, 0xa5, 0x6a, - 0x64, 0x66, 0x66, 0x10, 0xca, 0xd9, 0x84, 0x1c, 0x1a, 0x93, 0x4f, 0xe9, 0x33, 0xb0, - 0xf1, 0x9f, 0xb7, 0x1d, 0x06, 0x1c, 0x58, 0xf2, 0x1a, 0x49, 0x81, 0xce, 0x3e, 0x68, - 0xc5, 0x02, 0x39, 0x03, 0x60, 0x8d, 0xe5, 0x83, 0x02, 0xc6, 0xc8, 0xde, 0xf4, 0xe5, - 0x61, 0x9e, 0xc0, 0xd9, 0x1c, 0xf9, 0x35, 0x44, 0x75, 0x97, 0x2b, 0xfe, 0x0d, 0x75, - 0x75, 0x60, 0x2a, 0xaf, 0x0e, 0x9e, 0x88, 0x5c, 0x6b, 0xaf, 0x9d, 0x56, 0x7b, 0x1f, - 0xcb, 0x63, 0x19, 0x0c, 0xb7, 0x92, 0xf1, 0xd8, 0x71, 0x61, 0x1a, 0xdb, 0x4f, 0x3d, - 0x1e, 0xd3, 0x28, 0x02, 0x69, 0x18, 0xe2, 0x8d, 0x2f, 0xd4, 0x5a, 0xb9, 0xd3, 0x70, - 0xe7, 0x29, 0x2e, 0xd7, 0x54, 0xce, 0x29, 0xfb, 0x78, 0x7f, 0xd5, 0xd0, 0x9e, 0x6d, - 0x47, 0xcb, 0xc8, 0x00, 0x21, 0xab, 0xf7, 0xd2, 0xef, 0xeb, 0xdb, 0xe0, 0xad, 0xd8, - 0x70, 0x16, 0x8f, 0x51, 0xdc, 0xc4, 0x09, 0x57, 0xa4, 0xa3, 0xc8, 0xe1, 0x92, 0x60, - 0x13, 0x83, 0xb7, 0x68, 0x41, 0x36, 0xdc, 0xa2, 0x82, 0x62, 0x3f, 0x31, 0xba, 0x7a, - 0xe5, 0x36, 0x6b, 0x45, 0x3c, 0x6a, 0x26, 0xf6, 0x8a, 0x14, 0xdb, 0x65, 0x59, 0xbc, - 0xb1, 0x02, 0x37, 0x37, 0x9a, 0x27, 0xa9, 0x50, 0x2f, 0xf9, 0xd6, 0x4a, 0x33, 0x83, - 0x20, 0x75, 0x15, 0x30, 0xf1, 0xf8, 0x92, 0xa6, 0xd4, 0x6f, 0x50, 0x31, 0x1b, 0x5e, - 0x18, 0xf0, 0x33, 0x6f, 0xc4, 0x77, 0x21, 0x56, 0x66, 0xe1, 0x88, 0x93, 0x3c, 0x69, - 0x39, 0x98, 0x9f, 0x6e, 0x6a, 0x3a, 0xdb, 0xa2, 0x29, 0x96, 0xaa, 0xe6, 0xa0, 0xfe, - 0x1b, 0xdd, 0xcb, 0xe1, 0x49, 0x6d, 0x96, 0x8d, 0xe0, 0x93, 0xdf, 0x44, 0xa3, 0x30, - 0x0f, 0x75, 0x15, 0xa1, 0x2c, 0x9d, 0x82, 0x22, 0x6d, 0x6b, 0x4d, 0x62, 0xc4, 0x6a, - 0x21, 0x3d, 0x5f, 0x01, 0x07, 0x10, 0x6f, 0xd2, 0xa2, 0x2d, 0x3b, 0x59, 0x86, 0x13, - 0xdb, 0x49, 0x1f, 0x70, 0xcc, 0xb1, 0xf0, 0x3b, 0x86, 0x59, 0x66, 0x9e, 0xd7, 0x44, - 0x34, 0xe4, 0x3b, 0x77, 0x1f, 0x22, 0x78, 0x07, 0x10, 0xfb, 0xd8, 0xf2, 0xf2, 0x0e, - 0x98, 0x97, 0xdf, 0x5c, 0xc2, 0x35, 0x48, 0x77, 0x9c, 0x6c, 0x08, 0x30, 0x83, 0x9d, - 0x23, 0x1c, 0x3f, 0xf9, 0xac, 0x54, 0x40, 0x7d, 0xfd, 0xfc, 0xc5, 0x90, 0x14, 0xbf, - 0x67, 0xd9, 0x68, 0x57, 0x06, 0xa5, 0x62, 0x2e, 0x38, 0xf7, 0xa9, 0x33, 0xc3, 0x4a, - 0xfb, 0xb6, 0xaa, 0x8c, 0xdf, 0xd9, 0x3b, 0xd2, 0xec, 0x91, 0xad, 0x37, 0x90, 0x4c, - 0xe1, 0x3b, 0x8a, 0xb8, 0xef, 0x77, 0x23, 0x66, 0xfa, 0xd3, 0xc3, 0xeb, 0xee, 0x8f, - 0x26, 0x11, 0xee, 0x7b, 0x6c, 0x2a, 0xf7, 0xe6, 0x53, 0xef, 0xbe, 0xc4, 0xdc, 0x4c, - 0xbf, 0x13, 0xac, 0xf3, 0x7e, 0x39, 0x9e, 0x2b, 0x0b, 0x05, 0xb6, 0x1c, 0xb7, 0xe1, - 0x7b, 0x15, 0x62, 0x7b, 0x62, 0x96, 0x2e, 0x21, 0x00, 0xb1, 0x95, 0xfe, 0xfe, 0x94, - 0xbc, 0x48, 0x4e, 0x88, 0x13, 0x97, 0x00, 0x73, 0x7d, 0xe1, 0xa5, 0xec, 0x7d, 0x9c, - 0xc8, 0x5d, 0x53, 0x3b, 0x61, 0xec, 0xad, 0x86, 0x53, 0xce, 0xdb, 0xb7, 0x71, 0xf6, - 0x75, 0xaf, 0x61, 0xe4, 0xc6, 0xf7, 0xef, 0xaa, 0xcc, 0x9f, 0x7e, 0x42, 0x4c, 0x16, - 0x71, 0x5b, 0x0a, 0x98, 0xc4, 0x46, 0x05, 0x9a, 0x27, 0x1a, 0x27, 0xbd, 0x56, 0x9d, - 0x1b, 0x5d, 0xbf, 0xae, 0x8f, 0x53, 0x89, 0x85, 0x24, 0xca, 0xe8, 0x70, 0x59, 0xff, - 0x34, 0xfb, 0x2a, 0x53, 0x32, 0x26, 0xbd, 0x29, 0xa0, 0xba, 0x6f, 0x8d, 0x08, 0x36, - 0xfd, 0x0a, 0x4c, 0x0d, 0x60, 0x9a, 0x72, 0xe1, 0x05, 0x39, 0xa4, 0x4f, 0x8c, 0x39, - 0xf6, 0x27, 0x9b, 0xe3, 0x96, 0xe4, 0x1c, 0xa9, 0xf2, 0x9a, 0x28, 0xce, 0x9f, 0xa0, - 0xdd, 0x51, 0xa3, 0x02, 0xe7, 0x70, 0xe1, 0xe3, 0xdb, 0x70, 0x6a, 0x34, 0xcb, 0x90, - 0x4e, 0xf0, 0x8d, 0x9c, 0x82, 0xc5, 0x5b, 0xc7, 0x28, 0xc9, 0x55, 0xb1, 0x20, 0xbb, - 0x2e, 0xc3, 0x73, 0xfc, 0xff, 0xff, 0x3c, 0x46, 0xd6, 0x03, 0xab, 0x38, 0x78, 0x96, - 0xd4, 0x9c, 0xd2, 0x1b, 0x2f, 0x77, 0xec, 0xfb, 0xbb, 0x02, 0xa5, 0xe1, 0x53, 0xb1, - 0x71, 0xaf, 0xed, 0x98, 0x6c, 0x15, 0xda, 0x6f, 0x2d, 0x4c, 0xf7, 0x45, 0xd1, 0x99, - 0x5f, 0x51, 0x36, 0xe1, 0xb3, 0xe6, 0x8a, 0x67, 0xa8, 0x99, 0x6f, 0xe7, 0x65, 0x61, - 0x6d, 0x8a, 0xa1, 0x1b, 0xcd, 0x9f, 0x8b, 0x59, 0x1d, 0xb8, 0x7e, 0xfc, 0xda, 0xaf, - 0xfd, 0x41, 0x00, 0x3e, 0xc7, 0x29, 0x36, 0x05, 0x42, 0x62, 0x08, 0x54, 0xfb, 0x04, - 0xb8, 0x0c, 0xb8, 0x61, 0xa6, 0x36, 0xa4, 0x71, 0x7d, 0x66, 0x68, 0x94, 0xc3, 0x2f, - 0x1f, 0x2b, 0xf2, 0x24, 0x7c, 0xc4, 0x15, 0xde, 0x1d, 0x0c, 0x4e, 0x71, 0x2b, 0x95, - 0x88, 0x42, 0xd6, 0xa4, 0xb2, 0x76, 0xde, 0xa5, 0xdb, 0x88, 0x42, 0x3f, 0x2b, 0x4c, - 0x66, 0x4b, 0x1d, 0x2b, 0x18, 0x77, 0xba, 0xf3, 0x37, 0x47, 0x34, 0x36, 0x14, 0xe5, - 0xeb, 0xe9, 0xb7, 0xe1, 0x2e, 0xd0, 0x15, 0x3f, 0x9c, 0xa7, 0x45, 0x8e, 0x4d, 0xa4, - 0x97, 0x63, 0x9d, 0xff, 0x13, 0x52, 0xff, 0x0e, 0xfa, 0xe0, 0x1d, 0x14, 0x03, 0x21, - 0xc2, 0x8d, 0xd0, 0xb6, 0x7b, 0x06, 0x98, 0x90, 0xf6, 0x13, 0x0f, 0x82, 0x46, 0xab, - 0x85, 0x44, 0x71, 0x75, 0x32, 0xd3, 0xa5, 0xf6, 0x36, 0x39, 0xa9, 0x9d, 0x7f, 0x8e, - 0x98, 0x31, 0xc6, 0x48, 0x51, 0xb7, 0xef, 0x68, 0x93, 0xb3, 0xc9, 0x74, 0x0f, 0x98, - 0x44, 0xd1, 0x8a, 0x61, 0x3b, 0x5f, 0x9a, 0x6a, 0xb4, 0xbd, 0x6e, 0x6a, 0x93, 0xe8, - 0xe4, 0xbe, 0xa5, 0x57, 0x5d, 0x2c, 0xb4, 0x33, 0x0c, 0x0a, 0xf8, 0x55, 0x83, 0x19, - 0xa9, 0x09, 0xa5, 0x98, 0x8a, 0x99, 0x2e, 0x40, 0x63, 0x43, 0xdd, 0x1c, 0x74, 0x2d, - 0x64, 0xcd, 0x4a, 0x17, 0xa2, 0xf3, 0x79, 0x5e, 0x8d, 0xb4, 0xd3, 0x0c, 0xcd, 0xf4, - 0x41, 0x56, 0x55, 0xed, 0xa7, 0xb4, 0x37, 0xe3, 0x39, 0x73, 0x23, 0x89, 0x6b, 0x11, - 0xb1, 0xbe, 0xd7, 0x2d, 0x63, 0xe3, 0x10, 0xaa, 0x49, 0x67, 0x1d, 0x85, 0x53, 0x4f, - 0x6d, 0xbc, 0x18, 0x1f, 0xeb, 0xb5, 0xbd, 0xc0, 0x8a, 0xc0, 0xd1, 0x23, 0x82, 0x9d, - 0x10, 0x8c, 0xd2, 0x69, 0xf3, 0xb0, 0xa3, 0x96, 0xf4, 0x24, 0x1e, 0x7d, 0xda, 0x72, - 0xf5, 0x48, 0x62, 0xbe, 0xde, 0xf0, 0x1c, 0x12, 0xe3, 0xc6, 0xcf, 0xdf, 0x75, 0xf6, - 0x76, 0xc2, 0xdd, 0xef, 0x91, 0xaf, 0x7f, 0x8a, 0x8a, 0x76, 0x9c, 0x25, 0xe1, 0x77, - 0xcd, 0x43, 0x0b, 0xed, 0xe7, 0x4b, 0x57, 0x69, 0x05, 0x19, 0xa9, 0x8d, 0xb1, 0xfb, - 0x5c, 0x36, 0x12, 0x80, 0xf7, 0x54, 0x0a, 0xc8, 0x27, 0xa9, 0x1b, 0x2d, 0x08, 0x75, - 0x2d, 0xec, 0xfb, 0x71, 0x56, 0xfc, 0xdb, 0x61, 0x75, 0x78, 0xb0, 0x53, 0xee, 0xe4, - 0x1f, 0x66, 0xa6, 0x0e, 0x04, 0x5c, 0x3a, 0x56, 0x9f, 0x3f, 0x7e, 0xdb, 0x76, 0x31, - 0x68, 0x2f, 0xde, 0x9e, 0xf9, 0x1e, 0xa8, 0x81, 0x1f, 0xc2, 0xc7, 0x8f, 0x64, 0x6a, - 0xf6, 0xb4, 0x71, 0x0e, 0xdb, 0xb8, 0xbf, 0x23, 0x28, 0xbd, 0x32, 0x73, 0xa2, 0xcb, - 0x72, 0xff, 0xcc, 0xa7, 0xc2, 0x17, 0xb8, 0x27, 0x19, 0x2d, 0xd2, 0xea, 0x92, 0x9e, - 0x97, 0x6d, 0x13, 0x1c, 0x9d, 0x20, 0x2e, 0xc5, 0x06, 0xa3, 0x5d, 0x93, 0xab, 0x21, - 0x6f, 0x64, 0xbd, 0x73, 0xfe, 0x5d, 0x8a, 0xba, 0xe4, 0x57, 0x1f, 0x85, 0xbe, 0xb8, - 0x4a, 0x7f, 0x93, 0xa3, 0xde, 0x37, 0xa4, 0x51, 0xf3, 0x08, 0xf7, 0xde, 0x6c, 0xcd, - 0x1a, 0x6e, 0xef, 0xef, 0x24, 0x69, 0x9f, 0x21, 0x58, 0xd1, 0x26, 0x1f, 0xe2, 0x51, - 0x82, 0xb5, 0x02, 0xda, 0x3e, 0x74, 0x61, 0x1a, 0x61, 0x16, 0xfc, 0x30, 0x64, 0xfa, - 0x72, 0x3c, 0x5a, 0x81, 0xad, 0xc0, 0xa3, 0x2f, 0x1e, 0xd6, 0x29, 0x91, 0x57, 0xd1, - 0xc1, 0x1c, 0x0a, 0xd9, 0x90, 0x41, 0x89, 0x46, 0x96, 0x30, 0x1d, 0x5b, 0x3f, 0x1b, - 0xf4, 0x32, 0x05, 0xd7, 0xdc, 0xcf, 0xa6, 0x8b, 0xbb, 0x4a, 0x1f, 0x5e, 0x24, 0x2b, - 0x3e, 0x69, 0x0b, 0xfc, 0x97, 0xb9, 0x43, 0x66, 0xa3, 0x43, 0xf5, 0xdd, 0x16, 0xdf, - 0x67, 0xb2, 0xed, 0x2b, 0xe2, 0x1c, 0x74, 0x71, 0x18, 0x87, 0x2b, 0x46, 0x2e, 0xe2, - 0x0c, 0x77, 0x8c, 0xed, 0x85, 0x6f, 0xa9, 0x80, 0x40, 0x3f, 0xb2, 0x4b, 0x78, 0x61, - 0x37, 0xd0, 0xef, 0x02, 0x78, 0x53, 0x9b, 0x00, 0xce, 0x6e, 0x23, 0xc0, 0x7e, 0xf2, - 0xa0, 0x7c, 0xb2, 0x4c, 0x51, 0xc5, 0xb4, 0x85, 0xe4, 0x54, 0xed, 0xf6, 0x61, 0xdb, - 0x4b, 0x93, 0x1a, 0xb8, 0xcb, 0x49, 0x4e, 0xb3, 0x94, 0xfd, 0x13, 0xc1, 0xb3, 0x20, - 0x85, 0xf2, 0x7b, 0x20, 0x4a, 0x4b, 0x87, 0xee, 0x6c, 0x80, 0x63, 0x45, 0xd7, 0x58, - 0x4c, 0xb1, 0x61, 0x00, 0x6a, 0xd9, 0x84, 0x8a, 0x24, 0xa2, 0x2a, 0x57, 0x71, 0xe3, - 0xa2, 0xab, 0x65, 0x46, 0x3f, 0x55, 0x3d, 0x52, 0xcd, 0x53, 0x5e, 0xf1, 0x0b, 0xdd, - 0x40, 0xd8, 0x87, 0x73, 0x72, 0xa5, 0x32, 0xe3, 0x73, 0x1b, 0x0e, 0xe9, 0x0c, 0x04, - 0xe8, 0xe4, 0x37, 0x47, 0xcc, 0x3e, 0xb9, 0x6b, 0xb8, 0x79, 0xbd, 0x94, 0xd7, 0x01, - 0x2a, 0xf4, 0x6a, 0x93, 0xba, 0x17, 0x70, 0x37, 0xf0, 0x62, 0x74, 0x4d, 0x3f, 0xdf, - 0xcc, 0xd3, 0x6a, 0xab, 0xe0, 0xf8, 0xcc, 0xca, 0x19, 0xdc, 0xf7, 0x84, 0x1b, 0x1e, - 0xe2, 0xf4, 0xfe, 0xb1, 0x80, 0x0e, 0x75, 0x44, 0x1c, 0x51, 0xe9, 0x5c, 0xce, 0x94, - 0xce, 0xee, 0xcd, 0x85, 0x87, 0xfb, 0xf5, 0x74, 0x30, 0x8d, 0xd7, 0x63, 0x63, 0x1b, - 0x73, 0x35, 0x78, 0x30, 0x91, 0xf4, 0xc8, 0xb3, 0xc8, 0xfb, 0x3c, 0xd9, 0x39, 0x70, - 0xce, 0xf0, 0xed, 0xa4, 0xca, 0x08, 0x44, 0x75, 0x68, 0x23, 0x9c, 0x02, 0xfe, 0x8f, - 0x67, 0x5e, 0x15, 0xc4, 0x9b, 0x51, 0x21, 0xb1, 0x00, 0xcc, 0x19, 0xfc, 0xc2, 0xb2, - 0x91, 0x3d, 0xf7, 0x4f, 0x75, 0x8f, 0x70, 0xbd, 0x6e, 0xeb, 0x73, 0x39, 0x51, 0x6e, - 0x5f, 0x1e, 0xff, 0x97, 0x00, 0xf8, 0xee, 0x13, 0x0e, 0x5c, 0x84, 0xce, 0xd7, 0xb1, - 0xce, 0xd6, 0x6b, 0xe9, 0xa0, 0x55, 0x96, 0xbe, 0x8e, 0x55, 0xf6, 0xd9, 0xfd, 0xf7, - 0xcf, 0x0f, 0xa6, 0x22, 0x90, 0xec, 0x67, 0x0b, 0x6b, 0xdd, 0x67, 0x38, 0xbb, 0x5c, - 0xfb, 0x34, 0x1e, 0xf5, 0xff, 0xb4, 0x2b, 0xc2, 0xab, 0xc5, 0x08, 0xff, 0x23, 0x12, - 0x48, 0xf2, 0xc2, 0xdc, 0x15, 0x77, 0x0d, 0x33, 0x72, 0x2b, 0x9c, 0x9d, 0xae, - ], - script_code: vec![0xac, 0x65], - transparent_input: Some(0), - hash_type: 3, - amount: 391892287957268, - consensus_branch_id: 1991772603, - sighash: [ - 0x6a, 0x3b, 0x2b, 0xcc, 0x15, 0x57, 0x89, 0xa2, 0x74, 0x39, 0xaa, 0x27, 0x5c, 0xa9, - 0x9e, 0xc6, 0x48, 0xdd, 0xd5, 0x88, 0xe8, 0x2e, 0xfa, 0xe4, 0xac, 0x46, 0xba, 0x3f, - 0xd0, 0xe3, 0xbb, 0xa0, - ], - }, - ]; - - for tv in test_vectors { - let tx = Transaction::read(&tv.tx[..]).unwrap(); - let transparent_input = if let Some(n) = tv.transparent_input { - Some((n as usize, Script(tv.script_code), Amount(tv.amount))) - } else { - None - }; - - assert_eq!( - signature_hash(&tx, tv.consensus_branch_id, tv.hash_type, transparent_input,), - tv.sighash - ); - } -} diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml deleted file mode 100644 index 68a4a45..0000000 --- a/zcash_proofs/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "zcash_proofs" -version = "0.0.0" -authors = [ - "Jack Grigg ", -] - -[dependencies] -bellman = { path = "../bellman" } -byteorder = "1" -pairing = { path = "../pairing" } -rand = "0.4" -sapling-crypto = { path = "../sapling-crypto" } diff --git a/zcash_proofs/LICENSE-APACHE b/zcash_proofs/LICENSE-APACHE deleted file mode 100644 index 1e5006d..0000000 --- a/zcash_proofs/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. - diff --git a/zcash_proofs/LICENSE-MIT b/zcash_proofs/LICENSE-MIT deleted file mode 100644 index 5b7be8e..0000000 --- a/zcash_proofs/LICENSE-MIT +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017 Zcash Company - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/zcash_proofs/README.md b/zcash_proofs/README.md deleted file mode 100644 index 92d9c77..0000000 --- a/zcash_proofs/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# zcash_proofs - -This library contains the zk-SNARK circuits for Zcash, and the APIs for creating -and verifying proofs. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. - diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs deleted file mode 100644 index bdebdd6..0000000 --- a/zcash_proofs/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -extern crate bellman; -extern crate byteorder; -extern crate pairing; -extern crate rand; -extern crate sapling_crypto; - -pub mod sapling; diff --git a/zcash_proofs/src/sapling/mod.rs b/zcash_proofs/src/sapling/mod.rs deleted file mode 100644 index 2cfb2e9..0000000 --- a/zcash_proofs/src/sapling/mod.rs +++ /dev/null @@ -1,39 +0,0 @@ -use pairing::bls12_381::Bls12; -use sapling_crypto::jubjub::{ - edwards, fs::FsRepr, FixedGenerators, JubjubBls12, JubjubParams, Unknown, -}; - -mod prover; -mod verifier; - -pub use self::prover::{CommitmentTreeWitness, SaplingProvingContext}; -pub use self::verifier::SaplingVerificationContext; - -// This function computes `value` in the exponent of the value commitment base -fn compute_value_balance( - value: i64, - params: &JubjubBls12, -) -> Option> { - // Compute the absolute value (failing if -i64::MAX is - // the value) - let abs = match value.checked_abs() { - Some(a) => a as u64, - None => return None, - }; - - // Is it negative? We'll have to negate later if so. - let is_negative = value.is_negative(); - - // Compute it in the exponent - let mut value_balance = params - .generator(FixedGenerators::ValueCommitmentValue) - .mul(FsRepr::from(abs), params); - - // Negate if necessary - if is_negative { - value_balance = value_balance.negate(); - } - - // Convert to unknown order point - Some(value_balance.into()) -} diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs deleted file mode 100644 index f43dae7..0000000 --- a/zcash_proofs/src/sapling/prover.rs +++ /dev/null @@ -1,365 +0,0 @@ -use bellman::groth16::{ - create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof, -}; -use byteorder::{LittleEndian, ReadBytesExt}; -use pairing::{ - bls12_381::{Bls12, Fr, FrRepr}, - Field, PrimeField, PrimeFieldRepr, -}; -use rand::{OsRng, Rand}; -use sapling_crypto::{ - circuit::{ - multipack, - sapling::{Output, Spend, TREE_DEPTH}, - }, - jubjub::{edwards, fs::Fs, FixedGenerators, JubjubBls12, Unknown}, - primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, - redjubjub::{PrivateKey, PublicKey, Signature}, -}; - -use super::compute_value_balance; - -/// A witness to a path from a postion in a particular Sapling commitment tree -/// to the root of that tree. -pub struct CommitmentTreeWitness { - auth_path: Vec>, - position: u64, -} - -impl CommitmentTreeWitness { - pub fn from_slice(mut witness: &[u8]) -> Result { - // Skip the first byte, which should be "32" to signify the length of - // the following vector of Pedersen hashes. - assert_eq!(witness[0], TREE_DEPTH as u8); - witness = &witness[1..]; - - // Begin to construct the authentication path - let mut auth_path = vec![None; TREE_DEPTH]; - - // The vector works in reverse - for i in (0..TREE_DEPTH).rev() { - // skip length of inner vector - assert_eq!(witness[0], 32); // the length of a pedersen hash - witness = &witness[1..]; - - // Grab the sibling node at this depth in the tree - let mut sibling = [0u8; 32]; - sibling.copy_from_slice(&witness[0..32]); - witness = &witness[32..]; - - // Sibling node should be an element of Fr - let sibling = match { - let mut repr = FrRepr::default(); - repr.read_le(&sibling[..]).expect("length is 32 bytes"); - Fr::from_repr(repr) - } { - Ok(p) => p, - Err(_) => return Err(()), - }; - - // Set the value in the auth path; we put false here - // for now (signifying the position bit) which we'll - // fill in later. - auth_path[i] = Some((sibling, false)); - } - - // Read the position from the witness - let position = witness - .read_u64::() - .expect("should have had index at the end"); - - // Given the position, let's finish constructing the authentication - // path - let mut tmp = position; - for i in 0..TREE_DEPTH { - auth_path[i].as_mut().map(|p| p.1 = (tmp & 1) == 1); - - tmp >>= 1; - } - - // The witness should be empty now; if it wasn't, the caller would - // have provided more information than they should have, indicating - // a bug downstream - assert_eq!(witness.len(), 0); - - Ok(CommitmentTreeWitness { - auth_path, - position, - }) - } -} - -/// A context object for creating the Sapling components of a Zcash transaction. -pub struct SaplingProvingContext { - bsk: Fs, - bvk: edwards::Point, -} - -impl SaplingProvingContext { - /// Construct a new context to be used with a single transaction. - pub fn new() -> Self { - SaplingProvingContext { - bsk: Fs::zero(), - bvk: edwards::Point::zero(), - } - } - - /// Create the value commitment, re-randomized key, and proof for a Sapling - /// SpendDescription, while accumulating its value commitment randomness - /// inside the context for later use. - pub fn spend_proof( - &mut self, - proof_generation_key: ProofGenerationKey, - diversifier: Diversifier, - rcm: Fs, - ar: Fs, - value: u64, - anchor: Fr, - witness: CommitmentTreeWitness, - proving_key: &Parameters, - verifying_key: &PreparedVerifyingKey, - params: &JubjubBls12, - ) -> Result< - ( - Proof, - edwards::Point, - PublicKey, - ), - (), - > { - // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); - - // We create the randomness of the value commitment - let rcv = Fs::rand(&mut rng); - - // Accumulate the value commitment randomness in the context - { - let mut tmp = rcv.clone(); - tmp.add_assign(&self.bsk); - - // Update the context - self.bsk = tmp; - } - - // Construct the value commitment - let value_commitment = ValueCommitment:: { - value: value, - randomness: rcv, - }; - - // Construct the viewing key - let viewing_key = proof_generation_key.into_viewing_key(params); - - // Construct the payment address with the viewing key / diversifier - let payment_address = match viewing_key.into_payment_address(diversifier, params) { - Some(p) => p, - None => return Err(()), - }; - - // This is the result of the re-randomization, we compute it for the caller - let rk = PublicKey::(proof_generation_key.ak.clone().into()).randomize( - ar, - FixedGenerators::SpendingKeyGenerator, - params, - ); - - // Let's compute the nullifier while we have the position - let note = Note { - value: value, - g_d: diversifier - .g_d::(params) - .expect("was a valid diversifier before"), - pk_d: payment_address.pk_d.clone(), - r: rcm, - }; - - let nullifier = note.nf(&viewing_key, witness.position, params); - - // We now have the full witness for our circuit - let instance = Spend { - params, - value_commitment: Some(value_commitment.clone()), - proof_generation_key: Some(proof_generation_key), - payment_address: Some(payment_address), - commitment_randomness: Some(rcm), - ar: Some(ar), - auth_path: witness.auth_path, - anchor: Some(anchor), - }; - - // Create proof - let proof = - create_random_proof(instance, proving_key, &mut rng).expect("proving should not fail"); - - // Try to verify the proof: - // Construct public input for circuit - let mut public_input = [Fr::zero(); 7]; - { - let (x, y) = rk.0.into_xy(); - public_input[0] = x; - public_input[1] = y; - } - { - let (x, y) = value_commitment.cm(params).into_xy(); - public_input[2] = x; - public_input[3] = y; - } - public_input[4] = anchor; - - // Add the nullifier through multiscalar packing - { - let nullifier = multipack::bytes_to_bits_le(&nullifier); - let nullifier = multipack::compute_multipacking::(&nullifier); - - assert_eq!(nullifier.len(), 2); - - public_input[5] = nullifier[0]; - public_input[6] = nullifier[1]; - } - - // Verify the proof - match verify_proof(verifying_key, &proof, &public_input[..]) { - // No error, and proof verification successful - Ok(true) => {} - - // Any other case - _ => { - return Err(()); - } - } - - // Compute value commitment - let value_commitment: edwards::Point = value_commitment.cm(params).into(); - - // Accumulate the value commitment in the context - { - let mut tmp = value_commitment.clone(); - tmp = tmp.add(&self.bvk, params); - - // Update the context - self.bvk = tmp; - } - - Ok((proof, value_commitment, rk)) - } - - /// Create the value commitment and proof for a Sapling OutputDescription, - /// while accumulating its value commitment randomness inside the context - /// for later use. - pub fn output_proof( - &mut self, - esk: Fs, - payment_address: PaymentAddress, - rcm: Fs, - value: u64, - proving_key: &Parameters, - params: &JubjubBls12, - ) -> (Proof, edwards::Point) { - // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); - - // We construct ephemeral randomness for the value commitment. This - // randomness is not given back to the caller, but the synthetic - // blinding factor `bsk` is accumulated in the context. - let rcv = Fs::rand(&mut rng); - - // Accumulate the value commitment randomness in the context - { - let mut tmp = rcv.clone(); - tmp.negate(); // Outputs subtract from the total. - tmp.add_assign(&self.bsk); - - // Update the context - self.bsk = tmp; - } - - // Construct the value commitment for the proof instance - let value_commitment = ValueCommitment:: { - value: value, - randomness: rcv, - }; - - // We now have a full witness for the output proof. - let instance = Output { - params, - value_commitment: Some(value_commitment.clone()), - payment_address: Some(payment_address.clone()), - commitment_randomness: Some(rcm), - esk: Some(esk.clone()), - }; - - // Create proof - let proof = - create_random_proof(instance, proving_key, &mut rng).expect("proving should not fail"); - - // Compute the actual value commitment - let value_commitment: edwards::Point = value_commitment.cm(params).into(); - - // Accumulate the value commitment in the context. We do this to check internal consistency. - { - let mut tmp = value_commitment.clone(); - tmp = tmp.negate(); // Outputs subtract from the total. - tmp = tmp.add(&self.bvk, params); - - // Update the context - self.bvk = tmp; - } - - (proof, value_commitment) - } - - /// Create the bindingSig for a Sapling transaction. All calls to spend_proof() - /// and output_proof() must be completed before calling this function. - pub fn binding_sig( - &self, - value_balance: i64, - sighash: &[u8; 32], - params: &JubjubBls12, - ) -> Result { - // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); - - // Grab the current `bsk` from the context - let bsk = PrivateKey::(self.bsk); - - // Grab the `bvk` using DerivePublic. - let bvk = PublicKey::from_private(&bsk, FixedGenerators::ValueCommitmentRandomness, params); - - // In order to check internal consistency, let's use the accumulated value - // commitments (as the verifier would) and apply valuebalance to compare - // against our derived bvk. - { - // Compute value balance - let mut value_balance = match compute_value_balance(value_balance, params) { - Some(a) => a, - None => return Err(()), - }; - - // Subtract value_balance from current bvk to get final bvk - value_balance = value_balance.negate(); - let mut tmp = self.bvk.clone(); - tmp = tmp.add(&value_balance, params); - - // The result should be the same, unless the provided valueBalance is wrong. - if bvk.0 != tmp { - return Err(()); - } - } - - // Construct signature message - let mut data_to_be_signed = [0u8; 64]; - bvk.0 - .write(&mut data_to_be_signed[0..32]) - .expect("message buffer should be 32 bytes"); - (&mut data_to_be_signed[32..64]).copy_from_slice(&sighash[..]); - - // Sign - Ok(bsk.sign( - &data_to_be_signed, - &mut rng, - FixedGenerators::ValueCommitmentRandomness, - params, - )) - } -} diff --git a/zcash_proofs/src/sapling/verifier.rs b/zcash_proofs/src/sapling/verifier.rs deleted file mode 100644 index e9a5f2f..0000000 --- a/zcash_proofs/src/sapling/verifier.rs +++ /dev/null @@ -1,207 +0,0 @@ -use bellman::groth16::{verify_proof, PreparedVerifyingKey, Proof}; -use pairing::{ - bls12_381::{Bls12, Fr}, - Field, -}; -use sapling_crypto::{ - circuit::multipack, - jubjub::{edwards, FixedGenerators, JubjubBls12, Unknown}, - redjubjub::{PublicKey, Signature}, -}; - -use super::compute_value_balance; - -fn is_small_order(p: &edwards::Point, params: &JubjubBls12) -> bool { - p.double(params).double(params).double(params) == edwards::Point::zero() -} - -/// A context object for verifying the Sapling components of a Zcash transaction. -pub struct SaplingVerificationContext { - bvk: edwards::Point, -} - -impl SaplingVerificationContext { - /// Construct a new context to be used with a single transaction. - pub fn new() -> Self { - SaplingVerificationContext { - bvk: edwards::Point::zero(), - } - } - - /// Perform consensus checks on a Sapling SpendDescription, while - /// accumulating its value commitment inside the context for later use. - pub fn check_spend( - &mut self, - cv: edwards::Point, - anchor: Fr, - nullifier: &[u8; 32], - rk: PublicKey, - sighash_value: &[u8; 32], - spend_auth_sig: Signature, - zkproof: Proof, - verifying_key: &PreparedVerifyingKey, - params: &JubjubBls12, - ) -> bool { - if is_small_order(&cv, params) { - return false; - } - - if is_small_order(&rk.0, params) { - return false; - } - - // Accumulate the value commitment in the context - { - let mut tmp = cv.clone(); - tmp = tmp.add(&self.bvk, params); - - // Update the context - self.bvk = tmp; - } - - // Grab the nullifier as a sequence of bytes - let nullifier = &nullifier[..]; - - // Compute the signature's message for rk/spend_auth_sig - let mut data_to_be_signed = [0u8; 64]; - rk.0.write(&mut data_to_be_signed[0..32]) - .expect("message buffer should be 32 bytes"); - (&mut data_to_be_signed[32..64]).copy_from_slice(&sighash_value[..]); - - // Verify the spend_auth_sig - if !rk.verify( - &data_to_be_signed, - &spend_auth_sig, - FixedGenerators::SpendingKeyGenerator, - params, - ) { - return false; - } - - // Construct public input for circuit - let mut public_input = [Fr::zero(); 7]; - { - let (x, y) = rk.0.into_xy(); - public_input[0] = x; - public_input[1] = y; - } - { - let (x, y) = cv.into_xy(); - public_input[2] = x; - public_input[3] = y; - } - public_input[4] = anchor; - - // Add the nullifier through multiscalar packing - { - let nullifier = multipack::bytes_to_bits_le(nullifier); - let nullifier = multipack::compute_multipacking::(&nullifier); - - assert_eq!(nullifier.len(), 2); - - public_input[5] = nullifier[0]; - public_input[6] = nullifier[1]; - } - - // Verify the proof - match verify_proof(verifying_key, &zkproof, &public_input[..]) { - // No error, and proof verification successful - Ok(true) => true, - - // Any other case - _ => false, - } - } - - /// Perform consensus checks on a Sapling OutputDescription, while - /// accumulating its value commitment inside the context for later use. - pub fn check_output( - &mut self, - cv: edwards::Point, - cm: Fr, - epk: edwards::Point, - zkproof: Proof, - verifying_key: &PreparedVerifyingKey, - params: &JubjubBls12, - ) -> bool { - if is_small_order(&cv, params) { - return false; - } - - if is_small_order(&epk, params) { - return false; - } - - // Accumulate the value commitment in the context - { - let mut tmp = cv.clone(); - tmp = tmp.negate(); // Outputs subtract from the total. - tmp = tmp.add(&self.bvk, params); - - // Update the context - self.bvk = tmp; - } - - // Construct public input for circuit - let mut public_input = [Fr::zero(); 5]; - { - let (x, y) = cv.into_xy(); - public_input[0] = x; - public_input[1] = y; - } - { - let (x, y) = epk.into_xy(); - public_input[2] = x; - public_input[3] = y; - } - public_input[4] = cm; - - // Verify the proof - match verify_proof(verifying_key, &zkproof, &public_input[..]) { - // No error, and proof verification successful - Ok(true) => true, - - // Any other case - _ => false, - } - } - - /// Perform consensus checks on the valueBalance and bindingSig parts of a - /// Sapling transaction. All SpendDescriptions and OutputDescriptions must - /// have been checked before calling this function. - pub fn final_check( - &self, - value_balance: i64, - sighash_value: &[u8; 32], - binding_sig: Signature, - params: &JubjubBls12, - ) -> bool { - // Obtain current bvk from the context - let mut bvk = PublicKey(self.bvk.clone()); - - // Compute value balance - let mut value_balance = match compute_value_balance(value_balance, params) { - Some(a) => a, - None => return false, - }; - - // Subtract value_balance from current bvk to get final bvk - value_balance = value_balance.negate(); - bvk.0 = bvk.0.add(&value_balance, params); - - // Compute the signature's message for bvk/binding_sig - let mut data_to_be_signed = [0u8; 64]; - bvk.0 - .write(&mut data_to_be_signed[0..32]) - .expect("bvk is 32 bytes"); - (&mut data_to_be_signed[32..64]).copy_from_slice(&sighash_value[..]); - - // Verify the binding_sig - bvk.verify( - &data_to_be_signed, - &binding_sig, - FixedGenerators::ValueCommitmentRandomness, - params, - ) - } -} diff --git a/zcash_wallet/Cargo.toml b/zcash_wallet/Cargo.toml deleted file mode 100644 index a7b6c91..0000000 --- a/zcash_wallet/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "zcash_wallet" -version = "0.0.0" -authors = [ - "Jack Grigg ", -] - -[dependencies] diff --git a/zcash_wallet/LICENSE-APACHE b/zcash_wallet/LICENSE-APACHE deleted file mode 100644 index 1e5006d..0000000 --- a/zcash_wallet/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. - diff --git a/zcash_wallet/LICENSE-MIT b/zcash_wallet/LICENSE-MIT deleted file mode 100644 index 5b7be8e..0000000 --- a/zcash_wallet/LICENSE-MIT +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017 Zcash Company - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/zcash_wallet/README.md b/zcash_wallet/README.md deleted file mode 100644 index 14c1a38..0000000 --- a/zcash_wallet/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# zcash_wallet - -This library contains Rust structs and traits for creating shielded Zcash wallets. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. - diff --git a/zcash_wallet/src/lib.rs b/zcash_wallet/src/lib.rs deleted file mode 100644 index 31e1bb2..0000000 --- a/zcash_wallet/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/zip32/.gitignore b/zip32/.gitignore deleted file mode 100644 index 6936990..0000000 --- a/zip32/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target -**/*.rs.bk -Cargo.lock diff --git a/zip32/COPYRIGHT b/zip32/COPYRIGHT deleted file mode 100644 index e58e868..0000000 --- a/zip32/COPYRIGHT +++ /dev/null @@ -1,14 +0,0 @@ -Copyrights in the "zip32" library are retained by their contributors. No -copyright assignment is required to contribute to the "zip32" library. - -The "zip32" library is licensed under either of - - * Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT) - -at your option. - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/zip32/Cargo.toml b/zip32/Cargo.toml deleted file mode 100644 index 031d636..0000000 --- a/zip32/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "zip32" -version = "0.0.0" -authors = [ - "Jack Grigg ", -] -license = "MIT/Apache-2.0" - -description = "Library for implementing shielded hierarchical deterministic wallets" -documentation = "https://docs.rs/zip32/" -homepage = "https://github.com/zcash-hackworks/zip32" -repository = "https://github.com/zcash-hackworks/zip32" - -[dependencies] -aes = "0.2" -byteorder = "1" -fpe = "0.1" -lazy_static = "1.0" -pairing = { path = "../pairing" } -sapling-crypto = { path = "../sapling-crypto" } - -[dependencies.blake2-rfc] -git = "https://github.com/gtank/blake2-rfc" -rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" diff --git a/zip32/LICENSE-APACHE b/zip32/LICENSE-APACHE deleted file mode 100644 index 16fe87b..0000000 --- a/zip32/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. diff --git a/zip32/LICENSE-MIT b/zip32/LICENSE-MIT deleted file mode 100644 index 31aa793..0000000 --- a/zip32/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/zip32/README.md b/zip32/README.md deleted file mode 100644 index 898d56c..0000000 --- a/zip32/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# zip32 [![Crates.io](https://img.shields.io/crates/v/zip32.svg)](https://crates.io/crates/zip32) # - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/zip32/src/lib.rs b/zip32/src/lib.rs deleted file mode 100644 index 5b322db..0000000 --- a/zip32/src/lib.rs +++ /dev/null @@ -1,1233 +0,0 @@ -extern crate aes; -extern crate blake2_rfc; -extern crate byteorder; -extern crate fpe; -#[macro_use] -extern crate lazy_static; -extern crate pairing; -extern crate sapling_crypto; - -use aes::Aes256; -use blake2_rfc::blake2b::{Blake2b, Blake2bResult}; -use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt}; -use fpe::ff1::{BinaryNumeralString, FF1}; -use pairing::{bls12_381::Bls12, Field, PrimeField, PrimeFieldRepr}; -use sapling_crypto::{ - jubjub::{ - edwards, FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, ToUniform, Unknown, - }, - primitives::{Diversifier, PaymentAddress, ViewingKey}, -}; -use std::io::{self, Read, Write}; - -lazy_static! { - static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() }; -} - -pub const PRF_EXPAND_PERSONALIZATION: &'static [u8; 16] = b"Zcash_ExpandSeed"; -pub const ZIP32_SAPLING_MASTER_PERSONALIZATION: &'static [u8; 16] = b"ZcashIP32Sapling"; -pub const ZIP32_SAPLING_FVFP_PERSONALIZATION: &'static [u8; 16] = b"ZcashSaplingFVFP"; - -// Sapling key components - -/// PRF^expand(sk, t) := BLAKE2b-512("Zcash_ExpandSeed", sk || t) -fn prf_expand(sk: &[u8], t: &[u8]) -> Blake2bResult { - prf_expand_vec(sk, &vec![t]) -} - -fn prf_expand_vec(sk: &[u8], ts: &[&[u8]]) -> Blake2bResult { - let mut h = Blake2b::with_params(64, &[], &[], PRF_EXPAND_PERSONALIZATION); - h.update(sk); - for t in ts { - h.update(t); - } - h.finalize() -} - -/// An outgoing viewing key -#[derive(Clone, Copy, PartialEq)] -struct OutgoingViewingKey([u8; 32]); - -impl OutgoingViewingKey { - fn derive_child(&self, i_l: &[u8]) -> Self { - let mut ovk = [0u8; 32]; - ovk.copy_from_slice(&prf_expand_vec(i_l, &[&[0x15], &self.0]).as_bytes()[..32]); - OutgoingViewingKey(ovk) - } -} - -/// A Sapling expanded spending key -#[derive(Clone)] -pub struct ExpandedSpendingKey { - ask: E::Fs, - nsk: E::Fs, - ovk: OutgoingViewingKey, -} - -/// A Sapling full viewing key -pub struct FullViewingKey { - vk: ViewingKey, - ovk: OutgoingViewingKey, -} - -impl ExpandedSpendingKey { - fn from_spending_key(sk: &[u8]) -> Self { - let ask = E::Fs::to_uniform(prf_expand(sk, &[0x00]).as_bytes()); - let nsk = E::Fs::to_uniform(prf_expand(sk, &[0x01]).as_bytes()); - let mut ovk = OutgoingViewingKey([0u8; 32]); - ovk.0 - .copy_from_slice(&prf_expand(sk, &[0x02]).as_bytes()[..32]); - ExpandedSpendingKey { ask, nsk, ovk } - } - - fn derive_child(&self, i_l: &[u8]) -> Self { - let mut ask = E::Fs::to_uniform(prf_expand(i_l, &[0x13]).as_bytes()); - let mut nsk = E::Fs::to_uniform(prf_expand(i_l, &[0x14]).as_bytes()); - ask.add_assign(&self.ask); - nsk.add_assign(&self.nsk); - let ovk = self.ovk.derive_child(i_l); - ExpandedSpendingKey { ask, nsk, ovk } - } - - pub fn read(mut reader: R) -> io::Result { - let mut ask_repr = ::Repr::default(); - ask_repr.read_le(&mut reader)?; - let ask = E::Fs::from_repr(ask_repr) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - - let mut nsk_repr = ::Repr::default(); - nsk_repr.read_le(&mut reader)?; - let nsk = E::Fs::from_repr(nsk_repr) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - - let mut ovk = [0; 32]; - reader.read_exact(&mut ovk)?; - - Ok(ExpandedSpendingKey { - ask, - nsk, - ovk: OutgoingViewingKey(ovk), - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - self.ask.into_repr().write_le(&mut writer)?; - self.nsk.into_repr().write_le(&mut writer)?; - writer.write_all(&self.ovk.0)?; - - Ok(()) - } - - fn to_bytes(&self) -> [u8; 96] { - let mut result = [0u8; 96]; - self.write(&mut result[..]) - .expect("should be able to serialize an ExpandedSpendingKey"); - result - } -} - -impl FullViewingKey { - fn from_expanded_spending_key(expsk: &ExpandedSpendingKey, params: &E::Params) -> Self { - FullViewingKey { - vk: ViewingKey { - ak: params - .generator(FixedGenerators::SpendingKeyGenerator) - .mul(expsk.ask, params), - nk: params - .generator(FixedGenerators::ProofGenerationKey) - .mul(expsk.nsk, params), - }, - ovk: expsk.ovk, - } - } - - fn derive_child(&self, i_l: &[u8], params: &E::Params) -> Self { - let i_ask = E::Fs::to_uniform(prf_expand(i_l, &[0x13]).as_bytes()); - let i_nsk = E::Fs::to_uniform(prf_expand(i_l, &[0x14]).as_bytes()); - let ak = params - .generator(FixedGenerators::SpendingKeyGenerator) - .mul(i_ask, params) - .add(&self.vk.ak, params); - let nk = params - .generator(FixedGenerators::ProofGenerationKey) - .mul(i_nsk, params) - .add(&self.vk.nk, params); - - FullViewingKey { - vk: ViewingKey { ak, nk }, - ovk: self.ovk.derive_child(i_l), - } - } - - pub fn read(mut reader: R, params: &E::Params) -> io::Result { - let ak = edwards::Point::::read(&mut reader, params)?; - let ak = match ak.as_prime_order(params) { - Some(p) => p, - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "ak not of prime order", - )) - } - }; - - let nk = edwards::Point::::read(&mut reader, params)?; - let nk = match nk.as_prime_order(params) { - Some(p) => p, - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "nk not of prime order", - )) - } - }; - - let mut ovk = [0; 32]; - reader.read_exact(&mut ovk)?; - - Ok(FullViewingKey { - vk: ViewingKey { ak, nk }, - ovk: OutgoingViewingKey(ovk), - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - self.vk.ak.write(&mut writer)?; - self.vk.nk.write(&mut writer)?; - writer.write_all(&self.ovk.0)?; - - Ok(()) - } - - fn to_bytes(&self) -> [u8; 96] { - let mut result = [0u8; 96]; - self.write(&mut result[..]) - .expect("should be able to serialize a FullViewingKey"); - result - } - - fn fingerprint(&self) -> FVKFingerprint { - let mut h = Blake2b::with_params(32, &[], &[], ZIP32_SAPLING_FVFP_PERSONALIZATION); - h.update(&self.to_bytes()); - let mut fvfp = [0u8; 32]; - fvfp.copy_from_slice(h.finalize().as_bytes()); - FVKFingerprint(fvfp) - } -} - -// ZIP 32 structures - -/// A Sapling full viewing key fingerprint -struct FVKFingerprint([u8; 32]); - -/// A Sapling full viewing key tag -#[derive(Clone, Copy, Debug, PartialEq)] -struct FVKTag([u8; 4]); - -impl FVKFingerprint { - fn tag(&self) -> FVKTag { - let mut tag = [0u8; 4]; - tag.copy_from_slice(&self.0[..4]); - FVKTag(tag) - } -} - -impl FVKTag { - fn master() -> Self { - FVKTag([0u8; 4]) - } -} - -/// A child index for a derived key -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum ChildIndex { - NonHardened(u32), - Hardened(u32), // Hardened(n) == n + (1 << 31) == n' in path notation -} - -impl ChildIndex { - pub fn from_index(i: u32) -> Self { - match i { - n if n >= (1 << 31) => ChildIndex::Hardened(n - (1 << 31)), - n => ChildIndex::NonHardened(n), - } - } - - fn master() -> Self { - ChildIndex::from_index(0) - } - - fn to_index(&self) -> u32 { - match self { - &ChildIndex::Hardened(i) => i + (1 << 31), - &ChildIndex::NonHardened(i) => i, - } - } -} - -/// A chain code -#[derive(Clone, Copy, Debug, PartialEq)] -struct ChainCode([u8; 32]); - -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct DiversifierIndex(pub [u8; 11]); - -impl DiversifierIndex { - fn new() -> Self { - DiversifierIndex([0; 11]) - } - - pub fn increment(&mut self) -> Result<(), ()> { - for k in 0..11 { - self.0[k] = self.0[k].wrapping_add(1); - if self.0[k] != 0 { - // No overflow - return Ok(()); - } - } - // Overflow - Err(()) - } -} - -/// A key used to derive diversifiers for a particular child key -#[derive(Clone, Copy, Debug, PartialEq)] -struct DiversifierKey([u8; 32]); - -impl DiversifierKey { - fn master(sk_m: &[u8]) -> Self { - let mut dk_m = [0u8; 32]; - dk_m.copy_from_slice(&prf_expand(sk_m, &[0x10]).as_bytes()[..32]); - DiversifierKey(dk_m) - } - - fn derive_child(&self, i_l: &[u8]) -> Self { - let mut dk = [0u8; 32]; - dk.copy_from_slice(&prf_expand_vec(i_l, &[&[0x16], &self.0]).as_bytes()[..32]); - DiversifierKey(dk) - } - - /// Returns the first index starting from j that generates a valid - /// diversifier, along with the corresponding diversifier. Returns - /// an error if the diversifier space is exhausted. - fn diversifier(&self, mut j: DiversifierIndex) -> Result<(DiversifierIndex, Diversifier), ()> { - let ff = FF1::::new(&self.0, 2).unwrap(); - loop { - // Generate d_j - let enc = ff - .encrypt(&[], &BinaryNumeralString::from_bytes_le(&j.0[..])) - .unwrap(); - let mut d_j = [0; 11]; - d_j.copy_from_slice(&enc.to_bytes_le()); - let d_j = Diversifier(d_j); - - // Return (j, d_j) if valid, else increment j and try again - match d_j.g_d::(&JUBJUB) { - Some(_) => return Ok((j, d_j)), - None => { - if j.increment().is_err() { - return Err(()); - } - } - } - } - } -} - -/// A Sapling extended spending key -#[derive(Clone)] -pub struct ExtendedSpendingKey { - depth: u8, - parent_fvk_tag: FVKTag, - child_index: ChildIndex, - chain_code: ChainCode, - pub expsk: ExpandedSpendingKey, - dk: DiversifierKey, -} - -// A Sapling extended full viewing key -pub struct ExtendedFullViewingKey { - depth: u8, - parent_fvk_tag: FVKTag, - child_index: ChildIndex, - chain_code: ChainCode, - pub fvk: FullViewingKey, - dk: DiversifierKey, -} - -impl std::cmp::PartialEq for ExtendedSpendingKey { - fn eq(&self, rhs: &ExtendedSpendingKey) -> bool { - self.depth == rhs.depth - && self.parent_fvk_tag == rhs.parent_fvk_tag - && self.child_index == rhs.child_index - && self.chain_code == rhs.chain_code - && self.expsk.ask == rhs.expsk.ask - && self.expsk.nsk == rhs.expsk.nsk - && self.expsk.ovk == rhs.expsk.ovk - && self.dk == rhs.dk - } -} - -impl std::fmt::Debug for ExtendedSpendingKey { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - write!( - f, - "ExtendedSpendingKey(d = {}, tag_p = {:?}, i = {:?})", - self.depth, self.parent_fvk_tag, self.child_index - ) - } -} - -impl std::cmp::PartialEq for ExtendedFullViewingKey { - fn eq(&self, rhs: &ExtendedFullViewingKey) -> bool { - self.depth == rhs.depth - && self.parent_fvk_tag == rhs.parent_fvk_tag - && self.child_index == rhs.child_index - && self.chain_code == rhs.chain_code - && self.fvk.vk.ak == rhs.fvk.vk.ak - && self.fvk.vk.nk == rhs.fvk.vk.nk - && self.fvk.ovk == rhs.fvk.ovk - && self.dk == rhs.dk - } -} - -impl std::fmt::Debug for ExtendedFullViewingKey { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - write!( - f, - "ExtendedFullViewingKey(d = {}, tag_p = {:?}, i = {:?})", - self.depth, self.parent_fvk_tag, self.child_index - ) - } -} - -impl ExtendedSpendingKey { - pub fn master(seed: &[u8]) -> Self { - let mut h = Blake2b::with_params(64, &[], &[], ZIP32_SAPLING_MASTER_PERSONALIZATION); - h.update(seed); - let i = h.finalize(); - - let sk_m = &i.as_bytes()[..32]; - let mut c_m = [0u8; 32]; - c_m.copy_from_slice(&i.as_bytes()[32..]); - - ExtendedSpendingKey { - depth: 0, - parent_fvk_tag: FVKTag::master(), - child_index: ChildIndex::master(), - chain_code: ChainCode(c_m), - expsk: ExpandedSpendingKey::from_spending_key(sk_m), - dk: DiversifierKey::master(sk_m), - } - } - - pub fn read(mut reader: R) -> io::Result { - let depth = reader.read_u8()?; - let mut tag = [0; 4]; - reader.read_exact(&mut tag)?; - let i = reader.read_u32::()?; - let mut c = [0; 32]; - reader.read_exact(&mut c)?; - let expsk = ExpandedSpendingKey::read(&mut reader)?; - let mut dk = [0; 32]; - reader.read_exact(&mut dk)?; - - Ok(ExtendedSpendingKey { - depth, - parent_fvk_tag: FVKTag(tag), - child_index: ChildIndex::from_index(i), - chain_code: ChainCode(c), - expsk, - dk: DiversifierKey(dk), - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_u8(self.depth)?; - writer.write_all(&self.parent_fvk_tag.0)?; - writer.write_u32::(self.child_index.to_index())?; - writer.write_all(&self.chain_code.0)?; - writer.write_all(&self.expsk.to_bytes())?; - writer.write_all(&self.dk.0)?; - - Ok(()) - } - - /// Returns the child key corresponding to the path derived from the master key - pub fn from_path(master: &ExtendedSpendingKey, path: &[ChildIndex]) -> Self { - let mut xsk = master.clone(); - for &i in path.iter() { - xsk = xsk.derive_child(i); - } - xsk - } - - pub fn derive_child(&self, i: ChildIndex) -> Self { - let fvk = FullViewingKey::from_expanded_spending_key(&self.expsk, &JUBJUB); - let tmp = match i { - ChildIndex::Hardened(i) => { - let mut le_i = [0; 4]; - LittleEndian::write_u32(&mut le_i, i + (1 << 31)); - prf_expand_vec( - &self.chain_code.0, - &[&[0x11], &self.expsk.to_bytes(), &self.dk.0, &le_i], - ) - } - ChildIndex::NonHardened(i) => { - let mut le_i = [0; 4]; - LittleEndian::write_u32(&mut le_i, i); - prf_expand_vec( - &self.chain_code.0, - &[&[0x12], &fvk.to_bytes(), &self.dk.0, &le_i], - ) - } - }; - let i_l = &tmp.as_bytes()[..32]; - let mut c_i = [0u8; 32]; - c_i.copy_from_slice(&tmp.as_bytes()[32..]); - - ExtendedSpendingKey { - depth: self.depth + 1, - parent_fvk_tag: fvk.fingerprint().tag(), - child_index: i, - chain_code: ChainCode(c_i), - expsk: self.expsk.derive_child(i_l), - dk: self.dk.derive_child(i_l), - } - } - - pub fn default_address(&self) -> Result<(DiversifierIndex, PaymentAddress), ()> { - ExtendedFullViewingKey::from(self).default_address() - } -} - -impl<'a> From<&'a ExtendedSpendingKey> for ExtendedFullViewingKey { - fn from(xsk: &ExtendedSpendingKey) -> Self { - ExtendedFullViewingKey { - depth: xsk.depth, - parent_fvk_tag: xsk.parent_fvk_tag, - child_index: xsk.child_index, - chain_code: xsk.chain_code, - fvk: FullViewingKey::from_expanded_spending_key(&xsk.expsk, &JUBJUB), - dk: xsk.dk, - } - } -} - -impl ExtendedFullViewingKey { - pub fn read(mut reader: R) -> io::Result { - let depth = reader.read_u8()?; - let mut tag = [0; 4]; - reader.read_exact(&mut tag)?; - let i = reader.read_u32::()?; - let mut c = [0; 32]; - reader.read_exact(&mut c)?; - let fvk = FullViewingKey::read(&mut reader, &*JUBJUB)?; - let mut dk = [0; 32]; - reader.read_exact(&mut dk)?; - - Ok(ExtendedFullViewingKey { - depth, - parent_fvk_tag: FVKTag(tag), - child_index: ChildIndex::from_index(i), - chain_code: ChainCode(c), - fvk, - dk: DiversifierKey(dk), - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_u8(self.depth)?; - writer.write_all(&self.parent_fvk_tag.0)?; - writer.write_u32::(self.child_index.to_index())?; - writer.write_all(&self.chain_code.0)?; - writer.write_all(&self.fvk.to_bytes())?; - writer.write_all(&self.dk.0)?; - - Ok(()) - } - - pub fn derive_child(&self, i: ChildIndex) -> Result { - let tmp = match i { - ChildIndex::Hardened(_) => return Err(()), - ChildIndex::NonHardened(i) => { - let mut le_i = [0; 4]; - LittleEndian::write_u32(&mut le_i, i); - prf_expand_vec( - &self.chain_code.0, - &[&[0x12], &self.fvk.to_bytes(), &self.dk.0, &le_i], - ) - } - }; - let i_l = &tmp.as_bytes()[..32]; - let mut c_i = [0u8; 32]; - c_i.copy_from_slice(&tmp.as_bytes()[32..]); - - Ok(ExtendedFullViewingKey { - depth: self.depth + 1, - parent_fvk_tag: self.fvk.fingerprint().tag(), - child_index: i, - chain_code: ChainCode(c_i), - fvk: self.fvk.derive_child(i_l, &JUBJUB), - dk: self.dk.derive_child(i_l), - }) - } - - pub fn address( - &self, - j: DiversifierIndex, - ) -> Result<(DiversifierIndex, PaymentAddress), ()> { - let (j, d_j) = match self.dk.diversifier(j) { - Ok(ret) => ret, - Err(()) => return Err(()), - }; - match self.fvk.vk.into_payment_address(d_j, &JUBJUB) { - Some(addr) => Ok((j, addr)), - None => Err(()), - } - } - - pub fn default_address(&self) -> Result<(DiversifierIndex, PaymentAddress), ()> { - self.address(DiversifierIndex::new()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn derive_nonhardened_child() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - let xfvk_m = ExtendedFullViewingKey::from(&xsk_m); - - let i_5 = ChildIndex::NonHardened(5); - let xsk_5 = xsk_m.derive_child(i_5); - let xfvk_5 = xfvk_m.derive_child(i_5); - - assert!(xfvk_5.is_ok()); - assert_eq!(ExtendedFullViewingKey::from(&xsk_5), xfvk_5.unwrap()); - } - - #[test] - fn derive_hardened_child() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - let xfvk_m = ExtendedFullViewingKey::from(&xsk_m); - - let i_5h = ChildIndex::Hardened(5); - let xsk_5h = xsk_m.derive_child(i_5h); - let xfvk_5h = xfvk_m.derive_child(i_5h); - - // Cannot derive a hardened child from an ExtendedFullViewingKey - assert!(xfvk_5h.is_err()); - let xfvk_5h = ExtendedFullViewingKey::from(&xsk_5h); - - let i_7 = ChildIndex::NonHardened(7); - let xsk_5h_7 = xsk_5h.derive_child(i_7); - let xfvk_5h_7 = xfvk_5h.derive_child(i_7); - - // But we *can* derive a non-hardened child from a hardened parent - assert!(xfvk_5h_7.is_ok()); - assert_eq!(ExtendedFullViewingKey::from(&xsk_5h_7), xfvk_5h_7.unwrap()); - } - - #[test] - fn path() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - - let xsk_5h = xsk_m.derive_child(ChildIndex::Hardened(5)); - assert_eq!( - ExtendedSpendingKey::from_path(&xsk_m, &[ChildIndex::Hardened(5)]), - xsk_5h - ); - - let xsk_5h_7 = xsk_5h.derive_child(ChildIndex::NonHardened(7)); - assert_eq!( - ExtendedSpendingKey::from_path( - &xsk_m, - &[ChildIndex::Hardened(5), ChildIndex::NonHardened(7)] - ), - xsk_5h_7 - ); - } - - #[test] - fn diversifier() { - let dk = DiversifierKey([0; 32]); - let j_0 = DiversifierIndex::new(); - let j_1 = DiversifierIndex([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - let j_2 = DiversifierIndex([2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - let j_3 = DiversifierIndex([3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - // Computed using this Rust implementation - let d_0 = [220, 231, 126, 188, 236, 10, 38, 175, 214, 153, 140]; - let d_3 = [60, 253, 170, 8, 171, 147, 220, 31, 3, 144, 34]; - - // j = 0 - let (j, d_j) = dk.diversifier(j_0).unwrap(); - assert_eq!(j, j_0); - assert_eq!(d_j.0, d_0); - - // j = 1 - let (j, d_j) = dk.diversifier(j_1).unwrap(); - assert_eq!(j, j_3); - assert_eq!(d_j.0, d_3); - - // j = 2 - let (j, d_j) = dk.diversifier(j_2).unwrap(); - assert_eq!(j, j_3); - assert_eq!(d_j.0, d_3); - - // j = 3 - let (j, d_j) = dk.diversifier(j_3).unwrap(); - assert_eq!(j, j_3); - assert_eq!(d_j.0, d_3); - } - - #[test] - fn default_address() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - let (j_m, addr_m) = xsk_m.default_address().unwrap(); - assert_eq!(j_m.0, [0; 11]); - assert_eq!( - addr_m.diversifier.0, - // Computed using this Rust implementation - [59, 246, 250, 31, 131, 191, 69, 99, 200, 167, 19] - ); - } - - #[test] - fn read_write() { - let seed = [0; 32]; - let xsk = ExtendedSpendingKey::master(&seed); - let fvk = ExtendedFullViewingKey::from(&xsk); - - let mut ser = vec![]; - xsk.write(&mut ser).unwrap(); - let xsk2 = ExtendedSpendingKey::read(&ser[..]).unwrap(); - assert_eq!(xsk2, xsk); - - let mut ser = vec![]; - fvk.write(&mut ser).unwrap(); - let fvk2 = ExtendedFullViewingKey::read(&ser[..]).unwrap(); - assert_eq!(fvk2, fvk); - } - - #[test] - fn test_vectors() { - struct TestVector { - ask: Option<[u8; 32]>, - nsk: Option<[u8; 32]>, - ovk: [u8; 32], - dk: [u8; 32], - c: [u8; 32], - ak: [u8; 32], - nk: [u8; 32], - ivk: [u8; 32], - xsk: Option<[u8; 169]>, - xfvk: [u8; 169], - fp: [u8; 32], - d0: Option<[u8; 11]>, - d1: Option<[u8; 11]>, - d2: Option<[u8; 11]>, - dmax: Option<[u8; 11]>, - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_zip32.py - let test_vectors = vec![ - TestVector { - ask: Some([ - 0xb6, 0xc0, 0x0c, 0x93, 0xd3, 0x60, 0x32, 0xb9, 0xa2, 0x68, 0xe9, 0x9e, 0x86, - 0xa8, 0x60, 0x77, 0x65, 0x60, 0xbf, 0x0e, 0x83, 0xc1, 0xa1, 0x0b, 0x51, 0xf6, - 0x07, 0xc9, 0x54, 0x74, 0x25, 0x06, - ]), - nsk: Some([ - 0x82, 0x04, 0xed, 0xe8, 0x3b, 0x2f, 0x1f, 0xbd, 0x84, 0xf9, 0xb4, 0x5d, 0x7f, - 0x99, 0x6e, 0x2e, 0xbd, 0x0a, 0x03, 0x0a, 0xd2, 0x43, 0xb4, 0x8e, 0xd3, 0x9f, - 0x74, 0x8a, 0x88, 0x21, 0xea, 0x06, - ]), - ovk: [ - 0x39, 0x58, 0x84, 0x89, 0x03, 0x23, 0xb9, 0xd4, 0x93, 0x3c, 0x02, 0x1d, 0xb8, - 0x9b, 0xcf, 0x76, 0x7d, 0xf2, 0x19, 0x77, 0xb2, 0xff, 0x06, 0x83, 0x84, 0x83, - 0x21, 0xa4, 0xdf, 0x4a, 0xfb, 0x21, - ], - dk: [ - 0x77, 0xc1, 0x7c, 0xb7, 0x5b, 0x77, 0x96, 0xaf, 0xb3, 0x9f, 0x0f, 0x3e, 0x91, - 0xc9, 0x24, 0x60, 0x7d, 0xa5, 0x6f, 0xa9, 0xa2, 0x0e, 0x28, 0x35, 0x09, 0xbc, - 0x8a, 0x3e, 0xf9, 0x96, 0xa1, 0x72, - ], - c: [ - 0xd0, 0x94, 0x7c, 0x4b, 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, - 0x6d, 0x1c, 0xf3, 0xfd, 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, - 0x0d, 0x75, 0x20, 0x18, 0x66, 0x8e, - ], - ak: [ - 0x93, 0x44, 0x2e, 0x5f, 0xef, 0xfb, 0xff, 0x16, 0xe7, 0x21, 0x72, 0x02, 0xdc, - 0x73, 0x06, 0x72, 0x9f, 0xff, 0xfe, 0x85, 0xaf, 0x56, 0x83, 0xbc, 0xe2, 0x64, - 0x2e, 0x3e, 0xeb, 0x5d, 0x38, 0x71, - ], - nk: [ - 0xdc, 0xe8, 0xe7, 0xed, 0xec, 0xe0, 0x4b, 0x89, 0x50, 0x41, 0x7f, 0x85, 0xba, - 0x57, 0x69, 0x1b, 0x78, 0x3c, 0x45, 0xb1, 0xa2, 0x74, 0x22, 0xdb, 0x16, 0x93, - 0xdc, 0xeb, 0x67, 0xb1, 0x01, 0x06, - ], - ivk: [ - 0x48, 0x47, 0xa1, 0x30, 0xe7, 0x99, 0xd3, 0xdb, 0xea, 0x36, 0xa1, 0xc1, 0x64, - 0x67, 0xd6, 0x21, 0xfb, 0x2d, 0x80, 0xe3, 0x0b, 0x3b, 0x1d, 0x1a, 0x42, 0x68, - 0x93, 0x41, 0x5d, 0xad, 0x66, 0x01, - ], - xsk: Some([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x94, 0x7c, 0x4b, - 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, 0x6d, 0x1c, 0xf3, 0xfd, - 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, 0x0d, 0x75, 0x20, 0x18, - 0x66, 0x8e, 0xb6, 0xc0, 0x0c, 0x93, 0xd3, 0x60, 0x32, 0xb9, 0xa2, 0x68, 0xe9, - 0x9e, 0x86, 0xa8, 0x60, 0x77, 0x65, 0x60, 0xbf, 0x0e, 0x83, 0xc1, 0xa1, 0x0b, - 0x51, 0xf6, 0x07, 0xc9, 0x54, 0x74, 0x25, 0x06, 0x82, 0x04, 0xed, 0xe8, 0x3b, - 0x2f, 0x1f, 0xbd, 0x84, 0xf9, 0xb4, 0x5d, 0x7f, 0x99, 0x6e, 0x2e, 0xbd, 0x0a, - 0x03, 0x0a, 0xd2, 0x43, 0xb4, 0x8e, 0xd3, 0x9f, 0x74, 0x8a, 0x88, 0x21, 0xea, - 0x06, 0x39, 0x58, 0x84, 0x89, 0x03, 0x23, 0xb9, 0xd4, 0x93, 0x3c, 0x02, 0x1d, - 0xb8, 0x9b, 0xcf, 0x76, 0x7d, 0xf2, 0x19, 0x77, 0xb2, 0xff, 0x06, 0x83, 0x84, - 0x83, 0x21, 0xa4, 0xdf, 0x4a, 0xfb, 0x21, 0x77, 0xc1, 0x7c, 0xb7, 0x5b, 0x77, - 0x96, 0xaf, 0xb3, 0x9f, 0x0f, 0x3e, 0x91, 0xc9, 0x24, 0x60, 0x7d, 0xa5, 0x6f, - 0xa9, 0xa2, 0x0e, 0x28, 0x35, 0x09, 0xbc, 0x8a, 0x3e, 0xf9, 0x96, 0xa1, 0x72, - ]), - xfvk: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x94, 0x7c, 0x4b, - 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, 0x6d, 0x1c, 0xf3, 0xfd, - 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, 0x0d, 0x75, 0x20, 0x18, - 0x66, 0x8e, 0x93, 0x44, 0x2e, 0x5f, 0xef, 0xfb, 0xff, 0x16, 0xe7, 0x21, 0x72, - 0x02, 0xdc, 0x73, 0x06, 0x72, 0x9f, 0xff, 0xfe, 0x85, 0xaf, 0x56, 0x83, 0xbc, - 0xe2, 0x64, 0x2e, 0x3e, 0xeb, 0x5d, 0x38, 0x71, 0xdc, 0xe8, 0xe7, 0xed, 0xec, - 0xe0, 0x4b, 0x89, 0x50, 0x41, 0x7f, 0x85, 0xba, 0x57, 0x69, 0x1b, 0x78, 0x3c, - 0x45, 0xb1, 0xa2, 0x74, 0x22, 0xdb, 0x16, 0x93, 0xdc, 0xeb, 0x67, 0xb1, 0x01, - 0x06, 0x39, 0x58, 0x84, 0x89, 0x03, 0x23, 0xb9, 0xd4, 0x93, 0x3c, 0x02, 0x1d, - 0xb8, 0x9b, 0xcf, 0x76, 0x7d, 0xf2, 0x19, 0x77, 0xb2, 0xff, 0x06, 0x83, 0x84, - 0x83, 0x21, 0xa4, 0xdf, 0x4a, 0xfb, 0x21, 0x77, 0xc1, 0x7c, 0xb7, 0x5b, 0x77, - 0x96, 0xaf, 0xb3, 0x9f, 0x0f, 0x3e, 0x91, 0xc9, 0x24, 0x60, 0x7d, 0xa5, 0x6f, - 0xa9, 0xa2, 0x0e, 0x28, 0x35, 0x09, 0xbc, 0x8a, 0x3e, 0xf9, 0x96, 0xa1, 0x72, - ], - fp: [ - 0x14, 0xc2, 0x71, 0x3a, 0xdc, 0xe9, 0x3a, 0x83, 0x0e, 0xa8, 0x3a, 0x05, 0x19, - 0x08, 0xb7, 0x44, 0x77, 0x83, 0xf5, 0xd1, 0x06, 0xc0, 0x98, 0x5e, 0x02, 0x55, - 0x0e, 0x42, 0x6f, 0x27, 0x59, 0x7c, - ], - d0: Some([ - 0xd8, 0x62, 0x1b, 0x98, 0x1c, 0xf3, 0x00, 0xe9, 0xd4, 0xcc, 0x89, - ]), - d1: Some([ - 0x48, 0xea, 0x17, 0xa1, 0x99, 0xc8, 0x4b, 0xd1, 0xba, 0xa5, 0xd4, - ]), - d2: None, - dmax: None, - }, - TestVector { - ask: Some([ - 0x28, 0x2b, 0xc1, 0x97, 0xa5, 0x16, 0x28, 0x7c, 0x8e, 0xa8, 0xf6, 0x8c, 0x42, - 0x4a, 0xba, 0xd3, 0x02, 0xb4, 0x5c, 0xdf, 0x95, 0x40, 0x79, 0x61, 0xd7, 0xb8, - 0xb4, 0x55, 0x26, 0x7a, 0x35, 0x0c, - ]), - nsk: Some([ - 0xe7, 0xa3, 0x29, 0x88, 0xfd, 0xca, 0x1e, 0xfc, 0xd6, 0xd1, 0xc4, 0xc5, 0x62, - 0xe6, 0x29, 0xc2, 0xe9, 0x6b, 0x2c, 0x3f, 0x7e, 0xda, 0x04, 0xac, 0x4e, 0xfd, - 0x18, 0x10, 0xff, 0x6b, 0xba, 0x01, - ]), - ovk: [ - 0x5f, 0x13, 0x81, 0xfc, 0x88, 0x86, 0xda, 0x6a, 0x02, 0xdf, 0xfe, 0xef, 0xcf, - 0x50, 0x3c, 0x40, 0xfa, 0x8f, 0x5a, 0x36, 0xf7, 0xa7, 0x14, 0x2f, 0xd8, 0x1b, - 0x55, 0x18, 0xc5, 0xa4, 0x74, 0x74, - ], - dk: [ - 0xe0, 0x4d, 0xe8, 0x32, 0xa2, 0xd7, 0x91, 0xec, 0x12, 0x9a, 0xb9, 0x00, 0x2b, - 0x91, 0xc9, 0xe9, 0xcd, 0xee, 0xd7, 0x92, 0x41, 0xa7, 0xc4, 0x96, 0x0e, 0x51, - 0x78, 0xd8, 0x70, 0xc1, 0xb4, 0xdc, - ], - c: [ - 0x01, 0x47, 0x11, 0x0c, 0x69, 0x1a, 0x03, 0xb9, 0xd9, 0xf0, 0xba, 0x90, 0x05, - 0xc5, 0xe7, 0x90, 0xa5, 0x95, 0xb7, 0xf0, 0x4e, 0x33, 0x29, 0xd2, 0xfa, 0x43, - 0x8a, 0x67, 0x05, 0xda, 0xbc, 0xe6, - ], - ak: [ - 0xdc, 0x14, 0xb5, 0x14, 0xd3, 0xa9, 0x25, 0x94, 0xc2, 0x19, 0x25, 0xaf, 0x2f, - 0x77, 0x65, 0xa5, 0x47, 0xb3, 0x0e, 0x73, 0xfa, 0x7b, 0x70, 0x0e, 0xa1, 0xbf, - 0xf2, 0xe5, 0xef, 0xaa, 0xa8, 0x8b, - ], - nk: [ - 0x61, 0x52, 0xeb, 0x7f, 0xdb, 0x25, 0x27, 0x79, 0xdd, 0xcb, 0x95, 0xd2, 0x17, - 0xea, 0x4b, 0x6f, 0xd3, 0x40, 0x36, 0xe9, 0xad, 0xad, 0xb3, 0xb5, 0xc9, 0xcb, - 0xec, 0xeb, 0x41, 0xba, 0x45, 0x2a, - ], - ivk: [ - 0x15, 0x5a, 0x8e, 0xe2, 0x05, 0xd3, 0x87, 0x2d, 0x12, 0xf8, 0xa3, 0xe6, 0x39, - 0x91, 0x46, 0x33, 0xc2, 0x3c, 0xde, 0x1f, 0x30, 0xed, 0x50, 0x51, 0xe5, 0x21, - 0x30, 0xb1, 0xd0, 0x10, 0x4c, 0x06, - ], - xsk: Some([ - 0x01, 0x14, 0xc2, 0x71, 0x3a, 0x01, 0x00, 0x00, 0x00, 0x01, 0x47, 0x11, 0x0c, - 0x69, 0x1a, 0x03, 0xb9, 0xd9, 0xf0, 0xba, 0x90, 0x05, 0xc5, 0xe7, 0x90, 0xa5, - 0x95, 0xb7, 0xf0, 0x4e, 0x33, 0x29, 0xd2, 0xfa, 0x43, 0x8a, 0x67, 0x05, 0xda, - 0xbc, 0xe6, 0x28, 0x2b, 0xc1, 0x97, 0xa5, 0x16, 0x28, 0x7c, 0x8e, 0xa8, 0xf6, - 0x8c, 0x42, 0x4a, 0xba, 0xd3, 0x02, 0xb4, 0x5c, 0xdf, 0x95, 0x40, 0x79, 0x61, - 0xd7, 0xb8, 0xb4, 0x55, 0x26, 0x7a, 0x35, 0x0c, 0xe7, 0xa3, 0x29, 0x88, 0xfd, - 0xca, 0x1e, 0xfc, 0xd6, 0xd1, 0xc4, 0xc5, 0x62, 0xe6, 0x29, 0xc2, 0xe9, 0x6b, - 0x2c, 0x3f, 0x7e, 0xda, 0x04, 0xac, 0x4e, 0xfd, 0x18, 0x10, 0xff, 0x6b, 0xba, - 0x01, 0x5f, 0x13, 0x81, 0xfc, 0x88, 0x86, 0xda, 0x6a, 0x02, 0xdf, 0xfe, 0xef, - 0xcf, 0x50, 0x3c, 0x40, 0xfa, 0x8f, 0x5a, 0x36, 0xf7, 0xa7, 0x14, 0x2f, 0xd8, - 0x1b, 0x55, 0x18, 0xc5, 0xa4, 0x74, 0x74, 0xe0, 0x4d, 0xe8, 0x32, 0xa2, 0xd7, - 0x91, 0xec, 0x12, 0x9a, 0xb9, 0x00, 0x2b, 0x91, 0xc9, 0xe9, 0xcd, 0xee, 0xd7, - 0x92, 0x41, 0xa7, 0xc4, 0x96, 0x0e, 0x51, 0x78, 0xd8, 0x70, 0xc1, 0xb4, 0xdc, - ]), - xfvk: [ - 0x01, 0x14, 0xc2, 0x71, 0x3a, 0x01, 0x00, 0x00, 0x00, 0x01, 0x47, 0x11, 0x0c, - 0x69, 0x1a, 0x03, 0xb9, 0xd9, 0xf0, 0xba, 0x90, 0x05, 0xc5, 0xe7, 0x90, 0xa5, - 0x95, 0xb7, 0xf0, 0x4e, 0x33, 0x29, 0xd2, 0xfa, 0x43, 0x8a, 0x67, 0x05, 0xda, - 0xbc, 0xe6, 0xdc, 0x14, 0xb5, 0x14, 0xd3, 0xa9, 0x25, 0x94, 0xc2, 0x19, 0x25, - 0xaf, 0x2f, 0x77, 0x65, 0xa5, 0x47, 0xb3, 0x0e, 0x73, 0xfa, 0x7b, 0x70, 0x0e, - 0xa1, 0xbf, 0xf2, 0xe5, 0xef, 0xaa, 0xa8, 0x8b, 0x61, 0x52, 0xeb, 0x7f, 0xdb, - 0x25, 0x27, 0x79, 0xdd, 0xcb, 0x95, 0xd2, 0x17, 0xea, 0x4b, 0x6f, 0xd3, 0x40, - 0x36, 0xe9, 0xad, 0xad, 0xb3, 0xb5, 0xc9, 0xcb, 0xec, 0xeb, 0x41, 0xba, 0x45, - 0x2a, 0x5f, 0x13, 0x81, 0xfc, 0x88, 0x86, 0xda, 0x6a, 0x02, 0xdf, 0xfe, 0xef, - 0xcf, 0x50, 0x3c, 0x40, 0xfa, 0x8f, 0x5a, 0x36, 0xf7, 0xa7, 0x14, 0x2f, 0xd8, - 0x1b, 0x55, 0x18, 0xc5, 0xa4, 0x74, 0x74, 0xe0, 0x4d, 0xe8, 0x32, 0xa2, 0xd7, - 0x91, 0xec, 0x12, 0x9a, 0xb9, 0x00, 0x2b, 0x91, 0xc9, 0xe9, 0xcd, 0xee, 0xd7, - 0x92, 0x41, 0xa7, 0xc4, 0x96, 0x0e, 0x51, 0x78, 0xd8, 0x70, 0xc1, 0xb4, 0xdc, - ], - fp: [ - 0xdb, 0x99, 0x9e, 0x07, 0x1d, 0xcb, 0x58, 0xdd, 0x93, 0x02, 0x9a, 0xe6, 0x97, - 0x05, 0x3e, 0x90, 0xed, 0xb3, 0x59, 0xd1, 0xa1, 0xb7, 0xa1, 0x25, 0x16, 0x7e, - 0xfb, 0xe9, 0x28, 0x06, 0x84, 0x23, - ], - d0: Some([ - 0x8b, 0x41, 0x38, 0x32, 0x0d, 0xfa, 0xfd, 0x7b, 0x39, 0x97, 0x81, - ]), - d1: None, - d2: Some([ - 0x57, 0x49, 0xa1, 0x33, 0x52, 0xbc, 0x22, 0x3e, 0x30, 0x80, 0x78, - ]), - dmax: Some([ - 0x63, 0x89, 0x57, 0x4c, 0xde, 0x0f, 0xbb, 0xc6, 0x36, 0x81, 0x31, - ]), - }, - TestVector { - ask: Some([ - 0x8b, 0xe8, 0x11, 0x3c, 0xee, 0x34, 0x13, 0xa7, 0x1f, 0x82, 0xc4, 0x1f, 0xc8, - 0xda, 0x51, 0x7b, 0xe1, 0x34, 0x04, 0x98, 0x32, 0xe6, 0x82, 0x5c, 0x92, 0xda, - 0x6b, 0x84, 0xfe, 0xe4, 0xc6, 0x0d, - ]), - nsk: Some([ - 0x37, 0x78, 0x05, 0x9d, 0xc5, 0x69, 0xe7, 0xd0, 0xd3, 0x23, 0x91, 0x57, 0x3f, - 0x95, 0x1b, 0xbd, 0xe9, 0x2f, 0xc6, 0xb9, 0xcf, 0x61, 0x47, 0x73, 0x66, 0x1c, - 0x5c, 0x27, 0x3a, 0xa6, 0x99, 0x0c, - ]), - ovk: [ - 0xcf, 0x81, 0x18, 0x2e, 0x96, 0x22, 0x3c, 0x02, 0x8c, 0xe3, 0xd6, 0xeb, 0x47, - 0x94, 0xd3, 0x11, 0x3b, 0x95, 0x06, 0x9d, 0x14, 0xc5, 0x75, 0x88, 0xe1, 0x93, - 0xb6, 0x5e, 0xfc, 0x28, 0x13, 0xbc, - ], - dk: [ - 0xa3, 0xed, 0xa1, 0x9f, 0x9e, 0xff, 0x46, 0xca, 0x12, 0xdf, 0xa1, 0xbf, 0x10, - 0x37, 0x1b, 0x48, 0xd1, 0xb4, 0xa4, 0x0c, 0x4d, 0x05, 0xa0, 0xd8, 0xdc, 0xe0, - 0xe7, 0xdc, 0x62, 0xb0, 0x7b, 0x37, - ], - c: [ - 0x97, 0xce, 0x15, 0xf4, 0xed, 0x1b, 0x97, 0x39, 0xb0, 0x26, 0x2a, 0x46, 0x3b, - 0xcb, 0x3d, 0xc9, 0xb3, 0xbd, 0x23, 0x23, 0xa9, 0xba, 0xa4, 0x41, 0xca, 0x42, - 0x77, 0x73, 0x83, 0xa8, 0xd4, 0x35, - ], - ak: [ - 0xa6, 0xc5, 0x92, 0x5a, 0x0f, 0x85, 0xfa, 0x4f, 0x1e, 0x40, 0x5e, 0x3a, 0x49, - 0x70, 0xd0, 0xc4, 0xa4, 0xb4, 0x81, 0x44, 0x38, 0xf4, 0xe9, 0xd4, 0x52, 0x0e, - 0x20, 0xf7, 0xfd, 0xcf, 0x38, 0x41, - ], - nk: [ - 0x30, 0x4e, 0x30, 0x59, 0x16, 0x21, 0x6b, 0xeb, 0x7b, 0x65, 0x4d, 0x8a, 0xae, - 0x50, 0xec, 0xd1, 0x88, 0xfc, 0xb3, 0x84, 0xbc, 0x36, 0xc0, 0x0c, 0x66, 0x4f, - 0x30, 0x77, 0x25, 0xe2, 0xee, 0x11, - ], - ivk: [ - 0xa2, 0xa1, 0x3c, 0x1e, 0x38, 0xb4, 0x59, 0x84, 0x44, 0x58, 0x03, 0xe4, 0x30, - 0xa6, 0x83, 0xc9, 0x0b, 0xb2, 0xe1, 0x4d, 0x4c, 0x86, 0x92, 0xff, 0x25, 0x3a, - 0x64, 0x84, 0xdd, 0x9b, 0xb5, 0x04, - ], - xsk: Some([ - 0x02, 0xdb, 0x99, 0x9e, 0x07, 0x02, 0x00, 0x00, 0x80, 0x97, 0xce, 0x15, 0xf4, - 0xed, 0x1b, 0x97, 0x39, 0xb0, 0x26, 0x2a, 0x46, 0x3b, 0xcb, 0x3d, 0xc9, 0xb3, - 0xbd, 0x23, 0x23, 0xa9, 0xba, 0xa4, 0x41, 0xca, 0x42, 0x77, 0x73, 0x83, 0xa8, - 0xd4, 0x35, 0x8b, 0xe8, 0x11, 0x3c, 0xee, 0x34, 0x13, 0xa7, 0x1f, 0x82, 0xc4, - 0x1f, 0xc8, 0xda, 0x51, 0x7b, 0xe1, 0x34, 0x04, 0x98, 0x32, 0xe6, 0x82, 0x5c, - 0x92, 0xda, 0x6b, 0x84, 0xfe, 0xe4, 0xc6, 0x0d, 0x37, 0x78, 0x05, 0x9d, 0xc5, - 0x69, 0xe7, 0xd0, 0xd3, 0x23, 0x91, 0x57, 0x3f, 0x95, 0x1b, 0xbd, 0xe9, 0x2f, - 0xc6, 0xb9, 0xcf, 0x61, 0x47, 0x73, 0x66, 0x1c, 0x5c, 0x27, 0x3a, 0xa6, 0x99, - 0x0c, 0xcf, 0x81, 0x18, 0x2e, 0x96, 0x22, 0x3c, 0x02, 0x8c, 0xe3, 0xd6, 0xeb, - 0x47, 0x94, 0xd3, 0x11, 0x3b, 0x95, 0x06, 0x9d, 0x14, 0xc5, 0x75, 0x88, 0xe1, - 0x93, 0xb6, 0x5e, 0xfc, 0x28, 0x13, 0xbc, 0xa3, 0xed, 0xa1, 0x9f, 0x9e, 0xff, - 0x46, 0xca, 0x12, 0xdf, 0xa1, 0xbf, 0x10, 0x37, 0x1b, 0x48, 0xd1, 0xb4, 0xa4, - 0x0c, 0x4d, 0x05, 0xa0, 0xd8, 0xdc, 0xe0, 0xe7, 0xdc, 0x62, 0xb0, 0x7b, 0x37, - ]), - xfvk: [ - 0x02, 0xdb, 0x99, 0x9e, 0x07, 0x02, 0x00, 0x00, 0x80, 0x97, 0xce, 0x15, 0xf4, - 0xed, 0x1b, 0x97, 0x39, 0xb0, 0x26, 0x2a, 0x46, 0x3b, 0xcb, 0x3d, 0xc9, 0xb3, - 0xbd, 0x23, 0x23, 0xa9, 0xba, 0xa4, 0x41, 0xca, 0x42, 0x77, 0x73, 0x83, 0xa8, - 0xd4, 0x35, 0xa6, 0xc5, 0x92, 0x5a, 0x0f, 0x85, 0xfa, 0x4f, 0x1e, 0x40, 0x5e, - 0x3a, 0x49, 0x70, 0xd0, 0xc4, 0xa4, 0xb4, 0x81, 0x44, 0x38, 0xf4, 0xe9, 0xd4, - 0x52, 0x0e, 0x20, 0xf7, 0xfd, 0xcf, 0x38, 0x41, 0x30, 0x4e, 0x30, 0x59, 0x16, - 0x21, 0x6b, 0xeb, 0x7b, 0x65, 0x4d, 0x8a, 0xae, 0x50, 0xec, 0xd1, 0x88, 0xfc, - 0xb3, 0x84, 0xbc, 0x36, 0xc0, 0x0c, 0x66, 0x4f, 0x30, 0x77, 0x25, 0xe2, 0xee, - 0x11, 0xcf, 0x81, 0x18, 0x2e, 0x96, 0x22, 0x3c, 0x02, 0x8c, 0xe3, 0xd6, 0xeb, - 0x47, 0x94, 0xd3, 0x11, 0x3b, 0x95, 0x06, 0x9d, 0x14, 0xc5, 0x75, 0x88, 0xe1, - 0x93, 0xb6, 0x5e, 0xfc, 0x28, 0x13, 0xbc, 0xa3, 0xed, 0xa1, 0x9f, 0x9e, 0xff, - 0x46, 0xca, 0x12, 0xdf, 0xa1, 0xbf, 0x10, 0x37, 0x1b, 0x48, 0xd1, 0xb4, 0xa4, - 0x0c, 0x4d, 0x05, 0xa0, 0xd8, 0xdc, 0xe0, 0xe7, 0xdc, 0x62, 0xb0, 0x7b, 0x37, - ], - fp: [ - 0x48, 0xc1, 0x83, 0x75, 0x7b, 0x5d, 0xa6, 0x61, 0x2a, 0x81, 0xb3, 0x0e, 0x40, - 0xb4, 0xac, 0xaa, 0x2d, 0x9e, 0x73, 0x95, 0x12, 0xe1, 0xd2, 0xd0, 0x01, 0x0e, - 0x92, 0xa7, 0xf7, 0xf2, 0xfc, 0xdf, - ], - d0: Some([ - 0xe8, 0xd0, 0x37, 0x93, 0xcd, 0xd2, 0xba, 0xcc, 0x9c, 0x70, 0x41, - ]), - d1: Some([ - 0x02, 0x0a, 0x7a, 0x6b, 0x0b, 0xf8, 0x4d, 0x3e, 0x89, 0x9f, 0x68, - ]), - d2: None, - dmax: None, - }, - TestVector { - ask: None, - nsk: None, - ovk: [ - 0xcf, 0x81, 0x18, 0x2e, 0x96, 0x22, 0x3c, 0x02, 0x8c, 0xe3, 0xd6, 0xeb, 0x47, - 0x94, 0xd3, 0x11, 0x3b, 0x95, 0x06, 0x9d, 0x14, 0xc5, 0x75, 0x88, 0xe1, 0x93, - 0xb6, 0x5e, 0xfc, 0x28, 0x13, 0xbc, - ], - dk: [ - 0xa3, 0xed, 0xa1, 0x9f, 0x9e, 0xff, 0x46, 0xca, 0x12, 0xdf, 0xa1, 0xbf, 0x10, - 0x37, 0x1b, 0x48, 0xd1, 0xb4, 0xa4, 0x0c, 0x4d, 0x05, 0xa0, 0xd8, 0xdc, 0xe0, - 0xe7, 0xdc, 0x62, 0xb0, 0x7b, 0x37, - ], - c: [ - 0x97, 0xce, 0x15, 0xf4, 0xed, 0x1b, 0x97, 0x39, 0xb0, 0x26, 0x2a, 0x46, 0x3b, - 0xcb, 0x3d, 0xc9, 0xb3, 0xbd, 0x23, 0x23, 0xa9, 0xba, 0xa4, 0x41, 0xca, 0x42, - 0x77, 0x73, 0x83, 0xa8, 0xd4, 0x35, - ], - ak: [ - 0xa6, 0xc5, 0x92, 0x5a, 0x0f, 0x85, 0xfa, 0x4f, 0x1e, 0x40, 0x5e, 0x3a, 0x49, - 0x70, 0xd0, 0xc4, 0xa4, 0xb4, 0x81, 0x44, 0x38, 0xf4, 0xe9, 0xd4, 0x52, 0x0e, - 0x20, 0xf7, 0xfd, 0xcf, 0x38, 0x41, - ], - nk: [ - 0x30, 0x4e, 0x30, 0x59, 0x16, 0x21, 0x6b, 0xeb, 0x7b, 0x65, 0x4d, 0x8a, 0xae, - 0x50, 0xec, 0xd1, 0x88, 0xfc, 0xb3, 0x84, 0xbc, 0x36, 0xc0, 0x0c, 0x66, 0x4f, - 0x30, 0x77, 0x25, 0xe2, 0xee, 0x11, - ], - ivk: [ - 0xa2, 0xa1, 0x3c, 0x1e, 0x38, 0xb4, 0x59, 0x84, 0x44, 0x58, 0x03, 0xe4, 0x30, - 0xa6, 0x83, 0xc9, 0x0b, 0xb2, 0xe1, 0x4d, 0x4c, 0x86, 0x92, 0xff, 0x25, 0x3a, - 0x64, 0x84, 0xdd, 0x9b, 0xb5, 0x04, - ], - xsk: None, - xfvk: [ - 0x02, 0xdb, 0x99, 0x9e, 0x07, 0x02, 0x00, 0x00, 0x80, 0x97, 0xce, 0x15, 0xf4, - 0xed, 0x1b, 0x97, 0x39, 0xb0, 0x26, 0x2a, 0x46, 0x3b, 0xcb, 0x3d, 0xc9, 0xb3, - 0xbd, 0x23, 0x23, 0xa9, 0xba, 0xa4, 0x41, 0xca, 0x42, 0x77, 0x73, 0x83, 0xa8, - 0xd4, 0x35, 0xa6, 0xc5, 0x92, 0x5a, 0x0f, 0x85, 0xfa, 0x4f, 0x1e, 0x40, 0x5e, - 0x3a, 0x49, 0x70, 0xd0, 0xc4, 0xa4, 0xb4, 0x81, 0x44, 0x38, 0xf4, 0xe9, 0xd4, - 0x52, 0x0e, 0x20, 0xf7, 0xfd, 0xcf, 0x38, 0x41, 0x30, 0x4e, 0x30, 0x59, 0x16, - 0x21, 0x6b, 0xeb, 0x7b, 0x65, 0x4d, 0x8a, 0xae, 0x50, 0xec, 0xd1, 0x88, 0xfc, - 0xb3, 0x84, 0xbc, 0x36, 0xc0, 0x0c, 0x66, 0x4f, 0x30, 0x77, 0x25, 0xe2, 0xee, - 0x11, 0xcf, 0x81, 0x18, 0x2e, 0x96, 0x22, 0x3c, 0x02, 0x8c, 0xe3, 0xd6, 0xeb, - 0x47, 0x94, 0xd3, 0x11, 0x3b, 0x95, 0x06, 0x9d, 0x14, 0xc5, 0x75, 0x88, 0xe1, - 0x93, 0xb6, 0x5e, 0xfc, 0x28, 0x13, 0xbc, 0xa3, 0xed, 0xa1, 0x9f, 0x9e, 0xff, - 0x46, 0xca, 0x12, 0xdf, 0xa1, 0xbf, 0x10, 0x37, 0x1b, 0x48, 0xd1, 0xb4, 0xa4, - 0x0c, 0x4d, 0x05, 0xa0, 0xd8, 0xdc, 0xe0, 0xe7, 0xdc, 0x62, 0xb0, 0x7b, 0x37, - ], - fp: [ - 0x48, 0xc1, 0x83, 0x75, 0x7b, 0x5d, 0xa6, 0x61, 0x2a, 0x81, 0xb3, 0x0e, 0x40, - 0xb4, 0xac, 0xaa, 0x2d, 0x9e, 0x73, 0x95, 0x12, 0xe1, 0xd2, 0xd0, 0x01, 0x0e, - 0x92, 0xa7, 0xf7, 0xf2, 0xfc, 0xdf, - ], - d0: Some([ - 0xe8, 0xd0, 0x37, 0x93, 0xcd, 0xd2, 0xba, 0xcc, 0x9c, 0x70, 0x41, - ]), - d1: Some([ - 0x02, 0x0a, 0x7a, 0x6b, 0x0b, 0xf8, 0x4d, 0x3e, 0x89, 0x9f, 0x68, - ]), - d2: None, - dmax: None, - }, - TestVector { - ask: None, - nsk: None, - ovk: [ - 0x69, 0xb9, 0xe0, 0xfa, 0x1c, 0x4b, 0x3d, 0xeb, 0x91, 0xd5, 0x3b, 0xee, 0xe8, - 0x71, 0x15, 0x61, 0x21, 0x47, 0x4b, 0x8b, 0x62, 0xef, 0x24, 0x13, 0x44, 0x78, - 0xdc, 0x34, 0x99, 0x69, 0x1a, 0xf6, - ], - dk: [ - 0xbe, 0xcb, 0x50, 0xc3, 0x63, 0xbb, 0x2e, 0xd9, 0xda, 0x5c, 0x30, 0x43, 0xce, - 0xb0, 0xf1, 0xa0, 0x52, 0x7b, 0xf8, 0x36, 0xb2, 0x9a, 0x35, 0xf7, 0xc0, 0xc9, - 0xf2, 0x61, 0x12, 0x3b, 0xe5, 0x6e, - ], - c: [ - 0x8d, 0x93, 0x7b, 0xcf, 0x81, 0xba, 0x43, 0x0d, 0x5b, 0x49, 0xaf, 0xc0, 0xa4, - 0x03, 0x36, 0x7b, 0x1f, 0xd9, 0x98, 0x79, 0xec, 0xba, 0x41, 0xbe, 0x05, 0x1c, - 0x5a, 0x4a, 0xa7, 0xd6, 0xe7, 0xe8, - ], - ak: [ - 0xb1, 0x85, 0xc5, 0x7b, 0x50, 0x9c, 0x25, 0x36, 0xc4, 0xf2, 0xd3, 0x26, 0xd7, - 0x66, 0xc8, 0xfa, 0xb2, 0x54, 0x47, 0xde, 0x53, 0x75, 0xa9, 0x32, 0x8d, 0x64, - 0x9d, 0xda, 0xbd, 0x97, 0xa6, 0xa3, - ], - nk: [ - 0xdb, 0x88, 0x04, 0x9e, 0x02, 0xd2, 0x07, 0x56, 0x8a, 0xfc, 0x42, 0xe0, 0x7d, - 0xb2, 0xab, 0xed, 0x50, 0x0b, 0x27, 0x01, 0xc0, 0x1b, 0xbf, 0xf3, 0x63, 0x99, - 0x76, 0x4b, 0x81, 0xc0, 0x66, 0x4f, - ], - ivk: [ - 0xb0, 0xa5, 0xf3, 0x37, 0x23, 0x2f, 0x2c, 0x3d, 0xac, 0x70, 0xc2, 0xa4, 0x10, - 0xfa, 0x56, 0x1f, 0xc4, 0x5d, 0x8c, 0xc5, 0x9c, 0xda, 0x24, 0x6d, 0x31, 0xc8, - 0xb1, 0x71, 0x5a, 0x57, 0xd9, 0x00, - ], - xsk: None, - xfvk: [ - 0x03, 0x48, 0xc1, 0x83, 0x75, 0x03, 0x00, 0x00, 0x00, 0x8d, 0x93, 0x7b, 0xcf, - 0x81, 0xba, 0x43, 0x0d, 0x5b, 0x49, 0xaf, 0xc0, 0xa4, 0x03, 0x36, 0x7b, 0x1f, - 0xd9, 0x98, 0x79, 0xec, 0xba, 0x41, 0xbe, 0x05, 0x1c, 0x5a, 0x4a, 0xa7, 0xd6, - 0xe7, 0xe8, 0xb1, 0x85, 0xc5, 0x7b, 0x50, 0x9c, 0x25, 0x36, 0xc4, 0xf2, 0xd3, - 0x26, 0xd7, 0x66, 0xc8, 0xfa, 0xb2, 0x54, 0x47, 0xde, 0x53, 0x75, 0xa9, 0x32, - 0x8d, 0x64, 0x9d, 0xda, 0xbd, 0x97, 0xa6, 0xa3, 0xdb, 0x88, 0x04, 0x9e, 0x02, - 0xd2, 0x07, 0x56, 0x8a, 0xfc, 0x42, 0xe0, 0x7d, 0xb2, 0xab, 0xed, 0x50, 0x0b, - 0x27, 0x01, 0xc0, 0x1b, 0xbf, 0xf3, 0x63, 0x99, 0x76, 0x4b, 0x81, 0xc0, 0x66, - 0x4f, 0x69, 0xb9, 0xe0, 0xfa, 0x1c, 0x4b, 0x3d, 0xeb, 0x91, 0xd5, 0x3b, 0xee, - 0xe8, 0x71, 0x15, 0x61, 0x21, 0x47, 0x4b, 0x8b, 0x62, 0xef, 0x24, 0x13, 0x44, - 0x78, 0xdc, 0x34, 0x99, 0x69, 0x1a, 0xf6, 0xbe, 0xcb, 0x50, 0xc3, 0x63, 0xbb, - 0x2e, 0xd9, 0xda, 0x5c, 0x30, 0x43, 0xce, 0xb0, 0xf1, 0xa0, 0x52, 0x7b, 0xf8, - 0x36, 0xb2, 0x9a, 0x35, 0xf7, 0xc0, 0xc9, 0xf2, 0x61, 0x12, 0x3b, 0xe5, 0x6e, - ], - fp: [ - 0x2e, 0x08, 0x15, 0x6d, 0xf8, 0xdf, 0xa2, 0x5b, 0x50, 0x55, 0xfc, 0x06, 0x3c, - 0x67, 0x15, 0x35, 0xa6, 0xa6, 0x5a, 0x60, 0x43, 0x7d, 0x96, 0xe7, 0x93, 0x08, - 0x15, 0xd0, 0x90, 0xf6, 0x2d, 0x67, - ], - d0: None, - d1: Some([ - 0x03, 0x0f, 0xfb, 0x26, 0x3a, 0x93, 0x9e, 0x23, 0x0e, 0x96, 0xdd, - ]), - d2: Some([ - 0x7b, 0xbf, 0x63, 0x93, 0x4c, 0x7e, 0x92, 0x67, 0x0c, 0xdb, 0x55, - ]), - dmax: Some([ - 0x1a, 0x73, 0x0f, 0xeb, 0x00, 0x59, 0xcf, 0x1f, 0x5b, 0xde, 0xa8, - ]), - }, - ]; - - let seed = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - ]; - - let i1 = ChildIndex::NonHardened(1); - let i2h = ChildIndex::Hardened(2); - let i3 = ChildIndex::NonHardened(3); - - let m = ExtendedSpendingKey::master(&seed); - let m_1 = m.derive_child(i1); - let m_1_2h = ExtendedSpendingKey::from_path(&m, &[i1, i2h]); - let m_1_2hv = ExtendedFullViewingKey::from(&m_1_2h); - let m_1_2hv_3 = m_1_2hv.derive_child(i3).unwrap(); - - let xfvks = [ - ExtendedFullViewingKey::from(&m), - ExtendedFullViewingKey::from(&m_1), - ExtendedFullViewingKey::from(&m_1_2h), - m_1_2hv, // Appears twice so we can de-duplicate test code below - m_1_2hv_3, - ]; - assert_eq!(test_vectors.len(), xfvks.len()); - - let xsks = [m, m_1, m_1_2h]; - - for j in 0..xsks.len() { - let xsk = &xsks[j]; - let tv = &test_vectors[j]; - - let mut buf = [0; 32]; - xsk.expsk.ask.into_repr().write_le(&mut buf[..]).unwrap(); - assert_eq!(buf, tv.ask.unwrap()); - xsk.expsk.nsk.into_repr().write_le(&mut buf[..]).unwrap(); - assert_eq!(buf, tv.nsk.unwrap()); - - assert_eq!(xsk.expsk.ovk.0, tv.ovk); - assert_eq!(xsk.dk.0, tv.dk); - assert_eq!(xsk.chain_code.0, tv.c); - - let mut ser = vec![]; - xsk.write(&mut ser).unwrap(); - assert_eq!(&ser[..], &tv.xsk.unwrap()[..]); - } - - for j in 0..xfvks.len() { - let xfvk = &xfvks[j]; - let tv = &test_vectors[j]; - - let mut buf = [0; 32]; - xfvk.fvk.vk.ak.write(&mut buf[..]).unwrap(); - assert_eq!(buf, tv.ak); - xfvk.fvk.vk.nk.write(&mut buf[..]).unwrap(); - assert_eq!(buf, tv.nk); - - assert_eq!(xfvk.fvk.ovk.0, tv.ovk); - assert_eq!(xfvk.dk.0, tv.dk); - assert_eq!(xfvk.chain_code.0, tv.c); - - xfvk.fvk - .vk - .ivk() - .into_repr() - .write_le(&mut buf[..]) - .unwrap(); - assert_eq!(buf, tv.ivk); - - let mut ser = vec![]; - xfvk.write(&mut ser).unwrap(); - assert_eq!(&ser[..], &tv.xfvk[..]); - assert_eq!(xfvk.fvk.fingerprint().0, tv.fp); - - // d0 - let mut di = DiversifierIndex::new(); - match xfvk.dk.diversifier(di) { - Ok((l, d)) if l == di => assert_eq!(d.0, tv.d0.unwrap()), - Ok((_, _)) => assert!(tv.d0.is_none()), - Err(_) => panic!(), - } - - // d1 - di.increment().unwrap(); - match xfvk.dk.diversifier(di) { - Ok((l, d)) if l == di => assert_eq!(d.0, tv.d1.unwrap()), - Ok((_, _)) => assert!(tv.d1.is_none()), - Err(_) => panic!(), - } - - // d2 - di.increment().unwrap(); - match xfvk.dk.diversifier(di) { - Ok((l, d)) if l == di => assert_eq!(d.0, tv.d2.unwrap()), - Ok((_, _)) => assert!(tv.d2.is_none()), - Err(_) => panic!(), - } - - // dmax - let dmax = DiversifierIndex([0xff; 11]); - match xfvk.dk.diversifier(dmax) { - Ok((l, d)) if l == dmax => assert_eq!(d.0, tv.dmax.unwrap()), - Ok((_, _)) => panic!(), - Err(_) => assert!(tv.dmax.is_none()), - } - } - } -} From f337eb1f5c67d9305b1fb4fb35507bb50817259b Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 3 Mar 2020 17:46:04 -0700 Subject: [PATCH 323/330] Squashed 'bellman/' changes from 4272cfa..2279da4 2279da4 Merge pull request #38 from debris/docs 2e57190 Remove documentation entry from Cargo.toml 346d540 bellman 0.2.0 8d79665 Merge pull request #93 from defuse/qed-it-lrz f50079f Crate docs 701cb2b Update READMEs ccf1ee9 CI: Check intra-doc links ddd390a Add READMEs to Cargo.toml files 54d3122 Add missing cs.is_satisfied() to bellman test 52bf23c Fix build warnings 581ad35 boolean: adds tests for alloc_conditionally 0403396 blake2s: adds test vectors from go-jubjub 9f24e47 Fix blake2s test data length assertion. 42d5b3b Add blake2s test vectors for varying sizes from go-jubjub b2597de pedersen_hash: removes debug prints c903fad pedersen hashes: example of size limit bug bc697c1 bellman: Fix compile errors without multicore feature a4e5df9 Upgrade to hex-literal 0.2 c063509 Migrate bellman to crossbeam 0.7 1775843 Take self directly in into_* functions 614d784 Rename into_ -> to_ where &self is used. 08664b1 Address various clippy warnings/errors in bellman bb11ef2 cargo fmt cff2e2f cargo fix --edition-idioms for bellman dc2a280 Add edition = 2018 1a2bc19 cargo fmt ad37878 cargo fix --edition for bellman e73d1a2 cargo fmt bellman dfb86fc Move generic circuit gadgets into bellman 9b3d766 Migrate to rand 0.7 055280f Migrate ff, group, pairing, and bellman to rand 0.6 533d586 Migrate bellman to rand 0.5 bfa9aaf Merge pull request #61 from rex4539/fix-typos 3dd8490 Place bellman multicore operations behind a (default) feature flag 955e679 Merge pull request #46 from str4d/ff-traits d4ddaa9 Fix typos 12f93f2 Add ff and group crates to Cargo workspace 2e35a32 Update sapling-crypto crate to use ff crate 2019e63 Update workspace after pulling in external crates git-subtree-dir: bellman git-subtree-split: 2279da422ca9d7b83e84cb85018c713976b873e5 --- .gitignore | 1 + .gitlab-ci.yml | 66 - .travis.yml | 8 - bellman/COPYRIGHT => COPYRIGHT | 0 Cargo.lock | 521 -- Cargo.toml | 56 +- LICENSE-APACHE | 1 - LICENSE-MIT | 40 +- README.md | 20 +- bellman/.gitignore | 2 - bellman/Cargo.toml | 30 - bellman/LICENSE-APACHE | 201 - bellman/LICENSE-MIT | 23 - bellman/README.md | 19 - bellman/src/multicore.rs | 106 - librustzcash/Cargo.toml | 29 - librustzcash/README.md | 20 - librustzcash/include/librustzcash.h | 313 - librustzcash/src/equihash.rs | 467 -- librustzcash/src/hashreader.rs | 42 - librustzcash/src/rustzcash.rs | 1315 ---- librustzcash/src/tests/key_agreement.rs | 74 - librustzcash/src/tests/key_components.rs | 666 -- librustzcash/src/tests/mod.rs | 96 - librustzcash/src/tests/notes.rs | 673 -- librustzcash/src/tests/signatures.rs | 515 -- pairing/.gitignore | 3 - pairing/COPYRIGHT | 14 - pairing/Cargo.toml | 26 - pairing/LICENSE-APACHE | 201 - pairing/LICENSE-MIT | 23 - pairing/README.md | 27 - pairing/benches/bls12_381/ec.rs | 127 - pairing/benches/bls12_381/fq.rs | 268 - pairing/benches/bls12_381/fq12.rs | 94 - pairing/benches/bls12_381/fq2.rs | 110 - pairing/benches/bls12_381/fr.rs | 268 - pairing/benches/bls12_381/mod.rs | 107 - pairing/benches/pairing_benches.rs | 9 - pairing/src/bls12_381/README.md | 71 - pairing/src/bls12_381/ec.rs | 2030 ------ pairing/src/bls12_381/fq.rs | 2246 ------- pairing/src/bls12_381/fq12.rs | 189 - pairing/src/bls12_381/fq2.rs | 910 --- pairing/src/bls12_381/fq6.rs | 374 -- pairing/src/bls12_381/fr.rs | 986 --- pairing/src/bls12_381/mod.rs | 370 -- .../g1_compressed_valid_test_vectors.dat | Bin 48000 -> 0 bytes .../g1_uncompressed_invalid_test_vectors.dat | 0 .../g1_uncompressed_valid_test_vectors.dat | Bin 96000 -> 0 bytes .../g2_compressed_valid_test_vectors.dat | Bin 96000 -> 0 bytes .../g2_uncompressed_valid_test_vectors.dat | Bin 192000 -> 0 bytes pairing/src/bls12_381/tests/mod.rs | 614 -- pairing/src/lib.rs | 118 - pairing/src/tests/engine.rs | 127 - pairing/src/tests/field.rs | 266 - pairing/src/tests/mod.rs | 3 - pairing/src/tests/repr.rs | 98 - sapling-crypto/.gitignore | 3 - sapling-crypto/COPYRIGHT | 14 - sapling-crypto/Cargo.toml | 27 - sapling-crypto/LICENSE-APACHE | 201 - sapling-crypto/LICENSE-MIT | 23 - sapling-crypto/README.md | 23 - sapling-crypto/benches/pedersen_hash.rs | 23 - sapling-crypto/examples/bench.rs | 102 - sapling-crypto/src/circuit/blake2s.rs | 438 -- sapling-crypto/src/circuit/ecc.rs | 1213 ---- sapling-crypto/src/circuit/multipack.rs | 113 - sapling-crypto/src/circuit/pedersen_hash.rs | 194 - sapling-crypto/src/circuit/sapling/mod.rs | 817 --- .../src/circuit/sprout/commitment.rs | 42 - sapling-crypto/src/circuit/sprout/input.rs | 226 - sapling-crypto/src/circuit/sprout/mod.rs | 488 -- sapling-crypto/src/circuit/sprout/output.rs | 54 - sapling-crypto/src/circuit/sprout/prfs.rs | 79 - .../src/circuit/sprout/test_vectors.dat | Bin 10864 -> 0 bytes sapling-crypto/src/constants.rs | 40 - sapling-crypto/src/group_hash.rs | 46 - sapling-crypto/src/jubjub/edwards.rs | 523 -- sapling-crypto/src/jubjub/fs.rs | 1232 ---- sapling-crypto/src/jubjub/mod.rs | 435 -- sapling-crypto/src/jubjub/montgomery.rs | 358 -- sapling-crypto/src/jubjub/tests.rs | 416 -- sapling-crypto/src/lib.rs | 22 - sapling-crypto/src/pedersen_hash.rs | 103 - sapling-crypto/src/primitives/mod.rs | 258 - sapling-crypto/src/redjubjub.rs | 343 -- sapling-crypto/src/util.rs | 11 - {bellman/src => src}/domain.rs | 174 +- .../src/circuit/mod.rs => src/gadgets.rs | 24 +- src/gadgets/blake2s.rs | 696 +++ .../src/circuit => src/gadgets}/boolean.rs | 1308 ++-- .../src/circuit => src/gadgets}/lookup.rs | 222 +- .../src/circuit => src/gadgets}/multieq.rs | 88 +- src/gadgets/multipack.rs | 111 + .../src/circuit => src/gadgets}/num.rs | 349 +- .../src/circuit => src/gadgets}/sha256.rs | 263 +- .../src/circuit => src/gadgets}/test/mod.rs | 224 +- .../src/circuit => src/gadgets}/uint32.rs | 516 +- {bellman/src => src}/groth16/generator.rs | 237 +- {bellman/src => src}/groth16/mod.rs | 348 +- {bellman/src => src}/groth16/prover.rs | 195 +- .../src => src}/groth16/tests/dummy_engine.rs | 69 +- {bellman/src => src}/groth16/tests/mod.rs | 166 +- {bellman/src => src}/groth16/verifier.rs | 35 +- {bellman/src => src}/lib.rs | 348 +- src/multicore.rs | 164 + {bellman/src => src}/multiexp.rs | 120 +- {bellman/tests => tests}/mimc.rs | 113 +- zcash_primitives/Cargo.toml | 17 - zcash_primitives/LICENSE-APACHE | 202 - zcash_primitives/LICENSE-MIT | 21 - zcash_primitives/README.md | 20 - zcash_primitives/src/lib.rs | 17 - zcash_primitives/src/serialize.rs | 156 - .../src/transaction/components.rs | 432 -- zcash_primitives/src/transaction/mod.rs | 257 - zcash_primitives/src/transaction/sighash.rs | 234 - zcash_primitives/src/transaction/tests.rs | 5422 ----------------- zcash_proofs/Cargo.toml | 13 - zcash_proofs/LICENSE-APACHE | 202 - zcash_proofs/LICENSE-MIT | 21 - zcash_proofs/README.md | 21 - zcash_proofs/src/lib.rs | 7 - zcash_proofs/src/sapling/mod.rs | 39 - zcash_proofs/src/sapling/prover.rs | 365 -- zcash_proofs/src/sapling/verifier.rs | 207 - zcash_wallet/Cargo.toml | 8 - zcash_wallet/LICENSE-APACHE | 202 - zcash_wallet/LICENSE-MIT | 21 - zcash_wallet/README.md | 20 - zcash_wallet/src/lib.rs | 7 - zip32/.gitignore | 3 - zip32/COPYRIGHT | 14 - zip32/Cargo.toml | 24 - zip32/LICENSE-APACHE | 201 - zip32/LICENSE-MIT | 23 - zip32/README.md | 17 - zip32/src/lib.rs | 1233 ---- 140 files changed, 3568 insertions(+), 34478 deletions(-) delete mode 100644 .gitlab-ci.yml delete mode 100644 .travis.yml rename bellman/COPYRIGHT => COPYRIGHT (100%) delete mode 100644 Cargo.lock delete mode 100644 bellman/.gitignore delete mode 100644 bellman/Cargo.toml delete mode 100644 bellman/LICENSE-APACHE delete mode 100644 bellman/LICENSE-MIT delete mode 100644 bellman/README.md delete mode 100644 bellman/src/multicore.rs delete mode 100644 librustzcash/Cargo.toml delete mode 100644 librustzcash/README.md delete mode 100644 librustzcash/include/librustzcash.h delete mode 100644 librustzcash/src/equihash.rs delete mode 100644 librustzcash/src/hashreader.rs delete mode 100644 librustzcash/src/rustzcash.rs delete mode 100644 librustzcash/src/tests/key_agreement.rs delete mode 100644 librustzcash/src/tests/key_components.rs delete mode 100644 librustzcash/src/tests/mod.rs delete mode 100644 librustzcash/src/tests/notes.rs delete mode 100644 librustzcash/src/tests/signatures.rs delete mode 100644 pairing/.gitignore delete mode 100644 pairing/COPYRIGHT delete mode 100644 pairing/Cargo.toml delete mode 100644 pairing/LICENSE-APACHE delete mode 100644 pairing/LICENSE-MIT delete mode 100644 pairing/README.md delete mode 100644 pairing/benches/bls12_381/ec.rs delete mode 100644 pairing/benches/bls12_381/fq.rs delete mode 100644 pairing/benches/bls12_381/fq12.rs delete mode 100644 pairing/benches/bls12_381/fq2.rs delete mode 100644 pairing/benches/bls12_381/fr.rs delete mode 100644 pairing/benches/bls12_381/mod.rs delete mode 100644 pairing/benches/pairing_benches.rs delete mode 100644 pairing/src/bls12_381/README.md delete mode 100644 pairing/src/bls12_381/ec.rs delete mode 100644 pairing/src/bls12_381/fq.rs delete mode 100644 pairing/src/bls12_381/fq12.rs delete mode 100644 pairing/src/bls12_381/fq2.rs delete mode 100644 pairing/src/bls12_381/fq6.rs delete mode 100644 pairing/src/bls12_381/fr.rs delete mode 100644 pairing/src/bls12_381/mod.rs delete mode 100644 pairing/src/bls12_381/tests/g1_compressed_valid_test_vectors.dat delete mode 100644 pairing/src/bls12_381/tests/g1_uncompressed_invalid_test_vectors.dat delete mode 100644 pairing/src/bls12_381/tests/g1_uncompressed_valid_test_vectors.dat delete mode 100644 pairing/src/bls12_381/tests/g2_compressed_valid_test_vectors.dat delete mode 100644 pairing/src/bls12_381/tests/g2_uncompressed_valid_test_vectors.dat delete mode 100644 pairing/src/bls12_381/tests/mod.rs delete mode 100644 pairing/src/lib.rs delete mode 100644 pairing/src/tests/engine.rs delete mode 100644 pairing/src/tests/field.rs delete mode 100644 pairing/src/tests/mod.rs delete mode 100644 pairing/src/tests/repr.rs delete mode 100644 sapling-crypto/.gitignore delete mode 100644 sapling-crypto/COPYRIGHT delete mode 100644 sapling-crypto/Cargo.toml delete mode 100644 sapling-crypto/LICENSE-APACHE delete mode 100644 sapling-crypto/LICENSE-MIT delete mode 100644 sapling-crypto/README.md delete mode 100644 sapling-crypto/benches/pedersen_hash.rs delete mode 100644 sapling-crypto/examples/bench.rs delete mode 100644 sapling-crypto/src/circuit/blake2s.rs delete mode 100644 sapling-crypto/src/circuit/ecc.rs delete mode 100644 sapling-crypto/src/circuit/multipack.rs delete mode 100644 sapling-crypto/src/circuit/pedersen_hash.rs delete mode 100644 sapling-crypto/src/circuit/sapling/mod.rs delete mode 100644 sapling-crypto/src/circuit/sprout/commitment.rs delete mode 100644 sapling-crypto/src/circuit/sprout/input.rs delete mode 100644 sapling-crypto/src/circuit/sprout/mod.rs delete mode 100644 sapling-crypto/src/circuit/sprout/output.rs delete mode 100644 sapling-crypto/src/circuit/sprout/prfs.rs delete mode 100644 sapling-crypto/src/circuit/sprout/test_vectors.dat delete mode 100644 sapling-crypto/src/constants.rs delete mode 100644 sapling-crypto/src/group_hash.rs delete mode 100644 sapling-crypto/src/jubjub/edwards.rs delete mode 100644 sapling-crypto/src/jubjub/fs.rs delete mode 100644 sapling-crypto/src/jubjub/mod.rs delete mode 100644 sapling-crypto/src/jubjub/montgomery.rs delete mode 100644 sapling-crypto/src/jubjub/tests.rs delete mode 100644 sapling-crypto/src/lib.rs delete mode 100644 sapling-crypto/src/pedersen_hash.rs delete mode 100644 sapling-crypto/src/primitives/mod.rs delete mode 100644 sapling-crypto/src/redjubjub.rs delete mode 100644 sapling-crypto/src/util.rs rename {bellman/src => src}/domain.rs (76%) rename sapling-crypto/src/circuit/mod.rs => src/gadgets.rs (75%) create mode 100644 src/gadgets/blake2s.rs rename {sapling-crypto/src/circuit => src/gadgets}/boolean.rs (56%) rename {sapling-crypto/src/circuit => src/gadgets}/lookup.rs (54%) rename {sapling-crypto/src/circuit => src/gadgets}/multieq.rs (52%) create mode 100644 src/gadgets/multipack.rs rename {sapling-crypto/src/circuit => src/gadgets}/num.rs (66%) rename {sapling-crypto/src/circuit => src/gadgets}/sha256.rs (61%) rename {sapling-crypto/src/circuit => src/gadgets}/test/mod.rs (71%) rename {sapling-crypto/src/circuit => src/gadgets}/uint32.rs (57%) rename {bellman/src => src}/groth16/generator.rs (71%) rename {bellman/src => src}/groth16/mod.rs (64%) rename {bellman/src => src}/groth16/prover.rs (65%) rename {bellman/src => src}/groth16/tests/dummy_engine.rs (89%) rename {bellman/src => src}/groth16/tests/mod.rs (78%) rename {bellman/src => src}/groth16/verifier.rs (73%) rename {bellman/src => src}/lib.rs (51%) create mode 100644 src/multicore.rs rename {bellman/src => src}/multiexp.rs (75%) rename {bellman/tests => tests}/mimc.rs (70%) delete mode 100644 zcash_primitives/Cargo.toml delete mode 100644 zcash_primitives/LICENSE-APACHE delete mode 100644 zcash_primitives/LICENSE-MIT delete mode 100644 zcash_primitives/README.md delete mode 100644 zcash_primitives/src/lib.rs delete mode 100644 zcash_primitives/src/serialize.rs delete mode 100644 zcash_primitives/src/transaction/components.rs delete mode 100644 zcash_primitives/src/transaction/mod.rs delete mode 100644 zcash_primitives/src/transaction/sighash.rs delete mode 100644 zcash_primitives/src/transaction/tests.rs delete mode 100644 zcash_proofs/Cargo.toml delete mode 100644 zcash_proofs/LICENSE-APACHE delete mode 100644 zcash_proofs/LICENSE-MIT delete mode 100644 zcash_proofs/README.md delete mode 100644 zcash_proofs/src/lib.rs delete mode 100644 zcash_proofs/src/sapling/mod.rs delete mode 100644 zcash_proofs/src/sapling/prover.rs delete mode 100644 zcash_proofs/src/sapling/verifier.rs delete mode 100644 zcash_wallet/Cargo.toml delete mode 100644 zcash_wallet/LICENSE-APACHE delete mode 100644 zcash_wallet/LICENSE-MIT delete mode 100644 zcash_wallet/README.md delete mode 100644 zcash_wallet/src/lib.rs delete mode 100644 zip32/.gitignore delete mode 100644 zip32/COPYRIGHT delete mode 100644 zip32/Cargo.toml delete mode 100644 zip32/LICENSE-APACHE delete mode 100644 zip32/LICENSE-MIT delete mode 100644 zip32/README.md delete mode 100644 zip32/src/lib.rs diff --git a/.gitignore b/.gitignore index eb5a316..a9d37c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ target +Cargo.lock diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 001f415..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,66 +0,0 @@ - -# /************************************************************************ - # File: .gitlab-ci.yml - # Author: mdr0id - # Date: 9/10/2018 - # Description: Used to setup runners/jobs for librustzcash - # Usage: Commit source and the pipeline will trigger the according jobs. - # For now the build and test are done in the same jobs. - # - # Known bugs/missing features: - # - # ************************************************************************/ - -stages: - - build - - test - - deploy - -rust-latest: - stage: build - image: rust:latest - script: - - cargo --verbose --version - - time cargo build --verbose - -rust-nightly: - stage: build - image: rustlang/rust:nightly - script: - - cargo --verbose --version - - cargo build --verbose - allow_failure: true - -librustzcash-test-latest: - stage: test - image: rust:latest - script: - - cargo --verbose --version - - time cargo test --release --verbose - -librustzcash-test-rust-nightly: - stage: test - image: rustlang/rust:nightly - script: - - cargo --verbose --version - - cargo test --release --verbose - allow_failure: true - -#used to manually deploy a given release -librustzcash-rust-rc: - stage: deploy - image: rust:latest - script: - - cargo --verbose --version - - time cargo build --release --verbose - when: manual - -#used to manually deploy a given release -librustzcash-rust-nightly-rc: - stage: deploy - image: rustlang/rust:nightly - script: - - cargo --verbose --version - - cargo build --release --verbose - allow_failure: true - when: manual diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index eea30a2..0000000 --- a/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: rust -rust: - - 1.31.0 - -cache: cargo - -script: - - cargo test --verbose --release --all diff --git a/bellman/COPYRIGHT b/COPYRIGHT similarity index 100% rename from bellman/COPYRIGHT rename to COPYRIGHT diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index c477d52..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,521 +0,0 @@ -[[package]] -name = "aes" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aes-soft" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aesni" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "arrayvec" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bellman" -version = "0.1.0" -dependencies = [ - "bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "group 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bit-vec" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "blake2-rfc" -version = "0.2.18" -source = "git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9#7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" -dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "block-cipher-trait" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "byte-tools" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byteorder" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "constant_time_eq" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "crossbeam" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "digest" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ff" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ff_derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fpe" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures-cpupool" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "gcc" -version = "0.3.54" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "generic-array" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "group" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ff 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hex-literal" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hex-literal-impl" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lazy_static" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.40" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "librustzcash" -version = "0.1.0" -dependencies = [ - "bellman 0.1.0", - "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sapling-crypto 0.0.1", - "zcash_proofs 0.0.0", - "zip32 0.0.0", -] - -[[package]] -name = "nodrop" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "num-bigint" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-integer" -version = "0.1.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "num_cpus" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "opaque-debug" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "pairing" -version = "0.14.2" -dependencies = [ - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "group 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-hack" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro-hack-impl" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "proc-macro2" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quote" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "redox_syscall" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rust-crypto" -version = "0.2.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "sapling-crypto" -version = "0.0.1" -dependencies = [ - "bellman 0.1.0", - "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "stream-cipher" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syn" -version = "0.14.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "time" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "typenum" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "zcash_primitives" -version = "0.0.0" -dependencies = [ - "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sapling-crypto 0.0.1", -] - -[[package]] -name = "zcash_proofs" -version = "0.0.0" -dependencies = [ - "bellman 0.1.0", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sapling-crypto 0.0.1", -] - -[[package]] -name = "zcash_wallet" -version = "0.0.0" - -[[package]] -name = "zip32" -version = "0.0.0" -dependencies = [ - "aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2", - "sapling-crypto 0.0.1", -] - -[metadata] -"checksum aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6fb1737cdc8da3db76e90ca817a194249a38fcb500c2e6ecec39b29448aa873" -"checksum aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67cc03b0a090a05cb01e96998a01905d7ceedce1bc23b756c0bb7faa0682ccb1" -"checksum aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6810b7fb9f2bb4f76f05ac1c170b8dde285b6308955dc3afd89710268c958d9e" -"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" -"checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" -"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" -"checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)" = "" -"checksum block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "370424437b9459f3dfd68428ed9376ddfe03d8b70ede29cc533b3557df186ab4" -"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" -"checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87" -"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" -"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" -"checksum digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603" -"checksum ff 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eec81e2e423086589b224dbcfbab70e3732913de25479d05165b20d4aaed05f4" -"checksum ff_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70335090ee115d5716416ca38980cce7752f40923f41d22cf5a69a6269f9e2a2" -"checksum fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce3371c82bfbd984f624cab093f55e7336f5a6e589f8518e1258f54f011b89ad" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" -"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" -"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" -"checksum group 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5fa874cb11ddaf7cf45b511138f24169985d61d8760779426016230d11101d1a" -"checksum hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4da5f0e01bd8a71a224a4eedecaacfcabda388dbb7a80faf04d3514287572d95" -"checksum hex-literal-impl 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d340b6514f232f6db1bd16db65302a5278a04fef9ce867cb932e7e5fa21130a" -"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" -"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" -"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" -"checksum num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3eceac7784c5dc97c2d6edf30259b4e153e6e2b42b3c85e9a6e9f45d06caef6e" -"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" -"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" -"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d620c9c26834b34f039489ac0dfdb12c7ac15ccaf818350a64c9b5334a452ad7" -"checksum proc-macro-hack 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ba8d4f9257b85eb6cdf13f055cea3190520aab1409ca2ab43493ea4820c25f0" -"checksum proc-macro-hack-impl 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d5cb6f960ad471404618e9817c0e5d10b1ae74cfdf01fab89ea0641fe7fb2892" -"checksum proc-macro2 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b331c6ad3411474cd55540398dc7ad89fc41488e64ec71fdecc9c9b86de96fb0" -"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" -"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" -"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" -"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" -"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" -"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "30dc6118470d69ce0fdcf7e6f95e95853f7f4f72f80d835d4519577c323814ab" -"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" -"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" -"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 3d1363d..3acc8c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,42 @@ -[workspace] -members = [ - "bellman", - "librustzcash", - "pairing", - "sapling-crypto", - "zcash_primitives", - "zcash_proofs", - "zcash_wallet", - "zip32", -] +[package] +authors = ["Sean Bowe "] +description = "zk-SNARK library" +readme = "README.md" +homepage = "https://github.com/ebfull/bellman" +license = "MIT/Apache-2.0" +name = "bellman" +repository = "https://github.com/ebfull/bellman" +version = "0.2.0" +edition = "2018" -[profile.release] -lto = true -panic = 'abort' -codegen-units = 1 +[dependencies] +bit-vec = "0.4.4" +blake2s_simd = "0.5" +ff = { version = "0.5.0", path = "../ff" } +futures = "0.1" +futures-cpupool = { version = "0.1", optional = true } +group = { version = "0.2.0", path = "../group" } +num_cpus = { version = "1", optional = true } +crossbeam = { version = "0.7", optional = true } +pairing = { version = "0.15.0", path = "../pairing", optional = true } +rand_core = "0.5" +byteorder = "1" + +[dev-dependencies] +hex-literal = "0.2" +rand = "0.7" +rand_xorshift = "0.2" +sha2 = "0.8" + +[features] +groth16 = ["pairing"] +multicore = ["futures-cpupool", "crossbeam", "num_cpus"] +default = ["groth16", "multicore"] + +[[test]] +name = "mimc" +path = "tests/mimc.rs" +required-features = ["groth16"] + +[badges] +maintenance = { status = "actively-developed" } diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 1e5006d..16fe87b 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -199,4 +199,3 @@ 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. - diff --git a/LICENSE-MIT b/LICENSE-MIT index 5b7be8e..31aa793 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,21 +1,23 @@ -The MIT License (MIT) +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: -Copyright (c) 2017 Zcash Company +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 3df799f..d64dd9c 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,23 @@ -# Zcash Rust crates +# bellman [![Crates.io](https://img.shields.io/crates/v/bellman.svg)](https://crates.io/crates/bellman) # -This repository contains a (work-in-progress) set of Rust crates for -working with Zcash. +`bellman` is a crate for building zk-SNARK circuits. It provides circuit traits +and primitive structures, as well as basic gadget implementations such as +booleans and number abstractions. -## Security Warnings +## Roadmap -These libraries are currently under development and have not been fully-reviewed. +`bellman` is being refactored into a generic proving library. Currently it is +pairing-specific, and different types of proving systems need to be implemented +as sub-modules. After the refactor, `bellman` will be generic using the `ff` and +`group` crates, while specific proving systems will be separate crates that pull +in the dependencies they require. ## License -All code in this workspace is licensed under either of +Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. diff --git a/bellman/.gitignore b/bellman/.gitignore deleted file mode 100644 index a9d37c5..0000000 --- a/bellman/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target -Cargo.lock diff --git a/bellman/Cargo.toml b/bellman/Cargo.toml deleted file mode 100644 index 6812a7f..0000000 --- a/bellman/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -authors = ["Sean Bowe "] -description = "zk-SNARK library" -documentation = "https://github.com/ebfull/bellman" -homepage = "https://github.com/ebfull/bellman" -license = "MIT/Apache-2.0" -name = "bellman" -repository = "https://github.com/ebfull/bellman" -version = "0.1.0" - -[dependencies] -rand = "0.4" -bit-vec = "0.4.4" -ff = "0.4" -futures = "0.1" -futures-cpupool = "0.1" -group = "0.1" -num_cpus = "1" -crossbeam = "0.3" -pairing = { path = "../pairing", optional = true } -byteorder = "1" - -[features] -groth16 = ["pairing"] -default = ["groth16"] - -[[test]] -name = "mimc" -path = "tests/mimc.rs" -required-features = ["groth16"] diff --git a/bellman/LICENSE-APACHE b/bellman/LICENSE-APACHE deleted file mode 100644 index 16fe87b..0000000 --- a/bellman/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. diff --git a/bellman/LICENSE-MIT b/bellman/LICENSE-MIT deleted file mode 100644 index 31aa793..0000000 --- a/bellman/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/bellman/README.md b/bellman/README.md deleted file mode 100644 index 659a81c..0000000 --- a/bellman/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# bellman [![Crates.io](https://img.shields.io/crates/v/bellman.svg)](https://crates.io/crates/bellman) # - -This is a research project being built for [Zcash](https://z.cash/). - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/bellman/src/multicore.rs b/bellman/src/multicore.rs deleted file mode 100644 index c0062fc..0000000 --- a/bellman/src/multicore.rs +++ /dev/null @@ -1,106 +0,0 @@ -//! This is an interface for dealing with the kinds of -//! parallel computations involved in bellman. It's -//! currently just a thin wrapper around CpuPool and -//! crossbeam but may be extended in the future to -//! allow for various parallelism strategies. - -use num_cpus; -use futures::{Future, IntoFuture, Poll}; -use futures_cpupool::{CpuPool, CpuFuture}; -use crossbeam::{self, Scope}; - -#[derive(Clone)] -pub struct Worker { - cpus: usize, - pool: CpuPool -} - -impl Worker { - // We don't expose this outside the library so that - // all `Worker` instances have the same number of - // CPUs configured. - pub(crate) fn new_with_cpus(cpus: usize) -> Worker { - Worker { - cpus: cpus, - pool: CpuPool::new(cpus) - } - } - - pub fn new() -> Worker { - Self::new_with_cpus(num_cpus::get()) - } - - pub fn log_num_cpus(&self) -> u32 { - log2_floor(self.cpus) - } - - pub fn compute( - &self, f: F - ) -> WorkerFuture - where F: FnOnce() -> R + Send + 'static, - R: IntoFuture + 'static, - R::Future: Send + 'static, - R::Item: Send + 'static, - R::Error: Send + 'static - { - WorkerFuture { - future: self.pool.spawn_fn(f) - } - } - - pub fn scope<'a, F, R>( - &self, - elements: usize, - f: F - ) -> R - where F: FnOnce(&Scope<'a>, usize) -> R - { - let chunk_size = if elements < self.cpus { - 1 - } else { - elements / self.cpus - }; - - crossbeam::scope(|scope| { - f(scope, chunk_size) - }) - } -} - -pub struct WorkerFuture { - future: CpuFuture -} - -impl Future for WorkerFuture { - type Item = T; - type Error = E; - - fn poll(&mut self) -> Poll - { - self.future.poll() - } -} - -fn log2_floor(num: usize) -> u32 { - assert!(num > 0); - - let mut pow = 0; - - while (1 << (pow+1)) <= num { - pow += 1; - } - - pow -} - -#[test] -fn test_log2_floor() { - assert_eq!(log2_floor(1), 0); - assert_eq!(log2_floor(2), 1); - assert_eq!(log2_floor(3), 1); - assert_eq!(log2_floor(4), 2); - assert_eq!(log2_floor(5), 2); - assert_eq!(log2_floor(6), 2); - assert_eq!(log2_floor(7), 2); - assert_eq!(log2_floor(8), 3); -} diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml deleted file mode 100644 index bb42b6c..0000000 --- a/librustzcash/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "librustzcash" -version = "0.1.0" -authors = [ - "Sean Bowe ", - "Jack Grigg ", - "Jay Graber ", - "Simon Liu " - ] - -[lib] -name = "rustzcash" -path = "src/rustzcash.rs" -crate-type = ["staticlib"] - -[dependencies] -bellman = { path = "../bellman" } -libc = "0.2" -pairing = { path = "../pairing" } -lazy_static = "1" -byteorder = "1" -rand = "0.4" -sapling-crypto = { path = "../sapling-crypto" } -zcash_proofs = { path = "../zcash_proofs" } -zip32 = { path = "../zip32" } - -[dependencies.blake2-rfc] -git = "https://github.com/gtank/blake2-rfc" -rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" diff --git a/librustzcash/README.md b/librustzcash/README.md deleted file mode 100644 index c21ca8e..0000000 --- a/librustzcash/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# librustzcash - -This repository contains librustzcash, a static library for Zcash code assets written in Rust. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. - diff --git a/librustzcash/include/librustzcash.h b/librustzcash/include/librustzcash.h deleted file mode 100644 index 4efb544..0000000 --- a/librustzcash/include/librustzcash.h +++ /dev/null @@ -1,313 +0,0 @@ -#ifndef LIBRUSTZCASH_INCLUDE_H_ -#define LIBRUSTZCASH_INCLUDE_H_ - -#include - -extern "C" { -#ifdef WIN32 - typedef uint16_t codeunit; -#else - typedef uint8_t codeunit; -#endif - - void librustzcash_to_scalar(const unsigned char *input, unsigned char *result); - - void librustzcash_ask_to_ak(const unsigned char *ask, unsigned char *result); - - void librustzcash_nsk_to_nk(const unsigned char *nsk, unsigned char *result); - - void librustzcash_crh_ivk(const unsigned char *ak, const unsigned char *nk, unsigned char *result); - - bool librustzcash_check_diversifier(const unsigned char *diversifier); - - bool librustzcash_ivk_to_pkd(const unsigned char *ivk, const unsigned char *diversifier, unsigned char *result); - - /// Loads the zk-SNARK parameters into memory and saves - /// paths as necessary. Only called once. - void librustzcash_init_zksnark_params( - const codeunit* spend_path, - size_t spend_path_len, - const char* spend_hash, - const codeunit* output_path, - size_t output_path_len, - const char* output_hash, - const codeunit* sprout_path, - size_t sprout_path_len, - const char* sprout_hash - ); - - /// Validates the provided Equihash solution against - /// the given parameters, input and nonce. - bool librustzcash_eh_isvalid( - uint32_t n, - uint32_t k, - const unsigned char* input, - size_t input_len, - const unsigned char* nonce, - size_t nonce_len, - const unsigned char* soln, - size_t soln_len - ); - - /// Writes the "uncommitted" note value for empty leaves - /// of the merkle tree. `result` must be a valid pointer - /// to 32 bytes which will be written. - void librustzcash_tree_uncommitted( - unsigned char *result - ); - - /// Computes a merkle tree hash for a given depth. - /// The `depth` parameter should not be larger than - /// 62. - /// - /// `a` and `b` each must be of length 32, and must each - /// be scalars of BLS12-381. - /// - /// The result of the merkle tree hash is placed in - /// `result`, which must also be of length 32. - void librustzcash_merkle_hash( - size_t depth, - const unsigned char *a, - const unsigned char *b, - unsigned char *result - ); - - /// Computes the signature for each Spend description, given the key - /// `ask`, the re-randomization `ar`, the 32-byte sighash `sighash`, - /// and an output `result` buffer of 64-bytes for the signature. - /// - /// This function will fail if the provided `ask` or `ar` are invalid. - bool librustzcash_sapling_spend_sig( - const unsigned char *ask, - const unsigned char *ar, - const unsigned char *sighash, - unsigned char *result - ); - - /// Creates a Sapling proving context. Please free this when you're done. - void * librustzcash_sapling_proving_ctx_init(); - - /// This function (using the proving context) constructs a Spend proof - /// given the necessary witness information. It outputs `cv` (the value - /// commitment) and `rk` (so that you don't have to compute it) along - /// with the proof. - bool librustzcash_sapling_spend_proof( - void *ctx, - const unsigned char *ak, - const unsigned char *nsk, - const unsigned char *diversifier, - const unsigned char *rcm, - const unsigned char *ar, - const uint64_t value, - const unsigned char *anchor, - const unsigned char *witness, - unsigned char *cv, - unsigned char *rk, - unsigned char *zkproof - ); - - /// This function (using the proving context) constructs an Output - /// proof given the necessary witness information. It outputs `cv` - /// and the `zkproof`. - bool librustzcash_sapling_output_proof( - void *ctx, - const unsigned char *esk, - const unsigned char *diversifier, - const unsigned char *pk_d, - const unsigned char *rcm, - const uint64_t value, - unsigned char *cv, - unsigned char *zkproof - ); - - /// This function (using the proving context) constructs a binding - /// signature. You must provide the intended valueBalance so that - /// we can internally check consistency. - bool librustzcash_sapling_binding_sig( - const void *ctx, - int64_t valueBalance, - const unsigned char *sighash, - unsigned char *result - ); - - /// Frees a Sapling proving context returned from - /// `librustzcash_sapling_proving_ctx_init`. - void librustzcash_sapling_proving_ctx_free(void *); - - /// Creates a Sapling verification context. Please free this - /// when you're done. - void * librustzcash_sapling_verification_ctx_init(); - - /// Check the validity of a Sapling Spend description, - /// accumulating the value commitment into the context. - bool librustzcash_sapling_check_spend( - void *ctx, - const unsigned char *cv, - const unsigned char *anchor, - const unsigned char *nullifier, - const unsigned char *rk, - const unsigned char *zkproof, - const unsigned char *spendAuthSig, - const unsigned char *sighashValue - ); - - /// Check the validity of a Sapling Output description, - /// accumulating the value commitment into the context. - bool librustzcash_sapling_check_output( - void *ctx, - const unsigned char *cv, - const unsigned char *cm, - const unsigned char *ephemeralKey, - const unsigned char *zkproof - ); - - /// Finally checks the validity of the entire Sapling - /// transaction given valueBalance and the binding signature. - bool librustzcash_sapling_final_check( - void *ctx, - int64_t valueBalance, - const unsigned char *bindingSig, - const unsigned char *sighashValue - ); - - /// Frees a Sapling verification context returned from - /// `librustzcash_sapling_verification_ctx_init`. - void librustzcash_sapling_verification_ctx_free(void *); - - /// Compute a Sapling nullifier. - /// - /// The `diversifier` parameter must be 11 bytes in length. - /// The `pk_d`, `r`, `ak` and `nk` parameters must be of length 32. - /// The result is also of length 32 and placed in `result`. - /// Returns false if the diversifier or pk_d is not valid - bool librustzcash_sapling_compute_nf( - const unsigned char *diversifier, - const unsigned char *pk_d, - const uint64_t value, - const unsigned char *r, - const unsigned char *ak, - const unsigned char *nk, - const uint64_t position, - unsigned char *result - ); - - /// Compute a Sapling commitment. - /// - /// The `diversifier` parameter must be 11 bytes in length. - /// The `pk_d` and `r` parameters must be of length 32. - /// The result is also of length 32 and placed in `result`. - /// Returns false if the diversifier or pk_d is not valid - bool librustzcash_sapling_compute_cm( - const unsigned char *diversifier, - const unsigned char *pk_d, - const uint64_t value, - const unsigned char *r, - unsigned char *result - ); - - /// Compute [sk] [8] P for some 32-byte - /// point P, and 32-byte Fs. If P or sk - /// are invalid, returns false. Otherwise, - /// the result is written to the 32-byte - /// `result` buffer. - bool librustzcash_sapling_ka_agree( - const unsigned char *p, - const unsigned char *sk, - unsigned char *result - ); - - /// Compute g_d = GH(diversifier) and returns - /// false if the diversifier is invalid. - /// Computes [esk] g_d and writes the result - /// to the 32-byte `result` buffer. Returns - /// false if `esk` is not a valid scalar. - bool librustzcash_sapling_ka_derivepublic( - const unsigned char *diversifier, - const unsigned char *esk, - unsigned char *result - ); - - /// Generate uniformly random scalar in Jubjub. - /// The result is of length 32. - void librustzcash_sapling_generate_r( - unsigned char *result - ); - - /// Sprout JoinSplit proof generation. - void librustzcash_sprout_prove( - unsigned char *proof_out, - - const unsigned char *phi, - const unsigned char *rt, - const unsigned char *h_sig, - - const unsigned char *in_sk1, - uint64_t in_value1, - const unsigned char *in_rho1, - const unsigned char *in_r1, - const unsigned char *in_auth1, - - const unsigned char *in_sk2, - uint64_t in_value2, - const unsigned char *in_rho2, - const unsigned char *in_r2, - const unsigned char *in_auth2, - - const unsigned char *out_pk1, - uint64_t out_value1, - const unsigned char *out_r1, - - const unsigned char *out_pk2, - uint64_t out_value2, - const unsigned char *out_r2, - - uint64_t vpub_old, - uint64_t vpub_new - ); - - /// Sprout JoinSplit proof verification. - bool librustzcash_sprout_verify( - const unsigned char *proof, - const unsigned char *rt, - const unsigned char *h_sig, - const unsigned char *mac1, - const unsigned char *mac2, - const unsigned char *nf1, - const unsigned char *nf2, - const unsigned char *cm1, - const unsigned char *cm2, - uint64_t vpub_old, - uint64_t vpub_new - ); - - /// Derive the master ExtendedSpendingKey from a seed. - void librustzcash_zip32_xsk_master( - const unsigned char *seed, - size_t seedlen, - unsigned char *xsk_master - ); - - /// Derive a child ExtendedSpendingKey from a parent. - void librustzcash_zip32_xsk_derive( - const unsigned char *xsk_parent, - uint32_t i, - unsigned char *xsk_i - ); - - /// Derive a child ExtendedFullViewingKey from a parent. - bool librustzcash_zip32_xfvk_derive( - const unsigned char *xfvk_parent, - uint32_t i, - unsigned char *xfvk_i - ); - - /// Derive a PaymentAddress from an ExtendedFullViewingKey. - bool librustzcash_zip32_xfvk_address( - const unsigned char *xfvk, - const unsigned char *j, - unsigned char *j_ret, - unsigned char *addr_ret - ); -} - -#endif // LIBRUSTZCASH_INCLUDE_H_ diff --git a/librustzcash/src/equihash.rs b/librustzcash/src/equihash.rs deleted file mode 100644 index da2693b..0000000 --- a/librustzcash/src/equihash.rs +++ /dev/null @@ -1,467 +0,0 @@ -use blake2_rfc::blake2b::{Blake2b, Blake2bResult}; -use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; -use std::io::Cursor; -use std::mem::size_of; - -struct Params { - n: u32, - k: u32, -} - -#[derive(Clone)] -struct Node { - hash: Vec, - indices: Vec, -} - -impl Params { - fn indices_per_hash_output(&self) -> u32 { - 512 / self.n - } - fn hash_output(&self) -> u8 { - (self.indices_per_hash_output() * self.n / 8) as u8 - } - fn collision_bit_length(&self) -> usize { - (self.n / (self.k + 1)) as usize - } - fn collision_byte_length(&self) -> usize { - (self.collision_bit_length() + 7) / 8 - } - fn hash_length(&self) -> usize { - ((self.k as usize) + 1) * self.collision_byte_length() - } -} - -impl Node { - fn new(p: &Params, state: &Blake2b, i: u32) -> Self { - let hash = generate_hash(state, i / p.indices_per_hash_output()); - let start = ((i % p.indices_per_hash_output()) * p.n / 8) as usize; - let end = start + (p.n as usize) / 8; - Node { - hash: expand_array(&hash.as_bytes()[start..end], p.collision_bit_length(), 0), - indices: vec![i], - } - } - - fn from_children(a: Node, b: Node, trim: usize) -> Self { - let hash: Vec<_> = a - .hash - .iter() - .zip(b.hash.iter()) - .skip(trim) - .map(|(a, b)| a ^ b) - .collect(); - let indices = if a.indices_before(&b) { - let mut indices = a.indices; - indices.extend(b.indices.iter()); - indices - } else { - let mut indices = b.indices; - indices.extend(a.indices.iter()); - indices - }; - Node { - hash: hash, - indices: indices, - } - } - - fn from_children_ref(a: &Node, b: &Node, trim: usize) -> Self { - let hash: Vec<_> = a - .hash - .iter() - .zip(b.hash.iter()) - .skip(trim) - .map(|(a, b)| a ^ b) - .collect(); - let mut indices = Vec::with_capacity(a.indices.len() + b.indices.len()); - if a.indices_before(b) { - indices.extend(a.indices.iter()); - indices.extend(b.indices.iter()); - } else { - indices.extend(b.indices.iter()); - indices.extend(a.indices.iter()); - } - Node { - hash: hash, - indices: indices, - } - } - - fn indices_before(&self, other: &Node) -> bool { - // Indices are serialized in big-endian so that integer - // comparison is equivalent to array comparison - self.indices[0] < other.indices[0] - } - - fn is_zero(&self, len: usize) -> bool { - self.hash.iter().take(len).all(|v| *v == 0) - } -} - -fn initialise_state(n: u32, k: u32, digest_len: u8) -> Blake2b { - let mut personalization: Vec = Vec::from("ZcashPoW"); - personalization.write_u32::(n).unwrap(); - personalization.write_u32::(k).unwrap(); - - Blake2b::with_params(digest_len as usize, &[], &[], &personalization) -} - -fn generate_hash(base_state: &Blake2b, i: u32) -> Blake2bResult { - let mut lei = [0u8; 4]; - (&mut lei[..]).write_u32::(i).unwrap(); - - let mut state = base_state.clone(); - state.update(&lei); - state.finalize() -} - -fn expand_array(vin: &[u8], bit_len: usize, byte_pad: usize) -> Vec { - assert!(bit_len >= 8); - assert!(8 * size_of::() >= 7 + bit_len); - - let out_width = (bit_len + 7) / 8 + byte_pad; - let out_len = 8 * out_width * vin.len() / bit_len; - - // Shortcut for parameters where expansion is a no-op - if out_len == vin.len() { - return vin.to_vec(); - } - - let mut vout: Vec = vec![0; out_len]; - let bit_len_mask: u32 = (1 << bit_len) - 1; - - // The acc_bits least-significant bits of acc_value represent a bit sequence - // in big-endian order. - let mut acc_bits = 0; - let mut acc_value: u32 = 0; - - let mut j = 0; - for b in vin { - acc_value = (acc_value << 8) | *b as u32; - acc_bits += 8; - - // When we have bit_len or more bits in the accumulator, write the next - // output element. - if acc_bits >= bit_len { - acc_bits -= bit_len; - for x in byte_pad..out_width { - vout[j + x] = (( - // Big-endian - acc_value >> (acc_bits + (8 * (out_width - x - 1))) - ) & ( - // Apply bit_len_mask across byte boundaries - (bit_len_mask >> (8 * (out_width - x - 1))) & 0xFF - )) as u8; - } - j += out_width; - } - } - - vout -} - -fn indices_from_minimal(minimal: &[u8], c_bit_len: usize) -> Vec { - assert!(((c_bit_len + 1) + 7) / 8 <= size_of::()); - let len_indices = 8 * size_of::() * minimal.len() / (c_bit_len + 1); - let byte_pad = size_of::() - ((c_bit_len + 1) + 7) / 8; - - let mut csr = Cursor::new(expand_array(minimal, c_bit_len + 1, byte_pad)); - let mut ret = Vec::with_capacity(len_indices); - - // Big-endian so that lexicographic array comparison is equivalent to integer - // comparison - while let Ok(i) = csr.read_u32::() { - ret.push(i); - } - - ret -} - -fn has_collision(a: &Node, b: &Node, len: usize) -> bool { - a.hash - .iter() - .zip(b.hash.iter()) - .take(len) - .all(|(a, b)| a == b) -} - -fn distinct_indices(a: &Node, b: &Node) -> bool { - for i in &(a.indices) { - for j in &(b.indices) { - if i == j { - return false; - } - } - } - return true; -} - -fn validate_subtrees(p: &Params, a: &Node, b: &Node) -> bool { - if !has_collision(a, b, p.collision_byte_length()) { - // error!("Invalid solution: invalid collision length between StepRows"); - false - } else if b.indices_before(a) { - // error!("Invalid solution: Index tree incorrectly ordered"); - false - } else if !distinct_indices(a, b) { - // error!("Invalid solution: duplicate indices"); - false - } else { - true - } -} - -pub fn is_valid_solution_iterative( - n: u32, - k: u32, - input: &[u8], - nonce: &[u8], - indices: &[u32], -) -> bool { - let p = Params { n: n, k: k }; - - let mut state = initialise_state(p.n, p.k, p.hash_output()); - state.update(input); - state.update(nonce); - - let mut rows = Vec::new(); - for i in indices { - rows.push(Node::new(&p, &state, *i)); - } - - let mut hash_len = p.hash_length(); - while rows.len() > 1 { - let mut cur_rows = Vec::new(); - for pair in rows.chunks(2) { - let a = &pair[0]; - let b = &pair[1]; - if !validate_subtrees(&p, a, b) { - return false; - } - cur_rows.push(Node::from_children_ref(a, b, p.collision_byte_length())); - } - rows = cur_rows; - hash_len -= p.collision_byte_length(); - } - - assert!(rows.len() == 1); - return rows[0].is_zero(hash_len); -} - -fn tree_validator(p: &Params, state: &Blake2b, indices: &[u32]) -> Option { - if indices.len() > 1 { - let end = indices.len(); - let mid = end / 2; - match tree_validator(p, state, &indices[0..mid]) { - Some(a) => match tree_validator(p, state, &indices[mid..end]) { - Some(b) => { - if validate_subtrees(p, &a, &b) { - Some(Node::from_children(a, b, p.collision_byte_length())) - } else { - None - } - } - None => None, - }, - None => None, - } - } else { - Some(Node::new(&p, &state, indices[0])) - } -} - -pub fn is_valid_solution_recursive( - n: u32, - k: u32, - input: &[u8], - nonce: &[u8], - indices: &[u32], -) -> bool { - let p = Params { n: n, k: k }; - - let mut state = initialise_state(p.n, p.k, p.hash_output()); - state.update(input); - state.update(nonce); - - match tree_validator(&p, &state, indices) { - Some(root) => { - // Hashes were trimmed, so only need to check remaining length - root.is_zero(p.collision_byte_length()) - } - None => false, - } -} - -pub fn is_valid_solution(n: u32, k: u32, input: &[u8], nonce: &[u8], soln: &[u8]) -> bool { - let p = Params { n: n, k: k }; - let indices = indices_from_minimal(soln, p.collision_bit_length()); - - // Recursive validation is faster - is_valid_solution_recursive(n, k, input, nonce, &indices) -} - -#[cfg(test)] -mod tests { - use super::is_valid_solution_iterative; - use super::is_valid_solution_recursive; - - fn is_valid_solution(n: u32, k: u32, input: &[u8], nonce: &[u8], indices: &[u32]) -> bool { - let a = is_valid_solution_iterative(n, k, input, nonce, indices); - let b = is_valid_solution_recursive(n, k, input, nonce, indices); - assert!(a == b); - a - } - - #[test] - fn equihash_test_cases() { - let input = b"block header"; - let mut nonce = [0 as u8; 32]; - let mut indices = vec![ - 976, 126621, 100174, 123328, 38477, 105390, 38834, 90500, 6411, 116489, 51107, 129167, - 25557, 92292, 38525, 56514, 1110, 98024, 15426, 74455, 3185, 84007, 24328, 36473, - 17427, 129451, 27556, 119967, 31704, 62448, 110460, 117894, - ]; - assert!(is_valid_solution(96, 5, input, &nonce, &indices)); - - indices = vec![ - 1008, 18280, 34711, 57439, 3903, 104059, 81195, 95931, 58336, 118687, 67931, 123026, - 64235, 95595, 84355, 122946, 8131, 88988, 45130, 58986, 59899, 78278, 94769, 118158, - 25569, 106598, 44224, 96285, 54009, 67246, 85039, 127667, - ]; - assert!(is_valid_solution(96, 5, input, &nonce, &indices)); - - indices = vec![ - 4313, 223176, 448870, 1692641, 214911, 551567, 1696002, 1768726, 500589, 938660, - 724628, 1319625, 632093, 1474613, 665376, 1222606, 244013, 528281, 1741992, 1779660, - 313314, 996273, 435612, 1270863, 337273, 1385279, 1031587, 1147423, 349396, 734528, - 902268, 1678799, 10902, 1231236, 1454381, 1873452, 120530, 2034017, 948243, 1160178, - 198008, 1704079, 1087419, 1734550, 457535, 698704, 649903, 1029510, 75564, 1860165, - 1057819, 1609847, 449808, 527480, 1106201, 1252890, 207200, 390061, 1557573, 1711408, - 396772, 1026145, 652307, 1712346, 10680, 1027631, 232412, 974380, 457702, 1827006, - 1316524, 1400456, 91745, 2032682, 192412, 710106, 556298, 1963798, 1329079, 1504143, - 102455, 974420, 639216, 1647860, 223846, 529637, 425255, 680712, 154734, 541808, - 443572, 798134, 322981, 1728849, 1306504, 1696726, 57884, 913814, 607595, 1882692, - 236616, 1439683, 420968, 943170, 1014827, 1446980, 1468636, 1559477, 1203395, 1760681, - 1439278, 1628494, 195166, 198686, 349906, 1208465, 917335, 1361918, 937682, 1885495, - 494922, 1745948, 1320024, 1826734, 847745, 894084, 1484918, 1523367, 7981, 1450024, - 861459, 1250305, 226676, 329669, 339783, 1935047, 369590, 1564617, 939034, 1908111, - 1147449, 1315880, 1276715, 1428599, 168956, 1442649, 766023, 1171907, 273361, 1902110, - 1169410, 1786006, 413021, 1465354, 707998, 1134076, 977854, 1604295, 1369720, 1486036, - 330340, 1587177, 502224, 1313997, 400402, 1667228, 889478, 946451, 470672, 2019542, - 1023489, 2067426, 658974, 876859, 794443, 1667524, 440815, 1099076, 897391, 1214133, - 953386, 1932936, 1100512, 1362504, 874364, 975669, 1277680, 1412800, 1227580, 1857265, - 1312477, 1514298, 12478, 219890, 534265, 1351062, 65060, 651682, 627900, 1331192, - 123915, 865936, 1218072, 1732445, 429968, 1097946, 947293, 1323447, 157573, 1212459, - 923792, 1943189, 488881, 1697044, 915443, 2095861, 333566, 732311, 336101, 1600549, - 575434, 1978648, 1071114, 1473446, 50017, 54713, 367891, 2055483, 561571, 1714951, - 715652, 1347279, 584549, 1642138, 1002587, 1125289, 1364767, 1382627, 1387373, 2054399, - 97237, 1677265, 707752, 1265819, 121088, 1810711, 1755448, 1858538, 444653, 1130822, - 514258, 1669752, 578843, 729315, 1164894, 1691366, 15609, 1917824, 173620, 587765, - 122779, 2024998, 804857, 1619761, 110829, 1514369, 410197, 493788, 637666, 1765683, - 782619, 1186388, 494761, 1536166, 1582152, 1868968, 825150, 1709404, 1273757, 1657222, - 817285, 1955796, 1014018, 1961262, 873632, 1689675, 985486, 1008905, 130394, 897076, - 419669, 535509, 980696, 1557389, 1244581, 1738170, 197814, 1879515, 297204, 1165124, - 883018, 1677146, 1545438, 2017790, 345577, 1821269, 761785, 1014134, 746829, 751041, - 930466, 1627114, 507500, 588000, 1216514, 1501422, 991142, 1378804, 1797181, 1976685, - 60742, 780804, 383613, 645316, 770302, 952908, 1105447, 1878268, 504292, 1961414, - 693833, 1198221, 906863, 1733938, 1315563, 2049718, 230826, 2064804, 1224594, 1434135, - 897097, 1961763, 993758, 1733428, 306643, 1402222, 532661, 627295, 453009, 973231, - 1746809, 1857154, 263652, 1683026, 1082106, 1840879, 768542, 1056514, 888164, 1529401, - 327387, 1708909, 961310, 1453127, 375204, 878797, 1311831, 1969930, 451358, 1229838, - 583937, 1537472, 467427, 1305086, 812115, 1065593, 532687, 1656280, 954202, 1318066, - 1164182, 1963300, 1232462, 1722064, 17572, 923473, 1715089, 2079204, 761569, 1557392, - 1133336, 1183431, 175157, 1560762, 418801, 927810, 734183, 825783, 1844176, 1951050, - 317246, 336419, 711727, 1630506, 634967, 1595955, 683333, 1461390, 458765, 1834140, - 1114189, 1761250, 459168, 1897513, 1403594, 1478683, 29456, 1420249, 877950, 1371156, - 767300, 1848863, 1607180, 1819984, 96859, 1601334, 171532, 2068307, 980009, 2083421, - 1329455, 2030243, 69434, 1965626, 804515, 1339113, 396271, 1252075, 619032, 2080090, - 84140, 658024, 507836, 772757, 154310, 1580686, 706815, 1024831, 66704, 614858, 256342, - 957013, 1488503, 1615769, 1515550, 1888497, 245610, 1333432, 302279, 776959, 263110, - 1523487, 623933, 2013452, 68977, 122033, 680726, 1849411, 426308, 1292824, 460128, - 1613657, 234271, 971899, 1320730, 1559313, 1312540, 1837403, 1690310, 2040071, 149918, - 380012, 785058, 1675320, 267071, 1095925, 1149690, 1318422, 361557, 1376579, 1587551, - 1715060, 1224593, 1581980, 1354420, 1850496, 151947, 748306, 1987121, 2070676, 273794, - 981619, 683206, 1485056, 766481, 2047708, 930443, 2040726, 1136227, 1945705, 1722044, - 1971986, - ]; - assert!(!is_valid_solution(96, 5, input, &nonce, &indices)); - assert!(is_valid_solution(200, 9, input, &nonce, &indices)); - - nonce[0] = 1; - assert!(!is_valid_solution(96, 5, input, &nonce, &indices)); - assert!(!is_valid_solution(200, 9, input, &nonce, &indices)); - - indices = vec![ - 1911, 96020, 94086, 96830, 7895, 51522, 56142, 62444, 15441, 100732, 48983, 64776, - 27781, 85932, 101138, 114362, 4497, 14199, 36249, 41817, 23995, 93888, 35798, 96337, - 5530, 82377, 66438, 85247, 39332, 78978, 83015, 123505, - ]; - assert!(is_valid_solution(96, 5, input, &nonce, &indices)); - - indices = vec![ - 1505, 1380774, 200806, 1787044, 101056, 1697952, 281464, 374899, 263712, 1532496, - 264180, 637056, 734225, 1882676, 1112004, 2093109, 193394, 1459136, 525171, 657480, - 214528, 1221365, 574444, 594726, 501919, 1309358, 1740268, 1989610, 654491, 1068055, - 919416, 1993208, 17599, 1858176, 1315176, 1901532, 108258, 109600, 1117445, 1936058, - 70247, 1036984, 628234, 1800109, 149791, 365740, 345683, 563554, 21678, 822781, - 1423722, 1644228, 792912, 1409641, 805060, 2041985, 453824, 1003179, 934427, 1068834, - 629003, 1456111, 670049, 1558594, 19016, 1343657, 1698188, 1865216, 45723, 1820952, - 1160970, 1585983, 422549, 1973097, 1296271, 2006382, 650084, 809838, 871727, 1080419, - 28500, 1471829, 384406, 619459, 212041, 1466258, 481435, 866461, 145340, 1403843, - 1339592, 1405761, 163425, 1073771, 285027, 1488210, 167744, 1182267, 1354059, 2089602, - 921700, 2059931, 1704721, 1853088, 585171, 739246, 747551, 1520527, 590255, 1175747, - 705292, 998433, 522014, 1931179, 1629531, 1692879, 588830, 1799457, 963672, 1664237, - 775408, 1926741, 907030, 1466738, 784179, 1972599, 1494787, 1598114, 1736, 1039487, - 88704, 1302687, 579526, 1476728, 1677992, 1854526, 432470, 2062305, 1471132, 1747579, - 1521894, 1917599, 1590975, 1936227, 151871, 1999775, 224664, 461809, 704084, 1306665, - 1316156, 1529628, 876811, 2086004, 1986383, 2012147, 1039505, 1637502, 1432721, - 1565477, 110385, 342650, 659137, 1285167, 367416, 2007586, 445677, 2084877, 285692, - 1144365, 988840, 1990372, 748425, 1617758, 1267712, 1510433, 152291, 1256291, 1722179, - 1995439, 864844, 1623380, 1071853, 1731862, 699978, 1407662, 1048047, 1849702, 962900, - 1083340, 1378752, 1534902, 11843, 115329, 454796, 548919, 148184, 1686936, 862432, - 873854, 60753, 999864, 385959, 1528101, 534420, 678401, 590419, 1962518, 54984, - 1141820, 243305, 1349970, 599681, 1817233, 1632537, 1698724, 580004, 673073, 1403350, - 2026104, 758881, 970056, 1717966, 2062827, 19624, 148580, 609748, 1588928, 456321, - 834920, 700532, 1682606, 20012, 441139, 1591072, 1923394, 194034, 1741063, 1156906, - 1983067, 20703, 1939972, 604581, 963600, 128170, 731716, 606773, 1626824, 139460, - 1386775, 521911, 2043473, 392180, 449532, 895678, 1453340, 7085, 598416, 1514260, - 2061068, 279532, 678363, 943255, 1405306, 119114, 2075865, 592839, 1972064, 254647, - 2078288, 946282, 1567138, 120422, 767626, 213242, 448366, 438457, 1768467, 853790, - 1509505, 735780, 1979631, 1461410, 1462050, 739008, 1572606, 920754, 1507358, 12883, - 1681167, 1308399, 1839490, 85599, 1387522, 703262, 1949514, 18523, 1236125, 669105, - 1464132, 68670, 2085647, 333393, 1731573, 21714, 637827, 985912, 2091029, 84065, - 1688993, 1574405, 1899543, 134032, 179206, 671016, 1118310, 288960, 861994, 622074, - 1738892, 10936, 343910, 598016, 1741971, 586348, 1956071, 851053, 1715626, 531385, - 1213667, 1093995, 1863757, 630365, 1851894, 1328101, 1770446, 31900, 734027, 1078651, - 1701535, 123276, 1916343, 581822, 1681706, 573135, 818091, 1454710, 2052521, 1150284, - 1451159, 1482280, 1811430, 26321, 785837, 877980, 2073103, 107324, 727248, 1785460, - 1840517, 184560, 185640, 364103, 1878753, 518459, 1984029, 964109, 1884200, 74003, - 527272, 516232, 711247, 148582, 209254, 634610, 1534140, 376714, 1573267, 421225, - 1265101, 1078858, 1374310, 1806283, 2091298, 23392, 389637, 413663, 1066737, 226164, - 762552, 1048220, 1583397, 40092, 277435, 775449, 1533894, 202582, 390703, 346741, - 1027320, 523034, 809424, 584882, 1296934, 528062, 733331, 1212771, 1958651, 653372, - 1313962, 1366332, 1784489, 1542466, 1580386, 1628948, 2000957, 57069, 1398636, 1250431, - 1698486, 57289, 596009, 582428, 966130, 167657, 1025537, 1227498, 1630134, 234060, - 1285209, 265623, 1165779, 68485, 632055, 96019, 1854676, 98410, 158575, 168035, - 1296171, 158847, 1243959, 977212, 1113647, 363568, 891940, 954593, 1987111, 90101, - 133251, 1136222, 1255117, 543075, 732768, 749576, 1174878, 422226, 1854657, 1143029, - 1457135, 927105, 1137382, 1566306, 1661926, 103057, 425126, 698089, 1774942, 911019, - 1793511, 1623559, 2002409, 457796, 1196971, 724257, 1811147, 956269, 1165590, 1137531, - 1381215, 201063, 1938529, 986021, 1297857, 921334, 1259083, 1440074, 1939366, 232907, - 747213, 1349009, 1945364, 689906, 1116453, 1904207, 1916192, 229793, 1576982, 1420059, - 1644978, 278248, 2024807, 297914, 419798, 555747, 712605, 1012424, 1428921, 890113, - 1822645, 1082368, 1392894, - ]; - assert!(!is_valid_solution(96, 5, input, &nonce, &indices)); - assert!(is_valid_solution(200, 9, input, &nonce, &indices)); - - let input2 = b"Equihash is an asymmetric PoW based on the Generalised Birthday problem."; - indices = vec![ - 2261, 15185, 36112, 104243, 23779, 118390, 118332, 130041, 32642, 69878, 76925, 80080, - 45858, 116805, 92842, 111026, 15972, 115059, 85191, 90330, 68190, 122819, 81830, 91132, - 23460, 49807, 52426, 80391, 69567, 114474, 104973, 122568, - ]; - assert!(is_valid_solution(96, 5, input2, &nonce, &indices)); - } -} diff --git a/librustzcash/src/hashreader.rs b/librustzcash/src/hashreader.rs deleted file mode 100644 index a422d52..0000000 --- a/librustzcash/src/hashreader.rs +++ /dev/null @@ -1,42 +0,0 @@ -use blake2_rfc::blake2b::Blake2b; -use std::io::{self, Read}; - -/// Abstraction over a reader which hashes the data being read. -pub struct HashReader { - reader: R, - hasher: Blake2b, -} - -impl HashReader { - /// Construct a new `HashReader` given an existing `reader` by value. - pub fn new(reader: R) -> Self { - HashReader { - reader: reader, - hasher: Blake2b::new(64), - } - } - - /// Destroy this reader and return the hash of what was read. - pub fn into_hash(self) -> String { - let hash = self.hasher.finalize(); - - let mut s = String::new(); - for c in hash.as_bytes().iter() { - s += &format!("{:02x}", c); - } - - s - } -} - -impl Read for HashReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let bytes = self.reader.read(buf)?; - - if bytes > 0 { - self.hasher.update(&buf[0..bytes]); - } - - Ok(bytes) - } -} diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs deleted file mode 100644 index b77b6b2..0000000 --- a/librustzcash/src/rustzcash.rs +++ /dev/null @@ -1,1315 +0,0 @@ -extern crate bellman; -extern crate blake2_rfc; -extern crate byteorder; -extern crate libc; -extern crate pairing; -extern crate rand; -extern crate sapling_crypto; -extern crate zcash_proofs; -extern crate zip32; - -mod hashreader; - -#[macro_use] -extern crate lazy_static; - -use pairing::{ - bls12_381::{Bls12, Fr, FrRepr}, - BitIterator, PrimeField, PrimeFieldRepr, -}; - -use sapling_crypto::{ - circuit::multipack, - constants::CRH_IVK_PERSONALIZATION, - jubjub::{ - edwards, - fs::{Fs, FsRepr}, - FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, PrimeOrder, ToUniform, Unknown, - }, - pedersen_hash::{pedersen_hash, Personalization}, - redjubjub::{self, Signature}, -}; - -use sapling_crypto::circuit::sapling::TREE_DEPTH as SAPLING_TREE_DEPTH; -use sapling_crypto::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH}; - -use bellman::groth16::{ - create_random_proof, prepare_verifying_key, verify_proof, Parameters, PreparedVerifyingKey, - Proof, VerifyingKey, -}; - -use blake2_rfc::blake2s::Blake2s; - -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; - -use rand::{OsRng, Rng}; -use std::io::{self, BufReader}; - -use libc::{c_char, c_uchar, int64_t, size_t, uint32_t, uint64_t}; -use std::ffi::CStr; -use std::fs::File; -use std::path::{Path, PathBuf}; -use std::slice; - -#[cfg(not(target_os = "windows"))] -use std::ffi::OsStr; -#[cfg(not(target_os = "windows"))] -use std::os::unix::ffi::OsStrExt; - -#[cfg(target_os = "windows")] -use std::ffi::OsString; -#[cfg(target_os = "windows")] -use std::os::windows::ffi::OsStringExt; - -use sapling_crypto::primitives::{ProofGenerationKey, ViewingKey}; -use zcash_proofs::sapling::{ - CommitmentTreeWitness, SaplingProvingContext, SaplingVerificationContext, -}; - -pub mod equihash; - -#[cfg(test)] -mod tests; - -lazy_static! { - static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() }; -} - -static mut SAPLING_SPEND_VK: Option> = None; -static mut SAPLING_OUTPUT_VK: Option> = None; -static mut SPROUT_GROTH16_VK: Option> = None; - -static mut SAPLING_SPEND_PARAMS: Option> = None; -static mut SAPLING_OUTPUT_PARAMS: Option> = None; -static mut SPROUT_GROTH16_PARAMS_PATH: Option = None; - -/// Writes an FrRepr to [u8] of length 32 -fn write_le(f: FrRepr, to: &mut [u8]) { - assert_eq!(to.len(), 32); - - f.write_le(to).expect("length is 32 bytes"); -} - -/// Reads an FrRepr from a [u8] of length 32. -/// This will panic (abort) if length provided is -/// not correct. -fn read_le(from: &[u8]) -> FrRepr { - assert_eq!(from.len(), 32); - - let mut f = FrRepr::default(); - f.read_le(from).expect("length is 32 bytes"); - - f -} - -/// Reads an FsRepr from [u8] of length 32 -/// This will panic (abort) if length provided is -/// not correct -fn read_fs(from: &[u8]) -> FsRepr { - assert_eq!(from.len(), 32); - - let mut f = <::Fs as PrimeField>::Repr::default(); - f.read_le(from).expect("length is 32 bytes"); - - f -} - -/// Reads an FsRepr from [u8] of length 32 -/// and multiplies it by the given base. -/// This will panic (abort) if length provided is -/// not correct -fn fixed_scalar_mult(from: &[u8], p_g: FixedGenerators) -> edwards::Point { - let f = read_fs(from); - - JUBJUB.generator(p_g).mul(f, &JUBJUB) -} - -#[cfg(not(target_os = "windows"))] -#[no_mangle] -pub extern "system" fn librustzcash_init_zksnark_params( - spend_path: *const u8, - spend_path_len: usize, - spend_hash: *const c_char, - output_path: *const u8, - output_path_len: usize, - output_hash: *const c_char, - sprout_path: *const u8, - sprout_path_len: usize, - sprout_hash: *const c_char, -) { - let spend_path = Path::new(OsStr::from_bytes(unsafe { - slice::from_raw_parts(spend_path, spend_path_len) - })); - let output_path = Path::new(OsStr::from_bytes(unsafe { - slice::from_raw_parts(output_path, output_path_len) - })); - let sprout_path = Path::new(OsStr::from_bytes(unsafe { - slice::from_raw_parts(sprout_path, sprout_path_len) - })); - - init_zksnark_params( - spend_path, - spend_hash, - output_path, - output_hash, - sprout_path, - sprout_hash, - ) -} - -#[cfg(target_os = "windows")] -#[no_mangle] -pub extern "system" fn librustzcash_init_zksnark_params( - spend_path: *const u16, - spend_path_len: usize, - spend_hash: *const c_char, - output_path: *const u16, - output_path_len: usize, - output_hash: *const c_char, - sprout_path: *const u16, - sprout_path_len: usize, - sprout_hash: *const c_char, -) { - let spend_path = - OsString::from_wide(unsafe { slice::from_raw_parts(spend_path, spend_path_len) }); - let output_path = - OsString::from_wide(unsafe { slice::from_raw_parts(output_path, output_path_len) }); - let sprout_path = - OsString::from_wide(unsafe { slice::from_raw_parts(sprout_path, sprout_path_len) }); - - init_zksnark_params( - Path::new(&spend_path), - spend_hash, - Path::new(&output_path), - output_hash, - Path::new(&sprout_path), - sprout_hash, - ) -} - -fn init_zksnark_params( - spend_path: &Path, - spend_hash: *const c_char, - output_path: &Path, - output_hash: *const c_char, - sprout_path: &Path, - sprout_hash: *const c_char, -) { - // Initialize jubjub parameters here - lazy_static::initialize(&JUBJUB); - - let spend_hash = unsafe { CStr::from_ptr(spend_hash) } - .to_str() - .expect("hash should be a valid string") - .to_string(); - - let output_hash = unsafe { CStr::from_ptr(output_hash) } - .to_str() - .expect("hash should be a valid string") - .to_string(); - - let sprout_hash = unsafe { CStr::from_ptr(sprout_hash) } - .to_str() - .expect("hash should be a valid string") - .to_string(); - - // Load from each of the paths - let spend_fs = File::open(spend_path).expect("couldn't load Sapling spend parameters file"); - let output_fs = File::open(output_path).expect("couldn't load Sapling output parameters file"); - let sprout_fs = File::open(sprout_path).expect("couldn't load Sprout groth16 parameters file"); - - let mut spend_fs = hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, spend_fs)); - let mut output_fs = - hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, output_fs)); - let mut sprout_fs = - hashreader::HashReader::new(BufReader::with_capacity(1024 * 1024, sprout_fs)); - - // Deserialize params - let spend_params = Parameters::::read(&mut spend_fs, false) - .expect("couldn't deserialize Sapling spend parameters file"); - let output_params = Parameters::::read(&mut output_fs, false) - .expect("couldn't deserialize Sapling spend parameters file"); - - // We only deserialize the verifying key for the Sprout parameters, which - // appears at the beginning of the parameter file. The rest is loaded - // during proving time. - let sprout_vk = VerifyingKey::::read(&mut sprout_fs) - .expect("couldn't deserialize Sprout Groth16 verifying key"); - - // There is extra stuff (the transcript) at the end of the parameter file which is - // used to verify the parameter validity, but we're not interested in that. We do - // want to read it, though, so that the BLAKE2b computed afterward is consistent - // with `b2sum` on the files. - let mut sink = io::sink(); - io::copy(&mut spend_fs, &mut sink) - .expect("couldn't finish reading Sapling spend parameter file"); - io::copy(&mut output_fs, &mut sink) - .expect("couldn't finish reading Sapling output parameter file"); - io::copy(&mut sprout_fs, &mut sink) - .expect("couldn't finish reading Sprout groth16 parameter file"); - - if spend_fs.into_hash() != spend_hash { - panic!("Sapling spend parameter file is not correct, please clean your `~/.zcash-params/` and re-run `fetch-params`."); - } - - if output_fs.into_hash() != output_hash { - panic!("Sapling output parameter file is not correct, please clean your `~/.zcash-params/` and re-run `fetch-params`."); - } - - if sprout_fs.into_hash() != sprout_hash { - panic!("Sprout groth16 parameter file is not correct, please clean your `~/.zcash-params/` and re-run `fetch-params`."); - } - - // Prepare verifying keys - let spend_vk = prepare_verifying_key(&spend_params.vk); - let output_vk = prepare_verifying_key(&output_params.vk); - let sprout_vk = prepare_verifying_key(&sprout_vk); - - // Caller is responsible for calling this function once, so - // these global mutations are safe. - unsafe { - SAPLING_SPEND_PARAMS = Some(spend_params); - SAPLING_OUTPUT_PARAMS = Some(output_params); - SPROUT_GROTH16_PARAMS_PATH = Some(sprout_path.to_owned()); - - SAPLING_SPEND_VK = Some(spend_vk); - SAPLING_OUTPUT_VK = Some(output_vk); - SPROUT_GROTH16_VK = Some(sprout_vk); - } -} - -#[no_mangle] -pub extern "system" fn librustzcash_tree_uncommitted(result: *mut [c_uchar; 32]) { - let tmp = sapling_crypto::primitives::Note::::uncommitted().into_repr(); - - // Should be okay, caller is responsible for ensuring the pointer - // is a valid pointer to 32 bytes that can be mutated. - let result = unsafe { &mut *result }; - - write_le(tmp, &mut result[..]); -} - -#[no_mangle] -pub extern "system" fn librustzcash_merkle_hash( - depth: size_t, - a: *const [c_uchar; 32], - b: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) { - // Should be okay, because caller is responsible for ensuring - // the pointer is a valid pointer to 32 bytes, and that is the - // size of the representation - let a_repr = read_le(unsafe { &(&*a)[..] }); - - // Should be okay, because caller is responsible for ensuring - // the pointer is a valid pointer to 32 bytes, and that is the - // size of the representation - let b_repr = read_le(unsafe { &(&*b)[..] }); - - let mut lhs = [false; 256]; - let mut rhs = [false; 256]; - - for (a, b) in lhs.iter_mut().rev().zip(BitIterator::new(a_repr)) { - *a = b; - } - - for (a, b) in rhs.iter_mut().rev().zip(BitIterator::new(b_repr)) { - *a = b; - } - - let tmp = pedersen_hash::( - Personalization::MerkleTree(depth), - lhs.iter() - .map(|&x| x) - .take(Fr::NUM_BITS as usize) - .chain(rhs.iter().map(|&x| x).take(Fr::NUM_BITS as usize)), - &JUBJUB, - ) - .into_xy() - .0 - .into_repr(); - - // Should be okay, caller is responsible for ensuring the pointer - // is a valid pointer to 32 bytes that can be mutated. - let result = unsafe { &mut *result }; - - write_le(tmp, &mut result[..]); -} - -#[no_mangle] // ToScalar -pub extern "system" fn librustzcash_to_scalar( - input: *const [c_uchar; 64], - result: *mut [c_uchar; 32], -) { - // Should be okay, because caller is responsible for ensuring - // the pointer is a valid pointer to 32 bytes, and that is the - // size of the representation - let scalar = ::Fs::to_uniform(unsafe { &(&*input)[..] }).into_repr(); - - let result = unsafe { &mut *result }; - - scalar - .write_le(&mut result[..]) - .expect("length is 32 bytes"); -} - -#[no_mangle] -pub extern "system" fn librustzcash_ask_to_ak( - ask: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) { - let ask = unsafe { &*ask }; - let ak = fixed_scalar_mult(ask, FixedGenerators::SpendingKeyGenerator); - - let result = unsafe { &mut *result }; - - ak.write(&mut result[..]).expect("length is 32 bytes"); -} - -#[no_mangle] -pub extern "system" fn librustzcash_nsk_to_nk( - nsk: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) { - let nsk = unsafe { &*nsk }; - let nk = fixed_scalar_mult(nsk, FixedGenerators::ProofGenerationKey); - - let result = unsafe { &mut *result }; - - nk.write(&mut result[..]).expect("length is 32 bytes"); -} - -#[no_mangle] -pub extern "system" fn librustzcash_crh_ivk( - ak: *const [c_uchar; 32], - nk: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) { - let ak = unsafe { &*ak }; - let nk = unsafe { &*nk }; - - let mut h = Blake2s::with_params(32, &[], &[], CRH_IVK_PERSONALIZATION); - h.update(ak); - h.update(nk); - let mut h = h.finalize().as_ref().to_vec(); - - // Drop the last five bits, so it can be interpreted as a scalar. - h[31] &= 0b0000_0111; - - let result = unsafe { &mut *result }; - - result.copy_from_slice(&h); -} - -#[no_mangle] -pub extern "system" fn librustzcash_check_diversifier(diversifier: *const [c_uchar; 11]) -> bool { - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); - diversifier.g_d::(&JUBJUB).is_some() -} - -#[no_mangle] -pub extern "system" fn librustzcash_ivk_to_pkd( - ivk: *const [c_uchar; 32], - diversifier: *const [c_uchar; 11], - result: *mut [c_uchar; 32], -) -> bool { - let ivk = read_fs(unsafe { &*ivk }); - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); - if let Some(g_d) = diversifier.g_d::(&JUBJUB) { - let pk_d = g_d.mul(ivk, &JUBJUB); - - let result = unsafe { &mut *result }; - - pk_d.write(&mut result[..]).expect("length is 32 bytes"); - - true - } else { - false - } -} - -/// Test generation of commitment randomness -#[test] -fn test_gen_r() { - let mut r1 = [0u8; 32]; - let mut r2 = [0u8; 32]; - - // Verify different r values are generated - librustzcash_sapling_generate_r(&mut r1); - librustzcash_sapling_generate_r(&mut r2); - assert_ne!(r1, r2); - - // Verify r values are valid in the field - let mut repr = FsRepr::default(); - repr.read_le(&r1[..]).expect("length is not 32 bytes"); - let _ = Fs::from_repr(repr).unwrap(); - repr.read_le(&r2[..]).expect("length is not 32 bytes"); - let _ = Fs::from_repr(repr).unwrap(); -} - -/// Return 32 byte random scalar, uniformly. -#[no_mangle] -pub extern "system" fn librustzcash_sapling_generate_r(result: *mut [c_uchar; 32]) { - // create random 64 byte buffer - let mut rng = OsRng::new().expect("should be able to construct RNG"); - let mut buffer = [0u8; 64]; - for i in 0..buffer.len() { - buffer[i] = rng.gen(); - } - - // reduce to uniform value - let r = ::Fs::to_uniform(&buffer[..]); - let result = unsafe { &mut *result }; - r.into_repr() - .write_le(&mut result[..]) - .expect("result must be 32 bytes"); -} - -// Private utility function to get Note from C parameters -fn priv_get_note( - diversifier: *const [c_uchar; 11], - pk_d: *const [c_uchar; 32], - value: uint64_t, - r: *const [c_uchar; 32], -) -> Result, ()> { - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); - let g_d = match diversifier.g_d::(&JUBJUB) { - Some(g_d) => g_d, - None => return Err(()), - }; - - let pk_d = match edwards::Point::::read(&(unsafe { &*pk_d })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return Err(()), - }; - - let pk_d = match pk_d.as_prime_order(&JUBJUB) { - Some(pk_d) => pk_d, - None => return Err(()), - }; - - // Deserialize randomness - let r = match Fs::from_repr(read_fs(&(unsafe { &*r })[..])) { - Ok(r) => r, - Err(_) => return Err(()), - }; - - let note = sapling_crypto::primitives::Note { - value, - g_d, - pk_d, - r, - }; - - Ok(note) -} - -/// Compute Sapling note nullifier. -#[no_mangle] -pub extern "system" fn librustzcash_sapling_compute_nf( - diversifier: *const [c_uchar; 11], - pk_d: *const [c_uchar; 32], - value: uint64_t, - r: *const [c_uchar; 32], - ak: *const [c_uchar; 32], - nk: *const [c_uchar; 32], - position: uint64_t, - result: *mut [c_uchar; 32], -) -> bool { - let note = match priv_get_note(diversifier, pk_d, value, r) { - Ok(p) => p, - Err(_) => return false, - }; - - let ak = match edwards::Point::::read(&(unsafe { &*ak })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - let ak = match ak.as_prime_order(&JUBJUB) { - Some(ak) => ak, - None => return false, - }; - - let nk = match edwards::Point::::read(&(unsafe { &*nk })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - let nk = match nk.as_prime_order(&JUBJUB) { - Some(nk) => nk, - None => return false, - }; - - let vk = ViewingKey { ak, nk }; - let nf = note.nf(&vk, position, &JUBJUB); - let result = unsafe { &mut *result }; - result.copy_from_slice(&nf); - - true -} - -/// Compute Sapling note commitment. -#[no_mangle] -pub extern "system" fn librustzcash_sapling_compute_cm( - diversifier: *const [c_uchar; 11], - pk_d: *const [c_uchar; 32], - value: uint64_t, - r: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) -> bool { - let note = match priv_get_note(diversifier, pk_d, value, r) { - Ok(p) => p, - Err(_) => return false, - }; - - let result = unsafe { &mut *result }; - write_le(note.cm(&JUBJUB).into_repr(), &mut result[..]); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_ka_agree( - p: *const [c_uchar; 32], - sk: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) -> bool { - // Deserialize p - let p = match edwards::Point::::read(&(unsafe { &*p })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - // Deserialize sk - let sk = match Fs::from_repr(read_fs(&(unsafe { &*sk })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - // Multiply by 8 - let p = p.mul_by_cofactor(&JUBJUB); - - // Multiply by sk - let p = p.mul(sk, &JUBJUB); - - // Produce result - let result = unsafe { &mut *result }; - p.write(&mut result[..]).expect("length is not 32 bytes"); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_ka_derivepublic( - diversifier: *const [c_uchar; 11], - esk: *const [c_uchar; 32], - result: *mut [c_uchar; 32], -) -> bool { - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); - - // Compute g_d from the diversifier - let g_d = match diversifier.g_d::(&JUBJUB) { - Some(g) => g, - None => return false, - }; - - // Deserialize esk - let esk = match Fs::from_repr(read_fs(&(unsafe { &*esk })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - let p = g_d.mul(esk, &JUBJUB); - - let result = unsafe { &mut *result }; - p.write(&mut result[..]).expect("length is not 32 bytes"); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_eh_isvalid( - n: uint32_t, - k: uint32_t, - input: *const c_uchar, - input_len: size_t, - nonce: *const c_uchar, - nonce_len: size_t, - soln: *const c_uchar, - soln_len: size_t, -) -> bool { - if (k >= n) || (n % 8 != 0) || (soln_len != (1 << k) * ((n / (k + 1)) as usize + 1) / 8) { - return false; - } - let rs_input = unsafe { slice::from_raw_parts(input, input_len) }; - let rs_nonce = unsafe { slice::from_raw_parts(nonce, nonce_len) }; - let rs_soln = unsafe { slice::from_raw_parts(soln, soln_len) }; - equihash::is_valid_solution(n, k, rs_input, rs_nonce, rs_soln) -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_verification_ctx_init( -) -> *mut SaplingVerificationContext { - let ctx = Box::new(SaplingVerificationContext::new()); - - Box::into_raw(ctx) -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_verification_ctx_free( - ctx: *mut SaplingVerificationContext, -) { - drop(unsafe { Box::from_raw(ctx) }); -} - -const GROTH_PROOF_SIZE: usize = 48 // π_A - + 96 // π_B - + 48; // π_C - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_check_spend( - ctx: *mut SaplingVerificationContext, - cv: *const [c_uchar; 32], - anchor: *const [c_uchar; 32], - nullifier: *const [c_uchar; 32], - rk: *const [c_uchar; 32], - zkproof: *const [c_uchar; GROTH_PROOF_SIZE], - spend_auth_sig: *const [c_uchar; 64], - sighash_value: *const [c_uchar; 32], -) -> bool { - // Deserialize the value commitment - let cv = match edwards::Point::::read(&(unsafe { &*cv })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - // Deserialize the anchor, which should be an element - // of Fr. - let anchor = match Fr::from_repr(read_le(&(unsafe { &*anchor })[..])) { - Ok(a) => a, - Err(_) => return false, - }; - - // Deserialize rk - let rk = match redjubjub::PublicKey::::read(&(unsafe { &*rk })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - // Deserialize the signature - let spend_auth_sig = match Signature::read(&(unsafe { &*spend_auth_sig })[..]) { - Ok(sig) => sig, - Err(_) => return false, - }; - - // Deserialize the proof - let zkproof = match Proof::::read(&(unsafe { &*zkproof })[..]) { - Ok(p) => p, - Err(_) => return false, - }; - - unsafe { &mut *ctx }.check_spend( - cv, - anchor, - unsafe { &*nullifier }, - rk, - unsafe { &*sighash_value }, - spend_auth_sig, - zkproof, - unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap(), - &JUBJUB, - ) -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_check_output( - ctx: *mut SaplingVerificationContext, - cv: *const [c_uchar; 32], - cm: *const [c_uchar; 32], - epk: *const [c_uchar; 32], - zkproof: *const [c_uchar; GROTH_PROOF_SIZE], -) -> bool { - // Deserialize the value commitment - let cv = match edwards::Point::::read(&(unsafe { &*cv })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - // Deserialize the commitment, which should be an element - // of Fr. - let cm = match Fr::from_repr(read_le(&(unsafe { &*cm })[..])) { - Ok(a) => a, - Err(_) => return false, - }; - - // Deserialize the ephemeral key - let epk = match edwards::Point::::read(&(unsafe { &*epk })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - // Deserialize the proof - let zkproof = match Proof::::read(&(unsafe { &*zkproof })[..]) { - Ok(p) => p, - Err(_) => return false, - }; - - unsafe { &mut *ctx }.check_output( - cv, - cm, - epk, - zkproof, - unsafe { SAPLING_OUTPUT_VK.as_ref() }.unwrap(), - &JUBJUB, - ) -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_final_check( - ctx: *mut SaplingVerificationContext, - value_balance: int64_t, - binding_sig: *const [c_uchar; 64], - sighash_value: *const [c_uchar; 32], -) -> bool { - // Deserialize the signature - let binding_sig = match Signature::read(&(unsafe { &*binding_sig })[..]) { - Ok(sig) => sig, - Err(_) => return false, - }; - - unsafe { &*ctx }.final_check( - value_balance, - unsafe { &*sighash_value }, - binding_sig, - &JUBJUB, - ) -} - -#[no_mangle] -pub extern "system" fn librustzcash_sprout_prove( - proof_out: *mut [c_uchar; GROTH_PROOF_SIZE], - - phi: *const [c_uchar; 32], - rt: *const [c_uchar; 32], - h_sig: *const [c_uchar; 32], - - // First input - in_sk1: *const [c_uchar; 32], - in_value1: uint64_t, - in_rho1: *const [c_uchar; 32], - in_r1: *const [c_uchar; 32], - in_auth1: *const [c_uchar; 1 + 33 * SPROUT_TREE_DEPTH + 8], - - // Second input - in_sk2: *const [c_uchar; 32], - in_value2: uint64_t, - in_rho2: *const [c_uchar; 32], - in_r2: *const [c_uchar; 32], - in_auth2: *const [c_uchar; 1 + 33 * SPROUT_TREE_DEPTH + 8], - - // First output - out_pk1: *const [c_uchar; 32], - out_value1: uint64_t, - out_r1: *const [c_uchar; 32], - - // Second output - out_pk2: *const [c_uchar; 32], - out_value2: uint64_t, - out_r2: *const [c_uchar; 32], - - // Public value - vpub_old: uint64_t, - vpub_new: uint64_t, -) { - let phi = unsafe { *phi }; - let rt = unsafe { *rt }; - let h_sig = unsafe { *h_sig }; - let in_sk1 = unsafe { *in_sk1 }; - let in_rho1 = unsafe { *in_rho1 }; - let in_r1 = unsafe { *in_r1 }; - let in_auth1 = unsafe { *in_auth1 }; - let in_sk2 = unsafe { *in_sk2 }; - let in_rho2 = unsafe { *in_rho2 }; - let in_r2 = unsafe { *in_r2 }; - let in_auth2 = unsafe { *in_auth2 }; - let out_pk1 = unsafe { *out_pk1 }; - let out_r1 = unsafe { *out_r1 }; - let out_pk2 = unsafe { *out_pk2 }; - let out_r2 = unsafe { *out_r2 }; - - let mut inputs = Vec::with_capacity(2); - { - let mut handle_input = |sk, value, rho, r, mut auth: &[u8]| { - let value = Some(value); - let rho = Some(sprout::UniqueRandomness(rho)); - let r = Some(sprout::CommitmentRandomness(r)); - let a_sk = Some(sprout::SpendingKey(sk)); - - // skip the first byte - assert_eq!(auth[0], SPROUT_TREE_DEPTH as u8); - auth = &auth[1..]; - - let mut auth_path = [None; SPROUT_TREE_DEPTH]; - for i in (0..SPROUT_TREE_DEPTH).rev() { - // skip length of inner vector - assert_eq!(auth[0], 32); - auth = &auth[1..]; - - let mut sibling = [0u8; 32]; - sibling.copy_from_slice(&auth[0..32]); - auth = &auth[32..]; - - auth_path[i] = Some((sibling, false)); - } - - let mut position = auth - .read_u64::() - .expect("should have had index at the end"); - - for i in 0..SPROUT_TREE_DEPTH { - auth_path[i].as_mut().map(|p| p.1 = (position & 1) == 1); - - position >>= 1; - } - - inputs.push(sprout::JSInput { - value: value, - a_sk: a_sk, - rho: rho, - r: r, - auth_path: auth_path, - }); - }; - - handle_input(in_sk1, in_value1, in_rho1, in_r1, &in_auth1[..]); - handle_input(in_sk2, in_value2, in_rho2, in_r2, &in_auth2[..]); - } - - let mut outputs = Vec::with_capacity(2); - { - let mut handle_output = |a_pk, value, r| { - outputs.push(sprout::JSOutput { - value: Some(value), - a_pk: Some(sprout::PayingKey(a_pk)), - r: Some(sprout::CommitmentRandomness(r)), - }); - }; - - handle_output(out_pk1, out_value1, out_r1); - handle_output(out_pk2, out_value2, out_r2); - } - - let js = sprout::JoinSplit { - vpub_old: Some(vpub_old), - vpub_new: Some(vpub_new), - h_sig: Some(h_sig), - phi: Some(phi), - inputs: inputs, - outputs: outputs, - rt: Some(rt), - }; - - // Load parameters from disk - let sprout_fs = File::open( - unsafe { &SPROUT_GROTH16_PARAMS_PATH } - .as_ref() - .expect("parameters should have been initialized"), - ) - .expect("couldn't load Sprout groth16 parameters file"); - - let mut sprout_fs = BufReader::with_capacity(1024 * 1024, sprout_fs); - - let params = Parameters::::read(&mut sprout_fs, false) - .expect("couldn't deserialize Sprout JoinSplit parameters file"); - - drop(sprout_fs); - - // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); - - let proof = create_random_proof(js, ¶ms, &mut rng).expect("proving should not fail"); - - proof - .write(&mut (unsafe { &mut *proof_out })[..]) - .expect("should be able to serialize a proof"); -} - -#[no_mangle] -pub extern "system" fn librustzcash_sprout_verify( - proof: *const [c_uchar; GROTH_PROOF_SIZE], - rt: *const [c_uchar; 32], - h_sig: *const [c_uchar; 32], - mac1: *const [c_uchar; 32], - mac2: *const [c_uchar; 32], - nf1: *const [c_uchar; 32], - nf2: *const [c_uchar; 32], - cm1: *const [c_uchar; 32], - cm2: *const [c_uchar; 32], - vpub_old: uint64_t, - vpub_new: uint64_t, -) -> bool { - // Prepare the public input for the verifier - let mut public_input = Vec::with_capacity((32 * 8) + (8 * 2)); - public_input.extend(unsafe { &(&*rt)[..] }); - public_input.extend(unsafe { &(&*h_sig)[..] }); - public_input.extend(unsafe { &(&*nf1)[..] }); - public_input.extend(unsafe { &(&*mac1)[..] }); - public_input.extend(unsafe { &(&*nf2)[..] }); - public_input.extend(unsafe { &(&*mac2)[..] }); - public_input.extend(unsafe { &(&*cm1)[..] }); - public_input.extend(unsafe { &(&*cm2)[..] }); - public_input.write_u64::(vpub_old).unwrap(); - public_input.write_u64::(vpub_new).unwrap(); - - let public_input = multipack::bytes_to_bits(&public_input); - let public_input = multipack::compute_multipacking::(&public_input); - - let proof = match Proof::read(unsafe { &(&*proof)[..] }) { - Ok(p) => p, - Err(_) => return false, - }; - - // Verify the proof - match verify_proof( - unsafe { SPROUT_GROTH16_VK.as_ref() }.expect("parameters should have been initialized"), - &proof, - &public_input[..], - ) { - // No error, and proof verification successful - Ok(true) => true, - - // Any other case - _ => false, - } -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_output_proof( - ctx: *mut SaplingProvingContext, - esk: *const [c_uchar; 32], - diversifier: *const [c_uchar; 11], - pk_d: *const [c_uchar; 32], - rcm: *const [c_uchar; 32], - value: uint64_t, - cv: *mut [c_uchar; 32], - zkproof: *mut [c_uchar; GROTH_PROOF_SIZE], -) -> bool { - // Grab `esk`, which the caller should have constructed for the DH key exchange. - let esk = match Fs::from_repr(read_fs(&(unsafe { &*esk })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - // Grab the diversifier from the caller. - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); - - // Grab pk_d from the caller. - let pk_d = match edwards::Point::::read(&(unsafe { &*pk_d })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - // pk_d should be prime order. - let pk_d = match pk_d.as_prime_order(&JUBJUB) { - Some(p) => p, - None => return false, - }; - - // Construct a payment address - let payment_address = sapling_crypto::primitives::PaymentAddress { - pk_d: pk_d, - diversifier: diversifier, - }; - - // The caller provides the commitment randomness for the output note - let rcm = match Fs::from_repr(read_fs(&(unsafe { &*rcm })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - // Create proof - let (proof, value_commitment) = unsafe { &mut *ctx }.output_proof( - esk, - payment_address, - rcm, - value, - unsafe { SAPLING_OUTPUT_PARAMS.as_ref() }.unwrap(), - &JUBJUB, - ); - - // Write the proof out to the caller - proof - .write(&mut (unsafe { &mut *zkproof })[..]) - .expect("should be able to serialize a proof"); - - // Write the value commitment to the caller - value_commitment - .write(&mut (unsafe { &mut *cv })[..]) - .expect("should be able to serialize rcv"); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_spend_sig( - ask: *const [c_uchar; 32], - ar: *const [c_uchar; 32], - sighash: *const [c_uchar; 32], - result: *mut [c_uchar; 64], -) -> bool { - // The caller provides the re-randomization of `ak`. - let ar = match Fs::from_repr(read_fs(&(unsafe { &*ar })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - // The caller provides `ask`, the spend authorizing key. - let ask = match redjubjub::PrivateKey::::read(&(unsafe { &*ask })[..]) { - Ok(p) => p, - Err(_) => return false, - }; - - // We compute `rsk`... - let rsk = ask.randomize(ar); - - // We compute `rk` from there (needed for key prefixing) - let rk = - redjubjub::PublicKey::from_private(&rsk, FixedGenerators::SpendingKeyGenerator, &JUBJUB); - - // Compute the signature's message for rk/spend_auth_sig - let mut data_to_be_signed = [0u8; 64]; - rk.0.write(&mut data_to_be_signed[0..32]) - .expect("message buffer should be 32 bytes"); - (&mut data_to_be_signed[32..64]).copy_from_slice(&(unsafe { &*sighash })[..]); - - // Do the signing - let mut rng = OsRng::new().expect("should be able to construct RNG"); - let sig = rsk.sign( - &data_to_be_signed, - &mut rng, - FixedGenerators::SpendingKeyGenerator, - &JUBJUB, - ); - - // Write out the signature - sig.write(&mut (unsafe { &mut *result })[..]) - .expect("result should be 64 bytes"); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_binding_sig( - ctx: *const SaplingProvingContext, - value_balance: int64_t, - sighash: *const [c_uchar; 32], - result: *mut [c_uchar; 64], -) -> bool { - // Sign - let sig = match unsafe { &*ctx }.binding_sig(value_balance, unsafe { &*sighash }, &JUBJUB) { - Ok(s) => s, - Err(_) => return false, - }; - - // Write out signature - sig.write(&mut (unsafe { &mut *result })[..]) - .expect("result should be 64 bytes"); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_spend_proof( - ctx: *mut SaplingProvingContext, - ak: *const [c_uchar; 32], - nsk: *const [c_uchar; 32], - diversifier: *const [c_uchar; 11], - rcm: *const [c_uchar; 32], - ar: *const [c_uchar; 32], - value: uint64_t, - anchor: *const [c_uchar; 32], - witness: *const [c_uchar; 1 + 33 * SAPLING_TREE_DEPTH + 8], - cv: *mut [c_uchar; 32], - rk_out: *mut [c_uchar; 32], - zkproof: *mut [c_uchar; GROTH_PROOF_SIZE], -) -> bool { - // Grab `ak` from the caller, which should be a point. - let ak = match edwards::Point::::read(&(unsafe { &*ak })[..], &JUBJUB) { - Ok(p) => p, - Err(_) => return false, - }; - - // `ak` should be prime order. - let ak = match ak.as_prime_order(&JUBJUB) { - Some(p) => p, - None => return false, - }; - - // Grab `nsk` from the caller - let nsk = match Fs::from_repr(read_fs(&(unsafe { &*nsk })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - // Construct the proof generation key - let proof_generation_key = ProofGenerationKey { - ak: ak.clone(), - nsk, - }; - - // Grab the diversifier from the caller - let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); - - // The caller chooses the note randomness - let rcm = match Fs::from_repr(read_fs(&(unsafe { &*rcm })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - // The caller also chooses the re-randomization of ak - let ar = match Fs::from_repr(read_fs(&(unsafe { &*ar })[..])) { - Ok(p) => p, - Err(_) => return false, - }; - - // We need to compute the anchor of the Spend. - let anchor = match Fr::from_repr(read_le(unsafe { &(&*anchor)[..] })) { - Ok(p) => p, - Err(_) => return false, - }; - - // The witness contains the incremental tree witness information, in a - // weird serialized format. - let witness = match CommitmentTreeWitness::from_slice(unsafe { &(&*witness)[..] }) { - Ok(w) => w, - Err(_) => return false, - }; - - // Create proof - let (proof, value_commitment, rk) = unsafe { &mut *ctx } - .spend_proof( - proof_generation_key, - diversifier, - rcm, - ar, - value, - anchor, - witness, - unsafe { SAPLING_SPEND_PARAMS.as_ref() }.unwrap(), - unsafe { SAPLING_SPEND_VK.as_ref() }.unwrap(), - &JUBJUB, - ) - .expect("proving should not fail"); - - // Write value commitment to caller - value_commitment - .write(&mut unsafe { &mut *cv }[..]) - .expect("should be able to serialize cv"); - - // Write proof out to caller - proof - .write(&mut (unsafe { &mut *zkproof })[..]) - .expect("should be able to serialize a proof"); - - // Write out `rk` to the caller - rk.write(&mut unsafe { &mut *rk_out }[..]) - .expect("should be able to write to rk_out"); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_proving_ctx_init() -> *mut SaplingProvingContext { - let ctx = Box::new(SaplingProvingContext::new()); - - Box::into_raw(ctx) -} - -#[no_mangle] -pub extern "system" fn librustzcash_sapling_proving_ctx_free(ctx: *mut SaplingProvingContext) { - drop(unsafe { Box::from_raw(ctx) }); -} - -#[no_mangle] -pub extern "system" fn librustzcash_zip32_xsk_master( - seed: *const c_uchar, - seedlen: size_t, - xsk_master: *mut [c_uchar; 169], -) { - let seed = unsafe { std::slice::from_raw_parts(seed, seedlen) }; - - let xsk = zip32::ExtendedSpendingKey::master(seed); - - xsk.write(&mut (unsafe { &mut *xsk_master })[..]) - .expect("should be able to serialize an ExtendedSpendingKey"); -} - -#[no_mangle] -pub extern "system" fn librustzcash_zip32_xsk_derive( - xsk_parent: *const [c_uchar; 169], - i: uint32_t, - xsk_i: *mut [c_uchar; 169], -) { - let xsk_parent = zip32::ExtendedSpendingKey::read(&unsafe { *xsk_parent }[..]) - .expect("valid ExtendedSpendingKey"); - let i = zip32::ChildIndex::from_index(i); - - let xsk = xsk_parent.derive_child(i); - - xsk.write(&mut (unsafe { &mut *xsk_i })[..]) - .expect("should be able to serialize an ExtendedSpendingKey"); -} - -#[no_mangle] -pub extern "system" fn librustzcash_zip32_xfvk_derive( - xfvk_parent: *const [c_uchar; 169], - i: uint32_t, - xfvk_i: *mut [c_uchar; 169], -) -> bool { - let xfvk_parent = zip32::ExtendedFullViewingKey::read(&unsafe { *xfvk_parent }[..]) - .expect("valid ExtendedFullViewingKey"); - let i = zip32::ChildIndex::from_index(i); - - let xfvk = match xfvk_parent.derive_child(i) { - Ok(xfvk) => xfvk, - Err(_) => return false, - }; - - xfvk.write(&mut (unsafe { &mut *xfvk_i })[..]) - .expect("should be able to serialize an ExtendedFullViewingKey"); - - true -} - -#[no_mangle] -pub extern "system" fn librustzcash_zip32_xfvk_address( - xfvk: *const [c_uchar; 169], - j: *const [c_uchar; 11], - j_ret: *mut [c_uchar; 11], - addr_ret: *mut [c_uchar; 43], -) -> bool { - let xfvk = zip32::ExtendedFullViewingKey::read(&unsafe { *xfvk }[..]) - .expect("valid ExtendedFullViewingKey"); - let j = zip32::DiversifierIndex(unsafe { *j }); - - let addr = match xfvk.address(j) { - Ok(addr) => addr, - Err(_) => return false, - }; - - let j_ret = unsafe { &mut *j_ret }; - let addr_ret = unsafe { &mut *addr_ret }; - - j_ret.copy_from_slice(&(addr.0).0); - addr_ret - .get_mut(..11) - .unwrap() - .copy_from_slice(&addr.1.diversifier.0); - addr.1 - .pk_d - .write(addr_ret.get_mut(11..).unwrap()) - .expect("should be able to serialize a PaymentAddress"); - - true -} diff --git a/librustzcash/src/tests/key_agreement.rs b/librustzcash/src/tests/key_agreement.rs deleted file mode 100644 index 01657d1..0000000 --- a/librustzcash/src/tests/key_agreement.rs +++ /dev/null @@ -1,74 +0,0 @@ -use pairing::bls12_381::Bls12; -use pairing::{PrimeField, PrimeFieldRepr}; -use rand::{OsRng, Rng}; -use sapling_crypto::jubjub::{edwards, JubjubBls12}; -use sapling_crypto::primitives::{Diversifier, ViewingKey}; - -use { - librustzcash_sapling_generate_r, librustzcash_sapling_ka_agree, - librustzcash_sapling_ka_derivepublic, -}; - -#[test] -fn test_key_agreement() { - let params = JubjubBls12::new(); - let mut rng = OsRng::new().unwrap(); - - // Create random viewing key - let vk = ViewingKey:: { - ak: edwards::Point::rand(&mut rng, ¶ms).mul_by_cofactor(¶ms), - nk: edwards::Point::rand(&mut rng, ¶ms).mul_by_cofactor(¶ms), - }; - - // Create a random address with the viewing key - let addr = loop { - match vk.into_payment_address(Diversifier(rng.gen()), ¶ms) { - Some(a) => break a, - None => {} - } - }; - - // Grab ivk from our viewing key in serialized form - let ivk = vk.ivk(); - let mut ivk_serialized = [0u8; 32]; - ivk.into_repr().write_le(&mut ivk_serialized[..]).unwrap(); - - // Create random esk - let mut esk = [0u8; 32]; - librustzcash_sapling_generate_r(&mut esk); - - // The sender will create a shared secret with the recipient - // by multiplying the pk_d from their address with the esk - // we randomly generated - let mut shared_secret_sender = [0u8; 32]; - - // Serialize pk_d for the call to librustzcash_sapling_ka_agree - let mut addr_pk_d = [0u8; 32]; - addr.pk_d.write(&mut addr_pk_d[..]).unwrap(); - - assert!(librustzcash_sapling_ka_agree( - &addr_pk_d, - &esk, - &mut shared_secret_sender - )); - - // Create epk for the recipient, placed in the transaction. Computed - // using the diversifier and esk. - let mut epk = [0u8; 32]; - assert!(librustzcash_sapling_ka_derivepublic( - &addr.diversifier.0, - &esk, - &mut epk - )); - - // Create sharedSecret with ephemeral key - let mut shared_secret_recipient = [0u8; 32]; - assert!(librustzcash_sapling_ka_agree( - &epk, - &ivk_serialized, - &mut shared_secret_recipient - )); - - assert!(!shared_secret_sender.iter().all(|&v| v == 0)); - assert_eq!(shared_secret_sender, shared_secret_recipient); -} diff --git a/librustzcash/src/tests/key_components.rs b/librustzcash/src/tests/key_components.rs deleted file mode 100644 index d63c4d4..0000000 --- a/librustzcash/src/tests/key_components.rs +++ /dev/null @@ -1,666 +0,0 @@ -use pairing::{bls12_381::Bls12, PrimeField, PrimeFieldRepr}; -use sapling_crypto::{ - jubjub::{fs::FsRepr, FixedGenerators, JubjubEngine, JubjubParams}, - primitives::{Diversifier, ProofGenerationKey}, -}; - -use super::JUBJUB; - -use { - librustzcash_ask_to_ak, librustzcash_check_diversifier, librustzcash_crh_ivk, - librustzcash_ivk_to_pkd, librustzcash_nsk_to_nk, -}; - -#[test] -fn key_components() { - #![allow(dead_code)] - struct TestVector { - sk: [u8; 32], - ask: [u8; 32], - nsk: [u8; 32], - ovk: [u8; 32], - ak: [u8; 32], - nk: [u8; 32], - ivk: [u8; 32], - default_d: [u8; 11], - default_pk_d: [u8; 32], - note_v: u64, - note_r: [u8; 32], - note_cm: [u8; 32], - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_key_components.py - let test_vectors = vec![ - TestVector { - sk: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - ask: [ - 0x85, 0x48, 0xa1, 0x4a, 0x47, 0x3e, 0xa5, 0x47, 0xaa, 0x23, 0x78, 0x40, 0x20, 0x44, - 0xf8, 0x18, 0xcf, 0x19, 0x11, 0xcf, 0x5d, 0xd2, 0x05, 0x4f, 0x67, 0x83, 0x45, 0xf0, - 0x0d, 0x0e, 0x88, 0x06, - ], - nsk: [ - 0x30, 0x11, 0x4e, 0xa0, 0xdd, 0x0b, 0xb6, 0x1c, 0xf0, 0xea, 0xea, 0xb6, 0xec, 0x33, - 0x31, 0xf5, 0x81, 0xb0, 0x42, 0x5e, 0x27, 0x33, 0x85, 0x01, 0x26, 0x2d, 0x7e, 0xac, - 0x74, 0x5e, 0x6e, 0x05, - ], - ovk: [ - 0x98, 0xd1, 0x69, 0x13, 0xd9, 0x9b, 0x04, 0x17, 0x7c, 0xab, 0xa4, 0x4f, 0x6e, 0x4d, - 0x22, 0x4e, 0x03, 0xb5, 0xac, 0x03, 0x1d, 0x7c, 0xe4, 0x5e, 0x86, 0x51, 0x38, 0xe1, - 0xb9, 0x96, 0xd6, 0x3b, - ], - ak: [ - 0xf3, 0x44, 0xec, 0x38, 0x0f, 0xe1, 0x27, 0x3e, 0x30, 0x98, 0xc2, 0x58, 0x8c, 0x5d, - 0x3a, 0x79, 0x1f, 0xd7, 0xba, 0x95, 0x80, 0x32, 0x76, 0x07, 0x77, 0xfd, 0x0e, 0xfa, - 0x8e, 0xf1, 0x16, 0x20, - ], - nk: [ - 0xf7, 0xcf, 0x9e, 0x77, 0xf2, 0xe5, 0x86, 0x83, 0x38, 0x3c, 0x15, 0x19, 0xac, 0x7b, - 0x06, 0x2d, 0x30, 0x04, 0x0e, 0x27, 0xa7, 0x25, 0xfb, 0x88, 0xfb, 0x19, 0xa9, 0x78, - 0xbd, 0x3f, 0xd6, 0xba, - ], - ivk: [ - 0xb7, 0x0b, 0x7c, 0xd0, 0xed, 0x03, 0xcb, 0xdf, 0xd7, 0xad, 0xa9, 0x50, 0x2e, 0xe2, - 0x45, 0xb1, 0x3e, 0x56, 0x9d, 0x54, 0xa5, 0x71, 0x9d, 0x2d, 0xaa, 0x0f, 0x5f, 0x14, - 0x51, 0x47, 0x92, 0x04, - ], - default_d: [ - 0xf1, 0x9d, 0x9b, 0x79, 0x7e, 0x39, 0xf3, 0x37, 0x44, 0x58, 0x39, - ], - default_pk_d: [ - 0xdb, 0x4c, 0xd2, 0xb0, 0xaa, 0xc4, 0xf7, 0xeb, 0x8c, 0xa1, 0x31, 0xf1, 0x65, 0x67, - 0xc4, 0x45, 0xa9, 0x55, 0x51, 0x26, 0xd3, 0xc2, 0x9f, 0x14, 0xe3, 0xd7, 0x76, 0xe8, - 0x41, 0xae, 0x74, 0x15, - ], - note_v: 0, - note_r: [ - 0x39, 0x17, 0x6d, 0xac, 0x39, 0xac, 0xe4, 0x98, 0x0e, 0xcc, 0x8d, 0x77, 0x8e, 0x89, - 0x86, 0x02, 0x55, 0xec, 0x36, 0x15, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - note_cm: [ - 0xcb, 0x3c, 0xf9, 0x15, 0x32, 0x70, 0xd5, 0x7e, 0xb9, 0x14, 0xc6, 0xc2, 0xbc, 0xc0, - 0x18, 0x50, 0xc9, 0xfe, 0xd4, 0x4f, 0xce, 0x08, 0x06, 0x27, 0x8f, 0x08, 0x3e, 0xf2, - 0xdd, 0x07, 0x64, 0x39, - ], - }, - TestVector { - sk: [ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, - ], - ask: [ - 0xc9, 0x43, 0x56, 0x29, 0xbf, 0x8b, 0xff, 0xe5, 0x5e, 0x73, 0x35, 0xec, 0x07, 0x77, - 0x18, 0xba, 0x60, 0xba, 0x28, 0xd7, 0xac, 0x37, 0x94, 0xb7, 0x4f, 0x51, 0x2c, 0x31, - 0xaf, 0x0a, 0x53, 0x04, - ], - nsk: [ - 0x11, 0xac, 0xc2, 0xea, 0xd0, 0x7b, 0x5f, 0x00, 0x8c, 0x1f, 0x0f, 0x09, 0x0c, 0xc8, - 0xdd, 0xf3, 0x35, 0x23, 0x6f, 0xf4, 0xb2, 0x53, 0xc6, 0x49, 0x56, 0x95, 0xe9, 0xd6, - 0x39, 0xda, 0xcd, 0x08, - ], - ovk: [ - 0x3b, 0x94, 0x62, 0x10, 0xce, 0x6d, 0x1b, 0x16, 0x92, 0xd7, 0x39, 0x2a, 0xc8, 0x4a, - 0x8b, 0xc8, 0xf0, 0x3b, 0x72, 0x72, 0x3c, 0x7d, 0x36, 0x72, 0x1b, 0x80, 0x9a, 0x79, - 0xc9, 0xd6, 0xe4, 0x5b, - ], - ak: [ - 0x82, 0xff, 0x5e, 0xff, 0xc5, 0x27, 0xae, 0x84, 0x02, 0x0b, 0xf2, 0xd3, 0x52, 0x01, - 0xc1, 0x02, 0x19, 0x13, 0x19, 0x47, 0xff, 0x4b, 0x96, 0xf8, 0x81, 0xa4, 0x5f, 0x2e, - 0x8a, 0xe3, 0x05, 0x18, - ], - nk: [ - 0xc4, 0x53, 0x4d, 0x84, 0x8b, 0xb9, 0x18, 0xcf, 0x4a, 0x7f, 0x8b, 0x98, 0x74, 0x0a, - 0xb3, 0xcc, 0xee, 0x58, 0x67, 0x95, 0xff, 0x4d, 0xf6, 0x45, 0x47, 0xa8, 0x88, 0x8a, - 0x6c, 0x74, 0x15, 0xd2, - ], - ivk: [ - 0xc5, 0x18, 0x38, 0x44, 0x66, 0xb2, 0x69, 0x88, 0xb5, 0x10, 0x90, 0x67, 0x41, 0x8d, - 0x19, 0x2d, 0x9d, 0x6b, 0xd0, 0xd9, 0x23, 0x22, 0x05, 0xd7, 0x74, 0x18, 0xc2, 0x40, - 0xfc, 0x68, 0xa4, 0x06, - ], - default_d: [ - 0xae, 0xf1, 0x80, 0xf6, 0xe3, 0x4e, 0x35, 0x4b, 0x88, 0x8f, 0x81, - ], - default_pk_d: [ - 0xa6, 0xb1, 0x3e, 0xa3, 0x36, 0xdd, 0xb7, 0xa6, 0x7b, 0xb0, 0x9a, 0x0e, 0x68, 0xe9, - 0xd3, 0xcf, 0xb3, 0x92, 0x10, 0x83, 0x1e, 0xa3, 0xa2, 0x96, 0xba, 0x09, 0xa9, 0x22, - 0x06, 0x0f, 0xd3, 0x8b, - ], - note_v: 12227227834928555328, - note_r: [ - 0x47, 0x8b, 0xa0, 0xee, 0x6e, 0x1a, 0x75, 0xb6, 0x00, 0x03, 0x6f, 0x26, 0xf1, 0x8b, - 0x70, 0x15, 0xab, 0x55, 0x6b, 0xed, 0xdf, 0x8b, 0x96, 0x02, 0x38, 0x86, 0x9f, 0x89, - 0xdd, 0x80, 0x4e, 0x06, - ], - note_cm: [ - 0xb5, 0x78, 0x93, 0x50, 0x0b, 0xfb, 0x85, 0xdf, 0x2e, 0x8b, 0x01, 0xac, 0x45, 0x2f, - 0x89, 0xe1, 0x0e, 0x26, 0x6b, 0xcf, 0xa3, 0x1c, 0x31, 0xb2, 0x9a, 0x53, 0xae, 0x72, - 0xca, 0xd4, 0x69, 0x50, - ], - }, - TestVector { - sk: [ - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, - ], - ask: [ - 0xee, 0x1c, 0x3d, 0x7e, 0xfe, 0x0a, 0x78, 0x06, 0x3d, 0x6a, 0xf3, 0xd9, 0xd8, 0x12, - 0x12, 0xaf, 0x47, 0xb7, 0xc1, 0xb7, 0x61, 0xf8, 0x5c, 0xcb, 0x06, 0x6f, 0xc1, 0x1a, - 0x6a, 0x42, 0x17, 0x03, - ], - nsk: [ - 0x1d, 0x3b, 0x71, 0x37, 0x55, 0xd7, 0x48, 0x75, 0xe8, 0xea, 0x38, 0xfd, 0x16, 0x6e, - 0x76, 0xc6, 0x2a, 0x42, 0x50, 0x21, 0x6e, 0x6b, 0xbf, 0xe4, 0x8a, 0x5e, 0x2e, 0xab, - 0xad, 0x11, 0x7f, 0x0b, - ], - ovk: [ - 0x8b, 0xf4, 0x39, 0x0e, 0x28, 0xdd, 0xc9, 0x5b, 0x83, 0x02, 0xc3, 0x81, 0xd5, 0x81, - 0x0b, 0x84, 0xba, 0x8e, 0x60, 0x96, 0xe5, 0xa7, 0x68, 0x22, 0x77, 0x4f, 0xd4, 0x9f, - 0x49, 0x1e, 0x8f, 0x49, - ], - ak: [ - 0xab, 0x83, 0x57, 0x4e, 0xb5, 0xde, 0x85, 0x9a, 0x0a, 0xb8, 0x62, 0x9d, 0xec, 0x34, - 0xc7, 0xbe, 0xe8, 0xc3, 0xfc, 0x74, 0xdf, 0xa0, 0xb1, 0x9a, 0x3a, 0x74, 0x68, 0xd1, - 0x5d, 0xca, 0x64, 0xc6, - ], - nk: [ - 0x95, 0xd5, 0x80, 0x53, 0xe0, 0x59, 0x2e, 0x4a, 0x16, 0x9c, 0xc0, 0xb7, 0x92, 0x8a, - 0xaa, 0xc3, 0xde, 0x24, 0xef, 0x15, 0x31, 0xaa, 0x9e, 0xb6, 0xf4, 0xab, 0x93, 0x91, - 0x4d, 0xa8, 0xa0, 0x6e, - ], - ivk: [ - 0x47, 0x1c, 0x24, 0xa3, 0xdc, 0x87, 0x30, 0xe7, 0x50, 0x36, 0xc0, 0xa9, 0x5f, 0x3e, - 0x2f, 0x7d, 0xd1, 0xbe, 0x6f, 0xb9, 0x3a, 0xd2, 0x95, 0x92, 0x20, 0x3d, 0xef, 0x30, - 0x41, 0x95, 0x45, 0x05, - ], - default_d: [ - 0x75, 0x99, 0xf0, 0xbf, 0x9b, 0x57, 0xcd, 0x2d, 0xc2, 0x99, 0xb6, - ], - default_pk_d: [ - 0x66, 0x14, 0x17, 0x39, 0x51, 0x4b, 0x28, 0xf0, 0x5d, 0xef, 0x8a, 0x18, 0xee, 0xee, - 0x5e, 0xed, 0x4d, 0x44, 0xc6, 0x22, 0x5c, 0x3c, 0x65, 0xd8, 0x8d, 0xd9, 0x90, 0x77, - 0x08, 0x01, 0x2f, 0x5a, - ], - note_v: 6007711596147559040, - note_r: [ - 0x14, 0x7c, 0xf2, 0xb5, 0x1b, 0x4c, 0x7c, 0x63, 0xcb, 0x77, 0xb9, 0x9e, 0x8b, 0x78, - 0x3e, 0x5b, 0x51, 0x11, 0xdb, 0x0a, 0x7c, 0xa0, 0x4d, 0x6c, 0x01, 0x4a, 0x1d, 0x7d, - 0xa8, 0x3b, 0xae, 0x0a, - ], - note_cm: [ - 0xdb, 0x85, 0xa7, 0x0a, 0x98, 0x43, 0x7f, 0x73, 0x16, 0x7f, 0xc3, 0x32, 0xd5, 0xb7, - 0xb7, 0x40, 0x82, 0x96, 0x66, 0x17, 0x70, 0xb1, 0x01, 0xb0, 0xaa, 0x87, 0x83, 0x9f, - 0x4e, 0x55, 0xf1, 0x51, - ], - }, - TestVector { - sk: [ - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, - ], - ask: [ - 0x00, 0xc3, 0xa1, 0xe1, 0xca, 0x8f, 0x4e, 0x04, 0x80, 0xee, 0x1e, 0xe9, 0x0c, 0xa7, - 0x51, 0x78, 0x79, 0xd3, 0xfc, 0x5c, 0x81, 0x5c, 0x09, 0x03, 0xe5, 0xee, 0xbc, 0x94, - 0xbb, 0x80, 0x95, 0x03, - ], - nsk: [ - 0xe6, 0x62, 0x85, 0xa5, 0xe9, 0xb6, 0x5e, 0x15, 0x7a, 0xd2, 0xfc, 0xd5, 0x43, 0xda, - 0xd9, 0x8c, 0x67, 0xa5, 0x8a, 0xbd, 0xf2, 0x87, 0xe0, 0x55, 0x06, 0xbd, 0x1c, 0x2e, - 0x59, 0xb0, 0x72, 0x0b, - ], - ovk: [ - 0x14, 0x76, 0x78, 0xe0, 0x55, 0x3b, 0x97, 0x82, 0x93, 0x47, 0x64, 0x7c, 0x5b, 0xc7, - 0xda, 0xb4, 0xcc, 0x22, 0x02, 0xb5, 0x4e, 0xc2, 0x9f, 0xd3, 0x1a, 0x3d, 0xe6, 0xbe, - 0x08, 0x25, 0xfc, 0x5e, - ], - ak: [ - 0x3c, 0x9c, 0xde, 0x7e, 0x5d, 0x0d, 0x38, 0xa8, 0x61, 0x0f, 0xaa, 0xdb, 0xcf, 0x4c, - 0x34, 0x3f, 0x5d, 0x3c, 0xfa, 0x31, 0x55, 0xa5, 0xb9, 0x46, 0x61, 0xa6, 0x75, 0x3e, - 0x96, 0xe8, 0x84, 0xea, - ], - nk: [ - 0xb7, 0x7d, 0x36, 0xf5, 0x08, 0x94, 0x1d, 0xbd, 0x61, 0xcf, 0xd0, 0xf1, 0x59, 0xee, - 0x05, 0xcf, 0xaa, 0x78, 0xa2, 0x6c, 0x94, 0x92, 0x90, 0x38, 0x06, 0xd8, 0x3b, 0x59, - 0x8d, 0x3c, 0x1c, 0x2a, - ], - ivk: [ - 0x63, 0x6a, 0xa9, 0x64, 0xbf, 0xc2, 0x3c, 0xe4, 0xb1, 0xfc, 0xf7, 0xdf, 0xc9, 0x91, - 0x79, 0xdd, 0xc4, 0x06, 0xff, 0x55, 0x40, 0x0c, 0x92, 0x95, 0xac, 0xfc, 0x14, 0xf0, - 0x31, 0xc7, 0x26, 0x00, - ], - default_d: [ - 0x1b, 0x81, 0x61, 0x4f, 0x1d, 0xad, 0xea, 0x0f, 0x8d, 0x0a, 0x58, - ], - default_pk_d: [ - 0x25, 0xeb, 0x55, 0xfc, 0xcf, 0x76, 0x1f, 0xc6, 0x4e, 0x85, 0xa5, 0x88, 0xef, 0xe6, - 0xea, 0xd7, 0x83, 0x2f, 0xb1, 0xf0, 0xf7, 0xa8, 0x31, 0x65, 0x89, 0x5b, 0xdf, 0xf9, - 0x42, 0x92, 0x5f, 0x5c, - ], - note_v: 18234939431076114368, - note_r: [ - 0x34, 0xa4, 0xb2, 0xa9, 0x14, 0x4f, 0xf5, 0xea, 0x54, 0xef, 0xee, 0x87, 0xcf, 0x90, - 0x1b, 0x5b, 0xed, 0x5e, 0x35, 0xd2, 0x1f, 0xbb, 0xd7, 0x88, 0xd5, 0xbd, 0x9d, 0x83, - 0x3e, 0x11, 0x28, 0x04, - ], - note_cm: [ - 0xe0, 0x8c, 0xe4, 0x82, 0xb3, 0xa8, 0xfb, 0x3b, 0x35, 0xcc, 0xdb, 0xe3, 0x43, 0x37, - 0xbd, 0x10, 0x5d, 0x88, 0x39, 0x21, 0x2e, 0x0d, 0x16, 0x44, 0xb9, 0xd5, 0x5c, 0xaa, - 0x60, 0xd1, 0x9b, 0x6c, - ], - }, - TestVector { - sk: [ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, - ], - ask: [ - 0x82, 0x36, 0xd1, 0x9d, 0x32, 0x05, 0xd8, 0x55, 0x43, 0xa0, 0x68, 0x11, 0x34, 0x3f, - 0x82, 0x7b, 0x65, 0x63, 0x77, 0x0a, 0x49, 0xaa, 0x4d, 0x0c, 0xa0, 0x08, 0x18, 0x05, - 0xd4, 0xc8, 0xea, 0x0d, - ], - nsk: [ - 0x7e, 0xc1, 0xef, 0x0b, 0xed, 0x82, 0x71, 0x82, 0x72, 0xf0, 0xf4, 0x4f, 0x01, 0x7c, - 0x48, 0x41, 0x74, 0x51, 0x3d, 0x66, 0x1d, 0xd1, 0x68, 0xaf, 0x02, 0xd2, 0x09, 0x2a, - 0x1d, 0x8a, 0x05, 0x07, - ], - ovk: [ - 0x1b, 0x6e, 0x75, 0xec, 0xe3, 0xac, 0xe8, 0xdb, 0xa6, 0xa5, 0x41, 0x0d, 0x9a, 0xd4, - 0x75, 0x56, 0x68, 0xe4, 0xb3, 0x95, 0x85, 0xd6, 0x35, 0xec, 0x1d, 0xa7, 0xc8, 0xdc, - 0xfd, 0x5f, 0xc4, 0xed, - ], - ak: [ - 0x55, 0xe8, 0x83, 0x89, 0xbb, 0x7e, 0x41, 0xde, 0x13, 0x0c, 0xfa, 0x51, 0xa8, 0x71, - 0x5f, 0xde, 0x01, 0xff, 0x9c, 0x68, 0x76, 0x64, 0x7f, 0x01, 0x75, 0xad, 0x34, 0xf0, - 0x58, 0xdd, 0xe0, 0x1a, - ], - nk: [ - 0x72, 0x5d, 0x4a, 0xd6, 0xa1, 0x50, 0x21, 0xcd, 0x1c, 0x48, 0xc5, 0xee, 0x19, 0xde, - 0x6c, 0x1e, 0x76, 0x8a, 0x2c, 0xc0, 0xa9, 0xa7, 0x30, 0xa0, 0x1b, 0xb2, 0x1c, 0x95, - 0xe3, 0xd9, 0xe4, 0x3c, - ], - ivk: [ - 0x67, 0xfa, 0x2b, 0xf7, 0xc6, 0x7d, 0x46, 0x58, 0x24, 0x3c, 0x31, 0x7c, 0x0c, 0xb4, - 0x1f, 0xd3, 0x20, 0x64, 0xdf, 0xd3, 0x70, 0x9f, 0xe0, 0xdc, 0xb7, 0x24, 0xf1, 0x4b, - 0xb0, 0x1a, 0x1d, 0x04, - ], - default_d: [ - 0xfc, 0xfb, 0x68, 0xa4, 0x0d, 0x4b, 0xc6, 0xa0, 0x4b, 0x09, 0xc4, - ], - default_pk_d: [ - 0x8b, 0x2a, 0x33, 0x7f, 0x03, 0x62, 0x2c, 0x24, 0xff, 0x38, 0x1d, 0x4c, 0x54, 0x6f, - 0x69, 0x77, 0xf9, 0x05, 0x22, 0xe9, 0x2f, 0xde, 0x44, 0xc9, 0xd1, 0xbb, 0x09, 0x97, - 0x14, 0xb9, 0xdb, 0x2b, - ], - note_v: 12015423192295118080, - note_r: [ - 0xe5, 0x57, 0x85, 0x13, 0x55, 0x74, 0x7c, 0x09, 0xac, 0x59, 0x01, 0x3c, 0xbd, 0xe8, - 0x59, 0x80, 0x96, 0x4e, 0xc1, 0x84, 0x4d, 0x9c, 0x69, 0x67, 0xca, 0x0c, 0x02, 0x9c, - 0x84, 0x57, 0xbb, 0x04, - ], - note_cm: [ - 0xbd, 0xc8, 0x54, 0xbf, 0x3e, 0x7b, 0x00, 0x82, 0x1f, 0x3b, 0x8b, 0x85, 0x23, 0x8c, - 0xcf, 0x1e, 0x67, 0x15, 0xbf, 0xe7, 0x0b, 0x63, 0x2d, 0x04, 0x4b, 0x26, 0xfb, 0x2b, - 0xc7, 0x1b, 0x7f, 0x36, - ], - }, - TestVector { - sk: [ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, - ], - ask: [ - 0xea, 0xe6, 0x88, 0x4d, 0x76, 0x4a, 0x05, 0x40, 0x61, 0xa8, 0xf1, 0xc0, 0x07, 0x6c, - 0x62, 0x4d, 0xcb, 0x73, 0x87, 0x89, 0xf7, 0xad, 0x1e, 0x74, 0x08, 0xe3, 0x1f, 0x24, - 0xdf, 0xc8, 0x26, 0x07, - ], - nsk: [ - 0xfb, 0xe6, 0x10, 0xf4, 0x2a, 0x41, 0x74, 0x9f, 0x9b, 0x6e, 0x6e, 0x4a, 0x54, 0xb5, - 0xa3, 0x2e, 0xbf, 0xe8, 0xf4, 0x38, 0x00, 0x88, 0x1b, 0xa6, 0xcd, 0x13, 0xed, 0x0b, - 0x05, 0x29, 0x46, 0x01, - ], - ovk: [ - 0xc6, 0xbc, 0x1f, 0x39, 0xf0, 0xd7, 0x86, 0x31, 0x4c, 0xb2, 0x0b, 0xf9, 0xab, 0x22, - 0x85, 0x40, 0x91, 0x35, 0x55, 0xf9, 0x70, 0x69, 0x6b, 0x6d, 0x7c, 0x77, 0xbb, 0x33, - 0x23, 0x28, 0x37, 0x2a, - ], - ak: [ - 0xe6, 0x82, 0x76, 0x59, 0x14, 0xe3, 0x86, 0x4c, 0x33, 0x9e, 0x57, 0x82, 0xb8, 0x55, - 0xc0, 0xfd, 0xf4, 0x0e, 0x0d, 0xfc, 0xed, 0xb9, 0xe7, 0xb4, 0x7b, 0xc9, 0x4b, 0x90, - 0xb3, 0xa4, 0xc9, 0x88, - ], - nk: [ - 0x82, 0x25, 0x6b, 0x95, 0x62, 0x3c, 0x67, 0x02, 0x4b, 0x44, 0x24, 0xd9, 0x14, 0x00, - 0xa3, 0x70, 0xe7, 0xac, 0x8e, 0x4d, 0x15, 0x48, 0x2a, 0x37, 0x59, 0xe0, 0x0d, 0x21, - 0x97, 0x49, 0xda, 0xee, - ], - ivk: [ - 0xea, 0x3f, 0x1d, 0x80, 0xe4, 0x30, 0x7c, 0xa7, 0x3b, 0x9f, 0x37, 0x80, 0x1f, 0x91, - 0xfb, 0xa8, 0x10, 0xcc, 0x41, 0xd2, 0x79, 0xfc, 0x29, 0xf5, 0x64, 0x23, 0x56, 0x54, - 0xa2, 0x17, 0x8e, 0x03, - ], - default_d: [ - 0xeb, 0x51, 0x98, 0x82, 0xad, 0x1e, 0x5c, 0xc6, 0x54, 0xcd, 0x59, - ], - default_pk_d: [ - 0x6b, 0x27, 0xda, 0xcc, 0xb5, 0xa8, 0x20, 0x7f, 0x53, 0x2d, 0x10, 0xca, 0x23, 0x8f, - 0x97, 0x86, 0x64, 0x8a, 0x11, 0xb5, 0x96, 0x6e, 0x51, 0xa2, 0xf7, 0xd8, 0x9e, 0x15, - 0xd2, 0x9b, 0x8f, 0xdf, - ], - note_v: 5795906953514121792, - note_r: [ - 0x68, 0xf0, 0x61, 0x04, 0x60, 0x6b, 0x0c, 0x54, 0x49, 0x84, 0x5f, 0xf4, 0xc6, 0x5f, - 0x73, 0xe9, 0x0f, 0x45, 0xef, 0x5a, 0x43, 0xc9, 0xd7, 0x4c, 0xb2, 0xc8, 0x5c, 0xf5, - 0x6c, 0x94, 0xc0, 0x02, - ], - note_cm: [ - 0xe8, 0x26, 0x7d, 0x30, 0xac, 0x11, 0xc1, 0x00, 0xbc, 0x7a, 0x0f, 0xdf, 0x91, 0xf7, - 0x1d, 0x74, 0xc5, 0xbc, 0xf2, 0xe1, 0xef, 0x95, 0x66, 0x90, 0x44, 0x73, 0x01, 0x69, - 0xde, 0x1a, 0x5b, 0x4c, - ], - }, - TestVector { - sk: [ - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, - ], - ask: [ - 0xe8, 0xf8, 0x16, 0xb4, 0xbc, 0x08, 0xa7, 0xe5, 0x66, 0x75, 0x0c, 0xc2, 0x8a, 0xfe, - 0x82, 0xa4, 0xce, 0xa9, 0xc2, 0xbe, 0xf2, 0x44, 0xfa, 0x4b, 0x13, 0xc4, 0x73, 0x9b, - 0x28, 0x07, 0x4c, 0x0d, - ], - nsk: [ - 0x32, 0x61, 0x5b, 0x13, 0x7f, 0x28, 0x01, 0xed, 0x44, 0x6e, 0x48, 0x78, 0x1a, 0xb0, - 0x63, 0x45, 0x72, 0xe1, 0x8c, 0xfb, 0x06, 0x93, 0x72, 0x1b, 0x88, 0x03, 0xc0, 0x5b, - 0x82, 0x27, 0xd1, 0x07, - ], - ovk: [ - 0xf6, 0x2c, 0x05, 0xe8, 0x48, 0xa8, 0x73, 0xef, 0x88, 0x5e, 0x12, 0xb0, 0x8c, 0x5e, - 0x7c, 0xa2, 0xf3, 0x24, 0x24, 0xba, 0xcc, 0x75, 0x4c, 0xb6, 0x97, 0x50, 0x44, 0x4d, - 0x35, 0x5f, 0x51, 0x06, - ], - ak: [ - 0xff, 0x27, 0xdb, 0x07, 0x51, 0x94, 0x5d, 0x3e, 0xe4, 0xbe, 0x9c, 0xf1, 0x5c, 0x2e, - 0xa2, 0x11, 0xb2, 0x4b, 0x16, 0x4d, 0x5f, 0x2d, 0x7d, 0xdf, 0xf5, 0xe4, 0xa0, 0x70, - 0x8f, 0x10, 0xb9, 0x5e, - ], - nk: [ - 0x94, 0x38, 0x85, 0x95, 0x9d, 0x4e, 0xf8, 0xa9, 0xcf, 0xca, 0x07, 0xc4, 0x57, 0xf0, - 0x9e, 0xc7, 0x4b, 0x96, 0xf9, 0x93, 0xd8, 0xe0, 0xfa, 0x32, 0xb1, 0x9c, 0x03, 0xe3, - 0xb0, 0x7a, 0x42, 0x0f, - ], - ivk: [ - 0xb5, 0xc5, 0x89, 0x49, 0x43, 0x95, 0x69, 0x33, 0xc0, 0xe5, 0xc1, 0x2d, 0x31, 0x1f, - 0xc1, 0x2c, 0xba, 0x58, 0x35, 0x4b, 0x5c, 0x38, 0x9e, 0xdc, 0x03, 0xda, 0x55, 0x08, - 0x4f, 0x74, 0xc2, 0x05, - ], - default_d: [ - 0xbe, 0xbb, 0x0f, 0xb4, 0x6b, 0x8a, 0xaf, 0xf8, 0x90, 0x40, 0xf6, - ], - default_pk_d: [ - 0xd1, 0x1d, 0xa0, 0x1f, 0x0b, 0x43, 0xbd, 0xd5, 0x28, 0x8d, 0x32, 0x38, 0x5b, 0x87, - 0x71, 0xd2, 0x23, 0x49, 0x3c, 0x69, 0x80, 0x25, 0x44, 0x04, 0x3f, 0x77, 0xcf, 0x1d, - 0x71, 0xc1, 0xcb, 0x8c, - ], - note_v: 18023134788442677120, - note_r: [ - 0x49, 0xf9, 0x0b, 0x47, 0xfd, 0x52, 0xfe, 0xe7, 0xc1, 0xc8, 0x1f, 0x0d, 0xcb, 0x5b, - 0x74, 0xc3, 0xfb, 0x9b, 0x3e, 0x03, 0x97, 0x6f, 0x8b, 0x75, 0x24, 0xea, 0xba, 0xd0, - 0x08, 0x89, 0x21, 0x07, - ], - note_cm: [ - 0x57, 0x2b, 0xa2, 0x05, 0x25, 0xb0, 0xac, 0x4d, 0x6d, 0xc0, 0x1a, 0xc2, 0xea, 0x10, - 0x90, 0xb6, 0xe0, 0xf2, 0xf4, 0xbf, 0x4e, 0xc4, 0xa0, 0xdb, 0x5b, 0xbc, 0xcb, 0x5b, - 0x78, 0x3a, 0x1e, 0x55, - ], - }, - TestVector { - sk: [ - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, - ], - ask: [ - 0x74, 0xb4, 0x4a, 0x37, 0xf1, 0x50, 0x23, 0xc0, 0x60, 0x42, 0x7e, 0x1d, 0xae, 0xa3, - 0xf6, 0x43, 0x12, 0xdd, 0x8f, 0xeb, 0x7b, 0x2c, 0xed, 0xf0, 0xdd, 0x55, 0x44, 0x49, - 0x3f, 0x87, 0x2c, 0x06, - ], - nsk: [ - 0x07, 0x5c, 0x35, 0xdb, 0x8b, 0x1b, 0x25, 0x75, 0x42, 0x23, 0xec, 0xee, 0x34, 0xab, - 0x73, 0x0d, 0xdd, 0xd1, 0xf1, 0x4a, 0x6a, 0x54, 0xf4, 0xc6, 0xf4, 0x68, 0x45, 0x3c, - 0x3c, 0x6e, 0xd6, 0x0b, - ], - ovk: [ - 0xe9, 0xe0, 0xdc, 0x1e, 0xd3, 0x11, 0xda, 0xed, 0x64, 0xbd, 0x74, 0xda, 0x5d, 0x94, - 0xfe, 0x88, 0xa6, 0xea, 0x41, 0x4b, 0x73, 0x12, 0xde, 0x3d, 0x2a, 0x78, 0xf6, 0x46, - 0x32, 0xbb, 0xe3, 0x73, - ], - ak: [ - 0x28, 0x3f, 0x9a, 0xaf, 0xa9, 0xbc, 0xb3, 0xe6, 0xce, 0x17, 0xe6, 0x32, 0x12, 0x63, - 0x4c, 0xb3, 0xee, 0x55, 0x0c, 0x47, 0x6b, 0x67, 0x6b, 0xd3, 0x56, 0xa6, 0xdf, 0x8a, - 0xdf, 0x51, 0xd2, 0x5e, - ], - nk: [ - 0xdc, 0x4c, 0x67, 0xb1, 0x0d, 0x4b, 0x0a, 0x21, 0x8d, 0xc6, 0xe1, 0x48, 0x70, 0x66, - 0x74, 0x0a, 0x40, 0x93, 0x17, 0x86, 0x6c, 0x32, 0xe6, 0x64, 0xb5, 0x0e, 0x39, 0x7a, - 0xa8, 0x03, 0x89, 0xd4, - ], - ivk: [ - 0x87, 0x16, 0xc8, 0x28, 0x80, 0xe1, 0x36, 0x83, 0xe1, 0xbb, 0x05, 0x9d, 0xd0, 0x6c, - 0x80, 0xc9, 0x01, 0x34, 0xa9, 0x6d, 0x5a, 0xfc, 0xa8, 0xaa, 0xc2, 0xbb, 0xf6, 0x8b, - 0xb0, 0x5f, 0x84, 0x02, - ], - default_d: [ - 0xad, 0x6e, 0x2e, 0x18, 0x5a, 0x31, 0x00, 0xe3, 0xa6, 0xa8, 0xb3, - ], - default_pk_d: [ - 0x32, 0xcb, 0x28, 0x06, 0xb8, 0x82, 0xf1, 0x36, 0x8b, 0x0d, 0x4a, 0x89, 0x8f, 0x72, - 0xc4, 0xc8, 0xf7, 0x28, 0x13, 0x2c, 0xc1, 0x24, 0x56, 0x94, 0x6e, 0x7f, 0x4c, 0xb0, - 0xfb, 0x05, 0x8d, 0xa9, - ], - note_v: 11803618549661680832, - note_r: [ - 0x51, 0x65, 0xaf, 0xf2, 0x2d, 0xd4, 0xed, 0x56, 0xb4, 0xd8, 0x1d, 0x1f, 0x17, 0x1c, - 0xc3, 0xd6, 0x43, 0x2f, 0xed, 0x1b, 0xeb, 0xf2, 0x0a, 0x7b, 0xea, 0xb1, 0x2d, 0xb1, - 0x42, 0xf9, 0x4a, 0x0c, - ], - note_cm: [ - 0xab, 0x7f, 0xc5, 0x66, 0x87, 0x3c, 0xcd, 0xe6, 0x71, 0xf5, 0x98, 0x27, 0x67, 0x85, - 0x60, 0xa0, 0x06, 0xf8, 0x2b, 0xb7, 0xad, 0xcd, 0x75, 0x22, 0x3f, 0xa8, 0x59, 0x36, - 0xf7, 0x8c, 0x2b, 0x23, - ], - }, - TestVector { - sk: [ - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, - ], - ask: [ - 0x03, 0x9d, 0xd9, 0x3d, 0xf3, 0x11, 0xff, 0x8f, 0xba, 0xb3, 0xfe, 0x23, 0x02, 0x19, - 0xcd, 0x42, 0xac, 0x87, 0x94, 0x84, 0xf3, 0x0b, 0x90, 0x3a, 0x3c, 0x1e, 0x67, 0xcc, - 0xca, 0x5a, 0x7b, 0x0d, - ], - nsk: [ - 0x04, 0x9f, 0xa1, 0x4f, 0x48, 0x6c, 0x75, 0xb9, 0xfa, 0xd7, 0xe3, 0xb6, 0x73, 0xa4, - 0x43, 0xdd, 0x07, 0x4e, 0xaa, 0x96, 0xed, 0xcb, 0x2a, 0x53, 0xea, 0xaa, 0xbd, 0xaf, - 0x70, 0xff, 0xbb, 0x08, - ], - ovk: [ - 0x14, 0x7d, 0xd1, 0x1d, 0x77, 0xeb, 0xa1, 0xb1, 0x63, 0x6f, 0xd6, 0x19, 0x0c, 0x62, - 0xb9, 0xa5, 0xd0, 0x48, 0x1b, 0xee, 0x7e, 0x91, 0x7f, 0xab, 0x02, 0xe2, 0x18, 0x58, - 0x06, 0x3a, 0xb5, 0x04, - ], - ak: [ - 0x36, 0x40, 0x48, 0xee, 0xdb, 0xe8, 0xca, 0x20, 0x5e, 0xb7, 0xe7, 0xba, 0x0a, 0x90, - 0x12, 0x16, 0x6c, 0x7c, 0x7b, 0xd9, 0xeb, 0x22, 0x8e, 0x08, 0x48, 0x14, 0x48, 0xc4, - 0x88, 0xaa, 0x21, 0xd2, - ], - nk: [ - 0xed, 0x60, 0xaf, 0x1c, 0xe7, 0xdf, 0x38, 0x07, 0x0d, 0x38, 0x51, 0x43, 0x2a, 0x96, - 0x48, 0x0d, 0xb0, 0xb4, 0x17, 0xc3, 0x68, 0x2a, 0x1d, 0x68, 0xe3, 0xe8, 0x93, 0x34, - 0x23, 0x5c, 0x0b, 0xdf, - ], - ivk: [ - 0x99, 0xc9, 0xb4, 0xb8, 0x4f, 0x4b, 0x4e, 0x35, 0x0f, 0x78, 0x7d, 0x1c, 0xf7, 0x05, - 0x1d, 0x50, 0xec, 0xc3, 0x4b, 0x1a, 0x5b, 0x20, 0xd2, 0xd2, 0x13, 0x9b, 0x4a, 0xf1, - 0xf1, 0x60, 0xe0, 0x01, - ], - default_d: [ - 0x21, 0xc9, 0x0e, 0x1c, 0x65, 0x8b, 0x3e, 0xfe, 0x86, 0xaf, 0x58, - ], - default_pk_d: [ - 0x9e, 0x64, 0x17, 0x4b, 0x4a, 0xb9, 0x81, 0x40, 0x5c, 0x32, 0x3b, 0x5e, 0x12, 0x47, - 0x59, 0x45, 0xa4, 0x6d, 0x4f, 0xed, 0xf8, 0x06, 0x08, 0x28, 0x04, 0x1c, 0xd2, 0x0e, - 0x62, 0xfd, 0x2c, 0xef, - ], - note_v: 5584102310880684544, - note_r: [ - 0x8c, 0x3e, 0x56, 0x44, 0x9d, 0xc8, 0x63, 0x54, 0xd3, 0x3b, 0x02, 0x5e, 0xf2, 0x79, - 0x34, 0x60, 0xbc, 0xb1, 0x69, 0xf3, 0x32, 0x4e, 0x4a, 0x6b, 0x64, 0xba, 0xa6, 0x08, - 0x32, 0x31, 0x57, 0x04, - ], - note_cm: [ - 0x7b, 0x48, 0xa8, 0x37, 0x5d, 0x3e, 0xbd, 0x56, 0xbc, 0x64, 0x9b, 0xb5, 0xb5, 0x24, - 0x23, 0x36, 0xc2, 0xa0, 0x5a, 0x08, 0x03, 0x23, 0x9b, 0x5b, 0x88, 0xfd, 0x92, 0x07, - 0x8f, 0xea, 0x4d, 0x04, - ], - }, - TestVector { - sk: [ - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, - ], - ask: [ - 0xeb, 0xbb, 0x40, 0xa9, 0x80, 0xba, 0x3b, 0x88, 0x60, 0x94, 0x8d, 0x01, 0x1e, 0x1b, - 0xfb, 0x4a, 0xff, 0xe1, 0x6c, 0x65, 0x2e, 0x90, 0xe9, 0x82, 0x58, 0x30, 0x2f, 0x44, - 0x64, 0xc9, 0x1e, 0x0c, - ], - nsk: [ - 0x68, 0x43, 0x1b, 0x19, 0x91, 0x04, 0x21, 0x52, 0x00, 0xb9, 0x5e, 0xe5, 0xcb, 0x71, - 0xbf, 0x8b, 0x88, 0x3a, 0x3e, 0x95, 0xb7, 0x98, 0x9c, 0xad, 0x19, 0x70, 0x63, 0x14, - 0x1e, 0xbb, 0xfd, 0x00, - ], - ovk: [ - 0x57, 0x34, 0x67, 0xa7, 0xb3, 0x0e, 0xad, 0x6c, 0xcc, 0x50, 0x47, 0x44, 0xca, 0x9e, - 0x1a, 0x28, 0x1a, 0x0d, 0x1a, 0x08, 0x73, 0x8b, 0x06, 0xa0, 0x68, 0x4f, 0xea, 0xcd, - 0x1e, 0x9d, 0x12, 0x6d, - ], - ak: [ - 0x71, 0xc3, 0x52, 0x3e, 0xec, 0xa3, 0x53, 0x11, 0xfb, 0xd5, 0xd7, 0xe7, 0xd7, 0x0b, - 0x70, 0x9d, 0x6c, 0x35, 0xa2, 0x4f, 0x26, 0x2b, 0x34, 0xbf, 0x64, 0x05, 0x9b, 0xf2, - 0xc0, 0x2e, 0x0b, 0xa8, - ], - nk: [ - 0x62, 0x44, 0x00, 0x10, 0x3b, 0x65, 0x69, 0xb7, 0x35, 0x8f, 0xe8, 0x0f, 0x6f, 0x6c, - 0xad, 0x43, 0x25, 0xde, 0xfd, 0xa9, 0xd9, 0x49, 0x9c, 0x2b, 0x8f, 0x88, 0x6a, 0x62, - 0x69, 0xa2, 0xaa, 0x52, - ], - ivk: [ - 0xdb, 0x95, 0xea, 0x8b, 0xd9, 0xf9, 0x3d, 0x41, 0xb5, 0xab, 0x2b, 0xeb, 0xc9, 0x1a, - 0x38, 0xed, 0xd5, 0x27, 0x08, 0x3e, 0x2a, 0x6e, 0xf9, 0xf3, 0xc2, 0x97, 0x02, 0xd5, - 0xff, 0x89, 0xed, 0x00, - ], - default_d: [ - 0x23, 0x3c, 0x4a, 0xb8, 0x86, 0xa5, 0x5e, 0x3b, 0xa3, 0x74, 0xc0, - ], - default_pk_d: [ - 0xb6, 0x8e, 0x9e, 0xe0, 0xc0, 0x67, 0x8d, 0x7b, 0x30, 0x36, 0x93, 0x1c, 0x83, 0x1a, - 0x25, 0x25, 0x5f, 0x7e, 0xe4, 0x87, 0x38, 0x5a, 0x30, 0x31, 0x6e, 0x15, 0xf6, 0x48, - 0x2b, 0x87, 0x4f, 0xda, - ], - note_v: 17811330145809239872, - note_r: [ - 0x6e, 0xbb, 0xed, 0x74, 0x36, 0x19, 0xa2, 0x56, 0xf9, 0xad, 0x2e, 0x85, 0x88, 0x0c, - 0xfa, 0xa9, 0x09, 0x8a, 0x5f, 0xdb, 0x16, 0x29, 0x99, 0x0d, 0x9a, 0x7d, 0x3b, 0xb9, - 0x3f, 0xc9, 0x00, 0x03, - ], - note_cm: [ - 0xd3, 0x76, 0xa7, 0xbe, 0xe8, 0xce, 0x67, 0xf4, 0xef, 0xde, 0x56, 0xaa, 0x77, 0xcf, - 0x64, 0x41, 0x9b, 0x0e, 0x55, 0x0a, 0xbb, 0xcb, 0x8e, 0x2b, 0xcb, 0xda, 0x8b, 0x63, - 0xe4, 0x1d, 0xeb, 0x37, - ], - }, - ]; - - for tv in test_vectors { - let mut ask_repr = FsRepr::default(); - let mut nsk_repr = FsRepr::default(); - ask_repr.read_le(&tv.ask[..]).unwrap(); - nsk_repr.read_le(&tv.nsk[..]).unwrap(); - let nsk = ::Fs::from_repr(nsk_repr).unwrap(); - - let ak = JUBJUB - .generator(FixedGenerators::SpendingKeyGenerator) - .mul(ask_repr.clone(), &JUBJUB); - { - let mut vec = Vec::new(); - ak.write(&mut vec).unwrap(); - assert_eq!(&vec, &tv.ak); - } - { - let mut ak = [0u8; 32]; - librustzcash_ask_to_ak(&tv.ask, &mut ak); - assert_eq!(&ak, &tv.ak); - } - - let pgk = ProofGenerationKey { ak, nsk }; - let fvk = pgk.into_viewing_key(&JUBJUB); - { - let mut vec = Vec::new(); - fvk.nk.write(&mut vec).unwrap(); - assert_eq!(&vec, &tv.nk); - } - { - let mut nk = [0u8; 32]; - librustzcash_nsk_to_nk(&tv.nsk, &mut nk); - assert_eq!(&nk, &tv.nk); - } - - { - let mut vec = Vec::new(); - fvk.ivk().into_repr().write_le(&mut vec).unwrap(); - assert_eq!(&vec, &tv.ivk); - } - { - let mut ivk = [0u8; 32]; - librustzcash_crh_ivk(&tv.ak, &tv.nk, &mut ivk); - assert_eq!(&ivk, &tv.ivk); - } - - let diversifier = Diversifier(tv.default_d); - assert!(librustzcash_check_diversifier(&tv.default_d)); - - let addr = fvk.into_payment_address(diversifier, &JUBJUB).unwrap(); - { - let mut vec = Vec::new(); - addr.pk_d.write(&mut vec).unwrap(); - assert_eq!(&vec, &tv.default_pk_d); - } - { - let mut default_pk_d = [0u8; 32]; - librustzcash_ivk_to_pkd(&tv.ivk, &tv.default_d, &mut default_pk_d); - assert_eq!(&default_pk_d, &tv.default_pk_d); - } - - let mut note_r_repr = FsRepr::default(); - note_r_repr.read_le(&tv.note_r[..]).unwrap(); - let note_r = ::Fs::from_repr(note_r_repr).unwrap(); - let note = addr.create_note(tv.note_v, note_r, &JUBJUB).unwrap(); - { - let mut vec = Vec::new(); - note.cm(&JUBJUB).into_repr().write_le(&mut vec).unwrap(); - assert_eq!(&vec, &tv.note_cm); - } - } -} diff --git a/librustzcash/src/tests/mod.rs b/librustzcash/src/tests/mod.rs deleted file mode 100644 index a8cdcb7..0000000 --- a/librustzcash/src/tests/mod.rs +++ /dev/null @@ -1,96 +0,0 @@ -use sapling_crypto::jubjub::{FixedGenerators, JubjubParams}; - -use super::JUBJUB; - -mod key_agreement; -mod key_components; -mod notes; -mod signatures; - -#[test] -fn sapling_generators() { - struct SaplingGenerators { - skb: [u8; 32], - pkb: [u8; 32], - npb: [u8; 32], - wprb: [u8; 32], - vcvb: [u8; 32], - vcrb: [u8; 32], - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_generators.py - let sapling_generators = SaplingGenerators { - skb: [ - 0x30, 0xb5, 0xf2, 0xaa, 0xad, 0x32, 0x56, 0x30, 0xbc, 0xdd, 0xdb, 0xce, 0x4d, 0x67, - 0x65, 0x6d, 0x05, 0xfd, 0x1c, 0xc2, 0xd0, 0x37, 0xbb, 0x53, 0x75, 0xb6, 0xe9, 0x6d, - 0x9e, 0x01, 0xa1, 0xd7, - ], - pkb: [ - 0xe7, 0xe8, 0x5d, 0xe0, 0xf7, 0xf9, 0x7a, 0x46, 0xd2, 0x49, 0xa1, 0xf5, 0xea, 0x51, - 0xdf, 0x50, 0xcc, 0x48, 0x49, 0x0f, 0x84, 0x01, 0xc9, 0xde, 0x7a, 0x2a, 0xdf, 0x18, - 0x07, 0xd1, 0xb6, 0xd4, - ], - npb: [ - 0x65, 0x00, 0x2b, 0xc7, 0x36, 0xfa, 0xf7, 0xa3, 0x42, 0x2e, 0xff, 0xff, 0xe8, 0xb8, - 0x55, 0xe1, 0x8f, 0xba, 0x96, 0xa0, 0x15, 0x8a, 0x9e, 0xfc, 0xa5, 0x84, 0xbf, 0x40, - 0x54, 0x9d, 0x36, 0xe1, - ], - wprb: [ - 0xac, 0x77, 0x6c, 0x79, 0x65, 0x63, 0xfc, 0xd4, 0x4c, 0xc4, 0x9c, 0xfa, 0xea, 0x8b, - 0xb7, 0x96, 0x95, 0x2c, 0x26, 0x6e, 0x47, 0x77, 0x9d, 0x94, 0x57, 0x4c, 0x10, 0xad, - 0x01, 0x75, 0x4b, 0x11, - ], - vcvb: [ - 0xd7, 0xc8, 0x67, 0x06, 0xf5, 0x81, 0x7a, 0xa7, 0x18, 0xcd, 0x1c, 0xfa, 0xd0, 0x32, - 0x33, 0xbc, 0xd6, 0x4a, 0x77, 0x89, 0xfd, 0x94, 0x22, 0xd3, 0xb1, 0x7a, 0xf6, 0x82, - 0x3a, 0x7e, 0x6a, 0xc6, - ], - vcrb: [ - 0x8b, 0x6a, 0x0b, 0x38, 0xb9, 0xfa, 0xae, 0x3c, 0x3b, 0x80, 0x3b, 0x47, 0xb0, 0xf1, - 0x46, 0xad, 0x50, 0xab, 0x22, 0x1e, 0x6e, 0x2a, 0xfb, 0xe6, 0xdb, 0xde, 0x45, 0xcb, - 0xa9, 0xd3, 0x81, 0xed, - ], - }; - - { - let mut vec = Vec::new(); - let p = JUBJUB.generator(FixedGenerators::SpendingKeyGenerator); - p.write(&mut vec).unwrap(); - assert_eq!(&vec, &sapling_generators.skb); - } - - { - let mut vec = Vec::new(); - let p = JUBJUB.generator(FixedGenerators::ProofGenerationKey); - p.write(&mut vec).unwrap(); - assert_eq!(&vec, &sapling_generators.pkb); - } - - { - let mut vec = Vec::new(); - let p = JUBJUB.generator(FixedGenerators::NullifierPosition); - p.write(&mut vec).unwrap(); - assert_eq!(&vec, &sapling_generators.npb); - } - - { - let mut vec = Vec::new(); - let p = JUBJUB.generator(FixedGenerators::NoteCommitmentRandomness); - p.write(&mut vec).unwrap(); - assert_eq!(&vec, &sapling_generators.wprb); - } - - { - let mut vec = Vec::new(); - let p = JUBJUB.generator(FixedGenerators::ValueCommitmentValue); - p.write(&mut vec).unwrap(); - assert_eq!(&vec, &sapling_generators.vcvb); - } - - { - let mut vec = Vec::new(); - let p = JUBJUB.generator(FixedGenerators::ValueCommitmentRandomness); - p.write(&mut vec).unwrap(); - assert_eq!(&vec, &sapling_generators.vcrb); - } -} diff --git a/librustzcash/src/tests/notes.rs b/librustzcash/src/tests/notes.rs deleted file mode 100644 index 6f8c0f5..0000000 --- a/librustzcash/src/tests/notes.rs +++ /dev/null @@ -1,673 +0,0 @@ -use librustzcash_sapling_compute_cm; -use librustzcash_sapling_compute_nf; - -#[test] -fn notes() { - #![allow(dead_code)] - struct TestVector { - sk: [u8; 32], - ask: [u8; 32], - nsk: [u8; 32], - ovk: [u8; 32], - ak: [u8; 32], - nk: [u8; 32], - ivk: [u8; 32], - default_d: [u8; 11], - default_pk_d: [u8; 32], - note_v: u64, - note_r: [u8; 32], - note_cm: [u8; 32], - note_pos: u64, - note_nf: [u8; 32], - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_key_components.py - let test_vectors = vec![ - TestVector { - sk: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - ask: [ - 0x85, 0x48, 0xa1, 0x4a, 0x47, 0x3e, 0xa5, 0x47, 0xaa, 0x23, 0x78, 0x40, 0x20, 0x44, - 0xf8, 0x18, 0xcf, 0x19, 0x11, 0xcf, 0x5d, 0xd2, 0x05, 0x4f, 0x67, 0x83, 0x45, 0xf0, - 0x0d, 0x0e, 0x88, 0x06, - ], - nsk: [ - 0x30, 0x11, 0x4e, 0xa0, 0xdd, 0x0b, 0xb6, 0x1c, 0xf0, 0xea, 0xea, 0xb6, 0xec, 0x33, - 0x31, 0xf5, 0x81, 0xb0, 0x42, 0x5e, 0x27, 0x33, 0x85, 0x01, 0x26, 0x2d, 0x7e, 0xac, - 0x74, 0x5e, 0x6e, 0x05, - ], - ovk: [ - 0x98, 0xd1, 0x69, 0x13, 0xd9, 0x9b, 0x04, 0x17, 0x7c, 0xab, 0xa4, 0x4f, 0x6e, 0x4d, - 0x22, 0x4e, 0x03, 0xb5, 0xac, 0x03, 0x1d, 0x7c, 0xe4, 0x5e, 0x86, 0x51, 0x38, 0xe1, - 0xb9, 0x96, 0xd6, 0x3b, - ], - ak: [ - 0xf3, 0x44, 0xec, 0x38, 0x0f, 0xe1, 0x27, 0x3e, 0x30, 0x98, 0xc2, 0x58, 0x8c, 0x5d, - 0x3a, 0x79, 0x1f, 0xd7, 0xba, 0x95, 0x80, 0x32, 0x76, 0x07, 0x77, 0xfd, 0x0e, 0xfa, - 0x8e, 0xf1, 0x16, 0x20, - ], - nk: [ - 0xf7, 0xcf, 0x9e, 0x77, 0xf2, 0xe5, 0x86, 0x83, 0x38, 0x3c, 0x15, 0x19, 0xac, 0x7b, - 0x06, 0x2d, 0x30, 0x04, 0x0e, 0x27, 0xa7, 0x25, 0xfb, 0x88, 0xfb, 0x19, 0xa9, 0x78, - 0xbd, 0x3f, 0xd6, 0xba, - ], - ivk: [ - 0xb7, 0x0b, 0x7c, 0xd0, 0xed, 0x03, 0xcb, 0xdf, 0xd7, 0xad, 0xa9, 0x50, 0x2e, 0xe2, - 0x45, 0xb1, 0x3e, 0x56, 0x9d, 0x54, 0xa5, 0x71, 0x9d, 0x2d, 0xaa, 0x0f, 0x5f, 0x14, - 0x51, 0x47, 0x92, 0x04, - ], - default_d: [ - 0xf1, 0x9d, 0x9b, 0x79, 0x7e, 0x39, 0xf3, 0x37, 0x44, 0x58, 0x39, - ], - default_pk_d: [ - 0xdb, 0x4c, 0xd2, 0xb0, 0xaa, 0xc4, 0xf7, 0xeb, 0x8c, 0xa1, 0x31, 0xf1, 0x65, 0x67, - 0xc4, 0x45, 0xa9, 0x55, 0x51, 0x26, 0xd3, 0xc2, 0x9f, 0x14, 0xe3, 0xd7, 0x76, 0xe8, - 0x41, 0xae, 0x74, 0x15, - ], - note_v: 0, - note_r: [ - 0x39, 0x17, 0x6d, 0xac, 0x39, 0xac, 0xe4, 0x98, 0x0e, 0xcc, 0x8d, 0x77, 0x8e, 0x89, - 0x86, 0x02, 0x55, 0xec, 0x36, 0x15, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - note_cm: [ - 0xcb, 0x3c, 0xf9, 0x15, 0x32, 0x70, 0xd5, 0x7e, 0xb9, 0x14, 0xc6, 0xc2, 0xbc, 0xc0, - 0x18, 0x50, 0xc9, 0xfe, 0xd4, 0x4f, 0xce, 0x08, 0x06, 0x27, 0x8f, 0x08, 0x3e, 0xf2, - 0xdd, 0x07, 0x64, 0x39, - ], - note_pos: 0, - note_nf: [ - 0x44, 0xfa, 0xd6, 0x56, 0x4f, 0xfd, 0xec, 0x9f, 0xa1, 0x9c, 0x43, 0xa2, 0x8f, 0x86, - 0x1d, 0x5e, 0xbf, 0x60, 0x23, 0x46, 0x00, 0x7d, 0xe7, 0x62, 0x67, 0xd9, 0x75, 0x27, - 0x47, 0xab, 0x40, 0x63, - ], - }, - TestVector { - sk: [ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, - ], - ask: [ - 0xc9, 0x43, 0x56, 0x29, 0xbf, 0x8b, 0xff, 0xe5, 0x5e, 0x73, 0x35, 0xec, 0x07, 0x77, - 0x18, 0xba, 0x60, 0xba, 0x28, 0xd7, 0xac, 0x37, 0x94, 0xb7, 0x4f, 0x51, 0x2c, 0x31, - 0xaf, 0x0a, 0x53, 0x04, - ], - nsk: [ - 0x11, 0xac, 0xc2, 0xea, 0xd0, 0x7b, 0x5f, 0x00, 0x8c, 0x1f, 0x0f, 0x09, 0x0c, 0xc8, - 0xdd, 0xf3, 0x35, 0x23, 0x6f, 0xf4, 0xb2, 0x53, 0xc6, 0x49, 0x56, 0x95, 0xe9, 0xd6, - 0x39, 0xda, 0xcd, 0x08, - ], - ovk: [ - 0x3b, 0x94, 0x62, 0x10, 0xce, 0x6d, 0x1b, 0x16, 0x92, 0xd7, 0x39, 0x2a, 0xc8, 0x4a, - 0x8b, 0xc8, 0xf0, 0x3b, 0x72, 0x72, 0x3c, 0x7d, 0x36, 0x72, 0x1b, 0x80, 0x9a, 0x79, - 0xc9, 0xd6, 0xe4, 0x5b, - ], - ak: [ - 0x82, 0xff, 0x5e, 0xff, 0xc5, 0x27, 0xae, 0x84, 0x02, 0x0b, 0xf2, 0xd3, 0x52, 0x01, - 0xc1, 0x02, 0x19, 0x13, 0x19, 0x47, 0xff, 0x4b, 0x96, 0xf8, 0x81, 0xa4, 0x5f, 0x2e, - 0x8a, 0xe3, 0x05, 0x18, - ], - nk: [ - 0xc4, 0x53, 0x4d, 0x84, 0x8b, 0xb9, 0x18, 0xcf, 0x4a, 0x7f, 0x8b, 0x98, 0x74, 0x0a, - 0xb3, 0xcc, 0xee, 0x58, 0x67, 0x95, 0xff, 0x4d, 0xf6, 0x45, 0x47, 0xa8, 0x88, 0x8a, - 0x6c, 0x74, 0x15, 0xd2, - ], - ivk: [ - 0xc5, 0x18, 0x38, 0x44, 0x66, 0xb2, 0x69, 0x88, 0xb5, 0x10, 0x90, 0x67, 0x41, 0x8d, - 0x19, 0x2d, 0x9d, 0x6b, 0xd0, 0xd9, 0x23, 0x22, 0x05, 0xd7, 0x74, 0x18, 0xc2, 0x40, - 0xfc, 0x68, 0xa4, 0x06, - ], - default_d: [ - 0xae, 0xf1, 0x80, 0xf6, 0xe3, 0x4e, 0x35, 0x4b, 0x88, 0x8f, 0x81, - ], - default_pk_d: [ - 0xa6, 0xb1, 0x3e, 0xa3, 0x36, 0xdd, 0xb7, 0xa6, 0x7b, 0xb0, 0x9a, 0x0e, 0x68, 0xe9, - 0xd3, 0xcf, 0xb3, 0x92, 0x10, 0x83, 0x1e, 0xa3, 0xa2, 0x96, 0xba, 0x09, 0xa9, 0x22, - 0x06, 0x0f, 0xd3, 0x8b, - ], - note_v: 12227227834928555328, - note_r: [ - 0x47, 0x8b, 0xa0, 0xee, 0x6e, 0x1a, 0x75, 0xb6, 0x00, 0x03, 0x6f, 0x26, 0xf1, 0x8b, - 0x70, 0x15, 0xab, 0x55, 0x6b, 0xed, 0xdf, 0x8b, 0x96, 0x02, 0x38, 0x86, 0x9f, 0x89, - 0xdd, 0x80, 0x4e, 0x06, - ], - note_cm: [ - 0xb5, 0x78, 0x93, 0x50, 0x0b, 0xfb, 0x85, 0xdf, 0x2e, 0x8b, 0x01, 0xac, 0x45, 0x2f, - 0x89, 0xe1, 0x0e, 0x26, 0x6b, 0xcf, 0xa3, 0x1c, 0x31, 0xb2, 0x9a, 0x53, 0xae, 0x72, - 0xca, 0xd4, 0x69, 0x50, - ], - note_pos: 763714296, - note_nf: [ - 0x67, 0x9e, 0xb0, 0xc3, 0xa7, 0x57, 0xe2, 0xae, 0x83, 0xcd, 0xb4, 0x2a, 0x1a, 0xb2, - 0x59, 0xd7, 0x83, 0x88, 0x31, 0x54, 0x19, 0xad, 0xc7, 0x1d, 0x2e, 0x37, 0x63, 0x17, - 0x4c, 0x2e, 0x9d, 0x93, - ], - }, - TestVector { - sk: [ - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, - ], - ask: [ - 0xee, 0x1c, 0x3d, 0x7e, 0xfe, 0x0a, 0x78, 0x06, 0x3d, 0x6a, 0xf3, 0xd9, 0xd8, 0x12, - 0x12, 0xaf, 0x47, 0xb7, 0xc1, 0xb7, 0x61, 0xf8, 0x5c, 0xcb, 0x06, 0x6f, 0xc1, 0x1a, - 0x6a, 0x42, 0x17, 0x03, - ], - nsk: [ - 0x1d, 0x3b, 0x71, 0x37, 0x55, 0xd7, 0x48, 0x75, 0xe8, 0xea, 0x38, 0xfd, 0x16, 0x6e, - 0x76, 0xc6, 0x2a, 0x42, 0x50, 0x21, 0x6e, 0x6b, 0xbf, 0xe4, 0x8a, 0x5e, 0x2e, 0xab, - 0xad, 0x11, 0x7f, 0x0b, - ], - ovk: [ - 0x8b, 0xf4, 0x39, 0x0e, 0x28, 0xdd, 0xc9, 0x5b, 0x83, 0x02, 0xc3, 0x81, 0xd5, 0x81, - 0x0b, 0x84, 0xba, 0x8e, 0x60, 0x96, 0xe5, 0xa7, 0x68, 0x22, 0x77, 0x4f, 0xd4, 0x9f, - 0x49, 0x1e, 0x8f, 0x49, - ], - ak: [ - 0xab, 0x83, 0x57, 0x4e, 0xb5, 0xde, 0x85, 0x9a, 0x0a, 0xb8, 0x62, 0x9d, 0xec, 0x34, - 0xc7, 0xbe, 0xe8, 0xc3, 0xfc, 0x74, 0xdf, 0xa0, 0xb1, 0x9a, 0x3a, 0x74, 0x68, 0xd1, - 0x5d, 0xca, 0x64, 0xc6, - ], - nk: [ - 0x95, 0xd5, 0x80, 0x53, 0xe0, 0x59, 0x2e, 0x4a, 0x16, 0x9c, 0xc0, 0xb7, 0x92, 0x8a, - 0xaa, 0xc3, 0xde, 0x24, 0xef, 0x15, 0x31, 0xaa, 0x9e, 0xb6, 0xf4, 0xab, 0x93, 0x91, - 0x4d, 0xa8, 0xa0, 0x6e, - ], - ivk: [ - 0x47, 0x1c, 0x24, 0xa3, 0xdc, 0x87, 0x30, 0xe7, 0x50, 0x36, 0xc0, 0xa9, 0x5f, 0x3e, - 0x2f, 0x7d, 0xd1, 0xbe, 0x6f, 0xb9, 0x3a, 0xd2, 0x95, 0x92, 0x20, 0x3d, 0xef, 0x30, - 0x41, 0x95, 0x45, 0x05, - ], - default_d: [ - 0x75, 0x99, 0xf0, 0xbf, 0x9b, 0x57, 0xcd, 0x2d, 0xc2, 0x99, 0xb6, - ], - default_pk_d: [ - 0x66, 0x14, 0x17, 0x39, 0x51, 0x4b, 0x28, 0xf0, 0x5d, 0xef, 0x8a, 0x18, 0xee, 0xee, - 0x5e, 0xed, 0x4d, 0x44, 0xc6, 0x22, 0x5c, 0x3c, 0x65, 0xd8, 0x8d, 0xd9, 0x90, 0x77, - 0x08, 0x01, 0x2f, 0x5a, - ], - note_v: 6007711596147559040, - note_r: [ - 0x14, 0x7c, 0xf2, 0xb5, 0x1b, 0x4c, 0x7c, 0x63, 0xcb, 0x77, 0xb9, 0x9e, 0x8b, 0x78, - 0x3e, 0x5b, 0x51, 0x11, 0xdb, 0x0a, 0x7c, 0xa0, 0x4d, 0x6c, 0x01, 0x4a, 0x1d, 0x7d, - 0xa8, 0x3b, 0xae, 0x0a, - ], - note_cm: [ - 0xdb, 0x85, 0xa7, 0x0a, 0x98, 0x43, 0x7f, 0x73, 0x16, 0x7f, 0xc3, 0x32, 0xd5, 0xb7, - 0xb7, 0x40, 0x82, 0x96, 0x66, 0x17, 0x70, 0xb1, 0x01, 0xb0, 0xaa, 0x87, 0x83, 0x9f, - 0x4e, 0x55, 0xf1, 0x51, - ], - note_pos: 1527428592, - note_nf: [ - 0xe9, 0x8f, 0x6a, 0x8f, 0x34, 0xff, 0x49, 0x80, 0x59, 0xb3, 0xc7, 0x31, 0xb9, 0x1f, - 0x45, 0x11, 0x08, 0xc4, 0x95, 0x4d, 0x91, 0x94, 0x84, 0x36, 0x1c, 0xf9, 0xb4, 0x8f, - 0x59, 0xae, 0x1d, 0x14, - ], - }, - TestVector { - sk: [ - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, - ], - ask: [ - 0x00, 0xc3, 0xa1, 0xe1, 0xca, 0x8f, 0x4e, 0x04, 0x80, 0xee, 0x1e, 0xe9, 0x0c, 0xa7, - 0x51, 0x78, 0x79, 0xd3, 0xfc, 0x5c, 0x81, 0x5c, 0x09, 0x03, 0xe5, 0xee, 0xbc, 0x94, - 0xbb, 0x80, 0x95, 0x03, - ], - nsk: [ - 0xe6, 0x62, 0x85, 0xa5, 0xe9, 0xb6, 0x5e, 0x15, 0x7a, 0xd2, 0xfc, 0xd5, 0x43, 0xda, - 0xd9, 0x8c, 0x67, 0xa5, 0x8a, 0xbd, 0xf2, 0x87, 0xe0, 0x55, 0x06, 0xbd, 0x1c, 0x2e, - 0x59, 0xb0, 0x72, 0x0b, - ], - ovk: [ - 0x14, 0x76, 0x78, 0xe0, 0x55, 0x3b, 0x97, 0x82, 0x93, 0x47, 0x64, 0x7c, 0x5b, 0xc7, - 0xda, 0xb4, 0xcc, 0x22, 0x02, 0xb5, 0x4e, 0xc2, 0x9f, 0xd3, 0x1a, 0x3d, 0xe6, 0xbe, - 0x08, 0x25, 0xfc, 0x5e, - ], - ak: [ - 0x3c, 0x9c, 0xde, 0x7e, 0x5d, 0x0d, 0x38, 0xa8, 0x61, 0x0f, 0xaa, 0xdb, 0xcf, 0x4c, - 0x34, 0x3f, 0x5d, 0x3c, 0xfa, 0x31, 0x55, 0xa5, 0xb9, 0x46, 0x61, 0xa6, 0x75, 0x3e, - 0x96, 0xe8, 0x84, 0xea, - ], - nk: [ - 0xb7, 0x7d, 0x36, 0xf5, 0x08, 0x94, 0x1d, 0xbd, 0x61, 0xcf, 0xd0, 0xf1, 0x59, 0xee, - 0x05, 0xcf, 0xaa, 0x78, 0xa2, 0x6c, 0x94, 0x92, 0x90, 0x38, 0x06, 0xd8, 0x3b, 0x59, - 0x8d, 0x3c, 0x1c, 0x2a, - ], - ivk: [ - 0x63, 0x6a, 0xa9, 0x64, 0xbf, 0xc2, 0x3c, 0xe4, 0xb1, 0xfc, 0xf7, 0xdf, 0xc9, 0x91, - 0x79, 0xdd, 0xc4, 0x06, 0xff, 0x55, 0x40, 0x0c, 0x92, 0x95, 0xac, 0xfc, 0x14, 0xf0, - 0x31, 0xc7, 0x26, 0x00, - ], - default_d: [ - 0x1b, 0x81, 0x61, 0x4f, 0x1d, 0xad, 0xea, 0x0f, 0x8d, 0x0a, 0x58, - ], - default_pk_d: [ - 0x25, 0xeb, 0x55, 0xfc, 0xcf, 0x76, 0x1f, 0xc6, 0x4e, 0x85, 0xa5, 0x88, 0xef, 0xe6, - 0xea, 0xd7, 0x83, 0x2f, 0xb1, 0xf0, 0xf7, 0xa8, 0x31, 0x65, 0x89, 0x5b, 0xdf, 0xf9, - 0x42, 0x92, 0x5f, 0x5c, - ], - note_v: 18234939431076114368, - note_r: [ - 0x34, 0xa4, 0xb2, 0xa9, 0x14, 0x4f, 0xf5, 0xea, 0x54, 0xef, 0xee, 0x87, 0xcf, 0x90, - 0x1b, 0x5b, 0xed, 0x5e, 0x35, 0xd2, 0x1f, 0xbb, 0xd7, 0x88, 0xd5, 0xbd, 0x9d, 0x83, - 0x3e, 0x11, 0x28, 0x04, - ], - note_cm: [ - 0xe0, 0x8c, 0xe4, 0x82, 0xb3, 0xa8, 0xfb, 0x3b, 0x35, 0xcc, 0xdb, 0xe3, 0x43, 0x37, - 0xbd, 0x10, 0x5d, 0x88, 0x39, 0x21, 0x2e, 0x0d, 0x16, 0x44, 0xb9, 0xd5, 0x5c, 0xaa, - 0x60, 0xd1, 0x9b, 0x6c, - ], - note_pos: 2291142888, - note_nf: [ - 0x55, 0x47, 0xaa, 0x12, 0xff, 0x80, 0xa6, 0xb3, 0x30, 0x4e, 0x3b, 0x05, 0x86, 0x56, - 0x47, 0x2a, 0xbd, 0x2c, 0x81, 0x83, 0xb5, 0x9d, 0x07, 0x37, 0xb9, 0x3c, 0xee, 0x75, - 0x8b, 0xec, 0x47, 0xa1, - ], - }, - TestVector { - sk: [ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, - ], - ask: [ - 0x82, 0x36, 0xd1, 0x9d, 0x32, 0x05, 0xd8, 0x55, 0x43, 0xa0, 0x68, 0x11, 0x34, 0x3f, - 0x82, 0x7b, 0x65, 0x63, 0x77, 0x0a, 0x49, 0xaa, 0x4d, 0x0c, 0xa0, 0x08, 0x18, 0x05, - 0xd4, 0xc8, 0xea, 0x0d, - ], - nsk: [ - 0x7e, 0xc1, 0xef, 0x0b, 0xed, 0x82, 0x71, 0x82, 0x72, 0xf0, 0xf4, 0x4f, 0x01, 0x7c, - 0x48, 0x41, 0x74, 0x51, 0x3d, 0x66, 0x1d, 0xd1, 0x68, 0xaf, 0x02, 0xd2, 0x09, 0x2a, - 0x1d, 0x8a, 0x05, 0x07, - ], - ovk: [ - 0x1b, 0x6e, 0x75, 0xec, 0xe3, 0xac, 0xe8, 0xdb, 0xa6, 0xa5, 0x41, 0x0d, 0x9a, 0xd4, - 0x75, 0x56, 0x68, 0xe4, 0xb3, 0x95, 0x85, 0xd6, 0x35, 0xec, 0x1d, 0xa7, 0xc8, 0xdc, - 0xfd, 0x5f, 0xc4, 0xed, - ], - ak: [ - 0x55, 0xe8, 0x83, 0x89, 0xbb, 0x7e, 0x41, 0xde, 0x13, 0x0c, 0xfa, 0x51, 0xa8, 0x71, - 0x5f, 0xde, 0x01, 0xff, 0x9c, 0x68, 0x76, 0x64, 0x7f, 0x01, 0x75, 0xad, 0x34, 0xf0, - 0x58, 0xdd, 0xe0, 0x1a, - ], - nk: [ - 0x72, 0x5d, 0x4a, 0xd6, 0xa1, 0x50, 0x21, 0xcd, 0x1c, 0x48, 0xc5, 0xee, 0x19, 0xde, - 0x6c, 0x1e, 0x76, 0x8a, 0x2c, 0xc0, 0xa9, 0xa7, 0x30, 0xa0, 0x1b, 0xb2, 0x1c, 0x95, - 0xe3, 0xd9, 0xe4, 0x3c, - ], - ivk: [ - 0x67, 0xfa, 0x2b, 0xf7, 0xc6, 0x7d, 0x46, 0x58, 0x24, 0x3c, 0x31, 0x7c, 0x0c, 0xb4, - 0x1f, 0xd3, 0x20, 0x64, 0xdf, 0xd3, 0x70, 0x9f, 0xe0, 0xdc, 0xb7, 0x24, 0xf1, 0x4b, - 0xb0, 0x1a, 0x1d, 0x04, - ], - default_d: [ - 0xfc, 0xfb, 0x68, 0xa4, 0x0d, 0x4b, 0xc6, 0xa0, 0x4b, 0x09, 0xc4, - ], - default_pk_d: [ - 0x8b, 0x2a, 0x33, 0x7f, 0x03, 0x62, 0x2c, 0x24, 0xff, 0x38, 0x1d, 0x4c, 0x54, 0x6f, - 0x69, 0x77, 0xf9, 0x05, 0x22, 0xe9, 0x2f, 0xde, 0x44, 0xc9, 0xd1, 0xbb, 0x09, 0x97, - 0x14, 0xb9, 0xdb, 0x2b, - ], - note_v: 12015423192295118080, - note_r: [ - 0xe5, 0x57, 0x85, 0x13, 0x55, 0x74, 0x7c, 0x09, 0xac, 0x59, 0x01, 0x3c, 0xbd, 0xe8, - 0x59, 0x80, 0x96, 0x4e, 0xc1, 0x84, 0x4d, 0x9c, 0x69, 0x67, 0xca, 0x0c, 0x02, 0x9c, - 0x84, 0x57, 0xbb, 0x04, - ], - note_cm: [ - 0xbd, 0xc8, 0x54, 0xbf, 0x3e, 0x7b, 0x00, 0x82, 0x1f, 0x3b, 0x8b, 0x85, 0x23, 0x8c, - 0xcf, 0x1e, 0x67, 0x15, 0xbf, 0xe7, 0x0b, 0x63, 0x2d, 0x04, 0x4b, 0x26, 0xfb, 0x2b, - 0xc7, 0x1b, 0x7f, 0x36, - ], - note_pos: 3054857184, - note_nf: [ - 0x8a, 0x9a, 0xbd, 0xa3, 0xd4, 0xef, 0x85, 0xca, 0xf2, 0x2b, 0xfa, 0xf2, 0xc4, 0x8f, - 0x62, 0x38, 0x2a, 0x73, 0xa1, 0x62, 0x4e, 0xb8, 0xeb, 0x2b, 0xd0, 0x0d, 0x27, 0x03, - 0x01, 0xbf, 0x3d, 0x13, - ], - }, - TestVector { - sk: [ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, - ], - ask: [ - 0xea, 0xe6, 0x88, 0x4d, 0x76, 0x4a, 0x05, 0x40, 0x61, 0xa8, 0xf1, 0xc0, 0x07, 0x6c, - 0x62, 0x4d, 0xcb, 0x73, 0x87, 0x89, 0xf7, 0xad, 0x1e, 0x74, 0x08, 0xe3, 0x1f, 0x24, - 0xdf, 0xc8, 0x26, 0x07, - ], - nsk: [ - 0xfb, 0xe6, 0x10, 0xf4, 0x2a, 0x41, 0x74, 0x9f, 0x9b, 0x6e, 0x6e, 0x4a, 0x54, 0xb5, - 0xa3, 0x2e, 0xbf, 0xe8, 0xf4, 0x38, 0x00, 0x88, 0x1b, 0xa6, 0xcd, 0x13, 0xed, 0x0b, - 0x05, 0x29, 0x46, 0x01, - ], - ovk: [ - 0xc6, 0xbc, 0x1f, 0x39, 0xf0, 0xd7, 0x86, 0x31, 0x4c, 0xb2, 0x0b, 0xf9, 0xab, 0x22, - 0x85, 0x40, 0x91, 0x35, 0x55, 0xf9, 0x70, 0x69, 0x6b, 0x6d, 0x7c, 0x77, 0xbb, 0x33, - 0x23, 0x28, 0x37, 0x2a, - ], - ak: [ - 0xe6, 0x82, 0x76, 0x59, 0x14, 0xe3, 0x86, 0x4c, 0x33, 0x9e, 0x57, 0x82, 0xb8, 0x55, - 0xc0, 0xfd, 0xf4, 0x0e, 0x0d, 0xfc, 0xed, 0xb9, 0xe7, 0xb4, 0x7b, 0xc9, 0x4b, 0x90, - 0xb3, 0xa4, 0xc9, 0x88, - ], - nk: [ - 0x82, 0x25, 0x6b, 0x95, 0x62, 0x3c, 0x67, 0x02, 0x4b, 0x44, 0x24, 0xd9, 0x14, 0x00, - 0xa3, 0x70, 0xe7, 0xac, 0x8e, 0x4d, 0x15, 0x48, 0x2a, 0x37, 0x59, 0xe0, 0x0d, 0x21, - 0x97, 0x49, 0xda, 0xee, - ], - ivk: [ - 0xea, 0x3f, 0x1d, 0x80, 0xe4, 0x30, 0x7c, 0xa7, 0x3b, 0x9f, 0x37, 0x80, 0x1f, 0x91, - 0xfb, 0xa8, 0x10, 0xcc, 0x41, 0xd2, 0x79, 0xfc, 0x29, 0xf5, 0x64, 0x23, 0x56, 0x54, - 0xa2, 0x17, 0x8e, 0x03, - ], - default_d: [ - 0xeb, 0x51, 0x98, 0x82, 0xad, 0x1e, 0x5c, 0xc6, 0x54, 0xcd, 0x59, - ], - default_pk_d: [ - 0x6b, 0x27, 0xda, 0xcc, 0xb5, 0xa8, 0x20, 0x7f, 0x53, 0x2d, 0x10, 0xca, 0x23, 0x8f, - 0x97, 0x86, 0x64, 0x8a, 0x11, 0xb5, 0x96, 0x6e, 0x51, 0xa2, 0xf7, 0xd8, 0x9e, 0x15, - 0xd2, 0x9b, 0x8f, 0xdf, - ], - note_v: 5795906953514121792, - note_r: [ - 0x68, 0xf0, 0x61, 0x04, 0x60, 0x6b, 0x0c, 0x54, 0x49, 0x84, 0x5f, 0xf4, 0xc6, 0x5f, - 0x73, 0xe9, 0x0f, 0x45, 0xef, 0x5a, 0x43, 0xc9, 0xd7, 0x4c, 0xb2, 0xc8, 0x5c, 0xf5, - 0x6c, 0x94, 0xc0, 0x02, - ], - note_cm: [ - 0xe8, 0x26, 0x7d, 0x30, 0xac, 0x11, 0xc1, 0x00, 0xbc, 0x7a, 0x0f, 0xdf, 0x91, 0xf7, - 0x1d, 0x74, 0xc5, 0xbc, 0xf2, 0xe1, 0xef, 0x95, 0x66, 0x90, 0x44, 0x73, 0x01, 0x69, - 0xde, 0x1a, 0x5b, 0x4c, - ], - note_pos: 3818571480, - note_nf: [ - 0x33, 0x2a, 0xd9, 0x9e, 0xb9, 0xe9, 0x77, 0xeb, 0x62, 0x7a, 0x12, 0x2d, 0xbf, 0xb2, - 0xf2, 0x5f, 0xe5, 0x88, 0xe5, 0x97, 0x75, 0x3e, 0xc5, 0x58, 0x0f, 0xf2, 0xbe, 0x20, - 0xb6, 0xc9, 0xa7, 0xe1, - ], - }, - TestVector { - sk: [ - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, - ], - ask: [ - 0xe8, 0xf8, 0x16, 0xb4, 0xbc, 0x08, 0xa7, 0xe5, 0x66, 0x75, 0x0c, 0xc2, 0x8a, 0xfe, - 0x82, 0xa4, 0xce, 0xa9, 0xc2, 0xbe, 0xf2, 0x44, 0xfa, 0x4b, 0x13, 0xc4, 0x73, 0x9b, - 0x28, 0x07, 0x4c, 0x0d, - ], - nsk: [ - 0x32, 0x61, 0x5b, 0x13, 0x7f, 0x28, 0x01, 0xed, 0x44, 0x6e, 0x48, 0x78, 0x1a, 0xb0, - 0x63, 0x45, 0x72, 0xe1, 0x8c, 0xfb, 0x06, 0x93, 0x72, 0x1b, 0x88, 0x03, 0xc0, 0x5b, - 0x82, 0x27, 0xd1, 0x07, - ], - ovk: [ - 0xf6, 0x2c, 0x05, 0xe8, 0x48, 0xa8, 0x73, 0xef, 0x88, 0x5e, 0x12, 0xb0, 0x8c, 0x5e, - 0x7c, 0xa2, 0xf3, 0x24, 0x24, 0xba, 0xcc, 0x75, 0x4c, 0xb6, 0x97, 0x50, 0x44, 0x4d, - 0x35, 0x5f, 0x51, 0x06, - ], - ak: [ - 0xff, 0x27, 0xdb, 0x07, 0x51, 0x94, 0x5d, 0x3e, 0xe4, 0xbe, 0x9c, 0xf1, 0x5c, 0x2e, - 0xa2, 0x11, 0xb2, 0x4b, 0x16, 0x4d, 0x5f, 0x2d, 0x7d, 0xdf, 0xf5, 0xe4, 0xa0, 0x70, - 0x8f, 0x10, 0xb9, 0x5e, - ], - nk: [ - 0x94, 0x38, 0x85, 0x95, 0x9d, 0x4e, 0xf8, 0xa9, 0xcf, 0xca, 0x07, 0xc4, 0x57, 0xf0, - 0x9e, 0xc7, 0x4b, 0x96, 0xf9, 0x93, 0xd8, 0xe0, 0xfa, 0x32, 0xb1, 0x9c, 0x03, 0xe3, - 0xb0, 0x7a, 0x42, 0x0f, - ], - ivk: [ - 0xb5, 0xc5, 0x89, 0x49, 0x43, 0x95, 0x69, 0x33, 0xc0, 0xe5, 0xc1, 0x2d, 0x31, 0x1f, - 0xc1, 0x2c, 0xba, 0x58, 0x35, 0x4b, 0x5c, 0x38, 0x9e, 0xdc, 0x03, 0xda, 0x55, 0x08, - 0x4f, 0x74, 0xc2, 0x05, - ], - default_d: [ - 0xbe, 0xbb, 0x0f, 0xb4, 0x6b, 0x8a, 0xaf, 0xf8, 0x90, 0x40, 0xf6, - ], - default_pk_d: [ - 0xd1, 0x1d, 0xa0, 0x1f, 0x0b, 0x43, 0xbd, 0xd5, 0x28, 0x8d, 0x32, 0x38, 0x5b, 0x87, - 0x71, 0xd2, 0x23, 0x49, 0x3c, 0x69, 0x80, 0x25, 0x44, 0x04, 0x3f, 0x77, 0xcf, 0x1d, - 0x71, 0xc1, 0xcb, 0x8c, - ], - note_v: 18023134788442677120, - note_r: [ - 0x49, 0xf9, 0x0b, 0x47, 0xfd, 0x52, 0xfe, 0xe7, 0xc1, 0xc8, 0x1f, 0x0d, 0xcb, 0x5b, - 0x74, 0xc3, 0xfb, 0x9b, 0x3e, 0x03, 0x97, 0x6f, 0x8b, 0x75, 0x24, 0xea, 0xba, 0xd0, - 0x08, 0x89, 0x21, 0x07, - ], - note_cm: [ - 0x57, 0x2b, 0xa2, 0x05, 0x25, 0xb0, 0xac, 0x4d, 0x6d, 0xc0, 0x1a, 0xc2, 0xea, 0x10, - 0x90, 0xb6, 0xe0, 0xf2, 0xf4, 0xbf, 0x4e, 0xc4, 0xa0, 0xdb, 0x5b, 0xbc, 0xcb, 0x5b, - 0x78, 0x3a, 0x1e, 0x55, - ], - note_pos: 287318480, - note_nf: [ - 0xfc, 0x74, 0xcd, 0x0e, 0x4b, 0xe0, 0x49, 0x57, 0xb1, 0x96, 0xcf, 0x87, 0x34, 0xae, - 0x99, 0x23, 0x96, 0xaf, 0x4c, 0xfa, 0x8f, 0xec, 0xbb, 0x86, 0xf9, 0x61, 0xe6, 0xb4, - 0x07, 0xd5, 0x1e, 0x11, - ], - }, - TestVector { - sk: [ - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, - ], - ask: [ - 0x74, 0xb4, 0x4a, 0x37, 0xf1, 0x50, 0x23, 0xc0, 0x60, 0x42, 0x7e, 0x1d, 0xae, 0xa3, - 0xf6, 0x43, 0x12, 0xdd, 0x8f, 0xeb, 0x7b, 0x2c, 0xed, 0xf0, 0xdd, 0x55, 0x44, 0x49, - 0x3f, 0x87, 0x2c, 0x06, - ], - nsk: [ - 0x07, 0x5c, 0x35, 0xdb, 0x8b, 0x1b, 0x25, 0x75, 0x42, 0x23, 0xec, 0xee, 0x34, 0xab, - 0x73, 0x0d, 0xdd, 0xd1, 0xf1, 0x4a, 0x6a, 0x54, 0xf4, 0xc6, 0xf4, 0x68, 0x45, 0x3c, - 0x3c, 0x6e, 0xd6, 0x0b, - ], - ovk: [ - 0xe9, 0xe0, 0xdc, 0x1e, 0xd3, 0x11, 0xda, 0xed, 0x64, 0xbd, 0x74, 0xda, 0x5d, 0x94, - 0xfe, 0x88, 0xa6, 0xea, 0x41, 0x4b, 0x73, 0x12, 0xde, 0x3d, 0x2a, 0x78, 0xf6, 0x46, - 0x32, 0xbb, 0xe3, 0x73, - ], - ak: [ - 0x28, 0x3f, 0x9a, 0xaf, 0xa9, 0xbc, 0xb3, 0xe6, 0xce, 0x17, 0xe6, 0x32, 0x12, 0x63, - 0x4c, 0xb3, 0xee, 0x55, 0x0c, 0x47, 0x6b, 0x67, 0x6b, 0xd3, 0x56, 0xa6, 0xdf, 0x8a, - 0xdf, 0x51, 0xd2, 0x5e, - ], - nk: [ - 0xdc, 0x4c, 0x67, 0xb1, 0x0d, 0x4b, 0x0a, 0x21, 0x8d, 0xc6, 0xe1, 0x48, 0x70, 0x66, - 0x74, 0x0a, 0x40, 0x93, 0x17, 0x86, 0x6c, 0x32, 0xe6, 0x64, 0xb5, 0x0e, 0x39, 0x7a, - 0xa8, 0x03, 0x89, 0xd4, - ], - ivk: [ - 0x87, 0x16, 0xc8, 0x28, 0x80, 0xe1, 0x36, 0x83, 0xe1, 0xbb, 0x05, 0x9d, 0xd0, 0x6c, - 0x80, 0xc9, 0x01, 0x34, 0xa9, 0x6d, 0x5a, 0xfc, 0xa8, 0xaa, 0xc2, 0xbb, 0xf6, 0x8b, - 0xb0, 0x5f, 0x84, 0x02, - ], - default_d: [ - 0xad, 0x6e, 0x2e, 0x18, 0x5a, 0x31, 0x00, 0xe3, 0xa6, 0xa8, 0xb3, - ], - default_pk_d: [ - 0x32, 0xcb, 0x28, 0x06, 0xb8, 0x82, 0xf1, 0x36, 0x8b, 0x0d, 0x4a, 0x89, 0x8f, 0x72, - 0xc4, 0xc8, 0xf7, 0x28, 0x13, 0x2c, 0xc1, 0x24, 0x56, 0x94, 0x6e, 0x7f, 0x4c, 0xb0, - 0xfb, 0x05, 0x8d, 0xa9, - ], - note_v: 11803618549661680832, - note_r: [ - 0x51, 0x65, 0xaf, 0xf2, 0x2d, 0xd4, 0xed, 0x56, 0xb4, 0xd8, 0x1d, 0x1f, 0x17, 0x1c, - 0xc3, 0xd6, 0x43, 0x2f, 0xed, 0x1b, 0xeb, 0xf2, 0x0a, 0x7b, 0xea, 0xb1, 0x2d, 0xb1, - 0x42, 0xf9, 0x4a, 0x0c, - ], - note_cm: [ - 0xab, 0x7f, 0xc5, 0x66, 0x87, 0x3c, 0xcd, 0xe6, 0x71, 0xf5, 0x98, 0x27, 0x67, 0x85, - 0x60, 0xa0, 0x06, 0xf8, 0x2b, 0xb7, 0xad, 0xcd, 0x75, 0x22, 0x3f, 0xa8, 0x59, 0x36, - 0xf7, 0x8c, 0x2b, 0x23, - ], - note_pos: 1051032776, - note_nf: [ - 0xd2, 0xe8, 0x87, 0xbd, 0x85, 0x4a, 0x80, 0x2b, 0xce, 0x85, 0x70, 0x53, 0x02, 0x0f, - 0x5d, 0x3e, 0x7c, 0x8a, 0xe5, 0x26, 0x7c, 0x5b, 0x65, 0x83, 0xb3, 0xd2, 0x12, 0xcc, - 0x8b, 0xb6, 0x98, 0x90, - ], - }, - TestVector { - sk: [ - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, - ], - ask: [ - 0x03, 0x9d, 0xd9, 0x3d, 0xf3, 0x11, 0xff, 0x8f, 0xba, 0xb3, 0xfe, 0x23, 0x02, 0x19, - 0xcd, 0x42, 0xac, 0x87, 0x94, 0x84, 0xf3, 0x0b, 0x90, 0x3a, 0x3c, 0x1e, 0x67, 0xcc, - 0xca, 0x5a, 0x7b, 0x0d, - ], - nsk: [ - 0x04, 0x9f, 0xa1, 0x4f, 0x48, 0x6c, 0x75, 0xb9, 0xfa, 0xd7, 0xe3, 0xb6, 0x73, 0xa4, - 0x43, 0xdd, 0x07, 0x4e, 0xaa, 0x96, 0xed, 0xcb, 0x2a, 0x53, 0xea, 0xaa, 0xbd, 0xaf, - 0x70, 0xff, 0xbb, 0x08, - ], - ovk: [ - 0x14, 0x7d, 0xd1, 0x1d, 0x77, 0xeb, 0xa1, 0xb1, 0x63, 0x6f, 0xd6, 0x19, 0x0c, 0x62, - 0xb9, 0xa5, 0xd0, 0x48, 0x1b, 0xee, 0x7e, 0x91, 0x7f, 0xab, 0x02, 0xe2, 0x18, 0x58, - 0x06, 0x3a, 0xb5, 0x04, - ], - ak: [ - 0x36, 0x40, 0x48, 0xee, 0xdb, 0xe8, 0xca, 0x20, 0x5e, 0xb7, 0xe7, 0xba, 0x0a, 0x90, - 0x12, 0x16, 0x6c, 0x7c, 0x7b, 0xd9, 0xeb, 0x22, 0x8e, 0x08, 0x48, 0x14, 0x48, 0xc4, - 0x88, 0xaa, 0x21, 0xd2, - ], - nk: [ - 0xed, 0x60, 0xaf, 0x1c, 0xe7, 0xdf, 0x38, 0x07, 0x0d, 0x38, 0x51, 0x43, 0x2a, 0x96, - 0x48, 0x0d, 0xb0, 0xb4, 0x17, 0xc3, 0x68, 0x2a, 0x1d, 0x68, 0xe3, 0xe8, 0x93, 0x34, - 0x23, 0x5c, 0x0b, 0xdf, - ], - ivk: [ - 0x99, 0xc9, 0xb4, 0xb8, 0x4f, 0x4b, 0x4e, 0x35, 0x0f, 0x78, 0x7d, 0x1c, 0xf7, 0x05, - 0x1d, 0x50, 0xec, 0xc3, 0x4b, 0x1a, 0x5b, 0x20, 0xd2, 0xd2, 0x13, 0x9b, 0x4a, 0xf1, - 0xf1, 0x60, 0xe0, 0x01, - ], - default_d: [ - 0x21, 0xc9, 0x0e, 0x1c, 0x65, 0x8b, 0x3e, 0xfe, 0x86, 0xaf, 0x58, - ], - default_pk_d: [ - 0x9e, 0x64, 0x17, 0x4b, 0x4a, 0xb9, 0x81, 0x40, 0x5c, 0x32, 0x3b, 0x5e, 0x12, 0x47, - 0x59, 0x45, 0xa4, 0x6d, 0x4f, 0xed, 0xf8, 0x06, 0x08, 0x28, 0x04, 0x1c, 0xd2, 0x0e, - 0x62, 0xfd, 0x2c, 0xef, - ], - note_v: 5584102310880684544, - note_r: [ - 0x8c, 0x3e, 0x56, 0x44, 0x9d, 0xc8, 0x63, 0x54, 0xd3, 0x3b, 0x02, 0x5e, 0xf2, 0x79, - 0x34, 0x60, 0xbc, 0xb1, 0x69, 0xf3, 0x32, 0x4e, 0x4a, 0x6b, 0x64, 0xba, 0xa6, 0x08, - 0x32, 0x31, 0x57, 0x04, - ], - note_cm: [ - 0x7b, 0x48, 0xa8, 0x37, 0x5d, 0x3e, 0xbd, 0x56, 0xbc, 0x64, 0x9b, 0xb5, 0xb5, 0x24, - 0x23, 0x36, 0xc2, 0xa0, 0x5a, 0x08, 0x03, 0x23, 0x9b, 0x5b, 0x88, 0xfd, 0x92, 0x07, - 0x8f, 0xea, 0x4d, 0x04, - ], - note_pos: 1814747072, - note_nf: [ - 0xa8, 0x2f, 0x17, 0x50, 0xcc, 0x5b, 0x2b, 0xee, 0x64, 0x9a, 0x36, 0x5c, 0x04, 0x20, - 0xed, 0x87, 0x07, 0x5b, 0x88, 0x71, 0xfd, 0xa4, 0xa7, 0xf5, 0x84, 0x0d, 0x6b, 0xbe, - 0xb1, 0x7c, 0xd6, 0x20, - ], - }, - TestVector { - sk: [ - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, - ], - ask: [ - 0xeb, 0xbb, 0x40, 0xa9, 0x80, 0xba, 0x3b, 0x88, 0x60, 0x94, 0x8d, 0x01, 0x1e, 0x1b, - 0xfb, 0x4a, 0xff, 0xe1, 0x6c, 0x65, 0x2e, 0x90, 0xe9, 0x82, 0x58, 0x30, 0x2f, 0x44, - 0x64, 0xc9, 0x1e, 0x0c, - ], - nsk: [ - 0x68, 0x43, 0x1b, 0x19, 0x91, 0x04, 0x21, 0x52, 0x00, 0xb9, 0x5e, 0xe5, 0xcb, 0x71, - 0xbf, 0x8b, 0x88, 0x3a, 0x3e, 0x95, 0xb7, 0x98, 0x9c, 0xad, 0x19, 0x70, 0x63, 0x14, - 0x1e, 0xbb, 0xfd, 0x00, - ], - ovk: [ - 0x57, 0x34, 0x67, 0xa7, 0xb3, 0x0e, 0xad, 0x6c, 0xcc, 0x50, 0x47, 0x44, 0xca, 0x9e, - 0x1a, 0x28, 0x1a, 0x0d, 0x1a, 0x08, 0x73, 0x8b, 0x06, 0xa0, 0x68, 0x4f, 0xea, 0xcd, - 0x1e, 0x9d, 0x12, 0x6d, - ], - ak: [ - 0x71, 0xc3, 0x52, 0x3e, 0xec, 0xa3, 0x53, 0x11, 0xfb, 0xd5, 0xd7, 0xe7, 0xd7, 0x0b, - 0x70, 0x9d, 0x6c, 0x35, 0xa2, 0x4f, 0x26, 0x2b, 0x34, 0xbf, 0x64, 0x05, 0x9b, 0xf2, - 0xc0, 0x2e, 0x0b, 0xa8, - ], - nk: [ - 0x62, 0x44, 0x00, 0x10, 0x3b, 0x65, 0x69, 0xb7, 0x35, 0x8f, 0xe8, 0x0f, 0x6f, 0x6c, - 0xad, 0x43, 0x25, 0xde, 0xfd, 0xa9, 0xd9, 0x49, 0x9c, 0x2b, 0x8f, 0x88, 0x6a, 0x62, - 0x69, 0xa2, 0xaa, 0x52, - ], - ivk: [ - 0xdb, 0x95, 0xea, 0x8b, 0xd9, 0xf9, 0x3d, 0x41, 0xb5, 0xab, 0x2b, 0xeb, 0xc9, 0x1a, - 0x38, 0xed, 0xd5, 0x27, 0x08, 0x3e, 0x2a, 0x6e, 0xf9, 0xf3, 0xc2, 0x97, 0x02, 0xd5, - 0xff, 0x89, 0xed, 0x00, - ], - default_d: [ - 0x23, 0x3c, 0x4a, 0xb8, 0x86, 0xa5, 0x5e, 0x3b, 0xa3, 0x74, 0xc0, - ], - default_pk_d: [ - 0xb6, 0x8e, 0x9e, 0xe0, 0xc0, 0x67, 0x8d, 0x7b, 0x30, 0x36, 0x93, 0x1c, 0x83, 0x1a, - 0x25, 0x25, 0x5f, 0x7e, 0xe4, 0x87, 0x38, 0x5a, 0x30, 0x31, 0x6e, 0x15, 0xf6, 0x48, - 0x2b, 0x87, 0x4f, 0xda, - ], - note_v: 17811330145809239872, - note_r: [ - 0x6e, 0xbb, 0xed, 0x74, 0x36, 0x19, 0xa2, 0x56, 0xf9, 0xad, 0x2e, 0x85, 0x88, 0x0c, - 0xfa, 0xa9, 0x09, 0x8a, 0x5f, 0xdb, 0x16, 0x29, 0x99, 0x0d, 0x9a, 0x7d, 0x3b, 0xb9, - 0x3f, 0xc9, 0x00, 0x03, - ], - note_cm: [ - 0xd3, 0x76, 0xa7, 0xbe, 0xe8, 0xce, 0x67, 0xf4, 0xef, 0xde, 0x56, 0xaa, 0x77, 0xcf, - 0x64, 0x41, 0x9b, 0x0e, 0x55, 0x0a, 0xbb, 0xcb, 0x8e, 0x2b, 0xcb, 0xda, 0x8b, 0x63, - 0xe4, 0x1d, 0xeb, 0x37, - ], - note_pos: 2578461368, - note_nf: [ - 0x65, 0x36, 0x74, 0x87, 0x3b, 0x3c, 0x67, 0x0c, 0x58, 0x85, 0x84, 0x73, 0xe7, 0xfe, - 0x72, 0x19, 0x72, 0xfb, 0x96, 0xe2, 0x15, 0xb8, 0x73, 0x77, 0xa1, 0x7c, 0xa3, 0x71, - 0x0d, 0x93, 0xc9, 0xe9, - ], - }, - ]; - - for tv in test_vectors { - // Compute commitment and compare with test vector - let mut result = [0u8; 32]; - assert!(librustzcash_sapling_compute_cm( - &tv.default_d, - &tv.default_pk_d, - tv.note_v, - &tv.note_r, - &mut result - )); - assert_eq!(&result, &tv.note_cm); - - // Compute nullifier and compare with test vector - assert!(librustzcash_sapling_compute_nf( - &tv.default_d, - &tv.default_pk_d, - tv.note_v, - &tv.note_r, - &tv.ak, - &tv.nk, - tv.note_pos, - &mut result - )); - assert_eq!(&result, &tv.note_nf); - } -} diff --git a/librustzcash/src/tests/signatures.rs b/librustzcash/src/tests/signatures.rs deleted file mode 100644 index 23fc75b..0000000 --- a/librustzcash/src/tests/signatures.rs +++ /dev/null @@ -1,515 +0,0 @@ -use pairing::{bls12_381::Bls12, PrimeField, PrimeFieldRepr}; -use sapling_crypto::{ - jubjub::{FixedGenerators, JubjubEngine}, - redjubjub::{PrivateKey, PublicKey, Signature}, -}; - -use super::JUBJUB; - -#[test] -fn redjubjub_signatures() { - struct TestVector { - sk: [u8; 32], - vk: [u8; 32], - alpha: [u8; 32], - rsk: [u8; 32], - rvk: [u8; 32], - m: [u8; 32], - sig: [u8; 64], - rsig: [u8; 64], - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_signatures.py - let test_vectors = vec![ - TestVector { - sk: [ - 0x18, 0xe2, 0x8d, 0xea, 0x5c, 0x11, 0x81, 0x7a, 0xee, 0xb2, 0x1a, 0x19, 0x98, 0x1d, - 0x28, 0x36, 0x8e, 0xc4, 0x38, 0xaf, 0xc2, 0x5a, 0x8d, 0xb9, 0x4e, 0xbe, 0x08, 0xd7, - 0xa0, 0x28, 0x8e, 0x09, - ], - vk: [ - 0x9b, 0x01, 0x53, 0xb0, 0x3d, 0x32, 0x0f, 0xe2, 0x3e, 0x28, 0x34, 0xd5, 0xd6, 0x1d, - 0xbb, 0x1f, 0x51, 0x9b, 0x3f, 0x41, 0xf8, 0xf9, 0x46, 0x15, 0x2b, 0xf0, 0xc3, 0xf2, - 0x47, 0xd1, 0x18, 0x07, - ], - alpha: [ - 0xff, 0xd1, 0xa1, 0x27, 0x32, 0x52, 0xb1, 0x87, 0xf4, 0xed, 0x32, 0x6d, 0xfc, 0x98, - 0x85, 0x3e, 0x29, 0x17, 0xc2, 0xb3, 0x63, 0x79, 0xb1, 0x75, 0xda, 0x63, 0xb9, 0xef, - 0x6d, 0xda, 0x6c, 0x08, - ], - rsk: [ - 0x60, 0x87, 0x38, 0x3b, 0x30, 0x55, 0x9b, 0x31, 0x60, 0x90, 0x85, 0xb9, 0x00, 0x96, - 0x45, 0xce, 0xb6, 0xa0, 0xc6, 0x61, 0x25, 0x99, 0xd7, 0x28, 0x80, 0x72, 0x8e, 0x61, - 0x24, 0x4e, 0x7d, 0x03, - ], - rvk: [ - 0xc1, 0xba, 0xbc, 0xb6, 0xea, 0xe2, 0xb9, 0x94, 0xee, 0x6d, 0x65, 0xc1, 0x0b, 0x9d, - 0xad, 0x59, 0x40, 0xdc, 0x73, 0x5b, 0x07, 0x50, 0x4d, 0xae, 0xd1, 0xe4, 0x6b, 0x07, - 0x09, 0xb4, 0x51, 0x36, - ], - m: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - sig: [ - 0xea, 0xa0, 0x57, 0x47, 0x6b, 0x4a, 0xb4, 0x82, 0x28, 0x8b, 0x93, 0xdf, 0x8f, 0xe0, - 0xc5, 0xce, 0x9d, 0x78, 0x83, 0x67, 0xf2, 0xbe, 0x55, 0x1b, 0x7f, 0x7a, 0x82, 0xa6, - 0xdb, 0x36, 0x04, 0x68, 0xde, 0xb9, 0xa7, 0xb7, 0xaf, 0xaa, 0xdf, 0xec, 0xa6, 0xf4, - 0x81, 0x19, 0x3d, 0xc6, 0x57, 0x57, 0x47, 0xf6, 0x0a, 0x1a, 0x8a, 0x48, 0xff, 0x0a, - 0xd7, 0x0c, 0xf8, 0xcb, 0x8d, 0x52, 0x8e, 0x08, - ], - rsig: [ - 0xd5, 0x6f, 0x0d, 0x91, 0xaf, 0x42, 0x4e, 0x1f, 0x1c, 0x7f, 0xb8, 0x6b, 0xa4, 0xee, - 0xd1, 0x43, 0xcc, 0x16, 0x66, 0x0c, 0x5f, 0xe8, 0xd7, 0xdc, 0x0d, 0x28, 0x4b, 0xcf, - 0x65, 0xa0, 0x89, 0xe9, 0x8b, 0x56, 0x1f, 0x9f, 0x20, 0x1a, 0x63, 0x3d, 0x70, 0x0c, - 0xd3, 0x98, 0x1e, 0x8c, 0xac, 0x07, 0xb5, 0xa8, 0x7e, 0xfa, 0x61, 0x86, 0x06, 0x2d, - 0xd8, 0xe5, 0xd6, 0x32, 0x5e, 0x7b, 0x82, 0x02, - ], - }, - TestVector { - sk: [ - 0x05, 0x96, 0x54, 0xf9, 0x61, 0x27, 0x3d, 0xaf, 0xda, 0x3b, 0x26, 0x77, 0xb3, 0x5c, - 0x18, 0xaf, 0x6b, 0x11, 0xad, 0xfb, 0x9e, 0xe9, 0x0b, 0x48, 0x93, 0x5e, 0x55, 0x7c, - 0x8d, 0x5d, 0x9c, 0x04, - ], - vk: [ - 0xfa, 0xf6, 0xc3, 0xb7, 0x37, 0xe8, 0xe6, 0x11, 0xaa, 0xfe, 0xa5, 0x2f, 0x03, 0xbb, - 0x27, 0x86, 0xe1, 0x83, 0x53, 0xeb, 0xe0, 0xd3, 0x13, 0x9e, 0x3c, 0x54, 0x49, 0x87, - 0x80, 0xc8, 0xc1, 0x99, - ], - alpha: [ - 0xc3, 0x0b, 0x96, 0x20, 0x8d, 0xa8, 0x00, 0xe1, 0x0a, 0xf0, 0x25, 0x42, 0xce, 0x69, - 0x4b, 0x7e, 0xd7, 0x6a, 0x28, 0x29, 0x9f, 0x85, 0x99, 0x8e, 0x5d, 0x61, 0x08, 0x12, - 0x68, 0x1b, 0xf0, 0x03, - ], - rsk: [ - 0xc8, 0xa1, 0xea, 0x19, 0xef, 0xcf, 0x3d, 0x90, 0xe5, 0x2b, 0x4c, 0xb9, 0x81, 0xc6, - 0x63, 0x2d, 0x43, 0x7c, 0xd5, 0x24, 0x3e, 0x6f, 0xa5, 0xd6, 0xf0, 0xbf, 0x5d, 0x8e, - 0xf5, 0x78, 0x8c, 0x08, - ], - rvk: [ - 0xd5, 0x24, 0xdc, 0xe7, 0x73, 0x40, 0x69, 0x75, 0x8a, 0x91, 0xf0, 0x07, 0xa8, 0x69, - 0x50, 0x5d, 0xfc, 0x4a, 0xba, 0x17, 0x20, 0x59, 0x4d, 0x4d, 0x74, 0xf0, 0x07, 0x70, - 0x0e, 0x62, 0xee, 0x00, - ], - m: [ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, - ], - sig: [ - 0x22, 0x35, 0x54, 0x94, 0xa8, 0x31, 0x6a, 0xb1, 0x34, 0x73, 0xf5, 0x5e, 0x62, 0x66, - 0xb2, 0xfb, 0x41, 0x97, 0x31, 0x5e, 0xac, 0x62, 0xf8, 0x2c, 0xc7, 0x3d, 0xca, 0xca, - 0x19, 0x90, 0x90, 0xf1, 0x5b, 0xe1, 0x98, 0xce, 0x7d, 0x3f, 0x9f, 0xc8, 0xff, 0xf5, - 0x50, 0xe1, 0x08, 0x81, 0xec, 0x49, 0xff, 0x27, 0x36, 0x9e, 0x7d, 0x4f, 0xd9, 0x64, - 0x01, 0x53, 0x49, 0x2a, 0x0a, 0x06, 0x25, 0x08, - ], - rsig: [ - 0xf4, 0xb8, 0x94, 0xba, 0x84, 0xce, 0x1e, 0xc3, 0x8a, 0x63, 0x15, 0x2f, 0xc4, 0x09, - 0xf9, 0x47, 0xd6, 0x1a, 0xbb, 0x1f, 0x48, 0x91, 0x63, 0x6b, 0xc3, 0xee, 0x19, 0xef, - 0x6d, 0x4b, 0x30, 0xc0, 0xfd, 0x22, 0x86, 0x6b, 0x84, 0xff, 0xbc, 0x7e, 0x2a, 0x78, - 0xc4, 0x3f, 0x57, 0x83, 0xd2, 0xd2, 0xea, 0xd0, 0x78, 0x59, 0x55, 0x03, 0x74, 0x43, - 0xc2, 0xf4, 0xd5, 0x2f, 0x78, 0x5e, 0xee, 0x07, - ], - }, - TestVector { - sk: [ - 0xad, 0xe7, 0xab, 0xb5, 0x51, 0xc7, 0x9d, 0x0f, 0x0e, 0x42, 0xef, 0x7f, 0x12, 0x06, - 0xb8, 0x77, 0x12, 0xa8, 0x4a, 0x61, 0xde, 0xa3, 0xf3, 0x7b, 0x42, 0x49, 0x6d, 0x7e, - 0xfd, 0x12, 0x52, 0x0c, - ], - vk: [ - 0x36, 0x9e, 0xa7, 0x51, 0x76, 0x2f, 0x83, 0x9d, 0x25, 0x70, 0x1a, 0x5e, 0xeb, 0x55, - 0x1e, 0xc4, 0xf0, 0x6c, 0x12, 0x90, 0xb3, 0xb9, 0xc3, 0xa7, 0x24, 0x40, 0x2d, 0xec, - 0x02, 0x73, 0x92, 0x21, - ], - alpha: [ - 0x81, 0x92, 0x25, 0x29, 0xa6, 0x3e, 0xe7, 0x43, 0xfc, 0x4f, 0xbb, 0xac, 0x45, 0xc4, - 0x98, 0x83, 0x16, 0xbc, 0x9b, 0x6e, 0x42, 0x8b, 0x01, 0xa8, 0xd3, 0x1f, 0xc1, 0xc2, - 0xa6, 0xca, 0x62, 0x05, - ], - rsk: [ - 0x77, 0x4d, 0xda, 0x07, 0x99, 0xf7, 0xed, 0x82, 0x87, 0x81, 0xe2, 0x5f, 0xc4, 0xa9, - 0xe8, 0x54, 0x28, 0x29, 0xb2, 0xce, 0x1f, 0xf4, 0x8d, 0x1d, 0x6d, 0xb9, 0xfa, 0xdb, - 0xb9, 0x28, 0x37, 0x03, - ], - rvk: [ - 0x0d, 0x92, 0xad, 0x6d, 0x46, 0xed, 0xac, 0xd0, 0x23, 0xd4, 0xd2, 0xef, 0x70, 0x3a, - 0x6c, 0xa0, 0xa7, 0x92, 0xcf, 0xc4, 0xb7, 0xda, 0x11, 0xc2, 0x35, 0x3b, 0xc8, 0x45, - 0xa2, 0x7a, 0x97, 0x4d, - ], - m: [ - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, - ], - sig: [ - 0xdd, 0x65, 0x21, 0x01, 0x4d, 0xff, 0x70, 0x6e, 0x3a, 0x38, 0x52, 0x7a, 0x86, 0xb6, - 0xc1, 0x6e, 0x94, 0x14, 0x80, 0xe7, 0x33, 0xef, 0xf7, 0x9e, 0xbe, 0x0c, 0x43, 0x03, - 0x79, 0xd7, 0x57, 0x04, 0x9d, 0xb7, 0x90, 0xcd, 0x5e, 0x14, 0x44, 0x7c, 0x38, 0x6f, - 0x5f, 0xcb, 0x41, 0x9f, 0x27, 0xc4, 0x41, 0x3f, 0x35, 0x88, 0xfa, 0x21, 0x42, 0xd2, - 0xcf, 0xba, 0xed, 0x08, 0x2c, 0xc6, 0xdb, 0x07, - ], - rsig: [ - 0xd8, 0x94, 0x45, 0xcb, 0x9b, 0xd1, 0x03, 0x35, 0x69, 0x23, 0x1d, 0xd6, 0x28, 0xaa, - 0x62, 0x81, 0x09, 0xfe, 0x93, 0x50, 0x2b, 0xf2, 0x2f, 0x9a, 0x5f, 0x37, 0xb1, 0x4e, - 0x51, 0x7f, 0x9a, 0x20, 0x54, 0xae, 0xe3, 0xc8, 0x1b, 0x60, 0xb3, 0xf0, 0x55, 0x1e, - 0x32, 0xf7, 0x93, 0x5a, 0xbc, 0x2f, 0x37, 0xb9, 0x9a, 0xb3, 0xec, 0x99, 0x68, 0x02, - 0xef, 0xd6, 0x50, 0x69, 0xe1, 0x28, 0x12, 0x08, - ], - }, - TestVector { - sk: [ - 0xc9, 0xd2, 0xae, 0x1f, 0x6d, 0x32, 0xa6, 0x75, 0xd0, 0x9e, 0xb0, 0x82, 0x3f, 0x46, - 0x7f, 0xa9, 0x21, 0xb3, 0x28, 0x4a, 0xcb, 0x35, 0xfa, 0xbd, 0xfc, 0x99, 0x4d, 0xe5, - 0x49, 0xb8, 0x59, 0x0d, - ], - vk: [ - 0x2d, 0x2f, 0x31, 0x6e, 0x5c, 0x36, 0x9a, 0xe4, 0xdd, 0x2c, 0x82, 0x5f, 0x3d, 0x86, - 0x46, 0x00, 0x58, 0x40, 0x71, 0x84, 0x60, 0x3b, 0x21, 0x2c, 0xf3, 0x45, 0x9f, 0x36, - 0xc8, 0x69, 0x7f, 0xd8, - ], - alpha: [ - 0xeb, 0xbc, 0x89, 0x03, 0x11, 0x07, 0xc4, 0x4f, 0x47, 0x88, 0x9e, 0xd4, 0xd4, 0x37, - 0x5a, 0x41, 0x14, 0xcf, 0x8a, 0x75, 0xdd, 0x33, 0xb9, 0x62, 0xf2, 0xd7, 0x59, 0xd3, - 0xf4, 0xc6, 0xdf, 0x06, - ], - rsk: [ - 0xfd, 0x62, 0x41, 0x4c, 0x1f, 0x2b, 0xd3, 0xf4, 0x94, 0x16, 0x87, 0x8a, 0x80, 0x5d, - 0x71, 0x44, 0x35, 0x47, 0x7f, 0xbe, 0xa7, 0x2e, 0x4c, 0x1a, 0x46, 0xc2, 0x73, 0x53, - 0x54, 0xca, 0xbb, 0x05, - ], - rvk: [ - 0xf0, 0x43, 0x0e, 0x95, 0x3b, 0xe6, 0x0b, 0xf4, 0x38, 0xdb, 0xdc, 0xc2, 0x30, 0x3f, - 0x0e, 0x32, 0xa6, 0xf7, 0xce, 0x2f, 0xbe, 0xdf, 0xb1, 0x3a, 0xc5, 0x18, 0xf7, 0x5a, - 0x3f, 0xd1, 0x0e, 0xb5, - ], - m: [ - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, - ], - sig: [ - 0x72, 0x79, 0xa7, 0x5c, 0x01, 0x36, 0x75, 0xb3, 0x29, 0x84, 0xe5, 0xc7, 0x3a, 0x98, - 0x91, 0xeb, 0xf0, 0xb2, 0x29, 0xb1, 0x6e, 0x62, 0x35, 0xba, 0x36, 0xdf, 0xa1, 0xb5, - 0xa1, 0x0c, 0x5e, 0x44, 0x57, 0x81, 0x91, 0x89, 0x7c, 0x06, 0xb8, 0x52, 0x4a, 0x26, - 0x74, 0xaa, 0x7a, 0x0c, 0x8c, 0x23, 0x5f, 0x52, 0xd3, 0x3a, 0xc9, 0x2c, 0x70, 0x56, - 0xb2, 0xbe, 0x95, 0x3c, 0x3f, 0xaa, 0x3d, 0x07, - ], - rsig: [ - 0xaa, 0xd4, 0x82, 0x8c, 0xb3, 0x42, 0xcf, 0x09, 0xb0, 0x0e, 0x30, 0x2c, 0xbb, 0xe7, - 0xcc, 0x3e, 0x95, 0xfe, 0x1f, 0xf8, 0x28, 0x74, 0x8e, 0x5f, 0x5b, 0xc6, 0x9c, 0xbf, - 0xde, 0x6e, 0x27, 0x22, 0xd7, 0x64, 0x35, 0x68, 0x7e, 0x85, 0x0c, 0xd3, 0x07, 0xa9, - 0xc1, 0x82, 0xec, 0x10, 0xe6, 0x88, 0x1d, 0xd6, 0x5e, 0xed, 0xc1, 0x1f, 0xa7, 0xb4, - 0x6d, 0xe3, 0xa7, 0x19, 0x59, 0xce, 0xc0, 0x02, - ], - }, - TestVector { - sk: [ - 0x33, 0xbc, 0xd2, 0x86, 0x45, 0x41, 0xb8, 0xbb, 0x7f, 0xdc, 0x77, 0xa1, 0x9d, 0x97, - 0x0f, 0x92, 0x4e, 0xae, 0xec, 0xf4, 0x10, 0x3c, 0x38, 0xc8, 0xd2, 0xb0, 0x66, 0x81, - 0x42, 0xf2, 0x7d, 0x09, - ], - vk: [ - 0x74, 0x17, 0x94, 0xe6, 0x2c, 0xf9, 0x32, 0x0c, 0x58, 0xba, 0xc5, 0x94, 0xa2, 0xb9, - 0x0e, 0x34, 0x0a, 0x6d, 0x8a, 0x68, 0x05, 0x6f, 0x6e, 0xd5, 0xc7, 0x86, 0x8c, 0x5f, - 0xf3, 0xe4, 0xd6, 0x16, - ], - alpha: [ - 0x7c, 0xe7, 0x25, 0xa5, 0xfe, 0xf6, 0x1b, 0xd4, 0xa1, 0xe9, 0xc7, 0x73, 0x28, 0xe8, - 0x21, 0x0e, 0xb7, 0x29, 0x2d, 0x95, 0x4c, 0x64, 0xe9, 0x9e, 0x8b, 0xed, 0xd0, 0x7a, - 0xb3, 0xab, 0x0e, 0x0d, - ], - rsk: [ - 0xf8, 0x76, 0x01, 0x55, 0xe5, 0x29, 0x3d, 0xbf, 0x9e, 0xb5, 0x77, 0x48, 0x32, 0x5f, - 0xc9, 0xf9, 0x04, 0x9d, 0xe5, 0x88, 0x5c, 0x65, 0xba, 0x60, 0xb5, 0xee, 0x03, 0x97, - 0x0b, 0xe9, 0x0e, 0x08, - ], - rvk: [ - 0x66, 0x62, 0xba, 0x09, 0x95, 0x0a, 0xcc, 0xd2, 0xce, 0xa3, 0xc7, 0xa8, 0x12, 0x90, - 0xcd, 0x59, 0x78, 0xa6, 0x2b, 0x5a, 0xc5, 0xbb, 0xc4, 0x8d, 0x9f, 0x58, 0x19, 0xcd, - 0xc9, 0x64, 0x6f, 0x0a, - ], - m: [ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, - ], - sig: [ - 0x51, 0x23, 0xb3, 0x1f, 0x84, 0xaf, 0x0c, 0x35, 0x5e, 0x13, 0xe7, 0x8a, 0x64, 0xd7, - 0xa3, 0xcd, 0xfd, 0x6b, 0xdf, 0xfd, 0xc7, 0x33, 0x38, 0xd9, 0x31, 0x7f, 0x73, 0x43, - 0x91, 0xa5, 0x5a, 0xe6, 0x25, 0x8f, 0x69, 0x80, 0xb9, 0xc7, 0xd1, 0x90, 0xcf, 0xa3, - 0x65, 0x81, 0xa9, 0xa4, 0x7a, 0x86, 0x3f, 0xd3, 0xbf, 0x76, 0x59, 0x42, 0x22, 0x95, - 0xb7, 0x5f, 0xd1, 0x22, 0xc3, 0xdd, 0x8a, 0x05, - ], - rsig: [ - 0x5b, 0xae, 0x25, 0x4f, 0xbd, 0xed, 0x60, 0x7a, 0x5c, 0x48, 0xb5, 0x30, 0x29, 0xf5, - 0x9b, 0xa7, 0x06, 0x32, 0x48, 0x79, 0xaa, 0x18, 0xd9, 0xc4, 0x73, 0x19, 0x00, 0x4b, - 0xe0, 0x2c, 0xec, 0xe0, 0xb8, 0xbb, 0x02, 0x4a, 0x7a, 0xab, 0xaa, 0x0a, 0x64, 0x0f, - 0x3a, 0x54, 0xdc, 0xda, 0xf2, 0x11, 0x31, 0x46, 0x9a, 0x50, 0x06, 0xbe, 0x27, 0x81, - 0xa5, 0x67, 0xff, 0xa6, 0x50, 0x3a, 0x35, 0x03, - ], - }, - TestVector { - sk: [ - 0xca, 0x35, 0x06, 0xd6, 0xaf, 0x77, 0x67, 0xb5, 0x79, 0x0e, 0xf0, 0xc5, 0x19, 0x0f, - 0xb3, 0xf3, 0x87, 0x7c, 0x4a, 0xab, 0x40, 0xe0, 0xdd, 0x65, 0x1a, 0xbb, 0xda, 0xcb, - 0x54, 0x4e, 0xd0, 0x05, - ], - vk: [ - 0xba, 0xb6, 0xcf, 0xb5, 0xc8, 0xea, 0x34, 0x91, 0x25, 0x1b, 0x46, 0xd5, 0x2a, 0xca, - 0x25, 0xd9, 0xe9, 0xaf, 0x69, 0xfa, 0xa9, 0xb4, 0xe4, 0x0b, 0x03, 0xad, 0x00, 0x86, - 0xde, 0x59, 0xb5, 0x1f, - ], - alpha: [ - 0xbe, 0xa3, 0x87, 0x20, 0x3f, 0x43, 0x76, 0x0a, 0xd3, 0x7d, 0x61, 0xde, 0x0e, 0xb5, - 0x9f, 0xca, 0x6c, 0xab, 0x75, 0x60, 0xdf, 0x64, 0xfa, 0xbb, 0x95, 0x11, 0x57, 0x9f, - 0x6f, 0x68, 0x26, 0x06, - ], - rsk: [ - 0x88, 0xd9, 0x8d, 0xf6, 0xee, 0xba, 0xdd, 0xbf, 0x4c, 0x8c, 0x51, 0xa4, 0x28, 0xc4, - 0x52, 0xbe, 0xf4, 0x27, 0xc0, 0x0b, 0x20, 0x45, 0xd8, 0x21, 0xb0, 0xcc, 0x31, 0x6b, - 0xc4, 0xb6, 0xf6, 0x0b, - ], - rvk: [ - 0x11, 0x26, 0x7d, 0x14, 0xd5, 0xe0, 0xb2, 0xbb, 0x3c, 0xe0, 0x99, 0xe8, 0xef, 0x84, - 0x49, 0x47, 0x1c, 0xbc, 0xfc, 0x69, 0x39, 0xa4, 0xb3, 0x48, 0xde, 0xa2, 0xc1, 0x73, - 0x56, 0xa1, 0xe8, 0xdd, - ], - m: [ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, - ], - sig: [ - 0xdc, 0x18, 0xc8, 0x8d, 0x96, 0x44, 0x42, 0x40, 0x6d, 0x65, 0x0a, 0xa2, 0xff, 0xbd, - 0x83, 0xd1, 0x13, 0xbf, 0x6a, 0x19, 0xda, 0x78, 0xf2, 0x66, 0x5b, 0x29, 0x4f, 0xa5, - 0xfa, 0x45, 0x0b, 0x92, 0x81, 0xa0, 0x7e, 0x32, 0x0c, 0x1a, 0xa3, 0x1d, 0x32, 0x44, - 0x9e, 0x00, 0xc5, 0xc3, 0x2d, 0xb2, 0xf4, 0x13, 0xdf, 0x0b, 0x63, 0xd0, 0x72, 0x8f, - 0xa4, 0x09, 0x41, 0xa8, 0xda, 0x02, 0x4f, 0x01, - ], - rsig: [ - 0x59, 0xe2, 0xe8, 0x18, 0x76, 0x6c, 0x50, 0xfc, 0x8f, 0x38, 0x40, 0xb2, 0x72, 0xaf, - 0x9a, 0xd9, 0x47, 0x56, 0xc8, 0x41, 0x32, 0x95, 0xfc, 0x79, 0x5f, 0xaf, 0xbc, 0xc0, - 0x71, 0x8e, 0x6c, 0x08, 0x16, 0x9a, 0x00, 0xd5, 0x83, 0x02, 0x77, 0x2a, 0x28, 0x28, - 0x43, 0xe8, 0x88, 0xd9, 0x81, 0xfa, 0x04, 0x79, 0x5d, 0x01, 0x4c, 0xf9, 0xc8, 0xcd, - 0xb9, 0x07, 0xff, 0x1b, 0x43, 0x0d, 0x92, 0x00, - ], - }, - TestVector { - sk: [ - 0xbc, 0x27, 0x83, 0x8d, 0xe2, 0xa6, 0x14, 0xcf, 0xba, 0x6c, 0x3e, 0x92, 0x2a, 0x8f, - 0x84, 0x24, 0xd9, 0x85, 0x6f, 0x68, 0x16, 0xf3, 0xbc, 0x61, 0x02, 0x31, 0x3b, 0x7f, - 0xaf, 0x5c, 0x3a, 0x0c, - ], - vk: [ - 0xd7, 0x9b, 0xe9, 0xff, 0x22, 0x9a, 0x2e, 0x35, 0xf5, 0xbc, 0xa4, 0x48, 0xe5, 0xeb, - 0x4a, 0x8a, 0xa9, 0x7f, 0xb4, 0x18, 0x02, 0x91, 0x25, 0xcf, 0xba, 0xa7, 0x8a, 0x91, - 0xa3, 0x82, 0xb0, 0x94, - ], - alpha: [ - 0x21, 0xa7, 0x15, 0x0e, 0x19, 0x4f, 0xed, 0xfe, 0xf9, 0x0c, 0x5d, 0x10, 0xe4, 0x20, - 0x85, 0x8b, 0xca, 0x40, 0x04, 0x04, 0x0e, 0xb6, 0x81, 0xd1, 0x4e, 0x75, 0xc4, 0x47, - 0x13, 0x51, 0xcb, 0x02, - ], - rsk: [ - 0x26, 0xa2, 0xa1, 0xc4, 0x9c, 0xe7, 0x6a, 0xfd, 0x31, 0x69, 0xd3, 0xd5, 0x7a, 0x8f, - 0xa1, 0x09, 0xa3, 0x8b, 0x3f, 0x6b, 0x23, 0x6e, 0xd7, 0x2c, 0xa8, 0xf6, 0xcb, 0x61, - 0xd8, 0xf8, 0x87, 0x00, - ], - rvk: [ - 0x54, 0xbf, 0x1b, 0xe7, 0x2e, 0x6d, 0x41, 0x20, 0x8b, 0x8a, 0xec, 0x11, 0x61, 0xd3, - 0xba, 0x59, 0x51, 0x9f, 0xb9, 0x3d, 0xa0, 0x1a, 0x55, 0xe6, 0x78, 0xe2, 0x75, 0x20, - 0x06, 0x60, 0x36, 0xc9, - ], - m: [ - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, - ], - sig: [ - 0x9a, 0xf6, 0xf2, 0x80, 0x0f, 0x4b, 0x80, 0xf7, 0x93, 0xbe, 0x64, 0x8a, 0x43, 0x9f, - 0x86, 0xe5, 0x7d, 0xa1, 0xb9, 0x19, 0x99, 0x9e, 0x41, 0x91, 0x09, 0x99, 0xd4, 0x2e, - 0xd0, 0xf3, 0x89, 0x6d, 0xb7, 0x6e, 0x06, 0x38, 0x8b, 0x27, 0x2c, 0x99, 0x85, 0x8b, - 0x55, 0x04, 0xd0, 0x2e, 0xc6, 0xb4, 0xd5, 0x25, 0xb8, 0x71, 0x38, 0x10, 0x50, 0x5f, - 0x4f, 0xc0, 0x31, 0x08, 0x3a, 0x14, 0xbf, 0x09, - ], - rsig: [ - 0x3f, 0x7d, 0x50, 0x71, 0xb8, 0x76, 0x17, 0x49, 0x05, 0x71, 0xa8, 0xbe, 0x91, 0x74, - 0x9e, 0x69, 0xf6, 0xbc, 0xba, 0x5a, 0xb6, 0x26, 0xe4, 0x2f, 0xf9, 0x2d, 0x0d, 0x7d, - 0xab, 0x73, 0xf3, 0x03, 0x61, 0xe5, 0xa2, 0x24, 0x99, 0x8e, 0x1f, 0x5e, 0xa1, 0xe5, - 0xf8, 0x68, 0x9a, 0x06, 0xa2, 0x77, 0x48, 0xbf, 0x74, 0x19, 0x63, 0xef, 0x51, 0x33, - 0x22, 0xf4, 0xa1, 0xba, 0x99, 0xaa, 0x36, 0x03, - ], - }, - TestVector { - sk: [ - 0xb2, 0x08, 0x59, 0xb8, 0x8e, 0xe3, 0x33, 0x8a, 0x64, 0x95, 0x4f, 0x8a, 0x9e, 0x8e, - 0x9b, 0xf3, 0xe7, 0x11, 0x5a, 0xcf, 0x7c, 0x6e, 0x7f, 0x01, 0x43, 0x2c, 0x5f, 0x76, - 0x96, 0xd2, 0xd0, 0x05, - ], - vk: [ - 0xa8, 0x1f, 0xe6, 0x84, 0x6d, 0xbe, 0x0a, 0x75, 0xc0, 0xf4, 0x9b, 0x21, 0x32, 0x32, - 0xbe, 0xad, 0xd1, 0xf9, 0xa5, 0x64, 0x67, 0x3d, 0x25, 0xb9, 0x1e, 0xe0, 0xf1, 0x7c, - 0xe9, 0xca, 0xa3, 0x63, - ], - alpha: [ - 0x44, 0xd9, 0x08, 0xe1, 0xc1, 0x5e, 0x6b, 0xd9, 0x38, 0x0a, 0x8b, 0x23, 0x5a, 0xce, - 0x02, 0xfa, 0xc1, 0xc0, 0x87, 0x94, 0x45, 0x4b, 0xcd, 0xb4, 0xa6, 0xf4, 0x8c, 0xea, - 0x78, 0xa7, 0x4a, 0x04, - ], - rsk: [ - 0xf6, 0xe1, 0x61, 0x99, 0x50, 0x42, 0x9f, 0x63, 0x9d, 0x9f, 0xda, 0xad, 0xf8, 0x5c, - 0x9e, 0xed, 0xa9, 0xd2, 0xe1, 0x63, 0xc2, 0xb9, 0x4c, 0xb6, 0xe9, 0x20, 0xec, 0x60, - 0x0f, 0x7a, 0x1b, 0x0a, - ], - rvk: [ - 0x0b, 0x68, 0xd5, 0x0f, 0x91, 0x3c, 0xd1, 0xb7, 0x8b, 0x59, 0x92, 0x1e, 0x16, 0x56, - 0xd5, 0x76, 0xb0, 0xeb, 0x17, 0x1e, 0xd3, 0x87, 0x0d, 0x39, 0xfe, 0xc6, 0x94, 0x41, - 0xb3, 0x4b, 0x25, 0x38, - ], - m: [ - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, - ], - sig: [ - 0x64, 0x59, 0x67, 0x6a, 0x94, 0x16, 0x34, 0xec, 0xb6, 0x1e, 0x59, 0xb7, 0x9a, 0x98, - 0xab, 0xe5, 0x87, 0x6f, 0x35, 0x6f, 0x72, 0x8a, 0xa0, 0x9e, 0x0c, 0xca, 0x9e, 0xfe, - 0x05, 0x76, 0x1a, 0x33, 0x09, 0xaa, 0x88, 0xb2, 0xfa, 0x0e, 0xe2, 0xd0, 0x4c, 0x1c, - 0x46, 0xe9, 0xf2, 0xa0, 0x48, 0xd5, 0x9d, 0x55, 0x65, 0xaf, 0xa6, 0xc3, 0xf1, 0x5b, - 0xce, 0x70, 0x8d, 0xaa, 0xab, 0x7b, 0x34, 0x0e, - ], - rsig: [ - 0xc9, 0x66, 0x84, 0xec, 0x7e, 0xa6, 0x0b, 0xde, 0x87, 0x88, 0x22, 0xdd, 0xca, 0xf6, - 0xb8, 0xb0, 0xbd, 0x31, 0x98, 0x51, 0x54, 0xdf, 0x9a, 0xd4, 0xf6, 0x90, 0x7d, 0xf8, - 0xfe, 0xd9, 0x5c, 0x1d, 0x84, 0xfe, 0x67, 0xe6, 0x78, 0x75, 0xa5, 0x39, 0x55, 0x0e, - 0xb2, 0x51, 0x4f, 0x19, 0x3b, 0x8e, 0xd4, 0x57, 0x25, 0x6c, 0x8d, 0x30, 0x28, 0x1d, - 0x6f, 0x8b, 0xb9, 0x54, 0x49, 0x24, 0xca, 0x0c, - ], - }, - TestVector { - sk: [ - 0x32, 0x16, 0xae, 0x47, 0xe9, 0xf5, 0x3e, 0x8a, 0x52, 0x79, 0x6f, 0x24, 0xb6, 0x24, - 0x60, 0x77, 0x6b, 0xd5, 0xf2, 0x05, 0xa7, 0x8e, 0x15, 0x95, 0xbc, 0x8e, 0xfe, 0xdc, - 0x51, 0x9d, 0x36, 0x0b, - ], - vk: [ - 0xdf, 0x74, 0xbf, 0x04, 0x79, 0x61, 0xcc, 0x5c, 0xda, 0xc8, 0x28, 0x90, 0xc7, 0x6e, - 0xc6, 0x75, 0xbd, 0x4e, 0x89, 0xea, 0xd2, 0x80, 0xc9, 0x52, 0xd7, 0xc3, 0x3e, 0xea, - 0xf2, 0xb5, 0xa6, 0x6b, - ], - alpha: [ - 0xc9, 0x61, 0xf2, 0xdd, 0x93, 0x68, 0x2a, 0xdb, 0x93, 0xf5, 0xc0, 0x5a, 0x73, 0xfd, - 0xbc, 0x6d, 0x43, 0xc7, 0x0e, 0x1b, 0x15, 0xe8, 0xd5, 0x3e, 0x3f, 0x17, 0xa8, 0x24, - 0x94, 0xe3, 0xf2, 0x09, - ], - rsk: [ - 0x44, 0x4b, 0xa9, 0x4e, 0x1e, 0x50, 0xd2, 0x94, 0x63, 0x5e, 0x68, 0xb2, 0x95, 0x01, - 0xb5, 0x3e, 0xae, 0x61, 0xcd, 0x1f, 0xbb, 0x3b, 0x84, 0xcd, 0x52, 0xf6, 0x72, 0x9c, - 0xfb, 0xcb, 0xab, 0x06, - ], - rvk: [ - 0x0a, 0xfb, 0xe4, 0x06, 0xa8, 0x91, 0xc3, 0xb8, 0xc3, 0x10, 0xc2, 0x15, 0xbc, 0x68, - 0xa9, 0x13, 0xde, 0x7c, 0xda, 0x06, 0xaf, 0x29, 0x42, 0x00, 0x56, 0x46, 0x8d, 0x0c, - 0x08, 0x85, 0x5b, 0x28, - ], - m: [ - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, - ], - sig: [ - 0x24, 0x93, 0x2c, 0x1f, 0xaa, 0x01, 0x63, 0xca, 0x9a, 0x7f, 0xcd, 0xe4, 0x76, 0x11, - 0x29, 0xd2, 0xe5, 0xe9, 0x9c, 0xf5, 0xef, 0xa2, 0x5d, 0x27, 0x04, 0x58, 0x8e, 0x1c, - 0x75, 0x67, 0x7b, 0x5e, 0xeb, 0xe4, 0x55, 0x04, 0x8d, 0x7c, 0xe1, 0xb0, 0xd2, 0x01, - 0x27, 0x53, 0xf7, 0x1b, 0x27, 0x25, 0x01, 0x2e, 0xe1, 0x85, 0x49, 0x28, 0x73, 0x18, - 0xf9, 0xcd, 0x73, 0xf0, 0x7f, 0x0f, 0xb5, 0x02, - ], - rsig: [ - 0xf7, 0xfa, 0x26, 0xca, 0x22, 0xf3, 0x86, 0xc4, 0x3c, 0x19, 0x1a, 0x0b, 0x3e, 0xa6, - 0x57, 0x7e, 0x8e, 0xea, 0xa3, 0xf3, 0x6b, 0x9b, 0xd1, 0xa3, 0xac, 0x3d, 0xf6, 0xf8, - 0x83, 0xa3, 0xff, 0xdb, 0x31, 0x32, 0x0b, 0xde, 0x62, 0x7f, 0xf4, 0x6f, 0xc2, 0x26, - 0x4a, 0x32, 0x63, 0xb9, 0xab, 0x67, 0x12, 0x3b, 0xa5, 0xe1, 0x08, 0x43, 0x20, 0xd9, - 0x10, 0xb3, 0x94, 0xef, 0x8c, 0x65, 0xba, 0x09, - ], - }, - TestVector { - sk: [ - 0x85, 0x83, 0x6f, 0x98, 0x32, 0xb2, 0x8d, 0xe7, 0xc6, 0x36, 0x13, 0xe2, 0xa6, 0xed, - 0x36, 0xfb, 0x1a, 0xb4, 0x4f, 0xb0, 0xc1, 0x3f, 0xa8, 0x79, 0x8c, 0xd9, 0xcd, 0x30, - 0x30, 0xd4, 0x55, 0x03, - ], - vk: [ - 0xbf, 0xd5, 0xbc, 0x00, 0xc7, 0xc0, 0x22, 0xaa, 0x89, 0x01, 0xae, 0x08, 0x3c, 0x12, - 0xd5, 0x4b, 0x82, 0xf0, 0xdd, 0xff, 0x8e, 0xd6, 0xdb, 0x9a, 0x12, 0xd5, 0x9a, 0x5e, - 0xf6, 0xa5, 0xa2, 0xe0, - ], - alpha: [ - 0xa2, 0xe8, 0xb9, 0xe1, 0x6d, 0x6f, 0xf3, 0xca, 0x6c, 0x53, 0xd4, 0xe8, 0x8a, 0xbb, - 0xb9, 0x9b, 0xe7, 0xaf, 0x7e, 0x36, 0x59, 0x63, 0x1f, 0x1e, 0xae, 0x1e, 0xff, 0x23, - 0x87, 0x4d, 0x8e, 0x0c, - ], - rsk: [ - 0x70, 0x3f, 0x32, 0xa3, 0x41, 0x13, 0xea, 0xe1, 0xb0, 0x79, 0x1f, 0xfe, 0x9d, 0x88, - 0x88, 0xf0, 0x01, 0x29, 0x9a, 0xe5, 0x19, 0x68, 0x60, 0x91, 0x91, 0x48, 0x99, 0xef, - 0xcc, 0x6c, 0x66, 0x01, - ], - rvk: [ - 0xeb, 0x92, 0x97, 0x03, 0x6c, 0xf5, 0x17, 0xe1, 0x5e, 0x9e, 0xfe, 0x39, 0x75, 0x32, - 0x8d, 0xb4, 0x8e, 0xe7, 0xc2, 0x69, 0x4e, 0x94, 0x6d, 0xb2, 0x5f, 0x52, 0x87, 0x88, - 0xf6, 0xa1, 0xdb, 0x14, - ], - m: [ - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, - ], - sig: [ - 0x64, 0xab, 0xd1, 0x25, 0xbf, 0xc4, 0xc6, 0x54, 0xfa, 0xf2, 0xb6, 0xdd, 0x75, 0x3e, - 0xc6, 0x90, 0x22, 0x4d, 0xbc, 0xab, 0x8c, 0xd6, 0x32, 0xdd, 0x59, 0x3c, 0x91, 0xce, - 0x3a, 0xb0, 0xbc, 0xad, 0xca, 0x92, 0x76, 0x34, 0x02, 0x1c, 0x31, 0x47, 0x6c, 0x78, - 0xc5, 0xac, 0x7c, 0xcc, 0xab, 0xbd, 0x6f, 0x92, 0x7d, 0xf2, 0x05, 0xea, 0xa7, 0x07, - 0xcc, 0x00, 0xd4, 0x7d, 0x39, 0xf3, 0xe4, 0x0c, - ], - rsig: [ - 0xeb, 0x7a, 0x06, 0x5d, 0x75, 0xf8, 0x45, 0xdc, 0x09, 0x41, 0xb7, 0x09, 0xc0, 0xb1, - 0x49, 0xea, 0xfd, 0x80, 0x5e, 0xa5, 0x8f, 0x38, 0x0b, 0x92, 0xb9, 0xd3, 0x10, 0x8a, - 0x56, 0x1b, 0xda, 0x17, 0x85, 0xdf, 0x8f, 0x10, 0x1e, 0x0e, 0x14, 0x0f, 0xca, 0xee, - 0x99, 0xb7, 0xdb, 0xb7, 0xdf, 0xbf, 0x7e, 0x61, 0xf3, 0xa1, 0x2f, 0x46, 0x09, 0x50, - 0x69, 0xe0, 0x6e, 0x88, 0x96, 0xa9, 0xe4, 0x04, - ], - }, - ]; - - for tv in test_vectors { - let sk = PrivateKey::::read(&tv.sk[..]).unwrap(); - let vk = PublicKey::::read(&tv.vk[..], &JUBJUB).unwrap(); - let rvk = PublicKey::::read(&tv.rvk[..], &JUBJUB).unwrap(); - let sig = Signature::read(&tv.sig[..]).unwrap(); - let rsig = Signature::read(&tv.rsig[..]).unwrap(); - - let mut alpha_repr = <::Fs as PrimeField>::Repr::default(); - alpha_repr.read_le(&tv.alpha[..]).unwrap(); - let alpha = ::Fs::from_repr(alpha_repr).unwrap(); - - { - let mut vec = Vec::new(); - sk.randomize(alpha.clone()).write(&mut vec).unwrap(); - assert_eq!(&vec, &tv.rsk); - } - { - let mut vec = Vec::new(); - vk.randomize(alpha, FixedGenerators::SpendingKeyGenerator, &JUBJUB) - .write(&mut vec) - .unwrap(); - assert_eq!(&vec, &tv.rvk); - } - - assert!(vk.verify(&tv.m, &sig, FixedGenerators::SpendingKeyGenerator, &JUBJUB)); - assert!(rvk.verify(&tv.m, &rsig, FixedGenerators::SpendingKeyGenerator, &JUBJUB)); - assert!(!vk.verify(&tv.m, &rsig, FixedGenerators::SpendingKeyGenerator, &JUBJUB)); - assert!(!rvk.verify(&tv.m, &sig, FixedGenerators::SpendingKeyGenerator, &JUBJUB)); - } -} diff --git a/pairing/.gitignore b/pairing/.gitignore deleted file mode 100644 index 4308d82..0000000 --- a/pairing/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -target/ -**/*.rs.bk -Cargo.lock diff --git a/pairing/COPYRIGHT b/pairing/COPYRIGHT deleted file mode 100644 index c3876a4..0000000 --- a/pairing/COPYRIGHT +++ /dev/null @@ -1,14 +0,0 @@ -Copyrights in the "pairing" library are retained by their contributors. No -copyright assignment is required to contribute to the "pairing" library. - -The "pairing" library is licensed under either of - - * Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT) - -at your option. - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/pairing/Cargo.toml b/pairing/Cargo.toml deleted file mode 100644 index 68971c3..0000000 --- a/pairing/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "pairing" - -# Remember to change version string in README.md. -version = "0.14.2" -authors = [ - "Sean Bowe ", - "Jack Grigg ", -] -license = "MIT/Apache-2.0" - -description = "Pairing-friendly elliptic curve library" -documentation = "https://docs.rs/pairing/" -homepage = "https://github.com/ebfull/pairing" -repository = "https://github.com/ebfull/pairing" - -[dependencies] -rand = "0.4" -byteorder = "1" -ff = { version = "0.4", features = ["derive"] } -group = "0.1" - -[features] -unstable-features = ["expose-arith"] -expose-arith = [] -default = [] diff --git a/pairing/LICENSE-APACHE b/pairing/LICENSE-APACHE deleted file mode 100644 index 16fe87b..0000000 --- a/pairing/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. diff --git a/pairing/LICENSE-MIT b/pairing/LICENSE-MIT deleted file mode 100644 index 31aa793..0000000 --- a/pairing/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/pairing/README.md b/pairing/README.md deleted file mode 100644 index bf386de..0000000 --- a/pairing/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# pairing [![Crates.io](https://img.shields.io/crates/v/pairing.svg)](https://crates.io/crates/pairing) # - -This is a Rust crate for using pairing-friendly elliptic curves. Currently, only the [BLS12-381](https://z.cash/blog/new-snark-curve.html) construction is implemented. - -## [Documentation](https://docs.rs/pairing/) - -Bring the `pairing` crate into your project just as you normally would. - -## Security Warnings - -This library does not make any guarantees about constant-time operations, memory access patterns, or resistance to side-channel attacks. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/pairing/benches/bls12_381/ec.rs b/pairing/benches/bls12_381/ec.rs deleted file mode 100644 index d8f6618..0000000 --- a/pairing/benches/bls12_381/ec.rs +++ /dev/null @@ -1,127 +0,0 @@ -mod g1 { - use rand::{Rand, SeedableRng, XorShiftRng}; - - use group::CurveProjective; - use pairing::bls12_381::*; - - #[bench] - fn bench_g1_mul_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(G1, Fr)> = (0..SAMPLES) - .map(|_| (G1::rand(&mut rng), Fr::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.mul_assign(v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); - } - - #[bench] - fn bench_g1_add_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(G1, G1)> = (0..SAMPLES) - .map(|_| (G1::rand(&mut rng), G1::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.add_assign(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); - } - - #[bench] - fn bench_g1_add_assign_mixed(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(G1, G1Affine)> = (0..SAMPLES) - .map(|_| (G1::rand(&mut rng), G1::rand(&mut rng).into())) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.add_assign_mixed(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); - } -} - -mod g2 { - use rand::{Rand, SeedableRng, XorShiftRng}; - - use group::CurveProjective; - use pairing::bls12_381::*; - - #[bench] - fn bench_g2_mul_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(G2, Fr)> = (0..SAMPLES) - .map(|_| (G2::rand(&mut rng), Fr::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.mul_assign(v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); - } - - #[bench] - fn bench_g2_add_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(G2, G2)> = (0..SAMPLES) - .map(|_| (G2::rand(&mut rng), G2::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.add_assign(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); - } - - #[bench] - fn bench_g2_add_assign_mixed(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(G2, G2Affine)> = (0..SAMPLES) - .map(|_| (G2::rand(&mut rng), G2::rand(&mut rng).into())) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.add_assign_mixed(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); - } -} diff --git a/pairing/benches/bls12_381/fq.rs b/pairing/benches/bls12_381/fq.rs deleted file mode 100644 index 053a10c..0000000 --- a/pairing/benches/bls12_381/fq.rs +++ /dev/null @@ -1,268 +0,0 @@ -use rand::{Rand, SeedableRng, XorShiftRng}; - -use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField}; -use pairing::bls12_381::*; - -#[bench] -fn bench_fq_repr_add_nocarry(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES) - .map(|_| { - let mut tmp1 = FqRepr::rand(&mut rng); - let mut tmp2 = FqRepr::rand(&mut rng); - // Shave a few bits off to avoid overflow. - for _ in 0..3 { - tmp1.div2(); - tmp2.div2(); - } - (tmp1, tmp2) - }) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.add_nocarry(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq_repr_sub_noborrow(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES) - .map(|_| { - let tmp1 = FqRepr::rand(&mut rng); - let mut tmp2 = tmp1; - // Ensure tmp2 is smaller than tmp1. - for _ in 0..10 { - tmp2.div2(); - } - (tmp1, tmp2) - }) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.sub_noborrow(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq_repr_num_bits(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let tmp = v[count].num_bits(); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq_repr_mul2(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count]; - tmp.mul2(); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq_repr_div2(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count]; - tmp.div2(); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq_add_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(Fq, Fq)> = (0..SAMPLES) - .map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.add_assign(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq_sub_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(Fq, Fq)> = (0..SAMPLES) - .map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.sub_assign(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq_mul_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(Fq, Fq)> = (0..SAMPLES) - .map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.mul_assign(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq_square(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count]; - tmp.square(); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq_inverse(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - count = (count + 1) % SAMPLES; - v[count].inverse() - }); -} - -#[bench] -fn bench_fq_negate(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count]; - tmp.negate(); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq_sqrt(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES) - .map(|_| { - let mut tmp = Fq::rand(&mut rng); - tmp.square(); - tmp - }) - .collect(); - - let mut count = 0; - b.iter(|| { - count = (count + 1) % SAMPLES; - v[count].sqrt() - }); -} - -#[bench] -fn bench_fq_into_repr(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - count = (count + 1) % SAMPLES; - v[count].into_repr() - }); -} - -#[bench] -fn bench_fq_from_repr(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES) - .map(|_| Fq::rand(&mut rng).into_repr()) - .collect(); - - let mut count = 0; - b.iter(|| { - count = (count + 1) % SAMPLES; - Fq::from_repr(v[count]) - }); -} diff --git a/pairing/benches/bls12_381/fq12.rs b/pairing/benches/bls12_381/fq12.rs deleted file mode 100644 index 84daca2..0000000 --- a/pairing/benches/bls12_381/fq12.rs +++ /dev/null @@ -1,94 +0,0 @@ -use rand::{Rand, SeedableRng, XorShiftRng}; - -use ff::Field; -use pairing::bls12_381::*; - -#[bench] -fn bench_fq12_add_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(Fq12, Fq12)> = (0..SAMPLES) - .map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.add_assign(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq12_sub_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(Fq12, Fq12)> = (0..SAMPLES) - .map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.sub_assign(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq12_mul_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(Fq12, Fq12)> = (0..SAMPLES) - .map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.mul_assign(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq12_squaring(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| Fq12::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count]; - tmp.square(); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq12_inverse(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| Fq12::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let tmp = v[count].inverse(); - count = (count + 1) % SAMPLES; - tmp - }); -} diff --git a/pairing/benches/bls12_381/fq2.rs b/pairing/benches/bls12_381/fq2.rs deleted file mode 100644 index 521b6ab..0000000 --- a/pairing/benches/bls12_381/fq2.rs +++ /dev/null @@ -1,110 +0,0 @@ -use rand::{Rand, SeedableRng, XorShiftRng}; - -use ff::{Field, SqrtField}; -use pairing::bls12_381::*; - -#[bench] -fn bench_fq2_add_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(Fq2, Fq2)> = (0..SAMPLES) - .map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.add_assign(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq2_sub_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(Fq2, Fq2)> = (0..SAMPLES) - .map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.sub_assign(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq2_mul_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(Fq2, Fq2)> = (0..SAMPLES) - .map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.mul_assign(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq2_squaring(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count]; - tmp.square(); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq2_inverse(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let tmp = v[count].inverse(); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fq2_sqrt(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let tmp = v[count].sqrt(); - count = (count + 1) % SAMPLES; - tmp - }); -} diff --git a/pairing/benches/bls12_381/fr.rs b/pairing/benches/bls12_381/fr.rs deleted file mode 100644 index 13b0d0e..0000000 --- a/pairing/benches/bls12_381/fr.rs +++ /dev/null @@ -1,268 +0,0 @@ -use rand::{Rand, SeedableRng, XorShiftRng}; - -use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField}; -use pairing::bls12_381::*; - -#[bench] -fn bench_fr_repr_add_nocarry(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES) - .map(|_| { - let mut tmp1 = FrRepr::rand(&mut rng); - let mut tmp2 = FrRepr::rand(&mut rng); - // Shave a few bits off to avoid overflow. - for _ in 0..3 { - tmp1.div2(); - tmp2.div2(); - } - (tmp1, tmp2) - }) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.add_nocarry(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fr_repr_sub_noborrow(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES) - .map(|_| { - let tmp1 = FrRepr::rand(&mut rng); - let mut tmp2 = tmp1; - // Ensure tmp2 is smaller than tmp1. - for _ in 0..10 { - tmp2.div2(); - } - (tmp1, tmp2) - }) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.sub_noborrow(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fr_repr_num_bits(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let tmp = v[count].num_bits(); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fr_repr_mul2(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count]; - tmp.mul2(); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fr_repr_div2(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count]; - tmp.div2(); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fr_add_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(Fr, Fr)> = (0..SAMPLES) - .map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.add_assign(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fr_sub_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(Fr, Fr)> = (0..SAMPLES) - .map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.sub_assign(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fr_mul_assign(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(Fr, Fr)> = (0..SAMPLES) - .map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count].0; - tmp.mul_assign(&v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fr_square(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count]; - tmp.square(); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fr_inverse(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - count = (count + 1) % SAMPLES; - v[count].inverse() - }); -} - -#[bench] -fn bench_fr_negate(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let mut tmp = v[count]; - tmp.negate(); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_fr_sqrt(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES) - .map(|_| { - let mut tmp = Fr::rand(&mut rng); - tmp.square(); - tmp - }) - .collect(); - - let mut count = 0; - b.iter(|| { - count = (count + 1) % SAMPLES; - v[count].sqrt() - }); -} - -#[bench] -fn bench_fr_into_repr(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - count = (count + 1) % SAMPLES; - v[count].into_repr() - }); -} - -#[bench] -fn bench_fr_from_repr(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES) - .map(|_| Fr::rand(&mut rng).into_repr()) - .collect(); - - let mut count = 0; - b.iter(|| { - count = (count + 1) % SAMPLES; - Fr::from_repr(v[count]) - }); -} diff --git a/pairing/benches/bls12_381/mod.rs b/pairing/benches/bls12_381/mod.rs deleted file mode 100644 index 96bcdd5..0000000 --- a/pairing/benches/bls12_381/mod.rs +++ /dev/null @@ -1,107 +0,0 @@ -mod ec; -mod fq; -mod fq12; -mod fq2; -mod fr; - -use rand::{Rand, SeedableRng, XorShiftRng}; - -use pairing::bls12_381::*; -use pairing::{Engine, PairingCurveAffine}; - -#[bench] -fn bench_pairing_g1_preparation(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| G1::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let tmp = G1Affine::from(v[count]).prepare(); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_pairing_g2_preparation(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES).map(|_| G2::rand(&mut rng)).collect(); - - let mut count = 0; - b.iter(|| { - let tmp = G2Affine::from(v[count]).prepare(); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_pairing_miller_loop(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(G1Prepared, G2Prepared)> = (0..SAMPLES) - .map(|_| { - ( - G1Affine::from(G1::rand(&mut rng)).prepare(), - G2Affine::from(G2::rand(&mut rng)).prepare(), - ) - }) - .collect(); - - let mut count = 0; - b.iter(|| { - let tmp = Bls12::miller_loop(&[(&v[count].0, &v[count].1)]); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_pairing_final_exponentiation(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec = (0..SAMPLES) - .map(|_| { - ( - G1Affine::from(G1::rand(&mut rng)).prepare(), - G2Affine::from(G2::rand(&mut rng)).prepare(), - ) - }) - .map(|(ref p, ref q)| Bls12::miller_loop(&[(p, q)])) - .collect(); - - let mut count = 0; - b.iter(|| { - let tmp = Bls12::final_exponentiation(&v[count]); - count = (count + 1) % SAMPLES; - tmp - }); -} - -#[bench] -fn bench_pairing_full(b: &mut ::test::Bencher) { - const SAMPLES: usize = 1000; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let v: Vec<(G1, G2)> = (0..SAMPLES) - .map(|_| (G1::rand(&mut rng), G2::rand(&mut rng))) - .collect(); - - let mut count = 0; - b.iter(|| { - let tmp = Bls12::pairing(v[count].0, v[count].1); - count = (count + 1) % SAMPLES; - tmp - }); -} diff --git a/pairing/benches/pairing_benches.rs b/pairing/benches/pairing_benches.rs deleted file mode 100644 index d76e50b..0000000 --- a/pairing/benches/pairing_benches.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(test)] - -extern crate ff; -extern crate group; -extern crate pairing; -extern crate rand; -extern crate test; - -mod bls12_381; diff --git a/pairing/src/bls12_381/README.md b/pairing/src/bls12_381/README.md deleted file mode 100644 index d3811a1..0000000 --- a/pairing/src/bls12_381/README.md +++ /dev/null @@ -1,71 +0,0 @@ -# BLS12-381 - -This is an implementation of the BLS12-381 pairing-friendly elliptic curve construction. - -## BLS12 Parameterization - -BLS12 curves are parameterized by a value *x* such that the base field modulus *q* and subgroup *r* can be computed by: - -* q = (x - 1)2 ((x4 - x2 + 1) / 3) + x -* r = (x4 - x2 + 1) - -Given primes *q* and *r* parameterized as above, we can easily construct an elliptic curve over the prime field F*q* which contains a subgroup of order *r* such that *r* | (*q*12 - 1), giving it an embedding degree of 12. Instantiating its sextic twist over an extension field Fq2 gives rise to an efficient bilinear pairing function between elements of the order *r* subgroups of either curves, into an order *r* multiplicative subgroup of Fq12. - -In zk-SNARK schemes, we require Fr with large 2n roots of unity for performing efficient fast-fourier transforms. As such, guaranteeing that large 2n | (r - 1), or equivalently that *x* has a large 2n factor, gives rise to BLS12 curves suitable for zk-SNARKs. - -Due to recent research, it is estimated by many that *q* should be approximately 384 bits to target 128-bit security. Conveniently, *r* is approximately 256 bits when *q* is approximately 384 bits, making BLS12 curves ideal for 128-bit security. It also makes them ideal for many zk-SNARK applications, as the scalar field can be used for keying material such as embedded curve constructions. - -Many curves match our descriptions, but we require some extra properties for efficiency purposes: - -* *q* should be smaller than 2383, and *r* should be smaller than 2255, so that the most significant bit is unset when using 64-bit or 32-bit limbs. This allows for cheap reductions. -* Fq12 is typically constructed using towers of extension fields. As a byproduct of [research](https://eprint.iacr.org/2011/465.pdf) for BLS curves of embedding degree 24, we can identify subfamilies of BLS12 curves (for our purposes, where x mod 72 = {16, 64}) that produce efficient extension field towers and twisting isomorphisms. -* We desire *x* of small Hamming weight, to increase the performance of the pairing function. - -## BLS12-381 Instantiation - -The BLS12-381 construction is instantiated by `x = -0xd201000000010000`, which produces the largest `q` and smallest Hamming weight of `x` that meets the above requirements. This produces: - -* q = `0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab` (381 bits) -* r = `0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001` (255 bits) - -Our extension field tower is constructed as follows: - -1. Fq2 is constructed as Fq(u) / (u2 - β) where β = -1. -2. Fq6 is constructed as Fq2(v) / (v3 - ξ) where ξ = u + 1 -3. Fq12 is constructed as Fq6(w) / (w2 - γ) where γ = v - -Now, we instantiate the elliptic curve E(Fq) : y2 = x3 + 4, and the elliptic curve E'(Fq2) : y2 = x3 + 4(u + 1). - -The group G1 is the *r* order subgroup of E, which has cofactor (x - 1)2 / 3. The group G2 is the *r* order subgroup of E', which has cofactor (x8 - 4x7 + 5x6 - 4x4 + 6x3 - 4x2 - 4x + 13) / 9. - -### Generators - -The generators of G1 and G2 are computed by finding the lexicographically smallest valid `x`-coordinate, and its lexicographically smallest `y`-coordinate and scaling it by the cofactor such that the result is not the point at infinity. - -#### G1 - -``` -x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507 -y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569 -``` - -#### G2 - -``` -x = 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758*u + 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160 -y = 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582*u + 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905 -``` - -### Serialization - -* Fq elements are encoded in big-endian form. They occupy 48 bytes in this form. -* Fq2 elements are encoded in big-endian form, meaning that the Fq element c0 + c1 * u is represented by the Fq element c1 followed by the Fq element c0. This means Fq2 elements occupy 96 bytes in this form. -* The group G1 uses Fq elements for coordinates. The group G2 uses Fq2 elements for coordinates. -* G1 and G2 elements can be encoded in uncompressed form (the x-coordinate followed by the y-coordinate) or in compressed form (just the x-coordinate). G1 elements occupy 96 bytes in uncompressed form, and 48 bytes in compressed form. G2 elements occupy 192 bytes in uncompressed form, and 96 bytes in compressed form. - -The most-significant three bits of a G1 or G2 encoding should be masked away before the coordinate(s) are interpreted. These bits are used to unambiguously represent the underlying element: - -* The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. -* The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. -* The third-most significant bit is set if (and only if) this point is in compressed form _and_ it is not the point at infinity _and_ its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. - diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs deleted file mode 100644 index f5a6d8f..0000000 --- a/pairing/src/bls12_381/ec.rs +++ /dev/null @@ -1,2030 +0,0 @@ -macro_rules! curve_impl { - ( - $name:expr, - $projective:ident, - $affine:ident, - $prepared:ident, - $basefield:ident, - $scalarfield:ident, - $uncompressed:ident, - $compressed:ident, - $pairing:ident - ) => { - #[derive(Copy, Clone, PartialEq, Eq, Debug)] - pub struct $affine { - pub(crate) x: $basefield, - pub(crate) y: $basefield, - pub(crate) infinity: bool - } - - impl ::std::fmt::Display for $affine - { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - if self.infinity { - write!(f, "{}(Infinity)", $name) - } else { - write!(f, "{}(x={}, y={})", $name, self.x, self.y) - } - } - } - - #[derive(Copy, Clone, Debug, Eq)] - pub struct $projective { - pub(crate) x: $basefield, - pub(crate) y: $basefield, - pub(crate) z: $basefield - } - - impl ::std::fmt::Display for $projective - { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "{}", self.into_affine()) - } - } - - impl PartialEq for $projective { - fn eq(&self, other: &$projective) -> bool { - if self.is_zero() { - return other.is_zero(); - } - - if other.is_zero() { - return false; - } - - // The points (X, Y, Z) and (X', Y', Z') - // are equal when (X * Z^2) = (X' * Z'^2) - // and (Y * Z^3) = (Y' * Z'^3). - - let mut z1 = self.z; - z1.square(); - let mut z2 = other.z; - z2.square(); - - let mut tmp1 = self.x; - tmp1.mul_assign(&z2); - - let mut tmp2 = other.x; - tmp2.mul_assign(&z1); - - if tmp1 != tmp2 { - return false; - } - - z1.mul_assign(&self.z); - z2.mul_assign(&other.z); - z2.mul_assign(&self.y); - z1.mul_assign(&other.y); - - if z1 != z2 { - return false; - } - - true - } - } - - impl $affine { - fn mul_bits>(&self, bits: BitIterator) -> $projective { - let mut res = $projective::zero(); - for i in bits { - res.double(); - if i { res.add_assign_mixed(self) } - } - res - } - - /// Attempts to construct an affine point given an x-coordinate. The - /// point is not guaranteed to be in the prime order subgroup. - /// - /// If and only if `greatest` is set will the lexicographically - /// largest y-coordinate be selected. - fn get_point_from_x(x: $basefield, greatest: bool) -> Option<$affine> { - // Compute x^3 + b - let mut x3b = x; - x3b.square(); - x3b.mul_assign(&x); - x3b.add_assign(&$affine::get_coeff_b()); - - x3b.sqrt().map(|y| { - let mut negy = y; - negy.negate(); - - $affine { - x: x, - y: if (y < negy) ^ greatest { - y - } else { - negy - }, - infinity: false - } - }) - } - - fn is_on_curve(&self) -> bool { - if self.is_zero() { - true - } else { - // Check that the point is on the curve - let mut y2 = self.y; - y2.square(); - - let mut x3b = self.x; - x3b.square(); - x3b.mul_assign(&self.x); - x3b.add_assign(&Self::get_coeff_b()); - - y2 == x3b - } - } - - fn is_in_correct_subgroup_assuming_on_curve(&self) -> bool { - self.mul($scalarfield::char()).is_zero() - } - } - - impl CurveAffine for $affine { - type Engine = Bls12; - type Scalar = $scalarfield; - type Base = $basefield; - type Projective = $projective; - type Uncompressed = $uncompressed; - type Compressed = $compressed; - - fn zero() -> Self { - $affine { - x: $basefield::zero(), - y: $basefield::one(), - infinity: true - } - } - - fn one() -> Self { - Self::get_generator() - } - - fn is_zero(&self) -> bool { - self.infinity - } - - fn mul::Repr>>(&self, by: S) -> $projective { - let bits = BitIterator::new(by.into()); - self.mul_bits(bits) - } - - fn negate(&mut self) { - if !self.is_zero() { - self.y.negate(); - } - } - - fn into_projective(&self) -> $projective { - (*self).into() - } - - } - - impl PairingCurveAffine for $affine { - type Prepared = $prepared; - type Pair = $pairing; - type PairingResult = Fq12; - - fn prepare(&self) -> Self::Prepared { - $prepared::from_affine(*self) - } - - fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult { - self.perform_pairing(other) - } - - } - - impl Rand for $projective { - fn rand(rng: &mut R) -> Self { - loop { - let x = rng.gen(); - let greatest = rng.gen(); - - if let Some(p) = $affine::get_point_from_x(x, greatest) { - let p = p.scale_by_cofactor(); - - if !p.is_zero() { - return p; - } - } - } - } - } - - impl CurveProjective for $projective { - type Engine = Bls12; - type Scalar = $scalarfield; - type Base = $basefield; - type Affine = $affine; - - // The point at infinity is always represented by - // Z = 0. - fn zero() -> Self { - $projective { - x: $basefield::zero(), - y: $basefield::one(), - z: $basefield::zero() - } - } - - fn one() -> Self { - $affine::one().into() - } - - // The point at infinity is always represented by - // Z = 0. - fn is_zero(&self) -> bool { - self.z.is_zero() - } - - fn is_normalized(&self) -> bool { - self.is_zero() || self.z == $basefield::one() - } - - fn batch_normalization(v: &mut [Self]) - { - // Montgomery’s Trick and Fast Implementation of Masked AES - // Genelle, Prouff and Quisquater - // Section 3.2 - - // First pass: compute [a, ab, abc, ...] - let mut prod = Vec::with_capacity(v.len()); - let mut tmp = $basefield::one(); - for g in v.iter_mut() - // Ignore normalized elements - .filter(|g| !g.is_normalized()) - { - tmp.mul_assign(&g.z); - prod.push(tmp); - } - - // Invert `tmp`. - tmp = tmp.inverse().unwrap(); // Guaranteed to be nonzero. - - // Second pass: iterate backwards to compute inverses - for (g, s) in v.iter_mut() - // Backwards - .rev() - // Ignore normalized elements - .filter(|g| !g.is_normalized()) - // Backwards, skip last element, fill in one for last term. - .zip(prod.into_iter().rev().skip(1).chain(Some($basefield::one()))) - { - // tmp := tmp * g.z; g.z := tmp * s = 1/z - let mut newtmp = tmp; - newtmp.mul_assign(&g.z); - g.z = tmp; - g.z.mul_assign(&s); - tmp = newtmp; - } - - // Perform affine transformations - for g in v.iter_mut() - .filter(|g| !g.is_normalized()) - { - let mut z = g.z; // 1/z - z.square(); // 1/z^2 - g.x.mul_assign(&z); // x/z^2 - z.mul_assign(&g.z); // 1/z^3 - g.y.mul_assign(&z); // y/z^3 - g.z = $basefield::one(); // z = 1 - } - } - - fn double(&mut self) { - if self.is_zero() { - return; - } - - // Other than the point at infinity, no points on E or E' - // can double to equal the point at infinity, as y=0 is - // never true for points on the curve. (-4 and -4u-4 - // are not cubic residue in their respective fields.) - - // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l - - // A = X1^2 - let mut a = self.x; - a.square(); - - // B = Y1^2 - let mut b = self.y; - b.square(); - - // C = B^2 - let mut c = b; - c.square(); - - // D = 2*((X1+B)2-A-C) - let mut d = self.x; - d.add_assign(&b); - d.square(); - d.sub_assign(&a); - d.sub_assign(&c); - d.double(); - - // E = 3*A - let mut e = a; - e.double(); - e.add_assign(&a); - - // F = E^2 - let mut f = e; - f.square(); - - // Z3 = 2*Y1*Z1 - self.z.mul_assign(&self.y); - self.z.double(); - - // X3 = F-2*D - self.x = f; - self.x.sub_assign(&d); - self.x.sub_assign(&d); - - // Y3 = E*(D-X3)-8*C - self.y = d; - self.y.sub_assign(&self.x); - self.y.mul_assign(&e); - c.double(); - c.double(); - c.double(); - self.y.sub_assign(&c); - } - - fn add_assign(&mut self, other: &Self) { - if self.is_zero() { - *self = *other; - return; - } - - if other.is_zero() { - return; - } - - // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl - - // Z1Z1 = Z1^2 - let mut z1z1 = self.z; - z1z1.square(); - - // Z2Z2 = Z2^2 - let mut z2z2 = other.z; - z2z2.square(); - - // U1 = X1*Z2Z2 - let mut u1 = self.x; - u1.mul_assign(&z2z2); - - // U2 = X2*Z1Z1 - let mut u2 = other.x; - u2.mul_assign(&z1z1); - - // S1 = Y1*Z2*Z2Z2 - let mut s1 = self.y; - s1.mul_assign(&other.z); - s1.mul_assign(&z2z2); - - // S2 = Y2*Z1*Z1Z1 - let mut s2 = other.y; - s2.mul_assign(&self.z); - s2.mul_assign(&z1z1); - - if u1 == u2 && s1 == s2 { - // The two points are equal, so we double. - self.double(); - } else { - // If we're adding -a and a together, self.z becomes zero as H becomes zero. - - // H = U2-U1 - let mut h = u2; - h.sub_assign(&u1); - - // I = (2*H)^2 - let mut i = h; - i.double(); - i.square(); - - // J = H*I - let mut j = h; - j.mul_assign(&i); - - // r = 2*(S2-S1) - let mut r = s2; - r.sub_assign(&s1); - r.double(); - - // V = U1*I - let mut v = u1; - v.mul_assign(&i); - - // X3 = r^2 - J - 2*V - self.x = r; - self.x.square(); - self.x.sub_assign(&j); - self.x.sub_assign(&v); - self.x.sub_assign(&v); - - // Y3 = r*(V - X3) - 2*S1*J - self.y = v; - self.y.sub_assign(&self.x); - self.y.mul_assign(&r); - s1.mul_assign(&j); // S1 = S1 * J * 2 - s1.double(); - self.y.sub_assign(&s1); - - // Z3 = ((Z1+Z2)^2 - Z1Z1 - Z2Z2)*H - self.z.add_assign(&other.z); - self.z.square(); - self.z.sub_assign(&z1z1); - self.z.sub_assign(&z2z2); - self.z.mul_assign(&h); - } - } - - fn add_assign_mixed(&mut self, other: &Self::Affine) { - if other.is_zero() { - return; - } - - if self.is_zero() { - self.x = other.x; - self.y = other.y; - self.z = $basefield::one(); - return; - } - - // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl - - // Z1Z1 = Z1^2 - let mut z1z1 = self.z; - z1z1.square(); - - // U2 = X2*Z1Z1 - let mut u2 = other.x; - u2.mul_assign(&z1z1); - - // S2 = Y2*Z1*Z1Z1 - let mut s2 = other.y; - s2.mul_assign(&self.z); - s2.mul_assign(&z1z1); - - if self.x == u2 && self.y == s2 { - // The two points are equal, so we double. - self.double(); - } else { - // If we're adding -a and a together, self.z becomes zero as H becomes zero. - - // H = U2-X1 - let mut h = u2; - h.sub_assign(&self.x); - - // HH = H^2 - let mut hh = h; - hh.square(); - - // I = 4*HH - let mut i = hh; - i.double(); - i.double(); - - // J = H*I - let mut j = h; - j.mul_assign(&i); - - // r = 2*(S2-Y1) - let mut r = s2; - r.sub_assign(&self.y); - r.double(); - - // V = X1*I - let mut v = self.x; - v.mul_assign(&i); - - // X3 = r^2 - J - 2*V - self.x = r; - self.x.square(); - self.x.sub_assign(&j); - self.x.sub_assign(&v); - self.x.sub_assign(&v); - - // Y3 = r*(V-X3)-2*Y1*J - j.mul_assign(&self.y); // J = 2*Y1*J - j.double(); - self.y = v; - self.y.sub_assign(&self.x); - self.y.mul_assign(&r); - self.y.sub_assign(&j); - - // Z3 = (Z1+H)^2-Z1Z1-HH - self.z.add_assign(&h); - self.z.square(); - self.z.sub_assign(&z1z1); - self.z.sub_assign(&hh); - } - } - - fn negate(&mut self) { - if !self.is_zero() { - self.y.negate() - } - } - - fn mul_assign::Repr>>(&mut self, other: S) { - let mut res = Self::zero(); - - let mut found_one = false; - - for i in BitIterator::new(other.into()) - { - if found_one { - res.double(); - } else { - found_one = i; - } - - if i { - res.add_assign(self); - } - } - - *self = res; - } - - fn into_affine(&self) -> $affine { - (*self).into() - } - - fn recommended_wnaf_for_scalar(scalar: ::Repr) -> usize { - Self::empirical_recommended_wnaf_for_scalar(scalar) - } - - fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize { - Self::empirical_recommended_wnaf_for_num_scalars(num_scalars) - } - } - - // The affine point X, Y is represented in the jacobian - // coordinates with Z = 1. - impl From<$affine> for $projective { - fn from(p: $affine) -> $projective { - if p.is_zero() { - $projective::zero() - } else { - $projective { - x: p.x, - y: p.y, - z: $basefield::one() - } - } - } - } - - // The projective point X, Y, Z is represented in the affine - // coordinates as X/Z^2, Y/Z^3. - impl From<$projective> for $affine { - fn from(p: $projective) -> $affine { - if p.is_zero() { - $affine::zero() - } else if p.z == $basefield::one() { - // If Z is one, the point is already normalized. - $affine { - x: p.x, - y: p.y, - infinity: false - } - } else { - // Z is nonzero, so it must have an inverse in a field. - let zinv = p.z.inverse().unwrap(); - let mut zinv_powered = zinv; - zinv_powered.square(); - - // X/Z^2 - let mut x = p.x; - x.mul_assign(&zinv_powered); - - // Y/Z^3 - let mut y = p.y; - zinv_powered.mul_assign(&zinv); - y.mul_assign(&zinv_powered); - - $affine { - x: x, - y: y, - infinity: false - } - } - } - } - } -} - -pub mod g1 { - use super::super::{Bls12, Fq, Fq12, FqRepr, Fr, FrRepr}; - use super::g2::G2Affine; - use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; - use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; - use rand::{Rand, Rng}; - use std::fmt; - use {Engine, PairingCurveAffine}; - - curve_impl!( - "G1", - G1, - G1Affine, - G1Prepared, - Fq, - Fr, - G1Uncompressed, - G1Compressed, - G2Affine - ); - - #[derive(Copy, Clone)] - pub struct G1Uncompressed([u8; 96]); - - impl AsRef<[u8]> for G1Uncompressed { - fn as_ref(&self) -> &[u8] { - &self.0 - } - } - - impl AsMut<[u8]> for G1Uncompressed { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0 - } - } - - impl fmt::Debug for G1Uncompressed { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.0[..].fmt(formatter) - } - } - - impl EncodedPoint for G1Uncompressed { - type Affine = G1Affine; - - fn empty() -> Self { - G1Uncompressed([0; 96]) - } - fn size() -> usize { - 96 - } - fn into_affine(&self) -> Result { - let affine = self.into_affine_unchecked()?; - - if !affine.is_on_curve() { - Err(GroupDecodingError::NotOnCurve) - } else if !affine.is_in_correct_subgroup_assuming_on_curve() { - Err(GroupDecodingError::NotInSubgroup) - } else { - Ok(affine) - } - } - fn into_affine_unchecked(&self) -> Result { - // Create a copy of this representation. - let mut copy = self.0; - - if copy[0] & (1 << 7) != 0 { - // Distinguisher bit is set, but this should be uncompressed! - return Err(GroupDecodingError::UnexpectedCompressionMode); - } - - if copy[0] & (1 << 6) != 0 { - // This is the point at infinity, which means that if we mask away - // the first two bits, the entire representation should consist - // of zeroes. - copy[0] &= 0x3f; - - if copy.iter().all(|b| *b == 0) { - Ok(G1Affine::zero()) - } else { - Err(GroupDecodingError::UnexpectedInformation) - } - } else { - if copy[0] & (1 << 5) != 0 { - // The bit indicating the y-coordinate should be lexicographically - // largest is set, but this is an uncompressed element. - return Err(GroupDecodingError::UnexpectedInformation); - } - - // Unset the three most significant bits. - copy[0] &= 0x1f; - - let mut x = FqRepr([0; 6]); - let mut y = FqRepr([0; 6]); - - { - let mut reader = ©[..]; - - x.read_be(&mut reader).unwrap(); - y.read_be(&mut reader).unwrap(); - } - - Ok(G1Affine { - x: Fq::from_repr(x).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("x coordinate", e) - })?, - y: Fq::from_repr(y).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("y coordinate", e) - })?, - infinity: false, - }) - } - } - fn from_affine(affine: G1Affine) -> Self { - let mut res = Self::empty(); - - if affine.is_zero() { - // Set the second-most significant bit to indicate this point - // is at infinity. - res.0[0] |= 1 << 6; - } else { - let mut writer = &mut res.0[..]; - - affine.x.into_repr().write_be(&mut writer).unwrap(); - affine.y.into_repr().write_be(&mut writer).unwrap(); - } - - res - } - } - - #[derive(Copy, Clone)] - pub struct G1Compressed([u8; 48]); - - impl AsRef<[u8]> for G1Compressed { - fn as_ref(&self) -> &[u8] { - &self.0 - } - } - - impl AsMut<[u8]> for G1Compressed { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0 - } - } - - impl fmt::Debug for G1Compressed { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.0[..].fmt(formatter) - } - } - - impl EncodedPoint for G1Compressed { - type Affine = G1Affine; - - fn empty() -> Self { - G1Compressed([0; 48]) - } - fn size() -> usize { - 48 - } - fn into_affine(&self) -> Result { - let affine = self.into_affine_unchecked()?; - - // NB: Decompression guarantees that it is on the curve already. - - if !affine.is_in_correct_subgroup_assuming_on_curve() { - Err(GroupDecodingError::NotInSubgroup) - } else { - Ok(affine) - } - } - fn into_affine_unchecked(&self) -> Result { - // Create a copy of this representation. - let mut copy = self.0; - - if copy[0] & (1 << 7) == 0 { - // Distinguisher bit isn't set. - return Err(GroupDecodingError::UnexpectedCompressionMode); - } - - if copy[0] & (1 << 6) != 0 { - // This is the point at infinity, which means that if we mask away - // the first two bits, the entire representation should consist - // of zeroes. - copy[0] &= 0x3f; - - if copy.iter().all(|b| *b == 0) { - Ok(G1Affine::zero()) - } else { - Err(GroupDecodingError::UnexpectedInformation) - } - } else { - // Determine if the intended y coordinate must be greater - // lexicographically. - let greatest = copy[0] & (1 << 5) != 0; - - // Unset the three most significant bits. - copy[0] &= 0x1f; - - let mut x = FqRepr([0; 6]); - - { - let mut reader = ©[..]; - - x.read_be(&mut reader).unwrap(); - } - - // Interpret as Fq element. - let x = Fq::from_repr(x) - .map_err(|e| GroupDecodingError::CoordinateDecodingError("x coordinate", e))?; - - G1Affine::get_point_from_x(x, greatest).ok_or(GroupDecodingError::NotOnCurve) - } - } - fn from_affine(affine: G1Affine) -> Self { - let mut res = Self::empty(); - - if affine.is_zero() { - // Set the second-most significant bit to indicate this point - // is at infinity. - res.0[0] |= 1 << 6; - } else { - { - let mut writer = &mut res.0[..]; - - affine.x.into_repr().write_be(&mut writer).unwrap(); - } - - let mut negy = affine.y; - negy.negate(); - - // Set the third most significant bit if the correct y-coordinate - // is lexicographically largest. - if affine.y > negy { - res.0[0] |= 1 << 5; - } - } - - // Set highest bit to distinguish this as a compressed element. - res.0[0] |= 1 << 7; - - res - } - } - - impl G1Affine { - fn scale_by_cofactor(&self) -> G1 { - // G1 cofactor = (x - 1)^2 / 3 = 76329603384216526031706109802092473003 - let cofactor = BitIterator::new([0x8c00aaab0000aaab, 0x396c8c005555e156]); - self.mul_bits(cofactor) - } - - fn get_generator() -> Self { - G1Affine { - x: super::super::fq::G1_GENERATOR_X, - y: super::super::fq::G1_GENERATOR_Y, - infinity: false, - } - } - - fn get_coeff_b() -> Fq { - super::super::fq::B_COEFF - } - - fn perform_pairing(&self, other: &G2Affine) -> Fq12 { - super::super::Bls12::pairing(*self, *other) - } - } - - impl G1 { - fn empirical_recommended_wnaf_for_scalar(scalar: FrRepr) -> usize { - let num_bits = scalar.num_bits() as usize; - - if num_bits >= 130 { - 4 - } else if num_bits >= 34 { - 3 - } else { - 2 - } - } - - fn empirical_recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize { - const RECOMMENDATIONS: [usize; 12] = - [1, 3, 7, 20, 43, 120, 273, 563, 1630, 3128, 7933, 62569]; - - let mut ret = 4; - for r in &RECOMMENDATIONS { - if num_scalars > *r { - ret += 1; - } else { - break; - } - } - - ret - } - } - - #[derive(Clone, Debug)] - pub struct G1Prepared(pub(crate) G1Affine); - - impl G1Prepared { - pub fn is_zero(&self) -> bool { - self.0.is_zero() - } - - pub fn from_affine(p: G1Affine) -> Self { - G1Prepared(p) - } - } - - #[test] - fn g1_generator() { - use SqrtField; - - let mut x = Fq::zero(); - let mut i = 0; - loop { - // y^2 = x^3 + b - let mut rhs = x; - rhs.square(); - rhs.mul_assign(&x); - rhs.add_assign(&G1Affine::get_coeff_b()); - - if let Some(y) = rhs.sqrt() { - let yrepr = y.into_repr(); - let mut negy = y; - negy.negate(); - let negyrepr = negy.into_repr(); - - let p = G1Affine { - x: x, - y: if yrepr < negyrepr { y } else { negy }, - infinity: false, - }; - assert!(!p.is_in_correct_subgroup_assuming_on_curve()); - - let g1 = p.scale_by_cofactor(); - if !g1.is_zero() { - assert_eq!(i, 4); - let g1 = G1Affine::from(g1); - - assert!(g1.is_in_correct_subgroup_assuming_on_curve()); - - assert_eq!(g1, G1Affine::one()); - break; - } - } - - i += 1; - x.add_assign(&Fq::one()); - } - } - - #[test] - fn g1_test_is_valid() { - // Reject point on isomorphic twist (b = 24) - { - let p = G1Affine { - x: Fq::from_repr(FqRepr([ - 0xc58d887b66c035dc, - 0x10cbfd301d553822, - 0xaf23e064f1131ee5, - 0x9fe83b1b4a5d648d, - 0xf583cc5a508f6a40, - 0xc3ad2aefde0bb13, - ])).unwrap(), - y: Fq::from_repr(FqRepr([ - 0x60aa6f9552f03aae, - 0xecd01d5181300d35, - 0x8af1cdb8aa8ce167, - 0xe760f57922998c9d, - 0x953703f5795a39e5, - 0xfe3ae0922df702c, - ])).unwrap(), - infinity: false, - }; - assert!(!p.is_on_curve()); - assert!(p.is_in_correct_subgroup_assuming_on_curve()); - } - - // Reject point on a twist (b = 3) - { - let p = G1Affine { - x: Fq::from_repr(FqRepr([ - 0xee6adf83511e15f5, - 0x92ddd328f27a4ba6, - 0xe305bd1ac65adba7, - 0xea034ee2928b30a8, - 0xbd8833dc7c79a7f7, - 0xe45c9f0c0438675, - ])).unwrap(), - y: Fq::from_repr(FqRepr([ - 0x3b450eb1ab7b5dad, - 0xa65cb81e975e8675, - 0xaa548682b21726e5, - 0x753ddf21a2601d20, - 0x532d0b640bd3ff8b, - 0x118d2c543f031102, - ])).unwrap(), - infinity: false, - }; - assert!(!p.is_on_curve()); - assert!(!p.is_in_correct_subgroup_assuming_on_curve()); - } - - // Reject point in an invalid subgroup - // There is only one r-order subgroup, as r does not divide the cofactor. - { - let p = G1Affine { - x: Fq::from_repr(FqRepr([ - 0x76e1c971c6db8fe8, - 0xe37e1a610eff2f79, - 0x88ae9c499f46f0c0, - 0xf35de9ce0d6b4e84, - 0x265bddd23d1dec54, - 0x12a8778088458308, - ])).unwrap(), - y: Fq::from_repr(FqRepr([ - 0x8a22defa0d526256, - 0xc57ca55456fcb9ae, - 0x1ba194e89bab2610, - 0x921beef89d4f29df, - 0x5b6fda44ad85fa78, - 0xed74ab9f302cbe0, - ])).unwrap(), - infinity: false, - }; - assert!(p.is_on_curve()); - assert!(!p.is_in_correct_subgroup_assuming_on_curve()); - } - } - - #[test] - fn test_g1_addition_correctness() { - let mut p = G1 { - x: Fq::from_repr(FqRepr([ - 0x47fd1f891d6e8bbf, - 0x79a3b0448f31a2aa, - 0x81f3339e5f9968f, - 0x485e77d50a5df10d, - 0x4c6fcac4b55fd479, - 0x86ed4d9906fb064, - ])).unwrap(), - y: Fq::from_repr(FqRepr([ - 0xd25ee6461538c65, - 0x9f3bbb2ecd3719b9, - 0xa06fd3f1e540910d, - 0xcefca68333c35288, - 0x570c8005f8573fa6, - 0x152ca696fe034442, - ])).unwrap(), - z: Fq::one(), - }; - - p.add_assign(&G1 { - x: Fq::from_repr(FqRepr([ - 0xeec78f3096213cbf, - 0xa12beb1fea1056e6, - 0xc286c0211c40dd54, - 0x5f44314ec5e3fb03, - 0x24e8538737c6e675, - 0x8abd623a594fba8, - ])).unwrap(), - y: Fq::from_repr(FqRepr([ - 0x6b0528f088bb7044, - 0x2fdeb5c82917ff9e, - 0x9a5181f2fac226ad, - 0xd65104c6f95a872a, - 0x1f2998a5a9c61253, - 0xe74846154a9e44, - ])).unwrap(), - z: Fq::one(), - }); - - let p = G1Affine::from(p); - - assert_eq!( - p, - G1Affine { - x: Fq::from_repr(FqRepr([ - 0x6dd3098f22235df, - 0xe865d221c8090260, - 0xeb96bb99fa50779f, - 0xc4f9a52a428e23bb, - 0xd178b28dd4f407ef, - 0x17fb8905e9183c69 - ])).unwrap(), - y: Fq::from_repr(FqRepr([ - 0xd0de9d65292b7710, - 0xf6a05f2bcf1d9ca7, - 0x1040e27012f20b64, - 0xeec8d1a5b7466c58, - 0x4bc362649dce6376, - 0x430cbdc5455b00a - ])).unwrap(), - infinity: false, - } - ); - } - - #[test] - fn test_g1_doubling_correctness() { - let mut p = G1 { - x: Fq::from_repr(FqRepr([ - 0x47fd1f891d6e8bbf, - 0x79a3b0448f31a2aa, - 0x81f3339e5f9968f, - 0x485e77d50a5df10d, - 0x4c6fcac4b55fd479, - 0x86ed4d9906fb064, - ])).unwrap(), - y: Fq::from_repr(FqRepr([ - 0xd25ee6461538c65, - 0x9f3bbb2ecd3719b9, - 0xa06fd3f1e540910d, - 0xcefca68333c35288, - 0x570c8005f8573fa6, - 0x152ca696fe034442, - ])).unwrap(), - z: Fq::one(), - }; - - p.double(); - - let p = G1Affine::from(p); - - assert_eq!( - p, - G1Affine { - x: Fq::from_repr(FqRepr([ - 0xf939ddfe0ead7018, - 0x3b03942e732aecb, - 0xce0e9c38fdb11851, - 0x4b914c16687dcde0, - 0x66c8baf177d20533, - 0xaf960cff3d83833 - ])).unwrap(), - y: Fq::from_repr(FqRepr([ - 0x3f0675695f5177a8, - 0x2b6d82ae178a1ba0, - 0x9096380dd8e51b11, - 0x1771a65b60572f4e, - 0x8b547c1313b27555, - 0x135075589a687b1e - ])).unwrap(), - infinity: false, - } - ); - } - - #[test] - fn test_g1_same_y() { - // Test the addition of two points with different x coordinates - // but the same y coordinate. - - // x1 = 128100205326445210408953809171070606737678357140298133325128175840781723996595026100005714405541449960643523234125 - // x2 = 3821408151224848222394078037104966877485040835569514006839342061575586899845797797516352881516922679872117658572470 - // y = 2291134451313223670499022936083127939567618746216464377735567679979105510603740918204953301371880765657042046687078 - - let a = G1Affine { - x: Fq::from_repr(FqRepr([ - 0xea431f2cc38fc94d, - 0x3ad2354a07f5472b, - 0xfe669f133f16c26a, - 0x71ffa8021531705, - 0x7418d484386d267, - 0xd5108d8ff1fbd6, - ])).unwrap(), - y: Fq::from_repr(FqRepr([ - 0xa776ccbfe9981766, - 0x255632964ff40f4a, - 0xc09744e650b00499, - 0x520f74773e74c8c3, - 0x484c8fc982008f0, - 0xee2c3d922008cc6, - ])).unwrap(), - infinity: false, - }; - - let b = G1Affine { - x: Fq::from_repr(FqRepr([ - 0xe06cdb156b6356b6, - 0xd9040b2d75448ad9, - 0xe702f14bb0e2aca5, - 0xc6e05201e5f83991, - 0xf7c75910816f207c, - 0x18d4043e78103106, - ])).unwrap(), - y: Fq::from_repr(FqRepr([ - 0xa776ccbfe9981766, - 0x255632964ff40f4a, - 0xc09744e650b00499, - 0x520f74773e74c8c3, - 0x484c8fc982008f0, - 0xee2c3d922008cc6, - ])).unwrap(), - infinity: false, - }; - - // Expected - // x = 52901198670373960614757979459866672334163627229195745167587898707663026648445040826329033206551534205133090753192 - // y = 1711275103908443722918766889652776216989264073722543507596490456144926139887096946237734327757134898380852225872709 - let c = G1Affine { - x: Fq::from_repr(FqRepr([ - 0xef4f05bdd10c8aa8, - 0xad5bf87341a2df9, - 0x81c7424206b78714, - 0x9676ff02ec39c227, - 0x4c12c15d7e55b9f3, - 0x57fd1e317db9bd, - ])).unwrap(), - y: Fq::from_repr(FqRepr([ - 0x1288334016679345, - 0xf955cd68615ff0b5, - 0xa6998dbaa600f18a, - 0x1267d70db51049fb, - 0x4696deb9ab2ba3e7, - 0xb1e4e11177f59d4, - ])).unwrap(), - infinity: false, - }; - - assert!(a.is_on_curve() && a.is_in_correct_subgroup_assuming_on_curve()); - assert!(b.is_on_curve() && b.is_in_correct_subgroup_assuming_on_curve()); - assert!(c.is_on_curve() && c.is_in_correct_subgroup_assuming_on_curve()); - - let mut tmp1 = a.into_projective(); - tmp1.add_assign(&b.into_projective()); - assert_eq!(tmp1.into_affine(), c); - assert_eq!(tmp1, c.into_projective()); - - let mut tmp2 = a.into_projective(); - tmp2.add_assign_mixed(&b); - assert_eq!(tmp2.into_affine(), c); - assert_eq!(tmp2, c.into_projective()); - } - - #[test] - fn g1_curve_tests() { - use group::tests::curve_tests; - curve_tests::(); - } -} - -pub mod g2 { - use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr, FrRepr}; - use super::g1::G1Affine; - use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; - use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; - use rand::{Rand, Rng}; - use std::fmt; - use {Engine, PairingCurveAffine}; - - curve_impl!( - "G2", - G2, - G2Affine, - G2Prepared, - Fq2, - Fr, - G2Uncompressed, - G2Compressed, - G1Affine - ); - - #[derive(Copy, Clone)] - pub struct G2Uncompressed([u8; 192]); - - impl AsRef<[u8]> for G2Uncompressed { - fn as_ref(&self) -> &[u8] { - &self.0 - } - } - - impl AsMut<[u8]> for G2Uncompressed { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0 - } - } - - impl fmt::Debug for G2Uncompressed { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.0[..].fmt(formatter) - } - } - - impl EncodedPoint for G2Uncompressed { - type Affine = G2Affine; - - fn empty() -> Self { - G2Uncompressed([0; 192]) - } - fn size() -> usize { - 192 - } - fn into_affine(&self) -> Result { - let affine = self.into_affine_unchecked()?; - - if !affine.is_on_curve() { - Err(GroupDecodingError::NotOnCurve) - } else if !affine.is_in_correct_subgroup_assuming_on_curve() { - Err(GroupDecodingError::NotInSubgroup) - } else { - Ok(affine) - } - } - fn into_affine_unchecked(&self) -> Result { - // Create a copy of this representation. - let mut copy = self.0; - - if copy[0] & (1 << 7) != 0 { - // Distinguisher bit is set, but this should be uncompressed! - return Err(GroupDecodingError::UnexpectedCompressionMode); - } - - if copy[0] & (1 << 6) != 0 { - // This is the point at infinity, which means that if we mask away - // the first two bits, the entire representation should consist - // of zeroes. - copy[0] &= 0x3f; - - if copy.iter().all(|b| *b == 0) { - Ok(G2Affine::zero()) - } else { - Err(GroupDecodingError::UnexpectedInformation) - } - } else { - if copy[0] & (1 << 5) != 0 { - // The bit indicating the y-coordinate should be lexicographically - // largest is set, but this is an uncompressed element. - return Err(GroupDecodingError::UnexpectedInformation); - } - - // Unset the three most significant bits. - copy[0] &= 0x1f; - - let mut x_c0 = FqRepr([0; 6]); - let mut x_c1 = FqRepr([0; 6]); - let mut y_c0 = FqRepr([0; 6]); - let mut y_c1 = FqRepr([0; 6]); - - { - let mut reader = ©[..]; - - x_c1.read_be(&mut reader).unwrap(); - x_c0.read_be(&mut reader).unwrap(); - y_c1.read_be(&mut reader).unwrap(); - y_c0.read_be(&mut reader).unwrap(); - } - - Ok(G2Affine { - x: Fq2 { - c0: Fq::from_repr(x_c0).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("x coordinate (c0)", e) - })?, - c1: Fq::from_repr(x_c1).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("x coordinate (c1)", e) - })?, - }, - y: Fq2 { - c0: Fq::from_repr(y_c0).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("y coordinate (c0)", e) - })?, - c1: Fq::from_repr(y_c1).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("y coordinate (c1)", e) - })?, - }, - infinity: false, - }) - } - } - fn from_affine(affine: G2Affine) -> Self { - let mut res = Self::empty(); - - if affine.is_zero() { - // Set the second-most significant bit to indicate this point - // is at infinity. - res.0[0] |= 1 << 6; - } else { - let mut writer = &mut res.0[..]; - - affine.x.c1.into_repr().write_be(&mut writer).unwrap(); - affine.x.c0.into_repr().write_be(&mut writer).unwrap(); - affine.y.c1.into_repr().write_be(&mut writer).unwrap(); - affine.y.c0.into_repr().write_be(&mut writer).unwrap(); - } - - res - } - } - - #[derive(Copy, Clone)] - pub struct G2Compressed([u8; 96]); - - impl AsRef<[u8]> for G2Compressed { - fn as_ref(&self) -> &[u8] { - &self.0 - } - } - - impl AsMut<[u8]> for G2Compressed { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0 - } - } - - impl fmt::Debug for G2Compressed { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.0[..].fmt(formatter) - } - } - - impl EncodedPoint for G2Compressed { - type Affine = G2Affine; - - fn empty() -> Self { - G2Compressed([0; 96]) - } - fn size() -> usize { - 96 - } - fn into_affine(&self) -> Result { - let affine = self.into_affine_unchecked()?; - - // NB: Decompression guarantees that it is on the curve already. - - if !affine.is_in_correct_subgroup_assuming_on_curve() { - Err(GroupDecodingError::NotInSubgroup) - } else { - Ok(affine) - } - } - fn into_affine_unchecked(&self) -> Result { - // Create a copy of this representation. - let mut copy = self.0; - - if copy[0] & (1 << 7) == 0 { - // Distinguisher bit isn't set. - return Err(GroupDecodingError::UnexpectedCompressionMode); - } - - if copy[0] & (1 << 6) != 0 { - // This is the point at infinity, which means that if we mask away - // the first two bits, the entire representation should consist - // of zeroes. - copy[0] &= 0x3f; - - if copy.iter().all(|b| *b == 0) { - Ok(G2Affine::zero()) - } else { - Err(GroupDecodingError::UnexpectedInformation) - } - } else { - // Determine if the intended y coordinate must be greater - // lexicographically. - let greatest = copy[0] & (1 << 5) != 0; - - // Unset the three most significant bits. - copy[0] &= 0x1f; - - let mut x_c1 = FqRepr([0; 6]); - let mut x_c0 = FqRepr([0; 6]); - - { - let mut reader = ©[..]; - - x_c1.read_be(&mut reader).unwrap(); - x_c0.read_be(&mut reader).unwrap(); - } - - // Interpret as Fq element. - let x = Fq2 { - c0: Fq::from_repr(x_c0).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("x coordinate (c0)", e) - })?, - c1: Fq::from_repr(x_c1).map_err(|e| { - GroupDecodingError::CoordinateDecodingError("x coordinate (c1)", e) - })?, - }; - - G2Affine::get_point_from_x(x, greatest).ok_or(GroupDecodingError::NotOnCurve) - } - } - fn from_affine(affine: G2Affine) -> Self { - let mut res = Self::empty(); - - if affine.is_zero() { - // Set the second-most significant bit to indicate this point - // is at infinity. - res.0[0] |= 1 << 6; - } else { - { - let mut writer = &mut res.0[..]; - - affine.x.c1.into_repr().write_be(&mut writer).unwrap(); - affine.x.c0.into_repr().write_be(&mut writer).unwrap(); - } - - let mut negy = affine.y; - negy.negate(); - - // Set the third most significant bit if the correct y-coordinate - // is lexicographically largest. - if affine.y > negy { - res.0[0] |= 1 << 5; - } - } - - // Set highest bit to distinguish this as a compressed element. - res.0[0] |= 1 << 7; - - res - } - } - - impl G2Affine { - fn get_generator() -> Self { - G2Affine { - x: Fq2 { - c0: super::super::fq::G2_GENERATOR_X_C0, - c1: super::super::fq::G2_GENERATOR_X_C1, - }, - y: Fq2 { - c0: super::super::fq::G2_GENERATOR_Y_C0, - c1: super::super::fq::G2_GENERATOR_Y_C1, - }, - infinity: false, - } - } - - fn get_coeff_b() -> Fq2 { - Fq2 { - c0: super::super::fq::B_COEFF, - c1: super::super::fq::B_COEFF, - } - } - - fn scale_by_cofactor(&self) -> G2 { - // G2 cofactor = (x^8 - 4 x^7 + 5 x^6) - (4 x^4 + 6 x^3 - 4 x^2 - 4 x + 13) // 9 - // 0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5 - let cofactor = BitIterator::new([ - 0xcf1c38e31c7238e5, - 0x1616ec6e786f0c70, - 0x21537e293a6691ae, - 0xa628f1cb4d9e82ef, - 0xa68a205b2e5a7ddf, - 0xcd91de4547085aba, - 0x91d50792876a202, - 0x5d543a95414e7f1, - ]); - self.mul_bits(cofactor) - } - - fn perform_pairing(&self, other: &G1Affine) -> Fq12 { - super::super::Bls12::pairing(*other, *self) - } - } - - impl G2 { - fn empirical_recommended_wnaf_for_scalar(scalar: FrRepr) -> usize { - let num_bits = scalar.num_bits() as usize; - - if num_bits >= 103 { - 4 - } else if num_bits >= 37 { - 3 - } else { - 2 - } - } - - fn empirical_recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize { - const RECOMMENDATIONS: [usize; 11] = - [1, 3, 8, 20, 47, 126, 260, 826, 1501, 4555, 84071]; - - let mut ret = 4; - for r in &RECOMMENDATIONS { - if num_scalars > *r { - ret += 1; - } else { - break; - } - } - - ret - } - } - - #[derive(Clone, Debug)] - pub struct G2Prepared { - pub(crate) coeffs: Vec<(Fq2, Fq2, Fq2)>, - pub(crate) infinity: bool, - } - - #[test] - fn g2_generator() { - use SqrtField; - - let mut x = Fq2::zero(); - let mut i = 0; - loop { - // y^2 = x^3 + b - let mut rhs = x; - rhs.square(); - rhs.mul_assign(&x); - rhs.add_assign(&G2Affine::get_coeff_b()); - - if let Some(y) = rhs.sqrt() { - let mut negy = y; - negy.negate(); - - let p = G2Affine { - x: x, - y: if y < negy { y } else { negy }, - infinity: false, - }; - - assert!(!p.is_in_correct_subgroup_assuming_on_curve()); - - let g2 = p.scale_by_cofactor(); - if !g2.is_zero() { - assert_eq!(i, 2); - let g2 = G2Affine::from(g2); - - assert!(g2.is_in_correct_subgroup_assuming_on_curve()); - assert_eq!(g2, G2Affine::one()); - break; - } - } - - i += 1; - x.add_assign(&Fq2::one()); - } - } - - #[test] - fn g2_test_is_valid() { - // Reject point on isomorphic twist (b = 3 * (u + 1)) - { - let p = G2Affine { - x: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0xa757072d9fa35ba9, - 0xae3fb2fb418f6e8a, - 0xc1598ec46faa0c7c, - 0x7a17a004747e3dbe, - 0xcc65406a7c2e5a73, - 0x10b8c03d64db4d0c, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0xd30e70fe2f029778, - 0xda30772df0f5212e, - 0x5b47a9ff9a233a50, - 0xfb777e5b9b568608, - 0x789bac1fec71a2b9, - 0x1342f02e2da54405, - ])).unwrap(), - }, - y: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0xfe0812043de54dca, - 0xe455171a3d47a646, - 0xa493f36bc20be98a, - 0x663015d9410eb608, - 0x78e82a79d829a544, - 0x40a00545bb3c1e, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x4709802348e79377, - 0xb5ac4dc9204bcfbd, - 0xda361c97d02f42b2, - 0x15008b1dc399e8df, - 0x68128fd0548a3829, - 0x16a613db5c873aaa, - ])).unwrap(), - }, - infinity: false, - }; - assert!(!p.is_on_curve()); - assert!(p.is_in_correct_subgroup_assuming_on_curve()); - } - - // Reject point on a twist (b = 2 * (u + 1)) - { - let p = G2Affine { - x: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0xf4fdfe95a705f917, - 0xc2914df688233238, - 0x37c6b12cca35a34b, - 0x41abba710d6c692c, - 0xffcc4b2b62ce8484, - 0x6993ec01b8934ed, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0xb94e92d5f874e26, - 0x44516408bc115d95, - 0xe93946b290caa591, - 0xa5a0c2b7131f3555, - 0x83800965822367e7, - 0x10cf1d3ad8d90bfa, - ])).unwrap(), - }, - y: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0xbf00334c79701d97, - 0x4fe714f9ff204f9a, - 0xab70b28002f3d825, - 0x5a9171720e73eb51, - 0x38eb4fd8d658adb7, - 0xb649051bbc1164d, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x9225814253d7df75, - 0xc196c2513477f887, - 0xe05e2fbd15a804e0, - 0x55f2b8efad953e04, - 0x7379345eda55265e, - 0x377f2e6208fd4cb, - ])).unwrap(), - }, - infinity: false, - }; - assert!(!p.is_on_curve()); - assert!(!p.is_in_correct_subgroup_assuming_on_curve()); - } - - // Reject point in an invalid subgroup - // There is only one r-order subgroup, as r does not divide the cofactor. - { - let p = G2Affine { - x: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x262cea73ea1906c, - 0x2f08540770fabd6, - 0x4ceb92d0a76057be, - 0x2199bc19c48c393d, - 0x4a151b732a6075bf, - 0x17762a3b9108c4a7, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x26f461e944bbd3d1, - 0x298f3189a9cf6ed6, - 0x74328ad8bc2aa150, - 0x7e147f3f9e6e241, - 0x72a9b63583963fff, - 0x158b0083c000462, - ])).unwrap(), - }, - y: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x91fb0b225ecf103b, - 0x55d42edc1dc46ba0, - 0x43939b11997b1943, - 0x68cad19430706b4d, - 0x3ccfb97b924dcea8, - 0x1660f93434588f8d, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0xaaed3985b6dcb9c7, - 0xc1e985d6d898d9f4, - 0x618bd2ac3271ac42, - 0x3940a2dbb914b529, - 0xbeb88137cf34f3e7, - 0x1699ee577c61b694, - ])).unwrap(), - }, - infinity: false, - }; - assert!(p.is_on_curve()); - assert!(!p.is_in_correct_subgroup_assuming_on_curve()); - } - } - - #[test] - fn test_g2_addition_correctness() { - let mut p = G2 { - x: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x6c994cc1e303094e, - 0xf034642d2c9e85bd, - 0x275094f1352123a9, - 0x72556c999f3707ac, - 0x4617f2e6774e9711, - 0x100b2fe5bffe030b, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x7a33555977ec608, - 0xe23039d1fe9c0881, - 0x19ce4678aed4fcb5, - 0x4637c4f417667e2e, - 0x93ebe7c3e41f6acc, - 0xde884f89a9a371b, - ])).unwrap(), - }, - y: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0xe073119472e1eb62, - 0x44fb3391fe3c9c30, - 0xaa9b066d74694006, - 0x25fd427b4122f231, - 0xd83112aace35cae, - 0x191b2432407cbb7f, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0xf68ae82fe97662f5, - 0xe986057068b50b7d, - 0x96c30f0411590b48, - 0x9eaa6d19de569196, - 0xf6a03d31e2ec2183, - 0x3bdafaf7ca9b39b, - ])).unwrap(), - }, - z: Fq2::one(), - }; - - p.add_assign(&G2 { - x: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0xa8c763d25910bdd3, - 0x408777b30ca3add4, - 0x6115fcc12e2769e, - 0x8e73a96b329ad190, - 0x27c546f75ee1f3ab, - 0xa33d27add5e7e82, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x93b1ebcd54870dfe, - 0xf1578300e1342e11, - 0x8270dca3a912407b, - 0x2089faf462438296, - 0x828e5848cd48ea66, - 0x141ecbac1deb038b, - ])).unwrap(), - }, - y: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0xf5d2c28857229c3f, - 0x8c1574228757ca23, - 0xe8d8102175f5dc19, - 0x2767032fc37cc31d, - 0xd5ee2aba84fd10fe, - 0x16576ccd3dd0a4e8, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x4da9b6f6a96d1dd2, - 0x9657f7da77f1650e, - 0xbc150712f9ffe6da, - 0x31898db63f87363a, - 0xabab040ddbd097cc, - 0x11ad236b9ba02990, - ])).unwrap(), - }, - z: Fq2::one(), - }); - - let p = G2Affine::from(p); - - assert_eq!( - p, - G2Affine { - x: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0xcde7ee8a3f2ac8af, - 0xfc642eb35975b069, - 0xa7de72b7dd0e64b7, - 0xf1273e6406eef9cc, - 0xababd760ff05cb92, - 0xd7c20456617e89 - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0xd1a50b8572cbd2b8, - 0x238f0ac6119d07df, - 0x4dbe924fe5fd6ac2, - 0x8b203284c51edf6b, - 0xc8a0b730bbb21f5e, - 0x1a3b59d29a31274 - ])).unwrap(), - }, - y: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x9e709e78a8eaa4c9, - 0xd30921c93ec342f4, - 0x6d1ef332486f5e34, - 0x64528ab3863633dc, - 0x159384333d7cba97, - 0x4cb84741f3cafe8 - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x242af0dc3640e1a4, - 0xe90a73ad65c66919, - 0x2bd7ca7f4346f9ec, - 0x38528f92b689644d, - 0xb6884deec59fb21f, - 0x3c075d3ec52ba90 - ])).unwrap(), - }, - infinity: false, - } - ); - } - - #[test] - fn test_g2_doubling_correctness() { - let mut p = G2 { - x: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x6c994cc1e303094e, - 0xf034642d2c9e85bd, - 0x275094f1352123a9, - 0x72556c999f3707ac, - 0x4617f2e6774e9711, - 0x100b2fe5bffe030b, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x7a33555977ec608, - 0xe23039d1fe9c0881, - 0x19ce4678aed4fcb5, - 0x4637c4f417667e2e, - 0x93ebe7c3e41f6acc, - 0xde884f89a9a371b, - ])).unwrap(), - }, - y: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0xe073119472e1eb62, - 0x44fb3391fe3c9c30, - 0xaa9b066d74694006, - 0x25fd427b4122f231, - 0xd83112aace35cae, - 0x191b2432407cbb7f, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0xf68ae82fe97662f5, - 0xe986057068b50b7d, - 0x96c30f0411590b48, - 0x9eaa6d19de569196, - 0xf6a03d31e2ec2183, - 0x3bdafaf7ca9b39b, - ])).unwrap(), - }, - z: Fq2::one(), - }; - - p.double(); - - let p = G2Affine::from(p); - - assert_eq!( - p, - G2Affine { - x: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x91ccb1292727c404, - 0x91a6cb182438fad7, - 0x116aee59434de902, - 0xbcedcfce1e52d986, - 0x9755d4a3926e9862, - 0x18bab73760fd8024 - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x4e7c5e0a2ae5b99e, - 0x96e582a27f028961, - 0xc74d1cf4ef2d5926, - 0xeb0cf5e610ef4fe7, - 0x7b4c2bae8db6e70b, - 0xf136e43909fca0 - ])).unwrap(), - }, - y: Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x954d4466ab13e58, - 0x3ee42eec614cf890, - 0x853bb1d28877577e, - 0xa5a2a51f7fde787b, - 0x8b92866bc6384188, - 0x81a53fe531d64ef - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x4c5d607666239b34, - 0xeddb5f48304d14b3, - 0x337167ee6e8e3cb6, - 0xb271f52f12ead742, - 0x244e6c2015c83348, - 0x19e2deae6eb9b441 - ])).unwrap(), - }, - infinity: false, - } - ); - } - - #[test] - fn g2_curve_tests() { - use group::tests::curve_tests; - curve_tests::(); - } -} - -pub use self::g1::*; -pub use self::g2::*; diff --git a/pairing/src/bls12_381/fq.rs b/pairing/src/bls12_381/fq.rs deleted file mode 100644 index fd0d416..0000000 --- a/pairing/src/bls12_381/fq.rs +++ /dev/null @@ -1,2246 +0,0 @@ -use super::fq2::Fq2; -use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr}; - -// B coefficient of BLS12-381 curve, 4. -pub const B_COEFF: Fq = Fq(FqRepr([ - 0xaa270000000cfff3, - 0x53cc0032fc34000a, - 0x478fe97a6b0a807f, - 0xb1d37ebee6ba24d7, - 0x8ec9733bbf78ab2f, - 0x9d645513d83de7e, -])); - -// The generators of G1/G2 are computed by finding the lexicographically smallest valid x coordinate, -// and its lexicographically smallest y coordinate and multiplying it by the cofactor such that the -// result is nonzero. - -// Generator of G1 -// x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507 -// y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569 -pub const G1_GENERATOR_X: Fq = Fq(FqRepr([ - 0x5cb38790fd530c16, - 0x7817fc679976fff5, - 0x154f95c7143ba1c1, - 0xf0ae6acdf3d0e747, - 0xedce6ecc21dbf440, - 0x120177419e0bfb75, -])); -pub const G1_GENERATOR_Y: Fq = Fq(FqRepr([ - 0xbaac93d50ce72271, - 0x8c22631a7918fd8e, - 0xdd595f13570725ce, - 0x51ac582950405194, - 0xe1c8c3fad0059c0, - 0xbbc3efc5008a26a, -])); - -// Generator of G2 -// x = 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758*u + 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160 -// y = 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582*u + 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905 -pub const G2_GENERATOR_X_C0: Fq = Fq(FqRepr([ - 0xf5f28fa202940a10, - 0xb3f5fb2687b4961a, - 0xa1a893b53e2ae580, - 0x9894999d1a3caee9, - 0x6f67b7631863366b, - 0x58191924350bcd7, -])); -pub const G2_GENERATOR_X_C1: Fq = Fq(FqRepr([ - 0xa5a9c0759e23f606, - 0xaaa0c59dbccd60c3, - 0x3bb17e18e2867806, - 0x1b1ab6cc8541b367, - 0xc2b6ed0ef2158547, - 0x11922a097360edf3, -])); -pub const G2_GENERATOR_Y_C0: Fq = Fq(FqRepr([ - 0x4c730af860494c4a, - 0x597cfa1f5e369c5a, - 0xe7e6856caa0a635a, - 0xbbefb5e96e0d495f, - 0x7d3a975f0ef25a2, - 0x83fd8e7e80dae5, -])); -pub const G2_GENERATOR_Y_C1: Fq = Fq(FqRepr([ - 0xadc0fc92df64b05d, - 0x18aa270a2b1461dc, - 0x86adac6a3be4eba0, - 0x79495c4ec93da33a, - 0xe7175850a43ccaed, - 0xb2bc2a163de1bf2, -])); - -// Coefficients for the Frobenius automorphism. -pub const FROBENIUS_COEFF_FQ2_C1: [Fq; 2] = [ - // Fq(-1)**(((q^0) - 1) / 2) - Fq(FqRepr([ - 0x760900000002fffd, - 0xebf4000bc40c0002, - 0x5f48985753c758ba, - 0x77ce585370525745, - 0x5c071a97a256ec6d, - 0x15f65ec3fa80e493, - ])), - // Fq(-1)**(((q^1) - 1) / 2) - Fq(FqRepr([ - 0x43f5fffffffcaaae, - 0x32b7fff2ed47fffd, - 0x7e83a49a2e99d69, - 0xeca8f3318332bb7a, - 0xef148d1ea0f4c069, - 0x40ab3263eff0206, - ])), -]; - -pub const FROBENIUS_COEFF_FQ6_C1: [Fq2; 6] = [ - // Fq2(u + 1)**(((q^0) - 1) / 3) - Fq2 { - c0: Fq(FqRepr([ - 0x760900000002fffd, - 0xebf4000bc40c0002, - 0x5f48985753c758ba, - 0x77ce585370525745, - 0x5c071a97a256ec6d, - 0x15f65ec3fa80e493, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - }, - // Fq2(u + 1)**(((q^1) - 1) / 3) - Fq2 { - c0: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - c1: Fq(FqRepr([ - 0xcd03c9e48671f071, - 0x5dab22461fcda5d2, - 0x587042afd3851b95, - 0x8eb60ebe01bacb9e, - 0x3f97d6e83d050d2, - 0x18f0206554638741, - ])), - }, - // Fq2(u + 1)**(((q^2) - 1) / 3) - Fq2 { - c0: Fq(FqRepr([ - 0x30f1361b798a64e8, - 0xf3b8ddab7ece5a2a, - 0x16a8ca3ac61577f7, - 0xc26a2ff874fd029b, - 0x3636b76660701c6e, - 0x51ba4ab241b6160, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - }, - // Fq2(u + 1)**(((q^3) - 1) / 3) - Fq2 { - c0: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - c1: Fq(FqRepr([ - 0x760900000002fffd, - 0xebf4000bc40c0002, - 0x5f48985753c758ba, - 0x77ce585370525745, - 0x5c071a97a256ec6d, - 0x15f65ec3fa80e493, - ])), - }, - // Fq2(u + 1)**(((q^4) - 1) / 3) - Fq2 { - c0: Fq(FqRepr([ - 0xcd03c9e48671f071, - 0x5dab22461fcda5d2, - 0x587042afd3851b95, - 0x8eb60ebe01bacb9e, - 0x3f97d6e83d050d2, - 0x18f0206554638741, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - }, - // Fq2(u + 1)**(((q^5) - 1) / 3) - Fq2 { - c0: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - c1: Fq(FqRepr([ - 0x30f1361b798a64e8, - 0xf3b8ddab7ece5a2a, - 0x16a8ca3ac61577f7, - 0xc26a2ff874fd029b, - 0x3636b76660701c6e, - 0x51ba4ab241b6160, - ])), - }, -]; - -pub const FROBENIUS_COEFF_FQ6_C2: [Fq2; 6] = [ - // Fq2(u + 1)**(((2q^0) - 2) / 3) - Fq2 { - c0: Fq(FqRepr([ - 0x760900000002fffd, - 0xebf4000bc40c0002, - 0x5f48985753c758ba, - 0x77ce585370525745, - 0x5c071a97a256ec6d, - 0x15f65ec3fa80e493, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - }, - // Fq2(u + 1)**(((2q^1) - 2) / 3) - Fq2 { - c0: Fq(FqRepr([ - 0x890dc9e4867545c3, - 0x2af322533285a5d5, - 0x50880866309b7e2c, - 0xa20d1b8c7e881024, - 0x14e4f04fe2db9068, - 0x14e56d3f1564853a, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - }, - // Fq2(u + 1)**(((2q^2) - 2) / 3) - Fq2 { - c0: Fq(FqRepr([ - 0xcd03c9e48671f071, - 0x5dab22461fcda5d2, - 0x587042afd3851b95, - 0x8eb60ebe01bacb9e, - 0x3f97d6e83d050d2, - 0x18f0206554638741, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - }, - // Fq2(u + 1)**(((2q^3) - 2) / 3) - Fq2 { - c0: Fq(FqRepr([ - 0x43f5fffffffcaaae, - 0x32b7fff2ed47fffd, - 0x7e83a49a2e99d69, - 0xeca8f3318332bb7a, - 0xef148d1ea0f4c069, - 0x40ab3263eff0206, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - }, - // Fq2(u + 1)**(((2q^4) - 2) / 3) - Fq2 { - c0: Fq(FqRepr([ - 0x30f1361b798a64e8, - 0xf3b8ddab7ece5a2a, - 0x16a8ca3ac61577f7, - 0xc26a2ff874fd029b, - 0x3636b76660701c6e, - 0x51ba4ab241b6160, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - }, - // Fq2(u + 1)**(((2q^5) - 2) / 3) - Fq2 { - c0: Fq(FqRepr([ - 0xecfb361b798dba3a, - 0xc100ddb891865a2c, - 0xec08ff1232bda8e, - 0xd5c13cc6f1ca4721, - 0x47222a47bf7b5c04, - 0x110f184e51c5f59, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - }, -]; - -// non_residue^((modulus^i-1)/6) for i=0,...,11 -pub const FROBENIUS_COEFF_FQ12_C1: [Fq2; 12] = [ - // Fq2(u + 1)**(((q^0) - 1) / 6) - Fq2 { - c0: Fq(FqRepr([ - 0x760900000002fffd, - 0xebf4000bc40c0002, - 0x5f48985753c758ba, - 0x77ce585370525745, - 0x5c071a97a256ec6d, - 0x15f65ec3fa80e493, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - }, - // Fq2(u + 1)**(((q^1) - 1) / 6) - Fq2 { - c0: Fq(FqRepr([ - 0x7089552b319d465, - 0xc6695f92b50a8313, - 0x97e83cccd117228f, - 0xa35baecab2dc29ee, - 0x1ce393ea5daace4d, - 0x8f2220fb0fb66eb, - ])), - c1: Fq(FqRepr([ - 0xb2f66aad4ce5d646, - 0x5842a06bfc497cec, - 0xcf4895d42599d394, - 0xc11b9cba40a8e8d0, - 0x2e3813cbe5a0de89, - 0x110eefda88847faf, - ])), - }, - // Fq2(u + 1)**(((q^2) - 1) / 6) - Fq2 { - c0: Fq(FqRepr([ - 0xecfb361b798dba3a, - 0xc100ddb891865a2c, - 0xec08ff1232bda8e, - 0xd5c13cc6f1ca4721, - 0x47222a47bf7b5c04, - 0x110f184e51c5f59, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - }, - // Fq2(u + 1)**(((q^3) - 1) / 6) - Fq2 { - c0: Fq(FqRepr([ - 0x3e2f585da55c9ad1, - 0x4294213d86c18183, - 0x382844c88b623732, - 0x92ad2afd19103e18, - 0x1d794e4fac7cf0b9, - 0xbd592fc7d825ec8, - ])), - c1: Fq(FqRepr([ - 0x7bcfa7a25aa30fda, - 0xdc17dec12a927e7c, - 0x2f088dd86b4ebef1, - 0xd1ca2087da74d4a7, - 0x2da2596696cebc1d, - 0xe2b7eedbbfd87d2, - ])), - }, - // Fq2(u + 1)**(((q^4) - 1) / 6) - Fq2 { - c0: Fq(FqRepr([ - 0x30f1361b798a64e8, - 0xf3b8ddab7ece5a2a, - 0x16a8ca3ac61577f7, - 0xc26a2ff874fd029b, - 0x3636b76660701c6e, - 0x51ba4ab241b6160, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - }, - // Fq2(u + 1)**(((q^5) - 1) / 6) - Fq2 { - c0: Fq(FqRepr([ - 0x3726c30af242c66c, - 0x7c2ac1aad1b6fe70, - 0xa04007fbba4b14a2, - 0xef517c3266341429, - 0x95ba654ed2226b, - 0x2e370eccc86f7dd, - ])), - c1: Fq(FqRepr([ - 0x82d83cf50dbce43f, - 0xa2813e53df9d018f, - 0xc6f0caa53c65e181, - 0x7525cf528d50fe95, - 0x4a85ed50f4798a6b, - 0x171da0fd6cf8eebd, - ])), - }, - // Fq2(u + 1)**(((q^6) - 1) / 6) - Fq2 { - c0: Fq(FqRepr([ - 0x43f5fffffffcaaae, - 0x32b7fff2ed47fffd, - 0x7e83a49a2e99d69, - 0xeca8f3318332bb7a, - 0xef148d1ea0f4c069, - 0x40ab3263eff0206, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - }, - // Fq2(u + 1)**(((q^7) - 1) / 6) - Fq2 { - c0: Fq(FqRepr([ - 0xb2f66aad4ce5d646, - 0x5842a06bfc497cec, - 0xcf4895d42599d394, - 0xc11b9cba40a8e8d0, - 0x2e3813cbe5a0de89, - 0x110eefda88847faf, - ])), - c1: Fq(FqRepr([ - 0x7089552b319d465, - 0xc6695f92b50a8313, - 0x97e83cccd117228f, - 0xa35baecab2dc29ee, - 0x1ce393ea5daace4d, - 0x8f2220fb0fb66eb, - ])), - }, - // Fq2(u + 1)**(((q^8) - 1) / 6) - Fq2 { - c0: Fq(FqRepr([ - 0xcd03c9e48671f071, - 0x5dab22461fcda5d2, - 0x587042afd3851b95, - 0x8eb60ebe01bacb9e, - 0x3f97d6e83d050d2, - 0x18f0206554638741, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - }, - // Fq2(u + 1)**(((q^9) - 1) / 6) - Fq2 { - c0: Fq(FqRepr([ - 0x7bcfa7a25aa30fda, - 0xdc17dec12a927e7c, - 0x2f088dd86b4ebef1, - 0xd1ca2087da74d4a7, - 0x2da2596696cebc1d, - 0xe2b7eedbbfd87d2, - ])), - c1: Fq(FqRepr([ - 0x3e2f585da55c9ad1, - 0x4294213d86c18183, - 0x382844c88b623732, - 0x92ad2afd19103e18, - 0x1d794e4fac7cf0b9, - 0xbd592fc7d825ec8, - ])), - }, - // Fq2(u + 1)**(((q^10) - 1) / 6) - Fq2 { - c0: Fq(FqRepr([ - 0x890dc9e4867545c3, - 0x2af322533285a5d5, - 0x50880866309b7e2c, - 0xa20d1b8c7e881024, - 0x14e4f04fe2db9068, - 0x14e56d3f1564853a, - ])), - c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])), - }, - // Fq2(u + 1)**(((q^11) - 1) / 6) - Fq2 { - c0: Fq(FqRepr([ - 0x82d83cf50dbce43f, - 0xa2813e53df9d018f, - 0xc6f0caa53c65e181, - 0x7525cf528d50fe95, - 0x4a85ed50f4798a6b, - 0x171da0fd6cf8eebd, - ])), - c1: Fq(FqRepr([ - 0x3726c30af242c66c, - 0x7c2ac1aad1b6fe70, - 0xa04007fbba4b14a2, - 0xef517c3266341429, - 0x95ba654ed2226b, - 0x2e370eccc86f7dd, - ])), - }, -]; - -// -((2**384) mod q) mod q -pub const NEGATIVE_ONE: Fq = Fq(FqRepr([ - 0x43f5fffffffcaaae, - 0x32b7fff2ed47fffd, - 0x7e83a49a2e99d69, - 0xeca8f3318332bb7a, - 0xef148d1ea0f4c069, - 0x40ab3263eff0206, -])); - -#[derive(PrimeField)] -#[PrimeFieldModulus = "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787"] -#[PrimeFieldGenerator = "2"] -pub struct Fq(FqRepr); - -#[test] -fn test_b_coeff() { - assert_eq!(Fq::from_repr(FqRepr::from(4)).unwrap(), B_COEFF); -} - -#[test] -fn test_frob_coeffs() { - let mut nqr = Fq::one(); - nqr.negate(); - - assert_eq!(FROBENIUS_COEFF_FQ2_C1[0], Fq::one()); - assert_eq!( - FROBENIUS_COEFF_FQ2_C1[1], - nqr.pow([ - 0xdcff7fffffffd555, - 0xf55ffff58a9ffff, - 0xb39869507b587b12, - 0xb23ba5c279c2895f, - 0x258dd3db21a5d66b, - 0xd0088f51cbff34d - ]) - ); - - let nqr = Fq2 { - c0: Fq::one(), - c1: Fq::one(), - }; - - assert_eq!(FROBENIUS_COEFF_FQ6_C1[0], Fq2::one()); - assert_eq!( - FROBENIUS_COEFF_FQ6_C1[1], - nqr.pow([ - 0x9354ffffffffe38e, - 0xa395554e5c6aaaa, - 0xcd104635a790520c, - 0xcc27c3d6fbd7063f, - 0x190937e76bc3e447, - 0x8ab05f8bdd54cde - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ6_C1[2], - nqr.pow([ - 0xb78e0000097b2f68, - 0xd44f23b47cbd64e3, - 0x5cb9668120b069a9, - 0xccea85f9bf7b3d16, - 0xdba2c8d7adb356d, - 0x9cd75ded75d7429, - 0xfc65c31103284fab, - 0xc58cb9a9b249ee24, - 0xccf734c3118a2e9a, - 0xa0f4304c5a256ce6, - 0xc3f0d2f8e0ba61f8, - 0xe167e192ebca97 - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ6_C1[3], - nqr.pow([ - 0xdbc6fcd6f35b9e06, - 0x997dead10becd6aa, - 0x9dbbd24c17206460, - 0x72b97acc6057c45e, - 0xf8e9a230bf0c628e, - 0x647ccb1885c63a7, - 0xce80264fc55bf6ee, - 0x94d8d716c3939fc4, - 0xad78f0eb77ee6ee1, - 0xd6fe49bfe57dc5f9, - 0x2656d6c15c63647, - 0xdf6282f111fa903, - 0x1bdba63e0632b4bb, - 0x6883597bcaa505eb, - 0xa56d4ec90c34a982, - 0x7e4c42823bbe90b2, - 0xf64728aa6dcb0f20, - 0x16e57e16ef152f - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ6_C1[4], - nqr.pow([ - 0x4649add3c71c6d90, - 0x43caa6528972a865, - 0xcda8445bbaaa0fbb, - 0xc93dea665662aa66, - 0x2863bc891834481d, - 0x51a0c3f5d4ccbed8, - 0x9210e660f90ccae9, - 0xe2bd6836c546d65e, - 0xf223abbaa7cf778b, - 0xd4f10b222cf11680, - 0xd540f5eff4a1962e, - 0xa123a1f140b56526, - 0x31ace500636a59f6, - 0x3a82bc8c8dfa57a9, - 0x648c511e217fc1f8, - 0x36c17ffd53a4558f, - 0x881bef5fd684eefd, - 0x5d648dbdc5dbb522, - 0x8fd07bf06e5e59b8, - 0x8ddec8a9acaa4b51, - 0x4cc1f8688e2def26, - 0xa74e63cb492c03de, - 0x57c968173d1349bb, - 0x253674e02a866 - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ6_C1[5], - nqr.pow([ - 0xf896f792732eb2be, - 0x49c86a6d1dc593a1, - 0xe5b31e94581f91c3, - 0xe3da5cc0a6b20d7f, - 0x822caef950e0bfed, - 0x317ed950b9ee67cd, - 0xffd664016ee3f6cd, - 0x77d991c88810b122, - 0x62e72e635e698264, - 0x905e1a1a2d22814a, - 0xf5b7ab3a3f33d981, - 0x175871b0bc0e25dd, - 0x1e2e9a63df5c3772, - 0xe888b1f7445b149d, - 0x9551c19e5e7e2c24, - 0xecf21939a3d2d6be, - 0xd830dbfdab72dbd4, - 0x7b34af8d622d40c0, - 0x3df6d20a45671242, - 0xaf86bee30e21d98, - 0x41064c1534e5df5d, - 0xf5f6cabd3164c609, - 0xa5d14bdf2b7ee65, - 0xa718c069defc9138, - 0xdb1447e770e3110e, - 0xc1b164a9e90af491, - 0x7180441f9d251602, - 0x1fd3a5e6a9a893e, - 0x1e17b779d54d5db, - 0x3c7afafe3174 - ]) - ); - - assert_eq!(FROBENIUS_COEFF_FQ6_C2[0], Fq2::one()); - assert_eq!( - FROBENIUS_COEFF_FQ6_C2[1], - nqr.pow([ - 0x26a9ffffffffc71c, - 0x1472aaa9cb8d5555, - 0x9a208c6b4f20a418, - 0x984f87adf7ae0c7f, - 0x32126fced787c88f, - 0x11560bf17baa99bc - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ6_C2[2], - nqr.pow([ - 0x6f1c000012f65ed0, - 0xa89e4768f97ac9c7, - 0xb972cd024160d353, - 0x99d50bf37ef67a2c, - 0x1b74591af5b66adb, - 0x139aebbdaebae852, - 0xf8cb862206509f56, - 0x8b1973536493dc49, - 0x99ee698623145d35, - 0x41e86098b44ad9cd, - 0x87e1a5f1c174c3f1, - 0x1c2cfc325d7952f - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ6_C2[3], - nqr.pow([ - 0xb78df9ade6b73c0c, - 0x32fbd5a217d9ad55, - 0x3b77a4982e40c8c1, - 0xe572f598c0af88bd, - 0xf1d344617e18c51c, - 0xc8f996310b8c74f, - 0x9d004c9f8ab7eddc, - 0x29b1ae2d87273f89, - 0x5af1e1d6efdcddc3, - 0xadfc937fcafb8bf3, - 0x4cadad82b8c6c8f, - 0x1bec505e223f5206, - 0x37b74c7c0c656976, - 0xd106b2f7954a0bd6, - 0x4ada9d9218695304, - 0xfc988504777d2165, - 0xec8e5154db961e40, - 0x2dcafc2dde2a5f - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ6_C2[4], - nqr.pow([ - 0x8c935ba78e38db20, - 0x87954ca512e550ca, - 0x9b5088b775541f76, - 0x927bd4ccacc554cd, - 0x50c779123068903b, - 0xa34187eba9997db0, - 0x2421ccc1f21995d2, - 0xc57ad06d8a8dacbd, - 0xe44757754f9eef17, - 0xa9e2164459e22d01, - 0xaa81ebdfe9432c5d, - 0x424743e2816aca4d, - 0x6359ca00c6d4b3ed, - 0x750579191bf4af52, - 0xc918a23c42ff83f0, - 0x6d82fffaa748ab1e, - 0x1037debfad09ddfa, - 0xbac91b7b8bb76a45, - 0x1fa0f7e0dcbcb370, - 0x1bbd9153595496a3, - 0x9983f0d11c5bde4d, - 0x4e9cc796925807bc, - 0xaf92d02e7a269377, - 0x4a6ce9c0550cc - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ6_C2[5], - nqr.pow([ - 0xf12def24e65d657c, - 0x9390d4da3b8b2743, - 0xcb663d28b03f2386, - 0xc7b4b9814d641aff, - 0x4595df2a1c17fdb, - 0x62fdb2a173dccf9b, - 0xffacc802ddc7ed9a, - 0xefb3239110216245, - 0xc5ce5cc6bcd304c8, - 0x20bc34345a450294, - 0xeb6f56747e67b303, - 0x2eb0e361781c4bbb, - 0x3c5d34c7beb86ee4, - 0xd11163ee88b6293a, - 0x2aa3833cbcfc5849, - 0xd9e4327347a5ad7d, - 0xb061b7fb56e5b7a9, - 0xf6695f1ac45a8181, - 0x7beda4148ace2484, - 0x15f0d7dc61c43b30, - 0x820c982a69cbbeba, - 0xebed957a62c98c12, - 0x14ba297be56fdccb, - 0x4e3180d3bdf92270, - 0xb6288fcee1c6221d, - 0x8362c953d215e923, - 0xe300883f3a4a2c05, - 0x3fa74bcd535127c, - 0x3c2f6ef3aa9abb6, - 0x78f5f5fc62e8 - ]) - ); - - assert_eq!(FROBENIUS_COEFF_FQ12_C1[0], Fq2::one()); - assert_eq!( - FROBENIUS_COEFF_FQ12_C1[1], - nqr.pow([ - 0x49aa7ffffffff1c7, - 0x51caaaa72e35555, - 0xe688231ad3c82906, - 0xe613e1eb7deb831f, - 0xc849bf3b5e1f223, - 0x45582fc5eeaa66f - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ12_C1[2], - nqr.pow([ - 0xdbc7000004bd97b4, - 0xea2791da3e5eb271, - 0x2e5cb340905834d4, - 0xe67542fcdfbd9e8b, - 0x86dd1646bd6d9ab6, - 0x84e6baef6baeba14, - 0x7e32e188819427d5, - 0x62c65cd4d924f712, - 0x667b9a6188c5174d, - 0x507a18262d12b673, - 0xe1f8697c705d30fc, - 0x70b3f0c975e54b - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ12_C1[3], - nqr.pow(vec![ - 0x6de37e6b79adcf03, - 0x4cbef56885f66b55, - 0x4edde9260b903230, - 0x395cbd66302be22f, - 0xfc74d1185f863147, - 0x323e658c42e31d3, - 0x67401327e2adfb77, - 0xca6c6b8b61c9cfe2, - 0xd6bc7875bbf73770, - 0xeb7f24dff2bee2fc, - 0x8132b6b60ae31b23, - 0x86fb1417888fd481, - 0x8dedd31f03195a5d, - 0x3441acbde55282f5, - 0x52b6a764861a54c1, - 0x3f2621411ddf4859, - 0xfb23945536e58790, - 0xb72bf0b778a97, - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ12_C1[4], - nqr.pow(vec![ - 0xa324d6e9e38e36c8, - 0xa1e5532944b95432, - 0x66d4222ddd5507dd, - 0xe49ef5332b315533, - 0x1431de448c1a240e, - 0xa8d061faea665f6c, - 0x490873307c866574, - 0xf15eb41b62a36b2f, - 0x7911d5dd53e7bbc5, - 0x6a78859116788b40, - 0x6aa07af7fa50cb17, - 0x5091d0f8a05ab293, - 0x98d6728031b52cfb, - 0x1d415e4646fd2bd4, - 0xb246288f10bfe0fc, - 0x9b60bffea9d22ac7, - 0x440df7afeb42777e, - 0x2eb246dee2edda91, - 0xc7e83df8372f2cdc, - 0x46ef6454d65525a8, - 0x2660fc344716f793, - 0xd3a731e5a49601ef, - 0x2be4b40b9e89a4dd, - 0x129b3a7015433, - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ12_C1[5], - nqr.pow(vec![ - 0xfc4b7bc93997595f, - 0xa4e435368ee2c9d0, - 0xf2d98f4a2c0fc8e1, - 0xf1ed2e60535906bf, - 0xc116577ca8705ff6, - 0x98bf6ca85cf733e6, - 0x7feb3200b771fb66, - 0x3becc8e444085891, - 0x31739731af34c132, - 0xc82f0d0d169140a5, - 0xfadbd59d1f99ecc0, - 0xbac38d85e0712ee, - 0x8f174d31efae1bb9, - 0x744458fba22d8a4e, - 0x4aa8e0cf2f3f1612, - 0x76790c9cd1e96b5f, - 0x6c186dfed5b96dea, - 0x3d9a57c6b116a060, - 0x1efb690522b38921, - 0x857c35f718710ecc, - 0xa083260a9a72efae, - 0xfafb655e98b26304, - 0x52e8a5ef95bf732, - 0x538c6034ef7e489c, - 0xed8a23f3b8718887, - 0x60d8b254f4857a48, - 0x38c0220fce928b01, - 0x80fe9d2f354d449f, - 0xf0bdbbceaa6aed, - 0x1e3d7d7f18ba, - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ12_C1[6], - nqr.pow(vec![ - 0x21219610a012ba3c, - 0xa5c19ad35375325, - 0x4e9df1e497674396, - 0xfb05b717c991c6ef, - 0x4a1265bca93a32f2, - 0xd875ff2a7bdc1f66, - 0xc6d8754736c771b2, - 0x2d80c759ba5a2ae7, - 0x138a20df4b03cc1a, - 0xc22d07fe68e93024, - 0xd1dc474d3b433133, - 0xc22aa5e75044e5c, - 0xf657c6fbf9c17ebf, - 0xc591a794a58660d, - 0x2261850ee1453281, - 0xd17d3bd3b7f5efb4, - 0xf00cec8ec507d01, - 0x2a6a775657a00ae6, - 0x5f098a12ff470719, - 0x409d194e7b5c5afa, - 0x1d66478e982af5b, - 0xda425a5b5e01ca3f, - 0xf77e4f78747e903c, - 0x177d49f73732c6fc, - 0xa9618fecabe0e1f4, - 0xba5337eac90bd080, - 0x66fececdbc35d4e7, - 0xa4cd583203d9206f, - 0x98391632ceeca596, - 0x4946b76e1236ad3f, - 0xa0dec64e60e711a1, - 0xfcb41ed3605013, - 0x8ca8f9692ae1e3a9, - 0xd3078bfc28cc1baf, - 0xf0536f764e982f82, - 0x3125f1a2656, - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ12_C1[7], - nqr.pow(vec![ - 0x742754a1f22fdb, - 0x2a1955c2dec3a702, - 0x9747b28c796d134e, - 0xc113a0411f59db79, - 0x3bb0fa929853bfc1, - 0x28c3c25f8f6fb487, - 0xbc2b6c99d3045b34, - 0x98fb67d6badde1fd, - 0x48841d76a24d2073, - 0xd49891145fe93ae6, - 0xc772b9c8e74d4099, - 0xccf4e7b9907755bb, - 0x9cf47b25d42fd908, - 0x5616a0c347fc445d, - 0xff93b7a7ad1b8a6d, - 0xac2099256b78a77a, - 0x7804a95b02892e1c, - 0x5cf59ca7bfd69776, - 0xa7023502acd3c866, - 0xc76f4982fcf8f37, - 0x51862a5a57ac986e, - 0x38b80ed72b1b1023, - 0x4a291812066a61e1, - 0xcd8a685eff45631, - 0x3f40f708764e4fa5, - 0x8aa0441891285092, - 0x9eff60d71cdf0a9, - 0x4fdd9d56517e2bfa, - 0x1f3c80d74a28bc85, - 0x24617417c064b648, - 0x7ddda1e4385d5088, - 0xf9e132b11dd32a16, - 0xcc957cb8ef66ab99, - 0xd4f206d37cb752c5, - 0x40de343f28ad616b, - 0x8d1f24379068f0e3, - 0x6f31d7947ea21137, - 0x27311f9c32184061, - 0x9eea0664cc78ce5f, - 0x7d4151f6fea9a0da, - 0x454096fa75bd571a, - 0x4fe0f20ecb, - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ12_C1[8], - nqr.pow(vec![ - 0x802f5720d0b25710, - 0x6714f0a258b85c7c, - 0x31394c90afdf16e, - 0xe9d2b0c64f957b19, - 0xe67c0d9c5e7903ee, - 0x3156fdc5443ea8ef, - 0x7c4c50524d88c892, - 0xc99dc8990c0ad244, - 0xd37ababf3649a896, - 0x76fe4b838ff7a20c, - 0xcf69ee2cec728db3, - 0xb83535548e5f41, - 0x371147684ccb0c23, - 0x194f6f4fa500db52, - 0xc4571dc78a4c5374, - 0xe4d46d479999ca97, - 0x76b6785a615a151c, - 0xcceb8bcea7eaf8c1, - 0x80d87a6fbe5ae687, - 0x6a97ddddb85ce85, - 0xd783958f26034204, - 0x7144506f2e2e8590, - 0x948693d377aef166, - 0x8364621ed6f96056, - 0xf021777c4c09ee2d, - 0xc6cf5e746ecd50b, - 0xa2337b7aa22743df, - 0xae753f8bbacab39c, - 0xfc782a9e34d3c1cc, - 0x21b827324fe494d9, - 0x5692ce350ed03b38, - 0xf323a2b3cd0481b0, - 0xe859c97a4ccad2e3, - 0x48434b70381e4503, - 0x46042d62e4132ed8, - 0x48c4d6f56122e2f2, - 0xf87711ab9f5c1af7, - 0xb14b7a054759b469, - 0x8eb0a96993ffa9aa, - 0x9b21fb6fc58b760c, - 0xf3abdd115d2e7d25, - 0xf7beac3d4d12409c, - 0x40a5585cce69bf03, - 0x697881e1ba22d5a8, - 0x3d6c04e6ad373fd9, - 0x849871bf627be886, - 0x550f4b9b71b28ef9, - 0x81d2e0d78, - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ12_C1[9], - nqr.pow(vec![ - 0x4af4accf7de0b977, - 0x742485e21805b4ee, - 0xee388fbc4ac36dec, - 0x1e199da57ad178a, - 0xc27c12b292c6726a, - 0x162e6ed84505b5e8, - 0xe191683f336e09df, - 0x17deb7e8d1e0fce6, - 0xd944f19ad06f5836, - 0x4c5f5e59f6276026, - 0xf1ba9c7c148a38a8, - 0xd205fe2dba72b326, - 0x9a2cf2a4c289824e, - 0x4f47ad512c39e24d, - 0xc5894d984000ea09, - 0x2974c03ff7cf01fa, - 0xfcd243b48cb99a22, - 0x2b5150c9313ac1e8, - 0x9089f37c7fc80eda, - 0x989540cc9a7aea56, - 0x1ab1d4e337e63018, - 0x42b546c30d357e43, - 0x1c6abc04f76233d9, - 0x78b3b8d88bf73e47, - 0x151c4e4c45dc68e6, - 0x519a79c4f54397ed, - 0x93f5b51535a127c5, - 0x5fc51b6f52fa153e, - 0x2e0504f2d4a965c3, - 0xc85bd3a3da52bffe, - 0x98c60957a46a89ef, - 0x48c03b5976b91cae, - 0xc6598040a0a61438, - 0xbf0b49dc255953af, - 0xb78dff905b628ab4, - 0x68140b797ba74ab8, - 0x116cf037991d1143, - 0x2f7fe82e58acb0b8, - 0xc20bf7a8f7be5d45, - 0x86c2905c338d5709, - 0xff13a3ae6c8ace3d, - 0xb6f95e2282d08337, - 0xd49f7b313e9cbf29, - 0xf794517193a1ce8c, - 0x39641fecb596a874, - 0x411c4c4edf462fb3, - 0x3f8cd55c10cf25b4, - 0x2bdd7ea165e860b6, - 0xacd7d2cef4caa193, - 0x6558a1d09a05f96, - 0x1f52b5f5b546fc20, - 0x4ee22a5a8c250c12, - 0xd3a63a54a205b6b3, - 0xd2ff5be8, - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ12_C1[10], - nqr.pow(vec![ - 0xe5953a4f96cdda44, - 0x336b2d734cbc32bb, - 0x3f79bfe3cd7410e, - 0x267ae19aaa0f0332, - 0x85a9c4db78d5c749, - 0x90996b046b5dc7d8, - 0x8945eae9820afc6a, - 0x2644ddea2b036bd, - 0x39898e35ac2e3819, - 0x2574eab095659ab9, - 0x65953d51ac5ea798, - 0xc6b8c7afe6752466, - 0x40e9e993e9286544, - 0x7e0ad34ad9700ea0, - 0xac1015eba2c69222, - 0x24f057a19239b5d8, - 0x2043b48c8a3767eb, - 0x1117c124a75d7ff4, - 0x433cfd1a09fb3ce7, - 0x25b087ce4bcf7fb, - 0xbcee0dc53a3e5bdb, - 0xbffda040cf028735, - 0xf7cf103a25512acc, - 0x31d4ecda673130b9, - 0xea0906dab18461e6, - 0x5a40585a5ac3050d, - 0x803358fc14fd0eda, - 0x3678ca654eada770, - 0x7b91a1293a45e33e, - 0xcd5e5b8ea8530e43, - 0x21ae563ab34da266, - 0xecb00dad60df8894, - 0x77fe53e652facfef, - 0x9b7d1ad0b00244ec, - 0xe695df5ca73f801, - 0x23cdb21feeab0149, - 0x14de113e7ea810d9, - 0x52600cd958dac7e7, - 0xc83392c14667e488, - 0x9f808444bc1717fc, - 0x56facb4bcf7c788f, - 0x8bcad53245fc3ca0, - 0xdef661e83f27d81c, - 0x37d4ebcac9ad87e5, - 0x6fe8b24f5cdb9324, - 0xee08a26c1197654c, - 0xc98b22f65f237e9a, - 0xf54873a908ed3401, - 0x6e1cb951d41f3f3, - 0x290b2250a54e8df6, - 0x7f36d51eb1db669e, - 0xb08c7ed81a6ee43e, - 0x95e1c90fb092f680, - 0x429e4afd0e8b820, - 0x2c14a83ee87d715c, - 0xf37267575cfc8af5, - 0xb99e9afeda3c2c30, - 0x8f0f69da75792d5a, - 0x35074a85a533c73, - 0x156ed119, - ]) - ); - assert_eq!( - FROBENIUS_COEFF_FQ12_C1[11], - nqr.pow(vec![ - 0x107db680942de533, - 0x6262b24d2052393b, - 0x6136df824159ebc, - 0xedb052c9970c5deb, - 0xca813aea916c3777, - 0xf49dacb9d76c1788, - 0x624941bd372933bb, - 0xa5e60c2520638331, - 0xb38b661683411074, - 0x1d2c9af4c43d962b, - 0x17d807a0f14aa830, - 0x6e6581a51012c108, - 0x668a537e5b35e6f5, - 0x6c396cf3782dca5d, - 0x33b679d1bff536ed, - 0x736cce41805d90aa, - 0x8a562f369eb680bf, - 0x9f61aa208a11ded8, - 0x43dd89dd94d20f35, - 0xcf84c6610575c10a, - 0x9f318d49cf2fe8e6, - 0xbbc6e5f25a6e434e, - 0x6528c433d11d987b, - 0xffced71cc48c0e8a, - 0x4cbb1474f4cb2a26, - 0x66a035c0b28b7231, - 0xa6f2875faa1a82ae, - 0xdd1ea3deff818b02, - 0xe0cfdf0dcdecf701, - 0x9aefa231f2f6d23, - 0xfb251297efa06746, - 0x5a40d367df985538, - 0x1ea31d69ab506fed, - 0xc64ea8280e89a73f, - 0x969acf9f2d4496f4, - 0xe84c9181ee60c52c, - 0xc60f27fc19fc6ca4, - 0x760b33d850154048, - 0x84f69080f66c8457, - 0xc0192ba0fabf640e, - 0xd2c338765c23a3a8, - 0xa7838c20f02cec6c, - 0xb7cf01d020572877, - 0xd63ffaeba0be200a, - 0xf7492baeb5f041ac, - 0x8602c5212170d117, - 0xad9b2e83a5a42068, - 0x2461829b3ba1083e, - 0x7c34650da5295273, - 0xdc824ba800a8265a, - 0xd18d9b47836af7b2, - 0x3af78945c58cbf4d, - 0x7ed9575b8596906c, - 0x6d0c133895009a66, - 0x53bc1247ea349fe1, - 0x6b3063078d41aa7a, - 0x6184acd8cd880b33, - 0x76f4d15503fd1b96, - 0x7a9afd61eef25746, - 0xce974aadece60609, - 0x88ca59546a8ceafd, - 0x6d29391c41a0ac07, - 0x443843a60e0f46a6, - 0xa1590f62fd2602c7, - 0x536d5b15b514373f, - 0x22d582b, - ]) - ); -} - -#[test] -fn test_neg_one() { - let mut o = Fq::one(); - o.negate(); - - assert_eq!(NEGATIVE_ONE, o); -} - -#[cfg(test)] -use rand::{Rand, SeedableRng, XorShiftRng}; - -#[test] -fn test_fq_repr_ordering() { - use std::cmp::Ordering; - - fn assert_equality(a: FqRepr, b: FqRepr) { - assert_eq!(a, b); - assert!(a.cmp(&b) == Ordering::Equal); - } - - fn assert_lt(a: FqRepr, b: FqRepr) { - assert!(a < b); - assert!(b > a); - } - - assert_equality( - FqRepr([9999, 9999, 9999, 9999, 9999, 9999]), - FqRepr([9999, 9999, 9999, 9999, 9999, 9999]), - ); - assert_equality( - FqRepr([9999, 9998, 9999, 9999, 9999, 9999]), - FqRepr([9999, 9998, 9999, 9999, 9999, 9999]), - ); - assert_equality( - FqRepr([9999, 9999, 9999, 9997, 9999, 9999]), - FqRepr([9999, 9999, 9999, 9997, 9999, 9999]), - ); - assert_lt( - FqRepr([9999, 9999, 9999, 9997, 9999, 9998]), - FqRepr([9999, 9999, 9999, 9997, 9999, 9999]), - ); - assert_lt( - FqRepr([9999, 9999, 9999, 9997, 9998, 9999]), - FqRepr([9999, 9999, 9999, 9997, 9999, 9999]), - ); - assert_lt( - FqRepr([9, 9999, 9999, 9997, 9998, 9999]), - FqRepr([9999, 9999, 9999, 9997, 9999, 9999]), - ); -} - -#[test] -fn test_fq_repr_from() { - assert_eq!(FqRepr::from(100), FqRepr([100, 0, 0, 0, 0, 0])); -} - -#[test] -fn test_fq_repr_is_odd() { - assert!(!FqRepr::from(0).is_odd()); - assert!(FqRepr::from(0).is_even()); - assert!(FqRepr::from(1).is_odd()); - assert!(!FqRepr::from(1).is_even()); - assert!(!FqRepr::from(324834872).is_odd()); - assert!(FqRepr::from(324834872).is_even()); - assert!(FqRepr::from(324834873).is_odd()); - assert!(!FqRepr::from(324834873).is_even()); -} - -#[test] -fn test_fq_repr_is_zero() { - assert!(FqRepr::from(0).is_zero()); - assert!(!FqRepr::from(1).is_zero()); - assert!(!FqRepr([0, 0, 0, 0, 1, 0]).is_zero()); -} - -#[test] -fn test_fq_repr_div2() { - let mut a = FqRepr([ - 0x8b0ad39f8dd7482a, - 0x147221c9a7178b69, - 0x54764cb08d8a6aa0, - 0x8519d708e1d83041, - 0x41f82777bd13fdb, - 0xf43944578f9b771b, - ]); - a.div2(); - assert_eq!( - a, - FqRepr([ - 0xc58569cfc6eba415, - 0xa3910e4d38bc5b4, - 0xaa3b265846c53550, - 0xc28ceb8470ec1820, - 0x820fc13bbde89fed, - 0x7a1ca22bc7cdbb8d - ]) - ); - for _ in 0..10 { - a.div2(); - } - assert_eq!( - a, - FqRepr([ - 0x6d31615a73f1bae9, - 0x54028e443934e2f1, - 0x82a8ec99611b14d, - 0xfb70a33ae11c3b06, - 0xe36083f04eef7a27, - 0x1e87288af1f36e - ]) - ); - for _ in 0..300 { - a.div2(); - } - assert_eq!(a, FqRepr([0x7288af1f36ee3608, 0x1e8, 0x0, 0x0, 0x0, 0x0])); - for _ in 0..50 { - a.div2(); - } - assert_eq!(a, FqRepr([0x7a1ca2, 0x0, 0x0, 0x0, 0x0, 0x0])); - for _ in 0..22 { - a.div2(); - } - assert_eq!(a, FqRepr([0x1, 0x0, 0x0, 0x0, 0x0, 0x0])); - a.div2(); - assert!(a.is_zero()); -} - -#[test] -fn test_fq_repr_shr() { - let mut a = FqRepr([ - 0xaa5cdd6172847ffd, - 0x43242c06aed55287, - 0x9ddd5b312f3dd104, - 0xc5541fd48046b7e7, - 0x16080cf4071e0b05, - 0x1225f2901aea514e, - ]); - a.shr(0); - assert_eq!( - a, - FqRepr([ - 0xaa5cdd6172847ffd, - 0x43242c06aed55287, - 0x9ddd5b312f3dd104, - 0xc5541fd48046b7e7, - 0x16080cf4071e0b05, - 0x1225f2901aea514e - ]) - ); - a.shr(1); - assert_eq!( - a, - FqRepr([ - 0xd52e6eb0b9423ffe, - 0x21921603576aa943, - 0xceeead98979ee882, - 0xe2aa0fea40235bf3, - 0xb04067a038f0582, - 0x912f9480d7528a7 - ]) - ); - a.shr(50); - assert_eq!( - a, - FqRepr([ - 0x8580d5daaa50f54b, - 0xab6625e7ba208864, - 0x83fa9008d6fcf3bb, - 0x19e80e3c160b8aa, - 0xbe52035d4a29c2c1, - 0x244 - ]) - ); - a.shr(130); - assert_eq!( - a, - FqRepr([ - 0xa0fea40235bf3cee, - 0x4067a038f0582e2a, - 0x2f9480d7528a70b0, - 0x91, - 0x0, - 0x0 - ]) - ); - a.shr(64); - assert_eq!( - a, - FqRepr([0x4067a038f0582e2a, 0x2f9480d7528a70b0, 0x91, 0x0, 0x0, 0x0]) - ); -} - -#[test] -fn test_fq_repr_mul2() { - let mut a = FqRepr::from(23712937547); - a.mul2(); - assert_eq!(a, FqRepr([0xb0acd6c96, 0x0, 0x0, 0x0, 0x0, 0x0])); - for _ in 0..60 { - a.mul2(); - } - assert_eq!( - a, - FqRepr([0x6000000000000000, 0xb0acd6c9, 0x0, 0x0, 0x0, 0x0]) - ); - for _ in 0..300 { - a.mul2(); - } - assert_eq!(a, FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0xcd6c960000000000])); - for _ in 0..17 { - a.mul2(); - } - assert_eq!(a, FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x2c00000000000000])); - for _ in 0..6 { - a.mul2(); - } - assert!(a.is_zero()); -} - -#[test] -fn test_fq_repr_num_bits() { - let mut a = FqRepr::from(0); - assert_eq!(0, a.num_bits()); - a = FqRepr::from(1); - for i in 1..385 { - assert_eq!(i, a.num_bits()); - a.mul2(); - } - assert_eq!(0, a.num_bits()); -} - -#[test] -fn test_fq_repr_sub_noborrow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let mut t = FqRepr([ - 0x827a4a08041ebd9, - 0x3c239f3dcc8f0d6b, - 0x9ab46a912d555364, - 0x196936b17b43910b, - 0xad0eb3948a5c34fd, - 0xd56f7b5ab8b5ce8, - ]); - t.sub_noborrow(&FqRepr([ - 0xc7867917187ca02b, - 0x5d75679d4911ffef, - 0x8c5b3e48b1a71c15, - 0x6a427ae846fd66aa, - 0x7a37e7265ee1eaf9, - 0x7c0577a26f59d5, - ])); - assert!( - t == FqRepr([ - 0x40a12b8967c54bae, - 0xdeae37a0837d0d7b, - 0xe592c487bae374e, - 0xaf26bbc934462a61, - 0x32d6cc6e2b7a4a03, - 0xcdaf23e091c0313 - ]) - ); - - for _ in 0..1000 { - let mut a = FqRepr::rand(&mut rng); - a.0[5] >>= 30; - let mut b = a; - for _ in 0..10 { - b.mul2(); - } - let mut c = b; - for _ in 0..10 { - c.mul2(); - } - - assert!(a < b); - assert!(b < c); - - let mut csub_ba = c; - csub_ba.sub_noborrow(&b); - csub_ba.sub_noborrow(&a); - - let mut csub_ab = c; - csub_ab.sub_noborrow(&a); - csub_ab.sub_noborrow(&b); - - assert_eq!(csub_ab, csub_ba); - } - - // Subtracting q+1 from q should produce -1 (mod 2**384) - let mut qplusone = FqRepr([ - 0xb9feffffffffaaab, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a, - ]); - qplusone.sub_noborrow(&FqRepr([ - 0xb9feffffffffaaac, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a, - ])); - assert_eq!( - qplusone, - FqRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff - ]) - ); -} - -#[test] -fn test_fq_repr_add_nocarry() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let mut t = FqRepr([ - 0x827a4a08041ebd9, - 0x3c239f3dcc8f0d6b, - 0x9ab46a912d555364, - 0x196936b17b43910b, - 0xad0eb3948a5c34fd, - 0xd56f7b5ab8b5ce8, - ]); - t.add_nocarry(&FqRepr([ - 0xc7867917187ca02b, - 0x5d75679d4911ffef, - 0x8c5b3e48b1a71c15, - 0x6a427ae846fd66aa, - 0x7a37e7265ee1eaf9, - 0x7c0577a26f59d5, - ])); - assert!( - t == FqRepr([ - 0xcfae1db798be8c04, - 0x999906db15a10d5a, - 0x270fa8d9defc6f79, - 0x83abb199c240f7b6, - 0x27469abae93e1ff6, - 0xdd2fd2d4dfab6be - ]) - ); - - // Test for the associativity of addition. - for _ in 0..1000 { - let mut a = FqRepr::rand(&mut rng); - let mut b = FqRepr::rand(&mut rng); - let mut c = FqRepr::rand(&mut rng); - - // Unset the first few bits, so that overflow won't occur. - a.0[5] >>= 3; - b.0[5] >>= 3; - c.0[5] >>= 3; - - let mut abc = a; - abc.add_nocarry(&b); - abc.add_nocarry(&c); - - let mut acb = a; - acb.add_nocarry(&c); - acb.add_nocarry(&b); - - let mut bac = b; - bac.add_nocarry(&a); - bac.add_nocarry(&c); - - let mut bca = b; - bca.add_nocarry(&c); - bca.add_nocarry(&a); - - let mut cab = c; - cab.add_nocarry(&a); - cab.add_nocarry(&b); - - let mut cba = c; - cba.add_nocarry(&b); - cba.add_nocarry(&a); - - assert_eq!(abc, acb); - assert_eq!(abc, bac); - assert_eq!(abc, bca); - assert_eq!(abc, cab); - assert_eq!(abc, cba); - } - - // Adding 1 to (2^384 - 1) should produce zero - let mut x = FqRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - ]); - x.add_nocarry(&FqRepr::from(1)); - assert!(x.is_zero()); -} - -#[test] -fn test_fq_is_valid() { - let mut a = Fq(MODULUS); - assert!(!a.is_valid()); - a.0.sub_noborrow(&FqRepr::from(1)); - assert!(a.is_valid()); - assert!(Fq(FqRepr::from(0)).is_valid()); - assert!( - Fq(FqRepr([ - 0xdf4671abd14dab3e, - 0xe2dc0c9f534fbd33, - 0x31ca6c880cc444a6, - 0x257a67e70ef33359, - 0xf9b29e493f899b36, - 0x17c8be1800b9f059 - ])).is_valid() - ); - assert!( - !Fq(FqRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff - ])).is_valid() - ); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let a = Fq::rand(&mut rng); - assert!(a.is_valid()); - } -} - -#[test] -fn test_fq_add_assign() { - { - // Random number - let mut tmp = Fq(FqRepr([ - 0x624434821df92b69, - 0x503260c04fd2e2ea, - 0xd9df726e0d16e8ce, - 0xfbcb39adfd5dfaeb, - 0x86b8a22b0c88b112, - 0x165a2ed809e4201b, - ])); - assert!(tmp.is_valid()); - // Test that adding zero has no effect. - tmp.add_assign(&Fq(FqRepr::from(0))); - assert_eq!( - tmp, - Fq(FqRepr([ - 0x624434821df92b69, - 0x503260c04fd2e2ea, - 0xd9df726e0d16e8ce, - 0xfbcb39adfd5dfaeb, - 0x86b8a22b0c88b112, - 0x165a2ed809e4201b - ])) - ); - // Add one and test for the result. - tmp.add_assign(&Fq(FqRepr::from(1))); - assert_eq!( - tmp, - Fq(FqRepr([ - 0x624434821df92b6a, - 0x503260c04fd2e2ea, - 0xd9df726e0d16e8ce, - 0xfbcb39adfd5dfaeb, - 0x86b8a22b0c88b112, - 0x165a2ed809e4201b - ])) - ); - // Add another random number that exercises the reduction. - tmp.add_assign(&Fq(FqRepr([ - 0x374d8f8ea7a648d8, - 0xe318bb0ebb8bfa9b, - 0x613d996f0a95b400, - 0x9fac233cb7e4fef1, - 0x67e47552d253c52, - 0x5c31b227edf25da, - ]))); - assert_eq!( - tmp, - Fq(FqRepr([ - 0xdf92c410c59fc997, - 0x149f1bd05a0add85, - 0xd3ec393c20fba6ab, - 0x37001165c1bde71d, - 0x421b41c9f662408e, - 0x21c38104f435f5b - ])) - ); - // Add one to (q - 1) and test for the result. - tmp = Fq(FqRepr([ - 0xb9feffffffffaaaa, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a, - ])); - tmp.add_assign(&Fq(FqRepr::from(1))); - assert!(tmp.0.is_zero()); - // Add a random number to another one such that the result is q - 1 - tmp = Fq(FqRepr([ - 0x531221a410efc95b, - 0x72819306027e9717, - 0x5ecefb937068b746, - 0x97de59cd6feaefd7, - 0xdc35c51158644588, - 0xb2d176c04f2100, - ])); - tmp.add_assign(&Fq(FqRepr([ - 0x66ecde5bef0fe14f, - 0xac2a6cf8aed568e8, - 0x861d70d86483edd, - 0xcc98f1b7839a22e8, - 0x6ee5e2a4eae7674e, - 0x194e40737930c599, - ]))); - assert_eq!( - tmp, - Fq(FqRepr([ - 0xb9feffffffffaaaa, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a - ])) - ); - // Add one to the result and test for it. - tmp.add_assign(&Fq(FqRepr::from(1))); - assert!(tmp.0.is_zero()); - } - - // Test associativity - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Generate a, b, c and ensure (a + b) + c == a + (b + c). - let a = Fq::rand(&mut rng); - let b = Fq::rand(&mut rng); - let c = Fq::rand(&mut rng); - - let mut tmp1 = a; - tmp1.add_assign(&b); - tmp1.add_assign(&c); - - let mut tmp2 = b; - tmp2.add_assign(&c); - tmp2.add_assign(&a); - - assert!(tmp1.is_valid()); - assert!(tmp2.is_valid()); - assert_eq!(tmp1, tmp2); - } -} - -#[test] -fn test_fq_sub_assign() { - { - // Test arbitrary subtraction that tests reduction. - let mut tmp = Fq(FqRepr([ - 0x531221a410efc95b, - 0x72819306027e9717, - 0x5ecefb937068b746, - 0x97de59cd6feaefd7, - 0xdc35c51158644588, - 0xb2d176c04f2100, - ])); - tmp.sub_assign(&Fq(FqRepr([ - 0x98910d20877e4ada, - 0x940c983013f4b8ba, - 0xf677dc9b8345ba33, - 0xbef2ce6b7f577eba, - 0xe1ae288ac3222c44, - 0x5968bb602790806, - ]))); - assert_eq!( - tmp, - Fq(FqRepr([ - 0x748014838971292c, - 0xfd20fad49fddde5c, - 0xcf87f198e3d3f336, - 0x3d62d6e6e41883db, - 0x45a3443cd88dc61b, - 0x151d57aaf755ff94 - ])) - ); - - // Test the opposite subtraction which doesn't test reduction. - tmp = Fq(FqRepr([ - 0x98910d20877e4ada, - 0x940c983013f4b8ba, - 0xf677dc9b8345ba33, - 0xbef2ce6b7f577eba, - 0xe1ae288ac3222c44, - 0x5968bb602790806, - ])); - tmp.sub_assign(&Fq(FqRepr([ - 0x531221a410efc95b, - 0x72819306027e9717, - 0x5ecefb937068b746, - 0x97de59cd6feaefd7, - 0xdc35c51158644588, - 0xb2d176c04f2100, - ]))); - assert_eq!( - tmp, - Fq(FqRepr([ - 0x457eeb7c768e817f, - 0x218b052a117621a3, - 0x97a8e10812dd02ed, - 0x2714749e0f6c8ee3, - 0x57863796abde6bc, - 0x4e3ba3f4229e706 - ])) - ); - - // Test for sensible results with zero - tmp = Fq(FqRepr::from(0)); - tmp.sub_assign(&Fq(FqRepr::from(0))); - assert!(tmp.is_zero()); - - tmp = Fq(FqRepr([ - 0x98910d20877e4ada, - 0x940c983013f4b8ba, - 0xf677dc9b8345ba33, - 0xbef2ce6b7f577eba, - 0xe1ae288ac3222c44, - 0x5968bb602790806, - ])); - tmp.sub_assign(&Fq(FqRepr::from(0))); - assert_eq!( - tmp, - Fq(FqRepr([ - 0x98910d20877e4ada, - 0x940c983013f4b8ba, - 0xf677dc9b8345ba33, - 0xbef2ce6b7f577eba, - 0xe1ae288ac3222c44, - 0x5968bb602790806 - ])) - ); - } - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Ensure that (a - b) + (b - a) = 0. - let a = Fq::rand(&mut rng); - let b = Fq::rand(&mut rng); - - let mut tmp1 = a; - tmp1.sub_assign(&b); - - let mut tmp2 = b; - tmp2.sub_assign(&a); - - tmp1.add_assign(&tmp2); - assert!(tmp1.is_zero()); - } -} - -#[test] -fn test_fq_mul_assign() { - let mut tmp = Fq(FqRepr([ - 0xcc6200000020aa8a, - 0x422800801dd8001a, - 0x7f4f5e619041c62c, - 0x8a55171ac70ed2ba, - 0x3f69cc3a3d07d58b, - 0xb972455fd09b8ef, - ])); - tmp.mul_assign(&Fq(FqRepr([ - 0x329300000030ffcf, - 0x633c00c02cc40028, - 0xbef70d925862a942, - 0x4f7fa2a82a963c17, - 0xdf1eb2575b8bc051, - 0x1162b680fb8e9566, - ]))); - assert!( - tmp == Fq(FqRepr([ - 0x9dc4000001ebfe14, - 0x2850078997b00193, - 0xa8197f1abb4d7bf, - 0xc0309573f4bfe871, - 0xf48d0923ffaf7620, - 0x11d4b58c7a926e66 - ])) - ); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000000 { - // Ensure that (a * b) * c = a * (b * c) - let a = Fq::rand(&mut rng); - let b = Fq::rand(&mut rng); - let c = Fq::rand(&mut rng); - - let mut tmp1 = a; - tmp1.mul_assign(&b); - tmp1.mul_assign(&c); - - let mut tmp2 = b; - tmp2.mul_assign(&c); - tmp2.mul_assign(&a); - - assert_eq!(tmp1, tmp2); - } - - for _ in 0..1000000 { - // Ensure that r * (a + b + c) = r*a + r*b + r*c - - let r = Fq::rand(&mut rng); - let mut a = Fq::rand(&mut rng); - let mut b = Fq::rand(&mut rng); - let mut c = Fq::rand(&mut rng); - - let mut tmp1 = a; - tmp1.add_assign(&b); - tmp1.add_assign(&c); - tmp1.mul_assign(&r); - - a.mul_assign(&r); - b.mul_assign(&r); - c.mul_assign(&r); - - a.add_assign(&b); - a.add_assign(&c); - - assert_eq!(tmp1, a); - } -} - -#[test] -fn test_fq_squaring() { - let mut a = Fq(FqRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0x19ffffffffffffff, - ])); - assert!(a.is_valid()); - a.square(); - assert_eq!( - a, - Fq::from_repr(FqRepr([ - 0x1cfb28fe7dfbbb86, - 0x24cbe1731577a59, - 0xcce1d4edc120e66e, - 0xdc05c659b4e15b27, - 0x79361e5a802c6a23, - 0x24bcbe5d51b9a6f - ])).unwrap() - ); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000000 { - // Ensure that (a * a) = a^2 - let a = Fq::rand(&mut rng); - - let mut tmp = a; - tmp.square(); - - let mut tmp2 = a; - tmp2.mul_assign(&a); - - assert_eq!(tmp, tmp2); - } -} - -#[test] -fn test_fq_inverse() { - assert!(Fq::zero().inverse().is_none()); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let one = Fq::one(); - - for _ in 0..1000 { - // Ensure that a * a^-1 = 1 - let mut a = Fq::rand(&mut rng); - let ainv = a.inverse().unwrap(); - a.mul_assign(&ainv); - assert_eq!(a, one); - } -} - -#[test] -fn test_fq_double() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Ensure doubling a is equivalent to adding a to itself. - let mut a = Fq::rand(&mut rng); - let mut b = a; - b.add_assign(&a); - a.double(); - assert_eq!(a, b); - } -} - -#[test] -fn test_fq_negate() { - { - let mut a = Fq::zero(); - a.negate(); - - assert!(a.is_zero()); - } - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Ensure (a - (-a)) = 0. - let mut a = Fq::rand(&mut rng); - let mut b = a; - b.negate(); - a.add_assign(&b); - - assert!(a.is_zero()); - } -} - -#[test] -fn test_fq_pow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for i in 0..1000 { - // Exponentiate by various small numbers and ensure it consists with repeated - // multiplication. - let a = Fq::rand(&mut rng); - let target = a.pow(&[i]); - let mut c = Fq::one(); - for _ in 0..i { - c.mul_assign(&a); - } - assert_eq!(c, target); - } - - for _ in 0..1000 { - // Exponentiating by the modulus should have no effect in a prime field. - let a = Fq::rand(&mut rng); - - assert_eq!(a, a.pow(Fq::char())); - } -} - -#[test] -fn test_fq_sqrt() { - use ff::SqrtField; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - assert_eq!(Fq::zero().sqrt().unwrap(), Fq::zero()); - - for _ in 0..1000 { - // Ensure sqrt(a^2) = a or -a - let a = Fq::rand(&mut rng); - let mut nega = a; - nega.negate(); - let mut b = a; - b.square(); - - let b = b.sqrt().unwrap(); - - assert!(a == b || nega == b); - } - - for _ in 0..1000 { - // Ensure sqrt(a)^2 = a for random a - let a = Fq::rand(&mut rng); - - if let Some(mut tmp) = a.sqrt() { - tmp.square(); - - assert_eq!(a, tmp); - } - } -} - -#[test] -fn test_fq_from_into_repr() { - // q + 1 should not be in the field - assert!( - Fq::from_repr(FqRepr([ - 0xb9feffffffffaaac, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a - ])).is_err() - ); - - // q should not be in the field - assert!(Fq::from_repr(Fq::char()).is_err()); - - // Multiply some arbitrary representations to see if the result is as expected. - let a = FqRepr([ - 0x4a49dad4ff6cde2d, - 0xac62a82a8f51cd50, - 0x2b1f41ab9f36d640, - 0x908a387f480735f1, - 0xae30740c08a875d7, - 0x6c80918a365ef78, - ]); - let mut a_fq = Fq::from_repr(a).unwrap(); - let b = FqRepr([ - 0xbba57917c32f0cf0, - 0xe7f878cf87f05e5d, - 0x9498b4292fd27459, - 0xd59fd94ee4572cfa, - 0x1f607186d5bb0059, - 0xb13955f5ac7f6a3, - ]); - let b_fq = Fq::from_repr(b).unwrap(); - let c = FqRepr([ - 0xf5f70713b717914c, - 0x355ea5ac64cbbab1, - 0xce60dd43417ec960, - 0xf16b9d77b0ad7d10, - 0xa44c204c1de7cdb7, - 0x1684487772bc9a5a, - ]); - a_fq.mul_assign(&b_fq); - assert_eq!(a_fq.into_repr(), c); - - // Zero should be in the field. - assert!(Fq::from_repr(FqRepr::from(0)).unwrap().is_zero()); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Try to turn Fq elements into representations and back again, and compare. - let a = Fq::rand(&mut rng); - let a_repr = a.into_repr(); - let b_repr = FqRepr::from(a); - assert_eq!(a_repr, b_repr); - let a_again = Fq::from_repr(a_repr).unwrap(); - - assert_eq!(a, a_again); - } -} - -#[test] -fn test_fq_repr_display() { - assert_eq!( - format!("{}", FqRepr([0xa956babf9301ea24, 0x39a8f184f3535c7b, 0xb38d35b3f6779585, 0x676cc4eef4c46f2c, 0xb1d4aad87651e694, 0x1947f0d5f4fe325a])), - "0x1947f0d5f4fe325ab1d4aad87651e694676cc4eef4c46f2cb38d35b3f677958539a8f184f3535c7ba956babf9301ea24".to_string() - ); - assert_eq!( - format!("{}", FqRepr([0xb4171485fd8622dd, 0x864229a6edec7ec5, 0xc57f7bdcf8dfb707, 0x6db7ff0ecea4584a, 0xf8d8578c4a57132d, 0x6eb66d42d9fcaaa])), - "0x06eb66d42d9fcaaaf8d8578c4a57132d6db7ff0ecea4584ac57f7bdcf8dfb707864229a6edec7ec5b4171485fd8622dd".to_string() - ); - assert_eq!( - format!("{}", FqRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])), - "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string() - ); - assert_eq!( - format!("{}", FqRepr([0, 0, 0, 0, 0, 0])), - "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".to_string() - ); -} - -#[test] -fn test_fq_display() { - assert_eq!( - format!("{}", Fq::from_repr(FqRepr([0xa956babf9301ea24, 0x39a8f184f3535c7b, 0xb38d35b3f6779585, 0x676cc4eef4c46f2c, 0xb1d4aad87651e694, 0x1947f0d5f4fe325a])).unwrap()), - "Fq(0x1947f0d5f4fe325ab1d4aad87651e694676cc4eef4c46f2cb38d35b3f677958539a8f184f3535c7ba956babf9301ea24)".to_string() - ); - assert_eq!( - format!("{}", Fq::from_repr(FqRepr([0xe28e79396ac2bbf8, 0x413f6f7f06ea87eb, 0xa4b62af4a792a689, 0xb7f89f88f59c1dc5, 0x9a551859b1e43a9a, 0x6c9f5a1060de974])).unwrap()), - "Fq(0x06c9f5a1060de9749a551859b1e43a9ab7f89f88f59c1dc5a4b62af4a792a689413f6f7f06ea87ebe28e79396ac2bbf8)".to_string() - ); -} - -#[test] -fn test_fq_num_bits() { - assert_eq!(Fq::NUM_BITS, 381); - assert_eq!(Fq::CAPACITY, 380); -} - -#[test] -fn test_fq_root_of_unity() { - use ff::SqrtField; - - assert_eq!(Fq::S, 1); - assert_eq!( - Fq::multiplicative_generator(), - Fq::from_repr(FqRepr::from(2)).unwrap() - ); - assert_eq!( - Fq::multiplicative_generator().pow([ - 0xdcff7fffffffd555, - 0xf55ffff58a9ffff, - 0xb39869507b587b12, - 0xb23ba5c279c2895f, - 0x258dd3db21a5d66b, - 0xd0088f51cbff34d - ]), - Fq::root_of_unity() - ); - assert_eq!(Fq::root_of_unity().pow([1 << Fq::S]), Fq::one()); - assert!(Fq::multiplicative_generator().sqrt().is_none()); -} - -#[test] -fn fq_field_tests() { - ::tests::field::random_field_tests::(); - ::tests::field::random_sqrt_tests::(); - ::tests::field::random_frobenius_tests::(Fq::char(), 13); - ::tests::field::from_str_tests::(); -} - -#[test] -fn test_fq_ordering() { - // FqRepr's ordering is well-tested, but we still need to make sure the Fq - // elements aren't being compared in Montgomery form. - for i in 0..100 { - assert!( - Fq::from_repr(FqRepr::from(i + 1)).unwrap() > Fq::from_repr(FqRepr::from(i)).unwrap() - ); - } -} - -#[test] -fn fq_repr_tests() { - ::tests::repr::random_repr_tests::(); -} - -#[test] -fn test_fq_legendre() { - use ff::LegendreSymbol::*; - use ff::SqrtField; - - assert_eq!(QuadraticResidue, Fq::one().legendre()); - assert_eq!(Zero, Fq::zero().legendre()); - - assert_eq!( - QuadraticNonResidue, - Fq::from_repr(FqRepr::from(2)).unwrap().legendre() - ); - assert_eq!( - QuadraticResidue, - Fq::from_repr(FqRepr::from(4)).unwrap().legendre() - ); - - let e = FqRepr([ - 0x52a112f249778642, - 0xd0bedb989b7991f, - 0xdad3b6681aa63c05, - 0xf2efc0bb4721b283, - 0x6057a98f18c24733, - 0x1022c2fd122889e4, - ]); - assert_eq!(QuadraticNonResidue, Fq::from_repr(e).unwrap().legendre()); - let e = FqRepr([ - 0x6dae594e53a96c74, - 0x19b16ca9ba64b37b, - 0x5c764661a59bfc68, - 0xaa346e9b31c60a, - 0x346059f9d87a9fa9, - 0x1d61ac6bfd5c88b, - ]); - assert_eq!(QuadraticResidue, Fq::from_repr(e).unwrap().legendre()); -} diff --git a/pairing/src/bls12_381/fq12.rs b/pairing/src/bls12_381/fq12.rs deleted file mode 100644 index b24fcaa..0000000 --- a/pairing/src/bls12_381/fq12.rs +++ /dev/null @@ -1,189 +0,0 @@ -use super::fq::FROBENIUS_COEFF_FQ12_C1; -use super::fq2::Fq2; -use super::fq6::Fq6; -use ff::Field; -use rand::{Rand, Rng}; - -/// An element of Fq12, represented by c0 + c1 * w. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Fq12 { - pub c0: Fq6, - pub c1: Fq6, -} - -impl ::std::fmt::Display for Fq12 { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "Fq12({} + {} * w)", self.c0, self.c1) - } -} - -impl Rand for Fq12 { - fn rand(rng: &mut R) -> Self { - Fq12 { - c0: rng.gen(), - c1: rng.gen(), - } - } -} - -impl Fq12 { - pub fn conjugate(&mut self) { - self.c1.negate(); - } - - pub fn mul_by_014(&mut self, c0: &Fq2, c1: &Fq2, c4: &Fq2) { - let mut aa = self.c0; - aa.mul_by_01(c0, c1); - let mut bb = self.c1; - bb.mul_by_1(c4); - let mut o = *c1; - o.add_assign(c4); - self.c1.add_assign(&self.c0); - self.c1.mul_by_01(c0, &o); - self.c1.sub_assign(&aa); - self.c1.sub_assign(&bb); - self.c0 = bb; - self.c0.mul_by_nonresidue(); - self.c0.add_assign(&aa); - } -} - -impl Field for Fq12 { - fn zero() -> Self { - Fq12 { - c0: Fq6::zero(), - c1: Fq6::zero(), - } - } - - fn one() -> Self { - Fq12 { - c0: Fq6::one(), - c1: Fq6::zero(), - } - } - - fn is_zero(&self) -> bool { - self.c0.is_zero() && self.c1.is_zero() - } - - fn double(&mut self) { - self.c0.double(); - self.c1.double(); - } - - fn negate(&mut self) { - self.c0.negate(); - self.c1.negate(); - } - - fn add_assign(&mut self, other: &Self) { - self.c0.add_assign(&other.c0); - self.c1.add_assign(&other.c1); - } - - fn sub_assign(&mut self, other: &Self) { - self.c0.sub_assign(&other.c0); - self.c1.sub_assign(&other.c1); - } - - fn frobenius_map(&mut self, power: usize) { - self.c0.frobenius_map(power); - self.c1.frobenius_map(power); - - self.c1.c0.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]); - self.c1.c1.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]); - self.c1.c2.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]); - } - - fn square(&mut self) { - let mut ab = self.c0; - ab.mul_assign(&self.c1); - let mut c0c1 = self.c0; - c0c1.add_assign(&self.c1); - let mut c0 = self.c1; - c0.mul_by_nonresidue(); - c0.add_assign(&self.c0); - c0.mul_assign(&c0c1); - c0.sub_assign(&ab); - self.c1 = ab; - self.c1.add_assign(&ab); - ab.mul_by_nonresidue(); - c0.sub_assign(&ab); - self.c0 = c0; - } - - fn mul_assign(&mut self, other: &Self) { - let mut aa = self.c0; - aa.mul_assign(&other.c0); - let mut bb = self.c1; - bb.mul_assign(&other.c1); - let mut o = other.c0; - o.add_assign(&other.c1); - self.c1.add_assign(&self.c0); - self.c1.mul_assign(&o); - self.c1.sub_assign(&aa); - self.c1.sub_assign(&bb); - self.c0 = bb; - self.c0.mul_by_nonresidue(); - self.c0.add_assign(&aa); - } - - fn inverse(&self) -> Option { - let mut c0s = self.c0; - c0s.square(); - let mut c1s = self.c1; - c1s.square(); - c1s.mul_by_nonresidue(); - c0s.sub_assign(&c1s); - - c0s.inverse().map(|t| { - let mut tmp = Fq12 { c0: t, c1: t }; - tmp.c0.mul_assign(&self.c0); - tmp.c1.mul_assign(&self.c1); - tmp.c1.negate(); - - tmp - }) - } -} - -#[cfg(test)] -use rand::{SeedableRng, XorShiftRng}; - -#[test] -fn test_fq12_mul_by_014() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let c0 = Fq2::rand(&mut rng); - let c1 = Fq2::rand(&mut rng); - let c5 = Fq2::rand(&mut rng); - let mut a = Fq12::rand(&mut rng); - let mut b = a; - - a.mul_by_014(&c0, &c1, &c5); - b.mul_assign(&Fq12 { - c0: Fq6 { - c0: c0, - c1: c1, - c2: Fq2::zero(), - }, - c1: Fq6 { - c0: Fq2::zero(), - c1: c5, - c2: Fq2::zero(), - }, - }); - - assert_eq!(a, b); - } -} - -#[test] -fn fq12_field_tests() { - use ff::PrimeField; - - ::tests::field::random_field_tests::(); - ::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); -} diff --git a/pairing/src/bls12_381/fq2.rs b/pairing/src/bls12_381/fq2.rs deleted file mode 100644 index 363439a..0000000 --- a/pairing/src/bls12_381/fq2.rs +++ /dev/null @@ -1,910 +0,0 @@ -use super::fq::{FROBENIUS_COEFF_FQ2_C1, Fq, NEGATIVE_ONE}; -use ff::{Field, SqrtField}; -use rand::{Rand, Rng}; - -use std::cmp::Ordering; - -/// An element of Fq2, represented by c0 + c1 * u. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Fq2 { - pub c0: Fq, - pub c1: Fq, -} - -impl ::std::fmt::Display for Fq2 { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "Fq2({} + {} * u)", self.c0, self.c1) - } -} - -/// `Fq2` elements are ordered lexicographically. -impl Ord for Fq2 { - #[inline(always)] - fn cmp(&self, other: &Fq2) -> Ordering { - match self.c1.cmp(&other.c1) { - Ordering::Greater => Ordering::Greater, - Ordering::Less => Ordering::Less, - Ordering::Equal => self.c0.cmp(&other.c0), - } - } -} - -impl PartialOrd for Fq2 { - #[inline(always)] - fn partial_cmp(&self, other: &Fq2) -> Option { - Some(self.cmp(other)) - } -} - -impl Fq2 { - /// Multiply this element by the cubic and quadratic nonresidue 1 + u. - pub fn mul_by_nonresidue(&mut self) { - let t0 = self.c0; - self.c0.sub_assign(&self.c1); - self.c1.add_assign(&t0); - } - - /// Norm of Fq2 as extension field in i over Fq - pub fn norm(&self) -> Fq { - let mut t0 = self.c0; - let mut t1 = self.c1; - t0.square(); - t1.square(); - t1.add_assign(&t0); - - t1 - } -} - -impl Rand for Fq2 { - fn rand(rng: &mut R) -> Self { - Fq2 { - c0: rng.gen(), - c1: rng.gen(), - } - } -} - -impl Field for Fq2 { - fn zero() -> Self { - Fq2 { - c0: Fq::zero(), - c1: Fq::zero(), - } - } - - fn one() -> Self { - Fq2 { - c0: Fq::one(), - c1: Fq::zero(), - } - } - - fn is_zero(&self) -> bool { - self.c0.is_zero() && self.c1.is_zero() - } - - fn square(&mut self) { - let mut ab = self.c0; - ab.mul_assign(&self.c1); - let mut c0c1 = self.c0; - c0c1.add_assign(&self.c1); - let mut c0 = self.c1; - c0.negate(); - c0.add_assign(&self.c0); - c0.mul_assign(&c0c1); - c0.sub_assign(&ab); - self.c1 = ab; - self.c1.add_assign(&ab); - c0.add_assign(&ab); - self.c0 = c0; - } - - fn double(&mut self) { - self.c0.double(); - self.c1.double(); - } - - fn negate(&mut self) { - self.c0.negate(); - self.c1.negate(); - } - - fn add_assign(&mut self, other: &Self) { - self.c0.add_assign(&other.c0); - self.c1.add_assign(&other.c1); - } - - fn sub_assign(&mut self, other: &Self) { - self.c0.sub_assign(&other.c0); - self.c1.sub_assign(&other.c1); - } - - fn mul_assign(&mut self, other: &Self) { - let mut aa = self.c0; - aa.mul_assign(&other.c0); - let mut bb = self.c1; - bb.mul_assign(&other.c1); - let mut o = other.c0; - o.add_assign(&other.c1); - self.c1.add_assign(&self.c0); - self.c1.mul_assign(&o); - self.c1.sub_assign(&aa); - self.c1.sub_assign(&bb); - self.c0 = aa; - self.c0.sub_assign(&bb); - } - - fn inverse(&self) -> Option { - let mut t1 = self.c1; - t1.square(); - let mut t0 = self.c0; - t0.square(); - t0.add_assign(&t1); - t0.inverse().map(|t| { - let mut tmp = Fq2 { - c0: self.c0, - c1: self.c1, - }; - tmp.c0.mul_assign(&t); - tmp.c1.mul_assign(&t); - tmp.c1.negate(); - - tmp - }) - } - - fn frobenius_map(&mut self, power: usize) { - self.c1.mul_assign(&FROBENIUS_COEFF_FQ2_C1[power % 2]); - } -} - -impl SqrtField for Fq2 { - fn legendre(&self) -> ::ff::LegendreSymbol { - self.norm().legendre() - } - - fn sqrt(&self) -> Option { - // Algorithm 9, https://eprint.iacr.org/2012/685.pdf - - if self.is_zero() { - Some(Self::zero()) - } else { - // a1 = self^((q - 3) / 4) - let mut a1 = self.pow([ - 0xee7fbfffffffeaaa, - 0x7aaffffac54ffff, - 0xd9cc34a83dac3d89, - 0xd91dd2e13ce144af, - 0x92c6e9ed90d2eb35, - 0x680447a8e5ff9a6, - ]); - let mut alpha = a1; - alpha.square(); - alpha.mul_assign(self); - let mut a0 = alpha; - a0.frobenius_map(1); - a0.mul_assign(&alpha); - - let neg1 = Fq2 { - c0: NEGATIVE_ONE, - c1: Fq::zero(), - }; - - if a0 == neg1 { - None - } else { - a1.mul_assign(self); - - if alpha == neg1 { - a1.mul_assign(&Fq2 { - c0: Fq::zero(), - c1: Fq::one(), - }); - } else { - alpha.add_assign(&Fq2::one()); - // alpha = alpha^((q - 1) / 2) - alpha = alpha.pow([ - 0xdcff7fffffffd555, - 0xf55ffff58a9ffff, - 0xb39869507b587b12, - 0xb23ba5c279c2895f, - 0x258dd3db21a5d66b, - 0xd0088f51cbff34d, - ]); - a1.mul_assign(&alpha); - } - - Some(a1) - } - } - } -} - -#[test] -fn test_fq2_ordering() { - let mut a = Fq2 { - c0: Fq::zero(), - c1: Fq::zero(), - }; - - let mut b = a.clone(); - - assert!(a.cmp(&b) == Ordering::Equal); - b.c0.add_assign(&Fq::one()); - assert!(a.cmp(&b) == Ordering::Less); - a.c0.add_assign(&Fq::one()); - assert!(a.cmp(&b) == Ordering::Equal); - b.c1.add_assign(&Fq::one()); - assert!(a.cmp(&b) == Ordering::Less); - a.c0.add_assign(&Fq::one()); - assert!(a.cmp(&b) == Ordering::Less); - a.c1.add_assign(&Fq::one()); - assert!(a.cmp(&b) == Ordering::Greater); - b.c0.add_assign(&Fq::one()); - assert!(a.cmp(&b) == Ordering::Equal); -} - -#[test] -fn test_fq2_basics() { - assert_eq!( - Fq2 { - c0: Fq::zero(), - c1: Fq::zero(), - }, - Fq2::zero() - ); - assert_eq!( - Fq2 { - c0: Fq::one(), - c1: Fq::zero(), - }, - Fq2::one() - ); - assert!(Fq2::zero().is_zero()); - assert!(!Fq2::one().is_zero()); - assert!( - !Fq2 { - c0: Fq::zero(), - c1: Fq::one(), - }.is_zero() - ); -} - -#[test] -fn test_fq2_squaring() { - use super::fq::FqRepr; - use ff::PrimeField; - - let mut a = Fq2 { - c0: Fq::one(), - c1: Fq::one(), - }; // u + 1 - a.square(); - assert_eq!( - a, - Fq2 { - c0: Fq::zero(), - c1: Fq::from_repr(FqRepr::from(2)).unwrap(), - } - ); // 2u - - let mut a = Fq2 { - c0: Fq::zero(), - c1: Fq::one(), - }; // u - a.square(); - assert_eq!(a, { - let mut neg1 = Fq::one(); - neg1.negate(); - Fq2 { - c0: neg1, - c1: Fq::zero(), - } - }); // -1 - - let mut a = Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x9c2c6309bbf8b598, - 0x4eef5c946536f602, - 0x90e34aab6fb6a6bd, - 0xf7f295a94e58ae7c, - 0x41b76dcc1c3fbe5e, - 0x7080c5fa1d8e042, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x38f473b3c870a4ab, - 0x6ad3291177c8c7e5, - 0xdac5a4c911a4353e, - 0xbfb99020604137a0, - 0xfc58a7b7be815407, - 0x10d1615e75250a21, - ])).unwrap(), - }; - a.square(); - assert_eq!( - a, - Fq2 { - c0: Fq::from_repr(FqRepr([ - 0xf262c28c538bcf68, - 0xb9f2a66eae1073ba, - 0xdc46ab8fad67ae0, - 0xcb674157618da176, - 0x4cf17b5893c3d327, - 0x7eac81369c43361 - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0xc1579cf58e980cf8, - 0xa23eb7e12dd54d98, - 0xe75138bce4cec7aa, - 0x38d0d7275a9689e1, - 0x739c983042779a65, - 0x1542a61c8a8db994 - ])).unwrap(), - } - ); -} - -#[test] -fn test_fq2_mul() { - use super::fq::FqRepr; - use ff::PrimeField; - - let mut a = Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x85c9f989e1461f03, - 0xa2e33c333449a1d6, - 0x41e461154a7354a3, - 0x9ee53e7e84d7532e, - 0x1c202d8ed97afb45, - 0x51d3f9253e2516f, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0xa7348a8b511aedcf, - 0x143c215d8176b319, - 0x4cc48081c09b8903, - 0x9533e4a9a5158be, - 0x7a5e1ecb676d65f9, - 0x180c3ee46656b008, - ])).unwrap(), - }; - a.mul_assign(&Fq2 { - c0: Fq::from_repr(FqRepr([ - 0xe21f9169805f537e, - 0xfc87e62e179c285d, - 0x27ece175be07a531, - 0xcd460f9f0c23e430, - 0x6c9110292bfa409, - 0x2c93a72eb8af83e, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x4b1c3f936d8992d4, - 0x1d2a72916dba4c8a, - 0x8871c508658d1e5f, - 0x57a06d3135a752ae, - 0x634cd3c6c565096d, - 0x19e17334d4e93558, - ])).unwrap(), - }); - assert_eq!( - a, - Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x95b5127e6360c7e4, - 0xde29c31a19a6937e, - 0xf61a96dacf5a39bc, - 0x5511fe4d84ee5f78, - 0x5310a202d92f9963, - 0x1751afbe166e5399 - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x84af0e1bd630117a, - 0x6c63cd4da2c2aa7, - 0x5ba6e5430e883d40, - 0xc975106579c275ee, - 0x33a9ac82ce4c5083, - 0x1ef1a36c201589d - ])).unwrap(), - } - ); -} - -#[test] -fn test_fq2_inverse() { - use super::fq::FqRepr; - use ff::PrimeField; - - assert!(Fq2::zero().inverse().is_none()); - - let a = Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x85c9f989e1461f03, - 0xa2e33c333449a1d6, - 0x41e461154a7354a3, - 0x9ee53e7e84d7532e, - 0x1c202d8ed97afb45, - 0x51d3f9253e2516f, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0xa7348a8b511aedcf, - 0x143c215d8176b319, - 0x4cc48081c09b8903, - 0x9533e4a9a5158be, - 0x7a5e1ecb676d65f9, - 0x180c3ee46656b008, - ])).unwrap(), - }; - let a = a.inverse().unwrap(); - assert_eq!( - a, - Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x70300f9bcb9e594, - 0xe5ecda5fdafddbb2, - 0x64bef617d2915a8f, - 0xdfba703293941c30, - 0xa6c3d8f9586f2636, - 0x1351ef01941b70c4 - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x8c39fd76a8312cb4, - 0x15d7b6b95defbff0, - 0x947143f89faedee9, - 0xcbf651a0f367afb2, - 0xdf4e54f0d3ef15a6, - 0x103bdf241afb0019 - ])).unwrap(), - } - ); -} - -#[test] -fn test_fq2_addition() { - use super::fq::FqRepr; - use ff::PrimeField; - - let mut a = Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837, - ])).unwrap(), - }; - a.add_assign(&Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x619a02d78dc70ef2, - 0xb93adfc9119e33e8, - 0x4bf0b99a9f0dca12, - 0x3b88899a42a6318f, - 0x986a4a62fa82a49d, - 0x13ce433fa26027f5, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x66323bf80b58b9b9, - 0xa1379b6facf6e596, - 0x402aef1fb797e32f, - 0x2236f55246d0d44d, - 0x4c8c1800eb104566, - 0x11d6e20e986c2085, - ])).unwrap(), - }); - assert_eq!( - a, - Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x8e9a7adaf6eb0eb9, - 0xcb207e6b3341eaba, - 0xd70b0c7b481d23ff, - 0xf4ef57d604b6bca2, - 0x65309427b3d5d090, - 0x14c715d5553f01d2 - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0xfdb032e7d9079a94, - 0x35a2809d15468d83, - 0xfe4b23317e0796d5, - 0xd62fa51334f560fa, - 0x9ad265eb46e01984, - 0x1303f3465112c8bc - ])).unwrap(), - } - ); -} - -#[test] -fn test_fq2_subtraction() { - use super::fq::FqRepr; - use ff::PrimeField; - - let mut a = Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837, - ])).unwrap(), - }; - a.sub_assign(&Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x619a02d78dc70ef2, - 0xb93adfc9119e33e8, - 0x4bf0b99a9f0dca12, - 0x3b88899a42a6318f, - 0x986a4a62fa82a49d, - 0x13ce433fa26027f5, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x66323bf80b58b9b9, - 0xa1379b6facf6e596, - 0x402aef1fb797e32f, - 0x2236f55246d0d44d, - 0x4c8c1800eb104566, - 0x11d6e20e986c2085, - ])).unwrap(), - }); - assert_eq!( - a, - Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x8565752bdb5c9b80, - 0x7756bed7c15982e9, - 0xa65a6be700b285fe, - 0xe255902672ef6c43, - 0x7f77a718021c342d, - 0x72ba14049fe9881 - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0xeb4abaf7c255d1cd, - 0x11df49bc6cacc256, - 0xe52617930588c69a, - 0xf63905f39ad8cb1f, - 0x4cd5dd9fb40b3b8f, - 0x957411359ba6e4c - ])).unwrap(), - } - ); -} - -#[test] -fn test_fq2_negation() { - use super::fq::FqRepr; - use ff::PrimeField; - - let mut a = Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837, - ])).unwrap(), - }; - a.negate(); - assert_eq!( - a, - Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x8cfe87fc96dbaae4, - 0xcc6615c8fb0492d, - 0xdc167fc04da19c37, - 0xab107d49317487ab, - 0x7e555df189f880e3, - 0x19083f5486a10cbd - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x228109103250c9d0, - 0x8a411ad149045812, - 0xa9109e8f3041427e, - 0xb07e9bc405608611, - 0xfcd559cbe77bd8b8, - 0x18d400b280d93e62 - ])).unwrap(), - } - ); -} - -#[test] -fn test_fq2_doubling() { - use super::fq::FqRepr; - use ff::PrimeField; - - let mut a = Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837, - ])).unwrap(), - }; - a.double(); - assert_eq!( - a, - Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x5a00f006d247ff8e, - 0x23cb3d4443476da4, - 0x1634a5c1521eb3da, - 0x72cd9c7784211627, - 0x998c938972a657e7, - 0x1f1a52b65bdb3b9 - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x2efbeddf9b5dc1b6, - 0x28d5ca5ad09f4fdb, - 0x7c4068238cdf674b, - 0x67f15f81dc49195b, - 0x9c8c9bd4b79fa83d, - 0x25a226f714d506e - ])).unwrap(), - } - ); -} - -#[test] -fn test_fq2_frobenius_map() { - use super::fq::FqRepr; - use ff::PrimeField; - - let mut a = Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc, - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837, - ])).unwrap(), - }; - a.frobenius_map(0); - assert_eq!( - a, - Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837 - ])).unwrap(), - } - ); - a.frobenius_map(1); - assert_eq!( - a, - Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x228109103250c9d0, - 0x8a411ad149045812, - 0xa9109e8f3041427e, - 0xb07e9bc405608611, - 0xfcd559cbe77bd8b8, - 0x18d400b280d93e62 - ])).unwrap(), - } - ); - a.frobenius_map(1); - assert_eq!( - a, - Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837 - ])).unwrap(), - } - ); - a.frobenius_map(2); - assert_eq!( - a, - Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x2d0078036923ffc7, - 0x11e59ea221a3b6d2, - 0x8b1a52e0a90f59ed, - 0xb966ce3bc2108b13, - 0xccc649c4b9532bf3, - 0xf8d295b2ded9dc - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0x977df6efcdaee0db, - 0x946ae52d684fa7ed, - 0xbe203411c66fb3a5, - 0xb3f8afc0ee248cad, - 0x4e464dea5bcfd41e, - 0x12d1137b8a6a837 - ])).unwrap(), - } - ); -} - -#[test] -fn test_fq2_sqrt() { - use super::fq::FqRepr; - use ff::PrimeField; - - assert_eq!( - Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x476b4c309720e227, - 0x34c2d04faffdab6, - 0xa57e6fc1bab51fd9, - 0xdb4a116b5bf74aa1, - 0x1e58b2159dfe10e2, - 0x7ca7da1f13606ac - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0xfa8de88b7516d2c3, - 0x371a75ed14f41629, - 0x4cec2dca577a3eb6, - 0x212611bca4e99121, - 0x8ee5394d77afb3d, - 0xec92336650e49d5 - ])).unwrap(), - }.sqrt() - .unwrap(), - Fq2 { - c0: Fq::from_repr(FqRepr([ - 0x40b299b2704258c5, - 0x6ef7de92e8c68b63, - 0x6d2ddbe552203e82, - 0x8d7f1f723d02c1d3, - 0x881b3e01b611c070, - 0x10f6963bbad2ebc5 - ])).unwrap(), - c1: Fq::from_repr(FqRepr([ - 0xc099534fc209e752, - 0x7670594665676447, - 0x28a20faed211efe7, - 0x6b852aeaf2afcb1b, - 0xa4c93b08105d71a9, - 0x8d7cfff94216330 - ])).unwrap(), - } - ); - - assert_eq!( - Fq2 { - c0: Fq::from_repr(FqRepr([ - 0xb9f78429d1517a6b, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a - ])).unwrap(), - c1: Fq::zero(), - }.sqrt() - .unwrap(), - Fq2 { - c0: Fq::zero(), - c1: Fq::from_repr(FqRepr([ - 0xb9fefffffd4357a3, - 0x1eabfffeb153ffff, - 0x6730d2a0f6b0f624, - 0x64774b84f38512bf, - 0x4b1ba7b6434bacd7, - 0x1a0111ea397fe69a - ])).unwrap(), - } - ); -} - -#[test] -fn test_fq2_legendre() { - use ff::LegendreSymbol::*; - - assert_eq!(Zero, Fq2::zero().legendre()); - // i^2 = -1 - let mut m1 = Fq2::one(); - m1.negate(); - assert_eq!(QuadraticResidue, m1.legendre()); - m1.mul_by_nonresidue(); - assert_eq!(QuadraticNonResidue, m1.legendre()); -} - -#[cfg(test)] -use rand::{SeedableRng, XorShiftRng}; - -#[test] -fn test_fq2_mul_nonresidue() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let nqr = Fq2 { - c0: Fq::one(), - c1: Fq::one(), - }; - - for _ in 0..1000 { - let mut a = Fq2::rand(&mut rng); - let mut b = a; - a.mul_by_nonresidue(); - b.mul_assign(&nqr); - - assert_eq!(a, b); - } -} - -#[test] -fn fq2_field_tests() { - use ff::PrimeField; - - ::tests::field::random_field_tests::(); - ::tests::field::random_sqrt_tests::(); - ::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); -} diff --git a/pairing/src/bls12_381/fq6.rs b/pairing/src/bls12_381/fq6.rs deleted file mode 100644 index 36c6e28..0000000 --- a/pairing/src/bls12_381/fq6.rs +++ /dev/null @@ -1,374 +0,0 @@ -use super::fq::{FROBENIUS_COEFF_FQ6_C1, FROBENIUS_COEFF_FQ6_C2}; -use super::fq2::Fq2; -use ff::Field; -use rand::{Rand, Rng}; - -/// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2). -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Fq6 { - pub c0: Fq2, - pub c1: Fq2, - pub c2: Fq2, -} - -impl ::std::fmt::Display for Fq6 { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "Fq6({} + {} * v, {} * v^2)", self.c0, self.c1, self.c2) - } -} - -impl Rand for Fq6 { - fn rand(rng: &mut R) -> Self { - Fq6 { - c0: rng.gen(), - c1: rng.gen(), - c2: rng.gen(), - } - } -} - -impl Fq6 { - /// Multiply by quadratic nonresidue v. - pub fn mul_by_nonresidue(&mut self) { - use std::mem::swap; - swap(&mut self.c0, &mut self.c1); - swap(&mut self.c0, &mut self.c2); - - self.c0.mul_by_nonresidue(); - } - - pub fn mul_by_1(&mut self, c1: &Fq2) { - let mut b_b = self.c1; - b_b.mul_assign(c1); - - let mut t1 = *c1; - { - let mut tmp = self.c1; - tmp.add_assign(&self.c2); - - t1.mul_assign(&tmp); - t1.sub_assign(&b_b); - t1.mul_by_nonresidue(); - } - - let mut t2 = *c1; - { - let mut tmp = self.c0; - tmp.add_assign(&self.c1); - - t2.mul_assign(&tmp); - t2.sub_assign(&b_b); - } - - self.c0 = t1; - self.c1 = t2; - self.c2 = b_b; - } - - pub fn mul_by_01(&mut self, c0: &Fq2, c1: &Fq2) { - let mut a_a = self.c0; - let mut b_b = self.c1; - a_a.mul_assign(c0); - b_b.mul_assign(c1); - - let mut t1 = *c1; - { - let mut tmp = self.c1; - tmp.add_assign(&self.c2); - - t1.mul_assign(&tmp); - t1.sub_assign(&b_b); - t1.mul_by_nonresidue(); - t1.add_assign(&a_a); - } - - let mut t3 = *c0; - { - let mut tmp = self.c0; - tmp.add_assign(&self.c2); - - t3.mul_assign(&tmp); - t3.sub_assign(&a_a); - t3.add_assign(&b_b); - } - - let mut t2 = *c0; - t2.add_assign(c1); - { - let mut tmp = self.c0; - tmp.add_assign(&self.c1); - - t2.mul_assign(&tmp); - t2.sub_assign(&a_a); - t2.sub_assign(&b_b); - } - - self.c0 = t1; - self.c1 = t2; - self.c2 = t3; - } -} - -impl Field for Fq6 { - fn zero() -> Self { - Fq6 { - c0: Fq2::zero(), - c1: Fq2::zero(), - c2: Fq2::zero(), - } - } - - fn one() -> Self { - Fq6 { - c0: Fq2::one(), - c1: Fq2::zero(), - c2: Fq2::zero(), - } - } - - fn is_zero(&self) -> bool { - self.c0.is_zero() && self.c1.is_zero() && self.c2.is_zero() - } - - fn double(&mut self) { - self.c0.double(); - self.c1.double(); - self.c2.double(); - } - - fn negate(&mut self) { - self.c0.negate(); - self.c1.negate(); - self.c2.negate(); - } - - fn add_assign(&mut self, other: &Self) { - self.c0.add_assign(&other.c0); - self.c1.add_assign(&other.c1); - self.c2.add_assign(&other.c2); - } - - fn sub_assign(&mut self, other: &Self) { - self.c0.sub_assign(&other.c0); - self.c1.sub_assign(&other.c1); - self.c2.sub_assign(&other.c2); - } - - fn frobenius_map(&mut self, power: usize) { - self.c0.frobenius_map(power); - self.c1.frobenius_map(power); - self.c2.frobenius_map(power); - - self.c1.mul_assign(&FROBENIUS_COEFF_FQ6_C1[power % 6]); - self.c2.mul_assign(&FROBENIUS_COEFF_FQ6_C2[power % 6]); - } - - fn square(&mut self) { - let mut s0 = self.c0; - s0.square(); - let mut ab = self.c0; - ab.mul_assign(&self.c1); - let mut s1 = ab; - s1.double(); - let mut s2 = self.c0; - s2.sub_assign(&self.c1); - s2.add_assign(&self.c2); - s2.square(); - let mut bc = self.c1; - bc.mul_assign(&self.c2); - let mut s3 = bc; - s3.double(); - let mut s4 = self.c2; - s4.square(); - - self.c0 = s3; - self.c0.mul_by_nonresidue(); - self.c0.add_assign(&s0); - - self.c1 = s4; - self.c1.mul_by_nonresidue(); - self.c1.add_assign(&s1); - - self.c2 = s1; - self.c2.add_assign(&s2); - self.c2.add_assign(&s3); - self.c2.sub_assign(&s0); - self.c2.sub_assign(&s4); - } - - fn mul_assign(&mut self, other: &Self) { - let mut a_a = self.c0; - let mut b_b = self.c1; - let mut c_c = self.c2; - a_a.mul_assign(&other.c0); - b_b.mul_assign(&other.c1); - c_c.mul_assign(&other.c2); - - let mut t1 = other.c1; - t1.add_assign(&other.c2); - { - let mut tmp = self.c1; - tmp.add_assign(&self.c2); - - t1.mul_assign(&tmp); - t1.sub_assign(&b_b); - t1.sub_assign(&c_c); - t1.mul_by_nonresidue(); - t1.add_assign(&a_a); - } - - let mut t3 = other.c0; - t3.add_assign(&other.c2); - { - let mut tmp = self.c0; - tmp.add_assign(&self.c2); - - t3.mul_assign(&tmp); - t3.sub_assign(&a_a); - t3.add_assign(&b_b); - t3.sub_assign(&c_c); - } - - let mut t2 = other.c0; - t2.add_assign(&other.c1); - { - let mut tmp = self.c0; - tmp.add_assign(&self.c1); - - t2.mul_assign(&tmp); - t2.sub_assign(&a_a); - t2.sub_assign(&b_b); - c_c.mul_by_nonresidue(); - t2.add_assign(&c_c); - } - - self.c0 = t1; - self.c1 = t2; - self.c2 = t3; - } - - fn inverse(&self) -> Option { - let mut c0 = self.c2; - c0.mul_by_nonresidue(); - c0.mul_assign(&self.c1); - c0.negate(); - { - let mut c0s = self.c0; - c0s.square(); - c0.add_assign(&c0s); - } - let mut c1 = self.c2; - c1.square(); - c1.mul_by_nonresidue(); - { - let mut c01 = self.c0; - c01.mul_assign(&self.c1); - c1.sub_assign(&c01); - } - let mut c2 = self.c1; - c2.square(); - { - let mut c02 = self.c0; - c02.mul_assign(&self.c2); - c2.sub_assign(&c02); - } - - let mut tmp1 = self.c2; - tmp1.mul_assign(&c1); - let mut tmp2 = self.c1; - tmp2.mul_assign(&c2); - tmp1.add_assign(&tmp2); - tmp1.mul_by_nonresidue(); - tmp2 = self.c0; - tmp2.mul_assign(&c0); - tmp1.add_assign(&tmp2); - - match tmp1.inverse() { - Some(t) => { - let mut tmp = Fq6 { - c0: t, - c1: t, - c2: t, - }; - tmp.c0.mul_assign(&c0); - tmp.c1.mul_assign(&c1); - tmp.c2.mul_assign(&c2); - - Some(tmp) - } - None => None, - } - } -} - -#[cfg(test)] -use rand::{SeedableRng, XorShiftRng}; - -#[test] -fn test_fq6_mul_nonresidue() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let nqr = Fq6 { - c0: Fq2::zero(), - c1: Fq2::one(), - c2: Fq2::zero(), - }; - - for _ in 0..1000 { - let mut a = Fq6::rand(&mut rng); - let mut b = a; - a.mul_by_nonresidue(); - b.mul_assign(&nqr); - - assert_eq!(a, b); - } -} - -#[test] -fn test_fq6_mul_by_1() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let c1 = Fq2::rand(&mut rng); - let mut a = Fq6::rand(&mut rng); - let mut b = a; - - a.mul_by_1(&c1); - b.mul_assign(&Fq6 { - c0: Fq2::zero(), - c1: c1, - c2: Fq2::zero(), - }); - - assert_eq!(a, b); - } -} - -#[test] -fn test_fq6_mul_by_01() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let c0 = Fq2::rand(&mut rng); - let c1 = Fq2::rand(&mut rng); - let mut a = Fq6::rand(&mut rng); - let mut b = a; - - a.mul_by_01(&c0, &c1); - b.mul_assign(&Fq6 { - c0: c0, - c1: c1, - c2: Fq2::zero(), - }); - - assert_eq!(a, b); - } -} - -#[test] -fn fq6_field_tests() { - use ff::PrimeField; - - ::tests::field::random_field_tests::(); - ::tests::field::random_frobenius_tests::(super::fq::Fq::char(), 13); -} diff --git a/pairing/src/bls12_381/fr.rs b/pairing/src/bls12_381/fr.rs deleted file mode 100644 index 5e57631..0000000 --- a/pairing/src/bls12_381/fr.rs +++ /dev/null @@ -1,986 +0,0 @@ -use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr}; - -#[derive(PrimeField)] -#[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"] -#[PrimeFieldGenerator = "7"] -pub struct Fr(FrRepr); - -#[cfg(test)] -use rand::{Rand, SeedableRng, XorShiftRng}; - -#[test] -fn test_fr_repr_ordering() { - fn assert_equality(a: FrRepr, b: FrRepr) { - assert_eq!(a, b); - assert!(a.cmp(&b) == ::std::cmp::Ordering::Equal); - } - - fn assert_lt(a: FrRepr, b: FrRepr) { - assert!(a < b); - assert!(b > a); - } - - assert_equality( - FrRepr([9999, 9999, 9999, 9999]), - FrRepr([9999, 9999, 9999, 9999]), - ); - assert_equality( - FrRepr([9999, 9998, 9999, 9999]), - FrRepr([9999, 9998, 9999, 9999]), - ); - assert_equality( - FrRepr([9999, 9999, 9999, 9997]), - FrRepr([9999, 9999, 9999, 9997]), - ); - assert_lt( - FrRepr([9999, 9997, 9999, 9998]), - FrRepr([9999, 9997, 9999, 9999]), - ); - assert_lt( - FrRepr([9999, 9997, 9998, 9999]), - FrRepr([9999, 9997, 9999, 9999]), - ); - assert_lt( - FrRepr([9, 9999, 9999, 9997]), - FrRepr([9999, 9999, 9999, 9997]), - ); -} - -#[test] -fn test_fr_repr_from() { - assert_eq!(FrRepr::from(100), FrRepr([100, 0, 0, 0])); -} - -#[test] -fn test_fr_repr_is_odd() { - assert!(!FrRepr::from(0).is_odd()); - assert!(FrRepr::from(0).is_even()); - assert!(FrRepr::from(1).is_odd()); - assert!(!FrRepr::from(1).is_even()); - assert!(!FrRepr::from(324834872).is_odd()); - assert!(FrRepr::from(324834872).is_even()); - assert!(FrRepr::from(324834873).is_odd()); - assert!(!FrRepr::from(324834873).is_even()); -} - -#[test] -fn test_fr_repr_is_zero() { - assert!(FrRepr::from(0).is_zero()); - assert!(!FrRepr::from(1).is_zero()); - assert!(!FrRepr([0, 0, 1, 0]).is_zero()); -} - -#[test] -fn test_fr_repr_div2() { - let mut a = FrRepr([ - 0xbd2920b19c972321, - 0x174ed0466a3be37e, - 0xd468d5e3b551f0b5, - 0xcb67c072733beefc, - ]); - a.div2(); - assert_eq!( - a, - FrRepr([ - 0x5e949058ce4b9190, - 0x8ba76823351df1bf, - 0x6a346af1daa8f85a, - 0x65b3e039399df77e - ]) - ); - for _ in 0..10 { - a.div2(); - } - assert_eq!( - a, - FrRepr([ - 0x6fd7a524163392e4, - 0x16a2e9da08cd477c, - 0xdf9a8d1abc76aa3e, - 0x196cf80e4e677d - ]) - ); - for _ in 0..200 { - a.div2(); - } - assert_eq!(a, FrRepr([0x196cf80e4e67, 0x0, 0x0, 0x0])); - for _ in 0..40 { - a.div2(); - } - assert_eq!(a, FrRepr([0x19, 0x0, 0x0, 0x0])); - for _ in 0..4 { - a.div2(); - } - assert_eq!(a, FrRepr([0x1, 0x0, 0x0, 0x0])); - a.div2(); - assert!(a.is_zero()); -} - -#[test] -fn test_fr_repr_shr() { - let mut a = FrRepr([ - 0xb33fbaec482a283f, - 0x997de0d3a88cb3df, - 0x9af62d2a9a0e5525, - 0x36003ab08de70da1, - ]); - a.shr(0); - assert_eq!( - a, - FrRepr([ - 0xb33fbaec482a283f, - 0x997de0d3a88cb3df, - 0x9af62d2a9a0e5525, - 0x36003ab08de70da1 - ]) - ); - a.shr(1); - assert_eq!( - a, - FrRepr([ - 0xd99fdd762415141f, - 0xccbef069d44659ef, - 0xcd7b16954d072a92, - 0x1b001d5846f386d0 - ]) - ); - a.shr(50); - assert_eq!( - a, - FrRepr([ - 0xbc1a7511967bf667, - 0xc5a55341caa4b32f, - 0x75611bce1b4335e, - 0x6c0 - ]) - ); - a.shr(130); - assert_eq!(a, FrRepr([0x1d5846f386d0cd7, 0x1b0, 0x0, 0x0])); - a.shr(64); - assert_eq!(a, FrRepr([0x1b0, 0x0, 0x0, 0x0])); -} - -#[test] -fn test_fr_repr_mul2() { - let mut a = FrRepr::from(23712937547); - a.mul2(); - assert_eq!(a, FrRepr([0xb0acd6c96, 0x0, 0x0, 0x0])); - for _ in 0..60 { - a.mul2(); - } - assert_eq!(a, FrRepr([0x6000000000000000, 0xb0acd6c9, 0x0, 0x0])); - for _ in 0..128 { - a.mul2(); - } - assert_eq!(a, FrRepr([0x0, 0x0, 0x6000000000000000, 0xb0acd6c9])); - for _ in 0..60 { - a.mul2(); - } - assert_eq!(a, FrRepr([0x0, 0x0, 0x0, 0x9600000000000000])); - for _ in 0..7 { - a.mul2(); - } - assert!(a.is_zero()); -} - -#[test] -fn test_fr_repr_num_bits() { - let mut a = FrRepr::from(0); - assert_eq!(0, a.num_bits()); - a = FrRepr::from(1); - for i in 1..257 { - assert_eq!(i, a.num_bits()); - a.mul2(); - } - assert_eq!(0, a.num_bits()); -} - -#[test] -fn test_fr_repr_sub_noborrow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let mut t = FrRepr([ - 0x8e62a7e85264e2c3, - 0xb23d34c1941d3ca, - 0x5976930b7502dd15, - 0x600f3fb517bf5495, - ]); - t.sub_noborrow(&FrRepr([ - 0xd64f669809cbc6a4, - 0xfa76cb9d90cf7637, - 0xfefb0df9038d43b3, - 0x298a30c744b31acf, - ])); - assert!( - t == FrRepr([ - 0xb813415048991c1f, - 0x10ad07ae88725d92, - 0x5a7b851271759961, - 0x36850eedd30c39c5 - ]) - ); - - for _ in 0..1000 { - let mut a = FrRepr::rand(&mut rng); - a.0[3] >>= 30; - let mut b = a; - for _ in 0..10 { - b.mul2(); - } - let mut c = b; - for _ in 0..10 { - c.mul2(); - } - - assert!(a < b); - assert!(b < c); - - let mut csub_ba = c; - csub_ba.sub_noborrow(&b); - csub_ba.sub_noborrow(&a); - - let mut csub_ab = c; - csub_ab.sub_noborrow(&a); - csub_ab.sub_noborrow(&b); - - assert_eq!(csub_ab, csub_ba); - } - - // Subtracting r+1 from r should produce -1 (mod 2**256) - let mut qplusone = FrRepr([ - 0xffffffff00000001, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48, - ]); - qplusone.sub_noborrow(&FrRepr([ - 0xffffffff00000002, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48, - ])); - assert_eq!( - qplusone, - FrRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff - ]) - ); -} - -#[test] -fn test_fr_legendre() { - use ff::LegendreSymbol::*; - use ff::SqrtField; - - assert_eq!(QuadraticResidue, Fr::one().legendre()); - assert_eq!(Zero, Fr::zero().legendre()); - - let e = FrRepr([ - 0x0dbc5349cd5664da, - 0x8ac5b6296e3ae29d, - 0x127cb819feceaa3b, - 0x3a6b21fb03867191, - ]); - assert_eq!(QuadraticResidue, Fr::from_repr(e).unwrap().legendre()); - let e = FrRepr([ - 0x96341aefd047c045, - 0x9b5f4254500a4d65, - 0x1ee08223b68ac240, - 0x31d9cd545c0ec7c6, - ]); - assert_eq!(QuadraticNonResidue, Fr::from_repr(e).unwrap().legendre()); -} - -#[test] -fn test_fr_repr_add_nocarry() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let mut t = FrRepr([ - 0xd64f669809cbc6a4, - 0xfa76cb9d90cf7637, - 0xfefb0df9038d43b3, - 0x298a30c744b31acf, - ]); - t.add_nocarry(&FrRepr([ - 0x8e62a7e85264e2c3, - 0xb23d34c1941d3ca, - 0x5976930b7502dd15, - 0x600f3fb517bf5495, - ])); - assert_eq!( - t, - FrRepr([ - 0x64b20e805c30a967, - 0x59a9ee9aa114a02, - 0x5871a104789020c9, - 0x8999707c5c726f65 - ]) - ); - - // Test for the associativity of addition. - for _ in 0..1000 { - let mut a = FrRepr::rand(&mut rng); - let mut b = FrRepr::rand(&mut rng); - let mut c = FrRepr::rand(&mut rng); - - // Unset the first few bits, so that overflow won't occur. - a.0[3] >>= 3; - b.0[3] >>= 3; - c.0[3] >>= 3; - - let mut abc = a; - abc.add_nocarry(&b); - abc.add_nocarry(&c); - - let mut acb = a; - acb.add_nocarry(&c); - acb.add_nocarry(&b); - - let mut bac = b; - bac.add_nocarry(&a); - bac.add_nocarry(&c); - - let mut bca = b; - bca.add_nocarry(&c); - bca.add_nocarry(&a); - - let mut cab = c; - cab.add_nocarry(&a); - cab.add_nocarry(&b); - - let mut cba = c; - cba.add_nocarry(&b); - cba.add_nocarry(&a); - - assert_eq!(abc, acb); - assert_eq!(abc, bac); - assert_eq!(abc, bca); - assert_eq!(abc, cab); - assert_eq!(abc, cba); - } - - // Adding 1 to (2^256 - 1) should produce zero - let mut x = FrRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - ]); - x.add_nocarry(&FrRepr::from(1)); - assert!(x.is_zero()); -} - -#[test] -fn test_fr_is_valid() { - let mut a = Fr(MODULUS); - assert!(!a.is_valid()); - a.0.sub_noborrow(&FrRepr::from(1)); - assert!(a.is_valid()); - assert!(Fr(FrRepr::from(0)).is_valid()); - assert!( - Fr(FrRepr([ - 0xffffffff00000000, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48 - ])).is_valid() - ); - assert!( - !Fr(FrRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff - ])).is_valid() - ); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let a = Fr::rand(&mut rng); - assert!(a.is_valid()); - } -} - -#[test] -fn test_fr_add_assign() { - { - // Random number - let mut tmp = Fr(FrRepr([ - 0x437ce7616d580765, - 0xd42d1ccb29d1235b, - 0xed8f753821bd1423, - 0x4eede1c9c89528ca, - ])); - assert!(tmp.is_valid()); - // Test that adding zero has no effect. - tmp.add_assign(&Fr(FrRepr::from(0))); - assert_eq!( - tmp, - Fr(FrRepr([ - 0x437ce7616d580765, - 0xd42d1ccb29d1235b, - 0xed8f753821bd1423, - 0x4eede1c9c89528ca - ])) - ); - // Add one and test for the result. - tmp.add_assign(&Fr(FrRepr::from(1))); - assert_eq!( - tmp, - Fr(FrRepr([ - 0x437ce7616d580766, - 0xd42d1ccb29d1235b, - 0xed8f753821bd1423, - 0x4eede1c9c89528ca - ])) - ); - // Add another random number that exercises the reduction. - tmp.add_assign(&Fr(FrRepr([ - 0x946f435944f7dc79, - 0xb55e7ee6533a9b9b, - 0x1e43b84c2f6194ca, - 0x58717ab525463496, - ]))); - assert_eq!( - tmp, - Fr(FrRepr([ - 0xd7ec2abbb24fe3de, - 0x35cdf7ae7d0d62f7, - 0xd899557c477cd0e9, - 0x3371b52bc43de018 - ])) - ); - // Add one to (r - 1) and test for the result. - tmp = Fr(FrRepr([ - 0xffffffff00000000, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48, - ])); - tmp.add_assign(&Fr(FrRepr::from(1))); - assert!(tmp.0.is_zero()); - // Add a random number to another one such that the result is r - 1 - tmp = Fr(FrRepr([ - 0xade5adacdccb6190, - 0xaa21ee0f27db3ccd, - 0x2550f4704ae39086, - 0x591d1902e7c5ba27, - ])); - tmp.add_assign(&Fr(FrRepr([ - 0x521a525223349e70, - 0xa99bb5f3d8231f31, - 0xde8e397bebe477e, - 0x1ad08e5041d7c321, - ]))); - assert_eq!( - tmp, - Fr(FrRepr([ - 0xffffffff00000000, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48 - ])) - ); - // Add one to the result and test for it. - tmp.add_assign(&Fr(FrRepr::from(1))); - assert!(tmp.0.is_zero()); - } - - // Test associativity - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Generate a, b, c and ensure (a + b) + c == a + (b + c). - let a = Fr::rand(&mut rng); - let b = Fr::rand(&mut rng); - let c = Fr::rand(&mut rng); - - let mut tmp1 = a; - tmp1.add_assign(&b); - tmp1.add_assign(&c); - - let mut tmp2 = b; - tmp2.add_assign(&c); - tmp2.add_assign(&a); - - assert!(tmp1.is_valid()); - assert!(tmp2.is_valid()); - assert_eq!(tmp1, tmp2); - } -} - -#[test] -fn test_fr_sub_assign() { - { - // Test arbitrary subtraction that tests reduction. - let mut tmp = Fr(FrRepr([ - 0x6a68c64b6f735a2b, - 0xd5f4d143fe0a1972, - 0x37c17f3829267c62, - 0xa2f37391f30915c, - ])); - tmp.sub_assign(&Fr(FrRepr([ - 0xade5adacdccb6190, - 0xaa21ee0f27db3ccd, - 0x2550f4704ae39086, - 0x591d1902e7c5ba27, - ]))); - assert_eq!( - tmp, - Fr(FrRepr([ - 0xbc83189d92a7f89c, - 0x7f908737d62d38a3, - 0x45aa62cfe7e4c3e1, - 0x24ffc5896108547d - ])) - ); - - // Test the opposite subtraction which doesn't test reduction. - tmp = Fr(FrRepr([ - 0xade5adacdccb6190, - 0xaa21ee0f27db3ccd, - 0x2550f4704ae39086, - 0x591d1902e7c5ba27, - ])); - tmp.sub_assign(&Fr(FrRepr([ - 0x6a68c64b6f735a2b, - 0xd5f4d143fe0a1972, - 0x37c17f3829267c62, - 0xa2f37391f30915c, - ]))); - assert_eq!( - tmp, - Fr(FrRepr([ - 0x437ce7616d580765, - 0xd42d1ccb29d1235b, - 0xed8f753821bd1423, - 0x4eede1c9c89528ca - ])) - ); - - // Test for sensible results with zero - tmp = Fr(FrRepr::from(0)); - tmp.sub_assign(&Fr(FrRepr::from(0))); - assert!(tmp.is_zero()); - - tmp = Fr(FrRepr([ - 0x437ce7616d580765, - 0xd42d1ccb29d1235b, - 0xed8f753821bd1423, - 0x4eede1c9c89528ca, - ])); - tmp.sub_assign(&Fr(FrRepr::from(0))); - assert_eq!( - tmp, - Fr(FrRepr([ - 0x437ce7616d580765, - 0xd42d1ccb29d1235b, - 0xed8f753821bd1423, - 0x4eede1c9c89528ca - ])) - ); - } - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Ensure that (a - b) + (b - a) = 0. - let a = Fr::rand(&mut rng); - let b = Fr::rand(&mut rng); - - let mut tmp1 = a; - tmp1.sub_assign(&b); - - let mut tmp2 = b; - tmp2.sub_assign(&a); - - tmp1.add_assign(&tmp2); - assert!(tmp1.is_zero()); - } -} - -#[test] -fn test_fr_mul_assign() { - let mut tmp = Fr(FrRepr([ - 0x6b7e9b8faeefc81a, - 0xe30a8463f348ba42, - 0xeff3cb67a8279c9c, - 0x3d303651bd7c774d, - ])); - tmp.mul_assign(&Fr(FrRepr([ - 0x13ae28e3bc35ebeb, - 0xa10f4488075cae2c, - 0x8160e95a853c3b5d, - 0x5ae3f03b561a841d, - ]))); - assert!( - tmp == Fr(FrRepr([ - 0x23717213ce710f71, - 0xdbee1fe53a16e1af, - 0xf565d3e1c2a48000, - 0x4426507ee75df9d7 - ])) - ); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000000 { - // Ensure that (a * b) * c = a * (b * c) - let a = Fr::rand(&mut rng); - let b = Fr::rand(&mut rng); - let c = Fr::rand(&mut rng); - - let mut tmp1 = a; - tmp1.mul_assign(&b); - tmp1.mul_assign(&c); - - let mut tmp2 = b; - tmp2.mul_assign(&c); - tmp2.mul_assign(&a); - - assert_eq!(tmp1, tmp2); - } - - for _ in 0..1000000 { - // Ensure that r * (a + b + c) = r*a + r*b + r*c - - let r = Fr::rand(&mut rng); - let mut a = Fr::rand(&mut rng); - let mut b = Fr::rand(&mut rng); - let mut c = Fr::rand(&mut rng); - - let mut tmp1 = a; - tmp1.add_assign(&b); - tmp1.add_assign(&c); - tmp1.mul_assign(&r); - - a.mul_assign(&r); - b.mul_assign(&r); - c.mul_assign(&r); - - a.add_assign(&b); - a.add_assign(&c); - - assert_eq!(tmp1, a); - } -} - -#[test] -fn test_fr_squaring() { - let mut a = Fr(FrRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0x73eda753299d7d47, - ])); - assert!(a.is_valid()); - a.square(); - assert_eq!( - a, - Fr::from_repr(FrRepr([ - 0xc0d698e7bde077b8, - 0xb79a310579e76ec2, - 0xac1da8d0a9af4e5f, - 0x13f629c49bf23e97 - ])).unwrap() - ); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000000 { - // Ensure that (a * a) = a^2 - let a = Fr::rand(&mut rng); - - let mut tmp = a; - tmp.square(); - - let mut tmp2 = a; - tmp2.mul_assign(&a); - - assert_eq!(tmp, tmp2); - } -} - -#[test] -fn test_fr_inverse() { - assert!(Fr::zero().inverse().is_none()); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let one = Fr::one(); - - for _ in 0..1000 { - // Ensure that a * a^-1 = 1 - let mut a = Fr::rand(&mut rng); - let ainv = a.inverse().unwrap(); - a.mul_assign(&ainv); - assert_eq!(a, one); - } -} - -#[test] -fn test_fr_double() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Ensure doubling a is equivalent to adding a to itself. - let mut a = Fr::rand(&mut rng); - let mut b = a; - b.add_assign(&a); - a.double(); - assert_eq!(a, b); - } -} - -#[test] -fn test_fr_negate() { - { - let mut a = Fr::zero(); - a.negate(); - - assert!(a.is_zero()); - } - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Ensure (a - (-a)) = 0. - let mut a = Fr::rand(&mut rng); - let mut b = a; - b.negate(); - a.add_assign(&b); - - assert!(a.is_zero()); - } -} - -#[test] -fn test_fr_pow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for i in 0..1000 { - // Exponentiate by various small numbers and ensure it consists with repeated - // multiplication. - let a = Fr::rand(&mut rng); - let target = a.pow(&[i]); - let mut c = Fr::one(); - for _ in 0..i { - c.mul_assign(&a); - } - assert_eq!(c, target); - } - - for _ in 0..1000 { - // Exponentiating by the modulus should have no effect in a prime field. - let a = Fr::rand(&mut rng); - - assert_eq!(a, a.pow(Fr::char())); - } -} - -#[test] -fn test_fr_sqrt() { - use ff::SqrtField; - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - assert_eq!(Fr::zero().sqrt().unwrap(), Fr::zero()); - - for _ in 0..1000 { - // Ensure sqrt(a^2) = a or -a - let a = Fr::rand(&mut rng); - let mut nega = a; - nega.negate(); - let mut b = a; - b.square(); - - let b = b.sqrt().unwrap(); - - assert!(a == b || nega == b); - } - - for _ in 0..1000 { - // Ensure sqrt(a)^2 = a for random a - let a = Fr::rand(&mut rng); - - if let Some(mut tmp) = a.sqrt() { - tmp.square(); - - assert_eq!(a, tmp); - } - } -} - -#[test] -fn test_fr_from_into_repr() { - // r + 1 should not be in the field - assert!( - Fr::from_repr(FrRepr([ - 0xffffffff00000002, - 0x53bda402fffe5bfe, - 0x3339d80809a1d805, - 0x73eda753299d7d48 - ])).is_err() - ); - - // r should not be in the field - assert!(Fr::from_repr(Fr::char()).is_err()); - - // Multiply some arbitrary representations to see if the result is as expected. - let a = FrRepr([ - 0x25ebe3a3ad3c0c6a, - 0x6990e39d092e817c, - 0x941f900d42f5658e, - 0x44f8a103b38a71e0, - ]); - let mut a_fr = Fr::from_repr(a).unwrap(); - let b = FrRepr([ - 0x264e9454885e2475, - 0x46f7746bb0308370, - 0x4683ef5347411f9, - 0x58838d7f208d4492, - ]); - let b_fr = Fr::from_repr(b).unwrap(); - let c = FrRepr([ - 0x48a09ab93cfc740d, - 0x3a6600fbfc7a671, - 0x838567017501d767, - 0x7161d6da77745512, - ]); - a_fr.mul_assign(&b_fr); - assert_eq!(a_fr.into_repr(), c); - - // Zero should be in the field. - assert!(Fr::from_repr(FrRepr::from(0)).unwrap().is_zero()); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Try to turn Fr elements into representations and back again, and compare. - let a = Fr::rand(&mut rng); - let a_repr = a.into_repr(); - let b_repr = FrRepr::from(a); - assert_eq!(a_repr, b_repr); - let a_again = Fr::from_repr(a_repr).unwrap(); - - assert_eq!(a, a_again); - } -} - -#[test] -fn test_fr_repr_display() { - assert_eq!( - format!( - "{}", - FrRepr([ - 0x2829c242fa826143, - 0x1f32cf4dd4330917, - 0x932e4e479d168cd9, - 0x513c77587f563f64 - ]) - ), - "0x513c77587f563f64932e4e479d168cd91f32cf4dd43309172829c242fa826143".to_string() - ); - assert_eq!( - format!( - "{}", - FrRepr([ - 0x25ebe3a3ad3c0c6a, - 0x6990e39d092e817c, - 0x941f900d42f5658e, - 0x44f8a103b38a71e0 - ]) - ), - "0x44f8a103b38a71e0941f900d42f5658e6990e39d092e817c25ebe3a3ad3c0c6a".to_string() - ); - assert_eq!( - format!( - "{}", - FrRepr([ - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff, - 0xffffffffffffffff - ]) - ), - "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string() - ); - assert_eq!( - format!("{}", FrRepr([0, 0, 0, 0])), - "0x0000000000000000000000000000000000000000000000000000000000000000".to_string() - ); -} - -#[test] -fn test_fr_display() { - assert_eq!( - format!( - "{}", - Fr::from_repr(FrRepr([ - 0xc3cae746a3b5ecc7, - 0x185ec8eb3f5b5aee, - 0x684499ffe4b9dd99, - 0x7c9bba7afb68faa - ])).unwrap() - ), - "Fr(0x07c9bba7afb68faa684499ffe4b9dd99185ec8eb3f5b5aeec3cae746a3b5ecc7)".to_string() - ); - assert_eq!( - format!( - "{}", - Fr::from_repr(FrRepr([ - 0x44c71298ff198106, - 0xb0ad10817df79b6a, - 0xd034a80a2b74132b, - 0x41cf9a1336f50719 - ])).unwrap() - ), - "Fr(0x41cf9a1336f50719d034a80a2b74132bb0ad10817df79b6a44c71298ff198106)".to_string() - ); -} - -#[test] -fn test_fr_num_bits() { - assert_eq!(Fr::NUM_BITS, 255); - assert_eq!(Fr::CAPACITY, 254); -} - -#[test] -fn test_fr_root_of_unity() { - use ff::SqrtField; - - assert_eq!(Fr::S, 32); - assert_eq!( - Fr::multiplicative_generator(), - Fr::from_repr(FrRepr::from(7)).unwrap() - ); - assert_eq!( - Fr::multiplicative_generator().pow([ - 0xfffe5bfeffffffff, - 0x9a1d80553bda402, - 0x299d7d483339d808, - 0x73eda753 - ]), - Fr::root_of_unity() - ); - assert_eq!(Fr::root_of_unity().pow([1 << Fr::S]), Fr::one()); - assert!(Fr::multiplicative_generator().sqrt().is_none()); -} - -#[test] -fn fr_field_tests() { - ::tests::field::random_field_tests::(); - ::tests::field::random_sqrt_tests::(); - ::tests::field::random_frobenius_tests::(Fr::char(), 13); - ::tests::field::from_str_tests::(); -} - -#[test] -fn fr_repr_tests() { - ::tests::repr::random_repr_tests::(); -} diff --git a/pairing/src/bls12_381/mod.rs b/pairing/src/bls12_381/mod.rs deleted file mode 100644 index 7bc03c6..0000000 --- a/pairing/src/bls12_381/mod.rs +++ /dev/null @@ -1,370 +0,0 @@ -mod ec; -mod fq; -mod fq12; -mod fq2; -mod fq6; -mod fr; - -#[cfg(test)] -mod tests; - -pub use self::ec::{ - G1, G1Affine, G1Compressed, G1Prepared, G1Uncompressed, G2, G2Affine, G2Compressed, G2Prepared, - G2Uncompressed, -}; -pub use self::fq::{Fq, FqRepr}; -pub use self::fq12::Fq12; -pub use self::fq2::Fq2; -pub use self::fq6::Fq6; -pub use self::fr::{Fr, FrRepr}; - -use super::{Engine, PairingCurveAffine}; - -use ff::{BitIterator, Field, ScalarEngine}; -use group::CurveAffine; - -// The BLS parameter x for BLS12-381 is -0xd201000000010000 -const BLS_X: u64 = 0xd201000000010000; -const BLS_X_IS_NEGATIVE: bool = true; - -#[derive(Clone, Debug)] -pub struct Bls12; - -impl ScalarEngine for Bls12 { - type Fr = Fr; -} - -impl Engine for Bls12 { - type G1 = G1; - type G1Affine = G1Affine; - type G2 = G2; - type G2Affine = G2Affine; - type Fq = Fq; - type Fqe = Fq2; - type Fqk = Fq12; - - fn miller_loop<'a, I>(i: I) -> Self::Fqk - where - I: IntoIterator< - Item = &'a ( - &'a ::Prepared, - &'a ::Prepared, - ), - >, - { - let mut pairs = vec![]; - for &(p, q) in i { - if !p.is_zero() && !q.is_zero() { - pairs.push((p, q.coeffs.iter())); - } - } - - // Twisting isomorphism from E to E' - fn ell(f: &mut Fq12, coeffs: &(Fq2, Fq2, Fq2), p: &G1Affine) { - let mut c0 = coeffs.0; - let mut c1 = coeffs.1; - - c0.c0.mul_assign(&p.y); - c0.c1.mul_assign(&p.y); - - c1.c0.mul_assign(&p.x); - c1.c1.mul_assign(&p.x); - - // Sparse multiplication in Fq12 - f.mul_by_014(&coeffs.2, &c1, &c0); - } - - let mut f = Fq12::one(); - - let mut found_one = false; - for i in BitIterator::new(&[BLS_X >> 1]) { - if !found_one { - found_one = i; - continue; - } - - for &mut (p, ref mut coeffs) in &mut pairs { - ell(&mut f, coeffs.next().unwrap(), &p.0); - } - - if i { - for &mut (p, ref mut coeffs) in &mut pairs { - ell(&mut f, coeffs.next().unwrap(), &p.0); - } - } - - f.square(); - } - - for &mut (p, ref mut coeffs) in &mut pairs { - ell(&mut f, coeffs.next().unwrap(), &p.0); - } - - if BLS_X_IS_NEGATIVE { - f.conjugate(); - } - - f - } - - fn final_exponentiation(r: &Fq12) -> Option { - let mut f1 = *r; - f1.conjugate(); - - match r.inverse() { - Some(mut f2) => { - let mut r = f1; - r.mul_assign(&f2); - f2 = r; - r.frobenius_map(2); - r.mul_assign(&f2); - - fn exp_by_x(f: &mut Fq12, x: u64) { - *f = f.pow(&[x]); - if BLS_X_IS_NEGATIVE { - f.conjugate(); - } - } - - let mut x = BLS_X; - let mut y0 = r; - y0.square(); - let mut y1 = y0; - exp_by_x(&mut y1, x); - x >>= 1; - let mut y2 = y1; - exp_by_x(&mut y2, x); - x <<= 1; - let mut y3 = r; - y3.conjugate(); - y1.mul_assign(&y3); - y1.conjugate(); - y1.mul_assign(&y2); - y2 = y1; - exp_by_x(&mut y2, x); - y3 = y2; - exp_by_x(&mut y3, x); - y1.conjugate(); - y3.mul_assign(&y1); - y1.conjugate(); - y1.frobenius_map(3); - y2.frobenius_map(2); - y1.mul_assign(&y2); - y2 = y3; - exp_by_x(&mut y2, x); - y2.mul_assign(&y0); - y2.mul_assign(&r); - y1.mul_assign(&y2); - y2 = y3; - y2.frobenius_map(1); - y1.mul_assign(&y2); - - Some(y1) - } - None => None, - } - } -} - -impl G2Prepared { - pub fn is_zero(&self) -> bool { - self.infinity - } - - pub fn from_affine(q: G2Affine) -> Self { - if q.is_zero() { - return G2Prepared { - coeffs: vec![], - infinity: true, - }; - } - - fn doubling_step(r: &mut G2) -> (Fq2, Fq2, Fq2) { - // Adaptation of Algorithm 26, https://eprint.iacr.org/2010/354.pdf - let mut tmp0 = r.x; - tmp0.square(); - - let mut tmp1 = r.y; - tmp1.square(); - - let mut tmp2 = tmp1; - tmp2.square(); - - let mut tmp3 = tmp1; - tmp3.add_assign(&r.x); - tmp3.square(); - tmp3.sub_assign(&tmp0); - tmp3.sub_assign(&tmp2); - tmp3.double(); - - let mut tmp4 = tmp0; - tmp4.double(); - tmp4.add_assign(&tmp0); - - let mut tmp6 = r.x; - tmp6.add_assign(&tmp4); - - let mut tmp5 = tmp4; - tmp5.square(); - - let mut zsquared = r.z; - zsquared.square(); - - r.x = tmp5; - r.x.sub_assign(&tmp3); - r.x.sub_assign(&tmp3); - - r.z.add_assign(&r.y); - r.z.square(); - r.z.sub_assign(&tmp1); - r.z.sub_assign(&zsquared); - - r.y = tmp3; - r.y.sub_assign(&r.x); - r.y.mul_assign(&tmp4); - - tmp2.double(); - tmp2.double(); - tmp2.double(); - - r.y.sub_assign(&tmp2); - - tmp3 = tmp4; - tmp3.mul_assign(&zsquared); - tmp3.double(); - tmp3.negate(); - - tmp6.square(); - tmp6.sub_assign(&tmp0); - tmp6.sub_assign(&tmp5); - - tmp1.double(); - tmp1.double(); - - tmp6.sub_assign(&tmp1); - - tmp0 = r.z; - tmp0.mul_assign(&zsquared); - tmp0.double(); - - (tmp0, tmp3, tmp6) - } - - fn addition_step(r: &mut G2, q: &G2Affine) -> (Fq2, Fq2, Fq2) { - // Adaptation of Algorithm 27, https://eprint.iacr.org/2010/354.pdf - let mut zsquared = r.z; - zsquared.square(); - - let mut ysquared = q.y; - ysquared.square(); - - let mut t0 = zsquared; - t0.mul_assign(&q.x); - - let mut t1 = q.y; - t1.add_assign(&r.z); - t1.square(); - t1.sub_assign(&ysquared); - t1.sub_assign(&zsquared); - t1.mul_assign(&zsquared); - - let mut t2 = t0; - t2.sub_assign(&r.x); - - let mut t3 = t2; - t3.square(); - - let mut t4 = t3; - t4.double(); - t4.double(); - - let mut t5 = t4; - t5.mul_assign(&t2); - - let mut t6 = t1; - t6.sub_assign(&r.y); - t6.sub_assign(&r.y); - - let mut t9 = t6; - t9.mul_assign(&q.x); - - let mut t7 = t4; - t7.mul_assign(&r.x); - - r.x = t6; - r.x.square(); - r.x.sub_assign(&t5); - r.x.sub_assign(&t7); - r.x.sub_assign(&t7); - - r.z.add_assign(&t2); - r.z.square(); - r.z.sub_assign(&zsquared); - r.z.sub_assign(&t3); - - let mut t10 = q.y; - t10.add_assign(&r.z); - - let mut t8 = t7; - t8.sub_assign(&r.x); - t8.mul_assign(&t6); - - t0 = r.y; - t0.mul_assign(&t5); - t0.double(); - - r.y = t8; - r.y.sub_assign(&t0); - - t10.square(); - t10.sub_assign(&ysquared); - - let mut ztsquared = r.z; - ztsquared.square(); - - t10.sub_assign(&ztsquared); - - t9.double(); - t9.sub_assign(&t10); - - t10 = r.z; - t10.double(); - - t6.negate(); - - t1 = t6; - t1.double(); - - (t10, t1, t9) - } - - let mut coeffs = vec![]; - let mut r: G2 = q.into(); - - let mut found_one = false; - for i in BitIterator::new([BLS_X >> 1]) { - if !found_one { - found_one = i; - continue; - } - - coeffs.push(doubling_step(&mut r)); - - if i { - coeffs.push(addition_step(&mut r, &q)); - } - } - - coeffs.push(doubling_step(&mut r)); - - G2Prepared { - coeffs, - infinity: false, - } - } -} - -#[test] -fn bls12_engine_tests() { - ::tests::engine::engine_tests::(); -} diff --git a/pairing/src/bls12_381/tests/g1_compressed_valid_test_vectors.dat b/pairing/src/bls12_381/tests/g1_compressed_valid_test_vectors.dat deleted file mode 100644 index ea8cd67652d133010e79df8488452450b6f5cb17..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48000 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 Rm?nepfGSPSF*XppvfIk?3d#Tg diff --git a/pairing/src/bls12_381/tests/g1_uncompressed_invalid_test_vectors.dat b/pairing/src/bls12_381/tests/g1_uncompressed_invalid_test_vectors.dat deleted file mode 100644 index e69de29..0000000 diff --git a/pairing/src/bls12_381/tests/g1_uncompressed_valid_test_vectors.dat b/pairing/src/bls12_381/tests/g1_uncompressed_valid_test_vectors.dat deleted file mode 100644 index 86abfba945c7b701750d637bffe6701330e10e88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 96000 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%0A9l>2- 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 diff --git a/pairing/src/bls12_381/tests/g2_compressed_valid_test_vectors.dat b/pairing/src/bls12_381/tests/g2_compressed_valid_test_vectors.dat deleted file mode 100644 index a40bbe251d90e576060adb7eaa2456197878804c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 96000 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 diff --git a/pairing/src/bls12_381/tests/g2_uncompressed_valid_test_vectors.dat b/pairing/src/bls12_381/tests/g2_uncompressed_valid_test_vectors.dat deleted file mode 100644 index 92e4bc528e8937a311b502e4940e5e363a1f7c57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 192000 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�uc*gWwz@d=S2~bA~LrFNXzUL(>hGG#V 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%0DJH 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�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 zy6->(expected: &[u8]) { - let mut e = G::zero(); - - let mut v = vec![]; - { - let mut expected = expected; - for _ in 0..1000 { - let e_affine = e.into_affine(); - let encoded = E::from_affine(e_affine); - v.extend_from_slice(encoded.as_ref()); - - let mut decoded = E::empty(); - decoded.as_mut().copy_from_slice(&expected[0..E::size()]); - expected = &expected[E::size()..]; - let decoded = decoded.into_affine().unwrap(); - assert_eq!(e_affine, decoded); - - e.add_assign(&G::one()); - } - } - - assert_eq!(&v[..], expected); -} - -#[test] -fn test_g1_uncompressed_valid_vectors() { - test_vectors::(include_bytes!("g1_uncompressed_valid_test_vectors.dat")); -} - -#[test] -fn test_g1_compressed_valid_vectors() { - test_vectors::(include_bytes!("g1_compressed_valid_test_vectors.dat")); -} - -#[test] -fn test_g2_uncompressed_valid_vectors() { - test_vectors::(include_bytes!("g2_uncompressed_valid_test_vectors.dat")); -} - -#[test] -fn test_g2_compressed_valid_vectors() { - test_vectors::(include_bytes!("g2_compressed_valid_test_vectors.dat")); -} - -#[test] -fn test_g1_uncompressed_invalid_vectors() { - { - let z = G1Affine::zero().into_uncompressed(); - - { - let mut z = z; - z.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() { - // :) - } else { - panic!("should have rejected the point because we expected an uncompressed point"); - } - } - - { - let mut z = z; - z.as_mut()[0] |= 0b0010_0000; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { - // :) - } else { - panic!("should have rejected the point because the parity bit should not be set if the point is at infinity"); - } - } - - for i in 0..G1Uncompressed::size() { - let mut z = z; - z.as_mut()[i] |= 0b0000_0001; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { - // :) - } else { - panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity"); - } - } - } - - let o = G1Affine::one().into_uncompressed(); - - { - let mut o = o; - o.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() { - // :) - } else { - panic!("should have rejected the point because we expected an uncompressed point"); - } - } - - let m = Fq::char(); - - { - let mut o = o; - m.write_be(&mut o.as_mut()[0..]).unwrap(); - - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { - assert_eq!(coordinate, "x coordinate"); - } else { - panic!("should have rejected the point") - } - } - - { - let mut o = o; - m.write_be(&mut o.as_mut()[48..]).unwrap(); - - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { - assert_eq!(coordinate, "y coordinate"); - } else { - panic!("should have rejected the point") - } - } - - { - let m = Fq::zero().into_repr(); - - let mut o = o; - m.write_be(&mut o.as_mut()[0..]).unwrap(); - - if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { - // :) - } else { - panic!("should have rejected the point because it isn't on the curve") - } - } - - { - let mut o = o; - let mut x = Fq::one(); - - loop { - let mut x3b = x; - x3b.square(); - x3b.mul_assign(&x); - x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); // TODO: perhaps expose coeff_b through API? - - if let Some(y) = x3b.sqrt() { - // We know this is on the curve, but it's likely not going to be in the correct subgroup. - x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); - y.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); - - if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { - break; - } else { - panic!( - "should have rejected the point because it isn't in the correct subgroup" - ) - } - } else { - x.add_assign(&Fq::one()); - } - } - } -} - -#[test] -fn test_g2_uncompressed_invalid_vectors() { - { - let z = G2Affine::zero().into_uncompressed(); - - { - let mut z = z; - z.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() { - // :) - } else { - panic!("should have rejected the point because we expected an uncompressed point"); - } - } - - { - let mut z = z; - z.as_mut()[0] |= 0b0010_0000; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { - // :) - } else { - panic!("should have rejected the point because the parity bit should not be set if the point is at infinity"); - } - } - - for i in 0..G2Uncompressed::size() { - let mut z = z; - z.as_mut()[i] |= 0b0000_0001; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { - // :) - } else { - panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity"); - } - } - } - - let o = G2Affine::one().into_uncompressed(); - - { - let mut o = o; - o.as_mut()[0] |= 0b1000_0000; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() { - // :) - } else { - panic!("should have rejected the point because we expected an uncompressed point"); - } - } - - let m = Fq::char(); - - { - let mut o = o; - m.write_be(&mut o.as_mut()[0..]).unwrap(); - - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { - assert_eq!(coordinate, "x coordinate (c1)"); - } else { - panic!("should have rejected the point") - } - } - - { - let mut o = o; - m.write_be(&mut o.as_mut()[48..]).unwrap(); - - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { - assert_eq!(coordinate, "x coordinate (c0)"); - } else { - panic!("should have rejected the point") - } - } - - { - let mut o = o; - m.write_be(&mut o.as_mut()[96..]).unwrap(); - - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { - assert_eq!(coordinate, "y coordinate (c1)"); - } else { - panic!("should have rejected the point") - } - } - - { - let mut o = o; - m.write_be(&mut o.as_mut()[144..]).unwrap(); - - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { - assert_eq!(coordinate, "y coordinate (c0)"); - } else { - panic!("should have rejected the point") - } - } - - { - let m = Fq::zero().into_repr(); - - let mut o = o; - m.write_be(&mut o.as_mut()[0..]).unwrap(); - m.write_be(&mut o.as_mut()[48..]).unwrap(); - - if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { - // :) - } else { - panic!("should have rejected the point because it isn't on the curve") - } - } - - { - let mut o = o; - let mut x = Fq2::one(); - - loop { - let mut x3b = x; - x3b.square(); - x3b.mul_assign(&x); - x3b.add_assign(&Fq2 { - c0: Fq::from_repr(FqRepr::from(4)).unwrap(), - c1: Fq::from_repr(FqRepr::from(4)).unwrap(), - }); // TODO: perhaps expose coeff_b through API? - - if let Some(y) = x3b.sqrt() { - // We know this is on the curve, but it's likely not going to be in the correct subgroup. - x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); - x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); - y.c1.into_repr().write_be(&mut o.as_mut()[96..]).unwrap(); - y.c0.into_repr().write_be(&mut o.as_mut()[144..]).unwrap(); - - if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { - break; - } else { - panic!( - "should have rejected the point because it isn't in the correct subgroup" - ) - } - } else { - x.add_assign(&Fq2::one()); - } - } - } -} - -#[test] -fn test_g1_compressed_invalid_vectors() { - { - let z = G1Affine::zero().into_compressed(); - - { - let mut z = z; - z.as_mut()[0] &= 0b0111_1111; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() { - // :) - } else { - panic!("should have rejected the point because we expected a compressed point"); - } - } - - { - let mut z = z; - z.as_mut()[0] |= 0b0010_0000; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { - // :) - } else { - panic!("should have rejected the point because the parity bit should not be set if the point is at infinity"); - } - } - - for i in 0..G1Compressed::size() { - let mut z = z; - z.as_mut()[i] |= 0b0000_0001; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { - // :) - } else { - panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity"); - } - } - } - - let o = G1Affine::one().into_compressed(); - - { - let mut o = o; - o.as_mut()[0] &= 0b0111_1111; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() { - // :) - } else { - panic!("should have rejected the point because we expected a compressed point"); - } - } - - let m = Fq::char(); - - { - let mut o = o; - m.write_be(&mut o.as_mut()[0..]).unwrap(); - o.as_mut()[0] |= 0b1000_0000; - - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { - assert_eq!(coordinate, "x coordinate"); - } else { - panic!("should have rejected the point") - } - } - - { - let mut o = o; - let mut x = Fq::one(); - - loop { - let mut x3b = x; - x3b.square(); - x3b.mul_assign(&x); - x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); // TODO: perhaps expose coeff_b through API? - - if let Some(_) = x3b.sqrt() { - x.add_assign(&Fq::one()); - } else { - x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); - o.as_mut()[0] |= 0b1000_0000; - - if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { - break; - } else { - panic!("should have rejected the point because it isn't on the curve") - } - } - } - } - - { - let mut o = o; - let mut x = Fq::one(); - - loop { - let mut x3b = x; - x3b.square(); - x3b.mul_assign(&x); - x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); // TODO: perhaps expose coeff_b through API? - - if let Some(_) = x3b.sqrt() { - // We know this is on the curve, but it's likely not going to be in the correct subgroup. - x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); - o.as_mut()[0] |= 0b1000_0000; - - if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { - break; - } else { - panic!( - "should have rejected the point because it isn't in the correct subgroup" - ) - } - } else { - x.add_assign(&Fq::one()); - } - } - } -} - -#[test] -fn test_g2_compressed_invalid_vectors() { - { - let z = G2Affine::zero().into_compressed(); - - { - let mut z = z; - z.as_mut()[0] &= 0b0111_1111; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = z.into_affine() { - // :) - } else { - panic!("should have rejected the point because we expected a compressed point"); - } - } - - { - let mut z = z; - z.as_mut()[0] |= 0b0010_0000; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { - // :) - } else { - panic!("should have rejected the point because the parity bit should not be set if the point is at infinity"); - } - } - - for i in 0..G2Compressed::size() { - let mut z = z; - z.as_mut()[i] |= 0b0000_0001; - if let Err(GroupDecodingError::UnexpectedInformation) = z.into_affine() { - // :) - } else { - panic!("should have rejected the point because the coordinates should be zeroes at the point at infinity"); - } - } - } - - let o = G2Affine::one().into_compressed(); - - { - let mut o = o; - o.as_mut()[0] &= 0b0111_1111; - if let Err(GroupDecodingError::UnexpectedCompressionMode) = o.into_affine() { - // :) - } else { - panic!("should have rejected the point because we expected a compressed point"); - } - } - - let m = Fq::char(); - - { - let mut o = o; - m.write_be(&mut o.as_mut()[0..]).unwrap(); - o.as_mut()[0] |= 0b1000_0000; - - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { - assert_eq!(coordinate, "x coordinate (c1)"); - } else { - panic!("should have rejected the point") - } - } - - { - let mut o = o; - m.write_be(&mut o.as_mut()[48..]).unwrap(); - o.as_mut()[0] |= 0b1000_0000; - - if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() { - assert_eq!(coordinate, "x coordinate (c0)"); - } else { - panic!("should have rejected the point") - } - } - - { - let mut o = o; - let mut x = Fq2 { - c0: Fq::one(), - c1: Fq::one(), - }; - - loop { - let mut x3b = x; - x3b.square(); - x3b.mul_assign(&x); - x3b.add_assign(&Fq2 { - c0: Fq::from_repr(FqRepr::from(4)).unwrap(), - c1: Fq::from_repr(FqRepr::from(4)).unwrap(), - }); // TODO: perhaps expose coeff_b through API? - - if let Some(_) = x3b.sqrt() { - x.add_assign(&Fq2::one()); - } else { - x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); - x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); - o.as_mut()[0] |= 0b1000_0000; - - if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() { - break; - } else { - panic!("should have rejected the point because it isn't on the curve") - } - } - } - } - - { - let mut o = o; - let mut x = Fq2 { - c0: Fq::one(), - c1: Fq::one(), - }; - - loop { - let mut x3b = x; - x3b.square(); - x3b.mul_assign(&x); - x3b.add_assign(&Fq2 { - c0: Fq::from_repr(FqRepr::from(4)).unwrap(), - c1: Fq::from_repr(FqRepr::from(4)).unwrap(), - }); // TODO: perhaps expose coeff_b through API? - - if let Some(_) = x3b.sqrt() { - // We know this is on the curve, but it's likely not going to be in the correct subgroup. - x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap(); - x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap(); - o.as_mut()[0] |= 0b1000_0000; - - if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() { - break; - } else { - panic!( - "should have rejected the point because it isn't in the correct subgroup" - ) - } - } else { - x.add_assign(&Fq2::one()); - } - } - } -} diff --git a/pairing/src/lib.rs b/pairing/src/lib.rs deleted file mode 100644 index adabcce..0000000 --- a/pairing/src/lib.rs +++ /dev/null @@ -1,118 +0,0 @@ -// `clippy` is a code linting tool for improving code quality by catching -// common mistakes or strange code patterns. If the `cargo-clippy` feature -// is provided, all compiler warnings are prohibited. -#![cfg_attr(feature = "cargo-clippy", deny(warnings))] -#![cfg_attr(feature = "cargo-clippy", allow(inline_always))] -#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] -#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] -#![cfg_attr(feature = "cargo-clippy", allow(many_single_char_names))] -#![cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))] -#![cfg_attr(feature = "cargo-clippy", allow(write_literal))] -// Force public structures to implement Debug -#![deny(missing_debug_implementations)] - -extern crate byteorder; -#[macro_use] -extern crate ff; -extern crate group; -extern crate rand; - -#[cfg(test)] -pub mod tests; - -pub mod bls12_381; - -use ff::{Field, PrimeField, ScalarEngine, SqrtField}; -use group::{CurveAffine, CurveProjective}; - -/// An "engine" is a collection of types (fields, elliptic curve groups, etc.) -/// with well-defined relationships. In particular, the G1/G2 curve groups are -/// of prime order `r`, and are equipped with a bilinear pairing function. -pub trait Engine: ScalarEngine { - /// The projective representation of an element in G1. - type G1: CurveProjective< - Engine = Self, - Base = Self::Fq, - Scalar = Self::Fr, - Affine = Self::G1Affine, - > - + From; - - /// The affine representation of an element in G1. - type G1Affine: PairingCurveAffine< - Engine = Self, - Base = Self::Fq, - Scalar = Self::Fr, - Projective = Self::G1, - Pair = Self::G2Affine, - PairingResult = Self::Fqk, - > - + From; - - /// The projective representation of an element in G2. - type G2: CurveProjective< - Engine = Self, - Base = Self::Fqe, - Scalar = Self::Fr, - Affine = Self::G2Affine, - > - + From; - - /// The affine representation of an element in G2. - type G2Affine: PairingCurveAffine< - Engine = Self, - Base = Self::Fqe, - Scalar = Self::Fr, - Projective = Self::G2, - Pair = Self::G1Affine, - PairingResult = Self::Fqk, - > - + From; - - /// The base field that hosts G1. - type Fq: PrimeField + SqrtField; - - /// The extension field that hosts G2. - type Fqe: SqrtField; - - /// The extension field that hosts the target group of the pairing. - type Fqk: Field; - - /// Perform a miller loop with some number of (G1, G2) pairs. - fn miller_loop<'a, I>(i: I) -> Self::Fqk - where - I: IntoIterator< - Item = &'a ( - &'a ::Prepared, - &'a ::Prepared, - ), - >; - - /// Perform final exponentiation of the result of a miller loop. - fn final_exponentiation(&Self::Fqk) -> Option; - - /// Performs a complete pairing operation `(p, q)`. - fn pairing(p: G1, q: G2) -> Self::Fqk - where - G1: Into, - G2: Into, - { - Self::final_exponentiation(&Self::miller_loop( - [(&(p.into().prepare()), &(q.into().prepare()))].into_iter(), - )).unwrap() - } -} - -/// Affine representation of an elliptic curve point that can be used -/// to perform pairings. -pub trait PairingCurveAffine: CurveAffine { - type Prepared: Clone + Send + Sync + 'static; - type Pair: PairingCurveAffine; - type PairingResult: Field; - - /// Prepares this element for pairing purposes. - fn prepare(&self) -> Self::Prepared; - - /// Perform a pairing - fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult; -} diff --git a/pairing/src/tests/engine.rs b/pairing/src/tests/engine.rs deleted file mode 100644 index 7b1944d..0000000 --- a/pairing/src/tests/engine.rs +++ /dev/null @@ -1,127 +0,0 @@ -use group::{CurveAffine, CurveProjective}; -use rand::{Rand, SeedableRng, XorShiftRng}; - -use {Engine, Field, PairingCurveAffine, PrimeField}; - -pub fn engine_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..10 { - let a = E::G1::rand(&mut rng).into_affine(); - let b = E::G2::rand(&mut rng).into_affine(); - - assert!(a.pairing_with(&b) == b.pairing_with(&a)); - assert!(a.pairing_with(&b) == E::pairing(a, b)); - } - - for _ in 0..1000 { - let z1 = E::G1Affine::zero().prepare(); - let z2 = E::G2Affine::zero().prepare(); - - let a = E::G1::rand(&mut rng).into_affine().prepare(); - let b = E::G2::rand(&mut rng).into_affine().prepare(); - let c = E::G1::rand(&mut rng).into_affine().prepare(); - let d = E::G2::rand(&mut rng).into_affine().prepare(); - - assert_eq!( - E::Fqk::one(), - E::final_exponentiation(&E::miller_loop(&[(&z1, &b)])).unwrap() - ); - - assert_eq!( - E::Fqk::one(), - E::final_exponentiation(&E::miller_loop(&[(&a, &z2)])).unwrap() - ); - - assert_eq!( - E::final_exponentiation(&E::miller_loop(&[(&z1, &b), (&c, &d)])).unwrap(), - E::final_exponentiation(&E::miller_loop(&[(&a, &z2), (&c, &d)])).unwrap() - ); - - assert_eq!( - E::final_exponentiation(&E::miller_loop(&[(&a, &b), (&z1, &d)])).unwrap(), - E::final_exponentiation(&E::miller_loop(&[(&a, &b), (&c, &z2)])).unwrap() - ); - } - - random_bilinearity_tests::(); - random_miller_loop_tests::(); -} - -fn random_miller_loop_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - // Exercise the miller loop for a reduced pairing - for _ in 0..1000 { - let a = E::G1::rand(&mut rng); - let b = E::G2::rand(&mut rng); - - let p2 = E::pairing(a, b); - - let a = a.into_affine().prepare(); - let b = b.into_affine().prepare(); - - let p1 = E::final_exponentiation(&E::miller_loop(&[(&a, &b)])).unwrap(); - - assert_eq!(p1, p2); - } - - // Exercise a double miller loop - for _ in 0..1000 { - let a = E::G1::rand(&mut rng); - let b = E::G2::rand(&mut rng); - let c = E::G1::rand(&mut rng); - let d = E::G2::rand(&mut rng); - - let ab = E::pairing(a, b); - let cd = E::pairing(c, d); - - let mut abcd = ab; - abcd.mul_assign(&cd); - - let a = a.into_affine().prepare(); - let b = b.into_affine().prepare(); - let c = c.into_affine().prepare(); - let d = d.into_affine().prepare(); - - let abcd_with_double_loop = - E::final_exponentiation(&E::miller_loop(&[(&a, &b), (&c, &d)])).unwrap(); - - assert_eq!(abcd, abcd_with_double_loop); - } -} - -fn random_bilinearity_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let a = E::G1::rand(&mut rng); - let b = E::G2::rand(&mut rng); - - let c = E::Fr::rand(&mut rng); - let d = E::Fr::rand(&mut rng); - - let mut ac = a; - ac.mul_assign(c); - - let mut ad = a; - ad.mul_assign(d); - - let mut bc = b; - bc.mul_assign(c); - - let mut bd = b; - bd.mul_assign(d); - - let acbd = E::pairing(ac, bd); - let adbc = E::pairing(ad, bc); - - let mut cd = c; - cd.mul_assign(&d); - - let abcd = E::pairing(a, b).pow(cd.into_repr()); - - assert_eq!(acbd, adbc); - assert_eq!(acbd, abcd); - } -} diff --git a/pairing/src/tests/field.rs b/pairing/src/tests/field.rs deleted file mode 100644 index 55396a7..0000000 --- a/pairing/src/tests/field.rs +++ /dev/null @@ -1,266 +0,0 @@ -use ff::{Field, LegendreSymbol, PrimeField, SqrtField}; -use rand::{Rng, SeedableRng, XorShiftRng}; - -pub fn random_frobenius_tests>(characteristic: C, maxpower: usize) { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - for i in 0..(maxpower + 1) { - let mut a = F::rand(&mut rng); - let mut b = a; - - for _ in 0..i { - a = a.pow(&characteristic); - } - b.frobenius_map(i); - - assert_eq!(a, b); - } - } -} - -pub fn random_sqrt_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..10000 { - let a = F::rand(&mut rng); - let mut b = a; - b.square(); - assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); - - let b = b.sqrt().unwrap(); - let mut negb = b; - negb.negate(); - - assert!(a == b || a == negb); - } - - let mut c = F::one(); - for _ in 0..10000 { - let mut b = c; - b.square(); - assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); - - b = b.sqrt().unwrap(); - - if b != c { - b.negate(); - } - - assert_eq!(b, c); - - c.add_assign(&F::one()); - } -} - -pub fn random_field_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - random_multiplication_tests::(&mut rng); - random_addition_tests::(&mut rng); - random_subtraction_tests::(&mut rng); - random_negation_tests::(&mut rng); - random_doubling_tests::(&mut rng); - random_squaring_tests::(&mut rng); - random_inversion_tests::(&mut rng); - random_expansion_tests::(&mut rng); - - assert!(F::zero().is_zero()); - { - let mut z = F::zero(); - z.negate(); - assert!(z.is_zero()); - } - - assert!(F::zero().inverse().is_none()); - - // Multiplication by zero - { - let mut a = F::rand(&mut rng); - a.mul_assign(&F::zero()); - assert!(a.is_zero()); - } - - // Addition by zero - { - let mut a = F::rand(&mut rng); - let copy = a; - a.add_assign(&F::zero()); - assert_eq!(a, copy); - } -} - -pub fn from_str_tests() { - { - let a = "84395729384759238745923745892374598234705297301958723458712394587103249587213984572934750213947582345792304758273458972349582734958273495872304598234"; - let b = "38495729084572938457298347502349857029384609283450692834058293405982304598230458230495820394850293845098234059823049582309485203948502938452093482039"; - let c = "3248875134290623212325429203829831876024364170316860259933542844758450336418538569901990710701240661702808867062612075657861768196242274635305077449545396068598317421057721935408562373834079015873933065667961469731886739181625866970316226171512545167081793907058686908697431878454091011239990119126"; - - let mut a = F::from_str(a).unwrap(); - let b = F::from_str(b).unwrap(); - let c = F::from_str(c).unwrap(); - - a.mul_assign(&b); - - assert_eq!(a, c); - } - - { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let n: u64 = rng.gen(); - - let a = F::from_str(&format!("{}", n)).unwrap(); - let b = F::from_repr(n.into()).unwrap(); - - assert_eq!(a, b); - } - } - - assert!(F::from_str("").is_none()); - assert!(F::from_str("0").unwrap().is_zero()); - assert!(F::from_str("00").is_none()); - assert!(F::from_str("00000000000").is_none()); -} - -fn random_multiplication_tests(rng: &mut R) { - for _ in 0..10000 { - let a = F::rand(rng); - let b = F::rand(rng); - let c = F::rand(rng); - - let mut t0 = a; // (a * b) * c - t0.mul_assign(&b); - t0.mul_assign(&c); - - let mut t1 = a; // (a * c) * b - t1.mul_assign(&c); - t1.mul_assign(&b); - - let mut t2 = b; // (b * c) * a - t2.mul_assign(&c); - t2.mul_assign(&a); - - assert_eq!(t0, t1); - assert_eq!(t1, t2); - } -} - -fn random_addition_tests(rng: &mut R) { - for _ in 0..10000 { - let a = F::rand(rng); - let b = F::rand(rng); - let c = F::rand(rng); - - let mut t0 = a; // (a + b) + c - t0.add_assign(&b); - t0.add_assign(&c); - - let mut t1 = a; // (a + c) + b - t1.add_assign(&c); - t1.add_assign(&b); - - let mut t2 = b; // (b + c) + a - t2.add_assign(&c); - t2.add_assign(&a); - - assert_eq!(t0, t1); - assert_eq!(t1, t2); - } -} - -fn random_subtraction_tests(rng: &mut R) { - for _ in 0..10000 { - let a = F::rand(rng); - let b = F::rand(rng); - - let mut t0 = a; // (a - b) - t0.sub_assign(&b); - - let mut t1 = b; // (b - a) - t1.sub_assign(&a); - - let mut t2 = t0; // (a - b) + (b - a) = 0 - t2.add_assign(&t1); - - assert!(t2.is_zero()); - } -} - -fn random_negation_tests(rng: &mut R) { - for _ in 0..10000 { - let a = F::rand(rng); - let mut b = a; - b.negate(); - b.add_assign(&a); - - assert!(b.is_zero()); - } -} - -fn random_doubling_tests(rng: &mut R) { - for _ in 0..10000 { - let mut a = F::rand(rng); - let mut b = a; - a.add_assign(&b); - b.double(); - - assert_eq!(a, b); - } -} - -fn random_squaring_tests(rng: &mut R) { - for _ in 0..10000 { - let mut a = F::rand(rng); - let mut b = a; - a.mul_assign(&b); - b.square(); - - assert_eq!(a, b); - } -} - -fn random_inversion_tests(rng: &mut R) { - assert!(F::zero().inverse().is_none()); - - for _ in 0..10000 { - let mut a = F::rand(rng); - let b = a.inverse().unwrap(); // probablistically nonzero - a.mul_assign(&b); - - assert_eq!(a, F::one()); - } -} - -fn random_expansion_tests(rng: &mut R) { - for _ in 0..10000 { - // Compare (a + b)(c + d) and (a*c + b*c + a*d + b*d) - - let a = F::rand(rng); - let b = F::rand(rng); - let c = F::rand(rng); - let d = F::rand(rng); - - let mut t0 = a; - t0.add_assign(&b); - let mut t1 = c; - t1.add_assign(&d); - t0.mul_assign(&t1); - - let mut t2 = a; - t2.mul_assign(&c); - let mut t3 = b; - t3.mul_assign(&c); - let mut t4 = a; - t4.mul_assign(&d); - let mut t5 = b; - t5.mul_assign(&d); - - t2.add_assign(&t3); - t2.add_assign(&t4); - t2.add_assign(&t5); - - assert_eq!(t0, t2); - } -} diff --git a/pairing/src/tests/mod.rs b/pairing/src/tests/mod.rs deleted file mode 100644 index d6ad6a1..0000000 --- a/pairing/src/tests/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod engine; -pub mod field; -pub mod repr; diff --git a/pairing/src/tests/repr.rs b/pairing/src/tests/repr.rs deleted file mode 100644 index 09dd441..0000000 --- a/pairing/src/tests/repr.rs +++ /dev/null @@ -1,98 +0,0 @@ -use ff::PrimeFieldRepr; -use rand::{SeedableRng, XorShiftRng}; - -pub fn random_repr_tests() { - random_encoding_tests::(); - random_shl_tests::(); - random_shr_tests::(); -} - -fn random_encoding_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let r = R::rand(&mut rng); - - // Big endian - { - let mut rdecoded = R::default(); - - let mut v: Vec = vec![]; - r.write_be(&mut v).unwrap(); - rdecoded.read_be(&v[0..]).unwrap(); - - assert_eq!(r, rdecoded); - } - - // Little endian - { - let mut rdecoded = R::default(); - - let mut v: Vec = vec![]; - r.write_le(&mut v).unwrap(); - rdecoded.read_le(&v[0..]).unwrap(); - - assert_eq!(r, rdecoded); - } - - { - let mut rdecoded_le = R::default(); - let mut rdecoded_be_flip = R::default(); - - let mut v: Vec = vec![]; - r.write_le(&mut v).unwrap(); - - // This reads in little-endian, so we are done. - rdecoded_le.read_le(&v[..]).unwrap(); - - // This reads in big-endian, so we perform a swap of the - // bytes beforehand. - let v: Vec = v.into_iter().rev().collect(); - rdecoded_be_flip.read_be(&v[..]).unwrap(); - - assert_eq!(rdecoded_le, rdecoded_be_flip); - } - } -} - -fn random_shl_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let r = R::rand(&mut rng); - - for shift in 0..(r.num_bits() + 1) { - let mut r1 = r; - let mut r2 = r; - - for _ in 0..shift { - r1.mul2(); - } - - r2.shl(shift); - - assert_eq!(r1, r2); - } - } -} - -fn random_shr_tests() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let r = R::rand(&mut rng); - - for shift in 0..(r.num_bits() + 1) { - let mut r1 = r; - let mut r2 = r; - - for _ in 0..shift { - r1.div2(); - } - - r2.shr(shift); - - assert_eq!(r1, r2); - } - } -} diff --git a/sapling-crypto/.gitignore b/sapling-crypto/.gitignore deleted file mode 100644 index 6aa1064..0000000 --- a/sapling-crypto/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target/ -**/*.rs.bk -Cargo.lock diff --git a/sapling-crypto/COPYRIGHT b/sapling-crypto/COPYRIGHT deleted file mode 100644 index f2c6a3b..0000000 --- a/sapling-crypto/COPYRIGHT +++ /dev/null @@ -1,14 +0,0 @@ -Copyrights in the "sapling-crypto" library are retained by their contributors. No -copyright assignment is required to contribute to the "sapling-crypto" library. - -The "sapling-crypto" library is licensed under either of - - * Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT) - -at your option. - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/sapling-crypto/Cargo.toml b/sapling-crypto/Cargo.toml deleted file mode 100644 index 393c01f..0000000 --- a/sapling-crypto/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -authors = ["Sean Bowe "] -description = "Cryptographic library for Zcash Sapling" -documentation = "https://github.com/zcash-hackworks/sapling" -homepage = "https://github.com/zcash-hackworks/sapling" -license = "MIT/Apache-2.0" -name = "sapling-crypto" -repository = "https://github.com/zcash-hackworks/sapling" -version = "0.0.1" - -[dependencies.pairing] -path = "../pairing" -features = ["expose-arith"] - -[dependencies] -bellman = { path = "../bellman" } -rand = "0.4" -digest = "0.7" -byteorder = "1" - -[dependencies.blake2-rfc] -git = "https://github.com/gtank/blake2-rfc" -rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" - -[dev-dependencies] -hex-literal = "0.1" -rust-crypto = "0.2" diff --git a/sapling-crypto/LICENSE-APACHE b/sapling-crypto/LICENSE-APACHE deleted file mode 100644 index 16fe87b..0000000 --- a/sapling-crypto/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. diff --git a/sapling-crypto/LICENSE-MIT b/sapling-crypto/LICENSE-MIT deleted file mode 100644 index 31aa793..0000000 --- a/sapling-crypto/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/sapling-crypto/README.md b/sapling-crypto/README.md deleted file mode 100644 index f5d3bce..0000000 --- a/sapling-crypto/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# sapling-crypto - -This repository contains a (work-in-progress) implementation of Zcash's "Sapling" cryptography. - -## Security Warnings - -This library is currently under development and has not been reviewed. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/sapling-crypto/benches/pedersen_hash.rs b/sapling-crypto/benches/pedersen_hash.rs deleted file mode 100644 index c5968de..0000000 --- a/sapling-crypto/benches/pedersen_hash.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![feature(test)] - -extern crate rand; -extern crate test; -extern crate pairing; -extern crate sapling_crypto; - -use rand::{Rand, thread_rng}; -use pairing::bls12_381::Bls12; -use sapling_crypto::jubjub::JubjubBls12; -use sapling_crypto::pedersen_hash::{pedersen_hash, Personalization}; - -#[bench] -fn bench_pedersen_hash(b: &mut test::Bencher) { - let params = JubjubBls12::new(); - let rng = &mut thread_rng(); - let bits = (0..510).map(|_| bool::rand(rng)).collect::>(); - let personalization = Personalization::MerkleTree(31); - - b.iter(|| { - pedersen_hash::(personalization, bits.clone(), ¶ms) - }); -} diff --git a/sapling-crypto/examples/bench.rs b/sapling-crypto/examples/bench.rs deleted file mode 100644 index 4b7a707..0000000 --- a/sapling-crypto/examples/bench.rs +++ /dev/null @@ -1,102 +0,0 @@ -extern crate sapling_crypto; -extern crate bellman; -extern crate rand; -extern crate pairing; - -use std::time::{Duration, Instant}; -use sapling_crypto::jubjub::{ - JubjubBls12, - edwards, - fs, -}; -use sapling_crypto::circuit::sapling::{ - Spend -}; -use sapling_crypto::primitives::{ - Diversifier, - ProofGenerationKey, - ValueCommitment -}; -use bellman::groth16::*; -use rand::{XorShiftRng, SeedableRng, Rng}; -use pairing::bls12_381::{Bls12, Fr}; - -const TREE_DEPTH: usize = 32; - -fn main() { - let jubjub_params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - println!("Creating sample parameters..."); - let groth_params = generate_random_parameters::( - Spend { - params: jubjub_params, - value_commitment: None, - proof_generation_key: None, - payment_address: None, - commitment_randomness: None, - ar: None, - auth_path: vec![None; TREE_DEPTH], - anchor: None - }, - rng - ).unwrap(); - - const SAMPLES: u32 = 50; - - let mut total_time = Duration::new(0, 0); - for _ in 0..SAMPLES { - let value_commitment = ValueCommitment { - value: 1, - randomness: rng.gen() - }; - - let nsk: fs::Fs = rng.gen(); - let ak = edwards::Point::rand(rng, jubjub_params).mul_by_cofactor(jubjub_params); - - let proof_generation_key = ProofGenerationKey { - ak: ak.clone(), - nsk: nsk.clone() - }; - - let viewing_key = proof_generation_key.into_viewing_key(jubjub_params); - - let payment_address; - - loop { - let diversifier = Diversifier(rng.gen()); - - if let Some(p) = viewing_key.into_payment_address( - diversifier, - jubjub_params - ) - { - payment_address = p; - break; - } - } - - let commitment_randomness: fs::Fs = rng.gen(); - let auth_path = vec![Some((rng.gen(), rng.gen())); TREE_DEPTH]; - let ar: fs::Fs = rng.gen(); - let anchor: Fr = rng.gen(); - - let start = Instant::now(); - let _ = create_random_proof(Spend { - params: jubjub_params, - value_commitment: Some(value_commitment), - proof_generation_key: Some(proof_generation_key), - payment_address: Some(payment_address), - commitment_randomness: Some(commitment_randomness), - ar: Some(ar), - auth_path: auth_path, - anchor: Some(anchor) - }, &groth_params, rng).unwrap(); - total_time += start.elapsed(); - } - let avg = total_time / SAMPLES; - let avg = avg.subsec_nanos() as f64 / 1_000_000_000f64 - + (avg.as_secs() as f64); - - println!("Average proving time (in seconds): {}", avg); -} diff --git a/sapling-crypto/src/circuit/blake2s.rs b/sapling-crypto/src/circuit/blake2s.rs deleted file mode 100644 index 93af806..0000000 --- a/sapling-crypto/src/circuit/blake2s.rs +++ /dev/null @@ -1,438 +0,0 @@ -use pairing::{ - Engine, -}; - -use bellman::{ - SynthesisError, - ConstraintSystem -}; - -use super::boolean::{ - Boolean -}; - -use super::uint32::{ - UInt32 -}; - -use super::multieq::MultiEq; - -/* -2.1. Parameters - The following table summarizes various parameters and their ranges: - | BLAKE2b | BLAKE2s | - --------------+------------------+------------------+ - Bits in word | w = 64 | w = 32 | - Rounds in F | r = 12 | r = 10 | - Block bytes | bb = 128 | bb = 64 | - Hash bytes | 1 <= nn <= 64 | 1 <= nn <= 32 | - Key bytes | 0 <= kk <= 64 | 0 <= kk <= 32 | - Input bytes | 0 <= ll < 2**128 | 0 <= ll < 2**64 | - --------------+------------------+------------------+ - G Rotation | (R1, R2, R3, R4) | (R1, R2, R3, R4) | - constants = | (32, 24, 16, 63) | (16, 12, 8, 7) | - --------------+------------------+------------------+ -*/ - -const R1: usize = 16; -const R2: usize = 12; -const R3: usize = 8; -const R4: usize = 7; - -/* - Round | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | - ----------+-------------------------------------------------+ - SIGMA[0] | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | - SIGMA[1] | 14 10 4 8 9 15 13 6 1 12 0 2 11 7 5 3 | - SIGMA[2] | 11 8 12 0 5 2 15 13 10 14 3 6 7 1 9 4 | - SIGMA[3] | 7 9 3 1 13 12 11 14 2 6 5 10 4 0 15 8 | - SIGMA[4] | 9 0 5 7 2 4 10 15 14 1 11 12 6 8 3 13 | - SIGMA[5] | 2 12 6 10 0 11 8 3 4 13 7 5 15 14 1 9 | - SIGMA[6] | 12 5 1 15 14 13 4 10 0 7 6 3 9 2 8 11 | - SIGMA[7] | 13 11 7 14 12 1 3 9 5 0 15 4 8 6 2 10 | - SIGMA[8] | 6 15 14 9 11 3 0 8 12 2 13 7 1 4 10 5 | - SIGMA[9] | 10 2 8 4 7 6 1 5 15 11 9 14 3 12 13 0 | - ----------+-------------------------------------------------+ -*/ - -const SIGMA: [[usize; 16]; 10] = [ - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], - [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], - [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], - [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], - [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], - [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], - [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], - [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], - [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], - [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0] -]; - -/* -3.1. Mixing Function G - The G primitive function mixes two input words, "x" and "y", into - four words indexed by "a", "b", "c", and "d" in the working vector - v[0..15]. The full modified vector is returned. The rotation - constants (R1, R2, R3, R4) are given in Section 2.1. - FUNCTION G( v[0..15], a, b, c, d, x, y ) - | - | v[a] := (v[a] + v[b] + x) mod 2**w - | v[d] := (v[d] ^ v[a]) >>> R1 - | v[c] := (v[c] + v[d]) mod 2**w - | v[b] := (v[b] ^ v[c]) >>> R2 - | v[a] := (v[a] + v[b] + y) mod 2**w - | v[d] := (v[d] ^ v[a]) >>> R3 - | v[c] := (v[c] + v[d]) mod 2**w - | v[b] := (v[b] ^ v[c]) >>> R4 - | - | RETURN v[0..15] - | - END FUNCTION. -*/ - -fn mixing_g, M>( - mut cs: M, - v: &mut [UInt32], - a: usize, - b: usize, - c: usize, - d: usize, - x: &UInt32, - y: &UInt32 -) -> Result<(), SynthesisError> - where M: ConstraintSystem> -{ - v[a] = UInt32::addmany(cs.namespace(|| "mixing step 1"), &[v[a].clone(), v[b].clone(), x.clone()])?; - v[d] = v[d].xor(cs.namespace(|| "mixing step 2"), &v[a])?.rotr(R1); - v[c] = UInt32::addmany(cs.namespace(|| "mixing step 3"), &[v[c].clone(), v[d].clone()])?; - v[b] = v[b].xor(cs.namespace(|| "mixing step 4"), &v[c])?.rotr(R2); - v[a] = UInt32::addmany(cs.namespace(|| "mixing step 5"), &[v[a].clone(), v[b].clone(), y.clone()])?; - v[d] = v[d].xor(cs.namespace(|| "mixing step 6"), &v[a])?.rotr(R3); - v[c] = UInt32::addmany(cs.namespace(|| "mixing step 7"), &[v[c].clone(), v[d].clone()])?; - v[b] = v[b].xor(cs.namespace(|| "mixing step 8"), &v[c])?.rotr(R4); - - Ok(()) -} - -/* -3.2. Compression Function F - Compression function F takes as an argument the state vector "h", - message block vector "m" (last block is padded with zeros to full - block size, if required), 2w-bit offset counter "t", and final block - indicator flag "f". Local vector v[0..15] is used in processing. F - returns a new state vector. The number of rounds, "r", is 12 for - BLAKE2b and 10 for BLAKE2s. Rounds are numbered from 0 to r - 1. - FUNCTION F( h[0..7], m[0..15], t, f ) - | - | // Initialize local work vector v[0..15] - | v[0..7] := h[0..7] // First half from state. - | v[8..15] := IV[0..7] // Second half from IV. - | - | v[12] := v[12] ^ (t mod 2**w) // Low word of the offset. - | v[13] := v[13] ^ (t >> w) // High word. - | - | IF f = TRUE THEN // last block flag? - | | v[14] := v[14] ^ 0xFF..FF // Invert all bits. - | END IF. - | - | // Cryptographic mixing - | FOR i = 0 TO r - 1 DO // Ten or twelve rounds. - | | - | | // Message word selection permutation for this round. - | | s[0..15] := SIGMA[i mod 10][0..15] - | | - | | v := G( v, 0, 4, 8, 12, m[s[ 0]], m[s[ 1]] ) - | | v := G( v, 1, 5, 9, 13, m[s[ 2]], m[s[ 3]] ) - | | v := G( v, 2, 6, 10, 14, m[s[ 4]], m[s[ 5]] ) - | | v := G( v, 3, 7, 11, 15, m[s[ 6]], m[s[ 7]] ) - | | - | | v := G( v, 0, 5, 10, 15, m[s[ 8]], m[s[ 9]] ) - | | v := G( v, 1, 6, 11, 12, m[s[10]], m[s[11]] ) - | | v := G( v, 2, 7, 8, 13, m[s[12]], m[s[13]] ) - | | v := G( v, 3, 4, 9, 14, m[s[14]], m[s[15]] ) - | | - | END FOR - | - | FOR i = 0 TO 7 DO // XOR the two halves. - | | h[i] := h[i] ^ v[i] ^ v[i + 8] - | END FOR. - | - | RETURN h[0..7] // New state. - | - END FUNCTION. -*/ - - -fn blake2s_compression>( - mut cs: CS, - h: &mut [UInt32], - m: &[UInt32], - t: u64, - f: bool -) -> Result<(), SynthesisError> -{ - assert_eq!(h.len(), 8); - assert_eq!(m.len(), 16); - - /* - static const uint32_t blake2s_iv[8] = - { - 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, - 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 - }; - */ - - let mut v = Vec::with_capacity(16); - v.extend_from_slice(h); - v.push(UInt32::constant(0x6A09E667)); - v.push(UInt32::constant(0xBB67AE85)); - v.push(UInt32::constant(0x3C6EF372)); - v.push(UInt32::constant(0xA54FF53A)); - v.push(UInt32::constant(0x510E527F)); - v.push(UInt32::constant(0x9B05688C)); - v.push(UInt32::constant(0x1F83D9AB)); - v.push(UInt32::constant(0x5BE0CD19)); - - assert_eq!(v.len(), 16); - - v[12] = v[12].xor(cs.namespace(|| "first xor"), &UInt32::constant(t as u32))?; - v[13] = v[13].xor(cs.namespace(|| "second xor"), &UInt32::constant((t >> 32) as u32))?; - - if f { - v[14] = v[14].xor(cs.namespace(|| "third xor"), &UInt32::constant(u32::max_value()))?; - } - - { - let mut cs = MultiEq::new(&mut cs); - - for i in 0..10 { - let mut cs = cs.namespace(|| format!("round {}", i)); - - let s = SIGMA[i % 10]; - - mixing_g(cs.namespace(|| "mixing invocation 1"), &mut v, 0, 4, 8, 12, &m[s[ 0]], &m[s[ 1]])?; - mixing_g(cs.namespace(|| "mixing invocation 2"), &mut v, 1, 5, 9, 13, &m[s[ 2]], &m[s[ 3]])?; - mixing_g(cs.namespace(|| "mixing invocation 3"), &mut v, 2, 6, 10, 14, &m[s[ 4]], &m[s[ 5]])?; - mixing_g(cs.namespace(|| "mixing invocation 4"), &mut v, 3, 7, 11, 15, &m[s[ 6]], &m[s[ 7]])?; - - mixing_g(cs.namespace(|| "mixing invocation 5"), &mut v, 0, 5, 10, 15, &m[s[ 8]], &m[s[ 9]])?; - mixing_g(cs.namespace(|| "mixing invocation 6"), &mut v, 1, 6, 11, 12, &m[s[10]], &m[s[11]])?; - mixing_g(cs.namespace(|| "mixing invocation 7"), &mut v, 2, 7, 8, 13, &m[s[12]], &m[s[13]])?; - mixing_g(cs.namespace(|| "mixing invocation 8"), &mut v, 3, 4, 9, 14, &m[s[14]], &m[s[15]])?; - } - } - - for i in 0..8 { - let mut cs = cs.namespace(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i=i)); - - h[i] = h[i].xor(cs.namespace(|| "first xor"), &v[i])?; - h[i] = h[i].xor(cs.namespace(|| "second xor"), &v[i + 8])?; - } - - Ok(()) -} - -/* - FUNCTION BLAKE2( d[0..dd-1], ll, kk, nn ) - | - | h[0..7] := IV[0..7] // Initialization Vector. - | - | // Parameter block p[0] - | h[0] := h[0] ^ 0x01010000 ^ (kk << 8) ^ nn - | - | // Process padded key and data blocks - | IF dd > 1 THEN - | | FOR i = 0 TO dd - 2 DO - | | | h := F( h, d[i], (i + 1) * bb, FALSE ) - | | END FOR. - | END IF. - | - | // Final block. - | IF kk = 0 THEN - | | h := F( h, d[dd - 1], ll, TRUE ) - | ELSE - | | h := F( h, d[dd - 1], ll + bb, TRUE ) - | END IF. - | - | RETURN first "nn" bytes from little-endian word array h[]. - | - END FUNCTION. -*/ - -pub fn blake2s>( - mut cs: CS, - input: &[Boolean], - personalization: &[u8] -) -> Result, SynthesisError> -{ - use byteorder::{ByteOrder, LittleEndian}; - - assert_eq!(personalization.len(), 8); - assert!(input.len() % 8 == 0); - - let mut h = Vec::with_capacity(8); - h.push(UInt32::constant(0x6A09E667 ^ 0x01010000 ^ 32)); - h.push(UInt32::constant(0xBB67AE85)); - h.push(UInt32::constant(0x3C6EF372)); - h.push(UInt32::constant(0xA54FF53A)); - h.push(UInt32::constant(0x510E527F)); - h.push(UInt32::constant(0x9B05688C)); - - // Personalization is stored here - h.push(UInt32::constant(0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4]))); - h.push(UInt32::constant(0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8]))); - - let mut blocks: Vec> = vec![]; - - for block in input.chunks(512) { - let mut this_block = Vec::with_capacity(16); - for word in block.chunks(32) { - let mut tmp = word.to_vec(); - while tmp.len() < 32 { - tmp.push(Boolean::constant(false)); - } - this_block.push(UInt32::from_bits(&tmp)); - } - while this_block.len() < 16 { - this_block.push(UInt32::constant(0)); - } - blocks.push(this_block); - } - - if blocks.len() == 0 { - blocks.push((0..16).map(|_| UInt32::constant(0)).collect()); - } - - for (i, block) in blocks[0..blocks.len() - 1].iter().enumerate() { - let cs = cs.namespace(|| format!("block {}", i)); - - blake2s_compression(cs, &mut h, block, ((i as u64) + 1) * 64, false)?; - } - - { - let cs = cs.namespace(|| "final block"); - - blake2s_compression(cs, &mut h, &blocks[blocks.len() - 1], (input.len() / 8) as u64, true)?; - } - - Ok(h.iter().flat_map(|b| b.into_bits()).collect()) -} - -#[cfg(test)] -mod test { - use rand::{XorShiftRng, SeedableRng, Rng}; - use pairing::bls12_381::{Bls12}; - use ::circuit::boolean::{Boolean, AllocatedBit}; - use ::circuit::test::TestConstraintSystem; - use super::blake2s; - use bellman::{ConstraintSystem}; - use blake2_rfc::blake2s::Blake2s; - - #[test] - fn test_blank_hash() { - let mut cs = TestConstraintSystem::::new(); - let input_bits = vec![]; - let out = blake2s(&mut cs, &input_bits, b"12345678").unwrap(); - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 0); - - // >>> import blake2s from hashlib - // >>> h = blake2s(digest_size=32, person=b'12345678') - // >>> h.hexdigest() - let expected = hex!("c59f682376d137f3f255e671e207d1f2374ebe504e9314208a52d9f88d69e8c8"); - - let mut out = out.into_iter(); - for b in expected.into_iter() { - for i in 0..8 { - let c = out.next().unwrap().get_value().unwrap(); - - assert_eq!(c, (b >> i) & 1u8 == 1u8); - } - } - } - - #[test] - fn test_blake2s_constraints() { - let mut cs = TestConstraintSystem::::new(); - let input_bits: Vec<_> = (0..512).map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into()).collect(); - blake2s(&mut cs, &input_bits, b"12345678").unwrap(); - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 21518); - } - - #[test] - fn test_blake2s_precomp_constraints() { - // Test that 512 fixed leading bits (constants) - // doesn't result in more constraints. - - let mut cs = TestConstraintSystem::::new(); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - let input_bits: Vec<_> = (0..512) - .map(|_| Boolean::constant(rng.gen())) - .chain((0..512) - .map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into())) - .collect(); - blake2s(&mut cs, &input_bits, b"12345678").unwrap(); - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 21518); - } - - #[test] - fn test_blake2s_constant_constraints() { - let mut cs = TestConstraintSystem::::new(); - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - let input_bits: Vec<_> = (0..512).map(|_| Boolean::constant(rng.gen())).collect(); - blake2s(&mut cs, &input_bits, b"12345678").unwrap(); - assert_eq!(cs.num_constraints(), 0); - } - - #[test] - fn test_blake2s() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) - { - let mut h = Blake2s::with_params(32, &[], &[], b"12345678"); - - let data: Vec = (0..input_len).map(|_| rng.gen()).collect(); - - h.update(&data); - - let hash_result = h.finalize(); - - let mut cs = TestConstraintSystem::::new(); - - let mut input_bits = vec![]; - - for (byte_i, input_byte) in data.into_iter().enumerate() { - for bit_i in 0..8 { - let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i)); - - input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into()); - } - } - - let r = blake2s(&mut cs, &input_bits, b"12345678").unwrap(); - - assert!(cs.is_satisfied()); - - let mut s = hash_result.as_ref().iter() - .flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8)); - - for b in r { - match b { - Boolean::Is(b) => { - assert!(s.next().unwrap() == b.get_value().unwrap()); - }, - Boolean::Not(b) => { - assert!(s.next().unwrap() != b.get_value().unwrap()); - }, - Boolean::Constant(b) => { - assert!(input_len == 0); - assert!(s.next().unwrap() == b); - } - } - } - } - } -} diff --git a/sapling-crypto/src/circuit/ecc.rs b/sapling-crypto/src/circuit/ecc.rs deleted file mode 100644 index 71f1caa..0000000 --- a/sapling-crypto/src/circuit/ecc.rs +++ /dev/null @@ -1,1213 +0,0 @@ -use pairing::{ - Engine, - Field -}; - -use bellman::{ - SynthesisError, - ConstraintSystem -}; - -use super::{ - Assignment -}; - -use super::num::{ - AllocatedNum, - Num -}; - -use ::jubjub::{ - edwards, - JubjubEngine, - JubjubParams, - FixedGenerators -}; - -use super::lookup::{ - lookup3_xy -}; - -use super::boolean::Boolean; - -#[derive(Clone)] -pub struct EdwardsPoint { - x: AllocatedNum, - y: AllocatedNum -} - -/// Perform a fixed-base scalar multiplication with -/// `by` being in little-endian bit order. -pub fn fixed_base_multiplication( - mut cs: CS, - base: FixedGenerators, - by: &[Boolean], - params: &E::Params -) -> Result, SynthesisError> - where CS: ConstraintSystem, - E: JubjubEngine -{ - // Represents the result of the multiplication - let mut result = None; - - for (i, (chunk, window)) in by.chunks(3) - .zip(params.circuit_generators(base).iter()) - .enumerate() - { - let chunk_a = chunk.get(0).map(|e| e.clone()).unwrap_or(Boolean::constant(false)); - let chunk_b = chunk.get(1).map(|e| e.clone()).unwrap_or(Boolean::constant(false)); - let chunk_c = chunk.get(2).map(|e| e.clone()).unwrap_or(Boolean::constant(false)); - - let (x, y) = lookup3_xy( - cs.namespace(|| format!("window table lookup {}", i)), - &[chunk_a, chunk_b, chunk_c], - window - )?; - - let p = EdwardsPoint { - x: x, - y: y - }; - - if result.is_none() { - result = Some(p); - } else { - result = Some(result.unwrap().add( - cs.namespace(|| format!("addition {}", i)), - &p, - params - )?); - } - } - - Ok(result.get()?.clone()) -} - -impl EdwardsPoint { - pub fn get_x(&self) -> &AllocatedNum { - &self.x - } - - pub fn get_y(&self) -> &AllocatedNum { - &self.y - } - - pub fn assert_not_small_order( - &self, - mut cs: CS, - params: &E::Params - ) -> Result<(), SynthesisError> - where CS: ConstraintSystem - { - let tmp = self.double( - cs.namespace(|| "first doubling"), - params - )?; - let tmp = tmp.double( - cs.namespace(|| "second doubling"), - params - )?; - let tmp = tmp.double( - cs.namespace(|| "third doubling"), - params - )?; - - // (0, -1) is a small order point, but won't ever appear here - // because cofactor is 2^3, and we performed three doublings. - // (0, 1) is the neutral element, so checking if x is nonzero - // is sufficient to prevent small order points here. - tmp.x.assert_nonzero(cs.namespace(|| "check x != 0"))?; - - Ok(()) - } - - pub fn inputize( - &self, - mut cs: CS - ) -> Result<(), SynthesisError> - where CS: ConstraintSystem - { - self.x.inputize(cs.namespace(|| "x"))?; - self.y.inputize(cs.namespace(|| "y"))?; - - Ok(()) - } - - /// This converts the point into a representation. - pub fn repr( - &self, - mut cs: CS - ) -> Result, SynthesisError> - where CS: ConstraintSystem - { - let mut tmp = vec![]; - - let x = self.x.into_bits_le_strict( - cs.namespace(|| "unpack x") - )?; - - let y = self.y.into_bits_le_strict( - cs.namespace(|| "unpack y") - )?; - - tmp.extend(y); - tmp.push(x[0].clone()); - - Ok(tmp) - } - - /// This 'witnesses' a point inside the constraint system. - /// It guarantees the point is on the curve. - pub fn witness( - mut cs: CS, - p: Option>, - params: &E::Params - ) -> Result - where CS: ConstraintSystem - { - let p = p.map(|p| p.into_xy()); - - // Allocate x - let x = AllocatedNum::alloc( - cs.namespace(|| "x"), - || { - Ok(p.get()?.0) - } - )?; - - // Allocate y - let y = AllocatedNum::alloc( - cs.namespace(|| "y"), - || { - Ok(p.get()?.1) - } - )?; - - Self::interpret( - cs.namespace(|| "point interpretation"), - &x, - &y, - params - ) - } - - /// Returns `self` if condition is true, and the neutral - /// element (0, 1) otherwise. - pub fn conditionally_select( - &self, - mut cs: CS, - condition: &Boolean - ) -> Result - where CS: ConstraintSystem - { - // Compute x' = self.x if condition, and 0 otherwise - let x_prime = AllocatedNum::alloc(cs.namespace(|| "x'"), || { - if *condition.get_value().get()? { - Ok(*self.x.get_value().get()?) - } else { - Ok(E::Fr::zero()) - } - })?; - - // condition * x = x' - // if condition is 0, x' must be 0 - // if condition is 1, x' must be x - let one = CS::one(); - cs.enforce( - || "x' computation", - |lc| lc + self.x.get_variable(), - |_| condition.lc(one, E::Fr::one()), - |lc| lc + x_prime.get_variable() - ); - - // Compute y' = self.y if condition, and 1 otherwise - let y_prime = AllocatedNum::alloc(cs.namespace(|| "y'"), || { - if *condition.get_value().get()? { - Ok(*self.y.get_value().get()?) - } else { - Ok(E::Fr::one()) - } - })?; - - // condition * y = y' - (1 - condition) - // if condition is 0, y' must be 1 - // if condition is 1, y' must be y - cs.enforce( - || "y' computation", - |lc| lc + self.y.get_variable(), - |_| condition.lc(one, E::Fr::one()), - |lc| lc + y_prime.get_variable() - - &condition.not().lc(one, E::Fr::one()) - ); - - Ok(EdwardsPoint { - x: x_prime, - y: y_prime - }) - } - - /// Performs a scalar multiplication of this twisted Edwards - /// point by a scalar represented as a sequence of booleans - /// in little-endian bit order. - pub fn mul( - &self, - mut cs: CS, - by: &[Boolean], - params: &E::Params - ) -> Result - where CS: ConstraintSystem - { - // Represents the current "magnitude" of the base - // that we're operating over. Starts at self, - // then 2*self, then 4*self, ... - let mut curbase = None; - - // Represents the result of the multiplication - let mut result = None; - - for (i, bit) in by.iter().enumerate() { - if curbase.is_none() { - curbase = Some(self.clone()); - } else { - // Double the previous value - curbase = Some( - curbase.unwrap() - .double(cs.namespace(|| format!("doubling {}", i)), params)? - ); - } - - // Represents the select base. If the bit for this magnitude - // is true, this will return `curbase`. Otherwise it will - // return the neutral element, which will have no effect on - // the result. - let thisbase = curbase.as_ref() - .unwrap() - .conditionally_select( - cs.namespace(|| format!("selection {}", i)), - bit - )?; - - if result.is_none() { - result = Some(thisbase); - } else { - result = Some(result.unwrap().add( - cs.namespace(|| format!("addition {}", i)), - &thisbase, - params - )?); - } - } - - Ok(result.get()?.clone()) - } - - pub fn interpret( - mut cs: CS, - x: &AllocatedNum, - y: &AllocatedNum, - params: &E::Params - ) -> Result - where CS: ConstraintSystem - { - // -x^2 + y^2 = 1 + dx^2y^2 - - let x2 = x.square(cs.namespace(|| "x^2"))?; - let y2 = y.square(cs.namespace(|| "y^2"))?; - let x2y2 = x2.mul(cs.namespace(|| "x^2 y^2"), &y2)?; - - let one = CS::one(); - cs.enforce( - || "on curve check", - |lc| lc - x2.get_variable() - + y2.get_variable(), - |lc| lc + one, - |lc| lc + one - + (*params.edwards_d(), x2y2.get_variable()) - ); - - Ok(EdwardsPoint { - x: x.clone(), - y: y.clone() - }) - } - - pub fn double( - &self, - mut cs: CS, - params: &E::Params - ) -> Result - where CS: ConstraintSystem - { - // Compute T = (x1 + y1) * (x1 + y1) - let t = AllocatedNum::alloc(cs.namespace(|| "T"), || { - let mut t0 = *self.x.get_value().get()?; - t0.add_assign(self.y.get_value().get()?); - - let mut t1 = *self.x.get_value().get()?; - t1.add_assign(self.y.get_value().get()?); - - t0.mul_assign(&t1); - - Ok(t0) - })?; - - cs.enforce( - || "T computation", - |lc| lc + self.x.get_variable() - + self.y.get_variable(), - |lc| lc + self.x.get_variable() - + self.y.get_variable(), - |lc| lc + t.get_variable() - ); - - // Compute A = x1 * y1 - let a = self.x.mul(cs.namespace(|| "A computation"), &self.y)?; - - // Compute C = d*A*A - let c = AllocatedNum::alloc(cs.namespace(|| "C"), || { - let mut t0 = *a.get_value().get()?; - t0.square(); - t0.mul_assign(params.edwards_d()); - - Ok(t0) - })?; - - cs.enforce( - || "C computation", - |lc| lc + (*params.edwards_d(), a.get_variable()), - |lc| lc + a.get_variable(), - |lc| lc + c.get_variable() - ); - - // Compute x3 = (2.A) / (1 + C) - let x3 = AllocatedNum::alloc(cs.namespace(|| "x3"), || { - let mut t0 = *a.get_value().get()?; - t0.double(); - - let mut t1 = E::Fr::one(); - t1.add_assign(c.get_value().get()?); - - match t1.inverse() { - Some(t1) => { - t0.mul_assign(&t1); - - Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) - } - } - })?; - - let one = CS::one(); - cs.enforce( - || "x3 computation", - |lc| lc + one + c.get_variable(), - |lc| lc + x3.get_variable(), - |lc| lc + a.get_variable() - + a.get_variable() - ); - - // Compute y3 = (U - 2.A) / (1 - C) - let y3 = AllocatedNum::alloc(cs.namespace(|| "y3"), || { - let mut t0 = *a.get_value().get()?; - t0.double(); - t0.negate(); - t0.add_assign(t.get_value().get()?); - - let mut t1 = E::Fr::one(); - t1.sub_assign(c.get_value().get()?); - - match t1.inverse() { - Some(t1) => { - t0.mul_assign(&t1); - - Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) - } - } - })?; - - cs.enforce( - || "y3 computation", - |lc| lc + one - c.get_variable(), - |lc| lc + y3.get_variable(), - |lc| lc + t.get_variable() - - a.get_variable() - - a.get_variable() - ); - - Ok(EdwardsPoint { - x: x3, - y: y3 - }) - } - - /// Perform addition between any two points - pub fn add( - &self, - mut cs: CS, - other: &Self, - params: &E::Params - ) -> Result - where CS: ConstraintSystem - { - // Compute U = (x1 + y1) * (x2 + y2) - let u = AllocatedNum::alloc(cs.namespace(|| "U"), || { - let mut t0 = *self.x.get_value().get()?; - t0.add_assign(self.y.get_value().get()?); - - let mut t1 = *other.x.get_value().get()?; - t1.add_assign(other.y.get_value().get()?); - - t0.mul_assign(&t1); - - Ok(t0) - })?; - - cs.enforce( - || "U computation", - |lc| lc + self.x.get_variable() - + self.y.get_variable(), - |lc| lc + other.x.get_variable() - + other.y.get_variable(), - |lc| lc + u.get_variable() - ); - - // Compute A = y2 * x1 - let a = other.y.mul(cs.namespace(|| "A computation"), &self.x)?; - - // Compute B = x2 * y1 - let b = other.x.mul(cs.namespace(|| "B computation"), &self.y)?; - - // Compute C = d*A*B - let c = AllocatedNum::alloc(cs.namespace(|| "C"), || { - let mut t0 = *a.get_value().get()?; - t0.mul_assign(b.get_value().get()?); - t0.mul_assign(params.edwards_d()); - - Ok(t0) - })?; - - cs.enforce( - || "C computation", - |lc| lc + (*params.edwards_d(), a.get_variable()), - |lc| lc + b.get_variable(), - |lc| lc + c.get_variable() - ); - - // Compute x3 = (A + B) / (1 + C) - let x3 = AllocatedNum::alloc(cs.namespace(|| "x3"), || { - let mut t0 = *a.get_value().get()?; - t0.add_assign(b.get_value().get()?); - - let mut t1 = E::Fr::one(); - t1.add_assign(c.get_value().get()?); - - match t1.inverse() { - Some(t1) => { - t0.mul_assign(&t1); - - Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) - } - } - })?; - - let one = CS::one(); - cs.enforce( - || "x3 computation", - |lc| lc + one + c.get_variable(), - |lc| lc + x3.get_variable(), - |lc| lc + a.get_variable() - + b.get_variable() - ); - - // Compute y3 = (U - A - B) / (1 - C) - let y3 = AllocatedNum::alloc(cs.namespace(|| "y3"), || { - let mut t0 = *u.get_value().get()?; - t0.sub_assign(a.get_value().get()?); - t0.sub_assign(b.get_value().get()?); - - let mut t1 = E::Fr::one(); - t1.sub_assign(c.get_value().get()?); - - match t1.inverse() { - Some(t1) => { - t0.mul_assign(&t1); - - Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) - } - } - })?; - - cs.enforce( - || "y3 computation", - |lc| lc + one - c.get_variable(), - |lc| lc + y3.get_variable(), - |lc| lc + u.get_variable() - - a.get_variable() - - b.get_variable() - ); - - Ok(EdwardsPoint { - x: x3, - y: y3 - }) - } -} - -pub struct MontgomeryPoint { - x: Num, - y: Num -} - -impl MontgomeryPoint { - /// Converts an element in the prime order subgroup into - /// a point in the birationally equivalent twisted - /// Edwards curve. - pub fn into_edwards( - &self, - mut cs: CS, - params: &E::Params - ) -> Result, SynthesisError> - where CS: ConstraintSystem - { - // Compute u = (scale*x) / y - let u = AllocatedNum::alloc(cs.namespace(|| "u"), || { - let mut t0 = *self.x.get_value().get()?; - t0.mul_assign(params.scale()); - - match self.y.get_value().get()?.inverse() { - Some(invy) => { - t0.mul_assign(&invy); - - Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) - } - } - })?; - - cs.enforce( - || "u computation", - |lc| lc + &self.y.lc(E::Fr::one()), - |lc| lc + u.get_variable(), - |lc| lc + &self.x.lc(*params.scale()) - ); - - // Compute v = (x - 1) / (x + 1) - let v = AllocatedNum::alloc(cs.namespace(|| "v"), || { - let mut t0 = *self.x.get_value().get()?; - let mut t1 = t0; - t0.sub_assign(&E::Fr::one()); - t1.add_assign(&E::Fr::one()); - - match t1.inverse() { - Some(t1) => { - t0.mul_assign(&t1); - - Ok(t0) - }, - None => { - Err(SynthesisError::DivisionByZero) - } - } - })?; - - let one = CS::one(); - cs.enforce( - || "v computation", - |lc| lc + &self.x.lc(E::Fr::one()) - + one, - |lc| lc + v.get_variable(), - |lc| lc + &self.x.lc(E::Fr::one()) - - one, - ); - - Ok(EdwardsPoint { - x: u, - y: v - }) - } - - /// Interprets an (x, y) pair as a point - /// in Montgomery, does not check that it's - /// on the curve. Useful for constants and - /// window table lookups. - pub fn interpret_unchecked( - x: Num, - y: Num - ) -> Self - { - MontgomeryPoint { - x: x, - y: y - } - } - - /// Performs an affine point addition, not defined for - /// coincident points. - pub fn add( - &self, - mut cs: CS, - other: &Self, - params: &E::Params - ) -> Result - where CS: ConstraintSystem - { - // Compute lambda = (y' - y) / (x' - x) - let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || { - let mut n = *other.y.get_value().get()?; - n.sub_assign(self.y.get_value().get()?); - - let mut d = *other.x.get_value().get()?; - d.sub_assign(self.x.get_value().get()?); - - match d.inverse() { - Some(d) => { - n.mul_assign(&d); - Ok(n) - }, - None => { - Err(SynthesisError::DivisionByZero) - } - } - })?; - - cs.enforce( - || "evaluate lambda", - |lc| lc + &other.x.lc(E::Fr::one()) - - &self.x.lc(E::Fr::one()), - - |lc| lc + lambda.get_variable(), - - |lc| lc + &other.y.lc(E::Fr::one()) - - &self.y.lc(E::Fr::one()) - ); - - // Compute x'' = lambda^2 - A - x - x' - let xprime = AllocatedNum::alloc(cs.namespace(|| "xprime"), || { - let mut t0 = *lambda.get_value().get()?; - t0.square(); - t0.sub_assign(params.montgomery_a()); - t0.sub_assign(self.x.get_value().get()?); - t0.sub_assign(other.x.get_value().get()?); - - Ok(t0) - })?; - - // (lambda) * (lambda) = (A + x + x' + x'') - let one = CS::one(); - cs.enforce( - || "evaluate xprime", - |lc| lc + lambda.get_variable(), - |lc| lc + lambda.get_variable(), - |lc| lc + (*params.montgomery_a(), one) - + &self.x.lc(E::Fr::one()) - + &other.x.lc(E::Fr::one()) - + xprime.get_variable() - ); - - // Compute y' = -(y + lambda(x' - x)) - let yprime = AllocatedNum::alloc(cs.namespace(|| "yprime"), || { - let mut t0 = *xprime.get_value().get()?; - t0.sub_assign(self.x.get_value().get()?); - t0.mul_assign(lambda.get_value().get()?); - t0.add_assign(self.y.get_value().get()?); - t0.negate(); - - Ok(t0) - })?; - - // y' + y = lambda(x - x') - cs.enforce( - || "evaluate yprime", - |lc| lc + &self.x.lc(E::Fr::one()) - - xprime.get_variable(), - - |lc| lc + lambda.get_variable(), - - |lc| lc + yprime.get_variable() - + &self.y.lc(E::Fr::one()) - ); - - Ok(MontgomeryPoint { - x: xprime.into(), - y: yprime.into() - }) - } -} - -#[cfg(test)] -mod test { - use bellman::{ConstraintSystem}; - use rand::{XorShiftRng, SeedableRng, Rand, Rng}; - use pairing::bls12_381::{Bls12, Fr}; - use pairing::{BitIterator, Field, PrimeField}; - use ::circuit::test::*; - use ::jubjub::{ - montgomery, - edwards, - JubjubBls12, - JubjubParams, - FixedGenerators - }; - use ::jubjub::fs::Fs; - use super::{ - MontgomeryPoint, - EdwardsPoint, - AllocatedNum, - fixed_base_multiplication - }; - use super::super::boolean::{ - Boolean, - AllocatedBit - }; - - #[test] - fn test_into_edwards() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let mut cs = TestConstraintSystem::::new(); - - let p = montgomery::Point::::rand(rng, params); - let (u, v) = edwards::Point::from_montgomery(&p, params).into_xy(); - let (x, y) = p.into_xy().unwrap(); - - let numx = AllocatedNum::alloc(cs.namespace(|| "mont x"), || { - Ok(x) - }).unwrap(); - let numy = AllocatedNum::alloc(cs.namespace(|| "mont y"), || { - Ok(y) - }).unwrap(); - - let p = MontgomeryPoint::interpret_unchecked(numx.into(), numy.into()); - - let q = p.into_edwards(&mut cs, params).unwrap(); - - assert!(cs.is_satisfied()); - assert!(q.x.get_value().unwrap() == u); - assert!(q.y.get_value().unwrap() == v); - - cs.set("u/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "u computation"); - cs.set("u/num", u); - assert!(cs.is_satisfied()); - - cs.set("v/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "v computation"); - cs.set("v/num", v); - assert!(cs.is_satisfied()); - } - } - - #[test] - fn test_interpret() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let p = edwards::Point::::rand(rng, ¶ms); - - let mut cs = TestConstraintSystem::::new(); - let q = EdwardsPoint::witness( - &mut cs, - Some(p.clone()), - ¶ms - ).unwrap(); - - let p = p.into_xy(); - - assert!(cs.is_satisfied()); - assert_eq!(q.x.get_value().unwrap(), p.0); - assert_eq!(q.y.get_value().unwrap(), p.1); - } - - for _ in 0..100 { - let p = edwards::Point::::rand(rng, ¶ms); - let (x, y) = p.into_xy(); - - let mut cs = TestConstraintSystem::::new(); - let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || { - Ok(x) - }).unwrap(); - let numy = AllocatedNum::alloc(cs.namespace(|| "y"), || { - Ok(y) - }).unwrap(); - - let p = EdwardsPoint::interpret(&mut cs, &numx, &numy, ¶ms).unwrap(); - - assert!(cs.is_satisfied()); - assert_eq!(p.x.get_value().unwrap(), x); - assert_eq!(p.y.get_value().unwrap(), y); - } - - // Random (x, y) are unlikely to be on the curve. - for _ in 0..100 { - let x = rng.gen(); - let y = rng.gen(); - - let mut cs = TestConstraintSystem::::new(); - let numx = AllocatedNum::alloc(cs.namespace(|| "x"), || { - Ok(x) - }).unwrap(); - let numy = AllocatedNum::alloc(cs.namespace(|| "y"), || { - Ok(y) - }).unwrap(); - - EdwardsPoint::interpret(&mut cs, &numx, &numy, ¶ms).unwrap(); - - assert_eq!(cs.which_is_unsatisfied().unwrap(), "on curve check"); - } - } - - #[test] - fn test_edwards_fixed_base_multiplication() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let mut cs = TestConstraintSystem::::new(); - - let p = params.generator(FixedGenerators::NoteCommitmentRandomness); - let s = Fs::rand(rng); - let q = p.mul(s, params); - let (x1, y1) = q.into_xy(); - - let mut s_bits = BitIterator::new(s.into_repr()).collect::>(); - s_bits.reverse(); - s_bits.truncate(Fs::NUM_BITS as usize); - - let s_bits = s_bits.into_iter() - .enumerate() - .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("scalar bit {}", i)), Some(b)).unwrap()) - .map(|v| Boolean::from(v)) - .collect::>(); - - let q = fixed_base_multiplication( - cs.namespace(|| "multiplication"), - FixedGenerators::NoteCommitmentRandomness, - &s_bits, - params - ).unwrap(); - - assert_eq!(q.x.get_value().unwrap(), x1); - assert_eq!(q.y.get_value().unwrap(), y1); - } - } - - #[test] - fn test_edwards_multiplication() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let mut cs = TestConstraintSystem::::new(); - - let p = edwards::Point::::rand(rng, params); - let s = Fs::rand(rng); - let q = p.mul(s, params); - - let (x0, y0) = p.into_xy(); - let (x1, y1) = q.into_xy(); - - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || { - Ok(x0) - }).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || { - Ok(y0) - }).unwrap(); - - let p = EdwardsPoint { - x: num_x0, - y: num_y0 - }; - - let mut s_bits = BitIterator::new(s.into_repr()).collect::>(); - s_bits.reverse(); - s_bits.truncate(Fs::NUM_BITS as usize); - - let s_bits = s_bits.into_iter() - .enumerate() - .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("scalar bit {}", i)), Some(b)).unwrap()) - .map(|v| Boolean::from(v)) - .collect::>(); - - let q = p.mul( - cs.namespace(|| "scalar mul"), - &s_bits, - params - ).unwrap(); - - assert!(cs.is_satisfied()); - - assert_eq!( - q.x.get_value().unwrap(), - x1 - ); - - assert_eq!( - q.y.get_value().unwrap(), - y1 - ); - } - } - - #[test] - fn test_conditionally_select() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let mut cs = TestConstraintSystem::::new(); - - let p = edwards::Point::::rand(rng, params); - - let (x0, y0) = p.into_xy(); - - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || { - Ok(x0) - }).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || { - Ok(y0) - }).unwrap(); - - let p = EdwardsPoint { - x: num_x0, - y: num_y0 - }; - - let mut should_we_select = rng.gen(); - - // Conditionally allocate - let mut b = if rng.gen() { - Boolean::from(AllocatedBit::alloc( - cs.namespace(|| "condition"), - Some(should_we_select) - ).unwrap()) - } else { - Boolean::constant(should_we_select) - }; - - // Conditionally negate - if rng.gen() { - b = b.not(); - should_we_select = !should_we_select; - } - - let q = p.conditionally_select(cs.namespace(|| "select"), &b).unwrap(); - - assert!(cs.is_satisfied()); - - if should_we_select { - assert_eq!(q.x.get_value().unwrap(), x0); - assert_eq!(q.y.get_value().unwrap(), y0); - - cs.set("select/y'/num", Fr::one()); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/y' computation"); - cs.set("select/x'/num", Fr::zero()); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/x' computation"); - } else { - assert_eq!(q.x.get_value().unwrap(), Fr::zero()); - assert_eq!(q.y.get_value().unwrap(), Fr::one()); - - cs.set("select/y'/num", x0); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/y' computation"); - cs.set("select/x'/num", y0); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/x' computation"); - } - } - } - - #[test] - fn test_edwards_addition() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let p1 = edwards::Point::::rand(rng, params); - let p2 = edwards::Point::::rand(rng, params); - - let p3 = p1.add(&p2, params); - - let (x0, y0) = p1.into_xy(); - let (x1, y1) = p2.into_xy(); - let (x2, y2) = p3.into_xy(); - - let mut cs = TestConstraintSystem::::new(); - - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || { - Ok(x0) - }).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || { - Ok(y0) - }).unwrap(); - - let num_x1 = AllocatedNum::alloc(cs.namespace(|| "x1"), || { - Ok(x1) - }).unwrap(); - let num_y1 = AllocatedNum::alloc(cs.namespace(|| "y1"), || { - Ok(y1) - }).unwrap(); - - let p1 = EdwardsPoint { - x: num_x0, - y: num_y0 - }; - - let p2 = EdwardsPoint { - x: num_x1, - y: num_y1 - }; - - let p3 = p1.add(cs.namespace(|| "addition"), &p2, params).unwrap(); - - assert!(cs.is_satisfied()); - - assert!(p3.x.get_value().unwrap() == x2); - assert!(p3.y.get_value().unwrap() == y2); - - let u = cs.get("addition/U/num"); - cs.set("addition/U/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/U computation")); - cs.set("addition/U/num", u); - assert!(cs.is_satisfied()); - - let x3 = cs.get("addition/x3/num"); - cs.set("addition/x3/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/x3 computation")); - cs.set("addition/x3/num", x3); - assert!(cs.is_satisfied()); - - let y3 = cs.get("addition/y3/num"); - cs.set("addition/y3/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/y3 computation")); - cs.set("addition/y3/num", y3); - assert!(cs.is_satisfied()); - } - } - - #[test] - fn test_edwards_doubling() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let p1 = edwards::Point::::rand(rng, params); - let p2 = p1.double(params); - - let (x0, y0) = p1.into_xy(); - let (x1, y1) = p2.into_xy(); - - let mut cs = TestConstraintSystem::::new(); - - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || { - Ok(x0) - }).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || { - Ok(y0) - }).unwrap(); - - let p1 = EdwardsPoint { - x: num_x0, - y: num_y0 - }; - - let p2 = p1.double(cs.namespace(|| "doubling"), params).unwrap(); - - assert!(cs.is_satisfied()); - - assert!(p2.x.get_value().unwrap() == x1); - assert!(p2.y.get_value().unwrap() == y1); - } - } - - #[test] - fn test_montgomery_addition() { - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let p1 = loop { - let x: Fr = rng.gen(); - let s: bool = rng.gen(); - - if let Some(p) = montgomery::Point::::get_for_x(x, s, params) { - break p; - } - }; - - let p2 = loop { - let x: Fr = rng.gen(); - let s: bool = rng.gen(); - - if let Some(p) = montgomery::Point::::get_for_x(x, s, params) { - break p; - } - }; - - let p3 = p1.add(&p2, params); - - let (x0, y0) = p1.into_xy().unwrap(); - let (x1, y1) = p2.into_xy().unwrap(); - let (x2, y2) = p3.into_xy().unwrap(); - - let mut cs = TestConstraintSystem::::new(); - - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || { - Ok(x0) - }).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || { - Ok(y0) - }).unwrap(); - - let num_x1 = AllocatedNum::alloc(cs.namespace(|| "x1"), || { - Ok(x1) - }).unwrap(); - let num_y1 = AllocatedNum::alloc(cs.namespace(|| "y1"), || { - Ok(y1) - }).unwrap(); - - let p1 = MontgomeryPoint { - x: num_x0.into(), - y: num_y0.into() - }; - - let p2 = MontgomeryPoint { - x: num_x1.into(), - y: num_y1.into() - }; - - let p3 = p1.add(cs.namespace(|| "addition"), &p2, params).unwrap(); - - assert!(cs.is_satisfied()); - - assert!(p3.x.get_value().unwrap() == x2); - assert!(p3.y.get_value().unwrap() == y2); - - cs.set("addition/yprime/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate yprime")); - cs.set("addition/yprime/num", y2); - assert!(cs.is_satisfied()); - - cs.set("addition/xprime/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate xprime")); - cs.set("addition/xprime/num", x2); - assert!(cs.is_satisfied()); - - cs.set("addition/lambda/num", rng.gen()); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate lambda")); - } - } -} diff --git a/sapling-crypto/src/circuit/multipack.rs b/sapling-crypto/src/circuit/multipack.rs deleted file mode 100644 index 54d4138..0000000 --- a/sapling-crypto/src/circuit/multipack.rs +++ /dev/null @@ -1,113 +0,0 @@ -use pairing::{Engine, Field, PrimeField}; -use bellman::{ConstraintSystem, SynthesisError}; -use super::boolean::{Boolean}; -use super::num::Num; -use super::Assignment; - -/// Takes a sequence of booleans and exposes them as compact -/// public inputs -pub fn pack_into_inputs( - mut cs: CS, - bits: &[Boolean] -) -> Result<(), SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() - { - let mut num = Num::::zero(); - let mut coeff = E::Fr::one(); - for bit in bits { - num = num.add_bool_with_coeff(CS::one(), bit, coeff); - - coeff.double(); - } - - let input = cs.alloc_input(|| format!("input {}", i), || { - Ok(*num.get_value().get()?) - })?; - - // num * 1 = input - cs.enforce( - || format!("packing constraint {}", i), - |_| num.lc(E::Fr::one()), - |lc| lc + CS::one(), - |lc| lc + input - ); - } - - Ok(()) -} - -pub fn bytes_to_bits(bytes: &[u8]) -> Vec -{ - bytes.iter() - .flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1)) - .collect() -} - -pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec -{ - bytes.iter() - .flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1)) - .collect() -} - -pub fn compute_multipacking( - bits: &[bool] -) -> Vec -{ - let mut result = vec![]; - - for bits in bits.chunks(E::Fr::CAPACITY as usize) - { - let mut cur = E::Fr::zero(); - let mut coeff = E::Fr::one(); - - for bit in bits { - if *bit { - cur.add_assign(&coeff); - } - - coeff.double(); - } - - result.push(cur); - } - - result -} - -#[test] -fn test_multipacking() { - use rand::{SeedableRng, Rng, XorShiftRng}; - use bellman::{ConstraintSystem}; - use pairing::bls12_381::{Bls12}; - use ::circuit::test::*; - use super::boolean::{AllocatedBit, Boolean}; - - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for num_bits in 0..1500 { - let mut cs = TestConstraintSystem::::new(); - - let bits: Vec = (0..num_bits).map(|_| rng.gen()).collect(); - - let circuit_bits = bits.iter().enumerate() - .map(|(i, &b)| { - Boolean::from( - AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - Some(b) - ).unwrap() - ) - }) - .collect::>(); - - let expected_inputs = compute_multipacking::(&bits); - - pack_into_inputs(cs.namespace(|| "pack"), &circuit_bits).unwrap(); - - assert!(cs.is_satisfied()); - assert!(cs.verify(&expected_inputs)); - } -} diff --git a/sapling-crypto/src/circuit/pedersen_hash.rs b/sapling-crypto/src/circuit/pedersen_hash.rs deleted file mode 100644 index eb1745f..0000000 --- a/sapling-crypto/src/circuit/pedersen_hash.rs +++ /dev/null @@ -1,194 +0,0 @@ -use super::*; -use super::ecc::{ - MontgomeryPoint, - EdwardsPoint -}; -use super::boolean::Boolean; -use ::jubjub::*; -use bellman::{ - ConstraintSystem -}; -use super::lookup::*; -pub use pedersen_hash::Personalization; - -impl Personalization { - fn get_constant_bools(&self) -> Vec { - self.get_bits() - .into_iter() - .map(|e| Boolean::constant(e)) - .collect() - } -} - -pub fn pedersen_hash( - mut cs: CS, - personalization: Personalization, - bits: &[Boolean], - params: &E::Params -) -> Result, SynthesisError> - where CS: ConstraintSystem -{ - let personalization = personalization.get_constant_bools(); - assert_eq!(personalization.len(), 6); - - let mut edwards_result = None; - let mut bits = personalization.iter().chain(bits.iter()); - let mut segment_generators = params.pedersen_circuit_generators().iter(); - let boolean_false = Boolean::constant(false); - - let mut segment_i = 0; - loop { - let mut segment_result = None; - let mut segment_windows = &segment_generators.next() - .expect("enough segments")[..]; - - let mut window_i = 0; - while let Some(a) = bits.next() { - let b = bits.next().unwrap_or(&boolean_false); - let c = bits.next().unwrap_or(&boolean_false); - - let tmp = lookup3_xy_with_conditional_negation( - cs.namespace(|| format!("segment {}, window {}", segment_i, window_i)), - &[a.clone(), b.clone(), c.clone()], - &segment_windows[0] - )?; - - let tmp = MontgomeryPoint::interpret_unchecked(tmp.0, tmp.1); - - match segment_result { - None => { - segment_result = Some(tmp); - }, - Some(ref mut segment_result) => { - *segment_result = tmp.add( - cs.namespace(|| format!("addition of segment {}, window {}", segment_i, window_i)), - segment_result, - params - )?; - } - } - - segment_windows = &segment_windows[1..]; - - if segment_windows.len() == 0 { - break; - } - - window_i += 1; - } - - match segment_result { - Some(segment_result) => { - // Convert this segment into twisted Edwards form. - let segment_result = segment_result.into_edwards( - cs.namespace(|| format!("conversion of segment {} into edwards", segment_i)), - params - )?; - - match edwards_result { - Some(ref mut edwards_result) => { - *edwards_result = segment_result.add( - cs.namespace(|| format!("addition of segment {} to accumulator", segment_i)), - edwards_result, - params - )?; - }, - None => { - edwards_result = Some(segment_result); - } - } - }, - None => { - // We didn't process any new bits. - break; - } - } - - segment_i += 1; - } - - Ok(edwards_result.unwrap()) -} - -#[cfg(test)] -mod test { - use rand::{SeedableRng, Rng, XorShiftRng}; - use super::*; - use ::circuit::test::*; - use ::circuit::boolean::{Boolean, AllocatedBit}; - use pairing::bls12_381::{Bls12, Fr}; - use pairing::PrimeField; - - #[test] - fn test_pedersen_hash_constraints() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - let params = &JubjubBls12::new(); - let mut cs = TestConstraintSystem::::new(); - - let input: Vec = (0..(Fr::NUM_BITS * 2)).map(|_| rng.gen()).collect(); - - let input_bools: Vec = input.iter().enumerate().map(|(i, b)| { - Boolean::from( - AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap() - ) - }).collect(); - - pedersen_hash( - cs.namespace(|| "pedersen hash"), - Personalization::NoteCommitment, - &input_bools, - params - ).unwrap(); - - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 1377); - } - - #[test] - fn test_pedersen_hash() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - let params = &JubjubBls12::new(); - - for length in 0..751 { - for _ in 0..5 { - let mut input: Vec = (0..length).map(|_| rng.gen()).collect(); - - let mut cs = TestConstraintSystem::::new(); - - let input_bools: Vec = input.iter().enumerate().map(|(i, b)| { - Boolean::from( - AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap() - ) - }).collect(); - - let res = pedersen_hash( - cs.namespace(|| "pedersen hash"), - Personalization::MerkleTree(1), - &input_bools, - params - ).unwrap(); - - assert!(cs.is_satisfied()); - - let expected = ::pedersen_hash::pedersen_hash::( - Personalization::MerkleTree(1), - input.clone().into_iter(), - params - ).into_xy(); - - assert_eq!(res.get_x().get_value().unwrap(), expected.0); - assert_eq!(res.get_y().get_value().unwrap(), expected.1); - - // Test against the output of a different personalization - let unexpected = ::pedersen_hash::pedersen_hash::( - Personalization::MerkleTree(0), - input.into_iter(), - params - ).into_xy(); - - assert!(res.get_x().get_value().unwrap() != unexpected.0); - assert!(res.get_y().get_value().unwrap() != unexpected.1); - } - } - } -} diff --git a/sapling-crypto/src/circuit/sapling/mod.rs b/sapling-crypto/src/circuit/sapling/mod.rs deleted file mode 100644 index 650e162..0000000 --- a/sapling-crypto/src/circuit/sapling/mod.rs +++ /dev/null @@ -1,817 +0,0 @@ -use pairing::{ - PrimeField, - PrimeFieldRepr, - Field, -}; - -use bellman::{ - SynthesisError, - ConstraintSystem, - Circuit -}; - -use jubjub::{ - JubjubEngine, - FixedGenerators -}; - -use constants; - -use primitives::{ - ValueCommitment, - ProofGenerationKey, - PaymentAddress -}; - -use super::Assignment; -use super::boolean; -use super::ecc; -use super::pedersen_hash; -use super::blake2s; -use super::num; -use super::multipack; - -pub const TREE_DEPTH: usize = 32; - -/// This is an instance of the `Spend` circuit. -pub struct Spend<'a, E: JubjubEngine> { - pub params: &'a E::Params, - - /// Pedersen commitment to the value being spent - pub value_commitment: Option>, - - /// Key required to construct proofs for spending notes - /// for a particular spending key - pub proof_generation_key: Option>, - - /// The payment address associated with the note - pub payment_address: Option>, - - /// The randomness of the note commitment - pub commitment_randomness: Option, - - /// Re-randomization of the public key - pub ar: Option, - - /// The authentication path of the commitment in the tree - pub auth_path: Vec>, - - /// The anchor; the root of the tree. If the note being - /// spent is zero-value, this can be anything. - pub anchor: Option -} - -/// This is an output circuit instance. -pub struct Output<'a, E: JubjubEngine> { - pub params: &'a E::Params, - - /// Pedersen commitment to the value being spent - pub value_commitment: Option>, - - /// The payment address of the recipient - pub payment_address: Option>, - - /// The randomness used to hide the note commitment data - pub commitment_randomness: Option, - - /// The ephemeral secret key for DH with recipient - pub esk: Option -} - -/// Exposes a Pedersen commitment to the value as an -/// input to the circuit -fn expose_value_commitment( - mut cs: CS, - value_commitment: Option>, - params: &E::Params -) -> Result, SynthesisError> - where E: JubjubEngine, - CS: ConstraintSystem -{ - // Booleanize the value into little-endian bit order - let value_bits = boolean::u64_into_boolean_vec_le( - cs.namespace(|| "value"), - value_commitment.as_ref().map(|c| c.value) - )?; - - // Compute the note value in the exponent - let value = ecc::fixed_base_multiplication( - cs.namespace(|| "compute the value in the exponent"), - FixedGenerators::ValueCommitmentValue, - &value_bits, - params - )?; - - // Booleanize the randomness. This does not ensure - // the bit representation is "in the field" because - // it doesn't matter for security. - let rcv = boolean::field_into_boolean_vec_le( - cs.namespace(|| "rcv"), - value_commitment.as_ref().map(|c| c.randomness) - )?; - - // Compute the randomness in the exponent - let rcv = ecc::fixed_base_multiplication( - cs.namespace(|| "computation of rcv"), - FixedGenerators::ValueCommitmentRandomness, - &rcv, - params - )?; - - // Compute the Pedersen commitment to the value - let cv = value.add( - cs.namespace(|| "computation of cv"), - &rcv, - params - )?; - - // Expose the commitment as an input to the circuit - cv.inputize(cs.namespace(|| "commitment point"))?; - - Ok(value_bits) -} - -impl<'a, E: JubjubEngine> Circuit for Spend<'a, E> { - fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> - { - // Prover witnesses ak (ensures that it's on the curve) - let ak = ecc::EdwardsPoint::witness( - cs.namespace(|| "ak"), - self.proof_generation_key.as_ref().map(|k| k.ak.clone()), - self.params - )?; - - // There are no sensible attacks on small order points - // of ak (that we're aware of!) but it's a cheap check, - // so we do it. - ak.assert_not_small_order( - cs.namespace(|| "ak not small order"), - self.params - )?; - - // Rerandomize ak and expose it as an input to the circuit - { - let ar = boolean::field_into_boolean_vec_le( - cs.namespace(|| "ar"), - self.ar - )?; - - // Compute the randomness in the exponent - let ar = ecc::fixed_base_multiplication( - cs.namespace(|| "computation of randomization for the signing key"), - FixedGenerators::SpendingKeyGenerator, - &ar, - self.params - )?; - - let rk = ak.add( - cs.namespace(|| "computation of rk"), - &ar, - self.params - )?; - - rk.inputize(cs.namespace(|| "rk"))?; - } - - // Compute nk = [nsk] ProofGenerationKey - let nk; - { - // Witness nsk as bits - let nsk = boolean::field_into_boolean_vec_le( - cs.namespace(|| "nsk"), - self.proof_generation_key.as_ref().map(|k| k.nsk.clone()) - )?; - - // NB: We don't ensure that the bit representation of nsk - // is "in the field" (Fs) because it's not used except to - // demonstrate the prover knows it. If they know a - // congruency then that's equivalent. - - // Compute nk = [nsk] ProvingPublicKey - nk = ecc::fixed_base_multiplication( - cs.namespace(|| "computation of nk"), - FixedGenerators::ProofGenerationKey, - &nsk, - self.params - )?; - } - - // This is the "viewing key" preimage for CRH^ivk - let mut ivk_preimage = vec![]; - - // Place ak in the preimage for CRH^ivk - ivk_preimage.extend( - ak.repr(cs.namespace(|| "representation of ak"))? - ); - - // This is the nullifier preimage for PRF^nf - let mut nf_preimage = vec![]; - - // Extend ivk and nf preimages with the representation of - // nk. - { - let repr_nk = nk.repr( - cs.namespace(|| "representation of nk") - )?; - - ivk_preimage.extend(repr_nk.iter().cloned()); - nf_preimage.extend(repr_nk); - } - - assert_eq!(ivk_preimage.len(), 512); - assert_eq!(nf_preimage.len(), 256); - - // Compute the incoming viewing key ivk - let mut ivk = blake2s::blake2s( - cs.namespace(|| "computation of ivk"), - &ivk_preimage, - constants::CRH_IVK_PERSONALIZATION - )?; - - // drop_5 to ensure it's in the field - ivk.truncate(E::Fs::CAPACITY as usize); - - // Witness g_d, checking that it's on the curve. - let g_d = { - // This binding is to avoid a weird edge case in Rust's - // ownership/borrowing rules. self is partially moved - // above, but the closure for and_then will have to - // move self (or a reference to self) to reference - // self.params, so we have to copy self.params here. - let params = self.params; - - ecc::EdwardsPoint::witness( - cs.namespace(|| "witness g_d"), - self.payment_address.as_ref().and_then(|a| a.g_d(params)), - self.params - )? - }; - - // Check that g_d is not small order. Technically, this check - // is already done in the Output circuit, and this proof ensures - // g_d is bound to a product of that check, but for defense in - // depth let's check it anyway. It's cheap. - g_d.assert_not_small_order( - cs.namespace(|| "g_d not small order"), - self.params - )?; - - // Compute pk_d = g_d^ivk - let pk_d = g_d.mul( - cs.namespace(|| "compute pk_d"), - &ivk, - self.params - )?; - - // Compute note contents: - // value (in big endian) followed by g_d and pk_d - let mut note_contents = vec![]; - - // Handle the value; we'll need it later for the - // dummy input check. - let mut value_num = num::Num::zero(); - { - // Get the value in little-endian bit order - let value_bits = expose_value_commitment( - cs.namespace(|| "value commitment"), - self.value_commitment, - self.params - )?; - - // Compute the note's value as a linear combination - // of the bits. - let mut coeff = E::Fr::one(); - for bit in &value_bits { - value_num = value_num.add_bool_with_coeff( - CS::one(), - bit, - coeff - ); - coeff.double(); - } - - // Place the value in the note - note_contents.extend(value_bits); - } - - // Place g_d in the note - note_contents.extend( - g_d.repr(cs.namespace(|| "representation of g_d"))? - ); - - // Place pk_d in the note - note_contents.extend( - pk_d.repr(cs.namespace(|| "representation of pk_d"))? - ); - - assert_eq!( - note_contents.len(), - 64 + // value - 256 + // g_d - 256 // p_d - ); - - // Compute the hash of the note contents - let mut cm = pedersen_hash::pedersen_hash( - cs.namespace(|| "note content hash"), - pedersen_hash::Personalization::NoteCommitment, - ¬e_contents, - self.params - )?; - - { - // Booleanize the randomness for the note commitment - let rcm = boolean::field_into_boolean_vec_le( - cs.namespace(|| "rcm"), - self.commitment_randomness - )?; - - // Compute the note commitment randomness in the exponent - let rcm = ecc::fixed_base_multiplication( - cs.namespace(|| "computation of commitment randomness"), - FixedGenerators::NoteCommitmentRandomness, - &rcm, - self.params - )?; - - // Randomize the note commitment. Pedersen hashes are not - // themselves hiding commitments. - cm = cm.add( - cs.namespace(|| "randomization of note commitment"), - &rcm, - self.params - )?; - } - - // This will store (least significant bit first) - // the position of the note in the tree, for use - // in nullifier computation. - let mut position_bits = vec![]; - - // This is an injective encoding, as cur is a - // point in the prime order subgroup. - let mut cur = cm.get_x().clone(); - - // Ascend the merkle tree authentication path - for (i, e) in self.auth_path.into_iter().enumerate() { - let cs = &mut cs.namespace(|| format!("merkle tree hash {}", i)); - - // Determines if the current subtree is the "right" leaf at this - // depth of the tree. - let cur_is_right = boolean::Boolean::from(boolean::AllocatedBit::alloc( - cs.namespace(|| "position bit"), - e.map(|e| e.1) - )?); - - // Push this boolean for nullifier computation later - position_bits.push(cur_is_right.clone()); - - // Witness the authentication path element adjacent - // at this depth. - let path_element = num::AllocatedNum::alloc( - cs.namespace(|| "path element"), - || { - Ok(e.get()?.0) - } - )?; - - // Swap the two if the current subtree is on the right - let (xl, xr) = num::AllocatedNum::conditionally_reverse( - cs.namespace(|| "conditional reversal of preimage"), - &cur, - &path_element, - &cur_is_right - )?; - - // We don't need to be strict, because the function is - // collision-resistant. If the prover witnesses a congruency, - // they will be unable to find an authentication path in the - // tree with high probability. - let mut preimage = vec![]; - preimage.extend(xl.into_bits_le(cs.namespace(|| "xl into bits"))?); - preimage.extend(xr.into_bits_le(cs.namespace(|| "xr into bits"))?); - - // Compute the new subtree value - cur = pedersen_hash::pedersen_hash( - cs.namespace(|| "computation of pedersen hash"), - pedersen_hash::Personalization::MerkleTree(i), - &preimage, - self.params - )?.get_x().clone(); // Injective encoding - } - - { - let real_anchor_value = self.anchor; - - // Allocate the "real" anchor that will be exposed. - let rt = num::AllocatedNum::alloc( - cs.namespace(|| "conditional anchor"), - || { - Ok(*real_anchor_value.get()?) - } - )?; - - // (cur - rt) * value = 0 - // if value is zero, cur and rt can be different - // if value is nonzero, they must be equal - cs.enforce( - || "conditionally enforce correct root", - |lc| lc + cur.get_variable() - rt.get_variable(), - |lc| lc + &value_num.lc(E::Fr::one()), - |lc| lc - ); - - // Expose the anchor - rt.inputize(cs.namespace(|| "anchor"))?; - } - - // Compute the cm + g^position for preventing - // faerie gold attacks - let mut rho = cm; - { - // Compute the position in the exponent - let position = ecc::fixed_base_multiplication( - cs.namespace(|| "g^position"), - FixedGenerators::NullifierPosition, - &position_bits, - self.params - )?; - - // Add the position to the commitment - rho = rho.add( - cs.namespace(|| "faerie gold prevention"), - &position, - self.params - )?; - } - - // Let's compute nf = BLAKE2s(nk || rho) - nf_preimage.extend( - rho.repr(cs.namespace(|| "representation of rho"))? - ); - - assert_eq!(nf_preimage.len(), 512); - - // Compute nf - let nf = blake2s::blake2s( - cs.namespace(|| "nf computation"), - &nf_preimage, - constants::PRF_NF_PERSONALIZATION - )?; - - multipack::pack_into_inputs(cs.namespace(|| "pack nullifier"), &nf) - } -} - -impl<'a, E: JubjubEngine> Circuit for Output<'a, E> { - fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> - { - // Let's start to construct our note, which contains - // value (big endian) - let mut note_contents = vec![]; - - // Expose the value commitment and place the value - // in the note. - note_contents.extend(expose_value_commitment( - cs.namespace(|| "value commitment"), - self.value_commitment, - self.params - )?); - - // Let's deal with g_d - { - let params = self.params; - - // Prover witnesses g_d, ensuring it's on the - // curve. - let g_d = ecc::EdwardsPoint::witness( - cs.namespace(|| "witness g_d"), - self.payment_address.as_ref().and_then(|a| a.g_d(params)), - self.params - )?; - - // g_d is ensured to be large order. The relationship - // between g_d and pk_d ultimately binds ivk to the - // note. If this were a small order point, it would - // not do this correctly, and the prover could - // double-spend by finding random ivk's that satisfy - // the relationship. - // - // Further, if it were small order, epk would be - // small order too! - g_d.assert_not_small_order( - cs.namespace(|| "g_d not small order"), - self.params - )?; - - // Extend our note contents with the representation of - // g_d. - note_contents.extend( - g_d.repr(cs.namespace(|| "representation of g_d"))? - ); - - // Booleanize our ephemeral secret key - let esk = boolean::field_into_boolean_vec_le( - cs.namespace(|| "esk"), - self.esk - )?; - - // Create the ephemeral public key from g_d. - let epk = g_d.mul( - cs.namespace(|| "epk computation"), - &esk, - self.params - )?; - - // Expose epk publicly. - epk.inputize(cs.namespace(|| "epk"))?; - } - - // Now let's deal with pk_d. We don't do any checks and - // essentially allow the prover to witness any 256 bits - // they would like. - { - // Just grab pk_d from the witness - let pk_d = self.payment_address.as_ref().map(|e| e.pk_d.into_xy()); - - // Witness the y-coordinate, encoded as little - // endian bits (to match the representation) - let y_contents = boolean::field_into_boolean_vec_le( - cs.namespace(|| "pk_d bits of y"), - pk_d.map(|e| e.1) - )?; - - // Witness the sign bit - let sign_bit = boolean::Boolean::from(boolean::AllocatedBit::alloc( - cs.namespace(|| "pk_d bit of x"), - pk_d.map(|e| e.0.into_repr().is_odd()) - )?); - - // Extend the note with pk_d representation - note_contents.extend(y_contents); - note_contents.push(sign_bit); - } - - assert_eq!( - note_contents.len(), - 64 + // value - 256 + // g_d - 256 // pk_d - ); - - // Compute the hash of the note contents - let mut cm = pedersen_hash::pedersen_hash( - cs.namespace(|| "note content hash"), - pedersen_hash::Personalization::NoteCommitment, - ¬e_contents, - self.params - )?; - - { - // Booleanize the randomness - let rcm = boolean::field_into_boolean_vec_le( - cs.namespace(|| "rcm"), - self.commitment_randomness - )?; - - // Compute the note commitment randomness in the exponent - let rcm = ecc::fixed_base_multiplication( - cs.namespace(|| "computation of commitment randomness"), - FixedGenerators::NoteCommitmentRandomness, - &rcm, - self.params - )?; - - // Randomize our note commitment - cm = cm.add( - cs.namespace(|| "randomization of note commitment"), - &rcm, - self.params - )?; - } - - // Only the x-coordinate of the output is revealed, - // since we know it is prime order, and we know that - // the x-coordinate is an injective encoding for - // prime-order elements. - cm.get_x().inputize(cs.namespace(|| "commitment"))?; - - Ok(()) - } -} - -#[test] -fn test_input_circuit_with_bls12_381() { - use pairing::{Field, BitIterator}; - use pairing::bls12_381::*; - use rand::{SeedableRng, Rng, XorShiftRng}; - use ::circuit::test::*; - use jubjub::{JubjubBls12, fs, edwards}; - - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let tree_depth = 32; - - for _ in 0..10 { - let value_commitment = ValueCommitment { - value: rng.gen(), - randomness: rng.gen() - }; - - let nsk: fs::Fs = rng.gen(); - let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params); - - let proof_generation_key = ::primitives::ProofGenerationKey { - ak: ak.clone(), - nsk: nsk.clone() - }; - - let viewing_key = proof_generation_key.into_viewing_key(params); - - let payment_address; - - loop { - let diversifier = ::primitives::Diversifier(rng.gen()); - - if let Some(p) = viewing_key.into_payment_address( - diversifier, - params - ) - { - payment_address = p; - break; - } - } - - let g_d = payment_address.diversifier.g_d(params).unwrap(); - let commitment_randomness: fs::Fs = rng.gen(); - let auth_path = vec![Some((rng.gen(), rng.gen())); tree_depth]; - let ar: fs::Fs = rng.gen(); - - { - let rk = viewing_key.rk(ar, params).into_xy(); - let expected_value_cm = value_commitment.cm(params).into_xy(); - let note = ::primitives::Note { - value: value_commitment.value, - g_d: g_d.clone(), - pk_d: payment_address.pk_d.clone(), - r: commitment_randomness.clone() - }; - - let mut position = 0u64; - let cm: Fr = note.cm(params); - let mut cur = cm.clone(); - - for (i, val) in auth_path.clone().into_iter().enumerate() - { - let (uncle, b) = val.unwrap(); - - let mut lhs = cur; - let mut rhs = uncle; - - if b { - ::std::mem::swap(&mut lhs, &mut rhs); - } - - let mut lhs: Vec = BitIterator::new(lhs.into_repr()).collect(); - let mut rhs: Vec = BitIterator::new(rhs.into_repr()).collect(); - - lhs.reverse(); - rhs.reverse(); - - cur = ::pedersen_hash::pedersen_hash::( - ::pedersen_hash::Personalization::MerkleTree(i), - lhs.into_iter() - .take(Fr::NUM_BITS as usize) - .chain(rhs.into_iter().take(Fr::NUM_BITS as usize)), - params - ).into_xy().0; - - if b { - position |= 1 << i; - } - } - - let expected_nf = note.nf(&viewing_key, position, params); - let expected_nf = multipack::bytes_to_bits_le(&expected_nf); - let expected_nf = multipack::compute_multipacking::(&expected_nf); - assert_eq!(expected_nf.len(), 2); - - let mut cs = TestConstraintSystem::::new(); - - let instance = Spend { - params: params, - value_commitment: Some(value_commitment.clone()), - proof_generation_key: Some(proof_generation_key.clone()), - payment_address: Some(payment_address.clone()), - commitment_randomness: Some(commitment_randomness), - ar: Some(ar), - auth_path: auth_path.clone(), - anchor: Some(cur) - }; - - instance.synthesize(&mut cs).unwrap(); - - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 98777); - assert_eq!(cs.hash(), "d37c738e83df5d9b0bb6495ac96abf21bcb2697477e2c15c2c7916ff7a3b6a89"); - - assert_eq!(cs.get("randomization of note commitment/x3/num"), cm); - - assert_eq!(cs.num_inputs(), 8); - assert_eq!(cs.get_input(0, "ONE"), Fr::one()); - assert_eq!(cs.get_input(1, "rk/x/input variable"), rk.0); - assert_eq!(cs.get_input(2, "rk/y/input variable"), rk.1); - assert_eq!(cs.get_input(3, "value commitment/commitment point/x/input variable"), expected_value_cm.0); - assert_eq!(cs.get_input(4, "value commitment/commitment point/y/input variable"), expected_value_cm.1); - assert_eq!(cs.get_input(5, "anchor/input variable"), cur); - assert_eq!(cs.get_input(6, "pack nullifier/input 0"), expected_nf[0]); - assert_eq!(cs.get_input(7, "pack nullifier/input 1"), expected_nf[1]); - } - } -} - -#[test] -fn test_output_circuit_with_bls12_381() { - use pairing::{Field}; - use pairing::bls12_381::*; - use rand::{SeedableRng, Rng, XorShiftRng}; - use ::circuit::test::*; - use jubjub::{JubjubBls12, fs, edwards}; - - let params = &JubjubBls12::new(); - let rng = &mut XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - let value_commitment = ValueCommitment { - value: rng.gen(), - randomness: rng.gen() - }; - - let nsk: fs::Fs = rng.gen(); - let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params); - - let proof_generation_key = ::primitives::ProofGenerationKey { - ak: ak.clone(), - nsk: nsk.clone() - }; - - let viewing_key = proof_generation_key.into_viewing_key(params); - - let payment_address; - - loop { - let diversifier = ::primitives::Diversifier(rng.gen()); - - if let Some(p) = viewing_key.into_payment_address( - diversifier, - params - ) - { - payment_address = p; - break; - } - } - - let commitment_randomness: fs::Fs = rng.gen(); - let esk: fs::Fs = rng.gen(); - - { - let mut cs = TestConstraintSystem::::new(); - - let instance = Output { - params: params, - value_commitment: Some(value_commitment.clone()), - payment_address: Some(payment_address.clone()), - commitment_randomness: Some(commitment_randomness), - esk: Some(esk.clone()) - }; - - instance.synthesize(&mut cs).unwrap(); - - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 7827); - assert_eq!(cs.hash(), "c26d5cdfe6ccd65c03390902c02e11393ea6bb96aae32a7f2ecb12eb9103faee"); - - let expected_cm = payment_address.create_note( - value_commitment.value, - commitment_randomness, - params - ).expect("should be valid").cm(params); - - let expected_value_cm = value_commitment.cm(params).into_xy(); - - let expected_epk = payment_address.g_d(params).expect("should be valid").mul(esk, params); - let expected_epk_xy = expected_epk.into_xy(); - - assert_eq!(cs.num_inputs(), 6); - assert_eq!(cs.get_input(0, "ONE"), Fr::one()); - assert_eq!(cs.get_input(1, "value commitment/commitment point/x/input variable"), expected_value_cm.0); - assert_eq!(cs.get_input(2, "value commitment/commitment point/y/input variable"), expected_value_cm.1); - assert_eq!(cs.get_input(3, "epk/x/input variable"), expected_epk_xy.0); - assert_eq!(cs.get_input(4, "epk/y/input variable"), expected_epk_xy.1); - assert_eq!(cs.get_input(5, "commitment/input variable"), expected_cm); - } - } -} diff --git a/sapling-crypto/src/circuit/sprout/commitment.rs b/sapling-crypto/src/circuit/sprout/commitment.rs deleted file mode 100644 index a32f05c..0000000 --- a/sapling-crypto/src/circuit/sprout/commitment.rs +++ /dev/null @@ -1,42 +0,0 @@ -use pairing::{Engine}; -use bellman::{ConstraintSystem, SynthesisError}; -use circuit::sha256::{ - sha256 -}; -use circuit::boolean::{ - Boolean -}; - -pub fn note_comm( - cs: CS, - a_pk: &[Boolean], - value: &[Boolean], - rho: &[Boolean], - r: &[Boolean] -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - assert_eq!(a_pk.len(), 256); - assert_eq!(value.len(), 64); - assert_eq!(rho.len(), 256); - assert_eq!(r.len(), 256); - - let mut image = vec![]; - image.push(Boolean::constant(true)); - image.push(Boolean::constant(false)); - image.push(Boolean::constant(true)); - image.push(Boolean::constant(true)); - image.push(Boolean::constant(false)); - image.push(Boolean::constant(false)); - image.push(Boolean::constant(false)); - image.push(Boolean::constant(false)); - image.extend(a_pk.iter().cloned()); - image.extend(value.iter().cloned()); - image.extend(rho.iter().cloned()); - image.extend(r.iter().cloned()); - - sha256( - cs, - &image - ) -} diff --git a/sapling-crypto/src/circuit/sprout/input.rs b/sapling-crypto/src/circuit/sprout/input.rs deleted file mode 100644 index ce69bc0..0000000 --- a/sapling-crypto/src/circuit/sprout/input.rs +++ /dev/null @@ -1,226 +0,0 @@ -use pairing::{Engine}; -use bellman::{ConstraintSystem, SynthesisError}; -use circuit::sha256::{ - sha256_block_no_padding -}; -use circuit::boolean::{ - AllocatedBit, - Boolean -}; - -use super::*; -use super::prfs::*; -use super::commitment::note_comm; - -pub struct InputNote { - pub nf: Vec, - pub mac: Vec, -} - -impl InputNote { - pub fn compute( - mut cs: CS, - a_sk: Option, - rho: Option, - r: Option, - value: &NoteValue, - h_sig: &[Boolean], - nonce: bool, - auth_path: [Option<([u8; 32], bool)>; TREE_DEPTH], - rt: &[Boolean] - ) -> Result - where E: Engine, CS: ConstraintSystem - { - let a_sk = witness_u252( - cs.namespace(|| "a_sk"), - a_sk.as_ref().map(|a_sk| &a_sk.0[..]) - )?; - - let rho = witness_u256( - cs.namespace(|| "rho"), - rho.as_ref().map(|rho| &rho.0[..]) - )?; - - let r = witness_u256( - cs.namespace(|| "r"), - r.as_ref().map(|r| &r.0[..]) - )?; - - let a_pk = prf_a_pk( - cs.namespace(|| "a_pk computation"), - &a_sk - )?; - - let nf = prf_nf( - cs.namespace(|| "nf computation"), - &a_sk, - &rho - )?; - - let mac = prf_pk( - cs.namespace(|| "mac computation"), - &a_sk, - h_sig, - nonce - )?; - - let cm = note_comm( - cs.namespace(|| "cm computation"), - &a_pk, - &value.bits_le(), - &rho, - &r - )?; - - // Witness into the merkle tree - let mut cur = cm.clone(); - - for (i, layer) in auth_path.into_iter().enumerate() { - let cs = &mut cs.namespace(|| format!("layer {}", i)); - - let cur_is_right = AllocatedBit::alloc( - cs.namespace(|| "cur is right"), - layer.as_ref().map(|&(_, p)| p) - )?; - - let lhs = cur; - let rhs = witness_u256( - cs.namespace(|| "sibling"), - layer.as_ref().map(|&(ref sibling, _)| &sibling[..]) - )?; - - // Conditionally swap if cur is right - let preimage = conditionally_swap_u256( - cs.namespace(|| "conditional swap"), - &lhs[..], - &rhs[..], - &cur_is_right - )?; - - cur = sha256_block_no_padding( - cs.namespace(|| "hash of this layer"), - &preimage - )?; - } - - // enforce must be true if the value is nonzero - let enforce = AllocatedBit::alloc( - cs.namespace(|| "enforce"), - value.get_value().map(|n| n != 0) - )?; - - // value * (1 - enforce) = 0 - // If `value` is zero, `enforce` _can_ be zero. - // If `value` is nonzero, `enforce` _must_ be one. - cs.enforce( - || "enforce validity", - |_| value.lc(), - |lc| lc + CS::one() - enforce.get_variable(), - |lc| lc - ); - - assert_eq!(cur.len(), rt.len()); - - // Check that the anchor (exposed as a public input) - // is equal to the merkle tree root that we calculated - // for this note - for (i, (cur, rt)) in cur.into_iter().zip(rt.iter()).enumerate() { - // (cur - rt) * enforce = 0 - // if enforce is zero, cur and rt can be different - // if enforce is one, they must be equal - cs.enforce( - || format!("conditionally enforce correct root for bit {}", i), - |_| cur.lc(CS::one(), E::Fr::one()) - &rt.lc(CS::one(), E::Fr::one()), - |lc| lc + enforce.get_variable(), - |lc| lc - ); - } - - Ok(InputNote { - mac: mac, - nf: nf - }) - } -} - -/// Swaps two 256-bit blobs conditionally, returning the -/// 512-bit concatenation. -pub fn conditionally_swap_u256( - mut cs: CS, - lhs: &[Boolean], - rhs: &[Boolean], - condition: &AllocatedBit -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem, -{ - assert_eq!(lhs.len(), 256); - assert_eq!(rhs.len(), 256); - - let mut new_lhs = vec![]; - let mut new_rhs = vec![]; - - for (i, (lhs, rhs)) in lhs.iter().zip(rhs.iter()).enumerate() { - let cs = &mut cs.namespace(|| format!("bit {}", i)); - - let x = Boolean::from(AllocatedBit::alloc( - cs.namespace(|| "x"), - condition.get_value().and_then(|v| { - if v { - rhs.get_value() - } else { - lhs.get_value() - } - }) - )?); - - // x = (1-condition)lhs + (condition)rhs - // x = lhs - lhs(condition) + rhs(condition) - // x - lhs = condition (rhs - lhs) - // if condition is zero, we don't swap, so - // x - lhs = 0 - // x = lhs - // if condition is one, we do swap, so - // x - lhs = rhs - lhs - // x = rhs - cs.enforce( - || "conditional swap for x", - |lc| lc + &rhs.lc(CS::one(), E::Fr::one()) - - &lhs.lc(CS::one(), E::Fr::one()), - |lc| lc + condition.get_variable(), - |lc| lc + &x.lc(CS::one(), E::Fr::one()) - - &lhs.lc(CS::one(), E::Fr::one()) - ); - - let y = Boolean::from(AllocatedBit::alloc( - cs.namespace(|| "y"), - condition.get_value().and_then(|v| { - if v { - lhs.get_value() - } else { - rhs.get_value() - } - }) - )?); - - // y = (1-condition)rhs + (condition)lhs - // y - rhs = condition (lhs - rhs) - cs.enforce( - || "conditional swap for y", - |lc| lc + &lhs.lc(CS::one(), E::Fr::one()) - - &rhs.lc(CS::one(), E::Fr::one()), - |lc| lc + condition.get_variable(), - |lc| lc + &y.lc(CS::one(), E::Fr::one()) - - &rhs.lc(CS::one(), E::Fr::one()) - ); - - new_lhs.push(x); - new_rhs.push(y); - } - - let mut f = new_lhs; - f.extend(new_rhs); - - assert_eq!(f.len(), 512); - - Ok(f) -} diff --git a/sapling-crypto/src/circuit/sprout/mod.rs b/sapling-crypto/src/circuit/sprout/mod.rs deleted file mode 100644 index 586de8c..0000000 --- a/sapling-crypto/src/circuit/sprout/mod.rs +++ /dev/null @@ -1,488 +0,0 @@ -use pairing::{Engine, Field}; -use bellman::{ConstraintSystem, SynthesisError, Circuit, LinearCombination}; -use circuit::boolean::{ - AllocatedBit, - Boolean -}; -use circuit::multipack::pack_into_inputs; - -mod prfs; -mod commitment; -mod input; -mod output; - -use self::input::*; -use self::output::*; - -pub const TREE_DEPTH: usize = 29; - -pub struct SpendingKey(pub [u8; 32]); -pub struct PayingKey(pub [u8; 32]); -pub struct UniqueRandomness(pub [u8; 32]); -pub struct CommitmentRandomness(pub [u8; 32]); - -pub struct JoinSplit { - pub vpub_old: Option, - pub vpub_new: Option, - pub h_sig: Option<[u8; 32]>, - pub phi: Option<[u8; 32]>, - pub inputs: Vec, - pub outputs: Vec, - pub rt: Option<[u8; 32]>, -} - -pub struct JSInput { - pub value: Option, - pub a_sk: Option, - pub rho: Option, - pub r: Option, - pub auth_path: [Option<([u8; 32], bool)>; TREE_DEPTH] -} - -pub struct JSOutput { - pub value: Option, - pub a_pk: Option, - pub r: Option -} - -impl Circuit for JoinSplit { - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { - assert_eq!(self.inputs.len(), 2); - assert_eq!(self.outputs.len(), 2); - - // vpub_old is the value entering the - // JoinSplit from the "outside" value - // pool - let vpub_old = NoteValue::new( - cs.namespace(|| "vpub_old"), - self.vpub_old - )?; - - // vpub_new is the value leaving the - // JoinSplit into the "outside" value - // pool - let vpub_new = NoteValue::new( - cs.namespace(|| "vpub_new"), - self.vpub_new - )?; - - // The left hand side of the balance equation - // vpub_old + inputs[0].value + inputs[1].value - let mut lhs = vpub_old.lc(); - - // The right hand side of the balance equation - // vpub_old + inputs[0].value + inputs[1].value - let mut rhs = vpub_new.lc(); - - // Witness rt (merkle tree root) - let rt = witness_u256( - cs.namespace(|| "rt"), - self.rt.as_ref().map(|v| &v[..]) - ).unwrap(); - - // Witness h_sig - let h_sig = witness_u256( - cs.namespace(|| "h_sig"), - self.h_sig.as_ref().map(|v| &v[..]) - ).unwrap(); - - // Witness phi - let phi = witness_u252( - cs.namespace(|| "phi"), - self.phi.as_ref().map(|v| &v[..]) - ).unwrap(); - - let mut input_notes = vec![]; - let mut lhs_total = self.vpub_old; - - // Iterate over the JoinSplit inputs - for (i, input) in self.inputs.into_iter().enumerate() { - let cs = &mut cs.namespace(|| format!("input {}", i)); - - // Accumulate the value of the left hand side - if let Some(value) = input.value { - lhs_total = lhs_total.map(|v| v.wrapping_add(value)); - } - - // Allocate the value of the note - let value = NoteValue::new( - cs.namespace(|| "value"), - input.value - )?; - - // Compute the nonce (for PRF inputs) which is false - // for the first input, and true for the second input. - let nonce = match i { - 0 => false, - 1 => true, - _ => unreachable!() - }; - - // Perform input note computations - input_notes.push(InputNote::compute( - cs.namespace(|| "note"), - input.a_sk, - input.rho, - input.r, - &value, - &h_sig, - nonce, - input.auth_path, - &rt - )?); - - // Add the note value to the left hand side of - // the balance equation - lhs = lhs + &value.lc(); - } - - // Rebind lhs so that it isn't mutable anymore - let lhs = lhs; - - // See zcash/zcash/issues/854 - { - // Expected sum of the left hand side of the balance - // equation, expressed as a 64-bit unsigned integer - let lhs_total = NoteValue::new( - cs.namespace(|| "total value of left hand side"), - lhs_total - )?; - - // Enforce that the left hand side can be expressed as a 64-bit - // integer - cs.enforce( - || "left hand side can be expressed as a 64-bit unsigned integer", - |_| lhs.clone(), - |lc| lc + CS::one(), - |_| lhs_total.lc() - ); - } - - let mut output_notes = vec![]; - - // Iterate over the JoinSplit outputs - for (i, output) in self.outputs.into_iter().enumerate() { - let cs = &mut cs.namespace(|| format!("output {}", i)); - - let value = NoteValue::new( - cs.namespace(|| "value"), - output.value - )?; - - // Compute the nonce (for PRF inputs) which is false - // for the first output, and true for the second output. - let nonce = match i { - 0 => false, - 1 => true, - _ => unreachable!() - }; - - // Perform output note computations - output_notes.push(OutputNote::compute( - cs.namespace(|| "note"), - output.a_pk, - &value, - output.r, - &phi, - &h_sig, - nonce - )?); - - // Add the note value to the right hand side of - // the balance equation - rhs = rhs + &value.lc(); - } - - // Enforce that balance is equal - cs.enforce( - || "balance equation", - |_| lhs.clone(), - |lc| lc + CS::one(), - |_| rhs - ); - - let mut public_inputs = vec![]; - public_inputs.extend(rt); - public_inputs.extend(h_sig); - - for note in input_notes { - public_inputs.extend(note.nf); - public_inputs.extend(note.mac); - } - - for note in output_notes { - public_inputs.extend(note.cm); - } - - public_inputs.extend(vpub_old.bits_le()); - public_inputs.extend(vpub_new.bits_le()); - - pack_into_inputs(cs.namespace(|| "input packing"), &public_inputs) - } -} - -pub struct NoteValue { - value: Option, - // Least significant digit first - bits: Vec -} - -impl NoteValue { - fn new( - mut cs: CS, - value: Option - ) -> Result - where E: Engine, CS: ConstraintSystem, - { - let mut values; - match value { - Some(mut val) => { - values = vec![]; - for _ in 0..64 { - values.push(Some(val & 1 == 1)); - val >>= 1; - } - }, - None => { - values = vec![None; 64]; - } - } - - let mut bits = vec![]; - for (i, value) in values.into_iter().enumerate() { - bits.push( - AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - value - )? - ); - } - - Ok(NoteValue { - value: value, - bits: bits - }) - } - - /// Encodes the bits of the value into little-endian - /// byte order. - fn bits_le(&self) -> Vec { - self.bits.chunks(8) - .flat_map(|v| v.iter().rev()) - .cloned() - .map(|e| Boolean::from(e)) - .collect() - } - - /// Computes this value as a linear combination of - /// its bits. - fn lc(&self) -> LinearCombination { - let mut tmp = LinearCombination::zero(); - - let mut coeff = E::Fr::one(); - for b in &self.bits { - tmp = tmp + (coeff, b.get_variable()); - coeff.double(); - } - - tmp - } - - fn get_value(&self) -> Option { - self.value - } -} - -/// Witnesses some bytes in the constraint system, -/// skipping the first `skip_bits`. -fn witness_bits( - mut cs: CS, - value: Option<&[u8]>, - num_bits: usize, - skip_bits: usize -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem, -{ - let bit_values = if let Some(value) = value { - let mut tmp = vec![]; - for b in value.iter() - .flat_map(|&m| (0..8).rev().map(move |i| m >> i & 1 == 1)) - .skip(skip_bits) - { - tmp.push(Some(b)); - } - tmp - } else { - vec![None; num_bits] - }; - assert_eq!(bit_values.len(), num_bits); - - let mut bits = vec![]; - - for (i, value) in bit_values.into_iter().enumerate() { - bits.push(Boolean::from(AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - value - )?)); - } - - Ok(bits) -} - -fn witness_u256( - cs: CS, - value: Option<&[u8]>, -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem, -{ - witness_bits(cs, value, 256, 0) -} - -fn witness_u252( - cs: CS, - value: Option<&[u8]>, -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem, -{ - witness_bits(cs, value, 252, 4) -} - -#[test] -fn test_sprout_constraints() { - use pairing::bls12_381::{Bls12}; - use ::circuit::test::*; - - use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian}; - - let test_vector = include_bytes!("test_vectors.dat"); - let mut test_vector = &test_vector[..]; - - fn get_u256(mut reader: R) -> [u8; 32] { - let mut result = [0u8; 32]; - - for i in 0..32 { - result[i] = reader.read_u8().unwrap(); - } - - result - } - - while test_vector.len() != 0 { - let mut cs = TestConstraintSystem::::new(); - - let phi = Some(get_u256(&mut test_vector)); - let rt = Some(get_u256(&mut test_vector)); - let h_sig = Some(get_u256(&mut test_vector)); - - let mut inputs = vec![]; - for _ in 0..2 { - test_vector.read_u8().unwrap(); - - let mut auth_path = [None; TREE_DEPTH]; - for i in (0..TREE_DEPTH).rev() { - test_vector.read_u8().unwrap(); - - let sibling = get_u256(&mut test_vector); - - auth_path[i] = Some((sibling, false)); - } - let mut position = test_vector.read_u64::().unwrap(); - for i in 0..TREE_DEPTH { - auth_path[i].as_mut().map(|p| { - p.1 = (position & 1) == 1 - }); - - position >>= 1; - } - - // a_pk - let _ = Some(SpendingKey(get_u256(&mut test_vector))); - let value = Some(test_vector.read_u64::().unwrap()); - let rho = Some(UniqueRandomness(get_u256(&mut test_vector))); - let r = Some(CommitmentRandomness(get_u256(&mut test_vector))); - let a_sk = Some(SpendingKey(get_u256(&mut test_vector))); - - inputs.push( - JSInput { - value: value, - a_sk: a_sk, - rho: rho, - r: r, - auth_path: auth_path - } - ); - } - - let mut outputs = vec![]; - - for _ in 0..2 { - let a_pk = Some(PayingKey(get_u256(&mut test_vector))); - let value = Some(test_vector.read_u64::().unwrap()); - get_u256(&mut test_vector); - let r = Some(CommitmentRandomness(get_u256(&mut test_vector))); - - outputs.push( - JSOutput { - value: value, - a_pk: a_pk, - r: r - } - ); - } - - let vpub_old = Some(test_vector.read_u64::().unwrap()); - let vpub_new = Some(test_vector.read_u64::().unwrap()); - - let nf1 = get_u256(&mut test_vector); - let nf2 = get_u256(&mut test_vector); - - let cm1 = get_u256(&mut test_vector); - let cm2 = get_u256(&mut test_vector); - - let mac1 = get_u256(&mut test_vector); - let mac2 = get_u256(&mut test_vector); - - let js = JoinSplit { - vpub_old: vpub_old, - vpub_new: vpub_new, - h_sig: h_sig, - phi: phi, - inputs: inputs, - outputs: outputs, - rt: rt - }; - - js.synthesize(&mut cs).unwrap(); - - if let Some(s) = cs.which_is_unsatisfied() { - panic!("{:?}", s); - } - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 1989085); - assert_eq!(cs.num_inputs(), 10); - assert_eq!(cs.hash(), "1a228d3c6377130d1778c7885811dc8b8864049cb5af8aff7e6cd46c5bc4b84c"); - - let mut expected_inputs = vec![]; - expected_inputs.extend(rt.unwrap().to_vec()); - expected_inputs.extend(h_sig.unwrap().to_vec()); - expected_inputs.extend(nf1.to_vec()); - expected_inputs.extend(mac1.to_vec()); - expected_inputs.extend(nf2.to_vec()); - expected_inputs.extend(mac2.to_vec()); - expected_inputs.extend(cm1.to_vec()); - expected_inputs.extend(cm2.to_vec()); - expected_inputs.write_u64::(vpub_old.unwrap()).unwrap(); - expected_inputs.write_u64::(vpub_new.unwrap()).unwrap(); - - use circuit::multipack; - - let expected_inputs = multipack::bytes_to_bits(&expected_inputs); - let expected_inputs = multipack::compute_multipacking::(&expected_inputs); - - assert!(cs.verify(&expected_inputs)); - } -} diff --git a/sapling-crypto/src/circuit/sprout/output.rs b/sapling-crypto/src/circuit/sprout/output.rs deleted file mode 100644 index 9cdbf52..0000000 --- a/sapling-crypto/src/circuit/sprout/output.rs +++ /dev/null @@ -1,54 +0,0 @@ -use pairing::{Engine}; -use bellman::{ConstraintSystem, SynthesisError}; -use circuit::boolean::{Boolean}; - -use super::*; -use super::prfs::*; -use super::commitment::note_comm; - -pub struct OutputNote { - pub cm: Vec -} - -impl OutputNote { - pub fn compute<'a, E, CS>( - mut cs: CS, - a_pk: Option, - value: &NoteValue, - r: Option, - phi: &[Boolean], - h_sig: &[Boolean], - nonce: bool - ) -> Result - where E: Engine, CS: ConstraintSystem, - { - let rho = prf_rho( - cs.namespace(|| "rho"), - phi, - h_sig, - nonce - )?; - - let a_pk = witness_u256( - cs.namespace(|| "a_pk"), - a_pk.as_ref().map(|a_pk| &a_pk.0[..]) - )?; - - let r = witness_u256( - cs.namespace(|| "r"), - r.as_ref().map(|r| &r.0[..]) - )?; - - let cm = note_comm( - cs.namespace(|| "cm computation"), - &a_pk, - &value.bits_le(), - &rho, - &r - )?; - - Ok(OutputNote { - cm: cm - }) - } -} diff --git a/sapling-crypto/src/circuit/sprout/prfs.rs b/sapling-crypto/src/circuit/sprout/prfs.rs deleted file mode 100644 index fff8648..0000000 --- a/sapling-crypto/src/circuit/sprout/prfs.rs +++ /dev/null @@ -1,79 +0,0 @@ -use pairing::{Engine}; -use bellman::{ConstraintSystem, SynthesisError}; -use circuit::sha256::{ - sha256_block_no_padding -}; -use circuit::boolean::{ - Boolean -}; - -fn prf( - cs: CS, - a: bool, - b: bool, - c: bool, - d: bool, - x: &[Boolean], - y: &[Boolean] -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - assert_eq!(x.len(), 252); - assert_eq!(y.len(), 256); - - let mut image = vec![]; - image.push(Boolean::constant(a)); - image.push(Boolean::constant(b)); - image.push(Boolean::constant(c)); - image.push(Boolean::constant(d)); - image.extend(x.iter().cloned()); - image.extend(y.iter().cloned()); - - assert_eq!(image.len(), 512); - - sha256_block_no_padding( - cs, - &image - ) -} - -pub fn prf_a_pk( - cs: CS, - a_sk: &[Boolean] -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - prf(cs, true, true, false, false, a_sk, &(0..256).map(|_| Boolean::constant(false)).collect::>()) -} - -pub fn prf_nf( - cs: CS, - a_sk: &[Boolean], - rho: &[Boolean] -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - prf(cs, true, true, true, false, a_sk, rho) -} - -pub fn prf_pk( - cs: CS, - a_sk: &[Boolean], - h_sig: &[Boolean], - nonce: bool -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - prf(cs, false, nonce, false, false, a_sk, h_sig) -} - -pub fn prf_rho( - cs: CS, - phi: &[Boolean], - h_sig: &[Boolean], - nonce: bool -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem -{ - prf(cs, false, nonce, true, false, phi, h_sig) -} diff --git a/sapling-crypto/src/circuit/sprout/test_vectors.dat b/sapling-crypto/src/circuit/sprout/test_vectors.dat deleted file mode 100644 index 1316955771eb17e9a3e11352f1252b6591c151da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10864 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 E1!z(1KmY&$ diff --git a/sapling-crypto/src/constants.rs b/sapling-crypto/src/constants.rs deleted file mode 100644 index dfdd36f..0000000 --- a/sapling-crypto/src/constants.rs +++ /dev/null @@ -1,40 +0,0 @@ -/// First 64 bytes of the BLAKE2s input during group hash. -/// This is chosen to be some random string that we couldn't have anticipated when we designed -/// the algorithm, for rigidity purposes. -/// We deliberately use an ASCII hex string of 32 bytes here. -pub const GH_FIRST_BLOCK: &'static [u8; 64] - = b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0"; - -// BLAKE2s invocation personalizations -/// BLAKE2s Personalization for CRH^ivk = BLAKE2s(ak | nk) -pub const CRH_IVK_PERSONALIZATION: &'static [u8; 8] - = b"Zcashivk"; - -/// BLAKE2s Personalization for PRF^nf = BLAKE2s(nk | rho) -pub const PRF_NF_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_nf"; - -// Group hash personalizations -/// BLAKE2s Personalization for Pedersen hash generators. -pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_PH"; - -/// BLAKE2s Personalization for the group hash for key diversification -pub const KEY_DIVERSIFICATION_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_gd"; - -/// BLAKE2s Personalization for the spending key base point -pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_G_"; - -/// BLAKE2s Personalization for the proof generation key base point -pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_H_"; - -/// BLAKE2s Personalization for the value commitment generator for the value -pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_cv"; - -/// BLAKE2s Personalization for the nullifier position generator (for computing rho) -pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &'static [u8; 8] - = b"Zcash_J_"; diff --git a/sapling-crypto/src/group_hash.rs b/sapling-crypto/src/group_hash.rs deleted file mode 100644 index 25e65f9..0000000 --- a/sapling-crypto/src/group_hash.rs +++ /dev/null @@ -1,46 +0,0 @@ -use jubjub::{ - JubjubEngine, - PrimeOrder, - edwards -}; - -use pairing::{ - PrimeField -}; - -use blake2_rfc::blake2s::Blake2s; -use constants; - -/// Produces a random point in the Jubjub curve. -/// The point is guaranteed to be prime order -/// and not the identity. -pub fn group_hash( - tag: &[u8], - personalization: &[u8], - params: &E::Params -) -> Option> -{ - assert_eq!(personalization.len(), 8); - - // Check to see that scalar field is 255 bits - assert!(E::Fr::NUM_BITS == 255); - - let mut h = Blake2s::with_params(32, &[], &[], personalization); - h.update(constants::GH_FIRST_BLOCK); - h.update(tag); - let h = h.finalize().as_ref().to_vec(); - assert!(h.len() == 32); - - match edwards::Point::::read(&h[..], params) { - Ok(p) => { - let p = p.mul_by_cofactor(params); - - if p != edwards::Point::zero() { - Some(p) - } else { - None - } - }, - Err(_) => None - } -} diff --git a/sapling-crypto/src/jubjub/edwards.rs b/sapling-crypto/src/jubjub/edwards.rs deleted file mode 100644 index e91455c..0000000 --- a/sapling-crypto/src/jubjub/edwards.rs +++ /dev/null @@ -1,523 +0,0 @@ -use pairing::{ - Field, - SqrtField, - PrimeField, - PrimeFieldRepr, - BitIterator -}; - -use super::{ - JubjubEngine, - JubjubParams, - Unknown, - PrimeOrder, - montgomery -}; - -use rand::{ - Rng -}; - -use std::marker::PhantomData; - -use std::io::{ - self, - Write, - Read -}; - -// Represents the affine point (X/Z, Y/Z) via the extended -// twisted Edwards coordinates. -// -// See "Twisted Edwards Curves Revisited" -// Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson -pub struct Point { - x: E::Fr, - y: E::Fr, - t: E::Fr, - z: E::Fr, - _marker: PhantomData -} - -fn convert_subgroup(from: &Point) -> Point -{ - Point { - x: from.x, - y: from.y, - t: from.t, - z: from.z, - _marker: PhantomData - } -} - -impl From> for Point -{ - fn from(p: Point) -> Point - { - convert_subgroup(&p) - } -} - -impl Clone for Point -{ - fn clone(&self) -> Self { - convert_subgroup(self) - } -} - -impl PartialEq for Point { - fn eq(&self, other: &Point) -> bool { - // p1 = (x1/z1, y1/z1) - // p2 = (x2/z2, y2/z2) - // Deciding that these two points are equal is a matter of - // determining that x1/z1 = x2/z2, or equivalently that - // x1*z2 = x2*z1, and similarly for y. - - let mut x1 = self.x; - x1.mul_assign(&other.z); - - let mut y1 = self.y; - y1.mul_assign(&other.z); - - let mut x2 = other.x; - x2.mul_assign(&self.z); - - let mut y2 = other.y; - y2.mul_assign(&self.z); - - x1 == x2 && y1 == y2 - } -} - -impl Point { - pub fn read( - reader: R, - params: &E::Params - ) -> io::Result - { - let mut y_repr = ::Repr::default(); - y_repr.read_le(reader)?; - - let x_sign = (y_repr.as_ref()[3] >> 63) == 1; - y_repr.as_mut()[3] &= 0x7fffffffffffffff; - - match E::Fr::from_repr(y_repr) { - Ok(y) => { - match Self::get_for_y(y, x_sign, params) { - Some(p) => Ok(p), - None => { - Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve")) - } - } - }, - Err(_) => { - Err(io::Error::new(io::ErrorKind::InvalidInput, "y is not in field")) - } - } - } - - pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> Option - { - // Given a y on the curve, x^2 = (y^2 - 1) / (dy^2 + 1) - // This is defined for all valid y-coordinates, - // as dy^2 + 1 = 0 has no solution in Fr. - - // tmp1 = y^2 - let mut tmp1 = y; - tmp1.square(); - - // tmp2 = (y^2 * d) + 1 - let mut tmp2 = tmp1; - tmp2.mul_assign(params.edwards_d()); - tmp2.add_assign(&E::Fr::one()); - - // tmp1 = y^2 - 1 - tmp1.sub_assign(&E::Fr::one()); - - match tmp2.inverse() { - Some(tmp2) => { - // tmp1 = (y^2 - 1) / (dy^2 + 1) - tmp1.mul_assign(&tmp2); - - match tmp1.sqrt() { - Some(mut x) => { - if x.into_repr().is_odd() != sign { - x.negate(); - } - - let mut t = x; - t.mul_assign(&y); - - Some(Point { - x: x, - y: y, - t: t, - z: E::Fr::one(), - _marker: PhantomData - }) - }, - None => None - } - }, - None => None - } - } - - /// This guarantees the point is in the prime order subgroup - #[must_use] - pub fn mul_by_cofactor(&self, params: &E::Params) -> Point - { - let tmp = self.double(params) - .double(params) - .double(params); - - convert_subgroup(&tmp) - } - - pub fn rand(rng: &mut R, params: &E::Params) -> Self - { - loop { - let y: E::Fr = rng.gen(); - - if let Some(p) = Self::get_for_y(y, rng.gen(), params) { - return p; - } - } - } -} - -impl Point { - pub fn write( - &self, - writer: W - ) -> io::Result<()> - { - let (x, y) = self.into_xy(); - - assert_eq!(E::Fr::NUM_BITS, 255); - - let x_repr = x.into_repr(); - let mut y_repr = y.into_repr(); - if x_repr.is_odd() { - y_repr.as_mut()[3] |= 0x8000000000000000u64; - } - - y_repr.write_le(writer) - } - - /// Convert from a Montgomery point - pub fn from_montgomery( - m: &montgomery::Point, - params: &E::Params - ) -> Self - { - match m.into_xy() { - None => { - // Map the point at infinity to the neutral element. - Point::zero() - }, - Some((x, y)) => { - // The map from a Montgomery curve is defined as: - // (x, y) -> (u, v) where - // u = x / y - // v = (x - 1) / (x + 1) - // - // This map is not defined for y = 0 and x = -1. - // - // y = 0 is a valid point only for x = 0: - // y^2 = x^3 + A.x^2 + x - // 0 = x^3 + A.x^2 + x - // 0 = x(x^2 + A.x + 1) - // We have: x = 0 OR x^2 + A.x + 1 = 0 - // x^2 + A.x + 1 = 0 - // (2.x + A)^2 = A^2 - 4 (Complete the square.) - // The left hand side is a square, and so if A^2 - 4 - // is nonsquare, there is no solution. Indeed, A^2 - 4 - // is nonsquare. - // - // (0, 0) is a point of order 2, and so we map it to - // (0, -1) in the twisted Edwards curve, which is the - // only point of order 2 that is not the neutral element. - if y.is_zero() { - // This must be the point (0, 0) as above. - let mut neg1 = E::Fr::one(); - neg1.negate(); - - Point { - x: E::Fr::zero(), - y: neg1, - t: E::Fr::zero(), - z: E::Fr::one(), - _marker: PhantomData - } - } else { - // Otherwise, as stated above, the mapping is still - // not defined at x = -1. However, x = -1 is not - // on the curve when A - 2 is nonsquare: - // y^2 = x^3 + A.x^2 + x - // y^2 = (-1) + A + (-1) - // y^2 = A - 2 - // Indeed, A - 2 is nonsquare. - // - // We need to map into (projective) extended twisted - // Edwards coordinates (X, Y, T, Z) which represents - // the point (X/Z, Y/Z) with Z nonzero and T = XY/Z. - // - // Thus, we compute... - // - // u = x(x + 1) - // v = y(x - 1) - // t = x(x - 1) - // z = y(x + 1) (Cannot be nonzero, as above.) - // - // ... which represents the point ( x / y , (x - 1) / (x + 1) ) - // as required by the mapping and preserves the property of - // the auxiliary coordinate t. - // - // We need to scale the coordinate, so u and t will have - // an extra factor s. - - // u = xs - let mut u = x; - u.mul_assign(params.scale()); - - // v = x - 1 - let mut v = x; - v.sub_assign(&E::Fr::one()); - - // t = xs(x - 1) - let mut t = u; - t.mul_assign(&v); - - // z = (x + 1) - let mut z = x; - z.add_assign(&E::Fr::one()); - - // u = xs(x + 1) - u.mul_assign(&z); - - // z = y(x + 1) - z.mul_assign(&y); - - // v = y(x - 1) - v.mul_assign(&y); - - Point { - x: u, - y: v, - t: t, - z: z, - _marker: PhantomData - } - } - } - } - } - - /// Attempts to cast this as a prime order element, failing if it's - /// not in the prime order subgroup. - pub fn as_prime_order(&self, params: &E::Params) -> Option> { - if self.mul(E::Fs::char(), params) == Point::zero() { - Some(convert_subgroup(self)) - } else { - None - } - } - - pub fn zero() -> Self { - Point { - x: E::Fr::zero(), - y: E::Fr::one(), - t: E::Fr::zero(), - z: E::Fr::one(), - _marker: PhantomData - } - } - - pub fn into_xy(&self) -> (E::Fr, E::Fr) - { - let zinv = self.z.inverse().unwrap(); - - let mut x = self.x; - x.mul_assign(&zinv); - - let mut y = self.y; - y.mul_assign(&zinv); - - (x, y) - } - - #[must_use] - pub fn negate(&self) -> Self { - let mut p = self.clone(); - - p.x.negate(); - p.t.negate(); - - p - } - - #[must_use] - pub fn double(&self, _: &E::Params) -> Self { - // See "Twisted Edwards Curves Revisited" - // Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson - // Section 3.3 - // http://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd - - // A = X1^2 - let mut a = self.x; - a.square(); - - // B = Y1^2 - let mut b = self.y; - b.square(); - - // C = 2*Z1^2 - let mut c = self.z; - c.square(); - c.double(); - - // D = a*A - // = -A - let mut d = a; - d.negate(); - - // E = (X1+Y1)^2 - A - B - let mut e = self.x; - e.add_assign(&self.y); - e.square(); - e.add_assign(&d); // -A = D - e.sub_assign(&b); - - // G = D+B - let mut g = d; - g.add_assign(&b); - - // F = G-C - let mut f = g; - f.sub_assign(&c); - - // H = D-B - let mut h = d; - h.sub_assign(&b); - - // X3 = E*F - let mut x3 = e; - x3.mul_assign(&f); - - // Y3 = G*H - let mut y3 = g; - y3.mul_assign(&h); - - // T3 = E*H - let mut t3 = e; - t3.mul_assign(&h); - - // Z3 = F*G - let mut z3 = f; - z3.mul_assign(&g); - - Point { - x: x3, - y: y3, - t: t3, - z: z3, - _marker: PhantomData - } - } - - #[must_use] - pub fn add(&self, other: &Self, params: &E::Params) -> Self - { - // See "Twisted Edwards Curves Revisited" - // Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson - // 3.1 Unified Addition in E^e - - // A = x1 * x2 - let mut a = self.x; - a.mul_assign(&other.x); - - // B = y1 * y2 - let mut b = self.y; - b.mul_assign(&other.y); - - // C = d * t1 * t2 - let mut c = params.edwards_d().clone(); - c.mul_assign(&self.t); - c.mul_assign(&other.t); - - // D = z1 * z2 - let mut d = self.z; - d.mul_assign(&other.z); - - // H = B - aA - // = B + A - let mut h = b; - h.add_assign(&a); - - // E = (x1 + y1) * (x2 + y2) - A - B - // = (x1 + y1) * (x2 + y2) - H - let mut e = self.x; - e.add_assign(&self.y); - { - let mut tmp = other.x; - tmp.add_assign(&other.y); - e.mul_assign(&tmp); - } - e.sub_assign(&h); - - // F = D - C - let mut f = d; - f.sub_assign(&c); - - // G = D + C - let mut g = d; - g.add_assign(&c); - - // x3 = E * F - let mut x3 = e; - x3.mul_assign(&f); - - // y3 = G * H - let mut y3 = g; - y3.mul_assign(&h); - - // t3 = E * H - let mut t3 = e; - t3.mul_assign(&h); - - // z3 = F * G - let mut z3 = f; - z3.mul_assign(&g); - - Point { - x: x3, - y: y3, - t: t3, - z: z3, - _marker: PhantomData - } - } - - #[must_use] - pub fn mul::Repr>>( - &self, - scalar: S, - params: &E::Params - ) -> Self - { - // Standard double-and-add scalar multiplication - - let mut res = Self::zero(); - - for b in BitIterator::new(scalar.into()) { - res = res.double(params); - - if b { - res = res.add(self, params); - } - } - - res - } -} diff --git a/sapling-crypto/src/jubjub/fs.rs b/sapling-crypto/src/jubjub/fs.rs deleted file mode 100644 index eb10e65..0000000 --- a/sapling-crypto/src/jubjub/fs.rs +++ /dev/null @@ -1,1232 +0,0 @@ -use byteorder::{ByteOrder, LittleEndian}; -use pairing::{BitIterator, Field, PrimeField, SqrtField, PrimeFieldRepr, PrimeFieldDecodingError, LegendreSymbol}; -use pairing::LegendreSymbol::*; -use pairing::{adc, sbb, mac_with_carry}; - -use super::ToUniform; - -// s = 6554484396890773809930967563523245729705921265872317281365359162392183254199 -const MODULUS: FsRepr = FsRepr([0xd0970e5ed6f72cb7, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9]); - -// The number of bits needed to represent the modulus. -const MODULUS_BITS: u32 = 252; - -// The number of bits that must be shaved from the beginning of -// the representation when randomly sampling. -const REPR_SHAVE_BITS: u32 = 4; - -// R = 2**256 % s -const R: FsRepr = FsRepr([0x25f80bb3b99607d9, 0xf315d62f66b6e750, 0x932514eeeb8814f4, 0x9a6fc6f479155c6]); - -// R2 = R^2 % s -const R2: FsRepr = FsRepr([0x67719aa495e57731, 0x51b0cef09ce3fc26, 0x69dab7fac026e9a5, 0x4f6547b8d127688]); - -// INV = -(s^{-1} mod 2^64) mod s -const INV: u64 = 0x1ba3a358ef788ef9; - -// GENERATOR = 6 (multiplicative generator of r-1 order, that is also quadratic nonresidue) -const GENERATOR: FsRepr = FsRepr([0x720b1b19d49ea8f1, 0xbf4aa36101f13a58, 0x5fa8cc968193ccbb, 0xe70cbdc7dccf3ac]); - -// 2^S * t = MODULUS - 1 with t odd -const S: u32 = 1; - -// 2^S root of unity computed by GENERATOR^t -const ROOT_OF_UNITY: FsRepr = FsRepr([0xaa9f02ab1d6124de, 0xb3524a6466112932, 0x7342261215ac260b, 0x4d6b87b1da259e2]); - -// -((2**256) mod s) mod s -const NEGATIVE_ONE: Fs = Fs(FsRepr([0xaa9f02ab1d6124de, 0xb3524a6466112932, 0x7342261215ac260b, 0x4d6b87b1da259e2])); - -/// This is the underlying representation of an element of `Fs`. -#[derive(Copy, Clone, PartialEq, Eq, Default, Debug)] -pub struct FsRepr(pub [u64; 4]); - -impl ::rand::Rand for FsRepr { - #[inline(always)] - fn rand(rng: &mut R) -> Self { - FsRepr(rng.gen()) - } -} - -impl ::std::fmt::Display for FsRepr -{ - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - try!(write!(f, "0x")); - for i in self.0.iter().rev() { - try!(write!(f, "{:016x}", *i)); - } - - Ok(()) - } -} - -impl AsRef<[u64]> for FsRepr { - #[inline(always)] - fn as_ref(&self) -> &[u64] { - &self.0 - } -} - -impl AsMut<[u64]> for FsRepr { - #[inline(always)] - fn as_mut(&mut self) -> &mut [u64] { - &mut self.0 - } -} - -impl From for FsRepr { - #[inline(always)] - fn from(val: u64) -> FsRepr { - let mut repr = Self::default(); - repr.0[0] = val; - repr - } -} - -impl Ord for FsRepr { - #[inline(always)] - fn cmp(&self, other: &FsRepr) -> ::std::cmp::Ordering { - for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) { - if a < b { - return ::std::cmp::Ordering::Less - } else if a > b { - return ::std::cmp::Ordering::Greater - } - } - - ::std::cmp::Ordering::Equal - } -} - -impl PartialOrd for FsRepr { - #[inline(always)] - fn partial_cmp(&self, other: &FsRepr) -> Option<::std::cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl PrimeFieldRepr for FsRepr { - #[inline(always)] - fn is_odd(&self) -> bool { - self.0[0] & 1 == 1 - } - - #[inline(always)] - fn is_even(&self) -> bool { - !self.is_odd() - } - - #[inline(always)] - fn is_zero(&self) -> bool { - self.0.iter().all(|&e| e == 0) - } - - #[inline(always)] - fn shr(&mut self, mut n: u32) { - if n >= 64 * 4 { - *self = Self::from(0); - return; - } - - while n >= 64 { - let mut t = 0; - for i in self.0.iter_mut().rev() { - ::std::mem::swap(&mut t, i); - } - n -= 64; - } - - if n > 0 { - let mut t = 0; - for i in self.0.iter_mut().rev() { - let t2 = *i << (64 - n); - *i >>= n; - *i |= t; - t = t2; - } - } - } - - #[inline(always)] - fn div2(&mut self) { - let mut t = 0; - for i in self.0.iter_mut().rev() { - let t2 = *i << 63; - *i >>= 1; - *i |= t; - t = t2; - } - } - - #[inline(always)] - fn mul2(&mut self) { - let mut last = 0; - for i in &mut self.0 { - let tmp = *i >> 63; - *i <<= 1; - *i |= last; - last = tmp; - } - } - - #[inline(always)] - fn shl(&mut self, mut n: u32) { - if n >= 64 * 4 { - *self = Self::from(0); - return; - } - - while n >= 64 { - let mut t = 0; - for i in &mut self.0 { - ::std::mem::swap(&mut t, i); - } - n -= 64; - } - - if n > 0 { - let mut t = 0; - for i in &mut self.0 { - let t2 = *i >> (64 - n); - *i <<= n; - *i |= t; - t = t2; - } - } - } - - #[inline(always)] - fn num_bits(&self) -> u32 { - let mut ret = (4 as u32) * 64; - for i in self.0.iter().rev() { - let leading = i.leading_zeros(); - ret -= leading; - if leading != 64 { - break; - } - } - - ret - } - - #[inline(always)] - fn add_nocarry(&mut self, other: &FsRepr) { - let mut carry = 0; - - for (a, b) in self.0.iter_mut().zip(other.0.iter()) { - *a = adc(*a, *b, &mut carry); - } - } - - #[inline(always)] - fn sub_noborrow(&mut self, other: &FsRepr) { - let mut borrow = 0; - - for (a, b) in self.0.iter_mut().zip(other.0.iter()) { - *a = sbb(*a, *b, &mut borrow); - } - } -} - -/// This is an element of the scalar field of the Jubjub curve. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Fs(FsRepr); - -impl ::std::fmt::Display for Fs -{ - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "Fs({})", self.into_repr()) - } -} - -impl ::rand::Rand for Fs { - fn rand(rng: &mut R) -> Self { - loop { - let mut tmp = Fs(FsRepr::rand(rng)); - - // Mask away the unused bits at the beginning. - tmp.0.as_mut()[3] &= 0xffffffffffffffff >> REPR_SHAVE_BITS; - - if tmp.is_valid() { - return tmp - } - } - } -} - -impl From for FsRepr { - fn from(e: Fs) -> FsRepr { - e.into_repr() - } -} - -impl PrimeField for Fs { - type Repr = FsRepr; - - fn from_repr(r: FsRepr) -> Result { - let mut r = Fs(r); - if r.is_valid() { - r.mul_assign(&Fs(R2)); - - Ok(r) - } else { - Err(PrimeFieldDecodingError::NotInField(format!("{}", r.0))) - } - } - - fn into_repr(&self) -> FsRepr { - let mut r = *self; - r.mont_reduce((self.0).0[0], (self.0).0[1], - (self.0).0[2], (self.0).0[3], - 0, 0, 0, 0); - r.0 - } - - fn char() -> FsRepr { - MODULUS - } - - const NUM_BITS: u32 = MODULUS_BITS; - - const CAPACITY: u32 = Self::NUM_BITS - 1; - - fn multiplicative_generator() -> Self { - Fs(GENERATOR) - } - - const S: u32 = S; - - fn root_of_unity() -> Self { - Fs(ROOT_OF_UNITY) - } -} - -impl Field for Fs { - #[inline] - fn zero() -> Self { - Fs(FsRepr::from(0)) - } - - #[inline] - fn one() -> Self { - Fs(R) - } - - #[inline] - fn is_zero(&self) -> bool { - self.0.is_zero() - } - - #[inline] - fn add_assign(&mut self, other: &Fs) { - // This cannot exceed the backing capacity. - self.0.add_nocarry(&other.0); - - // However, it may need to be reduced. - self.reduce(); - } - - #[inline] - fn double(&mut self) { - // This cannot exceed the backing capacity. - self.0.mul2(); - - // However, it may need to be reduced. - self.reduce(); - } - - #[inline] - fn sub_assign(&mut self, other: &Fs) { - // If `other` is larger than `self`, we'll need to add the modulus to self first. - if other.0 > self.0 { - self.0.add_nocarry(&MODULUS); - } - - self.0.sub_noborrow(&other.0); - } - - #[inline] - fn negate(&mut self) { - if !self.is_zero() { - let mut tmp = MODULUS; - tmp.sub_noborrow(&self.0); - self.0 = tmp; - } - } - - fn inverse(&self) -> Option { - if self.is_zero() { - None - } else { - // Guajardo Kumar Paar Pelzl - // Efficient Software-Implementation of Finite Fields with Applications to Cryptography - // Algorithm 16 (BEA for Inversion in Fp) - - let one = FsRepr::from(1); - - let mut u = self.0; - let mut v = MODULUS; - let mut b = Fs(R2); // Avoids unnecessary reduction step. - let mut c = Self::zero(); - - while u != one && v != one { - while u.is_even() { - u.div2(); - - if b.0.is_even() { - b.0.div2(); - } else { - b.0.add_nocarry(&MODULUS); - b.0.div2(); - } - } - - while v.is_even() { - v.div2(); - - if c.0.is_even() { - c.0.div2(); - } else { - c.0.add_nocarry(&MODULUS); - c.0.div2(); - } - } - - if v < u { - u.sub_noborrow(&v); - b.sub_assign(&c); - } else { - v.sub_noborrow(&u); - c.sub_assign(&b); - } - } - - if u == one { - Some(b) - } else { - Some(c) - } - } - } - - #[inline(always)] - fn frobenius_map(&mut self, _: usize) { - // This has no effect in a prime field. - } - - #[inline] - fn mul_assign(&mut self, other: &Fs) - { - let mut carry = 0; - let r0 = mac_with_carry(0, (self.0).0[0], (other.0).0[0], &mut carry); - let r1 = mac_with_carry(0, (self.0).0[0], (other.0).0[1], &mut carry); - let r2 = mac_with_carry(0, (self.0).0[0], (other.0).0[2], &mut carry); - let r3 = mac_with_carry(0, (self.0).0[0], (other.0).0[3], &mut carry); - let r4 = carry; - let mut carry = 0; - let r1 = mac_with_carry(r1, (self.0).0[1], (other.0).0[0], &mut carry); - let r2 = mac_with_carry(r2, (self.0).0[1], (other.0).0[1], &mut carry); - let r3 = mac_with_carry(r3, (self.0).0[1], (other.0).0[2], &mut carry); - let r4 = mac_with_carry(r4, (self.0).0[1], (other.0).0[3], &mut carry); - let r5 = carry; - let mut carry = 0; - let r2 = mac_with_carry(r2, (self.0).0[2], (other.0).0[0], &mut carry); - let r3 = mac_with_carry(r3, (self.0).0[2], (other.0).0[1], &mut carry); - let r4 = mac_with_carry(r4, (self.0).0[2], (other.0).0[2], &mut carry); - let r5 = mac_with_carry(r5, (self.0).0[2], (other.0).0[3], &mut carry); - let r6 = carry; - let mut carry = 0; - let r3 = mac_with_carry(r3, (self.0).0[3], (other.0).0[0], &mut carry); - let r4 = mac_with_carry(r4, (self.0).0[3], (other.0).0[1], &mut carry); - let r5 = mac_with_carry(r5, (self.0).0[3], (other.0).0[2], &mut carry); - let r6 = mac_with_carry(r6, (self.0).0[3], (other.0).0[3], &mut carry); - let r7 = carry; - self.mont_reduce(r0, r1, r2, r3, r4, r5, r6, r7); - } - - #[inline] - fn square(&mut self) - { - let mut carry = 0; - let r1 = mac_with_carry(0, (self.0).0[0], (self.0).0[1], &mut carry); - let r2 = mac_with_carry(0, (self.0).0[0], (self.0).0[2], &mut carry); - let r3 = mac_with_carry(0, (self.0).0[0], (self.0).0[3], &mut carry); - let r4 = carry; - let mut carry = 0; - let r3 = mac_with_carry(r3, (self.0).0[1], (self.0).0[2], &mut carry); - let r4 = mac_with_carry(r4, (self.0).0[1], (self.0).0[3], &mut carry); - let r5 = carry; - let mut carry = 0; - let r5 = mac_with_carry(r5, (self.0).0[2], (self.0).0[3], &mut carry); - let r6 = carry; - - let r7 = r6 >> 63; - let r6 = (r6 << 1) | (r5 >> 63); - let r5 = (r5 << 1) | (r4 >> 63); - let r4 = (r4 << 1) | (r3 >> 63); - let r3 = (r3 << 1) | (r2 >> 63); - let r2 = (r2 << 1) | (r1 >> 63); - let r1 = r1 << 1; - - let mut carry = 0; - let r0 = mac_with_carry(0, (self.0).0[0], (self.0).0[0], &mut carry); - let r1 = adc(r1, 0, &mut carry); - let r2 = mac_with_carry(r2, (self.0).0[1], (self.0).0[1], &mut carry); - let r3 = adc(r3, 0, &mut carry); - let r4 = mac_with_carry(r4, (self.0).0[2], (self.0).0[2], &mut carry); - let r5 = adc(r5, 0, &mut carry); - let r6 = mac_with_carry(r6, (self.0).0[3], (self.0).0[3], &mut carry); - let r7 = adc(r7, 0, &mut carry); - self.mont_reduce(r0, r1, r2, r3, r4, r5, r6, r7); - } -} - -impl Fs { - /// Determines if the element is really in the field. This is only used - /// internally. - #[inline(always)] - fn is_valid(&self) -> bool { - self.0 < MODULUS - } - - /// Subtracts the modulus from this element if this element is not in the - /// field. Only used internally. - #[inline(always)] - fn reduce(&mut self) { - if !self.is_valid() { - self.0.sub_noborrow(&MODULUS); - } - } - - #[inline(always)] - fn mont_reduce( - &mut self, - r0: u64, - mut r1: u64, - mut r2: u64, - mut r3: u64, - mut r4: u64, - mut r5: u64, - mut r6: u64, - mut r7: u64 - ) - { - // The Montgomery reduction here is based on Algorithm 14.32 in - // Handbook of Applied Cryptography - // . - - let k = r0.wrapping_mul(INV); - let mut carry = 0; - mac_with_carry(r0, k, MODULUS.0[0], &mut carry); - r1 = mac_with_carry(r1, k, MODULUS.0[1], &mut carry); - r2 = mac_with_carry(r2, k, MODULUS.0[2], &mut carry); - r3 = mac_with_carry(r3, k, MODULUS.0[3], &mut carry); - r4 = adc(r4, 0, &mut carry); - let carry2 = carry; - let k = r1.wrapping_mul(INV); - let mut carry = 0; - mac_with_carry(r1, k, MODULUS.0[0], &mut carry); - r2 = mac_with_carry(r2, k, MODULUS.0[1], &mut carry); - r3 = mac_with_carry(r3, k, MODULUS.0[2], &mut carry); - r4 = mac_with_carry(r4, k, MODULUS.0[3], &mut carry); - r5 = adc(r5, carry2, &mut carry); - let carry2 = carry; - let k = r2.wrapping_mul(INV); - let mut carry = 0; - mac_with_carry(r2, k, MODULUS.0[0], &mut carry); - r3 = mac_with_carry(r3, k, MODULUS.0[1], &mut carry); - r4 = mac_with_carry(r4, k, MODULUS.0[2], &mut carry); - r5 = mac_with_carry(r5, k, MODULUS.0[3], &mut carry); - r6 = adc(r6, carry2, &mut carry); - let carry2 = carry; - let k = r3.wrapping_mul(INV); - let mut carry = 0; - mac_with_carry(r3, k, MODULUS.0[0], &mut carry); - r4 = mac_with_carry(r4, k, MODULUS.0[1], &mut carry); - r5 = mac_with_carry(r5, k, MODULUS.0[2], &mut carry); - r6 = mac_with_carry(r6, k, MODULUS.0[3], &mut carry); - r7 = adc(r7, carry2, &mut carry); - (self.0).0[0] = r4; - (self.0).0[1] = r5; - (self.0).0[2] = r6; - (self.0).0[3] = r7; - self.reduce(); - } - - fn mul_bits>(&self, bits: BitIterator) -> Self { - let mut res = Self::zero(); - for bit in bits { - res.double(); - - if bit { - res.add_assign(self) - } - } - res - } -} - -impl ToUniform for Fs { - /// Convert a little endian byte string into a uniform - /// field element. The number is reduced mod s. The caller - /// is responsible for ensuring the input is 64 bytes of - /// Random Oracle output. - fn to_uniform(digest: &[u8]) -> Self { - assert_eq!(digest.len(), 64); - let mut repr: [u64; 8] = [0; 8]; - LittleEndian::read_u64_into(digest, &mut repr); - Self::one().mul_bits(BitIterator::new(repr)) - } -} - -impl SqrtField for Fs { - - fn legendre(&self) -> LegendreSymbol { - // s = self^((s - 1) // 2) - let s = self.pow([0x684b872f6b7b965b, 0x53341049e6640841, 0x83339d80809a1d80, 0x73eda753299d7d4]); - if s == Self::zero() { Zero } - else if s == Self::one() { QuadraticResidue } - else { QuadraticNonResidue } - } - - fn sqrt(&self) -> Option { - // Shank's algorithm for s mod 4 = 3 - // https://eprint.iacr.org/2012/685.pdf (page 9, algorithm 2) - - // a1 = self^((s - 3) // 4) - let mut a1 = self.pow([0xb425c397b5bdcb2d, 0x299a0824f3320420, 0x4199cec0404d0ec0, 0x39f6d3a994cebea]); - let mut a0 = a1; - a0.square(); - a0.mul_assign(self); - - if a0 == NEGATIVE_ONE - { - None - } - else - { - a1.mul_assign(self); - Some(a1) - } - } -} - - -#[test] -fn test_neg_one() { - let mut o = Fs::one(); - o.negate(); - - assert_eq!(NEGATIVE_ONE, o); -} - -#[cfg(test)] -use rand::{SeedableRng, XorShiftRng, Rand}; - -#[test] -fn test_fs_repr_ordering() { - fn assert_equality(a: FsRepr, b: FsRepr) { - assert_eq!(a, b); - assert!(a.cmp(&b) == ::std::cmp::Ordering::Equal); - } - - fn assert_lt(a: FsRepr, b: FsRepr) { - assert!(a < b); - assert!(b > a); - } - - assert_equality(FsRepr([9999, 9999, 9999, 9999]), FsRepr([9999, 9999, 9999, 9999])); - assert_equality(FsRepr([9999, 9998, 9999, 9999]), FsRepr([9999, 9998, 9999, 9999])); - assert_equality(FsRepr([9999, 9999, 9999, 9997]), FsRepr([9999, 9999, 9999, 9997])); - assert_lt(FsRepr([9999, 9997, 9999, 9998]), FsRepr([9999, 9997, 9999, 9999])); - assert_lt(FsRepr([9999, 9997, 9998, 9999]), FsRepr([9999, 9997, 9999, 9999])); - assert_lt(FsRepr([9, 9999, 9999, 9997]), FsRepr([9999, 9999, 9999, 9997])); -} - -#[test] -fn test_fs_repr_from() { - assert_eq!(FsRepr::from(100), FsRepr([100, 0, 0, 0])); -} - -#[test] -fn test_fs_repr_is_odd() { - assert!(!FsRepr::from(0).is_odd()); - assert!(FsRepr::from(0).is_even()); - assert!(FsRepr::from(1).is_odd()); - assert!(!FsRepr::from(1).is_even()); - assert!(!FsRepr::from(324834872).is_odd()); - assert!(FsRepr::from(324834872).is_even()); - assert!(FsRepr::from(324834873).is_odd()); - assert!(!FsRepr::from(324834873).is_even()); -} - -#[test] -fn test_fs_repr_is_zero() { - assert!(FsRepr::from(0).is_zero()); - assert!(!FsRepr::from(1).is_zero()); - assert!(!FsRepr([0, 0, 1, 0]).is_zero()); -} - -#[test] -fn test_fs_repr_div2() { - let mut a = FsRepr([0xbd2920b19c972321, 0x174ed0466a3be37e, 0xd468d5e3b551f0b5, 0xcb67c072733beefc]); - a.div2(); - assert_eq!(a, FsRepr([0x5e949058ce4b9190, 0x8ba76823351df1bf, 0x6a346af1daa8f85a, 0x65b3e039399df77e])); - for _ in 0..10 { - a.div2(); - } - assert_eq!(a, FsRepr([0x6fd7a524163392e4, 0x16a2e9da08cd477c, 0xdf9a8d1abc76aa3e, 0x196cf80e4e677d])); - for _ in 0..200 { - a.div2(); - } - assert_eq!(a, FsRepr([0x196cf80e4e67, 0x0, 0x0, 0x0])); - for _ in 0..40 { - a.div2(); - } - assert_eq!(a, FsRepr([0x19, 0x0, 0x0, 0x0])); - for _ in 0..4 { - a.div2(); - } - assert_eq!(a, FsRepr([0x1, 0x0, 0x0, 0x0])); - a.div2(); - assert!(a.is_zero()); -} - -#[test] -fn test_fs_repr_shr() { - let mut a = FsRepr([0xb33fbaec482a283f, 0x997de0d3a88cb3df, 0x9af62d2a9a0e5525, 0x36003ab08de70da1]); - a.shr(0); - assert_eq!( - a, - FsRepr([0xb33fbaec482a283f, 0x997de0d3a88cb3df, 0x9af62d2a9a0e5525, 0x36003ab08de70da1]) - ); - a.shr(1); - assert_eq!( - a, - FsRepr([0xd99fdd762415141f, 0xccbef069d44659ef, 0xcd7b16954d072a92, 0x1b001d5846f386d0]) - ); - a.shr(50); - assert_eq!( - a, - FsRepr([0xbc1a7511967bf667, 0xc5a55341caa4b32f, 0x75611bce1b4335e, 0x6c0]) - ); - a.shr(130); - assert_eq!( - a, - FsRepr([0x1d5846f386d0cd7, 0x1b0, 0x0, 0x0]) - ); - a.shr(64); - assert_eq!( - a, - FsRepr([0x1b0, 0x0, 0x0, 0x0]) - ); -} - -#[test] -fn test_fs_repr_mul2() { - let mut a = FsRepr::from(23712937547); - a.mul2(); - assert_eq!(a, FsRepr([0xb0acd6c96, 0x0, 0x0, 0x0])); - for _ in 0..60 { - a.mul2(); - } - assert_eq!(a, FsRepr([0x6000000000000000, 0xb0acd6c9, 0x0, 0x0])); - for _ in 0..128 { - a.mul2(); - } - assert_eq!(a, FsRepr([0x0, 0x0, 0x6000000000000000, 0xb0acd6c9])); - for _ in 0..60 { - a.mul2(); - } - assert_eq!(a, FsRepr([0x0, 0x0, 0x0, 0x9600000000000000])); - for _ in 0..7 { - a.mul2(); - } - assert!(a.is_zero()); -} - -#[test] -fn test_fs_repr_num_bits() { - let mut a = FsRepr::from(0); - assert_eq!(0, a.num_bits()); - a = FsRepr::from(1); - for i in 1..257 { - assert_eq!(i, a.num_bits()); - a.mul2(); - } - assert_eq!(0, a.num_bits()); -} - -#[test] -fn test_fs_repr_sub_noborrow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let mut t = FsRepr([0x8e62a7e85264e2c3, 0xb23d34c1941d3ca, 0x5976930b7502dd15, 0x600f3fb517bf5495]); - t.sub_noborrow(&FsRepr([0xd64f669809cbc6a4, 0xfa76cb9d90cf7637, 0xfefb0df9038d43b3, 0x298a30c744b31acf])); - assert!(t == FsRepr([0xb813415048991c1f, 0x10ad07ae88725d92, 0x5a7b851271759961, 0x36850eedd30c39c5])); - - for _ in 0..1000 { - let mut a = FsRepr::rand(&mut rng); - a.0[3] >>= 30; - let mut b = a; - for _ in 0..10 { - b.mul2(); - } - let mut c = b; - for _ in 0..10 { - c.mul2(); - } - - assert!(a < b); - assert!(b < c); - - let mut csub_ba = c; - csub_ba.sub_noborrow(&b); - csub_ba.sub_noborrow(&a); - - let mut csub_ab = c; - csub_ab.sub_noborrow(&a); - csub_ab.sub_noborrow(&b); - - assert_eq!(csub_ab, csub_ba); - } -} - -#[test] -fn test_fs_legendre() { - assert_eq!(QuadraticResidue, Fs::one().legendre()); - assert_eq!(Zero, Fs::zero().legendre()); - - let e = FsRepr([0x8385eec23df1f88e, 0x9a01fb412b2dba16, 0x4c928edcdd6c22f, 0x9f2df7ef69ecef9]); - assert_eq!(QuadraticResidue, Fs::from_repr(e).unwrap().legendre()); - let e = FsRepr([0xe8ed9f299da78568, 0x35efdebc88b2209, 0xc82125cb1f916dbe, 0x6813d2b38c39bd0]); - assert_eq!(QuadraticNonResidue, Fs::from_repr(e).unwrap().legendre()); -} - -#[test] -fn test_fr_repr_add_nocarry() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let mut t = FsRepr([0xd64f669809cbc6a4, 0xfa76cb9d90cf7637, 0xfefb0df9038d43b3, 0x298a30c744b31acf]); - t.add_nocarry(&FsRepr([0x8e62a7e85264e2c3, 0xb23d34c1941d3ca, 0x5976930b7502dd15, 0x600f3fb517bf5495])); - assert_eq!(t, FsRepr([0x64b20e805c30a967, 0x59a9ee9aa114a02, 0x5871a104789020c9, 0x8999707c5c726f65])); - - // Test for the associativity of addition. - for _ in 0..1000 { - let mut a = FsRepr::rand(&mut rng); - let mut b = FsRepr::rand(&mut rng); - let mut c = FsRepr::rand(&mut rng); - - // Unset the first few bits, so that overflow won't occur. - a.0[3] >>= 3; - b.0[3] >>= 3; - c.0[3] >>= 3; - - let mut abc = a; - abc.add_nocarry(&b); - abc.add_nocarry(&c); - - let mut acb = a; - acb.add_nocarry(&c); - acb.add_nocarry(&b); - - let mut bac = b; - bac.add_nocarry(&a); - bac.add_nocarry(&c); - - let mut bca = b; - bca.add_nocarry(&c); - bca.add_nocarry(&a); - - let mut cab = c; - cab.add_nocarry(&a); - cab.add_nocarry(&b); - - let mut cba = c; - cba.add_nocarry(&b); - cba.add_nocarry(&a); - - assert_eq!(abc, acb); - assert_eq!(abc, bac); - assert_eq!(abc, bca); - assert_eq!(abc, cab); - assert_eq!(abc, cba); - } -} - -#[test] -fn test_fs_is_valid() { - let mut a = Fs(MODULUS); - assert!(!a.is_valid()); - a.0.sub_noborrow(&FsRepr::from(1)); - assert!(a.is_valid()); - assert!(Fs(FsRepr::from(0)).is_valid()); - assert!(Fs(FsRepr([0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9])).is_valid()); - assert!(!Fs(FsRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])).is_valid()); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let a = Fs::rand(&mut rng); - assert!(a.is_valid()); - } -} - -#[test] -fn test_fs_add_assign() { - { - // Random number - let mut tmp = Fs::from_str("4577408157467272683998459759522778614363623736323078995109579213719612604198").unwrap(); - assert!(tmp.is_valid()); - // Test that adding zero has no effect. - tmp.add_assign(&Fs(FsRepr::from(0))); - assert_eq!(tmp, Fs(FsRepr([0x8e6bfff4722d6e67, 0x5643da5c892044f9, 0x9465f4b281921a69, 0x25f752d3edd7162]))); - // Add one and test for the result. - tmp.add_assign(&Fs(FsRepr::from(1))); - assert_eq!(tmp, Fs(FsRepr([0x8e6bfff4722d6e68, 0x5643da5c892044f9, 0x9465f4b281921a69, 0x25f752d3edd7162]))); - // Add another random number that exercises the reduction. - tmp.add_assign(&Fs(FsRepr([0xb634d07bc42d4a70, 0xf724f0c008411f5f, 0x456d4053d865af34, 0x24ce814e8c63027]))); - assert_eq!(tmp, Fs(FsRepr([0x44a0d070365ab8d8, 0x4d68cb1c91616459, 0xd9d3350659f7c99e, 0x4ac5d4227a3a189]))); - // Add one to (s - 1) and test for the result. - tmp = Fs(FsRepr([0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9])); - tmp.add_assign(&Fs(FsRepr::from(1))); - assert!(tmp.0.is_zero()); - // Add a random number to another one such that the result is s - 1 - tmp = Fs(FsRepr([0xa11fda5950ce3636, 0x922e0dbccfe0ca0e, 0xacebb6e215b82d4a, 0x97ffb8cdc3aee93])); - tmp.add_assign(&Fs(FsRepr([0x2f7734058628f680, 0x143a12d6fce74674, 0x597b841eeb7c0db6, 0x4fdb95d88f8c115]))); - assert_eq!(tmp, Fs(FsRepr([0xd0970e5ed6f72cb6, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9]))); - // Add one to the result and test for it. - tmp.add_assign(&Fs(FsRepr::from(1))); - assert!(tmp.0.is_zero()); - } - - // Test associativity - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Generate a, b, c and ensure (a + b) + c == a + (b + c). - let a = Fs::rand(&mut rng); - let b = Fs::rand(&mut rng); - let c = Fs::rand(&mut rng); - - let mut tmp1 = a; - tmp1.add_assign(&b); - tmp1.add_assign(&c); - - let mut tmp2 = b; - tmp2.add_assign(&c); - tmp2.add_assign(&a); - - assert!(tmp1.is_valid()); - assert!(tmp2.is_valid()); - assert_eq!(tmp1, tmp2); - } -} - -#[test] -fn test_fs_sub_assign() { - { - // Test arbitrary subtraction that tests reduction. - let mut tmp = Fs(FsRepr([0xb384d9f6877afd99, 0x4442513958e1a1c1, 0x352c4b8a95eccc3f, 0x2db62dee4b0f2])); - tmp.sub_assign(&Fs(FsRepr([0xec5bd2d13ed6b05a, 0x2adc0ab3a39b5fa, 0x82d3360a493e637e, 0x53ccff4a64d6679]))); - assert_eq!(tmp, Fs(FsRepr([0x97c015841f9b79f6, 0xe7fcb121eb6ffc49, 0xb8c050814de2a3c1, 0x943c0589dcafa21]))); - - // Test the opposite subtraction which doesn't test reduction. - tmp = Fs(FsRepr([0xec5bd2d13ed6b05a, 0x2adc0ab3a39b5fa, 0x82d3360a493e637e, 0x53ccff4a64d6679])); - tmp.sub_assign(&Fs(FsRepr([0xb384d9f6877afd99, 0x4442513958e1a1c1, 0x352c4b8a95eccc3f, 0x2db62dee4b0f2]))); - assert_eq!(tmp, Fs(FsRepr([0x38d6f8dab75bb2c1, 0xbe6b6f71e1581439, 0x4da6ea7fb351973e, 0x539f491c768b587]))); - - // Test for sensible results with zero - tmp = Fs(FsRepr::from(0)); - tmp.sub_assign(&Fs(FsRepr::from(0))); - assert!(tmp.is_zero()); - - tmp = Fs(FsRepr([0x361e16aef5cce835, 0x55bbde2536e274c1, 0x4dc77a63fd15ee75, 0x1e14bb37c14f230])); - tmp.sub_assign(&Fs(FsRepr::from(0))); - assert_eq!(tmp, Fs(FsRepr([0x361e16aef5cce835, 0x55bbde2536e274c1, 0x4dc77a63fd15ee75, 0x1e14bb37c14f230]))); - } - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Ensure that (a - b) + (b - a) = 0. - let a = Fs::rand(&mut rng); - let b = Fs::rand(&mut rng); - - let mut tmp1 = a; - tmp1.sub_assign(&b); - - let mut tmp2 = b; - tmp2.sub_assign(&a); - - tmp1.add_assign(&tmp2); - assert!(tmp1.is_zero()); - } -} - -#[test] -fn test_fs_mul_assign() { - let mut tmp = Fs(FsRepr([0xb433b01287f71744, 0x4eafb86728c4d108, 0xfdd52c14b9dfbe65, 0x2ff1f3434821118])); - tmp.mul_assign(&Fs(FsRepr([0xdae00fc63c9fa90f, 0x5a5ed89b96ce21ce, 0x913cd26101bd6f58, 0x3f0822831697fe9]))); - assert!(tmp == Fs(FsRepr([0xb68ecb61d54d2992, 0x5ff95874defce6a6, 0x3590eb053894657d, 0x53823a118515933]))); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000000 { - // Ensure that (a * b) * c = a * (b * c) - let a = Fs::rand(&mut rng); - let b = Fs::rand(&mut rng); - let c = Fs::rand(&mut rng); - - let mut tmp1 = a; - tmp1.mul_assign(&b); - tmp1.mul_assign(&c); - - let mut tmp2 = b; - tmp2.mul_assign(&c); - tmp2.mul_assign(&a); - - assert_eq!(tmp1, tmp2); - } - - for _ in 0..1000000 { - // Ensure that r * (a + b + c) = r*a + r*b + r*c - - let r = Fs::rand(&mut rng); - let mut a = Fs::rand(&mut rng); - let mut b = Fs::rand(&mut rng); - let mut c = Fs::rand(&mut rng); - - let mut tmp1 = a; - tmp1.add_assign(&b); - tmp1.add_assign(&c); - tmp1.mul_assign(&r); - - a.mul_assign(&r); - b.mul_assign(&r); - c.mul_assign(&r); - - a.add_assign(&b); - a.add_assign(&c); - - assert_eq!(tmp1, a); - } -} - -#[test] -fn test_fr_squaring() { - let mut a = Fs(FsRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xe7db4ea6533afa8])); - assert!(a.is_valid()); - a.square(); - assert_eq!(a, Fs::from_repr(FsRepr([0x12c7f55cbc52fbaa, 0xdedc98a0b5e6ce9e, 0xad2892726a5396a, 0x9fe82af8fee77b3])).unwrap()); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000000 { - // Ensure that (a * a) = a^2 - let a = Fs::rand(&mut rng); - - let mut tmp = a; - tmp.square(); - - let mut tmp2 = a; - tmp2.mul_assign(&a); - - assert_eq!(tmp, tmp2); - } -} - -#[test] -fn test_fs_inverse() { - assert!(Fs::zero().inverse().is_none()); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - let one = Fs::one(); - - for _ in 0..1000 { - // Ensure that a * a^-1 = 1 - let mut a = Fs::rand(&mut rng); - let ainv = a.inverse().unwrap(); - a.mul_assign(&ainv); - assert_eq!(a, one); - } -} - -#[test] -fn test_fs_double() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Ensure doubling a is equivalent to adding a to itself. - let mut a = Fs::rand(&mut rng); - let mut b = a; - b.add_assign(&a); - a.double(); - assert_eq!(a, b); - } -} - -#[test] -fn test_fs_negate() { - { - let mut a = Fs::zero(); - a.negate(); - - assert!(a.is_zero()); - } - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Ensure (a - (-a)) = 0. - let mut a = Fs::rand(&mut rng); - let mut b = a; - b.negate(); - a.add_assign(&b); - - assert!(a.is_zero()); - } -} - -#[test] -fn test_fs_pow() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for i in 0..1000 { - // Exponentiate by various small numbers and ensure it consists with repeated - // multiplication. - let a = Fs::rand(&mut rng); - let target = a.pow(&[i]); - let mut c = Fs::one(); - for _ in 0..i { - c.mul_assign(&a); - } - assert_eq!(c, target); - } - - for _ in 0..1000 { - // Exponentiating by the modulus should have no effect in a prime field. - let a = Fs::rand(&mut rng); - - assert_eq!(a, a.pow(Fs::char())); - } -} - -#[test] -fn test_fs_sqrt() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - assert_eq!(Fs::zero().sqrt().unwrap(), Fs::zero()); - - for _ in 0..1000 { - // Ensure sqrt(a^2) = a or -a - let a = Fs::rand(&mut rng); - let mut nega = a; - nega.negate(); - let mut b = a; - b.square(); - - let b = b.sqrt().unwrap(); - - assert!(a == b || nega == b); - } - - for _ in 0..1000 { - // Ensure sqrt(a)^2 = a for random a - let a = Fs::rand(&mut rng); - - if let Some(mut tmp) = a.sqrt() { - tmp.square(); - - assert_eq!(a, tmp); - } - } -} - -#[test] -fn test_fs_from_into_repr() { - // r + 1 should not be in the field - assert!(Fs::from_repr(FsRepr([0xd0970e5ed6f72cb8, 0xa6682093ccc81082, 0x6673b0101343b00, 0xe7db4ea6533afa9])).is_err()); - - // r should not be in the field - assert!(Fs::from_repr(Fs::char()).is_err()); - - // Multiply some arbitrary representations to see if the result is as expected. - let a = FsRepr([0x5f2d0c05d0337b71, 0xa1df2b0f8a20479, 0xad73785e71bb863, 0x504a00480c9acec]); - let mut a_fs = Fs::from_repr(a).unwrap(); - let b = FsRepr([0x66356ff51e477562, 0x60a92ab55cf7603, 0x8e4273c7364dd192, 0x36df8844a344dc5]); - let b_fs = Fs::from_repr(b).unwrap(); - let c = FsRepr([0x7eef61708f4f2868, 0x747a7e6cf52946fb, 0x83dd75d7c9120017, 0x762f5177f0f3df7]); - a_fs.mul_assign(&b_fs); - assert_eq!(a_fs.into_repr(), c); - - // Zero should be in the field. - assert!(Fs::from_repr(FsRepr::from(0)).unwrap().is_zero()); - - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - // Try to turn Fs elements into representations and back again, and compare. - let a = Fs::rand(&mut rng); - let a_repr = a.into_repr(); - let b_repr = FsRepr::from(a); - assert_eq!(a_repr, b_repr); - let a_again = Fs::from_repr(a_repr).unwrap(); - - assert_eq!(a, a_again); - } -} - -#[test] -fn test_fs_repr_display() { - assert_eq!( - format!("{}", FsRepr([0xa296db59787359df, 0x8d3e33077430d318, 0xd1abf5c606102eb7, 0xcbc33ee28108f0])), - "0x00cbc33ee28108f0d1abf5c606102eb78d3e33077430d318a296db59787359df".to_string() - ); - assert_eq!( - format!("{}", FsRepr([0x14cb03535054a620, 0x312aa2bf2d1dff52, 0x970fe98746ab9361, 0xc1e18acf82711e6])), - "0x0c1e18acf82711e6970fe98746ab9361312aa2bf2d1dff5214cb03535054a620".to_string() - ); - assert_eq!( - format!("{}", FsRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])), - "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string() - ); - assert_eq!( - format!("{}", FsRepr([0, 0, 0, 0])), - "0x0000000000000000000000000000000000000000000000000000000000000000".to_string() - ); -} - -#[test] -fn test_fs_display() { - assert_eq!( - format!("{}", Fs::from_repr(FsRepr([0x5528efb9998a01a3, 0x5bd2add5cb357089, 0xc061fa6adb491f98, 0x70db9d143db03d9])).unwrap()), - "Fs(0x070db9d143db03d9c061fa6adb491f985bd2add5cb3570895528efb9998a01a3)".to_string() - ); - assert_eq!( - format!("{}", Fs::from_repr(FsRepr([0xd674745e2717999e, 0xbeb1f52d3e96f338, 0x9c7ae147549482b9, 0x999706024530d22])).unwrap()), - "Fs(0x0999706024530d229c7ae147549482b9beb1f52d3e96f338d674745e2717999e)".to_string() - ); -} - -#[test] -fn test_fs_num_bits() { - assert_eq!(Fs::NUM_BITS, 252); - assert_eq!(Fs::CAPACITY, 251); -} - -#[test] -fn test_fs_root_of_unity() { - assert_eq!(Fs::S, 1); - assert_eq!(Fs::multiplicative_generator(), Fs::from_repr(FsRepr::from(6)).unwrap()); - assert_eq!( - Fs::multiplicative_generator().pow([0x684b872f6b7b965b, 0x53341049e6640841, 0x83339d80809a1d80, 0x73eda753299d7d4]), - Fs::root_of_unity() - ); - assert_eq!( - Fs::root_of_unity().pow([1 << Fs::S]), - Fs::one() - ); - assert!(Fs::multiplicative_generator().sqrt().is_none()); -} diff --git a/sapling-crypto/src/jubjub/mod.rs b/sapling-crypto/src/jubjub/mod.rs deleted file mode 100644 index 51a000a..0000000 --- a/sapling-crypto/src/jubjub/mod.rs +++ /dev/null @@ -1,435 +0,0 @@ -//! Jubjub is a twisted Edwards curve defined over the BLS12-381 scalar -//! field, Fr. It takes the form `-x^2 + y^2 = 1 + dx^2y^2` with -//! `d = -(10240/10241)`. It is birationally equivalent to a Montgomery -//! curve of the form `y^2 = x^3 + Ax^2 + x` with `A = 40962`. This -//! value `A` is the smallest integer choice such that: -//! -//! * `(A - 2) / 4` is a small integer (`10240`). -//! * `A^2 - 4` is quadratic nonresidue. -//! * The group order of the curve and its quadratic twist has a large -//! prime factor. -//! -//! Jubjub has `s = 0x0e7db4ea6533afa906673b0101343b00a6682093ccc81082d0970e5ed6f72cb7` -//! as the prime subgroup order, with cofactor 8. (The twist has -//! cofactor 4.) -//! -//! It is a complete twisted Edwards curve, so the equivalence with -//! the Montgomery curve forms a group isomorphism, allowing points -//! to be freely converted between the two forms. - -use pairing::{ - Engine, - Field, - PrimeField, - SqrtField -}; - -use group_hash::group_hash; - -use constants; - -use pairing::bls12_381::{ - Bls12, - Fr -}; - -/// This is an implementation of the twisted Edwards Jubjub curve. -pub mod edwards; - -/// This is an implementation of the birationally equivalent -/// Montgomery curve. -pub mod montgomery; - -/// This is an implementation of the scalar field for Jubjub. -pub mod fs; - -#[cfg(test)] -pub mod tests; - -/// Point of unknown order. -pub enum Unknown { } - -/// Point of prime order. -pub enum PrimeOrder { } - -/// Fixed generators of the Jubjub curve of unknown -/// exponent. -#[derive(Copy, Clone)] -pub enum FixedGenerators { - /// The prover will demonstrate knowledge of discrete log - /// with respect to this base when they are constructing - /// a proof, in order to authorize proof construction. - ProofGenerationKey = 0, - - /// The note commitment is randomized over this generator. - NoteCommitmentRandomness = 1, - - /// The node commitment is randomized again by the position - /// in order to supply the nullifier computation with a - /// unique input w.r.t. the note being spent, to prevent - /// Faerie gold attacks. - NullifierPosition = 2, - - /// The value commitment is used to check balance between - /// inputs and outputs. The value is placed over this - /// generator. - ValueCommitmentValue = 3, - /// The value commitment is randomized over this generator, - /// for privacy. - ValueCommitmentRandomness = 4, - - /// The spender proves discrete log with respect to this - /// base at spend time. - SpendingKeyGenerator = 5, - - Max = 6 -} - -pub trait ToUniform { - fn to_uniform(digest: &[u8]) -> Self; -} - -/// This is an extension to the pairing Engine trait which -/// offers a scalar field for the embedded curve (Jubjub) -/// and some pre-computed parameters. -pub trait JubjubEngine: Engine { - /// The scalar field of the Jubjub curve - type Fs: PrimeField + SqrtField + ToUniform; - /// The parameters of Jubjub and the Sapling protocol - type Params: JubjubParams; -} - -/// The pre-computed parameters for Jubjub, including curve -/// constants and various limits and window tables. -pub trait JubjubParams: Sized { - /// The `d` constant of the twisted Edwards curve. - fn edwards_d(&self) -> &E::Fr; - /// The `A` constant of the birationally equivalent Montgomery curve. - fn montgomery_a(&self) -> &E::Fr; - /// The `A` constant, doubled. - fn montgomery_2a(&self) -> &E::Fr; - /// The scaling factor used for conversion from the Montgomery form. - fn scale(&self) -> &E::Fr; - /// Returns the generators (for each segment) used in all Pedersen commitments. - fn pedersen_hash_generators(&self) -> &[edwards::Point]; - /// Returns the exp table for Pedersen hashes. - fn pedersen_hash_exp_table(&self) -> &[Vec>>]; - /// Returns the maximum number of chunks per segment of the Pedersen hash. - fn pedersen_hash_chunks_per_generator(&self) -> usize; - /// Returns the pre-computed window tables [-4, 3, 2, 1, 1, 2, 3, 4] of different - /// magnitudes of the Pedersen hash segment generators. - fn pedersen_circuit_generators(&self) -> &[Vec>]; - - /// Returns the number of chunks needed to represent a full scalar during fixed-base - /// exponentiation. - fn fixed_base_chunks_per_generator(&self) -> usize; - /// Returns a fixed generator. - fn generator(&self, base: FixedGenerators) -> &edwards::Point; - /// Returns a window table [0, 1, ..., 8] for different magnitudes of some - /// fixed generator. - fn circuit_generators(&self, FixedGenerators) -> &[Vec<(E::Fr, E::Fr)>]; - /// Returns the window size for exponentiation of Pedersen hash generators - /// outside the circuit - fn pedersen_hash_exp_window_size() -> u32; -} - -impl JubjubEngine for Bls12 { - type Fs = self::fs::Fs; - type Params = JubjubBls12; -} - -pub struct JubjubBls12 { - edwards_d: Fr, - montgomery_a: Fr, - montgomery_2a: Fr, - scale: Fr, - - pedersen_hash_generators: Vec>, - pedersen_hash_exp: Vec>>>, - pedersen_circuit_generators: Vec>>, - - fixed_base_generators: Vec>, - fixed_base_circuit_generators: Vec>>, -} - -impl JubjubParams for JubjubBls12 { - fn edwards_d(&self) -> &Fr { &self.edwards_d } - fn montgomery_a(&self) -> &Fr { &self.montgomery_a } - fn montgomery_2a(&self) -> &Fr { &self.montgomery_2a } - fn scale(&self) -> &Fr { &self.scale } - fn pedersen_hash_generators(&self) -> &[edwards::Point] { - &self.pedersen_hash_generators - } - fn pedersen_hash_exp_table(&self) -> &[Vec>>] { - &self.pedersen_hash_exp - } - fn pedersen_hash_chunks_per_generator(&self) -> usize { - 63 - } - fn fixed_base_chunks_per_generator(&self) -> usize { - 84 - } - fn pedersen_circuit_generators(&self) -> &[Vec>] { - &self.pedersen_circuit_generators - } - fn generator(&self, base: FixedGenerators) -> &edwards::Point - { - &self.fixed_base_generators[base as usize] - } - fn circuit_generators(&self, base: FixedGenerators) -> &[Vec<(Fr, Fr)>] - { - &self.fixed_base_circuit_generators[base as usize][..] - } - fn pedersen_hash_exp_window_size() -> u32 { - 8 - } -} - -impl JubjubBls12 { - pub fn new() -> Self { - let montgomery_a = Fr::from_str("40962").unwrap(); - let mut montgomery_2a = montgomery_a; - montgomery_2a.double(); - - let mut tmp_params = JubjubBls12 { - // d = -(10240/10241) - edwards_d: Fr::from_str("19257038036680949359750312669786877991949435402254120286184196891950884077233").unwrap(), - // A = 40962 - montgomery_a: montgomery_a, - // 2A = 2.A - montgomery_2a: montgomery_2a, - // scaling factor = sqrt(4 / (a - d)) - scale: Fr::from_str("17814886934372412843466061268024708274627479829237077604635722030778476050649").unwrap(), - - // We'll initialize these below - pedersen_hash_generators: vec![], - pedersen_hash_exp: vec![], - pedersen_circuit_generators: vec![], - fixed_base_generators: vec![], - fixed_base_circuit_generators: vec![], - }; - - fn find_group_hash( - m: &[u8], - personalization: &[u8; 8], - params: &E::Params - ) -> edwards::Point - { - let mut tag = m.to_vec(); - let i = tag.len(); - tag.push(0u8); - - loop { - let gh = group_hash( - &tag, - personalization, - params - ); - - // We don't want to overflow and start reusing generators - assert!(tag[i] != u8::max_value()); - tag[i] += 1; - - if let Some(gh) = gh { - break gh; - } - } - } - - // Create the bases for the Pedersen hashes - { - let mut pedersen_hash_generators = vec![]; - - for m in 0..5 { - use byteorder::{WriteBytesExt, LittleEndian}; - - let mut segment_number = [0u8; 4]; - (&mut segment_number[0..4]).write_u32::(m).unwrap(); - - pedersen_hash_generators.push( - find_group_hash( - &segment_number, - constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, - &tmp_params - ) - ); - } - - // Check for duplicates, far worse than spec inconsistencies! - for (i, p1) in pedersen_hash_generators.iter().enumerate() { - if p1 == &edwards::Point::zero() { - panic!("Neutral element!"); - } - - for p2 in pedersen_hash_generators.iter().skip(i+1) { - if p1 == p2 { - panic!("Duplicate generator!"); - } - } - } - - tmp_params.pedersen_hash_generators = pedersen_hash_generators; - } - - // Create the exp table for the Pedersen hash generators - { - let mut pedersen_hash_exp = vec![]; - - for g in &tmp_params.pedersen_hash_generators { - let mut g = g.clone(); - - let window = JubjubBls12::pedersen_hash_exp_window_size(); - - let mut tables = vec![]; - - let mut num_bits = 0; - while num_bits <= fs::Fs::NUM_BITS { - let mut table = Vec::with_capacity(1 << window); - - let mut base = edwards::Point::zero(); - - for _ in 0..(1 << window) { - table.push(base.clone()); - base = base.add(&g, &tmp_params); - } - - tables.push(table); - num_bits += window; - - for _ in 0..window { - g = g.double(&tmp_params); - } - } - - pedersen_hash_exp.push(tables); - } - - tmp_params.pedersen_hash_exp = pedersen_hash_exp; - } - - // Create the bases for other parts of the protocol - { - let mut fixed_base_generators = vec![edwards::Point::zero(); FixedGenerators::Max as usize]; - - fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] = - find_group_hash(&[], constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION, &tmp_params); - - fixed_base_generators[FixedGenerators::NoteCommitmentRandomness as usize] = - find_group_hash(b"r", constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, &tmp_params); - - fixed_base_generators[FixedGenerators::NullifierPosition as usize] = - find_group_hash(&[], constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION, &tmp_params); - - fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] = - find_group_hash(b"v", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params); - - fixed_base_generators[FixedGenerators::ValueCommitmentRandomness as usize] = - find_group_hash(b"r", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params); - - fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] = - find_group_hash(&[], constants::SPENDING_KEY_GENERATOR_PERSONALIZATION, &tmp_params); - - // Check for duplicates, far worse than spec inconsistencies! - for (i, p1) in fixed_base_generators.iter().enumerate() { - if p1 == &edwards::Point::zero() { - panic!("Neutral element!"); - } - - for p2 in fixed_base_generators.iter().skip(i+1) { - if p1 == p2 { - panic!("Duplicate generator!"); - } - } - } - - tmp_params.fixed_base_generators = fixed_base_generators; - } - - // Create the 2-bit window table lookups for each 4-bit - // "chunk" in each segment of the Pedersen hash - { - let mut pedersen_circuit_generators = vec![]; - - // Process each segment - for mut gen in tmp_params.pedersen_hash_generators.iter().cloned() { - let mut gen = montgomery::Point::from_edwards(&gen, &tmp_params); - let mut windows = vec![]; - for _ in 0..tmp_params.pedersen_hash_chunks_per_generator() { - // Create (x, y) coeffs for this chunk - let mut coeffs = vec![]; - let mut g = gen.clone(); - - // coeffs = g, g*2, g*3, g*4 - for _ in 0..4 { - coeffs.push(g.into_xy().expect("cannot produce O")); - g = g.add(&gen, &tmp_params); - } - windows.push(coeffs); - - // Our chunks are separated by 2 bits to prevent overlap. - for _ in 0..4 { - gen = gen.double(&tmp_params); - } - } - pedersen_circuit_generators.push(windows); - } - - tmp_params.pedersen_circuit_generators = pedersen_circuit_generators; - } - - // Create the 3-bit window table lookups for fixed-base - // exp of each base in the protocol. - { - let mut fixed_base_circuit_generators = vec![]; - - for mut gen in tmp_params.fixed_base_generators.iter().cloned() { - let mut windows = vec![]; - for _ in 0..tmp_params.fixed_base_chunks_per_generator() { - let mut coeffs = vec![(Fr::zero(), Fr::one())]; - let mut g = gen.clone(); - for _ in 0..7 { - coeffs.push(g.into_xy()); - g = g.add(&gen, &tmp_params); - } - windows.push(coeffs); - - // gen = gen * 8 - gen = g; - } - fixed_base_circuit_generators.push(windows); - } - - tmp_params.fixed_base_circuit_generators = fixed_base_circuit_generators; - } - - tmp_params - } -} - -#[test] -fn test_jubjub_bls12() { - let params = JubjubBls12::new(); - - tests::test_suite::(¶ms); - - let test_repr = hex!("9d12b88b08dcbef8a11ee0712d94cb236ee2f4ca17317075bfafc82ce3139d31"); - let p = edwards::Point::::read(&test_repr[..], ¶ms).unwrap(); - let q = edwards::Point::::get_for_y( - Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(), - false, - ¶ms - ).unwrap(); - - assert!(p == q); - - // Same thing, but sign bit set - let test_repr = hex!("9d12b88b08dcbef8a11ee0712d94cb236ee2f4ca17317075bfafc82ce3139db1"); - let p = edwards::Point::::read(&test_repr[..], ¶ms).unwrap(); - let q = edwards::Point::::get_for_y( - Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(), - true, - ¶ms - ).unwrap(); - - assert!(p == q); -} diff --git a/sapling-crypto/src/jubjub/montgomery.rs b/sapling-crypto/src/jubjub/montgomery.rs deleted file mode 100644 index 18d0fcb..0000000 --- a/sapling-crypto/src/jubjub/montgomery.rs +++ /dev/null @@ -1,358 +0,0 @@ -use pairing::{ - Field, - SqrtField, - PrimeField, - PrimeFieldRepr, - BitIterator -}; - -use super::{ - JubjubEngine, - JubjubParams, - Unknown, - PrimeOrder, - edwards -}; - -use rand::{ - Rng -}; - -use std::marker::PhantomData; - -// Represents the affine point (X, Y) -pub struct Point { - x: E::Fr, - y: E::Fr, - infinity: bool, - _marker: PhantomData -} - -fn convert_subgroup(from: &Point) -> Point -{ - Point { - x: from.x, - y: from.y, - infinity: from.infinity, - _marker: PhantomData - } -} - -impl From> for Point -{ - fn from(p: Point) -> Point - { - convert_subgroup(&p) - } -} - -impl Clone for Point -{ - fn clone(&self) -> Self { - convert_subgroup(self) - } -} - -impl PartialEq for Point { - fn eq(&self, other: &Point) -> bool { - match (self.infinity, other.infinity) { - (true, true) => true, - (true, false) | (false, true) => false, - (false, false) => { - self.x == other.x && self.y == other.y - } - } - } -} - -impl Point { - pub fn get_for_x(x: E::Fr, sign: bool, params: &E::Params) -> Option - { - // Given an x on the curve, y = sqrt(x^3 + A*x^2 + x) - - let mut x2 = x; - x2.square(); - - let mut rhs = x2; - rhs.mul_assign(params.montgomery_a()); - rhs.add_assign(&x); - x2.mul_assign(&x); - rhs.add_assign(&x2); - - match rhs.sqrt() { - Some(mut y) => { - if y.into_repr().is_odd() != sign { - y.negate(); - } - - return Some(Point { - x: x, - y: y, - infinity: false, - _marker: PhantomData - }) - }, - None => None - } - } - - /// This guarantees the point is in the prime order subgroup - #[must_use] - pub fn mul_by_cofactor(&self, params: &E::Params) -> Point - { - let tmp = self.double(params) - .double(params) - .double(params); - - convert_subgroup(&tmp) - } - - pub fn rand(rng: &mut R, params: &E::Params) -> Self - { - loop { - let x: E::Fr = rng.gen(); - - match Self::get_for_x(x, rng.gen(), params) { - Some(p) => { - return p - }, - None => {} - } - } - } -} - -impl Point { - /// Convert from an Edwards point - pub fn from_edwards( - e: &edwards::Point, - params: &E::Params - ) -> Self - { - let (x, y) = e.into_xy(); - - if y == E::Fr::one() { - // The only solution for y = 1 is x = 0. (0, 1) is - // the neutral element, so we map this to the point - // at infinity. - - Point::zero() - } else { - // The map from a twisted Edwards curve is defined as - // (x, y) -> (u, v) where - // u = (1 + y) / (1 - y) - // v = u / x - // - // This mapping is not defined for y = 1 and for x = 0. - // - // We have that y != 1 above. If x = 0, the only - // solutions for y are 1 (contradiction) or -1. - if x.is_zero() { - // (0, -1) is the point of order two which is not - // the neutral element, so we map it to (0, 0) which is - // the only affine point of order 2. - - Point { - x: E::Fr::zero(), - y: E::Fr::zero(), - infinity: false, - _marker: PhantomData - } - } else { - // The mapping is defined as above. - // - // (x, y) -> (u, v) where - // u = (1 + y) / (1 - y) - // v = u / x - - let mut u = E::Fr::one(); - u.add_assign(&y); - { - let mut tmp = E::Fr::one(); - tmp.sub_assign(&y); - u.mul_assign(&tmp.inverse().unwrap()) - } - - let mut v = u; - v.mul_assign(&x.inverse().unwrap()); - - // Scale it into the correct curve constants - v.mul_assign(params.scale()); - - Point { - x: u, - y: v, - infinity: false, - _marker: PhantomData - } - } - } - } - - /// Attempts to cast this as a prime order element, failing if it's - /// not in the prime order subgroup. - pub fn as_prime_order(&self, params: &E::Params) -> Option> { - if self.mul(E::Fs::char(), params) == Point::zero() { - Some(convert_subgroup(self)) - } else { - None - } - } - - pub fn zero() -> Self { - Point { - x: E::Fr::zero(), - y: E::Fr::zero(), - infinity: true, - _marker: PhantomData - } - } - - pub fn into_xy(&self) -> Option<(E::Fr, E::Fr)> - { - if self.infinity { - None - } else { - Some((self.x, self.y)) - } - } - - #[must_use] - pub fn negate(&self) -> Self { - let mut p = self.clone(); - - p.y.negate(); - - p - } - - #[must_use] - pub fn double(&self, params: &E::Params) -> Self { - if self.infinity { - return Point::zero(); - } - - // (0, 0) is the point of order 2. Doubling - // produces the point at infinity. - if self.y == E::Fr::zero() { - return Point::zero(); - } - - // This is a standard affine point doubling formula - // See 4.3.2 The group law for Weierstrass curves - // Montgomery curves and the Montgomery Ladder - // Daniel J. Bernstein and Tanja Lange - - let mut delta = E::Fr::one(); - { - let mut tmp = params.montgomery_a().clone(); - tmp.mul_assign(&self.x); - tmp.double(); - delta.add_assign(&tmp); - } - { - let mut tmp = self.x; - tmp.square(); - delta.add_assign(&tmp); - tmp.double(); - delta.add_assign(&tmp); - } - { - let mut tmp = self.y; - tmp.double(); - delta.mul_assign(&tmp.inverse().expect("y is nonzero so this must be nonzero")); - } - - let mut x3 = delta; - x3.square(); - x3.sub_assign(params.montgomery_a()); - x3.sub_assign(&self.x); - x3.sub_assign(&self.x); - - let mut y3 = x3; - y3.sub_assign(&self.x); - y3.mul_assign(&delta); - y3.add_assign(&self.y); - y3.negate(); - - Point { - x: x3, - y: y3, - infinity: false, - _marker: PhantomData - } - } - - #[must_use] - pub fn add(&self, other: &Self, params: &E::Params) -> Self - { - // This is a standard affine point addition formula - // See 4.3.2 The group law for Weierstrass curves - // Montgomery curves and the Montgomery Ladder - // Daniel J. Bernstein and Tanja Lange - - match (self.infinity, other.infinity) { - (true, true) => Point::zero(), - (true, false) => other.clone(), - (false, true) => self.clone(), - (false, false) => { - if self.x == other.x { - if self.y == other.y { - self.double(params) - } else { - Point::zero() - } - } else { - let mut delta = other.y; - delta.sub_assign(&self.y); - { - let mut tmp = other.x; - tmp.sub_assign(&self.x); - delta.mul_assign(&tmp.inverse().expect("self.x != other.x, so this must be nonzero")); - } - - let mut x3 = delta; - x3.square(); - x3.sub_assign(params.montgomery_a()); - x3.sub_assign(&self.x); - x3.sub_assign(&other.x); - - let mut y3 = x3; - y3.sub_assign(&self.x); - y3.mul_assign(&delta); - y3.add_assign(&self.y); - y3.negate(); - - Point { - x: x3, - y: y3, - infinity: false, - _marker: PhantomData - } - } - } - } - } - - #[must_use] - pub fn mul::Repr>>( - &self, - scalar: S, - params: &E::Params - ) -> Self - { - // Standard double-and-add scalar multiplication - - let mut res = Self::zero(); - - for b in BitIterator::new(scalar.into()) { - res = res.double(params); - - if b { - res = res.add(self, params); - } - } - - res - } -} diff --git a/sapling-crypto/src/jubjub/tests.rs b/sapling-crypto/src/jubjub/tests.rs deleted file mode 100644 index 421a8f7..0000000 --- a/sapling-crypto/src/jubjub/tests.rs +++ /dev/null @@ -1,416 +0,0 @@ -use super::{ - JubjubEngine, - JubjubParams, - PrimeOrder, - montgomery, - edwards -}; - -use pairing::{ - Field, - PrimeField, - PrimeFieldRepr, - SqrtField, - LegendreSymbol -}; - -use rand::{XorShiftRng, SeedableRng, Rand}; - -pub fn test_suite(params: &E::Params) { - test_back_and_forth::(params); - test_jubjub_params::(params); - test_rand::(params); - test_get_for::(params); - test_identities::(params); - test_addition_associativity::(params); - test_order::(params); - test_mul_associativity::(params); - test_loworder::(params); - test_read_write::(params); -} - -fn is_on_mont_curve>( - x: E::Fr, - y: E::Fr, - params: &P -) -> bool -{ - let mut lhs = y; - lhs.square(); - - let mut x2 = x; - x2.square(); - - let mut x3 = x2; - x3.mul_assign(&x); - - let mut rhs = x2; - rhs.mul_assign(params.montgomery_a()); - rhs.add_assign(&x); - rhs.add_assign(&x3); - - lhs == rhs -} - -fn is_on_twisted_edwards_curve>( - x: E::Fr, - y: E::Fr, - params: &P -) -> bool -{ - let mut x2 = x; - x2.square(); - - let mut y2 = y; - y2.square(); - - // -x^2 + y^2 - let mut lhs = y2; - lhs.sub_assign(&x2); - - // 1 + d x^2 y^2 - let mut rhs = y2; - rhs.mul_assign(&x2); - rhs.mul_assign(params.edwards_d()); - rhs.add_assign(&E::Fr::one()); - - lhs == rhs -} - -fn test_loworder(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - let inf = montgomery::Point::zero(); - - // try to find a point of order 8 - let p = loop { - let r = montgomery::Point::::rand(rng, params).mul(E::Fs::char(), params); - - let r2 = r.double(params); - let r4 = r2.double(params); - let r8 = r4.double(params); - - if r2 != inf && r4 != inf && r8 == inf { - break r; - } - }; - - let mut loworder_points = vec![]; - { - let mut tmp = p.clone(); - - for _ in 0..8 { - assert!(!loworder_points.contains(&tmp)); - loworder_points.push(tmp.clone()); - tmp = tmp.add(&p, params); - } - } - assert!(loworder_points[7] == inf); -} - -fn test_mul_associativity(params: &E::Params) { - use self::edwards::Point; - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..100 { - // Pick a random point and multiply it by the cofactor - let base = Point::::rand(rng, params).mul_by_cofactor(params); - - let mut a = E::Fs::rand(rng); - let b = E::Fs::rand(rng); - let c = E::Fs::rand(rng); - - let res1 = base.mul(a, params).mul(b, params).mul(c, params); - let res2 = base.mul(b, params).mul(c, params).mul(a, params); - let res3 = base.mul(c, params).mul(a, params).mul(b, params); - a.mul_assign(&b); - a.mul_assign(&c); - let res4 = base.mul(a, params); - - assert!(res1 == res2); - assert!(res2 == res3); - assert!(res3 == res4); - - let (x, y) = res1.into_xy(); - assert!(is_on_twisted_edwards_curve(x, y, params)); - - let (x, y) = res2.into_xy(); - assert!(is_on_twisted_edwards_curve(x, y, params)); - - let (x, y) = res3.into_xy(); - assert!(is_on_twisted_edwards_curve(x, y, params)); - } -} - -fn test_order(params: &E::Params) { - use self::edwards::Point; - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - // The neutral element is in the prime order subgroup. - assert!(Point::::zero().as_prime_order(params).is_some()); - - for _ in 0..50 { - // Pick a random point and multiply it by the cofactor - let base = Point::::rand(rng, params).mul_by_cofactor(params); - - // Any point multiplied by the cofactor will be in the prime - // order subgroup - assert!(base.as_prime_order(params).is_some()); - } - - // It's very likely that at least one out of 50 random points on the curve - // is not in the prime order subgroup. - let mut at_least_one_not_in_prime_order_subgroup = false; - for _ in 0..50 { - // Pick a random point. - let base = Point::::rand(rng, params); - - at_least_one_not_in_prime_order_subgroup |= base.as_prime_order(params).is_none(); - } - assert!(at_least_one_not_in_prime_order_subgroup); -} - -fn test_addition_associativity(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - use self::montgomery::Point; - - let a = Point::::rand(rng, params); - let b = Point::::rand(rng, params); - let c = Point::::rand(rng, params); - - assert!(a.add(&b, ¶ms).add(&c, ¶ms) == c.add(&a, ¶ms).add(&b, ¶ms)); - } - - for _ in 0..1000 { - use self::edwards::Point; - - let a = Point::::rand(rng, params); - let b = Point::::rand(rng, params); - let c = Point::::rand(rng, params); - - assert!(a.add(&b, ¶ms).add(&c, ¶ms) == c.add(&a, ¶ms).add(&b, ¶ms)); - } -} - -fn test_identities(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - { - use self::edwards::Point; - - let z = Point::::zero(); - assert!(z.double(¶ms) == z); - assert!(z.negate() == z); - - for _ in 0..100 { - let r = Point::::rand(rng, params); - - assert!(r.add(&Point::zero(), ¶ms) == r); - assert!(r.add(&r.negate(), ¶ms) == Point::zero()); - } - } - - { - use self::montgomery::Point; - - let z = Point::::zero(); - assert!(z.double(¶ms) == z); - assert!(z.negate() == z); - - for _ in 0..100 { - let r = Point::::rand(rng, params); - - assert!(r.add(&Point::zero(), ¶ms) == r); - assert!(r.add(&r.negate(), ¶ms) == Point::zero()); - } - } -} - -fn test_get_for(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let y = E::Fr::rand(rng); - let sign = bool::rand(rng); - - if let Some(mut p) = edwards::Point::::get_for_y(y, sign, params) { - assert!(p.into_xy().0.into_repr().is_odd() == sign); - p = p.negate(); - assert!( - edwards::Point::::get_for_y(y, !sign, params).unwrap() - == - p - ); - } - } -} - -fn test_read_write(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let e = edwards::Point::::rand(rng, params); - - let mut v = vec![]; - e.write(&mut v).unwrap(); - - let e2 = edwards::Point::read(&v[..], params).unwrap(); - - assert!(e == e2); - } -} - -fn test_rand(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let p = montgomery::Point::::rand(rng, params); - let e = edwards::Point::::rand(rng, params); - - { - let (x, y) = p.into_xy().unwrap(); - assert!(is_on_mont_curve(x, y, params)); - } - - { - let (x, y) = e.into_xy(); - assert!(is_on_twisted_edwards_curve(x, y, params)); - } - } -} - -fn test_back_and_forth(params: &E::Params) { - let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); - - for _ in 0..1000 { - let s = E::Fs::rand(rng); - let edwards_p1 = edwards::Point::::rand(rng, params); - let mont_p1 = montgomery::Point::from_edwards(&edwards_p1, params); - let mont_p2 = montgomery::Point::::rand(rng, params); - let edwards_p2 = edwards::Point::from_montgomery(&mont_p2, params); - - let mont = mont_p1.add(&mont_p2, params).mul(s, params); - let edwards = edwards_p1.add(&edwards_p2, params).mul(s, params); - - assert!( - montgomery::Point::from_edwards(&edwards, params) == mont - ); - - assert!( - edwards::Point::from_montgomery(&mont, params) == edwards - ); - } -} - -fn test_jubjub_params(params: &E::Params) { - // a = -1 - let mut a = E::Fr::one(); - a.negate(); - - { - // Check that 2A is consistent with A - let mut tmp = *params.montgomery_a(); - tmp.double(); - - assert_eq!(&tmp, params.montgomery_2a()); - } - - { - // The twisted Edwards addition law is complete when d is nonsquare - // and a is square. - - assert!(params.edwards_d().legendre() == LegendreSymbol::QuadraticNonResidue); - assert!(a.legendre() == LegendreSymbol::QuadraticResidue); - } - - { - // Other convenient sanity checks regarding d - - // tmp = d - let mut tmp = *params.edwards_d(); - - // 1 / d is nonsquare - assert!(tmp.inverse().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue); - - // tmp = -d - tmp.negate(); - - // -d is nonsquare - assert!(tmp.legendre() == LegendreSymbol::QuadraticNonResidue); - - // 1 / -d is nonsquare - assert!(tmp.inverse().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue); - } - - { - // Check that A^2 - 4 is nonsquare: - let mut tmp = params.montgomery_a().clone(); - tmp.square(); - tmp.sub_assign(&E::Fr::from_str("4").unwrap()); - assert!(tmp.legendre() == LegendreSymbol::QuadraticNonResidue); - } - - { - // Check that A - 2 is nonsquare: - let mut tmp = params.montgomery_a().clone(); - tmp.sub_assign(&E::Fr::from_str("2").unwrap()); - assert!(tmp.legendre() == LegendreSymbol::QuadraticNonResidue); - } - - { - // Check the validity of the scaling factor - let mut tmp = a; - tmp.sub_assign(¶ms.edwards_d()); - tmp = tmp.inverse().unwrap(); - tmp.mul_assign(&E::Fr::from_str("4").unwrap()); - tmp = tmp.sqrt().unwrap(); - assert_eq!(&tmp, params.scale()); - } - - { - // Check that the number of windows per generator - // in the Pedersen hash does not allow for collisions - - let mut cur = E::Fs::one().into_repr(); - - let mut max = E::Fs::char(); - { - max.sub_noborrow(&E::Fs::one().into_repr()); - max.div2(); - } - - let mut pacc = E::Fs::zero().into_repr(); - let mut nacc = E::Fs::char(); - - for _ in 0..params.pedersen_hash_chunks_per_generator() - { - // tmp = cur * 4 - let mut tmp = cur; - tmp.mul2(); - tmp.mul2(); - - pacc.add_nocarry(&tmp); - nacc.sub_noborrow(&tmp); - - assert!(pacc < max); - assert!(pacc < nacc); - - // cur = cur * 16 - for _ in 0..4 { - cur.mul2(); - } - } - } - - { - // Check that the number of windows for fixed-base - // scalar multiplication is sufficient for all scalars. - - assert!(params.fixed_base_chunks_per_generator() * 3 >= E::Fs::NUM_BITS as usize); - - // ... and that it's *just* efficient enough. - - assert!((params.fixed_base_chunks_per_generator() - 1) * 3 < E::Fs::NUM_BITS as usize); - } -} diff --git a/sapling-crypto/src/lib.rs b/sapling-crypto/src/lib.rs deleted file mode 100644 index 27d306c..0000000 --- a/sapling-crypto/src/lib.rs +++ /dev/null @@ -1,22 +0,0 @@ -extern crate pairing; -extern crate bellman; -extern crate blake2_rfc; -extern crate digest; -extern crate rand; -extern crate byteorder; - -#[cfg(test)] -#[macro_use] -extern crate hex_literal; - -#[cfg(test)] -extern crate crypto; - -pub mod jubjub; -pub mod group_hash; -pub mod circuit; -pub mod pedersen_hash; -pub mod primitives; -pub mod constants; -pub mod redjubjub; -pub mod util; diff --git a/sapling-crypto/src/pedersen_hash.rs b/sapling-crypto/src/pedersen_hash.rs deleted file mode 100644 index 0590a5c..0000000 --- a/sapling-crypto/src/pedersen_hash.rs +++ /dev/null @@ -1,103 +0,0 @@ -use jubjub::*; -use pairing::*; - -#[derive(Copy, Clone)] -pub enum Personalization { - NoteCommitment, - MerkleTree(usize) -} - -impl Personalization { - pub fn get_bits(&self) -> Vec { - match *self { - Personalization::NoteCommitment => - vec![true, true, true, true, true, true], - Personalization::MerkleTree(num) => { - assert!(num < 63); - - (0..6).map(|i| (num >> i) & 1 == 1).collect() - } - } - } -} - -pub fn pedersen_hash( - personalization: Personalization, - bits: I, - params: &E::Params -) -> edwards::Point - where I: IntoIterator, - E: JubjubEngine -{ - let mut bits = personalization.get_bits().into_iter().chain(bits.into_iter()); - - let mut result = edwards::Point::zero(); - let mut generators = params.pedersen_hash_exp_table().iter(); - - loop { - let mut acc = E::Fs::zero(); - let mut cur = E::Fs::one(); - let mut chunks_remaining = params.pedersen_hash_chunks_per_generator(); - let mut encountered_bits = false; - - // Grab three bits from the input - while let Some(a) = bits.next() { - encountered_bits = true; - - let b = bits.next().unwrap_or(false); - let c = bits.next().unwrap_or(false); - - // Start computing this portion of the scalar - let mut tmp = cur; - if a { - tmp.add_assign(&cur); - } - cur.double(); // 2^1 * cur - if b { - tmp.add_assign(&cur); - } - - // conditionally negate - if c { - tmp.negate(); - } - - acc.add_assign(&tmp); - - chunks_remaining -= 1; - - if chunks_remaining == 0 { - break; - } else { - cur.double(); // 2^2 * cur - cur.double(); // 2^3 * cur - cur.double(); // 2^4 * cur - } - } - - if !encountered_bits { - break; - } - - let mut table: &[Vec>] = &generators.next().expect("we don't have enough generators"); - let window = JubjubBls12::pedersen_hash_exp_window_size(); - let window_mask = (1 << window) - 1; - - let mut acc = acc.into_repr(); - - let mut tmp = edwards::Point::zero(); - - while !acc.is_zero() { - let i = (acc.as_ref()[0] & window_mask) as usize; - - tmp = tmp.add(&table[0][i], params); - - acc.shr(window); - table = &table[1..]; - } - - result = result.add(&tmp, params); - } - - result -} diff --git a/sapling-crypto/src/primitives/mod.rs b/sapling-crypto/src/primitives/mod.rs deleted file mode 100644 index 26dafab..0000000 --- a/sapling-crypto/src/primitives/mod.rs +++ /dev/null @@ -1,258 +0,0 @@ -use pairing::{ - Field, - PrimeField, - PrimeFieldRepr -}; - -use constants; - -use group_hash::group_hash; - -use pedersen_hash::{ - pedersen_hash, - Personalization -}; - -use byteorder::{ - LittleEndian, - WriteBytesExt -}; - -use jubjub::{ - JubjubEngine, - JubjubParams, - edwards, - PrimeOrder, - FixedGenerators -}; - -use blake2_rfc::blake2s::Blake2s; - -#[derive(Clone)] -pub struct ValueCommitment { - pub value: u64, - pub randomness: E::Fs -} - -impl ValueCommitment { - pub fn cm( - &self, - params: &E::Params - ) -> edwards::Point - { - params.generator(FixedGenerators::ValueCommitmentValue) - .mul(self.value, params) - .add( - ¶ms.generator(FixedGenerators::ValueCommitmentRandomness) - .mul(self.randomness, params), - params - ) - } -} - -#[derive(Clone)] -pub struct ProofGenerationKey { - pub ak: edwards::Point, - pub nsk: E::Fs -} - -impl ProofGenerationKey { - pub fn into_viewing_key(&self, params: &E::Params) -> ViewingKey { - ViewingKey { - ak: self.ak.clone(), - nk: params.generator(FixedGenerators::ProofGenerationKey) - .mul(self.nsk, params) - } - } -} - -pub struct ViewingKey { - pub ak: edwards::Point, - pub nk: edwards::Point -} - -impl ViewingKey { - pub fn rk( - &self, - ar: E::Fs, - params: &E::Params - ) -> edwards::Point { - self.ak.add( - ¶ms.generator(FixedGenerators::SpendingKeyGenerator) - .mul(ar, params), - params - ) - } - - pub fn ivk(&self) -> E::Fs { - let mut preimage = [0; 64]; - - self.ak.write(&mut preimage[0..32]).unwrap(); - self.nk.write(&mut preimage[32..64]).unwrap(); - - let mut h = Blake2s::with_params(32, &[], &[], constants::CRH_IVK_PERSONALIZATION); - h.update(&preimage); - let mut h = h.finalize().as_ref().to_vec(); - - // Drop the most significant five bits, so it can be interpreted as a scalar. - h[31] &= 0b0000_0111; - - let mut e = ::Repr::default(); - e.read_le(&h[..]).unwrap(); - - E::Fs::from_repr(e).expect("should be a valid scalar") - } - - pub fn into_payment_address( - &self, - diversifier: Diversifier, - params: &E::Params - ) -> Option> - { - diversifier.g_d(params).map(|g_d| { - let pk_d = g_d.mul(self.ivk(), params); - - PaymentAddress { - pk_d: pk_d, - diversifier: diversifier - } - }) - } -} - -#[derive(Copy, Clone)] -pub struct Diversifier(pub [u8; 11]); - -impl Diversifier { - pub fn g_d( - &self, - params: &E::Params - ) -> Option> - { - group_hash::(&self.0, constants::KEY_DIVERSIFICATION_PERSONALIZATION, params) - } -} - -#[derive(Clone)] -pub struct PaymentAddress { - pub pk_d: edwards::Point, - pub diversifier: Diversifier -} - -impl PaymentAddress { - pub fn g_d( - &self, - params: &E::Params - ) -> Option> - { - self.diversifier.g_d(params) - } - - pub fn create_note( - &self, - value: u64, - randomness: E::Fs, - params: &E::Params - ) -> Option> - { - self.g_d(params).map(|g_d| { - Note { - value: value, - r: randomness, - g_d: g_d, - pk_d: self.pk_d.clone() - } - }) - } -} - -pub struct Note { - /// The value of the note - pub value: u64, - /// The diversified base of the address, GH(d) - pub g_d: edwards::Point, - /// The public key of the address, g_d^ivk - pub pk_d: edwards::Point, - /// The commitment randomness - pub r: E::Fs -} - -impl Note { - pub fn uncommitted() -> E::Fr { - // The smallest u-coordinate that is not on the curve - // is one. - // TODO: This should be relocated to JubjubEngine as - // it's specific to the curve we're using, not all - // twisted edwards curves. - E::Fr::one() - } - - /// Computes the note commitment, returning the full point. - fn cm_full_point(&self, params: &E::Params) -> edwards::Point - { - // Calculate the note contents, as bytes - let mut note_contents = vec![]; - - // Writing the value in little endian - (&mut note_contents).write_u64::(self.value).unwrap(); - - // Write g_d - self.g_d.write(&mut note_contents).unwrap(); - - // Write pk_d - self.pk_d.write(&mut note_contents).unwrap(); - - assert_eq!(note_contents.len(), 32 + 32 + 8); - - // Compute the Pedersen hash of the note contents - let hash_of_contents = pedersen_hash( - Personalization::NoteCommitment, - note_contents.into_iter() - .flat_map(|byte| { - (0..8).map(move |i| ((byte >> i) & 1) == 1) - }), - params - ); - - // Compute final commitment - params.generator(FixedGenerators::NoteCommitmentRandomness) - .mul(self.r, params) - .add(&hash_of_contents, params) - } - - /// Computes the nullifier given the viewing key and - /// note position - pub fn nf( - &self, - viewing_key: &ViewingKey, - position: u64, - params: &E::Params - ) -> Vec - { - // Compute rho = cm + position.G - let rho = self - .cm_full_point(params) - .add( - ¶ms.generator(FixedGenerators::NullifierPosition) - .mul(position, params), - params - ); - - // Compute nf = BLAKE2s(nk | rho) - let mut nf_preimage = [0u8; 64]; - viewing_key.nk.write(&mut nf_preimage[0..32]).unwrap(); - rho.write(&mut nf_preimage[32..64]).unwrap(); - let mut h = Blake2s::with_params(32, &[], &[], constants::PRF_NF_PERSONALIZATION); - h.update(&nf_preimage); - - h.finalize().as_ref().to_vec() - } - - /// Computes the note commitment - pub fn cm(&self, params: &E::Params) -> E::Fr - { - // The commitment is in the prime order subgroup, so mapping the - // commitment to the x-coordinate is an injective encoding. - self.cm_full_point(params).into_xy().0 - } -} diff --git a/sapling-crypto/src/redjubjub.rs b/sapling-crypto/src/redjubjub.rs deleted file mode 100644 index dfae28c..0000000 --- a/sapling-crypto/src/redjubjub.rs +++ /dev/null @@ -1,343 +0,0 @@ -//! Implementation of RedJubjub, a specialization of RedDSA to the Jubjub curve. -//! See section 5.4.6 of the Sapling protocol specification. - -use pairing::{Field, PrimeField, PrimeFieldRepr}; -use rand::{Rng, Rand}; -use std::io::{self, Read, Write}; - -use jubjub::{FixedGenerators, JubjubEngine, JubjubParams, Unknown, edwards::Point}; -use util::{hash_to_scalar}; - -fn read_scalar(reader: R) -> io::Result { - let mut s_repr = ::Repr::default(); - s_repr.read_le(reader)?; - - match E::Fs::from_repr(s_repr) { - Ok(s) => Ok(s), - Err(_) => Err(io::Error::new( - io::ErrorKind::InvalidInput, - "scalar is not in field", - )), - } -} - -fn write_scalar(s: &E::Fs, writer: W) -> io::Result<()> { - s.into_repr().write_le(writer) -} - -fn h_star(a: &[u8], b: &[u8]) -> E::Fs { - hash_to_scalar::(b"Zcash_RedJubjubH", a, b) -} - -#[derive(Copy, Clone)] -pub struct Signature { - rbar: [u8; 32], - sbar: [u8; 32], -} - -pub struct PrivateKey(pub E::Fs); - -pub struct PublicKey(pub Point); - -impl Signature { - pub fn read(mut reader: R) -> io::Result { - let mut rbar = [0u8; 32]; - let mut sbar = [0u8; 32]; - reader.read_exact(&mut rbar)?; - reader.read_exact(&mut sbar)?; - Ok(Signature { rbar, sbar }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_all(&self.rbar)?; - writer.write_all(&self.sbar) - } -} - -impl PrivateKey { - pub fn randomize(&self, alpha: E::Fs) -> Self { - let mut tmp = self.0; - tmp.add_assign(&alpha); - PrivateKey(tmp) - } - - pub fn read(reader: R) -> io::Result { - let pk = read_scalar::(reader)?; - Ok(PrivateKey(pk)) - } - - pub fn write(&self, writer: W) -> io::Result<()> { - write_scalar::(&self.0, writer) - } - - pub fn sign( - &self, - msg: &[u8], - rng: &mut R, - p_g: FixedGenerators, - params: &E::Params, - ) -> Signature { - // T = (l_H + 128) bits of randomness - // For H*, l_H = 512 bits - let mut t = [0u8; 80]; - rng.fill_bytes(&mut t[..]); - - // r = H*(T || M) - let r = h_star::(&t[..], msg); - - // R = r . P_G - let r_g = params.generator(p_g).mul(r, params); - let mut rbar = [0u8; 32]; - r_g.write(&mut rbar[..]) - .expect("Jubjub points should serialize to 32 bytes"); - - // S = r + H*(Rbar || M) . sk - let mut s = h_star::(&rbar[..], msg); - s.mul_assign(&self.0); - s.add_assign(&r); - let mut sbar = [0u8; 32]; - write_scalar::(&s, &mut sbar[..]) - .expect("Jubjub scalars should serialize to 32 bytes"); - - Signature { rbar, sbar } - } -} - -impl PublicKey { - pub fn from_private(privkey: &PrivateKey, p_g: FixedGenerators, params: &E::Params) -> Self { - let res = params.generator(p_g).mul(privkey.0, params).into(); - PublicKey(res) - } - - pub fn randomize(&self, alpha: E::Fs, p_g: FixedGenerators, params: &E::Params) -> Self { - let res: Point = params.generator(p_g).mul(alpha, params).into(); - let res = res.add(&self.0, params); - PublicKey(res) - } - - pub fn read(reader: R, params: &E::Params) -> io::Result { - let p = Point::read(reader, params)?; - Ok(PublicKey(p)) - } - - pub fn write(&self, writer: W) -> io::Result<()> { - self.0.write(writer) - } - - pub fn verify( - &self, - msg: &[u8], - sig: &Signature, - p_g: FixedGenerators, - params: &E::Params, - ) -> bool { - // c = H*(Rbar || M) - let c = h_star::(&sig.rbar[..], msg); - - // Signature checks: - // R != invalid - let r = match Point::read(&sig.rbar[..], params) { - Ok(r) => r, - Err(_) => return false, - }; - // S < order(G) - // (E::Fs guarantees its representation is in the field) - let s = match read_scalar::(&sig.sbar[..]) { - Ok(s) => s, - Err(_) => return false, - }; - // 0 = h_G(-S . P_G + R + c . vk) - self.0.mul(c, params).add(&r, params).add( - ¶ms.generator(p_g).mul(s, params).negate().into(), - params - ).mul_by_cofactor(params).eq(&Point::zero()) - } -} - -pub struct BatchEntry<'a, E: JubjubEngine> { - vk: PublicKey, - msg: &'a [u8], - sig: Signature, -} - -// TODO: #82: This is a naive implementation currently, -// and doesn't use multiexp. -pub fn batch_verify<'a, E: JubjubEngine, R: Rng>( - rng: &mut R, - batch: &[BatchEntry<'a, E>], - p_g: FixedGenerators, - params: &E::Params, -) -> bool -{ - let mut acc = Point::::zero(); - - for entry in batch { - let mut r = match Point::::read(&entry.sig.rbar[..], params) { - Ok(r) => r, - Err(_) => return false, - }; - let mut s = match read_scalar::(&entry.sig.sbar[..]) { - Ok(s) => s, - Err(_) => return false, - }; - - let mut c = h_star::(&entry.sig.rbar[..], entry.msg); - - let z = E::Fs::rand(rng); - - s.mul_assign(&z); - s.negate(); - - r = r.mul(z, params); - - c.mul_assign(&z); - - acc = acc.add(&r, params); - acc = acc.add(&entry.vk.0.mul(c, params), params); - acc = acc.add(¶ms.generator(p_g).mul(s, params).into(), params); - } - - acc = acc.mul_by_cofactor(params).into(); - - acc.eq(&Point::zero()) -} - -#[cfg(test)] -mod tests { - use pairing::bls12_381::Bls12; - use rand::thread_rng; - - use jubjub::{JubjubBls12, fs::Fs, edwards}; - - use super::*; - - #[test] - fn test_batch_verify() { - let rng = &mut thread_rng(); - let params = &JubjubBls12::new(); - let p_g = FixedGenerators::SpendingKeyGenerator; - - let sk1 = PrivateKey::(rng.gen()); - let vk1 = PublicKey::from_private(&sk1, p_g, params); - let msg1 = b"Foo bar"; - let sig1 = sk1.sign(msg1, rng, p_g, params); - assert!(vk1.verify(msg1, &sig1, p_g, params)); - - let sk2 = PrivateKey::(rng.gen()); - let vk2 = PublicKey::from_private(&sk2, p_g, params); - let msg2 = b"Foo bar"; - let sig2 = sk2.sign(msg2, rng, p_g, params); - assert!(vk2.verify(msg2, &sig2, p_g, params)); - - let mut batch = vec![ - BatchEntry { vk: vk1, msg: msg1, sig: sig1 }, - BatchEntry { vk: vk2, msg: msg2, sig: sig2 } - ]; - - assert!(batch_verify(rng, &batch, p_g, params)); - - batch[0].sig = sig2; - - assert!(!batch_verify(rng, &batch, p_g, params)); - } - - #[test] - fn cofactor_check() { - let rng = &mut thread_rng(); - let params = &JubjubBls12::new(); - let zero = edwards::Point::zero(); - let p_g = FixedGenerators::SpendingKeyGenerator; - - // Get a point of order 8 - let p8 = loop { - let r = edwards::Point::::rand(rng, params).mul(Fs::char(), params); - - let r2 = r.double(params); - let r4 = r2.double(params); - let r8 = r4.double(params); - - if r2 != zero && r4 != zero && r8 == zero { - break r; - } - }; - - let sk = PrivateKey::(rng.gen()); - let vk = PublicKey::from_private(&sk, p_g, params); - - // TODO: This test will need to change when #77 is fixed - let msg = b"Foo bar"; - let sig = sk.sign(msg, rng, p_g, params); - assert!(vk.verify(msg, &sig, p_g, params)); - - let vktorsion = PublicKey(vk.0.add(&p8, params)); - assert!(vktorsion.verify(msg, &sig, p_g, params)); - } - - #[test] - fn round_trip_serialization() { - let rng = &mut thread_rng(); - let p_g = FixedGenerators::SpendingKeyGenerator; - let params = &JubjubBls12::new(); - - for _ in 0..1000 { - let sk = PrivateKey::(rng.gen()); - let vk = PublicKey::from_private(&sk, p_g, params); - let msg = b"Foo bar"; - let sig = sk.sign(msg, rng, p_g, params); - - let mut sk_bytes = [0u8; 32]; - let mut vk_bytes = [0u8; 32]; - let mut sig_bytes = [0u8; 64]; - sk.write(&mut sk_bytes[..]).unwrap(); - vk.write(&mut vk_bytes[..]).unwrap(); - sig.write(&mut sig_bytes[..]).unwrap(); - - let sk_2 = PrivateKey::::read(&sk_bytes[..]).unwrap(); - let vk_2 = PublicKey::from_private(&sk_2, p_g, params); - let mut vk_2_bytes = [0u8; 32]; - vk_2.write(&mut vk_2_bytes[..]).unwrap(); - assert!(vk_bytes == vk_2_bytes); - - let vk_2 = PublicKey::::read(&vk_bytes[..], params).unwrap(); - let sig_2 = Signature::read(&sig_bytes[..]).unwrap(); - assert!(vk.verify(msg, &sig_2, p_g, params)); - assert!(vk_2.verify(msg, &sig, p_g, params)); - assert!(vk_2.verify(msg, &sig_2, p_g, params)); - } - } - - #[test] - fn random_signatures() { - let rng = &mut thread_rng(); - let p_g = FixedGenerators::SpendingKeyGenerator; - let params = &JubjubBls12::new(); - - for _ in 0..1000 { - let sk = PrivateKey::(rng.gen()); - let vk = PublicKey::from_private(&sk, p_g, params); - - let msg1 = b"Foo bar"; - let msg2 = b"Spam eggs"; - - let sig1 = sk.sign(msg1, rng, p_g, params); - let sig2 = sk.sign(msg2, rng, p_g, params); - - assert!(vk.verify(msg1, &sig1, p_g, params)); - assert!(vk.verify(msg2, &sig2, p_g, params)); - assert!(!vk.verify(msg1, &sig2, p_g, params)); - assert!(!vk.verify(msg2, &sig1, p_g, params)); - - let alpha = rng.gen(); - let rsk = sk.randomize(alpha); - let rvk = vk.randomize(alpha, p_g, params); - - let sig1 = rsk.sign(msg1, rng, p_g, params); - let sig2 = rsk.sign(msg2, rng, p_g, params); - - assert!(rvk.verify(msg1, &sig1, p_g, params)); - assert!(rvk.verify(msg2, &sig2, p_g, params)); - assert!(!rvk.verify(msg1, &sig2, p_g, params)); - assert!(!rvk.verify(msg2, &sig1, p_g, params)); - } - } -} diff --git a/sapling-crypto/src/util.rs b/sapling-crypto/src/util.rs deleted file mode 100644 index e67e660..0000000 --- a/sapling-crypto/src/util.rs +++ /dev/null @@ -1,11 +0,0 @@ -use blake2_rfc::blake2b::Blake2b; - -use jubjub::{JubjubEngine, ToUniform}; - -pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> E::Fs { - let mut hasher = Blake2b::with_params(64, &[], &[], persona); - hasher.update(a); - hasher.update(b); - let ret = hasher.finalize(); - E::Fs::to_uniform(ret.as_ref()) -} diff --git a/bellman/src/domain.rs b/src/domain.rs similarity index 76% rename from bellman/src/domain.rs rename to src/domain.rs index 4606ce5..ddba4f4 100644 --- a/bellman/src/domain.rs +++ b/src/domain.rs @@ -1,21 +1,20 @@ -//! This module contains an `EvaluationDomain` abstraction for -//! performing various kinds of polynomial arithmetic on top of -//! the scalar field. +//! This module contains an [`EvaluationDomain`] abstraction for performing +//! various kinds of polynomial arithmetic on top of the scalar field. //! -//! In pairing-based SNARKs like Groth16, we need to calculate -//! a quotient polynomial over a target polynomial with roots -//! at distinct points associated with each constraint of the -//! constraint system. In order to be efficient, we choose these -//! roots to be the powers of a 2^n root of unity in the field. -//! This allows us to perform polynomial operations in O(n) -//! by performing an O(n log n) FFT over such a domain. +//! In pairing-based SNARKs like [Groth16], we need to calculate a quotient +//! polynomial over a target polynomial with roots at distinct points associated +//! with each constraint of the constraint system. In order to be efficient, we +//! choose these roots to be the powers of a 2n root of unity in the +//! field. This allows us to perform polynomial operations in O(n) by performing +//! an O(n log n) FFT over such a domain. +//! +//! [`EvaluationDomain`]: crate::domain::EvaluationDomain +//! [Groth16]: https://eprint.iacr.org/2016/260 use ff::{Field, PrimeField, ScalarEngine}; use group::CurveProjective; -use super::{ - SynthesisError -}; +use super::SynthesisError; use super::multicore::Worker; @@ -25,24 +24,27 @@ pub struct EvaluationDomain> { omega: E::Fr, omegainv: E::Fr, geninv: E::Fr, - minv: E::Fr + minv: E::Fr, +} + +impl> AsRef<[G]> for EvaluationDomain { + fn as_ref(&self) -> &[G] { + &self.coeffs + } +} + +impl> AsMut<[G]> for EvaluationDomain { + fn as_mut(&mut self) -> &mut [G] { + &mut self.coeffs + } } impl> EvaluationDomain { - pub fn as_ref(&self) -> &[G] { - &self.coeffs - } - - pub fn as_mut(&mut self) -> &mut [G] { - &mut self.coeffs - } - pub fn into_coeffs(self) -> Vec { self.coeffs } - pub fn from_coeffs(mut coeffs: Vec) -> Result, SynthesisError> - { + pub fn from_coeffs(mut coeffs: Vec) -> Result, SynthesisError> { // Compute the size of our evaluation domain let mut m = 1; let mut exp = 0; @@ -53,7 +55,7 @@ impl> EvaluationDomain { // The pairing-friendly curve may not be able to support // large enough (radix2) evaluation domains. if exp >= E::Fr::S { - return Err(SynthesisError::PolynomialDegreeTooLarge) + return Err(SynthesisError::PolynomialDegreeTooLarge); } } @@ -67,29 +69,30 @@ impl> EvaluationDomain { coeffs.resize(m, G::group_zero()); Ok(EvaluationDomain { - coeffs: coeffs, - exp: exp, - omega: omega, + coeffs, + exp, + omega, omegainv: omega.inverse().unwrap(), geninv: E::Fr::multiplicative_generator().inverse().unwrap(), - minv: E::Fr::from_str(&format!("{}", m)).unwrap().inverse().unwrap() + minv: E::Fr::from_str(&format!("{}", m)) + .unwrap() + .inverse() + .unwrap(), }) } - pub fn fft(&mut self, worker: &Worker) - { + pub fn fft(&mut self, worker: &Worker) { best_fft(&mut self.coeffs, worker, &self.omega, self.exp); } - pub fn ifft(&mut self, worker: &Worker) - { + pub fn ifft(&mut self, worker: &Worker) { best_fft(&mut self.coeffs, worker, &self.omegainv, self.exp); worker.scope(self.coeffs.len(), |scope, chunk| { let minv = self.minv; for v in self.coeffs.chunks_mut(chunk) { - scope.spawn(move || { + scope.spawn(move |_scope| { for v in v { v.group_mul_assign(&minv); } @@ -98,11 +101,10 @@ impl> EvaluationDomain { }); } - pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr) - { + pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr) { worker.scope(self.coeffs.len(), |scope, chunk| { for (i, v) in self.coeffs.chunks_mut(chunk).enumerate() { - scope.spawn(move || { + scope.spawn(move |_scope| { let mut u = g.pow(&[(i * chunk) as u64]); for v in v.iter_mut() { v.group_mul_assign(&u); @@ -113,14 +115,12 @@ impl> EvaluationDomain { }); } - pub fn coset_fft(&mut self, worker: &Worker) - { + pub fn coset_fft(&mut self, worker: &Worker) { self.distribute_powers(worker, E::Fr::multiplicative_generator()); self.fft(worker); } - pub fn icoset_fft(&mut self, worker: &Worker) - { + pub fn icoset_fft(&mut self, worker: &Worker) { let geninv = self.geninv; self.ifft(worker); @@ -139,13 +139,15 @@ impl> EvaluationDomain { /// The target polynomial is the zero polynomial in our /// evaluation domain, so we must perform division over /// a coset. - pub fn divide_by_z_on_coset(&mut self, worker: &Worker) - { - let i = self.z(&E::Fr::multiplicative_generator()).inverse().unwrap(); + pub fn divide_by_z_on_coset(&mut self, worker: &Worker) { + let i = self + .z(&E::Fr::multiplicative_generator()) + .inverse() + .unwrap(); worker.scope(self.coeffs.len(), |scope, chunk| { for v in self.coeffs.chunks_mut(chunk) { - scope.spawn(move || { + scope.spawn(move |_scope| { for v in v { v.group_mul_assign(&i); } @@ -159,8 +161,12 @@ impl> EvaluationDomain { assert_eq!(self.coeffs.len(), other.coeffs.len()); worker.scope(self.coeffs.len(), |scope, chunk| { - for (a, b) in self.coeffs.chunks_mut(chunk).zip(other.coeffs.chunks(chunk)) { - scope.spawn(move || { + for (a, b) in self + .coeffs + .chunks_mut(chunk) + .zip(other.coeffs.chunks(chunk)) + { + scope.spawn(move |_scope| { for (a, b) in a.iter_mut().zip(b.iter()) { a.group_mul_assign(&b.0); } @@ -174,8 +180,12 @@ impl> EvaluationDomain { assert_eq!(self.coeffs.len(), other.coeffs.len()); worker.scope(self.coeffs.len(), |scope, chunk| { - for (a, b) in self.coeffs.chunks_mut(chunk).zip(other.coeffs.chunks(chunk)) { - scope.spawn(move || { + for (a, b) in self + .coeffs + .chunks_mut(chunk) + .zip(other.coeffs.chunks(chunk)) + { + scope.spawn(move |_scope| { for (a, b) in a.iter_mut().zip(b.iter()) { a.group_sub_assign(&b); } @@ -200,7 +210,7 @@ impl PartialEq for Point { } } -impl Copy for Point { } +impl Copy for Point {} impl Clone for Point { fn clone(&self) -> Point { @@ -231,7 +241,7 @@ impl PartialEq for Scalar { } } -impl Copy for Scalar { } +impl Copy for Scalar {} impl Clone for Scalar { fn clone(&self) -> Scalar { @@ -254,8 +264,7 @@ impl Group for Scalar { } } -fn best_fft>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32) -{ +fn best_fft>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32) { let log_cpus = worker.log_num_cpus(); if log_n <= log_cpus { @@ -265,8 +274,7 @@ fn best_fft>(a: &mut [T], worker: &Worker, omega: & } } -fn serial_fft>(a: &mut [T], omega: &E::Fr, log_n: u32) -{ +fn serial_fft>(a: &mut [T], omega: &E::Fr, log_n: u32) { fn bitreverse(mut n: u32, l: u32) -> u32 { let mut r = 0; for _ in 0..l { @@ -288,22 +296,22 @@ fn serial_fft>(a: &mut [T], omega: &E::Fr, log_n: u let mut m = 1; for _ in 0..log_n { - let w_m = omega.pow(&[(n / (2*m)) as u64]); + let w_m = omega.pow(&[u64::from(n / (2 * m))]); let mut k = 0; while k < n { let mut w = E::Fr::one(); for j in 0..m { - let mut t = a[(k+j+m) as usize]; + let mut t = a[(k + j + m) as usize]; t.group_mul_assign(&w); - let mut tmp = a[(k+j) as usize]; + let mut tmp = a[(k + j) as usize]; tmp.group_sub_assign(&t); - a[(k+j+m) as usize] = tmp; - a[(k+j) as usize].group_add_assign(&t); + a[(k + j + m) as usize] = tmp; + a[(k + j) as usize].group_add_assign(&t); w.mul_assign(&w_m); } - k += 2*m; + k += 2 * m; } m *= 2; @@ -315,9 +323,8 @@ fn parallel_fft>( worker: &Worker, omega: &E::Fr, log_n: u32, - log_cpus: u32 -) -{ + log_cpus: u32, +) { assert!(log_n >= log_cpus); let num_cpus = 1 << log_cpus; @@ -329,18 +336,18 @@ fn parallel_fft>( let a = &*a; for (j, tmp) in tmp.iter_mut().enumerate() { - scope.spawn(move || { + scope.spawn(move |_scope| { // Shuffle into a sub-FFT let omega_j = omega.pow(&[j as u64]); let omega_step = omega.pow(&[(j as u64) << log_new_n]); let mut elt = E::Fr::one(); - for i in 0..(1 << log_new_n) { + for (i, tmp) in tmp.iter_mut().enumerate() { for s in 0..num_cpus { let idx = (i + (s << log_new_n)) % (1 << log_n); let mut t = a[idx]; t.group_mul_assign(&elt); - tmp[i].group_add_assign(&t); + tmp.group_add_assign(&t); elt.mul_assign(&omega_step); } elt.mul_assign(&omega_j); @@ -357,7 +364,7 @@ fn parallel_fft>( let tmp = &tmp; for (idx, a) in a.chunks_mut(chunk).enumerate() { - scope.spawn(move || { + scope.spawn(move |_scope| { let mut idx = idx * chunk; let mask = (1 << log_cpus) - 1; for a in a { @@ -375,16 +382,19 @@ fn parallel_fft>( #[test] fn polynomial_arith() { use pairing::bls12_381::Bls12; - use rand::{self, Rand}; + use rand_core::RngCore; - fn test_mul(rng: &mut R) - { + fn test_mul(rng: &mut R) { let worker = Worker::new(); for coeffs_a in 0..70 { for coeffs_b in 0..70 { - let mut a: Vec<_> = (0..coeffs_a).map(|_| Scalar::(E::Fr::rand(rng))).collect(); - let mut b: Vec<_> = (0..coeffs_b).map(|_| Scalar::(E::Fr::rand(rng))).collect(); + let mut a: Vec<_> = (0..coeffs_a) + .map(|_| Scalar::(E::Fr::random(rng))) + .collect(); + let mut b: Vec<_> = (0..coeffs_b) + .map(|_| Scalar::(E::Fr::random(rng))) + .collect(); // naive evaluation let mut naive = vec![Scalar(E::Fr::zero()); coeffs_a + coeffs_b]; @@ -423,10 +433,9 @@ fn polynomial_arith() { #[test] fn fft_composition() { use pairing::bls12_381::Bls12; - use rand; + use rand_core::RngCore; - fn test_comp(rng: &mut R) - { + fn test_comp(rng: &mut R) { let worker = Worker::new(); for coeffs in 0..10 { @@ -434,7 +443,7 @@ fn fft_composition() { let mut v = vec![]; for _ in 0..coeffs { - v.push(Scalar::(rng.gen())); + v.push(Scalar::(E::Fr::random(rng))); } let mut domain = EvaluationDomain::from_coeffs(v.clone()).unwrap(); @@ -462,22 +471,23 @@ fn fft_composition() { #[test] fn parallel_fft_consistency() { use pairing::bls12_381::Bls12; - use rand::{self, Rand}; + use rand_core::RngCore; use std::cmp::min; - fn test_consistency(rng: &mut R) - { + fn test_consistency(rng: &mut R) { let worker = Worker::new(); for _ in 0..5 { for log_d in 0..10 { let d = 1 << log_d; - let v1 = (0..d).map(|_| Scalar::(E::Fr::rand(rng))).collect::>(); + let v1 = (0..d) + .map(|_| Scalar::(E::Fr::random(rng))) + .collect::>(); let mut v1 = EvaluationDomain::from_coeffs(v1).unwrap(); let mut v2 = EvaluationDomain::from_coeffs(v1.coeffs.clone()).unwrap(); - for log_cpus in log_d..min(log_d+1, 3) { + for log_cpus in log_d..min(log_d + 1, 3) { parallel_fft(&mut v1.coeffs, &worker, &v1.omega, log_d, log_cpus); serial_fft(&mut v2.coeffs, &v2.omega, log_d); diff --git a/sapling-crypto/src/circuit/mod.rs b/src/gadgets.rs similarity index 75% rename from sapling-crypto/src/circuit/mod.rs rename to src/gadgets.rs index fe0fe50..b0ce734 100644 --- a/sapling-crypto/src/circuit/mod.rs +++ b/src/gadgets.rs @@ -1,23 +1,17 @@ -#[cfg(test)] +//! Self-contained sub-circuit implementations for various primitives. + pub mod test; -pub mod boolean; -pub mod multieq; -pub mod uint32; pub mod blake2s; -pub mod num; +pub mod boolean; pub mod lookup; -pub mod ecc; -pub mod pedersen_hash; +pub mod multieq; pub mod multipack; +pub mod num; pub mod sha256; +pub mod uint32; -pub mod sapling; -pub mod sprout; - -use bellman::{ - SynthesisError -}; +use crate::SynthesisError; // TODO: This should probably be removed and we // should use existing helper methods on `Option` @@ -25,7 +19,7 @@ use bellman::{ /// This basically is just an extension to `Option` /// which allows for a convenient mapping to an /// error on `None`. -trait Assignment { +pub trait Assignment { fn get(&self) -> Result<&T, SynthesisError>; } @@ -33,7 +27,7 @@ impl Assignment for Option { fn get(&self) -> Result<&T, SynthesisError> { match *self { Some(ref v) => Ok(v), - None => Err(SynthesisError::AssignmentMissing) + None => Err(SynthesisError::AssignmentMissing), } } } diff --git a/src/gadgets/blake2s.rs b/src/gadgets/blake2s.rs new file mode 100644 index 0000000..9b6693b --- /dev/null +++ b/src/gadgets/blake2s.rs @@ -0,0 +1,696 @@ +//! The [BLAKE2s] hash function with personalization support. +//! +//! [BLAKE2s]: https://tools.ietf.org/html/rfc7693 + +use super::{boolean::Boolean, multieq::MultiEq, uint32::UInt32}; +use crate::{ConstraintSystem, SynthesisError}; +use ff::ScalarEngine; + +/* +2.1. Parameters + The following table summarizes various parameters and their ranges: + | BLAKE2b | BLAKE2s | + --------------+------------------+------------------+ + Bits in word | w = 64 | w = 32 | + Rounds in F | r = 12 | r = 10 | + Block bytes | bb = 128 | bb = 64 | + Hash bytes | 1 <= nn <= 64 | 1 <= nn <= 32 | + Key bytes | 0 <= kk <= 64 | 0 <= kk <= 32 | + Input bytes | 0 <= ll < 2**128 | 0 <= ll < 2**64 | + --------------+------------------+------------------+ + G Rotation | (R1, R2, R3, R4) | (R1, R2, R3, R4) | + constants = | (32, 24, 16, 63) | (16, 12, 8, 7) | + --------------+------------------+------------------+ +*/ + +const R1: usize = 16; +const R2: usize = 12; +const R3: usize = 8; +const R4: usize = 7; + +/* + Round | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | + ----------+-------------------------------------------------+ + SIGMA[0] | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | + SIGMA[1] | 14 10 4 8 9 15 13 6 1 12 0 2 11 7 5 3 | + SIGMA[2] | 11 8 12 0 5 2 15 13 10 14 3 6 7 1 9 4 | + SIGMA[3] | 7 9 3 1 13 12 11 14 2 6 5 10 4 0 15 8 | + SIGMA[4] | 9 0 5 7 2 4 10 15 14 1 11 12 6 8 3 13 | + SIGMA[5] | 2 12 6 10 0 11 8 3 4 13 7 5 15 14 1 9 | + SIGMA[6] | 12 5 1 15 14 13 4 10 0 7 6 3 9 2 8 11 | + SIGMA[7] | 13 11 7 14 12 1 3 9 5 0 15 4 8 6 2 10 | + SIGMA[8] | 6 15 14 9 11 3 0 8 12 2 13 7 1 4 10 5 | + SIGMA[9] | 10 2 8 4 7 6 1 5 15 11 9 14 3 12 13 0 | + ----------+-------------------------------------------------+ +*/ + +const SIGMA: [[usize; 16]; 10] = [ + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], + [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3], + [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4], + [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8], + [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13], + [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9], + [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11], + [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10], + [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5], + [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0], +]; + +/* +3.1. Mixing Function G + The G primitive function mixes two input words, "x" and "y", into + four words indexed by "a", "b", "c", and "d" in the working vector + v[0..15]. The full modified vector is returned. The rotation + constants (R1, R2, R3, R4) are given in Section 2.1. + FUNCTION G( v[0..15], a, b, c, d, x, y ) + | + | v[a] := (v[a] + v[b] + x) mod 2**w + | v[d] := (v[d] ^ v[a]) >>> R1 + | v[c] := (v[c] + v[d]) mod 2**w + | v[b] := (v[b] ^ v[c]) >>> R2 + | v[a] := (v[a] + v[b] + y) mod 2**w + | v[d] := (v[d] ^ v[a]) >>> R3 + | v[c] := (v[c] + v[d]) mod 2**w + | v[b] := (v[b] ^ v[c]) >>> R4 + | + | RETURN v[0..15] + | + END FUNCTION. +*/ + +fn mixing_g, M>( + mut cs: M, + v: &mut [UInt32], + a: usize, + b: usize, + c: usize, + d: usize, + x: &UInt32, + y: &UInt32, +) -> Result<(), SynthesisError> +where + M: ConstraintSystem>, +{ + v[a] = UInt32::addmany( + cs.namespace(|| "mixing step 1"), + &[v[a].clone(), v[b].clone(), x.clone()], + )?; + v[d] = v[d].xor(cs.namespace(|| "mixing step 2"), &v[a])?.rotr(R1); + v[c] = UInt32::addmany( + cs.namespace(|| "mixing step 3"), + &[v[c].clone(), v[d].clone()], + )?; + v[b] = v[b].xor(cs.namespace(|| "mixing step 4"), &v[c])?.rotr(R2); + v[a] = UInt32::addmany( + cs.namespace(|| "mixing step 5"), + &[v[a].clone(), v[b].clone(), y.clone()], + )?; + v[d] = v[d].xor(cs.namespace(|| "mixing step 6"), &v[a])?.rotr(R3); + v[c] = UInt32::addmany( + cs.namespace(|| "mixing step 7"), + &[v[c].clone(), v[d].clone()], + )?; + v[b] = v[b].xor(cs.namespace(|| "mixing step 8"), &v[c])?.rotr(R4); + + Ok(()) +} + +/* +3.2. Compression Function F + Compression function F takes as an argument the state vector "h", + message block vector "m" (last block is padded with zeros to full + block size, if required), 2w-bit offset counter "t", and final block + indicator flag "f". Local vector v[0..15] is used in processing. F + returns a new state vector. The number of rounds, "r", is 12 for + BLAKE2b and 10 for BLAKE2s. Rounds are numbered from 0 to r - 1. + FUNCTION F( h[0..7], m[0..15], t, f ) + | + | // Initialize local work vector v[0..15] + | v[0..7] := h[0..7] // First half from state. + | v[8..15] := IV[0..7] // Second half from IV. + | + | v[12] := v[12] ^ (t mod 2**w) // Low word of the offset. + | v[13] := v[13] ^ (t >> w) // High word. + | + | IF f = TRUE THEN // last block flag? + | | v[14] := v[14] ^ 0xFF..FF // Invert all bits. + | END IF. + | + | // Cryptographic mixing + | FOR i = 0 TO r - 1 DO // Ten or twelve rounds. + | | + | | // Message word selection permutation for this round. + | | s[0..15] := SIGMA[i mod 10][0..15] + | | + | | v := G( v, 0, 4, 8, 12, m[s[ 0]], m[s[ 1]] ) + | | v := G( v, 1, 5, 9, 13, m[s[ 2]], m[s[ 3]] ) + | | v := G( v, 2, 6, 10, 14, m[s[ 4]], m[s[ 5]] ) + | | v := G( v, 3, 7, 11, 15, m[s[ 6]], m[s[ 7]] ) + | | + | | v := G( v, 0, 5, 10, 15, m[s[ 8]], m[s[ 9]] ) + | | v := G( v, 1, 6, 11, 12, m[s[10]], m[s[11]] ) + | | v := G( v, 2, 7, 8, 13, m[s[12]], m[s[13]] ) + | | v := G( v, 3, 4, 9, 14, m[s[14]], m[s[15]] ) + | | + | END FOR + | + | FOR i = 0 TO 7 DO // XOR the two halves. + | | h[i] := h[i] ^ v[i] ^ v[i + 8] + | END FOR. + | + | RETURN h[0..7] // New state. + | + END FUNCTION. +*/ + +fn blake2s_compression>( + mut cs: CS, + h: &mut [UInt32], + m: &[UInt32], + t: u64, + f: bool, +) -> Result<(), SynthesisError> { + assert_eq!(h.len(), 8); + assert_eq!(m.len(), 16); + + /* + static const uint32_t blake2s_iv[8] = + { + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 + }; + */ + + let mut v = Vec::with_capacity(16); + v.extend_from_slice(h); + v.push(UInt32::constant(0x6A09E667)); + v.push(UInt32::constant(0xBB67AE85)); + v.push(UInt32::constant(0x3C6EF372)); + v.push(UInt32::constant(0xA54FF53A)); + v.push(UInt32::constant(0x510E527F)); + v.push(UInt32::constant(0x9B05688C)); + v.push(UInt32::constant(0x1F83D9AB)); + v.push(UInt32::constant(0x5BE0CD19)); + + assert_eq!(v.len(), 16); + + v[12] = v[12].xor(cs.namespace(|| "first xor"), &UInt32::constant(t as u32))?; + v[13] = v[13].xor( + cs.namespace(|| "second xor"), + &UInt32::constant((t >> 32) as u32), + )?; + + if f { + v[14] = v[14].xor( + cs.namespace(|| "third xor"), + &UInt32::constant(u32::max_value()), + )?; + } + + { + let mut cs = MultiEq::new(&mut cs); + + for i in 0..10 { + let mut cs = cs.namespace(|| format!("round {}", i)); + + let s = SIGMA[i % 10]; + + mixing_g( + cs.namespace(|| "mixing invocation 1"), + &mut v, + 0, + 4, + 8, + 12, + &m[s[0]], + &m[s[1]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 2"), + &mut v, + 1, + 5, + 9, + 13, + &m[s[2]], + &m[s[3]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 3"), + &mut v, + 2, + 6, + 10, + 14, + &m[s[4]], + &m[s[5]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 4"), + &mut v, + 3, + 7, + 11, + 15, + &m[s[6]], + &m[s[7]], + )?; + + mixing_g( + cs.namespace(|| "mixing invocation 5"), + &mut v, + 0, + 5, + 10, + 15, + &m[s[8]], + &m[s[9]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 6"), + &mut v, + 1, + 6, + 11, + 12, + &m[s[10]], + &m[s[11]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 7"), + &mut v, + 2, + 7, + 8, + 13, + &m[s[12]], + &m[s[13]], + )?; + mixing_g( + cs.namespace(|| "mixing invocation 8"), + &mut v, + 3, + 4, + 9, + 14, + &m[s[14]], + &m[s[15]], + )?; + } + } + + for i in 0..8 { + let mut cs = cs.namespace(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i = i)); + + h[i] = h[i].xor(cs.namespace(|| "first xor"), &v[i])?; + h[i] = h[i].xor(cs.namespace(|| "second xor"), &v[i + 8])?; + } + + Ok(()) +} + +/* + FUNCTION BLAKE2( d[0..dd-1], ll, kk, nn ) + | + | h[0..7] := IV[0..7] // Initialization Vector. + | + | // Parameter block p[0] + | h[0] := h[0] ^ 0x01010000 ^ (kk << 8) ^ nn + | + | // Process padded key and data blocks + | IF dd > 1 THEN + | | FOR i = 0 TO dd - 2 DO + | | | h := F( h, d[i], (i + 1) * bb, FALSE ) + | | END FOR. + | END IF. + | + | // Final block. + | IF kk = 0 THEN + | | h := F( h, d[dd - 1], ll, TRUE ) + | ELSE + | | h := F( h, d[dd - 1], ll + bb, TRUE ) + | END IF. + | + | RETURN first "nn" bytes from little-endian word array h[]. + | + END FUNCTION. +*/ + +pub fn blake2s>( + mut cs: CS, + input: &[Boolean], + personalization: &[u8], +) -> Result, SynthesisError> { + use byteorder::{ByteOrder, LittleEndian}; + + assert_eq!(personalization.len(), 8); + assert!(input.len() % 8 == 0); + + let mut h = Vec::with_capacity(8); + h.push(UInt32::constant(0x6A09E667 ^ 0x01010000 ^ 32)); + h.push(UInt32::constant(0xBB67AE85)); + h.push(UInt32::constant(0x3C6EF372)); + h.push(UInt32::constant(0xA54FF53A)); + h.push(UInt32::constant(0x510E527F)); + h.push(UInt32::constant(0x9B05688C)); + + // Personalization is stored here + h.push(UInt32::constant( + 0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4]), + )); + h.push(UInt32::constant( + 0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8]), + )); + + let mut blocks: Vec> = vec![]; + + for block in input.chunks(512) { + let mut this_block = Vec::with_capacity(16); + for word in block.chunks(32) { + let mut tmp = word.to_vec(); + while tmp.len() < 32 { + tmp.push(Boolean::constant(false)); + } + this_block.push(UInt32::from_bits(&tmp)); + } + while this_block.len() < 16 { + this_block.push(UInt32::constant(0)); + } + blocks.push(this_block); + } + + if blocks.is_empty() { + blocks.push((0..16).map(|_| UInt32::constant(0)).collect()); + } + + for (i, block) in blocks[0..blocks.len() - 1].iter().enumerate() { + let cs = cs.namespace(|| format!("block {}", i)); + + blake2s_compression(cs, &mut h, block, ((i as u64) + 1) * 64, false)?; + } + + { + let cs = cs.namespace(|| "final block"); + + blake2s_compression( + cs, + &mut h, + &blocks[blocks.len() - 1], + (input.len() / 8) as u64, + true, + )?; + } + + Ok(h.into_iter().flat_map(|b| b.into_bits()).collect()) +} + +#[cfg(test)] +mod test { + use blake2s_simd::Params as Blake2sParams; + use pairing::bls12_381::Bls12; + use rand_core::{RngCore, SeedableRng}; + use rand_xorshift::XorShiftRng; + + use super::blake2s; + use crate::gadgets::boolean::{AllocatedBit, Boolean}; + use crate::gadgets::test::TestConstraintSystem; + use crate::ConstraintSystem; + + #[test] + fn test_blank_hash() { + let mut cs = TestConstraintSystem::::new(); + let input_bits = vec![]; + let out = blake2s(&mut cs, &input_bits, b"12345678").unwrap(); + assert!(cs.is_satisfied()); + assert_eq!(cs.num_constraints(), 0); + + // >>> import blake2s from hashlib + // >>> h = blake2s(digest_size=32, person=b'12345678') + // >>> h.hexdigest() + let expected = hex!("c59f682376d137f3f255e671e207d1f2374ebe504e9314208a52d9f88d69e8c8"); + + let mut out = out.into_iter(); + for b in expected.iter() { + for i in 0..8 { + let c = out.next().unwrap().get_value().unwrap(); + + assert_eq!(c, (b >> i) & 1u8 == 1u8); + } + } + } + + #[test] + fn test_blake2s_constraints() { + let mut cs = TestConstraintSystem::::new(); + let input_bits: Vec<_> = (0..512) + .map(|i| { + AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)) + .unwrap() + .into() + }) + .collect(); + blake2s(&mut cs, &input_bits, b"12345678").unwrap(); + assert!(cs.is_satisfied()); + assert_eq!(cs.num_constraints(), 21518); + } + + #[test] + fn test_blake2s_precomp_constraints() { + // Test that 512 fixed leading bits (constants) + // doesn't result in more constraints. + + let mut cs = TestConstraintSystem::::new(); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); + let input_bits: Vec<_> = (0..512) + .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) + .chain((0..512).map(|i| { + AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)) + .unwrap() + .into() + })) + .collect(); + blake2s(&mut cs, &input_bits, b"12345678").unwrap(); + assert!(cs.is_satisfied()); + assert_eq!(cs.num_constraints(), 21518); + } + + #[test] + fn test_blake2s_constant_constraints() { + let mut cs = TestConstraintSystem::::new(); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); + let input_bits: Vec<_> = (0..512) + .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) + .collect(); + blake2s(&mut cs, &input_bits, b"12345678").unwrap(); + assert_eq!(cs.num_constraints(), 0); + } + + #[test] + fn test_blake2s() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); + + for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) { + let mut h = Blake2sParams::new() + .hash_length(32) + .personal(b"12345678") + .to_state(); + + let data: Vec = (0..input_len).map(|_| rng.next_u32() as u8).collect(); + + h.update(&data); + + let hash_result = h.finalize(); + + let mut cs = TestConstraintSystem::::new(); + + let mut input_bits = vec![]; + + for (byte_i, input_byte) in data.into_iter().enumerate() { + for bit_i in 0..8 { + let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i)); + + input_bits.push( + AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)) + .unwrap() + .into(), + ); + } + } + + let r = blake2s(&mut cs, &input_bits, b"12345678").unwrap(); + + assert!(cs.is_satisfied()); + + let mut s = hash_result + .as_ref() + .iter() + .flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8)); + + for b in r { + match b { + Boolean::Is(b) => { + assert!(s.next().unwrap() == b.get_value().unwrap()); + } + Boolean::Not(b) => { + assert!(s.next().unwrap() != b.get_value().unwrap()); + } + Boolean::Constant(b) => { + assert!(input_len == 0); + assert!(s.next().unwrap() == b); + } + } + } + } + } + + #[test] + fn test_blake2s_256_vars() { + let data: Vec = hex!("be9f9c485e670acce8b1516a378176161b20583637b6f1c536fbc1158a0a3296831df2920e57a442d5738f4be4dd6be89dd7913fc8b4d1c0a815646a4d674b77f7caf313bd880bf759fcac27037c48c2b2a20acd2fd5248e3be426c84a341c0a3c63eaf36e0d537d10b8db5c6e4c801832c41eb1a3ed602177acded8b4b803bd34339d99a18b71df399641cc8dfae2ad193fcd74b5913e704551777160d14c78f2e8d5c32716a8599c1080cb89a40ccd6ba596694a8b4a065d9f2d0667ef423ed2e418093caff884540858b4f4b62acd47edcea880523e1b1cda8eb225c128c2e9e83f14f6e7448c5733a195cac7d79a53dde5083172462c45b2f799e42af1c9").to_vec(); + assert_eq!(data.len(), 256); + + let mut cs = TestConstraintSystem::::new(); + + let mut input_bits = vec![]; + + for (byte_i, input_byte) in data.into_iter().enumerate() { + for bit_i in 0..8 { + let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i)); + + input_bits.push( + AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)) + .unwrap() + .into(), + ); + } + } + + let r = blake2s(&mut cs, &input_bits, b"12345678").unwrap(); + + assert!(cs.is_satisfied()); + + let expected = hex!("0af5695115ced92c8a0341e43869209636e9aa6472e4576f0f2b996cf812b30e"); + + let mut out = r.into_iter(); + for b in expected.into_iter() { + for i in 0..8 { + let c = out.next().unwrap().get_value().unwrap(); + + assert_eq!(c, (b >> i) & 1u8 == 1u8); + } + } + } + + #[test] + fn test_blake2s_700_vars() { + let data: Vec = hex!("5dcfe8bab4c758d2eb1ddb7ef337583e0df3e2c358e1755b7cd303a658de9a1227eed1d1114179a5c3c38d692ff2cf2d4e5c92a9516de750106774bbf9f7d063f707f4c9b6a02c0a77e4feb99e036c3ccaee7d1a31cb144093aa074bc9da608f8ff30b39c3c60e4a243cc0bbd406d1262a7d6607b31c60275c6bcc8b0ac49a06a4b629a98693c5f7640f3bca45e4977cfabc5b17f52838af3433b1fd407dbbdc131e8e4bd58bcee85bbab4b57b656c6a2ec6cf852525bc8423675e2bf29159139cd5df99db94719f3f7167230e0d5bd76f6d7891b656732cef9c3c0d48a5fa3d7a879988157b39015a85451b25af0301ca5e759ac35fea79dca38c673ec6db9f3885d9103e2dcb3304bd3d59b0b1d01babc97ef8a74d91b6ab6bf50f29eb5adf7250a28fd85db37bff0133193635da69caeefc72979cf3bef1d2896d847eea7e8a81e0927893dbd010feb6fb845d0399007d9a148a0596d86cd8f4192631f975c560f4de8da5f712c161342063af3c11029d93d6df7ff46db48343499de9ec4786cac059c4025ef418c9fe40132428ff8b91259d71d1709ff066add84ae944b45a817f60b4c1bf719e39ae23e9b413469db2310793e9137cf38741e5dd2a3c138a566dbde1950c00071b20ac457b46ba9b0a7ebdddcc212bd228d2a4c4146a970e54158477247c27871af1564b176576e9fd43bf63740bf77434bc4ea3b1a4b430e1a11714bf43160145578a575c3f78ddeaa48de97f73460f26f8df2b5d63e31800100d16bc27160fea5ced5a977ef541cfe8dadc7b3991ed1c0d4f16a3076bbfed96ba3e155113e794987af8abb133f06feefabc2ac32eb4d4d4ba1541ca08b9e518d2e74b7f946b0cbd2663d58c689359b9a565821acc619011233d1011963fa302cde34fc9c5ba2e03eeb2512f547391e940d56218e22ae325f2dfa38d4bae35744ee707aa5dc9c17674025d15390a08f5c452343546ef6da0f7").to_vec(); + assert_eq!(data.len(), 700); + + let mut cs = TestConstraintSystem::::new(); + + let mut input_bits = vec![]; + + for (byte_i, input_byte) in data.into_iter().enumerate() { + for bit_i in 0..8 { + let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i)); + + input_bits.push( + AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)) + .unwrap() + .into(), + ); + } + } + + let r = blake2s(&mut cs, &input_bits, b"12345678").unwrap(); + + assert!(cs.is_satisfied()); + + let expected = hex!("2ab8f0683167ba220eef19dccf4f9b1a8193cc09b35e0235842323950530f18a"); + + let mut out = r.into_iter(); + for b in expected.into_iter() { + for i in 0..8 { + let c = out.next().unwrap().get_value().unwrap(); + + assert_eq!(c, (b >> i) & 1u8 == 1u8); + } + } + } + + #[test] + fn test_blake2s_test_vectors() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); + + let expecteds = [ + hex!("a1309e334376c8f36a736a4ab0e691ef931ee3ebdb9ea96187127136fea622a1"), + hex!("82fefff60f265cea255252f7c194a7f93965dffee0609ef74eb67f0d76cd41c6"), + ]; + for i in 0..2 { + let mut h = Blake2sParams::new() + .hash_length(32) + .personal(b"12345678") + .to_state(); + let input_len = 1024; + let data: Vec = (0..input_len).map(|_| rng.next_u32() as u8).collect(); + + h.update(&data); + + let hash_result = h.finalize(); + + let mut cs = TestConstraintSystem::::new(); + + let mut input_bits = vec![]; + + for (byte_i, input_byte) in data.into_iter().enumerate() { + for bit_i in 0..8 { + let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i)); + + input_bits.push( + AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)) + .unwrap() + .into(), + ); + } + } + + let r = blake2s(&mut cs, &input_bits, b"12345678").unwrap(); + + assert!(cs.is_satisfied()); + + let mut s = hash_result + .as_ref() + .iter() + .flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8)); + + for b in r { + match b { + Boolean::Is(b) => { + assert!(s.next().unwrap() == b.get_value().unwrap()); + } + Boolean::Not(b) => { + assert!(s.next().unwrap() != b.get_value().unwrap()); + } + Boolean::Constant(b) => { + assert!(input_len == 0); + assert!(s.next().unwrap() == b); + } + } + } + + assert_eq!(expecteds[i], hash_result.as_bytes()); + } + } +} diff --git a/sapling-crypto/src/circuit/boolean.rs b/src/gadgets/boolean.rs similarity index 56% rename from sapling-crypto/src/circuit/boolean.rs rename to src/gadgets/boolean.rs index 08f407e..d3c882d 100644 --- a/sapling-crypto/src/circuit/boolean.rs +++ b/src/gadgets/boolean.rs @@ -1,27 +1,17 @@ -use pairing::{ - Engine, - Field, - PrimeField, - BitIterator -}; +//! Gadgets for allocating bits in the circuit and performing boolean logic. -use bellman::{ - ConstraintSystem, - SynthesisError, - LinearCombination, - Variable -}; +use ff::{BitIterator, Field, PrimeField, ScalarEngine}; -use super::{ - Assignment -}; +use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; + +use super::Assignment; /// Represents a variable in the constraint system which is guaranteed /// to be either zero or one. #[derive(Clone)] pub struct AllocatedBit { variable: Variable, - value: Option + value: Option, } impl AllocatedBit { @@ -39,18 +29,22 @@ impl AllocatedBit { pub fn alloc_conditionally( mut cs: CS, value: Option, - must_be_false: &AllocatedBit + must_be_false: &AllocatedBit, ) -> Result - where E: Engine, - CS: ConstraintSystem + where + E: ScalarEngine, + CS: ConstraintSystem, { - let var = cs.alloc(|| "boolean", || { - if *value.get()? { - Ok(E::Fr::one()) - } else { - Ok(E::Fr::zero()) - } - })?; + let var = cs.alloc( + || "boolean", + || { + if *value.get()? { + Ok(E::Fr::one()) + } else { + Ok(E::Fr::zero()) + } + }, + )?; // Constrain: (1 - must_be_false - a) * a = 0 // if must_be_false is true, the equation @@ -62,31 +56,32 @@ impl AllocatedBit { || "boolean constraint", |lc| lc + CS::one() - must_be_false.variable - var, |lc| lc + var, - |lc| lc + |lc| lc, ); Ok(AllocatedBit { variable: var, - value: value + value, }) } /// Allocate a variable in the constraint system which can only be a /// boolean value. - pub fn alloc( - mut cs: CS, - value: Option, - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn alloc(mut cs: CS, value: Option) -> Result + where + E: ScalarEngine, + CS: ConstraintSystem, { - let var = cs.alloc(|| "boolean", || { - if *value.get()? { - Ok(E::Fr::one()) - } else { - Ok(E::Fr::zero()) - } - })?; + let var = cs.alloc( + || "boolean", + || { + if *value.get()? { + Ok(E::Fr::one()) + } else { + Ok(E::Fr::zero()) + } + }, + )?; // Constrain: (1 - a) * a = 0 // This constrains a to be either 0 or 1. @@ -94,38 +89,38 @@ impl AllocatedBit { || "boolean constraint", |lc| lc + CS::one() - var, |lc| lc + var, - |lc| lc + |lc| lc, ); Ok(AllocatedBit { variable: var, - value: value + value, }) } /// Performs an XOR operation over the two operands, returning /// an `AllocatedBit`. - pub fn xor( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn xor(mut cs: CS, a: &Self, b: &Self) -> Result + where + E: ScalarEngine, + CS: ConstraintSystem, { let mut result_value = None; - let result_var = cs.alloc(|| "xor result", || { - if *a.value.get()? ^ *b.value.get()? { - result_value = Some(true); + let result_var = cs.alloc( + || "xor result", + || { + if *a.value.get()? ^ *b.value.get()? { + result_value = Some(true); - Ok(E::Fr::one()) - } else { - result_value = Some(false); + Ok(E::Fr::one()) + } else { + result_value = Some(false); - Ok(E::Fr::zero()) - } - })?; + Ok(E::Fr::zero()) + } + }, + )?; // Constrain (a + a) * (b) = (a + b - c) // Given that a and b are boolean constrained, if they @@ -146,38 +141,38 @@ impl AllocatedBit { || "xor constraint", |lc| lc + a.variable + a.variable, |lc| lc + b.variable, - |lc| lc + a.variable + b.variable - result_var + |lc| lc + a.variable + b.variable - result_var, ); Ok(AllocatedBit { variable: result_var, - value: result_value + value: result_value, }) } /// Performs an AND operation over the two operands, returning /// an `AllocatedBit`. - pub fn and( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn and(mut cs: CS, a: &Self, b: &Self) -> Result + where + E: ScalarEngine, + CS: ConstraintSystem, { let mut result_value = None; - let result_var = cs.alloc(|| "and result", || { - if *a.value.get()? & *b.value.get()? { - result_value = Some(true); + let result_var = cs.alloc( + || "and result", + || { + if *a.value.get()? & *b.value.get()? { + result_value = Some(true); - Ok(E::Fr::one()) - } else { - result_value = Some(false); + Ok(E::Fr::one()) + } else { + result_value = Some(false); - Ok(E::Fr::zero()) - } - })?; + Ok(E::Fr::zero()) + } + }, + )?; // Constrain (a) * (b) = (c), ensuring c is 1 iff // a AND b are both 1. @@ -185,37 +180,37 @@ impl AllocatedBit { || "and constraint", |lc| lc + a.variable, |lc| lc + b.variable, - |lc| lc + result_var + |lc| lc + result_var, ); Ok(AllocatedBit { variable: result_var, - value: result_value + value: result_value, }) } /// Calculates `a AND (NOT b)`. - pub fn and_not( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn and_not(mut cs: CS, a: &Self, b: &Self) -> Result + where + E: ScalarEngine, + CS: ConstraintSystem, { let mut result_value = None; - let result_var = cs.alloc(|| "and not result", || { - if *a.value.get()? & !*b.value.get()? { - result_value = Some(true); + let result_var = cs.alloc( + || "and not result", + || { + if *a.value.get()? & !*b.value.get()? { + result_value = Some(true); - Ok(E::Fr::one()) - } else { - result_value = Some(false); + Ok(E::Fr::one()) + } else { + result_value = Some(false); - Ok(E::Fr::zero()) - } - })?; + Ok(E::Fr::zero()) + } + }, + )?; // Constrain (a) * (1 - b) = (c), ensuring c is 1 iff // a is true and b is false, and otherwise c is 0. @@ -223,37 +218,37 @@ impl AllocatedBit { || "and not constraint", |lc| lc + a.variable, |lc| lc + CS::one() - b.variable, - |lc| lc + result_var + |lc| lc + result_var, ); Ok(AllocatedBit { variable: result_var, - value: result_value + value: result_value, }) } /// Calculates `(NOT a) AND (NOT b)`. - pub fn nor( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn nor(mut cs: CS, a: &Self, b: &Self) -> Result + where + E: ScalarEngine, + CS: ConstraintSystem, { let mut result_value = None; - let result_var = cs.alloc(|| "nor result", || { - if !*a.value.get()? & !*b.value.get()? { - result_value = Some(true); + let result_var = cs.alloc( + || "nor result", + || { + if !*a.value.get()? & !*b.value.get()? { + result_value = Some(true); - Ok(E::Fr::one()) - } else { - result_value = Some(false); + Ok(E::Fr::one()) + } else { + result_value = Some(false); - Ok(E::Fr::zero()) - } - })?; + Ok(E::Fr::zero()) + } + }, + )?; // Constrain (1 - a) * (1 - b) = (c), ensuring c is 1 iff // a and b are both false, and otherwise c is 0. @@ -261,21 +256,20 @@ impl AllocatedBit { || "nor constraint", |lc| lc + CS::one() - a.variable, |lc| lc + CS::one() - b.variable, - |lc| lc + result_var + |lc| lc + result_var, ); Ok(AllocatedBit { variable: result_var, - value: result_value + value: result_value, }) } } -pub fn u64_into_boolean_vec_le>( +pub fn u64_into_boolean_vec_le>( mut cs: CS, - value: Option -) -> Result, SynthesisError> -{ + value: Option, +) -> Result, SynthesisError> { let values = match value { Some(ref value) => { let mut tmp = Vec::with_capacity(64); @@ -285,37 +279,37 @@ pub fn u64_into_boolean_vec_le>( } tmp - }, - None => { - vec![None; 64] } + None => vec![None; 64], }; - let bits = values.into_iter().enumerate().map(|(i, b)| { - Ok(Boolean::from(AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - b - )?)) - }).collect::, SynthesisError>>()?; + let bits = values + .into_iter() + .enumerate() + .map(|(i, b)| { + Ok(Boolean::from(AllocatedBit::alloc( + cs.namespace(|| format!("bit {}", i)), + b, + )?)) + }) + .collect::, SynthesisError>>()?; Ok(bits) } -pub fn field_into_boolean_vec_le, F: PrimeField>( +pub fn field_into_boolean_vec_le, F: PrimeField>( cs: CS, - value: Option -) -> Result, SynthesisError> -{ + value: Option, +) -> Result, SynthesisError> { let v = field_into_allocated_bits_le::(cs, value)?; - Ok(v.into_iter().map(|e| Boolean::from(e)).collect()) + Ok(v.into_iter().map(Boolean::from).collect()) } -pub fn field_into_allocated_bits_le, F: PrimeField>( +pub fn field_into_allocated_bits_le, F: PrimeField>( mut cs: CS, - value: Option -) -> Result, SynthesisError> -{ + value: Option, +) -> Result, SynthesisError> { // Deconstruct in big-endian bit order let values = match value { Some(ref value) => { @@ -337,19 +331,17 @@ pub fn field_into_allocated_bits_le, F: Prime assert_eq!(tmp.len(), F::NUM_BITS as usize); tmp - }, - None => { - vec![None; F::NUM_BITS as usize] } + None => vec![None; F::NUM_BITS as usize], }; // Allocate in little-endian order - let bits = values.into_iter().rev().enumerate().map(|(i, b)| { - AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - b - ) - }).collect::, SynthesisError>>()?; + let bits = values + .into_iter() + .rev() + .enumerate() + .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), b)) + .collect::, SynthesisError>>()?; Ok(bits) } @@ -363,24 +355,21 @@ pub enum Boolean { /// Negated view of the boolean variable Not(AllocatedBit), /// Constant (not an allocated variable) - Constant(bool) + Constant(bool), } impl Boolean { pub fn is_constant(&self) -> bool { match *self { Boolean::Constant(_) => true, - _ => false + _ => false, } } - pub fn enforce_equal( - mut cs: CS, - a: &Self, - b: &Self - ) -> Result<(), SynthesisError> - where E: Engine, - CS: ConstraintSystem + pub fn enforce_equal(mut cs: CS, a: &Self, b: &Self) -> Result<(), SynthesisError> + where + E: ScalarEngine, + CS: ConstraintSystem, { match (a, b) { (&Boolean::Constant(a), &Boolean::Constant(b)) => { @@ -389,33 +378,33 @@ impl Boolean { } else { Err(SynthesisError::Unsatisfiable) } - }, + } (&Boolean::Constant(true), a) | (a, &Boolean::Constant(true)) => { cs.enforce( || "enforce equal to one", |lc| lc, |lc| lc, - |lc| lc + CS::one() - &a.lc(CS::one(), E::Fr::one()) + |lc| lc + CS::one() - &a.lc(CS::one(), E::Fr::one()), ); Ok(()) - }, + } (&Boolean::Constant(false), a) | (a, &Boolean::Constant(false)) => { cs.enforce( || "enforce equal to zero", |lc| lc, |lc| lc, - |_| a.lc(CS::one(), E::Fr::one()) + |_| a.lc(CS::one(), E::Fr::one()), ); Ok(()) - }, + } (a, b) => { cs.enforce( || "enforce equal", |lc| lc, |lc| lc, - |_| a.lc(CS::one(), E::Fr::one()) - &b.lc(CS::one(), E::Fr::one()) + |_| a.lc(CS::one(), E::Fr::one()) - &b.lc(CS::one(), E::Fr::one()), ); Ok(()) @@ -424,31 +413,24 @@ impl Boolean { } pub fn get_value(&self) -> Option { - match self { - &Boolean::Constant(c) => Some(c), - &Boolean::Is(ref v) => v.get_value(), - &Boolean::Not(ref v) => v.get_value().map(|b| !b) + match *self { + Boolean::Constant(c) => Some(c), + Boolean::Is(ref v) => v.get_value(), + Boolean::Not(ref v) => v.get_value().map(|b| !b), } } - pub fn lc( - &self, - one: Variable, - coeff: E::Fr - ) -> LinearCombination - { - match self { - &Boolean::Constant(c) => { + pub fn lc(&self, one: Variable, coeff: E::Fr) -> LinearCombination { + match *self { + Boolean::Constant(c) => { if c { LinearCombination::::zero() + (coeff, one) } else { LinearCombination::::zero() } - }, - &Boolean::Is(ref v) => { - LinearCombination::::zero() + (coeff, v.get_variable()) - }, - &Boolean::Not(ref v) => { + } + Boolean::Is(ref v) => LinearCombination::::zero() + (coeff, v.get_variable()), + Boolean::Not(ref v) => { LinearCombination::::zero() + (coeff, one) - (coeff, v.get_variable()) } } @@ -461,62 +443,57 @@ impl Boolean { /// Return a negated interpretation of this boolean. pub fn not(&self) -> Self { - match self { - &Boolean::Constant(c) => Boolean::Constant(!c), - &Boolean::Is(ref v) => Boolean::Not(v.clone()), - &Boolean::Not(ref v) => Boolean::Is(v.clone()) + match *self { + Boolean::Constant(c) => Boolean::Constant(!c), + Boolean::Is(ref v) => Boolean::Not(v.clone()), + Boolean::Not(ref v) => Boolean::Is(v.clone()), } } /// Perform XOR over two boolean operands - pub fn xor<'a, E, CS>( - cs: CS, - a: &'a Self, - b: &'a Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn xor<'a, E, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result + where + E: ScalarEngine, + CS: ConstraintSystem, { match (a, b) { (&Boolean::Constant(false), x) | (x, &Boolean::Constant(false)) => Ok(x.clone()), (&Boolean::Constant(true), x) | (x, &Boolean::Constant(true)) => Ok(x.not()), // a XOR (NOT b) = NOT(a XOR b) - (is @ &Boolean::Is(_), not @ &Boolean::Not(_)) | (not @ &Boolean::Not(_), is @ &Boolean::Is(_)) => { - Ok(Boolean::xor( - cs, - is, - ¬.not() - )?.not()) - }, + (is @ &Boolean::Is(_), not @ &Boolean::Not(_)) + | (not @ &Boolean::Not(_), is @ &Boolean::Is(_)) => { + Ok(Boolean::xor(cs, is, ¬.not())?.not()) + } // a XOR b = (NOT a) XOR (NOT b) - (&Boolean::Is(ref a), &Boolean::Is(ref b)) | (&Boolean::Not(ref a), &Boolean::Not(ref b)) => { + (&Boolean::Is(ref a), &Boolean::Is(ref b)) + | (&Boolean::Not(ref a), &Boolean::Not(ref b)) => { Ok(Boolean::Is(AllocatedBit::xor(cs, a, b)?)) } } } /// Perform AND over two boolean operands - pub fn and<'a, E, CS>( - cs: CS, - a: &'a Self, - b: &'a Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn and<'a, E, CS>(cs: CS, a: &'a Self, b: &'a Self) -> Result + where + E: ScalarEngine, + CS: ConstraintSystem, { match (a, b) { // false AND x is always false - (&Boolean::Constant(false), _) | (_, &Boolean::Constant(false)) => Ok(Boolean::Constant(false)), + (&Boolean::Constant(false), _) | (_, &Boolean::Constant(false)) => { + Ok(Boolean::Constant(false)) + } // true AND x is always x (&Boolean::Constant(true), x) | (x, &Boolean::Constant(true)) => Ok(x.clone()), // a AND (NOT b) - (&Boolean::Is(ref is), &Boolean::Not(ref not)) | (&Boolean::Not(ref not), &Boolean::Is(ref is)) => { + (&Boolean::Is(ref is), &Boolean::Not(ref not)) + | (&Boolean::Not(ref not), &Boolean::Is(ref is)) => { Ok(Boolean::Is(AllocatedBit::and_not(cs, is, not)?)) - }, + } // (NOT a) AND (NOT b) = a NOR b (&Boolean::Not(ref a), &Boolean::Not(ref b)) => { Ok(Boolean::Is(AllocatedBit::nor(cs, a, b)?)) - }, + } // a AND b (&Boolean::Is(ref a), &Boolean::Is(ref b)) => { Ok(Boolean::Is(AllocatedBit::and(cs, a, b)?)) @@ -529,27 +506,26 @@ impl Boolean { mut cs: CS, a: &'a Self, b: &'a Self, - c: &'a Self + c: &'a Self, ) -> Result - where E: Engine, - CS: ConstraintSystem + where + E: ScalarEngine, + CS: ConstraintSystem, { let ch_value = match (a.get_value(), b.get_value(), c.get_value()) { (Some(a), Some(b), Some(c)) => { // (a and b) xor ((not a) and c) Some((a & b) ^ ((!a) & c)) - }, - _ => None + } + _ => None, }; match (a, b, c) { - (&Boolean::Constant(_), - &Boolean::Constant(_), - &Boolean::Constant(_)) => { + (&Boolean::Constant(_), &Boolean::Constant(_), &Boolean::Constant(_)) => { // They're all constants, so we can just compute the value. return Ok(Boolean::Constant(ch_value.expect("they're all constants"))); - }, + } (&Boolean::Constant(false), _, c) => { // If a is false // (a and b) xor ((not a) and c) @@ -558,29 +534,21 @@ impl Boolean { // equals // c return Ok(c.clone()); - }, + } (a, &Boolean::Constant(false), c) => { // If b is false // (a and b) xor ((not a) and c) // equals // ((not a) and c) - return Boolean::and( - cs, - &a.not(), - &c - ); - }, + return Boolean::and(cs, &a.not(), &c); + } (a, b, &Boolean::Constant(false)) => { // If c is false // (a and b) xor ((not a) and c) // equals // (a and b) - return Boolean::and( - cs, - &a, - &b - ); - }, + return Boolean::and(cs, &a, &b); + } (a, b, &Boolean::Constant(true)) => { // If c is true // (a and b) xor ((not a) and c) @@ -588,12 +556,8 @@ impl Boolean { // (a and b) xor (not a) // equals // not (a and (not b)) - return Ok(Boolean::and( - cs, - &a, - &b.not() - )?.not()); - }, + return Ok(Boolean::and(cs, &a, &b.not())?.not()); + } (a, &Boolean::Constant(true), c) => { // If b is true // (a and b) xor ((not a) and c) @@ -601,53 +565,47 @@ impl Boolean { // a xor ((not a) and c) // equals // not ((not a) and (not c)) - return Ok(Boolean::and( - cs, - &a.not(), - &c.not() - )?.not()); - }, + return Ok(Boolean::and(cs, &a.not(), &c.not())?.not()); + } (&Boolean::Constant(true), _, _) => { // If a is true // (a and b) xor ((not a) and c) // equals // b xor ((not a) and c) // So we just continue! - }, - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_)) - => {} + } + (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) + | (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) + | (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) + | (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) + | (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) + | (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) + | (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) + | (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_)) => {} } - let ch = cs.alloc(|| "ch", || { - ch_value.get().map(|v| { - if *v { - E::Fr::one() - } else { - E::Fr::zero() - } - }) - })?; + let ch = cs.alloc( + || "ch", + || { + ch_value + .get() + .map(|v| if *v { E::Fr::one() } else { E::Fr::zero() }) + }, + )?; // a(b - c) = ch - c cs.enforce( || "ch computation", - |_| b.lc(CS::one(), E::Fr::one()) - - &c.lc(CS::one(), E::Fr::one()), + |_| b.lc(CS::one(), E::Fr::one()) - &c.lc(CS::one(), E::Fr::one()), |_| a.lc(CS::one(), E::Fr::one()), - |lc| lc + ch - &c.lc(CS::one(), E::Fr::one()) + |lc| lc + ch - &c.lc(CS::one(), E::Fr::one()), ); Ok(AllocatedBit { value: ch_value, - variable: ch - }.into()) + variable: ch, + } + .into()) } /// Computes (a and b) xor (a and c) xor (b and c) @@ -657,58 +615,45 @@ impl Boolean { b: &'a Self, c: &'a Self, ) -> Result - where E: Engine, - CS: ConstraintSystem + where + E: ScalarEngine, + CS: ConstraintSystem, { let maj_value = match (a.get_value(), b.get_value(), c.get_value()) { (Some(a), Some(b), Some(c)) => { // (a and b) xor (a and c) xor (b and c) Some((a & b) ^ (a & c) ^ (b & c)) - }, - _ => None + } + _ => None, }; match (a, b, c) { - (&Boolean::Constant(_), - &Boolean::Constant(_), - &Boolean::Constant(_)) => { + (&Boolean::Constant(_), &Boolean::Constant(_), &Boolean::Constant(_)) => { // They're all constants, so we can just compute the value. return Ok(Boolean::Constant(maj_value.expect("they're all constants"))); - }, + } (&Boolean::Constant(false), b, c) => { // If a is false, // (a and b) xor (a and c) xor (b and c) // equals // (b and c) - return Boolean::and( - cs, - b, - c - ); - }, + return Boolean::and(cs, b, c); + } (a, &Boolean::Constant(false), c) => { // If b is false, // (a and b) xor (a and c) xor (b and c) // equals // (a and c) - return Boolean::and( - cs, - a, - c - ); - }, + return Boolean::and(cs, a, c); + } (a, b, &Boolean::Constant(false)) => { // If c is false, // (a and b) xor (a and c) xor (b and c) // equals // (a and b) - return Boolean::and( - cs, - a, - b - ); - }, + return Boolean::and(cs, a, b); + } (a, b, &Boolean::Constant(true)) => { // If c is true, // (a and b) xor (a and c) xor (b and c) @@ -716,54 +661,40 @@ impl Boolean { // (a and b) xor (a) xor (b) // equals // not ((not a) and (not b)) - return Ok(Boolean::and( - cs, - &a.not(), - &b.not() - )?.not()); - }, + return Ok(Boolean::and(cs, &a.not(), &b.not())?.not()); + } (a, &Boolean::Constant(true), c) => { // If b is true, // (a and b) xor (a and c) xor (b and c) // equals // (a) xor (a and c) xor (c) - return Ok(Boolean::and( - cs, - &a.not(), - &c.not() - )?.not()); - }, + return Ok(Boolean::and(cs, &a.not(), &c.not())?.not()); + } (&Boolean::Constant(true), b, c) => { // If a is true, // (a and b) xor (a and c) xor (b and c) // equals // (b) xor (c) xor (b and c) - return Ok(Boolean::and( - cs, - &b.not(), - &c.not() - )?.not()); - }, - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) | - (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_)) - => {} + return Ok(Boolean::and(cs, &b.not(), &c.not())?.not()); + } + (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Is(_)) + | (&Boolean::Is(_), &Boolean::Is(_), &Boolean::Not(_)) + | (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Is(_)) + | (&Boolean::Is(_), &Boolean::Not(_), &Boolean::Not(_)) + | (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Is(_)) + | (&Boolean::Not(_), &Boolean::Is(_), &Boolean::Not(_)) + | (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Is(_)) + | (&Boolean::Not(_), &Boolean::Not(_), &Boolean::Not(_)) => {} } - let maj = cs.alloc(|| "maj", || { - maj_value.get().map(|v| { - if *v { - E::Fr::one() - } else { - E::Fr::zero() - } - }) - })?; + let maj = cs.alloc( + || "maj", + || { + maj_value + .get() + .map(|v| if *v { E::Fr::one() } else { E::Fr::zero() }) + }, + )?; // ¬(¬a ∧ ¬b) ∧ ¬(¬a ∧ ¬c) ∧ ¬(¬b ∧ ¬c) // (1 - ((1 - a) * (1 - b))) * (1 - ((1 - a) * (1 - c))) * (1 - ((1 - b) * (1 - c))) @@ -774,26 +705,24 @@ impl Boolean { // (b) * (c) = (bc) // (2bc - b - c) * (a) = bc - maj - let bc = Self::and( - cs.namespace(|| "b and c"), - b, - c - )?; + let bc = Self::and(cs.namespace(|| "b and c"), b, c)?; cs.enforce( || "maj computation", - |_| bc.lc(CS::one(), E::Fr::one()) - + &bc.lc(CS::one(), E::Fr::one()) - - &b.lc(CS::one(), E::Fr::one()) - - &c.lc(CS::one(), E::Fr::one()), + |_| { + bc.lc(CS::one(), E::Fr::one()) + &bc.lc(CS::one(), E::Fr::one()) + - &b.lc(CS::one(), E::Fr::one()) + - &c.lc(CS::one(), E::Fr::one()) + }, |_| a.lc(CS::one(), E::Fr::one()), - |_| bc.lc(CS::one(), E::Fr::one()) - maj + |_| bc.lc(CS::one(), E::Fr::one()) - maj, ); Ok(AllocatedBit { value: maj_value, - variable: maj - }.into()) + variable: maj, + } + .into()) } } @@ -805,16 +734,11 @@ impl From for Boolean { #[cfg(test)] mod test { - use bellman::{ConstraintSystem}; + use super::{field_into_allocated_bits_le, u64_into_boolean_vec_le, AllocatedBit, Boolean}; + use crate::gadgets::test::*; + use crate::ConstraintSystem; + use ff::{Field, PrimeField}; use pairing::bls12_381::{Bls12, Fr}; - use pairing::{Field, PrimeField}; - use ::circuit::test::*; - use super::{ - AllocatedBit, - Boolean, - field_into_allocated_bits_le, - u64_into_boolean_vec_le - }; #[test] fn test_allocated_bit() { @@ -843,10 +767,24 @@ mod test { assert!(cs.is_satisfied()); assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("xor result") == if *a_val ^ *b_val { Field::one() } else { Field::zero() }); + assert!( + cs.get("xor result") + == if *a_val ^ *b_val { + Field::one() + } else { + Field::zero() + } + ); // Invert the result and check if the constraint system is still satisfied - cs.set("xor result", if *a_val ^ *b_val { Field::zero() } else { Field::one() }); + cs.set( + "xor result", + if *a_val ^ *b_val { + Field::zero() + } else { + Field::one() + }, + ); assert!(!cs.is_satisfied()); } } @@ -865,10 +803,24 @@ mod test { assert!(cs.is_satisfied()); assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("and result") == if *a_val & *b_val { Field::one() } else { Field::zero() }); + assert!( + cs.get("and result") + == if *a_val & *b_val { + Field::one() + } else { + Field::zero() + } + ); // Invert the result and check if the constraint system is still satisfied - cs.set("and result", if *a_val & *b_val { Field::zero() } else { Field::one() }); + cs.set( + "and result", + if *a_val & *b_val { + Field::zero() + } else { + Field::one() + }, + ); assert!(!cs.is_satisfied()); } } @@ -887,10 +839,24 @@ mod test { assert!(cs.is_satisfied()); assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("and not result") == if *a_val & !*b_val { Field::one() } else { Field::zero() }); + assert!( + cs.get("and not result") + == if *a_val & !*b_val { + Field::one() + } else { + Field::zero() + } + ); // Invert the result and check if the constraint system is still satisfied - cs.set("and not result", if *a_val & !*b_val { Field::zero() } else { Field::one() }); + cs.set( + "and not result", + if *a_val & !*b_val { + Field::zero() + } else { + Field::one() + }, + ); assert!(!cs.is_satisfied()); } } @@ -909,10 +875,24 @@ mod test { assert!(cs.is_satisfied()); assert!(cs.get("a/boolean") == if *a_val { Field::one() } else { Field::zero() }); assert!(cs.get("b/boolean") == if *b_val { Field::one() } else { Field::zero() }); - assert!(cs.get("nor result") == if !*a_val & !*b_val { Field::one() } else { Field::zero() }); + assert!( + cs.get("nor result") + == if !*a_val & !*b_val { + Field::one() + } else { + Field::zero() + } + ); // Invert the result and check if the constraint system is still satisfied - cs.set("nor result", if !*a_val & !*b_val { Field::zero() } else { Field::one() }); + cs.set( + "nor result", + if !*a_val & !*b_val { + Field::zero() + } else { + Field::one() + }, + ); assert!(!cs.is_satisfied()); } } @@ -927,8 +907,12 @@ mod test { { let mut cs = TestConstraintSystem::::new(); - let mut a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap()); - let mut b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap()); + let mut a = Boolean::from( + AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap(), + ); + let mut b = Boolean::from( + AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap(), + ); if a_neg { a = a.not(); @@ -939,16 +923,15 @@ mod test { Boolean::enforce_equal(&mut cs, &a, &b).unwrap(); - assert_eq!( - cs.is_satisfied(), - (a_bool ^ a_neg) == (b_bool ^ b_neg) - ); + assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg)); } { let mut cs = TestConstraintSystem::::new(); let mut a = Boolean::Constant(a_bool); - let mut b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap()); + let mut b = Boolean::from( + AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap(), + ); if a_neg { a = a.not(); @@ -959,15 +942,14 @@ mod test { Boolean::enforce_equal(&mut cs, &a, &b).unwrap(); - assert_eq!( - cs.is_satisfied(), - (a_bool ^ a_neg) == (b_bool ^ b_neg) - ); + assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg)); } { let mut cs = TestConstraintSystem::::new(); - let mut a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap()); + let mut a = Boolean::from( + AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap(), + ); let mut b = Boolean::Constant(b_bool); if a_neg { @@ -979,10 +961,7 @@ mod test { Boolean::enforce_equal(&mut cs, &a, &b).unwrap(); - assert_eq!( - cs.is_satisfied(), - (a_bool ^ a_neg) == (b_bool ^ b_neg) - ); + assert_eq!(cs.is_satisfied(), (a_bool ^ a_neg) == (b_bool ^ b_neg)); } { let mut cs = TestConstraintSystem::::new(); @@ -1019,43 +998,43 @@ mod test { let mut b = Boolean::from(AllocatedBit::alloc(&mut cs, Some(true)).unwrap()); match b { - Boolean::Is(_) => {}, - _ => panic!("unexpected value") + Boolean::Is(_) => {} + _ => panic!("unexpected value"), } b = b.not(); match b { - Boolean::Not(_) => {}, - _ => panic!("unexpected value") + Boolean::Not(_) => {} + _ => panic!("unexpected value"), } b = b.not(); match b { - Boolean::Is(_) => {}, - _ => panic!("unexpected value") + Boolean::Is(_) => {} + _ => panic!("unexpected value"), } b = Boolean::constant(true); match b { - Boolean::Constant(true) => {}, - _ => panic!("unexpected value") + Boolean::Constant(true) => {} + _ => panic!("unexpected value"), } b = b.not(); match b { - Boolean::Constant(false) => {}, - _ => panic!("unexpected value") + Boolean::Constant(false) => {} + _ => panic!("unexpected value"), } b = b.not(); match b { - Boolean::Constant(true) => {}, - _ => panic!("unexpected value") + Boolean::Constant(true) => {} + _ => panic!("unexpected value"), } } @@ -1066,7 +1045,7 @@ mod test { AllocatedTrue, AllocatedFalse, NegatedAllocatedTrue, - NegatedAllocatedFalse + NegatedAllocatedFalse, } impl OperandType { @@ -1077,7 +1056,7 @@ mod test { OperandType::AllocatedTrue => false, OperandType::AllocatedFalse => false, OperandType::NegatedAllocatedTrue => false, - OperandType::NegatedAllocatedFalse => false + OperandType::NegatedAllocatedFalse => false, } } @@ -1088,12 +1067,11 @@ mod test { OperandType::AllocatedTrue => true, OperandType::AllocatedFalse => false, OperandType::NegatedAllocatedTrue => false, - OperandType::NegatedAllocatedFalse => true + OperandType::NegatedAllocatedFalse => true, } } } - #[test] fn test_boolean_xor() { let variants = [ @@ -1102,7 +1080,7 @@ mod test { OperandType::AllocatedTrue, OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse + OperandType::NegatedAllocatedFalse, ]; for first_operand in variants.iter().cloned() { @@ -1119,10 +1097,18 @@ mod test { match operand { OperandType::True => Boolean::constant(true), OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), + OperandType::AllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + } + OperandType::AllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + } + OperandType::NegatedAllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not() + } + OperandType::NegatedAllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not() + } } }; @@ -1135,97 +1121,161 @@ mod test { assert!(cs.is_satisfied()); match (first_operand, second_operand, c) { - (OperandType::True, OperandType::True, Boolean::Constant(false)) => {}, - (OperandType::True, OperandType::False, Boolean::Constant(true)) => {}, - (OperandType::True, OperandType::AllocatedTrue, Boolean::Not(_)) => {}, - (OperandType::True, OperandType::AllocatedFalse, Boolean::Not(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Is(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Is(_)) => {}, + (OperandType::True, OperandType::True, Boolean::Constant(false)) => {} + (OperandType::True, OperandType::False, Boolean::Constant(true)) => {} + (OperandType::True, OperandType::AllocatedTrue, Boolean::Not(_)) => {} + (OperandType::True, OperandType::AllocatedFalse, Boolean::Not(_)) => {} + (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Is(_)) => {} + (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Is(_)) => {} - (OperandType::False, OperandType::True, Boolean::Constant(true)) => {}, - (OperandType::False, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::AllocatedTrue, Boolean::Is(_)) => {}, - (OperandType::False, OperandType::AllocatedFalse, Boolean::Is(_)) => {}, - (OperandType::False, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {}, - (OperandType::False, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {}, + (OperandType::False, OperandType::True, Boolean::Constant(true)) => {} + (OperandType::False, OperandType::False, Boolean::Constant(false)) => {} + (OperandType::False, OperandType::AllocatedTrue, Boolean::Is(_)) => {} + (OperandType::False, OperandType::AllocatedFalse, Boolean::Is(_)) => {} + (OperandType::False, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {} + (OperandType::False, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {} - (OperandType::AllocatedTrue, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::AllocatedTrue, OperandType::False, Boolean::Is(_)) => {}, - (OperandType::AllocatedTrue, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::AllocatedTrue, OperandType::True, Boolean::Not(_)) => {} + (OperandType::AllocatedTrue, OperandType::False, Boolean::Is(_)) => {} + ( + OperandType::AllocatedTrue, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Not(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::NegatedAllocatedTrue, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Not(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::NegatedAllocatedFalse, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, + } - (OperandType::AllocatedFalse, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::AllocatedFalse, OperandType::False, Boolean::Is(_)) => {}, - (OperandType::AllocatedFalse, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::AllocatedFalse, OperandType::True, Boolean::Not(_)) => {} + (OperandType::AllocatedFalse, OperandType::False, Boolean::Is(_)) => {} + ( + OperandType::AllocatedFalse, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedFalse, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Not(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::NegatedAllocatedTrue, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Not(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::NegatedAllocatedFalse, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, + } - (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::False, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedTrue, Boolean::Not(ref v)) => { + (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Is(_)) => {} + (OperandType::NegatedAllocatedTrue, OperandType::False, Boolean::Not(_)) => {} + ( + OperandType::NegatedAllocatedTrue, + OperandType::AllocatedTrue, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedFalse, Boolean::Not(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::AllocatedFalse, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, + } - (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::False, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedTrue, Boolean::Not(ref v)) => { + (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Is(_)) => {} + (OperandType::NegatedAllocatedFalse, OperandType::False, Boolean::Not(_)) => {} + ( + OperandType::NegatedAllocatedFalse, + OperandType::AllocatedTrue, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedFalse, Boolean::Not(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::AllocatedFalse, + Boolean::Not(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("xor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, + } - _ => panic!("this should never be encountered") + _ => panic!("this should never be encountered"), } } } @@ -1239,7 +1289,7 @@ mod test { OperandType::AllocatedTrue, OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse + OperandType::NegatedAllocatedFalse, ]; for first_operand in variants.iter().cloned() { @@ -1256,10 +1306,18 @@ mod test { match operand { OperandType::True => Boolean::constant(true), OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), + OperandType::AllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + } + OperandType::AllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + } + OperandType::NegatedAllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not() + } + OperandType::NegatedAllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not() + } } }; @@ -1272,98 +1330,183 @@ mod test { assert!(cs.is_satisfied()); match (first_operand, second_operand, c) { - (OperandType::True, OperandType::True, Boolean::Constant(true)) => {}, - (OperandType::True, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::True, OperandType::AllocatedTrue, Boolean::Is(_)) => {}, - (OperandType::True, OperandType::AllocatedFalse, Boolean::Is(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {}, - (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {}, + (OperandType::True, OperandType::True, Boolean::Constant(true)) => {} + (OperandType::True, OperandType::False, Boolean::Constant(false)) => {} + (OperandType::True, OperandType::AllocatedTrue, Boolean::Is(_)) => {} + (OperandType::True, OperandType::AllocatedFalse, Boolean::Is(_)) => {} + (OperandType::True, OperandType::NegatedAllocatedTrue, Boolean::Not(_)) => {} + (OperandType::True, OperandType::NegatedAllocatedFalse, Boolean::Not(_)) => {} - (OperandType::False, OperandType::True, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::AllocatedTrue, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::AllocatedFalse, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::NegatedAllocatedTrue, Boolean::Constant(false)) => {}, - (OperandType::False, OperandType::NegatedAllocatedFalse, Boolean::Constant(false)) => {}, + (OperandType::False, OperandType::True, Boolean::Constant(false)) => {} + (OperandType::False, OperandType::False, Boolean::Constant(false)) => {} + (OperandType::False, OperandType::AllocatedTrue, Boolean::Constant(false)) => {} + (OperandType::False, OperandType::AllocatedFalse, Boolean::Constant(false)) => { + } + ( + OperandType::False, + OperandType::NegatedAllocatedTrue, + Boolean::Constant(false), + ) => {} + ( + OperandType::False, + OperandType::NegatedAllocatedFalse, + Boolean::Constant(false), + ) => {} - (OperandType::AllocatedTrue, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::AllocatedTrue, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::AllocatedTrue, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::AllocatedTrue, OperandType::True, Boolean::Is(_)) => {} + (OperandType::AllocatedTrue, OperandType::False, Boolean::Constant(false)) => {} + ( + OperandType::AllocatedTrue, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::AllocatedTrue, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedTrue, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::one()); assert_eq!(v.value, Some(true)); - }, + } - (OperandType::AllocatedFalse, OperandType::True, Boolean::Is(_)) => {}, - (OperandType::AllocatedFalse, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::AllocatedFalse, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::AllocatedFalse, OperandType::True, Boolean::Is(_)) => {} + (OperandType::AllocatedFalse, OperandType::False, Boolean::Constant(false)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::AllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::AllocatedFalse, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, + } - (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::NegatedAllocatedTrue, OperandType::True, Boolean::Not(_)) => {} + ( + OperandType::NegatedAllocatedTrue, + OperandType::False, + Boolean::Constant(false), + ) => {} + ( + OperandType::NegatedAllocatedTrue, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("nor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedTrue, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedTrue, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("nor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, + } - (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Not(_)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::False, Boolean::Constant(false)) => {}, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedTrue, Boolean::Is(ref v)) => { + (OperandType::NegatedAllocatedFalse, OperandType::True, Boolean::Not(_)) => {} + ( + OperandType::NegatedAllocatedFalse, + OperandType::False, + Boolean::Constant(false), + ) => {} + ( + OperandType::NegatedAllocatedFalse, + OperandType::AllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::one()); assert_eq!(v.value, Some(true)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::AllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::AllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("and not result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedTrue, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::NegatedAllocatedTrue, + Boolean::Is(ref v), + ) => { assert!(cs.get("nor result") == Field::zero()); assert_eq!(v.value, Some(false)); - }, - (OperandType::NegatedAllocatedFalse, OperandType::NegatedAllocatedFalse, Boolean::Is(ref v)) => { + } + ( + OperandType::NegatedAllocatedFalse, + OperandType::NegatedAllocatedFalse, + Boolean::Is(ref v), + ) => { assert!(cs.get("nor result") == Field::one()); assert_eq!(v.value, Some(true)); - }, + } _ => { - panic!("unexpected behavior at {:?} AND {:?}", first_operand, second_operand); + panic!( + "unexpected behavior at {:?} AND {:?}", + first_operand, second_operand + ); } } } @@ -1395,7 +1538,10 @@ mod test { fn test_field_into_allocated_bits_le() { let mut cs = TestConstraintSystem::::new(); - let r = Fr::from_str("9147677615426976802526883532204139322118074541891858454835346926874644257775").unwrap(); + let r = Fr::from_str( + "9147677615426976802526883532204139322118074541891858454835346926874644257775", + ) + .unwrap(); let bits = field_into_allocated_bits_le(&mut cs, Some(r)).unwrap(); @@ -1421,7 +1567,7 @@ mod test { OperandType::AllocatedTrue, OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse + OperandType::NegatedAllocatedFalse, ]; for first_operand in variants.iter().cloned() { @@ -1434,8 +1580,8 @@ mod test { let c; // ch = (a and b) xor ((not a) and c) - let expected = (first_operand.val() & second_operand.val()) ^ - ((!first_operand.val()) & third_operand.val()); + let expected = (first_operand.val() & second_operand.val()) + ^ ((!first_operand.val()) & third_operand.val()); { let mut dyn_construct = |operand, name| { @@ -1444,10 +1590,20 @@ mod test { match operand { OperandType::True => Boolean::constant(true), OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), + OperandType::AllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + } + OperandType::AllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + } + OperandType::NegatedAllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + .not() + } + OperandType::NegatedAllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + .not() + } } }; @@ -1462,19 +1618,17 @@ mod test { assert_eq!(maj.get_value().unwrap(), expected); - if first_operand.is_constant() || - second_operand.is_constant() || - third_operand.is_constant() + if first_operand.is_constant() + || second_operand.is_constant() + || third_operand.is_constant() { - if first_operand.is_constant() && - second_operand.is_constant() && - third_operand.is_constant() + if first_operand.is_constant() + && second_operand.is_constant() + && third_operand.is_constant() { assert_eq!(cs.num_constraints(), 0); } - } - else - { + } else { assert_eq!(cs.get("ch"), { if expected { Fr::one() @@ -1504,7 +1658,7 @@ mod test { OperandType::AllocatedTrue, OperandType::AllocatedFalse, OperandType::NegatedAllocatedTrue, - OperandType::NegatedAllocatedFalse + OperandType::NegatedAllocatedFalse, ]; for first_operand in variants.iter().cloned() { @@ -1517,9 +1671,9 @@ mod test { let c; // maj = (a and b) xor (a and c) xor (b and c) - let expected = (first_operand.val() & second_operand.val()) ^ - (first_operand.val() & third_operand.val()) ^ - (second_operand.val() & third_operand.val()); + let expected = (first_operand.val() & second_operand.val()) + ^ (first_operand.val() & third_operand.val()) + ^ (second_operand.val() & third_operand.val()); { let mut dyn_construct = |operand, name| { @@ -1528,10 +1682,20 @@ mod test { match operand { OperandType::True => Boolean::constant(true), OperandType::False => Boolean::constant(false), - OperandType::AllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()), - OperandType::AllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()), - OperandType::NegatedAllocatedTrue => Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()).not(), - OperandType::NegatedAllocatedFalse => Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()).not(), + OperandType::AllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + } + OperandType::AllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + } + OperandType::NegatedAllocatedTrue => { + Boolean::from(AllocatedBit::alloc(cs, Some(true)).unwrap()) + .not() + } + OperandType::NegatedAllocatedFalse => { + Boolean::from(AllocatedBit::alloc(cs, Some(false)).unwrap()) + .not() + } } }; @@ -1546,19 +1710,17 @@ mod test { assert_eq!(maj.get_value().unwrap(), expected); - if first_operand.is_constant() || - second_operand.is_constant() || - third_operand.is_constant() + if first_operand.is_constant() + || second_operand.is_constant() + || third_operand.is_constant() { - if first_operand.is_constant() && - second_operand.is_constant() && - third_operand.is_constant() + if first_operand.is_constant() + && second_operand.is_constant() + && third_operand.is_constant() { assert_eq!(cs.num_constraints(), 0); } - } - else - { + } else { assert_eq!(cs.get("maj"), { if expected { Fr::one() @@ -1579,4 +1741,72 @@ mod test { } } } + + #[test] + fn test_alloc_conditionally() { + { + let mut cs = TestConstraintSystem::::new(); + let b = AllocatedBit::alloc(&mut cs, Some(false)).unwrap(); + + let value = None; + // if value is none, fail with SynthesisError + let is_err = AllocatedBit::alloc_conditionally( + cs.namespace(|| "alloc_conditionally"), + value, + &b, + ) + .is_err(); + assert!(is_err); + } + + { + // since value is true, b must be false, so it should succeed + let mut cs = TestConstraintSystem::::new(); + + let value = Some(true); + let b = AllocatedBit::alloc(&mut cs, Some(false)).unwrap(); + let allocated_value = AllocatedBit::alloc_conditionally( + cs.namespace(|| "alloc_conditionally"), + value, + &b, + ) + .unwrap(); + + assert_eq!(allocated_value.get_value().unwrap(), true); + assert!(cs.is_satisfied()); + } + + { + // since value is true, b must be false, so it should fail + let mut cs = TestConstraintSystem::::new(); + + let value = Some(true); + let b = AllocatedBit::alloc(&mut cs, Some(true)).unwrap(); + AllocatedBit::alloc_conditionally(cs.namespace(|| "alloc_conditionally"), value, &b) + .unwrap(); + + assert!(!cs.is_satisfied()); + } + + { + // since value is false, we don't care about the value of the bit + + let value = Some(false); + //check with false bit + let mut cs = TestConstraintSystem::::new(); + let b1 = AllocatedBit::alloc(&mut cs, Some(false)).unwrap(); + AllocatedBit::alloc_conditionally(cs.namespace(|| "alloc_conditionally"), value, &b1) + .unwrap(); + + assert!(cs.is_satisfied()); + + //check with true bit + let mut cs = TestConstraintSystem::::new(); + let b2 = AllocatedBit::alloc(&mut cs, Some(true)).unwrap(); + AllocatedBit::alloc_conditionally(cs.namespace(|| "alloc_conditionally"), value, &b2) + .unwrap(); + + assert!(cs.is_satisfied()); + } + } } diff --git a/sapling-crypto/src/circuit/lookup.rs b/src/gadgets/lookup.rs similarity index 54% rename from sapling-crypto/src/circuit/lookup.rs rename to src/gadgets/lookup.rs index 1ffc7f7..b83844d 100644 --- a/sapling-crypto/src/circuit/lookup.rs +++ b/src/gadgets/lookup.rs @@ -1,21 +1,16 @@ -use pairing::{Engine, Field}; -use super::*; -use super::num::{ - AllocatedNum, - Num -}; +//! Window table lookup gadgets. + +use ff::{Field, ScalarEngine}; + use super::boolean::Boolean; -use bellman::{ - ConstraintSystem -}; +use super::num::{AllocatedNum, Num}; +use super::*; +use crate::ConstraintSystem; // Synthesize the constants for each base pattern. -fn synth<'a, E: Engine, I>( - window_size: usize, - constants: I, - assignment: &mut [E::Fr] -) - where I: IntoIterator +fn synth<'a, E: ScalarEngine, I>(window_size: usize, constants: I, assignment: &mut [E::Fr]) +where + I: IntoIterator, { assert_eq!(assignment.len(), 1 << window_size); @@ -34,19 +29,23 @@ fn synth<'a, E: Engine, I>( /// Performs a 3-bit window table lookup. `bits` is in /// little-endian order. -pub fn lookup3_xy( +pub fn lookup3_xy( mut cs: CS, bits: &[Boolean], - coords: &[(E::Fr, E::Fr)] + coords: &[(E::Fr, E::Fr)], ) -> Result<(AllocatedNum, AllocatedNum), SynthesisError> - where CS: ConstraintSystem +where + CS: ConstraintSystem, { assert_eq!(bits.len(), 3); assert_eq!(coords.len(), 8); // Calculate the index into `coords` - let i = - match (bits[0].get_value(), bits[1].get_value(), bits[2].get_value()) { + let i = match ( + bits[0].get_value(), + bits[1].get_value(), + bits[2].get_value(), + ) { (Some(a_value), Some(b_value), Some(c_value)) => { let mut tmp = 0; if a_value { @@ -59,25 +58,15 @@ pub fn lookup3_xy( tmp += 4; } Some(tmp) - }, - _ => None + } + _ => None, }; // Allocate the x-coordinate resulting from the lookup - let res_x = AllocatedNum::alloc( - cs.namespace(|| "x"), - || { - Ok(coords[*i.get()?].0) - } - )?; + let res_x = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(coords[*i.get()?].0))?; // Allocate the y-coordinate resulting from the lookup - let res_y = AllocatedNum::alloc( - cs.namespace(|| "y"), - || { - Ok(coords[*i.get()?].1) - } - )?; + let res_y = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(coords[*i.get()?].1))?; // Compute the coefficients for the lookup constraints let mut x_coeffs = [E::Fr::zero(); 8]; @@ -91,30 +80,38 @@ pub fn lookup3_xy( cs.enforce( || "x-coordinate lookup", - |lc| lc + (x_coeffs[0b001], one) + |lc| { + lc + (x_coeffs[0b001], one) + &bits[1].lc::(one, x_coeffs[0b011]) + &bits[2].lc::(one, x_coeffs[0b101]) - + &precomp.lc::(one, x_coeffs[0b111]), + + &precomp.lc::(one, x_coeffs[0b111]) + }, |lc| lc + &bits[0].lc::(one, E::Fr::one()), - |lc| lc + res_x.get_variable() + |lc| { + lc + res_x.get_variable() - (x_coeffs[0b000], one) - &bits[1].lc::(one, x_coeffs[0b010]) - &bits[2].lc::(one, x_coeffs[0b100]) - - &precomp.lc::(one, x_coeffs[0b110]), + - &precomp.lc::(one, x_coeffs[0b110]) + }, ); cs.enforce( || "y-coordinate lookup", - |lc| lc + (y_coeffs[0b001], one) + |lc| { + lc + (y_coeffs[0b001], one) + &bits[1].lc::(one, y_coeffs[0b011]) + &bits[2].lc::(one, y_coeffs[0b101]) - + &precomp.lc::(one, y_coeffs[0b111]), + + &precomp.lc::(one, y_coeffs[0b111]) + }, |lc| lc + &bits[0].lc::(one, E::Fr::one()), - |lc| lc + res_y.get_variable() + |lc| { + lc + res_y.get_variable() - (y_coeffs[0b000], one) - &bits[1].lc::(one, y_coeffs[0b010]) - &bits[2].lc::(one, y_coeffs[0b100]) - - &precomp.lc::(one, y_coeffs[0b110]), + - &precomp.lc::(one, y_coeffs[0b110]) + }, ); Ok((res_x, res_y)) @@ -122,19 +119,19 @@ pub fn lookup3_xy( /// Performs a 3-bit window table lookup, where /// one of the bits is a sign bit. -pub fn lookup3_xy_with_conditional_negation( +pub fn lookup3_xy_with_conditional_negation( mut cs: CS, bits: &[Boolean], - coords: &[(E::Fr, E::Fr)] + coords: &[(E::Fr, E::Fr)], ) -> Result<(Num, Num), SynthesisError> - where CS: ConstraintSystem +where + CS: ConstraintSystem, { assert_eq!(bits.len(), 3); assert_eq!(coords.len(), 4); // Calculate the index into `coords` - let i = - match (bits[0].get_value(), bits[1].get_value()) { + let i = match (bits[0].get_value(), bits[1].get_value()) { (Some(a_value), Some(b_value)) => { let mut tmp = 0; if a_value { @@ -144,22 +141,19 @@ pub fn lookup3_xy_with_conditional_negation( tmp += 2; } Some(tmp) - }, - _ => None + } + _ => None, }; // Allocate the y-coordinate resulting from the lookup // and conditional negation - let y = AllocatedNum::alloc( - cs.namespace(|| "y"), - || { - let mut tmp = coords[*i.get()?].1; - if *bits[2].get_value().get()? { - tmp.negate(); - } - Ok(tmp) + let y = AllocatedNum::alloc(cs.namespace(|| "y"), || { + let mut tmp = coords[*i.get()?].1; + if *bits[2].get_value().get()? { + tmp.negate(); } - )?; + Ok(tmp) + })?; let one = CS::one(); @@ -172,21 +166,21 @@ pub fn lookup3_xy_with_conditional_negation( let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[0], &bits[1])?; let x = Num::zero() - .add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00]) - .add_bool_with_coeff(one, &bits[0], x_coeffs[0b01]) - .add_bool_with_coeff(one, &bits[1], x_coeffs[0b10]) - .add_bool_with_coeff(one, &precomp, x_coeffs[0b11]); + .add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00]) + .add_bool_with_coeff(one, &bits[0], x_coeffs[0b01]) + .add_bool_with_coeff(one, &bits[1], x_coeffs[0b10]) + .add_bool_with_coeff(one, &precomp, x_coeffs[0b11]); - let y_lc = precomp.lc::(one, y_coeffs[0b11]) + - &bits[1].lc::(one, y_coeffs[0b10]) + - &bits[0].lc::(one, y_coeffs[0b01]) + - (y_coeffs[0b00], one); + let y_lc = precomp.lc::(one, y_coeffs[0b11]) + + &bits[1].lc::(one, y_coeffs[0b10]) + + &bits[0].lc::(one, y_coeffs[0b01]) + + (y_coeffs[0b00], one); cs.enforce( || "y-coordinate lookup", |lc| lc + &y_lc + &y_lc, |lc| lc + &bits[2].lc::(one, E::Fr::one()), - |lc| lc + &y_lc - y.get_variable() + |lc| lc + &y_lc - y.get_variable(), ); Ok((x, y.into())) @@ -194,46 +188,52 @@ pub fn lookup3_xy_with_conditional_negation( #[cfg(test)] mod test { - use rand::{SeedableRng, Rand, Rng, XorShiftRng}; use super::*; - use ::circuit::test::*; - use ::circuit::boolean::{Boolean, AllocatedBit}; + use crate::gadgets::boolean::{AllocatedBit, Boolean}; + use crate::gadgets::test::*; use pairing::bls12_381::{Bls12, Fr}; + use rand_core::{RngCore, SeedableRng}; + use rand_xorshift::XorShiftRng; #[test] fn test_lookup3_xy() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0656]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); for _ in 0..100 { let mut cs = TestConstraintSystem::::new(); - let a_val = rng.gen(); - let a = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap() - ); + let a_val = rng.next_u32() % 2 != 0; + let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()); - let b_val = rng.gen(); - let b = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap() - ); + let b_val = rng.next_u32() % 2 != 0; + let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap()); - let c_val = rng.gen(); - let c = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap() - ); + let c_val = rng.next_u32() % 2 != 0; + let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap()); let bits = vec![a, b, c]; - let points: Vec<(Fr, Fr)> = (0..8).map(|_| (rng.gen(), rng.gen())).collect(); + let points: Vec<(Fr, Fr)> = (0..8) + .map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))) + .collect(); let res = lookup3_xy(&mut cs, &bits, &points).unwrap(); assert!(cs.is_satisfied()); let mut index = 0; - if a_val { index += 1 } - if b_val { index += 2 } - if c_val { index += 4 } + if a_val { + index += 1 + } + if b_val { + index += 2 + } + if c_val { + index += 4 + } assert_eq!(res.0.get_value().unwrap(), points[index].0); assert_eq!(res.1.get_value().unwrap(), points[index].1); @@ -242,53 +242,63 @@ mod test { #[test] fn test_lookup3_xy_with_conditional_negation() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); for _ in 0..100 { let mut cs = TestConstraintSystem::::new(); - let a_val = rng.gen(); - let a = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap() - ); + let a_val = rng.next_u32() % 2 != 0; + let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()); - let b_val = rng.gen(); - let b = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap() - ); + let b_val = rng.next_u32() % 2 != 0; + let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap()); - let c_val = rng.gen(); - let c = Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap() - ); + let c_val = rng.next_u32() % 2 != 0; + let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap()); let bits = vec![a, b, c]; - let points: Vec<(Fr, Fr)> = (0..4).map(|_| (rng.gen(), rng.gen())).collect(); + let points: Vec<(Fr, Fr)> = (0..4) + .map(|_| (Fr::random(&mut rng), Fr::random(&mut rng))) + .collect(); let res = lookup3_xy_with_conditional_negation(&mut cs, &bits, &points).unwrap(); assert!(cs.is_satisfied()); let mut index = 0; - if a_val { index += 1 } - if b_val { index += 2 } + if a_val { + index += 1 + } + if b_val { + index += 2 + } assert_eq!(res.0.get_value().unwrap(), points[index].0); let mut tmp = points[index].1; - if c_val { tmp.negate() } + if c_val { + tmp.negate() + } assert_eq!(res.1.get_value().unwrap(), tmp); } } #[test] fn test_synth() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let window_size = 4; let mut assignment = vec![Fr::zero(); 1 << window_size]; - let constants: Vec<_> = (0..(1 << window_size)).map(|_| Fr::rand(&mut rng)).collect(); + let constants: Vec<_> = (0..(1 << window_size)) + .map(|_| Fr::random(&mut rng)) + .collect(); synth::(window_size, &constants, &mut assignment); diff --git a/sapling-crypto/src/circuit/multieq.rs b/src/gadgets/multieq.rs similarity index 52% rename from sapling-crypto/src/circuit/multieq.rs rename to src/gadgets/multieq.rs index 0f9c755..d052822 100644 --- a/sapling-crypto/src/circuit/multieq.rs +++ b/src/gadgets/multieq.rs @@ -1,17 +1,8 @@ -use pairing::{ - Engine, - Field, - PrimeField -}; +use ff::{Field, PrimeField, ScalarEngine}; -use bellman::{ - SynthesisError, - ConstraintSystem, - LinearCombination, - Variable -}; +use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; -pub struct MultiEq>{ +pub struct MultiEq> { cs: CS, ops: usize, bits_used: usize, @@ -19,19 +10,18 @@ pub struct MultiEq>{ rhs: LinearCombination, } -impl> MultiEq { +impl> MultiEq { pub fn new(cs: CS) -> Self { MultiEq { - cs: cs, + cs, ops: 0, bits_used: 0, lhs: LinearCombination::zero(), - rhs: LinearCombination::zero() + rhs: LinearCombination::zero(), } } - fn accumulate(&mut self) - { + fn accumulate(&mut self) { let ops = self.ops; let lhs = self.lhs.clone(); let rhs = self.rhs.clone(); @@ -39,7 +29,7 @@ impl> MultiEq { || format!("multieq {}", ops), |_| lhs, |lc| lc + CS::one(), - |_| rhs + |_| rhs, ); self.lhs = LinearCombination::zero(); self.rhs = LinearCombination::zero(); @@ -51,9 +41,8 @@ impl> MultiEq { &mut self, num_bits: usize, lhs: &LinearCombination, - rhs: &LinearCombination - ) - { + rhs: &LinearCombination, + ) { // Check if we will exceed the capacity if (E::Fr::CAPACITY as usize) <= (self.bits_used + num_bits) { self.accumulate(); @@ -68,70 +57,63 @@ impl> MultiEq { } } -impl> Drop for MultiEq { +impl> Drop for MultiEq { fn drop(&mut self) { if self.bits_used > 0 { - self.accumulate(); + self.accumulate(); } } } -impl> ConstraintSystem for MultiEq -{ +impl> ConstraintSystem for MultiEq { type Root = Self; fn one() -> Variable { CS::one() } - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.cs.alloc(annotation, f) } - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.cs.alloc_input(annotation, f) } - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, annotation: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { self.cs.enforce(annotation, a, b, c) } fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { self.cs.get_root().push_namespace(name_fn) } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { self.cs.get_root().pop_namespace() } - fn get_root(&mut self) -> &mut Self::Root - { + fn get_root(&mut self) -> &mut Self::Root { self } } diff --git a/src/gadgets/multipack.rs b/src/gadgets/multipack.rs new file mode 100644 index 0000000..c0dc50e --- /dev/null +++ b/src/gadgets/multipack.rs @@ -0,0 +1,111 @@ +//! Helpers for packing vectors of bits into scalar field elements. + +use super::boolean::Boolean; +use super::num::Num; +use super::Assignment; +use crate::{ConstraintSystem, SynthesisError}; +use ff::{Field, PrimeField, ScalarEngine}; + +/// Takes a sequence of booleans and exposes them as compact +/// public inputs +pub fn pack_into_inputs(mut cs: CS, bits: &[Boolean]) -> Result<(), SynthesisError> +where + E: ScalarEngine, + CS: ConstraintSystem, +{ + for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() { + let mut num = Num::::zero(); + let mut coeff = E::Fr::one(); + for bit in bits { + num = num.add_bool_with_coeff(CS::one(), bit, coeff); + + coeff.double(); + } + + let input = cs.alloc_input(|| format!("input {}", i), || Ok(*num.get_value().get()?))?; + + // num * 1 = input + cs.enforce( + || format!("packing constraint {}", i), + |_| num.lc(E::Fr::one()), + |lc| lc + CS::one(), + |lc| lc + input, + ); + } + + Ok(()) +} + +pub fn bytes_to_bits(bytes: &[u8]) -> Vec { + bytes + .iter() + .flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1)) + .collect() +} + +pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec { + bytes + .iter() + .flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1)) + .collect() +} + +pub fn compute_multipacking(bits: &[bool]) -> Vec { + let mut result = vec![]; + + for bits in bits.chunks(E::Fr::CAPACITY as usize) { + let mut cur = E::Fr::zero(); + let mut coeff = E::Fr::one(); + + for bit in bits { + if *bit { + cur.add_assign(&coeff); + } + + coeff.double(); + } + + result.push(cur); + } + + result +} + +#[test] +fn test_multipacking() { + use crate::ConstraintSystem; + use pairing::bls12_381::Bls12; + use rand_core::{RngCore, SeedableRng}; + use rand_xorshift::XorShiftRng; + + use super::boolean::{AllocatedBit, Boolean}; + use crate::gadgets::test::*; + + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for num_bits in 0..1500 { + let mut cs = TestConstraintSystem::::new(); + + let bits: Vec = (0..num_bits).map(|_| rng.next_u32() % 2 != 0).collect(); + + let circuit_bits = bits + .iter() + .enumerate() + .map(|(i, &b)| { + Boolean::from( + AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), Some(b)).unwrap(), + ) + }) + .collect::>(); + + let expected_inputs = compute_multipacking::(&bits); + + pack_into_inputs(cs.namespace(|| "pack"), &circuit_bits).unwrap(); + + assert!(cs.is_satisfied()); + assert!(cs.verify(&expected_inputs)); + } +} diff --git a/sapling-crypto/src/circuit/num.rs b/src/gadgets/num.rs similarity index 66% rename from sapling-crypto/src/circuit/num.rs rename to src/gadgets/num.rs index 53a2f6c..8be5448 100644 --- a/sapling-crypto/src/circuit/num.rs +++ b/src/gadgets/num.rs @@ -1,83 +1,62 @@ -use pairing::{ - Engine, - Field, - PrimeField, - PrimeFieldRepr, - BitIterator -}; +//! Gadgets representing numbers in the scalar field of the underlying curve. -use bellman::{ - SynthesisError, - ConstraintSystem, - LinearCombination, - Variable -}; +use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, ScalarEngine}; -use super::{ - Assignment -}; +use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable}; -use super::boolean::{ - self, - Boolean, - AllocatedBit -}; +use super::Assignment; -pub struct AllocatedNum { +use super::boolean::{self, AllocatedBit, Boolean}; + +pub struct AllocatedNum { value: Option, - variable: Variable + variable: Variable, } -impl Clone for AllocatedNum { +impl Clone for AllocatedNum { fn clone(&self) -> Self { AllocatedNum { value: self.value, - variable: self.variable + variable: self.variable, } } } -impl AllocatedNum { - pub fn alloc( - mut cs: CS, - value: F, - ) -> Result - where CS: ConstraintSystem, - F: FnOnce() -> Result +impl AllocatedNum { + pub fn alloc(mut cs: CS, value: F) -> Result + where + CS: ConstraintSystem, + F: FnOnce() -> Result, { let mut new_value = None; - let var = cs.alloc(|| "num", || { - let tmp = value()?; + let var = cs.alloc( + || "num", + || { + let tmp = value()?; - new_value = Some(tmp); + new_value = Some(tmp); - Ok(tmp) - })?; + Ok(tmp) + }, + )?; Ok(AllocatedNum { value: new_value, - variable: var + variable: var, }) } - pub fn inputize( - &self, - mut cs: CS - ) -> Result<(), SynthesisError> - where CS: ConstraintSystem + pub fn inputize(&self, mut cs: CS) -> Result<(), SynthesisError> + where + CS: ConstraintSystem, { - let input = cs.alloc_input( - || "input variable", - || { - Ok(*self.value.get()?) - } - )?; + let input = cs.alloc_input(|| "input variable", || Ok(*self.value.get()?))?; cs.enforce( || "enforce input is correct", |lc| lc + input, |lc| lc + CS::one(), - |lc| lc + self.variable + |lc| lc + self.variable, ); Ok(()) @@ -88,20 +67,19 @@ impl AllocatedNum { /// order, requiring that the representation /// strictly exists "in the field" (i.e., a /// congruency is not allowed.) - pub fn into_bits_le_strict( - &self, - mut cs: CS - ) -> Result, SynthesisError> - where CS: ConstraintSystem + pub fn to_bits_le_strict(&self, mut cs: CS) -> Result, SynthesisError> + where + CS: ConstraintSystem, { pub fn kary_and( mut cs: CS, - v: &[AllocatedBit] + v: &[AllocatedBit], ) -> Result - where E: Engine, - CS: ConstraintSystem + where + E: ScalarEngine, + CS: ConstraintSystem, { - assert!(v.len() > 0); + assert!(!v.is_empty()); // Let's keep this simple for now and just AND them all // manually @@ -114,7 +92,7 @@ impl AllocatedNum { cur = Some(AllocatedBit::and( cs.namespace(|| format!("and {}", i)), cur.as_ref().unwrap(), - v + v, )?); } } @@ -150,15 +128,12 @@ impl AllocatedNum { if b { // This is part of a run of ones. Let's just // allocate the boolean with the expected value. - let a_bit = AllocatedBit::alloc( - cs.namespace(|| format!("bit {}", i)), - a_bit - )?; + let a_bit = AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), a_bit)?; // ... and add it to the current run of ones. current_run.push(a_bit.clone()); result.push(a_bit); } else { - if current_run.len() > 0 { + if !current_run.is_empty() { // This is the start of a run of zeros, but we need // to k-ary AND against `last_run` first. @@ -167,7 +142,7 @@ impl AllocatedNum { } last_run = Some(kary_and( cs.namespace(|| format!("run ending at {}", i)), - ¤t_run + ¤t_run, )?); current_run.truncate(0); } @@ -180,7 +155,7 @@ impl AllocatedNum { let a_bit = AllocatedBit::alloc_conditionally( cs.namespace(|| format!("bit {}", i)), a_bit, - &last_run.as_ref().expect("char always starts with a one") + &last_run.as_ref().expect("char always starts with a one"), )?; result.push(a_bit); } @@ -206,30 +181,20 @@ impl AllocatedNum { lc = lc - self.variable; - cs.enforce( - || "unpacking constraint", - |lc| lc, - |lc| lc, - |_| lc - ); + cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc); // Convert into booleans, and reverse for little-endian bit order - Ok(result.into_iter().map(|b| Boolean::from(b)).rev().collect()) + Ok(result.into_iter().map(Boolean::from).rev().collect()) } /// Convert the allocated number into its little-endian representation. /// Note that this does not strongly enforce that the commitment is /// "in the field." - pub fn into_bits_le( - &self, - mut cs: CS - ) -> Result, SynthesisError> - where CS: ConstraintSystem + pub fn to_bits_le(&self, mut cs: CS) -> Result, SynthesisError> + where + CS: ConstraintSystem, { - let bits = boolean::field_into_allocated_bits_le( - &mut cs, - self.value - )?; + let bits = boolean::field_into_allocated_bits_le(&mut cs, self.value)?; let mut lc = LinearCombination::zero(); let mut coeff = E::Fr::one(); @@ -242,94 +207,91 @@ impl AllocatedNum { lc = lc - self.variable; - cs.enforce( - || "unpacking constraint", - |lc| lc, - |lc| lc, - |_| lc - ); + cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc); - Ok(bits.into_iter().map(|b| Boolean::from(b)).collect()) + Ok(bits.into_iter().map(Boolean::from).collect()) } - pub fn mul( - &self, - mut cs: CS, - other: &Self - ) -> Result - where CS: ConstraintSystem + pub fn mul(&self, mut cs: CS, other: &Self) -> Result + where + CS: ConstraintSystem, { let mut value = None; - let var = cs.alloc(|| "product num", || { - let mut tmp = *self.value.get()?; - tmp.mul_assign(other.value.get()?); + let var = cs.alloc( + || "product num", + || { + let mut tmp = *self.value.get()?; + tmp.mul_assign(other.value.get()?); - value = Some(tmp); + value = Some(tmp); - Ok(tmp) - })?; + Ok(tmp) + }, + )?; // Constrain: a * b = ab cs.enforce( || "multiplication constraint", |lc| lc + self.variable, |lc| lc + other.variable, - |lc| lc + var + |lc| lc + var, ); Ok(AllocatedNum { - value: value, - variable: var + value, + variable: var, }) } - pub fn square( - &self, - mut cs: CS - ) -> Result - where CS: ConstraintSystem + pub fn square(&self, mut cs: CS) -> Result + where + CS: ConstraintSystem, { let mut value = None; - let var = cs.alloc(|| "squared num", || { - let mut tmp = *self.value.get()?; - tmp.square(); + let var = cs.alloc( + || "squared num", + || { + let mut tmp = *self.value.get()?; + tmp.square(); - value = Some(tmp); + value = Some(tmp); - Ok(tmp) - })?; + Ok(tmp) + }, + )?; // Constrain: a * a = aa cs.enforce( || "squaring constraint", |lc| lc + self.variable, |lc| lc + self.variable, - |lc| lc + var + |lc| lc + var, ); Ok(AllocatedNum { - value: value, - variable: var + value, + variable: var, }) } - pub fn assert_nonzero( - &self, - mut cs: CS - ) -> Result<(), SynthesisError> - where CS: ConstraintSystem + pub fn assert_nonzero(&self, mut cs: CS) -> Result<(), SynthesisError> + where + CS: ConstraintSystem, { - let inv = cs.alloc(|| "ephemeral inverse", || { - let tmp = *self.value.get()?; - - if tmp.is_zero() { - Err(SynthesisError::DivisionByZero) - } else { - Ok(tmp.inverse().unwrap()) - } - })?; + let inv = cs.alloc( + || "ephemeral inverse", + || { + let tmp = *self.value.get()?; + + if tmp.is_zero() { + Err(SynthesisError::DivisionByZero) + } else { + Ok(tmp.inverse().unwrap()) + } + }, + )?; // Constrain a * inv = 1, which is only valid // iff a has a multiplicative inverse, untrue @@ -338,7 +300,7 @@ impl AllocatedNum { || "nonzero assertion constraint", |lc| lc + self.variable, |lc| lc + inv, - |lc| lc + CS::one() + |lc| lc + CS::one(), ); Ok(()) @@ -351,44 +313,39 @@ impl AllocatedNum { mut cs: CS, a: &Self, b: &Self, - condition: &Boolean + condition: &Boolean, ) -> Result<(Self, Self), SynthesisError> - where CS: ConstraintSystem + where + CS: ConstraintSystem, { - let c = Self::alloc( - cs.namespace(|| "conditional reversal result 1"), - || { - if *condition.get_value().get()? { - Ok(*b.value.get()?) - } else { - Ok(*a.value.get()?) - } + let c = Self::alloc(cs.namespace(|| "conditional reversal result 1"), || { + if *condition.get_value().get()? { + Ok(*b.value.get()?) + } else { + Ok(*a.value.get()?) } - )?; + })?; cs.enforce( || "first conditional reversal", |lc| lc + a.variable - b.variable, |_| condition.lc(CS::one(), E::Fr::one()), - |lc| lc + a.variable - c.variable + |lc| lc + a.variable - c.variable, ); - let d = Self::alloc( - cs.namespace(|| "conditional reversal result 2"), - || { - if *condition.get_value().get()? { - Ok(*a.value.get()?) - } else { - Ok(*b.value.get()?) - } + let d = Self::alloc(cs.namespace(|| "conditional reversal result 2"), || { + if *condition.get_value().get()? { + Ok(*a.value.get()?) + } else { + Ok(*b.value.get()?) } - )?; + })?; cs.enforce( || "second conditional reversal", |lc| lc + b.variable - a.variable, |_| condition.lc(CS::one(), E::Fr::one()), - |lc| lc + b.variable - d.variable + |lc| lc + b.variable - d.variable, ); Ok((c, d)) @@ -403,25 +360,25 @@ impl AllocatedNum { } } -pub struct Num { +pub struct Num { value: Option, - lc: LinearCombination + lc: LinearCombination, } -impl From> for Num { +impl From> for Num { fn from(num: AllocatedNum) -> Num { Num { value: num.value, - lc: LinearCombination::::zero() + num.variable + lc: LinearCombination::::zero() + num.variable, } } } -impl Num { +impl Num { pub fn zero() -> Self { Num { value: Some(E::Fr::zero()), - lc: LinearCombination::zero() + lc: LinearCombination::zero(), } } @@ -433,13 +390,7 @@ impl Num { LinearCombination::zero() + (coeff, &self.lc) } - pub fn add_bool_with_coeff( - self, - one: Variable, - bit: &Boolean, - coeff: E::Fr - ) -> Self - { + pub fn add_bool_with_coeff(self, one: Variable, bit: &Boolean, coeff: E::Fr) -> Self { let newval = match (self.value, bit.get_value()) { (Some(mut curval), Some(bval)) => { if bval { @@ -447,25 +398,27 @@ impl Num { } Some(curval) - }, - _ => None + } + _ => None, }; Num { value: newval, - lc: self.lc + &bit.lc(one, coeff) + lc: self.lc + &bit.lc(one, coeff), } } } #[cfg(test)] mod test { - use rand::{SeedableRng, Rand, Rng, XorShiftRng}; - use bellman::{ConstraintSystem}; + use crate::ConstraintSystem; + use ff::{BitIterator, Field, PrimeField}; use pairing::bls12_381::{Bls12, Fr}; - use pairing::{Field, PrimeField, BitIterator}; - use ::circuit::test::*; + use rand_core::SeedableRng; + use rand_xorshift::XorShiftRng; + use super::{AllocatedNum, Boolean}; + use crate::gadgets::test::*; #[test] fn test_allocated_num() { @@ -494,8 +447,10 @@ mod test { fn test_num_multiplication() { let mut cs = TestConstraintSystem::::new(); - let n = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap(); - let n2 = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap(); + let n = + AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap(); + let n2 = + AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap(); let n3 = n.mul(&mut cs, &n2).unwrap(); assert!(cs.is_satisfied()); @@ -507,12 +462,15 @@ mod test { #[test] fn test_num_conditional_reversal() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); { let mut cs = TestConstraintSystem::::new(); - let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(rng.gen())).unwrap(); - let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(rng.gen())).unwrap(); + let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::random(&mut rng))).unwrap(); + let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::random(&mut rng))).unwrap(); let condition = Boolean::constant(false); let (c, d) = AllocatedNum::conditionally_reverse(&mut cs, &a, &b, &condition).unwrap(); @@ -525,8 +483,8 @@ mod test { { let mut cs = TestConstraintSystem::::new(); - let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(rng.gen())).unwrap(); - let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(rng.gen())).unwrap(); + let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::random(&mut rng))).unwrap(); + let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::random(&mut rng))).unwrap(); let condition = Boolean::constant(true); let (c, d) = AllocatedNum::conditionally_reverse(&mut cs, &a, &b, &condition).unwrap(); @@ -565,7 +523,7 @@ mod test { let mut cs = TestConstraintSystem::::new(); let n = AllocatedNum::alloc(&mut cs, || Ok(negone)).unwrap(); - n.into_bits_le_strict(&mut cs).unwrap(); + n.to_bits_le_strict(&mut cs).unwrap(); assert!(cs.is_satisfied()); @@ -573,28 +531,37 @@ mod test { cs.set("bit 254/boolean", Fr::one()); // this makes the conditional boolean constraint fail - assert_eq!(cs.which_is_unsatisfied().unwrap(), "bit 254/boolean constraint"); + assert_eq!( + cs.which_is_unsatisfied().unwrap(), + "bit 254/boolean constraint" + ); } #[test] fn test_into_bits() { - let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); for i in 0..200 { - let r = Fr::rand(&mut rng); + let r = Fr::random(&mut rng); let mut cs = TestConstraintSystem::::new(); let n = AllocatedNum::alloc(&mut cs, || Ok(r)).unwrap(); let bits = if i % 2 == 0 { - n.into_bits_le(&mut cs).unwrap() + n.to_bits_le(&mut cs).unwrap() } else { - n.into_bits_le_strict(&mut cs).unwrap() + n.to_bits_le_strict(&mut cs).unwrap() }; assert!(cs.is_satisfied()); - for (b, a) in BitIterator::new(r.into_repr()).skip(1).zip(bits.iter().rev()) { + for (b, a) in BitIterator::new(r.into_repr()) + .skip(1) + .zip(bits.iter().rev()) + { if let &Boolean::Is(ref a) = a { assert_eq!(b, a.get_value().unwrap()); } else { @@ -602,7 +569,7 @@ mod test { } } - cs.set("num", Fr::rand(&mut rng)); + cs.set("num", Fr::random(&mut rng)); assert!(!cs.is_satisfied()); cs.set("num", r); assert!(cs.is_satisfied()); diff --git a/sapling-crypto/src/circuit/sha256.rs b/src/gadgets/sha256.rs similarity index 61% rename from sapling-crypto/src/circuit/sha256.rs rename to src/gadgets/sha256.rs index 7b55fc8..0c8efea 100644 --- a/sapling-crypto/src/circuit/sha256.rs +++ b/src/gadgets/sha256.rs @@ -1,9 +1,15 @@ -use super::uint32::UInt32; -use super::multieq::MultiEq; -use super::boolean::Boolean; -use bellman::{ConstraintSystem, SynthesisError}; -use pairing::Engine; +//! Circuits for the [SHA-256] hash function and its internal compression +//! function. +//! +//! [SHA-256]: https://tools.ietf.org/html/rfc6234 +use super::boolean::Boolean; +use super::multieq::MultiEq; +use super::uint32::UInt32; +use crate::{ConstraintSystem, SynthesisError}; +use ff::ScalarEngine; + +#[allow(clippy::unreadable_literal)] const ROUND_CONSTANTS: [u32; 64] = [ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, @@ -12,37 +18,36 @@ const ROUND_CONSTANTS: [u32; 64] = [ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, ]; +#[allow(clippy::unreadable_literal)] const IV: [u32; 8] = [ - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, - 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, ]; pub fn sha256_block_no_padding( mut cs: CS, - input: &[Boolean] + input: &[Boolean], ) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem +where + E: ScalarEngine, + CS: ConstraintSystem, { assert_eq!(input.len(), 512); - Ok(sha256_compression_function( - &mut cs, - &input, - &get_sha256_iv() - )? - .into_iter() - .flat_map(|e| e.into_bits_be()) - .collect()) + Ok( + sha256_compression_function(&mut cs, &input, &get_sha256_iv())? + .into_iter() + .flat_map(|e| e.into_bits_be()) + .collect(), + ) } -pub fn sha256( - mut cs: CS, - input: &[Boolean] -) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem +pub fn sha256(mut cs: CS, input: &[Boolean]) -> Result, SynthesisError> +where + E: ScalarEngine, + CS: ConstraintSystem, { assert!(input.len() % 8 == 0); @@ -62,16 +67,10 @@ pub fn sha256( let mut cur = get_sha256_iv(); for (i, block) in padded.chunks(512).enumerate() { - cur = sha256_compression_function( - cs.namespace(|| format!("block {}", i)), - block, - &cur - )?; + cur = sha256_compression_function(cs.namespace(|| format!("block {}", i)), block, &cur)?; } - Ok(cur.into_iter() - .flat_map(|e| e.into_bits_be()) - .collect()) + Ok(cur.into_iter().flat_map(|e| e.into_bits_be()).collect()) } fn get_sha256_iv() -> Vec { @@ -81,16 +80,19 @@ fn get_sha256_iv() -> Vec { fn sha256_compression_function( cs: CS, input: &[Boolean], - current_hash_value: &[UInt32] + current_hash_value: &[UInt32], ) -> Result, SynthesisError> - where E: Engine, CS: ConstraintSystem +where + E: ScalarEngine, + CS: ConstraintSystem, { assert_eq!(input.len(), 512); assert_eq!(current_hash_value.len(), 8); - let mut w = input.chunks(32) - .map(|e| UInt32::from_bits_be(e)) - .collect::>(); + let mut w = input + .chunks(32) + .map(|e| UInt32::from_bits_be(e)) + .collect::>(); // We can save some constraints by combining some of // the constraints in different u32 additions @@ -100,30 +102,18 @@ fn sha256_compression_function( let cs = &mut cs.namespace(|| format!("w extension {}", i)); // s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3) - let mut s0 = w[i-15].rotr(7); - s0 = s0.xor( - cs.namespace(|| "first xor for s0"), - &w[i-15].rotr(18) - )?; - s0 = s0.xor( - cs.namespace(|| "second xor for s0"), - &w[i-15].shr(3) - )?; + let mut s0 = w[i - 15].rotr(7); + s0 = s0.xor(cs.namespace(|| "first xor for s0"), &w[i - 15].rotr(18))?; + s0 = s0.xor(cs.namespace(|| "second xor for s0"), &w[i - 15].shr(3))?; // s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10) - let mut s1 = w[i-2].rotr(17); - s1 = s1.xor( - cs.namespace(|| "first xor for s1"), - &w[i-2].rotr(19) - )?; - s1 = s1.xor( - cs.namespace(|| "second xor for s1"), - &w[i-2].shr(10) - )?; + let mut s1 = w[i - 2].rotr(17); + s1 = s1.xor(cs.namespace(|| "first xor for s1"), &w[i - 2].rotr(19))?; + s1 = s1.xor(cs.namespace(|| "second xor for s1"), &w[i - 2].shr(10))?; let tmp = UInt32::addmany( cs.namespace(|| "computation of w[i]"), - &[w[i-16].clone(), s0, w[i-7].clone(), s1] + &[w[i - 16].clone(), s0, w[i - 7].clone(), s1], )?; // w[i] := w[i-16] + s0 + w[i-7] + s1 @@ -134,29 +124,21 @@ fn sha256_compression_function( enum Maybe { Deferred(Vec), - Concrete(UInt32) + Concrete(UInt32), } impl Maybe { - fn compute( - self, - cs: M, - others: &[UInt32] - ) -> Result - where E: Engine, - CS: ConstraintSystem, - M: ConstraintSystem> + fn compute(self, cs: M, others: &[UInt32]) -> Result + where + E: ScalarEngine, + CS: ConstraintSystem, + M: ConstraintSystem>, { Ok(match self { - Maybe::Concrete(ref v) => { - return Ok(v.clone()) - }, + Maybe::Concrete(ref v) => return Ok(v.clone()), Maybe::Deferred(mut v) => { - v.extend(others.into_iter().cloned()); - UInt32::addmany( - cs, - &v - )? + v.extend(others.iter().cloned()); + UInt32::addmany(cs, &v)? } }) } @@ -177,22 +159,11 @@ fn sha256_compression_function( // S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25) let new_e = e.compute(cs.namespace(|| "deferred e computation"), &[])?; let mut s1 = new_e.rotr(6); - s1 = s1.xor( - cs.namespace(|| "first xor for s1"), - &new_e.rotr(11) - )?; - s1 = s1.xor( - cs.namespace(|| "second xor for s1"), - &new_e.rotr(25) - )?; + s1 = s1.xor(cs.namespace(|| "first xor for s1"), &new_e.rotr(11))?; + s1 = s1.xor(cs.namespace(|| "second xor for s1"), &new_e.rotr(25))?; // ch := (e and f) xor ((not e) and g) - let ch = UInt32::sha256_ch( - cs.namespace(|| "ch"), - &new_e, - &f, - &g - )?; + let ch = UInt32::sha256_ch(cs.namespace(|| "ch"), &new_e, &f, &g)?; // temp1 := h + S1 + ch + k[i] + w[i] let temp1 = vec![ @@ -200,28 +171,17 @@ fn sha256_compression_function( s1, ch, UInt32::constant(ROUND_CONSTANTS[i]), - w[i].clone() + w[i].clone(), ]; // S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22) let new_a = a.compute(cs.namespace(|| "deferred a computation"), &[])?; let mut s0 = new_a.rotr(2); - s0 = s0.xor( - cs.namespace(|| "first xor for s0"), - &new_a.rotr(13) - )?; - s0 = s0.xor( - cs.namespace(|| "second xor for s0"), - &new_a.rotr(22) - )?; + s0 = s0.xor(cs.namespace(|| "first xor for s0"), &new_a.rotr(13))?; + s0 = s0.xor(cs.namespace(|| "second xor for s0"), &new_a.rotr(22))?; // maj := (a and b) xor (a and c) xor (b and c) - let maj = UInt32::sha256_maj( - cs.namespace(|| "maj"), - &new_a, - &b, - &c - )?; + let maj = UInt32::sha256_maj(cs.namespace(|| "maj"), &new_a, &b, &c)?; // temp2 := S0 + maj let temp2 = vec![s0, maj]; @@ -244,7 +204,13 @@ fn sha256_compression_function( d = c; c = b; b = new_a; - a = Maybe::Deferred(temp1.iter().cloned().chain(temp2.iter().cloned()).collect::>()); + a = Maybe::Deferred( + temp1 + .iter() + .cloned() + .chain(temp2.iter().cloned()) + .collect::>(), + ); } /* @@ -261,42 +227,42 @@ fn sha256_compression_function( let h0 = a.compute( cs.namespace(|| "deferred h0 computation"), - &[current_hash_value[0].clone()] + &[current_hash_value[0].clone()], )?; let h1 = UInt32::addmany( cs.namespace(|| "new h1"), - &[current_hash_value[1].clone(), b] + &[current_hash_value[1].clone(), b], )?; let h2 = UInt32::addmany( cs.namespace(|| "new h2"), - &[current_hash_value[2].clone(), c] + &[current_hash_value[2].clone(), c], )?; let h3 = UInt32::addmany( cs.namespace(|| "new h3"), - &[current_hash_value[3].clone(), d] + &[current_hash_value[3].clone(), d], )?; let h4 = e.compute( cs.namespace(|| "deferred h4 computation"), - &[current_hash_value[4].clone()] + &[current_hash_value[4].clone()], )?; let h5 = UInt32::addmany( cs.namespace(|| "new h5"), - &[current_hash_value[5].clone(), f] + &[current_hash_value[5].clone(), f], )?; let h6 = UInt32::addmany( cs.namespace(|| "new h6"), - &[current_hash_value[6].clone(), g] + &[current_hash_value[6].clone(), g], )?; let h7 = UInt32::addmany( cs.namespace(|| "new h7"), - &[current_hash_value[7].clone(), h] + &[current_hash_value[7].clone(), h], )?; Ok(vec![h0, h1, h2, h3, h4, h5, h6, h7]) @@ -305,10 +271,11 @@ fn sha256_compression_function( #[cfg(test)] mod test { use super::*; - use circuit::boolean::AllocatedBit; + use crate::gadgets::boolean::AllocatedBit; + use crate::gadgets::test::TestConstraintSystem; use pairing::bls12_381::Bls12; - use circuit::test::TestConstraintSystem; - use rand::{XorShiftRng, SeedableRng, Rng}; + use rand_core::{RngCore, SeedableRng}; + use rand_xorshift::XorShiftRng; #[test] fn test_blank_hash() { @@ -317,11 +284,7 @@ mod test { let mut cs = TestConstraintSystem::::new(); let mut input_bits: Vec<_> = (0..512).map(|_| Boolean::Constant(false)).collect(); input_bits[0] = Boolean::Constant(true); - let out = sha256_compression_function( - &mut cs, - &input_bits, - &iv - ).unwrap(); + let out = sha256_compression_function(&mut cs, &input_bits, &iv).unwrap(); let out_bits: Vec<_> = out.into_iter().flat_map(|e| e.into_bits_be()).collect(); assert!(cs.is_satisfied()); @@ -330,7 +293,7 @@ mod test { let expected = hex!("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); let mut out = out_bits.into_iter(); - for b in expected.into_iter() { + for b in expected.iter() { for i in (0..8).rev() { let c = out.next().unwrap().get_value().unwrap(); @@ -341,25 +304,27 @@ mod test { #[test] fn test_full_block() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); let iv = get_sha256_iv(); let mut cs = TestConstraintSystem::::new(); - let input_bits: Vec<_> = (0..512).map(|i| { - Boolean::from( - AllocatedBit::alloc( - cs.namespace(|| format!("input bit {}", i)), - Some(rng.gen()) - ).unwrap() - ) - }).collect(); + let input_bits: Vec<_> = (0..512) + .map(|i| { + Boolean::from( + AllocatedBit::alloc( + cs.namespace(|| format!("input bit {}", i)), + Some(rng.next_u32() % 2 != 0), + ) + .unwrap(), + ) + }) + .collect(); - sha256_compression_function( - cs.namespace(|| "sha256"), - &input_bits, - &iv - ).unwrap(); + sha256_compression_function(cs.namespace(|| "sha256"), &input_bits, &iv).unwrap(); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints() - 512, 25840); @@ -367,18 +332,18 @@ mod test { #[test] fn test_against_vectors() { - use crypto::sha2::Sha256; - use crypto::digest::Digest; + use sha2::{Digest, Sha256}; - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); - for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) - { + for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) { let mut h = Sha256::new(); - let data: Vec = (0..input_len).map(|_| rng.gen()).collect(); + let data: Vec = (0..input_len).map(|_| rng.next_u32() as u8).collect(); h.input(&data); - let mut hash_result = [0u8; 32]; - h.result(&mut hash_result[..]); + let hash_result = h.result(); let mut cs = TestConstraintSystem::::new(); let mut input_bits = vec![]; @@ -387,7 +352,11 @@ mod test { for bit_i in (0..8).rev() { let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i)); - input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into()); + input_bits.push( + AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)) + .unwrap() + .into(), + ); } } @@ -395,17 +364,19 @@ mod test { assert!(cs.is_satisfied()); - let mut s = hash_result.as_ref().iter() - .flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8)); + let mut s = hash_result + .as_ref() + .iter() + .flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8)); for b in r { match b { Boolean::Is(b) => { assert!(s.next().unwrap() == b.get_value().unwrap()); - }, + } Boolean::Not(b) => { assert!(s.next().unwrap() != b.get_value().unwrap()); - }, + } Boolean::Constant(b) => { assert!(input_len == 0); assert!(s.next().unwrap() == b); diff --git a/sapling-crypto/src/circuit/test/mod.rs b/src/gadgets/test/mod.rs similarity index 71% rename from sapling-crypto/src/circuit/test/mod.rs rename to src/gadgets/test/mod.rs index 12fe0ca..47392f1 100644 --- a/sapling-crypto/src/circuit/test/mod.rs +++ b/src/gadgets/test/mod.rs @@ -1,17 +1,8 @@ -use pairing::{ - Engine, - Field, - PrimeField, - PrimeFieldRepr -}; +//! Helpers for testing circuit implementations. -use bellman::{ - LinearCombination, - SynthesisError, - ConstraintSystem, - Variable, - Index -}; +use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; + +use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; use std::collections::HashMap; use std::fmt::Write; @@ -20,27 +11,27 @@ use byteorder::{BigEndian, ByteOrder}; use std::cmp::Ordering; use std::collections::BTreeMap; -use blake2_rfc::blake2s::Blake2s; +use blake2s_simd::{Params as Blake2sParams, State as Blake2sState}; #[derive(Debug)] enum NamedObject { Constraint(usize), Var(Variable), - Namespace + Namespace, } /// Constraint system for testing purposes. -pub struct TestConstraintSystem { +pub struct TestConstraintSystem { named_objects: HashMap, current_namespace: Vec, constraints: Vec<( LinearCombination, LinearCombination, LinearCombination, - String + String, )>, inputs: Vec<(E::Fr, String)>, - aux: Vec<(E::Fr, String)> + aux: Vec<(E::Fr, String)>, } #[derive(Clone, Copy)] @@ -52,7 +43,7 @@ impl PartialEq for OrderedVariable { match (self.0.get_unchecked(), other.0.get_unchecked()) { (Index::Input(ref a), Index::Input(ref b)) => a == b, (Index::Aux(ref a), Index::Aux(ref b)) => a == b, - _ => false + _ => false, } } } @@ -67,20 +58,17 @@ impl Ord for OrderedVariable { (Index::Input(ref a), Index::Input(ref b)) => a.cmp(b), (Index::Aux(ref a), Index::Aux(ref b)) => a.cmp(b), (Index::Input(_), Index::Aux(_)) => Ordering::Less, - (Index::Aux(_), Index::Input(_)) => Ordering::Greater + (Index::Aux(_), Index::Input(_)) => Ordering::Greater, } } } -fn proc_lc( - terms: &[(Variable, E::Fr)], -) -> BTreeMap -{ +fn proc_lc(terms: &[(Variable, E::Fr)]) -> BTreeMap { let mut map = BTreeMap::new(); for &(var, coeff) in terms { map.entry(OrderedVariable(var)) - .or_insert(E::Fr::zero()) - .add_assign(&coeff); + .or_insert_with(E::Fr::zero) + .add_assign(&coeff); } // Remove terms that have a zero coefficient to normalize @@ -98,11 +86,7 @@ fn proc_lc( map } -fn hash_lc( - terms: &[(Variable, E::Fr)], - h: &mut Blake2s -) -{ +fn hash_lc(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) { let map = proc_lc::(terms); let mut buf = [0u8; 9 + 32]; @@ -114,31 +98,30 @@ fn hash_lc( Index::Input(i) => { buf[0] = b'I'; BigEndian::write_u64(&mut buf[1..9], i as u64); - }, + } Index::Aux(i) => { buf[0] = b'A'; BigEndian::write_u64(&mut buf[1..9], i as u64); } } - + coeff.into_repr().write_be(&mut buf[9..]).unwrap(); h.update(&buf); } } -fn eval_lc( +fn eval_lc( terms: &[(Variable, E::Fr)], inputs: &[(E::Fr, String)], - aux: &[(E::Fr, String)] -) -> E::Fr -{ + aux: &[(E::Fr, String)], +) -> E::Fr { let mut acc = E::Fr::zero(); for &(var, ref coeff) in terms { let mut tmp = match var.get_unchecked() { Index::Input(index) => inputs[index].0, - Index::Aux(index) => aux[index].0 + Index::Aux(index) => aux[index].0, }; tmp.mul_assign(&coeff); @@ -148,17 +131,20 @@ fn eval_lc( acc } -impl TestConstraintSystem { +impl TestConstraintSystem { pub fn new() -> TestConstraintSystem { let mut map = HashMap::new(); - map.insert("ONE".into(), NamedObject::Var(TestConstraintSystem::::one())); + map.insert( + "ONE".into(), + NamedObject::Var(TestConstraintSystem::::one()), + ); TestConstraintSystem { named_objects: map, current_namespace: vec![], constraints: vec![], inputs: vec![(E::Fr::one(), "ONE".into())], - aux: vec![] + aux: vec![], } } @@ -171,9 +157,9 @@ impl TestConstraintSystem { tmp }; - let powers_of_two = (0..E::Fr::NUM_BITS).map(|i| { - E::Fr::from_str("2").unwrap().pow(&[i as u64]) - }).collect::>(); + let powers_of_two = (0..E::Fr::NUM_BITS) + .map(|i| E::Fr::from_str("2").unwrap().pow(&[u64::from(i)])) + .collect::>(); let pp = |s: &mut String, lc: &LinearCombination| { write!(s, "(").unwrap(); @@ -200,7 +186,7 @@ impl TestConstraintSystem { match var.0.get_unchecked() { Index::Input(i) => { write!(s, "`{}`", &self.inputs[i].1).unwrap(); - }, + } Index::Aux(i) => { write!(s, "`{}`", &self.aux[i].1).unwrap(); } @@ -230,7 +216,7 @@ impl TestConstraintSystem { } pub fn hash(&self) -> String { - let mut h = Blake2s::new(32); + let mut h = Blake2sParams::new().hash_length(32).to_state(); { let mut buf = [0u8; 24]; @@ -263,57 +249,52 @@ impl TestConstraintSystem { a.mul_assign(&b); if a != c { - return Some(&*path) + return Some(&*path); } } None } - pub fn is_satisfied(&self) -> bool - { + pub fn is_satisfied(&self) -> bool { self.which_is_unsatisfied().is_none() } - pub fn num_constraints(&self) -> usize - { + pub fn num_constraints(&self) -> usize { self.constraints.len() } - pub fn set(&mut self, path: &str, to: E::Fr) - { + pub fn set(&mut self, path: &str, to: E::Fr) { match self.named_objects.get(path) { - Some(&NamedObject::Var(ref v)) => { - match v.get_unchecked() { - Index::Input(index) => self.inputs[index].0 = to, - Index::Aux(index) => self.aux[index].0 = to - } - } - Some(e) => panic!("tried to set path `{}` to value, but `{:?}` already exists there.", path, e), - _ => panic!("no variable exists at path: {}", path) + Some(&NamedObject::Var(ref v)) => match v.get_unchecked() { + Index::Input(index) => self.inputs[index].0 = to, + Index::Aux(index) => self.aux[index].0 = to, + }, + Some(e) => panic!( + "tried to set path `{}` to value, but `{:?}` already exists there.", + path, e + ), + _ => panic!("no variable exists at path: {}", path), } } - pub fn verify(&self, expected: &[E::Fr]) -> bool - { + pub fn verify(&self, expected: &[E::Fr]) -> bool { assert_eq!(expected.len() + 1, self.inputs.len()); - for (a, b) in self.inputs.iter().skip(1).zip(expected.iter()) - { + for (a, b) in self.inputs.iter().skip(1).zip(expected.iter()) { if &a.0 != b { - return false + return false; } } - return true; + true } pub fn num_inputs(&self) -> usize { self.inputs.len() } - pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr - { + pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr { let (assignment, name) = self.inputs[index].clone(); assert_eq!(path, name); @@ -321,17 +302,17 @@ impl TestConstraintSystem { assignment } - pub fn get(&mut self, path: &str) -> E::Fr - { + pub fn get(&mut self, path: &str) -> E::Fr { match self.named_objects.get(path) { - Some(&NamedObject::Var(ref v)) => { - match v.get_unchecked() { - Index::Input(index) => self.inputs[index].0, - Index::Aux(index) => self.aux[index].0 - } - } - Some(e) => panic!("tried to get value of path `{}`, but `{:?}` exists there (not a variable)", path, e), - _ => panic!("no variable exists at path: {}", path) + Some(&NamedObject::Var(ref v)) => match v.get_unchecked() { + Index::Input(index) => self.inputs[index].0, + Index::Aux(index) => self.aux[index].0, + }, + Some(e) => panic!( + "tried to get value of path `{}`, but `{:?}` exists there (not a variable)", + path, e + ), + _ => panic!("no variable exists at path: {}", path), } } @@ -352,8 +333,7 @@ fn compute_path(ns: &[String], this: String) -> String { let mut name = String::new(); let mut needs_separation = false; - for ns in ns.iter().chain(Some(&this).into_iter()) - { + for ns in ns.iter().chain(Some(&this).into_iter()) { if needs_separation { name += "/"; } @@ -365,15 +345,14 @@ fn compute_path(ns: &[String], this: String) -> String { name } -impl ConstraintSystem for TestConstraintSystem { +impl ConstraintSystem for TestConstraintSystem { type Root = Self; - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { let index = self.aux.len(); let path = compute_path(&self.current_namespace, annotation().into()); @@ -384,12 +363,11 @@ impl ConstraintSystem for TestConstraintSystem { Ok(var) } - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { let index = self.inputs.len(); let path = compute_path(&self.current_namespace, annotation().into()); @@ -400,17 +378,13 @@ impl ConstraintSystem for TestConstraintSystem { Ok(var) } - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, annotation: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { let path = compute_path(&self.current_namespace, annotation().into()); let index = self.constraints.len(); @@ -424,7 +398,9 @@ impl ConstraintSystem for TestConstraintSystem { } fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { let name = name_fn().into(); let path = compute_path(&self.current_namespace, name.clone()); @@ -432,47 +408,43 @@ impl ConstraintSystem for TestConstraintSystem { self.current_namespace.push(name); } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { assert!(self.current_namespace.pop().is_some()); } - fn get_root(&mut self) -> &mut Self::Root - { + fn get_root(&mut self) -> &mut Self::Root { self } } #[test] fn test_cs() { + use ff::PrimeField; use pairing::bls12_381::{Bls12, Fr}; - use pairing::PrimeField; let mut cs = TestConstraintSystem::::new(); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 0); - let a = cs.namespace(|| "a").alloc(|| "var", || Ok(Fr::from_str("10").unwrap())).unwrap(); - let b = cs.namespace(|| "b").alloc(|| "var", || Ok(Fr::from_str("4").unwrap())).unwrap(); - let c = cs.alloc(|| "product", || Ok(Fr::from_str("40").unwrap())).unwrap(); + let a = cs + .namespace(|| "a") + .alloc(|| "var", || Ok(Fr::from_str("10").unwrap())) + .unwrap(); + let b = cs + .namespace(|| "b") + .alloc(|| "var", || Ok(Fr::from_str("4").unwrap())) + .unwrap(); + let c = cs + .alloc(|| "product", || Ok(Fr::from_str("40").unwrap())) + .unwrap(); - cs.enforce( - || "mult", - |lc| lc + a, - |lc| lc + b, - |lc| lc + c - ); + cs.enforce(|| "mult", |lc| lc + a, |lc| lc + b, |lc| lc + c); assert!(cs.is_satisfied()); assert_eq!(cs.num_constraints(), 1); cs.set("a/var", Fr::from_str("4").unwrap()); let one = TestConstraintSystem::::one(); - cs.enforce( - || "eq", - |lc| lc + a, - |lc| lc + one, - |lc| lc + b - ); + cs.enforce(|| "eq", |lc| lc + a, |lc| lc + one, |lc| lc + b); assert!(!cs.is_satisfied()); assert!(cs.which_is_unsatisfied() == Some("mult")); diff --git a/sapling-crypto/src/circuit/uint32.rs b/src/gadgets/uint32.rs similarity index 57% rename from sapling-crypto/src/circuit/uint32.rs rename to src/gadgets/uint32.rs index fb0bfa9..a10be6c 100644 --- a/sapling-crypto/src/circuit/uint32.rs +++ b/src/gadgets/uint32.rs @@ -1,19 +1,11 @@ -use pairing::{ - Engine, - Field, - PrimeField -}; +//! Circuit representation of a [`u32`], with helpers for the [`sha256`] +//! gadgets. -use bellman::{ - SynthesisError, - ConstraintSystem, - LinearCombination -}; +use ff::{Field, PrimeField, ScalarEngine}; -use super::boolean::{ - Boolean, - AllocatedBit -}; +use crate::{ConstraintSystem, LinearCombination, SynthesisError}; + +use super::boolean::{AllocatedBit, Boolean}; use super::multieq::MultiEq; @@ -23,13 +15,12 @@ use super::multieq::MultiEq; pub struct UInt32 { // Least significant bit first bits: Vec, - value: Option + value: Option, } impl UInt32 { /// Construct a constant `UInt32` from a `u32` - pub fn constant(value: u32) -> Self - { + pub fn constant(value: u32) -> Self { let mut bits = Vec::with_capacity(32); let mut tmp = value; @@ -44,18 +35,16 @@ impl UInt32 { } UInt32 { - bits: bits, - value: Some(value) + bits, + value: Some(value), } } /// Allocate a `UInt32` in the constraint system - pub fn alloc( - mut cs: CS, - value: Option - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn alloc(mut cs: CS, value: Option) -> Result + where + E: ScalarEngine, + CS: ConstraintSystem, { let values = match value { Some(mut val) => { @@ -67,28 +56,28 @@ impl UInt32 { } v - }, - None => vec![None; 32] + } + None => vec![None; 32], }; - let bits = values.into_iter() - .enumerate() - .map(|(i, v)| { - Ok(Boolean::from(AllocatedBit::alloc( - cs.namespace(|| format!("allocated bit {}", i)), - v - )?)) - }) - .collect::, SynthesisError>>()?; + let bits = values + .into_iter() + .enumerate() + .map(|(i, v)| { + Ok(Boolean::from(AllocatedBit::alloc( + cs.namespace(|| format!("allocated bit {}", i)), + v, + )?)) + }) + .collect::, SynthesisError>>()?; - Ok(UInt32 { - bits: bits, - value: value - }) + Ok(UInt32 { bits, value }) } - pub fn into_bits_be(&self) -> Vec { - self.bits.iter().rev().cloned().collect() + pub fn into_bits_be(self) -> Vec { + let mut ret = self.bits; + ret.reverse(); + ret } pub fn from_bits_be(bits: &[Boolean]) -> Self { @@ -99,28 +88,30 @@ impl UInt32 { value.as_mut().map(|v| *v <<= 1); match b.get_value() { - Some(true) => { value.as_mut().map(|v| *v |= 1); }, - Some(false) => {}, - None => { value = None; } + Some(true) => { + value.as_mut().map(|v| *v |= 1); + } + Some(false) => {} + None => { + value = None; + } } } UInt32 { - value: value, - bits: bits.iter().rev().cloned().collect() + value, + bits: bits.iter().rev().cloned().collect(), } } - /// Turns this `UInt32` into its little-endian byte order representation. - pub fn into_bits(&self) -> Vec { - self.bits.clone() + pub fn into_bits(self) -> Vec { + self.bits } /// Converts a little-endian byte order representation of bits into a /// `UInt32`. - pub fn from_bits(bits: &[Boolean]) -> Self - { + pub fn from_bits(bits: &[Boolean]) -> Self { assert_eq!(bits.len(), 32); let new_bits = bits.to_vec(); @@ -129,48 +120,50 @@ impl UInt32 { for b in new_bits.iter().rev() { value.as_mut().map(|v| *v <<= 1); - match b { - &Boolean::Constant(b) => { + match *b { + Boolean::Constant(b) => { if b { value.as_mut().map(|v| *v |= 1); } - }, - &Boolean::Is(ref b) => { - match b.get_value() { - Some(true) => { value.as_mut().map(|v| *v |= 1); }, - Some(false) => {}, - None => { value = None } - } - }, - &Boolean::Not(ref b) => { - match b.get_value() { - Some(false) => { value.as_mut().map(|v| *v |= 1); }, - Some(true) => {}, - None => { value = None } - } } + Boolean::Is(ref b) => match b.get_value() { + Some(true) => { + value.as_mut().map(|v| *v |= 1); + } + Some(false) => {} + None => value = None, + }, + Boolean::Not(ref b) => match b.get_value() { + Some(false) => { + value.as_mut().map(|v| *v |= 1); + } + Some(true) => {} + None => value = None, + }, } } UInt32 { - value: value, - bits: new_bits + value, + bits: new_bits, } } pub fn rotr(&self, by: usize) -> Self { let by = by % 32; - let new_bits = self.bits.iter() - .skip(by) - .chain(self.bits.iter()) - .take(32) - .cloned() - .collect(); + let new_bits = self + .bits + .iter() + .skip(by) + .chain(self.bits.iter()) + .take(32) + .cloned() + .collect(); UInt32 { bits: new_bits, - value: self.value.map(|v| v.rotate_right(by as u32)) + value: self.value.map(|v| v.rotate_right(by as u32)), } } @@ -179,17 +172,18 @@ impl UInt32 { let fill = Boolean::constant(false); - let new_bits = self.bits - .iter() // The bits are least significant first - .skip(by) // Skip the bits that will be lost during the shift - .chain(Some(&fill).into_iter().cycle()) // Rest will be zeros - .take(32) // Only 32 bits needed! - .cloned() - .collect(); + let new_bits = self + .bits + .iter() // The bits are least significant first + .skip(by) // Skip the bits that will be lost during the shift + .chain(Some(&fill).into_iter().cycle()) // Rest will be zeros + .take(32) // Only 32 bits needed! + .cloned() + .collect(); UInt32 { bits: new_bits, - value: self.value.map(|v| v >> by as u32) + value: self.value.map(|v| v >> by as u32), } } @@ -199,121 +193,99 @@ impl UInt32 { b: &Self, c: &Self, tri_fn: F, - circuit_fn: U + circuit_fn: U, ) -> Result - where E: Engine, - CS: ConstraintSystem, - F: Fn(u32, u32, u32) -> u32, - U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result + where + E: ScalarEngine, + CS: ConstraintSystem, + F: Fn(u32, u32, u32) -> u32, + U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result, { let new_value = match (a.value, b.value, c.value) { - (Some(a), Some(b), Some(c)) => { - Some(tri_fn(a, b, c)) - }, - _ => None + (Some(a), Some(b), Some(c)) => Some(tri_fn(a, b, c)), + _ => None, }; - let bits = a.bits.iter() - .zip(b.bits.iter()) - .zip(c.bits.iter()) - .enumerate() - .map(|(i, ((a, b), c))| circuit_fn(&mut cs, i, a, b, c)) - .collect::>()?; + let bits = a + .bits + .iter() + .zip(b.bits.iter()) + .zip(c.bits.iter()) + .enumerate() + .map(|(i, ((a, b), c))| circuit_fn(&mut cs, i, a, b, c)) + .collect::>()?; Ok(UInt32 { - bits: bits, - value: new_value + bits, + value: new_value, }) } /// Compute the `maj` value (a and b) xor (a and c) xor (b and c) /// during SHA256. - pub fn sha256_maj( - cs: CS, - a: &Self, - b: &Self, - c: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn sha256_maj(cs: CS, a: &Self, b: &Self, c: &Self) -> Result + where + E: ScalarEngine, + CS: ConstraintSystem, { - Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ (a & c) ^ (b & c), - |cs, i, a, b, c| { - Boolean::sha256_maj( - cs.namespace(|| format!("maj {}", i)), - a, - b, - c - ) - } + Self::triop( + cs, + a, + b, + c, + |a, b, c| (a & b) ^ (a & c) ^ (b & c), + |cs, i, a, b, c| Boolean::sha256_maj(cs.namespace(|| format!("maj {}", i)), a, b, c), ) } /// Compute the `ch` value `(a and b) xor ((not a) and c)` /// during SHA256. - pub fn sha256_ch( - cs: CS, - a: &Self, - b: &Self, - c: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn sha256_ch(cs: CS, a: &Self, b: &Self, c: &Self) -> Result + where + E: ScalarEngine, + CS: ConstraintSystem, { - Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ ((!a) & c), - |cs, i, a, b, c| { - Boolean::sha256_ch( - cs.namespace(|| format!("ch {}", i)), - a, - b, - c - ) - } + Self::triop( + cs, + a, + b, + c, + |a, b, c| (a & b) ^ ((!a) & c), + |cs, i, a, b, c| Boolean::sha256_ch(cs.namespace(|| format!("ch {}", i)), a, b, c), ) } /// XOR this `UInt32` with another `UInt32` - pub fn xor( - &self, - mut cs: CS, - other: &Self - ) -> Result - where E: Engine, - CS: ConstraintSystem + pub fn xor(&self, mut cs: CS, other: &Self) -> Result + where + E: ScalarEngine, + CS: ConstraintSystem, { let new_value = match (self.value, other.value) { - (Some(a), Some(b)) => { - Some(a ^ b) - }, - _ => None + (Some(a), Some(b)) => Some(a ^ b), + _ => None, }; - let bits = self.bits.iter() - .zip(other.bits.iter()) - .enumerate() - .map(|(i, (a, b))| { - Boolean::xor( - cs.namespace(|| format!("xor of bit {}", i)), - a, - b - ) - }) - .collect::>()?; + let bits = self + .bits + .iter() + .zip(other.bits.iter()) + .enumerate() + .map(|(i, (a, b))| Boolean::xor(cs.namespace(|| format!("xor of bit {}", i)), a, b)) + .collect::>()?; Ok(UInt32 { - bits: bits, - value: new_value + bits, + value: new_value, }) } /// Perform modular addition of several `UInt32` objects. - pub fn addmany( - mut cs: M, - operands: &[Self] - ) -> Result - where E: Engine, - CS: ConstraintSystem, - M: ConstraintSystem> + pub fn addmany(mut cs: M, operands: &[Self]) -> Result + where + E: ScalarEngine, + CS: ConstraintSystem, + M: ConstraintSystem>, { // Make some arbitrary bounds for ourselves to avoid overflows // in the scalar field @@ -323,7 +295,7 @@ impl UInt32 { // Compute the maximum value of the sum so we allocate enough bits for // the result - let mut max_value = (operands.len() as u64) * (u32::max_value() as u64); + let mut max_value = (operands.len() as u64) * (u64::from(u32::max_value())); // Keep track of the resulting value let mut result_value = Some(0u64); @@ -339,8 +311,8 @@ impl UInt32 { // Accumulate the value match op.value { Some(val) => { - result_value.as_mut().map(|v| *v += val as u64); - }, + result_value.as_mut().map(|v| *v += u64::from(val)); + } None => { // If any of our operands have unknown value, we won't // know the value of the result @@ -384,7 +356,7 @@ impl UInt32 { // Allocate the bit let b = AllocatedBit::alloc( cs.namespace(|| format!("result bit {}", i)), - result_value.map(|v| (v >> i) & 1 == 1) + result_value.map(|v| (v >> i) & 1 == 1), )?; // Add this bit to the result combination @@ -405,48 +377,53 @@ impl UInt32 { Ok(UInt32 { bits: result_bits, - value: modular_value + value: modular_value, }) } } #[cfg(test)] mod test { - use rand::{XorShiftRng, SeedableRng, Rng}; - use ::circuit::boolean::{Boolean}; - use super::{UInt32}; - use pairing::bls12_381::{Bls12}; - use pairing::{Field}; - use ::circuit::test::*; - use bellman::{ConstraintSystem}; - use circuit::multieq::MultiEq; + use super::UInt32; + use crate::gadgets::boolean::Boolean; + use crate::gadgets::multieq::MultiEq; + use crate::gadgets::test::*; + use crate::ConstraintSystem; + use ff::Field; + use pairing::bls12_381::Bls12; + use rand_core::{RngCore, SeedableRng}; + use rand_xorshift::XorShiftRng; #[test] fn test_uint32_from_bits_be() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); for _ in 0..1000 { - let mut v = (0..32).map(|_| Boolean::constant(rng.gen())).collect::>(); + let v = (0..32) + .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) + .collect::>(); let b = UInt32::from_bits_be(&v); for (i, bit) in b.bits.iter().enumerate() { - match bit { - &Boolean::Constant(bit) => { + match *bit { + Boolean::Constant(bit) => { assert!(bit == ((b.value.unwrap() >> i) & 1 == 1)); - }, - _ => unreachable!() + } + _ => unreachable!(), } } let expected_to_be_same = b.into_bits_be(); - for x in v.iter().zip(expected_to_be_same.iter()) - { + for x in v.iter().zip(expected_to_be_same.iter()) { match x { - (&Boolean::Constant(true), &Boolean::Constant(true)) => {}, - (&Boolean::Constant(false), &Boolean::Constant(false)) => {}, - _ => unreachable!() + (&Boolean::Constant(true), &Boolean::Constant(true)) => {} + (&Boolean::Constant(false), &Boolean::Constant(false)) => {} + _ => unreachable!(), } } } @@ -454,30 +431,34 @@ mod test { #[test] fn test_uint32_from_bits() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); for _ in 0..1000 { - let mut v = (0..32).map(|_| Boolean::constant(rng.gen())).collect::>(); + let v = (0..32) + .map(|_| Boolean::constant(rng.next_u32() % 2 != 0)) + .collect::>(); let b = UInt32::from_bits(&v); for (i, bit) in b.bits.iter().enumerate() { - match bit { - &Boolean::Constant(bit) => { + match *bit { + Boolean::Constant(bit) => { assert!(bit == ((b.value.unwrap() >> i) & 1 == 1)); - }, - _ => unreachable!() + } + _ => unreachable!(), } } let expected_to_be_same = b.into_bits(); - for x in v.iter().zip(expected_to_be_same.iter()) - { + for x in v.iter().zip(expected_to_be_same.iter()) { match x { - (&Boolean::Constant(true), &Boolean::Constant(true)) => {}, - (&Boolean::Constant(false), &Boolean::Constant(false)) => {}, - _ => unreachable!() + (&Boolean::Constant(true), &Boolean::Constant(true)) => {} + (&Boolean::Constant(false), &Boolean::Constant(false)) => {} + _ => unreachable!(), } } } @@ -485,14 +466,17 @@ mod test { #[test] fn test_uint32_xor() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); - let a: u32 = rng.gen(); - let b: u32 = rng.gen(); - let c: u32 = rng.gen(); + let a = rng.next_u32(); + let b = rng.next_u32(); + let c = rng.next_u32(); let mut expected = a ^ b ^ c; @@ -508,14 +492,14 @@ mod test { assert!(r.value == Some(expected)); for b in r.bits.iter() { - match b { - &Boolean::Is(ref b) => { + match *b { + Boolean::Is(ref b) => { assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, - &Boolean::Not(ref b) => { + } + Boolean::Not(ref b) => { assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, - &Boolean::Constant(b) => { + } + Boolean::Constant(b) => { assert!(b == (expected & 1 == 1)); } } @@ -527,14 +511,17 @@ mod test { #[test] fn test_uint32_addmany_constants() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); - let a: u32 = rng.gen(); - let b: u32 = rng.gen(); - let c: u32 = rng.gen(); + let a = rng.next_u32(); + let b = rng.next_u32(); + let c = rng.next_u32(); let a_bit = UInt32::constant(a); let b_bit = UInt32::constant(b); @@ -544,17 +531,18 @@ mod test { let r = { let mut cs = MultiEq::new(&mut cs); - let r = UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap(); + let r = + UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap(); r }; assert!(r.value == Some(expected)); for b in r.bits.iter() { - match b { - &Boolean::Is(_) => panic!(), - &Boolean::Not(_) => panic!(), - &Boolean::Constant(b) => { + match *b { + Boolean::Is(_) => panic!(), + Boolean::Not(_) => panic!(), + Boolean::Constant(b) => { assert!(b == (expected & 1 == 1)); } } @@ -566,15 +554,18 @@ mod test { #[test] fn test_uint32_addmany() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); - let a: u32 = rng.gen(); - let b: u32 = rng.gen(); - let c: u32 = rng.gen(); - let d: u32 = rng.gen(); + let a = rng.next_u32(); + let b = rng.next_u32(); + let c = rng.next_u32(); + let d = rng.next_u32(); let mut expected = (a ^ b).wrapping_add(c).wrapping_add(d); @@ -586,8 +577,7 @@ mod test { let r = a_bit.xor(cs.namespace(|| "xor"), &b_bit).unwrap(); let r = { let mut cs = MultiEq::new(&mut cs); - let r = UInt32::addmany(cs.namespace(|| "addition"), &[r, c_bit, d_bit]).unwrap(); - r + UInt32::addmany(cs.namespace(|| "addition"), &[r, c_bit, d_bit]).unwrap() }; assert!(cs.is_satisfied()); @@ -595,16 +585,14 @@ mod test { assert!(r.value == Some(expected)); for b in r.bits.iter() { - match b { - &Boolean::Is(ref b) => { + match *b { + Boolean::Is(ref b) => { assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, - &Boolean::Not(ref b) => { - assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, - &Boolean::Constant(_) => { - unreachable!() } + Boolean::Not(ref b) => { + assert!(!b.get_value().unwrap() == (expected & 1 == 1)); + } + Boolean::Constant(_) => unreachable!(), } expected >>= 1; @@ -623,9 +611,12 @@ mod test { #[test] fn test_uint32_rotr() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); - let mut num = rng.gen(); + let mut num = rng.next_u32(); let a = UInt32::constant(num); @@ -637,11 +628,11 @@ mod test { let mut tmp = num; for b in &b.bits { - match b { - &Boolean::Constant(b) => { + match *b { + Boolean::Constant(b) => { assert_eq!(b, tmp & 1 == 1); - }, - _ => unreachable!() + } + _ => unreachable!(), } tmp >>= 1; @@ -653,15 +644,18 @@ mod test { #[test] fn test_uint32_shr() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); for _ in 0..50 { for i in 0..60 { - let num = rng.gen(); + let num = rng.next_u32(); let a = UInt32::constant(num).shr(i); - let b = UInt32::constant(num >> i); + let b = UInt32::constant(num.wrapping_shr(i as u32)); - assert_eq!(a.value.unwrap(), num >> i); + assert_eq!(a.value.unwrap(), num.wrapping_shr(i as u32)); assert_eq!(a.bits.len(), b.bits.len()); for (a, b) in a.bits.iter().zip(b.bits.iter()) { @@ -673,14 +667,17 @@ mod test { #[test] fn test_uint32_sha256_maj() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); - let a: u32 = rng.gen(); - let b: u32 = rng.gen(); - let c: u32 = rng.gen(); + let a = rng.next_u32(); + let b = rng.next_u32(); + let c = rng.next_u32(); let mut expected = (a & b) ^ (a & c) ^ (b & c); @@ -698,10 +695,10 @@ mod test { match b { &Boolean::Is(ref b) => { assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Not(ref b) => { assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Constant(b) => { assert!(b == (expected & 1 == 1)); } @@ -714,14 +711,17 @@ mod test { #[test] fn test_uint32_sha256_ch() { - let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]); + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); for _ in 0..1000 { let mut cs = TestConstraintSystem::::new(); - let a: u32 = rng.gen(); - let b: u32 = rng.gen(); - let c: u32 = rng.gen(); + let a = rng.next_u32(); + let b = rng.next_u32(); + let c = rng.next_u32(); let mut expected = (a & b) ^ ((!a) & c); @@ -739,10 +739,10 @@ mod test { match b { &Boolean::Is(ref b) => { assert!(b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Not(ref b) => { assert!(!b.get_value().unwrap() == (expected & 1 == 1)); - }, + } &Boolean::Constant(b) => { assert!(b == (expected & 1 == 1)); } diff --git a/bellman/src/groth16/generator.rs b/src/groth16/generator.rs similarity index 71% rename from bellman/src/groth16/generator.rs rename to src/groth16/generator.rs index f3f3d3a..767eddd 100644 --- a/bellman/src/groth16/generator.rs +++ b/src/groth16/generator.rs @@ -1,4 +1,4 @@ -use rand::Rng; +use rand_core::RngCore; use std::sync::Arc; @@ -6,55 +6,34 @@ use ff::{Field, PrimeField}; use group::{CurveAffine, CurveProjective, Wnaf}; use pairing::Engine; -use super::{ - Parameters, - VerifyingKey -}; +use super::{Parameters, VerifyingKey}; -use ::{ - SynthesisError, - Circuit, - ConstraintSystem, - LinearCombination, - Variable, - Index -}; +use crate::{Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; -use ::domain::{ - EvaluationDomain, - Scalar -}; +use crate::domain::{EvaluationDomain, Scalar}; -use ::multicore::{ - Worker -}; +use crate::multicore::Worker; /// Generates a random common reference string for /// a circuit. pub fn generate_random_parameters( circuit: C, - rng: &mut R + rng: &mut R, ) -> Result, SynthesisError> - where E: Engine, C: Circuit, R: Rng +where + E: Engine, + C: Circuit, + R: RngCore, { - let g1 = rng.gen(); - let g2 = rng.gen(); - let alpha = rng.gen(); - let beta = rng.gen(); - let gamma = rng.gen(); - let delta = rng.gen(); - let tau = rng.gen(); + let g1 = E::G1::random(rng); + let g2 = E::G2::random(rng); + let alpha = E::Fr::random(rng); + let beta = E::Fr::random(rng); + let gamma = E::Fr::random(rng); + let delta = E::Fr::random(rng); + let tau = E::Fr::random(rng); - generate_parameters::( - circuit, - g1, - g2, - alpha, - beta, - gamma, - delta, - tau - ) + generate_parameters::(circuit, g1, g2, alpha, beta, gamma, delta, tau) } /// This is our assembly structure that we'll use to synthesize the @@ -68,18 +47,17 @@ struct KeypairAssembly { ct_inputs: Vec>, at_aux: Vec>, bt_aux: Vec>, - ct_aux: Vec> + ct_aux: Vec>, } impl ConstraintSystem for KeypairAssembly { type Root = Self; - fn alloc( - &mut self, - _: A, - _: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, _: A, _: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { // There is no assignment, so we don't even invoke the // function for obtaining one. @@ -94,12 +72,11 @@ impl ConstraintSystem for KeypairAssembly { Ok(Variable(Index::Aux(index))) } - fn alloc_input( - &mut self, - _: A, - _: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, _: A, _: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { // There is no assignment, so we don't even invoke the // function for obtaining one. @@ -114,48 +91,59 @@ impl ConstraintSystem for KeypairAssembly { Ok(Variable(Index::Input(index))) } - fn enforce( - &mut self, - _: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, _: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { fn eval( l: LinearCombination, inputs: &mut [Vec<(E::Fr, usize)>], aux: &mut [Vec<(E::Fr, usize)>], - this_constraint: usize - ) - { + this_constraint: usize, + ) { for (index, coeff) in l.0 { match index { Variable(Index::Input(id)) => inputs[id].push((coeff, this_constraint)), - Variable(Index::Aux(id)) => aux[id].push((coeff, this_constraint)) + Variable(Index::Aux(id)) => aux[id].push((coeff, this_constraint)), } } } - eval(a(LinearCombination::zero()), &mut self.at_inputs, &mut self.at_aux, self.num_constraints); - eval(b(LinearCombination::zero()), &mut self.bt_inputs, &mut self.bt_aux, self.num_constraints); - eval(c(LinearCombination::zero()), &mut self.ct_inputs, &mut self.ct_aux, self.num_constraints); + eval( + a(LinearCombination::zero()), + &mut self.at_inputs, + &mut self.at_aux, + self.num_constraints, + ); + eval( + b(LinearCombination::zero()), + &mut self.bt_inputs, + &mut self.bt_aux, + self.num_constraints, + ); + eval( + c(LinearCombination::zero()), + &mut self.ct_inputs, + &mut self.ct_aux, + self.num_constraints, + ); self.num_constraints += 1; } fn push_namespace(&mut self, _: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { // Do nothing; we don't care about namespaces in this context. } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { // Do nothing; we don't care about namespaces in this context. } @@ -173,9 +161,11 @@ pub fn generate_parameters( beta: E::Fr, gamma: E::Fr, delta: E::Fr, - tau: E::Fr + tau: E::Fr, ) -> Result, SynthesisError> - where E: Engine, C: Circuit +where + E: Engine, + C: Circuit, { let mut assembly = KeypairAssembly { num_inputs: 0, @@ -186,7 +176,7 @@ pub fn generate_parameters( ct_inputs: vec![], at_aux: vec![], bt_aux: vec![], - ct_aux: vec![] + ct_aux: vec![], }; // Allocate the "one" input variable @@ -198,11 +188,7 @@ pub fn generate_parameters( // Input constraints to ensure full density of IC query // x * 0 = 0 for i in 0..assembly.num_inputs { - assembly.enforce(|| "", - |lc| lc + Variable(Index::Input(i)), - |lc| lc, - |lc| lc, - ); + assembly.enforce(|| "", |lc| lc + Variable(Index::Input(i)), |lc| lc, |lc| lc); } // Create bases for blind evaluation of polynomials at tau @@ -240,10 +226,9 @@ pub fn generate_parameters( { let powers_of_tau = powers_of_tau.as_mut(); worker.scope(powers_of_tau.len(), |scope, chunk| { - for (i, powers_of_tau) in powers_of_tau.chunks_mut(chunk).enumerate() - { - scope.spawn(move || { - let mut current_tau_power = tau.pow(&[(i*chunk) as u64]); + for (i, powers_of_tau) in powers_of_tau.chunks_mut(chunk).enumerate() { + scope.spawn(move |_scope| { + let mut current_tau_power = tau.pow(&[(i * chunk) as u64]); for p in powers_of_tau { p.0 = current_tau_power; @@ -260,14 +245,15 @@ pub fn generate_parameters( // Compute the H query with multiple threads worker.scope(h.len(), |scope, chunk| { - for (h, p) in h.chunks_mut(chunk).zip(powers_of_tau.as_ref().chunks(chunk)) + for (h, p) in h + .chunks_mut(chunk) + .zip(powers_of_tau.as_ref().chunks(chunk)) { let mut g1_wnaf = g1_wnaf.shared(); - scope.spawn(move || { + scope.spawn(move |_scope| { // Set values of the H query to g1^{(tau^i * t(tau)) / delta} - for (h, p) in h.iter_mut().zip(p.iter()) - { + for (h, p) in h.iter_mut().zip(p.iter()) { // Compute final exponent let mut exp = p.0; exp.mul_assign(&coeff); @@ -320,9 +306,8 @@ pub fn generate_parameters( beta: &E::Fr, // Worker - worker: &Worker - ) - { + worker: &Worker, + ) { // Sanity check assert_eq!(a.len(), at.len()); assert_eq!(a.len(), bt.len()); @@ -333,31 +318,32 @@ pub fn generate_parameters( // Evaluate polynomials in multiple threads worker.scope(a.len(), |scope, chunk| { - for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a.chunks_mut(chunk) - .zip(b_g1.chunks_mut(chunk)) - .zip(b_g2.chunks_mut(chunk)) - .zip(ext.chunks_mut(chunk)) - .zip(at.chunks(chunk)) - .zip(bt.chunks(chunk)) - .zip(ct.chunks(chunk)) + for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a + .chunks_mut(chunk) + .zip(b_g1.chunks_mut(chunk)) + .zip(b_g2.chunks_mut(chunk)) + .zip(ext.chunks_mut(chunk)) + .zip(at.chunks(chunk)) + .zip(bt.chunks(chunk)) + .zip(ct.chunks(chunk)) { let mut g1_wnaf = g1_wnaf.shared(); let mut g2_wnaf = g2_wnaf.shared(); - scope.spawn(move || { - for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a.iter_mut() - .zip(b_g1.iter_mut()) - .zip(b_g2.iter_mut()) - .zip(ext.iter_mut()) - .zip(at.iter()) - .zip(bt.iter()) - .zip(ct.iter()) + scope.spawn(move |_scope| { + for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a + .iter_mut() + .zip(b_g1.iter_mut()) + .zip(b_g2.iter_mut()) + .zip(ext.iter_mut()) + .zip(at.iter()) + .zip(bt.iter()) + .zip(ct.iter()) { fn eval_at_tau( powers_of_tau: &[Scalar], - p: &[(E::Fr, usize)] - ) -> E::Fr - { + p: &[(E::Fr, usize)], + ) -> E::Fr { let mut acc = E::Fr::zero(); for &(ref coeff, index) in p { @@ -422,10 +408,10 @@ pub fn generate_parameters( &gamma_inverse, &alpha, &beta, - &worker + &worker, ); - // Evaluate for auxillary variables. + // Evaluate for auxiliary variables. eval( &g1_wnaf, &g2_wnaf, @@ -440,7 +426,7 @@ pub fn generate_parameters( &delta_inverse, &alpha, &beta, - &worker + &worker, ); // Don't allow any elements be unconstrained, so that @@ -461,17 +447,32 @@ pub fn generate_parameters( gamma_g2: g2.mul(gamma).into_affine(), delta_g1: g1.mul(delta).into_affine(), delta_g2: g2.mul(delta).into_affine(), - ic: ic.into_iter().map(|e| e.into_affine()).collect() + ic: ic.into_iter().map(|e| e.into_affine()).collect(), }; Ok(Parameters { - vk: vk, + vk, h: Arc::new(h.into_iter().map(|e| e.into_affine()).collect()), l: Arc::new(l.into_iter().map(|e| e.into_affine()).collect()), // Filter points at infinity away from A/B queries - a: Arc::new(a.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()), - b_g1: Arc::new(b_g1.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()), - b_g2: Arc::new(b_g2.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()) + a: Arc::new( + a.into_iter() + .filter(|e| !e.is_zero()) + .map(|e| e.into_affine()) + .collect(), + ), + b_g1: Arc::new( + b_g1.into_iter() + .filter(|e| !e.is_zero()) + .map(|e| e.into_affine()) + .collect(), + ), + b_g2: Arc::new( + b_g2.into_iter() + .filter(|e| !e.is_zero()) + .map(|e| e.into_affine()) + .collect(), + ), }) } diff --git a/bellman/src/groth16/mod.rs b/src/groth16/mod.rs similarity index 64% rename from bellman/src/groth16/mod.rs rename to src/groth16/mod.rs index 620f32e..1ff152d 100644 --- a/bellman/src/groth16/mod.rs +++ b/src/groth16/mod.rs @@ -1,17 +1,16 @@ +//! The [Groth16] proving system. +//! +//! [Groth16]: https://eprint.iacr.org/2016/260 + use group::{CurveAffine, EncodedPoint}; -use pairing::{ - Engine, - PairingCurveAffine, -}; +use pairing::{Engine, PairingCurveAffine}; -use ::{ - SynthesisError -}; +use crate::SynthesisError; -use multiexp::SourceBuilder; +use crate::multiexp::SourceBuilder; +use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::io::{self, Read, Write}; use std::sync::Arc; -use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt}; #[cfg(test)] mod tests; @@ -28,23 +27,17 @@ pub use self::verifier::*; pub struct Proof { pub a: E::G1Affine, pub b: E::G2Affine, - pub c: E::G1Affine + pub c: E::G1Affine, } impl PartialEq for Proof { fn eq(&self, other: &Self) -> bool { - self.a == other.a && - self.b == other.b && - self.c == other.c + self.a == other.a && self.b == other.b && self.c == other.c } } impl Proof { - pub fn write( - &self, - mut writer: W - ) -> io::Result<()> - { + pub fn write(&self, mut writer: W) -> io::Result<()> { writer.write_all(self.a.into_compressed().as_ref())?; writer.write_all(self.b.into_compressed().as_ref())?; writer.write_all(self.c.into_compressed().as_ref())?; @@ -52,48 +45,56 @@ impl Proof { Ok(()) } - pub fn read( - mut reader: R - ) -> io::Result - { + pub fn read(mut reader: R) -> io::Result { let mut g1_repr = ::Compressed::empty(); let mut g2_repr = ::Compressed::empty(); reader.read_exact(g1_repr.as_mut())?; let a = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) } else { Ok(e) - })?; + } + })?; reader.read_exact(g2_repr.as_mut())?; let b = g2_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) } else { Ok(e) - })?; + } + })?; reader.read_exact(g1_repr.as_mut())?; let c = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) } else { Ok(e) - })?; + } + })?; - Ok(Proof { - a: a, - b: b, - c: c - }) + Ok(Proof { a, b, c }) } } @@ -122,27 +123,23 @@ pub struct VerifyingKey { // for all public inputs. Because all public inputs have a dummy constraint, // this is the same size as the number of inputs, and never contains points // at infinity. - pub ic: Vec + pub ic: Vec, } impl PartialEq for VerifyingKey { fn eq(&self, other: &Self) -> bool { - self.alpha_g1 == other.alpha_g1 && - self.beta_g1 == other.beta_g1 && - self.beta_g2 == other.beta_g2 && - self.gamma_g2 == other.gamma_g2 && - self.delta_g1 == other.delta_g1 && - self.delta_g2 == other.delta_g2 && - self.ic == other.ic + self.alpha_g1 == other.alpha_g1 + && self.beta_g1 == other.beta_g1 + && self.beta_g2 == other.beta_g2 + && self.gamma_g2 == other.gamma_g2 + && self.delta_g1 == other.delta_g1 + && self.delta_g2 == other.delta_g2 + && self.ic == other.ic } } impl VerifyingKey { - pub fn write( - &self, - mut writer: W - ) -> io::Result<()> - { + pub fn write(&self, mut writer: W) -> io::Result<()> { writer.write_all(self.alpha_g1.into_uncompressed().as_ref())?; writer.write_all(self.beta_g1.into_uncompressed().as_ref())?; writer.write_all(self.beta_g2.into_uncompressed().as_ref())?; @@ -157,30 +154,39 @@ impl VerifyingKey { Ok(()) } - pub fn read( - mut reader: R - ) -> io::Result - { + pub fn read(mut reader: R) -> io::Result { let mut g1_repr = ::Uncompressed::empty(); let mut g2_repr = ::Uncompressed::empty(); reader.read_exact(g1_repr.as_mut())?; - let alpha_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let alpha_g1 = g1_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; reader.read_exact(g1_repr.as_mut())?; - let beta_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let beta_g1 = g1_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; reader.read_exact(g2_repr.as_mut())?; - let beta_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let beta_g2 = g2_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; reader.read_exact(g2_repr.as_mut())?; - let gamma_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let gamma_g2 = g2_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; reader.read_exact(g1_repr.as_mut())?; - let delta_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let delta_g1 = g1_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; reader.read_exact(g2_repr.as_mut())?; - let delta_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + let delta_g2 = g2_repr + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; let ic_len = reader.read_u32::()? as usize; @@ -189,25 +195,30 @@ impl VerifyingKey { for _ in 0..ic_len { reader.read_exact(g1_repr.as_mut())?; let g1 = g1_repr - .into_affine() - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) - })?; + .into_affine() + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) + } else { + Ok(e) + } + })?; ic.push(g1); } Ok(VerifyingKey { - alpha_g1: alpha_g1, - beta_g1: beta_g1, - beta_g2: beta_g2, - gamma_g2: gamma_g2, - delta_g1: delta_g1, - delta_g2: delta_g2, - ic: ic + alpha_g1, + beta_g1, + beta_g2, + gamma_g2, + delta_g1, + delta_g2, + ic, }) } } @@ -216,12 +227,12 @@ impl VerifyingKey { pub struct Parameters { pub vk: VerifyingKey, - // Elements of the form ((tau^i * t(tau)) / delta) for i between 0 and + // Elements of the form ((tau^i * t(tau)) / delta) for i between 0 and // m-2 inclusive. Never contains points at infinity. pub h: Arc>, // Elements of the form (beta * u_i(tau) + alpha v_i(tau) + w_i(tau)) / delta - // for all auxillary inputs. Variables can never be unconstrained, so this + // for all auxiliary inputs. Variables can never be unconstrained, so this // never contains points at infinity. pub l: Arc>, @@ -234,26 +245,22 @@ pub struct Parameters { // G1 and G2 for C/B queries, respectively. Never contains points at // infinity for the same reason as the "A" polynomials. pub b_g1: Arc>, - pub b_g2: Arc> + pub b_g2: Arc>, } impl PartialEq for Parameters { fn eq(&self, other: &Self) -> bool { - self.vk == other.vk && - self.h == other.h && - self.l == other.l && - self.a == other.a && - self.b_g1 == other.b_g1 && - self.b_g2 == other.b_g2 + self.vk == other.vk + && self.h == other.h + && self.l == other.l + && self.a == other.a + && self.b_g1 == other.b_g1 + && self.b_g2 == other.b_g2 } } impl Parameters { - pub fn write( - &self, - mut writer: W - ) -> io::Result<()> - { + pub fn write(&self, mut writer: W) -> io::Result<()> { self.vk.write(&mut writer)?; writer.write_u32::(self.h.len() as u32)?; @@ -284,27 +291,26 @@ impl Parameters { Ok(()) } - pub fn read( - mut reader: R, - checked: bool - ) -> io::Result - { + pub fn read(mut reader: R, checked: bool) -> io::Result { let read_g1 = |reader: &mut R| -> io::Result { let mut repr = ::Uncompressed::empty(); reader.read_exact(repr.as_mut())?; if checked { - repr - .into_affine() + repr.into_affine() } else { - repr - .into_affine_unchecked() + repr.into_affine_unchecked() } .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) + } else { + Ok(e) + } }) }; @@ -313,17 +319,20 @@ impl Parameters { reader.read_exact(repr.as_mut())?; if checked { - repr - .into_affine() + repr.into_affine() } else { - repr - .into_affine_unchecked() + repr.into_affine_unchecked() } .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) - .and_then(|e| if e.is_zero() { - Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity")) - } else { - Ok(e) + .and_then(|e| { + if e.is_zero() { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "point at infinity", + )) + } else { + Ok(e) + } }) }; @@ -371,12 +380,12 @@ impl Parameters { } Ok(Parameters { - vk: vk, + vk, h: Arc::new(h), l: Arc::new(l), a: Arc::new(a), b_g1: Arc::new(b_g1), - b_g2: Arc::new(b_g2) + b_g2: Arc::new(b_g2), }) } } @@ -389,39 +398,30 @@ pub struct PreparedVerifyingKey { /// -delta in G2 neg_delta_g2: ::Prepared, /// Copy of IC from `VerifiyingKey`. - ic: Vec + ic: Vec, } pub trait ParameterSource { type G1Builder: SourceBuilder; type G2Builder: SourceBuilder; - fn get_vk( - &mut self, - num_ic: usize - ) -> Result, SynthesisError>; - fn get_h( - &mut self, - num_h: usize - ) -> Result; - fn get_l( - &mut self, - num_l: usize - ) -> Result; + fn get_vk(&mut self, num_ic: usize) -> Result, SynthesisError>; + fn get_h(&mut self, num_h: usize) -> Result; + fn get_l(&mut self, num_l: usize) -> Result; fn get_a( &mut self, num_inputs: usize, - num_aux: usize + num_aux: usize, ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>; fn get_b_g1( &mut self, num_inputs: usize, - num_aux: usize + num_aux: usize, ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>; fn get_b_g2( &mut self, num_inputs: usize, - num_aux: usize + num_aux: usize, ) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError>; } @@ -429,54 +429,39 @@ impl<'a, E: Engine> ParameterSource for &'a Parameters { type G1Builder = (Arc>, usize); type G2Builder = (Arc>, usize); - fn get_vk( - &mut self, - _: usize - ) -> Result, SynthesisError> - { + fn get_vk(&mut self, _: usize) -> Result, SynthesisError> { Ok(self.vk.clone()) } - fn get_h( - &mut self, - _: usize - ) -> Result - { + fn get_h(&mut self, _: usize) -> Result { Ok((self.h.clone(), 0)) } - fn get_l( - &mut self, - _: usize - ) -> Result - { + fn get_l(&mut self, _: usize) -> Result { Ok((self.l.clone(), 0)) } fn get_a( &mut self, num_inputs: usize, - _: usize - ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> - { + _: usize, + ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> { Ok(((self.a.clone(), 0), (self.a.clone(), num_inputs))) } fn get_b_g1( &mut self, num_inputs: usize, - _: usize - ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> - { + _: usize, + ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> { Ok(((self.b_g1.clone(), 0), (self.b_g1.clone(), num_inputs))) } fn get_b_g2( &mut self, num_inputs: usize, - _: usize - ) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError> - { + _: usize, + ) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError> { Ok(((self.b_g2.clone(), 0), (self.b_g2.clone(), num_inputs))) } } @@ -484,41 +469,38 @@ impl<'a, E: Engine> ParameterSource for &'a Parameters { #[cfg(test)] mod test_with_bls12_381 { use super::*; - use {Circuit, SynthesisError, ConstraintSystem}; + use crate::{Circuit, ConstraintSystem, SynthesisError}; use ff::Field; - use rand::{Rand, thread_rng}; use pairing::bls12_381::{Bls12, Fr}; + use rand::thread_rng; #[test] fn serialization() { struct MySillyCircuit { a: Option, - b: Option + b: Option, } impl Circuit for MySillyCircuit { fn synthesize>( self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { + cs: &mut CS, + ) -> Result<(), SynthesisError> { let a = cs.alloc(|| "a", || self.a.ok_or(SynthesisError::AssignmentMissing))?; let b = cs.alloc(|| "b", || self.b.ok_or(SynthesisError::AssignmentMissing))?; - let c = cs.alloc_input(|| "c", || { - let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?; - let b = self.b.ok_or(SynthesisError::AssignmentMissing)?; + let c = cs.alloc_input( + || "c", + || { + let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?; + let b = self.b.ok_or(SynthesisError::AssignmentMissing)?; - a.mul_assign(&b); - Ok(a) - })?; + a.mul_assign(&b); + Ok(a) + }, + )?; - cs.enforce( - || "a*b=c", - |lc| lc + a, - |lc| lc + b, - |lc| lc + c - ); + cs.enforce(|| "a*b=c", |lc| lc + a, |lc| lc + b, |lc| lc + c); Ok(()) } @@ -526,10 +508,9 @@ mod test_with_bls12_381 { let rng = &mut thread_rng(); - let params = generate_random_parameters::( - MySillyCircuit { a: None, b: None }, - rng - ).unwrap(); + let params = + generate_random_parameters::(MySillyCircuit { a: None, b: None }, rng) + .unwrap(); { let mut v = vec![]; @@ -547,19 +528,20 @@ mod test_with_bls12_381 { let pvk = prepare_verifying_key::(¶ms.vk); for _ in 0..100 { - let a = Fr::rand(rng); - let b = Fr::rand(rng); + let a = Fr::random(rng); + let b = Fr::random(rng); let mut c = a; c.mul_assign(&b); let proof = create_random_proof( MySillyCircuit { a: Some(a), - b: Some(b) + b: Some(b), }, ¶ms, - rng - ).unwrap(); + rng, + ) + .unwrap(); let mut v = vec![]; proof.write(&mut v).unwrap(); diff --git a/bellman/src/groth16/prover.rs b/src/groth16/prover.rs similarity index 65% rename from bellman/src/groth16/prover.rs rename to src/groth16/prover.rs index c674622..7fe282f 100644 --- a/bellman/src/groth16/prover.rs +++ b/src/groth16/prover.rs @@ -1,4 +1,4 @@ -use rand::Rng; +use rand_core::RngCore; use std::sync::Arc; @@ -8,43 +8,23 @@ use ff::{Field, PrimeField}; use group::{CurveAffine, CurveProjective}; use pairing::Engine; -use super::{ - ParameterSource, - Proof -}; +use super::{ParameterSource, Proof}; -use ::{ - SynthesisError, - Circuit, - ConstraintSystem, - LinearCombination, - Variable, - Index -}; +use crate::{Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable}; -use ::domain::{ - EvaluationDomain, - Scalar -}; +use crate::domain::{EvaluationDomain, Scalar}; -use ::multiexp::{ - DensityTracker, - FullDensity, - multiexp -}; +use crate::multiexp::{multiexp, DensityTracker, FullDensity}; -use ::multicore::{ - Worker -}; +use crate::multicore::Worker; fn eval( lc: &LinearCombination, mut input_density: Option<&mut DensityTracker>, mut aux_density: Option<&mut DensityTracker>, input_assignment: &[E::Fr], - aux_assignment: &[E::Fr] -) -> E::Fr -{ + aux_assignment: &[E::Fr], +) -> E::Fr { let mut acc = E::Fr::zero(); for &(index, coeff) in lc.0.iter() { @@ -56,7 +36,7 @@ fn eval( if let Some(ref mut v) = input_density { v.inc(i); } - }, + } Variable(Index::Aux(i)) => { tmp = aux_assignment[i]; if let Some(ref mut v) = aux_density { @@ -66,10 +46,10 @@ fn eval( } if coeff == E::Fr::one() { - acc.add_assign(&tmp); + acc.add_assign(&tmp); } else { - tmp.mul_assign(&coeff); - acc.add_assign(&tmp); + tmp.mul_assign(&coeff); + acc.add_assign(&tmp); } } @@ -89,18 +69,17 @@ struct ProvingAssignment { // Assignments of variables input_assignment: Vec, - aux_assignment: Vec + aux_assignment: Vec, } impl ConstraintSystem for ProvingAssignment { type Root = Self; - fn alloc( - &mut self, - _: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, _: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.aux_assignment.push(f()?); self.a_aux_density.add_element(); @@ -109,12 +88,11 @@ impl ConstraintSystem for ProvingAssignment { Ok(Variable(Index::Aux(self.aux_assignment.len() - 1))) } - fn alloc_input( - &mut self, - _: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, _: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.input_assignment.push(f()?); self.b_input_density.add_element(); @@ -122,17 +100,13 @@ impl ConstraintSystem for ProvingAssignment { Ok(Variable(Index::Input(self.input_assignment.len() - 1))) } - fn enforce( - &mut self, - _: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, _: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { let a = a(LinearCombination::zero()); let b = b(LinearCombination::zero()); @@ -146,14 +120,14 @@ impl ConstraintSystem for ProvingAssignment { None, Some(&mut self.a_aux_density), &self.input_assignment, - &self.aux_assignment + &self.aux_assignment, ))); self.b.push(Scalar(eval( &b, Some(&mut self.b_input_density), Some(&mut self.b_aux_density), &self.input_assignment, - &self.aux_assignment + &self.aux_assignment, ))); self.c.push(Scalar(eval( &c, @@ -164,18 +138,19 @@ impl ConstraintSystem for ProvingAssignment { None, None, &self.input_assignment, - &self.aux_assignment + &self.aux_assignment, ))); } fn push_namespace(&mut self, _: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { // Do nothing; we don't care about namespaces in this context. } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { // Do nothing; we don't care about namespaces in this context. } @@ -187,12 +162,15 @@ impl ConstraintSystem for ProvingAssignment { pub fn create_random_proof>( circuit: C, params: P, - rng: &mut R + rng: &mut R, ) -> Result, SynthesisError> - where E: Engine, C: Circuit, R: Rng +where + E: Engine, + C: Circuit, + R: RngCore, { - let r = rng.gen(); - let s = rng.gen(); + let r = E::Fr::random(rng); + let s = E::Fr::random(rng); create_proof::(circuit, params, r, s) } @@ -201,9 +179,11 @@ pub fn create_proof>( circuit: C, mut params: P, r: E::Fr, - s: E::Fr + s: E::Fr, ) -> Result, SynthesisError> - where E: Engine, C: Circuit +where + E: Engine, + C: Circuit, { let mut prover = ProvingAssignment { a_aux_density: DensityTracker::new(), @@ -213,7 +193,7 @@ pub fn create_proof>( b: vec![], c: vec![], input_assignment: vec![], - aux_assignment: vec![] + aux_assignment: vec![], }; prover.alloc_input(|| "", || Ok(E::Fr::one()))?; @@ -221,11 +201,7 @@ pub fn create_proof>( circuit.synthesize(&mut prover)?; for i in 0..prover.input_assignment.len() { - prover.enforce(|| "", - |lc| lc + Variable(Index::Input(i)), - |lc| lc, - |lc| lc, - ); + prover.enforce(|| "", |lc| lc + Variable(Index::Input(i)), |lc| lc, |lc| lc); } let worker = Worker::new(); @@ -259,31 +235,76 @@ pub fn create_proof>( }; // TODO: parallelize if it's even helpful - let input_assignment = Arc::new(prover.input_assignment.into_iter().map(|s| s.into_repr()).collect::>()); - let aux_assignment = Arc::new(prover.aux_assignment.into_iter().map(|s| s.into_repr()).collect::>()); + let input_assignment = Arc::new( + prover + .input_assignment + .into_iter() + .map(|s| s.into_repr()) + .collect::>(), + ); + let aux_assignment = Arc::new( + prover + .aux_assignment + .into_iter() + .map(|s| s.into_repr()) + .collect::>(), + ); - let l = multiexp(&worker, params.get_l(aux_assignment.len())?, FullDensity, aux_assignment.clone()); + let l = multiexp( + &worker, + params.get_l(aux_assignment.len())?, + FullDensity, + aux_assignment.clone(), + ); let a_aux_density_total = prover.a_aux_density.get_total_density(); - let (a_inputs_source, a_aux_source) = params.get_a(input_assignment.len(), a_aux_density_total)?; + let (a_inputs_source, a_aux_source) = + params.get_a(input_assignment.len(), a_aux_density_total)?; - let a_inputs = multiexp(&worker, a_inputs_source, FullDensity, input_assignment.clone()); - let a_aux = multiexp(&worker, a_aux_source, Arc::new(prover.a_aux_density), aux_assignment.clone()); + let a_inputs = multiexp( + &worker, + a_inputs_source, + FullDensity, + input_assignment.clone(), + ); + let a_aux = multiexp( + &worker, + a_aux_source, + Arc::new(prover.a_aux_density), + aux_assignment.clone(), + ); let b_input_density = Arc::new(prover.b_input_density); let b_input_density_total = b_input_density.get_total_density(); let b_aux_density = Arc::new(prover.b_aux_density); let b_aux_density_total = b_aux_density.get_total_density(); - let (b_g1_inputs_source, b_g1_aux_source) = params.get_b_g1(b_input_density_total, b_aux_density_total)?; + let (b_g1_inputs_source, b_g1_aux_source) = + params.get_b_g1(b_input_density_total, b_aux_density_total)?; - let b_g1_inputs = multiexp(&worker, b_g1_inputs_source, b_input_density.clone(), input_assignment.clone()); - let b_g1_aux = multiexp(&worker, b_g1_aux_source, b_aux_density.clone(), aux_assignment.clone()); + let b_g1_inputs = multiexp( + &worker, + b_g1_inputs_source, + b_input_density.clone(), + input_assignment.clone(), + ); + let b_g1_aux = multiexp( + &worker, + b_g1_aux_source, + b_aux_density.clone(), + aux_assignment.clone(), + ); - let (b_g2_inputs_source, b_g2_aux_source) = params.get_b_g2(b_input_density_total, b_aux_density_total)?; - - let b_g2_inputs = multiexp(&worker, b_g2_inputs_source, b_input_density, input_assignment); + let (b_g2_inputs_source, b_g2_aux_source) = + params.get_b_g2(b_input_density_total, b_aux_density_total)?; + + let b_g2_inputs = multiexp( + &worker, + b_g2_inputs_source, + b_input_density, + input_assignment, + ); let b_g2_aux = multiexp(&worker, b_g2_aux_source, b_aux_density, aux_assignment); if vk.delta_g1.is_zero() || vk.delta_g2.is_zero() { @@ -325,6 +346,6 @@ pub fn create_proof>( Ok(Proof { a: g_a.into_affine(), b: g_b.into_affine(), - c: g_c.into_affine() + c: g_c.into_affine(), }) } diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/src/groth16/tests/dummy_engine.rs similarity index 89% rename from bellman/src/groth16/tests/dummy_engine.rs rename to src/groth16/tests/dummy_engine.rs index d5f37a9..4692078 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/src/groth16/tests/dummy_engine.rs @@ -1,12 +1,13 @@ use ff::{ - Field, LegendreSymbol, PrimeField, PrimeFieldDecodingError, - PrimeFieldRepr, ScalarEngine, SqrtField}; + Field, LegendreSymbol, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine, + SqrtField, +}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use pairing::{Engine, PairingCurveAffine}; +use rand_core::RngCore; use std::cmp::Ordering; use std::fmt; -use rand::{Rand, Rng}; use std::num::Wrapping; const MODULUS_R: Wrapping = Wrapping(64513); @@ -15,18 +16,16 @@ const MODULUS_R: Wrapping = Wrapping(64513); pub struct Fr(Wrapping); impl fmt::Display for Fr { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{}", (self.0).0) } } -impl Rand for Fr { - fn rand(rng: &mut R) -> Self { - Fr(Wrapping(rng.gen()) % MODULUS_R) - } -} - impl Field for Fr { + fn random(rng: &mut R) -> Self { + Fr(Wrapping(rng.next_u32()) % MODULUS_R) + } + fn zero() -> Self { Fr(Wrapping(0)) } @@ -82,9 +81,13 @@ impl SqrtField for Fr { fn legendre(&self) -> LegendreSymbol { // s = self^((r - 1) // 2) let s = self.pow([32256]); - if s == ::zero() { LegendreSymbol::Zero } - else if s == ::one() { LegendreSymbol::QuadraticResidue } - else { LegendreSymbol::QuadraticNonResidue } + if s == ::zero() { + LegendreSymbol::Zero + } else if s == ::one() { + LegendreSymbol::QuadraticResidue + } else { + LegendreSymbol::QuadraticNonResidue + } } fn sqrt(&self) -> Option { @@ -102,7 +105,7 @@ impl SqrtField for Fr { let mut m = Fr::S; while t != ::one() { - let mut i = 1; + let mut i = 1; { let mut t2i = t; t2i.square(); @@ -145,14 +148,8 @@ impl PartialOrd for FrRepr { } } -impl Rand for FrRepr { - fn rand(rng: &mut R) -> Self { - FrRepr([rng.gen()]) - } -} - impl fmt::Display for FrRepr { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(f, "{}", (self.0)[0]) } } @@ -266,15 +263,18 @@ impl Engine for DummyEngine { type G2Affine = Fr; type Fq = Fr; type Fqe = Fr; - + // TODO: This should be F_645131 or something. Doesn't matter for now. type Fqk = Fr; fn miller_loop<'a, I>(i: I) -> Self::Fqk - where I: IntoIterator::Prepared, - &'a ::Prepared - )> + where + I: IntoIterator< + Item = &'a ( + &'a ::Prepared, + &'a ::Prepared, + ), + >, { let mut acc = ::zero(); @@ -288,8 +288,7 @@ impl Engine for DummyEngine { } /// Perform final exponentiation of the result of a miller loop. - fn final_exponentiation(this: &Self::Fqk) -> Option - { + fn final_exponentiation(this: &Self::Fqk) -> Option { Some(*this) } } @@ -300,6 +299,10 @@ impl CurveProjective for Fr { type Scalar = Fr; type Engine = DummyEngine; + fn random(rng: &mut R) -> Self { + ::random(rng) + } + fn zero() -> Self { ::zero() } @@ -312,9 +315,7 @@ impl CurveProjective for Fr { ::is_zero(self) } - fn batch_normalization(_: &mut [Self]) { - - } + fn batch_normalization(_: &mut [Self]) {} fn is_normalized(&self) -> bool { true @@ -336,8 +337,7 @@ impl CurveProjective for Fr { ::negate(self); } - fn mul_assign::Repr>>(&mut self, other: S) - { + fn mul_assign::Repr>>(&mut self, other: S) { let tmp = Fr::from_repr(other.into()).unwrap(); ::mul_assign(self, &tmp); @@ -419,8 +419,7 @@ impl CurveAffine for Fr { ::negate(self); } - fn mul::Repr>>(&self, other: S) -> Self::Projective - { + fn mul::Repr>>(&self, other: S) -> Self::Projective { let mut res = *self; let tmp = Fr::from_repr(other.into()).unwrap(); diff --git a/bellman/src/groth16/tests/mod.rs b/src/groth16/tests/mod.rs similarity index 78% rename from bellman/src/groth16/tests/mod.rs rename to src/groth16/tests/mod.rs index 0e05c36..d8be98e 100644 --- a/bellman/src/groth16/tests/mod.rs +++ b/src/groth16/tests/mod.rs @@ -6,86 +6,82 @@ use self::dummy_engine::*; use std::marker::PhantomData; -use ::{ - Circuit, - ConstraintSystem, - SynthesisError -}; +use crate::{Circuit, ConstraintSystem, SynthesisError}; -use super::{ - generate_parameters, - prepare_verifying_key, - create_proof, - verify_proof -}; +use super::{create_proof, generate_parameters, prepare_verifying_key, verify_proof}; struct XORDemo { a: Option, b: Option, - _marker: PhantomData + _marker: PhantomData, } impl Circuit for XORDemo { - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { - let a_var = cs.alloc(|| "a", || { - if self.a.is_some() { - if self.a.unwrap() { - Ok(E::Fr::one()) + fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { + let a_var = cs.alloc( + || "a", + || { + if self.a.is_some() { + if self.a.unwrap() { + Ok(E::Fr::one()) + } else { + Ok(E::Fr::zero()) + } } else { - Ok(E::Fr::zero()) + Err(SynthesisError::AssignmentMissing) } - } else { - Err(SynthesisError::AssignmentMissing) - } - })?; + }, + )?; cs.enforce( || "a_boolean_constraint", |lc| lc + CS::one() - a_var, |lc| lc + a_var, - |lc| lc + |lc| lc, ); - let b_var = cs.alloc(|| "b", || { - if self.b.is_some() { - if self.b.unwrap() { - Ok(E::Fr::one()) + let b_var = cs.alloc( + || "b", + || { + if self.b.is_some() { + if self.b.unwrap() { + Ok(E::Fr::one()) + } else { + Ok(E::Fr::zero()) + } } else { - Ok(E::Fr::zero()) + Err(SynthesisError::AssignmentMissing) } - } else { - Err(SynthesisError::AssignmentMissing) - } - })?; + }, + )?; cs.enforce( || "b_boolean_constraint", |lc| lc + CS::one() - b_var, |lc| lc + b_var, - |lc| lc + |lc| lc, ); - let c_var = cs.alloc_input(|| "c", || { - if self.a.is_some() && self.b.is_some() { - if self.a.unwrap() ^ self.b.unwrap() { - Ok(E::Fr::one()) + let c_var = cs.alloc_input( + || "c", + || { + if self.a.is_some() && self.b.is_some() { + if self.a.unwrap() ^ self.b.unwrap() { + Ok(E::Fr::one()) + } else { + Ok(E::Fr::zero()) + } } else { - Ok(E::Fr::zero()) + Err(SynthesisError::AssignmentMissing) } - } else { - Err(SynthesisError::AssignmentMissing) - } - })?; + }, + )?; cs.enforce( || "c_xor_constraint", |lc| lc + a_var + a_var, |lc| lc + b_var, - |lc| lc + a_var + b_var - c_var + |lc| lc + a_var + b_var - c_var, ); Ok(()) @@ -106,19 +102,10 @@ fn test_xordemo() { let c = XORDemo:: { a: None, b: None, - _marker: PhantomData + _marker: PhantomData, }; - generate_parameters( - c, - g1, - g2, - alpha, - beta, - gamma, - delta, - tau - ).unwrap() + generate_parameters(c, g1, g2, alpha, beta, gamma, delta, tau).unwrap() }; // This will synthesize the constraint system: @@ -226,32 +213,35 @@ fn test_xordemo() { 59158 */ - let u_i = [59158, 48317, 21767, 10402].iter().map(|e| { - Fr::from_str(&format!("{}", e)).unwrap() - }).collect::>(); - let v_i = [0, 0, 60619, 30791].iter().map(|e| { - Fr::from_str(&format!("{}", e)).unwrap() - }).collect::>(); - let w_i = [0, 23320, 41193, 41193].iter().map(|e| { - Fr::from_str(&format!("{}", e)).unwrap() - }).collect::>(); + let u_i = [59158, 48317, 21767, 10402] + .iter() + .map(|e| Fr::from_str(&format!("{}", e)).unwrap()) + .collect::>(); + let v_i = [0, 0, 60619, 30791] + .iter() + .map(|e| Fr::from_str(&format!("{}", e)).unwrap()) + .collect::>(); + let w_i = [0, 23320, 41193, 41193] + .iter() + .map(|e| Fr::from_str(&format!("{}", e)).unwrap()) + .collect::>(); - for (u, a) in u_i.iter() - .zip(¶ms.a[..]) - { + for (u, a) in u_i.iter().zip(¶ms.a[..]) { assert_eq!(u, a); } - for (v, b) in v_i.iter() - .filter(|&&e| e != Fr::zero()) - .zip(¶ms.b_g1[..]) + for (v, b) in v_i + .iter() + .filter(|&&e| e != Fr::zero()) + .zip(¶ms.b_g1[..]) { assert_eq!(v, b); } - for (v, b) in v_i.iter() - .filter(|&&e| e != Fr::zero()) - .zip(¶ms.b_g2[..]) + for (v, b) in v_i + .iter() + .filter(|&&e| e != Fr::zero()) + .zip(¶ms.b_g2[..]) { assert_eq!(v, b); } @@ -296,15 +286,10 @@ fn test_xordemo() { let c = XORDemo { a: Some(true), b: Some(false), - _marker: PhantomData + _marker: PhantomData, }; - create_proof( - c, - ¶ms, - r, - s - ).unwrap() + create_proof(c, ¶ms, r, s).unwrap() }; // A(x) = @@ -320,7 +305,7 @@ fn test_xordemo() { expected_a.add_assign(&u_i[0]); // a_0 = 1 expected_a.add_assign(&u_i[1]); // a_1 = 1 expected_a.add_assign(&u_i[2]); // a_2 = 1 - // a_3 = 0 + // a_3 = 0 assert_eq!(proof.a, expected_a); } @@ -337,7 +322,7 @@ fn test_xordemo() { expected_b.add_assign(&v_i[0]); // a_0 = 1 expected_b.add_assign(&v_i[1]); // a_1 = 1 expected_b.add_assign(&v_i[2]); // a_2 = 1 - // a_3 = 0 + // a_3 = 0 assert_eq!(proof.b, expected_b); } @@ -378,7 +363,10 @@ fn test_xordemo() { expected_c.add_assign(¶ms.l[0]); // H query answer - for (i, coeff) in [5040, 11763, 10755, 63633, 128, 9747, 8739].iter().enumerate() { + for (i, coeff) in [5040, 11763, 10755, 63633, 128, 9747, 8739] + .iter() + .enumerate() + { let coeff = Fr::from_str(&format!("{}", coeff)).unwrap(); let mut tmp = params.h[i]; @@ -389,9 +377,5 @@ fn test_xordemo() { assert_eq!(expected_c, proof.c); } - assert!(verify_proof( - &pvk, - &proof, - &[Fr::one()] - ).unwrap()); + assert!(verify_proof(&pvk, &proof, &[Fr::one()]).unwrap()); } diff --git a/bellman/src/groth16/verifier.rs b/src/groth16/verifier.rs similarity index 73% rename from bellman/src/groth16/verifier.rs rename to src/groth16/verifier.rs index 71c7478..5bc0581 100644 --- a/bellman/src/groth16/verifier.rs +++ b/src/groth16/verifier.rs @@ -2,20 +2,11 @@ use ff::PrimeField; use group::{CurveAffine, CurveProjective}; use pairing::{Engine, PairingCurveAffine}; -use super::{ - Proof, - VerifyingKey, - PreparedVerifyingKey -}; +use super::{PreparedVerifyingKey, Proof, VerifyingKey}; -use ::{ - SynthesisError -}; +use crate::SynthesisError; -pub fn prepare_verifying_key( - vk: &VerifyingKey -) -> PreparedVerifyingKey -{ +pub fn prepare_verifying_key(vk: &VerifyingKey) -> PreparedVerifyingKey { let mut gamma = vk.gamma_g2; gamma.negate(); let mut delta = vk.delta_g2; @@ -25,16 +16,15 @@ pub fn prepare_verifying_key( alpha_g1_beta_g2: E::pairing(vk.alpha_g1, vk.beta_g2), neg_gamma_g2: gamma.prepare(), neg_delta_g2: delta.prepare(), - ic: vk.ic.clone() + ic: vk.ic.clone(), } } pub fn verify_proof<'a, E: Engine>( pvk: &'a PreparedVerifyingKey, proof: &Proof, - public_inputs: &[E::Fr] -) -> Result -{ + public_inputs: &[E::Fr], +) -> Result { if (public_inputs.len() + 1) != pvk.ic.len() { return Err(SynthesisError::MalformedVerifyingKey); } @@ -53,11 +43,14 @@ pub fn verify_proof<'a, E: Engine>( // A * B + inputs * (-gamma) + C * (-delta) = alpha * beta // which allows us to do a single final exponentiation. - Ok(E::final_exponentiation( - &E::miller_loop([ + Ok(E::final_exponentiation(&E::miller_loop( + [ (&proof.a.prepare(), &proof.b.prepare()), (&acc.into_affine().prepare(), &pvk.neg_gamma_g2), - (&proof.c.prepare(), &pvk.neg_delta_g2) - ].into_iter()) - ).unwrap() == pvk.alpha_g1_beta_g2) + (&proof.c.prepare(), &pvk.neg_delta_g2), + ] + .iter(), + )) + .unwrap() + == pvk.alpha_g1_beta_g2) } diff --git a/bellman/src/lib.rs b/src/lib.rs similarity index 51% rename from bellman/src/lib.rs rename to src/lib.rs index f6d7163..a3b577b 100644 --- a/bellman/src/lib.rs +++ b/src/lib.rs @@ -1,28 +1,167 @@ -extern crate ff; -extern crate group; -#[cfg(feature = "pairing")] -extern crate pairing; -extern crate rand; -extern crate num_cpus; -extern crate futures; -extern crate futures_cpupool; -extern crate bit_vec; -extern crate crossbeam; -extern crate byteorder; +//! `bellman` is a crate for building zk-SNARK circuits. It provides circuit +//! traits and and primitive structures, as well as basic gadget implementations +//! such as booleans and number abstractions. +//! +//! # Example circuit +//! +//! Say we want to write a circuit that proves we know the preimage to some hash +//! computed using SHA-256d (calling SHA-256 twice). The preimage must have a +//! fixed length known in advance (because the circuit parameters will depend on +//! it), but can otherwise have any value. We take the following strategy: +//! +//! - Witness each bit of the preimage. +//! - Compute `hash = SHA-256d(preimage)` inside the circuit. +//! - Expose `hash` as a public input using multiscalar packing. +//! +//! ``` +//! use bellman::{ +//! gadgets::{ +//! boolean::{AllocatedBit, Boolean}, +//! multipack, +//! sha256::sha256, +//! }, +//! groth16, Circuit, ConstraintSystem, SynthesisError, +//! }; +//! use pairing::{bls12_381::Bls12, Engine}; +//! use rand::rngs::OsRng; +//! use sha2::{Digest, Sha256}; +//! +//! /// Our own SHA-256d gadget. Input and output are in little-endian bit order. +//! fn sha256d>( +//! mut cs: CS, +//! data: &[Boolean], +//! ) -> Result, SynthesisError> { +//! // Flip endianness of each input byte +//! let input: Vec<_> = data +//! .chunks(8) +//! .map(|c| c.iter().rev()) +//! .flatten() +//! .cloned() +//! .collect(); +//! +//! let mid = sha256(cs.namespace(|| "SHA-256(input)"), &input)?; +//! let res = sha256(cs.namespace(|| "SHA-256(mid)"), &mid)?; +//! +//! // Flip endianness of each output byte +//! Ok(res +//! .chunks(8) +//! .map(|c| c.iter().rev()) +//! .flatten() +//! .cloned() +//! .collect()) +//! } +//! +//! struct MyCircuit { +//! /// The input to SHA-256d we are proving that we know. Set to `None` when we +//! /// are verifying a proof (and do not have the witness data). +//! preimage: Option<[u8; 80]>, +//! } +//! +//! impl Circuit for MyCircuit { +//! fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { +//! // Compute the values for the bits of the preimage. If we are verifying a proof, +//! // we still need to create the same constraints, so we return an equivalent-size +//! // Vec of None (indicating that the value of each bit is unknown). +//! let bit_values = if let Some(preimage) = self.preimage { +//! preimage +//! .into_iter() +//! .map(|byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8)) +//! .flatten() +//! .map(|b| Some(b)) +//! .collect() +//! } else { +//! vec![None; 80 * 8] +//! }; +//! assert_eq!(bit_values.len(), 80 * 8); +//! +//! // Witness the bits of the preimage. +//! let preimage_bits = bit_values +//! .into_iter() +//! .enumerate() +//! // Allocate each bit. +//! .map(|(i, b)| { +//! AllocatedBit::alloc(cs.namespace(|| format!("preimage bit {}", i)), b) +//! }) +//! // Convert the AllocatedBits into Booleans (required for the sha256 gadget). +//! .map(|b| b.map(Boolean::from)) +//! .collect::, _>>()?; +//! +//! // Compute hash = SHA-256d(preimage). +//! let hash = sha256d(cs.namespace(|| "SHA-256d(preimage)"), &preimage_bits)?; +//! +//! // Expose the vector of 32 boolean variables as compact public inputs. +//! multipack::pack_into_inputs(cs.namespace(|| "pack hash"), &hash) +//! } +//! } +//! +//! // Create parameters for our circuit. In a production deployment these would +//! // be generated securely using a multiparty computation. +//! let params = { +//! let c = MyCircuit { preimage: None }; +//! groth16::generate_random_parameters::(c, &mut OsRng).unwrap() +//! }; +//! +//! // Prepare the verification key (for proof verification). +//! let pvk = groth16::prepare_verifying_key(¶ms.vk); +//! +//! // Pick a preimage and compute its hash. +//! let preimage = [42; 80]; +//! let hash = Sha256::digest(&Sha256::digest(&preimage)); +//! +//! // Create an instance of our circuit (with the preimage as a witness). +//! let c = MyCircuit { +//! preimage: Some(preimage), +//! }; +//! +//! // Create a Groth16 proof with our parameters. +//! let proof = groth16::create_random_proof(c, ¶ms, &mut OsRng).unwrap(); +//! +//! // Pack the hash as inputs for proof verification. +//! let hash_bits = multipack::bytes_to_bits_le(&hash); +//! let inputs = multipack::compute_multipacking::(&hash_bits); +//! +//! // Check the proof! +//! assert!(groth16::verify_proof(&pvk, &proof, &inputs).unwrap()); +//! ``` +//! +//! # Roadmap +//! +//! `bellman` is being refactored into a generic proving library. Currently it +//! is pairing-specific, and different types of proving systems need to be +//! implemented as sub-modules. After the refactor, `bellman` will be generic +//! using the [`ff`] and [`group`] crates, while specific proving systems will +//! be separate crates that pull in the dependencies they require. + +// Catch documentation errors caused by code changes. +#![deny(intra_doc_link_resolution_failure)] + +#[cfg(feature = "multicore")] +extern crate crossbeam; + +#[cfg(feature = "multicore")] +extern crate num_cpus; + +#[cfg(test)] +#[macro_use] +extern crate hex_literal; + +#[cfg(test)] +extern crate rand; -pub mod multicore; -mod multiexp; pub mod domain; +pub mod gadgets; #[cfg(feature = "groth16")] pub mod groth16; +pub mod multicore; +mod multiexp; use ff::{Field, ScalarEngine}; -use std::ops::{Add, Sub}; -use std::fmt; use std::error::Error; +use std::fmt; use std::io; use std::marker::PhantomData; +use std::ops::{Add, Sub}; /// Computations are expressed in terms of arithmetic circuits, in particular /// rank-1 quadratic constraint systems. The `Circuit` trait represents a @@ -30,10 +169,7 @@ use std::marker::PhantomData; /// CRS generation and during proving. pub trait Circuit { /// Synthesize the circuit into a rank-1 quadratic constraint system - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError>; + fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError>; } /// Represents a variable in our constraint system. @@ -55,11 +191,11 @@ impl Variable { } /// Represents the index of either an input variable or -/// auxillary variable. +/// auxiliary variable. #[derive(Copy, Clone, PartialEq, Debug)] pub enum Index { Input(usize), - Aux(usize) + Aux(usize), } /// This represents a linear combination of some variables, with coefficients @@ -92,6 +228,7 @@ impl Add<(E::Fr, Variable)> for LinearCombination { impl Sub<(E::Fr, Variable)> for LinearCombination { type Output = LinearCombination; + #[allow(clippy::suspicious_arithmetic_impl)] fn sub(self, (mut coeff, var): (E::Fr, Variable)) -> LinearCombination { coeff.negate(); @@ -185,8 +322,8 @@ pub enum SynthesisError { IoError(io::Error), /// During verification, our verifying key was malformed. MalformedVerifyingKey, - /// During CRS generation, we observed an unconstrained auxillary variable - UnconstrainedVariable + /// During CRS generation, we observed an unconstrained auxiliary variable + UnconstrainedVariable, } impl From for SynthesisError { @@ -198,21 +335,23 @@ impl From for SynthesisError { impl Error for SynthesisError { fn description(&self) -> &str { match *self { - SynthesisError::AssignmentMissing => "an assignment for a variable could not be computed", + SynthesisError::AssignmentMissing => { + "an assignment for a variable could not be computed" + } SynthesisError::DivisionByZero => "division by zero", SynthesisError::Unsatisfiable => "unsatisfiable constraint system", SynthesisError::PolynomialDegreeTooLarge => "polynomial degree is too large", SynthesisError::UnexpectedIdentity => "encountered an identity element in the CRS", SynthesisError::IoError(_) => "encountered an I/O error", SynthesisError::MalformedVerifyingKey => "malformed verifying key", - SynthesisError::UnconstrainedVariable => "auxillary variable was unconstrained" + SynthesisError::UnconstrainedVariable => "auxiliary variable was unconstrained", } } } impl fmt::Display for SynthesisError { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - if let &SynthesisError::IoError(ref e) = self { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + if let SynthesisError::IoError(ref e) = *self { write!(f, "I/O error: ")?; e.fmt(f) } else { @@ -237,40 +376,36 @@ pub trait ConstraintSystem: Sized { /// determine the assignment of the variable. The given `annotation` function is invoked /// in testing contexts in order to derive a unique name for this variable in the current /// namespace. - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into; + fn alloc(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into; /// Allocate a public variable in the constraint system. The provided function is used to /// determine the assignment of the variable. - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into; + fn alloc_input(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into; /// Enforce that `A` * `B` = `C`. The `annotation` function is invoked in testing contexts /// in order to derive a unique name for the constraint in the current namespace. - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination; + fn enforce(&mut self, annotation: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination; /// Create a new (sub)namespace and enter into it. Not intended /// for downstream use; use `namespace` instead. fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR; + where + NR: Into, + N: FnOnce() -> NR; /// Exit out of the existing namespace. Not intended for /// downstream use; use `namespace` instead. @@ -281,11 +416,10 @@ pub trait ConstraintSystem: Sized { fn get_root(&mut self) -> &mut Self::Root; /// Begin a namespace for this constraint system. - fn namespace<'a, NR, N>( - &'a mut self, - name_fn: N - ) -> Namespace<'a, E, Self::Root> - where NR: Into, N: FnOnce() -> NR + fn namespace(&mut self, name_fn: N) -> Namespace<'_, E, Self::Root> + where + NR: Into, + N: FnOnce() -> NR, { self.get_root().push_namespace(name_fn); @@ -295,7 +429,7 @@ pub trait ConstraintSystem: Sized { /// This is a "namespaced" constraint system which borrows a constraint system (pushing /// a namespace context) and, when dropped, pops out of the namespace context. -pub struct Namespace<'a, E: ScalarEngine, CS: ConstraintSystem + 'a>(&'a mut CS, PhantomData); +pub struct Namespace<'a, E: ScalarEngine, CS: ConstraintSystem>(&'a mut CS, PhantomData); impl<'cs, E: ScalarEngine, CS: ConstraintSystem> ConstraintSystem for Namespace<'cs, E, CS> { type Root = CS::Root; @@ -304,37 +438,31 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem> ConstraintSystem for Name CS::one() } - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.0.alloc(annotation, f) } - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { self.0.alloc_input(annotation, f) } - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, annotation: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { self.0.enforce(annotation, a, b, c) } @@ -344,18 +472,18 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem> ConstraintSystem for Name // never a root constraint system. fn push_namespace(&mut self, _: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { panic!("only the root's push_namespace should be called"); } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { panic!("only the root's pop_namespace should be called"); } - fn get_root(&mut self) -> &mut Self::Root - { + fn get_root(&mut self) -> &mut Self::Root { self.0.get_root() } } @@ -375,54 +503,48 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem> ConstraintSystem for &'cs CS::one() } - fn alloc( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { (**self).alloc(annotation, f) } - fn alloc_input( - &mut self, - annotation: A, - f: F - ) -> Result - where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into + fn alloc_input(&mut self, annotation: A, f: F) -> Result + where + F: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, { (**self).alloc_input(annotation, f) } - fn enforce( - &mut self, - annotation: A, - a: LA, - b: LB, - c: LC - ) - where A: FnOnce() -> AR, AR: Into, - LA: FnOnce(LinearCombination) -> LinearCombination, - LB: FnOnce(LinearCombination) -> LinearCombination, - LC: FnOnce(LinearCombination) -> LinearCombination + fn enforce(&mut self, annotation: A, a: LA, b: LB, c: LC) + where + A: FnOnce() -> AR, + AR: Into, + LA: FnOnce(LinearCombination) -> LinearCombination, + LB: FnOnce(LinearCombination) -> LinearCombination, + LC: FnOnce(LinearCombination) -> LinearCombination, { (**self).enforce(annotation, a, b, c) } fn push_namespace(&mut self, name_fn: N) - where NR: Into, N: FnOnce() -> NR + where + NR: Into, + N: FnOnce() -> NR, { (**self).push_namespace(name_fn) } - fn pop_namespace(&mut self) - { + fn pop_namespace(&mut self) { (**self).pop_namespace() } - fn get_root(&mut self) -> &mut Self::Root - { + fn get_root(&mut self) -> &mut Self::Root { (**self).get_root() } } diff --git a/src/multicore.rs b/src/multicore.rs new file mode 100644 index 0000000..ba69b5f --- /dev/null +++ b/src/multicore.rs @@ -0,0 +1,164 @@ +//! An interface for dealing with the kinds of parallel computations involved in +//! `bellman`. It's currently just a thin wrapper around [`CpuPool`] and +//! [`crossbeam`] but may be extended in the future to allow for various +//! parallelism strategies. +//! +//! [`CpuPool`]: futures_cpupool::CpuPool + +#[cfg(feature = "multicore")] +mod implementation { + use crossbeam::{self, thread::Scope}; + use futures::{Future, IntoFuture, Poll}; + use futures_cpupool::{CpuFuture, CpuPool}; + use num_cpus; + + #[derive(Clone)] + pub struct Worker { + cpus: usize, + pool: CpuPool, + } + + impl Worker { + // We don't expose this outside the library so that + // all `Worker` instances have the same number of + // CPUs configured. + pub(crate) fn new_with_cpus(cpus: usize) -> Worker { + Worker { + cpus, + pool: CpuPool::new(cpus), + } + } + + pub fn new() -> Worker { + Self::new_with_cpus(num_cpus::get()) + } + + pub fn log_num_cpus(&self) -> u32 { + log2_floor(self.cpus) + } + + pub fn compute(&self, f: F) -> WorkerFuture + where + F: FnOnce() -> R + Send + 'static, + R: IntoFuture + 'static, + R::Future: Send + 'static, + R::Item: Send + 'static, + R::Error: Send + 'static, + { + WorkerFuture { + future: self.pool.spawn_fn(f), + } + } + + pub fn scope<'a, F, R>(&self, elements: usize, f: F) -> R + where + F: FnOnce(&Scope<'a>, usize) -> R, + { + let chunk_size = if elements < self.cpus { + 1 + } else { + elements / self.cpus + }; + + // TODO: Handle case where threads fail + crossbeam::scope(|scope| f(scope, chunk_size)) + .expect("Threads aren't allowed to fail yet") + } + } + + pub struct WorkerFuture { + future: CpuFuture, + } + + impl Future for WorkerFuture { + type Item = T; + type Error = E; + + fn poll(&mut self) -> Poll { + self.future.poll() + } + } + + fn log2_floor(num: usize) -> u32 { + assert!(num > 0); + + let mut pow = 0; + + while (1 << (pow + 1)) <= num { + pow += 1; + } + + pow + } + + #[test] + fn test_log2_floor() { + assert_eq!(log2_floor(1), 0); + assert_eq!(log2_floor(2), 1); + assert_eq!(log2_floor(3), 1); + assert_eq!(log2_floor(4), 2); + assert_eq!(log2_floor(5), 2); + assert_eq!(log2_floor(6), 2); + assert_eq!(log2_floor(7), 2); + assert_eq!(log2_floor(8), 3); + } +} + +#[cfg(not(feature = "multicore"))] +mod implementation { + use futures::{future, Future, IntoFuture, Poll}; + + #[derive(Clone)] + pub struct Worker; + + impl Worker { + pub fn new() -> Worker { + Worker + } + + pub fn log_num_cpus(&self) -> u32 { + 0 + } + + pub fn compute(&self, f: F) -> R::Future + where + F: FnOnce() -> R + Send + 'static, + R: IntoFuture + 'static, + R::Future: Send + 'static, + R::Item: Send + 'static, + R::Error: Send + 'static, + { + f().into_future() + } + + pub fn scope(&self, elements: usize, f: F) -> R + where + F: FnOnce(&DummyScope, usize) -> R, + { + f(&DummyScope, elements) + } + } + + pub struct WorkerFuture { + future: future::FutureResult, + } + + impl Future for WorkerFuture { + type Item = T; + type Error = E; + + fn poll(&mut self) -> Poll { + self.future.poll() + } + } + + pub struct DummyScope; + + impl DummyScope { + pub fn spawn(&self, f: F) { + f(self); + } + } +} + +pub use self::implementation::*; diff --git a/bellman/src/multiexp.rs b/src/multiexp.rs similarity index 75% rename from bellman/src/multiexp.rs rename to src/multiexp.rs index d24572b..b7729a8 100644 --- a/bellman/src/multiexp.rs +++ b/src/multiexp.rs @@ -1,11 +1,11 @@ -use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; -use group::{CurveAffine, CurveProjective}; -use std::sync::Arc; -use std::io; -use bit_vec::{self, BitVec}; -use std::iter; -use futures::{Future}; use super::multicore::Worker; +use bit_vec::{self, BitVec}; +use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine}; +use futures::Future; +use group::{CurveAffine, CurveProjective}; +use std::io; +use std::iter; +use std::sync::Arc; use super::SynthesisError; @@ -19,7 +19,10 @@ pub trait SourceBuilder: Send + Sync + 'static + Clone { /// A source of bases, like an iterator. pub trait Source { /// Parses the element from the source. Fails if the point is at infinity. - fn add_assign_mixed(&mut self, to: &mut ::Projective) -> Result<(), SynthesisError>; + fn add_assign_mixed( + &mut self, + to: &mut ::Projective, + ) -> Result<(), SynthesisError>; /// Skips `amt` elements from the source, avoiding deserialization. fn skip(&mut self, amt: usize) -> Result<(), SynthesisError>; @@ -34,13 +37,20 @@ impl SourceBuilder for (Arc>, usize) { } impl Source for (Arc>, usize) { - fn add_assign_mixed(&mut self, to: &mut ::Projective) -> Result<(), SynthesisError> { + fn add_assign_mixed( + &mut self, + to: &mut ::Projective, + ) -> Result<(), SynthesisError> { if self.0.len() <= self.1 { - return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into()); + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + "expected more bases from source", + ) + .into()); } if self.0[self.1].is_zero() { - return Err(SynthesisError::UnexpectedIdentity) + return Err(SynthesisError::UnexpectedIdentity); } to.add_assign_mixed(&self.0[self.1]); @@ -52,7 +62,11 @@ impl Source for (Arc>, usize) { fn skip(&mut self, amt: usize) -> Result<(), SynthesisError> { if self.0.len() <= self.1 { - return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into()); + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + "expected more bases from source", + ) + .into()); } self.1 += amt; @@ -63,7 +77,7 @@ impl Source for (Arc>, usize) { pub trait QueryDensity { /// Returns whether the base exists. - type Iter: Iterator; + type Iter: Iterator; fn iter(self) -> Self::Iter; fn get_query_size(self) -> Option; @@ -92,7 +106,7 @@ impl<'a> QueryDensity for &'a FullDensity { pub struct DensityTracker { bv: BitVec, - total_density: usize + total_density: usize, } impl<'a> QueryDensity for &'a DensityTracker { @@ -111,7 +125,7 @@ impl DensityTracker { pub fn new() -> DensityTracker { DensityTracker { bv: BitVec::new(), - total_density: 0 + total_density: 0, } } @@ -138,12 +152,13 @@ fn multiexp_inner( exponents: Arc::Fr as PrimeField>::Repr>>, mut skip: u32, c: u32, - handle_trivial: bool -) -> Box::Projective, Error=SynthesisError>> - where for<'a> &'a Q: QueryDensity, - D: Send + Sync + 'static + Clone + AsRef, - G: CurveAffine, - S: SourceBuilder + handle_trivial: bool, +) -> Box::Projective, Error = SynthesisError>> +where + for<'a> &'a Q: QueryDensity, + D: Send + Sync + 'static + Clone + AsRef, + G: CurveAffine, + S: SourceBuilder, { // Perform this region of the multiexp let this = { @@ -212,16 +227,24 @@ fn multiexp_inner( // There's another region more significant. Calculate and join it with // this region recursively. Box::new( - this.join(multiexp_inner(pool, bases, density_map, exponents, skip, c, false)) - .map(move |(this, mut higher)| { - for _ in 0..c { - higher.double(); - } + this.join(multiexp_inner( + pool, + bases, + density_map, + exponents, + skip, + c, + false, + )) + .map(move |(this, mut higher)| { + for _ in 0..c { + higher.double(); + } - higher.add_assign(&this); + higher.add_assign(&this); - higher - }) + higher + }), ) } } @@ -232,12 +255,13 @@ pub fn multiexp( pool: &Worker, bases: S, density_map: D, - exponents: Arc::Fr as PrimeField>::Repr>> -) -> Box::Projective, Error=SynthesisError>> - where for<'a> &'a Q: QueryDensity, - D: Send + Sync + 'static + Clone + AsRef, - G: CurveAffine, - S: SourceBuilder + exponents: Arc::Fr as PrimeField>::Repr>>, +) -> Box::Projective, Error = SynthesisError>> +where + for<'a> &'a Q: QueryDensity, + D: Send + Sync + 'static + Clone + AsRef, + G: CurveAffine, + S: SourceBuilder, { let c = if exponents.len() < 32 { 3u32 @@ -260,9 +284,8 @@ pub fn multiexp( fn test_with_bls12() { fn naive_multiexp( bases: Arc>, - exponents: Arc::Repr>> - ) -> G::Projective - { + exponents: Arc::Repr>>, + ) -> G::Projective { assert_eq!(bases.len(), exponents.len()); let mut acc = G::Projective::zero(); @@ -274,25 +297,28 @@ fn test_with_bls12() { acc } - use rand::{self, Rand}; use pairing::{bls12_381::Bls12, Engine}; + use rand; const SAMPLES: usize = 1 << 14; let rng = &mut rand::thread_rng(); - let v = Arc::new((0..SAMPLES).map(|_| ::Fr::rand(rng).into_repr()).collect::>()); - let g = Arc::new((0..SAMPLES).map(|_| ::G1::rand(rng).into_affine()).collect::>()); + let v = Arc::new( + (0..SAMPLES) + .map(|_| ::Fr::random(rng).into_repr()) + .collect::>(), + ); + let g = Arc::new( + (0..SAMPLES) + .map(|_| ::G1::random(rng).into_affine()) + .collect::>(), + ); let naive = naive_multiexp(g.clone(), v.clone()); let pool = Worker::new(); - let fast = multiexp( - &pool, - (g, 0), - FullDensity, - v - ).wait().unwrap(); + let fast = multiexp(&pool, (g, 0), FullDensity, v).wait().unwrap(); assert_eq!(naive, fast); } diff --git a/bellman/tests/mimc.rs b/tests/mimc.rs similarity index 70% rename from bellman/tests/mimc.rs rename to tests/mimc.rs index 1d554a5..e9a4c7c 100644 --- a/bellman/tests/mimc.rs +++ b/tests/mimc.rs @@ -1,44 +1,29 @@ -extern crate bellman; -extern crate ff; -extern crate pairing; -extern crate rand; - // For randomness (during paramgen and proof generation) -use rand::{thread_rng, Rng}; +use rand::thread_rng; // For benchmarking use std::time::{Duration, Instant}; // Bring in some tools for using pairing-friendly curves -use ff::Field; +use ff::{Field, ScalarEngine}; use pairing::Engine; // We're going to use the BLS12-381 pairing-friendly elliptic curve. -use pairing::bls12_381::{ - Bls12 -}; +use pairing::bls12_381::Bls12; // We'll use these interfaces to construct our circuit. -use bellman::{ - Circuit, - ConstraintSystem, - SynthesisError -}; +use bellman::{Circuit, ConstraintSystem, SynthesisError}; // We're going to use the Groth16 proving system. use bellman::groth16::{ - Proof, - generate_random_parameters, - prepare_verifying_key, - create_random_proof, - verify_proof, + create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof, Proof, }; const MIMC_ROUNDS: usize = 322; /// This is an implementation of MiMC, specifically a /// variant named `LongsightF322p3` for BLS12-381. -/// See http://eprint.iacr.org/2016/492 for more +/// See http://eprint.iacr.org/2016/492 for more /// information about this construction. /// /// ``` @@ -49,12 +34,7 @@ const MIMC_ROUNDS: usize = 322; /// return xL /// } /// ``` -fn mimc( - mut xl: E::Fr, - mut xr: E::Fr, - constants: &[E::Fr] -) -> E::Fr -{ +fn mimc(mut xl: E::Fr, mut xr: E::Fr, constants: &[E::Fr]) -> E::Fr { assert_eq!(constants.len(), MIMC_ROUNDS); for i in 0..MIMC_ROUNDS { @@ -76,80 +56,81 @@ fn mimc( struct MiMCDemo<'a, E: Engine> { xl: Option, xr: Option, - constants: &'a [E::Fr] + constants: &'a [E::Fr], } /// Our demo circuit implements this `Circuit` trait which /// is used during paramgen and proving in order to /// synthesize the constraint system. impl<'a, E: Engine> Circuit for MiMCDemo<'a, E> { - fn synthesize>( - self, - cs: &mut CS - ) -> Result<(), SynthesisError> - { + fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { assert_eq!(self.constants.len(), MIMC_ROUNDS); // Allocate the first component of the preimage. let mut xl_value = self.xl; - let mut xl = cs.alloc(|| "preimage xl", || { - xl_value.ok_or(SynthesisError::AssignmentMissing) - })?; + let mut xl = cs.alloc( + || "preimage xl", + || xl_value.ok_or(SynthesisError::AssignmentMissing), + )?; // Allocate the second component of the preimage. let mut xr_value = self.xr; - let mut xr = cs.alloc(|| "preimage xr", || { - xr_value.ok_or(SynthesisError::AssignmentMissing) - })?; + let mut xr = cs.alloc( + || "preimage xr", + || xr_value.ok_or(SynthesisError::AssignmentMissing), + )?; for i in 0..MIMC_ROUNDS { // xL, xR := xR + (xL + Ci)^3, xL let cs = &mut cs.namespace(|| format!("round {}", i)); // tmp = (xL + Ci)^2 - let mut tmp_value = xl_value.map(|mut e| { + let tmp_value = xl_value.map(|mut e| { e.add_assign(&self.constants[i]); e.square(); e }); - let mut tmp = cs.alloc(|| "tmp", || { - tmp_value.ok_or(SynthesisError::AssignmentMissing) - })?; + let tmp = cs.alloc( + || "tmp", + || tmp_value.ok_or(SynthesisError::AssignmentMissing), + )?; cs.enforce( || "tmp = (xL + Ci)^2", |lc| lc + xl + (self.constants[i], CS::one()), |lc| lc + xl + (self.constants[i], CS::one()), - |lc| lc + tmp + |lc| lc + tmp, ); // new_xL = xR + (xL + Ci)^3 // new_xL = xR + tmp * (xL + Ci) // new_xL - xR = tmp * (xL + Ci) - let mut new_xl_value = xl_value.map(|mut e| { + let new_xl_value = xl_value.map(|mut e| { e.add_assign(&self.constants[i]); e.mul_assign(&tmp_value.unwrap()); e.add_assign(&xr_value.unwrap()); e }); - let mut new_xl = if i == (MIMC_ROUNDS-1) { + let new_xl = if i == (MIMC_ROUNDS - 1) { // This is the last round, xL is our image and so // we allocate a public input. - cs.alloc_input(|| "image", || { - new_xl_value.ok_or(SynthesisError::AssignmentMissing) - })? + cs.alloc_input( + || "image", + || new_xl_value.ok_or(SynthesisError::AssignmentMissing), + )? } else { - cs.alloc(|| "new_xl", || { - new_xl_value.ok_or(SynthesisError::AssignmentMissing) - })? + cs.alloc( + || "new_xl", + || new_xl_value.ok_or(SynthesisError::AssignmentMissing), + )? }; cs.enforce( || "new_xL = xR + (xL + Ci)^3", |lc| lc + tmp, |lc| lc + xl + (self.constants[i], CS::one()), - |lc| lc + new_xl - xr + |lc| lc + new_xl - xr, ); // xR = xL @@ -172,7 +153,9 @@ fn test_mimc() { let rng = &mut thread_rng(); // Generate the MiMC round constants - let constants = (0..MIMC_ROUNDS).map(|_| rng.gen()).collect::>(); + let constants = (0..MIMC_ROUNDS) + .map(|_| ::Fr::random(rng)) + .collect::>(); println!("Creating parameters..."); @@ -181,7 +164,7 @@ fn test_mimc() { let c = MiMCDemo:: { xl: None, xr: None, - constants: &constants + constants: &constants, }; generate_random_parameters(c, rng).unwrap() @@ -203,8 +186,8 @@ fn test_mimc() { for _ in 0..SAMPLES { // Generate a random preimage and compute the image - let xl = rng.gen(); - let xr = rng.gen(); + let xl = ::Fr::random(rng); + let xr = ::Fr::random(rng); let image = mimc::(xl, xr, &constants); proof_vec.truncate(0); @@ -216,7 +199,7 @@ fn test_mimc() { let c = MiMCDemo { xl: Some(xl), xr: Some(xr), - constants: &constants + constants: &constants, }; // Create a groth16 proof with our parameters. @@ -230,20 +213,16 @@ fn test_mimc() { let start = Instant::now(); let proof = Proof::read(&proof_vec[..]).unwrap(); // Check the proof - assert!(verify_proof( - &pvk, - &proof, - &[image] - ).unwrap()); + assert!(verify_proof(&pvk, &proof, &[image]).unwrap()); total_verifying += start.elapsed(); } let proving_avg = total_proving / SAMPLES; - let proving_avg = proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 - + (proving_avg.as_secs() as f64); + let proving_avg = + proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (proving_avg.as_secs() as f64); let verifying_avg = total_verifying / SAMPLES; - let verifying_avg = verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 - + (verifying_avg.as_secs() as f64); + let verifying_avg = + verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (verifying_avg.as_secs() as f64); println!("Average proving time: {:?} seconds", proving_avg); println!("Average verifying time: {:?} seconds", verifying_avg); diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml deleted file mode 100644 index bf6c03f..0000000 --- a/zcash_primitives/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "zcash_primitives" -version = "0.0.0" -authors = [ - "Jack Grigg ", -] - -[dependencies] -byteorder = "1" -lazy_static = "1" -pairing = { path = "../pairing" } -rand = "0.4" -sapling-crypto = { path = "../sapling-crypto" } - -[dependencies.blake2-rfc] -git = "https://github.com/gtank/blake2-rfc" -rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" diff --git a/zcash_primitives/LICENSE-APACHE b/zcash_primitives/LICENSE-APACHE deleted file mode 100644 index 1e5006d..0000000 --- a/zcash_primitives/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. - diff --git a/zcash_primitives/LICENSE-MIT b/zcash_primitives/LICENSE-MIT deleted file mode 100644 index 5b7be8e..0000000 --- a/zcash_primitives/LICENSE-MIT +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017 Zcash Company - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/zcash_primitives/README.md b/zcash_primitives/README.md deleted file mode 100644 index b284820..0000000 --- a/zcash_primitives/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# zcash_primitives - -This library contains Rust implementations of the Zcash primitives. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. - diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs deleted file mode 100644 index 5f4dd05..0000000 --- a/zcash_primitives/src/lib.rs +++ /dev/null @@ -1,17 +0,0 @@ -#[macro_use] -extern crate lazy_static; - -extern crate blake2_rfc; -extern crate byteorder; -extern crate pairing; -extern crate rand; -extern crate sapling_crypto; - -use sapling_crypto::jubjub::JubjubBls12; - -mod serialize; -pub mod transaction; - -lazy_static! { - static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() }; -} diff --git a/zcash_primitives/src/serialize.rs b/zcash_primitives/src/serialize.rs deleted file mode 100644 index f142943..0000000 --- a/zcash_primitives/src/serialize.rs +++ /dev/null @@ -1,156 +0,0 @@ -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use std::io::{self, Read, Write}; - -const MAX_SIZE: usize = 0x02000000; - -struct CompactSize; - -impl CompactSize { - fn read(mut reader: R) -> io::Result { - let flag = reader.read_u8()?; - match if flag < 253 { - Ok(flag as usize) - } else if flag == 253 { - match reader.read_u16::()? { - n if n < 253 => Err(io::Error::new( - io::ErrorKind::InvalidInput, - "non-canonical CompactSize", - )), - n => Ok(n as usize), - } - } else if flag == 254 { - match reader.read_u32::()? { - n if n < 0x10000 => Err(io::Error::new( - io::ErrorKind::InvalidInput, - "non-canonical CompactSize", - )), - n => Ok(n as usize), - } - } else { - match reader.read_u64::()? { - n if n < 0x100000000 => Err(io::Error::new( - io::ErrorKind::InvalidInput, - "non-canonical CompactSize", - )), - n => Ok(n as usize), - } - }? { - s if s > MAX_SIZE => Err(io::Error::new( - io::ErrorKind::InvalidInput, - "CompactSize too large", - )), - s => Ok(s), - } - } - - fn write(mut writer: W, size: usize) -> io::Result<()> { - match size { - s if s < 253 => writer.write_u8(s as u8), - s if s <= 0xFFFF => { - writer.write_u8(253)?; - writer.write_u16::(s as u16) - } - s if s <= 0xFFFFFFFF => { - writer.write_u8(254)?; - writer.write_u32::(s as u32) - } - s => { - writer.write_u8(255)?; - writer.write_u64::(s as u64) - } - } - } -} - -pub struct Vector; - -impl Vector { - pub fn read(mut reader: R, func: F) -> io::Result> - where - F: Fn(&mut R) -> io::Result, - { - let count = CompactSize::read(&mut reader)?; - (0..count).into_iter().map(|_| func(&mut reader)).collect() - } - - pub fn write(mut writer: W, vec: &[E], func: F) -> io::Result<()> - where - F: Fn(&mut W, &E) -> io::Result<()>, - { - CompactSize::write(&mut writer, vec.len())?; - vec.iter().map(|e| func(&mut writer, e)).collect() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn compact_size() { - macro_rules! eval { - ($value:expr, $expected:expr) => { - let mut data = vec![]; - CompactSize::write(&mut data, $value).unwrap(); - assert_eq!(&data[..], &$expected[..]); - match CompactSize::read(&data[..]) { - Ok(n) => assert_eq!(n, $value), - Err(e) => panic!("Unexpected error: {:?}", e), - } - }; - } - - eval!(0, [0]); - eval!(1, [1]); - eval!(252, [252]); - eval!(253, [253, 253, 0]); - eval!(254, [253, 254, 0]); - eval!(255, [253, 255, 0]); - eval!(256, [253, 0, 1]); - eval!(256, [253, 0, 1]); - eval!(65535, [253, 255, 255]); - eval!(65536, [254, 0, 0, 1, 0]); - eval!(65537, [254, 1, 0, 1, 0]); - - eval!(33554432, [254, 0, 0, 0, 2]); - - { - let value = 33554433; - let encoded = &[254, 1, 0, 0, 2][..]; - let mut data = vec![]; - CompactSize::write(&mut data, value).unwrap(); - assert_eq!(&data[..], encoded); - assert!(CompactSize::read(encoded).is_err()); - } - } - - #[test] - fn vector() { - macro_rules! eval { - ($value:expr, $expected:expr) => { - let mut data = vec![]; - Vector::write(&mut data, &$value, |w, e| w.write_u8(*e)).unwrap(); - assert_eq!(&data[..], &$expected[..]); - match Vector::read(&data[..], |r| r.read_u8()) { - Ok(v) => assert_eq!(v, $value), - Err(e) => panic!("Unexpected error: {:?}", e), - } - }; - } - - eval!(vec![], [0]); - eval!(vec![0], [1, 0]); - eval!(vec![1], [1, 1]); - eval!(vec![5; 8], [8, 5, 5, 5, 5, 5, 5, 5, 5]); - - { - // expected = [253, 4, 1, 7, 7, 7, ...] - let mut expected = vec![7; 263]; - expected[0] = 253; - expected[1] = 4; - expected[2] = 1; - - eval!(vec![7; 260], expected); - } - } -} diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs deleted file mode 100644 index 21dbd46..0000000 --- a/zcash_primitives/src/transaction/components.rs +++ /dev/null @@ -1,432 +0,0 @@ -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use pairing::{ - bls12_381::{Bls12, Fr, FrRepr}, - PrimeField, PrimeFieldRepr, -}; -use sapling_crypto::{ - jubjub::{edwards, Unknown}, - redjubjub::{PublicKey, Signature}, -}; -use std::io::{self, Read, Write}; - -use serialize::Vector; -use JUBJUB; - -// π_A + π_B + π_C -const GROTH_PROOF_SIZE: usize = (48 + 96 + 48); -// π_A + π_A' + π_B + π_B' + π_C + π_C' + π_K + π_H -const PHGR_PROOF_SIZE: usize = (33 + 33 + 65 + 33 + 33 + 33 + 33 + 33); - -const ZC_NUM_JS_INPUTS: usize = 2; -const ZC_NUM_JS_OUTPUTS: usize = 2; - -const COIN: i64 = 1_0000_0000; -const MAX_MONEY: i64 = 21_000_000 * COIN; - -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct Amount(pub i64); - -impl Amount { - // Read an Amount from a signed 64-bit little-endian integer. - pub fn read_i64(mut reader: R, allow_negative: bool) -> io::Result { - let amount = reader.read_i64::()?; - if 0 <= amount && amount <= MAX_MONEY { - Ok(Amount(amount)) - } else if allow_negative && -MAX_MONEY <= amount && amount < 0 { - Ok(Amount(amount)) - } else { - Err(io::Error::new( - io::ErrorKind::InvalidData, - if allow_negative { - "Amount not in {-MAX_MONEY..MAX_MONEY}" - } else { - "Amount not in {0..MAX_MONEY}" - }, - )) - } - } - - // Read an Amount from an unsigned 64-bit little-endian integer. - pub fn read_u64(mut reader: R) -> io::Result { - let amount = reader.read_u64::()?; - if amount <= MAX_MONEY as u64 { - Ok(Amount(amount as i64)) - } else { - Err(io::Error::new( - io::ErrorKind::InvalidData, - "Amount not in {0..MAX_MONEY}", - )) - } - } -} - -pub struct Script(pub Vec); - -impl Script { - pub fn read(mut reader: R) -> io::Result { - let script = Vector::read(&mut reader, |r| r.read_u8())?; - Ok(Script(script)) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - Vector::write(&mut writer, &self.0, |w, e| w.write_u8(*e)) - } -} - -pub struct OutPoint { - hash: [u8; 32], - n: u32, -} - -impl OutPoint { - pub fn read(mut reader: R) -> io::Result { - let mut hash = [0; 32]; - reader.read_exact(&mut hash)?; - let n = reader.read_u32::()?; - Ok(OutPoint { hash, n }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_all(&self.hash)?; - writer.write_u32::(self.n) - } -} - -pub struct TxIn { - pub prevout: OutPoint, - script_sig: Script, - pub sequence: u32, -} - -impl TxIn { - pub fn read(mut reader: &mut R) -> io::Result { - let prevout = OutPoint::read(&mut reader)?; - let script_sig = Script::read(&mut reader)?; - let sequence = reader.read_u32::()?; - - Ok(TxIn { - prevout, - script_sig, - sequence, - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - self.prevout.write(&mut writer)?; - self.script_sig.write(&mut writer)?; - writer.write_u32::(self.sequence) - } -} - -pub struct TxOut { - value: Amount, - script_pubkey: Script, -} - -impl TxOut { - pub fn read(mut reader: &mut R) -> io::Result { - let value = Amount::read_i64(&mut reader, false)?; - let script_pubkey = Script::read(&mut reader)?; - - Ok(TxOut { - value, - script_pubkey, - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_i64::(self.value.0)?; - self.script_pubkey.write(&mut writer) - } -} - -pub struct SpendDescription { - pub cv: edwards::Point, - pub anchor: Fr, - pub nullifier: [u8; 32], - pub rk: PublicKey, - pub zkproof: [u8; GROTH_PROOF_SIZE], - pub spend_auth_sig: Signature, -} - -impl SpendDescription { - pub fn read(mut reader: &mut R) -> io::Result { - // Consensus rules (§4.4): - // - Canonical encoding is enforced here. - // - "Not small order" is enforced in SaplingVerificationContext::check_spend() - // (located in zcash_proofs::sapling::verifier). - let cv = edwards::Point::::read(&mut reader, &JUBJUB)?; - - // Consensus rule (§7.3): Canonical encoding is enforced here - let anchor = { - let mut f = FrRepr::default(); - f.read_le(&mut reader)?; - Fr::from_repr(f).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))? - }; - - let mut nullifier = [0; 32]; - reader.read_exact(&mut nullifier)?; - - // Consensus rules (§4.4): - // - Canonical encoding is enforced here. - // - "Not small order" is enforced in SaplingVerificationContext::check_spend() - let rk = PublicKey::::read(&mut reader, &JUBJUB)?; - - // Consensus rules (§4.4): - // - Canonical encoding is enforced by the API of SaplingVerificationContext::check_spend() - // due to the need to parse this into a bellman::groth16::Proof. - // - Proof validity is enforced in SaplingVerificationContext::check_spend() - let mut zkproof = [0; GROTH_PROOF_SIZE]; - reader.read_exact(&mut zkproof)?; - - // Consensus rules (§4.4): - // - Canonical encoding is enforced here. - // - Signature validity is enforced in SaplingVerificationContext::check_spend() - let spend_auth_sig = Signature::read(&mut reader)?; - - Ok(SpendDescription { - cv, - anchor, - nullifier, - rk, - zkproof, - spend_auth_sig, - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - self.cv.write(&mut writer)?; - self.anchor.into_repr().write_le(&mut writer)?; - writer.write_all(&self.nullifier)?; - self.rk.write(&mut writer)?; - writer.write_all(&self.zkproof)?; - self.spend_auth_sig.write(&mut writer) - } -} - -pub struct OutputDescription { - pub cv: edwards::Point, - pub cmu: Fr, - pub ephemeral_key: edwards::Point, - pub enc_ciphertext: [u8; 580], - pub out_ciphertext: [u8; 80], - pub zkproof: [u8; GROTH_PROOF_SIZE], -} - -impl OutputDescription { - pub fn read(mut reader: &mut R) -> io::Result { - // Consensus rules (§4.5): - // - Canonical encoding is enforced here. - // - "Not small order" is enforced in SaplingVerificationContext::check_output() - // (located in zcash_proofs::sapling::verifier). - let cv = edwards::Point::::read(&mut reader, &JUBJUB)?; - - // Consensus rule (§7.4): Canonical encoding is enforced here - let cmu = { - let mut f = FrRepr::default(); - f.read_le(&mut reader)?; - Fr::from_repr(f).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))? - }; - - // Consensus rules (§4.5): - // - Canonical encoding is enforced here. - // - "Not small order" is enforced in SaplingVerificationContext::check_output() - let ephemeral_key = edwards::Point::::read(&mut reader, &JUBJUB)?; - - let mut enc_ciphertext = [0; 580]; - let mut out_ciphertext = [0; 80]; - reader.read_exact(&mut enc_ciphertext)?; - reader.read_exact(&mut out_ciphertext)?; - - // Consensus rules (§4.5): - // - Canonical encoding is enforced by the API of SaplingVerificationContext::check_output() - // due to the need to parse this into a bellman::groth16::Proof. - // - Proof validity is enforced in SaplingVerificationContext::check_output() - let mut zkproof = [0; GROTH_PROOF_SIZE]; - reader.read_exact(&mut zkproof)?; - - Ok(OutputDescription { - cv, - cmu, - ephemeral_key, - enc_ciphertext, - out_ciphertext, - zkproof, - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - self.cv.write(&mut writer)?; - self.cmu.into_repr().write_le(&mut writer)?; - self.ephemeral_key.write(&mut writer)?; - writer.write_all(&self.enc_ciphertext)?; - writer.write_all(&self.out_ciphertext)?; - writer.write_all(&self.zkproof) - } -} - -enum SproutProof { - Groth([u8; GROTH_PROOF_SIZE]), - PHGR([u8; PHGR_PROOF_SIZE]), -} - -pub struct JSDescription { - vpub_old: Amount, - vpub_new: Amount, - anchor: [u8; 32], - nullifiers: [[u8; 32]; ZC_NUM_JS_INPUTS], - commitments: [[u8; 32]; ZC_NUM_JS_OUTPUTS], - ephemeral_key: [u8; 32], - random_seed: [u8; 32], - macs: [[u8; 32]; ZC_NUM_JS_INPUTS], - proof: SproutProof, - ciphertexts: [[u8; 601]; ZC_NUM_JS_OUTPUTS], -} - -impl JSDescription { - pub fn read(mut reader: R, use_groth: bool) -> io::Result { - // Consensus rule (§4.3): Canonical encoding is enforced here - let vpub_old = Amount::read_u64(&mut reader)?; - - // Consensus rule (§4.3): Canonical encoding is enforced here - let vpub_new = Amount::read_u64(&mut reader)?; - - // Consensus rule (§4.3): One of vpub_old and vpub_new being zero is - // enforced by CheckTransactionWithoutProofVerification() in zcashd. - - let mut anchor = [0; 32]; - reader.read_exact(&mut anchor)?; - - let mut nullifiers = [[0; 32]; ZC_NUM_JS_INPUTS]; - nullifiers - .iter_mut() - .map(|nf| reader.read_exact(nf)) - .collect::>()?; - - let mut commitments = [[0; 32]; ZC_NUM_JS_OUTPUTS]; - commitments - .iter_mut() - .map(|cm| reader.read_exact(cm)) - .collect::>()?; - - // Consensus rule (§4.3): Canonical encoding is enforced by - // ZCNoteDecryption::decrypt() in zcashd - let mut ephemeral_key = [0; 32]; - reader.read_exact(&mut ephemeral_key)?; - - let mut random_seed = [0; 32]; - reader.read_exact(&mut random_seed)?; - - let mut macs = [[0; 32]; ZC_NUM_JS_INPUTS]; - macs.iter_mut() - .map(|mac| reader.read_exact(mac)) - .collect::>()?; - - let proof = match use_groth { - true => { - // Consensus rules (§4.3): - // - Canonical encoding is enforced in librustzcash_sprout_verify() - // - Proof validity is enforced in librustzcash_sprout_verify() - let mut proof = [0; GROTH_PROOF_SIZE]; - reader.read_exact(&mut proof)?; - SproutProof::Groth(proof) - } - false => { - // Consensus rules (§4.3): - // - Canonical encoding is enforced by PHGRProof in zcashd - // - Proof validity is enforced by JSDescription::Verify() in zcashd - let mut proof = [0; PHGR_PROOF_SIZE]; - reader.read_exact(&mut proof)?; - SproutProof::PHGR(proof) - } - }; - - let mut ciphertexts = [[0; 601]; ZC_NUM_JS_OUTPUTS]; - ciphertexts - .iter_mut() - .map(|ct| reader.read_exact(ct)) - .collect::>()?; - - Ok(JSDescription { - vpub_old, - vpub_new, - anchor, - nullifiers, - commitments, - ephemeral_key, - random_seed, - macs, - proof, - ciphertexts, - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_i64::(self.vpub_old.0)?; - writer.write_i64::(self.vpub_new.0)?; - writer.write_all(&self.anchor)?; - writer.write_all(&self.nullifiers[0])?; - writer.write_all(&self.nullifiers[1])?; - writer.write_all(&self.commitments[0])?; - writer.write_all(&self.commitments[1])?; - writer.write_all(&self.ephemeral_key)?; - writer.write_all(&self.random_seed)?; - writer.write_all(&self.macs[0])?; - writer.write_all(&self.macs[1])?; - - match &self.proof { - SproutProof::Groth(p) => writer.write_all(p)?, - SproutProof::PHGR(p) => writer.write_all(p)?, - } - - writer.write_all(&self.ciphertexts[0])?; - writer.write_all(&self.ciphertexts[1]) - } -} - -#[cfg(test)] -mod tests { - use super::{Amount, MAX_MONEY}; - - #[test] - fn amount_in_range() { - let zero = b"\x00\x00\x00\x00\x00\x00\x00\x00"; - assert_eq!(Amount::read_u64(&zero[..]).unwrap(), Amount(0)); - assert_eq!(Amount::read_i64(&zero[..], false).unwrap(), Amount(0)); - assert_eq!(Amount::read_i64(&zero[..], true).unwrap(), Amount(0)); - - let neg_one = b"\xff\xff\xff\xff\xff\xff\xff\xff"; - assert!(Amount::read_u64(&neg_one[..]).is_err()); - assert!(Amount::read_i64(&neg_one[..], false).is_err()); - assert_eq!(Amount::read_i64(&neg_one[..], true).unwrap(), Amount(-1)); - - let max_money = b"\x00\x40\x07\x5a\xf0\x75\x07\x00"; - assert_eq!(Amount::read_u64(&max_money[..]).unwrap(), Amount(MAX_MONEY)); - assert_eq!( - Amount::read_i64(&max_money[..], false).unwrap(), - Amount(MAX_MONEY) - ); - assert_eq!( - Amount::read_i64(&max_money[..], true).unwrap(), - Amount(MAX_MONEY) - ); - - let max_money_p1 = b"\x01\x40\x07\x5a\xf0\x75\x07\x00"; - assert!(Amount::read_u64(&max_money_p1[..]).is_err()); - assert!(Amount::read_i64(&max_money_p1[..], false).is_err()); - assert!(Amount::read_i64(&max_money_p1[..], true).is_err()); - - let neg_max_money = b"\x00\xc0\xf8\xa5\x0f\x8a\xf8\xff"; - assert!(Amount::read_u64(&neg_max_money[..]).is_err()); - assert!(Amount::read_i64(&neg_max_money[..], false).is_err()); - assert_eq!( - Amount::read_i64(&neg_max_money[..], true).unwrap(), - Amount(-MAX_MONEY) - ); - - let neg_max_money_m1 = b"\xff\xbf\xf8\xa5\x0f\x8a\xf8\xff"; - assert!(Amount::read_u64(&neg_max_money_m1[..]).is_err()); - assert!(Amount::read_i64(&neg_max_money_m1[..], false).is_err()); - assert!(Amount::read_i64(&neg_max_money_m1[..], true).is_err()); - } -} diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs deleted file mode 100644 index 787c01d..0000000 --- a/zcash_primitives/src/transaction/mod.rs +++ /dev/null @@ -1,257 +0,0 @@ -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use sapling_crypto::redjubjub::Signature; -use std::io::{self, Read, Write}; -use std::ops::Deref; - -use serialize::Vector; - -pub mod components; -mod sighash; - -#[cfg(test)] -mod tests; - -pub use self::sighash::{signature_hash, signature_hash_data, SIGHASH_ALL}; - -use self::components::{Amount, JSDescription, OutputDescription, SpendDescription, TxIn, TxOut}; - -const OVERWINTER_VERSION_GROUP_ID: u32 = 0x03C48270; -const OVERWINTER_TX_VERSION: u32 = 3; -const SAPLING_VERSION_GROUP_ID: u32 = 0x892F2085; -const SAPLING_TX_VERSION: u32 = 4; - -/// A Zcash transaction. -pub struct Transaction(TransactionData); - -impl Deref for Transaction { - type Target = TransactionData; - - fn deref(&self) -> &TransactionData { - &self.0 - } -} - -pub struct TransactionData { - pub overwintered: bool, - pub version: u32, - pub version_group_id: u32, - pub vin: Vec, - pub vout: Vec, - pub lock_time: u32, - pub expiry_height: u32, - pub value_balance: Amount, - pub shielded_spends: Vec, - pub shielded_outputs: Vec, - pub joinsplits: Vec, - pub joinsplit_pubkey: Option<[u8; 32]>, - pub joinsplit_sig: Option<[u8; 64]>, - pub binding_sig: Option, -} - -impl TransactionData { - pub fn new() -> Self { - TransactionData { - overwintered: true, - version: SAPLING_TX_VERSION, - version_group_id: SAPLING_VERSION_GROUP_ID, - vin: vec![], - vout: vec![], - lock_time: 0, - expiry_height: 0, - value_balance: Amount(0), - shielded_spends: vec![], - shielded_outputs: vec![], - joinsplits: vec![], - joinsplit_pubkey: None, - joinsplit_sig: None, - binding_sig: None, - } - } - - fn header(&self) -> u32 { - let mut header = self.version; - if self.overwintered { - header |= 1 << 31; - } - header - } - - pub fn freeze(self) -> Transaction { - Transaction(self) - } -} - -impl Transaction { - pub fn read(mut reader: R) -> io::Result { - let header = reader.read_u32::()?; - let overwintered = (header >> 31) == 1; - let version = header & 0x7FFFFFFF; - - let version_group_id = match overwintered { - true => reader.read_u32::()?, - false => 0, - }; - - let is_overwinter_v3 = overwintered - && version_group_id == OVERWINTER_VERSION_GROUP_ID - && version == OVERWINTER_TX_VERSION; - let is_sapling_v4 = overwintered - && version_group_id == SAPLING_VERSION_GROUP_ID - && version == SAPLING_TX_VERSION; - if overwintered && !(is_overwinter_v3 || is_sapling_v4) { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Unknown transaction format", - )); - } - - let vin = Vector::read(&mut reader, TxIn::read)?; - let vout = Vector::read(&mut reader, TxOut::read)?; - let lock_time = reader.read_u32::()?; - let expiry_height = match is_overwinter_v3 || is_sapling_v4 { - true => reader.read_u32::()?, - false => 0, - }; - - let (value_balance, shielded_spends, shielded_outputs) = if is_sapling_v4 { - let vb = Amount::read_i64(&mut reader, true)?; - let ss = Vector::read(&mut reader, SpendDescription::read)?; - let so = Vector::read(&mut reader, OutputDescription::read)?; - (vb, ss, so) - } else { - (Amount(0), vec![], vec![]) - }; - - let (joinsplits, joinsplit_pubkey, joinsplit_sig) = if version >= 2 { - let jss = Vector::read(&mut reader, |r| { - JSDescription::read(r, overwintered && version >= SAPLING_TX_VERSION) - })?; - let (pubkey, sig) = if !jss.is_empty() { - let mut joinsplit_pubkey = [0; 32]; - let mut joinsplit_sig = [0; 64]; - reader.read_exact(&mut joinsplit_pubkey)?; - reader.read_exact(&mut joinsplit_sig)?; - (Some(joinsplit_pubkey), Some(joinsplit_sig)) - } else { - (None, None) - }; - (jss, pubkey, sig) - } else { - (vec![], None, None) - }; - - let binding_sig = - match is_sapling_v4 && !(shielded_spends.is_empty() && shielded_outputs.is_empty()) { - true => Some(Signature::read(&mut reader)?), - false => None, - }; - - Ok(Transaction(TransactionData { - overwintered, - version, - version_group_id, - vin, - vout, - lock_time, - expiry_height, - value_balance, - shielded_spends, - shielded_outputs, - joinsplits, - joinsplit_pubkey, - joinsplit_sig, - binding_sig, - })) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_u32::(self.header())?; - if self.overwintered { - writer.write_u32::(self.version_group_id)?; - } - - let is_overwinter_v3 = self.overwintered - && self.version_group_id == OVERWINTER_VERSION_GROUP_ID - && self.version == OVERWINTER_TX_VERSION; - let is_sapling_v4 = self.overwintered - && self.version_group_id == SAPLING_VERSION_GROUP_ID - && self.version == SAPLING_TX_VERSION; - if self.overwintered && !(is_overwinter_v3 || is_sapling_v4) { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Unknown transaction format", - )); - } - - Vector::write(&mut writer, &self.vin, |w, e| e.write(w))?; - Vector::write(&mut writer, &self.vout, |w, e| e.write(w))?; - writer.write_u32::(self.lock_time)?; - if is_overwinter_v3 || is_sapling_v4 { - writer.write_u32::(self.expiry_height)?; - } - - if is_sapling_v4 { - writer.write_i64::(self.value_balance.0)?; - Vector::write(&mut writer, &self.shielded_spends, |w, e| e.write(w))?; - Vector::write(&mut writer, &self.shielded_outputs, |w, e| e.write(w))?; - } - - if self.version >= 2 { - Vector::write(&mut writer, &self.joinsplits, |w, e| e.write(w))?; - if !self.joinsplits.is_empty() { - match self.joinsplit_pubkey { - Some(pubkey) => writer.write_all(&pubkey)?, - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Missing JoinSplit pubkey", - )) - } - } - match self.joinsplit_sig { - Some(sig) => writer.write_all(&sig)?, - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Missing JoinSplit signature", - )) - } - } - } - } - - if self.version < 2 || self.joinsplits.is_empty() { - if self.joinsplit_pubkey.is_some() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "JoinSplit pubkey should not be present", - )); - } - if self.joinsplit_sig.is_some() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "JoinSplit signature should not be present", - )); - } - } - - if is_sapling_v4 && !(self.shielded_spends.is_empty() && self.shielded_outputs.is_empty()) { - match self.binding_sig { - Some(sig) => sig.write(&mut writer)?, - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Missing binding signature", - )) - } - } - } else if self.binding_sig.is_some() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "Binding signature should not be present", - )); - } - - Ok(()) - } -} diff --git a/zcash_primitives/src/transaction/sighash.rs b/zcash_primitives/src/transaction/sighash.rs deleted file mode 100644 index e5dcde0..0000000 --- a/zcash_primitives/src/transaction/sighash.rs +++ /dev/null @@ -1,234 +0,0 @@ -use blake2_rfc::blake2b::Blake2b; -use byteorder::{LittleEndian, WriteBytesExt}; -use pairing::{PrimeField, PrimeFieldRepr}; - -use super::{ - components::{Amount, Script, TxOut}, - Transaction, TransactionData, OVERWINTER_VERSION_GROUP_ID, SAPLING_TX_VERSION, - SAPLING_VERSION_GROUP_ID, -}; - -const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &'static [u8; 12] = b"ZcashSigHash"; -const ZCASH_PREVOUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashPrevoutHash"; -const ZCASH_SEQUENCE_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSequencHash"; -const ZCASH_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashOutputsHash"; -const ZCASH_JOINSPLITS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashJSplitsHash"; -const ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSSpendsHash"; -const ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSOutputHash"; - -pub const SIGHASH_ALL: u32 = 1; -const SIGHASH_NONE: u32 = 2; -const SIGHASH_SINGLE: u32 = 3; -const SIGHASH_MASK: u32 = 0x1f; -const SIGHASH_ANYONECANPAY: u32 = 0x80; - -macro_rules! update_u32 { - ($h:expr, $value:expr, $tmp:expr) => { - (&mut $tmp[..4]).write_u32::($value).unwrap(); - $h.update(&$tmp[..4]); - }; -} - -macro_rules! update_i64 { - ($h:expr, $value:expr, $tmp:expr) => { - (&mut $tmp[..8]).write_i64::($value).unwrap(); - $h.update(&$tmp[..8]); - }; -} - -macro_rules! update_hash { - ($h:expr, $cond:expr, $value:expr) => { - if $cond { - $h.update(&$value); - } else { - $h.update(&[0; 32]); - } - }; -} - -#[derive(PartialEq)] -enum SigHashVersion { - Sprout, - Overwinter, - Sapling, -} - -impl SigHashVersion { - fn from_tx(tx: &TransactionData) -> Self { - if tx.overwintered { - match tx.version_group_id { - OVERWINTER_VERSION_GROUP_ID => SigHashVersion::Overwinter, - SAPLING_VERSION_GROUP_ID => SigHashVersion::Sapling, - _ => unimplemented!(), - } - } else { - SigHashVersion::Sprout - } - } -} - -fn prevout_hash(tx: &TransactionData) -> Vec { - let mut data = Vec::with_capacity(tx.vin.len() * 36); - for t_in in &tx.vin { - t_in.prevout.write(&mut data).unwrap(); - } - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_PREVOUTS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() -} - -fn sequence_hash(tx: &TransactionData) -> Vec { - let mut data = Vec::with_capacity(tx.vin.len() * 4); - for t_in in &tx.vin { - (&mut data) - .write_u32::(t_in.sequence) - .unwrap(); - } - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SEQUENCE_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() -} - -fn outputs_hash(tx: &TransactionData) -> Vec { - let mut data = Vec::with_capacity(tx.vout.len() * (4 + 1)); - for t_out in &tx.vout { - t_out.write(&mut data).unwrap(); - } - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_OUTPUTS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() -} - -fn single_output_hash(tx_out: &TxOut) -> Vec { - let mut data = vec![]; - tx_out.write(&mut data).unwrap(); - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_OUTPUTS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() -} - -fn joinsplits_hash(tx: &TransactionData) -> Vec { - let mut data = Vec::with_capacity( - tx.joinsplits.len() - * if tx.version < SAPLING_TX_VERSION { - 1802 // JSDescription with PHGR13 proof - } else { - 1698 // JSDescription with Groth16 proof - }, - ); - for js in &tx.joinsplits { - js.write(&mut data).unwrap(); - } - data.extend_from_slice(&tx.joinsplit_pubkey.unwrap()); - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_JOINSPLITS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() -} - -fn shielded_spends_hash(tx: &TransactionData) -> Vec { - let mut data = Vec::with_capacity(tx.shielded_spends.len() * 384); - for s_spend in &tx.shielded_spends { - s_spend.cv.write(&mut data).unwrap(); - s_spend.anchor.into_repr().write_le(&mut data).unwrap(); - data.extend_from_slice(&s_spend.nullifier); - s_spend.rk.write(&mut data).unwrap(); - data.extend_from_slice(&s_spend.zkproof); - } - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() -} - -fn shielded_outputs_hash(tx: &TransactionData) -> Vec { - let mut data = Vec::with_capacity(tx.shielded_outputs.len() * 948); - for s_out in &tx.shielded_outputs { - s_out.write(&mut data).unwrap(); - } - let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION); - h.update(&data); - h.finalize().as_ref().to_vec() -} - -pub fn signature_hash_data( - tx: &TransactionData, - consensus_branch_id: u32, - hash_type: u32, - transparent_input: Option<(usize, Script, Amount)>, -) -> Vec { - let sigversion = SigHashVersion::from_tx(tx); - match sigversion { - SigHashVersion::Overwinter | SigHashVersion::Sapling => { - let hash_outputs = if (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE - && (hash_type & SIGHASH_MASK) != SIGHASH_NONE - { - outputs_hash(tx) - } else if (hash_type & SIGHASH_MASK) == SIGHASH_SINGLE - && transparent_input.is_some() - && transparent_input.as_ref().unwrap().0 < tx.vout.len() - { - single_output_hash(&tx.vout[transparent_input.as_ref().unwrap().0]) - } else { - vec![0; 32] - }; - - let mut personal = [0; 16]; - (&mut personal[..12]).copy_from_slice(ZCASH_SIGHASH_PERSONALIZATION_PREFIX); - (&mut personal[12..]) - .write_u32::(consensus_branch_id) - .unwrap(); - - let mut h = Blake2b::with_params(32, &[], &[], &personal); - let mut tmp = [0; 8]; - - update_u32!(h, tx.header(), tmp); - update_u32!(h, tx.version_group_id, tmp); - update_hash!(h, hash_type & SIGHASH_ANYONECANPAY == 0, prevout_hash(tx)); - update_hash!( - h, - hash_type & SIGHASH_ANYONECANPAY == 0 - && (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE - && (hash_type & SIGHASH_MASK) != SIGHASH_NONE, - sequence_hash(tx) - ); - h.update(&hash_outputs); - update_hash!(h, !tx.joinsplits.is_empty(), joinsplits_hash(tx)); - if sigversion == SigHashVersion::Sapling { - update_hash!(h, !tx.shielded_spends.is_empty(), shielded_spends_hash(tx)); - update_hash!( - h, - !tx.shielded_outputs.is_empty(), - shielded_outputs_hash(tx) - ); - } - update_u32!(h, tx.lock_time, tmp); - update_u32!(h, tx.expiry_height, tmp); - if sigversion == SigHashVersion::Sapling { - update_i64!(h, tx.value_balance.0, tmp); - } - update_u32!(h, hash_type, tmp); - - if let Some((n, script_code, amount)) = transparent_input { - let mut data = vec![]; - tx.vin[n].prevout.write(&mut data).unwrap(); - script_code.write(&mut data).unwrap(); - (&mut data).write_i64::(amount.0).unwrap(); - (&mut data) - .write_u32::(tx.vin[n].sequence) - .unwrap(); - h.update(&data); - } - - h.finalize().as_ref().to_vec() - } - SigHashVersion::Sprout => unimplemented!(), - } -} - -pub fn signature_hash( - tx: &Transaction, - consensus_branch_id: u32, - hash_type: u32, - transparent_input: Option<(usize, Script, Amount)>, -) -> Vec { - signature_hash_data(tx, consensus_branch_id, hash_type, transparent_input) -} diff --git a/zcash_primitives/src/transaction/tests.rs b/zcash_primitives/src/transaction/tests.rs deleted file mode 100644 index db3a4df..0000000 --- a/zcash_primitives/src/transaction/tests.rs +++ /dev/null @@ -1,5422 +0,0 @@ -use pairing::bls12_381::Bls12; -use rand::{thread_rng, Rng}; -use sapling_crypto::{jubjub::FixedGenerators, redjubjub::PrivateKey}; - -use super::{ - components::{Amount, Script}, - sighash::signature_hash, - Transaction, TransactionData, -}; -use JUBJUB; - -#[test] -fn tx_read_write() { - // TxID: 64f0bd7fe30ce23753358fe3a2dc835b8fba9c0274c4e2c54a6f73114cb55639 - // From testnet block 280003. - let data = [ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x01, 0x8f, 0x64, 0x29, 0x96, 0xdf, 0x1e, - 0x93, 0xa6, 0xd7, 0x9a, 0xe5, 0xba, 0xae, 0x34, 0x93, 0xf4, 0x23, 0xca, 0x6c, 0x82, 0xe9, - 0x9f, 0x3e, 0x8d, 0x95, 0x24, 0xfa, 0x78, 0xbc, 0xf1, 0x61, 0x67, 0x00, 0x00, 0x00, 0x00, - 0x6b, 0x48, 0x30, 0x45, 0x02, 0x21, 0x00, 0xb6, 0x5e, 0x37, 0x22, 0x97, 0x07, 0xd9, 0xcd, - 0x48, 0x39, 0x40, 0xd2, 0xab, 0x8b, 0xdc, 0x0b, 0x74, 0xb1, 0x2d, 0xda, 0x66, 0xd0, 0x2d, - 0xbd, 0xf3, 0x6f, 0xd3, 0x83, 0xb9, 0x60, 0x2a, 0x51, 0x02, 0x20, 0x4b, 0xe7, 0xfd, 0x7a, - 0x39, 0xa4, 0xa4, 0x2d, 0xff, 0x07, 0x1a, 0x5a, 0x2b, 0xc5, 0x1b, 0x49, 0x2d, 0x33, 0xf0, - 0xbc, 0x39, 0x4b, 0xc8, 0x78, 0x61, 0xe1, 0xbc, 0xaa, 0xf2, 0xba, 0xc9, 0x3b, 0x01, 0x21, - 0x02, 0x48, 0xe7, 0x8b, 0xdc, 0x18, 0xf1, 0xa8, 0x31, 0x10, 0xc1, 0x2e, 0x40, 0x08, 0xb7, - 0x64, 0x02, 0x69, 0x61, 0xb1, 0x68, 0xfe, 0x8d, 0x5a, 0x8d, 0x94, 0x7e, 0xfe, 0x6a, 0xf8, - 0x3c, 0xc8, 0x8e, 0xff, 0xff, 0xff, 0xff, 0x01, 0xf0, 0xf2, 0x70, 0x18, 0x02, 0x00, 0x00, - 0x00, 0x19, 0x76, 0xa9, 0x14, 0xa2, 0x84, 0xd0, 0x51, 0x1d, 0x0e, 0x52, 0x0d, 0x36, 0xf4, - 0x44, 0xa3, 0x6c, 0x10, 0xbf, 0x54, 0xb4, 0xb0, 0x17, 0xcd, 0x88, 0xac, 0x00, 0x00, 0x00, - 0x00, 0xd7, 0x45, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0xca, 0x9a, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x13, 0x31, 0xa3, 0x05, 0x9e, 0x66, 0xaa, 0x6c, 0xa9, 0x7a, 0x62, 0xf5, 0x6e, - 0xa2, 0x34, 0x20, 0x75, 0x68, 0x56, 0x6f, 0x69, 0x71, 0xb3, 0x72, 0x2a, 0xe0, 0xdd, 0x82, - 0xc0, 0x03, 0x99, 0x69, 0x2a, 0xac, 0xb5, 0xfb, 0x12, 0xac, 0x58, 0x0a, 0xc2, 0x66, 0x24, - 0xa8, 0xcf, 0x0a, 0x90, 0x4c, 0xd6, 0xf4, 0xbf, 0xea, 0x55, 0x62, 0x52, 0x05, 0xcb, 0x58, - 0xf0, 0x6b, 0x1c, 0x19, 0x74, 0x23, 0x28, 0x0d, 0xea, 0xc7, 0x4e, 0xea, 0x97, 0x59, 0x8c, - 0x43, 0x14, 0xd8, 0x99, 0xa4, 0xfd, 0x85, 0x31, 0x1e, 0x04, 0x62, 0x57, 0xd2, 0xd4, 0xc2, - 0x97, 0xf1, 0x40, 0x6c, 0xf7, 0x09, 0xd9, 0x2a, 0x86, 0x07, 0xf7, 0x69, 0x8d, 0x45, 0xfe, - 0x9f, 0x41, 0xde, 0xa3, 0xa0, 0x57, 0x1c, 0x5d, 0xa5, 0xcf, 0xa7, 0x8e, 0x18, 0xeb, 0xf5, - 0x80, 0xc3, 0x61, 0x79, 0xd9, 0xd6, 0xe6, 0x32, 0x0a, 0x34, 0x8f, 0x14, 0x6c, 0x40, 0x7a, - 0xda, 0xb4, 0xcb, 0x31, 0x03, 0x92, 0xa5, 0xf5, 0xb5, 0xab, 0x28, 0x3b, 0x78, 0x34, 0x3b, - 0xa9, 0x1a, 0xbc, 0x7c, 0x4b, 0xfe, 0x23, 0xa3, 0xdb, 0xaf, 0x80, 0x37, 0xc6, 0x76, 0xe5, - 0x95, 0xa2, 0x65, 0x74, 0xb1, 0x81, 0x3b, 0xc2, 0xbf, 0x2d, 0x2e, 0x91, 0x1f, 0x6f, 0x3a, - 0xbb, 0x0b, 0xa6, 0xbc, 0xac, 0x7a, 0x29, 0x01, 0xfb, 0xdc, 0xe6, 0x5f, 0xb0, 0x7b, 0x56, - 0x36, 0x01, 0x7e, 0xf1, 0x4d, 0xff, 0x44, 0xcd, 0xee, 0xa7, 0x30, 0x47, 0x72, 0x94, 0xf2, - 0xf8, 0x61, 0x9b, 0xd3, 0xd5, 0xe6, 0xbe, 0x48, 0x98, 0xbf, 0x8d, 0x39, 0xc0, 0xe0, 0xea, - 0xe5, 0xa3, 0x68, 0x64, 0x62, 0x52, 0x06, 0xb9, 0xa8, 0xf9, 0x94, 0x0b, 0xf1, 0x66, 0x50, - 0xde, 0xf7, 0x92, 0x6e, 0xb0, 0xdb, 0x43, 0xb7, 0xd7, 0x61, 0x5e, 0x47, 0x74, 0xcf, 0x10, - 0x94, 0x82, 0xf2, 0xe8, 0x07, 0xfe, 0xe6, 0xc0, 0xc8, 0x84, 0xe8, 0x31, 0x4c, 0x67, 0xc5, - 0xd8, 0x5f, 0x4c, 0x22, 0x9c, 0xde, 0xab, 0x1e, 0x96, 0x4c, 0xf0, 0xc1, 0xad, 0xcb, 0x47, - 0xce, 0xbf, 0xc7, 0xc0, 0x67, 0xa0, 0xf3, 0xc8, 0x06, 0x81, 0x4a, 0x28, 0x5e, 0xdb, 0xb6, - 0x24, 0xf4, 0x71, 0x06, 0x29, 0x09, 0x89, 0x44, 0xac, 0x75, 0xe7, 0xc9, 0xcb, 0xc5, 0x6b, - 0xd0, 0xa0, 0x29, 0xe1, 0x11, 0x0e, 0xac, 0x60, 0xcb, 0x40, 0x77, 0xeb, 0xf1, 0x08, 0xfe, - 0x3e, 0x67, 0xcd, 0x06, 0x13, 0x91, 0xe5, 0xd6, 0x91, 0x6d, 0x5f, 0x41, 0xc0, 0x2b, 0x89, - 0x14, 0xc1, 0x2c, 0xf6, 0x05, 0xdb, 0x7d, 0x95, 0x92, 0x26, 0xe2, 0xe8, 0xff, 0x71, 0x26, - 0x3b, 0x9a, 0xf4, 0xc5, 0x9b, 0x0f, 0x4d, 0xb3, 0x15, 0xb7, 0x4c, 0xa2, 0xb0, 0xb7, 0xd2, - 0x52, 0x13, 0xd5, 0x29, 0x39, 0x54, 0xc3, 0xe5, 0x11, 0x72, 0x37, 0x0f, 0xb6, 0xc3, 0x5a, - 0xbe, 0x9c, 0xe3, 0x6e, 0xf2, 0x53, 0xe3, 0xa7, 0x2e, 0x19, 0xda, 0xc9, 0xbd, 0x73, 0x62, - 0xc4, 0x49, 0x92, 0x97, 0x42, 0x15, 0xc8, 0x2c, 0xb9, 0x0c, 0x99, 0x48, 0x8d, 0xbd, 0xe1, - 0x19, 0x63, 0xe8, 0x57, 0xce, 0xa6, 0xb8, 0x1b, 0x8e, 0xaa, 0xe3, 0x4b, 0x7c, 0xf5, 0xa9, - 0x7d, 0x6b, 0x60, 0xd4, 0x9f, 0xdf, 0xa2, 0x0f, 0x5f, 0x3c, 0x12, 0x0e, 0xf3, 0x82, 0xca, - 0x24, 0x69, 0x60, 0x4f, 0xb0, 0xc6, 0x84, 0x2c, 0x6d, 0x4f, 0xae, 0x96, 0x61, 0x66, 0x5b, - 0x5c, 0xbc, 0x61, 0x2c, 0xef, 0x13, 0x2f, 0x88, 0xfb, 0x7d, 0xa3, 0x93, 0xf3, 0x56, 0xe3, - 0xad, 0x13, 0xfc, 0x35, 0x57, 0x98, 0x0a, 0x77, 0x34, 0x23, 0x14, 0x53, 0xe4, 0x40, 0x79, - 0x04, 0x2f, 0xb4, 0x32, 0xf5, 0x5e, 0x75, 0x14, 0x84, 0xd5, 0xd6, 0xd3, 0x0f, 0xbc, 0x4f, - 0x99, 0x90, 0x13, 0xd5, 0xd4, 0xf2, 0xfb, 0x62, 0xf7, 0x14, 0x4e, 0x8d, 0xcd, 0x2a, 0xe5, - 0x95, 0x46, 0xcc, 0x43, 0x79, 0xad, 0x9f, 0x18, 0x59, 0xef, 0x80, 0xde, 0xc6, 0x6b, 0x1a, - 0x9b, 0x0b, 0x7f, 0xd2, 0xc4, 0x7b, 0xd3, 0x83, 0x02, 0xd2, 0x9c, 0x31, 0x99, 0x03, 0x29, - 0xa8, 0x95, 0x87, 0x6e, 0xd1, 0xd8, 0x4d, 0xb7, 0x57, 0x85, 0x6e, 0x75, 0xce, 0x9a, 0x1d, - 0xc7, 0xc7, 0x47, 0x2b, 0xc2, 0x18, 0xfb, 0x8d, 0x7c, 0x7d, 0x02, 0x8b, 0xb0, 0x2f, 0x10, - 0xef, 0xe7, 0xfe, 0x6a, 0x8c, 0x9c, 0xe0, 0x34, 0xfe, 0xa6, 0x6b, 0x90, 0x9c, 0x8d, 0x41, - 0x26, 0x25, 0x1c, 0x7d, 0x6e, 0x54, 0xf4, 0xcf, 0xc7, 0x78, 0xcd, 0x4f, 0x0e, 0x0b, 0xad, - 0x10, 0x96, 0x17, 0x6f, 0x2d, 0xd4, 0x5c, 0x45, 0xcb, 0xe1, 0x5e, 0x11, 0x8f, 0x90, 0xff, - 0x25, 0x45, 0xf8, 0x32, 0xf2, 0x36, 0x98, 0xf2, 0xc9, 0x53, 0x1b, 0x52, 0x65, 0x5a, 0x4c, - 0x0c, 0x89, 0x53, 0x55, 0x99, 0x28, 0xee, 0xdf, 0xc7, 0x56, 0xc3, 0x65, 0xcf, 0x92, 0x9b, - 0x84, 0x47, 0xdc, 0xdc, 0x7d, 0x82, 0x38, 0x49, 0xe0, 0x2f, 0xf6, 0x8b, 0x62, 0x78, 0xd7, - 0x54, 0x2c, 0xe0, 0xf1, 0x07, 0x0b, 0xb1, 0xad, 0x91, 0x3c, 0x1a, 0x35, 0x36, 0x25, 0xf5, - 0xd3, 0x5b, 0x14, 0xcf, 0xec, 0x84, 0xa6, 0x33, 0xd7, 0xfe, 0x25, 0x25, 0x6d, 0xcf, 0xfe, - 0x92, 0xf9, 0xa6, 0xf0, 0xfe, 0x00, 0xca, 0xaa, 0xa5, 0xb3, 0x9c, 0xc2, 0xab, 0x06, 0x76, - 0x8a, 0x42, 0xa5, 0xb4, 0x00, 0x83, 0xce, 0xa0, 0x1c, 0x96, 0xb3, 0xe6, 0x8d, 0x0f, 0x6a, - 0x58, 0x7e, 0xaf, 0x2d, 0xa6, 0xfd, 0xad, 0xc8, 0x25, 0x27, 0xf1, 0x86, 0xa6, 0x04, 0x71, - 0xce, 0x98, 0xe2, 0x7d, 0x2b, 0x11, 0xef, 0xc4, 0x79, 0x98, 0xf3, 0x03, 0x0a, 0x7a, 0x2e, - 0x5d, 0x0b, 0x0a, 0x7e, 0xb8, 0x0f, 0x6b, 0xd0, 0xe4, 0xb9, 0xc8, 0x36, 0x7c, 0x6c, 0x52, - 0x2d, 0x94, 0x15, 0xf8, 0xca, 0xec, 0x7b, 0x0a, 0x73, 0x18, 0xd5, 0x3d, 0xce, 0x39, 0x1c, - 0xf7, 0xe7, 0x38, 0x9c, 0x9a, 0x74, 0xaa, 0x6a, 0x4c, 0x21, 0x7c, 0x28, 0x85, 0x19, 0xaf, - 0x81, 0xba, 0x21, 0x22, 0xca, 0x0c, 0x58, 0x40, 0xcc, 0x02, 0xcf, 0x1b, 0xcf, 0x15, 0x0c, - 0xd3, 0xdf, 0x33, 0xc0, 0xac, 0xfd, 0x00, 0x53, 0xe6, 0x68, 0xb9, 0x26, 0x56, 0x1b, 0x92, - 0x40, 0x98, 0xd9, 0x7a, 0xaa, 0xb5, 0x7e, 0xe1, 0x11, 0x3d, 0xf9, 0x66, 0xa4, 0x22, 0xef, - 0x9b, 0x01, 0x46, 0x17, 0xbc, 0xee, 0xf0, 0x5f, 0xb6, 0x46, 0x8e, 0x33, 0x0e, 0x2d, 0xec, - 0xe3, 0xf3, 0x75, 0xe9, 0x8e, 0xf0, 0x3e, 0x5b, 0x18, 0xa9, 0x53, 0xe2, 0x30, 0x1f, 0xcc, - 0xec, 0x86, 0x20, 0x0a, 0xe4, 0x32, 0xc9, 0xc1, 0x2c, 0x30, 0x77, 0x54, 0x37, 0xf3, 0x62, - 0x97, 0x14, 0xa9, 0xfa, 0xbe, 0xb5, 0x32, 0x89, 0x40, 0x2b, 0x7f, 0xd3, 0x86, 0xce, 0xf2, - 0xb1, 0x14, 0x67, 0x23, 0xa8, 0x9d, 0x0f, 0x81, 0x65, 0x1e, 0x00, 0xca, 0xea, 0x2f, 0x3a, - 0xc9, 0xee, 0xfe, 0xfb, 0x86, 0x8d, 0x85, 0xed, 0x23, 0x54, 0xf5, 0x30, 0xfe, 0x38, 0xfe, - 0x3a, 0x3a, 0x6a, 0xab, 0x47, 0xd4, 0x2d, 0xc2, 0x13, 0x29, 0xe3, 0xad, 0x1b, 0x9d, 0x06, - 0xc0, 0xc8, 0xd6, 0x53, 0x74, 0x56, 0xf5, 0x4a, 0xd0, 0x45, 0x3f, 0x44, 0x41, 0x75, 0xd8, - 0x7e, 0xf5, 0xcd, 0xd1, 0x69, 0x46, 0x62, 0xe0, 0xa1, 0xe6, 0xe3, 0x63, 0x2e, 0xd7, 0xa8, - 0xe7, 0x6b, 0xc7, 0xb1, 0xb5, 0xa4, 0x18, 0xf0, 0x86, 0xd3, 0x40, 0x81, 0x5e, 0xc3, 0x98, - 0xf0, 0x92, 0xe9, 0x78, 0x69, 0xf5, 0xe2, 0x01, 0xc2, 0x2c, 0x87, 0x91, 0x8f, 0x76, 0x6a, - 0x35, 0x32, 0xeb, 0x9a, 0x4f, 0xc9, 0xac, 0xf1, 0x96, 0xcb, 0xc2, 0xd0, 0x28, 0x51, 0x19, - 0xa4, 0x21, 0x6d, 0x25, 0x81, 0xcd, 0x2d, 0x91, 0xbc, 0xdc, 0xe8, 0x68, 0xc4, 0x68, 0xf6, - 0xf3, 0x4c, 0xf4, 0x9e, 0x3a, 0x56, 0xce, 0x24, 0x9a, 0x2f, 0xd8, 0xcf, 0x36, 0xb0, 0x1b, - 0x0f, 0x77, 0xde, 0x72, 0x2b, 0xbc, 0xe2, 0x67, 0xe3, 0xe5, 0x52, 0x16, 0x88, 0xe6, 0x52, - 0x22, 0x23, 0x5c, 0x91, 0xc2, 0x63, 0xd8, 0x0e, 0x28, 0x29, 0x7e, 0x92, 0x9d, 0x88, 0x5b, - 0x7b, 0x9c, 0x1a, 0x16, 0x54, 0xb2, 0xd0, 0xb8, 0x75, 0x77, 0xc9, 0xa1, 0xc7, 0x25, 0xf5, - 0x44, 0x15, 0xdc, 0x5f, 0x52, 0xdd, 0xe0, 0x69, 0x5f, 0x9f, 0x6d, 0xcb, 0x4b, 0x6e, 0xe3, - 0xe3, 0xea, 0x70, 0x29, 0x04, 0xc1, 0x1f, 0xf9, 0x2f, 0x55, 0x53, 0x4c, 0x7e, 0xf9, 0x8c, - 0xe7, 0x93, 0xd7, 0x47, 0x56, 0xa4, 0x5d, 0x4e, 0x32, 0x0a, 0x42, 0x5e, 0x98, 0x2d, 0x5b, - 0x37, 0x2d, 0x6a, 0x8d, 0x41, 0xfb, 0x86, 0xba, 0x51, 0x64, 0x81, 0x68, 0x32, 0xa4, 0x81, - 0x82, 0x5c, 0x8c, 0x6a, 0xd7, 0x27, 0x09, 0x69, 0x85, 0x9e, 0x55, 0xd2, 0x36, 0x75, 0x35, - 0x06, 0x0f, 0x99, 0x85, 0x70, 0x65, 0x17, 0x04, 0x66, 0xbd, 0xb7, 0x0c, 0xb9, 0x3a, 0xb2, - 0xf9, 0xc0, 0xe2, 0x93, 0xa0, 0xa9, 0x19, 0x84, 0x3b, 0xbf, 0x34, 0xc2, 0xfe, 0x61, 0xb0, - 0xc3, 0xe3, 0x2a, 0xa7, 0x07, 0x8e, 0x83, 0xd4, 0xc1, 0x92, 0x9e, 0x1e, 0x1d, 0x86, 0x14, - 0x1c, 0xde, 0xb1, 0x89, 0x20, 0x91, 0x09, 0x75, 0xdb, 0x3a, 0x76, 0x26, 0x82, 0x05, 0x99, - 0x63, 0x0c, 0x42, 0x3a, 0xde, 0x23, 0x3d, 0x5d, 0x60, 0x68, 0x55, 0x24, 0xe8, 0xd8, 0x03, - 0x2b, 0x86, 0x1b, 0x4a, 0xad, 0x20, 0x02, 0xa8, 0xfd, 0x17, 0xc9, 0x28, 0x2b, 0x82, 0x5f, - 0x02, 0xd3, 0x53, 0xe2, 0x91, 0x37, 0x9c, 0xed, 0x00, 0xeb, 0xaa, 0x3c, 0x03, 0xe0, 0x1d, - 0x9c, 0x59, 0xf4, 0x05, 0x09, 0x9d, 0x1c, 0x34, 0x32, 0xba, 0xd0, 0x63, 0x58, 0xd6, 0xb1, - 0x94, 0x2f, 0x0b, 0xaf, 0x71, 0x09, 0x98, 0xd1, 0x0a, 0x22, 0xd1, 0x55, 0xb0, 0xfe, 0x84, - 0x99, 0x52, 0x89, 0x31, 0x26, 0x94, 0x9f, 0xf9, 0x2d, 0xe3, 0xa4, 0xc2, 0xee, 0xaf, 0xdf, - 0x68, 0x84, 0x35, 0xe3, 0x25, 0xd8, 0x1c, 0x2c, 0xe0, 0x08, 0xcf, 0x6c, 0x76, 0x03, 0x0d, - 0x4d, 0x46, 0x34, 0x2a, 0xc3, 0x37, 0x2c, 0x73, 0x98, 0x65, 0x60, 0xc4, 0xec, 0x35, 0xa6, - 0xf6, 0x49, 0xef, 0x02, 0xc1, 0x19, 0x36, 0xb7, 0x03, 0x9b, 0xc6, 0xf5, 0xd0, 0x94, 0x38, - 0xdb, 0xe4, 0x76, 0x25, 0x1b, 0x59, 0x64, 0xb6, 0x8f, 0x02, 0xee, 0xdf, 0xf7, 0xa9, 0xe0, - 0xed, 0x3e, 0x30, 0x90, 0x96, 0x5a, 0x22, 0xf2, 0xc5, 0x52, 0xce, 0x3b, 0x2b, 0x47, 0x4f, - 0xd2, 0xfc, 0x06, 0xb5, 0x09, 0x27, 0x83, 0x0a, 0x05, 0xa3, 0x03, 0xfa, 0xff, 0xd6, 0x84, - 0x82, 0xd7, 0xb7, 0x85, 0x38, 0x43, 0x25, 0x40, 0xdd, 0x32, 0x61, 0xab, 0x75, 0x9b, 0x65, - 0x82, 0x12, 0x9a, 0x7f, 0x18, 0xd8, 0x01, 0xc5, 0x43, 0x19, 0xca, 0x52, 0xa3, 0xc6, 0xa3, - 0xdb, 0x63, 0x50, 0x44, 0xd6, 0x25, 0xe2, 0x40, 0x38, 0xad, 0x42, 0x77, 0xf8, 0xd5, 0xbf, - 0x01, 0x60, 0x35, 0x16, 0x5f, 0x21, 0xb0, 0x70, 0xe8, 0x16, 0x9d, 0x65, 0x7d, 0x6e, 0xd1, - 0xfa, 0x7f, 0x8e, 0xd0, 0x9b, 0x4e, 0x1d, 0x9c, 0xa2, 0xe5, 0x1a, 0x24, 0xda, 0x55, 0xe4, - 0x3b, 0x3f, 0xca, 0x98, 0x59, 0xb2, 0x40, 0x8c, 0x26, 0xaa, 0xcb, 0xad, 0x74, 0x9e, 0xbe, - 0x88, 0x2c, 0x31, 0xe7, 0x20, 0x5e, 0x63, 0x8b, 0xb7, 0xe2, 0xbf, 0xc8, 0xa3, 0xf1, 0xc0, - 0x2c, 0x0c, 0xa7, 0xbb, 0x9d, 0xaa, 0xab, 0x7f, 0xcb, 0xf8, 0x45, 0xd8, 0x00, 0x2c, 0x3d, - 0xe7, 0x99, 0x24, 0xdc, 0xaa, 0xdc, 0x24, 0xbd, 0xc0, 0x08, 0x2f, 0x4a, 0x6b, 0x61, 0x87, - 0x6f, 0x31, 0x92, 0xa8, 0x81, 0xf5, 0x9a, 0x68, 0x2d, 0x27, 0x36, 0x85, 0xd4, 0x79, 0x5c, - 0x9b, 0xd7, 0xcc, 0xcf, 0x49, 0xde, 0x34, 0x44, 0x3a, 0x9f, 0x9c, 0xb3, 0x5b, 0xbf, 0x25, - 0x4c, 0x50, 0x61, 0x1b, 0x7c, 0x13, 0x24, 0xb1, 0x10, 0x94, 0x66, 0x7b, 0x6b, 0x60, 0x8c, - 0x39, 0xd1, 0x25, 0x2c, 0xeb, 0xcc, 0x48, 0x77, 0xce, 0xea, 0x76, 0xe1, 0x9b, 0x84, 0x2b, - 0x67, 0xf6, 0x26, 0x74, 0x3f, 0xab, 0x29, 0x77, 0x76, 0xcc, 0x9c, 0xf7, 0x9e, 0x90, 0xe8, - 0xfc, 0xe1, 0x00, 0x17, 0x90, 0xc2, 0xe7, 0xd5, 0xc9, 0x58, 0x64, 0x7c, 0xca, 0x5d, 0x33, - 0x97, 0xd2, 0x0a, 0xfc, 0xf2, 0x9b, 0xa4, 0x4f, 0x62, 0xa7, 0xc6, 0x2e, 0x90, 0x8d, 0x84, - 0x8d, 0x81, 0xa7, 0x9f, 0xad, 0xbb, 0x37, 0x0a, 0xba, 0x93, 0xb0, 0x3e, 0x41, 0xd4, 0xbc, - 0x49, 0xe2, 0x99, 0xd6, 0xd3, 0x3f, 0xaf, 0x86, 0x9f, 0x36, 0x37, 0x14, 0x14, 0xce, 0x64, - 0x6f, 0xc2, 0xca, 0x6d, 0xcf, 0xf5, 0x5a, 0x6e, 0x06, 0x39, 0xd5, 0x0c, 0xae, 0xb1, 0x14, - 0xc4, 0x18, 0xc6, 0x26, 0xb8, 0x67, 0x15, 0x43, 0x64, 0x81, 0xd1, 0x92, 0x8d, 0x55, 0xa7, - 0x56, 0xa6, 0x03, 0xe7, 0x11, 0x0c, 0x3a, 0xfe, 0x96, 0x3c, 0x2b, 0x29, 0xa4, 0x78, 0xf9, - 0xd4, 0x39, 0x7b, 0x88, 0x5a, 0x67, 0xb0, 0x93, 0xa3, 0x45, 0x79, 0x62, 0x19, 0xc1, 0x11, - 0xb7, 0xe9, 0x4d, 0xb3, 0x90, 0xaa, 0x4b, 0xb7, 0x6b, 0x66, 0xa5, 0x34, 0xe5, 0xe2, 0x67, - 0x9b, 0x27, 0xdb, 0x5f, 0x95, 0xfd, 0x09, 0xa3, 0x6b, 0x05, - ]; - let tx = Transaction::read(&data[..]).unwrap(); - - let mut encoded = Vec::with_capacity(data.len()); - tx.write(&mut encoded).unwrap(); - assert_eq!(&data[..], &encoded[..]); -} - -#[test] -fn tx_write_rejects_unexpected_joinsplit_pubkey() { - // Succeeds without a JoinSplit pubkey - { - let tx = TransactionData::new().freeze(); - let mut encoded = Vec::new(); - assert!(tx.write(&mut encoded).is_ok()); - } - - // Fails with an unexpected JoinSplit pubkey - { - let mut tx = TransactionData::new(); - tx.joinsplit_pubkey = Some([0; 32]); - let tx = tx.freeze(); - - let mut encoded = Vec::new(); - assert!(tx.write(&mut encoded).is_err()); - } -} - -#[test] -fn tx_write_rejects_unexpected_joinsplit_sig() { - // Succeeds without a JoinSplit signature - { - let tx = TransactionData::new().freeze(); - let mut encoded = Vec::new(); - assert!(tx.write(&mut encoded).is_ok()); - } - - // Fails with an unexpected JoinSplit signature - { - let mut tx = TransactionData::new(); - tx.joinsplit_sig = Some([0; 64]); - let tx = tx.freeze(); - - let mut encoded = Vec::new(); - assert!(tx.write(&mut encoded).is_err()); - } -} - -#[test] -fn tx_write_rejects_unexpected_binding_sig() { - // Succeeds without a binding signature - { - let tx = TransactionData::new().freeze(); - let mut encoded = Vec::new(); - assert!(tx.write(&mut encoded).is_ok()); - } - - // Fails with an unexpected binding signature - { - let rng = &mut thread_rng(); - let sk = PrivateKey::(rng.gen()); - let sig = sk.sign( - b"Foo bar", - rng, - FixedGenerators::SpendingKeyGenerator, - &JUBJUB, - ); - - let mut tx = TransactionData::new(); - tx.binding_sig = Some(sig); - let tx = tx.freeze(); - - let mut encoded = Vec::new(); - assert!(tx.write(&mut encoded).is_err()); - } -} - -#[test] -fn zip_0143() { - struct TestVector { - tx: Vec, - script_code: Vec, - transparent_input: Option, - hash_type: u32, - amount: i64, - consensus_branch_id: u32, - sighash: [u8; 32], - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0143.py - let test_vectors = vec![ - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x00, 0x02, 0xe7, 0x71, 0x98, 0x11, - 0x89, 0x3e, 0x00, 0x00, 0x09, 0x52, 0x00, 0xac, 0x65, 0x51, 0xac, 0x63, 0x65, 0x65, - 0xb2, 0x83, 0x5a, 0x08, 0x05, 0x75, 0x02, 0x00, 0x02, 0x51, 0x51, 0x48, 0x1c, 0xdd, - 0x86, 0xb3, 0xcc, 0x43, 0x18, 0x00, - ], - script_code: vec![0x6a, 0x00, 0x00, 0x00, 0x63, 0xac, 0x53], - transparent_input: None, - hash_type: 1, - amount: 1672704339313879, - consensus_branch_id: 1537743641, - sighash: [ - 0xa1, 0xf1, 0xa4, 0xe5, 0xcd, 0x9b, 0xd5, 0x22, 0x32, 0x2d, 0x66, 0x1e, 0xdd, 0x2a, - 0xf1, 0xbf, 0x2a, 0x70, 0x19, 0xcf, 0xab, 0x94, 0xec, 0xe1, 0x8f, 0x4b, 0xa9, 0x35, - 0xb0, 0xa1, 0x90, 0x73, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x42, 0x01, 0xcf, 0xb1, 0xcd, - 0x8d, 0xbf, 0x69, 0xb8, 0x25, 0x0c, 0x18, 0xef, 0x41, 0x29, 0x4c, 0xa9, 0x79, 0x93, - 0xdb, 0x54, 0x6c, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, 0xa5, 0xe2, 0x9d, - 0x4e, 0x30, 0xa7, 0x03, 0xac, 0x6a, 0x00, 0x98, 0x42, 0x1c, 0x69, 0x37, 0x8a, 0xf1, - 0xe4, 0x0f, 0x64, 0xe1, 0x25, 0x94, 0x6f, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, - 0xb6, 0x4b, 0x69, 0x68, 0x91, 0x2a, 0x63, 0x81, 0xce, 0x3d, 0xc1, 0x66, 0xd5, 0x6a, - 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x05, 0x63, 0x63, 0x63, 0x53, 0x53, 0xe8, 0xc7, 0x20, - 0x3d, 0x02, 0xd2, 0xda, 0x86, 0x38, 0x7a, 0xe6, 0x01, 0x00, 0x08, 0x00, 0x63, 0x65, - 0x6a, 0x63, 0xac, 0x52, 0x00, 0xa7, 0x62, 0x29, 0x97, 0xf4, 0xff, 0x04, 0x00, 0x07, - 0x51, 0x51, 0x00, 0x53, 0x53, 0x65, 0x65, 0x97, 0xb0, 0xe4, 0xe4, 0xc7, 0x05, 0xfc, - 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x76, 0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, - 0xfa, 0x3d, 0x5a, 0x57, 0xef, 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, - 0xfb, 0x1a, 0x38, 0xe0, 0x1d, 0x94, 0x90, 0x3d, 0x3c, 0x3e, 0x0a, 0xd3, 0x36, 0x0c, - 0x1d, 0x37, 0x10, 0xac, 0xd2, 0x0b, 0x18, 0x3e, 0x31, 0xd4, 0x9f, 0x25, 0xc9, 0xa1, - 0x38, 0xf4, 0x9b, 0x1a, 0x53, 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x51, 0xa7, - 0xaf, 0x9d, 0xb6, 0x99, 0x0e, 0xd8, 0x3d, 0xd6, 0x4a, 0xf3, 0x59, 0x7c, 0x04, 0x32, - 0x3e, 0xa5, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, 0xb9, 0xda, 0x94, 0x8d, 0x32, - 0x0d, 0xad, 0xd6, 0x4f, 0x54, 0x31, 0xe6, 0x1d, 0xdf, 0x65, 0x8d, 0x24, 0xae, 0x67, - 0xc2, 0x2c, 0x8d, 0x13, 0x09, 0x13, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, 0x42, - 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x91, 0xe0, 0x0c, 0x7a, 0x1d, 0x48, 0xaf, 0x04, - 0x68, 0x27, 0x59, 0x1e, 0x97, 0x33, 0xa9, 0x7f, 0xa6, 0xb6, 0x79, 0xf3, 0xdc, 0x60, - 0x1d, 0x00, 0x82, 0x85, 0xed, 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0xfc, 0x1b, 0xe4, 0xaa, - 0xc0, 0x0f, 0xf2, 0x71, 0x1e, 0xbd, 0x93, 0x1d, 0xe5, 0x18, 0x85, 0x68, 0x78, 0xf7, - 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, 0x3c, - 0x94, 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, 0x79, - 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, 0x32, 0xb4, 0xf4, - 0x73, 0xf4, 0x68, 0xa0, 0x08, 0xe7, 0x23, 0x89, 0xfc, 0x03, 0x88, 0x0d, 0x78, 0x0c, - 0xb0, 0x7f, 0xcf, 0xaa, 0xbe, 0x3f, 0x1a, 0x84, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, - 0x3d, 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x55, 0xed, 0x94, 0x94, 0xc6, 0xac, - 0x89, 0x3c, 0x49, 0x72, 0x38, 0x33, 0xec, 0x89, 0x26, 0xc1, 0x03, 0x95, 0x86, 0xa7, - 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, 0x73, 0x1e, 0x98, 0x5d, 0x99, 0x58, 0x9c, 0x03, 0xb8, - 0x38, 0xe8, 0xaa, 0xf7, 0x45, 0x53, 0x3e, 0xd9, 0xe8, 0xae, 0x3a, 0x1c, 0xd0, 0x74, - 0xa5, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, 0xeb, 0xbc, 0x86, 0x2d, 0xed, - 0x42, 0x43, 0x5e, 0x02, 0x47, 0x69, 0x30, 0xd0, 0x69, 0x89, 0x6c, 0xff, 0x30, 0xeb, - 0x41, 0x4f, 0x72, 0x7b, 0x89, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, 0x6d, - 0x75, 0xa4, 0xa6, 0xf2, 0x65, 0x72, 0x50, 0x4b, 0x0b, 0x22, 0x32, 0xec, 0xb9, 0xf0, - 0xc0, 0x24, 0x11, 0xe5, 0x25, 0x96, 0xbc, 0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, - 0xff, 0xed, 0xbd, 0x12, 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, 0x7d, 0x41, 0x7a, - 0xdb, 0x3d, 0x15, 0xcc, 0x54, 0xdc, 0xb1, 0xfc, 0xe4, 0x67, 0x50, 0x0c, 0x6b, 0x8f, - 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, 0x82, 0x85, 0x7d, 0xee, 0xcc, 0x40, 0xa9, - 0x8d, 0x5f, 0x29, 0x03, 0x39, 0x5e, 0xe4, 0x76, 0x2d, 0xd2, 0x1a, 0xfd, 0xbb, 0x5d, - 0x47, 0xfa, 0x9a, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, 0xb9, 0x27, 0xb7, - 0xfa, 0xe2, 0xdb, 0x58, 0x71, 0x05, 0x41, 0x5d, 0x02, 0x42, 0x78, 0x9d, 0x38, 0xf5, - 0x0b, 0x8d, 0xbc, 0xc1, 0x29, 0xca, 0xb3, 0xd1, 0x7d, 0x19, 0xf3, 0x35, 0x5b, 0xcf, - 0x73, 0xce, 0xcb, 0x8c, 0xb8, 0xa5, 0xda, 0x01, 0x30, 0x71, 0x52, 0xf1, 0x39, 0x02, - 0xa2, 0x70, 0x57, 0x26, 0x70, 0xdc, 0x82, 0xd3, 0x90, 0x26, 0xc6, 0xcb, 0x4c, 0xd4, - 0xb0, 0xf7, 0xf5, 0xaa, 0x2a, 0x4f, 0x5a, 0x53, 0x41, 0xec, 0x5d, 0xd7, 0x15, 0x40, - 0x6f, 0x2f, 0xdd, 0x2a, 0x02, 0x73, 0x3f, 0x5f, 0x64, 0x1c, 0x8c, 0x21, 0x86, 0x2a, - 0x1b, 0xaf, 0xce, 0x26, 0x09, 0xd9, 0xee, 0xcf, 0xa1, 0x58, 0xcf, 0xb5, 0xcd, 0x79, - 0xf8, 0x80, 0x08, 0xe3, 0x15, 0xdc, 0x7d, 0x83, 0x88, 0x03, 0x6c, 0x17, 0x82, 0xfd, - 0x27, 0x95, 0xd1, 0x8a, 0x76, 0x36, 0x24, 0xc2, 0x5f, 0xa9, 0x59, 0xcc, 0x97, 0x48, - 0x9c, 0xe7, 0x57, 0x45, 0x82, 0x4b, 0x77, 0x86, 0x8c, 0x53, 0x23, 0x9c, 0xfb, 0xdf, - 0x73, 0xca, 0xec, 0x65, 0x60, 0x40, 0x37, 0x31, 0x4f, 0xaa, 0xce, 0xb5, 0x62, 0x18, - 0xc6, 0xbd, 0x30, 0xf8, 0x37, 0x4a, 0xc1, 0x33, 0x86, 0x79, 0x3f, 0x21, 0xa9, 0xfb, - 0x80, 0xad, 0x03, 0xbc, 0x0c, 0xda, 0x4a, 0x44, 0x94, 0x6c, 0x00, 0xe1, 0xb1, 0xa1, - 0xdf, 0x0e, 0x5b, 0x87, 0xb5, 0xbe, 0xce, 0x47, 0x7a, 0x70, 0x96, 0x49, 0xe9, 0x50, - 0x06, 0x05, 0x91, 0x39, 0x48, 0x12, 0x95, 0x1e, 0x1f, 0xe3, 0x89, 0x5b, 0x8c, 0xc3, - 0xd1, 0x4d, 0x2c, 0xf6, 0x55, 0x6d, 0xf6, 0xed, 0x4b, 0x4d, 0xdd, 0x3d, 0x9a, 0x69, - 0xf5, 0x33, 0x57, 0xd7, 0x76, 0x7f, 0x4f, 0x5c, 0xcb, 0xdb, 0xc5, 0x96, 0x63, 0x12, - 0x77, 0xf8, 0xfe, 0xcd, 0x08, 0xcb, 0x05, 0x6b, 0x95, 0xe3, 0x02, 0x5b, 0x97, 0x92, - 0xff, 0xf7, 0xf2, 0x44, 0xfc, 0x71, 0x62, 0x69, 0xb9, 0x26, 0xd6, 0x2e, 0x95, 0x96, - 0xfa, 0x82, 0x5c, 0x6b, 0xf2, 0x1a, 0xff, 0x9e, 0x68, 0x62, 0x5a, 0x19, 0x24, 0x40, - 0xea, 0x06, 0x82, 0x81, 0x23, 0xd9, 0x78, 0x84, 0x80, 0x6f, 0x15, 0xfa, 0x08, 0xda, - 0x52, 0x75, 0x4a, 0x10, 0x95, 0xe3, 0xff, 0x1a, 0xbd, 0x5c, 0xe4, 0xfd, 0xdf, 0xcc, - 0xfc, 0x3a, 0x61, 0x28, 0xae, 0xf7, 0x84, 0xa6, 0x46, 0x10, 0xa8, 0x9d, 0x1a, 0x70, - 0x99, 0x21, 0x6d, 0x08, 0x14, 0xd3, 0xa2, 0xd4, 0x52, 0x43, 0x1c, 0x32, 0xd4, 0x11, - 0xac, 0x1c, 0xce, 0x82, 0xad, 0x02, 0x29, 0x40, 0x7b, 0xbc, 0x48, 0x98, 0x56, 0x75, - 0xe3, 0xf8, 0x74, 0xa4, 0x53, 0x3f, 0x1d, 0x63, 0xa8, 0x4d, 0xfa, 0x3e, 0x0f, 0x46, - 0x0f, 0xe2, 0xf5, 0x7e, 0x34, 0xfb, 0xc7, 0x54, 0x23, 0xc3, 0x73, 0x7f, 0x5b, 0x2a, - 0x06, 0x15, 0xf5, 0x72, 0x2d, 0xb0, 0x41, 0xa3, 0xef, 0x66, 0xfa, 0x48, 0x3a, 0xfd, - 0x3c, 0x2e, 0x19, 0xe5, 0x94, 0x44, 0xa6, 0x4a, 0xdd, 0x6d, 0xf1, 0xd9, 0x63, 0xf5, - 0xdd, 0x5b, 0x50, 0x10, 0xd3, 0xd0, 0x25, 0xf0, 0x28, 0x7c, 0x4c, 0xf1, 0x9c, 0x75, - 0xf3, 0x3d, 0x51, 0xdd, 0xdd, 0xba, 0x5d, 0x65, 0x7b, 0x43, 0xee, 0x8d, 0xa6, 0x45, - 0x44, 0x38, 0x14, 0xcc, 0x73, 0x29, 0xf3, 0xe9, 0xb4, 0xe5, 0x4c, 0x23, 0x6c, 0x29, - 0xaf, 0x39, 0x23, 0x10, 0x17, 0x56, 0xd9, 0xfa, 0x4b, 0xd0, 0xf7, 0xd2, 0xdd, 0xaa, - 0xcb, 0x6b, 0x0f, 0x86, 0xa2, 0x65, 0x8e, 0x0a, 0x07, 0xa0, 0x5a, 0xc5, 0xb9, 0x50, - 0x05, 0x1c, 0xd2, 0x4c, 0x47, 0xa8, 0x8d, 0x13, 0xd6, 0x59, 0xba, 0x2a, 0x46, 0xca, - 0x18, 0x30, 0x81, 0x6d, 0x09, 0xcd, 0x76, 0x46, 0xf7, 0x6f, 0x71, 0x6a, 0xbe, 0xc5, - 0xde, 0x07, 0xfe, 0x9b, 0x52, 0x34, 0x10, 0x80, 0x6e, 0xa6, 0xf2, 0x88, 0xf8, 0x73, - 0x6c, 0x23, 0x35, 0x7c, 0x85, 0xf4, 0x57, 0x91, 0xe1, 0x70, 0x80, 0x29, 0xd9, 0x82, - 0x4d, 0x90, 0x70, 0x46, 0x07, 0xf3, 0x87, 0xa0, 0x3e, 0x49, 0xbf, 0x98, 0x36, 0x57, - 0x44, 0x31, 0x34, 0x5a, 0x78, 0x77, 0xef, 0xaa, 0x8a, 0x08, 0xe7, 0x30, 0x81, 0xef, - 0x8d, 0x62, 0xcb, 0x78, 0x0a, 0xb6, 0x88, 0x3a, 0x50, 0xa0, 0xd4, 0x70, 0x19, 0x0d, - 0xfb, 0xa1, 0x0a, 0x85, 0x7f, 0x82, 0x84, 0x2d, 0x38, 0x25, 0xb3, 0xd6, 0xda, 0x05, - 0x73, 0xd3, 0x16, 0xeb, 0x16, 0x0d, 0xc0, 0xb7, 0x16, 0xc4, 0x8f, 0xbd, 0x46, 0x7f, - 0x75, 0xb7, 0x80, 0x14, 0x9a, 0xe8, 0x80, 0x8f, 0x4e, 0x68, 0xf5, 0x0c, 0x05, 0x36, - 0xac, 0xdd, 0xf6, 0xf1, 0xae, 0xab, 0x01, 0x6b, 0x6b, 0xc1, 0xec, 0x14, 0x4b, 0x4e, - 0x55, 0x3a, 0xcf, 0xd6, 0x70, 0xf7, 0x7e, 0x75, 0x5f, 0xc8, 0x8e, 0x06, 0x77, 0xe3, - 0x1b, 0xa4, 0x59, 0xb4, 0x4e, 0x30, 0x77, 0x68, 0x95, 0x8f, 0xe3, 0x78, 0x9d, 0x41, - 0xc2, 0xb1, 0xff, 0x43, 0x4c, 0xb3, 0x0e, 0x15, 0x91, 0x4f, 0x01, 0xbc, 0x6b, 0xc2, - 0x30, 0x7b, 0x48, 0x8d, 0x25, 0x56, 0xd7, 0xb7, 0x38, 0x0e, 0xa4, 0xff, 0xd7, 0x12, - 0xf6, 0xb0, 0x2f, 0xe8, 0x06, 0xb9, 0x45, 0x69, 0xcd, 0x40, 0x59, 0xf3, 0x96, 0xbf, - 0x29, 0xb9, 0x9d, 0x0a, 0x40, 0xe5, 0xe1, 0x71, 0x1c, 0xa9, 0x44, 0xf7, 0x2d, 0x43, - 0x6a, 0x10, 0x2f, 0xca, 0x4b, 0x97, 0x69, 0x3d, 0xa0, 0xb0, 0x86, 0xfe, 0x9d, 0x2e, - 0x71, 0x62, 0x47, 0x0d, 0x02, 0xe0, 0xf0, 0x5d, 0x4b, 0xec, 0x95, 0x12, 0xbf, 0xb3, - 0xf3, 0x83, 0x27, 0x29, 0x6e, 0xfa, 0xa7, 0x43, 0x28, 0xb1, 0x18, 0xc2, 0x74, 0x02, - 0xc7, 0x0c, 0x3a, 0x90, 0xb4, 0x9a, 0xd4, 0xbb, 0xc6, 0x8e, 0x37, 0xc0, 0xaa, 0x7d, - 0x9b, 0x3f, 0xe1, 0x77, 0x99, 0xd7, 0x3b, 0x84, 0x1e, 0x75, 0x17, 0x13, 0xa0, 0x29, - 0x43, 0x90, 0x5a, 0xae, 0x08, 0x03, 0xfd, 0x69, 0x44, 0x2e, 0xb7, 0x68, 0x1e, 0xc2, - 0xa0, 0x56, 0x00, 0x05, 0x4e, 0x92, 0xee, 0xd5, 0x55, 0x02, 0x8f, 0x21, 0xb6, 0xa1, - 0x55, 0x26, 0x8a, 0x2d, 0xd6, 0x64, 0x0a, 0x69, 0x30, 0x1a, 0x52, 0xa3, 0x8d, 0x4d, - 0x9f, 0x9f, 0x95, 0x7a, 0xe3, 0x5a, 0xf7, 0x16, 0x71, 0x18, 0x14, 0x1c, 0xe4, 0xc9, - 0xbe, 0x0a, 0x6a, 0x49, 0x2f, 0xe7, 0x9f, 0x15, 0x81, 0xa1, 0x55, 0xfa, 0x3a, 0x2b, - 0x9d, 0xaf, 0xd8, 0x2e, 0x65, 0x0b, 0x38, 0x6a, 0xd3, 0xa0, 0x8c, 0xb6, 0xb8, 0x31, - 0x31, 0xac, 0x30, 0x0b, 0x08, 0x46, 0x35, 0x4a, 0x7e, 0xef, 0x9c, 0x41, 0x0e, 0x4b, - 0x62, 0xc4, 0x7c, 0x54, 0x26, 0x90, 0x7d, 0xfc, 0x66, 0x85, 0xc5, 0xc9, 0x9b, 0x71, - 0x41, 0xac, 0x62, 0x6a, 0xb4, 0x76, 0x1f, 0xd3, 0xf4, 0x1e, 0x72, 0x8e, 0x1a, 0x28, - 0xf8, 0x9d, 0xb8, 0x9f, 0xfd, 0xec, 0xa3, 0x64, 0xdd, 0x2f, 0x0f, 0x07, 0x39, 0xf0, - 0x53, 0x45, 0x56, 0x48, 0x31, 0x99, 0xc7, 0x1f, 0x18, 0x93, 0x41, 0xac, 0x9b, 0x78, - 0xa2, 0x69, 0x16, 0x42, 0x06, 0xa0, 0xea, 0x1c, 0xe7, 0x3b, 0xfb, 0x2a, 0x94, 0x2e, - 0x73, 0x70, 0xb2, 0x47, 0xc0, 0x46, 0xf8, 0xe7, 0x5e, 0xf8, 0xe3, 0xf8, 0xbd, 0x82, - 0x1c, 0xf5, 0x77, 0x49, 0x18, 0x64, 0xe2, 0x0e, 0x6d, 0x08, 0xfd, 0x2e, 0x32, 0xb5, - 0x55, 0xc9, 0x2c, 0x66, 0x1f, 0x19, 0x58, 0x8b, 0x72, 0xa8, 0x95, 0x99, 0x71, 0x0a, - 0x88, 0x06, 0x12, 0x53, 0xca, 0x28, 0x5b, 0x63, 0x04, 0xb3, 0x7d, 0xa2, 0xb5, 0x29, - 0x4f, 0x5c, 0xb3, 0x54, 0xa8, 0x94, 0x32, 0x28, 0x48, 0xcc, 0xbd, 0xc7, 0xc2, 0x54, - 0x5b, 0x7d, 0xa5, 0x68, 0xaf, 0xac, 0x87, 0xff, 0xa0, 0x05, 0xc3, 0x12, 0x24, 0x1c, - 0x2d, 0x57, 0xf4, 0xb4, 0x5d, 0x64, 0x19, 0xf0, 0xd2, 0xe2, 0xc5, 0xaf, 0x33, 0xae, - 0x24, 0x37, 0x85, 0xb3, 0x25, 0xcd, 0xab, 0x95, 0x40, 0x4f, 0xc7, 0xae, 0xd7, 0x05, - 0x25, 0xcd, 0xdb, 0x41, 0x87, 0x2c, 0xfc, 0xc2, 0x14, 0xb1, 0x32, 0x32, 0xed, 0xc7, - 0x86, 0x09, 0x75, 0x3d, 0xbf, 0xf9, 0x30, 0xeb, 0x0d, 0xc1, 0x56, 0x61, 0x2b, 0x9c, - 0xb4, 0x34, 0xbc, 0x4b, 0x69, 0x33, 0x92, 0xde, 0xb8, 0x7c, 0x53, 0x04, 0x35, 0x31, - 0x2e, 0xdc, 0xed, 0xc6, 0xa9, 0x61, 0x13, 0x33, 0x38, 0xd7, 0x86, 0xc4, 0xa3, 0xe1, - 0x03, 0xf6, 0x01, 0x10, 0xa1, 0x6b, 0x13, 0x37, 0x12, 0x97, 0x04, 0xbf, 0x47, 0x54, - 0xff, 0x6b, 0xa9, 0xfb, 0xe6, 0x59, 0x51, 0xe6, 0x10, 0x62, 0x0f, 0x71, 0xcd, 0xa8, - 0xfc, 0x87, 0x76, 0x25, 0xf2, 0xc5, 0xbb, 0x04, 0xcb, 0xe1, 0x22, 0x8b, 0x1e, 0x88, - 0x6f, 0x40, 0x50, 0xaf, 0xd8, 0xfe, 0x94, 0xe9, 0x7d, 0x2e, 0x9e, 0x85, 0xc6, 0xbb, - 0x74, 0x8c, 0x00, 0x42, 0xd3, 0x24, 0x9a, 0xbb, 0x13, 0x42, 0xbb, 0x0e, 0xeb, 0xf6, - 0x20, 0x58, 0xbf, 0x3d, 0xe0, 0x80, 0xd9, 0x46, 0x11, 0xa3, 0x75, 0x09, 0x15, 0xb5, - 0xdc, 0x6c, 0x0b, 0x38, 0x99, 0xd4, 0x12, 0x22, 0xba, 0xce, 0x76, 0x0e, 0xe9, 0xc8, - 0x81, 0x8d, 0xed, 0x59, 0x9e, 0x34, 0xc5, 0x6d, 0x73, 0x72, 0xaf, 0x1e, 0xb8, 0x68, - 0x52, 0xf2, 0xa7, 0x32, 0x10, 0x4b, 0xdb, 0x75, 0x07, 0x39, 0xde, 0x6c, 0x2c, 0x6e, - 0x0f, 0x9e, 0xb7, 0xcb, 0x17, 0xf1, 0x94, 0x2b, 0xfc, 0x9f, 0x4f, 0xd6, 0xeb, 0xb6, - 0xb4, 0xcd, 0xd4, 0xda, 0x2b, 0xca, 0x26, 0xfa, 0xc4, 0x57, 0x8e, 0x9f, 0x54, 0x34, - 0x05, 0xac, 0xc7, 0xd8, 0x6f, 0xf5, 0x91, 0x58, 0xbd, 0x0c, 0xba, 0x3a, 0xef, 0x6f, - 0x4a, 0x84, 0x72, 0xd1, 0x44, 0xd9, 0x9f, 0x8b, 0x8d, 0x1d, 0xed, 0xaa, 0x90, 0x77, - 0xd4, 0xf0, 0x1d, 0x4b, 0xb2, 0x7b, 0xbe, 0x31, 0xd8, 0x8f, 0xbe, 0xfa, 0xc3, 0xdc, - 0xd4, 0x79, 0x75, 0x63, 0xa2, 0x6b, 0x1d, 0x61, 0xfc, 0xd9, 0xa4, 0x64, 0xab, 0x21, - 0xed, 0x55, 0x0f, 0xe6, 0xfa, 0x09, 0x69, 0x5b, 0xa0, 0xb2, 0xf1, 0x0e, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xea, 0x64, 0x68, 0xcc, 0x6e, 0x20, 0xa6, 0x6f, 0x82, 0x6e, 0x3d, 0x14, 0xc5, 0x00, - 0x6f, 0x05, 0x63, 0x88, 0x7f, 0x5e, 0x12, 0x89, 0xbe, 0x1b, 0x20, 0x04, 0xca, 0xca, - 0x8d, 0x3f, 0x34, 0xd6, 0xe8, 0x4b, 0xf5, 0x9c, 0x1e, 0x04, 0x61, 0x9a, 0x7c, 0x23, - 0xa9, 0x96, 0x94, 0x1d, 0x88, 0x9e, 0x46, 0x22, 0xa9, 0xb9, 0xb1, 0xd5, 0x9d, 0x5e, - 0x31, 0x90, 0x94, 0x31, 0x8c, 0xd4, 0x05, 0xba, 0x27, 0xb7, 0xe2, 0xc0, 0x84, 0x76, - 0x2d, 0x31, 0x45, 0x3e, 0xc4, 0x54, 0x9a, 0x4d, 0x97, 0x72, 0x9d, 0x03, 0x34, 0x60, - 0xfc, 0xf8, 0x9d, 0x64, 0x94, 0xf2, 0xff, 0xd7, 0x89, 0xe9, 0x80, 0x82, 0xea, 0x5c, - 0xe9, 0x53, 0x4b, 0x3a, 0xcd, 0x60, 0xfe, 0x49, 0xe3, 0x7e, 0x4f, 0x66, 0x69, 0x31, - 0x67, 0x73, 0x19, 0xed, 0x89, 0xf8, 0x55, 0x88, 0x74, 0x1b, 0x31, 0x28, 0x90, 0x1a, - 0x93, 0xbd, 0x78, 0xe4, 0xbe, 0x02, 0x25, 0xa9, 0xe2, 0x69, 0x2c, 0x77, 0xc9, 0x69, - 0xed, 0x01, 0x76, 0xbd, 0xf9, 0x55, 0x59, 0x48, 0xcb, 0xd5, 0xa3, 0x32, 0xd0, 0x45, - 0xde, 0x6b, 0xa6, 0xbf, 0x44, 0x90, 0xad, 0xfe, 0x74, 0x44, 0xcd, 0x46, 0x7a, 0x09, - 0x07, 0x54, 0x17, 0xfc, 0xc0, 0x06, 0x2e, 0x49, 0xf0, 0x08, 0xc5, 0x1a, 0xd4, 0x22, - 0x74, 0x39, 0xc1, 0xb4, 0x47, 0x6c, 0xcd, 0x8e, 0x97, 0x86, 0x2d, 0xab, 0x7b, 0xe1, - 0xe8, 0xd3, 0x99, 0xc0, 0x5e, 0xf2, 0x7c, 0x6e, 0x22, 0xee, 0x27, 0x3e, 0x15, 0x78, - 0x6e, 0x39, 0x4c, 0x8f, 0x1b, 0xe3, 0x16, 0x82, 0xa3, 0x01, 0x47, 0x96, 0x3a, 0xc8, - 0xda, 0x8d, 0x41, 0xd8, 0x04, 0x25, 0x84, 0x26, 0xa3, 0xf7, 0x02, 0x89, 0xb8, 0xad, - 0x19, 0xd8, 0xde, 0x13, 0xbe, 0x4e, 0xeb, 0xe3, 0xbd, 0x4c, 0x8a, 0x6f, 0x55, 0xd6, - 0xe0, 0xc3, 0x73, 0xd4, 0x56, 0x85, 0x18, 0x79, 0xf5, 0xfb, 0xc2, 0x82, 0xdb, 0x9e, - 0x13, 0x48, 0x06, 0xbf, 0xf7, 0x1e, 0x11, 0xbc, 0x33, 0xab, 0x75, 0xdd, 0x6c, 0xa0, - 0x67, 0xfb, 0x73, 0xa0, 0x43, 0xb6, 0x46, 0xa7, 0x03, 0x39, 0xca, 0xb4, 0x92, 0x83, - 0x86, 0x78, 0x6d, 0x2f, 0x24, 0x14, 0x1e, 0xe1, 0x20, 0xfd, 0xc3, 0x4d, 0x67, 0x64, - 0xea, 0xfc, 0x66, 0x88, 0x0e, 0xe0, 0x20, 0x4f, 0x53, 0xcc, 0x11, 0x67, 0xed, 0x02, - 0xb4, 0x3a, 0x52, 0xde, 0xa3, 0xca, 0x7c, 0xff, 0x8e, 0xf3, 0x5c, 0xd8, 0xe6, 0xd7, - 0xc1, 0x11, 0xa6, 0x8e, 0xf4, 0x4b, 0xcd, 0x0c, 0x15, 0x13, 0xad, 0x47, 0xca, 0x61, - 0xc6, 0x59, 0xcc, 0x5d, 0x0a, 0x5b, 0x44, 0x0f, 0x6b, 0x9f, 0x59, 0xaf, 0xf6, 0x68, - 0x79, 0xbb, 0x66, 0x88, 0xfd, 0x28, 0x59, 0x36, 0x2b, 0x18, 0x2f, 0x20, 0x7b, 0x31, - 0x75, 0x96, 0x1f, 0x64, 0x11, 0xa4, 0x93, 0xbf, 0xfd, 0x04, 0x8e, 0x7d, 0x0d, 0x87, - 0xd8, 0x2f, 0xe6, 0xf9, 0x90, 0xa2, 0xb0, 0xa2, 0x5f, 0x5a, 0xa0, 0x11, 0x1a, 0x6e, - 0x68, 0xf3, 0x7b, 0xf6, 0xf3, 0xac, 0x2d, 0x26, 0xb8, 0x46, 0x86, 0xe5, 0x69, 0x03, - 0x8d, 0x99, 0xc1, 0x38, 0x35, 0x97, 0xfa, 0xd8, 0x11, 0x93, 0xc4, 0xc1, 0xb1, 0x6e, - 0x6a, 0x90, 0xe2, 0xd5, 0x07, 0xcd, 0xfe, 0x6f, 0xbd, 0xaa, 0x86, 0x16, 0x3e, 0x9c, - 0xf5, 0xde, 0x31, 0x00, 0x03, 0xca, 0x7e, 0x8d, 0xa0, 0x47, 0xb0, 0x90, 0xdb, 0x9f, - 0x37, 0x95, 0x2f, 0xbf, 0xee, 0x76, 0xaf, 0x61, 0x66, 0x81, 0x90, 0xbd, 0x52, 0xed, - 0x49, 0x0e, 0x67, 0x7b, 0x51, 0x5d, 0x01, 0x43, 0x84, 0x03, 0x07, 0x21, 0x9c, 0x7c, - 0x0e, 0xe7, 0xfc, 0x7b, 0xfc, 0x79, 0xf3, 0x25, 0x64, 0x4e, 0x4d, 0xf4, 0xc0, 0xd7, - 0xdb, 0x08, 0xe9, 0xf0, 0xbd, 0x02, 0x49, 0x43, 0xc7, 0x05, 0xab, 0xff, 0x89, 0x94, - 0x03, 0xa6, 0x05, 0xcf, 0xbc, 0x7e, 0xd7, 0x46, 0xa7, 0xd3, 0xf7, 0xc3, 0x7d, 0x9e, - 0x8b, 0xdc, 0x43, 0x3b, 0x7d, 0x79, 0xe0, 0x8a, 0x12, 0xf7, 0x38, 0xa8, 0xf0, 0xdb, - 0xdd, 0xfe, 0xf2, 0xf2, 0x65, 0x02, 0xf3, 0xe4, 0x7d, 0x1b, 0x0f, 0xd1, 0x1e, 0x6a, - 0x13, 0x31, 0x1f, 0xb7, 0x99, 0xc7, 0x9c, 0x64, 0x1d, 0x9d, 0xa4, 0x3b, 0x33, 0xe7, - 0xad, 0x01, 0x2e, 0x28, 0x25, 0x53, 0x98, 0x78, 0x92, 0x62, 0x27, 0x5f, 0x11, 0x75, - 0xbe, 0x84, 0x62, 0xc0, 0x14, 0x91, 0xc4, 0xd8, 0x42, 0x40, 0x6d, 0x0e, 0xc4, 0x28, - 0x2c, 0x95, 0x26, 0x17, 0x4a, 0x09, 0x87, 0x8f, 0xe8, 0xfd, 0xde, 0x33, 0xa2, 0x96, - 0x04, 0xe5, 0xe5, 0xe7, 0xb2, 0xa0, 0x25, 0xd6, 0x65, 0x0b, 0x97, 0xdb, 0xb5, 0x2b, - 0xef, 0xb5, 0x9b, 0x1d, 0x30, 0xa5, 0x74, 0x33, 0xb0, 0xa3, 0x51, 0x47, 0x44, 0x44, - 0x09, 0x9d, 0xaa, 0x37, 0x10, 0x46, 0x61, 0x32, 0x60, 0xcf, 0x33, 0x54, 0xcf, 0xcd, - 0xad, 0xa6, 0x63, 0xec, 0xe8, 0x24, 0xff, 0xd7, 0xe4, 0x43, 0x93, 0x88, 0x6a, 0x86, - 0x16, 0x5d, 0xdd, 0xdf, 0x2b, 0x4c, 0x41, 0x77, 0x35, 0x54, 0xc8, 0x69, 0x95, 0x26, - 0x94, 0x08, 0xb1, 0x1e, 0x67, 0x37, 0xa4, 0xc4, 0x47, 0x58, 0x6f, 0x69, 0x17, 0x34, - 0x46, 0xd8, 0xe4, 0x8b, 0xf8, 0x4c, 0xbc, 0x00, 0x0a, 0x80, 0x78, 0x99, 0x97, 0x3e, - 0xb9, 0x3c, 0x5e, 0x81, 0x9a, 0xad, 0x66, 0x94, 0x13, 0xf8, 0x38, 0x79, 0x33, 0xad, - 0x15, 0x84, 0xaa, 0x35, 0xe4, 0x3f, 0x4e, 0xcd, 0x1e, 0x2d, 0x04, 0x07, 0xc0, 0xb1, - 0xb8, 0x99, 0x20, 0xff, 0xdf, 0xdb, 0x9b, 0xea, 0x51, 0xac, 0x95, 0xb5, 0x57, 0xaf, - 0x71, 0xb8, 0x9f, 0x90, 0x3f, 0x5d, 0x98, 0x48, 0xf1, 0x4f, 0xcb, 0xeb, 0x18, 0x37, - 0x57, 0x0f, 0x54, 0x4d, 0x63, 0x59, 0xeb, 0x23, 0xfa, 0xf3, 0x8a, 0x08, 0x22, 0xda, - 0x36, 0xce, 0x42, 0x6c, 0x4a, 0x2f, 0xbe, 0xff, 0xeb, 0x0a, 0x8a, 0x2e, 0x29, 0x7a, - 0x9d, 0x19, 0xba, 0x15, 0x02, 0x45, 0x90, 0xe3, 0x32, 0x9d, 0x9f, 0xa9, 0x26, 0x1f, - 0x99, 0x38, 0xa4, 0x03, 0x2d, 0xd3, 0x46, 0x06, 0xc9, 0xcf, 0x9f, 0x3d, 0xd3, 0x3e, - 0x57, 0x6f, 0x05, 0xcd, 0x1d, 0xd6, 0x81, 0x1c, 0x62, 0x98, 0x75, 0x7d, 0x77, 0xd9, - 0xe8, 0x10, 0xab, 0xdb, 0x22, 0x6a, 0xfc, 0xaa, 0x43, 0x46, 0xa6, 0x56, 0x0f, 0x89, - 0x32, 0xb3, 0x18, 0x1f, 0xd3, 0x55, 0xd5, 0xd3, 0x91, 0x97, 0x61, 0x83, 0xf8, 0xd9, - 0x93, 0x88, 0x83, 0x96, 0x32, 0xd6, 0x35, 0x4f, 0x66, 0x6d, 0x09, 0xd3, 0xe5, 0x62, - 0x9e, 0xa1, 0x97, 0x37, 0x38, 0x86, 0x13, 0xd3, 0x8a, 0x34, 0xfd, 0x0f, 0x6e, 0x50, - 0xee, 0x5a, 0x0c, 0xc9, 0x67, 0x71, 0x77, 0xf5, 0x00, 0x28, 0xc1, 0x41, 0x37, 0x81, - 0x87, 0xbd, 0x28, 0x19, 0x40, 0x3f, 0xc5, 0x34, 0xf8, 0x00, 0x76, 0xe9, 0x38, 0x0c, - 0xb4, 0x96, 0x4d, 0x3b, 0x6b, 0x45, 0x81, 0x9d, 0x3b, 0x8e, 0x9c, 0xaf, 0x54, 0xf0, - 0x51, 0x85, 0x2d, 0x67, 0x1b, 0xf8, 0xc1, 0xff, 0xde, 0x2d, 0x15, 0x10, 0x75, 0x64, - 0x18, 0xcb, 0x48, 0x10, 0x93, 0x6a, 0xa5, 0x7e, 0x69, 0x65, 0xd6, 0xfb, 0x65, 0x6a, - 0x76, 0x0b, 0x7f, 0x19, 0xad, 0xf9, 0x6c, 0x17, 0x34, 0x88, 0x55, 0x21, 0x93, 0xb1, - 0x47, 0xee, 0x58, 0x85, 0x80, 0x33, 0xda, 0xc7, 0xcd, 0x0e, 0xb2, 0x04, 0xc0, 0x64, - 0x90, 0xbb, 0xde, 0xdf, 0x5f, 0x75, 0x71, 0xac, 0xb2, 0xeb, 0xe7, 0x6a, 0xce, 0xf3, - 0xf2, 0xa0, 0x1e, 0xe9, 0x87, 0x48, 0x6d, 0xfe, 0x6c, 0x3f, 0x0a, 0x5e, 0x23, 0x4c, - 0x12, 0x72, 0x58, 0xf9, 0x7a, 0x28, 0xfb, 0x5d, 0x16, 0x4a, 0x81, 0x76, 0xbe, 0x94, - 0x6b, 0x80, 0x97, 0xd0, 0xe3, 0x17, 0x28, 0x7f, 0x33, 0xbf, 0x9c, 0x16, 0xf9, 0xa5, - 0x45, 0x40, 0x9c, 0xe2, 0x9b, 0x1f, 0x42, 0x73, 0x72, 0x5f, 0xc0, 0xdf, 0x02, 0xa0, - 0x4e, 0xba, 0xe1, 0x78, 0xb3, 0x41, 0x4f, 0xb0, 0xa8, 0x2d, 0x50, 0xde, 0xb0, 0x9f, - 0xcf, 0x4e, 0x6e, 0xe9, 0xd1, 0x80, 0xff, 0x4f, 0x56, 0xff, 0x3b, 0xc1, 0xd3, 0x60, - 0x1f, 0xc2, 0xdc, 0x90, 0xd8, 0x14, 0xc3, 0x25, 0x6f, 0x49, 0x67, 0xd3, 0xa8, 0xd6, - 0x4c, 0x83, 0xfe, 0xa3, 0x39, 0xc5, 0x1f, 0x5a, 0x8e, 0x58, 0x01, 0xfb, 0xb9, 0x78, - 0x35, 0x58, 0x1b, 0x60, 0x24, 0x65, 0xde, 0xe0, 0x4b, 0x59, 0x22, 0xc2, 0x76, 0x1b, - 0x54, 0x24, 0x5b, 0xec, 0x0c, 0x9e, 0xef, 0x2d, 0xb9, 0x7d, 0x22, 0xb2, 0xb3, 0x55, - 0x6c, 0xc9, 0x69, 0xfb, 0xb1, 0x3d, 0x06, 0x50, 0x97, 0x65, 0xa5, 0x2b, 0x3f, 0xac, - 0x54, 0xb9, 0x3f, 0x42, 0x1b, 0xf0, 0x8e, 0x18, 0xd5, 0x2d, 0xdd, 0x52, 0xcc, 0x1c, - 0x8c, 0xa8, 0xad, 0xfa, 0xcc, 0xab, 0x7e, 0x5c, 0xc2, 0xf4, 0x57, 0x3f, 0xbb, 0xf8, - 0x23, 0x9b, 0xb0, 0xb8, 0xae, 0xdb, 0xf8, 0xda, 0xd1, 0x62, 0x82, 0xda, 0x5c, 0x91, - 0x25, 0xdb, 0xa1, 0xc0, 0x59, 0xd0, 0xdf, 0x8a, 0xbf, 0x62, 0x10, 0x78, 0xf0, 0x2d, - 0x6c, 0x4b, 0xc8, 0x6d, 0x40, 0x84, 0x5a, 0xc1, 0xd5, 0x97, 0x10, 0xc4, 0x5f, 0x07, - 0xd5, 0x85, 0xeb, 0x48, 0xb3, 0x2f, 0xc0, 0x16, 0x7b, 0xa2, 0x56, 0xe7, 0x3c, 0xa3, - 0xb9, 0x31, 0x1c, 0x62, 0xd1, 0x09, 0x49, 0x79, 0x57, 0xd8, 0xdb, 0xe1, 0x0a, 0xa3, - 0xe8, 0x66, 0xb4, 0x0c, 0x0b, 0xaa, 0x2b, 0xc4, 0x92, 0xc1, 0x9a, 0xd1, 0xe6, 0x37, - 0x2d, 0x96, 0x22, 0xbf, 0x16, 0x3f, 0xbf, 0xfe, 0xae, 0xee, 0x79, 0x6a, 0x3c, 0xd9, - 0xb6, 0xfb, 0xbf, 0xa4, 0xd7, 0x92, 0xf3, 0x4d, 0x7f, 0xd6, 0xe7, 0x63, 0xcd, 0x58, - 0x59, 0xdd, 0x26, 0x83, 0x3d, 0x21, 0xd9, 0xbc, 0x54, 0x52, 0xbd, 0x19, 0x51, 0x5d, - 0xff, 0x9f, 0x49, 0x95, 0xb3, 0x5b, 0xc0, 0xc1, 0xf8, 0x76, 0xe6, 0xad, 0x11, 0xf2, - 0x45, 0x2d, 0xc9, 0xae, 0x85, 0xae, 0xc0, 0x1f, 0xc5, 0x6f, 0x8c, 0xbf, 0xda, 0x75, - 0xa7, 0x72, 0x7b, 0x75, 0xeb, 0xbd, 0x6b, 0xbf, 0xfb, 0x43, 0xb6, 0x3a, 0x3b, 0x1b, - 0x67, 0x1e, 0x40, 0xfe, 0xb0, 0xdb, 0x00, 0x29, 0x74, 0xa3, 0xc3, 0xb1, 0xa7, 0x88, - 0x56, 0x72, 0x31, 0xbf, 0x63, 0x99, 0xff, 0x89, 0x23, 0x69, 0x81, 0x14, 0x9d, 0x42, - 0x38, 0x02, 0xd2, 0x34, 0x1a, 0x3b, 0xed, 0xb9, 0xdd, 0xcb, 0xac, 0x1f, 0xe7, 0xb6, - 0x43, 0x5e, 0x14, 0x79, 0xc7, 0x2e, 0x70, 0x89, 0xd0, 0x29, 0xe7, 0xfb, 0xba, 0xf3, - 0xcf, 0x37, 0xe9, 0xb9, 0xa6, 0xb7, 0x76, 0x79, 0x1e, 0x4c, 0x5e, 0x6f, 0xda, 0x57, - 0xe8, 0xd5, 0xf1, 0x4c, 0x8c, 0x35, 0xa2, 0xd2, 0x70, 0x84, 0x6b, 0x9d, 0xbe, 0x00, - 0x5c, 0xda, 0x16, 0xaf, 0x44, 0x08, 0xf3, 0xab, 0x06, 0xa9, 0x16, 0xee, 0xeb, 0x9c, - 0x95, 0x94, 0xb7, 0x04, 0x24, 0xa4, 0xc1, 0xd1, 0x71, 0x29, 0x5b, 0x67, 0x63, 0xb2, - 0x2f, 0x47, 0xf8, 0x0b, 0x53, 0xcc, 0xbb, 0x90, 0x4b, 0xd6, 0x8f, 0xd6, 0x5f, 0xbd, - 0x3f, 0xbd, 0xea, 0x10, 0x35, 0xe9, 0x8c, 0x21, 0xa7, 0xdb, 0xc9, 0x1a, 0x9b, 0x5b, - 0xc7, 0x69, 0x0f, 0x05, 0xec, 0x31, 0x7c, 0x97, 0xf8, 0x76, 0x4e, 0xb4, 0x8e, 0x91, - 0x1d, 0x42, 0x8e, 0xc8, 0xd8, 0x61, 0xb7, 0x08, 0xe8, 0x29, 0x8a, 0xcb, 0x62, 0x15, - 0x51, 0x45, 0x15, 0x5a, 0xe9, 0x5f, 0x0a, 0x1d, 0x15, 0x01, 0x03, 0x47, 0x53, 0x14, - 0x6e, 0x22, 0xd0, 0x5f, 0x58, 0x6d, 0x7f, 0x6b, 0x4f, 0xe1, 0x2d, 0xad, 0x9a, 0x17, - 0xf5, 0xdb, 0x70, 0xb1, 0xdb, 0x96, 0xb8, 0xd9, 0xa8, 0x3e, 0xda, 0xdc, 0x96, 0x6c, - 0x8a, 0x54, 0x66, 0xb6, 0x1f, 0xc9, 0x98, 0xc3, 0x1f, 0x10, 0x70, 0xd9, 0xa5, 0xc9, - 0xa6, 0xd2, 0x68, 0xd3, 0x04, 0xfe, 0x6b, 0x8f, 0xd3, 0xb4, 0x01, 0x03, 0x48, 0x61, - 0x1a, 0xbd, 0xcb, 0xd4, 0x9f, 0xe4, 0xf8, 0x5b, 0x62, 0x3c, 0x78, 0x28, 0xc7, 0x13, - 0x82, 0xe1, 0x03, 0x4e, 0xa6, 0x7b, 0xc8, 0xae, 0x97, 0x40, 0x4b, 0x0c, 0x50, 0xb2, - 0xa0, 0x4f, 0x55, 0x9e, 0x49, 0x95, 0x0a, 0xfc, 0xb0, 0xef, 0x46, 0x2a, 0x2a, 0xe0, - 0x24, 0xb0, 0xf0, 0x22, 0x4d, 0xfd, 0x73, 0x68, 0x4b, 0x88, 0xc7, 0xfb, 0xe9, 0x2d, - 0x02, 0xb6, 0x8f, 0x75, 0x9c, 0x47, 0x52, 0x66, 0x3c, 0xd7, 0xb9, 0x7a, 0x14, 0x94, - 0x36, 0x49, 0x30, 0x55, 0x21, 0x32, 0x6b, 0xde, 0x08, 0x56, 0x30, 0x86, 0x46, 0x29, - 0x29, 0x1b, 0xae, 0x25, 0xff, 0x88, 0x22, 0xa1, 0x4c, 0x4b, 0x66, 0x6a, 0x92, 0x59, - 0xad, 0x0d, 0xc4, 0x2a, 0x82, 0x90, 0xac, 0x7b, 0xc7, 0xf5, 0x3a, 0x16, 0xf3, 0x79, - 0xf7, 0x58, 0xe5, 0xde, 0x75, 0x0f, 0x04, 0xfd, 0x7c, 0xad, 0x47, 0x70, 0x1c, 0x85, - 0x97, 0xf9, 0x78, 0x88, 0xbe, 0xa6, 0xfa, 0x0b, 0xf2, 0x99, 0x99, 0x56, 0xfb, 0xfd, - 0x0e, 0xe6, 0x8e, 0xc3, 0x6e, 0x46, 0x88, 0x80, 0x9a, 0xe2, 0x31, 0xeb, 0x8b, 0xc4, - 0x36, 0x9f, 0x5f, 0xe1, 0x57, 0x3f, 0x57, 0xe0, 0x99, 0xd9, 0xc0, 0x99, 0x01, 0xbf, - 0x39, 0xca, 0xac, 0x48, 0xdc, 0x11, 0x95, 0x6a, 0x8a, 0xe9, 0x05, 0xea, 0xd8, 0x69, - 0x54, 0x54, 0x7c, 0x44, 0x8a, 0xe4, 0x3d, 0x31, 0x5e, 0x66, 0x9c, 0x42, 0x42, 0xda, - 0x56, 0x59, 0x38, 0xf4, 0x17, 0xbf, 0x43, 0xce, 0x7b, 0x2b, 0x30, 0xb1, 0xcd, 0x40, - 0x18, 0x38, 0x8e, 0x1a, 0x91, 0x0f, 0x0f, 0xc4, 0x1f, 0xb0, 0x87, 0x7a, 0x59, 0x25, - 0xe4, 0x66, 0x81, 0x9d, 0x37, 0x5b, 0x0a, 0x91, 0x2d, 0x4f, 0xe8, 0x43, 0xb7, 0x6e, - 0xf6, 0xf2, 0x23, 0xf0, 0xf7, 0xc8, 0x94, 0xf3, 0x8f, 0x7a, 0xb7, 0x80, 0xdf, 0xd7, - 0x5f, 0x66, 0x9c, 0x8c, 0x06, 0xcf, 0xfa, 0x43, 0xeb, 0x47, 0x56, 0x5a, 0x50, 0xe3, - 0xb1, 0xfa, 0x45, 0xad, 0x61, 0xce, 0x9a, 0x1c, 0x47, 0x27, 0xb7, 0xaa, 0xa5, 0x35, - 0x62, 0xf5, 0x23, 0xe7, 0x39, 0x52, - ], - script_code: vec![0x53], - transparent_input: Some(1), - hash_type: 3, - amount: 365293780364847, - consensus_branch_id: 1537743641, - sighash: [ - 0x23, 0x65, 0x2e, 0x76, 0xcb, 0x13, 0xb8, 0x5a, 0x0e, 0x33, 0x63, 0xbb, 0x5f, 0xca, - 0x06, 0x1f, 0xa7, 0x91, 0xc4, 0x0c, 0x53, 0x3e, 0xcc, 0xee, 0x89, 0x93, 0x64, 0xe6, - 0xe6, 0x0b, 0xb4, 0xf7, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x99, 0xa6, 0x9f, 0xdf, 0x1c, - 0x5a, 0xc7, 0x73, 0x21, 0x46, 0xee, 0x5e, 0x1d, 0x6b, 0x6c, 0xa9, 0xb9, 0x18, 0x0f, - 0x96, 0x4c, 0xc9, 0xd0, 0x87, 0x8a, 0xe1, 0x37, 0x35, 0x24, 0xd7, 0xd5, 0x10, 0xe5, - 0x82, 0x27, 0xdf, 0x09, 0x51, 0x53, 0x63, 0x6a, 0x00, 0x6a, 0xac, 0x51, 0x6a, 0xb0, - 0xf1, 0x85, 0x6e, 0x28, 0xd5, 0xc8, 0xaf, 0xb0, 0x95, 0xef, 0x61, 0x84, 0xfe, 0xd6, - 0x51, 0x58, 0x90, 0x22, 0xee, 0xae, 0xa4, 0xc0, 0xce, 0x1f, 0xa6, 0xf0, 0x85, 0x09, - 0x2b, 0x04, 0x97, 0x94, 0x89, 0x17, 0x2b, 0x3e, 0xf8, 0x19, 0x4a, 0x01, 0x63, 0xf5, - 0x72, 0x4d, 0x6b, 0x02, 0xde, 0xe1, 0x36, 0xf3, 0xa9, 0xaa, 0x02, 0x00, 0x03, 0x52, - 0x52, 0xac, 0x17, 0xb7, 0x3f, 0x8d, 0x38, 0x3e, 0x00, 0x00, 0x06, 0xac, 0x63, 0x00, - 0x53, 0xac, 0x51, 0x04, 0xb4, 0x75, 0x56, 0xaf, 0x73, 0xb6, 0x08, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xe2, 0x32, 0x1d, 0x14, 0x60, 0x71, 0x78, 0x9d, 0x23, 0x35, 0x93, 0x4a, 0x68, 0x06, - 0x14, 0xe8, 0x35, 0x62, 0xf8, 0x2d, 0xfd, 0x40, 0x5b, 0x54, 0xa4, 0x5e, 0xb3, 0x2c, - 0x16, 0x54, 0x48, 0xd4, 0xd5, 0xd6, 0x1c, 0xa2, 0x85, 0x95, 0x85, 0x36, 0x9f, 0x53, - 0xf1, 0xa1, 0x37, 0xe9, 0xe8, 0x2b, 0x67, 0xb8, 0xfd, 0xaf, 0x01, 0xbd, 0xa5, 0x4a, - 0x31, 0x73, 0x11, 0x89, 0x6a, 0xe1, 0x02, 0x80, 0xa0, 0x32, 0x44, 0x0c, 0x42, 0x0a, - 0x42, 0x1e, 0x94, 0x4d, 0x1e, 0x95, 0x2b, 0x70, 0xd5, 0x82, 0x6c, 0xd3, 0xb0, 0x8b, - 0x7d, 0xb9, 0x63, 0x0f, 0xe4, 0xfd, 0x5f, 0x22, 0x12, 0x5d, 0xe8, 0x40, 0xfc, 0xc4, - 0x0b, 0x98, 0x03, 0x8a, 0xf1, 0x1d, 0x55, 0xbe, 0x25, 0x43, 0x25, 0x97, 0xb4, 0xb6, - 0x5b, 0x9e, 0xc1, 0xc7, 0xa8, 0xbb, 0xfd, 0x05, 0x2c, 0xbf, 0x7e, 0x1c, 0x17, 0x85, - 0x31, 0x49, 0x34, 0xb2, 0x62, 0xd5, 0x85, 0x37, 0x54, 0xf1, 0xf1, 0x77, 0x71, 0xcf, - 0xb7, 0x50, 0x30, 0x72, 0x65, 0x57, 0x53, 0xfa, 0x3f, 0x54, 0xec, 0xc5, 0x87, 0xe9, - 0xf8, 0x3b, 0x58, 0x19, 0x16, 0x09, 0x2d, 0xf2, 0x6e, 0x63, 0xe1, 0x89, 0x94, 0xcb, - 0x0d, 0xb9, 0x1a, 0x0b, 0xbd, 0xc7, 0xb6, 0x11, 0x9b, 0x32, 0x22, 0x2a, 0xdf, 0x5e, - 0x61, 0xd8, 0xd8, 0xae, 0x89, 0xda, 0xe4, 0x95, 0x4b, 0x54, 0x81, 0x3b, 0xb3, 0x3f, - 0x08, 0xd5, 0x62, 0xba, 0x51, 0x3f, 0xee, 0x1b, 0x09, 0xc0, 0xfc, 0xd5, 0x16, 0x05, - 0x54, 0x19, 0x47, 0x4d, 0xd7, 0xfd, 0xa0, 0x38, 0xa8, 0x9c, 0x84, 0xea, 0x7b, 0x94, - 0x68, 0x28, 0x7f, 0x0e, 0xb0, 0xc1, 0x0c, 0x4b, 0x13, 0x25, 0x20, 0x19, 0x4d, 0x3d, - 0x8d, 0x53, 0x51, 0xfc, 0x10, 0xd0, 0x9c, 0x15, 0xc8, 0xcc, 0x10, 0x1a, 0xa1, 0x66, - 0x3b, 0xbf, 0x17, 0xb8, 0x41, 0x11, 0xf3, 0x8b, 0xb4, 0x39, 0xf0, 0x73, 0x53, 0xbd, - 0xea, 0x35, 0x96, 0xd1, 0x5e, 0x71, 0x3e, 0x1e, 0x2e, 0x7d, 0x3f, 0x1c, 0x38, 0x31, - 0x35, 0xb4, 0x7f, 0xa7, 0xf8, 0x1f, 0x46, 0xdf, 0x02, 0x90, 0x2a, 0x40, 0x46, 0x99, - 0xec, 0x91, 0x2f, 0x56, 0x56, 0xc3, 0x5b, 0x85, 0x76, 0x3e, 0x4d, 0xe5, 0x83, 0xae, - 0xca, 0xa1, 0xdf, 0xd5, 0xd2, 0x67, 0x7d, 0x9c, 0x8f, 0xfe, 0xe8, 0x77, 0xf6, 0x03, - 0x40, 0xa5, 0xca, 0x0d, 0x67, 0xf6, 0xe5, 0x54, 0x12, 0x47, 0x39, 0xf8, 0x05, 0xaf, - 0x87, 0x6a, 0xee, 0xde, 0x53, 0xaa, 0x8b, 0x0f, 0x8e, 0x56, 0x04, 0xa7, 0x3c, 0x30, - 0xcb, 0xd0, 0x9d, 0xad, 0x0a, 0x3d, 0x6f, 0x8a, 0x5d, 0xcc, 0x40, 0xde, 0xf4, 0x07, - 0x97, 0x34, 0x21, 0x13, 0xba, 0x20, 0x6f, 0xae, 0x8e, 0xbe, 0x4f, 0x3b, 0xc3, 0xca, - 0xf6, 0x92, 0x59, 0xe4, 0x62, 0xef, 0xf9, 0xba, 0x8b, 0x3f, 0x4b, 0xfa, 0xa1, 0x30, - 0x0c, 0x26, 0x92, 0x5a, 0x87, 0x29, 0xcd, 0x32, 0x91, 0x5b, 0xfc, 0x96, 0x60, 0x86, - 0xf0, 0xd5, 0x56, 0x0b, 0xbe, 0x32, 0xa5, 0x98, 0xc2, 0x2a, 0xdf, 0xb4, 0x8c, 0x03, - 0x72, 0xba, 0x5d, 0x42, 0x87, 0xc0, 0xce, 0xfb, 0xac, 0xfd, 0x8c, 0xe1, 0x95, 0xb4, - 0x96, 0x3c, 0x34, 0xa9, 0x4b, 0xba, 0x7a, 0x17, 0x5d, 0xae, 0x4b, 0xbe, 0x3e, 0xf4, - 0x86, 0x3d, 0x53, 0x70, 0x03, 0x15, 0x09, 0x0f, 0x47, 0xa0, 0x68, 0xe2, 0x27, 0x43, - 0x3f, 0x9e, 0x49, 0xd3, 0xaa, 0x09, 0xe3, 0x56, 0xd8, 0xd6, 0x6d, 0x0c, 0x01, 0x21, - 0xe9, 0x1a, 0x3c, 0x4a, 0xa3, 0xf2, 0x7f, 0xa1, 0xb6, 0x03, 0x96, 0xe2, 0xb4, 0x1d, - 0xb9, 0x08, 0xfd, 0xab, 0x8b, 0x18, 0xcc, 0x73, 0x04, 0xe9, 0x4e, 0x97, 0x05, 0x68, - 0xf9, 0x42, 0x1c, 0x0d, 0xbb, 0xba, 0xf8, 0x45, 0x98, 0xd9, 0x72, 0xb0, 0x53, 0x4f, - 0x02, 0xa5, 0xe5, 0x26, 0x70, 0x43, 0x6a, 0xaa, 0x77, 0x6e, 0xd2, 0x48, 0x2a, 0xd7, - 0x03, 0x43, 0x02, 0x01, 0xe5, 0x34, 0x43, 0xc3, 0x6d, 0xcf, 0xd3, 0x4a, 0x0c, 0xb6, - 0x63, 0x78, 0x76, 0x10, 0x5e, 0x03, 0xbf, 0x3b, 0xd5, 0x8e, 0xc1, 0x48, 0xcb, 0x64, - 0x97, 0x0e, 0x32, 0x23, 0xa9, 0x1f, 0x71, 0xdf, 0xcf, 0xd5, 0xa0, 0x4b, 0x66, 0x7f, - 0xba, 0xf3, 0xd4, 0xb3, 0xb9, 0x08, 0xb9, 0x82, 0x88, 0x20, 0xdf, 0xec, 0xdd, 0x75, - 0x37, 0x50, 0xb5, 0xf9, 0xd2, 0x21, 0x6e, 0x56, 0xc6, 0x15, 0x27, 0x2f, 0x85, 0x44, - 0x64, 0xc0, 0xca, 0x4b, 0x1e, 0x85, 0xae, 0xdd, 0x03, 0x82, 0x92, 0xc4, 0xe1, 0xa5, - 0x77, 0x44, 0xeb, 0xba, 0x01, 0x0b, 0x9e, 0xbf, 0xbb, 0x01, 0x1b, 0xd6, 0xf0, 0xb7, - 0x88, 0x05, 0x02, 0x5d, 0x27, 0xf3, 0xc1, 0x77, 0x46, 0xba, 0xe1, 0x16, 0xc1, 0x5d, - 0x9f, 0x47, 0x1f, 0x0f, 0x62, 0x88, 0xa1, 0x50, 0x64, 0x7b, 0x2a, 0xfe, 0x9d, 0xf7, - 0xcc, 0xcf, 0x01, 0xf5, 0xcd, 0xe5, 0xf0, 0x46, 0x80, 0xbb, 0xfe, 0xd8, 0x7f, 0x6c, - 0xf4, 0x29, 0xfb, 0x27, 0xad, 0x6b, 0xab, 0xe7, 0x91, 0x76, 0x66, 0x11, 0xcf, 0x5b, - 0xc2, 0x0e, 0x48, 0xbe, 0xf1, 0x19, 0x25, 0x9b, 0x9b, 0x8a, 0x0e, 0x39, 0xc3, 0xdf, - 0x28, 0xcb, 0x95, 0x82, 0xea, 0x33, 0x86, 0x01, 0xcd, 0xc4, 0x81, 0xb3, 0x2f, 0xb8, - 0x2a, 0xde, 0xeb, 0xb3, 0xda, 0xde, 0x25, 0xd1, 0xa3, 0xdf, 0x20, 0xc3, 0x7e, 0x71, - 0x25, 0x06, 0xb5, 0xd9, 0x96, 0xc4, 0x9a, 0x9f, 0x0f, 0x30, 0xdd, 0xcb, 0x91, 0xfe, - 0x90, 0x04, 0xe1, 0xe8, 0x32, 0x94, 0xa6, 0xc9, 0x20, 0x3d, 0x94, 0xe8, 0xdc, 0x2c, - 0xbb, 0x44, 0x9d, 0xe4, 0x15, 0x50, 0x32, 0x60, 0x4e, 0x47, 0x99, 0x70, 0x16, 0xb3, - 0x04, 0xfd, 0x43, 0x7d, 0x82, 0x35, 0x04, 0x5e, 0x25, 0x5a, 0x19, 0xb7, 0x43, 0xa0, - 0xa9, 0xf2, 0xe3, 0x36, 0xb4, 0x4c, 0xae, 0x30, 0x7b, 0xb3, 0x98, 0x7b, 0xd3, 0xe4, - 0xe7, 0x77, 0xfb, 0xb3, 0x4c, 0x0a, 0xb8, 0xcc, 0x3d, 0x67, 0x46, 0x6c, 0x0a, 0x88, - 0xdd, 0x4c, 0xca, 0xd1, 0x8a, 0x07, 0xa8, 0xd1, 0x06, 0x8d, 0xf5, 0xb6, 0x29, 0xe5, - 0x71, 0x8d, 0x0f, 0x6d, 0xf5, 0xc9, 0x57, 0xcf, 0x71, 0xbb, 0x00, 0xa5, 0x17, 0x8f, - 0x17, 0x5c, 0xac, 0xa9, 0x44, 0xe6, 0x35, 0xc5, 0x15, 0x9f, 0x73, 0x8e, 0x24, 0x02, - 0xa2, 0xd2, 0x1a, 0xa0, 0x81, 0xe1, 0x0e, 0x45, 0x6a, 0xfb, 0x00, 0xb9, 0xf6, 0x24, - 0x16, 0xc8, 0xb9, 0xc0, 0xf7, 0x22, 0x8f, 0x51, 0x07, 0x29, 0xe0, 0xbe, 0x3f, 0x30, - 0x53, 0x13, 0xd7, 0x7f, 0x73, 0x79, 0xdc, 0x2a, 0xf2, 0x48, 0x69, 0xc6, 0xc7, 0x4e, - 0xe4, 0x47, 0x14, 0x98, 0x86, 0x1d, 0x19, 0x2f, 0x0f, 0xf0, 0xf5, 0x08, 0x28, 0x5d, - 0xab, 0x6b, 0x6a, 0x36, 0xcc, 0xf7, 0xd1, 0x22, 0x56, 0xcc, 0x76, 0xb9, 0x55, 0x03, - 0x72, 0x0a, 0xc6, 0x72, 0xd0, 0x82, 0x68, 0xd2, 0xcf, 0x77, 0x73, 0xb6, 0xba, 0x2a, - 0x5f, 0x66, 0x48, 0x47, 0xbf, 0x70, 0x7f, 0x2f, 0xc1, 0x0c, 0x98, 0xf2, 0xf0, 0x06, - 0xec, 0x22, 0xcc, 0xb5, 0xa8, 0xc8, 0xb7, 0xc4, 0x0c, 0x7c, 0x2d, 0x49, 0xa6, 0x63, - 0x9b, 0x9f, 0x2c, 0xe3, 0x3c, 0x25, 0xc0, 0x4b, 0xc4, 0x61, 0xe7, 0x44, 0xdf, 0xa5, - 0x36, 0xb0, 0x0d, 0x94, 0xba, 0xdd, 0xf4, 0xf4, 0xd1, 0x40, 0x44, 0xc6, 0x95, 0xa3, - 0x38, 0x81, 0x47, 0x7d, 0xf1, 0x24, 0xf0, 0xfc, 0xf2, 0x06, 0xa9, 0xfb, 0x2e, 0x65, - 0xe3, 0x04, 0xcd, 0xbf, 0x0c, 0x4d, 0x23, 0x90, 0x17, 0x0c, 0x13, 0x0a, 0xb8, 0x49, - 0xc2, 0xf2, 0x2b, 0x5c, 0xdd, 0x39, 0x21, 0x64, 0x0c, 0x8c, 0xf1, 0x97, 0x6a, 0xe1, - 0x01, 0x0b, 0x0d, 0xfd, 0x9c, 0xb2, 0x54, 0x3e, 0x45, 0xf9, 0x97, 0x49, 0xcc, 0x4d, - 0x61, 0xf2, 0xe8, 0xaa, 0xbf, 0xe9, 0x8b, 0xd9, 0x05, 0xfa, 0x39, 0x95, 0x1b, 0x33, - 0xea, 0x76, 0x9c, 0x45, 0xab, 0x95, 0x31, 0xc5, 0x72, 0x09, 0x86, 0x2a, 0xd1, 0x2f, - 0xd7, 0x6b, 0xa4, 0x80, 0x7e, 0x65, 0x41, 0x7b, 0x6c, 0xd1, 0x2f, 0xa8, 0xec, 0x91, - 0x6f, 0x01, 0x3e, 0xbb, 0x87, 0x06, 0xa9, 0x6e, 0xff, 0xed, 0xa0, 0x6c, 0x4b, 0xe2, - 0x4b, 0x04, 0x84, 0x63, 0x92, 0xe9, 0xd1, 0xe6, 0x93, 0x0e, 0xae, 0x01, 0xfa, 0x21, - 0xfb, 0xd7, 0x00, 0x58, 0x3f, 0xb5, 0x98, 0xb9, 0x2c, 0x8f, 0x4e, 0xb8, 0xa6, 0x1a, - 0xa6, 0x23, 0x5d, 0xb6, 0x0f, 0x28, 0x41, 0xcf, 0x3a, 0x1c, 0x6a, 0xb5, 0x4c, 0x67, - 0x06, 0x68, 0x44, 0x71, 0x1d, 0x09, 0x1e, 0xb9, 0x31, 0xa1, 0xbd, 0x62, 0x81, 0xae, - 0xdf, 0x2a, 0x0e, 0x8f, 0xab, 0x18, 0x81, 0x72, 0x02, 0xa9, 0xbe, 0x06, 0x40, 0x2e, - 0xd9, 0xcc, 0x72, 0x0c, 0x16, 0xbf, 0xe8, 0x81, 0xe4, 0xdf, 0x42, 0x55, 0xe8, 0x7a, - 0xfb, 0x7f, 0xc6, 0x2f, 0x38, 0x11, 0x6b, 0xbe, 0x03, 0xcd, 0x8a, 0x3c, 0xb1, 0x1a, - 0x27, 0xd5, 0x68, 0x41, 0x47, 0x82, 0xf4, 0x7b, 0x1a, 0x44, 0xc9, 0x7c, 0x68, 0x04, - 0x67, 0x69, 0x4b, 0xc9, 0x70, 0x9d, 0x32, 0x91, 0x6c, 0x97, 0xe8, 0x00, 0x6c, 0xbb, - 0x07, 0xba, 0x0e, 0x41, 0x80, 0xa3, 0x73, 0x80, 0x38, 0xc3, 0x74, 0xc4, 0xcc, 0xe8, - 0xf3, 0x29, 0x59, 0xaf, 0xb2, 0x5f, 0x30, 0x3f, 0x58, 0x15, 0xc4, 0x53, 0x31, 0x24, - 0xac, 0xf9, 0xd1, 0x89, 0x40, 0xe7, 0x75, 0x22, 0xac, 0x5d, 0xc4, 0xb9, 0x57, 0x0a, - 0xae, 0x8f, 0x47, 0xb7, 0xf5, 0x7f, 0xd8, 0x76, 0x7b, 0xea, 0x1a, 0x24, 0xae, 0x7b, - 0xed, 0x65, 0xb4, 0xaf, 0xdc, 0x8f, 0x12, 0x78, 0xc3, 0x0e, 0x2d, 0xb9, 0x8f, 0xd1, - 0x72, 0x73, 0x0a, 0xc6, 0xbb, 0xed, 0x4f, 0x11, 0x27, 0xcd, 0x32, 0xb0, 0x4a, 0x95, - 0xb2, 0x05, 0x52, 0x6c, 0xfc, 0xb4, 0xc4, 0xe1, 0xcc, 0x95, 0x51, 0x75, 0xb3, 0xe8, - 0xde, 0x1f, 0x5d, 0x81, 0xb1, 0x86, 0x69, 0x69, 0x23, 0x50, 0xaa, 0xa1, 0xa1, 0xd7, - 0x97, 0x61, 0x75, 0x82, 0xe5, 0x4d, 0x7a, 0x5b, 0x57, 0xa6, 0x83, 0xb3, 0x2f, 0xb1, - 0x09, 0x80, 0x62, 0xda, 0xd7, 0xb0, 0xc2, 0xeb, 0x51, 0x8f, 0x68, 0x62, 0xe8, 0x3d, - 0xb2, 0x5e, 0x3d, 0xba, 0xf7, 0xae, 0xd5, 0x04, 0xde, 0x93, 0x2a, 0xcb, 0x99, 0xd7, - 0x35, 0x99, 0x2c, 0xe6, 0x2b, 0xae, 0x9e, 0xf8, 0x93, 0xff, 0x6a, 0xcc, 0x0f, 0xfc, - 0xf8, 0xe3, 0x48, 0x3e, 0x14, 0x6b, 0x9d, 0x49, 0xdd, 0x8c, 0x78, 0x35, 0xf4, 0x3a, - 0x37, 0xdc, 0xa0, 0x78, 0x7e, 0x3e, 0xc9, 0xf6, 0x60, 0x52, 0x23, 0xd5, 0xba, 0x7a, - 0xe0, 0xab, 0x90, 0x25, 0xb7, 0x3b, 0xc0, 0x3f, 0x7f, 0xac, 0x36, 0xc0, 0x09, 0xa5, - 0x6d, 0x4d, 0x95, 0xd1, 0xe8, 0x1d, 0x3b, 0x3e, 0xbc, 0xa7, 0xe5, 0x4c, 0xc1, 0xa1, - 0x2d, 0x12, 0x7b, 0x57, 0xc8, 0x13, 0x89, 0x76, 0xe7, 0x91, 0x01, 0x3b, 0x01, 0x5f, - 0x06, 0xa6, 0x24, 0xf5, 0x21, 0xb6, 0xee, 0x04, 0xec, 0x98, 0x08, 0x93, 0xc7, 0xe5, - 0xe0, 0x1a, 0x33, 0x62, 0x03, 0x59, 0x40, 0x94, 0xf8, 0x28, 0x33, 0xd7, 0x44, 0x5f, - 0xe2, 0xd0, 0x91, 0x30, 0xf6, 0x35, 0x11, 0xda, 0x54, 0x83, 0x2d, 0xe9, 0x13, 0x6b, - 0x39, 0xf4, 0x59, 0x9f, 0x5a, 0xa5, 0xdf, 0xbb, 0x45, 0xda, 0x60, 0xcd, 0xce, 0xab, - 0x7e, 0xef, 0xde, 0x89, 0xbe, 0x63, 0xf3, 0xf7, 0xc0, 0xd2, 0x32, 0x48, 0x47, 0xcc, - 0xe1, 0x40, 0x5d, 0xef, 0x7c, 0x46, 0x9b, 0x0e, 0x27, 0x24, 0x94, 0xe5, 0xdf, 0x54, - 0xf5, 0x68, 0x65, 0x6c, 0xb9, 0xc8, 0x81, 0x8d, 0x92, 0xb7, 0x2b, 0x8b, 0xc3, 0x4d, - 0xb7, 0xbb, 0x31, 0x12, 0x48, 0x7e, 0x74, 0x6e, 0xef, 0xe4, 0xe8, 0x08, 0xbb, 0xb2, - 0x87, 0xd9, 0x9b, 0xf0, 0x7d, 0x00, 0xda, 0xbe, 0xde, 0xdc, 0x5e, 0x5f, 0x07, 0x4f, - 0xfe, 0xae, 0x0c, 0xba, 0x7d, 0xa3, 0xa5, 0x16, 0xc1, 0x73, 0xbe, 0x1c, 0x51, 0x33, - 0x23, 0xe1, 0x19, 0xf6, 0x35, 0xe8, 0x20, 0x9a, 0x07, 0x4b, 0x21, 0x6b, 0x70, 0x23, - 0xfa, 0xdc, 0x2d, 0x25, 0x94, 0x9c, 0x90, 0x03, 0x7e, 0x71, 0xe3, 0xe5, 0x50, 0x72, - 0x6d, 0x21, 0x0a, 0x2c, 0x68, 0x83, 0x42, 0xe5, 0x24, 0x40, 0x63, 0x5e, 0x9c, 0xc1, - 0x4a, 0xfe, 0x10, 0x10, 0x26, 0x21, 0xa9, 0xc9, 0xac, 0xcb, 0x78, 0x2e, 0x9e, 0x4a, - 0x5f, 0xa8, 0x7f, 0x0a, 0x95, 0x6f, 0x5b, 0x85, 0x50, 0x99, 0x60, 0x28, 0x5c, 0x22, - 0x62, 0x7c, 0x59, 0x48, 0x3a, 0x5a, 0x4c, 0x28, 0xcc, 0xe4, 0xb1, 0x56, 0xe5, 0x51, - 0x40, 0x6a, 0x7e, 0xe8, 0x35, 0x56, 0x56, 0xa2, 0x1e, 0x43, 0xe3, 0x8c, 0xe1, 0x29, - 0xfd, 0xad, 0xb7, 0x59, 0xed, 0xdf, 0xa0, 0x8f, 0x00, 0xfc, 0x8e, 0x56, 0x7c, 0xef, - 0x93, 0xc6, 0x79, 0x2d, 0x01, 0xdf, 0x05, 0xe6, 0xd5, 0x80, 0xf4, 0xd5, 0xd4, 0x8d, - 0xf0, 0x42, 0x45, 0x1a, 0x33, 0x59, 0x0d, 0x3e, 0x8c, 0xf4, 0x9b, 0x26, 0x27, 0x21, - 0x8f, 0x0c, 0x29, 0x2f, 0xa6, 0x6a, 0xda, 0x94, 0x5f, 0xa5, 0x5b, 0xb2, 0x35, 0x48, - 0xe3, 0x3a, 0x83, 0xa5, 0x62, 0x95, 0x7a, 0x31, 0x49, 0xa9, 0x93, 0xcc, 0x47, 0x23, - 0x62, 0x29, 0x87, 0x36, 0xa8, 0xb7, 0x78, 0xd9, 0x7c, 0xe4, 0x23, 0x01, 0x3d, 0x64, - 0xb3, 0x2c, 0xd1, 0x72, 0xef, 0xa5, 0x51, 0xbf, 0x7f, 0x36, 0x8f, 0x04, 0xbd, 0xae, - 0xc6, 0x09, 0x1a, 0x30, 0x04, 0xa7, 0x57, 0x59, 0x8b, 0x80, 0x1d, 0xcf, 0x67, 0x5c, - 0xb8, 0x3e, 0x43, 0xa5, 0x3a, 0xe8, 0xb2, 0x54, 0xd3, 0x33, 0xbc, 0xda, 0x20, 0xd4, - 0x81, 0x7d, 0x34, 0x77, 0xab, 0xfb, 0xa2, 0x5b, 0xb8, 0x3d, 0xf5, 0x94, 0x9c, 0x12, - 0x6f, 0x14, 0x9b, 0x1d, 0x99, 0x34, 0x1e, 0x4e, 0x6f, 0x91, 0x20, 0xf4, 0xd4, 0x1e, - 0x62, 0x91, 0x85, 0x00, 0x2c, 0x72, 0xc0, 0x12, 0xc4, 0x14, 0xd2, 0x38, 0x2a, 0x6d, - 0x47, 0xc7, 0xb3, 0xde, 0xab, 0xa7, - ], - script_code: vec![0xac, 0x00], - transparent_input: Some(0), - hash_type: 3, - amount: 711752082734717, - consensus_branch_id: 1537743641, - sighash: [ - 0xb3, 0x8e, 0x31, 0x70, 0x8c, 0xb7, 0x8e, 0xee, 0xc7, 0x66, 0x3e, 0xca, 0x1e, 0x01, - 0xb7, 0x53, 0x9e, 0x26, 0xb7, 0x30, 0xcf, 0x44, 0x6d, 0x3b, 0xf5, 0x7a, 0x99, 0x8e, - 0x9e, 0xd9, 0x2b, 0x47, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x00, 0x02, 0x0d, 0x38, 0x6a, 0xe3, - 0x0d, 0xd3, 0x01, 0x00, 0x07, 0x00, 0x65, 0x51, 0x65, 0x53, 0x53, 0x6a, 0xd5, 0x09, - 0x42, 0xf7, 0x69, 0x67, 0x02, 0x00, 0x05, 0xac, 0x65, 0x63, 0x65, 0xac, 0x61, 0xa7, - 0xb8, 0xb9, 0xf6, 0x99, 0xd6, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x49, 0x23, 0x2f, 0x32, - 0x9f, 0xef, 0x95, 0xc7, 0xaf, 0x37, 0x00, 0x98, 0xff, 0xe4, 0x91, 0x8e, 0x0c, 0xa1, - 0xdf, 0x47, 0xf2, 0x75, 0x86, 0x7b, 0x73, 0x9e, 0x0a, 0x51, 0x4d, 0x32, 0x09, 0x32, - 0x5e, 0x21, 0x70, 0x45, 0x92, 0x7b, 0x47, 0x9c, 0x1c, 0xe2, 0xe5, 0xd5, 0x4f, 0x25, - 0x48, 0x8c, 0xad, 0x15, 0x13, 0xe3, 0xf4, 0x4a, 0x21, 0x26, 0x6c, 0xfd, 0x84, 0x16, - 0x33, 0x32, 0x7d, 0xee, 0x6c, 0xf8, 0x10, 0xfb, 0xf7, 0x39, 0x3e, 0x31, 0x7d, 0x9e, - 0x53, 0xd1, 0xbe, 0x1d, 0x5a, 0xe7, 0x83, 0x9b, 0x66, 0xb9, 0x43, 0xb9, 0xed, 0x18, - 0xf2, 0xc5, 0x30, 0xe9, 0x75, 0x42, 0x23, 0x32, 0xc3, 0x43, 0x9c, 0xce, 0x49, 0xa2, - 0x9f, 0x2a, 0x33, 0x6a, 0x48, 0x51, 0x26, 0x3c, 0x5e, 0x9b, 0xd1, 0x3d, 0x73, 0x11, - 0x09, 0xe8, 0x44, 0xb7, 0xf8, 0xc3, 0x92, 0xa5, 0xc1, 0xdc, 0xaa, 0x2a, 0xe5, 0xf5, - 0x0f, 0xf6, 0x3f, 0xab, 0x97, 0x65, 0xe0, 0x16, 0x70, 0x2c, 0x35, 0xa6, 0x7c, 0xd7, - 0x36, 0x4d, 0x3f, 0xab, 0x55, 0x2f, 0xb3, 0x49, 0xe3, 0x5c, 0x15, 0xc5, 0x02, 0x50, - 0x45, 0x3f, 0xd1, 0x8f, 0x7b, 0x85, 0x59, 0x92, 0x63, 0x2e, 0x2c, 0x76, 0xc0, 0xfb, - 0xf1, 0xef, 0x96, 0x3e, 0xa8, 0x0e, 0x32, 0x23, 0xde, 0x32, 0x77, 0xbc, 0x55, 0x92, - 0x51, 0x72, 0x58, 0x29, 0xec, 0x03, 0xf2, 0x13, 0xba, 0x89, 0x55, 0xca, 0xb2, 0x82, - 0x2f, 0xf2, 0x1a, 0x9b, 0x0a, 0x49, 0x04, 0xd6, 0x68, 0xfc, 0xd7, 0x72, 0x24, 0xbd, - 0xe3, 0xdd, 0x01, 0xf6, 0xff, 0xc4, 0x82, 0x8f, 0x6b, 0x64, 0x23, 0x0b, 0x35, 0xc6, - 0xa0, 0x49, 0x87, 0x34, 0x94, 0x27, 0x6e, 0xa1, 0xd7, 0xed, 0x5e, 0x92, 0xcb, 0x4f, - 0x90, 0xba, 0x83, 0xa9, 0xe4, 0x96, 0x01, 0xb1, 0x94, 0x04, 0x2f, 0x29, 0x00, 0xd9, - 0x9d, 0x31, 0x2d, 0x7b, 0x70, 0x50, 0x8c, 0xf1, 0x76, 0x06, 0x6d, 0x15, 0x4d, 0xbe, - 0x96, 0xef, 0x9d, 0x43, 0x67, 0xe4, 0xc8, 0x40, 0xe4, 0xa1, 0x7b, 0x5e, 0x51, 0x22, - 0xe8, 0xeb, 0xe2, 0x03, 0x8a, 0x3c, 0x5f, 0x4c, 0xba, 0xe2, 0x1e, 0xa3, 0xfa, 0x1a, - 0xe6, 0xc2, 0x5a, 0x94, 0x62, 0xeb, 0xcb, 0xb0, 0xfd, 0x5f, 0x14, 0x55, 0x4b, 0xc9, - 0x77, 0x47, 0xc3, 0x3e, 0x34, 0xda, 0x90, 0xc8, 0x02, 0xd8, 0xd0, 0xd5, 0x0b, 0xfe, - 0x37, 0x61, 0x8c, 0x58, 0x12, 0x89, 0x14, 0x84, 0xfa, 0x25, 0x93, 0x22, 0xc1, 0x50, - 0x92, 0xd4, 0x15, 0x5d, 0x86, 0x96, 0xd6, 0xf1, 0x2f, 0x24, 0xfd, 0x36, 0x44, 0x0a, - 0xb3, 0xbe, 0x08, 0x71, 0xca, 0x3d, 0xd9, 0x62, 0x53, 0x48, 0xa6, 0x14, 0xb5, 0x9b, - 0xde, 0x45, 0x88, 0x56, 0x49, 0xba, 0xe3, 0x6d, 0xe3, 0x4d, 0xef, 0x8f, 0xce, 0xc8, - 0x53, 0x43, 0x47, 0x5d, 0x97, 0x6a, 0xe1, 0xe9, 0xb2, 0x78, 0x29, 0xce, 0x2a, 0xc5, - 0xef, 0xd0, 0xb3, 0x99, 0xa8, 0xb4, 0x48, 0xbe, 0x65, 0x04, 0x29, 0x4e, 0xe6, 0xb3, - 0xc1, 0xc6, 0xa5, 0x34, 0x2d, 0x7c, 0x01, 0xae, 0x03, 0x8a, 0xd3, 0x07, 0x0c, 0x2b, - 0x1a, 0x91, 0x57, 0x3a, 0xf5, 0xe0, 0xc5, 0xe4, 0xcb, 0xbf, 0x4a, 0xcd, 0xc6, 0xb5, - 0x4c, 0x92, 0x72, 0x20, 0x0d, 0x99, 0x70, 0x25, 0x0c, 0x17, 0xc1, 0x03, 0x6f, 0x02, - 0x08, 0x5c, 0x41, 0x85, 0x8e, 0xd3, 0xa0, 0xc4, 0x81, 0x50, 0xbc, 0x69, 0x7e, 0x4a, - 0x69, 0x5f, 0xef, 0x33, 0x5f, 0x7a, 0xd0, 0x7e, 0x1a, 0x46, 0xdc, 0x76, 0x7f, 0xf8, - 0x22, 0xdb, 0x70, 0xe6, 0x02, 0x90, 0x80, 0xb9, 0x81, 0x6b, 0x22, 0x32, 0xc8, 0x1a, - 0x4c, 0x66, 0xcc, 0x58, 0x6a, 0xbf, 0xe1, 0xea, 0xa8, 0xca, 0x6c, 0xf4, 0x1f, 0xc3, - 0xc3, 0xe6, 0xc7, 0xb8, 0x86, 0xfb, 0x6d, 0xac, 0x9f, 0x02, 0x22, 0xb4, 0xfc, 0x6f, - 0xff, 0x9d, 0x05, 0x13, 0xd6, 0x1a, 0x21, 0xc8, 0x0a, 0x37, 0x76, 0x71, 0xd1, 0x35, - 0xa6, 0x68, 0xa0, 0xae, 0x2b, 0xb9, 0x34, 0xc8, 0x2c, 0x41, 0x42, 0xda, 0x69, 0xd1, - 0x02, 0xa7, 0xde, 0x9a, 0x7d, 0xf7, 0x06, 0x40, 0x0e, 0xc7, 0x98, 0x78, 0xd8, 0x68, - 0xe1, 0x7e, 0x8f, 0x71, 0xea, 0x31, 0x49, 0x5a, 0xf8, 0x19, 0xa0, 0x16, 0xcc, 0x41, - 0x9e, 0x07, 0xc5, 0x01, 0xaa, 0x83, 0x09, 0xb2, 0xe6, 0xc8, 0x5b, 0x79, 0xb2, 0x76, - 0x37, 0x33, 0xa3, 0x7b, 0xbc, 0x04, 0x20, 0xd4, 0x25, 0x37, 0xb8, 0x71, 0xb4, 0x29, - 0x4a, 0x65, 0xd3, 0xe0, 0x55, 0xff, 0x71, 0x8d, 0xd9, 0xdc, 0x8c, 0x75, 0xe7, 0xe5, - 0xb2, 0xef, 0xe4, 0x42, 0x63, 0x73, 0x71, 0xb7, 0xc4, 0x8f, 0x6e, 0xe9, 0x9e, 0x3e, - 0xa3, 0x8a, 0x4b, 0x0f, 0x2f, 0x67, 0xfc, 0x2b, 0x90, 0x8c, 0xda, 0x65, 0x7e, 0xae, - 0x75, 0x4e, 0x03, 0x7e, 0x26, 0x2e, 0x9a, 0x9f, 0x9b, 0xd7, 0xec, 0x42, 0x67, 0xed, - 0x8e, 0x96, 0x93, 0x0e, 0x10, 0x84, 0x78, 0x3c, 0x37, 0xd6, 0xf9, 0xdd, 0x15, 0xfd, - 0x29, 0xf4, 0xcc, 0x47, 0x7e, 0x66, 0xf1, 0x30, 0xd6, 0x30, 0x43, 0x0d, 0xcc, 0x01, - 0x04, 0x89, 0x9b, 0x4f, 0x9f, 0x46, 0xeb, 0x09, 0x0e, 0xf7, 0xfc, 0x90, 0xb4, 0x79, - 0xab, 0xf6, 0x1f, 0x93, 0x95, 0x5e, 0xe0, 0x0e, 0x6a, 0x18, 0x48, 0xf1, 0xab, 0x14, - 0xad, 0x33, 0x4f, 0x2b, 0x68, 0x03, 0x58, 0x08, 0xcd, 0xf1, 0xbb, 0x9e, 0x9d, 0x9a, - 0x81, 0x6b, 0xaf, 0x72, 0x8a, 0x95, 0x5b, 0x96, 0x0b, 0x77, 0x01, 0xfa, 0x62, 0x66, - 0x87, 0xdc, 0x3c, 0x9c, 0xba, 0x64, 0x63, 0x37, 0xb5, 0x3e, 0x29, 0x81, 0x6e, 0x94, - 0x82, 0xdd, 0xf5, 0x57, 0x8a, 0x87, 0x68, 0xaa, 0xe4, 0x77, 0xfc, 0xe4, 0x10, 0xac, - 0x2d, 0x5d, 0xe6, 0x09, 0x58, 0x61, 0xc1, 0x11, 0xd7, 0xfe, 0xb3, 0xe6, 0xbb, 0x4f, - 0xbb, 0x5a, 0x54, 0x95, 0x54, 0x95, 0x97, 0x27, 0x98, 0x35, 0x0a, 0x25, 0x3f, 0x05, - 0xf6, 0x6c, 0x2e, 0xcf, 0xcb, 0xc0, 0xed, 0x43, 0xf5, 0xec, 0x2e, 0x6d, 0x8d, 0xba, - 0x15, 0xa5, 0x12, 0x54, 0xd9, 0x7b, 0x18, 0x21, 0x10, 0x7c, 0x07, 0xdd, 0x9a, 0x16, - 0xef, 0x84, 0x06, 0xf9, 0x43, 0xe2, 0x82, 0xb9, 0x5d, 0x4b, 0x36, 0x25, 0x30, 0xc9, - 0x13, 0xd6, 0xba, 0x42, 0x1d, 0xf6, 0x02, 0x7d, 0xe5, 0xaf, 0x1e, 0x47, 0x45, 0xd5, - 0x86, 0x81, 0x06, 0x95, 0x4b, 0xe6, 0xc1, 0x96, 0x27, 0x80, 0xa2, 0x94, 0x10, 0x72, - 0xe9, 0x51, 0x31, 0xb1, 0x67, 0x9d, 0xf0, 0x63, 0x76, 0x25, 0x04, 0x2c, 0x37, 0xd4, - 0x8f, 0xfb, 0x15, 0x2e, 0x5e, 0xbc, 0x18, 0x5c, 0x8a, 0x2b, 0x7d, 0x43, 0x85, 0xf1, - 0xc9, 0x5a, 0xf9, 0x37, 0xdf, 0x78, 0xdf, 0xd8, 0x75, 0x7f, 0xab, 0x43, 0x49, 0x68, - 0xb0, 0xb5, 0x7c, 0x66, 0x57, 0x44, 0x68, 0xf1, 0x60, 0xb4, 0x47, 0xac, 0x82, 0x21, - 0xe5, 0x06, 0x06, 0x76, 0xa8, 0x42, 0xa1, 0xc6, 0xb7, 0x17, 0x2d, 0xd3, 0x34, 0x0f, - 0x76, 0x40, 0x70, 0xab, 0x1f, 0xe0, 0x91, 0xc5, 0xc7, 0x4c, 0x95, 0xa5, 0xdc, 0x04, - 0x33, 0x90, 0x72, 0x3a, 0x4c, 0x12, 0x7d, 0xa1, 0x4c, 0xdd, 0xe1, 0xdc, 0x26, 0x75, - 0xa6, 0x23, 0x40, 0xb3, 0xe6, 0xaf, 0xd0, 0x52, 0x2a, 0x31, 0xde, 0x26, 0xe7, 0xd1, - 0xec, 0x3a, 0x9c, 0x8a, 0x09, 0x1f, 0xfd, 0xc7, 0x5b, 0x7e, 0xcf, 0xdc, 0x7c, 0x12, - 0x99, 0x5a, 0x5e, 0x37, 0xce, 0x34, 0x88, 0xbd, 0x29, 0xf8, 0x62, 0x9d, 0x68, 0xf6, - 0x96, 0x49, 0x24, 0x48, 0xdd, 0x52, 0x66, 0x97, 0x47, 0x6d, 0xc0, 0x61, 0x34, 0x6e, - 0xbe, 0x3f, 0x67, 0x72, 0x17, 0xff, 0x9c, 0x60, 0xef, 0xce, 0x94, 0x3a, 0xf2, 0x8d, - 0xfd, 0x3f, 0x9e, 0x59, 0x69, 0x25, 0x98, 0xa6, 0x04, 0x7c, 0x23, 0xc4, 0xc0, 0x14, - 0x00, 0xf1, 0xab, 0x57, 0x30, 0xea, 0xc0, 0xae, 0x8d, 0x58, 0x43, 0xd5, 0x05, 0x1c, - 0x37, 0x62, 0x40, 0x17, 0x2a, 0xf2, 0x18, 0xd7, 0xa1, 0xec, 0xfe, 0x65, 0xb4, 0xf7, - 0x51, 0x00, 0x63, 0x89, 0x83, 0xc1, 0x4d, 0xe4, 0x97, 0x47, 0x55, 0xda, 0xde, 0x80, - 0x18, 0xc9, 0xb8, 0xf4, 0x54, 0x3f, 0xb0, 0x95, 0x96, 0x15, 0x13, 0xe6, 0x7c, 0x61, - 0xdb, 0xc5, 0x9c, 0x60, 0x7f, 0x9b, 0x51, 0xf8, 0xd0, 0x9b, 0xdc, 0xad, 0x28, 0xbc, - 0xfb, 0x9e, 0x5d, 0x27, 0x44, 0xea, 0x88, 0x48, 0xb2, 0x62, 0x3a, 0xc0, 0x7f, 0x8e, - 0xf6, 0x1a, 0x81, 0xa3, 0x59, 0x10, 0xb8, 0xa1, 0xba, 0xf3, 0x9a, 0x91, 0x9a, 0x7b, - 0x60, 0xbc, 0x60, 0x4d, 0x63, 0x18, 0x5f, 0x75, 0x92, 0x21, 0xd8, 0x47, 0xcc, 0x54, - 0xa2, 0x27, 0x65, 0xa4, 0xc3, 0x34, 0x75, 0xb5, 0x79, 0x1e, 0x9a, 0xf3, 0x27, 0x1f, - 0xc8, 0xd9, 0x35, 0x06, 0x67, 0x09, 0x0d, 0x81, 0x84, 0xec, 0x50, 0x52, 0x2d, 0x80, - 0x4f, 0x23, 0xc4, 0xfb, 0x44, 0xff, 0xa4, 0x81, 0xbc, 0x92, 0xae, 0x40, 0x8d, 0x1b, - 0x9f, 0x2b, 0x13, 0x19, 0x04, 0xf9, 0x70, 0x5c, 0x59, 0xe2, 0xf4, 0xbd, 0xe7, 0xa3, - 0xb2, 0xc0, 0x85, 0xd9, 0x3f, 0xd2, 0xab, 0xc5, 0xe1, 0x4d, 0x16, 0x30, 0x01, 0xa1, - 0x2f, 0x51, 0x93, 0x8d, 0x02, 0x1a, 0xfa, 0x92, 0x23, 0x9b, 0x87, 0x3d, 0xc6, 0xc3, - 0x57, 0xea, 0xa8, 0xaf, 0x4e, 0xe6, 0xd0, 0x05, 0x40, 0x65, 0x7f, 0xe3, 0x29, 0x14, - 0x10, 0x3b, 0x5d, 0x98, 0xf6, 0x8b, 0xd3, 0xe2, 0xb5, 0x35, 0x9f, 0x08, 0xcc, 0xd8, - 0x8d, 0x0c, 0x81, 0x1e, 0x4c, 0x31, 0xfb, 0xb4, 0x9f, 0x3a, 0x90, 0xbb, 0xd0, 0x5d, - 0xce, 0x62, 0xf3, 0x44, 0xe7, 0x07, 0x75, 0x93, 0x15, 0x9a, 0xe3, 0x50, 0x50, 0xb0, - 0x4c, 0x9e, 0x6b, 0x86, 0xbc, 0x43, 0x2d, 0xc8, 0xb0, 0x48, 0xc7, 0x3c, 0x00, 0x18, - 0xca, 0x5b, 0x69, 0x41, 0x12, 0x97, 0x73, 0x2a, 0x4e, 0x1a, 0xa9, 0x9a, 0x92, 0x8c, - 0x71, 0xe7, 0xa2, 0x4f, 0xd2, 0x77, 0x85, 0x6a, 0xa4, 0x25, 0x01, 0xe5, 0x1b, 0x01, - 0x2a, 0xea, 0x94, 0x46, 0xa2, 0x10, 0x4e, 0x93, 0xf8, 0x15, 0xa0, 0xb3, 0xa2, 0x9b, - 0x45, 0x83, 0x14, 0xf3, 0xd8, 0xbe, 0x2b, 0x98, 0x23, 0xd3, 0x42, 0xf4, 0x62, 0x13, - 0xe9, 0x42, 0xa7, 0xe1, 0x9a, 0x46, 0xe9, 0x70, 0xb5, 0xc5, 0x06, 0x70, 0x84, 0x30, - 0x31, 0x7b, 0x1b, 0xb3, 0xb3, 0x5d, 0xf6, 0x8a, 0xe3, 0x3a, 0x49, 0x26, 0xa0, 0x3e, - 0x6b, 0xfe, 0xb5, 0x51, 0x04, 0x16, 0xfc, 0xbb, 0x05, 0x24, 0xc9, 0xca, 0x50, 0x74, - 0x15, 0x6c, 0xc5, 0xa5, 0xd6, 0xfe, 0x1c, 0x99, 0x5e, 0xdc, 0x60, 0xa2, 0xf5, 0x50, - 0x41, 0x1a, 0xa4, 0x1e, 0x3d, 0xa3, 0xbd, 0xcf, 0x64, 0xbc, 0xf0, 0x4a, 0x05, 0x10, - 0x57, 0x1b, 0x93, 0x6d, 0x47, 0xe5, 0x5c, 0xec, 0x03, 0x30, 0xee, 0x8d, 0xfe, 0x73, - 0x56, 0x34, 0x04, 0xf0, 0x47, 0xd7, 0xf3, 0xa8, 0xa3, 0xd7, 0x74, 0x3b, 0xc5, 0x54, - 0x95, 0x52, 0x10, 0xf1, 0xeb, 0x0d, 0x08, 0x59, 0x9e, 0xa7, 0x7d, 0x5f, 0x97, 0x4d, - 0x87, 0x17, 0x6d, 0x37, 0xd9, 0x8b, 0x9c, 0x0a, 0xd4, 0x40, 0x40, 0x72, 0x09, 0xed, - 0x6a, 0x9f, 0x08, 0x46, 0x4d, 0x56, 0x55, 0x93, 0xe1, 0xa6, 0x3b, 0x93, 0x85, 0x36, - 0xb4, 0x92, 0x44, 0xe9, 0x7d, 0x88, 0x01, 0x73, 0xb6, 0x40, 0xf2, 0xdd, 0xb7, 0x4d, - 0x06, 0x8e, 0xcb, 0x46, 0xcf, 0x28, 0x9b, 0x7d, 0x89, 0x13, 0x07, 0xbb, 0xa3, 0x70, - 0x54, 0xcf, 0x91, 0xb3, 0x1f, 0xc8, 0x2f, 0x74, 0xd5, 0xfc, 0xc0, 0x00, 0x94, 0x2e, - 0xde, 0x91, 0x18, 0x25, 0xf5, 0x3f, 0xe6, 0x09, 0x68, 0x6f, 0x46, 0x32, 0x23, 0xb1, - 0xe9, 0xbc, 0x03, 0xbd, 0xe8, 0x95, 0xd1, 0x23, 0x8f, 0xad, 0x04, 0xa3, 0xbf, 0xce, - 0x68, 0xa0, 0x75, 0xe8, 0xa3, 0x7c, 0x0e, 0x87, 0xbf, 0x46, 0xdd, 0x01, 0x55, 0x45, - 0xf9, 0xb4, 0xfb, 0x0e, 0xec, 0x64, 0x5f, 0xfc, 0xbb, 0xe0, 0xca, 0x5f, 0x8c, 0x56, - 0x1b, 0x25, 0x7d, 0x52, 0xd6, 0x02, 0xd8, 0xc9, 0x4c, 0x50, 0x28, 0x73, 0xa0, 0x1d, - 0x92, 0x51, 0xd8, 0xc8, 0x60, 0xc0, 0x41, 0x52, 0x5b, 0x3b, 0xf4, 0xe3, 0xa2, 0xeb, - 0x92, 0x72, 0x81, 0x5c, 0x75, 0x86, 0x76, 0x84, 0x28, 0xb4, 0xc2, 0xb2, 0x5e, 0x37, - 0x45, 0xf0, 0x09, 0xc5, 0xdc, 0xe2, 0x0b, 0x69, 0xd5, 0xd7, 0xc4, 0x3c, 0xeb, 0x73, - 0x6b, 0x68, 0x31, 0xe8, 0xc1, 0x10, 0xf1, 0x6c, 0xfd, 0xb3, 0xa4, 0x67, 0xe9, 0x41, - 0x4c, 0x00, 0xec, 0xf1, 0x37, 0x31, 0x50, 0x08, 0x94, 0x55, 0x56, 0x78, 0xc4, 0x97, - 0xfa, 0xba, 0x9a, 0x95, 0xd0, 0x1c, 0xc4, 0x64, 0x39, 0x0f, 0xc4, 0xa7, 0x6b, 0xfa, - 0x8b, 0x0e, 0x1c, 0x68, 0xa5, 0x25, 0xd7, 0x06, 0xd6, 0x60, 0x4b, 0x23, 0x30, 0xb6, - 0xb3, 0x48, 0x52, 0x15, 0xf6, 0x06, 0xf1, 0x88, 0x3a, 0x75, 0x15, 0x88, 0xc7, 0xef, - 0xa5, 0x06, 0xc3, 0xe8, 0xd0, 0xc6, 0x01, 0x92, 0xe8, 0x47, 0x6b, 0xd1, 0x17, 0x5d, - 0x95, 0x62, 0x08, 0x7b, 0xdb, 0x81, 0x8e, 0x66, 0x21, 0x62, 0x86, 0xba, 0xfe, 0x47, - 0xff, 0x4d, 0xbc, 0xce, 0xd5, 0x14, 0x44, 0x48, 0x0a, 0x9a, 0x56, 0x73, 0xec, 0xe7, - 0xfa, 0xc7, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xd4, 0x1a, 0xb0, 0x05, 0x17, 0x53, 0xa7, 0xca, - 0xa8, 0x9b, 0xe3, 0x13, 0x9a, 0xfd, 0x97, 0x93, 0xb3, 0xe0, 0x2f, 0x27, 0xf0, 0x40, - 0x04, 0x65, 0x95, 0xac, 0xd4, 0x7b, 0xf1, 0x3f, 0xd0, 0xda, 0x27, 0xf0, 0x9e, 0xda, - 0x48, 0x03, 0x6d, 0x3e, 0xe4, 0x37, 0xf2, 0xee, 0x8f, 0x86, 0x06, 0xea, 0x97, 0x34, - 0x3c, 0x33, 0x58, 0x46, 0x57, 0xf4, 0x6d, 0xba, 0x99, 0xdb, 0x5c, 0xfe, 0x6c, 0xa1, - 0x76, 0xfa, 0xb7, 0xb0, 0xf3, 0xbf, 0xa0, 0xab, 0x61, 0xe3, 0x40, 0xc3, 0x4e, 0xb9, - 0xf1, 0x7c, 0x7e, 0xc2, 0xbe, 0x03, 0xb1, 0x80, 0xf0, 0xbb, 0x6f, 0x43, 0x4c, 0x2a, - 0x65, 0x42, 0xe0, 0x0e, 0x84, 0x37, 0x3f, 0x4f, 0x46, 0x49, 0xcd, 0xa3, 0x2b, 0xf6, - 0x86, 0x66, 0x61, 0x43, 0xf6, 0x22, 0xaa, 0x48, 0x04, 0x60, 0xb5, 0xaf, 0xac, 0x51, - 0x86, 0x07, 0xcd, 0x9a, 0xf8, 0xbc, 0xd6, 0xb5, 0x8c, 0x30, 0x12, 0x73, 0x16, 0xb2, - 0x5d, 0x5e, 0xa7, 0xbf, 0x6b, 0x0c, 0xab, 0x85, 0x42, 0xff, 0x69, 0xd9, 0xb2, 0xf1, - 0x80, 0xbe, 0x12, 0xed, 0x75, 0x34, 0x4a, 0x39, 0x5a, 0xa1, 0x0f, 0x85, 0x2f, 0x08, - 0x3a, 0xd6, 0x4e, 0xf4, 0x0e, 0x9c, 0x03, 0x09, 0xe9, 0xbb, 0xa5, 0x4b, 0x8c, 0xb3, - 0x3c, 0x95, 0x49, 0x8a, 0x69, 0x53, 0x8d, 0x3a, 0xe5, 0xb2, 0x5e, 0x24, 0x70, 0x98, - 0x30, 0x6f, 0xa8, 0xc7, 0x4a, 0x8e, 0xe5, 0xbc, 0xa9, 0x41, 0x53, 0x1d, 0x61, 0xaa, - 0xc2, 0x7a, 0xab, 0x3d, 0xc5, 0x61, 0x7d, 0x56, 0x06, 0xc9, 0x57, 0x7a, 0x2a, 0x83, - 0x46, 0xe8, 0xd8, 0x5b, 0x32, 0xb8, 0x50, 0x57, 0x75, 0x10, 0x8d, 0xc8, 0x5e, 0x2a, - 0xde, 0x2e, 0xac, 0x1e, 0x63, 0x6e, 0x1a, 0xf4, 0x05, 0x4c, 0x8b, 0x6f, 0x57, 0x63, - 0x2d, 0xf2, 0x69, 0xc3, 0x72, 0x3b, 0x32, 0x08, 0x72, 0xe4, 0xc5, 0x7b, 0x21, 0x83, - 0x58, 0xdc, 0x7e, 0x99, 0x05, 0xbb, 0x04, 0xed, 0xf9, 0x2e, 0xdf, 0x0d, 0xf6, 0x35, - 0xf3, 0xbf, 0x36, 0x1e, 0x57, 0xa1, 0x32, 0x96, 0xe1, 0x44, 0x7a, 0xf5, 0x08, 0x02, - 0x72, 0xd6, 0x36, 0xe2, 0x75, 0x18, 0xa9, 0x87, 0x6e, 0x15, 0xeb, 0x01, 0xf5, 0xe8, - 0xde, 0xd8, 0x18, 0x92, 0x51, 0x1c, 0xc2, 0x85, 0x1b, 0x00, 0xb8, 0x32, 0x71, 0x2a, - 0x6d, 0x3b, 0xa5, 0x66, 0x03, 0x17, 0xbc, 0xd3, 0x56, 0x76, 0x21, 0xa7, 0xcf, 0x84, - 0x45, 0x58, 0x96, 0x53, 0x26, 0x20, 0x20, 0xc3, 0x3b, 0xf7, 0x80, 0x31, 0xb8, 0xee, - 0x07, 0x07, 0xde, 0x07, 0x20, 0x68, 0xc1, 0x70, 0x57, 0x0b, 0x27, 0xe6, 0xd9, 0xf5, - 0xc6, 0xdd, 0xc3, 0x35, 0x40, 0x2e, 0xfc, 0x54, 0x88, 0x62, 0xf5, 0xa0, 0x70, 0x94, - 0xfd, 0x42, 0x8a, 0x7b, 0xbc, 0x15, 0xd7, 0xb3, 0x8d, 0x05, 0x36, 0x2c, 0x9c, 0xa9, - 0x85, 0xf5, 0x8a, 0x76, 0x64, 0x7d, 0x2b, 0xe4, 0xc2, 0xcd, 0x6b, 0x3d, 0x17, 0xd6, - 0x87, 0x09, 0x71, 0xd7, 0xa0, 0x98, 0xba, 0xf7, 0x2c, 0x6f, 0x6f, 0x12, 0x14, 0xcf, - 0x1f, 0xaa, 0xe4, 0x88, 0x03, 0x7d, 0xe2, 0x59, 0xd3, 0x41, 0x5c, 0x2f, 0x0d, 0xde, - 0xc7, 0x45, 0x70, 0x04, 0xf3, 0x57, 0x08, 0xd1, 0xec, 0xcc, 0xcc, 0x0d, 0xf6, 0x5a, - 0x04, 0x94, 0x3a, 0xd5, 0xcb, 0xc1, 0x3f, 0x29, 0x5f, 0x02, 0x0f, 0xe0, 0x56, 0xc4, - 0x0b, 0x2d, 0x88, 0xf2, 0x7d, 0xc3, 0x4c, 0xfe, 0xb8, 0x03, 0xbe, 0x34, 0x83, 0xa9, - 0xeb, 0xf9, 0xb5, 0xa9, 0x02, 0x60, 0x57, 0x72, 0x5d, 0x63, 0xea, 0xd2, 0xc0, 0xc0, - 0x03, 0x1f, 0xe2, 0x6a, 0xc1, 0xe7, 0xbd, 0xfc, 0xd6, 0xfa, 0xd8, 0x75, 0x84, 0x2d, - 0x19, 0x4f, 0x33, 0x17, 0x50, 0x46, 0x2c, 0x06, 0xb8, 0xd7, 0x98, 0x2d, 0x67, 0x99, - 0x5e, 0xd5, 0xd3, 0xae, 0x96, 0x02, 0x5a, 0xe0, 0x06, 0x7f, 0x4e, 0xb1, 0xc7, 0xc9, - 0x32, 0x31, 0xbd, 0x39, 0x77, 0x3c, 0xbe, 0x0a, 0x9d, 0x66, 0xb0, 0xc9, 0xaa, 0x8c, - 0xff, 0x6a, 0x37, 0x6e, 0x1f, 0x37, 0x2e, 0xac, 0x6a, 0xc4, 0x02, 0x6c, 0xc0, 0x94, - 0x22, 0x45, 0xd4, 0xc2, 0xdc, 0xf0, 0x2d, 0x76, 0x40, 0xff, 0xcc, 0x5a, 0x6a, 0xc3, - 0xa8, 0x7f, 0x5c, 0x41, 0x15, 0x51, 0xbc, 0xc2, 0xf2, 0x6c, 0xb9, 0x49, 0x61, 0xd5, - 0x3f, 0x95, 0xdd, 0xb1, 0x9a, 0xe9, 0x30, 0xc8, 0xd7, 0x0f, 0x03, 0x1b, 0x29, 0xa5, - 0xdf, 0x99, 0xff, 0x36, 0x69, 0x5e, 0x80, 0x2c, 0xbc, 0xb6, 0xb5, 0x8c, 0x1b, 0xa7, - 0xed, 0x5e, 0xac, 0xfa, 0x76, 0x41, 0x4a, 0x41, 0xad, 0x4a, 0x44, 0xf7, 0x1f, 0x1b, - 0x58, 0x0d, 0x34, 0xc3, 0xa9, 0x52, 0x92, 0x0b, 0x25, 0x4a, 0x14, 0x5f, 0xea, 0x51, - 0x7f, 0x5b, 0x42, 0xb2, 0xf6, 0x5e, 0xcd, 0x0f, 0x82, 0x59, 0x54, 0x78, 0xd8, 0x0a, - 0xe5, 0xc8, 0xce, 0xea, 0x12, 0xa1, 0x61, 0xcc, 0xbb, 0x5e, 0xac, 0x09, 0x99, 0x0f, - 0xc6, 0x19, 0xa4, 0x60, 0x80, 0x43, 0x6d, 0xbd, 0x08, 0xd7, 0x47, 0x84, 0xaf, 0x00, - 0x2d, 0x58, 0xe0, 0x6f, 0xaf, 0x7f, 0x3c, 0xea, 0xe7, 0xd3, 0x41, 0x9b, 0x1f, 0xca, - 0x26, 0x5a, 0x55, 0x59, 0xcf, 0x9e, 0x2d, 0x3b, 0x60, 0x97, 0x8d, 0x81, 0xa6, 0x78, - 0xb9, 0xed, 0x8e, 0x44, 0x86, 0xb4, 0xd1, 0x46, 0x09, 0xd6, 0xc1, 0x27, 0xc0, 0xc2, - 0xfb, 0xff, 0xe3, 0x0a, 0x60, 0xf7, 0xbf, 0xf1, 0xd9, 0xfb, 0x83, 0x00, 0xed, 0x00, - 0x92, 0x53, 0xba, 0x9b, 0x99, 0x6f, 0xa0, 0x52, 0x41, 0xb1, 0x0f, 0x5a, 0xc9, 0xa8, - 0x40, 0x8e, 0x92, 0x5b, 0x62, 0x6b, 0xb2, 0x1a, 0x47, 0x1f, 0xe3, 0xbe, 0xde, 0x52, - 0xbb, 0xa0, 0x97, 0xb2, 0xa9, 0x9a, 0x9b, 0xa5, 0xa8, 0x66, 0x58, 0xc3, 0xfd, 0x9e, - 0xc5, 0x5b, 0xfa, 0x9b, 0x32, 0x85, 0x67, 0x25, 0x4a, 0xb3, 0x6d, 0x2c, 0x7f, 0x44, - 0xd2, 0xc7, 0xe1, 0x3e, 0xb5, 0x4b, 0xeb, 0x70, 0xea, 0x8f, 0xa9, 0x4b, 0x6c, 0x6e, - 0x01, 0x2d, 0x79, 0xe3, 0xf5, 0x36, 0x89, 0xc2, 0xb1, 0xa1, 0x8e, 0xaf, 0x2d, 0x47, - 0x1d, 0x13, 0xc1, 0xab, 0x39, 0xd9, 0x19, 0x4a, 0xe8, 0x43, 0xab, 0x1d, 0x28, 0xff, - 0xa8, 0xf6, 0x9d, 0xc7, 0xe1, 0x5c, 0xc3, 0x8b, 0x12, 0xe8, 0xfc, 0xd7, 0x92, 0x55, - 0xb7, 0x21, 0x60, 0x56, 0xd9, 0xed, 0xb7, 0x48, 0x2f, 0xb9, 0x8a, 0xa0, 0x33, 0xb6, - 0x5e, 0x51, 0xc1, 0xa0, 0x8b, 0x8a, 0x11, 0xd8, 0x4d, 0x04, 0x09, 0xb7, 0x34, 0xf4, - 0x52, 0xaa, 0xf0, 0xd6, 0xb1, 0x8f, 0x50, 0x25, 0x86, 0x83, 0xd3, 0xf9, 0xa7, 0x6d, - 0x39, 0x9f, 0xd0, 0x47, 0xee, 0xe2, 0x88, 0xbb, 0x45, 0x85, 0x85, 0x1d, 0xc9, 0x3e, - 0xcc, 0xc6, 0x23, 0x22, 0x92, 0x4c, 0xd1, 0x3b, 0x5d, 0xd4, 0xee, 0xd6, 0x6e, 0xd8, - 0xd9, 0x97, 0x2d, 0x77, 0x26, 0x29, 0xea, 0x64, 0x74, 0x2e, 0x54, 0x73, 0x39, 0x81, - 0xb0, 0x06, 0xc0, 0x62, 0x46, 0x8e, 0x4b, 0xd8, 0xf7, 0xdd, 0x9a, 0xf6, 0x98, 0xf5, - 0x2a, 0xe8, 0x14, 0x63, 0x4e, 0x81, 0xd7, 0xf3, 0xe0, 0xc4, 0x20, 0x31, 0x7c, 0xac, - 0xa9, 0xae, 0x48, 0x11, 0xc6, 0xaf, 0x06, 0xfe, 0x80, 0xa8, 0xc0, 0x2a, 0xb7, 0xa0, - 0x0e, 0x18, 0xe4, 0xa6, 0xaa, 0x1e, 0xa1, 0xb7, 0x69, 0x45, 0xd2, 0x61, 0x5d, 0x43, - 0xac, 0x11, 0x8b, 0x56, 0xc2, 0xf2, 0x96, 0x0f, 0xe9, 0x3a, 0x02, 0x5f, 0x13, 0xec, - 0x91, 0xff, 0xc6, 0xd2, 0xc3, 0x53, 0x69, 0x9a, 0xbb, 0x09, 0x2d, 0xed, 0xc0, 0x65, - 0xdb, 0x8f, 0xa2, 0x14, 0xdb, 0xc4, 0x64, 0x66, 0xf8, 0x97, 0xb8, 0x8c, 0x58, 0xb3, - 0x01, 0x52, 0x13, 0x3a, 0xa3, 0x83, 0x1a, 0xf3, 0x7c, 0x74, 0xd9, 0x9e, 0x9e, 0x36, - 0xff, 0x70, 0x11, 0xd3, 0x23, 0x83, 0x05, 0x69, 0x15, 0x08, 0xa2, 0xc3, 0xa4, 0x3e, - 0x75, 0x5d, 0xc0, 0x81, 0xb5, 0x11, 0xd6, 0x48, 0x2a, 0x7d, 0xb6, 0x5f, 0xa9, 0x69, - 0x9e, 0xa8, 0x7f, 0xf4, 0x70, 0x99, 0xed, 0x36, 0x37, 0xdb, 0xb0, 0xa3, 0xd0, 0xef, - 0x79, 0x79, 0x6a, 0x8e, 0xf1, 0xe4, 0xd9, 0x4d, 0x42, 0xb4, 0xbc, 0x2b, 0x4a, 0x03, - 0x8a, 0xe6, 0xe4, 0x6b, 0x24, 0xcf, 0xc8, 0x41, 0x53, 0xd3, 0x1e, 0xaf, 0x89, 0x50, - 0x63, 0xa5, 0xca, 0x95, 0x9b, 0xe6, 0x3f, 0x37, 0xf2, 0xba, 0x0d, 0x43, 0x23, 0x66, - 0x73, 0x6d, 0x86, 0x32, 0xfc, 0xe0, 0x72, 0xb6, 0xae, 0x5b, 0x6f, 0x3f, 0xd5, 0x9d, - 0x3f, 0xaf, 0xf6, 0x38, 0x27, 0x5a, 0x99, 0x2f, 0xef, 0xc8, 0x7e, 0x60, 0xd4, 0x4c, - 0x2c, 0xad, 0xc2, 0xb5, 0xc4, 0x94, 0xe3, 0xe7, 0x2e, 0xb4, 0x59, 0x7c, 0x96, 0xb4, - 0x01, 0x67, 0x79, 0x9a, 0x90, 0x01, 0xa2, 0xed, 0x36, 0x76, 0xa8, 0xb4, 0x03, 0xae, - 0x25, 0xff, 0xd7, 0x72, 0xf7, 0x08, 0x1e, 0x9a, 0x32, 0xbc, 0xc1, 0xc5, 0xe2, 0xed, - 0xd4, 0xe2, 0xa6, 0x57, 0x6b, 0x78, 0x3c, 0xce, 0x3a, 0xae, 0x11, 0xfa, 0x43, 0x22, - 0x62, 0x54, 0x88, 0x56, 0x18, 0x3e, 0xe6, 0x82, 0xd5, 0xdc, 0x31, 0xbe, 0xb3, 0x8f, - 0x06, 0x1c, 0xbd, 0xec, 0xa7, 0x02, 0x1a, 0x44, 0x4e, 0x2d, 0xd4, 0x17, 0xdf, 0x26, - 0xdc, 0xd2, 0x20, 0xf2, 0xb7, 0x31, 0x77, 0x2b, 0x43, 0x9e, 0x96, 0xd6, 0x14, 0xe1, - 0xfa, 0xcb, 0x48, 0x6c, 0x7a, 0x7d, 0x51, 0x71, 0xb1, 0xde, 0x35, 0x9f, 0x6a, 0xd3, - 0xa9, 0x6f, 0x64, 0x9c, 0x96, 0x91, 0x02, 0xa1, 0x96, 0x4f, 0xb4, 0xb4, 0xa1, 0xa4, - 0x27, 0x9c, 0x68, 0xe6, 0xc3, 0x72, 0xe4, 0x21, 0x87, 0xd7, 0x54, 0xe8, 0x04, 0xa6, - 0x16, 0x53, 0x09, 0x20, 0x69, 0xfb, 0x9b, 0x6d, 0x25, 0x26, 0x68, 0x90, 0x80, 0x8b, - 0x01, 0x5d, 0xf2, 0x8c, 0x80, 0x10, 0x65, 0xda, 0x6f, 0xeb, 0xdc, 0x1a, 0x56, 0xbf, - 0xd0, 0x02, 0x62, 0x5a, 0xcf, 0xaa, 0x53, 0x73, 0xfd, 0xe1, 0x49, 0xc1, 0xcf, 0xc3, - 0x64, 0x9b, 0x48, 0x69, 0x69, 0x6d, 0x44, 0xec, 0xb1, 0x24, 0x79, 0xc5, 0xeb, 0xef, - 0x99, 0x5f, 0x10, 0x02, 0x9f, 0x8b, 0x53, 0x0e, 0xeb, 0x3f, 0xdc, 0x2e, 0x50, 0xe8, - 0x75, 0x7f, 0xc0, 0xbb, 0x9e, 0x26, 0x30, 0x23, 0xdb, 0x82, 0xf8, 0x78, 0xd9, 0xac, - 0x7f, 0xfb, 0x0b, 0xd4, 0x39, 0x1d, 0xf1, 0xd8, 0x79, 0x89, 0x9a, 0x3e, 0xf5, 0x7b, - 0xfd, 0x0d, 0x1f, 0x77, 0x55, 0x64, 0x8e, 0xdd, 0x85, 0xbb, 0x05, 0x2a, 0x6e, 0xdf, - 0x71, 0xcd, 0x26, 0x28, 0xc9, 0x87, 0x42, 0x9f, 0x36, 0xdc, 0x50, 0x5c, 0xcc, 0x43, - 0xf3, 0x0e, 0x7a, 0x86, 0x9c, 0x9e, 0x25, 0x5e, 0x2a, 0xf9, 0xfc, 0xf3, 0x0c, 0x12, - 0x17, 0x96, 0xd1, 0x90, 0x00, 0x09, 0x60, 0xcb, 0x6f, 0xe2, 0xf1, 0xbf, 0x24, 0x61, - 0x18, 0xb4, 0x98, 0xf3, 0x24, 0x7f, 0x9d, 0x48, 0x4c, 0x73, 0xcf, 0x09, 0x39, 0x30, - 0x39, 0xe4, 0x53, 0x26, 0xb8, 0xff, 0xff, 0xb3, 0xe7, 0xe6, 0x15, 0x9c, 0x46, 0x69, - 0x9f, 0x10, 0x07, 0x92, 0xd4, 0x67, 0x29, 0x50, 0x34, 0x8a, 0x90, 0x55, 0x2e, 0x45, - 0x94, 0x3b, 0xee, 0xac, 0xf0, 0x3f, 0x32, 0x16, 0xf9, 0x4e, 0x27, 0x4d, 0x63, 0xd6, - 0x37, 0xd9, 0xf1, 0x90, 0xe8, 0xa2, 0x66, 0xcd, 0xee, 0xf1, 0x53, 0x53, 0x0b, 0xee, - 0x5c, 0xb8, 0x35, 0x52, 0x60, 0x50, 0x5c, 0x2c, 0x2e, 0x5d, 0x99, 0x0f, 0xff, 0xdc, - 0x34, 0xec, 0x0f, 0xf7, 0xf1, 0xaf, 0x81, 0xb2, 0x4c, 0xed, 0x0e, 0xfa, 0x62, 0x13, - 0xda, 0x6c, 0x7c, 0x60, 0xc4, 0x87, 0xf5, 0xf7, 0xb0, 0x3f, 0x81, 0x60, 0xa0, 0x57, - 0xf4, 0x6d, 0x05, 0xbf, 0x82, 0x18, 0xb3, 0xad, 0xd9, 0xc0, 0x68, 0x93, 0xbd, 0x02, - 0xdb, 0x9b, 0x61, 0x19, 0x1d, 0xfb, 0x13, 0x3b, 0xfa, 0xbe, 0x48, 0x58, 0xe4, 0x7a, - 0x4c, 0xc3, 0x2e, 0x41, 0x6e, 0xc0, 0x8b, 0x8a, 0xc7, 0x91, 0x5a, 0x43, 0x73, 0x3f, - 0x44, 0x06, 0xe9, 0xd9, 0x67, 0xc5, 0x60, 0xf3, 0x44, 0xd7, 0xe9, 0x04, 0xa2, 0x80, - 0x45, 0xd9, 0x9f, 0x3a, 0xf8, 0xc8, 0x2e, 0x97, 0xe1, 0xb9, 0xc1, 0xb2, 0x05, 0xe5, - 0x85, 0xfb, 0xeb, 0xb4, 0x8f, 0xaf, 0x58, 0xf1, 0xb6, 0x5d, 0xca, 0x24, 0x97, 0xe0, - 0x9a, 0x70, 0xaa, 0xd4, 0x86, 0x5f, 0x85, 0x71, 0x5a, 0x28, 0x0e, 0x18, 0x6f, 0x3f, - 0xc1, 0x74, 0x0d, 0x81, 0x84, 0xd3, 0x3e, 0x83, 0x22, 0x16, 0x95, 0x21, 0xcd, 0xc1, - 0x32, 0x21, 0x29, 0x39, 0xc8, 0x4a, 0x10, 0x89, 0x64, 0xe2, 0xde, 0x74, 0xb6, 0xea, - 0x55, 0xb4, 0xcb, 0x8f, 0x6f, 0x9b, 0xee, 0x98, 0xb1, 0x0d, 0x41, 0x51, 0x09, 0x45, - 0x5f, 0x48, 0xb7, 0x76, 0x08, 0x2d, 0xc3, 0x0b, 0x4b, 0xc7, 0x34, 0x77, 0x07, 0x55, - 0x11, 0x70, 0x03, 0x08, 0x15, 0x8c, 0xe2, 0xf2, 0xf9, 0xbf, 0x0f, 0x69, 0x1b, 0x2c, - 0xe5, 0x3e, 0x61, 0x14, 0x2c, 0xb7, 0x40, 0xc1, 0x5b, 0x7b, 0x62, 0x3c, 0xf4, 0x8b, - 0x3f, 0x7b, 0xfe, 0xfa, 0x31, 0xbc, 0xdc, 0x66, 0x5c, 0x6d, 0x71, 0x23, 0xe9, 0x53, - 0x50, 0x81, 0x13, 0x75, 0x94, 0x7b, 0x05, 0x5a, 0x43, 0xdb, 0x07, 0xe0, 0x3f, 0x33, - 0x62, 0x7d, 0xf5, 0xc6, 0x38, 0xbf, 0xad, 0x95, 0x6d, 0xdc, 0x1e, 0xa7, 0xd7, 0x62, - 0x0a, 0x20, 0xf2, 0x79, 0x2f, 0x63, 0x81, 0x7a, 0x1c, 0xf3, 0x25, 0x80, 0xd0, 0x42, - 0x74, 0x23, 0x4a, 0xf2, 0xa5, 0x1b, 0x56, 0xbb, 0x68, 0xa2, 0x9e, 0x43, 0xa9, 0x54, - 0x14, 0x2b, 0xa4, 0xca, 0x68, 0x23, 0xbd, 0xe9, 0x05, 0x3d, 0x72, 0xfd, 0xad, 0xbc, - 0x61, 0xad, 0x59, 0x36, 0xc5, 0x3f, 0xdd, 0x75, 0x79, 0x44, 0x6d, 0x11, 0xc4, 0x46, - 0x07, 0xf4, 0x16, 0x30, 0xe4, 0xc0, 0x89, 0x15, 0xe6, 0x31, 0x77, 0x15, 0x50, 0xe9, - 0xce, 0x1f, 0xca, 0x2c, 0x63, 0xfe, 0x06, 0xb7, 0x98, 0x9d, 0x58, 0x4f, 0xa7, 0xd7, - 0x82, 0xa8, 0x8c, 0x1e, 0x7d, 0x64, 0xb6, 0xfb, 0xf5, 0x5e, 0x35, - ], - script_code: vec![0x6a, 0x53, 0x53, 0x63], - transparent_input: None, - hash_type: 1, - amount: 379068098637835, - consensus_branch_id: 1537743641, - sighash: [ - 0x92, 0xe7, 0xb4, 0x8f, 0x32, 0x81, 0x87, 0x71, 0x26, 0x87, 0xaf, 0x4d, 0xc1, 0x7a, - 0x73, 0xfe, 0x0a, 0x70, 0xac, 0x07, 0x8d, 0x24, 0xcd, 0xcd, 0xd4, 0x58, 0xa3, 0xd6, - 0x86, 0x61, 0xec, 0x0a, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x24, 0x9d, 0xf0, 0x57, 0x01, - 0xda, 0xb0, 0x31, 0xc4, 0xba, 0xc1, 0xea, 0x26, 0x7a, 0x29, 0x96, 0xa2, 0x02, 0x8d, - 0x1e, 0x6a, 0x0f, 0x80, 0xa3, 0x84, 0x7c, 0x53, 0x1d, 0xba, 0x96, 0xee, 0x65, 0xa2, - 0x41, 0x89, 0xbd, 0x09, 0x52, 0xac, 0x65, 0x63, 0x65, 0xac, 0x00, 0x65, 0x00, 0xb2, - 0xa4, 0xf9, 0x51, 0xef, 0x8f, 0x49, 0x7d, 0xff, 0xf2, 0xf2, 0xf2, 0x71, 0xea, 0xb8, - 0x9c, 0x62, 0x8e, 0x18, 0xb5, 0xfc, 0xb4, 0x38, 0x82, 0x53, 0x7e, 0xaf, 0x6a, 0xd2, - 0xa6, 0xb1, 0x75, 0x46, 0x33, 0xca, 0xa8, 0x6b, 0xf2, 0xc7, 0x6f, 0x07, 0x53, 0x63, - 0x6a, 0x6a, 0x65, 0x6a, 0x53, 0xa2, 0x21, 0x0c, 0x27, 0x01, 0xea, 0x6c, 0x54, 0x2c, - 0xc8, 0xc7, 0x06, 0x00, 0x00, 0xe0, 0x11, 0x29, 0xf0, 0x3a, 0x1e, 0x9c, 0x09, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xbe, 0x07, 0x62, 0xc0, 0xb1, 0xc6, 0x58, 0x55, 0xde, 0xba, 0x84, 0x22, - 0xca, 0x4b, 0x88, 0xab, 0xee, 0xa6, 0xa4, 0x38, 0x2c, 0xf1, 0x6c, 0xcd, 0x6d, 0xc7, - 0xc3, 0x7c, 0x44, 0xe5, 0x49, 0xc4, 0x53, 0x48, 0x19, 0xac, 0xd8, 0xbb, 0x0a, 0x02, - 0xa5, 0xfa, 0x7a, 0x1c, 0x1d, 0x38, 0x06, 0xfb, 0xc3, 0x40, 0x7f, 0xd7, 0xda, 0x93, - 0xfd, 0x0d, 0xe6, 0x40, 0x0d, 0x3a, 0xb8, 0x97, 0x74, 0x85, 0xcd, 0xdf, 0xbe, 0xd5, - 0x93, 0x2f, 0x50, 0x7b, 0x79, 0x94, 0x7a, 0xdb, 0x2f, 0xad, 0x37, 0x61, 0x5a, 0xa7, - 0x17, 0xdb, 0x5f, 0x29, 0x80, 0x99, 0xf2, 0x0f, 0x26, 0x3b, 0x35, 0x9a, 0x11, 0x51, - 0xa6, 0xb7, 0x5c, 0x01, 0x36, 0x5e, 0xb1, 0x54, 0xae, 0x42, 0x14, 0x0d, 0x6e, 0x10, - 0x34, 0x2f, 0x14, 0xf3, 0x4d, 0xc3, 0x3e, 0x07, 0xff, 0x0e, 0x4d, 0x1a, 0x6b, 0xe3, - 0x75, 0xb3, 0x2f, 0x84, 0xb9, 0x2e, 0x5d, 0x81, 0xeb, 0xb6, 0x39, 0xc4, 0xf2, 0x7e, - 0x71, 0x5a, 0xa4, 0x2c, 0xc7, 0x57, 0x07, 0xd4, 0xeb, 0xd1, 0xbb, 0xfb, 0xe8, 0xf9, - 0x0f, 0xc7, 0xc9, 0x53, 0xe7, 0xa9, 0x71, 0x5e, 0x65, 0xaf, 0x82, 0x67, 0x37, 0x3d, - 0x34, 0x51, 0x67, 0x4f, 0xf0, 0x84, 0xef, 0xd9, 0x2c, 0xcf, 0x3b, 0xcc, 0x7a, 0xca, - 0x14, 0x67, 0xb6, 0x32, 0x7e, 0x4f, 0x95, 0x22, 0xb2, 0xcc, 0x57, 0x9a, 0x7a, 0x8f, - 0xff, 0x7c, 0xa7, 0xcf, 0x14, 0x5d, 0xfc, 0x13, 0xea, 0xfc, 0x34, 0x15, 0x3b, 0x2c, - 0x3e, 0x8a, 0xfb, 0xe5, 0x34, 0x44, 0xd0, 0xc7, 0x3b, 0x3b, 0xd5, 0xbc, 0x87, 0x0b, - 0x01, 0xcd, 0x45, 0x79, 0x11, 0xe3, 0x56, 0x31, 0x3f, 0xd1, 0xda, 0xfb, 0x4c, 0x81, - 0x51, 0x63, 0x4a, 0x01, 0xaf, 0xf7, 0xcf, 0x11, 0x6d, 0x43, 0x3c, 0x3d, 0x2b, 0x3a, - 0xdd, 0xa9, 0xce, 0xbe, 0x18, 0xf7, 0xd1, 0x72, 0x44, 0x3e, 0x5e, 0x7b, 0x5a, 0xc9, - 0xab, 0xe8, 0xdb, 0x22, 0x56, 0xd7, 0xeb, 0xe2, 0xff, 0x28, 0x02, 0x09, 0x39, 0x50, - 0x38, 0x70, 0x59, 0x7b, 0x9a, 0x95, 0x58, 0x92, 0xc7, 0x38, 0x02, 0x50, 0xa2, 0xd4, - 0x2e, 0xc9, 0x2b, 0xe7, 0x23, 0xfe, 0xdf, 0x2f, 0x2e, 0xde, 0x5a, 0x47, 0x2a, 0xa1, - 0xe7, 0x4f, 0x33, 0xad, 0x41, 0x90, 0x15, 0x44, 0xed, 0xbb, 0xe3, 0xac, 0x46, 0x4c, - 0xf4, 0x03, 0x19, 0x60, 0x15, 0xf4, 0xf2, 0x2a, 0xc2, 0xb8, 0xfc, 0x01, 0x49, 0x6b, - 0xea, 0xb4, 0xd4, 0x59, 0x07, 0xf4, 0x79, 0x81, 0x2a, 0x25, 0x94, 0x31, 0xa2, 0xcb, - 0xc9, 0x3d, 0x4f, 0x3b, 0x84, 0xe4, 0x0b, 0x36, 0x60, 0x20, 0x27, 0x3a, 0x67, 0x52, - 0xe5, 0x01, 0xaf, 0x6f, 0xf1, 0xb7, 0x8d, 0xdc, 0x81, 0x7e, 0x6e, 0xa3, 0x51, 0xd6, - 0x00, 0x6b, 0xec, 0xf8, 0xd2, 0xff, 0xb0, 0x39, 0x90, 0xf6, 0x77, 0x74, 0xa8, 0x1e, - 0x05, 0xb7, 0xf4, 0xbb, 0xad, 0x85, 0x77, 0xfa, 0x27, 0xc9, 0xde, 0x64, 0xe1, 0xb1, - 0x1d, 0xcf, 0x38, 0x4f, 0x59, 0x56, 0x44, 0x37, 0x48, 0x75, 0x5a, 0x9f, 0xc6, 0xf2, - 0xa0, 0x03, 0x10, 0xc3, 0x65, 0x7e, 0xba, 0xc0, 0x3b, 0xfc, 0x0b, 0x58, 0x7b, 0xef, - 0x2f, 0x45, 0xec, 0x8a, 0xcd, 0xaa, 0x51, 0xc1, 0x43, 0xb0, 0xcb, 0x25, 0xb9, 0x14, - 0x2c, 0x61, 0xbd, 0x79, 0x0a, 0x80, 0x03, 0xc2, 0x3f, 0x90, 0xcc, 0x03, 0x49, 0x5b, - 0x51, 0xe4, 0xd2, 0x84, 0x3e, 0x55, 0x7f, 0x9e, 0x25, 0x45, 0x10, 0x8c, 0x6c, 0x6f, - 0xae, 0x35, 0x9f, 0x64, 0x5c, 0x27, 0x68, 0x91, 0xc0, 0xdc, 0xab, 0x03, 0xaf, 0x18, - 0x77, 0x00, 0xc0, 0x82, 0xdc, 0x47, 0x77, 0x40, 0xfb, 0x3f, 0x2c, 0xd7, 0xbb, 0x59, - 0xfb, 0x35, 0x85, 0x54, 0xe9, 0x4c, 0x7e, 0x67, 0x8c, 0xe0, 0x1a, 0xeb, 0xf9, 0x4e, - 0x51, 0x5e, 0x03, 0x72, 0x29, 0x67, 0x99, 0x5a, 0xea, 0x85, 0x8d, 0x64, 0xe7, 0x78, - 0x9f, 0xf3, 0x06, 0x36, 0x95, 0x77, 0x22, 0x81, 0x80, 0x32, 0x6a, 0x5b, 0x0a, 0xf4, - 0x75, 0xe2, 0x7a, 0x54, 0xb2, 0x07, 0xb4, 0x03, 0x92, 0xe3, 0x76, 0x17, 0x0e, 0x3f, - 0xb0, 0x05, 0x02, 0x82, 0x61, 0xc9, 0x9c, 0x2d, 0xbd, 0x0e, 0xed, 0xee, 0x87, 0x1c, - 0x1c, 0x0f, 0x48, 0xb8, 0xe9, 0xb8, 0xe4, 0xbe, 0x77, 0xd1, 0xb7, 0x37, 0xfe, 0x21, - 0xf0, 0xfa, 0x5a, 0x18, 0xeb, 0xb5, 0x27, 0x55, 0xb5, 0xa6, 0xcf, 0x61, 0x30, 0xfb, - 0x56, 0x94, 0x4c, 0xfa, 0xb8, 0x75, 0x27, 0xc2, 0x50, 0xd1, 0x13, 0xb2, 0x9b, 0xca, - 0xc9, 0xaa, 0xa1, 0x0c, 0x2e, 0x7d, 0xe4, 0x15, 0xed, 0xb0, 0x80, 0x6c, 0x6d, 0xa0, - 0x30, 0x20, 0xa1, 0x34, 0xca, 0x7e, 0xcd, 0xc8, 0xda, 0x1b, 0xd5, 0x7a, 0x37, 0xf5, - 0x5a, 0x46, 0x94, 0x0b, 0x45, 0xb2, 0x41, 0xb1, 0xc1, 0x6e, 0xe1, 0x00, 0x92, 0x7d, - 0x1b, 0xd8, 0x60, 0xd4, 0x45, 0xa9, 0xde, 0x50, 0xd4, 0xc3, 0x84, 0xd6, 0xe1, 0xd0, - 0x01, 0x08, 0x02, 0x6c, 0x0e, 0xa5, 0xeb, 0xbf, 0x0b, 0x72, 0xfb, 0xf5, 0xc3, 0x70, - 0xbc, 0xe1, 0x8d, 0x3a, 0xcb, 0xc4, 0x65, 0x99, 0x09, 0x9b, 0xaa, 0xe1, 0xd8, 0x02, - 0xf7, 0x73, 0x33, 0x49, 0x4a, 0x7a, 0xe1, 0x30, 0xfe, 0x86, 0xe8, 0xf8, 0x18, 0xf9, - 0x26, 0x1a, 0x2d, 0xad, 0xb4, 0x12, 0x52, 0x29, 0xba, 0x0f, 0xfc, 0x0e, 0x70, 0x90, - 0x32, 0x44, 0x30, 0xb5, 0x21, 0xa9, 0x0d, 0x22, 0x4a, 0xb7, 0xa1, 0x02, 0x4e, 0x1d, - 0x89, 0x3e, 0x74, 0x04, 0xfe, 0xdb, 0x34, 0x8e, 0x4d, 0x5e, 0x22, 0x35, 0xc5, 0x9a, - 0x78, 0x76, 0xa0, 0xfc, 0x60, 0x14, 0x5c, 0x6a, 0x00, 0x96, 0x87, 0x68, 0x44, 0x60, - 0x27, 0x1e, 0xe1, 0x33, 0xa4, 0x37, 0xfe, 0x52, 0xfb, 0x6c, 0xfb, 0xa9, 0x7f, 0xce, - 0xc1, 0x61, 0xdf, 0x51, 0x5d, 0xde, 0x90, 0x5a, 0x24, 0xda, 0x6d, 0x37, 0xbd, 0xc3, - 0x40, 0x44, 0xa9, 0x55, 0xe6, 0x82, 0xb4, 0x74, 0x71, 0xca, 0x1e, 0x8c, 0x78, 0xc5, - 0x1e, 0xd3, 0x77, 0xcd, 0x4a, 0xfa, 0x89, 0x4b, 0xd9, 0xbd, 0x12, 0xe7, 0x07, 0x15, - 0x6d, 0xa0, 0x72, 0x6f, 0x7c, 0xf5, 0x72, 0x9f, 0xab, 0xe3, 0x72, 0x16, 0x04, 0x63, - 0xfe, 0x04, 0x29, 0x24, 0x4d, 0x06, 0x74, 0x89, 0xba, 0x5d, 0x09, 0x47, 0x2e, 0xcd, - 0x9b, 0xcd, 0xc4, 0xd5, 0xe4, 0xdf, 0x10, 0x1e, 0x18, 0x9d, 0xb8, 0x46, 0x3e, 0xb5, - 0x38, 0x30, 0x7b, 0x58, 0x7d, 0xef, 0xf7, 0x8d, 0xe9, 0xc7, 0x3a, 0xf2, 0x80, 0x80, - 0xb2, 0xfd, 0x05, 0x00, 0x3e, 0x11, 0xd3, 0xe1, 0xb3, 0x29, 0x9d, 0xc9, 0x52, 0x1f, - 0x8b, 0x51, 0x3b, 0xad, 0xb0, 0x10, 0xe9, 0x1b, 0xfe, 0xb9, 0x1b, 0x0b, 0x2a, 0x6c, - 0xb1, 0x29, 0xc2, 0xe8, 0x25, 0xa5, 0x97, 0xb8, 0xfb, 0x75, 0xbc, 0x56, 0x2d, 0x65, - 0x4d, 0x62, 0x10, 0x46, 0x40, 0xdd, 0x74, 0xe5, 0x6c, 0xd1, 0x4b, 0xaa, 0xba, 0x56, - 0x5b, 0x84, 0xb8, 0x45, 0xe1, 0x63, 0xd1, 0xca, 0xef, 0x25, 0x33, 0xc3, 0x98, 0x16, - 0x37, 0x20, 0x4f, 0x96, 0xa5, 0x9c, 0x8e, 0x80, 0x24, 0xd9, 0x04, 0x1b, 0x20, 0x29, - 0xe9, 0x4c, 0x15, 0x24, 0x5f, 0x1a, 0x95, 0x88, 0x40, 0xba, 0x3f, 0x38, 0x0a, 0x4d, - 0x20, 0xf1, 0x18, 0x4e, 0x77, 0x82, 0x7d, 0xe3, 0xff, 0x8f, 0x3d, 0x73, 0x45, 0x9a, - 0xfe, 0x24, 0x1f, 0x72, 0x3c, 0x08, 0x48, 0x23, 0x23, 0x0e, 0x00, 0x3d, 0x3d, 0x21, - 0xe5, 0x35, 0x01, 0xec, 0x04, 0x99, 0xb0, 0x83, 0xa7, 0xda, 0xd6, 0x85, 0xc5, 0x71, - 0x27, 0xf4, 0xde, 0x64, 0x73, 0x3a, 0x88, 0x0c, 0x2d, 0xb2, 0x8f, 0xda, 0xab, 0xf1, - 0xb5, 0x42, 0xd2, 0x05, 0xf6, 0x64, 0xa3, 0x51, 0x35, 0x71, 0x27, 0x11, 0xdc, 0xcc, - 0xd9, 0x31, 0xa5, 0x0b, 0x9c, 0x56, 0x61, 0x88, 0x23, 0x60, 0xd4, 0xca, 0xc0, 0x04, - 0x76, 0x81, 0xbc, 0x2e, 0x2b, 0x3b, 0xf6, 0xc9, 0x97, 0x60, 0xd7, 0xcf, 0xb4, 0xfa, - 0x21, 0x39, 0x43, 0x77, 0xa4, 0x55, 0x1c, 0x76, 0xd1, 0xf7, 0x5a, 0xc0, 0x3c, 0x26, - 0x20, 0x54, 0xdf, 0xfd, 0x79, 0xa9, 0xde, 0xd0, 0x5e, 0x88, 0x89, 0x58, 0x19, 0x9e, - 0xea, 0x45, 0x01, 0xe2, 0x99, 0x0a, 0x53, 0xa5, 0xcd, 0x2a, 0x46, 0xa4, 0x01, 0x57, - 0x65, 0x88, 0xfd, 0x7d, 0x05, 0x8a, 0x26, 0xf2, 0x84, 0x38, 0xe5, 0x78, 0x2f, 0x45, - 0xac, 0x1d, 0x07, 0xf6, 0xf6, 0xf5, 0xed, 0x73, 0x74, 0x1d, 0x57, 0x85, 0x83, 0x7a, - 0x6b, 0x84, 0x4b, 0x47, 0x47, 0x75, 0x71, 0x8c, 0x29, 0xdd, 0x99, 0x08, 0x4e, 0x9f, - 0x88, 0xef, 0x15, 0x3a, 0x83, 0x29, 0xf5, 0x32, 0xa6, 0x90, 0x17, 0xdc, 0x3a, 0x97, - 0xed, 0x75, 0x43, 0x67, 0x72, 0x30, 0x98, 0xe5, 0x76, 0x58, 0x40, 0xb0, 0x22, 0x89, - 0x72, 0x44, 0x74, 0x5f, 0xbb, 0xbb, 0x30, 0xa7, 0xcb, 0x54, 0xfa, 0x05, 0x11, 0x16, - 0x6e, 0x95, 0x44, 0x12, 0x20, 0x00, 0x61, 0x0b, 0xd2, 0xaa, 0xcb, 0xd8, 0x23, 0x25, - 0xa5, 0x9b, 0x95, 0x15, 0x4e, 0xcd, 0x82, 0xc8, 0x8d, 0x23, 0xab, 0xd1, 0xe2, 0x07, - 0x70, 0xff, 0xb8, 0xaa, 0xbf, 0x83, 0xfc, 0x07, 0x34, 0x96, 0x4c, 0xcd, 0x41, 0x1d, - 0x1c, 0x93, 0x57, 0x14, 0xe2, 0x4a, 0xab, 0x56, 0x6f, 0x4f, 0x08, 0x42, 0x40, 0x14, - 0xc4, 0xec, 0xa9, 0x1b, 0x59, 0x0f, 0x08, 0x2b, 0x47, 0x3f, 0x36, 0x1c, 0x87, 0x41, - 0x5d, 0x37, 0xbd, 0x20, 0xd7, 0x0f, 0xd0, 0xb5, 0x2b, 0x6d, 0xdf, 0x18, 0x65, 0xf7, - 0x66, 0x70, 0x2e, 0x32, 0xb0, 0x5b, 0x3c, 0xf1, 0x63, 0x0e, 0xe8, 0x59, 0x7a, 0xae, - 0x19, 0x63, 0x3f, 0x35, 0x16, 0xa8, 0x55, 0x5a, 0xc5, 0xbe, 0x32, 0xc6, 0x75, 0xbe, - 0x18, 0x17, 0xef, 0xbf, 0xfd, 0x93, 0x69, 0x04, 0x1a, 0x08, 0x9c, 0x28, 0x3f, 0x19, - 0x64, 0x99, 0x68, 0xc2, 0x49, 0x8c, 0xde, 0x56, 0xf5, 0x00, 0x43, 0x4f, 0x28, 0x0d, - 0x77, 0xa9, 0xc6, 0x2e, 0x43, 0xcb, 0xd3, 0xf1, 0x36, 0xa4, 0xc6, 0xa0, 0x0a, 0x43, - 0xe6, 0xed, 0x53, 0x0c, 0xb2, 0xe8, 0xae, 0x83, 0x88, 0x60, 0xad, 0xc8, 0x8a, 0xac, - 0xc7, 0xbd, 0x6a, 0x00, 0xae, 0x0c, 0x19, 0xff, 0x45, 0x33, 0xa4, 0x85, 0xef, 0xde, - 0x08, 0x2b, 0x5f, 0x4d, 0x1f, 0x7a, 0x8e, 0xbe, 0x7e, 0xd8, 0x2b, 0x7b, 0x05, 0xa8, - 0xcf, 0xe1, 0xe3, 0x73, 0x45, 0x9f, 0x1b, 0xdc, 0xbf, 0x95, 0x25, 0x74, 0x7e, 0x8c, - 0x95, 0x08, 0xa5, 0x55, 0xfa, 0xcb, 0x79, 0x87, 0x40, 0xe0, 0xbd, 0xf9, 0x94, 0xd9, - 0x73, 0x9b, 0xbe, 0x55, 0x38, 0xa0, 0xae, 0x0f, 0x07, 0x6c, 0x58, 0x2c, 0x0f, 0x5b, - 0xa8, 0x78, 0xb9, 0x9b, 0x82, 0x49, 0xdb, 0x1d, 0x7e, 0x95, 0x05, 0x6c, 0x98, 0xaf, - 0x08, 0x3d, 0x98, 0xcb, 0x0e, 0xd9, 0xe3, 0xf7, 0x43, 0x6e, 0x1c, 0x76, 0x43, 0x76, - 0x6f, 0x96, 0x6b, 0x83, 0xe9, 0x99, 0x20, 0x6e, 0xbd, 0x13, 0x93, 0xb9, 0xb2, 0xa7, - 0xf4, 0x14, 0x48, 0x0f, 0xa0, 0x17, 0x48, 0x00, 0x69, 0xf8, 0x5c, 0x77, 0x49, 0xc4, - 0x35, 0xae, 0x2f, 0xba, 0x2d, 0xdc, 0x10, 0x38, 0xd5, 0x47, 0xd8, 0x48, 0x54, 0x81, - 0x7e, 0xf3, 0x96, 0x35, 0xc2, 0x98, 0x27, 0xaa, 0xd8, 0x67, 0x26, 0xc9, 0xad, 0xe3, - 0xb2, 0x65, 0xb9, 0x08, 0x6c, 0x8b, 0x5b, 0x75, 0xef, 0x56, 0xfe, 0x4b, 0xd8, 0xb4, - 0xd6, 0x28, 0x93, 0x89, 0x5b, 0x3f, 0xd2, 0x73, 0x4f, 0xda, 0xc4, 0x64, 0x15, 0x6d, - 0x7e, 0x5e, 0xbc, 0x7e, 0xcf, 0x1d, 0x83, 0xb8, 0x6f, 0x65, 0x96, 0x37, 0xe3, 0xb1, - 0x42, 0xc1, 0x64, 0x96, 0x3b, 0x8c, 0xdc, 0xf4, 0xba, 0x4f, 0x40, 0x35, 0xdf, 0xfc, - 0x5a, 0x78, 0x94, 0x58, 0x84, 0x77, 0x81, 0x91, 0x8a, 0xc7, 0x2f, 0xc1, 0x8b, 0xbb, - 0xf5, 0x11, 0x00, 0x32, 0xe6, 0x6d, 0x75, 0xb3, 0x17, 0x1e, 0xf4, 0xb5, 0x13, 0x29, - 0x01, 0x64, 0xa7, 0x7b, 0x42, 0xb0, 0xa4, 0xcf, 0xb8, 0x96, 0x39, 0xab, 0x23, 0x84, - 0x5e, 0x1a, 0xa2, 0xa4, 0x52, 0xf3, 0x73, 0x1c, 0x8c, 0xb6, 0x50, 0x82, 0xa6, 0x22, - 0xa7, 0xc2, 0xe0, 0x01, 0x3e, 0xa4, 0x7d, 0x0b, 0xdd, 0x42, 0xd6, 0x99, 0x04, 0x66, - 0x64, 0x9a, 0x90, 0x5c, 0x68, 0x4c, 0x32, 0x51, 0x71, 0x6d, 0x61, 0xf7, 0x60, 0xd5, - 0x3d, 0xe6, 0xe3, 0xf7, 0x90, 0xfb, 0xa7, 0xf5, 0xf1, 0xf4, 0xde, 0x26, 0x71, 0x13, - 0xbd, 0xfc, 0xd7, 0x42, 0x28, 0x22, 0x33, 0x0b, 0x32, 0xd5, 0x8e, 0x67, 0x77, 0x76, - 0x5f, 0x22, 0xa4, 0x11, 0x63, 0x44, 0xee, 0xb6, 0x5b, 0x2e, 0xc5, 0x16, 0x39, 0x3a, - 0xb3, 0x75, 0x1b, 0x53, 0x56, 0xd2, 0xb0, 0xc9, 0x50, 0x0c, 0x0f, 0x3e, 0x46, 0x91, - 0x81, 0x03, 0x5b, 0xc3, 0x66, 0x0f, 0x0b, 0x8f, 0x9f, 0xbe, 0x6e, 0x40, 0xb5, 0xe8, - 0x9c, 0xb7, 0x9b, 0x06, 0x37, 0x14, 0xca, 0x75, 0xe7, 0x2e, 0x2e, 0x10, 0x0a, 0x10, - 0xd6, 0x3b, 0xf7, 0x84, 0xdf, 0x08, 0x20, 0xef, 0x25, 0xf8, 0xef, 0x40, 0xfe, 0x5f, - 0x05, 0xfb, 0x95, 0x68, 0x3f, 0x91, 0x05, 0xff, 0x3c, 0xb2, 0xd2, 0x19, 0xab, 0x76, - 0x60, 0x5a, 0x06, 0x4f, 0x69, 0x21, 0x9f, 0x1d, 0xc0, 0xd0, 0x0b, 0x3b, 0x48, 0x64, - 0x2f, 0x97, 0x0d, 0xc0, 0x0c, 0xca, 0x4b, 0x8b, 0x43, 0x30, 0x8b, 0xe1, 0x82, 0x86, - 0xec, 0x5a, 0x42, 0x88, 0xd6, 0x00, 0xa3, 0x78, 0x5c, 0xb6, 0x22, 0xd4, 0x68, 0xa4, - 0xc6, 0x96, 0x9b, 0x37, 0x92, 0xf2, 0x48, 0x50, 0x27, 0xd0, 0xad, 0x9a, 0xa4, 0xa9, - 0xc2, 0xcc, 0x97, 0x2f, 0x9e, 0xe5, 0x19, 0x0a, 0x95, 0xb1, 0xeb, 0x05, 0x8d, 0xdd, - 0xd8, 0xc0, 0x8e, 0x7d, 0x75, 0x3f, 0x5e, 0x01, 0x1b, 0x2b, 0xcf, 0xee, 0x1d, 0x52, - 0xc1, 0xc4, 0xf2, 0xca, 0xcd, 0xa3, 0x0b, 0xdb, 0x69, 0x30, 0x65, 0x3c, 0x0c, 0xc4, - 0x48, 0x6e, 0x60, 0xe8, 0x9f, 0xa8, 0x49, 0xb3, - ], - script_code: vec![0x53, 0x52], - transparent_input: Some(0), - hash_type: 3, - amount: 1437866676382615, - consensus_branch_id: 1537743641, - sighash: [ - 0xd8, 0xe9, 0xb9, 0x72, 0xb2, 0x89, 0x8e, 0xfc, 0xca, 0x8e, 0x96, 0xbc, 0x98, 0x70, - 0x00, 0x8c, 0xdb, 0xc1, 0x9d, 0x45, 0xb7, 0x8d, 0x09, 0xef, 0xb1, 0x02, 0xf2, 0xd7, - 0x0d, 0xba, 0x01, 0xad, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x01, 0x87, 0xda, 0xa7, 0x31, 0xf5, - 0x70, 0xa7, 0xa4, 0x06, 0x0a, 0xf0, 0xce, 0x70, 0x0d, 0x31, 0xbc, 0xa7, 0xe7, 0x4b, - 0x3e, 0x3b, 0xa3, 0xd0, 0xe8, 0xa6, 0x39, 0x2a, 0x06, 0x2b, 0x8e, 0x86, 0xd9, 0xd7, - 0xd0, 0x0b, 0x21, 0x02, 0x65, 0x53, 0x06, 0x2e, 0x06, 0xb1, 0x01, 0x30, 0x11, 0xff, - 0x08, 0xf0, 0x83, 0x05, 0x00, 0x09, 0x63, 0x6a, 0x52, 0x63, 0x51, 0x63, 0x00, 0x6a, - 0xac, 0x9a, 0xbc, 0xef, 0x2a, 0x99, 0x08, 0x73, 0x19, 0x00, - ], - script_code: vec![0x63], - transparent_input: None, - hash_type: 1, - amount: 1993227025071196, - consensus_branch_id: 1537743641, - sighash: [ - 0x2b, 0x62, 0xff, 0x0c, 0x8d, 0xec, 0x4d, 0xf1, 0x8b, 0x99, 0x56, 0x61, 0x5b, 0x57, - 0x4d, 0xda, 0x39, 0x42, 0xfe, 0x45, 0x2d, 0x91, 0x78, 0xb0, 0xbb, 0xb2, 0xea, 0xee, - 0x4d, 0xe4, 0x4a, 0x8c, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x7c, 0x82, 0x97, 0x7c, 0x0f, - 0xf7, 0x97, 0x09, 0x3e, 0x2c, 0x1f, 0x3a, 0xe8, 0x55, 0xf6, 0x5a, 0xea, 0x91, 0xe1, - 0x31, 0x2f, 0xc6, 0xb8, 0xa4, 0x35, 0x1a, 0x2e, 0xc0, 0x3e, 0x02, 0xe5, 0xd0, 0x2f, - 0x53, 0x35, 0x4b, 0x05, 0x6a, 0x53, 0x52, 0x63, 0x6a, 0x82, 0xcd, 0x1f, 0x55, 0xeb, - 0xca, 0x57, 0xb6, 0x33, 0x7c, 0x85, 0x93, 0x8a, 0x79, 0x81, 0x3d, 0x20, 0x21, 0xd6, - 0x09, 0x4c, 0x68, 0xb3, 0x75, 0xe9, 0x84, 0xf6, 0x83, 0x93, 0x30, 0x08, 0x71, 0xe3, - 0x48, 0xfc, 0x52, 0x36, 0xcc, 0xa6, 0x33, 0x05, 0xac, 0x63, 0x65, 0x51, 0x63, 0x41, - 0x87, 0x01, 0xff, 0x01, 0x86, 0xd2, 0x6f, 0xee, 0x28, 0xca, 0x06, 0x00, 0x01, 0xac, - 0x5a, 0xa7, 0x27, 0xab, 0x79, 0x85, 0xda, 0x0e, 0x00, - ], - script_code: vec![0x65, 0x53, 0x51], - transparent_input: Some(1), - hash_type: 130, - amount: 449567650863240, - consensus_branch_id: 1537743641, - sighash: [ - 0x49, 0x3d, 0x49, 0xc3, 0xe2, 0x22, 0x5d, 0x11, 0xc4, 0x64, 0x05, 0x18, 0x20, 0x14, - 0x76, 0x25, 0xf3, 0x90, 0x9f, 0xa7, 0x18, 0x9f, 0x61, 0xc7, 0xea, 0xec, 0xfc, 0x6d, - 0xad, 0x2e, 0x82, 0x03, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x00, 0x02, 0xe9, 0x6a, 0xa7, 0x3c, - 0xd9, 0xd1, 0x04, 0x00, 0x02, 0x00, 0x53, 0x06, 0xf6, 0x99, 0xe0, 0xb1, 0x9a, 0x04, - 0x00, 0x06, 0xac, 0x65, 0x65, 0x51, 0xac, 0x51, 0x0e, 0x68, 0xae, 0x38, 0x75, 0x05, - 0x51, 0x13, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x92, 0xf1, 0x35, 0xbf, 0x5f, 0x68, 0x78, 0x7d, - 0x37, 0x0c, 0xa8, 0xc4, 0xc4, 0x07, 0x4d, 0xc5, 0xd6, 0x01, 0xae, 0x90, 0x49, 0x54, - 0x37, 0xc3, 0xc2, 0xd4, 0x8a, 0x3d, 0x96, 0x66, 0x83, 0xac, 0x05, 0x16, 0x0b, 0x7a, - 0x84, 0xea, 0xa7, 0xaa, 0xb7, 0x40, 0x09, 0xe5, 0x7a, 0x85, 0xf7, 0xbf, 0x68, 0xa2, - 0xe4, 0x82, 0x00, 0x0f, 0x82, 0x9c, 0x54, 0x50, 0x73, 0xa1, 0x5d, 0x5c, 0xd0, 0xfc, - 0xc5, 0x74, 0x39, 0xa4, 0x35, 0x0e, 0xaf, 0x09, 0x8d, 0xfb, 0x82, 0xa0, 0x85, 0xea, - 0x8a, 0x4a, 0xf6, 0xfa, 0x83, 0x81, 0xf0, 0x65, 0x88, 0x19, 0xea, 0xb4, 0x83, 0xf6, - 0x5b, 0x32, 0x5d, 0x5a, 0xed, 0xa1, 0x52, 0x32, 0xcf, 0xad, 0xec, 0x75, 0xab, 0x18, - 0x66, 0xe4, 0xc0, 0x15, 0x5a, 0x9c, 0x74, 0xa7, 0xa5, 0x7c, 0xcf, 0x34, 0xc4, 0x83, - 0xac, 0x7d, 0xa1, 0x58, 0x8a, 0x1b, 0x6b, 0x99, 0x41, 0xf1, 0x10, 0x40, 0xf9, 0x4c, - 0xf7, 0x8f, 0xad, 0x89, 0xbf, 0x11, 0xfe, 0xd6, 0x9a, 0xa0, 0xd8, 0x31, 0x05, 0xad, - 0xac, 0xdd, 0x4e, 0x5f, 0x04, 0xa6, 0x24, 0x24, 0x02, 0x3c, 0x9b, 0x9e, 0x33, 0xc4, - 0xfb, 0x7f, 0x12, 0xbd, 0xf2, 0x1f, 0x07, 0xf2, 0x65, 0xc5, 0x37, 0xd5, 0x1c, 0x65, - 0x51, 0xf4, 0x61, 0x7b, 0x91, 0x5d, 0x21, 0x99, 0x18, 0x39, 0xc3, 0xd0, 0xd3, 0x63, - 0x93, 0xd6, 0x46, 0xe0, 0xa8, 0xa4, 0x15, 0x09, 0x21, 0x7d, 0x0e, 0x7d, 0x2c, 0xa1, - 0xa0, 0xa0, 0xd6, 0x77, 0xa3, 0xea, 0xca, 0x23, 0xed, 0xeb, 0x07, 0xb7, 0x4e, 0x65, - 0x2a, 0x0b, 0xc5, 0x0c, 0x6c, 0x08, 0x3a, 0x55, 0xd6, 0xc7, 0x30, 0x6e, 0x74, 0x08, - 0x6f, 0x47, 0x68, 0x93, 0x3a, 0xa2, 0x48, 0x73, 0x68, 0x18, 0x67, 0xa7, 0x89, 0x3d, - 0x77, 0xcb, 0x7f, 0x29, 0xb8, 0xc8, 0x47, 0xc5, 0x83, 0xf2, 0xd0, 0x71, 0xa6, 0x86, - 0x61, 0x6e, 0x20, 0x67, 0x19, 0xf7, 0x61, 0xae, 0x39, 0xc1, 0x10, 0x44, 0x2e, 0x06, - 0x16, 0x3d, 0x2b, 0x84, 0x59, 0x03, 0x60, 0x69, 0x5d, 0x4e, 0x19, 0x84, 0x9e, 0x03, - 0x4f, 0x24, 0xd9, 0xad, 0x39, 0x6c, 0x19, 0xff, 0x83, 0xce, 0x74, 0xf4, 0x6e, 0x64, - 0x5f, 0x93, 0x2e, 0x14, 0x1a, 0x41, 0x19, 0x59, 0x36, 0xc8, 0x5d, 0x51, 0x44, 0x14, - 0xf1, 0x12, 0xe6, 0x0b, 0x02, 0x25, 0x37, 0xc3, 0x8d, 0x6d, 0xc6, 0xc4, 0x63, 0x83, - 0x05, 0xc9, 0xbd, 0x6c, 0x62, 0xe3, 0x66, 0xbc, 0x63, 0x12, 0x3e, 0x3e, 0x6d, 0xd3, - 0x6e, 0xed, 0xd3, 0x13, 0x6f, 0xce, 0x8d, 0xee, 0xca, 0x0a, 0xa0, 0x9a, 0x32, 0x98, - 0xa3, 0x9d, 0x83, 0x85, 0x9e, 0xfc, 0x9b, 0x2b, 0x69, 0xcf, 0x9a, 0x7d, 0xee, 0x08, - 0xa9, 0x8e, 0x4b, 0xe5, 0x58, 0xac, 0x79, 0x12, 0xfd, 0xcb, 0x42, 0x20, 0x90, 0x75, - 0x42, 0x02, 0x60, 0xf7, 0xca, 0xd0, 0xf2, 0xc0, 0x1f, 0x2a, 0xfe, 0x33, 0x07, 0x3f, - 0x26, 0x24, 0x9d, 0x94, 0x4f, 0x7a, 0x50, 0xdd, 0x84, 0x83, 0x9b, 0xc3, 0xea, 0x7f, - 0xde, 0xe4, 0xed, 0x71, 0x02, 0x9c, 0xf0, 0x75, 0x33, 0xd2, 0x6e, 0x1e, 0x27, 0xa3, - 0xef, 0xb0, 0x32, 0xc3, 0xa3, 0xb3, 0x4b, 0xd3, 0x09, 0x26, 0x22, 0xd2, 0x06, 0x2a, - 0xe5, 0x36, 0xef, 0x51, 0x49, 0xc4, 0x9b, 0x5b, 0xc9, 0x03, 0x5e, 0xaf, 0xab, 0x6e, - 0x67, 0x57, 0x61, 0x00, 0x8b, 0x0d, 0xad, 0xde, 0xec, 0xaa, 0x60, 0x44, 0x70, 0xbb, - 0xe0, 0xfa, 0xda, 0x25, 0x5d, 0x29, 0x0e, 0x92, 0xb1, 0x90, 0xc2, 0xc2, 0xd8, 0xc2, - 0x02, 0xe5, 0x45, 0x5d, 0x1f, 0xa9, 0xa9, 0xf3, 0xdb, 0x77, 0x79, 0xb5, 0x84, 0x64, - 0x34, 0x64, 0xaa, 0x80, 0x14, 0xba, 0x66, 0x99, 0x4d, 0xe2, 0x55, 0x17, 0xf8, 0x39, - 0x80, 0xe6, 0x6e, 0xe4, 0xf6, 0x03, 0x14, 0xae, 0x6d, 0xbe, 0xf4, 0x52, 0xd5, 0xd3, - 0x8b, 0x0a, 0x16, 0xf3, 0x99, 0x1f, 0x36, 0xd8, 0xa8, 0xb3, 0x9d, 0xdc, 0x0d, 0x55, - 0x95, 0xee, 0xd9, 0x87, 0x62, 0x87, 0x8c, 0xdf, 0x3f, 0x4a, 0x02, 0xdc, 0x5c, 0xda, - 0x77, 0xd5, 0xfe, 0x4f, 0xaf, 0x63, 0xa1, 0x5f, 0x56, 0x8a, 0x54, 0x0d, 0xa5, 0x7d, - 0xd9, 0xbe, 0xb6, 0xfb, 0x1a, 0x97, 0x7c, 0xcb, 0x91, 0xb4, 0xd7, 0x9c, 0xb3, 0x9b, - 0x28, 0x91, 0x1a, 0x29, 0xe7, 0xbf, 0x02, 0x8a, 0xc6, 0x10, 0x37, 0x96, 0xdf, 0xb6, - 0xb2, 0x09, 0x67, 0x23, 0x9a, 0xd3, 0x73, 0xc3, 0x8c, 0x53, 0xf6, 0xdf, 0x18, 0x23, - 0xd4, 0x95, 0x0a, 0x02, 0x83, 0xe9, 0x9b, 0x9c, 0x06, 0xab, 0x29, 0x66, 0x66, 0x7c, - 0x9d, 0xf6, 0x77, 0x71, 0x6b, 0x0c, 0xad, 0xed, 0x81, 0x8d, 0xf9, 0xe4, 0x49, 0xc0, - 0x72, 0xe2, 0x2f, 0x9d, 0x98, 0xbb, 0x0f, 0x9b, 0x03, 0xbd, 0x5f, 0xd0, 0x13, 0xfc, - 0xef, 0x3e, 0xd6, 0xa4, 0x9a, 0xeb, 0x98, 0x72, 0x02, 0x54, 0x08, 0x7e, 0xf7, 0x28, - 0xe3, 0x19, 0x47, 0xff, 0xe8, 0xf7, 0x66, 0xe6, 0x3e, 0xe4, 0x6f, 0xf2, 0x08, 0x16, - 0xd5, 0xfa, 0x8f, 0xf5, 0x5a, 0x26, 0x39, 0x89, 0x61, 0x49, 0x0a, 0xb9, 0xae, 0x36, - 0x6f, 0xc5, 0xa2, 0xd1, 0x99, 0x6e, 0xd6, 0x93, 0xcc, 0xca, 0x82, 0x35, 0x6f, 0x60, - 0x0a, 0xb0, 0x99, 0xf6, 0xec, 0xa8, 0xbf, 0xe6, 0x45, 0x27, 0x0d, 0x3f, 0x95, 0xed, - 0xba, 0x5b, 0x0d, 0xe7, 0xa3, 0x28, 0x19, 0x23, 0x3b, 0xcc, 0x75, 0x4a, 0x5c, 0xe2, - 0xe5, 0xea, 0x07, 0x84, 0x2e, 0x5f, 0xf2, 0xce, 0xbe, 0x62, 0xad, 0x76, 0xe8, 0xef, - 0xf8, 0xd1, 0x5e, 0xa4, 0xc2, 0x4a, 0x5f, 0x20, 0x78, 0x68, 0x31, 0x9a, 0x5a, 0xf6, - 0xb0, 0x35, 0xbe, 0x3f, 0x44, 0xf4, 0x34, 0x09, 0x4f, 0x6e, 0x52, 0x5b, 0xe6, 0x14, - 0xda, 0xc9, 0x20, 0xa3, 0x30, 0xbd, 0xfb, 0x26, 0xd7, 0x5f, 0xe7, 0xb4, 0xb3, 0x65, - 0xd0, 0x94, 0x45, 0x92, 0x50, 0xaa, 0xa5, 0x54, 0x44, 0x89, 0xfb, 0x1d, 0x99, 0x25, - 0x81, 0x80, 0x0a, 0x77, 0xb8, 0x91, 0x21, 0x57, 0xfc, 0x97, 0x13, 0xaa, 0xac, 0x25, - 0xb4, 0xc2, 0x6e, 0xb0, 0x3f, 0x71, 0x66, 0x46, 0x61, 0x9a, 0xf0, 0x24, 0x56, 0xae, - 0x69, 0x59, 0x62, 0xfe, 0x5e, 0x93, 0x1a, 0x63, 0xb5, 0xc7, 0x90, 0x52, 0xec, 0xd3, - 0x33, 0xe1, 0x84, 0x12, 0xdb, 0x91, 0xe1, 0x5f, 0x7c, 0xbc, 0x70, 0xb4, 0xcd, 0x7e, - 0x8e, 0x3c, 0x95, 0x1f, 0x35, 0x85, 0x72, 0xe3, 0x77, 0x67, 0xe7, 0xd5, 0x27, 0x04, - 0xa6, 0x72, 0x1b, 0x30, 0xef, 0xc4, 0x10, 0x17, 0xae, 0x4d, 0x23, 0x15, 0x58, 0xc5, - 0xc8, 0x2c, 0xc7, 0xdd, 0x7e, 0x33, 0x56, 0xc0, 0x9d, 0xc2, 0x49, 0x06, 0xf0, 0x43, - 0x8d, 0xfc, 0xc3, 0x00, 0x85, 0x6a, 0xc2, 0xce, 0xd8, 0xf7, 0x7f, 0xa8, 0x01, 0x57, - 0x36, 0xc6, 0x61, 0xe8, 0x02, 0x48, 0xae, 0xeb, 0x77, 0x48, 0x74, 0xaa, 0x79, 0xd2, - 0x90, 0xb8, 0xf5, 0x02, 0x7a, 0x0a, 0x50, 0x95, 0x37, 0xfc, 0x7c, 0x68, 0x9b, 0x7a, - 0xd8, 0x61, 0x16, 0xcf, 0xec, 0x26, 0x47, 0xcc, 0xaa, 0xe1, 0xc7, 0x4b, 0x41, 0x6f, - 0x3e, 0x6a, 0xe8, 0xf7, 0xcc, 0x60, 0xea, 0xaf, 0x7b, 0x6a, 0x59, 0x0d, 0x51, 0x54, - 0x41, 0x38, 0xe1, 0x73, 0x29, 0x45, 0x60, 0x3a, 0x53, 0x46, 0x2c, 0x60, 0xe1, 0xf6, - 0xcb, 0x0c, 0x9c, 0xa0, 0x39, 0x0c, 0x48, 0x82, 0x24, 0xc3, 0x13, 0x26, 0x9f, 0xcd, - 0x59, 0xfc, 0xb6, 0x11, 0xfb, 0x2d, 0x9b, 0x4c, 0x8f, 0xa6, 0x01, 0xbb, 0x1c, 0xb8, - 0xd0, 0x7d, 0x79, 0x7b, 0xf5, 0xde, 0x52, 0xbc, 0xee, 0xb0, 0x23, 0x01, 0xc8, 0x96, - 0x2a, 0xc1, 0xfc, 0x04, 0x91, 0xdc, 0x81, 0xaf, 0xfd, 0x6c, 0x1e, 0xbf, 0x89, 0xa1, - 0x3d, 0x6f, 0x29, 0x0e, 0xda, 0x5d, 0x5c, 0xef, 0x38, 0x22, 0x15, 0xc5, 0xe9, 0x51, - 0xd7, 0x13, 0x05, 0xef, 0x33, 0xd9, 0x73, 0x71, 0x26, 0xd0, 0xe6, 0x62, 0x90, 0x5f, - 0x12, 0x50, 0x92, 0x6f, 0x6a, 0x22, 0x99, 0x90, 0xe3, 0x8f, 0x69, 0xad, 0x9a, 0x91, - 0x92, 0xb3, 0x02, 0xf2, 0x6b, 0xdd, 0xa4, 0x65, 0xd9, 0x0b, 0x94, 0xb1, 0x2c, 0x57, - 0xfa, 0x3f, 0xd6, 0x93, 0x00, 0x83, 0xf1, 0x84, 0x43, 0x8d, 0x8a, 0x88, 0x9d, 0x3f, - 0x5e, 0xce, 0xa2, 0xc6, 0xd2, 0x3d, 0x67, 0x36, 0xf2, 0xa0, 0xf1, 0x8e, 0x26, 0xf4, - 0xfa, 0x45, 0xd1, 0xbe, 0x8f, 0x3d, 0xc4, 0xa7, 0x07, 0x13, 0x7e, 0x95, 0xd2, 0xad, - 0x59, 0x4f, 0x6c, 0x03, 0xd2, 0x49, 0x23, 0x06, 0x7a, 0xe4, 0x7f, 0xd6, 0x42, 0x5e, - 0xfb, 0x9c, 0x1d, 0x50, 0x4e, 0x6f, 0xd5, 0x57, 0x53, 0x40, 0x94, 0x56, 0x01, 0xfe, - 0x80, 0x6f, 0x57, 0x56, 0xac, 0xb5, 0x62, 0xf1, 0x3c, 0x0c, 0xa1, 0xd8, 0x03, 0xa1, - 0x95, 0xc2, 0xeb, 0xb2, 0xef, 0x02, 0xac, 0x33, 0xe6, 0xa8, 0x8d, 0xea, 0x07, 0x5b, - 0xa9, 0x96, 0xd3, 0xc3, 0x36, 0x64, 0x8e, 0x86, 0x94, 0xd3, 0xa1, 0x9d, 0x3d, 0xca, - 0x53, 0x1b, 0xeb, 0x50, 0xd4, 0x32, 0x7c, 0x5c, 0x0c, 0x23, 0xcb, 0x7c, 0xfd, 0xb0, - 0x8c, 0xa7, 0xcf, 0x2c, 0xac, 0x6b, 0xc1, 0x39, 0xd0, 0x74, 0x14, 0x73, 0xd3, 0x76, - 0x02, 0x9c, 0xb4, 0xab, 0x6b, 0xf0, 0x54, 0x55, 0x7c, 0xe2, 0x94, 0xc7, 0x28, 0xa4, - 0x68, 0x7d, 0x57, 0xec, 0x89, 0x09, 0xff, 0x51, 0xa4, 0xd0, 0x2f, 0x9d, 0xcd, 0x11, - 0x19, 0x3d, 0x7d, 0x1c, 0x9f, 0xda, 0xe6, 0xa1, 0x73, 0x96, 0xa1, 0xbf, 0x57, 0xa9, - 0x94, 0x93, 0x4f, 0x5e, 0x7a, 0x59, 0xf0, 0x45, 0xde, 0xbe, 0xaf, 0xf6, 0x2e, 0xf3, - 0x26, 0xb9, 0x47, 0xf2, 0xa8, 0xb4, 0x95, 0x55, 0xe4, 0xd9, 0x9b, 0x3b, 0xf5, 0xc8, - 0x1f, 0xf9, 0xfe, 0x31, 0x4e, 0x04, 0x7a, 0xf1, 0x52, 0x50, 0x8f, 0x57, 0x01, 0x5c, - 0xa4, 0x02, 0xc6, 0x7d, 0x92, 0x5c, 0x99, 0xac, 0xea, 0x3e, 0xe8, 0xcc, 0x4b, 0x00, - 0x8c, 0x5c, 0xb4, 0x39, 0x66, 0xe7, 0x14, 0xef, 0x48, 0x0f, 0xd0, 0x5e, 0x07, 0xc7, - 0xb2, 0xdd, 0xa9, 0xaa, 0x39, 0x66, 0x11, 0x3e, 0xaa, 0x29, 0x3d, 0x3f, 0x62, 0x2b, - 0x30, 0x9d, 0x64, 0x80, 0x3c, 0xe1, 0xe6, 0x37, 0x8b, 0x6a, 0xac, 0x4f, 0xab, 0x52, - 0x7c, 0x43, 0xcd, 0x45, 0xed, 0x0a, 0x3c, 0x1a, 0x4b, 0x9f, 0xb1, 0x8d, 0xcc, 0xcf, - 0xcd, 0xb6, 0xac, 0x0c, 0x24, 0x21, 0x63, 0x9c, 0xda, 0x00, 0x75, 0xa2, 0x0d, 0xc5, - 0x11, 0x1b, 0x8d, 0x3d, 0x31, 0x99, 0x49, 0x5b, 0xd9, 0x13, 0x3d, 0xba, 0xb9, 0x45, - 0x41, 0x41, 0x0e, 0x4f, 0xba, 0x92, 0xc7, 0xb6, 0x06, 0xa5, 0xcb, 0x12, 0x2f, 0x14, - 0x0c, 0xf1, 0xa3, 0x59, 0x6f, 0x27, 0x88, 0xf3, 0xc8, 0xb9, 0x26, 0x60, 0xf1, 0x4c, - 0xb6, 0x5a, 0xf5, 0xdd, 0x23, 0xdf, 0xdb, 0xac, 0x13, 0x71, 0xec, 0xf4, 0xb3, 0x37, - 0x12, 0xfe, 0xd2, 0x29, 0x2c, 0x44, 0xf7, 0x08, 0x34, 0xcf, 0x96, 0xc0, 0x5d, 0x58, - 0x82, 0x7e, 0x69, 0xbf, 0xc2, 0xe6, 0x96, 0xfa, 0x08, 0x74, 0x86, 0x9c, 0x02, 0xf3, - 0xdc, 0xa1, 0x1c, 0x3b, 0x90, 0xcb, 0x21, 0x4e, 0x68, 0xbc, 0x1c, 0xae, 0x03, 0x9d, - 0x7a, 0x14, 0x6c, 0xdc, 0x1d, 0x60, 0x9d, 0x7a, 0x6b, 0x3f, 0xd5, 0xd4, 0x61, 0xb0, - 0x95, 0x1c, 0x82, 0xcf, 0xb3, 0xe7, 0x63, 0xfa, 0xd2, 0xd1, 0xbc, 0x76, 0x78, 0xcd, - 0xf8, 0x27, 0x79, 0xf8, 0xfd, 0x5a, 0x1c, 0xe2, 0x2a, 0x8d, 0x3c, 0x45, 0x47, 0xab, - 0xd9, 0x59, 0x83, 0x8a, 0x46, 0xfb, 0x80, 0xaf, 0xe0, 0x1f, 0x8e, 0xcc, 0x99, 0x31, - 0x51, 0x3b, 0x19, 0x62, 0xec, 0x54, 0x08, 0x56, 0xcb, 0x18, 0x93, 0x87, 0xcf, 0xbf, - 0xcc, 0x0f, 0x7c, 0x68, 0x22, 0x3c, 0xba, 0x47, 0xfb, 0x0c, 0x9b, 0x48, 0x6e, 0x4d, - 0x99, 0x17, 0x19, 0x41, 0xf7, 0x67, 0x5a, 0x8b, 0x46, 0x32, 0x8a, 0x3b, 0xc1, 0x09, - 0xbf, 0x07, 0xc6, 0x6d, 0x5e, 0xde, 0x77, 0x1c, 0xc4, 0xc7, 0x4c, 0xe8, 0x03, 0x33, - 0x82, 0x91, 0x91, 0xee, 0xdc, 0x49, 0x35, 0x08, 0xa6, 0x44, 0x53, 0x0a, 0x61, 0x44, - 0xf2, 0x2d, 0xcf, 0x97, 0x52, 0x5a, 0x4c, 0xdc, 0xa1, 0xad, 0x71, 0x07, 0x3b, 0x08, - 0x0b, 0x73, 0xea, 0x45, 0x49, 0xf5, 0x40, 0x1b, 0xff, 0x43, 0x18, 0x26, 0x8e, 0x6a, - 0xd6, 0x37, 0x36, 0x31, 0x57, 0xa1, 0x9a, 0x53, 0xf1, 0x23, 0xa0, 0xb0, 0xe1, 0x6d, - 0x0b, 0x77, 0xf0, 0x20, 0x28, 0xda, 0x46, 0x41, 0x00, 0xfd, 0xe7, 0x6d, 0x83, 0xdd, - 0x0b, 0xb2, 0x24, 0xf7, 0xb5, 0x7a, 0x00, 0xc0, 0x2f, 0x68, 0xae, 0x64, 0x8f, 0xdc, - 0x52, 0x99, 0x57, 0xa1, 0x04, 0x90, 0xdc, 0xe1, 0xfd, 0xdb, 0xb0, 0x90, 0x4f, 0x0d, - 0x51, 0x8b, 0xb3, 0x87, 0x54, 0x40, 0x19, 0x98, 0x3b, 0x61, 0x69, 0x75, 0xa7, 0x8e, - 0x74, 0xd8, 0x54, 0xfd, 0xdc, 0x49, 0xb2, 0x55, 0x16, 0x7b, 0x55, 0xef, 0x4b, 0xee, - 0x46, 0x56, 0x68, 0xb2, 0x0e, 0xa4, 0x11, 0x8c, 0xa5, 0x69, 0xae, 0x48, 0x0e, 0x0f, - 0x6e, 0x5e, 0x04, 0x3a, 0x35, 0x7b, 0x36, 0xd3, 0xab, 0x36, 0xc8, 0x61, 0xf2, 0x27, - 0x83, 0x01, 0xdc, 0xe5, 0x76, 0x74, 0xd5, 0x07, 0x3b, 0x3a, 0x6f, 0x51, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xa0, 0x79, 0x3a, 0xf1, 0xb7, 0xd4, 0x6f, 0x95, 0x7e, 0x22, 0xd8, 0xd2, 0x58, - 0x3b, 0xf1, 0x81, 0x83, 0x6c, 0x3b, 0xe9, 0x93, 0x0b, 0xac, 0x8f, 0xa4, 0x60, 0xe9, - 0x68, 0xaa, 0x71, 0x09, 0x87, 0x0b, 0xbe, 0xd1, 0x7d, 0xf5, 0xf8, 0x88, 0xc8, 0xca, - 0x14, 0x67, 0xae, 0x17, 0xdb, 0xbc, 0xde, 0x31, 0xc1, 0x10, 0x5c, 0xb5, 0xbd, 0xa8, - 0x8a, 0xc6, 0xc6, 0x27, 0x00, 0x2c, 0xe2, 0x1c, 0x02, 0x14, 0x0f, 0xfe, 0x81, 0xec, - 0x58, 0xbf, 0x1e, 0x6d, 0x1b, 0xb7, 0xaa, 0xad, 0xa4, 0x1f, 0xba, 0x0b, 0xb5, 0x88, - 0x77, 0x8a, 0x7f, 0x65, 0x20, 0x2a, 0xd8, 0x11, 0xea, 0x73, 0xd2, 0x6c, 0x74, 0x55, - 0x03, 0x95, 0xaf, 0xf7, 0x53, 0x25, 0x10, 0x7c, 0x9b, 0x3f, 0x9a, 0xe9, 0xdc, 0xdc, - 0xd8, 0x6e, 0xd0, 0x81, 0xa2, 0xe7, 0x42, 0x47, 0x19, 0xa3, 0xd1, 0x85, 0xb7, 0xe0, - 0xa4, 0x3a, 0x47, 0x2e, 0x29, 0x8a, 0xc0, 0xaf, 0xdc, 0x52, 0x87, 0xd7, 0xad, 0x12, - 0x4c, 0xd9, 0x40, 0x5a, 0x62, 0xcd, 0x1c, 0xa0, 0x8b, 0x28, 0x2e, 0xfe, 0xf7, 0xf9, - 0x28, 0xdf, 0x76, 0xe2, 0x82, 0x1a, 0x41, 0x84, 0x13, 0xeb, 0x7c, 0xea, 0xa5, 0xff, - 0x12, 0x90, 0xb0, 0x3e, 0xc9, 0x1c, 0xe6, 0xdd, 0x28, 0x13, 0x0c, 0x3a, 0xb0, 0xb2, - 0x3b, 0x60, 0x2b, 0xd5, 0xbe, 0x5d, 0xc2, 0x60, 0x03, 0xaa, 0xe0, 0x4b, 0x33, 0xd7, - 0xbd, 0x25, 0x90, 0xe9, 0x0c, 0x8c, 0x38, 0x8e, 0xa7, 0x95, 0x51, 0x22, 0xdb, 0xac, - 0xa6, 0x7b, 0x30, 0x39, 0x5a, 0x92, 0x8b, 0x57, 0xb8, 0x57, 0x51, 0x23, 0x20, 0x5a, - 0xe1, 0x91, 0x52, 0xe4, 0x1e, 0x00, 0x29, 0x31, 0xb4, 0x57, 0x46, 0x19, 0x8e, 0x5d, - 0xd9, 0x57, 0x1a, 0x56, 0xa7, 0xe0, 0xd4, 0x23, 0xff, 0x27, 0x98, 0x9d, 0x3e, 0xb4, - 0x17, 0xec, 0xd3, 0xc3, 0x09, 0x3f, 0xb8, 0x2c, 0x56, 0x58, 0xe2, 0x96, 0x24, 0xc5, - 0x32, 0x19, 0xa6, 0x0c, 0xd0, 0xa8, 0xc4, 0xda, 0x36, 0x7e, 0x29, 0xa7, 0x17, 0x79, - 0xa7, 0x30, 0x32, 0x98, 0x5a, 0x3d, 0x1f, 0xd0, 0x3d, 0x02, 0xd0, 0x6e, 0x05, 0x56, - 0x6f, 0x3b, 0x84, 0x36, 0x7c, 0xf0, 0xfa, 0xee, 0x9b, 0xc3, 0xbd, 0x7a, 0x3a, 0x60, - 0x6a, 0x9f, 0xdb, 0x84, 0x9c, 0x5d, 0x82, 0xd0, 0xa6, 0x19, 0x23, 0xc2, 0xe5, 0xd8, - 0x02, 0x63, 0xa8, 0xa5, 0x0c, 0x38, 0xbd, 0x03, 0x87, 0x72, 0xc4, 0x14, 0x3d, 0x8b, - 0x7a, 0xcf, 0xd7, 0x4e, 0x72, 0xc0, 0x4d, 0x89, 0x24, 0x8d, 0xff, 0x20, 0xfe, 0x8d, - 0xc5, 0xec, 0x21, 0x49, 0x05, 0x0a, 0xa2, 0x41, 0x64, 0xe8, 0x5f, 0x67, 0x44, 0xad, - 0x0c, 0xac, 0xf1, 0xa8, 0xb7, 0x01, 0x26, 0xf4, 0x82, 0xc0, 0x92, 0xed, 0x9f, 0x61, - 0x27, 0xd2, 0x05, 0x0d, 0x12, 0xe8, 0x78, 0xa7, 0x96, 0x53, 0xa1, 0xe8, 0x4d, 0xae, - 0xc3, 0xeb, 0xe6, 0x2d, 0x5f, 0x6c, 0x4a, 0xbe, 0x5c, 0xe9, 0x0a, 0x7f, 0xe2, 0xe5, - 0x2a, 0x8d, 0x78, 0x46, 0xe8, 0xed, 0xf2, 0xf2, 0xbc, 0xe0, 0x5a, 0x03, 0x7c, 0x82, - 0x03, 0x22, 0xca, 0xad, 0x12, 0x61, 0x46, 0x7d, 0xcf, 0xb7, 0xd6, 0xb6, 0x13, 0x3d, - 0xc2, 0x1e, 0x80, 0x96, 0xc7, 0xe9, 0xf8, 0xe9, 0xe1, 0x0c, 0x1e, 0x3f, 0xac, 0x40, - 0x58, 0xb6, 0x82, 0xc6, 0x8e, 0x02, 0xfa, 0xca, 0xe0, 0xf9, 0xc2, 0xdd, 0x4d, 0x64, - 0xd9, 0x04, 0x61, 0x52, 0xb4, 0x76, 0x23, 0x32, 0x93, 0x9f, 0x17, 0xe6, 0xaa, 0xf7, - 0xd8, 0xb9, 0xd3, 0x58, 0xe2, 0x21, 0x8d, 0x4e, 0x0d, 0x69, 0x02, 0xf1, 0x19, 0xe1, - 0xc6, 0x4e, 0xec, 0x4c, 0x8b, 0x53, 0x28, 0x09, 0x70, 0x71, 0x31, 0xf0, 0x1f, 0x55, - 0xc7, 0xad, 0x04, 0xcf, 0xb6, 0x3f, 0x7c, 0x4a, 0x3d, 0x0a, 0x2b, 0x0f, 0xfb, 0x0b, - 0x05, 0x02, 0xbe, 0x05, 0x5b, 0x8c, 0x94, 0xca, 0x80, 0xbb, 0x0a, 0x1d, 0x13, 0xcd, - 0x4c, 0xd6, 0x9a, 0xb9, 0x83, 0x04, 0xae, 0x25, 0x15, 0xd5, 0xf7, 0x69, 0x9d, 0x4a, - 0xbe, 0xe5, 0xc2, 0x0b, 0xe6, 0x09, 0x02, 0x73, 0x51, 0x10, 0x12, 0xf2, 0x34, 0xbd, - 0x85, 0xa7, 0xef, 0xf5, 0xfb, 0x63, 0x4c, 0xff, 0x26, 0x58, 0xba, 0x65, 0x16, 0x04, - 0x85, 0x63, 0x09, 0x5e, 0xce, 0xfb, 0x30, 0x15, 0xee, 0x3f, 0x03, 0xca, 0x52, 0xa1, - 0x77, 0xf2, 0x61, 0xec, 0xdc, 0x26, 0xbc, 0x08, 0x9d, 0x34, 0xc6, 0x40, 0x48, 0x46, - 0xe9, 0xc6, 0x47, 0xfc, 0xfe, 0x98, 0xcc, 0x6a, 0xcd, 0xbb, 0x46, 0x4f, 0x64, 0x27, - 0x8a, 0xd8, 0xce, 0x9d, 0x1a, 0xe0, 0xd4, 0x15, 0xbc, 0x0c, 0x05, 0x24, 0x5f, 0xdd, - 0xaf, 0x4e, 0xbc, 0x8d, 0xc7, 0x03, 0xa8, 0x5c, 0xb2, 0x70, 0xf7, 0x96, 0xad, 0x2d, - 0x93, 0x7e, 0x2a, 0xc0, 0xd5, 0xe0, 0xa3, 0x48, 0x21, 0x75, 0x80, 0x00, 0xaa, 0x59, - 0xc9, 0xd4, 0x65, 0x24, 0x85, 0x29, 0x4e, 0xe0, 0xab, 0x29, 0x69, 0x6b, 0x21, 0x43, - 0x0f, 0xa5, 0x4d, 0xcf, 0xbf, 0x2b, 0x9c, 0x49, 0xd1, 0x42, 0x06, 0x42, 0x09, 0xee, - 0xee, 0xd4, 0xd4, 0x71, 0xff, 0xc0, 0x17, 0xd4, 0xe2, 0x0a, 0x79, 0x6b, 0x09, 0x27, - 0x80, 0x4c, 0x06, 0x1b, 0x9f, 0x4a, 0x70, 0x91, 0xfe, 0x01, 0x5a, 0xda, 0x68, 0xfd, - 0x84, 0x42, 0xe0, 0x18, 0x25, 0xc8, 0x8d, 0xfe, 0x55, 0xcf, 0x5d, 0xe3, 0x89, 0x36, - 0xf7, 0xce, 0x25, 0x31, 0x1b, 0x90, 0x2b, 0xa9, 0x7a, 0x3c, 0x12, 0xa9, 0x5c, 0xfa, - 0x1c, 0x3a, 0x59, 0x1b, 0x81, 0x8f, 0x60, 0x83, 0x27, 0x09, 0xd9, 0xe4, 0x83, 0x9e, - 0x41, 0x0f, 0xb3, 0x6b, 0x84, 0xf3, 0xac, 0x4f, 0x07, 0x0f, 0xc3, 0x5e, 0x16, 0x19, - 0x78, 0x25, 0x9e, 0x5b, 0x8e, 0xdc, 0x74, 0x4d, 0x90, 0x91, 0x9a, 0xa7, 0x70, 0xbb, - 0x36, 0x21, 0x51, 0x28, 0xe5, 0x82, 0xb5, 0x96, 0x41, 0xe2, 0x38, 0x52, 0xe9, 0x58, - 0xeb, 0x8f, 0xc3, 0xc0, 0xaa, 0x96, 0x15, 0x2b, 0xa4, 0xf7, 0x7f, 0x13, 0x8d, 0x6a, - 0x67, 0x12, 0xa3, 0xae, 0x32, 0x26, 0x01, 0x58, 0x83, 0xf8, 0x1d, 0xb2, 0x3e, 0x58, - 0x3c, 0x86, 0x9c, 0x4c, 0x71, 0x14, 0x3a, 0x6f, 0xff, 0xd6, 0x5e, 0x8d, 0xfd, 0xc5, - 0x0c, 0x99, 0xa2, 0xf1, 0xf3, 0x14, 0xcd, 0xcc, 0x71, 0x35, 0x9e, 0x23, 0x5f, 0x1d, - 0x7d, 0xc2, 0xb5, 0xf3, 0x8e, 0xf7, 0xb9, 0x70, 0x84, 0x31, 0x63, 0xc0, 0x3f, 0x9d, - 0xd4, 0x0a, 0x80, 0x15, 0xef, 0xdc, 0x87, 0x91, 0x95, 0x6a, 0x3f, 0x3c, 0xed, 0xd9, - 0xea, 0x64, 0xf8, 0xef, 0xa7, 0xa0, 0x81, 0x5a, 0x70, 0x38, 0x1d, 0x71, 0x46, 0x78, - 0x17, 0xbd, 0x04, 0xca, 0x52, 0x9a, 0xed, 0xe0, 0x7f, 0xf6, 0x0d, 0x17, 0x6a, 0xed, - 0x0f, 0x85, 0x5a, 0x2e, 0xae, 0xa8, 0x9e, 0xae, 0xac, 0xa8, 0x93, 0x58, 0xc0, 0x81, - 0x82, 0x6a, 0x08, 0x12, 0xa5, 0xbc, 0xa2, 0x8b, 0xe1, 0x37, 0x3f, 0x08, 0x6d, 0xbd, - 0xba, 0x7e, 0x43, 0xe2, 0x03, 0x21, 0x2c, 0x9f, 0xed, 0x21, 0x47, 0x4b, 0xa1, 0x9a, - 0x05, 0x5f, 0xfc, 0xc1, 0x79, 0x41, 0x2e, 0x89, 0x3a, 0x74, 0x48, 0x32, 0x29, 0x8c, - 0x5f, 0xe2, 0x4c, 0xc6, 0xb1, 0x86, 0x67, 0xf4, 0x9b, 0x34, 0xdf, 0xb1, 0x23, 0x79, - 0x26, 0x74, 0x19, 0xa9, 0xcb, 0x94, 0x03, 0xd8, 0x16, 0x7d, 0x8d, 0x1e, 0x91, 0xd2, - 0x81, 0x1a, 0x04, 0x3b, 0x29, 0x24, 0x3b, 0x06, 0x9b, 0x37, 0x58, 0x78, 0x47, 0xdc, - 0x6f, 0xcd, 0xdb, 0x18, 0x31, 0xbd, 0x1c, 0xc2, 0x56, 0x7c, 0xa0, 0x33, 0xac, 0x40, - 0xf7, 0x4a, 0xb6, 0x95, 0x5f, 0x68, 0x3b, 0x12, 0xe4, 0xe8, 0x25, 0x4e, 0x4e, 0xa7, - 0x60, 0xd3, 0x8b, 0x3f, 0x46, 0x79, 0x1c, 0x5c, 0x4c, 0xb1, 0x2b, 0xc7, 0xcc, 0xb0, - 0xed, 0x18, 0x65, 0xf2, 0x5d, 0x60, 0x1c, 0x30, 0x3f, 0x81, 0xfb, 0x1f, 0xa1, 0xdb, - 0x48, 0x53, 0x3d, 0x3d, 0x6b, 0x28, 0x8e, 0x4d, 0x9a, 0x4d, 0xff, 0x8e, 0xc2, 0x1c, - 0x96, 0xf5, 0x78, 0x39, 0x97, 0x10, 0xc8, 0x25, 0xfe, 0x7e, 0x32, 0xf9, 0x3a, 0x8c, - 0x07, 0x43, 0xf9, 0xeb, 0xd5, 0x4c, 0xc1, 0x51, 0xc7, 0x61, 0x03, 0x37, 0xae, 0xbf, - 0x7e, 0x9b, 0x91, 0x57, 0x20, 0xa5, 0x43, 0x51, 0xd4, 0x9a, 0xb8, 0xc2, 0x2f, 0xa3, - 0x49, 0x98, 0xdc, 0xf5, 0x83, 0xd4, 0x38, 0x73, 0x61, 0xef, 0x3f, 0xf8, 0x6f, 0x50, - 0xec, 0x53, 0xf4, 0x92, 0x49, 0xe4, 0xad, 0x34, 0x96, 0x03, 0x06, 0x6f, 0xc9, 0xc6, - 0x61, 0xd6, 0x9f, 0x91, 0x1d, 0xfa, 0x72, 0x41, 0xc8, 0xd5, 0x79, 0x2d, 0x43, 0xc4, - 0x57, 0xd5, 0xde, 0x96, 0x52, 0x3a, 0x53, 0xd6, 0x67, 0xec, 0x5c, 0x4e, 0xf9, 0xd5, - 0x02, 0xa1, 0x6f, 0x15, 0x22, 0x47, 0x58, 0x96, 0xd7, 0x9b, 0xc5, 0x78, 0x33, 0xe9, - 0x77, 0x17, 0x1c, 0x32, 0x4d, 0xce, 0x2a, 0x1e, 0xa1, 0xe4, 0x30, 0x4f, 0x49, 0xe4, - 0x3a, 0xe0, 0x65, 0xe3, 0xfb, 0x19, 0x6f, 0x76, 0xd9, 0xb8, 0x79, 0xc7, 0x20, 0x08, - 0x62, 0xea, 0xd1, 0x8d, 0xea, 0x5f, 0xb6, 0xa1, 0x7a, 0xce, 0xa3, 0x33, 0x86, 0xeb, - 0x4c, 0xa1, 0xb5, 0x14, 0x86, 0xa9, 0x14, 0x8f, 0xbd, 0xf9, 0xa9, 0x53, 0x32, 0xaa, - 0x60, 0x5c, 0x5d, 0x54, 0x83, 0xce, 0x4b, 0xa8, 0xec, 0xe0, 0x1a, 0x8f, 0xf2, 0xb7, - 0xef, 0x82, 0xd0, 0x5c, 0x0b, 0x6e, 0x86, 0x1b, 0x91, 0x5f, 0x13, 0xca, 0x0e, 0xb3, - 0xea, 0x13, 0xd5, 0x07, 0x08, 0x07, 0xa2, 0xcb, 0x66, 0x80, 0xa2, 0x49, 0xea, 0x9c, - 0x72, 0x24, 0x39, 0x2c, 0xbc, 0x8a, 0xb8, 0x25, 0x01, 0xb2, 0x6f, 0x11, 0x2a, 0xc7, - 0x89, 0xa1, 0x2a, 0x31, 0xad, 0x13, 0x14, 0xe2, 0xed, 0xe0, 0x8f, 0xad, 0x31, 0x43, - 0xaf, 0x30, 0xc2, 0x7f, 0x40, 0x3b, 0xc8, 0x66, 0xc7, 0x55, 0x17, 0x78, 0x52, 0xaf, - 0xd0, 0xab, 0xb9, 0x0a, 0xde, 0x1d, 0x68, 0x27, 0x26, 0xf4, 0x20, 0x08, 0xb4, 0x6a, - 0xd7, 0xf8, 0xab, 0xdb, 0x18, 0x11, 0x7f, 0x72, 0x64, 0x13, 0x90, 0xf0, 0x86, 0xb6, - 0xe1, 0x49, 0x8b, 0xe6, 0x95, 0x48, 0x52, 0x7e, 0x6a, 0xda, 0x2b, 0x38, 0xb9, 0xfe, - 0x12, 0x1e, 0xf6, 0x70, 0xaf, 0x74, 0x37, 0xd3, 0x25, 0x36, 0xd5, 0xcf, 0x5c, 0x4a, - 0xb1, 0x9d, 0xd9, 0x97, 0x71, 0x58, 0x2d, 0x03, 0x81, 0x04, 0xb7, 0xe0, 0x39, 0xa3, - 0x76, 0xf7, 0xac, 0xbb, 0xea, 0xdb, 0x34, 0xf9, 0x45, 0xbe, 0xb9, 0xd7, 0xca, 0x0e, - 0x4e, 0x3d, 0x5c, 0x5e, 0x4e, 0xb1, 0xd8, 0x52, 0x6e, 0xbd, 0x13, 0xda, 0xcb, 0x1b, - 0xa3, 0x57, 0x35, 0xc6, 0xd0, 0x4a, 0x45, 0x55, 0xac, 0xf4, 0xbf, 0x11, 0x76, 0x26, - 0x50, 0x0d, 0x77, 0xb3, 0x81, 0x89, 0xdd, 0x48, 0x88, 0x04, 0x12, 0x25, 0xac, 0xbe, - 0x38, 0x74, 0xa4, 0xc0, 0xf6, 0x07, 0xfe, 0x67, 0x45, 0xf9, 0x35, 0x5b, 0x3f, 0xa1, - 0x88, 0xf1, 0xd6, 0x5c, 0x09, 0xf3, 0x89, 0xaf, 0x1b, 0x9d, 0x62, 0x32, 0xaa, 0x79, - 0x44, 0x79, 0x19, 0xc5, 0x50, 0xf6, 0xf3, 0x1f, 0xec, 0x35, 0x48, 0x1c, 0xb9, 0x22, - 0xde, 0x2d, 0xb5, 0xb4, 0xda, 0x2f, 0x81, 0x94, 0x86, 0x17, 0x02, 0x8e, 0x32, 0x17, - 0x06, 0xa3, 0xa7, 0x78, 0xc1, 0x93, 0x8c, 0x44, 0x3b, 0xb0, 0x0e, 0x5b, 0x0f, 0xf0, - 0x6a, 0xd8, 0xab, 0x9b, 0x1a, 0xb0, 0xc1, 0x14, 0x77, 0x67, 0x3f, 0x85, 0xdf, 0x95, - 0x61, 0xdb, 0xea, 0x45, 0xd5, 0xf9, 0x78, 0x1e, 0xbe, 0x31, 0x7a, 0x07, 0x10, 0xae, - 0x54, 0x61, 0xe3, 0x4f, 0xe6, 0xf1, 0xb1, 0xaa, 0x9b, 0x4e, 0x67, 0xb1, 0x49, 0x10, - 0x98, 0x48, 0x02, 0xc2, 0xa7, 0xe3, 0x81, 0x93, 0xbc, 0x7b, 0xdc, 0x8b, 0xa3, 0xe4, - 0xe3, 0xd1, 0xd9, 0x33, 0xbf, 0xb5, 0x80, 0xf5, 0xb3, 0xe8, 0x7a, 0x2a, 0x06, 0x51, - 0x70, 0x51, 0x41, 0x0f, 0xe1, 0xb4, 0xff, 0x1e, 0xa0, 0xad, 0xe8, 0x24, 0xf3, 0x38, - 0x51, 0x54, 0x56, 0xa5, 0x7c, 0x7a, 0x91, 0x6a, 0x74, 0x38, 0x8e, 0xe8, 0xf1, 0x28, - 0x1f, 0x9a, 0xde, 0x0a, 0xe2, 0xa2, 0x61, 0x3a, 0x06, 0x12, 0xc4, 0x69, 0xdf, 0x79, - 0x2b, 0x8d, 0xf4, 0xca, 0xe4, 0xfc, 0x25, 0xc1, 0xca, 0xdb, 0xa9, 0x5a, 0x80, 0x7c, - 0xe6, 0x1e, 0x5a, 0x53, 0x03, 0xfa, 0xaf, 0x9e, 0x14, 0x65, 0x39, 0x96, 0xb5, 0xa8, - 0xad, 0xc3, 0x4f, 0xd4, 0x75, 0xef, 0x14, 0x99, 0x09, 0x4b, 0xab, 0xaf, 0x1f, 0x3f, - 0x07, 0xda, 0x9a, 0x39, 0x0b, 0x1d, 0x9f, 0xc9, 0xa0, 0x83, 0x27, 0x98, 0x7a, 0xdf, - 0xe9, 0x56, 0x48, 0x63, 0xfb, 0xdf, 0xa8, 0xf6, 0xb4, 0x6a, 0x88, 0x41, 0x58, 0x30, - 0x99, 0xaf, 0xb7, 0x87, 0x01, 0x18, 0xfa, 0xce, 0x76, 0x34, 0x7e, 0x40, 0xb6, 0xfd, - 0x8c, 0xd1, 0x55, 0x82, 0xae, 0x8e, 0x23, 0xbe, 0x9a, 0x02, 0x19, 0xbc, 0x3e, 0x4e, - 0x45, 0x46, 0xa3, 0x0d, 0x3b, 0xbb, 0xbd, 0x16, 0x86, 0x08, 0x68, 0x76, 0xbe, 0x0e, - 0x4c, 0x85, 0x9b, 0xe7, 0x1f, 0xb5, 0x8f, 0x4f, 0xab, 0x3d, 0x28, 0xc0, 0xb4, 0xf7, - 0xe7, 0x5a, 0xd1, 0xed, 0xb7, 0xf8, 0x89, 0x46, 0xfb, 0x40, 0xcf, 0xa5, 0x78, 0x6a, - 0x0f, 0xcb, 0xa1, 0x30, 0x3c, 0x83, 0x47, 0xec, 0xee, 0x93, 0xd4, 0x6d, 0x14, 0x0b, - 0xb5, 0xf6, 0x95, 0x31, 0xd6, 0x66, 0x54, 0x8b, 0x10, 0x9c, 0xe7, 0x64, 0xbe, 0xad, - 0x7c, 0x87, 0xbd, 0x4c, 0x87, 0x64, 0x94, 0xde, 0x82, 0xdb, 0x6e, 0x50, 0x73, 0xa6, - 0xc9, 0x4f, 0x7c, 0x09, 0x9a, 0x40, 0xd7, 0xa3, 0x1c, 0x4a, 0x04, 0xb6, 0x9c, 0x9f, - 0xcc, 0xf3, 0xc7, 0xdd, 0x56, 0xf5, 0x54, 0x47, 0x76, 0xc5, 0x3b, 0x4d, 0xf7, 0x95, - 0x39, 0x81, 0xd5, 0x5a, 0x96, 0xa6, 0xdc, 0xff, 0x99, 0x04, 0xa9, 0x08, 0x42, 0xe5, - 0xba, 0xfe, 0xc8, 0x84, 0x0c, 0x2d, 0x25, 0x5b, 0xf5, 0xad, 0x61, 0xc4, 0x60, 0xf9, - 0x8f, 0xeb, 0x82, 0xa1, 0x0f, 0xa1, 0xc0, - ], - script_code: vec![0x65, 0x6a, 0x65, 0x51, 0x52, 0x65, 0x63], - transparent_input: None, - hash_type: 1, - amount: 1712463999734827, - consensus_branch_id: 1537743641, - sighash: [ - 0xbb, 0x10, 0x30, 0x0e, 0x4d, 0xaf, 0xe3, 0x0c, 0x3f, 0xf0, 0x26, 0x34, 0xd0, 0xe0, - 0x03, 0x2f, 0x17, 0x15, 0xb0, 0x0c, 0xbc, 0x77, 0x3d, 0xf6, 0xb0, 0x9e, 0x00, 0x43, - 0x38, 0x6a, 0x14, 0x18, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x02, 0x13, 0xe5, 0x6c, 0x77, 0x2f, - 0x2c, 0x3b, 0x86, 0x0e, 0xa5, 0xb0, 0x3a, 0x88, 0x54, 0xbc, 0x6e, 0x65, 0x90, 0xd6, - 0x3c, 0xc0, 0xea, 0x54, 0xf1, 0x0b, 0x73, 0xba, 0x24, 0x1b, 0xf7, 0x4b, 0x63, 0x55, - 0x51, 0xa2, 0xaa, 0x06, 0x65, 0x6a, 0xac, 0x52, 0x51, 0x63, 0x36, 0x8b, 0x26, 0xd7, - 0x0a, 0x73, 0x7f, 0x26, 0x76, 0x85, 0x99, 0x8a, 0x3f, 0x7d, 0x26, 0x37, 0x91, 0x49, - 0x09, 0xc7, 0x46, 0x49, 0x5d, 0x24, 0xc4, 0x98, 0x63, 0x5e, 0xf9, 0x7a, 0xc6, 0x6a, - 0x40, 0x08, 0x94, 0xc0, 0x9f, 0x73, 0x48, 0x8e, 0x07, 0x6a, 0x53, 0x65, 0x52, 0x51, - 0x65, 0x52, 0x05, 0xf9, 0x1a, 0xd7, 0x00, 0x79, 0x65, 0xc2, 0x99, 0x36, 0x1d, 0x60, - 0x0d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x7e, 0x89, 0xee, 0x09, 0x62, 0xf5, 0x8c, 0x05, 0x1d, 0x11, - 0xd0, 0x55, 0xfc, 0xe2, 0x04, 0xa5, 0x62, 0xde, 0x68, 0x08, 0x8a, 0x1b, 0x26, 0x48, - 0xb8, 0x17, 0x4c, 0xbc, 0xfc, 0x8b, 0x5b, 0x5c, 0xd0, 0x77, 0x11, 0x5a, 0xfd, 0xe1, - 0x84, 0x05, 0x05, 0x4e, 0x5d, 0xa9, 0xa0, 0x43, 0x10, 0x34, 0x2c, 0x5d, 0x3b, 0x52, - 0x6e, 0x0b, 0x02, 0xc5, 0xca, 0x17, 0x22, 0xba, 0xde, 0xee, 0x23, 0xd1, 0x45, 0xe8, - 0xeb, 0x22, 0x13, 0xfc, 0x4a, 0xf1, 0xe4, 0x50, 0xe4, 0xd5, 0x21, 0x7c, 0x66, 0x17, - 0x00, 0x8c, 0x78, 0xf4, 0xfb, 0x11, 0x12, 0xf4, 0x02, 0x8a, 0x70, 0x4f, 0xc5, 0xa9, - 0x38, 0x2c, 0x6b, 0x03, 0xe7, 0xd8, 0x08, 0x5e, 0x90, 0x6c, 0xf8, 0x4c, 0xa2, 0xc1, - 0x20, 0x7c, 0x87, 0xa2, 0xbc, 0xe2, 0x08, 0x0a, 0x98, 0x91, 0x66, 0x8d, 0x69, 0xb0, - 0x44, 0xbe, 0xce, 0xd6, 0xcd, 0xa3, 0x2c, 0x22, 0x9c, 0x91, 0x17, 0x91, 0x7a, 0xa0, - 0x7d, 0xdf, 0xfc, 0xd3, 0x77, 0x39, 0x5c, 0xba, 0x61, 0x6d, 0x63, 0xc0, 0xb6, 0x9c, - 0x01, 0xfc, 0xc4, 0x53, 0x91, 0xfd, 0x5b, 0x87, 0x63, 0xfb, 0x96, 0xd7, 0xca, 0x33, - 0x3a, 0x12, 0xde, 0x3c, 0xef, 0xa9, 0x1c, 0x6c, 0x98, 0xf9, 0x47, 0x3b, 0x8e, 0x10, - 0x4a, 0x71, 0x29, 0x3e, 0x46, 0x37, 0x47, 0x05, 0xba, 0xf6, 0x5f, 0xa4, 0x13, 0x84, - 0xba, 0x5c, 0x8e, 0x0c, 0x88, 0xa3, 0xeb, 0x07, 0xe0, 0xbe, 0x34, 0xda, 0xdd, 0xfa, - 0xbb, 0x7b, 0x65, 0x54, 0x3b, 0x5f, 0x39, 0xcb, 0x20, 0x23, 0xd4, 0x67, 0x89, 0xeb, - 0x7d, 0x98, 0x9a, 0xf7, 0x79, 0xe5, 0xb8, 0xd2, 0x83, 0x85, 0xa8, 0x5b, 0x0d, 0xa2, - 0xab, 0xe0, 0x7f, 0x0c, 0x2b, 0xb4, 0x25, 0x5f, 0xce, 0xa0, 0x31, 0x88, 0x52, 0x7a, - 0x30, 0x7d, 0x40, 0x91, 0x59, 0xe9, 0x01, 0x66, 0xfa, 0xc6, 0xa0, 0x70, 0xba, 0x05, - 0xb3, 0xe4, 0xdb, 0xfd, 0x3a, 0x2b, 0xfc, 0xc9, 0xee, 0x6e, 0xd0, 0x16, 0xc0, 0xf6, - 0x65, 0xbe, 0x81, 0x33, 0xb7, 0xdc, 0x1d, 0x86, 0x04, 0x4d, 0xb0, 0xf9, 0x03, 0x40, - 0xfb, 0x0e, 0x9f, 0x8b, 0xc2, 0xe4, 0xdb, 0x53, 0x82, 0xa8, 0xb4, 0xf8, 0x15, 0xb4, - 0xe8, 0x43, 0x4a, 0xd0, 0xdf, 0xbc, 0x51, 0xa5, 0xe9, 0xb1, 0x45, 0xe1, 0x59, 0x6c, - 0xbf, 0x46, 0x70, 0x03, 0xe0, 0x5d, 0xfd, 0xaf, 0xbb, 0x0c, 0xf3, 0xdd, 0xee, 0x28, - 0xd7, 0x6a, 0x82, 0x42, 0x8e, 0x8a, 0xba, 0x43, 0x64, 0xe8, 0x4b, 0xac, 0x37, 0x92, - 0x98, 0xdf, 0x29, 0x32, 0xe6, 0x9b, 0xb5, 0xd0, 0x0b, 0x51, 0x6e, 0xfc, 0x33, 0xae, - 0x6c, 0xc3, 0x94, 0x7c, 0xeb, 0x09, 0xed, 0x37, 0x16, 0x67, 0x21, 0x2a, 0x83, 0x1b, - 0x54, 0x85, 0xea, 0xfc, 0xe8, 0x48, 0x81, 0x88, 0xea, 0x4e, 0x27, 0xd0, 0xcd, 0xf7, - 0xdd, 0xd3, 0x48, 0xab, 0xff, 0x77, 0x7f, 0x4a, 0x13, 0xbb, 0xc7, 0x16, 0xb6, 0xa5, - 0x94, 0x4e, 0xe7, 0x27, 0x96, 0x56, 0x90, 0xe2, 0x09, 0xb4, 0x9e, 0xb9, 0x62, 0xc0, - 0x39, 0x97, 0x5f, 0x03, 0x9e, 0xd5, 0xc6, 0xe4, 0xc4, 0x00, 0xd8, 0x87, 0x75, 0x94, - 0x33, 0xd3, 0xad, 0x71, 0x6d, 0xa0, 0xcb, 0x44, 0x61, 0x13, 0xc7, 0x72, 0x7a, 0x64, - 0xb5, 0x8c, 0x3f, 0x8a, 0x0f, 0x81, 0x18, 0x9f, 0x02, 0x00, 0x52, 0x33, 0xa8, 0x13, - 0x66, 0xae, 0xe7, 0x3c, 0xec, 0x85, 0x22, 0x8e, 0xbc, 0xfd, 0x5e, 0xe3, 0xc3, 0xfb, - 0x44, 0xdb, 0x76, 0xba, 0x24, 0x3f, 0x28, 0x42, 0xb7, 0xb5, 0xfc, 0x74, 0x6a, 0x03, - 0x1b, 0x0b, 0xc4, 0xbd, 0x4f, 0xc9, 0xfd, 0x83, 0x35, 0x65, 0xea, 0x85, 0x2b, 0x92, - 0xb2, 0x24, 0xf6, 0x99, 0x03, 0x18, 0xad, 0x8c, 0x7d, 0x94, 0x37, 0xe2, 0x0e, 0x2a, - 0x1f, 0x20, 0xe8, 0x18, 0x03, 0x05, 0x7c, 0x5a, 0xba, 0xaa, 0x2e, 0x5c, 0x15, 0xb9, - 0x49, 0x45, 0xcd, 0x42, 0x4c, 0x28, 0xa5, 0xfa, 0x38, 0x5d, 0xad, 0xfe, 0x49, 0x07, - 0xb2, 0x74, 0xd8, 0x42, 0x70, 0x7d, 0xb3, 0x69, 0x7a, 0x02, 0xe6, 0xc8, 0xf5, 0x42, - 0xe5, 0xec, 0xc0, 0x7f, 0xe4, 0x73, 0x50, 0xd1, 0x01, 0x46, 0x70, 0x21, 0x2e, 0xfe, - 0x81, 0xfb, 0x7c, 0x73, 0xe8, 0x45, 0x0d, 0xf8, 0x14, 0xef, 0x62, 0x32, 0xf7, 0x49, - 0x0f, 0x63, 0xcc, 0xf0, 0x74, 0x80, 0xf8, 0x84, 0xa6, 0x6e, 0xaf, 0xfc, 0x28, 0xfe, - 0xa4, 0x48, 0xd7, 0xb4, 0x01, 0xcd, 0xae, 0x10, 0xe7, 0xc0, 0xc7, 0xf9, 0xa7, 0xb1, - 0x53, 0x31, 0x96, 0x9f, 0xc8, 0xcb, 0x36, 0x39, 0x67, 0x73, 0xde, 0x19, 0x19, 0x31, - 0xc7, 0x50, 0xf6, 0xce, 0x5c, 0xaa, 0xf2, 0x97, 0x68, 0xeb, 0xb2, 0x7d, 0xac, 0xc7, - 0x38, 0x05, 0x6a, 0x81, 0x25, 0xb4, 0x77, 0x2b, 0xf8, 0x7a, 0xe1, 0x0a, 0x8a, 0x30, - 0x9b, 0x9b, 0xd6, 0x55, 0x04, 0x3c, 0xfc, 0x31, 0x59, 0x49, 0x43, 0x68, 0xc5, 0xab, - 0x8c, 0xad, 0xb7, 0xf6, 0x71, 0xe9, 0x62, 0x6b, 0xd2, 0x63, 0xe3, 0x11, 0x81, 0xa6, - 0x04, 0xb5, 0x06, 0xa0, 0x3b, 0x43, 0x9a, 0x7f, 0xfe, 0x43, 0x55, 0x89, 0x24, 0x77, - 0xe2, 0xbd, 0xf3, 0x38, 0xc6, 0x2c, 0x39, 0x22, 0xf7, 0xd3, 0xc9, 0xa5, 0x6c, 0x71, - 0x03, 0xd9, 0x11, 0x94, 0x8a, 0x84, 0xb5, 0xae, 0x2d, 0xbb, 0x16, 0xa3, 0x76, 0x1a, - 0xdd, 0x05, 0x3a, 0x0f, 0x96, 0x7e, 0x6b, 0x5b, 0xc9, 0x42, 0x11, 0xb6, 0x54, 0x71, - 0x53, 0x26, 0x7c, 0x6e, 0xe1, 0xca, 0xd0, 0xd9, 0x74, 0xa7, 0x10, 0x88, 0x58, 0x37, - 0x35, 0xe4, 0xf6, 0x3d, 0x33, 0x15, 0x6d, 0xad, 0xd5, 0x4c, 0x2f, 0xaf, 0x89, 0x11, - 0x4a, 0x12, 0x7b, 0x97, 0xb9, 0x4c, 0xc2, 0xa2, 0x2e, 0xf3, 0x03, 0xf4, 0x59, 0xd0, - 0x4f, 0xc0, 0xb5, 0x3a, 0xce, 0x59, 0x18, 0xd4, 0x7f, 0xf3, 0x3a, 0x55, 0x8b, 0xd7, - 0x1a, 0x75, 0xf3, 0x55, 0xfb, 0xd0, 0x6b, 0xbc, 0xcf, 0x4e, 0x02, 0xc3, 0xc0, 0xa4, - 0xb6, 0x3d, 0x0c, 0xc9, 0x49, 0x80, 0x1d, 0x63, 0xa6, 0x4c, 0xb2, 0xd3, 0x23, 0x73, - 0xb2, 0xc7, 0xb2, 0x74, 0xab, 0x2d, 0xb4, 0x68, 0x21, 0x42, 0xc8, 0xb2, 0x1d, 0x84, - 0xc4, 0x81, 0xf5, 0xef, 0x21, 0xe4, 0xb5, 0xe3, 0x60, 0x34, 0x51, 0xbf, 0x94, 0x77, - 0x4d, 0x0e, 0xf4, 0x7f, 0x63, 0xfa, 0x6a, 0xbb, 0x78, 0xd2, 0x1c, 0x19, 0x3c, 0xbe, - 0x65, 0xb6, 0x95, 0xfe, 0x67, 0x42, 0x3c, 0x1e, 0x2d, 0x31, 0x2e, 0x27, 0x76, 0xfa, - 0x24, 0xec, 0xe8, 0x46, 0x83, 0xe7, 0x48, 0x76, 0xc5, 0x5e, 0xa0, 0x36, 0x9e, 0x4e, - 0xa0, 0xe8, 0x64, 0x94, 0xe0, 0x0d, 0xde, 0x23, 0x6a, 0x16, 0x89, 0x73, 0x1f, 0x0a, - 0x5d, 0x82, 0x03, 0xaf, 0xde, 0x5c, 0x42, 0x36, 0x40, 0xb8, 0x1e, 0x4f, 0x63, 0x1c, - 0x98, 0x1c, 0x11, 0xa2, 0xe1, 0xd1, 0x84, 0xc6, 0x7c, 0x52, 0x8d, 0xf9, 0x2d, 0x53, - 0xae, 0xc4, 0x4a, 0x40, 0xa4, 0xea, 0x2a, 0x13, 0x1b, 0x47, 0x33, 0xcf, 0xe4, 0x5c, - 0x6b, 0x00, 0x12, 0xc3, 0xe9, 0xe2, 0x09, 0x75, 0xba, 0xae, 0xcb, 0x02, 0x32, 0xdf, - 0x88, 0x0b, 0xd7, 0xd1, 0xde, 0x13, 0xe1, 0x34, 0x94, 0x62, 0xec, 0x8d, 0x5d, 0xf3, - 0xe7, 0x80, 0xff, 0xa7, 0x2e, 0xba, 0x8a, 0x8d, 0xf7, 0xfc, 0xf3, 0x98, 0xec, 0x23, - 0x05, 0x13, 0xca, 0x9d, 0x61, 0x23, 0xf8, 0xb9, 0xd8, 0x17, 0x85, 0x60, 0xda, 0xf9, - 0x75, 0x11, 0x19, 0x55, 0xa2, 0xbc, 0xa3, 0x42, 0x3e, 0xee, 0xfc, 0x52, 0x7b, 0xe3, - 0xa8, 0x54, 0x3e, 0xb9, 0x0a, 0x5e, 0xc0, 0x2f, 0x35, 0xa7, 0xc6, 0x4b, 0x7d, 0xd5, - 0x9a, 0x72, 0xda, 0x00, 0x74, 0x63, 0x4e, 0x01, 0xd2, 0xab, 0xf3, 0x63, 0x7a, 0xdd, - 0x77, 0xc7, 0x35, 0x0f, 0x12, 0xb0, 0x11, 0xb2, 0x94, 0x16, 0x8e, 0xc7, 0x55, 0x76, - 0xe4, 0x7d, 0x16, 0x9e, 0x39, 0x38, 0xbf, 0x6a, 0xe2, 0xaa, 0x8f, 0xf7, 0xcf, 0xba, - 0x7c, 0xac, 0xb1, 0xf9, 0x2b, 0x6e, 0x4c, 0x24, 0x97, 0xbf, 0xfa, 0x9f, 0x17, 0xca, - 0xd2, 0x42, 0xfa, 0x9c, 0x31, 0x79, 0xc1, 0xa3, 0xaa, 0x81, 0xf7, 0x36, 0x16, 0x49, - 0x57, 0x2c, 0x71, 0x5c, 0x25, 0xa1, 0xf6, 0xcd, 0x5a, 0xce, 0x82, 0xc0, 0x0a, 0xb2, - 0x34, 0x2b, 0x9c, 0x3c, 0xb4, 0xff, 0xfd, 0xda, 0x16, 0x0c, 0xa5, 0xab, 0x9e, 0x9b, - 0xaf, 0x21, 0x39, 0xef, 0x9a, 0xfb, 0xe1, 0xb1, 0xf3, 0x09, 0x46, 0x2a, 0xfc, 0xe4, - 0x62, 0xa7, 0x9b, 0xb9, 0x69, 0x8e, 0x22, 0xc9, 0x57, 0xc5, 0x90, 0xa7, 0x53, 0xa7, - 0x6b, 0x87, 0xe0, 0x09, 0x12, 0x1e, 0x06, 0xf6, 0xa1, 0xbf, 0x62, 0xa0, 0x8b, 0xf4, - 0x35, 0xd9, 0x2e, 0x2f, 0xff, 0xe8, 0x6e, 0x2a, 0x9c, 0xbb, 0xa9, 0x13, 0x3a, 0x68, - 0xe4, 0xae, 0xbf, 0x33, 0xc3, 0x84, 0x36, 0xf2, 0x54, 0x5f, 0xc2, 0xd5, 0x28, 0x32, - 0xd1, 0x65, 0xaf, 0x41, 0x5b, 0x24, 0x4a, 0xdc, 0x5f, 0x57, 0x37, 0x7d, 0xee, 0xdf, - 0x46, 0x0a, 0xa3, 0xbe, 0xb4, 0x34, 0x19, 0xc6, 0xb0, 0x82, 0xe8, 0x35, 0xce, 0x84, - 0xca, 0x13, 0xb6, 0x90, 0x8a, 0x88, 0x13, 0xc0, 0x21, 0xde, 0x9f, 0xa9, 0xa4, 0x4e, - 0x4c, 0x18, 0xdc, 0xb3, 0xd2, 0x1f, 0xaa, 0xbd, 0xb4, 0x19, 0x31, 0xb2, 0xfd, 0x49, - 0x76, 0x44, 0xdc, 0x3a, 0x15, 0x07, 0xfa, 0x5a, 0xc7, 0xc7, 0x6b, 0xee, 0xbb, 0xdb, - 0xd1, 0xd4, 0x92, 0x99, 0xa5, 0x5b, 0xd4, 0x99, 0x27, 0xe9, 0xd7, 0xf4, 0x88, 0x4e, - 0x6e, 0xd3, 0xfd, 0x5e, 0x4b, 0x7c, 0xb8, 0x35, 0xb8, 0x33, 0x08, 0x96, 0x4e, 0x3c, - 0x46, 0x87, 0x3f, 0xd6, 0x13, 0x31, 0x7b, 0x91, 0xd2, 0x92, 0x36, 0xea, 0x90, 0xe3, - 0x65, 0xd1, 0x62, 0xcc, 0x05, 0x1c, 0x84, 0x6d, 0x24, 0x21, 0x76, 0xda, 0xf6, 0xd2, - 0x86, 0x18, 0xae, 0x31, 0xfb, 0xaa, 0xe9, 0x99, 0xa9, 0x3f, 0x17, 0x5c, 0x69, 0x38, - 0xe6, 0x31, 0xa0, 0x81, 0xf2, 0xc1, 0xf3, 0xfd, 0x78, 0x25, 0x49, 0xd3, 0xf3, 0x24, - 0x57, 0x59, 0x60, 0x6d, 0x9f, 0x92, 0xd5, 0x54, 0x8a, 0xcf, 0xea, 0xdb, 0xaf, 0x9c, - 0xaa, 0x6b, 0x93, 0xdc, 0x08, 0x82, 0x8d, 0x74, 0xf6, 0xd5, 0xfd, 0xd8, 0x33, 0x31, - 0xf0, 0x96, 0x91, 0x45, 0x95, 0x52, 0x97, 0xe6, 0x9f, 0x00, 0xfd, 0x29, 0x87, 0xf2, - 0xda, 0x2b, 0x94, 0xb9, 0x95, 0xfe, 0xcb, 0xe6, 0x22, 0xa7, 0x35, 0xef, 0x7f, 0x12, - 0x07, 0xf6, 0x71, 0x62, 0x94, 0x89, 0x20, 0x2b, 0xea, 0x0b, 0x47, 0x5e, 0x51, 0x68, - 0x1a, 0xa1, 0x67, 0x78, 0xb3, 0x9b, 0xd9, 0x23, 0xc9, 0x8d, 0xc6, 0xff, 0x83, 0x73, - 0xc7, 0x9b, 0xb1, 0x70, 0x30, 0x41, 0x7b, 0xc2, 0x00, 0xc8, 0xf0, 0xb8, 0x55, 0xac, - 0xfe, 0xc1, 0x79, 0xf7, 0x67, 0x4c, 0xec, 0x27, 0x21, 0xa1, 0x0f, 0xca, 0x69, 0x3d, - 0x83, 0xcf, 0xe5, 0xb8, 0xcd, 0xcc, 0x18, 0xf8, 0x1a, 0xd6, 0x17, 0xfa, 0x26, 0xf0, - 0xdf, 0xb8, 0x36, 0x55, 0xb8, 0xa2, 0x9a, 0x7f, 0x83, 0x42, 0x32, 0x42, 0x5e, 0x8c, - 0x47, 0x45, 0x88, 0xf1, 0x8d, 0xd3, 0x26, 0xaa, 0x39, 0x6c, 0x3e, 0x47, 0x75, 0xe0, - 0x02, 0x05, 0xfc, 0x9e, 0x45, 0xf7, 0xb7, 0xd2, 0xe6, 0xd5, 0x5d, 0xcb, 0x90, 0xe2, - 0x3f, 0xf6, 0xb5, 0x08, 0x45, 0x9a, 0xa6, 0x99, 0xbf, 0xcb, 0xd5, 0x6f, 0x10, 0x99, - 0x77, 0x64, 0xd0, 0x87, 0x40, 0x89, 0x86, 0xe7, 0x3d, 0x6e, 0x28, 0x4f, 0xea, 0x9a, - 0x23, 0xc3, 0x93, 0x11, 0x78, 0x2f, 0x86, 0xca, 0xbf, 0xf9, 0x45, 0x5e, 0x4c, 0xf6, - 0x99, 0xe5, 0xf5, 0xd4, 0xbc, 0x0b, 0x39, 0x05, 0xa4, 0xe3, 0xbd, 0x01, 0xc5, 0x4d, - 0xf8, 0x64, 0x34, 0x43, 0xbe, 0x0f, 0x88, 0x90, 0x32, 0xea, 0x32, 0x5b, 0xf0, 0x71, - 0x07, 0xfd, 0x41, 0xd6, 0x73, 0xee, 0xba, 0xe6, 0xfa, 0x63, 0x7b, 0x70, 0xcc, 0x0e, - 0xd3, 0xf0, 0x09, 0x58, 0xdf, 0xb8, 0xdc, 0xf0, 0x0e, 0x85, 0xa1, 0xd0, 0xa6, 0xa8, - 0x90, 0x81, 0x40, 0xc2, 0xf4, 0x34, 0xc2, 0xe2, 0x60, 0xef, 0xb0, 0xbc, 0xa2, 0x00, - 0x35, 0x04, 0xc9, 0x99, 0x93, 0xa9, 0xe1, 0xc0, 0xff, 0x9c, 0xef, 0xe6, 0xa6, 0x65, - 0xd7, 0x91, 0x42, 0x86, 0x90, 0xe4, 0x7e, 0xf8, 0xc1, 0x31, 0xa8, 0xe9, 0xbf, 0xb4, - 0xc3, 0x08, 0x02, 0x35, 0x03, 0x2d, 0x73, 0x1b, 0x0d, 0x38, 0x41, 0x22, 0x5f, 0x1c, - 0x11, 0xe2, 0xc2, 0x8e, 0xe8, 0x4d, 0x35, 0xf9, 0x22, 0x61, 0x00, 0x56, 0x59, 0x72, - 0xeb, 0x26, 0x9d, 0x27, 0x8e, 0xf6, 0x49, 0x79, 0xbf, 0x65, 0x15, 0xed, 0x4a, 0x68, - 0x40, 0xb0, 0x88, 0x3a, 0x9e, 0x6e, 0xf6, 0x4a, 0x0e, 0xfc, 0xae, 0x1c, 0xf2, 0x1d, - 0xfe, 0x74, 0x85, 0x4e, 0x84, 0xc2, 0x74, 0x9f, 0xac, 0x03, 0x82, 0x52, 0x75, 0xc9, - 0xb6, 0x30, 0x21, 0x84, 0xc7, 0x2d, 0xf4, 0xc4, 0xbb, 0x28, 0x62, 0xe4, 0xe8, 0xa7, - 0xd9, 0xa4, 0xa2, 0x82, 0x86, 0x6f, 0x9a, 0x7b, 0x2c, 0xfc, 0x9a, 0x56, 0x31, 0x3d, - 0xa0, 0xc4, 0x7a, 0x34, 0xb7, 0xb9, 0xcd, 0xa3, 0xac, 0xe8, 0x18, 0x5f, 0x07, 0xdf, - 0x36, 0xe4, 0x48, 0xa7, 0x6a, 0xa4, 0x77, 0xf2, 0x24, 0xd8, 0x7a, 0x07, 0x4f, 0x43, - 0xaf, 0x5d, 0x5f, 0x79, 0xb3, 0xab, 0x11, 0x28, 0xf0, 0x81, 0x91, 0x44, 0x7f, 0xa6, - 0x46, 0xbf, 0xdd, 0xe5, 0xb5, 0x1e, 0x23, 0x3c, 0xa6, 0x15, 0x5d, 0x10, 0x15, 0x85, - 0xbc, 0x2c, 0x40, 0x15, 0x8a, 0xc2, 0x10, 0x6e, 0x66, 0xa2, 0x6e, 0x46, 0x42, 0x33, - 0x70, 0x63, 0x68, 0x76, 0xb4, 0x34, 0xa7, 0x4f, 0x8c, 0xe8, 0x06, 0x00, 0x50, 0xb0, - 0x82, 0xa7, 0x9b, 0x61, 0xbb, 0x5d, 0x34, 0x4e, 0xb5, 0xa1, 0x15, 0x83, 0x26, 0xce, - 0xd9, 0xa9, 0xd9, 0xf5, 0x4f, 0xb2, 0xfe, 0x8f, 0x9f, 0x05, 0xcd, 0x11, 0x1e, 0xe4, - 0x6c, 0x47, 0x10, 0xf6, 0xf6, 0x3a, 0x62, 0x69, 0x45, 0x57, - ], - script_code: vec![0x53, 0x52, 0x00], - transparent_input: Some(1), - hash_type: 1, - amount: 1564816348934332, - consensus_branch_id: 1537743641, - sighash: [ - 0x21, 0x46, 0x62, 0xc6, 0x74, 0x50, 0x60, 0x3d, 0x8a, 0xa7, 0x3b, 0xea, 0xbb, 0xf7, - 0x51, 0x8d, 0x03, 0x6c, 0xe9, 0x1d, 0xc8, 0x7b, 0x01, 0x81, 0xe8, 0xa0, 0xf3, 0xfa, - 0x82, 0x2c, 0x7d, 0x8a, - ], - }, - TestVector { - tx: vec![ - 0x03, 0x00, 0x00, 0x80, 0x70, 0x82, 0xc4, 0x03, 0x01, 0x59, 0x07, 0x92, 0x9a, 0x2f, - 0x3f, 0xdb, 0x0d, 0x8f, 0x79, 0x14, 0xc4, 0x2d, 0xde, 0x2d, 0x20, 0x00, 0xf5, 0xae, - 0x02, 0xd4, 0x18, 0x21, 0xc8, 0xe1, 0xee, 0x01, 0x38, 0xeb, 0xcb, 0x72, 0x8d, 0x7c, - 0x6c, 0x3c, 0x80, 0x02, 0x65, 0x53, 0x75, 0x94, 0xc6, 0x70, 0x00, 0x6f, 0x39, 0x08, - 0x22, 0x2e, 0x89, 0xd1, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x27, 0x1a, 0xbe, 0x66, 0x0e, - 0x39, 0xe0, 0x51, 0xaa, 0xa6, 0xfc, 0xa1, 0x86, 0x22, 0x76, 0xe2, 0xba, 0xa0, 0xfe, - 0x0b, 0x16, 0x2a, 0xeb, 0xcf, 0xe3, 0xd9, 0x34, 0x9c, 0x8d, 0x15, 0x4b, 0xb7, 0xee, - 0x28, 0x21, 0x2c, 0x1b, 0xaa, 0x70, 0x5d, 0x82, 0x07, 0x0d, 0x70, 0x32, 0xf2, 0x69, - 0x5d, 0x17, 0x96, 0x80, 0x9f, 0xab, 0x41, 0x24, 0x69, 0x26, 0xaf, 0x99, 0x2b, 0x6e, - 0xee, 0x95, 0xa9, 0xa0, 0x6b, 0xc4, 0x56, 0x2c, 0x5f, 0x2f, 0x1b, 0x19, 0x54, 0x95, - 0x00, 0x37, 0x2e, 0x7a, 0xd5, 0x79, 0xa6, 0xd6, 0xd7, 0x8b, 0x33, 0x15, 0x31, 0x30, - 0xfb, 0x44, 0x8f, 0xb7, 0x9e, 0x8a, 0x66, 0x9d, 0xb8, 0xa0, 0xf3, 0x5c, 0xdf, 0x9a, - 0xe5, 0xd3, 0x2d, 0x73, 0x2f, 0xc7, 0x94, 0x18, 0xe2, 0x3b, 0x45, 0x1d, 0xdc, 0x95, - 0xa2, 0x2a, 0xba, 0xbb, 0x05, 0x6e, 0xc6, 0xb5, 0xe8, 0xba, 0x4f, 0x52, 0x4d, 0xfa, - 0xfe, 0x87, 0x52, 0x62, 0xdd, 0x7b, 0xe4, 0x1c, 0xbb, 0xc6, 0x24, 0x20, 0xd4, 0xad, - 0x6d, 0xf5, 0xc9, 0xb7, 0x13, 0x60, 0x4f, 0x65, 0x60, 0x88, 0xa4, 0x48, 0x5e, 0x93, - 0xbe, 0x19, 0x07, 0xd2, 0x7a, 0xc6, 0xec, 0x3c, 0x57, 0x25, 0x9b, 0xd6, 0x98, 0x1d, - 0x42, 0xc1, 0xb7, 0x8a, 0x29, 0xad, 0x96, 0x85, 0xe6, 0x3c, 0x49, 0x4d, 0x41, 0x29, - 0x62, 0x3e, 0xa1, 0xa7, 0xff, 0xec, 0x85, 0xfa, 0x29, 0x41, 0x10, 0x73, 0xed, 0xb2, - 0x97, 0x8e, 0xf4, 0xe4, 0x69, 0xdd, 0xd5, 0xcd, 0xa9, 0x86, 0x18, 0x99, 0x95, 0xf8, - 0x8d, 0x6a, 0xb3, 0x66, 0xdb, 0x01, 0x90, 0x01, 0xf5, 0xb2, 0x52, 0x88, 0xcf, 0x86, - 0x0f, 0xd9, 0x98, 0xee, 0x57, 0x3c, 0x8c, 0xc4, 0x8a, 0xa9, 0xef, 0xcf, 0x9b, 0x61, - 0x7e, 0x04, 0x3c, 0x32, 0x9c, 0xd1, 0xaa, 0x1a, 0x0e, 0xd3, 0xa4, 0x02, 0xfb, 0x96, - 0xe3, 0x36, 0xc7, 0x19, 0xe6, 0x25, 0x3c, 0xb6, 0x91, 0xaa, 0x0d, 0xb5, 0x27, 0x36, - 0x62, 0x6e, 0xd1, 0x97, 0x88, 0x75, 0x88, 0x8e, 0xc7, 0x6c, 0x84, 0x6b, 0xc2, 0x27, - 0x27, 0x2a, 0x02, 0x53, 0x17, 0xdf, 0xf0, 0xb1, 0x14, 0x8d, 0x92, 0xd6, 0xf5, 0xfb, - 0x7d, 0x95, 0x33, 0x67, 0x70, 0xa7, 0xd1, 0x6f, 0xac, 0x1a, 0xdd, 0x86, 0x07, 0x76, - 0xcb, 0x48, 0x02, 0x21, 0xf8, 0xfb, 0x33, 0x03, 0xe4, 0xe9, 0xb0, 0x79, 0x02, 0xd2, - 0xff, 0x86, 0xfd, 0xac, 0x72, 0x09, 0x62, 0x34, 0xae, 0xd4, 0x8d, 0xe8, 0x92, 0xff, - 0x73, 0x55, 0x07, 0x3b, 0xbf, 0x06, 0x15, 0xf6, 0x7b, 0x11, 0x00, 0xcc, 0x0a, 0xa3, - 0xba, 0x3d, 0x6c, 0x1a, 0x1a, 0x90, 0x87, 0xb1, 0x19, 0xba, 0xee, 0xbf, 0xa6, 0x2b, - 0xc9, 0xf0, 0xec, 0x47, 0x9d, 0x99, 0xc1, 0xa3, 0xb1, 0x58, 0xb5, 0x14, 0xd1, 0x62, - 0x9d, 0xb3, 0x99, 0x3f, 0x11, 0x67, 0x2a, 0x26, 0x70, 0x8e, 0x5a, 0xd8, 0x16, 0xb5, - 0x47, 0xab, 0x7e, 0x82, 0x7d, 0x07, 0x1b, 0xa7, 0x84, 0x2b, 0x3e, 0x90, 0x30, 0x53, - 0x83, 0x89, 0x6e, 0xc4, 0x90, 0x5f, 0x70, 0x03, 0x8b, 0x69, 0x4e, 0x6a, 0x5a, 0x3e, - 0x43, 0x12, 0xcd, 0x82, 0x08, 0x13, 0x2b, 0x84, 0x0f, 0x05, 0xc7, 0x14, 0x52, 0x3c, - 0xa8, 0x19, 0x72, 0x0a, 0xe2, 0x27, 0xfd, 0x1a, 0xcb, 0xa7, 0x14, 0xfa, 0x03, 0xc4, - 0x5f, 0xc5, 0x39, 0x88, 0x57, 0xb4, 0x0d, 0xc1, 0x48, 0x79, 0x85, 0x6f, 0x35, 0x4b, - 0xa4, 0xd2, 0x58, 0x1d, 0x0c, 0xda, 0x54, 0xb6, 0x38, 0xba, 0x9d, 0x76, 0xf9, 0xb5, - 0x2d, 0x17, 0xc8, 0x02, 0x8e, 0xe6, 0x3f, 0x58, 0x45, 0xb5, 0xdc, 0xef, 0xa4, 0xc3, - 0x47, 0x9b, 0xce, 0x9a, 0xca, 0xd1, 0x8b, 0x4a, 0xea, 0xe0, 0x3c, 0x0e, 0xae, 0x22, - 0x5d, 0x42, 0x84, 0x8b, 0xde, 0xaa, 0x53, 0x6d, 0x03, 0x8d, 0xd3, 0xbc, 0x97, 0x9f, - 0x06, 0x58, 0x66, 0x73, 0xbc, 0x6f, 0xf1, 0xc5, 0xd3, 0xb3, 0x20, 0xf3, 0x49, 0xa5, - 0xb3, 0xa8, 0xb3, 0x55, 0x59, 0x22, 0x96, 0xaa, 0xf6, 0x1c, 0x5b, 0x72, 0x52, 0x03, - 0x3e, 0xc0, 0xa9, 0x46, 0x6a, 0x1b, 0x85, 0x76, 0x4f, 0xb0, 0x83, 0x1b, 0x4a, 0x1a, - 0x36, 0x89, 0x0e, 0x22, 0x4c, 0x01, 0xac, 0xfc, 0xe4, 0x8e, 0xe3, 0xed, 0x93, 0x87, - 0x73, 0x98, 0xe0, 0x72, 0x6d, 0x02, 0x93, 0x6d, 0x0d, 0x03, 0x2e, 0x18, 0xe3, 0x28, - 0x8b, 0x26, 0x70, 0xe1, 0x36, 0x2c, 0x32, 0xd6, 0xe4, 0x73, 0x3b, 0x9d, 0xd2, 0xd5, - 0xf2, 0x6e, 0x1f, 0xe3, 0x06, 0xf7, 0x3c, 0x00, 0x7f, 0xdd, 0xca, 0xe9, 0xd9, 0xc0, - 0xaa, 0xf1, 0x87, 0xd7, 0x42, 0x8b, 0x1e, 0x9d, 0x47, 0x9c, 0x18, 0x23, 0x7b, 0x98, - 0x28, 0xbc, 0xa8, 0xb9, 0x8c, 0x9d, 0x9b, 0xec, 0x7d, 0x82, 0x70, 0xb5, 0xd8, 0xee, - 0xc3, 0xcc, 0x4f, 0x43, 0xfa, 0x01, 0x88, 0x52, 0x1b, 0xc6, 0x1b, 0x21, 0xdd, 0x04, - 0xe3, 0x7a, 0x83, 0xec, 0xe6, 0x8c, 0xa7, 0xa2, 0xfa, 0x6c, 0x8f, 0x9e, 0x34, 0xa6, - 0x29, 0x03, 0x35, 0xaa, 0x1f, 0xbd, 0x83, 0xd5, 0x4a, 0xaf, 0x44, 0x1e, 0x31, 0x9e, - 0xa4, 0x7a, 0x86, 0x2a, 0xd0, 0x29, 0x3c, 0xed, 0xf5, 0xdd, 0x9e, 0xda, 0xde, 0xee, - 0x33, 0xcb, 0x52, 0x2c, 0xd0, 0x11, 0x8b, 0xbd, 0x81, 0x1a, 0xce, 0x9a, 0x23, 0xbd, - 0xa3, 0x9a, 0xba, 0x72, 0xf1, 0x56, 0x6f, 0xc1, 0x68, 0x84, 0x97, 0xd2, 0xa7, 0x92, - 0x8c, 0x36, 0x70, 0x15, 0x25, 0x67, 0x8b, 0xc9, 0x72, 0x14, 0xb3, 0x1b, 0x37, 0xba, - 0xb4, 0x6b, 0x88, 0xf2, 0x7f, 0x04, 0x48, 0xde, 0xcb, 0x31, 0x62, 0x2d, 0x0f, 0x0f, - 0x87, 0xa8, 0x55, 0xba, 0x54, 0x00, 0x03, 0x32, 0x03, 0x1f, 0x73, 0xab, 0xff, 0xd4, - 0x65, 0x91, 0xda, 0x0b, 0x88, 0x72, 0x35, 0x04, 0xed, 0xb2, 0x33, 0x72, 0x30, 0xda, - 0xd2, 0xac, 0xc0, 0xd8, 0xbb, 0x68, 0xbc, 0x83, 0x7a, 0x2f, 0xf9, 0x30, 0xbf, 0xf0, - 0x6f, 0xde, 0x74, 0xeb, 0x90, 0xaa, 0xe4, 0xf6, 0x0d, 0xbb, 0x6e, 0xb8, 0x27, 0xea, - 0x99, 0x88, 0x4a, 0xcd, 0x62, 0x85, 0xa9, 0x88, 0x92, 0x80, 0x2c, 0xf5, 0x9d, 0x5d, - 0x60, 0xd0, 0x16, 0x63, 0x38, 0x7b, 0x3e, 0xd2, 0x72, 0x3b, 0xd6, 0x48, 0x9e, 0x9c, - 0x2c, 0x10, 0x6d, 0x4a, 0xa2, 0xde, 0x23, 0xce, 0xd1, 0x6c, 0x72, 0x04, 0x29, 0xc7, - 0x75, 0x3a, 0x77, 0x38, 0xec, 0x7d, 0x9d, 0xb8, 0x62, 0x42, 0x29, 0xed, 0xd2, 0x17, - 0xb8, 0x0d, 0x74, 0x87, 0x5a, 0x14, 0xca, 0xe4, 0x86, 0x3f, 0x13, 0x9e, 0x9c, 0x0b, - 0x13, 0x1b, 0x2a, 0x4c, 0x28, 0x07, 0x1a, 0x38, 0xec, 0x61, 0xf6, 0x68, 0x01, 0xaa, - 0x59, 0x56, 0xfc, 0xb2, 0xa4, 0x6b, 0x95, 0x87, 0x66, 0x5b, 0x75, 0x71, 0xaa, 0x03, - 0x48, 0x1f, 0xd8, 0xd9, 0xd5, 0x69, 0x8f, 0x83, 0x6f, 0xc8, 0x63, 0x5e, 0x69, 0xe3, - 0xbd, 0xe4, 0x2f, 0x4a, 0xc0, 0x71, 0x32, 0x8b, 0x54, 0x09, 0xf6, 0xe4, 0x2d, 0x79, - 0x0a, 0xed, 0xd7, 0x3b, 0xc1, 0xa2, 0x35, 0x47, 0x23, 0xb3, 0xb8, 0x19, 0xd0, 0x63, - 0x7a, 0x6f, 0xa4, 0x66, 0x39, 0x46, 0xa3, 0x0a, 0xc5, 0xaf, 0xdd, 0x30, 0xce, 0x83, - 0x0f, 0x67, 0x91, 0xb4, 0x57, 0x52, 0x70, 0xa1, 0x72, 0x0f, 0x91, 0x86, 0x6e, 0x2b, - 0x86, 0xf4, 0x78, 0x88, 0x94, 0xc8, 0xda, 0x62, 0xd8, 0xb9, 0x1f, 0xaf, 0x52, 0x0e, - 0x3b, 0xed, 0xbc, 0x12, 0x06, 0xa5, 0xa5, 0xe6, 0xef, 0xd3, 0xdf, 0xde, 0x08, 0x43, - 0xc3, 0xb0, 0x67, 0x57, 0x64, 0x3f, 0xc0, 0x06, 0x00, 0x88, 0x38, 0xca, 0x47, 0x30, - 0x87, 0xf8, 0x97, 0x79, 0x18, 0xcc, 0x1b, 0x81, 0xc9, 0xe6, 0x8e, 0x3b, 0x88, 0x8f, - 0xe6, 0xf7, 0xc6, 0x30, 0xf1, 0xbc, 0x7a, 0xe1, 0x88, 0xf5, 0x12, 0x84, 0x20, 0x41, - 0xca, 0xda, 0x1e, 0x05, 0xf8, 0x66, 0xd2, 0x56, 0x2d, 0xbe, 0x09, 0xc4, 0xb4, 0x30, - 0x68, 0xf7, 0x54, 0xda, 0xd3, 0x4d, 0xf0, 0xfc, 0xfc, 0x18, 0x1f, 0x31, 0x80, 0x1a, - 0x79, 0x92, 0xd2, 0xf1, 0x6b, 0xe0, 0x21, 0x1b, 0x4a, 0x22, 0xf6, 0x2a, 0xab, 0x64, - 0x70, 0x1b, 0xf4, 0xa4, 0xe6, 0xd6, 0x66, 0xfc, 0x30, 0x4a, 0x5c, 0x79, 0xc6, 0x09, - 0xac, 0xc4, 0x3b, 0x00, 0xb4, 0x86, 0x48, 0x93, 0xd3, 0x7d, 0x50, 0x07, 0xf0, 0xc3, - 0x29, 0xa4, 0x75, 0x50, 0x52, 0x57, 0x75, 0x70, 0xdd, 0x38, 0xfa, 0xc0, 0x43, 0xcd, - 0x91, 0xc1, 0x2e, 0xe3, 0x4e, 0x9c, 0xfa, 0xe3, 0x92, 0xa7, 0x8b, 0xda, 0xbd, 0x4e, - 0xe3, 0x1d, 0xc0, 0xde, 0xb0, 0x2f, 0xe7, 0xb1, 0xd8, 0xb0, 0x17, 0x8a, 0xc9, 0x51, - 0x31, 0x05, 0xfc, 0xc7, 0xe3, 0x0b, 0xa8, 0xe0, 0x16, 0xaa, 0x36, 0xa6, 0xb5, 0xdf, - 0x5e, 0x5a, 0x19, 0x09, 0xf6, 0x3a, 0xba, 0x09, 0x5d, 0x98, 0x77, 0xa8, 0xf2, 0xdc, - 0x53, 0xf4, 0x6f, 0x6c, 0x9b, 0x07, 0xad, 0xdf, 0x14, 0x6f, 0x4f, 0xfa, 0x50, 0x1f, - 0x9d, 0xd3, 0xcf, 0xf9, 0x24, 0xe3, 0x01, 0x0f, 0xaf, 0x50, 0x4e, 0x2b, 0x8a, 0xca, - 0x73, 0x57, 0xac, 0xbf, 0xfe, 0xc7, 0x3a, 0xc3, 0x4c, 0x1a, 0x73, 0x16, 0x0f, 0x2c, - 0xea, 0x1e, 0x05, 0x10, 0xf8, 0x4d, 0x2f, 0xe2, 0xf7, 0x3b, 0x6e, 0x92, 0x19, 0x07, - 0xa1, 0xb7, 0xb3, 0x75, 0x12, 0x13, 0x24, 0x1b, 0x2c, 0xfa, 0xa5, 0x5a, 0x5e, 0xa4, - 0xdd, 0x51, 0x7e, 0x7b, 0x49, 0xd2, 0xde, 0x8c, 0x09, 0x08, 0x43, 0x73, 0x0d, 0x24, - 0x08, 0xa2, 0xa3, 0x04, 0xaa, 0x1e, 0x2e, 0x13, 0x70, 0xa6, 0xbf, 0x6c, 0x2b, 0xc7, - 0x3f, 0xf0, 0x0d, 0x89, 0x3b, 0xc1, 0x28, 0x5e, 0xfc, 0xa8, 0x25, 0x99, 0xd1, 0x81, - 0xf1, 0x23, 0x51, 0xf9, 0x39, 0xa9, 0x4e, 0xa8, 0xb9, 0x75, 0xc0, 0x65, 0xa9, 0x1f, - 0xf2, 0x57, 0xca, 0xc7, 0xa9, 0x23, 0x85, 0xfc, 0x8f, 0xa9, 0x21, 0xb1, 0x06, 0xba, - 0x86, 0x60, 0xc6, 0x0a, 0xc8, 0xba, 0x5e, 0xce, 0x45, 0x60, 0x6f, 0x04, 0xf3, 0x6a, - 0x3a, 0x90, 0xbb, 0x38, 0x38, 0xc4, 0x2a, 0xbf, 0x62, 0xdd, 0x2d, 0x84, 0xba, 0xbe, - 0xf3, 0xe1, 0x88, 0xe9, 0x17, 0x1a, 0xff, 0x9b, 0xc1, 0x16, 0x66, 0x90, 0x09, 0xd8, - 0x87, 0x13, 0x0a, 0xc9, 0xf7, 0x39, 0x6a, 0x62, 0x7a, 0x84, 0x74, 0xc1, 0x81, 0x1b, - 0x69, 0x6f, 0x99, 0x55, 0x2b, 0x14, 0xc4, 0x84, 0xdf, 0xe4, 0x2c, 0x24, 0xd5, 0x7c, - 0x3a, 0x9c, 0x3f, 0xea, 0x13, 0x76, 0xcd, 0xcb, 0x63, 0x42, 0x1c, 0x31, 0x4a, 0x62, - 0x2a, 0x9a, 0xef, 0x0b, 0xc0, 0x57, 0xcb, 0x11, 0xbc, 0x5e, 0x30, 0x66, 0xe3, 0x3a, - 0x3b, 0x9b, 0x31, 0xdf, 0x25, 0x75, 0xcd, 0x51, 0x85, 0xa4, 0xf3, 0xfc, 0x4e, 0x4c, - 0x3d, 0x40, 0x2e, 0xd4, 0x20, 0x46, 0xf8, 0x1f, 0x97, 0x48, 0x16, 0xd2, 0x79, 0xb1, - 0x51, 0x3a, 0xb8, 0x1d, 0x3f, 0x0a, 0x3c, 0x7f, 0x7f, 0xcf, 0x2f, 0xbb, 0x4e, 0x26, - 0x32, 0x19, 0x93, 0xa5, 0x13, 0xad, 0x3d, 0x7f, 0x4a, 0xfe, 0x6c, 0x1b, 0xbd, 0xc6, - 0x57, 0x58, 0x50, 0x80, 0xbb, 0x5a, 0x0f, 0x25, 0x97, 0x3d, 0x63, 0xeb, 0x20, 0xad, - 0xa0, 0x16, 0x6b, 0xbd, 0x8a, 0x39, 0xff, 0x93, 0x24, 0x6f, 0x27, 0x89, 0x73, 0x2a, - 0xd0, 0x55, 0x87, 0xf8, 0xdb, 0x7b, 0xc8, 0x7c, 0x24, 0x2c, 0xfd, 0x36, 0xce, 0x68, - 0x5a, 0x4b, 0x65, 0x69, 0x86, 0xc3, 0x9f, 0xd7, 0xfc, 0xb2, 0x3c, 0x91, 0x91, 0x3e, - 0x46, 0x11, 0x19, 0x1e, 0xdc, 0xc8, 0x8b, 0x78, 0xf1, 0x45, 0xea, 0x29, 0xd2, 0x71, - 0xb9, 0x40, 0xc6, 0x99, 0x41, 0xe4, 0xc3, 0xfd, 0x2d, 0x71, 0xf3, 0xb1, 0x90, 0x69, - 0x0e, 0xe1, 0x6f, 0x5d, 0x14, 0xac, 0x22, 0x24, 0xe6, 0xfc, 0x89, 0x59, 0x76, 0x54, - 0x52, 0x7d, 0xab, 0xe7, 0x2e, 0x75, 0xd2, 0xd2, 0xa1, 0x3a, 0x9f, 0xba, 0xa6, 0x37, - 0x8e, 0x8a, 0x26, 0x43, 0x21, 0x08, 0x7a, 0x19, 0x00, 0xef, 0xe3, 0xca, 0xd1, 0x4a, - 0x57, 0x96, 0x86, 0xaa, 0x36, 0x36, 0xbd, 0x37, 0x5b, 0xd3, 0x13, 0x6b, 0xee, 0x0b, - 0xda, 0xab, 0xcf, 0xac, 0x88, 0x1b, 0xc7, 0x01, 0x81, 0x27, 0x21, 0xe6, 0xfb, 0x75, - 0xaa, 0x07, 0x2d, 0x2d, 0x18, 0x7e, 0x62, 0x25, 0x8d, 0x65, 0xa1, 0x92, 0x15, 0x7c, - 0xdf, 0x2e, 0xc3, 0x21, 0x40, 0x7f, 0x68, 0x2f, 0x5e, 0xec, 0x6a, 0x32, 0x97, 0xab, - 0x20, 0xb7, 0x06, 0x1c, 0x62, 0x24, 0x57, 0x16, 0xa4, 0x4f, 0x71, 0xfb, 0xfc, 0x34, - 0xc7, 0x9b, 0x44, 0xe0, 0x9e, 0x42, 0x12, 0xac, 0x26, 0x53, 0xf6, 0xc4, 0x03, 0x64, - 0x3e, 0x1c, 0x5b, 0x9a, 0xd1, 0x34, 0xd8, 0x9c, 0x68, 0x0b, 0x70, 0x72, 0x83, 0xaf, - 0x54, 0x32, 0x6f, 0xc4, 0xf8, 0x4d, 0x6a, 0x58, 0x29, 0xa0, 0xad, 0x48, 0x30, 0x80, - 0x6c, 0x05, 0x75, 0x84, 0x92, 0xcd, 0x6a, 0xc4, 0x6b, 0xa0, 0x1a, 0x2b, 0x37, 0x22, - 0xb5, 0xe4, 0xcd, 0xaf, 0xbb, 0x3f, 0x36, 0x78, 0x5f, 0x42, 0x4a, 0xf0, 0x44, 0xda, - 0xc5, 0xdb, 0x5f, 0x7d, 0xf8, 0x39, 0xeb, 0x63, 0xc0, 0xc1, 0x7d, 0x8b, 0x0c, 0x79, - 0xdb, 0x86, 0x30, 0x94, 0x20, 0x15, 0xbe, 0x13, 0xf7, 0x9a, 0xf6, 0xf4, 0x3e, 0x5a, - 0xb0, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x81, 0x14, 0x79, 0x8f, 0x44, 0x22, 0x58, 0xee, 0xdc, 0x43, - 0x6f, 0xcc, 0x38, 0x6b, 0x36, 0xb5, 0x7e, 0x19, 0x17, 0xd7, 0x20, 0x17, 0x73, 0x66, - 0xf4, 0x24, 0xb0, 0xa5, 0x4b, 0x0b, 0x60, 0xf4, 0xfb, 0x13, 0x58, 0xc2, 0x0a, 0xa4, - 0x1d, 0xc5, 0x02, 0xe1, 0xdd, 0x8a, 0x16, 0x33, 0xf3, 0xd8, 0xe3, 0x27, 0x6b, 0x59, - 0xe7, 0xd2, 0xc4, 0xe6, 0x24, 0xa6, 0xf5, 0x36, 0x95, 0xbc, 0xaf, 0x24, 0x7e, 0x36, - 0x48, 0x3f, 0x13, 0xb2, 0x04, 0x42, 0x22, 0x37, 0xfc, 0x6a, 0xb3, 0xeb, 0xa0, 0x2f, - 0xc4, 0x14, 0x2b, 0x42, 0x97, 0xeb, 0xb5, 0x68, 0x3d, 0xb8, 0xd2, 0x43, 0x19, 0x70, - 0x6a, 0xd2, 0x6a, 0xaf, 0xd8, 0x1c, 0x53, 0xb7, 0x40, 0xf3, 0x45, 0x43, 0xa6, 0xb3, - 0xe9, 0xf5, 0xbb, 0x7d, 0x5c, 0x49, 0xe8, 0xc3, 0x7f, 0x61, 0x49, 0x21, 0x25, 0x4f, - 0x32, 0x12, 0x39, 0x4c, 0x79, 0x7d, 0x1c, 0xee, 0x78, 0x99, 0xb7, 0xb4, 0xb6, 0x5b, - 0x59, 0xb7, 0x34, 0x2f, 0x92, 0x53, 0x1c, 0x1d, 0x59, 0xe1, 0x79, 0x70, 0xb7, 0x31, - 0x74, 0x14, 0x43, 0x8c, 0xd8, 0x0b, 0xd0, 0xf9, 0xa6, 0x7c, 0x9b, 0x9e, 0x55, 0x2f, - 0x01, 0x3c, 0x11, 0x5a, 0x95, 0x4f, 0x35, 0xe0, 0x61, 0x6c, 0x68, 0xd4, 0x31, 0x63, - 0xd3, 0x34, 0xda, 0xc3, 0x82, 0x70, 0x33, 0xe5, 0xad, 0x84, 0x88, 0xbf, 0xd9, 0xc4, - 0xbb, 0xbe, 0x8f, 0x59, 0x35, 0xc6, 0xc5, 0xea, 0x04, 0xc3, 0xad, 0x49, 0xc7, 0x47, - 0xa9, 0xe7, 0x23, 0x1b, 0xcd, 0x7d, 0x16, 0x21, 0x5e, 0x6e, 0x80, 0x73, 0x7d, 0x6b, - 0x54, 0xfe, 0xc8, 0xb8, 0x84, 0x02, 0xf0, 0x47, 0x52, 0x45, 0xe1, 0x74, 0xa7, 0x45, - 0xb8, 0x31, 0xf8, 0xfe, 0x03, 0xa7, 0x6f, 0xb9, 0xce, 0xca, 0x4d, 0x22, 0xb7, 0x83, - 0xc3, 0x28, 0xc6, 0x91, 0x5c, 0x43, 0x40, 0x50, 0x64, 0xae, 0x56, 0xbc, 0x89, 0xe6, - 0x4d, 0x15, 0x78, 0xe4, 0xd3, 0xa3, 0x4b, 0xb9, 0x55, 0x91, 0xea, 0xf1, 0xd3, 0xda, - 0x02, 0xa4, 0x54, 0x9f, 0xa8, 0x0d, 0xb0, 0xff, 0x7c, 0xb0, 0x39, 0x93, 0x02, 0x8a, - 0xe1, 0x5a, 0x30, 0xe8, 0x79, 0x49, 0xaa, 0x08, 0x0e, 0x94, 0xab, 0xde, 0x68, 0x89, - 0x8c, 0x33, 0x92, 0xa2, 0x17, 0xd6, 0x49, 0x61, 0x6b, 0xbe, 0x73, 0x9b, 0x13, 0xd1, - 0x4d, 0xf0, 0x3f, 0x02, 0x76, 0x71, 0x48, 0x9b, 0xe0, 0xb4, 0xbe, 0xba, 0xaf, 0xa7, - 0xd1, 0xe6, 0x39, 0xd5, 0xb3, 0xe9, 0x94, 0xff, 0xb6, 0xb7, 0xa2, 0x09, 0xf6, 0xad, - 0xfe, 0x8d, 0x1e, 0x5c, 0xcf, 0x01, 0x0c, 0x19, 0x0a, 0x8a, 0xeb, 0x18, 0xaa, 0x9d, - 0x68, 0x7e, 0x24, 0xad, 0xc0, 0xb1, 0x13, 0x5c, 0x70, 0xc9, 0x70, 0xe0, 0x90, 0x3a, - 0xf6, 0xe1, 0x70, 0x81, 0xd5, 0x81, 0x8e, 0x88, 0xb1, 0x4e, 0x4f, 0x60, 0x1b, 0x8c, - 0x06, 0x3e, 0x3f, 0x43, 0x87, 0xff, 0xa2, 0x32, 0x2a, 0x51, 0x81, 0x90, 0x9f, 0x09, - 0x80, 0xd6, 0x89, 0xde, 0x7f, 0x8e, 0x6a, 0x5c, 0x62, 0xa7, 0x77, 0xd1, 0x75, 0x00, - 0x2a, 0x13, 0x7d, 0x02, 0x5b, 0x88, 0x88, 0x92, 0x91, 0x98, 0x11, 0x7a, 0xa5, 0xd6, - 0x19, 0x93, 0xe1, 0xdc, 0xf7, 0x58, 0x76, 0xdc, 0xa6, 0x09, 0xf9, 0xd2, 0x84, 0x71, - 0xf9, 0x97, 0xfa, 0x11, 0xf9, 0x9d, 0x42, 0x3f, 0x02, 0xf1, 0x73, 0x4b, 0xe8, 0xa5, - 0xff, 0x99, 0x7d, 0x45, 0x1e, 0xb3, 0xcf, 0x4b, 0x3d, 0xfd, 0xd9, 0xd4, 0x54, 0x5c, - 0x35, 0xb2, 0xb5, 0xa7, 0xdc, 0x17, 0xa8, 0x36, 0xb1, 0x2b, 0x43, 0xbe, 0xfc, 0x03, - 0xe0, 0xa1, 0xbd, 0x36, 0x97, 0x72, 0x33, 0x80, 0x78, 0xb4, 0xff, 0x7d, 0x8e, 0x2d, - 0x97, 0x9a, 0x34, 0x41, 0xe1, 0xc8, 0xf5, 0xaf, 0xe4, 0x7b, 0x1e, 0x7d, 0xa5, 0x6c, - 0xf0, 0x06, 0x02, 0xd0, 0x03, 0x11, 0x0c, 0x05, 0xcf, 0x48, 0xfd, 0xa3, 0xe6, 0xcc, - 0xe3, 0x2a, 0x04, 0x40, 0x00, 0xf4, 0x5c, 0x6d, 0x1e, 0x69, 0x6d, 0x24, 0x5c, 0xbd, - 0x31, 0x2b, 0xdc, 0x3a, 0x3a, 0x21, 0xc9, 0x92, 0xd0, 0x03, 0xc8, 0xcc, 0x8f, 0xa6, - 0x30, 0x6d, 0x7e, 0x13, 0x0a, 0x2b, 0xa4, 0x20, 0x18, 0xfe, 0x59, 0x69, 0x49, 0xfd, - 0x82, 0x26, 0x7b, 0xcc, 0x59, 0xdd, 0x46, 0x26, 0xef, 0xc3, 0xea, 0x74, 0x38, 0xd0, - 0x5c, 0x91, 0xb0, 0xf8, 0xe0, 0x92, 0x55, 0x0d, 0x2d, 0x39, 0xa0, 0x1e, 0xb4, 0x5e, - 0xe8, 0xf7, 0xd0, 0x9b, 0x03, 0x8d, 0x83, 0x83, 0xe1, 0x9b, 0xc3, 0x0e, 0x64, 0x03, - 0x82, 0x8c, 0xdb, 0x65, 0x2a, 0x55, 0x6b, 0x12, 0x04, 0x09, 0x31, 0x40, 0x2a, 0xa6, - 0xac, 0x34, 0xfc, 0x19, 0xfd, 0xc0, 0x6e, 0x2e, 0x77, 0x87, 0xf5, 0xb7, 0x7b, 0x04, - 0x5f, 0xd0, 0x98, 0xc0, 0x31, 0xbd, 0xbd, 0x46, 0x27, 0x76, 0x09, 0xd8, 0x42, 0xf4, - 0x84, 0x24, 0xed, 0xa3, 0x1e, 0x3c, 0xf2, 0xcd, 0xd6, 0x43, 0x85, 0xba, 0xd3, 0x11, - 0x88, 0x58, 0xd1, 0x42, 0xd9, 0x06, 0xea, 0xdb, 0x75, 0x90, 0xc9, 0x41, 0x36, 0xda, - 0x6a, 0x06, 0x35, 0x14, 0xd6, 0xa2, 0x5f, 0x7b, 0x37, 0xd7, 0x66, 0x4f, 0x9b, 0x97, - 0x09, 0x43, 0x3e, 0x6e, 0x70, 0x21, 0x18, 0xa4, 0xab, 0x9e, 0x7a, 0x7a, 0x3e, 0x62, - 0x59, 0x12, 0x99, 0x37, 0xd2, 0x9d, 0x0d, 0xb2, 0x60, 0x70, 0x52, 0x3e, 0x8b, 0x06, - 0x43, 0x13, 0x0a, 0xbe, 0xfe, 0x94, 0x3b, 0x40, 0x12, 0x98, 0xae, 0x01, 0xa3, 0xab, - 0x00, 0xab, 0xbc, 0x60, 0xd7, 0xdb, 0x93, 0x3c, 0x7f, 0x07, 0xa8, 0xbf, 0x0f, 0x7c, - 0xe1, 0x66, 0x0b, 0xcc, 0xb4, 0x5e, 0x04, 0x2b, 0x45, 0x1b, 0x93, 0x50, 0x02, 0xce, - 0xce, 0x27, 0xf3, 0x6a, 0xba, 0x56, 0x47, 0xac, 0x28, 0xd8, 0x18, 0x6c, 0xdd, 0x1f, - 0xb9, 0x5d, 0xc1, 0x35, 0xd4, 0x89, 0x92, 0xf6, 0x8d, 0xa1, 0x2a, 0xd6, 0x1a, 0xc7, - 0x56, 0x68, 0x0d, 0xd7, 0xf8, 0xd0, 0x77, 0x4a, 0xbd, 0x6c, 0xfd, 0xa2, 0xf0, 0x32, - 0xaf, 0x3b, 0xe1, 0x39, 0xa6, 0x33, 0xd6, 0x73, 0x3c, 0x75, 0xd1, 0xab, 0xa8, 0x90, - 0x18, 0xc8, 0x57, 0x2b, 0x99, 0xcd, 0x30, 0xc5, 0x37, 0x06, 0x79, 0x41, 0xdf, 0x1c, - 0x4b, 0xc1, 0xfd, 0x57, 0x0f, 0x7b, 0x4d, 0xdc, 0x97, 0x51, 0x86, 0x23, 0xe3, 0xae, - 0x4a, 0x87, 0xbd, 0xb9, 0x66, 0xc9, 0x4d, 0x86, 0x1e, 0x80, 0xde, 0x88, 0xc2, 0x92, - 0xae, 0xe9, 0x38, 0x71, 0x94, 0xe2, 0x56, 0xc6, 0x70, 0x07, 0x52, 0x30, 0x1c, 0x73, - 0xfc, 0x95, 0x65, 0xa4, 0x04, 0x80, 0xd8, 0x12, 0x6e, 0x9d, 0x08, 0x58, 0x79, 0xe2, - 0x4b, 0x16, 0xe9, 0xc4, 0x85, 0xd8, 0xf0, 0xd6, 0x18, 0xca, 0x0d, 0xd1, 0x21, 0xb5, - 0x1a, 0x7c, 0xab, 0x23, 0x0c, 0x5b, 0x45, 0x67, 0x2b, 0xdb, 0x8e, 0xa3, 0xa0, 0x40, - 0xf7, 0xaa, 0xa0, 0x98, 0xba, 0x26, 0x02, 0x5d, 0x2e, 0xab, 0x79, 0x48, 0x69, 0x3d, - 0xd5, 0xf6, 0xd3, 0x09, 0x65, 0x01, 0xe9, 0xe0, 0x71, 0x25, 0xd7, 0xeb, 0x29, 0x3b, - 0x3a, 0xba, 0xd5, 0x7f, 0xd5, 0xf0, 0x11, 0x64, 0x70, 0x2d, 0xae, 0x64, 0xbd, 0xba, - 0x8c, 0x92, 0x4f, 0xb0, 0x79, 0x96, 0x79, 0xd7, 0x7f, 0x98, 0xd3, 0x03, 0x91, 0x9f, - 0xb4, 0xa7, 0xff, 0x26, 0xa9, 0x6f, 0x13, 0x7a, 0x5e, 0x5c, 0xb9, 0x5b, 0xc4, 0xc6, - 0xff, 0x99, 0x93, 0x52, 0x6b, 0xda, 0x15, 0x03, 0x16, 0x8a, 0xb4, 0x8c, 0xbd, 0x45, - 0x15, 0x39, 0x27, 0xd3, 0x04, 0x30, 0x42, 0x3d, 0xbd, 0xf0, 0x66, 0x05, 0xf5, 0xb5, - 0x4b, 0x80, 0x8f, 0xeb, 0x22, 0xb2, 0x08, 0xb0, 0x64, 0x58, 0x18, 0x47, 0xb2, 0xf6, - 0x4c, 0xa6, 0x48, 0x37, 0x00, 0x72, 0x16, 0xde, 0x6e, 0xca, 0xff, 0xeb, 0x4b, 0x69, - 0xe6, 0x33, 0x47, 0xf8, 0x4a, 0xbc, 0xad, 0x8f, 0x2e, 0x75, 0x7d, 0x58, 0x61, 0xce, - 0x77, 0xee, 0x46, 0x51, 0x3d, 0xa7, 0x41, 0x68, 0x37, 0xdc, 0xb2, 0x3d, 0x33, 0xea, - 0x72, 0xaf, 0x23, 0xd0, 0xad, 0x8c, 0x93, 0x07, 0xd0, 0xb5, 0x85, 0x8d, 0xa9, 0x5b, - 0x77, 0xff, 0xf9, 0x02, 0x7b, 0x88, 0x59, 0xe1, 0x1d, 0xcb, 0xd5, 0x98, 0x35, 0x0e, - 0xee, 0x50, 0x93, 0x94, 0x81, 0x70, 0x8e, 0xa7, 0x08, 0xeb, 0x9f, 0x66, 0x43, 0x88, - 0xb9, 0xc6, 0x4d, 0x6a, 0xf0, 0xf9, 0x66, 0x90, 0x34, 0x24, 0x00, 0x34, 0x8e, 0x92, - 0x9e, 0x07, 0x46, 0x02, 0x53, 0xf3, 0x83, 0x90, 0xf8, 0x7b, 0xd6, 0xc0, 0x53, 0x08, - 0xc3, 0xbd, 0xe2, 0x52, 0x28, 0xe0, 0xfa, 0x08, 0x80, 0xb0, 0x8e, 0xf3, 0x4a, 0x5a, - 0x9c, 0xc0, 0xea, 0x0a, 0x67, 0xca, 0x65, 0xb6, 0xff, 0xd0, 0x05, 0x57, 0x29, 0x09, - 0xf1, 0xc4, 0x2d, 0xd7, 0x45, 0xee, 0xee, 0x9d, 0xd6, 0xb4, 0x43, 0x9c, 0x9f, 0x3f, - 0x98, 0xa1, 0x18, 0xfe, 0x16, 0x69, 0x8e, 0x9c, 0xef, 0xf5, 0x58, 0xf1, 0x60, 0x66, - 0x97, 0x5f, 0xe3, 0x95, 0x83, 0xe9, 0xb5, 0x85, 0x3b, 0x13, 0x11, 0x39, 0x15, 0x80, - 0x01, 0x9f, 0xe5, 0x5d, 0x59, 0xd1, 0xc8, 0x28, 0xd3, 0xfe, 0xb6, 0xa3, 0xb9, 0xce, - 0x92, 0xd0, 0x89, 0xae, 0x4b, 0x40, 0x8e, 0x23, 0xd6, 0xa4, 0x37, 0xd4, 0x98, 0x9b, - 0x51, 0x9b, 0x7a, 0x9e, 0xb0, 0x8a, 0xe6, 0xd4, 0x48, 0xa7, 0xa1, 0x6e, 0x8a, 0xed, - 0x26, 0xa2, 0xec, 0xd0, 0xca, 0xd8, 0x08, 0x44, 0xfd, 0x06, 0x50, 0xd8, 0xc4, 0xe4, - 0xd2, 0xaf, 0x90, 0x65, 0x67, 0x48, 0xd8, 0x09, 0x9a, 0x0c, 0x75, 0x6f, 0xc1, 0x6c, - 0xca, 0x06, 0xa3, 0x34, 0x43, 0x07, 0x02, 0xae, 0x19, 0x61, 0x66, 0x5b, 0x48, 0x45, - 0xac, 0xd1, 0xa8, 0xe3, 0x41, 0x01, 0xe6, 0x8b, 0xb6, 0x44, 0xac, 0x03, 0x4d, 0xc6, - 0x3e, 0x6e, 0x34, 0x4c, 0x3d, 0x63, 0x76, 0x2a, 0x7a, 0x5b, 0xf5, 0x9f, 0x13, 0x09, - 0x54, 0x10, 0x98, 0x1d, 0x6b, 0x6b, 0x16, 0xbc, 0xd4, 0xc9, 0xfa, 0x68, 0xaf, 0x6e, - 0x53, 0x65, 0xe9, 0x4e, 0xcb, 0xe7, 0xab, 0x8b, 0x80, 0x43, 0xdf, 0xba, 0xcb, 0x23, - 0xc8, 0x4d, 0x71, 0xa8, 0xfe, 0x5d, 0x9a, 0xc5, 0x50, 0x2c, 0xe9, 0xf7, 0x3f, 0x40, - 0x8e, 0x14, 0x37, 0x6d, 0xb8, 0x6e, 0xf5, 0x7c, 0xc3, 0x7d, 0x09, 0x89, 0x6f, 0xa9, - 0x06, 0x97, 0x2e, 0x55, 0x71, 0x80, 0xa4, 0xab, 0x5a, 0xd0, 0x9d, 0x88, 0x46, 0xdd, - 0x6d, 0xa7, 0x48, 0x76, 0x54, 0x36, 0xe0, 0x16, 0x02, 0x40, 0xf8, 0xd4, 0x1c, 0x0a, - 0xc7, 0x83, 0xf9, 0x39, 0xf2, 0xd0, 0xed, 0x26, 0x2c, 0xe8, 0x59, 0xc1, 0x31, 0xeb, - 0xc9, 0x3f, 0xf2, 0xe6, 0xe4, 0x07, 0xd4, 0xe2, 0x43, 0xe1, 0xe9, 0x31, 0xd5, 0x3a, - 0x45, 0x43, 0xb6, 0xe2, 0x6d, 0x82, 0x59, 0x6f, 0xc5, 0x3b, 0x52, 0x31, 0x2c, 0x77, - 0x6d, 0x12, 0xeb, 0x2b, 0x65, 0x9b, 0x4f, 0xb0, 0x98, 0xdf, 0x87, 0xd6, 0x83, 0xcf, - 0x9e, 0x54, 0x12, 0xee, 0x56, 0xc3, 0xfe, 0x98, 0x41, 0xd7, 0x3f, 0xd0, 0x70, 0xdf, - 0xa5, 0x1f, 0x5b, 0xaf, 0xed, 0xf2, 0x06, 0xf1, 0x3c, 0x52, 0x4e, 0x5c, 0x50, 0xca, - 0xc9, 0x90, 0x6e, 0xfa, 0x39, 0x32, 0x90, 0x04, 0x2e, 0x3b, 0xc5, 0x9f, 0x96, 0x0b, - 0x7d, 0x24, 0x0a, 0xe4, 0x43, 0xfc, 0x49, 0x26, 0x9c, 0xe0, 0x00, 0x61, 0xe6, 0x5c, - 0x6d, 0x74, 0x81, 0x2a, 0x30, 0xdd, 0x5f, 0x5f, 0xe7, 0x4e, 0xff, 0x61, 0xe0, 0xcb, - 0xab, 0x3c, 0xec, 0x75, 0xd0, 0xae, 0xf9, 0x50, 0x83, 0x18, 0x94, 0x52, 0xdd, 0x3d, - 0x9e, 0xdf, 0x44, 0x87, 0xbc, 0x73, 0x4c, 0x8b, 0x24, 0xf2, 0x12, 0x96, 0xe4, 0xe9, - 0xef, 0x11, 0x7d, 0x7f, 0xb9, 0x77, 0xe3, 0xb0, 0xe6, 0x40, 0x6e, 0x63, 0x08, 0x59, - 0x06, 0x33, 0x1a, 0x93, 0x03, 0x3d, 0x1c, 0xb8, 0x36, 0x0f, 0xe6, 0xfe, 0xa6, 0x1a, - 0x68, 0x26, 0xdf, 0x36, 0x25, 0x57, 0x89, 0xf9, 0x2e, 0x40, 0xba, 0xfc, 0xb2, 0xeb, - 0xcb, 0x9e, 0x55, 0x6f, 0x6c, 0x0c, 0xca, 0xdc, 0x6a, 0xf0, 0x8e, 0x31, 0xec, 0x4a, - 0xd5, 0x28, 0x80, 0x34, 0xe1, 0x6d, 0x15, 0x5c, 0xfd, 0xca, 0xda, 0x7b, 0xab, 0x59, - 0x9c, 0x2f, 0xa4, 0xad, 0x2e, 0x62, 0x93, 0xf9, 0xfe, 0x09, 0x71, 0x69, 0x14, 0x82, - 0x76, 0xb6, 0xa9, 0xea, 0xa7, 0x2f, 0x14, 0x8b, 0x0c, 0x95, 0x65, 0xc3, 0xc2, 0xdd, - 0x63, 0x12, 0x5e, 0x0f, 0xa5, 0x30, 0x86, 0x1a, 0x71, 0x0d, 0xf8, 0xe4, 0x81, 0xf2, - 0x71, 0x29, 0x20, 0xf8, 0x78, 0x7e, 0x0a, 0xed, 0xfe, 0x61, 0x8a, 0xff, 0x50, 0xa3, - 0xb5, 0x62, 0x13, 0x88, 0x4d, 0x62, 0x62, 0xc1, 0x1d, 0xeb, 0xf2, 0xba, 0x7e, 0x8a, - 0xd6, 0x69, 0x2c, 0xb1, 0x70, 0x78, 0x33, 0x14, 0x18, 0xda, 0x4b, 0xe0, 0x64, 0xff, - 0x52, 0x70, 0x07, 0x39, 0x34, 0xab, 0xcd, 0x2a, 0xb0, 0x46, 0x9e, 0xca, 0xf7, 0x27, - 0x5b, 0x4b, 0xd7, 0x2b, 0xc6, 0xed, 0x34, 0x47, 0x8e, 0xa4, 0x08, 0x9b, 0x73, 0x6a, - 0x16, 0xdd, 0x90, 0x6d, 0x49, 0xf2, 0x5c, 0x33, 0x82, 0x7c, 0x57, 0x1c, 0xe0, 0xb5, - 0xd7, 0x21, 0x77, 0xaa, 0x35, 0x08, 0x80, 0x4b, 0xc0, 0xf8, 0xfa, 0xa9, 0x47, 0x12, - 0x22, 0x31, 0x40, 0x2d, 0x2f, 0x5c, 0xc9, 0xa0, 0xeb, 0x0e, 0x09, 0xd4, 0x27, 0xb4, - 0x27, 0x28, 0x8d, 0x93, 0x7d, 0x9d, 0x72, 0xb7, 0x74, 0x56, 0xf8, 0x86, 0x59, 0x4c, - 0xd8, 0xc6, 0xa4, 0x62, 0xf7, 0x7f, 0xd8, 0x30, 0x76, 0x46, 0x9c, 0xc0, 0xec, 0xba, - 0x3c, 0xc4, 0x0c, 0xad, 0x69, 0xe5, 0xb5, 0x41, 0x12, 0xea, 0xb3, 0x33, 0x96, 0xae, - 0xcf, 0xbc, 0x21, 0x1f, 0x1f, 0x79, 0xcf, 0x33, 0x10, 0x8e, 0x93, 0xd9, 0x53, 0x78, - 0xba, 0xe6, 0x95, 0x82, 0x74, 0xb3, 0x10, 0x88, 0xfb, 0xd8, 0xb3, 0xa3, 0xa0, 0xd1, - 0x54, 0xa7, 0x89, 0x73, 0x5b, 0x03, 0x49, 0xc4, 0xd5, 0x1c, 0x88, 0x9d, 0x08, 0x95, - 0x2d, 0xdd, 0x54, 0x88, 0xbe, 0x95, 0x56, 0x05, 0x94, 0xe6, - ], - script_code: vec![0x52, 0x63, 0x53, 0x51, 0x65], - transparent_input: Some(0), - hash_type: 2, - amount: 483959951916902, - consensus_branch_id: 1537743641, - sighash: [ - 0x29, 0x6f, 0xd7, 0x63, 0xf2, 0x54, 0x5e, 0x64, 0xfb, 0x5d, 0x7d, 0x49, 0xc0, 0x00, - 0xd2, 0xb4, 0x18, 0xb9, 0x3b, 0xde, 0x22, 0x34, 0xf8, 0x74, 0x29, 0x11, 0xe8, 0xaf, - 0xef, 0xd0, 0x6d, 0x57, - ], - }, - ]; - - for tv in test_vectors { - let tx = Transaction::read(&tv.tx[..]).unwrap(); - let transparent_input = if let Some(n) = tv.transparent_input { - Some((n as usize, Script(tv.script_code), Amount(tv.amount))) - } else { - None - }; - - assert_eq!( - signature_hash(&tx, tv.consensus_branch_id, tv.hash_type, transparent_input,), - tv.sighash - ); - } -} - -#[test] -fn zip_0243() { - struct TestVector { - tx: Vec, - script_code: Vec, - transparent_input: Option, - hash_type: u32, - amount: i64, - consensus_branch_id: u32, - sighash: [u8; 32], - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0243.py - let test_vectors = vec![ - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x00, 0x02, 0xe7, 0x71, 0x98, 0x11, - 0x89, 0x3e, 0x00, 0x00, 0x09, 0x52, 0x00, 0xac, 0x65, 0x51, 0xac, 0x63, 0x65, 0x65, - 0xb2, 0x83, 0x5a, 0x08, 0x05, 0x75, 0x02, 0x00, 0x02, 0x51, 0x51, 0x48, 0x1c, 0xdd, - 0x86, 0xb3, 0xcc, 0x43, 0x18, 0x44, 0x21, 0x17, 0x62, 0x3c, 0xeb, 0x05, 0x00, 0x03, - 0x1b, 0x3d, 0x1a, 0x02, 0x7c, 0x2c, 0x40, 0x59, 0x09, 0x58, 0xb7, 0xeb, 0x13, 0xd7, - 0x42, 0xa9, 0x97, 0x73, 0x8c, 0x46, 0xa4, 0x58, 0x96, 0x5b, 0xaf, 0x27, 0x6b, 0xa9, - 0x2f, 0x27, 0x2c, 0x72, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, 0xa5, 0xe2, - 0x9d, 0x4e, 0x30, 0xa7, 0x35, 0x94, 0xbf, 0x50, 0x98, 0x42, 0x1c, 0x69, 0x37, 0x8a, - 0xf1, 0xe4, 0x0f, 0x64, 0xe1, 0x25, 0x94, 0x6f, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, - 0xbc, 0xb6, 0x4b, 0x69, 0x68, 0x91, 0x2a, 0x63, 0x81, 0xce, 0x3d, 0xc1, 0x66, 0xd5, - 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, 0xb5, 0xfd, 0x93, 0x13, 0x25, 0xc9, - 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x51, - 0xa7, 0xaf, 0x9d, 0xb6, 0x99, 0x0e, 0xd8, 0x3d, 0xd6, 0x4a, 0xf3, 0x59, 0x7c, 0x04, - 0x32, 0x3e, 0xa5, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, 0xb9, 0xda, 0x94, 0x8d, - 0x32, 0x0d, 0xad, 0xd6, 0x4f, 0x54, 0x31, 0xe6, 0x1d, 0xdf, 0x65, 0x8d, 0x24, 0xae, - 0x67, 0xc2, 0x2c, 0x8d, 0x13, 0x09, 0x13, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, - 0x42, 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x91, 0xe0, 0x0c, 0x7a, 0x1d, 0x48, 0xaf, - 0x04, 0x68, 0x27, 0x59, 0x1e, 0x97, 0x33, 0xa9, 0x7f, 0xa6, 0xb6, 0x79, 0xf3, 0xdc, - 0x60, 0x1d, 0x00, 0x82, 0x85, 0xed, 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0xfc, 0x1b, 0xe4, - 0xaa, 0xc0, 0x0f, 0xf2, 0x71, 0x1e, 0xbd, 0x93, 0x1d, 0xe5, 0x18, 0x85, 0x68, 0x78, - 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, - 0x3c, 0x94, 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, - 0x79, 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, 0x32, 0xb4, - 0xf4, 0x73, 0xf4, 0x68, 0xa0, 0x08, 0xe7, 0x23, 0x89, 0xfc, 0x03, 0x88, 0x0d, 0x78, - 0x0c, 0xb0, 0x7f, 0xcf, 0xaa, 0xbe, 0x3f, 0x1a, 0x84, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, - 0x15, 0x3d, 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x55, 0xed, 0x94, 0x94, 0xc6, - 0xac, 0x89, 0x3c, 0x49, 0x72, 0x38, 0x33, 0xec, 0x89, 0x26, 0xc1, 0x03, 0x95, 0x86, - 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, 0x73, 0x1e, 0x98, 0x5d, 0x99, 0x58, 0x9c, 0x8b, - 0xb8, 0x38, 0xe8, 0xaa, 0xf7, 0x45, 0x53, 0x3e, 0xd9, 0xe8, 0xae, 0x3a, 0x1c, 0xd0, - 0x74, 0xa5, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, 0xeb, 0xbc, 0x86, 0x2d, - 0xed, 0x42, 0x43, 0x5e, 0x92, 0x47, 0x69, 0x30, 0xd0, 0x69, 0x89, 0x6c, 0xff, 0x30, - 0xeb, 0x41, 0x4f, 0x72, 0x7b, 0x89, 0x5a, 0x4b, 0x7b, 0xe1, 0x76, 0x93, 0x67, 0xe1, - 0xfe, 0x8a, 0xd1, 0x8d, 0xe1, 0x1e, 0x58, 0xd8, 0x8a, 0x0a, 0xd5, 0x51, 0x1d, 0x35, - 0x25, 0x12, 0x2b, 0x7b, 0x0a, 0x6f, 0x25, 0xd2, 0x8b, 0x16, 0x45, 0x7e, 0x74, 0x59, - 0x39, 0xff, 0xed, 0xbd, 0x12, 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, 0x7d, 0x41, - 0x7a, 0xdb, 0x3d, 0x15, 0xcc, 0x54, 0xdc, 0xb1, 0xfc, 0xe4, 0x67, 0x50, 0x0c, 0x6b, - 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, 0x82, 0x85, 0x7d, 0xee, 0xcc, 0x40, - 0xa9, 0x8d, 0x5f, 0x29, 0x35, 0x39, 0x5e, 0xe4, 0x76, 0x2d, 0xd2, 0x1a, 0xfd, 0xbb, - 0x5d, 0x47, 0xfa, 0x9a, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, 0xb9, 0x27, - 0xb7, 0xfa, 0xe2, 0xdb, 0x58, 0x71, 0x05, 0x41, 0x5d, 0x46, 0x42, 0x78, 0x9d, 0x38, - 0xf5, 0x0b, 0x8d, 0xbc, 0xc1, 0x29, 0xca, 0xb3, 0xd1, 0x7d, 0x19, 0xf3, 0x35, 0x5b, - 0xcf, 0x73, 0xce, 0xcb, 0x8c, 0xb8, 0xa5, 0xda, 0x01, 0x30, 0x71, 0x52, 0xf1, 0x39, - 0x36, 0xa2, 0x70, 0x57, 0x26, 0x70, 0xdc, 0x82, 0xd3, 0x90, 0x26, 0xc6, 0xcb, 0x4c, - 0xd4, 0xb0, 0xf7, 0xf5, 0xaa, 0x2a, 0x4f, 0x5a, 0x53, 0x41, 0xec, 0x5d, 0xd7, 0x15, - 0x40, 0x6f, 0x2f, 0xdd, 0x2a, 0xfa, 0x73, 0x3f, 0x5f, 0x64, 0x1c, 0x8c, 0x21, 0x86, - 0x2a, 0x1b, 0xaf, 0xce, 0x26, 0x09, 0xd9, 0xee, 0xcf, 0xa1, 0x58, 0xcf, 0xb5, 0xcd, - 0x79, 0xf8, 0x80, 0x08, 0xe3, 0x15, 0xdc, 0x7d, 0x83, 0x88, 0xe7, 0x6c, 0x17, 0x82, - 0xfd, 0x27, 0x95, 0xd1, 0x8a, 0x76, 0x36, 0x24, 0xc2, 0x5f, 0xa9, 0x59, 0xcc, 0x97, - 0x48, 0x9c, 0xe7, 0x57, 0x45, 0x82, 0x4b, 0x77, 0x86, 0x8c, 0x53, 0x23, 0x9c, 0xfb, - 0xdf, 0x73, 0xca, 0xec, 0x65, 0x60, 0x40, 0x37, 0x31, 0x4f, 0xaa, 0xce, 0xb5, 0x62, - 0x18, 0xc6, 0xbd, 0x30, 0xf8, 0x37, 0x4a, 0xc1, 0x33, 0x86, 0x79, 0x3f, 0x21, 0xa9, - 0xfb, 0x80, 0xad, 0x03, 0xbc, 0x0c, 0xda, 0x4a, 0x44, 0x94, 0x6c, 0x00, 0xe1, 0xb1, - 0xa1, 0xdf, 0x0e, 0x5b, 0x87, 0xb5, 0xbe, 0xce, 0x47, 0x7a, 0x70, 0x96, 0x49, 0xe9, - 0x50, 0x06, 0x05, 0x91, 0x39, 0x48, 0x12, 0x95, 0x1e, 0x1f, 0xe3, 0x89, 0x5b, 0x8c, - 0xc3, 0xd1, 0x4d, 0x2c, 0xf6, 0x55, 0x6d, 0xf6, 0xed, 0x4b, 0x4d, 0xdd, 0x3d, 0x9a, - 0x69, 0xf5, 0x33, 0x57, 0xd7, 0x76, 0x7f, 0x4f, 0x5c, 0xcb, 0xdb, 0xc5, 0x96, 0x63, - 0x12, 0x77, 0xf8, 0xfe, 0xcd, 0x08, 0xcb, 0x05, 0x6b, 0x95, 0xe3, 0x02, 0x5b, 0x97, - 0x92, 0xff, 0xf7, 0xf2, 0x44, 0xfc, 0x71, 0x62, 0x69, 0xb9, 0x26, 0xd6, 0x2e, 0x95, - 0x96, 0xfa, 0x82, 0x5c, 0x6b, 0xf2, 0x1a, 0xff, 0x9e, 0x68, 0x62, 0x5a, 0x6b, 0x4c, - 0xbc, 0x4b, 0x70, 0x0a, 0x36, 0x4f, 0xa7, 0x6b, 0xd8, 0x29, 0x8b, 0xc3, 0xec, 0x60, - 0x8d, 0x4c, 0xf7, 0xf3, 0x56, 0x66, 0x58, 0xd5, 0x58, 0x87, 0x14, 0xec, 0x94, 0x48, - 0xb0, 0xf0, 0x39, 0x61, 0x28, 0xae, 0xf8, 0x84, 0xa6, 0x46, 0x11, 0x4c, 0x9f, 0x1a, - 0x6d, 0xf5, 0x63, 0x19, 0x03, 0x3c, 0x31, 0x99, 0xcc, 0x7a, 0x09, 0xe9, 0xe9, 0x56, - 0x74, 0x82, 0xc9, 0x26, 0x95, 0x39, 0x02, 0x29, 0x40, 0x7b, 0xbc, 0x48, 0x98, 0x56, - 0x75, 0xe3, 0xf8, 0x74, 0xa4, 0x53, 0x3f, 0x1d, 0x63, 0xa8, 0x4d, 0xfa, 0x3e, 0x0f, - 0x46, 0x0f, 0xe2, 0xf5, 0x7e, 0x34, 0xfb, 0xc7, 0x54, 0x23, 0xb6, 0x88, 0x3a, 0x50, - 0xa0, 0xd4, 0x70, 0x19, 0x0d, 0xfb, 0xa1, 0x0a, 0x85, 0x7f, 0x82, 0x84, 0x2d, 0x38, - 0x25, 0xb3, 0xd6, 0xda, 0x05, 0x73, 0xd3, 0x16, 0xeb, 0x16, 0x0d, 0xc0, 0xb7, 0x16, - 0xc4, 0x8f, 0xbd, 0x46, 0x7f, 0x75, 0xb7, 0x80, 0x14, 0x9a, 0xe8, 0x80, 0x8f, 0x4e, - 0x68, 0xf5, 0x0c, 0x05, 0x36, 0xac, 0xdd, 0xf6, 0xf1, 0xae, 0xab, 0x01, 0x6b, 0x6b, - 0xc1, 0xec, 0x14, 0x4b, 0x4e, 0x55, 0x3a, 0xcf, 0xd6, 0x70, 0xf7, 0x7e, 0x75, 0x5f, - 0xc8, 0x8e, 0x06, 0x77, 0xe3, 0x1b, 0xa4, 0x59, 0xb4, 0x4e, 0x30, 0x77, 0x68, 0x95, - 0x8f, 0xe3, 0x78, 0x9d, 0x41, 0xc2, 0xb1, 0xff, 0x43, 0x4c, 0xb3, 0x0e, 0x15, 0x91, - 0x4f, 0x01, 0xbc, 0x6b, 0xc2, 0x30, 0x7b, 0x48, 0x8d, 0x25, 0x56, 0xd7, 0xb7, 0x38, - 0x0e, 0xa4, 0xff, 0xd7, 0x12, 0xf6, 0xb0, 0x2f, 0xe8, 0x06, 0xb9, 0x45, 0x69, 0xcd, - 0x40, 0x59, 0xf3, 0x96, 0xbf, 0x29, 0xb9, 0x9d, 0x0a, 0x40, 0xe5, 0xe1, 0x71, 0x1c, - 0xa9, 0x44, 0xf7, 0x2d, 0x43, 0x6a, 0x10, 0x2f, 0xca, 0x4b, 0x97, 0x69, 0x3d, 0xa0, - 0xb0, 0x86, 0xfe, 0x9d, 0x2e, 0x71, 0x62, 0x47, 0x0d, 0x02, 0xe0, 0xf0, 0x5d, 0x4b, - 0xec, 0x95, 0x12, 0xbf, 0xb3, 0xf3, 0x83, 0x27, 0x29, 0x6e, 0xfa, 0xa7, 0x43, 0x28, - 0xb1, 0x18, 0xc2, 0x74, 0x02, 0xc7, 0x0c, 0x3a, 0x90, 0xb4, 0x9a, 0xd4, 0xbb, 0xc6, - 0x8e, 0x37, 0xc0, 0xaa, 0x7d, 0x9b, 0x3f, 0xe1, 0x77, 0x99, 0xd7, 0x3b, 0x84, 0x1e, - 0x75, 0x17, 0x13, 0xa0, 0x29, 0x43, 0x90, 0x5a, 0xae, 0x08, 0x03, 0xfd, 0x69, 0x44, - 0x2e, 0xb7, 0x68, 0x1e, 0xc2, 0xa0, 0x56, 0x00, 0x05, 0x4e, 0x92, 0xee, 0xd5, 0x55, - 0x02, 0x8f, 0x21, 0xb6, 0xa1, 0x55, 0x26, 0x8a, 0x2d, 0xd6, 0x64, 0x0a, 0x69, 0x30, - 0x1a, 0x52, 0xa3, 0x8d, 0x4d, 0x9f, 0x9f, 0x95, 0x7a, 0xe3, 0x5a, 0xf7, 0x16, 0x71, - 0x18, 0x14, 0x1c, 0xe4, 0xc9, 0xbe, 0x0a, 0x6a, 0x49, 0x2f, 0xe7, 0x9f, 0x15, 0x81, - 0xa1, 0x55, 0xfa, 0x3a, 0x03, 0x49, 0x99, 0xc5, 0x38, 0xf7, 0xa7, 0x58, 0xbb, 0x5b, - 0x1d, 0x28, 0xfd, 0x21, 0x8f, 0xba, 0x19, 0x38, 0x74, 0x4b, 0xdb, 0x77, 0xb4, 0xa4, - 0xdf, 0xa7, 0xa5, 0xfa, 0xe9, 0x6e, 0x8c, 0xd4, 0x9b, 0x26, 0x90, 0x7d, 0xfc, 0x66, - 0x85, 0xc5, 0xc9, 0x9b, 0x71, 0x41, 0xac, 0x62, 0x6a, 0xb4, 0x76, 0x1f, 0xd3, 0xf4, - 0x1e, 0x72, 0x8e, 0x1a, 0x28, 0xf8, 0x9d, 0xb8, 0x9f, 0xfd, 0xec, 0xa3, 0x64, 0xe4, - 0xb2, 0x2d, 0x81, 0xd9, 0x96, 0x8d, 0x01, 0x19, 0xe4, 0xc7, 0xa1, 0x89, 0xad, 0xf2, - 0x2a, 0xd9, 0x68, 0x30, 0xa5, 0x4e, 0x40, 0xdc, 0x73, 0xea, 0xba, 0x6b, 0x2a, 0xaf, - 0x14, 0xf7, 0xca, 0x94, 0x2e, 0x73, 0x70, 0xb2, 0x47, 0xc0, 0x46, 0xf8, 0xe7, 0x5e, - 0xf8, 0xe3, 0xf8, 0xbd, 0x82, 0x1c, 0xf5, 0x77, 0x49, 0x18, 0x64, 0xe2, 0x0e, 0x6d, - 0x08, 0xfd, 0x2e, 0x32, 0xb5, 0x55, 0xc9, 0x2c, 0x66, 0x1f, 0x19, 0x58, 0x8b, 0x72, - 0xa8, 0x95, 0x99, 0x71, 0x0a, 0x88, 0x06, 0x12, 0x53, 0xca, 0x28, 0x5b, 0x63, 0x04, - 0xb3, 0x7d, 0xa2, 0xb5, 0x29, 0x4f, 0x5c, 0xb3, 0x54, 0xa8, 0x94, 0x32, 0x28, 0x48, - 0xcc, 0xbd, 0xc7, 0xc2, 0x54, 0x5b, 0x7d, 0xa5, 0x68, 0xaf, 0xac, 0x87, 0xff, 0xa0, - 0x05, 0xc3, 0x12, 0x24, 0x1c, 0x2d, 0x57, 0xf4, 0xb4, 0x5d, 0x64, 0x19, 0xf0, 0xd2, - 0xe2, 0xc5, 0xaf, 0x33, 0xae, 0x24, 0x37, 0x85, 0xb3, 0x25, 0xcd, 0xab, 0x95, 0x40, - 0x4f, 0xc7, 0xae, 0xd7, 0x05, 0x25, 0xcd, 0xdb, 0x41, 0x87, 0x2c, 0xfc, 0xc2, 0x14, - 0xb1, 0x32, 0x32, 0xed, 0xc7, 0x86, 0x09, 0x75, 0x3d, 0xbf, 0xf9, 0x30, 0xeb, 0x0d, - 0xc1, 0x56, 0x61, 0x2b, 0x9c, 0xb4, 0x34, 0xbc, 0x4b, 0x69, 0x33, 0x92, 0xde, 0xb8, - 0x7c, 0x53, 0x04, 0x35, 0x31, 0x2e, 0xdc, 0xed, 0xc6, 0xa9, 0x61, 0x13, 0x33, 0x38, - 0xd7, 0x86, 0xc4, 0xa3, 0xe1, 0x03, 0xf6, 0x01, 0x10, 0xa1, 0x6b, 0x13, 0x37, 0x12, - 0x97, 0x04, 0xbf, 0x47, 0x54, 0xff, 0x6b, 0xa9, 0xfb, 0xe6, 0x59, 0x51, 0xe6, 0x10, - 0x62, 0x0f, 0x71, 0xcd, 0xa8, 0xfc, 0x87, 0x76, 0x25, 0xf2, 0xc5, 0xbb, 0x04, 0xcb, - 0xe1, 0x22, 0x8b, 0x1e, 0x88, 0x6f, 0x40, 0x50, 0xaf, 0xd8, 0xfe, 0x94, 0xe9, 0x7d, - 0x2e, 0x9e, 0x85, 0xc6, 0xbb, 0x74, 0x8c, 0x00, 0x42, 0xd3, 0x24, 0x9a, 0xbb, 0x13, - 0x42, 0xbb, 0x0e, 0xeb, 0xf6, 0x20, 0x58, 0xbf, 0x3d, 0xe0, 0x80, 0xd9, 0x46, 0x11, - 0xa3, 0x75, 0x09, 0x15, 0xb5, 0xdc, 0x6c, 0x0b, 0x38, 0x99, 0xd4, 0x12, 0x22, 0xba, - 0xce, 0x76, 0x0e, 0xe9, 0xc8, 0x81, 0x8d, 0xed, 0x59, 0x9e, 0x34, 0xc5, 0x6d, 0x73, - 0x72, 0xaf, 0x1e, 0xb8, 0x68, 0x52, 0xf2, 0xa7, 0x32, 0x10, 0x4b, 0xdb, 0x75, 0x07, - 0x39, 0xde, 0x6c, 0x2c, 0x6e, 0x0f, 0x9e, 0xb7, 0xcb, 0x17, 0xf1, 0x94, 0x2b, 0xfc, - 0x9f, 0x4f, 0xd6, 0xeb, 0xb6, 0xb4, 0xcd, 0xd4, 0xda, 0x2b, 0xca, 0x26, 0xfa, 0xc4, - 0x57, 0x8e, 0x9f, 0x54, 0x34, 0x05, 0xac, 0xc7, 0xd8, 0x6f, 0xf5, 0x91, 0x58, 0xbd, - 0x0c, 0xba, 0x3a, 0xef, 0x6f, 0x4a, 0x84, 0x72, 0xd1, 0x44, 0xd9, 0x9f, 0x8b, 0x8d, - 0x1d, 0xed, 0xaa, 0x90, 0x77, 0xd4, 0xf0, 0x1d, 0x4b, 0xb2, 0x7b, 0xbe, 0x31, 0xd8, - 0x8f, 0xbe, 0xfa, 0xc3, 0xdc, 0xd4, 0x79, 0x75, 0x63, 0xa2, 0x6b, 0x1d, 0x61, 0xfc, - 0xd9, 0xa4, 0x64, 0xab, 0x21, 0xed, 0x55, 0x0f, 0xe6, 0xfa, 0x09, 0x69, 0x5b, 0xa0, - 0xb2, 0xf1, 0x0e, 0xea, 0x64, 0x68, 0xcc, 0x6e, 0x20, 0xa6, 0x6f, 0x82, 0x6e, 0x3d, - 0x14, 0xc5, 0x00, 0x6f, 0x05, 0x63, 0x88, 0x7f, 0x5e, 0x12, 0x89, 0xbe, 0x1b, 0x20, - 0x04, 0xca, 0xca, 0x8d, 0x3f, 0x34, 0xd6, 0xe8, 0x4b, 0xf5, 0x9c, 0x1e, 0x04, 0x61, - 0x9a, 0x7c, 0x23, 0xa9, 0x96, 0x94, 0x1d, 0x88, 0x9e, 0x46, 0x22, 0xa9, 0xb9, 0xb1, - 0xd5, 0x9d, 0x5e, 0x31, 0x90, 0x94, 0x31, 0x8c, 0xd4, 0x05, 0xba, 0x27, 0xb7, 0xe2, - 0xc0, 0x84, 0x76, 0x2d, 0x31, 0x45, 0x3e, 0xc4, 0x54, 0x9a, 0x4d, 0x97, 0x72, 0x9d, - 0x03, 0x34, 0x60, 0xfc, 0xf8, 0x9d, 0x64, 0x94, 0xf2, 0xff, 0xd7, 0x89, 0xe9, 0x80, - 0x82, 0xea, 0x5c, 0xe9, 0x53, 0x4b, 0x3a, 0xcd, 0x60, 0xfe, 0x49, 0xe3, 0x7e, 0x4f, - 0x66, 0x69, 0x31, 0x67, 0x73, 0x19, 0xed, 0x89, 0xf8, 0x55, 0x88, 0x74, 0x1b, 0x31, - 0x28, 0x90, 0x1a, 0x93, 0xbd, 0x78, 0xe4, 0xbe, 0x02, 0x25, 0xa9, 0xe2, 0x69, 0x2c, - 0x77, 0xc9, 0x69, 0xed, 0x01, 0x76, 0xbd, 0xf9, 0x55, 0x59, 0x48, 0xcb, 0xd5, 0xa3, - 0x32, 0xd0, 0x45, 0xde, 0x6b, 0xa6, 0xbf, 0x44, 0x90, 0xad, 0xfe, 0x74, 0x44, 0xcd, - 0x46, 0x7a, 0x09, 0x07, 0x54, 0x17, 0xfc, 0xc0, 0x06, 0x2e, 0x49, 0xf0, 0x08, 0xc5, - 0x1a, 0xd4, 0x22, 0x74, 0x39, 0xc1, 0xb4, 0x47, 0x6c, 0xcd, 0x8e, 0x97, 0x86, 0x2d, - 0xab, 0x7b, 0xe1, 0xe8, 0xd3, 0x99, 0xc0, 0x5e, 0xf2, 0x7c, 0x6e, 0x22, 0xee, 0x27, - 0x3e, 0x15, 0x78, 0x6e, 0x39, 0x4c, 0x8f, 0x1b, 0xe3, 0x16, 0x82, 0xa3, 0x01, 0x47, - 0x96, 0x3a, 0xc8, 0xda, 0x8d, 0x41, 0xd8, 0x04, 0x25, 0x84, 0x26, 0xa3, 0xf7, 0x02, - 0x89, 0xb8, 0xad, 0x19, 0xd8, 0xde, 0x13, 0xbe, 0x4e, 0xeb, 0xe3, 0xbd, 0x4c, 0x8a, - 0x6f, 0x55, 0xd6, 0xe0, 0xc3, 0x73, 0xd4, 0x56, 0x85, 0x18, 0x79, 0xf5, 0xfb, 0xc2, - 0x82, 0xdb, 0x9e, 0x13, 0x48, 0x06, 0xbf, 0xf7, 0x1e, 0x11, 0xbc, 0x33, 0xab, 0x75, - 0xdd, 0x6c, 0xa0, 0x67, 0xfb, 0x73, 0xa0, 0x43, 0xb6, 0x46, 0xa7, 0xcf, 0x39, 0xca, - 0xb4, 0x92, 0x83, 0x86, 0x78, 0x6d, 0x2f, 0x24, 0x14, 0x1e, 0xe1, 0x20, 0xfd, 0xc3, - 0x4d, 0x67, 0x64, 0xea, 0xfc, 0x66, 0x88, 0x0e, 0xe0, 0x20, 0x4f, 0x53, 0xcc, 0x11, - 0x67, 0xed, 0x20, 0xb4, 0x3a, 0x52, 0xde, 0xa3, 0xca, 0x7c, 0xff, 0x8e, 0xf3, 0x5c, - 0xd8, 0xe6, 0xd7, 0xc1, 0x11, 0xa6, 0x8e, 0xf4, 0x4b, 0xcd, 0x0c, 0x15, 0x13, 0xad, - 0x47, 0xca, 0x61, 0xc6, 0x59, 0xcc, 0x5d, 0x32, 0x5b, 0x44, 0x0f, 0x6b, 0x9f, 0x59, - 0xaf, 0xf6, 0x68, 0x79, 0xbb, 0x66, 0x88, 0xfd, 0x28, 0x59, 0x36, 0x2b, 0x18, 0x2f, - 0x20, 0x7b, 0x31, 0x75, 0x96, 0x1f, 0x64, 0x11, 0xa4, 0x93, 0xbf, 0xfd, 0x04, 0x8e, - 0x7d, 0x0d, 0x87, 0xd8, 0x2f, 0xe6, 0xf9, 0x90, 0xa2, 0xb0, 0xa2, 0x5f, 0x5a, 0xa0, - 0x11, 0x1a, 0x6e, 0x68, 0xf3, 0x7b, 0xf6, 0xf3, 0xac, 0x2d, 0x26, 0xb8, 0x46, 0x86, - 0xe5, 0x69, 0xd5, 0x8d, 0x99, 0xc1, 0x38, 0x35, 0x97, 0xfa, 0xd8, 0x11, 0x93, 0xc4, - 0xc1, 0xb1, 0x6e, 0x6a, 0x90, 0xe2, 0xd5, 0x07, 0xcd, 0xfe, 0x6f, 0xbd, 0xaa, 0x86, - 0x16, 0x3e, 0x9c, 0xf5, 0xde, 0x31, 0x00, 0xfb, 0xca, 0x7e, 0x8d, 0xa0, 0x47, 0xb0, - 0x90, 0x79, 0x36, 0x2d, 0x77, 0x92, 0xde, 0xb3, 0xca, 0x9d, 0xc1, 0x56, 0x1b, 0x87, - 0xc8, 0x2e, 0x3c, 0xb9, 0x9e, 0xb5, 0x83, 0x73, 0x19, 0x58, 0x22, 0x16, 0xa3, 0x22, - 0x67, 0x74, 0xef, 0xa9, 0x0e, 0xfb, 0x7b, 0xfc, 0x79, 0xf4, 0x25, 0x64, 0x4e, 0x4e, - 0x98, 0xc2, 0xd7, 0xd8, 0x64, 0x2b, 0x9d, 0xb8, 0x2a, 0xa7, 0x39, 0xbf, 0x2d, 0x71, - 0xcc, 0x41, 0x17, 0x22, 0x7d, 0xb2, 0x27, 0xcf, 0x0a, 0x05, 0xad, 0x9a, 0x95, 0x83, - 0x2e, 0x23, 0xc9, 0x4f, 0x27, 0x1c, 0xa0, 0xe4, 0x69, 0x4f, 0xac, 0x63, 0x22, 0x28, - 0x2e, 0xba, 0xc6, 0x98, 0x6b, 0x8f, 0xdc, 0x8a, 0xd8, 0x63, 0x08, 0x4f, 0xf1, 0x0f, - 0xd1, 0x1e, 0x6a, 0x13, 0x31, 0x1f, 0xb7, 0x99, 0xc7, 0x9c, 0x64, 0x1d, 0x9d, 0xa4, - 0x3b, 0x33, 0xe7, 0xad, 0x01, 0x2e, 0x28, 0x25, 0x53, 0x98, 0x78, 0x92, 0x62, 0x27, - 0x5f, 0x11, 0x75, 0xbe, 0x84, 0x62, 0xc0, 0x14, 0x91, 0xc4, 0xd8, 0x42, 0x40, 0x6d, - 0x0e, 0xc4, 0x28, 0x2c, 0x95, 0x26, 0x17, 0x4a, 0x09, 0x87, 0x8f, 0xe8, 0xfd, 0xde, - 0x33, 0xa2, 0x96, 0x04, 0xe5, 0xe5, 0xe7, 0xb2, 0xa0, 0x25, 0xd6, 0x65, 0x0b, 0x97, - 0xdb, 0xb5, 0x2b, 0xef, 0xb5, 0x9b, 0x1d, 0x30, 0xa5, 0x74, 0x33, 0xb0, 0xa3, 0x51, - 0x47, 0x44, 0x44, 0x09, 0x9d, 0xaa, 0x37, 0x10, 0x46, 0x61, 0x32, 0x60, 0xcf, 0x33, - 0x54, 0xcf, 0xcd, 0xad, 0xa6, 0x63, 0xec, 0xe8, 0x24, 0xff, 0xd7, 0xe4, 0x43, 0x93, - 0x88, 0x6a, 0x86, 0x16, 0x5d, 0xdd, 0xdf, 0x2b, 0x4c, 0x41, 0x77, 0x35, 0x54, 0xc8, - 0x69, 0x95, 0x26, 0x94, 0x08, 0xb1, 0x1e, 0x67, 0x37, 0xa4, 0xc4, 0x47, 0x58, 0x6f, - 0x69, 0x17, 0x34, 0x46, 0xd8, 0xe4, 0x8b, 0xf8, 0x4c, 0xbc, 0x00, 0x0a, 0x80, 0x78, - 0x99, 0x97, 0x3e, 0xb9, 0x3c, 0x5e, 0x81, 0x9a, 0xad, 0x66, 0x94, 0x13, 0xf8, 0x38, - 0x79, 0x33, 0xad, 0x15, 0x84, 0xaa, 0x35, 0xe4, 0x3f, 0x4e, 0xcd, 0x1e, 0x2d, 0x04, - 0x07, 0xc0, 0xb1, 0xb8, 0x99, 0x20, 0xff, 0xdf, 0xdb, 0x9b, 0xea, 0x51, 0xac, 0x95, - 0xb5, 0x57, 0xaf, 0x71, 0xb8, 0x9f, 0x90, 0x3f, 0x5d, 0x98, 0x48, 0xf1, 0x4f, 0xcb, - 0xeb, 0x18, 0x37, 0x57, 0x0f, 0x54, 0x4d, 0x63, 0x59, 0xeb, 0x23, 0xfa, 0xf3, 0x8a, - 0x08, 0x22, 0xda, 0x36, 0xce, 0x42, 0x6c, 0x4a, 0x2f, 0xbe, 0xff, 0xeb, 0x0a, 0x8a, - 0x2e, 0x29, 0x7a, 0x9d, 0x19, 0xba, 0x15, 0x02, 0x45, 0x90, 0xe3, 0x32, 0x9d, 0x9f, - 0xa9, 0x26, 0x1f, 0x99, 0x38, 0xa4, 0x03, 0x2d, 0xd3, 0x46, 0x06, 0xc9, 0xcf, 0x9f, - 0x3d, 0xd3, 0x3e, 0x57, 0x6f, 0x05, 0xcd, 0x1d, 0xd6, 0x81, 0x1c, 0x62, 0x98, 0x75, - 0x7d, 0x77, 0xd9, 0xe8, 0x10, 0xab, 0xdb, 0x22, 0x6a, 0xfc, 0xaa, 0x43, 0x46, 0xa6, - 0x56, 0x0f, 0x89, 0x32, 0xb3, 0x18, 0x1f, 0xd3, 0x55, 0xd5, 0xd3, 0x91, 0x97, 0x61, - 0x83, 0xf8, 0xd9, 0x93, 0x88, 0x83, 0x96, 0x32, 0xd6, 0x35, 0x4f, 0x66, 0x6d, 0x09, - 0xd3, 0xe5, 0x62, 0x9e, 0xa1, 0x97, 0x37, 0x38, 0x86, 0x13, 0xd3, 0x8a, 0x34, 0xfd, - 0x0f, 0x6e, 0x50, 0xee, 0x5a, 0x0c, 0xc9, 0x67, 0x71, 0x77, 0xf5, 0x00, 0x28, 0xc1, - 0x41, 0x37, 0x81, 0x87, 0xbd, 0x28, 0x19, 0x40, 0x3f, 0xc5, 0x34, 0xf8, 0x00, 0x76, - 0xe9, 0x38, 0x0c, 0xb4, 0x96, 0x4d, 0x3b, 0x6b, 0x45, 0x81, 0x9d, 0x3b, 0x8e, 0x9c, - 0xaf, 0x54, 0xf0, 0x51, 0x85, 0x2d, 0x67, 0x1b, 0xf8, 0xc1, 0xff, 0xde, 0x2d, 0x15, - 0x10, 0x75, 0x64, 0x18, 0xcb, 0x48, 0x10, 0x93, 0x6a, 0xa5, 0x7e, 0x69, 0x65, 0xd6, - 0xfb, 0x65, 0x6a, 0x76, 0x0b, 0x7f, 0x19, 0xad, 0xf9, 0x6c, 0x17, 0x34, 0x88, 0x55, - 0x21, 0x93, 0xb1, 0x47, 0xee, 0x58, 0x85, 0x80, 0x33, 0xda, 0xc7, 0xcd, 0x0e, 0xb2, - 0x04, 0xc0, 0x64, 0x90, 0xbb, 0xde, 0xdf, 0x5f, 0x75, 0x71, 0xac, 0xb2, 0xeb, 0xe7, - 0x6a, 0xce, 0xf3, 0xf2, 0xa0, 0x1e, 0xe9, 0x87, 0x48, 0x6d, 0xfe, 0x6c, 0x3f, 0x0a, - 0x5e, 0x23, 0x4c, 0x12, 0x72, 0x58, 0xf9, 0x7a, 0x28, 0xfb, 0x5d, 0x16, 0x4a, 0x81, - 0x76, 0xbe, 0x94, 0x6b, 0x80, 0x97, 0xd0, 0xe3, 0x17, 0x28, 0x7f, 0x33, 0xbf, 0x9c, - 0x16, 0xf9, 0xa5, 0x45, 0x40, 0x9c, 0xe2, 0x9b, 0x1f, 0x42, 0x73, 0x72, 0x5f, 0xc0, - 0xdf, 0x02, 0xa0, 0x4e, 0xba, 0xe1, 0x78, 0xb3, 0x41, 0x4f, 0xb0, 0xa8, 0x2d, 0x50, - 0xde, 0xb0, 0x9f, 0xcf, 0x4e, 0x6e, 0xe9, 0xd1, 0x80, 0xff, 0x4f, 0x56, 0xff, 0x3b, - 0xc1, 0xd3, 0x60, 0x1f, 0xc2, 0xdc, 0x90, 0xd8, 0x14, 0xc3, 0x25, 0x6f, 0x49, 0x67, - 0xd3, 0xa8, 0xd6, 0x4c, 0x83, 0xfe, 0xa3, 0x39, 0xc5, 0x1f, 0x5a, 0x8e, 0x58, 0x01, - 0xfb, 0xb9, 0x78, 0x35, 0x58, 0x1b, 0x60, 0x24, 0x65, 0xde, 0xe0, 0x4b, 0x59, 0x22, - 0xc2, 0x76, 0x1b, 0x54, 0x24, 0x5b, 0xec, 0x0c, 0x9e, 0xef, 0x2d, 0xb9, 0x7d, 0x22, - 0xb2, 0xb3, 0x55, 0x6c, 0xc9, 0x69, 0xfb, 0xb1, 0x3d, 0x06, 0x50, 0x97, 0x65, 0xa5, - 0x2b, 0x3f, 0xac, 0x54, 0xb9, 0x3f, 0x42, 0x1b, 0xf0, 0x8e, 0x18, 0xd5, 0x2d, 0xdd, - 0x52, 0xcc, 0x1c, 0x8c, 0xa8, 0xad, 0xfa, 0xcc, 0xab, 0x7e, 0x5c, 0xc2, 0xf4, 0x57, - 0x3f, 0xbb, 0xf8, 0x23, 0x9b, 0xb0, 0xb8, 0xae, 0xdb, 0xf8, 0xda, 0xd1, 0x62, 0x82, - 0xda, 0x5c, 0x91, 0x25, 0xdb, 0xa1, 0xc0, 0x59, 0xd0, 0xdf, 0x8a, 0xbf, 0x62, 0x10, - 0x78, 0xf0, 0x2d, 0x6c, 0x4b, 0xc8, 0x6d, 0x40, 0x84, 0x5a, 0xc1, 0xd5, 0x97, 0x10, - 0xc4, 0x5f, 0x07, 0xd5, 0x85, 0xeb, 0x48, 0xb3, 0x2f, 0xc0, 0x16, 0x7b, 0xa2, 0x56, - 0xe7, 0x3c, 0xa3, 0xb9, 0x31, 0x1c, 0x62, 0xd1, 0x09, 0x49, 0x79, 0x57, 0xd8, 0xdb, - 0xe1, 0x0a, 0xa3, 0xe8, 0x66, 0xb4, 0x0c, 0x0b, 0xaa, 0x2b, 0xc4, 0x92, 0xc1, 0x9a, - 0xd1, 0xe6, 0x37, 0x2d, 0x96, 0x22, 0xbf, 0x16, 0x3f, 0xbf, 0xfe, 0xae, 0xee, 0x79, - 0x6a, 0x3c, 0xd9, 0xb6, 0xfb, 0xbf, 0xa4, 0xd7, 0x92, 0xf3, 0x4d, 0x7f, 0xd6, 0xe7, - 0x63, 0xcd, 0x58, 0x59, 0xdd, 0x26, 0x83, 0x3d, 0x21, 0xd9, 0xbc, 0x54, 0x52, 0xbd, - 0x19, 0x51, 0x5d, 0xff, 0x9f, 0x49, 0x95, 0xb3, 0x5b, 0xc0, 0xc1, 0xf8, 0x76, 0xe6, - 0xad, 0x11, 0xf2, 0x45, 0x2d, 0xc9, 0xae, 0x85, 0xae, 0xc0, 0x1f, 0xc5, 0x6f, 0x8c, - 0xbf, 0xda, 0x75, 0xa7, 0x72, 0x7b, 0x75, 0xeb, 0xbd, 0x6b, 0xbf, 0xfb, 0x43, 0xb6, - 0x3a, 0x3b, 0x1b, 0x67, 0x1e, 0x40, 0xfe, 0xb0, 0xdb, 0x00, 0x29, 0x74, 0xa3, 0xc3, - 0xb1, 0xa7, 0x88, 0x56, 0x72, 0x31, 0xbf, 0x63, 0x99, 0xff, 0x89, 0x23, 0x69, 0x81, - 0x14, 0x9d, 0x42, 0x38, 0x02, 0xd2, 0x34, 0x1a, 0x3b, 0xed, 0xb9, 0xdd, 0xcb, 0xac, - 0x1f, 0xe7, 0xb6, 0x43, 0x5e, 0x14, 0x79, 0xc7, 0x2e, 0x70, 0x89, 0xb5, 0x1b, 0xfe, - 0x2f, 0xf3, 0x45, 0x85, 0x7d, 0xa9, 0xb5, 0x45, 0xe8, 0x8e, 0x32, 0x21, 0xf3, 0xf5, - 0xf7, 0x2d, 0x1e, 0x06, 0x9c, 0x9a, 0x85, 0xdd, 0x22, 0x36, 0xd3, 0x90, 0x98, 0x95, - 0x87, 0xbe, 0x00, 0x5c, 0xda, 0x16, 0xaf, 0x44, 0x08, 0xf3, 0xab, 0x06, 0xa9, 0x16, - 0xee, 0xeb, 0x9c, 0x95, 0x94, 0xb7, 0x04, 0x24, 0xa4, 0xc1, 0xd1, 0x71, 0x29, 0x5b, - 0x67, 0x63, 0xb2, 0x2f, 0x47, 0x12, 0xba, 0x7b, 0xef, 0xf0, 0xff, 0x27, 0x88, 0x3a, - 0xfa, 0xff, 0x26, 0x03, 0x4b, 0x89, 0x57, 0x35, 0x70, 0x9c, 0xf9, 0x37, 0xbd, 0x22, - 0x31, 0x89, 0x1e, 0x70, 0xeb, 0x27, 0x71, 0xe9, 0x92, 0x7c, 0x97, 0xf8, 0x76, 0x4e, - 0xb4, 0x8e, 0x91, 0x1d, 0x42, 0x8e, 0xc8, 0xd8, 0x61, 0xb7, 0x08, 0xe8, 0x29, 0x8a, - 0xcb, 0x62, 0x15, 0x51, 0x45, 0x15, 0x5a, 0xe9, 0x5f, 0x0a, 0x1d, 0x15, 0x01, 0x03, - 0x47, 0x53, 0x14, 0x6e, 0x22, 0xd0, 0x5f, 0x58, 0x6d, 0x7f, 0x6b, 0x4f, 0xe1, 0x2d, - 0xad, 0x9a, 0x17, 0xf5, 0xdb, 0x70, 0xb1, 0xdb, 0x96, 0xb8, 0xd9, 0xa8, 0x3e, 0xda, - 0xdc, 0x96, 0x6c, 0x8a, 0x54, 0x66, 0xb6, 0x1f, 0xc9, 0x98, 0xc3, 0x1f, 0x10, 0x70, - 0xd9, 0xa5, 0xc9, 0xa6, 0xd2, 0x68, 0xd3, 0x04, 0xfe, 0x6b, 0x8f, 0xd3, 0xb4, 0x01, - 0x03, 0x48, 0x61, 0x1a, 0xbd, 0xcb, 0xd4, 0x9f, 0xe4, 0xf8, 0x5b, 0x62, 0x3c, 0x78, - 0x28, 0xc7, 0x13, 0x82, 0xe1, 0x03, 0x4e, 0xa6, 0x7b, 0xc8, 0xae, 0x97, 0x40, 0x4b, - 0x0c, 0x50, 0xb2, 0xa0, 0x4f, 0x55, 0x9e, 0x49, 0x95, 0x0a, 0xfc, 0xb0, 0xef, 0x46, - 0x2a, 0x2a, 0xe0, 0x24, 0xb0, 0xf0, 0x22, 0x4d, 0xfd, 0x73, 0x68, 0x4b, 0x88, 0xc7, - 0xfb, 0xe9, 0x2d, 0x02, 0xb6, 0x8f, 0x75, 0x9c, 0x47, 0x52, 0x66, 0x3c, 0xd7, 0xb9, - 0x7a, 0x14, 0x94, 0x36, 0x49, 0x30, 0x55, 0x21, 0x32, 0x6b, 0xde, 0x08, 0x56, 0x30, - 0x86, 0x46, 0x29, 0x29, 0x1b, 0xae, 0x25, 0xff, 0x88, 0x22, 0xa1, 0x4c, 0x4b, 0x66, - 0x6a, 0x92, 0x59, 0xad, 0x0d, 0xc4, 0x2a, 0x82, 0x90, 0xac, 0x7b, 0xc7, 0xf5, 0x3a, - 0x16, 0xf3, 0x79, 0xf7, 0x58, 0xe5, 0xde, 0x75, 0x0f, 0x04, 0xfd, 0x7c, 0xad, 0x47, - 0x70, 0x1c, 0x85, 0x97, 0xf9, 0x78, 0x88, 0xbe, 0xa6, 0xfa, 0x0b, 0xf2, 0x99, 0x99, - 0x56, 0xfb, 0xfd, 0x0e, 0xe6, 0x8e, 0xc3, 0x6e, 0x46, 0x88, 0x80, 0x9a, 0xe2, 0x31, - 0xeb, 0x8b, 0xc4, 0x36, 0x9f, 0x5f, 0xe1, 0x57, 0x3f, 0x57, 0xe0, 0x99, 0xd9, 0xc0, - 0x99, 0x01, 0xbf, 0x39, 0xca, 0xac, 0x48, 0xdc, 0x11, 0x95, 0x6a, 0x8a, 0xe9, 0x05, - 0xea, 0xd8, 0x69, 0x54, 0x54, 0x7c, 0x44, 0x8a, 0xe4, 0x3d, 0x31, 0x5e, 0x66, 0x9c, - 0x42, 0x42, 0xda, 0x56, 0x59, 0x38, 0xf4, 0x17, 0xbf, 0x43, 0xce, 0x7b, 0x2b, 0x30, - 0xb1, 0xcd, 0x40, 0x18, 0x38, 0x8e, 0x1a, 0x91, 0x0f, 0x0f, 0xc4, 0x1f, 0xb0, 0x87, - 0x7a, 0x59, 0x25, 0xe4, 0x66, 0x81, 0x9d, 0x37, 0x5b, 0x0a, 0x91, 0x2d, 0x4f, 0xe8, - 0x43, 0xb7, 0x6e, 0xf6, 0xf2, 0x23, 0xf0, 0xf7, 0xc8, 0x94, 0xf3, 0x8f, 0x7a, 0xb7, - 0x80, 0xdf, 0xd7, 0x5f, 0x66, 0x9c, 0x8c, 0x06, 0xcf, 0xfa, 0x43, 0xeb, 0x47, 0x56, - 0x5a, 0x50, 0xe3, 0xb1, 0xfa, 0x45, 0xad, 0x61, 0xce, 0x9a, 0x1c, 0x47, 0x27, 0xb7, - 0xaa, 0xa5, 0x35, 0x62, 0xf5, 0x23, 0xe7, 0x39, 0x52, 0xbb, 0xf3, 0x3d, 0x8a, 0x41, - 0x04, 0x07, 0x8a, 0xde, 0x3e, 0xaa, 0xa4, 0x96, 0x99, 0xa6, 0x9f, 0xdf, 0x1c, 0x5a, - 0xc7, 0x73, 0x21, 0x46, 0xee, 0x5e, 0x1d, 0x6b, 0x6c, 0xa9, 0xb9, 0x18, 0x0f, 0x96, - 0x4c, 0xc9, 0xd0, 0x87, 0x8a, 0xe1, 0x37, 0x35, 0x24, 0xd7, 0xd5, 0x10, 0xe5, 0x82, - 0x27, 0xdf, 0x6d, 0xe9, 0xd3, 0x0d, 0x27, 0x18, 0x67, 0x64, 0x01, 0x77, 0xb0, 0xf1, - 0x85, 0x6e, 0x28, 0xd5, 0xc8, 0xaf, 0xb0, 0x95, 0xef, 0x61, 0x84, 0xfe, 0xd6, 0x51, - 0x58, 0x90, 0x22, 0xee, 0xae, 0xa4, 0xc0, 0xce, 0x1f, 0xa6, 0xf0, 0x85, 0x09, 0x2b, - 0x04, 0x97, 0x94, 0x89, 0x17, 0x2b, 0x3e, 0xf8, 0x19, 0x4a, 0x79, 0x8d, 0xf5, 0x72, - 0x4d, 0x6b, 0x05, 0xf1, 0xae, 0x00, 0x00, 0x13, 0xa0, 0x8d, 0x61, 0x2b, 0xca, 0x8a, - 0x8c, 0x31, 0x44, 0x3c, 0x10, 0x34, 0x6d, 0xbf, 0x61, 0xde, 0x84, 0x75, 0xc0, 0xbb, - 0xec, 0x51, 0x04, 0xb4, 0x75, 0x56, 0xaf, 0x3d, 0x51, 0x44, 0x58, 0xe2, 0x32, 0x1d, - 0x14, 0x60, 0x71, 0x78, 0x9d, 0x23, 0x35, 0x93, 0x4a, 0x68, 0x06, 0x14, 0xe8, 0x35, - 0x62, 0xf8, 0x2d, 0xfd, 0x40, 0x5b, 0x54, 0xa4, 0x5e, 0xb3, 0x2c, 0x16, 0x54, 0x48, - 0xd4, 0xd5, 0xd6, 0x1c, 0xa2, 0x85, 0x95, 0x85, 0x36, 0x9f, 0x53, 0xf1, 0xa1, 0x37, - 0xe9, 0xe8, 0x2b, 0x67, 0xb8, 0xfd, 0xaf, 0x01, 0xbd, 0xa5, 0x4a, 0x31, 0x73, 0x11, - 0x89, 0x6a, 0xe1, 0x02, 0x80, 0xa0, 0x32, 0x44, 0x0c, 0x42, 0x0a, 0x42, 0x1e, 0x94, - 0x4d, 0x1e, 0x95, 0x2b, 0x70, 0xd5, 0x82, 0x6c, 0xd3, 0xb0, 0x8b, 0x7d, 0xb9, 0x63, - 0x0f, 0xe4, 0xfd, 0x5f, 0x22, 0x12, 0x5d, 0xe8, 0x40, 0xfc, 0xc4, 0x0b, 0x98, 0x03, - 0x8a, 0xf1, 0x1d, 0x55, 0xbe, 0x25, 0x43, 0x25, 0x97, 0xb4, 0xb6, 0x5b, 0x9e, 0xc1, - 0xc7, 0xa8, 0xbb, 0xfd, 0x05, 0x2c, 0xbf, 0x7e, 0x1c, 0x17, 0x85, 0x31, 0x49, 0x34, - 0xb2, 0x62, 0xd5, 0x85, 0x37, 0x54, 0xf1, 0xf1, 0x77, 0x71, 0xcf, 0xb7, 0x50, 0x30, - 0x72, 0x65, 0x57, 0x53, 0xfa, 0x3f, 0x54, 0xec, 0xc5, 0x87, 0xe9, 0xf8, 0x3b, 0x58, - 0x19, 0x16, 0x09, 0x2d, 0xf2, 0x6e, 0x63, 0xe1, 0x89, 0x94, 0xcb, 0x0d, 0xb9, 0x1a, - 0x0b, 0xbd, 0xc7, 0xb6, 0x11, 0x9b, 0x32, 0x22, 0x2a, 0xdf, 0x5e, 0x61, 0xd8, 0xd8, - 0xae, 0x89, 0xda, 0xe4, 0x95, 0x4b, 0x54, 0x81, 0x3b, 0xb3, 0x3f, 0x08, 0xd5, 0x62, - 0xba, 0x51, 0x3f, 0xee, 0x1b, 0x09, 0xc0, 0xfc, 0xd5, 0x16, 0x05, 0x54, 0x19, 0x47, - 0x4d, 0xd7, 0xfd, 0xa0, 0x38, 0xa8, 0x9c, 0x84, 0xea, 0x7b, 0x94, 0x68, 0x28, 0x7f, - 0x0e, 0xb0, 0xc1, 0x0c, 0x4b, 0x13, 0x25, 0x20, 0x19, 0x4d, 0x3d, 0x8d, 0x53, 0x51, - 0xfc, 0x10, 0xd0, 0x9c, 0x15, 0xc8, 0xcc, 0x10, 0x1a, 0xa1, 0x66, 0x3b, 0xbf, 0x17, - 0xb8, 0x41, 0x11, 0xf3, 0x8b, 0xb4, 0x39, 0xf0, 0x73, 0x53, 0xbd, 0xea, 0x35, 0x96, - 0xd1, 0x5e, 0x71, 0x3e, 0x1e, 0x2e, 0x7d, 0x3f, 0x1c, 0x38, 0x31, 0x35, 0xb4, 0x7f, - 0xa7, 0xf8, 0x1f, 0x46, 0xdf, 0x7a, 0x90, 0x2a, 0x40, 0x46, 0x99, 0xec, 0x91, 0x2f, - 0x56, 0x56, 0xc3, 0x5b, 0x85, 0x76, 0x3e, 0x4d, 0xe5, 0x83, 0xae, 0xca, 0xa1, 0xdf, - 0xd5, 0xd2, 0x67, 0x7d, 0x9c, 0x8f, 0xfe, 0xe8, 0x77, 0xf6, 0x3f, 0x40, 0xa5, 0xca, - 0x0d, 0x67, 0xf6, 0xe5, 0x54, 0x12, 0x47, 0x00, 0xf8, 0x05, 0xaf, 0x87, 0x6a, 0xee, - 0xde, 0x53, 0xaa, 0x8b, 0x0f, 0x8e, 0x56, 0x04, 0xa7, 0x3c, 0x30, 0xcb, 0xd0, 0x9d, - 0xad, 0x96, 0x3d, 0x6f, 0x8a, 0x5d, 0xcc, 0x40, 0xde, 0xf4, 0x07, 0x97, 0x34, 0x21, - 0x13, 0xba, 0x20, 0x6f, 0xae, 0x8e, 0xbe, 0x4f, 0x3b, 0xc3, 0xca, 0xf6, 0x92, 0x59, - 0xe4, 0x62, 0xef, 0xf9, 0xba, 0x8b, 0x3f, 0x4b, 0xfa, 0xa1, 0x30, 0x0c, 0x26, 0x92, - 0x5a, 0x87, - ], - script_code: vec![0x63], - transparent_input: None, - hash_type: 1, - amount: 1969273897303781, - consensus_branch_id: 1991772603, - sighash: [ - 0x63, 0xd1, 0x85, 0x34, 0xde, 0x5f, 0x2d, 0x1c, 0x9e, 0x16, 0x9b, 0x73, 0xf9, 0xc7, - 0x83, 0x71, 0x8a, 0xdb, 0xef, 0x5c, 0x8a, 0x7d, 0x55, 0xb5, 0xe7, 0xa3, 0x7a, 0xff, - 0xa1, 0xdd, 0x3f, 0xf3, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0x0b, 0xbe, 0x32, 0xa5, 0x98, - 0xc2, 0x2a, 0xdf, 0xb4, 0x8c, 0xef, 0x72, 0xba, 0x5d, 0x42, 0x87, 0xc0, 0xce, 0xfb, - 0xac, 0xfd, 0x8c, 0xe1, 0x95, 0xb4, 0x96, 0x3c, 0x34, 0xa9, 0x4b, 0xba, 0x7a, 0x17, - 0x5d, 0xae, 0x4b, 0x04, 0x65, 0xac, 0x65, 0x63, 0x53, 0x70, 0x89, 0x15, 0x09, 0x0f, - 0x47, 0xa0, 0x68, 0xe2, 0x27, 0x43, 0x3f, 0x9e, 0x49, 0xd3, 0xaa, 0x09, 0xe3, 0x56, - 0xd8, 0xd6, 0x6d, 0x0c, 0x01, 0x21, 0xe9, 0x1a, 0x3c, 0x4a, 0xa3, 0xf2, 0x7f, 0xa1, - 0xb6, 0x33, 0x96, 0xe2, 0xb4, 0x1d, 0x09, 0x00, 0x63, 0x53, 0x53, 0x00, 0xac, 0x53, - 0xac, 0x51, 0x4e, 0x97, 0x05, 0x68, 0x02, 0xda, 0x07, 0x1b, 0x97, 0x0d, 0x48, 0x07, - 0x00, 0x01, 0x52, 0xa8, 0x44, 0x55, 0x0b, 0xdc, 0x20, 0x02, 0x00, 0x07, 0x52, 0x52, - 0x6a, 0x65, 0x52, 0x00, 0x52, 0xd7, 0x03, 0x43, 0x02, 0x01, 0x1b, 0x9a, 0x07, 0x66, - 0x20, 0xed, 0xc0, 0x67, 0xff, 0x02, 0x00, 0x00, 0x03, 0x53, 0xe3, 0xb8, 0xa7, 0x1f, - 0xac, 0xe1, 0xc9, 0xf3, 0x77, 0x45, 0xed, 0x36, 0x88, 0x35, 0x29, 0x30, 0x4b, 0xfd, - 0x5a, 0x39, 0x0b, 0x37, 0xbc, 0x5a, 0x34, 0x45, 0x24, 0x1f, 0x03, 0xf6, 0x4a, 0x81, - 0x88, 0x20, 0xdf, 0xed, 0xdd, 0x75, 0x37, 0x51, 0x59, 0xfb, 0xd2, 0x1e, 0xca, 0x98, - 0x72, 0x10, 0x4f, 0x8d, 0x7b, 0x3c, 0x8c, 0x86, 0x97, 0x03, 0xa1, 0xe7, 0x84, 0x8a, - 0x5c, 0x94, 0x1e, 0x45, 0xa9, 0xc7, 0x94, 0x34, 0x46, 0xd0, 0xdc, 0x96, 0x27, 0xcb, - 0x31, 0xf8, 0x0e, 0x7a, 0xa5, 0x96, 0xd4, 0x82, 0x1d, 0xc9, 0x9a, 0x7d, 0x77, 0x7c, - 0xd5, 0x7e, 0x19, 0x48, 0x42, 0xa0, 0x23, 0x47, 0x1f, 0x0f, 0x62, 0x88, 0xa1, 0x50, - 0x64, 0x7b, 0x2a, 0xfe, 0x9d, 0xf7, 0xcc, 0xcf, 0x01, 0xf5, 0xcd, 0xe5, 0xf0, 0x46, - 0x80, 0xbb, 0xfe, 0xd8, 0x7f, 0x6c, 0xf4, 0x29, 0xfb, 0x27, 0xad, 0x6b, 0xab, 0xe7, - 0x91, 0x76, 0x66, 0x11, 0xcf, 0x5b, 0xc2, 0x0e, 0x48, 0xbe, 0xf1, 0x19, 0x25, 0x9b, - 0x9b, 0x8a, 0x0e, 0x39, 0xc3, 0xdf, 0x28, 0xcb, 0x95, 0x82, 0xea, 0x33, 0x86, 0x01, - 0xcd, 0xc4, 0x81, 0xb3, 0x2f, 0xb8, 0x2a, 0xde, 0xeb, 0xb3, 0xda, 0xde, 0x25, 0xd1, - 0xa3, 0xdf, 0x20, 0xc3, 0x7e, 0x71, 0x25, 0x06, 0xb5, 0xd9, 0x96, 0xc4, 0x9a, 0x9f, - 0x0f, 0x30, 0xdd, 0xcb, 0x91, 0xfe, 0x90, 0x04, 0xe1, 0xe8, 0x32, 0x94, 0xa6, 0xc9, - 0x20, 0x3d, 0x94, 0xe8, 0xdc, 0x2c, 0xbb, 0x44, 0x9d, 0xe4, 0x15, 0x50, 0x32, 0x60, - 0x4e, 0x47, 0x99, 0x70, 0x16, 0xb3, 0x04, 0xfd, 0x43, 0x7d, 0x82, 0x35, 0x04, 0x5e, - 0x25, 0x5a, 0x19, 0xb7, 0x43, 0xa0, 0xa9, 0xf2, 0xe3, 0x36, 0xb4, 0x4c, 0xae, 0x30, - 0x7b, 0xb3, 0x98, 0x7b, 0xd3, 0xe4, 0xe7, 0x77, 0xfb, 0xb3, 0x4c, 0x0a, 0xb8, 0xcc, - 0x3d, 0x67, 0x46, 0x6c, 0x0a, 0x88, 0xdd, 0x4c, 0xca, 0xd1, 0x8a, 0x07, 0xa8, 0xd1, - 0x06, 0x8d, 0xf5, 0xb6, 0x29, 0xe5, 0x71, 0x8d, 0x0f, 0x6d, 0xf5, 0xc9, 0x57, 0xcf, - 0x71, 0xbb, 0x00, 0xa5, 0x17, 0x8f, 0x17, 0x5c, 0xac, 0xa9, 0x44, 0xe6, 0x35, 0xc5, - 0x15, 0x9f, 0x73, 0x8e, 0x24, 0x02, 0xa2, 0xd2, 0x1a, 0xa0, 0x81, 0xe1, 0x0e, 0x45, - 0x6a, 0xfb, 0x00, 0xb9, 0xf6, 0x24, 0x16, 0xc8, 0xb9, 0xc0, 0xf7, 0x22, 0x8f, 0x51, - 0x07, 0x29, 0xe0, 0xbe, 0x3f, 0x30, 0x53, 0x13, 0xd7, 0x7f, 0x73, 0x79, 0xdc, 0x2a, - 0xf2, 0x48, 0x69, 0xc6, 0xc7, 0x4e, 0xe4, 0x47, 0x14, 0x98, 0x86, 0x1d, 0x19, 0x2f, - 0x0f, 0xf0, 0xf5, 0x08, 0x28, 0x5d, 0xab, 0x6b, 0x6a, 0x36, 0xcc, 0xf7, 0xd1, 0x22, - 0x56, 0xcc, 0x76, 0xb9, 0x55, 0x03, 0x72, 0x0a, 0xc6, 0x72, 0xd0, 0x82, 0x68, 0xd2, - 0xcf, 0x77, 0x73, 0xb6, 0xba, 0x2a, 0x5f, 0x66, 0x48, 0x47, 0xbf, 0x70, 0x7f, 0x2f, - 0xc1, 0x0c, 0x98, 0xf2, 0xf0, 0x06, 0xec, 0x22, 0xcc, 0xb5, 0xa8, 0xc8, 0xb7, 0xc4, - 0x0c, 0x7c, 0x2d, 0x49, 0xa6, 0x63, 0x9b, 0x9f, 0x2c, 0xe3, 0x3c, 0x25, 0xc0, 0x4b, - 0xc4, 0x61, 0xe7, 0x44, 0xdf, 0xa5, 0x36, 0xb0, 0x0d, 0x94, 0xba, 0xdd, 0xf4, 0xf4, - 0xd1, 0x40, 0x44, 0xc6, 0x95, 0xa3, 0x38, 0x81, 0x47, 0x7d, 0xf1, 0x24, 0xf0, 0xfc, - 0xf2, 0x06, 0xa9, 0xfb, 0x2e, 0x65, 0xe3, 0x04, 0xcd, 0xbf, 0x0c, 0x4d, 0x23, 0x90, - 0x17, 0x0c, 0x13, 0x0a, 0xb8, 0x49, 0xc2, 0xf2, 0x2b, 0x5c, 0xdd, 0x39, 0x21, 0x64, - 0x0c, 0x8c, 0xf1, 0x97, 0x6a, 0xe1, 0x01, 0x0b, 0x0d, 0xfd, 0x9c, 0xb2, 0x54, 0x3e, - 0x45, 0xf9, 0x97, 0x49, 0xcc, 0x4d, 0x61, 0xf2, 0xe8, 0xaa, 0xbf, 0xe9, 0x8b, 0xd9, - 0x05, 0xfa, 0x39, 0x95, 0x1b, 0x33, 0xea, 0x76, 0x9c, 0x45, 0xab, 0x95, 0x31, 0xc5, - 0x72, 0x09, 0x86, 0x2a, 0xd1, 0x2f, 0xd7, 0x6b, 0xa4, 0x80, 0x7e, 0x65, 0x41, 0x7b, - 0x6c, 0xd1, 0x2f, 0xa8, 0xec, 0x91, 0x6f, 0x01, 0x3e, 0xbb, 0x87, 0x06, 0xa9, 0x6e, - 0xff, 0xed, 0xa0, 0x6c, 0x4b, 0xe2, 0x4b, 0x04, 0x84, 0x63, 0x92, 0xe9, 0xd1, 0xe6, - 0x93, 0x0e, 0xae, 0x01, 0xfa, 0x21, 0xfb, 0xd7, 0x00, 0x58, 0x3f, 0xb5, 0x98, 0xb9, - 0x2c, 0x8f, 0x4e, 0xb8, 0xa6, 0x1a, 0xa6, 0x23, 0x5d, 0xb6, 0x0f, 0x28, 0x41, 0xcf, - 0x3a, 0x1c, 0x6a, 0xb5, 0x4c, 0x67, 0x06, 0x68, 0x44, 0x71, 0x1d, 0x09, 0x1e, 0xb9, - 0x31, 0xa1, 0xbd, 0x62, 0x81, 0xae, 0xdf, 0x2a, 0x0e, 0x8f, 0xab, 0x18, 0x81, 0x72, - 0x02, 0xa9, 0xbe, 0x06, 0x40, 0x2e, 0xd9, 0xcc, 0x72, 0x0c, 0x16, 0xbf, 0xe8, 0x81, - 0xe4, 0xdf, 0x42, 0x55, 0xe8, 0x7a, 0xfb, 0x7f, 0xc6, 0x2f, 0x38, 0x11, 0x6b, 0xbe, - 0x03, 0xcd, 0x8a, 0x3c, 0xb1, 0x1a, 0x27, 0xd5, 0x68, 0x41, 0x47, 0x82, 0xf4, 0x7b, - 0x1a, 0x44, 0xc9, 0x7c, 0x68, 0x04, 0x67, 0x69, 0x4b, 0xc9, 0x70, 0x9d, 0x32, 0x91, - 0x6c, 0x97, 0xe8, 0x00, 0x6c, 0xbb, 0x07, 0xba, 0x0e, 0x41, 0x80, 0xa3, 0x73, 0x80, - 0x38, 0xc3, 0x74, 0xc4, 0xcc, 0xe8, 0xf3, 0x29, 0x59, 0xaf, 0xb2, 0x5f, 0x30, 0x3f, - 0x58, 0x15, 0xc4, 0x53, 0x31, 0x24, 0xac, 0xf9, 0xd1, 0x89, 0x40, 0xe7, 0x75, 0x22, - 0xac, 0x5d, 0xc4, 0xb9, 0x57, 0x0a, 0xae, 0x8f, 0x47, 0xb7, 0xf5, 0x7f, 0xd8, 0x76, - 0x7b, 0xea, 0x1a, 0x24, 0xae, 0x7b, 0xed, 0x65, 0xb4, 0xaf, 0xdc, 0x8f, 0x12, 0x78, - 0xc3, 0x0e, 0x2d, 0xb9, 0x8f, 0xd1, 0x72, 0x73, 0x0a, 0xc6, 0xbb, 0xed, 0x4f, 0x11, - 0x27, 0xcd, 0x32, 0xb0, 0x4a, 0x95, 0xb2, 0x05, 0x52, 0x6c, 0xfc, 0xb4, 0xc4, 0xe1, - 0xcc, 0x95, 0x51, 0x75, 0xb3, 0xe8, 0xde, 0x1f, 0x5d, 0x81, 0xb1, 0x86, 0x69, 0x69, - 0x23, 0x50, 0xaa, 0xa1, 0xa1, 0xd7, 0x97, 0x61, 0x75, 0x82, 0xe5, 0x4d, 0x7a, 0x5b, - 0x57, 0xa6, 0x83, 0xb3, 0x2f, 0xb1, 0x09, 0x80, 0x62, 0xda, 0xd7, 0xb0, 0xc2, 0xeb, - 0x51, 0x8f, 0x68, 0x62, 0xe8, 0x3d, 0xb2, 0x5e, 0x3d, 0xba, 0xf7, 0xae, 0xd5, 0x04, - 0xde, 0x93, 0x2a, 0xcb, 0x99, 0xd7, 0x35, 0x99, 0x2c, 0xe6, 0x2b, 0xae, 0x9e, 0xf8, - 0x93, 0xff, 0x6a, 0xcc, 0x0f, 0xfc, 0xf8, 0xe3, 0x48, 0x3e, 0x14, 0x6b, 0x9d, 0x49, - 0xdd, 0x8c, 0x78, 0x35, 0xf4, 0x3a, 0x37, 0xdc, 0xa0, 0x78, 0x7e, 0x3e, 0xc9, 0xf6, - 0x60, 0x52, 0x23, 0xd5, 0xba, 0x7a, 0xe0, 0xab, 0x90, 0x25, 0xb7, 0x3b, 0xc0, 0x3f, - 0x7f, 0xac, 0x36, 0xc0, 0x09, 0xa5, 0x6d, 0x4d, 0x95, 0xd1, 0xe8, 0x1d, 0x3b, 0x3e, - 0xbc, 0xa7, 0xe5, 0x4c, 0xc1, 0xa1, 0x2d, 0x12, 0x7b, 0x57, 0xc8, 0x13, 0x89, 0x76, - 0xe7, 0x91, 0x01, 0x3b, 0x01, 0x5f, 0x06, 0xa6, 0x24, 0xf5, 0x21, 0xb6, 0xee, 0x04, - 0xec, 0x98, 0x08, 0x93, 0xc7, 0xe5, 0xe0, 0x1a, 0x33, 0x62, 0x03, 0x59, 0x40, 0x94, - 0xf8, 0x28, 0x33, 0xd7, 0x44, 0x27, 0x88, 0x00, 0x84, 0xd3, 0x58, 0x63, 0xc8, 0xe7, - 0xeb, 0xb5, 0xc9, 0xee, 0xd9, 0x8e, 0x72, 0x57, 0x2e, 0xc4, 0x0c, 0x79, 0xb2, 0x66, - 0x23, 0xb5, 0x80, 0x22, 0xf4, 0x89, 0xb0, 0x89, 0x3d, 0x88, 0xbe, 0x63, 0xf3, 0xf8, - 0xc0, 0xd2, 0x32, 0x49, 0xeb, 0xcd, 0xe1, 0x3d, 0xb9, 0x31, 0x29, 0x41, 0xc3, 0x6c, - 0x1d, 0x1c, 0xbc, 0xab, 0xac, 0x0c, 0x78, 0xcb, 0x3b, 0x19, 0x12, 0xdb, 0x0d, 0xcb, - 0xfe, 0x18, 0x93, 0xd9, 0xb5, 0x1b, 0xe4, 0xaf, 0x1d, 0x00, 0x0b, 0xac, 0x1a, 0xd0, - 0xa3, 0xae, 0x2c, 0xe1, 0xe7, 0x32, 0x25, 0xfb, 0x11, 0x4d, 0x05, 0xaf, 0x4c, 0xef, - 0xc0, 0x6e, 0x87, 0x5f, 0x07, 0x4f, 0xfe, 0xae, 0x0c, 0xba, 0x7d, 0xa3, 0xa5, 0x16, - 0xc1, 0x73, 0xbe, 0x1c, 0x51, 0x33, 0x23, 0xe1, 0x19, 0xf6, 0x35, 0xe8, 0x20, 0x9a, - 0x07, 0x4b, 0x21, 0x6b, 0x70, 0x23, 0xfa, 0xdc, 0x2d, 0x25, 0x94, 0x9c, 0x90, 0x03, - 0x7e, 0x71, 0xe3, 0xe5, 0x50, 0x72, 0x6d, 0x21, 0x0a, 0x2c, 0x68, 0x83, 0x42, 0xe5, - 0x24, 0x40, 0x63, 0x5e, 0x9c, 0xc1, 0x4a, 0xfe, 0x10, 0x10, 0x26, 0x21, 0xa9, 0xc9, - 0xac, 0xcb, 0x78, 0x2e, 0x9e, 0x4a, 0x5f, 0xa8, 0x7f, 0x0a, 0x95, 0x6f, 0x5b, 0x85, - 0x50, 0x99, 0x60, 0x28, 0x5c, 0x22, 0x62, 0x7c, 0x59, 0x48, 0x3a, 0x5a, 0x4c, 0x28, - 0xcc, 0xe4, 0xb1, 0x56, 0xe5, 0x51, 0x40, 0x6a, 0x7e, 0xe8, 0x35, 0x56, 0x56, 0xa2, - 0x1e, 0x43, 0xe3, 0x8c, 0xe1, 0x29, 0xfd, 0xad, 0xb7, 0x59, 0xed, 0xdf, 0xa0, 0x8f, - 0x00, 0xfc, 0x8e, 0x56, 0x7c, 0xef, 0x93, 0xc6, 0x79, 0x2d, 0x01, 0xdf, 0x05, 0xe6, - 0xd5, 0x80, 0xf4, 0xd5, 0xd4, 0x8d, 0xf0, 0x42, 0x45, 0x1a, 0x33, 0x59, 0x0d, 0x3e, - 0x8c, 0xf4, 0x9b, 0x26, 0x27, 0x21, 0x8f, 0x0c, 0x29, 0x2f, 0xa6, 0x6a, 0xda, 0x94, - 0x5f, 0xa5, 0x5b, 0xb2, 0x35, 0x48, 0xe3, 0x3a, 0x83, 0xa5, 0x62, 0x95, 0x7a, 0x31, - 0x49, 0xa9, 0x93, 0xcc, 0x47, 0x23, 0x62, 0x29, 0x87, 0x36, 0xa8, 0xb7, 0x78, 0xd9, - 0x7c, 0xe4, 0x23, 0x01, 0x3d, 0x64, 0xb3, 0x2c, 0xd1, 0x72, 0xef, 0xa5, 0x51, 0xbf, - 0x7f, 0x36, 0x8f, 0x04, 0xbd, 0xae, 0xc6, 0x09, 0x1a, 0x30, 0x04, 0xa7, 0x57, 0x59, - 0x8b, 0x80, 0x1d, 0xcf, 0x67, 0x5c, 0xb8, 0x3e, 0x43, 0xa5, 0x3a, 0xe8, 0xb2, 0x54, - 0xd3, 0x33, 0xbc, 0xda, 0x20, 0xd4, 0x81, 0x7d, 0x34, 0x77, 0xab, 0xfb, 0xa2, 0x5b, - 0xb8, 0x3d, 0xf5, 0x94, 0x9c, 0x12, 0x6f, 0x14, 0x9b, 0x1d, 0x99, 0x34, 0x1e, 0x4e, - 0x6f, 0x91, 0x20, 0xf4, 0xd4, 0x1e, 0x62, 0x91, 0x85, 0x00, 0x2c, 0x72, 0xc0, 0x12, - 0xc4, 0x14, 0xd2, 0x38, 0x2a, 0x6d, 0x47, 0xc7, 0xb3, 0xde, 0xab, 0xa7, 0x70, 0xc4, - 0x00, 0xca, 0x96, 0xb2, 0x81, 0x4f, 0x6b, 0x26, 0xc3, 0xef, 0x17, 0x42, 0x9f, 0x1a, - 0x98, 0xc8, 0x5d, 0x83, 0xdb, 0x20, 0xef, 0xad, 0x48, 0xbe, 0x89, 0x96, 0xfb, 0x1b, - 0xff, 0x59, 0x1e, 0xff, 0xf3, 0x60, 0xfe, 0x11, 0x99, 0x05, 0x6c, 0x56, 0xe5, 0xfe, - 0xec, 0x61, 0xa7, 0xb8, 0xb9, 0xf6, 0x99, 0xd6, 0x01, 0x2c, 0x28, 0x49, 0x23, 0x2f, - 0x32, 0x9f, 0xef, 0x95, 0xc7, 0xaf, 0x37, 0x00, 0x98, 0xff, 0xe4, 0x91, 0x8e, 0x0c, - 0xa1, 0xdf, 0x47, 0xf2, 0x75, 0x86, 0x7b, 0x73, 0x9e, 0x0a, 0x51, 0x4d, 0x32, 0x09, - 0x32, 0x5e, 0x21, 0x70, 0x45, 0x92, 0x7b, 0x47, 0x9c, 0x1c, 0xe2, 0xe5, 0xd5, 0x4f, - 0x25, 0x48, 0x8c, 0xad, 0x15, 0x13, 0xe3, 0xf4, 0x4a, 0x21, 0x26, 0x6c, 0xfd, 0x84, - 0x16, 0x33, 0x32, 0x7d, 0xee, 0x6c, 0xf8, 0x10, 0xfb, 0xf7, 0x39, 0x3e, 0x31, 0x7d, - 0x9e, 0x53, 0xd1, 0xbe, 0x1d, 0x5a, 0xe7, 0x83, 0x9b, 0x66, 0xb9, 0x43, 0xb9, 0xed, - 0x18, 0xf2, 0xc5, 0x30, 0xe9, 0x75, 0x42, 0x23, 0x32, 0xc3, 0x43, 0x9c, 0xce, 0x49, - 0xa2, 0x9f, 0x2a, 0x33, 0x6a, 0x48, 0x51, 0x26, 0x3c, 0x5e, 0x9b, 0xd1, 0x3d, 0x73, - 0x11, 0x09, 0xe8, 0x44, 0xb7, 0xf8, 0xc3, 0x92, 0xa5, 0xc1, 0xdc, 0xaa, 0x2a, 0xe5, - 0xf5, 0x0f, 0xf6, 0x3f, 0xab, 0x97, 0x65, 0xe0, 0x16, 0x70, 0x2c, 0x35, 0xa6, 0x7c, - 0xd7, 0x36, 0x4d, 0x3f, 0xab, 0x55, 0x2f, 0xb3, 0x49, 0xe3, 0x5c, 0x15, 0xc5, 0x02, - 0x50, 0x45, 0x3f, 0xd1, 0x8f, 0x7b, 0x85, 0x59, 0x92, 0x63, 0x2e, 0x2c, 0x76, 0xc0, - 0xfb, 0xf1, 0xef, 0x96, 0x3e, 0xa8, 0x0e, 0x32, 0x23, 0xde, 0x32, 0x77, 0xbc, 0x55, - 0x92, 0x51, 0x72, 0x58, 0x29, 0xec, 0x03, 0xf2, 0x13, 0xba, 0x89, 0x55, 0xca, 0xb2, - 0x82, 0x2f, 0xf2, 0x1a, 0x9b, 0x0a, 0x49, 0x04, 0xd6, 0x68, 0xfc, 0xd7, 0x72, 0x24, - 0xbd, 0xe3, 0xdd, 0x01, 0xf6, 0xff, 0xc4, 0x82, 0x8f, 0x6b, 0x64, 0x23, 0x0b, 0x35, - 0xc6, 0xa0, 0x49, 0x87, 0x34, 0x94, 0x27, 0x6e, 0xa1, 0xd7, 0xed, 0x5e, 0x92, 0xcb, - 0x4f, 0x90, 0xba, 0x83, 0xa9, 0xe4, 0x96, 0x01, 0xb1, 0x94, 0x04, 0x2f, 0x29, 0x00, - 0xd9, 0x9d, 0x31, 0x2d, 0x7b, 0x70, 0x50, 0x8c, 0xf1, 0x76, 0x06, 0x6d, 0x15, 0x4d, - 0xbe, 0x96, 0xef, 0x9d, 0x43, 0x67, 0xe4, 0xc8, 0x40, 0xe4, 0xa1, 0x7b, 0x5e, 0x51, - 0x22, 0xe8, 0xeb, 0xe2, 0x15, 0x8a, 0x3c, 0x5f, 0x4c, 0xba, 0xe2, 0x1e, 0xa3, 0xfa, - 0x1a, 0xe6, 0xc2, 0x5a, 0x94, 0x62, 0xeb, 0xcb, 0xb0, 0xfd, 0x5f, 0x14, 0x55, 0x4b, - 0xc9, 0x77, 0x47, 0xc3, 0x3e, 0x34, 0xda, 0x90, 0xc8, 0x16, 0xd8, 0xd0, 0xd5, 0x0b, - 0xfe, 0x37, 0x61, 0x8c, 0x58, 0x12, 0x89, 0x14, 0x84, 0xfa, 0x25, 0x93, 0x22, 0xc1, - 0x50, 0x92, 0xd4, 0x15, 0x5d, 0x86, 0x96, 0xd6, 0xf1, 0x2f, 0x24, 0xfd, 0x36, 0x44, - 0x96, 0xb3, 0xbe, 0x08, 0x71, 0xca, 0x3d, 0xd9, 0x62, 0x53, 0x48, 0xa6, 0x14, 0xb5, - 0x9b, 0xde, 0x45, 0x88, 0x56, 0x49, 0xba, 0xe3, 0x6d, 0xe3, 0x4d, 0xef, 0x8f, 0xce, - 0xc8, 0x53, 0x43, 0x47, 0x5d, 0x97, 0x6a, 0xe1, 0xe9, 0xb2, 0x78, 0x29, 0xce, 0x2a, - 0xc5, 0xef, 0xd0, 0xb3, 0x99, 0xa8, 0xb4, 0x48, 0xbe, 0x65, 0x04, 0x29, 0x4e, 0xe6, - 0xb3, 0xc1, 0xc6, 0xa5, 0x34, 0x2d, 0x7c, 0x01, 0xae, 0x9d, 0x8a, 0xd3, 0x07, 0x0c, - 0x2b, 0x1a, 0x91, 0x57, 0x3a, 0xf5, 0xe0, 0xc5, 0xe4, 0xcb, 0xbf, 0x4a, 0xcd, 0xc6, - 0xb5, 0x4c, 0x92, 0x72, 0x20, 0x0d, 0x99, 0x70, 0x25, 0x0c, 0x17, 0xc1, 0x03, 0x6f, - 0x06, 0x08, 0x5c, 0x41, 0x85, 0x8e, 0xd3, 0xa0, 0xc4, 0x81, 0x50, 0xbc, 0x69, 0x7e, - 0x4a, 0x69, 0x5f, 0xef, 0x33, 0x5f, 0x7a, 0xd0, 0x7e, 0x1a, 0x46, 0xdc, 0x76, 0x7f, - 0xf8, 0x22, 0xdb, 0x70, 0xe6, 0x66, 0x90, 0x80, 0xb9, 0x81, 0x6b, 0x22, 0x32, 0xc8, - 0x1a, 0x4c, 0x66, 0xcc, 0x58, 0x6a, 0xbf, 0xe1, 0xea, 0xa8, 0xca, 0x6c, 0xf4, 0x1f, - 0xc3, 0x0e, 0xb8, 0xdc, 0x57, 0xc3, 0x7a, 0x3c, 0x39, 0xc5, 0x9c, 0x94, 0x23, 0x2d, - 0xf9, 0xd3, 0x88, 0xdb, 0xfa, 0x35, 0xc2, 0xcd, 0x5c, 0x75, 0xf3, 0x28, 0xe9, 0xfe, - 0xa7, 0x8f, 0x65, 0x56, 0x8f, 0x2b, 0xb9, 0x34, 0xc8, 0x2c, 0x41, 0x42, 0xda, 0x69, - 0xd1, 0x2c, 0xa7, 0xde, 0x9a, 0x7d, 0xf7, 0x06, 0x40, 0x0e, 0xc7, 0x98, 0x78, 0xd8, - 0x68, 0xe1, 0x7e, 0x8f, 0x71, 0xea, 0x31, 0x49, 0x5a, 0x8b, 0xae, 0x7b, 0xdc, 0x2e, - 0x48, 0xb5, 0x11, 0x87, 0x71, 0xc2, 0xfc, 0xa0, 0x78, 0xcc, 0xa1, 0xfc, 0xe0, 0xd7, - 0xef, 0x0a, 0xf3, 0x47, 0x8c, 0xf3, 0x6f, 0x69, 0xe8, 0x5a, 0x41, 0xdd, 0x29, 0xb4, - 0x29, 0x4a, 0x65, 0xd3, 0xe0, 0x55, 0xff, 0x71, 0x8d, 0xd9, 0xdc, 0x8c, 0x75, 0xe7, - 0xe5, 0xb2, 0xef, 0xe4, 0x42, 0x63, 0x73, 0x71, 0xb7, 0xc4, 0x8f, 0x6e, 0xe9, 0x9e, - 0x3e, 0xa3, 0x8a, 0x4b, 0x0f, 0x2f, 0x67, 0xfc, 0x2b, 0x90, 0x8c, 0xda, 0x65, 0x7e, - 0xae, 0x75, 0x4e, 0x03, 0x7e, 0x26, 0x2e, 0x9a, 0x9f, 0x9b, 0xd7, 0xec, 0x42, 0x67, - 0xed, 0x8e, 0x96, 0x93, 0x0e, 0x10, 0x84, 0x78, 0x3c, 0x37, 0xd6, 0xf9, 0xdd, 0x15, - 0xfd, 0x29, 0xf4, 0xcc, 0x47, 0x7e, 0x66, 0xf1, 0x30, 0xd6, 0x30, 0x43, 0x0d, 0xcc, - 0x01, 0x04, 0x89, 0x9b, 0x4f, 0x9f, 0x46, 0xeb, 0x09, 0x0e, 0xf7, 0xfc, 0x90, 0xb4, - 0x79, 0xab, 0xf6, 0x1f, 0x93, 0x95, 0x5e, 0xe0, 0x0e, 0x6a, 0x18, 0x48, 0xf1, 0xab, - 0x14, 0xad, 0x33, 0x4f, 0x2b, 0x68, 0x03, 0x58, 0x08, 0xcd, 0xf1, 0xbb, 0x9e, 0x9d, - 0x9a, 0x81, 0x6b, 0xaf, 0x72, 0x8a, 0x95, 0x5b, 0x96, 0x0b, 0x77, 0x01, 0xfa, 0x62, - 0x66, 0x87, 0xdc, 0x3c, 0x9c, 0xba, 0x64, 0x63, 0x37, 0xb5, 0x3e, 0x29, 0x81, 0x6e, - 0x94, 0x82, 0xdd, 0xf5, 0x57, 0x8a, 0x87, 0x68, 0xaa, 0xe4, 0x77, 0xfc, 0xe4, 0x10, - 0xac, 0x2d, 0x5d, 0xe6, 0x09, 0x58, 0x61, 0xc1, 0x11, 0xd7, 0xfe, 0xb3, 0xe6, 0xbb, - 0x4f, 0xbb, 0x5a, 0x54, 0x95, 0x54, 0x95, 0x97, 0x27, 0x98, 0x35, 0x0a, 0x25, 0x3f, - 0x05, 0xf6, 0x6c, 0x2e, 0xcf, 0xcb, 0xc0, 0xed, 0x43, 0xf5, 0xec, 0x2e, 0x6d, 0x8d, - 0xba, 0x15, 0xa5, 0x12, 0x54, 0xd9, 0x7b, 0x18, 0x21, 0x10, 0x7c, 0x07, 0xdd, 0x9a, - 0x16, 0xef, 0x84, 0x06, 0xf9, 0x43, 0xe2, 0x82, 0xb9, 0x5d, 0x4b, 0x36, 0x25, 0x30, - 0xc9, 0x13, 0xd6, 0xba, 0x42, 0x1d, 0xf6, 0x02, 0x7d, 0xe5, 0xaf, 0x1e, 0x47, 0x45, - 0xd5, 0x86, 0x81, 0x06, 0x95, 0x4b, 0xe6, 0xc1, 0x96, 0x27, 0x80, 0xa2, 0x94, 0x10, - 0x72, 0xe9, 0x51, 0x31, 0xb1, 0x67, 0x9d, 0xf0, 0x63, 0x76, 0x25, 0x04, 0x2c, 0x37, - 0xd4, 0x8f, 0xfb, 0x15, 0x2e, 0x5e, 0xbc, 0x18, 0x5c, 0x8a, 0x2b, 0x7d, 0x43, 0x85, - 0xf1, 0xc9, 0x5a, 0xf9, 0x37, 0xdf, 0x78, 0xdf, 0xd8, 0x75, 0x7f, 0xab, 0x43, 0x49, - 0x68, 0xb0, 0xb5, 0x7c, 0x66, 0x57, 0x44, 0x68, 0xf1, 0x60, 0xb4, 0x47, 0xac, 0x82, - 0x21, 0xe5, 0x06, 0x06, 0x76, 0xa8, 0x42, 0xa1, 0xc6, 0xb7, 0x17, 0x2d, 0xd3, 0x34, - 0x0f, 0x76, 0x40, 0x70, 0xab, 0x1f, 0xe0, 0x91, 0xc5, 0xc7, 0x4c, 0x95, 0xa5, 0xdc, - 0x04, 0x33, 0x90, 0x72, 0x3a, 0x4c, 0x12, 0x7d, 0xa1, 0x4c, 0xdd, 0xe1, 0xdc, 0x26, - 0x75, 0xa6, 0x23, 0x40, 0xb3, 0xe6, 0xaf, 0xd0, 0x52, 0x2a, 0x31, 0xde, 0x26, 0xe7, - 0xd1, 0xec, 0x3a, 0x9c, 0x8a, 0x09, 0x1f, 0xfd, 0xc7, 0x5b, 0x7e, 0xcf, 0xdc, 0x7c, - 0x12, 0x99, 0x5a, 0x5e, 0x37, 0xce, 0x34, 0x88, 0xbd, 0x29, 0xf8, 0x62, 0x9d, 0x68, - 0xf6, 0x96, 0x49, 0x24, 0x48, 0xdd, 0x52, 0x66, 0x97, 0x47, 0x6d, 0xc0, 0x61, 0x34, - 0x6e, 0xbe, 0x3f, 0x67, 0x72, 0x17, 0xff, 0x9c, 0x60, 0xef, 0xce, 0x94, 0x3a, 0xf2, - 0x8d, 0xfd, 0x3f, 0x9e, 0x59, 0x69, 0x25, 0x98, 0xa6, 0x04, 0x7c, 0x23, 0xc4, 0xc0, - 0x14, 0x00, 0xf1, 0xab, 0x57, 0x30, 0xea, 0xc0, 0xae, 0x8d, 0x58, 0x43, 0xd5, 0x05, - 0x1c, 0x37, 0x62, 0x40, 0x17, 0x2a, 0xf2, 0x18, 0xd7, 0xa1, 0xec, 0xfe, 0x65, 0xb4, - 0xf7, 0x51, 0x00, 0x63, 0x89, 0x83, 0xc1, 0x4d, 0xe4, 0x97, 0x47, 0x55, 0xda, 0xde, - 0x80, 0x18, 0xc9, 0xb8, 0xf4, 0x54, 0x3f, 0xb0, 0x95, 0x96, 0x15, 0x13, 0xe6, 0x7c, - 0x61, 0xdb, 0xc5, 0x9c, 0x60, 0x7f, 0x9b, 0x51, 0xf8, 0xd0, 0x9b, 0xdc, 0xad, 0x28, - 0xbc, 0xfb, 0x9e, 0x5d, 0x27, 0x44, 0xea, 0x88, 0x48, 0xb2, 0x62, 0x3a, 0xc0, 0x7f, - 0x8e, 0xf6, 0x1a, 0x81, 0xa3, 0x59, 0x10, 0xb8, 0xa1, 0xba, 0xf3, 0x9a, 0x91, 0x9a, - 0x7b, 0x60, 0xbc, 0x60, 0x4d, 0x63, 0x18, 0x5f, 0x75, 0x92, 0x21, 0xd8, 0x47, 0xcc, - 0x54, 0xa2, 0x27, 0x65, 0xa4, 0xc3, 0x34, 0x75, 0xb5, 0x79, 0x1e, 0x9a, 0xf3, 0x27, - 0x1f, 0xc8, 0xd9, 0x35, 0x06, 0x67, 0x09, 0x0d, 0x81, 0x84, 0xec, 0x50, 0x52, 0x2d, - 0x80, 0x4f, 0x23, 0xc4, 0xfb, 0x44, 0xff, 0xa4, 0x81, 0xbc, 0x92, 0xae, 0x40, 0x8d, - 0x1b, 0x9f, 0x2b, 0x13, 0x19, 0x04, 0xf9, 0x70, 0x5c, 0x59, 0xe2, 0xf4, 0xbd, 0xe7, - 0xa3, 0xb2, 0xc0, 0x85, 0xd9, 0x3f, 0xd2, 0xab, 0xc5, 0xe1, 0x4d, 0x16, 0x30, 0x01, - 0xa1, 0x2f, 0x51, 0x93, 0x8d, 0x02, 0x1a, 0xfa, 0x92, 0x23, 0x9b, 0x87, 0x3d, 0xc6, - 0xc3, 0x57, 0xea, 0xa8, 0xaf, 0x4e, 0xe6, 0xd0, 0x05, 0x40, 0x65, 0x7f, 0xe3, 0x29, - 0x14, 0x10, 0x3b, 0x5d, 0x98, 0xf6, 0x8b, 0xd3, 0xe2, 0xb5, 0x35, 0x9f, 0x08, 0xcc, - 0xd8, 0x8d, 0x0c, 0x81, 0x1e, 0x4c, 0x31, 0xfb, 0xb4, 0x9f, 0x3a, 0x90, 0xbb, 0xd0, - 0x5d, 0xce, 0x62, 0xf3, 0x44, 0xe7, 0x07, 0x75, 0x93, 0x15, 0x9a, 0xe3, 0x50, 0x50, - 0xb0, 0x4c, 0x9e, 0x6b, 0x86, 0xbc, 0x43, 0x2d, 0xc8, 0xb0, 0x48, 0xc7, 0x3c, 0x00, - 0x18, 0xca, 0x5b, 0x69, 0x41, 0x12, 0x97, 0x73, 0x2a, 0x4e, 0x1a, 0xa9, 0x9a, 0x92, - 0x8c, 0x71, 0xe7, 0xa2, 0x4f, 0xd2, 0x77, 0x85, 0x6a, 0xa4, 0x25, 0x01, 0xe5, 0x1b, - 0x01, 0x2a, 0xea, 0x94, 0x46, 0xa2, 0x10, 0x4e, 0x93, 0xf8, 0x15, 0xa0, 0xb3, 0xa2, - 0x9b, 0x45, 0x83, 0x14, 0xf3, 0xd8, 0xbe, 0x2b, 0x98, 0x23, 0xd3, 0x42, 0xf4, 0x62, - 0x13, 0xe9, 0x42, 0xa7, 0xe1, 0x9a, 0x46, 0xe9, 0x70, 0xb5, 0xc5, 0x06, 0x70, 0x84, - 0x30, 0x31, 0x7b, 0x1b, 0xb3, 0xb3, 0x5d, 0xf6, 0x8a, 0xe3, 0x3a, 0x49, 0x26, 0xa0, - 0x3e, 0x6b, 0xfe, 0xb5, 0x51, 0x04, 0x16, 0xfc, 0xbb, 0x05, 0x24, 0xc9, 0xca, 0x50, - 0x74, 0x15, 0x6c, 0xc5, 0xa5, 0xd6, 0xfe, 0x1c, 0x99, 0x5e, 0xdc, 0x60, 0xa2, 0xf5, - 0x50, 0x41, 0x1a, 0xa4, 0x1e, 0x3d, 0xa3, 0xbd, 0xcf, 0x64, 0xbc, 0xf0, 0x4a, 0x05, - 0x10, 0x57, 0x1b, 0x93, 0x6d, 0x47, 0xe5, 0x5c, 0xec, 0x03, 0x30, 0x00, 0x8d, 0xfe, - 0x73, 0x56, 0x34, 0x04, 0xf0, 0x47, 0xd7, 0xf3, 0xa8, 0xa3, 0xd7, 0x74, 0x3b, 0xc5, - 0x54, 0x95, 0x52, 0x10, 0xf1, 0xeb, 0x0d, 0x08, 0x59, 0x9e, 0xa7, 0x7d, 0x5f, 0x97, - 0x4d, 0x87, 0x17, 0x6d, 0x37, 0xd9, 0x8b, 0x9c, 0x0a, 0xd4, 0x40, 0x40, 0x72, 0x09, - 0xed, 0x6a, 0x9f, 0x08, 0x46, 0x4d, 0x56, 0x55, 0x93, 0xe1, 0xa6, 0x3b, 0x93, 0x85, - 0x36, 0xb4, 0x92, 0x44, 0xe9, 0x7d, - ], - script_code: vec![], - transparent_input: Some(1), - hash_type: 2, - amount: 652655344020909, - consensus_branch_id: 1991772603, - sighash: [ - 0xbb, 0xe6, 0xd8, 0x4f, 0x57, 0xc5, 0x6b, 0x29, 0xb9, 0x14, 0xc6, 0x94, 0xba, 0xac, - 0xcb, 0x89, 0x12, 0x97, 0xe9, 0x61, 0xde, 0x3e, 0xb4, 0x6c, 0x68, 0xe3, 0xc8, 0x9c, - 0x47, 0xb1, 0xa1, 0xdb, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x01, 0x46, 0xcf, 0x28, 0x9b, 0x7d, - 0x89, 0x13, 0x07, 0xbb, 0xa3, 0x70, 0x54, 0xcf, 0x91, 0xb3, 0x1f, 0xc8, 0x2f, 0x74, - 0xd5, 0xfc, 0xc0, 0x00, 0x94, 0x2e, 0xde, 0x91, 0x18, 0x25, 0xf5, 0x3f, 0xe6, 0x09, - 0x68, 0x6f, 0x46, 0x00, 0x23, 0xb1, 0xe9, 0xbc, 0x00, 0xbd, 0xe8, 0x95, 0xd1, 0x23, - 0x8f, 0xad, 0x04, 0xab, 0xa9, 0x88, 0x99, 0x66, 0x7d, 0x01, 0x00, 0x04, 0xea, 0x42, - 0x71, 0x76, 0x09, 0x84, 0x13, 0x90, 0x59, 0x18, 0xee, 0x21, 0x3d, 0x4e, 0xc1, 0x27, - 0x94, 0x74, 0x2d, 0x19, 0xf6, 0x7d, 0x6f, 0x86, 0xce, 0xf7, 0xe6, 0x98, 0x2e, 0x88, - 0x41, 0x71, 0x28, 0x73, 0xa0, 0x1d, 0x92, 0x51, 0xd8, 0xc8, 0x60, 0xc0, 0x41, 0x52, - 0x5b, 0x3b, 0xf4, 0xe3, 0xa2, 0xeb, 0x92, 0x72, 0x81, 0x5c, 0x75, 0x86, 0x76, 0x84, - 0x28, 0xb4, 0xc2, 0xb2, 0x5e, 0x37, 0x45, 0xf0, 0x09, 0xc5, 0xdc, 0xe2, 0x0b, 0x69, - 0xd5, 0xd7, 0xc4, 0x3c, 0xeb, 0x73, 0x6b, 0x68, 0x31, 0xe8, 0xc1, 0x10, 0xf1, 0x6c, - 0xfd, 0xb3, 0xa4, 0x67, 0xe9, 0x41, 0x4c, 0x00, 0xec, 0xf1, 0x37, 0x31, 0x50, 0x08, - 0x94, 0x55, 0x56, 0x78, 0xc4, 0x97, 0xfa, 0xba, 0x9a, 0x95, 0xd0, 0x1c, 0xc4, 0x64, - 0x39, 0x0f, 0xc4, 0xa7, 0x6b, 0xfa, 0x8b, 0x0e, 0x1c, 0x68, 0xa5, 0x25, 0xd7, 0x06, - 0xd6, 0x60, 0x4b, 0x23, 0x30, 0xb6, 0xb3, 0x48, 0x52, 0x15, 0xf6, 0x06, 0xf1, 0x88, - 0x3a, 0x75, 0x15, 0x88, 0xc7, 0xef, 0xa5, 0x06, 0xc3, 0xe8, 0xd0, 0xc6, 0x01, 0x92, - 0xe8, 0x47, 0x6b, 0xd1, 0x17, 0x5d, 0x95, 0x62, 0x08, 0x7b, 0xdb, 0x81, 0x8e, 0x66, - 0x21, 0x62, 0x86, 0xba, 0xfe, 0x47, 0xff, 0x4d, 0xbc, 0xce, 0xd5, 0x14, 0x44, 0x48, - 0x0a, 0x9a, 0x56, 0x73, 0xec, 0xe7, 0xfa, 0xc7, 0x3a, 0x0e, 0xd4, 0x1a, 0xb0, 0x05, - 0x17, 0x53, 0xa7, 0xca, 0xa8, 0x9b, 0xe3, 0x13, 0x9a, 0xfd, 0x97, 0x93, 0xb3, 0xe0, - 0x2f, 0x27, 0xf0, 0x40, 0x04, 0x65, 0x95, 0xac, 0xd4, 0x7b, 0xf1, 0x3f, 0xd0, 0xda, - 0x27, 0xf0, 0x9e, 0xda, 0x48, 0x03, 0x6d, 0x3e, 0xe4, 0x37, 0xf2, 0xee, 0x8f, 0x86, - 0x06, 0xea, 0x97, 0x34, 0x3c, 0x33, 0x58, 0x46, 0x57, 0xf4, 0x6d, 0xba, 0x99, 0xdb, - 0x5c, 0xfe, 0x6c, 0xa1, 0x76, 0xfa, 0xb7, 0xb0, 0xf3, 0xbf, 0xa0, 0xab, 0x61, 0xe3, - 0x40, 0xc3, 0x4e, 0xb9, 0xf1, 0x7c, 0x7e, 0xc2, 0xbe, 0x03, 0xb1, 0x80, 0xf0, 0xbb, - 0x6f, 0x43, 0x4c, 0x2a, 0x65, 0x42, 0xe0, 0x0e, 0x84, 0x37, 0x3f, 0x4f, 0x46, 0x49, - 0xcd, 0xa3, 0x2b, 0xf6, 0x86, 0x66, 0x61, 0x43, 0xf6, 0x22, 0xaa, 0x48, 0x04, 0x60, - 0xb5, 0xaf, 0xac, 0x51, 0x86, 0x07, 0xcd, 0x9a, 0xf8, 0xbc, 0xd6, 0xb5, 0x8c, 0x30, - 0x12, 0x73, 0x16, 0xb2, 0x5d, 0x5e, 0xa7, 0xbf, 0x6b, 0x0c, 0xab, 0x85, 0x42, 0xff, - 0x69, 0xd9, 0xb2, 0xf1, 0x80, 0xbe, 0x12, 0xed, 0x75, 0x34, 0x4a, 0x39, 0x5a, 0xa1, - 0x0f, 0x85, 0x2f, 0x08, 0x3a, 0xd6, 0x4e, 0xf4, 0x0e, 0x9c, 0x03, 0x09, 0xe9, 0xbb, - 0xa5, 0x4b, 0x8c, 0xb3, 0x3c, 0x95, 0x49, 0x8a, 0x69, 0x53, 0x8d, 0x3a, 0xe5, 0xb2, - 0x5e, 0x24, 0x70, 0x98, 0xe1, 0x11, 0x7c, 0x91, 0x8a, 0xaa, 0xae, 0x9c, 0xb6, 0xef, - 0x77, 0xab, 0xd1, 0xe0, 0x1c, 0xc7, 0x43, 0xd0, 0xdd, 0xd0, 0x22, 0x75, 0x95, 0x1b, - 0x92, 0x49, 0x95, 0x65, 0xce, 0x83, 0x1f, 0x30, 0x32, 0xb8, 0x50, 0x57, 0x75, 0x10, - 0x8d, 0xc8, 0x5e, 0x2a, 0xde, 0x2e, 0xac, 0x1e, 0x63, 0x6e, 0x1a, 0xf4, 0x05, 0x4c, - 0x8b, 0x6f, 0x57, 0x63, 0x2d, 0xf2, 0x69, 0xc3, 0x72, 0x3b, 0x32, 0x08, 0x72, 0xe4, - 0xc5, 0x7b, 0x21, 0x83, 0x58, 0xdc, 0x7e, 0x99, 0x05, 0xbb, 0x04, 0xed, 0xf9, 0x2e, - 0xdf, 0x0d, 0xf6, 0x35, 0xf3, 0xbf, 0x36, 0x1e, 0x57, 0xa1, 0x32, 0x96, 0xe1, 0x44, - 0x7a, 0xf5, 0xa5, 0x66, 0x65, 0x17, 0xbc, 0xd3, 0x56, 0x76, 0x21, 0xa7, 0xcf, 0x84, - 0x45, 0x58, 0x96, 0x53, 0x26, 0x20, 0x20, 0xc3, 0x3b, 0xf7, 0x80, 0x31, 0xb8, 0xee, - 0x07, 0x07, 0xde, 0x07, 0x20, 0x68, 0xc1, 0x70, 0x57, 0x03, 0x27, 0xe6, 0xd9, 0xf5, - 0xc6, 0xdd, 0xc3, 0x35, 0x40, 0x2e, 0xfc, 0x54, 0x88, 0x62, 0xf5, 0xa0, 0x70, 0x94, - 0xfd, 0x42, 0x8a, 0x7b, 0xbc, 0x15, 0xd7, 0xb3, 0x8d, 0x05, 0x36, 0x2c, 0x9c, 0xa9, - 0x85, 0xf5, 0x8a, 0x76, 0x64, 0x7d, 0x2b, 0xe4, 0xc2, 0xcd, 0x6b, 0x3d, 0x17, 0xd6, - 0x87, 0x09, 0x71, 0xd7, 0xa0, 0x98, 0xba, 0xf7, 0x2c, 0x6f, 0x6f, 0x12, 0x14, 0xcf, - 0x1f, 0xaa, 0xe4, 0x88, 0xbd, 0x7d, 0xe2, 0x59, 0xd3, 0x41, 0x5c, 0x2f, 0x0d, 0xde, - 0xc7, 0x45, 0x70, 0x04, 0xf3, 0x57, 0x08, 0xd1, 0xec, 0xcc, 0xcc, 0x0d, 0xf6, 0x5a, - 0x04, 0x94, 0x3a, 0xd5, 0xcb, 0xc1, 0x3f, 0x29, 0x5f, 0x00, 0x0f, 0xe0, 0x56, 0xc4, - 0x0b, 0x2d, 0x88, 0xf2, 0x7d, 0xc3, 0x4c, 0xfe, 0xb8, 0x03, 0xbe, 0x34, 0x83, 0xa9, - 0xeb, 0xf9, 0xb5, 0xa9, 0x02, 0x60, 0x57, 0x72, 0x5d, 0x63, 0xea, 0xd2, 0xc0, 0xc0, - 0xff, 0x1f, 0xe2, 0x6a, 0xc1, 0xe7, 0xbd, 0xfc, 0xd6, 0xfa, 0xd8, 0x75, 0x84, 0x2d, - 0x19, 0x4f, 0x33, 0x17, 0x50, 0x46, 0x2c, 0x06, 0xb8, 0xd7, 0x98, 0x2d, 0x67, 0x99, - 0x5e, 0xd5, 0xd3, 0xae, 0x96, 0xa0, 0x5a, 0xe0, 0x06, 0x7f, 0x4e, 0xb1, 0xc7, 0xc9, - 0x32, 0x31, 0xbd, 0x39, 0x77, 0x3c, 0xbe, 0x0a, 0x9d, 0x66, 0xb0, 0xc9, 0xaa, 0x8c, - 0xff, 0x6a, 0x37, 0x6e, 0x1f, 0x37, 0x2e, 0xac, 0x6a, 0xc4, 0xe4, 0x6c, 0xc0, 0x94, - 0x22, 0x45, 0xd4, 0xc2, 0xdc, 0xf0, 0x2d, 0x76, 0x40, 0xff, 0xcc, 0x5a, 0x6a, 0xc3, - 0xa8, 0x7f, 0x5c, 0x41, 0x15, 0x51, 0xbc, 0xc2, 0xf2, 0x6c, 0xb9, 0x49, 0x61, 0xd5, - 0x3f, 0x95, 0xdd, 0xb1, 0x9a, 0xe9, 0x30, 0xc8, 0xd7, 0x0f, 0x03, 0x1b, 0x29, 0xa5, - 0xdf, 0x99, 0xff, 0x36, 0x69, 0x5e, 0x80, 0x2c, 0xbc, 0xb6, 0xb1, 0xcf, 0x7d, 0xc9, - 0x7a, 0xbb, 0x3b, 0x25, 0x27, 0x64, 0xc0, 0x1a, 0x62, 0x2d, 0xfb, 0x2e, 0xcb, 0x49, - 0xce, 0x71, 0xf7, 0x38, 0x6e, 0x23, 0x89, 0x5b, 0x5a, 0xfe, 0x16, 0x61, 0x98, 0xb6, - 0x7f, 0x5b, 0x42, 0xb2, 0xf6, 0x5e, 0xcd, 0x0f, 0x82, 0x59, 0x54, 0x78, 0xd8, 0x0a, - 0xe5, 0xc8, 0xce, 0xea, 0x12, 0xa1, 0x61, 0xcc, 0xbb, 0x5e, 0xac, 0x09, 0x99, 0x0f, - 0xc6, 0x19, 0xa4, 0x60, 0x80, 0x43, 0x6d, 0xbd, 0x08, 0xd7, 0x47, 0x84, 0xaf, 0x00, - 0x2d, 0x58, 0xe0, 0x6f, 0xaf, 0x7f, 0x3c, 0xea, 0xe7, 0xd3, 0x41, 0x9b, 0x1f, 0xca, - 0x26, 0x5a, 0x55, 0x59, 0xcf, 0x9e, 0x2d, 0x3b, 0x97, 0xb2, 0xa9, 0x9a, 0x9b, 0xa5, - 0xa8, 0x66, 0x58, 0xc3, 0xfd, 0x9e, 0xc5, 0x5b, 0xfa, 0x9b, 0x32, 0x85, 0x67, 0x25, - 0x4a, 0xb3, 0x6d, 0x2c, 0x7f, 0x44, 0xd2, 0xc7, 0xe1, 0x3e, 0xb5, 0x4b, 0xeb, 0x70, - 0xea, 0x8f, 0xa9, 0x4b, 0x6c, 0x6e, 0x01, 0x2d, 0x79, 0xe3, 0xf5, 0x36, 0x89, 0xc2, - 0xb1, 0xa1, 0x8e, 0xaf, 0x2d, 0x47, 0x1d, 0x13, 0xc1, 0xab, 0x39, 0xd9, 0x19, 0x4a, - 0xe8, 0x43, 0xab, 0x1d, 0x28, 0xff, 0xa8, 0xf6, 0x9d, 0xc7, 0xe1, 0x5c, 0xc3, 0x8b, - 0x12, 0xe8, 0xfc, 0xd7, 0x92, 0x55, 0xb7, 0x21, 0x60, 0x56, 0xd9, 0xed, 0xb7, 0x48, - 0x2f, 0xb9, 0x8a, 0xa0, 0x33, 0xb6, 0x5e, 0x51, 0xc1, 0xa0, 0x8b, 0x8a, 0x11, 0xd8, - 0x4d, 0x04, 0x09, 0xb7, 0x34, 0xf4, 0x52, 0xaa, 0xf0, 0xd6, 0xb1, 0x8f, 0x50, 0x25, - 0x86, 0x83, 0xd3, 0xf9, 0xa7, 0x6d, 0x39, 0x9f, 0xd0, 0x47, 0xee, 0xe2, 0x88, 0xbb, - 0x45, 0x85, 0x85, 0x1d, 0xc9, 0x3e, 0xcc, 0xc6, 0x23, 0x22, 0x92, 0x4c, 0xd1, 0x3b, - 0x5d, 0xd4, 0xee, 0xd6, 0x6e, 0xd8, 0xd9, 0x97, 0x2d, 0x77, 0x26, 0x29, 0xea, 0x64, - 0x74, 0x2e, 0x54, 0x73, 0x39, 0x81, 0xb0, 0x06, 0xc0, 0x62, 0x46, 0x8e, 0x4b, 0xd8, - 0xf7, 0xdd, 0x9a, 0xf6, 0x98, 0xf5, 0x2a, 0xe8, 0x14, 0x63, 0x4e, 0x81, 0xd7, 0xf3, - 0xe0, 0xc4, 0x20, 0x31, 0x7c, 0xac, 0xa9, 0xae, 0x48, 0x11, 0xc6, 0xaf, 0x06, 0xfe, - 0x80, 0xa8, 0xc0, 0x2a, 0xb7, 0xa0, 0x0e, 0x18, 0xe4, 0xa6, 0xaa, 0x1e, 0xa1, 0xb7, - 0x69, 0x45, 0xd2, 0x61, 0x5d, 0x43, 0xac, 0x11, 0x8b, 0x56, 0xc2, 0xf2, 0x96, 0x0f, - 0xe9, 0x3a, 0x02, 0x5f, 0x13, 0xec, 0x91, 0xff, 0xc6, 0xd2, 0xc3, 0x53, 0x69, 0x9a, - 0xbb, 0x09, 0x2d, 0xed, 0xc0, 0x65, 0xdb, 0x8f, 0xa2, 0x14, 0xdb, 0xc4, 0x64, 0x66, - 0xf8, 0x97, 0xb8, 0x8c, 0x58, 0xb3, 0x01, 0x52, 0x13, 0x3a, 0xa3, 0x83, 0x1a, 0xf3, - 0x7c, 0x74, 0xd9, 0x9e, 0x9e, 0x36, 0xff, 0x70, 0x11, 0xd3, 0x23, 0x83, 0x05, 0x69, - 0x15, 0x08, 0xd0, 0xf1, 0xf6, 0xaa, 0xaa, 0xa4, 0x25, 0x12, 0x30, 0xc6, 0xcc, 0xc4, - 0x66, 0x68, 0xbb, 0xcf, 0x35, 0xe5, 0xa5, 0xef, 0x2f, 0x86, 0xe6, 0x65, 0xd8, 0xcf, - 0xac, 0x74, 0x76, 0xec, 0xb2, 0x43, 0x78, 0x79, 0x6a, 0x8e, 0xf2, 0xe4, 0xd9, 0x4d, - 0x43, 0x58, 0xbe, 0x2b, 0x47, 0x5f, 0xcc, 0x92, 0xdf, 0x93, 0x82, 0xc5, 0xc0, 0x69, - 0x19, 0xa0, 0xd6, 0x31, 0xec, 0x26, 0x10, 0xfe, 0xdc, 0x21, 0x9b, 0xe6, 0x3f, 0x37, - 0xf2, 0xba, 0x0d, 0x43, 0x23, 0x66, 0x73, 0x6d, 0x86, 0x32, 0xfc, 0xe0, 0x72, 0xb6, - 0xae, 0x5b, 0x6f, 0x3f, 0xd5, 0x9d, 0x3f, 0xaf, 0xf6, 0x38, 0x27, 0x5a, 0x99, 0x2f, - 0xef, 0xc8, 0x7e, 0x60, 0xd4, 0x4c, 0x2c, 0xad, 0xc2, 0xb5, 0xc4, 0x94, 0xe3, 0xe7, - 0x2e, 0xb4, 0x59, 0x7c, 0x96, 0xb4, 0x01, 0x67, 0x79, 0x9a, 0x90, 0x01, 0xa2, 0xed, - 0x36, 0x76, 0xa8, 0xb4, 0x03, 0xae, 0x25, 0xff, 0xd7, 0x72, 0xf7, 0x08, 0x1e, 0x9a, - 0x32, 0xbc, 0xc1, 0xc5, 0xe2, 0xed, 0xd4, 0xe2, 0xa6, 0x57, 0x6b, 0x78, 0x3c, 0xce, - 0x3a, 0xae, 0x11, 0xfa, 0x43, 0x22, 0x62, 0x54, 0x88, 0x56, 0x18, 0x3e, 0xe6, 0x82, - 0xd5, 0xdc, 0x31, 0xbe, 0xb3, 0x8f, 0x06, 0x1c, 0xbd, 0xec, 0xa7, 0x02, 0x1a, 0x44, - 0x4e, 0x2d, 0xd4, 0x17, 0xdf, 0x26, 0xdc, 0xd2, 0x20, 0xf2, 0xb7, 0x31, 0x77, 0x2b, - 0x43, 0x9e, 0x96, 0xd6, 0x14, 0xe1, 0xfa, 0xcb, 0x48, 0x6c, 0x7a, 0x7d, 0x51, 0x71, - 0xb1, 0xde, 0x35, 0x9f, 0x6a, 0xd3, 0xa9, 0x6f, 0x64, 0x9c, 0x96, 0x91, 0x02, 0xa1, - 0x96, 0x4f, 0xb4, 0xb4, 0xa1, 0xa4, 0x27, 0x9c, 0x68, 0xe6, 0xc3, 0x72, 0xe4, 0x21, - 0x87, 0xd7, 0x54, 0xe8, 0x04, 0xa6, 0x16, 0x53, 0x09, 0x20, 0x69, 0xfb, 0x9b, 0x6d, - 0x25, 0x26, 0x68, 0x90, 0x80, 0x8b, 0x01, 0x5d, 0xf2, 0x8c, 0x80, 0x10, 0x65, 0xda, - 0x6f, 0xeb, 0xdc, 0x1a, 0x56, 0xbf, 0xd0, 0x02, 0x62, 0x5a, 0xcf, 0xaa, 0x53, 0x73, - 0xfd, 0xe1, 0x49, 0xc1, 0xcf, 0xc3, 0x64, 0x9b, 0x48, 0x69, 0x69, 0x6d, 0x44, 0xec, - 0xb1, 0x24, 0x79, 0xc5, 0xeb, 0xef, 0x99, 0x5f, 0x10, 0x02, 0x9f, 0x8b, 0x53, 0x0e, - 0xeb, 0x3f, 0xdc, 0x2e, 0x50, 0xe8, 0x75, 0x7f, 0xc0, 0xbb, 0x9e, 0x26, 0x30, 0x23, - 0xdb, 0x82, 0xf8, 0x78, 0xd9, 0xac, 0x7f, 0xfb, 0x0b, 0xd4, 0x39, 0x1d, 0xf1, 0xd8, - 0x79, 0x89, 0x9a, 0x3e, 0xf5, 0x7b, 0xfd, 0x0d, 0x1f, 0x77, 0x55, 0x64, 0x8e, 0xdd, - 0x85, 0xbb, 0x05, 0x2a, 0x6e, 0xdf, 0x71, 0xcd, 0x26, 0x28, 0xc9, 0x87, 0x42, 0x9f, - 0x36, 0xdc, 0x50, 0x5c, 0xcc, 0x43, 0xf3, 0x0e, 0x7a, 0x86, 0x9c, 0x9e, 0x25, 0x5e, - 0x2a, 0xf9, 0xfc, 0xf3, 0x0c, 0x12, 0x17, 0x96, 0x03, 0xae, 0x17, 0x57, 0x55, 0x3b, - 0x5c, 0x94, 0x60, 0x7e, 0x00, 0xd0, 0x32, 0xfb, 0xbe, 0xd2, 0x3c, 0x4c, 0xba, 0xbf, - 0x74, 0x1d, 0x68, 0xaa, 0xb3, 0x0e, 0x0b, 0x8f, 0x15, 0xf4, 0x44, 0xd5, 0x86, 0xb3, - 0xe7, 0xe6, 0x15, 0x9c, 0x46, 0x69, 0x9f, 0x10, 0x07, 0x92, 0xd4, 0x67, 0x29, 0x50, - 0x34, 0x8a, 0x90, 0x55, 0x2e, 0x45, 0x94, 0x3b, 0xee, 0xac, 0xf0, 0x3f, 0x32, 0x16, - 0xf9, 0x4e, 0x27, 0x90, 0x6e, 0xdc, 0x63, 0x23, 0x19, 0xad, 0x8d, 0x37, 0x44, 0x7f, - 0x5c, 0x59, 0xcc, 0xde, 0x35, 0x4f, 0x99, 0xff, 0x6c, 0x7a, 0x76, 0x23, 0xf6, 0xd4, - 0x15, 0x25, 0xa8, 0x09, 0xce, 0x2f, 0x41, 0xec, 0x0f, 0xf7, 0xf1, 0xaf, 0x81, 0xb2, - 0x4c, 0xed, 0x0e, 0xfa, 0x62, 0x13, 0xda, 0x6c, 0x7c, 0x60, 0xc4, 0x87, 0xf5, 0xf7, - 0xb0, 0x3f, 0x81, 0x60, 0xa0, 0x57, 0xf4, 0x6d, 0x05, 0xbf, 0x82, 0x18, 0xb3, 0xad, - 0xd9, 0xc0, 0x68, 0x93, 0xbd, 0x02, 0xdb, 0x9b, 0x61, 0x19, 0x1d, 0xfb, 0x13, 0x3b, - 0xfa, 0xbe, 0x48, 0x58, 0xe4, 0x7a, 0x4c, 0xc3, 0x2e, 0x41, 0x6e, 0xc0, 0x8b, 0x8a, - 0xc7, 0x91, 0x5a, 0x43, 0x73, 0x3f, 0x44, 0x06, 0xe9, 0xd9, 0x67, 0xc5, 0x60, 0xf3, - 0x44, 0xd7, 0xe9, 0x04, 0xa2, 0x80, 0x45, 0xd9, 0x9f, 0x3a, 0xf8, 0xc8, 0x2e, 0x97, - 0xe1, 0xb9, 0xc1, 0xb2, 0x05, 0xe5, 0x85, 0xfb, 0xeb, 0xb4, 0x8f, 0xaf, 0x58, 0xf1, - 0xb6, 0x5d, 0xca, 0x24, 0x97, 0xe0, 0x9a, 0x70, 0xaa, 0xd4, 0x86, 0x5f, 0x85, 0x71, - 0x5a, 0x28, 0x0e, 0x18, 0x6f, 0x3f, 0xc1, 0x74, 0x0d, 0x81, 0x84, 0xd3, 0x3e, 0x83, - 0x22, 0x16, 0x95, 0x21, 0xcd, 0xc1, 0x32, 0x21, 0x29, 0x39, 0xc8, 0x4a, 0x10, 0x89, - 0x64, 0xe2, 0xde, 0x74, 0xb6, 0xea, 0x55, 0xb4, 0xcb, 0x8f, 0x6f, 0x9b, 0xee, 0x98, - 0xb1, 0x0d, 0x41, 0x51, 0x09, 0x45, 0x5f, 0x48, 0xb7, 0x76, 0x08, 0x2d, 0xc3, 0x0b, - 0x4b, 0xc7, 0x34, 0x77, 0x07, 0x55, 0x11, 0x70, 0x03, 0x08, 0x15, 0x8c, 0xe2, 0xf2, - 0xf9, 0xbf, 0x0f, 0x69, 0x1b, 0x2c, 0xe5, 0x3e, 0x61, 0x14, 0x2c, 0xb7, 0x40, 0xc1, - 0x5b, 0x7b, 0x62, 0x3c, 0xf4, 0x8b, 0x3f, 0x7b, 0xfe, 0xfa, 0x31, 0xbc, 0xdc, 0x66, - 0x5c, 0x6d, 0x71, 0x23, 0xe9, 0x53, 0x50, 0x81, 0x13, 0x75, 0x94, 0x7b, 0x05, 0x5a, - 0x43, 0xdb, 0x07, 0xe0, 0x3f, 0x33, 0x62, 0x7d, 0xf5, 0xc6, 0x38, 0xbf, 0xad, 0x95, - 0x6d, 0xdc, 0x1e, 0xa7, 0xd7, 0x62, 0x0a, 0x20, 0xf2, 0x79, 0x2f, 0x63, 0x81, 0x7a, - 0x1c, 0xf3, 0x25, 0x80, 0xd0, 0x42, 0x74, 0x23, 0x4a, 0xf2, 0xa5, 0x1b, 0x56, 0xbb, - 0x68, 0xa2, 0x9e, 0x43, 0xa9, 0x54, 0x14, 0x2b, 0xa4, 0xca, 0x68, 0x23, 0xbd, 0xe9, - 0x05, 0x3d, 0x72, 0xfd, 0xad, 0xbc, 0x61, 0xad, 0x59, 0x36, 0xc5, 0x3f, 0xdd, 0x75, - 0x79, 0x44, 0x6d, 0x11, 0xc4, 0x46, 0x07, 0xf4, 0x16, 0x30, 0xe4, 0xc0, 0x89, 0x15, - 0xe6, 0x31, 0x77, 0x15, 0x50, 0xe9, 0xce, 0x1f, 0xca, 0x2c, 0x63, 0xfe, 0x06, 0xb7, - 0x98, 0x9d, 0x58, 0x4f, 0xa7, 0xd7, 0x82, 0xa8, 0x8c, 0x1e, 0x7d, 0x64, 0xb6, 0xfb, - 0xf5, 0x5e, 0x35, 0x96, 0xaf, 0x9b, 0xcb, 0x75, 0x85, 0xf8, 0xc7, 0xd3, 0xaa, 0x5c, - 0x20, 0x82, 0xb2, 0x65, 0x24, 0x9d, 0xf0, 0x57, 0x01, 0xda, 0xb0, 0x31, 0xc4, 0xba, - 0xc1, 0xea, 0x26, 0x7a, 0x29, 0x96, 0xa2, 0x02, 0x8d, 0x1e, 0x6a, 0x0f, 0x80, 0xa3, - 0x84, 0x7c, 0x53, 0x1d, 0xba, 0x96, 0xee, 0x65, 0xa2, 0x41, 0x89, 0xbd, 0x27, 0x12, - 0xe4, 0x0e, 0x95, 0x96, 0x64, 0x98, 0x1e, 0x58, 0xb2, 0xa4, 0xf9, 0x51, 0xef, 0x8f, - 0x49, 0x7d, 0xff, 0xf2, 0xf2, 0xf2, 0x71, 0xea, 0xb8, 0x9c, 0x62, 0x8e, 0x18, 0xb5, - 0xfc, 0xb4, 0x38, 0x82, 0x53, 0x7e, 0xaf, 0x6a, 0xd2, 0xa6, 0xb1, 0x75, 0x46, 0x33, - 0xca, 0xa8, 0x6b, 0xf2, 0xc7, 0x6f, 0x39, 0x93, 0x15, 0x4f, 0xc7, 0x3e, 0x6f, 0xbb, - 0xa2, 0x21, 0x0c, 0x27, 0x43, 0xf5, 0x30, 0xa4, 0x27, 0x84, 0x9a, 0x30, 0x1e, 0x00, - 0xe0, 0x11, 0x29, 0xf0, 0x3a, 0x46, 0x07, 0xf8, 0x7c, 0xbe, 0x07, 0x62, 0xc0, 0xb1, - 0xc6, 0x58, 0x55, 0xde, 0xba, 0x84, 0x22, 0xca, 0x4b, 0x88, 0xab, 0xee, 0xa6, 0xa4, - 0x38, 0x2c, 0xf1, 0x6c, 0xcd, 0x6d, 0xc7, 0xc3, 0x7c, 0x44, 0xe5, 0x49, 0xc4, 0x53, - 0x48, 0x19, 0xac, 0xd8, 0xbb, 0x0a, 0x02, 0xa5, 0xfa, 0x7a, 0x1c, 0x1d, 0x38, 0x06, - 0xfb, 0xc3, 0x40, 0x7f, 0xd7, 0xda, 0x93, 0xfd, 0x0d, 0xe6, 0x40, 0x0d, 0x3a, 0xb8, - 0x97, 0x74, 0x85, 0xcd, 0xdf, 0xbe, 0xd5, 0x93, 0x2f, 0x50, 0x7b, 0x79, 0x94, 0x7a, - 0xdb, 0x2f, 0xad, 0x37, 0x61, 0x5a, 0xa7, 0x17, 0xdb, 0x5f, 0x29, 0x80, 0x99, 0xf2, - 0x0f, 0x26, 0x3b, 0x35, 0x9a, 0x11, 0x51, 0xa6, 0xb7, 0x5c, 0x01, 0x36, 0x5e, 0xb1, - 0x54, 0xae, 0x42, 0x14, 0x0d, 0x6e, 0x10, 0x34, 0x2f, 0x14, 0xf3, 0x4d, 0xc3, 0x3e, - 0x07, 0xff, 0x0e, 0x4d, 0x1a, 0x6b, 0xe3, 0x75, 0xb3, 0x2f, 0x84, 0xb9, 0x2e, 0x5d, - 0x81, 0xeb, 0xb6, 0x39, 0xc4, 0xf2, 0x7e, 0x71, 0x5a, 0xa4, 0x2c, 0xc7, 0x57, 0x07, - 0xd4, 0xeb, 0xd1, 0xbb, 0xfb, 0xe8, 0xf9, 0x0f, 0xc7, 0xc9, 0x53, 0xe7, 0xa9, 0x71, - 0x5e, 0x65, 0xaf, 0x82, 0x67, 0x37, 0x3d, 0x34, 0x51, 0x67, 0x4f, 0xf0, 0x84, 0xef, - 0xd9, 0x2c, 0xcf, 0x3b, 0xcc, 0x7a, 0xca, 0x14, 0x67, 0xb6, 0x32, 0x7e, 0x4f, 0x95, - 0x22, 0xb2, 0xcc, 0x57, 0x9a, 0x7a, 0x8f, 0xff, 0x7c, 0xa7, 0xcf, 0x14, 0x5d, 0xfc, - 0x13, 0xea, 0xfc, 0x34, 0x15, 0x3b, 0x2c, 0x3e, 0x8a, 0xfb, 0xe5, 0x34, 0x44, 0xd0, - 0xc7, 0x3b, 0x3b, 0xd5, 0xbc, 0x87, 0x0b, 0x01, 0xcd, 0x45, 0x79, 0x11, 0xe3, 0x56, - 0x31, 0x3f, 0xd1, 0xda, 0xfb, 0x4c, 0x81, 0x51, 0x63, 0x4a, 0x01, 0xaf, 0xf7, 0xcf, - 0x11, 0x6d, 0x43, 0x3c, 0x3d, 0x2b, 0x3a, 0xdd, 0xa9, 0xce, 0xbe, 0x18, 0xf7, 0xd1, - 0x72, 0x44, 0x3e, 0x5e, 0x7b, 0x5a, 0xc9, 0xab, 0xe8, 0xdb, 0x22, 0x56, 0xd7, 0xeb, - 0xe2, 0xff, 0x28, 0x02, 0x09, 0x39, 0x50, 0x38, 0x70, 0x59, 0x7b, 0x9a, 0x95, 0x58, - 0x92, 0xc7, 0x38, 0x96, 0x50, 0xa2, 0xd4, 0x2e, 0xc9, 0x2b, 0xe7, 0x23, 0xfe, 0xdf, - 0x2f, 0x2e, 0xde, 0x5a, 0x47, 0x2a, 0xa1, 0xe7, 0x4f, 0x33, 0xad, 0x41, 0x90, 0x15, - 0x44, 0xed, 0xbb, 0xe3, 0xac, 0x46, 0x4c, 0xf4, 0x39, 0x19, 0x60, 0x15, 0xf4, 0xf2, - 0x2a, 0xc2, 0xb8, 0xfc, 0x01, 0x49, 0x6b, 0xea, 0xb4, 0xd4, 0x59, 0x07, 0xf4, 0x79, - 0x81, 0x2a, 0x25, 0x94, 0x31, 0xa2, 0xcb, 0xc9, 0x3d, 0x4f, 0x3b, 0x84, 0xe4, 0xdd, - 0x36, 0x60, 0x20, 0x27, 0x3a, 0x67, 0x52, 0xe5, 0x01, 0xaf, 0x6f, 0xf1, 0xb7, 0x8d, - 0xdc, 0x81, 0x7e, 0x6e, 0xa3, 0xe5, 0x37, 0x5c, 0xa3, 0xfe, 0x2f, 0xb1, 0xd1, 0xa9, - 0x37, 0x15, 0xdf, 0xf9, 0x29, 0x93, 0xcc, 0xc6, 0x50, 0x4f, 0x64, 0xfc, 0xbf, 0x22, - 0x17, 0x30, 0xd9, 0xef, 0xf4, 0xf3, 0x27, 0xe0, 0xad, 0x37, 0x4f, 0x59, 0x56, 0x45, - 0x37, 0x48, 0x75, 0x5b, 0x43, 0xc8, 0xf2, 0x9d, 0x67, 0x52, 0x6f, 0x60, 0xa6, 0x18, - 0xb7, 0x33, 0x24, 0xd2, 0x24, 0x33, 0x72, 0x92, 0x1b, 0x99, 0xe3, 0xdf, 0x36, 0x85, - 0x0c, 0x60, 0xd5, 0xd9, 0x34, 0x3a, 0x48, 0x70, 0xa0, 0xe7, 0x52, 0x8c, 0x65, 0x13, - 0xc2, 0x7c, 0x56, 0x43, 0x90, 0x93, 0xf9, 0x33, 0x68, 0x1d, 0x93, 0xa4, 0xd4, 0xbc, - 0xee, 0xac, 0x2b, 0x10, 0x8c, 0x6c, 0x6f, 0xae, 0x35, 0x9f, 0x64, 0x5c, 0x27, 0x68, - 0x91, 0xc0, 0xdc, 0xab, 0x3f, 0xaf, 0x18, 0x77, 0x00, 0xc0, 0x82, 0xdc, 0x47, 0x77, - 0x40, 0xfb, 0x3f, 0x2c, 0xd7, 0xbb, 0x59, 0xfb, 0x35, 0x85, 0x54, 0xe9, 0x4c, 0x7e, - 0x67, 0x8c, 0xe0, 0x1a, 0xeb, 0xf9, 0x4e, 0x51, 0x5e, 0x49, 0x72, 0x29, 0x67, 0x99, - 0x5a, 0xea, 0x85, 0x8d, 0x64, 0xe7, 0x78, 0x9f, 0xf3, 0x06, 0x36, 0x95, 0x77, 0x22, - 0x81, 0x80, 0x32, 0x6a, 0x5b, 0x0a, 0xf4, 0x75, 0xe2, 0x7a, 0x54, 0xb2, 0x07, 0xb4, - 0x1f, 0x92, 0xe3, 0x76, 0x17, 0x0e, 0x3f, 0xb0, 0x05, 0x02, 0x82, 0x61, 0xc9, 0x9c, - 0x2d, 0xbd, 0x0e, 0xed, 0xee, 0x87, 0x1c, 0x1c, 0x0f, 0x48, 0xb8, 0xe9, 0xb8, 0xe4, - 0xbe, 0x77, 0xd1, 0xb7, 0x37, 0xfe, 0x21, 0xf0, 0xfa, 0x5a, 0x18, 0xeb, 0xb5, 0x27, - 0x55, 0xb5, 0xa6, 0xcf, 0x61, 0x30, 0xfb, 0x56, 0x94, 0x4c, 0xfa, 0xb8, 0x75, 0x27, - 0xc2, 0x50, 0xd1, 0x13, 0xb2, 0x9b, 0xca, 0xc9, 0xaa, 0xa1, 0x0c, 0x2e, 0x7d, 0xe4, - 0x15, 0xed, 0xb0, 0x80, 0x6c, 0x6d, 0xa0, 0x30, 0x20, 0xa1, 0x34, 0xca, 0x7e, 0xcd, - 0xc8, 0xda, 0x1b, 0xd5, 0x7a, 0x37, 0xf5, 0x5a, 0x46, 0x94, 0x0b, 0x45, 0xb2, 0x41, - 0xb1, 0xc1, 0x6e, 0xe1, 0x00, 0x92, 0x7d, 0x1b, 0xd8, 0x60, 0xd4, 0x45, 0xa9, 0xde, - 0x50, 0xd4, 0xc3, 0x84, 0xd6, 0xe1, 0xd0, 0x01, 0x08, 0x02, 0x6c, 0x0e, 0xa5, 0xeb, - 0xbf, 0x0b, 0x72, 0xfb, 0xf5, 0xc3, 0x70, 0xbc, 0xe1, 0x8d, 0x3a, 0xcb, 0xc4, 0x65, - 0x99, 0x09, 0x9b, 0xaa, 0xe1, 0xd8, 0x02, 0xf7, 0x73, 0x33, 0x49, 0x4a, 0x7a, 0xe1, - 0x30, 0xfe, 0x86, 0xe8, 0xf8, 0x18, 0xf9, 0x26, 0x1a, 0x2d, 0xad, 0xb4, 0x12, 0x52, - 0x29, 0xba, 0x0f, 0xfc, 0x0e, 0x70, 0x90, 0x32, 0x44, 0x30, 0xb5, 0x21, 0xa9, 0x0d, - 0x22, 0x4a, 0xb7, 0xa1, 0x02, 0x4e, 0x1d, 0x89, 0x3e, 0x74, 0x04, 0xfe, 0xdb, 0x34, - 0x8e, 0x4d, 0x5e, 0x22, 0x35, 0xc5, 0x9a, 0x78, 0x76, 0xa0, 0xfc, 0x60, 0x14, 0x5c, - 0x6a, 0x00, 0x96, 0x87, 0x68, 0x44, 0x60, 0x27, 0x1e, 0xe1, 0x33, 0xa4, 0x37, 0xfe, - 0x52, 0xfb, 0x6c, 0xfb, 0xa9, 0x7f, 0xce, 0xc1, 0x61, 0xdf, 0x51, 0x5d, 0xde, 0x90, - 0x5a, 0x24, 0xda, 0x6d, 0x37, 0xbd, 0xc3, 0x40, 0x44, 0xa9, 0x55, 0xe6, 0x82, 0xb4, - 0x74, 0x71, 0xca, 0x1e, 0x8c, 0x78, 0xc5, 0x1e, 0xd3, 0x77, 0xcd, 0x4a, 0xfa, 0x89, - 0x4b, 0xd9, 0xbd, 0x12, 0xe7, 0x07, 0x15, 0x6d, 0xa0, 0x72, 0x6f, 0x7c, 0xf5, 0x72, - 0x9f, 0xab, 0xe3, 0x72, 0x16, 0x04, 0x63, 0xfe, 0x04, 0x29, 0x24, 0x4d, 0x06, 0x74, - 0x89, 0xba, 0x5d, 0x09, 0x47, 0x2e, 0xcd, 0x9b, 0xcd, 0xc4, 0xd5, 0xe4, 0xdf, 0x10, - 0x1e, 0x18, 0x9d, 0xb8, 0x46, 0x3e, 0xb5, 0x38, 0x30, 0x7b, 0x58, 0x7d, 0xef, 0xf7, - 0x8d, 0xe9, 0xc7, 0x3a, 0xf2, 0x80, 0x80, 0xb2, 0xfd, 0x05, 0x00, 0x3e, 0x11, 0xd3, - 0xe1, 0xb3, 0x29, 0x9d, 0xc9, 0x52, 0x1f, 0x8b, 0x51, 0x3b, 0xad, 0xb0, 0x10, 0xe9, - 0x1b, 0xfe, 0xb9, 0x1b, 0x0b, 0x2a, 0x6c, 0xb1, 0x29, 0xc2, 0xe8, 0x25, 0xa5, 0x97, - 0xb8, 0xfb, 0x75, 0xbc, 0x56, 0x2d, 0x65, 0x4d, 0x62, 0x10, 0x46, 0x40, 0xdd, 0x74, - 0xe5, 0x6c, 0xd1, 0x4b, 0xaa, 0xba, 0x56, 0x5b, 0x84, 0xb8, 0x45, 0xe1, 0x63, 0xd1, - 0xca, 0xef, 0x25, 0x33, 0xc3, 0x98, 0x16, 0x37, 0x20, 0x4f, 0x96, 0xa5, 0x9c, 0x8e, - 0x80, 0x24, 0xd9, 0x04, 0x1b, 0x20, 0x29, 0xe9, 0x4c, 0x15, 0x24, 0x5f, 0x1a, 0x95, - 0x88, 0x40, 0xba, 0x3f, 0x38, 0x0a, 0x4d, 0x20, 0xf1, 0x18, 0x4e, 0x77, 0x82, 0x7d, - 0xe3, 0xff, 0x8f, 0x3d, 0x73, 0x45, 0x9a, 0xfe, 0x24, 0x1f, 0x72, 0x3c, 0x08, 0x48, - 0x23, 0x23, 0x0e, 0x00, 0x3d, 0x3d, 0x21, 0xe5, 0x35, 0x01, 0xec, 0x04, 0x99, 0xb0, - 0x83, 0xa7, 0xda, 0xd6, 0x85, 0xc5, 0x71, 0x27, 0xf4, 0xde, 0x64, 0x73, 0x3a, 0x88, - 0x0c, 0x2d, 0xb2, 0x8f, 0xda, 0xab, 0xf1, 0xb5, 0x42, 0xd2, 0x05, 0xf6, 0x64, 0xa3, - 0x51, 0x35, 0x71, 0x27, 0x11, 0xdc, 0xcc, 0xd9, 0x31, 0xa5, 0x0b, 0x9c, 0x56, 0x61, - 0x88, 0x23, 0x60, 0xd4, 0xca, 0xc0, 0x04, 0x76, 0x81, 0xbc, 0x2e, 0x2b, 0x3b, 0xf6, - 0xc9, 0x97, 0x60, 0xd7, 0xcf, 0xb4, 0xfa, 0x21, 0x39, 0x43, 0x77, 0xa4, 0x55, 0x1c, - 0x76, 0xd1, 0xf7, 0x5a, 0xc0, 0x3c, 0x26, 0x20, 0x54, 0xdf, 0xfd, 0x79, 0xa9, 0xde, - 0xd0, 0x5e, 0x88, 0x89, 0x58, 0x19, 0x9e, 0xea, 0x45, 0x01, 0xe2, 0x99, 0x0a, 0x53, - 0xa5, 0xcd, 0x2a, 0x46, 0xa4, 0x01, 0x57, 0x65, 0x88, 0xfd, 0x7d, 0x05, 0x8a, 0x26, - 0xf2, 0x84, 0x38, 0xe5, 0x78, 0x2f, 0x45, 0xac, 0x1d, 0x07, 0xf6, 0xf6, 0xf5, 0xed, - 0x73, 0x74, 0x1d, 0x57, 0x85, 0x83, 0x7a, 0x6b, 0x84, 0x4b, 0x47, 0x47, 0x75, 0x71, - 0x8c, 0x29, 0xdd, 0x99, 0x08, 0x4e, 0x9f, 0x88, 0xef, 0x15, 0x3a, 0x83, 0x29, 0xf5, - 0x32, 0xa6, 0x90, 0x17, 0xdc, 0x3a, 0x97, 0xed, 0x75, 0x43, 0x67, 0x72, 0x30, 0x98, - 0xe5, 0x76, 0x58, 0x40, 0xb0, 0x22, 0x89, 0x72, 0x44, 0x74, 0x5f, 0xbb, 0xbb, 0x30, - 0xa7, 0xcb, 0x54, 0xfa, 0x05, 0x11, 0x16, 0x6e, 0x95, 0x44, 0x12, 0x20, 0x00, 0x61, - 0x0b, 0xd2, 0xaa, 0xcb, 0xd8, 0x23, 0x25, 0xa5, 0x9b, 0x95, 0x15, 0x4e, 0xcd, 0x82, - 0xc8, 0x8d, 0x23, 0xab, 0xd1, 0xe2, 0x07, 0x70, 0xff, 0xb8, 0xaa, 0xbf, 0x83, 0xfc, - 0x07, 0x34, 0x96, 0x4c, 0xcd, 0x41, 0x1d, 0x1c, 0x93, 0x57, 0x14, 0xe2, 0x4a, 0xab, - 0x56, 0x6f, 0x4f, 0x08, 0x42, 0x40, 0x14, 0xc4, 0xec, 0xa9, 0x1b, 0x59, 0x0f, 0x08, - 0x2b, 0x47, 0x3f, 0x36, 0x1c, 0x87, 0x41, 0x5d, 0x37, 0xbd, 0x20, 0xd7, 0x0f, 0xd0, - 0xb5, 0x2b, 0x6d, 0xdf, 0x18, 0x65, 0xf7, 0x66, 0x70, 0x2e, 0x32, 0xb0, 0x5b, 0x3c, - 0xf1, 0x63, 0x0e, 0xe8, 0x59, 0x7a, 0xae, 0x19, 0x63, 0x3f, 0x35, 0x16, 0xa8, 0x55, - 0x5a, 0xc5, 0xbe, 0x32, 0xc6, 0x75, 0xbe, 0x18, 0x17, 0xef, 0xbf, 0xfd, 0x93, 0x69, - 0x04, 0xbd, 0x73, 0x4d, 0x97, 0x23, 0x3a, 0xaa, 0x38, 0x3b, 0x41, 0xba, 0x6d, 0x27, - 0xf6, 0x42, 0x84, 0x7d, 0x1e, 0xda, 0xcb, 0x4b, 0xf8, 0x22, 0xe6, 0x70, 0x80, 0x86, - 0x75, 0x18, 0xae, 0x5a, 0x8f, 0x0a, 0x43, 0xe6, 0xed, 0x53, 0x0c, 0xb2, 0xe8, 0xae, - 0x83, 0x88, 0x60, 0xad, 0xc8, 0x8a, 0xac, 0xc7, 0xbd, 0x6a, 0x00, 0xae, 0x0c, 0x19, - 0xff, 0x45, 0x33, 0xa4, 0x85, 0xef, 0xde, 0x08, 0x2b, 0xc5, 0x21, 0x40, 0x18, 0x2b, - 0x23, 0x4d, 0x1a, 0x0d, 0x0e, 0xeb, 0xdf, 0xb9, 0x87, 0x75, 0x98, 0xe0, 0x34, 0x7f, - 0xb1, 0x00, 0x1e, 0x15, 0xb5, 0xd4, 0x44, 0x6e, 0x76, 0x6c, 0xde, 0x25, 0xef, 0x79, - 0x87, 0x40, 0xe0, 0xbd, 0xf9, 0x94, 0xd9, 0x73, 0x9b, 0xbe, 0x55, 0x38, 0xa0, 0xae, - 0x0f, 0x07, 0x6c, 0x58, 0x2c, 0x0f, 0x5b, 0xa8, 0x78, 0xb9, 0x9b, 0x82, 0x49, 0xdb, - 0x1d, 0x7e, 0x95, 0x05, 0x6c, 0x98, 0xaf, 0x08, 0x3d, 0x98, 0xcb, 0x0e, 0xd9, 0xe3, - 0xf7, 0x43, 0x6e, 0x1c, 0x76, 0x43, 0x76, 0x6f, 0x96, 0x6b, 0x83, 0xe9, 0x99, 0x20, - 0x6e, 0xbd, 0x13, 0x93, 0xb9, 0xb2, 0xa7, 0xf4, 0x14, 0x48, 0x0f, 0xa0, 0x17, 0x48, - 0x00, 0x69, 0xf8, 0x5c, 0x77, 0x49, 0xc4, 0x35, 0xae, 0x2f, 0xba, 0x2d, 0xdc, 0x10, - 0x38, 0xd5, 0x47, 0xd8, 0x48, 0x54, 0x81, 0x7e, 0xf3, 0x96, 0x35, 0xc2, 0x98, 0x27, - 0xaa, 0xd8, 0x67, 0x26, 0xc9, 0xad, 0xe3, 0xb2, 0x65, 0xb9, 0x08, 0x6c, 0x8b, 0x5b, - 0x75, 0xef, 0x56, 0xfe, 0x4b, 0xd8, 0xb4, 0xd6, 0x28, 0x93, 0x89, 0x5b, 0x3f, 0xd2, - 0x73, 0x4f, 0xda, 0xc4, 0x64, 0x15, 0x6d, 0x7e, 0x5e, 0xbc, 0x7e, 0xcf, 0x1d, 0x83, - 0xb8, 0x6f, 0x65, 0x96, 0x37, 0xe3, 0xb1, 0x42, 0xc1, 0x64, 0x96, 0x3b, 0x8c, 0xdc, - 0xf4, 0xba, 0x4f, 0x40, 0x35, 0xdf, 0xfc, 0x5a, 0x78, 0x94, 0x58, 0x84, 0x77, 0x81, - 0x91, 0x8a, 0xc7, 0x2f, 0xc1, 0x8b, 0xbb, 0xf5, 0x11, 0x00, 0x32, 0xe6, 0x6d, 0x75, - 0xb3, 0x17, 0x1e, 0xf4, 0xb5, 0x13, 0x29, 0x01, 0x64, 0xa7, 0x7b, 0x42, 0xb0, 0xa4, - 0xcf, 0xb8, 0x96, 0x39, 0xab, 0x23, 0x84, 0x5e, 0x1a, 0xa2, 0xa4, 0x52, 0xf3, 0x73, - 0x1c, 0x8c, 0xb6, 0x50, 0x82, 0xa6, 0x22, 0xa7, 0xc2, 0xe0, 0x01, 0x3e, 0xa4, 0x7d, - 0x0b, 0xdd, 0x42, 0xd6, 0x99, 0x04, 0x66, 0x64, 0x9a, 0x90, 0x5c, 0x68, 0x4c, 0x32, - 0x51, 0x71, 0x6d, 0x61, 0xf7, 0x60, 0xd5, 0x3d, 0xe6, 0xe3, 0xf7, 0x90, 0xfb, 0xa7, - 0xf5, 0xf1, 0xf4, 0xde, 0x26, 0x71, 0x13, 0xbd, 0xfc, 0xd7, 0x42, 0x28, 0x22, 0x33, - 0x0b, 0x32, 0xd5, 0x8e, 0x67, 0x77, 0x76, 0x5f, 0x22, 0xa4, 0x11, 0x63, 0x44, 0xee, - 0xb6, 0x5b, 0x2e, 0xc5, 0x16, 0x39, 0x3a, 0xb3, 0x75, 0x1b, 0x53, 0x56, 0xd2, 0xb0, - 0xc9, 0x50, 0x0c, 0x0f, 0x3e, 0x46, 0x91, 0x81, 0x03, 0x5b, 0xc3, 0x66, 0x0f, 0x0b, - 0x8f, 0x9f, 0xbe, 0x6e, 0x40, 0xb5, 0xe8, 0x9c, 0xb7, 0x9b, 0x06, 0x37, 0x14, 0xca, - 0x75, 0xe7, 0x2e, 0x2e, 0x10, 0x0a, 0x10, 0xd6, 0x3b, 0xf7, 0x84, 0xdf, 0x08, 0x20, - 0xef, 0x25, 0xf8, 0xef, 0x40, 0xfe, 0x5f, 0x05, 0xfb, 0x95, 0x68, 0x3f, 0x91, 0x05, - 0xff, 0x3c, 0xb2, 0xd2, 0x19, 0xab, 0x76, 0x60, 0x5a, 0x06, 0x4f, 0x69, 0x21, 0x9f, - 0x1d, 0xc0, 0xd0, 0x0b, 0x3b, 0x48, 0x64, 0x2f, 0x97, 0x0d, 0xc0, 0x0c, 0xca, 0x4b, - 0x8b, 0x43, 0x30, 0x8b, 0xe1, 0x82, 0x86, 0xec, 0x5a, 0x42, 0x88, 0xd6, 0x00, 0xa3, - 0x78, 0x5c, 0xb6, 0x22, 0xd4, 0x68, 0xa4, 0xc6, 0x96, 0x9b, 0x37, 0x92, 0xf2, 0x48, - 0x50, 0x27, 0xd0, 0xad, 0x9a, 0xa4, 0xa9, 0xc2, 0xcc, 0x97, 0x2f, 0x9e, 0xe5, 0x19, - 0x0a, 0x95, 0xb1, 0xeb, 0x05, 0x8d, 0xdd, 0xd8, 0xc0, 0x8e, 0x7d, 0x75, 0x3f, 0x5e, - 0x01, 0x1b, 0x2b, 0xcf, 0xee, 0x1d, 0x52, 0xc1, 0xc4, 0xf2, 0xca, 0xcd, 0xa3, 0x0b, - 0xdb, 0x69, 0x30, 0x65, 0x3c, 0x0c, 0xc4, 0x48, 0x6e, 0x60, 0xe8, 0x9f, 0xa8, 0x49, - 0xb3, 0x20, 0x83, 0xba, 0x9d, 0xb4, 0x53, 0xfb, 0x8d, 0xf6, 0x83, 0xcd, 0x68, 0x75, - 0x4c, 0x87, 0xda, 0xa7, 0x31, 0xf5, 0x70, 0xa7, 0xa4, 0x06, 0x0a, 0xf0, 0xce, 0x70, - 0x0d, 0x31, 0xbc, 0xa7, 0xe7, 0x4b, 0x3e, 0x3b, 0xa3, 0xd0, 0xe8, 0xa6, 0x39, 0x2a, - 0x06, 0x2b, 0x8e, 0x86, 0xd9, 0xd7, 0xd0, 0x0b, 0x21, 0x70, 0x1e, 0x7b, 0x06, 0x2e, - 0x06, 0xb1, 0xbc, 0xd8, 0x2a, 0x01, 0xd3, 0x75, 0x62, 0x6f, 0xbf, 0x87, 0x2d, 0x27, - 0xfa, 0x45, 0x11, 0xf5, 0xf8, 0xcf, 0x8c, 0x9a, 0xbc, 0xef, 0x2a, 0x99, 0x01, 0x76, - 0xae, 0x33, 0x93, 0x25, 0xd5, 0xa5, 0x88, 0xda, 0x57, 0x96, 0xfa, 0xae, 0x5b, 0xab, - 0x7c, 0x82, 0x97, 0x7c, 0x0f, 0xf7, 0x97, 0x09, 0x3e, 0x2c, 0x1f, 0x3a, 0xe8, 0x55, - 0xf6, 0x5a, 0xea, 0x91, 0xe1, 0x31, 0x2f, 0xc6, 0xb8, 0xa4, 0x35, 0x1a, 0x2e, 0xc0, - 0x3e, 0x02, 0xe5, 0xd0, 0x2f, 0x53, 0x35, 0x4b, 0x05, 0x2f, 0xd3, 0xda, 0x0d, 0xff, - 0x82, 0xcd, 0x1f, 0x55, 0xeb, 0xca, 0x57, 0xb6, 0x33, 0x7c, 0x85, 0x93, 0x8a, 0x79, - 0x81, 0x3d, 0x20, 0x21, 0xd6, 0x09, 0x4c, 0x68, 0xb3, 0x75, 0xe9, 0x84, 0xf6, 0x83, - 0x93, 0x30, 0x08, 0x71, 0xe3, 0x48, 0xfc, 0x52, 0x36, 0xcc, 0xa6, 0x33, 0x05, 0x44, - 0xe5, 0x46, 0x39, 0xb5, 0x41, 0x87, 0x01, 0xff, 0x4c, 0xc4, 0x5a, 0x31, 0xf6, 0x2e, - 0xdd, 0x84, 0x3d, 0xbb, 0xdc, 0x5a, 0xa7, 0x27, 0xab, 0x79, 0xb4, 0x42, 0x68, 0x3c, - 0x49, 0x56, 0xbb, 0xb1, 0x95, 0xa4, 0xfa, 0x66, 0xdc, 0x9c, 0xd5, 0x42, 0xc7, 0x6b, - 0x91, 0x50, 0xc8, 0x4b, 0xf8, 0x90, 0x78, 0x99, 0x42, 0xf5, 0x5c, 0x20, 0x0b, 0x77, - 0x3e, 0xcd, 0xd7, 0x99, 0x2c, 0xff, 0x3e, 0xca, 0x24, 0xde, 0x3e, 0x09, 0x84, 0xe1, - 0x0e, 0x68, 0xae, 0x38, 0x75, 0x34, 0xb9, 0x6c, 0xde, 0x37, 0x92, 0xf1, 0x35, 0xbf, - 0x5f, 0x68, 0x78, 0x7d, 0x37, 0x0c, 0xa8, 0xc4, 0xc4, 0x07, 0x4d, 0xc5, 0xd6, 0x01, - 0xae, 0x90, 0x49, 0x54, 0x37, 0xc3, 0xc2, 0xd4, 0x8a, 0x3d, 0x96, 0x66, 0x83, 0xac, - 0x05, 0x16, 0x0b, 0x7a, 0x84, 0xea, 0xa7, 0xaa, 0xb7, 0x40, 0x09, 0xe5, 0x7a, 0x85, - 0xf7, 0xbf, 0x68, 0xa2, 0xe4, 0x82, 0x00, 0x0f, 0x82, 0x9c, 0x54, 0x50, 0x73, 0xa1, - 0x5d, 0x5c, 0xd0, 0xfc, 0xc5, 0x74, 0x39, 0xa4, 0x35, 0x0e, 0xaf, 0x09, 0x8d, 0xfb, - 0x82, 0xa0, 0x85, 0xea, 0x8a, 0x4a, 0xf6, 0xfa, 0x83, 0x81, 0xf0, 0x65, 0x88, 0x19, - 0xea, 0xb4, 0x83, 0xf6, 0x5b, 0x32, 0x5d, 0x5a, 0xed, 0xa1, 0x52, 0x32, 0xcf, 0xad, - 0xec, 0x75, 0xab, 0x18, 0x66, 0xe4, 0xc0, 0x15, 0x5a, 0x9c, 0x74, 0xa7, 0xa5, 0x7c, - 0xcf, 0x34, 0xc4, 0x83, 0xac, 0x7d, 0xa1, 0x58, 0x8a, 0x1b, 0x6b, 0x02, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x41, 0xf1, 0x10, 0x40, 0xf9, 0x4c, 0xf7, 0x8f, 0xad, 0x89, 0xbf, 0x11, 0xfe, 0xd6, - 0x9a, 0xa0, 0xd8, 0x31, 0x05, 0xad, 0xac, 0xdd, 0x4e, 0x5f, 0x04, 0xa6, 0x24, 0x24, - 0x02, 0x3c, 0x9b, 0x9e, 0x33, 0xc4, 0xfb, 0x7f, 0x12, 0xbd, 0xf2, 0x1f, 0x07, 0xf2, - 0x65, 0xc5, 0x37, 0xd5, 0x1c, 0x65, 0x51, 0xf4, 0x61, 0x7b, 0x91, 0x5d, 0x21, 0x99, - 0x18, 0x39, 0xc3, 0xd0, 0xd3, 0x63, 0x93, 0xd6, 0x46, 0xe0, 0xa8, 0xa4, 0x15, 0x09, - 0x21, 0x7d, 0x0e, 0x7d, 0x2c, 0xa1, 0xa0, 0xa0, 0xd6, 0x77, 0xa3, 0xea, 0xca, 0x23, - 0xed, 0xeb, 0x07, 0xb7, 0x4e, 0x65, 0x2a, 0x0b, 0xc5, 0x0c, 0x6c, 0x08, 0x3a, 0x55, - 0xd6, 0xc7, 0x30, 0x6e, 0x74, 0x08, 0x6f, 0x47, 0x68, 0x93, 0x3a, 0xa2, 0x48, 0x73, - 0x68, 0x18, 0x67, 0xa7, 0x89, 0x3d, 0x77, 0xcb, 0x7f, 0x29, 0xb8, 0xc8, 0x47, 0xc5, - 0x83, 0xf2, 0xd0, 0x71, 0xa6, 0x86, 0x61, 0x6e, 0x20, 0x67, 0x19, 0xf7, 0x61, 0xae, - 0x39, 0xc1, 0x10, 0x44, 0x2e, 0x06, 0x16, 0x3d, 0x2b, 0x84, 0x59, 0x03, 0x60, 0x69, - 0x5d, 0x4e, 0x19, 0x84, 0x9e, 0x63, 0x4f, 0x24, 0xd9, 0xad, 0x39, 0x6c, 0x19, 0xff, - 0x83, 0xce, 0x74, 0xf4, 0x6e, 0x64, 0x5f, 0x93, 0x2e, 0x14, 0x1a, 0x41, 0x19, 0x59, - 0x36, 0xc8, 0x5d, 0x51, 0x44, 0x14, 0xf1, 0x12, 0xe6, 0x0b, 0x1a, 0x25, 0x37, 0xc3, - 0x8d, 0x6d, 0xc6, 0xc4, 0x63, 0x83, 0x05, 0xc9, 0xbd, 0x6c, 0x62, 0xe3, 0x66, 0xbc, - 0x63, 0x12, 0x3e, 0x3e, 0x6d, 0xd3, 0x6e, 0xed, 0xd3, 0x13, 0x6f, 0xce, 0x8d, 0xee, - 0xca, 0x2a, 0xa0, 0x9a, 0x32, 0x98, 0xa3, 0x9d, 0x83, 0x85, 0x9e, 0xfc, 0x9b, 0x2b, - 0x69, 0xcf, 0x9a, 0x7d, 0xee, 0x08, 0xa9, 0x8e, 0x4b, 0xe5, 0x58, 0xac, 0x79, 0x12, - 0xfd, 0xcb, 0x42, 0x20, 0x90, 0x75, 0x42, 0x02, 0x60, 0xf7, 0xca, 0xd0, 0xf2, 0xc0, - 0x1f, 0x2a, 0xfe, 0x33, 0x07, 0x3f, 0x26, 0x24, 0x9d, 0x94, 0x4f, 0x7a, 0x50, 0xdd, - 0x84, 0x83, 0x9b, 0xc3, 0xea, 0x7f, 0xde, 0xe4, 0xed, 0x71, 0x44, 0x9c, 0xf0, 0x75, - 0x33, 0xd2, 0x6e, 0x1e, 0x27, 0xa3, 0xef, 0xb0, 0x32, 0xc3, 0xa3, 0xb3, 0x4b, 0xd3, - 0x09, 0x26, 0x22, 0xd2, 0x06, 0x2a, 0xe5, 0x36, 0xef, 0x51, 0x49, 0xc4, 0x9b, 0x5b, - 0xc9, 0x47, 0x5e, 0xaf, 0xab, 0x6e, 0x67, 0x57, 0x61, 0x00, 0x8b, 0x0d, 0xad, 0xde, - 0xec, 0xaa, 0x60, 0x44, 0x70, 0xbb, 0xe0, 0xfa, 0xda, 0x25, 0x5d, 0x29, 0x0e, 0x92, - 0xb1, 0x90, 0xc2, 0xc2, 0xd8, 0xc2, 0xde, 0xe5, 0x45, 0x5d, 0x1f, 0xa9, 0xa9, 0xf3, - 0xdb, 0x77, 0x79, 0xb5, 0x84, 0x64, 0x34, 0x64, 0xaa, 0x80, 0x14, 0xba, 0x66, 0x99, - 0x4d, 0xe2, 0x55, 0x17, 0xf8, 0x39, 0x80, 0xe6, 0x6e, 0xe4, 0xf6, 0x23, 0x14, 0xae, - 0x6d, 0xbe, 0xf4, 0x52, 0xd5, 0xd3, 0x8b, 0x0a, 0x16, 0xf3, 0x99, 0x1f, 0x36, 0xd8, - 0xa8, 0xb3, 0x9d, 0xdc, 0x0d, 0x55, 0x95, 0xee, 0xd9, 0x87, 0x62, 0x87, 0x8c, 0xdf, - 0x3f, 0x4a, 0x2e, 0xdc, 0x5c, 0xda, 0x77, 0xd5, 0xfe, 0x4f, 0xaf, 0x63, 0xa1, 0x5f, - 0x56, 0x8a, 0x54, 0x0d, 0xa5, 0x7d, 0xd9, 0xbe, 0xb6, 0xfb, 0x1a, 0x97, 0x7c, 0xcb, - 0x91, 0xb4, 0xd7, 0x9c, 0xb3, 0x9b, 0x28, 0x91, 0x1a, 0x29, 0xe7, 0xbf, 0x02, 0x8a, - 0xc6, 0x10, 0x37, 0x96, 0xdf, 0xb6, 0xb2, 0x09, 0x67, 0x23, 0x9a, 0xd3, 0x73, 0xc3, - 0x8c, 0x53, 0xf6, 0xdf, 0x18, 0x23, 0xd4, 0x95, 0x0a, 0x02, 0x83, 0xe9, 0x9b, 0x9c, - 0x06, 0xab, 0x29, 0x66, 0x66, 0x7c, 0x9d, 0xf6, 0x77, 0x71, 0x6b, 0x0c, 0xad, 0xed, - 0x81, 0x8d, 0xf9, 0xe4, 0x49, 0xc0, 0x72, 0xe2, 0x2f, 0x9d, 0x98, 0xbb, 0x0f, 0x9b, - 0x03, 0xbd, 0x5f, 0xd0, 0x13, 0xfc, 0xef, 0x3e, 0xd6, 0xa4, 0x9a, 0xeb, 0x98, 0x72, - 0x02, 0x54, 0x08, 0x7e, 0xf7, 0x28, 0xe3, 0x19, 0x47, 0xff, 0xe8, 0xf7, 0x66, 0xe6, - 0x3e, 0xe4, 0x6f, 0xf2, 0x08, 0x16, 0xd5, 0xfa, 0x8f, 0xf5, 0x5a, 0x26, 0x39, 0x89, - 0x61, 0x49, 0x0a, 0xb9, 0xae, 0x36, 0x6f, 0xc5, 0xa2, 0xd1, 0x99, 0x6e, 0xd6, 0x93, - 0xcc, 0xca, 0x82, 0x35, 0x6f, 0x60, 0x0a, 0xb0, 0x99, 0xf6, 0xec, 0xa8, 0xbf, 0xe6, - 0x45, 0x27, 0x0d, 0x3f, 0x95, 0xed, 0xba, 0x5b, 0x0d, 0xe7, 0xa3, 0x28, 0x19, 0x23, - 0x3b, 0xcc, 0x75, 0x4a, 0x5c, 0xe2, 0xe5, 0xea, 0x07, 0x84, 0x2e, 0x5f, 0xf2, 0xce, - 0xbe, 0x62, 0xad, 0x76, 0xe8, 0xef, 0xf8, 0xd1, 0x5e, 0xa4, 0xc2, 0x4a, 0x5f, 0x20, - 0x78, 0x68, 0x31, 0x9a, 0x5a, 0xf6, 0xb0, 0x35, 0xbe, 0x3f, 0x44, 0xf4, 0x34, 0x09, - 0x4f, 0x6e, 0x52, 0x5b, 0xe6, 0x14, 0xda, 0xc9, 0x20, 0xa3, 0x30, 0xbd, 0xfb, 0x26, - 0xd7, 0x5f, 0xe7, 0xb4, 0xb3, 0x65, 0xd0, 0x94, 0x45, 0x92, 0x50, 0xaa, 0xa5, 0x54, - 0x44, 0x89, 0xfb, 0x1d, 0x99, 0x25, 0x81, 0x80, 0x0a, 0x77, 0xb8, 0x91, 0x21, 0x57, - 0xfc, 0x97, 0x13, 0xaa, 0xac, 0x25, 0xb4, 0xc2, 0x6e, 0xb0, 0x3f, 0x71, 0x66, 0x46, - 0x61, 0x9a, 0xf0, 0x24, 0x56, 0xae, 0x69, 0x59, 0x62, 0xfe, 0x5e, 0x93, 0x1a, 0x63, - 0xb5, 0xc7, 0x90, 0x52, 0xec, 0xd3, 0x33, 0xe1, 0x84, 0x12, 0xdb, 0x91, 0xe1, 0x5f, - 0x7c, 0xbc, 0x70, 0xb4, 0xcd, 0x7e, 0x8e, 0x3c, 0x95, 0x1f, 0x35, 0x85, 0x72, 0xe3, - 0x77, 0x67, 0xe7, 0xd5, 0x27, 0x04, 0xa6, 0x72, 0x1b, 0x30, 0xef, 0xc4, 0x10, 0x17, - 0xae, 0x4d, 0x23, 0x15, 0x58, 0xc5, 0xc8, 0x2c, 0xc7, 0xdd, 0x7e, 0x33, 0x56, 0xc0, - 0x9d, 0xc2, 0x49, 0x06, 0xf0, 0x43, 0x8d, 0xfc, 0xc3, 0x00, 0x85, 0x6a, 0xc2, 0xce, - 0xd8, 0xf7, 0x7f, 0xa8, 0x01, 0x57, 0x36, 0xc6, 0x61, 0xe8, 0x02, 0x48, 0xae, 0xeb, - 0x77, 0x48, 0x74, 0xaa, 0x79, 0xd2, 0x90, 0xb8, 0xf5, 0x02, 0x7a, 0x0a, 0x50, 0x95, - 0x37, 0xfc, 0x7c, 0x68, 0x9b, 0x7a, 0xd8, 0x61, 0x16, 0xcf, 0xec, 0x26, 0x47, 0xcc, - 0xaa, 0xe1, 0xc7, 0x4b, 0x41, 0x6f, 0x3e, 0x6a, 0xe8, 0xf7, 0xcc, 0x60, 0xea, 0xaf, - 0x7b, 0x6a, 0x59, 0x0d, 0x51, 0x54, 0x41, 0x38, 0xe1, 0x73, 0x29, 0x45, 0x60, 0x3a, - 0x53, 0x46, 0x2c, 0x60, 0xe1, 0xf6, 0xcb, 0x0c, 0x9c, 0xa0, 0x39, 0x0c, 0x48, 0x82, - 0x24, 0xc3, 0x13, 0x26, 0x9f, 0xcd, 0x59, 0xfc, 0xb6, 0x11, 0xfb, 0x2d, 0x9b, 0x4c, - 0x8f, 0xa6, 0x01, 0xbb, 0x1c, 0xb8, 0xd0, 0x7d, 0x79, 0x7b, 0xf5, 0xde, 0x52, 0xbc, - 0xee, 0xb0, 0x23, 0x01, 0xc8, 0x96, 0x2a, 0xc1, 0xfc, 0x04, 0x91, 0xdc, 0x81, 0xaf, - 0xfd, 0x6c, 0x1e, 0xbf, 0x89, 0xa1, 0x3d, 0x6f, 0x29, 0x0e, 0xda, 0x5d, 0x5c, 0xef, - 0x38, 0x22, 0x15, 0xc5, 0xe9, 0x51, 0xd7, 0x13, 0x05, 0xef, 0x33, 0xd9, 0x73, 0x71, - 0x26, 0xd0, 0xe6, 0x62, 0x90, 0x5f, 0x12, 0x50, 0x92, 0x6f, 0x6a, 0x22, 0x99, 0x90, - 0xe3, 0x8f, 0x69, 0xad, 0x9a, 0x91, 0x92, 0xb3, 0x02, 0xf2, 0x6b, 0xdd, 0xa4, 0x65, - 0xd9, 0x0b, 0x94, 0xb1, 0x2c, 0x57, 0xfa, 0x3f, 0xd6, 0x93, 0x00, 0x83, 0xf1, 0x84, - 0x43, 0x8d, 0x8a, 0x88, 0x9d, 0x3f, 0x5e, 0xce, 0xa2, 0xc6, 0xd2, 0x3d, 0x67, 0x36, - 0xf2, 0xa0, 0xf1, 0x8e, 0x26, 0xf4, 0xfa, 0x45, 0xd1, 0xbe, 0x8f, 0x3d, 0xc4, 0xa7, - 0x07, 0x13, 0x7e, 0x95, 0xd2, 0xad, 0x59, 0x4f, 0x6c, 0x03, 0xd2, 0x49, 0x23, 0x06, - 0x7a, 0xe4, 0x7f, 0xd6, 0x42, 0x5e, 0xfb, 0x9c, 0x1d, 0x50, 0x4e, 0x6f, 0xd5, 0x57, - 0x53, 0x40, 0x94, 0x56, 0x01, 0xfe, 0x80, 0x6f, 0x57, 0x56, 0xac, 0xb5, 0x62, 0xf1, - 0x3c, 0x0c, 0xa1, 0xd8, 0x03, 0xa1, 0x95, 0xc2, 0xeb, 0xb2, 0xef, 0x02, 0xac, 0x33, - 0xe6, 0xa8, 0x8d, 0xea, 0x07, 0x5b, 0xa9, 0x96, 0xd3, 0xc3, 0x36, 0x64, 0x8e, 0x86, - 0x94, 0xd3, 0xa1, 0x9d, 0x3d, 0xca, 0x53, 0x1b, 0xeb, 0x50, 0xd4, 0x32, 0x7c, 0x5c, - 0x0c, 0x23, 0xcb, 0x7c, 0xfd, 0xb0, 0x8c, 0xa7, 0xcf, 0x2c, 0xac, 0x6b, 0xc1, 0x39, - 0xd0, 0x74, 0x14, 0x73, 0xd3, 0x76, 0x02, 0x9c, 0xb4, 0xab, 0x6b, 0xf0, 0x54, 0x55, - 0x7c, 0xe2, 0x94, 0xc7, 0x28, 0xa4, 0x68, 0x7d, 0x57, 0xec, 0x89, 0x09, 0xff, 0x51, - 0xa4, 0xd0, 0x2f, 0x9d, 0xcd, 0x11, 0x19, 0x3d, 0x7d, 0x1c, 0x9f, 0xda, 0xe6, 0xa1, - 0x73, 0x96, 0xa1, 0xbf, 0x57, 0xa9, 0x94, 0x93, 0x4f, 0x5e, 0x7a, 0x59, 0xf0, 0x45, - 0xde, 0xbe, 0xaf, 0xf6, 0x2e, 0xf3, 0x26, 0xb9, 0x47, 0xf2, 0xa8, 0xb4, 0x95, 0x55, - 0xe4, 0xd9, 0x9b, 0x3b, 0xf5, 0xc8, 0x1f, 0xf9, 0xfe, 0x31, 0x4e, 0x04, 0x7a, 0xf1, - 0x52, 0x50, 0x8f, 0x57, 0x01, 0x5c, 0xa4, 0x02, 0xc6, 0x7d, 0x92, 0x5c, 0x99, 0xac, - 0xea, 0x3e, 0xe8, 0xcc, 0x4b, 0x00, 0x8c, 0x5c, 0xb4, 0x39, 0x66, 0xe7, 0x14, 0xef, - 0x48, 0x0f, 0xd0, 0x5e, 0x07, 0xc7, 0xb2, 0xdd, 0xa9, 0xaa, 0x39, 0x66, 0x11, 0x3e, - 0xaa, 0x29, 0x3d, 0x3f, 0x62, 0x2b, 0x30, 0x9d, 0x64, 0x80, 0x3c, 0xe1, 0xe6, 0x37, - 0x8b, 0x6a, 0xac, 0x4f, 0xab, 0x52, 0x7c, 0x43, 0xcd, 0x45, 0xed, 0x0a, 0x3c, 0x1a, - 0x4b, 0x9f, 0xb1, 0x8d, 0xcc, 0xcf, 0xcd, 0xb6, 0xac, 0x0c, 0x24, 0x21, 0x63, 0x9c, - 0xda, 0x00, 0x75, 0xa2, 0x0d, 0xc5, 0x11, 0x1b, 0x8d, 0x3d, 0x31, 0x99, 0x49, 0x5b, - 0xd9, 0x13, 0x3d, 0xba, 0xb9, 0x45, 0x41, 0x41, 0x0e, 0x4f, 0xba, 0x92, 0xc7, 0xb6, - 0x06, 0xa5, 0xcb, 0x12, 0x2f, 0x14, 0x0c, 0xf1, 0xa3, 0x59, 0x6f, 0x27, 0x88, 0xf3, - 0xc8, 0xb9, 0x26, 0x60, 0xf1, 0x4c, 0xb6, 0x5a, 0xf5, 0xdd, 0x23, 0xdf, 0xdb, 0xac, - 0x13, 0x71, 0xec, 0xf4, 0xb3, 0x37, 0x12, 0xfe, 0xd2, 0x29, 0x2c, 0x44, 0xf7, 0x08, - 0x34, 0xcf, 0x96, 0xc0, 0x5d, 0x58, 0x82, 0x7e, 0x69, 0xbf, 0xc2, 0xe6, 0x96, 0xfa, - 0x08, 0x74, 0x86, 0x9c, 0x02, 0xf3, 0xdc, 0xa1, 0x1c, 0x3b, 0x90, 0xcb, 0x21, 0x4e, - 0x68, 0xbc, 0x1c, 0xae, 0x03, 0x9d, 0x7a, 0x14, 0x6c, 0xdc, 0x1d, 0x60, 0x9d, 0x7a, - 0x6b, 0x3f, 0xd5, 0xd4, 0x61, 0xb0, 0x95, 0x1c, 0x82, 0xcf, 0xb3, 0xe7, 0x63, 0xfa, - 0xd2, 0xd1, 0xbc, 0x76, 0x78, 0xcd, 0xf8, 0x27, 0x79, 0xf8, 0xfd, 0x5a, 0x1c, 0xe2, - 0x2a, 0x8d, 0x3c, 0x45, 0x47, 0xab, 0xd9, 0x59, 0x83, 0x8a, 0x46, 0xfb, 0x80, 0xaf, - 0xe0, 0x1f, 0x8e, 0xcc, 0x99, 0x31, 0x51, 0x3b, 0x19, 0x62, 0xec, 0x54, 0x08, 0x56, - 0xcb, 0x18, 0x93, 0x87, 0xcf, 0xbf, 0xcc, 0x0f, 0x7c, 0x68, 0x22, 0x3c, 0xba, 0x47, - 0xfb, 0x0c, 0x9b, 0x48, 0x6e, 0x4d, 0x99, 0x17, 0x19, 0x41, 0xf7, 0x67, 0x5a, 0x8b, - 0x46, 0x32, 0x8a, 0x3b, 0xc1, 0x09, 0xbf, 0x07, 0xc6, 0x6d, 0x5e, 0xde, 0x77, 0x1c, - 0xc4, 0xc7, 0x4c, 0xe8, 0x03, 0x33, 0x82, 0x91, 0x91, 0xee, 0xdc, 0x49, 0x35, 0x08, - 0xa6, 0x44, 0x53, 0x0a, 0x61, 0x44, 0xf2, 0x2d, 0xcf, 0x97, 0x52, 0x5a, 0x4c, 0xdc, - 0xa1, 0xad, 0x71, 0x07, 0x3b, 0x08, 0x0b, 0x73, 0xea, 0x45, 0x49, 0xf5, 0x40, 0x1b, - 0xff, 0x43, 0x18, 0x26, 0x8e, 0x6a, 0xd6, 0x37, 0x36, 0x31, 0x57, 0xa1, 0x9a, 0x53, - 0xf1, 0x23, 0xa0, 0xb0, 0xe1, 0x6d, 0x0b, 0x77, 0xf0, 0x20, 0x28, 0xda, 0x46, 0x41, - 0x00, 0xfd, 0xe7, 0x6d, 0x83, 0xdd, 0x0b, 0xb2, 0x24, 0xf7, 0xb5, 0x7a, 0x00, 0xc0, - 0x2f, 0x68, 0xae, 0x64, 0x8f, 0xdc, 0x52, 0x99, 0x57, 0xa1, 0x04, 0x90, 0xdc, 0xe1, - 0xfd, 0xdb, 0xb0, 0x90, 0x4f, 0x0d, 0x51, 0x8b, 0xb3, 0x87, 0x54, 0x40, 0x19, 0x98, - 0x3b, 0x61, 0x69, 0x75, 0xa7, 0x8e, 0x74, 0xd8, 0x54, 0xfd, 0xdc, 0x49, 0xb2, 0x55, - 0x16, 0x7b, 0x55, 0xef, 0x4b, 0xee, 0x46, 0x56, 0x68, 0xb2, 0x0e, 0xa4, 0x11, 0x8c, - 0xa5, 0x69, 0xae, 0x48, 0x0e, 0x0f, 0x6e, 0x5e, 0x04, 0x3a, 0x35, 0x7b, 0x36, 0xd3, - 0xab, 0x36, 0xc8, 0x61, 0xf2, 0x27, 0x83, 0x01, 0xdc, 0xe5, 0x76, 0x74, 0xd5, 0x07, - 0x3b, 0x3a, 0x6f, 0x51, 0x03, 0xa0, 0x79, 0x3a, 0xf1, 0xb7, 0xd4, 0x6f, 0x95, 0x7e, - 0x22, 0xd8, 0xd2, 0x58, 0x3b, 0xf1, 0x81, 0x83, 0x6c, 0x3b, 0xe9, 0x93, 0x0b, 0xac, - 0x8f, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x60, 0xe9, 0x68, 0xaa, 0x71, 0x09, 0x87, 0x0b, 0xbe, 0xd1, - 0x7d, 0xf5, 0xf8, 0x88, 0xc8, 0xca, 0x14, 0x67, 0xae, 0x17, 0xdb, 0xbc, 0xde, 0x31, - 0xc1, 0x10, 0x5c, 0xb5, 0xbd, 0xa8, 0x8a, 0xc6, 0xc6, 0x27, 0x00, 0x2c, 0xe2, 0x1c, - 0x02, 0x14, 0x0f, 0xfe, 0x81, 0xec, 0x58, 0xbf, 0x1e, 0x6d, 0x1b, 0xb7, 0xaa, 0xad, - 0xa4, 0x1f, 0xba, 0x0b, 0xb5, 0x88, 0x77, 0x8a, 0x7f, 0x65, 0x20, 0x2a, 0xd8, 0x11, - 0xea, 0x73, 0xd2, 0x6c, 0x74, 0x55, 0x03, 0x95, 0xaf, 0xf7, 0x53, 0x25, 0x10, 0x7c, - 0x9b, 0x3f, 0x9a, 0xe9, 0xdc, 0xdc, 0xd8, 0x6e, 0xd0, 0x81, 0xa2, 0xe7, 0x42, 0x47, - 0x19, 0xa3, 0xd1, 0x85, 0xb7, 0xe0, 0xa4, 0x3a, 0x47, 0x2e, 0x29, 0x8a, 0xc0, 0xaf, - 0xdc, 0x52, 0x87, 0xd7, 0xad, 0x12, 0x4c, 0xd9, 0x40, 0x5a, 0x62, 0xcd, 0x1c, 0xa0, - 0x8b, 0x28, 0x2e, 0xfe, 0xf7, 0xf9, 0x28, 0xdf, 0x76, 0xe2, 0x82, 0x1a, 0x41, 0x84, - 0x13, 0xeb, 0x7c, 0xea, 0xa5, 0xff, 0x12, 0x90, 0xb0, 0x3e, 0xc9, 0x1c, 0xe6, 0xdd, - 0x28, 0x13, 0x0c, 0x3a, 0xb0, 0xb2, 0x3b, 0x60, 0x2b, 0xd5, 0xbe, 0x5d, 0xc2, 0x60, - 0x03, 0xaa, 0xe0, 0x4b, 0x33, 0xd7, 0xbd, 0x25, 0x90, 0xe9, 0x0c, 0x8c, 0x38, 0x8e, - 0xa7, 0x95, 0x51, 0x22, 0xdb, 0xac, 0xa6, 0x7b, 0x30, 0x39, 0x5a, 0x92, 0x8b, 0x57, - 0xb8, 0x57, 0x51, 0x23, 0x20, 0x5a, 0xe1, 0x91, 0x52, 0xe4, 0x1e, 0x00, 0x29, 0x31, - 0xb4, 0x57, 0x46, 0x19, 0x8e, 0x5d, 0xd9, 0x57, 0x1a, 0x56, 0xa7, 0xe0, 0xd4, 0x23, - 0xff, 0x27, 0x98, 0x9d, 0x3e, 0xb4, 0x17, 0xec, 0xd3, 0xc3, 0x09, 0x3f, 0xb8, 0x2c, - 0x56, 0x58, 0xe2, 0x96, 0x24, 0xc5, 0x32, 0x19, 0xa6, 0x0c, 0xd0, 0xa8, 0xc4, 0xda, - 0x36, 0x7e, 0x29, 0xa7, 0x17, 0x79, 0xa7, 0x30, 0x32, 0x98, 0x5a, 0x3d, 0x1f, 0xd0, - 0x3d, 0xd4, 0xd0, 0x6e, 0x05, 0x56, 0x6f, 0x3b, 0x84, 0x36, 0x7c, 0xf0, 0xfa, 0xee, - 0x9b, 0xc3, 0xbd, 0x7a, 0x3a, 0x60, 0x6a, 0x9f, 0xdb, 0x84, 0x9c, 0x5d, 0x82, 0xd0, - 0xa6, 0x19, 0x23, 0xc2, 0xe5, 0xd8, 0xaa, 0x63, 0xa8, 0xa5, 0x0c, 0x38, 0xbd, 0x03, - 0x87, 0x72, 0xc4, 0x14, 0x3d, 0x8b, 0x7a, 0xcf, 0xd7, 0x4e, 0x72, 0xc0, 0x4d, 0x89, - 0x24, 0x8d, 0xff, 0x20, 0xfe, 0x8d, 0xc5, 0xec, 0x21, 0x49, 0x05, 0x4e, 0xa2, 0x41, - 0x64, 0xe8, 0x5f, 0x67, 0x44, 0xad, 0x0c, 0xac, 0xf1, 0xa8, 0xb7, 0x01, 0x26, 0xf4, - 0x82, 0xc0, 0x92, 0xed, 0x9f, 0x61, 0x27, 0xd2, 0x05, 0x0d, 0x12, 0xe8, 0x78, 0xa7, - 0x96, 0x53, 0xa1, 0xe8, 0x4d, 0xae, 0xc3, 0xeb, 0xe6, 0x2d, 0x5f, 0x6c, 0x4a, 0xbe, - 0x5c, 0xe9, 0x0a, 0x7f, 0xe2, 0xe5, 0x2a, 0x8d, 0x78, 0x46, 0xe8, 0xed, 0xf2, 0xf2, - 0xbc, 0xe0, 0x5a, 0x03, 0x7c, 0x82, 0x6f, 0x22, 0xca, 0xad, 0x12, 0x61, 0x46, 0x7d, - 0xcf, 0xb7, 0xd6, 0xb6, 0x13, 0x3d, 0xc2, 0x1e, 0x80, 0x96, 0xc7, 0xe9, 0xf8, 0xe9, - 0xe1, 0x0c, 0x1e, 0x3f, 0xac, 0x40, 0x58, 0xb6, 0x82, 0xc6, 0x8e, 0x54, 0xfa, 0xca, - 0xe0, 0xf9, 0xc2, 0xdd, 0x4d, 0x64, 0xd9, 0x04, 0x61, 0x52, 0xb4, 0x76, 0x23, 0x32, - 0x93, 0x9f, 0x17, 0xe6, 0xaa, 0xf7, 0xd8, 0xb9, 0xd3, 0x58, 0xe2, 0x21, 0x8d, 0x4e, - 0x0d, 0x69, 0xa4, 0xf1, 0x19, 0xe1, 0xc6, 0x4e, 0xec, 0x4c, 0x8b, 0x53, 0x28, 0x09, - 0x70, 0x71, 0x31, 0xf0, 0x1f, 0x55, 0xc7, 0xad, 0x04, 0xcf, 0xb6, 0x3f, 0x7c, 0x4a, - 0x3d, 0x0a, 0x2b, 0x0f, 0xfb, 0x0b, 0x05, 0xa6, 0xbe, 0x05, 0x5b, 0x8c, 0x94, 0xca, - 0x80, 0xbb, 0x0a, 0x1d, 0x13, 0xcd, 0x4c, 0xd6, 0x9a, 0xb9, 0x83, 0x04, 0xae, 0x25, - 0x15, 0xd5, 0xf7, 0x69, 0x9d, 0x4a, 0xbe, 0xe5, 0xc2, 0x0b, 0xe6, 0x09, 0xd8, 0x73, - 0x51, 0x10, 0x12, 0xf2, 0x34, 0xbd, 0x85, 0xa7, 0xef, 0xf5, 0xfb, 0x63, 0x4c, 0xff, - 0x26, 0x58, 0xba, 0x65, 0x16, 0x04, 0x85, 0x63, 0x09, 0x5e, 0xce, 0xfb, 0x30, 0x15, - 0xee, 0x3f, 0x03, 0xca, 0x52, 0xa1, 0x77, 0xf2, 0x61, 0xec, 0xdc, 0x26, 0xbc, 0x08, - 0x9d, 0x34, 0xc6, 0x40, 0x48, 0x46, 0xe9, 0xc6, 0x47, 0xfc, 0xfe, 0x98, 0xcc, 0x6a, - 0xcd, 0xbb, 0x46, 0x4f, 0x64, 0x27, 0x8a, 0xd8, 0xce, 0x9d, 0x1a, 0xe0, 0xd4, 0x15, - 0xbc, 0x0c, 0x05, 0x24, 0x5f, 0xdd, 0xaf, 0x4e, 0xbc, 0x8d, 0xc7, 0x03, 0xa8, 0x5c, - 0xb2, 0x70, 0xf7, 0x96, 0xad, 0x2d, 0x93, 0x7e, 0x2a, 0xc0, 0xd5, 0xe0, 0xa3, 0x48, - 0x21, 0x75, 0x80, 0x00, 0xaa, 0x59, 0xc9, 0xd4, 0x65, 0x24, 0x85, 0x29, 0x4e, 0xe0, - 0xab, 0x29, 0x69, 0x6b, 0x21, 0x43, 0x0f, 0xa5, 0x4d, 0xcf, 0xbf, 0x2b, 0x9c, 0x49, - 0xd1, 0x42, 0x06, 0x42, 0x09, 0xee, 0xee, 0xd4, 0xd4, 0x71, 0xff, 0xc0, 0x17, 0xd4, - 0xe2, 0x0a, 0x79, 0x6b, 0x09, 0x27, 0x80, 0x4c, 0x06, 0x1b, 0x9f, 0x4a, 0x70, 0x91, - 0xfe, 0x01, 0x5a, 0xda, 0x68, 0xfd, 0x84, 0x42, 0xe0, 0x18, 0x25, 0xc8, 0x8d, 0xfe, - 0x55, 0xcf, 0x5d, 0xe3, 0x89, 0x36, 0xf7, 0xce, 0x25, 0x31, 0x1b, 0x90, 0x2b, 0xa9, - 0x7a, 0x3c, 0x12, 0xa9, 0x5c, 0xfa, 0x1c, 0x3a, 0x59, 0x1b, 0x81, 0x8f, 0x60, 0x83, - 0x27, 0x09, 0xd9, 0xe4, 0x83, 0x9e, 0x41, 0x0f, 0xb3, 0x6b, 0x84, 0xf3, 0xac, 0x4f, - 0x07, 0x0f, 0xc3, 0x5e, 0x16, 0x19, 0x78, 0x25, 0x9e, 0x5b, 0x8e, 0xdc, 0x74, 0x4d, - 0x90, 0x91, 0x9a, 0xa7, 0x70, 0xbb, 0x36, 0x21, 0x51, 0x28, 0xe5, 0x82, 0xb5, 0x96, - 0x41, 0xe2, 0x38, 0x52, 0xe9, 0x58, 0xeb, 0x8f, 0xc3, 0xc0, 0xaa, 0x96, 0x15, 0x2b, - 0xa4, 0xf7, 0x7f, 0x13, 0x8d, 0x6a, 0x67, 0x12, 0xa3, 0xae, 0x32, 0x26, 0x01, 0x58, - 0x83, 0xf8, 0x1d, 0xb2, 0x3e, 0x58, 0x3c, 0x86, 0x9c, 0x4c, 0x71, 0x14, 0x3a, 0x6f, - 0xff, 0xd6, 0x5e, 0x8d, 0xfd, 0xc5, 0x0c, 0x99, 0xa2, 0xf1, 0xf3, 0x14, 0xcd, 0xcc, - 0x71, 0x35, 0x9e, 0x23, 0x5f, 0x1d, 0x7d, 0xc2, 0xb5, 0xf3, 0x8e, 0xf7, 0xb9, 0x70, - 0x84, 0x31, 0x63, 0xc0, 0x3f, 0x9d, 0xd4, 0x0a, 0x80, 0x15, 0xef, 0xdc, 0x87, 0x91, - 0x95, 0x6a, 0x3f, 0x3c, 0xed, 0xd9, 0xea, 0x64, 0xf8, 0xef, 0xa7, 0xa0, 0x81, 0x5a, - 0x70, 0x38, 0x1d, 0x71, 0x46, 0x78, 0x17, 0xbd, 0x04, 0xca, 0x52, 0x9a, 0xed, 0xe0, - 0x7f, 0xf6, 0x0d, 0x17, 0x6a, 0xed, 0x0f, 0x85, 0x5a, 0x2e, 0xae, 0xa8, 0x9e, 0xae, - 0xac, 0xa8, 0x93, 0x58, 0xc0, 0x81, 0x82, 0x6a, 0x08, 0x12, 0xa5, 0xbc, 0xa2, 0x8b, - 0xe1, 0x37, 0x3f, 0x08, 0x6d, 0xbd, 0xba, 0x7e, 0x43, 0xe2, 0x03, 0x21, 0x2c, 0x9f, - 0xed, 0x21, 0x47, 0x4b, 0xa1, 0x9a, 0x05, 0x5f, 0xfc, 0xc1, 0x79, 0x41, 0x2e, 0x89, - 0x3a, 0x74, 0x48, 0x32, 0x29, 0x8c, 0x5f, 0xe2, 0x4c, 0xc6, 0xb1, 0x86, 0x67, 0xf4, - 0x9b, 0x34, 0xdf, 0xb1, 0x23, 0x79, 0x26, 0x74, 0x19, 0xa9, 0xcb, 0x94, 0x03, 0xd8, - 0x16, 0x7d, 0x8d, 0x1e, 0x91, 0xd2, 0x81, 0x1a, 0x04, 0x3b, 0x29, 0x24, 0x3b, 0x06, - 0x9b, 0x37, 0x58, 0x78, 0x47, 0xdc, 0x6f, 0xcd, 0xdb, 0x18, 0x31, 0xbd, 0x1c, 0xc2, - 0x56, 0x7c, 0xa0, 0x33, 0xac, 0x40, 0xf7, 0x4a, 0xb6, 0x95, 0x5f, 0x68, 0x3b, 0x12, - 0xe4, 0xe8, 0x25, 0x4e, 0x4e, 0xa7, 0x60, 0xd3, 0x8b, 0x3f, 0x46, 0x79, 0x1c, 0x5c, - 0x4c, 0xb1, 0x2b, 0xc7, 0xcc, 0xb0, 0xed, 0x18, 0x65, 0xf2, 0x5d, 0x60, 0x1c, 0x30, - 0x3f, 0x81, 0xfb, 0x1f, 0xa1, 0xdb, 0x48, 0x53, 0x3d, 0x3d, 0x6b, 0x28, 0x8e, 0x4d, - 0x9a, 0x4d, 0xff, 0x8e, 0xc2, 0x1c, 0x96, 0xf5, 0x78, 0x39, 0x97, 0x10, 0xc8, 0x25, - 0xfe, 0x7e, 0x32, 0xf9, 0x3a, 0x8c, 0x07, 0x43, 0xf9, 0xeb, 0xd5, 0x4c, 0xc1, 0x51, - 0xc7, 0x61, 0x03, 0x37, 0xae, 0xbf, 0x7e, 0x9b, 0x91, 0x57, 0x20, 0xa5, 0x43, 0x51, - 0xd4, 0x9a, 0xb8, 0xc2, 0x2f, 0xa3, 0x49, 0x98, 0xdc, 0xf5, 0x83, 0xd4, 0x38, 0x73, - 0x61, 0xef, 0x3f, 0xf8, 0x6f, 0x50, 0xec, 0x53, 0xf4, 0x92, 0x49, 0xe4, 0xad, 0x34, - 0x96, 0x03, 0x06, 0x6f, 0xc9, 0xc6, 0x61, 0xd6, 0x9f, 0x91, 0x1d, 0xfa, 0x72, 0x41, - 0xc8, 0xd5, 0x79, 0x2d, 0x43, 0xc4, 0x57, 0xd5, 0xde, 0x96, 0x52, 0x3a, 0x53, 0xd6, - 0x67, 0xec, 0x5c, 0x4e, 0xf9, 0xd5, 0x02, 0xa1, 0x6f, 0x15, 0x22, 0x47, 0x58, 0x96, - 0xd7, 0x9b, 0xc5, 0x78, 0x33, 0xe9, 0x77, 0x17, 0x1c, 0x32, 0x4d, 0xce, 0x2a, 0x1e, - 0xa1, 0xe4, 0x30, 0x4f, 0x49, 0xe4, 0x3a, 0xe0, 0x65, 0xe3, 0xfb, 0x19, 0x6f, 0x76, - 0xd9, 0xb8, 0x79, 0xc7, 0x20, 0x08, 0x62, 0xea, 0xd1, 0x8d, 0xea, 0x5f, 0xb6, 0xa1, - 0x7a, 0xce, 0xa3, 0x33, 0x86, 0xeb, 0x4c, 0xa1, 0xb5, 0x14, 0x86, 0xa9, 0x14, 0x8f, - 0xbd, 0xf9, 0xa9, 0x53, 0x32, 0xaa, 0x60, 0x5c, 0x5d, 0x54, 0x83, 0xce, 0x4b, 0xa8, - 0xec, 0xe0, 0x1a, 0x8f, 0xf2, 0xb7, 0xef, 0x82, 0xd0, 0x5c, 0x0b, 0x6e, 0x86, 0x1b, - 0x91, 0x5f, 0x13, 0xca, 0x0e, 0xb3, 0xea, 0x13, 0xd5, 0x07, 0x08, 0x07, 0xa2, 0xcb, - 0x66, 0x80, 0xa2, 0x49, 0xea, 0x9c, 0x72, 0x24, 0x39, 0x2c, 0xbc, 0x8a, 0xb8, 0x25, - 0x01, 0xb2, 0x6f, 0x11, 0x2a, 0xc7, 0x89, 0xa1, 0x2a, 0x31, 0xad, 0x13, 0x14, 0xe2, - 0xed, 0xe0, 0x8f, 0xad, 0x31, 0x43, 0xaf, 0x30, 0xc2, 0x7f, 0x40, 0x3b, 0xc8, 0x66, - 0xc7, 0x55, 0x17, 0x78, 0x52, 0xaf, 0xd0, 0xab, 0xb9, 0x0a, 0xde, 0x1d, 0x68, 0x27, - 0x26, 0xf4, 0x20, 0x08, 0xb4, 0x6a, 0xd7, 0xf8, 0xab, 0xdb, 0x18, 0x11, 0x7f, 0x72, - 0x64, 0x13, 0x90, 0xf0, 0x86, 0xb6, 0xe1, 0x49, 0x8b, 0xe6, 0x95, 0x48, 0x52, 0x7e, - 0x6a, 0xda, 0x2b, 0x38, 0xb9, 0xfe, 0x12, 0x1e, 0xf6, 0x70, 0xaf, 0x74, 0x37, 0xd3, - 0x25, 0x36, 0xd5, 0xcf, 0x5c, 0x4a, 0xb1, 0x9d, 0xd9, 0x97, 0x71, 0x58, 0x2d, 0x03, - 0x81, 0x04, 0xb7, 0xe0, 0x39, 0xa3, 0x76, 0xf7, 0xac, 0xbb, 0xea, 0xdb, 0x34, 0xf9, - 0x45, 0xbe, 0xb9, 0xd7, 0xca, 0x0e, 0x4e, 0x3d, 0x5c, 0x5e, 0x4e, 0xb1, 0xd8, 0x52, - 0x6e, 0xbd, 0x13, 0xda, 0xcb, 0x1b, 0xa3, 0x57, 0x35, 0xc6, 0xd0, 0x4a, 0x45, 0x55, - 0xac, 0xf4, 0xbf, 0x11, 0x76, 0x26, 0x50, 0x0d, 0x77, 0xb3, 0x81, 0x89, 0xdd, 0x48, - 0x88, 0x04, 0x12, 0x25, 0xac, 0xbe, 0x38, 0x74, 0xa4, 0xc0, 0xf6, 0x07, 0xfe, 0x67, - 0x45, 0xf9, 0x35, 0x5b, 0x3f, 0xa1, 0x88, 0xf1, 0xd6, 0x5c, 0x09, 0xf3, 0x89, 0xaf, - 0x1b, 0x9d, 0x62, 0x32, 0xaa, 0x79, 0x44, 0x79, 0x19, 0xc5, 0x50, 0xf6, 0xf3, 0x1f, - 0xec, 0x35, 0x48, 0x1c, 0xb9, 0x22, 0xde, 0x2d, 0xb5, 0xb4, 0xda, 0x2f, 0x81, 0x94, - 0x86, 0x17, 0x02, 0x8e, 0x32, 0x17, 0x06, 0xa3, 0xa7, 0x78, 0xc1, 0x93, 0x8c, 0x44, - 0x3b, 0xb0, 0x0e, 0x5b, 0x0f, 0xf0, 0x6a, 0xd8, 0xab, 0x9b, 0x1a, 0xb0, 0xc1, 0x14, - 0x77, 0x67, 0x3f, 0x85, 0xdf, 0x95, 0x61, 0xdb, 0xea, 0x45, 0xd5, 0xf9, 0x78, 0x1e, - 0xbe, 0x31, 0x7a, 0x07, 0x10, 0xae, 0x54, 0x61, 0xe3, 0x4f, 0xe6, 0xf1, 0xb1, 0xaa, - 0x9b, 0x4e, 0x67, 0xb1, 0x49, 0x10, 0x98, 0x48, 0x02, 0xc2, 0xa7, 0xe3, 0x81, 0x93, - 0xbc, 0x7b, 0xdc, 0x8b, 0xa3, 0xe4, 0xe3, 0xd1, 0xd9, 0x33, 0xbf, 0xb5, 0x80, 0xf5, - 0xb3, 0xe8, 0x7a, 0x2a, 0x06, 0x51, 0x70, 0x51, 0x41, 0x0f, 0xe1, 0xb4, 0xff, 0x1e, - 0xa0, 0xad, 0xe8, 0x24, 0xf3, 0x38, 0x51, 0x54, 0x56, 0xa5, 0x7c, 0x7a, 0x91, 0x6a, - 0x74, 0x38, 0x8e, 0xe8, 0xf1, 0x28, 0x1f, 0x9a, 0xde, 0x0a, 0xe2, 0xa2, 0x61, 0x3a, - 0x06, 0x12, 0xc4, 0x69, 0xdf, 0x79, 0x2b, 0x8d, 0xf4, 0xca, 0xe4, 0xfc, 0x25, 0xc1, - 0xca, 0xdb, 0xa9, 0x5a, 0x80, 0x7c, 0xe6, 0x1e, 0x5a, 0x53, 0x03, 0xfa, 0xaf, 0x9e, - 0x14, 0x65, 0x39, 0x96, 0xb5, 0xa8, 0xad, 0xc3, 0x4f, 0xd4, 0x75, 0xef, 0x14, 0x99, - 0x09, 0x4b, 0xab, 0xaf, 0x1f, 0x3f, 0x07, 0xda, 0x9a, 0x39, 0x0b, 0x1d, 0x9f, 0xc9, - 0xa0, 0x83, 0x27, 0x98, 0x7a, 0xdf, 0xe9, 0x56, 0x48, 0x63, 0xfb, 0xdf, 0xa8, 0xf6, - 0xb4, 0x6a, 0x88, 0x41, 0x58, 0x30, 0x99, 0xaf, 0xb7, 0x87, 0x01, 0x18, 0xfa, 0xce, - 0x76, 0x34, 0x7e, 0x40, 0xb6, 0xfd, 0x8c, 0xd1, 0x55, 0x82, 0xae, 0x8e, 0x23, 0xbe, - 0x9a, 0x02, 0x19, 0xbc, 0x3e, 0x4e, 0x45, 0x46, 0xa3, 0x0d, 0x3b, 0xbb, 0xbd, 0x16, - 0x86, 0x08, 0x68, 0x76, 0xbe, 0x0e, 0x4c, 0x85, 0x9b, 0xe7, 0x1f, 0xb5, 0x8f, 0x4f, - 0xab, 0x3d, 0x28, 0xc0, 0xb4, 0xf7, 0xe7, 0x5a, 0xd1, 0xed, 0xb7, 0xf8, 0x89, 0x46, - 0xfb, 0x40, 0xcf, 0xa5, 0x78, 0x6a, 0x0f, 0xcb, 0xa1, 0x30, 0x3c, 0x83, 0x47, 0xec, - 0xee, 0x93, 0xd4, 0x6d, 0x14, 0x0b, 0xb5, 0xf6, 0x95, 0x31, 0xd6, 0x66, 0x54, 0x8b, - 0x10, 0x9c, 0xe7, 0x64, 0xbe, 0xad, 0x7c, 0x87, 0xbd, 0x4c, 0x87, 0x64, 0x94, 0xde, - 0x82, 0xdb, 0x6e, 0x50, 0x73, 0xa6, 0xc9, 0x4f, 0x7c, 0x09, 0x9a, 0x40, 0xd7, 0xa3, - 0x1c, 0x4a, 0x04, 0xb6, 0x9c, 0x9f, 0xcc, 0xf3, 0xc7, 0xdd, 0x56, 0xf5, 0x54, 0x47, - 0x76, 0xc5, 0x3b, 0x4d, 0xf7, 0x95, 0x39, 0x81, 0xd5, 0x5a, 0x96, 0xa6, 0xdc, 0xff, - 0x99, 0x04, 0xa9, 0x08, 0x42, 0xe5, 0xba, 0xfe, 0xc8, 0x84, 0x0c, 0x2d, - ], - script_code: vec![0x53, 0x63, 0x63, 0x51, 0xac, 0x00, 0x51], - transparent_input: None, - hash_type: 1, - amount: 1345602751504862, - consensus_branch_id: 1991772603, - sighash: [ - 0x15, 0x53, 0xd4, 0xf1, 0x07, 0x45, 0x10, 0x71, 0x81, 0x99, 0x00, 0x5f, 0xef, 0xaa, - 0xa8, 0x3e, 0x29, 0xd1, 0x63, 0xee, 0xbd, 0xf3, 0xc0, 0x33, 0x82, 0x79, 0x08, 0xac, - 0xb4, 0x6f, 0xa2, 0x4b, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x00, 0x01, 0x13, 0xf9, 0x12, 0xa5, - 0xdc, 0x0e, 0x00, 0x00, 0x09, 0x53, 0x53, 0xac, 0x63, 0x6a, 0x53, 0x63, 0xac, 0x6a, - 0x2f, 0x2c, 0x3b, 0x86, 0x0e, 0x40, 0xe3, 0x1c, 0x61, 0x8c, 0xa1, 0x7d, 0xf7, 0x15, - 0x04, 0x00, 0x01, 0x21, 0xbf, 0x07, 0x11, 0x5b, 0x3a, 0x39, 0xbb, 0x87, 0xf7, 0x23, - 0x91, 0x52, 0x4b, 0x82, 0x0e, 0xf3, 0x5c, 0xfc, 0x09, 0x58, 0xd4, 0x19, 0x2f, 0x49, - 0x59, 0xef, 0xe4, 0xb9, 0xa7, 0xb5, 0x29, 0x98, 0x8a, 0x3f, 0x7d, 0x27, 0x37, 0x91, - 0x49, 0x0a, 0x6b, 0x48, 0x49, 0x5a, 0x80, 0x06, 0x45, 0x5e, 0x86, 0x57, 0x71, 0xbe, - 0x92, 0x06, 0xd5, 0x4b, 0x43, 0x02, 0x4a, 0xf5, 0xe6, 0xc9, 0x5b, 0x33, 0xf6, 0xda, - 0xd1, 0x66, 0x6a, 0x05, 0xf9, 0x1a, 0xd7, 0x75, 0x79, 0x65, 0xc2, 0x99, 0x36, 0xe7, - 0xfa, 0x48, 0xd7, 0x7e, 0x89, 0xee, 0x09, 0x62, 0xf5, 0x8c, 0x05, 0x1d, 0x11, 0xd0, - 0x55, 0xfc, 0xe2, 0x04, 0xa5, 0x62, 0xde, 0x68, 0x08, 0x8a, 0x1b, 0x26, 0x48, 0xb8, - 0x17, 0x4c, 0xbc, 0xfc, 0x8b, 0x5b, 0x5c, 0xd0, 0x77, 0x11, 0x5a, 0xfd, 0xe1, 0x84, - 0x05, 0x05, 0x4e, 0x5d, 0xa9, 0xa0, 0x43, 0x10, 0x34, 0x2c, 0x5d, 0x3b, 0x52, 0x6e, - 0x0b, 0x02, 0xc5, 0xca, 0x17, 0x22, 0xba, 0xde, 0xee, 0x23, 0xd1, 0x45, 0xe8, 0xeb, - 0x22, 0x13, 0xfc, 0x4a, 0xf1, 0xe4, 0x50, 0xe4, 0xd5, 0x21, 0x7c, 0x66, 0x17, 0x00, - 0x8c, 0x78, 0xf4, 0xfb, 0x11, 0x12, 0xf4, 0x02, 0x8a, 0x70, 0x4f, 0xc5, 0xa9, 0x38, - 0x2c, 0x6b, 0x03, 0xe7, 0xd8, 0x08, 0x5e, 0x90, 0x6c, 0xf8, 0x4c, 0xa2, 0xc1, 0x20, - 0x7c, 0x87, 0xa2, 0xbc, 0xe2, 0x08, 0x0a, 0x98, 0x91, 0x66, 0x8d, 0x69, 0xb0, 0x44, - 0xbe, 0xce, 0xd6, 0xcd, 0xa3, 0x2c, 0x22, 0x9c, 0x91, 0x17, 0x91, 0x7a, 0xa0, 0x7d, - 0xdf, 0xfc, 0xd3, 0x77, 0x39, 0x5c, 0xba, 0x61, 0x6d, 0x63, 0xc0, 0xb6, 0x9c, 0x01, - 0xfc, 0xc4, 0x53, 0x91, 0xfd, 0x5b, 0x87, 0x63, 0xfb, 0x96, 0xd7, 0xca, 0x33, 0x3a, - 0x12, 0xde, 0x3c, 0xef, 0xa9, 0x1c, 0x6c, 0x98, 0xf9, 0x47, 0x3b, 0x8e, 0x10, 0x4a, - 0x71, 0x29, 0x3e, 0x46, 0x37, 0x47, 0x05, 0xba, 0xf6, 0x5f, 0xa4, 0x13, 0x84, 0xba, - 0x5c, 0x8e, 0x0c, 0x88, 0xa3, 0xeb, 0x07, 0xe0, 0xbe, 0x34, 0xda, 0xdd, 0xfa, 0xbb, - 0x7b, 0x65, 0x54, 0x3b, 0x5f, 0x39, 0xcb, 0x20, 0x23, 0xd4, 0x67, 0x89, 0xeb, 0x7d, - 0x98, 0x9a, 0xf7, 0x79, 0xe5, 0xb8, 0xd2, 0x83, 0x85, 0xa8, 0x5b, 0x0d, 0xa2, 0xab, - 0xe0, 0x7f, 0x0c, 0x2b, 0xb4, 0x25, 0x5f, 0xce, 0xa0, 0x31, 0x88, 0x52, 0x7a, 0x30, - 0x7d, 0x40, 0x91, 0x59, 0xe9, 0x01, 0x66, 0xfa, 0xc6, 0xa0, 0x70, 0xba, 0x05, 0xb3, - 0xe4, 0xdb, 0xfd, 0x3a, 0x2b, 0xfc, 0xc9, 0xee, 0x6e, 0xd0, 0x16, 0xc0, 0xf6, 0x65, - 0xbe, 0x81, 0x33, 0xb7, 0xdc, 0x1d, 0x86, 0x04, 0x4d, 0xb0, 0xf9, 0xdb, 0x40, 0xfb, - 0x0e, 0x9f, 0x8b, 0xc2, 0xe4, 0xdb, 0x53, 0x82, 0xa8, 0x04, 0x53, 0xfd, 0xd8, 0x8f, - 0x52, 0xb0, 0x59, 0xc7, 0x96, 0x49, 0x43, 0xc1, 0xc0, 0xdf, 0x3b, 0x6b, 0x64, 0x10, - 0xf9, 0x5d, 0xef, 0x5c, 0x04, 0x78, 0xf6, 0x85, 0xc6, 0xb3, 0x3a, 0xa0, 0xc8, 0x8e, - 0x68, 0x82, 0x42, 0x8e, 0x8c, 0xba, 0x43, 0x64, 0xea, 0x93, 0xaf, 0x37, 0x8c, 0x50, - 0x64, 0x82, 0x27, 0x36, 0x58, 0xa2, 0xc0, 0x95, 0xdd, 0x07, 0x6c, 0x39, 0x73, 0x19, - 0x1d, 0x46, 0xa1, 0x03, 0x9e, 0x5d, 0x6b, 0x7d, 0x9c, 0x08, 0x6b, 0x25, 0x85, 0x90, - 0xd3, 0x2d, 0x76, 0xe3, 0xd4, 0x20, 0x38, 0x43, 0x57, 0x0e, 0xfe, 0xed, 0x97, 0x1c, - 0x14, 0x12, 0x2f, 0x5b, 0x21, 0x5b, 0x0f, 0x38, 0xbb, 0xc7, 0x16, 0xb6, 0xa5, 0x94, - 0x4e, 0xe7, 0x27, 0x96, 0x56, 0x90, 0xe2, 0x09, 0xb4, 0x9e, 0xb9, 0x62, 0xc0, 0x39, - 0x97, 0x5f, 0x93, 0x9e, 0xd5, 0xc6, 0xe4, 0xc4, 0x00, 0xd8, 0x87, 0x75, 0x94, 0x33, - 0xd3, 0xad, 0x71, 0x6d, 0xa0, 0xcb, 0x44, 0x61, 0x13, 0xc7, 0x72, 0x7a, 0x64, 0xb5, - 0x8c, 0x3f, 0x8a, 0x0f, 0x81, 0x18, 0x9f, 0x98, 0x00, 0x52, 0x33, 0xa8, 0x13, 0x66, - 0xae, 0xe7, 0x3c, 0xec, 0x85, 0x22, 0x8e, 0xbc, 0xfd, 0x5e, 0xe3, 0xc3, 0xfb, 0x44, - 0xdb, 0x76, 0xba, 0x24, 0x3f, 0x28, 0x42, 0xb7, 0xb5, 0xfc, 0x74, 0x6a, 0xe5, 0x1b, - 0x0b, 0xc4, 0xbd, 0x4f, 0xc9, 0xfd, 0x83, 0x35, 0x65, 0xea, 0x85, 0x2b, 0x92, 0xb2, - 0x24, 0xf6, 0x99, 0x03, 0x18, 0xad, 0x8c, 0x7d, 0x94, 0x37, 0xe2, 0x0e, 0x2a, 0x1f, - 0x20, 0xe8, 0x18, 0xf9, 0x05, 0x7c, 0x5a, 0xba, 0xaa, 0x2e, 0x5c, 0x15, 0xb9, 0x49, - 0x45, 0xcd, 0x42, 0x4c, 0x28, 0xa5, 0xfa, 0x38, 0x5d, 0xad, 0xfe, 0x49, 0x07, 0xb2, - 0x74, 0xd8, 0x42, 0x70, 0x7d, 0xb3, 0x69, 0x7a, 0x5a, 0xe6, 0xc8, 0xf5, 0x42, 0xe5, - 0xec, 0xc0, 0x7f, 0xe4, 0x73, 0x50, 0xd1, 0x01, 0x46, 0x70, 0x21, 0x2e, 0xfe, 0x81, - 0xfb, 0x7c, 0x73, 0xe8, 0x45, 0x0d, 0xf8, 0x14, 0xef, 0x62, 0x32, 0xf7, 0x49, 0x0f, - 0x63, 0xcc, 0xf0, 0x74, 0x80, 0xf8, 0x84, 0xa6, 0x6e, 0xaf, 0xfc, 0x28, 0xfe, 0xa4, - 0x48, 0xd7, 0xb4, 0x01, 0xcd, 0xae, 0x10, 0xe7, 0xc0, 0xc7, 0xf9, 0xa7, 0xb1, 0x53, - 0x31, 0x96, 0x9f, 0xc8, 0xcb, 0x36, 0x39, 0x67, 0x73, 0xde, 0x19, 0x19, 0x31, 0xc7, - 0x50, 0xf6, 0xce, 0x5c, 0xaa, 0xf2, 0x97, 0x68, 0xeb, 0xb2, 0x7d, 0xac, 0xc7, 0x38, - 0x05, 0x6a, 0x81, 0x25, 0xb4, 0x77, 0x2b, 0xf8, 0x7a, 0xe1, 0x0a, 0x8a, 0x30, 0x9b, - 0x9b, 0xd6, 0x55, 0x04, 0x3c, 0xfc, 0x31, 0x59, 0x49, 0x43, 0x68, 0xc5, 0xab, 0x8c, - 0xad, 0xb7, 0xf6, 0x71, 0xe9, 0x62, 0x6b, 0xd2, 0x63, 0xe3, 0x11, 0x81, 0xa6, 0x04, - 0xb5, 0x06, 0xa0, 0x3b, 0x43, 0x9a, 0x7f, 0xfe, 0x43, 0x55, 0x89, 0x24, 0x77, 0xe2, - 0xbd, 0xf3, 0x38, 0xc6, 0x2c, 0x39, 0x22, 0xf7, 0xd3, 0xc9, 0xa5, 0x6c, 0x71, 0x03, - 0xd9, 0x11, 0x94, 0x8a, 0x84, 0xb5, 0xae, 0x2d, 0xbb, 0x16, 0xa3, 0x76, 0x1a, 0xdd, - 0x05, 0x3a, 0x0f, 0x96, 0x7e, 0x6b, 0x5b, 0xc9, 0x42, 0x11, 0xb6, 0x54, 0x71, 0x53, - 0x26, 0x7c, 0x6e, 0xe1, 0xca, 0xd0, 0xd9, 0x74, 0xa7, 0x10, 0x88, 0x58, 0x37, 0x35, - 0xe4, 0xf6, 0x3d, 0x33, 0x15, 0x6d, 0xad, 0xd5, 0x4c, 0x2f, 0xaf, 0x89, 0x11, 0x4a, - 0x12, 0x7b, 0x97, 0xb9, 0x4c, 0xc2, 0xa2, 0x2e, 0xf3, 0x03, 0xf4, 0x59, 0xd0, 0x4f, - 0xc0, 0xb5, 0x3a, 0xce, 0x59, 0x18, 0xd4, 0x7f, 0xf3, 0x3a, 0x55, 0x8b, 0xd7, 0x1a, - 0x75, 0xf3, 0x55, 0xfb, 0xd0, 0x6b, 0xbc, 0xcf, 0x4e, 0x02, 0xc3, 0xc0, 0xa4, 0xb6, - 0x3d, 0x0c, 0xc9, 0x49, 0x80, 0x1d, 0x63, 0xa6, 0x4c, 0xb2, 0xd3, 0x23, 0x73, 0xb2, - 0xc7, 0xb2, 0x74, 0xab, 0x2d, 0xb4, 0x68, 0x21, 0x42, 0xc8, 0xb2, 0x1d, 0x84, 0xc4, - 0x81, 0xf5, 0xef, 0x21, 0xe4, 0xb5, 0xe3, 0x60, 0x34, 0x51, 0xbf, 0x94, 0x77, 0x4d, - 0x0e, 0xf4, 0x7f, 0x63, 0xfa, 0x6a, 0xbb, 0x78, 0xd2, 0x1c, 0x19, 0x3c, 0xbe, 0x65, - 0xb6, 0x95, 0xfe, 0x67, 0x42, 0x3c, 0x1e, 0x2d, 0x31, 0x2e, 0x27, 0x76, 0xfa, 0x24, - 0xec, 0xe8, 0x46, 0x83, 0xe7, 0x48, 0x76, 0xc5, 0x5e, 0xa0, 0x36, 0x9e, 0x4e, 0xa0, - 0xe8, 0x64, 0x94, 0xe0, 0x0d, 0xde, 0x23, 0x6a, 0x16, 0x89, 0x73, 0x1f, 0x0a, 0x5d, - 0x82, 0x03, 0xaf, 0xde, 0x5c, 0x42, 0x36, 0x40, 0xb8, 0x1e, 0x4f, 0x63, 0x1c, 0x98, - 0x1c, 0x11, 0xa2, 0xe1, 0xd1, 0x84, 0xc6, 0x7c, 0x52, 0x8d, 0xf9, 0x2d, 0x53, 0xae, - 0xc4, 0x4a, 0x40, 0xa4, 0xea, 0x2a, 0x13, 0x1b, 0x47, 0x33, 0xcf, 0xe4, 0x5c, 0x6b, - 0x00, 0x12, 0xc3, 0xe9, 0xe2, 0x09, 0x75, 0xba, 0xae, 0xcb, 0x02, 0x32, 0xdf, 0x88, - 0x0b, 0xd7, 0xd1, 0xde, 0x13, 0xe1, 0x34, 0x94, 0x62, 0xec, 0x8d, 0x5d, 0xf3, 0xe7, - 0x80, 0xff, 0xa7, 0x2e, 0xba, 0x8a, 0x8d, 0xf7, 0xfc, 0xf3, 0x98, 0xec, 0x23, 0x05, - 0x13, 0xca, 0x9d, 0x61, 0x23, 0xf8, 0xb9, 0xd8, 0x17, 0x85, 0x60, 0xda, 0xf9, 0x75, - 0x11, 0x19, 0x55, 0xa2, 0xbc, 0xa3, 0x42, 0x3e, 0xee, 0xfc, 0x52, 0x7b, 0xe3, 0xa8, - 0x54, 0x3e, 0xb9, 0x0a, 0x5e, 0xc0, 0x2f, 0x35, 0xa7, 0xc6, 0x4b, 0x7d, 0xd5, 0x9a, - 0x72, 0xda, 0x00, 0x74, 0x63, 0x4e, 0x01, 0xd2, 0xab, 0xf3, 0x63, 0x7a, 0xdd, 0x77, - 0xc7, 0x35, 0x0f, 0x12, 0xb0, 0x11, 0xb2, 0x94, 0x16, 0x8e, 0xc7, 0x55, 0x76, 0xe4, - 0x7d, 0x16, 0x9e, 0x39, 0x38, 0xbf, 0x6a, 0xe2, 0xaa, 0x8f, 0xf7, 0xcf, 0xba, 0x7c, - 0xac, 0xb1, 0xf9, 0x2b, 0x6e, 0x4c, 0x24, 0x97, 0xbf, 0xfa, 0x9f, 0x17, 0xca, 0xd2, - 0x42, 0xfa, 0x9c, 0x31, 0x79, 0xc1, 0xa3, 0xaa, 0x81, 0xf7, 0x36, 0x16, 0x49, 0x57, - 0x2c, 0x71, 0x5c, 0x25, 0xa1, 0xf6, 0xcd, 0x5a, 0xce, 0x82, 0xc0, 0x0a, 0xb2, 0x34, - 0x2b, 0x9c, 0x3c, 0xb4, 0xff, 0xfd, 0xda, 0x16, 0x0c, 0xa5, 0xab, 0x9e, 0x9b, 0xaf, - 0x21, 0x39, 0xef, 0x9a, 0xfb, 0xe1, 0xb1, 0xf3, 0x09, 0x46, 0x2a, 0xfc, 0xe4, 0x62, - 0xa7, 0x9b, 0xb9, 0x69, 0x8e, 0x22, 0xc9, 0x57, 0xc5, 0x90, 0xa7, 0x53, 0xa7, 0x6b, - 0x87, 0xe0, 0x09, 0x12, 0x1e, 0x06, 0xf6, 0xa1, 0xbf, 0x62, 0xa0, 0x8b, 0xf4, 0x35, - 0xd9, 0x2e, 0x2f, 0xff, 0xe8, 0x6e, 0x2a, 0x9c, 0xbb, 0xa9, 0x13, 0x3a, 0x68, 0xe4, - 0xae, 0xbf, 0x33, 0xc3, 0x84, 0x36, 0xf2, 0x54, 0x5f, 0xc2, 0xd5, 0x28, 0x32, 0xd1, - 0x65, 0xaf, 0x41, 0x5b, 0x24, 0x4a, 0xdc, 0x5f, 0x57, 0x37, 0x7d, 0xee, 0xdf, 0x46, - 0x0a, 0xa3, 0xbe, 0xb4, 0x34, 0x19, 0xc6, 0xb0, 0x82, 0xe8, 0x35, 0xce, 0x84, 0xca, - 0x13, 0xb6, 0x90, 0x8a, 0x88, 0x13, 0xc0, 0x21, 0xde, 0x9f, 0xa9, 0xa4, 0x4e, 0x4c, - 0x18, 0xdc, 0xb3, 0xd2, 0x1f, 0xaa, 0x8b, 0x86, 0xc8, 0x70, 0x28, 0xd0, 0xb5, 0x53, - 0x21, 0x07, 0xf9, 0xf6, 0xfd, 0x49, 0x00, 0x22, 0x7d, 0x0d, 0x8f, 0xf2, 0xbf, 0x9d, - 0x28, 0xcb, 0xcc, 0x99, 0x6c, 0x47, 0x3c, 0xe6, 0x16, 0x41, 0xf4, 0x88, 0x4e, 0x6e, - 0xd3, 0xfd, 0x5e, 0x4b, 0x7c, 0xb8, 0x35, 0xb8, 0x33, 0x08, 0x96, 0x4e, 0x3c, 0x46, - 0x87, 0x3f, 0xd6, 0x13, 0x31, 0x7b, 0x91, 0xd2, 0x92, 0x36, 0xea, 0x90, 0xe3, 0x65, - 0x32, 0xec, 0x5d, 0x6b, 0x42, 0x32, 0xe8, 0xbc, 0xcc, 0x36, 0x75, 0xb9, 0x8b, 0x35, - 0xf8, 0xde, 0x4d, 0x08, 0x88, 0x84, 0x14, 0x6f, 0x3d, 0xb8, 0x97, 0x0b, 0x38, 0xd1, - 0xe5, 0x01, 0xae, 0xe9, 0xc1, 0xf3, 0xfd, 0x78, 0x25, 0x49, 0xd3, 0xf3, 0x24, 0x57, - 0x59, 0x60, 0x6d, 0x9f, 0x92, 0xd5, 0x54, 0x8a, 0xcf, 0xea, 0xdb, 0xaf, 0x9c, 0xaa, - 0x6b, 0x93, 0xdc, 0x08, 0x82, 0x8d, 0x74, 0xf6, 0xd5, 0xfd, 0xd8, 0x33, 0x31, 0xf0, - 0x96, 0x91, 0x45, 0x95, 0x52, 0x97, 0xe6, 0x9f, 0x00, 0xfd, 0x29, 0x87, 0xf2, 0xda, - 0x2b, 0x94, 0xb9, 0x95, 0xfe, 0xcb, 0xe6, 0x22, 0xa7, 0x35, 0xef, 0x7f, 0x12, 0x07, - 0xf6, 0x71, 0x62, 0x94, 0x89, 0x20, 0x2b, 0xea, 0x0b, 0x47, 0x5e, 0x51, 0x68, 0x1a, - 0xa1, 0x67, 0x78, 0xb3, 0x9b, 0xd9, 0x23, 0xc9, 0x8d, 0xc6, 0xff, 0x83, 0x73, 0xc7, - 0x9b, 0xb1, 0x70, 0x30, 0x41, 0x7b, 0xc2, 0x00, 0xc8, 0xf0, 0xb8, 0x55, 0xac, 0xfe, - 0xc1, 0x79, 0xf7, 0x67, 0x4c, 0xec, 0x27, 0x21, 0xa1, 0x0f, 0xca, 0x69, 0x3d, 0x83, - 0xcf, 0xe5, 0xb8, 0xcd, 0xcc, 0x18, 0xf8, 0x1a, 0xd6, 0x17, 0xfa, 0x26, 0xf0, 0xdf, - 0xb8, 0x36, 0x55, 0xb8, 0xa2, 0x9a, 0x7f, 0x83, 0x42, 0x32, 0x42, 0x5e, 0x8c, 0x47, - 0x45, 0x88, 0xf1, 0x8d, 0xd3, 0x26, 0xaa, 0x39, 0x6c, 0x3e, 0x47, 0x75, 0xe0, 0x02, - 0x05, 0xfc, 0x9e, 0x45, 0xf7, 0xb7, 0xd2, 0xe6, 0xd5, 0x5d, 0xcb, 0x90, 0xe2, 0x3f, - 0xf6, 0xb5, 0x08, 0x45, 0x9a, 0xa6, 0x99, 0xbf, 0xcb, 0xd5, 0x6f, 0x10, 0x99, 0x77, - 0x64, 0xd0, 0x87, 0x40, 0x89, 0x86, 0xe7, 0x3d, 0x6e, 0x28, 0x4f, 0xea, 0x9a, 0x23, - 0xc3, 0x93, 0x11, 0x78, 0x2f, 0x86, 0xca, 0xbf, 0xf9, 0x45, 0x5e, 0x4c, 0xf6, 0x99, - 0xe5, 0xf5, 0xd4, 0xbc, 0x0b, 0x39, 0x05, 0xa4, 0xe3, 0xbd, 0x01, 0xc5, 0x4d, 0xf8, - 0x64, 0x34, 0x43, 0xbe, 0x0f, 0x88, 0x90, 0x32, 0xea, 0x32, 0x5b, 0xf0, 0x71, 0x07, - 0xfd, 0x41, 0xd6, 0x73, 0xee, 0xba, 0xe6, 0xfa, 0x63, 0x7b, 0x70, 0xcc, 0x0e, 0xd3, - 0xf0, 0x09, 0x58, 0xdf, 0xb8, 0xdc, 0xf0, 0x0e, 0x85, 0xa1, 0xd0, 0xa6, 0xa8, 0x90, - 0x81, 0x40, 0xc2, 0xf4, 0x34, 0xc2, 0xe2, 0x60, 0xef, 0xb0, 0xbc, 0xa2, 0x00, 0x35, - 0x04, 0xc9, 0x99, 0x93, 0xa9, 0xe1, 0xc0, 0xff, 0x9c, 0xef, 0xe6, 0xa6, 0x65, 0xd7, - 0x91, 0x42, 0x86, 0x90, 0xe4, 0x7e, 0xf8, 0xc1, 0x31, 0xa8, 0xe9, 0xbf, 0xb4, 0xc3, - 0x08, 0x02, 0x35, 0x03, 0x2d, 0x73, 0x1b, 0x0d, 0x38, 0x41, 0x22, 0x5f, 0x1c, 0x11, - 0xe2, 0xc2, 0x8e, 0xe8, 0x4d, 0x35, 0xf9, 0x22, 0x61, 0x00, 0x56, 0x59, 0x72, 0xeb, - 0x26, 0x9d, 0x27, 0x8e, 0xf6, 0x49, 0x79, 0xbf, 0x65, 0x15, 0xed, 0x4a, 0x68, 0x40, - 0xb0, 0x88, 0x3a, 0x9e, 0x6e, 0xf6, 0x4a, 0x0e, 0xfc, 0xae, 0x1c, 0xf2, 0x1d, 0xfe, - 0x74, 0x85, 0x4e, 0x84, 0xc2, 0x74, 0x9f, 0xac, 0x03, 0x82, 0x52, 0x75, 0xc9, 0xb6, - 0x30, 0x21, 0x84, 0xc7, 0x2d, 0xf4, 0xc4, 0xbb, 0x28, 0x62, 0xe4, 0xe8, 0xa7, 0xd9, - 0xa4, 0xa2, 0x82, 0x86, 0x6f, 0x9a, 0x7b, 0x2c, 0xfc, 0x9a, 0x56, 0x31, 0x3d, 0xa0, - 0xc4, 0x7a, 0x34, 0xb7, 0xb9, 0xcd, 0xa3, 0xac, 0xe8, 0x18, 0x5f, 0x07, 0xdf, 0x36, - 0xe4, 0x48, 0xa7, 0x6a, 0xa4, 0x77, 0xf2, 0x24, 0xd8, 0x7a, 0x07, 0x4f, 0x43, 0xaf, - 0x5d, 0x5f, 0x79, 0xb3, 0xab, 0x11, 0x28, 0xf0, 0x81, 0x91, 0x44, 0x7f, 0xa6, 0x46, - 0xbf, 0xdd, 0xe5, 0xb5, 0x1e, 0x23, 0x3c, 0xa6, 0x15, 0x5d, 0x10, 0x15, 0x85, 0xbc, - 0x2c, 0x40, 0x15, 0x8a, 0xc2, 0x10, 0x6e, 0x66, 0xa2, 0x6e, 0x46, 0x42, 0x33, 0x70, - 0x63, 0x68, 0x76, 0xb4, 0x34, 0xa7, 0x4f, 0x8c, 0xe8, 0x06, 0x00, 0x50, 0xb0, 0x82, - 0xa7, 0x9b, 0x61, 0xbb, 0x5d, 0x34, 0x4e, 0xb5, 0xa1, 0x15, 0x83, 0x26, 0xce, 0xd9, - 0xa9, 0xd9, 0xf5, 0x4f, 0xb2, 0xfe, 0x8f, 0x9f, 0x05, 0xcd, 0x11, 0x1e, 0xe4, 0x6c, - 0x47, 0x10, 0xf6, 0xf6, 0x3a, 0x62, 0x69, 0x45, 0x57, 0xef, 0x1b, 0x12, 0xc8, 0x80, - 0x06, 0xb6, 0x78, 0x72, 0x50, 0x5f, 0x4e, 0x88, 0x3b, 0x58, 0x59, 0x07, 0x92, 0x9a, - 0x2f, 0x3f, 0xdb, 0x0d, 0x8f, 0x79, 0x14, 0xc4, 0x2d, 0xde, 0x2d, 0x20, 0x00, 0xf5, - 0xae, 0x02, 0xd4, 0x18, 0x21, 0xc8, 0xe1, 0xee, 0x01, 0x38, 0xeb, 0xcb, 0x72, 0x8d, - 0x7c, 0x6c, 0x3c, 0x80, 0x02, 0x7e, 0x43, 0x75, 0x94, 0xc6, 0x70, 0xfd, 0x6f, 0x39, - 0x08, 0x22, 0x2e, 0xe7, 0xa1, 0xb9, 0x17, 0xf8, 0x27, 0x1a, 0xbe, 0x66, 0x0e, 0x39, - 0xe0, 0x51, 0xaa, 0xa6, 0xfc, 0xa1, 0x86, 0x22, 0x76, 0xe2, 0xba, 0xa0, 0xfe, 0x0b, - 0x16, 0x2a, 0xeb, 0xcf, 0xe3, 0xd9, 0x34, 0x9c, 0x8d, 0x15, 0x4b, 0xb7, 0xee, 0x28, - 0x21, 0x2c, 0x1b, 0xaa, 0x70, 0x5d, 0x82, 0x07, 0x0d, 0x70, 0x32, 0xf2, 0x69, 0x5d, - 0x17, 0x96, 0x80, 0x9f, 0xab, 0x41, 0x24, 0x69, 0x26, 0xaf, 0x99, 0x2b, 0x6e, 0xee, - 0x95, 0xa9, 0xa0, 0x6b, 0xc4, 0x56, 0x2c, 0x5f, 0x2f, 0x1b, 0x19, 0x54, 0x95, 0x00, - 0x37, 0x2e, 0x7a, 0xd5, 0x79, 0xa6, 0xd6, 0xd7, 0x8b, 0x33, 0x15, 0x31, 0x30, 0xfb, - 0x44, 0x8f, 0xb7, 0x9e, 0x8a, 0x66, 0x9d, 0xb8, 0xa0, 0xf3, 0x5c, 0xdf, 0x9a, 0xe5, - 0xd3, 0x2d, 0x73, 0x2f, 0xc7, 0x94, 0x18, 0xe2, 0x3b, 0x45, 0x1d, 0xdc, 0x95, 0xa2, - 0x2a, 0xba, 0xbb, 0x05, 0x6e, 0xc6, 0xb5, 0xe8, 0xba, 0x4f, 0x52, 0x4d, 0xfa, 0xfe, - 0x87, 0x52, 0x62, 0xdd, 0x7b, 0xe4, 0x1c, 0xbb, 0xc6, 0x24, 0x20, 0xd4, 0xad, 0x6d, - 0xf5, 0xc9, 0xb7, 0x13, 0x60, 0x4f, 0x65, 0x60, 0x88, 0xa4, 0x48, 0x5e, 0x93, 0xbe, - 0x19, 0x07, 0xd2, 0x7a, 0xc6, 0xec, 0x3c, 0x57, 0x25, 0x9b, 0xd6, 0x98, 0x1d, 0x42, - 0xc1, 0xb7, 0x8a, 0x29, 0xad, 0x96, 0x85, 0xe6, 0x3c, 0x49, 0x4d, 0x41, 0x29, 0x62, - 0x3e, 0xa1, 0xa7, 0xff, 0xec, 0x85, 0xfa, 0x29, 0x41, 0x10, 0x73, 0xed, 0xb2, 0x97, - 0x8e, 0xf4, 0xe4, 0x69, 0xdd, 0xd5, 0xcd, 0xa9, 0x86, 0x18, 0x99, 0x95, 0xf8, 0x8d, - 0x6a, 0xb3, 0x66, 0xdb, 0x01, 0x90, 0x01, 0xf5, 0xb2, 0x52, 0x88, 0xcf, 0x86, 0x0f, - 0xd9, 0x98, 0xee, 0x57, 0x3c, 0x8c, 0xc4, 0x8a, 0xa9, 0xef, 0xcf, 0x9b, 0x61, 0x7e, - 0x04, 0x3c, 0x99, 0x00, 0x8e, 0x35, 0x00, 0x96, 0xfd, 0xa4, 0xeb, 0x24, 0xc2, 0x0f, - 0x46, 0x90, 0xf1, 0xe2, 0xc5, 0xef, 0x86, 0x6c, 0x0e, 0xe5, 0xdd, 0xa1, 0x19, 0xee, - 0xea, 0xf1, 0x19, 0xdb, 0xdc, 0xae, 0x8d, 0xc7, 0x6c, 0x84, 0x6c, 0xc2, 0x27, 0x27, - 0x2b, 0xfc, 0x54, 0x17, 0xdc, 0x4c, 0xf4, 0xc0, 0x87, 0xba, 0x34, 0xec, 0xf3, 0xa5, - 0x5b, 0x00, 0x1f, 0xf3, 0x09, 0xa8, 0x1c, 0x05, 0x2d, 0x69, 0x26, 0xa9, 0xdd, 0xf0, - 0xf7, 0x8c, 0x5f, 0xc0, 0x64, 0xc6, 0xa6, 0x40, 0x16, 0x21, 0xb3, 0x8a, 0xa5, 0x49, - 0x44, 0x19, 0x81, 0x99, 0x21, 0x0d, 0x2b, 0x42, 0xe6, 0x1d, 0xde, 0x1d, 0x08, 0xaf, - 0x55, 0x07, 0x3b, 0xbf, 0x06, 0x15, 0xf6, 0x7b, 0x11, 0x00, 0xcc, 0x2e, 0xa3, 0xba, - 0x3d, 0x6c, 0x1a, 0x1a, 0x90, 0x87, 0xb1, 0x19, 0xba, 0xee, 0xbf, 0xa6, 0x2b, 0xc9, - 0xf0, 0xec, 0x47, 0x9d, 0x99, 0xc1, 0xa3, 0xb1, 0x58, 0xb5, 0x14, 0xd1, 0x62, 0x9d, - 0xb3, 0x99, 0x3f, 0x11, 0x67, 0x2a, 0x26, 0x70, 0x8e, 0x5a, 0xd8, 0x16, 0xb5, 0x47, - 0xab, 0x7e, 0x82, 0x7d, 0x07, 0x1b, 0xa7, 0x84, 0x2b, 0x3e, 0x90, 0x30, 0x53, 0x83, - 0x89, 0x6e, 0xc4, 0x90, 0x5f, 0x70, 0xc7, 0x8b, 0x69, 0x4e, 0x6a, 0x5a, 0x3e, 0x43, - 0x12, 0xcd, 0x82, 0x08, 0x13, 0x2b, 0x84, 0x0f, 0x05, 0xc7, 0x14, 0x52, 0x3c, 0xa8, - 0x19, 0x72, 0x0a, 0xe2, 0x27, 0xfd, 0x1a, 0xcb, 0xa7, 0x14, 0xfa, 0x4f, 0xc4, 0x5f, - 0xc5, 0x39, 0x88, 0x57, 0xb4, 0x0d, 0xc1, 0x48, 0x79, 0x85, 0x6f, 0x35, 0x4b, 0xa4, - 0xd2, 0x58, 0x1d, 0x0c, 0xda, 0x54, 0xb6, 0x38, 0xba, 0x9d, 0x76, 0xf9, 0xb5, 0x2d, - 0x17, 0xc8, 0xf8, 0x8e, 0xe6, 0x3f, 0x58, 0x45, 0xb5, 0xdc, 0xef, 0xa4, 0xc3, 0x47, - 0x9b, 0xce, 0x9a, 0xca, 0xd1, 0x8b, 0x4a, 0xea, 0xe0, 0x3c, 0x0e, 0xae, 0x22, 0x5d, - 0x42, 0x84, 0x8b, 0xde, 0xaa, 0x53, 0x6d, 0x7d, 0x8d, 0xd3, 0xbc, 0x97, 0x9f, 0x06, - 0x58, 0x66, 0x73, 0xbc, 0x6f, 0xf1, 0xc5, 0xd3, 0xb3, 0x20, 0xf3, 0x49, 0xa5, 0xb3, - 0xa8, 0xb3, 0x55, 0x59, 0x22, 0x96, 0xaa, 0xf6, 0x1c, 0x5b, 0x72, 0x52, 0xf7, 0x3e, - 0xc0, 0xa9, 0x46, 0x6a, 0x1b, 0x85, 0x76, 0x4f, 0xb0, 0x83, 0x1b, 0x4a, 0x1a, 0x36, - 0x89, 0x0e, 0x22, 0x4c, 0x01, 0xac, 0xfc, 0xe4, 0x8e, 0xe3, 0xed, 0x93, 0x87, 0x73, - 0x98, 0xe0, 0x72, 0x6d, 0x02, 0x93, 0x6d, 0x0d, 0x03, 0x2e, 0x18, 0xe3, 0x28, 0x8b, - 0x26, 0x70, 0xe1, 0x36, 0x2c, 0x32, 0xd6, 0xe4, 0x73, 0x3b, 0x9d, 0xd2, 0xd5, 0xf2, - 0x6e, 0x1f, 0xe3, 0x06, 0xf7, 0x3c, 0x00, 0x7f, 0xdd, 0xca, 0xe9, 0xd9, 0xc0, 0xaa, - 0xf1, 0x87, 0xd7, 0x42, 0x8b, 0x1e, 0x9d, 0x47, 0x9c, 0x18, 0x23, 0x7b, 0x98, 0x28, - 0xbc, 0xa8, 0xb9, 0x8c, 0x9d, 0x9b, 0xec, 0x7d, 0x82, 0x70, 0xb5, 0xd8, 0xee, 0xc3, - 0xcc, 0x4f, 0x43, 0xfa, 0x01, 0x88, 0x52, 0x1b, 0xc6, 0x1b, 0x21, 0xdd, 0x04, 0xe3, - 0x7a, 0x83, 0xec, 0xe6, 0x8c, 0xa7, 0xa2, 0xfa, 0x6c, 0x8f, 0x9e, 0x34, 0xa6, 0x29, - 0x03, 0x35, 0xaa, 0x1f, 0xbd, 0x83, 0xd5, 0x4a, 0xaf, 0x44, 0x1e, 0x31, 0x9e, 0xa4, - 0x7a, 0x86, 0x2a, 0xd0, 0x29, 0x3c, 0xed, 0xf5, 0xdd, 0x9e, 0xda, 0xde, 0xee, 0x33, - 0xcb, 0x52, 0x2c, 0xd0, 0x11, 0x8b, 0xbd, 0x81, 0x1a, 0xce, 0x9a, 0x23, 0xbd, 0xa3, - 0x9a, 0xba, 0x72, 0xf1, 0x56, 0x6f, 0xc1, 0x68, 0x84, 0x97, 0xd2, 0xa7, 0x92, 0x8c, - 0x36, 0x70, 0x15, 0x25, 0x67, 0x8b, 0xc9, 0x72, 0x14, 0xb3, 0x1b, 0x37, 0xba, 0xb4, - 0x6b, 0x88, 0xf2, 0x7f, 0x04, 0x48, 0xde, 0xcb, 0x31, 0x62, 0x2d, 0x0f, 0x0f, 0x87, - 0xa8, 0x55, 0xba, 0x54, 0x00, 0x03, 0x32, 0x03, 0x1f, 0x73, 0xab, 0xff, 0xd4, 0x65, - 0x91, 0xda, 0x0b, 0x88, 0x72, 0x35, 0x04, 0xed, 0xb2, 0x33, 0x72, 0x30, 0xda, 0xd2, - 0xac, 0xc0, 0xd8, 0xbb, 0x68, 0xbc, 0x83, 0x7a, 0x2f, 0xf9, 0x30, 0xbf, 0xf0, 0x6f, - 0xde, 0x74, 0xeb, 0x90, 0xaa, 0xe4, 0xf6, 0x0d, 0xbb, 0x6e, 0xb8, 0x27, 0xea, 0x99, - 0x88, 0x4a, 0xcd, 0x62, 0x85, 0xa9, 0x88, 0x92, 0x80, 0x2c, 0xf5, 0x9d, 0x5d, 0x60, - 0xd0, 0x16, 0x63, 0x38, 0x7b, 0x3e, 0xd2, 0x72, 0x3b, 0xd6, 0x48, 0x9e, 0x9c, 0x2c, - 0x10, 0x6d, 0x4a, 0xa2, 0xde, 0x23, 0xce, 0xd1, 0x6c, 0x72, 0x04, 0x29, 0xc7, 0x75, - 0x3a, 0x77, 0x38, 0xec, 0x7d, 0x9d, 0xb8, 0x62, 0x42, 0x29, 0xed, 0xd2, 0x17, 0xb8, - 0x0d, 0x74, 0x87, 0x5a, 0x14, 0xca, 0xe4, 0x86, 0x3f, 0x13, 0x9e, 0x9c, 0x0b, 0x13, - 0x1b, 0x2a, 0x4c, 0x28, 0x07, 0x1a, 0x38, 0xec, 0x61, 0xf6, 0x68, 0x01, 0xaa, 0x59, - 0x56, 0xfc, 0xb2, 0xa4, 0x6b, 0x95, 0x87, 0x66, 0x5b, 0x75, 0x71, 0xaa, 0x03, 0x48, - 0x1f, 0xd8, 0xd9, 0xd5, 0x69, 0x8f, 0x83, 0x6f, 0xc8, 0x63, 0x5e, 0x69, 0xe3, 0xbd, - 0xe4, 0x2f, 0x4a, 0xc0, 0x71, 0x32, 0x8b, 0x54, 0x09, 0xf6, 0xe4, 0x2d, 0x79, 0x0a, - 0xed, 0xd7, 0x3b, 0xc1, 0xa2, 0x35, 0x47, 0x23, 0xb3, 0xb8, 0x19, 0xd0, 0x63, 0x7a, - 0x6f, 0xa4, 0x66, 0x39, 0x46, 0xa3, 0x0a, 0xc5, 0xaf, 0xdd, 0x30, 0xce, 0x83, 0x0f, - 0x67, 0x91, 0xb4, 0x57, 0x52, 0x70, 0xa1, 0x72, 0x0f, 0x91, 0x86, 0x6e, 0x2b, 0x86, - 0xf4, 0x78, 0x88, 0x94, 0xc8, 0xda, 0x62, 0xd8, 0xb9, 0x1f, 0xaf, 0x52, 0x0e, 0x3b, - 0xed, 0xbc, 0x12, 0x06, 0xa5, 0xa5, 0xe6, 0xef, 0xd3, 0xdf, 0xde, 0x08, 0x43, 0xc3, - 0xb0, 0x67, 0x57, 0x64, 0x3f, 0xc0, 0x06, 0x00, 0x88, 0x38, 0xca, 0x47, 0x30, 0x87, - 0xf8, 0x97, 0x79, 0x18, 0xcc, 0x1b, 0x81, 0xc9, 0xe6, 0x8e, 0x3b, 0x88, 0x8f, 0xe6, - 0xf7, 0xc6, 0x30, 0xf1, 0xbc, 0x7a, 0xe1, 0x88, 0xf5, 0x12, 0x84, 0x20, 0x41, 0xca, - 0xda, 0x1e, 0x05, 0xf8, 0x66, 0xd2, 0x56, 0x2d, 0xbe, 0x09, 0xc4, 0xb4, 0x30, 0x68, - 0xf7, 0x54, 0xda, 0xd3, 0x4d, 0xf0, 0xfc, 0xfc, 0x18, 0x1f, 0x31, 0x80, 0x1a, 0x79, - 0x92, 0xd2, 0xf1, 0x6b, 0xe0, 0x21, 0x1b, 0x4a, 0x22, 0xf6, 0x2a, 0xab, 0x64, 0x70, - 0x1b, 0xf4, 0xa4, 0xe6, 0xd6, 0x66, 0xfc, 0x30, 0x4a, 0x5c, 0x79, 0xc6, 0x09, 0xac, - 0xc4, 0x3b, 0x00, 0xb4, 0x86, 0x48, 0x93, 0xd3, 0x7d, 0x50, 0x07, 0xf0, 0xc3, 0x29, - 0xa4, 0x75, 0x50, 0x52, 0x57, 0x75, 0x70, 0xdd, 0x38, 0xfa, 0xc0, 0x43, 0xcd, 0x91, - 0xc1, 0x2e, 0xe3, 0x4e, 0x9c, 0xfa, 0xe3, 0x92, 0xa7, 0x8b, 0xda, 0xbd, 0x4e, 0xe3, - 0x1d, 0xc0, 0xde, 0xb0, 0x2f, 0xe7, 0xb1, 0xd8, 0xb0, 0x17, 0x8a, 0xc9, 0x51, 0x31, - 0x05, 0xfc, 0xc7, 0xe3, 0x0b, 0xa8, 0xe0, 0x16, 0xaa, 0x36, 0xa6, 0xb5, 0xdf, 0x5e, - 0x5a, 0x19, 0x09, 0xf6, 0x3a, 0xba, 0x09, 0x5d, 0x98, 0x77, 0xa8, 0xf2, 0x6e, 0x40, - 0x3d, 0xc2, 0x54, 0x76, 0xad, 0xd8, 0x3d, 0xb1, 0xca, 0x15, 0x8f, 0x0b, 0x42, 0x2b, - 0x5f, 0xf4, 0xdb, 0x69, 0xb1, 0x24, 0x4b, 0xc0, 0x90, 0x2e, 0xd0, 0x30, 0x3f, 0xec, - 0x73, 0xa5, 0xbf, 0xfe, 0xc7, 0x3a, 0xc3, 0x4c, 0x1a, 0x73, 0x16, 0x0f, 0x2c, 0xea, - 0x1e, 0x05, 0x10, 0xf8, 0x4d, 0x2f, 0xe2, 0xf7, 0x3b, 0x6e, 0x92, 0x19, 0x07, 0xa1, - 0xb7, 0xb3, 0x75, 0x12, 0x13, 0x24, 0x30, 0x11, 0x76, 0xb0, 0x9b, 0xc0, 0x41, 0xe4, - 0x68, 0x42, 0x3e, 0x93, 0xd5, 0xdc, 0xa3, 0x3e, 0x67, 0x1a, 0x78, 0x6d, 0x23, 0x1f, - 0x16, 0x43, 0xea, 0x66, 0x43, 0x8b, 0xa7, 0x85, 0xb8, 0x1e, 0x6c, 0x2b, 0xc7, 0x3f, - 0xf0, 0x0d, 0x89, 0x3b, 0xc1, 0x28, 0x5e, 0xfc, 0xa8, 0x25, 0x99, 0xd1, 0x81, 0xf1, - 0x23, 0x51, 0xf9, 0x39, 0xa9, 0x4e, 0xa8, 0xb9, 0x75, 0xc0, 0x65, 0xa9, 0x1f, 0xf2, - 0x57, 0xca, 0xc7, 0xa9, 0x23, 0x85, 0xfc, 0x8f, 0xa9, 0x21, 0xb1, 0x06, 0xba, 0x86, - 0x60, 0xc6, 0x0a, 0xc8, 0xba, 0x5e, 0xce, 0x45, 0x60, 0x6f, 0x04, 0xf3, 0x6a, 0x3a, - 0x90, 0xbb, 0x38, 0x38, 0xc4, 0x2a, 0xbf, 0x62, 0xdd, 0x2d, 0x84, 0xba, 0xbe, 0xf3, - 0xe1, 0x88, 0xe9, 0x17, 0x1a, 0xff, 0x9b, 0xc1, 0x16, 0x66, 0x90, 0x09, 0xd8, 0x87, - 0x13, 0x0a, 0xc9, 0xf7, 0x39, 0x6a, 0x62, 0x7a, 0x84, 0x74, 0xc1, 0x81, 0x1b, 0x69, - 0x6f, 0x99, 0x55, 0x2b, 0x14, 0xc4, 0x84, 0xdf, 0xe4, 0x2c, 0x24, 0xd5, 0x7c, 0x3a, - 0x9c, 0x3f, 0xea, 0x13, 0x76, 0xcd, 0xcb, 0x63, 0x42, 0x1c, 0x31, 0x4a, 0x62, 0x2a, - 0x9a, 0xef, 0x0b, 0xc0, 0x57, 0xcb, 0x11, 0xbc, 0x5e, 0x30, 0x66, 0xe3, 0x3a, 0x3b, - 0x9b, 0x31, 0xdf, 0x25, 0x75, 0xcd, 0x51, 0x85, 0xa4, 0xf3, 0xfc, 0x4e, 0x4c, 0x3d, - 0x40, 0x2e, 0xd4, 0x20, 0x46, 0xf8, 0x1f, 0x97, 0x48, 0x16, 0xd2, 0x79, 0xb1, 0x51, - 0x3a, 0xb8, 0x1d, 0x3f, 0x0a, 0x3c, 0x7f, 0x7f, 0xcf, 0x2f, 0xbb, 0x4e, 0x26, 0x32, - 0x19, 0x93, 0xa5, 0x13, 0xad, 0x3d, 0x7f, 0x4a, 0xfe, 0x6c, 0x1b, 0xbd, 0xc6, 0x57, - 0x58, 0x50, 0x80, 0xbb, 0x5a, 0x0f, 0x25, 0x97, 0x3d, 0x63, 0xeb, 0x20, 0xad, 0xa0, - 0x16, 0x6b, 0xbd, 0x8a, 0x39, 0xff, 0x93, 0x24, 0x6f, 0x27, 0x89, 0x73, 0x2a, 0xd0, - 0x55, 0x87, 0xf8, 0xdb, 0x7b, 0xc8, 0x7c, 0x24, 0x2c, 0xfd, 0x36, 0xce, 0x68, 0x5a, - 0x4b, 0x65, 0x69, 0x86, 0xc3, 0x9f, 0xd7, 0xfc, 0xb2, 0x3c, 0x91, 0x91, 0x3e, 0x46, - 0x11, 0x19, 0x1e, 0xdc, 0xc8, 0x8b, 0x78, 0xf1, 0x45, 0xea, 0x29, 0xd2, 0x71, 0xb9, - 0x40, 0xc6, 0x99, 0x41, 0xe4, 0xc3, 0xfd, 0x2d, 0x71, 0xf3, 0xb1, 0x90, 0x69, 0x0e, - 0xe1, 0x6f, 0x5d, 0x14, 0xac, 0x22, 0x24, 0xe6, 0xfc, 0x89, 0x59, 0x76, 0x54, 0x52, - 0x7d, 0xab, 0xe7, 0x2e, 0x75, 0xd2, 0xd2, 0xa1, 0x3a, 0x9f, 0xba, 0xa6, 0x37, 0x8e, - 0x8a, 0x26, 0x43, 0x21, 0x08, 0x7a, 0x19, 0x00, 0xef, 0xe3, 0xca, 0xd1, 0x4a, 0x57, - 0x96, 0x86, 0xaa, 0x36, 0x36, 0xbd, 0x37, 0x5b, 0xd3, 0x13, 0x6b, 0xee, 0x0b, 0xda, - 0xab, 0xcf, 0xac, 0x88, 0x1b, 0xc7, 0x01, 0x81, 0x27, 0x21, 0xe6, 0xfb, 0x75, 0xaa, - 0x07, 0x2d, 0x2d, 0x18, 0x7e, 0x62, 0x25, 0x8d, 0x65, 0xa1, 0x92, 0x15, 0x7c, 0xdf, - 0x2e, 0xc3, 0x21, 0x40, 0x7f, 0x68, 0x2f, 0x5e, 0xec, 0x6a, 0x32, 0x97, 0xab, 0x20, - 0xb7, 0x06, 0x1c, 0x62, 0x24, 0x57, 0x16, 0xa4, 0x4f, 0x71, 0xfb, 0xfc, 0x34, 0xc7, - 0x9b, 0x44, 0xe0, 0x9e, 0x42, 0x12, 0xac, 0x26, 0x53, 0xf6, 0xc4, 0x03, 0x64, 0x3e, - 0x1c, 0x5b, 0x9a, 0xd1, 0x34, 0xd8, 0x9c, 0x68, 0x0b, 0x70, 0x72, 0x83, 0xaf, 0x54, - 0x32, 0x6f, 0xc4, 0xf8, 0x4d, 0x6a, 0x58, 0x29, 0xa0, 0xad, 0x48, 0x30, 0x80, 0x6c, - 0x05, 0x75, 0x84, 0x92, 0xcd, 0x6a, 0xc4, 0x6b, 0xa0, 0x1a, 0x2b, 0x37, 0x22, 0xb5, - 0xe4, 0xcd, 0xaf, 0xbb, 0x3f, 0x36, 0x78, 0x5f, 0x42, 0x4a, 0xf0, 0x44, 0xda, 0xc5, - 0xdb, 0x5f, 0x7d, 0xf8, 0x39, 0xeb, 0x63, 0xc0, 0xc1, 0x7d, 0x8b, 0x0c, 0x79, 0xdb, - 0x86, 0x30, 0x94, 0x20, 0x15, 0xbe, 0x13, 0xf7, 0x9a, 0xf6, 0xf4, 0x3e, 0x5a, 0xb0, - 0x77, 0x81, 0x14, 0x79, 0x8f, 0x44, 0x22, 0x58, 0xee, 0xdc, 0x43, 0x6f, 0xcc, 0x38, - 0x6b, 0x36, 0xb5, 0x7e, 0x19, 0x17, 0xd7, 0x20, 0x17, 0x73, 0x66, 0xf4, 0x24, 0xb0, - 0xa5, 0x4b, 0x0b, 0x60, 0xf4, 0xfb, 0x13, 0x58, 0xc2, 0x0a, 0xa4, 0x1d, 0xc5, 0x02, - 0xe1, 0xdd, 0x8a, 0x16, 0x33, 0xf3, 0xd8, 0xe3, 0x27, 0x6b, 0x59, 0xe7, 0xd2, 0xc4, - 0xe6, 0x24, 0xa6, 0xf5, 0x36, 0x95, 0xbc, 0xaf, 0x24, 0x7e, 0x36, 0x48, 0x3f, 0x13, - 0xb2, 0x04, 0x42, 0x22, 0x37, 0xfc, 0x6a, 0xb3, 0xeb, 0xa0, 0x2f, 0xc4, 0x14, 0x2b, - 0x42, 0x97, 0xeb, 0xb5, 0x68, 0x3d, 0xb8, 0xd2, 0x43, 0x19, 0x70, 0x6a, 0xd2, 0x6a, - 0xaf, 0xd8, 0x1c, 0x53, 0xb7, 0x40, 0xf3, 0x45, 0x43, 0xa6, 0xb3, 0xe9, 0xf5, 0xbb, - 0x7d, 0x5c, 0x49, 0xe8, 0xc3, 0x7f, 0x61, 0x49, 0x21, 0x25, 0x4f, 0x32, 0x12, 0x39, - 0x4c, 0x79, 0x7d, 0x1c, 0xee, 0x78, 0x99, 0xb7, 0xb4, 0xb6, 0x5b, 0x59, 0xb7, 0x34, - 0x2f, 0x92, 0x53, 0x1c, 0x1d, 0x59, 0xe1, 0x79, 0x70, 0xb7, 0x31, 0x74, 0x14, 0x43, - 0x8c, 0xd8, 0x0b, 0xd0, 0xf9, 0xa6, 0x7c, 0x9b, 0x9e, 0x55, 0x2f, 0x01, 0x3c, 0x11, - 0x5a, 0x95, 0x4f, 0x35, 0xe0, 0x61, 0x6c, 0x68, 0xd4, 0x31, 0x63, 0xd3, 0x34, 0xda, - 0xc3, 0x82, 0x70, 0x33, 0xe5, 0xad, 0x84, 0x88, 0xbf, 0xd9, 0xc4, 0xbb, 0xbe, 0x8f, - 0x59, 0x35, 0xc6, 0xc5, 0xea, 0x04, 0xc3, 0xad, 0x49, 0xc7, 0x47, 0xa9, 0xe7, 0x23, - 0x1b, 0xcd, 0x7d, 0x16, 0x21, 0x5e, 0x6e, 0x80, 0x73, 0x7d, 0x6b, 0x54, 0xfe, 0xc8, - 0xb8, 0x84, 0x02, 0xf0, 0x47, 0x52, 0x45, 0xe1, 0x74, 0xa7, 0x45, 0xb8, 0x31, 0xf8, - 0xfe, 0x03, 0xa7, 0x6f, 0xb9, 0xce, 0xca, 0x4d, 0x22, 0xb7, 0x83, 0xc3, 0x28, 0xc6, - 0x91, 0x5c, 0x43, 0x40, 0x50, 0x64, 0xae, 0x56, 0xbc, 0x89, 0xe6, 0x4d, 0x15, 0x78, - 0xe4, 0xd3, 0xa3, 0x4b, 0xb9, 0x55, 0x91, 0xea, 0xf1, 0xd3, 0xda, 0x02, 0xa4, 0x54, - 0x9f, 0xa8, 0x0d, 0xb0, 0xff, 0x7c, 0xb0, 0x39, 0x93, 0xb6, 0x8a, 0xe1, 0x5a, 0x30, - 0xe8, 0x79, 0x49, 0xaa, 0x08, 0x0e, 0x94, 0xab, 0xde, 0x68, 0x89, 0x8c, 0x33, 0x92, - 0xa2, 0x17, 0xd6, 0x49, 0x61, 0x6b, 0xbe, 0x73, 0x9b, 0x13, 0xd1, 0x4d, 0xf0, 0x3f, - 0xf2, 0x76, 0x71, 0x48, 0x9b, 0xe0, 0xb4, 0xbe, 0xba, 0xaf, 0xa7, 0xd1, 0xe6, 0x39, - 0xd5, 0xb3, 0xe9, 0x94, 0xff, 0xb6, 0xb7, 0xa2, 0x09, 0xf6, 0xad, 0xfe, 0x8d, 0x1e, - 0x5c, 0xcf, 0x01, 0x0c, 0x19, 0x16, 0x8a, 0xeb, 0x00, 0xaa, 0x9d, 0x68, 0x7e, 0x24, - 0xad, 0xc0, 0xb1, 0x13, 0x5c, 0x70, 0xc9, 0x70, 0xe0, 0x90, 0x3a, 0xf6, 0xe1, 0x70, - 0x81, 0xd5, 0x81, 0x8e, 0x88, 0xb1, 0x4e, 0x4f, 0x60, 0x1b, 0x8c, 0x06, 0x3e, 0x3f, - 0x43, 0x87, 0xff, 0xa2, 0x32, 0x2a, 0x51, 0x81, 0x90, 0x9f, 0x09, 0x80, 0xd6, 0x89, - 0xde, 0x7f, 0x8e, 0x6a, 0x5c, 0x62, 0xa7, 0x77, 0xd1, 0x75, 0x00, 0x2a, 0x13, 0x7d, - 0xe8, 0x5b, 0x88, - ], - script_code: vec![], - transparent_input: None, - hash_type: 1, - amount: 1039204199089370, - consensus_branch_id: 1991772603, - sighash: [ - 0x6c, 0x4e, 0x32, 0x44, 0xc2, 0xd2, 0xbf, 0xb8, 0xd6, 0xf6, 0x69, 0x97, 0x77, 0xa1, - 0x1a, 0x64, 0xad, 0xfe, 0xe4, 0x9b, 0x2f, 0xc7, 0x81, 0xe6, 0x95, 0x15, 0x34, 0xf9, - 0x73, 0x44, 0x0d, 0xdb, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0xdc, 0xf7, 0x58, 0x76, 0xdc, - 0xa6, 0x09, 0xf9, 0xd2, 0x84, 0x71, 0xf9, 0x97, 0xfa, 0x11, 0xf9, 0x9d, 0x42, 0x3f, - 0x9c, 0xf1, 0x73, 0x4b, 0xe8, 0xa5, 0xff, 0x99, 0x7d, 0x45, 0x1e, 0xb3, 0xcf, 0x4b, - 0x3d, 0xfd, 0xd9, 0x06, 0xac, 0xac, 0x63, 0x52, 0x63, 0x6a, 0xdc, 0x17, 0xa8, 0x36, - 0xb1, 0x2b, 0x43, 0xbe, 0xfc, 0x0b, 0xe0, 0xa1, 0xbd, 0x36, 0x97, 0x72, 0x33, 0x80, - 0x78, 0xb4, 0xff, 0x7d, 0x8e, 0x2d, 0x97, 0x9a, 0x34, 0x41, 0xe1, 0xc8, 0xf5, 0xaf, - 0xe4, 0x7b, 0x1e, 0x7d, 0xa5, 0x6c, 0xf0, 0x06, 0x02, 0x00, 0x53, 0x11, 0x0c, 0x05, - 0xcf, 0x00, 0xfd, 0xa3, 0xe6, 0xcc, 0xe3, 0x60, 0x69, 0x04, 0x1f, 0xaf, 0xfd, 0x2f, - 0x77, 0xff, 0x06, 0x00, 0x02, 0xef, 0x12, 0xc3, 0x67, 0xf2, 0x1d, 0xea, 0x65, 0xc6, - 0xea, 0xaf, 0xb8, 0xaf, 0x58, 0x42, 0x8f, 0x6c, 0x54, 0x8e, 0x50, 0x17, 0x0f, 0x9e, - 0x6f, 0xcd, 0xdf, 0xe7, 0x51, 0xe0, 0xb6, 0x80, 0x12, 0xcb, 0x59, 0xdd, 0x46, 0x27, - 0xef, 0xc3, 0xea, 0x75, 0xdc, 0xd1, 0x5c, 0x8e, 0x0c, 0x3b, 0x8d, 0x8d, 0x7d, 0x6b, - 0x23, 0x31, 0xc8, 0xe4, 0x80, 0x16, 0x6b, 0x5a, 0xa7, 0x48, 0x5c, 0x9f, 0x0f, 0x83, - 0xe1, 0x9b, 0xc3, 0x0e, 0x64, 0x03, 0x82, 0x8c, 0xdb, 0x65, 0x2a, 0x55, 0x6b, 0x12, - 0x04, 0x09, 0x31, 0x40, 0x2a, 0xa6, 0xac, 0x34, 0xfc, 0x19, 0xfd, 0xc0, 0x6e, 0x2e, - 0x77, 0x87, 0xf5, 0x58, 0xd1, 0x42, 0xd9, 0x06, 0xea, 0xdb, 0x75, 0x90, 0xc9, 0x41, - 0x36, 0xda, 0x6a, 0x06, 0x35, 0x14, 0xd6, 0xa2, 0x5f, 0x7b, 0x37, 0xd7, 0x66, 0x4f, - 0x9b, 0x97, 0x09, 0x43, 0x3e, 0x6e, 0x70, 0x21, 0x18, 0xa4, 0xab, 0x9e, 0x7a, 0x7a, - 0x3e, 0x62, 0x59, 0x12, 0x99, 0x37, 0xd2, 0x9d, 0x0d, 0xb2, 0x60, 0x70, 0x52, 0x3e, - 0x8b, 0x06, 0x43, 0x13, 0x0a, 0xbe, 0xfe, 0x94, 0x3b, 0x40, 0x12, 0x98, 0xae, 0x01, - 0xa3, 0xab, 0x00, 0xab, 0xbc, 0x60, 0xd7, 0xdb, 0x93, 0x3c, 0x7f, 0x07, 0xa8, 0xbf, - 0x0f, 0x7c, 0xe1, 0x66, 0x0b, 0xcc, 0xb4, 0x5e, 0x04, 0x2b, 0x45, 0x1b, 0x93, 0x50, - 0x02, 0xce, 0xce, 0x27, 0xf3, 0x6a, 0xba, 0x56, 0x47, 0xac, 0x28, 0xd8, 0x18, 0x6c, - 0xdd, 0x1f, 0xb9, 0x5d, 0xc1, 0x35, 0xd4, 0x89, 0x92, 0xf6, 0x8d, 0xa1, 0x2a, 0xd6, - 0x1a, 0xc7, 0x56, 0x68, 0x0d, 0xd7, 0xf8, 0xd0, 0x77, 0x4a, 0xbd, 0x6c, 0xfd, 0xa2, - 0xf0, 0x32, 0xaf, 0x3b, 0xe1, 0x39, 0xa6, 0x33, 0xd6, 0x73, 0x3c, 0x75, 0xd1, 0xab, - 0xa8, 0x90, 0x18, 0xc8, 0x57, 0x2b, 0x99, 0xcd, 0x30, 0xc5, 0x37, 0x06, 0x79, 0x41, - 0xdf, 0x1c, 0x4b, 0xc1, 0xfd, 0x57, 0x0f, 0x7b, 0x4d, 0xdc, 0x97, 0x51, 0x86, 0x23, - 0xe3, 0xae, 0x4a, 0x87, 0xbd, 0xb9, 0x66, 0xc9, 0x4d, 0x86, 0x1e, 0x80, 0xde, 0x88, - 0xc2, 0x92, 0xae, 0xe9, 0x38, 0x71, 0x94, 0xe2, 0x56, 0xc6, 0x70, 0x07, 0x52, 0x30, - 0x1c, 0x73, 0xfc, 0x95, 0x65, 0xa4, 0x04, 0x80, 0xd8, 0x12, 0x6e, 0x9d, 0x08, 0x58, - 0x79, 0xe2, 0x4b, 0x16, 0xe9, 0xc4, 0x85, 0xd8, 0xf0, 0xd6, 0x18, 0xca, 0x0d, 0xd1, - 0x21, 0xb5, 0x1a, 0x7c, 0xab, 0x23, 0x0c, 0x5b, 0x45, 0x67, 0x2b, 0xdb, 0x8e, 0xa3, - 0xa0, 0x40, 0xf7, 0xaa, 0xa0, 0x98, 0xba, 0x26, 0x02, 0x5d, 0x2e, 0xab, 0x79, 0x48, - 0x69, 0x3d, 0xd5, 0xf6, 0xd3, 0x09, 0x65, 0x01, 0xe9, 0xe0, 0x71, 0x25, 0xd7, 0xeb, - 0x29, 0x3b, 0x3a, 0xba, 0xd5, 0x7f, 0xd5, 0xf0, 0x11, 0x64, 0x70, 0x02, 0xd6, 0x26, - 0xae, 0x88, 0xdc, 0x61, 0xe6, 0x47, 0xff, 0x46, 0x8d, 0xfa, 0x7a, 0x03, 0x07, 0x72, - 0x78, 0x79, 0x32, 0x75, 0xf1, 0x95, 0xa9, 0x75, 0x30, 0x28, 0x91, 0x78, 0x51, 0x61, - 0x80, 0xc5, 0xff, 0x99, 0x93, 0x53, 0x6b, 0xda, 0x15, 0x04, 0xba, 0x8b, 0xb4, 0x89, - 0x19, 0x88, 0xc1, 0x33, 0x4f, 0x31, 0xfb, 0x27, 0x6a, 0x03, 0x8a, 0xa8, 0xe9, 0x67, - 0xcb, 0x62, 0xa4, 0x92, 0x1b, 0xeb, 0x22, 0xb2, 0x08, 0xb0, 0x64, 0x58, 0x18, 0x47, - 0xb2, 0xf6, 0x4c, 0xa6, 0x48, 0x37, 0x00, 0x72, 0x16, 0xde, 0x6e, 0xca, 0xff, 0xeb, - 0x4b, 0x69, 0xe6, 0x33, 0x47, 0xf8, 0x4a, 0xbc, 0xad, 0x8f, 0x2e, 0x75, 0x7d, 0x58, - 0x61, 0xce, 0x77, 0xee, 0x46, 0x51, 0x3d, 0xa7, 0x41, 0x68, 0x37, 0xdc, 0xb2, 0x3d, - 0x33, 0xea, 0x72, 0xaf, 0x23, 0xd0, 0xad, 0x8c, 0x93, 0x07, 0xd0, 0xb5, 0x85, 0x8d, - 0xa9, 0x5b, 0x77, 0xff, 0xf9, 0x02, 0x7b, 0x88, 0x59, 0xe1, 0x1d, 0xcb, 0xd5, 0x98, - 0x35, 0x0e, 0xee, 0x50, 0x93, 0x94, 0x81, 0x70, 0x8e, 0xa7, 0x08, 0xeb, 0x9f, 0x66, - 0x43, 0x88, 0xb9, 0xc6, 0x4d, 0x6a, 0xf0, 0xf9, 0x66, 0x90, 0x34, 0x24, 0x00, 0x34, - 0x8e, 0x92, 0x9e, 0x07, 0x46, 0x02, 0x53, 0xf3, 0x83, 0x90, 0xf8, 0x7b, 0xd6, 0xc0, - 0x53, 0x08, 0xc3, 0xbd, 0xe2, 0x52, 0x28, 0xe0, 0xfa, 0x08, 0x80, 0xb0, 0x8e, 0xf3, - 0x4a, 0x5a, 0x9c, 0xc0, 0xea, 0x0a, 0x67, 0xca, 0x65, 0xb6, 0xff, 0xd0, 0x05, 0x57, - 0x29, 0x09, 0xf1, 0xc4, 0x2d, 0xd7, 0x45, 0xee, 0xee, 0x9d, 0xd6, 0xb4, 0x43, 0x9c, - 0x9f, 0x3f, 0x98, 0xa1, 0x18, 0xfe, 0x16, 0x69, 0x8e, 0x9c, 0xef, 0xf5, 0x58, 0xf1, - 0x60, 0x66, 0x97, 0x5f, 0xe3, 0x95, 0x83, 0xe9, 0xb5, 0x85, 0x3b, 0x13, 0x11, 0x39, - 0x15, 0x80, 0x01, 0x9f, 0xe5, 0x5d, 0x59, 0xd1, 0xc8, 0x28, 0xd3, 0xfe, 0xb6, 0xa3, - 0xb9, 0xce, 0x92, 0xd0, 0x89, 0xae, 0x4b, 0x40, 0x8e, 0x23, 0xd6, 0xa4, 0x37, 0xd4, - 0x98, 0x9b, 0x51, 0x9b, 0x7a, 0x9e, 0xb0, 0x8a, 0xe6, 0xd4, 0x48, 0xa7, 0xa1, 0x6e, - 0x8a, 0xed, 0x26, 0xa2, 0xec, 0xd0, 0xca, 0xd8, 0x08, 0x44, 0xfd, 0x06, 0x50, 0xd8, - 0xc4, 0xe4, 0xd2, 0xaf, 0x90, 0x65, 0x67, 0x48, 0xd8, 0x09, 0x9a, 0x0c, 0x75, 0x6f, - 0xc1, 0x6c, 0xca, 0x06, 0xa3, 0x34, 0x43, 0x07, 0x02, 0xae, 0x19, 0x61, 0x66, 0x5b, - 0x48, 0x45, 0xac, 0xd1, 0xa8, 0xe3, 0x41, 0x01, 0xe6, 0x8b, 0xb6, 0x44, 0xac, 0x03, - 0x4d, 0xc6, 0x3e, 0x6e, 0x34, 0x4c, 0x3d, 0x63, 0x76, 0x2a, 0x7a, 0x5b, 0xf5, 0x9f, - 0x13, 0x09, 0x54, 0x10, 0x98, 0x1d, 0x6b, 0x6b, 0x16, 0xbc, 0xd4, 0xc9, 0xfa, 0x68, - 0xaf, 0x6e, 0x53, 0x01, 0xef, 0x19, 0xbf, 0x3a, 0x43, 0x2e, 0x40, 0x6f, 0x85, 0x67, - 0xeb, 0xd9, 0x77, 0x2e, 0x92, 0xb5, 0xca, 0x5a, 0x59, 0x96, 0x71, 0xcb, 0xfd, 0x7d, - 0xdf, 0xa3, 0x63, 0xa5, 0x36, 0xb7, 0xac, 0x45, 0xf5, 0x7c, 0xc3, 0x7d, 0x09, 0x89, - 0x6f, 0xa9, 0x06, 0x97, 0x2e, 0x55, 0x71, 0x80, 0xa4, 0xab, 0x5a, 0xd0, 0x9d, 0x88, - 0x46, 0xdd, 0x6d, 0xa7, 0x48, 0x76, 0x54, 0x36, 0xe0, 0x16, 0x02, 0x40, 0xbd, 0x5c, - 0x92, 0x16, 0x66, 0xa1, 0xee, 0xaa, 0xce, 0x04, 0xa7, 0x1b, 0x50, 0x3a, 0x1c, 0xad, - 0xf8, 0x0b, 0x39, 0x24, 0x26, 0x6c, 0x59, 0x50, 0x4f, 0x8f, 0x21, 0x5f, 0x61, 0x8b, - 0x05, 0xd5, 0x45, 0x43, 0xb6, 0xe2, 0x6d, 0x82, 0x59, 0x6f, 0xc5, 0x3b, 0x52, 0x31, - 0x2c, 0x77, 0x6d, 0x12, 0xeb, 0x2b, 0x65, 0x9b, 0x4f, 0xb0, 0x98, 0xdf, 0x87, 0xd6, - 0x83, 0xcf, 0x9e, 0x54, 0x12, 0xee, 0x56, 0xc3, 0xfe, 0x98, 0x41, 0xd7, 0x3f, 0xd0, - 0x70, 0xdf, 0xa5, 0x1f, 0x5b, 0xaf, 0xed, 0xf2, 0x06, 0xf1, 0x3c, 0x52, 0x4e, 0x5c, - 0x50, 0xca, 0xc9, 0x90, 0x6e, 0xfa, 0x39, 0x32, 0x90, 0x04, 0x2e, 0x3b, 0xc5, 0x9f, - 0x96, 0x0b, 0x7d, 0x24, 0x0a, 0xe4, 0x43, 0xfc, 0x49, 0x26, 0x9c, 0xe0, 0x00, 0x61, - 0xe6, 0x5c, 0x6d, 0x74, 0x81, 0x2a, 0x30, 0xdd, 0x5f, 0x5f, 0xe7, 0x4e, 0xff, 0x61, - 0xe0, 0xcb, 0xab, 0x3c, 0xec, 0x75, 0xd0, 0xae, 0xf9, 0x50, 0x83, 0x18, 0x94, 0x52, - 0xdd, 0x3d, 0x9e, 0xdf, 0x44, 0x87, 0xbc, 0x73, 0x4c, 0x8b, 0x24, 0xf2, 0x12, 0x96, - 0xe4, 0xe9, 0xef, 0x11, 0x7d, 0x7f, 0xb9, 0x77, 0xe3, 0xb0, 0xe6, 0x40, 0x6e, 0x63, - 0x08, 0x59, 0x06, 0x33, 0x1a, 0x93, 0x03, 0x3d, 0x1c, 0xb8, 0x36, 0x0f, 0xe6, 0xfe, - 0xa6, 0x1a, 0x68, 0x26, 0xdf, 0x36, 0x25, 0x57, 0x89, 0xf9, 0x2e, 0x40, 0xba, 0xfc, - 0xb2, 0xeb, 0xcb, 0x9e, 0x55, 0x6f, 0x6c, 0x0c, 0xca, 0xdc, 0x6a, 0xf0, 0x8e, 0x31, - 0xec, 0x4a, 0xd5, 0x28, 0x80, 0x34, 0xe1, 0x6d, 0x15, 0x5c, 0xfd, 0xca, 0xda, 0x7b, - 0xab, 0x59, 0x9c, 0x2f, 0xa4, 0xad, 0x2e, 0x62, 0x93, 0xf9, 0xfe, 0x09, 0x71, 0x69, - 0x14, 0x82, 0x76, 0xb6, 0xa9, 0xea, 0xa7, 0x2f, 0x14, 0x8b, 0x0c, 0x95, 0x65, 0xc3, - 0xc2, 0xdd, 0x63, 0x12, 0x5e, 0x0f, 0xa5, 0x30, 0x86, 0x1a, 0x71, 0x0d, 0xf8, 0xe4, - 0x81, 0xf2, 0x71, 0x29, 0x20, 0xf8, 0x78, 0x7e, 0x0a, 0xed, 0xfe, 0x61, 0x8a, 0xff, - 0x50, 0xa3, 0xb5, 0x62, 0x13, 0x88, 0x4d, 0x62, 0x62, 0xc1, 0x1d, 0xeb, 0xf2, 0xba, - 0x7e, 0x8a, 0xd6, 0x69, 0x2c, 0xb1, 0x70, 0x78, 0x33, 0x14, 0x18, 0xda, 0x4b, 0xe0, - 0x64, 0xff, 0x52, 0x70, 0x07, 0x39, 0x34, 0xab, 0xcd, 0x2a, 0xb0, 0x46, 0x9e, 0xca, - 0xf7, 0x27, 0x5b, 0x4b, 0xd7, 0x2b, 0xc6, 0xed, 0x34, 0x47, 0x8e, 0xa4, 0x08, 0x9b, - 0x73, 0x6a, 0x16, 0xdd, 0x90, 0x6d, 0x49, 0xf2, 0x5c, 0x33, 0x82, 0x7c, 0x57, 0x1c, - 0xe0, 0xb5, 0xd7, 0x21, 0x77, 0xaa, 0x35, 0x08, 0x80, 0x4b, 0xc0, 0xf8, 0xfa, 0xa9, - 0x47, 0x12, 0x22, 0x31, 0x40, 0x2d, 0x2f, 0x5c, 0xc9, 0xa0, 0xeb, 0x0e, 0x09, 0xd4, - 0x27, 0xb4, 0x27, 0x28, 0x8d, 0x93, 0x7d, 0x9d, 0x72, 0xb7, 0x74, 0x56, 0xf8, 0x86, - 0x59, 0x4c, 0xd8, 0xc6, 0xa4, 0x62, 0xf7, 0x7f, 0xd8, 0x30, 0x76, 0x46, 0x9c, 0xc0, - 0xec, 0xba, 0x3c, 0xc4, 0x0c, 0xad, 0x69, 0xe5, 0xb5, 0x41, 0x12, 0xea, 0xb3, 0x33, - 0x96, 0xae, 0xcf, 0xbc, 0x21, 0x1f, 0x1f, 0x79, 0xcf, 0x33, 0x10, 0x8e, 0x93, 0xd9, - 0x53, 0x78, 0xba, 0xe6, 0x95, 0x82, 0x74, 0xb3, 0x10, 0x88, 0xfb, 0xd8, 0xb3, 0xa3, - 0xa0, 0xd1, 0x54, 0xa7, 0x89, 0x73, 0x5b, 0x03, 0x49, 0xc4, 0xd5, 0x1c, 0x88, 0x9d, - 0x08, 0x95, 0x2d, 0xdd, 0x54, 0x88, 0xbe, 0x95, 0x56, 0x05, 0x94, 0xe6, 0x73, 0xfa, - 0x05, 0x1b, 0xf9, 0xb6, 0x14, 0xa1, 0x5e, 0x10, 0x0b, 0x60, 0xa0, 0xfe, 0x9a, 0x7e, - 0x12, 0xa9, 0xb2, 0x56, 0xdf, 0x58, 0x9b, 0x3e, 0x48, 0xe5, 0xb8, 0x0f, 0xb8, 0xcf, - 0xf0, 0x3e, 0x86, 0xf6, 0x0c, 0xc0, 0x70, 0xfb, 0x23, 0xc9, 0x7d, 0x4c, 0x14, 0xfa, - 0x3a, 0x73, 0x46, 0xff, 0x55, 0x6b, 0xc6, 0x85, 0x5a, 0x5f, 0x83, 0xe3, 0xdc, 0xd9, - 0xf6, 0xea, 0xb3, 0xda, 0xbc, 0xd4, 0x77, 0x50, 0xe3, 0x4e, 0x7c, 0x09, 0x38, 0xf6, - 0x4d, 0x45, 0x1e, 0x39, 0x50, 0x9e, 0x90, 0x27, 0x47, 0xa7, 0x07, 0x55, 0x12, 0x20, - 0x95, 0x08, 0x2a, 0xb7, 0x98, 0x59, 0x19, 0x07, 0x31, 0x41, 0xb6, 0xd3, 0x70, 0x20, - 0x91, 0xab, 0x71, 0x72, 0x80, 0xbd, 0xc5, 0x5e, 0x79, 0x9c, 0x01, 0xad, 0x86, 0x41, - 0x90, 0x4e, 0x3b, 0x1d, 0xd2, 0x9e, 0x1a, 0x96, 0x4c, 0x73, 0x7d, 0x3c, 0x15, 0x5a, - 0xfb, 0x30, 0x7b, 0x74, 0x8e, 0x41, 0x12, 0xb4, 0x8b, 0x77, 0xd5, 0xed, 0x57, 0x00, - 0xe6, 0x00, 0x2b, 0x18, 0xb0, 0xfe, 0xd2, 0xcf, 0xfd, 0xf6, 0x1f, 0xd9, 0x93, 0x4b, - 0x60, 0x73, 0x2f, 0x4d, 0x37, 0x81, 0x0a, 0x91, 0xac, 0xef, 0x1e, 0x03, 0x8b, 0x81, - 0xd7, 0x36, 0xd9, 0x8e, 0xad, 0xa9, 0xcd, 0x7e, 0x0c, 0x2b, 0xe2, 0x7a, 0xb8, 0x50, - 0x32, 0x06, 0x60, 0x91, 0x22, 0x4e, 0xdf, 0x87, 0x2f, 0x79, 0x63, 0x7d, 0xda, 0x39, - 0x16, 0x79, 0x6a, 0x5c, 0x62, 0xf5, 0x7f, 0x1d, 0xe3, 0x76, 0x78, 0xb6, 0xde, 0xa0, - 0x08, 0x69, 0x93, 0x36, 0x74, 0xf8, 0x8e, 0x41, 0xa9, 0x18, 0x08, 0x07, 0x3b, 0x0f, - 0x43, 0x6e, 0xbe, 0x25, 0xa5, 0xf4, 0x4a, 0x60, 0x10, 0x33, 0xe2, 0x18, 0x4b, 0x88, - 0xdb, 0x79, 0xe9, 0x68, 0xca, 0x6d, 0x89, 0xb7, 0x49, 0x01, 0xbe, 0x6c, 0x6d, 0xb3, - 0x63, 0x65, 0x80, 0x18, 0x2e, 0x65, 0x8d, 0xfc, 0x68, 0x67, 0x67, 0xd6, 0xd8, 0x19, - 0xfa, 0x92, 0x3e, 0x0c, 0xdf, 0x3e, 0xa3, 0x65, 0x76, 0xf8, 0x52, 0xbc, 0xd4, 0xe1, - 0x96, 0xa7, 0x1a, 0x13, 0x29, 0xf6, 0xc3, 0xff, 0x8e, 0x42, 0xe3, 0x09, 0x5a, 0xbd, - 0x8e, 0xc1, 0x97, 0x99, 0x07, 0x13, 0xee, 0x89, 0x39, 0x4c, 0x57, 0x19, 0xb2, 0x76, - 0xde, 0x8f, 0x81, 0x8a, 0x34, 0xa7, 0xbe, 0xc1, 0xf2, 0x68, 0x68, 0x2e, 0x91, 0x42, - 0xc7, 0xd3, 0x87, 0x89, 0xf6, 0x76, 0xcc, 0x12, 0xb7, 0x1a, 0xb6, 0x66, 0x35, 0xc5, - 0x02, 0xe6, 0x9d, 0x05, 0xb9, 0xc7, 0xef, 0x01, 0x52, 0x97, 0x75, 0xc6, 0x23, 0xa4, - 0x8e, 0x4c, 0xc5, 0xc4, 0x15, 0xc9, 0xfd, 0x56, 0x53, 0x65, 0xa4, 0x16, 0x37, 0x68, - 0x78, 0x51, 0x53, 0x88, 0x7f, 0xb5, 0xf9, 0x63, 0xe7, 0xac, 0xc1, 0x62, 0xf2, 0x80, - 0x5f, 0x45, 0xf4, 0x44, 0x87, 0xf8, 0x5e, 0x19, 0x9c, 0x1d, 0xf4, 0xa0, 0xfc, 0xa4, - 0xd4, 0x4b, 0xaa, 0x62, 0xda, 0x7a, 0xf5, 0xed, 0x69, 0x68, 0x41, 0x12, 0xd3, 0x5f, - 0x00, 0x73, 0x73, 0x2f, 0x5a, 0x1a, 0xc3, 0xe4, 0xf0, 0x21, 0xba, 0x5c, 0x2c, 0x32, - 0xf0, 0x6e, 0x6b, 0x90, 0xfa, 0xe2, 0xd2, 0x54, 0xcf, 0x09, 0xe7, 0x69, 0x0c, 0xf4, - 0xe3, 0xaa, 0x70, 0x30, 0x98, 0x74, 0x48, 0xe1, 0x47, 0xf9, 0x43, 0xba, 0xb5, 0xca, - 0xb5, 0x58, 0x02, 0x9a, 0x36, 0x02, 0x4d, 0x2e, 0x79, 0x0f, 0xc6, 0xfd, 0x66, 0x7f, - 0x17, 0x6e, 0x0a, 0xa9, 0x9d, 0xd1, 0xd7, 0x2b, 0x57, - ], - script_code: vec![0x6a, 0x51, 0x65, 0xac], - transparent_input: None, - hash_type: 1, - amount: 691732482992802, - consensus_branch_id: 1991772603, - sighash: [ - 0x5d, 0x40, 0x5a, 0x1c, 0x4d, 0xed, 0x19, 0x87, 0x98, 0x8a, 0x10, 0x03, 0x64, 0xa3, - 0xcd, 0x6f, 0xe0, 0xba, 0x22, 0x20, 0xa6, 0xab, 0xce, 0x08, 0xc5, 0x17, 0x13, 0x59, - 0x55, 0x30, 0x65, 0xe9, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x01, 0xa4, 0x96, 0x69, 0x60, 0x21, - 0x82, 0x08, 0x46, 0x69, 0x61, 0x12, 0x94, 0x90, 0xa7, 0xd8, 0xb6, 0x5c, 0x14, 0x70, - 0xba, 0xd8, 0xdb, 0x08, 0x28, 0xef, 0x06, 0xc1, 0xcb, 0x55, 0x70, 0x0e, 0x85, 0xe2, - 0x4f, 0xde, 0xa9, 0x08, 0x52, 0x00, 0x65, 0x63, 0x52, 0x51, 0xac, 0x51, 0x87, 0x1f, - 0x88, 0xfb, 0x02, 0x57, 0x2c, 0x4f, 0x50, 0xa0, 0xf8, 0x01, 0x00, 0x06, 0x63, 0x00, - 0x63, 0x63, 0x51, 0xac, 0xcb, 0x37, 0x9c, 0x68, 0xc8, 0x7d, 0x04, 0x00, 0x03, 0x00, - 0x6a, 0x63, 0x53, 0x3c, 0x92, 0xcf, 0x4c, 0x1c, 0xac, 0x18, 0x99, 0x41, 0x99, 0xa8, - 0xec, 0x8e, 0x01, 0x00, 0x04, 0x1b, 0x31, 0xeb, 0xfb, 0xf8, 0x18, 0xa3, 0x99, 0x2b, - 0xf3, 0x68, 0xc2, 0x4e, 0x9a, 0xcc, 0x83, 0x14, 0x2b, 0x24, 0x0f, 0xec, 0x55, 0x4c, - 0xed, 0xa1, 0xd3, 0xfc, 0x04, 0x32, 0xc5, 0x72, 0x51, 0x34, 0x19, 0xaf, 0x1d, 0xe6, - 0x56, 0xfd, 0xd0, 0x39, 0x07, 0x22, 0xa7, 0xf4, 0x6a, 0x1f, 0xc0, 0x56, 0x3f, 0x0a, - 0xda, 0xb8, 0xbc, 0xbb, 0xb0, 0xd1, 0xb2, 0x29, 0xf5, 0xa5, 0xb9, 0x23, 0x03, 0x77, - 0x5a, 0x90, 0x4d, 0xec, 0x82, 0x7f, 0xd8, 0x7a, 0x18, 0x86, 0x0d, 0x6e, 0x8a, 0x4a, - 0x52, 0xb5, 0xcf, 0x44, 0xbe, 0x28, 0xa6, 0x2d, 0x41, 0x59, 0x02, 0x09, 0x3a, 0x0c, - 0x36, 0x5d, 0x29, 0x24, 0x12, 0x01, 0xb8, 0x26, 0x1a, 0x49, 0xd4, 0x91, 0xaf, 0x04, - 0x9b, 0x39, 0xe2, 0x6d, 0x13, 0x57, 0xc3, 0x06, 0x92, 0x64, 0x16, 0x77, 0x6d, 0x7d, - 0x13, 0xf8, 0x40, 0xbd, 0x82, 0xac, 0xa0, 0x1c, 0x83, 0x1c, 0x98, 0x3f, 0x19, 0x85, - 0xee, 0x0a, 0xda, 0xe8, 0xdb, 0x84, 0x47, 0xc0, 0xe5, 0x1c, 0x09, 0xdf, 0xe3, 0xde, - 0xe3, 0x88, 0x0a, 0x97, 0x13, 0xce, 0xb7, 0x45, 0xab, 0xfd, 0xd9, 0xf1, 0xc7, 0xea, - 0xd7, 0x63, 0x08, 0xcd, 0xee, 0xa2, 0x1c, 0x8b, 0x09, 0x57, 0x02, 0x7c, 0x5d, 0x00, - 0xe5, 0x0a, 0x43, 0x88, 0xc7, 0xaf, 0x2b, 0xd6, 0x43, 0xcb, 0x5e, 0xae, 0x49, 0x27, - 0x4d, 0x12, 0x30, 0xa4, 0xcd, 0x49, 0x23, 0x7a, 0xe3, 0x7b, 0x38, 0x10, 0xc2, 0xc3, - 0x95, 0x8a, 0x7d, 0xee, 0x02, 0x34, 0x30, 0x1b, 0x89, 0xa2, 0xdf, 0x2a, 0x78, 0xef, - 0x0b, 0xfb, 0x4b, 0xf6, 0xb3, 0x87, 0xdf, 0x2c, 0x6c, 0x86, 0xe6, 0x1c, 0xd1, 0x0c, - 0xa1, 0x1f, 0x81, 0x13, 0x01, 0x26, 0x07, 0xf1, 0x5b, 0x28, 0x56, 0x24, 0x0f, 0xdc, - 0x52, 0x06, 0x5a, 0x10, 0x28, 0xc8, 0xa2, 0xdd, 0xfd, 0xd1, 0x5c, 0xf5, 0x26, 0x5f, - 0x87, 0x38, 0x8a, 0xb9, 0xbf, 0x21, 0xc9, 0xa7, 0x8c, 0x59, 0x03, 0x8a, 0x98, 0xab, - 0x64, 0xfd, 0x67, 0x10, 0x77, 0xd4, 0x72, 0xc2, 0x09, 0xdd, 0x72, 0x9b, 0xd7, 0xf8, - 0x48, 0x09, 0x45, 0xfb, 0xa7, 0x52, 0x09, 0x8a, 0x94, 0xcc, 0xb2, 0x4c, 0xf3, 0xbc, - 0x09, 0x2d, 0x42, 0x36, 0x46, 0x11, 0xa2, 0x93, 0xaf, 0xf3, 0xc5, 0x79, 0x37, 0x2c, - 0x12, 0xe1, 0x50, 0x90, 0xaa, 0x27, 0x23, 0x20, 0x57, 0xf2, 0xed, 0xde, 0x4e, 0x1d, - 0xb2, 0x92, 0xf7, 0xb1, 0x86, 0x47, 0x22, 0x67, 0x35, 0x17, 0x6d, 0x90, 0xf1, 0x26, - 0x5b, 0x37, 0x98, 0xcc, 0xab, 0xac, 0x0b, 0x8d, 0x79, 0xb1, 0x77, 0x20, 0xb2, 0xba, - 0x71, 0xd7, 0x85, 0x0c, 0xc2, 0xa0, 0x87, 0x2b, 0xf0, 0xf4, 0xb8, 0x14, 0x36, 0x78, - 0x59, 0xf8, 0x99, 0x48, 0xf0, 0xa1, 0xa3, 0x83, 0x60, 0x4b, 0x9e, 0x1a, 0xa4, 0xc7, - 0xea, 0x28, 0x92, 0x05, 0x6f, 0x81, 0x28, 0x5b, 0xc2, 0x6f, 0x30, 0x08, 0x5d, 0xd0, - 0xef, 0x3b, 0x14, 0xd1, 0x7d, 0xda, 0x57, 0x30, 0x6a, 0xe4, 0xf6, 0x6c, 0x45, 0x9a, - 0xee, 0x8a, 0x4e, 0xd9, 0x02, 0xc6, 0x6e, 0x49, 0x18, 0xfa, 0xee, 0x8d, 0xc0, 0x06, - 0x72, 0x46, 0x96, 0x0d, 0xb1, 0xf8, 0xcd, 0x07, 0xbf, 0x90, 0xd7, 0x53, 0x7c, 0xc2, - 0x7b, 0xbb, 0x8c, 0x9d, 0x5b, 0x29, 0x62, 0xc4, 0x7e, 0xd1, 0x82, 0xa2, 0xfc, 0xe0, - 0x5f, 0x8e, 0x03, 0xc4, 0xe2, 0x5e, 0x49, 0x6d, 0xd5, 0x7d, 0x6a, 0xb3, 0x45, 0x8f, - 0xac, 0xbd, 0x91, 0xea, 0x22, 0x72, 0xff, 0xda, 0x47, 0xbf, 0xd0, 0x17, 0x39, 0x20, - 0xd7, 0x17, 0x51, 0x30, 0xf0, 0xe4, 0xd0, 0x93, 0x74, 0x41, 0xbc, 0xe9, 0x8c, 0xfa, - 0x5b, 0x33, 0x3b, 0x66, 0x19, 0x0f, 0x2b, 0x44, 0x71, 0x38, 0xe8, 0xc2, 0x6d, 0x84, - 0x12, 0xca, 0xc8, 0x20, 0x86, 0xd6, 0x1b, 0x5d, 0x2c, 0x8c, 0xf0, 0xbb, 0xeb, 0xac, - 0x5b, 0x89, 0xbf, 0xe8, 0x2b, 0x58, 0x91, 0x76, 0x64, 0xba, 0xb9, 0x1c, 0xe2, 0xec, - 0xe2, 0x90, 0xb2, 0x7b, 0x60, 0x52, 0xd4, 0xbf, 0x99, 0x1a, 0x33, 0xf4, 0x58, 0x1a, - 0x63, 0x36, 0x25, 0x78, 0x79, 0x58, 0x89, 0x7f, 0xca, 0x4b, 0x98, 0xb7, 0xe7, 0x27, - 0x7c, 0x5e, 0x6a, 0x1d, 0x88, 0x59, 0x48, 0xc9, 0xd4, 0x84, 0xdd, 0x0c, 0xef, 0xef, - 0x85, 0x4e, 0x81, 0x76, 0xc3, 0x97, 0xdc, 0xfa, 0x77, 0x2e, 0x71, 0x14, 0x72, 0xe7, - 0x90, 0xba, 0x8d, 0x39, 0x35, 0xd5, 0x7c, 0xa3, 0x13, 0x49, 0x37, 0x9e, 0x62, 0x83, - 0xa6, 0xaa, 0x8f, 0xc9, 0x91, 0xef, 0xc7, 0xd3, 0xb7, 0xef, 0x66, 0xb9, 0x2f, 0xe0, - 0x9d, 0x35, 0x16, 0x27, 0x0a, 0xe1, 0x9a, 0x99, 0x92, 0x16, 0xee, 0xae, 0x16, 0x21, - 0x44, 0xac, 0xea, 0x56, 0x0d, 0x17, 0x72, 0x05, 0xf2, 0x6c, 0x97, 0x03, 0xb5, 0x4e, - 0x80, 0xaf, 0x1a, 0x87, 0x94, 0xd6, 0xd3, 0xf1, 0xc5, 0xee, 0xad, 0x22, 0x0b, 0x11, - 0x9f, 0x06, 0xb2, 0x00, 0x98, 0x6c, 0x91, 0x21, 0x32, 0xcb, 0x08, 0xa9, 0x8e, 0x0f, - 0xee, 0x35, 0xe7, 0xf7, 0x7f, 0xc8, 0x52, 0x1d, 0x38, 0x77, 0x3e, 0x61, 0x4e, 0xee, - 0xb8, 0xa3, 0xea, 0xd8, 0x6a, 0x02, 0x48, 0x32, 0xe6, 0x4a, 0x4c, 0x75, 0x72, 0x0c, - 0xdc, 0xdd, 0xf9, 0xd0, 0x77, 0x09, 0xa1, 0x68, 0xd0, 0x10, 0x12, 0xc2, 0xe4, 0xf3, - 0x34, 0x30, 0xf2, 0x99, 0x70, 0xc6, 0x0b, 0xe8, 0xc5, 0xe2, 0xc8, 0xcc, 0x8a, 0x86, - 0xed, 0xcd, 0x51, 0x2d, 0xa7, 0x0d, 0xd7, 0xbb, 0x40, 0xe2, 0x7b, 0x32, 0xdf, 0x3d, - 0x77, 0x6a, 0x4a, 0x7b, 0x00, 0xe3, 0xbd, 0x8f, 0x69, 0x7f, 0x1f, 0x4e, 0x5c, 0x9f, - 0xbe, 0xbe, 0xb4, 0xe6, 0xfa, 0xd9, 0x1e, 0x09, 0x3d, 0xd5, 0xba, 0xc9, 0x92, 0xac, - 0xbc, 0xb8, 0x38, 0x3f, 0x9a, 0x8d, 0x8c, 0x04, 0xea, 0x6e, 0x2e, 0x0d, 0x03, 0xa2, - 0xdf, 0x83, 0xd4, 0xf4, 0x94, 0x59, 0x5b, 0x2c, 0xa1, 0x0b, 0x70, 0x79, 0x25, 0x9c, - 0x50, 0x7d, 0xf1, 0xec, 0xe4, 0x4d, 0xea, 0x4e, 0x9a, 0x4a, 0xe4, 0x0e, 0xc8, 0x33, - 0x1e, 0xeb, 0x03, 0x94, 0x73, 0xbd, 0x39, 0xc0, 0x9d, 0x01, 0x4b, 0x0d, 0x7b, 0xb9, - 0x01, 0x61, 0x66, 0x55, 0x4f, 0xf3, 0x8a, 0x1d, 0x77, 0xf2, 0xfd, 0xa4, 0xe7, 0xeb, - 0xa7, 0xa7, 0x8a, 0xb3, 0x1f, 0x38, 0x29, 0x42, 0x52, 0xa2, 0xb1, 0x0f, 0xd2, 0x86, - 0x5b, 0x57, 0x05, 0x05, 0x5d, 0xfe, 0x9b, 0x3e, 0x9e, 0x8f, 0x7a, 0xd5, 0xf4, 0x00, - 0x7d, 0xbe, 0x42, 0x2b, 0x3a, 0xa0, 0xbe, 0xb9, 0xd1, 0xc8, 0x9d, 0x37, 0x46, 0x08, - 0x54, 0xff, 0x6e, 0x5f, 0x03, 0xe5, 0xff, 0x3d, 0x4f, 0x18, 0x48, 0xf4, 0xcc, 0x64, - 0x21, 0x8a, 0x01, 0xf2, 0x47, 0x2b, 0xb0, 0x55, 0x80, 0x2f, 0x97, 0xf3, 0x20, 0x41, - 0xa7, 0x92, 0x79, 0x0b, 0x7c, 0x22, 0x6b, 0x04, 0xa6, 0xea, 0xe8, 0x5f, 0x1b, 0x71, - 0xca, 0x19, 0xa1, 0x71, 0x89, 0x02, 0xb4, 0xc3, 0xa3, 0xb5, 0x06, 0xd8, 0xc1, 0xb7, - 0xae, 0x72, 0x8c, 0x9b, 0x6c, 0xc3, 0x17, 0xe5, 0xe0, 0xde, 0xe5, 0x33, 0xe2, 0xe9, - 0x99, 0x73, 0xd8, 0x83, 0xa4, 0x0c, 0x6e, 0x68, 0xf2, 0x31, 0xd2, 0xcb, 0x01, 0x2f, - 0x60, 0xc1, 0x43, 0xcc, 0xab, 0xdd, 0x40, 0x45, 0x59, 0x0d, 0x9e, 0x43, 0xfb, 0xa3, - 0x6f, 0xe4, 0xcf, 0xd9, 0x7b, 0x4b, 0xdd, 0x0c, 0x4d, 0x2c, 0x93, 0xc5, 0x72, 0x8b, - 0x12, 0x87, 0xfd, 0x25, 0x41, 0x72, 0x2c, 0x69, 0x9b, 0xc1, 0xa0, 0x05, 0x83, 0xdb, - 0xc9, 0x48, 0xd5, 0x32, 0x4a, 0xc5, 0xbd, 0x7a, 0x68, 0x09, 0x64, 0x67, 0x3e, 0xdf, - 0x2c, 0x6d, 0xeb, 0xb1, 0xc8, 0xe1, 0xd0, 0x24, 0x16, 0xe6, 0xbd, 0xb2, 0xa7, 0x68, - 0x1b, 0xf4, 0x29, 0x92, 0x25, 0xc2, 0x1b, 0x5d, 0xb6, 0xa8, 0x45, 0xad, 0x10, 0x4d, - 0x34, 0x29, 0xcd, 0xc5, 0x9e, 0x3b, 0xca, 0xcf, 0x6d, 0xbc, 0x88, 0xaf, 0x0f, 0x67, - 0xdc, 0xbd, 0xf3, 0xa0, 0x72, 0x3e, 0x4d, 0x4b, 0xce, 0x32, 0x85, 0x1b, 0xb5, 0x19, - 0x7a, 0x8f, 0x43, 0x30, 0xb2, 0x72, 0x27, 0xf0, 0xb7, 0x71, 0xd0, 0xaf, 0x17, 0x5e, - 0x9c, 0x3f, 0x6e, 0x1f, 0x68, 0x46, 0x2e, 0xe7, 0xfe, 0x17, 0x97, 0xd9, 0x28, 0x40, - 0x6f, 0x92, 0x38, 0xa3, 0xf3, 0xfd, 0x83, 0x6a, 0x27, 0x56, 0xdd, 0x0a, 0x11, 0xe1, - 0xab, 0x94, 0x9d, 0x5e, 0x30, 0x89, 0x4f, 0x56, 0x29, 0x95, 0x25, 0xe6, 0x5d, 0x95, - 0x0f, 0x2e, 0xb5, 0x0b, 0x3a, 0x8e, 0xa7, 0xac, 0xad, 0x82, 0xde, 0x26, 0x2f, 0xa3, - 0x44, 0x80, 0xa2, 0x9c, 0x26, 0x19, 0xba, 0x45, 0x90, 0x3d, 0xf9, 0xa7, 0xf9, 0x86, - 0x2d, 0xc0, 0x49, 0xce, 0xf3, 0x97, 0xf7, 0x73, 0xbe, 0xed, 0xd3, 0x22, 0x6a, 0x8c, - 0xab, 0x1c, 0x86, 0x4d, 0x00, 0xb8, 0xfd, 0x37, 0xea, 0xf1, 0xd5, 0x93, 0x5a, 0x5b, - 0xbb, 0x6a, 0xd9, 0xf2, 0x7a, 0x1d, 0x8b, 0xaf, 0xc0, 0xac, 0x5f, 0x58, 0x02, 0x36, - 0x93, 0x82, 0x2a, 0x1d, 0xd4, 0xa7, 0xca, 0x1c, 0x49, 0xec, 0x81, 0x4e, 0x8f, 0xe6, - 0xe0, 0xe0, 0xde, 0x54, 0x6a, 0x4f, 0xbe, 0x7d, 0x25, 0x67, 0x0b, 0x2f, 0xc6, 0x8a, - 0x8f, 0xb2, 0xc4, 0xa6, 0x3d, 0xef, 0xec, 0x79, 0xc9, 0x0c, 0x63, 0xff, 0x96, 0xe5, - 0x40, 0xb7, 0x61, 0x5d, 0x43, 0xa6, 0x26, 0x1d, 0x57, 0x73, 0x03, 0x06, 0xb6, 0x63, - 0x2c, 0x8e, 0xe6, 0x1b, 0xaa, 0x4a, 0xb4, 0xd3, 0x08, 0x4d, 0x65, 0x9c, 0xab, 0xcf, - 0xc4, 0x06, 0x4c, 0x09, 0xd2, 0x42, 0x69, 0xb3, 0x03, 0x17, 0x10, 0xb6, 0x7d, 0x3b, - 0x0b, 0x73, 0x6f, 0xac, 0xbc, 0x18, 0x1e, 0xb1, 0xdc, 0x8c, 0x49, 0x3f, 0x10, 0xdb, - 0xe6, 0xfe, 0x45, 0xfd, 0xd4, 0xab, 0x60, 0x22, 0xfa, 0xbd, 0xd3, 0x4c, 0x09, 0xf7, - 0x51, 0x04, 0xc3, 0x85, 0xc9, 0x26, 0x83, 0x41, 0xc1, 0x6e, 0xbe, 0x80, 0xf8, 0xc8, - 0x0e, 0x8e, 0x06, 0x23, 0x06, 0x03, 0x99, 0x5a, 0xde, 0x55, 0x61, 0xfe, 0xd4, 0x5c, - 0xf8, 0xd1, 0x14, 0xd4, 0xcf, 0x02, 0x42, 0x0c, 0x4b, 0x96, 0x2d, 0xc2, 0x02, 0xf8, - 0xa5, 0x07, 0xf3, 0xd8, 0xe8, 0xa3, 0x44, 0xfb, 0xa1, 0x0a, 0x32, 0x7f, 0xf2, 0x22, - 0x54, 0xf6, 0xc3, 0xac, 0x8f, 0x3c, 0xf9, 0x70, 0x0b, 0x1f, 0xd2, 0xec, 0xbe, 0x9f, - 0x4e, 0x91, 0xe4, 0x3a, 0x65, 0x4f, 0xff, 0x02, 0x7c, 0xd9, 0x17, 0x4b, 0x63, 0x8e, - 0x6e, 0xfe, 0xc4, 0xab, 0xfb, 0xa1, 0x87, 0xf8, 0xf3, 0xdb, 0xa0, 0x45, 0x9d, 0xa6, - 0xc3, 0xf8, 0x00, 0xcb, 0x6b, 0x61, 0x33, 0xa8, 0xb4, 0xac, 0x1e, 0xf6, 0x58, 0xd1, - 0x11, 0xc0, 0x3f, 0x07, 0x22, 0x08, 0xdc, 0xc2, 0x07, 0xa2, 0x22, 0x3a, 0x70, 0x22, - 0x92, 0x43, 0x2e, 0x83, 0x06, 0xfc, 0x03, 0x04, 0x63, 0xe7, 0x54, 0xff, 0x0f, 0x15, - 0x3d, 0x97, 0xbc, 0x9c, 0xe9, 0x6d, 0xff, 0x4b, 0xed, 0x2f, 0x1e, 0xa5, 0xb8, 0xea, - 0x87, 0x6d, 0x2e, 0xe4, 0xe4, 0xf6, 0xe4, 0x9a, 0x4a, 0x85, 0xa9, 0xcf, 0x4a, 0x33, - 0xdc, 0xd9, 0x36, 0x60, 0xa4, 0x25, 0x43, 0xe5, 0x34, 0x22, 0x39, 0x0d, 0x66, 0x5b, - 0xdd, 0x30, 0x24, 0x78, 0xb3, 0x3c, 0x8d, 0x57, 0x47, 0x92, 0x41, 0x4c, 0x5f, 0xe5, - 0xb7, 0x4f, 0xe1, 0xd1, 0x69, 0x52, 0x5c, 0x99, 0x30, 0x1a, 0x3a, 0x68, 0xa0, 0xc8, - 0x5f, 0x02, 0x0f, 0xd5, 0x8f, 0x6d, 0x9f, 0x3a, 0xcb, 0x13, 0x9c, 0x96, 0x65, 0x38, - 0x56, 0xa3, 0x2e, 0x21, 0x02, 0x7a, 0xa2, 0xba, 0x18, 0x60, 0x10, 0xd5, 0x3c, 0xdd, - 0x4c, 0x41, 0x50, 0xcb, 0x2b, 0xb2, 0x42, 0x44, 0x65, 0x42, 0xb0, 0x17, 0x84, 0x40, - 0x1f, 0xa2, 0xcb, 0xf1, 0x22, 0xc9, 0xf1, 0x1d, 0x8c, 0x81, 0x36, 0x98, 0x7b, 0x67, - 0x86, 0x29, 0x93, 0x84, 0x58, 0x5f, 0x9c, 0xa2, 0x93, 0x53, 0x7b, 0x4b, 0xe5, 0x72, - 0x6f, 0x94, 0xd4, 0x77, 0x60, 0x5a, 0x8a, 0x6c, 0x53, 0x06, 0x02, 0xbb, 0x46, 0xc4, - 0xde, 0x20, 0x7f, 0xc5, 0x9e, 0x91, 0xe4, 0xa9, 0x0a, 0x91, 0x11, 0x77, 0x74, 0x69, - 0xf1, 0xe2, 0x87, 0x82, 0x76, 0x7d, 0x9d, 0xe5, 0x7d, 0xea, 0xde, 0xad, 0xcb, 0x4a, - 0xf5, 0x19, 0x3e, 0x09, 0xc9, 0xbb, 0x74, 0x73, 0x77, 0x3a, 0x8c, 0xa5, 0x6d, 0x76, - 0x51, 0x1d, 0x65, 0x99, 0x20, 0xdb, 0x99, 0x64, 0xd3, 0x2b, 0xad, 0xb6, 0x1f, 0x4c, - 0xf6, 0xb0, 0x22, 0xd7, 0xc1, 0x53, 0x93, 0x18, 0x49, 0x64, 0x3e, 0x8b, 0x99, 0xea, - 0xe0, 0x28, 0x4f, 0x8b, 0x01, 0x15, 0xb4, 0x23, 0x7a, 0x7c, 0x5d, 0x81, 0x97, 0x0f, - 0xe8, 0x7c, 0x6f, 0x84, 0xb6, 0x68, 0x6c, 0x46, 0x25, 0xdb, 0xdd, 0x9d, 0x79, 0xd2, - 0xc5, 0x55, 0xdd, 0x4f, 0xce, 0xed, 0x2c, 0x5e, 0x5e, 0x89, 0x6f, 0x63, 0x1a, 0xe4, - 0x59, 0x7e, 0x9c, 0xc0, 0xbe, 0xe7, 0xb3, 0x02, 0x5f, 0x95, 0x56, 0x10, 0x6a, 0x84, - 0x3a, 0x18, 0x22, 0x7f, 0x5a, 0xb9, 0x61, 0x7d, 0x7b, 0xcb, 0x1a, 0xf5, 0x28, 0xfa, - 0xa7, 0xa0, 0x52, 0xea, 0x4f, 0x52, 0xca, 0x59, 0x45, 0x57, 0xfd, 0xad, 0x33, 0x05, - 0x2b, 0xc8, 0x2b, 0x39, 0xc6, 0xa6, 0x09, 0xa0, 0x70, 0x75, 0x3d, 0x78, 0x8b, 0x2c, - 0x4a, 0x2c, 0xae, 0xbb, 0xe7, 0x9f, 0xf0, 0x12, 0x07, 0x1c, 0x07, 0x08, 0x10, 0x94, - 0xad, 0x60, 0x59, 0xc2, 0x8f, 0x48, 0xe5, 0x56, 0xc4, 0xe8, 0xd8, 0xc5, 0x37, 0x8b, - 0xc2, 0x93, 0x07, 0x6b, 0xb4, 0x97, 0x07, 0x5f, 0x9c, 0xa0, 0xba, 0x13, 0x11, 0x55, - 0x0f, 0xa2, 0x17, 0x3d, 0x0e, 0xb1, 0xf0, 0xbd, 0xdd, 0xf3, 0xb3, 0xd5, 0xc2, 0x43, - 0xff, 0xea, 0xbe, 0xe8, 0x23, 0xcd, 0x63, 0xb4, 0x39, 0x39, 0xce, 0x95, 0x46, 0xed, - 0x4c, 0x41, 0xe6, 0x0c, 0xcc, 0x7e, 0x1c, 0x54, 0x3c, 0xb3, 0xe2, 0xd3, 0x50, 0xe2, - 0xe2, 0xe9, 0x74, 0x21, 0x5c, 0xf7, 0xaa, 0x96, 0x9b, 0x66, 0x81, 0x14, 0xac, 0xdb, - 0x29, 0xf4, 0xcd, 0xcf, 0xdc, 0xec, 0x2a, 0x8c, 0xe4, 0xf5, 0x95, 0xf4, 0xff, 0x5f, - 0x70, 0x7e, 0x7f, 0xa4, 0xde, 0xe8, 0xbf, 0x8f, 0x39, 0x52, 0xae, 0x32, 0xe7, 0x7f, - 0x34, 0xf8, 0xb3, 0xab, 0xaa, 0xe9, 0x69, 0x28, 0xba, 0x4a, 0x6c, 0x0f, 0xbf, 0x5b, - 0x29, 0x19, 0x2d, 0xae, 0x80, 0x0d, 0xfa, 0x79, 0x57, 0x0c, 0xaf, 0x0b, 0xb8, 0x33, - 0xbd, 0x37, 0xa3, 0xd4, 0xbe, 0xaf, 0x09, 0x1f, 0x6b, 0x3e, 0x55, 0xaa, 0xe5, 0x25, - 0xf4, 0x13, 0xac, 0x80, 0x4c, 0x34, 0x7d, 0x54, 0x1d, 0x2c, 0x09, 0xec, 0x6e, 0x54, - 0x03, 0x5d, 0xf1, 0xd8, 0x30, 0x28, 0x4d, 0x9b, 0x46, 0xff, 0xd2, 0xb2, 0xeb, 0x04, - 0x0b, 0x61, 0x77, 0xd0, 0xa0, 0x9c, 0x16, 0x60, 0x34, 0xa9, 0x57, 0xb1, 0x8f, 0xf6, - 0x2e, 0x43, 0x4a, 0x3e, 0xc7, 0x32, 0x62, 0xe4, 0xb2, 0x3f, 0xec, 0x9d, 0x29, 0x0a, - 0x81, 0xc5, 0xb1, 0xf7, 0x3c, 0xb4, 0xcd, 0x1c, 0x47, 0x2b, 0x86, 0xe5, 0x34, 0xab, - 0x9e, 0x65, 0x53, 0x29, 0x5d, 0xb0, 0xcf, 0x34, 0xe1, 0x39, 0x2a, 0xad, 0x5a, 0xbc, - 0xf3, 0x98, 0x64, 0x16, 0xa7, 0x0a, 0x9d, 0xbe, 0x59, 0xbb, 0x95, 0x8e, 0xbc, 0x71, - 0x1c, 0x3a, 0xe0, 0x8c, 0xaf, 0x52, 0xec, 0xa9, 0xcb, 0x54, 0xc4, 0x58, 0xbe, 0x7f, - 0x5e, 0x62, 0x14, 0xec, 0xa0, 0xf0, 0xa3, 0x81, 0x52, 0x62, 0x20, 0x01, 0x32, 0xe6, - 0x14, 0x54, 0x37, 0xec, 0xd2, 0x1f, 0xc8, 0x03, 0x6c, 0xb0, 0x0a, 0x49, 0x13, 0x84, - 0xc3, 0x41, 0xd8, 0x72, 0xdc, 0xda, 0x31, 0xb1, 0x42, 0x96, 0x73, 0xd9, 0xc4, 0xf5, - 0x7b, 0x81, 0xa0, 0x23, 0x6d, 0xa5, 0xec, 0x55, 0x02, 0xee, 0x29, 0x63, 0x15, 0x0a, - 0x00, 0x26, 0xbd, 0x63, 0xef, 0x67, 0x9e, 0x8c, 0x25, 0xb8, 0xec, 0xee, 0x06, 0x56, - 0x4a, 0xf3, 0xb0, 0x2d, 0xea, 0xb1, 0x06, 0x97, 0xa2, 0x4d, 0xe6, 0x7d, 0x4f, 0x65, - 0x04, 0xae, 0x27, 0x37, 0xb8, 0xe1, 0x73, 0x25, 0xc2, 0xff, 0x15, 0x0c, 0x62, 0xe3, - 0x79, 0x83, 0x44, 0xa1, 0xad, 0x3c, 0xbb, 0x75, 0xb7, 0xf2, 0xa1, 0x57, 0x38, 0xf6, - 0x01, 0xcf, 0x00, 0xf7, 0xe8, 0xbc, 0x08, 0xb6, 0x89, 0x56, 0x7e, 0x4c, 0x7c, 0x01, - 0x05, 0x8b, 0xee, 0xc2, 0x90, 0x3c, 0x5c, 0xa6, 0xb4, 0xc4, 0xa5, 0x71, 0xf4, 0x60, - 0xd6, 0x05, 0x87, 0x36, 0x29, 0x96, 0xc6, 0xe1, 0x25, 0x54, 0xe8, 0xe3, 0x4e, 0x68, - 0x3a, 0x27, 0xf8, 0xa5, 0xff, 0x97, 0x1d, 0x5a, 0x0d, 0xc2, 0xf3, 0xef, 0xd3, 0x88, - 0x99, 0x87, 0xc1, 0xcc, 0x39, 0xce, 0x5d, 0x4b, 0x6b, 0x54, 0x4c, 0xe0, 0x4c, 0x71, - 0xee, 0x4b, 0xfa, 0xe5, 0x04, 0x0d, 0x61, 0xf0, 0x57, 0xe4, 0xf7, 0x70, 0x17, 0x28, - 0xf1, 0x20, 0x04, 0xa7, 0xf7, 0xed, 0xeb, 0x3a, 0xb2, 0x26, 0x09, 0xed, 0x33, 0xb0, - 0xab, 0x5d, 0x69, 0xb1, 0x2d, 0x45, 0x76, 0x57, 0x77, 0x14, 0xdf, 0xc6, 0xdd, 0xa7, - 0x1f, 0xf6, 0x01, 0x7b, 0x55, 0xb3, 0x35, 0x4d, 0x11, 0xe9, 0x21, 0x67, 0x92, 0xe5, - 0x60, 0x9f, 0xc0, 0x67, 0x88, 0xec, 0x66, 0x8e, 0xef, 0x64, 0x5e, 0x63, 0xb3, 0x7e, - 0x2d, 0x0c, 0xd2, 0x63, 0x04, 0x08, 0x00, 0xbc, 0x8a, 0xa2, 0x80, 0x15, 0x6a, 0x79, - 0x4f, 0x62, 0xa5, 0xf6, 0x93, 0xeb, 0xd9, 0x07, 0x4b, 0x5d, 0x35, 0x4a, 0x71, 0xc8, - 0xe3, 0x36, 0xde, 0x04, 0x08, 0xac, 0x70, 0x80, 0xa2, 0xae, 0xee, 0x36, 0x6c, 0x58, - 0x14, 0x6f, 0x32, 0xe3, 0x49, 0xa9, 0xbc, 0x65, 0x7e, 0xc9, 0xe5, 0x7a, 0x89, 0xa0, - 0x4c, 0xce, 0xee, 0x21, 0xbd, 0xf3, 0x79, 0x3e, 0x49, 0xa5, 0xcf, 0x71, 0x3a, 0x42, - 0xd0, 0x29, 0xdd, 0xdb, 0x3d, 0xb4, 0x95, 0x09, 0x2c, 0x37, 0xce, 0x81, 0x4b, 0xe7, - 0x3e, 0xf4, 0xec, 0x8d, 0x70, 0xe8, 0x69, 0xbd, 0x2b, 0x78, 0x8f, 0x15, 0x00, 0xfe, - 0x5e, 0xe5, 0x6c, 0x0c, 0xe7, 0x04, 0xeb, 0xa2, 0xc1, 0xa3, 0xa3, 0x29, 0x0d, 0xe6, - 0xec, 0x68, 0xcc, 0xb5, 0xef, 0x7c, 0xd0, 0x21, 0x2a, 0x3f, 0x09, 0x96, 0x92, 0xcf, - 0x00, 0x04, 0x8d, 0xe5, 0x01, 0x26, 0x19, 0xe7, 0x41, 0x69, 0x2b, 0xfc, 0x74, 0x05, - 0xba, 0x3e, 0x87, 0x5e, 0x98, 0xb7, 0xca, 0x31, 0xe9, 0x65, 0xa1, 0x6f, 0xdd, 0xb5, - 0xb0, 0xb7, 0x72, 0xa3, 0xf5, 0xd0, 0x50, 0xd8, 0xad, 0x7f, 0x60, 0x7f, 0x55, 0xc0, - 0xdc, 0x52, 0xb4, 0x8f, 0xb0, 0x2a, 0x8b, 0x1d, 0xef, 0xc6, 0xc3, 0x10, 0xb2, 0x47, - 0x55, 0x59, 0xb4, 0x7e, 0x84, 0x4e, 0xd3, 0x77, 0x60, 0xd7, 0xd1, 0x6f, 0x27, 0xcb, - 0x48, 0xbf, 0x36, 0x16, 0xc4, 0x6f, 0xb0, 0xcf, 0x3c, 0x8c, 0x28, 0xb9, 0x39, 0x27, - 0x80, 0x0a, 0x29, 0x16, 0xa4, 0x07, 0xa6, 0x0d, 0x68, 0x99, 0x7b, 0x10, 0x50, 0x51, - 0x32, 0xad, 0x33, 0xf9, 0xce, 0x26, 0xb4, 0xac, 0xba, 0x27, 0xa2, 0xa0, 0xc2, 0x18, - 0xdb, 0x15, 0xa5, 0xd7, 0xaa, 0xed, 0x4f, 0x6a, 0x72, 0x00, 0x36, 0x72, 0xca, 0x70, - 0x49, 0x8b, 0x05, 0x49, 0x4a, 0x93, 0x34, 0x1f, 0xcf, 0x96, 0xc0, 0x99, 0x4e, 0x42, - 0x7b, 0xeb, 0xd3, 0x56, 0xe4, 0x17, 0x6d, 0xec, 0x83, 0xe6, 0xfe, 0x80, 0x02, 0x9c, - 0xfc, 0x47, 0x8b, 0x88, 0xb6, 0xfd, 0x38, 0xc0, 0x39, 0xe0, 0x8b, 0x6f, 0xd9, 0x5d, - 0xab, 0xcf, 0xb2, 0x5f, 0x23, 0x8b, 0x26, 0x62, 0x06, 0xb0, 0xa2, 0xf9, 0xa2, 0xee, - 0xa1, 0xc0, 0x83, 0xfa, 0xc8, 0x08, 0xaa, 0xfa, 0x03, 0x65, 0x66, 0xcc, 0xd2, 0x02, - 0xbc, 0xfa, 0x41, 0x4e, 0x71, 0xc8, 0xb4, 0x89, 0x33, 0xc8, 0xed, 0x45, 0x28, 0x7e, - 0x1b, 0x43, 0x9b, 0x61, 0x06, 0xa5, 0x50, 0x94, 0x73, 0xf5, 0x7b, 0x87, 0x88, 0xaf, - 0x52, 0x7c, 0xf9, 0xa7, 0xab, 0xa5, 0x93, 0xdc, 0x9f, 0x5e, 0x5a, 0xca, 0x1a, 0x64, - 0x8e, 0xe4, 0x88, 0xf3, 0x6d, 0xeb, 0x4a, 0x3f, 0xdb, 0x0f, 0xf6, 0xf5, 0xa3, 0x04, - 0x4a, 0x63, 0xe1, 0x7f, 0x70, 0xa4, 0x30, 0x38, 0x24, 0x60, 0x3a, 0xb5, 0x0e, 0x9b, - 0xf7, 0x5b, 0xae, 0xb5, 0x7b, 0xfd, 0xc8, 0x9b, 0xfd, 0xbc, 0x27, 0x27, 0x9d, 0x10, - 0x73, 0xbf, 0x7f, 0x95, 0x05, 0xfb, 0x31, 0x68, 0xd2, 0x06, 0xe2, 0xbf, 0x41, 0x02, - 0xbf, 0x15, 0x9c, 0xff, 0x61, 0xe6, 0xd6, 0x6c, 0x80, 0x37, 0x50, 0xda, 0x25, 0x4c, - 0xd6, 0xb8, 0x1a, 0xed, 0x42, 0x09, 0x97, 0x94, 0xb8, 0x4e, 0xce, 0x90, 0x42, 0x18, - 0xe6, 0xf6, 0x6e, 0xc6, 0x34, 0xe9, 0x2e, 0xef, 0xf4, 0x5f, 0x52, 0xe0, 0x4b, 0x4b, - 0x79, 0x5a, 0x15, 0x25, 0xaa, 0xf9, 0xc5, 0x1d, 0x62, 0x60, 0xfb, 0xd6, 0x4e, 0x8d, - 0x8a, 0xc2, 0x66, 0xdc, 0x6e, 0x7d, 0xf6, 0x15, 0x3a, 0xd9, 0x73, 0x55, 0x83, 0x79, - 0x28, 0x40, 0x4c, 0xd5, 0x81, 0xbc, 0x9c, 0xf9, 0xdc, 0xd6, 0x67, 0x47, 0xdc, 0x97, - 0x0a, 0x9f, 0x00, 0xde, 0xb4, 0x4b, 0xd6, 0x34, 0xab, 0x04, 0x2e, 0x01, 0x04, 0xc1, - 0xce, 0x74, 0x7f, 0x53, 0x75, 0x1b, 0xc3, 0x3e, 0x38, 0x4c, 0x6b, 0x55, 0x76, 0x39, - 0x9e, 0x16, 0xf8, 0xf0, 0xcb, 0x08, 0xde, 0x35, 0x08, 0x37, 0x33, 0x95, 0x45, 0x87, - 0xc1, 0xc2, 0x4d, 0xf2, 0xae, 0x66, 0x30, 0xff, 0xfe, 0x99, 0x62, 0x15, 0xef, 0xe4, - 0xd2, 0x62, 0x6d, 0xeb, 0x20, 0x56, 0x6a, 0x8f, 0x5e, 0xad, 0x2f, 0x04, 0xdb, 0x5d, - 0x08, 0x77, 0x9c, 0x9c, 0x65, 0x9e, 0xa3, 0x43, 0xcd, 0x78, 0x46, 0x34, 0xc9, 0x9d, - 0x8c, 0x8b, 0xad, 0xa9, 0x3b, 0xe8, 0xe6, 0xda, 0x84, 0x15, 0x94, 0xba, 0xcf, 0x7c, - 0xb3, 0xe6, 0x92, 0xc7, 0x4b, 0x5f, 0xfe, 0x95, 0x78, 0x73, 0x11, 0x3a, 0x1a, 0xb0, - 0x64, 0x02, 0x6f, 0x6d, 0xee, 0x8b, 0x48, 0xa3, 0x84, 0xa1, 0x33, 0x83, 0x18, 0x36, - 0x07, 0x86, 0x50, 0x27, 0x84, 0xd1, 0x7d, 0x40, 0x0c, 0xe3, 0xd7, 0x21, 0x78, 0x7e, - 0xdc, 0x4c, 0x6b, 0x39, 0x35, 0x66, 0x25, 0x10, 0x77, 0x10, 0x00, 0x68, 0x0d, 0x78, - 0xbb, 0x49, 0xc5, 0x66, 0xef, 0x27, 0xdf, 0x61, 0xc9, 0xfe, 0xb9, 0x2c, 0x08, 0x97, - 0x59, 0x44, 0x87, 0x27, 0xa9, 0x34, 0xe3, 0x57, 0x95, 0x3d, 0xe1, 0xe9, 0xe9, 0x0f, - 0xd8, 0xdf, 0xfe, 0x40, 0xb8, 0x73, 0xbc, 0xd5, 0xb9, 0x82, 0x08, 0xdf, 0x4b, 0x2c, - 0xa2, 0x89, 0x7a, 0xf9, 0x0d, 0x8c, 0x8a, 0x23, 0x62, 0x30, 0x02, 0xa9, 0xd8, 0xbc, - 0x02, 0xe8, 0x06, 0x25, 0x4f, 0x41, 0x0e, 0x3b, 0x02, 0x40, 0x9c, 0xbe, 0xbf, 0xce, - 0x8a, 0xcf, 0x65, 0xcf, 0x39, 0x42, 0x6b, 0x64, 0xa6, 0xba, 0x93, 0x74, 0xa1, 0x3d, - 0x72, 0x59, 0x62, 0x3f, 0x65, 0xe9, 0x3e, 0x10, 0xbf, 0x1f, 0x16, 0xba, 0x7a, 0xe0, - 0x7d, 0xa9, 0x20, 0x58, 0x1c, 0x70, 0x40, 0x9e, 0xdc, 0x7b, 0x9e, 0x21, 0x4e, 0x95, - 0x91, 0x92, 0x82, 0x4c, 0x1d, 0xa6, 0x5d, 0x33, 0x7b, 0x73, 0x75, 0xf5, 0x03, 0x2f, - 0xea, 0xd3, 0xb4, 0xf3, 0x28, 0x48, 0x11, 0x95, 0x0c, 0x7a, 0x90, 0xae, 0xc9, 0x75, - 0xd4, 0xe3, 0x62, 0x9f, 0x52, 0xd1, 0x9a, 0x16, 0x4e, 0x51, 0x16, 0xef, 0x3a, 0xd0, - 0x22, 0x44, 0x2d, 0x1e, 0xec, 0x76, 0xb8, 0x88, 0x73, 0x8b, 0x53, 0xe5, 0x05, 0x58, - 0xa7, 0x0f, 0x20, 0xc8, 0xac, 0xb5, 0x8d, 0xee, 0x63, 0x27, 0x15, 0xe4, 0x78, 0xe2, - 0xbc, 0x21, 0xbc, 0xfb, 0xe3, 0x15, 0x59, 0x96, 0xca, 0xe7, 0xbd, 0x97, 0xf0, 0x2b, - 0x51, 0x6d, 0x32, 0x00, 0xfb, 0x3c, 0x17, 0x39, 0x7c, 0xc1, 0x2b, 0xb7, 0xa1, 0x9f, - 0xd4, 0x36, 0xe6, 0x7a, 0xbc, 0xe6, 0x6d, 0x30, 0xfe, 0xc0, 0x47, 0xfb, 0x27, 0x70, - 0x82, 0x0e, 0x47, 0x6f, 0x3e, 0x32, 0xbc, 0x48, 0x3b, 0xf5, 0x31, 0x64, 0xae, 0x49, - 0x70, 0xf1, 0x1b, 0x9c, 0xae, 0xe4, 0xed, 0x6c, 0xb8, 0xd2, 0xd7, 0x0f, 0x69, 0x13, - 0xd8, 0xe0, 0x2a, 0xf8, 0xfb, 0xb1, 0xe4, 0x09, 0xb4, 0xef, 0x08, 0x04, 0x48, 0xe5, - 0x3b, 0xe6, 0xe5, 0xe6, 0x05, 0x75, 0xdf, 0xde, 0x94, 0x28, 0xb0, 0x06, 0x96, 0x61, - 0x1a, 0x2f, 0x72, 0x33, 0x2a, 0xe2, 0x90, 0x23, 0xdd, 0x88, 0xae, 0x77, 0xf1, 0x5b, - 0x8a, 0xe2, 0xc2, 0x4b, 0x86, 0xcf, 0x3d, 0x57, 0x43, 0x9c, 0xaf, 0x17, 0xf2, 0x8e, - 0xda, 0x94, 0x93, 0x2e, 0xef, 0x28, 0x53, 0x4e, 0x16, 0x49, 0xce, 0xf8, 0x85, 0x40, - 0xfc, 0xb1, 0xa6, 0x3e, 0x11, 0x5c, 0x58, 0x22, 0xaf, 0xa4, 0x40, 0xc8, 0xd7, 0x9d, - 0x66, 0xf9, 0xbb, 0x1f, 0x48, 0xe1, 0x14, 0x0b, 0x06, 0xec, 0x87, 0x18, 0x3c, 0xbc, - 0x6e, 0x95, 0xf6, 0xcd, 0x5f, 0x7e, 0xbc, 0xad, 0xb8, 0x97, 0xc7, 0x7b, 0x4a, 0xfb, - 0x36, 0x7b, 0x95, 0x2d, 0xbb, 0x71, 0x7f, 0x75, 0x18, 0x90, 0xc8, 0xac, 0x30, 0x36, - 0xda, 0xcd, 0xbd, 0x78, 0x4a, 0x0d, 0x83, 0xab, 0xb8, 0x44, 0x6b, 0x3f, 0x93, 0x96, - 0x33, 0x5f, 0xbf, 0x0b, 0x44, 0xed, 0xc9, 0x9e, 0x1c, 0x67, 0xc5, 0xc3, 0x81, 0x6a, - 0xce, 0x76, 0x29, 0xe6, 0xe7, 0xb0, 0x28, 0xd6, 0xc8, 0x62, 0x74, 0x9e, 0x86, 0xeb, - 0xc5, 0x11, 0x7e, 0x21, 0xf4, 0x23, 0xe1, 0x8d, 0x09, 0x76, 0xa1, 0xf5, 0x1d, 0x45, - 0x47, 0x6d, 0xa5, 0x60, 0xff, 0x23, 0x15, 0x42, 0xbb, 0x21, 0xc3, 0xde, 0xd2, 0xf2, - 0x3b, 0x2a, 0x50, 0xe0, 0xb8, 0x22, 0x56, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x1d, 0x11, - 0x65, 0xd7, 0x60, 0x70, 0x2e, 0xf1, 0x03, 0xd2, 0x23, 0x67, 0x26, 0x90, 0x23, 0x59, - 0xbe, 0x8d, 0x79, 0x73, 0x52, 0xf9, 0x6d, 0x22, 0x46, 0xa2, 0xee, 0x0a, 0xf8, 0x0a, - 0x2a, 0x2d, 0x89, 0xa5, 0x85, 0x30, 0xd6, 0xe3, 0x6b, 0xd3, 0x3a, 0x00, 0xc1, 0xb8, - 0x93, 0xd6, 0xff, 0x8f, 0x90, 0x01, 0x44, 0x15, 0x1b, 0xee, 0x34, 0xc7, 0x94, 0x4b, - 0x99, 0xed, 0x6e, 0x79, 0x45, 0xe7, 0xf0, 0xde, 0x87, 0x26, 0x3d, 0x0b, 0xba, 0x6e, - 0x55, 0xac, 0x96, 0xa9, 0x6d, 0x49, 0x95, 0x12, 0x9b, 0xcf, 0xa9, 0xd9, 0xda, 0x6d, - 0xe6, 0xdd, 0x48, 0x26, 0x39, 0x15, 0x3a, 0x81, 0x69, 0xa4, 0xab, 0x46, 0x4e, 0x39, - 0x0b, 0x7f, 0x0a, 0x96, 0xd1, 0x4a, 0x73, 0xf7, 0x69, 0x7f, 0x7e, 0xce, 0x3c, 0xd7, - 0x81, 0xd3, 0x5d, 0xd2, 0x2a, 0xdd, 0xdd, 0x2f, 0x5d, 0x34, 0x52, 0x04, 0xe4, 0xbb, - 0x55, 0x7e, 0x88, 0x45, 0x3f, 0x18, 0x8c, 0xac, 0xbe, 0x92, 0x29, 0x87, 0xbb, 0xe3, - 0xb3, 0xd9, 0x76, 0x82, 0x61, 0x35, 0xc1, 0x03, 0xb6, 0xca, 0x18, 0x2b, 0x63, 0xe9, - 0xe6, 0x7f, 0x83, 0xdc, 0x9f, 0x48, 0x93, 0x33, 0xd5, 0x2a, 0x7f, 0xd7, 0x68, 0x8a, - 0x58, 0xd6, 0x62, 0x0b, 0x67, 0xe9, 0xc7, 0xb0, 0x91, 0x6f, 0xef, 0x90, 0xf1, 0x5d, - 0x8e, 0x4e, 0xb8, 0x0c, 0xf5, 0x99, 0x68, 0x2f, 0x95, 0x4f, 0xf4, 0xe0, 0xb3, 0x71, - 0x83, 0x13, 0x0c, 0xa2, 0xee, 0xd0, 0x91, 0x3f, 0x46, 0xa4, 0xdb, 0x99, 0x2a, 0x1c, - 0x3b, 0xf3, 0x19, 0xdc, 0x86, 0x75, 0x94, 0x01, 0x01, 0x53, 0x7c, 0xff, 0xc4, 0xa8, - 0x2d, 0x59, 0x9b, 0xbe, 0xa0, 0xd4, 0x7e, 0x7a, 0xbf, 0xa9, 0x92, 0xb4, 0x99, 0x8c, - 0xb2, 0x50, 0x09, 0x55, 0xe6, 0x1c, 0x0d, 0x46, 0xb3, 0x21, 0x17, 0xfb, 0xb9, 0x7f, - 0x7a, 0x76, 0x32, 0xd8, 0x72, 0x4b, 0x5d, 0xff, 0x67, 0xf7, 0x5e, 0x2d, 0x31, 0x74, - 0x06, 0xa0, 0xce, 0xc2, 0x89, 0xed, 0x08, 0x3b, 0x7c, 0x58, 0x19, 0x81, 0x8c, 0x50, - 0x47, 0x93, 0xde, 0x53, 0xb6, 0xbf, 0xdb, 0x51, 0x0e, 0x7c, 0xa7, 0x29, 0xba, 0x74, - 0x3d, 0x10, 0xb3, 0xe9, 0x95, 0x7e, 0xfa, 0x84, 0x20, 0x13, 0x39, 0x47, 0x7c, 0xf3, - 0x5f, 0xbb, 0x6a, 0x27, 0x9b, 0xad, 0x9e, 0x8f, 0x42, 0xb9, 0xb3, 0xfd, 0x6f, 0x3b, - 0xc7, 0x70, 0x67, 0x1d, 0x9c, 0x19, 0x12, 0x2f, 0xa3, 0x25, 0x6d, 0x09, 0x07, 0x36, - 0xb6, 0xd6, 0x4e, 0xb9, 0xcc, 0x03, 0x20, 0xf1, 0xea, 0xaa, 0x27, 0x1b, 0xa2, 0x86, - 0x1e, 0xc4, 0xb3, 0xf3, 0xf6, 0xc8, 0x40, 0xb6, 0x19, 0xff, 0x38, 0x8d, 0x81, 0xfc, - 0x40, 0x44, 0xa0, 0xd5, 0x31, 0xa4, 0xbb, 0x44, 0xc9, 0x3d, 0x09, 0x9d, 0xb0, 0x8a, - 0x9b, 0xc3, 0x46, 0xa0, 0xb6, 0x2f, 0x16, 0x8f, 0xfb, 0xdb, 0x73, 0x93, 0x66, 0xbb, - 0x53, 0x5d, 0xde, 0x66, 0xc2, 0xc1, 0x28, 0x7b, 0x3b, 0x27, 0x85, 0xae, 0xd6, 0x4c, - 0xc4, 0x0c, 0xbc, 0x7d, 0x33, 0xcb, 0xa4, 0xa9, 0xf3, 0xfc, 0xf5, 0xf8, 0x31, 0x36, - 0xa4, 0x39, 0x2d, 0x21, 0xa7, 0xf9, 0xeb, 0x1c, 0xe4, 0xb6, 0xe1, 0x7e, 0x6f, 0x4a, - 0x85, 0xa5, 0x79, 0x66, 0x9e, 0xfd, 0x0f, 0xb0, 0x98, 0x78, 0xe0, 0x88, 0xe3, 0x22, - 0xe9, 0x06, 0xe8, 0x0d, 0x27, 0xf8, 0xd0, 0xca, 0x7e, 0x79, 0x15, 0xab, 0x40, 0x96, - 0x59, 0xa6, 0xd8, 0x0f, 0xde, 0xd1, 0x0a, 0xff, 0x9f, 0xb7, 0x73, 0x74, 0x9d, 0x79, - 0x28, 0x57, 0xf6, 0x8c, 0x7e, 0x8c, 0xf5, 0x18, 0x26, 0x0a, 0x61, 0x08, 0x6d, 0xe3, - 0x2f, 0xff, 0x82, 0x39, 0xf4, 0x53, 0x61, 0x7a, 0x19, 0xf6, 0xfe, 0xc2, 0x20, 0x67, - 0x60, 0x65, 0xeb, 0xe2, 0x75, 0x7e, 0xfc, 0xac, 0xcb, 0x77, 0xfc, 0x61, 0xe5, 0x9b, - 0x97, 0x63, 0x7e, 0x92, 0x0d, 0xee, 0x5e, 0x7e, 0x7a, 0x12, 0xe9, 0xd6, 0xd2, 0x28, - 0xb2, 0x6b, 0x2f, 0xa8, 0x36, 0xf4, 0x72, 0x83, 0x69, 0xad, 0xcd, 0xfc, 0xd0, 0x04, - 0xdc, 0xf1, 0x9e, 0x27, 0xc0, 0xc0, 0x84, 0x44, 0xd2, 0x9a, 0x12, 0x2b, 0x23, 0x09, - 0xf7, 0x16, 0x3c, 0x99, 0x0e, 0xb9, 0x26, 0x1f, 0xd4, 0x15, 0xc0, 0x45, 0x4a, 0x56, - 0xaa, 0x3e, 0xaf, 0x9c, 0x1f, 0x9b, 0xff, 0xf6, 0x04, 0x77, 0x6a, 0x4d, 0x25, 0xe7, - 0xd3, 0xcd, 0xc5, 0xc5, 0xf1, 0x9c, 0xd2, 0xa8, 0x79, 0x4a, 0x4f, 0x57, 0x16, 0x7f, - 0xbc, 0x7e, 0xaa, 0x06, 0x16, 0x4d, 0x51, 0xc4, 0x53, 0x06, 0x14, 0xbc, 0xf5, 0x20, - 0xb2, 0x63, 0x82, 0x0a, 0xa1, 0x7b, 0x20, 0xb4, 0x8c, 0xbf, 0x59, 0xd8, 0xe3, 0x09, - 0x32, 0x2e, 0xbe, 0x56, 0x6f, 0xbe, 0x46, 0xe0, 0xaa, 0x29, 0x76, 0x6a, 0xdf, 0xdf, - 0x01, 0x7a, 0x71, 0x05, 0x10, 0x3c, 0x7f, 0xca, 0xb7, 0xb0, 0x76, 0x48, 0xc7, 0xc1, - 0x16, 0x04, 0x84, 0xf7, 0x7a, 0x6c, 0x70, 0xa5, 0x38, 0x1b, 0x82, 0x56, 0x40, 0xa1, - 0xbe, 0x48, 0xe4, 0x15, 0xa1, 0xe6, 0xa2, 0x7d, 0x78, 0x02, 0x2a, 0x8a, 0x2f, 0xf0, - 0x70, 0xab, 0xf1, 0x23, 0x94, 0xe3, 0xae, 0x5a, 0x8c, 0x23, 0xe3, 0x73, 0x3e, 0xa4, - 0x7a, 0x44, 0xcb, 0x2c, 0x96, 0x8b, 0xca, 0x24, 0x98, 0x37, 0xde, 0x1d, 0x39, 0xa5, - 0xa1, 0xdc, 0xae, 0x71, 0x0c, 0xe0, 0x43, 0x01, 0x69, 0xbd, 0x6e, 0x9f, 0x64, 0xab, - 0xf1, 0xe6, 0x4e, 0xc4, 0x9e, 0xd0, 0x80, 0x4e, 0xb6, 0x47, 0x74, 0x3a, 0xce, 0xa9, - 0x29, 0xed, 0x0f, 0x7c, 0x90, 0x15, 0xb0, 0xe8, 0x1e, 0x21, 0x29, 0xdb, 0x05, 0x0d, - 0x5e, 0x78, 0xe6, 0x82, 0xc8, 0x19, 0x93, 0xea, 0x87, 0x53, 0xc9, 0x91, 0xb0, 0x2e, - 0x61, 0x81, 0x0e, 0x74, 0x61, 0xed, 0x87, 0xb3, 0x80, 0xdb, 0x96, 0xab, 0xe3, 0xbe, - 0xad, 0x0f, 0x4b, 0x22, 0x12, 0xdb, 0x65, 0x8c, 0x11, 0xb8, 0x3f, 0x53, 0x11, 0x47, - 0x85, 0x27, 0x65, 0x98, 0xb0, 0x19, 0x7a, 0x7f, 0x1c, 0x25, 0x62, 0x7d, 0x79, 0x62, - 0x4d, 0xac, 0xee, 0x97, 0x7d, 0x9f, 0x4e, 0x1a, 0x35, 0xed, 0x2e, 0xaa, 0xd3, 0xcb, - 0x68, 0x25, 0x0a, 0xa9, 0xb3, 0xab, 0x1a, 0x83, 0x45, 0x72, 0x8e, 0x7d, 0x1a, 0x78, - 0xbe, 0x1f, 0xe4, 0x62, 0xce, 0x8e, 0xad, 0x52, 0x8f, 0x7c, 0x05, 0x0f, 0x1f, 0x6e, - 0x02, 0x2b, 0xa8, 0xb0, 0xce, 0xdf, 0x6e, 0x29, 0x7a, 0xb5, 0x64, 0xca, 0x1a, 0x1f, - 0xaa, 0xf4, 0xcf, 0xf1, 0xe4, 0x20, 0x32, 0xfb, 0xbb, 0x38, 0x9d, 0x3f, 0x66, 0xd5, - 0x75, 0x55, 0xef, 0x3f, 0x3e, 0x9e, 0x49, 0xc2, 0xac, 0x4e, 0x85, 0xbb, 0x75, 0x1d, - 0x62, 0x66, 0xc9, 0x03, 0x5b, 0x77, 0x9d, 0x76, 0x9d, 0x49, 0x5c, 0x91, 0x8a, 0x05, - 0x5e, 0x77, 0x67, 0xfb, 0xb4, 0xbb, 0xac, 0x3f, 0x96, 0x3d, 0xe9, 0x97, 0x46, 0xec, - 0x4d, 0xfb, 0x64, 0x2d, 0x9c, 0x2b, 0x86, 0x38, 0xe1, 0x6c, 0x16, 0xe7, 0x27, 0x70, - 0x79, 0x3b, 0x7e, 0xa1, 0xd0, 0x70, 0xc4, 0xe1, 0x1c, 0xbc, 0x20, 0xd8, 0xff, 0x3b, - 0xea, 0xd1, 0x0d, 0xb9, 0xc9, 0x4a, 0xe0, 0x48, 0x27, 0x21, 0xe1, 0xf2, 0x2c, 0xef, - 0xe0, 0xdf, 0x7c, 0x57, 0x7a, 0xa3, 0x8e, 0xc0, 0xe6, 0xc7, 0x8c, 0x9b, 0xa1, 0x64, - 0xe9, 0xdd, 0x00, 0x55, 0xdd, 0xe8, 0x3e, 0x8a, 0xd2, 0x40, 0xe6, 0xdf, 0xdb, 0xfb, - 0xe1, 0x76, 0xe4, 0x55, 0x1f, 0xdd, 0xe9, 0x2d, 0xb1, 0x67, 0x27, 0x42, 0x04, 0x41, - 0x70, 0x06, 0x58, 0xb5, 0x0e, 0xbb, 0x5a, 0x16, 0x13, 0x26, 0x7e, 0xac, 0x51, 0xc8, - 0x0b, 0x19, 0xec, 0xb7, 0x86, 0xab, 0x3b, 0xb9, 0x37, 0xf0, 0xd9, 0x8e, 0x08, 0xb9, - 0xc9, 0xcd, 0x4d, 0xf1, 0x53, 0x4e, 0xfe, 0xe3, 0x8a, 0x8f, 0x87, 0x8c, 0x9f, 0x3b, - 0xdc, 0x7e, 0xfb, 0x2d, 0x53, 0xff, 0x84, 0xfb, 0x83, 0xea, 0xe7, 0xc9, 0x9e, 0xff, - 0xa6, 0x3c, 0x96, 0x49, 0xa1, 0xf1, 0x70, 0xd2, 0x9a, 0xf0, 0x3a, 0x3b, 0x45, 0x58, - 0x9f, 0xae, 0x81, 0xeb, 0x0b, 0x5d, 0x8e, 0x0d, 0x38, 0x02, 0x1d, 0x3b, 0x5f, 0x07, - 0xe8, 0x8c, 0x99, 0x04, 0x37, 0x6d, 0x27, 0xf1, 0x3e, 0x44, 0x41, 0xd5, 0x38, 0x74, - 0x42, 0xc5, 0xea, 0x0a, 0xf5, 0xa2, 0x0a, 0x38, 0x32, 0xbc, 0x3b, 0x9c, 0x59, 0xb8, - 0x4b, 0xca, 0x39, 0xb5, 0x2c, 0xd6, 0xb1, 0xfa, 0x29, 0x32, 0xba, 0x9d, 0x66, 0xc4, - 0x12, 0xf5, 0xcd, 0x39, 0x35, 0x1e, 0x13, 0x33, 0xef, 0x85, 0xd0, 0xee, 0xe5, 0x45, - 0xa7, 0xe4, 0x06, 0xf6, 0xeb, 0x3b, 0xf8, 0x93, 0xf3, 0xed, 0xac, 0x94, 0x64, 0x33, - 0x92, 0xa2, 0x8b, 0x0e, 0x49, 0x0c, 0x51, 0xe4, 0xb7, 0x16, 0x3c, 0x1c, 0xf7, 0x57, - 0xd2, 0x24, 0x18, 0xdd, 0x63, 0x38, 0x1b, 0xa2, 0xf2, 0x98, 0x28, 0x83, 0x6f, 0xe9, - 0x78, 0xda, 0xb5, 0x20, 0x1b, 0x2d, 0xb0, 0x8c, 0x3b, 0x38, 0x9b, 0xa4, 0xb6, 0xac, - 0xf7, 0x78, 0xc2, 0xbf, 0x91, 0x02, 0xbe, 0x0c, 0x3e, 0x12, 0xd7, 0x7a, 0xea, 0x6d, - 0xf7, 0x53, 0x8e, 0x8c, 0xf3, 0x62, 0xba, 0xaa, 0xad, 0x1d, 0xc5, 0x60, 0x42, 0xc6, - 0xf2, 0x4c, 0xaf, 0x46, 0xbe, 0xd6, 0x6a, 0xbf, 0x4c, 0x40, 0x2a, 0x74, 0x92, 0x4e, - 0xcf, 0xd0, 0xa0, 0x8d, 0xed, 0xee, 0xa0, 0xef, 0xce, 0xcd, 0x35, 0x2c, 0x27, 0x5f, - 0x13, 0xed, 0x20, 0x76, 0x03, 0x82, 0x2b, 0x1e, 0xf9, 0x97, 0xb7, 0xed, 0x42, 0xf4, - 0xa5, 0x76, 0xb9, 0xe4, 0xc0, 0x07, 0x38, 0x56, 0x3f, 0x82, 0xa7, 0x62, 0x85, 0x46, - 0x7d, 0xa2, 0x95, 0xc2, 0x3b, 0xa1, 0xc5, 0x87, 0xeb, 0xef, 0xaf, 0x13, 0xcd, 0x4d, - 0x50, 0xf2, 0x3c, 0xa5, 0x74, 0x3c, 0x22, 0x5c, 0x38, 0x6d, 0x46, 0xd4, 0xac, 0x70, - 0x83, 0x79, 0xef, 0x99, 0x96, 0x74, 0x4b, 0x39, 0x12, 0x04, 0x4b, 0x35, 0x5f, 0x92, - 0x7a, 0x67, 0xaf, 0x1e, 0xf2, 0x6a, 0x71, 0x7f, 0xb5, 0xa8, 0x46, 0xac, 0x9d, 0xa1, - 0x5e, 0xa3, 0xf1, 0x8f, 0x8c, 0x36, 0x18, 0x3f, 0x87, 0x9b, 0xb9, 0xa3, 0xb2, 0x98, - 0xff, 0xf9, 0xa4, 0x89, 0x64, 0x6e, 0x77, 0x8e, 0x6d, 0x67, 0x01, 0xf9, 0xad, 0xac, - 0x7a, 0xe8, 0x82, 0x09, 0xa8, 0x43, 0xba, 0x8a, 0x55, 0xd1, 0x19, 0x2b, 0xbe, 0xef, - 0x31, 0xd0, 0x71, 0x45, 0x37, 0xf7, 0xa0, 0x35, 0xb0, 0x79, 0xc6, 0xad, 0xd4, 0xab, - 0x50, 0x61, 0x2d, 0x35, 0x89, 0x7a, 0x93, 0x3d, 0x49, 0xe8, 0xef, 0x08, 0x6c, 0xdf, - 0x96, 0xc8, 0x0d, 0x28, 0x56, 0xcc, 0xc7, 0xe4, 0x5f, 0xc4, 0xef, 0xd4, 0xbf, 0x1b, - 0x98, 0xab, 0x28, 0x89, 0x1b, 0x4a, 0xea, 0x7e, 0xf8, 0x4c, 0xf7, 0x36, 0x93, 0x5c, - 0x46, 0x6b, 0x24, 0x97, 0x4d, 0xf8, 0xf5, 0x35, 0x5b, 0x8b, 0xa3, 0x20, 0xac, 0x5f, - 0xbc, 0x47, 0x5a, 0xa2, 0xcf, 0x5a, 0xd3, 0x77, 0x80, 0xbd, 0x9f, 0x9d, 0x46, 0x42, - 0xcf, 0x6c, 0x2d, 0xc6, 0xb8, 0x2f, 0x91, 0x7d, 0x09, 0xc4, 0xf7, 0x28, 0x88, 0xf9, - 0x15, 0x53, 0x44, 0x7f, 0xc5, 0x70, 0x26, 0x6d, 0xaa, 0xfd, 0x4b, 0x96, 0xcf, 0xe2, - 0xa0, 0xb0, 0x67, 0x92, 0x46, 0x9a, 0x72, 0x7d, 0xbe, 0xd0, 0x55, 0x91, 0xea, 0x60, - 0x57, 0x32, 0x20, 0x5e, 0x26, 0x05, 0x97, 0x8a, 0x3a, 0x90, 0x2c, 0x3c, 0xd6, 0x5f, - 0x94, 0x83, 0x00, 0xf7, 0x37, 0x51, 0x88, 0x15, 0xf4, 0x63, 0xd3, 0xc6, 0x1a, 0x18, - 0x9b, 0xc3, 0xbc, 0x84, 0xb0, 0x22, 0xf6, 0x3d, 0x65, 0x4f, 0x52, 0x0e, 0x3a, 0x7a, - 0xd8, 0x8e, 0x5d, 0x8d, 0xa1, 0x50, 0x14, 0xbe, 0x4b, 0xb9, 0x67, 0x99, 0x27, 0xdc, - 0x7e, 0x0f, 0xba, 0xf0, 0x58, 0xd9, 0x3f, 0x37, 0xc7, 0x2b, 0x28, 0x6b, 0x02, 0xb7, - 0x5f, 0x3c, 0xdb, 0xfb, 0x85, 0x0e, 0xed, 0x90, 0xcb, 0x23, 0x39, 0x24, 0x32, 0xeb, - 0xc3, 0x6b, 0xd2, 0x47, 0x54, 0x46, 0x9c, 0x03, 0x73, 0x1a, 0x7e, 0xbb, 0xed, 0x28, - 0x57, 0x78, 0x49, 0x81, 0xa0, 0x71, 0x67, 0x05, 0xd9, 0xcb, 0x47, 0xd9, 0x87, 0xf8, - 0x3d, 0x34, 0x21, 0xb1, 0x07, 0xd1, 0x55, 0xdb, 0xb6, 0x61, 0xed, 0x08, 0xf2, 0xfc, - 0x2e, 0x6b, 0x4a, 0x5b, 0x09, 0x77, 0x64, 0x51, 0xd8, 0x73, 0xb2, 0xfc, 0x63, 0x68, - 0x1c, 0xe3, 0x08, 0xc8, 0x08, 0xf5, 0x38, 0x8c, 0xb1, 0xaa, 0x55, 0x89, 0xa1, 0x87, - 0x73, 0xdb, 0x39, 0x07, 0xa0, 0x6b, 0xef, 0x62, 0xd1, 0x29, 0x60, 0xaa, 0xe7, 0x2a, - 0x2b, 0x89, 0x7e, 0x26, 0xb5, 0x75, 0xfd, 0x04, 0x8a, 0x57, 0x22, 0x2c, 0x7c, 0x68, - 0x0d, 0x54, 0xdc, 0x73, 0x28, 0xd0, 0xf0, 0xf2, 0xd7, 0x0b, 0x43, 0x10, 0x8c, 0xb2, - 0x0c, 0x5c, 0x31, 0x16, 0x46, 0x31, 0xb0, 0xe5, 0xb3, 0xbd, 0x31, 0xb7, 0xdf, 0x8f, - 0x4c, 0x1f, 0xe1, 0x43, 0x4f, 0xa7, 0x47, 0x56, 0x70, 0x6f, 0x83, 0x10, 0x60, 0xa5, - 0xb7, 0x03, 0xdf, 0x9c, 0xd4, 0x2e, 0x24, 0x96, 0x0e, 0x50, 0x8a, 0x04, 0x36, 0x11, - 0x8d, 0x4a, 0x92, 0x07, 0xb6, 0xd8, 0x50, 0x59, 0x6d, 0xde, 0xbe, 0x30, 0xf9, 0x28, - 0xee, 0xea, 0xe7, 0x35, 0x98, 0xfb, 0x3d, 0x86, 0x9d, 0x2d, 0x18, 0x15, 0xa9, 0xe1, - 0x4d, 0x12, 0x79, 0xf7, 0xb4, 0xb6, 0x3f, 0x4b, 0xca, 0x0f, 0x56, 0x68, 0x9b, 0xf8, - 0x73, 0x3b, 0x03, 0x06, 0x49, 0x64, 0xa4, 0xb0, 0x20, 0xb0, 0x60, 0xdc, 0xf4, 0x54, - 0x71, 0xfa, 0x1d, 0x41, 0xe5, 0xee, 0x03, 0xf9, 0xbd, 0x90, 0x65, 0x2b, 0x53, 0x72, - 0x30, 0x3a, 0x3a, 0xb9, 0xbb, 0x2e, 0xe3, 0x79, 0xb9, 0xaf, 0xcd, 0x1f, 0x6a, 0x3c, - 0xb9, 0x00, 0x0b, 0xb1, 0x4e, - ], - script_code: vec![0x53, 0x63, 0x63, 0xac, 0x63, 0x52], - transparent_input: None, - hash_type: 1, - amount: 1152393991505765, - consensus_branch_id: 1991772603, - sighash: [ - 0x58, 0x11, 0x0e, 0x23, 0x19, 0xad, 0x85, 0x50, 0x4a, 0x69, 0x8f, 0x73, 0xe7, 0xac, - 0x31, 0xa7, 0x23, 0xa0, 0x29, 0xec, 0x07, 0xb7, 0x72, 0xfb, 0xb3, 0x2f, 0xba, 0x17, - 0xff, 0xe2, 0xcc, 0x8d, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0xb5, 0xcb, 0x96, 0x49, 0x97, - 0x9e, 0x3c, 0xcf, 0x75, 0xa8, 0xda, 0xd0, 0x54, 0x60, 0x26, 0x1f, 0xcd, 0xcb, 0x00, - 0x7a, 0xeb, 0xc1, 0x5e, 0x11, 0x67, 0x5c, 0x2d, 0xb4, 0xa6, 0xcb, 0x79, 0x38, 0xe1, - 0xfe, 0xb5, 0xcd, 0x04, 0x6a, 0x65, 0x00, 0x63, 0x44, 0x1e, 0x16, 0xc7, 0x07, 0xf0, - 0x97, 0x14, 0x47, 0x4c, 0x96, 0x16, 0x0a, 0xa6, 0x8e, 0xaa, 0x12, 0x31, 0x79, 0x06, - 0x9c, 0xd2, 0x20, 0x44, 0x06, 0x26, 0xcd, 0xfe, 0xed, 0x65, 0xf9, 0xfa, 0xbd, 0xaa, - 0x6d, 0xb1, 0x76, 0x0d, 0xa5, 0xd8, 0x06, 0x63, 0x00, 0x53, 0x6a, 0x65, 0x52, 0xfd, - 0xd0, 0xd2, 0xa9, 0x01, 0xfd, 0xc8, 0x17, 0x1c, 0x9b, 0x0e, 0x06, 0x00, 0x01, 0x65, - 0x26, 0x27, 0xba, 0x0e, 0x87, 0xb5, 0xcd, 0x0f, 0xc8, 0x7b, 0xa3, 0xa2, 0x3c, 0x78, - 0x02, 0x00, 0x00, 0x02, 0x59, 0xb1, 0xb2, 0x59, 0xc5, 0xa2, 0xd8, 0xb7, 0xa6, 0x03, - 0x9b, 0x0e, 0x12, 0xac, 0xd8, 0x89, 0xb5, 0x1b, 0x47, 0x2d, 0xd5, 0x33, 0xa4, 0x61, - 0xfb, 0x0c, 0x3f, 0x96, 0xa9, 0xc0, 0x0a, 0x0b, 0x38, 0x39, 0xfa, 0x89, 0x77, 0x6f, - 0xf0, 0x98, 0xae, 0xef, 0xc7, 0x40, 0x34, 0xff, 0x8c, 0x1f, 0x0d, 0xae, 0x63, 0x68, - 0x32, 0x4c, 0xe5, 0xda, 0x68, 0xd7, 0x71, 0x35, 0x08, 0xae, 0x6d, 0x01, 0x1a, 0xd0, - 0x5f, 0xea, 0xf2, 0x03, 0x56, 0x5c, 0x71, 0xa0, 0x48, 0x66, 0x21, 0xbd, 0xc4, 0x3c, - 0x2a, 0x8e, 0xbb, 0x82, 0x61, 0xd8, 0x47, 0x42, 0x4a, 0x4c, 0xfd, 0x0d, 0xad, 0xcf, - 0x95, 0x9d, 0xb4, 0x37, 0x2b, 0x58, 0xa0, 0xde, 0x19, 0x78, 0x9c, 0x91, 0xfc, 0x99, - 0x31, 0xec, 0xbc, 0xac, 0x64, 0x19, 0xca, 0x0e, 0x5d, 0x97, 0xa3, 0xb4, 0x1c, 0x76, - 0xc8, 0xa1, 0x96, 0xc7, 0xa3, 0xad, 0xf5, 0x5b, 0xdb, 0xe6, 0x0e, 0x85, 0x59, 0x26, - 0x4b, 0x6d, 0x8e, 0xf7, 0x5d, 0x26, 0xdc, 0x72, 0x0f, 0xe5, 0xec, 0x1f, 0x59, 0x66, - 0x2d, 0x95, 0xd0, 0x8e, 0x78, 0x9e, 0x3a, 0xd1, 0x82, 0x9e, 0x40, 0x11, 0x9a, 0xa7, - 0x89, 0x7d, 0x89, 0x40, 0x4d, 0xc4, 0x96, 0x60, 0x46, 0x68, 0xf5, 0x59, 0xca, 0x67, - 0x43, 0x7d, 0x2b, 0xfb, 0xb7, 0xf5, 0x1f, 0x36, 0xe0, 0xa5, 0xb7, 0x22, 0x8f, 0x05, - 0xb6, 0xec, 0x57, 0x89, 0xc1, 0x3f, 0xc2, 0x71, 0x95, 0x56, 0x15, 0x52, 0x63, 0x96, - 0x6e, 0x81, 0xf5, 0x21, 0x51, 0xe2, 0xf6, 0xe3, 0x68, 0x69, 0xd8, 0xa3, 0xc4, 0xc4, - 0x96, 0xa5, 0x13, 0x63, 0x2c, 0xaa, 0x8a, 0xbe, 0x1f, 0x27, 0x35, 0xeb, 0x60, 0xfc, - 0x12, 0x85, 0x82, 0x8e, 0xad, 0xdc, 0x54, 0x41, 0xa4, 0x02, 0xa3, 0xbf, 0x5b, 0xcd, - 0x22, 0x7c, 0xd8, 0x04, 0xe3, 0xc8, 0xca, 0x21, 0x24, 0x3c, 0xdf, 0xcd, 0x53, 0xd8, - 0x66, 0x05, 0xf3, 0xf8, 0xaf, 0x1a, 0x9c, 0xc5, 0x69, 0x33, 0x15, 0x53, 0x28, 0x28, - 0x01, 0x43, 0xfa, 0xdb, 0x3a, 0x1f, 0xc3, 0x3d, 0x76, 0x9f, 0x07, 0xff, 0xc0, 0x1e, - 0x35, 0x79, 0xe1, 0x18, 0x1f, 0x19, 0x15, 0xdb, 0x89, 0xd8, 0x2e, 0x50, 0xbd, 0x74, - 0x24, 0x08, 0x7c, 0x79, 0x7d, 0x9b, 0x7b, 0x3b, 0x7d, 0x2a, 0x53, 0xb8, 0xff, 0xf9, - 0xf2, 0xd9, 0x28, 0xab, 0x99, 0x6d, 0xce, 0x5e, 0xd2, 0x71, 0x58, 0x98, 0xe4, 0x85, - 0x8e, 0xec, 0x60, 0x78, 0xa9, 0x48, 0x8d, 0x2d, 0xa6, 0xd1, 0x73, 0x05, 0xd0, 0xa3, - 0x47, 0x18, 0x62, 0xa2, 0x22, 0x38, 0xb9, 0xbe, 0xc2, 0x3e, 0xf2, 0xe2, 0x04, 0x1d, - 0x50, 0x08, 0x73, 0x3e, 0x9e, 0xa5, 0x66, 0x2c, 0x9f, 0xea, 0x0e, 0x4a, 0xfd, 0xf3, - 0x27, 0x0c, 0x11, 0x32, 0x3b, 0xa4, 0x8b, 0x35, 0x50, 0x85, 0x74, 0x40, 0x97, 0xf3, - 0xf6, 0xc5, 0x2e, 0xe4, 0x04, 0x31, 0x73, 0x9c, 0x5c, 0xa8, 0xdb, 0x2b, 0xda, 0x13, - 0xda, 0x9b, 0x33, 0x0b, 0x62, 0x00, 0x0b, 0x79, 0xfd, 0x35, 0x44, 0xb1, 0x31, 0x83, - 0x15, 0x9d, 0x17, 0x4f, 0xfe, 0xd2, 0x54, 0x85, 0x40, 0xa5, 0x2e, 0xe4, 0xb6, 0x2d, - 0x35, 0xaa, 0x5a, 0x58, 0x63, 0xf2, 0xba, 0xa4, 0x47, 0x5f, 0x3e, 0xb6, 0xc7, 0x35, - 0x9d, 0xc8, 0x39, 0xdb, 0xc8, 0x68, 0x90, 0xd1, 0x99, 0xd8, 0xea, 0x6c, 0x9d, 0x97, - 0xf1, 0x9e, 0x79, 0x2c, 0x7b, 0xcb, 0x66, 0x25, 0xff, 0x32, 0xb7, 0x31, 0x57, 0x5f, - 0x62, 0xd9, 0x44, 0xc8, 0x06, 0xb3, 0xf9, 0x3c, 0x04, 0xb7, 0x3a, 0x98, 0xb2, 0x73, - 0x43, 0xeb, 0x25, 0xa0, 0x6c, 0x87, 0x53, 0x60, 0xde, 0x1a, 0x14, 0x38, 0x84, 0x0a, - 0xd0, 0x66, 0x1d, 0xeb, 0xdc, 0x9b, 0x82, 0x8a, 0xd0, 0xcb, 0xc0, 0x01, 0x1b, 0x32, - 0x35, 0xb2, 0xc7, 0x53, 0x77, 0x78, 0xf4, 0x58, 0x82, 0x1b, 0x83, 0xaa, 0x4c, 0xb3, - 0xe5, 0x4e, 0xd0, 0x61, 0x3e, 0x32, 0xe6, 0x3e, 0xf9, 0x85, 0xf9, 0x35, 0xbd, 0x7f, - 0xf8, 0xc7, 0x70, 0x5c, 0x89, 0xc0, 0xbb, 0xcc, 0xda, 0x9e, 0x66, 0x5e, 0x3b, 0x06, - 0xba, 0x87, 0x9f, 0xdd, 0xf3, 0x5e, 0x0b, 0x2f, 0x60, 0xc2, 0xa7, 0x0c, 0xb8, 0xeb, - 0x9d, 0xe2, 0xf5, 0xd7, 0x38, 0xc0, 0x5e, 0x34, 0xe5, 0x0f, 0x1f, 0x26, 0x19, 0x25, - 0x8b, 0x89, 0xe5, 0x73, 0xda, 0x55, 0x75, 0x46, 0x3d, 0x2e, 0x3b, 0xce, 0x39, 0xf7, - 0x0e, 0xb4, 0x55, 0x26, 0xcd, 0x99, 0xfa, 0xd9, 0x0f, 0x97, 0x92, 0xd0, 0xcd, 0x59, - 0x3b, 0xa8, 0x6a, 0xa1, 0xae, 0xa5, 0x03, 0xdd, 0xca, 0x5e, 0x3e, 0x57, 0x37, 0xe6, - 0xfc, 0x7b, 0xab, 0x27, 0x85, 0x12, 0x69, 0x20, 0xc4, 0x47, 0xd5, 0xe5, 0x6a, 0x75, - 0xdb, 0xe8, 0x9d, 0x68, 0x8b, 0xc0, 0xda, 0xa7, 0x9a, 0xa6, 0x2d, 0xe9, 0xea, 0x29, - 0x55, 0xf7, 0x1e, 0x1a, 0x61, 0x68, 0x2a, 0x61, 0x78, 0xf8, 0x0b, 0xca, 0xda, 0x3b, - 0x97, 0xae, 0xec, 0x77, 0xd9, 0xc8, 0x56, 0x3b, 0x06, 0x9e, 0xa0, 0x13, 0x2f, 0x72, - 0x3f, 0xbe, 0x75, 0x60, 0x2d, 0xd6, 0x29, 0xac, 0x48, 0x09, 0x93, 0xd3, 0x71, 0x4f, - 0xf0, 0x2c, 0x97, 0x0e, 0xbd, 0x83, 0xe6, 0xd6, 0xcb, 0xbe, 0x39, 0x08, 0x6b, 0x03, - 0x54, 0x20, 0xe0, 0xc2, 0x75, 0x62, 0x86, 0x58, 0xa3, 0xba, 0x92, 0x30, 0x5c, 0xc0, - 0x76, 0x98, 0xf1, 0x2e, 0xe1, 0xe4, 0x17, 0x13, 0x70, 0xac, 0x39, 0xdf, 0x0e, 0x46, - 0x6d, 0xc8, 0xec, 0xc3, 0x9d, 0xa5, 0xee, 0x47, 0xb6, 0x82, 0x9d, 0xbb, 0xa9, 0x97, - 0x0f, 0x03, 0x58, 0xed, 0x68, 0x26, 0x49, 0x60, 0x5c, 0x7b, 0xfe, 0xe6, 0x93, 0x1a, - 0x29, 0x5b, 0x14, 0xa3, 0x40, 0x76, 0x00, 0x07, 0x4e, 0xdc, 0x79, 0xfa, 0x61, 0xe6, - 0x80, 0x6f, 0x11, 0x08, 0xd3, 0x34, 0xb4, 0xa5, 0x90, 0xf7, 0xa0, 0x26, 0xb0, 0xeb, - 0x02, 0x80, 0x4d, 0x39, 0x17, 0x46, 0x6e, 0x99, 0x91, 0x20, 0x64, 0x1c, 0xe0, 0x7e, - 0xbc, 0xdc, 0x99, 0x42, 0x60, 0x82, 0xe0, 0x77, 0x1f, 0x15, 0x9c, 0x82, 0x6a, 0x9b, - 0xe6, 0xce, 0xd7, 0x2d, 0x0e, 0x9c, 0xfa, 0x5b, 0x4b, 0x8a, 0x86, 0x40, 0xca, 0x34, - 0x88, 0xa1, 0xeb, 0x2b, 0x6e, 0x37, 0x4e, 0x8c, 0x2e, 0x00, 0x3c, 0xdf, 0xa2, 0x32, - 0x10, 0x37, 0x48, 0xb5, 0xc9, 0xdc, 0x11, 0xbb, 0x30, 0xf6, 0x46, 0xb9, 0x73, 0xd7, - 0x83, 0xf5, 0x99, 0x14, 0x17, 0x4e, 0x48, 0xbd, 0x6a, 0x84, 0xfa, 0xd8, 0x9d, 0xbc, - 0xa5, 0xc7, 0x6d, 0x0a, 0xb4, 0x14, 0x5a, 0xbd, 0x08, 0xe4, 0xd0, 0xf2, 0xc7, 0x60, - 0x25, 0xfc, 0x85, 0xfc, 0x11, 0x6c, 0xca, 0x8d, 0x30, 0x2c, 0x8a, 0x3b, 0xeb, 0x26, - 0x60, 0x3a, 0x1a, 0xf1, 0xb5, 0x93, 0x91, 0xea, 0xf4, 0x71, 0x75, 0x9a, 0xdf, 0x19, - 0x4c, 0x40, 0xc2, 0x09, 0x29, 0x8c, 0xc0, 0x51, 0xfc, 0x79, 0x03, 0xfe, 0x40, 0x90, - 0x2c, 0x35, 0x6f, 0x28, 0x27, 0x9f, 0x27, 0x94, 0xbb, 0xb9, 0xe0, 0x0b, 0x1e, 0x22, - 0x1b, 0x0a, 0x26, 0x41, 0x06, 0xea, 0x50, 0x4f, 0xb8, 0x90, 0x6a, 0x20, 0x84, 0x5a, - 0x05, 0x9a, 0x60, 0x3b, 0x4f, 0x00, 0xe7, 0x83, 0x6d, 0x40, 0x67, 0xa6, 0x04, 0x19, - 0x5f, 0x24, 0x6a, 0x0f, 0x3b, 0x31, 0x82, 0x3f, 0xdf, 0x69, 0x57, 0x8c, 0x47, 0xdb, - 0x5b, 0x3d, 0xda, 0x86, 0xaa, 0xb1, 0xec, 0x9f, 0x58, 0xd9, 0x62, 0x26, 0xc6, 0xb9, - 0x1d, 0xc0, 0xf0, 0x3f, 0xe8, 0xd7, 0xdf, 0x23, 0xcf, 0x53, 0xca, 0x8e, 0xa2, 0xa9, - 0x09, 0x4f, 0xc0, 0x28, 0x65, 0x26, 0x7c, 0x88, 0xfa, 0x8c, 0x01, 0x0e, 0xb5, 0x66, - 0x13, 0x06, 0x6e, 0x50, 0xf1, 0x55, 0x4a, 0xa4, 0x10, 0x8e, 0x25, 0xa9, 0xe9, 0x67, - 0xd3, 0x4a, 0x9c, 0xf1, 0x02, 0x8c, 0x17, 0x05, 0xfa, 0x37, 0x67, 0xf4, 0x6d, 0x4b, - 0xab, 0x70, 0x28, 0xb0, 0x9b, 0x20, 0x38, 0xfc, 0x1b, 0x72, 0x7f, 0x61, 0x9e, 0x61, - 0xc4, 0xfc, 0x16, 0xbf, 0xfe, 0x65, 0x7e, 0x99, 0x12, 0x6a, 0xc5, 0x18, 0x4f, 0xc8, - 0x7f, 0x5e, 0x53, 0x01, 0x88, 0x64, 0x23, 0xb3, 0x56, 0x87, 0x59, 0x09, 0xec, 0x92, - 0xb3, 0x2d, 0x33, 0x08, 0x42, 0x53, 0xa1, 0xb9, 0x7c, 0x5d, 0x2e, 0xd6, 0x6c, 0x7e, - 0x22, 0xd1, 0x85, 0x58, 0xfe, 0x82, 0xb5, 0xec, 0x88, 0xc6, 0x07, 0x05, 0x82, 0xfa, - 0xcf, 0x75, 0x6d, 0x70, 0x32, 0x38, 0xd9, 0xaf, 0x94, 0x19, 0x96, 0x6b, 0xe4, 0x62, - 0xdf, 0xbd, 0x31, 0x5c, 0x5b, 0xfa, 0xf0, 0x44, 0xaa, 0x69, 0x5a, 0x05, 0xe6, 0x9d, - 0x3d, 0x41, 0xe7, 0x73, 0x78, 0x75, 0x1d, 0x4e, 0x02, 0xc2, 0x66, 0xdf, 0xb5, 0xcb, - 0x6a, 0x7c, 0x40, 0x08, 0xf9, 0x44, 0x88, 0x83, 0x11, 0xe6, 0xde, 0x37, 0xdc, 0x7b, - 0xdf, 0x65, 0xd7, 0x0c, 0xab, 0x3e, 0x07, 0x8a, 0xb4, 0x4e, 0x23, 0x2b, 0x41, 0x1c, - 0xaf, 0xb2, 0x88, 0x4e, 0x26, 0x45, 0x95, 0xbe, 0xed, 0xf9, 0xd4, 0x9a, 0x79, 0x36, - 0xbb, 0x28, 0x7f, 0xe2, 0x8e, 0x1c, 0x29, 0x63, 0x5e, 0xae, 0xca, 0x74, 0x7d, 0x06, - 0x87, 0xcf, 0x46, 0x59, 0x02, 0xd2, 0x5f, 0x5e, 0x51, 0x58, 0x48, 0x1d, 0xaa, 0xcd, - 0xd3, 0x00, 0xb4, 0x77, 0x40, 0xbc, 0x0c, 0x62, 0x77, 0xb4, 0x47, 0xcc, 0x26, 0x64, - 0x04, 0x42, 0x43, 0xdd, 0x48, 0x11, 0x40, 0x4e, 0xcb, 0xd7, 0xc7, 0xa6, 0x3c, 0x9f, - 0xb7, 0xd9, 0x37, 0xbc, 0xd8, 0x12, 0xc2, 0x34, 0x59, 0x23, 0xb5, 0x90, 0x26, 0x83, - 0xbd, 0x2e, 0xd5, 0x4c, 0x01, 0xae, 0x04, 0x19, 0xa7, 0xf5, 0x4e, 0x8a, 0x3a, 0x59, - 0xc6, 0xa6, 0xda, 0xcf, 0x89, 0xc7, 0x37, 0x0e, 0x79, 0xb5, 0x60, 0x13, 0x6a, 0x2b, - 0x00, 0xdd, 0xb6, 0x07, 0x4d, 0x74, 0xff, 0xc5, 0xc5, 0xdf, 0xd0, 0x6b, 0x6c, 0x51, - 0x9a, 0xbe, 0xc3, 0x59, 0x6a, 0x47, 0x61, 0x13, 0xbe, 0x41, 0x38, 0xee, 0xad, 0x5f, - 0xfd, 0xe8, 0x6b, 0x1e, 0x32, 0x40, 0x1f, 0xa3, 0x84, 0x62, 0x32, 0xd0, 0xb3, 0xc9, - 0xbd, 0x56, 0x88, 0xb6, 0x4a, 0x33, 0x09, 0x38, 0x16, 0x2a, 0x8b, 0x89, 0x29, 0xd7, - 0x0c, 0x1b, 0x67, 0x53, 0x62, 0xf4, 0xc2, 0xa9, 0xbb, 0x6b, 0x7f, 0x91, 0xeb, 0xd4, - 0x7d, 0x26, 0x3c, 0xf0, 0xa4, 0x05, 0xa2, 0x8b, 0xa7, 0x41, 0x56, 0x44, 0xf9, 0x3b, - 0x6c, 0xdf, 0xa3, 0xec, 0xeb, 0xb7, 0xb8, 0xd4, 0xee, 0x8b, 0x94, 0xb2, 0x7b, 0x61, - 0xe4, 0x03, 0x5e, 0xd6, 0xa4, 0x77, 0x46, 0x7f, 0x4a, 0x32, 0x0b, 0x8a, 0x4e, 0xba, - 0x0a, 0xb5, 0x6c, 0x26, 0x3e, 0x4b, 0xfb, 0xe2, 0x6a, 0x41, 0x8e, 0xd1, 0xcd, 0xe6, - 0x18, 0x4b, 0x89, 0x50, 0xfe, 0x7a, 0xac, 0x7f, 0x20, 0xa4, 0x7b, 0xa1, 0xbf, 0xf9, - 0x80, 0x4f, 0x53, 0xf6, 0x93, 0x23, 0xdb, 0x84, 0x75, 0x20, 0xa6, 0x58, 0x47, 0xb3, - 0x03, 0x4c, 0x4e, 0x08, 0x1b, 0xb4, 0xb8, 0x69, 0x26, 0x3b, 0x5f, 0x9b, 0x3a, 0x7a, - 0x83, 0x3b, 0x6e, 0x4c, 0xa7, 0x90, 0xcc, 0xf9, 0xfd, 0xae, 0x80, 0x79, 0xe5, 0x56, - 0x09, 0x27, 0x2c, 0x63, 0xb5, 0x49, 0xb0, 0xc8, 0x5f, 0x11, 0x0c, 0xc9, 0xc9, 0x58, - 0x68, 0x01, 0x14, 0xb3, 0x11, 0x74, 0x80, 0xaf, 0x57, 0xcb, 0x15, 0x9e, 0xdf, 0xbe, - 0x5c, 0xb9, 0xc6, 0x2b, 0xce, 0x2c, 0xf2, 0xab, 0x29, 0xb6, 0x67, 0x11, 0xac, 0x7a, - 0xa5, 0x3a, 0x74, 0x9f, 0xfa, 0x83, 0x90, 0x7e, 0xcb, 0x69, 0x12, 0xaa, 0x56, 0x96, - 0x38, 0xde, 0xa1, 0x9e, 0x54, 0x41, 0x61, 0x1e, 0xfc, 0xa3, 0x20, 0x99, 0x65, 0x3e, - 0x8a, 0x5c, 0xa1, 0xfb, 0xbd, 0xba, 0xb1, 0xd6, 0x44, 0x71, 0xec, 0x32, 0x0e, 0xc3, - 0x8e, 0xa4, 0x88, 0x40, 0x0c, 0x9b, 0x1f, 0x4e, 0x8c, 0xb5, 0x48, 0x0c, 0x0e, 0x92, - 0x42, 0xb0, 0x86, 0xa8, 0x0e, 0xee, 0xd4, 0x90, 0xae, 0x32, 0x00, 0x0c, 0x80, 0x09, - 0xec, 0xb7, 0x1f, 0xfa, 0x39, 0xf4, 0xf3, 0xb5, 0x74, 0x9c, 0xfd, 0x1b, 0xef, 0xe0, - 0xd9, 0x66, 0x7a, 0xb3, 0x02, 0x20, 0xc2, 0xdc, 0x04, 0x39, 0x36, 0x98, 0xb2, 0xcf, - 0xa2, 0x04, 0x92, 0xf2, 0x50, 0xce, 0x14, 0x32, 0x35, 0x81, 0x58, 0x70, 0x3d, 0xf7, - 0xb1, 0x39, 0xd7, 0x45, 0xce, 0x1f, 0xc3, 0x40, 0x78, 0x77, 0x01, 0xfb, 0x51, 0xdd, - 0x5e, 0x48, 0xb8, 0x95, 0x09, 0x41, 0x7d, 0x88, 0x89, 0x00, 0x80, 0x63, 0xf9, 0xba, - 0x01, 0x5a, 0x07, 0xd8, 0xd3, 0x9b, 0xbd, 0x00, 0x76, 0x2f, 0x59, 0x5a, 0xfa, 0xd8, - 0xd8, 0x59, 0xea, 0xab, 0xf0, 0xd8, 0x2d, 0x46, 0x33, 0xcf, 0x82, 0x98, 0xb0, 0x9b, - 0xea, 0x3f, 0x22, 0x28, 0x55, 0xa9, 0x2a, 0x08, 0x43, 0xf5, 0x2f, 0xa5, 0x8d, 0xb3, - 0xa1, 0x75, 0xc3, 0x0d, 0x2a, 0xbe, 0x64, 0x82, 0x64, 0x90, 0xcb, 0xe6, 0xca, 0x14, - 0x88, 0xfe, 0x3a, 0x01, 0x5a, 0x94, 0x6d, 0xc9, 0xc4, 0x5a, 0xc3, 0x09, 0x25, 0x72, - 0x7a, 0x13, 0xe0, 0x89, 0x78, 0xf7, 0x24, 0x03, 0x47, 0x20, 0x8a, 0x4d, 0x25, 0x38, - 0xc2, 0xd5, 0x61, 0x24, 0x37, 0x8c, 0x22, 0xc0, 0x4e, 0x23, 0xdc, 0x28, 0xb1, 0x50, - 0x19, 0xbe, 0x77, 0x6d, 0x70, 0xbf, 0xc1, 0xd2, 0x64, 0x5b, 0x5e, 0x80, 0xd1, 0xfd, - 0x84, 0x19, 0xdf, 0x72, 0x90, 0x43, 0x80, 0xe2, 0xe1, 0xfc, 0x4d, 0xd1, 0xdf, 0x1b, - 0xa3, 0xdf, 0xe4, 0x80, 0xcc, 0x84, 0x6d, 0x51, 0x51, 0x4a, 0x06, 0x5e, 0xd7, 0x62, - 0x78, 0x7a, 0xfd, 0x6e, 0xb9, 0x0b, 0xdf, 0x8f, 0xbb, 0xad, 0x5e, 0xb3, 0xd2, 0x3f, - 0xdc, 0x8c, 0x54, 0xcc, 0xa1, 0x0f, 0xa1, 0xfe, 0x54, 0x64, 0x82, 0xf5, 0xe1, 0x42, - 0x4b, 0xfd, 0xa8, 0x7a, 0xa7, 0xfb, 0x78, 0x6e, 0x26, 0x0f, 0x26, 0x14, 0xbe, 0x08, - 0x11, 0xee, 0x16, 0xb8, 0xd2, 0x9d, 0xf9, 0xa0, 0xf3, 0x30, 0xe9, 0x70, 0x9f, 0x63, - 0xc9, 0x50, 0xfb, 0xd9, 0x03, 0xff, 0x7d, 0x5b, 0x0c, 0xa2, 0x9f, 0xd6, 0x3b, 0x0f, - 0x97, 0x51, 0x77, 0x69, 0x02, 0x5c, 0xc3, 0x6a, 0x52, 0xe0, 0x00, 0x15, 0x93, 0x4a, - 0x3c, 0xa2, 0x58, 0xb8, 0xba, 0xb9, 0x00, 0x16, 0xa4, 0x01, 0xd5, 0xd8, 0xd7, 0xc3, - 0xb9, 0x44, 0x92, 0x5b, 0x35, 0xa9, 0x34, 0x9a, 0x1a, 0xc7, 0xd9, 0x85, 0x21, 0x61, - 0x0c, 0x2f, 0xad, 0x8b, 0x5c, 0x8b, 0x31, 0x9c, 0xd6, 0xe0, 0x5f, 0x9b, 0xbe, 0xd3, - 0x53, 0xf1, 0xd0, 0xc8, 0x65, 0xa9, 0x4a, 0xa4, 0x56, 0xdc, 0xd1, 0x8a, 0x39, 0xe2, - 0xf5, 0x85, 0xd9, 0xbe, 0xa8, - ], - script_code: vec![0x63, 0x00, 0x6a, 0x53, 0x63, 0x6a, 0xac, 0x00], - transparent_input: None, - hash_type: 1, - amount: 1788797765223798, - consensus_branch_id: 1991772603, - sighash: [ - 0xcb, 0xfa, 0x22, 0x69, 0x9b, 0x04, 0xbe, 0xb7, 0x67, 0x07, 0xb5, 0x1d, 0x62, 0x5e, - 0x94, 0xd2, 0x6c, 0x0d, 0xf8, 0xad, 0xa7, 0xcf, 0x68, 0xfc, 0xde, 0xd9, 0x60, 0x65, - 0x4b, 0x20, 0xf3, 0x60, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x00, 0x02, 0x12, 0x9a, 0x03, 0xd5, - 0x7d, 0x32, 0x07, 0x00, 0x07, 0x52, 0x51, 0xac, 0x51, 0x65, 0xac, 0x00, 0x91, 0xdb, - 0xbd, 0x6f, 0xf3, 0x8f, 0x01, 0x00, 0x05, 0x53, 0x6a, 0x63, 0x63, 0x53, 0x6f, 0x34, - 0xc4, 0x99, 0x32, 0x68, 0xc7, 0x09, 0xef, 0xf1, 0x20, 0x1b, 0x50, 0x92, 0x05, 0x00, - 0x02, 0x3b, 0x5c, 0x8b, 0x5b, 0x80, 0xe7, 0x7b, 0x87, 0xf1, 0xeb, 0x73, 0xaf, 0x77, - 0x60, 0xed, 0xae, 0x0e, 0x19, 0x3e, 0x38, 0x96, 0xb1, 0x5c, 0x55, 0x8f, 0x00, 0x4e, - 0x7c, 0x7d, 0x93, 0x24, 0xd3, 0x85, 0xb4, 0x50, 0xcd, 0x4b, 0x98, 0x2a, 0xba, 0x8d, - 0x2e, 0x91, 0xf4, 0x1f, 0x22, 0xee, 0xe7, 0xf3, 0x6d, 0x79, 0xcc, 0xa9, 0xc0, 0xe0, - 0x1b, 0x26, 0xc4, 0x65, 0x11, 0x18, 0xea, 0x77, 0x15, 0x14, 0xc7, 0x7e, 0xd6, 0x0c, - 0xd5, 0x24, 0x51, 0x94, 0x2d, 0xc8, 0x5b, 0x3f, 0xba, 0x44, 0x8b, 0x2d, 0x63, 0x10, - 0xf2, 0x77, 0x79, 0x42, 0x83, 0x2e, 0x21, 0xcf, 0x3d, 0x44, 0x87, 0x4f, 0x8d, 0xca, - 0x98, 0x2b, 0x68, 0x7c, 0x9e, 0xd7, 0xe0, 0xb2, 0x32, 0x77, 0x07, 0x3c, 0x19, 0x30, - 0xa4, 0x73, 0xd1, 0x66, 0x8e, 0xf2, 0xe9, 0xae, 0x96, 0x63, 0xcf, 0xf0, 0x58, 0x16, - 0x62, 0x6c, 0xd3, 0xc5, 0xbf, 0x77, 0x16, 0x53, 0xd7, 0x78, 0x51, 0x81, 0x35, 0x5c, - 0x05, 0xae, 0xd2, 0x4a, 0x99, 0xc4, 0xb6, 0x74, 0xd2, 0x4a, 0x0f, 0x08, 0xf4, 0xb0, - 0xcf, 0xbe, 0x90, 0xf2, 0xfd, 0xba, 0xb4, 0x24, 0x82, 0xe9, 0x8f, 0x13, 0xff, 0xfc, - 0xd1, 0xad, 0x33, 0xf4, 0xf4, 0xc0, 0x4d, 0xeb, 0xc8, 0x9f, 0x40, 0xb5, 0xdb, 0xf6, - 0x45, 0x46, 0xc5, 0x20, 0xdc, 0xa5, 0xd0, 0xec, 0xf3, 0xf6, 0x5d, 0x3a, 0x77, 0xd0, - 0x12, 0x9f, 0x60, 0x03, 0x71, 0x10, 0x8a, 0xac, 0x30, 0xa9, 0xec, 0xa8, 0xbe, 0xe5, - 0x52, 0x4f, 0xab, 0x67, 0x1f, 0xc0, 0x86, 0x58, 0x76, 0x2c, 0x87, 0x38, 0xab, 0xc9, - 0xfa, 0x76, 0x93, 0xe3, 0x9d, 0x39, 0xd7, 0x03, 0xd5, 0xcd, 0x94, 0x2b, 0x5a, 0x55, - 0xfe, 0xda, 0xfe, 0xcc, 0xae, 0xf7, 0x02, 0x17, 0x69, 0xe9, 0x2c, 0xc9, 0xd3, 0xac, - 0x7b, 0x4c, 0x23, 0xb3, 0x3f, 0xc2, 0x23, 0x21, 0x85, 0x4b, 0xa3, 0x3f, 0x49, 0xee, - 0xba, 0xdd, 0xca, 0x29, 0xb3, 0x56, 0x40, 0xe4, 0xf0, 0xc2, 0xfd, 0x8c, 0x12, 0xb9, - 0x84, 0x52, 0x97, 0x60, 0xe0, 0x65, 0xfe, 0xcb, 0xa1, 0x21, 0x86, 0xd2, 0x0a, 0xee, - 0xc3, 0xda, 0x58, 0xfc, 0x35, 0x9b, 0xa8, 0x25, 0xe5, 0xb8, 0xe2, 0xe1, 0x8f, 0x12, - 0xcf, 0x29, 0x49, 0xc3, 0x12, 0xf6, 0x3c, 0x4d, 0xd7, 0xa7, 0x9b, 0x0e, 0x66, 0xb9, - 0xc8, 0xb6, 0x6f, 0xe8, 0x9a, 0xd7, 0xed, 0xc6, 0x2a, 0xc4, 0xd2, 0x07, 0xe2, 0x77, - 0xb9, 0x33, 0xb0, 0xc2, 0x06, 0xdd, 0x7c, 0x22, 0xd2, 0xdb, 0x26, 0x33, 0xfc, 0x01, - 0xa8, 0x3c, 0x24, 0xfc, 0xad, 0x40, 0x9c, 0xee, 0xd5, 0x36, 0xa6, 0xd3, 0xe8, 0xe0, - 0x8d, 0x42, 0xb5, 0x13, 0x48, 0x97, 0xb4, 0x36, 0xbf, 0xf3, 0xa1, 0xbc, 0xef, 0xc5, - 0x3a, 0xec, 0x30, 0xed, 0x89, 0x11, 0x0f, 0x89, 0x60, 0x88, 0x8a, 0x1c, 0xf2, 0x41, - 0x5c, 0xc6, 0x93, 0xa8, 0x52, 0x97, 0xd6, 0xb7, 0x89, 0x14, 0x1e, 0x04, 0x1a, 0x3c, - 0x14, 0xa5, 0xf9, 0xc6, 0x46, 0x33, 0xbe, 0x06, 0x56, 0x45, 0xe9, 0xca, 0x36, 0x37, - 0xf3, 0x73, 0x83, 0x04, 0xec, 0x3b, 0x16, 0x51, 0x31, 0x46, 0x83, 0xa0, 0x27, 0x5e, - 0x73, 0x36, 0x79, 0x70, 0x01, 0x06, 0x78, 0x23, 0x17, 0x79, 0x3e, 0x86, 0x6c, 0xed, - 0x59, 0x89, 0x21, 0x3f, 0x3b, 0xac, 0xfc, 0xfd, 0x20, 0x02, 0xea, 0x86, 0x6f, 0x3f, - 0x17, 0x07, 0x35, 0x12, 0x64, 0xb6, 0x67, 0x88, 0xf4, 0xeb, 0x7f, 0x68, 0xc5, 0xa5, - 0x36, 0xfa, 0x9c, 0x13, 0x0d, 0x20, 0x26, 0xea, 0x80, 0x97, 0x94, 0xd3, 0xb7, 0x4d, - 0x78, 0x01, 0x7e, 0xe0, 0xfb, 0xca, 0x83, 0xcc, 0x7e, 0x5c, 0xbd, 0x52, 0x7a, 0xcd, - 0xe7, 0x46, 0x53, 0x73, 0x51, 0x2c, 0x07, 0x64, 0x6a, 0x62, 0xc6, 0x0f, 0x5c, 0x16, - 0xc2, 0xef, 0x9f, 0x41, 0x8d, 0x8c, 0x7d, 0x18, 0x8f, 0x7b, 0x13, 0xdd, 0x45, 0x38, - 0xa5, 0x5d, 0x18, 0x6a, 0xd6, 0x36, 0x2a, 0x58, 0x9a, 0x9f, 0x52, 0xb2, 0x5e, 0x61, - 0x6f, 0xb2, 0xa3, 0x57, 0xac, 0xca, 0xde, 0x63, 0x57, 0xfa, 0x5a, 0x42, 0xa7, 0x98, - 0xe4, 0x17, 0x13, 0x11, 0xad, 0xe9, 0xcc, 0xfd, 0x15, 0xf2, 0x7c, 0x8c, 0x19, 0x72, - 0x17, 0x9d, 0x26, 0x1f, 0xb9, 0xb0, 0x9b, 0xc7, 0xa0, 0x36, 0xc1, 0x05, 0x55, 0x9b, - 0x04, 0x38, 0x9d, 0xfd, 0x8a, 0x7b, 0xe2, 0xa3, 0xae, 0x2b, 0xba, 0x2a, 0xfb, 0xd1, - 0xe9, 0xbf, 0x90, 0x05, 0xc8, 0xb3, 0x66, 0x35, 0x4f, 0x90, 0x9b, 0xe7, 0x1e, 0x52, - 0xc0, 0x90, 0x80, 0xfb, 0xa7, 0x45, 0x23, 0x77, 0xe8, 0xf1, 0x2c, 0x18, 0x4f, 0xe7, - 0xed, 0x46, 0x5b, 0x32, 0xc9, 0xf9, 0xb2, 0x81, 0x9e, 0xa1, 0xd1, 0x19, 0xfc, 0x26, - 0x7c, 0x8a, 0x75, 0x33, 0x81, 0xeb, 0x51, 0xac, 0xf8, 0x54, 0xc1, 0x9e, 0x8d, 0x58, - 0xff, 0x42, 0x74, 0xeb, 0xa8, 0xc6, 0x3f, 0x0f, 0xa1, 0x70, 0xa6, 0x3c, 0xbf, 0xce, - 0x2c, 0xf8, 0x7b, 0xdc, 0xdf, 0x32, 0xb7, 0xe1, 0x98, 0x04, 0x54, 0x1c, 0x2c, 0x58, - 0x97, 0x24, 0xef, 0xc6, 0x9b, 0xc4, 0x65, 0xd0, 0x90, 0x8e, 0x09, 0xb8, 0x4d, 0x1f, - 0x50, 0x41, 0x2b, 0xb0, 0x7f, 0x47, 0xfb, 0x9f, 0x0d, 0x47, 0x29, 0x28, 0x16, 0x14, - 0xca, 0xca, 0xb6, 0x14, 0xef, 0x65, 0xce, 0xba, 0x13, 0x96, 0xb5, 0x24, 0x9d, 0x2c, - 0x61, 0x70, 0x4f, 0xb6, 0xf3, 0x48, 0x44, 0x71, 0x83, 0xf9, 0x88, 0x2a, 0x98, 0xae, - 0x9c, 0x71, 0xa7, 0x66, 0x33, 0xe0, 0x5b, 0x33, 0x3a, 0x1b, 0xce, 0xee, 0xc9, 0xbd, - 0x44, 0xb8, 0x87, 0x6f, 0xab, 0x6c, 0xd7, 0x2a, 0x5e, 0x33, 0x5c, 0x97, 0x7a, 0x04, - 0x55, 0xc5, 0x36, 0x5f, 0xe8, 0x7f, 0x17, 0xa0, 0x5c, 0x0f, 0x8c, 0x23, 0x3b, 0x97, - 0x29, 0xc1, 0x09, 0x3b, 0xae, 0xb8, 0x57, 0x5c, 0xe5, 0xfd, 0xfb, 0xfd, 0x6e, 0x6a, - 0x8e, 0xbf, 0x76, 0x46, 0x47, 0x81, 0xf9, 0xb2, 0x10, 0xed, 0xb3, 0x9d, 0x20, 0x6a, - 0x68, 0x5d, 0x0d, 0xc7, 0xec, 0x06, 0x8e, 0x3c, 0x6b, 0x13, 0xd2, 0xf2, 0xaa, 0x74, - 0x11, 0x92, 0xbc, 0x86, 0x25, 0xab, 0xd3, 0x0d, 0xb6, 0xe6, 0x64, 0xfb, 0x33, 0x30, - 0xf9, 0x5c, 0xb3, 0x1b, 0xa1, 0x29, 0x0b, 0xd7, 0xf8, 0x30, 0x31, 0xc7, 0x89, 0xc2, - 0x4f, 0xd5, 0x73, 0x93, 0x46, 0x90, 0xa7, 0x3b, 0x54, 0xa9, 0x05, 0xdf, 0x8e, 0x1d, - 0x59, 0x32, 0x2f, 0x26, 0x2b, 0xbf, 0xbe, 0x95, 0xcc, 0x5b, 0x9b, 0x1e, 0x20, 0x31, - 0x0b, 0x76, 0x35, 0x0b, 0x4d, 0x60, 0x4c, 0xd1, 0xa4, 0x58, 0x66, 0x1d, 0xc4, 0x74, - 0xfe, 0x4c, 0x58, 0x79, 0x04, 0xc0, 0x53, 0x47, 0x5e, 0x17, 0x61, 0xb8, 0x0a, 0x60, - 0xcc, 0x48, 0xed, 0xd9, 0x54, 0x34, 0xdf, 0x02, 0x3b, 0x94, 0xa5, 0x8a, 0x99, 0xd6, - 0x25, 0x66, 0xe0, 0x0f, 0x67, 0x77, 0x90, 0xdc, 0xa0, 0x76, 0xa4, 0xf1, 0x67, 0x47, - 0x0c, 0x43, 0xa8, 0x1e, 0x6c, 0x32, 0xf0, 0xd0, 0x0d, 0x23, 0x65, 0x6b, 0xa7, 0x48, - 0x28, 0xb8, 0xe4, 0xd4, 0x75, 0x38, 0xe5, 0x0c, 0x0e, 0xce, 0xe2, 0xcd, 0xfe, 0x0d, - 0x59, 0x43, 0xe2, 0x3e, 0x3f, 0x17, 0x33, 0x82, 0x9d, 0x3e, 0x1b, 0x80, 0x53, 0x93, - 0x30, 0xe0, 0x6c, 0x6a, 0xe3, 0xd0, 0xec, 0xe7, 0x38, 0xc0, 0xdd, 0x74, 0x2a, 0xa5, - 0x86, 0x0f, 0x43, 0xb5, 0x30, 0xf0, 0x3d, 0xc5, 0x5d, 0xeb, 0xf7, 0x20, 0x12, 0x3f, - 0x8f, 0xba, 0xf2, 0xe5, 0x68, 0x59, 0xa5, 0x34, 0x3d, 0x46, 0x12, 0xee, 0x21, 0x46, - 0x4d, 0xb2, 0x50, 0x1d, 0x4f, 0x35, 0x31, 0x47, 0xf3, 0xe1, 0xa5, 0xab, 0xb8, 0x93, - 0x85, 0x08, 0x16, 0xc8, 0x0a, 0xf2, 0x9d, 0x88, 0x92, 0x48, 0xc9, 0x2a, 0x72, 0x9a, - 0x0e, 0x2b, 0xe2, 0xb6, 0x6c, 0xc1, 0x3a, 0xc5, 0xd9, 0x96, 0xb2, 0x50, 0x14, 0x66, - 0x6d, 0xdc, 0x63, 0x8a, 0x1f, 0xd2, 0xa0, 0xaf, 0xee, 0x93, 0xd9, 0x8e, 0x31, 0xdc, - 0x1e, 0xa8, 0x58, 0xd7, 0x2b, 0x84, 0xbb, 0xd3, 0x2f, 0xc0, 0xc6, 0x16, 0xe7, 0xd4, - 0xab, 0xda, 0xf3, 0xc1, 0x8f, 0xf9, 0x60, 0x13, 0x24, 0x5d, 0x83, 0xb3, 0xbd, 0xf9, - 0x21, 0xf4, 0x03, 0xf1, 0xae, 0xcf, 0xdd, 0xd8, 0x85, 0xfd, 0xcf, 0xc7, 0x33, 0x87, - 0x0f, 0x76, 0x0c, 0xb8, 0x7e, 0xd4, 0xfc, 0xd9, 0xcc, 0xa9, 0x33, 0x2e, 0x8e, 0x1c, - 0x85, 0x62, 0x3b, 0x20, 0x66, 0x09, 0xf8, 0x87, 0xeb, 0xdb, 0xcf, 0x9d, 0xa1, 0x0f, - 0x38, 0x14, 0x19, 0x7a, 0x9f, 0x82, 0x07, 0x05, 0xea, 0xa1, 0x28, 0x3a, 0xc7, 0x93, - 0x16, 0x83, 0x08, 0x3f, 0x22, 0xfc, 0x4d, 0xc7, 0xff, 0x68, 0x1a, 0xb8, 0x46, 0x18, - 0x6f, 0x22, 0xd5, 0x73, 0x08, 0x43, 0xde, 0x71, 0x00, 0xf0, 0x31, 0x17, 0xa3, 0xbb, - 0xa0, 0x64, 0xca, 0x3c, 0xea, 0x93, 0xf3, 0xab, 0xd3, 0x0b, 0xe6, 0xdb, 0x09, 0x35, - 0x52, 0x9d, 0xed, 0x0b, 0x50, 0xec, 0xef, 0x9f, 0x59, 0x6d, 0xb0, 0x1a, 0x87, 0xa8, - 0xda, 0xdb, 0x82, 0x7a, 0x1b, 0xe8, 0xb5, 0x79, 0x9b, 0x33, 0xc9, 0x9a, 0x82, 0x2b, - 0x73, 0xf7, 0xe6, 0x62, 0xed, 0x6f, 0x86, 0x03, 0x45, 0xa2, 0x62, 0x83, 0xc1, 0xb4, - 0x08, 0x0e, 0xcd, 0xf5, 0x79, 0xd7, 0x0e, 0x7b, 0x0c, 0x0a, 0xb7, 0x1e, 0x11, 0x6e, - 0xe2, 0xd9, 0xda, 0x27, 0x46, 0x1e, 0x28, 0x12, 0x2a, 0x09, 0xca, 0x04, 0xde, 0x38, - 0x76, 0x50, 0x2f, 0xd2, 0x4d, 0xff, 0x92, 0x09, 0x55, 0x2f, 0x91, 0x13, 0x87, 0x70, - 0x78, 0xa0, 0x94, 0xe0, 0xe5, 0xf8, 0xce, 0xbb, 0x41, 0x54, 0xe0, 0x3a, 0x6b, 0x56, - 0xf6, 0x04, 0xdf, 0x98, 0x4b, 0xd2, 0x9e, 0xfd, 0x4f, 0x88, 0xc3, 0xf6, 0x29, 0xea, - 0x2b, 0xba, 0x91, 0x27, 0xea, 0x5a, 0x6c, 0xc5, 0xa3, 0x9d, 0x74, 0x1e, 0xdd, 0x71, - 0x1a, 0x24, 0x44, 0x7f, 0xe0, 0x6c, 0xf8, 0x45, 0x5a, 0x44, 0x06, 0x5e, 0x24, 0x52, - 0x76, 0x3b, 0x0d, 0x93, 0xf8, 0x6a, 0x31, 0x47, 0xbd, 0x08, 0x75, 0x7a, 0x4f, 0x7a, - 0xa7, 0x79, 0x3c, 0x97, 0x82, 0x1c, 0x2b, 0x57, 0x22, 0xc9, 0xdb, 0xad, 0x20, 0xf6, - 0xa1, 0xe7, 0xad, 0xf6, 0x8b, 0xf2, 0x22, 0x7b, 0xe5, 0x12, 0x04, 0xe9, 0xde, 0xca, - 0x8d, 0x9e, 0xb6, 0x26, 0x6f, 0x65, 0x9b, 0x33, 0x55, 0xc8, 0x97, 0x7e, 0xae, 0x7e, - 0x9e, 0xd5, 0x39, 0xd1, 0x79, 0x39, 0xf0, 0xc6, 0x16, 0x6b, 0x01, 0x13, 0x2d, 0xb0, - 0x01, 0x66, 0x25, 0x0e, 0xa9, 0x64, 0xe3, 0x9d, 0x9d, 0x55, 0xab, 0x43, 0x9a, 0x29, - 0xbb, 0x0b, 0xcf, 0xd3, 0xa9, 0x99, 0xb3, 0x1f, 0xe7, 0xa9, 0x51, 0x00, 0x2e, 0xe5, - 0xdc, 0x01, 0x27, 0x03, 0x24, 0xb1, 0x10, 0x10, 0x37, 0x89, 0x29, 0x42, 0x90, 0x7c, - 0x6e, 0x19, 0x50, 0x9a, 0x6c, 0x5f, 0x66, 0x59, 0xba, 0xf7, 0xf4, 0x36, 0x3c, 0x49, - 0x15, 0xe6, 0x1b, 0xda, 0x34, 0x06, 0x9b, 0xd9, 0x86, 0xb6, 0x37, 0x7f, 0xf6, 0x04, - 0xed, 0xe5, 0xa7, 0x42, 0x5d, 0xb2, 0x88, 0x86, 0xb1, 0xa2, 0x61, 0x36, 0x6d, 0xa8, - 0xa1, 0x39, 0x86, 0x65, 0xbe, 0xed, 0x3b, 0xe9, 0xbc, 0x2e, 0x05, 0x5e, 0x71, 0x1b, - 0x7d, 0x36, 0xdd, 0xbd, 0xd3, 0x65, 0xcc, 0xdc, 0xd7, 0xfc, 0xba, 0xfe, 0x71, 0x29, - 0x66, 0x95, 0x08, 0xda, 0xc0, 0xad, 0x2d, 0x55, 0xee, 0x7f, 0xc6, 0x0b, 0xce, 0x22, - 0x88, 0x50, 0xba, 0x7b, 0x94, 0x3a, 0x8d, 0x50, 0xff, 0xcb, 0x2a, 0x67, 0x06, 0x51, - 0xd3, 0x15, 0xd8, 0x71, 0x9c, 0x7b, 0x57, 0xf6, 0x37, 0xa3, 0x7e, 0xdd, 0x32, 0x6a, - 0xbc, 0x76, 0xf0, 0xa7, 0x69, 0x0c, 0x23, 0x68, 0x80, 0x16, 0x01, 0x07, 0xc2, 0xb4, - 0xc8, 0x5e, 0xcf, 0x2a, 0xd9, 0xf5, 0xdd, 0x26, 0x45, 0x62, 0x6e, 0x40, 0x90, 0xf1, - 0x00, 0x47, 0xcc, 0x13, 0x15, 0x40, 0xca, 0x58, 0x03, 0x04, 0x5a, 0x6a, 0xee, 0x91, - 0xea, 0x0b, 0x3f, 0x9b, 0x77, 0xc4, 0x43, 0x40, 0x69, 0xc5, 0x32, 0x0c, 0xf5, 0xb7, - 0x01, 0x82, 0xd9, 0xfb, 0xbf, 0x30, 0x98, 0x30, 0x60, 0x11, 0x75, 0x9d, 0x0d, 0x64, - 0xa8, 0x84, 0x14, 0x1e, 0xa0, 0x21, 0xcd, 0xd9, 0x5e, 0xfa, 0x32, 0x63, 0xa5, 0x05, - 0xb8, 0x52, 0x29, 0xd1, 0x54, 0xec, 0xaa, 0x23, 0x5e, 0x8f, 0xa1, 0x07, 0x95, 0xc9, - 0xda, 0x27, 0x41, 0xcd, 0x98, 0x71, 0x90, 0x16, 0xa9, 0x01, 0x17, 0xa7, 0x6f, 0x84, - 0xf0, 0x0b, 0x5c, 0x3d, 0x4b, 0xce, 0xd7, 0x9a, 0x73, 0xbf, 0xb3, 0xa1, 0xc7, 0x8a, - 0xd1, 0xad, 0xea, 0x50, 0x78, 0xf2, 0xf1, 0xb0, 0x0f, 0x81, 0x5b, 0xc7, 0xa3, 0x0e, - 0xf8, 0x58, 0x40, 0x07, 0x77, 0x32, 0xdc, 0xb1, 0xa6, 0x1e, 0xd4, 0xbc, 0xbd, 0x66, - 0x35, 0x28, 0x50, 0x29, 0x77, 0x94, 0xad, 0x67, 0xd2, 0x93, 0xdc, 0xe9, 0x10, 0x61, - 0x13, 0x0c, 0xa4, 0x8b, 0xab, 0xca, 0xaa, 0xd6, 0x0b, 0x1f, 0x7c, 0xed, 0x07, 0xac, - 0x3f, 0xf3, 0x32, 0xd5, 0xc8, 0xd3, 0x2b, 0xa2, 0xf1, 0xe7, 0x8a, 0x23, 0xb0, 0x66, - 0x29, 0xb8, 0x89, 0x06, 0x6f, 0x07, 0x9b, 0xcd, 0xa2, 0x9f, 0xb5, 0xc8, 0x3b, 0xbb, - 0xd3, 0x7e, 0xc6, 0x17, 0x3e, 0x8a, 0x74, 0x81, 0x22, 0x12, 0x86, 0x6b, 0xcb, 0x58, - 0x80, 0x5e, 0x9e, 0x70, 0x17, 0x96, 0xa7, 0x23, 0xd5, 0x15, 0xe6, 0x15, 0x33, 0x20, - 0x0b, 0xe0, 0x6b, 0x01, 0x5f, 0xa0, 0x22, 0x35, 0xc8, 0xcb, 0xc9, 0xf3, 0x61, 0x7e, - 0xe8, 0x19, 0x5f, 0xe1, 0xbc, 0xf5, 0xbb, 0x1b, 0x63, 0x4c, 0xd4, 0x3f, 0x62, 0xea, - 0x93, 0xa4, 0x6d, 0x88, 0xf2, 0xfc, 0xbc, 0x3e, 0x28, 0x40, 0x84, 0xe7, 0x04, 0xfb, - 0x1d, 0x7d, 0x0d, 0x9a, 0xcb, 0x91, 0x96, 0x1e, 0x2e, 0xeb, 0xe2, 0xdc, 0x9e, 0xbe, - 0x36, 0x5b, 0x25, 0xb5, 0x66, 0x75, 0x97, 0x3d, 0x0c, 0x38, 0xf4, 0x76, 0x30, 0x57, - 0x47, 0x23, 0xcd, 0x3e, 0xc6, 0x6c, 0x8f, 0x3b, 0x12, 0x82, 0x21, 0xa7, 0x90, 0xd9, - 0x2c, 0x89, 0x5b, 0x94, 0x27, 0x0f, 0xe9, 0x40, 0x51, 0xa1, 0x70, 0xe9, 0x5b, 0x8b, - 0xe7, 0x16, 0x34, 0x86, 0xec, 0x8c, 0x0b, 0xee, 0xbe, 0xf6, 0x5e, 0x16, 0x26, 0xb0, - 0x46, 0xd7, 0xe7, 0xf8, 0x26, 0x37, 0x2b, 0x6a, 0xa1, 0x0b, 0xae, 0xfb, 0x84, 0x8f, - 0xa1, 0xdf, 0x6b, 0xb1, 0xdc, 0x43, 0x95, 0x40, 0xf6, 0x3c, 0x9c, 0x7a, 0x9d, 0x5f, - 0x88, 0x13, 0x40, 0x29, 0x62, 0x65, 0x1e, 0xe9, 0x84, 0x39, 0x02, 0xb6, 0xc3, 0x98, - 0x2d, 0xce, 0x50, 0xa6, 0x17, 0x8a, 0x55, 0xa1, 0xad, 0xc0, 0x1c, 0xe7, 0xdc, 0x6c, - 0x83, 0x38, 0xe1, 0xa9, 0xce, 0xef, 0xc1, 0x78, 0xdc, 0x43, 0x14, 0xf6, 0x74, 0x9a, - 0x81, 0xa7, 0x31, 0xee, 0x3c, 0x7f, 0xc0, 0xc3, 0x5d, 0x1c, 0xe3, 0x63, 0xce, 0xf1, - 0x13, 0x28, 0xf3, 0x87, 0xc4, 0x01, 0xfe, 0xf2, 0x7a, 0x67, 0xa6, 0x29, 0x2f, 0x6f, - 0x72, 0xb0, 0xa1, 0xd6, 0xc3, 0x89, 0x16, 0x2d, 0x16, 0x2e, 0xf0, 0x50, 0xae, 0x5f, - 0x3d, 0xdb, 0xb5, 0x5c, 0xaa, 0xbc, 0xa9, 0xa1, 0xbe, 0x89, 0xb4, 0x63, 0x49, 0x4d, - 0x74, 0x39, 0xfb, 0x56, 0x47, 0xa9, 0x18, 0x12, 0x8b, 0x96, 0x25, 0xd3, 0x3e, 0xac, - 0xa6, 0x19, 0xd5, 0x2f, 0x03, 0x5f, 0xe6, 0x08, 0x9c, 0xe8, 0xd8, 0xb9, 0x0f, 0xe3, - 0x67, 0x0d, 0x8c, 0x5a, 0x2e, 0x3e, 0x05, 0x49, 0x69, 0xa3, 0xd9, 0x7e, 0x61, 0xb5, - 0xe6, 0x30, 0x67, 0x4f, 0xc7, 0x08, 0x57, 0xf1, 0xbb, 0xf1, 0x0f, 0xdc, 0x40, 0x49, - 0xef, 0xf5, 0x60, 0xeb, 0xa5, 0xf2, 0x2a, 0xcc, 0x8d, 0x77, 0xdb, 0xee, 0x0b, 0x20, - 0x55, 0x7f, 0xa4, 0xd0, 0x33, 0x31, 0x72, 0xcb, 0xb5, 0xcb, 0xcc, 0x2b, 0x13, 0x5f, - 0x2c, 0xcd, 0xe0, 0x14, 0xe6, 0x3e, 0xbe, 0x4e, 0xdf, 0x92, 0x5e, 0x61, 0xba, 0x2a, - 0x32, 0x0c, 0xd3, 0x99, 0x91, 0x5a, 0xdd, 0xfc, 0xeb, 0x1a, 0xd0, 0x69, 0xa9, 0xfd, - 0x5b, 0x62, 0x10, 0xa4, 0xb6, 0xe5, 0x04, 0x52, 0xb1, 0xf9, 0x06, 0xdd, 0x16, 0xf0, - 0x16, 0x68, 0xf0, 0xaf, 0x56, 0x6a, 0x28, 0x7c, 0xce, 0xfc, 0xd8, 0x94, 0x73, 0x41, - 0x85, 0x9a, 0xe7, 0xdc, 0x3a, 0x06, 0xf6, 0xbf, 0x15, 0x74, 0xfe, 0xb9, 0x31, 0xf9, - 0x27, 0xe2, 0xd5, 0x05, 0xf6, 0x08, 0x59, 0x9e, 0x23, 0xb0, 0x5a, 0xf7, 0xc3, 0x23, - 0x69, 0x83, 0x97, 0xa8, 0x01, 0xdc, 0x7f, 0x78, 0x82, 0x5c, 0xc7, 0xeb, 0x9f, 0xcc, - 0xe6, 0xc6, 0xc4, 0xf8, 0xf6, 0x88, 0x39, 0xd3, 0x0a, 0xc5, 0x67, 0x14, 0x8e, 0x70, - 0x84, 0xdb, 0x2b, 0x37, 0x58, 0x30, 0xa0, 0x7b, 0x30, 0x5f, 0xed, 0xd6, 0x07, 0xa3, - 0x47, 0xfa, 0x65, 0xde, 0xf0, 0x1d, 0x4e, 0x1f, 0xd6, 0xc1, 0x6b, 0x4b, 0x47, 0xf5, - 0xb0, 0x1b, 0x43, 0x65, 0xb7, 0x72, 0x26, 0xe6, 0x0f, 0xdd, 0x40, 0xf2, 0x2a, 0x39, - 0x5a, 0xa2, 0x35, 0xf0, 0xdf, 0xda, 0x8f, 0xb4, 0xd3, 0xde, 0x65, 0xb0, 0xcf, 0x4f, - 0x4c, 0x22, 0x0b, 0x3b, 0x4a, 0x9e, 0x32, 0xbc, 0x0d, 0xb6, 0x4f, 0x16, 0x2c, 0x07, - 0xdf, 0x42, 0xa1, 0x01, 0x99, 0x03, 0xa6, 0x7c, 0xda, 0x69, 0x3d, 0xde, 0xb5, 0xca, - 0x39, 0xa0, 0xfe, 0x50, 0x08, 0x50, 0xec, 0x7c, 0x06, 0xbe, 0xe7, 0x18, 0x66, 0xb3, - 0x55, 0xcc, 0xbc, 0x07, 0x8c, 0xd4, 0xdc, 0x03, 0x6f, 0xda, 0xa8, 0x1c, 0xb2, 0xde, - 0x99, 0xcc, 0x88, 0xf6, 0x0a, 0x49, 0x46, 0x42, 0x87, 0xf5, 0x9f, 0xc7, 0x14, 0x8b, - 0x1a, 0xfb, 0x4a, 0x2f, 0x9b, 0xb8, 0x97, 0x14, 0xe1, 0xeb, 0x8c, 0x03, 0x61, 0xe5, - 0x99, 0x2a, 0x5b, 0x79, 0xcd, 0xbb, 0x91, 0xd9, 0xbf, 0x29, 0xeb, 0x59, 0x8c, 0xbb, - 0x4b, 0xda, 0x92, 0x3d, 0x26, 0x7f, 0xea, 0xcb, 0x91, 0xce, 0x72, 0xd6, 0x1a, 0xb1, - 0xea, 0x00, 0xf5, 0x6a, 0xa6, 0x76, 0x6e, 0xab, 0xc4, 0x7d, 0xca, 0xa6, 0x9a, 0x02, - 0x4b, 0xbf, 0xf2, 0xf2, 0x96, 0x91, 0x7f, 0x17, 0xa3, 0xf8, 0xc9, 0x3e, 0x1b, 0xf2, - 0x9c, 0x3c, 0xfc, 0x99, 0x1a, 0x2b, 0xe8, 0xcf, 0xa7, 0x0e, 0x5d, 0xe3, 0xf2, 0xdd, - 0x52, 0xa7, 0x55, 0x01, 0x38, 0x68, 0x7a, 0xec, 0x28, 0x92, 0x6f, 0xa1, 0x68, 0xb1, - 0x81, 0xdb, 0x72, 0x82, 0xbd, 0x60, 0xda, 0xd3, 0x31, 0x0d, 0xfe, 0x54, 0x2c, 0xeb, - 0xe6, 0x94, 0x74, 0x00, 0x25, 0xc7, 0xec, 0x2a, 0x20, 0x43, 0xfe, 0xbb, 0x77, 0x9f, - 0x7f, 0x37, 0x89, 0xa5, 0xe2, 0x42, 0xdb, 0x48, 0x03, 0xee, 0x36, 0x72, 0x52, 0xc4, - 0x63, 0xc9, 0xa8, 0x8b, 0x41, 0x7b, 0x70, 0x86, 0x6d, 0x9a, 0xfb, 0x7a, 0x08, 0x27, - 0x68, 0x01, 0xf9, 0x22, 0x7c, 0x63, 0x81, 0xf1, 0x5c, 0xc0, 0x94, 0xac, 0x7b, 0xd1, - 0x54, 0xa4, 0xce, 0xf9, 0x0b, 0x48, 0x47, 0xdc, 0x16, 0x8a, 0x01, 0xf1, 0xe3, 0x1e, - 0xec, 0x74, 0xa7, 0xef, 0xce, 0xba, 0x11, 0xf5, 0x07, 0x69, 0xf5, 0xd8, 0xf5, 0x4d, - 0x36, 0x20, 0xc2, 0x3e, 0xc8, 0x99, 0x3f, 0x7a, 0xef, 0x27, 0xc1, 0xd3, 0x51, 0x96, - 0xb1, 0x02, 0xb3, 0xcf, 0x3f, 0xed, 0x8b, 0xf8, 0x5d, 0x8a, 0x45, 0xf6, 0x96, 0x83, - 0xec, 0xdd, 0x1a, 0x23, 0x44, 0xef, 0xb8, 0x48, 0x07, 0xd9, 0x0f, 0x18, 0x35, 0xb4, - 0xf2, 0xf2, 0x4d, 0x8f, 0xf8, 0x12, 0x30, 0x47, 0xeb, 0x9f, 0x7d, 0x30, 0x62, 0x3e, - 0x14, 0x29, 0x0d, 0x56, 0x17, 0x96, 0x3b, 0x42, 0x21, 0x40, 0x4a, 0xe7, 0x61, 0xc8, - 0x6b, 0xec, 0x7a, 0x07, 0xbf, 0x81, 0xa0, 0xb9, 0xa7, 0xf7, 0xd0, 0x87, 0xac, 0x26, - 0xce, 0x3d, 0xfa, 0x9c, 0x93, 0xfe, 0xea, 0xeb, 0xd1, 0x0d, 0xc1, 0x88, 0xc6, 0x27, - 0xd4, 0xb9, 0x1d, 0x2a, 0x79, 0x01, 0xee, 0x5a, 0x1b, 0x38, 0x4d, 0xa3, 0x6e, 0x78, - 0x95, 0xd5, 0xb7, 0x78, 0x21, 0xfe, 0x6b, 0xca, 0xa3, 0xaf, 0xe8, 0xf2, 0x3a, 0x96, - 0x8f, 0xc9, 0xab, 0xa3, 0x7b, 0x1a, 0x4e, 0x25, 0xf5, 0xdb, 0xa1, 0xd1, 0x42, 0xff, - 0x11, 0xff, 0xd7, 0xa1, 0xba, 0x41, 0xef, 0x82, 0xc6, 0x2a, 0x95, 0x94, 0x66, 0xe7, - 0x11, 0x2a, 0xf7, 0x79, 0x6d, 0x47, 0x67, 0x12, 0x69, 0xad, 0xd3, 0xee, 0x2b, 0x17, - 0x21, 0x3e, 0xc3, 0xbd, 0x51, 0x30, 0x24, 0x4c, 0xb9, 0x07, 0x0e, 0xa8, 0xcf, 0xa4, - 0x6d, 0x44, 0xf2, 0xfc, 0xd9, 0x64, 0x06, 0x37, 0xf7, 0xde, 0xfd, 0x50, 0xb6, 0xdc, - 0x93, 0x60, 0x19, 0x45, 0xb9, 0x31, 0xe8, 0xbb, 0x72, 0x67, 0x1f, 0xe4, 0xb4, 0xb5, - 0x88, 0xc9, 0x0a, 0xd5, 0xc0, 0x0b, 0x55, 0xdc, 0x8c, 0x8a, 0xf9, 0xb0, 0xf6, 0xa3, - 0xca, 0x1e, 0x07, 0xef, 0xf1, 0x58, 0x11, 0x39, 0x1c, 0x53, 0xf7, 0xe4, 0x3b, 0x1b, - 0x81, 0x16, 0xda, 0xdc, 0x01, 0x6d, 0x19, 0x26, 0xc8, 0x48, 0x0d, 0x4e, 0xe3, 0x4e, - 0x76, 0x19, 0x1b, 0x79, 0xbe, 0xd0, 0xce, 0x95, 0x97, 0x3a, 0x4c, 0x7c, 0xf2, 0xf0, - 0x57, 0xc7, 0x14, 0x7e, 0xdb, 0x01, 0x3d, 0x20, 0x5d, 0x81, 0xe2, 0x36, 0x08, 0x88, - 0xa2, 0xab, 0xdd, 0xcc, 0xf0, 0xf6, 0xf3, 0xd8, 0xf8, 0xba, 0x11, 0x1d, 0x64, 0x2c, - 0x52, 0xd0, 0x4e, 0xbd, 0x3c, 0xe1, 0x7c, 0x60, 0xd9, 0x22, 0x57, 0xea, 0x58, 0x69, - 0x09, 0x45, 0x01, 0xbb, 0x67, 0x12, 0x68, 0xb2, 0x24, 0x47, 0x7a, 0x8e, 0x01, 0x41, - 0xd6, 0xff, 0x37, 0xe2, 0x4f, 0xf1, 0xc7, 0x65, 0xe8, 0x4d, 0x26, 0x4d, 0xb8, 0x8f, - 0x00, 0x92, 0x8e, 0x64, 0xc4, 0x12, 0xbd, 0x59, 0x15, 0x1a, 0x65, 0x71, 0xc6, 0x67, - 0x09, 0x16, 0xb0, 0x70, 0x6b, 0x04, 0x4f, 0xc5, 0xc2, 0xbd, 0x93, 0xad, 0xe3, 0x96, - 0x79, 0x57, 0xcd, 0xb9, 0x41, 0x27, 0x4c, 0xc6, 0xbd, 0xb4, 0xe0, 0x36, 0xb7, 0x67, - 0xb9, 0x50, 0xc0, 0x9e, 0x46, 0x26, 0xa1, 0xd0, 0x05, 0xbc, 0xf4, 0x83, 0x6e, 0xf6, - 0xa1, 0xde, 0x48, 0x09, 0x5d, 0xcb, 0x46, 0x12, 0x78, 0xb1, 0x6c, 0x45, 0x68, 0x90, - 0xb2, 0x3d, 0x40, 0xbd, 0x36, 0x04, 0x10, 0xf0, 0x01, 0x0a, 0x55, 0xf5, 0x05, 0xfe, - 0x5e, 0x2d, 0xb2, 0x01, 0xc7, 0x52, 0xe9, 0xb5, 0xb1, 0x5b, 0xf8, 0xaa, 0x9e, 0x82, - 0xd6, 0x49, 0xab, 0x11, 0x73, 0xba, 0x2a, 0x51, 0x32, 0xe0, 0xcc, 0x50, 0x51, 0xcc, - 0xf7, 0x4c, 0x7a, 0x6a, 0x37, 0x07, 0xab, 0x59, 0x83, 0xf7, 0xcc, 0x27, 0x5c, 0x99, - 0x1a, 0xbe, 0x4d, 0x7c, 0xee, 0x5f, 0x28, 0x9e, 0xfe, 0x72, 0x7e, 0xb3, 0xda, 0x86, - 0xfa, 0x21, 0xa2, 0x8d, 0x6b, 0x8a, 0x2a, 0xff, 0xd4, 0x2d, 0xb9, 0x8b, 0xb2, 0xa4, - 0x6c, 0xd8, 0xa3, 0x29, 0x31, 0x2f, 0xa9, 0x45, 0x39, 0xd9, 0xcb, 0x35, 0xdc, 0xb6, - 0x04, 0x67, 0x8b, 0x63, 0x90, 0x64, 0xd9, 0x20, 0x05, 0xdf, 0x2d, 0x10, 0x68, 0x1c, - 0x64, 0xb9, 0xed, 0x8c, 0xe4, 0x7d, 0x7e, 0xba, 0x0f, 0x2b, 0x50, 0x2b, 0x20, 0x6a, - 0xd4, 0xb2, 0xe9, 0x2b, 0xbe, 0x45, 0x86, 0xf6, 0xd7, 0x50, 0x9e, 0x57, 0xa6, 0x37, - 0x7f, 0xea, 0xbe, 0x38, 0xb3, 0xcc, 0x6c, 0x95, 0x5d, 0x5e, 0x7b, 0xdf, 0x7e, 0xb1, - 0x32, 0xd8, 0x6b, 0xc0, 0x7a, 0x30, 0x98, 0xb4, 0x13, 0xe4, 0x40, 0x5d, 0xaa, 0xa2, - 0x55, 0x29, 0x1d, 0x55, 0x2b, 0x2c, 0x80, 0x07, 0xbe, 0xd4, 0x1e, 0x22, 0xf1, 0xcf, - 0x79, 0x11, 0x82, 0x12, 0x00, 0x55, 0x5e, 0x9c, 0x4f, 0xfb, 0x09, 0xef, 0xc1, 0x22, - 0x38, 0x11, 0x75, 0x03, 0x1c, 0x38, 0x28, 0x0b, 0x53, 0x26, 0xeb, 0xbe, 0xaf, 0x33, - 0x4f, 0xdc, 0xf0, 0xdc, 0x44, 0x4e, 0x62, 0x9f, 0x93, 0x95, 0x51, 0x54, 0x0b, 0xcb, - 0xbb, 0xb1, 0xab, 0x9c, 0x23, 0x1a, 0x86, 0x6b, 0x32, 0x9e, 0x85, 0x24, 0xab, 0x25, - 0xf9, 0x3e, 0x5e, 0x33, 0x4a, 0x05, 0x27, 0x2a, 0x3f, 0x82, 0x6f, 0x9d, 0x05, 0xa4, - 0x50, 0x58, 0xdf, 0xcd, 0xf6, 0x88, 0x43, 0xa8, 0xb9, 0x36, 0xa0, 0xcf, 0x5e, 0x6a, - 0xa8, 0xae, 0x1b, 0x80, 0xf6, 0x01, 0x61, 0xbf, 0x41, 0x4f, 0x28, 0x02, 0x11, 0x11, - 0x09, 0x21, 0xa9, 0xc8, 0x5f, 0x51, 0x04, 0xa0, 0x16, 0x8e, 0x8e, 0x72, 0xde, 0x4f, - 0x8a, 0xa0, 0x41, 0x32, 0xeb, 0x25, 0x88, 0x76, 0xf1, 0x9d, 0x7b, 0xe5, 0xf2, 0xdd, - 0x2b, 0x0b, 0x30, 0x4b, 0x92, 0x3b, 0x29, 0x52, 0xd9, 0x1f, 0xde, 0xe7, 0xe5, 0x52, - 0x05, 0xdb, 0xb1, 0x94, 0xeb, 0xba, 0x32, 0x2f, 0xdc, 0x67, 0xb2, 0x52, 0x2c, 0x92, - 0x61, 0x21, 0xc7, 0xfa, 0x1a, 0xf1, 0x7e, 0xd0, 0x6c, 0x47, 0x27, 0x8f, 0x96, 0x08, - 0x92, 0x96, 0x08, 0x7a, 0x70, 0x4b, 0x7d, 0x0f, 0x84, 0x7d, 0x51, 0xd6, 0xcc, 0x68, - 0xac, 0xc5, 0x22, 0x07, 0x74, 0x73, 0x41, 0xf6, 0xb9, 0x8c, 0xb1, 0xcd, 0x4f, 0xaf, - 0xcd, 0x2b, 0xb0, 0xd0, 0x5b, 0xc7, 0x9b, 0xb8, 0x0d, 0x7c, 0x4b, 0x8a, 0x1a, 0x11, - 0xbc, 0x0a, 0x3b, 0xde, 0xca, 0x45, 0x41, 0x86, 0x9b, 0x4d, 0xc9, 0xd6, 0xb4, 0x8c, - 0xd7, 0x86, 0x9b, 0xf7, 0x63, 0xb9, 0xdc, 0x42, 0x45, 0x27, 0x3c, 0x70, 0x4b, 0x0d, - 0x8d, 0xec, 0x4b, 0x85, 0xd1, 0x6d, 0xd4, 0x38, 0xce, 0xd6, 0x22, 0x0f, 0xa6, 0x69, - 0x26, 0x66, 0x3f, 0xcc, 0x22, 0x8f, 0xc6, 0xc4, 0xd2, 0x7e, 0x17, 0xe3, 0x27, 0x83, - 0x4b, 0x67, 0x57, 0x91, 0x4d, 0x1b, 0xcb, 0xf3, 0x4b, 0x65, 0xd8, 0x58, 0xab, 0x8b, - 0x5c, 0x12, 0x0c, 0xb0, 0x85, 0x05, 0x22, 0xf5, 0x42, 0x89, 0x3f, 0xdd, 0xb1, 0x79, - 0xe8, 0x7f, 0x83, 0x2d, 0xaa, 0xa1, 0x52, 0xc8, 0x31, 0xf1, 0x35, 0x64, 0x00, 0x9c, - 0x41, 0x81, 0x23, 0x53, 0x3d, 0xe2, 0xc6, 0x79, 0x49, 0xe3, 0xaf, 0x2d, 0xcb, 0x60, - 0xd6, 0xbd, 0xbd, 0xda, 0xda, 0x63, 0xa3, 0x0b, 0x4b, 0x54, 0xcd, 0x1c, 0xe5, 0xa5, - 0xa0, 0x0f, 0x8e, 0x85, 0x57, 0xeb, 0xa9, 0x23, 0x4e, 0x81, 0x17, 0x8d, 0x0f, 0xca, - 0xb5, 0x61, 0x0f, 0xba, 0x96, 0x69, 0xcf, 0xeb, 0x1b, 0xd0, 0x8c, 0xd9, 0x65, 0x33, - 0x49, 0x8b, 0x27, 0x2c, 0x57, 0x79, 0xa9, 0xf9, 0x39, 0x69, 0x1d, 0xe1, 0xad, 0x88, - 0x1c, 0x80, 0x87, 0x8d, 0x6c, 0x29, 0x42, 0x15, 0x23, 0x0b, 0xbb, 0x61, 0x90, 0x69, - 0xb4, 0xdc, 0x17, 0xb3, 0xe5, 0x9d, 0xbd, 0x24, 0x2c, 0xd8, 0x8e, 0xcc, 0x3b, 0xe3, - 0xa2, 0x69, 0x6b, 0xf7, 0xf2, 0xd9, 0xe5, 0xb8, 0xc1, 0x52, 0xcc, 0x0d, 0x99, 0xa0, - 0xa5, 0xe9, 0xa3, 0x8b, 0x1b, 0x8e, 0xb1, 0xa0, 0x13, 0xeb, 0x76, 0x51, 0x33, 0x37, - 0xa7, 0xb0, 0xda, 0xdb, 0x4e, 0x81, 0x7b, 0x6f, 0x49, 0x78, 0x02, 0xbd, 0x47, 0xe9, - 0x3a, 0x82, 0x0c, 0x4f, 0xad, 0x6c, 0x65, 0x09, 0x74, 0x42, 0xb9, 0xca, 0xc1, 0x61, - 0xb6, 0x4d, 0x0f, 0xcb, 0xfb, 0xf5, 0x4f, 0xc3, 0x04, 0xc9, 0xb7, 0x0c, 0x74, 0xfb, - 0xb0, 0xd7, 0x05, 0xc7, 0x4d, 0x56, 0xac, 0xb2, 0xfe, 0x6c, 0x91, 0x74, 0xcc, 0x00, - 0xea, 0xbe, 0xa0, 0xe5, 0x97, 0x0d, 0xff, 0xe3, 0x2c, 0xb6, 0x12, 0x92, 0x05, 0x3d, - 0xb8, 0x6d, 0x36, 0x6b, 0x7e, 0x6b, 0x30, 0x13, 0xd1, 0x4b, 0x20, 0x5f, 0xb4, 0x5d, - 0x06, 0x7e, 0x37, 0x50, 0x2e, 0x37, 0x9c, 0x4a, 0xa1, 0x38, 0xbe, 0xc2, 0xc6, 0xbd, - 0x33, 0x1f, 0x58, 0xe9, 0xaa, 0x10, 0x09, 0xb0, 0x66, 0xdc, 0xe9, 0x9a, 0xcc, 0x1d, - 0xc5, 0xa6, 0x3a, 0x8f, 0x75, 0xd1, 0x98, 0x22, 0x7c, 0x2f, 0xbd, 0x20, 0xd5, 0x34, - 0xf1, 0x20, 0x30, 0xc4, 0x00, 0x99, 0xd8, 0x77, 0xca, 0xbe, 0x81, 0xb0, 0x87, 0x50, - 0xe3, 0xfb, 0xfe, 0x63, 0x12, 0xf6, 0x38, 0x0b, 0x98, 0xfb, 0x85, 0x0a, 0x2a, 0x14, - 0x2b, 0x91, 0x4a, 0xdc, 0x71, 0x54, 0x47, 0xc5, 0x79, 0x1a, 0x1b, 0x67, 0xae, 0x65, - 0x6c, 0xad, 0xdd, 0x21, 0xe1, 0xb4, 0x6d, 0xc9, 0xa7, 0x64, 0x12, 0x7b, 0xc0, 0xa3, - 0x01, 0xb4, 0x80, 0x04, 0xa9, 0xc5, 0x27, 0x6b, 0xcf, 0x08, 0xe7, 0xfe, 0x4a, 0xe5, - 0x2d, 0x76, 0xe4, 0x31, 0x48, 0x8a, 0x5b, 0x9d, 0x43, 0x1f, 0xa1, 0x36, 0x34, 0x6e, - 0x5a, 0x53, 0xab, 0x3f, 0x68, 0x12, 0xf2, 0xd9, 0x70, 0xf7, 0xb3, 0x98, 0x98, 0xcf, - 0x8b, 0x62, 0xf2, 0xdb, 0xf6, 0x1e, 0x99, 0xa2, 0x91, 0x5d, 0xfb, 0x75, 0xae, 0x22, - 0xb7, 0x9f, 0x84, 0xcf, 0x25, 0x97, 0xeb, 0x34, 0xec, 0x3d, 0x29, 0x2e, 0x6b, 0x5d, - 0x84, 0xeb, 0xac, 0x4d, 0x92, 0xde, 0x52, 0xe1, 0xf8, 0xbf, 0x6b, 0xfd, 0xba, 0xda, - 0x63, 0x44, 0x09, 0xf2, 0x0e, 0xf2, 0xcc, 0x6e, 0x3c, 0x39, 0x0e, 0x43, 0x5f, 0x47, - 0xe3, 0x47, 0x23, 0x8d, 0xb4, 0x86, 0x90, 0x84, 0x04, 0x73, 0xb0, 0xa0, 0x83, 0x1a, - 0x5a, 0x8a, 0x58, 0xc4, 0xdc, 0xfc, 0x4e, 0xab, 0x7b, 0x41, 0x8c, 0xba, 0x2a, 0x41, - 0x4f, 0x95, 0x57, 0x71, 0x90, 0xff, 0x88, 0xd7, 0x27, 0xf7, 0x3e, 0x2f, 0xff, 0x97, - 0xaa, 0xbd, 0x11, 0x14, 0xb7, 0x64, 0xe3, 0xed, 0xbc, 0x18, 0x3e, 0x60, 0x3a, 0xcf, - 0xb7, 0xc0, 0x9b, 0xf1, 0x32, 0xbb, 0x01, 0xef, 0xc7, 0x17, 0x8d, 0x4f, 0x9a, 0x2d, - 0xba, 0xf4, 0x92, 0x4f, 0xd8, 0x0f, 0xbe, 0x0e, 0x60, 0x4f, 0x60, 0x39, 0x08, 0x32, - 0xeb, 0x98, 0x04, 0x79, 0xe0, 0x4e, 0x9c, 0x9a, 0x2b, 0xb2, 0xfb, 0x36, 0x84, 0xd8, - 0xf8, 0x06, 0x48, 0xd5, 0x80, 0x78, 0x38, 0x54, 0x58, 0x4f, 0x62, 0xbe, 0x0c, 0xc9, - 0x21, 0x88, 0x32, 0x38, 0x56, 0x10, 0xd9, 0x62, 0x36, 0x5f, 0x50, 0x71, 0xfa, 0x3d, - 0x36, 0x8f, 0xfb, 0x67, 0x1b, 0xa2, 0xc2, 0xf9, 0xa0, 0xfc, 0x68, 0xd8, 0x07, 0x22, - 0x19, 0xa7, 0x7b, 0xef, 0x2d, 0x6b, 0x4a, 0x19, 0xf1, 0x6d, 0xd5, 0x30, 0x74, 0x22, - 0x47, 0x46, 0xbb, 0xa5, 0xf1, 0x72, 0x82, 0x20, 0xb1, 0x96, 0xe4, 0x0f, 0x93, 0x7c, - 0x47, 0x05, 0x42, 0x9d, 0x04, 0xaa, 0x3c, 0x50, 0x5c, 0x95, 0x60, 0x3e, 0x05, 0xff, - 0x55, 0x2e, 0xc1, 0x86, 0x42, 0xd5, 0x67, 0x05, 0x02, 0x67, 0xb9, 0xf9, 0x92, 0x9c, - 0x2e, 0x13, 0x80, 0x14, 0xb5, 0xef, 0x1b, 0xa7, 0x1d, 0x9a, 0x71, 0x86, 0xe3, 0xd1, - 0x3c, 0x8a, 0x8e, 0x40, 0x8c, 0x2a, 0x9d, 0x12, 0x01, 0xa7, 0xfe, 0xbb, 0x83, 0x34, - 0x51, 0x2b, 0x44, 0xb8, 0x2b, 0xb2, 0x01, 0x78, 0x9f, 0x63, 0x58, 0x04, 0x89, 0x6e, - 0x3e, 0xb2, 0x1b, 0x5b, 0xd8, 0xc4, 0x21, 0xf0, 0xb4, 0xcf, 0xba, 0x04, 0xde, 0x92, - 0x52, 0x8f, 0x04, 0xfb, 0x4b, 0x52, 0x6b, 0x73, 0x7e, 0xe3, 0x2d, 0xa8, 0x63, 0xf5, - 0x98, 0x45, 0x61, 0x31, 0x98, 0x3a, 0x01, 0x35, 0x8f, 0xb0, 0x7d, 0xe6, 0x75, 0x21, - 0x11, 0x58, 0x5a, 0x86, 0x25, 0x6c, 0xe0, 0x34, 0xc0, 0xd8, 0x57, 0x5a, 0x42, 0x76, - 0x13, 0x61, 0xb1, 0x18, 0x77, 0x05, 0x0b, 0xc6, 0xaf, 0xc3, 0x16, 0x15, 0x64, 0xe9, - 0x6f, 0xd8, 0xcf, 0x04, 0x8f, 0xeb, 0xeb, 0x2a, 0x92, 0x20, 0x07, 0x1c, 0xff, 0x18, - 0x2d, 0x6c, 0xa0, 0x37, 0xce, 0x2c, 0x2d, 0xed, 0x91, 0x6b, 0xd7, 0xb8, 0x4d, 0xe2, - 0x8a, 0xc0, 0x17, 0x1d, 0x97, 0xfc, 0x24, 0x95, 0x6c, 0x26, 0x66, 0x69, 0xc1, 0x03, - 0x6b, 0x2b, 0x1a, 0x23, 0xda, 0xbc, 0xf3, 0x4e, 0x38, 0xf3, 0x51, 0x45, 0x12, 0xae, - 0x8a, 0x47, 0xb3, 0x53, 0xb4, 0x16, 0x69, 0x96, 0x75, 0xe4, 0xd3, 0x1a, 0x2f, 0xe0, - 0x34, 0x08, 0xe4, 0x24, 0xa7, 0x82, 0x9a, 0x06, 0xad, 0xe6, 0x36, 0x53, 0x61, 0xd8, - 0xa9, 0x61, 0x25, 0x7c, 0xbe, 0x25, 0xb0, 0xcd, 0xe3, 0x3e, 0x96, 0x48, 0x77, 0xdf, - 0x5e, 0x57, 0xc5, 0x3d, 0xb2, 0x83, 0x51, 0x77, 0x34, 0x3e, 0x2d, 0x87, 0x6d, 0x51, - 0x4c, 0x62, 0xfb, 0xb3, 0xb4, 0xa7, 0x08, 0xce, 0x62, 0x62, 0x05, 0xcc, 0xf9, 0x2f, - 0x24, 0x0d, 0x60, 0x2c, 0xdb, 0x5d, 0x68, 0x41, 0xfd, 0x29, 0xda, 0x63, 0x08, 0xb6, - 0xca, 0x40, 0x97, 0xd8, 0x52, 0x54, 0x10, 0x46, 0x54, 0x52, 0x23, 0x9b, 0x04, 0x51, - 0xa8, 0xdb, 0xed, 0xac, 0x1e, 0x41, 0xed, 0xdd, 0x0f, 0x6b, 0xe0, 0xe3, 0xd8, 0x89, - 0x69, 0x07, 0x03, 0xa3, 0x14, 0x57, 0x07, 0xe0, 0xb3, 0xf5, 0xdb, 0x91, 0xb8, 0x19, - 0x37, 0x56, 0xe0, 0xe3, 0x47, 0xb6, 0x64, 0xa1, 0xcc, 0xcb, 0xd7, 0x86, 0x9a, 0x40, - 0x22, 0xea, 0xdf, 0x3f, 0x87, 0x3c, 0x10, 0xec, 0xab, 0x9a, 0x93, 0xf2, 0xca, 0xdc, - 0xa7, 0xa3, 0x33, 0xb8, 0x1b, 0xb6, 0x10, 0x4e, 0x82, 0xea, 0x14, 0xfe, 0x74, 0x1e, - 0xb0, 0x62, 0x08, 0x0d, 0xc8, 0x5a, 0xcb, 0xc8, 0xcc, 0x3a, 0x9b, 0xc8, 0x0c, 0x03, - 0xd9, 0x1f, 0xfb, 0x3c, 0x25, 0xf9, 0xe4, 0x2b, 0xc2, 0x5c, 0xf7, 0x7d, 0x73, 0x90, - 0xc3, 0xab, 0xaf, 0x26, 0x10, 0xf4, 0xec, 0xdb, 0x01, 0x9b, 0x15, 0x8d, 0xa2, 0x15, - 0x5b, 0xef, 0xec, 0xb9, 0xc2, 0x29, 0x6d, 0x03, 0xf8, 0x23, 0xea, 0xac, 0x0c, 0x74, - 0x0d, 0x2a, 0x44, 0x89, 0xb8, 0x28, 0x4c, 0x7e, 0x7b, 0x3a, 0x72, 0x9a, 0xfb, 0x69, - 0xbd, 0x5b, 0xfa, 0x5f, 0x62, 0xf9, 0xb5, 0x27, 0x37, 0x97, 0xdd, 0x24, 0xa0, 0x18, - 0x30, 0x7f, 0xc6, 0x20, 0xe6, 0x42, 0xaa, 0x27, 0xe7, 0x50, 0x6e, 0x17, 0xb1, 0x98, - 0xdc, 0xa4, 0x79, 0x0e, 0x8d, 0xe1, 0xbf, 0xb6, 0x71, 0xd8, 0xdc, 0x75, 0x13, 0x91, - 0x0e, 0x95, 0x43, 0x10, 0x72, 0x1b, 0x4f, 0xb5, 0x37, 0x33, 0xc9, 0x18, 0xf0, 0xd1, - 0x89, 0x85, 0x18, 0x89, 0x62, 0x73, 0x22, 0xd5, 0x20, 0xca, 0xcc, 0x9d, 0xd7, 0x03, - 0x6b, 0xb4, 0x39, 0xa1, 0x69, 0xef, 0x2c, 0xdd, 0x6c, 0xdb, 0xae, 0xa5, 0xa9, 0x1b, - 0xc2, 0x4a, 0xb3, 0xfc, 0xa1, 0x57, 0x4c, 0x12, 0xc9, 0x31, 0xe7, 0xaa, 0x02, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xd3, 0xc6, 0x49, 0x66, 0xc0, 0x6b, 0x62, 0x2d, 0x23, 0xc8, 0x8d, 0xb2, 0xfd, - 0x4b, 0x8f, 0xa5, 0x0b, 0xe3, 0x61, 0x94, 0x3b, 0x79, 0x6d, 0x14, 0x85, 0x5f, 0x20, - 0x71, 0xd3, 0x20, 0xd4, 0x3d, 0x6c, 0x49, 0x4c, 0x9e, 0xda, 0x35, 0xcf, 0x9b, 0xf3, - 0x7d, 0xc5, 0x4b, 0x40, 0x2e, 0xb2, 0x87, 0x64, 0xa0, 0xb9, 0x17, 0x6c, 0xf9, 0x49, - 0xb2, 0xa7, 0x78, 0x64, 0x19, 0x83, 0x89, 0x2f, 0xfb, 0x5c, 0x7b, 0xfa, 0x68, 0xe6, - 0x36, 0xde, 0xfe, 0xfc, 0xb2, 0xfa, 0x07, 0x94, 0x45, 0xec, 0xd3, 0xad, 0xdf, 0x0c, - 0x22, 0xb2, 0x61, 0x72, 0x49, 0x92, 0xe2, 0xf0, 0xd2, 0x7c, 0xff, 0x23, 0xa6, 0x46, - 0x15, 0x30, 0xdc, 0x05, 0xf4, 0x9e, 0x97, 0x2d, 0xa3, 0x71, 0x6f, 0x41, 0x91, 0xbf, - 0xf4, 0xed, 0x29, 0x02, 0x67, 0x46, 0xf0, 0x9e, 0xfa, 0x9d, 0xfc, 0xbc, 0xde, 0xc5, - 0xa6, 0x95, 0xb1, 0xf7, 0x31, 0x36, 0x14, 0x64, 0xec, 0x42, 0xe3, 0xb5, 0x26, 0x7e, - 0xb6, 0x5f, 0x55, 0x6b, 0x26, 0x7a, 0xf3, 0x59, 0x71, 0xb4, 0x14, 0x9b, 0xb3, 0xe5, - 0xaa, 0x03, 0xa4, 0x95, 0xfb, 0xeb, 0x90, 0x15, 0xac, 0x3f, 0xf1, 0x3a, 0x5c, 0x1c, - 0x2a, 0x5f, 0x81, 0x96, 0x47, 0x3d, 0x5b, 0xfe, 0x70, 0x48, 0xdf, 0x27, 0x7f, 0x0b, - 0x5c, 0xf4, 0xe6, 0xc7, 0x1c, 0xa9, 0x36, 0x6e, 0xca, 0x3b, 0x9c, 0xf1, 0xe6, 0x06, - 0x9d, 0x53, 0x9e, 0x5c, 0xe4, 0x3f, 0xd9, 0xaa, 0x25, 0xc2, 0x11, 0xd3, 0x79, 0x92, - 0xc3, 0x40, 0xad, 0xea, 0x8b, 0x24, 0x9f, 0x28, 0xab, 0x23, 0x49, 0x39, 0x17, 0xc4, - 0x9d, 0xeb, 0x28, 0x3b, 0x4c, 0x8a, 0x64, 0x90, 0x41, 0x88, 0x7e, 0x66, 0x83, 0x8d, - 0x1c, 0x42, 0x9d, 0xec, 0xdb, 0x31, 0x59, 0xcb, 0x30, 0xaf, 0xe4, 0xfb, 0x31, 0x68, - 0xcc, 0xec, 0x44, 0x98, 0x2e, 0x05, 0xf8, 0x71, 0x13, 0x2e, 0xfa, 0x63, 0xd6, 0x5a, - 0x24, 0x93, 0xcd, 0xf2, 0x39, 0xe8, 0xb2, 0xc8, 0x09, 0x05, 0xe8, 0x04, 0xa8, 0x4d, - 0xd7, 0x6a, 0xfe, 0xaa, 0x68, 0x94, 0x79, 0x1d, 0x49, 0xb1, 0xe4, 0x00, 0xb3, 0xfc, - 0xaa, 0x82, 0x73, 0x99, 0x60, 0xad, 0xda, 0x36, 0x45, 0xbb, 0x85, 0x75, 0x6c, 0x63, - 0x00, 0x5c, 0x01, 0x6f, 0x65, 0x8b, 0xa6, 0xab, 0x52, 0x57, 0xc4, 0x86, 0xaf, 0x13, - 0xed, 0xc9, 0xb4, 0x6b, 0xf6, 0x29, 0x34, 0xaa, 0x71, 0x4f, 0x00, 0x36, 0x05, 0x96, - 0x5a, 0xc5, 0x4d, 0x82, 0x50, 0xa5, 0x53, 0x52, 0x00, 0xd1, 0x20, 0x2a, 0xcc, 0xca, - 0xaa, 0x9e, 0x42, 0xea, 0x98, 0x2a, 0x21, 0x61, 0x8e, 0xdb, 0xb1, 0x34, 0xc3, 0x3b, - 0xc8, 0x4e, 0x35, 0xfc, 0x76, 0x56, 0x05, 0x86, 0xa3, 0xc3, 0x43, 0x8e, 0x8f, 0x2b, - 0x0c, 0xe7, 0x0d, 0x86, 0x31, 0x71, 0xdf, 0x23, 0x8e, 0x12, 0x60, 0xd5, 0x9f, 0x82, - 0x40, 0x37, 0xa7, 0x71, 0x7b, 0x2e, 0x21, 0xa9, 0x6e, 0x4d, 0x79, 0x9b, 0x8e, 0xc4, - 0xc9, 0x8b, 0x8d, 0x16, 0x83, 0x6c, 0x18, 0x22, 0xb2, 0x45, 0x62, 0x66, 0x46, 0x59, - 0x86, 0x85, 0x0d, 0x23, 0x31, 0xc7, 0x29, 0x34, 0xbd, 0xb6, 0x71, 0x54, 0xab, 0xa0, - 0xad, 0x49, 0xbe, 0x0e, 0x52, 0xd8, 0xb0, 0x78, 0x41, 0x11, 0x7c, 0x0e, 0xb7, 0x6a, - 0x39, 0x54, 0x96, 0x39, 0xf7, 0xad, 0xe7, 0x6a, 0x90, 0x71, 0x0e, 0x79, 0x83, 0x97, - 0x8e, 0x9b, 0x23, 0x34, 0x9b, 0xee, 0x22, 0xcd, 0x0c, 0x71, 0xa1, 0xf0, 0x72, 0x70, - 0xe2, 0xce, 0x8b, 0x36, 0x05, 0x1b, 0x00, 0x55, 0xba, 0x97, 0x05, 0xab, 0x22, 0x2e, - 0x8e, 0x85, 0x8d, 0xc4, 0x5b, 0x66, 0xc1, 0xef, 0x3f, 0xe2, 0x66, 0x55, 0x03, 0xe7, - 0x8b, 0x30, 0x29, 0xef, 0xfb, 0xd5, 0xbb, 0x13, 0x9e, 0x85, 0x2c, 0x3b, 0xf9, 0x07, - 0x13, 0x2e, 0x54, 0xc3, 0xed, 0xad, 0x03, 0xf7, 0xe8, 0x68, 0xf5, 0x23, 0x15, 0x5f, - 0x9f, 0x6b, 0xce, 0xf4, 0x50, 0xbc, 0x9b, 0x56, 0x31, 0x0c, 0xda, 0x17, 0x3e, 0x50, - 0xe9, 0x5a, 0x6e, 0xe5, 0xf0, 0x68, 0xb2, 0x5e, 0x32, 0x9c, 0x35, 0x48, 0xfc, 0x24, - 0x99, 0x37, 0x3c, 0xde, 0x29, 0x36, 0x0f, 0xbb, 0xfa, 0x5b, 0x64, 0xb5, 0x74, 0x4a, - 0xb0, 0x3a, 0x4b, 0xd5, 0xd9, 0x48, 0xc1, 0xbe, 0xf8, 0xcf, 0x4e, 0x6b, 0xd9, 0x4c, - 0x32, 0x80, 0x9b, 0x18, 0xf1, 0x18, 0x9c, 0x32, 0xbb, 0x8f, 0xae, 0x27, 0x53, 0xe4, - 0x85, 0x1c, 0x31, 0x96, 0xf5, 0xbb, 0x1d, 0xa0, 0x78, 0x51, 0xb5, 0xd3, 0x1f, 0x20, - 0xa0, 0xfd, 0x3a, 0x7a, 0x4b, 0x45, 0x01, 0xf3, 0x18, 0x5d, 0x26, 0x7b, 0x1c, 0x8b, - 0xb3, 0x59, 0x5d, 0x85, 0xc5, 0x3c, 0xae, 0x18, 0x9e, 0xc9, 0xdb, 0x6f, 0x14, 0x53, - 0xb3, 0xc6, 0xad, 0x4f, 0x3b, 0x93, 0xdd, 0x10, 0x6a, 0x3a, 0x39, 0x0d, 0xb2, 0x7a, - 0x1a, 0x75, 0x0e, 0x7e, 0xd0, 0x89, 0x7e, 0xbb, 0x61, 0x98, 0x48, 0x4d, 0xcc, 0xdf, - 0xa7, 0xa7, 0xe1, 0xd8, 0xeb, 0x2f, 0x23, 0x66, 0x8d, 0x54, 0xe9, 0x8f, 0x9e, 0xd3, - 0xae, 0x90, 0xfe, 0x0c, 0x27, 0x5f, 0x17, 0x7e, 0xcf, 0x70, 0x1f, 0xd3, 0x0b, 0x92, - 0xf6, 0x1b, 0x3c, 0x12, 0x53, 0xcc, 0x31, 0x78, 0x95, 0xfe, 0x5e, 0x39, 0xc4, 0xea, - 0x03, 0x24, 0x8e, 0x83, 0x20, 0x2e, 0xa5, 0x89, 0xa0, 0xe8, 0xfc, 0xaf, 0xc4, 0x34, - 0x07, 0xb5, 0x71, 0x9c, 0x08, 0x6a, 0xc2, 0xf5, 0x8c, 0x1c, 0x4e, 0x05, 0x63, 0x69, - 0x56, 0xb6, 0x30, 0x4e, 0x31, 0x7f, 0x4f, 0x65, 0xb4, 0xe2, 0xb9, 0x9f, 0x25, 0xe8, - 0xd7, 0xbb, 0x53, 0x28, 0xea, 0x1f, 0x31, 0x13, 0x25, 0x6a, 0x45, 0x08, 0x01, 0x6a, - 0x3e, 0x9d, 0x01, 0x2e, 0xf8, 0x19, 0xfa, 0x36, 0xa5, 0xdb, 0xce, 0x7e, 0x3a, 0xff, - 0x47, 0x42, 0xc0, 0xcd, 0x3d, 0x5d, 0x9e, 0xb8, 0x40, 0x44, 0xa0, 0x03, 0x23, 0x39, - 0x40, 0x69, 0x9b, 0xc2, 0x79, 0x45, 0xb9, 0xac, 0x93, 0x82, 0x23, 0xc1, 0x17, 0x3f, - 0x34, 0xd1, 0x7e, 0x7e, 0x2e, 0x7b, 0xbc, 0xad, 0x2d, 0x91, 0x9d, 0x1a, 0xf5, 0x54, - 0x94, 0x0b, 0x68, 0xd7, 0x43, 0x3a, 0x6d, 0x67, 0xe8, 0x5c, 0xd3, 0x35, 0x66, 0xb0, - 0x60, 0xe4, 0x48, 0xb4, 0xa2, 0xa0, 0x52, 0xa8, 0xb7, 0x9e, 0x27, 0x57, 0x8d, 0xce, - 0x6e, 0x09, 0x88, 0x6e, 0xf0, 0x92, 0xef, 0x09, 0x67, 0x97, 0x47, 0x8b, 0xb5, 0x4b, - 0x9a, 0xbb, 0xa5, 0xae, 0x26, 0x79, 0x9b, 0x07, 0xcd, 0xc8, 0x8c, 0x80, 0x2e, 0x6a, - 0xf5, 0xcb, 0xfd, 0x41, 0x24, 0x29, 0x57, 0x00, 0xac, 0x12, 0xd9, 0x10, 0xa0, 0x2a, - 0x74, 0xc8, 0xab, 0xd2, 0x4d, 0x39, 0x88, 0x72, 0xdd, 0x9d, 0x3a, 0xb3, 0xc5, 0x4c, - 0x63, 0xa0, 0x9e, 0x51, 0xbb, 0x51, 0x62, 0x54, 0x01, 0x03, 0xab, 0x0c, 0xae, 0xfc, - 0x6e, 0x5b, 0x88, 0x05, 0x21, 0xf4, 0x9c, 0x55, 0x93, 0xa7, 0xec, 0xe1, 0xef, 0xdc, - 0x00, 0xad, 0x96, 0xc3, 0x82, 0xfe, 0xcf, 0x0f, 0x9c, 0x1c, 0x8e, 0xcd, 0xcb, 0xc2, - 0x2e, 0x89, 0x07, 0xce, 0x99, 0xdf, 0x99, 0x4a, 0x33, 0x0a, 0x90, 0x44, 0x6d, 0xae, - 0xec, 0xab, 0x71, 0xf0, 0x02, 0x35, 0xdd, 0x70, 0x23, 0x3c, 0x43, 0x17, 0xd6, 0x4e, - 0xf6, 0xba, 0x3f, 0x65, 0x76, 0x42, 0xba, 0xad, 0x97, 0x35, 0xe5, 0x48, 0x68, 0xc1, - 0x97, 0x54, 0x56, 0x89, 0xa0, 0x57, 0x0b, 0xd4, 0x58, 0x4a, 0xad, 0xe4, 0x1a, 0x59, - 0x08, 0xb8, 0xaa, 0x33, 0x54, 0x95, 0x72, 0xc7, 0x20, 0x9f, 0x63, 0xad, 0x0b, 0x80, - 0x4c, 0x76, 0x02, 0xf4, 0x8d, 0xed, 0x66, 0x8c, 0x31, 0xa0, 0x7d, 0x76, 0x02, 0xd6, - 0xf8, 0x24, 0x29, 0xc3, 0xd2, 0xde, 0xe9, 0x2f, 0x38, 0xdb, 0x5b, 0x92, 0x03, 0xac, - 0x84, 0xd0, 0xfe, 0x14, 0xba, 0x6a, 0xc1, 0x9a, 0xaf, 0x94, 0x00, 0xf2, 0xe3, 0x58, - 0x3f, 0xb1, 0x68, 0xd3, 0x03, 0xca, 0x7a, 0x88, 0x71, 0xdd, 0xd9, 0xa2, 0x95, 0x04, - 0x1b, 0x30, 0xb8, 0x1e, 0xea, 0x1e, 0x7d, 0x82, 0x24, 0x34, 0x4b, 0xd2, 0x68, 0xa9, - 0x4a, 0x11, 0x1e, 0xa7, 0xc9, 0xb0, 0x6e, 0xc5, 0x69, 0x12, 0x45, 0x2e, 0xeb, 0x01, - 0xcf, 0x88, 0x87, 0xa3, 0xe2, 0x6e, 0x14, 0x40, 0x6f, 0xfe, 0xec, 0x4b, 0xfd, 0x7a, - 0x9f, 0xd8, 0x77, 0xce, 0x52, 0x03, 0xfe, 0x6b, 0x05, 0x8d, 0x23, 0x1e, 0xc7, 0x1a, - 0xf9, 0xca, 0x18, 0xed, 0x5c, 0x73, 0x55, 0x06, 0xd7, 0xba, 0x28, 0xee, 0x68, 0xee, - 0x66, 0x58, 0x7c, 0x99, 0x8c, 0x8f, 0xec, 0xa7, 0xae, 0x06, 0x8c, 0x8e, 0xd0, 0x79, - 0xe5, 0xa9, 0xa4, 0x36, 0x72, 0x8c, 0xce, 0xe1, 0x0c, 0x8f, 0x12, 0x6f, 0x7b, 0x2f, - 0xa0, 0xd0, 0xff, 0x91, 0xcc, 0x41, 0xee, 0x28, 0xa1, 0x96, 0x23, 0x03, 0x37, 0xc6, - 0x1f, 0x42, 0xe9, 0x52, 0x2b, 0xf6, 0xde, 0x64, 0xfc, 0x5a, 0x57, 0xe3, 0x74, 0x77, - 0x06, 0x07, 0x63, 0x0b, 0xc1, 0x96, 0xed, 0x05, 0x2d, 0xff, 0x00, 0x83, 0x61, 0xfc, - 0x59, 0xfd, 0x9c, 0x48, 0xd2, 0x62, 0xb9, 0x3a, 0xee, 0x45, 0x65, 0x2c, 0x78, 0x78, - 0x05, 0xdf, 0xac, 0xe8, 0x3d, 0x04, 0xe5, 0x24, 0x40, 0x3a, 0x25, 0xa1, 0x66, 0xa1, - 0xf4, 0x8e, 0xcc, 0x8f, 0xff, 0x84, 0x4f, 0x09, 0xde, 0x67, 0x48, 0x04, 0x52, 0xa6, - 0x78, 0x9d, 0x48, 0xb7, 0xbd, 0xbd, 0x81, 0x1f, 0x0e, 0xda, 0xda, 0xa8, 0xee, 0x8e, - 0xb9, 0x16, 0x17, 0x99, 0x2e, 0xad, 0x6f, 0x8a, 0x8b, 0x9e, 0xf4, 0xc5, 0xad, 0xb6, - 0xf2, 0x52, 0x48, 0xb2, 0x13, 0xf3, 0xd6, 0x93, 0xf6, 0x3c, 0x0d, 0x5d, 0x15, 0xab, - 0x54, 0x32, 0x88, 0x07, 0x14, 0x27, 0x35, 0x79, 0x37, 0x3c, 0x49, 0xcb, 0xf1, 0x47, - 0xf9, 0x4a, 0x84, 0xad, 0xe6, 0x48, 0x49, 0xeb, 0x5a, 0x94, 0x04, 0x40, 0x13, 0x38, - 0x96, 0xa2, 0x45, 0x55, 0xe4, 0x01, 0x55, 0x99, 0xc0, 0x46, 0xdf, 0xa6, 0xf1, 0x4a, - 0x28, 0x70, 0x53, 0x3a, 0xe4, 0x7d, 0x33, 0xff, 0x81, 0x6b, 0x8e, 0x46, 0x63, 0xf0, - 0x70, 0xc8, 0x0d, 0x8d, 0xb0, 0x1b, 0x43, 0xc6, 0x0f, 0x5f, 0xc0, 0x2c, 0x85, 0xac, - 0xf5, 0xe1, 0x06, 0xd3, 0xba, 0x71, 0xea, 0x69, 0x3b, 0xa4, 0x65, 0xdd, 0x61, 0xff, - 0x1d, 0x80, 0xfe, 0xee, 0xa1, 0xb6, 0xd5, 0xa1, 0x63, 0xd0, 0xc9, 0x62, 0x43, 0x16, - 0x36, 0xe1, 0xed, 0x62, 0x19, 0x66, 0xfe, 0x28, 0x5b, 0xc9, 0x70, 0xa2, 0x66, 0xbb, - 0x40, 0x8d, 0x4d, 0x48, 0xd5, 0x5e, 0xf7, 0x17, 0x04, 0xf5, 0xb7, 0x98, 0x62, 0xbd, - 0x80, 0x6a, 0x6a, 0x33, 0xe1, 0x13, 0xb1, 0x88, 0x32, 0xb3, 0xd5, 0x9e, 0x3a, 0x69, - 0x84, 0xe1, 0x4f, 0xd5, 0x2a, 0xc9, 0xd2, 0xbe, 0x3a, 0xea, 0xaa, 0xbf, 0x38, 0x29, - 0xcb, 0xf4, 0xdf, 0xca, 0x68, 0x03, 0xaf, 0xcd, 0x1f, 0xc4, 0xcd, 0x02, 0x44, 0xd7, - 0xb6, 0x3b, 0x4c, 0x9d, 0x4a, 0xa1, 0xa2, 0x27, 0xad, 0xda, 0x80, 0x6a, 0x46, 0x24, - 0xa0, 0x79, 0x65, 0xb9, 0xfd, 0xa1, 0x73, 0xa2, 0xd9, 0x9a, 0x62, 0x4f, 0x4a, 0x78, - 0xe9, 0xc7, 0x17, 0x63, 0x01, 0x2b, 0x77, 0xaf, 0x32, 0x6c, 0x75, 0x22, 0x6b, 0x7d, - 0xe8, 0x29, 0x74, 0x4b, 0x6d, 0x39, 0x72, 0xe4, 0x7f, 0x6a, 0x14, 0x5b, 0x81, 0x34, - 0x0d, 0x27, 0x16, 0x20, 0x1e, 0x07, 0x1e, 0x47, 0x1a, 0x85, 0x5e, 0x9c, 0xc3, 0x6d, - 0x39, 0x49, 0x97, 0x15, 0x74, 0xbf, 0x3a, 0x06, 0x0f, 0xc0, 0xd8, 0x82, 0xd0, 0xa9, - 0x86, 0x5c, 0x24, 0xe0, 0x94, 0x03, 0x17, 0x30, 0xcb, 0xe1, 0x88, 0xe6, 0xfd, 0xaf, - 0xcb, 0xba, 0xf7, 0x51, 0xbe, 0x87, 0xaf, 0x96, 0x5c, 0xd9, 0x8d, 0x99, 0x31, 0x04, - 0xca, 0x6e, 0xdd, 0x29, 0x28, 0x0c, 0xda, 0x86, 0x55, 0x67, 0xbd, 0xd4, 0xb4, 0xba, - 0x47, 0x37, 0xe6, 0x1c, 0x3f, 0x0a, 0xd8, 0x75, 0xa8, 0xde, 0xe6, 0xe6, 0xcd, 0xff, - 0x26, 0x81, 0x88, 0x08, 0xff, 0x9b, 0x2d, 0x55, 0x87, 0x95, 0xd6, 0x5d, 0x2a, 0x95, - 0xb4, 0x56, 0x56, 0x19, 0xf7, 0xb2, 0x41, 0x62, 0xcc, 0x47, 0x59, 0x9a, 0x33, 0x13, - 0x06, 0xe3, 0x65, 0x2f, 0xfb, 0xc3, 0xb3, 0xfd, 0x06, 0xc1, 0x46, 0x0c, 0x80, 0x6f, - 0x4e, 0x61, 0xbe, 0xc2, 0xa2, 0xa7, 0xb6, 0xc7, 0x96, 0xf6, 0x5d, 0xcf, 0x36, 0xa4, - 0xaf, 0xc6, 0xd8, 0x10, 0x09, 0x35, 0x21, 0x0a, 0x86, 0x38, 0x9f, 0x24, 0x9e, 0x2f, - 0x82, 0x32, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x8b, 0x33, 0x6b, 0x5f, 0x55, 0x40, 0x0b, 0x06, - 0x79, 0xba, 0x0c, 0x1e, 0xf0, 0x20, 0xc9, 0x26, 0x85, 0xa4, 0x24, 0x91, 0x79, 0x95, - 0xea, 0x63, 0xad, 0x1d, 0x5e, 0x28, 0xdd, 0x63, 0x99, 0x83, 0x82, 0xc7, 0xb3, 0x9d, - 0x26, 0xdb, 0x80, 0xb4, 0x3e, 0x32, 0x4f, 0xaf, 0x5d, 0x63, 0x60, 0x4a, 0x84, 0xf2, - 0x13, 0x5c, 0xbf, 0xf5, 0x98, 0xeb, 0x50, 0xe1, 0xd3, 0xa4, 0xb9, 0x9c, 0xd6, 0x6c, - 0x7a, 0xfd, 0xe6, 0x7f, 0xac, 0x47, 0xf0, 0x35, 0x8e, 0xc7, 0x83, 0xbe, 0x35, 0x95, - 0x47, 0x96, 0xe5, 0x97, 0x3a, 0xcf, 0xf6, 0x31, 0x98, 0xa3, 0x55, 0x94, 0x18, 0x7e, - 0xf8, 0x17, 0x00, 0x0b, 0x08, 0x88, 0x1e, 0x70, 0xe0, 0xb2, 0xcd, 0xe2, 0x31, 0x51, - 0x79, 0xc0, 0x84, 0x15, 0x51, 0xe8, 0xbd, 0x92, 0x8e, 0xb6, 0x24, 0x87, 0x6e, 0x86, - 0xb0, 0xb3, 0x3a, 0xab, 0x0c, 0xde, 0x87, 0xeb, 0x8f, 0xd4, 0x78, 0x8d, 0xe9, 0xfb, - 0x37, 0xea, 0xb3, 0xb4, 0x7f, 0xd5, 0xdf, 0xe9, 0xb3, 0x7b, 0xcb, 0xb6, 0xe1, 0xf2, - 0x25, 0xfd, 0x29, 0xab, 0x07, 0xfc, 0x9f, 0xf5, 0xa0, 0x8f, 0x48, 0x66, 0x9e, 0x1c, - 0x99, 0x68, 0xf5, 0x21, 0x7a, 0xd3, 0x45, 0x2d, 0xad, 0x04, 0x78, 0x39, 0x07, 0x44, - 0xe9, 0xd1, 0x67, 0x85, 0xcd, 0x54, 0xa5, 0x03, 0x98, 0xb0, 0x14, 0xa0, 0x7b, 0x78, - 0x45, 0x99, 0x7a, 0x5b, 0x11, 0x6b, 0xb2, 0xc2, 0xf4, 0xc4, 0xe5, 0x64, 0x6e, 0x63, - 0x08, 0x2c, 0x5e, 0x3f, 0xee, 0x50, 0x92, 0xff, 0x2f, 0xa8, 0x9a, 0xe3, 0x2a, 0xd6, - 0x99, 0x07, 0x50, 0x4d, 0x68, 0x85, 0xb5, 0xbd, 0x72, 0xc8, 0x23, 0xd4, 0xc7, 0x0d, - 0x5e, 0xd4, 0x5c, 0xb0, 0x0c, 0x3e, 0x04, 0x05, 0x89, 0x2c, 0x88, 0x83, 0x74, 0x53, - 0xfe, 0xf2, 0xef, 0xb7, 0x51, 0x37, 0xf3, 0xc2, 0xab, 0xbc, 0x35, 0x47, 0xdf, 0x86, - 0xee, 0x01, 0x36, 0xb6, 0xe8, 0x5f, 0x33, 0xc5, 0x25, 0x58, 0x3f, 0xfe, 0x27, 0xe6, - 0xff, 0x48, 0xa8, 0x0d, 0x12, 0x4e, 0xf8, 0x01, 0xd3, 0x24, 0x75, 0x4e, 0x16, 0x1d, - 0x8b, 0xd6, 0x77, 0x44, 0xdf, 0x8a, 0xc5, 0x84, 0x9b, 0x65, 0x5a, 0xcf, 0x9f, 0xa7, - 0xb2, 0xea, 0x84, 0x62, 0x1d, 0x8e, 0x4d, 0xd8, 0x57, 0x6d, 0xa7, 0x5e, 0xd1, 0xb4, - 0x8a, 0xcb, 0x91, 0x08, 0x03, 0x27, 0x3e, 0x48, 0x37, 0x73, 0xa9, 0x9d, 0x58, 0xcb, - 0x70, 0x40, 0x8f, 0x3f, 0x23, 0xa3, 0xea, 0x71, 0xd6, 0x73, 0x23, 0xb8, 0xf9, 0xfd, - 0x51, 0x93, 0xb8, 0xdb, 0x90, 0x6a, 0x18, 0x86, 0xe4, 0x26, 0xd0, 0xd3, 0x21, 0x6e, - 0x7f, 0x0f, 0x42, 0xa9, 0xaa, 0xe0, 0x0f, 0xc3, 0x79, 0x12, 0x20, 0xdb, 0xb1, 0x03, - 0x15, 0x19, 0xbc, 0x1e, 0xcc, 0xf8, 0x29, 0x8a, 0x22, 0xab, 0x20, 0x92, 0x71, 0x65, - 0xaa, 0x95, 0xd5, 0x46, 0x88, 0x83, 0x48, 0x17, 0x58, 0x3c, 0x64, 0x90, 0x28, 0x77, - 0x34, 0xea, 0x30, 0x0c, 0x38, 0x94, 0xf9, 0x9b, 0xaa, 0x29, 0xee, 0x97, 0x50, 0x9d, - 0x1c, 0x10, 0x71, 0xf2, 0x17, 0x42, 0xba, 0x67, 0x13, 0xed, 0xa0, 0x20, 0x38, 0x1e, - 0x60, 0x98, 0xb0, 0x5a, 0xde, 0x28, 0x09, 0x63, 0xb3, 0x98, 0xc0, 0x3b, 0xf4, 0xc4, - 0xe1, 0xf1, 0x9a, 0xd1, 0xad, 0xf1, 0xf0, 0xd6, 0x1f, 0xac, 0xbf, 0x99, 0x66, 0xbd, - 0xb0, 0x1f, 0xd1, 0x84, 0xb2, 0x00, 0xf8, 0x66, 0xc5, 0xd1, 0x2e, 0x3d, 0xc5, 0x7e, - 0xcf, 0x4f, 0xcd, 0x60, 0xc4, 0xa7, 0x56, 0x19, 0x1d, 0xcf, 0x50, 0xbb, 0x0f, 0x97, - 0x6f, 0x00, 0xe4, 0x36, 0x36, 0xa6, 0x83, 0x08, 0x69, 0x2f, 0x40, 0x24, 0x4c, 0x39, - 0x15, 0x34, 0x4b, 0x6f, 0x1f, 0x5e, 0xe7, 0x0e, 0x51, 0xe1, 0x2b, 0x28, 0x53, 0x85, - 0x53, 0x40, 0x3b, 0xe1, 0x49, 0x8e, 0x00, 0x75, 0xdb, 0xda, 0x3e, 0x66, 0x6d, 0x9e, - 0xbd, 0x18, 0xa1, 0x27, 0x21, 0xc9, 0x73, 0x49, 0xac, 0x10, 0xe8, 0xfa, 0x2d, 0x6a, - 0x59, 0xb2, 0x23, 0x56, 0xa7, 0x71, 0x96, 0x18, 0xaa, 0xb5, 0xc7, 0x57, 0xf8, 0x82, - 0x1e, 0xfc, 0x3e, 0x07, 0x1b, 0x75, 0xf2, 0x15, 0xb2, 0x00, 0xb7, 0xd2, 0x99, 0x98, - 0xed, 0x7a, 0xe0, 0x05, 0x7f, 0xb2, 0x32, 0x9c, 0xa9, 0x13, 0x6d, 0xd2, 0xbc, 0x51, - 0xa6, 0x59, 0x01, 0x71, 0xdf, 0xca, 0x3b, 0xcb, 0x93, 0x6b, 0x11, 0xc6, 0x3c, 0x03, - 0xbb, 0x7f, 0xce, 0x30, 0xa0, 0x5f, 0x9b, 0x6f, 0x8f, 0xf3, 0x54, 0x06, 0x04, 0x50, - 0xa3, 0x45, 0x2d, 0xa1, 0x86, 0xe9, 0x3d, 0x6c, 0x32, 0xda, 0x62, 0x72, 0xb8, 0x9b, - 0xc4, 0xd6, 0xd5, 0xe8, 0x47, 0x8f, 0x29, 0x91, 0x01, 0x98, 0x97, 0x11, 0xa9, 0xd2, - 0x20, 0x97, 0xcd, 0xb7, 0x0c, 0x15, 0x0e, 0xd2, 0x6d, 0xf4, 0x7b, 0x0c, 0xdd, 0xee, - 0x52, 0x1b, 0x4f, 0x1e, 0x98, 0x96, 0xa1, 0xb6, 0x97, 0x86, 0x53, 0xa4, 0xe3, 0x8b, - 0x0d, 0x28, 0x52, 0x6e, 0x1e, 0x3a, 0x87, 0x43, 0x5a, 0xc4, 0xfd, 0x30, 0x97, 0xaf, - 0xe3, 0x21, 0xe7, 0x2d, 0x40, 0xc4, 0x70, 0xf3, 0xb5, 0x3f, 0x5c, 0x35, 0x8d, 0x2e, - 0x53, 0x69, 0x7c, 0xaf, 0x66, 0x9d, 0xea, 0xa1, 0x1d, 0xe7, 0x7c, 0x98, 0x4a, 0x73, - 0x0e, 0x5b, 0xf7, 0xb3, 0x8e, 0xf6, 0x58, 0x9a, 0x5a, 0xa7, 0x55, 0x81, 0xbf, 0xd3, - 0xc0, 0x07, 0x8a, 0x63, 0xa3, 0x92, 0x96, 0x0e, 0xc3, 0xf2, 0xa0, 0x5c, 0x08, 0x1a, - 0x48, 0x4e, 0xb4, 0xf4, 0x25, 0xb7, 0x08, 0x36, 0x0f, 0x82, 0x85, 0x3c, 0xfd, 0x50, - 0xa0, 0x27, 0xfa, 0x92, 0x51, 0x76, 0x86, 0x96, 0xf3, 0x73, 0x5c, 0xd9, 0xed, 0xf7, - 0x9e, 0xcd, 0x4b, 0xe0, 0x8c, 0x57, 0x85, 0xc8, 0xae, 0xe7, 0x9a, 0x13, 0x23, 0x87, - 0x09, 0x94, 0x2f, 0x2c, 0xfd, 0x0f, 0x80, 0x7d, 0xaa, 0xb5, 0x0c, 0xc6, 0x13, 0x1b, - 0xab, 0x91, 0x25, 0x67, 0x36, 0x27, 0xf5, 0xe9, 0xa3, 0xd5, 0x3d, 0x99, 0xfa, 0x02, - 0x5c, 0x39, 0xfa, 0xb0, 0x9e, 0x2a, 0x21, 0x34, 0x6d, 0xc7, 0xf8, 0x60, 0xa6, 0x2d, - 0xd2, 0x10, 0x8e, 0x04, 0x41, 0x17, 0x8e, 0xf9, 0x76, 0x21, 0xae, 0xfc, 0xe8, 0x97, - 0x28, 0x10, 0xa4, 0xc7, 0xfc, 0x1b, 0x3c, 0x7e, 0xaa, 0x83, 0xd4, 0xa6, 0x2b, 0xd7, - 0x10, 0x98, 0x96, 0x11, 0xdd, 0x7e, 0x2f, 0x4b, 0xdf, 0x15, 0xd8, 0x31, 0x00, 0x60, - 0x11, 0xb4, 0x4e, 0xd9, 0x59, 0xdc, 0x61, 0xd8, 0xde, 0x52, 0x74, 0x5e, 0x30, 0x67, - 0x9c, 0xef, 0x04, 0x01, 0x3a, 0xc6, 0x15, 0x4e, 0xf0, 0x64, 0x69, 0x82, 0x38, 0x74, - 0x25, 0x21, 0x62, 0x26, 0x3f, 0x3a, 0x4b, 0xa5, 0x65, 0x7b, 0x8d, 0x0e, 0xcf, 0x03, - 0x86, 0x44, 0x1f, 0x87, 0x30, 0xd0, 0xf1, 0x4e, 0x86, 0x8a, 0x32, 0x46, 0x37, 0xb0, - 0xd3, 0x4a, 0x9d, 0x1d, 0xd6, 0xc3, 0x9f, 0x28, 0xfd, 0x9a, 0xf3, 0x50, 0xdc, 0x23, - 0x93, 0x79, 0x29, 0xe3, 0x79, 0x70, 0xf8, 0x87, 0x37, 0x01, 0xd3, 0xfa, 0x47, 0x10, - 0x10, 0xa7, 0x21, 0x40, 0x68, 0xad, 0x1b, 0x89, 0x02, 0x52, 0x26, 0x1d, 0xd9, 0x0d, - 0x89, 0xc5, 0xa6, 0xf2, 0x90, 0x4b, 0xc6, 0x16, 0xb0, 0x27, 0xd7, 0xbe, 0xc8, 0x79, - 0xb7, 0xa1, 0x78, 0x25, 0x4f, 0xdc, 0xaa, 0x99, 0x1b, 0x42, 0x2b, 0x7a, 0x96, 0x93, - 0xe7, 0x64, 0xa1, 0x27, 0xb1, 0x72, 0xa0, 0xdc, 0xca, 0xc4, 0x4f, 0x15, 0x27, 0x08, - 0x6c, 0x48, 0x89, 0x85, 0xf9, 0x23, 0x5e, 0x28, 0x82, 0xb4, 0x78, 0x16, 0x44, 0xeb, - 0xa9, 0xed, 0x09, 0x61, 0xca, 0x7a, 0x68, 0x45, 0xb5, 0x73, 0x65, 0xd8, 0x75, 0x4b, - 0xdc, 0x79, 0x1f, 0x81, 0xc8, 0x09, 0xd0, 0x12, 0xbd, 0x32, 0x9b, 0x6a, 0x44, 0xbd, - 0x3d, 0xfa, 0x34, 0x73, 0x5c, 0xe4, 0xc7, 0x38, 0xed, 0xef, 0xa4, 0x2d, 0x3c, 0x74, - 0x09, 0x2b, 0x5c, 0xba, 0x9c, 0x35, 0x81, 0x57, 0xd2, 0xab, 0x8a, 0x68, 0x83, 0x04, - 0x0f, 0x40, 0xce, 0xc7, 0x98, 0xa6, 0x9d, 0x7e, 0x0e, 0xa3, 0xb4, 0x76, 0xd9, 0x93, - 0xd6, 0x96, 0xdb, 0x0a, 0xdd, 0xd5, 0x43, 0x3f, 0x9e, 0x7a, 0x0f, 0xfb, 0xe0, 0x24, - 0x26, 0x1e, 0x79, 0x8d, 0xad, 0x05, 0x8e, 0xc8, 0xde, 0x26, 0x7c, 0x94, 0x78, 0xc8, - 0x01, 0xff, 0x37, 0x1e, 0x41, 0xc0, 0xbc, 0x0c, 0xf4, 0x6a, 0x4a, 0x84, 0xd0, 0xac, - 0xa4, 0x73, 0xe8, 0x80, 0xde, 0x96, 0x29, 0x69, 0xe9, 0xde, 0x23, 0x99, 0xa2, 0x99, - 0x56, 0x80, 0xdd, 0x76, 0x8f, 0xd7, 0x6b, 0xc6, 0x89, 0x6f, 0xe0, 0x2a, 0xa4, 0x82, - 0xf7, 0x6c, 0x72, 0x52, 0xe6, 0x65, 0x04, 0xe8, 0x80, 0xd2, 0x76, 0xbf, 0x7d, 0x55, - 0x7b, 0x39, 0x6a, 0xde, 0x3b, 0xb4, 0x7a, 0x6b, 0x0e, 0x0d, 0xcf, 0x06, 0x3b, 0x1a, - 0xd8, 0x56, 0x69, 0x4f, 0x8e, 0xef, 0x54, 0xca, 0x7d, 0xf4, 0x2b, 0x41, 0xf9, 0xc6, - 0x15, 0x3e, 0xa7, 0x47, 0x1c, 0xd5, 0x4f, 0x90, 0x54, 0x7c, 0xc4, 0xd4, 0xef, 0x5f, - 0xb1, 0xbf, 0xe5, 0x82, 0x88, 0x22, 0x59, 0xc7, 0x77, 0xef, 0xc4, 0xeb, 0x8f, 0x5d, - 0x75, 0x53, 0x1c, 0x1b, 0x80, 0x1b, 0x72, 0x12, 0xc6, 0xf1, 0x45, 0x09, 0x78, 0x40, - 0x20, 0xcb, 0xc3, 0xb0, 0x0e, 0xb5, 0x31, 0xc5, 0x62, 0x44, 0x36, 0x89, 0x28, 0xa8, - 0x51, 0xae, 0x53, 0x7c, 0x74, 0x80, 0xee, 0x6e, 0x45, 0x1b, 0x29, 0x74, 0x32, 0xee, - 0x17, 0x58, 0x22, 0x99, 0x50, 0xcf, 0x78, 0x08, 0x49, 0x32, 0x6c, 0x3f, 0x28, 0xdd, - 0x53, 0xd6, 0x81, 0x19, 0xd2, 0x96, 0x95, 0x50, 0x12, 0xa2, 0x6f, 0x83, 0x3c, 0xdd, - 0x29, 0xc6, 0xf4, 0xc7, 0x16, 0xf1, 0xd3, 0x37, 0xd3, 0xf4, 0xd2, 0x1c, 0x7a, 0x63, - 0xf8, 0x54, 0xc9, 0xf4, 0xc1, 0xc4, 0xcc, 0xf1, 0x81, 0xad, 0x43, 0x16, 0xca, 0xb1, - 0x36, 0x46, 0x7c, 0x01, 0xd9, 0x6d, 0x36, 0xe2, 0x98, 0x1c, 0x86, 0xc4, 0x76, 0x56, - 0x7d, 0x83, 0x77, 0x6b, 0x73, 0x37, 0x35, 0xd5, 0x65, 0x8a, 0x48, 0xf9, 0x89, 0x7c, - 0xf1, 0xe5, 0x05, 0x2b, 0x37, 0xec, 0x1c, 0x88, 0x91, 0x47, 0x36, 0xd9, 0xf9, 0x7c, - 0x54, 0x99, 0xd7, 0x3d, 0x92, 0x3b, 0x45, 0x00, 0x69, 0x4f, 0xfa, 0x57, 0x35, 0xc9, - 0x3c, 0xdb, 0x87, 0xb3, 0x5d, 0x82, 0x95, 0x49, 0xb1, 0xc6, 0x38, 0x3e, 0x95, 0xfd, - 0x19, 0x02, 0xad, 0x29, 0x80, 0xf2, 0xa3, 0xa2, 0x48, 0x3a, 0xce, 0x74, 0xb7, 0x64, - 0x3d, 0x8e, 0xae, 0x8d, 0x07, 0x9a, 0xa0, 0x06, 0x75, 0x41, 0x00, 0x6b, 0x94, 0xa6, - 0xf9, 0x13, 0xdc, 0xff, 0x13, 0xd6, 0x7c, 0xd9, 0xa8, 0xcf, 0xdf, 0x30, 0xb0, 0xc3, - 0xd1, 0x5a, 0xaa, 0x47, 0x0b, 0x3f, 0x89, 0x56, 0x10, 0x51, 0x42, 0xfa, 0x26, 0x11, - 0xfe, 0xda, 0xa4, 0x3f, 0xac, 0xbb, 0x3f, 0x05, 0x96, 0xf6, 0x78, 0x87, 0xcd, 0xee, - 0x91, 0x42, 0xc5, 0x09, 0x0a, 0x84, 0xe6, 0x25, 0x29, 0x31, 0xff, 0xcf, 0x61, 0xa5, - 0x0a, 0x4b, 0x92, 0x85, 0x30, 0x60, 0xe8, 0xb8, 0x7e, 0x10, 0xce, 0xa8, 0xce, 0x00, - 0xe4, 0x66, 0x5e, 0x5f, 0x93, 0x1f, 0x0e, 0x08, 0xdc, 0x52, 0x47, 0xbe, 0x1a, 0xed, - 0xc7, 0x9e, 0xbb, 0x7c, 0x20, 0x16, 0x2f, 0xca, 0x7b, 0xf9, 0x0e, 0x58, 0x83, 0x02, - 0x5f, 0xc9, 0x24, 0x36, 0x8d, 0x42, 0x45, 0x0b, 0x4f, 0xb7, 0xa7, 0xe1, 0x91, 0x0e, - 0xdd, 0x8d, 0x29, 0x5f, 0x03, 0xd4, 0xde, 0x03, 0xde, 0x60, 0x51, 0xd1, 0xfc, 0xf2, - 0x87, 0xf5, 0x4f, 0x38, 0x24, 0x41, 0xdd, 0xe0, 0x0c, 0xb6, 0x83, 0xa4, 0x04, 0x8c, - 0xe5, 0x4d, 0x42, 0x20, 0x90, 0x57, 0x24, 0xb3, 0x09, 0xc7, 0x99, 0x92, 0x4b, 0x85, - 0x4a, 0xfa, 0x37, 0x7b, 0x80, 0x1a, 0x03, 0x52, 0xfc, 0x44, 0x50, 0xb3, 0x35, 0x27, - 0x7a, 0xda, 0xd7, 0x61, 0xe4, 0x8a, 0x1d, 0x1d, 0xd3, 0x78, 0x93, 0x6a, 0x49, 0x1e, - 0x28, 0x6c, 0xaf, 0xc7, 0x00, 0xb4, 0x8e, 0xdf, 0x15, 0xf1, 0xc2, 0xd6, 0xed, 0xf1, - 0xa2, 0x4e, 0x0e, 0x51, 0xb3, 0x98, 0x55, 0x64, 0xeb, 0xa9, 0x69, 0xcd, 0x6e, 0xe6, - 0x59, 0xba, 0xae, 0xf7, 0x46, 0xe1, 0x3a, 0xba, 0x64, 0xaf, 0xad, 0x58, 0xaf, 0x52, - 0xf4, 0x28, 0x17, 0x36, 0x45, 0x75, 0x7a, 0x40, 0x7e, 0x1f, 0xdf, 0xd9, 0x89, 0x38, - 0x0c, 0x02, 0xbc, 0xc3, 0xc3, 0x7f, 0x48, 0x90, 0xc0, 0x8e, 0xb9, 0x31, 0x62, 0xcf, - 0x78, 0xbc, 0x3c, 0x74, 0x53, 0xf3, 0xf9, 0x92, 0xa7, 0x94, 0x53, 0x4c, 0x07, 0xe3, - 0x96, 0x8d, 0x82, 0x70, 0xaa, 0x19, 0x1f, 0x67, 0x80, 0x0a, 0x0b, 0xb3, 0xe7, 0xbf, - 0xa5, 0x4b, 0x0f, 0x6f, 0xa5, 0x3e, 0xe8, 0xfb, 0x13, 0x69, 0x82, 0xce, 0x71, 0xf4, - 0x08, 0x64, 0xb5, 0x4d, 0x00, 0x45, 0x1a, 0xf3, 0xf5, 0x32, 0x74, 0x22, 0x42, 0x16, - 0x06, 0xea, 0x10, 0xc0, 0xd6, 0x12, 0x7c, 0x02, 0xf9, 0x1a, 0xd3, 0xae, 0xb9, 0xff, - 0xd6, 0x11, 0x12, 0x25, 0x14, 0x14, 0x48, 0xbe, 0x82, 0x40, 0xc4, 0x29, 0x73, 0xac, - 0x52, 0xd7, 0x1b, 0x01, 0x2f, 0xe8, 0xef, 0x41, 0xf0, 0x0e, 0xc1, 0x96, 0xc7, 0x57, - 0x89, 0x9e, 0xf8, 0xc0, 0x0e, 0xf8, 0xdf, 0x44, 0x5c, 0x56, 0x54, 0x69, 0xd8, 0x4b, - 0xd0, 0x2c, 0x7f, 0xc4, 0x1b, 0xfc, 0xdf, 0x98, 0x95, 0x1f, 0x50, 0xe8, 0x3f, 0x19, - 0xa0, 0x00, 0xa9, 0xe4, 0x53, 0xf6, 0x21, 0x67, 0xe7, 0x35, 0x0f, 0x92, 0x36, 0x08, - 0x31, 0xbd, 0x7c, 0x52, 0x22, 0xb6, 0x70, 0x61, 0x6e, 0x4b, 0x6c, 0xa8, 0xa2, 0x35, - 0x50, 0xca, 0xd8, 0xac, 0x0d, 0xdb, 0x76, 0x45, 0xe2, 0xb9, 0x71, 0x3b, 0xe7, - ], - script_code: vec![0x6a, 0x00, 0x00, 0x65, 0x53, 0xac, 0x63, 0x53, 0x63], - transparent_input: None, - hash_type: 1, - amount: 1871432121379810, - consensus_branch_id: 1991772603, - sighash: [ - 0x36, 0x77, 0xa9, 0x48, 0x4f, 0x04, 0x04, 0xfb, 0x50, 0x64, 0x58, 0x56, 0xf4, 0xd4, - 0xa7, 0x0b, 0x2e, 0x2b, 0x1c, 0x2d, 0x86, 0x2f, 0x1d, 0x4e, 0xf6, 0x8d, 0x52, 0x09, - 0x60, 0xa1, 0x2a, 0x2b, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0xa0, 0x1e, 0x64, 0x49, 0xae, - 0x43, 0x5c, 0x24, 0xbe, 0x7b, 0x9d, 0x28, 0x8a, 0xd7, 0x57, 0x12, 0xc9, 0x2a, 0xa5, - 0x06, 0x18, 0xdf, 0xba, 0x18, 0xe8, 0x4e, 0x88, 0xd4, 0x60, 0x68, 0xdf, 0x0b, 0x42, - 0xaf, 0x89, 0x29, 0x07, 0x00, 0x6a, 0x52, 0xac, 0x65, 0x51, 0x63, 0x6e, 0x99, 0x51, - 0xd0, 0x09, 0xa9, 0x39, 0xf7, 0x59, 0xa8, 0xa2, 0xc0, 0x49, 0xde, 0xf0, 0x97, 0x7f, - 0x61, 0xea, 0x11, 0x23, 0x14, 0x06, 0xcd, 0x10, 0x95, 0x6d, 0x16, 0x55, 0x78, 0xbb, - 0x29, 0xe4, 0x76, 0x96, 0x76, 0x9a, 0x58, 0x0e, 0x07, 0x01, 0x00, 0x15, 0xaf, 0x3b, - 0x50, 0x00, 0x13, 0x58, 0xd0, 0x37, 0xe5, 0x70, 0xfe, 0x0b, 0x50, 0x0e, 0xe2, 0x99, - 0x8c, 0xdf, 0x06, 0x00, 0x03, 0x7e, 0x28, 0x30, 0x34, 0x34, 0x96, 0x2f, 0x03, 0x92, - 0x48, 0x3d, 0xec, 0xad, 0x2f, 0x9f, 0x4e, 0xbc, 0x99, 0x05, 0x4b, 0xbc, 0xf1, 0x55, - 0xff, 0xae, 0x67, 0x76, 0x34, 0xc3, 0xfb, 0x98, 0x0d, 0xc5, 0xe8, 0xec, 0x67, 0xa4, - 0x65, 0x7e, 0x80, 0xa2, 0x9a, 0x79, 0x6f, 0x39, 0x62, 0xae, 0x0c, 0xb9, 0xc7, 0x86, - 0x82, 0xb3, 0xf4, 0xf9, 0x2e, 0x5a, 0x1e, 0xd1, 0xda, 0x2b, 0xbf, 0xc1, 0x71, 0x07, - 0x7e, 0xef, 0x83, 0x65, 0xbb, 0x38, 0xce, 0x94, 0xca, 0xb0, 0x28, 0x33, 0xce, 0x47, - 0xd4, 0xa0, 0x98, 0x65, 0x72, 0x94, 0xec, 0x10, 0xb2, 0x99, 0x74, 0x22, 0x22, 0xd0, - 0xbf, 0x74, 0x3f, 0x40, 0xc8, 0xea, 0x97, 0x14, 0x32, 0x5c, 0x8a, 0x37, 0x05, 0x08, - 0x24, 0xfa, 0x75, 0x62, 0xd2, 0xc9, 0x25, 0x2c, 0x34, 0xa9, 0x84, 0x50, 0x27, 0xd6, - 0x63, 0x90, 0xe9, 0x56, 0xb2, 0x5e, 0x16, 0x6c, 0x44, 0x95, 0xd3, 0xde, 0xd3, 0xf7, - 0xac, 0xcf, 0x74, 0x76, 0x38, 0x99, 0x47, 0x35, 0x11, 0x34, 0x12, 0x98, 0xfe, 0xb1, - 0x89, 0xb7, 0xed, 0x34, 0xe5, 0x67, 0xd7, 0x2f, 0x1d, 0xf4, 0xbf, 0x69, 0x7f, 0x71, - 0x46, 0x49, 0x3f, 0xa5, 0xc2, 0x36, 0x91, 0x22, 0x7b, 0x90, 0xb2, 0x51, 0x22, 0xc5, - 0x40, 0xdf, 0x0a, 0x6f, 0x2e, 0xc0, 0x6f, 0x9d, 0x89, 0xa3, 0xf7, 0x71, 0xe9, 0xb8, - 0xed, 0x74, 0x79, 0x40, 0x85, 0x51, 0x06, 0xd5, 0xea, 0x71, 0xba, 0x89, 0xe8, 0xf2, - 0x0c, 0xde, 0xa6, 0x9a, 0x77, 0x8a, 0x59, 0xe4, 0xdf, 0x79, 0x28, 0xc0, 0x35, 0x56, - 0x23, 0x31, 0xc8, 0xe1, 0x62, 0xb8, 0xfd, 0x5e, 0xbb, 0xd5, 0xe2, 0xb3, 0x7b, 0xea, - 0x7a, 0xf0, 0x69, 0x07, 0x10, 0x40, 0xc3, 0x7c, 0x1a, 0x1c, 0x37, 0xf0, 0x76, 0x0f, - 0xed, 0x7d, 0xb7, 0xfa, 0x70, 0xa9, 0x48, 0x94, 0x03, 0x00, 0x45, 0x76, 0xa2, 0xcc, - 0xe9, 0x0a, 0x39, 0x4b, 0x5e, 0xc5, 0x8b, 0x2e, 0x5d, 0x0e, 0x1a, 0xf8, 0xb0, 0x29, - 0x6d, 0x0b, 0xf0, 0x2c, 0x55, 0x97, 0xa4, 0x33, 0x54, 0x14, 0x43, 0x35, 0xe0, 0x6a, - 0x80, 0x1c, 0x6e, 0x7c, 0x73, 0x29, 0x7d, 0xfe, 0x0b, 0x32, 0xfc, 0xb8, 0x75, 0x33, - 0x81, 0x71, 0xdd, 0x1e, 0xeb, 0xeb, 0x12, 0x3f, 0xea, 0xfa, 0x32, 0xa5, 0xd8, 0xc7, - 0xce, 0x58, 0x39, 0x0e, 0xa2, 0xdf, 0x26, 0xc6, 0x88, 0x88, 0xda, 0xf3, 0x81, 0x6b, - 0x7d, 0x02, 0x97, 0xa1, 0x7b, 0x5f, 0x5d, 0x20, 0x8d, 0xe9, 0x22, 0xe7, 0x73, 0x97, - 0x2b, 0x95, 0xe6, 0x96, 0x5e, 0x58, 0xfb, 0xf6, 0x4f, 0xae, 0x06, 0xf0, 0xc3, 0x89, - 0x6e, 0x0b, 0x57, 0x89, 0x0d, 0xd7, 0xf3, 0xc6, 0x4c, 0x3d, 0x5c, 0xeb, 0xb6, 0xa7, - 0x44, 0xc5, 0x93, 0x38, 0x61, 0x22, 0x71, 0x82, 0x08, 0x04, 0x95, 0xce, 0x9a, 0xc2, - 0xe1, 0x73, 0x09, 0x9c, 0xdc, 0x35, 0x8d, 0xa8, 0x7d, 0xd7, 0x4a, 0x77, 0x34, 0xff, - 0xff, 0xc4, 0x5f, 0xb6, 0xad, 0x1f, 0x38, 0x9c, 0x6a, 0x4d, 0x49, 0x86, 0x62, 0x64, - 0x60, 0x56, 0x08, 0x4d, 0x09, 0xb7, 0x84, 0x88, 0xa3, 0xba, 0x1d, 0x8a, 0x3d, 0x6b, - 0x48, 0x9a, 0xfd, 0xf2, 0x32, 0xd6, 0xd0, 0x70, 0xa1, 0xb5, 0x06, 0x0c, 0xaa, 0x44, - 0x3d, 0x0c, 0x7e, 0xe5, 0x19, 0x04, 0x54, 0x7f, 0xaf, 0x53, 0x95, 0xcb, 0xd0, 0xba, - 0x99, 0x48, 0x0a, 0xd0, 0x4a, 0xe0, 0xe1, 0x91, 0x5b, 0xd7, 0x7f, 0xa2, 0x6d, 0x04, - 0x17, 0x5b, 0x00, 0xfd, 0xc8, 0x1e, 0xf6, 0xf3, 0x79, 0x23, 0x72, 0x49, 0x27, 0xf0, - 0x82, 0x66, 0xb6, 0x86, 0x40, 0x93, 0x13, 0xdc, 0x13, 0xbc, 0x39, 0x9d, 0x19, 0x77, - 0xb8, 0xf6, 0x58, 0x8c, 0x0e, 0x08, 0x72, 0x10, 0xf0, 0x51, 0xcf, 0x6e, 0x36, 0xe1, - 0x4e, 0x32, 0xaa, 0x23, 0xba, 0x6a, 0xe4, 0x33, 0x1f, 0x22, 0x39, 0xe7, 0x05, 0xf6, - 0x79, 0x54, 0x2f, 0xbd, 0x4e, 0xd2, 0xbf, 0x31, 0x91, 0x24, 0x36, 0x81, 0xf8, 0x27, - 0x89, 0x6b, 0x1b, 0xb1, 0xc4, 0xb7, 0x8b, 0x34, 0xc4, 0x87, 0xa4, 0xed, 0xfa, 0x97, - 0xd3, 0x6d, 0x62, 0xee, 0x32, 0x49, 0xef, 0xe0, 0x94, 0xc3, 0x87, 0x8a, 0xde, 0xdf, - 0x9f, 0x2b, 0x17, 0xd5, 0x11, 0x99, 0x80, 0x4f, 0x42, 0x9c, 0xd7, 0x04, 0xa7, 0xc8, - 0x6c, 0x85, 0x0c, 0xe1, 0x5d, 0x3c, 0x5f, 0x01, 0xd1, 0xad, 0x17, 0xeb, 0xb6, 0xc2, - 0x88, 0x3f, 0x28, 0xe8, 0x15, 0xbc, 0x45, 0x2a, 0x56, 0x07, 0x98, 0x05, 0xa5, 0xdd, - 0x69, 0x00, 0xe5, 0x5f, 0x47, 0x7e, 0xca, 0xc2, 0x14, 0x3f, 0x02, 0xee, 0x98, 0xc8, - 0xd9, 0xb1, 0xb7, 0x03, 0x93, 0xa1, 0x70, 0xba, 0x25, 0x48, 0x06, 0xb4, 0x08, 0x5b, - 0x8d, 0xf9, 0xca, 0x04, 0x07, 0x18, 0x42, 0xa3, 0xaf, 0x93, 0x33, 0x16, 0x83, 0x0d, - 0x53, 0xa7, 0xcb, 0x88, 0xd2, 0xa9, 0x82, 0x3b, 0xcd, 0xfb, 0xec, 0x8f, 0x18, 0xc8, - 0x6a, 0xc3, 0xdf, 0x89, 0x42, 0x38, 0x00, 0x1b, 0xa8, 0xfa, 0x31, 0x3f, 0x80, 0xcf, - 0xe7, 0x5f, 0x7c, 0xb5, 0xd9, 0x73, 0xcc, 0x77, 0xf3, 0x21, 0xf1, 0x95, 0x2f, 0x30, - 0x50, 0x18, 0xc0, 0xbf, 0x23, 0x8b, 0x80, 0xe3, 0x21, 0x19, 0x90, 0x60, 0x66, 0xf6, - 0x4e, 0x64, 0x5e, 0x2b, 0xca, 0xd7, 0xe4, 0xcd, 0xbe, 0xf0, 0x07, 0xf7, 0xe9, 0xad, - 0x8a, 0x31, 0x83, 0x8b, 0x9e, 0xae, 0xc3, 0x85, 0xe3, 0xf2, 0x5e, 0x16, 0x04, 0xa6, - 0xd4, 0x64, 0x99, 0x87, 0x5a, 0xc1, 0x4a, 0x6c, 0xb3, 0x55, 0xa3, 0xd4, 0x32, 0x91, - 0x45, 0x80, 0x3c, 0x6b, 0xfb, 0x82, 0xe2, 0x9a, 0xb0, 0x29, 0x9f, 0x91, 0x7a, 0x74, - 0x02, 0x81, 0x57, 0x71, 0x7c, 0x08, 0x48, 0x68, 0x63, 0x94, 0x5c, 0x5a, 0x02, 0x36, - 0x58, 0xee, 0xe4, 0xa8, 0xb2, 0x89, 0x56, 0x4c, 0x22, 0xa9, 0x67, 0x1c, 0x56, 0x91, - 0x33, 0x5e, 0xb1, 0x25, 0x89, 0x88, 0x51, 0x67, 0x8f, 0x54, 0x93, 0x45, 0x10, 0xbf, - 0x30, 0x91, 0xc6, 0x02, 0xe1, 0x2a, 0x32, 0x03, 0xa2, 0xf3, 0x2f, 0x34, 0x7d, 0x4b, - 0xdc, 0x9d, 0x44, 0x92, 0x4d, 0xc8, 0x67, 0x5c, 0x9f, 0x24, 0x06, 0x4d, 0x35, 0xb0, - 0x09, 0xb6, 0xdd, 0xbd, 0xb2, 0x37, 0x20, 0x75, 0x33, 0xd5, 0xbb, 0xad, 0x3b, 0xa1, - 0xa3, 0xd6, 0xb0, 0x89, 0x32, 0x9b, 0xe1, 0x47, 0x23, 0x4e, 0x75, 0x1a, 0x49, 0x27, - 0x9d, 0x74, 0xdb, 0x88, 0xdb, 0x5c, 0xa1, 0x02, 0xd5, 0xe0, 0xe1, 0xaa, 0xc7, 0xcc, - 0xf9, 0x66, 0xb0, 0xa8, 0x13, 0x67, 0x09, 0x5d, 0xa2, 0x1d, 0xc4, 0xb7, 0x36, 0x55, - 0x95, 0x30, 0x80, 0xe3, 0x54, 0xbd, 0x22, 0x09, 0xf2, 0x66, 0x82, 0x10, 0xe9, 0x47, - 0x41, 0x27, 0x31, 0x1d, 0x93, 0x45, 0xce, 0x1e, 0xbd, 0x3a, 0xe5, 0x24, 0x24, 0x5b, - 0xbb, 0x44, 0x7a, 0x44, 0x50, 0x80, 0xb5, 0xfa, 0x23, 0xcd, 0xfe, 0x98, 0xb3, 0xf6, - 0xf6, 0x3c, 0x44, 0xeb, 0xe7, 0x22, 0xb9, 0x7a, 0x79, 0x10, 0xdf, 0x7e, 0xa6, 0x22, - 0x5e, 0xd9, 0xdc, 0xb4, 0x49, 0x84, 0x93, 0xe8, 0xef, 0x55, 0x31, 0xf9, 0xf9, 0x77, - 0x31, 0x84, 0xd7, 0xb4, 0xf5, 0x36, 0x77, 0xb1, 0xd0, 0x44, 0xf6, 0xf1, 0x44, 0x07, - 0xde, 0x5d, 0x67, 0xe0, 0x77, 0xd2, 0x0f, 0x2e, 0x9d, 0x7f, 0xd7, 0x15, 0xbf, 0x9b, - 0x19, 0x9b, 0x93, 0xb9, 0x84, 0x02, 0x46, 0xef, 0x9c, 0x07, 0x35, 0xe4, 0x88, 0xff, - 0x7c, 0x80, 0xb9, 0x41, 0x78, 0xac, 0xa3, 0x1b, 0x13, 0xc3, 0x7c, 0x9a, 0xeb, 0x7f, - 0x62, 0xe2, 0xd8, 0x58, 0x97, 0xea, 0x2e, 0x2a, 0x23, 0x28, 0xee, 0x03, 0xc9, 0x7f, - 0x2f, 0x3f, 0x4d, 0x20, 0xa8, 0xe7, 0x30, 0x24, 0xc5, 0x50, 0x8e, 0xee, 0xbd, 0x3a, - 0x12, 0x67, 0x31, 0xcd, 0xbf, 0x21, 0xfd, 0xad, 0xb1, 0x4b, 0x4e, 0x59, 0x1c, 0xba, - 0xb1, 0x44, 0xbe, 0xc3, 0x5a, 0x72, 0xac, 0xbf, 0x94, 0x84, 0xf4, 0x7a, 0x10, 0xb9, - 0x1e, 0xfc, 0x04, 0x27, 0xfe, 0xcf, 0x3f, 0xfc, 0xf1, 0x69, 0xd7, 0x00, 0x59, 0xb4, - 0x02, 0x79, 0xff, 0xa0, 0x2c, 0x51, 0x06, 0x74, 0x27, 0xa0, 0xda, 0xea, 0xd6, 0xf9, - 0x4b, 0xaf, 0xe4, 0xc1, 0x23, 0x3a, 0x22, 0x25, 0xeb, 0x56, 0x00, 0x3f, 0xc3, 0x85, - 0x42, 0x0d, 0x5a, 0x9f, 0xf3, 0xd5, 0x91, 0x55, 0x23, 0xa0, 0x8c, 0x87, 0xeb, 0x2e, - 0xa6, 0x69, 0x17, 0x23, 0x3a, 0x73, 0x25, 0xfe, 0x79, 0x3f, 0x41, 0x07, 0x6d, 0x64, - 0x25, 0x5a, 0xbd, 0x15, 0x21, 0x47, 0x66, 0x60, 0xe9, 0x04, 0x91, 0x60, 0x2c, 0x69, - 0xa4, 0xab, 0xb1, 0x38, 0x84, 0x43, 0x10, 0x72, 0xef, 0x96, 0xa0, 0x95, 0xbe, 0x41, - 0x1f, 0xfc, 0xff, 0xb7, 0x86, 0x3f, 0xef, 0x7d, 0xab, 0x4d, 0x4a, 0x72, 0xa2, 0xd0, - 0xbb, 0xd3, 0x6f, 0x9f, 0xdf, 0x0b, 0x35, 0x38, 0xb3, 0x9c, 0xae, 0x5f, 0xf6, 0x0e, - 0x5a, 0xc6, 0xb6, 0x09, 0x70, 0x72, 0x43, 0x14, 0x6e, 0xb5, 0x36, 0x0a, 0xe7, 0xf9, - 0x3f, 0x79, 0x9b, 0x6c, 0x27, 0xe6, 0x5a, 0x0a, 0x06, 0x39, 0x87, 0x38, 0x66, 0x0f, - 0xda, 0xd2, 0xcf, 0xb3, 0x1a, 0xa5, 0x40, 0xd5, 0xe8, 0x90, 0x06, 0x78, 0xb9, 0xda, - 0xb5, 0x24, 0x79, 0xbd, 0x0c, 0xd6, 0xf1, 0xa5, 0x98, 0x67, 0x3e, 0xed, 0x9c, 0x76, - 0xe3, 0x38, 0x10, 0x49, 0x47, 0x18, 0xd0, 0x5d, 0xdf, 0xdc, 0x00, 0x7a, 0x54, 0xbc, - 0xd1, 0xcc, 0x4c, 0x97, 0x40, 0xf7, 0xe5, 0x3a, 0x31, 0x68, 0x1d, 0x2b, 0x2c, 0x6e, - 0xde, 0x79, 0x28, 0x11, 0x49, 0xea, 0xc3, 0x0f, 0x6e, 0xe5, 0x83, 0x60, 0x5a, 0xc2, - 0xff, 0xae, 0xc1, 0x55, 0x00, 0x35, 0xdc, 0x5a, 0xbb, 0x35, 0x89, 0x44, 0x68, 0xf1, - 0x2d, 0x5d, 0x08, 0xd7, 0x34, 0x36, 0xa8, 0x59, 0xe5, 0x50, 0x7f, 0xdd, 0x1a, 0x46, - 0x38, 0xfb, 0xe6, 0x81, 0xb0, 0xa0, 0xef, 0xfb, 0xbb, 0xf7, 0x4c, 0x99, 0x39, 0x9d, - 0xca, 0x69, 0x02, 0xa0, 0x74, 0xc8, 0x33, 0x35, 0x60, 0x7a, 0x0c, 0x0d, 0xb0, 0x1c, - 0xa3, 0xca, 0x2f, 0xa8, 0x18, 0x57, 0x24, 0x02, 0xe2, 0xfa, 0xef, 0xb3, 0x07, 0xbe, - 0x22, 0xc7, 0xd5, 0x61, 0x1f, 0xf6, 0xfb, 0x5a, 0x31, 0xb4, 0x62, 0x16, 0x59, 0xd8, - 0x4d, 0x8a, 0x7a, 0x1a, 0xdc, 0xa2, 0xfc, 0x4e, 0xb8, 0xb8, 0x97, 0x04, 0x43, 0x93, - 0x27, 0x64, 0x46, 0x31, 0xa7, 0xbb, 0xc1, 0xa8, 0x41, 0xf3, 0x65, 0x83, 0x0d, 0x27, - 0xc8, 0xaa, 0x4d, 0x75, 0xc8, 0x07, 0x87, 0xbd, 0x10, 0xb7, 0x14, 0xcb, 0x97, 0x9c, - 0x1b, 0x0f, 0x3f, 0x0b, 0x41, 0xee, 0x94, 0x22, 0x94, 0x24, 0x8c, 0x48, 0x5c, 0xf9, - 0x9c, 0x6b, 0xc4, 0x63, 0x20, 0x7a, 0xf3, 0x83, 0x61, 0x97, 0x83, 0x57, 0x41, 0x41, - 0x5d, 0xe6, 0x1f, 0xf2, 0x9f, 0xad, 0x30, 0x01, 0x82, 0x71, 0x4c, 0x20, 0xca, 0x34, - 0x04, 0x7b, 0xcc, 0xb7, 0x05, 0x81, 0x0f, 0xfa, 0xe5, 0x3a, 0x34, 0x16, 0xa5, 0x3f, - 0x28, 0xaf, 0xc0, 0x08, 0xe8, 0xbf, 0xf9, 0x49, 0xe4, 0x3a, 0x54, 0x10, 0xe6, 0xad, - 0xb6, 0x65, 0xf9, 0x9f, 0xa4, 0xca, 0xfa, 0xc2, 0xe0, 0xf2, 0xc0, 0xf1, 0x34, 0xbd, - 0xba, 0x83, 0x81, 0xc2, 0xbb, 0xac, 0x43, 0x33, 0x2a, 0xcd, 0xcb, 0x10, 0x08, 0x2e, - 0xf3, 0x43, 0xa3, 0x5a, 0xc6, 0x4f, 0x4b, 0xa1, 0x6e, 0x49, 0x57, 0xc7, 0x1e, 0x9a, - 0x2b, 0xd9, 0xa5, 0xcd, 0x6a, 0x92, 0x25, 0x8a, 0x9e, 0x58, 0x8e, 0x02, 0x1a, 0x06, - 0x65, 0x09, 0x04, 0x67, 0x0d, 0xa2, 0xc0, 0xe5, 0x2c, 0x52, 0x4f, 0x6e, 0x5c, 0xe3, - 0xee, 0x27, 0x5a, 0x0a, 0x63, 0x10, 0x3b, 0x5f, 0x92, 0x64, 0x16, 0xc0, 0xbd, 0x5d, - 0xa1, 0xae, 0x65, 0x69, 0xd3, 0xa4, 0xee, 0x4d, 0xbc, 0x5e, 0xc0, 0x8b, 0x29, 0x72, - 0x02, 0xc9, 0xd7, 0x13, 0xab, 0xc3, 0x47, 0x4d, 0xe4, 0x94, 0x0f, 0x59, 0xb1, 0xf3, - 0xfe, 0x0e, 0x92, 0x76, 0xa1, 0x76, 0x3b, 0x2d, 0xea, 0x39, 0x40, 0xb0, 0xc1, 0xf7, - 0xab, 0x5d, 0xa3, 0xf4, 0x55, 0x62, 0x3e, 0x04, 0x96, 0x82, 0xd0, 0x92, 0x18, 0x9c, - 0xb7, 0x9e, 0xcf, 0xd4, 0x3c, 0x3b, 0xf1, 0x0e, 0x7f, 0x2c, 0x8d, 0x4d, 0xe3, 0xa7, - 0x36, 0xf8, 0x69, 0xf0, 0x87, 0x03, 0xc4, 0xe5, 0x9f, 0x57, 0x4f, 0x77, 0xaa, 0x86, - 0x1c, 0xbf, 0xdd, 0xd0, 0x7f, 0x77, 0xdc, 0x24, 0xa9, 0x74, 0x10, 0xaf, 0xc7, 0xcf, - 0xbe, 0x3c, 0xe1, 0xff, 0xd2, 0x24, 0x53, 0x5c, 0xf3, 0x05, 0xce, 0xcc, 0x78, 0x56, - 0xa4, 0xd4, 0x8a, 0x6d, 0xec, 0x17, 0xa2, 0x4b, 0x6d, 0x27, 0xfe, 0x26, 0x64, 0xbc, - 0x2b, 0x2b, 0x71, 0x1d, 0x67, 0x13, 0x90, 0x6c, 0xed, 0x8a, 0x80, 0x66, 0x62, 0x18, - 0x40, 0xd9, 0x0c, 0x23, 0xae, 0x33, 0x77, 0x30, 0x67, 0x9d, 0x2c, 0xde, 0x32, 0x69, - 0xab, 0x1f, 0x42, 0xac, 0x03, 0xff, 0xdb, 0xa0, 0x32, 0xd3, 0x2c, 0xa8, 0x79, 0x63, - 0x82, 0x56, 0x56, 0x5d, 0xe1, 0xd2, 0xde, 0x39, 0xf5, 0x6f, 0x94, 0x57, 0x95, 0xd6, - 0xe9, 0x58, 0xe6, 0x93, 0xdc, 0x8c, 0xbf, 0x6d, 0x04, 0x30, 0x00, 0xcc, 0x7a, 0x40, - 0x15, 0xf0, 0x2d, 0x0f, 0xe3, 0x97, 0xec, 0x57, 0xf8, 0xfe, 0x29, 0x2e, 0x85, 0x14, - 0x24, 0xe8, 0x40, 0x6d, 0x38, 0xdd, 0xb8, 0xd1, 0xde, 0x9d, 0xef, 0x67, 0x2e, 0x92, - 0x7d, 0x3d, 0xc1, 0xf4, 0x11, 0xdc, 0x78, 0xad, 0xa7, 0x61, 0x00, 0x91, 0xbf, 0xe2, - 0x63, 0xcd, 0x79, 0x96, 0xd1, 0x80, 0x5e, 0xe4, 0x91, 0xe9, 0x95, 0x91, 0xd6, 0xef, - 0xdb, 0x2e, 0x3c, 0x79, 0x71, 0x57, 0x41, 0xd0, 0xd4, 0x72, 0xac, 0x11, 0xdb, 0x78, - 0x64, 0x4f, 0x3d, 0x23, 0xe5, 0x8f, 0x0b, 0x01, 0xa8, 0x61, 0xe0, 0x85, 0x65, 0x53, - 0x52, 0x07, 0xcd, 0x5e, 0x71, 0x0f, 0xc3, 0x3e, 0xb2, 0xf8, 0x92, 0x8b, 0xc7, 0xd4, - 0x01, 0x7e, 0x4e, 0x56, 0xc0, 0xc2, 0xeb, 0x95, 0x85, 0xd6, 0x99, 0x74, 0x5e, 0x3b, - 0xb9, 0x61, 0x8b, 0x2c, 0x1b, 0x90, 0xf2, 0x35, 0x1b, 0xaf, 0x27, 0x6a, 0x70, 0x17, - 0xb0, 0xfc, 0xfa, 0xcb, 0x52, 0xea, 0x27, 0x31, 0x95, 0xa8, 0xde, 0xe1, 0x67, 0x79, - 0x13, 0xc7, 0x86, 0xcc, 0x3a, 0xcb, 0x06, 0xa9, 0xec, 0x7a, 0x37, 0xb0, 0x58, 0x98, - 0x0c, 0xeb, 0x3c, 0x82, 0xaa, 0xb0, 0x3e, 0xaf, 0xc1, 0xbb, 0x88, 0xcf, 0x7a, 0xb7, - 0x98, 0xf1, 0x65, 0x1d, 0x67, 0xbf, 0x22, 0x30, 0xd5, 0x34, 0xec, 0x55, 0x23, 0x1d, - 0x21, 0x31, 0x7b, 0x1c, 0xb3, 0x0b, 0x3c, 0x38, 0xff, 0x8d, 0x21, 0x1b, 0x76, 0x36, - 0x70, 0x2a, 0x25, 0xca, 0x7c, 0xa1, 0xbf, 0xf1, 0xf2, 0xc1, 0x58, 0xc6, 0xef, 0x22, - 0x13, 0xff, 0xab, 0xb9, 0xc0, 0x9f, 0x5c, 0x47, 0xe7, 0x3b, 0xbe, 0xbb, 0xd3, 0x7f, - 0x3d, 0x3e, 0xbc, 0x24, 0xa6, 0x65, 0xb2, 0x9f, 0x10, 0xde, 0x8b, 0x9c, 0xf1, 0x94, - 0x2d, 0x90, 0xb4, 0xc3, 0x1d, 0x89, 0xa9, 0x88, 0x3b, 0xf5, 0xa0, 0x27, 0xe9, 0x20, - 0xd1, 0xb8, 0x51, 0x19, 0xf2, 0xf2, 0xf9, 0x5f, 0xd5, 0x5e, 0xda, 0x85, 0x75, 0xa4, - 0xdb, 0x62, 0x69, 0x05, 0x68, 0x1c, 0x29, 0xe8, 0xd8, 0xe7, 0x41, 0xd4, 0x20, 0xa8, - 0x34, 0x42, 0xa9, 0xd3, 0x8a, 0xf4, 0x19, 0x9e, 0xf9, 0x5c, 0xb3, 0x0b, 0xc4, 0x4e, - 0x93, 0xfe, 0x4d, 0x0e, 0xb7, 0x42, 0x22, 0xfc, 0x10, 0xac, 0x8d, 0x40, 0x0e, 0x10, - 0xed, 0x4e, 0x56, 0xfa, 0x39, 0xda, 0x01, 0x2a, 0xc1, 0x8d, 0xee, 0x4d, 0x99, 0x42, - 0x5c, 0x8f, 0x71, 0x4c, 0x51, 0xac, 0x1b, 0xa5, 0x6e, 0x0e, 0x81, 0x47, 0x4b, 0xad, - 0x3e, 0x74, 0x18, 0xed, 0x4c, 0x82, 0xb4, 0xd7, 0x75, 0x12, 0x0b, 0x19, 0x3e, 0xdc, - 0x66, 0x76, 0x30, 0x32, 0x66, 0xe3, 0x1e, 0xcf, 0x55, 0x1e, 0xb9, 0x13, 0xa6, 0x41, - 0x15, 0xbc, 0xcb, 0xbb, 0x2e, 0xcc, 0x89, 0x81, 0x55, 0x21, 0xe5, 0x6e, 0x07, 0xc8, - 0x8b, 0xbb, 0x4a, 0x55, 0xe9, 0x94, 0x5d, 0x03, 0xdb, 0x2d, 0xa0, 0xfc, 0xae, 0x3c, - 0x08, 0xf1, 0xd7, 0x7c, 0x57, 0x26, 0x1e, 0x98, 0x23, 0x66, 0x03, 0xa8, 0xc5, 0x2c, - 0x6c, 0x27, 0x98, 0xb5, 0x45, 0x61, 0xaf, 0xfe, 0x07, 0x61, 0xe6, 0xab, 0x24, 0x72, - 0x07, 0xad, 0xfc, 0x3c, 0x43, 0x22, 0xbe, 0x0f, 0xb2, 0x49, 0xbf, 0xd3, 0xc5, 0xe7, - 0xfb, 0x38, 0x37, 0xe9, 0xff, 0x21, 0x35, 0x07, 0x3a, 0xe1, 0x36, 0x0d, 0xcf, 0xaf, - 0x5f, 0xb6, 0x78, 0x56, 0x8f, 0xd8, 0x4d, 0x99, 0xa5, 0x1f, 0x32, 0xeb, 0x94, 0xcc, - 0xf5, 0xf2, 0x39, 0x02, 0x5b, 0x2b, 0x97, 0xbe, 0xf6, 0x25, 0xdb, 0xb6, 0x7f, 0x20, - 0xc3, 0xe0, 0xd9, 0x51, 0x73, 0x12, 0x9c, 0x06, 0x37, 0x50, 0x39, 0x52, 0x13, 0x41, - 0x49, 0x24, 0xe0, 0xa3, 0xfd, 0xd3, 0x66, 0xff, 0xd4, 0x69, 0xc9, 0xeb, 0xea, 0x79, - 0xfb, 0x76, 0xaf, 0x10, 0xea, 0x45, 0xb5, 0x66, 0xf1, 0xfc, 0x92, 0xaf, 0x48, 0xce, - 0xe2, 0x11, 0xf8, 0xe1, 0xb0, 0x58, 0xfb, 0x72, 0x1a, 0x8b, 0x22, 0xce, 0x43, 0x0c, - 0x54, 0x94, 0x0e, 0x24, 0xb3, 0x30, 0x8e, 0x57, 0x0a, 0xb8, 0x57, 0x25, 0x0d, 0x10, - 0xcd, 0xec, 0xe1, 0x05, 0x07, 0x1b, 0xc8, 0x66, 0xea, 0x4d, 0x6d, 0x5c, 0x69, 0xf9, - 0x59, 0x28, 0xf3, 0x9f, 0x7f, 0x1f, 0xcd, 0xf1, 0x5a, 0xcd, 0xbb, 0xec, 0x67, 0xd8, - 0x48, 0xf7, 0xc1, 0xb2, 0xef, 0x57, 0x7f, 0x48, 0xa7, 0x0b, 0x4b, 0xf3, 0xd8, 0xa7, - 0x88, 0x14, 0x31, 0x6b, 0x3d, 0x7f, 0xa3, 0xe3, 0xc9, 0x8c, 0xdf, 0xa1, 0x78, 0xb9, - 0x89, 0xbc, 0x78, 0xde, 0x8d, 0x24, 0xc1, 0xbb, 0xc0, 0x9d, 0x20, 0x7e, 0x11, 0x18, - 0x1e, 0x59, 0x1a, 0x60, 0x9a, 0xbf, 0xf9, 0xa2, 0x00, 0xd3, 0x4e, 0x1a, 0xc6, 0x3a, - 0x38, 0xf0, 0x40, 0x05, 0x3a, 0x32, 0x01, 0x68, 0xb8, 0x23, 0xac, 0x76, 0x6e, 0x02, - 0x6c, 0xbe, 0x1a, 0xbf, 0x27, 0x55, 0xbe, 0x0c, 0x73, 0xc8, 0xfd, 0x98, 0x62, 0x55, - 0x56, 0x40, 0x6c, 0x14, 0x99, 0x3f, 0x6a, 0x28, 0xae, 0x4b, 0xb3, 0xa4, 0x73, 0xa1, - 0x8d, 0xd3, 0x74, 0x3d, 0x88, 0x7e, 0xac, 0x54, 0x8e, 0xb7, 0xca, 0x4d, 0x46, 0x15, - 0x7c, 0x62, 0xb7, 0x29, 0xf3, 0x66, 0xa9, 0x56, 0x02, 0x28, 0x7c, 0x8c, 0x56, 0x33, - 0x5b, 0x78, 0xbc, 0x68, 0x9f, 0xc5, 0x38, 0x9c, 0x39, 0x79, 0xb8, 0xe7, 0x5d, 0xaf, - 0x31, 0xbd, 0x60, 0xa9, 0xcc, 0x2a, 0x92, 0x0d, 0xbc, 0xc6, 0x71, 0xdd, 0xe2, 0x7e, - 0xb4, 0x60, 0x0f, 0x12, 0xdc, 0x2a, 0xb3, 0x94, 0x4a, 0xa1, 0x9c, 0x71, 0xa9, 0x87, - 0xd8, 0x71, 0x3d, 0x99, 0xa4, 0xba, 0x9b, 0x9a, 0x19, 0xa9, 0x21, 0x60, 0x6c, 0x56, - 0x20, 0xc1, 0x67, 0xd4, 0xc7, 0xf4, 0xa2, 0x8a, 0x46, 0x4a, 0x9d, 0x16, 0xc4, 0xb0, - 0xd7, 0x4e, 0x0e, 0x75, 0xdf, 0x6d, 0xba, 0x0e, 0x1d, 0xfe, 0x60, 0x1c, 0x04, 0xc8, - 0xeb, 0x37, 0x01, 0x0e, 0x13, 0x92, 0x1d, 0x5b, 0x6c, 0x93, 0xb9, 0xf0, 0xc3, 0xdd, - 0xd3, 0x2f, 0x7b, 0xec, 0xb2, 0xd7, 0x7d, 0x79, 0xa1, 0x61, 0x8a, 0x79, 0xf7, 0x3c, - 0x45, 0x9b, 0x0d, 0xf5, 0x29, 0x7f, 0x8e, 0xab, 0xd6, 0xed, 0x06, 0xfd, 0x23, 0x40, - 0xe8, 0x60, 0x0a, 0x95, 0xd7, 0x2c, 0xef, 0xd1, 0x2e, 0x62, 0x2c, 0x57, 0xb4, 0x57, - 0xa4, 0xe8, 0x39, 0x75, 0x93, 0x74, 0x6a, 0x6b, 0xcf, 0x04, 0xc4, 0x9c, 0x6d, 0xd4, - 0xa3, 0x36, 0x68, 0xda, 0x53, 0x8d, 0x90, 0x93, 0xa4, 0x50, 0xa4, 0xd8, 0x24, 0x51, - 0xb6, 0x12, 0xff, 0x54, 0x70, 0x73, 0x8e, 0x62, 0xbf, 0xdf, 0xc7, 0x9b, 0x3e, 0x31, - 0xbb, 0x47, 0xfc, 0xa1, 0xe9, 0x87, 0x22, 0xa5, 0x98, 0x3a, 0xff, 0xe5, 0xf6, 0x32, - 0x84, 0x0b, 0x92, 0x3a, 0xb5, 0x6b, 0x1d, 0xa1, 0x53, 0xd3, 0x5d, 0x82, 0x23, 0x24, - 0xe7, 0xd5, 0x6d, 0x61, 0x3c, 0x73, 0xeb, 0xc6, 0x34, 0x1e, 0xa0, 0x3b, 0xee, 0x3a, - 0xb9, 0x73, 0xe8, 0x4d, 0x8f, 0xfc, 0x4a, 0x7c, 0x58, 0x13, 0x83, 0xe2, 0x14, 0x2d, - 0x29, 0x2a, 0x58, 0x0b, 0x6d, 0x30, 0x83, 0x43, 0xdc, 0xf1, 0xef, 0x49, 0x29, 0xa9, - 0xe3, 0xe6, 0x15, 0x32, 0xfc, 0xff, 0xb7, 0x4d, 0x30, 0x19, 0xf4, 0xe2, 0xd6, 0xd3, - 0x11, 0x78, 0x57, 0x5a, 0xca, 0x94, 0x12, 0x99, 0x22, 0x50, 0x44, 0xe1, 0xd3, 0x7b, - 0xab, 0x9f, 0x10, 0xe2, 0x9f, 0xd9, 0x6f, 0x9c, 0xf6, 0x84, 0xaf, 0x98, 0xed, 0x64, - 0x8b, 0x83, 0xd6, 0x1e, 0x52, 0x5b, 0xe3, 0x2c, 0xdb, 0x45, 0x3d, 0x2d, 0x38, 0x93, - 0x5f, 0xee, 0xb3, 0x22, 0xce, 0xb9, 0xd2, 0xa2, 0xe9, 0x5e, 0xb7, 0xfc, 0x61, 0x2d, - 0x89, 0xf4, 0xcf, 0xe8, 0x93, 0x22, 0x8e, 0x88, 0x28, 0xb1, 0x89, 0x00, 0x90, 0x45, - 0x62, 0x90, 0x75, 0xc0, 0xc2, 0x03, 0x9d, 0x5a, 0x73, 0x32, 0xfd, 0xbc, 0xd7, 0xc7, - 0xb0, 0x91, 0x01, 0x5c, 0x45, 0x69, 0xa3, 0x00, 0x53, 0x23, 0x56, 0xbb, 0xad, 0x08, - 0xff, 0xa3, 0xbb, 0x16, 0x7a, 0x3e, 0xbe, 0xb4, 0x62, 0x66, 0xb7, 0x06, 0x06, 0x49, - 0x4a, 0xda, 0xe9, 0x14, 0x9e, 0x1a, 0x64, 0xc0, 0xa0, 0xaa, 0x5d, 0xaa, 0x53, 0x62, - 0xd3, 0xc7, 0xa8, 0x96, 0xfd, 0x52, 0x78, 0x08, 0xd0, 0xa3, 0xc1, 0xcf, 0x70, 0x61, - 0xba, 0x67, 0x89, 0x39, 0x80, 0x78, 0x85, 0x0b, 0xe4, 0xb9, 0x94, 0x0e, 0x01, 0xae, - 0xbb, 0x93, 0x6d, 0xd8, 0x1a, 0x31, 0x82, 0x04, 0x28, 0x1d, 0x43, 0x97, 0x6f, 0x4e, - 0x0f, 0xa2, 0x07, 0xe4, 0xbe, 0x1f, 0xb8, 0x2c, 0x91, 0xbb, 0x26, 0x42, 0xf7, 0x36, - 0x85, 0x6d, 0xcd, 0x5a, 0xeb, 0x75, 0xc5, 0x0a, 0xf2, 0x00, 0xe1, 0x4b, 0xe5, 0xb7, - 0x8c, 0xe6, 0x9a, 0x88, 0x51, 0x54, 0xef, 0xe3, 0x0e, 0xdd, 0x09, 0xae, 0x8c, 0x5e, - 0xb5, 0x3f, 0x4b, 0x8b, 0x7c, 0x75, 0x35, 0x37, 0x3c, 0x0f, 0xe6, 0xcf, 0xe4, 0x48, - 0xa9, 0xb9, 0xf4, 0xd9, 0xe3, 0x10, 0x93, 0x03, 0xd6, 0xce, 0xe9, 0x10, 0x6a, 0xa2, - 0x2b, 0xd5, 0x9a, 0xe0, 0xe0, 0x27, 0xd3, 0x25, 0x6a, 0x75, 0xb9, 0xc5, 0xd6, 0x07, - 0x09, 0x09, 0x97, 0x53, 0xce, 0x57, 0x2c, 0x9e, 0x29, 0xdc, 0x92, 0x56, 0x2d, 0x1c, - 0x3f, 0x4a, 0x0b, 0x4d, 0x36, 0xa6, 0xfe, 0xc2, 0x1b, 0xa4, 0x94, 0x17, 0x3e, 0x44, - 0xd7, 0x9b, 0xc2, 0x34, 0x18, 0x95, 0xbd, 0x0c, 0x70, 0x96, 0xf0, 0x97, 0x4f, 0x12, - 0x67, 0xfe, 0xf6, 0x72, 0x1d, 0x58, 0xb8, 0xc4, 0xe3, 0x34, 0xf1, 0x4d, 0x86, 0xc0, - 0xee, 0x3b, 0x1a, 0xb5, 0x88, 0x0c, 0xa4, 0x29, 0x8d, 0x7f, 0x84, 0x76, 0x3b, 0xdc, - 0x71, 0x09, 0xbc, 0x82, 0x0f, 0x45, 0xc5, 0x04, 0x53, 0xe3, 0x3d, 0x96, 0x8e, 0xf9, - 0xd8, 0x6c, 0xd6, 0xeb, 0xe7, 0x15, 0xe8, 0x9d, 0x5d, 0xe3, 0x24, 0x09, 0x10, 0xc5, - 0x9c, 0x36, 0xec, 0x8f, 0xe9, 0x9b, 0x32, 0x49, 0x16, 0x30, 0xab, 0x35, 0xb1, 0x24, - 0x53, 0x1d, 0x9c, 0x29, 0xe0, 0x46, 0xc4, 0x78, 0xe6, 0x2a, 0xd1, 0x8b, 0x25, 0x39, - 0xa5, 0x09, 0x6e, 0xe2, 0x9a, 0x4d, 0x4b, 0x4b, 0x53, 0xa1, 0xcf, 0xfa, 0x93, 0x23, - 0xbc, 0x73, 0x21, 0x81, 0x7d, 0x96, 0xfd, 0x02, 0x05, 0xea, 0x9c, 0xbc, 0x4e, 0x15, - 0x88, 0xb7, 0x61, 0x3d, 0x4c, 0x39, 0x3c, 0xac, 0x21, 0x05, 0xb2, 0x8f, 0xd0, 0x46, - 0x7a, 0x0b, 0xf0, 0x23, 0xf0, 0x0d, 0x1a, 0x17, 0xf6, 0x53, 0xcd, 0xb6, 0xb5, 0xa8, - 0x3e, 0x4c, 0xf1, 0x5c, 0x34, 0x7b, 0x34, 0xb9, 0x7f, 0xbf, 0xe6, 0xea, 0xee, 0x13, - 0xbb, 0x90, 0x15, 0x3a, 0xfd, 0xc9, 0x11, 0x26, 0x37, 0xfa, 0xd1, 0xcf, 0xe1, 0x7e, - 0xdd, 0xcb, 0x0c, 0x81, 0x9e, 0x60, 0xd3, 0x50, 0x39, 0x34, 0x9b, 0x69, 0xf7, 0xca, - 0x9b, 0xa6, 0x4d, 0xf9, 0xf5, 0xe4, 0x71, 0x11, 0x5c, 0xd6, 0x79, 0x26, 0xbd, 0xf1, - 0x6e, 0x30, 0x12, 0x39, 0x8d, 0xae, 0x59, 0x5b, 0xfd, 0x25, 0xf3, 0xae, 0xe5, 0x8a, - 0xcf, 0xfe, 0x2f, 0x3e, 0xd7, 0x48, 0xfd, 0xf9, 0x3a, 0x6e, 0xd2, 0x1e, 0x87, 0x2d, - 0x94, 0x97, 0xa9, 0xf3, 0xb7, 0xb1, 0x6b, 0x7e, 0xa9, 0xea, 0x19, 0xf2, 0x47, 0x9e, - 0x4f, 0x8b, 0x6d, 0x42, 0x3f, 0xa1, 0x5f, 0xbc, 0xdf, 0xa3, 0xc9, 0x9b, 0x9a, 0x39, - 0x70, 0xee, 0x74, 0xa8, 0xd8, 0x5e, 0xc2, 0x15, 0x96, 0x52, 0xda, 0xa7, 0x67, 0x03, - 0x12, 0x63, 0xbb, 0x4b, 0x49, 0x28, 0x5d, 0x70, 0x5e, 0x24, 0xe8, 0x19, 0x26, 0x86, - 0xeb, 0xc8, 0xff, 0x85, 0x98, 0xd2, 0x4b, 0x51, 0x23, 0x2a, 0x99, 0x38, 0x56, 0x5d, - 0x0f, 0x68, 0xbe, 0x7f, 0x3a, 0x53, 0x36, 0x4a, 0xcc, 0x69, 0x21, 0xa3, 0x5b, 0xc5, - 0x99, 0x10, 0xbb, 0x71, 0xfb, 0x58, 0xb8, 0x67, 0x37, 0x3c, 0xe9, 0x5f, 0x19, 0x84, - 0x09, 0xaa, 0xef, 0x97, 0xf4, 0x01, 0xe4, 0x33, 0x00, 0x4b, 0x99, 0x19, 0x04, 0x9f, - 0x93, 0x7f, 0xd7, 0x76, 0xc4, 0xb6, 0x31, 0xa5, 0x91, 0x2a, 0x08, 0xd4, 0x9f, 0xdf, - 0x65, 0x28, 0xf8, 0x1a, 0x6f, 0x32, 0x00, 0x09, 0x37, 0x67, 0xbb, 0x77, 0x89, 0xd9, - 0x5a, 0x75, 0x03, 0x0a, 0xc1, 0xd2, 0x4c, 0x2c, 0x75, 0xbd, 0x60, 0x38, 0x25, 0x52, - 0x86, 0x3f, 0x09, 0x8d, 0x36, 0xbd, 0x48, 0x33, 0x28, 0x3d, 0x3a, 0x2d, 0x21, 0x5d, - 0x10, 0xc7, 0xff, 0xe9, 0xc8, 0x40, 0x37, 0x23, 0x14, 0x45, 0x58, 0x33, 0x29, 0x26, - 0x16, 0x74, 0x19, 0x3b, 0xdd, 0x1c, 0x64, 0x81, 0xbe, 0xf9, 0xf2, 0x26, 0xe1, 0xe6, - 0x0b, 0xb1, 0xc7, 0x76, 0xa4, 0xbe, 0x7d, 0xc6, 0x9b, 0x44, 0x30, 0xa7, 0x5a, 0x0c, - 0xbd, 0x55, 0x86, 0x7a, 0x6f, 0x46, 0xff, 0x93, 0x03, 0xf9, 0xa2, 0x9b, 0x6f, 0x3f, - 0x7c, 0x7a, 0x9c, 0x9f, 0xbc, 0xf7, 0x47, 0xb2, 0x3f, 0x86, 0x45, 0xf4, 0xda, 0x3d, - 0x9f, 0x72, 0xd0, 0xd8, 0x76, 0xa7, 0x5e, 0x54, 0x8a, 0x49, 0xdb, 0x37, 0x5b, 0x40, - 0xeb, 0xe1, 0xbb, 0xe0, 0x81, 0x7a, 0x99, 0x49, 0xde, 0xc1, 0x15, 0x7d, 0x62, 0xa7, - 0x1d, 0xbf, 0xbd, 0x9b, 0xb1, 0xd6, 0x55, 0x17, 0x53, 0xdf, 0xf5, 0xbb, 0x7f, 0xc9, - 0x36, 0x48, 0xd4, 0xeb, 0x6c, 0xad, 0x41, 0x67, 0x33, 0xad, 0xfd, 0xcc, 0x87, 0x08, - 0xdd, 0xe8, 0xbe, 0x87, 0x34, 0xd0, 0x5d, 0xec, 0x9e, 0x45, 0xdf, 0x3f, 0xa4, 0x5a, - 0xda, 0xc4, 0x1a, 0x6d, 0x23, 0xa2, 0x24, 0xa0, 0x4f, 0xdc, 0x0d, 0x96, 0x73, 0x87, - 0x98, 0x0f, 0x95, 0xe6, 0x27, 0xe6, 0xb3, 0xdc, 0xe1, 0x9c, 0xaf, 0x01, 0x09, 0x84, - 0x8c, 0xa9, 0xda, 0xea, 0x2e, 0x24, 0x6e, 0x62, 0xc2, 0x85, 0x07, 0xd2, 0x56, 0xeb, - 0xab, 0xe1, 0x18, 0xf1, 0xf6, 0xef, 0x97, 0x6e, 0x4a, 0x31, 0xa0, 0xe4, 0x14, 0x3c, - 0x43, 0x60, 0xd8, 0xb1, 0x79, 0xb3, 0x0e, 0x4b, 0xfa, 0x7e, 0x16, 0x1b, 0x1e, 0x6c, - 0x70, 0x7d, 0x8e, 0xae, 0x76, 0x28, 0x71, 0x59, 0x21, 0x94, 0x1e, 0x78, 0x54, 0xe1, - 0x0d, 0x11, 0x99, 0x12, 0x58, 0xc4, 0x3f, 0xe6, 0xc4, 0x45, 0x29, 0xf6, 0x61, 0x4b, - 0x58, 0x41, 0x61, 0x5d, 0x3e, 0x4e, 0x77, 0xfb, 0x09, 0xa6, 0xf0, 0x20, 0xe0, 0xb8, - 0x32, 0x28, 0xac, 0x17, 0x55, 0xad, 0x47, 0x71, 0x16, 0xde, 0xca, 0xac, 0x51, 0x7b, - 0xfb, 0xcf, 0x67, 0x37, 0xf5, 0xbb, 0x99, 0xe0, 0x07, 0xeb, 0x64, 0x00, 0x76, 0x6b, - 0x6c, 0xfd, 0xd7, 0x37, 0xe2, 0x08, 0x57, 0xdf, 0x3c, 0x85, 0xca, 0x16, 0xab, 0x21, - 0x17, 0x7b, 0x53, 0x1e, 0x55, 0x32, 0xc4, 0x45, 0xde, 0xd0, 0x0c, 0x1e, 0x96, 0x63, - 0x5e, 0x9f, 0x50, 0x0b, 0xa8, 0x76, 0x44, 0xb8, 0xc1, 0xd5, 0x33, 0x25, 0x37, 0xab, - 0xf2, 0x9f, 0xcc, 0xab, 0x8a, 0xe3, 0xe3, 0x88, 0x27, 0x18, 0x82, 0x6b, 0xdb, 0x8d, - 0xbd, 0xb8, 0x51, 0xa4, 0x77, 0x05, 0xeb, 0x0d, 0xec, 0x2d, 0x5e, 0xe9, 0x39, 0xdc, - 0x79, 0x87, 0x25, 0x6f, 0xee, 0xe6, 0x7f, 0x09, 0x90, 0x28, 0xf1, 0x45, 0xe2, 0x0b, - 0xf4, 0x88, 0x94, 0x98, 0x24, 0x30, 0x14, 0x35, 0x13, 0x73, 0xfd, 0xf6, 0x33, 0x01, - 0x8d, 0x21, 0x7c, 0x58, 0x8c, 0x52, 0x98, 0x6f, 0xc5, 0x24, 0xe7, 0x97, 0x97, 0xab, - 0x65, 0x58, 0x43, 0xc2, 0x61, 0xae, 0x7f, 0xc9, 0xcc, 0x3f, 0x47, 0x05, 0x46, 0x00, - 0xe4, 0xcd, 0x38, 0x5c, 0x46, 0x7a, 0x78, 0x8a, 0x9f, 0xff, 0xc3, 0x7e, 0x9d, 0xdb, - 0xb5, 0xd3, 0xe8, 0xa4, 0xbd, 0x0c, 0x4e, 0x8f, 0x56, 0xe5, 0x69, 0x5a, 0xfa, 0x90, - 0xfe, 0x50, 0xce, 0x0a, 0x30, 0x04, 0xfe, 0xd7, 0x12, 0xb4, 0xde, 0x15, 0xad, 0x5f, - 0x01, 0x71, 0xad, 0x51, 0xed, 0xfa, 0x54, 0xdb, 0xd4, 0x8b, 0x1f, 0xcc, 0x5e, 0xf6, - 0xac, 0x73, 0xcf, 0x0a, 0x28, 0xe9, 0xd9, 0x3e, 0x0c, 0xaf, 0xad, 0x88, 0x16, 0x76, - 0x1b, 0x3b, 0xe6, 0x38, 0x39, 0x8c, 0x00, 0x14, 0x33, 0x38, 0xea, 0x27, 0xa9, 0xff, - 0xf2, 0x2e, 0xc4, 0x73, 0x16, 0x36, 0x96, 0x12, 0x25, 0xca, 0x49, 0xe0, 0x13, 0xa6, - 0xdc, 0x80, 0x2b, 0xc7, 0xfb, 0x77, 0xca, 0xd1, 0x0a, 0xca, 0xfe, 0xfc, 0xe5, 0xfa, - 0x9a, 0x37, 0x35, 0x63, 0xb3, 0x91, 0x7a, 0x3a, 0x37, 0x39, 0xcc, 0x97, 0x80, 0xea, - 0x81, 0x50, 0x73, 0xde, 0x8e, 0xb4, 0x2e, 0x3f, 0x66, 0x93, 0xe8, 0x52, 0xbe, 0xfd, - 0xde, 0xdd, 0x61, 0x91, 0x29, 0xd0, 0xaa, 0x13, 0xc4, 0xbd, 0x83, 0x86, 0x22, 0xb5, - 0xe3, 0x28, 0x56, 0x35, 0x8e, 0x6d, 0x82, 0x78, 0x78, 0x95, 0x7e, 0x5d, 0xc8, 0x2c, - 0xd4, 0x37, 0x0b, 0x66, 0x10, 0x84, 0x9e, 0x95, 0x6d, 0x0a, 0x7c, 0xdf, 0xf5, 0x61, - 0x8f, 0x5c, 0x2c, 0xea, 0x61, 0x23, 0x0b, 0x47, 0x00, 0x1c, 0x30, 0xe5, 0xa8, 0xf9, - 0x37, 0xca, 0x7f, 0x9f, 0x9e, 0x66, 0x0f, 0xfa, 0xa7, 0x71, 0x80, 0xcb, 0xa2, 0x6f, - 0x90, 0xda, 0x00, 0x7c, 0xda, 0x40, 0x57, 0xa6, 0xce, 0xa2, 0xe2, 0x6b, 0xfd, 0xe5, - 0x0c, 0x7f, 0x90, 0x79, 0x88, 0x00, 0x53, 0xd0, 0x5d, 0xaa, 0xaa, 0xb3, 0xd7, 0xe4, - 0xdc, 0x9d, 0x81, 0xd0, 0x99, 0x0d, 0x2b, 0xc3, 0x69, 0xa6, 0x6b, 0x55, 0xac, 0x8b, - 0x63, 0x97, 0xbd, 0x47, 0xdb, 0x42, 0x89, 0xc5, 0x45, 0x22, 0x85, 0x55, 0x1a, 0xaa, - 0x7f, 0xa6, 0x7b, 0x01, 0x36, 0xcd, 0x11, 0x9f, 0x87, 0xd8, 0x21, 0x9e, 0x00, 0x02, - 0x97, 0xf0, 0x2c, 0x0c, 0xe6, 0xe3, 0x7b, 0x62, 0x0f, 0x5e, 0x47, 0xfc, 0xa0, 0x3a, - 0xcd, 0xd6, 0x54, 0x4a, 0x47, 0xf4, 0xde, 0xef, 0x19, 0x4f, 0x95, 0x9a, 0xdc, 0x36, - 0x8b, 0x3b, 0x5d, 0x27, 0xd3, 0x83, 0xfe, 0x2f, 0x2b, 0x52, 0x5d, 0xae, 0x04, 0x50, - 0x55, 0x06, 0x35, 0xaa, 0x21, 0x58, 0x18, 0xf7, 0xf5, 0x03, 0x78, 0x90, 0xf0, 0x53, - 0x23, 0x3f, 0x9a, 0xa5, 0x0a, 0xe2, 0x9c, 0x05, 0x56, 0xc3, 0x6d, 0x67, 0xb2, 0x64, - 0x7e, 0x54, 0xeb, 0xe7, 0x58, 0x8e, 0x1f, 0x02, 0xb3, 0xc7, 0x17, 0xdf, 0x02, 0x98, - 0x43, 0x0e, 0xc9, 0xd2, 0xbb, 0x11, 0x4b, 0x35, 0x42, 0xb7, 0x5d, 0x01, 0x0d, 0x93, - 0x4e, 0x58, 0x96, 0xe1, 0xd2, 0xd1, 0x0a, 0x09, 0x20, 0x11, 0x9d, 0xf7, 0x29, 0x2c, - 0x8c, 0x28, 0x47, 0x65, 0x0f, 0xbf, 0x42, 0x80, 0x57, 0x12, 0x8a, 0x02, 0x04, 0x0e, - 0xb3, 0xe3, 0x2d, 0xb5, 0x0c, 0xa7, 0xd8, 0xda, 0x7f, 0xf4, 0xc4, 0xa7, 0xa0, 0xe9, - 0xcf, 0x4b, 0x65, 0x2b, 0x65, 0x3d, 0x42, 0x8f, 0x83, 0xf4, 0x85, 0x33, 0x57, 0x84, - 0x1b, 0x28, 0x13, 0x80, 0x55, 0xb9, 0x13, 0x81, 0x17, 0x79, 0x0a, 0x91, 0xe2, 0x8f, - 0xaa, 0x41, 0x2f, 0xd7, 0xd0, 0x73, 0x32, 0x56, 0x73, 0x44, 0x85, 0xd1, 0xd6, 0xd1, - 0xa9, 0x8c, 0xc2, 0xd7, 0xc8, 0x2b, 0x37, 0x9e, 0x60, 0x72, 0x5d, 0x31, 0x8c, 0x14, - 0x77, 0xce, 0x49, 0x6c, 0x95, 0x86, 0x31, 0x08, 0xa1, 0xc7, 0xe4, 0xf0, 0x20, 0x0b, - 0x7a, 0x3c, 0x08, 0x8d, 0xe7, 0x7e, 0xb4, 0xbc, 0x95, 0xa1, 0xc6, 0xc8, 0x39, 0xd7, - 0x5f, 0xab, 0x59, 0x40, 0xd3, 0x07, 0x94, 0x24, 0xd5, 0x23, 0xd6, 0xd9, 0xa4, 0x6b, - 0xe5, 0x4e, 0x18, 0xf5, 0x29, 0xdc, 0x9e, 0x56, 0x77, 0x6c, 0x5e, 0xc4, 0x51, 0xce, - 0x28, 0x07, 0x9d, 0x37, 0x82, 0x6a, 0xec, 0x40, 0x97, 0xca, 0x7a, 0xee, 0xc8, 0x08, - 0x3f, 0xf5, 0xc4, 0x29, 0x56, 0x9f, 0x91, 0x53, 0xf6, 0x96, 0xbe, 0x62, 0xbd, 0x38, - 0xa3, 0xe7, 0x27, 0xa6, 0x8a, 0xcc, 0xdf, 0xab, 0x02, 0x9b, 0x0b, 0x21, 0xe6, 0xd0, - 0xcd, 0x46, 0x0a, 0x57, 0xd5, 0xf9, 0x03, 0xda, 0x18, 0xa6, 0x07, 0x86, 0xb3, 0x91, - 0xdd, 0x1f, 0x5b, 0xe9, 0x49, 0x82, 0x7e, 0x0c, 0xe7, 0xdf, 0xd1, 0xe0, 0x84, 0x27, - 0xf0, 0xd3, 0xc2, 0x86, 0x53, 0x78, 0xc7, 0x3d, 0x46, 0xa7, 0x3c, 0x55, 0x4a, 0x12, - 0x99, 0x86, 0x02, 0x2a, 0x4f, 0x38, 0x36, 0x0c, 0x39, 0xeb, 0x9c, 0xdd, 0x05, 0x0f, - 0x56, 0xec, 0x05, 0x95, 0x68, 0x65, 0x3c, 0x78, 0x29, 0xe0, 0xa4, 0x4f, 0x2c, 0x70, - 0x10, 0xad, 0xb6, 0x73, 0xe8, 0xde, 0x77, 0x04, 0xe5, 0x4c, 0x03, 0xa7, 0x7a, 0xb7, - 0x8e, 0x85, 0xb6, 0x3f, 0x2b, 0x91, 0x18, 0x5c, 0xa5, 0xda, 0x67, 0xd3, 0x28, 0x30, - 0x65, 0x8b, 0x54, 0xbb, 0x33, 0x58, 0x75, 0x13, 0xc4, 0x2e, 0x03, 0xb5, 0x2c, 0xeb, - 0x9a, 0x19, 0x57, 0xa9, 0xe9, 0x05, 0x84, 0x72, 0x37, 0xce, 0x44, 0x56, 0xe5, 0x33, - 0x50, 0x68, 0x26, 0x49, 0x0e, 0xc5, 0x55, 0x2b, 0x39, 0x12, 0xdb, 0x1c, 0x88, 0x0e, - 0xd4, 0x71, 0xb1, 0x09, 0x29, 0x98, 0xdc, 0xc1, 0x6f, 0xa9, 0x8d, 0x5a, 0xe9, 0xe7, - 0x6f, 0xd2, 0x9d, 0x17, 0x9f, 0xd7, 0x36, 0x59, 0x78, 0xc0, 0x80, 0x44, 0x51, 0x18, - 0x80, 0x1a, 0xc1, 0x0d, 0xc0, 0xf5, 0x78, 0x8f, 0x47, 0x86, 0x69, 0x34, 0xb9, 0x8a, - 0xad, 0xb9, 0xc6, 0x8d, 0xd8, 0x84, 0x83, 0xc1, 0x5d, 0x47, 0xaf, 0x8f, 0xf4, 0x2e, - 0x6b, 0xfb, 0xb8, 0xe0, 0xe5, 0x3a, 0x04, 0x7e, 0x58, 0xe5, 0xba, 0x90, 0xd1, 0xdb, - 0x1e, 0xa1, 0x26, 0x01, 0x7c, 0x65, 0x6d, 0x01, 0x1c, 0x68, 0x7b, 0xb0, 0x4f, 0x47, - 0xa5, 0x60, 0xef, 0x7c, 0xed, 0x23, 0x1b, 0x24, 0x38, 0x7f, 0xf4, 0x01, 0x90, 0x43, - 0xcf, 0xfd, 0x67, 0xfb, 0x9d, 0x89, 0x20, 0x06, 0xc3, 0x91, 0x7f, 0xd7, 0xa9, 0x6f, - 0xe0, 0x3d, 0x7b, 0xea, 0xa2, 0x17, 0x12, 0x8d, 0x71, 0xf0, 0xa2, 0x8a, 0x83, 0x78, - 0x7a, 0x86, 0xcf, 0xc9, 0x33, 0x69, 0xd0, 0xdd, 0x54, 0x65, 0x32, 0x7f, 0xc4, 0x29, - 0x4d, 0xae, 0x81, 0xc4, 0x35, 0x1c, 0x42, 0xa6, 0xf0, 0xa8, 0x0e, 0xef, 0xa6, 0x1d, - 0xb6, 0xa4, 0x0b, 0xb6, 0x81, 0xf5, 0x58, 0xf8, 0x1b, 0x10, 0x1e, 0xb6, 0x57, 0xf6, - 0x57, 0x27, 0xd6, 0x17, 0x69, 0x1b, 0x8b, 0xee, 0x3a, 0xa7, 0xe5, 0x75, 0xb4, 0x11, - 0xa0, 0x12, 0x8a, 0x3f, 0x24, 0x75, 0x3e, 0x52, 0xee, 0x34, 0x90, 0x04, 0xcf, 0x6d, - 0x25, 0xfa, 0xd6, 0xc4, 0x68, 0x1b, 0x02, 0xa2, 0xe1, 0x96, 0x14, 0xe8, 0x0c, 0x95, - 0x83, 0x81, 0x36, 0x2a, 0x91, 0xd3, 0xcd, 0x3b, 0x4e, 0x76, 0x58, 0x32, 0x94, 0x31, - 0x0c, 0x82, 0x41, 0x11, 0x29, 0xac, 0x97, 0xf2, 0xad, 0x5a, 0x5b, 0x9f, 0xa8, 0x64, - 0xa9, 0xc5, 0xd0, 0x2d, 0x8c, 0x92, 0xd6, 0x42, 0x44, 0xfa, 0x6c, 0x40, 0x9c, 0x21, - 0x69, 0x48, 0x62, 0xc4, 0x42, 0x7d, 0xc5, 0x1a, 0xec, 0x57, 0x7f, 0x6e, 0xa3, 0x38, - 0x05, 0x03, 0x13, 0x99, 0x91, 0xe6, 0xe8, 0x89, 0x09, 0x87, 0x64, 0x9f, 0xa7, 0xc4, - 0x3a, 0xc8, 0x03, 0xf6, 0x89, 0xb6, 0x9d, 0x70, 0xab, 0xd7, 0xef, 0xa7, 0x1c, 0xf9, - 0xa0, 0xf2, 0xa4, 0x1d, 0xf9, 0x41, 0x89, 0x76, 0xa4, 0xff, 0xa4, 0x4f, 0x43, 0x75, - 0x92, 0xf1, 0x9c, 0x09, 0xcb, 0x49, 0x31, 0xb3, 0xd3, 0xcd, 0x01, 0x59, 0x31, 0xcf, - 0xfa, 0xe1, 0x71, 0xe0, 0x8a, 0xc5, 0x92, 0x88, 0x61, 0xfc, 0xc3, 0x2e, 0x08, 0x81, - 0x15, 0x59, 0x76, 0x49, 0x66, 0xbe, 0xbc, 0x14, 0x14, 0x36, 0xb9, 0x17, 0xc5, 0x27, - 0x1b, 0x2c, 0x68, 0x0c, 0xdc, 0x50, 0x2c, 0xba, 0xd5, 0x27, 0xac, 0x08, 0x7b, 0x34, - 0x65, 0x6f, 0x75, 0x5d, 0xfb, 0xf0, 0xae, 0x5a, 0xed, 0xc8, 0x09, 0x85, 0xf6, 0x3d, - 0x0c, 0xa4, 0x4a, 0x76, 0x2f, 0x9b, 0x31, 0x1f, 0x15, 0x6d, 0xe6, 0x27, 0x74, 0x19, - 0x19, 0x99, 0x8e, 0x67, 0x44, 0x66, 0xc7, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x04, 0xc4, - 0x9e, 0xb1, 0x87, 0xfb, 0xf7, 0x5e, 0x5f, 0x7c, 0xee, 0x26, 0x1e, 0x30, 0x75, 0xc2, - 0xb2, 0xc2, 0x81, 0x2f, 0xe8, 0x32, 0x32, 0xc4, 0x1a, 0x5f, 0x10, 0xf4, 0x0b, 0x91, - 0x1e, 0xbc, 0xeb, 0xb7, 0x8c, 0x91, 0xc2, 0x0b, 0x82, 0xc0, 0x05, 0x0f, 0xe2, 0xee, - 0x10, 0x4b, 0x39, 0x20, 0xed, 0x0a, 0x05, 0xd1, 0x7b, 0x06, 0x0d, 0x99, 0xd5, 0x87, - 0x01, 0x98, 0xe6, 0x3c, 0xcf, 0x51, 0xb1, 0x5d, 0xf8, 0x0e, 0x87, 0xac, 0xbd, 0x30, - 0x12, 0x6c, 0xda, 0x2a, 0xff, 0xb8, 0xf1, 0xce, 0xcb, 0x1b, 0xaa, 0x6a, 0x91, 0x9e, - 0x0a, 0x97, 0x87, 0x91, 0x39, 0x69, 0x04, 0x44, 0x9a, 0xde, 0x4b, 0x0b, 0x02, 0x92, - 0x0f, 0xb8, 0xc0, 0xbf, 0x7f, 0xc0, 0x82, 0xeb, 0x74, 0x98, 0x73, 0xc1, 0x0d, 0x17, - 0xdb, 0xd9, 0x1f, 0xfe, 0xa9, 0x36, 0x10, 0xee, 0xea, 0x62, 0x57, 0x90, 0xad, 0xa2, - 0x8e, 0x3a, 0x2c, 0xf2, 0x2c, 0x0d, 0x4e, 0xa2, 0xb9, 0x26, 0x41, 0xf2, 0x16, 0xd3, - 0x92, 0x2c, 0x1f, 0xc3, 0x2d, 0xbc, 0x1e, 0x0e, 0x99, 0x00, 0x38, 0x6c, 0xf8, 0x98, - 0xcb, 0x8e, 0xd5, 0x6c, 0x06, 0x4e, 0x5b, 0x12, 0xb0, 0x26, 0xbf, 0x03, 0x5d, 0xfb, - 0xc4, 0xeb, 0x92, 0xce, 0x33, 0xf8, 0x2b, 0xbe, 0x48, 0xca, 0x94, 0x5f, 0x12, 0x44, - 0x83, 0x10, 0xd7, 0xb9, 0xdb, 0x85, 0xf1, 0xb0, 0x46, 0xdc, 0x9c, 0x56, 0x51, 0x2f, - 0x61, 0xe0, 0xa3, 0x96, 0x6f, 0xa4, 0xab, 0x71, 0xd1, 0x5f, 0x4e, 0x23, 0xe4, 0xe3, - 0x1c, 0xb9, 0x62, 0x10, 0x60, 0x14, 0xc4, 0xc2, 0x9e, 0xc3, 0xb9, 0x10, 0xe0, 0x72, - 0x2d, 0xac, 0x38, 0xaa, 0x4d, 0xc8, 0x1e, 0x17, 0x6d, 0x72, 0xfe, 0xaf, 0x2f, 0x93, - 0xf9, 0xec, 0xd5, 0x04, 0xcb, 0xaf, 0x95, 0x59, 0x83, 0x30, 0x09, 0xd9, 0x2c, 0x9d, - 0x2f, 0x81, 0x68, 0x7b, 0xf5, 0x89, 0xa4, 0x93, 0x66, 0xcd, 0x0a, 0xba, 0xe7, 0xa1, - 0x74, 0xa4, 0x8f, 0xf7, 0x6c, 0xd7, 0x2f, 0x02, 0xb1, 0x8a, 0xf8, 0x18, 0x75, 0x26, - 0xd4, 0x70, 0x94, 0x9c, 0xb8, 0xd9, 0x3e, 0xfe, 0x6c, 0x5b, 0xc7, 0x91, 0xca, 0x93, - 0xb1, 0x10, 0xc1, 0x82, 0x5b, 0x6a, 0xfb, 0x04, 0x5d, 0x9d, 0x8c, 0xa3, 0x51, 0xf7, - 0xad, 0xa3, 0x28, 0xfd, 0xd5, 0x2a, 0xec, 0x29, 0x77, 0xd2, 0x94, 0x0e, 0x2c, 0xdc, - 0xb2, 0x66, 0x4d, 0x78, 0xb7, 0x6a, 0xc0, 0xe0, 0x6d, 0x78, 0x8e, 0x57, 0xf8, 0x24, - 0x4f, 0x44, 0x2c, 0x88, 0x6a, 0x8f, 0x31, 0x13, 0x7c, 0xd7, 0xf1, 0x9e, 0x82, 0x21, - 0xa3, 0x85, 0xcb, 0xfb, 0x3f, 0x7f, 0x2a, 0x1e, 0x79, 0x50, 0x4b, 0xcf, 0x1a, 0xe0, - 0x83, 0xb1, 0x29, 0x02, 0xa5, 0x01, 0x2c, 0xd5, 0xea, 0x2f, 0xc8, 0x56, 0x43, 0xdd, - 0xec, 0xee, 0xf4, 0xab, 0x95, 0x93, 0x43, 0x21, 0x9b, 0x0c, 0x63, 0xdd, 0x0a, 0x8b, - 0x0e, 0x23, 0x3e, 0xfc, 0x68, 0xfc, 0x63, 0x30, 0x73, 0xe6, 0x6c, 0x59, 0x97, 0x5f, - 0x23, 0x52, 0x4b, 0x6a, 0xa1, 0xab, 0x9a, 0xe7, 0xb1, 0x33, 0xd5, 0xf3, 0x0c, 0xf9, - 0xe1, 0xd0, 0xf9, 0xba, 0xd7, 0x1f, 0x67, 0x3f, 0x5b, 0x75, 0x4c, 0xf4, 0x00, 0x99, - 0x77, 0x57, 0xa6, 0x45, 0x8a, 0xd3, 0xb9, 0xdc, 0x8e, 0xc0, 0xc6, 0x9c, 0x66, 0x09, - 0x66, 0x3b, 0x42, 0xbb, 0xb0, 0xca, 0x1a, 0x55, 0x73, 0x37, 0x42, 0x81, 0x1f, 0x0d, - 0x71, 0x30, 0xe0, 0x13, 0xfe, 0x2f, 0x88, 0x05, 0x8e, 0xe8, 0x9b, 0x90, 0xa7, 0x5c, - 0xd0, 0x69, 0xda, 0xf1, 0x00, 0x37, 0x25, 0x4d, 0x10, 0x16, 0xd3, 0xac, 0xf7, 0xe6, - 0x2f, 0x18, 0x3b, 0x2c, 0x55, 0x1a, 0x59, 0x90, 0xe4, 0xed, 0x73, 0xdc, 0xd8, 0x94, - 0xf7, 0x85, 0x70, 0xfd, 0x19, 0x56, 0xcb, 0x22, 0x7c, 0x65, 0x00, 0x01, 0xf2, 0x7f, - 0x94, 0x23, 0xf4, 0xed, 0x12, 0x56, 0x0b, 0x2e, 0x1c, 0x8d, 0xbc, 0xb4, 0xc3, 0x02, - 0x15, 0xb2, 0x16, 0x7f, 0x02, 0xef, 0xeb, 0x70, 0x7a, 0xf1, 0xb5, 0xc7, 0x84, 0xb7, - 0xf5, 0x8b, 0x2e, 0x51, 0x73, 0x03, 0xf3, 0xaf, 0x71, 0xb1, 0xee, 0x39, 0xa9, 0xae, - 0x06, 0xb9, 0x77, 0x28, 0xe6, 0x4f, 0x67, 0x6d, 0xed, 0x50, 0xa3, 0xf5, 0x1b, 0xc9, - 0xe0, 0x17, 0x07, 0xbf, 0x57, 0x95, 0x6f, 0x01, 0xb7, 0xda, 0x7c, 0x23, 0xe6, 0x93, - 0x52, 0x06, 0x57, 0x28, 0x6f, 0xe7, 0x3e, 0xee, 0x9e, 0xb1, 0xd5, 0x83, 0x75, 0x22, - 0x03, 0xf3, 0xd9, 0x2b, 0xd4, 0x04, 0x7b, 0x83, 0xfd, 0x38, 0xf5, 0x66, 0xdd, 0x25, - 0xb9, 0x6d, 0x11, 0xb7, 0x22, 0x2b, 0x67, 0x82, 0xda, 0xde, 0xf5, 0xee, 0x78, 0x82, - 0x14, 0x7c, 0xbb, 0x4f, 0xcf, 0xe7, 0x0d, 0x2c, 0xa7, 0xf3, 0x9a, 0x29, 0x7b, 0x21, - 0xd5, 0x6d, 0x66, 0x10, 0xe9, 0xda, 0x9d, 0x8e, 0xef, 0xdc, 0x69, 0x9e, 0x4a, 0x30, - 0x06, 0x8a, 0x14, 0x57, 0xcf, 0x5e, 0xaf, 0x69, 0x87, 0x78, 0x21, 0xd3, 0x9e, 0xa0, - 0x85, 0x94, 0xc2, 0xfb, 0x9e, 0xb9, 0xd8, 0x04, 0x64, 0x50, 0xe4, 0x13, 0x03, 0xf1, - 0x95, 0xbd, 0xc9, 0x05, 0xe4, 0xf2, 0x58, 0x3c, 0x6a, 0xe3, 0x86, 0x1b, 0x87, 0x19, - 0xbb, 0xce, 0xd1, 0xce, 0x58, 0xc4, 0x68, 0x81, 0x6d, 0x45, 0x15, 0xe6, 0x09, 0x7b, - 0x3e, 0x2e, 0x81, 0x82, 0x21, 0x0f, 0x6c, 0x1b, 0xb3, 0xaa, 0xa6, 0x2a, 0xe0, 0xf6, - 0x9f, 0x79, 0xfc, 0xc5, 0x47, 0xba, 0xab, 0x31, 0x1d, 0x99, 0x7c, 0x84, 0x95, 0xd6, - 0xab, 0xe3, 0xa5, 0x1f, 0x56, 0x53, 0xf3, 0x1c, 0x5a, 0x2e, 0xea, 0x8d, 0x31, 0x90, - 0x97, 0xf3, 0x04, 0x5e, 0x6c, 0x3c, 0x3d, 0x8c, 0x87, 0xc9, 0xbd, 0x55, 0xb4, 0x19, - 0x2e, 0xbf, 0x00, 0xff, 0x8f, 0xc7, 0xf4, 0x1e, 0x18, 0x93, 0x0a, 0x99, 0x72, 0xa3, - 0x4d, 0x9e, 0x6a, 0xa9, 0xd9, 0x1d, 0x2e, 0x28, 0x17, 0xeb, 0x6d, 0xe9, 0xba, 0x38, - 0x9e, 0x69, 0xaa, 0x51, 0x2f, 0x3f, 0xb4, 0xdf, 0xf8, 0xca, 0x1c, 0xe7, 0xc9, 0xca, - 0x39, 0x6e, 0x8a, 0x9d, 0x99, 0xd4, 0x96, 0x51, 0xb0, 0x58, 0x2f, 0xc5, 0x86, 0xce, - 0x92, 0x7e, 0xa2, 0x64, 0x5b, 0xda, 0xa3, 0x79, 0x28, 0x6f, 0x95, 0xd3, 0x9b, 0x95, - 0x81, 0xde, 0xb2, 0xc5, 0x37, 0x75, 0xae, 0xef, 0x20, 0xe7, 0xbd, 0xbc, 0x3b, 0x19, - 0xd8, 0x9b, 0xac, 0xee, 0xa1, 0x3b, 0x74, 0xe6, 0xc7, 0xf5, 0x20, 0x89, 0x39, 0x7d, - 0x11, 0x6e, 0xbf, 0xac, 0x6a, 0x30, 0xed, 0x27, 0xd6, 0x27, 0x81, 0xa0, 0x3b, 0x66, - 0xb0, 0x52, 0xf7, 0x51, 0xfb, 0x36, 0x88, 0x2b, 0x9a, 0x14, 0x34, 0x23, 0xad, 0x02, - 0xf3, 0x36, 0x0a, 0xfa, 0x54, 0xc4, 0xcf, 0x23, 0x53, 0x0c, 0x68, 0xd6, 0x0e, 0x99, - 0x56, 0x1c, 0xce, 0x0d, 0x6a, 0x9c, 0x32, 0xef, 0xc7, 0x1f, 0xef, 0xaf, 0x23, 0x57, - 0x86, 0x3f, 0xa0, 0xb9, 0xf7, 0xbe, 0x76, 0xc2, 0xd1, 0xd3, 0x88, 0x49, 0xa0, 0x0a, - 0xb0, 0x41, 0xf1, 0x82, 0xad, 0x63, 0x35, 0xe9, 0x55, 0xcc, 0x65, 0xcd, 0xfd, 0x3b, - 0x69, 0x1a, 0x3d, 0x96, 0xc4, 0xbd, 0x56, 0xf5, 0x25, 0xce, 0xdb, 0x7f, 0xdc, 0xb7, - 0x33, 0xe7, 0x67, 0x06, 0x2f, 0xd8, 0xa4, 0xef, 0x1a, 0x4b, 0x71, 0x5e, 0x5e, 0xdf, - 0x76, 0x26, 0x14, 0x4e, 0x28, 0x5f, 0x2b, 0x3c, 0x4e, 0x2c, 0xb4, 0x1b, 0x7d, 0xb9, - 0x66, 0x35, 0x82, 0xad, 0x65, 0xa5, 0x41, 0x6e, 0x57, 0xf7, 0x48, 0x5f, 0x39, 0xc0, - 0x5e, 0x8e, 0x7a, 0xf9, 0x6b, 0x36, 0x78, 0xc8, 0x0a, 0x8d, 0x4b, 0xa2, 0xf9, 0x5d, - 0x5f, 0xeb, 0x0c, 0xcb, 0x0f, 0x71, 0x7b, 0x9d, 0xb7, 0x24, 0xab, 0xf4, 0xcc, 0xd4, - 0x10, 0x49, 0x00, 0x18, 0x6f, 0x4a, 0x93, 0x0d, 0x4b, 0x2a, 0xcb, 0x9f, 0x9a, 0x16, - 0xaf, 0x89, 0x77, 0x27, 0x7d, 0x6f, 0x0b, 0xc9, 0x0a, 0xb8, 0x59, 0xc3, 0x33, 0x3b, - 0x3d, 0xe8, 0x6f, 0x41, 0xfa, 0x85, 0xd5, 0x70, 0xf1, 0x6c, 0x74, 0x82, 0x0a, 0x70, - 0x41, 0xfe, 0xa1, 0x5e, 0xe9, 0x50, 0xc3, 0x30, 0xac, 0xa3, 0xf1, 0xe5, 0x1c, 0x69, - 0x44, 0x74, 0x72, 0xf2, 0x6a, 0x3d, 0x67, 0x41, 0xbc, 0x67, 0xe9, 0x2e, 0x00, 0xa0, - 0x83, 0xb6, 0x95, 0x33, 0x03, 0xb3, 0x73, 0x1c, 0xf2, 0x84, 0x8d, 0x81, 0x7c, 0xeb, - 0x77, 0xf1, 0xcc, 0xa7, 0x1e, 0xc9, 0x13, 0x91, 0x20, 0x2b, 0x73, 0x4d, 0x54, 0x8f, - 0xa3, 0x14, 0x2c, 0x37, 0xe6, 0xfc, 0xac, 0x51, 0x92, 0xfc, 0xa2, 0x8d, 0x63, 0x98, - 0x1f, 0x67, 0xdd, 0xdc, 0x28, 0xb3, 0x1f, 0xd0, 0xb9, 0x3a, 0x7f, 0x21, 0x88, 0xc1, - 0xec, 0xa2, 0xc1, 0xef, 0xa4, 0x61, 0xd2, 0xdd, 0x73, 0x38, 0xdf, 0x07, 0x05, 0xae, - 0x70, 0x10, 0x62, 0xfb, 0xcd, 0x8d, 0x50, 0x29, 0x98, 0x85, 0xd8, 0xe3, 0xd4, 0xfb, - 0xd6, 0xa4, 0xf2, 0x15, 0x5d, 0xc8, 0xd8, 0xfd, 0x0b, 0x05, 0x8f, 0x3c, 0x77, 0x50, - 0x83, 0xf5, 0x96, 0x12, 0xac, 0x66, 0x02, 0xd9, 0xad, 0xfa, 0x49, 0xe2, 0x60, 0x2a, - 0x12, 0xf2, 0x90, 0x0d, 0x22, 0xb9, 0x9c, 0x0b, 0x8a, 0x32, 0x68, 0xa0, 0x19, 0xc0, - 0xdd, 0xf3, 0x14, 0x3e, 0x8a, 0xf4, 0x13, 0x07, 0xd9, 0x26, 0x74, 0x02, 0x13, 0x08, - 0x59, 0xee, 0x92, 0x43, 0x4d, 0x23, 0x79, 0xe9, 0x4b, 0xcb, 0xbe, 0x56, 0x1d, 0xe0, - 0x42, 0x92, 0xb5, 0x32, 0xab, 0xc3, 0x5d, 0xde, 0x53, 0xd2, 0xad, 0x86, 0x7f, 0x7a, - 0xd9, 0x42, 0x00, 0xe4, 0x8e, 0x50, 0x3e, 0x7d, 0x41, 0x6b, 0xcf, 0x98, 0x29, 0x9f, - 0x82, 0xfc, 0xba, 0xe2, 0xdc, 0x42, 0xae, 0xc1, 0x8a, 0x29, 0x3b, 0x63, 0x79, 0x5b, - 0x68, 0x63, 0xf3, 0x22, 0x49, 0xcd, 0x20, 0x5e, 0x54, 0xd7, 0xcb, 0x7c, 0x82, 0x3b, - 0x00, 0x74, 0x77, 0x35, 0x96, 0xc1, 0xc5, 0x33, 0x92, 0x1d, 0x3b, 0xae, 0x11, 0xfe, - 0x1c, 0x6b, 0xfb, 0x77, 0x74, 0xe1, 0x49, 0x88, 0x64, 0xf3, 0xb6, 0x26, 0xd4, 0xcb, - 0x14, 0x47, 0x95, 0xd8, 0xf3, 0x59, 0xf5, 0xc5, 0x5d, 0xa3, 0xd7, 0x11, 0x70, 0x4e, - 0x74, 0x29, 0x58, 0x95, 0x5e, 0xaf, 0xa4, 0xb7, 0xd0, 0x31, 0xb2, 0xd6, 0xda, 0x0c, - 0x52, 0x9d, 0x41, 0xf3, 0x16, 0x93, 0xe4, 0xe5, 0x10, 0xb6, 0xb1, 0xe4, 0xab, 0xb6, - 0x01, 0x5f, 0x0d, 0x6d, 0x12, 0x61, 0x5e, 0xc1, 0xea, 0xf2, 0x75, 0xd4, 0x62, 0x96, - 0x2f, 0x17, 0x68, 0x4a, 0x7a, 0x25, 0x30, 0x1a, 0x99, 0x55, 0x5d, 0xef, 0x47, 0x15, - 0xff, 0x62, 0xce, 0x3c, 0xa6, 0x2f, 0x82, 0xe1, 0xf0, 0xec, 0x3b, 0x76, 0xd9, 0xea, - 0x82, 0x5a, 0xbc, 0x46, 0xfa, 0x2c, 0xf2, 0xb7, 0xa9, 0x64, 0x3e, 0xf2, 0x11, 0x0d, - 0x16, 0xef, 0x7a, 0x37, 0x0a, 0x5a, 0x99, 0xc0, 0xf7, 0x3d, 0xd2, 0x07, 0xb7, 0xba, - 0xc5, 0x2f, 0x36, 0x7d, 0xc4, 0xba, 0x9f, 0x52, 0x1c, 0x2d, 0x48, 0x77, 0xba, 0x68, - 0x98, 0xb8, 0xc9, 0x0c, 0x6d, 0xa7, 0x33, 0x64, 0x5c, 0xfb, 0x78, 0xc6, 0xf4, 0x09, - 0x92, 0xc7, 0x20, 0x96, 0x8f, 0xe4, 0x3c, 0x32, 0xbb, 0x59, 0x39, 0x9b, 0xa8, 0x82, - 0x36, 0x06, 0x4a, 0xa0, 0xa6, 0x8f, 0x1a, 0x5a, 0xfa, 0xae, 0xd0, 0xf5, 0x39, 0xc2, - 0x4e, 0xf9, 0xe6, 0x9d, 0x37, 0xdd, 0xba, 0x2d, 0x15, 0x86, 0xc0, 0x3b, 0x52, 0x45, - 0x48, 0xd8, 0x20, 0x7d, 0xa9, 0x58, 0x92, 0xc0, 0x0a, 0xcf, 0xee, 0x51, 0xb2, 0x42, - 0x4c, 0x2d, 0x1a, 0x4d, 0x7d, 0x4d, 0xd9, 0x8a, 0x1c, 0x6f, 0x2a, 0x5f, 0x6b, 0x39, - 0x20, 0x64, 0x30, 0xf1, 0x84, 0x37, 0x3a, 0x96, 0xc6, 0xaa, 0x58, 0xcc, 0xe2, 0xe1, - 0xc5, 0x04, 0xd4, 0x0e, 0xe9, 0xef, 0xda, 0x58, 0x8d, 0x43, 0xef, 0xb1, 0xda, 0x53, - 0xc7, 0x3d, 0x53, 0x0f, 0xa7, 0x6b, 0x11, 0x2f, 0x33, 0xb4, 0xaf, 0xa9, 0x41, 0xcd, - 0x1e, 0x20, 0x5a, 0xcd, 0x72, 0xca, 0x86, 0x84, 0xad, 0xe8, 0x33, 0x3d, 0x46, 0x32, - 0xab, 0x94, 0x3d, 0x69, 0x0f, 0x13, 0x2b, 0xc9, 0x9f, 0x5c, 0x5a, 0x1d, 0x3e, 0xa4, - 0xe0, 0xca, 0x8f, 0x43, 0x23, 0x8c, 0xd9, 0xeb, 0x09, 0xc8, 0xbf, 0x11, 0xe9, 0x18, - 0xa9, 0xc7, 0xf8, 0x83, 0xbe, 0x94, 0x89, 0x06, 0x56, 0x33, 0x66, 0x67, 0x95, 0x4a, - 0x51, 0xa8, 0xae, 0xcd, 0xc4, 0xcb, 0xd3, 0x9a, 0xca, 0xc7, 0x52, 0x05, 0x6e, 0x71, - 0xcc, 0x96, 0x91, 0x55, 0xdd, 0x65, 0x6d, 0x79, 0x59, 0x00, 0x8c, 0x0e, 0xcf, 0x61, - 0x83, 0x2a, 0x5c, 0x44, 0xe2, 0xe0, 0xde, 0x68, 0xf5, 0x04, 0xc1, 0x77, 0xdf, 0x68, - 0x8b, 0xee, 0x55, 0x8c, 0x6f, 0x4e, 0x5e, 0xa5, 0xf9, 0xad, 0x78, 0x26, 0x73, 0x40, - 0xe2, 0xc8, 0x35, 0xb9, 0x74, 0xdd, 0x12, 0xcd, 0xb9, 0x05, 0x08, 0x87, 0x60, 0x34, - 0xdd, 0xde, 0x0d, 0x97, 0xea, 0xfa, 0xf9, 0x70, 0x18, 0x34, 0x90, 0xcd, 0x22, 0xea, - 0x57, 0xb9, 0x8a, 0xbd, 0x1a, 0x7f, 0x79, 0xe2, 0xcf, 0x23, 0xcf, 0x8d, 0x1b, 0x0e, - 0x9b, 0x7c, 0x93, 0x8a, 0xcc, 0x6b, 0x14, 0x4b, 0x54, 0x13, 0xd3, 0x2f, 0x50, 0xcd, - 0x09, 0x61, 0x8f, 0xa9, 0x74, 0x10, 0x3a, 0x72, 0x8e, 0x2b, 0x71, 0x76, 0x63, 0xd4, - 0xbd, 0x9b, 0x07, 0x20, 0xb7, 0x75, 0xf5, 0xee, 0x25, 0xa6, 0xd7, 0x4d, 0x12, 0x8c, - 0x49, 0xb4, 0x0a, 0x19, 0x74, 0x1c, 0x37, 0xdd, 0x34, 0x61, 0x6d, 0xb3, 0x1e, 0xac, - 0x0b, 0xe7, 0xf5, 0x3f, 0xfa, 0x61, 0x9f, 0x45, 0x18, 0x1f, 0x5a, 0x4d, 0xbe, 0x5b, - 0x1b, 0x48, 0x09, 0x8e, 0xba, 0x2c, 0x2e, 0xc2, 0x0a, 0x0a, 0xc0, 0x44, 0x3b, 0xa8, - 0xe9, 0x48, 0x7b, 0xcf, 0x7d, - ], - script_code: vec![0xac, 0x53, 0x63, 0x52, 0x6a, 0x51, 0xac], - transparent_input: None, - hash_type: 1, - amount: 1501997449504444, - consensus_branch_id: 1991772603, - sighash: [ - 0xa1, 0xcf, 0x50, 0xcf, 0xfe, 0x59, 0xbe, 0x5f, 0x31, 0x5f, 0xfe, 0x51, 0x6e, 0x28, - 0x9e, 0xe8, 0x02, 0x5e, 0x59, 0x38, 0xf1, 0xe8, 0xe1, 0x88, 0x53, 0x7f, 0xf1, 0xa8, - 0x93, 0xac, 0x71, 0x14, - ], - }, - TestVector { - tx: vec![ - 0x04, 0x00, 0x00, 0x80, 0x85, 0x20, 0x2f, 0x89, 0x02, 0x88, 0x1d, 0xdf, 0x4f, 0x95, - 0x78, 0x97, 0x34, 0xfc, 0xc1, 0x65, 0xee, 0x1e, 0x04, 0x40, 0x85, 0xb6, 0xe7, 0xa1, - 0x77, 0x50, 0x8c, 0x29, 0xda, 0x0c, 0xe7, 0x7d, 0xed, 0x75, 0x08, 0x98, 0xde, 0x89, - 0xd2, 0x60, 0xd3, 0x02, 0x63, 0x52, 0x44, 0xcc, 0x75, 0xe1, 0x98, 0x34, 0x52, 0x5f, - 0xba, 0x56, 0x90, 0x0d, 0xe9, 0x93, 0x85, 0x44, 0x2e, 0xb9, 0xec, 0x9a, 0x5f, 0x18, - 0x2b, 0x87, 0x5d, 0x70, 0xb5, 0xb1, 0x53, 0x79, 0x0a, 0x1e, 0xe7, 0x9c, 0x0e, 0x86, - 0x78, 0x37, 0x95, 0xfa, 0x06, 0x6a, 0x00, 0x63, 0x00, 0x00, 0x63, 0xfc, 0x92, 0x29, - 0x92, 0x00, 0x83, 0x64, 0xff, 0xfc, 0x7c, 0x00, 0xc0, 0x0e, 0x0f, 0x99, 0xde, 0x47, - 0x42, 0x89, 0x06, 0x00, 0x01, 0x39, 0x21, 0x97, 0xd6, 0x23, 0xf7, 0xeb, 0xda, 0x07, - 0xcd, 0x00, 0x58, 0xd9, 0xa1, 0xd1, 0x72, 0x04, 0x3c, 0x2f, 0xc9, 0x4f, 0x14, 0x19, - 0x3e, 0x27, 0x0e, 0xef, 0xe8, 0x3c, 0x3f, 0x01, 0xb2, 0x65, 0x05, 0x4c, 0x3f, 0x6a, - 0x60, 0xe2, 0xb7, 0x6e, 0x17, 0x56, 0x08, 0x8b, 0x87, 0xda, 0x83, 0x9f, 0x77, 0x2c, - 0xbd, 0x0f, 0x27, 0x5c, 0x92, 0x28, 0x38, 0x5a, 0x04, 0xbb, 0x50, 0xec, 0x3c, 0xfa, - 0x9e, 0xe2, 0xe1, 0x5b, 0x15, 0x3d, 0x4c, 0x85, 0xfe, 0x50, 0xb6, 0x00, 0x62, 0x58, - 0xe9, 0xe8, 0xc2, 0x52, 0x99, 0xc0, 0x9d, 0xf8, 0xb4, 0x55, 0x46, 0x6b, 0xa2, 0x5f, - 0x7e, 0x4c, 0x8f, 0xe7, 0xe2, 0x50, 0xed, 0xba, 0x60, 0x69, 0x5d, 0xa4, 0x7f, 0xaa, - 0xfd, 0xd6, 0x26, 0xba, 0x7e, 0x9d, 0x48, 0x96, 0xe4, 0xb8, 0xa8, 0xa1, 0xa1, 0xdc, - 0x21, 0x5b, 0x0a, 0x25, 0xee, 0xb0, 0x4e, 0xd1, 0xbe, 0xfb, 0x5b, 0x31, 0x38, 0xc6, - 0x9f, 0xe5, 0x28, 0xe7, 0x29, 0x11, 0x23, 0xfc, 0xdf, 0x8a, 0x36, 0x6c, 0x25, 0x7d, - 0x32, 0x95, 0x38, 0x25, 0x0a, 0x0c, 0xb7, 0xf5, 0x4e, 0x1c, 0x01, 0x6c, 0xe1, 0xc6, - 0x23, 0xb2, 0xe2, 0x76, 0xa5, 0x2c, 0x6e, 0x41, 0x24, 0x1b, 0x2a, 0xc5, 0x09, 0x37, - 0x3c, 0x18, 0x81, 0x40, 0xe8, 0x36, 0x5c, 0x94, 0xf5, 0x8c, 0x63, 0xf2, 0x7f, 0xf8, - 0xe6, 0xe8, 0x69, 0xa9, 0x85, 0xaf, 0xb6, 0x1e, 0x97, 0xd8, 0xce, 0xec, 0x2a, 0x78, - 0x24, 0xa5, 0xc1, 0x07, 0xb0, 0xba, 0xa4, 0xd6, 0xe7, 0x9a, 0x6c, 0x71, 0x87, 0x2a, - 0x7b, 0x3b, 0x17, 0xef, 0x91, 0x8a, 0xe4, 0xe2, 0x5f, 0x98, 0xa7, 0x2d, 0xb5, 0x3b, - 0xa7, 0xf2, 0x6e, 0x40, 0x8b, 0xd4, 0xd1, 0xf9, 0xe3, 0x47, 0x4d, 0xdc, 0xa5, 0x83, - 0x3f, 0xf5, 0xff, 0x8d, 0x11, 0xb1, 0xbf, 0x1e, 0x2b, 0xb4, 0xd1, 0x96, 0x8a, 0x82, - 0x38, 0x88, 0xbd, 0x91, 0xa2, 0x1a, 0x76, 0x79, 0x6b, 0xca, 0x44, 0x53, 0xe2, 0x89, - 0x2d, 0x1b, 0x6e, 0x13, 0x63, 0xed, 0x10, 0x7a, 0x9e, 0x7e, 0xd9, 0x3f, 0xb1, 0xda, - 0x99, 0x4a, 0x9d, 0x4e, 0x7e, 0xc9, 0x2e, 0x29, 0xa6, 0x87, 0xf2, 0x18, 0xd2, 0x8a, - 0x76, 0x46, 0x06, 0x9b, 0xca, 0xcb, 0x4d, 0xa7, 0xba, 0xdf, 0x4e, 0xb1, 0x33, 0x1a, - 0xab, 0x21, 0x2b, 0x92, 0xc6, 0xea, 0x64, 0x76, 0xa0, 0xa0, 0x9d, 0x6b, 0xd2, 0xe0, - 0xf7, 0x6f, 0xa8, 0x73, 0x79, 0xab, 0xfd, 0x17, 0x58, 0x2f, 0x3e, 0xb2, 0x3b, 0x86, - 0xc9, 0x66, 0x9f, 0x86, 0x73, 0x70, 0x48, 0xd7, 0x71, 0x84, 0x9b, 0x8f, 0x70, 0xbd, - 0x87, 0x99, 0x01, 0x3b, 0xe0, 0xbf, 0xbd, 0x7b, 0x57, 0xbe, 0xa1, 0xa4, 0x9a, 0x4a, - 0x39, 0x14, 0x79, 0x12, 0xd7, 0xba, 0xf6, 0x80, 0x04, 0xd4, 0x15, 0x02, 0x6b, 0xbc, - 0x6f, 0x69, 0x32, 0x5f, 0x4f, 0xf7, 0x87, 0x28, 0x77, 0x5a, 0x67, 0xaa, 0xdd, 0x72, - 0x2c, 0x73, 0x31, 0x1d, 0xba, 0x5c, 0x2c, 0xf1, 0x4c, 0xcb, 0xd5, 0x7e, 0xab, 0xed, - 0x71, 0x92, 0x0f, 0xf9, 0x62, 0x32, 0x89, 0xbb, 0x76, 0x05, 0x1c, 0x73, 0xa2, 0x06, - 0xa3, 0xc2, 0xb4, 0x0c, 0xac, 0x01, 0xd5, 0xf1, 0x1f, 0xa6, 0x4c, 0x1b, 0x7d, 0xed, - 0x70, 0xea, 0x17, 0x42, 0x9c, 0x66, 0x21, 0xca, 0x9b, 0x92, 0x3c, 0x48, 0x11, 0x85, - 0x0c, 0x3d, 0xf4, 0x01, 0x3d, 0x17, 0xbd, 0xc5, 0x10, 0x1c, 0x8d, 0x80, 0xb3, 0xa0, - 0x4a, 0x4c, 0xc2, 0x3d, 0x13, 0xfe, 0x31, 0x84, 0xe8, 0xb1, 0xad, 0xe6, 0x35, 0x17, - 0x59, 0x3f, 0x7b, 0xe6, 0x69, 0x48, 0xc0, 0x85, 0x7a, 0xec, 0xe0, 0x1b, 0xc2, 0x72, - 0x29, 0x5e, 0x60, 0xb1, 0x80, 0x69, 0x46, 0xc9, 0x3b, 0xc8, 0xc7, 0xd2, 0xa2, 0xed, - 0xc3, 0x7f, 0xa3, 0x7c, 0x47, 0x7a, 0x69, 0xa9, 0x0b, 0x59, 0xb4, 0xc6, 0x91, 0x2e, - 0x91, 0x3a, 0x57, 0xef, 0xa9, 0xd5, 0x4c, 0x7e, 0x80, 0xd5, 0xac, 0x8a, 0x42, 0x94, - 0xd0, 0xfd, 0x31, 0xa4, 0x02, 0xe4, 0xb4, 0x7e, 0xc7, 0xbf, 0x03, 0x31, 0xb2, 0xc9, - 0xa4, 0x8f, 0x44, 0x57, 0x3f, 0xc7, 0xe7, 0xf1, 0x02, 0xed, 0x48, 0xc9, 0x75, 0x08, - 0xcb, 0xe4, 0x30, 0x65, 0xa9, 0xe9, 0x9f, 0xb4, 0xce, 0x13, 0x62, 0xbb, 0x8a, 0x76, - 0xb1, 0x41, 0x9d, 0x95, 0x03, 0x0e, 0x9c, 0x24, 0xee, 0xba, 0x9f, 0xf8, 0xcf, 0xda, - 0x95, 0x7b, 0x17, 0x09, 0x8c, 0xdf, 0x8c, 0x9a, 0x91, 0x9e, 0x47, 0xa1, 0x3a, 0x5b, - 0x33, 0x46, 0xe3, 0x7e, 0x82, 0x7c, 0xc8, 0x3b, 0x3c, 0x9a, 0xab, 0xf2, 0xd0, 0xba, - 0x17, 0xff, 0x3d, 0x9e, 0x0d, 0x22, 0x3c, 0x41, 0xc8, 0x8e, 0xc2, 0x39, 0x1c, 0x76, - 0x62, 0x2d, 0x7b, 0xd6, 0x21, 0x17, 0x33, 0x1e, 0x21, 0xff, 0xec, 0x32, 0x72, 0xc1, - 0xe1, 0x42, 0x39, 0x82, 0xc6, 0xb6, 0x3a, 0xec, 0x8d, 0xbf, 0x5c, 0xa2, 0xdd, 0x15, - 0x81, 0x0f, 0x53, 0x42, 0xaf, 0x49, 0xfa, 0xd2, 0x79, 0xb7, 0xca, 0x23, 0xde, 0xd3, - 0x08, 0x24, 0x79, 0x96, 0x30, 0xde, 0xdc, 0x6d, 0xb7, 0x24, 0xbc, 0xe1, 0x11, 0x36, - 0x21, 0xc4, 0xa6, 0x47, 0x9d, 0xd5, 0x55, 0xf4, 0x85, 0x21, 0x7c, 0xb5, 0x67, 0x13, - 0x9e, 0xea, 0xdd, 0x7e, 0xe8, 0xdc, 0x5b, 0x26, 0x62, 0xf1, 0x06, 0x6a, 0x7c, 0x60, - 0xde, 0xe0, 0x09, 0x3c, 0x92, 0x46, 0xde, 0x7a, 0x05, 0xe8, 0xb0, 0xf6, 0xbe, 0xf0, - 0x03, 0x3d, 0xde, 0x2e, 0x87, 0xcb, 0xa6, 0x8d, 0x23, 0x6e, 0xf6, 0x6a, 0x23, 0xd5, - 0x5e, 0x7b, 0xd2, 0x8d, 0x02, 0x59, 0x9c, 0xca, 0x0d, 0xf7, 0xa9, 0x00, 0x63, 0x7b, - 0xb3, 0x46, 0x4d, 0x62, 0x2b, 0x7c, 0x9c, 0x9c, 0x8c, 0x91, 0x46, 0x89, 0x74, 0x88, - 0x01, 0x64, 0xde, 0xf7, 0x99, 0x90, 0x8a, 0x11, 0xa5, 0x91, 0xab, 0xb3, 0xc8, 0xd8, - 0xbd, 0x9c, 0x12, 0xb1, 0xf6, 0xf3, 0xcd, 0xc9, 0xed, 0x8e, 0x16, 0xe5, 0x7d, 0x23, - 0x34, 0xb2, 0x17, 0x79, 0x7d, 0xf1, 0x90, 0x52, 0xfe, 0xeb, 0xed, 0x6c, 0xdb, 0x99, - 0xac, 0x44, 0xea, 0x13, 0xaf, 0xea, 0xc4, 0x37, 0x7d, 0x0f, 0xa3, 0x7e, 0xf5, 0x16, - 0xdd, 0xac, 0xea, 0xb0, 0xd9, 0x39, 0x5b, 0xd4, 0x40, 0x46, 0x0e, 0x28, 0xb5, 0xf5, - 0x7a, 0x6e, 0xfd, 0x37, 0xd2, 0x68, 0xa8, 0x64, 0xcb, 0x5c, 0xa3, 0x4b, 0xe2, 0x87, - 0xe1, 0x04, 0x8e, 0xfc, 0x1e, 0x40, 0xcd, 0xf4, 0xfc, 0xfc, 0x02, 0x4c, 0xf1, 0x82, - 0x03, 0x8b, 0x9d, 0x80, 0xed, 0x1c, 0x07, 0x63, 0x62, 0x00, 0xc8, 0x19, 0xa7, 0xe7, - 0xc2, 0x40, 0xc3, 0xc4, 0xf7, 0xa9, 0x17, 0x32, 0xe3, 0xff, 0x13, 0xe2, 0xa5, 0x6a, - 0x64, 0x66, 0x66, 0x10, 0xca, 0xd9, 0x84, 0x1c, 0x1a, 0x93, 0x4f, 0xe9, 0x33, 0xb0, - 0xf1, 0x9f, 0xb7, 0x1d, 0x06, 0x1c, 0x58, 0xf2, 0x1a, 0x49, 0x81, 0xce, 0x3e, 0x68, - 0xc5, 0x02, 0x39, 0x03, 0x60, 0x8d, 0xe5, 0x83, 0x02, 0xc6, 0xc8, 0xde, 0xf4, 0xe5, - 0x61, 0x9e, 0xc0, 0xd9, 0x1c, 0xf9, 0x35, 0x44, 0x75, 0x97, 0x2b, 0xfe, 0x0d, 0x75, - 0x75, 0x60, 0x2a, 0xaf, 0x0e, 0x9e, 0x88, 0x5c, 0x6b, 0xaf, 0x9d, 0x56, 0x7b, 0x1f, - 0xcb, 0x63, 0x19, 0x0c, 0xb7, 0x92, 0xf1, 0xd8, 0x71, 0x61, 0x1a, 0xdb, 0x4f, 0x3d, - 0x1e, 0xd3, 0x28, 0x02, 0x69, 0x18, 0xe2, 0x8d, 0x2f, 0xd4, 0x5a, 0xb9, 0xd3, 0x70, - 0xe7, 0x29, 0x2e, 0xd7, 0x54, 0xce, 0x29, 0xfb, 0x78, 0x7f, 0xd5, 0xd0, 0x9e, 0x6d, - 0x47, 0xcb, 0xc8, 0x00, 0x21, 0xab, 0xf7, 0xd2, 0xef, 0xeb, 0xdb, 0xe0, 0xad, 0xd8, - 0x70, 0x16, 0x8f, 0x51, 0xdc, 0xc4, 0x09, 0x57, 0xa4, 0xa3, 0xc8, 0xe1, 0x92, 0x60, - 0x13, 0x83, 0xb7, 0x68, 0x41, 0x36, 0xdc, 0xa2, 0x82, 0x62, 0x3f, 0x31, 0xba, 0x7a, - 0xe5, 0x36, 0x6b, 0x45, 0x3c, 0x6a, 0x26, 0xf6, 0x8a, 0x14, 0xdb, 0x65, 0x59, 0xbc, - 0xb1, 0x02, 0x37, 0x37, 0x9a, 0x27, 0xa9, 0x50, 0x2f, 0xf9, 0xd6, 0x4a, 0x33, 0x83, - 0x20, 0x75, 0x15, 0x30, 0xf1, 0xf8, 0x92, 0xa6, 0xd4, 0x6f, 0x50, 0x31, 0x1b, 0x5e, - 0x18, 0xf0, 0x33, 0x6f, 0xc4, 0x77, 0x21, 0x56, 0x66, 0xe1, 0x88, 0x93, 0x3c, 0x69, - 0x39, 0x98, 0x9f, 0x6e, 0x6a, 0x3a, 0xdb, 0xa2, 0x29, 0x96, 0xaa, 0xe6, 0xa0, 0xfe, - 0x1b, 0xdd, 0xcb, 0xe1, 0x49, 0x6d, 0x96, 0x8d, 0xe0, 0x93, 0xdf, 0x44, 0xa3, 0x30, - 0x0f, 0x75, 0x15, 0xa1, 0x2c, 0x9d, 0x82, 0x22, 0x6d, 0x6b, 0x4d, 0x62, 0xc4, 0x6a, - 0x21, 0x3d, 0x5f, 0x01, 0x07, 0x10, 0x6f, 0xd2, 0xa2, 0x2d, 0x3b, 0x59, 0x86, 0x13, - 0xdb, 0x49, 0x1f, 0x70, 0xcc, 0xb1, 0xf0, 0x3b, 0x86, 0x59, 0x66, 0x9e, 0xd7, 0x44, - 0x34, 0xe4, 0x3b, 0x77, 0x1f, 0x22, 0x78, 0x07, 0x10, 0xfb, 0xd8, 0xf2, 0xf2, 0x0e, - 0x98, 0x97, 0xdf, 0x5c, 0xc2, 0x35, 0x48, 0x77, 0x9c, 0x6c, 0x08, 0x30, 0x83, 0x9d, - 0x23, 0x1c, 0x3f, 0xf9, 0xac, 0x54, 0x40, 0x7d, 0xfd, 0xfc, 0xc5, 0x90, 0x14, 0xbf, - 0x67, 0xd9, 0x68, 0x57, 0x06, 0xa5, 0x62, 0x2e, 0x38, 0xf7, 0xa9, 0x33, 0xc3, 0x4a, - 0xfb, 0xb6, 0xaa, 0x8c, 0xdf, 0xd9, 0x3b, 0xd2, 0xec, 0x91, 0xad, 0x37, 0x90, 0x4c, - 0xe1, 0x3b, 0x8a, 0xb8, 0xef, 0x77, 0x23, 0x66, 0xfa, 0xd3, 0xc3, 0xeb, 0xee, 0x8f, - 0x26, 0x11, 0xee, 0x7b, 0x6c, 0x2a, 0xf7, 0xe6, 0x53, 0xef, 0xbe, 0xc4, 0xdc, 0x4c, - 0xbf, 0x13, 0xac, 0xf3, 0x7e, 0x39, 0x9e, 0x2b, 0x0b, 0x05, 0xb6, 0x1c, 0xb7, 0xe1, - 0x7b, 0x15, 0x62, 0x7b, 0x62, 0x96, 0x2e, 0x21, 0x00, 0xb1, 0x95, 0xfe, 0xfe, 0x94, - 0xbc, 0x48, 0x4e, 0x88, 0x13, 0x97, 0x00, 0x73, 0x7d, 0xe1, 0xa5, 0xec, 0x7d, 0x9c, - 0xc8, 0x5d, 0x53, 0x3b, 0x61, 0xec, 0xad, 0x86, 0x53, 0xce, 0xdb, 0xb7, 0x71, 0xf6, - 0x75, 0xaf, 0x61, 0xe4, 0xc6, 0xf7, 0xef, 0xaa, 0xcc, 0x9f, 0x7e, 0x42, 0x4c, 0x16, - 0x71, 0x5b, 0x0a, 0x98, 0xc4, 0x46, 0x05, 0x9a, 0x27, 0x1a, 0x27, 0xbd, 0x56, 0x9d, - 0x1b, 0x5d, 0xbf, 0xae, 0x8f, 0x53, 0x89, 0x85, 0x24, 0xca, 0xe8, 0x70, 0x59, 0xff, - 0x34, 0xfb, 0x2a, 0x53, 0x32, 0x26, 0xbd, 0x29, 0xa0, 0xba, 0x6f, 0x8d, 0x08, 0x36, - 0xfd, 0x0a, 0x4c, 0x0d, 0x60, 0x9a, 0x72, 0xe1, 0x05, 0x39, 0xa4, 0x4f, 0x8c, 0x39, - 0xf6, 0x27, 0x9b, 0xe3, 0x96, 0xe4, 0x1c, 0xa9, 0xf2, 0x9a, 0x28, 0xce, 0x9f, 0xa0, - 0xdd, 0x51, 0xa3, 0x02, 0xe7, 0x70, 0xe1, 0xe3, 0xdb, 0x70, 0x6a, 0x34, 0xcb, 0x90, - 0x4e, 0xf0, 0x8d, 0x9c, 0x82, 0xc5, 0x5b, 0xc7, 0x28, 0xc9, 0x55, 0xb1, 0x20, 0xbb, - 0x2e, 0xc3, 0x73, 0xfc, 0xff, 0xff, 0x3c, 0x46, 0xd6, 0x03, 0xab, 0x38, 0x78, 0x96, - 0xd4, 0x9c, 0xd2, 0x1b, 0x2f, 0x77, 0xec, 0xfb, 0xbb, 0x02, 0xa5, 0xe1, 0x53, 0xb1, - 0x71, 0xaf, 0xed, 0x98, 0x6c, 0x15, 0xda, 0x6f, 0x2d, 0x4c, 0xf7, 0x45, 0xd1, 0x99, - 0x5f, 0x51, 0x36, 0xe1, 0xb3, 0xe6, 0x8a, 0x67, 0xa8, 0x99, 0x6f, 0xe7, 0x65, 0x61, - 0x6d, 0x8a, 0xa1, 0x1b, 0xcd, 0x9f, 0x8b, 0x59, 0x1d, 0xb8, 0x7e, 0xfc, 0xda, 0xaf, - 0xfd, 0x41, 0x00, 0x3e, 0xc7, 0x29, 0x36, 0x05, 0x42, 0x62, 0x08, 0x54, 0xfb, 0x04, - 0xb8, 0x0c, 0xb8, 0x61, 0xa6, 0x36, 0xa4, 0x71, 0x7d, 0x66, 0x68, 0x94, 0xc3, 0x2f, - 0x1f, 0x2b, 0xf2, 0x24, 0x7c, 0xc4, 0x15, 0xde, 0x1d, 0x0c, 0x4e, 0x71, 0x2b, 0x95, - 0x88, 0x42, 0xd6, 0xa4, 0xb2, 0x76, 0xde, 0xa5, 0xdb, 0x88, 0x42, 0x3f, 0x2b, 0x4c, - 0x66, 0x4b, 0x1d, 0x2b, 0x18, 0x77, 0xba, 0xf3, 0x37, 0x47, 0x34, 0x36, 0x14, 0xe5, - 0xeb, 0xe9, 0xb7, 0xe1, 0x2e, 0xd0, 0x15, 0x3f, 0x9c, 0xa7, 0x45, 0x8e, 0x4d, 0xa4, - 0x97, 0x63, 0x9d, 0xff, 0x13, 0x52, 0xff, 0x0e, 0xfa, 0xe0, 0x1d, 0x14, 0x03, 0x21, - 0xc2, 0x8d, 0xd0, 0xb6, 0x7b, 0x06, 0x98, 0x90, 0xf6, 0x13, 0x0f, 0x82, 0x46, 0xab, - 0x85, 0x44, 0x71, 0x75, 0x32, 0xd3, 0xa5, 0xf6, 0x36, 0x39, 0xa9, 0x9d, 0x7f, 0x8e, - 0x98, 0x31, 0xc6, 0x48, 0x51, 0xb7, 0xef, 0x68, 0x93, 0xb3, 0xc9, 0x74, 0x0f, 0x98, - 0x44, 0xd1, 0x8a, 0x61, 0x3b, 0x5f, 0x9a, 0x6a, 0xb4, 0xbd, 0x6e, 0x6a, 0x93, 0xe8, - 0xe4, 0xbe, 0xa5, 0x57, 0x5d, 0x2c, 0xb4, 0x33, 0x0c, 0x0a, 0xf8, 0x55, 0x83, 0x19, - 0xa9, 0x09, 0xa5, 0x98, 0x8a, 0x99, 0x2e, 0x40, 0x63, 0x43, 0xdd, 0x1c, 0x74, 0x2d, - 0x64, 0xcd, 0x4a, 0x17, 0xa2, 0xf3, 0x79, 0x5e, 0x8d, 0xb4, 0xd3, 0x0c, 0xcd, 0xf4, - 0x41, 0x56, 0x55, 0xed, 0xa7, 0xb4, 0x37, 0xe3, 0x39, 0x73, 0x23, 0x89, 0x6b, 0x11, - 0xb1, 0xbe, 0xd7, 0x2d, 0x63, 0xe3, 0x10, 0xaa, 0x49, 0x67, 0x1d, 0x85, 0x53, 0x4f, - 0x6d, 0xbc, 0x18, 0x1f, 0xeb, 0xb5, 0xbd, 0xc0, 0x8a, 0xc0, 0xd1, 0x23, 0x82, 0x9d, - 0x10, 0x8c, 0xd2, 0x69, 0xf3, 0xb0, 0xa3, 0x96, 0xf4, 0x24, 0x1e, 0x7d, 0xda, 0x72, - 0xf5, 0x48, 0x62, 0xbe, 0xde, 0xf0, 0x1c, 0x12, 0xe3, 0xc6, 0xcf, 0xdf, 0x75, 0xf6, - 0x76, 0xc2, 0xdd, 0xef, 0x91, 0xaf, 0x7f, 0x8a, 0x8a, 0x76, 0x9c, 0x25, 0xe1, 0x77, - 0xcd, 0x43, 0x0b, 0xed, 0xe7, 0x4b, 0x57, 0x69, 0x05, 0x19, 0xa9, 0x8d, 0xb1, 0xfb, - 0x5c, 0x36, 0x12, 0x80, 0xf7, 0x54, 0x0a, 0xc8, 0x27, 0xa9, 0x1b, 0x2d, 0x08, 0x75, - 0x2d, 0xec, 0xfb, 0x71, 0x56, 0xfc, 0xdb, 0x61, 0x75, 0x78, 0xb0, 0x53, 0xee, 0xe4, - 0x1f, 0x66, 0xa6, 0x0e, 0x04, 0x5c, 0x3a, 0x56, 0x9f, 0x3f, 0x7e, 0xdb, 0x76, 0x31, - 0x68, 0x2f, 0xde, 0x9e, 0xf9, 0x1e, 0xa8, 0x81, 0x1f, 0xc2, 0xc7, 0x8f, 0x64, 0x6a, - 0xf6, 0xb4, 0x71, 0x0e, 0xdb, 0xb8, 0xbf, 0x23, 0x28, 0xbd, 0x32, 0x73, 0xa2, 0xcb, - 0x72, 0xff, 0xcc, 0xa7, 0xc2, 0x17, 0xb8, 0x27, 0x19, 0x2d, 0xd2, 0xea, 0x92, 0x9e, - 0x97, 0x6d, 0x13, 0x1c, 0x9d, 0x20, 0x2e, 0xc5, 0x06, 0xa3, 0x5d, 0x93, 0xab, 0x21, - 0x6f, 0x64, 0xbd, 0x73, 0xfe, 0x5d, 0x8a, 0xba, 0xe4, 0x57, 0x1f, 0x85, 0xbe, 0xb8, - 0x4a, 0x7f, 0x93, 0xa3, 0xde, 0x37, 0xa4, 0x51, 0xf3, 0x08, 0xf7, 0xde, 0x6c, 0xcd, - 0x1a, 0x6e, 0xef, 0xef, 0x24, 0x69, 0x9f, 0x21, 0x58, 0xd1, 0x26, 0x1f, 0xe2, 0x51, - 0x82, 0xb5, 0x02, 0xda, 0x3e, 0x74, 0x61, 0x1a, 0x61, 0x16, 0xfc, 0x30, 0x64, 0xfa, - 0x72, 0x3c, 0x5a, 0x81, 0xad, 0xc0, 0xa3, 0x2f, 0x1e, 0xd6, 0x29, 0x91, 0x57, 0xd1, - 0xc1, 0x1c, 0x0a, 0xd9, 0x90, 0x41, 0x89, 0x46, 0x96, 0x30, 0x1d, 0x5b, 0x3f, 0x1b, - 0xf4, 0x32, 0x05, 0xd7, 0xdc, 0xcf, 0xa6, 0x8b, 0xbb, 0x4a, 0x1f, 0x5e, 0x24, 0x2b, - 0x3e, 0x69, 0x0b, 0xfc, 0x97, 0xb9, 0x43, 0x66, 0xa3, 0x43, 0xf5, 0xdd, 0x16, 0xdf, - 0x67, 0xb2, 0xed, 0x2b, 0xe2, 0x1c, 0x74, 0x71, 0x18, 0x87, 0x2b, 0x46, 0x2e, 0xe2, - 0x0c, 0x77, 0x8c, 0xed, 0x85, 0x6f, 0xa9, 0x80, 0x40, 0x3f, 0xb2, 0x4b, 0x78, 0x61, - 0x37, 0xd0, 0xef, 0x02, 0x78, 0x53, 0x9b, 0x00, 0xce, 0x6e, 0x23, 0xc0, 0x7e, 0xf2, - 0xa0, 0x7c, 0xb2, 0x4c, 0x51, 0xc5, 0xb4, 0x85, 0xe4, 0x54, 0xed, 0xf6, 0x61, 0xdb, - 0x4b, 0x93, 0x1a, 0xb8, 0xcb, 0x49, 0x4e, 0xb3, 0x94, 0xfd, 0x13, 0xc1, 0xb3, 0x20, - 0x85, 0xf2, 0x7b, 0x20, 0x4a, 0x4b, 0x87, 0xee, 0x6c, 0x80, 0x63, 0x45, 0xd7, 0x58, - 0x4c, 0xb1, 0x61, 0x00, 0x6a, 0xd9, 0x84, 0x8a, 0x24, 0xa2, 0x2a, 0x57, 0x71, 0xe3, - 0xa2, 0xab, 0x65, 0x46, 0x3f, 0x55, 0x3d, 0x52, 0xcd, 0x53, 0x5e, 0xf1, 0x0b, 0xdd, - 0x40, 0xd8, 0x87, 0x73, 0x72, 0xa5, 0x32, 0xe3, 0x73, 0x1b, 0x0e, 0xe9, 0x0c, 0x04, - 0xe8, 0xe4, 0x37, 0x47, 0xcc, 0x3e, 0xb9, 0x6b, 0xb8, 0x79, 0xbd, 0x94, 0xd7, 0x01, - 0x2a, 0xf4, 0x6a, 0x93, 0xba, 0x17, 0x70, 0x37, 0xf0, 0x62, 0x74, 0x4d, 0x3f, 0xdf, - 0xcc, 0xd3, 0x6a, 0xab, 0xe0, 0xf8, 0xcc, 0xca, 0x19, 0xdc, 0xf7, 0x84, 0x1b, 0x1e, - 0xe2, 0xf4, 0xfe, 0xb1, 0x80, 0x0e, 0x75, 0x44, 0x1c, 0x51, 0xe9, 0x5c, 0xce, 0x94, - 0xce, 0xee, 0xcd, 0x85, 0x87, 0xfb, 0xf5, 0x74, 0x30, 0x8d, 0xd7, 0x63, 0x63, 0x1b, - 0x73, 0x35, 0x78, 0x30, 0x91, 0xf4, 0xc8, 0xb3, 0xc8, 0xfb, 0x3c, 0xd9, 0x39, 0x70, - 0xce, 0xf0, 0xed, 0xa4, 0xca, 0x08, 0x44, 0x75, 0x68, 0x23, 0x9c, 0x02, 0xfe, 0x8f, - 0x67, 0x5e, 0x15, 0xc4, 0x9b, 0x51, 0x21, 0xb1, 0x00, 0xcc, 0x19, 0xfc, 0xc2, 0xb2, - 0x91, 0x3d, 0xf7, 0x4f, 0x75, 0x8f, 0x70, 0xbd, 0x6e, 0xeb, 0x73, 0x39, 0x51, 0x6e, - 0x5f, 0x1e, 0xff, 0x97, 0x00, 0xf8, 0xee, 0x13, 0x0e, 0x5c, 0x84, 0xce, 0xd7, 0xb1, - 0xce, 0xd6, 0x6b, 0xe9, 0xa0, 0x55, 0x96, 0xbe, 0x8e, 0x55, 0xf6, 0xd9, 0xfd, 0xf7, - 0xcf, 0x0f, 0xa6, 0x22, 0x90, 0xec, 0x67, 0x0b, 0x6b, 0xdd, 0x67, 0x38, 0xbb, 0x5c, - 0xfb, 0x34, 0x1e, 0xf5, 0xff, 0xb4, 0x2b, 0xc2, 0xab, 0xc5, 0x08, 0xff, 0x23, 0x12, - 0x48, 0xf2, 0xc2, 0xdc, 0x15, 0x77, 0x0d, 0x33, 0x72, 0x2b, 0x9c, 0x9d, 0xae, - ], - script_code: vec![0xac, 0x65], - transparent_input: Some(0), - hash_type: 3, - amount: 391892287957268, - consensus_branch_id: 1991772603, - sighash: [ - 0x6a, 0x3b, 0x2b, 0xcc, 0x15, 0x57, 0x89, 0xa2, 0x74, 0x39, 0xaa, 0x27, 0x5c, 0xa9, - 0x9e, 0xc6, 0x48, 0xdd, 0xd5, 0x88, 0xe8, 0x2e, 0xfa, 0xe4, 0xac, 0x46, 0xba, 0x3f, - 0xd0, 0xe3, 0xbb, 0xa0, - ], - }, - ]; - - for tv in test_vectors { - let tx = Transaction::read(&tv.tx[..]).unwrap(); - let transparent_input = if let Some(n) = tv.transparent_input { - Some((n as usize, Script(tv.script_code), Amount(tv.amount))) - } else { - None - }; - - assert_eq!( - signature_hash(&tx, tv.consensus_branch_id, tv.hash_type, transparent_input,), - tv.sighash - ); - } -} diff --git a/zcash_proofs/Cargo.toml b/zcash_proofs/Cargo.toml deleted file mode 100644 index 68a4a45..0000000 --- a/zcash_proofs/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "zcash_proofs" -version = "0.0.0" -authors = [ - "Jack Grigg ", -] - -[dependencies] -bellman = { path = "../bellman" } -byteorder = "1" -pairing = { path = "../pairing" } -rand = "0.4" -sapling-crypto = { path = "../sapling-crypto" } diff --git a/zcash_proofs/LICENSE-APACHE b/zcash_proofs/LICENSE-APACHE deleted file mode 100644 index 1e5006d..0000000 --- a/zcash_proofs/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. - diff --git a/zcash_proofs/LICENSE-MIT b/zcash_proofs/LICENSE-MIT deleted file mode 100644 index 5b7be8e..0000000 --- a/zcash_proofs/LICENSE-MIT +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017 Zcash Company - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/zcash_proofs/README.md b/zcash_proofs/README.md deleted file mode 100644 index 92d9c77..0000000 --- a/zcash_proofs/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# zcash_proofs - -This library contains the zk-SNARK circuits for Zcash, and the APIs for creating -and verifying proofs. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. - diff --git a/zcash_proofs/src/lib.rs b/zcash_proofs/src/lib.rs deleted file mode 100644 index bdebdd6..0000000 --- a/zcash_proofs/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -extern crate bellman; -extern crate byteorder; -extern crate pairing; -extern crate rand; -extern crate sapling_crypto; - -pub mod sapling; diff --git a/zcash_proofs/src/sapling/mod.rs b/zcash_proofs/src/sapling/mod.rs deleted file mode 100644 index 2cfb2e9..0000000 --- a/zcash_proofs/src/sapling/mod.rs +++ /dev/null @@ -1,39 +0,0 @@ -use pairing::bls12_381::Bls12; -use sapling_crypto::jubjub::{ - edwards, fs::FsRepr, FixedGenerators, JubjubBls12, JubjubParams, Unknown, -}; - -mod prover; -mod verifier; - -pub use self::prover::{CommitmentTreeWitness, SaplingProvingContext}; -pub use self::verifier::SaplingVerificationContext; - -// This function computes `value` in the exponent of the value commitment base -fn compute_value_balance( - value: i64, - params: &JubjubBls12, -) -> Option> { - // Compute the absolute value (failing if -i64::MAX is - // the value) - let abs = match value.checked_abs() { - Some(a) => a as u64, - None => return None, - }; - - // Is it negative? We'll have to negate later if so. - let is_negative = value.is_negative(); - - // Compute it in the exponent - let mut value_balance = params - .generator(FixedGenerators::ValueCommitmentValue) - .mul(FsRepr::from(abs), params); - - // Negate if necessary - if is_negative { - value_balance = value_balance.negate(); - } - - // Convert to unknown order point - Some(value_balance.into()) -} diff --git a/zcash_proofs/src/sapling/prover.rs b/zcash_proofs/src/sapling/prover.rs deleted file mode 100644 index f43dae7..0000000 --- a/zcash_proofs/src/sapling/prover.rs +++ /dev/null @@ -1,365 +0,0 @@ -use bellman::groth16::{ - create_random_proof, verify_proof, Parameters, PreparedVerifyingKey, Proof, -}; -use byteorder::{LittleEndian, ReadBytesExt}; -use pairing::{ - bls12_381::{Bls12, Fr, FrRepr}, - Field, PrimeField, PrimeFieldRepr, -}; -use rand::{OsRng, Rand}; -use sapling_crypto::{ - circuit::{ - multipack, - sapling::{Output, Spend, TREE_DEPTH}, - }, - jubjub::{edwards, fs::Fs, FixedGenerators, JubjubBls12, Unknown}, - primitives::{Diversifier, Note, PaymentAddress, ProofGenerationKey, ValueCommitment}, - redjubjub::{PrivateKey, PublicKey, Signature}, -}; - -use super::compute_value_balance; - -/// A witness to a path from a postion in a particular Sapling commitment tree -/// to the root of that tree. -pub struct CommitmentTreeWitness { - auth_path: Vec>, - position: u64, -} - -impl CommitmentTreeWitness { - pub fn from_slice(mut witness: &[u8]) -> Result { - // Skip the first byte, which should be "32" to signify the length of - // the following vector of Pedersen hashes. - assert_eq!(witness[0], TREE_DEPTH as u8); - witness = &witness[1..]; - - // Begin to construct the authentication path - let mut auth_path = vec![None; TREE_DEPTH]; - - // The vector works in reverse - for i in (0..TREE_DEPTH).rev() { - // skip length of inner vector - assert_eq!(witness[0], 32); // the length of a pedersen hash - witness = &witness[1..]; - - // Grab the sibling node at this depth in the tree - let mut sibling = [0u8; 32]; - sibling.copy_from_slice(&witness[0..32]); - witness = &witness[32..]; - - // Sibling node should be an element of Fr - let sibling = match { - let mut repr = FrRepr::default(); - repr.read_le(&sibling[..]).expect("length is 32 bytes"); - Fr::from_repr(repr) - } { - Ok(p) => p, - Err(_) => return Err(()), - }; - - // Set the value in the auth path; we put false here - // for now (signifying the position bit) which we'll - // fill in later. - auth_path[i] = Some((sibling, false)); - } - - // Read the position from the witness - let position = witness - .read_u64::() - .expect("should have had index at the end"); - - // Given the position, let's finish constructing the authentication - // path - let mut tmp = position; - for i in 0..TREE_DEPTH { - auth_path[i].as_mut().map(|p| p.1 = (tmp & 1) == 1); - - tmp >>= 1; - } - - // The witness should be empty now; if it wasn't, the caller would - // have provided more information than they should have, indicating - // a bug downstream - assert_eq!(witness.len(), 0); - - Ok(CommitmentTreeWitness { - auth_path, - position, - }) - } -} - -/// A context object for creating the Sapling components of a Zcash transaction. -pub struct SaplingProvingContext { - bsk: Fs, - bvk: edwards::Point, -} - -impl SaplingProvingContext { - /// Construct a new context to be used with a single transaction. - pub fn new() -> Self { - SaplingProvingContext { - bsk: Fs::zero(), - bvk: edwards::Point::zero(), - } - } - - /// Create the value commitment, re-randomized key, and proof for a Sapling - /// SpendDescription, while accumulating its value commitment randomness - /// inside the context for later use. - pub fn spend_proof( - &mut self, - proof_generation_key: ProofGenerationKey, - diversifier: Diversifier, - rcm: Fs, - ar: Fs, - value: u64, - anchor: Fr, - witness: CommitmentTreeWitness, - proving_key: &Parameters, - verifying_key: &PreparedVerifyingKey, - params: &JubjubBls12, - ) -> Result< - ( - Proof, - edwards::Point, - PublicKey, - ), - (), - > { - // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); - - // We create the randomness of the value commitment - let rcv = Fs::rand(&mut rng); - - // Accumulate the value commitment randomness in the context - { - let mut tmp = rcv.clone(); - tmp.add_assign(&self.bsk); - - // Update the context - self.bsk = tmp; - } - - // Construct the value commitment - let value_commitment = ValueCommitment:: { - value: value, - randomness: rcv, - }; - - // Construct the viewing key - let viewing_key = proof_generation_key.into_viewing_key(params); - - // Construct the payment address with the viewing key / diversifier - let payment_address = match viewing_key.into_payment_address(diversifier, params) { - Some(p) => p, - None => return Err(()), - }; - - // This is the result of the re-randomization, we compute it for the caller - let rk = PublicKey::(proof_generation_key.ak.clone().into()).randomize( - ar, - FixedGenerators::SpendingKeyGenerator, - params, - ); - - // Let's compute the nullifier while we have the position - let note = Note { - value: value, - g_d: diversifier - .g_d::(params) - .expect("was a valid diversifier before"), - pk_d: payment_address.pk_d.clone(), - r: rcm, - }; - - let nullifier = note.nf(&viewing_key, witness.position, params); - - // We now have the full witness for our circuit - let instance = Spend { - params, - value_commitment: Some(value_commitment.clone()), - proof_generation_key: Some(proof_generation_key), - payment_address: Some(payment_address), - commitment_randomness: Some(rcm), - ar: Some(ar), - auth_path: witness.auth_path, - anchor: Some(anchor), - }; - - // Create proof - let proof = - create_random_proof(instance, proving_key, &mut rng).expect("proving should not fail"); - - // Try to verify the proof: - // Construct public input for circuit - let mut public_input = [Fr::zero(); 7]; - { - let (x, y) = rk.0.into_xy(); - public_input[0] = x; - public_input[1] = y; - } - { - let (x, y) = value_commitment.cm(params).into_xy(); - public_input[2] = x; - public_input[3] = y; - } - public_input[4] = anchor; - - // Add the nullifier through multiscalar packing - { - let nullifier = multipack::bytes_to_bits_le(&nullifier); - let nullifier = multipack::compute_multipacking::(&nullifier); - - assert_eq!(nullifier.len(), 2); - - public_input[5] = nullifier[0]; - public_input[6] = nullifier[1]; - } - - // Verify the proof - match verify_proof(verifying_key, &proof, &public_input[..]) { - // No error, and proof verification successful - Ok(true) => {} - - // Any other case - _ => { - return Err(()); - } - } - - // Compute value commitment - let value_commitment: edwards::Point = value_commitment.cm(params).into(); - - // Accumulate the value commitment in the context - { - let mut tmp = value_commitment.clone(); - tmp = tmp.add(&self.bvk, params); - - // Update the context - self.bvk = tmp; - } - - Ok((proof, value_commitment, rk)) - } - - /// Create the value commitment and proof for a Sapling OutputDescription, - /// while accumulating its value commitment randomness inside the context - /// for later use. - pub fn output_proof( - &mut self, - esk: Fs, - payment_address: PaymentAddress, - rcm: Fs, - value: u64, - proving_key: &Parameters, - params: &JubjubBls12, - ) -> (Proof, edwards::Point) { - // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); - - // We construct ephemeral randomness for the value commitment. This - // randomness is not given back to the caller, but the synthetic - // blinding factor `bsk` is accumulated in the context. - let rcv = Fs::rand(&mut rng); - - // Accumulate the value commitment randomness in the context - { - let mut tmp = rcv.clone(); - tmp.negate(); // Outputs subtract from the total. - tmp.add_assign(&self.bsk); - - // Update the context - self.bsk = tmp; - } - - // Construct the value commitment for the proof instance - let value_commitment = ValueCommitment:: { - value: value, - randomness: rcv, - }; - - // We now have a full witness for the output proof. - let instance = Output { - params, - value_commitment: Some(value_commitment.clone()), - payment_address: Some(payment_address.clone()), - commitment_randomness: Some(rcm), - esk: Some(esk.clone()), - }; - - // Create proof - let proof = - create_random_proof(instance, proving_key, &mut rng).expect("proving should not fail"); - - // Compute the actual value commitment - let value_commitment: edwards::Point = value_commitment.cm(params).into(); - - // Accumulate the value commitment in the context. We do this to check internal consistency. - { - let mut tmp = value_commitment.clone(); - tmp = tmp.negate(); // Outputs subtract from the total. - tmp = tmp.add(&self.bvk, params); - - // Update the context - self.bvk = tmp; - } - - (proof, value_commitment) - } - - /// Create the bindingSig for a Sapling transaction. All calls to spend_proof() - /// and output_proof() must be completed before calling this function. - pub fn binding_sig( - &self, - value_balance: i64, - sighash: &[u8; 32], - params: &JubjubBls12, - ) -> Result { - // Initialize secure RNG - let mut rng = OsRng::new().expect("should be able to construct RNG"); - - // Grab the current `bsk` from the context - let bsk = PrivateKey::(self.bsk); - - // Grab the `bvk` using DerivePublic. - let bvk = PublicKey::from_private(&bsk, FixedGenerators::ValueCommitmentRandomness, params); - - // In order to check internal consistency, let's use the accumulated value - // commitments (as the verifier would) and apply valuebalance to compare - // against our derived bvk. - { - // Compute value balance - let mut value_balance = match compute_value_balance(value_balance, params) { - Some(a) => a, - None => return Err(()), - }; - - // Subtract value_balance from current bvk to get final bvk - value_balance = value_balance.negate(); - let mut tmp = self.bvk.clone(); - tmp = tmp.add(&value_balance, params); - - // The result should be the same, unless the provided valueBalance is wrong. - if bvk.0 != tmp { - return Err(()); - } - } - - // Construct signature message - let mut data_to_be_signed = [0u8; 64]; - bvk.0 - .write(&mut data_to_be_signed[0..32]) - .expect("message buffer should be 32 bytes"); - (&mut data_to_be_signed[32..64]).copy_from_slice(&sighash[..]); - - // Sign - Ok(bsk.sign( - &data_to_be_signed, - &mut rng, - FixedGenerators::ValueCommitmentRandomness, - params, - )) - } -} diff --git a/zcash_proofs/src/sapling/verifier.rs b/zcash_proofs/src/sapling/verifier.rs deleted file mode 100644 index e9a5f2f..0000000 --- a/zcash_proofs/src/sapling/verifier.rs +++ /dev/null @@ -1,207 +0,0 @@ -use bellman::groth16::{verify_proof, PreparedVerifyingKey, Proof}; -use pairing::{ - bls12_381::{Bls12, Fr}, - Field, -}; -use sapling_crypto::{ - circuit::multipack, - jubjub::{edwards, FixedGenerators, JubjubBls12, Unknown}, - redjubjub::{PublicKey, Signature}, -}; - -use super::compute_value_balance; - -fn is_small_order(p: &edwards::Point, params: &JubjubBls12) -> bool { - p.double(params).double(params).double(params) == edwards::Point::zero() -} - -/// A context object for verifying the Sapling components of a Zcash transaction. -pub struct SaplingVerificationContext { - bvk: edwards::Point, -} - -impl SaplingVerificationContext { - /// Construct a new context to be used with a single transaction. - pub fn new() -> Self { - SaplingVerificationContext { - bvk: edwards::Point::zero(), - } - } - - /// Perform consensus checks on a Sapling SpendDescription, while - /// accumulating its value commitment inside the context for later use. - pub fn check_spend( - &mut self, - cv: edwards::Point, - anchor: Fr, - nullifier: &[u8; 32], - rk: PublicKey, - sighash_value: &[u8; 32], - spend_auth_sig: Signature, - zkproof: Proof, - verifying_key: &PreparedVerifyingKey, - params: &JubjubBls12, - ) -> bool { - if is_small_order(&cv, params) { - return false; - } - - if is_small_order(&rk.0, params) { - return false; - } - - // Accumulate the value commitment in the context - { - let mut tmp = cv.clone(); - tmp = tmp.add(&self.bvk, params); - - // Update the context - self.bvk = tmp; - } - - // Grab the nullifier as a sequence of bytes - let nullifier = &nullifier[..]; - - // Compute the signature's message for rk/spend_auth_sig - let mut data_to_be_signed = [0u8; 64]; - rk.0.write(&mut data_to_be_signed[0..32]) - .expect("message buffer should be 32 bytes"); - (&mut data_to_be_signed[32..64]).copy_from_slice(&sighash_value[..]); - - // Verify the spend_auth_sig - if !rk.verify( - &data_to_be_signed, - &spend_auth_sig, - FixedGenerators::SpendingKeyGenerator, - params, - ) { - return false; - } - - // Construct public input for circuit - let mut public_input = [Fr::zero(); 7]; - { - let (x, y) = rk.0.into_xy(); - public_input[0] = x; - public_input[1] = y; - } - { - let (x, y) = cv.into_xy(); - public_input[2] = x; - public_input[3] = y; - } - public_input[4] = anchor; - - // Add the nullifier through multiscalar packing - { - let nullifier = multipack::bytes_to_bits_le(nullifier); - let nullifier = multipack::compute_multipacking::(&nullifier); - - assert_eq!(nullifier.len(), 2); - - public_input[5] = nullifier[0]; - public_input[6] = nullifier[1]; - } - - // Verify the proof - match verify_proof(verifying_key, &zkproof, &public_input[..]) { - // No error, and proof verification successful - Ok(true) => true, - - // Any other case - _ => false, - } - } - - /// Perform consensus checks on a Sapling OutputDescription, while - /// accumulating its value commitment inside the context for later use. - pub fn check_output( - &mut self, - cv: edwards::Point, - cm: Fr, - epk: edwards::Point, - zkproof: Proof, - verifying_key: &PreparedVerifyingKey, - params: &JubjubBls12, - ) -> bool { - if is_small_order(&cv, params) { - return false; - } - - if is_small_order(&epk, params) { - return false; - } - - // Accumulate the value commitment in the context - { - let mut tmp = cv.clone(); - tmp = tmp.negate(); // Outputs subtract from the total. - tmp = tmp.add(&self.bvk, params); - - // Update the context - self.bvk = tmp; - } - - // Construct public input for circuit - let mut public_input = [Fr::zero(); 5]; - { - let (x, y) = cv.into_xy(); - public_input[0] = x; - public_input[1] = y; - } - { - let (x, y) = epk.into_xy(); - public_input[2] = x; - public_input[3] = y; - } - public_input[4] = cm; - - // Verify the proof - match verify_proof(verifying_key, &zkproof, &public_input[..]) { - // No error, and proof verification successful - Ok(true) => true, - - // Any other case - _ => false, - } - } - - /// Perform consensus checks on the valueBalance and bindingSig parts of a - /// Sapling transaction. All SpendDescriptions and OutputDescriptions must - /// have been checked before calling this function. - pub fn final_check( - &self, - value_balance: i64, - sighash_value: &[u8; 32], - binding_sig: Signature, - params: &JubjubBls12, - ) -> bool { - // Obtain current bvk from the context - let mut bvk = PublicKey(self.bvk.clone()); - - // Compute value balance - let mut value_balance = match compute_value_balance(value_balance, params) { - Some(a) => a, - None => return false, - }; - - // Subtract value_balance from current bvk to get final bvk - value_balance = value_balance.negate(); - bvk.0 = bvk.0.add(&value_balance, params); - - // Compute the signature's message for bvk/binding_sig - let mut data_to_be_signed = [0u8; 64]; - bvk.0 - .write(&mut data_to_be_signed[0..32]) - .expect("bvk is 32 bytes"); - (&mut data_to_be_signed[32..64]).copy_from_slice(&sighash_value[..]); - - // Verify the binding_sig - bvk.verify( - &data_to_be_signed, - &binding_sig, - FixedGenerators::ValueCommitmentRandomness, - params, - ) - } -} diff --git a/zcash_wallet/Cargo.toml b/zcash_wallet/Cargo.toml deleted file mode 100644 index a7b6c91..0000000 --- a/zcash_wallet/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "zcash_wallet" -version = "0.0.0" -authors = [ - "Jack Grigg ", -] - -[dependencies] diff --git a/zcash_wallet/LICENSE-APACHE b/zcash_wallet/LICENSE-APACHE deleted file mode 100644 index 1e5006d..0000000 --- a/zcash_wallet/LICENSE-APACHE +++ /dev/null @@ -1,202 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. - diff --git a/zcash_wallet/LICENSE-MIT b/zcash_wallet/LICENSE-MIT deleted file mode 100644 index 5b7be8e..0000000 --- a/zcash_wallet/LICENSE-MIT +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017 Zcash Company - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/zcash_wallet/README.md b/zcash_wallet/README.md deleted file mode 100644 index 14c1a38..0000000 --- a/zcash_wallet/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# zcash_wallet - -This library contains Rust structs and traits for creating shielded Zcash wallets. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. - diff --git a/zcash_wallet/src/lib.rs b/zcash_wallet/src/lib.rs deleted file mode 100644 index 31e1bb2..0000000 --- a/zcash_wallet/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/zip32/.gitignore b/zip32/.gitignore deleted file mode 100644 index 6936990..0000000 --- a/zip32/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target -**/*.rs.bk -Cargo.lock diff --git a/zip32/COPYRIGHT b/zip32/COPYRIGHT deleted file mode 100644 index e58e868..0000000 --- a/zip32/COPYRIGHT +++ /dev/null @@ -1,14 +0,0 @@ -Copyrights in the "zip32" library are retained by their contributors. No -copyright assignment is required to contribute to the "zip32" library. - -The "zip32" library is licensed under either of - - * Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT) - -at your option. - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/zip32/Cargo.toml b/zip32/Cargo.toml deleted file mode 100644 index 031d636..0000000 --- a/zip32/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "zip32" -version = "0.0.0" -authors = [ - "Jack Grigg ", -] -license = "MIT/Apache-2.0" - -description = "Library for implementing shielded hierarchical deterministic wallets" -documentation = "https://docs.rs/zip32/" -homepage = "https://github.com/zcash-hackworks/zip32" -repository = "https://github.com/zcash-hackworks/zip32" - -[dependencies] -aes = "0.2" -byteorder = "1" -fpe = "0.1" -lazy_static = "1.0" -pairing = { path = "../pairing" } -sapling-crypto = { path = "../sapling-crypto" } - -[dependencies.blake2-rfc] -git = "https://github.com/gtank/blake2-rfc" -rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" diff --git a/zip32/LICENSE-APACHE b/zip32/LICENSE-APACHE deleted file mode 100644 index 16fe87b..0000000 --- a/zip32/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -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. diff --git a/zip32/LICENSE-MIT b/zip32/LICENSE-MIT deleted file mode 100644 index 31aa793..0000000 --- a/zip32/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/zip32/README.md b/zip32/README.md deleted file mode 100644 index 898d56c..0000000 --- a/zip32/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# zip32 [![Crates.io](https://img.shields.io/crates/v/zip32.svg)](https://crates.io/crates/zip32) # - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/zip32/src/lib.rs b/zip32/src/lib.rs deleted file mode 100644 index 5b322db..0000000 --- a/zip32/src/lib.rs +++ /dev/null @@ -1,1233 +0,0 @@ -extern crate aes; -extern crate blake2_rfc; -extern crate byteorder; -extern crate fpe; -#[macro_use] -extern crate lazy_static; -extern crate pairing; -extern crate sapling_crypto; - -use aes::Aes256; -use blake2_rfc::blake2b::{Blake2b, Blake2bResult}; -use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt}; -use fpe::ff1::{BinaryNumeralString, FF1}; -use pairing::{bls12_381::Bls12, Field, PrimeField, PrimeFieldRepr}; -use sapling_crypto::{ - jubjub::{ - edwards, FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, ToUniform, Unknown, - }, - primitives::{Diversifier, PaymentAddress, ViewingKey}, -}; -use std::io::{self, Read, Write}; - -lazy_static! { - static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() }; -} - -pub const PRF_EXPAND_PERSONALIZATION: &'static [u8; 16] = b"Zcash_ExpandSeed"; -pub const ZIP32_SAPLING_MASTER_PERSONALIZATION: &'static [u8; 16] = b"ZcashIP32Sapling"; -pub const ZIP32_SAPLING_FVFP_PERSONALIZATION: &'static [u8; 16] = b"ZcashSaplingFVFP"; - -// Sapling key components - -/// PRF^expand(sk, t) := BLAKE2b-512("Zcash_ExpandSeed", sk || t) -fn prf_expand(sk: &[u8], t: &[u8]) -> Blake2bResult { - prf_expand_vec(sk, &vec![t]) -} - -fn prf_expand_vec(sk: &[u8], ts: &[&[u8]]) -> Blake2bResult { - let mut h = Blake2b::with_params(64, &[], &[], PRF_EXPAND_PERSONALIZATION); - h.update(sk); - for t in ts { - h.update(t); - } - h.finalize() -} - -/// An outgoing viewing key -#[derive(Clone, Copy, PartialEq)] -struct OutgoingViewingKey([u8; 32]); - -impl OutgoingViewingKey { - fn derive_child(&self, i_l: &[u8]) -> Self { - let mut ovk = [0u8; 32]; - ovk.copy_from_slice(&prf_expand_vec(i_l, &[&[0x15], &self.0]).as_bytes()[..32]); - OutgoingViewingKey(ovk) - } -} - -/// A Sapling expanded spending key -#[derive(Clone)] -pub struct ExpandedSpendingKey { - ask: E::Fs, - nsk: E::Fs, - ovk: OutgoingViewingKey, -} - -/// A Sapling full viewing key -pub struct FullViewingKey { - vk: ViewingKey, - ovk: OutgoingViewingKey, -} - -impl ExpandedSpendingKey { - fn from_spending_key(sk: &[u8]) -> Self { - let ask = E::Fs::to_uniform(prf_expand(sk, &[0x00]).as_bytes()); - let nsk = E::Fs::to_uniform(prf_expand(sk, &[0x01]).as_bytes()); - let mut ovk = OutgoingViewingKey([0u8; 32]); - ovk.0 - .copy_from_slice(&prf_expand(sk, &[0x02]).as_bytes()[..32]); - ExpandedSpendingKey { ask, nsk, ovk } - } - - fn derive_child(&self, i_l: &[u8]) -> Self { - let mut ask = E::Fs::to_uniform(prf_expand(i_l, &[0x13]).as_bytes()); - let mut nsk = E::Fs::to_uniform(prf_expand(i_l, &[0x14]).as_bytes()); - ask.add_assign(&self.ask); - nsk.add_assign(&self.nsk); - let ovk = self.ovk.derive_child(i_l); - ExpandedSpendingKey { ask, nsk, ovk } - } - - pub fn read(mut reader: R) -> io::Result { - let mut ask_repr = ::Repr::default(); - ask_repr.read_le(&mut reader)?; - let ask = E::Fs::from_repr(ask_repr) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - - let mut nsk_repr = ::Repr::default(); - nsk_repr.read_le(&mut reader)?; - let nsk = E::Fs::from_repr(nsk_repr) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - - let mut ovk = [0; 32]; - reader.read_exact(&mut ovk)?; - - Ok(ExpandedSpendingKey { - ask, - nsk, - ovk: OutgoingViewingKey(ovk), - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - self.ask.into_repr().write_le(&mut writer)?; - self.nsk.into_repr().write_le(&mut writer)?; - writer.write_all(&self.ovk.0)?; - - Ok(()) - } - - fn to_bytes(&self) -> [u8; 96] { - let mut result = [0u8; 96]; - self.write(&mut result[..]) - .expect("should be able to serialize an ExpandedSpendingKey"); - result - } -} - -impl FullViewingKey { - fn from_expanded_spending_key(expsk: &ExpandedSpendingKey, params: &E::Params) -> Self { - FullViewingKey { - vk: ViewingKey { - ak: params - .generator(FixedGenerators::SpendingKeyGenerator) - .mul(expsk.ask, params), - nk: params - .generator(FixedGenerators::ProofGenerationKey) - .mul(expsk.nsk, params), - }, - ovk: expsk.ovk, - } - } - - fn derive_child(&self, i_l: &[u8], params: &E::Params) -> Self { - let i_ask = E::Fs::to_uniform(prf_expand(i_l, &[0x13]).as_bytes()); - let i_nsk = E::Fs::to_uniform(prf_expand(i_l, &[0x14]).as_bytes()); - let ak = params - .generator(FixedGenerators::SpendingKeyGenerator) - .mul(i_ask, params) - .add(&self.vk.ak, params); - let nk = params - .generator(FixedGenerators::ProofGenerationKey) - .mul(i_nsk, params) - .add(&self.vk.nk, params); - - FullViewingKey { - vk: ViewingKey { ak, nk }, - ovk: self.ovk.derive_child(i_l), - } - } - - pub fn read(mut reader: R, params: &E::Params) -> io::Result { - let ak = edwards::Point::::read(&mut reader, params)?; - let ak = match ak.as_prime_order(params) { - Some(p) => p, - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "ak not of prime order", - )) - } - }; - - let nk = edwards::Point::::read(&mut reader, params)?; - let nk = match nk.as_prime_order(params) { - Some(p) => p, - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "nk not of prime order", - )) - } - }; - - let mut ovk = [0; 32]; - reader.read_exact(&mut ovk)?; - - Ok(FullViewingKey { - vk: ViewingKey { ak, nk }, - ovk: OutgoingViewingKey(ovk), - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - self.vk.ak.write(&mut writer)?; - self.vk.nk.write(&mut writer)?; - writer.write_all(&self.ovk.0)?; - - Ok(()) - } - - fn to_bytes(&self) -> [u8; 96] { - let mut result = [0u8; 96]; - self.write(&mut result[..]) - .expect("should be able to serialize a FullViewingKey"); - result - } - - fn fingerprint(&self) -> FVKFingerprint { - let mut h = Blake2b::with_params(32, &[], &[], ZIP32_SAPLING_FVFP_PERSONALIZATION); - h.update(&self.to_bytes()); - let mut fvfp = [0u8; 32]; - fvfp.copy_from_slice(h.finalize().as_bytes()); - FVKFingerprint(fvfp) - } -} - -// ZIP 32 structures - -/// A Sapling full viewing key fingerprint -struct FVKFingerprint([u8; 32]); - -/// A Sapling full viewing key tag -#[derive(Clone, Copy, Debug, PartialEq)] -struct FVKTag([u8; 4]); - -impl FVKFingerprint { - fn tag(&self) -> FVKTag { - let mut tag = [0u8; 4]; - tag.copy_from_slice(&self.0[..4]); - FVKTag(tag) - } -} - -impl FVKTag { - fn master() -> Self { - FVKTag([0u8; 4]) - } -} - -/// A child index for a derived key -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum ChildIndex { - NonHardened(u32), - Hardened(u32), // Hardened(n) == n + (1 << 31) == n' in path notation -} - -impl ChildIndex { - pub fn from_index(i: u32) -> Self { - match i { - n if n >= (1 << 31) => ChildIndex::Hardened(n - (1 << 31)), - n => ChildIndex::NonHardened(n), - } - } - - fn master() -> Self { - ChildIndex::from_index(0) - } - - fn to_index(&self) -> u32 { - match self { - &ChildIndex::Hardened(i) => i + (1 << 31), - &ChildIndex::NonHardened(i) => i, - } - } -} - -/// A chain code -#[derive(Clone, Copy, Debug, PartialEq)] -struct ChainCode([u8; 32]); - -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct DiversifierIndex(pub [u8; 11]); - -impl DiversifierIndex { - fn new() -> Self { - DiversifierIndex([0; 11]) - } - - pub fn increment(&mut self) -> Result<(), ()> { - for k in 0..11 { - self.0[k] = self.0[k].wrapping_add(1); - if self.0[k] != 0 { - // No overflow - return Ok(()); - } - } - // Overflow - Err(()) - } -} - -/// A key used to derive diversifiers for a particular child key -#[derive(Clone, Copy, Debug, PartialEq)] -struct DiversifierKey([u8; 32]); - -impl DiversifierKey { - fn master(sk_m: &[u8]) -> Self { - let mut dk_m = [0u8; 32]; - dk_m.copy_from_slice(&prf_expand(sk_m, &[0x10]).as_bytes()[..32]); - DiversifierKey(dk_m) - } - - fn derive_child(&self, i_l: &[u8]) -> Self { - let mut dk = [0u8; 32]; - dk.copy_from_slice(&prf_expand_vec(i_l, &[&[0x16], &self.0]).as_bytes()[..32]); - DiversifierKey(dk) - } - - /// Returns the first index starting from j that generates a valid - /// diversifier, along with the corresponding diversifier. Returns - /// an error if the diversifier space is exhausted. - fn diversifier(&self, mut j: DiversifierIndex) -> Result<(DiversifierIndex, Diversifier), ()> { - let ff = FF1::::new(&self.0, 2).unwrap(); - loop { - // Generate d_j - let enc = ff - .encrypt(&[], &BinaryNumeralString::from_bytes_le(&j.0[..])) - .unwrap(); - let mut d_j = [0; 11]; - d_j.copy_from_slice(&enc.to_bytes_le()); - let d_j = Diversifier(d_j); - - // Return (j, d_j) if valid, else increment j and try again - match d_j.g_d::(&JUBJUB) { - Some(_) => return Ok((j, d_j)), - None => { - if j.increment().is_err() { - return Err(()); - } - } - } - } - } -} - -/// A Sapling extended spending key -#[derive(Clone)] -pub struct ExtendedSpendingKey { - depth: u8, - parent_fvk_tag: FVKTag, - child_index: ChildIndex, - chain_code: ChainCode, - pub expsk: ExpandedSpendingKey, - dk: DiversifierKey, -} - -// A Sapling extended full viewing key -pub struct ExtendedFullViewingKey { - depth: u8, - parent_fvk_tag: FVKTag, - child_index: ChildIndex, - chain_code: ChainCode, - pub fvk: FullViewingKey, - dk: DiversifierKey, -} - -impl std::cmp::PartialEq for ExtendedSpendingKey { - fn eq(&self, rhs: &ExtendedSpendingKey) -> bool { - self.depth == rhs.depth - && self.parent_fvk_tag == rhs.parent_fvk_tag - && self.child_index == rhs.child_index - && self.chain_code == rhs.chain_code - && self.expsk.ask == rhs.expsk.ask - && self.expsk.nsk == rhs.expsk.nsk - && self.expsk.ovk == rhs.expsk.ovk - && self.dk == rhs.dk - } -} - -impl std::fmt::Debug for ExtendedSpendingKey { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - write!( - f, - "ExtendedSpendingKey(d = {}, tag_p = {:?}, i = {:?})", - self.depth, self.parent_fvk_tag, self.child_index - ) - } -} - -impl std::cmp::PartialEq for ExtendedFullViewingKey { - fn eq(&self, rhs: &ExtendedFullViewingKey) -> bool { - self.depth == rhs.depth - && self.parent_fvk_tag == rhs.parent_fvk_tag - && self.child_index == rhs.child_index - && self.chain_code == rhs.chain_code - && self.fvk.vk.ak == rhs.fvk.vk.ak - && self.fvk.vk.nk == rhs.fvk.vk.nk - && self.fvk.ovk == rhs.fvk.ovk - && self.dk == rhs.dk - } -} - -impl std::fmt::Debug for ExtendedFullViewingKey { - fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - write!( - f, - "ExtendedFullViewingKey(d = {}, tag_p = {:?}, i = {:?})", - self.depth, self.parent_fvk_tag, self.child_index - ) - } -} - -impl ExtendedSpendingKey { - pub fn master(seed: &[u8]) -> Self { - let mut h = Blake2b::with_params(64, &[], &[], ZIP32_SAPLING_MASTER_PERSONALIZATION); - h.update(seed); - let i = h.finalize(); - - let sk_m = &i.as_bytes()[..32]; - let mut c_m = [0u8; 32]; - c_m.copy_from_slice(&i.as_bytes()[32..]); - - ExtendedSpendingKey { - depth: 0, - parent_fvk_tag: FVKTag::master(), - child_index: ChildIndex::master(), - chain_code: ChainCode(c_m), - expsk: ExpandedSpendingKey::from_spending_key(sk_m), - dk: DiversifierKey::master(sk_m), - } - } - - pub fn read(mut reader: R) -> io::Result { - let depth = reader.read_u8()?; - let mut tag = [0; 4]; - reader.read_exact(&mut tag)?; - let i = reader.read_u32::()?; - let mut c = [0; 32]; - reader.read_exact(&mut c)?; - let expsk = ExpandedSpendingKey::read(&mut reader)?; - let mut dk = [0; 32]; - reader.read_exact(&mut dk)?; - - Ok(ExtendedSpendingKey { - depth, - parent_fvk_tag: FVKTag(tag), - child_index: ChildIndex::from_index(i), - chain_code: ChainCode(c), - expsk, - dk: DiversifierKey(dk), - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_u8(self.depth)?; - writer.write_all(&self.parent_fvk_tag.0)?; - writer.write_u32::(self.child_index.to_index())?; - writer.write_all(&self.chain_code.0)?; - writer.write_all(&self.expsk.to_bytes())?; - writer.write_all(&self.dk.0)?; - - Ok(()) - } - - /// Returns the child key corresponding to the path derived from the master key - pub fn from_path(master: &ExtendedSpendingKey, path: &[ChildIndex]) -> Self { - let mut xsk = master.clone(); - for &i in path.iter() { - xsk = xsk.derive_child(i); - } - xsk - } - - pub fn derive_child(&self, i: ChildIndex) -> Self { - let fvk = FullViewingKey::from_expanded_spending_key(&self.expsk, &JUBJUB); - let tmp = match i { - ChildIndex::Hardened(i) => { - let mut le_i = [0; 4]; - LittleEndian::write_u32(&mut le_i, i + (1 << 31)); - prf_expand_vec( - &self.chain_code.0, - &[&[0x11], &self.expsk.to_bytes(), &self.dk.0, &le_i], - ) - } - ChildIndex::NonHardened(i) => { - let mut le_i = [0; 4]; - LittleEndian::write_u32(&mut le_i, i); - prf_expand_vec( - &self.chain_code.0, - &[&[0x12], &fvk.to_bytes(), &self.dk.0, &le_i], - ) - } - }; - let i_l = &tmp.as_bytes()[..32]; - let mut c_i = [0u8; 32]; - c_i.copy_from_slice(&tmp.as_bytes()[32..]); - - ExtendedSpendingKey { - depth: self.depth + 1, - parent_fvk_tag: fvk.fingerprint().tag(), - child_index: i, - chain_code: ChainCode(c_i), - expsk: self.expsk.derive_child(i_l), - dk: self.dk.derive_child(i_l), - } - } - - pub fn default_address(&self) -> Result<(DiversifierIndex, PaymentAddress), ()> { - ExtendedFullViewingKey::from(self).default_address() - } -} - -impl<'a> From<&'a ExtendedSpendingKey> for ExtendedFullViewingKey { - fn from(xsk: &ExtendedSpendingKey) -> Self { - ExtendedFullViewingKey { - depth: xsk.depth, - parent_fvk_tag: xsk.parent_fvk_tag, - child_index: xsk.child_index, - chain_code: xsk.chain_code, - fvk: FullViewingKey::from_expanded_spending_key(&xsk.expsk, &JUBJUB), - dk: xsk.dk, - } - } -} - -impl ExtendedFullViewingKey { - pub fn read(mut reader: R) -> io::Result { - let depth = reader.read_u8()?; - let mut tag = [0; 4]; - reader.read_exact(&mut tag)?; - let i = reader.read_u32::()?; - let mut c = [0; 32]; - reader.read_exact(&mut c)?; - let fvk = FullViewingKey::read(&mut reader, &*JUBJUB)?; - let mut dk = [0; 32]; - reader.read_exact(&mut dk)?; - - Ok(ExtendedFullViewingKey { - depth, - parent_fvk_tag: FVKTag(tag), - child_index: ChildIndex::from_index(i), - chain_code: ChainCode(c), - fvk, - dk: DiversifierKey(dk), - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_u8(self.depth)?; - writer.write_all(&self.parent_fvk_tag.0)?; - writer.write_u32::(self.child_index.to_index())?; - writer.write_all(&self.chain_code.0)?; - writer.write_all(&self.fvk.to_bytes())?; - writer.write_all(&self.dk.0)?; - - Ok(()) - } - - pub fn derive_child(&self, i: ChildIndex) -> Result { - let tmp = match i { - ChildIndex::Hardened(_) => return Err(()), - ChildIndex::NonHardened(i) => { - let mut le_i = [0; 4]; - LittleEndian::write_u32(&mut le_i, i); - prf_expand_vec( - &self.chain_code.0, - &[&[0x12], &self.fvk.to_bytes(), &self.dk.0, &le_i], - ) - } - }; - let i_l = &tmp.as_bytes()[..32]; - let mut c_i = [0u8; 32]; - c_i.copy_from_slice(&tmp.as_bytes()[32..]); - - Ok(ExtendedFullViewingKey { - depth: self.depth + 1, - parent_fvk_tag: self.fvk.fingerprint().tag(), - child_index: i, - chain_code: ChainCode(c_i), - fvk: self.fvk.derive_child(i_l, &JUBJUB), - dk: self.dk.derive_child(i_l), - }) - } - - pub fn address( - &self, - j: DiversifierIndex, - ) -> Result<(DiversifierIndex, PaymentAddress), ()> { - let (j, d_j) = match self.dk.diversifier(j) { - Ok(ret) => ret, - Err(()) => return Err(()), - }; - match self.fvk.vk.into_payment_address(d_j, &JUBJUB) { - Some(addr) => Ok((j, addr)), - None => Err(()), - } - } - - pub fn default_address(&self) -> Result<(DiversifierIndex, PaymentAddress), ()> { - self.address(DiversifierIndex::new()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn derive_nonhardened_child() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - let xfvk_m = ExtendedFullViewingKey::from(&xsk_m); - - let i_5 = ChildIndex::NonHardened(5); - let xsk_5 = xsk_m.derive_child(i_5); - let xfvk_5 = xfvk_m.derive_child(i_5); - - assert!(xfvk_5.is_ok()); - assert_eq!(ExtendedFullViewingKey::from(&xsk_5), xfvk_5.unwrap()); - } - - #[test] - fn derive_hardened_child() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - let xfvk_m = ExtendedFullViewingKey::from(&xsk_m); - - let i_5h = ChildIndex::Hardened(5); - let xsk_5h = xsk_m.derive_child(i_5h); - let xfvk_5h = xfvk_m.derive_child(i_5h); - - // Cannot derive a hardened child from an ExtendedFullViewingKey - assert!(xfvk_5h.is_err()); - let xfvk_5h = ExtendedFullViewingKey::from(&xsk_5h); - - let i_7 = ChildIndex::NonHardened(7); - let xsk_5h_7 = xsk_5h.derive_child(i_7); - let xfvk_5h_7 = xfvk_5h.derive_child(i_7); - - // But we *can* derive a non-hardened child from a hardened parent - assert!(xfvk_5h_7.is_ok()); - assert_eq!(ExtendedFullViewingKey::from(&xsk_5h_7), xfvk_5h_7.unwrap()); - } - - #[test] - fn path() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - - let xsk_5h = xsk_m.derive_child(ChildIndex::Hardened(5)); - assert_eq!( - ExtendedSpendingKey::from_path(&xsk_m, &[ChildIndex::Hardened(5)]), - xsk_5h - ); - - let xsk_5h_7 = xsk_5h.derive_child(ChildIndex::NonHardened(7)); - assert_eq!( - ExtendedSpendingKey::from_path( - &xsk_m, - &[ChildIndex::Hardened(5), ChildIndex::NonHardened(7)] - ), - xsk_5h_7 - ); - } - - #[test] - fn diversifier() { - let dk = DiversifierKey([0; 32]); - let j_0 = DiversifierIndex::new(); - let j_1 = DiversifierIndex([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - let j_2 = DiversifierIndex([2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - let j_3 = DiversifierIndex([3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - // Computed using this Rust implementation - let d_0 = [220, 231, 126, 188, 236, 10, 38, 175, 214, 153, 140]; - let d_3 = [60, 253, 170, 8, 171, 147, 220, 31, 3, 144, 34]; - - // j = 0 - let (j, d_j) = dk.diversifier(j_0).unwrap(); - assert_eq!(j, j_0); - assert_eq!(d_j.0, d_0); - - // j = 1 - let (j, d_j) = dk.diversifier(j_1).unwrap(); - assert_eq!(j, j_3); - assert_eq!(d_j.0, d_3); - - // j = 2 - let (j, d_j) = dk.diversifier(j_2).unwrap(); - assert_eq!(j, j_3); - assert_eq!(d_j.0, d_3); - - // j = 3 - let (j, d_j) = dk.diversifier(j_3).unwrap(); - assert_eq!(j, j_3); - assert_eq!(d_j.0, d_3); - } - - #[test] - fn default_address() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - let (j_m, addr_m) = xsk_m.default_address().unwrap(); - assert_eq!(j_m.0, [0; 11]); - assert_eq!( - addr_m.diversifier.0, - // Computed using this Rust implementation - [59, 246, 250, 31, 131, 191, 69, 99, 200, 167, 19] - ); - } - - #[test] - fn read_write() { - let seed = [0; 32]; - let xsk = ExtendedSpendingKey::master(&seed); - let fvk = ExtendedFullViewingKey::from(&xsk); - - let mut ser = vec![]; - xsk.write(&mut ser).unwrap(); - let xsk2 = ExtendedSpendingKey::read(&ser[..]).unwrap(); - assert_eq!(xsk2, xsk); - - let mut ser = vec![]; - fvk.write(&mut ser).unwrap(); - let fvk2 = ExtendedFullViewingKey::read(&ser[..]).unwrap(); - assert_eq!(fvk2, fvk); - } - - #[test] - fn test_vectors() { - struct TestVector { - ask: Option<[u8; 32]>, - nsk: Option<[u8; 32]>, - ovk: [u8; 32], - dk: [u8; 32], - c: [u8; 32], - ak: [u8; 32], - nk: [u8; 32], - ivk: [u8; 32], - xsk: Option<[u8; 169]>, - xfvk: [u8; 169], - fp: [u8; 32], - d0: Option<[u8; 11]>, - d1: Option<[u8; 11]>, - d2: Option<[u8; 11]>, - dmax: Option<[u8; 11]>, - }; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_zip32.py - let test_vectors = vec![ - TestVector { - ask: Some([ - 0xb6, 0xc0, 0x0c, 0x93, 0xd3, 0x60, 0x32, 0xb9, 0xa2, 0x68, 0xe9, 0x9e, 0x86, - 0xa8, 0x60, 0x77, 0x65, 0x60, 0xbf, 0x0e, 0x83, 0xc1, 0xa1, 0x0b, 0x51, 0xf6, - 0x07, 0xc9, 0x54, 0x74, 0x25, 0x06, - ]), - nsk: Some([ - 0x82, 0x04, 0xed, 0xe8, 0x3b, 0x2f, 0x1f, 0xbd, 0x84, 0xf9, 0xb4, 0x5d, 0x7f, - 0x99, 0x6e, 0x2e, 0xbd, 0x0a, 0x03, 0x0a, 0xd2, 0x43, 0xb4, 0x8e, 0xd3, 0x9f, - 0x74, 0x8a, 0x88, 0x21, 0xea, 0x06, - ]), - ovk: [ - 0x39, 0x58, 0x84, 0x89, 0x03, 0x23, 0xb9, 0xd4, 0x93, 0x3c, 0x02, 0x1d, 0xb8, - 0x9b, 0xcf, 0x76, 0x7d, 0xf2, 0x19, 0x77, 0xb2, 0xff, 0x06, 0x83, 0x84, 0x83, - 0x21, 0xa4, 0xdf, 0x4a, 0xfb, 0x21, - ], - dk: [ - 0x77, 0xc1, 0x7c, 0xb7, 0x5b, 0x77, 0x96, 0xaf, 0xb3, 0x9f, 0x0f, 0x3e, 0x91, - 0xc9, 0x24, 0x60, 0x7d, 0xa5, 0x6f, 0xa9, 0xa2, 0x0e, 0x28, 0x35, 0x09, 0xbc, - 0x8a, 0x3e, 0xf9, 0x96, 0xa1, 0x72, - ], - c: [ - 0xd0, 0x94, 0x7c, 0x4b, 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, - 0x6d, 0x1c, 0xf3, 0xfd, 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, - 0x0d, 0x75, 0x20, 0x18, 0x66, 0x8e, - ], - ak: [ - 0x93, 0x44, 0x2e, 0x5f, 0xef, 0xfb, 0xff, 0x16, 0xe7, 0x21, 0x72, 0x02, 0xdc, - 0x73, 0x06, 0x72, 0x9f, 0xff, 0xfe, 0x85, 0xaf, 0x56, 0x83, 0xbc, 0xe2, 0x64, - 0x2e, 0x3e, 0xeb, 0x5d, 0x38, 0x71, - ], - nk: [ - 0xdc, 0xe8, 0xe7, 0xed, 0xec, 0xe0, 0x4b, 0x89, 0x50, 0x41, 0x7f, 0x85, 0xba, - 0x57, 0x69, 0x1b, 0x78, 0x3c, 0x45, 0xb1, 0xa2, 0x74, 0x22, 0xdb, 0x16, 0x93, - 0xdc, 0xeb, 0x67, 0xb1, 0x01, 0x06, - ], - ivk: [ - 0x48, 0x47, 0xa1, 0x30, 0xe7, 0x99, 0xd3, 0xdb, 0xea, 0x36, 0xa1, 0xc1, 0x64, - 0x67, 0xd6, 0x21, 0xfb, 0x2d, 0x80, 0xe3, 0x0b, 0x3b, 0x1d, 0x1a, 0x42, 0x68, - 0x93, 0x41, 0x5d, 0xad, 0x66, 0x01, - ], - xsk: Some([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x94, 0x7c, 0x4b, - 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, 0x6d, 0x1c, 0xf3, 0xfd, - 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, 0x0d, 0x75, 0x20, 0x18, - 0x66, 0x8e, 0xb6, 0xc0, 0x0c, 0x93, 0xd3, 0x60, 0x32, 0xb9, 0xa2, 0x68, 0xe9, - 0x9e, 0x86, 0xa8, 0x60, 0x77, 0x65, 0x60, 0xbf, 0x0e, 0x83, 0xc1, 0xa1, 0x0b, - 0x51, 0xf6, 0x07, 0xc9, 0x54, 0x74, 0x25, 0x06, 0x82, 0x04, 0xed, 0xe8, 0x3b, - 0x2f, 0x1f, 0xbd, 0x84, 0xf9, 0xb4, 0x5d, 0x7f, 0x99, 0x6e, 0x2e, 0xbd, 0x0a, - 0x03, 0x0a, 0xd2, 0x43, 0xb4, 0x8e, 0xd3, 0x9f, 0x74, 0x8a, 0x88, 0x21, 0xea, - 0x06, 0x39, 0x58, 0x84, 0x89, 0x03, 0x23, 0xb9, 0xd4, 0x93, 0x3c, 0x02, 0x1d, - 0xb8, 0x9b, 0xcf, 0x76, 0x7d, 0xf2, 0x19, 0x77, 0xb2, 0xff, 0x06, 0x83, 0x84, - 0x83, 0x21, 0xa4, 0xdf, 0x4a, 0xfb, 0x21, 0x77, 0xc1, 0x7c, 0xb7, 0x5b, 0x77, - 0x96, 0xaf, 0xb3, 0x9f, 0x0f, 0x3e, 0x91, 0xc9, 0x24, 0x60, 0x7d, 0xa5, 0x6f, - 0xa9, 0xa2, 0x0e, 0x28, 0x35, 0x09, 0xbc, 0x8a, 0x3e, 0xf9, 0x96, 0xa1, 0x72, - ]), - xfvk: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x94, 0x7c, 0x4b, - 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, 0x6d, 0x1c, 0xf3, 0xfd, - 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, 0x0d, 0x75, 0x20, 0x18, - 0x66, 0x8e, 0x93, 0x44, 0x2e, 0x5f, 0xef, 0xfb, 0xff, 0x16, 0xe7, 0x21, 0x72, - 0x02, 0xdc, 0x73, 0x06, 0x72, 0x9f, 0xff, 0xfe, 0x85, 0xaf, 0x56, 0x83, 0xbc, - 0xe2, 0x64, 0x2e, 0x3e, 0xeb, 0x5d, 0x38, 0x71, 0xdc, 0xe8, 0xe7, 0xed, 0xec, - 0xe0, 0x4b, 0x89, 0x50, 0x41, 0x7f, 0x85, 0xba, 0x57, 0x69, 0x1b, 0x78, 0x3c, - 0x45, 0xb1, 0xa2, 0x74, 0x22, 0xdb, 0x16, 0x93, 0xdc, 0xeb, 0x67, 0xb1, 0x01, - 0x06, 0x39, 0x58, 0x84, 0x89, 0x03, 0x23, 0xb9, 0xd4, 0x93, 0x3c, 0x02, 0x1d, - 0xb8, 0x9b, 0xcf, 0x76, 0x7d, 0xf2, 0x19, 0x77, 0xb2, 0xff, 0x06, 0x83, 0x84, - 0x83, 0x21, 0xa4, 0xdf, 0x4a, 0xfb, 0x21, 0x77, 0xc1, 0x7c, 0xb7, 0x5b, 0x77, - 0x96, 0xaf, 0xb3, 0x9f, 0x0f, 0x3e, 0x91, 0xc9, 0x24, 0x60, 0x7d, 0xa5, 0x6f, - 0xa9, 0xa2, 0x0e, 0x28, 0x35, 0x09, 0xbc, 0x8a, 0x3e, 0xf9, 0x96, 0xa1, 0x72, - ], - fp: [ - 0x14, 0xc2, 0x71, 0x3a, 0xdc, 0xe9, 0x3a, 0x83, 0x0e, 0xa8, 0x3a, 0x05, 0x19, - 0x08, 0xb7, 0x44, 0x77, 0x83, 0xf5, 0xd1, 0x06, 0xc0, 0x98, 0x5e, 0x02, 0x55, - 0x0e, 0x42, 0x6f, 0x27, 0x59, 0x7c, - ], - d0: Some([ - 0xd8, 0x62, 0x1b, 0x98, 0x1c, 0xf3, 0x00, 0xe9, 0xd4, 0xcc, 0x89, - ]), - d1: Some([ - 0x48, 0xea, 0x17, 0xa1, 0x99, 0xc8, 0x4b, 0xd1, 0xba, 0xa5, 0xd4, - ]), - d2: None, - dmax: None, - }, - TestVector { - ask: Some([ - 0x28, 0x2b, 0xc1, 0x97, 0xa5, 0x16, 0x28, 0x7c, 0x8e, 0xa8, 0xf6, 0x8c, 0x42, - 0x4a, 0xba, 0xd3, 0x02, 0xb4, 0x5c, 0xdf, 0x95, 0x40, 0x79, 0x61, 0xd7, 0xb8, - 0xb4, 0x55, 0x26, 0x7a, 0x35, 0x0c, - ]), - nsk: Some([ - 0xe7, 0xa3, 0x29, 0x88, 0xfd, 0xca, 0x1e, 0xfc, 0xd6, 0xd1, 0xc4, 0xc5, 0x62, - 0xe6, 0x29, 0xc2, 0xe9, 0x6b, 0x2c, 0x3f, 0x7e, 0xda, 0x04, 0xac, 0x4e, 0xfd, - 0x18, 0x10, 0xff, 0x6b, 0xba, 0x01, - ]), - ovk: [ - 0x5f, 0x13, 0x81, 0xfc, 0x88, 0x86, 0xda, 0x6a, 0x02, 0xdf, 0xfe, 0xef, 0xcf, - 0x50, 0x3c, 0x40, 0xfa, 0x8f, 0x5a, 0x36, 0xf7, 0xa7, 0x14, 0x2f, 0xd8, 0x1b, - 0x55, 0x18, 0xc5, 0xa4, 0x74, 0x74, - ], - dk: [ - 0xe0, 0x4d, 0xe8, 0x32, 0xa2, 0xd7, 0x91, 0xec, 0x12, 0x9a, 0xb9, 0x00, 0x2b, - 0x91, 0xc9, 0xe9, 0xcd, 0xee, 0xd7, 0x92, 0x41, 0xa7, 0xc4, 0x96, 0x0e, 0x51, - 0x78, 0xd8, 0x70, 0xc1, 0xb4, 0xdc, - ], - c: [ - 0x01, 0x47, 0x11, 0x0c, 0x69, 0x1a, 0x03, 0xb9, 0xd9, 0xf0, 0xba, 0x90, 0x05, - 0xc5, 0xe7, 0x90, 0xa5, 0x95, 0xb7, 0xf0, 0x4e, 0x33, 0x29, 0xd2, 0xfa, 0x43, - 0x8a, 0x67, 0x05, 0xda, 0xbc, 0xe6, - ], - ak: [ - 0xdc, 0x14, 0xb5, 0x14, 0xd3, 0xa9, 0x25, 0x94, 0xc2, 0x19, 0x25, 0xaf, 0x2f, - 0x77, 0x65, 0xa5, 0x47, 0xb3, 0x0e, 0x73, 0xfa, 0x7b, 0x70, 0x0e, 0xa1, 0xbf, - 0xf2, 0xe5, 0xef, 0xaa, 0xa8, 0x8b, - ], - nk: [ - 0x61, 0x52, 0xeb, 0x7f, 0xdb, 0x25, 0x27, 0x79, 0xdd, 0xcb, 0x95, 0xd2, 0x17, - 0xea, 0x4b, 0x6f, 0xd3, 0x40, 0x36, 0xe9, 0xad, 0xad, 0xb3, 0xb5, 0xc9, 0xcb, - 0xec, 0xeb, 0x41, 0xba, 0x45, 0x2a, - ], - ivk: [ - 0x15, 0x5a, 0x8e, 0xe2, 0x05, 0xd3, 0x87, 0x2d, 0x12, 0xf8, 0xa3, 0xe6, 0x39, - 0x91, 0x46, 0x33, 0xc2, 0x3c, 0xde, 0x1f, 0x30, 0xed, 0x50, 0x51, 0xe5, 0x21, - 0x30, 0xb1, 0xd0, 0x10, 0x4c, 0x06, - ], - xsk: Some([ - 0x01, 0x14, 0xc2, 0x71, 0x3a, 0x01, 0x00, 0x00, 0x00, 0x01, 0x47, 0x11, 0x0c, - 0x69, 0x1a, 0x03, 0xb9, 0xd9, 0xf0, 0xba, 0x90, 0x05, 0xc5, 0xe7, 0x90, 0xa5, - 0x95, 0xb7, 0xf0, 0x4e, 0x33, 0x29, 0xd2, 0xfa, 0x43, 0x8a, 0x67, 0x05, 0xda, - 0xbc, 0xe6, 0x28, 0x2b, 0xc1, 0x97, 0xa5, 0x16, 0x28, 0x7c, 0x8e, 0xa8, 0xf6, - 0x8c, 0x42, 0x4a, 0xba, 0xd3, 0x02, 0xb4, 0x5c, 0xdf, 0x95, 0x40, 0x79, 0x61, - 0xd7, 0xb8, 0xb4, 0x55, 0x26, 0x7a, 0x35, 0x0c, 0xe7, 0xa3, 0x29, 0x88, 0xfd, - 0xca, 0x1e, 0xfc, 0xd6, 0xd1, 0xc4, 0xc5, 0x62, 0xe6, 0x29, 0xc2, 0xe9, 0x6b, - 0x2c, 0x3f, 0x7e, 0xda, 0x04, 0xac, 0x4e, 0xfd, 0x18, 0x10, 0xff, 0x6b, 0xba, - 0x01, 0x5f, 0x13, 0x81, 0xfc, 0x88, 0x86, 0xda, 0x6a, 0x02, 0xdf, 0xfe, 0xef, - 0xcf, 0x50, 0x3c, 0x40, 0xfa, 0x8f, 0x5a, 0x36, 0xf7, 0xa7, 0x14, 0x2f, 0xd8, - 0x1b, 0x55, 0x18, 0xc5, 0xa4, 0x74, 0x74, 0xe0, 0x4d, 0xe8, 0x32, 0xa2, 0xd7, - 0x91, 0xec, 0x12, 0x9a, 0xb9, 0x00, 0x2b, 0x91, 0xc9, 0xe9, 0xcd, 0xee, 0xd7, - 0x92, 0x41, 0xa7, 0xc4, 0x96, 0x0e, 0x51, 0x78, 0xd8, 0x70, 0xc1, 0xb4, 0xdc, - ]), - xfvk: [ - 0x01, 0x14, 0xc2, 0x71, 0x3a, 0x01, 0x00, 0x00, 0x00, 0x01, 0x47, 0x11, 0x0c, - 0x69, 0x1a, 0x03, 0xb9, 0xd9, 0xf0, 0xba, 0x90, 0x05, 0xc5, 0xe7, 0x90, 0xa5, - 0x95, 0xb7, 0xf0, 0x4e, 0x33, 0x29, 0xd2, 0xfa, 0x43, 0x8a, 0x67, 0x05, 0xda, - 0xbc, 0xe6, 0xdc, 0x14, 0xb5, 0x14, 0xd3, 0xa9, 0x25, 0x94, 0xc2, 0x19, 0x25, - 0xaf, 0x2f, 0x77, 0x65, 0xa5, 0x47, 0xb3, 0x0e, 0x73, 0xfa, 0x7b, 0x70, 0x0e, - 0xa1, 0xbf, 0xf2, 0xe5, 0xef, 0xaa, 0xa8, 0x8b, 0x61, 0x52, 0xeb, 0x7f, 0xdb, - 0x25, 0x27, 0x79, 0xdd, 0xcb, 0x95, 0xd2, 0x17, 0xea, 0x4b, 0x6f, 0xd3, 0x40, - 0x36, 0xe9, 0xad, 0xad, 0xb3, 0xb5, 0xc9, 0xcb, 0xec, 0xeb, 0x41, 0xba, 0x45, - 0x2a, 0x5f, 0x13, 0x81, 0xfc, 0x88, 0x86, 0xda, 0x6a, 0x02, 0xdf, 0xfe, 0xef, - 0xcf, 0x50, 0x3c, 0x40, 0xfa, 0x8f, 0x5a, 0x36, 0xf7, 0xa7, 0x14, 0x2f, 0xd8, - 0x1b, 0x55, 0x18, 0xc5, 0xa4, 0x74, 0x74, 0xe0, 0x4d, 0xe8, 0x32, 0xa2, 0xd7, - 0x91, 0xec, 0x12, 0x9a, 0xb9, 0x00, 0x2b, 0x91, 0xc9, 0xe9, 0xcd, 0xee, 0xd7, - 0x92, 0x41, 0xa7, 0xc4, 0x96, 0x0e, 0x51, 0x78, 0xd8, 0x70, 0xc1, 0xb4, 0xdc, - ], - fp: [ - 0xdb, 0x99, 0x9e, 0x07, 0x1d, 0xcb, 0x58, 0xdd, 0x93, 0x02, 0x9a, 0xe6, 0x97, - 0x05, 0x3e, 0x90, 0xed, 0xb3, 0x59, 0xd1, 0xa1, 0xb7, 0xa1, 0x25, 0x16, 0x7e, - 0xfb, 0xe9, 0x28, 0x06, 0x84, 0x23, - ], - d0: Some([ - 0x8b, 0x41, 0x38, 0x32, 0x0d, 0xfa, 0xfd, 0x7b, 0x39, 0x97, 0x81, - ]), - d1: None, - d2: Some([ - 0x57, 0x49, 0xa1, 0x33, 0x52, 0xbc, 0x22, 0x3e, 0x30, 0x80, 0x78, - ]), - dmax: Some([ - 0x63, 0x89, 0x57, 0x4c, 0xde, 0x0f, 0xbb, 0xc6, 0x36, 0x81, 0x31, - ]), - }, - TestVector { - ask: Some([ - 0x8b, 0xe8, 0x11, 0x3c, 0xee, 0x34, 0x13, 0xa7, 0x1f, 0x82, 0xc4, 0x1f, 0xc8, - 0xda, 0x51, 0x7b, 0xe1, 0x34, 0x04, 0x98, 0x32, 0xe6, 0x82, 0x5c, 0x92, 0xda, - 0x6b, 0x84, 0xfe, 0xe4, 0xc6, 0x0d, - ]), - nsk: Some([ - 0x37, 0x78, 0x05, 0x9d, 0xc5, 0x69, 0xe7, 0xd0, 0xd3, 0x23, 0x91, 0x57, 0x3f, - 0x95, 0x1b, 0xbd, 0xe9, 0x2f, 0xc6, 0xb9, 0xcf, 0x61, 0x47, 0x73, 0x66, 0x1c, - 0x5c, 0x27, 0x3a, 0xa6, 0x99, 0x0c, - ]), - ovk: [ - 0xcf, 0x81, 0x18, 0x2e, 0x96, 0x22, 0x3c, 0x02, 0x8c, 0xe3, 0xd6, 0xeb, 0x47, - 0x94, 0xd3, 0x11, 0x3b, 0x95, 0x06, 0x9d, 0x14, 0xc5, 0x75, 0x88, 0xe1, 0x93, - 0xb6, 0x5e, 0xfc, 0x28, 0x13, 0xbc, - ], - dk: [ - 0xa3, 0xed, 0xa1, 0x9f, 0x9e, 0xff, 0x46, 0xca, 0x12, 0xdf, 0xa1, 0xbf, 0x10, - 0x37, 0x1b, 0x48, 0xd1, 0xb4, 0xa4, 0x0c, 0x4d, 0x05, 0xa0, 0xd8, 0xdc, 0xe0, - 0xe7, 0xdc, 0x62, 0xb0, 0x7b, 0x37, - ], - c: [ - 0x97, 0xce, 0x15, 0xf4, 0xed, 0x1b, 0x97, 0x39, 0xb0, 0x26, 0x2a, 0x46, 0x3b, - 0xcb, 0x3d, 0xc9, 0xb3, 0xbd, 0x23, 0x23, 0xa9, 0xba, 0xa4, 0x41, 0xca, 0x42, - 0x77, 0x73, 0x83, 0xa8, 0xd4, 0x35, - ], - ak: [ - 0xa6, 0xc5, 0x92, 0x5a, 0x0f, 0x85, 0xfa, 0x4f, 0x1e, 0x40, 0x5e, 0x3a, 0x49, - 0x70, 0xd0, 0xc4, 0xa4, 0xb4, 0x81, 0x44, 0x38, 0xf4, 0xe9, 0xd4, 0x52, 0x0e, - 0x20, 0xf7, 0xfd, 0xcf, 0x38, 0x41, - ], - nk: [ - 0x30, 0x4e, 0x30, 0x59, 0x16, 0x21, 0x6b, 0xeb, 0x7b, 0x65, 0x4d, 0x8a, 0xae, - 0x50, 0xec, 0xd1, 0x88, 0xfc, 0xb3, 0x84, 0xbc, 0x36, 0xc0, 0x0c, 0x66, 0x4f, - 0x30, 0x77, 0x25, 0xe2, 0xee, 0x11, - ], - ivk: [ - 0xa2, 0xa1, 0x3c, 0x1e, 0x38, 0xb4, 0x59, 0x84, 0x44, 0x58, 0x03, 0xe4, 0x30, - 0xa6, 0x83, 0xc9, 0x0b, 0xb2, 0xe1, 0x4d, 0x4c, 0x86, 0x92, 0xff, 0x25, 0x3a, - 0x64, 0x84, 0xdd, 0x9b, 0xb5, 0x04, - ], - xsk: Some([ - 0x02, 0xdb, 0x99, 0x9e, 0x07, 0x02, 0x00, 0x00, 0x80, 0x97, 0xce, 0x15, 0xf4, - 0xed, 0x1b, 0x97, 0x39, 0xb0, 0x26, 0x2a, 0x46, 0x3b, 0xcb, 0x3d, 0xc9, 0xb3, - 0xbd, 0x23, 0x23, 0xa9, 0xba, 0xa4, 0x41, 0xca, 0x42, 0x77, 0x73, 0x83, 0xa8, - 0xd4, 0x35, 0x8b, 0xe8, 0x11, 0x3c, 0xee, 0x34, 0x13, 0xa7, 0x1f, 0x82, 0xc4, - 0x1f, 0xc8, 0xda, 0x51, 0x7b, 0xe1, 0x34, 0x04, 0x98, 0x32, 0xe6, 0x82, 0x5c, - 0x92, 0xda, 0x6b, 0x84, 0xfe, 0xe4, 0xc6, 0x0d, 0x37, 0x78, 0x05, 0x9d, 0xc5, - 0x69, 0xe7, 0xd0, 0xd3, 0x23, 0x91, 0x57, 0x3f, 0x95, 0x1b, 0xbd, 0xe9, 0x2f, - 0xc6, 0xb9, 0xcf, 0x61, 0x47, 0x73, 0x66, 0x1c, 0x5c, 0x27, 0x3a, 0xa6, 0x99, - 0x0c, 0xcf, 0x81, 0x18, 0x2e, 0x96, 0x22, 0x3c, 0x02, 0x8c, 0xe3, 0xd6, 0xeb, - 0x47, 0x94, 0xd3, 0x11, 0x3b, 0x95, 0x06, 0x9d, 0x14, 0xc5, 0x75, 0x88, 0xe1, - 0x93, 0xb6, 0x5e, 0xfc, 0x28, 0x13, 0xbc, 0xa3, 0xed, 0xa1, 0x9f, 0x9e, 0xff, - 0x46, 0xca, 0x12, 0xdf, 0xa1, 0xbf, 0x10, 0x37, 0x1b, 0x48, 0xd1, 0xb4, 0xa4, - 0x0c, 0x4d, 0x05, 0xa0, 0xd8, 0xdc, 0xe0, 0xe7, 0xdc, 0x62, 0xb0, 0x7b, 0x37, - ]), - xfvk: [ - 0x02, 0xdb, 0x99, 0x9e, 0x07, 0x02, 0x00, 0x00, 0x80, 0x97, 0xce, 0x15, 0xf4, - 0xed, 0x1b, 0x97, 0x39, 0xb0, 0x26, 0x2a, 0x46, 0x3b, 0xcb, 0x3d, 0xc9, 0xb3, - 0xbd, 0x23, 0x23, 0xa9, 0xba, 0xa4, 0x41, 0xca, 0x42, 0x77, 0x73, 0x83, 0xa8, - 0xd4, 0x35, 0xa6, 0xc5, 0x92, 0x5a, 0x0f, 0x85, 0xfa, 0x4f, 0x1e, 0x40, 0x5e, - 0x3a, 0x49, 0x70, 0xd0, 0xc4, 0xa4, 0xb4, 0x81, 0x44, 0x38, 0xf4, 0xe9, 0xd4, - 0x52, 0x0e, 0x20, 0xf7, 0xfd, 0xcf, 0x38, 0x41, 0x30, 0x4e, 0x30, 0x59, 0x16, - 0x21, 0x6b, 0xeb, 0x7b, 0x65, 0x4d, 0x8a, 0xae, 0x50, 0xec, 0xd1, 0x88, 0xfc, - 0xb3, 0x84, 0xbc, 0x36, 0xc0, 0x0c, 0x66, 0x4f, 0x30, 0x77, 0x25, 0xe2, 0xee, - 0x11, 0xcf, 0x81, 0x18, 0x2e, 0x96, 0x22, 0x3c, 0x02, 0x8c, 0xe3, 0xd6, 0xeb, - 0x47, 0x94, 0xd3, 0x11, 0x3b, 0x95, 0x06, 0x9d, 0x14, 0xc5, 0x75, 0x88, 0xe1, - 0x93, 0xb6, 0x5e, 0xfc, 0x28, 0x13, 0xbc, 0xa3, 0xed, 0xa1, 0x9f, 0x9e, 0xff, - 0x46, 0xca, 0x12, 0xdf, 0xa1, 0xbf, 0x10, 0x37, 0x1b, 0x48, 0xd1, 0xb4, 0xa4, - 0x0c, 0x4d, 0x05, 0xa0, 0xd8, 0xdc, 0xe0, 0xe7, 0xdc, 0x62, 0xb0, 0x7b, 0x37, - ], - fp: [ - 0x48, 0xc1, 0x83, 0x75, 0x7b, 0x5d, 0xa6, 0x61, 0x2a, 0x81, 0xb3, 0x0e, 0x40, - 0xb4, 0xac, 0xaa, 0x2d, 0x9e, 0x73, 0x95, 0x12, 0xe1, 0xd2, 0xd0, 0x01, 0x0e, - 0x92, 0xa7, 0xf7, 0xf2, 0xfc, 0xdf, - ], - d0: Some([ - 0xe8, 0xd0, 0x37, 0x93, 0xcd, 0xd2, 0xba, 0xcc, 0x9c, 0x70, 0x41, - ]), - d1: Some([ - 0x02, 0x0a, 0x7a, 0x6b, 0x0b, 0xf8, 0x4d, 0x3e, 0x89, 0x9f, 0x68, - ]), - d2: None, - dmax: None, - }, - TestVector { - ask: None, - nsk: None, - ovk: [ - 0xcf, 0x81, 0x18, 0x2e, 0x96, 0x22, 0x3c, 0x02, 0x8c, 0xe3, 0xd6, 0xeb, 0x47, - 0x94, 0xd3, 0x11, 0x3b, 0x95, 0x06, 0x9d, 0x14, 0xc5, 0x75, 0x88, 0xe1, 0x93, - 0xb6, 0x5e, 0xfc, 0x28, 0x13, 0xbc, - ], - dk: [ - 0xa3, 0xed, 0xa1, 0x9f, 0x9e, 0xff, 0x46, 0xca, 0x12, 0xdf, 0xa1, 0xbf, 0x10, - 0x37, 0x1b, 0x48, 0xd1, 0xb4, 0xa4, 0x0c, 0x4d, 0x05, 0xa0, 0xd8, 0xdc, 0xe0, - 0xe7, 0xdc, 0x62, 0xb0, 0x7b, 0x37, - ], - c: [ - 0x97, 0xce, 0x15, 0xf4, 0xed, 0x1b, 0x97, 0x39, 0xb0, 0x26, 0x2a, 0x46, 0x3b, - 0xcb, 0x3d, 0xc9, 0xb3, 0xbd, 0x23, 0x23, 0xa9, 0xba, 0xa4, 0x41, 0xca, 0x42, - 0x77, 0x73, 0x83, 0xa8, 0xd4, 0x35, - ], - ak: [ - 0xa6, 0xc5, 0x92, 0x5a, 0x0f, 0x85, 0xfa, 0x4f, 0x1e, 0x40, 0x5e, 0x3a, 0x49, - 0x70, 0xd0, 0xc4, 0xa4, 0xb4, 0x81, 0x44, 0x38, 0xf4, 0xe9, 0xd4, 0x52, 0x0e, - 0x20, 0xf7, 0xfd, 0xcf, 0x38, 0x41, - ], - nk: [ - 0x30, 0x4e, 0x30, 0x59, 0x16, 0x21, 0x6b, 0xeb, 0x7b, 0x65, 0x4d, 0x8a, 0xae, - 0x50, 0xec, 0xd1, 0x88, 0xfc, 0xb3, 0x84, 0xbc, 0x36, 0xc0, 0x0c, 0x66, 0x4f, - 0x30, 0x77, 0x25, 0xe2, 0xee, 0x11, - ], - ivk: [ - 0xa2, 0xa1, 0x3c, 0x1e, 0x38, 0xb4, 0x59, 0x84, 0x44, 0x58, 0x03, 0xe4, 0x30, - 0xa6, 0x83, 0xc9, 0x0b, 0xb2, 0xe1, 0x4d, 0x4c, 0x86, 0x92, 0xff, 0x25, 0x3a, - 0x64, 0x84, 0xdd, 0x9b, 0xb5, 0x04, - ], - xsk: None, - xfvk: [ - 0x02, 0xdb, 0x99, 0x9e, 0x07, 0x02, 0x00, 0x00, 0x80, 0x97, 0xce, 0x15, 0xf4, - 0xed, 0x1b, 0x97, 0x39, 0xb0, 0x26, 0x2a, 0x46, 0x3b, 0xcb, 0x3d, 0xc9, 0xb3, - 0xbd, 0x23, 0x23, 0xa9, 0xba, 0xa4, 0x41, 0xca, 0x42, 0x77, 0x73, 0x83, 0xa8, - 0xd4, 0x35, 0xa6, 0xc5, 0x92, 0x5a, 0x0f, 0x85, 0xfa, 0x4f, 0x1e, 0x40, 0x5e, - 0x3a, 0x49, 0x70, 0xd0, 0xc4, 0xa4, 0xb4, 0x81, 0x44, 0x38, 0xf4, 0xe9, 0xd4, - 0x52, 0x0e, 0x20, 0xf7, 0xfd, 0xcf, 0x38, 0x41, 0x30, 0x4e, 0x30, 0x59, 0x16, - 0x21, 0x6b, 0xeb, 0x7b, 0x65, 0x4d, 0x8a, 0xae, 0x50, 0xec, 0xd1, 0x88, 0xfc, - 0xb3, 0x84, 0xbc, 0x36, 0xc0, 0x0c, 0x66, 0x4f, 0x30, 0x77, 0x25, 0xe2, 0xee, - 0x11, 0xcf, 0x81, 0x18, 0x2e, 0x96, 0x22, 0x3c, 0x02, 0x8c, 0xe3, 0xd6, 0xeb, - 0x47, 0x94, 0xd3, 0x11, 0x3b, 0x95, 0x06, 0x9d, 0x14, 0xc5, 0x75, 0x88, 0xe1, - 0x93, 0xb6, 0x5e, 0xfc, 0x28, 0x13, 0xbc, 0xa3, 0xed, 0xa1, 0x9f, 0x9e, 0xff, - 0x46, 0xca, 0x12, 0xdf, 0xa1, 0xbf, 0x10, 0x37, 0x1b, 0x48, 0xd1, 0xb4, 0xa4, - 0x0c, 0x4d, 0x05, 0xa0, 0xd8, 0xdc, 0xe0, 0xe7, 0xdc, 0x62, 0xb0, 0x7b, 0x37, - ], - fp: [ - 0x48, 0xc1, 0x83, 0x75, 0x7b, 0x5d, 0xa6, 0x61, 0x2a, 0x81, 0xb3, 0x0e, 0x40, - 0xb4, 0xac, 0xaa, 0x2d, 0x9e, 0x73, 0x95, 0x12, 0xe1, 0xd2, 0xd0, 0x01, 0x0e, - 0x92, 0xa7, 0xf7, 0xf2, 0xfc, 0xdf, - ], - d0: Some([ - 0xe8, 0xd0, 0x37, 0x93, 0xcd, 0xd2, 0xba, 0xcc, 0x9c, 0x70, 0x41, - ]), - d1: Some([ - 0x02, 0x0a, 0x7a, 0x6b, 0x0b, 0xf8, 0x4d, 0x3e, 0x89, 0x9f, 0x68, - ]), - d2: None, - dmax: None, - }, - TestVector { - ask: None, - nsk: None, - ovk: [ - 0x69, 0xb9, 0xe0, 0xfa, 0x1c, 0x4b, 0x3d, 0xeb, 0x91, 0xd5, 0x3b, 0xee, 0xe8, - 0x71, 0x15, 0x61, 0x21, 0x47, 0x4b, 0x8b, 0x62, 0xef, 0x24, 0x13, 0x44, 0x78, - 0xdc, 0x34, 0x99, 0x69, 0x1a, 0xf6, - ], - dk: [ - 0xbe, 0xcb, 0x50, 0xc3, 0x63, 0xbb, 0x2e, 0xd9, 0xda, 0x5c, 0x30, 0x43, 0xce, - 0xb0, 0xf1, 0xa0, 0x52, 0x7b, 0xf8, 0x36, 0xb2, 0x9a, 0x35, 0xf7, 0xc0, 0xc9, - 0xf2, 0x61, 0x12, 0x3b, 0xe5, 0x6e, - ], - c: [ - 0x8d, 0x93, 0x7b, 0xcf, 0x81, 0xba, 0x43, 0x0d, 0x5b, 0x49, 0xaf, 0xc0, 0xa4, - 0x03, 0x36, 0x7b, 0x1f, 0xd9, 0x98, 0x79, 0xec, 0xba, 0x41, 0xbe, 0x05, 0x1c, - 0x5a, 0x4a, 0xa7, 0xd6, 0xe7, 0xe8, - ], - ak: [ - 0xb1, 0x85, 0xc5, 0x7b, 0x50, 0x9c, 0x25, 0x36, 0xc4, 0xf2, 0xd3, 0x26, 0xd7, - 0x66, 0xc8, 0xfa, 0xb2, 0x54, 0x47, 0xde, 0x53, 0x75, 0xa9, 0x32, 0x8d, 0x64, - 0x9d, 0xda, 0xbd, 0x97, 0xa6, 0xa3, - ], - nk: [ - 0xdb, 0x88, 0x04, 0x9e, 0x02, 0xd2, 0x07, 0x56, 0x8a, 0xfc, 0x42, 0xe0, 0x7d, - 0xb2, 0xab, 0xed, 0x50, 0x0b, 0x27, 0x01, 0xc0, 0x1b, 0xbf, 0xf3, 0x63, 0x99, - 0x76, 0x4b, 0x81, 0xc0, 0x66, 0x4f, - ], - ivk: [ - 0xb0, 0xa5, 0xf3, 0x37, 0x23, 0x2f, 0x2c, 0x3d, 0xac, 0x70, 0xc2, 0xa4, 0x10, - 0xfa, 0x56, 0x1f, 0xc4, 0x5d, 0x8c, 0xc5, 0x9c, 0xda, 0x24, 0x6d, 0x31, 0xc8, - 0xb1, 0x71, 0x5a, 0x57, 0xd9, 0x00, - ], - xsk: None, - xfvk: [ - 0x03, 0x48, 0xc1, 0x83, 0x75, 0x03, 0x00, 0x00, 0x00, 0x8d, 0x93, 0x7b, 0xcf, - 0x81, 0xba, 0x43, 0x0d, 0x5b, 0x49, 0xaf, 0xc0, 0xa4, 0x03, 0x36, 0x7b, 0x1f, - 0xd9, 0x98, 0x79, 0xec, 0xba, 0x41, 0xbe, 0x05, 0x1c, 0x5a, 0x4a, 0xa7, 0xd6, - 0xe7, 0xe8, 0xb1, 0x85, 0xc5, 0x7b, 0x50, 0x9c, 0x25, 0x36, 0xc4, 0xf2, 0xd3, - 0x26, 0xd7, 0x66, 0xc8, 0xfa, 0xb2, 0x54, 0x47, 0xde, 0x53, 0x75, 0xa9, 0x32, - 0x8d, 0x64, 0x9d, 0xda, 0xbd, 0x97, 0xa6, 0xa3, 0xdb, 0x88, 0x04, 0x9e, 0x02, - 0xd2, 0x07, 0x56, 0x8a, 0xfc, 0x42, 0xe0, 0x7d, 0xb2, 0xab, 0xed, 0x50, 0x0b, - 0x27, 0x01, 0xc0, 0x1b, 0xbf, 0xf3, 0x63, 0x99, 0x76, 0x4b, 0x81, 0xc0, 0x66, - 0x4f, 0x69, 0xb9, 0xe0, 0xfa, 0x1c, 0x4b, 0x3d, 0xeb, 0x91, 0xd5, 0x3b, 0xee, - 0xe8, 0x71, 0x15, 0x61, 0x21, 0x47, 0x4b, 0x8b, 0x62, 0xef, 0x24, 0x13, 0x44, - 0x78, 0xdc, 0x34, 0x99, 0x69, 0x1a, 0xf6, 0xbe, 0xcb, 0x50, 0xc3, 0x63, 0xbb, - 0x2e, 0xd9, 0xda, 0x5c, 0x30, 0x43, 0xce, 0xb0, 0xf1, 0xa0, 0x52, 0x7b, 0xf8, - 0x36, 0xb2, 0x9a, 0x35, 0xf7, 0xc0, 0xc9, 0xf2, 0x61, 0x12, 0x3b, 0xe5, 0x6e, - ], - fp: [ - 0x2e, 0x08, 0x15, 0x6d, 0xf8, 0xdf, 0xa2, 0x5b, 0x50, 0x55, 0xfc, 0x06, 0x3c, - 0x67, 0x15, 0x35, 0xa6, 0xa6, 0x5a, 0x60, 0x43, 0x7d, 0x96, 0xe7, 0x93, 0x08, - 0x15, 0xd0, 0x90, 0xf6, 0x2d, 0x67, - ], - d0: None, - d1: Some([ - 0x03, 0x0f, 0xfb, 0x26, 0x3a, 0x93, 0x9e, 0x23, 0x0e, 0x96, 0xdd, - ]), - d2: Some([ - 0x7b, 0xbf, 0x63, 0x93, 0x4c, 0x7e, 0x92, 0x67, 0x0c, 0xdb, 0x55, - ]), - dmax: Some([ - 0x1a, 0x73, 0x0f, 0xeb, 0x00, 0x59, 0xcf, 0x1f, 0x5b, 0xde, 0xa8, - ]), - }, - ]; - - let seed = [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - ]; - - let i1 = ChildIndex::NonHardened(1); - let i2h = ChildIndex::Hardened(2); - let i3 = ChildIndex::NonHardened(3); - - let m = ExtendedSpendingKey::master(&seed); - let m_1 = m.derive_child(i1); - let m_1_2h = ExtendedSpendingKey::from_path(&m, &[i1, i2h]); - let m_1_2hv = ExtendedFullViewingKey::from(&m_1_2h); - let m_1_2hv_3 = m_1_2hv.derive_child(i3).unwrap(); - - let xfvks = [ - ExtendedFullViewingKey::from(&m), - ExtendedFullViewingKey::from(&m_1), - ExtendedFullViewingKey::from(&m_1_2h), - m_1_2hv, // Appears twice so we can de-duplicate test code below - m_1_2hv_3, - ]; - assert_eq!(test_vectors.len(), xfvks.len()); - - let xsks = [m, m_1, m_1_2h]; - - for j in 0..xsks.len() { - let xsk = &xsks[j]; - let tv = &test_vectors[j]; - - let mut buf = [0; 32]; - xsk.expsk.ask.into_repr().write_le(&mut buf[..]).unwrap(); - assert_eq!(buf, tv.ask.unwrap()); - xsk.expsk.nsk.into_repr().write_le(&mut buf[..]).unwrap(); - assert_eq!(buf, tv.nsk.unwrap()); - - assert_eq!(xsk.expsk.ovk.0, tv.ovk); - assert_eq!(xsk.dk.0, tv.dk); - assert_eq!(xsk.chain_code.0, tv.c); - - let mut ser = vec![]; - xsk.write(&mut ser).unwrap(); - assert_eq!(&ser[..], &tv.xsk.unwrap()[..]); - } - - for j in 0..xfvks.len() { - let xfvk = &xfvks[j]; - let tv = &test_vectors[j]; - - let mut buf = [0; 32]; - xfvk.fvk.vk.ak.write(&mut buf[..]).unwrap(); - assert_eq!(buf, tv.ak); - xfvk.fvk.vk.nk.write(&mut buf[..]).unwrap(); - assert_eq!(buf, tv.nk); - - assert_eq!(xfvk.fvk.ovk.0, tv.ovk); - assert_eq!(xfvk.dk.0, tv.dk); - assert_eq!(xfvk.chain_code.0, tv.c); - - xfvk.fvk - .vk - .ivk() - .into_repr() - .write_le(&mut buf[..]) - .unwrap(); - assert_eq!(buf, tv.ivk); - - let mut ser = vec![]; - xfvk.write(&mut ser).unwrap(); - assert_eq!(&ser[..], &tv.xfvk[..]); - assert_eq!(xfvk.fvk.fingerprint().0, tv.fp); - - // d0 - let mut di = DiversifierIndex::new(); - match xfvk.dk.diversifier(di) { - Ok((l, d)) if l == di => assert_eq!(d.0, tv.d0.unwrap()), - Ok((_, _)) => assert!(tv.d0.is_none()), - Err(_) => panic!(), - } - - // d1 - di.increment().unwrap(); - match xfvk.dk.diversifier(di) { - Ok((l, d)) if l == di => assert_eq!(d.0, tv.d1.unwrap()), - Ok((_, _)) => assert!(tv.d1.is_none()), - Err(_) => panic!(), - } - - // d2 - di.increment().unwrap(); - match xfvk.dk.diversifier(di) { - Ok((l, d)) if l == di => assert_eq!(d.0, tv.d2.unwrap()), - Ok((_, _)) => assert!(tv.d2.is_none()), - Err(_) => panic!(), - } - - // dmax - let dmax = DiversifierIndex([0xff; 11]); - match xfvk.dk.diversifier(dmax) { - Ok((l, d)) if l == dmax => assert_eq!(d.0, tv.dmax.unwrap()), - Ok((_, _)) => panic!(), - Err(_) => assert!(tv.dmax.is_none()), - } - } - } -} From b52e4aac3af675269c0f7997cfafd15e89cd31c3 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 3 Mar 2020 17:39:11 -0700 Subject: [PATCH 324/330] Fix Field::random method declarations. --- bellman/src/groth16/tests/dummy_engine.rs | 2 +- zcash_primitives/src/jubjub/fs.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs index 4692078..b25e713 100644 --- a/bellman/src/groth16/tests/dummy_engine.rs +++ b/bellman/src/groth16/tests/dummy_engine.rs @@ -22,7 +22,7 @@ impl fmt::Display for Fr { } impl Field for Fr { - fn random(rng: &mut R) -> Self { + fn random(rng: &mut R) -> Self { Fr(Wrapping(rng.next_u32()) % MODULUS_R) } diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs index 7cf4d79..81120e6 100644 --- a/zcash_primitives/src/jubjub/fs.rs +++ b/zcash_primitives/src/jubjub/fs.rs @@ -317,7 +317,7 @@ impl PrimeField for Fs { } impl Field for Fs { - fn random(rng: &mut R) -> Self { + fn random(rng: &mut R) -> Self { loop { let mut tmp = { let mut repr = [0u64; 4]; From be0ee9eb829f2b684f3506e5f1b9d212a8af917a Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 3 Mar 2020 17:49:24 -0700 Subject: [PATCH 325/330] Changes to Cargo.lock to reflect upstream crate changes. --- Cargo.lock | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9a09a9d..2232447 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,13 +60,13 @@ dependencies = [ "blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.5.0", + "ff 0.5.2", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "group 0.2.0", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.15.0", + "pairing 0.15.1", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -270,16 +270,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ff" -version = "0.5.0" +version = "0.5.2" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff_derive 0.4.0", + "ff_derive 0.4.1", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ff_derive" -version = "0.4.0" +version = "0.4.1" dependencies = [ "num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", @@ -337,7 +337,7 @@ dependencies = [ name = "group" version = "0.2.0" dependencies = [ - "ff 0.5.0", + "ff 0.5.2", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -381,10 +381,10 @@ dependencies = [ "bellman 0.2.0", "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.5.0", + "ff 0.5.2", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.15.0", + "pairing 0.15.1", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "zcash_mmr 0.1.0 (git+https://github.com/nikvolf/zcash-mmr)", "zcash_primitives 0.1.0", @@ -454,10 +454,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "pairing" -version = "0.15.0" +version = "0.15.1" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.5.0", + "ff 0.5.2", "group 0.2.0", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -670,9 +670,9 @@ name = "zcash_client_backend" version = "0.1.0" dependencies = [ "bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.5.0", + "ff 0.5.2", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.15.0", + "pairing 0.15.1", "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf-codegen-pure 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -700,13 +700,13 @@ dependencies = [ "blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto_api_chachapoly 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.5.0", + "ff 0.5.2", "fpe 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.15.0", + "pairing 0.15.1", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -723,8 +723,8 @@ dependencies = [ "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.5.0", - "pairing 0.15.0", + "ff 0.5.2", + "pairing 0.15.1", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "zcash_primitives 0.1.0", From 9379eec1b8a222ed2ebf4fe0bfbf29fc3ddc9e8a Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 3 Mar 2020 18:02:31 -0700 Subject: [PATCH 326/330] Bring zcash_mmr into workspace. --- Cargo.lock | 212 +++++++++++++++++++++++++++++++++++++++- Cargo.toml | 1 + librustzcash/Cargo.toml | 2 +- 3 files changed, 211 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2232447..63a8edd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,6 +29,14 @@ dependencies = [ "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "aho-corasick" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "arrayref" version = "0.3.5" @@ -42,6 +50,11 @@ dependencies = [ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "assert_matches" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "autocfg" version = "0.1.6" @@ -87,6 +100,11 @@ name = "bit-vec" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "blake2b_simd" version = "0.5.8" @@ -163,6 +181,14 @@ name = "cfg-if" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "constant_time_eq" version = "0.1.4" @@ -263,6 +289,15 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "env_logger" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -301,6 +336,11 @@ dependencies = [ "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "futures" version = "0.1.29" @@ -386,7 +426,7 @@ dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.15.1", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_mmr 0.1.0 (git+https://github.com/nikvolf/zcash-mmr)", + "zcash_mmr 0.1.0", "zcash_primitives 0.1.0", "zcash_proofs 0.1.0", ] @@ -399,6 +439,11 @@ dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "memoffset" version = "0.5.1" @@ -508,6 +553,17 @@ dependencies = [ "protobuf-codegen 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quickcheck" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "1.0.2" @@ -516,6 +572,24 @@ dependencies = [ "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.7.0" @@ -528,6 +602,15 @@ dependencies = [ "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_chacha" version = "0.2.1" @@ -537,6 +620,19 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rand_core" version = "0.5.1" @@ -545,6 +641,14 @@ dependencies = [ "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_hc" version = "0.2.0" @@ -553,6 +657,54 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_xorshift" version = "0.2.0" @@ -561,6 +713,30 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ripemd160" version = "0.8.0" @@ -631,6 +807,14 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "typenum" version = "1.11.2" @@ -684,11 +868,12 @@ dependencies = [ [[package]] name = "zcash_mmr" version = "0.1.0" -source = "git+https://github.com/nikvolf/zcash-mmr#26be46573ee7e0094f19d861fd29793adda6298e" dependencies = [ + "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quickcheck 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -734,12 +919,15 @@ dependencies = [ "checksum aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "54eb1d8fe354e5fc611daf4f2ea97dd45a765f4f1e4512306ec183ae2e8f20c9" "checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" "checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" +"checksum aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d5e63fd144e18ba274ae7095c0197a870a7b9468abc801dd62f190d80817d2ec" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" +"checksum assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7deb0a829ca7bcfaf5da70b073a8d128619259a7be8216a355e23f00763059e5" "checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" "checksum bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0089c35ab7c6f2bc55ab23f769913f0ac65b1023e7e74638a1f43128dd5df2" "checksum bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebecac13b3c745150d7b6c3ea7572d372f09d627c2077e893bf26c5c7f70d282" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182" "checksum blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "979da0ce13c897d6be19e005ea77ac12b0fea0157aeeee7feb8c49f91386f0ea" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" @@ -750,6 +938,7 @@ dependencies = [ "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" "checksum crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2d818a4990769aac0c7ff1360e233ef3a41adcb009ebb2036bf6915eb0f6b23c" "checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" @@ -762,8 +951,10 @@ dependencies = [ "checksum crypto_api_chachapoly 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95b2ad7cab08fd71addba81df5077c49df208effdfb3118a1519f9cdeac5aaf2" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" "checksum directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72d337a64190607d4fcca2cb78982c5dd57f4916e19696b48a575fa746b6cb0f" +"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fpe 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21988a326139165b75e3196bc6962ca638e5fb0c95102fbf152a3743174b01e4" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" @@ -774,6 +965,7 @@ dependencies = [ "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a" @@ -787,12 +979,26 @@ dependencies = [ "checksum protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40361836defdd5871ff7e84096c6f6444af7fc157f8ef1789f54f147687caa20" "checksum protobuf-codegen 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "12c6abd78435445fc86898ebbd0521a68438063d4a73e23527b7134e6bf58b4a" "checksum protobuf-codegen-pure 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c1646acda5319f5b28b0bff4a484324df43ddae2c0f5a3f3e63c0b26095cd600" +"checksum quickcheck 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9c35d9c36a562f37eca96e79f66d5fd56eefbc22560dacc4a864cabd2d277456" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" +"checksum regex-syntax 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "1132f845907680735a84409c3bebc64d1364a5683ffbce899550cd09d5eaefc1" "checksum ripemd160 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad5112e0dbbb87577bfbc56c42450235e3012ce336e29c5befd7807bd626da4a" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" @@ -802,10 +1008,10 @@ dependencies = [ "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d" "checksum subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab3af2eb31c42e8f0ccf43548232556c42737e01a96db6e1777b0be108e79799" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" +"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum zcash_mmr 0.1.0 (git+https://github.com/nikvolf/zcash-mmr)" = "" diff --git a/Cargo.toml b/Cargo.toml index 69639cf..a147250 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "librustzcash", "pairing", "zcash_client_backend", + "zcash_history", "zcash_primitives", "zcash_proofs", ] diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index 64999f2..8c7d4ff 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -28,7 +28,7 @@ libc = "0.2" pairing = { version = "0.15.0", path = "../pairing" } lazy_static = "1" rand_core = "0.5.1" -zcash_mmr = { git = "https://github.com/nikvolf/zcash-mmr" } +zcash_mmr = { version = "0.1.0", path = "../zcash_history" } zcash_primitives = { version = "0.1.0", path = "../zcash_primitives" } zcash_proofs = { version = "0.1.0", path = "../zcash_proofs" } From 5e1a2f9d3fd1004d0f7a54a0e755ff5526da9354 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 3 Mar 2020 18:05:14 -0700 Subject: [PATCH 327/330] Rename zcash_mmr to zcash_history. This crate will contain all chain history logic. --- Cargo.lock | 6 +++--- librustzcash/Cargo.toml | 2 +- librustzcash/src/rustzcash.rs | 18 +++++++++--------- librustzcash/src/tests/mmr.rs | 16 ++++++++-------- zcash_history/.travis.yml | 4 ---- zcash_history/COPYRIGHT | 14 ++++++++++++++ zcash_history/Cargo.toml | 4 ++-- zcash_history/README.md | 6 +++--- zcash_history/examples/lib/shared.rs | 2 +- zcash_history/examples/long.rs | 2 +- zcash_history/src/lib.rs | 2 +- 11 files changed, 43 insertions(+), 33 deletions(-) delete mode 100644 zcash_history/.travis.yml create mode 100644 zcash_history/COPYRIGHT diff --git a/Cargo.lock b/Cargo.lock index 63a8edd..37967cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -426,7 +426,7 @@ dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "pairing 0.15.1", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_mmr 0.1.0", + "zcash_history 0.0.1", "zcash_primitives 0.1.0", "zcash_proofs 0.1.0", ] @@ -866,8 +866,8 @@ dependencies = [ ] [[package]] -name = "zcash_mmr" -version = "0.1.0" +name = "zcash_history" +version = "0.0.1" dependencies = [ "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/librustzcash/Cargo.toml b/librustzcash/Cargo.toml index 8c7d4ff..304dbdf 100644 --- a/librustzcash/Cargo.toml +++ b/librustzcash/Cargo.toml @@ -28,7 +28,7 @@ libc = "0.2" pairing = { version = "0.15.0", path = "../pairing" } lazy_static = "1" rand_core = "0.5.1" -zcash_mmr = { version = "0.1.0", path = "../zcash_history" } +zcash_history = { version = "0.0.1", path = "../zcash_history" } zcash_primitives = { version = "0.1.0", path = "../zcash_primitives" } zcash_proofs = { version = "0.1.0", path = "../zcash_proofs" } diff --git a/librustzcash/src/rustzcash.rs b/librustzcash/src/rustzcash.rs index 084d5b0..c60b1d5 100644 --- a/librustzcash/src/rustzcash.rs +++ b/librustzcash/src/rustzcash.rs @@ -65,7 +65,7 @@ use zcash_proofs::{ sprout, }; -use zcash_mmr::{Entry as MMREntry, NodeData as MMRNodeData, Tree as MMRTree}; +use zcash_history::{Entry as MMREntry, NodeData as MMRNodeData, Tree as MMRTree}; #[cfg(test)] mod tests; @@ -1173,7 +1173,7 @@ fn construct_mmr_tree( // Indices of provided tree nodes, length of p_len+e_len ni_ptr: *const u32, // Provided tree nodes data, length of p_len+e_len - n_ptr: *const [c_uchar; zcash_mmr::MAX_ENTRY_SIZE], + n_ptr: *const [c_uchar; zcash_history::MAX_ENTRY_SIZE], // Peaks count p_len: size_t, @@ -1211,17 +1211,17 @@ pub extern "system" fn librustzcash_mmr_append( // Indices of provided tree nodes, length of p_len ni_ptr: *const u32, // Provided tree nodes data, length of p_len - n_ptr: *const [c_uchar; zcash_mmr::MAX_ENTRY_SIZE], + n_ptr: *const [c_uchar; zcash_history::MAX_ENTRY_SIZE], // Peaks count p_len: size_t, // New node pointer - nn_ptr: *const [u8; zcash_mmr::MAX_NODE_DATA_SIZE], + nn_ptr: *const [u8; zcash_history::MAX_NODE_DATA_SIZE], // Return of root commitment rt_ret: *mut [u8; 32], // Return buffer for appended leaves, should be pre-allocated of ceiling(log2(t_len)) length - buf_ret: *mut [c_uchar; zcash_mmr::MAX_NODE_DATA_SIZE], + buf_ret: *mut [c_uchar; zcash_history::MAX_NODE_DATA_SIZE], ) -> u32 { - let new_node_bytes: &[u8; zcash_mmr::MAX_NODE_DATA_SIZE] = unsafe { + let new_node_bytes: &[u8; zcash_history::MAX_NODE_DATA_SIZE] = unsafe { match nn_ptr.as_ref() { Some(r) => r, None => { @@ -1283,7 +1283,7 @@ pub extern "system" fn librustzcash_mmr_delete( // Indices of provided tree nodes, length of p_len+e_len ni_ptr: *const u32, // Provided tree nodes data, length of p_len+e_len - n_ptr: *const [c_uchar; zcash_mmr::MAX_ENTRY_SIZE], + n_ptr: *const [c_uchar; zcash_history::MAX_ENTRY_SIZE], // Peaks count p_len: size_t, // Extra nodes loaded (for deletion) count @@ -1319,10 +1319,10 @@ pub extern "system" fn librustzcash_mmr_delete( #[no_mangle] pub extern "system" fn librustzcash_mmr_hash_node( cbranch: u32, - n_ptr: *const [u8; zcash_mmr::MAX_NODE_DATA_SIZE], + n_ptr: *const [u8; zcash_history::MAX_NODE_DATA_SIZE], h_ret: *mut [u8; 32], ) -> u32 { - let node_bytes: &[u8; zcash_mmr::MAX_NODE_DATA_SIZE] = unsafe { + let node_bytes: &[u8; zcash_history::MAX_NODE_DATA_SIZE] = unsafe { match n_ptr.as_ref() { Some(r) => r, None => return 1, diff --git a/librustzcash/src/tests/mmr.rs b/librustzcash/src/tests/mmr.rs index 4107a75..d077f07 100644 --- a/librustzcash/src/tests/mmr.rs +++ b/librustzcash/src/tests/mmr.rs @@ -1,4 +1,4 @@ -use zcash_mmr::{Entry, EntryLink, NodeData}; +use zcash_history::{Entry, EntryLink, NodeData}; use crate::{librustzcash_mmr_append, librustzcash_mmr_delete}; @@ -82,7 +82,7 @@ fn prepare_tree(nodes: &[NodeData]) -> TreeView { TreeView { peaks, extra } } -fn preload_tree_append(nodes: &[NodeData]) -> (Vec, Vec<[u8; zcash_mmr::MAX_ENTRY_SIZE]>) { +fn preload_tree_append(nodes: &[NodeData]) -> (Vec, Vec<[u8; zcash_history::MAX_ENTRY_SIZE]>) { assert!(!nodes.is_empty()); let tree_view = prepare_tree(nodes); @@ -91,7 +91,7 @@ fn preload_tree_append(nodes: &[NodeData]) -> (Vec, Vec<[u8; zcash_mmr::MAX let mut bytes = Vec::new(); for (idx, entry) in tree_view.peaks.into_iter() { - let mut buf = [0u8; zcash_mmr::MAX_ENTRY_SIZE]; + let mut buf = [0u8; zcash_history::MAX_ENTRY_SIZE]; entry .write(&mut &mut buf[..]) .expect("Cannot fail if enough buffer length"); @@ -105,7 +105,7 @@ fn preload_tree_append(nodes: &[NodeData]) -> (Vec, Vec<[u8; zcash_mmr::MAX // also returns number of peaks fn preload_tree_delete( nodes: &[NodeData], -) -> (Vec, Vec<[u8; zcash_mmr::MAX_ENTRY_SIZE]>, usize) { +) -> (Vec, Vec<[u8; zcash_history::MAX_ENTRY_SIZE]>, usize) { assert!(!nodes.is_empty()); let tree_view = prepare_tree(nodes); @@ -120,7 +120,7 @@ fn preload_tree_delete( .into_iter() .chain(tree_view.extra.into_iter()) { - let mut buf = [0u8; zcash_mmr::MAX_ENTRY_SIZE]; + let mut buf = [0u8; zcash_history::MAX_ENTRY_SIZE]; entry .write(&mut &mut buf[..]) .expect("Cannot fail if enough buffer length"); @@ -136,7 +136,7 @@ fn load_nodes(bytes: &'static [u8]) -> Vec { let mut cursor = std::io::Cursor::new(bytes); while (cursor.position() as usize) < bytes.len() { let node_data = - zcash_mmr::NodeData::read(0, &mut cursor).expect("Statically checked to be correct"); + zcash_history::NodeData::read(0, &mut cursor).expect("Statically checked to be correct"); res.push(node_data); } @@ -150,9 +150,9 @@ fn append() { let mut rt_ret = [0u8; 32]; - let mut buf_ret = Vec::<[u8; zcash_mmr::MAX_NODE_DATA_SIZE]>::with_capacity(32); + let mut buf_ret = Vec::<[u8; zcash_history::MAX_NODE_DATA_SIZE]>::with_capacity(32); - let mut new_node_data = [0u8; zcash_mmr::MAX_NODE_DATA_SIZE]; + let mut new_node_data = [0u8; zcash_history::MAX_NODE_DATA_SIZE]; let new_node = NodeData { consensus_branch_id: 0, subtree_commitment: [0u8; 32], diff --git a/zcash_history/.travis.yml b/zcash_history/.travis.yml deleted file mode 100644 index 00e7694..0000000 --- a/zcash_history/.travis.yml +++ /dev/null @@ -1,4 +0,0 @@ -language: rust -rust: -- nightly -- stable \ No newline at end of file diff --git a/zcash_history/COPYRIGHT b/zcash_history/COPYRIGHT new file mode 100644 index 0000000..bb8c4e7 --- /dev/null +++ b/zcash_history/COPYRIGHT @@ -0,0 +1,14 @@ +Copyrights in the "zcash_history" library are retained by their contributors. No +copyright assignment is required to contribute to the "zcash_history" library. + +The "zcash_history" library is licensed under either of + + * Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT) + +at your option. + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/zcash_history/Cargo.toml b/zcash_history/Cargo.toml index d527675..f397e3f 100644 --- a/zcash_history/Cargo.toml +++ b/zcash_history/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "zcash_mmr" -version = "0.1.0" +name = "zcash_history" +version = "0.0.1" authors = ["NikVolf "] edition = "2018" diff --git a/zcash_history/README.md b/zcash_history/README.md index f034137..5658ec1 100644 --- a/zcash_history/README.md +++ b/zcash_history/README.md @@ -1,4 +1,4 @@ -# zcash_mmr +# zcash_history Special implementation of Merkle mountain ranges (MMR) for Zcash! @@ -14,7 +14,7 @@ The main design goals of this MMR implementation are # License -`zcash_mmr` is distributed under the terms of both the MIT +`zcash_history` is distributed under the terms of both the MIT license and the Apache License (Version 2.0), at your choice. See LICENSE-APACHE, and LICENSE-MIT for details. @@ -22,5 +22,5 @@ See LICENSE-APACHE, and LICENSE-MIT for details. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in `zcash_mmr` by you, as defined in the Apache-2.0 license, shall be +for inclusion in `zcash_history` by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/zcash_history/examples/lib/shared.rs b/zcash_history/examples/lib/shared.rs index 4cd9262..dc1b3f9 100644 --- a/zcash_history/examples/lib/shared.rs +++ b/zcash_history/examples/lib/shared.rs @@ -1,4 +1,4 @@ -use zcash_mmr:: {NodeData, Tree, Entry, EntryLink}; +use zcash_history:: {NodeData, Tree, Entry, EntryLink}; pub struct NodeDataIterator { return_stack: Vec, diff --git a/zcash_history/examples/long.rs b/zcash_history/examples/long.rs index 951d226..0844974 100644 --- a/zcash_history/examples/long.rs +++ b/zcash_history/examples/long.rs @@ -1,4 +1,4 @@ -use zcash_mmr::{Entry, EntryLink, NodeData, Tree}; +use zcash_history::{Entry, EntryLink, NodeData, Tree}; #[path= "lib/shared.rs"] mod share; diff --git a/zcash_history/src/lib.rs b/zcash_history/src/lib.rs index 0c26dfa..d1a2ecf 100644 --- a/zcash_history/src/lib.rs +++ b/zcash_history/src/lib.rs @@ -1,4 +1,4 @@ -//! MMR library for Zcash +//! Chain history library for Zcash //! //! To be used in zebra and via FFI bindings in zcashd #![warn(missing_docs)] From 46e88a5e6961fc0ddca0720271bca2b4991292aa Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 3 Mar 2020 18:11:44 -0700 Subject: [PATCH 328/330] cargo fmt --- librustzcash/src/tests/mmr.rs | 4 +- zcash_history/examples/lib/main.rs | 4 +- zcash_history/examples/lib/shared.rs | 40 +++++--- zcash_history/examples/long.rs | 40 ++++---- zcash_history/examples/write.rs | 19 ++-- zcash_history/src/entry.rs | 44 +++++---- zcash_history/src/lib.rs | 22 +++-- zcash_history/src/node_data.rs | 33 +++---- zcash_history/src/tree.rs | 139 ++++++++++++--------------- 9 files changed, 173 insertions(+), 172 deletions(-) diff --git a/librustzcash/src/tests/mmr.rs b/librustzcash/src/tests/mmr.rs index d077f07..09bacfd 100644 --- a/librustzcash/src/tests/mmr.rs +++ b/librustzcash/src/tests/mmr.rs @@ -135,8 +135,8 @@ fn load_nodes(bytes: &'static [u8]) -> Vec { let mut res = Vec::new(); let mut cursor = std::io::Cursor::new(bytes); while (cursor.position() as usize) < bytes.len() { - let node_data = - zcash_history::NodeData::read(0, &mut cursor).expect("Statically checked to be correct"); + let node_data = zcash_history::NodeData::read(0, &mut cursor) + .expect("Statically checked to be correct"); res.push(node_data); } diff --git a/zcash_history/examples/lib/main.rs b/zcash_history/examples/lib/main.rs index 6850079..980f0d6 100644 --- a/zcash_history/examples/lib/main.rs +++ b/zcash_history/examples/lib/main.rs @@ -1,4 +1,2 @@ // dummy example -pub fn main() { - -} \ No newline at end of file +pub fn main() {} diff --git a/zcash_history/examples/lib/shared.rs b/zcash_history/examples/lib/shared.rs index dc1b3f9..e15771c 100644 --- a/zcash_history/examples/lib/shared.rs +++ b/zcash_history/examples/lib/shared.rs @@ -1,4 +1,4 @@ -use zcash_history:: {NodeData, Tree, Entry, EntryLink}; +use zcash_history::{Entry, EntryLink, NodeData, Tree}; pub struct NodeDataIterator { return_stack: Vec, @@ -22,11 +22,20 @@ impl Iterator for NodeDataIterator { } else if self.return_stack.len() > 0 { self.return_stack.pop() } else { - for n_append in - self.tree.append_leaf(leaf(self.leaf_cursor as u32)) - .expect("full tree cannot fail").into_iter().rev() + for n_append in self + .tree + .append_leaf(leaf(self.leaf_cursor as u32)) + .expect("full tree cannot fail") + .into_iter() + .rev() { - self.return_stack.push(self.tree.resolve_link(n_append).expect("just pushed").data().clone()) + self.return_stack.push( + self.tree + .resolve_link(n_append) + .expect("just pushed") + .data() + .clone(), + ) } self.leaf_cursor += 1; self.return_stack.pop() @@ -42,14 +51,13 @@ impl NodeDataIterator { let root = Entry::new( NodeData::combine(&leaf(1), &leaf(2)), EntryLink::Stored(0), - EntryLink::Stored(1) + EntryLink::Stored(1), + ); + let tree = Tree::new( + 3, + vec![(2, root)], + vec![(0, leaf(1).into()), (1, leaf(2).into())], ); - let tree = - Tree::new( - 3, - vec![(2, root)], - vec![(0, leaf(1).into()), (1, leaf(2).into())] - ); NodeDataIterator { return_stack: Vec::new(), @@ -64,10 +72,10 @@ fn leaf(height: u32) -> NodeData { NodeData { consensus_branch_id: 0, subtree_commitment: [0u8; 32], - start_time: height*10+1, - end_time: (height+1)*10, - start_target: 100 + height*10, - end_target: 100 + (height+1)*10, + start_time: height * 10 + 1, + end_time: (height + 1) * 10, + start_target: 100 + height * 10, + end_target: 100 + (height + 1) * 10, start_sapling_root: [0u8; 32], end_sapling_root: [0u8; 32], subtree_total_work: 0.into(), diff --git a/zcash_history/examples/long.rs b/zcash_history/examples/long.rs index 0844974..f718f35 100644 --- a/zcash_history/examples/long.rs +++ b/zcash_history/examples/long.rs @@ -1,10 +1,10 @@ use zcash_history::{Entry, EntryLink, NodeData, Tree}; -#[path= "lib/shared.rs"] +#[path = "lib/shared.rs"] mod share; fn draft(into: &mut Vec<(u32, Entry)>, vec: &Vec, peak_pos: usize, h: u32) { - let node_data = vec[peak_pos-1].clone(); + let node_data = vec[peak_pos - 1].clone(); let peak: Entry = match h { 0 => node_data.into(), _ => Entry::new( @@ -16,16 +16,15 @@ fn draft(into: &mut Vec<(u32, Entry)>, vec: &Vec, peak_pos: usize, h: println!("Entry #{}: {}", into.len(), peak); - into.push(((peak_pos-1) as u32, peak)); + into.push(((peak_pos - 1) as u32, peak)); } fn prepare_tree(vec: &Vec) -> Tree { - assert!(vec.len() > 0); // integer log2 of (vec.len()+1), -1 - let mut h = (32 - ((vec.len()+1) as u32).leading_zeros() - 1)-1; - let mut peak_pos = (1 << (h+1)) - 1; + let mut h = (32 - ((vec.len() + 1) as u32).leading_zeros() - 1) - 1; + let mut peak_pos = (1 << (h + 1)) - 1; let mut nodes = Vec::new(); // used later @@ -33,10 +32,9 @@ fn prepare_tree(vec: &Vec) -> Tree { let mut last_peak_h = 0; loop { - if peak_pos > vec.len() { // left child, -2^h - peak_pos = peak_pos - (1<) -> Tree { last_peak_h = h; // right sibling - peak_pos = peak_pos + (1 << (h+1)) - 1; + peak_pos = peak_pos + (1 << (h + 1)) - 1; } if h == 0 { @@ -62,7 +60,7 @@ fn prepare_tree(vec: &Vec) -> Tree { let mut peak_pos = last_peak_pos; while h > 0 { - let left_pos = peak_pos - (1<) -> Tree { } fn main() { - let number= match std::env::args().skip(1).next() { - None => { eprintln!("writer []"); std::process::exit(1); }, - Some(number) => { - number.parse::().expect("invalid number") + let number = match std::env::args().skip(1).next() { + None => { + eprintln!("writer []"); + std::process::exit(1); } + Some(number) => number.parse::().expect("invalid number"), }; - let long_vec = share::NodeDataIterator::new().take(number) + let long_vec = share::NodeDataIterator::new() + .take(number) .collect::>(); let now = std::time::Instant::now(); @@ -97,13 +97,17 @@ fn main() { let tree = prepare_tree(&long_vec); let elapsed = now.elapsed(); - println!("Tree final root: {}-{}", + println!( + "Tree final root: {}-{}", tree.root_node().expect("root").data().start_height, tree.root_node().expect("root").data().end_height, ); - println!("Prepare tree of {} length: {} ns / {} mcs / {} ms", + println!( + "Prepare tree of {} length: {} ns / {} mcs / {} ms", number, - elapsed.as_nanos(), elapsed.as_micros(), elapsed.as_millis() + elapsed.as_nanos(), + elapsed.as_micros(), + elapsed.as_millis() ); } diff --git a/zcash_history/examples/write.rs b/zcash_history/examples/write.rs index c029a85..cd9d651 100644 --- a/zcash_history/examples/write.rs +++ b/zcash_history/examples/write.rs @@ -1,4 +1,4 @@ -#[path= "lib/shared.rs"] +#[path = "lib/shared.rs"] mod share; // Test data generator @@ -11,10 +11,14 @@ fn main() { let mut args = std::env::args().skip(1); let (number, out_file) = match args.next() { - None => { eprintln!("writer []"); std::process::exit(1); }, - Some(number) => { - (number.parse::().expect("invalid number"), args.next()) + None => { + eprintln!("writer []"); + std::process::exit(1); } + Some(number) => ( + number.parse::().expect("invalid number"), + args.next(), + ), }; let iterator = share::NodeDataIterator::new().take(number); @@ -24,12 +28,11 @@ fn main() { let mut buf = Vec::new(); - for node in iterator{ + for node in iterator { node.write(&mut buf).expect("Failed to write data"); } - let mut file = std::fs::File::create(&out_file_path) - .expect("Failed to create output file"); + let mut file = std::fs::File::create(&out_file_path).expect("Failed to create output file"); file.write_all(&buf[..]) .expect("Failed to write data to file"); @@ -38,4 +41,4 @@ fn main() { println!("{:?}", n); } } -} \ No newline at end of file +} diff --git a/zcash_history/src/entry.rs b/zcash_history/src/entry.rs index ab95a38..bfd4d17 100644 --- a/zcash_history/src/entry.rs +++ b/zcash_history/src/entry.rs @@ -1,6 +1,6 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use crate::{EntryKind, NodeData, Error, EntryLink, MAX_NODE_DATA_SIZE}; +use crate::{EntryKind, EntryLink, Error, NodeData, MAX_NODE_DATA_SIZE}; /// Max serialized length of entry data. pub const MAX_ENTRY_SIZE: usize = MAX_NODE_DATA_SIZE + 9; @@ -34,22 +34,26 @@ impl Entry { /// Is this node a leaf. pub fn leaf(&self) -> bool { - if let EntryKind::Leaf = self.kind { true } else { false } + if let EntryKind::Leaf = self.kind { + true + } else { + false + } } /// Left child pub fn left(&self) -> Result { match self.kind { - EntryKind::Leaf => { Err(Error::node_expected()) } - EntryKind::Node(left, _) => Ok(left) + EntryKind::Leaf => Err(Error::node_expected()), + EntryKind::Node(left, _) => Ok(left), } } /// Right child. pub fn right(&self) -> Result { match self.kind { - EntryKind::Leaf => { Err(Error::node_expected()) } - EntryKind::Node(_, right) => Ok(right) + EntryKind::Leaf => Err(Error::node_expected()), + EntryKind::Node(_, right) => Ok(right), } } @@ -61,22 +65,15 @@ impl Entry { let left = r.read_u32::()?; let right = r.read_u32::()?; EntryKind::Node(EntryLink::Stored(left), EntryLink::Stored(right)) - }, - 1 => { - EntryKind::Leaf - }, - _ => { - return Err(std::io::Error::from(std::io::ErrorKind::InvalidData)) - }, + } + 1 => EntryKind::Leaf, + _ => return Err(std::io::Error::from(std::io::ErrorKind::InvalidData)), } }; let data = NodeData::read(consensus_branch_id, r)?; - Ok(Entry { - kind, - data, - }) + Ok(Entry { kind, data }) } /// Write to byte representation. @@ -86,11 +83,13 @@ impl Entry { w.write_u8(0)?; w.write_u32::(left)?; w.write_u32::(right)?; - }, + } EntryKind::Leaf => { w.write_u8(1)?; - }, - _ => { return Err(std::io::Error::from(std::io::ErrorKind::InvalidData)); } + } + _ => { + return Err(std::io::Error::from(std::io::ErrorKind::InvalidData)); + } } self.data.write(w)?; @@ -107,7 +106,10 @@ impl Entry { impl From for Entry { fn from(s: NodeData) -> Self { - Entry { kind: EntryKind::Leaf, data: s } + Entry { + kind: EntryKind::Leaf, + data: s, + } } } diff --git a/zcash_history/src/lib.rs b/zcash_history/src/lib.rs index d1a2ecf..9bc487b 100644 --- a/zcash_history/src/lib.rs +++ b/zcash_history/src/lib.rs @@ -3,14 +3,13 @@ //! To be used in zebra and via FFI bindings in zcashd #![warn(missing_docs)] -mod tree; -mod node_data; mod entry; +mod node_data; +mod tree; - -pub use tree::Tree; -pub use node_data::{NodeData, MAX_NODE_DATA_SIZE}; pub use entry::{Entry, MAX_ENTRY_SIZE}; +pub use node_data::{NodeData, MAX_NODE_DATA_SIZE}; +pub use tree::Tree; /// Crate-level error type #[derive(Debug)] @@ -62,16 +61,19 @@ pub enum EntryKind { impl Error { /// Entry expected to be a node (specifying for which link this is not true). - pub fn link_node_expected(link: EntryLink) -> Self { Self::ExpectedNode(Some(link)) } + pub fn link_node_expected(link: EntryLink) -> Self { + Self::ExpectedNode(Some(link)) + } /// Some entry is expected to be node - pub fn node_expected() -> Self { Self::ExpectedNode(None) } + pub fn node_expected() -> Self { + Self::ExpectedNode(None) + } - pub (crate) fn augment(self, link: EntryLink) -> Self { + pub(crate) fn augment(self, link: EntryLink) -> Self { match self { Error::ExpectedNode(_) => Error::ExpectedNode(Some(link)), - val => val + val => val, } } } - diff --git a/zcash_history/src/node_data.rs b/zcash_history/src/node_data.rs index 55b2df2..013c22d 100644 --- a/zcash_history/src/node_data.rs +++ b/zcash_history/src/node_data.rs @@ -1,10 +1,9 @@ -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt, ByteOrder}; use bigint::U256; use blake2::Params as Blake2Params; +use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt}; /// Maximum serialized size of the node metadata. -pub const MAX_NODE_DATA_SIZE: usize = - 32 + // subtree commitment +pub const MAX_NODE_DATA_SIZE: usize = 32 + // subtree commitment 4 + // start time 4 + // end time 4 + // start target @@ -14,8 +13,8 @@ pub const MAX_NODE_DATA_SIZE: usize = 32 + // subtree total work 9 + // start height (compact uint) 9 + // end height (compact uint) - 9; // shielded tx count (compact uint) - // = total of 171 + 9; // shielded tx count (compact uint) + // = total of 171 /// Node metadata. #[repr(C)] @@ -75,14 +74,17 @@ impl NodeData { let mut hash_buf = [0u8; MAX_NODE_DATA_SIZE * 2]; let size = { let mut cursor = ::std::io::Cursor::new(&mut hash_buf[..]); - left.write(&mut cursor).expect("Writing to memory buf with enough length cannot fail; qed"); - right.write(&mut cursor).expect("Writing to memory buf with enough length cannot fail; qed"); + left.write(&mut cursor) + .expect("Writing to memory buf with enough length cannot fail; qed"); + right + .write(&mut cursor) + .expect("Writing to memory buf with enough length cannot fail; qed"); cursor.position() as usize }; let hash = blake2b_personal( &personalization(left.consensus_branch_id), - &hash_buf[..size] + &hash_buf[..size], ); NodeData { @@ -103,17 +105,15 @@ impl NodeData { fn write_compact(w: &mut W, compact: u64) -> std::io::Result<()> { match compact { - 0..=0xfc => { - w.write_all(&[compact as u8])? - }, + 0..=0xfc => w.write_all(&[compact as u8])?, 0xfd..=0xffff => { w.write_all(&[0xfd])?; w.write_u16::(compact as u16)?; - }, + } 0x10000..=0xffff_ffff => { w.write_all(&[0xfe])?; w.write_u32::(compact as u32)?; - }, + } _ => { w.write_all(&[0xff])?; w.write_u64::(compact)?; @@ -160,8 +160,8 @@ impl NodeData { r.read_exact(&mut data.subtree_commitment)?; data.start_time = r.read_u32::()?; data.end_time = r.read_u32::()?; - data.start_target= r.read_u32::()?; - data.end_target= r.read_u32::()?; + data.start_target = r.read_u32::()?; + data.end_target = r.read_u32::()?; r.read_exact(&mut data.start_sapling_root)?; r.read_exact(&mut data.end_sapling_root)?; @@ -230,10 +230,9 @@ mod tests { use super::NodeData; use quickcheck::{quickcheck, TestResult}; - quickcheck! { fn serialization_round_trip(node_data: NodeData) -> TestResult { TestResult::from_bool(NodeData::from_bytes(0, &node_data.to_bytes()).unwrap() == node_data) } } -} \ No newline at end of file +} diff --git a/zcash_history/src/tree.rs b/zcash_history/src/tree.rs index c020c72..21974f4 100644 --- a/zcash_history/src/tree.rs +++ b/zcash_history/src/tree.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::{Entry, EntryLink, NodeData, Error, EntryKind}; +use crate::{Entry, EntryKind, EntryLink, Error, NodeData}; /// Represents partially loaded tree. /// @@ -28,15 +28,12 @@ pub struct Tree { impl Tree { /// Resolve link originated from this tree pub fn resolve_link(&self, link: EntryLink) -> Result { - match link { - EntryLink::Generated(index) => self.generated.get(index as usize), - EntryLink::Stored(index) => self.stored.get(&index), - } - .map(|node| IndexedNode { - node, - link, - }) - .ok_or(Error::ExpectedInMemory(link)) + match link { + EntryLink::Generated(index) => self.generated.get(index as usize), + EntryLink::Stored(index) => self.stored.get(&index), + } + .map(|node| IndexedNode { node, link }) + .ok_or(Error::ExpectedInMemory(link)) } fn push(&mut self, data: Entry) -> EntryLink { @@ -86,11 +83,7 @@ impl Tree { /// # Panics /// /// Will panic if `peaks` is empty. - pub fn new( - length: u32, - peaks: Vec<(u32, Entry)>, - extra: Vec<(u32, Entry)>, - ) -> Self { + pub fn new(length: u32, peaks: Vec<(u32, Entry)>, extra: Vec<(u32, Entry)>) -> Self { assert!(peaks.len() > 0); let mut result = Tree::invalid(); @@ -102,11 +95,14 @@ impl Tree { for (idx, node) in peaks.into_iter() { result.stored.insert(idx, node); if gen != 0 { - let next_generated = - combine_nodes(result. - resolve_link(root).expect("Inserted before, cannot fail; qed"), - result.resolve_link(EntryLink::Stored(idx)).expect("Inserted before, cannot fail; qed") - ); + let next_generated = combine_nodes( + result + .resolve_link(root) + .expect("Inserted before, cannot fail; qed"), + result + .resolve_link(EntryLink::Stored(idx)) + .expect("Inserted before, cannot fail; qed"), + ); root = result.push_generated(next_generated); } gen += 1; @@ -122,17 +118,13 @@ impl Tree { } fn get_peaks(&self, root: EntryLink, target: &mut Vec) -> Result<(), Error> { - let (left_child_link, right_child_link) = { let root = self.resolve_link(root)?; if root.node.complete() { target.push(root.link); return Ok(()); } - ( - root.left()?, - root.right()?, - ) + (root.left()?, root.right()?) }; self.get_peaks(left_child_link, target)?; @@ -161,14 +153,18 @@ impl Tree { // complete subtrees. After this, merge_stack only contains peaks of // unequal-sized subtrees. while let Some(next_peak) = peaks.pop() { - let next_merge = merge_stack.pop().expect("there should be at least one, initial or re-pushed"); + let next_merge = merge_stack + .pop() + .expect("there should be at least one, initial or re-pushed"); if let Some(stored) = { let peak = self.resolve_link(next_peak)?; let m = self.resolve_link(next_merge)?; if peak.node.leaf_count() == m.node.leaf_count() { Some(combine_nodes(peak, m)) - } else { None } + } else { + None + } } { let link = self.push(stored); merge_stack.push(link); @@ -180,16 +176,16 @@ impl Tree { } } - let mut new_root = merge_stack.pop().expect("Loop above cannot reduce the merge_stack"); + let mut new_root = merge_stack + .pop() + .expect("Loop above cannot reduce the merge_stack"); // Scan the peaks left-to-right, producing new generated nodes that // connect the subtrees while let Some(next_child) = merge_stack.pop() { - new_root = self.push_generated( - combine_nodes( - self.resolve_link(new_root)?, - self.resolve_link(next_child)?, - ) - ) + new_root = self.push_generated(combine_nodes( + self.resolve_link(new_root)?, + self.resolve_link(next_child)?, + )) } self.root = new_root; @@ -200,7 +196,9 @@ impl Tree { #[cfg(test)] fn for_children(&self, node: EntryLink, f: F) { let (left, right) = { - let link = self.resolve_link(node).expect("Failed to resolve link in test"); + let link = self + .resolve_link(node) + .expect("Failed to resolve link in test"); ( link.left().expect("Failed to find node in test"), link.right().expect("Failed to find node in test"), @@ -210,7 +208,7 @@ impl Tree { } fn pop(&mut self) { - self.stored.remove(&(self.stored_count-1)); + self.stored.remove(&(self.stored_count - 1)); self.stored_count = self.stored_count - 1; } @@ -222,10 +220,7 @@ impl Tree { let root = { let (leaves, root_left_child) = { let n = self.resolve_link(self.root)?; - ( - n.node.leaf_count(), - n.node.left()?, - ) + (n.node.leaf_count(), n.node.left()?) }; if leaves & 1 != 0 { self.pop(); @@ -247,7 +242,9 @@ impl Tree { subtree_root_link = right; truncated += 1; } else { - if root.node.complete() { truncated += 1; } + if root.node.complete() { + truncated += 1; + } break; } } @@ -255,15 +252,15 @@ impl Tree { let mut new_root = *peaks.get(0).expect("At lest 1 elements in peaks"); for next_peak in peaks.into_iter().skip(1) { - new_root = self.push_generated( - combine_nodes( + new_root = self.push_generated(combine_nodes( self.resolve_link(new_root)?, self.resolve_link(next_peak)?, - ) - ); + )); } - for _ in 0..truncated { self.pop(); } + for _ in 0..truncated { + self.pop(); + } self.root = new_root; @@ -276,7 +273,9 @@ impl Tree { } /// Link to the root node - pub fn root(&self) -> EntryLink { self.root } + pub fn root(&self) -> EntryLink { + self.root + } /// Reference to the root node. pub fn root_node(&self) -> Result { @@ -297,7 +296,6 @@ pub struct IndexedNode<'a> { } impl<'a> IndexedNode<'a> { - fn left(&self) -> Result { self.node.left().map_err(|e| e.augment(self.link)) } @@ -332,9 +330,9 @@ fn combine_nodes<'a>(left: IndexedNode<'a>, right: IndexedNode<'a>) -> Entry { #[cfg(test)] mod tests { - use super::{Entry, NodeData, Tree, EntryLink, EntryKind}; - use quickcheck::{quickcheck, TestResult}; + use super::{Entry, EntryKind, EntryLink, NodeData, Tree}; use assert_matches::assert_matches; + use quickcheck::{quickcheck, TestResult}; fn leaf(height: u32) -> NodeData { NodeData { @@ -370,7 +368,8 @@ mod tests { assert!(length >= 3); let mut tree = initial(); for i in 2..length { - tree.append_leaf(leaf(i+1).into()).expect("Failed to append"); + tree.append_leaf(leaf(i + 1).into()) + .expect("Failed to append"); } tree @@ -381,9 +380,7 @@ mod tests { let mut tree = initial(); // ** APPEND 3 ** - let appended = tree - .append_leaf(leaf(3)) - .expect("Failed to append"); + let appended = tree.append_leaf(leaf(3)).expect("Failed to append"); let new_root = tree.root_node().expect("Failed to resolve root").node; // initial tree: (2) @@ -403,9 +400,7 @@ mod tests { assert_eq!(appended.len(), 1); // ** APPEND 4 ** - let appended = tree - .append_leaf(leaf(4)) - .expect("Failed to append"); + let appended = tree.append_leaf(leaf(4)).expect("Failed to append"); let new_root = tree.root_node().expect("Failed to resolve root").node; @@ -431,9 +426,7 @@ mod tests { // ** APPEND 5 ** - let appended = tree - .append_leaf(leaf(5)) - .expect("Failed to append"); + let appended = tree.append_leaf(leaf(5)).expect("Failed to append"); let new_root = tree.root_node().expect("Failed to resolve root").node; // intermediate tree: @@ -463,9 +456,7 @@ mod tests { }); // *** APPEND #6 *** - let appended = tree - .append_leaf(leaf(6)) - .expect("Failed to append"); + let appended = tree.append_leaf(leaf(6)).expect("Failed to append"); let new_root = tree.root_node().expect("Failed to resolve root").node; // intermediate tree: @@ -498,13 +489,8 @@ mod tests { // *** APPEND #7 *** - let appended = tree - .append_leaf(leaf(7)) - .expect("Failed to append"); - let new_root = tree - .root_node() - .expect("Failed to resolve root") - .node; + let appended = tree.append_leaf(leaf(7)).expect("Failed to append"); + let new_root = tree.root_node().expect("Failed to resolve root").node; // intermediate tree: // (---8g---) @@ -533,9 +519,9 @@ mod tests { assert_matches!(tree.root(), EntryLink::Generated(_)); tree.for_children(tree.root(), |l, r| { assert_matches!(l, EntryLink::Generated(_)); - tree.for_children(l, |l, r| + tree.for_children(l, |l, r| { assert_matches!((l, r), (EntryLink::Stored(6), EntryLink::Stored(9))) - ); + }); assert_matches!(r, EntryLink::Stored(10)); }); } @@ -606,12 +592,12 @@ mod tests { assert_matches!(tree.root(), EntryLink::Generated(_)); - tree.for_children(tree.root(),|left, right| + tree.for_children(tree.root(), |left, right| { assert_matches!( (left, right), (EntryLink::Stored(14), EntryLink::Stored(15)) ) - ); + }); // two stored nodes should leave us (leaf 16 and no longer needed node 17) assert_eq!(deleted, 2); @@ -625,7 +611,7 @@ mod tests { assert_eq!(tree.len(), 3); for i in 0..2 { - tree.append_leaf(leaf(i+3)).expect("Failed to append"); + tree.append_leaf(leaf(i + 3)).expect("Failed to append"); } assert_eq!(tree.len(), 7); @@ -641,7 +627,7 @@ mod tests { assert_eq!(tree.len(), 3); for i in 0..4094 { - tree.append_leaf(leaf(i+3)).expect("Failed to append"); + tree.append_leaf(leaf(i + 3)).expect("Failed to append"); } assert_eq!(tree.len(), 8191); // 4096*2-1 (full tree) @@ -652,7 +638,6 @@ mod tests { assert_eq!(tree.len(), 4083); // 4095 - log2(4096) } - quickcheck! { fn there_and_back(number: u32) -> TestResult { if number > 1024*1024 { From cafbe61eba91a18034fdb5e8c24d2ebc0fa75969 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 4 Mar 2020 15:33:23 +1300 Subject: [PATCH 329/330] Commit to number of Sapling transactions instead of shielded transactions --- librustzcash/src/tests/mmr.rs | 4 ++-- zcash_history/examples/lib/shared.rs | 2 +- zcash_history/src/node_data.rs | 14 +++++++------- zcash_history/src/tree.rs | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/librustzcash/src/tests/mmr.rs b/librustzcash/src/tests/mmr.rs index 09bacfd..aa83aa3 100644 --- a/librustzcash/src/tests/mmr.rs +++ b/librustzcash/src/tests/mmr.rs @@ -165,7 +165,7 @@ fn append() { subtree_total_work: Default::default(), start_height: 10, end_height: 10, - shielded_tx: 13, + sapling_tx: 13, }; new_node .write(&mut &mut new_node_data[..]) @@ -200,7 +200,7 @@ fn append() { // this is combined new node (which is `new_node_1`) + the one which was there before (for block #9) assert_eq!(new_node_2.start_height, 9); assert_eq!(new_node_2.end_height, 10); - assert_eq!(new_node_2.shielded_tx, 27); + assert_eq!(new_node_2.sapling_tx, 27); } #[test] diff --git a/zcash_history/examples/lib/shared.rs b/zcash_history/examples/lib/shared.rs index e15771c..49c3f9d 100644 --- a/zcash_history/examples/lib/shared.rs +++ b/zcash_history/examples/lib/shared.rs @@ -81,6 +81,6 @@ fn leaf(height: u32) -> NodeData { subtree_total_work: 0.into(), start_height: height as u64, end_height: height as u64, - shielded_tx: 5 + height as u64, + sapling_tx: 5 + height as u64, } } diff --git a/zcash_history/src/node_data.rs b/zcash_history/src/node_data.rs index 013c22d..b4563e3 100644 --- a/zcash_history/src/node_data.rs +++ b/zcash_history/src/node_data.rs @@ -13,7 +13,7 @@ pub const MAX_NODE_DATA_SIZE: usize = 32 + // subtree commitment 32 + // subtree total work 9 + // start height (compact uint) 9 + // end height (compact uint) - 9; // shielded tx count (compact uint) + 9; // Sapling tx count (compact uint) // = total of 171 /// Node metadata. @@ -43,8 +43,8 @@ pub struct NodeData { pub start_height: u64, /// End height pub end_height: u64, - /// Number of shielded transactions. - pub shielded_tx: u64, + /// Number of Sapling transactions. + pub sapling_tx: u64, } fn blake2b_personal(personalization: &[u8], input: &[u8]) -> [u8; 32] { @@ -99,7 +99,7 @@ impl NodeData { subtree_total_work: left.subtree_total_work + right.subtree_total_work, start_height: left.start_height, end_height: right.end_height, - shielded_tx: left.shielded_tx + right.shielded_tx, + sapling_tx: left.sapling_tx + right.sapling_tx, } } @@ -149,7 +149,7 @@ impl NodeData { Self::write_compact(w, self.start_height)?; Self::write_compact(w, self.end_height)?; - Self::write_compact(w, self.shielded_tx)?; + Self::write_compact(w, self.sapling_tx)?; Ok(()) } @@ -171,7 +171,7 @@ impl NodeData { data.start_height = Self::read_compact(r)?; data.end_height = Self::read_compact(r)?; - data.shielded_tx = Self::read_compact(r)?; + data.sapling_tx = Self::read_compact(r)?; Ok(data) } @@ -219,7 +219,7 @@ impl quickcheck::Arbitrary for NodeData { node_data.subtree_total_work = U256::from_little_endian(&number[..]); node_data.start_height = gen.next_u64(); node_data.end_height = gen.next_u64(); - node_data.shielded_tx = gen.next_u64(); + node_data.sapling_tx = gen.next_u64(); node_data } diff --git a/zcash_history/src/tree.rs b/zcash_history/src/tree.rs index 21974f4..ca4c8ef 100644 --- a/zcash_history/src/tree.rs +++ b/zcash_history/src/tree.rs @@ -347,7 +347,7 @@ mod tests { subtree_total_work: 0.into(), start_height: height as u64, end_height: height as u64, - shielded_tx: 7, + sapling_tx: 7, } } From 0f0d84e9ca3da115bc789bea57e4a46074d4f59a Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Wed, 4 Mar 2020 09:28:56 -0700 Subject: [PATCH 330/330] Update manifest for zcash_history. --- zcash_history/Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zcash_history/Cargo.toml b/zcash_history/Cargo.toml index f397e3f..ee91d3a 100644 --- a/zcash_history/Cargo.toml +++ b/zcash_history/Cargo.toml @@ -3,6 +3,9 @@ name = "zcash_history" version = "0.0.1" authors = ["NikVolf "] edition = "2018" +license = "MIT/Apache-2.0" +documentation = "https://docs.rs/zcash_history/" +description = "Library for Zcash blockchain history tools" [dev-dependencies] assert_matches = "1.3.0"