add secp256k1 condition type to cryptoconditions
This commit is contained in:
2
.gitmodules
vendored
2
.gitmodules
vendored
@@ -1,4 +1,4 @@
|
|||||||
[submodule "cryptoconditions"]
|
[submodule "cryptoconditions"]
|
||||||
path = src/cryptoconditions
|
path = src/cryptoconditions
|
||||||
url = https://github.com/libscott/libcryptoconditions.git
|
url = https://github.com/libscott/libcryptoconditions.git
|
||||||
branch = komodo-integration
|
branch = komodo
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import struct
|
|||||||
from testsupport import *
|
from testsupport import *
|
||||||
|
|
||||||
|
|
||||||
|
SCRIPT_FALSE = 'Script evaluated without error but finished with a false/empty top stack element'
|
||||||
|
|
||||||
|
|
||||||
@fanout_input(0)
|
@fanout_input(0)
|
||||||
def test_basic_spend(inp):
|
def test_basic_spend(inp):
|
||||||
spend = {'inputs': [inp], "outputs": [nospend]}
|
spend = {'inputs': [inp], "outputs": [nospend]}
|
||||||
@@ -27,7 +30,7 @@ def test_fulfillment_wrong_signature(inp):
|
|||||||
try:
|
try:
|
||||||
assert not submit(signed), 'should raise an error'
|
assert not submit(signed), 'should raise an error'
|
||||||
except RPCError as e:
|
except RPCError as e:
|
||||||
assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e)
|
assert SCRIPT_FALSE in str(e), str(e)
|
||||||
|
|
||||||
|
|
||||||
@fanout_input(2)
|
@fanout_input(2)
|
||||||
@@ -41,7 +44,7 @@ def test_fulfillment_wrong_pubkey(inp):
|
|||||||
try:
|
try:
|
||||||
assert not submit(signed), 'should raise an error'
|
assert not submit(signed), 'should raise an error'
|
||||||
except RPCError as e:
|
except RPCError as e:
|
||||||
assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e)
|
assert SCRIPT_FALSE in str(e), str(e)
|
||||||
|
|
||||||
|
|
||||||
@fanout_input(3)
|
@fanout_input(3)
|
||||||
@@ -71,7 +74,7 @@ def test_invalid_condition(inp):
|
|||||||
try:
|
try:
|
||||||
assert not submit(sign(spend1)), 'should raise an error'
|
assert not submit(sign(spend1)), 'should raise an error'
|
||||||
except RPCError as e:
|
except RPCError as e:
|
||||||
assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e)
|
assert SCRIPT_FALSE in str(e), str(e)
|
||||||
|
|
||||||
|
|
||||||
@fanout_input(5)
|
@fanout_input(5)
|
||||||
@@ -124,7 +127,7 @@ def test_aux_basic(inp):
|
|||||||
try:
|
try:
|
||||||
assert not submit(sign(spend2)), 'should raise an error'
|
assert not submit(sign(spend2)), 'should raise an error'
|
||||||
except RPCError as e:
|
except RPCError as e:
|
||||||
assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e)
|
assert SCRIPT_FALSE in str(e), str(e)
|
||||||
|
|
||||||
|
|
||||||
@fanout_input(7)
|
@fanout_input(7)
|
||||||
@@ -168,7 +171,47 @@ def test_aux_complex(inp):
|
|||||||
try:
|
try:
|
||||||
assert not submit(sign(spend2)), 'should raise an error'
|
assert not submit(sign(spend2)), 'should raise an error'
|
||||||
except RPCError as e:
|
except RPCError as e:
|
||||||
assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e)
|
assert SCRIPT_FALSE in str(e), str(e)
|
||||||
|
|
||||||
|
|
||||||
|
@fanout_input(8)
|
||||||
|
def test_secp256k1_condition(inp):
|
||||||
|
ec_cond = {
|
||||||
|
'type': 'secp256k1-sha-256',
|
||||||
|
'publicKey': notary_pk
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create some secp256k1 outputs
|
||||||
|
spend0 = {
|
||||||
|
'inputs': [inp],
|
||||||
|
'outputs': [
|
||||||
|
{'amount': 500, 'script': {'condition': ec_cond}},
|
||||||
|
{'amount': 500, 'script': {'condition': ec_cond}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
spend0_txid = submit(sign(spend0))
|
||||||
|
assert rpc.getrawtransaction(spend0_txid)
|
||||||
|
|
||||||
|
# Test a good fulfillment
|
||||||
|
spend1 = {
|
||||||
|
'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': ec_cond}}],
|
||||||
|
'outputs': [{'amount': 500, 'script': {'condition': ec_cond}}]
|
||||||
|
}
|
||||||
|
spend1_txid = submit(sign(spend1))
|
||||||
|
assert rpc.getrawtransaction(spend1_txid)
|
||||||
|
|
||||||
|
# Test a bad fulfillment
|
||||||
|
spend2 = {
|
||||||
|
'inputs': [{'txid': spend0_txid, 'idx': 1, 'script': {'fulfillment': ec_cond}}],
|
||||||
|
'outputs': [{'amount': 500, 'script': {'condition': ec_cond}}]
|
||||||
|
}
|
||||||
|
signed = sign(spend2)
|
||||||
|
signed['tx']['inputs'][0]['script']['fulfillment']['publicKey'] = \
|
||||||
|
'0275cef12fc5c49be64f5aab3d1fbba08cd7b0d02908b5112fbd8504218d14bc7d'
|
||||||
|
try:
|
||||||
|
assert not submit(signed), 'should raise an error'
|
||||||
|
except RPCError as e:
|
||||||
|
assert SCRIPT_FALSE in str(e), str(e)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -74,7 +74,8 @@ def wait_for_block(height):
|
|||||||
|
|
||||||
def sign(tx):
|
def sign(tx):
|
||||||
signed = hoek.signTxBitcoin({'tx': tx, 'privateKeys': [notary_sk]})
|
signed = hoek.signTxBitcoin({'tx': tx, 'privateKeys': [notary_sk]})
|
||||||
return hoek.signTxEd25519({'tx': signed['tx'], 'privateKeys': [alice_sk, bob_sk]})
|
signed = hoek.signTxEd25519({'tx': signed['tx'], 'privateKeys': [alice_sk, bob_sk]})
|
||||||
|
return hoek.signTxSecp256k1({'tx': signed['tx'], 'privateKeys': [notary_sk]})
|
||||||
|
|
||||||
|
|
||||||
def submit(tx):
|
def submit(tx):
|
||||||
@@ -96,14 +97,14 @@ def get_fanout_txid():
|
|||||||
reward_tx = hoek.decodeTx({'hex': reward_tx_raw})
|
reward_tx = hoek.decodeTx({'hex': reward_tx_raw})
|
||||||
balance = reward_tx['tx']['outputs'][0]['amount']
|
balance = reward_tx['tx']['outputs'][0]['amount']
|
||||||
|
|
||||||
n_outs = 100
|
n_outs = 16
|
||||||
remainder = balance - n_outs * 1000
|
remainder = balance - n_outs * 1000
|
||||||
|
|
||||||
fanout = {
|
fanout = {
|
||||||
'inputs': [
|
'inputs': [
|
||||||
{'txid': reward_txid, 'idx': 0, 'script': {'pubkey': notary_pk}}
|
{'txid': reward_txid, 'idx': 0, 'script': {'pubkey': notary_pk}}
|
||||||
],
|
],
|
||||||
"outputs": (100 * [
|
"outputs": (n_outs * [
|
||||||
{"amount": 1000, "script": {"condition": cond_alice}}
|
{"amount": 1000, "script": {"condition": cond_alice}}
|
||||||
] + [{"amount": remainder, 'script': {'address': notary_addr}}])
|
] + [{"amount": remainder, 'script': {'address': notary_addr}}])
|
||||||
}
|
}
|
||||||
@@ -122,6 +123,21 @@ def fanout_input(n):
|
|||||||
return decorate
|
return decorate
|
||||||
|
|
||||||
|
|
||||||
|
def decode_base64(data):
|
||||||
|
"""Decode base64, padding being optional.
|
||||||
|
|
||||||
|
:param data: Base64 data as an ASCII byte string
|
||||||
|
:returns: The decoded byte string.
|
||||||
|
"""
|
||||||
|
missing_padding = len(data) % 4
|
||||||
|
if missing_padding:
|
||||||
|
data += '=' * (4 - missing_padding)
|
||||||
|
return base64.urlsafe_b64decode(data)
|
||||||
|
|
||||||
|
|
||||||
|
def encode_base64(data):
|
||||||
|
return base64.urlsafe_b64encode(data).rstrip(b'=')
|
||||||
|
|
||||||
|
|
||||||
notary_addr = 'RXSwmXKtDURwXP7sdqNfsJ6Ga8RaxTchxE'
|
notary_addr = 'RXSwmXKtDURwXP7sdqNfsJ6Ga8RaxTchxE'
|
||||||
notary_pk = '0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47'
|
notary_pk = '0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47'
|
||||||
|
|||||||
Submodule src/cryptoconditions updated: 0dcac79cf9...863d926614
@@ -3,8 +3,8 @@
|
|||||||
#include "script/interpreter.h"
|
#include "script/interpreter.h"
|
||||||
|
|
||||||
|
|
||||||
int TransactionSignatureChecker::CheckAuxCondition(const CC *cond) const {
|
int TransactionSignatureChecker::CheckAuxCondition(const CC *cond) const
|
||||||
|
{
|
||||||
// Check that condition is equal to fulfillment
|
// Check that condition is equal to fulfillment
|
||||||
if (0 == strcmp((const char*)cond->method, "equals")) {
|
if (0 == strcmp((const char*)cond->method, "equals")) {
|
||||||
return (cond->conditionAuxLength == cond->fulfillmentAuxLength) &&
|
return (cond->conditionAuxLength == cond->fulfillmentAuxLength) &&
|
||||||
|
|||||||
@@ -1164,7 +1164,7 @@ static int komodoCCAux(CC *cond, void *checker) {
|
|||||||
bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std::vector<unsigned char>& condBin, const CScript& scriptCode) const
|
bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std::vector<unsigned char>& condBin, const CScript& scriptCode) const
|
||||||
{
|
{
|
||||||
uint256 message = SignatureHash(scriptCode, *txTo, nIn, SIGHASH_ALL);
|
uint256 message = SignatureHash(scriptCode, *txTo, nIn, SIGHASH_ALL);
|
||||||
return cc_verify(cond, (const unsigned char*)&message, 32,
|
return cc_verify(cond, (const unsigned char*)&message, 32, 0,
|
||||||
condBin.data(), condBin.size(), komodoCCAux, (void*)this);
|
condBin.data(), condBin.size(), komodoCCAux, (void*)this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,12 +47,20 @@ static const secp256k1_fe_t secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_C
|
|||||||
);
|
);
|
||||||
|
|
||||||
static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) {
|
static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) {
|
||||||
|
|
||||||
|
/* libscott had to add this to get this version of the library to read compact sigs */
|
||||||
|
int overflow = 0;
|
||||||
|
if (size == 64) {
|
||||||
|
secp256k1_scalar_set_b32(&r->r, sig, &overflow);
|
||||||
|
secp256k1_scalar_set_b32(&r->s, sig+32, &overflow);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char ra[32] = {0}, sa[32] = {0};
|
unsigned char ra[32] = {0}, sa[32] = {0};
|
||||||
const unsigned char *rp;
|
const unsigned char *rp;
|
||||||
const unsigned char *sp;
|
const unsigned char *sp;
|
||||||
int lenr;
|
int lenr;
|
||||||
int lens;
|
int lens;
|
||||||
int overflow;
|
|
||||||
if (sig[0] != 0x30) {
|
if (sig[0] != 0x30) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user