Хороший выбор для легкого алгоритма контрольной суммы?
Мне нужно создать контрольную сумму для строки данных для целей согласованности. Широкая идея заключается в том, что клиент может регенерировать контрольную сумму на основе получаемой ими полезной нагрузки и, таким образом, обнаруживать любую коррупцию, имевшую место при транзите. Я смутно осознаю, что для такого рода вещей существуют всевозможные математические принципы, и очень легко для тонких ошибок сделать весь алгоритм неэффективным, если вы попытаетесь свернуть его самостоятельно.
Итак, я ищу совет по алгоритму хеширования/контрольной суммы со следующими критериями:
- Он будет сгенерирован Javascript, поэтому должен быть относительно легким вычислительно.
- Проверка будет выполняться с помощью Java (хотя я не вижу, что это действительно проблема).
- Требуется текстовый ввод (Юникод с кодировкой URL, который, я считаю, ASCII) с умеренной длиной; обычно около 200-300 символов и во всех случаях ниже 2000.
- Выход должен быть также ASCII-текстом, а чем короче, тем лучше.
В первую очередь меня интересует что-то легкое, а не возможное возможное минимальное возможное возможное столкновение. Буду ли я наивно воображать, что для этого подходит восьмисимвольный хеш? Я также должен уточнить, что не конец света, если коррупция не будет поднята на этапе проверки (и я действительно понимаю, что это не будет на 100% надежным), хотя остальная часть моего кода заметно менее эффективна для каждого поврежденный вход, который проскальзывает.
Изменить - благодаря всем, что было сделано. Я пошел с опцией Adler32 и дал понять, что он был естественным образом поддержан на Java, чрезвычайно простой в реализации в Javascript, быстро рассчитанный с обоих концов и имеющий 8-байтовый вывод, это было точно для моих требований.
(Обратите внимание, что я понимаю, что сетевой транспорт вряд ли будет отвечать за любые ошибки в коррупции и пока не будет складывать мои руки по этой проблеме, однако добавление проверки контрольной суммы устраняет одну точку отказа и означает, что мы можем сосредоточиться в других областях, если это повторится.)
Ответы
Ответ 1
CRC32 не слишком сложно реализовать на любом языке, он достаточно хорош, чтобы обнаруживать простое повреждение данных и при правильном использовании, это очень быстро. Однако вы также можете попробовать Adler32, который почти одинаково хорош как CRC32, но его еще проще реализовать (и примерно одинаково быстро).
Adler32 в Википедии
Пример реализации CRC32 JavaScript
Любой из этих двух (или, возможно, даже обоих) доступен в Java прямо из коробки.
Ответ 2
Знают, что и TCP, и UDP (и IP, и Ethernet и...) уже обеспечивают защиту контрольной суммы для данных в пути?
Если вы делаете что-то действительно странное, если вы видите коррупцию, что-то очень не так. Я предлагаю начать с тестера памяти.
Кроме того, вы получаете надежную защиту целостности данных, если используете SSL/TLS.
Ответ 3
[UPDATE 30/5/2013: ссылка на старую реализацию JS CRC32 умерла, поэтому я теперь связан с другим.]
Google CRC32: быстрый и гораздо более легкий вес, чем MD5 и др. Существует реализация Javascript здесь.
Ответ 4
Выполнение Javascript MD4, MD5 и SHA1. Лицензия BSD.
Ответ 5
Другие люди уже упоминали CRC32, но здесь ссылка на реализация W3C CRC-32 для PNG, как один из немногих известных, авторитетных сайтов с эталонной CRC-реализацией.
(Несколько лет назад я попытался найти известный сайт с алгоритмом CRC или, по крайней мере, тот, который привел источник для его алгоритма, и почти разорвал мои волосы, пока не нашел страницу PNG.)
Ответ 6
В моем поиске реализации JavaScript хорошего алгоритма контрольной суммы я столкнулся с этим вопросом. Andrzej Doyle по праву выбрал Adler32 в качестве контрольной суммы, поскольку ее действительно легко реализовать и обладает отличными свойствами. Затем DroidOS предоставил фактическую реализацию в JavaScript, которая продемонстрировала простоту.
Однако алгоритм может быть дополнительно улучшен, как описано на странице Википедии, и как это реализовано ниже. Фокус в том, что вам не нужно определять модуль на каждом шаге. Скорее, вы можете отложить это до конца. Это значительно увеличивает скорость реализации, до 6 раз быстрее в Chrome и Safari. Кроме того, эта оптимизация не влияет на читаемость кода, что делает его беспроигрышным. Таким образом, он определенно хорошо вписывается в исходный вопрос о том, что алгоритм/реализация, которая является вычислительно легкой.
function adler32(data) {
var MOD_ADLER = 65521;
var a = 1, b = 0;
var len = data.length;
for (var i = 0; i < len; i++) {
a += data.charCodeAt(i);
b += a;
}
a %= MOD_ADLER;
b %= MOD_ADLER;
return (b << 16) | a;
}
edit: imaya создала сравнение jsperf, показывая разницу в скорости при запуске простой версии, как подробно описано DroidOS, по сравнению с оптимизированной версией, которая отменяет операцию по модулю. Я добавил вышеприведенную реализацию под именем полной длины на страницу jsperf, указав, что приведенная выше реализация составляет около 25 % быстрее, чем у имаи и на 570% быстрее, чем простая реализация (тесты выполняются в Chrome 30): http://jsperf.com/adler-32-simple-vs-optimized/6
edit2: не забывайте, что при работе с большими файлами вы в конечном итоге попадете в предел вашей реализации JavaScript в терминах переменных a и b. Таким образом, при работе с большим источником данных вы должны выполнять промежуточные операции с модулями, чтобы гарантировать, что вы не превысите максимальное значение целого, которое вы можете надежно хранить.
Ответ 7
Используйте SHA-1 JS-реализация. Это не так медленно, как вы думаете (Firefox 3.0 на Core 2 Duo 2.4Ghz хэширует более 100 КБ в секунду).
Ответ 8
Здесь относительно простой, который я "придумал" - там нет математических исследований, но он очень быстрый и работает на практике. Я также включил эквивалент Java, который проверяет алгоритм и показывает, что существует менее 1 из 10 000 000 случаев сбоя (для запуска требуется одна или две минуты).
JavaScript
function getCrc(s) {
var result = 0;
for(var i = 0; i < s.length; i++) {
var c = s.charCodeAt(i);
result = (result << 1) ^ c;
}
return result;
}
Java
package test;
import java.util.*;
public class SimpleCrc {
public static void main(String[] args) {
final Random randomGenerator = new Random();
int lastCrc = -1;
int dupes = 0;
for(int i = 0; i < 10000000; i++) {
final StringBuilder sb = new StringBuilder();
for(int j = 0; j < 1000; j++) {
final char c = (char)(randomGenerator.nextInt(128 - 32) + 32);
sb.append(c);
}
final int crc = crc(sb.toString());
if(lastCrc == crc) {
dupes++;
}
lastCrc = crc;
}
System.out.println("Dupes: " + dupes);
}
public static int crc(String string) {
int result = 0;
for(final char c : string.toCharArray()) {
result = (result << 1) ^ c;
}
return result;
}
}
Ответ 9
Это довольно старый поток, но я подозреваю, что он по-прежнему просматривается довольно часто - если вам нужно всего лишь короткая, но надежная часть кода для создания контрольной суммы Adler32 алгоритм должен быть вашим выбором. Вот код JavaScript
function adler32(data)
{
var MOD_ADLER = 65521;
var a = 1, b = 0;
for (var i = 0;i < data.length;i++)
{
a = (a + data.charCodeAt(i)) % MOD_ADLER;
b = (b + a) % MOD_ADLER;
}
var adler = a | (b << 16);
return adler;
}
Соответствующая скрипка, демонизирующая алгоритм в действии, здесь.