e2e-protection 0.3.0

End-to-End protection core with pluggable profiles. AUTOSAR (P11/P22) profile family is optional via feature
Documentation
// Internal generic MSB-first CRC engine with presets (not re-exported).

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct CrcParams {
    pub width: u8,     // 8/16/32/64
    pub poly: u128,
    pub init: u128,
    pub refin: bool,
    pub refout: bool,
    pub xorout: u128,
    pub msb_first: bool, // v0.1+: true
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CrcPreset {
    Crc8SaeJ1850,       // poly=0x1D, init=0xFF, refin=false, refout=false, xorout=0xFF
    Crc8H2F,            // poly=0x2F, init=0xFF, refin=false, refout=false, xorout=0xFF
    Crc16CcittFalse,    // poly=0x1021, init=0xFFFF, refin=false, refout=false, xorout=0x0000
    Crc32IsoHdlc,       // poly=0x04C11DB7, init=0xFFFFFFFF, refin=true,  refout=true,  xorout=0xFFFFFFFF
    Crc64Ecma182,       // poly=0x42F0E1EBA9EA3693, init=0, refin=false, refout=false, xorout=0
    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
}