Bunch more work implementing orchard, porting from sapling where applicable
This commit is contained in:
parent
40383b2741
commit
c3e40d73cf
|
@ -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};
|
||||
|
|
|
@ -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<T>(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<jubjub::ExtendedPoint> for NoteCommitment {
|
||||
fn from(extended_point: jubjub::ExtendedPoint) -> Self {
|
||||
Self(pallas::Affine::from(extended_point))
|
||||
impl From<pallas::Point> 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<NonNegative>,
|
||||
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<Lsb0, u8> = BitVec::new();
|
||||
unimplemented!();
|
||||
|
||||
// Prefix
|
||||
s.append(&mut bitvec![1; 6]);
|
||||
// // s as in the argument name for WindowedPedersenCommit_r(s)
|
||||
// let mut s: BitVec<Lsb0, u8> = BitVec::new();
|
||||
|
||||
// Jubjub repr_J canonical byte encoding
|
||||
// https://zips.z.cash/protocol/protocol.pdf#jubjub
|
||||
//
|
||||
// The `TryFrom<Diversifier>` 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<Diversifier>` 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::<Lsb0, u8>::from_slice(&g_d_bytes[..]));
|
||||
s.append(&mut BitVec::<Lsb0, u8>::from_slice(&pk_d_bytes[..]));
|
||||
s.append(&mut BitVec::<Lsb0, u8>::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::<Lsb0, u8>::from_slice(&g_d_bytes[..]));
|
||||
// s.append(&mut BitVec::<Lsb0, u8>::from_slice(&pk_d_bytes[..]));
|
||||
// s.append(&mut BitVec::<Lsb0, u8>::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<ValueCommitment> 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<jubjub::ExtendedPoint> for ValueCommitment {
|
||||
fn from(extended_point: jubjub::ExtendedPoint) -> Self {
|
||||
Self(pallas::Affine::from(extended_point))
|
||||
impl From<pallas::Point> 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<ValueCommitment> 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,
|
||||
|
|
|
@ -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<Lsb0, u8>) -> 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::<Lsb0>();
|
||||
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<Lsb0, u8>) -> 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<Lsb0, u8>) -> 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<Lsb0, u8>) -> 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<T>(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)
|
||||
}
|
|
@ -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<T: AsRef<[u8]>>(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<Lsb0, u8>,
|
||||
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"
|
||||
),
|
||||
},
|
||||
];
|
||||
}
|
|
@ -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<pallas::Point> {
|
||||
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<SpendAuthorizingKey> for [u8; 32] {
|
|||
}
|
||||
|
||||
impl From<SpendingKey> 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<ProofAuthorizingKey> for [u8; 32] {
|
||||
fn from(nsk: ProofAuthorizingKey) -> Self {
|
||||
nsk.0.to_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpendingKey> 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<OutgoingViewingKey> for [u8; 32] {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<SpendingKey> for OutgoingViewingKey {
|
||||
/// For this invocation of Blake2b-512 as _PRF^expand_, t=2.
|
||||
impl From<FullViewingKey> 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<SpendAuth>);
|
||||
pub struct SpendValidatingKey(pub redpallas::VerificationKey<SpendAuth>);
|
||||
|
||||
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<AuthorizingKey> for [u8; 32] {
|
||||
fn from(ak: AuthorizingKey) -> [u8; 32] {
|
||||
impl From<SpendValidatingKey> for [u8; 32] {
|
||||
fn from(ak: SpendValidatingKey) -> [u8; 32] {
|
||||
ak.0.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpendAuthorizingKey> for AuthorizingKey {
|
||||
impl From<SpendAuthorizingKey> for SpendValidatingKey {
|
||||
fn from(ask: SpendAuthorizingKey) -> Self {
|
||||
let sk = redjubjub::SigningKey::<SpendAuth>::try_from(<[u8; 32]>::from(ask)).unwrap();
|
||||
Self(redjubjub::VerificationKey::from(&sk))
|
||||
let sk = redpallas::SigningKey::<SpendAuth>::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<ProofAuthorizingKey> for NullifierDerivingKey {
|
||||
impl From<SpendingKey> 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<ExtendedPoint> 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<Diversifier> for [u8; 11] {
|
|||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Diversifier> for jubjub::AffinePoint {
|
||||
impl TryFrom<Diversifier> 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<Self, Self::Error> {
|
||||
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<Diversifier> for pallas::Point {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(d: Diversifier) -> Result<Self, Self::Error> {
|
||||
let possible_point = diversify_hash(d.0);
|
||||
|
||||
if let Some(point) = possible_point {
|
||||
Ok(point)
|
||||
} else {
|
||||
Err("Invalid Diversifier -> pallas::Point")
|
||||
}
|
||||
impl From<Diversifier> 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<SpendingKey> 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<SpendingKey> 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<T>(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<TransmissionKey> 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::<u8>::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<Self, Self::Error> {
|
||||
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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
],
|
||||
},
|
||||
];
|
|
@ -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<NonNegative>,
|
||||
/// 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,
|
||||
}
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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<Lsb0, u8>) -> 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::<Lsb0>();
|
||||
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<Lsb0, u8>) -> 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::<Lsb0>();
|
||||
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<Lsb0, u8>) -> pallas
|
|||
///
|
||||
/// https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash
|
||||
#[allow(non_snake_case)]
|
||||
pub fn sinsemilla_hash(domain: [u8; 8], M: &BitVec<Lsb0, u8>) -> 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<T>(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<Lsb0, u8>) -> pallas::Base {
|
||||
extract_p(sinsemilla_hash_to_point(D, M))
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
|
Loading…
Reference in New Issue