mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-20 10:38:42 +01:00
Add ElligatorSwift key creation and ECDH logic
Co-authored-by: Dhruv Mehta <856960+dhruv@users.noreply.github.com>
This commit is contained in:
parent
42239f8390
commit
eff72a0dff
37
src/key.cpp
37
src/key.cpp
@ -11,6 +11,7 @@
|
||||
#include <random.h>
|
||||
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_ellswift.h>
|
||||
#include <secp256k1_extrakeys.h>
|
||||
#include <secp256k1_recovery.h>
|
||||
#include <secp256k1_schnorrsig.h>
|
||||
@ -331,6 +332,42 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
|
||||
return ret;
|
||||
}
|
||||
|
||||
EllSwiftPubKey CKey::EllSwiftCreate(Span<const std::byte> ent32) const
|
||||
{
|
||||
assert(fValid);
|
||||
assert(ent32.size() == 32);
|
||||
std::array<std::byte, EllSwiftPubKey::size()> encoded_pubkey;
|
||||
|
||||
auto success = secp256k1_ellswift_create(secp256k1_context_sign,
|
||||
UCharCast(encoded_pubkey.data()),
|
||||
keydata.data(),
|
||||
UCharCast(ent32.data()));
|
||||
|
||||
// Should always succeed for valid keys (asserted above).
|
||||
assert(success);
|
||||
return {encoded_pubkey};
|
||||
}
|
||||
|
||||
ECDHSecret CKey::ComputeBIP324ECDHSecret(const EllSwiftPubKey& their_ellswift, const EllSwiftPubKey& our_ellswift, bool initiating) const
|
||||
{
|
||||
assert(fValid);
|
||||
|
||||
ECDHSecret output;
|
||||
// BIP324 uses the initiator as party A, and the responder as party B. Remap the inputs
|
||||
// accordingly:
|
||||
bool success = secp256k1_ellswift_xdh(secp256k1_context_sign,
|
||||
UCharCast(output.data()),
|
||||
UCharCast(initiating ? our_ellswift.data() : their_ellswift.data()),
|
||||
UCharCast(initiating ? their_ellswift.data() : our_ellswift.data()),
|
||||
keydata.data(),
|
||||
initiating ? 0 : 1,
|
||||
secp256k1_ellswift_xdh_hash_function_bip324,
|
||||
nullptr);
|
||||
// Should always succeed for valid keys (assert above).
|
||||
assert(success);
|
||||
return output;
|
||||
}
|
||||
|
||||
bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const {
|
||||
if (nDepth == std::numeric_limits<unsigned char>::max()) return false;
|
||||
out.nDepth = nDepth + 1;
|
||||
|
27
src/key.h
27
src/key.h
@ -22,6 +22,12 @@
|
||||
*/
|
||||
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
|
||||
|
||||
/** Size of ECDH shared secrets. */
|
||||
constexpr static size_t ECDH_SECRET_SIZE = CSHA256::OUTPUT_SIZE;
|
||||
|
||||
// Used to represent ECDH shared secret (ECDH_SECRET_SIZE bytes)
|
||||
using ECDHSecret = std::array<std::byte, ECDH_SECRET_SIZE>;
|
||||
|
||||
/** An encapsulated private key. */
|
||||
class CKey
|
||||
{
|
||||
@ -156,6 +162,27 @@ public:
|
||||
|
||||
//! Load private key and check that public key matches.
|
||||
bool Load(const CPrivKey& privkey, const CPubKey& vchPubKey, bool fSkipCheck);
|
||||
|
||||
/** Create an ellswift-encoded public key for this key, with specified entropy.
|
||||
*
|
||||
* entropy must be a 32-byte span with additional entropy to use in the encoding. Every
|
||||
* public key has ~2^256 different encodings, and this function will deterministically pick
|
||||
* one of them, based on entropy. Note that even without truly random entropy, the
|
||||
* resulting encoding will be indistinguishable from uniform to any adversary who does not
|
||||
* know the private key (because the private key itself is always used as entropy as well).
|
||||
*/
|
||||
EllSwiftPubKey EllSwiftCreate(Span<const std::byte> entropy) const;
|
||||
|
||||
/** Compute a BIP324-style ECDH shared secret.
|
||||
*
|
||||
* - their_ellswift: EllSwiftPubKey that was received from the other side.
|
||||
* - our_ellswift: EllSwiftPubKey that was sent to the other side (must have been generated
|
||||
* from *this using EllSwiftCreate()).
|
||||
* - initiating: whether we are the initiating party (true) or responding party (false).
|
||||
*/
|
||||
ECDHSecret ComputeBIP324ECDHSecret(const EllSwiftPubKey& their_ellswift,
|
||||
const EllSwiftPubKey& our_ellswift,
|
||||
bool initiating) const;
|
||||
};
|
||||
|
||||
struct CExtKey {
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <hash.h>
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_ellswift.h>
|
||||
#include <secp256k1_extrakeys.h>
|
||||
#include <secp256k1_recovery.h>
|
||||
#include <secp256k1_schnorrsig.h>
|
||||
@ -335,6 +336,20 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChi
|
||||
return true;
|
||||
}
|
||||
|
||||
CPubKey EllSwiftPubKey::Decode() const
|
||||
{
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_ellswift_decode(secp256k1_context_static, &pubkey, UCharCast(m_pubkey.data()));
|
||||
|
||||
size_t sz = CPubKey::COMPRESSED_SIZE;
|
||||
std::array<uint8_t, CPubKey::COMPRESSED_SIZE> vch_bytes;
|
||||
|
||||
secp256k1_ec_pubkey_serialize(secp256k1_context_static, vch_bytes.data(), &sz, &pubkey, SECP256K1_EC_COMPRESSED);
|
||||
assert(sz == vch_bytes.size());
|
||||
|
||||
return CPubKey{vch_bytes.begin(), vch_bytes.end()};
|
||||
}
|
||||
|
||||
void CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {
|
||||
code[0] = nDepth;
|
||||
memcpy(code+1, vchFingerprint, 4);
|
||||
|
22
src/pubkey.h
22
src/pubkey.h
@ -291,6 +291,28 @@ public:
|
||||
SERIALIZE_METHODS(XOnlyPubKey, obj) { READWRITE(obj.m_keydata); }
|
||||
};
|
||||
|
||||
/** An ElligatorSwift-encoded public key. */
|
||||
struct EllSwiftPubKey
|
||||
{
|
||||
private:
|
||||
static constexpr size_t SIZE = 64;
|
||||
std::array<std::byte, SIZE> m_pubkey;
|
||||
|
||||
public:
|
||||
/** Construct a new ellswift public key from a given serialization. */
|
||||
EllSwiftPubKey(const std::array<std::byte, SIZE>& ellswift) :
|
||||
m_pubkey(ellswift) {}
|
||||
|
||||
/** Decode to normal compressed CPubKey (for debugging purposes). */
|
||||
CPubKey Decode() const;
|
||||
|
||||
// Read-only access for serialization.
|
||||
const std::byte* data() const { return m_pubkey.data(); }
|
||||
static constexpr size_t size() { return SIZE; }
|
||||
auto begin() const { return m_pubkey.cbegin(); }
|
||||
auto end() const { return m_pubkey.cend(); }
|
||||
};
|
||||
|
||||
struct CExtPubKey {
|
||||
unsigned char version[4];
|
||||
unsigned char nDepth;
|
||||
|
@ -274,6 +274,7 @@ Span<std::byte> MakeWritableByteSpan(V&& v) noexcept
|
||||
// Helper functions to safely cast to unsigned char pointers.
|
||||
inline unsigned char* UCharCast(char* c) { return (unsigned char*)c; }
|
||||
inline unsigned char* UCharCast(unsigned char* c) { return c; }
|
||||
inline unsigned char* UCharCast(std::byte* c) { return (unsigned char*)c; }
|
||||
inline const unsigned char* UCharCast(const char* c) { return (unsigned char*)c; }
|
||||
inline const unsigned char* UCharCast(const unsigned char* c) { return c; }
|
||||
inline const unsigned char* UCharCast(const std::byte* c) { return reinterpret_cast<const unsigned char*>(c); }
|
||||
|
Loading…
Reference in New Issue
Block a user