upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/btfchan.cpp
diff options
context:
space:
mode:
authorbitflash-coin <bookofshamers@outlook.com>2026-08-04 06:34:32 -0700
committerbitflash-coin <bookofshamers@outlook.com>2026-08-04 06:34:32 -0700
commit5ce650382352c1503f40abf08129ada69402af55 (patch)
tree6a18198901f1e2c4933f1ac53c9365eec512bf63 /src/btfchan.cpp
parentf34113291da7e5e3dc7d2468d4f9c212c05c584b (diff)
public commit
Diffstat (limited to 'src/btfchan.cpp')
-rw-r--r--src/btfchan.cpp94
1 files changed, 94 insertions, 0 deletions
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 @@
1// Copyright (c) 2026 Bitflash developers
2// Distributed under the MIT/X11 software license.
3//
4// Bitflash end-to-end encrypted channel. Ported from Itzal echan.rs.
5// Uses libsodium crypto_box_curve25519xchacha20poly1305 (X25519 + XChaCha20-Poly1305),
6// the same primitive as Rust's crypto_box ChaChaBox.
7
8#include "btfchan.h"
9#include <sodium.h>
10#include <cstring>
11
12namespace btf
13{
14
15// Compile-time sanity: our constants match libsodium's.
16static_assert(CHAN_NONCEBYTES == crypto_box_curve25519xchacha20poly1305_NONCEBYTES, "nonce");
17static_assert(CHAN_MACBYTES == crypto_box_curve25519xchacha20poly1305_MACBYTES, "mac");
18static_assert(CHAN_KEYBYTES == crypto_box_curve25519xchacha20poly1305_BEFORENMBYTES, "key");
19
20bool ChanInit()
21{
22 return sodium_init() >= 0;
23}
24
25void ChanKeypair(unsigned char pk[32], unsigned char sk[32])
26{
27 crypto_box_curve25519xchacha20poly1305_keypair(pk, sk);
28}
29
30void ChanPublicFromSecret(unsigned char pk[32], const unsigned char sk[32])
31{
32 // X25519 public = scalarmult of the secret with the curve25519 base point.
33 crypto_scalarmult_base(pk, sk);
34}
35
36bool ChanClientHandshake(const unsigned char endpoint_static_pub[32],
37 unsigned char eph_pub_out[32], unsigned char shared_out[32])
38{
39 unsigned char eph_sk[32];
40 crypto_box_curve25519xchacha20poly1305_keypair(eph_pub_out, eph_sk);
41 // shared = X25519(eph_sk, endpoint_static_pub) -> hashed to a box key
42 int r = crypto_box_curve25519xchacha20poly1305_beforenm(shared_out, endpoint_static_pub, eph_sk);
43 sodium_memzero(eph_sk, sizeof(eph_sk));
44 return r == 0;
45}
46
47bool ChanEndpointHandshake(const unsigned char client_eph_pub[32],
48 const unsigned char my_static_sk[32], unsigned char shared_out[32])
49{
50 // shared = X25519(my_static_sk, client_eph_pub) -> same box key as the client computed
51 return crypto_box_curve25519xchacha20poly1305_beforenm(shared_out, client_eph_pub, my_static_sk) == 0;
52}
53
54std::vector<unsigned char> ChanEncryptFrame(const unsigned char shared[32],
55 const unsigned char* pt, size_t n)
56{
57 unsigned char nonce[CHAN_NONCEBYTES];
58 randombytes_buf(nonce, sizeof(nonce));
59
60 size_t ctlen = n + CHAN_MACBYTES;
61 size_t bodylen = CHAN_NONCEBYTES + ctlen;
62
63 std::vector<unsigned char> out(4 + bodylen);
64 out[0] = (unsigned char)((bodylen >> 24) & 0xff);
65 out[1] = (unsigned char)((bodylen >> 16) & 0xff);
66 out[2] = (unsigned char)((bodylen >> 8) & 0xff);
67 out[3] = (unsigned char)(bodylen & 0xff);
68 memcpy(&out[4], nonce, CHAN_NONCEBYTES);
69
70 crypto_box_curve25519xchacha20poly1305_easy_afternm(
71 &out[4 + CHAN_NONCEBYTES], pt, n, nonce, shared);
72 return out;
73}
74
75bool ChanDecryptBody(const unsigned char shared[32],
76 const unsigned char* body, size_t n, std::vector<unsigned char>& out)
77{
78 if (n < (size_t)(CHAN_NONCEBYTES + CHAN_MACBYTES))
79 return false;
80 const unsigned char* nonce = body;
81 const unsigned char* ct = body + CHAN_NONCEBYTES;
82 size_t ctlen = n - CHAN_NONCEBYTES;
83 out.resize(ctlen - CHAN_MACBYTES);
84 int r = crypto_box_curve25519xchacha20poly1305_open_easy_afternm(
85 out.empty() ? NULL : &out[0], ct, ctlen, nonce, shared);
86 if (r != 0)
87 {
88 out.clear();
89 return false;
90 }
91 return true;
92}
93
94} // namespace btf