Cleanup
This commit is contained in:
parent
df1ecc72b1
commit
bd4e5e1f38
|
@ -4448,6 +4448,7 @@ dependencies = [
|
||||||
"fpe",
|
"fpe",
|
||||||
"funty",
|
"funty",
|
||||||
"futures 0.3.14",
|
"futures 0.3.14",
|
||||||
|
"group 0.9.0",
|
||||||
"halo2",
|
"halo2",
|
||||||
"hex",
|
"hex",
|
||||||
"itertools 0.10.0",
|
"itertools 0.10.0",
|
||||||
|
|
|
@ -27,6 +27,7 @@ displaydoc = "0.2.1"
|
||||||
equihash = "0.1"
|
equihash = "0.1"
|
||||||
fpe = "0.4"
|
fpe = "0.4"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
|
group = "0.9"
|
||||||
halo2 = { git = "https://github.com/zcash/halo2.git", branch = "main" }
|
halo2 = { git = "https://github.com/zcash/halo2.git", branch = "main" }
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
jubjub = "0.6.0"
|
jubjub = "0.6.0"
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
convert::{From, Into, TryFrom},
|
convert::{From, Into, TryFrom, TryInto},
|
||||||
fmt,
|
fmt,
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
|
@ -18,7 +18,8 @@ use std::{
|
||||||
use aes::Aes256;
|
use aes::Aes256;
|
||||||
use bech32::{self, FromBase32, ToBase32, Variant};
|
use bech32::{self, FromBase32, ToBase32, Variant};
|
||||||
use fpe::ff1::{BinaryNumeralString, FF1};
|
use fpe::ff1::{BinaryNumeralString, FF1};
|
||||||
use halo2::pasta::pallas;
|
use group::GroupEncoding;
|
||||||
|
use halo2::{arithmetic::FieldExt, pasta::pallas};
|
||||||
use rand_core::{CryptoRng, RngCore};
|
use rand_core::{CryptoRng, RngCore};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -42,13 +43,15 @@ use super::sinsemilla::*;
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn prp_d(K: [u8; 32], d: [u8; 11]) -> [u8; 11] {
|
fn prp_d(K: [u8; 32], d: [u8; 11]) -> [u8; 11] {
|
||||||
let radix = 2;
|
let radix = 2;
|
||||||
let tweak = "";
|
let tweak = b"";
|
||||||
|
|
||||||
let ff = FF1::<Aes256>::new(&K, radix).expect("valid radix");
|
let ff = FF1::<Aes256>::new(&K, radix).expect("valid radix");
|
||||||
|
|
||||||
let enc = ff
|
ff.encrypt(tweak, &BinaryNumeralString::from_bytes_le(&d))
|
||||||
.encrypt(tweak.into(), &BinaryNumeralString::from_bytes_le(&d))
|
.unwrap()
|
||||||
.unwrap();
|
.to_bytes_le()
|
||||||
|
.try_into()
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invokes Blake2b-512 as PRF^expand with parameter t.
|
/// Invokes Blake2b-512 as PRF^expand with parameter t.
|
||||||
|
@ -59,16 +62,17 @@ fn prp_d(K: [u8; 32], d: [u8; 11]) -> [u8; 11] {
|
||||||
// TODO: This is basically a duplicate of the one in our sapling module, its
|
// 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
|
// definition in the draft NU5 spec is incomplete so I'm putting it here in case
|
||||||
// it changes.
|
// it changes.
|
||||||
fn prf_expand(sk: [u8; 32], t: &[u8]) -> [u8; 64] {
|
fn prf_expand(sk: [u8; 32], t: &[&[u8]]) -> [u8; 64] {
|
||||||
let hash = blake2b_simd::Params::new()
|
let state = blake2b_simd::Params::new()
|
||||||
.hash_length(64)
|
.hash_length(64)
|
||||||
.personal(b"Zcash_ExpandSeed")
|
.personal(b"Zcash_ExpandSeed")
|
||||||
.to_state()
|
.to_state();
|
||||||
.update(&sk[..])
|
|
||||||
.update(t)
|
|
||||||
.finalize();
|
|
||||||
|
|
||||||
*hash.as_array()
|
state.update(&sk[..]);
|
||||||
|
|
||||||
|
t.iter().for_each(|t_i| state.update(t_i));
|
||||||
|
|
||||||
|
*state.finalize().as_array()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to derive the outgoing cipher key _ock_ used to encrypt an encrypted
|
/// Used to derive the outgoing cipher key _ock_ used to encrypt an encrypted
|
||||||
|
@ -77,15 +81,15 @@ fn prf_expand(sk: [u8; 32], t: &[u8]) -> [u8; 64] {
|
||||||
/// PRF^ock(ovk, cv, cm_x, ephemeralKey) := BLAKE2b-256(“Zcash_Orchardock”, ovk || cv || cm_x || ephemeralKey)
|
/// 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_ock(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; 64] {
|
||||||
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")
|
||||||
.to_state()
|
.to_state()
|
||||||
.update(ovk)
|
.update(&ovk)
|
||||||
.update(cv)
|
.update(&cv)
|
||||||
.update(cm_x)
|
.update(&cm_x)
|
||||||
.update(ephemeral_key)
|
.update(&ephemeral_key)
|
||||||
.finalize();
|
.finalize();
|
||||||
|
|
||||||
*hash.as_array()
|
*hash.as_array()
|
||||||
|
@ -348,8 +352,8 @@ 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 {
|
||||||
f.debug_struct("NullifierDerivingKey")
|
f.debug_struct("NullifierDerivingKey")
|
||||||
.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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -406,7 +410,7 @@ impl From<SpendingKey> for IvkCommitRandomness {
|
||||||
///
|
///
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
/// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
||||||
fn from(sk: SpendingKey) -> Self {
|
fn from(sk: SpendingKey) -> Self {
|
||||||
Self(pallas::Scalar::from_bytes_wide(prf_expand(sk, [8])))
|
Self(pallas::Scalar::from_bytes_wide(prf_expand(sk.into(), &[8])))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,6 +420,20 @@ impl From<IvkCommitRandomness> for [u8; 32] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<[u8; 32]> for IvkCommitRandomness {
|
||||||
|
type Error = &'static str;
|
||||||
|
|
||||||
|
fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
|
||||||
|
let possible_scalar = pallas::Scalar::from_bytes(&bytes);
|
||||||
|
|
||||||
|
if possible_scalar.is_some().into() {
|
||||||
|
Ok(Self(possible_scalar.unwrap()))
|
||||||
|
} else {
|
||||||
|
Err("Invalid pallas::Scalar value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Magic human-readable strings used to identify what networks Orchard incoming
|
/// Magic human-readable strings used to identify what networks Orchard incoming
|
||||||
/// viewing keys are associated with when encoded/decoded with bech32.
|
/// viewing keys are associated with when encoded/decoded with bech32.
|
||||||
///
|
///
|
||||||
|
@ -476,10 +494,18 @@ impl From<FullViewingKey> for IncomingViewingKey {
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
/// 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(fvk: FullViewingKey) -> Self {
|
fn from(fvk: FullViewingKey) -> Self {
|
||||||
let M = (fvk.ak.into(), fvk.nk.into()).concat();
|
let M = (
|
||||||
|
fvk.spend_validating_key.into(),
|
||||||
|
fvk.nullifier_deriving_key.into(),
|
||||||
|
)
|
||||||
|
.concat();
|
||||||
|
|
||||||
// Commit^ivk_rivk
|
// Commit^ivk_rivk
|
||||||
let scalar = sinsemilla_short_commit(fvk.ivk.into(), "z.cash:Orchard-CommitIvk", M);
|
let scalar = sinsemilla_short_commit(
|
||||||
|
fvk.ivk_commit_randomness.into(),
|
||||||
|
"z.cash:Orchard-CommitIvk",
|
||||||
|
M,
|
||||||
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
network: Network::default(),
|
network: Network::default(),
|
||||||
|
@ -594,7 +620,7 @@ impl FromStr for FullViewingKey {
|
||||||
},
|
},
|
||||||
spend_validating_key: SpendValidatingKey::from(ak_bytes),
|
spend_validating_key: SpendValidatingKey::from(ak_bytes),
|
||||||
nullifier_deriving_key: NullifierDerivingKey::from(nk_bytes),
|
nullifier_deriving_key: NullifierDerivingKey::from(nk_bytes),
|
||||||
ivk_commit_randomness: IvkCommitRandomness::from(rivk_bytes),
|
ivk_commit_randomness: IvkCommitRandomness::try_from(rivk_bytes).unwrap(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => Err(SerializationError::Parse("bech32 decoding error")),
|
_ => Err(SerializationError::Parse("bech32 decoding error")),
|
||||||
|
@ -605,12 +631,19 @@ impl FromStr for FullViewingKey {
|
||||||
impl FullViewingKey {
|
impl FullViewingKey {
|
||||||
/// [4.2.3]: https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
/// [4.2.3]: https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn to_R(&self) -> [u8; 32] {
|
pub fn to_R(&self) -> [u8; 64] {
|
||||||
// let K = I2LEBSP_l_sk(rivk)
|
// let K = I2LEBSP_l_sk(rivk)
|
||||||
let K: [u8; 32] = self.ivk_commit_randomness.into();
|
let K: [u8; 32] = self.ivk_commit_randomness.into();
|
||||||
|
|
||||||
// let R = PRF^expand_K( [0x82] || I2LEOSP256(ak) || I2LEOSP256(nk) )
|
// let R = PRF^expand_K( [0x82] || I2LEOSP256(ak) || I2LEOSP256(nk) )
|
||||||
prf_expand(K, ([0x82], self.ak.into(), self.nk.into()).concat())
|
prf_expand(
|
||||||
|
K,
|
||||||
|
[
|
||||||
|
[0x82u8],
|
||||||
|
self.spend_validating_key.into(),
|
||||||
|
self.nullifier_deriving_key.into(),
|
||||||
|
],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,7 +721,7 @@ impl From<Diversifier> for pallas::Point {
|
||||||
///
|
///
|
||||||
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
|
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
|
||||||
fn from(d: Diversifier) -> Self {
|
fn from(d: Diversifier) -> Self {
|
||||||
diversify_hash(d.0)
|
diversify_hash(&d.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,20 @@ use bitvec::prelude::*;
|
||||||
|
|
||||||
use halo2::pasta::pallas;
|
use halo2::pasta::pallas;
|
||||||
|
|
||||||
|
/// [Hash Extractor for Pallas][concreteextractorpallas]
|
||||||
|
///
|
||||||
|
/// P → B^[l^Orchard_Merkle]
|
||||||
|
///
|
||||||
|
/// [concreteextractorpallas]: https://zips.z.cash/protocol/nu5.pdf#concreteextractorpallas
|
||||||
|
// TODO: should this return the basefield element type, or the bytes?
|
||||||
|
pub fn extract_p(point: pallas::Point) -> pallas::Base {
|
||||||
|
match pallas::Affine::from(point).get_xy().into() {
|
||||||
|
// If Some, it's not the identity.
|
||||||
|
Some((x, _)) => x,
|
||||||
|
_ => pallas::Base::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// GroupHash into Pallas, aka _GroupHash^P_
|
/// GroupHash into Pallas, aka _GroupHash^P_
|
||||||
///
|
///
|
||||||
/// Produces a random point in the Pallas curve. The first input element acts
|
/// Produces a random point in the Pallas curve. The first input element acts
|
||||||
|
@ -21,7 +35,7 @@ pub fn pallas_group_hash(D: &[u8], M: &[u8]) -> pallas::Point {
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash
|
/// https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn Q(D: &[u8]) -> pallas::Point {
|
fn Q(D: &[u8]) -> pallas::Point {
|
||||||
pallas_group_hash("z.cash:SinsemillaQ", D)
|
pallas_group_hash(b"z.cash:SinsemillaQ", D)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// S(j) := GroupHash^P(︀“z.cash:SinsemillaS”, LEBS2OSP32(I2LEBSP32(j)))
|
/// S(j) := GroupHash^P(︀“z.cash:SinsemillaS”, LEBS2OSP32(I2LEBSP32(j)))
|
||||||
|
@ -32,7 +46,7 @@ fn Q(D: &[u8]) -> pallas::Point {
|
||||||
// XXX: should j be strictly limited to k=10 bits?
|
// XXX: should j be strictly limited to k=10 bits?
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn S(j: [u8; 2]) -> pallas::Point {
|
fn S(j: [u8; 2]) -> pallas::Point {
|
||||||
pallas_group_hash("z.cash:SinsemillaS", &j)
|
pallas_group_hash(b"z.cash:SinsemillaS", &j)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// "...an algebraic hash function with collision resistance (for fixed input
|
/// "...an algebraic hash function with collision resistance (for fixed input
|
||||||
|
@ -76,20 +90,6 @@ pub fn sinsemilla_hash_to_point(D: &[u8], M: &BitVec<Lsb0, u8>) -> pallas::Point
|
||||||
acc
|
acc
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [Hash Extractor for Pallas][concreteextractorpallas]
|
|
||||||
///
|
|
||||||
/// P → B^[l^Orchard_Merkle]
|
|
||||||
///
|
|
||||||
/// [concreteextractorpallas]: https://zips.z.cash/protocol/nu5.pdf#concreteextractorpallas
|
|
||||||
// TODO: should this return the basefield element type, or the bytes?
|
|
||||||
pub fn extract_p(point: pallas::Point) -> pallas::Base {
|
|
||||||
match pallas::Affine::from(point).get_xy().into() {
|
|
||||||
// If Some, it's not the identity.
|
|
||||||
Some((x, _)) => x,
|
|
||||||
_ => pallas::Base::zero(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
||||||
|
@ -117,7 +117,7 @@ pub fn sinsemilla_hash(D: &[u8], M: &BitVec<Lsb0, u8>) -> pallas::Base {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn sinsemilla_commit(r: pallas::Scalar, D: &[u8], M: &BitVec<Lsb0, u8>) -> pallas::Point {
|
pub fn sinsemilla_commit(r: pallas::Scalar, D: &[u8], M: &BitVec<Lsb0, u8>) -> pallas::Point {
|
||||||
sinsemilla_hash_to_point((D, b"-M").concat(), M)
|
sinsemilla_hash_to_point((D, b"-M").concat(), M)
|
||||||
+ r * pallas_group_hash((D, b"r").concat(), b"")
|
+ pallas_group_hash((D, b"r").concat(), b"") * r
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SinsemillaShortCommit_r(D, M) := Extract_P(SinsemillaCommit_r(D, M))
|
/// SinsemillaShortCommit_r(D, M) := Extract_P(SinsemillaCommit_r(D, M))
|
||||||
|
|
Loading…
Reference in New Issue