Skip to content

Commit 18895d3

Browse files
committed
Encode CKey to ElligatorSwift representation
1 parent 5b01fda commit 18895d3

File tree

6 files changed

+67
-2
lines changed

6 files changed

+67
-2
lines changed

Diff for: 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_RECOVERY;ENABLE_MODULE_EXTRAKEYS;ENABLE_MODULE_SCHNORRSIG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
17+
<PreprocessorDefinitions>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>

Diff for: configure.ac

+1-1
Original file line numberDiff line numberDiff line change
@@ -2012,7 +2012,7 @@ LIBS_TEMP="$LIBS"
20122012
unset LIBS
20132013
LIBS="$LIBS_TEMP"
20142014

2015-
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --disable-module-ecdh"
2015+
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery --disable-module-ecdh --enable-experimental --enable-module-ellswift"
20162016
AC_CONFIG_SUBDIRS([src/secp256k1])
20172017

20182018
AC_OUTPUT

Diff for: src/key.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
#include <crypto/hmac_sha512.h>
1010
#include <hash.h>
1111
#include <random.h>
12+
#include <span.h>
1213

1314
#include <secp256k1.h>
15+
#include <secp256k1_ellswift.h>
1416
#include <secp256k1_extrakeys.h>
1517
#include <secp256k1_recovery.h>
1618
#include <secp256k1_schnorrsig.h>
@@ -332,6 +334,21 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
332334
return ret;
333335
}
334336

337+
EllSwiftPubKey CKey::EllSwiftEncode(const std::array<std::byte, 32>& rnd32) const
338+
{
339+
assert(fValid);
340+
EllSwiftPubKey encoded_pubkey;
341+
342+
auto success = secp256k1_ellswift_create(secp256k1_context_sign,
343+
reinterpret_cast<unsigned char*>(encoded_pubkey.data()),
344+
keydata.data(),
345+
UCharCast(rnd32.data()));
346+
347+
// Should always succeed for valid keys (asserted above)
348+
assert(success);
349+
return encoded_pubkey;
350+
}
351+
335352
bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const {
336353
if (nDepth == std::numeric_limits<unsigned char>::max()) return false;
337354
out.nDepth = nDepth + 1;

Diff for: src/key.h

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include <support/allocators/secure.h>
1313
#include <uint256.h>
1414

15+
#include <array>
16+
#include <cstddef>
1517
#include <stdexcept>
1618
#include <vector>
1719

@@ -156,6 +158,8 @@ class CKey
156158

157159
//! Load private key and check that public key matches.
158160
bool Load(const CPrivKey& privkey, const CPubKey& vchPubKey, bool fSkipCheck);
161+
162+
EllSwiftPubKey EllSwiftEncode(const std::array<std::byte, 32>& rnd32) const;
159163
};
160164

161165
struct CExtKey {

Diff for: 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
{

Diff for: src/test/key_tests.cpp

+39
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@
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>
1114
#include <util/strencodings.h>
1215
#include <util/string.h>
1316
#include <util/system.h>
1417

18+
#include <array>
19+
#include <cstddef>
1520
#include <string>
1621
#include <vector>
1722

@@ -344,4 +349,38 @@ BOOST_AUTO_TEST_CASE(bip340_test_vectors)
344349
}
345350
}
346351

352+
CPubKey EllSwiftDecode(const EllSwiftPubKey& encoded_pubkey)
353+
{
354+
secp256k1_pubkey pubkey;
355+
secp256k1_ellswift_decode(secp256k1_context_static, &pubkey, reinterpret_cast<const unsigned char*>(encoded_pubkey.data()));
356+
357+
size_t sz = CPubKey::COMPRESSED_SIZE;
358+
std::array<uint8_t, CPubKey::COMPRESSED_SIZE> vch_bytes;
359+
360+
secp256k1_ec_pubkey_serialize(secp256k1_context_static, vch_bytes.data(), &sz, &pubkey, SECP256K1_EC_COMPRESSED);
361+
362+
return CPubKey{vch_bytes.begin(), vch_bytes.end()};
363+
}
364+
365+
BOOST_AUTO_TEST_CASE(key_ellswift)
366+
{
367+
for (const auto& secret : {strSecret1, strSecret2, strSecret1C, strSecret2C}) {
368+
CKey key = DecodeSecret(secret);
369+
BOOST_CHECK(key.IsValid());
370+
371+
std::array<std::byte, 32> rnd32;
372+
GetRandBytes({reinterpret_cast<unsigned char*>(rnd32.data()), 32});
373+
auto ellswift_encoded_pubkey = key.EllSwiftEncode(rnd32);
374+
375+
CPubKey decoded_pubkey = EllSwiftDecode(ellswift_encoded_pubkey);
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)