UltrafastSecp256k1 3.50.0
Ultra high-performance secp256k1 elliptic curve cryptography library
Loading...
Searching...
No Matches
bip324.hpp
Go to the documentation of this file.
1#ifndef SECP256K1_BIP324_HPP
2#define SECP256K1_BIP324_HPP
3#pragma once
4
5// ============================================================================
6// BIP-324: Version 2 P2P Encrypted Transport Protocol
7// ============================================================================
8// Implements the BIP-324 v2 encrypted transport, consisting of:
9// 1. Key exchange via ElligatorSwift-encoded ECDH
10// 2. Key derivation via HKDF-SHA256
11// 3. Packet encryption via ChaCha20-Poly1305 AEAD
12//
13// Session lifecycle:
14// 1. Both peers generate ephemeral keys and ElligatorSwift encodings
15// 2. Exchange 64-byte encodings
16// 3. Derive symmetric keys via ECDH + HKDF
17// 4. Encrypt/decrypt packets with ChaCha20-Poly1305
18//
19// Packet format:
20// [3 bytes encrypted length] [N bytes encrypted payload] [16 bytes Poly1305 tag]
21//
22// Reference: https://github.com/bitcoin/bips/blob/master/bip-0324.mediawiki
23// ============================================================================
24
25#include <array>
26#include <cstdint>
27#include <cstddef>
28#include <cstring>
29#include <vector>
30#include "secp256k1/scalar.hpp"
31
32namespace secp256k1 {
33
34// -- BIP-324 Cipher Suite (per-direction) -------------------------------------
35
37public:
38 Bip324Cipher() noexcept = default;
39 ~Bip324Cipher() noexcept {
40 // Volatile write to prevent dead-store elimination
41 volatile std::uint8_t* p = key_;
42 for (std::size_t i = 0; i < 32; ++i) p[i] = 0;
43 }
44
45 // Initialize with a 32-byte key for this direction
46 void init(const std::uint8_t* key) noexcept;
47
48 // Encrypt a packet (plaintext -> header_enc[3] + payload_enc[len] + tag[16])
49 // aad is optional associated data.
50 // Returns the encrypted output vector: [3-byte enc length][payload][16-byte tag]
51 std::vector<std::uint8_t> encrypt(
52 const std::uint8_t* aad, std::size_t aad_len,
53 const std::uint8_t* plaintext, std::size_t plaintext_len) noexcept;
54
55 // Decrypt a packet. header_enc is the 3-byte encrypted length prefix.
56 // contents is the encrypted payload + 16-byte tag.
57 // Returns true on success and writes the decrypted payload to plaintext_out.
58 // Returns false on auth failure or malformed decrypted packet framing.
59 bool decrypt(
60 const std::uint8_t* aad, std::size_t aad_len,
61 const std::uint8_t* header_enc,
62 const std::uint8_t* contents, std::size_t contents_len,
63 std::vector<std::uint8_t>& plaintext_out) noexcept;
64
65 // Get the current packet counter (nonce)
66 std::uint64_t packet_counter() const noexcept { return packet_counter_; }
67
68private:
69 std::uint8_t key_[32]{};
70 std::uint64_t packet_counter_ = 0;
71
72 // Build a 12-byte nonce from the packet counter
73 void build_nonce(std::uint8_t* nonce) const noexcept;
74};
75
76// -- BIP-324 Session ----------------------------------------------------------
77
79public:
80 // Initialize session: generate ephemeral key and ElligatorSwift encoding.
81 // After construction, call our_ellswift_encoding() to get our 64-byte message.
82 explicit Bip324Session(bool initiator) noexcept;
83
84 // Initialize with a specific private key (for testing / deterministic use)
85 Bip324Session(bool initiator, const std::uint8_t* privkey) noexcept;
86
87 ~Bip324Session() noexcept {
88 // Erase private key material on destruction
89 volatile std::uint8_t* p = privkey_.data();
90 for (std::size_t i = 0; i < 32; ++i) p[i] = 0;
91 }
92
93 // Get our 64-byte ElligatorSwift-encoded public key to send to peer
94 const std::array<std::uint8_t, 64>& our_ellswift_encoding() const noexcept {
95 return our_encoding_;
96 }
97
98 // Complete the handshake by providing the peer's 64-byte ElligatorSwift encoding.
99 // This derives the shared secret and symmetric keys.
100 // Returns true on success.
101 bool complete_handshake(const std::uint8_t* peer_encoding) noexcept;
102
103 // Encrypt a message for sending to the peer.
104 // Returns: [3-byte encrypted length][payload][16-byte tag]
105 std::vector<std::uint8_t> encrypt(
106 const std::uint8_t* plaintext, std::size_t plaintext_len) noexcept;
107
108 // Decrypt a received message.
109 // header is the 3-byte encrypted length prefix.
110 // payload_and_tag is the encrypted payload followed by the 16-byte tag.
111 // Returns true on success and writes the decrypted payload to plaintext_out.
112 // Returns false on auth failure or malformed decrypted packet framing.
114 const std::uint8_t* header,
115 const std::uint8_t* payload_and_tag, std::size_t len,
116 std::vector<std::uint8_t>& plaintext_out) noexcept;
117
118 // Check if handshake is complete
119 bool is_established() const noexcept { return established_; }
120
121 // Get session ID (32 bytes, derived during key setup)
122 const std::array<std::uint8_t, 32>& session_id() const noexcept {
123 return session_id_;
124 }
125
126private:
127 bool initiator_;
128 bool established_ = false;
129
130 // Our ephemeral key
131 std::array<std::uint8_t, 32> privkey_{};
132 std::array<std::uint8_t, 64> our_encoding_{};
133
134 // Peer's encoding
135 std::array<std::uint8_t, 64> peer_encoding_{};
136
137 // Derived keys
138 std::array<std::uint8_t, 32> session_id_{};
139 Bip324Cipher send_cipher_;
140 Bip324Cipher recv_cipher_;
141};
142
143} // namespace secp256k1
144
145#endif // SECP256K1_BIP324_HPP
Bip324Cipher() noexcept=default
bool decrypt(const std::uint8_t *aad, std::size_t aad_len, const std::uint8_t *header_enc, const std::uint8_t *contents, std::size_t contents_len, std::vector< std::uint8_t > &plaintext_out) noexcept
std::uint64_t packet_counter() const noexcept
Definition bip324.hpp:66
void init(const std::uint8_t *key) noexcept
std::vector< std::uint8_t > encrypt(const std::uint8_t *aad, std::size_t aad_len, const std::uint8_t *plaintext, std::size_t plaintext_len) noexcept
const std::array< std::uint8_t, 32 > & session_id() const noexcept
Definition bip324.hpp:122
bool complete_handshake(const std::uint8_t *peer_encoding) noexcept
std::vector< std::uint8_t > encrypt(const std::uint8_t *plaintext, std::size_t plaintext_len) noexcept
const std::array< std::uint8_t, 64 > & our_ellswift_encoding() const noexcept
Definition bip324.hpp:94
Bip324Session(bool initiator, const std::uint8_t *privkey) noexcept
~Bip324Session() noexcept
Definition bip324.hpp:87
bool is_established() const noexcept
Definition bip324.hpp:119
Bip324Session(bool initiator) noexcept
bool decrypt(const std::uint8_t *header, const std::uint8_t *payload_and_tag, std::size_t len, std::vector< std::uint8_t > &plaintext_out) noexcept