Обратная реализация на основе Crc64 LSB

Я попытался реализовать функцию разворота на основе LSB. Код находится на C#. Ошибка при изменении контрольной суммы. Функция может изменить контрольную сумму Crc64 только тогда, когда она была вычислена только с 8 байтами исходных данных. Когда я пытаюсь отменить контрольную сумму с помощью метода FixChecksum, средние 6 байтов меняются местами, но первый и последний байты меняются местами. Сообщите, пожалуйста, что не так, что нужно реализовать или исправить. Буду признателен за любое решение.

[ОБНОВЛЕНО]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MYC;
using primaryMethodsCS_2;
using System.Globalization;
using UnitsFramework.Numerics;
using UnitsFramework;

namespace MYC
{
    public class Crc64_LSB_Reverse
    {
        public const UInt64 POLY64REV = 0xD800000000000000; //0xffffffffffffff00;

        public static ulong TOPBIT_MASK = 0x8000000000000000;
        public static ulong LOWBIT_MASK = 0x0000000000000001;

        public const ulong startxor = 0; //0xffffffffffffffff;
        public const ulong FinalXor = 0; // 0xffffffffffffffff;

        public UInt64[] CRCTable;
        public UInt64[] revCRCTable;
        public UInt64 crc = 0;

        public Crc64_LSB_Reverse(UInt64 POLY = POLY64REV)
        {
            List<ulong> listforward = new List<ulong>();
            List<ulong> listreverse = new List<ulong>();

            for (int i = 0; i <= 255; i++)
            {
                List<ulong> forward = generateCrcTableConstants(new List<ulong>() { (UInt64)i }, POLY);
                List<ulong> reverse = generateRevCrcTableConstants(new List<ulong>() { (UInt64)i }, POLY);

                listforward.AddRange(forward);
                listreverse.AddRange(reverse);
            }

            this.CRCTable = listforward.ToArray();
            this.revCRCTable = listreverse.ToArray();

            return;
        }

        public static List<UInt64> generateCrcTableConstants(List<UInt64> initialValues, UInt64 POLY)
        {
            List<UInt64> list = new List<ulong>();

            for (int thisValue = 0; thisValue < initialValues.Count; thisValue++)
            {
                UInt64 currentValue = initialValues[thisValue];
                UInt64 initialValue = currentValue;
                currentValue <<= 56; // is valid for MSB forward table creation

                // MSB based forward table implementation.
                for (byte bit = 0; bit < 8; bit++)
                {

                    if ((currentValue & TOPBIT_MASK) != 0)
                    {
                        //currentValue <<= 1;
                        //currentValue ^= CrcFramework.Reflect64(POLY);
                        currentValue = (currentValue << 1) ^ ((0 - (currentValue >> 63)) & POLY); // fwd
                    }
                    else
                    {
                        currentValue <<= 1;
                    }
                }
                list.Add(currentValue);
            }
            return list;
        }

        public static List<UInt64> generateRevCrcTableConstants(List<UInt64> initialValues, UInt64 POLY)
        {
            List<UInt64> list = new List<ulong>();

            for (int thisValue = 0; thisValue < initialValues.Count; thisValue++)
            {
                UInt64 initialValue = initialValues[thisValue];
                UInt64 currentValue = initialValues[thisValue];

                // LSB based reverse table implementation for MSB based forward table function.
                for (byte bit = 0; bit < 8; bit++)
                {
                    if ((currentValue & LOWBIT_MASK) != 0)
                    {
                        //currentValue ^= POLY; // CrcFramework.Reflect64(POLY); //POLY;
                        currentValue = (currentValue >> 1) ^ ((0 - (currentValue & 1)) & POLY); // rvs
                        //currentValue >>= 1;
                        //currentValue |= 1; // TOPBIT_MASK;
                    }
                    else
                    {
                        currentValue >>= 1;
                    }
                }
                list.Add(currentValue);
            }
            return list;
        }

        public ulong Compute_LSB(byte[] bytes, bool reset = true)
        {
            if (reset) this.crc = startxor;

            foreach (byte b in bytes)
            {
                byte curByte = b;

                /* update the LSB of crc value with next input byte */
                crc = (ulong)(crc ^ (ulong)(curByte));
                /* this byte value is the index into the lookup table */
                byte pos = (byte)(crc & 0xFF); // tushar: original 12-September-2019-1: & 0xFF);
                /* shift out this index */
                crc = (ulong)(crc >> 8);
                /* XOR-in remainder from lookup table using the calculated index */
                crc = (ulong)(crc ^ (ulong)CRCTable[pos]);

                /* shorter:
                byte pos = (byte)((crc ^ curByte) & 0xFF);
                crc = (ulong)((crc >> 8) ^ (ulong)(crcTable[pos]));
                */
            }
            return (ulong)(crc ^ FinalXor);
        }

        public ulong Compute_MSB(byte[] bytes, bool reset = true)
        {
            if (reset) this.crc = startxor;

            foreach (byte b in bytes)
            {
                byte curByte = b;

                /* update the MSB of crc value with next input byte */
                crc = (ulong)(crc ^ (ulong)((ulong)curByte << 56));
                /* this MSB byte value is the index into the lookup table */
                byte pos = (byte)(crc >> 56);
                /* shift out this index */
                crc = (ulong)(crc << 8);
                /* XOR-in remainder from lookup table using the calculated index */
                crc = (ulong)(crc ^ (ulong)CRCTable[pos]);

                /* shorter:
                byte pos = (byte)((crc ^ (curByte << 56)) >> 56);
                crc = (uint)((crc << 8) ^ (ulong)(crcTable[pos]));
                */
            }
            return (ulong)(crc ^ FinalXor);
        }

        public UInt64 FixChecksum(byte[] bytes, Int64 length, Int64 fixpos, UInt64 wantcrc)
        {
            if (fixpos + 8 > length) return 0;

            UInt64 crc = startxor;
            for (Int64 i = 0; i < fixpos; i++)
            {
                crc = (crc >> 8) ^ CRCTable[(crc ^ bytes[i]) & 0xff];
            }

            Array.Copy(BitConverter.GetBytes(crc), 0, bytes, fixpos, 8);

            List<UInt64> list = new List<UInt64>();

            crc = wantcrc ^ startxor;
            for (Int64 i = length - 1; i >= fixpos; i--)
            {

                UInt64 param0 = (UInt64)(crc >> 56); 
                list.Add(param0);
                crc = (crc << 8) ^ revCRCTable[param0] ^ bytes[i]; //
            }

            Array.Copy(BitConverter.GetBytes(crc), 0, bytes, fixpos, 8);
            return crc;
        }

    }
}

1 ответ

Решение этой проблемы заключается в обратном цикле CRC.

При использовании таблиц для генерации CRC (циклическая перемотка вперед), CRC со сдвигом влево использует левый байт CRC для индексации таблицы, а CRC со сдвигом вправо использует правый байт CRC для индексации таблицы. Для обратного цикла CRC, CRC со сдвигом влево использует правый байт CRC для индексации таблицы, а CRC со сдвигом вправо использует левый байт CRC для индексации таблицы.

Пример кода ниже для CRC сдвига влево и вправо. Две дополнительные таблицы используются для обратного цикла CRC. Функции CRC принимают параметр длины данных, если в буфере есть дополнительное пространство для хранения CRC после его генерации.

Чтобы упростить функции обратного цикла, CRC генерируется и xor'ed с желаемым CRC, который может использоваться с мнимым буфером нулей, чтобы сгенерировать 8 байтов данных, необходимых для создания CRC после xor'ed. Затем 8 байтов данных помещаются в исходный буфер. Xor отменяет начальные значения CRC и xor out, поэтому функции обратного цикла не должны учитывать эти значения.

Обратите внимание, что байты CRC могут идти в любом месте сообщения (хотя обычно они находятся в конце сообщения). Например, 24-байтовое сообщение, состоящее из 8 байтов данных, 8 байтов CRC, 8 байтов данных, которое может быть создано с помощью crc64fw(0ul, bfr, 24, 8); или crc64rw(0ul, bfr, 24, 8);.

namespace crc64
{
    public class crc64
    {
        public const ulong poly64f = 0x000000000000001bul;
        public const ulong poly64r = 0xd800000000000000ul;
        public const ulong crcin   = 0x0000000000000000ul; // initial value
        public const ulong xorot   = 0x0000000000000000ul; // xorout

        public static ulong[] crctblf;          // fwd tbl
        public static ulong[] crctblg;          // fwd tbl reverse cycle
        public static ulong[] crctblr;          // ref tbl
        public static ulong[] crctbls;          // ref tbl reverse cycle

        // generate tables
        public static void gentbls()
        {
            ulong crc;
            byte b;
            b = 0;
            do
            {
                crc = ((ulong)b)<<56;
                for(int i = 0; i < 8; i++)
                    crc = (crc<<1)^((0-(crc>>63))&poly64f);
                crctblf[b] = crc;
                b++;
            }while (b != 0);
            do
            {
                crc = ((ulong)b) << 0;
                for (int i = 0; i < 8; i++)
                    crc = (crc<<63)^((crc^((0-(crc&1))&poly64f))>>1);
                crctblg[b] = crc;
                b++;
            } while (b != 0);
            do
            {
                crc = ((ulong)b)<<0;
                for(int i = 0; i < 8; i++)
                    crc = (crc>>1)^((0-(crc&1))&poly64r);
                crctblr[b] = crc;
                b++;
            }while (b != 0);
            do
            {
                crc = ((ulong)b) << 56;
                for (int i = 0; i < 8; i++)
                    crc = (crc>>63)^((crc^((0-(crc>>63))&poly64r))<<1);
                crctbls[b] = crc;
                b++;
            } while (b != 0);
        }

        // generate forward crc
        public static ulong crc64f(byte[] bfr, int len)
        {
            ulong crc = crcin;
            for(int i = 0; i < len; i++)
                crc = (crc<<8)^(crctblf[(crc>>56)^bfr[i]]);
            return (crc^xorot);
        }

        // append forward crc
        public static void crc64fa(ulong crc, byte[] bfr, int pos)
        {
            bfr[pos+0] = (byte)(crc>>56);
            bfr[pos+1] = (byte)(crc>>48);
            bfr[pos+2] = (byte)(crc>>40);
            bfr[pos+3] = (byte)(crc>>32);
            bfr[pos+4] = (byte)(crc>>24);
            bfr[pos+5] = (byte)(crc>>16);
            bfr[pos+6] = (byte)(crc>> 8);
            bfr[pos+7] = (byte)(crc>> 0);
        }

        // "fix" bfr to generate wanted forward crc
        public static void crc64fw(ulong crc, byte[] bfr, int len, int pos)
        {
            crc ^= crc64f(bfr, len);
            for(int i = pos; i < len; i++)
                crc = (crc>>8)^(crctblg[crc&0xff]);
            bfr[pos+0] ^= (byte)(crc>>56);
            bfr[pos+1] ^= (byte)(crc>>48);
            bfr[pos+2] ^= (byte)(crc>>40);
            bfr[pos+3] ^= (byte)(crc>>32);
            bfr[pos+4] ^= (byte)(crc>>24);
            bfr[pos+5] ^= (byte)(crc>>16);
            bfr[pos+6] ^= (byte)(crc>> 8);
            bfr[pos+7] ^= (byte)(crc>> 0);
        }

        // generate reflected crc
        public static ulong crc64r(byte[] bfr, int len)
        {
            ulong crc = crcin;
            for(int i = 0; i < len; i++)
                crc = (crc>>8)^(crctblr[(crc&0xff)^bfr[i]]);
            return (crc^xorot);
        }

        // append reflected crc
        public static void crc64ra(ulong crc, byte[] bfr, int pos)
        {
            bfr[pos+0] = (byte)(crc>> 0);
            bfr[pos+1] = (byte)(crc>> 8);
            bfr[pos+2] = (byte)(crc>>16);
            bfr[pos+3] = (byte)(crc>>24);
            bfr[pos+4] = (byte)(crc>>32);
            bfr[pos+5] = (byte)(crc>>40);
            bfr[pos+6] = (byte)(crc>>48);
            bfr[pos+7] = (byte)(crc>>56);
        }

        // "fix" bfr to generate wanted reflected crc
        public static void crc64rw(ulong crc, byte[] bfr, int len, int pos)
        {
            crc ^= crc64r(bfr, len);
            for (int i = pos; i < len; i++)
                crc = (crc<<8)^(crctbls[crc>>56]);
            bfr[pos+0] ^= (byte)(crc>> 0);
            bfr[pos+1] ^= (byte)(crc>> 8);
            bfr[pos+2] ^= (byte)(crc>>16);
            bfr[pos+3] ^= (byte)(crc>>24);
            bfr[pos+4] ^= (byte)(crc>>32);
            bfr[pos+5] ^= (byte)(crc>>40);
            bfr[pos+6] ^= (byte)(crc>>48);
            bfr[pos+7] ^= (byte)(crc>>56);
        }

        static void Main(string[] args)
        {
            crctblf = new ulong[256];
            crctblg = new ulong[256];
            crctblr = new ulong[256];
            crctbls = new ulong[256];
            byte[] bfr = {0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,   // data (16 bytes)
                          0x38,0x39,0x61,0x62,0x63,0x64,0x65,0x66,
                          0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};  // space for crc
            ulong crcf, crcr, crcw, crcg, crcs;
            int dl = bfr.Length-8;          // length of data
            int bl = bfr.Length;            // length of bfr
            gentbls();
            crcf = crc64f(bfr, dl);         // forward crc
            crc64fa(crcf, bfr, dl);         // append crc
            crcw = crc64f(bfr, bl);         // crcw == 0
            crcr = crc64r(bfr, dl);         // reflected crc
            crc64ra(crcr, bfr, dl);         // append crc
            crcw = crc64r(bfr, bl);         // crcw == 0
            Console.WriteLine(crcf.ToString("x16") + " " + crcr.ToString("x16"));
            crcw = 0x0001020304050607ul;    // wanted crc
            crc64fw(crcw, bfr, dl, 8);      // "fix" for forward
            crcg = crc64f(bfr, dl);         // crcg == crcw
            crc64fw(crcf, bfr, dl, 8);      // undo "fix" for forward (restore bfr)
            crc64rw(crcw, bfr, dl, 8);      // "fix" for reflected
            crcs = crc64r(bfr, dl);         // crcs == crcw
            Console.WriteLine(crcg.ToString("x16") + " " + crcs.ToString("x16"));
        }
    }
}
Другие вопросы по тегам