Контрольная сумма (CRC)

Тема в разделе "WASM.ASSEMBLER", создана пользователем droopy, 27 окт 2007.

  1. droopy

    droopy New Member

    Публикаций:
    0
    Регистрация:
    2 окт 2004
    Сообщения:
    21
    Здравствуйте!
    Задумался над одной проблемой.. Хотел сделать чтобы моя программа давала контрольную сумму 0.
    Конечно, все зависит от способа ее подсчета. Если считать сумму всех байтов с учетом переполнения (счетчик 32битный), то сумма будет расчитываться примерно так:
    Код (Text):
    1.           mov      esi, offset Buffer
    2.           mov      ecx, BufSize
    3.           mov      CRC, 0
    4. @@:       lodsb
    5.           add      byte ptr CRC, al
    6.           adc      dword ptr CRC+1, 0
    7.           loop     @B
    8. ...
    9. CRC       dd          ?
    10.          db          ?
    В этом случае приходит в голову только добавить ~10Мб байтов, заполненных 0FFh, чтобы сбросить счетчик

    Если CRC считается простой суммой байтов без учета переноса,
    Код (Text):
    1. @@:       lodsb
    2.           add     byte ptr CRC, al
    3.           loop    @B
    то все просто - добавляем к программе 1 байт, дополняющий CRC до нуля.

    Если считается сумма двойных слов
    Код (Text):
    1. @@:       lodsd
    2.           add     dword ptr CRC, eax
    3.           loop    @B
    - то добавляем соответенно двойное слово, равное -(CRC).

    Тут мне стало интересно, можно ли сделать так, чтобы CRC высчитанный двумя последними способами, был равен нулю? То есть, чтобы у куска кода, сумма всех байтов (без учета переполнения) была равна 0 и сумма всех двойных слов (начиная с 1 байта, размер кода кратен 4), тоже была равна нулю. Пример - поле, заполненное нулями :)

    Допустим, у нас есть кусок памяти заданного размера. У него известна сумма всех байтов (байтовая величина, без учета переполнения) - X, а также сумма всех двойных слов - Y(4 байтовая). Можно ли добавить к этой памяти какие-то значения, чтобы после подсчета вместе с ними стало X=0 и Y=0? Или это невозможно?
     
  2. 0x00786F72

    0x00786F72 New Member

    Публикаций:
    0
    Регистрация:
    30 авг 2006
    Сообщения:
    30
    'x80\x00\x00\x00\x80\x00\x00\x00', 'xC0\x40\x00\x00\x40\xC0\x00\x00', etc
    Сложение не рулит, юзайте деление;)
    http://www.wasm.ru/docs/5/crc.zip
     
  3. persicum

    persicum New Member

    Публикаций:
    0
    Регистрация:
    2 фев 2007
    Сообщения:
    947
    Нафига тебе все эти арифметические суммы и переполнения?
    Программер должен отдавать предпочтение XOR.

    Перексорь все байты-слова - вот тебе и контрольная сумма!
    Если есть предубеждения против обычного ксора, типа просто и ненадежно, тогда применяй xor и циклический поворот,
    скажем, на 17 бит.
    sum = ЦП(Sum,17) xor Data
     
  4. droopy

    droopy New Member

    Публикаций:
    0
    Регистрация:
    2 окт 2004
    Сообщения:
    21
    Не катит) сумма по двойным словам - 1'00'00'00

    Я не ставлю себе задачу искать методы вычисления контрольной суммы.. Просто заинтересовался вопросом можно так сделать или нет.

    Думаю, для того чтобы условие выполнилось, нужно чтобы сумма байтов двойного слова (которое мы будем добавлять) была равна сумме по байтам, взятой со знаком минус. То есть
    допустим, Y - сумма двойных слов
    (-Y) будет записываться как AABBCCDD, где A,B,C,D - hex цифры
    надо чтобы AA+BB+CC+DD = -X
    где X - сумма по байтам
    Есть идеи?
     
  5. Stiver

    Stiver Партизан дзена

    Публикаций:
    0
    Регистрация:
    18 дек 2004
    Сообщения:
    812
    Адрес:
    Germany
    droopy
    То есть, если я правильно понял, в первом случае мы производим сложение байтов mod 2^8, во втором сложение двойных слов mod 2^32. Обозначим 0-X=:a mod 2^8 и 0-Y=:b mod 2^32. Дополнять кусок памяти будем некоторым количеством двойных слов.

    Получаем два уравнения:

    k + m + n + p = a mod 2^8
    k*2^24 + m*2^16 + n*2^8 + p = b mod 2^32

    где k,m,n,p соответственно суммы четвертого(высшего), третьего, второго и первого(низшего) байтов добавленных двойных слов. Эти два уравнения можно переформулировать в линейную систему с байтовыми переменными по модулю 2^8. Размер k,m,n,p и значит количество переменных системы зависит от количества слов. В случае одного DWORD'a система получается переопределенной (4 переменных, 5 уравнений) ) => решение существует, если b_{1} + b_{2} + b_{3} + b_{4} = a mod 2^8. Если разрешено добавлять более одного DWORD'a, то система будет недоопределенной и решение существует для всех a и b.
     
  6. persicum

    persicum New Member

    Публикаций:
    0
    Регистрация:
    2 фев 2007
    Сообщения:
    947
    Чувак, я же говорю, контрольная сумма - это не обязательно складывать! Лучше даже, надежней не складывать, а делить на простое число или полином - так будет меньше коллизий.

    Но вернемся к нашим баранам...
    Те че нужно, чтобы checksum рассчитанная по байтам равнялась checksum рассчитанной по dword и равнялась нулю?
    Через XOR решается элементарно!!!

    Перексориваем все dword и приписываем ЧЕТЫРЕ байта к результату. Все, задача решена. =)))
    Теперь можно проксоривать как dword, так и отдельные байты, в результате будет нулль.
     
  7. Stiver

    Stiver Партизан дзена

    Публикаций:
    0
    Регистрация:
    18 дек 2004
    Сообщения:
    812
    Адрес:
    Germany
    Вдогонку: интереснее будет наверное вопрос про размер дополнительных данных. То есть для заданных X и Y найти (= привести алгоритм) _минимальное_ количество DWORD'ов, которыми можно дополнить обе суммы до нуля.

    persicum

    Перечитай тему еще раз и внимательно. Человек задал совершенно определенный вопрос по совершенно определенной задаче. Вряд ли стоит впихивать сюда объяснения, как работает XOR.
     
  8. AlB80

    AlB80 New Member

    Публикаций:
    0
    Регистрация:
    11 май 2006
    Сообщения:
    25
    Адрес:
    Russia
    Сегодня с droopy разобрали, не оптимальный алгоритм, но 100%.

    1. dword подгоняем 32 битную сумму к 0.
    2. Добавляем N комплементарных пар dword. Сумма пары равна 0, но при этом существуют пары у которых по-байтная сумма равна 0,-1,-2,-3.

    Итог:
    максимальный случай 4 + 85*8 = 684 байта.
     
  9. Stiver

    Stiver Партизан дзена

    Публикаций:
    0
    Регистрация:
    18 дек 2004
    Сообщения:
    812
    Адрес:
    Germany
    Похоже оптимальная длина в DWORD'aх будет где-то в районе (b_{1} + b_{2} + b_{3} + b_{4} - a mod 2^8)/3, но не уверен, проверю вечером..
     
  10. droopy

    droopy New Member

    Публикаций:
    0
    Регистрация:
    2 окт 2004
    Сообщения:
    21
    Респект AlB80
    Прокомментирую его решение:
    Имеются заданные суммы - X (байтовая) и Y (4-байтовая)
    Сначала мы добавляем 1 двойное слово, равное -Y. Этим мы сбрасываем сумму по двойным словам в ноль.
    Далее, есть такие замечательные пары двойных слов:
    1)FF'FF'00'00 - 00'01'00'00 - сумма по байтам -1
    2)FF'FF'FF'00 - 00'00'01'00 - сумма по байтам -2
    3)FF'FF'FF'FF - 00'00'00'01 - сумма по байтам -3
    Заметьте, что у них всех сумма равно нулю.
    Мы берем сумму кода по байтам, делим ее на три. Добавляем такое количество пар №3. Если остаток от деления получился 1 или 2, то добавляем соответственно пару №1 или №2.
    Этим мы приводим сумму по байтам к нулю.
    В лучшем случае добавляем 4 байта, в худшем - 4+(255/3)*8 = 684 байта
     
  11. AlB80

    AlB80 New Member

    Публикаций:
    0
    Регистрация:
    11 май 2006
    Сообщения:
    25
    Адрес:
    Russia
    В лучшем случае мы добавляем 0 байт, т.к. п.1 также опционален.
     
  12. Stiver

    Stiver Партизан дзена

    Публикаций:
    0
    Регистрация:
    18 дек 2004
    Сообщения:
    812
    Адрес:
    Germany
    Размер дополнительных данных действительно зависит от a и b:

    количество DWORD'ов = ceil((b_{1} + b_{2} + b_{3} + b_{4} - a)/3) + 1

    где b_{1} + b_{2} + b_{3} + b_{4} - отдельные байты в b и операции производятся по модулю 256. Таким образом
    в худшем случае случае (например b=0 и a=1) требуются 86*4 = 344 байта. Это верхняя граница - оптимальная длина
    может быть на 1 меньше (как в случае b=0 и a=0), но рассматривать этот граничный случай я, честно говоря, поленился :)

    Вот код, который строит искомую байтовую последовательность. Для наглядности никак не оптимировал.

    Код (Text):
    1. // input data - a, b
    2. int a = 1;
    3. int b[] = new int[]{0,0,0,0};
    4.  
    5. int diff = mod(b[0] + b[1] + b[2] + b[3] - a, 256);
    6.  
    7. int alpha2 = diff / 3;
    8. int beta1 = mod(b[1] - alpha2, 256);
    9. int over = alpha2>b[1]?1:0;
    10.  
    11. diff = mod(diff - alpha2 - over, 256);
    12. int beta2 = diff / 2;
    13. int gamma1 = mod(b[2] - over - beta2, 256);
    14. over = over + beta2>b[2]?1:0;
    15.  
    16. int gamma2 = mod(diff - beta2 - over, 256);
    17. int delta1 = mod(b[3] - gamma2 - over, 256);
    18.  
    19. int alpha = alpha2*256 + b[0];
    20. int beta = beta2*256 + beta1;
    21. int gamma = gamma2*256 + gamma1;
    22.  
    23. int[] arr = new int[4*(alpha2+2)];
    24.  
    25. int i = 0;
    26. for(;;) {
    27.    
    28.     if(alpha>=255) {
    29.         arr[i+3]=255;
    30.         alpha-=255;
    31.     } else {
    32.         arr[i+3]=alpha;
    33.         alpha = 0;
    34.     }
    35.    
    36.     if(beta>=255) {
    37.         arr[i+2]=255;
    38.         beta-=255;
    39.     } else {
    40.         arr[i+2]=beta;
    41.         beta = 0;
    42.     }
    43.    
    44.     if(gamma>=255) {
    45.         arr[i+1]+=255;
    46.         gamma-=255;
    47.     } else {
    48.         arr[i+1]=gamma;
    49.         gamma = 0;
    50.     }
    51.    
    52.     i+=4;
    53.  
    54.     if(alpha + beta + gamma == 0) {
    55.         break;
    56.     }
    57. }
    58.  
    59. arr[0] = delta1;
    60.  
    61. System.out.println("Array length: "+i + "(bytes), "+i/4+" (DWORDs)");
    62. System.out.println("Array content: ");
    63. for(int j=0;j<i;j++) {
    64.     System.out.print(Integer.toHexString(arr[j])+" ");
    65. }
    Вроде не наврал нигде..