Skip to content

Commit 3fbc703

Browse files
committed
Encode CKey to ElligatorSwift representation
1 parent 0fafefb commit 3fbc703

File tree

6 files changed

+60
-2
lines changed

6 files changed

+60
-2
lines changed

build_msvc/libsecp256k1/libsecp256k1.vcxproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
</ItemGroup>
1515
<ItemDefinitionGroup>
1616
<ClCompile>
17-
<PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;ENABLE_MODULE_EXTRAKEYS;ENABLE_MODULE_SCHNORRSIG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
17+
<PreprocessorDefinitions>ENABLE_MODULE_ECDH;ENABLE_MODULE_RECOVERY;ENABLE_MODULE_EXTRAKEYS;ENABLE_MODULE_SCHNORRSIG;ENABLE_MODULE_ELLSWIFT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
1818
<AdditionalIncludeDirectories>..\..\src\secp256k1;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
1919
<DisableSpecificWarnings>4146;4244;4267;4334</DisableSpecificWarnings>
2020
</ClCompile>

configure.ac

+1-1
Original file line numberDiff line numberDiff line change
@@ -2016,7 +2016,7 @@ LIBS_TEMP="$LIBS"
20162016
unset LIBS
20172017
LIBS="$LIBS_TEMP"
20182018

2019-
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --enable-module-schnorrsig"
2019+
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --enable-module-schnorrsig --enable-experimental --enable-module-ellswift"
20202020
AC_CONFIG_SUBDIRS([src/secp256k1])
20212021

20222022
AC_OUTPUT

src/key.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <random.h>
1212

1313
#include <secp256k1.h>
14+
#include <secp256k1_ellswift.h>
1415
#include <secp256k1_extrakeys.h>
1516
#include <secp256k1_recovery.h>
1617
#include <secp256k1_schnorrsig.h>
@@ -332,6 +333,17 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
332333
return ret;
333334
}
334335

336+
std::optional<EllSwiftPubKey> CKey::EllSwiftEncode() const
337+
{
338+
EllSwiftPubKey encoded_pubkey;
339+
if (!secp256k1_ellswift_create(secp256k1_context_sign,
340+
reinterpret_cast<unsigned char*>(encoded_pubkey.data()),
341+
keydata.data(), nullptr)) {
342+
return {};
343+
}
344+
return encoded_pubkey;
345+
}
346+
335347
bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const {
336348
if (nDepth == std::numeric_limits<unsigned char>::max()) return false;
337349
out.nDepth = nDepth + 1;

src/key.h

+2
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ class CKey
156156

157157
//! Load private key and check that public key matches.
158158
bool Load(const CPrivKey& privkey, const CPubKey& vchPubKey, bool fSkipCheck);
159+
160+
std::optional<EllSwiftPubKey> EllSwiftEncode() const;
159161
};
160162

161163
struct CExtKey {

src/pubkey.h

+5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include <span.h>
1313
#include <uint256.h>
1414

15+
#include <array>
16+
#include <cstddef>
1517
#include <cstring>
1618
#include <optional>
1719
#include <vector>
@@ -29,6 +31,9 @@ class CKeyID : public uint160
2931

3032
typedef uint256 ChainCode;
3133

34+
constexpr size_t ELLSWIFT_ENCODED_SIZE = 64;
35+
using EllSwiftPubKey = std::array<std::byte, ELLSWIFT_ENCODED_SIZE>;
36+
3237
/** An encapsulated public key. */
3338
class CPubKey
3439
{

src/test/key_tests.cpp

+39
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
#include <key.h>
66

77
#include <key_io.h>
8+
#include <random.h>
9+
#include <secp256k1.h>
10+
#include <secp256k1_ellswift.h>
811
#include <streams.h>
912
#include <test/util/setup_common.h>
1013
#include <uint256.h>
@@ -344,4 +347,40 @@ BOOST_AUTO_TEST_CASE(bip340_test_vectors)
344347
}
345348
}
346349

350+
CPubKey EllSwiftDecode(const EllSwiftPubKey& encoded_pubkey)
351+
{
352+
auto secp256k1_context_verify = GetVerifyContext();
353+
assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey.");
354+
assert(encoded_pubkey.size() == ELLSWIFT_ENCODED_SIZE && "Elligator-swift encoded pub keys must be 64 bytes");
355+
356+
secp256k1_pubkey pubkey;
357+
secp256k1_ellswift_decode(secp256k1_context_verify, &pubkey, reinterpret_cast<const unsigned char*>(encoded_pubkey.data()));
358+
359+
size_t sz = CPubKey::COMPRESSED_SIZE;
360+
std::array<uint8_t, CPubKey::COMPRESSED_SIZE> vch_bytes;
361+
362+
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, vch_bytes.data(), &sz, &pubkey, SECP256K1_EC_COMPRESSED);
363+
364+
return CPubKey{vch_bytes.begin(), vch_bytes.end()};
365+
}
366+
367+
BOOST_AUTO_TEST_CASE(key_ellswift)
368+
{
369+
for (const auto& secret : {strSecret1, strSecret2, strSecret1C, strSecret2C}) {
370+
CKey key = DecodeSecret(secret);
371+
BOOST_CHECK(key.IsValid());
372+
373+
auto ellswift_encoded_pubkey = key.EllSwiftEncode();
374+
375+
CPubKey decoded_pubkey = EllSwiftDecode(ellswift_encoded_pubkey.value());
376+
if (!key.IsCompressed()) {
377+
// The decoding constructor returns a compressed pubkey. If the
378+
// original was uncompressed, we must decompress the decoded one
379+
// to compare.
380+
decoded_pubkey.Decompress();
381+
}
382+
BOOST_CHECK(key.GetPubKey() == decoded_pubkey);
383+
}
384+
}
385+
347386
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)