Проверка криптографических реализаций на известных тестовых векторах является обязательным этапом верификации корректности. Для библиотек уровня TweetNaCl.js / nacl.js это особенно критично, поскольку любая ошибка в реализации алгоритмов приводит к полной компрометации безопасности: несовпадение одного байта в результате шифрования или подписи означает некорректную реализацию примитивов.
Тестовые векторы представляют собой заранее вычисленные входные данные и ожидаемые выходы для конкретных криптографических операций. Они публикуются в спецификациях алгоритмов (например, Curve25519, XSalsa20-Poly1305, Ed25519) и используются как эталон.
Основные источники корректных наборов:
TweetNaCl.js стремится быть совместимым с оригинальной NaCl, поэтому наиболее важны именно эталонные векторы DJB.
Типичный тестовый вектор включает:
Пример абстрактной структуры:
message = "..."
key = 32 bytes
nonce = 24 bytes
expected = 64 bytes ciphertext
TweetNaCl.js использует nacl.secretbox на основе
XSalsa20 + Poly1305.
const nacl = require('tweetnacl');
nacl.util = require('tweetnacl-util');
const key = new Uint8Array(32).fill(1);
const nonce = new Uint8Array(24).fill(2);
const message = nacl.util.decodeUTF8("test message");
const encrypted = nacl.secretbox(message, nonce, key);
Ожидаемое поведение:
Для корректного тестирования используется обратное преобразование:
const decrypted = nacl.secretbox.open(encrypted, nonce, key);
const result = nacl.util.encodeUTF8(decrypted);
Ключевые свойства:
box.open(box(m)) == mnullnullКлючевая часть тестирования — обмен ключами через Curve25519.
const alice = nacl.box.keyPair();
const bob = nacl.box.keyPair();
const nonce = new Uint8Array(24).fill(5);
const msg = nacl.util.decodeUTF8("hello");
const boxed = nacl.box(msg, nonce, bob.publicKey, alice.secretKey);
const opened = nacl.box.open(boxed, nonce, alice.publicKey, bob.secretKey);
Проверки:
nullПодписи являются детерминированными, что критично для тестовых векторов.
const keyPair = nacl.sign.keyPair();
const message = nacl.util.decodeUTF8("message");
const signed = nacl.sign(message, keyPair.secretKey);
const opened = nacl.sign.open(signed, keyPair.publicKey);
Ожидания:
sign.open(sign(m)) == mnullДля Ed25519 используется набор известных тестов:
Проверка выглядит как жесткое сравнение:
if (!equalBytes(signature, expectedSignature)) {
throw new Error("Ed25519 mismatch");
}
Криптографические тесты не допускают частичных совпадений. Проверка всегда бинарная:
function equalBytes(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;
}
Любое расхождение считается критической ошибкой реализации.
Nonce в NaCl не должен повторяться. Тестовые векторы проверяют:
const c1 = nacl.secretbox(msg, nonce1, key);
const c2 = nacl.secretbox(msg, nonce2, key);
c1 !== c2
Важный класс тестов — проверка реакции на битовые ошибки.
const corrupted = encrypted.slice();
corrupted[0] ^= 1;
const opened = nacl.secretbox.open(corrupted, nonce, key);
Ожидание:
nullTweetNaCl.js должен совпадать с:
Сравнение производится через фиксированные векторы:
assert.equal(
nacl.util.encodeBase64(result),
expectedBase64
);
Little-endian / big-endian несоответствия приводят к расхождению ключей Curve25519.
XSalsa20 требует строго 24 байта.
Любое отклонение ломает MAC-верификацию.
JavaScript-реализация часто ломается на:
В реальных проектах тестовые векторы оформляются как JSON:
{
"secretbox": [
{
"key": "...",
"nonce": "...",
"message": "...",
"ciphertext": "..."
}
]
}
И прогоняются автоматически:
vectors.secretbox.forEach(v => {
const out = nacl.secretbox(v.msg, v.nonce, v.key);
assert(equalBytes(out, v.ciphertext));
});
При изменении реализации обязательно прогоняются:
Типичная схема CI:
Криптография не допускает статистической корректности. Только строгая детерминированная эквивалентность с эталоном считается допустимой.
Тестовые векторы выполняют роль формальной спецификации поведения библиотеки, фиксируя:
Любое отклонение от векторов означает не просто баг, а потенциальную уязвимость протокола, построенного поверх библиотеки.