Migrate to blake2b_simd and blake2s_simd crates

The primary reason for migrating is that these crates provide APIs for
setting the personalisation string. This enables us to depend solely on
published crates, and thus publish our own crates.

The SIMD implementations are ported from libsodium.

Closes #67.
This commit is contained in:
Jack Grigg
2019-06-04 13:15:12 +01:00
parent 91c6b0b3f0
commit 999dcbfcab
20 changed files with 172 additions and 129 deletions

View File

@@ -7,6 +7,7 @@ authors = [
[dependencies]
aes = "0.2"
blake2b_simd = "0.5"
byteorder = "1"
crypto_api_chachapoly = "0.1"
ff = { path = "../ff" }
@@ -17,7 +18,3 @@ pairing = { path = "../pairing" }
rand = "0.4"
sapling-crypto = { path = "../sapling-crypto" }
sha2 = "0.8"
[dependencies.blake2-rfc]
git = "https://github.com/gtank/blake2-rfc"
rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"

View File

@@ -2,7 +2,7 @@
//!
//! Implements section 4.2.2 of the Zcash Protocol Specification.
use blake2_rfc::blake2b::{Blake2b, Blake2bResult};
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
use ff::{PrimeField, PrimeFieldRepr};
use sapling_crypto::{
jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, ToUniform, Unknown},
@@ -13,12 +13,15 @@ use std::io::{self, Read, Write};
pub const PRF_EXPAND_PERSONALIZATION: &'static [u8; 16] = b"Zcash_ExpandSeed";
/// PRF^expand(sk, t) := BLAKE2b-512("Zcash_ExpandSeed", sk || t)
pub fn prf_expand(sk: &[u8], t: &[u8]) -> Blake2bResult {
prf_expand_vec(sk, &[t])
pub fn prf_expand(sk: &[u8], t: &[u8]) -> Blake2bHash {
prf_expand_vec(sk, &vec![t])
}
pub fn prf_expand_vec(sk: &[u8], ts: &[&[u8]]) -> Blake2bResult {
let mut h = Blake2b::with_params(64, &[], &[], PRF_EXPAND_PERSONALIZATION);
pub fn prf_expand_vec(sk: &[u8], ts: &[&[u8]]) -> Blake2bHash {
let mut h = Blake2bParams::new()
.hash_length(64)
.personal(PRF_EXPAND_PERSONALIZATION)
.to_state();
h.update(sk);
for t in ts {
h.update(t);

View File

@@ -2,7 +2,7 @@
extern crate lazy_static;
extern crate aes;
extern crate blake2_rfc;
extern crate blake2b_simd;
extern crate byteorder;
extern crate crypto_api_chachapoly;
extern crate ff;

View File

@@ -1,6 +1,6 @@
//! Implementation of in-band secret distribution for Zcash transactions.
use blake2_rfc::blake2b::{Blake2b, Blake2bResult};
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf};
use ff::{PrimeField, PrimeFieldRepr};
@@ -168,14 +168,15 @@ where
fn kdf_sapling(
dhsecret: edwards::Point<Bls12, PrimeOrder>,
epk: &edwards::Point<Bls12, PrimeOrder>,
) -> Blake2bResult {
) -> Blake2bHash {
let mut input = [0u8; 64];
dhsecret.write(&mut input[0..32]).unwrap();
epk.write(&mut input[32..64]).unwrap();
let mut h = Blake2b::with_params(32, &[], &[], KDF_SAPLING_PERSONALIZATION);
h.update(&input);
h.finalize()
Blake2bParams::new()
.hash_length(32)
.personal(KDF_SAPLING_PERSONALIZATION)
.hash(&input)
}
/// Sapling PRF^ock.
@@ -186,16 +187,17 @@ fn prf_ock(
cv: &edwards::Point<Bls12, Unknown>,
cmu: &Fr,
epk: &edwards::Point<Bls12, PrimeOrder>,
) -> Blake2bResult {
) -> Blake2bHash {
let mut ock_input = [0u8; 128];
ock_input[0..32].copy_from_slice(&ovk.0);
cv.write(&mut ock_input[32..64]).unwrap();
cmu.into_repr().write_le(&mut ock_input[64..96]).unwrap();
epk.write(&mut ock_input[96..128]).unwrap();
let mut h = Blake2b::with_params(32, &[], &[], PRF_OCK_PERSONALIZATION);
h.update(&ock_input);
h.finalize()
Blake2bParams::new()
.hash_length(32)
.personal(PRF_OCK_PERSONALIZATION)
.hash(&ock_input)
}
/// An API for encrypting Sapling notes.

View File

@@ -1,4 +1,4 @@
use blake2_rfc::blake2b::Blake2b;
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
use byteorder::{LittleEndian, WriteBytesExt};
use ff::{PrimeField, PrimeFieldRepr};
@@ -39,7 +39,7 @@ macro_rules! update_i64 {
macro_rules! update_hash {
($h:expr, $cond:expr, $value:expr) => {
if $cond {
$h.update(&$value);
$h.update(&$value.as_ref());
} else {
$h.update(&[0; 32]);
}
@@ -67,47 +67,51 @@ impl SigHashVersion {
}
}
fn prevout_hash(tx: &TransactionData) -> Vec<u8> {
fn prevout_hash(tx: &TransactionData) -> Blake2bHash {
let mut data = Vec::with_capacity(tx.vin.len() * 36);
for t_in in &tx.vin {
t_in.prevout.write(&mut data).unwrap();
}
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_PREVOUTS_HASH_PERSONALIZATION);
h.update(&data);
h.finalize().as_ref().to_vec()
Blake2bParams::new()
.hash_length(32)
.personal(ZCASH_PREVOUTS_HASH_PERSONALIZATION)
.hash(&data)
}
fn sequence_hash(tx: &TransactionData) -> Vec<u8> {
fn sequence_hash(tx: &TransactionData) -> Blake2bHash {
let mut data = Vec::with_capacity(tx.vin.len() * 4);
for t_in in &tx.vin {
(&mut data)
.write_u32::<LittleEndian>(t_in.sequence)
.unwrap();
}
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SEQUENCE_HASH_PERSONALIZATION);
h.update(&data);
h.finalize().as_ref().to_vec()
Blake2bParams::new()
.hash_length(32)
.personal(ZCASH_SEQUENCE_HASH_PERSONALIZATION)
.hash(&data)
}
fn outputs_hash(tx: &TransactionData) -> Vec<u8> {
fn outputs_hash(tx: &TransactionData) -> Blake2bHash {
let mut data = Vec::with_capacity(tx.vout.len() * (4 + 1));
for t_out in &tx.vout {
t_out.write(&mut data).unwrap();
}
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_OUTPUTS_HASH_PERSONALIZATION);
h.update(&data);
h.finalize().as_ref().to_vec()
Blake2bParams::new()
.hash_length(32)
.personal(ZCASH_OUTPUTS_HASH_PERSONALIZATION)
.hash(&data)
}
fn single_output_hash(tx_out: &TxOut) -> Vec<u8> {
fn single_output_hash(tx_out: &TxOut) -> Blake2bHash {
let mut data = vec![];
tx_out.write(&mut data).unwrap();
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_OUTPUTS_HASH_PERSONALIZATION);
h.update(&data);
h.finalize().as_ref().to_vec()
Blake2bParams::new()
.hash_length(32)
.personal(ZCASH_OUTPUTS_HASH_PERSONALIZATION)
.hash(&data)
}
fn joinsplits_hash(tx: &TransactionData) -> Vec<u8> {
fn joinsplits_hash(tx: &TransactionData) -> Blake2bHash {
let mut data = Vec::with_capacity(
tx.joinsplits.len()
* if tx.version < SAPLING_TX_VERSION {
@@ -120,12 +124,13 @@ fn joinsplits_hash(tx: &TransactionData) -> Vec<u8> {
js.write(&mut data).unwrap();
}
data.extend_from_slice(&tx.joinsplit_pubkey.unwrap());
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_JOINSPLITS_HASH_PERSONALIZATION);
h.update(&data);
h.finalize().as_ref().to_vec()
Blake2bParams::new()
.hash_length(32)
.personal(ZCASH_JOINSPLITS_HASH_PERSONALIZATION)
.hash(&data)
}
fn shielded_spends_hash(tx: &TransactionData) -> Vec<u8> {
fn shielded_spends_hash(tx: &TransactionData) -> Blake2bHash {
let mut data = Vec::with_capacity(tx.shielded_spends.len() * 384);
for s_spend in &tx.shielded_spends {
s_spend.cv.write(&mut data).unwrap();
@@ -134,19 +139,21 @@ fn shielded_spends_hash(tx: &TransactionData) -> Vec<u8> {
s_spend.rk.write(&mut data).unwrap();
data.extend_from_slice(&s_spend.zkproof);
}
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION);
h.update(&data);
h.finalize().as_ref().to_vec()
Blake2bParams::new()
.hash_length(32)
.personal(ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION)
.hash(&data)
}
fn shielded_outputs_hash(tx: &TransactionData) -> Vec<u8> {
fn shielded_outputs_hash(tx: &TransactionData) -> Blake2bHash {
let mut data = Vec::with_capacity(tx.shielded_outputs.len() * 948);
for s_out in &tx.shielded_outputs {
s_out.write(&mut data).unwrap();
}
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION);
h.update(&data);
h.finalize().as_ref().to_vec()
Blake2bParams::new()
.hash_length(32)
.personal(ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION)
.hash(&data)
}
pub fn signature_hash_data(
@@ -158,26 +165,16 @@ pub fn signature_hash_data(
let sigversion = SigHashVersion::from_tx(tx);
match sigversion {
SigHashVersion::Overwinter | SigHashVersion::Sapling => {
let hash_outputs = if (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE
&& (hash_type & SIGHASH_MASK) != SIGHASH_NONE
{
outputs_hash(tx)
} else if (hash_type & SIGHASH_MASK) == SIGHASH_SINGLE
&& transparent_input.is_some()
&& transparent_input.as_ref().unwrap().0 < tx.vout.len()
{
single_output_hash(&tx.vout[transparent_input.as_ref().unwrap().0])
} else {
vec![0; 32]
};
let mut personal = [0; 16];
(&mut personal[..12]).copy_from_slice(ZCASH_SIGHASH_PERSONALIZATION_PREFIX);
(&mut personal[12..])
.write_u32::<LittleEndian>(consensus_branch_id)
.unwrap();
let mut h = Blake2b::with_params(32, &[], &[], &personal);
let mut h = Blake2bParams::new()
.hash_length(32)
.personal(&personal)
.to_state();
let mut tmp = [0; 8];
update_u32!(h, tx.header(), tmp);
@@ -190,7 +187,20 @@ pub fn signature_hash_data(
&& (hash_type & SIGHASH_MASK) != SIGHASH_NONE,
sequence_hash(tx)
);
h.update(&hash_outputs);
if (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE
&& (hash_type & SIGHASH_MASK) != SIGHASH_NONE
{
h.update(outputs_hash(tx).as_ref());
} else if (hash_type & SIGHASH_MASK) == SIGHASH_SINGLE
&& transparent_input.is_some()
&& transparent_input.as_ref().unwrap().0 < tx.vout.len()
{
h.update(
single_output_hash(&tx.vout[transparent_input.as_ref().unwrap().0]).as_ref(),
);
} else {
h.update(&[0; 32]);
};
update_hash!(h, !tx.joinsplits.is_empty(), joinsplits_hash(tx));
if sigversion == SigHashVersion::Sapling {
update_hash!(h, !tx.shielded_spends.is_empty(), shielded_spends_hash(tx));

View File

@@ -1,5 +1,5 @@
use aes::Aes256;
use blake2_rfc::blake2b::Blake2b;
use blake2b_simd::Params as Blake2bParams;
use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt};
use ff::Field;
use fpe::ff1::{BinaryNumeralString, FF1};
@@ -33,7 +33,10 @@ struct FVKFingerprint([u8; 32]);
impl<E: JubjubEngine> From<&FullViewingKey<E>> for FVKFingerprint {
fn from(fvk: &FullViewingKey<E>) -> Self {
let mut h = Blake2b::with_params(32, &[], &[], ZIP32_SAPLING_FVFP_PERSONALIZATION);
let mut h = Blake2bParams::new()
.hash_length(32)
.personal(ZIP32_SAPLING_FVFP_PERSONALIZATION)
.to_state();
h.update(&fvk.to_bytes());
let mut fvfp = [0u8; 32];
fvfp.copy_from_slice(h.finalize().as_bytes());
@@ -225,9 +228,10 @@ impl std::fmt::Debug for ExtendedFullViewingKey {
impl ExtendedSpendingKey {
pub fn master(seed: &[u8]) -> Self {
let mut h = Blake2b::with_params(64, &[], &[], ZIP32_SAPLING_MASTER_PERSONALIZATION);
h.update(seed);
let i = h.finalize();
let i = Blake2bParams::new()
.hash_length(64)
.personal(ZIP32_SAPLING_MASTER_PERSONALIZATION)
.hash(seed);
let sk_m = &i.as_bytes()[..32];
let mut c_m = [0u8; 32];