From 081937162ce7cea128d7fd6adea30d35ef14b584 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Mon, 19 Aug 2019 11:29:06 +0300 Subject: [PATCH 01/84] 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 000000000..6eefe94d2 --- /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 02/84] 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 000000000..293dd90a8 --- /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 000000000..c64cb6a8b --- /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 000000000..abc0d45ad --- /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 000000000..9027f21cd --- /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 03/84] 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 000000000..818dfc86f --- /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 abc0d45ad..726e473fa 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 845babc3c213a1de8fdd79f7c5b665be9c2f3d25 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 20 Aug 2019 18:42:44 +0300 Subject: [PATCH 04/84] remove unuse dep --- Cargo.toml | 5 ----- src/lib.rs | 2 -- 2 files changed, 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c64cb6a8b..0157039bd 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 726e473fa..f164295c0 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 05/84] 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 f164295c0..cc7309892 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 9027f21cd..5495b49b4 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 06/84] commit from cbindgen --- bindings.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bindings.h b/bindings.h index 818dfc86f..fca8fa6ca 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 261ad90d337e10aacfa18b6327eabf13a8191c61 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 22 Aug 2019 14:36:57 +0300 Subject: [PATCH 07/84] 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 5495b49b4..119673eee 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 08/84] remove whitespaces --- src/tree.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index 119673eee..aeeb2cd2b 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 09/84] extra test --- src/tree.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/tree.rs b/src/tree.rs index aeeb2cd2b..1ab941d2b 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 10/84] extra asserts --- src/tree.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tree.rs b/src/tree.rs index 1ab941d2b..aade99609 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 11/84] 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 aade99609..8b4648d8d 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 bd8eea97b7d81ef85181803883d0a718e3b84680 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 22 Aug 2019 17:36:05 +0300 Subject: [PATCH 12/84] 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 cc7309892..923322bee 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 8b4648d8d..cd45287d1 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 13/84] 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 0157039bd..522af41ea 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 923322bee..1b5ad7934 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 cd45287d1..09fff6908 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 14/84] new initializer --- src/tree.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/tree.rs b/src/tree.rs index 09fff6908..136c9cf8f 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 e7d67364cca6c63d40eb25ad3abed2688d87bee6 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 23 Aug 2019 16:25:34 +0300 Subject: [PATCH 15/84] 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 522af41ea..839ef380b 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 1b5ad7934..e398029e3 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 136c9cf8f..5a387403e 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 c05446d2aee99bc47662619500ec90be388a2748 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 29 Aug 2019 19:34:27 +0300 Subject: [PATCH 16/84] add get_peaks method --- src/tree.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/tree.rs b/src/tree.rs index 5a387403e..f199461f3 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 17/84] 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 e398029e3..e55c308d9 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 f199461f3..c26696b4a 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 18/84] 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 c26696b4a..c3e0bedff 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 19/84] 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 c3e0bedff..008a19ac7 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 20/84] 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 008a19ac7..22abd366b 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 21/84] extra long truncate --- src/tree.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/tree.rs b/src/tree.rs index 22abd366b..1dd7b81ad 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 22/84] 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 fca8fa6ca..000000000 --- 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 e55c308d9..f6c555b5f 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 1dd7b81ad..2faebb60e 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 23/84] 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 839ef380b..219918bf4 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 f6c555b5f..f7afa462d 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 24/84] 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 f7afa462d..1511ea7b1 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 000000000..8d81c71b3 --- /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 2faebb60e..c5fc08f84 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 25/84] 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 c5fc08f84..9be1b5e3a 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 26/84] 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 219918bf4..355bd0914 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 1511ea7b1..dbc5b91b7 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 8d81c71b3..ba7877f9d 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 9be1b5e3a..e2b1c5bb7 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 27/84] 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 355bd0914..b2d0d811e 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 dbc5b91b7..5ba7e161d 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 ba7877f9d..10bb5b3cb 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 e2b1c5bb7..efb59e370 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 28/84] 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 10bb5b3cb..23452c2ff 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 29/84] 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 efb59e370..bc8541621 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 6b36cb5a51bc32ccda167aa062a0a0e7cfccba4e Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 6 Sep 2019 15:40:26 +0300 Subject: [PATCH 30/84] 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 000000000..b439947f1 --- /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 23452c2ff..d5cec6132 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 bc8541621..11e93e367 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 31/84] 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 b439947f1..5c669857c 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 11e93e367..cf0bf9339 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 32/84] 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 cf0bf9339..3e2d4b078 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 33/84] simplify tree preparation --- examples/producer.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/examples/producer.rs b/examples/producer.rs index 5c669857c..2ef7598ca 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: Sat, 7 Sep 2019 11:19:06 +0300 Subject: [PATCH 34/84] 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 d5cec6132..ab08d4a56 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 35/84] 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 b2d0d811e..637341706 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 5c3b673b2..cac231376 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 3e2d4b078..d5210e54b 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 36/84] 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 000000000..da0b1319f --- /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 cac231376..552dee293 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 37/84] 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 da0b1319f..3ed1c71ab 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 ab08d4a56..b95f643cd 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 38/84] 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 2ef7598ca..7d93cba8d 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 3ed1c71ab..485b36486 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 552dee293..f0eb3f466 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 b95f643cd..59591e532 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 39/84] 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 485b36486..59663fcdb 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 40/84] 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 59591e532..fd01c3a9a 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 41/84] add data reader --- src/tree.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tree.rs b/src/tree.rs index d5210e54b..c4ab9826a 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 42/84] 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 c4ab9826a..36c3e4ec5 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 43/84] 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 000000000..00e7694a3 --- /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 44/84] 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 000000000..16fe87b06 --- /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 000000000..5ee6ad60c --- /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 6eefe94d2..db76689f0 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 45/84] 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 46/84] 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 59663fcdb..982b879fd 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 fd01c3a9a..dcc8ded09 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 36c3e4ec5..b816287c4 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 47/84] 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 7d93cba8d..1bc5824e4 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 48/84] update readme --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index db76689f0..6f753461e 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 49/84] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6f753461e..26532bb9c 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 50/84] 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 1bc5824e4..108bc2517 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 982b879fd..72582c240 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 51/84] 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 108bc2517..000000000 --- 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 000000000..f51e2a7bf --- /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 52/84] 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 f51e2a7bf..c029a85ce 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 53/84] 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 000000000..bb2f2d481 --- /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 4cbc0451c1f4e713886df833466923931c802f8e Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 24 Sep 2019 10:34:27 +0200 Subject: [PATCH 54/84] 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 637341706..ff2a2f8db 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 dcc8ded09..0adc0f2f6 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 55/84] change package name --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ff2a2f8db..ce1763818 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 56/84] update readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 26532bb9c..088208c58 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 ce2416623fd95f1307fb5f1058431b3a51d45e30 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 24 Sep 2019 12:19:25 +0200 Subject: [PATCH 57/84] 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 ce1763818..d527675e7 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 f0eb3f466..da0cc5d32 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 58/84] 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 72582c240..04490b3c5 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 da0cc5d32..c0c781cc6 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 0adc0f2f6..a018daa88 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 b816287c4..8b65c5244 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 59/84] 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 8b65c5244..4482cd808 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 60/84] 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 bb2f2d481..45e66c2cf 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 43efdf992b3a135b8016122db6500d54377573de Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 24 Sep 2019 15:28:34 +0200 Subject: [PATCH 61/84] 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 45e66c2cf..85f2c13ce 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: Wed, 25 Sep 2019 09:50:59 +0200 Subject: [PATCH 62/84] 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 85f2c13ce..951d2262e 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 04490b3c5..b20855523 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 63/84] 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 7ead49ddf..4cd926212 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 b20855523..a3f14a8bb 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 84dc3bf73c71a499245a8a360ad1ac188576f7e2 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Fri, 11 Oct 2019 07:58:29 +0300 Subject: [PATCH 64/84] license notice --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 088208c58..defdafe26 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 65/84] 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 a3f14a8bb..257b9ddb2 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 66/84] 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 a018daa88..5d7535bbd 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 67/84] 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 5d7535bbd..bbaa98c07 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 68/84] 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 defdafe26..f034137ec 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 bbaa98c07..ac545e24f 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 69/84] 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 4482cd808..d1bf93666 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 70/84] 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 d1bf93666..65e0220d6 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 71/84] style fixes --- src/tree.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index 65e0220d6..1d3db06da 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 72/84] add is_empty --- src/tree.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tree.rs b/src/tree.rs index 1d3db06da..d1d1d6f13 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 73/84] 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 d1d1d6f13..fbadaba81 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 74/84] test updates --- src/tree.rs | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/tree.rs b/src/tree.rs index fbadaba81..d3b6dcd7a 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 26be46573ee7e0094f19d861fd29793adda6298e Mon Sep 17 00:00:00 2001 From: NikVolf Date: Thu, 28 Nov 2019 10:31:16 +0300 Subject: [PATCH 75/84] 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 ac545e24f..0e972f933 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 76/84] 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 257b9ddb2..ab95a38b1 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 c0c781cc6..0c26dfa94 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 0e972f933..55b2df21f 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 d3b6dcd7a..c020c72f0 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 d7f78db121ee6f720e97401ded0c9c597d1a4857 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 3 Mar 2020 17:43:16 -0700 Subject: [PATCH 77/84] 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 22db67a8e..94480b04c 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 3efef941b..57ef693f3 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 914e39258..04a9bc23c 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 45d344537..5e56e7499 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 a9d117f24..c66163db4 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 78/84] 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 eb5a316cb..4308d8220 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 001f415bb..000000000 --- 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 eea30a20a..000000000 --- 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 e9452e19b..000000000 --- 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 3d1363de3..d46fad7a2 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 1e5006dc1..16fe87b06 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 5b7be8e66..31aa79387 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 3df799fe0..47a25dc68 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 a9d37c560..000000000 --- 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 8b5f8cf37..000000000 --- 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 b7699cf76..000000000 --- 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 16fe87b06..000000000 --- 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 31aa79387..000000000 --- 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 659a81c45..000000000 --- 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 ff626e5d0..000000000 --- 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 1eed62db0..000000000 --- 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 3b8d67148..000000000 --- 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 f21fcce90..000000000 --- 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 26c899650..000000000 --- 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 a8e291477..000000000 --- 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 083e1d025..000000000 --- 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 fb8d0431b..000000000 --- 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 c0062fc0f..000000000 --- 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 b1dc1f1fc..000000000 --- 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 d6ff72b7b..000000000 --- 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 d8f6618ca..04bed0d5b 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 053a10cc8..b66332205 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 84daca2f3..8bf0392db 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 521b6ab98..028c42e53 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 13b0d0e85..9e767d8f3 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 96bcdd516..2c23c2a2e 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 d76e50b27..b083b4250 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 bb42b6caa..000000000 --- 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 c21ca8e56..000000000 --- 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 4efb544d3..000000000 --- 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 da2693bc5..000000000 --- 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 a422d5203..000000000 --- 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 b77b6b2ea..000000000 --- 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 01657d14b..000000000 --- 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 d63c4d480..000000000 --- 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 a8cdcb794..000000000 --- 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 6f8c0f589..000000000 --- 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 23fc75bc8..000000000 --- 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 4308d8220..000000000 --- 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 68971c3d8..000000000 --- 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 16fe87b06..000000000 --- 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 31aa79387..000000000 --- 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 bf386dea2..000000000 --- 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 6aa106405..000000000 --- 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 f2c6a3b05..000000000 --- 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 393c01f68..000000000 --- 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 16fe87b06..000000000 --- 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 31aa79387..000000000 --- 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 f5d3bceaa..000000000 --- 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 c5968dec4..000000000 --- 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 4b7a707b4..000000000 --- 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 93af8069c..000000000 --- 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 08f407edf..000000000 --- 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 71f1caa7a..000000000 --- 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 1ffc7f7d9..000000000 --- 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 fe0fe50ef..000000000 --- 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 0f9c75568..000000000 --- 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 54d41385a..000000000 --- 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 53a2f6cf5..000000000 --- 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 eb1745fd7..000000000 --- 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 650e16224..000000000 --- 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 7b55fc89b..000000000 --- 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 a32f05c30..000000000 --- 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 ce69bc00d..000000000 --- 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 586de8c7d..000000000 --- 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 9cdbf527c..000000000 --- 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 fff86481d..000000000 --- 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 zcmeI%S2UdK{s-_;MrRO=M946rLJz}0ZS_NQuyIr$(oo}1j?QxA=XgM6P2xnMZ?hKGGJeg;P?^$J zdV6G=9MX)b;uQ|>_xJG+v>^x$9{KUrv(r$a4aDzJ4UoJkWCGFlr7jB?{I!hwEkUzA zpg_=3D@PkNSFA*%K@`=#q~8TGDGk=BS8;f9sC?z=n*k0MwOy6sG38&Tr_jRc25o;1 zh>OVVc{APCE7j~ODFWH9E>Q^YN8}=3ZU|O|87V=<2zik!T6W|6w5{*(I{T;}Bpb=8 zJ{q~WiPL|IsmD6fi$FRAVkk}J^l-b(4IJdx+k9&55G^&UzFX6a-QGDmV(AdpxtS*Z zB7wD^#|x2>hIi$hJj7RDG%<}7S19eb5po4WGJ}+Cf~MNk*?9o9*03-u_=*D)8`-as>sO>fSLEGKOpUNqdv11G&c2@ zXH49L5Rm_9LvtCN2Psp=c!jI1c<~tQN(+6eE17J)JAk_{4B;vVa=kuP_)%iZtt4UmYJR;p6iQOLzf0eCFMg5fVzAV92c5&uYrAwBeLMa=eS$sw@s!| ziTXKb$BkjvMV7;DdIC;fV8${+xr@4gyG2nW1C0DPTMQ1c=MkdYVWBOdZ2cNkHk(QU z)QK84(O_;YOOE!Y=bJ;=jSL20N%+p|{(XKBcIIQq+%HsyRdG-0T*vB`uYpfShE<_k z^|t!+x-G=T92J85Z^Ny7?dHliaQ#%c+&t z&=Z!_FNksg+t@=HOQlnRi*qja>(gJ|ZYOXMocI^MfIrK#qk<7U6wqgfPS2x^F|;oB z`(6d@BuA20(i}6=dBxKUczV6Y6Qq8N8nR$zm2BB&!o$K&)R|ixX?BW|Wc40!exyn4 zE1MU!t9LouSFp+o{WSr6v)qjNM!p>wLiQOyKNxPP8v7318#0#Nzk5<< zaMMwm<_6Rq5*oW;kh>&!1nS4kPx z?{>hUt3<{+HT#|jOZP~L9v7DoD@=>MeDfolAhpoBru5aYJC9w3Cj+0EmE~{hX;2oC z0rmoJ#FPYy!aG^3mqZiKtoENd-Uj8OM$YNCW@EwdTQ>|}T=%;lYMEC|%$F5PFNseR ze460X5W=Wb#7a9(1WSEwFdUC3% ziWS1tPGqMQ-a>r}-Ib}M39>IA3h%SE5Sx5SG*vhp!S}|tRvS>Q81W_l% zZNNh^e>&oYa4A(slVl*1*4w@J((h;Vnvpf+xdqlV9U0&?!E1uoNRykD zUDJ-)I+Sx=^;Iz-_7T!s$h`gNhi6Yxz`{-QO-hl529-ASHsM&2L;y$Fs!zfl`)hyB zK@4F32=HyfT3(GL@q|Xv6|Pu>Idz=&_sJJOW~I;3WB>YswZ}HvWk8wJ2)P~ZDe6#V zI$@b1jx|zvd-HB`YbNDo_YnO1fnyjVvOU<1vvOjbedx5|-;^Dfr}vCp20G1c*k(G^ zY?GWFe+V8pk{zK*i)H$MyJLzD^5d$FH#ll7XzXEXHh-Q&eDV4K0(~n&UBNG5E$^8l zc)wD)EYErt)D^eC4zS2H>QH>$7|aUse>?ta(Zatl(bdmY$nhgnEC9!Zsx0RzH2(gs zTC`G&kA-6LrtaoQg=ih@xolQMa()3{UJ##QYodGIf z$CZ_Bwp#02-x^psm$qi9_VSoj>O5SQr&HDY+Z&<+SLem{y_EgF!;)X-Xz_CHVwfyb z;ilzcjl}D7H;JJk0>Dl>ql&0soK6UoIxF4KkZ-_Bj8>))j~VR}H;J}|JHh}~(S{7sJ4V+ok2_nZdZ%aU92@KzuP zUK6|~cuoFSHMy+I5dB3>{;sZenI;Mdix$_(bn}L2O&aPu*c)X#9xZ(Y-}|~NgLW)$ z)J9*-f#`{pmUa}&f1D=62d{8j_pwBO=;?Ca@Pa|!I?gv&2OY-r+=lf6?(+-Wq27bX z`E_bf?E5tsBt<2A?*|Z=U8d*x|1BcGa)ibTG*nlg+ka0Y!GS!+v_w@3N7ryl87x~` zGf{u<7yv-7exa@5EeMqn;~RomCXSMXpf-fF6HG$AM|+DdO6kSi@U-w6MAxctD!sb6 zuM5D3P!Q)SLHwmaY%u^7>sNPM`yN|&{P#FX=BU92O|aO{9UEOQ#t-w|NzlB9wthVK zdKlYVB2osfg8D$)WNcHnL&&)Jj1VPr1V+KMOhRNIltHn{YX=9xS5Twg-2)E*-w*GQ zMyIs#xG6o1p912T4&Jz8$Ab1c*TfuOha9Ggk*j9U#T5>s35W!Aw2yy|k8WuBDy~$% z?{w@xIgl-({&;J0O0SRqBmn(^3p{88qzNqQdbF`Fd4!()Y^mt#!J}hi0{<3#Pb2S| z_M&{u^o*h9)qEsxQheHn(eSdAJ(G*g+$Dh|!&>37q_ z7OjB?md(oK>AzNWyS__W!lwy7P4H>*|C1&rRA%PUyvmvjAz-ldqz}8CMx4<*HHNOz zM;62!7{mI@|LI?*%f&bNe@by8#yIUwSu;9>g;ZCrfwf;}ICR!&dVix7If;?f8m_`? zg4YDE$^WV*mvtH7U+kuTS692Nn~tEVJyJWN3{M5**u7nycG$b3GK(aGJ~LQIk0H1O z9WJ__>vLN&hJYd7$PS$R_RDW{NR{F2)Wg(_k|DRUWH>cQN25)4v(lh|iYT`2_AL1Q zH8`wMv&n&$>)ZoJAoavXrOQ36E;bP;xM?xeP37_&hh2>wVuZR+I8#wEQAGG(+yl;8 zi;!K_cp^xv$Bz|XD_2C{A3H0tPPiqNz0(+*f+fLGXVP{%w__C;p|K03RELG|@aOY) zGN~nH>Y1SRq!;J>xf25dTqL%J6-AU9gK`AZC zA%i&4QYQ@#4Q?d}O}FU!dCiMj&t1QLk<&hGp`vkhunt!~^j76b5&B$&+-3G2=#Rx? ztNLXBcvr5;+di^GVchjZ@jlgW+^^R?>VZ}rgw3HR+;#in*EQH%ft@e5zY32wB2DuD 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 12fe0ca33..000000000 --- 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 fb0bfa922..000000000 --- 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 dfdd36ff7..000000000 --- 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 25e65f90e..000000000 --- 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 e91455c81..000000000 --- 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 eb10e6505..000000000 --- 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 51a000a29..000000000 --- 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 18d0fcb0a..000000000 --- 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 421a8f704..000000000 --- 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 27d306cf8..000000000 --- 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 0590a5c88..000000000 --- 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 26dafabcd..000000000 --- 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 dfae28c05..000000000 --- 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 e67e66089..000000000 --- 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 f5a6d8f4b..019b19a6b 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 fd0d416d5..08135e3c1 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 b24fcaaac..17ae39073 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 363439a67..4fd391b34 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 36c6e285e..92128ca0f 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 5e5763142..76f3ffe07 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 7bc03c623..e6e88ddba 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 b5b75a330..636fcfef7 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 adabcce1f..89e587373 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 7b1944dd5..b6ae50edb 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 55396a74b..8f3d8d9e0 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 09dd44135..67badd802 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 bf6c03fe4..000000000 --- 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 1e5006dc1..000000000 --- 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 5b7be8e66..000000000 --- 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 b284820ce..000000000 --- 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 5f4dd056b..000000000 --- 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 f1429438e..000000000 --- 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 21dbd46ca..000000000 --- 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 787c01de7..000000000 --- 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 e5dcde070..000000000 --- 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 db3a4dfa1..000000000 --- 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 68a4a4531..000000000 --- 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 1e5006dc1..000000000 --- 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 5b7be8e66..000000000 --- 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 92d9c7736..000000000 --- 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 bdebdd634..000000000 --- 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 2cfb2e94c..000000000 --- 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 f43dae73f..000000000 --- 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 e9a5f2f7d..000000000 --- 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 a7b6c91ea..000000000 --- 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 1e5006dc1..000000000 --- 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 5b7be8e66..000000000 --- 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 14c1a389e..000000000 --- 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 31e1bb209..000000000 --- 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 693699042..000000000 --- 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 e58e86893..000000000 --- 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 031d6364c..000000000 --- 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 16fe87b06..000000000 --- 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 31aa79387..000000000 --- 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 898d56cdf..000000000 --- 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 5b322db94..000000000 --- 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 79/84] 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 eb5a316cb..a9d37c560 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 001f415bb..000000000 --- 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 eea30a20a..000000000 --- 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 c477d522f..000000000 --- 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 3d1363de3..3acc8c424 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 1e5006dc1..16fe87b06 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 5b7be8e66..31aa79387 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 3df799fe0..d64dd9c1e 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 a9d37c560..000000000 --- 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 6812a7fe3..000000000 --- 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 16fe87b06..000000000 --- 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 31aa79387..000000000 --- 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 659a81c45..000000000 --- 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 c0062fc0f..000000000 --- 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 bb42b6caa..000000000 --- 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 c21ca8e56..000000000 --- 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 4efb544d3..000000000 --- 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 da2693bc5..000000000 --- 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 a422d5203..000000000 --- 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 b77b6b2ea..000000000 --- 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 01657d14b..000000000 --- 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 d63c4d480..000000000 --- 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 a8cdcb794..000000000 --- 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 6f8c0f589..000000000 --- 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 23fc75bc8..000000000 --- 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 4308d8220..000000000 --- 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 c3876a4d7..000000000 --- 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 68971c3d8..000000000 --- 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 16fe87b06..000000000 --- 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 31aa79387..000000000 --- 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 bf386dea2..000000000 --- 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 d8f6618ca..000000000 --- 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 053a10cc8..000000000 --- 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 84daca2f3..000000000 --- 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 521b6ab98..000000000 --- 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 13b0d0e85..000000000 --- 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 96bcdd516..000000000 --- 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 d76e50b27..000000000 --- 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 d3811a142..000000000 --- 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 f5a6d8f4b..000000000 --- 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 fd0d416d5..000000000 --- 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 b24fcaaac..000000000 --- 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 363439a67..000000000 --- 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 36c6e285e..000000000 --- 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 5e5763142..000000000 --- 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 7bc03c623..000000000 --- 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 e69de29bb..000000000 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 adabcce1f..000000000 --- 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 7b1944dd5..000000000 --- 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 55396a74b..000000000 --- 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 d6ad6a12f..000000000 --- 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 09dd44135..000000000 --- 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 6aa106405..000000000 --- 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 f2c6a3b05..000000000 --- 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 393c01f68..000000000 --- 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 16fe87b06..000000000 --- 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 31aa79387..000000000 --- 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 f5d3bceaa..000000000 --- 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 c5968dec4..000000000 --- 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 4b7a707b4..000000000 --- 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 93af8069c..000000000 --- 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 71f1caa7a..000000000 --- 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 54d41385a..000000000 --- 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 eb1745fd7..000000000 --- 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 650e16224..000000000 --- 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 a32f05c30..000000000 --- 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 ce69bc00d..000000000 --- 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 586de8c7d..000000000 --- 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 9cdbf527c..000000000 --- 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 fff86481d..000000000 --- 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 dfdd36ff7..000000000 --- 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 25e65f90e..000000000 --- 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 e91455c81..000000000 --- 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 eb10e6505..000000000 --- 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 51a000a29..000000000 --- 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 18d0fcb0a..000000000 --- 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 421a8f704..000000000 --- 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 27d306cf8..000000000 --- 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 0590a5c88..000000000 --- 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 26dafabcd..000000000 --- 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 dfae28c05..000000000 --- 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 e67e66089..000000000 --- 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 4606ce5a2..ddba4f430 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 fe0fe50ef..b0ce73472 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 000000000..9b6693b2b --- /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 08f407edf..d3c882d11 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 1ffc7f7d9..b83844de4 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 0f9c75568..d05282270 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 000000000..c0dc50e1f --- /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 53a2f6cf5..8be54480e 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 7b55fc89b..0c8efea70 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 12fe0ca33..47392f147 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 fb0bfa922..a10be6c03 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 f3f3d3afd..767edddb9 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 620f32edb..1ff152d60 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 c674622cf..7fe282f6c 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 d5f37a971..46920786a 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 0e05c36ab..d8be98e40 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 71c747837..5bc05810b 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 f6d716399..a3b577b99 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 000000000..ba69b5f33 --- /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 d24572bf6..b7729a868 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 1d554a57d..e9a4c7c70 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 bf6c03fe4..000000000 --- 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 1e5006dc1..000000000 --- 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 5b7be8e66..000000000 --- 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 b284820ce..000000000 --- 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 5f4dd056b..000000000 --- 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 f1429438e..000000000 --- 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 21dbd46ca..000000000 --- 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 787c01de7..000000000 --- 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 e5dcde070..000000000 --- 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 db3a4dfa1..000000000 --- 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 68a4a4531..000000000 --- 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 1e5006dc1..000000000 --- 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 5b7be8e66..000000000 --- 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 92d9c7736..000000000 --- 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 bdebdd634..000000000 --- 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 2cfb2e94c..000000000 --- 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 f43dae73f..000000000 --- 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 e9a5f2f7d..000000000 --- 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 a7b6c91ea..000000000 --- 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 1e5006dc1..000000000 --- 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 5b7be8e66..000000000 --- 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 14c1a389e..000000000 --- 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 31e1bb209..000000000 --- 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 693699042..000000000 --- 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 e58e86893..000000000 --- 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 031d6364c..000000000 --- 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 16fe87b06..000000000 --- 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 31aa79387..000000000 --- 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 898d56cdf..000000000 --- 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 5b322db94..000000000 --- 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 80/84] 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 46920786a..b25e713fe 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 7cf4d7945..81120e617 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 81/84] 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 9a09a9d54..223244707 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 82/84] 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 223244707..63a8edd09 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 69639cf07..a147250e2 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 64999f23f..8c7d4ff8b 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 83/84] 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 63a8edd09..37967cf2a 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 8c7d4ff8b..304dbdfec 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 084d5b0ff..c60b1d55a 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 4107a75a5..d077f0738 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 00e7694a3..000000000 --- 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 000000000..bb8c4e7dd --- /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 d527675e7..f397e3fde 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 f034137ec..5658ec1bc 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 4cd926212..dc1b3f932 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 951d2262e..084497457 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 0c26dfa94..d1a2ecfdc 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 84/84] 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 d077f0738..09bacfd1c 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 685007957..980f0d6e0 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 dc1b3f932..e15771cf1 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 084497457..f718f35a2 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 c029a85ce..cd9d6511c 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 ab95a38b1..bfd4d178d 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 d1a2ecfdc..9bc487b5f 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 55b2df21f..013c22d39 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 c020c72f0..21974f421 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 {