mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-26 09:28:13 +00:00
trezor.crypto: curve.nist256p1 and curve.secp256k1 now sign/verify 256-bit digests, not arbitrary length messages
This commit is contained in:
parent
1bb20c2521
commit
8d1109986c
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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!)
|
||||||
|
'''
|
||||||
|
0
mocks/trezor/crypto/.mock-generated
Normal file
0
mocks/trezor/crypto/.mock-generated
Normal 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:
|
||||||
'''
|
'''
|
||||||
|
0
mocks/trezor/crypto/__init__.py
Normal file
0
mocks/trezor/crypto/__init__.py
Normal 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.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
@ -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.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
@ -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()
|
||||||
|
Loading…
Reference in New Issue
Block a user