add unit tests, add t.c.sha512

This commit is contained in:
Pavol Rusnak 2016-04-12 18:09:23 +02:00
parent e88cd6f20d
commit 4eccc55c5c
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
9 changed files with 376 additions and 0 deletions

View File

@ -25,6 +25,9 @@ clean_stmhal: ## clean stmhal build
clean_unix: ## clean unix build
make -C vendor/micropython/unix clean
test: ## run unit tests
cd src/tests ; ./run_tests.sh
flash: ## flash firmware using st-flash
st-flash write $(STMHAL_BUILD_DIR)/firmware0.bin 0x8000000
sleep 0.1

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) Pavol Rusnak, SatoshiLabs
*
* Licensed under Microsoft Reference Source License (Ms-RSL)
* see LICENSE.md file for details
*/
#include "trezor-crypto/sha2.h"
// class Sha512(object):
typedef struct _mp_obj_Sha512_t {
mp_obj_base_t base;
} mp_obj_Sha512_t;
// def Sha512.__init__(self):
STATIC mp_obj_t mod_TrezorCrypto_Sha512_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_obj_Sha512_t *o = m_new_obj(mp_obj_Sha512_t);
o->base.type = type;
return MP_OBJ_FROM_PTR(o);
}
// def Sha512.hash(self, data: bytes) -> bytes
STATIC mp_obj_t mod_TrezorCrypto_Sha512_hash(mp_obj_t self, mp_obj_t data) {
mp_buffer_info_t databuf;
mp_get_buffer_raise(data, &databuf, MP_BUFFER_READ);
vstr_t vstr;
vstr_init_len(&vstr, 64); // 512 bit = 64 bytes
sha512_Raw(databuf.buf, databuf.len, (uint8_t *)vstr.buf);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_TrezorCrypto_Sha512_hash_obj, mod_TrezorCrypto_Sha512_hash);
// Sha512 stuff
STATIC const mp_rom_map_elem_t mod_TrezorCrypto_Sha512_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_hash), MP_ROM_PTR(&mod_TrezorCrypto_Sha512_hash_obj) },
};
STATIC MP_DEFINE_CONST_DICT(mod_TrezorCrypto_Sha512_locals_dict, mod_TrezorCrypto_Sha512_locals_dict_table);
STATIC const mp_obj_type_t mod_TrezorCrypto_Sha512_type = {
{ &mp_type_type },
.name = MP_QSTR_Sha512,
.make_new = mod_TrezorCrypto_Sha512_make_new,
.locals_dict = (void*)&mod_TrezorCrypto_Sha512_locals_dict,
};

View File

@ -17,6 +17,7 @@
#include "modTrezorCrypto-base58.h"
#include "modTrezorCrypto-sha256.h"
#include "modTrezorCrypto-sha512.h"
// module stuff
@ -24,6 +25,7 @@ STATIC const mp_rom_map_elem_t mp_module_TrezorCrypto_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_TrezorCrypto) },
{ MP_ROM_QSTR(MP_QSTR_Base58), MP_ROM_PTR(&mod_TrezorCrypto_Base58_type) },
{ MP_ROM_QSTR(MP_QSTR_Sha256), MP_ROM_PTR(&mod_TrezorCrypto_Sha256_type) },
{ MP_ROM_QSTR(MP_QSTR_Sha512), MP_ROM_PTR(&mod_TrezorCrypto_Sha512_type) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_TrezorCrypto_globals, mp_module_TrezorCrypto_globals_table);

203
src/lib/unittest.py Normal file
View File

@ -0,0 +1,203 @@
class SkipTest(Exception):
pass
class AssertRaisesContext:
def __init__(self, exc):
self.expected = exc
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, tb):
if exc_type is None:
assert False, "%r not raised" % self.expected
if issubclass(exc_type, self.expected):
return True
return False
class TestCase:
def fail(self, msg=''):
assert False, msg
def assertEqual(self, x, y, msg=''):
if not msg:
msg = "%r vs (expected) %r" % (x, y)
assert x == y, msg
def assertNotEqual(self, x, y, msg=''):
if not msg:
msg = "%r not expected to be equal %r" % (x, y)
assert x != y, msg
def assertAlmostEqual(self, x, y, places=None, msg='', delta=None):
if x == y:
return
if delta is not None and places is not None:
raise TypeError("specify delta or places not both")
if delta is not None:
if abs(x - y) <= delta:
return
if not msg:
msg = '%r != %r within %r delta' % (x, y, delta)
else:
if places is None:
places = 7
if round(abs(y-x), places) == 0:
return
if not msg:
msg = '%r != %r within %r places' % (x, y, places)
assert False, msg
def assertNotAlmostEqual(self, x, y, places=None, msg='', delta=None):
if delta is not None and places is not None:
raise TypeError("specify delta or places not both")
if delta is not None:
if not (x == y) and abs(x - y) > delta:
return
if not msg:
msg = '%r == %r within %r delta' % (x, y, delta)
else:
if places is None:
places = 7
if not (x == y) and round(abs(y-x), places) != 0:
return
if not msg:
msg = '%r == %r within %r places' % (x, y, places)
assert False, msg
def assertIs(self, x, y, msg=''):
if not msg:
msg = "%r is not %r" % (x, y)
assert x is y, msg
def assertIsNot(self, x, y, msg=''):
if not msg:
msg = "%r is %r" % (x, y)
assert x is not y, msg
def assertIsNone(self, x, msg=''):
if not msg:
msg = "%r is not None" % x
assert x is None, msg
def assertIsNotNone(self, x, msg=''):
if not msg:
msg = "%r is None" % x
assert x is not None, msg
def assertTrue(self, x, msg=''):
if not msg:
msg = "Expected %r to be True" % x
assert x, msg
def assertFalse(self, x, msg=''):
if not msg:
msg = "Expected %r to be False" % x
assert not x, msg
def assertIn(self, x, y, msg=''):
if not msg:
msg = "Expected %r to be in %r" % (x, y)
assert x in y, msg
def assertIsInstance(self, x, y, msg=''):
assert isinstance(x, y), msg
def assertRaises(self, exc, func=None, *args, **kwargs):
if func is None:
return AssertRaisesContext(exc)
try:
func(*args, **kwargs)
assert False, "%r not raised" % exc
except Exception as e:
if isinstance(e, exc):
return
raise
def skip(msg):
def _decor(fun):
# We just replace original fun with _inner
def _inner(self):
raise SkipTest(msg)
return _inner
return _decor
def skipUnless(cond, msg):
if cond:
return lambda x: x
return skip(msg)
class TestSuite:
def __init__(self):
self.tests = []
def addTest(self, cls):
self.tests.append(cls)
class TestRunner:
def run(self, suite):
res = TestResult()
for c in suite.tests:
run_class(c, res)
return res
class TestResult:
def __init__(self):
self.errorsNum = 0
self.failuresNum = 0
self.skippedNum = 0
self.testsRun = 0
def wasSuccessful(self):
return self.errorsNum == 0 and self.failuresNum == 0
# TODO: Uncompliant
def run_class(c, test_result):
o = c()
set_up = getattr(o, "setUp", lambda: None)
tear_down = getattr(o, "tearDown", lambda: None)
print('class', c.__qualname__)
for name in dir(o):
if name.startswith("test"):
print(name, end=' ...')
m = getattr(o, name)
try:
set_up()
test_result.testsRun += 1
m()
tear_down()
print(" ok")
except SkipTest as e:
print(" skipped:", e.args[0])
test_result.skippedNum += 1
def main(module="__main__"):
def test_cases(m):
for tn in dir(m):
c = getattr(m, tn)
if isinstance(c, object) and isinstance(c, type) and issubclass(c, TestCase):
yield c
m = __import__(module)
suite = TestSuite()
for c in test_cases(m):
suite.addTest(c)
runner = TestRunner()
result = runner.run(suite)
msg = "Ran %d tests" % result.testsRun
if result.skippedNum > 0:
msg += " (%d skipped)" % result.skippedNum
print(msg)

5
src/tests/run_tests.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/sh
for i in *.py; do
echo
../../vendor/micropython/unix/micropython $i
done

View File

@ -0,0 +1,74 @@
import sys
sys.path.append('..')
sys.path.append('../lib')
import unittest
import trezor.utils
import trezor.crypto.base58
class TestCryptoBase58(unittest.TestCase):
# vectors from https://github.com/bitcoin/bitcoin/blob/master/src/test/data/base58_keys_valid.json
vectors = [
('0065a16059864a2fdbc7c99a4723a8395bc6f188eb', '1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i'),
('0574f209f6ea907e2ea48f74fae05782ae8a665257', '3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou'),
('6f53c0307d6851aa0ce7825ba883c6bd9ad242b486', 'mo9ncXisMeAoXwqcV5EWuyncbmCcQN4rVs'),
('c46349a418fc4578d10a372b54b45c280cc8c4382f', '2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br'),
('80eddbdc1168f1daeadbd3e44c1e3f8f5a284c2029f78ad26af98583a499de5b19', '5Kd3NBUAdUnhyzenEwVLy9pBKxSwXvE9FMPyR4UKZvpe6E3AgLr'),
('8055c9bccb9ed68446d1b75273bbce89d7fe013a8acd1625514420fb2aca1a21c401', 'Kz6UJmQACJmLtaQj5A3JAge4kVTNQ8gbvXuwbmCj7bsaabudb3RD'),
('ef36cb93b9ab1bdabf7fb9f2c04f1b9cc879933530ae7842398eef5a63a56800c2', '9213qJab2HNEpMpYNBa7wHGFKKbkDn24jpANDs2huN3yi4J11ko'),
('efb9f4892c9e8282028fea1d2667c4dc5213564d41fc5783896a0d843fc15089f301', 'cTpB4YiyKiBcPxnefsDpbnDxFDffjqJob8wGCEDXxgQ7zQoMXJdH'),
('006d23156cbbdcc82a5a47eee4c2c7c583c18b6bf4', '1Ax4gZtb7gAit2TivwejZHYtNNLT18PUXJ'),
('05fcc5460dd6e2487c7d75b1963625da0e8f4c5975', '3QjYXhTkvuj8qPaXHTTWb5wjXhdsLAAWVy'),
('6ff1d470f9b02370fdec2e6b708b08ac431bf7a5f7', 'n3ZddxzLvAY9o7184TB4c6FJasAybsw4HZ'),
('c4c579342c2c4c9220205e2cdc285617040c924a0a', '2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n'),
('80a326b95ebae30164217d7a7f57d72ab2b54e3be64928a19da0210b9568d4015e', '5K494XZwps2bGyeL71pWid4noiSNA2cfCibrvRWqcHSptoFn7rc'),
('807d998b45c219a1e38e99e7cbd312ef67f77a455a9b50c730c27f02c6f730dfb401', 'L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi'),
('efd6bca256b5abc5602ec2e1c121a08b0da2556587430bcf7e1898af2224885203', '93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj'),
('efa81ca4e8f90181ec4b61b6a7eb998af17b2cb04de8a03b504b9e34c4c61db7d901', 'cTDVKtMGVYWTHCb1AFjmVbEbWjvKpKqKgMaR3QJxToMSQAhmCeTN'),
('007987ccaa53d02c8873487ef919677cd3db7a6912', '1C5bSj1iEGUgSTbziymG7Cn18ENQuT36vv'),
('0563bcc565f9e68ee0189dd5cc67f1b0e5f02f45cb', '3AnNxabYGoTxYiTEZwFEnerUoeFXK2Zoks'),
('6fef66444b5b17f14e8fae6e7e19b045a78c54fd79', 'n3LnJXCqbPjghuVs8ph9CYsAe4Sh4j97wk'),
('c4c3e55fceceaa4391ed2a9677f4a4d34eacd021a0', '2NB72XtkjpnATMggui83aEtPawyyKvnbX2o'),
('80e75d936d56377f432f404aabb406601f892fd49da90eb6ac558a733c93b47252', '5KaBW9vNtWNhc3ZEDyNCiXLPdVPHCikRxSBWwV9NrpLLa4LsXi9'),
('808248bd0375f2f75d7e274ae544fb920f51784480866b102384190b1addfbaa5c01', 'L1axzbSyynNYA8mCAhzxkipKkfHtAXYF4YQnhSKcLV8YXA874fgT'),
('ef44c4f6a096eac5238291a94cc24c01e3b19b8d8cef72874a079e00a242237a52', '927CnUkUbasYtDwYwVn2j8GdTuACNnKkjZ1rpZd2yBB1CLcnXpo'),
('efd1de707020a9059d6d3abaf85e17967c6555151143db13dbb06db78df0f15c6901', 'cUcfCMRjiQf85YMzzQEk9d1s5A4K7xL5SmBCLrezqXFuTVefyhY7'),
('00adc1cc2081a27206fae25792f28bbc55b831549d', '1Gqk4Tv79P91Cc1STQtU3s1W6277M2CVWu'),
('05188f91a931947eddd7432d6e614387e32b244709', '33vt8ViH5jsr115AGkW6cEmEz9MpvJSwDk'),
('6f1694f5bc1a7295b600f40018a618a6ea48eeb498', 'mhaMcBxNh5cqXm4aTQ6EcVbKtfL6LGyK2H'),
('c43b9b3fd7a50d4f08d1a5b0f62f644fa7115ae2f3', '2MxgPqX1iThW3oZVk9KoFcE5M4JpiETssVN'),
('80091035445ef105fa1bb125eccfb1882f3fe69592265956ade751fd095033d8d0', '5HtH6GdcwCJA4ggWEL1B3jzBBUB8HPiBi9SBc5h9i4Wk4PSeApR'),
('80ab2b4bcdfc91d34dee0ae2a8c6b6668dadaeb3a88b9859743156f462325187af01', 'L2xSYmMeVo3Zek3ZTsv9xUrXVAmrWxJ8Ua4cw8pkfbQhcEFhkXT8'),
('efb4204389cef18bbe2b353623cbf93e8678fbc92a475b664ae98ed594e6cf0856', '92xFEve1Z9N8Z641KQQS7ByCSb8kGjsDzw6fAmjHN1LZGKQXyMq'),
('efe7b230133f1b5489843260236b06edca25f66adb1be455fbd38d4010d48faeef01', 'cVM65tdYu1YK37tNoAyGoJTR13VBYFva1vg9FLuPAsJijGvG6NEA'),
('00c4c1b72491ede1eedaca00618407ee0b772cad0d', '1JwMWBVLtiqtscbaRHai4pqHokhFCbtoB4'),
('05f6fe69bcb548a829cce4c57bf6fff8af3a5981f9', '3QCzvfL4ZRvmJFiWWBVwxfdaNBT8EtxB5y'),
('6f261f83568a098a8638844bd7aeca039d5f2352c0', 'mizXiucXRCsEriQCHUkCqef9ph9qtPbZZ6'),
('c4e930e1834a4d234702773951d627cce82fbb5d2e', '2NEWDzHWwY5ZZp8CQWbB7ouNMLqCia6YRda'),
('80d1fab7ab7385ad26872237f1eb9789aa25cc986bacc695e07ac571d6cdac8bc0', '5KQmDryMNDcisTzRp3zEq9e4awRmJrEVU1j5vFRTKpRNYPqYrMg'),
('80b0bbede33ef254e8376aceb1510253fc3550efd0fcf84dcd0c9998b288f166b301', 'L39Fy7AC2Hhj95gh3Yb2AU5YHh1mQSAHgpNixvm27poizcJyLtUi'),
('ef037f4192c630f399d9271e26c575269b1d15be553ea1a7217f0cb8513cef41cb', '91cTVUcgydqyZLgaANpf1fvL55FH53QMm4BsnCADVNYuWuqdVys'),
('ef6251e205e8ad508bab5596bee086ef16cd4b239e0cc0c5d7c4e6035441e7d5de01', 'cQspfSzsgLeiJGB2u8vrAiWpCU4MxUT6JseWo2SjXy4Qbzn2fwDw'),
('005eadaf9bb7121f0f192561a5a62f5e5f54210292', '19dcawoKcZdQz365WpXWMhX6QCUpR9SY4r'),
('053f210e7277c899c3a155cc1c90f4106cbddeec6e', '37Sp6Rv3y4kVd1nQ1JV5pfqXccHNyZm1x3'),
('6fc8a3c2a09a298592c3e180f02487cd91ba3400b5', 'myoqcgYiehufrsnnkqdqbp69dddVDMopJu'),
('c499b31df7c9068d1481b596578ddbb4d3bd90baeb', '2N7FuwuUuoTBrDFdrAZ9KxBmtqMLxce9i1C'),
('80c7666842503db6dc6ea061f092cfb9c388448629a6fe868d068c42a488b478ae', '5KL6zEaMtPRXZKo1bbMq7JDjjo1bJuQcsgL33je3oY8uSJCR5b4'),
('8007f0803fc5399e773555ab1e8939907e9badacc17ca129e67a2f5f2ff84351dd01', 'KwV9KAfwbwt51veZWNscRTeZs9CKpojyu1MsPnaKTF5kz69H1UN2'),
('efea577acfb5d1d14d3b7b195c321566f12f87d2b77ea3a53f68df7ebf8604a801', '93N87D6uxSBzwXvpokpzg8FFmfQPmvX4xHoWQe3pLdYpbiwT5YV'),
('ef0b3b34f0958d8a268193a9814da92c3e8b58b4a4378a542863e34ac289cd830c01', 'cMxXusSihaX58wpJ3tNuuUcZEQGt6DKJ1wEpxys88FFaQCYjku9h'),
('001ed467017f043e91ed4c44b4e8dd674db211c4e6', '13p1ijLwsnrcuyqcTvJXkq2ASdXqcnEBLE'),
('055ece0cadddc415b1980f001785947120acdb36fc', '3ALJH9Y951VCGcVZYAdpA3KchoP9McEj1G'),
]
def test_decode_check(self):
for a, b in self.vectors:
self.assertEqual(trezor.crypto.base58.decode_check(b), trezor.utils.unhexlify('a'))
def test_encode_check(self):
for a, b in self.vectors:
self.assertEqual(trezor.crypto.base58.encode_check(trezor.utils.unhexlify('a')), b)
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,19 @@
import sys
sys.path.append('..')
sys.path.append('../lib')
import unittest
import trezor.utils
import trezor.crypto.sha256
class TestCryptoSha256(unittest.TestCase):
# vectors from http://www.di-mgt.com.au/sha_testvectors.html
def test_hash(self):
self.assertEqual(trezor.crypto.sha256.hash(b''), trezor.utils.unhexlify('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'))
self.assertEqual(trezor.crypto.sha256.hash(b'abc'), trezor.utils.unhexlify('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'))
self.assertEqual(trezor.crypto.sha256.hash(b'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'), trezor.utils.unhexlify('248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1'))
self.assertEqual(trezor.crypto.sha256.hash(b'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu'), trezor.utils.unhexlify('cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1'))
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,19 @@
import sys
sys.path.append('..')
sys.path.append('../lib')
import unittest
import trezor.utils
import trezor.crypto.sha512
class TestCryptoSha512(unittest.TestCase):
# vectors from http://www.di-mgt.com.au/sha_testvectors.html
def test_hash(self):
self.assertEqual(trezor.crypto.sha512.hash(b''), trezor.utils.unhexlify('cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e'))
self.assertEqual(trezor.crypto.sha512.hash(b'abc'), trezor.utils.unhexlify('ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f'))
self.assertEqual(trezor.crypto.sha512.hash(b'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'), trezor.utils.unhexlify('204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445'))
self.assertEqual(trezor.crypto.sha512.hash(b'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu'), trezor.utils.unhexlify('8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909'))
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,6 @@
from TrezorCrypto import Sha512
_sha512 = Sha512()
def hash(data):
return _sha512.hash(data)