Livt packages
Livt.Utils
Version 1.1.1
Reusable Livt utility components, including configurable CRC helpers and CRC32.
Published files (8)
src/hashing/Crc.lvt
namespace Livt.Utils.Hashing
/**
* Pure CRC updates, specialized at compile time; no storage, clock or lookup RAM.
* POLYNOMIAL uses normal notation without its leading x^WIDTH term. REFLECTED
* selects a right-shifting register and least-significant input bit first.
* The caller owns the running state and supplies the profile's initial value.
* Finalize applies optional register reflection followed by XOR_OUT; it does not
* choose wire byte order. Never feed a finalized value back into UpdateByte.
*/
component Crc<WIDTH: int = 32, POLYNOMIAL: uint = 0x04C11DB7, REFLECTED: bool = true>
{
static assert WIDTH >= 1 && WIDTH <= 32, "CRC width must be 1 through 32"
static assert POLYNOMIAL != 0, "CRC polynomial must be nonzero"
static assert ((POLYNOMIAL as logic[WIDTH]) as uint) == POLYNOMIAL, "CRC polynomial must fit its width"
/**
* Reverses exactly WIDTH bits, independent of byte boundaries.
*/
public fn Reflect[](value: logic[WIDTH]) logic[WIDTH]
{
var result: logic[WIDTH] = 0
for (var index = 0; index < WIDTH; index++) {
result = (result << 1) | ((value >> index) & 1)
}
return result
}
/**
* Advances by one bit supplied in transmission order.
*/
public fn UpdateBit[](crc: logic[WIDTH], value: bool) logic[WIDTH]
{
var polynomial = POLYNOMIAL as logic[WIDTH]
var feedback = ((crc >> (WIDTH - 1)) & 1) != 0
var next = crc << 1
if (REFLECTED) {
polynomial = Reflect(polynomial)
feedback = (crc & 1) != 0
next = crc >> 1
}
if (feedback != value) {
next = next ^ polynomial
}
return next
}
/**
* Advances by eight bits; reflection selects input bit order as well as state.
*/
public fn UpdateByte[](crc: logic[WIDTH], value: byte) logic[WIDTH]
{
var next = crc
for (var index = 0; index < 8; index++) {
var shift = 7 - index
if (REFLECTED) {
shift = index
}
next = UpdateBit(next, (((value as uint) >> shift) & 1) != 0)
}
return next
}
/**
* Advances by count bits (0..32) of value, starting at its least-significant
* bit for reflected profiles or bit count-1 otherwise. No byte padding.
*/
public fn UpdateBits[](crc: logic[WIDTH], value: uint, count: int) logic[WIDTH]
{
var next = crc
for (var index = 0; index < 32; index++) {
var shift = count - 1 - index
if (REFLECTED) {
shift = index
}
if (index < count && count <= 32) {
next = UpdateBit(next, ((value >> shift) & 1) != 0)
}
}
return next
}
/**
* Produces a checksum without changing the caller's running state.
* reverse reverses the current register orientation, not the input bytes.
*/
public fn Finalize[](crc: logic[WIDTH], xorOut: logic[WIDTH], reverse: bool) logic[WIDTH]
{
var result = crc
if (reverse) {
result = Reflect(result)
}
return result ^ xorOut
}
}