From c3e40d73cf881b229dea8a174489421a1c2c8185 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Mon, 8 Mar 2021 05:30:39 -0500 Subject: [PATCH] Bunch more work implementing orchard, porting from sapling where applicable --- zebra-chain/src/orchard.rs | 9 +- zebra-chain/src/orchard/commitment.rs | 151 +++-- .../src/orchard/commitment/pedersen_hashes.rs | 147 ---- .../src/orchard/commitment/test_vectors.rs | 299 -------- zebra-chain/src/orchard/keys.rs | 459 ++++++------- zebra-chain/src/orchard/keys/test_vectors.rs | 641 ------------------ zebra-chain/src/orchard/note.rs | 17 +- zebra-chain/src/orchard/note/nullifiers.rs | 44 +- .../sinsemilla_hashes.rs => sinsemilla.rs} | 151 ++--- zebra-chain/src/orchard/tests.rs | 1 - 10 files changed, 385 insertions(+), 1534 deletions(-) delete mode 100644 zebra-chain/src/orchard/commitment/pedersen_hashes.rs delete mode 100644 zebra-chain/src/orchard/commitment/test_vectors.rs delete mode 100644 zebra-chain/src/orchard/keys/test_vectors.rs rename zebra-chain/src/orchard/{commitment/sinsemilla_hashes.rs => sinsemilla.rs} (66%) delete mode 100644 zebra-chain/src/orchard/tests.rs diff --git a/zebra-chain/src/orchard.rs b/zebra-chain/src/orchard.rs index 82b3b07ac..87df96a20 100644 --- a/zebra-chain/src/orchard.rs +++ b/zebra-chain/src/orchard.rs @@ -5,16 +5,13 @@ mod address; #[cfg(any(test, feature = "proptest-impl"))] mod arbitrary; mod commitment; -mod note; - -#[cfg(test)] -mod tests; - pub mod keys; +mod note; +mod sinsemilla; pub mod tree; pub use action::Action; pub use address::Address; pub use commitment::{CommitmentRandomness, NoteCommitment, ValueCommitment}; pub use keys::Diversifier; -pub use note::{EncryptedNote, Note, Nullifier, WrappedNoteKey}; +pub use note::{EncryptedNote, Note, Nullifier}; diff --git a/zebra-chain/src/orchard/commitment.rs b/zebra-chain/src/orchard/commitment.rs index e41c65876..ed5897754 100644 --- a/zebra-chain/src/orchard/commitment.rs +++ b/zebra-chain/src/orchard/commitment.rs @@ -1,9 +1,9 @@ //! Note and value commitments. -#[cfg(test)] -mod test_vectors; +// #[cfg(test)] +// mod test_vectors; -pub mod pedersen_hashes; +pub mod sinsemilla_hashes; use std::{convert::TryFrom, fmt, io}; @@ -18,9 +18,23 @@ use crate::{ }, }; -use super::keys::{find_group_hash, Diversifier, TransmissionKey}; +use super::{ + keys::{Diversifier, TransmissionKey}, + sinsemilla::*, +}; -use pedersen_hashes::*; +/// Generates a random scalar from the scalar field 𝔽_{q_P}. +/// +/// https://zips.z.cash/protocol/nu5.pdf#pallasandvesta +pub fn generate_trapdoor(csprng: &mut T) -> pallas::Scalar +where + T: RngCore + CryptoRng, +{ + let mut bytes = [0u8; 64]; + csprng.fill_bytes(&mut bytes); + // Scalar::from_bytes_wide() reduces the input modulo q under the hood. + pallas::Scalar::from_bytes_wide(&bytes) +} /// The randomness used in the Simsemilla Hash for note commitment. #[derive(Copy, Clone, Debug, PartialEq)] @@ -33,17 +47,17 @@ pub struct NoteCommitment(#[serde(with = "serde_helpers::Affine")] pub pallas::A impl fmt::Debug for NoteCommitment { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("NoteCommitment") - .field("u", &hex::encode(self.0.get_u().to_bytes())) - .field("v", &hex::encode(self.0.get_v().to_bytes())) + .field("x", &hex::encode(self.0.get_x().to_bytes())) + .field("y", &hex::encode(self.0.get_y().to_bytes())) .finish() } } impl Eq for NoteCommitment {} -impl From for NoteCommitment { - fn from(extended_point: jubjub::ExtendedPoint) -> Self { - Self(pallas::Affine::from(extended_point)) +impl From for NoteCommitment { + fn from(projective_point: pallas::Point) -> Self { + Self(pallas::Affine::from(projective_point)) } } @@ -71,11 +85,10 @@ impl NoteCommitment { /// Generate a new _NoteCommitment_ and the randomness used to create it. /// /// We return the randomness because it is needed to construct a _Note_, - /// before it is encrypted as part of an _Output Description_. This is a + /// before it is encrypted as part of an output of an _Action_. This is a /// higher level function that calls `NoteCommit^Orchard_rcm` internally. /// - /// NoteCommit^Orchard_rcm (g*_d , pk*_d , v) := - /// WindowedPedersenCommit_rcm([1; 6] || I2LEBSP_64(v) || g*_d || pk*_d) + /// NoteCommit^Orchard_rcm(repr_P(gd),repr_P(pkd), v, ρ, ψ) := /// /// https://zips.z.cash/protocol/protocol.pdf#concretewindowedcommit #[allow(non_snake_case)] @@ -84,48 +97,42 @@ impl NoteCommitment { diversifier: Diversifier, transmission_key: TransmissionKey, value: Amount, + rho: pallas::Base, + psi: pallas::Base, ) -> Option<(CommitmentRandomness, Self)> where T: RngCore + CryptoRng, { - // s as in the argument name for WindowedPedersenCommit_r(s) - let mut s: BitVec = BitVec::new(); + unimplemented!(); - // Prefix - s.append(&mut bitvec![1; 6]); + // // s as in the argument name for WindowedPedersenCommit_r(s) + // let mut s: BitVec = BitVec::new(); - // Jubjub repr_J canonical byte encoding - // https://zips.z.cash/protocol/protocol.pdf#jubjub - // - // The `TryFrom` impls for the `jubjub::*Point`s handles - // calling `DiversifyHash` implicitly. - let g_d_bytes: [u8; 32]; - if let Ok(g_d) = pallas::Affine::try_from(diversifier) { - g_d_bytes = g_d.to_bytes(); - } else { - return None; - } + // // Prefix + // s.append(&mut bitvec![1; 6]); - let pk_d_bytes = <[u8; 32]>::from(transmission_key); - let v_bytes = value.to_bytes(); + // // The `TryFrom` impls for the `jubjub::*Point`s handles + // // calling `DiversifyHash` implicitly. + // let g_d_bytes: [u8; 32]; + // if let Ok(g_d) = pallas::Affine::try_from(diversifier) { + // g_d_bytes = g_d.to_bytes(); + // } else { + // return None; + // } - s.append(&mut BitVec::::from_slice(&g_d_bytes[..])); - s.append(&mut BitVec::::from_slice(&pk_d_bytes[..])); - s.append(&mut BitVec::::from_slice(&v_bytes[..])); + // let pk_d_bytes = <[u8; 32]>::from(transmission_key); + // let v_bytes = value.to_bytes(); - let rcm = CommitmentRandomness(generate_trapdoor(csprng)); + // s.append(&mut BitVec::::from_slice(&g_d_bytes[..])); + // s.append(&mut BitVec::::from_slice(&pk_d_bytes[..])); + // s.append(&mut BitVec::::from_slice(&v_bytes[..])); - Some(( - rcm, - NoteCommitment::from(windowed_pedersen_commitment(rcm.0, &s)), - )) - } + // let rcm = CommitmentRandomness(generate_trapdoor(csprng)); - /// Hash Extractor for Pallas (?) - /// - /// https://zips.z.cash/protocol/nu5.pdf#concreteextractorpallas - pub fn extract_x(&self) -> pallas::Base { - self.0.get_u() + // Some(( + // rcm, + // NoteCommitment::from(windowed_pedersen_commitment(rcm.0, &s)), + // )) } } @@ -162,24 +169,23 @@ impl std::ops::AddAssign for ValueCommitment { impl fmt::Debug for ValueCommitment { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("ValueCommitment") - .field("u", &hex::encode(self.0.get_u().to_bytes())) - .field("v", &hex::encode(self.0.get_v().to_bytes())) + .field("x", &hex::encode(self.0.get_x().to_bytes())) + .field("y", &hex::encode(self.0.get_y().to_bytes())) .finish() } } -impl From for ValueCommitment { - fn from(extended_point: jubjub::ExtendedPoint) -> Self { - Self(pallas::Affine::from(extended_point)) +impl From for ValueCommitment { + fn from(projective_point: pallas::Point) -> Self { + Self(pallas::Affine::from(projective_point)) } } impl Eq for ValueCommitment {} -/// LEBS2OSP256(repr_J(cv)) +/// LEBS2OSP256(repr_P(cv)) /// -/// https://zips.z.cash/protocol/protocol.pdf#spendencoding -/// https://zips.z.cash/protocol/protocol.pdf#jubjub +/// https://zips.z.cash/protocol/protocol.pdf#pallasandvesta impl From for [u8; 32] { fn from(cm: ValueCommitment) -> [u8; 32] { cm.0.to_bytes() @@ -220,10 +226,9 @@ impl std::iter::Sum for ValueCommitment { } } -/// LEBS2OSP256(repr_J(cv)) +/// LEBS2OSP256(repr_P(cv)) /// -/// https://zips.z.cash/protocol/protocol.pdf#spendencoding -/// https://zips.z.cash/protocol/protocol.pdf#jubjub +/// https://zips.z.cash/protocol/protocol.pdf#pallasandvesta impl TryFrom<[u8; 32]> for ValueCommitment { type Error = &'static str; @@ -266,15 +271,17 @@ impl ValueCommitment { /// Generate a new _ValueCommitment_ from an existing _rcv_ on a _value_. /// + /// ValueCommit^Orchard(v) := + /// /// https://zips.z.cash/protocol/protocol.pdf#concretehomomorphiccommit #[allow(non_snake_case)] - pub fn new(rcv: jubjub::Fr, value: Amount) -> Self { - let v = jubjub::Fr::from(value); + pub fn new(rcv: pallas::Scalar, value: Amount) -> Self { + let v = pallas::Scalar::from(value); // TODO: These generator points can be generated once somewhere else to // avoid having to recompute them on every new commitment. - let V = find_group_hash(*b"z.cash:Orchard-cv", b"v"); - let R = find_group_hash(*b"z.cash:Orchard-cv", b"r"); + let V = pallas_group_hash(*b"z.cash:Orchard-cv", b"v"); + let R = pallas_group_hash(*b"z.cash:Orchard-cv", b"r"); Self::from(V * v + R * rcv) } @@ -288,19 +295,21 @@ mod tests { use super::*; #[test] - fn pedersen_hash_to_point_test_vectors() { + fn sinsemilla_hash_to_point_test_vectors() { zebra_test::init(); const D: [u8; 8] = *b"Zcash_PH"; for test_vector in test_vectors::TEST_VECTORS.iter() { let result = - pallas::Affine::from(pedersen_hash_to_point(D, &test_vector.input_bits.clone())); + pallas::Affine::from(sinsemilla_hash_to_point(D, &test_vector.input_bits.clone())); assert_eq!(result, test_vector.output_point); } } + // TODO: these test vectors for ops are from Jubjub, replace with Pallas ones + #[test] fn add() { zebra_test::init(); @@ -308,13 +317,13 @@ mod tests { let identity = ValueCommitment(pallas::Affine::identity()); let g = ValueCommitment(pallas::Affine::from_raw_unchecked( - jubjub::Fq::from_raw([ + pallas::Base::from_raw([ 0xe4b3_d35d_f1a7_adfe, 0xcaf5_5d1b_29bf_81af, 0x8b0f_03dd_d60a_8187, 0x62ed_cbb8_bf37_87c8, ]), - jubjub::Fq::from_raw([ + pallas::Base::from_raw([ 0x0000_0000_0000_000b, 0x0000_0000_0000_0000, 0x0000_0000_0000_0000, @@ -332,13 +341,13 @@ mod tests { let mut identity = ValueCommitment(pallas::Affine::identity()); let g = ValueCommitment(pallas::Affine::from_raw_unchecked( - jubjub::Fq::from_raw([ + pallas::Base::from_raw([ 0xe4b3_d35d_f1a7_adfe, 0xcaf5_5d1b_29bf_81af, 0x8b0f_03dd_d60a_8187, 0x62ed_cbb8_bf37_87c8, ]), - jubjub::Fq::from_raw([ + pallas::Base::from_raw([ 0x0000_0000_0000_000b, 0x0000_0000_0000_0000, 0x0000_0000_0000_0000, @@ -357,13 +366,13 @@ mod tests { zebra_test::init(); let g_point = pallas::Affine::from_raw_unchecked( - jubjub::Fq::from_raw([ + pallas::Base::from_raw([ 0xe4b3_d35d_f1a7_adfe, 0xcaf5_5d1b_29bf_81af, 0x8b0f_03dd_d60a_8187, 0x62ed_cbb8_bf37_87c8, ]), - jubjub::Fq::from_raw([ + pallas::Base::from_raw([ 0x0000_0000_0000_000b, 0x0000_0000_0000_0000, 0x0000_0000_0000_0000, @@ -383,13 +392,13 @@ mod tests { zebra_test::init(); let g_point = pallas::Affine::from_raw_unchecked( - jubjub::Fq::from_raw([ + pallas::Base::from_raw([ 0xe4b3_d35d_f1a7_adfe, 0xcaf5_5d1b_29bf_81af, 0x8b0f_03dd_d60a_8187, 0x62ed_cbb8_bf37_87c8, ]), - jubjub::Fq::from_raw([ + pallas::Base::from_raw([ 0x0000_0000_0000_000b, 0x0000_0000_0000_0000, 0x0000_0000_0000_0000, @@ -412,13 +421,13 @@ mod tests { zebra_test::init(); let g_point = pallas::Affine::from_raw_unchecked( - jubjub::Fq::from_raw([ + pallas::Base::from_raw([ 0xe4b3_d35d_f1a7_adfe, 0xcaf5_5d1b_29bf_81af, 0x8b0f_03dd_d60a_8187, 0x62ed_cbb8_bf37_87c8, ]), - jubjub::Fq::from_raw([ + pallas::Base::from_raw([ 0x0000_0000_0000_000b, 0x0000_0000_0000_0000, 0x0000_0000_0000_0000, diff --git a/zebra-chain/src/orchard/commitment/pedersen_hashes.rs b/zebra-chain/src/orchard/commitment/pedersen_hashes.rs deleted file mode 100644 index e3f69676c..000000000 --- a/zebra-chain/src/orchard/commitment/pedersen_hashes.rs +++ /dev/null @@ -1,147 +0,0 @@ -//! Pedersen hash functions and helpers. - -use bitvec::prelude::*; -use rand_core::{CryptoRng, RngCore}; - -use super::super::keys::find_group_hash; - -/// I_i -/// -/// Expects i to be 1-indexed from the loop it's called in. -/// -/// https://zips.z.cash/protocol/protocol.pdf#concretepedersenhash -#[allow(non_snake_case)] -fn I_i(domain: [u8; 8], i: u32) -> jubjub::ExtendedPoint { - find_group_hash(domain, &(i - 1).to_le_bytes()) -} - -/// The encoding function ⟨Mᵢ⟩ -/// -/// Σ j={0,k-1}: (1 - 2x₂)⋅(1 + x₀ + 2x₁)⋅2^(4⋅j) -/// -/// https://zips.z.cash/protocol/protocol.pdf#concretepedersenhash -#[allow(non_snake_case)] -fn M_i(segment: &BitSlice) -> jubjub::Fr { - let mut m_i = jubjub::Fr::zero(); - - for (j, chunk) in segment.chunks(3).enumerate() { - // Pad each chunk with zeros. - let mut store = 0u8; - let bits = store.bits_mut::(); - chunk - .iter() - .enumerate() - .for_each(|(i, bit)| bits.set(i, *bit)); - - let mut tmp = jubjub::Fr::one(); - - if bits[0] { - tmp += &jubjub::Fr::one(); - } - - if bits[1] { - tmp += &jubjub::Fr::one().double(); - } - - if bits[2] { - tmp -= tmp.double(); - } - - if j > 0 { - // Inclusive range! - tmp *= (1..=(4 * j)).fold(jubjub::Fr::one(), |acc, _| acc.double()); - } - - m_i += tmp; - } - - m_i -} - -/// "...an algebraic hash function with collision resistance (for fixed input -/// length) derived from assumed hardness of the Discrete Logarithm Problem on -/// the Jubjub curve." -/// -/// PedersenHash is used in the definitions of Pedersen commitments (§ -/// 5.4.7.2 ‘Windowed Pedersen commitments’), and of the Pedersen hash for the -/// Sapling incremental Merkle tree (§ 5.4.1.3 ‘MerkleCRH^Sapling Hash -/// Function’). -/// -/// https://zips.z.cash/protocol/protocol.pdf#concretepedersenhash -#[allow(non_snake_case)] -pub fn pedersen_hash_to_point(domain: [u8; 8], M: &BitVec) -> jubjub::ExtendedPoint { - let mut result = jubjub::ExtendedPoint::identity(); - - // Split M into n segments of 3 * c bits, where c = 63, padding the last - // segment with zeros. - // - // This loop is 1-indexed per the math definitions in the spec. - // - // https://zips.z.cash/protocol/protocol.pdf#concretepedersenhash - for (i, segment) in M - .chunks(189) - .enumerate() - .map(|(i, segment)| (i + 1, segment)) - { - result += I_i(domain, i as u32) * M_i(&segment); - } - - result -} - -/// Pedersen Hash Function -/// -/// This is technically returning 255 (l_MerkleSapling) bits, not 256. -/// -/// https://zips.z.cash/protocol/protocol.pdf#concretepedersenhash -#[allow(non_snake_case)] -pub fn pedersen_hash(domain: [u8; 8], M: &BitVec) -> jubjub::Fq { - jubjub::AffinePoint::from(pedersen_hash_to_point(domain, M)).get_u() -} - -/// Mixing Pedersen Hash Function -/// -/// Used to compute ρ from a note commitment and its position in the note -/// commitment tree. It takes as input a Pedersen commitment P, and hashes it -/// with another input x. -/// -/// MixingPedersenHash(P, x) := P + [x]FindGroupHash^J^(r)(“Zcash_J_”, “”) -/// -/// https://zips.z.cash/protocol/protocol.pdf#concretemixinghash -#[allow(non_snake_case)] -pub fn mixing_pedersen_hash(P: jubjub::ExtendedPoint, x: jubjub::Fr) -> jubjub::ExtendedPoint { - const J: [u8; 8] = *b"Zcash_J_"; - - P + find_group_hash(J, b"") * x -} - -/// Construct a 'windowed' Pedersen commitment by reusing a Pederson hash -/// construction, and adding a randomized point on the Jubjub curve. -/// -/// WindowedPedersenCommit_r (s) := \ -/// PedersenHashToPoint(“Zcash_PH”, s) + [r]FindGroupHash^J^(r)(“Zcash_PH”, “r”) -/// -/// https://zips.z.cash/protocol/protocol.pdf#concretewindowedcommit -pub fn windowed_pedersen_commitment(r: jubjub::Fr, s: &BitVec) -> jubjub::ExtendedPoint { - const D: [u8; 8] = *b"Zcash_PH"; - - pedersen_hash_to_point(D, &s) + find_group_hash(D, b"r") * r -} - -/// Generates a random scalar from the scalar field 𝔽_{r_𝕁}. -/// -/// The prime order subgroup 𝕁^(r) is the order-r_𝕁 subgroup of 𝕁 that consists -/// of the points whose order divides r. This function is useful when generating -/// the uniform distribution on 𝔽_{r_𝕁} needed for Sapling commitment schemes' -/// trapdoor generators. -/// -/// https://zips.z.cash/protocol/protocol.pdf#jubjub -pub fn generate_trapdoor(csprng: &mut T) -> jubjub::Fr -where - T: RngCore + CryptoRng, -{ - let mut bytes = [0u8; 64]; - csprng.fill_bytes(&mut bytes); - // Fr::from_bytes_wide() reduces the input modulo r via Fr::from_u512() - jubjub::Fr::from_bytes_wide(&bytes) -} diff --git a/zebra-chain/src/orchard/commitment/test_vectors.rs b/zebra-chain/src/orchard/commitment/test_vectors.rs deleted file mode 100644 index 0a8c0852f..000000000 --- a/zebra-chain/src/orchard/commitment/test_vectors.rs +++ /dev/null @@ -1,299 +0,0 @@ -// Test vector data generated from -// https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_pedersen.py -// -// These vectors in particular correspond to the Personalization::NoteCommitment -// enum variant from the original source. -// -// The Python hex-encoded outputs for these test vectors were output in -// big-endian byte order, so to parse them, we reversed their order; in -// librustzcash, they match their Display impl to match the Python hex strings -// and that's what they compare in their unit tests, not the bytes. - -#![allow(dead_code)] - -use bitvec::prelude::*; -use lazy_static::lazy_static; - -fn point_from_hex>(point_in_hex: T) -> jubjub::AffinePoint { - let mut bytes = [0u8; 32]; - let _ = hex::decode_to_slice(point_in_hex, &mut bytes); - - jubjub::AffinePoint::from_bytes(bytes).unwrap() -} - -pub struct TestVector { - pub input_bits: BitVec, - pub output_point: jubjub::AffinePoint, -} - -lazy_static! { - pub static ref TEST_VECTORS: [TestVector; 12] = [ - TestVector { - input_bits: bitvec![Lsb0, u8; 1, 1, 1, 1, 1, 1], - // original librustzcash affine point test vector (in reversed-endian byte order): - // "06b1187c11ca4fb4383b2e0d0dbbde3ad3617338b5029187ec65a5eaed5e4d0b", - // "3ce70f536652f0dea496393a1e55c4e08b9d55508e16d11e5db40d4810cbc982" - output_point: point_from_hex( - "82c9cb10480db45d1ed1168e50559d8be0c4551e3a3996a4def05266530fe7bc" - ) - }, - TestVector { - input_bits: bitvec![Lsb0, u8; 1, 1, 1, 1, 1, 1, 0], - // Original librustzcash affine point test vector (in reversed-endian byte order): - // "2fc3bc454c337f71d4f04f86304262fcbfc9ecd808716b92fc42cbe6827f7f1a", - // "46d0d25bf1a654eedc6a9b1e5af398925113959feac31b7a2c036ff9b9ec0638" - output_point: point_from_hex( - "3806ecb9f96f032c7a1bc3ea9f9513519298f35a1e9b6adcee54a6f15bd2d046" - ) - }, - TestVector { - input_bits: bitvec![Lsb0, u8; 1, 1, 1, 1, 1, 1, 1], - // Original librustzcash affine point test vector (in reversed-endian byte order): - // "4f8ce0e0a9e674b3ab9606a7d7aefba386e81583d81918127814cde41d209d97", - // "312b5ab93b14c9b9af334fe1fe3c50fffb53fbd074fa40ca600febde7c97e346" - output_point: point_from_hex( - "46e3977cdeeb0f60ca40fa74d0fb53fbff503cfee14f33afb9c9143bb95a2bb1" - ) - }, - TestVector { - input_bits: bitvec![Lsb0, u8; 1, 1, 1, 1, 1, 1, 1, 0, 0], - // Original librustzcash affine point test vector (in reversed-endian byte order): - // "4f8ce0e0a9e674b3ab9606a7d7aefba386e81583d81918127814cde41d209d97", - // "312b5ab93b14c9b9af334fe1fe3c50fffb53fbd074fa40ca600febde7c97e346" - output_point: point_from_hex( - "46e3977cdeeb0f60ca40fa74d0fb53fbff503cfee14f33afb9c9143bb95a2bb1" - ), - }, - TestVector { - input_bits: bitvec![Lsb0, u8; - 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, - ], - // Original librustzcash affine point test vector (in reversed-endian byte order): - // "599ab788360ae8c6d5bb7618aec37056d6227408d857fdc394078a3d7afdfe0f", - // "4320c373da670e28d168f4ffd72b43208e8c815f40841682c57a3ee1d005a527" - output_point: point_from_hex( - "27a505d0e13e7ac5821684405f818c8e20432bd7fff468d1280e67da73c320c3" - ), - }, - TestVector { - input_bits: bitvec![Lsb0, u8; - 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, - ], - // Original librustzcash affine point test vector (in reversed-endian byte order): - // "2da510317620f5dfdce1f31db6019f947eedcf02ff2972cff597a5c3ad21f5dd", - // "198789969c0c33e6c359b9da4a51771f4d50863f36beef90436944fe568399f2" - output_point: point_from_hex( - "f2998356fe44694390efbe363f86504d1f77514adab959c3e6330c9c96898799" - ), - }, - TestVector { - input_bits: bitvec![Lsb0, u8; - 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, - ], - // Original librustzcash affine point test vector (in reversed-endian byte order): - // "601247c7e640992d193dfb51df6ed93446687a7f2bcd0e4a598e6feb1ef20c40", - // "371931733b73e7b95c2cad55a6cebd15c83619f697c64283e54e5ef61442a743" - output_point: point_from_hex( - "43a74214f65e4ee58342c697f61936c815bdcea655ad2c5cb9e7733b73311937" - ) - }, - TestVector { - input_bits: bitvec![Lsb0, u8; - 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, - ], - // Original librustzcash affine point test vector (in reversed-endian byte order): - // "314192ecb1f2d8806a8108704c875a25d9fb7e444f9f373919adedebe8f2ae27", - // "6b12b32f1372ad574799dee9eb591d961b704bf611f55fcc71f7e82cd3330b74" - output_point: point_from_hex( - "740b33d32ce8f771cc5ff511f64b701b961d59ebe9de994757ad72132fb312eb" - ), - }, - TestVector { - input_bits: bitvec![Lsb0, u8; - 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, - ], - // Original librustzcash affine point test vector (in reversed-endian byte order): - // "0666c2bce7f362a2b807d212e9a577f116891a932affd7addec39fbf372c494e", - // "6758bccfaf2e47c07756b96edea23aa8d10c33b38220bd1c411af612eeec18ab" - output_point: point_from_hex( - "ab18ecee12f61a411cbd2082b3330cd1a83aa2de6eb95677c0472eafcfbc5867" - ), - }, - TestVector { - input_bits: bitvec![Lsb0, u8; - 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, - ], - // Original librustzcash affine point test vector (in reversed-endian byte order): - // "130afe02b99375484efb0998f5331d2178e1d00e803049bb0769099420624f5f", - // "5e2fc6970554ffe358652aa7968ac4fcf3de0c830e6ea492e01a38fafb68cd71" - output_point: point_from_hex( - "71cd68fbfa381ae092a46e0e830cdef3fcc48a96a72a6558e3ff540597c62fde" - ), - }, - TestVector { - input_bits: bitvec![Lsb0, u8; - 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, - ], - // Original librustzcash affine point test vector (in reversed-endian byte order): - // "67914ebd539961b70f468fa23d4cb42133693a8ac57cd35a1e6369fe34fbedf7", - // "44770870c0f0cfe59a10df95d6c21e6f1514a2f464b66377599438c126052d9f" - output_point: point_from_hex( - "9f2d0526c13894597763b664f4a214156f1ec2d695df109ae5cff0c0700877c4" - ), - }, - TestVector { - input_bits: bitvec![Lsb0, u8; - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - ], - // Original librustzcash affine point test vector (in reversed-endian byte order): - // "329e3bb2ca31ea6e13a986730237f6fd16b842a510cbabe851bdbcf57d75ee0d", - // "471d2109656afcb96d0609b371b132b97efcf72c6051064dd19fdc004799bfa9" - output_point: point_from_hex( - "a9bf994700dc9fd14d0651602cf7fc7eb932b171b309066db9fc6a6509211dc7" - ), - }, - ]; -} diff --git a/zebra-chain/src/orchard/keys.rs b/zebra-chain/src/orchard/keys.rs index a7516ec37..c04e08325 100644 --- a/zebra-chain/src/orchard/keys.rs +++ b/zebra-chain/src/orchard/keys.rs @@ -16,6 +16,7 @@ use std::{ }; use bech32::{self, FromBase32, ToBase32, Variant}; +use halo2::pasta::pallas; use rand_core::{CryptoRng, RngCore}; use crate::{ @@ -26,12 +27,35 @@ use crate::{ }, }; -/// Used to derive the outgoing cipher key _ock_ used to encrypt an Output ciphertext. +use super::sinsemilla::*; + +/// Invokes Blake2b-512 as PRF^expand with parameter t. /// -/// PRF^ovk(ock, cv, cm_x, ephemeralKey) := BLAKE2b-256(“Zcash_Orchardock”, ovk || cv || cm_x || ephemeralKey) +/// PRF^expand(sk, t) := BLAKE2b-512("Zcash_ExpandSeed", sk || t) +/// +/// https://zips.z.cash/protocol/protocol.pdf#concreteprfs +// TODO: This is basically a duplicate of the one in our sapling module, its +// definition in the draft NU5 spec is incomplete so I'm putting it here in case +// it changes. +fn prf_expand(sk: [u8; 32], t: &[u8]) -> [u8; 64] { + let hash = blake2b_simd::Params::new() + .hash_length(64) + .personal(b"Zcash_ExpandSeed") + .to_state() + .update(&sk[..]) + .update(t) + .finalize(); + + *hash.as_array() +} + +/// Used to derive the outgoing cipher key _ock_ used to encrypt an encrypted +/// output note from an Action. +/// +/// PRF^ock(ovk, cv, cm_x, ephemeralKey) := BLAKE2b-256(“Zcash_Orchardock”, ovk || cv || cm_x || ephemeralKey) /// /// https://zips.z.cash/protocol/nu5.pdf#concreteprfs -fn prf_ovk(ovk: [u8; 32], cv: [u8; 32], cm_x: [u8; 32], ephemeral_key: [u8; 32]) -> [u8; 32] { +fn prf_ock(ovk: [u8; 32], cv: [u8; 32], cm_x: [u8; 32], ephemeral_key: [u8; 32]) -> [u8; 32] { let hash = blake2b_simd::Params::new() .hash_length(32) .personal(b"Zcash_Orchardock") @@ -45,50 +69,30 @@ fn prf_ovk(ovk: [u8; 32], cv: [u8; 32], cm_x: [u8; 32], ephemeral_key: [u8; 32]) *hash.as_array() } -/// Invokes Blake2s-256 as _CRH^ivk_, to derive the IncomingViewingKey -/// bytes from an AuthorizingKey and NullifierDerivingKey. -/// -/// _CRH^ivk(ak, nk) := BLAKE2s-256("Zcashivk", ak || nk)_ -/// -/// https://zips.z.cash/protocol/protocol.pdf#concretecrhivk -fn crh_ivk(ak: [u8; 32], nk: [u8; 32]) -> [u8; 32] { - let hash = blake2s_simd::Params::new() - .hash_length(32) - .personal(b"Zcashivk") - .to_state() - .update(&ak[..]) - .update(&nk[..]) - .finalize(); - - *hash.as_array() -} - /// Used to derive a diversified base point from a diversifier value. /// +/// DiversifyHash^Orchard(d) := GroupHash^P("z.cash:Orchard-gd", LEBS2OSP_l_d(d)) +/// /// https://zips.z.cash/protocol/protocol.pdf#concretediversifyhash -fn diversify_hash(d: [u8; 11]) -> Option { - jubjub_group_hash(*b"Zcash_gd", &d) +fn diversify_hash(d: &[u8]) -> pallas::Point { + pallas_group_hash(*b"z.cash:Orchard-gd", &d) } -// TODO: replace with reference to redjubjub or jubjub when merged and -// exported. -type Scalar = jubjub::Fr; - -/// Magic human-readable strings used to identify what networks -/// Sapling Spending Keys are associated with when encoded/decoded -/// with bech32. +/// Magic human-readable strings used to identify what networks Orchard spending +/// keys are associated with when encoded/decoded with bech32. +/// +/// [orchardspendingkeyencoding]: https://zips.z.cash/protocol/nu5.pdf#orchardspendingkeyencoding mod sk_hrp { - pub const MAINNET: &str = "secret-spending-key-main"; - pub const TESTNET: &str = "secret-spending-key-test"; + pub const MAINNET: &str = "secret-orchard-sk-main"; + pub const TESTNET: &str = "secret-orchard-sk-test"; } -/// A _Spending Key_, as described in [protocol specification -/// §4.2.2][ps]. +/// A spending key, as described in [protocol specification §4.2.3][ps]. /// -/// Our root secret key of the Sapling key derivation tree. All other -/// Sapling key types derive from the SpendingKey value. +/// Our root secret key of the Orchard key derivation tree. All other Orchard +/// key types derive from the [`SpendingKey`] value. /// -/// [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents +/// [ps]: https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[cfg_attr( any(test, feature = "proptest-impl"), @@ -159,15 +163,15 @@ impl SpendingKey { } } -/// A _Spend Authorizing Key_, as described in [protocol specification -/// §4.2.2][ps]. +/// A Spend authorizing key (_ask_), as described in [protocol specification +/// §4.2.3][orchardkeycomponents]. /// -/// Used to generate _spend authorization randomizers_ to sign each -/// _Spend Description_, proving ownership of notes. +/// Used to generate _spend authorization randomizers_ to sign each _Spend +/// Description_, proving ownership of notes. /// -/// [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents +/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents #[derive(Copy, Clone, Eq, PartialEq)] -pub struct SpendAuthorizingKey(pub Scalar); +pub struct SpendAuthorizingKey(pub pallas::Scalar); impl fmt::Debug for SpendAuthorizingKey { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -184,15 +188,18 @@ impl From for [u8; 32] { } impl From for SpendAuthorizingKey { - /// Invokes Blake2b-512 as _PRF^expand_, t=0, to derive a - /// SpendAuthorizingKey from a SpendingKey. + /// Invokes Blake2b-512 as _PRF^expand_, t=6, to derive a + /// `SpendAuthorizingKey` from a `SpendingKey`. /// - /// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents + /// ask := ToScalar^Orchard(PRF^expand(sk, [6])) + /// + /// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents /// https://zips.z.cash/protocol/protocol.pdf#concreteprfs fn from(spending_key: SpendingKey) -> SpendAuthorizingKey { - let hash_bytes = prf_expand(spending_key.bytes, &[0]); + let hash_bytes = prf_expand(spending_key.bytes, &[6]); - Self(Scalar::from_bytes_wide(&hash_bytes)) + // Handles ToScalar^Orchard + Self(pallas::Scalar::from_bytes_wide(&hash_bytes)) } } @@ -202,53 +209,12 @@ impl PartialEq<[u8; 32]> for SpendAuthorizingKey { } } -/// A _Proof Authorizing Key_, as described in [protocol specification -/// §4.2.2][ps]. -/// -/// Used in the _Spend Statement_ to prove nullifier integrity. -/// -/// [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents -#[derive(Copy, Clone, Eq, PartialEq)] -pub struct ProofAuthorizingKey(pub Scalar); - -impl fmt::Debug for ProofAuthorizingKey { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("ProofAuthorizingKey") - .field(&hex::encode(<[u8; 32]>::from(*self))) - .finish() - } -} - -impl From for [u8; 32] { - fn from(nsk: ProofAuthorizingKey) -> Self { - nsk.0.to_bytes() - } -} - -impl From for ProofAuthorizingKey { - /// For this invocation of Blake2b-512 as _PRF^expand_, t=1. - /// - /// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents - /// https://zips.z.cash/protocol/protocol.pdf#concreteprfs - fn from(spending_key: SpendingKey) -> ProofAuthorizingKey { - let hash_bytes = prf_expand(spending_key.bytes, &[1]); - - Self(Scalar::from_bytes_wide(&hash_bytes)) - } -} - -impl PartialEq<[u8; 32]> for ProofAuthorizingKey { - fn eq(&self, other: &[u8; 32]) -> bool { - <[u8; 32]>::from(*self) == *other - } -} - -/// An _Outgoing Viewing Key_, as described in [protocol specification -/// §4.2.2][ps]. +/// An outgoing viewing key, as described in [protocol specification +/// §4.2.3][ps]. /// /// Used to decrypt outgoing notes without spending them. /// -/// [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents +/// [ps]: https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents #[derive(Copy, Clone, Eq, PartialEq)] pub struct OutgoingViewingKey(pub [u8; 32]); @@ -261,7 +227,7 @@ impl fmt::Debug for OutgoingViewingKey { } impl From<[u8; 32]> for OutgoingViewingKey { - /// Generate an _OutgoingViewingKey_ from existing bytes. + /// Generate an `OutgoingViewingKey` from existing bytes. fn from(bytes: [u8; 32]) -> Self { Self(bytes) } @@ -273,18 +239,18 @@ impl From for [u8; 32] { } } -impl From for OutgoingViewingKey { - /// For this invocation of Blake2b-512 as _PRF^expand_, t=2. +impl From for OutgoingViewingKey { + /// Derive an `OutgoingViewingKey` from a `FullViewingKey`. /// - /// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents - /// https://zips.z.cash/protocol/protocol.pdf#concreteprfs + /// let 𝐾 = I2LEBSPℓsk(rivk) + /// let 𝐵 = reprP(ak) || I2LEBSP256(nk) + /// let 𝑅 = PRFexpand + /// 𝐾 ([0x82] || LEBS2OSP512(B)) + /// let dk be the rst ℓdk/8 bytes of 𝑅 and let ovk be the remaining ℓovk/8 bytes of 𝑅. + /// + /// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents fn from(spending_key: SpendingKey) -> OutgoingViewingKey { - let hash_bytes = prf_expand(spending_key.bytes, &[2]); - - let mut bytes = [0u8; 32]; - bytes[..].copy_from_slice(&hash_bytes[0..32]); - - Self(bytes) + unimplemented!() } } @@ -294,57 +260,56 @@ impl PartialEq<[u8; 32]> for OutgoingViewingKey { } } -/// An _Authorizing Key_, as described in [protocol specification -/// §4.2.2][ps]. +/// A Spend validating key, as described in [protocol specification §4.2.3][orchardkeycomponents]. /// -/// Used to validate _Spend Authorization Signatures_, proving -/// ownership of notes. +/// Used to validate Orchard _Spend Authorization Signatures_, proving ownership +/// of notes. /// -/// [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents +/// [orchardkeycomponents]: https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents #[derive(Copy, Clone, Debug)] -pub struct AuthorizingKey(pub redjubjub::VerificationKey); +pub struct SpendValidatingKey(pub redpallas::VerificationKey); -impl Eq for AuthorizingKey {} +impl Eq for SpendValidatingKey {} -impl From<[u8; 32]> for AuthorizingKey { +impl From<[u8; 32]> for SpendValidatingKey { fn from(bytes: [u8; 32]) -> Self { - Self(redjubjub::VerificationKey::try_from(bytes).unwrap()) + Self(redpallas::VerificationKey::try_from(bytes).unwrap()) } } -impl From for [u8; 32] { - fn from(ak: AuthorizingKey) -> [u8; 32] { +impl From for [u8; 32] { + fn from(ak: SpendValidatingKey) -> [u8; 32] { ak.0.into() } } -impl From for AuthorizingKey { +impl From for SpendValidatingKey { fn from(ask: SpendAuthorizingKey) -> Self { - let sk = redjubjub::SigningKey::::try_from(<[u8; 32]>::from(ask)).unwrap(); - Self(redjubjub::VerificationKey::from(&sk)) + let sk = redpallas::SigningKey::::try_from(<[u8; 32]>::from(ask)).unwrap(); + Self(redpallas::VerificationKey::from(&sk)) } } -impl PartialEq for AuthorizingKey { +impl PartialEq for SpendValidatingKey { fn eq(&self, other: &Self) -> bool { <[u8; 32]>::from(self.0) == <[u8; 32]>::from(other.0) } } -impl PartialEq<[u8; 32]> for AuthorizingKey { +impl PartialEq<[u8; 32]> for SpendValidatingKey { fn eq(&self, other: &[u8; 32]) -> bool { <[u8; 32]>::from(self.0) == *other } } -/// A _Nullifier Deriving Key_, as described in [protocol -/// specification §4.2.2][ps]. +/// A Orchard nullifier deriving key, as described in [protocol specification +/// §4.2.3][orchardkeycomponents]. /// /// Used to create a _Nullifier_ per note. /// -/// [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents +/// [orchardkeycomponents]: https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents #[derive(Copy, Clone, PartialEq)] -pub struct NullifierDerivingKey(pub jubjub::AffinePoint); +pub struct NullifierDerivingKey(pub pallas::Base); impl fmt::Debug for NullifierDerivingKey { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -357,7 +322,7 @@ impl fmt::Debug for NullifierDerivingKey { impl From<[u8; 32]> for NullifierDerivingKey { fn from(bytes: [u8; 32]) -> Self { - Self(jubjub::AffinePoint::from_bytes(bytes).unwrap()) + Self(pallas::Affine::from_bytes(bytes).unwrap()) } } @@ -375,24 +340,17 @@ impl From<&NullifierDerivingKey> for [u8; 32] { } } -impl From for NullifierDerivingKey { +impl From for NullifierDerivingKey { /// Requires JubJub's _FindGroupHash^J("Zcash_H_", "")_, then uses /// the resulting generator point to scalar multiply the /// ProofAuthorizingKey into the new NullifierDerivingKey /// - /// https://github.com/zcash/librustzcash/blob/master/zcash_primitives/src/group_hash.rs - /// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents + /// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents /// https://zips.z.cash/protocol/protocol.pdf#concretegrouphashjubjub - fn from(nsk: ProofAuthorizingKey) -> Self { - // Should this point, when generated, be fixed for the rest of - // the protocol instance? Since this is kind of hash-and-pray, it - // seems it might not always return the same result? - let generator_point = zcash_h(); + fn from(sk: SpendingKey) -> Self { + let generator_point = prf_expand(sk, []); - // TODO: impl Mul for Fr, so we can reverse - // this to match the math in the spec / general scalar mult - // notation convention. - Self(jubjub::AffinePoint::from(generator_point * nsk.0)) + Self(pallas::Affine::from(generator_point * sk.0)) } } @@ -402,24 +360,36 @@ impl PartialEq<[u8; 32]> for NullifierDerivingKey { } } -/// Magic human-readable strings used to identify what networks -/// Sapling IncomingViewingKeys are associated with when -/// encoded/decoded with bech32. +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct IvkCommitRandomness(pallas::Scalar); + +impl fmt::Debug for IvkCommitRandomness { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("IvkCommitRandomness") + .field(&hex::encode(self.0.to_bytes())) + .finish() + } +} + +/// Magic human-readable strings used to identify what networks Orchard incoming +/// viewing keys are associated with when encoded/decoded with bech32. +/// +/// https://zips.z.cash/protocol/nu5.pdf#orchardinviewingkeyencoding mod ivk_hrp { - pub const MAINNET: &str = "zivks"; - pub const TESTNET: &str = "zivktestsapling"; + pub const MAINNET: &str = "zivko"; + pub const TESTNET: &str = "zivktestorchard"; } /// An _Incoming Viewing Key_, as described in [protocol specification -/// §4.2.2][ps]. +/// §4.2.3][ps]. /// /// Used to decrypt incoming notes without spending them. /// -/// [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents +/// [ps]: https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents #[derive(Copy, Clone, Eq, PartialEq)] pub struct IncomingViewingKey { network: Network, - scalar: Scalar, + scalar: pallas::Scalar, } // TODO: impl a From that accepts a Network? @@ -446,38 +416,24 @@ impl fmt::Display for IncomingViewingKey { impl From<[u8; 32]> for IncomingViewingKey { /// Generate an _IncomingViewingKey_ from existing bytes. fn from(mut bytes: [u8; 32]) -> Self { - // Drop the most significant five bits, so it can be interpreted - // as a scalar. - // - // I don't want to put this inside crh_ivk, but does it belong - // inside Scalar/Fr::from_bytes()? That seems the better - // place... - // - // https://github.com/zcash/librustzcash/blob/master/zcash_primitives/src/primitives.rs#L86 - bytes[31] &= 0b0000_0111; - Self { // TODO: handle setting the Network better. network: Network::default(), - scalar: Scalar::from_bytes(&bytes).unwrap(), + scalar: pallas::Scalar::from_bytes(&bytes).unwrap(), } } } -impl From<(AuthorizingKey, NullifierDerivingKey)> for IncomingViewingKey { +impl From<(SpendValidatingKey, NullifierDerivingKey)> for IncomingViewingKey { /// For this invocation of Blake2s-256 as _CRH^ivk_. /// - /// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents + /// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents /// https://zips.z.cash/protocol/protocol.pdf#concreteprfs - /// https://zips.z.cash/protocol/protocol.pdf#jubjub - // TODO: return None if ivk = 0 - // - // "If ivk = 0, discard this key and start over with a new - // [spending key]." - [§4.2.2][ps] - // - // [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents - fn from((ask, nk): (AuthorizingKey, NullifierDerivingKey)) -> Self { - let hash_bytes = crh_ivk(ask.into(), nk.into()); + + fn from((ask, nk): (SpendValidatingKey, NullifierDerivingKey)) -> Self { + unimplemented!(); + + let hash_bytes = commit_ivk(ask.into(), nk.into()); IncomingViewingKey::from(hash_bytes) } @@ -499,7 +455,7 @@ impl FromStr for IncomingViewingKey { ivk_hrp::MAINNET => Network::Mainnet, _ => Network::Testnet, }, - scalar: Scalar::from_bytes(&scalar_bytes).unwrap(), + scalar: pallas::Scalar::from_bytes(&scalar_bytes).unwrap(), }) } _ => Err(SerializationError::Parse("bech32 decoding error")), @@ -513,12 +469,12 @@ impl PartialEq<[u8; 32]> for IncomingViewingKey { } } -/// A _Diversifier_, as described in [protocol specification §4.2.2][ps]. +/// A _Diversifier_, as described in [protocol specification §4.2.3][ps]. /// /// Combined with an _IncomingViewingKey_, produces a _diversified /// payment address_. /// -/// [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents +/// [ps]: https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents #[derive(Copy, Clone, Eq, PartialEq)] #[cfg_attr( any(test, feature = "proptest-impl"), @@ -546,36 +502,31 @@ impl From for [u8; 11] { } } -impl TryFrom for jubjub::AffinePoint { +impl TryFrom for pallas::Affine { type Error = &'static str; /// Get a diversified base point from a diversifier value in affine /// representation. fn try_from(d: Diversifier) -> Result { - if let Ok(extended_point) = pallas::Point::try_from(d) { - Ok(extended_point.into()) + if let Ok(projective_point) = pallas::Point::try_from(d) { + Ok(projective_point.into()) } else { - Err("Invalid Diversifier -> jubjub::AffinePoint") + Err("Invalid Diversifier -> pallas::Affine") } } } -impl TryFrom for pallas::Point { - type Error = &'static str; - - fn try_from(d: Diversifier) -> Result { - let possible_point = diversify_hash(d.0); - - if let Some(point) = possible_point { - Ok(point) - } else { - Err("Invalid Diversifier -> pallas::Point") - } +impl From for pallas::Point { + /// g_d := DiversifyHash^Orchard(d) + /// + /// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents + fn from(d: Diversifier) -> Self { + diversify_hash(d.0) } } impl From for Diversifier { - /// Derives a [_default diversifier_][4.2.2] from a SpendingKey. + /// Derives a [_default diversifier_][4.2.3] from a `SpendingKey`. /// /// 'For each spending key, there is also a default diversified /// payment address with a “random-looking” diversifier. This @@ -584,22 +535,13 @@ impl From for Diversifier { /// that cannot be distinguished (without knowledge of the /// spending key) from one with a random diversifier...' /// - /// [4.2.2]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents + /// Derived as specied in [ZIP-32]. + /// + /// [4.2.3]: https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents + /// [ZIP-32]: https://zips.z.cash/zip-0032#orchard-diversifier-derivation fn from(sk: SpendingKey) -> Diversifier { - let mut i = 0u8; - - loop { - let mut d_bytes = [0u8; 11]; - d_bytes[..].copy_from_slice(&prf_expand(sk.bytes, &[3, i])[..11]); - - if diversify_hash(d_bytes).is_some() { - break Self(d_bytes); - } - - assert!(i < 255); - - i += 1; - } + // Needs FF1-AES permutation + unimplemented!() } } @@ -610,47 +552,39 @@ impl PartialEq<[u8; 11]> for Diversifier { } impl Diversifier { - /// Generate a new _Diversifier_ that has already been confirmed - /// as a preimage to a valid diversified base point when used to - /// derive a diversified payment address. + /// Generate a new `Diversifier`. /// - /// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents - /// https://zips.z.cash/protocol/protocol.pdf#concretediversifyhash + /// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents pub fn new(csprng: &mut T) -> Self where T: RngCore + CryptoRng, { - loop { - let mut bytes = [0u8; 11]; - csprng.fill_bytes(&mut bytes); + let mut bytes = [0u8; 11]; + csprng.fill_bytes(&mut bytes); - if diversify_hash(bytes).is_some() { - break Self(bytes); - } - } + Self::from(bytes) } } -/// A (diversified) _TransmissionKey_ +/// A (diversified) transmission Key /// -/// In Sapling, secrets need to be transmitted to a recipient of funds -/// in order for them to be later spent. To transmit these secrets -/// securely to a recipient without requiring an out-of-band -/// communication channel, the diversified transmission key is used to -/// encrypt them. +/// In Orchard, secrets need to be transmitted to a recipient of funds in order +/// for them to be later spent. To transmit these secrets securely to a +/// recipient without requiring an out-of-band communication channel, the +/// transmission key is used to encrypt them. /// -/// Derived by multiplying a JubJub point [derived][ps] from a -/// _Diversifier_ by the _IncomingViewingKey_ scalar. +/// Derived by multiplying a Pallas point [derived][ps] from a `Diversifier` by +/// the `IncomingViewingKey` scalar. /// /// [ps]: https://zips.z.cash/protocol/protocol.pdf#concretediversifyhash #[derive(Copy, Clone, PartialEq)] -pub struct TransmissionKey(pub jubjub::AffinePoint); +pub struct TransmissionKey(pub pallas::Affine); impl fmt::Debug for TransmissionKey { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("TransmissionKey") - .field("u", &hex::encode(self.0.get_u().to_bytes())) - .field("v", &hex::encode(self.0.get_v().to_bytes())) + .field("x", &hex::encode(self.0.get_x().to_bytes())) + .field("y", &hex::encode(self.0.get_y().to_bytes())) .finish() } } @@ -658,13 +592,12 @@ impl fmt::Debug for TransmissionKey { impl Eq for TransmissionKey {} impl From<[u8; 32]> for TransmissionKey { - /// Attempts to interpret a byte representation of an - /// affine point, failing if the element is not on - /// the curve or non-canonical. + /// Attempts to interpret a byte representation of an affine point, failing + /// if the element is not on the curve or non-canonical. /// /// https://github.com/zkcrypto/jubjub/blob/master/src/lib.rs#L411 fn from(bytes: [u8; 32]) -> Self { - Self(jubjub::AffinePoint::from_bytes(bytes).unwrap()) + Self(pallas::Affine::from_bytes(bytes).unwrap()) } } @@ -675,15 +608,13 @@ impl From for [u8; 32] { } impl From<(IncomingViewingKey, Diversifier)> for TransmissionKey { - /// This includes _KA^Sapling.DerivePublic(ivk, G_d)_, which is just a + /// This includes _KA^Orchard.DerivePublic(ivk, G_d)_, which is just a /// scalar mult _\[ivk\]G_d_. /// - /// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents - /// https://zips.z.cash/protocol/protocol.pdf#concretesaplingkeyagreement + /// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents + /// https://zips.z.cash/protocol/protocol.pdf#concreteorchardkeyagreement fn from((ivk, d): (IncomingViewingKey, Diversifier)) -> Self { - Self(jubjub::AffinePoint::from( - diversify_hash(d.0).unwrap() * ivk.scalar, - )) + Self(pallas::Affine::from(ivk.scalar * pallas::Point::from(d))) } } @@ -693,12 +624,13 @@ impl PartialEq<[u8; 32]> for TransmissionKey { } } -/// Magic human-readable strings used to identify what networks -/// Sapling FullViewingKeys are associated with when encoded/decoded -/// with bech32. +/// Magic human-readable strings used to identify what networks Orchard full +/// viewing keys are associated with when encoded/decoded with bech32. +/// +/// https://zips.z.cash/protocol/nu5.pdf#orchardfullviewingkeyencoding mod fvk_hrp { - pub const MAINNET: &str = "zviews"; - pub const TESTNET: &str = "zviewtestsapling"; + pub const MAINNET: &str = "zviewo"; + pub const TESTNET: &str = "zviewtestorchard"; } /// Full Viewing Keys @@ -707,16 +639,16 @@ mod fvk_hrp { /// spend authority. /// /// For incoming viewing keys on the production network, the -/// Human-Readable Part is “zviews”. For incoming viewing keys on the -/// test network, the Human-Readable Part is “zviewtestsapling”. +/// Human-Readable Part is “zviewo”. For incoming viewing keys on the +/// test network, the Human-Readable Part is “zviewtestorchard”. /// -/// https://zips.z.cash/protocol/protocol.pdf#saplingfullviewingkeyencoding +/// https://zips.z.cash/protocol/protocol.pdf#orchardfullviewingkeyencoding #[derive(Copy, Clone, Eq, PartialEq)] pub struct FullViewingKey { network: Network, - authorizing_key: AuthorizingKey, + spend_validating_key: SpendValidatingKey, nullifier_deriving_key: NullifierDerivingKey, - outgoing_viewing_key: OutgoingViewingKey, + ivk_commit_randomness: IvkCommitRandomness, } // TODO: impl a From that accepts a Network? @@ -725,9 +657,9 @@ impl fmt::Debug for FullViewingKey { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("FullViewingKey") .field("network", &self.network) - .field("authorizing_key", &self.authorizing_key) + .field("spend_validating_key", &self.spend_validating_key) .field("nullifier_deriving_key", &self.nullifier_deriving_key) - .field("outgoing_viewing_key", &self.outgoing_viewing_key) + .field("ivk_commit_randomness", &self.ivk_commit_randomness) .finish() } } @@ -736,9 +668,9 @@ impl fmt::Display for FullViewingKey { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let mut bytes = io::Cursor::new(Vec::new()); - let _ = bytes.write_all(&<[u8; 32]>::from(self.authorizing_key)); + let _ = bytes.write_all(&<[u8; 32]>::from(self.spend_validating_key)); let _ = bytes.write_all(&<[u8; 32]>::from(self.nullifier_deriving_key)); - let _ = bytes.write_all(&<[u8; 32]>::from(self.outgoing_viewing_key)); + let _ = bytes.write_all(&<[u8; 32]>::from(self.ivk_commit_randomness)); let hrp = match self.network { Network::Mainnet => fvk_hrp::MAINNET, @@ -757,20 +689,18 @@ impl FromStr for FullViewingKey { Ok((hrp, bytes, Variant::Bech32)) => { let mut decoded_bytes = io::Cursor::new(Vec::::from_base32(&bytes).unwrap()); - let authorizing_key_bytes = decoded_bytes.read_32_bytes()?; - let nullifier_deriving_key_bytes = decoded_bytes.read_32_bytes()?; - let outgoing_key_bytes = decoded_bytes.read_32_bytes()?; + let ak_bytes = decoded_bytes.read_32_bytes()?; + let nk_bytes = decoded_bytes.read_32_bytes()?; + let rivk_bytes = decoded_bytes.read_32_bytes()?; Ok(FullViewingKey { network: match hrp.as_str() { fvk_hrp::MAINNET => Network::Mainnet, _ => Network::Testnet, }, - authorizing_key: AuthorizingKey::from(authorizing_key_bytes), - nullifier_deriving_key: NullifierDerivingKey::from( - nullifier_deriving_key_bytes, - ), - outgoing_viewing_key: OutgoingViewingKey::from(outgoing_key_bytes), + spend_validating_key: SpendValidatingKey::from(ak_bytes), + nullifier_deriving_key: NullifierDerivingKey::from(nk_bytes), + ivk_commit_randomness: IvkCommitRandomness::from(rivk_bytes), }) } _ => Err(SerializationError::Parse("bech32 decoding error")), @@ -778,19 +708,20 @@ impl FromStr for FullViewingKey { } } -/// An ephemeral public key for Sapling key agreement. +#[derive(Copy, Clone, PartialEq)] +pub struct DiversifierKey(); + +/// An ephemeral public key for Orchard key agreement. /// -/// https://zips.z.cash/protocol/protocol.pdf#concretesaplingkeyagreement +/// https://zips.z.cash/protocol/protocol.pdf#concreteorchardkeyagreement #[derive(Copy, Clone, Deserialize, PartialEq, Serialize)] -pub struct EphemeralPublicKey( - #[serde(with = "serde_helpers::AffinePoint")] pub jubjub::AffinePoint, -); +pub struct EphemeralPublicKey(#[serde(with = "serde_helpers::Affine")] pub pallas::Affine); impl fmt::Debug for EphemeralPublicKey { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("EphemeralPublicKey") - .field("u", &hex::encode(self.0.get_u().to_bytes())) - .field("v", &hex::encode(self.0.get_v().to_bytes())) + .field("x", &hex::encode(self.0.get_x().to_bytes())) + .field("y", &hex::encode(self.0.get_y().to_bytes())) .finish() } } @@ -813,12 +744,12 @@ impl TryFrom<[u8; 32]> for EphemeralPublicKey { type Error = &'static str; fn try_from(bytes: [u8; 32]) -> Result { - let possible_point = jubjub::AffinePoint::from_bytes(bytes); + let possible_point = pallas::Affine::from_bytes(bytes); if possible_point.is_some().into() { Ok(Self(possible_point.unwrap())) } else { - Err("Invalid jubjub::AffinePoint value") + Err("Invalid pallas::Affine value") } } } diff --git a/zebra-chain/src/orchard/keys/test_vectors.rs b/zebra-chain/src/orchard/keys/test_vectors.rs deleted file mode 100644 index 8e18a8af1..000000000 --- a/zebra-chain/src/orchard/keys/test_vectors.rs +++ /dev/null @@ -1,641 +0,0 @@ -// Generated from https://github.com/zcash-hackworks/zcash-test-vectors/blob/07dc43fd90cd78a0b45b2eb5d2be3ce3c1841603/sapling_key_components.py - -pub struct TestVector { - pub sk: [u8; 32], - pub ask: [u8; 32], - pub nsk: [u8; 32], - pub ovk: [u8; 32], - pub ak: [u8; 32], - pub nk: [u8; 32], - pub ivk: [u8; 32], - pub default_d: [u8; 11], - pub default_pk_d: [u8; 32], - pub note_v: u64, - pub note_r: [u8; 32], - pub note_cmu: [u8; 32], - pub note_pos: u64, - pub note_nf: [u8; 32], -} - -pub const TEST_VECTORS: [TestVector; 10] = [ - TestVector { - sk: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - ask: [ - 0x85, 0x48, 0xa1, 0x4a, 0x47, 0x3e, 0xa5, 0x47, 0xaa, 0x23, 0x78, 0x40, 0x20, 0x44, - 0xf8, 0x18, 0xcf, 0x19, 0x11, 0xcf, 0x5d, 0xd2, 0x05, 0x4f, 0x67, 0x83, 0x45, 0xf0, - 0x0d, 0x0e, 0x88, 0x06, - ], - nsk: [ - 0x30, 0x11, 0x4e, 0xa0, 0xdd, 0x0b, 0xb6, 0x1c, 0xf0, 0xea, 0xea, 0xb6, 0xec, 0x33, - 0x31, 0xf5, 0x81, 0xb0, 0x42, 0x5e, 0x27, 0x33, 0x85, 0x01, 0x26, 0x2d, 0x7e, 0xac, - 0x74, 0x5e, 0x6e, 0x05, - ], - ovk: [ - 0x98, 0xd1, 0x69, 0x13, 0xd9, 0x9b, 0x04, 0x17, 0x7c, 0xab, 0xa4, 0x4f, 0x6e, 0x4d, - 0x22, 0x4e, 0x03, 0xb5, 0xac, 0x03, 0x1d, 0x7c, 0xe4, 0x5e, 0x86, 0x51, 0x38, 0xe1, - 0xb9, 0x96, 0xd6, 0x3b, - ], - ak: [ - 0xf3, 0x44, 0xec, 0x38, 0x0f, 0xe1, 0x27, 0x3e, 0x30, 0x98, 0xc2, 0x58, 0x8c, 0x5d, - 0x3a, 0x79, 0x1f, 0xd7, 0xba, 0x95, 0x80, 0x32, 0x76, 0x07, 0x77, 0xfd, 0x0e, 0xfa, - 0x8e, 0xf1, 0x16, 0x20, - ], - nk: [ - 0xf7, 0xcf, 0x9e, 0x77, 0xf2, 0xe5, 0x86, 0x83, 0x38, 0x3c, 0x15, 0x19, 0xac, 0x7b, - 0x06, 0x2d, 0x30, 0x04, 0x0e, 0x27, 0xa7, 0x25, 0xfb, 0x88, 0xfb, 0x19, 0xa9, 0x78, - 0xbd, 0x3f, 0xd6, 0xba, - ], - ivk: [ - 0xb7, 0x0b, 0x7c, 0xd0, 0xed, 0x03, 0xcb, 0xdf, 0xd7, 0xad, 0xa9, 0x50, 0x2e, 0xe2, - 0x45, 0xb1, 0x3e, 0x56, 0x9d, 0x54, 0xa5, 0x71, 0x9d, 0x2d, 0xaa, 0x0f, 0x5f, 0x14, - 0x51, 0x47, 0x92, 0x04, - ], - default_d: [ - 0xf1, 0x9d, 0x9b, 0x79, 0x7e, 0x39, 0xf3, 0x37, 0x44, 0x58, 0x39, - ], - default_pk_d: [ - 0xdb, 0x4c, 0xd2, 0xb0, 0xaa, 0xc4, 0xf7, 0xeb, 0x8c, 0xa1, 0x31, 0xf1, 0x65, 0x67, - 0xc4, 0x45, 0xa9, 0x55, 0x51, 0x26, 0xd3, 0xc2, 0x9f, 0x14, 0xe3, 0xd7, 0x76, 0xe8, - 0x41, 0xae, 0x74, 0x15, - ], - note_v: 0, - note_r: [ - 0x39, 0x17, 0x6d, 0xac, 0x39, 0xac, 0xe4, 0x98, 0x0e, 0xcc, 0x8d, 0x77, 0x8e, 0x89, - 0x86, 0x02, 0x55, 0xec, 0x36, 0x15, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - note_cmu: [ - 0xcb, 0x3c, 0xf9, 0x15, 0x32, 0x70, 0xd5, 0x7e, 0xb9, 0x14, 0xc6, 0xc2, 0xbc, 0xc0, - 0x18, 0x50, 0xc9, 0xfe, 0xd4, 0x4f, 0xce, 0x08, 0x06, 0x27, 0x8f, 0x08, 0x3e, 0xf2, - 0xdd, 0x07, 0x64, 0x39, - ], - note_pos: 0, - note_nf: [ - 0x44, 0xfa, 0xd6, 0x56, 0x4f, 0xfd, 0xec, 0x9f, 0xa1, 0x9c, 0x43, 0xa2, 0x8f, 0x86, - 0x1d, 0x5e, 0xbf, 0x60, 0x23, 0x46, 0x00, 0x7d, 0xe7, 0x62, 0x67, 0xd9, 0x75, 0x27, - 0x47, 0xab, 0x40, 0x63, - ], - }, - TestVector { - sk: [ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, - ], - ask: [ - 0xc9, 0x43, 0x56, 0x29, 0xbf, 0x8b, 0xff, 0xe5, 0x5e, 0x73, 0x35, 0xec, 0x07, 0x77, - 0x18, 0xba, 0x60, 0xba, 0x28, 0xd7, 0xac, 0x37, 0x94, 0xb7, 0x4f, 0x51, 0x2c, 0x31, - 0xaf, 0x0a, 0x53, 0x04, - ], - nsk: [ - 0x11, 0xac, 0xc2, 0xea, 0xd0, 0x7b, 0x5f, 0x00, 0x8c, 0x1f, 0x0f, 0x09, 0x0c, 0xc8, - 0xdd, 0xf3, 0x35, 0x23, 0x6f, 0xf4, 0xb2, 0x53, 0xc6, 0x49, 0x56, 0x95, 0xe9, 0xd6, - 0x39, 0xda, 0xcd, 0x08, - ], - ovk: [ - 0x3b, 0x94, 0x62, 0x10, 0xce, 0x6d, 0x1b, 0x16, 0x92, 0xd7, 0x39, 0x2a, 0xc8, 0x4a, - 0x8b, 0xc8, 0xf0, 0x3b, 0x72, 0x72, 0x3c, 0x7d, 0x36, 0x72, 0x1b, 0x80, 0x9a, 0x79, - 0xc9, 0xd6, 0xe4, 0x5b, - ], - ak: [ - 0x82, 0xff, 0x5e, 0xff, 0xc5, 0x27, 0xae, 0x84, 0x02, 0x0b, 0xf2, 0xd3, 0x52, 0x01, - 0xc1, 0x02, 0x19, 0x13, 0x19, 0x47, 0xff, 0x4b, 0x96, 0xf8, 0x81, 0xa4, 0x5f, 0x2e, - 0x8a, 0xe3, 0x05, 0x18, - ], - nk: [ - 0xc4, 0x53, 0x4d, 0x84, 0x8b, 0xb9, 0x18, 0xcf, 0x4a, 0x7f, 0x8b, 0x98, 0x74, 0x0a, - 0xb3, 0xcc, 0xee, 0x58, 0x67, 0x95, 0xff, 0x4d, 0xf6, 0x45, 0x47, 0xa8, 0x88, 0x8a, - 0x6c, 0x74, 0x15, 0xd2, - ], - ivk: [ - 0xc5, 0x18, 0x38, 0x44, 0x66, 0xb2, 0x69, 0x88, 0xb5, 0x10, 0x90, 0x67, 0x41, 0x8d, - 0x19, 0x2d, 0x9d, 0x6b, 0xd0, 0xd9, 0x23, 0x22, 0x05, 0xd7, 0x74, 0x18, 0xc2, 0x40, - 0xfc, 0x68, 0xa4, 0x06, - ], - default_d: [ - 0xae, 0xf1, 0x80, 0xf6, 0xe3, 0x4e, 0x35, 0x4b, 0x88, 0x8f, 0x81, - ], - default_pk_d: [ - 0xa6, 0xb1, 0x3e, 0xa3, 0x36, 0xdd, 0xb7, 0xa6, 0x7b, 0xb0, 0x9a, 0x0e, 0x68, 0xe9, - 0xd3, 0xcf, 0xb3, 0x92, 0x10, 0x83, 0x1e, 0xa3, 0xa2, 0x96, 0xba, 0x09, 0xa9, 0x22, - 0x06, 0x0f, 0xd3, 0x8b, - ], - note_v: 12_227_227_834_928_555_328, - note_r: [ - 0x47, 0x8b, 0xa0, 0xee, 0x6e, 0x1a, 0x75, 0xb6, 0x00, 0x03, 0x6f, 0x26, 0xf1, 0x8b, - 0x70, 0x15, 0xab, 0x55, 0x6b, 0xed, 0xdf, 0x8b, 0x96, 0x02, 0x38, 0x86, 0x9f, 0x89, - 0xdd, 0x80, 0x4e, 0x06, - ], - note_cmu: [ - 0xb5, 0x78, 0x93, 0x50, 0x0b, 0xfb, 0x85, 0xdf, 0x2e, 0x8b, 0x01, 0xac, 0x45, 0x2f, - 0x89, 0xe1, 0x0e, 0x26, 0x6b, 0xcf, 0xa3, 0x1c, 0x31, 0xb2, 0x9a, 0x53, 0xae, 0x72, - 0xca, 0xd4, 0x69, 0x50, - ], - note_pos: 763_714_296, - note_nf: [ - 0x67, 0x9e, 0xb0, 0xc3, 0xa7, 0x57, 0xe2, 0xae, 0x83, 0xcd, 0xb4, 0x2a, 0x1a, 0xb2, - 0x59, 0xd7, 0x83, 0x88, 0x31, 0x54, 0x19, 0xad, 0xc7, 0x1d, 0x2e, 0x37, 0x63, 0x17, - 0x4c, 0x2e, 0x9d, 0x93, - ], - }, - TestVector { - sk: [ - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, - ], - ask: [ - 0xee, 0x1c, 0x3d, 0x7e, 0xfe, 0x0a, 0x78, 0x06, 0x3d, 0x6a, 0xf3, 0xd9, 0xd8, 0x12, - 0x12, 0xaf, 0x47, 0xb7, 0xc1, 0xb7, 0x61, 0xf8, 0x5c, 0xcb, 0x06, 0x6f, 0xc1, 0x1a, - 0x6a, 0x42, 0x17, 0x03, - ], - nsk: [ - 0x1d, 0x3b, 0x71, 0x37, 0x55, 0xd7, 0x48, 0x75, 0xe8, 0xea, 0x38, 0xfd, 0x16, 0x6e, - 0x76, 0xc6, 0x2a, 0x42, 0x50, 0x21, 0x6e, 0x6b, 0xbf, 0xe4, 0x8a, 0x5e, 0x2e, 0xab, - 0xad, 0x11, 0x7f, 0x0b, - ], - ovk: [ - 0x8b, 0xf4, 0x39, 0x0e, 0x28, 0xdd, 0xc9, 0x5b, 0x83, 0x02, 0xc3, 0x81, 0xd5, 0x81, - 0x0b, 0x84, 0xba, 0x8e, 0x60, 0x96, 0xe5, 0xa7, 0x68, 0x22, 0x77, 0x4f, 0xd4, 0x9f, - 0x49, 0x1e, 0x8f, 0x49, - ], - ak: [ - 0xab, 0x83, 0x57, 0x4e, 0xb5, 0xde, 0x85, 0x9a, 0x0a, 0xb8, 0x62, 0x9d, 0xec, 0x34, - 0xc7, 0xbe, 0xe8, 0xc3, 0xfc, 0x74, 0xdf, 0xa0, 0xb1, 0x9a, 0x3a, 0x74, 0x68, 0xd1, - 0x5d, 0xca, 0x64, 0xc6, - ], - nk: [ - 0x95, 0xd5, 0x80, 0x53, 0xe0, 0x59, 0x2e, 0x4a, 0x16, 0x9c, 0xc0, 0xb7, 0x92, 0x8a, - 0xaa, 0xc3, 0xde, 0x24, 0xef, 0x15, 0x31, 0xaa, 0x9e, 0xb6, 0xf4, 0xab, 0x93, 0x91, - 0x4d, 0xa8, 0xa0, 0x6e, - ], - ivk: [ - 0x47, 0x1c, 0x24, 0xa3, 0xdc, 0x87, 0x30, 0xe7, 0x50, 0x36, 0xc0, 0xa9, 0x5f, 0x3e, - 0x2f, 0x7d, 0xd1, 0xbe, 0x6f, 0xb9, 0x3a, 0xd2, 0x95, 0x92, 0x20, 0x3d, 0xef, 0x30, - 0x41, 0x95, 0x45, 0x05, - ], - default_d: [ - 0x75, 0x99, 0xf0, 0xbf, 0x9b, 0x57, 0xcd, 0x2d, 0xc2, 0x99, 0xb6, - ], - default_pk_d: [ - 0x66, 0x14, 0x17, 0x39, 0x51, 0x4b, 0x28, 0xf0, 0x5d, 0xef, 0x8a, 0x18, 0xee, 0xee, - 0x5e, 0xed, 0x4d, 0x44, 0xc6, 0x22, 0x5c, 0x3c, 0x65, 0xd8, 0x8d, 0xd9, 0x90, 0x77, - 0x08, 0x01, 0x2f, 0x5a, - ], - note_v: 6_007_711_596_147_559_040, - note_r: [ - 0x14, 0x7c, 0xf2, 0xb5, 0x1b, 0x4c, 0x7c, 0x63, 0xcb, 0x77, 0xb9, 0x9e, 0x8b, 0x78, - 0x3e, 0x5b, 0x51, 0x11, 0xdb, 0x0a, 0x7c, 0xa0, 0x4d, 0x6c, 0x01, 0x4a, 0x1d, 0x7d, - 0xa8, 0x3b, 0xae, 0x0a, - ], - note_cmu: [ - 0xdb, 0x85, 0xa7, 0x0a, 0x98, 0x43, 0x7f, 0x73, 0x16, 0x7f, 0xc3, 0x32, 0xd5, 0xb7, - 0xb7, 0x40, 0x82, 0x96, 0x66, 0x17, 0x70, 0xb1, 0x01, 0xb0, 0xaa, 0x87, 0x83, 0x9f, - 0x4e, 0x55, 0xf1, 0x51, - ], - note_pos: 1_527_428_592, - note_nf: [ - 0xe9, 0x8f, 0x6a, 0x8f, 0x34, 0xff, 0x49, 0x80, 0x59, 0xb3, 0xc7, 0x31, 0xb9, 0x1f, - 0x45, 0x11, 0x08, 0xc4, 0x95, 0x4d, 0x91, 0x94, 0x84, 0x36, 0x1c, 0xf9, 0xb4, 0x8f, - 0x59, 0xae, 0x1d, 0x14, - ], - }, - TestVector { - sk: [ - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, - ], - ask: [ - 0x00, 0xc3, 0xa1, 0xe1, 0xca, 0x8f, 0x4e, 0x04, 0x80, 0xee, 0x1e, 0xe9, 0x0c, 0xa7, - 0x51, 0x78, 0x79, 0xd3, 0xfc, 0x5c, 0x81, 0x5c, 0x09, 0x03, 0xe5, 0xee, 0xbc, 0x94, - 0xbb, 0x80, 0x95, 0x03, - ], - nsk: [ - 0xe6, 0x62, 0x85, 0xa5, 0xe9, 0xb6, 0x5e, 0x15, 0x7a, 0xd2, 0xfc, 0xd5, 0x43, 0xda, - 0xd9, 0x8c, 0x67, 0xa5, 0x8a, 0xbd, 0xf2, 0x87, 0xe0, 0x55, 0x06, 0xbd, 0x1c, 0x2e, - 0x59, 0xb0, 0x72, 0x0b, - ], - ovk: [ - 0x14, 0x76, 0x78, 0xe0, 0x55, 0x3b, 0x97, 0x82, 0x93, 0x47, 0x64, 0x7c, 0x5b, 0xc7, - 0xda, 0xb4, 0xcc, 0x22, 0x02, 0xb5, 0x4e, 0xc2, 0x9f, 0xd3, 0x1a, 0x3d, 0xe6, 0xbe, - 0x08, 0x25, 0xfc, 0x5e, - ], - ak: [ - 0x3c, 0x9c, 0xde, 0x7e, 0x5d, 0x0d, 0x38, 0xa8, 0x61, 0x0f, 0xaa, 0xdb, 0xcf, 0x4c, - 0x34, 0x3f, 0x5d, 0x3c, 0xfa, 0x31, 0x55, 0xa5, 0xb9, 0x46, 0x61, 0xa6, 0x75, 0x3e, - 0x96, 0xe8, 0x84, 0xea, - ], - nk: [ - 0xb7, 0x7d, 0x36, 0xf5, 0x08, 0x94, 0x1d, 0xbd, 0x61, 0xcf, 0xd0, 0xf1, 0x59, 0xee, - 0x05, 0xcf, 0xaa, 0x78, 0xa2, 0x6c, 0x94, 0x92, 0x90, 0x38, 0x06, 0xd8, 0x3b, 0x59, - 0x8d, 0x3c, 0x1c, 0x2a, - ], - ivk: [ - 0x63, 0x6a, 0xa9, 0x64, 0xbf, 0xc2, 0x3c, 0xe4, 0xb1, 0xfc, 0xf7, 0xdf, 0xc9, 0x91, - 0x79, 0xdd, 0xc4, 0x06, 0xff, 0x55, 0x40, 0x0c, 0x92, 0x95, 0xac, 0xfc, 0x14, 0xf0, - 0x31, 0xc7, 0x26, 0x00, - ], - default_d: [ - 0x1b, 0x81, 0x61, 0x4f, 0x1d, 0xad, 0xea, 0x0f, 0x8d, 0x0a, 0x58, - ], - default_pk_d: [ - 0x25, 0xeb, 0x55, 0xfc, 0xcf, 0x76, 0x1f, 0xc6, 0x4e, 0x85, 0xa5, 0x88, 0xef, 0xe6, - 0xea, 0xd7, 0x83, 0x2f, 0xb1, 0xf0, 0xf7, 0xa8, 0x31, 0x65, 0x89, 0x5b, 0xdf, 0xf9, - 0x42, 0x92, 0x5f, 0x5c, - ], - note_v: 18_234_939_431_076_114_368, - note_r: [ - 0x34, 0xa4, 0xb2, 0xa9, 0x14, 0x4f, 0xf5, 0xea, 0x54, 0xef, 0xee, 0x87, 0xcf, 0x90, - 0x1b, 0x5b, 0xed, 0x5e, 0x35, 0xd2, 0x1f, 0xbb, 0xd7, 0x88, 0xd5, 0xbd, 0x9d, 0x83, - 0x3e, 0x11, 0x28, 0x04, - ], - note_cmu: [ - 0xe0, 0x8c, 0xe4, 0x82, 0xb3, 0xa8, 0xfb, 0x3b, 0x35, 0xcc, 0xdb, 0xe3, 0x43, 0x37, - 0xbd, 0x10, 0x5d, 0x88, 0x39, 0x21, 0x2e, 0x0d, 0x16, 0x44, 0xb9, 0xd5, 0x5c, 0xaa, - 0x60, 0xd1, 0x9b, 0x6c, - ], - note_pos: 2_291_142_888, - note_nf: [ - 0x55, 0x47, 0xaa, 0x12, 0xff, 0x80, 0xa6, 0xb3, 0x30, 0x4e, 0x3b, 0x05, 0x86, 0x56, - 0x47, 0x2a, 0xbd, 0x2c, 0x81, 0x83, 0xb5, 0x9d, 0x07, 0x37, 0xb9, 0x3c, 0xee, 0x75, - 0x8b, 0xec, 0x47, 0xa1, - ], - }, - TestVector { - sk: [ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, - ], - ask: [ - 0x82, 0x36, 0xd1, 0x9d, 0x32, 0x05, 0xd8, 0x55, 0x43, 0xa0, 0x68, 0x11, 0x34, 0x3f, - 0x82, 0x7b, 0x65, 0x63, 0x77, 0x0a, 0x49, 0xaa, 0x4d, 0x0c, 0xa0, 0x08, 0x18, 0x05, - 0xd4, 0xc8, 0xea, 0x0d, - ], - nsk: [ - 0x7e, 0xc1, 0xef, 0x0b, 0xed, 0x82, 0x71, 0x82, 0x72, 0xf0, 0xf4, 0x4f, 0x01, 0x7c, - 0x48, 0x41, 0x74, 0x51, 0x3d, 0x66, 0x1d, 0xd1, 0x68, 0xaf, 0x02, 0xd2, 0x09, 0x2a, - 0x1d, 0x8a, 0x05, 0x07, - ], - ovk: [ - 0x1b, 0x6e, 0x75, 0xec, 0xe3, 0xac, 0xe8, 0xdb, 0xa6, 0xa5, 0x41, 0x0d, 0x9a, 0xd4, - 0x75, 0x56, 0x68, 0xe4, 0xb3, 0x95, 0x85, 0xd6, 0x35, 0xec, 0x1d, 0xa7, 0xc8, 0xdc, - 0xfd, 0x5f, 0xc4, 0xed, - ], - ak: [ - 0x55, 0xe8, 0x83, 0x89, 0xbb, 0x7e, 0x41, 0xde, 0x13, 0x0c, 0xfa, 0x51, 0xa8, 0x71, - 0x5f, 0xde, 0x01, 0xff, 0x9c, 0x68, 0x76, 0x64, 0x7f, 0x01, 0x75, 0xad, 0x34, 0xf0, - 0x58, 0xdd, 0xe0, 0x1a, - ], - nk: [ - 0x72, 0x5d, 0x4a, 0xd6, 0xa1, 0x50, 0x21, 0xcd, 0x1c, 0x48, 0xc5, 0xee, 0x19, 0xde, - 0x6c, 0x1e, 0x76, 0x8a, 0x2c, 0xc0, 0xa9, 0xa7, 0x30, 0xa0, 0x1b, 0xb2, 0x1c, 0x95, - 0xe3, 0xd9, 0xe4, 0x3c, - ], - ivk: [ - 0x67, 0xfa, 0x2b, 0xf7, 0xc6, 0x7d, 0x46, 0x58, 0x24, 0x3c, 0x31, 0x7c, 0x0c, 0xb4, - 0x1f, 0xd3, 0x20, 0x64, 0xdf, 0xd3, 0x70, 0x9f, 0xe0, 0xdc, 0xb7, 0x24, 0xf1, 0x4b, - 0xb0, 0x1a, 0x1d, 0x04, - ], - default_d: [ - 0xfc, 0xfb, 0x68, 0xa4, 0x0d, 0x4b, 0xc6, 0xa0, 0x4b, 0x09, 0xc4, - ], - default_pk_d: [ - 0x8b, 0x2a, 0x33, 0x7f, 0x03, 0x62, 0x2c, 0x24, 0xff, 0x38, 0x1d, 0x4c, 0x54, 0x6f, - 0x69, 0x77, 0xf9, 0x05, 0x22, 0xe9, 0x2f, 0xde, 0x44, 0xc9, 0xd1, 0xbb, 0x09, 0x97, - 0x14, 0xb9, 0xdb, 0x2b, - ], - note_v: 12_015_423_192_295_118_080, - note_r: [ - 0xe5, 0x57, 0x85, 0x13, 0x55, 0x74, 0x7c, 0x09, 0xac, 0x59, 0x01, 0x3c, 0xbd, 0xe8, - 0x59, 0x80, 0x96, 0x4e, 0xc1, 0x84, 0x4d, 0x9c, 0x69, 0x67, 0xca, 0x0c, 0x02, 0x9c, - 0x84, 0x57, 0xbb, 0x04, - ], - note_cmu: [ - 0xbd, 0xc8, 0x54, 0xbf, 0x3e, 0x7b, 0x00, 0x82, 0x1f, 0x3b, 0x8b, 0x85, 0x23, 0x8c, - 0xcf, 0x1e, 0x67, 0x15, 0xbf, 0xe7, 0x0b, 0x63, 0x2d, 0x04, 0x4b, 0x26, 0xfb, 0x2b, - 0xc7, 0x1b, 0x7f, 0x36, - ], - note_pos: 3_054_857_184, - note_nf: [ - 0x8a, 0x9a, 0xbd, 0xa3, 0xd4, 0xef, 0x85, 0xca, 0xf2, 0x2b, 0xfa, 0xf2, 0xc4, 0x8f, - 0x62, 0x38, 0x2a, 0x73, 0xa1, 0x62, 0x4e, 0xb8, 0xeb, 0x2b, 0xd0, 0x0d, 0x27, 0x03, - 0x01, 0xbf, 0x3d, 0x13, - ], - }, - TestVector { - sk: [ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, - ], - ask: [ - 0xea, 0xe6, 0x88, 0x4d, 0x76, 0x4a, 0x05, 0x40, 0x61, 0xa8, 0xf1, 0xc0, 0x07, 0x6c, - 0x62, 0x4d, 0xcb, 0x73, 0x87, 0x89, 0xf7, 0xad, 0x1e, 0x74, 0x08, 0xe3, 0x1f, 0x24, - 0xdf, 0xc8, 0x26, 0x07, - ], - nsk: [ - 0xfb, 0xe6, 0x10, 0xf4, 0x2a, 0x41, 0x74, 0x9f, 0x9b, 0x6e, 0x6e, 0x4a, 0x54, 0xb5, - 0xa3, 0x2e, 0xbf, 0xe8, 0xf4, 0x38, 0x00, 0x88, 0x1b, 0xa6, 0xcd, 0x13, 0xed, 0x0b, - 0x05, 0x29, 0x46, 0x01, - ], - ovk: [ - 0xc6, 0xbc, 0x1f, 0x39, 0xf0, 0xd7, 0x86, 0x31, 0x4c, 0xb2, 0x0b, 0xf9, 0xab, 0x22, - 0x85, 0x40, 0x91, 0x35, 0x55, 0xf9, 0x70, 0x69, 0x6b, 0x6d, 0x7c, 0x77, 0xbb, 0x33, - 0x23, 0x28, 0x37, 0x2a, - ], - ak: [ - 0xe6, 0x82, 0x76, 0x59, 0x14, 0xe3, 0x86, 0x4c, 0x33, 0x9e, 0x57, 0x82, 0xb8, 0x55, - 0xc0, 0xfd, 0xf4, 0x0e, 0x0d, 0xfc, 0xed, 0xb9, 0xe7, 0xb4, 0x7b, 0xc9, 0x4b, 0x90, - 0xb3, 0xa4, 0xc9, 0x88, - ], - nk: [ - 0x82, 0x25, 0x6b, 0x95, 0x62, 0x3c, 0x67, 0x02, 0x4b, 0x44, 0x24, 0xd9, 0x14, 0x00, - 0xa3, 0x70, 0xe7, 0xac, 0x8e, 0x4d, 0x15, 0x48, 0x2a, 0x37, 0x59, 0xe0, 0x0d, 0x21, - 0x97, 0x49, 0xda, 0xee, - ], - ivk: [ - 0xea, 0x3f, 0x1d, 0x80, 0xe4, 0x30, 0x7c, 0xa7, 0x3b, 0x9f, 0x37, 0x80, 0x1f, 0x91, - 0xfb, 0xa8, 0x10, 0xcc, 0x41, 0xd2, 0x79, 0xfc, 0x29, 0xf5, 0x64, 0x23, 0x56, 0x54, - 0xa2, 0x17, 0x8e, 0x03, - ], - default_d: [ - 0xeb, 0x51, 0x98, 0x82, 0xad, 0x1e, 0x5c, 0xc6, 0x54, 0xcd, 0x59, - ], - default_pk_d: [ - 0x6b, 0x27, 0xda, 0xcc, 0xb5, 0xa8, 0x20, 0x7f, 0x53, 0x2d, 0x10, 0xca, 0x23, 0x8f, - 0x97, 0x86, 0x64, 0x8a, 0x11, 0xb5, 0x96, 0x6e, 0x51, 0xa2, 0xf7, 0xd8, 0x9e, 0x15, - 0xd2, 0x9b, 0x8f, 0xdf, - ], - note_v: 5_795_906_953_514_121_792, - note_r: [ - 0x68, 0xf0, 0x61, 0x04, 0x60, 0x6b, 0x0c, 0x54, 0x49, 0x84, 0x5f, 0xf4, 0xc6, 0x5f, - 0x73, 0xe9, 0x0f, 0x45, 0xef, 0x5a, 0x43, 0xc9, 0xd7, 0x4c, 0xb2, 0xc8, 0x5c, 0xf5, - 0x6c, 0x94, 0xc0, 0x02, - ], - note_cmu: [ - 0xe8, 0x26, 0x7d, 0x30, 0xac, 0x11, 0xc1, 0x00, 0xbc, 0x7a, 0x0f, 0xdf, 0x91, 0xf7, - 0x1d, 0x74, 0xc5, 0xbc, 0xf2, 0xe1, 0xef, 0x95, 0x66, 0x90, 0x44, 0x73, 0x01, 0x69, - 0xde, 0x1a, 0x5b, 0x4c, - ], - note_pos: 3_818_571_480, - note_nf: [ - 0x33, 0x2a, 0xd9, 0x9e, 0xb9, 0xe9, 0x77, 0xeb, 0x62, 0x7a, 0x12, 0x2d, 0xbf, 0xb2, - 0xf2, 0x5f, 0xe5, 0x88, 0xe5, 0x97, 0x75, 0x3e, 0xc5, 0x58, 0x0f, 0xf2, 0xbe, 0x20, - 0xb6, 0xc9, 0xa7, 0xe1, - ], - }, - TestVector { - sk: [ - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, - ], - ask: [ - 0xe8, 0xf8, 0x16, 0xb4, 0xbc, 0x08, 0xa7, 0xe5, 0x66, 0x75, 0x0c, 0xc2, 0x8a, 0xfe, - 0x82, 0xa4, 0xce, 0xa9, 0xc2, 0xbe, 0xf2, 0x44, 0xfa, 0x4b, 0x13, 0xc4, 0x73, 0x9b, - 0x28, 0x07, 0x4c, 0x0d, - ], - nsk: [ - 0x32, 0x61, 0x5b, 0x13, 0x7f, 0x28, 0x01, 0xed, 0x44, 0x6e, 0x48, 0x78, 0x1a, 0xb0, - 0x63, 0x45, 0x72, 0xe1, 0x8c, 0xfb, 0x06, 0x93, 0x72, 0x1b, 0x88, 0x03, 0xc0, 0x5b, - 0x82, 0x27, 0xd1, 0x07, - ], - ovk: [ - 0xf6, 0x2c, 0x05, 0xe8, 0x48, 0xa8, 0x73, 0xef, 0x88, 0x5e, 0x12, 0xb0, 0x8c, 0x5e, - 0x7c, 0xa2, 0xf3, 0x24, 0x24, 0xba, 0xcc, 0x75, 0x4c, 0xb6, 0x97, 0x50, 0x44, 0x4d, - 0x35, 0x5f, 0x51, 0x06, - ], - ak: [ - 0xff, 0x27, 0xdb, 0x07, 0x51, 0x94, 0x5d, 0x3e, 0xe4, 0xbe, 0x9c, 0xf1, 0x5c, 0x2e, - 0xa2, 0x11, 0xb2, 0x4b, 0x16, 0x4d, 0x5f, 0x2d, 0x7d, 0xdf, 0xf5, 0xe4, 0xa0, 0x70, - 0x8f, 0x10, 0xb9, 0x5e, - ], - nk: [ - 0x94, 0x38, 0x85, 0x95, 0x9d, 0x4e, 0xf8, 0xa9, 0xcf, 0xca, 0x07, 0xc4, 0x57, 0xf0, - 0x9e, 0xc7, 0x4b, 0x96, 0xf9, 0x93, 0xd8, 0xe0, 0xfa, 0x32, 0xb1, 0x9c, 0x03, 0xe3, - 0xb0, 0x7a, 0x42, 0x0f, - ], - ivk: [ - 0xb5, 0xc5, 0x89, 0x49, 0x43, 0x95, 0x69, 0x33, 0xc0, 0xe5, 0xc1, 0x2d, 0x31, 0x1f, - 0xc1, 0x2c, 0xba, 0x58, 0x35, 0x4b, 0x5c, 0x38, 0x9e, 0xdc, 0x03, 0xda, 0x55, 0x08, - 0x4f, 0x74, 0xc2, 0x05, - ], - default_d: [ - 0xbe, 0xbb, 0x0f, 0xb4, 0x6b, 0x8a, 0xaf, 0xf8, 0x90, 0x40, 0xf6, - ], - default_pk_d: [ - 0xd1, 0x1d, 0xa0, 0x1f, 0x0b, 0x43, 0xbd, 0xd5, 0x28, 0x8d, 0x32, 0x38, 0x5b, 0x87, - 0x71, 0xd2, 0x23, 0x49, 0x3c, 0x69, 0x80, 0x25, 0x44, 0x04, 0x3f, 0x77, 0xcf, 0x1d, - 0x71, 0xc1, 0xcb, 0x8c, - ], - note_v: 18_023_134_788_442_677_120, - note_r: [ - 0x49, 0xf9, 0x0b, 0x47, 0xfd, 0x52, 0xfe, 0xe7, 0xc1, 0xc8, 0x1f, 0x0d, 0xcb, 0x5b, - 0x74, 0xc3, 0xfb, 0x9b, 0x3e, 0x03, 0x97, 0x6f, 0x8b, 0x75, 0x24, 0xea, 0xba, 0xd0, - 0x08, 0x89, 0x21, 0x07, - ], - note_cmu: [ - 0x57, 0x2b, 0xa2, 0x05, 0x25, 0xb0, 0xac, 0x4d, 0x6d, 0xc0, 0x1a, 0xc2, 0xea, 0x10, - 0x90, 0xb6, 0xe0, 0xf2, 0xf4, 0xbf, 0x4e, 0xc4, 0xa0, 0xdb, 0x5b, 0xbc, 0xcb, 0x5b, - 0x78, 0x3a, 0x1e, 0x55, - ], - note_pos: 287_318_480, - note_nf: [ - 0xfc, 0x74, 0xcd, 0x0e, 0x4b, 0xe0, 0x49, 0x57, 0xb1, 0x96, 0xcf, 0x87, 0x34, 0xae, - 0x99, 0x23, 0x96, 0xaf, 0x4c, 0xfa, 0x8f, 0xec, 0xbb, 0x86, 0xf9, 0x61, 0xe6, 0xb4, - 0x07, 0xd5, 0x1e, 0x11, - ], - }, - TestVector { - sk: [ - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, - ], - ask: [ - 0x74, 0xb4, 0x4a, 0x37, 0xf1, 0x50, 0x23, 0xc0, 0x60, 0x42, 0x7e, 0x1d, 0xae, 0xa3, - 0xf6, 0x43, 0x12, 0xdd, 0x8f, 0xeb, 0x7b, 0x2c, 0xed, 0xf0, 0xdd, 0x55, 0x44, 0x49, - 0x3f, 0x87, 0x2c, 0x06, - ], - nsk: [ - 0x07, 0x5c, 0x35, 0xdb, 0x8b, 0x1b, 0x25, 0x75, 0x42, 0x23, 0xec, 0xee, 0x34, 0xab, - 0x73, 0x0d, 0xdd, 0xd1, 0xf1, 0x4a, 0x6a, 0x54, 0xf4, 0xc6, 0xf4, 0x68, 0x45, 0x3c, - 0x3c, 0x6e, 0xd6, 0x0b, - ], - ovk: [ - 0xe9, 0xe0, 0xdc, 0x1e, 0xd3, 0x11, 0xda, 0xed, 0x64, 0xbd, 0x74, 0xda, 0x5d, 0x94, - 0xfe, 0x88, 0xa6, 0xea, 0x41, 0x4b, 0x73, 0x12, 0xde, 0x3d, 0x2a, 0x78, 0xf6, 0x46, - 0x32, 0xbb, 0xe3, 0x73, - ], - ak: [ - 0x28, 0x3f, 0x9a, 0xaf, 0xa9, 0xbc, 0xb3, 0xe6, 0xce, 0x17, 0xe6, 0x32, 0x12, 0x63, - 0x4c, 0xb3, 0xee, 0x55, 0x0c, 0x47, 0x6b, 0x67, 0x6b, 0xd3, 0x56, 0xa6, 0xdf, 0x8a, - 0xdf, 0x51, 0xd2, 0x5e, - ], - nk: [ - 0xdc, 0x4c, 0x67, 0xb1, 0x0d, 0x4b, 0x0a, 0x21, 0x8d, 0xc6, 0xe1, 0x48, 0x70, 0x66, - 0x74, 0x0a, 0x40, 0x93, 0x17, 0x86, 0x6c, 0x32, 0xe6, 0x64, 0xb5, 0x0e, 0x39, 0x7a, - 0xa8, 0x03, 0x89, 0xd4, - ], - ivk: [ - 0x87, 0x16, 0xc8, 0x28, 0x80, 0xe1, 0x36, 0x83, 0xe1, 0xbb, 0x05, 0x9d, 0xd0, 0x6c, - 0x80, 0xc9, 0x01, 0x34, 0xa9, 0x6d, 0x5a, 0xfc, 0xa8, 0xaa, 0xc2, 0xbb, 0xf6, 0x8b, - 0xb0, 0x5f, 0x84, 0x02, - ], - default_d: [ - 0xad, 0x6e, 0x2e, 0x18, 0x5a, 0x31, 0x00, 0xe3, 0xa6, 0xa8, 0xb3, - ], - default_pk_d: [ - 0x32, 0xcb, 0x28, 0x06, 0xb8, 0x82, 0xf1, 0x36, 0x8b, 0x0d, 0x4a, 0x89, 0x8f, 0x72, - 0xc4, 0xc8, 0xf7, 0x28, 0x13, 0x2c, 0xc1, 0x24, 0x56, 0x94, 0x6e, 0x7f, 0x4c, 0xb0, - 0xfb, 0x05, 0x8d, 0xa9, - ], - note_v: 11_803_618_549_661_680_832, - note_r: [ - 0x51, 0x65, 0xaf, 0xf2, 0x2d, 0xd4, 0xed, 0x56, 0xb4, 0xd8, 0x1d, 0x1f, 0x17, 0x1c, - 0xc3, 0xd6, 0x43, 0x2f, 0xed, 0x1b, 0xeb, 0xf2, 0x0a, 0x7b, 0xea, 0xb1, 0x2d, 0xb1, - 0x42, 0xf9, 0x4a, 0x0c, - ], - note_cmu: [ - 0xab, 0x7f, 0xc5, 0x66, 0x87, 0x3c, 0xcd, 0xe6, 0x71, 0xf5, 0x98, 0x27, 0x67, 0x85, - 0x60, 0xa0, 0x06, 0xf8, 0x2b, 0xb7, 0xad, 0xcd, 0x75, 0x22, 0x3f, 0xa8, 0x59, 0x36, - 0xf7, 0x8c, 0x2b, 0x23, - ], - note_pos: 1_051_032_776, - note_nf: [ - 0xd2, 0xe8, 0x87, 0xbd, 0x85, 0x4a, 0x80, 0x2b, 0xce, 0x85, 0x70, 0x53, 0x02, 0x0f, - 0x5d, 0x3e, 0x7c, 0x8a, 0xe5, 0x26, 0x7c, 0x5b, 0x65, 0x83, 0xb3, 0xd2, 0x12, 0xcc, - 0x8b, 0xb6, 0x98, 0x90, - ], - }, - TestVector { - sk: [ - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, - ], - ask: [ - 0x03, 0x9d, 0xd9, 0x3d, 0xf3, 0x11, 0xff, 0x8f, 0xba, 0xb3, 0xfe, 0x23, 0x02, 0x19, - 0xcd, 0x42, 0xac, 0x87, 0x94, 0x84, 0xf3, 0x0b, 0x90, 0x3a, 0x3c, 0x1e, 0x67, 0xcc, - 0xca, 0x5a, 0x7b, 0x0d, - ], - nsk: [ - 0x04, 0x9f, 0xa1, 0x4f, 0x48, 0x6c, 0x75, 0xb9, 0xfa, 0xd7, 0xe3, 0xb6, 0x73, 0xa4, - 0x43, 0xdd, 0x07, 0x4e, 0xaa, 0x96, 0xed, 0xcb, 0x2a, 0x53, 0xea, 0xaa, 0xbd, 0xaf, - 0x70, 0xff, 0xbb, 0x08, - ], - ovk: [ - 0x14, 0x7d, 0xd1, 0x1d, 0x77, 0xeb, 0xa1, 0xb1, 0x63, 0x6f, 0xd6, 0x19, 0x0c, 0x62, - 0xb9, 0xa5, 0xd0, 0x48, 0x1b, 0xee, 0x7e, 0x91, 0x7f, 0xab, 0x02, 0xe2, 0x18, 0x58, - 0x06, 0x3a, 0xb5, 0x04, - ], - ak: [ - 0x36, 0x40, 0x48, 0xee, 0xdb, 0xe8, 0xca, 0x20, 0x5e, 0xb7, 0xe7, 0xba, 0x0a, 0x90, - 0x12, 0x16, 0x6c, 0x7c, 0x7b, 0xd9, 0xeb, 0x22, 0x8e, 0x08, 0x48, 0x14, 0x48, 0xc4, - 0x88, 0xaa, 0x21, 0xd2, - ], - nk: [ - 0xed, 0x60, 0xaf, 0x1c, 0xe7, 0xdf, 0x38, 0x07, 0x0d, 0x38, 0x51, 0x43, 0x2a, 0x96, - 0x48, 0x0d, 0xb0, 0xb4, 0x17, 0xc3, 0x68, 0x2a, 0x1d, 0x68, 0xe3, 0xe8, 0x93, 0x34, - 0x23, 0x5c, 0x0b, 0xdf, - ], - ivk: [ - 0x99, 0xc9, 0xb4, 0xb8, 0x4f, 0x4b, 0x4e, 0x35, 0x0f, 0x78, 0x7d, 0x1c, 0xf7, 0x05, - 0x1d, 0x50, 0xec, 0xc3, 0x4b, 0x1a, 0x5b, 0x20, 0xd2, 0xd2, 0x13, 0x9b, 0x4a, 0xf1, - 0xf1, 0x60, 0xe0, 0x01, - ], - default_d: [ - 0x21, 0xc9, 0x0e, 0x1c, 0x65, 0x8b, 0x3e, 0xfe, 0x86, 0xaf, 0x58, - ], - default_pk_d: [ - 0x9e, 0x64, 0x17, 0x4b, 0x4a, 0xb9, 0x81, 0x40, 0x5c, 0x32, 0x3b, 0x5e, 0x12, 0x47, - 0x59, 0x45, 0xa4, 0x6d, 0x4f, 0xed, 0xf8, 0x06, 0x08, 0x28, 0x04, 0x1c, 0xd2, 0x0e, - 0x62, 0xfd, 0x2c, 0xef, - ], - note_v: 5_584_102_310_880_684_544, - note_r: [ - 0x8c, 0x3e, 0x56, 0x44, 0x9d, 0xc8, 0x63, 0x54, 0xd3, 0x3b, 0x02, 0x5e, 0xf2, 0x79, - 0x34, 0x60, 0xbc, 0xb1, 0x69, 0xf3, 0x32, 0x4e, 0x4a, 0x6b, 0x64, 0xba, 0xa6, 0x08, - 0x32, 0x31, 0x57, 0x04, - ], - note_cmu: [ - 0x7b, 0x48, 0xa8, 0x37, 0x5d, 0x3e, 0xbd, 0x56, 0xbc, 0x64, 0x9b, 0xb5, 0xb5, 0x24, - 0x23, 0x36, 0xc2, 0xa0, 0x5a, 0x08, 0x03, 0x23, 0x9b, 0x5b, 0x88, 0xfd, 0x92, 0x07, - 0x8f, 0xea, 0x4d, 0x04, - ], - note_pos: 1_814_747_072, - note_nf: [ - 0xa8, 0x2f, 0x17, 0x50, 0xcc, 0x5b, 0x2b, 0xee, 0x64, 0x9a, 0x36, 0x5c, 0x04, 0x20, - 0xed, 0x87, 0x07, 0x5b, 0x88, 0x71, 0xfd, 0xa4, 0xa7, 0xf5, 0x84, 0x0d, 0x6b, 0xbe, - 0xb1, 0x7c, 0xd6, 0x20, - ], - }, - TestVector { - sk: [ - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, - ], - ask: [ - 0xeb, 0xbb, 0x40, 0xa9, 0x80, 0xba, 0x3b, 0x88, 0x60, 0x94, 0x8d, 0x01, 0x1e, 0x1b, - 0xfb, 0x4a, 0xff, 0xe1, 0x6c, 0x65, 0x2e, 0x90, 0xe9, 0x82, 0x58, 0x30, 0x2f, 0x44, - 0x64, 0xc9, 0x1e, 0x0c, - ], - nsk: [ - 0x68, 0x43, 0x1b, 0x19, 0x91, 0x04, 0x21, 0x52, 0x00, 0xb9, 0x5e, 0xe5, 0xcb, 0x71, - 0xbf, 0x8b, 0x88, 0x3a, 0x3e, 0x95, 0xb7, 0x98, 0x9c, 0xad, 0x19, 0x70, 0x63, 0x14, - 0x1e, 0xbb, 0xfd, 0x00, - ], - ovk: [ - 0x57, 0x34, 0x67, 0xa7, 0xb3, 0x0e, 0xad, 0x6c, 0xcc, 0x50, 0x47, 0x44, 0xca, 0x9e, - 0x1a, 0x28, 0x1a, 0x0d, 0x1a, 0x08, 0x73, 0x8b, 0x06, 0xa0, 0x68, 0x4f, 0xea, 0xcd, - 0x1e, 0x9d, 0x12, 0x6d, - ], - ak: [ - 0x71, 0xc3, 0x52, 0x3e, 0xec, 0xa3, 0x53, 0x11, 0xfb, 0xd5, 0xd7, 0xe7, 0xd7, 0x0b, - 0x70, 0x9d, 0x6c, 0x35, 0xa2, 0x4f, 0x26, 0x2b, 0x34, 0xbf, 0x64, 0x05, 0x9b, 0xf2, - 0xc0, 0x2e, 0x0b, 0xa8, - ], - nk: [ - 0x62, 0x44, 0x00, 0x10, 0x3b, 0x65, 0x69, 0xb7, 0x35, 0x8f, 0xe8, 0x0f, 0x6f, 0x6c, - 0xad, 0x43, 0x25, 0xde, 0xfd, 0xa9, 0xd9, 0x49, 0x9c, 0x2b, 0x8f, 0x88, 0x6a, 0x62, - 0x69, 0xa2, 0xaa, 0x52, - ], - ivk: [ - 0xdb, 0x95, 0xea, 0x8b, 0xd9, 0xf9, 0x3d, 0x41, 0xb5, 0xab, 0x2b, 0xeb, 0xc9, 0x1a, - 0x38, 0xed, 0xd5, 0x27, 0x08, 0x3e, 0x2a, 0x6e, 0xf9, 0xf3, 0xc2, 0x97, 0x02, 0xd5, - 0xff, 0x89, 0xed, 0x00, - ], - default_d: [ - 0x23, 0x3c, 0x4a, 0xb8, 0x86, 0xa5, 0x5e, 0x3b, 0xa3, 0x74, 0xc0, - ], - default_pk_d: [ - 0xb6, 0x8e, 0x9e, 0xe0, 0xc0, 0x67, 0x8d, 0x7b, 0x30, 0x36, 0x93, 0x1c, 0x83, 0x1a, - 0x25, 0x25, 0x5f, 0x7e, 0xe4, 0x87, 0x38, 0x5a, 0x30, 0x31, 0x6e, 0x15, 0xf6, 0x48, - 0x2b, 0x87, 0x4f, 0xda, - ], - note_v: 17_811_330_145_809_239_872, - note_r: [ - 0x6e, 0xbb, 0xed, 0x74, 0x36, 0x19, 0xa2, 0x56, 0xf9, 0xad, 0x2e, 0x85, 0x88, 0x0c, - 0xfa, 0xa9, 0x09, 0x8a, 0x5f, 0xdb, 0x16, 0x29, 0x99, 0x0d, 0x9a, 0x7d, 0x3b, 0xb9, - 0x3f, 0xc9, 0x00, 0x03, - ], - note_cmu: [ - 0xd3, 0x76, 0xa7, 0xbe, 0xe8, 0xce, 0x67, 0xf4, 0xef, 0xde, 0x56, 0xaa, 0x77, 0xcf, - 0x64, 0x41, 0x9b, 0x0e, 0x55, 0x0a, 0xbb, 0xcb, 0x8e, 0x2b, 0xcb, 0xda, 0x8b, 0x63, - 0xe4, 0x1d, 0xeb, 0x37, - ], - note_pos: 2_578_461_368, - note_nf: [ - 0x65, 0x36, 0x74, 0x87, 0x3b, 0x3c, 0x67, 0x0c, 0x58, 0x85, 0x84, 0x73, 0xe7, 0xfe, - 0x72, 0x19, 0x72, 0xfb, 0x96, 0xe2, 0x15, 0xb8, 0x73, 0x77, 0xa1, 0x7c, 0xa3, 0x71, - 0x0d, 0x93, 0xc9, 0xe9, - ], - }, -]; diff --git a/zebra-chain/src/orchard/note.rs b/zebra-chain/src/orchard/note.rs index 40de64b14..22923c1be 100644 --- a/zebra-chain/src/orchard/note.rs +++ b/zebra-chain/src/orchard/note.rs @@ -1,25 +1,24 @@ -//! Sapling notes +//! Orchard notes #![allow(clippy::unit_arg)] #![allow(dead_code)] +use halo2::pasta::pallas; + mod ciphertexts; mod nullifiers; #[cfg(any(test, feature = "proptest-impl"))] mod arbitrary; -use crate::{ - amount::{Amount, NonNegative}, - transaction::Memo, -}; +use crate::amount::{Amount, NonNegative}; use super::{ commitment::CommitmentRandomness, keys::{Diversifier, TransmissionKey}, }; -pub use ciphertexts::{EncryptedNote, WrappedNoteKey}; +pub use ciphertexts::EncryptedNote; pub use nullifiers::Nullifier; @@ -35,9 +34,11 @@ pub struct Note { pub transmission_key: TransmissionKey, /// An integer representing the value of the note in zatoshi. pub value: Amount, + /// Used as input to PRF^nf as part of deriving the nullier of the note. + pub rho: pallas::Base, // TODO: refine type + /// Sender-controlled randomness. + pub psi: pallas::Base, // TODO: refine type /// A random commitment trapdoor used to produce the associated /// note commitment. pub rcm: CommitmentRandomness, - /// The note memo, after decryption - pub memo: Memo, } diff --git a/zebra-chain/src/orchard/note/nullifiers.rs b/zebra-chain/src/orchard/note/nullifiers.rs index d7fc14187..37f647b9e 100644 --- a/zebra-chain/src/orchard/note/nullifiers.rs +++ b/zebra-chain/src/orchard/note/nullifiers.rs @@ -1,31 +1,33 @@ #![allow(clippy::unit_arg)] #![allow(dead_code)] -use super::super::{ - commitment::{pedersen_hashes::mixing_pedersen_hash, NoteCommitment}, - keys::NullifierDerivingKey, - tree::Position, -}; +use halo2::pasta::pallas; -/// Invokes Blake2s-256 as PRF^nfSapling to derive the nullifier for a -/// Sapling note. -/// -/// PRF^nfSapling(ρ*) := BLAKE2s-256("Zcash_nf", nk* || ρ*) -/// -/// https://zips.z.cash/protocol/protocol.pdf#concreteprfs -fn prf_nf(nk: [u8; 32], rho: [u8; 32]) -> [u8; 32] { - let hash = blake2s_simd::Params::new() - .hash_length(32) - .personal(b"Zcash_nf") - .to_state() - .update(&nk[..]) - .update(&rho[..]) - .finalize(); +use super::super::{commitment::NoteCommitment, keys::NullifierDerivingKey, tree::Position}; - *hash.as_array() +/// A cryptographic permutation, defined in [poseidonhash]. +/// +/// PoseidonHash(x, y) = f([x, y, 0])_1 (using 1-based indexing). +/// +/// [poseidonhash]: https://zips.z.cash/protocol/nu5.pdf#poseidonhash +fn poseidon_hash(x: pallas::Base, y: pallas::Base) -> pallas::Base { + unimplemented!() } -/// A Nullifier for Sapling transactions +/// Derive the nullifier for a Orchard note. +/// +/// Instantiated using the PoseidonHash hash function defined in [§5.4.1.10 +/// ‘PoseidonHash Function’][poseidon] +/// +/// PRF^nfOrchard(nk*, ρ*) := PoseidonHash(nk*, ρ*) +/// +/// [concreteprfs]: https://zips.z.cash/protocol/protocol.pdf#concreteprfs +/// [poseidonhash]: https://zips.z.cash/protocol/nu5.pdf#poseidonhash +fn prf_nf(nk: [u8; 32], rho: [u8; 32]) -> [u8; 32] { + poseidon_hash(nk, rho) +} + +/// A Nullifier for Orchard transactions #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)] #[cfg_attr( any(test, feature = "proptest-impl"), diff --git a/zebra-chain/src/orchard/commitment/sinsemilla_hashes.rs b/zebra-chain/src/orchard/sinsemilla.rs similarity index 66% rename from zebra-chain/src/orchard/commitment/sinsemilla_hashes.rs rename to zebra-chain/src/orchard/sinsemilla.rs index c244839e2..a3dd1f8e0 100644 --- a/zebra-chain/src/orchard/commitment/sinsemilla_hashes.rs +++ b/zebra-chain/src/orchard/sinsemilla.rs @@ -1,10 +1,81 @@ //! Sinsemilla hash functions and helpers. use bitvec::prelude::*; -use rand_core::{CryptoRng, RngCore}; use halo2::pasta::pallas; +/// GroupHash into Pallas, aka _GroupHash^P_ +/// +/// Produces a random point in the Pallas curve. The first input element acts +/// as a domain separator to distinguish uses of the group hash for different +/// purposes; the second input element is the message. +/// +/// https://zips.z.cash/protocol/protocol.pdf#concretegrouphashpallasandvesta +#[allow(non_snake_case)] +pub fn pallas_group_hash(D: &[u8], M: &[u8]) -> pallas::Point { + pallas::Point::hash_to_curve(D)(M) +} + +/// Q(D) := GroupHash^P(︀“z.cash:SinsemillaQ”, D) +/// +/// https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash +#[allow(non_snake_case)] +fn Q(D: &[u8]) -> pallas::Point { + pallas_group_hash("z.cash:SinsemillaQ", D) +} + +/// S(j) := GroupHash^P(︀“z.cash:SinsemillaS”, LEBS2OSP32(I2LEBSP32(j))) +/// +/// S: {0 .. 2^k - 1} -> P^*, aka 10 bits hashed into the group +/// +/// https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash +// XXX: should j be strictly limited to k=10 bits? +#[allow(non_snake_case)] +fn S(j: [u8; 2]) -> pallas::Point { + pallas_group_hash("z.cash:SinsemillaS", &j) +} + +/// "...an algebraic hash function with collision resistance (for fixed input +/// length) derived from assumed hardness of the Discrete Logarithm Problem on +/// the Pallas curve." +/// +/// SinsemillaHash is used in the definitions of Sinsemilla commitments and of +/// the Sinsemilla hash for the Orchard incremental Merkle tree (§ 5.4.1.3 +/// ‘MerkleCRH^Orchard Hash Function’). +/// +/// https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash +#[allow(non_snake_case)] +// XXX: M is a max of k*c = 2530 bits +pub fn sinsemilla_hash_to_point(D: &[u8], M: &BitVec) -> pallas::Point { + let k = 10; + let c = 253; + + assert!(M.len() <= k * c); + + let mut acc = Q(D); + + // Split M into n segments of k bits, where k = 10 and c = 253, padding + // the last segment with zeros. + // + // https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash + for chunk in M.chunks(k) { + // Pad each chunk with zeros. + let mut store = 0u8; + let bits = store.bits_mut::(); + chunk + .iter() + .enumerate() + .for_each(|(i, bit)| bits.set(i, *bit)); + + // An instance of LEBS2IP_k + let j = &bits.iter().fold(0u16, |j, &bit| j * *2 + bit as u16); + + acc += acc + S(j.to_le_bytes()); + } + + acc +} + /// [Hash Extractor for Pallas][concreteextractorpallas] /// /// P → B^[l^Orchard_Merkle] @@ -19,66 +90,6 @@ pub fn extract_p(point: pallas::Point) -> pallas::Base { } } -/// Q -/// -/// Q(D) := GroupHash^P(︀“z.cash:SinsemillaQ”, D) -/// -/// https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash -#[allow(non_snake_case)] -fn Q(domain: [u8; 8]) -> pallas::Point { - pallas::Point::hash_to_curve("z.cash:SinsemillaQ")(&domain[..]) -} - -/// S -/// -/// S(j) := GroupHash^P(︀“z.cash:SinsemillaS”, LEBS2OSP32(I2LEBSP32(j))) -/// -/// https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash -#[allow(non_snake_case)] -fn S(j: [u8; 2]) -> pallas::Point { - pallas::Point::hash_to_curve("z.cash:SinsemillaS")(&j) -} - -/// "...an algebraic hash function with collision resistance (for fixed input -/// length) derived from assumed hardness of the Discrete Logarithm Problem on -/// the Jubjub curve." -/// -/// SinsemillaHash is used in the definitions of Sinsemilla commitments and of -/// the Sinsemilla hash for the Sapling incremental Merkle tree (§ 5.4.1.3 -/// ‘MerkleCRH^Orchard Hash Function’). -/// -/// https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash -#[allow(non_snake_case)] -pub fn sinsemilla_hash_to_point(domain: [u8; 8], M: &BitVec) -> pallas::Point { - const K: u8 = 10; - const C: u8 = 253; - - assert!(M.len() <= K * C); - - let mut acc = Q(domain); - - // Split M into n segments of k bits, where k = 10 and c = 253, padding - // the last segment with zeros. - // - // https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash - for chunk in M.chunks(K) { - // Pad each chunk with zeros. - let mut store = 0u8; - let bits = store.bits_mut::(); - chunk - .iter() - .enumerate() - .for_each(|(i, bit)| bits.set(i, *bit)); - - // An instance of LEBS2IP_k - let j = &bits.iter().fold(0u16, |j, &bit| j * *2 + bit as u16); - - acc += (acc + S(j.to_le_bytes())); - } - - acc -} - /// Sinsemilla Hash Function /// /// "SinsemillaHash is an algebraic hash function with collision resistance (for @@ -90,19 +101,7 @@ pub fn sinsemilla_hash_to_point(domain: [u8; 8], M: &BitVec) -> pallas /// /// https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash #[allow(non_snake_case)] -pub fn sinsemilla_hash(domain: [u8; 8], M: &BitVec) -> pallas::Base { - extract_p(sinsemilla_hash_to_point(domain, M)) -} - -/// Generates a random scalar from the scalar field 𝔽_{q_P}. -/// -/// https://zips.z.cash/protocol/nu5.pdf#pallasandvesta -pub fn generate_trapdoor(csprng: &mut T) -> pallas::Scalar -where - T: RngCore + CryptoRng, -{ - let mut bytes = [0u8; 64]; - csprng.fill_bytes(&mut bytes); - // Scalar::from_bytes_wide() reduces the input modulo q under the hood. - pallas::Scalar::from_bytes_wide(&bytes) +// XXX: M is a max of k*c = 2530 bits, sinsemilla_hash_to_point checks this +pub fn sinsemilla_hash(D: &[u8], M: &BitVec) -> pallas::Base { + extract_p(sinsemilla_hash_to_point(D, M)) } diff --git a/zebra-chain/src/orchard/tests.rs b/zebra-chain/src/orchard/tests.rs deleted file mode 100644 index 8b1378917..000000000 --- a/zebra-chain/src/orchard/tests.rs +++ /dev/null @@ -1 +0,0 @@ -