2021-08-06 08:20:42 -07:00
|
|
|
//! APIs for batch trial decryption.
|
|
|
|
|
2021-11-24 05:58:52 -08:00
|
|
|
use alloc::vec::Vec; // module is alloc only
|
2021-08-06 08:20:42 -07:00
|
|
|
|
|
|
|
use crate::{
|
2021-11-17 04:14:26 -08:00
|
|
|
try_compact_note_decryption_inner, try_note_decryption_inner, BatchDomain, EphemeralKeyBytes,
|
2021-12-16 21:13:52 -08:00
|
|
|
ShieldedOutput, COMPACT_NOTE_SIZE, ENC_CIPHERTEXT_SIZE,
|
2021-08-06 08:20:42 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
/// Trial decryption of a batch of notes with a set of recipients.
|
|
|
|
///
|
2021-09-01 09:21:05 -07:00
|
|
|
/// This is the batched version of [`crate::try_note_decryption`].
|
2022-07-25 18:06:53 -07:00
|
|
|
///
|
|
|
|
/// Returns a vector containing the decrypted result for each output,
|
|
|
|
/// with the same length and in the same order as the outputs were
|
|
|
|
/// provided, along with the index in the `ivks` slice associated with
|
|
|
|
/// the IVK that successfully decrypted the output.
|
2021-08-30 09:50:25 -07:00
|
|
|
#[allow(clippy::type_complexity)]
|
2021-12-16 21:13:52 -08:00
|
|
|
pub fn try_note_decryption<D: BatchDomain, Output: ShieldedOutput<D, ENC_CIPHERTEXT_SIZE>>(
|
2021-08-06 08:20:42 -07:00
|
|
|
ivks: &[D::IncomingViewingKey],
|
|
|
|
outputs: &[(D, Output)],
|
2022-07-25 18:06:53 -07:00
|
|
|
) -> Vec<Option<((D::Note, D::Recipient, D::Memo), usize)>> {
|
2021-08-06 08:20:42 -07:00
|
|
|
batch_note_decryption(ivks, outputs, try_note_decryption_inner)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Trial decryption of a batch of notes for light clients with a set of recipients.
|
|
|
|
///
|
2021-09-01 09:21:05 -07:00
|
|
|
/// This is the batched version of [`crate::try_compact_note_decryption`].
|
2022-07-25 18:06:53 -07:00
|
|
|
///
|
|
|
|
/// Returns a vector containing the decrypted result for each output,
|
|
|
|
/// with the same length and in the same order as the outputs were
|
|
|
|
/// provided, along with the index in the `ivks` slice associated with
|
|
|
|
/// the IVK that successfully decrypted the output.
|
|
|
|
#[allow(clippy::type_complexity)]
|
2021-12-16 21:13:52 -08:00
|
|
|
pub fn try_compact_note_decryption<D: BatchDomain, Output: ShieldedOutput<D, COMPACT_NOTE_SIZE>>(
|
2021-08-06 08:20:42 -07:00
|
|
|
ivks: &[D::IncomingViewingKey],
|
|
|
|
outputs: &[(D, Output)],
|
2022-07-25 18:06:53 -07:00
|
|
|
) -> Vec<Option<((D::Note, D::Recipient), usize)>> {
|
2021-08-06 08:20:42 -07:00
|
|
|
batch_note_decryption(ivks, outputs, try_compact_note_decryption_inner)
|
|
|
|
}
|
|
|
|
|
2021-12-16 21:13:52 -08:00
|
|
|
fn batch_note_decryption<D: BatchDomain, Output: ShieldedOutput<D, CS>, F, FR, const CS: usize>(
|
2021-08-06 08:20:42 -07:00
|
|
|
ivks: &[D::IncomingViewingKey],
|
|
|
|
outputs: &[(D, Output)],
|
|
|
|
decrypt_inner: F,
|
2022-07-25 18:06:53 -07:00
|
|
|
) -> Vec<Option<(FR, usize)>>
|
2021-08-06 08:20:42 -07:00
|
|
|
where
|
2022-07-25 18:06:53 -07:00
|
|
|
F: Fn(&D, &D::IncomingViewingKey, &EphemeralKeyBytes, &Output, &D::SymmetricKey) -> Option<FR>,
|
2021-08-06 08:20:42 -07:00
|
|
|
{
|
2021-08-09 18:57:11 -07:00
|
|
|
// Fetch the ephemeral keys for each output and batch-parse them.
|
|
|
|
let ephemeral_keys = D::batch_epk(outputs.iter().map(|(_, output)| output.ephemeral_key()));
|
2021-08-06 08:20:42 -07:00
|
|
|
|
|
|
|
// Derive the shared secrets for all combinations of (ivk, output).
|
2021-08-09 18:57:11 -07:00
|
|
|
// The scalar multiplications cannot benefit from batching.
|
2022-07-25 18:06:53 -07:00
|
|
|
let items = ephemeral_keys.iter().flat_map(|(epk, ephemeral_key)| {
|
|
|
|
ivks.iter().map(move |ivk| {
|
2021-08-06 08:20:42 -07:00
|
|
|
(
|
2021-08-09 18:57:11 -07:00
|
|
|
epk.as_ref().map(|epk| D::ka_agree_dec(ivk, epk)),
|
2021-08-06 08:20:42 -07:00
|
|
|
ephemeral_key,
|
|
|
|
)
|
|
|
|
})
|
|
|
|
});
|
|
|
|
|
|
|
|
// Run the batch-KDF to obtain the symmetric keys from the shared secrets.
|
|
|
|
let keys = D::batch_kdf(items);
|
|
|
|
|
|
|
|
// Finish the trial decryption!
|
2022-07-25 18:06:53 -07:00
|
|
|
keys.chunks(ivks.len())
|
|
|
|
.zip(ephemeral_keys.iter().zip(outputs.iter()))
|
|
|
|
.map(|(key_chunk, ((_, ephemeral_key), (domain, output)))| {
|
|
|
|
key_chunk
|
|
|
|
.iter()
|
|
|
|
.zip(ivks.iter().enumerate())
|
|
|
|
.filter_map(|(key, (i, ivk))| {
|
|
|
|
key.as_ref()
|
|
|
|
.and_then(|key| decrypt_inner(domain, ivk, ephemeral_key, output, key))
|
|
|
|
.map(|out| (out, i))
|
|
|
|
})
|
|
|
|
.next()
|
2021-08-06 08:20:42 -07:00
|
|
|
})
|
2022-07-25 18:06:53 -07:00
|
|
|
.collect::<Vec<Option<_>>>()
|
2021-08-06 08:20:42 -07:00
|
|
|
}
|