mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-04-24 13:59:38 +02:00
Merge bitcoin/bitcoin#27479: BIP324: ElligatorSwift integrations
3168b08043Bench test for EllSwift ECDH (Pieter Wuille)42d759f239Bench tests for CKey->EllSwift (dhruv)2e5a8a437cFuzz test for Ellswift ECDH (dhruv)c3ac9f5cf4Fuzz test for CKey->EllSwift->CPubKey creation/decoding (dhruv)aae432a764Unit test for ellswift creation/decoding roundtrip (dhruv)eff72a0dffAdd ElligatorSwift key creation and ECDH logic (Pieter Wuille)42239f8390Enable ellswift module in libsecp256k1 (dhruv)901336eee7Squashed 'src/secp256k1/' changes from 4258c54f4e..705ce7ed8c (Pieter Wuille) Pull request description: This replaces #23432 and part of #23561. This PR introduces all of the ElligatorSwift-related changes (libsecp256k1 updates, generation, decoding, ECDH, tests, fuzzing, benchmarks) needed for BIP324. ElligatorSwift is a special 64-byte encoding format for public keys introduced in libsecp256k1 in https://github.com/bitcoin-core/secp256k1/pull/1129. It has the property that *every* 64-byte array is a valid encoding for some public key, and every key has approximately $2^{256}$ encodings. Furthermore, it is possible to efficiently generate a uniformly random encoding for a given public key or private key. This is used for the key exchange phase in BIP324, to achieve a byte stream that is entirely pseudorandom, even before the shared encryption key is established. ACKs for top commit: instagibbs: reACK3168b08043achow101: ACK3168b08043theStack: re-ACK3168b08043Tree-SHA512: 308ac3d33e9a2deecb65826cbf0390480a38de201918429c35c796f3421cdf94c5501d027a043ae8f012cfaa0584656da1de6393bfba3532ab4c20f9533f06a6
This commit is contained in:
@@ -15,13 +15,17 @@
|
||||
#include <script/signingprovider.h>
|
||||
#include <script/standard.h>
|
||||
#include <streams.h>
|
||||
#include <test/fuzz/FuzzedDataProvider.h>
|
||||
#include <test/fuzz/fuzz.h>
|
||||
#include <util/chaintype.h>
|
||||
#include <util/strencodings.h>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -303,3 +307,79 @@ FUZZ_TARGET_INIT(key, initialize_key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FUZZ_TARGET_INIT(ellswift_roundtrip, initialize_key)
|
||||
{
|
||||
FuzzedDataProvider fdp{buffer.data(), buffer.size()};
|
||||
|
||||
auto key_bytes = fdp.ConsumeBytes<uint8_t>(32);
|
||||
key_bytes.resize(32);
|
||||
CKey key;
|
||||
key.Set(key_bytes.begin(), key_bytes.end(), true);
|
||||
if (!key.IsValid()) return;
|
||||
|
||||
auto ent32 = fdp.ConsumeBytes<std::byte>(32);
|
||||
ent32.resize(32);
|
||||
|
||||
auto encoded_ellswift = key.EllSwiftCreate(ent32);
|
||||
auto decoded_pubkey = encoded_ellswift.Decode();
|
||||
|
||||
assert(key.VerifyPubKey(decoded_pubkey));
|
||||
}
|
||||
|
||||
FUZZ_TARGET_INIT(bip324_ecdh, initialize_key)
|
||||
{
|
||||
FuzzedDataProvider fdp{buffer.data(), buffer.size()};
|
||||
|
||||
// We generate private key, k1.
|
||||
auto rnd32 = fdp.ConsumeBytes<uint8_t>(32);
|
||||
rnd32.resize(32);
|
||||
CKey k1;
|
||||
k1.Set(rnd32.begin(), rnd32.end(), true);
|
||||
if (!k1.IsValid()) return;
|
||||
|
||||
// They generate private key, k2.
|
||||
rnd32 = fdp.ConsumeBytes<uint8_t>(32);
|
||||
rnd32.resize(32);
|
||||
CKey k2;
|
||||
k2.Set(rnd32.begin(), rnd32.end(), true);
|
||||
if (!k2.IsValid()) return;
|
||||
|
||||
// We construct an ellswift encoding for our key, k1_ellswift.
|
||||
auto ent32_1 = fdp.ConsumeBytes<std::byte>(32);
|
||||
ent32_1.resize(32);
|
||||
auto k1_ellswift = k1.EllSwiftCreate(ent32_1);
|
||||
|
||||
// They construct an ellswift encoding for their key, k2_ellswift.
|
||||
auto ent32_2 = fdp.ConsumeBytes<std::byte>(32);
|
||||
ent32_2.resize(32);
|
||||
auto k2_ellswift = k2.EllSwiftCreate(ent32_2);
|
||||
|
||||
// They construct another (possibly distinct) ellswift encoding for their key, k2_ellswift_bad.
|
||||
auto ent32_2_bad = fdp.ConsumeBytes<std::byte>(32);
|
||||
ent32_2_bad.resize(32);
|
||||
auto k2_ellswift_bad = k2.EllSwiftCreate(ent32_2_bad);
|
||||
assert((ent32_2_bad == ent32_2) == (k2_ellswift_bad == k2_ellswift));
|
||||
|
||||
// Determine who is who.
|
||||
bool initiating = fdp.ConsumeBool();
|
||||
|
||||
// We compute our shared secret using our key and their public key.
|
||||
auto ecdh_secret_1 = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, initiating);
|
||||
// They compute their shared secret using their key and our public key.
|
||||
auto ecdh_secret_2 = k2.ComputeBIP324ECDHSecret(k1_ellswift, k2_ellswift, !initiating);
|
||||
// Those must match, as everyone is behaving correctly.
|
||||
assert(ecdh_secret_1 == ecdh_secret_2);
|
||||
|
||||
if (k1_ellswift != k2_ellswift) {
|
||||
// Unless the two keys are exactly identical, acting as the wrong party breaks things.
|
||||
auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift, k1_ellswift, !initiating);
|
||||
assert(ecdh_secret_bad != ecdh_secret_1);
|
||||
}
|
||||
|
||||
if (k2_ellswift_bad != k2_ellswift) {
|
||||
// Unless both encodings created by them are identical, using the second one breaks things.
|
||||
auto ecdh_secret_bad = k1.ComputeBIP324ECDHSecret(k2_ellswift_bad, k1_ellswift, initiating);
|
||||
assert(ecdh_secret_bad != ecdh_secret_1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,4 +344,24 @@ BOOST_AUTO_TEST_CASE(bip340_test_vectors)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(key_ellswift)
|
||||
{
|
||||
for (const auto& secret : {strSecret1, strSecret2, strSecret1C, strSecret2C}) {
|
||||
CKey key = DecodeSecret(secret);
|
||||
BOOST_CHECK(key.IsValid());
|
||||
|
||||
uint256 ent32 = InsecureRand256();
|
||||
auto ellswift = key.EllSwiftCreate(AsBytes(Span{ent32}));
|
||||
|
||||
CPubKey decoded_pubkey = ellswift.Decode();
|
||||
if (!key.IsCompressed()) {
|
||||
// The decoding constructor returns a compressed pubkey. If the
|
||||
// original was uncompressed, we must decompress the decoded one
|
||||
// to compare.
|
||||
decoded_pubkey.Decompress();
|
||||
}
|
||||
BOOST_CHECK(key.GetPubKey() == decoded_pubkey);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
Reference in New Issue
Block a user