Define PAKList structure and operations

This commit is contained in:
Gregory Sanders 2019-01-03 15:49:38 -05:00
parent 40571ab6d4
commit 378e594617
4 changed files with 217 additions and 0 deletions

View file

@ -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 \

View file

@ -10,6 +10,7 @@
#include <utilstrencodings.h>
#include <crypto/common.h>
bool g_con_blockheightinheader = false;
bool g_signed_blocks = false;

144
src/primitives/pak.cpp Normal file
View file

@ -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 <primitives/pak.h>
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<CScript> CPAKList::GenerateCoinbasePAKCommitments() const
{
std::vector<CScript> 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<unsigned char>(pubkey, pubkey+outputlen);
secp256k1_ec_pubkey_serialize(secp256k1_ctx, pubkey, &outputlen, &m_online_keys[i], SECP256K1_EC_COMPRESSED);
assert(outputlen == 33);
scriptCommitment << std::vector<unsigned char>(pubkey, pubkey+outputlen);
commitments.push_back(scriptCommitment);
}
return commitments;
}
std::vector<CScript> CPAKList::GenerateCoinbasePAKReject() const
{
CScript scriptPubKey = CPAKList::Magic();
std::vector<unsigned char> 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<CScript> commitment;
commitment.push_back(scriptPubKey);
return commitment;
}
void CPAKList::CreateCommitments(std::vector<CScript> &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<std::vector<unsigned char> >& offline_keys_bytes, std::vector<std::vector<unsigned char> >& 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<secp256k1_pubkey> offline_keys;
std::vector<secp256k1_pubkey> 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<std::vector<unsigned char> >& offline_keys, std::vector<std::vector<unsigned char> >& 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<unsigned char>(pubkey, pubkey+outputlen));
secp256k1_ec_pubkey_serialize(secp256k1_ctx, pubkey, &outputlen, &m_online_keys[i], SECP256K1_EC_COMPRESSED);
online_keys.push_back(std::vector<unsigned char>(pubkey, pubkey+outputlen));
}
is_reject = reject;
}

70
src/primitives/pak.h Normal file
View file

@ -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 <script/script.h>
#include <secp256k1/include/secp256k1_whitelist.h>
class CPAKList
{
private:
std::vector<secp256k1_pubkey> m_offline_keys;
std::vector<secp256k1_pubkey> m_online_keys;
bool reject;
std::vector<CScript> GenerateCoinbasePAKCommitments() const;
std::vector<CScript> GenerateCoinbasePAKReject() const;
public:
CPAKList()
{
reject = true;
}
/**
* Creates a new CPAKList. Requires that the number of offline keys is the same as the number of online keys
* and that this number is not larger than SECP256K1_WHITELIST_MAX_N_KEYS.
*/
CPAKList(std::vector<secp256k1_pubkey> offline_keys, std::vector<secp256k1_pubkey> online_keys, bool reject) :
m_offline_keys(offline_keys), m_online_keys(online_keys), reject(reject) {
assert(m_offline_keys.size() == m_online_keys.size());
assert(m_offline_keys.size() <= SECP256K1_WHITELIST_MAX_N_KEYS);
}
bool operator==(const CPAKList &other) const;
bool operator!=(const CPAKList &other) const
{
return !(*this == other);
}
bool IsReject() const
{
return reject;
}
bool IsEmpty() const
{
return !reject && this->size() == 0;
}
std::vector<secp256k1_pubkey> OnlineKeys() const
{
return m_online_keys;
}
std::vector<secp256k1_pubkey> OfflineKeys() const
{
return m_offline_keys;
}
size_t size() const
{
return m_offline_keys.size();
}
static CScript Magic();
/** Produce a list of scripts to add to the coinbase to signal changes in PAK list or rejection of any pak proofs to nodes */
void CreateCommitments(std::vector<CScript> &commitments) const;
static bool FromBytes(CPAKList &paklist, std::vector<std::vector<unsigned char> >& offline_keys, std::vector<std::vector<unsigned char> >& online_keys, bool is_reject);
void ToBytes(std::vector<std::vector<unsigned char> >& offline_keys, std::vector<std::vector<unsigned char> >& online_keys, bool &is_reject) const;
};
#endif // BITCOIN_PRIMITIVES_PAK_H