Skip to content

Commit 43424cb

Browse files
committed
Add PAK proof validation function
1 parent 378e594 commit 43424cb

File tree

2 files changed

+98
-9
lines changed

2 files changed

+98
-9
lines changed

src/primitives/pak.cpp

Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,19 @@
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

55
#include <primitives/pak.h>
6+
#include <pubkey.h>
67

78
namespace {
89

9-
static secp256k1_context *secp256k1_ctx;
10+
static secp256k1_context *secp256k1_ctx_pak;
1011

1112
class CSecp256k1Init {
1213
public:
1314
CSecp256k1Init() {
14-
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
15+
secp256k1_ctx_pak = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
1516
}
1617
~CSecp256k1Init() {
17-
secp256k1_context_destroy(secp256k1_ctx);
18+
secp256k1_context_destroy(secp256k1_ctx_pak);
1819
}
1920
};
2021
static CSecp256k1Init instance_of_csecp256k1;
@@ -42,10 +43,10 @@ std::vector<CScript> CPAKList::GenerateCoinbasePAKCommitments() const
4243
CScript scriptCommitment(scriptPubKey);
4344
unsigned char pubkey[33];
4445
size_t outputlen = 33;
45-
secp256k1_ec_pubkey_serialize(secp256k1_ctx, pubkey, &outputlen, &m_offline_keys[i], SECP256K1_EC_COMPRESSED);
46+
secp256k1_ec_pubkey_serialize(secp256k1_ctx_pak, pubkey, &outputlen, &m_offline_keys[i], SECP256K1_EC_COMPRESSED);
4647
assert(outputlen == 33);
4748
scriptCommitment << std::vector<unsigned char>(pubkey, pubkey+outputlen);
48-
secp256k1_ec_pubkey_serialize(secp256k1_ctx, pubkey, &outputlen, &m_online_keys[i], SECP256K1_EC_COMPRESSED);
49+
secp256k1_ec_pubkey_serialize(secp256k1_ctx_pak, pubkey, &outputlen, &m_online_keys[i], SECP256K1_EC_COMPRESSED);
4950
assert(outputlen == 33);
5051
scriptCommitment << std::vector<unsigned char>(pubkey, pubkey+outputlen);
5152
commitments.push_back(scriptCommitment);
@@ -111,8 +112,8 @@ bool CPAKList::FromBytes(CPAKList &paklist, std::vector<std::vector<unsigned cha
111112
for (unsigned int i = 0; i < offline_keys_bytes.size(); i++) {
112113
secp256k1_pubkey pubkey1;
113114
secp256k1_pubkey pubkey2;
114-
int ret1 = secp256k1_ec_pubkey_parse(secp256k1_ctx, &pubkey1, &offline_keys_bytes[i][0], offline_keys_bytes[i].size());
115-
int ret2 = secp256k1_ec_pubkey_parse(secp256k1_ctx, &pubkey2, &online_keys_bytes[i][0], online_keys_bytes[i].size());
115+
int ret1 = secp256k1_ec_pubkey_parse(secp256k1_ctx_pak, &pubkey1, &offline_keys_bytes[i][0], offline_keys_bytes[i].size());
116+
int ret2 = secp256k1_ec_pubkey_parse(secp256k1_ctx_pak, &pubkey2, &online_keys_bytes[i][0], online_keys_bytes[i].size());
116117

117118
if (ret1 != 1 || ret2 != 1) {
118119
return false;
@@ -133,12 +134,92 @@ void CPAKList::ToBytes(std::vector<std::vector<unsigned char> >& offline_keys, s
133134
for (unsigned int i = 0; i < m_offline_keys.size(); i++) {
134135
unsigned char pubkey[33];
135136
size_t outputlen = 33;
136-
secp256k1_ec_pubkey_serialize(secp256k1_ctx, pubkey, &outputlen, &m_offline_keys[i], SECP256K1_EC_COMPRESSED);
137+
secp256k1_ec_pubkey_serialize(secp256k1_ctx_pak, pubkey, &outputlen, &m_offline_keys[i], SECP256K1_EC_COMPRESSED);
137138
offline_keys.push_back(std::vector<unsigned char>(pubkey, pubkey+outputlen));
138-
secp256k1_ec_pubkey_serialize(secp256k1_ctx, pubkey, &outputlen, &m_online_keys[i], SECP256K1_EC_COMPRESSED);
139+
secp256k1_ec_pubkey_serialize(secp256k1_ctx_pak, pubkey, &outputlen, &m_online_keys[i], SECP256K1_EC_COMPRESSED);
139140
online_keys.push_back(std::vector<unsigned char>(pubkey, pubkey+outputlen));
140141
}
141142
is_reject = reject;
142143
}
143144

145+
// Proof follows the OP_RETURN <genesis_block_hash> <destination_scriptpubkey>
146+
// in multiple pushes: <full_pubkey> <proof>
147+
bool ScriptHasValidPAKProof(const CScript& script, const uint256& genesis_hash)
148+
{
149+
assert(script.IsPegoutScript(genesis_hash));
150+
151+
CPAKList paklist;
152+
if (g_paklist_config) {
153+
paklist = *g_paklist_config;
154+
} else {
155+
paklist = g_paklist_blockchain;
156+
}
144157

158+
if (paklist.IsReject() || paklist.IsEmpty()) {
159+
return false;
160+
}
161+
162+
CScript::const_iterator pc = script.begin();
163+
std::vector<unsigned char> data;
164+
opcodetype opcode;
165+
166+
script.GetOp(pc, opcode, data);
167+
script.GetOp(pc, opcode, data);
168+
script.GetOp(pc, opcode, data);
169+
170+
CScript destination(data.begin(), data.end());
171+
172+
// Only accept p2pkh
173+
if (!destination.IsPayToPubkeyHash()) {
174+
return false;
175+
}
176+
177+
// Grab pubkey hash within the extracted sub-script
178+
CScript::const_iterator pc2 = destination.begin();
179+
std::vector<unsigned char> data2;
180+
opcodetype opcode2;
181+
if (!destination.GetOp(pc2, opcode2, data2) || !destination.GetOp(pc2, opcode2, data2) ||!destination.GetOp(pc2, opcode2, data2)) {
182+
return false;
183+
}
184+
185+
// Follow-up with full pubkey
186+
if (!script.GetOp(pc, opcode, data) || opcode != 33 || data.size() != 33) {
187+
return false;
188+
}
189+
190+
CPubKey cpubkey(data.begin(), data.end());
191+
//Ensure the chaindest p2pkh matches the included pubkey
192+
if (cpubkey.GetID() != uint160(data2)) {
193+
return false;
194+
}
195+
196+
// Parse pubkey
197+
secp256k1_pubkey pubkey;
198+
if (secp256k1_ec_pubkey_parse(secp256k1_ctx_pak, &pubkey, &data[0], data.size()) != 1) {
199+
return false;
200+
}
201+
202+
if (!script.GetOp(pc, opcode, data) || opcode > OP_PUSHDATA4 || data.size() == 0) {
203+
return false;
204+
}
205+
206+
// Parse whitelist proof
207+
secp256k1_whitelist_signature sig;
208+
if (secp256k1_whitelist_signature_parse(secp256k1_ctx_pak, &sig, &data[0], data.size()) != 1)
209+
return false;
210+
211+
if (secp256k1_whitelist_signature_n_keys(&sig) != paklist.size()) {
212+
return false;
213+
}
214+
215+
if (secp256k1_whitelist_verify(secp256k1_ctx_pak, &sig, &paklist.OnlineKeys()[0], &paklist.OfflineKeys()[0], paklist.size(), &pubkey) != 1) {
216+
return false;
217+
}
218+
219+
//No more pushes allowed
220+
if (script.GetOp(pc, opcode, data)) {
221+
return false;
222+
}
223+
224+
return true;
225+
}

src/primitives/pak.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,12 @@ class CPAKList
6767
void ToBytes(std::vector<std::vector<unsigned char> >& offline_keys, std::vector<std::vector<unsigned char> >& online_keys, bool &is_reject) const;
6868
};
6969

70+
/**
71+
** Returns true if the script includes valid pegout proof
72+
** given the PAK list loaded. Two pushes after regular pegout script:
73+
** <full_pubkey> <proof>
74+
**/
75+
bool ScriptHasValidPAKProof(const CScript& script, const uint256& genesis_hash);
76+
77+
7078
#endif // BITCOIN_PRIMITIVES_PAK_H

0 commit comments

Comments
 (0)