Files
michael 268b986bb9 Rust port of OmniVox, wire-compatible with the C++ original
Byte-exact cereal binary layout, RFC 8439 ChaCha20-Poly1305, RFC 7914
scrypt defaults; tokio transport preserving the original's observable
behavior (contract B1-B3, B5 quirks included). Parity evidence: golden
C++ vectors in tests/vectors.rs and loopback behavior tests; both
cross-directions verified against the unmodified C++ binaries.

Source: https://git.0xfeedc0de.com/michael/OmniVox
2026-09-30 06:35:24 -04:00

73 lines
3.2 KiB
C++

// Golden-vector generator for the Rust port. Output is normative.
#include "common.h"
#include <iomanip>
#include <sstream>
static std::string hex(const uint8_t* p, size_t n) {
std::ostringstream os; os << std::hex << std::setfill('0');
for (size_t i = 0; i < n; i++) os << std::setw(2) << (int)p[i];
return os.str();
}
static std::string hexv(const std::vector<uint8_t>& v) { return hex(v.data(), v.size()); }
int main() {
// 1. scrypt key derivation (default params N=2^17 r=8 p=1)
OmniVox<DatagramPayload> vox;
std::vector<uint8_t> pw(g_sPassword.begin(), g_sPassword.end());
auto key = vox.deriveEncryptKey(pw, g_vecSalt);
std::cout << "scrypt_key=" << hex(key.data(), key.size()) << "\n";
// extra scrypt vector: known short inputs
std::vector<uint8_t> pw2{'p','a','s','s'}, salt2{'s','a','l','t'};
auto key2 = vox.deriveEncryptKey(pw2, salt2);
std::cout << "scrypt_key2=" << hex(key2.data(), key2.size()) << "\n";
vox.setEncryptKey(key);
// 2. cereal byte layouts
DatagramPayload dp;
dp.id = 0x1234; dp.v1.qword = 0x1122334455667788ULL;
dp.payload = {'H','e','l','l','o'};
std::cout << "cereal_datagram=" << hexv(serializeObject(dp)) << "\n";
DatagramPayload dp0; // all defaults
std::cout << "cereal_datagram_default=" << hexv(serializeObject(dp0)) << "\n";
AeadPacket ap{};
for (int i = 0; i < 12; i++) ap.nonce[i] = (uint8_t)i;
for (int i = 0; i < 16; i++) ap.tag[i] = (uint8_t)(0xA0 + i);
ap.payload = {0xDE, 0xAD, 0xBE, 0xEF};
std::cout << "cereal_aead=" << hexv(serializeObject(ap)) << "\n";
AeadPacket ap0{};
std::cout << "cereal_aead_empty=" << hexv(serializeObject(ap0)) << "\n";
// 3. AEAD vectors: fixed nonce, CryptoPP as the oracle
auto vec = [](std::string s){ return std::vector<uint8_t>(s.begin(), s.end()); };
{
auto pkt = vox.encrypt(vec("Hello")); // random nonce: structure check only
std::cout << "aead_random_payloadlen=" << pkt.payload.size() << "\n";
}
// deterministic: set key, encrypt with forced nonce by round-tripping through
// a fresh object whose rng we can't seed... instead use Crypto++ directly.
{
CryptoPP::ChaCha20Poly1305::Encryption enc;
uint8_t nonce[12] = {0,1,2,3,4,5,6,7,8,9,10,11};
enc.SetKeyWithIV(key.data(), key.size(), nonce, 12);
std::string pt = "Hello";
std::vector<uint8_t> ct(pt.size()), tag(16);
enc.EncryptAndAuthenticate(ct.data(), tag.data(), 16, nonce, 12,
nullptr, 0,
(const unsigned char*)pt.data(), pt.size());
std::cout << "aead_ct=" << hexv(ct) << "\n";
std::cout << "aead_tag=" << hex(tag.data(), 16) << "\n";
}
{
CryptoPP::ChaCha20Poly1305::Encryption enc;
uint8_t nonce[12] = {0,1,2,3,4,5,6,7,8,9,10,11};
enc.SetKeyWithIV(key.data(), key.size(), nonce, 12);
std::vector<uint8_t> ct(0), tag(16);
enc.EncryptAndAuthenticate(ct.data(), tag.data(), 16, nonce, 12,
nullptr, 0, (const unsigned char*)"", 0);
std::cout << "aead_empty_tag=" << hex(tag.data(), 16) << "\n";
}
return 0;
}