Cleanup
This commit is contained in:
parent
df1ecc72b1
commit
bd4e5e1f38
|
@ -4448,6 +4448,7 @@ dependencies = [
|
|||
"fpe",
|
||||
"funty",
|
||||
"futures 0.3.14",
|
||||
"group 0.9.0",
|
||||
"halo2",
|
||||
"hex",
|
||||
"itertools 0.10.0",
|
||||
|
|
|
@ -27,6 +27,7 @@ displaydoc = "0.2.1"
|
|||
equihash = "0.1"
|
||||
fpe = "0.4"
|
||||
futures = "0.3"
|
||||
group = "0.9"
|
||||
halo2 = { git = "https://github.com/zcash/halo2.git", branch = "main" }
|
||||
hex = "0.4"
|
||||
jubjub = "0.6.0"
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
mod tests;
|
||||
|
||||
use std::{
|
||||
convert::{From, Into, TryFrom},
|
||||
convert::{From, Into, TryFrom, TryInto},
|
||||
fmt,
|
||||
io::{self, Write},
|
||||
str::FromStr,
|
||||
|
@ -18,7 +18,8 @@ use std::{
|
|||
use aes::Aes256;
|
||||
use bech32::{self, FromBase32, ToBase32, Variant};
|
||||
use fpe::ff1::{BinaryNumeralString, FF1};
|
||||
use halo2::pasta::pallas;
|
||||
use group::GroupEncoding;
|
||||
use halo2::{arithmetic::FieldExt, pasta::pallas};
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
|
||||
use crate::{
|
||||
|
@ -42,13 +43,15 @@ use super::sinsemilla::*;
|
|||
#[allow(non_snake_case)]
|
||||
fn prp_d(K: [u8; 32], d: [u8; 11]) -> [u8; 11] {
|
||||
let radix = 2;
|
||||
let tweak = "";
|
||||
let tweak = b"";
|
||||
|
||||
let ff = FF1::<Aes256>::new(&K, radix).expect("valid radix");
|
||||
|
||||
let enc = ff
|
||||
.encrypt(tweak.into(), &BinaryNumeralString::from_bytes_le(&d))
|
||||
.unwrap();
|
||||
ff.encrypt(tweak, &BinaryNumeralString::from_bytes_le(&d))
|
||||
.unwrap()
|
||||
.to_bytes_le()
|
||||
.try_into()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// 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
|
||||
// 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()
|
||||
fn prf_expand(sk: [u8; 32], t: &[&[u8]]) -> [u8; 64] {
|
||||
let state = blake2b_simd::Params::new()
|
||||
.hash_length(64)
|
||||
.personal(b"Zcash_ExpandSeed")
|
||||
.to_state()
|
||||
.update(&sk[..])
|
||||
.update(t)
|
||||
.finalize();
|
||||
.to_state();
|
||||
|
||||
*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
|
||||
|
@ -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)
|
||||
///
|
||||
/// 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()
|
||||
.hash_length(32)
|
||||
.personal(b"Zcash_Orchardock")
|
||||
.to_state()
|
||||
.update(ovk)
|
||||
.update(cv)
|
||||
.update(cm_x)
|
||||
.update(ephemeral_key)
|
||||
.update(&ovk)
|
||||
.update(&cv)
|
||||
.update(&cm_x)
|
||||
.update(&ephemeral_key)
|
||||
.finalize();
|
||||
|
||||
*hash.as_array()
|
||||
|
@ -348,8 +352,8 @@ pub struct NullifierDerivingKey(pub pallas::Base);
|
|||
impl fmt::Debug for NullifierDerivingKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("NullifierDerivingKey")
|
||||
.field("u", &hex::encode(self.0.get_u().to_bytes()))
|
||||
.field("v", &hex::encode(self.0.get_v().to_bytes()))
|
||||
.field("x", &hex::encode(self.0.get_x().to_bytes()))
|
||||
.field("y", &hex::encode(self.0.get_y().to_bytes()))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
@ -406,7 +410,7 @@ impl From<SpendingKey> for IvkCommitRandomness {
|
|||
///
|
||||
/// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
||||
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
|
||||
/// 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#concreteprfs
|
||||
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
|
||||
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 {
|
||||
network: Network::default(),
|
||||
|
@ -594,7 +620,7 @@ impl FromStr for FullViewingKey {
|
|||
},
|
||||
spend_validating_key: SpendValidatingKey::from(ak_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")),
|
||||
|
@ -605,12 +631,19 @@ impl FromStr for FullViewingKey {
|
|||
impl FullViewingKey {
|
||||
/// [4.2.3]: https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
||||
#[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: [u8; 32] = self.ivk_commit_randomness.into();
|
||||
|
||||
// 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
|
||||
fn from(d: Diversifier) -> Self {
|
||||
diversify_hash(d.0)
|
||||
diversify_hash(&d.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,20 @@ use bitvec::prelude::*;
|
|||
|
||||
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_
|
||||
///
|
||||
/// 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
|
||||
#[allow(non_snake_case)]
|
||||
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)))
|
||||
|
@ -32,7 +46,7 @@ fn Q(D: &[u8]) -> pallas::Point {
|
|||
// 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)
|
||||
pallas_group_hash(b"z.cash:SinsemillaS", &j)
|
||||
}
|
||||
|
||||
/// "...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
|
||||
}
|
||||
|
||||
/// [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
|
||||
///
|
||||
/// "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)]
|
||||
pub fn sinsemilla_commit(r: pallas::Scalar, D: &[u8], M: &BitVec<Lsb0, u8>) -> pallas::Point {
|
||||
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))
|
||||
|
|
Loading…
Reference in New Issue