///|
fn crc32c_step(crc : UInt, byte : Byte) -> UInt {
let mut value = crc ^ byte.to_uint()
for bit = 0; bit < 8; bit = bit + 1 {
value = if (value & 1U) != 0U {
(value >> 1) ^ 0x82f63b78U
} else {
value >> 1
}
}
value
}
///|
pub fn crc32c(data : Bytes) -> UInt {
let mut value = 0xffffffffU
for byte in data {
value = crc32c_step(value, byte)
}
value ^ 0xffffffffU
}
///|
pub fn crc32c_reference(data : Bytes) -> UInt {
let mut remainder = 0xffffffffU
for byte in data {
remainder = remainder ^ byte.to_uint()
for bit = 0; bit < 8; bit = bit + 1 {
if (remainder & 1U) == 1U {
remainder = (remainder >> 1) ^ 0x82f63b78U
} else {
remainder = remainder >> 1
}
}
}
remainder ^ 0xffffffffU
}
///|
pub fn verify_proxy_crc32c(complete_header : Bytes) -> Result[Unit, ProxyError] {
if complete_header.length() < 16 {
return Err(
proxy_error(NeedMoreData, 0, "v2 header is shorter than fixed header"),
)
}
let declared = (complete_header[14].to_int() << 8) |
complete_header[15].to_int()
if complete_header.length() != 16 + declared {
return Err(
proxy_error(
InvalidLength,
14,
"CRC validation requires exactly one complete v2 header",
),
)
}
let mut at = 16
let family = complete_header[13].to_int() >> 4
let address_length = if family == 1 {
12
} else if family == 2 {
36
} else if family == 3 {
216
} else {
0
}
if declared < address_length {
return Err(proxy_error(TruncatedAddress, 16, "address block is truncated"))
}
at = at + address_length
let mut crc_value : UInt? = None
let mut crc_offset = -1
while at < complete_header.length() {
if complete_header.length() - at < 3 {
return Err(proxy_error(TruncatedTlv, at, "incomplete TLV header"))
}
let kind = complete_header[at]
let length = (complete_header[at + 1].to_int() << 8) |
complete_header[at + 2].to_int()
if length > complete_header.length() - at - 3 {
return Err(proxy_error(TruncatedTlv, at, "truncated TLV"))
}
if kind == TLV_CRC32C {
if length != 4 {
return Err(proxy_error(InvalidTlv, at, "CRC32C TLV must be four bytes"))
}
if crc_value is Some(_) {
return Err(proxy_error(DuplicateCrc32c, at, "more than one CRC32C TLV"))
}
crc_value = Some(
(complete_header[at + 3].to_uint() << 24) |
(complete_header[at + 4].to_uint() << 16) |
(complete_header[at + 5].to_uint() << 8) |
complete_header[at + 6].to_uint(),
)
crc_offset = at + 3
}
at = at + 3 + length
}
match crc_value {
None => Err(proxy_error(MissingCrc32c, 16, "CRC32C TLV is absent"))
Some(expected) => {
let copy = complete_header.to_array()
for i = 0; i < 4; i = i + 1 {
copy[crc_offset + i] = b'\x00'
}
if crc32c(Bytes::from_array(copy)) == expected {
Ok(())
} else {
Err(proxy_error(Crc32cMismatch, crc_offset, "CRC32C checksum differs"))
}
}
}
}