33// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44
55#include < primitives/pak.h>
6+ #include < pubkey.h>
67
78namespace {
89
9- static secp256k1_context *secp256k1_ctx ;
10+ static secp256k1_context *secp256k1_ctx_pak ;
1011
1112class CSecp256k1Init {
1213public:
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};
2021static 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+ }
0 commit comments