// KoopmanP examples -- Chapter 8 // Copyright 2024 Philip Koopman // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "chapter8_examples.h" #include static const uint32_t initialSeed = SEED; // initial sum // Computes parity of 32-bit input value via XOR folding static uint32_t Parity(uint32_t value) { uint32_t parity = value; parity ^= (parity>>16); parity ^= (parity>>8); parity ^= (parity>>4); parity ^= (parity>>2); parity ^= (parity>>1); parity &= 1; return(parity); } // ---------------------- // Example from section 8.5.1 // Adaptive modulo with 16-bit block processing // dataWord: data word in 8-bit blocks processed // dwSize: number of 8-bit blocks in the data word // modulus: modulus for both running sums uint16_t DualX16P(uint8_t dataWord[], uint32_t dwSize, uint32_t modulus) { assert(modulus == 125); assert((dwSize & 1) == 0); uint32_t sumA = initialSeed; // Initialize sumA uint32_t sumB = initialSeed; // Initialize sumB uint32_t parityC = 0; // Initialize parity const uint32_t blockSize = 2; for(uint32_t index = 0; index < dwSize; index += blockSize ) { // Add next data word byte with modulus uint32_t block = (((uint32_t)dataWord[index+1])<<0) | (((uint32_t)dataWord[index+0])<<8); sumA = (sumA + block); sumB = (sumB + sumA); parityC ^= block; // Time for a modulo if sumB is saturated const uint32_t topBits = 0xC0000000; if((sumB & topBits) != 0) { sumA = sumA % modulus; sumB = sumB % modulus; } } // Final deferred modulo sumA = sumA % modulus; sumB = sumB % modulus; // Shift sumA left 8 bits for aggregate check value // Shift sumA left 1 bit to leave room for parity bit uint32_t concatenated = (uint32_t) ((sumA <<8) | (sumB <<1)); parityC ^= concatenated; // Return checksum value return((uint16_t) (concatenated | Parity(parityC))); } // ---------------------- // Example from section 8.5.2 // Adaptive modulo with 32-bit block processing // dataWord: data word in 8-bit blocks processed // dwSize: number of 8-bit blocks in the data word // modulus: modulus for both running sums uint32_t DualX32P(uint8_t dataWord[], uint32_t dwSize, uint32_t modulus) { assert(modulus == 32749); assert((dwSize & 3) == 0); uint64_t sumA = initialSeed; // Initialize sumA uint64_t sumB = initialSeed; // Initialize sumB uint32_t parityC = 0; // Initialize parity // Loop over all bytes in data word const uint32_t blockSize = 4; for(uint32_t index = 0; index < dwSize; index += blockSize ) { // Add next data word byte with modulus uint32_t block =(((uint32_t)dataWord[index+3])<<0) |(((uint32_t)dataWord[index+2])<<8) |(((uint32_t)dataWord[index+1])<<16) |(((uint32_t)dataWord[index+0])<<24); sumA = (sumA + (uint64_t)block); sumB = (sumB + sumA); parityC ^= block; // Time for a modulo if sumB is saturated const uint64_t topBits = 0xC000000000000000UL; if((sumB & topBits) != 0) { sumA = sumA % modulus; sumB = sumB % modulus; } } // Final deferred modulo sumA = sumA % modulus; sumB = sumB % modulus; // Shift sumA left 16 bits for aggregate check value // Shift sumA left 1 bit to leave room for parity bit uint32_t concatenated = (uint32_t) ((sumA <<16) | (sumB <<1)); parityC = parityC ^ concatenated; // Return checksum value return((uint32_t) (concatenated | Parity(parityC))); } // ---------------------- // Example from section 8.5.3 // Koopman8P checksum computed byte-by-byte // dataWord: data word in 8-bit blocks // dwSize: number of bytes in the data word // modulus: should be set to 125 // Only uses bottom 16 bits of sum uint8_t Koopman8P(uint8_t dataWord[], uint32_t dwSize, uint32_t modulus) { assert(modulus == 125); assert(dwSize > 0); assert(initialSeed <= 0xFF); uint32_t sum = initialSeed ^ dataWord[0]; uint32_t psum = sum; // Initialize parity sum for(uint32_t index = 1; index < dwSize; index++) { sum = ((sum<<8) + dataWord[index] ) % modulus; psum ^= dataWord[index]; // Compute LRC value } // Append one byte of implicit zeros sum = (sum<<8) % modulus; // Pack sum with parity sum = (sum<<1) | Parity((uint8_t)psum); // Append parity as bottom bit of check value return((uint8_t)sum); } // ---------------------- // Example from section 8.5.4 // Koopman16P checksum computed byte-by-byte // dataWord: data word in 8-bit bytes // dwSize: number of bytes in the data word // modulus: should be set to 32749 // Only uses bottom 16 bits of sum uint16_t Koopman16P(uint8_t dataWord[], uint32_t dwSize, uint32_t modulus) { assert(modulus == 32749); assert(dwSize > 0); assert(initialSeed <= 0xFF); uint32_t sum = initialSeed ^ dataWord[0]; uint32_t psum = sum; // Initialize parity sum for(uint32_t index = 1; index < dwSize; index++) { sum = ((sum<<8) + dataWord[index] ) % modulus; psum ^= dataWord[index]; } // Append two bytes of implicit zeros sum = (sum<<16) % modulus; // Pack sum with parity sum = (sum<<1) | Parity((uint8_t)psum); // Append parity as bottom bit of check value return((uint16_t)sum); } // ---------------------- // Example from section 8.5.5 // Koopman24P checksum computed byte-by-byte // dataWord: data word in 8-bit bytes // dwSize: number of bytes in the data word // modulus: should be set to 8388587 // Only uses bottom 16 bits of sum uint32_t Koopman24P(uint8_t dataWord[], uint32_t dwSize, uint32_t modulus) { assert(modulus == 8388587); assert(dwSize > 0); assert(initialSeed <= 0xFF); uint32_t sum = initialSeed ^ dataWord[0]; uint32_t psum = sum; // Initialize parity sum for(uint32_t index = 1; index < dwSize; index++) { sum = ((sum<<8) + dataWord[index] ) % modulus; psum ^= dataWord[index]; } // Append three bytes of implicit zeros sum = (sum<<8) % modulus; sum = (sum<<8) % modulus; sum = (sum<<8) % modulus; // Pack sum with parity sum = (sum<<1) | Parity((uint8_t)psum); // Append parity as bottom bit of check value return((uint32_t)sum); } // ---------------------- // Example from section 8.5.6 // Koopman32P checksum computed byte-by-byte // dataWord: data word in 8-bit bytes // dwSize: number of bytes in the data word // modulus: should be set to 0x7FFFFFED // Note: needs a sum 5 bytes in size to handle intermediate sum values uint32_t Koopman32P(uint8_t dataWord[], uint32_t dwSize, uint32_t modulus) { assert(dwSize > 1); assert(modulus == 0x7FFFFFED); uint64_t sum = initialSeed ^ dataWord[0]; uint32_t psum = (uint32_t)sum; // Initialize parity sum for(uint32_t index = 1; index < dwSize; index++) { sum = ((sum<<8) + (uint64_t)dataWord[index] ) % modulus; psum ^= dataWord[index]; } // Append four bytes of implicit zeros sum = (sum<<32) % modulus; // Pack sum with parity sum = (sum<<1) | Parity((uint8_t)psum); // Append parity as bottom bit of check value return((uint32_t)sum); }