You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
506 lines
24 KiB
506 lines
24 KiB
# -*- coding: utf-8 -*- |
|
|
|
import os |
|
|
|
import electrum_ecc as ecc |
|
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey |
|
|
|
from electrum.bitcoin import sha256 |
|
from electrum.transaction import Transaction |
|
from electrum.util import to_bytes, bfh |
|
|
|
from electrum.plugins.joinmarket.jm_util import verify_txin_sig |
|
from electrum.plugins.joinmarket.jmbase import utxostr_to_utxo, utxo_to_utxostr |
|
from electrum.plugins.joinmarket.jmclient import ( |
|
PoDLE, getNUMS, getP2, PoDLEError) |
|
from electrum.plugins.joinmarket.jmbitcoin import ( |
|
N, multiply, add_pubkeys, getG) |
|
from electrum.plugins.joinmarket.jmdaemon.enc_wrapper import ( |
|
core_salsa20, core_hsalsa20, stream_salsa20, stream_xsalsa20_xor, |
|
stream_salsa20_xor_ic, stream_xsalsa20, stream_xsalsa20_xor_ic, core_salsa, |
|
secretbox_xsalsa20poly1305_open, secretbox_xsalsa20poly1305, CryptoBox, |
|
crypto_box_afternm, crypto_box_open_afternm, CRYPTO_BOX_ZEROBYTES, |
|
encrypt_encode, decode_decrypt) |
|
|
|
from electrum.plugins.joinmarket.tests import JMTestCase |
|
|
|
|
|
class CryptoBoxTestCase(JMTestCase): |
|
|
|
async def test_core_salsa(self): |
|
data = b'\x01\x02\x03\x04' * 4 |
|
key = b'\x05\x06\x07\x08' * 8 |
|
c = b'\x04\x03\x02\x01' * 4 |
|
wrong_c = c + b'\x05' |
|
res = bfh('9a357b4b062d7b74bd21b3937ee4bc94' |
|
'525ed648acae612f5bf6f3059274f38e' |
|
'14c6badf679f1e1bbeed6b8fc508f1ec' |
|
'ea0d45359bf6b272e5765309ec9b0111') |
|
c_res = bfh('fd0777b560a17196022d48b3b1071c93' |
|
'15f7bda24c314cfc148d648a7265d317' |
|
'87635683536168977f890626f9998e2e' |
|
'8c3416edcfd15e022b887d1ff940f7d9') |
|
assert core_salsa(data, key, b'') == res |
|
assert core_salsa(data, key, c) == c_res |
|
with self.assertRaises(AssertionError): |
|
assert core_salsa(data, key, wrong_c) |
|
|
|
async def test_core_salsa20(self): |
|
key = bytes(range(1, 33)) |
|
nonce = bytes([3, 1, 4, 1, 5, 9, 2, 6]) |
|
block_counter = bytes([7, 0, 0, 0, 0, 0, 0, 0]) |
|
s_int = [0xb9a205a3, 0x0695e150, 0xaa94881a, 0xadb7b12c, |
|
0x798942d4, 0x26107016, 0x64edb1a4, 0x2d27173f, |
|
0xb1c7f1fa, 0x62066edc, 0xe035fa23, 0xc4496f04, |
|
0x2131e6b3, 0x810bde28, 0xf62cb407, 0x6bdede3d] |
|
|
|
s = b''.join([s.to_bytes(4, 'little') for s in s_int]) |
|
assert core_salsa20(nonce + block_counter, key) == s |
|
|
|
async def test_core_hsalsa20(self): |
|
sk1_hex = ('f4bd945d9554aeadaf589d4bd93c00a7' |
|
'06a3bce1b9d21e1748d70ae06d334349') |
|
sk2_hex = ('4d4cd62cb727351f273d6e999bc8f99d' |
|
'8e14c95fedcce9591e2500eefb786147') |
|
shared_hex = ('3b6bd938b8b43f23a8530b291e76c2b5' |
|
'08932421875487785266dfa6ec49a948') |
|
k_hex = ('1f2d9875e1dacd7642257a1318595e9c' |
|
'0588f313b79ef263905769c4d44618c7') |
|
k2_hex = ('81514eb8a907a83980ebefac8c824eff' |
|
'7853698dfea8bde2324484bd2f140ed5') |
|
sk1 = X25519PrivateKey.from_private_bytes(bfh(sk1_hex)) |
|
sk2 = X25519PrivateKey.from_private_bytes(bfh(sk2_hex)) |
|
assert sk1.exchange(sk2.public_key()) == bfh(shared_hex) |
|
assert core_hsalsa20(bfh(shared_hex)) == bfh(k_hex) |
|
assert core_hsalsa20(bfh(shared_hex), nonce=b'\xff'*16) == bfh(k2_hex) |
|
|
|
async def test_stream_salsa20(self): |
|
nonce = bytes([3, 1, 4, 1, 5, 9, 2, 6]) |
|
key = bytes(range(1, 33)) |
|
s_hex = ('6ebcbdbf76fccc64ab05542bee8a67cb' |
|
'c28fa2e141fbefbb3a2f9b221909c8d7') |
|
s_hex_128 = ('6ebcbdbf76fccc64ab05542bee8a67cb' |
|
'c28fa2e141fbefbb3a2f9b221909c8d7' |
|
'd4295258cb539770dd24d7ac3443769f' |
|
'fa27a50e60644264dc8b6b612683372e' |
|
'085d0a12bf240b189ce2b78289862b56' |
|
'fdc9fcffc33bef9325a2e81b98fb3fb9' |
|
'aa04cf434615ceffeb985c1cb08d8440' |
|
'e90b1d56ddeaea16d9e15affff1f698c') |
|
assert stream_salsa20(32, nonce, key) == bfh(s_hex) |
|
assert stream_salsa20(128, nonce, key) == bfh(s_hex_128) |
|
|
|
async def test_stream_xsalsa20(self): |
|
nonce = bytes([3, 1, 4, 1, 5, 9, 2, 6]*3) |
|
key = bytes(range(1, 33)) |
|
s_hex = ('6f0b37b2a23c7d05b66ca1cc5785723f' |
|
'125b295e69497d07d4e7e72c0ed79e0e') |
|
assert stream_xsalsa20(32, nonce, key) == bfh(s_hex) |
|
|
|
async def test_stream_salsa20_xor_ic(self): |
|
msg = to_bytes('test_msg ' * 10) |
|
nonce = bytes([3, 1, 4, 1, 5, 9, 2, 6]) |
|
ic = 0 |
|
key = bytes(range(1, 33)) |
|
s_hex = ('1ad9cecb2991bf038b7131589ad50ab8a5afd684328fb0' |
|
'd64948bb567c7abc88b95a3578bf36e4048249a4cb1437' |
|
'13ec8e78c87d07443601afff340c55e4175a6d2e7e4dd2' |
|
'576c38e887c4f6d6eb5831ddbd998cb76482e04282') |
|
assert stream_salsa20_xor_ic(msg, nonce, ic, key) == bfh(s_hex) |
|
|
|
async def test_stream_xsalsa20_xor_ic(self): |
|
msg = to_bytes('test_msg ' * 10) |
|
nonce = bytes([3, 1, 4, 1, 5, 9, 2, 6]*3) |
|
ic = 0 |
|
key = bytes(range(1, 33)) |
|
s_hex = ('1b6e44c6fd510e629618c4bf23da1f4c757b5d3b1a3d22' |
|
'6aa780c7586ba4ea51c389c2282f37bfe617d6147a8fb9' |
|
'8110d35abbaf91a69f0e326ec82564362b00fe949fae0c' |
|
'c2037d96cc9829be8c807cb3c5a86c1c190ac90ae2') |
|
assert stream_xsalsa20_xor_ic(msg, nonce, ic, key) == bfh(s_hex) |
|
|
|
async def test_stream_xsalsa20_xor(self): |
|
msg = to_bytes('test_msg ' * 10) |
|
nonce = bytes([3, 1, 4, 1, 5, 9, 2, 6]*3) |
|
key = bytes(range(1, 33)) |
|
s_hex = ('1b6e44c6fd510e629618c4bf23da1f4c757b5d3b1a3d22' |
|
'6aa780c7586ba4ea51c389c2282f37bfe617d6147a8fb9' |
|
'8110d35abbaf91a69f0e326ec82564362b00fe949fae0c' |
|
'c2037d96cc9829be8c807cb3c5a86c1c190ac90ae2') |
|
assert stream_xsalsa20_xor(msg, nonce, key) == bfh(s_hex) |
|
|
|
async def test_secretbox_xsalsa20poly1305(self): |
|
msg = to_bytes('test_msg ' * 10) |
|
nonce = bytes([3, 1, 4, 1, 5, 9, 2, 6]*3) |
|
key = bytes(range(1, 33)) |
|
pad = b'\x00' * CRYPTO_BOX_ZEROBYTES |
|
s_hex = ('00000000000000000000000000000000046cebaf04688d6a42dcec49f0' |
|
'72e6e0da9fd67c043fbff568cf026edb928910c025a2b985f2b406327d' |
|
'b73c72227f2bf6948cd115d41729bdc4983ac1959668e7eea06c0f6613' |
|
'df1eb6ccd93e1827c769410c084bf7d628bb63f34ddda70914b390ee45' |
|
'229e2d85df36') |
|
assert secretbox_xsalsa20poly1305(pad+msg, nonce, key) == bfh(s_hex) |
|
|
|
async def test_secretbox_xsalsa20poly1305_open(self): |
|
msg = to_bytes('test_msg ' * 10) |
|
nonce = bytes([3, 1, 4, 1, 5, 9, 2, 6]*3) |
|
key = bytes(range(1, 33)) |
|
pad = b'\x00' * CRYPTO_BOX_ZEROBYTES |
|
ctxt = ('00000000000000000000000000000000046cebaf04688d6a42dcec49f0' |
|
'72e6e0da9fd67c043fbff568cf026edb928910c025a2b985f2b406327d' |
|
'b73c72227f2bf6948cd115d41729bdc4983ac1959668e7eea06c0f6613' |
|
'df1eb6ccd93e1827c769410c084bf7d628bb63f34ddda70914b390ee45' |
|
'229e2d85df36') |
|
assert secretbox_xsalsa20poly1305_open(bfh(ctxt), nonce, key) == \ |
|
(pad + msg) |
|
|
|
async def test_crypto_box_afternm(self): |
|
msg = to_bytes('test_msg ' * 10) |
|
nonce = bytes([3, 1, 4, 1, 5, 9, 2, 6]*3) |
|
key = bytes(range(1, 33)) |
|
ctxt = ('046cebaf04688d6a42dcec49f072e6e0da9fd67c043fbff568cf026edb92' |
|
'8910c025a2b985f2b406327db73c72227f2bf6948cd115d41729bdc4983a' |
|
'c1959668e7eea06c0f6613df1eb6ccd93e1827c769410c084bf7d628bb63' |
|
'f34ddda70914b390ee45229e2d85df36') |
|
assert crypto_box_afternm(msg, nonce, key) == bfh(ctxt) |
|
|
|
async def test_crypto_box_open_afternm(self): |
|
msg = to_bytes('test_msg ' * 10) |
|
nonce = bytes([3, 1, 4, 1, 5, 9, 2, 6]*3) |
|
key = bytes(range(1, 33)) |
|
ctxt = ('046cebaf04688d6a42dcec49f072e6e0da9fd67c043fbff568cf026edb92' |
|
'8910c025a2b985f2b406327db73c72227f2bf6948cd115d41729bdc4983a' |
|
'c1959668e7eea06c0f6613df1eb6ccd93e1827c769410c084bf7d628bb63' |
|
'f34ddda70914b390ee45229e2d85df36') |
|
assert crypto_box_open_afternm(bfh(ctxt), nonce, key) == msg |
|
|
|
async def test_CryptoBox_encrypt_decrypt(self): |
|
sk1_hex = ('f4bd945d9554aeadaf589d4bd93c00a7' |
|
'06a3bce1b9d21e1748d70ae06d334349') |
|
sk2_hex = ('4d4cd62cb727351f273d6e999bc8f99d' |
|
'8e14c95fedcce9591e2500eefb786147') |
|
k_hex = ('1f2d9875e1dacd7642257a1318595e9c' |
|
'0588f313b79ef263905769c4d44618c7') |
|
sk1 = X25519PrivateKey.from_private_bytes(bfh(sk1_hex)) |
|
sk2 = X25519PrivateKey.from_private_bytes(bfh(sk2_hex)) |
|
box1 = CryptoBox(sk1, sk2.public_key()) |
|
assert box1._k == bfh(k_hex) |
|
msg = to_bytes('test msg') |
|
ctxt = box1.encrypt(msg) |
|
ctxt_b64 = encrypt_encode(msg, box1) |
|
box2 = CryptoBox(sk2, sk1.public_key()) |
|
with self.assertRaises(ValueError): |
|
assert box2.decrypt(ctxt, b'\x01\x02') == msg |
|
assert box2.decrypt(ctxt) == msg |
|
assert decode_decrypt(ctxt_b64, box2) == msg |
|
with self.assertRaises(ValueError): |
|
box1.encrypt(msg, b'\x01\x02') |
|
assert isinstance(box1.encrypt(msg, None, False), tuple) |
|
|
|
|
|
class PoDLETestCase(JMTestCase): |
|
|
|
async def _init_all_data(self): |
|
txid = ('f4bd945d9554aeadaf589d4bd93c00a7' |
|
'f4bd945d9554aeadaf589d4bd93c00a7') |
|
u = (bfh(txid), 0) |
|
privk = ecc.ECPrivkey.generate_random_key() |
|
privk_bytes = privk.get_secret_bytes() |
|
pubk = ecc.ECPubkey(privk.get_public_key_bytes()) |
|
pubk_bytes = pubk.get_public_key_bytes() |
|
J = getNUMS(0) |
|
J_bytes = J.get_public_key_bytes() |
|
k = os.urandom(32) |
|
k_int = int.from_bytes(k, byteorder='big') |
|
P2 = getP2(privk, J) |
|
P2_bytes = P2.get_public_key_bytes() |
|
KG = ecc.ECPubkey(ecc.ECPrivkey(k).get_public_key_bytes()) |
|
KJ = multiply(k_int, J_bytes, return_serialized=False) |
|
e = sha256(b''.join([x.get_public_key_bytes() |
|
for x in [KG, KJ, privk, P2]])) |
|
priv_int, e_int = (int.from_bytes(x, byteorder='big') |
|
for x in [privk_bytes, e]) |
|
sig_int = (k_int + priv_int * e_int) % N |
|
s = (sig_int).to_bytes(32, byteorder='big') |
|
return (u, privk, privk_bytes, pubk, pubk_bytes, J, J_bytes, k, k_int, |
|
P2, P2_bytes, KG, KJ, e, priv_int, e_int, sig_int, s) |
|
|
|
async def test_PoDLE_init(self): |
|
(u, privk, privk_bytes, pubk, pubk_bytes, J, J_bytes, k, k_int, |
|
P2, P2_bytes, KG, KJ, e, priv_int, e_int, sig_int, s) = \ |
|
await self._init_all_data() |
|
podle = PoDLE(u=u, priv=privk_bytes, P2=P2_bytes, s=s, e=e) |
|
with self.assertRaises(PoDLEError): |
|
PoDLE(u=u, priv=privk_bytes, P=pubk_bytes, P2=P2_bytes, s=s, e=e) |
|
assert repr(podle) |
|
|
|
async def test_PoDLE_reveal(self): |
|
(u, privk, privk_bytes, pubk, pubk_bytes, J, J_bytes, k, k_int, |
|
P2, P2_bytes, KG, KJ, e, priv_int, e_int, sig_int, s) = \ |
|
await self._init_all_data() |
|
podle = PoDLE(u=u, priv=privk_bytes, P2=P2_bytes, s=s, e=e) |
|
with self.assertRaises(PoDLEError): |
|
podle.s = None |
|
podle.reveal() |
|
|
|
async def test_PoDLE_get_commitment(self): |
|
(u, privk, privk_bytes, pubk, pubk_bytes, J, J_bytes, k, k_int, |
|
P2, P2_bytes, KG, KJ, e, priv_int, e_int, sig_int, s) = \ |
|
await self._init_all_data() |
|
podle = PoDLE(u=u, P=pubk_bytes, P2=P2_bytes, s=s, e=e) |
|
podle.get_commitment() |
|
|
|
podle2 = PoDLE() |
|
with self.assertRaises(PoDLEError): |
|
podle2.get_commitment() |
|
podle2.P2 = P2_bytes |
|
with self.assertRaises(PoDLEError): |
|
podle2.get_commitment() |
|
podle2.P2 = P2 |
|
podle.get_commitment() |
|
|
|
async def test_PoDLE_generate_podle(self): |
|
(u, privk, privk_bytes, pubk, pubk_bytes, J, J_bytes, k, k_int, |
|
P2, P2_bytes, KG, KJ, e, priv_int, e_int, sig_int, s) = \ |
|
await self._init_all_data() |
|
podle = PoDLE(u=u, priv=privk_bytes) |
|
r = podle.generate_podle() |
|
assert r |
|
assert r['utxo'] |
|
assert r['commit'] |
|
|
|
async def test_PoDLE_serialize_deserialize_revelation(self): |
|
(u, privk, privk_bytes, pubk, pubk_bytes, J, J_bytes, k, k_int, |
|
P2, P2_bytes, KG, KJ, e, priv_int, e_int, sig_int, s) = \ |
|
await self._init_all_data() |
|
podle = PoDLE(u=u, priv=privk_bytes) |
|
r1 = podle.generate_podle() |
|
sr = podle.serialize_revelation() |
|
sr_split = sr.split('|') |
|
assert len(sr_split) == 5 |
|
r2 = PoDLE.deserialize_revelation(sr) |
|
assert r2['P'] == r1['P'] |
|
assert r2['P2'] == r1['P2'] |
|
assert r2['e'] == r1['e'] |
|
assert r2['sig'] == r1['sig'] |
|
assert r2['utxo'] == r1['utxo'] |
|
with self.assertRaises(PoDLEError): |
|
r2 = PoDLE.deserialize_revelation(sr + '|00') |
|
|
|
async def test_PoDLE_verify(self): |
|
(u, privk, privk_bytes, pubk, pubk_bytes, J, J_bytes, k, k_int, |
|
P2, P2_bytes, KG, KJ, e, priv_int, e_int, sig_int, s) = \ |
|
await self._init_all_data() |
|
podle = PoDLE(u=u, priv=privk_bytes, P2=P2_bytes, s=s, e=e) |
|
commitment = podle.get_commitment() |
|
podle2 = PoDLE(u=u, P=pubk_bytes, P2=P2_bytes, s=s, e=e) |
|
assert podle2.verify(commitment, [0]) |
|
assert not podle2.verify(commitment, [1]) |
|
assert not podle2.verify(commitment + b'\x00', [0]) |
|
podle2.s = None |
|
with self.assertRaises(PoDLEError): |
|
podle2.verify(commitment, [0]) |
|
|
|
|
|
class PoDLEFunctionsTestCase(JMTestCase): |
|
|
|
async def test_utxostr_to_utxo(self): |
|
txid = ('f4bd945d9554aeadaf589d4bd93c00a7' |
|
'f4bd945d9554aeadaf589d4bd93c00a7') |
|
assert not utxostr_to_utxo(5)[0] # not a str |
|
assert not utxostr_to_utxo(txid)[0] # has no ':' |
|
assert not utxostr_to_utxo(f'{txid}:z')[0] # not int n |
|
assert not utxostr_to_utxo(f'{txid}:-1')[0] # n < 0 |
|
assert not utxostr_to_utxo(f'{txid[2:]}:0')[0] # txid len < 64 |
|
assert not utxostr_to_utxo(f'g{txid[1:]}:0')[0] # txid not hex |
|
assert utxostr_to_utxo(f'{txid}:0') == (True, (bfh(txid), 0)) |
|
|
|
async def test_utxo_to_utxostr(self): |
|
txid = ('f4bd945d9554aeadaf589d4bd93c00a7' |
|
'f4bd945d9554aeadaf589d4bd93c00a7') |
|
assert not utxo_to_utxostr(f'{txid}:0')[0] # not a tuple |
|
assert not utxo_to_utxostr((1, 2, 3))[0] # utxo len != 2 |
|
assert not utxo_to_utxostr((txid, 0))[0] # not bytes |
|
assert not utxo_to_utxostr((bfh(txid), '0'))[0] # n not int |
|
assert not utxo_to_utxostr((bfh(txid), -1))[0] # n < 0 |
|
assert not utxo_to_utxostr((bfh(txid[2:]), 0))[0] # txid len < 32 |
|
assert utxo_to_utxostr((bfh(txid), 0)) == (True, f'{txid}:0') |
|
|
|
async def test_multiply(self): |
|
privk = ecc.ECPrivkey.generate_random_key() |
|
pubk = ecc.ECPubkey(privk.get_public_key_bytes()) |
|
pubk_bytes = pubk.get_public_key_bytes() |
|
assert multiply(10, pubk_bytes) == (pubk * 10).get_public_key_bytes() |
|
assert multiply(10, pubk_bytes, False) == (pubk * 10) |
|
|
|
async def test_add_pubkeys(self): |
|
privk1 = ecc.ECPrivkey.generate_random_key() |
|
pubk1 = ecc.ECPubkey(privk1.get_public_key_bytes()) |
|
pubk1_bytes = pubk1.get_public_key_bytes() |
|
privk2 = ecc.ECPrivkey.generate_random_key() |
|
pubk2 = ecc.ECPubkey(privk2.get_public_key_bytes()) |
|
pubk2_bytes = pubk2.get_public_key_bytes() |
|
privk3 = ecc.ECPrivkey.generate_random_key() |
|
pubk3 = ecc.ECPubkey(privk3.get_public_key_bytes()) |
|
pubk3_bytes = pubk3.get_public_key_bytes() |
|
assert add_pubkeys([pubk1_bytes, pubk2_bytes, pubk3_bytes]) == \ |
|
(pubk1 + pubk2 + pubk3).get_public_key_bytes() |
|
|
|
async def test_getG(self): |
|
assert getG() == ecc.GENERATOR.get_public_key_bytes() |
|
assert getG(False) == ecc.GENERATOR.get_public_key_bytes(False) |
|
|
|
async def test_getNUMS(self): |
|
for i in range(256): |
|
pubk = getNUMS(i) |
|
pubk_bytes = pubk.get_public_key_bytes() |
|
assert len(pubk_bytes.hex()) == 66 |
|
with self.assertRaises(AssertionError): |
|
getNUMS(256) |
|
with self.assertRaises(AssertionError): |
|
getNUMS(-1) |
|
|
|
async def test_getP2(self): |
|
privk = ecc.ECPrivkey.generate_random_key() |
|
nums0 = getNUMS(0) |
|
nums0_bytes = nums0.get_public_key_bytes() |
|
assert getP2(privk, nums0) == multiply(privk.secret_scalar, |
|
nums0_bytes, False) |
|
|
|
|
|
class TxUtilTestCase(JMTestCase): |
|
|
|
raw_tx = ('0200000002a3c3741aebeec8b8c62cb057ea549b0d3643bfebe523628b063c' |
|
'9db5e4c90353000000006a47304402204644617dd2b5840820f30d63cf4508' |
|
'26bab7437f57a45a761f9224731900338802205d4403ee8bed1741af6ad640' |
|
'1b529b51344e5da96f94becbc2a98d2b1f26565801210220083a2355781ff1' |
|
'f57bae38b8a143c058faed25fd60d90186f5c4ea8741b131feffffff96c205' |
|
'1bc69b2a0b2629e2df1e3c298502235a72752fbabbbd39da72334e8e810000' |
|
'00006a473044022014baa38694ce16a7cd00468ef1dc4afb4b2953d05030da' |
|
'0b7928d270c62c8ede02202cb9c751424eb826b1c3a5f09afcc04393f31d9a' |
|
'1d844f853adba8c0da04ddd5012102ef66d742685f5bfb22c5364f8d13c899' |
|
'5a9c776a9b3ad1d25e823414ab307fa5feffffff0130660000000000001976' |
|
'a91467e333a26ba6ebbc26067034e7d4fd5036f53e0e88ac08010900') |
|
|
|
prevtx = ('02000000027366833e954d625d2c7c323a33bdedba986cf3153ff1c1bd1e14' |
|
'3ca789278b27000000006b483045022100c36856a7341f75b6f4e36f74a2da' |
|
'12e19e7881abd4e29bae2e4e4587fad2bcb9022002f2e6184684d2ade510c1' |
|
'84c8ebdea063f8fcb65f7c17b62cf70f25915a666401210287b3a996386eb7' |
|
'798222ff1575b0325c3a51ccbe8aff238132b60b2a6f2bec02feffffff715f' |
|
'25c2d747193a26dc9085b57b49470b13b63760191206041b0839cd0b697600' |
|
'0000006a47304402204cb360acc74874afac4a4ecd91e96d9d6259bac05af2' |
|
'632096139f911fa66cf102207c83dc64f0ef3612c326dd91ad161ebd4cf0db' |
|
'398847ef4120b086baf9af7142012102ef66d742685f5bfb22c5364f8d13c8' |
|
'995a9c776a9b3ad1d25e823414ab307fa5feffffff03641900000000000019' |
|
'76a91467e333a26ba6ebbc26067034e7d4fd5036f53e0e88ac641900000000' |
|
'00001976a914c67034239c66de4b562469db89f1b834733c22c388ac19b19a' |
|
'3b000000001976a9149f1708ce9b84576b4b5cca5816886bb609da94b888ac' |
|
'00000000') |
|
|
|
raw_tx_native_segwit = ( |
|
'020000000001016102df5977d8479baa63e0de187f5fb16d46da05ab26df8f6738fc' |
|
'dd627097420100000000feffffff0240420f0000000000160014c380cfad0316be20' |
|
'cc1d4bc94f7f620d8d8d74b80ca92200000000001600144c079970fecec16b29e283' |
|
'3bdb380767fdc2c2f402473044022074e78765a4d27279012165b8db490f4a51b129' |
|
'de6a7a4057563538f57cbc9566022015f5f20920c3d03eb3a3d058ca4156f03f8110' |
|
'69c6f107ef2218341c7fe884370121026572d52c070a27d3dacc5f085298d56d5966' |
|
'36cfbef9be83103ee4d0f81208b46b662200') |
|
|
|
prevtx_native_segwit = ( |
|
'02000000000103c17208c443a3d3d2223884ef11ac83dadb1a3abe4d3474694414c8' |
|
'dcd3c697510000000000feffffffe8e58405385783c155108da5193dff0b9fd6ab60' |
|
'1a5e8e5c4af73d8e96af0f730000000000feffffffa2fdfbaf5fda84096b34f08afd' |
|
'cfb28d0d43231127f2d5d0da41831aa0e7db830100000000feffffff0260ae0a0000' |
|
'0000001600147a01e4c62b173c6cac94628687b6aa467adbfa2714ec310000000000' |
|
'160014f5dfeaace8e313a161fcb670193f38efd97b7bce0247304402205554e284e1' |
|
'96d6b3dc4a96cdc24f857dca68f41f65124bab91ec46251004a396022019339072cd' |
|
'717aac0e9e1d142e482fe7a6513593cf99521b2b861b10f471238501210242276a06' |
|
'847935a063f8f9973f7dea10a720152ee789c4c72fcbc64a7749f46f024730440220' |
|
'4b1ea07b9dd27db75d50ff35535fe7ed123aed81eba9fa41f56c3d9ec08a7b2f0220' |
|
'73164defcbf577c7168508bdfea8be698d2f1e09913f925459c7cb8382aa81f30121' |
|
'0242276a06847935a063f8f9973f7dea10a720152ee789c4c72fcbc64a7749f46f02' |
|
'4730440220155ddb1f9815bbdd25c86e9edda7adf88d3e9e944a08bdf41b319fc714' |
|
'4da95802205e022944be559f6525131d82b54f0dcf22383c2a589e7d61da4d1ac46a' |
|
'3e246601210242276a06847935a063f8f9973f7dea10a720152ee789c4c72fcbc64a' |
|
'7749f46f76832100') |
|
|
|
raw_tx_p2sh_segwit = ( |
|
'02000000000101923694e55341a1065e92351464928652d107e2c7e7efa40ee7ceea' |
|
'665357645401000000171600147e316097bd838a8de7afa7b45ef4b2e24a90a6b7fd' |
|
'ffffff018a2600000000000017a914a12bfecbd723838fea79ce3d709ab09f3f46da' |
|
'738702473044022002ed167bdcca402715f796c015eed1cd28647c2af465abfe2867' |
|
'09c2a4917ad702202f41b4567c95213c65c64f754554a40550491bafc33844e0f0cc' |
|
'eb99e20c22740121038623a41ac0d23be7015ba711706bc23ddf385f559565a69885' |
|
'291d38c80c2a9d7faa2600') |
|
|
|
prevtx_p2sh_segwit = ( |
|
'02000000000101bf2d2d42655d0e2cd9f282df619a22036cde72ff61d365492772a5' |
|
'6f32793f930100000000fdffffff021c0c0000000000001600145b058870c3f1296f' |
|
'71262b78be0f389110e95213102700000000000017a9147d8cbb88869840e0deaceb' |
|
'980a2943472f36513d870247304402200c58deeb5474d02460fff10fb96794512044' |
|
'bb8f5015d2ad038f3a606eb4ca6502202038a8263f71fa459cdc947897c7ddfe921a' |
|
'c012cd38be692903c13463034d81012102218051896d4a685aed1437eb2e982741a8' |
|
'2c232284158ab6edae97bc94cb0ba9abaa2600') |
|
|
|
async def test_verify_txin_sig(self): |
|
jmman = self.jmman |
|
txin_idx = 1 |
|
assert verify_txin_sig(jmman, self.raw_tx, txin_idx, self.prevtx) |
|
txin_idx = 0 |
|
assert verify_txin_sig(jmman, self.raw_tx_native_segwit, txin_idx, |
|
self.prevtx_native_segwit) |
|
txin_idx = 0 |
|
assert verify_txin_sig(jmman, self.raw_tx_p2sh_segwit, txin_idx, |
|
self.prevtx_p2sh_segwit) |
|
|
|
async def test_verify_txin_sig_fails(self): |
|
prevout_idx = 0 |
|
txin_idx = 1 |
|
txin_idx10 = 10 |
|
|
|
jmman = self.jmman |
|
assert not verify_txin_sig(jmman, self.raw_tx, txin_idx10, self.prevtx) |
|
|
|
prevtx = Transaction(self.prevtx) |
|
prevout = prevtx.outputs()[prevout_idx] |
|
prevout.scriptpubkey = prevout.scriptpubkey[:-1] |
|
prevtx = prevtx.serialize_to_network() |
|
assert not verify_txin_sig(jmman, self.raw_tx, txin_idx, prevtx) |
|
|
|
prevtx = Transaction(self.prevtx) |
|
prevout = prevtx.outputs()[prevout_idx] |
|
prevout.scriptpubkey = prevout.scriptpubkey[:-1] + b'\x00' |
|
prevtx = prevtx.serialize_to_network() |
|
assert not verify_txin_sig(jmman, self.raw_tx, txin_idx, prevtx) |
|
|
|
tx = Transaction(self.raw_tx) |
|
tx.inputs()[txin_idx].script_sig = b'' |
|
raw_tx = tx.serialize_to_network() |
|
assert not verify_txin_sig(jmman, raw_tx, txin_idx, self.prevtx) |
|
|
|
tx = Transaction(self.raw_tx) |
|
script_sig = bytearray(tx.inputs()[txin_idx].script_sig) |
|
script_sig[0] = 70 |
|
tx.inputs()[txin_idx].script_sig = bytes(script_sig) |
|
raw_tx = tx.serialize_to_network() |
|
assert not verify_txin_sig(jmman, raw_tx, txin_idx, self.prevtx) |
|
|
|
tx = Transaction(self.raw_tx) |
|
script_sig = tx.inputs()[txin_idx].script_sig |
|
tx.inputs()[txin_idx].script_sig = script_sig[:-1] |
|
raw_tx = tx.serialize_to_network() |
|
assert not verify_txin_sig(jmman, raw_tx, txin_idx, self.prevtx) |
|
|
|
tx = Transaction(self.raw_tx) |
|
script_sig = tx.inputs()[txin_idx].script_sig |
|
tx.inputs()[txin_idx].script_sig = script_sig[:-1] + b'\x00' |
|
raw_tx = tx.serialize_to_network() |
|
assert not verify_txin_sig(jmman, raw_tx, txin_idx, self.prevtx) |
|
|
|
tx = Transaction(self.raw_tx) |
|
script_sig = bytearray(tx.inputs()[txin_idx].script_sig) |
|
sighash_type_pos = 1 + script_sig[0] - 1 |
|
script_sig[sighash_type_pos] = 127 |
|
tx.inputs()[txin_idx].script_sig = bytes(script_sig) |
|
raw_tx = tx.serialize_to_network() |
|
assert not verify_txin_sig(jmman, raw_tx, txin_idx, self.prevtx)
|
|
|