diff --git a/src/Makefile.am b/src/Makefile.am index d23081c76c..75388fe57b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -361,6 +361,8 @@ libbitcoin_consensus_a_SOURCES = \ primitives/block.h \ primitives/transaction.cpp \ primitives/transaction.h \ + primitives/pak.cpp \ + primitives/pak.h \ primitives/bitcoin/block.cpp \ primitives/bitcoin/block.h \ primitives/bitcoin/merkleblock.cpp \ diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 42e7e3f6eb..d0b15ea275 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -10,6 +10,7 @@ #include #include + bool g_con_blockheightinheader = false; bool g_signed_blocks = false; diff --git a/src/primitives/pak.cpp b/src/primitives/pak.cpp new file mode 100644 index 0000000000..665bcc1478 --- /dev/null +++ b/src/primitives/pak.cpp @@ -0,0 +1,144 @@ +// Copyright (c) 2018-2018 The Elements developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +namespace { + +static secp256k1_context *secp256k1_ctx; + +class CSecp256k1Init { +public: + CSecp256k1Init() { + secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + } + ~CSecp256k1Init() { + secp256k1_context_destroy(secp256k1_ctx); + } +}; +static CSecp256k1Init instance_of_csecp256k1; +} + +CScript CPAKList::Magic() +{ + CScript scriptPubKey; + scriptPubKey.resize(6); + scriptPubKey[0] = OP_RETURN; + scriptPubKey[1] = 0x04; + scriptPubKey[2] = 0xab; + scriptPubKey[3] = 0x22; + scriptPubKey[4] = 0xaa; + scriptPubKey[5] = 0xee; + return scriptPubKey; +} + +std::vector CPAKList::GenerateCoinbasePAKCommitments() const +{ + std::vector commitments; + CScript scriptPubKey = CPAKList::Magic(); + + for (unsigned int i = 0; i < m_offline_keys.size(); i++) { + CScript scriptCommitment(scriptPubKey); + unsigned char pubkey[33]; + size_t outputlen = 33; + secp256k1_ec_pubkey_serialize(secp256k1_ctx, pubkey, &outputlen, &m_offline_keys[i], SECP256K1_EC_COMPRESSED); + assert(outputlen == 33); + scriptCommitment << std::vector(pubkey, pubkey+outputlen); + secp256k1_ec_pubkey_serialize(secp256k1_ctx, pubkey, &outputlen, &m_online_keys[i], SECP256K1_EC_COMPRESSED); + assert(outputlen == 33); + scriptCommitment << std::vector(pubkey, pubkey+outputlen); + commitments.push_back(scriptCommitment); + } + + return commitments; +} + +std::vector CPAKList::GenerateCoinbasePAKReject() const +{ + CScript scriptPubKey = CPAKList::Magic(); + + std::vector reject; + reject.push_back('R'); + reject.push_back('E'); + reject.push_back('J'); + reject.push_back('E'); + reject.push_back('C'); + reject.push_back('T'); + + scriptPubKey << reject; + + std::vector commitment; + commitment.push_back(scriptPubKey); + return commitment; +} + +void CPAKList::CreateCommitments(std::vector &commitments) const +{ + if(reject) { + commitments = GenerateCoinbasePAKReject(); + } else { + commitments = GenerateCoinbasePAKCommitments(); + } +} + +bool CPAKList::operator==(const CPAKList &other) const +{ + if (this->reject != other.reject) { + return false; + } else if (this->m_offline_keys.size() != other.m_offline_keys.size()) { + return false; + } else { + for (unsigned int i = 0; i < this->m_offline_keys.size(); i++) { + if (memcmp(&this->m_offline_keys[i], &other.m_offline_keys[i], sizeof(secp256k1_pubkey)) != 0 || + memcmp(&this->m_online_keys[i], &other.m_online_keys[i], sizeof(secp256k1_pubkey)) != 0) { + return false; + } + } + } + return true; +} + +bool CPAKList::FromBytes(CPAKList &paklist, std::vector >& offline_keys_bytes, std::vector >& online_keys_bytes, bool is_reject) +{ + if(offline_keys_bytes.size() != online_keys_bytes.size() + || offline_keys_bytes.size() > SECP256K1_WHITELIST_MAX_N_KEYS) { + return false; + } + + std::vector offline_keys; + std::vector online_keys; + for (unsigned int i = 0; i < offline_keys_bytes.size(); i++) { + secp256k1_pubkey pubkey1; + secp256k1_pubkey pubkey2; + int ret1 = secp256k1_ec_pubkey_parse(secp256k1_ctx, &pubkey1, &offline_keys_bytes[i][0], offline_keys_bytes[i].size()); + int ret2 = secp256k1_ec_pubkey_parse(secp256k1_ctx, &pubkey2, &online_keys_bytes[i][0], online_keys_bytes[i].size()); + + if (ret1 != 1 || ret2 != 1) { + return false; + } + offline_keys.push_back(pubkey1); + online_keys.push_back(pubkey2); + } + + paklist = CPAKList(offline_keys, online_keys, is_reject); + return true; +} + +void CPAKList::ToBytes(std::vector >& offline_keys, std::vector >& online_keys, bool &is_reject) const +{ + offline_keys.resize(0); + online_keys.resize(0); + + for (unsigned int i = 0; i < m_offline_keys.size(); i++) { + unsigned char pubkey[33]; + size_t outputlen = 33; + secp256k1_ec_pubkey_serialize(secp256k1_ctx, pubkey, &outputlen, &m_offline_keys[i], SECP256K1_EC_COMPRESSED); + offline_keys.push_back(std::vector(pubkey, pubkey+outputlen)); + secp256k1_ec_pubkey_serialize(secp256k1_ctx, pubkey, &outputlen, &m_online_keys[i], SECP256K1_EC_COMPRESSED); + online_keys.push_back(std::vector(pubkey, pubkey+outputlen)); + } + is_reject = reject; +} + + diff --git a/src/primitives/pak.h b/src/primitives/pak.h new file mode 100644 index 0000000000..11cf1a8757 --- /dev/null +++ b/src/primitives/pak.h @@ -0,0 +1,70 @@ +// Copyright (c) 2018-2018 The Elements developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_PRIMITIVES_PAK_H +#define BITCOIN_PRIMITIVES_PAK_H + +#include