-
Notifications
You must be signed in to change notification settings - Fork 215
Encoding Collision Resistance #1816
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Sounds good, but I am not sure that Another open question is what to do with truncated outputs. For example, what should we use for the "collision resistance" number of BLAKE2b used with output variable at runtime (i.e. |
Maybe a separate trait is necessary then?
I don't know where this is used exactly, but if desirable these would need a different trait. E.g.
I was thinking along the lines of: impl<OutSize> CollisionResistanceFixed for Blake2b<OutSize>
where
OutSize: ArrayLength<u8> + IsLessOrEqual<U64, Output = True> + Mul<U8>,
Prod<OutSize, U8>: Div<U2>,
Quot<Prod<OutSize, U8>, U2>: Unsigned,
{
type CollisionResistance = Quot<Prod<OutSize, U8>, U2>;
}
It seems to me that we need to go with whats claimed. Otherwise constraints would block certain hashes that would be needed in practice but in the meantime had their collision resistance reduced because of discovered attacks. So after some more thinking with the input you gave, I propose the following: trait CollisionResistanceFixed {
type CollisionResistance: Unsigned;
}
trait CollisionResistanceXof {
fn collision_resistance_with_output(len: u64) -> u16;
}
trait CollisionResistanceVar {
fn collision_resistance(&self) -> u16;
}
// Implementation Examples
impl<OutSize> CollisionResistanceFixed for Blake2b<OutSize>
where
OutSize: ArrayLength<u8> + IsLessOrEqual<U64, Output = True> + Mul<U8>,
Prod<OutSize, U8>: Div<U2>,
Quot<Prod<OutSize, U8>, U2>: Unsigned,
{
type CollisionResistance = Quot<Prod<OutSize, U8>, U2>;
}
impl CollisionResistanceXof for Shake256 {
fn collision_resistance_with_output(len: u64) -> u16 {
((len / 2).min(256)) as u16
}
}
impl CollisionResistanceVar for Blake2bVar {
fn collision_resistance(&self) -> u16 {
(self.output_size() * 8 / 2) as u16
}
}
#[test]
fn test() {
assert_eq!(
<Blake2b<U64> as CollisionResistanceFixed>::CollisionResistance::U16,
256
);
assert_eq!(
<Blake2b<U32> as CollisionResistanceFixed>::CollisionResistance::U16,
128
);
assert_eq!(Shake256::collision_resistance_with_output(512), 256);
assert_eq!(Shake256::collision_resistance_with_output(256), 128);
assert_eq!(Shake256::collision_resistance_with_output(1024), 256);
assert_eq!(Blake2bVar::new(64).unwrap().collision_resistance(), 256);
assert_eq!(Blake2bVar::new(32).unwrap().collision_resistance(), 128);
} If there is a demand to "query" XOFs at compile time, we could also provide this: trait CollisionResistanceXofConst<O> {
type CollisionResistance: Unsigned;
}
// Implementation Example
impl<O> CollisionResistanceXofConst<O> for Shake256
where
O: Mul<U2>,
Prod<O, U2>: Div<U2>,
Quot<Prod<O, U2>, U2>: Min<U256>,
Minimum<Quot<Prod<O, U2>, U2>, U256>: Unsigned,
{
type CollisionResistance = Minimum<Quot<Prod<O, U2>, U2>, U256>;
} |
I am not sure about utility of |
To address the constraints around hash2curve, at least
E.g. SHAKE-256, doesn't have fixed variants. Do we want to introduce fixed variants on demand, or did you have something else in mind? E.g. for my use-case that would be 512-bit output size. The newly introduced |
SHAKE-n provides n bits of collision resistance assuming you generated at least 2*n bits. In the trait we could specify this number with the caveat that users have to generate the sufficient number of bits to achieve it. We also could apply the same principle to the hashes with output size variable at runtime. |
So going back to Unless the formula In this case the proposal would look like this: trait CollisionResistance {
type CollisionResistance: Unsigned;
type OutputSize: ArrayLength<u8>;
} |
I think it should apply to all non-broken hashes. We probably can just use: trait CollisionResistance {
type CollisionResistance: Unsigned;
} Whether users have to take into account output size or not will depend on the concrete use case. |
Nice! Thanks for confirming!
I'm not following, do you mean you would like to see a use case?
And the output size of the hash is defined by the parameter Equally I intend to enforce this limit at compile-time if possible in Apologies if I misunderstood your intention here! |
I mean that you would have to write in your code: // Assuming K is converted to bytes
if 2 * len_in_bytes < K || H::CollisionResistance::USIZE < K {
return Err(...);
} In other words, handling potential smaller lengths used in runtime would not be an area of responsibility of the |
Sure, that works for me. |
When creating protocols/algorithms that are generic over hashes, it could be useful to constrain hashes depending on their collision resistance.
The primary motivation, which also serves as an example, is properly constraining
ExpandMsg
implementations according to the spec. Bothexpand_message_xmd
andexpand_message_xof
require the hash's collision resistance to be at least higher than the curves security level.For
expand_message_xmd
this was simpler, because it requires a hash with a fixed output, so the requirement is set that the output size of the hash has to be at least twice the security level of the curve. I implemented this constraint in #1813. I don't know if this is a general property of cryptographically secure hash algorithm, but I suspect it just aligns with SHA-2/SHA-3.For
expand_message_xof
, there is currently no way to extract any information from an existing trait about this. However, e.g. for SHAKE the specification is quite clear about the collision resistance.I propose adding an associated type to
HashMarker
, like this:I'm happy to do the implementation upon approval!
The text was updated successfully, but these errors were encountered: