Description
Summary
From the audit report point BLS01:
The h()
function in hash.rs hashes to a subgroup element by truncating
a 64-byte BLAKE2B hash to BlsScalar::SIZE=32
bytes, then clearing the
top 2 bytes to obtain a value less than 2254:
/// Hash an arbitrary slice of bytes into a [`BlsScalar`]
fn h(msg: &[u8]) -> BlsScalar {
let mut digest: [u8; BlsScalar::SIZE] = Blake2b::digest(msg).into();
// Truncate the contract id to fit bls
digest[31] &= 0x3f;
let hash: Option<BlsScalar> = BlsScalar::from_bytes(&digest).into();
hash.unwrap_or_default()
}
However with such an implementation, certain subgroup elements cannot be
reached: as the subgroup size
0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 is
approx. 2254.857.
It means that certain points will never be reached by h0()
, and
certain scalars will never be reached by h1()
(approx.
2253.7.
This appears to us not to be exploitable, but it would be safer to
implement the standard hash_to_field()
function, as defined in the
Hashing to Ellpitic
Curve
RFC and implemented in
zkcrypto/bls12_381.
Possible Solution
We can use our BlsScalar::hash_to_scalar(msg)
here.