Merge pull request #633 from daira/prepare-epks-and-ivks
Add APIs to prepare ivk and epk and implement them for Sapling
Extracted from: 84835035d5
This commit is contained in:
commit
61a2c3ef72
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -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.
|
||||
|
|
|
@ -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 }
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
|
19
src/lib.rs
19
src/lib.rs
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue