///|
/// Calculate the reflected IEEE CRC-32 checksum.
pub fn crc32(data : Bytes) -> UInt {
let mut crc = 0xFFFFFFFFU
for byte in data {
crc = crc ^ byte.to_uint()
for bit = 0; bit < 8; bit = bit + 1 {
if (crc & 1U) != 0U {
crc = (crc >> 1) ^ 0xEDB88320U
} else {
crc = crc >> 1
}
}
}
crc ^ 0xFFFFFFFFU
}
///|
/// Calculate CRC-16/CCITT-FALSE with initial value `0xFFFF`.
pub fn crc16_ccitt_false(data : Bytes) -> Int {
let mut crc = 0xFFFF
for byte in data {
crc = crc ^ (byte.to_int() << 8)
for bit = 0; bit < 8; bit = bit + 1 {
if (crc & 0x8000) != 0 {
crc = ((crc << 1) ^ 0x1021) & 0xFFFF
} else {
crc = (crc << 1) & 0xFFFF
}
}
}
crc
}
///|
pub(all) struct SegmentDigest {
address_value : UInt64
length_value : Int
crc32_value : UInt
crc16_value : Int
} derive(Eq, Debug)
///|
pub struct ImageManifest {
segment_digest_values : Array[SegmentDigest]
total_bytes_value : Int
entry_point_value : UInt64?
fingerprint_value : UInt
} derive(Eq, Debug)
///|
fn crc32_update_byte(crc : UInt, byte : Byte) -> UInt {
let mut value = crc ^ byte.to_uint()
for bit = 0; bit < 8; bit = bit + 1 {
if (value & 1U) != 0U {
value = (value >> 1) ^ 0xEDB88320U
} else {
value = value >> 1
}
}
value
}
///|
fn image_fingerprint(image : FirmwareImage) -> UInt {
let mut crc = 0xFFFFFFFFU
for segment in image.segments() {
let address = segment.address()
for index = 0; index < 8; index = index + 1 {
let shift = (7 - index) * 8
crc = crc32_update_byte(crc, ((address >> shift) & 0xFFUL).to_byte())
}
let length = segment.length().to_uint64()
for index = 0; index < 8; index = index + 1 {
let shift = (7 - index) * 8
crc = crc32_update_byte(crc, ((length >> shift) & 0xFFUL).to_byte())
}
for byte in segment.data() {
crc = crc32_update_byte(crc, byte)
}
}
crc ^ 0xFFFFFFFFU
}
///|
/// Build reproducible per-segment checksums and an address-sensitive fingerprint.
pub fn build_manifest(image : FirmwareImage) -> ImageManifest {
let digests : Array[SegmentDigest] = []
for segment in image.segments() {
let data = segment.data()
digests.push({
address_value: segment.address(),
length_value: segment.length(),
crc32_value: crc32(data),
crc16_value: crc16_ccitt_false(data),
})
}
{
segment_digest_values: digests,
total_bytes_value: image.total_bytes(),
entry_point_value: image.entry_point(),
fingerprint_value: image_fingerprint(image),
}
}
///|
pub fn SegmentDigest::address(self : SegmentDigest) -> UInt64 {
self.address_value
}
///|
pub fn SegmentDigest::length(self : SegmentDigest) -> Int {
self.length_value
}
///|
pub fn SegmentDigest::crc32(self : SegmentDigest) -> UInt {
self.crc32_value
}
///|
pub fn SegmentDigest::crc16(self : SegmentDigest) -> Int {
self.crc16_value
}
///|
pub fn ImageManifest::segment_digests(
self : ImageManifest,
) -> Array[SegmentDigest] {
self.segment_digest_values.copy()
}
///|
pub fn ImageManifest::total_bytes(self : ImageManifest) -> Int {
self.total_bytes_value
}
///|
pub fn ImageManifest::entry_point(self : ImageManifest) -> UInt64? {
self.entry_point_value
}
///|
pub fn ImageManifest::fingerprint(self : ImageManifest) -> UInt {
self.fingerprint_value
}