Skip to content

Commit

Permalink
Merge pull request #502 from Foundation-Devices/jeandudey/sft-3618-us…
Browse files Browse the repository at this point in the history
…e-only-rust-secp256k1

SFT-3618: Use only rust-secp256k1.
  • Loading branch information
jeandudey committed May 15, 2024
2 parents 247adfc + 059eb58 commit c166616
Show file tree
Hide file tree
Showing 15 changed files with 146 additions and 31 deletions.
1 change: 1 addition & 0 deletions extmod/foundation-rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion extmod/foundation-rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ license = "GPL-3.0-or-later"
name = "sizes"
required-features = ["std"]

[dependencies.bitcoin_hashes]
version = "0.13"
features = ["small-hash"]
default-features = false

[dependencies.minicbor]
version = "0.20"
default-features = false
Expand Down Expand Up @@ -46,7 +51,7 @@ features = ["critical-section"]
[dependencies.secp256k1]
version = "0.27"
default-features = false
features = ["rand"]
features = ["lowmemory", "rand"]

[dependencies.rand]
version = "0.8.5"
Expand Down
23 changes: 22 additions & 1 deletion extmod/foundation-rust/include/foundation.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,14 +360,35 @@ extern UR_Decoder UR_DECODER;

extern UR_Encoder UR_ENCODER;

/**
* Calculate a "Schnorr" public key from the secret key.
*
* See also:
*
* - https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki#user-content-Public_Key_Conversion
*/
void foundation_secp256k1_public_key_schnorr(const uint8_t (*secret_key)[32],
uint8_t (*public_key)[32]);

/**
* Computes a ECDSA signature over the message `data`.
*
* - `data` is the message hash.
* - `secret_key` is the secret key used to sign the message.
* - `signature` is the output of the resulting signature.
*/
void foundation_secp256k1_sign_ecdsa(const uint8_t (*data)[32],
const uint8_t (*secret_key)[32],
uint8_t (*signature)[64]);

/**
* Computes a Schnorr signature over the message `data`.
*
* - `data` is the message hash.
* - `secret_key` is the secret key used to sign the message.
* - `signature` is the output of the resulting signature.
*/
void foundation_secp256k1_schnorr_sign(const uint8_t (*data)[32],
void foundation_secp256k1_sign_schnorr(const uint8_t (*data)[32],
const uint8_t (*secret_key)[32],
uint8_t (*signature)[64]);

Expand Down
38 changes: 37 additions & 1 deletion extmod/foundation-rust/src/secp256k1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use core::ptr;
use once_cell::sync::Lazy;
use secp256k1::{
ffi::types::AlignedType, AllPreallocated, KeyPair, Message, Secp256k1,
SecretKey,
};

/// cbindgen:ignore
Expand All @@ -24,12 +25,47 @@ static PRE_ALLOCATED_CTX: Lazy<Secp256k1<AllPreallocated<'static>>> =
.expect("the pre-allocated context buf should have enough space")
});

/// Calculate a "Schnorr" public key from the secret key.
///
/// See also:
///
/// - https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki#user-content-Public_Key_Conversion
#[export_name = "foundation_secp256k1_public_key_schnorr"]
pub extern "C" fn secp256k1_public_key_schnorr(
secret_key: &[u8; 32],
public_key: &mut [u8; 32],
) {
let keypair = KeyPair::from_seckey_slice(&PRE_ALLOCATED_CTX, secret_key)
.expect("invalid secret key");
let compressed_key = keypair.public_key().serialize();
public_key.copy_from_slice(&compressed_key[1..]);
}

/// Computes a ECDSA signature over the message `data`.
///
/// - `data` is the message hash.
/// - `secret_key` is the secret key used to sign the message.
/// - `signature` is the output of the resulting signature.
#[export_name = "foundation_secp256k1_sign_ecdsa"]
pub extern "C" fn secp256k1_sign_ecdsa(
data: &[u8; 32],
secret_key: &[u8; 32],
signature: &mut [u8; 64],
) {
let secret_key =
SecretKey::from_slice(secret_key).expect("invalid secret key");

let msg = Message::from_slice(data).unwrap();
let sig = PRE_ALLOCATED_CTX.sign_ecdsa(&msg, &secret_key);
signature.copy_from_slice(&sig.serialize_compact());
}

/// Computes a Schnorr signature over the message `data`.
///
/// - `data` is the message hash.
/// - `secret_key` is the secret key used to sign the message.
/// - `signature` is the output of the resulting signature.
#[export_name = "foundation_secp256k1_schnorr_sign"]
#[export_name = "foundation_secp256k1_sign_schnorr"]
pub extern "C" fn secp256k1_sign_schnorr(
data: &[u8; 32],
secret_key: &[u8; 32],
Expand Down
51 changes: 49 additions & 2 deletions extmod/foundation/modfoundation-secp56k1.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,51 @@

#include "foundation.h"

/// def public_key(secret_key) -> bytes:
STATIC mp_obj_t mod_foundation_secp256k1_public_key_schnorr(mp_obj_t secret_key_obj)
{
uint8_t public_key[32];
mp_buffer_info_t secret_key;

mp_get_buffer_raise(secret_key_obj, &secret_key, MP_BUFFER_READ);
if (secret_key.len != 32) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("secret key should be 32 bytes"));
}

foundation_secp256k1_public_key_schnorr(secret_key.buf, &public_key);
return mp_obj_new_bytes(public_key, 32);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_foundation_secp256k1_public_key_schnorr_obj,
mod_foundation_secp256k1_public_key_schnorr);

/// def sign_ecdsa(data, secret_key) -> bytes:
STATIC mp_obj_t mod_foundation_secp256k1_sign_ecdsa(mp_obj_t data_obj,
mp_obj_t secret_key_obj)
{
mp_buffer_info_t data;
mp_buffer_info_t secret_key;
uint8_t signature[64];

mp_get_buffer_raise(data_obj, &data, MP_BUFFER_READ);
mp_get_buffer_raise(secret_key_obj, &secret_key, MP_BUFFER_READ);

if (data.len != 32) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("data should be 32 bytes"));
}

if (secret_key.len != 32) {
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("secret key should be 32 bytes"));
}

foundation_secp256k1_sign_ecdsa(data.buf,
secret_key.buf,
&signature);

return mp_obj_new_bytes(signature, sizeof(signature));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_foundation_secp256k1_sign_ecdsa_obj,
mod_foundation_secp256k1_sign_ecdsa);

/// def sign_schnorr(data, secret_key) -> bytes:
/// """
/// """
Expand All @@ -24,7 +69,7 @@ STATIC mp_obj_t mod_foundation_secp256k1_sign_schnorr(mp_obj_t data_obj,
mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("secret key should be 32 bytes"));
}

foundation_secp256k1_schnorr_sign(data.buf,
foundation_secp256k1_sign_schnorr(data.buf,
secret_key.buf,
&signature);

Expand All @@ -34,7 +79,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_foundation_secp256k1_sign_schnorr_obj,
mod_foundation_secp256k1_sign_schnorr);

STATIC const mp_rom_map_elem_t mod_foundation_secp256k1_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_schnorr_sign), MP_ROM_PTR(&mod_foundation_secp256k1_sign_schnorr_obj) },
{ MP_ROM_QSTR(MP_QSTR_public_key_schnorr), MP_ROM_PTR(&mod_foundation_secp256k1_public_key_schnorr_obj) },
{ MP_ROM_QSTR(MP_QSTR_sign_ecdsa), MP_ROM_PTR(&mod_foundation_secp256k1_sign_ecdsa_obj) },
{ MP_ROM_QSTR(MP_QSTR_sign_schnorr), MP_ROM_PTR(&mod_foundation_secp256k1_sign_schnorr_obj) },
};
STATIC MP_DEFINE_CONST_DICT(mod_foundation_secp256k1_globals, mod_foundation_secp256k1_globals_table);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ static void wrapped_ui_wait_callback(uint32_t current, uint32_t total) {
}
}

#define FOUNDATION_ADDITIONS

#include "modtrezorcrypto-aes.h"
#include "modtrezorcrypto-bip32.h"
#include "modtrezorcrypto-bip340.h"
Expand All @@ -56,7 +54,9 @@ static void wrapped_ui_wait_callback(uint32_t current, uint32_t total) {
#include "modtrezorcrypto-pbkdf2.h"
#include "modtrezorcrypto-random.h"
#include "modtrezorcrypto-ripemd160.h"
#ifndef FOUNDATION_ADDITIONS
#include "modtrezorcrypto-secp256k1.h"
#endif
#include "modtrezorcrypto-sha1.h"
#include "modtrezorcrypto-sha256.h"
#if USE_KECCAK
Expand Down Expand Up @@ -116,9 +116,9 @@ STATIC const mp_rom_map_elem_t mp_module_trezorcrypto_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mod_trezorcrypto_random_module)},
{MP_ROM_QSTR(MP_QSTR_ripemd160),
MP_ROM_PTR(&mod_trezorcrypto_Ripemd160_type)},
#ifndef FOUNDATION_ADDITIONS
{MP_ROM_QSTR(MP_QSTR_secp256k1),
MP_ROM_PTR(&mod_trezorcrypto_secp256k1_module)},
#ifndef FOUNDATION_ADDITIONS
{MP_ROM_QSTR(MP_QSTR_bip340), MP_ROM_PTR(&mod_trezorcrypto_bip340_module)},
{MP_ROM_QSTR(MP_QSTR_sha1), MP_ROM_PTR(&mod_trezorcrypto_Sha1_type)},
#endif // FOUNDATION_ADDITIONS
Expand Down
4 changes: 4 additions & 0 deletions extmod/trezor-firmware/crypto/bip32.c
Original file line number Diff line number Diff line change
Expand Up @@ -785,20 +785,24 @@ const curve_info *get_curve_by_name(const char *curve_name) {
if (strcmp(curve_name, SECP256K1_NAME) == 0) {
return &secp256k1_info;
}
#ifndef FOUNDATION_ADDITIONS
if (strcmp(curve_name, SECP256K1_DECRED_NAME) == 0) {
return &secp256k1_decred_info;
}
if (strcmp(curve_name, SECP256K1_GROESTL_NAME) == 0) {
return &secp256k1_groestl_info;
}
#endif
#if USE_KECCAK
if (strcmp(curve_name, SECP256K1_SMART_NAME) == 0) {
return &secp256k1_smart_info;
}
#endif
#ifndef FOUNDATION_ADDITIONS
if (strcmp(curve_name, NIST256P1_NAME) == 0) {
return &nist256p1_info;
}
#endif
if (strcmp(curve_name, ED25519_NAME) == 0) {
return &ed25519_info;
}
Expand Down
6 changes: 6 additions & 0 deletions extmod/trezor-firmware/crypto/hasher.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ void hasher_InitParam(Hasher *hasher, HasherType type, const void *param,
#endif
sha3_256_Init(&hasher->ctx.sha3);
break;
#ifndef FOUNDATION_ADDITIONS
case HASHER_BLAKE:
case HASHER_BLAKED:
case HASHER_BLAKE_RIPEMD:
Expand All @@ -64,6 +65,7 @@ void hasher_InitParam(Hasher *hasher, HasherType type, const void *param,
blake2b_InitPersonal(&hasher->ctx.blake2b, 32, hasher->param,
hasher->param_size);
break;
#endif
}
}

Expand All @@ -89,6 +91,7 @@ void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) {
#endif
sha3_Update(&hasher->ctx.sha3, data, length);
break;
#ifndef FOUNDATION_ADDITIONS
case HASHER_BLAKE:
case HASHER_BLAKED:
case HASHER_BLAKE_RIPEMD:
Expand All @@ -101,6 +104,7 @@ void hasher_Update(Hasher *hasher, const uint8_t *data, size_t length) {
case HASHER_BLAKE2B_PERSONAL:
blake2b_Update(&hasher->ctx.blake2b, data, length);
break;
#endif
}
}

Expand All @@ -126,6 +130,7 @@ void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) {
keccak_Final(&hasher->ctx.sha3, hash);
break;
#endif
#ifndef FOUNDATION_ADDITIONS
case HASHER_BLAKE:
blake256_Final(&hasher->ctx.blake, hash);
break;
Expand All @@ -144,6 +149,7 @@ void hasher_Final(Hasher *hasher, uint8_t hash[HASHER_DIGEST_LENGTH]) {
case HASHER_BLAKE2B_PERSONAL:
blake2b_Final(&hasher->ctx.blake2b, hash, 32);
break;
#endif
}
}

Expand Down
2 changes: 2 additions & 0 deletions extmod/trezor-firmware/crypto/hasher.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ typedef enum {
HASHER_SHA3K,
#endif

#ifndef FOUNDATION_ADDITIONS
HASHER_BLAKE,
HASHER_BLAKED,
HASHER_BLAKE_RIPEMD,
Expand All @@ -53,6 +54,7 @@ typedef enum {

HASHER_BLAKE2B,
HASHER_BLAKE2B_PERSONAL,
#endif
} HasherType;

typedef struct {
Expand Down
2 changes: 2 additions & 0 deletions extmod/trezor-firmware/crypto/secp256k1.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ const curve_info secp256k1_info = {
.hasher_script = HASHER_SHA2,
};

#ifndef FOUNDATION_ADDITIONS
const curve_info secp256k1_decred_info = {
.bip32_name = "Bitcoin seed",
.params = &secp256k1,
Expand All @@ -83,6 +84,7 @@ const curve_info secp256k1_groestl_info = {
.hasher_pubkey = HASHER_SHA2_RIPEMD,
.hasher_script = HASHER_SHA2,
};
#endif

#if USE_KECCAK
const curve_info secp256k1_smart_info = {
Expand Down
2 changes: 1 addition & 1 deletion ports/stm32/boards/Passport/modules/taproot.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def taproot_sign_key(script_tree, internal_seckey, hash_type, sighash):
else:
_, h = taproot_tree_helper(script_tree)
output_seckey = taproot_tweak_seckey(internal_seckey, h)
sig = secp256k1.schnorr_sign(sighash, output_seckey)
sig = secp256k1.sign_schnorr(sighash, output_seckey)
if hash_type != 0:
sig += bytes([hash_type])
return sig
Expand Down
5 changes: 3 additions & 2 deletions ports/stm32/boards/Passport/modules/tasks/nostr_key_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@

async def nostr_key_task(on_done, index):
import stash
from utils import nostr_pubkey_from_pk, nostr_nip19_from_key
from foundation import secp256k1
from utils import nostr_nip19_from_key

path = "m/44'/1237'/{}'/0/0".format(index)
with stash.SensitiveValues() as sv:
node = sv.derive_path(path)
key = node.private_key()
pub = nostr_pubkey_from_pk(key)
pub = secp256k1.public_key_schnorr(key)
nsec = nostr_nip19_from_key(key, "nsec")
npub = nostr_nip19_from_key(pub, "npub")
await on_done({'priv': nsec, 'npub': npub, 'pk': key, 'pub': pub}, None)
9 changes: 4 additions & 5 deletions ports/stm32/boards/Passport/modules/tasks/sign_psbt_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ async def sign_psbt_task(on_done, psbt):
from errors import Error
from utils import keypath_to_str, swab32
from serializations import ser_sig_der
import trezorcrypto
import stash
import gc
from foundation import secp256k1
Expand Down Expand Up @@ -122,14 +121,14 @@ async def sign_psbt_task(on_done, psbt):
# TODO: handle taproot scripts
inp.tap_key_sig = taproot_sign_key(None, pk, inp.sighash, digest)
else:
result = trezorcrypto.secp256k1.sign(pk, digest)
result = secp256k1.sign_ecdsa(digest, pk)

# convert signature to DER format
if len(result) != 65:
if len(result) != 64:
raise AssertionError('Incorrect signature length.')

r = result[1:33]
s = result[33:65]
r = result[0:32]
s = result[32:64]

inp.added_sig = (which_key, ser_sig_der(r, s, inp.sighash))

Expand Down
Loading

0 comments on commit c166616

Please sign in to comment.