Функция nacl.verify в TweetNaCl.js предназначена для
сравнения двух массивов байт в константное время.
Основная цель — исключение утечек информации через различия во времени
выполнения при сравнении данных.
Обычное сравнение массивов в JavaScript может зависеть от содержимого: при первом несовпадении цикл завершится раньше. В криптографических сценариях такая разница во времени становится уязвимостью.
nacl.verify устраняет этот класс атак, обеспечивая
одинаковое время выполнения вне зависимости от содержимого входных
данных.
Типичная реализация сравнения массивов:
function unsafeEqual(a, b) {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
Проблема заключается в раннем выходе из цикла. Если первый байт не совпадает, функция завершится мгновенно. Если несовпадение ближе к концу массива — выполнение займёт больше времени.
Такая разница может быть измерена атакующим при большом количестве запросов и использована для восстановления секретных данных, например:
Атака по времени (timing attack) основана на измерении длительности выполнения операций.
В криптографии особенно критично избегать:
returnКонстантное время означает:
выполнение алгоритма занимает одинаковое количество времени для любых входных данных одинаковой длины
Даже если массивы полностью различны или идентичны.
Внутри TweetNaCl.js используется побайтовое сравнение без ветвлений, зависящих от значения байтов.
Идея алгоритма:
Упрощённая логика:
function constantTimeEqual(a, b) {
let diff = a.length ^ b.length;
for (let i = 0; i < a.length; i++) {
diff |= a[i] ^ b[i];
}
return diff === 0;
}
В реальной реализации TweetNaCl используется более низкоуровневая оптимизация, но принцип сохраняется:
nacl.verify(x: Uint8Array, y: Uint8Array) -> 0 | 1
Особенности:
входы должны иметь одинаковую длину
возвращаемое значение:
0 — массивы равны1 — массивы различаютсяВажно: возврат инвертирован относительно привычного boolean-подхода.
Сравнение двух буферов:
import nacl from "tweetnacl";
const a = new Uint8Array([1, 2, 3]);
const b = new Uint8Array([1, 2, 3]);
const c = new Uint8Array([1, 2, 4]);
nacl.verify(a, b); // 0 (равны)
nacl.verify(a, c); // 1 (не равны)
Проверка подписи:
import nacl from "tweetnacl";
const message = new Uint8Array([10, 20, 30]);
const signature = nacl.sign.detached(message, secretKey);
const valid = nacl.verify(
nacl.sign.detached(message, publicKey),
signature
);
В криптографических протоколах verify часто используется
для проверки MAC, подписей и ключевых дериваций.
a === b
Сравнивает только ссылки, а не содержимое.
Buffer.compare(a, b)
Может быть реализован с оптимизациями, но не всегда гарантирует константное время во всех версиях окружения.
nacl.verify(
new TextEncoder().encode("abc"),
new TextEncoder().encode("abc")
);
Хотя технически возможно, криптографическая модель предполагает работу с бинарными данными, а не текстом.
Разные по длине массивы всегда считаются неравными, но передача некорректных данных может приводить к ошибкам логики протокола.
nacl.verify не предназначен для структурированных
данных. Перед использованием данные должны быть сериализованы в
стабильный бинарный формат.
В TweetNaCl.js функция активно применяется внутри:
nacl.signnacl.boxnacl.secretboxОсобенно важно при проверке:
Пример проверки аутентификации:
const valid = nacl.verify(calculatedMAC, receivedMAC);
При несовпадении даже одного байта результат немедленно становится отрицательным без раскрытия информации о позиции ошибки.
Несмотря на константное время, функция оптимизирована под массовое использование:
На практике производительность сопоставима с обычным сравнением, но с дополнительной защитой от side-channel атак.
Ключевые характеристики поведения:
Такой подход делает поведение функции независимым от входных данных, сохраняя стабильный профиль выполнения.
undefined или не-Uint8Array значения могут привести к
ошибкам выполненияКонстантное сравнение является базовым строительным блоком защиты:
Без подобных функций криптографические схемы, даже математически корректные, становятся уязвимыми на уровне реализации.