in src/util.rs [272:350]
fn compute_composites<
CS: CipherSuite,
IC: Iterator<Item = <CS::Group as Group>::Elem> + ExactSizeIterator,
ID: Iterator<Item = <CS::Group as Group>::Elem> + ExactSizeIterator,
>(
k_option: Option<<CS::Group as Group>::Scalar>,
b: <CS::Group as Group>::Elem,
c_slice: IC,
d_slice: ID,
mode: Mode,
) -> Result<ComputeCompositesResult<CS>>
where
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-08.html#section-3.3.2.3-2
let elem_len = <CS::Group as Group>::ElemLen::U16.to_be_bytes();
if c_slice.len() != d_slice.len() {
return Err(Error::Batch);
}
let len = u16::try_from(c_slice.len()).map_err(|_| Error::Batch)?;
// seedDST = "Seed-" || contextString
let seed_dst = GenericArray::from(STR_SEED).concat(create_context_string::<CS>(mode));
// h1Input = I2OSP(len(Bm), 2) || Bm ||
// I2OSP(len(seedDST), 2) || seedDST
// seed = Hash(h1Input)
let seed = CS::Hash::new()
.chain_update(&elem_len)
.chain_update(CS::Group::serialize_elem(b))
.chain_update(i2osp_2_array(&seed_dst))
.chain_update(seed_dst)
.finalize();
let seed_len = i2osp_2_array(&seed);
let mut m = CS::Group::identity_elem();
let mut z = CS::Group::identity_elem();
for (i, (c, d)) in (0..len).zip(c_slice.zip(d_slice)) {
// Ci = GG.SerializeElement(Cs[i])
let ci = CS::Group::serialize_elem(c);
// Di = GG.SerializeElement(Ds[i])
let di = CS::Group::serialize_elem(d);
// h2Input = I2OSP(len(seed), 2) || seed || I2OSP(i, 2) ||
// I2OSP(len(Ci), 2) || Ci ||
// I2OSP(len(Di), 2) || Di ||
// "Composite"
let h2_input = [
seed_len.as_slice(),
&seed,
&i.to_be_bytes(),
&elem_len,
&ci,
&elem_len,
&di,
&STR_COMPOSITE,
];
let dst = GenericArray::from(STR_HASH_TO_SCALAR).concat(create_context_string::<CS>(mode));
// This can't fail, the size of the `input` is known.
let di = CS::Group::hash_to_scalar::<CS>(&h2_input, &dst).unwrap();
m = c * &di + &m;
z = match k_option {
Some(_) => z,
None => d * &di + &z,
};
}
z = match k_option {
Some(k) => m * &k,
None => z,
};
Ok((m, z))
}