mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-07-30 20:11:23 +00:00
Update master
This commit is contained in:
@@ -1,9 +1,15 @@
|
||||
[package]
|
||||
name = "zcash_primitives"
|
||||
version = "0.0.0"
|
||||
description = "Rust implementations of the Zcash primitives"
|
||||
version = "0.2.0"
|
||||
authors = [
|
||||
"Jack Grigg <jack@z.cash>",
|
||||
]
|
||||
homepage = "https://github.com/zcash/librustzcash"
|
||||
repository = "https://github.com/zcash/librustzcash"
|
||||
readme = "README.md"
|
||||
license = "MIT OR Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
aes = "0.3"
|
||||
@@ -11,21 +17,30 @@ blake2b_simd = "0.5"
|
||||
blake2s_simd = "0.5"
|
||||
byteorder = "1"
|
||||
crypto_api_chachapoly = "0.2.1"
|
||||
ff = { path = "../ff" }
|
||||
ff = { version = "0.6", path = "../ff" }
|
||||
fpe = "0.2"
|
||||
hex = "0.3"
|
||||
lazy_static = "1"
|
||||
pairing = { path = "../pairing" }
|
||||
log = "0.4"
|
||||
pairing = { version = "0.16", path = "../pairing" }
|
||||
rand = "0.7"
|
||||
rand_core = "0.5"
|
||||
rand_os = "0.2"
|
||||
rand_core = "0.5.1"
|
||||
ripemd160 = { version = "0.8", optional = true }
|
||||
secp256k1 = { version = "=0.15.0", optional = true }
|
||||
sha2 = "0.8"
|
||||
subtle = "2.2.1"
|
||||
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.1"
|
||||
criterion = "0.3"
|
||||
hex-literal = "0.2"
|
||||
rand_xorshift = "0.2"
|
||||
|
||||
[features]
|
||||
transparent-inputs = ["ripemd160", "secp256k1"]
|
||||
|
||||
[[bench]]
|
||||
name = "pedersen_hash"
|
||||
harness = false
|
||||
|
||||
[badges]
|
||||
maintenance = { status = "actively-developed" }
|
||||
|
@@ -6,7 +6,8 @@ This library contains Rust implementations of the Zcash primitives.
|
||||
|
||||
Licensed under either of
|
||||
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
||||
http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
@@ -1,19 +1,10 @@
|
||||
#![feature(test)]
|
||||
|
||||
extern crate pairing;
|
||||
extern crate rand_core;
|
||||
extern crate rand_os;
|
||||
extern crate test;
|
||||
extern crate zcash_primitives;
|
||||
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use pairing::bls12_381::Bls12;
|
||||
use rand_core::RngCore;
|
||||
use rand_os::OsRng;
|
||||
use rand_core::{OsRng, RngCore};
|
||||
use zcash_primitives::jubjub::JubjubBls12;
|
||||
use zcash_primitives::pedersen_hash::{pedersen_hash, Personalization};
|
||||
|
||||
#[bench]
|
||||
fn bench_pedersen_hash(b: &mut test::Bencher) {
|
||||
fn bench_pedersen_hash(c: &mut Criterion) {
|
||||
let params = JubjubBls12::new();
|
||||
let rng = &mut OsRng;
|
||||
let bits = (0..510)
|
||||
@@ -21,5 +12,10 @@ fn bench_pedersen_hash(b: &mut test::Bencher) {
|
||||
.collect::<Vec<_>>();
|
||||
let personalization = Personalization::MerkleTree(31);
|
||||
|
||||
b.iter(|| pedersen_hash::<Bls12, _>(personalization, bits.clone(), ¶ms));
|
||||
c.bench_function("Pedersen hash", |b| {
|
||||
b.iter(|| pedersen_hash::<Bls12, _>(personalization, bits.clone(), ¶ms))
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_pedersen_hash);
|
||||
criterion_main!(benches);
|
||||
|
@@ -1,3 +1,5 @@
|
||||
//! Structs and methods for handling Zcash block headers.
|
||||
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use hex;
|
||||
use sha2::{Digest, Sha256};
|
||||
@@ -5,14 +7,16 @@ use std::fmt;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::ops::Deref;
|
||||
|
||||
use serialize::Vector;
|
||||
use crate::serialize::Vector;
|
||||
|
||||
pub mod equihash;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct BlockHash(pub [u8; 32]);
|
||||
|
||||
impl fmt::Display for BlockHash {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut data = self.0.clone();
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut data = self.0;
|
||||
data.reverse();
|
||||
formatter.write_str(&hex::encode(data))
|
||||
}
|
||||
|
469
zcash_primitives/src/block/equihash.rs
Normal file
469
zcash_primitives/src/block/equihash.rs
Normal file
@@ -0,0 +1,469 @@
|
||||
//! Verification functions for the [Equihash] proof-of-work algorithm.
|
||||
//!
|
||||
//! [Equihash]: https://zips.z.cash/protocol/protocol.pdf#equihash
|
||||
|
||||
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams, State as Blake2bState};
|
||||
use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use log::error;
|
||||
use std::io::Cursor;
|
||||
use std::mem::size_of;
|
||||
|
||||
struct Params {
|
||||
n: u32,
|
||||
k: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Node {
|
||||
hash: Vec<u8>,
|
||||
indices: Vec<u32>,
|
||||
}
|
||||
|
||||
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: &Blake2bState, i: u32) -> Self {
|
||||
let hash = generate_hash(state, i / p.indices_per_hash_output());
|
||||
let start = ((i % p.indices_per_hash_output()) * p.n / 8) as usize;
|
||||
let end = start + (p.n as usize) / 8;
|
||||
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, 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, 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) -> Blake2bState {
|
||||
let mut personalization: Vec<u8> = Vec::from("ZcashPoW");
|
||||
personalization.write_u32::<LittleEndian>(n).unwrap();
|
||||
personalization.write_u32::<LittleEndian>(k).unwrap();
|
||||
|
||||
Blake2bParams::new()
|
||||
.hash_length(digest_len as usize)
|
||||
.personal(&personalization)
|
||||
.to_state()
|
||||
}
|
||||
|
||||
fn generate_hash(base_state: &Blake2bState, i: u32) -> Blake2bHash {
|
||||
let mut lei = [0u8; 4];
|
||||
(&mut lei[..]).write_u32::<LittleEndian>(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<u8> {
|
||||
assert!(bit_len >= 8);
|
||||
assert!(8 * size_of::<u32>() >= 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<u8> = 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) | u32::from(*b);
|
||||
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<u32> {
|
||||
assert!(((c_bit_len + 1) + 7) / 8 <= size_of::<u32>());
|
||||
let len_indices = 8 * size_of::<u32>() * minimal.len() / (c_bit_len + 1);
|
||||
let byte_pad = size_of::<u32>() - ((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::<BigEndian>() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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, 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);
|
||||
rows[0].is_zero(hash_len)
|
||||
}
|
||||
|
||||
fn tree_validator(p: &Params, state: &Blake2bState, indices: &[u32]) -> Option<Node> {
|
||||
if indices.len() > 1 {
|
||||
let end = indices.len();
|
||||
let mid = end / 2;
|
||||
match (
|
||||
tree_validator(p, state, &indices[0..mid]),
|
||||
tree_validator(p, state, &indices[mid..end]),
|
||||
) {
|
||||
(Some(a), Some(b)) => {
|
||||
if validate_subtrees(p, &a, &b) {
|
||||
Some(Node::from_children(a, b, p.collision_byte_length()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
} 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, 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, 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));
|
||||
}
|
||||
}
|
237
zcash_primitives/src/consensus.rs
Normal file
237
zcash_primitives/src/consensus.rs
Normal file
@@ -0,0 +1,237 @@
|
||||
//! Consensus parameters.
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
|
||||
/// Zcash consensus parameters.
|
||||
pub trait Parameters {
|
||||
fn activation_height(nu: NetworkUpgrade) -> Option<u32>;
|
||||
|
||||
fn is_nu_active(nu: NetworkUpgrade, height: u32) -> bool {
|
||||
match Self::activation_height(nu) {
|
||||
Some(h) if h <= height => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Marker struct for the production network.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct MainNetwork;
|
||||
|
||||
impl Parameters for MainNetwork {
|
||||
fn activation_height(nu: NetworkUpgrade) -> Option<u32> {
|
||||
match nu {
|
||||
NetworkUpgrade::Overwinter => Some(347_500),
|
||||
NetworkUpgrade::Sapling => Some(419_200),
|
||||
NetworkUpgrade::Blossom => Some(653_600),
|
||||
NetworkUpgrade::Heartwood => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Marker struct for the test network.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct TestNetwork;
|
||||
|
||||
impl Parameters for TestNetwork {
|
||||
fn activation_height(nu: NetworkUpgrade) -> Option<u32> {
|
||||
match nu {
|
||||
NetworkUpgrade::Overwinter => Some(207_500),
|
||||
NetworkUpgrade::Sapling => Some(280_000),
|
||||
NetworkUpgrade::Blossom => Some(584_000),
|
||||
NetworkUpgrade::Heartwood => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An event that occurs at a specified height on the Zcash chain, at which point the
|
||||
/// consensus rules enforced by the network are altered.
|
||||
///
|
||||
/// See [ZIP 200](https://zips.z.cash/zip-0200) for more details.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum NetworkUpgrade {
|
||||
/// The [Overwinter] network upgrade.
|
||||
///
|
||||
/// [Overwinter]: https://z.cash/upgrade/overwinter/
|
||||
Overwinter,
|
||||
/// The [Sapling] network upgrade.
|
||||
///
|
||||
/// [Sapling]: https://z.cash/upgrade/sapling/
|
||||
Sapling,
|
||||
/// The [Blossom] network upgrade.
|
||||
///
|
||||
/// [Blossom]: https://z.cash/upgrade/blossom/
|
||||
Blossom,
|
||||
/// The [Heartwood] network upgrade.
|
||||
///
|
||||
/// [Heartwood]: https://z.cash/upgrade/heartwood/
|
||||
Heartwood,
|
||||
}
|
||||
|
||||
impl fmt::Display for NetworkUpgrade {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
NetworkUpgrade::Overwinter => write!(f, "Overwinter"),
|
||||
NetworkUpgrade::Sapling => write!(f, "Sapling"),
|
||||
NetworkUpgrade::Blossom => write!(f, "Blossom"),
|
||||
NetworkUpgrade::Heartwood => write!(f, "Heartwood"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkUpgrade {
|
||||
fn branch_id(self) -> BranchId {
|
||||
match self {
|
||||
NetworkUpgrade::Overwinter => BranchId::Overwinter,
|
||||
NetworkUpgrade::Sapling => BranchId::Sapling,
|
||||
NetworkUpgrade::Blossom => BranchId::Blossom,
|
||||
NetworkUpgrade::Heartwood => BranchId::Heartwood,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The network upgrades on the Zcash chain in order of activation.
|
||||
///
|
||||
/// This order corresponds to the activation heights, but because Rust enums are
|
||||
/// full-fledged algebraic data types, we need to define it manually.
|
||||
const UPGRADES_IN_ORDER: &[NetworkUpgrade] = &[
|
||||
NetworkUpgrade::Overwinter,
|
||||
NetworkUpgrade::Sapling,
|
||||
NetworkUpgrade::Blossom,
|
||||
NetworkUpgrade::Heartwood,
|
||||
];
|
||||
|
||||
/// A globally-unique identifier for a set of consensus rules within the Zcash chain.
|
||||
///
|
||||
/// Each branch ID in this enum corresponds to one of the epochs between a pair of Zcash
|
||||
/// network upgrades. For example, `BranchId::Overwinter` corresponds to the blocks
|
||||
/// starting at Overwinter activation, and ending the block before Sapling activation.
|
||||
///
|
||||
/// The main use of the branch ID is in signature generation: transactions commit to a
|
||||
/// specific branch ID by including it as part of [`signature_hash`]. This ensures
|
||||
/// two-way replay protection for transactions across network upgrades.
|
||||
///
|
||||
/// See [ZIP 200](https://zips.z.cash/zip-0200) for more details.
|
||||
///
|
||||
/// [`signature_hash`]: crate::transaction::signature_hash
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum BranchId {
|
||||
/// The consensus rules at the launch of Zcash.
|
||||
Sprout,
|
||||
/// The consensus rules deployed by [`NetworkUpgrade::Overwinter`].
|
||||
Overwinter,
|
||||
/// The consensus rules deployed by [`NetworkUpgrade::Sapling`].
|
||||
Sapling,
|
||||
/// The consensus rules deployed by [`NetworkUpgrade::Blossom`].
|
||||
Blossom,
|
||||
/// The consensus rules deployed by [`NetworkUpgrade::Heartwood`].
|
||||
Heartwood,
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for BranchId {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0 => Ok(BranchId::Sprout),
|
||||
0x5ba8_1b19 => Ok(BranchId::Overwinter),
|
||||
0x76b8_09bb => Ok(BranchId::Sapling),
|
||||
0x2bb4_0e60 => Ok(BranchId::Blossom),
|
||||
0xf5b9_230b => Ok(BranchId::Heartwood),
|
||||
_ => Err("Unknown consensus branch ID"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BranchId> for u32 {
|
||||
fn from(consensus_branch_id: BranchId) -> u32 {
|
||||
match consensus_branch_id {
|
||||
BranchId::Sprout => 0,
|
||||
BranchId::Overwinter => 0x5ba8_1b19,
|
||||
BranchId::Sapling => 0x76b8_09bb,
|
||||
BranchId::Blossom => 0x2bb4_0e60,
|
||||
BranchId::Heartwood => 0xf5b9_230b,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BranchId {
|
||||
/// Returns the branch ID corresponding to the consensus rule set that is active at
|
||||
/// the given height.
|
||||
///
|
||||
/// This is the branch ID that should be used when creating transactions.
|
||||
pub fn for_height<C: Parameters>(height: u32) -> Self {
|
||||
for nu in UPGRADES_IN_ORDER.iter().rev() {
|
||||
if C::is_nu_active(*nu, height) {
|
||||
return nu.branch_id();
|
||||
}
|
||||
}
|
||||
|
||||
// Sprout rules apply before any network upgrade
|
||||
BranchId::Sprout
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use super::{BranchId, MainNetwork, NetworkUpgrade, Parameters, UPGRADES_IN_ORDER};
|
||||
|
||||
#[test]
|
||||
fn nu_ordering() {
|
||||
for i in 1..UPGRADES_IN_ORDER.len() {
|
||||
let nu_a = UPGRADES_IN_ORDER[i - 1];
|
||||
let nu_b = UPGRADES_IN_ORDER[i];
|
||||
match (
|
||||
MainNetwork::activation_height(nu_a),
|
||||
MainNetwork::activation_height(nu_b),
|
||||
) {
|
||||
(Some(a), Some(b)) if a < b => (),
|
||||
(Some(_), None) => (),
|
||||
(None, None) => (),
|
||||
_ => panic!(
|
||||
"{} should not be before {} in UPGRADES_IN_ORDER",
|
||||
nu_a, nu_b
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nu_is_active() {
|
||||
assert!(!MainNetwork::is_nu_active(NetworkUpgrade::Overwinter, 0));
|
||||
assert!(!MainNetwork::is_nu_active(
|
||||
NetworkUpgrade::Overwinter,
|
||||
347_499
|
||||
));
|
||||
assert!(MainNetwork::is_nu_active(
|
||||
NetworkUpgrade::Overwinter,
|
||||
347_500
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branch_id_from_u32() {
|
||||
assert_eq!(BranchId::try_from(0), Ok(BranchId::Sprout));
|
||||
assert!(BranchId::try_from(1).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branch_id_for_height() {
|
||||
assert_eq!(BranchId::for_height::<MainNetwork>(0), BranchId::Sprout,);
|
||||
assert_eq!(
|
||||
BranchId::for_height::<MainNetwork>(419_199),
|
||||
BranchId::Overwinter,
|
||||
);
|
||||
assert_eq!(
|
||||
BranchId::for_height::<MainNetwork>(419_200),
|
||||
BranchId::Sapling,
|
||||
);
|
||||
assert_eq!(
|
||||
BranchId::for_height::<MainNetwork>(5_000_000),
|
||||
BranchId::Blossom,
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,32 +1,34 @@
|
||||
//! Various constants used by the Zcash primitives.
|
||||
|
||||
/// First 64 bytes of the BLAKE2s input during group hash.
|
||||
/// This is chosen to be some random string that we couldn't have anticipated when we designed
|
||||
/// the algorithm, for rigidity purposes.
|
||||
/// We deliberately use an ASCII hex string of 32 bytes here.
|
||||
pub const GH_FIRST_BLOCK: &'static [u8; 64] =
|
||||
pub const GH_FIRST_BLOCK: &[u8; 64] =
|
||||
b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0";
|
||||
|
||||
// BLAKE2s invocation personalizations
|
||||
/// BLAKE2s Personalization for CRH^ivk = BLAKE2s(ak | nk)
|
||||
pub const CRH_IVK_PERSONALIZATION: &'static [u8; 8] = b"Zcashivk";
|
||||
pub const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk";
|
||||
|
||||
/// BLAKE2s Personalization for PRF^nf = BLAKE2s(nk | rho)
|
||||
pub const PRF_NF_PERSONALIZATION: &'static [u8; 8] = b"Zcash_nf";
|
||||
pub const PRF_NF_PERSONALIZATION: &[u8; 8] = b"Zcash_nf";
|
||||
|
||||
// Group hash personalizations
|
||||
/// BLAKE2s Personalization for Pedersen hash generators.
|
||||
pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8] = b"Zcash_PH";
|
||||
pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &[u8; 8] = b"Zcash_PH";
|
||||
|
||||
/// BLAKE2s Personalization for the group hash for key diversification
|
||||
pub const KEY_DIVERSIFICATION_PERSONALIZATION: &'static [u8; 8] = b"Zcash_gd";
|
||||
pub const KEY_DIVERSIFICATION_PERSONALIZATION: &[u8; 8] = b"Zcash_gd";
|
||||
|
||||
/// BLAKE2s Personalization for the spending key base point
|
||||
pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_G_";
|
||||
pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_G_";
|
||||
|
||||
/// BLAKE2s Personalization for the proof generation key base point
|
||||
pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_H_";
|
||||
pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_H_";
|
||||
|
||||
/// BLAKE2s Personalization for the value commitment generator for the value
|
||||
pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_cv";
|
||||
pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_cv";
|
||||
|
||||
/// BLAKE2s Personalization for the nullifier position generator (for computing rho)
|
||||
pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_J_";
|
||||
pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_J_";
|
||||
|
@@ -1,9 +1,13 @@
|
||||
use jubjub::{edwards, JubjubEngine, PrimeOrder};
|
||||
//! Implementation of [group hashing into Jubjub][grouphash].
|
||||
//!
|
||||
//! [grouphash]: https://zips.z.cash/protocol/protocol.pdf#concretegrouphashjubjub
|
||||
|
||||
use crate::jubjub::{edwards, JubjubEngine, PrimeOrder};
|
||||
|
||||
use ff::PrimeField;
|
||||
|
||||
use crate::constants;
|
||||
use blake2s_simd::Params;
|
||||
use constants;
|
||||
|
||||
/// Produces a random point in the Jubjub curve.
|
||||
/// The point is guaranteed to be prime order
|
||||
|
@@ -1,4 +1,6 @@
|
||||
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
|
||||
use ff::{BitIterator, Field, PrimeField};
|
||||
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
|
||||
use subtle::CtOption;
|
||||
|
||||
use super::{montgomery, JubjubEngine, JubjubParams, PrimeOrder, Unknown};
|
||||
|
||||
@@ -81,33 +83,36 @@ impl<E: JubjubEngine, Subgroup> PartialEq for Point<E, Subgroup> {
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> Point<E, Unknown> {
|
||||
pub fn read<R: Read>(reader: R, params: &E::Params) -> io::Result<Self> {
|
||||
pub fn read<R: Read>(mut reader: R, params: &E::Params) -> io::Result<Self> {
|
||||
let mut y_repr = <E::Fr as PrimeField>::Repr::default();
|
||||
y_repr.read_le(reader)?;
|
||||
reader.read_exact(y_repr.as_mut())?;
|
||||
|
||||
let x_sign = (y_repr.as_ref()[3] >> 63) == 1;
|
||||
y_repr.as_mut()[3] &= 0x7fffffffffffffff;
|
||||
let x_sign = (y_repr.as_ref()[31] >> 7) == 1;
|
||||
y_repr.as_mut()[31] &= 0x7f;
|
||||
|
||||
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(
|
||||
Some(y) => {
|
||||
let p = Self::get_for_y(y, x_sign, params);
|
||||
if bool::from(p.is_some()) {
|
||||
Ok(p.unwrap())
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve"))
|
||||
}
|
||||
}
|
||||
None => 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<Self> {
|
||||
pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> CtOption<Self> {
|
||||
// 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();
|
||||
let mut tmp1 = y.square();
|
||||
|
||||
// tmp2 = (y^2 * d) + 1
|
||||
let mut tmp2 = tmp1;
|
||||
@@ -117,33 +122,27 @@ impl<E: JubjubEngine> Point<E, Unknown> {
|
||||
// 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);
|
||||
tmp2.invert().and_then(|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,
|
||||
tmp1.sqrt().map(|mut x| {
|
||||
if x.is_odd() != sign {
|
||||
x = x.neg();
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
|
||||
let mut t = x;
|
||||
t.mul_assign(&y);
|
||||
|
||||
Point {
|
||||
x,
|
||||
y,
|
||||
t,
|
||||
z: E::Fr::one(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// This guarantees the point is in the prime order subgroup
|
||||
@@ -159,31 +158,31 @@ impl<E: JubjubEngine> Point<E, Unknown> {
|
||||
let y = E::Fr::random(rng);
|
||||
let sign = rng.next_u32() % 2 != 0;
|
||||
|
||||
if let Some(p) = Self::get_for_y(y, sign, params) {
|
||||
return p;
|
||||
let p = Self::get_for_y(y, sign, params);
|
||||
if bool::from(p.is_some()) {
|
||||
return p.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
pub fn write<W: Write>(&self, writer: W) -> io::Result<()> {
|
||||
let (x, y) = self.into_xy();
|
||||
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||
let (x, y) = self.to_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;
|
||||
let mut y_repr = y.to_repr();
|
||||
if x.is_odd() {
|
||||
y_repr.as_mut()[31] |= 0x80;
|
||||
}
|
||||
|
||||
y_repr.write_le(writer)
|
||||
writer.write_all(y_repr.as_ref())
|
||||
}
|
||||
|
||||
/// Convert from a Montgomery point
|
||||
pub fn from_montgomery(m: &montgomery::Point<E, Subgroup>, params: &E::Params) -> Self {
|
||||
match m.into_xy() {
|
||||
match m.to_xy() {
|
||||
None => {
|
||||
// Map the point at infinity to the neutral element.
|
||||
Point::zero()
|
||||
@@ -212,12 +211,9 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
// 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,
|
||||
y: E::Fr::one().neg(),
|
||||
t: E::Fr::zero(),
|
||||
z: E::Fr::one(),
|
||||
_marker: PhantomData,
|
||||
@@ -277,8 +273,8 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
Point {
|
||||
x: u,
|
||||
y: v,
|
||||
t: t,
|
||||
z: z,
|
||||
t,
|
||||
z,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -306,8 +302,9 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_xy(&self) -> (E::Fr, E::Fr) {
|
||||
let zinv = self.z.inverse().unwrap();
|
||||
/// Convert to affine coordinates
|
||||
pub fn to_xy(&self) -> (E::Fr, E::Fr) {
|
||||
let zinv = self.z.invert().unwrap();
|
||||
|
||||
let mut x = self.x;
|
||||
x.mul_assign(&zinv);
|
||||
@@ -322,8 +319,8 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
pub fn negate(&self) -> Self {
|
||||
let mut p = self.clone();
|
||||
|
||||
p.x.negate();
|
||||
p.t.negate();
|
||||
p.x = p.x.neg();
|
||||
p.t = p.t.neg();
|
||||
|
||||
p
|
||||
}
|
||||
@@ -336,27 +333,22 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
// http://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd
|
||||
|
||||
// A = X1^2
|
||||
let mut a = self.x;
|
||||
a.square();
|
||||
let a = self.x.square();
|
||||
|
||||
// B = Y1^2
|
||||
let mut b = self.y;
|
||||
b.square();
|
||||
let b = self.y.square();
|
||||
|
||||
// C = 2*Z1^2
|
||||
let mut c = self.z;
|
||||
c.square();
|
||||
c.double();
|
||||
let c = self.z.square().double();
|
||||
|
||||
// D = a*A
|
||||
// = -A
|
||||
let mut d = a;
|
||||
d.negate();
|
||||
let d = a.neg();
|
||||
|
||||
// E = (X1+Y1)^2 - A - B
|
||||
let mut e = self.x;
|
||||
e.add_assign(&self.y);
|
||||
e.square();
|
||||
e = e.square();
|
||||
e.add_assign(&d); // -A = D
|
||||
e.sub_assign(&b);
|
||||
|
||||
@@ -412,7 +404,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
b.mul_assign(&other.y);
|
||||
|
||||
// C = d * t1 * t2
|
||||
let mut c = params.edwards_d().clone();
|
||||
let mut c = *params.edwards_d();
|
||||
c.mul_assign(&self.t);
|
||||
c.mul_assign(&other.t);
|
||||
|
||||
@@ -475,7 +467,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
|
||||
let mut res = Self::zero();
|
||||
|
||||
for b in BitIterator::new(scalar.into()) {
|
||||
for b in BitIterator::<u8, _>::new(scalar.into()) {
|
||||
res = res.double(params);
|
||||
|
||||
if b {
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,6 @@
|
||||
//! The [Jubjub] curve for efficient elliptic curve operations in circuits built
|
||||
//! over [BLS12-381].
|
||||
//!
|
||||
//! Jubjub is a twisted Edwards curve defined over the BLS12-381 scalar
|
||||
//! field, Fr. It takes the form `-x^2 + y^2 = 1 + dx^2y^2` with
|
||||
//! `d = -(10240/10241)`. It is birationally equivalent to a Montgomery
|
||||
@@ -16,13 +19,16 @@
|
||||
//! It is a complete twisted Edwards curve, so the equivalence with
|
||||
//! the Montgomery curve forms a group isomorphism, allowing points
|
||||
//! to be freely converted between the two forms.
|
||||
//!
|
||||
//! [Jubjub]: https://zips.z.cash/protocol/protocol.pdf#jubjub
|
||||
//! [BLS12-381]: pairing::bls12_381
|
||||
|
||||
use ff::{Field, PrimeField, SqrtField};
|
||||
use ff::{Field, PrimeField};
|
||||
use pairing::Engine;
|
||||
|
||||
use group_hash::group_hash;
|
||||
use crate::group_hash::group_hash;
|
||||
|
||||
use constants;
|
||||
use crate::constants;
|
||||
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
|
||||
@@ -89,7 +95,7 @@ pub trait ToUniform {
|
||||
/// and some pre-computed parameters.
|
||||
pub trait JubjubEngine: Engine {
|
||||
/// The scalar field of the Jubjub curve
|
||||
type Fs: PrimeField + SqrtField + ToUniform;
|
||||
type Fs: PrimeField + ToUniform;
|
||||
/// The parameters of Jubjub and the Sapling protocol
|
||||
type Params: JubjubParams<Self>;
|
||||
}
|
||||
@@ -122,7 +128,7 @@ pub trait JubjubParams<E: JubjubEngine>: Sized {
|
||||
fn generator(&self, base: FixedGenerators) -> &edwards::Point<E, PrimeOrder>;
|
||||
/// Returns a window table [0, 1, ..., 8] for different magnitudes of some
|
||||
/// fixed generator.
|
||||
fn circuit_generators(&self, FixedGenerators) -> &[Vec<(E::Fr, E::Fr)>];
|
||||
fn circuit_generators(&self, _: FixedGenerators) -> &[Vec<(E::Fr, E::Fr)>];
|
||||
/// Returns the window size for exponentiation of Pedersen hash generators
|
||||
/// outside the circuit
|
||||
fn pedersen_hash_exp_window_size() -> u32;
|
||||
@@ -189,8 +195,7 @@ impl JubjubParams<Bls12> for JubjubBls12 {
|
||||
impl JubjubBls12 {
|
||||
pub fn new() -> Self {
|
||||
let montgomery_a = Fr::from_str("40962").unwrap();
|
||||
let mut montgomery_2a = montgomery_a;
|
||||
montgomery_2a.double();
|
||||
let montgomery_2a = montgomery_a.double();
|
||||
|
||||
let mut tmp_params = JubjubBls12 {
|
||||
// d = -(10240/10241)
|
||||
@@ -199,9 +204,9 @@ impl JubjubBls12 {
|
||||
)
|
||||
.unwrap(),
|
||||
// A = 40962
|
||||
montgomery_a: montgomery_a,
|
||||
montgomery_a,
|
||||
// 2A = 2.A
|
||||
montgomery_2a: montgomery_2a,
|
||||
montgomery_2a,
|
||||
// scaling factor = sqrt(4 / (a - d))
|
||||
scale: Fr::from_str(
|
||||
"17814886934372412843466061268024708274627479829237077604635722030778476050649",
|
||||
@@ -216,33 +221,11 @@ impl JubjubBls12 {
|
||||
fixed_base_circuit_generators: vec![],
|
||||
};
|
||||
|
||||
fn find_group_hash<E: JubjubEngine>(
|
||||
m: &[u8],
|
||||
personalization: &[u8; 8],
|
||||
params: &E::Params,
|
||||
) -> edwards::Point<E, PrimeOrder> {
|
||||
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 {
|
||||
for m in 0..6 {
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
|
||||
let mut segment_number = [0u8; 4];
|
||||
@@ -250,26 +233,17 @@ impl JubjubBls12 {
|
||||
.write_u32::<LittleEndian>(m)
|
||||
.unwrap();
|
||||
|
||||
pedersen_hash_generators.push(find_group_hash(
|
||||
pedersen_hash_generators.push(JubjubBls12::find_group_hash(
|
||||
&segment_number,
|
||||
constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
));
|
||||
}
|
||||
|
||||
// Check for duplicates, far worse than spec inconsistencies!
|
||||
for (i, p1) in pedersen_hash_generators.iter().enumerate() {
|
||||
if p1 == &edwards::Point::zero() {
|
||||
panic!("Neutral element!");
|
||||
}
|
||||
|
||||
for p2 in pedersen_hash_generators.iter().skip(i + 1) {
|
||||
if p1 == p2 {
|
||||
panic!("Duplicate generator!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JubjubBls12::check_consistency_of_pedersen_hash_generators(
|
||||
&tmp_params,
|
||||
&pedersen_hash_generators,
|
||||
);
|
||||
tmp_params.pedersen_hash_generators = pedersen_hash_generators;
|
||||
}
|
||||
|
||||
@@ -314,43 +288,47 @@ impl JubjubBls12 {
|
||||
let mut fixed_base_generators =
|
||||
vec![edwards::Point::zero(); FixedGenerators::Max as usize];
|
||||
|
||||
fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] = find_group_hash(
|
||||
&[],
|
||||
constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] =
|
||||
JubjubBls12::find_group_hash(
|
||||
&[],
|
||||
constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
|
||||
fixed_base_generators[FixedGenerators::NoteCommitmentRandomness as usize] =
|
||||
find_group_hash(
|
||||
JubjubBls12::find_group_hash(
|
||||
b"r",
|
||||
constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
|
||||
fixed_base_generators[FixedGenerators::NullifierPosition as usize] = find_group_hash(
|
||||
&[],
|
||||
constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
fixed_base_generators[FixedGenerators::NullifierPosition as usize] =
|
||||
JubjubBls12::find_group_hash(
|
||||
&[],
|
||||
constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
|
||||
fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] = find_group_hash(
|
||||
b"v",
|
||||
constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] =
|
||||
JubjubBls12::find_group_hash(
|
||||
b"v",
|
||||
constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
|
||||
fixed_base_generators[FixedGenerators::ValueCommitmentRandomness as usize] =
|
||||
find_group_hash(
|
||||
JubjubBls12::find_group_hash(
|
||||
b"r",
|
||||
constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
|
||||
fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] = find_group_hash(
|
||||
&[],
|
||||
constants::SPENDING_KEY_GENERATOR_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] =
|
||||
JubjubBls12::find_group_hash(
|
||||
&[],
|
||||
constants::SPENDING_KEY_GENERATOR_PERSONALIZATION,
|
||||
&tmp_params,
|
||||
);
|
||||
|
||||
// Check for duplicates, far worse than spec inconsistencies!
|
||||
for (i, p1) in fixed_base_generators.iter().enumerate() {
|
||||
@@ -374,7 +352,7 @@ impl JubjubBls12 {
|
||||
let mut pedersen_circuit_generators = vec![];
|
||||
|
||||
// Process each segment
|
||||
for mut gen in tmp_params.pedersen_hash_generators.iter().cloned() {
|
||||
for gen in tmp_params.pedersen_hash_generators.iter().cloned() {
|
||||
let mut gen = montgomery::Point::from_edwards(&gen, &tmp_params);
|
||||
let mut windows = vec![];
|
||||
for _ in 0..tmp_params.pedersen_hash_chunks_per_generator() {
|
||||
@@ -384,7 +362,7 @@ impl JubjubBls12 {
|
||||
|
||||
// coeffs = g, g*2, g*3, g*4
|
||||
for _ in 0..4 {
|
||||
coeffs.push(g.into_xy().expect("cannot produce O"));
|
||||
coeffs.push(g.to_xy().expect("cannot produce O"));
|
||||
g = g.add(&gen, &tmp_params);
|
||||
}
|
||||
windows.push(coeffs);
|
||||
@@ -411,7 +389,7 @@ impl JubjubBls12 {
|
||||
let mut coeffs = vec![(Fr::zero(), Fr::one())];
|
||||
let mut g = gen.clone();
|
||||
for _ in 0..7 {
|
||||
coeffs.push(g.into_xy());
|
||||
coeffs.push(g.to_xy());
|
||||
g = g.add(&gen, &tmp_params);
|
||||
}
|
||||
windows.push(coeffs);
|
||||
@@ -427,10 +405,71 @@ impl JubjubBls12 {
|
||||
|
||||
tmp_params
|
||||
}
|
||||
|
||||
fn find_group_hash<E: JubjubEngine>(
|
||||
m: &[u8],
|
||||
personalization: &[u8; 8],
|
||||
params: &E::Params,
|
||||
) -> edwards::Point<E, PrimeOrder> {
|
||||
let mut tag = m.to_vec();
|
||||
let i = tag.len();
|
||||
tag.push(0u8);
|
||||
|
||||
loop {
|
||||
let gh = group_hash(&tag, personalization, params);
|
||||
|
||||
// We don't want to overflow and start reusing generators
|
||||
assert!(tag[i] != u8::max_value());
|
||||
tag[i] += 1;
|
||||
|
||||
if let Some(gh) = gh {
|
||||
break gh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check for simple relations between the generators, that make finding collisions easy;
|
||||
/// far worse than spec inconsistencies!
|
||||
fn check_consistency_of_pedersen_hash_generators<E: JubjubEngine>(
|
||||
tmp_params: &E::Params,
|
||||
pedersen_hash_generators: &[edwards::Point<E, PrimeOrder>],
|
||||
) {
|
||||
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!");
|
||||
}
|
||||
if p1 == &p2.negate() {
|
||||
panic!("Inverse generator!");
|
||||
}
|
||||
}
|
||||
|
||||
// check for a generator being the sum of any other two
|
||||
for (j, p2) in pedersen_hash_generators.iter().enumerate() {
|
||||
if j == i {
|
||||
continue;
|
||||
}
|
||||
for (k, p3) in pedersen_hash_generators.iter().enumerate() {
|
||||
if k == j || k == i {
|
||||
continue;
|
||||
}
|
||||
let sum = &p2.add(&p3, &tmp_params);
|
||||
if sum == p1 {
|
||||
panic!("Linear relation between generators!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_jubjub_bls12() {
|
||||
use hex_literal::hex;
|
||||
|
||||
let params = JubjubBls12::new();
|
||||
|
||||
tests::test_suite::<Bls12>(¶ms);
|
||||
@@ -464,3 +503,35 @@ fn test_jubjub_bls12() {
|
||||
|
||||
assert!(p == q);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Linear relation between generators!")]
|
||||
fn test_jubjub_bls12_pedersen_hash_generators_consistency_check_linear_relation() {
|
||||
let params = JubjubBls12::new();
|
||||
|
||||
let mut pedersen_hash_generators: Vec<edwards::Point<Bls12, PrimeOrder>> = vec![];
|
||||
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
|
||||
for m in 0..5 {
|
||||
let mut segment_number = [0u8; 4];
|
||||
(&mut segment_number[0..4])
|
||||
.write_u32::<LittleEndian>(m)
|
||||
.unwrap();
|
||||
|
||||
let p = JubjubBls12::find_group_hash(
|
||||
&segment_number,
|
||||
constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION,
|
||||
¶ms,
|
||||
);
|
||||
pedersen_hash_generators.push(p);
|
||||
}
|
||||
|
||||
let p1 = pedersen_hash_generators[0].clone();
|
||||
let p2 = pedersen_hash_generators[1].clone();
|
||||
|
||||
//test for linear relation
|
||||
pedersen_hash_generators.push(p1.add(&p2, ¶ms));
|
||||
|
||||
JubjubBls12::check_consistency_of_pedersen_hash_generators(¶ms, &pedersen_hash_generators);
|
||||
}
|
||||
|
@@ -1,4 +1,6 @@
|
||||
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
|
||||
use ff::{BitIterator, Field, PrimeField};
|
||||
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
|
||||
use subtle::CtOption;
|
||||
|
||||
use super::{edwards, JubjubEngine, JubjubParams, PrimeOrder, Unknown};
|
||||
|
||||
@@ -46,11 +48,10 @@ impl<E: JubjubEngine, Subgroup> PartialEq for Point<E, Subgroup> {
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> Point<E, Unknown> {
|
||||
pub fn get_for_x(x: E::Fr, sign: bool, params: &E::Params) -> Option<Self> {
|
||||
pub fn get_for_x(x: E::Fr, sign: bool, params: &E::Params) -> CtOption<Self> {
|
||||
// Given an x on the curve, y = sqrt(x^3 + A*x^2 + x)
|
||||
|
||||
let mut x2 = x;
|
||||
x2.square();
|
||||
let mut x2 = x.square();
|
||||
|
||||
let mut rhs = x2;
|
||||
rhs.mul_assign(params.montgomery_a());
|
||||
@@ -58,21 +59,18 @@ impl<E: JubjubEngine> Point<E, Unknown> {
|
||||
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,
|
||||
});
|
||||
rhs.sqrt().map(|mut y| {
|
||||
if y.is_odd() != sign {
|
||||
y = y.neg();
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
|
||||
Point {
|
||||
x,
|
||||
y,
|
||||
infinity: false,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// This guarantees the point is in the prime order subgroup
|
||||
@@ -88,9 +86,9 @@ impl<E: JubjubEngine> Point<E, Unknown> {
|
||||
let x = E::Fr::random(rng);
|
||||
let sign = rng.next_u32() % 2 != 0;
|
||||
|
||||
match Self::get_for_x(x, sign, params) {
|
||||
Some(p) => return p,
|
||||
None => {}
|
||||
let p = Self::get_for_x(x, sign, params);
|
||||
if p.is_some().into() {
|
||||
return p.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,7 +97,7 @@ impl<E: JubjubEngine> Point<E, Unknown> {
|
||||
impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
/// Convert from an Edwards point
|
||||
pub fn from_edwards(e: &edwards::Point<E, Subgroup>, params: &E::Params) -> Self {
|
||||
let (x, y) = e.into_xy();
|
||||
let (x, y) = e.to_xy();
|
||||
|
||||
if y == E::Fr::one() {
|
||||
// The only solution for y = 1 is x = 0. (0, 1) is
|
||||
@@ -140,11 +138,11 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
{
|
||||
let mut tmp = E::Fr::one();
|
||||
tmp.sub_assign(&y);
|
||||
u.mul_assign(&tmp.inverse().unwrap())
|
||||
u.mul_assign(&tmp.invert().unwrap())
|
||||
}
|
||||
|
||||
let mut v = u;
|
||||
v.mul_assign(&x.inverse().unwrap());
|
||||
v.mul_assign(&x.invert().unwrap());
|
||||
|
||||
// Scale it into the correct curve constants
|
||||
v.mul_assign(params.scale());
|
||||
@@ -178,7 +176,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_xy(&self) -> Option<(E::Fr, E::Fr)> {
|
||||
pub fn to_xy(&self) -> Option<(E::Fr, E::Fr)> {
|
||||
if self.infinity {
|
||||
None
|
||||
} else {
|
||||
@@ -190,7 +188,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
pub fn negate(&self) -> Self {
|
||||
let mut p = self.clone();
|
||||
|
||||
p.y.negate();
|
||||
p.y = p.y.neg();
|
||||
|
||||
p
|
||||
}
|
||||
@@ -214,26 +212,24 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
|
||||
let mut delta = E::Fr::one();
|
||||
{
|
||||
let mut tmp = params.montgomery_a().clone();
|
||||
let mut tmp = *params.montgomery_a();
|
||||
tmp.mul_assign(&self.x);
|
||||
tmp.double();
|
||||
tmp = tmp.double();
|
||||
delta.add_assign(&tmp);
|
||||
}
|
||||
{
|
||||
let mut tmp = self.x;
|
||||
tmp.square();
|
||||
let mut tmp = self.x.square();
|
||||
delta.add_assign(&tmp);
|
||||
tmp.double();
|
||||
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 tmp = self.y.double();
|
||||
// y is nonzero so this must be nonzero
|
||||
delta.mul_assign(&tmp.invert().unwrap());
|
||||
}
|
||||
|
||||
let mut x3 = delta;
|
||||
x3.square();
|
||||
let mut x3 = delta.square();
|
||||
x3.sub_assign(params.montgomery_a());
|
||||
x3.sub_assign(&self.x);
|
||||
x3.sub_assign(&self.x);
|
||||
@@ -242,7 +238,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
y3.sub_assign(&self.x);
|
||||
y3.mul_assign(&delta);
|
||||
y3.add_assign(&self.y);
|
||||
y3.negate();
|
||||
y3 = y3.neg();
|
||||
|
||||
Point {
|
||||
x: x3,
|
||||
@@ -276,14 +272,11 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
{
|
||||
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"),
|
||||
);
|
||||
// self.x != other.x, so this must be nonzero
|
||||
delta.mul_assign(&tmp.invert().unwrap());
|
||||
}
|
||||
|
||||
let mut x3 = delta;
|
||||
x3.square();
|
||||
let mut x3 = delta.square();
|
||||
x3.sub_assign(params.montgomery_a());
|
||||
x3.sub_assign(&self.x);
|
||||
x3.sub_assign(&other.x);
|
||||
@@ -292,7 +285,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
y3.sub_assign(&self.x);
|
||||
y3.mul_assign(&delta);
|
||||
y3.add_assign(&self.y);
|
||||
y3.negate();
|
||||
y3 = y3.neg();
|
||||
|
||||
Point {
|
||||
x: x3,
|
||||
@@ -311,7 +304,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||
|
||||
let mut res = Self::zero();
|
||||
|
||||
for b in BitIterator::new(scalar.into()) {
|
||||
for b in BitIterator::<u8, _>::new(scalar.into()) {
|
||||
res = res.double(params);
|
||||
|
||||
if b {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
use super::{edwards, montgomery, JubjubEngine, JubjubParams, PrimeOrder};
|
||||
|
||||
use ff::{Field, LegendreSymbol, PrimeField, PrimeFieldRepr, SqrtField};
|
||||
use ff::{Endianness, Field, PrimeField};
|
||||
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
|
||||
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
@@ -19,11 +20,9 @@ pub fn test_suite<E: JubjubEngine>(params: &E::Params) {
|
||||
}
|
||||
|
||||
fn is_on_mont_curve<E: JubjubEngine, P: JubjubParams<E>>(x: E::Fr, y: E::Fr, params: &P) -> bool {
|
||||
let mut lhs = y;
|
||||
lhs.square();
|
||||
let lhs = y.square();
|
||||
|
||||
let mut x2 = x;
|
||||
x2.square();
|
||||
let x2 = x.square();
|
||||
|
||||
let mut x3 = x2;
|
||||
x3.mul_assign(&x);
|
||||
@@ -41,11 +40,9 @@ fn is_on_twisted_edwards_curve<E: JubjubEngine, P: JubjubParams<E>>(
|
||||
y: E::Fr,
|
||||
params: &P,
|
||||
) -> bool {
|
||||
let mut x2 = x;
|
||||
x2.square();
|
||||
let x2 = x.square();
|
||||
|
||||
let mut y2 = y;
|
||||
y2.square();
|
||||
let y2 = y.square();
|
||||
|
||||
// -x^2 + y^2
|
||||
let mut lhs = y2;
|
||||
@@ -119,13 +116,13 @@ fn test_mul_associativity<E: JubjubEngine>(params: &E::Params) {
|
||||
assert!(res2 == res3);
|
||||
assert!(res3 == res4);
|
||||
|
||||
let (x, y) = res1.into_xy();
|
||||
let (x, y) = res1.to_xy();
|
||||
assert!(is_on_twisted_edwards_curve(x, y, params));
|
||||
|
||||
let (x, y) = res2.into_xy();
|
||||
let (x, y) = res2.to_xy();
|
||||
assert!(is_on_twisted_edwards_curve(x, y, params));
|
||||
|
||||
let (x, y) = res3.into_xy();
|
||||
let (x, y) = res3.to_xy();
|
||||
assert!(is_on_twisted_edwards_curve(x, y, params));
|
||||
}
|
||||
}
|
||||
@@ -237,8 +234,10 @@ fn test_get_for<E: JubjubEngine>(params: &E::Params) {
|
||||
let y = E::Fr::random(rng);
|
||||
let sign = rng.next_u32() % 2 == 1;
|
||||
|
||||
if let Some(mut p) = edwards::Point::<E, _>::get_for_y(y, sign, params) {
|
||||
assert!(p.into_xy().0.into_repr().is_odd() == sign);
|
||||
let p = edwards::Point::<E, _>::get_for_y(y, sign, params);
|
||||
if bool::from(p.is_some()) {
|
||||
let mut p = p.unwrap();
|
||||
assert!(p.to_xy().0.is_odd() == sign);
|
||||
p = p.negate();
|
||||
assert!(edwards::Point::<E, _>::get_for_y(y, !sign, params).unwrap() == p);
|
||||
}
|
||||
@@ -274,12 +273,12 @@ fn test_rand<E: JubjubEngine>(params: &E::Params) {
|
||||
let e = edwards::Point::<E, _>::rand(rng, params);
|
||||
|
||||
{
|
||||
let (x, y) = p.into_xy().unwrap();
|
||||
let (x, y) = p.to_xy().unwrap();
|
||||
assert!(is_on_mont_curve(x, y, params));
|
||||
}
|
||||
|
||||
{
|
||||
let (x, y) = e.into_xy();
|
||||
let (x, y) = e.to_xy();
|
||||
assert!(is_on_twisted_edwards_curve(x, y, params));
|
||||
}
|
||||
}
|
||||
@@ -309,23 +308,19 @@ fn test_back_and_forth<E: JubjubEngine>(params: &E::Params) {
|
||||
|
||||
fn test_jubjub_params<E: JubjubEngine>(params: &E::Params) {
|
||||
// a = -1
|
||||
let mut a = E::Fr::one();
|
||||
a.negate();
|
||||
let a = E::Fr::one().neg();
|
||||
|
||||
{
|
||||
// Check that 2A is consistent with A
|
||||
let mut tmp = *params.montgomery_a();
|
||||
tmp.double();
|
||||
|
||||
assert_eq!(&tmp, params.montgomery_2a());
|
||||
assert_eq!(¶ms.montgomery_a().double(), 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);
|
||||
assert!(bool::from(params.edwards_d().sqrt().is_none()));
|
||||
assert!(bool::from(a.sqrt().is_some()));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -335,38 +330,37 @@ fn test_jubjub_params<E: JubjubEngine>(params: &E::Params) {
|
||||
let mut tmp = *params.edwards_d();
|
||||
|
||||
// 1 / d is nonsquare
|
||||
assert!(tmp.inverse().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue);
|
||||
assert!(bool::from(tmp.invert().unwrap().sqrt().is_none()));
|
||||
|
||||
// tmp = -d
|
||||
tmp.negate();
|
||||
tmp = tmp.neg();
|
||||
|
||||
// -d is nonsquare
|
||||
assert!(tmp.legendre() == LegendreSymbol::QuadraticNonResidue);
|
||||
assert!(bool::from(tmp.sqrt().is_none()));
|
||||
|
||||
// 1 / -d is nonsquare
|
||||
assert!(tmp.inverse().unwrap().legendre() == LegendreSymbol::QuadraticNonResidue);
|
||||
assert!(bool::from(tmp.invert().unwrap().sqrt().is_none()));
|
||||
}
|
||||
|
||||
{
|
||||
// Check that A^2 - 4 is nonsquare:
|
||||
let mut tmp = params.montgomery_a().clone();
|
||||
tmp.square();
|
||||
let mut tmp = params.montgomery_a().square();
|
||||
tmp.sub_assign(&E::Fr::from_str("4").unwrap());
|
||||
assert!(tmp.legendre() == LegendreSymbol::QuadraticNonResidue);
|
||||
assert!(bool::from(tmp.sqrt().is_none()));
|
||||
}
|
||||
|
||||
{
|
||||
// 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);
|
||||
assert!(bool::from(tmp.sqrt().is_none()));
|
||||
}
|
||||
|
||||
{
|
||||
// Check the validity of the scaling factor
|
||||
let mut tmp = a;
|
||||
tmp.sub_assign(¶ms.edwards_d());
|
||||
tmp = tmp.inverse().unwrap();
|
||||
tmp = tmp.invert().unwrap();
|
||||
tmp.mul_assign(&E::Fr::from_str("4").unwrap());
|
||||
tmp = tmp.sqrt().unwrap();
|
||||
assert_eq!(&tmp, params.scale());
|
||||
@@ -376,32 +370,55 @@ fn test_jubjub_params<E: JubjubEngine>(params: &E::Params) {
|
||||
// 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 cur = E::Fs::one();
|
||||
|
||||
let mut max = E::Fs::char();
|
||||
{
|
||||
max.sub_noborrow(&E::Fs::one().into_repr());
|
||||
max.div2();
|
||||
}
|
||||
let max = {
|
||||
// Grab char - 1 in little endian.
|
||||
let mut tmp = (-E::Fs::one()).to_repr();
|
||||
<E::Fs as PrimeField>::ReprEndianness::toggle_little_endian(&mut tmp);
|
||||
|
||||
let mut pacc = E::Fs::zero().into_repr();
|
||||
let mut nacc = E::Fs::char();
|
||||
// Shift right by 1 bit.
|
||||
let mut borrow = 0;
|
||||
for b in tmp.as_mut().iter_mut().rev() {
|
||||
let new_borrow = *b & 1;
|
||||
*b = (borrow << 7) | (*b >> 1);
|
||||
borrow = new_borrow;
|
||||
}
|
||||
|
||||
// Turns out we want this in little endian!
|
||||
tmp
|
||||
};
|
||||
|
||||
let mut pacc = E::Fs::zero();
|
||||
let mut nacc = E::Fs::zero();
|
||||
|
||||
for _ in 0..params.pedersen_hash_chunks_per_generator() {
|
||||
// tmp = cur * 4
|
||||
let mut tmp = cur;
|
||||
tmp.mul2();
|
||||
tmp.mul2();
|
||||
let tmp = cur.double().double();
|
||||
|
||||
pacc.add_nocarry(&tmp);
|
||||
nacc.sub_noborrow(&tmp);
|
||||
pacc += &tmp;
|
||||
nacc -= &tmp; // The first subtraction wraps intentionally.
|
||||
|
||||
assert!(pacc < max);
|
||||
assert!(pacc < nacc);
|
||||
let mut pacc_repr = pacc.to_repr();
|
||||
let mut nacc_repr = nacc.to_repr();
|
||||
<E::Fs as PrimeField>::ReprEndianness::toggle_little_endian(&mut pacc_repr);
|
||||
<E::Fs as PrimeField>::ReprEndianness::toggle_little_endian(&mut nacc_repr);
|
||||
|
||||
fn less_than(val: &[u8], bound: &[u8]) -> bool {
|
||||
for (a, b) in val.iter().rev().zip(bound.iter().rev()) {
|
||||
if a < b {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
assert!(less_than(pacc_repr.as_ref(), max.as_ref()));
|
||||
assert!(less_than(pacc_repr.as_ref(), nacc_repr.as_ref()));
|
||||
|
||||
// cur = cur * 16
|
||||
for _ in 0..4 {
|
||||
cur.mul2();
|
||||
cur = cur.double();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,20 +1,22 @@
|
||||
//! Sapling key components.
|
||||
//!
|
||||
//! Implements section 4.2.2 of the Zcash Protocol Specification.
|
||||
//! Implements [section 4.2.2] of the Zcash Protocol Specification.
|
||||
//!
|
||||
//! [section 4.2.2]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
|
||||
|
||||
use crate::{
|
||||
jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, ToUniform, Unknown},
|
||||
primitives::{ProofGenerationKey, ViewingKey},
|
||||
};
|
||||
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
|
||||
use ff::{PrimeField, PrimeFieldRepr};
|
||||
use ff::PrimeField;
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
pub const PRF_EXPAND_PERSONALIZATION: &'static [u8; 16] = b"Zcash_ExpandSeed";
|
||||
pub const PRF_EXPAND_PERSONALIZATION: &[u8; 16] = b"Zcash_ExpandSeed";
|
||||
|
||||
/// PRF^expand(sk, t) := BLAKE2b-512("Zcash_ExpandSeed", sk || t)
|
||||
pub fn prf_expand(sk: &[u8], t: &[u8]) -> Blake2bHash {
|
||||
prf_expand_vec(sk, &vec![t])
|
||||
prf_expand_vec(sk, &[t])
|
||||
}
|
||||
|
||||
pub fn prf_expand_vec(sk: &[u8], ts: &[&[u8]]) -> Blake2bHash {
|
||||
@@ -69,14 +71,14 @@ impl<E: JubjubEngine> ExpandedSpendingKey<E> {
|
||||
|
||||
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||
let mut ask_repr = <E::Fs as PrimeField>::Repr::default();
|
||||
ask_repr.read_le(&mut reader)?;
|
||||
reader.read_exact(ask_repr.as_mut())?;
|
||||
let ask = E::Fs::from_repr(ask_repr)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "ask not in field"))?;
|
||||
|
||||
let mut nsk_repr = <E::Fs as PrimeField>::Repr::default();
|
||||
nsk_repr.read_le(&mut reader)?;
|
||||
reader.read_exact(nsk_repr.as_mut())?;
|
||||
let nsk = E::Fs::from_repr(nsk_repr)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "nsk not in field"))?;
|
||||
|
||||
let mut ovk = [0; 32];
|
||||
reader.read_exact(&mut ovk)?;
|
||||
@@ -89,8 +91,8 @@ impl<E: JubjubEngine> ExpandedSpendingKey<E> {
|
||||
}
|
||||
|
||||
pub fn write<W: 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.ask.to_repr().as_ref())?;
|
||||
writer.write_all(self.nsk.to_repr().as_ref())?;
|
||||
writer.write_all(&self.ovk.0)?;
|
||||
|
||||
Ok(())
|
||||
@@ -111,7 +113,7 @@ impl<E: JubjubEngine> Clone for FullViewingKey<E> {
|
||||
ak: self.vk.ak.clone(),
|
||||
nk: self.vk.nk.clone(),
|
||||
},
|
||||
ovk: self.ovk.clone(),
|
||||
ovk: self.ovk,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,19 +1,10 @@
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
//! *General Zcash primitives.*
|
||||
//!
|
||||
//! `zcash_primitives` is a library that provides the core structs and functions necessary
|
||||
//! for working with Zcash.
|
||||
|
||||
extern crate aes;
|
||||
extern crate blake2b_simd;
|
||||
extern crate blake2s_simd;
|
||||
extern crate byteorder;
|
||||
extern crate crypto_api_chachapoly;
|
||||
extern crate ff;
|
||||
extern crate fpe;
|
||||
extern crate hex;
|
||||
extern crate pairing;
|
||||
extern crate rand;
|
||||
extern crate rand_core;
|
||||
extern crate rand_os;
|
||||
extern crate sha2;
|
||||
// Catch documentation errors caused by code changes.
|
||||
#![deny(intra_doc_link_resolution_failure)]
|
||||
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
extern crate ripemd160;
|
||||
@@ -27,8 +18,10 @@ extern crate hex_literal;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate rand_xorshift;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
pub mod block;
|
||||
pub mod consensus;
|
||||
pub mod constants;
|
||||
pub mod group_hash;
|
||||
pub mod jubjub;
|
||||
@@ -49,7 +42,7 @@ pub mod zip32;
|
||||
#[cfg(test)]
|
||||
mod test_vectors;
|
||||
|
||||
use jubjub::JubjubBls12;
|
||||
use crate::jubjub::JubjubBls12;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() };
|
||||
|
@@ -5,8 +5,8 @@ use std::collections::VecDeque;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::iter;
|
||||
|
||||
use sapling::SAPLING_COMMITMENT_TREE_DEPTH;
|
||||
use serialize::{Optional, Vector};
|
||||
use crate::sapling::SAPLING_COMMITMENT_TREE_DEPTH;
|
||||
use crate::serialize::{Optional, Vector};
|
||||
|
||||
/// A hashable node within a Merkle tree.
|
||||
pub trait Hashable: Clone + Copy {
|
||||
@@ -17,13 +17,13 @@ pub trait Hashable: Clone + Copy {
|
||||
fn write<W: Write>(&self, writer: W) -> io::Result<()>;
|
||||
|
||||
/// Returns the parent node within the tree of the two given nodes.
|
||||
fn combine(usize, &Self, &Self) -> Self;
|
||||
fn combine(_: usize, _: &Self, _: &Self) -> Self;
|
||||
|
||||
/// Returns a blank leaf node.
|
||||
fn blank() -> Self;
|
||||
|
||||
/// Returns the empty root for the given depth.
|
||||
fn empty_root(usize) -> Self;
|
||||
fn empty_root(_: usize) -> Self;
|
||||
}
|
||||
|
||||
struct PathFiller<Node: Hashable> {
|
||||
@@ -164,14 +164,8 @@ impl<Node: Hashable> CommitmentTree<Node> {
|
||||
// - Empty leaves are used as needed.
|
||||
let leaf_root = Node::combine(
|
||||
0,
|
||||
&match self.left {
|
||||
Some(node) => node,
|
||||
None => filler.next(0),
|
||||
},
|
||||
&match self.right {
|
||||
Some(node) => node,
|
||||
None => filler.next(0),
|
||||
},
|
||||
&self.left.unwrap_or_else(|| filler.next(0)),
|
||||
&self.right.unwrap_or_else(|| filler.next(0)),
|
||||
);
|
||||
|
||||
// 2) Hash in parents up to the currently-filled depth.
|
||||
@@ -202,27 +196,28 @@ impl<Node: Hashable> CommitmentTree<Node> {
|
||||
/// ```
|
||||
/// extern crate ff;
|
||||
/// extern crate pairing;
|
||||
/// extern crate rand_os;
|
||||
/// extern crate rand_core;
|
||||
/// extern crate zcash_primitives;
|
||||
///
|
||||
/// use ff::{Field, PrimeField};
|
||||
/// use pairing::bls12_381::Fr;
|
||||
/// use rand_os::OsRng;
|
||||
/// use rand_core::OsRng;
|
||||
/// use zcash_primitives::{
|
||||
/// merkle_tree::{CommitmentTree, IncrementalWitness},
|
||||
/// sapling::Node,
|
||||
/// };
|
||||
///
|
||||
/// let mut rng = OsRng::new().unwrap();
|
||||
/// let mut rng = OsRng;
|
||||
///
|
||||
/// let mut tree = CommitmentTree::<Node>::new();
|
||||
///
|
||||
/// tree.append(Node::new(Fr::random(&mut rng).into_repr()));
|
||||
/// tree.append(Node::new(Fr::random(&mut rng).into_repr()));
|
||||
/// tree.append(Node::new(Fr::random(&mut rng).to_repr()));
|
||||
/// tree.append(Node::new(Fr::random(&mut rng).to_repr()));
|
||||
/// let mut witness = IncrementalWitness::from_tree(&tree);
|
||||
/// assert_eq!(witness.position(), 1);
|
||||
/// assert_eq!(tree.root(), witness.root());
|
||||
///
|
||||
/// let cmu = Node::new(Fr::random(&mut rng).into_repr());
|
||||
/// let cmu = Node::new(Fr::random(&mut rng).to_repr());
|
||||
/// tree.append(cmu);
|
||||
/// witness.append(cmu);
|
||||
/// assert_eq!(tree.root(), witness.root());
|
||||
@@ -380,19 +375,19 @@ impl<Node: Hashable> IncrementalWitness<Node> {
|
||||
}
|
||||
|
||||
/// Returns the current witness, or None if the tree is empty.
|
||||
pub fn path(&self) -> Option<CommitmentTreeWitness<Node>> {
|
||||
pub fn path(&self) -> Option<MerklePath<Node>> {
|
||||
self.path_inner(SAPLING_COMMITMENT_TREE_DEPTH)
|
||||
}
|
||||
|
||||
fn path_inner(&self, depth: usize) -> Option<CommitmentTreeWitness<Node>> {
|
||||
fn path_inner(&self, depth: usize) -> Option<MerklePath<Node>> {
|
||||
let mut filler = self.filler();
|
||||
let mut auth_path = Vec::new();
|
||||
|
||||
if let Some(node) = self.tree.left {
|
||||
if self.tree.right.is_some() {
|
||||
auth_path.push(Some((node, true)));
|
||||
auth_path.push((node, true));
|
||||
} else {
|
||||
auth_path.push(Some((filler.next(0), false)));
|
||||
auth_path.push((filler.next(0), false));
|
||||
}
|
||||
} else {
|
||||
// Can't create an authentication path for the beginning of the tree
|
||||
@@ -401,41 +396,37 @@ impl<Node: Hashable> IncrementalWitness<Node> {
|
||||
|
||||
for (i, p) in self.tree.parents.iter().enumerate() {
|
||||
auth_path.push(match p {
|
||||
Some(node) => Some((*node, true)),
|
||||
None => Some((filler.next(i + 1), false)),
|
||||
Some(node) => (*node, true),
|
||||
None => (filler.next(i + 1), false),
|
||||
});
|
||||
}
|
||||
|
||||
for i in self.tree.parents.len()..(depth - 1) {
|
||||
auth_path.push(Some((filler.next(i + 1), false)));
|
||||
auth_path.push((filler.next(i + 1), false));
|
||||
}
|
||||
assert_eq!(auth_path.len(), depth);
|
||||
|
||||
Some(CommitmentTreeWitness::from_path(
|
||||
auth_path,
|
||||
self.position() as u64,
|
||||
))
|
||||
Some(MerklePath::from_path(auth_path, self.position() as u64))
|
||||
}
|
||||
}
|
||||
|
||||
/// A witness to a path from a position in a particular commitment tree to the root of
|
||||
/// that tree.
|
||||
/// A path from a position in a particular commitment tree to the root of that tree.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct CommitmentTreeWitness<Node: Hashable> {
|
||||
pub auth_path: Vec<Option<(Node, bool)>>,
|
||||
pub struct MerklePath<Node: Hashable> {
|
||||
pub auth_path: Vec<(Node, bool)>,
|
||||
pub position: u64,
|
||||
}
|
||||
|
||||
impl<Node: Hashable> CommitmentTreeWitness<Node> {
|
||||
/// Constructs a witness directly from its path and position.
|
||||
pub fn from_path(auth_path: Vec<Option<(Node, bool)>>, position: u64) -> Self {
|
||||
CommitmentTreeWitness {
|
||||
impl<Node: Hashable> MerklePath<Node> {
|
||||
/// Constructs a Merkle path directly from a path and position.
|
||||
pub fn from_path(auth_path: Vec<(Node, bool)>, position: u64) -> Self {
|
||||
MerklePath {
|
||||
auth_path,
|
||||
position,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a witness from its serialized form.
|
||||
/// Reads a Merkle path from its serialized form.
|
||||
pub fn from_slice(witness: &[u8]) -> Result<Self, ()> {
|
||||
Self::from_slice_with_depth(witness, SAPLING_COMMITMENT_TREE_DEPTH)
|
||||
}
|
||||
@@ -449,46 +440,41 @@ impl<Node: Hashable> CommitmentTreeWitness<Node> {
|
||||
witness = &witness[1..];
|
||||
|
||||
// Begin to construct the authentication path
|
||||
let mut auth_path = vec![None; depth];
|
||||
let iter = witness.chunks_exact(33);
|
||||
witness = iter.remainder();
|
||||
|
||||
// The vector works in reverse
|
||||
for i in (0..depth).rev() {
|
||||
// skip length of inner vector
|
||||
if witness[0] != 32 {
|
||||
// the length of a pedersen hash
|
||||
return Err(());
|
||||
}
|
||||
witness = &witness[1..];
|
||||
|
||||
// Grab the sibling node at this depth in the tree
|
||||
let mut sibling = [0u8; 32];
|
||||
sibling.copy_from_slice(&witness[0..32]);
|
||||
witness = &witness[32..];
|
||||
|
||||
// Sibling node should be an element of Fr
|
||||
let sibling = match Node::read(&sibling[..]) {
|
||||
Ok(p) => p,
|
||||
Err(_) => return Err(()),
|
||||
};
|
||||
|
||||
// Set the value in the auth path; we put false here
|
||||
// for now (signifying the position bit) which we'll
|
||||
// fill in later.
|
||||
auth_path[i] = Some((sibling, false));
|
||||
let mut auth_path = iter
|
||||
.rev()
|
||||
.map(|bytes| {
|
||||
// Length of inner vector should be the length of a Pedersen hash
|
||||
if bytes[0] == 32 {
|
||||
// Sibling node should be an element of Fr
|
||||
Node::read(&bytes[1..])
|
||||
.map(|sibling| {
|
||||
// Set the value in the auth path; we put false here
|
||||
// for now (signifying the position bit) which we'll
|
||||
// fill in later.
|
||||
(sibling, false)
|
||||
})
|
||||
.map_err(|_| ())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
if auth_path.len() != depth {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
// Read the position from the witness
|
||||
let position = match witness.read_u64::<LittleEndian>() {
|
||||
Ok(pos) => pos,
|
||||
Err(_) => return Err(()),
|
||||
};
|
||||
let position = witness.read_u64::<LittleEndian>().map_err(|_| ())?;
|
||||
|
||||
// Given the position, let's finish constructing the authentication
|
||||
// path
|
||||
let mut tmp = position;
|
||||
for i in 0..depth {
|
||||
auth_path[i].as_mut().map(|p| p.1 = (tmp & 1) == 1);
|
||||
|
||||
for entry in auth_path.iter_mut() {
|
||||
entry.1 = (tmp & 1) == 1;
|
||||
tmp >>= 1;
|
||||
}
|
||||
|
||||
@@ -496,7 +482,7 @@ impl<Node: Hashable> CommitmentTreeWitness<Node> {
|
||||
// have provided more information than they should have, indicating
|
||||
// a bug downstream
|
||||
if witness.is_empty() {
|
||||
Ok(CommitmentTreeWitness {
|
||||
Ok(MerklePath {
|
||||
auth_path,
|
||||
position,
|
||||
})
|
||||
@@ -504,16 +490,30 @@ impl<Node: Hashable> CommitmentTreeWitness<Node> {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the root of the tree corresponding to this path applied to `leaf`.
|
||||
pub fn root(&self, leaf: Node) -> Node {
|
||||
self.auth_path
|
||||
.iter()
|
||||
.enumerate()
|
||||
.fold(
|
||||
leaf,
|
||||
|root, (i, (p, leaf_is_on_right))| match leaf_is_on_right {
|
||||
false => Node::combine(i, &root, p),
|
||||
true => Node::combine(i, p, &root),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{CommitmentTree, CommitmentTreeWitness, Hashable, IncrementalWitness, PathFiller};
|
||||
use sapling::Node;
|
||||
use super::{CommitmentTree, Hashable, IncrementalWitness, MerklePath, PathFiller};
|
||||
use crate::sapling::Node;
|
||||
|
||||
use ff::PrimeFieldRepr;
|
||||
use hex;
|
||||
use pairing::bls12_381::FrRepr;
|
||||
use std::convert::TryInto;
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
const HEX_EMPTY_ROOTS: [&str; 33] = [
|
||||
@@ -607,7 +607,7 @@ mod tests {
|
||||
self.0.root_inner(TESTING_DEPTH)
|
||||
}
|
||||
|
||||
fn path(&self) -> Option<CommitmentTreeWitness<Node>> {
|
||||
fn path(&self) -> Option<MerklePath<Node>> {
|
||||
self.0.path_inner(TESTING_DEPTH)
|
||||
}
|
||||
}
|
||||
@@ -1012,17 +1012,16 @@ mod tests {
|
||||
assert_eq!(tree.size(), 0);
|
||||
|
||||
let mut witnesses = vec![];
|
||||
let mut last_cm = None;
|
||||
let mut paths_i = 0;
|
||||
let mut witness_ser_i = 0;
|
||||
for i in 0..16 {
|
||||
let mut cm = FrRepr::default();
|
||||
cm.read_le(&hex::decode(commitments[i]).unwrap()[..])
|
||||
.expect("length is 32 bytes");
|
||||
let cm = FrRepr(hex::decode(commitments[i]).unwrap()[..].try_into().unwrap());
|
||||
|
||||
let cm = Node::new(cm);
|
||||
|
||||
// Witness here
|
||||
witnesses.push(TestIncrementalWitness::from_tree(&tree));
|
||||
witnesses.push((TestIncrementalWitness::from_tree(&tree), last_cm));
|
||||
|
||||
// Now append a commitment to the tree
|
||||
assert!(tree.append(cm).is_ok());
|
||||
@@ -1036,22 +1035,23 @@ mod tests {
|
||||
// Check serialization of tree
|
||||
assert_tree_ser_eq(&tree, tree_ser[i]);
|
||||
|
||||
let mut first = true; // The first witness can never form a path
|
||||
for witness in witnesses.as_mut_slice() {
|
||||
for (witness, leaf) in witnesses.as_mut_slice() {
|
||||
// Append the same commitment to all the witnesses
|
||||
assert!(witness.append(cm).is_ok());
|
||||
|
||||
if first {
|
||||
assert!(witness.path().is_none());
|
||||
} else {
|
||||
if let Some(leaf) = leaf {
|
||||
let path = witness.path().expect("should be able to create a path");
|
||||
let expected = CommitmentTreeWitness::from_slice_with_depth(
|
||||
let expected = MerklePath::from_slice_with_depth(
|
||||
&mut hex::decode(paths[paths_i]).unwrap(),
|
||||
TESTING_DEPTH,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(path, expected);
|
||||
assert_eq!(path.root(*leaf), witness.root());
|
||||
paths_i += 1;
|
||||
} else {
|
||||
// The first witness can never form a path
|
||||
assert!(witness.path().is_none());
|
||||
}
|
||||
|
||||
// Check witness serialization
|
||||
@@ -1059,15 +1059,15 @@ mod tests {
|
||||
witness_ser_i += 1;
|
||||
|
||||
assert_eq!(witness.root(), tree.root());
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
last_cm = Some(cm);
|
||||
}
|
||||
|
||||
// Tree should be full now
|
||||
let node = Node::blank();
|
||||
assert!(tree.append(node).is_err());
|
||||
for witness in witnesses.as_mut_slice() {
|
||||
for (witness, _) in witnesses.as_mut_slice() {
|
||||
assert!(witness.append(node).is_err());
|
||||
}
|
||||
}
|
||||
|
@@ -11,16 +11,17 @@ use crate::{
|
||||
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf};
|
||||
use ff::{PrimeField, PrimeFieldRepr};
|
||||
use ff::PrimeField;
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
use std::convert::TryInto;
|
||||
use std::fmt;
|
||||
use std::str;
|
||||
|
||||
use crate::{keys::OutgoingViewingKey, JUBJUB};
|
||||
|
||||
pub const KDF_SAPLING_PERSONALIZATION: &'static [u8; 16] = b"Zcash_SaplingKDF";
|
||||
pub const PRF_OCK_PERSONALIZATION: &'static [u8; 16] = b"Zcash_Derive_ock";
|
||||
pub const KDF_SAPLING_PERSONALIZATION: &[u8; 16] = b"Zcash_SaplingKDF";
|
||||
pub const PRF_OCK_PERSONALIZATION: &[u8; 16] = b"Zcash_Derive_ock";
|
||||
|
||||
const COMPACT_NOTE_SIZE: usize = (
|
||||
1 + // version
|
||||
@@ -85,7 +86,7 @@ impl Default for Memo {
|
||||
|
||||
impl PartialEq for Memo {
|
||||
fn eq(&self, rhs: &Memo) -> bool {
|
||||
&self.0[..] == &rhs.0[..]
|
||||
self.0[..] == rhs.0[..]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,11 +107,6 @@ impl Memo {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a `Memo` containing the given string, or `None` if the string is too long.
|
||||
pub fn from_str(memo: &str) -> Option<Memo> {
|
||||
Memo::from_bytes(memo.as_bytes())
|
||||
}
|
||||
|
||||
/// Returns the underlying bytes of the `Memo`.
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
&self.0[..]
|
||||
@@ -134,6 +130,15 @@ impl Memo {
|
||||
}
|
||||
}
|
||||
|
||||
impl str::FromStr for Memo {
|
||||
type Err = ();
|
||||
|
||||
/// Returns a `Memo` containing the given string, or an error if the string is too long.
|
||||
fn from_str(memo: &str) -> Result<Self, Self::Err> {
|
||||
Memo::from_bytes(memo.as_bytes()).ok_or(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_esk<R: RngCore + CryptoRng>(rng: &mut R) -> Fs {
|
||||
// create random 64 byte buffer
|
||||
let mut buffer = [0u8; 64];
|
||||
@@ -188,7 +193,7 @@ fn prf_ock(
|
||||
let mut ock_input = [0u8; 128];
|
||||
ock_input[0..32].copy_from_slice(&ovk.0);
|
||||
cv.write(&mut ock_input[32..64]).unwrap();
|
||||
cmu.into_repr().write_le(&mut ock_input[64..96]).unwrap();
|
||||
ock_input[64..96].copy_from_slice(cmu.to_repr().as_ref());
|
||||
epk.write(&mut ock_input[96..128]).unwrap();
|
||||
|
||||
Blake2bParams::new()
|
||||
@@ -210,12 +215,12 @@ fn prf_ock(
|
||||
/// ```
|
||||
/// extern crate ff;
|
||||
/// extern crate pairing;
|
||||
/// extern crate rand_os;
|
||||
/// extern crate rand_core;
|
||||
/// extern crate zcash_primitives;
|
||||
///
|
||||
/// use ff::Field;
|
||||
/// use pairing::bls12_381::Bls12;
|
||||
/// use rand_os::OsRng;
|
||||
/// use rand_core::OsRng;
|
||||
/// use zcash_primitives::{
|
||||
/// jubjub::fs::Fs,
|
||||
/// keys::OutgoingViewingKey,
|
||||
@@ -228,10 +233,7 @@ fn prf_ock(
|
||||
///
|
||||
/// let diversifier = Diversifier([0; 11]);
|
||||
/// let pk_d = diversifier.g_d::<Bls12>(&JUBJUB).unwrap();
|
||||
/// let to = PaymentAddress {
|
||||
/// pk_d,
|
||||
/// diversifier,
|
||||
/// };
|
||||
/// let to = PaymentAddress::from_parts(diversifier, pk_d).unwrap();
|
||||
/// let ovk = OutgoingViewingKey([0; 32]);
|
||||
///
|
||||
/// let value = 1000;
|
||||
@@ -290,22 +292,18 @@ impl SaplingNoteEncryption {
|
||||
|
||||
/// Generates `encCiphertext` for this note.
|
||||
pub fn encrypt_note_plaintext(&self) -> [u8; ENC_CIPHERTEXT_SIZE] {
|
||||
let shared_secret = sapling_ka_agree(&self.esk, &self.to.pk_d);
|
||||
let shared_secret = sapling_ka_agree(&self.esk, self.to.pk_d());
|
||||
let key = kdf_sapling(shared_secret, &self.epk);
|
||||
|
||||
// Note plaintext encoding is defined in section 5.5 of the Zcash Protocol
|
||||
// Specification.
|
||||
let mut input = [0; NOTE_PLAINTEXT_SIZE];
|
||||
input[0] = 1;
|
||||
input[1..12].copy_from_slice(&self.to.diversifier.0);
|
||||
input[1..12].copy_from_slice(&self.to.diversifier().0);
|
||||
(&mut input[12..20])
|
||||
.write_u64::<LittleEndian>(self.note.value)
|
||||
.unwrap();
|
||||
self.note
|
||||
.r
|
||||
.into_repr()
|
||||
.write_le(&mut input[20..COMPACT_NOTE_SIZE])
|
||||
.unwrap();
|
||||
input[20..COMPACT_NOTE_SIZE].copy_from_slice(self.note.r.to_repr().as_ref());
|
||||
input[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE].copy_from_slice(&self.memo.0);
|
||||
|
||||
let mut output = [0u8; ENC_CIPHERTEXT_SIZE];
|
||||
@@ -329,10 +327,7 @@ impl SaplingNoteEncryption {
|
||||
|
||||
let mut input = [0u8; OUT_PLAINTEXT_SIZE];
|
||||
self.note.pk_d.write(&mut input[0..32]).unwrap();
|
||||
self.esk
|
||||
.into_repr()
|
||||
.write_le(&mut input[32..OUT_PLAINTEXT_SIZE])
|
||||
.unwrap();
|
||||
input[32..OUT_PLAINTEXT_SIZE].copy_from_slice(self.esk.to_repr().as_ref());
|
||||
|
||||
let mut output = [0u8; OUT_CIPHERTEXT_SIZE];
|
||||
assert_eq!(
|
||||
@@ -362,16 +357,18 @@ fn parse_note_plaintext_without_memo(
|
||||
|
||||
let v = (&plaintext[12..20]).read_u64::<LittleEndian>().ok()?;
|
||||
|
||||
let mut rcm = FsRepr::default();
|
||||
rcm.read_le(&plaintext[20..COMPACT_NOTE_SIZE]).ok()?;
|
||||
let rcm = Fs::from_repr(rcm).ok()?;
|
||||
let rcm = Fs::from_repr(FsRepr(
|
||||
plaintext[20..COMPACT_NOTE_SIZE]
|
||||
.try_into()
|
||||
.expect("slice is the correct length"),
|
||||
))?;
|
||||
|
||||
let diversifier = Diversifier(d);
|
||||
let pk_d = diversifier
|
||||
.g_d::<Bls12>(&JUBJUB)?
|
||||
.mul(ivk.into_repr(), &JUBJUB);
|
||||
.mul(ivk.to_repr(), &JUBJUB);
|
||||
|
||||
let to = PaymentAddress { pk_d, diversifier };
|
||||
let to = PaymentAddress::from_parts(diversifier, pk_d)?;
|
||||
let note = to.create_note(v, rcm, &JUBJUB).unwrap();
|
||||
|
||||
if note.cm(&JUBJUB) != *cmu {
|
||||
@@ -482,9 +479,11 @@ pub fn try_sapling_output_recovery(
|
||||
.ok()?
|
||||
.as_prime_order(&JUBJUB)?;
|
||||
|
||||
let mut esk = FsRepr::default();
|
||||
esk.read_le(&op[32..OUT_PLAINTEXT_SIZE]).ok()?;
|
||||
let esk = Fs::from_repr(esk).ok()?;
|
||||
let esk = Fs::from_repr(FsRepr(
|
||||
op[32..OUT_PLAINTEXT_SIZE]
|
||||
.try_into()
|
||||
.expect("slice is the correct length"),
|
||||
))?;
|
||||
|
||||
let shared_secret = sapling_ka_agree(&esk, &pk_d);
|
||||
let key = kdf_sapling(shared_secret, &epk);
|
||||
@@ -514,9 +513,11 @@ pub fn try_sapling_output_recovery(
|
||||
|
||||
let v = (&plaintext[12..20]).read_u64::<LittleEndian>().ok()?;
|
||||
|
||||
let mut rcm = FsRepr::default();
|
||||
rcm.read_le(&plaintext[20..COMPACT_NOTE_SIZE]).ok()?;
|
||||
let rcm = Fs::from_repr(rcm).ok()?;
|
||||
let rcm = Fs::from_repr(FsRepr(
|
||||
plaintext[20..COMPACT_NOTE_SIZE]
|
||||
.try_into()
|
||||
.expect("slice is the correct length"),
|
||||
))?;
|
||||
|
||||
let mut memo = [0u8; 512];
|
||||
memo.copy_from_slice(&plaintext[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]);
|
||||
@@ -524,14 +525,14 @@ pub fn try_sapling_output_recovery(
|
||||
let diversifier = Diversifier(d);
|
||||
if diversifier
|
||||
.g_d::<Bls12>(&JUBJUB)?
|
||||
.mul(esk.into_repr(), &JUBJUB)
|
||||
.mul(esk.to_repr(), &JUBJUB)
|
||||
!= *epk
|
||||
{
|
||||
// Published epk doesn't match calculated epk
|
||||
return None;
|
||||
}
|
||||
|
||||
let to = PaymentAddress { pk_d, diversifier };
|
||||
let to = PaymentAddress::from_parts(diversifier, pk_d)?;
|
||||
let note = to.create_note(v, rcm, &JUBJUB).unwrap();
|
||||
|
||||
if note.cm(&JUBJUB) != *cmu {
|
||||
@@ -553,10 +554,12 @@ mod tests {
|
||||
primitives::{Diversifier, PaymentAddress, ValueCommitment},
|
||||
};
|
||||
use crypto_api_chachapoly::ChachaPolyIetf;
|
||||
use ff::{Field, PrimeField, PrimeFieldRepr};
|
||||
use ff::{Field, PrimeField};
|
||||
use pairing::bls12_381::{Bls12, Fr, FrRepr};
|
||||
use rand_core::OsRng;
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
use rand_os::OsRng;
|
||||
use std::convert::TryInto;
|
||||
use std::str::FromStr;
|
||||
|
||||
use super::{
|
||||
kdf_sapling, prf_ock, sapling_ka_agree, try_sapling_compact_note_decryption,
|
||||
@@ -661,16 +664,18 @@ mod tests {
|
||||
0x74, 0x20, 0x65, 0x6e, 0x6f, 0x75, 0x67, 0x68
|
||||
])
|
||||
);
|
||||
assert!(Memo::from_str(
|
||||
"thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \
|
||||
iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
|
||||
veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeryyyyyyyyyyyyyyyyyyyyyyyyyy \
|
||||
looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong \
|
||||
meeeeeeeeeeeeeeeeeeemooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo \
|
||||
but it's now a bit too long"
|
||||
)
|
||||
.is_none());
|
||||
assert_eq!(
|
||||
Memo::from_str(
|
||||
"thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \
|
||||
iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
|
||||
veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeryyyyyyyyyyyyyyyyyyyyyyyyyy \
|
||||
looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong \
|
||||
meeeeeeeeeeeeeeeeeeemooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo \
|
||||
but it's now a bit too long"
|
||||
),
|
||||
Err(())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -691,10 +696,47 @@ mod tests {
|
||||
[u8; ENC_CIPHERTEXT_SIZE],
|
||||
[u8; OUT_CIPHERTEXT_SIZE],
|
||||
) {
|
||||
let diversifier = Diversifier([0; 11]);
|
||||
let ivk = Fs::random(&mut rng);
|
||||
|
||||
let (ovk, ivk, cv, cmu, epk, enc_ciphertext, out_ciphertext) =
|
||||
random_enc_ciphertext_with(ivk, rng);
|
||||
|
||||
assert!(try_sapling_note_decryption(&ivk, &epk, &cmu, &enc_ciphertext).is_some());
|
||||
assert!(try_sapling_compact_note_decryption(
|
||||
&ivk,
|
||||
&epk,
|
||||
&cmu,
|
||||
&enc_ciphertext[..COMPACT_NOTE_SIZE]
|
||||
)
|
||||
.is_some());
|
||||
assert!(try_sapling_output_recovery(
|
||||
&ovk,
|
||||
&cv,
|
||||
&cmu,
|
||||
&epk,
|
||||
&enc_ciphertext,
|
||||
&out_ciphertext
|
||||
)
|
||||
.is_some());
|
||||
|
||||
(ovk, ivk, cv, cmu, epk, enc_ciphertext, out_ciphertext)
|
||||
}
|
||||
|
||||
fn random_enc_ciphertext_with<R: RngCore + CryptoRng>(
|
||||
ivk: Fs,
|
||||
mut rng: &mut R,
|
||||
) -> (
|
||||
OutgoingViewingKey,
|
||||
Fs,
|
||||
edwards::Point<Bls12, Unknown>,
|
||||
Fr,
|
||||
edwards::Point<Bls12, PrimeOrder>,
|
||||
[u8; ENC_CIPHERTEXT_SIZE],
|
||||
[u8; OUT_CIPHERTEXT_SIZE],
|
||||
) {
|
||||
let diversifier = Diversifier([0; 11]);
|
||||
let pk_d = diversifier.g_d::<Bls12>(&JUBJUB).unwrap().mul(ivk, &JUBJUB);
|
||||
let pa = PaymentAddress { diversifier, pk_d };
|
||||
let pa = PaymentAddress::from_parts_unchecked(diversifier, pk_d);
|
||||
|
||||
// Construct the value commitment for the proof instance
|
||||
let value = 100;
|
||||
@@ -715,24 +757,6 @@ mod tests {
|
||||
let enc_ciphertext = ne.encrypt_note_plaintext();
|
||||
let out_ciphertext = ne.encrypt_outgoing_plaintext(&cv, &cmu);
|
||||
|
||||
assert!(try_sapling_note_decryption(&ivk, epk, &cmu, &enc_ciphertext).is_some());
|
||||
assert!(try_sapling_compact_note_decryption(
|
||||
&ivk,
|
||||
epk,
|
||||
&cmu,
|
||||
&enc_ciphertext[..COMPACT_NOTE_SIZE]
|
||||
)
|
||||
.is_some());
|
||||
assert!(try_sapling_output_recovery(
|
||||
&ovk,
|
||||
&cv,
|
||||
&cmu,
|
||||
&epk,
|
||||
&enc_ciphertext,
|
||||
&out_ciphertext
|
||||
)
|
||||
.is_some());
|
||||
|
||||
(
|
||||
ovk,
|
||||
ivk,
|
||||
@@ -768,9 +792,7 @@ mod tests {
|
||||
.as_prime_order(&JUBJUB)
|
||||
.unwrap();
|
||||
|
||||
let mut esk = FsRepr::default();
|
||||
esk.read_le(&op[32..OUT_PLAINTEXT_SIZE]).unwrap();
|
||||
let esk = Fs::from_repr(esk).unwrap();
|
||||
let esk = Fs::from_repr(FsRepr(op[32..OUT_PLAINTEXT_SIZE].try_into().unwrap())).unwrap();
|
||||
|
||||
let shared_secret = sapling_ka_agree(&esk, &pk_d);
|
||||
let key = kdf_sapling(shared_secret, &epk);
|
||||
@@ -1249,23 +1271,33 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recovery_with_invalid_pk_d() {
|
||||
let mut rng = OsRng;
|
||||
|
||||
let ivk = Fs::zero();
|
||||
let (ovk, _, cv, cmu, epk, enc_ciphertext, out_ciphertext) =
|
||||
random_enc_ciphertext_with(ivk, &mut rng);
|
||||
|
||||
assert_eq!(
|
||||
try_sapling_output_recovery(&ovk, &cv, &cmu, &epk, &enc_ciphertext, &out_ciphertext),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vectors() {
|
||||
let test_vectors = crate::test_vectors::note_encryption::make_test_vectors();
|
||||
|
||||
macro_rules! read_fr {
|
||||
($field:expr) => {{
|
||||
let mut repr = FrRepr::default();
|
||||
repr.read_le(&$field[..]).unwrap();
|
||||
Fr::from_repr(repr).unwrap()
|
||||
Fr::from_repr(FrRepr($field[..].try_into().unwrap())).unwrap()
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! read_fs {
|
||||
($field:expr) => {{
|
||||
let mut repr = FsRepr::default();
|
||||
repr.read_le(&$field[..]).unwrap();
|
||||
Fs::from_repr(repr).unwrap()
|
||||
Fs::from_repr(FsRepr($field[..].try_into().unwrap())).unwrap()
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -1310,10 +1342,7 @@ mod tests {
|
||||
let ock = prf_ock(&ovk, &cv, &cmu, &epk);
|
||||
assert_eq!(ock.as_bytes(), tv.ock);
|
||||
|
||||
let to = PaymentAddress {
|
||||
pk_d,
|
||||
diversifier: Diversifier(tv.default_d),
|
||||
};
|
||||
let to = PaymentAddress::from_parts(Diversifier(tv.default_d), pk_d).unwrap();
|
||||
let note = to.create_note(tv.v, rcm, &JUBJUB).unwrap();
|
||||
assert_eq!(note.cm(&JUBJUB), cmu);
|
||||
|
||||
|
@@ -1,5 +1,9 @@
|
||||
use ff::{Field, PrimeField, PrimeFieldRepr};
|
||||
use jubjub::*;
|
||||
//! Implementation of the Pedersen hash function used in Sapling.
|
||||
|
||||
use crate::jubjub::*;
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use ff::{Endianness, Field, PrimeField};
|
||||
use std::ops::{AddAssign, Neg};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Personalization {
|
||||
@@ -55,14 +59,14 @@ where
|
||||
if a {
|
||||
tmp.add_assign(&cur);
|
||||
}
|
||||
cur.double(); // 2^1 * cur
|
||||
cur = cur.double(); // 2^1 * cur
|
||||
if b {
|
||||
tmp.add_assign(&cur);
|
||||
}
|
||||
|
||||
// conditionally negate
|
||||
if c {
|
||||
tmp.negate();
|
||||
tmp = tmp.neg();
|
||||
}
|
||||
|
||||
acc.add_assign(&tmp);
|
||||
@@ -72,9 +76,7 @@ where
|
||||
if chunks_remaining == 0 {
|
||||
break;
|
||||
} else {
|
||||
cur.double(); // 2^2 * cur
|
||||
cur.double(); // 2^3 * cur
|
||||
cur.double(); // 2^4 * cur
|
||||
cur = cur.double().double().double(); // 2^4 * cur
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,19 +86,32 @@ where
|
||||
|
||||
let mut table: &[Vec<edwards::Point<E, _>>] =
|
||||
&generators.next().expect("we don't have enough generators");
|
||||
let window = JubjubBls12::pedersen_hash_exp_window_size();
|
||||
let window_mask = (1 << window) - 1;
|
||||
let window = JubjubBls12::pedersen_hash_exp_window_size() as usize;
|
||||
let window_mask = (1u64 << window) - 1;
|
||||
|
||||
let mut acc = acc.into_repr();
|
||||
let mut acc = acc.to_repr();
|
||||
<E::Fs as PrimeField>::ReprEndianness::toggle_little_endian(&mut acc);
|
||||
let num_limbs: usize = acc.as_ref().len() / 8;
|
||||
let mut limbs = vec![0u64; num_limbs + 1];
|
||||
LittleEndian::read_u64_into(acc.as_ref(), &mut limbs[..num_limbs]);
|
||||
|
||||
let mut tmp = edwards::Point::zero();
|
||||
|
||||
while !acc.is_zero() {
|
||||
let i = (acc.as_ref()[0] & window_mask) as usize;
|
||||
let mut pos = 0;
|
||||
while pos < E::Fs::NUM_BITS as usize {
|
||||
let u64_idx = pos / 64;
|
||||
let bit_idx = pos % 64;
|
||||
let i = (if bit_idx + window < 64 {
|
||||
// This window's bits are contained in a single u64.
|
||||
limbs[u64_idx] >> bit_idx
|
||||
} else {
|
||||
// Combine the current u64's bits with the bits from the next u64.
|
||||
(limbs[u64_idx] >> bit_idx) | (limbs[u64_idx + 1] << (64 - bit_idx))
|
||||
} & window_mask) as usize;
|
||||
|
||||
tmp = tmp.add(&table[0][i], params);
|
||||
|
||||
acc.shr(window);
|
||||
pos += window;
|
||||
table = &table[1..];
|
||||
}
|
||||
|
||||
@@ -105,3 +120,44 @@ where
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod test {
|
||||
|
||||
use super::*;
|
||||
use crate::test_vectors::pedersen_hash_vectors;
|
||||
use pairing::bls12_381::Bls12;
|
||||
|
||||
pub struct TestVector<'a> {
|
||||
pub personalization: Personalization,
|
||||
pub input_bits: Vec<u8>,
|
||||
pub hash_x: &'a str,
|
||||
pub hash_y: &'a str,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pedersen_hash_points() {
|
||||
let test_vectors = pedersen_hash_vectors::get_vectors();
|
||||
|
||||
assert!(test_vectors.len() > 0);
|
||||
|
||||
for v in test_vectors.iter() {
|
||||
let params = &JubjubBls12::new();
|
||||
|
||||
let input_bools: Vec<bool> = v.input_bits.iter().map(|&i| i == 1).collect();
|
||||
|
||||
// The 6 bits prefix is handled separately
|
||||
assert_eq!(v.personalization.get_bits(), &input_bools[..6]);
|
||||
|
||||
let (x, y) = pedersen_hash::<Bls12, _>(
|
||||
v.personalization,
|
||||
input_bools.into_iter().skip(6),
|
||||
params,
|
||||
)
|
||||
.to_xy();
|
||||
|
||||
assert_eq!(x.to_string(), v.hash_x);
|
||||
assert_eq!(y.to_string(), v.hash_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,14 +1,16 @@
|
||||
use ff::{Field, PrimeField, PrimeFieldRepr};
|
||||
//! Structs for core Zcash primitives.
|
||||
|
||||
use constants;
|
||||
use ff::{Field, PrimeField};
|
||||
|
||||
use group_hash::group_hash;
|
||||
use crate::constants;
|
||||
|
||||
use pedersen_hash::{pedersen_hash, Personalization};
|
||||
use crate::group_hash::group_hash;
|
||||
|
||||
use crate::pedersen_hash::{pedersen_hash, Personalization};
|
||||
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
|
||||
use jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder};
|
||||
use crate::jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder};
|
||||
|
||||
use blake2s_simd::Params as Blake2sParams;
|
||||
|
||||
@@ -22,7 +24,7 @@ impl<E: JubjubEngine> ValueCommitment<E> {
|
||||
pub fn cm(&self, params: &E::Params) -> edwards::Point<E, PrimeOrder> {
|
||||
params
|
||||
.generator(FixedGenerators::ValueCommitmentValue)
|
||||
.mul(self.value, params)
|
||||
.mul(E::Fs::from(self.value), params)
|
||||
.add(
|
||||
¶ms
|
||||
.generator(FixedGenerators::ValueCommitmentRandomness)
|
||||
@@ -39,7 +41,7 @@ pub struct ProofGenerationKey<E: JubjubEngine> {
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> ProofGenerationKey<E> {
|
||||
pub fn into_viewing_key(&self, params: &E::Params) -> ViewingKey<E> {
|
||||
pub fn to_viewing_key(&self, params: &E::Params) -> ViewingKey<E> {
|
||||
ViewingKey {
|
||||
ak: self.ak.clone(),
|
||||
nk: params
|
||||
@@ -84,23 +86,20 @@ impl<E: JubjubEngine> ViewingKey<E> {
|
||||
h[31] &= 0b0000_0111;
|
||||
|
||||
let mut e = <E::Fs as PrimeField>::Repr::default();
|
||||
e.read_le(&h[..]).unwrap();
|
||||
e.as_mut().copy_from_slice(&h[..]);
|
||||
|
||||
E::Fs::from_repr(e).expect("should be a valid scalar")
|
||||
}
|
||||
|
||||
pub fn into_payment_address(
|
||||
pub fn to_payment_address(
|
||||
&self,
|
||||
diversifier: Diversifier,
|
||||
params: &E::Params,
|
||||
) -> Option<PaymentAddress<E>> {
|
||||
diversifier.g_d(params).map(|g_d| {
|
||||
diversifier.g_d(params).and_then(|g_d| {
|
||||
let pk_d = g_d.mul(self.ivk(), params);
|
||||
|
||||
PaymentAddress {
|
||||
pk_d: pk_d,
|
||||
diversifier: diversifier,
|
||||
}
|
||||
PaymentAddress::from_parts(diversifier, pk_d)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -121,10 +120,16 @@ impl Diversifier {
|
||||
}
|
||||
}
|
||||
|
||||
/// A Sapling payment address.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// `pk_d` is guaranteed to be prime-order (i.e. in the prime-order subgroup of Jubjub,
|
||||
/// and not the identity).
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PaymentAddress<E: JubjubEngine> {
|
||||
pub pk_d: edwards::Point<E, PrimeOrder>,
|
||||
pub diversifier: Diversifier,
|
||||
pk_d: edwards::Point<E, PrimeOrder>,
|
||||
diversifier: Diversifier,
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> PartialEq for PaymentAddress<E> {
|
||||
@@ -134,6 +139,67 @@ impl<E: JubjubEngine> PartialEq for PaymentAddress<E> {
|
||||
}
|
||||
|
||||
impl<E: JubjubEngine> PaymentAddress<E> {
|
||||
/// Constructs a PaymentAddress from a diversifier and a Jubjub point.
|
||||
///
|
||||
/// Returns None if `pk_d` is the identity.
|
||||
pub fn from_parts(
|
||||
diversifier: Diversifier,
|
||||
pk_d: edwards::Point<E, PrimeOrder>,
|
||||
) -> Option<Self> {
|
||||
if pk_d == edwards::Point::zero() {
|
||||
None
|
||||
} else {
|
||||
Some(PaymentAddress { pk_d, diversifier })
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a PaymentAddress from a diversifier and a Jubjub point.
|
||||
///
|
||||
/// Only for test code, as this explicitly bypasses the invariant.
|
||||
#[cfg(test)]
|
||||
pub(crate) fn from_parts_unchecked(
|
||||
diversifier: Diversifier,
|
||||
pk_d: edwards::Point<E, PrimeOrder>,
|
||||
) -> Self {
|
||||
PaymentAddress { pk_d, diversifier }
|
||||
}
|
||||
|
||||
/// Parses a PaymentAddress from bytes.
|
||||
pub fn from_bytes(bytes: &[u8; 43], params: &E::Params) -> Option<Self> {
|
||||
let diversifier = {
|
||||
let mut tmp = [0; 11];
|
||||
tmp.copy_from_slice(&bytes[0..11]);
|
||||
Diversifier(tmp)
|
||||
};
|
||||
// Check that the diversifier is valid
|
||||
if diversifier.g_d::<E>(params).is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
edwards::Point::<E, _>::read(&bytes[11..43], params)
|
||||
.ok()?
|
||||
.as_prime_order(params)
|
||||
.and_then(|pk_d| PaymentAddress::from_parts(diversifier, pk_d))
|
||||
}
|
||||
|
||||
/// Returns the byte encoding of this `PaymentAddress`.
|
||||
pub fn to_bytes(&self) -> [u8; 43] {
|
||||
let mut bytes = [0; 43];
|
||||
bytes[0..11].copy_from_slice(&self.diversifier.0);
|
||||
self.pk_d.write(&mut bytes[11..]).unwrap();
|
||||
bytes
|
||||
}
|
||||
|
||||
/// Returns the [`Diversifier`] for this `PaymentAddress`.
|
||||
pub fn diversifier(&self) -> &Diversifier {
|
||||
&self.diversifier
|
||||
}
|
||||
|
||||
/// Returns `pk_d` for this `PaymentAddress`.
|
||||
pub fn pk_d(&self) -> &edwards::Point<E, PrimeOrder> {
|
||||
&self.pk_d
|
||||
}
|
||||
|
||||
pub fn g_d(&self, params: &E::Params) -> Option<edwards::Point<E, PrimeOrder>> {
|
||||
self.diversifier.g_d(params)
|
||||
}
|
||||
@@ -145,9 +211,9 @@ impl<E: JubjubEngine> PaymentAddress<E> {
|
||||
params: &E::Params,
|
||||
) -> Option<Note<E>> {
|
||||
self.g_d(params).map(|g_d| Note {
|
||||
value: value,
|
||||
value,
|
||||
r: randomness,
|
||||
g_d: g_d,
|
||||
g_d,
|
||||
pk_d: self.pk_d.clone(),
|
||||
})
|
||||
}
|
||||
@@ -225,7 +291,7 @@ impl<E: JubjubEngine> Note<E> {
|
||||
let rho = self.cm_full_point(params).add(
|
||||
¶ms
|
||||
.generator(FixedGenerators::NullifierPosition)
|
||||
.mul(position, params),
|
||||
.mul(E::Fs::from(position), params),
|
||||
params,
|
||||
);
|
||||
|
||||
@@ -245,6 +311,6 @@ impl<E: JubjubEngine> Note<E> {
|
||||
pub fn cm(&self, params: &E::Params) -> E::Fr {
|
||||
// The commitment is in the prime order subgroup, so mapping the
|
||||
// commitment to the x-coordinate is an injective encoding.
|
||||
self.cm_full_point(params).into_xy().0
|
||||
self.cm_full_point(params).to_xy().0
|
||||
}
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@ use crate::{
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
|
||||
use crate::{
|
||||
merkle_tree::CommitmentTreeWitness,
|
||||
merkle_tree::MerklePath,
|
||||
redjubjub::{PublicKey, Signature},
|
||||
sapling::Node,
|
||||
transaction::components::{Amount, GROTH_PROOF_SIZE},
|
||||
@@ -35,7 +35,7 @@ pub trait TxProver {
|
||||
ar: Fs,
|
||||
value: u64,
|
||||
anchor: Fr,
|
||||
witness: CommitmentTreeWitness<Node>,
|
||||
merkle_path: MerklePath<Node>,
|
||||
) -> Result<
|
||||
(
|
||||
[u8; GROTH_PROOF_SIZE],
|
||||
@@ -74,7 +74,7 @@ pub trait TxProver {
|
||||
pub(crate) mod mock {
|
||||
use ff::Field;
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use rand_os::OsRng;
|
||||
use rand_core::OsRng;
|
||||
|
||||
use crate::{
|
||||
jubjub::{edwards, fs::Fs, FixedGenerators, Unknown},
|
||||
@@ -82,7 +82,7 @@ pub(crate) mod mock {
|
||||
};
|
||||
|
||||
use crate::{
|
||||
merkle_tree::CommitmentTreeWitness,
|
||||
merkle_tree::MerklePath,
|
||||
redjubjub::{PublicKey, Signature},
|
||||
sapling::Node,
|
||||
transaction::components::{Amount, GROTH_PROOF_SIZE},
|
||||
@@ -108,7 +108,7 @@ pub(crate) mod mock {
|
||||
ar: Fs,
|
||||
value: u64,
|
||||
_anchor: Fr,
|
||||
_witness: CommitmentTreeWitness<Node>,
|
||||
_merkle_path: MerklePath<Node>,
|
||||
) -> Result<
|
||||
(
|
||||
[u8; GROTH_PROOF_SIZE],
|
||||
|
@@ -1,28 +1,26 @@
|
||||
//! Implementation of RedJubjub, a specialization of RedDSA to the Jubjub curve.
|
||||
//! See section 5.4.6 of the Sapling protocol specification.
|
||||
//! Implementation of [RedJubjub], a specialization of RedDSA to the Jubjub
|
||||
//! curve.
|
||||
//!
|
||||
//! [RedJubjub]: https://zips.z.cash/protocol/protocol.pdf#concretereddsa
|
||||
|
||||
use crate::jubjub::{edwards::Point, FixedGenerators, JubjubEngine, JubjubParams, Unknown};
|
||||
use ff::{Field, PrimeField, PrimeFieldRepr};
|
||||
use ff::{Field, PrimeField};
|
||||
use rand_core::RngCore;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::ops::{AddAssign, MulAssign, Neg};
|
||||
|
||||
use util::hash_to_scalar;
|
||||
use crate::util::hash_to_scalar;
|
||||
|
||||
fn read_scalar<E: JubjubEngine, R: Read>(reader: R) -> io::Result<E::Fs> {
|
||||
fn read_scalar<E: JubjubEngine, R: Read>(mut reader: R) -> io::Result<E::Fs> {
|
||||
let mut s_repr = <E::Fs as PrimeField>::Repr::default();
|
||||
s_repr.read_le(reader)?;
|
||||
reader.read_exact(s_repr.as_mut())?;
|
||||
|
||||
match E::Fs::from_repr(s_repr) {
|
||||
Ok(s) => Ok(s),
|
||||
Err(_) => Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"scalar is not in field",
|
||||
)),
|
||||
}
|
||||
E::Fs::from_repr(s_repr)
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "scalar is not in field"))
|
||||
}
|
||||
|
||||
fn write_scalar<E: JubjubEngine, W: Write>(s: &E::Fs, writer: W) -> io::Result<()> {
|
||||
s.into_repr().write_le(writer)
|
||||
fn write_scalar<E: JubjubEngine, W: Write>(s: &E::Fs, mut writer: W) -> io::Result<()> {
|
||||
writer.write_all(s.to_repr().as_ref())
|
||||
}
|
||||
|
||||
fn h_star<E: JubjubEngine>(a: &[u8], b: &[u8]) -> E::Fs {
|
||||
@@ -191,7 +189,7 @@ pub fn batch_verify<'a, E: JubjubEngine, R: RngCore>(
|
||||
let z = E::Fs::random(rng);
|
||||
|
||||
s.mul_assign(&z);
|
||||
s.negate();
|
||||
s = s.neg();
|
||||
|
||||
r = r.mul(z, params);
|
||||
|
||||
|
@@ -5,14 +5,15 @@ use crate::{
|
||||
pedersen_hash::{pedersen_hash, Personalization},
|
||||
primitives::Note,
|
||||
};
|
||||
use ff::{BitIterator, PrimeField, PrimeFieldRepr};
|
||||
use ff::{BitIterator, PrimeField};
|
||||
use lazy_static::lazy_static;
|
||||
use pairing::bls12_381::{Bls12, Fr, FrRepr};
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use crate::merkle_tree::Hashable;
|
||||
use crate::redjubjub::{PrivateKey, PublicKey, Signature};
|
||||
use JUBJUB;
|
||||
use crate::JUBJUB;
|
||||
|
||||
pub const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32;
|
||||
|
||||
@@ -20,7 +21,7 @@ pub const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32;
|
||||
pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr {
|
||||
let lhs = {
|
||||
let mut tmp = [false; 256];
|
||||
for (a, b) in tmp.iter_mut().rev().zip(BitIterator::new(lhs)) {
|
||||
for (a, b) in tmp.iter_mut().rev().zip(BitIterator::<u8, _>::new(lhs)) {
|
||||
*a = b;
|
||||
}
|
||||
tmp
|
||||
@@ -28,7 +29,7 @@ pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr {
|
||||
|
||||
let rhs = {
|
||||
let mut tmp = [false; 256];
|
||||
for (a, b) in tmp.iter_mut().rev().zip(BitIterator::new(rhs)) {
|
||||
for (a, b) in tmp.iter_mut().rev().zip(BitIterator::<u8, _>::new(rhs)) {
|
||||
*a = b;
|
||||
}
|
||||
tmp
|
||||
@@ -37,14 +38,14 @@ pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr {
|
||||
pedersen_hash::<Bls12, _>(
|
||||
Personalization::MerkleTree(depth),
|
||||
lhs.iter()
|
||||
.map(|&x| x)
|
||||
.copied()
|
||||
.take(Fr::NUM_BITS as usize)
|
||||
.chain(rhs.iter().map(|&x| x).take(Fr::NUM_BITS as usize)),
|
||||
.chain(rhs.iter().copied().take(Fr::NUM_BITS as usize)),
|
||||
&JUBJUB,
|
||||
)
|
||||
.into_xy()
|
||||
.to_xy()
|
||||
.0
|
||||
.into_repr()
|
||||
.to_repr()
|
||||
}
|
||||
|
||||
/// A node within the Sapling commitment tree.
|
||||
@@ -61,13 +62,13 @@ impl Node {
|
||||
|
||||
impl Hashable for Node {
|
||||
fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||
let mut repr = FrRepr::default();
|
||||
repr.read_le(&mut reader)?;
|
||||
let mut repr = FrRepr([0; 32]);
|
||||
reader.read_exact(&mut repr.0)?;
|
||||
Ok(Node::new(repr))
|
||||
}
|
||||
|
||||
fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||
self.repr.write_le(&mut writer)
|
||||
writer.write_all(self.repr.as_ref())
|
||||
}
|
||||
|
||||
fn combine(depth: usize, lhs: &Self, rhs: &Self) -> Self {
|
||||
@@ -78,7 +79,7 @@ impl Hashable for Node {
|
||||
|
||||
fn blank() -> Self {
|
||||
Node {
|
||||
repr: Note::<Bls12>::uncommitted().into_repr(),
|
||||
repr: Note::<Bls12>::uncommitted().to_repr(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -70,7 +70,7 @@ impl Vector {
|
||||
F: Fn(&mut R) -> io::Result<E>,
|
||||
{
|
||||
let count = CompactSize::read(&mut reader)?;
|
||||
(0..count).into_iter().map(|_| func(&mut reader)).collect()
|
||||
(0..count).map(|_| func(&mut reader)).collect()
|
||||
}
|
||||
|
||||
pub fn write<W: Write, E, F>(mut writer: W, vec: &[E], func: F) -> io::Result<()>
|
||||
|
@@ -1 +1,2 @@
|
||||
pub(crate) mod note_encryption;
|
||||
pub(crate) mod pedersen_hash_vectors;
|
||||
|
715
zcash_primitives/src/test_vectors/pedersen_hash_vectors.rs
Normal file
715
zcash_primitives/src/test_vectors/pedersen_hash_vectors.rs
Normal file
@@ -0,0 +1,715 @@
|
||||
//! Test vectors from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_pedersen.py
|
||||
|
||||
use crate::pedersen_hash::{test::TestVector, Personalization};
|
||||
|
||||
pub fn get_vectors<'a>() -> Vec<TestVector<'a>> {
|
||||
return vec![
|
||||
TestVector {
|
||||
personalization: Personalization::NoteCommitment,
|
||||
input_bits: vec![1, 1, 1, 1, 1, 1],
|
||||
hash_x: "Fr(0x06b1187c11ca4fb4383b2e0d0dbbde3ad3617338b5029187ec65a5eaed5e4d0b)",
|
||||
hash_y: "Fr(0x3ce70f536652f0dea496393a1e55c4e08b9d55508e16d11e5db40d4810cbc982)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::NoteCommitment,
|
||||
input_bits: vec![1, 1, 1, 1, 1, 1, 0],
|
||||
hash_x: "Fr(0x2fc3bc454c337f71d4f04f86304262fcbfc9ecd808716b92fc42cbe6827f7f1a)",
|
||||
hash_y: "Fr(0x46d0d25bf1a654eedc6a9b1e5af398925113959feac31b7a2c036ff9b9ec0638)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::NoteCommitment,
|
||||
input_bits: vec![1, 1, 1, 1, 1, 1, 1],
|
||||
hash_x: "Fr(0x4f8ce0e0a9e674b3ab9606a7d7aefba386e81583d81918127814cde41d209d97)",
|
||||
hash_y: "Fr(0x312b5ab93b14c9b9af334fe1fe3c50fffb53fbd074fa40ca600febde7c97e346)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::NoteCommitment,
|
||||
input_bits: vec![1, 1, 1, 1, 1, 1, 1, 0, 0],
|
||||
hash_x: "Fr(0x4f8ce0e0a9e674b3ab9606a7d7aefba386e81583d81918127814cde41d209d97)",
|
||||
hash_y: "Fr(0x312b5ab93b14c9b9af334fe1fe3c50fffb53fbd074fa40ca600febde7c97e346)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::NoteCommitment,
|
||||
input_bits: vec![
|
||||
1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1,
|
||||
0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1,
|
||||
1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0,
|
||||
1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1,
|
||||
0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
],
|
||||
hash_x: "Fr(0x599ab788360ae8c6d5bb7618aec37056d6227408d857fdc394078a3d7afdfe0f)",
|
||||
hash_y: "Fr(0x4320c373da670e28d168f4ffd72b43208e8c815f40841682c57a3ee1d005a527)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::NoteCommitment,
|
||||
input_bits: vec![
|
||||
1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0,
|
||||
1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1,
|
||||
1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
|
||||
0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0,
|
||||
],
|
||||
hash_x: "Fr(0x2da510317620f5dfdce1f31db6019f947eedcf02ff2972cff597a5c3ad21f5dd)",
|
||||
hash_y: "Fr(0x198789969c0c33e6c359b9da4a51771f4d50863f36beef90436944fe568399f2)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::NoteCommitment,
|
||||
input_bits: vec![
|
||||
1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
|
||||
1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0,
|
||||
0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1,
|
||||
],
|
||||
hash_x: "Fr(0x601247c7e640992d193dfb51df6ed93446687a7f2bcd0e4a598e6feb1ef20c40)",
|
||||
hash_y: "Fr(0x371931733b73e7b95c2cad55a6cebd15c83619f697c64283e54e5ef61442a743)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::NoteCommitment,
|
||||
input_bits: vec![
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0,
|
||||
0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
|
||||
1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1,
|
||||
0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0,
|
||||
1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
|
||||
1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1,
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1,
|
||||
1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0,
|
||||
1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0,
|
||||
1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1,
|
||||
1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0,
|
||||
0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1,
|
||||
0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1,
|
||||
0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1,
|
||||
1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0,
|
||||
1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1,
|
||||
1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
|
||||
],
|
||||
hash_x: "Fr(0x314192ecb1f2d8806a8108704c875a25d9fb7e444f9f373919adedebe8f2ae27)",
|
||||
hash_y: "Fr(0x6b12b32f1372ad574799dee9eb591d961b704bf611f55fcc71f7e82cd3330b74)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::NoteCommitment,
|
||||
input_bits: vec![
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0,
|
||||
0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0,
|
||||
1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1,
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0,
|
||||
0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0,
|
||||
1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1,
|
||||
1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0,
|
||||
1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0,
|
||||
1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1,
|
||||
1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0,
|
||||
1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1,
|
||||
0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0,
|
||||
0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0,
|
||||
0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1,
|
||||
0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1,
|
||||
0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1,
|
||||
0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0,
|
||||
1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1,
|
||||
1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1,
|
||||
0,
|
||||
],
|
||||
hash_x: "Fr(0x0666c2bce7f362a2b807d212e9a577f116891a932affd7addec39fbf372c494e)",
|
||||
hash_y: "Fr(0x6758bccfaf2e47c07756b96edea23aa8d10c33b38220bd1c411af612eeec18ab)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::NoteCommitment,
|
||||
input_bits: vec![
|
||||
1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1,
|
||||
1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1,
|
||||
0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1,
|
||||
0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0,
|
||||
1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0,
|
||||
1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
|
||||
1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
|
||||
0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1,
|
||||
0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0,
|
||||
0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0,
|
||||
1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1,
|
||||
0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1,
|
||||
0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1,
|
||||
1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
|
||||
1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,
|
||||
1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1,
|
||||
1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0,
|
||||
1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0,
|
||||
1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1,
|
||||
],
|
||||
hash_x: "Fr(0x130afe02b99375484efb0998f5331d2178e1d00e803049bb0769099420624f5f)",
|
||||
hash_y: "Fr(0x5e2fc6970554ffe358652aa7968ac4fcf3de0c830e6ea492e01a38fafb68cd71)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::NoteCommitment,
|
||||
input_bits: vec![
|
||||
1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0,
|
||||
1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1,
|
||||
0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0,
|
||||
0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0,
|
||||
1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1,
|
||||
0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0,
|
||||
1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1,
|
||||
1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0,
|
||||
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1,
|
||||
1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0,
|
||||
0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1,
|
||||
1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0,
|
||||
1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||
1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1,
|
||||
1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0,
|
||||
1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0,
|
||||
1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0,
|
||||
1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0,
|
||||
1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1,
|
||||
1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
|
||||
1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0,
|
||||
0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1,
|
||||
1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1,
|
||||
],
|
||||
hash_x: "Fr(0x67914ebd539961b70f468fa23d4cb42133693a8ac57cd35a1e6369fe34fbedf7)",
|
||||
hash_y: "Fr(0x44770870c0f0cfe59a10df95d6c21e6f1514a2f464b66377599438c126052d9f)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(0),
|
||||
input_bits: vec![0, 0, 0, 0, 0, 0],
|
||||
hash_x: "Fr(0x62454a957289b3930d10f3def0d512cfe0ef3de06421321221af3558de9d481d)",
|
||||
hash_y: "Fr(0x0279f0aebfb66e53ff69fba16b6608dbf4319b944432f45c6e69a3dbd1f7b330)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(0),
|
||||
input_bits: vec![0, 0, 0, 0, 0, 0, 0],
|
||||
hash_x: "Fr(0x283c7880f35179e201161402d9c4556b255917dbbf0142ae60519787d36d4dea)",
|
||||
hash_y: "Fr(0x648224408b4b83297cd0feb4cdc4eeb224237734931145432793bcd414228dc4)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(0),
|
||||
input_bits: vec![0, 0, 0, 0, 0, 0, 1],
|
||||
hash_x: "Fr(0x1f1086b287636a20063c9614db2de66bb7d49242e88060956a5e5845057f6f5d)",
|
||||
hash_y: "Fr(0x6b1b395421dde74d53341caa9e01f39d7a3138efb9b57fc0381f98f4868df622)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(0),
|
||||
input_bits: vec![0, 0, 0, 0, 0, 0, 1, 0, 0],
|
||||
hash_x: "Fr(0x1f1086b287636a20063c9614db2de66bb7d49242e88060956a5e5845057f6f5d)",
|
||||
hash_y: "Fr(0x6b1b395421dde74d53341caa9e01f39d7a3138efb9b57fc0381f98f4868df622)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(0),
|
||||
input_bits: vec![
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1,
|
||||
0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1,
|
||||
1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0,
|
||||
1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1,
|
||||
1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0,
|
||||
],
|
||||
hash_x: "Fr(0x20d2b1b0551efe511755d564f8da4f5bf285fd6051331fa5f129ad95b318f6cd)",
|
||||
hash_y: "Fr(0x2834d96950de67ae80e85545f8333c6e14b5cf5be7325dac768f401e6edd9544)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(0),
|
||||
input_bits: vec![
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1,
|
||||
1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0,
|
||||
0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1,
|
||||
1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0,
|
||||
0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0,
|
||||
],
|
||||
hash_x: "Fr(0x01f4850a0f40e07186fee1f0a276f52fb12cffe05c18eb2aa18170330a93c555)",
|
||||
hash_y: "Fr(0x19b0807358e7c8cba9168815ec54c4cd76997c34c592607d172151c48d5377cb)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(0),
|
||||
input_bits: vec![
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
|
||||
0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1,
|
||||
0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0,
|
||||
0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1,
|
||||
0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0,
|
||||
],
|
||||
hash_x: "Fr(0x26dd81a3ffa37452c6a932d41eb4f2e0fedd531e9af8c2a7935b91dff653879d)",
|
||||
hash_y: "Fr(0x2fc7aebb729ef5cabf0fb3f883bc2eb2603093850b0ec19c1a3c08b653e7f27f)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(0),
|
||||
input_bits: vec![
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1,
|
||||
0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0,
|
||||
1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1,
|
||||
1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,
|
||||
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0,
|
||||
0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1,
|
||||
0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1,
|
||||
0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1,
|
||||
0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0,
|
||||
0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1,
|
||||
0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0,
|
||||
0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0,
|
||||
1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1,
|
||||
0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1,
|
||||
0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1,
|
||||
1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
|
||||
],
|
||||
hash_x: "Fr(0x1111740552773b00aa6a2334575aa94102cfbd084290a430c90eb56d6db65b85)",
|
||||
hash_y: "Fr(0x6560c44b11683c20030626f89456f78a53ae8a89f565956a98ffc554b48fbb1a)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(0),
|
||||
input_bits: vec![
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1,
|
||||
1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1,
|
||||
0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0,
|
||||
0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1,
|
||||
1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1,
|
||||
1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0,
|
||||
1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1,
|
||||
0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0,
|
||||
0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
|
||||
1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1,
|
||||
0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1,
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0,
|
||||
1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1,
|
||||
1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0,
|
||||
1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1,
|
||||
1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1,
|
||||
1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0,
|
||||
0,
|
||||
],
|
||||
hash_x: "Fr(0x429349ea9b5f8163bcda3014b3e15554df5173353fd73f315a49360c97265f68)",
|
||||
hash_y: "Fr(0x188774bb6de41eba669be5d368942783f937acf2f418385fc5c78479b0a405ee)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(0),
|
||||
input_bits: vec![
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0,
|
||||
0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1,
|
||||
0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1,
|
||||
1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1,
|
||||
1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1,
|
||||
0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0,
|
||||
1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0,
|
||||
1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0,
|
||||
1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1,
|
||||
0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1,
|
||||
0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||
1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1,
|
||||
1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1,
|
||||
0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1,
|
||||
0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1,
|
||||
0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1,
|
||||
0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1,
|
||||
0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1,
|
||||
0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0,
|
||||
0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0,
|
||||
],
|
||||
hash_x: "Fr(0x00e827f3ed136f3c91c61c97ab9b7cca0ea53c20e47abb5e226ede297bdd5f37)",
|
||||
hash_y: "Fr(0x315cc00a54972df6a19f650d3fab5f2ad0fb07397bacb6944568618f2aa76bf6)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(0),
|
||||
input_bits: vec![
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1,
|
||||
1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0,
|
||||
0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1,
|
||||
1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1,
|
||||
0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1,
|
||||
0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0,
|
||||
1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
|
||||
0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0,
|
||||
1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1,
|
||||
0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0,
|
||||
0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1,
|
||||
1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0,
|
||||
0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1,
|
||||
0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0,
|
||||
1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1,
|
||||
1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0,
|
||||
],
|
||||
hash_x: "Fr(0x3ee50557c4aa9158c4bb9d5961208e6c62f55c73ad7c7695a0eba0bcb6d83d05)",
|
||||
hash_y: "Fr(0x1b1a2be6e47688828aeadf2d37db298eac0c2736c2722b227871fdeeee29de33)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(34),
|
||||
input_bits: vec![0, 1, 0, 0, 0, 1],
|
||||
hash_x: "Fr(0x61f8e2cb8e945631677b450d5e5669bc6b5f2ec69b321ac550dbe74525d7ac9a)",
|
||||
hash_y: "Fr(0x4e11951ab9c9400ee38a18bd98cdb9453f1f67141ee9d9bf0c1c157d4fb34f9a)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(34),
|
||||
input_bits: vec![0, 1, 0, 0, 0, 1, 0],
|
||||
hash_x: "Fr(0x27fa1e296c37dde8448483ce5485c2604d1d830e53812246299773a02ecd519c)",
|
||||
hash_y: "Fr(0x08e499113675202cb42b4b681a31430814edebd72c5bb3bc3bfedf91fb0605df)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(34),
|
||||
input_bits: vec![0, 1, 0, 0, 0, 1, 1],
|
||||
hash_x: "Fr(0x52112dd7a4293d049bb011683244a0f957e6ba95e1d1cf2fb6654d449a6d3fbc)",
|
||||
hash_y: "Fr(0x2ae14ecd81bb5b4489d2d64b5d2eb92a684087b28dd9a4950ecdb78c014e178c)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(34),
|
||||
input_bits: vec![0, 1, 0, 0, 0, 1, 1, 0, 0],
|
||||
hash_x: "Fr(0x52112dd7a4293d049bb011683244a0f957e6ba95e1d1cf2fb6654d449a6d3fbc)",
|
||||
hash_y: "Fr(0x2ae14ecd81bb5b4489d2d64b5d2eb92a684087b28dd9a4950ecdb78c014e178c)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(34),
|
||||
input_bits: vec![
|
||||
0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0,
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1,
|
||||
1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0,
|
||||
1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0,
|
||||
0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0,
|
||||
],
|
||||
hash_x: "Fr(0x544a0b44c35dca64ee806d1af70b7c44134e5d86efed413947657ffd71adf9b2)",
|
||||
hash_y: "Fr(0x5ddc5dbf12abbbc5561defd3782a32f450b3c398f52ff4629677e59e86e3ab31)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(34),
|
||||
input_bits: vec![
|
||||
0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1,
|
||||
0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||
0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0,
|
||||
1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1,
|
||||
1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1,
|
||||
],
|
||||
hash_x: "Fr(0x6cb6490ccb0ca9ccd657146f58a7b800bc4fb2556ee37861227ee8fda724acfb)",
|
||||
hash_y: "Fr(0x05c6fe100926f5cc441e54e72f024b6b12c907f2ec5680335057896411984c9f)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(34),
|
||||
input_bits: vec![
|
||||
0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1,
|
||||
0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1,
|
||||
1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1,
|
||||
0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0,
|
||||
],
|
||||
hash_x: "Fr(0x40901e2175cb7f06a00c676d54d90e59fd448f11cbbc5eb517f9fea74b795ce2)",
|
||||
hash_y: "Fr(0x42d512891f91087310c9bc630c8d0ecc014596f884fd6df55dada8195ed726de)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(34),
|
||||
input_bits: vec![
|
||||
0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0,
|
||||
0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1,
|
||||
1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
|
||||
0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0,
|
||||
0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1,
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1,
|
||||
1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0,
|
||||
1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1,
|
||||
0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0,
|
||||
1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0,
|
||||
1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1,
|
||||
1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0,
|
||||
1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0,
|
||||
1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0,
|
||||
1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1,
|
||||
0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1,
|
||||
],
|
||||
hash_x: "Fr(0x66a433542419f1a086ed0663b0e8df2ece9a04065f147896976baba1a916b6dc)",
|
||||
hash_y: "Fr(0x203bd3672522e1d3c86fa6b9f3b58f20199a4216adfd40982add13a856f6f3de)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(34),
|
||||
input_bits: vec![
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1,
|
||||
1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1,
|
||||
1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1,
|
||||
1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0,
|
||||
1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1,
|
||||
0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0,
|
||||
1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1,
|
||||
1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1,
|
||||
1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1,
|
||||
0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0,
|
||||
0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0,
|
||||
1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1,
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1,
|
||||
1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1,
|
||||
0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0,
|
||||
1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1,
|
||||
0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0,
|
||||
0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1,
|
||||
1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
|
||||
1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0,
|
||||
1,
|
||||
],
|
||||
hash_x: "Fr(0x119db3b38086c1a3c6c6f53c529ee62d9311d69c2d8aeeafa6e172e650d3afda)",
|
||||
hash_y: "Fr(0x72287540be7d2b0f58f5c73eaa53c55bea6b79dd79873b4e47cc11787bb9a15d)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(34),
|
||||
input_bits: vec![
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1,
|
||||
1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1,
|
||||
1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0,
|
||||
0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0,
|
||||
1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0,
|
||||
0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
|
||||
1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0,
|
||||
1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0,
|
||||
1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0,
|
||||
1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0,
|
||||
1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1,
|
||||
1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0,
|
||||
0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1,
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1,
|
||||
0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0,
|
||||
1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||
0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1,
|
||||
1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0,
|
||||
1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0,
|
||||
0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1,
|
||||
1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,
|
||||
0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1,
|
||||
1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0,
|
||||
],
|
||||
hash_x: "Fr(0x446efdcf89b70ba2b03427a0893008181d0fc4e76b84b1a500d7ee523c8e3666)",
|
||||
hash_y: "Fr(0x125ee0048efb0372b92c3c15d51a7c5c77a712054cc4fdd0774563da46ec7289)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(34),
|
||||
input_bits: vec![
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1,
|
||||
0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0,
|
||||
1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0,
|
||||
1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0,
|
||||
0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0,
|
||||
0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0,
|
||||
1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0,
|
||||
0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0,
|
||||
0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1,
|
||||
1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1,
|
||||
0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0,
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0,
|
||||
0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1,
|
||||
1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1,
|
||||
1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1,
|
||||
1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0,
|
||||
0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0,
|
||||
1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1,
|
||||
1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1,
|
||||
1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1,
|
||||
0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1,
|
||||
0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
|
||||
1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0,
|
||||
0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1,
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1,
|
||||
1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1,
|
||||
],
|
||||
hash_x: "Fr(0x72723bf0573bcb4b72d4184cfeb707d9556b7f705f56a4652707a36f2edf10f7)",
|
||||
hash_y: "Fr(0x3a7f0999a6a1393bd49fc82302e7352e01176fbebb0192bf5e6ef39eb8c585ad)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(27),
|
||||
input_bits: vec![
|
||||
1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,
|
||||
1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
|
||||
0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0,
|
||||
1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1,
|
||||
1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1,
|
||||
0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0,
|
||||
1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0,
|
||||
],
|
||||
hash_x: "Fr(0x414f6ba05f6b92da1f9051950769e1083d05615def32b016ae424309828a11f4)",
|
||||
hash_y: "Fr(0x471d2109656afcb96d0609b371b132b97efcf72c6051064dd19fdc004799bfa9)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(36),
|
||||
input_bits: vec![
|
||||
0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
|
||||
],
|
||||
hash_x: "Fr(0x62d6fe1e373225a5695f3115aed8265c59e2d6275ceef6bbc53fde3fc6594024)",
|
||||
hash_y: "Fr(0x407275be7d5a4c48204c8d83f5b211d09a2f285d4f0f87a928d4de9a6338e1d1)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::MerkleTree(0),
|
||||
input_bits: vec![
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
],
|
||||
hash_x: "Fr(0x1116a934f26b57a2c9daa6f25ac9b1a8f9dacddba30f65433ac021bf39a6bfdd)",
|
||||
hash_y: "Fr(0x407275be7d5a4c48204c8d83f5b211d09a2f285d4f0f87a928d4de9a6338e1d1)",
|
||||
},
|
||||
TestVector {
|
||||
personalization: Personalization::NoteCommitment,
|
||||
input_bits: vec![
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
],
|
||||
hash_x: "Fr(0x329e3bb2ca31ea6e13a986730237f6fd16b842a510cbabe851bdbcf57d75ee0d)",
|
||||
hash_y: "Fr(0x471d2109656afcb96d0609b371b132b97efcf72c6051064dd19fdc004799bfa9)",
|
||||
},
|
||||
];
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
//! Structs for building transactions.
|
||||
|
||||
use crate::zip32::ExtendedSpendingKey;
|
||||
use crate::{
|
||||
jubjub::fs::Fs,
|
||||
primitives::{Diversifier, Note, PaymentAddress},
|
||||
@@ -7,14 +8,12 @@ use crate::{
|
||||
use ff::Field;
|
||||
use pairing::bls12_381::{Bls12, Fr};
|
||||
use rand::{rngs::OsRng, seq::SliceRandom, CryptoRng, RngCore};
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use zip32::ExtendedSpendingKey;
|
||||
|
||||
use crate::{
|
||||
consensus,
|
||||
keys::OutgoingViewingKey,
|
||||
legacy::TransparentAddress,
|
||||
merkle_tree::{CommitmentTreeWitness, IncrementalWitness},
|
||||
merkle_tree::MerklePath,
|
||||
note_encryption::{generate_esk, Memo, SaplingNoteEncryption},
|
||||
prover::TxProver,
|
||||
redjubjub::PrivateKey,
|
||||
@@ -45,38 +44,16 @@ pub enum Error {
|
||||
ChangeIsNegative(Amount),
|
||||
InvalidAddress,
|
||||
InvalidAmount,
|
||||
InvalidWitness,
|
||||
NoChangeAddress,
|
||||
SpendProof,
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::AnchorMismatch => {
|
||||
write!(f, "Anchor mismatch (anchors for all spends must be equal)")
|
||||
}
|
||||
Error::BindingSig => write!(f, "Failed to create bindingSig"),
|
||||
Error::ChangeIsNegative(amount) => {
|
||||
write!(f, "Change is negative ({:?} zatoshis)", amount)
|
||||
}
|
||||
Error::InvalidAddress => write!(f, "Invalid address"),
|
||||
Error::InvalidAmount => write!(f, "Invalid amount"),
|
||||
Error::InvalidWitness => write!(f, "Invalid note witness"),
|
||||
Error::NoChangeAddress => write!(f, "No change address specified or discoverable"),
|
||||
Error::SpendProof => write!(f, "Failed to create Sapling spend proof"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {}
|
||||
|
||||
struct SpendDescriptionInfo {
|
||||
extsk: ExtendedSpendingKey,
|
||||
diversifier: Diversifier,
|
||||
note: Note<Bls12>,
|
||||
alpha: Fs,
|
||||
witness: CommitmentTreeWitness<Node>,
|
||||
merkle_path: MerklePath<Node>,
|
||||
}
|
||||
|
||||
pub struct SaplingOutput {
|
||||
@@ -106,7 +83,7 @@ impl SaplingOutput {
|
||||
|
||||
let note = Note {
|
||||
g_d,
|
||||
pk_d: to.pk_d.clone(),
|
||||
pk_d: to.pk_d().clone(),
|
||||
value: value.into(),
|
||||
r: rcm,
|
||||
};
|
||||
@@ -187,7 +164,38 @@ impl Default for TransparentInputs {
|
||||
struct TransparentInputs;
|
||||
|
||||
impl TransparentInputs {
|
||||
fn input_sum(&self) -> Amount {
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
fn push(
|
||||
&mut self,
|
||||
mtx: &mut TransactionData,
|
||||
sk: secp256k1::SecretKey,
|
||||
utxo: OutPoint,
|
||||
coin: TxOut,
|
||||
) -> Result<(), Error> {
|
||||
if coin.value.is_negative() {
|
||||
return Err(Error::InvalidAmount);
|
||||
}
|
||||
|
||||
let pubkey = secp256k1::PublicKey::from_secret_key(&self.secp, &sk).serialize();
|
||||
match coin.script_pubkey.address() {
|
||||
Some(TransparentAddress::PublicKey(hash)) => {
|
||||
use ripemd160::Ripemd160;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
if &hash[..] != &Ripemd160::digest(&Sha256::digest(&pubkey))[..] {
|
||||
return Err(Error::InvalidAddress);
|
||||
}
|
||||
}
|
||||
_ => return Err(Error::InvalidAddress),
|
||||
}
|
||||
|
||||
mtx.vin.push(TxIn::new(utxo));
|
||||
self.inputs.push(TransparentInputInfo { sk, pubkey, coin });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn value_sum(&self) -> Amount {
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
{
|
||||
self.inputs
|
||||
@@ -201,6 +209,36 @@ impl TransparentInputs {
|
||||
Amount::zero()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
fn apply_signatures(
|
||||
&self,
|
||||
mtx: &mut TransactionData,
|
||||
consensus_branch_id: consensus::BranchId,
|
||||
) {
|
||||
let mut sighash = [0u8; 32];
|
||||
for (i, info) in self.inputs.iter().enumerate() {
|
||||
sighash.copy_from_slice(&signature_hash_data(
|
||||
mtx,
|
||||
consensus_branch_id,
|
||||
SIGHASH_ALL,
|
||||
Some((i, &info.coin.script_pubkey, info.coin.value)),
|
||||
));
|
||||
|
||||
let msg = secp256k1::Message::from_slice(&sighash).expect("32 bytes");
|
||||
let sig = self.secp.sign(&msg, &info.sk);
|
||||
|
||||
// Signature has to have "SIGHASH_ALL" appended to it
|
||||
let mut sig_bytes: Vec<u8> = sig.serialize_der()[..].to_vec();
|
||||
sig_bytes.extend(&[SIGHASH_ALL as u8]);
|
||||
|
||||
// P2PKH scriptSig
|
||||
mtx.vin[i].script_sig = Script::default() << &sig_bytes[..] << &info.pubkey[..];
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "transparent-inputs"))]
|
||||
fn apply_signatures(&self, _: &mut TransactionData, _: consensus::BranchId) {}
|
||||
}
|
||||
|
||||
/// Metadata about a transaction created by a [`Builder`].
|
||||
@@ -226,7 +264,7 @@ impl TransactionMetadata {
|
||||
/// they added (via the first call to [`Builder::add_sapling_spend`]) is the first
|
||||
/// [`SpendDescription`] in the transaction.
|
||||
pub fn spend_index(&self, n: usize) -> Option<usize> {
|
||||
self.spend_indices.get(n).map(|i| *i)
|
||||
self.spend_indices.get(n).copied()
|
||||
}
|
||||
|
||||
/// Returns the index within the transaction of the [`OutputDescription`] corresponding
|
||||
@@ -237,7 +275,7 @@ impl TransactionMetadata {
|
||||
/// they added (via the first call to [`Builder::add_sapling_output`]) is the first
|
||||
/// [`OutputDescription`] in the transaction.
|
||||
pub fn output_index(&self, n: usize) -> Option<usize> {
|
||||
self.output_indices.get(n).map(|i| *i)
|
||||
self.output_indices.get(n).copied()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +287,7 @@ pub struct Builder<R: RngCore + CryptoRng> {
|
||||
anchor: Option<Fr>,
|
||||
spends: Vec<SpendDescriptionInfo>,
|
||||
outputs: Vec<SaplingOutput>,
|
||||
legacy: TransparentInputs,
|
||||
transparent_inputs: TransparentInputs,
|
||||
change_address: Option<(OutgoingViewingKey, PaymentAddress<Bls12>)>,
|
||||
}
|
||||
|
||||
@@ -289,32 +327,32 @@ impl<R: RngCore + CryptoRng> Builder<R> {
|
||||
anchor: None,
|
||||
spends: vec![],
|
||||
outputs: vec![],
|
||||
legacy: TransparentInputs::default(),
|
||||
transparent_inputs: TransparentInputs::default(),
|
||||
change_address: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds a Sapling note to be spent in this transaction.
|
||||
///
|
||||
/// Returns an error if the given witness does not have the same anchor as previous
|
||||
/// witnesses, or has no path.
|
||||
/// Returns an error if the given Merkle path does not have the same anchor as the
|
||||
/// paths for previous Sapling notes.
|
||||
pub fn add_sapling_spend(
|
||||
&mut self,
|
||||
extsk: ExtendedSpendingKey,
|
||||
diversifier: Diversifier,
|
||||
note: Note<Bls12>,
|
||||
witness: IncrementalWitness<Node>,
|
||||
merkle_path: MerklePath<Node>,
|
||||
) -> Result<(), Error> {
|
||||
// Consistency check: all anchors must equal the first one
|
||||
let cm = Node::new(note.cm(&JUBJUB).into());
|
||||
if let Some(anchor) = self.anchor {
|
||||
let witness_root: Fr = witness.root().into();
|
||||
if witness_root != anchor {
|
||||
let path_root: Fr = merkle_path.root(cm).into();
|
||||
if path_root != anchor {
|
||||
return Err(Error::AnchorMismatch);
|
||||
}
|
||||
} else {
|
||||
self.anchor = Some(witness.root().into())
|
||||
self.anchor = Some(merkle_path.root(cm).into())
|
||||
}
|
||||
let witness = witness.path().ok_or(Error::InvalidWitness)?;
|
||||
|
||||
let alpha = Fs::random(&mut self.rng);
|
||||
|
||||
@@ -325,7 +363,7 @@ impl<R: RngCore + CryptoRng> Builder<R> {
|
||||
diversifier,
|
||||
note,
|
||||
alpha,
|
||||
witness,
|
||||
merkle_path,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
@@ -356,29 +394,7 @@ impl<R: RngCore + CryptoRng> Builder<R> {
|
||||
utxo: OutPoint,
|
||||
coin: TxOut,
|
||||
) -> Result<(), Error> {
|
||||
if coin.value.is_negative() {
|
||||
return Err(Error::InvalidAmount);
|
||||
}
|
||||
|
||||
let pubkey = secp256k1::PublicKey::from_secret_key(&self.legacy.secp, &sk).serialize();
|
||||
match coin.script_pubkey.address() {
|
||||
Some(TransparentAddress::PublicKey(hash)) => {
|
||||
use ripemd160::Ripemd160;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
if &hash[..] != &Ripemd160::digest(&Sha256::digest(&pubkey))[..] {
|
||||
return Err(Error::InvalidAddress);
|
||||
}
|
||||
}
|
||||
_ => return Err(Error::InvalidAddress),
|
||||
}
|
||||
|
||||
self.mtx.vin.push(TxIn::new(utxo));
|
||||
self.legacy
|
||||
.inputs
|
||||
.push(TransparentInputInfo { sk, pubkey, coin });
|
||||
|
||||
Ok(())
|
||||
self.transparent_inputs.push(&mut self.mtx, sk, utxo, coin)
|
||||
}
|
||||
|
||||
/// Adds a transparent address to send funds to.
|
||||
@@ -418,8 +434,8 @@ impl<R: RngCore + CryptoRng> Builder<R> {
|
||||
/// the network.
|
||||
pub fn build(
|
||||
mut self,
|
||||
consensus_branch_id: u32,
|
||||
prover: impl TxProver,
|
||||
consensus_branch_id: consensus::BranchId,
|
||||
prover: &impl TxProver,
|
||||
) -> Result<(Transaction, TransactionMetadata), Error> {
|
||||
let mut tx_metadata = TransactionMetadata::new();
|
||||
|
||||
@@ -428,7 +444,7 @@ impl<R: RngCore + CryptoRng> Builder<R> {
|
||||
//
|
||||
|
||||
// Valid change
|
||||
let change = self.mtx.value_balance - self.fee + self.legacy.input_sum()
|
||||
let change = self.mtx.value_balance - self.fee + self.transparent_inputs.value_sum()
|
||||
- self
|
||||
.mtx
|
||||
.vout
|
||||
@@ -451,10 +467,11 @@ impl<R: RngCore + CryptoRng> Builder<R> {
|
||||
} else if !self.spends.is_empty() {
|
||||
(
|
||||
self.spends[0].extsk.expsk.ovk,
|
||||
PaymentAddress {
|
||||
diversifier: self.spends[0].diversifier,
|
||||
pk_d: self.spends[0].note.pk_d.clone(),
|
||||
},
|
||||
PaymentAddress::from_parts(
|
||||
self.spends[0].diversifier,
|
||||
self.spends[0].note.pk_d.clone(),
|
||||
)
|
||||
.ok_or(Error::InvalidAddress)?,
|
||||
)
|
||||
} else {
|
||||
return Err(Error::NoChangeAddress);
|
||||
@@ -498,16 +515,16 @@ impl<R: RngCore + CryptoRng> Builder<R> {
|
||||
let binding_sig_needed = !spends.is_empty() || !outputs.is_empty();
|
||||
|
||||
// Create Sapling SpendDescriptions
|
||||
if spends.len() > 0 {
|
||||
if !spends.is_empty() {
|
||||
let anchor = self.anchor.expect("anchor was set if spends were added");
|
||||
|
||||
|
||||
for (i, (pos, spend)) in spends.iter().enumerate() {
|
||||
let proof_generation_key = spend.extsk.expsk.proof_generation_key(&JUBJUB);
|
||||
|
||||
let mut nullifier = [0u8; 32];
|
||||
nullifier.copy_from_slice(&spend.note.nf(
|
||||
&proof_generation_key.into_viewing_key(&JUBJUB),
|
||||
spend.witness.position,
|
||||
&proof_generation_key.to_viewing_key(&JUBJUB),
|
||||
spend.merkle_path.position,
|
||||
&JUBJUB,
|
||||
));
|
||||
|
||||
@@ -520,13 +537,13 @@ impl<R: RngCore + CryptoRng> Builder<R> {
|
||||
spend.alpha,
|
||||
spend.note.value,
|
||||
anchor,
|
||||
spend.witness.clone(),
|
||||
spend.merkle_path.clone(),
|
||||
)
|
||||
.map_err(|()| Error::SpendProof)?;
|
||||
|
||||
self.mtx.shielded_spends.push(SpendDescription {
|
||||
cv,
|
||||
anchor: anchor,
|
||||
anchor,
|
||||
nullifier,
|
||||
rk,
|
||||
zkproof,
|
||||
@@ -544,7 +561,7 @@ impl<R: RngCore + CryptoRng> Builder<R> {
|
||||
// Record the post-randomized output location
|
||||
tx_metadata.output_indices[pos] = i;
|
||||
|
||||
output.build(&prover, &mut ctx, &mut self.rng)
|
||||
output.build(prover, &mut ctx, &mut self.rng)
|
||||
} else {
|
||||
// This is a dummy output
|
||||
let (dummy_to, dummy_note) = {
|
||||
@@ -563,16 +580,16 @@ impl<R: RngCore + CryptoRng> Builder<R> {
|
||||
(diversifier, g_d)
|
||||
};
|
||||
|
||||
let pk_d = {
|
||||
let (pk_d, payment_address) = loop {
|
||||
let dummy_ivk = Fs::random(&mut self.rng);
|
||||
g_d.mul(dummy_ivk, &JUBJUB)
|
||||
let pk_d = g_d.mul(dummy_ivk, &JUBJUB);
|
||||
if let Some(addr) = PaymentAddress::from_parts(diversifier, pk_d.clone()) {
|
||||
break (pk_d, addr);
|
||||
}
|
||||
};
|
||||
|
||||
(
|
||||
PaymentAddress {
|
||||
diversifier,
|
||||
pk_d: pk_d.clone(),
|
||||
},
|
||||
payment_address,
|
||||
Note {
|
||||
g_d,
|
||||
pk_d,
|
||||
@@ -643,28 +660,8 @@ impl<R: RngCore + CryptoRng> Builder<R> {
|
||||
}
|
||||
|
||||
// Transparent signatures
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
{
|
||||
for (i, info) in self.legacy.inputs.iter().enumerate() {
|
||||
sighash.copy_from_slice(&signature_hash_data(
|
||||
&self.mtx,
|
||||
consensus_branch_id,
|
||||
SIGHASH_ALL,
|
||||
Some((i, &info.coin.script_pubkey, info.coin.value)),
|
||||
));
|
||||
|
||||
let msg = secp256k1::Message::from_slice(&sighash).expect("32 bytes");
|
||||
let sig = self.legacy.secp.sign(&msg, &info.sk);
|
||||
|
||||
// Signature has to have "SIGHASH_ALL" appended to it
|
||||
let mut sig_bytes: Vec<u8> = sig.serialize_der()[..].to_vec();
|
||||
sig_bytes.extend(&[SIGHASH_ALL as u8]);
|
||||
|
||||
// P2PKH scriptSig
|
||||
self.mtx.vin[i].script_sig =
|
||||
Script::default() << &sig_bytes[..] << &info.pubkey[..];
|
||||
}
|
||||
}
|
||||
self.transparent_inputs
|
||||
.apply_signatures(&mut self.mtx, consensus_branch_id);
|
||||
|
||||
Ok((
|
||||
self.mtx.freeze().expect("Transaction should be complete"),
|
||||
@@ -676,12 +673,13 @@ impl<R: RngCore + CryptoRng> Builder<R> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ff::{Field, PrimeField};
|
||||
use rand::rngs::OsRng;
|
||||
use rand_core::OsRng;
|
||||
|
||||
use crate::jubjub::fs::Fs;
|
||||
|
||||
use super::{Builder, Error};
|
||||
use crate::{
|
||||
consensus,
|
||||
legacy::TransparentAddress,
|
||||
merkle_tree::{CommitmentTree, IncrementalWitness},
|
||||
prover::mock::MockTxProver,
|
||||
@@ -737,6 +735,77 @@ mod tests {
|
||||
assert!(tx.binding_sig.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn binding_sig_absent_if_no_shielded_spend_or_output() {
|
||||
use crate::transaction::{
|
||||
builder::{self, TransparentInputs},
|
||||
TransactionData,
|
||||
};
|
||||
|
||||
// Create a builder with 0 fee, so we can construct t outputs
|
||||
let mut builder = builder::Builder {
|
||||
rng: OsRng,
|
||||
mtx: TransactionData::new(),
|
||||
fee: Amount::zero(),
|
||||
anchor: None,
|
||||
spends: vec![],
|
||||
outputs: vec![],
|
||||
transparent_inputs: TransparentInputs::default(),
|
||||
change_address: None,
|
||||
};
|
||||
|
||||
// Create a tx with only t output. No binding_sig should be present
|
||||
builder
|
||||
.add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount::zero())
|
||||
.unwrap();
|
||||
|
||||
let (tx, _) = builder
|
||||
.build(consensus::BranchId::Sapling, &MockTxProver)
|
||||
.unwrap();
|
||||
// No binding signature, because only t input and outputs
|
||||
assert!(tx.binding_sig.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn binding_sig_present_if_shielded_spend() {
|
||||
let extsk = ExtendedSpendingKey::master(&[]);
|
||||
let extfvk = ExtendedFullViewingKey::from(&extsk);
|
||||
let to = extfvk.default_address().unwrap().1;
|
||||
|
||||
let mut rng = OsRng;
|
||||
|
||||
let note1 = to
|
||||
.create_note(50000, Fs::random(&mut rng), &JUBJUB)
|
||||
.unwrap();
|
||||
let cm1 = Node::new(note1.cm(&JUBJUB).to_repr());
|
||||
let mut tree = CommitmentTree::new();
|
||||
tree.append(cm1).unwrap();
|
||||
let witness1 = IncrementalWitness::from_tree(&tree);
|
||||
|
||||
let mut builder = Builder::new(0);
|
||||
|
||||
// Create a tx with a sapling spend. binding_sig should be present
|
||||
builder
|
||||
.add_sapling_spend(
|
||||
extsk.clone(),
|
||||
*to.diversifier(),
|
||||
note1.clone(),
|
||||
witness1.path().unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
builder
|
||||
.add_transparent_output(&TransparentAddress::PublicKey([0; 20]), Amount::zero())
|
||||
.unwrap();
|
||||
|
||||
// Expect a binding signature error, because our inputs aren't valid, but this shows
|
||||
// that a binding signature was attempted
|
||||
assert_eq!(
|
||||
builder.build(consensus::BranchId::Sapling, &MockTxProver),
|
||||
Err(Error::BindingSig)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fails_on_negative_transparent_output() {
|
||||
let mut builder = Builder::new(0);
|
||||
@@ -761,7 +830,7 @@ mod tests {
|
||||
{
|
||||
let builder = Builder::new(0);
|
||||
assert_eq!(
|
||||
builder.build(1, MockTxProver),
|
||||
builder.build(consensus::BranchId::Sapling, &MockTxProver),
|
||||
Err(Error::ChangeIsNegative(Amount::from_i64(-10000).unwrap()))
|
||||
);
|
||||
}
|
||||
@@ -783,7 +852,7 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
builder.build(1, MockTxProver),
|
||||
builder.build(consensus::BranchId::Sapling, &MockTxProver),
|
||||
Err(Error::ChangeIsNegative(Amount::from_i64(-60000).unwrap()))
|
||||
);
|
||||
}
|
||||
@@ -799,7 +868,7 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
builder.build(1, MockTxProver),
|
||||
builder.build(consensus::BranchId::Sapling, &MockTxProver),
|
||||
Err(Error::ChangeIsNegative(Amount::from_i64(-60000).unwrap()))
|
||||
);
|
||||
}
|
||||
@@ -807,7 +876,7 @@ mod tests {
|
||||
let note1 = to
|
||||
.create_note(59999, Fs::random(&mut rng), &JUBJUB)
|
||||
.unwrap();
|
||||
let cm1 = Node::new(note1.cm(&JUBJUB).into_repr());
|
||||
let cm1 = Node::new(note1.cm(&JUBJUB).to_repr());
|
||||
let mut tree = CommitmentTree::new();
|
||||
tree.append(cm1).unwrap();
|
||||
let mut witness1 = IncrementalWitness::from_tree(&tree);
|
||||
@@ -819,9 +888,9 @@ mod tests {
|
||||
builder
|
||||
.add_sapling_spend(
|
||||
extsk.clone(),
|
||||
to.diversifier,
|
||||
*to.diversifier(),
|
||||
note1.clone(),
|
||||
witness1.clone(),
|
||||
witness1.path().unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
builder
|
||||
@@ -839,13 +908,13 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
builder.build(1, MockTxProver),
|
||||
builder.build(consensus::BranchId::Sapling, &MockTxProver),
|
||||
Err(Error::ChangeIsNegative(Amount::from_i64(-1).unwrap()))
|
||||
);
|
||||
}
|
||||
|
||||
let note2 = to.create_note(1, Fs::random(&mut rng), &JUBJUB).unwrap();
|
||||
let cm2 = Node::new(note2.cm(&JUBJUB).into_repr());
|
||||
let cm2 = Node::new(note2.cm(&JUBJUB).to_repr());
|
||||
tree.append(cm2).unwrap();
|
||||
witness1.append(cm2).unwrap();
|
||||
let witness2 = IncrementalWitness::from_tree(&tree);
|
||||
@@ -858,10 +927,15 @@ mod tests {
|
||||
{
|
||||
let mut builder = Builder::new(0);
|
||||
builder
|
||||
.add_sapling_spend(extsk.clone(), to.diversifier, note1, witness1)
|
||||
.add_sapling_spend(
|
||||
extsk.clone(),
|
||||
*to.diversifier(),
|
||||
note1,
|
||||
witness1.path().unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
builder
|
||||
.add_sapling_spend(extsk, to.diversifier, note2, witness2)
|
||||
.add_sapling_spend(extsk, *to.diversifier(), note2, witness2.path().unwrap())
|
||||
.unwrap();
|
||||
builder
|
||||
.add_sapling_output(ovk, to, Amount::from_u64(30000).unwrap(), None)
|
||||
@@ -872,7 +946,10 @@ mod tests {
|
||||
Amount::from_u64(20000).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(builder.build(1, MockTxProver), Err(Error::BindingSig))
|
||||
assert_eq!(
|
||||
builder.build(consensus::BranchId::Sapling, &MockTxProver),
|
||||
Err(Error::BindingSig)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,12 +1,14 @@
|
||||
//! Structs representing the components within Zcash transactions.
|
||||
|
||||
use crate::jubjub::{edwards, Unknown};
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use ff::{PrimeField, PrimeFieldRepr};
|
||||
use ff::PrimeField;
|
||||
use pairing::bls12_381::{Bls12, Fr, FrRepr};
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use legacy::Script;
|
||||
use redjubjub::{PublicKey, Signature};
|
||||
use JUBJUB;
|
||||
use crate::legacy::Script;
|
||||
use crate::redjubjub::{PublicKey, Signature};
|
||||
use crate::JUBJUB;
|
||||
|
||||
pub mod amount;
|
||||
pub use self::amount::Amount;
|
||||
@@ -27,7 +29,7 @@ pub struct OutPoint {
|
||||
|
||||
impl OutPoint {
|
||||
pub fn new(hash: [u8; 32], n: u32) -> Self {
|
||||
OutPoint {hash, n}
|
||||
OutPoint { hash, n }
|
||||
}
|
||||
|
||||
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||
@@ -117,7 +119,7 @@ pub struct SpendDescription {
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for SpendDescription {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
write!(
|
||||
f,
|
||||
"SpendDescription(cv = {:?}, anchor = {:?}, nullifier = {:?}, rk = {:?}, spend_auth_sig = {:?})",
|
||||
@@ -136,9 +138,10 @@ impl SpendDescription {
|
||||
|
||||
// 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 f = FrRepr([0; 32]);
|
||||
reader.read_exact(&mut f.0)?;
|
||||
Fr::from_repr(f)
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "anchor not in field"))?
|
||||
};
|
||||
|
||||
let mut nullifier = [0; 32];
|
||||
@@ -173,18 +176,16 @@ impl SpendDescription {
|
||||
|
||||
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||
self.cv.write(&mut writer)?;
|
||||
self.anchor.into_repr().write_le(&mut writer)?;
|
||||
writer.write_all(self.anchor.to_repr().as_ref())?;
|
||||
writer.write_all(&self.nullifier)?;
|
||||
self.rk.write(&mut writer)?;
|
||||
writer.write_all(&self.zkproof)?;
|
||||
match self.spend_auth_sig {
|
||||
Some(sig) => sig.write(&mut writer),
|
||||
None => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Missing spend auth signature",
|
||||
));
|
||||
}
|
||||
None => Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Missing spend auth signature",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -199,7 +200,7 @@ pub struct OutputDescription {
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for OutputDescription {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
write!(
|
||||
f,
|
||||
"OutputDescription(cv = {:?}, cmu = {:?}, ephemeral_key = {:?})",
|
||||
@@ -218,9 +219,10 @@ impl OutputDescription {
|
||||
|
||||
// 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))?
|
||||
let mut f = FrRepr([0; 32]);
|
||||
reader.read_exact(&mut f.0)?;
|
||||
Fr::from_repr(f)
|
||||
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "cmu not in field"))?
|
||||
};
|
||||
|
||||
// Consensus rules (§4.5):
|
||||
@@ -252,7 +254,7 @@ impl OutputDescription {
|
||||
|
||||
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||
self.cv.write(&mut writer)?;
|
||||
self.cmu.into_repr().write_le(&mut writer)?;
|
||||
writer.write_all(self.cmu.to_repr().as_ref())?;
|
||||
self.ephemeral_key.write(&mut writer)?;
|
||||
writer.write_all(&self.enc_ciphertext)?;
|
||||
writer.write_all(&self.out_ciphertext)?;
|
||||
@@ -266,7 +268,7 @@ enum SproutProof {
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for SproutProof {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
match self {
|
||||
SproutProof::Groth(_) => write!(f, "SproutProof::Groth"),
|
||||
SproutProof::PHGR(_) => write!(f, "SproutProof::PHGR"),
|
||||
@@ -288,7 +290,7 @@ pub struct JSDescription {
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for JSDescription {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
write!(
|
||||
f,
|
||||
"JSDescription(
|
||||
@@ -360,23 +362,20 @@ impl JSDescription {
|
||||
.map(|mac| reader.read_exact(mac))
|
||||
.collect::<io::Result<()>>()?;
|
||||
|
||||
let proof = match use_groth {
|
||||
true => {
|
||||
// Consensus rules (§4.3):
|
||||
// - Canonical encoding is enforced in librustzcash_sprout_verify()
|
||||
// - Proof validity is enforced in librustzcash_sprout_verify()
|
||||
let mut proof = [0; GROTH_PROOF_SIZE];
|
||||
reader.read_exact(&mut proof)?;
|
||||
SproutProof::Groth(proof)
|
||||
}
|
||||
false => {
|
||||
// Consensus rules (§4.3):
|
||||
// - Canonical encoding is enforced by PHGRProof in zcashd
|
||||
// - Proof validity is enforced by JSDescription::Verify() in zcashd
|
||||
let mut proof = [0; PHGR_PROOF_SIZE];
|
||||
reader.read_exact(&mut proof)?;
|
||||
SproutProof::PHGR(proof)
|
||||
}
|
||||
let proof = if use_groth {
|
||||
// Consensus rules (§4.3):
|
||||
// - Canonical encoding is enforced in librustzcash_sprout_verify()
|
||||
// - Proof validity is enforced in librustzcash_sprout_verify()
|
||||
let mut proof = [0; GROTH_PROOF_SIZE];
|
||||
reader.read_exact(&mut proof)?;
|
||||
SproutProof::Groth(proof)
|
||||
} else {
|
||||
// Consensus rules (§4.3):
|
||||
// - Canonical encoding is enforced by PHGRProof in zcashd
|
||||
// - Proof validity is enforced by JSDescription::Verify() in zcashd
|
||||
let mut proof = [0; PHGR_PROOF_SIZE];
|
||||
reader.read_exact(&mut proof)?;
|
||||
SproutProof::PHGR(proof)
|
||||
};
|
||||
|
||||
let mut ciphertexts = [[0; 601]; ZC_NUM_JS_OUTPUTS];
|
||||
|
@@ -206,7 +206,7 @@ mod tests {
|
||||
#[should_panic]
|
||||
fn add_panics_on_overflow() {
|
||||
let v = Amount(MAX_MONEY);
|
||||
let sum = v + Amount(1);
|
||||
let _sum = v + Amount(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -220,7 +220,7 @@ mod tests {
|
||||
#[should_panic]
|
||||
fn sub_panics_on_underflow() {
|
||||
let v = Amount(-MAX_MONEY);
|
||||
let diff = v - Amount(1);
|
||||
let _diff = v - Amount(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@@ -1,3 +1,5 @@
|
||||
//! Structs and methods for handling Zcash transactions.
|
||||
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use hex;
|
||||
use sha2::{Digest, Sha256};
|
||||
@@ -5,8 +7,8 @@ use std::fmt;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::ops::Deref;
|
||||
|
||||
use redjubjub::Signature;
|
||||
use serialize::Vector;
|
||||
use crate::redjubjub::Signature;
|
||||
use crate::serialize::Vector;
|
||||
|
||||
pub mod builder;
|
||||
pub mod components;
|
||||
@@ -28,8 +30,8 @@ const SAPLING_TX_VERSION: u32 = 4;
|
||||
pub struct TxId(pub [u8; 32]);
|
||||
|
||||
impl fmt::Display for TxId {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut data = self.0.clone();
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut data = self.0;
|
||||
data.reverse();
|
||||
formatter.write_str(&hex::encode(data))
|
||||
}
|
||||
@@ -74,7 +76,7 @@ pub struct TransactionData {
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for TransactionData {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
write!(
|
||||
f,
|
||||
"TransactionData(
|
||||
@@ -164,9 +166,10 @@ impl Transaction {
|
||||
let overwintered = (header >> 31) == 1;
|
||||
let version = header & 0x7FFFFFFF;
|
||||
|
||||
let version_group_id = match overwintered {
|
||||
true => reader.read_u32::<LittleEndian>()?,
|
||||
false => 0,
|
||||
let version_group_id = if overwintered {
|
||||
reader.read_u32::<LittleEndian>()?
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let is_overwinter_v3 = overwintered
|
||||
@@ -185,9 +188,10 @@ impl Transaction {
|
||||
let vin = Vector::read(&mut reader, TxIn::read)?;
|
||||
let vout = Vector::read(&mut reader, TxOut::read)?;
|
||||
let lock_time = reader.read_u32::<LittleEndian>()?;
|
||||
let expiry_height = match is_overwinter_v3 || is_sapling_v4 {
|
||||
true => reader.read_u32::<LittleEndian>()?,
|
||||
false => 0,
|
||||
let expiry_height = if is_overwinter_v3 || is_sapling_v4 {
|
||||
reader.read_u32::<LittleEndian>()?
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let (value_balance, shielded_spends, shielded_outputs) = if is_sapling_v4 {
|
||||
@@ -223,9 +227,10 @@ impl Transaction {
|
||||
};
|
||||
|
||||
let binding_sig =
|
||||
match is_sapling_v4 && !(shielded_spends.is_empty() && shielded_outputs.is_empty()) {
|
||||
true => Some(Signature::read(&mut reader)?),
|
||||
false => None,
|
||||
if is_sapling_v4 && !(shielded_spends.is_empty() && shielded_outputs.is_empty()) {
|
||||
Some(Signature::read(&mut reader)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Transaction::from_data(TransactionData {
|
||||
|
@@ -1,21 +1,21 @@
|
||||
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
use ff::{PrimeField, PrimeFieldRepr};
|
||||
use ff::PrimeField;
|
||||
|
||||
use super::{
|
||||
components::{Amount, TxOut},
|
||||
Transaction, TransactionData, OVERWINTER_VERSION_GROUP_ID, SAPLING_TX_VERSION,
|
||||
SAPLING_VERSION_GROUP_ID,
|
||||
};
|
||||
use legacy::Script;
|
||||
use crate::{consensus, legacy::Script};
|
||||
|
||||
const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &'static [u8; 12] = b"ZcashSigHash";
|
||||
const ZCASH_PREVOUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashPrevoutHash";
|
||||
const ZCASH_SEQUENCE_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSequencHash";
|
||||
const ZCASH_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashOutputsHash";
|
||||
const ZCASH_JOINSPLITS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashJSplitsHash";
|
||||
const ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSSpendsHash";
|
||||
const ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSOutputHash";
|
||||
const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &[u8; 12] = b"ZcashSigHash";
|
||||
const ZCASH_PREVOUTS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashPrevoutHash";
|
||||
const ZCASH_SEQUENCE_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashSequencHash";
|
||||
const ZCASH_OUTPUTS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashOutputsHash";
|
||||
const ZCASH_JOINSPLITS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashJSplitsHash";
|
||||
const ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashSSpendsHash";
|
||||
const ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashSOutputHash";
|
||||
|
||||
pub const SIGHASH_ALL: u32 = 1;
|
||||
const SIGHASH_NONE: u32 = 2;
|
||||
@@ -128,7 +128,7 @@ fn shielded_spends_hash(tx: &TransactionData) -> Blake2bHash {
|
||||
let mut data = Vec::with_capacity(tx.shielded_spends.len() * 384);
|
||||
for s_spend in &tx.shielded_spends {
|
||||
s_spend.cv.write(&mut data).unwrap();
|
||||
s_spend.anchor.into_repr().write_le(&mut data).unwrap();
|
||||
data.extend_from_slice(s_spend.anchor.to_repr().as_ref());
|
||||
data.extend_from_slice(&s_spend.nullifier);
|
||||
s_spend.rk.write(&mut data).unwrap();
|
||||
data.extend_from_slice(&s_spend.zkproof);
|
||||
@@ -152,7 +152,7 @@ fn shielded_outputs_hash(tx: &TransactionData) -> Blake2bHash {
|
||||
|
||||
pub fn signature_hash_data(
|
||||
tx: &TransactionData,
|
||||
consensus_branch_id: u32,
|
||||
consensus_branch_id: consensus::BranchId,
|
||||
hash_type: u32,
|
||||
transparent_input: Option<(usize, &Script, Amount)>,
|
||||
) -> Vec<u8> {
|
||||
@@ -162,7 +162,7 @@ pub fn signature_hash_data(
|
||||
let mut personal = [0; 16];
|
||||
(&mut personal[..12]).copy_from_slice(ZCASH_SIGHASH_PERSONALIZATION_PREFIX);
|
||||
(&mut personal[12..])
|
||||
.write_u32::<LittleEndian>(consensus_branch_id)
|
||||
.write_u32::<LittleEndian>(consensus_branch_id.into())
|
||||
.unwrap();
|
||||
|
||||
let mut h = Blake2bParams::new()
|
||||
@@ -230,7 +230,7 @@ pub fn signature_hash_data(
|
||||
|
||||
pub fn signature_hash(
|
||||
tx: &Transaction,
|
||||
consensus_branch_id: u32,
|
||||
consensus_branch_id: consensus::BranchId,
|
||||
hash_type: u32,
|
||||
transparent_input: Option<(usize, &Script, Amount)>,
|
||||
) -> Vec<u8> {
|
||||
|
File diff suppressed because it is too large
Load Diff
5686
zcash_primitives/src/transaction/tests/data.rs
Normal file
5686
zcash_primitives/src/transaction/tests/data.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,13 @@
|
||||
//! Implementation of [ZIP 32] for hierarchical deterministic key management.
|
||||
//!
|
||||
//! [ZIP 32]: https://zips.z.cash/zip-0032
|
||||
|
||||
use aes::Aes256;
|
||||
use blake2b_simd::Params as Blake2bParams;
|
||||
use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use ff::Field;
|
||||
use fpe::ff1::{BinaryNumeralString, FF1};
|
||||
use pairing::bls12_381::Bls12;
|
||||
use std::ops::AddAssign;
|
||||
|
||||
use crate::{
|
||||
jubjub::{fs::Fs, FixedGenerators, JubjubEngine, JubjubParams, ToUniform},
|
||||
@@ -16,8 +20,8 @@ use crate::{
|
||||
JUBJUB,
|
||||
};
|
||||
|
||||
pub const ZIP32_SAPLING_MASTER_PERSONALIZATION: &'static [u8; 16] = b"ZcashIP32Sapling";
|
||||
pub const ZIP32_SAPLING_FVFP_PERSONALIZATION: &'static [u8; 16] = b"ZcashSaplingFVFP";
|
||||
pub const ZIP32_SAPLING_MASTER_PERSONALIZATION: &[u8; 16] = b"ZcashIP32Sapling";
|
||||
pub const ZIP32_SAPLING_FVFP_PERSONALIZATION: &[u8; 16] = b"ZcashSaplingFVFP";
|
||||
|
||||
// Common helper functions
|
||||
|
||||
@@ -83,9 +87,9 @@ impl ChildIndex {
|
||||
}
|
||||
|
||||
fn to_index(&self) -> u32 {
|
||||
match self {
|
||||
&ChildIndex::Hardened(i) => i + (1 << 31),
|
||||
&ChildIndex::NonHardened(i) => i,
|
||||
match *self {
|
||||
ChildIndex::Hardened(i) => i + (1 << 31),
|
||||
ChildIndex::NonHardened(i) => i,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -198,7 +202,7 @@ impl std::cmp::PartialEq for ExtendedSpendingKey {
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ExtendedSpendingKey {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
write!(
|
||||
f,
|
||||
"ExtendedSpendingKey(d = {}, tag_p = {:?}, i = {:?})",
|
||||
@@ -221,7 +225,7 @@ impl std::cmp::PartialEq for ExtendedFullViewingKey {
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ExtendedFullViewingKey {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
write!(
|
||||
f,
|
||||
"ExtendedFullViewingKey(d = {}, tag_p = {:?}, i = {:?})",
|
||||
@@ -434,7 +438,7 @@ impl ExtendedFullViewingKey {
|
||||
Ok(ret) => ret,
|
||||
Err(()) => return Err(()),
|
||||
};
|
||||
match self.fvk.vk.into_payment_address(d_j, &JUBJUB) {
|
||||
match self.fvk.vk.to_payment_address(d_j, &JUBJUB) {
|
||||
Some(addr) => Ok((j, addr)),
|
||||
None => Err(()),
|
||||
}
|
||||
@@ -449,7 +453,7 @@ impl ExtendedFullViewingKey {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use ff::{PrimeField, PrimeFieldRepr};
|
||||
use ff::PrimeField;
|
||||
|
||||
#[test]
|
||||
fn derive_nonhardened_child() {
|
||||
@@ -548,7 +552,7 @@ mod tests {
|
||||
let (j_m, addr_m) = xsk_m.default_address().unwrap();
|
||||
assert_eq!(j_m.0, [0; 11]);
|
||||
assert_eq!(
|
||||
addr_m.diversifier.0,
|
||||
addr_m.diversifier().0,
|
||||
// Computed using this Rust implementation
|
||||
[59, 246, 250, 31, 131, 191, 69, 99, 200, 167, 19]
|
||||
);
|
||||
@@ -1010,11 +1014,8 @@ mod tests {
|
||||
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.ask.to_repr().as_ref(), tv.ask.unwrap());
|
||||
assert_eq!(xsk.expsk.nsk.to_repr().as_ref(), tv.nsk.unwrap());
|
||||
|
||||
assert_eq!(xsk.expsk.ovk.0, tv.ovk);
|
||||
assert_eq!(xsk.dk.0, tv.dk);
|
||||
@@ -1039,13 +1040,7 @@ mod tests {
|
||||
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);
|
||||
assert_eq!(xfvk.fvk.vk.ivk().to_repr().as_ref(), tv.ivk);
|
||||
|
||||
let mut ser = vec![];
|
||||
xfvk.write(&mut ser).unwrap();
|
||||
|
Reference in New Issue
Block a user