From 0db6333bc3c5109ad264e5fbf5502f912fae160d Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Thu, 21 Nov 2024 18:37:53 +0100 Subject: [PATCH] feat: improve type system --- include/kth/domain/wallet/ec_private.hpp | 13 +++++++-- include/kth/domain/wallet/ec_public.hpp | 16 +++++++++-- src/wallet/ec_private.cpp | 35 ++++++----------------- src/wallet/ec_public.cpp | 10 +------ src/wallet/encrypted_keys.cpp | 8 +++--- src/wallet/message.cpp | 3 +- src/wallet/stealth_receiver.cpp | 2 +- src/wallet/stealth_sender.cpp | 2 +- test/math/stealth.cpp | 2 +- test/wallet/message.cpp | 36 ++++++++++++------------ test/wallet/stealth_receiver.cpp | 2 +- 11 files changed, 60 insertions(+), 69 deletions(-) diff --git a/include/kth/domain/wallet/ec_private.hpp b/include/kth/domain/wallet/ec_private.hpp index 141fc14d2..9adf5a468 100644 --- a/include/kth/domain/wallet/ec_private.hpp +++ b/include/kth/domain/wallet/ec_private.hpp @@ -76,16 +76,23 @@ class KD_API ec_private { } /// Constructors. - ec_private(); - ec_private(ec_private const& x) = default; + ec_private() = default; + + explicit ec_private(std::string const& wif, uint8_t version = mainnet_p2kh); + + explicit ec_private(wif_compressed const& wif, uint8_t version = mainnet_p2kh); + + explicit ec_private(const wif_uncompressed& wif, uint8_t version = mainnet_p2kh); /// The version is 16 bits. The most significant byte is the WIF prefix and /// the least significant byte is the address perfix. 0x8000 by default. + explicit ec_private(ec_secret const& secret, uint16_t version = mainnet, bool compress = true); + ec_private(ec_private const& x) = default; ec_private& operator=(ec_private const& x) = default; /// Operators. @@ -147,7 +154,7 @@ class KD_API ec_private { bool valid_{false}; bool compress_{true}; uint16_t version_{0}; - ec_secret secret_; + ec_secret secret_{null_hash}; }; } // namespace kth::domain::wallet diff --git a/include/kth/domain/wallet/ec_public.hpp b/include/kth/domain/wallet/ec_public.hpp index 2c6329ca5..0b66183cb 100644 --- a/include/kth/domain/wallet/ec_public.hpp +++ b/include/kth/domain/wallet/ec_public.hpp @@ -36,14 +36,24 @@ class KD_API ec_public { uint8_t const mainnet_p2kh; /// Constructors. - ec_public(); - ec_public(ec_public const& x); + ec_public() = default; + + explicit ec_public(ec_private const& secret); + + explicit ec_public(data_chunk const& decoded); + + explicit ec_public(std::string const& base16); + + explicit ec_public(ec_compressed const& point, bool compress = true); + + explicit ec_public(ec_uncompressed const& point, bool compress = false); + ec_public(ec_public const& x) = default; ec_public& operator=(ec_public const& x) = default; /// Operators. @@ -108,7 +118,7 @@ class KD_API ec_public { bool valid_{false}; bool compress_{true}; uint8_t version_; - ec_compressed point_; + ec_compressed point_ = null_compressed_point; }; } // namespace kth::domain::wallet diff --git a/src/wallet/ec_private.cpp b/src/wallet/ec_private.cpp index 40758fbc8..de607a497 100644 --- a/src/wallet/ec_private.cpp +++ b/src/wallet/ec_private.cpp @@ -35,38 +35,21 @@ uint8_t const ec_private::testnet_wif = 0xef; uint8_t const ec_private::testnet_p2kh = 0x6f; uint16_t const ec_private::testnet = to_version(testnet_p2kh, testnet_wif); -ec_private::ec_private() - : secret_(null_hash) -{} - -// ec_private::ec_private(ec_private const& x) -// : valid_(x.valid_), compress_(x.compress_), version_(x.version_), secret_(x.secret_) { -// } - ec_private::ec_private(std::string const& wif, uint8_t version) - : ec_private(from_string(wif, version)) { -} + : ec_private(from_string(wif, version)) +{} ec_private::ec_private(wif_compressed const& wif, uint8_t version) - : ec_private(from_compressed(wif, version)) { -} + : ec_private(from_compressed(wif, version)) +{} ec_private::ec_private(const wif_uncompressed& wif, uint8_t version) - : ec_private(from_uncompressed(wif, version)) { -} + : ec_private(from_uncompressed(wif, version)) +{} ec_private::ec_private(ec_secret const& secret, uint16_t version, bool compress) - : valid_(true), compress_(compress), version_(version), secret_(secret) { -} - -// ec_private& ec_private::operator=(ec_private const& x) { -// valid_ = x.valid_; -// compress_ = x.compress_; -// version_ = x.version_; -// secret_ = x.secret_; -// return *this; -// } - + : valid_(true), compress_(compress), version_(version), secret_(secret) +{} // Validators. // ---------------------------------------------------------------------------- @@ -182,7 +165,7 @@ ec_public ec_private::to_public() const { } payment_address ec_private::to_payment_address() const { - return {*this}; + return payment_address{*this}; } // Operators. diff --git a/src/wallet/ec_public.cpp b/src/wallet/ec_public.cpp index 62ebcf813..097e4412e 100644 --- a/src/wallet/ec_public.cpp +++ b/src/wallet/ec_public.cpp @@ -27,14 +27,6 @@ uint8_t const ec_public::mainnet_p2kh = 0x30; uint8_t const ec_public::mainnet_p2kh = 0x00; #endif -ec_public::ec_public() - : point_(null_compressed_point) -{} - -ec_public::ec_public(ec_public const& x) - : valid_(x.valid_), compress_(x.compress_), point_(x.point_) { -} - ec_public::ec_public(ec_private const& secret) : ec_public(from_private(secret)) { } @@ -173,7 +165,7 @@ bool ec_public::to_uncompressed(ec_uncompressed& out) const { } payment_address ec_public::to_payment_address(uint8_t version) const { - return {*this, version}; + return payment_address{*this, version}; } // Operators. diff --git a/src/wallet/encrypted_keys.cpp b/src/wallet/encrypted_keys.cpp index f46cc5241..1878a6450 100644 --- a/src/wallet/encrypted_keys.cpp +++ b/src/wallet/encrypted_keys.cpp @@ -54,13 +54,13 @@ bool address_salt(ek_salt& salt, payment_address const& address) { static bool address_salt(ek_salt& salt, ec_compressed const& point, uint8_t version, bool compressed) { - payment_address address({point, compressed}, version); + payment_address address(ec_public{point, compressed}, version); return address ? address_salt(salt, address) : false; } static bool address_salt(ek_salt& salt, ec_secret const& secret, uint8_t version, bool compressed) { - payment_address address({secret, version, compressed}); + payment_address address(ec_private{secret, version, compressed}); return address ? address_salt(salt, address) : false; } @@ -73,13 +73,13 @@ bool address_validate(const ek_salt& salt, static bool address_validate(const ek_salt& salt, ec_compressed const& point, uint8_t version, bool compressed) { - payment_address address({point, compressed}, version); + payment_address address(ec_public{point, compressed}, version); return address ? address_validate(salt, address) : false; } static bool address_validate(const ek_salt& salt, ec_secret const& secret, uint8_t version, bool compressed) { - payment_address address({secret, version, compressed}); + payment_address address(ec_private{secret, version, compressed}); return address ? address_validate(salt, address) : false; } diff --git a/src/wallet/message.cpp b/src/wallet/message.cpp index 661998e90..d3df81b28 100644 --- a/src/wallet/message.cpp +++ b/src/wallet/message.cpp @@ -129,8 +129,7 @@ bool verify_message(data_slice message, payment_address const& address, message_ short_hash hash; auto const message_digest = hash_message(message); return recover(hash, compressed, compact, recovery_id, message_digest) && - std::equal(hash.begin(), hash.end(), address.hash20().begin()); - // (hash == address.hash20()); + hash == address.hash20(); } } // namespace kth::domain::wallet diff --git a/src/wallet/stealth_receiver.cpp b/src/wallet/stealth_receiver.cpp index 9084bfaf0..265a3cdd8 100644 --- a/src/wallet/stealth_receiver.cpp +++ b/src/wallet/stealth_receiver.cpp @@ -44,7 +44,7 @@ bool stealth_receiver::derive_address(payment_address& out_address, return false; } - out_address = {receiver_public, version_}; + out_address = payment_address{ec_public{receiver_public}, version_}; return true; } diff --git a/src/wallet/stealth_sender.cpp b/src/wallet/stealth_sender.cpp index 303c34747..cf11633fb 100644 --- a/src/wallet/stealth_sender.cpp +++ b/src/wallet/stealth_sender.cpp @@ -60,7 +60,7 @@ void stealth_sender::initialize(ec_secret const& ephemeral_private, } if (create_stealth_script(script_, ephemeral_private, filter, seed)) { - address_ = {sender_public, version_}; + address_ = wallet::payment_address{ec_public{sender_public}, version_}; } } diff --git a/test/math/stealth.cpp b/test/math/stealth.cpp index 6ec82ab88..39e90bbe6 100644 --- a/test/math/stealth.cpp +++ b/test/math/stealth.cpp @@ -74,7 +74,7 @@ TEST_CASE("stealth round trip", "[stealth]") { // Both parties therefore have the ability to generate the p2pkh address. // versioning: stealth_address::main corresponds to payment_address::main_p2pkh - wallet::payment_address address(stealth_public, wallet::payment_address::mainnet_p2kh); + wallet::payment_address address(wallet::ec_public{stealth_public}, wallet::payment_address::mainnet_p2kh); REQUIRE(address.encoded_legacy() == P2PKH_ADDRESS); } diff --git a/test/wallet/message.cpp b/test/wallet/message.cpp index fe9ff5e0f..66fcac1bb 100644 --- a/test/wallet/message.cpp +++ b/test/wallet/message.cpp @@ -114,7 +114,7 @@ TEST_CASE("message magic to recovery id invalid false", "[message recovery m TEST_CASE("message sign message compressed expected", "[message sign message]") { auto const compressed = true; auto const secret = base16_literal(SECRET); - const payment_address address({secret, 0x00, compressed}); + payment_address const address(ec_private{secret, 0x00, compressed}); auto const message = to_chunk(std::string("Compressed")); message_signature out_signature; REQUIRE(sign_message(out_signature, message, secret, compressed)); @@ -124,7 +124,7 @@ TEST_CASE("message sign message compressed expected", "[message sign message TEST_CASE("message sign message uncompressed expected", "[message sign message]") { auto const compressed = false; auto const secret = base16_literal(SECRET); - const payment_address address({secret, 0x00, compressed}); + payment_address const address(ec_private{secret, 0x00, compressed}); auto const message = to_chunk(std::string("Uncompressed")); message_signature out_signature; REQUIRE(sign_message(out_signature, message, secret, compressed)); @@ -133,7 +133,7 @@ TEST_CASE("message sign message uncompressed expected", "[message sign messa TEST_CASE("message sign message secret compressed expected", "[message sign message]") { ec_private secret(WIF_COMPRESSED); - const payment_address address(secret); + payment_address const address(secret); auto const message = to_chunk(std::string("Compressed")); message_signature out_signature; REQUIRE(sign_message(out_signature, message, secret)); @@ -142,7 +142,7 @@ TEST_CASE("message sign message secret compressed expected", "[message sign TEST_CASE("message sign message wif compressed expected", "[message sign message]") { ec_private secret(WIF_COMPRESSED); - const payment_address address(secret); + payment_address const address(secret); auto const message = to_chunk(std::string("Compressed")); message_signature out_signature; REQUIRE(sign_message(out_signature, message, secret, secret.compressed())); @@ -151,7 +151,7 @@ TEST_CASE("message sign message wif compressed expected", "[message sign mes TEST_CASE("message sign message wif uncompressed expected", "[message sign message]") { ec_private secret(WIF_UNCOMPRESSED); - const payment_address address(secret); + payment_address const address(secret); auto const message = to_chunk(std::string("Uncompressed")); message_signature out_signature; REQUIRE(sign_message(out_signature, message, secret, secret.compressed())); @@ -160,54 +160,54 @@ TEST_CASE("message sign message wif uncompressed expected", "[message sign m // End Test Suite -// Start Test Suite: message verify message +// Start Test Suite: message verify message -TEST_CASE("message verify message compressed expected", "[message verify message]") { - const payment_address address(base16_literal(SECRET)); +TEST_CASE("message verify message compressed expected", "[message verify message]") { + payment_address const address(ec_private{base16_literal(SECRET)}); auto const message = to_chunk(std::string("Compressed")); auto const signature = base16_literal(SIGNATURE_COMPRESSED); REQUIRE(verify_message(message, address, signature)); } -TEST_CASE("message verify message uncompressed expected", "[message verify message]") { - const payment_address address({base16_literal(SECRET), 0x00, false}); +TEST_CASE("message verify message uncompressed expected", "[message verify message]") { + payment_address const address(ec_private{base16_literal(SECRET), 0x00, false}); auto const message = to_chunk(std::string("Uncompressed")); auto const signature = base16_literal(SIGNATURE_UNCOMPRESSED); REQUIRE(verify_message(message, address, signature)); } -TEST_CASE("message verify message wif compressed round trip", "[message verify message]") { +TEST_CASE("message verify message wif compressed round trip", "[message verify message]") { ec_private secret(WIF_COMPRESSED); - const payment_address address(secret); + payment_address const address(secret); auto const message = to_chunk(std::string("Compressed")); auto const signature = base16_literal(SIGNATURE_WIF_COMPRESSED); REQUIRE(verify_message(message, address, signature)); } -TEST_CASE("message verify message wif uncompressed round trip", "[message verify message]") { +TEST_CASE("message verify message wif uncompressed round trip", "[message verify message]") { ec_private secret(WIF_UNCOMPRESSED); - const payment_address address(secret); + payment_address const address(secret); auto const message = to_chunk(std::string("Uncompressed")); auto const signature = base16_literal(SIGNATURE_WIF_UNCOMPRESSED); REQUIRE(verify_message(message, address, signature)); } -TEST_CASE("message verify message electrum compressed okay", "[message verify message]") { +TEST_CASE("message verify message electrum compressed okay", "[message verify message]") { message_signature signature; REQUIRE(decode_base16(signature, ELECTRUM_SIGNATURE)); // Address of the compressed public key of the message signer. - const payment_address address("1PeChFbhxDD9NLbU21DfD55aQBC4ZTR3tE"); + payment_address const address("1PeChFbhxDD9NLbU21DfD55aQBC4ZTR3tE"); auto const message = to_chunk(std::string("Nakomoto")); REQUIRE(verify_message(message, address, signature)); } -TEST_CASE("message verify message electrum incorrect address false", "[message verify message]") { +TEST_CASE("message verify message electrum incorrect address false", "[message verify message]") { message_signature signature; REQUIRE(decode_base16(signature, ELECTRUM_SIGNATURE)); // Address of the uncompressed public key of the message signer (incorrect). - const payment_address address("1Em1SX7qQq1pTmByqLRafhL1ypx2V786tP"); + payment_address const address("1Em1SX7qQq1pTmByqLRafhL1ypx2V786tP"); auto const message = to_chunk(std::string("Nakomoto")); REQUIRE( ! verify_message(message, address, signature)); } diff --git a/test/wallet/stealth_receiver.cpp b/test/wallet/stealth_receiver.cpp index c9d47872a..a51af6103 100644 --- a/test/wallet/stealth_receiver.cpp +++ b/test/wallet/stealth_receiver.cpp @@ -69,7 +69,7 @@ TEST_CASE("stealth receiver exchange between sender and receiver always round // The receiver now has the stealth private key and the send address. REQUIRE(encode_base16(receiver_private) == RECEIVER_PRIVATE); - REQUIRE(payment_address(receiver_public, version) == derived_address); + REQUIRE(payment_address(ec_public{receiver_public}, version) == derived_address); } // End Test Suite