no more cryptoconditions submodule
This commit is contained in:
0
src/cryptoconditions/tests/__init__.py
Normal file
0
src/cryptoconditions/tests/__init__.py
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"json": {
|
||||
"type": "eval-sha-256",
|
||||
"method": "testEval",
|
||||
"params": "dGVzdEV2YWw"
|
||||
},
|
||||
"cost": 131072,
|
||||
"subtypes": [],
|
||||
"fingerprintContents": "",
|
||||
"fulfillment": "AF148008746573744576616C8108746573744576616C",
|
||||
"conditionBinary": "AF27802062CC11575F91E1611379B5A0B53678805FC03858544FC28E72BB66A14629C08F8103100000",
|
||||
"conditionUri": "ni:///sha-256;YswRV1-R4WETebWgtTZ4gF_AOFhUT8KOcrtmoUYpwI8?fpt=eval-sha-256&cost=1048576",
|
||||
"message": ""
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"json": {
|
||||
"type": "secp256k1-sha-256",
|
||||
"publicKey": "AtXZaTBVNawpp3B5wR1PDdQGYc-W4E6XSl6NfjdO4iWq",
|
||||
"signature": "nC1v8580C7r2XohL3_rnQ2p7dWiDnFuhF_poGCRfudo83sfP1NPfcZG9siY4_Ybz2aO4yyV_z5tU0JMcTQGV0w"
|
||||
},
|
||||
"cost": 131072,
|
||||
"subtypes": [],
|
||||
"fingerprintContents": "",
|
||||
"fulfillment": "A565802102D5D969305535AC29A77079C11D4F0DD40661CF96E04E974A5E8D7E374EE225AA81409C2D6FF39F340BBAF65E884BDFFAE7436A7B7568839C5BA117FA6818245FB9DA3CDEC7CFD4D3DF7191BDB22638FD86F3D9A3B8CB257FCF9B54D0931C4D0195D3",
|
||||
"conditionBinary": "A52780209C2850F5147E9903DD317C650AC1D6E80E695280789887F2E3179E5C65C9DF3A8103020000",
|
||||
"conditionUri": "ni:///sha-256;nChQ9RR-mQPdMXxlCsHW6A5pUoB4mIfy4xeeXGXJ3zo?fpt=secp256k1-sha-256&cost=131072",
|
||||
"message": ""
|
||||
}
|
||||
73
src/cryptoconditions/tests/test_ed25519.py
Normal file
73
src/cryptoconditions/tests/test_ed25519.py
Normal file
@@ -0,0 +1,73 @@
|
||||
import json
|
||||
import base64
|
||||
from test_vectors import jsonRPC
|
||||
|
||||
|
||||
def test_sign_ed25519_pass_simple():
|
||||
res = jsonRPC('signTreeEd25519', {
|
||||
'condition': {
|
||||
'type': 'ed25519-sha-256',
|
||||
'publicKey': "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k",
|
||||
},
|
||||
'privateKey': '11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo',
|
||||
'message': '',
|
||||
})
|
||||
|
||||
assert res == {
|
||||
"num_signed": 1,
|
||||
"condition": {
|
||||
"type": "ed25519-sha-256",
|
||||
"publicKey": "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k",
|
||||
"signature": "jcuovSRpHwqiC781KzSM1Jd0Qtyfge0cMGttUdLOVdjJlSBFLTtgpinASOaJpd-VGjhSGWkp1hPWuMAAZq6pAg"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def test_sign_ed25519_pass_prefix():
|
||||
res = jsonRPC('signTreeEd25519', {
|
||||
'condition': {
|
||||
'type': 'prefix-sha-256',
|
||||
'prefix': 'YmJi',
|
||||
'maxMessageLength': 3,
|
||||
'subfulfillment': {
|
||||
'type': 'ed25519-sha-256',
|
||||
'publicKey': "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k",
|
||||
}
|
||||
},
|
||||
'privateKey': '11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo',
|
||||
'message': '',
|
||||
})
|
||||
|
||||
assert res == {
|
||||
"num_signed": 1,
|
||||
'condition': {
|
||||
'type': 'prefix-sha-256',
|
||||
'prefix': 'YmJi',
|
||||
'maxMessageLength': 3,
|
||||
'subfulfillment': {
|
||||
'type': 'ed25519-sha-256',
|
||||
'publicKey': "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k",
|
||||
'signature': '4Y6keUFEl4KgIum9e3MBdlhlp32FRas-1N1vhtdy5q3JEPdqMvmXo2Rb99fC6j_3vflh8_QtOEW5rj4utjMOBg',
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_sign_ed25519_fail():
|
||||
# privateKey doesnt match publicKey
|
||||
res = jsonRPC('signTreeEd25519', {
|
||||
'condition': {
|
||||
'type': 'ed25519-sha-256',
|
||||
'publicKey': "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k",
|
||||
},
|
||||
'privateKey': '22qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo',
|
||||
'message': '',
|
||||
})
|
||||
|
||||
assert res == {
|
||||
"num_signed": 0,
|
||||
"condition": {
|
||||
"type": "ed25519-sha-256",
|
||||
"publicKey": "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k",
|
||||
}
|
||||
}
|
||||
63
src/cryptoconditions/tests/test_failure_modes.py
Normal file
63
src/cryptoconditions/tests/test_failure_modes.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import json
|
||||
import ctypes
|
||||
import base64
|
||||
from test_vectors import jsonRPC, so, decode_base64 as d64
|
||||
|
||||
|
||||
'''
|
||||
These tests are aimed at edge cases of serverside deployment.
|
||||
|
||||
As such, the main functions to test are decoding and verifying fulfillment payloads.
|
||||
'''
|
||||
|
||||
|
||||
cc_rfb = lambda f: so.cc_readFulfillmentBinary(f, len(f))
|
||||
cc_rcb = lambda f: so.cc_readConditionBinary(f, len(f))
|
||||
|
||||
unhex = lambda s: base64.b16decode(s.upper())
|
||||
|
||||
|
||||
def test_decode_valid_fulfillment():
|
||||
f = unhex('a42480206ee12ed43d7dce6fc0b2be20e6808380baafc03d400404bbf95165d7527b373a8100')
|
||||
assert cc_rfb(f)
|
||||
|
||||
|
||||
def test_decode_invalid_fulfillment():
|
||||
# This fulfillment payload has an invalid type ID but is otherwise valid
|
||||
invalid_type_id = unhex('bf632480206ee12ed43d7dce6fc0b2be20e6808380baafc03d400404bbf95165d7527b373a8100')
|
||||
assert cc_rfb(invalid_type_id) == 0
|
||||
assert cc_rfb('\0') == 0
|
||||
assert cc_rfb('') == 0
|
||||
|
||||
|
||||
def test_large_fulfillment():
|
||||
# This payload is valid and very large
|
||||
f = unhex("a1839896b28083989680") + 10000000 * b'e' + \
|
||||
unhex("81030186a0a226a42480206ee12ed43d7dce6fc0b2be20e68083"
|
||||
"80baafc03d400404bbf95165d7527b373a8100")
|
||||
cond = cc_rfb(f)
|
||||
buflen = len(f) + 1000 # Wiggle room
|
||||
buf = ctypes.create_string_buffer(buflen)
|
||||
assert so.cc_fulfillmentBinary(cond, buf, buflen)
|
||||
so.cc_free(cond)
|
||||
|
||||
|
||||
def test_decode_valid_condition():
|
||||
# Valid preimage
|
||||
assert cc_rcb(d64('oCWAIMqXgRLKG73K-sIxs5oj3E2nhu_4FHxOcrmAd4Wv7ki7gQEB'))
|
||||
|
||||
# Somewhat bogus condition (prefix with no subtypes) but nonetheless valid structure
|
||||
assert cc_rcb(unhex("a10a8001618101ff82020700"))
|
||||
|
||||
|
||||
def test_decode_invalid_condition():
|
||||
assert 0 == cc_rcb("")
|
||||
assert 0 == cc_rcb("\0")
|
||||
|
||||
# Bogus type ID
|
||||
assert 0 == cc_rcb(unhex('bf630c80016181030186a082020700'))
|
||||
|
||||
|
||||
def test_validate_empty_sigs():
|
||||
#// TODO: test failure mode: empty sig / null pointer
|
||||
pass
|
||||
62
src/cryptoconditions/tests/test_secp256k1.py
Normal file
62
src/cryptoconditions/tests/test_secp256k1.py
Normal file
@@ -0,0 +1,62 @@
|
||||
import json
|
||||
import base64
|
||||
import hashlib
|
||||
import secp256k1
|
||||
from test_vectors import jsonRPC, encode_base64, decode_base64
|
||||
|
||||
|
||||
key = secp256k1.PrivateKey()
|
||||
|
||||
|
||||
def test_sign_secp256k1_pass_simple():
|
||||
pubkey = encode_base64(key.pubkey.serialize())
|
||||
msg = ''
|
||||
res = jsonRPC('signTreeSecp256k1', {
|
||||
'condition': {
|
||||
'type': 'secp256k1-sha-256',
|
||||
'publicKey': pubkey,
|
||||
},
|
||||
'privateKey': encode_base64(key.private_key),
|
||||
'message': msg,
|
||||
})
|
||||
|
||||
sig = encode_base64(key.ecdsa_serialize_compact(key.ecdsa_sign(msg)))
|
||||
|
||||
assert res == {
|
||||
"num_signed": 1,
|
||||
"condition": {
|
||||
"type": "secp256k1-sha-256",
|
||||
"publicKey": pubkey,
|
||||
"signature": sig
|
||||
}
|
||||
}
|
||||
cond_bin = jsonRPC('encodeCondition', res['condition'])['bin']
|
||||
ffill_bin = jsonRPC('encodeFulfillment', res['condition'])['fulfillment']
|
||||
assert jsonRPC('verifyFulfillment', {
|
||||
'fulfillment': ffill_bin,
|
||||
'message': msg,
|
||||
'condition': cond_bin
|
||||
}) == {'valid': True}
|
||||
|
||||
|
||||
|
||||
def test_sign_secp256k1_fail():
|
||||
# privateKey doesnt match publicKey
|
||||
pubkey = encode_base64(key.pubkey.serialize())
|
||||
msg = ''
|
||||
res = jsonRPC('signTreeSecp256k1', {
|
||||
'condition': {
|
||||
'type': 'secp256k1-sha-256',
|
||||
'publicKey': pubkey,
|
||||
},
|
||||
'privateKey': encode_base64('0' * 32),
|
||||
'message': msg,
|
||||
})
|
||||
|
||||
assert res == {
|
||||
"num_signed": 0,
|
||||
"condition": {
|
||||
"type": "secp256k1-sha-256",
|
||||
"publicKey": pubkey,
|
||||
}
|
||||
}
|
||||
149
src/cryptoconditions/tests/test_vectors.py
Normal file
149
src/cryptoconditions/tests/test_vectors.py
Normal file
@@ -0,0 +1,149 @@
|
||||
import json
|
||||
import ctypes
|
||||
import base64
|
||||
import pytest
|
||||
import os.path
|
||||
from ctypes import *
|
||||
|
||||
|
||||
v0000 = '0000_test-minimal-preimage'
|
||||
v0001 = '0001_test-minimal-prefix'
|
||||
v0002 = '0002_test-minimal-threshold'
|
||||
v0003 = '0003_test-minimal-rsa'
|
||||
v0004 = '0004_test-minimal-ed25519'
|
||||
v0005 = '0005_test-basic-preimage'
|
||||
v0006 = '0006_test-basic-prefix'
|
||||
v0007 = '0007_test-basic-prefix-two-levels-deep'
|
||||
v0010 = '0010_test-basic-threshold-same-fulfillment-twice'
|
||||
v0015 = '0015_test-basic-ed25519'
|
||||
v0016 = '0016_test-advanced-notarized-receipt'
|
||||
v0017 = '0017_test-advanced-notarized-receipt-multiple-notaries'
|
||||
|
||||
# These contain RSA conditions which are not implemented yet
|
||||
#v0008 = '0008_test-basic-threshold'
|
||||
#v0009 = '0009_test-basic-threshold-same-condition-twice'
|
||||
#v0011 = '0011_test-basic-threshold-two-levels-deep'
|
||||
#v0012 = '0012_test-basic-threshold-schroedinger'
|
||||
#v0013 = '0013_test-basic-rsa'
|
||||
#v0014 = '0014_test-basic-rsa4096'
|
||||
|
||||
# Custom test vectors
|
||||
v1000 = '1000_test-minimal-eval'
|
||||
v1001 = '1001_test-minimal-secp256k1'
|
||||
|
||||
|
||||
all_vectors = {v0000, v0001, v0002, v0004, v0005, v0006, v0007, v0010,
|
||||
v0015, v0016, v0017, v1000, v1001}
|
||||
|
||||
|
||||
@pytest.mark.parametrize('vectors_file', all_vectors)
|
||||
def test_encodeCondition(vectors_file):
|
||||
vectors = _read_vectors(vectors_file)
|
||||
response = jsonRPC('encodeCondition', vectors['json'])
|
||||
assert response == {
|
||||
'uri': vectors['conditionUri'],
|
||||
'bin': vectors['conditionBinary'],
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize('vectors_file', all_vectors)
|
||||
def test_encodeFulfillment(vectors_file):
|
||||
vectors = _read_vectors(vectors_file)
|
||||
response = jsonRPC('encodeFulfillment', vectors['json'])
|
||||
assert response == {
|
||||
'fulfillment': vectors['fulfillment'],
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize('vectors_file', all_vectors)
|
||||
def test_verifyFulfillment(vectors_file):
|
||||
vectors = _read_vectors(vectors_file)
|
||||
req = {
|
||||
'fulfillment': vectors['fulfillment'],
|
||||
'message': vectors['message'],
|
||||
'condition': vectors['conditionBinary'],
|
||||
}
|
||||
assert jsonRPC('verifyFulfillment', req) == {'valid': True}
|
||||
|
||||
|
||||
@pytest.mark.parametrize('vectors_file', all_vectors)
|
||||
def test_decodeFulfillment(vectors_file):
|
||||
vectors = _read_vectors(vectors_file)
|
||||
response = jsonRPC('decodeFulfillment', {
|
||||
'fulfillment': vectors['fulfillment'],
|
||||
})
|
||||
assert response == {
|
||||
'uri': vectors['conditionUri'],
|
||||
'bin': vectors['conditionBinary'],
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize('vectors_file', all_vectors)
|
||||
def test_decodeCondition(vectors_file):
|
||||
vectors = _read_vectors(vectors_file)
|
||||
response = jsonRPC('decodeCondition', {
|
||||
'bin': vectors['conditionBinary'],
|
||||
})
|
||||
assert response['uri'] == vectors['conditionUri']
|
||||
|
||||
|
||||
@pytest.mark.parametrize('vectors_file', all_vectors)
|
||||
def test_json_condition_json_parse(vectors_file):
|
||||
vectors = _read_vectors(vectors_file)
|
||||
err = ctypes.create_string_buffer(100)
|
||||
cc = so.cc_conditionFromJSONString(json.dumps(vectors['json']).encode(), err)
|
||||
out_ptr = so.cc_conditionToJSONString(cc)
|
||||
out = ctypes.cast(out_ptr, c_char_p).value.decode()
|
||||
assert json.loads(out) == vectors['json']
|
||||
|
||||
|
||||
def b16_to_b64(b16):
|
||||
return base64.urlsafe_b64encode(base64.b16decode(b16)).rstrip('=')
|
||||
|
||||
|
||||
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'=')
|
||||
|
||||
|
||||
def b16_to_b64(b16):
|
||||
return encode_base64(base64.b16decode(b16)).decode()
|
||||
|
||||
|
||||
def _read_vectors(name):
|
||||
paths = ['ext/crypto-conditions/test-vectors/valid/%s.json',
|
||||
'tests/custom-vectors/%s.json']
|
||||
for fmt in paths:
|
||||
path = fmt % name
|
||||
if os.path.isfile(path):
|
||||
vectors = json.load(open(path))
|
||||
break
|
||||
else:
|
||||
raise IOError("Vectors file not found: %s.json" % name)
|
||||
for key in ['conditionBinary', 'fulfillment', 'message']:
|
||||
vectors[key] = b16_to_b64(vectors[key])
|
||||
return vectors
|
||||
|
||||
|
||||
so = cdll.LoadLibrary('.libs/libcryptoconditions.so')
|
||||
so.cc_jsonRPC.restype = c_char_p
|
||||
|
||||
|
||||
def jsonRPC(method, params):
|
||||
req = json.dumps({
|
||||
'method': method,
|
||||
'params': params,
|
||||
})
|
||||
out = so.cc_jsonRPC(req.encode())
|
||||
return json.loads(out.decode())
|
||||
Reference in New Issue
Block a user