e2e-protection 0.2.0

Pluggable End-to-End (E2E) protection profiles. First class support for AUTOSAR P11 (CAN) and P22 (CAN FD).
Documentation
// Internal generic MSB-first CRC engine with presets.
// No public re-exports; not part of the crate surface.

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct CrcParams {
    pub width: u8,
    pub poly: u128,
    pub init: u128,
    pub refin: bool,
    pub refout: bool,
    pub xorout: u128,
    pub msb_first: bool,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CrcPreset {
    Crc8SaeJ1850,
    Crc8H2F,
    Crc16CcittFalse,
    Crc32IsoHdlc,
    Crc64Ecma182,
    Custom(CrcParams),
}

pub fn params_for(preset: CrcPreset) -> CrcParams {
    match preset {
        CrcPreset::Crc8SaeJ1850 => CrcParams { width:8,  poly:0x1D, init:0xFF, refin:false, refout:false, xorout:0xFF, msb_first:true },
        CrcPreset::Crc8H2F      => CrcParams { width:8,  poly:0x2F, init:0xFF, refin:false, refout:false, xorout:0xFF, msb_first:true },
        CrcPreset::Crc16CcittFalse => CrcParams { width:16, poly:0x1021, init:0xFFFF, refin:false, refout:false, xorout:0x0000, msb_first:true },
        CrcPreset::Crc32IsoHdlc => CrcParams { width:32, poly:0x04C11DB7, init:0xFFFF_FFFF, refin:true, refout:true, xorout:0xFFFF_FFFF, msb_first:true },
        CrcPreset::Crc64Ecma182 => CrcParams { width:64, poly:0x42F0E1EBA9EA3693, init:0, refin:false, refout:false, xorout:0, msb_first:true },
        CrcPreset::Custom(p) => p,
    }
}

#[inline]
fn reflect(mut x: u128, bits: u8) -> u128 {
    let mut r = 0u128;
    for _ in 0..bits { r = (r << 1) | (x & 1); x >>= 1; }
    r
}

pub fn crc_compute(p: CrcParams, data: &[u8]) -> u128 {
    debug_assert!(p.width >= 8 && p.width <= 64);
    debug_assert!(p.msb_first);

    let w = p.width;
    let top_bit = 1u128 << (w - 1);
    let mask = if w == 128 { !0 } else { (1u128 << w) - 1 };
    let mut reg = p.init & mask;

    for &b in data {
        let byte = if p.refin { reflect(b as u128, 8) as u8 } else { b };
        reg ^= (byte as u128) << (w - 8);
        for _ in 0..8 {
            if (reg & top_bit) != 0 { reg = ((reg << 1) ^ p.poly) & mask; }
            else { reg = (reg << 1) & mask; }
        }
    }
    if p.refout { reg = reflect(reg, w); }
    (reg ^ p.xorout) & mask
}