Closed orlp closed 11 months ago
The AES intrinsics are not correctly implemented on ARM. These are the implementations (stripped of compiler directives for posterity):
pub(crate) fn aesenc_x86(value: u128, xor: u128) -> u128 { use core::arch::x86_64::*; unsafe { let value = transmute(value); transmute(_mm_aesenc_si128(value, transmute(xor))) } } pub(crate) fn aesenc_arm(value: u128, xor: u128) -> u128 { use core::arch::aarch64::*; unsafe { let value = transmute(value); transmute(vaesmcq_u8(vaeseq_u8(value, transmute(xor)))) } }
In detail, we see the following intrinsic for x86:
_mm_aesenc_si128(value, transmute(xor))
This is xor ^ MixColumns(SubBytes(ShiftRows(value))). For ARM on the other hand we have:
xor ^ MixColumns(SubBytes(ShiftRows(value)))
vaesmcq_u8(vaeseq_u8(value, transmute(xor)))
This is MixColumns(SubBytes(ShiftRows(xor ^ value))).
MixColumns(SubBytes(ShiftRows(xor ^ value)))
This difference goes wrong in a nuclear fashion in the final step of the specialized hash:
#[cfg(feature = "specialize")] fn short_finish(&self) -> u64 { let combined = aesdec(self.sum, self.enc); let result: [u64; 2] = aesenc(combined, combined).convert(); result[0] }
The first step of aesenc(combined, combined) on ARM is combined ^ combined, which simplifies to... the constant 0. That is, aHash's specialized hash implementation used by hash_one on ARM is always a constant value.
aesenc(combined, combined)
combined ^ combined
hash_one
The AES intrinsics are not correctly implemented on ARM. These are the implementations (stripped of compiler directives for posterity):
In detail, we see the following intrinsic for x86:
This is
xor ^ MixColumns(SubBytes(ShiftRows(value)))
. For ARM on the other hand we have:This is
MixColumns(SubBytes(ShiftRows(xor ^ value)))
.This difference goes wrong in a nuclear fashion in the final step of the specialized hash:
The first step of
aesenc(combined, combined)
on ARM iscombined ^ combined
, which simplifies to... the constant 0. That is, aHash's specialized hash implementation used byhash_one
on ARM is always a constant value.