Bitcoin Core
31.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
src
test
fuzz
bip324.cpp
Go to the documentation of this file.
1
// Copyright (c) 2023-present The Bitcoin Core developers
2
// Distributed under the MIT software license, see the accompanying
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5
#include <
bip324.h
>
6
#include <chainparams.h>
7
#include <random.h>
8
#include <
span.h
>
9
#include <
test/fuzz/FuzzedDataProvider.h
>
10
#include <
test/fuzz/fuzz.h
>
11
#include <
test/fuzz/util.h
>
12
13
#include <algorithm>
14
#include <cstdint>
15
#include <vector>
16
17
namespace
{
18
19
void
Initialize()
20
{
21
static
ECC_Context
ecc_context
{};
22
SelectParams
(
ChainType::MAIN
);
23
}
24
25
}
// namespace
26
27
FUZZ_TARGET
(
bip324_cipher_roundtrip
, .
init
=Initialize)
28
{
29
// Test that BIP324Cipher's encryption and decryption agree.
30
31
// Load keys from fuzzer.
32
FuzzedDataProvider
provider(buffer.data(), buffer.size());
33
// Initiator key
34
CKey
init_key
=
ConsumePrivateKey
(provider,
/*compressed=*/
true
);
35
if
(!
init_key
.IsValid())
return
;
36
// Initiator entropy
37
auto
init_ent
= provider.
ConsumeBytes
<std::byte>(32);
38
init_ent
.resize(32);
39
// Responder key
40
CKey
resp_key
=
ConsumePrivateKey
(provider,
/*compressed=*/
true
);
41
if
(!
resp_key
.IsValid())
return
;
42
// Responder entropy
43
auto
resp_ent
= provider.
ConsumeBytes
<std::byte>(32);
44
resp_ent
.resize(32);
45
46
// Initialize ciphers by exchanging public keys.
47
BIP324Cipher
initiator
(
init_key
,
init_ent
);
48
assert
(!
initiator
);
49
BIP324Cipher
responder
(
resp_key
,
resp_ent
);
50
assert
(!
responder
);
51
initiator
.Initialize(
responder
.GetOurPubKey(),
true
);
52
assert
(
initiator
);
53
responder
.Initialize(
initiator
.GetOurPubKey(),
false
);
54
assert
(
responder
);
55
56
// Initialize RNG deterministically, to generate contents and AAD. We assume that there are no
57
// (potentially buggy) edge cases triggered by specific values of contents/AAD, so we can avoid
58
// reading the actual data for those from the fuzzer input (which would need large amounts of
59
// data).
60
InsecureRandomContext
rng(provider.
ConsumeIntegral
<
uint64_t
>());
61
62
// Compare session IDs and garbage terminators.
63
assert
(std::ranges::equal(
initiator
.GetSessionID(),
responder
.GetSessionID()));
64
assert
(std::ranges::equal(
initiator
.GetSendGarbageTerminator(),
responder
.GetReceiveGarbageTerminator()));
65
assert
(std::ranges::equal(
initiator
.GetReceiveGarbageTerminator(),
responder
.GetSendGarbageTerminator()));
66
67
LIMITED_WHILE
(provider.
remaining_bytes
(), 1000) {
68
// Mode:
69
// - Bit 0: whether the ignore bit is set in message
70
// - Bit 1: whether the responder (0) or initiator (1) sends
71
// - Bit 2: whether this ciphertext will be corrupted (making it the last sent one)
72
// - Bit 3-4: controls the maximum aad length (max 4095 bytes)
73
// - Bit 5-7: controls the maximum content length (max 16383 bytes, for performance reasons)
74
unsigned
mode = provider.
ConsumeIntegral
<
uint8_t
>();
75
bool
ignore = mode & 1;
76
bool
from_init
= mode & 2;
77
bool
damage
= mode & 4;
78
unsigned
aad_length_bits
= 4 * ((mode >> 3) & 3);
79
unsigned
aad_length
= provider.
ConsumeIntegralInRange
<
unsigned
>(0, (1 <<
aad_length_bits
) - 1);
80
unsigned
length_bits
= 2 * ((mode >> 5) & 7);
81
unsigned
length = provider.
ConsumeIntegralInRange
<
unsigned
>(0, (1 <<
length_bits
) - 1);
82
// Generate aad and content.
83
auto
aad
= rng.
randbytes
<std::byte>(
aad_length
);
84
auto
contents
= rng.
randbytes
<std::byte>(length);
85
86
// Pick sides.
87
auto
&
sender
{
from_init
?
initiator
:
responder
};
88
auto
&
receiver
{
from_init
?
responder
:
initiator
};
89
90
// Encrypt
91
std::vector<std::byte>
ciphertext
(length +
initiator
.EXPANSION);
92
sender
.Encrypt(
contents
,
aad
, ignore,
ciphertext
);
93
94
// Optionally damage 1 bit in either the ciphertext (corresponding to a change in transit)
95
// or the aad (to make sure that decryption will fail if the AAD mismatches).
96
if
(
damage
) {
97
unsigned
damage_bit
= provider.
ConsumeIntegralInRange
<
unsigned
>(0,
98
(
ciphertext
.size() +
aad
.size()) * 8U - 1U);
99
unsigned
damage_pos
=
damage_bit
>> 3;
100
std::byte
damage_val
{(
uint8_t
)(1U << (
damage_bit
& 7))};
101
if
(
damage_pos
>=
ciphertext
.size()) {
102
aad
[
damage_pos
-
ciphertext
.size()] ^=
damage_val
;
103
}
else
{
104
ciphertext
[
damage_pos
] ^=
damage_val
;
105
}
106
}
107
108
// Decrypt length
109
uint32_t
dec_length
=
receiver
.DecryptLength(std::span{
ciphertext
}.first(
initiator
.LENGTH_LEN));
110
if
(!
damage
) {
111
assert
(
dec_length
== length);
112
}
else
{
113
// For performance reasons, don't try to decode if length got increased too much.
114
if
(
dec_length
> 16384 + length)
break
;
115
// Otherwise, just append zeros if dec_length > length.
116
ciphertext
.resize(
dec_length
+
initiator
.EXPANSION);
117
}
118
119
// Decrypt
120
std::vector<std::byte>
decrypt
(
dec_length
);
121
bool
dec_ignore
{
false
};
122
bool
ok
=
receiver
.Decrypt(std::span{
ciphertext
}.subspan(
initiator
.LENGTH_LEN),
aad
,
dec_ignore
,
decrypt
);
123
// Decryption *must* fail if the packet was damaged, and succeed if it wasn't.
124
assert
(!
ok
==
damage
);
125
if
(!
ok
)
break
;
126
assert
(ignore ==
dec_ignore
);
127
assert
(
decrypt
==
contents
);
128
}
129
}
FuzzedDataProvider.h
bip324.h
ecc_context
ECC_Context ecc_context
Definition
bitcoin-wallet.cpp:126
SelectParams
void SelectParams(const ChainType chain)
Sets the params returned by Params() to those for the given chain type.
Definition
chainparams.cpp:140
ChainType::MAIN
@ MAIN
BIP324Cipher
The BIP324 packet cipher, encapsulating its key derivation, stream cipher, and AEAD.
Definition
bip324.h:20
CKey
An encapsulated private key.
Definition
key.h:36
ECC_Context
RAII class initializing and deinitializing global state for elliptic curve support.
Definition
key.h:326
FuzzedDataProvider
Definition
FuzzedDataProvider.h:32
FuzzedDataProvider::ConsumeBytes
std::vector< T > ConsumeBytes(size_t num_bytes)
Definition
FuzzedDataProvider.h:109
FuzzedDataProvider::remaining_bytes
size_t remaining_bytes()
Definition
FuzzedDataProvider.h:85
FuzzedDataProvider::ConsumeIntegralInRange
T ConsumeIntegralInRange(T min, T max)
Definition
FuzzedDataProvider.h:205
FuzzedDataProvider::ConsumeIntegral
T ConsumeIntegral()
Definition
FuzzedDataProvider.h:195
InsecureRandomContext
xoroshiro128++ PRNG.
Definition
random.h:425
RandomMixin::randbytes
std::vector< B > randbytes(size_t len) noexcept
Generate random bytes.
Definition
random.h:297
fuzz.h
FUZZ_TARGET
#define FUZZ_TARGET(...)
Definition
fuzz.h:35
LIMITED_WHILE
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
Definition
fuzz.h:22
init
Definition
bitcoin-gui.cpp:17
span.h
ConsumePrivateKey
CKey ConsumePrivateKey(FuzzedDataProvider &fuzzed_data_provider, std::optional< bool > compressed) noexcept
Definition
util.cpp:235
util.h
Ticks
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition
time.h:73
assert
assert(!tx.IsCoinBase())
Generated on Thu Apr 16 2026 09:42:38 for Bitcoin Core by
1.10.0