From 5ce650382352c1503f40abf08129ada69402af55 Mon Sep 17 00:00:00 2001 From: bitflash-coin Date: Tue, 4 Aug 2026 06:34:32 -0700 Subject: public commit --- src/btfchan.cpp | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 src/btfchan.cpp (limited to 'src/btfchan.cpp') diff --git a/src/btfchan.cpp b/src/btfchan.cpp new file mode 100644 index 0000000..09aaaad --- /dev/null +++ b/src/btfchan.cpp @@ -0,0 +1,94 @@ +// Copyright (c) 2026 Bitflash developers +// Distributed under the MIT/X11 software license. +// +// Bitflash end-to-end encrypted channel. Ported from Itzal echan.rs. +// Uses libsodium crypto_box_curve25519xchacha20poly1305 (X25519 + XChaCha20-Poly1305), +// the same primitive as Rust's crypto_box ChaChaBox. + +#include "btfchan.h" +#include +#include + +namespace btf +{ + +// Compile-time sanity: our constants match libsodium's. +static_assert(CHAN_NONCEBYTES == crypto_box_curve25519xchacha20poly1305_NONCEBYTES, "nonce"); +static_assert(CHAN_MACBYTES == crypto_box_curve25519xchacha20poly1305_MACBYTES, "mac"); +static_assert(CHAN_KEYBYTES == crypto_box_curve25519xchacha20poly1305_BEFORENMBYTES, "key"); + +bool ChanInit() +{ + return sodium_init() >= 0; +} + +void ChanKeypair(unsigned char pk[32], unsigned char sk[32]) +{ + crypto_box_curve25519xchacha20poly1305_keypair(pk, sk); +} + +void ChanPublicFromSecret(unsigned char pk[32], const unsigned char sk[32]) +{ + // X25519 public = scalarmult of the secret with the curve25519 base point. + crypto_scalarmult_base(pk, sk); +} + +bool ChanClientHandshake(const unsigned char endpoint_static_pub[32], + unsigned char eph_pub_out[32], unsigned char shared_out[32]) +{ + unsigned char eph_sk[32]; + crypto_box_curve25519xchacha20poly1305_keypair(eph_pub_out, eph_sk); + // shared = X25519(eph_sk, endpoint_static_pub) -> hashed to a box key + int r = crypto_box_curve25519xchacha20poly1305_beforenm(shared_out, endpoint_static_pub, eph_sk); + sodium_memzero(eph_sk, sizeof(eph_sk)); + return r == 0; +} + +bool ChanEndpointHandshake(const unsigned char client_eph_pub[32], + const unsigned char my_static_sk[32], unsigned char shared_out[32]) +{ + // shared = X25519(my_static_sk, client_eph_pub) -> same box key as the client computed + return crypto_box_curve25519xchacha20poly1305_beforenm(shared_out, client_eph_pub, my_static_sk) == 0; +} + +std::vector ChanEncryptFrame(const unsigned char shared[32], + const unsigned char* pt, size_t n) +{ + unsigned char nonce[CHAN_NONCEBYTES]; + randombytes_buf(nonce, sizeof(nonce)); + + size_t ctlen = n + CHAN_MACBYTES; + size_t bodylen = CHAN_NONCEBYTES + ctlen; + + std::vector out(4 + bodylen); + out[0] = (unsigned char)((bodylen >> 24) & 0xff); + out[1] = (unsigned char)((bodylen >> 16) & 0xff); + out[2] = (unsigned char)((bodylen >> 8) & 0xff); + out[3] = (unsigned char)(bodylen & 0xff); + memcpy(&out[4], nonce, CHAN_NONCEBYTES); + + crypto_box_curve25519xchacha20poly1305_easy_afternm( + &out[4 + CHAN_NONCEBYTES], pt, n, nonce, shared); + return out; +} + +bool ChanDecryptBody(const unsigned char shared[32], + const unsigned char* body, size_t n, std::vector& out) +{ + if (n < (size_t)(CHAN_NONCEBYTES + CHAN_MACBYTES)) + return false; + const unsigned char* nonce = body; + const unsigned char* ct = body + CHAN_NONCEBYTES; + size_t ctlen = n - CHAN_NONCEBYTES; + out.resize(ctlen - CHAN_MACBYTES); + int r = crypto_box_curve25519xchacha20poly1305_open_easy_afternm( + out.empty() ? NULL : &out[0], ct, ctlen, nonce, shared); + if (r != 0) + { + out.clear(); + return false; + } + return true; +} + +} // namespace btf -- cgit v1.2.3