Skip to content

Commit edab3c7

Browse files
committed
Encode/Decode CPubKey from to/from elligator-swift representation
1 parent 6ae4b53 commit edab3c7

File tree

5 files changed

+67
-2
lines changed

5 files changed

+67
-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
@@ -1997,7 +1997,7 @@ LIBS_TEMP="$LIBS"
19971997
unset LIBS
19981998
LIBS="$LIBS_TEMP"
19991999

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

20032003
AC_OUTPUT

src/pubkey.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <hash.h>
99
#include <secp256k1.h>
10+
#include <secp256k1_ellswift.h>
1011
#include <secp256k1_extrakeys.h>
1112
#include <secp256k1_recovery.h>
1213
#include <secp256k1_schnorrsig.h>
@@ -334,6 +335,21 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChi
334335
return true;
335336
}
336337

338+
std::optional<EllSwiftPubKey> CPubKey::EllSwiftEncode(const std::array<uint8_t, 32>& rnd32) const
339+
{
340+
assert(secp256k1_context_verify && "secp256k1_context_verify must be initialized to use CPubKey.");
341+
342+
secp256k1_pubkey pubkey;
343+
344+
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size())) {
345+
return {};
346+
}
347+
348+
EllSwiftPubKey encoded_pubkey;
349+
secp256k1_ellswift_encode(secp256k1_context_verify, encoded_pubkey.data(), &pubkey, rnd32.data());
350+
return encoded_pubkey;
351+
}
352+
337353
void CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {
338354
code[0] = nDepth;
339355
memcpy(code+1, vchFingerprint, 4);

src/pubkey.h

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

15+
#include <array>
1516
#include <cstring>
1617
#include <optional>
1718
#include <vector>
@@ -29,6 +30,9 @@ class CKeyID : public uint160
2930

3031
typedef uint256 ChainCode;
3132

33+
constexpr size_t ELLSWIFT_ENCODED_SIZE = 64;
34+
using EllSwiftPubKey = std::array<uint8_t, ELLSWIFT_ENCODED_SIZE>;
35+
3236
/** An encapsulated public key. */
3337
class CPubKey
3438
{
@@ -108,6 +112,7 @@ class CPubKey
108112
Set(_vch.begin(), _vch.end());
109113
}
110114

115+
111116
//! Simple read-only vector-like interface to the pubkey data.
112117
unsigned int size() const { return GetLen(vch[0]); }
113118
const unsigned char* data() const { return vch; }
@@ -219,6 +224,8 @@ class CPubKey
219224

220225
//! Derive BIP32 child pubkey.
221226
bool Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const;
227+
228+
std::optional<EllSwiftPubKey> EllSwiftEncode(const std::array<uint8_t, 32>& rnd32) const;
222229
};
223230

224231
class XOnlyPubKey

src/test/key_tests.cpp

+42
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,43 @@ 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, 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 (auto secret : {strSecret1, strSecret2, strSecret1C, strSecret2C}) {
370+
CKey key = DecodeSecret(secret);
371+
BOOST_CHECK(key.IsValid());
372+
373+
std::array<uint8_t, 32> rnd32;
374+
GetRandBytes(rnd32);
375+
auto original_pubkey = key.GetPubKey();
376+
auto ellswift_encoded_pubkey = original_pubkey.EllSwiftEncode(rnd32);
377+
378+
CPubKey decoded_pubkey = EllSwiftDecode(ellswift_encoded_pubkey.value());
379+
if (!key.IsCompressed()) {
380+
// The decoding constructor returns a compressed pubkey. If the
381+
// original was uncompressed, we must decompress the decoded one
382+
// to compare.
383+
decoded_pubkey.Decompress();
384+
}
385+
BOOST_CHECK(original_pubkey == decoded_pubkey);
386+
}
387+
}
388+
347389
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)