Skip to content

Commit 2e5a8a4

Browse files
dhruvPieter Wuille
authored andcommitted
Fuzz test for Ellswift ECDH
Co-authored-by: Pieter Wuille <[email protected]>
1 parent c3ac9f5 commit 2e5a8a4

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

src/pubkey.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,16 @@ struct EllSwiftPubKey
311311
static constexpr size_t size() { return SIZE; }
312312
auto begin() const { return m_pubkey.cbegin(); }
313313
auto end() const { return m_pubkey.cend(); }
314+
315+
bool friend operator==(const EllSwiftPubKey& a, const EllSwiftPubKey& b)
316+
{
317+
return a.m_pubkey == b.m_pubkey;
318+
}
319+
320+
bool friend operator!=(const EllSwiftPubKey& a, const EllSwiftPubKey& b)
321+
{
322+
return a.m_pubkey != b.m_pubkey;
323+
}
314324
};
315325

316326
struct CExtPubKey {

src/test/fuzz/key.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222

2323
#include <array>
2424
#include <cassert>
25+
#include <cstddef>
2526
#include <cstdint>
2627
#include <numeric>
28+
#include <optional>
2729
#include <string>
2830
#include <vector>
2931

@@ -324,3 +326,60 @@ FUZZ_TARGET_INIT(ellswift_roundtrip, initialize_key)
324326

325327
assert(key.VerifyPubKey(decoded_pubkey));
326328
}
329+
330+
FUZZ_TARGET_INIT(bip324_ecdh, initialize_key)
331+
{
332+
FuzzedDataProvider fdp{buffer.data(), buffer.size()};
333+
334+
// We generate private key, k1.
335+
auto rnd32 = fdp.ConsumeBytes<uint8_t>(32);
336+
rnd32.resize(32);
337+
CKey k1;
338+
k1.Set(rnd32.begin(), rnd32.end(), true);
339+
if (!k1.IsValid()) return;
340+
341+
// They generate private key, k2.
342+
rnd32 = fdp.ConsumeBytes<uint8_t>(32);
343+
rnd32.resize(32);
344+
CKey k2;
345+
k2.Set(rnd32.begin(), rnd32.end(), true);
346+
if (!k2.IsValid()) return;
347+
348+
// We construct an ellswift encoding for our key, k1_ellswift.
349+
auto ent32_1 = fdp.ConsumeBytes<std::byte>(32);
350+
ent32_1.resize(32);
351+
auto k1_ellswift = k1.EllSwiftCreate(ent32_1);
352+
353+
// They construct an ellswift encoding for their key, k2_ellswift.
354+
auto ent32_2 = fdp.ConsumeBytes<std::byte>(32);
355+
ent32_2.resize(32);
356+
auto k2_ellswift = k2.EllSwiftCreate(ent32_2);
357+
358+
// They construct another (possibly distinct) ellswift encoding for their key, k2_ellswift_bad.
359+
auto ent32_2_bad = fdp.ConsumeBytes<std::byte>(32);
360+
ent32_2_bad.resize(32);
361+
auto k2_ellswift_bad = k2.EllSwiftCreate(ent32_2_bad);
362+
assert((ent32_2_bad == ent32_2) == (k2_ellswift_bad == k2_ellswift));
363+
364+
// Determine who is who.
365+
bool initiating = fdp.ConsumeBool();
366+
367+
// We compute our shared secret using our key and their public key.
368+
auto ecdh_secret_1 = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, initiating);
369+
// They compute their shared secret using their key and our public key.
370+
auto ecdh_secret_2 = k2.ComputeBIP324ECDHSecret(k1_ellswift, k2_ellswift, !initiating);
371+
// Those must match, as everyone is behaving correctly.
372+
assert(ecdh_secret_1 == ecdh_secret_2);
373+
374+
if (k1_ellswift != k2_ellswift) {
375+
// Unless the two keys are exactly identical, acting as the wrong party breaks things.
376+
auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, !initiating);
377+
assert(ecdh_secret_bad != ecdh_secret_1);
378+
}
379+
380+
if (k2_ellswift_bad != k2_ellswift) {
381+
// Unless both encodings created by them are identical, using the second one breaks things.
382+
auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift_bad, k1_ellswift, initiating);
383+
assert(ecdh_secret_bad != ecdh_secret_1);
384+
}
385+
}

0 commit comments

Comments
 (0)