From 9c921c073f71858ab924d01abc2ac6340a840b5e Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 24 Oct 2016 12:08:12 +0200 Subject: [PATCH] modtrezorcrypto: add generate_secret methods to curves --- .../modtrezorcrypto-curve25519.h | 19 +++++++++++++++++++ .../modtrezorcrypto/modtrezorcrypto-ed25519.h | 19 +++++++++++++++++++ .../modtrezorcrypto-nist256p1.h | 19 +++++++++++++++++++ .../modtrezorcrypto-secp256k1.h | 19 +++++++++++++++++++ src/tests/test_crypto_curve25519.py | 14 ++++++++------ src/tests/test_crypto_ed25519.py | 15 +++++++++++++++ src/tests/test_crypto_nist256p1.py | 7 +++++++ src/tests/test_crypto_secp256k1.py | 7 +++++++ 8 files changed, 113 insertions(+), 6 deletions(-) diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-curve25519.h b/extmod/modtrezorcrypto/modtrezorcrypto-curve25519.h index 5e892e866..338ea4e41 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-curve25519.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-curve25519.h @@ -9,6 +9,8 @@ #include "trezor-crypto/curve25519-donna/curve25519-donna.h" +#include "rand.h" + typedef struct _mp_obj_Curve25519_t { mp_obj_base_t base; } mp_obj_Curve25519_t; @@ -20,6 +22,22 @@ STATIC mp_obj_t mod_TrezorCrypto_Curve25519_make_new(const mp_obj_type_t *type, return MP_OBJ_FROM_PTR(o); } +/// def trezor.crypto.curve.curve25519.generate_secret() -> bytes: +/// ''' +/// Generate secret key. +/// ''' +STATIC mp_obj_t mod_TrezorCrypto_Curve25519_generate_secret(mp_obj_t self) { + vstr_t vstr; + vstr_init_len(&vstr, 32); + random_buffer((uint8_t *)vstr.buf, 32); + // taken from https://cr.yp.to/ecdh.html + vstr.buf[0] &= 248; + vstr.buf[31] &= 127; + vstr.buf[31] |= 64; + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_TrezorCrypto_Curve25519_generate_secret_obj, mod_TrezorCrypto_Curve25519_generate_secret); + /// def trezor.crypto.curve.curve25519.publickey(secret_key: bytes) -> bytes: /// ''' /// Computes public key from secret key. @@ -60,6 +78,7 @@ STATIC mp_obj_t mod_TrezorCrypto_Curve25519_multiply(mp_obj_t self, mp_obj_t sec STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorCrypto_Curve25519_multiply_obj, mod_TrezorCrypto_Curve25519_multiply); STATIC const mp_rom_map_elem_t mod_TrezorCrypto_Curve25519_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_generate_secret), MP_ROM_PTR(&mod_TrezorCrypto_Curve25519_generate_secret_obj) }, { MP_ROM_QSTR(MP_QSTR_publickey), MP_ROM_PTR(&mod_TrezorCrypto_Curve25519_publickey_obj) }, { MP_ROM_QSTR(MP_QSTR_multiply), MP_ROM_PTR(&mod_TrezorCrypto_Curve25519_multiply_obj) }, }; diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h b/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h index 242619d53..38133696b 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h @@ -9,6 +9,8 @@ #include "trezor-crypto/ed25519-donna/ed25519.h" +#include "rand.h" + typedef struct _mp_obj_Ed25519_t { mp_obj_base_t base; } mp_obj_Ed25519_t; @@ -20,6 +22,22 @@ STATIC mp_obj_t mod_TrezorCrypto_Ed25519_make_new(const mp_obj_type_t *type, siz return MP_OBJ_FROM_PTR(o); } +/// def trezor.crypto.curve.ed25519.generate_secret() -> bytes: +/// ''' +/// Generate secret key. +/// ''' +STATIC mp_obj_t mod_TrezorCrypto_Ed25519_generate_secret(mp_obj_t self) { + vstr_t vstr; + vstr_init_len(&vstr, 32); + random_buffer((uint8_t *)vstr.buf, 32); + // taken from https://cr.yp.to/ecdh.html + vstr.buf[0] &= 248; + vstr.buf[31] &= 127; + vstr.buf[31] |= 64; + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_TrezorCrypto_Ed25519_generate_secret_obj, mod_TrezorCrypto_Ed25519_generate_secret); + /// def trezor.crypto.curve.ed25519.publickey(secret_key: bytes) -> bytes: /// ''' /// Computes public key from secret key. @@ -84,6 +102,7 @@ STATIC mp_obj_t mod_TrezorCrypto_Ed25519_verify(size_t n_args, const mp_obj_t *a STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorCrypto_Ed25519_verify_obj, 4, 4, mod_TrezorCrypto_Ed25519_verify); STATIC const mp_rom_map_elem_t mod_TrezorCrypto_Ed25519_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_generate_secret), MP_ROM_PTR(&mod_TrezorCrypto_Ed25519_generate_secret_obj) }, { MP_ROM_QSTR(MP_QSTR_publickey), MP_ROM_PTR(&mod_TrezorCrypto_Ed25519_publickey_obj) }, { MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_TrezorCrypto_Ed25519_sign_obj) }, { MP_ROM_QSTR(MP_QSTR_verify), MP_ROM_PTR(&mod_TrezorCrypto_Ed25519_verify_obj) }, diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h b/extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h index 498290eb7..bf829af4c 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h @@ -21,6 +21,24 @@ STATIC mp_obj_t mod_TrezorCrypto_Nist256p1_make_new(const mp_obj_type_t *type, s return MP_OBJ_FROM_PTR(o); } +/// def trezor.crypto.curve.nist256p1.generate_secret() -> bytes: +/// ''' +/// Generate secret key. +/// ''' +STATIC mp_obj_t mod_TrezorCrypto_Nist256p1_generate_secret(mp_obj_t self) { + vstr_t vstr; + vstr_init_len(&vstr, 32); + for (;;) { + random_buffer((uint8_t *)vstr.buf, 32); + // check whether secret > 0 && secret < curve_order + if (0 == memcmp(vstr.buf, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32)) continue; + if (0 <= memcmp(vstr.buf, "\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xBC\xE6\xFA\xAD\xA7\x17\x9E\x84\xF3\xB9\xCA\xC2\xFC\x63\x25\x51", 32)) continue; + break; + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_TrezorCrypto_Nist256p1_generate_secret_obj, mod_TrezorCrypto_Nist256p1_generate_secret); + /// def trezor.crypto.curve.nist256p1.publickey(secret_key: bytes, compressed: bool=True) -> bytes: /// ''' /// Computes public key from secret key. @@ -117,6 +135,7 @@ STATIC mp_obj_t mod_TrezorCrypto_Nist256p1_multiply(mp_obj_t self, mp_obj_t secr STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorCrypto_Nist256p1_multiply_obj, mod_TrezorCrypto_Nist256p1_multiply); STATIC const mp_rom_map_elem_t mod_TrezorCrypto_Nist256p1_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_generate_secret), MP_ROM_PTR(&mod_TrezorCrypto_Nist256p1_generate_secret_obj) }, { MP_ROM_QSTR(MP_QSTR_publickey), MP_ROM_PTR(&mod_TrezorCrypto_Nist256p1_publickey_obj) }, { MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_TrezorCrypto_Nist256p1_sign_obj) }, { MP_ROM_QSTR(MP_QSTR_verify), MP_ROM_PTR(&mod_TrezorCrypto_Nist256p1_verify_obj) }, diff --git a/extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h b/extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h index 592feb53f..e1f3e4994 100644 --- a/extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h +++ b/extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h @@ -21,6 +21,24 @@ STATIC mp_obj_t mod_TrezorCrypto_Secp256k1_make_new(const mp_obj_type_t *type, s return MP_OBJ_FROM_PTR(o); } +/// def trezor.crypto.curve.secp256k1.generate_secret() -> bytes: +/// ''' +/// Generate secret key. +/// ''' +STATIC mp_obj_t mod_TrezorCrypto_Secp256k1_generate_secret(mp_obj_t self) { + vstr_t vstr; + vstr_init_len(&vstr, 32); + for (;;) { + random_buffer((uint8_t *)vstr.buf, 32); + // check whether secret > 0 && secret < curve_order + if (0 == memcmp(vstr.buf, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32)) continue; + if (0 <= memcmp(vstr.buf, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xBA\xAE\xDC\xE6\xAF\x48\xA0\x3B\xBF\xD2\x5E\x8C\xD0\x36\x41\x41", 32)) continue; + break; + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_TrezorCrypto_Secp256k1_generate_secret_obj, mod_TrezorCrypto_Secp256k1_generate_secret); + /// def trezor.crypto.curve.secp256k1.publickey(secret_key: bytes, compressed: bool=True) -> bytes: /// ''' /// Computes public key from secret key. @@ -117,6 +135,7 @@ STATIC mp_obj_t mod_TrezorCrypto_Secp256k1_multiply(mp_obj_t self, mp_obj_t secr STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorCrypto_Secp256k1_multiply_obj, mod_TrezorCrypto_Secp256k1_multiply); STATIC const mp_rom_map_elem_t mod_TrezorCrypto_Secp256k1_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_generate_secret), MP_ROM_PTR(&mod_TrezorCrypto_Secp256k1_generate_secret_obj) }, { MP_ROM_QSTR(MP_QSTR_publickey), MP_ROM_PTR(&mod_TrezorCrypto_Secp256k1_publickey_obj) }, { MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_TrezorCrypto_Secp256k1_sign_obj) }, { MP_ROM_QSTR(MP_QSTR_verify), MP_ROM_PTR(&mod_TrezorCrypto_Secp256k1_verify_obj) }, diff --git a/src/tests/test_crypto_curve25519.py b/src/tests/test_crypto_curve25519.py index 3d0ce144a..29700418c 100644 --- a/src/tests/test_crypto_curve25519.py +++ b/src/tests/test_crypto_curve25519.py @@ -5,7 +5,6 @@ import unittest from ubinascii import unhexlify from trezor.crypto.curve import curve25519 -from trezor.crypto import random class TestCryptoCurve25519(unittest.TestCase): @@ -13,6 +12,12 @@ class TestCryptoCurve25519(unittest.TestCase): ('38c9d9b17911de26ed812f5cc19c0029e8d016bcbc6078bc9db2af33f1761e4a', '311b6248af8dabec5cc81eac5bf229925f6d218a12e0547fb1856e015cc76f5d', 'a93dbdb23e5c99da743e203bd391af79f2b83fb8d0fd6ec813371c71f08f2d4d'), ] + def test_generate_secret(self): + for _ in range(100): + sk = curve25519.generate_secret() + self.assertTrue(len(sk) == 32) + self.assertTrue(sk[0] & 7 == 0 and sk[31] & 128 == 0 and sk[31] & 64 == 64) + def test_multiply(self): for sk, pk, session in self.vectors: session2 = curve25519.multiply(unhexlify(sk), unhexlify(pk)) @@ -20,11 +25,8 @@ class TestCryptoCurve25519(unittest.TestCase): def test_multiply_random(self): for _ in range(100): - sk1 = bytearray(random.bytes(32)) - sk2 = bytearray(random.bytes(32)) - # taken from https://cr.yp.to/ecdh.html - sk1[0] &= 248 ; sk1[31] &= 127 ; sk1[31] |= 64 - sk2[0] &= 248 ; sk2[31] &= 127 ; sk2[31] |= 64 + sk1 = curve25519.generate_secret() + sk2 = curve25519.generate_secret() pk1 = curve25519.publickey(sk1) pk2 = curve25519.publickey(sk2) session1 = curve25519.multiply(sk1, pk2) diff --git a/src/tests/test_crypto_ed25519.py b/src/tests/test_crypto_ed25519.py index 15ad0cc9c..2fc8d633f 100644 --- a/src/tests/test_crypto_ed25519.py +++ b/src/tests/test_crypto_ed25519.py @@ -5,6 +5,7 @@ import unittest from ubinascii import unhexlify from trezor.crypto.curve import ed25519 +from trezor.crypto import random class TestCryptoEd25519(unittest.TestCase): @@ -36,5 +37,19 @@ class TestCryptoEd25519(unittest.TestCase): self.assertTrue(ed25519.verify(unhexlify(pk), unhexlify(sig), unhexlify(pk))) pass + def test_generate_secret(self): + for _ in range(100): + sk = ed25519.generate_secret() + self.assertTrue(len(sk) == 32) + self.assertTrue(sk[0] & 7 == 0 and sk[31] & 128 == 0 and sk[31] & 64 == 64) + + def test_random(self): + for l in range(1, 300): + sk = ed25519.generate_secret() + pk = ed25519.publickey(sk) + msg = random.bytes(l) + sig = ed25519.sign(sk, msg) + self.assertTrue(ed25519.verify(pk, sig, msg)) + if __name__ == '__main__': unittest.main() diff --git a/src/tests/test_crypto_nist256p1.py b/src/tests/test_crypto_nist256p1.py index 499cc9841..05deda3be 100644 --- a/src/tests/test_crypto_nist256p1.py +++ b/src/tests/test_crypto_nist256p1.py @@ -64,6 +64,13 @@ class TestCryptoNist256p1(unittest.TestCase): (115792089210356248762697446949407573529996955224135760342422259061068512044368, '6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296B01CBD1C01E58065711814B583F061E9D431CCA994CEA1313449BF97C840AE0A'), ] + def test_generate_secret(self): + for _ in range(100): + sk = nist256p1.generate_secret() + self.assertTrue(len(sk) == 32) + self.assertTrue(sk != b'\x00' * 32) + self.assertTrue(sk < b'\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xBC\xE6\xFA\xAD\xA7\x17\x9E\x84\xF3\xB9\xCA\xC2\xFC\x63\x25\x51') + def test_publickey(self): for sk, pk in self.vectors: sk = hex(sk)[2:] diff --git a/src/tests/test_crypto_secp256k1.py b/src/tests/test_crypto_secp256k1.py index 63e6d5cc2..18e1276d2 100644 --- a/src/tests/test_crypto_secp256k1.py +++ b/src/tests/test_crypto_secp256k1.py @@ -57,6 +57,13 @@ class TestCryptoSecp256k1(unittest.TestCase): (115792089237316195423570985008687907852837564279074904382605163141518161494336, '79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798B7C52588D95C3B9AA25B0403F1EEF75702E84BB7597AABE663B82F6F04EF2777'), ] + def test_generate_secret(self): + for _ in range(100): + sk = secp256k1.generate_secret() + self.assertTrue(len(sk) == 32) + self.assertTrue(sk != b'\x00' * 32) + self.assertTrue(sk < b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xBA\xAE\xDC\xE6\xAF\x48\xA0\x3B\xBF\xD2\x5E\x8C\xD0\x36\x41\x41') + def test_publickey(self): for sk, pk in self.vectors: sk = hex(sk)[2:]