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"))]
|
#[cfg(any(test, feature = "proptest-impl"))]
|
||||||
mod arbitrary;
|
mod arbitrary;
|
||||||
mod commitment;
|
mod commitment;
|
||||||
mod note;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests;
|
|
||||||
|
|
||||||
pub mod keys;
|
pub mod keys;
|
||||||
|
mod note;
|
||||||
|
mod sinsemilla;
|
||||||
pub mod tree;
|
pub mod tree;
|
||||||
|
|
||||||
pub use action::Action;
|
pub use action::Action;
|
||||||
pub use address::Address;
|
pub use address::Address;
|
||||||
pub use commitment::{CommitmentRandomness, NoteCommitment, ValueCommitment};
|
pub use commitment::{CommitmentRandomness, NoteCommitment, ValueCommitment};
|
||||||
pub use keys::Diversifier;
|
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.
|
//! Note and value commitments.
|
||||||
|
|
||||||
#[cfg(test)]
|
// #[cfg(test)]
|
||||||
mod test_vectors;
|
// mod test_vectors;
|
||||||
|
|
||||||
pub mod pedersen_hashes;
|
pub mod sinsemilla_hashes;
|
||||||
|
|
||||||
use std::{convert::TryFrom, fmt, io};
|
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.
|
/// The randomness used in the Simsemilla Hash for note commitment.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[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 {
|
impl fmt::Debug for NoteCommitment {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_struct("NoteCommitment")
|
f.debug_struct("NoteCommitment")
|
||||||
.field("u", &hex::encode(self.0.get_u().to_bytes()))
|
.field("x", &hex::encode(self.0.get_x().to_bytes()))
|
||||||
.field("v", &hex::encode(self.0.get_v().to_bytes()))
|
.field("y", &hex::encode(self.0.get_y().to_bytes()))
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for NoteCommitment {}
|
impl Eq for NoteCommitment {}
|
||||||
|
|
||||||
impl From<jubjub::ExtendedPoint> for NoteCommitment {
|
impl From<pallas::Point> for NoteCommitment {
|
||||||
fn from(extended_point: jubjub::ExtendedPoint) -> Self {
|
fn from(projective_point: pallas::Point) -> Self {
|
||||||
Self(pallas::Affine::from(extended_point))
|
Self(pallas::Affine::from(projective_point))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,11 +85,10 @@ impl NoteCommitment {
|
||||||
/// Generate a new _NoteCommitment_ and the randomness used to create it.
|
/// Generate a new _NoteCommitment_ and the randomness used to create it.
|
||||||
///
|
///
|
||||||
/// We return the randomness because it is needed to construct a _Note_,
|
/// 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.
|
/// higher level function that calls `NoteCommit^Orchard_rcm` internally.
|
||||||
///
|
///
|
||||||
/// NoteCommit^Orchard_rcm (g*_d , pk*_d , v) :=
|
/// NoteCommit^Orchard_rcm(repr_P(gd),repr_P(pkd), v, ρ, ψ) :=
|
||||||
/// WindowedPedersenCommit_rcm([1; 6] || I2LEBSP_64(v) || g*_d || pk*_d)
|
|
||||||
///
|
///
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#concretewindowedcommit
|
/// https://zips.z.cash/protocol/protocol.pdf#concretewindowedcommit
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
@ -84,48 +97,42 @@ impl NoteCommitment {
|
||||||
diversifier: Diversifier,
|
diversifier: Diversifier,
|
||||||
transmission_key: TransmissionKey,
|
transmission_key: TransmissionKey,
|
||||||
value: Amount<NonNegative>,
|
value: Amount<NonNegative>,
|
||||||
|
rho: pallas::Base,
|
||||||
|
psi: pallas::Base,
|
||||||
) -> Option<(CommitmentRandomness, Self)>
|
) -> Option<(CommitmentRandomness, Self)>
|
||||||
where
|
where
|
||||||
T: RngCore + CryptoRng,
|
T: RngCore + CryptoRng,
|
||||||
{
|
{
|
||||||
// s as in the argument name for WindowedPedersenCommit_r(s)
|
unimplemented!();
|
||||||
let mut s: BitVec<Lsb0, u8> = BitVec::new();
|
|
||||||
|
|
||||||
// Prefix
|
// // s as in the argument name for WindowedPedersenCommit_r(s)
|
||||||
s.append(&mut bitvec![1; 6]);
|
// let mut s: BitVec<Lsb0, u8> = BitVec::new();
|
||||||
|
|
||||||
// Jubjub repr_J canonical byte encoding
|
// // Prefix
|
||||||
// https://zips.z.cash/protocol/protocol.pdf#jubjub
|
// s.append(&mut bitvec![1; 6]);
|
||||||
//
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
let pk_d_bytes = <[u8; 32]>::from(transmission_key);
|
// // The `TryFrom<Diversifier>` impls for the `jubjub::*Point`s handles
|
||||||
let v_bytes = value.to_bytes();
|
// // 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[..]));
|
// let pk_d_bytes = <[u8; 32]>::from(transmission_key);
|
||||||
s.append(&mut BitVec::<Lsb0, u8>::from_slice(&pk_d_bytes[..]));
|
// let v_bytes = value.to_bytes();
|
||||||
s.append(&mut BitVec::<Lsb0, u8>::from_slice(&v_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((
|
// let rcm = CommitmentRandomness(generate_trapdoor(csprng));
|
||||||
rcm,
|
|
||||||
NoteCommitment::from(windowed_pedersen_commitment(rcm.0, &s)),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Hash Extractor for Pallas (?)
|
// Some((
|
||||||
///
|
// rcm,
|
||||||
/// https://zips.z.cash/protocol/nu5.pdf#concreteextractorpallas
|
// NoteCommitment::from(windowed_pedersen_commitment(rcm.0, &s)),
|
||||||
pub fn extract_x(&self) -> pallas::Base {
|
// ))
|
||||||
self.0.get_u()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,24 +169,23 @@ impl std::ops::AddAssign<ValueCommitment> for ValueCommitment {
|
||||||
impl fmt::Debug for ValueCommitment {
|
impl fmt::Debug for ValueCommitment {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_struct("ValueCommitment")
|
f.debug_struct("ValueCommitment")
|
||||||
.field("u", &hex::encode(self.0.get_u().to_bytes()))
|
.field("x", &hex::encode(self.0.get_x().to_bytes()))
|
||||||
.field("v", &hex::encode(self.0.get_v().to_bytes()))
|
.field("y", &hex::encode(self.0.get_y().to_bytes()))
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<jubjub::ExtendedPoint> for ValueCommitment {
|
impl From<pallas::Point> for ValueCommitment {
|
||||||
fn from(extended_point: jubjub::ExtendedPoint) -> Self {
|
fn from(projective_point: pallas::Point) -> Self {
|
||||||
Self(pallas::Affine::from(extended_point))
|
Self(pallas::Affine::from(projective_point))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for ValueCommitment {}
|
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#pallasandvesta
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#jubjub
|
|
||||||
impl From<ValueCommitment> for [u8; 32] {
|
impl From<ValueCommitment> for [u8; 32] {
|
||||||
fn from(cm: ValueCommitment) -> [u8; 32] {
|
fn from(cm: ValueCommitment) -> [u8; 32] {
|
||||||
cm.0.to_bytes()
|
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#pallasandvesta
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#jubjub
|
|
||||||
impl TryFrom<[u8; 32]> for ValueCommitment {
|
impl TryFrom<[u8; 32]> for ValueCommitment {
|
||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
|
|
||||||
|
@ -266,15 +271,17 @@ impl ValueCommitment {
|
||||||
|
|
||||||
/// Generate a new _ValueCommitment_ from an existing _rcv_ on a _value_.
|
/// Generate a new _ValueCommitment_ from an existing _rcv_ on a _value_.
|
||||||
///
|
///
|
||||||
|
/// ValueCommit^Orchard(v) :=
|
||||||
|
///
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#concretehomomorphiccommit
|
/// https://zips.z.cash/protocol/protocol.pdf#concretehomomorphiccommit
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn new(rcv: jubjub::Fr, value: Amount) -> Self {
|
pub fn new(rcv: pallas::Scalar, value: Amount) -> Self {
|
||||||
let v = jubjub::Fr::from(value);
|
let v = pallas::Scalar::from(value);
|
||||||
|
|
||||||
// TODO: These generator points can be generated once somewhere else to
|
// TODO: These generator points can be generated once somewhere else to
|
||||||
// avoid having to recompute them on every new commitment.
|
// avoid having to recompute them on every new commitment.
|
||||||
let V = find_group_hash(*b"z.cash:Orchard-cv", b"v");
|
let V = pallas_group_hash(*b"z.cash:Orchard-cv", b"v");
|
||||||
let R = find_group_hash(*b"z.cash:Orchard-cv", b"r");
|
let R = pallas_group_hash(*b"z.cash:Orchard-cv", b"r");
|
||||||
|
|
||||||
Self::from(V * v + R * rcv)
|
Self::from(V * v + R * rcv)
|
||||||
}
|
}
|
||||||
|
@ -288,19 +295,21 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pedersen_hash_to_point_test_vectors() {
|
fn sinsemilla_hash_to_point_test_vectors() {
|
||||||
zebra_test::init();
|
zebra_test::init();
|
||||||
|
|
||||||
const D: [u8; 8] = *b"Zcash_PH";
|
const D: [u8; 8] = *b"Zcash_PH";
|
||||||
|
|
||||||
for test_vector in test_vectors::TEST_VECTORS.iter() {
|
for test_vector in test_vectors::TEST_VECTORS.iter() {
|
||||||
let result =
|
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);
|
assert_eq!(result, test_vector.output_point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: these test vectors for ops are from Jubjub, replace with Pallas ones
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add() {
|
fn add() {
|
||||||
zebra_test::init();
|
zebra_test::init();
|
||||||
|
@ -308,13 +317,13 @@ mod tests {
|
||||||
let identity = ValueCommitment(pallas::Affine::identity());
|
let identity = ValueCommitment(pallas::Affine::identity());
|
||||||
|
|
||||||
let g = ValueCommitment(pallas::Affine::from_raw_unchecked(
|
let g = ValueCommitment(pallas::Affine::from_raw_unchecked(
|
||||||
jubjub::Fq::from_raw([
|
pallas::Base::from_raw([
|
||||||
0xe4b3_d35d_f1a7_adfe,
|
0xe4b3_d35d_f1a7_adfe,
|
||||||
0xcaf5_5d1b_29bf_81af,
|
0xcaf5_5d1b_29bf_81af,
|
||||||
0x8b0f_03dd_d60a_8187,
|
0x8b0f_03dd_d60a_8187,
|
||||||
0x62ed_cbb8_bf37_87c8,
|
0x62ed_cbb8_bf37_87c8,
|
||||||
]),
|
]),
|
||||||
jubjub::Fq::from_raw([
|
pallas::Base::from_raw([
|
||||||
0x0000_0000_0000_000b,
|
0x0000_0000_0000_000b,
|
||||||
0x0000_0000_0000_0000,
|
0x0000_0000_0000_0000,
|
||||||
0x0000_0000_0000_0000,
|
0x0000_0000_0000_0000,
|
||||||
|
@ -332,13 +341,13 @@ mod tests {
|
||||||
let mut identity = ValueCommitment(pallas::Affine::identity());
|
let mut identity = ValueCommitment(pallas::Affine::identity());
|
||||||
|
|
||||||
let g = ValueCommitment(pallas::Affine::from_raw_unchecked(
|
let g = ValueCommitment(pallas::Affine::from_raw_unchecked(
|
||||||
jubjub::Fq::from_raw([
|
pallas::Base::from_raw([
|
||||||
0xe4b3_d35d_f1a7_adfe,
|
0xe4b3_d35d_f1a7_adfe,
|
||||||
0xcaf5_5d1b_29bf_81af,
|
0xcaf5_5d1b_29bf_81af,
|
||||||
0x8b0f_03dd_d60a_8187,
|
0x8b0f_03dd_d60a_8187,
|
||||||
0x62ed_cbb8_bf37_87c8,
|
0x62ed_cbb8_bf37_87c8,
|
||||||
]),
|
]),
|
||||||
jubjub::Fq::from_raw([
|
pallas::Base::from_raw([
|
||||||
0x0000_0000_0000_000b,
|
0x0000_0000_0000_000b,
|
||||||
0x0000_0000_0000_0000,
|
0x0000_0000_0000_0000,
|
||||||
0x0000_0000_0000_0000,
|
0x0000_0000_0000_0000,
|
||||||
|
@ -357,13 +366,13 @@ mod tests {
|
||||||
zebra_test::init();
|
zebra_test::init();
|
||||||
|
|
||||||
let g_point = pallas::Affine::from_raw_unchecked(
|
let g_point = pallas::Affine::from_raw_unchecked(
|
||||||
jubjub::Fq::from_raw([
|
pallas::Base::from_raw([
|
||||||
0xe4b3_d35d_f1a7_adfe,
|
0xe4b3_d35d_f1a7_adfe,
|
||||||
0xcaf5_5d1b_29bf_81af,
|
0xcaf5_5d1b_29bf_81af,
|
||||||
0x8b0f_03dd_d60a_8187,
|
0x8b0f_03dd_d60a_8187,
|
||||||
0x62ed_cbb8_bf37_87c8,
|
0x62ed_cbb8_bf37_87c8,
|
||||||
]),
|
]),
|
||||||
jubjub::Fq::from_raw([
|
pallas::Base::from_raw([
|
||||||
0x0000_0000_0000_000b,
|
0x0000_0000_0000_000b,
|
||||||
0x0000_0000_0000_0000,
|
0x0000_0000_0000_0000,
|
||||||
0x0000_0000_0000_0000,
|
0x0000_0000_0000_0000,
|
||||||
|
@ -383,13 +392,13 @@ mod tests {
|
||||||
zebra_test::init();
|
zebra_test::init();
|
||||||
|
|
||||||
let g_point = pallas::Affine::from_raw_unchecked(
|
let g_point = pallas::Affine::from_raw_unchecked(
|
||||||
jubjub::Fq::from_raw([
|
pallas::Base::from_raw([
|
||||||
0xe4b3_d35d_f1a7_adfe,
|
0xe4b3_d35d_f1a7_adfe,
|
||||||
0xcaf5_5d1b_29bf_81af,
|
0xcaf5_5d1b_29bf_81af,
|
||||||
0x8b0f_03dd_d60a_8187,
|
0x8b0f_03dd_d60a_8187,
|
||||||
0x62ed_cbb8_bf37_87c8,
|
0x62ed_cbb8_bf37_87c8,
|
||||||
]),
|
]),
|
||||||
jubjub::Fq::from_raw([
|
pallas::Base::from_raw([
|
||||||
0x0000_0000_0000_000b,
|
0x0000_0000_0000_000b,
|
||||||
0x0000_0000_0000_0000,
|
0x0000_0000_0000_0000,
|
||||||
0x0000_0000_0000_0000,
|
0x0000_0000_0000_0000,
|
||||||
|
@ -412,13 +421,13 @@ mod tests {
|
||||||
zebra_test::init();
|
zebra_test::init();
|
||||||
|
|
||||||
let g_point = pallas::Affine::from_raw_unchecked(
|
let g_point = pallas::Affine::from_raw_unchecked(
|
||||||
jubjub::Fq::from_raw([
|
pallas::Base::from_raw([
|
||||||
0xe4b3_d35d_f1a7_adfe,
|
0xe4b3_d35d_f1a7_adfe,
|
||||||
0xcaf5_5d1b_29bf_81af,
|
0xcaf5_5d1b_29bf_81af,
|
||||||
0x8b0f_03dd_d60a_8187,
|
0x8b0f_03dd_d60a_8187,
|
||||||
0x62ed_cbb8_bf37_87c8,
|
0x62ed_cbb8_bf37_87c8,
|
||||||
]),
|
]),
|
||||||
jubjub::Fq::from_raw([
|
pallas::Base::from_raw([
|
||||||
0x0000_0000_0000_000b,
|
0x0000_0000_0000_000b,
|
||||||
0x0000_0000_0000_0000,
|
0x0000_0000_0000_0000,
|
||||||
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 bech32::{self, FromBase32, ToBase32, Variant};
|
||||||
|
use halo2::pasta::pallas;
|
||||||
use rand_core::{CryptoRng, RngCore};
|
use rand_core::{CryptoRng, RngCore};
|
||||||
|
|
||||||
use crate::{
|
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
|
/// 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()
|
let hash = blake2b_simd::Params::new()
|
||||||
.hash_length(32)
|
.hash_length(32)
|
||||||
.personal(b"Zcash_Orchardock")
|
.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()
|
*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.
|
/// 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
|
/// https://zips.z.cash/protocol/protocol.pdf#concretediversifyhash
|
||||||
fn diversify_hash(d: [u8; 11]) -> Option<pallas::Point> {
|
fn diversify_hash(d: &[u8]) -> pallas::Point {
|
||||||
jubjub_group_hash(*b"Zcash_gd", &d)
|
pallas_group_hash(*b"z.cash:Orchard-gd", &d)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: replace with reference to redjubjub or jubjub when merged and
|
/// Magic human-readable strings used to identify what networks Orchard spending
|
||||||
// exported.
|
/// keys are associated with when encoded/decoded with bech32.
|
||||||
type Scalar = jubjub::Fr;
|
///
|
||||||
|
/// [orchardspendingkeyencoding]: https://zips.z.cash/protocol/nu5.pdf#orchardspendingkeyencoding
|
||||||
/// Magic human-readable strings used to identify what networks
|
|
||||||
/// Sapling Spending Keys are associated with when encoded/decoded
|
|
||||||
/// with bech32.
|
|
||||||
mod sk_hrp {
|
mod sk_hrp {
|
||||||
pub const MAINNET: &str = "secret-spending-key-main";
|
pub const MAINNET: &str = "secret-orchard-sk-main";
|
||||||
pub const TESTNET: &str = "secret-spending-key-test";
|
pub const TESTNET: &str = "secret-orchard-sk-test";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A _Spending Key_, as described in [protocol specification
|
/// A spending key, as described in [protocol specification §4.2.3][ps].
|
||||||
/// §4.2.2][ps].
|
|
||||||
///
|
///
|
||||||
/// Our root secret key of the Sapling key derivation tree. All other
|
/// Our root secret key of the Orchard key derivation tree. All other Orchard
|
||||||
/// Sapling key types derive from the SpendingKey value.
|
/// 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)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
any(test, feature = "proptest-impl"),
|
any(test, feature = "proptest-impl"),
|
||||||
|
@ -159,15 +163,15 @@ impl SpendingKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A _Spend Authorizing Key_, as described in [protocol specification
|
/// A Spend authorizing key (_ask_), as described in [protocol specification
|
||||||
/// §4.2.2][ps].
|
/// §4.2.3][orchardkeycomponents].
|
||||||
///
|
///
|
||||||
/// Used to generate _spend authorization randomizers_ to sign each
|
/// Used to generate _spend authorization randomizers_ to sign each _Spend
|
||||||
/// _Spend Description_, proving ownership of notes.
|
/// 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)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
pub struct SpendAuthorizingKey(pub Scalar);
|
pub struct SpendAuthorizingKey(pub pallas::Scalar);
|
||||||
|
|
||||||
impl fmt::Debug for SpendAuthorizingKey {
|
impl fmt::Debug for SpendAuthorizingKey {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
@ -184,15 +188,18 @@ impl From<SpendAuthorizingKey> for [u8; 32] {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SpendingKey> for SpendAuthorizingKey {
|
impl From<SpendingKey> for SpendAuthorizingKey {
|
||||||
/// Invokes Blake2b-512 as _PRF^expand_, t=0, to derive a
|
/// Invokes Blake2b-512 as _PRF^expand_, t=6, to derive a
|
||||||
/// SpendAuthorizingKey from a SpendingKey.
|
/// `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
|
/// https://zips.z.cash/protocol/protocol.pdf#concreteprfs
|
||||||
fn from(spending_key: SpendingKey) -> SpendAuthorizingKey {
|
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
|
/// An outgoing viewing key, as described in [protocol specification
|
||||||
/// §4.2.2][ps].
|
/// §4.2.3][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].
|
|
||||||
///
|
///
|
||||||
/// Used to decrypt outgoing notes without spending them.
|
/// 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)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
pub struct OutgoingViewingKey(pub [u8; 32]);
|
pub struct OutgoingViewingKey(pub [u8; 32]);
|
||||||
|
|
||||||
|
@ -261,7 +227,7 @@ impl fmt::Debug for OutgoingViewingKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<[u8; 32]> 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 {
|
fn from(bytes: [u8; 32]) -> Self {
|
||||||
Self(bytes)
|
Self(bytes)
|
||||||
}
|
}
|
||||||
|
@ -273,18 +239,18 @@ impl From<OutgoingViewingKey> for [u8; 32] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SpendingKey> for OutgoingViewingKey {
|
impl From<FullViewingKey> for OutgoingViewingKey {
|
||||||
/// For this invocation of Blake2b-512 as _PRF^expand_, t=2.
|
/// Derive an `OutgoingViewingKey` from a `FullViewingKey`.
|
||||||
///
|
///
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
|
/// let 𝐾 = I2LEBSPℓsk(rivk)
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#concreteprfs
|
/// 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 {
|
fn from(spending_key: SpendingKey) -> OutgoingViewingKey {
|
||||||
let hash_bytes = prf_expand(spending_key.bytes, &[2]);
|
unimplemented!()
|
||||||
|
|
||||||
let mut bytes = [0u8; 32];
|
|
||||||
bytes[..].copy_from_slice(&hash_bytes[0..32]);
|
|
||||||
|
|
||||||
Self(bytes)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,57 +260,56 @@ impl PartialEq<[u8; 32]> for OutgoingViewingKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An _Authorizing Key_, as described in [protocol specification
|
/// A Spend validating key, as described in [protocol specification §4.2.3][orchardkeycomponents].
|
||||||
/// §4.2.2][ps].
|
|
||||||
///
|
///
|
||||||
/// Used to validate _Spend Authorization Signatures_, proving
|
/// Used to validate Orchard _Spend Authorization Signatures_, proving ownership
|
||||||
/// ownership of notes.
|
/// of notes.
|
||||||
///
|
///
|
||||||
/// [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
|
/// [orchardkeycomponents]: https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[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 {
|
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] {
|
impl From<SpendValidatingKey> for [u8; 32] {
|
||||||
fn from(ak: AuthorizingKey) -> [u8; 32] {
|
fn from(ak: SpendValidatingKey) -> [u8; 32] {
|
||||||
ak.0.into()
|
ak.0.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SpendAuthorizingKey> for AuthorizingKey {
|
impl From<SpendAuthorizingKey> for SpendValidatingKey {
|
||||||
fn from(ask: SpendAuthorizingKey) -> Self {
|
fn from(ask: SpendAuthorizingKey) -> Self {
|
||||||
let sk = redjubjub::SigningKey::<SpendAuth>::try_from(<[u8; 32]>::from(ask)).unwrap();
|
let sk = redpallas::SigningKey::<SpendAuth>::try_from(<[u8; 32]>::from(ask)).unwrap();
|
||||||
Self(redjubjub::VerificationKey::from(&sk))
|
Self(redpallas::VerificationKey::from(&sk))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for AuthorizingKey {
|
impl PartialEq for SpendValidatingKey {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
<[u8; 32]>::from(self.0) == <[u8; 32]>::from(other.0)
|
<[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 {
|
fn eq(&self, other: &[u8; 32]) -> bool {
|
||||||
<[u8; 32]>::from(self.0) == *other
|
<[u8; 32]>::from(self.0) == *other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A _Nullifier Deriving Key_, as described in [protocol
|
/// A Orchard nullifier deriving key, as described in [protocol specification
|
||||||
/// specification §4.2.2][ps].
|
/// §4.2.3][orchardkeycomponents].
|
||||||
///
|
///
|
||||||
/// Used to create a _Nullifier_ per note.
|
/// 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)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub struct NullifierDerivingKey(pub jubjub::AffinePoint);
|
pub struct NullifierDerivingKey(pub pallas::Base);
|
||||||
|
|
||||||
impl fmt::Debug for NullifierDerivingKey {
|
impl fmt::Debug for NullifierDerivingKey {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
@ -357,7 +322,7 @@ impl fmt::Debug for NullifierDerivingKey {
|
||||||
|
|
||||||
impl From<[u8; 32]> for NullifierDerivingKey {
|
impl From<[u8; 32]> for NullifierDerivingKey {
|
||||||
fn from(bytes: [u8; 32]) -> Self {
|
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
|
/// Requires JubJub's _FindGroupHash^J("Zcash_H_", "")_, then uses
|
||||||
/// the resulting generator point to scalar multiply the
|
/// the resulting generator point to scalar multiply the
|
||||||
/// ProofAuthorizingKey into the new NullifierDerivingKey
|
/// 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#orchardkeycomponents
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
|
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#concretegrouphashjubjub
|
/// https://zips.z.cash/protocol/protocol.pdf#concretegrouphashjubjub
|
||||||
fn from(nsk: ProofAuthorizingKey) -> Self {
|
fn from(sk: SpendingKey) -> Self {
|
||||||
// Should this point, when generated, be fixed for the rest of
|
let generator_point = prf_expand(sk, []);
|
||||||
// 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();
|
|
||||||
|
|
||||||
// TODO: impl Mul<ExtendedPoint> for Fr, so we can reverse
|
Self(pallas::Affine::from(generator_point * sk.0))
|
||||||
// this to match the math in the spec / general scalar mult
|
|
||||||
// notation convention.
|
|
||||||
Self(jubjub::AffinePoint::from(generator_point * nsk.0))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,24 +360,36 @@ impl PartialEq<[u8; 32]> for NullifierDerivingKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Magic human-readable strings used to identify what networks
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
/// Sapling IncomingViewingKeys are associated with when
|
pub struct IvkCommitRandomness(pallas::Scalar);
|
||||||
/// encoded/decoded with bech32.
|
|
||||||
|
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 {
|
mod ivk_hrp {
|
||||||
pub const MAINNET: &str = "zivks";
|
pub const MAINNET: &str = "zivko";
|
||||||
pub const TESTNET: &str = "zivktestsapling";
|
pub const TESTNET: &str = "zivktestorchard";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An _Incoming Viewing Key_, as described in [protocol specification
|
/// 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.
|
/// 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)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
pub struct IncomingViewingKey {
|
pub struct IncomingViewingKey {
|
||||||
network: Network,
|
network: Network,
|
||||||
scalar: Scalar,
|
scalar: pallas::Scalar,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: impl a From that accepts a Network?
|
// TODO: impl a From that accepts a Network?
|
||||||
|
@ -446,38 +416,24 @@ impl fmt::Display for IncomingViewingKey {
|
||||||
impl From<[u8; 32]> for IncomingViewingKey {
|
impl From<[u8; 32]> for IncomingViewingKey {
|
||||||
/// Generate an _IncomingViewingKey_ from existing bytes.
|
/// Generate an _IncomingViewingKey_ from existing bytes.
|
||||||
fn from(mut bytes: [u8; 32]) -> Self {
|
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 {
|
Self {
|
||||||
// TODO: handle setting the Network better.
|
// TODO: handle setting the Network better.
|
||||||
network: Network::default(),
|
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_.
|
/// 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#concreteprfs
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#jubjub
|
|
||||||
// TODO: return None if ivk = 0
|
fn from((ask, nk): (SpendValidatingKey, NullifierDerivingKey)) -> Self {
|
||||||
//
|
unimplemented!();
|
||||||
// "If ivk = 0, discard this key and start over with a new
|
|
||||||
// [spending key]." - [§4.2.2][ps]
|
let hash_bytes = commit_ivk(ask.into(), nk.into());
|
||||||
//
|
|
||||||
// [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());
|
|
||||||
|
|
||||||
IncomingViewingKey::from(hash_bytes)
|
IncomingViewingKey::from(hash_bytes)
|
||||||
}
|
}
|
||||||
|
@ -499,7 +455,7 @@ impl FromStr for IncomingViewingKey {
|
||||||
ivk_hrp::MAINNET => Network::Mainnet,
|
ivk_hrp::MAINNET => Network::Mainnet,
|
||||||
_ => Network::Testnet,
|
_ => Network::Testnet,
|
||||||
},
|
},
|
||||||
scalar: Scalar::from_bytes(&scalar_bytes).unwrap(),
|
scalar: pallas::Scalar::from_bytes(&scalar_bytes).unwrap(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => Err(SerializationError::Parse("bech32 decoding error")),
|
_ => 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
|
/// Combined with an _IncomingViewingKey_, produces a _diversified
|
||||||
/// payment address_.
|
/// 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)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
any(test, feature = "proptest-impl"),
|
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;
|
type Error = &'static str;
|
||||||
|
|
||||||
/// Get a diversified base point from a diversifier value in affine
|
/// Get a diversified base point from a diversifier value in affine
|
||||||
/// representation.
|
/// representation.
|
||||||
fn try_from(d: Diversifier) -> Result<Self, Self::Error> {
|
fn try_from(d: Diversifier) -> Result<Self, Self::Error> {
|
||||||
if let Ok(extended_point) = pallas::Point::try_from(d) {
|
if let Ok(projective_point) = pallas::Point::try_from(d) {
|
||||||
Ok(extended_point.into())
|
Ok(projective_point.into())
|
||||||
} else {
|
} else {
|
||||||
Err("Invalid Diversifier -> jubjub::AffinePoint")
|
Err("Invalid Diversifier -> pallas::Affine")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Diversifier> for pallas::Point {
|
impl From<Diversifier> for pallas::Point {
|
||||||
type Error = &'static str;
|
/// g_d := DiversifyHash^Orchard(d)
|
||||||
|
///
|
||||||
fn try_from(d: Diversifier) -> Result<Self, Self::Error> {
|
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
|
||||||
let possible_point = diversify_hash(d.0);
|
fn from(d: Diversifier) -> Self {
|
||||||
|
diversify_hash(d.0)
|
||||||
if let Some(point) = possible_point {
|
|
||||||
Ok(point)
|
|
||||||
} else {
|
|
||||||
Err("Invalid Diversifier -> pallas::Point")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SpendingKey> for Diversifier {
|
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
|
/// 'For each spending key, there is also a default diversified
|
||||||
/// payment address with a “random-looking” diversifier. This
|
/// 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
|
/// that cannot be distinguished (without knowledge of the
|
||||||
/// spending key) from one with a random diversifier...'
|
/// 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 {
|
fn from(sk: SpendingKey) -> Diversifier {
|
||||||
let mut i = 0u8;
|
// Needs FF1-AES permutation
|
||||||
|
unimplemented!()
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,47 +552,39 @@ impl PartialEq<[u8; 11]> for Diversifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Diversifier {
|
impl Diversifier {
|
||||||
/// Generate a new _Diversifier_ that has already been confirmed
|
/// Generate a new `Diversifier`.
|
||||||
/// as a preimage to a valid diversified base point when used to
|
|
||||||
/// derive a diversified payment address.
|
|
||||||
///
|
///
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
|
/// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#concretediversifyhash
|
|
||||||
pub fn new<T>(csprng: &mut T) -> Self
|
pub fn new<T>(csprng: &mut T) -> Self
|
||||||
where
|
where
|
||||||
T: RngCore + CryptoRng,
|
T: RngCore + CryptoRng,
|
||||||
{
|
{
|
||||||
loop {
|
let mut bytes = [0u8; 11];
|
||||||
let mut bytes = [0u8; 11];
|
csprng.fill_bytes(&mut bytes);
|
||||||
csprng.fill_bytes(&mut bytes);
|
|
||||||
|
|
||||||
if diversify_hash(bytes).is_some() {
|
Self::from(bytes)
|
||||||
break Self(bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A (diversified) _TransmissionKey_
|
/// A (diversified) transmission Key
|
||||||
///
|
///
|
||||||
/// In Sapling, secrets need to be transmitted to a recipient of funds
|
/// In Orchard, secrets need to be transmitted to a recipient of funds in order
|
||||||
/// in order for them to be later spent. To transmit these secrets
|
/// for them to be later spent. To transmit these secrets securely to a
|
||||||
/// securely to a recipient without requiring an out-of-band
|
/// recipient without requiring an out-of-band communication channel, the
|
||||||
/// communication channel, the diversified transmission key is used to
|
/// transmission key is used to encrypt them.
|
||||||
/// encrypt them.
|
|
||||||
///
|
///
|
||||||
/// Derived by multiplying a JubJub point [derived][ps] from a
|
/// Derived by multiplying a Pallas point [derived][ps] from a `Diversifier` by
|
||||||
/// _Diversifier_ by the _IncomingViewingKey_ scalar.
|
/// the `IncomingViewingKey` scalar.
|
||||||
///
|
///
|
||||||
/// [ps]: https://zips.z.cash/protocol/protocol.pdf#concretediversifyhash
|
/// [ps]: https://zips.z.cash/protocol/protocol.pdf#concretediversifyhash
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub struct TransmissionKey(pub jubjub::AffinePoint);
|
pub struct TransmissionKey(pub pallas::Affine);
|
||||||
|
|
||||||
impl fmt::Debug for TransmissionKey {
|
impl fmt::Debug for TransmissionKey {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_struct("TransmissionKey")
|
f.debug_struct("TransmissionKey")
|
||||||
.field("u", &hex::encode(self.0.get_u().to_bytes()))
|
.field("x", &hex::encode(self.0.get_x().to_bytes()))
|
||||||
.field("v", &hex::encode(self.0.get_v().to_bytes()))
|
.field("y", &hex::encode(self.0.get_y().to_bytes()))
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -658,13 +592,12 @@ impl fmt::Debug for TransmissionKey {
|
||||||
impl Eq for TransmissionKey {}
|
impl Eq for TransmissionKey {}
|
||||||
|
|
||||||
impl From<[u8; 32]> for TransmissionKey {
|
impl From<[u8; 32]> for TransmissionKey {
|
||||||
/// Attempts to interpret a byte representation of an
|
/// Attempts to interpret a byte representation of an affine point, failing
|
||||||
/// affine point, failing if the element is not on
|
/// if the element is not on the curve or non-canonical.
|
||||||
/// the curve or non-canonical.
|
|
||||||
///
|
///
|
||||||
/// https://github.com/zkcrypto/jubjub/blob/master/src/lib.rs#L411
|
/// https://github.com/zkcrypto/jubjub/blob/master/src/lib.rs#L411
|
||||||
fn from(bytes: [u8; 32]) -> Self {
|
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 {
|
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_.
|
/// scalar mult _\[ivk\]G_d_.
|
||||||
///
|
///
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
|
/// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#concretesaplingkeyagreement
|
/// https://zips.z.cash/protocol/protocol.pdf#concreteorchardkeyagreement
|
||||||
fn from((ivk, d): (IncomingViewingKey, Diversifier)) -> Self {
|
fn from((ivk, d): (IncomingViewingKey, Diversifier)) -> Self {
|
||||||
Self(jubjub::AffinePoint::from(
|
Self(pallas::Affine::from(ivk.scalar * pallas::Point::from(d)))
|
||||||
diversify_hash(d.0).unwrap() * ivk.scalar,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,12 +624,13 @@ impl PartialEq<[u8; 32]> for TransmissionKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Magic human-readable strings used to identify what networks
|
/// Magic human-readable strings used to identify what networks Orchard full
|
||||||
/// Sapling FullViewingKeys are associated with when encoded/decoded
|
/// viewing keys are associated with when encoded/decoded with bech32.
|
||||||
/// with bech32.
|
///
|
||||||
|
/// https://zips.z.cash/protocol/nu5.pdf#orchardfullviewingkeyencoding
|
||||||
mod fvk_hrp {
|
mod fvk_hrp {
|
||||||
pub const MAINNET: &str = "zviews";
|
pub const MAINNET: &str = "zviewo";
|
||||||
pub const TESTNET: &str = "zviewtestsapling";
|
pub const TESTNET: &str = "zviewtestorchard";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Full Viewing Keys
|
/// Full Viewing Keys
|
||||||
|
@ -707,16 +639,16 @@ mod fvk_hrp {
|
||||||
/// spend authority.
|
/// spend authority.
|
||||||
///
|
///
|
||||||
/// For incoming viewing keys on the production network, the
|
/// For incoming viewing keys on the production network, the
|
||||||
/// Human-Readable Part is “zviews”. For incoming viewing keys on the
|
/// Human-Readable Part is “zviewo”. For incoming viewing keys on the
|
||||||
/// test network, the Human-Readable Part is “zviewtestsapling”.
|
/// 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)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
pub struct FullViewingKey {
|
pub struct FullViewingKey {
|
||||||
network: Network,
|
network: Network,
|
||||||
authorizing_key: AuthorizingKey,
|
spend_validating_key: SpendValidatingKey,
|
||||||
nullifier_deriving_key: NullifierDerivingKey,
|
nullifier_deriving_key: NullifierDerivingKey,
|
||||||
outgoing_viewing_key: OutgoingViewingKey,
|
ivk_commit_randomness: IvkCommitRandomness,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: impl a From that accepts a Network?
|
// 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 {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_struct("FullViewingKey")
|
f.debug_struct("FullViewingKey")
|
||||||
.field("network", &self.network)
|
.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("nullifier_deriving_key", &self.nullifier_deriving_key)
|
||||||
.field("outgoing_viewing_key", &self.outgoing_viewing_key)
|
.field("ivk_commit_randomness", &self.ivk_commit_randomness)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -736,9 +668,9 @@ impl fmt::Display for FullViewingKey {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let mut bytes = io::Cursor::new(Vec::new());
|
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.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 {
|
let hrp = match self.network {
|
||||||
Network::Mainnet => fvk_hrp::MAINNET,
|
Network::Mainnet => fvk_hrp::MAINNET,
|
||||||
|
@ -757,20 +689,18 @@ impl FromStr for FullViewingKey {
|
||||||
Ok((hrp, bytes, Variant::Bech32)) => {
|
Ok((hrp, bytes, Variant::Bech32)) => {
|
||||||
let mut decoded_bytes = io::Cursor::new(Vec::<u8>::from_base32(&bytes).unwrap());
|
let mut decoded_bytes = io::Cursor::new(Vec::<u8>::from_base32(&bytes).unwrap());
|
||||||
|
|
||||||
let authorizing_key_bytes = decoded_bytes.read_32_bytes()?;
|
let ak_bytes = decoded_bytes.read_32_bytes()?;
|
||||||
let nullifier_deriving_key_bytes = decoded_bytes.read_32_bytes()?;
|
let nk_bytes = decoded_bytes.read_32_bytes()?;
|
||||||
let outgoing_key_bytes = decoded_bytes.read_32_bytes()?;
|
let rivk_bytes = decoded_bytes.read_32_bytes()?;
|
||||||
|
|
||||||
Ok(FullViewingKey {
|
Ok(FullViewingKey {
|
||||||
network: match hrp.as_str() {
|
network: match hrp.as_str() {
|
||||||
fvk_hrp::MAINNET => Network::Mainnet,
|
fvk_hrp::MAINNET => Network::Mainnet,
|
||||||
_ => Network::Testnet,
|
_ => Network::Testnet,
|
||||||
},
|
},
|
||||||
authorizing_key: AuthorizingKey::from(authorizing_key_bytes),
|
spend_validating_key: SpendValidatingKey::from(ak_bytes),
|
||||||
nullifier_deriving_key: NullifierDerivingKey::from(
|
nullifier_deriving_key: NullifierDerivingKey::from(nk_bytes),
|
||||||
nullifier_deriving_key_bytes,
|
ivk_commit_randomness: IvkCommitRandomness::from(rivk_bytes),
|
||||||
),
|
|
||||||
outgoing_viewing_key: OutgoingViewingKey::from(outgoing_key_bytes),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => Err(SerializationError::Parse("bech32 decoding error")),
|
_ => 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)]
|
#[derive(Copy, Clone, Deserialize, PartialEq, Serialize)]
|
||||||
pub struct EphemeralPublicKey(
|
pub struct EphemeralPublicKey(#[serde(with = "serde_helpers::Affine")] pub pallas::Affine);
|
||||||
#[serde(with = "serde_helpers::AffinePoint")] pub jubjub::AffinePoint,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl fmt::Debug for EphemeralPublicKey {
|
impl fmt::Debug for EphemeralPublicKey {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_struct("EphemeralPublicKey")
|
f.debug_struct("EphemeralPublicKey")
|
||||||
.field("u", &hex::encode(self.0.get_u().to_bytes()))
|
.field("x", &hex::encode(self.0.get_x().to_bytes()))
|
||||||
.field("v", &hex::encode(self.0.get_v().to_bytes()))
|
.field("y", &hex::encode(self.0.get_y().to_bytes()))
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -813,12 +744,12 @@ impl TryFrom<[u8; 32]> for EphemeralPublicKey {
|
||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
|
|
||||||
fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
|
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() {
|
if possible_point.is_some().into() {
|
||||||
Ok(Self(possible_point.unwrap()))
|
Ok(Self(possible_point.unwrap()))
|
||||||
} else {
|
} 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(clippy::unit_arg)]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use halo2::pasta::pallas;
|
||||||
|
|
||||||
mod ciphertexts;
|
mod ciphertexts;
|
||||||
mod nullifiers;
|
mod nullifiers;
|
||||||
|
|
||||||
#[cfg(any(test, feature = "proptest-impl"))]
|
#[cfg(any(test, feature = "proptest-impl"))]
|
||||||
mod arbitrary;
|
mod arbitrary;
|
||||||
|
|
||||||
use crate::{
|
use crate::amount::{Amount, NonNegative};
|
||||||
amount::{Amount, NonNegative},
|
|
||||||
transaction::Memo,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
commitment::CommitmentRandomness,
|
commitment::CommitmentRandomness,
|
||||||
keys::{Diversifier, TransmissionKey},
|
keys::{Diversifier, TransmissionKey},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use ciphertexts::{EncryptedNote, WrappedNoteKey};
|
pub use ciphertexts::EncryptedNote;
|
||||||
|
|
||||||
pub use nullifiers::Nullifier;
|
pub use nullifiers::Nullifier;
|
||||||
|
|
||||||
|
@ -35,9 +34,11 @@ pub struct Note {
|
||||||
pub transmission_key: TransmissionKey,
|
pub transmission_key: TransmissionKey,
|
||||||
/// An integer representing the value of the note in zatoshi.
|
/// An integer representing the value of the note in zatoshi.
|
||||||
pub value: Amount<NonNegative>,
|
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
|
/// A random commitment trapdoor used to produce the associated
|
||||||
/// note commitment.
|
/// note commitment.
|
||||||
pub rcm: CommitmentRandomness,
|
pub rcm: CommitmentRandomness,
|
||||||
/// The note memo, after decryption
|
|
||||||
pub memo: Memo,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,33 @@
|
||||||
#![allow(clippy::unit_arg)]
|
#![allow(clippy::unit_arg)]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use super::super::{
|
use halo2::pasta::pallas;
|
||||||
commitment::{pedersen_hashes::mixing_pedersen_hash, NoteCommitment},
|
|
||||||
keys::NullifierDerivingKey,
|
|
||||||
tree::Position,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Invokes Blake2s-256 as PRF^nfSapling to derive the nullifier for a
|
use super::super::{commitment::NoteCommitment, keys::NullifierDerivingKey, tree::Position};
|
||||||
/// 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();
|
|
||||||
|
|
||||||
*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)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
any(test, feature = "proptest-impl"),
|
any(test, feature = "proptest-impl"),
|
||||||
|
|
|
@ -1,10 +1,81 @@
|
||||||
//! Sinsemilla hash functions and helpers.
|
//! Sinsemilla hash functions and helpers.
|
||||||
|
|
||||||
use bitvec::prelude::*;
|
use bitvec::prelude::*;
|
||||||
use rand_core::{CryptoRng, RngCore};
|
|
||||||
|
|
||||||
use halo2::pasta::pallas;
|
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]
|
/// [Hash Extractor for Pallas][concreteextractorpallas]
|
||||||
///
|
///
|
||||||
/// P → B^[l^Orchard_Merkle]
|
/// 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
|
/// Sinsemilla Hash Function
|
||||||
///
|
///
|
||||||
/// "SinsemillaHash is an algebraic hash function with collision resistance (for
|
/// "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
|
/// https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn sinsemilla_hash(domain: [u8; 8], M: &BitVec<Lsb0, u8>) -> pallas::Base {
|
// XXX: M is a max of k*c = 2530 bits, sinsemilla_hash_to_point checks this
|
||||||
extract_p(sinsemilla_hash_to_point(domain, M))
|
pub fn sinsemilla_hash(D: &[u8], M: &BitVec<Lsb0, u8>) -> pallas::Base {
|
||||||
}
|
extract_p(sinsemilla_hash_to_point(D, 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)
|
|
||||||
}
|
}
|
|
@ -1 +0,0 @@
|
||||||
|
|
Loading…
Reference in New Issue