Browse Source

Switch to crypto_api_chachapoly crate

This crate exposes both the ChaCha20Poly1305 IETF construction, and the
underlying ChaCha20 IETF primitive, removing the need for depending on
our own fork of the previous chacha20-poly1305-aead crate.
hush
Jack Grigg 5 years ago
parent
commit
6dcb4040af
No known key found for this signature in database GPG Key ID: 9E8255172BBF9898
  1. 26
      Cargo.lock
  2. 5
      zcash_primitives/Cargo.toml
  3. 2
      zcash_primitives/src/lib.rs
  4. 146
      zcash_primitives/src/note_encryption.rs

26
Cargo.lock

@ -114,14 +114,6 @@ name = "byteorder"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "chacha20-poly1305-aead"
version = "0.1.2"
source = "git+https://github.com/gtank/chacha20-poly1305-aead?rev=aefc71f95e8bc43f2070e3c5b08130d9c86bbf4f#aefc71f95e8bc43f2070e3c5b08130d9c86bbf4f"
dependencies = [
"constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "constant_time_eq"
version = "0.1.3"
@ -132,6 +124,19 @@ name = "crossbeam"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "crypto_api"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "crypto_api_chachapoly"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crypto_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "digest"
version = "0.7.2"
@ -508,7 +513,7 @@ version = "0.0.0"
dependencies = [
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)",
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"chacha20-poly1305-aead 0.1.2 (git+https://github.com/gtank/chacha20-poly1305-aead?rev=aefc71f95e8bc43f2070e3c5b08130d9c86bbf4f)",
"crypto_api_chachapoly 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ff 0.4.0",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -563,9 +568,10 @@ dependencies = [
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
"checksum byte-tools 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "980479e6fde23246dfb54d47580d66b4e99202e7579c5eaa9fe10ecb5ebd2182"
"checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87"
"checksum chacha20-poly1305-aead 0.1.2 (git+https://github.com/gtank/chacha20-poly1305-aead?rev=aefc71f95e8bc43f2070e3c5b08130d9c86bbf4f)" = "<none>"
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19"
"checksum crypto_api 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f855e87e75a4799e18b8529178adcde6fd4f97c1449ff4821e747ff728bb102"
"checksum crypto_api_chachapoly 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9ee35dbace0831b5fe7cb9b43eb029aa14a10f594a115025d4628a2baa63ab"
"checksum digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603"
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"

5
zcash_primitives/Cargo.toml

@ -7,6 +7,7 @@ authors = [
[dependencies]
byteorder = "1"
crypto_api_chachapoly = "0.1"
ff = { path = "../ff" }
hex = "0.3"
lazy_static = "1"
@ -18,7 +19,3 @@ sha2 = "0.8"
[dependencies.blake2-rfc]
git = "https://github.com/gtank/blake2-rfc"
rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
[dependencies.chacha20-poly1305-aead]
git = "https://github.com/gtank/chacha20-poly1305-aead"
rev = "aefc71f95e8bc43f2070e3c5b08130d9c86bbf4f"

2
zcash_primitives/src/lib.rs

@ -3,7 +3,7 @@ extern crate lazy_static;
extern crate blake2_rfc;
extern crate byteorder;
extern crate chacha20_poly1305_aead;
extern crate crypto_api_chachapoly;
extern crate ff;
extern crate hex;
extern crate pairing;

146
zcash_primitives/src/note_encryption.rs

@ -1,6 +1,6 @@
use blake2_rfc::blake2b::{Blake2b, Blake2bResult};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use chacha20_poly1305_aead::{self, as_bytes::AsBytes, chacha20::ChaCha20};
use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf};
use ff::{PrimeField, PrimeFieldRepr};
use pairing::bls12_381::{Bls12, Fr};
use rand::{OsRng, Rng};
@ -240,19 +240,14 @@ impl SaplingNoteEncryption {
input.extend_from_slice(&self.memo.0);
assert_eq!(input.len(), NOTE_PLAINTEXT_SIZE);
let mut ciphertext = Vec::with_capacity(NOTE_PLAINTEXT_SIZE);
let tag = chacha20_poly1305_aead::encrypt(
&key.as_bytes(),
&[0u8; 12],
&[],
&input,
&mut ciphertext,
)
.unwrap();
let mut output = [0u8; ENC_CIPHERTEXT_SIZE];
output[0..NOTE_PLAINTEXT_SIZE].copy_from_slice(&ciphertext);
output[NOTE_PLAINTEXT_SIZE..ENC_CIPHERTEXT_SIZE].copy_from_slice(&tag);
assert_eq!(
ChachaPolyIetf::aead_cipher()
.seal_to(&mut output, &input, &[], &key.as_bytes(), &[0u8; 12])
.unwrap(),
ENC_CIPHERTEXT_SIZE
);
output
}
@ -263,23 +258,26 @@ impl SaplingNoteEncryption {
) -> [u8; OUT_CIPHERTEXT_SIZE] {
let key = prf_ock(&self.ovk, &cv, &cmu, &self.epk);
let mut input = [0u8; OUT_PLAINTEXT_SIZE];
self.note.pk_d.write(&mut input[0..32]).unwrap();
let mut buf = [0u8; OUT_CIPHERTEXT_SIZE];
self.note.pk_d.write(&mut buf[0..32]).unwrap();
self.esk
.into_repr()
.write_le(&mut input[32..OUT_PLAINTEXT_SIZE])
.write_le(&mut buf[32..OUT_PLAINTEXT_SIZE])
.unwrap();
let mut buffer = Vec::with_capacity(OUT_PLAINTEXT_SIZE);
let tag =
chacha20_poly1305_aead::encrypt(key.as_bytes(), &[0u8; 12], &[], &input, &mut buffer)
.unwrap();
let mut output = [0u8; OUT_CIPHERTEXT_SIZE];
output[0..OUT_PLAINTEXT_SIZE].copy_from_slice(&buffer);
output[OUT_PLAINTEXT_SIZE..OUT_CIPHERTEXT_SIZE].copy_from_slice(&tag[..]);
output
assert_eq!(
ChachaPolyIetf::aead_cipher()
.seal(
&mut buf,
OUT_PLAINTEXT_SIZE,
&[],
key.as_bytes(),
&[0u8; 12]
)
.unwrap(),
OUT_CIPHERTEXT_SIZE
);
buf
}
}
@ -329,16 +327,19 @@ pub fn try_sapling_note_decryption(
let shared_secret = sapling_ka_agree(ivk, epk);
let key = kdf_sapling(&shared_secret, &epk);
let mut plaintext = Vec::with_capacity(NOTE_PLAINTEXT_SIZE);
chacha20_poly1305_aead::decrypt(
key.as_bytes(),
&[0u8; 12],
&[],
&enc_ciphertext[..NOTE_PLAINTEXT_SIZE],
&enc_ciphertext[NOTE_PLAINTEXT_SIZE..],
&mut plaintext,
)
.ok()?;
let mut plaintext = vec![0; ENC_CIPHERTEXT_SIZE];
assert_eq!(
ChachaPolyIetf::aead_cipher()
.open_to(
&mut plaintext,
&enc_ciphertext,
&[],
key.as_bytes(),
&[0u8; 12]
)
.ok()?,
NOTE_PLAINTEXT_SIZE
);
let (note, to) = parse_note_plaintext_minus_memo(ivk, cmu, &plaintext)?;
@ -364,18 +365,24 @@ pub fn try_sapling_compact_note_decryption(
let shared_secret = sapling_ka_agree(ivk, epk);
let key = kdf_sapling(&shared_secret, &epk);
let mut chacha20 = ChaCha20::new(key.as_bytes(), &[0u8; 12]);
// Skip over Poly1305 keying output
chacha20.next();
let mut plaintext = Vec::with_capacity(COMPACT_NOTE_SIZE);
// Prefix plaintext with 64 zero-bytes to skip over Poly1305 keying output
const CHACHA20_BLOCK_SIZE: usize = 64;
let mut plaintext = Vec::with_capacity(CHACHA20_BLOCK_SIZE + COMPACT_NOTE_SIZE);
plaintext.extend_from_slice(&[0; CHACHA20_BLOCK_SIZE]);
plaintext.extend_from_slice(&enc_ciphertext[0..COMPACT_NOTE_SIZE]);
let keystream = chacha20.next();
for i in 0..COMPACT_NOTE_SIZE {
plaintext[i] ^= keystream.as_bytes()[i];
}
assert_eq!(
ChaCha20Ietf::cipher()
.decrypt(
&mut plaintext,
CHACHA20_BLOCK_SIZE + COMPACT_NOTE_SIZE,
key.as_bytes(),
&[0u8; 12],
)
.ok()?,
CHACHA20_BLOCK_SIZE + COMPACT_NOTE_SIZE
);
parse_note_plaintext_minus_memo(ivk, cmu, &plaintext)
parse_note_plaintext_minus_memo(ivk, cmu, &plaintext[CHACHA20_BLOCK_SIZE..])
}
/// Attempts to decrypt and validate the given `enc_ciphertext` using the given `ovk`.
@ -396,16 +403,13 @@ pub fn try_sapling_output_recovery(
let ock = prf_ock(&ovk, &cv, &cmu, &epk);
let mut op = Vec::with_capacity(OUT_PLAINTEXT_SIZE);
chacha20_poly1305_aead::decrypt(
ock.as_bytes(),
&[0u8; 12],
&[],
&out_ciphertext[..OUT_PLAINTEXT_SIZE],
&out_ciphertext[OUT_PLAINTEXT_SIZE..],
&mut op,
)
.ok()?;
let mut op = vec![0; OUT_CIPHERTEXT_SIZE];
assert_eq!(
ChachaPolyIetf::aead_cipher()
.open_to(&mut op, &out_ciphertext, &[], ock.as_bytes(), &[0u8; 12])
.ok()?,
OUT_PLAINTEXT_SIZE
);
let pk_d = edwards::Point::<Bls12, _>::read(&op[0..32], &JUBJUB)
.ok()?
@ -418,16 +422,19 @@ pub fn try_sapling_output_recovery(
let shared_secret = sapling_ka_agree(&esk, &pk_d);
let key = kdf_sapling(&shared_secret, &epk);
let mut plaintext = Vec::with_capacity(NOTE_PLAINTEXT_SIZE);
chacha20_poly1305_aead::decrypt(
key.as_bytes(),
&[0u8; 12],
&[],
&enc_ciphertext[..NOTE_PLAINTEXT_SIZE],
&enc_ciphertext[NOTE_PLAINTEXT_SIZE..],
&mut plaintext,
)
.ok()?;
let mut plaintext = vec![0; ENC_CIPHERTEXT_SIZE];
assert_eq!(
ChachaPolyIetf::aead_cipher()
.open_to(
&mut plaintext,
&enc_ciphertext,
&[],
key.as_bytes(),
&[0u8; 12]
)
.ok()?,
NOTE_PLAINTEXT_SIZE
);
let mut d = [0u8; 11];
d.copy_from_slice(&plaintext[1..12]);
@ -631,6 +638,13 @@ mod tests {
let out_ciphertext = ne.encrypt_outgoing_plaintext(&cv, &cmu);
assert!(try_sapling_note_decryption(&ivk, epk, &cmu, &enc_ciphertext).is_some());
assert!(try_sapling_compact_note_decryption(
&ivk,
epk,
&cmu,
&enc_ciphertext[..COMPACT_NOTE_SIZE]
)
.is_some());
assert!(try_sapling_output_recovery(
&ovk,
&cv,

Loading…
Cancel
Save