zcash_note_encryption: Add API to prepare epk.

Co-authored-by: Jack Grigg <jack@electriccoin.co>
Signed-off-by: Daira Hopwood <daira@jacaranda.org>


Extracted from: 515b0a40ec
This commit is contained in:
Daira Hopwood 2022-09-12 22:52:54 +01:00
parent e6483762f2
commit f1d4498da6
4 changed files with 26 additions and 9 deletions

View File

@ -6,7 +6,17 @@ and this library adheres to Rust's notion of
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- `zcash_note_encryption::Domain`:
- `Domain::PreparedEphemeralPublicKey` associated type.
- `Domain::prepare_epk` method, which produces the above type.
### Changed
- MSRV is now 1.56.1.
- Migrated to `group 0.13`.
- `zcash_note_encryption::Domain` now requires `epk` to be converted to
`Domain::PreparedEphemeralPublicKey` before being passed to
`Domain::ka_agree_dec`.
- Changes to batch decryption APIs:
- The return types of `batch::try_note_decryption` and
`batch::try_compact_note_decryption` have changed. Now, instead of
@ -16,8 +26,5 @@ and this library adheres to Rust's notion of
argument to the function. Each successful result includes the index of the
entry in `ivks` used to decrypt the value.
### Changed
- MSRV is now 1.56.1.
## [0.1.0] - 2021-12-17
Initial release.

View File

@ -21,6 +21,7 @@ rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
chacha20 = { version = "0.8", default-features = false }
chacha20poly1305 = { version = "0.9", default-features = false }
group = "0.12"
rand_core = { version = "0.6", default-features = false }
subtle = { version = "2.2.3", default-features = false }

View File

@ -51,7 +51,7 @@ where
return (0..outputs.len()).map(|_| None).collect();
};
// Fetch the ephemeral keys for each output and batch-parse them.
// Fetch the ephemeral keys for each output, and batch-parse and prepare them.
let ephemeral_keys = D::batch_epk(outputs.iter().map(|(_, output)| output.ephemeral_key()));
// Derive the shared secrets for all combinations of (ivk, output).

View File

@ -113,6 +113,7 @@ enum NoteValidity {
pub trait Domain {
type EphemeralSecretKey: ConstantTimeEq;
type EphemeralPublicKey;
type PreparedEphemeralPublicKey;
type SharedSecret;
type SymmetricKey: AsRef<[u8]>;
type Note;
@ -136,6 +137,9 @@ pub trait Domain {
/// Extracts the `DiversifiedTransmissionKey` from the note.
fn get_pk_d(note: &Self::Note) -> Self::DiversifiedTransmissionKey;
/// Prepare an ephemeral public key for more efficient scalar multiplication.
fn prepare_epk(epk: Self::EphemeralPublicKey) -> Self::PreparedEphemeralPublicKey;
/// Derives `EphemeralPublicKey` from `esk` and the note's diversifier.
fn ka_derive_public(
note: &Self::Note,
@ -152,7 +156,7 @@ pub trait Domain {
/// decryption.
fn ka_agree_dec(
ivk: &Self::IncomingViewingKey,
epk: &Self::EphemeralPublicKey,
epk: &Self::PreparedEphemeralPublicKey,
) -> Self::SharedSecret;
/// Derives the `SymmetricKey` used to encrypt the note plaintext.
@ -306,10 +310,15 @@ pub trait BatchDomain: Domain {
/// them.
fn batch_epk(
ephemeral_keys: impl Iterator<Item = EphemeralKeyBytes>,
) -> Vec<(Option<Self::EphemeralPublicKey>, EphemeralKeyBytes)> {
) -> Vec<(Option<Self::PreparedEphemeralPublicKey>, EphemeralKeyBytes)> {
// Default implementation: do the non-batched thing.
ephemeral_keys
.map(|ephemeral_key| (Self::epk(&ephemeral_key), ephemeral_key))
.map(|ephemeral_key| {
(
Self::epk(&ephemeral_key).map(Self::prepare_epk),
ephemeral_key,
)
})
.collect()
}
}
@ -514,7 +523,7 @@ pub fn try_note_decryption<D: Domain, Output: ShieldedOutput<D, ENC_CIPHERTEXT_S
) -> Option<(D::Note, D::Recipient, D::Memo)> {
let ephemeral_key = output.ephemeral_key();
let epk = D::epk(&ephemeral_key)?;
let epk = D::prepare_epk(D::epk(&ephemeral_key)?);
let shared_secret = D::ka_agree_dec(ivk, &epk);
let key = D::kdf(shared_secret, &ephemeral_key);
@ -611,7 +620,7 @@ pub fn try_compact_note_decryption<D: Domain, Output: ShieldedOutput<D, COMPACT_
) -> Option<(D::Note, D::Recipient)> {
let ephemeral_key = output.ephemeral_key();
let epk = D::epk(&ephemeral_key)?;
let epk = D::prepare_epk(D::epk(&ephemeral_key)?);
let shared_secret = D::ka_agree_dec(ivk, &epk);
let key = D::kdf(shared_secret, &ephemeral_key);