trezor.crypto: curve.nist256p1 and curve.secp256k1 now sign/verify 256-bit digests, not arbitrary length messages

This commit is contained in:
Pavol Rusnak 2016-11-08 15:37:48 +01:00
parent 1bb20c2521
commit 8d1109986c
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
10 changed files with 90 additions and 46 deletions

View File

@ -62,24 +62,24 @@ STATIC mp_obj_t mod_TrezorCrypto_Nist256p1_publickey(size_t n_args, const mp_obj
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorCrypto_Nist256p1_publickey_obj, 2, 3, mod_TrezorCrypto_Nist256p1_publickey); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorCrypto_Nist256p1_publickey_obj, 2, 3, mod_TrezorCrypto_Nist256p1_publickey);
/// def trezor.crypto.curve.nist256p1.sign(secret_key: bytes, message: bytes) -> bytes: /// def trezor.crypto.curve.nist256p1.sign(secret_key: bytes, digest: bytes) -> bytes:
/// ''' /// '''
/// Uses secret key to produce the signature of message. /// Uses secret key to produce the signature of the digest.
/// ''' /// '''
STATIC mp_obj_t mod_TrezorCrypto_Nist256p1_sign(mp_obj_t self, mp_obj_t secret_key, mp_obj_t message) { STATIC mp_obj_t mod_TrezorCrypto_Nist256p1_sign(mp_obj_t self, mp_obj_t secret_key, mp_obj_t digest) {
mp_buffer_info_t sk, msg; mp_buffer_info_t sk, dig;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ); mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
mp_get_buffer_raise(message, &msg, MP_BUFFER_READ); mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
if (sk.len != 32) { if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key"); mp_raise_ValueError("Invalid length of secret key");
} }
if (msg.len == 0) { if (dig.len != 32) {
mp_raise_ValueError("Empty data to sign"); mp_raise_ValueError("Invalid length of digest");
} }
vstr_t vstr; vstr_t vstr;
vstr_init_len(&vstr, 65); vstr_init_len(&vstr, 65);
uint8_t pby; uint8_t pby;
if (0 != ecdsa_sign(&nist256p1, (const uint8_t *)sk.buf, (const uint8_t *)msg.buf, msg.len, (uint8_t *)vstr.buf, &pby, NULL)) { // TODO: is_canonical if (0 != ecdsa_sign_digest(&nist256p1, (const uint8_t *)sk.buf, (const uint8_t *)dig.buf, (uint8_t *)vstr.buf, &pby, NULL)) { // TODO: is_canonical
mp_raise_ValueError("Signing failed"); mp_raise_ValueError("Signing failed");
} }
(void)pby; (void)pby;
@ -87,26 +87,26 @@ STATIC mp_obj_t mod_TrezorCrypto_Nist256p1_sign(mp_obj_t self, mp_obj_t secret_k
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorCrypto_Nist256p1_sign_obj, mod_TrezorCrypto_Nist256p1_sign); STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorCrypto_Nist256p1_sign_obj, mod_TrezorCrypto_Nist256p1_sign);
/// def trezor.crypto.curve.nist256p1.verify(public_key: bytes, signature: bytes, message: bytes) -> bool: /// def trezor.crypto.curve.nist256p1.verify(public_key: bytes, signature: bytes, digest: bytes) -> bool:
/// ''' /// '''
/// Uses public key to verify the signature of the message /// Uses public key to verify the signature of the digest.
/// Returns True on success. /// Returns True on success.
/// ''' /// '''
STATIC mp_obj_t mod_TrezorCrypto_Nist256p1_verify(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_TrezorCrypto_Nist256p1_verify(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t pk, sig, msg; mp_buffer_info_t pk, sig, dig;
mp_get_buffer_raise(args[1], &pk, MP_BUFFER_READ); mp_get_buffer_raise(args[1], &pk, MP_BUFFER_READ);
mp_get_buffer_raise(args[2], &sig, MP_BUFFER_READ); mp_get_buffer_raise(args[2], &sig, MP_BUFFER_READ);
mp_get_buffer_raise(args[3], &msg, MP_BUFFER_READ); mp_get_buffer_raise(args[3], &dig, MP_BUFFER_READ);
if (pk.len != 33 && pk.len != 65) { if (pk.len != 33 && pk.len != 65) {
mp_raise_ValueError("Invalid length of public key"); mp_raise_ValueError("Invalid length of public key");
} }
if (sig.len != 65) { if (sig.len != 65) {
mp_raise_ValueError("Invalid length of signature"); mp_raise_ValueError("Invalid length of signature");
} }
if (msg.len == 0) { if (dig.len != 32) {
mp_raise_ValueError("Empty data to verify"); mp_raise_ValueError("Invalid length of digest");
} }
return mp_obj_new_bool(0 == ecdsa_verify(&nist256p1, (const uint8_t *)pk.buf, (const uint8_t *)sig.buf, (const uint8_t *)msg.buf, msg.len)); return mp_obj_new_bool(0 == ecdsa_verify_digest(&nist256p1, (const uint8_t *)pk.buf, (const uint8_t *)sig.buf, (const uint8_t *)dig.buf));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorCrypto_Nist256p1_verify_obj, 4, 4, mod_TrezorCrypto_Nist256p1_verify); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorCrypto_Nist256p1_verify_obj, 4, 4, mod_TrezorCrypto_Nist256p1_verify);

View File

@ -62,24 +62,24 @@ STATIC mp_obj_t mod_TrezorCrypto_Secp256k1_publickey(size_t n_args, const mp_obj
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorCrypto_Secp256k1_publickey_obj, 2, 3, mod_TrezorCrypto_Secp256k1_publickey); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorCrypto_Secp256k1_publickey_obj, 2, 3, mod_TrezorCrypto_Secp256k1_publickey);
/// def trezor.crypto.curve.secp256k1.sign(secret_key: bytes, message: bytes) -> bytes: /// def trezor.crypto.curve.secp256k1.sign(secret_key: bytes, digest: bytes) -> bytes:
/// ''' /// '''
/// Uses secret key to produce the signature of message. /// Uses secret key to produce the signature of the digest.
/// ''' /// '''
STATIC mp_obj_t mod_TrezorCrypto_Secp256k1_sign(mp_obj_t self, mp_obj_t secret_key, mp_obj_t message) { STATIC mp_obj_t mod_TrezorCrypto_Secp256k1_sign(mp_obj_t self, mp_obj_t secret_key, mp_obj_t digest) {
mp_buffer_info_t sk, msg; mp_buffer_info_t sk, dig;
mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ); mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ);
mp_get_buffer_raise(message, &msg, MP_BUFFER_READ); mp_get_buffer_raise(digest, &dig, MP_BUFFER_READ);
if (sk.len != 32) { if (sk.len != 32) {
mp_raise_ValueError("Invalid length of secret key"); mp_raise_ValueError("Invalid length of secret key");
} }
if (msg.len == 0) { if (dig.len != 32) {
mp_raise_ValueError("Empty data to sign"); mp_raise_ValueError("Invalid length of digest");
} }
vstr_t vstr; vstr_t vstr;
vstr_init_len(&vstr, 65); vstr_init_len(&vstr, 65);
uint8_t pby; uint8_t pby;
if (0 != ecdsa_sign(&secp256k1, (const uint8_t *)sk.buf, (const uint8_t *)msg.buf, msg.len, (uint8_t *)vstr.buf, &pby, NULL)) { // TODO: is_canonical if (0 != ecdsa_sign_digest(&secp256k1, (const uint8_t *)sk.buf, (const uint8_t *)dig.buf, (uint8_t *)vstr.buf, &pby, NULL)) { // TODO: is_canonical
mp_raise_ValueError("Signing failed"); mp_raise_ValueError("Signing failed");
} }
(void)pby; (void)pby;
@ -87,26 +87,26 @@ STATIC mp_obj_t mod_TrezorCrypto_Secp256k1_sign(mp_obj_t self, mp_obj_t secret_k
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorCrypto_Secp256k1_sign_obj, mod_TrezorCrypto_Secp256k1_sign); STATIC MP_DEFINE_CONST_FUN_OBJ_3(mod_TrezorCrypto_Secp256k1_sign_obj, mod_TrezorCrypto_Secp256k1_sign);
/// def trezor.crypto.curve.secp256k1.verify(public_key: bytes, signature: bytes, message: bytes) -> bool: /// def trezor.crypto.curve.secp256k1.verify(public_key: bytes, signature: bytes, digest: bytes) -> bool:
/// ''' /// '''
/// Uses public key to verify the signature of the message /// Uses public key to verify the signature of the digest.
/// Returns True on success. /// Returns True on success.
/// ''' /// '''
STATIC mp_obj_t mod_TrezorCrypto_Secp256k1_verify(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t mod_TrezorCrypto_Secp256k1_verify(size_t n_args, const mp_obj_t *args) {
mp_buffer_info_t pk, sig, msg; mp_buffer_info_t pk, sig, dig;
mp_get_buffer_raise(args[1], &pk, MP_BUFFER_READ); mp_get_buffer_raise(args[1], &pk, MP_BUFFER_READ);
mp_get_buffer_raise(args[2], &sig, MP_BUFFER_READ); mp_get_buffer_raise(args[2], &sig, MP_BUFFER_READ);
mp_get_buffer_raise(args[3], &msg, MP_BUFFER_READ); mp_get_buffer_raise(args[3], &dig, MP_BUFFER_READ);
if (pk.len != 33 && pk.len != 65) { if (pk.len != 33 && pk.len != 65) {
mp_raise_ValueError("Invalid length of public key"); mp_raise_ValueError("Invalid length of public key");
} }
if (sig.len != 65) { if (sig.len != 65) {
mp_raise_ValueError("Invalid length of signature"); mp_raise_ValueError("Invalid length of signature");
} }
if (msg.len == 0) { if (dig.len != 32) {
mp_raise_ValueError("Empty data to verify"); mp_raise_ValueError("Invalid length of digest");
} }
return mp_obj_new_bool(0 == ecdsa_verify(&secp256k1, (const uint8_t *)pk.buf, (const uint8_t *)sig.buf, (const uint8_t *)msg.buf, msg.len)); return mp_obj_new_bool(0 == ecdsa_verify_digest(&secp256k1, (const uint8_t *)pk.buf, (const uint8_t *)sig.buf, (const uint8_t *)dig.buf));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorCrypto_Secp256k1_verify_obj, 4, 4, mod_TrezorCrypto_Secp256k1_verify); STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_TrezorCrypto_Secp256k1_verify_obj, 4, 4, mod_TrezorCrypto_Secp256k1_verify);

View File

@ -11,3 +11,9 @@ def set(app: int, key: int, value: bytes) -> None:
Sets a value of given key for given app. Sets a value of given key for given app.
Returns True on success. Returns True on success.
''' '''
# ../extmod/modtrezorconfig/modtrezorconfig.c
def wipe() -> None:
'''
Erases the whole config (use with caution!)
'''

View File

View File

@ -23,6 +23,12 @@ def serialize_private() -> str:
Serialize the private info HD node to base58 string. Serialize the private info HD node to base58 string.
''' '''
# ../extmod/modtrezorcrypto/modtrezorcrypto-bip32.h
def clone() -> HDNode:
'''
Returns a copy of the HD node.
'''
# ../extmod/modtrezorcrypto/modtrezorcrypto-bip32.h # ../extmod/modtrezorcrypto/modtrezorcrypto-bip32.h
def depth() -> int: def depth() -> int:
''' '''

View File

View File

@ -12,15 +12,15 @@ def publickey(secret_key: bytes, compressed: bool=True) -> bytes:
''' '''
# ../extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h # ../extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h
def sign(secret_key: bytes, message: bytes) -> bytes: def sign(secret_key: bytes, digest: bytes) -> bytes:
''' '''
Uses secret key to produce the signature of message. Uses secret key to produce the signature of the digest.
''' '''
# ../extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h # ../extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h
def verify(public_key: bytes, signature: bytes, message: bytes) -> bool: def verify(public_key: bytes, signature: bytes, digest: bytes) -> bool:
''' '''
Uses public key to verify the signature of the message Uses public key to verify the signature of the digest.
Returns True on success. Returns True on success.
''' '''

View File

@ -12,15 +12,15 @@ def publickey(secret_key: bytes, compressed: bool=True) -> bytes:
''' '''
# ../extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h # ../extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h
def sign(secret_key: bytes, message: bytes) -> bytes: def sign(secret_key: bytes, digest: bytes) -> bytes:
''' '''
Uses secret key to produce the signature of message. Uses secret key to produce the signature of the digest.
''' '''
# ../extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h # ../extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h
def verify(public_key: bytes, signature: bytes, message: bytes) -> bool: def verify(public_key: bytes, signature: bytes, digest: bytes) -> bool:
''' '''
Uses public key to verify the signature of the message Uses public key to verify the signature of the digest.
Returns True on success. Returns True on success.
''' '''

View File

@ -83,13 +83,29 @@ class TestCryptoNist256p1(unittest.TestCase):
else: else:
self.assertEqual(pk33, '03' + pk[:64]) self.assertEqual(pk33, '03' + pk[:64])
def test_sign_verify_min_max(self):
sk = nist256p1.generate_secret()
pk = nist256p1.publickey(sk)
dig = bytes([1] + [0]*31)
sig = nist256p1.sign(sk, dig)
self.assertTrue(nist256p1.verify(pk, sig, dig))
dig = bytes([0]*31 + [1])
sig = nist256p1.sign(sk, dig)
self.assertTrue(nist256p1.verify(pk, sig, dig))
dig = bytes([0xFF]*32)
sig = nist256p1.sign(sk, dig)
self.assertTrue(nist256p1.verify(pk, sig, dig))
def test_sign_verify_random(self): def test_sign_verify_random(self):
for l in range(1, 300): for _ in range(100):
sk = nist256p1.generate_secret() sk = nist256p1.generate_secret()
pk = nist256p1.publickey(sk) pk = nist256p1.publickey(sk)
msg = random.bytes(l) dig = random.bytes(32)
sig = nist256p1.sign(sk, msg) sig = nist256p1.sign(sk, dig)
self.assertTrue(nist256p1.verify(pk, sig, msg)) self.assertTrue(nist256p1.verify(pk, sig, dig))
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -76,13 +76,29 @@ class TestCryptoSecp256k1(unittest.TestCase):
else: else:
self.assertEqual(pk33, '03' + pk[:64]) self.assertEqual(pk33, '03' + pk[:64])
def test_sign_verify_min_max(self):
sk = secp256k1.generate_secret()
pk = secp256k1.publickey(sk)
dig = bytes([1] + [0]*31)
sig = secp256k1.sign(sk, dig)
self.assertTrue(secp256k1.verify(pk, sig, dig))
dig = bytes([0]*31 + [1])
sig = secp256k1.sign(sk, dig)
self.assertTrue(secp256k1.verify(pk, sig, dig))
dig = bytes([0xFF]*32)
sig = secp256k1.sign(sk, dig)
self.assertTrue(secp256k1.verify(pk, sig, dig))
def test_sign_verify_random(self): def test_sign_verify_random(self):
for l in range(1, 300): for _ in range(100):
sk = secp256k1.generate_secret() sk = secp256k1.generate_secret()
pk = secp256k1.publickey(sk) pk = secp256k1.publickey(sk)
msg = random.bytes(l) dig = random.bytes(32)
sig = secp256k1.sign(sk, msg) sig = secp256k1.sign(sk, dig)
self.assertTrue(secp256k1.verify(pk, sig, msg)) self.assertTrue(secp256k1.verify(pk, sig, dig))
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()