mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-06-09 09:38:46 +00:00
Merge branch 'release/22.08'
This commit is contained in:
commit
c962d3520b
@ -97,8 +97,8 @@ message ECDHSessionKey {
|
|||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message CosiCommit {
|
message CosiCommit {
|
||||||
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
||||||
optional bytes data = 2; // Data to be signed
|
optional bytes data = 2 [deprecated=true]; // Data to be signed. Deprecated in 1.10.2, the field is not needed, since CoSi commitments are no longer deterministic.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1 +0,0 @@
|
|||||||
Remove power-down power-up cycle from touch controller initialization in firmware
|
|
@ -1 +0,0 @@
|
|||||||
Add model R emulator
|
|
@ -1 +0,0 @@
|
|||||||
Add support for Monero HF15 features.
|
|
@ -1 +0,0 @@
|
|||||||
Add basic Trezor Model R hardware support
|
|
@ -1 +0,0 @@
|
|||||||
Show the fee rate on the singing confirmation screen.
|
|
@ -1 +0,0 @@
|
|||||||
Updated secp256k1-zkp.
|
|
@ -1 +0,0 @@
|
|||||||
Jump and stay in bootloader from firmware through SVC call reverse trampoline.
|
|
@ -1 +0,0 @@
|
|||||||
Expose raw pixel access to Rust
|
|
@ -1 +0,0 @@
|
|||||||
Add RGB LED for Model R
|
|
@ -1 +0,0 @@
|
|||||||
Cardano internal refactors
|
|
@ -1 +0,0 @@
|
|||||||
Boardloader capabilities structure
|
|
@ -1 +0,0 @@
|
|||||||
Support for Cardano Babbage era transaction items
|
|
@ -1,2 +0,0 @@
|
|||||||
Allow Cardano's `required_signers` in ordinary and multisig transactions
|
|
||||||
Allow Cardano's `datum_hash` in non-script outputs
|
|
@ -1 +0,0 @@
|
|||||||
Add "Show All"/"Show Simple" choice to Cardano transaction signing
|
|
@ -1 +0,0 @@
|
|||||||
Documentation for embedded C+Rust debugging
|
|
@ -1 +0,0 @@
|
|||||||
Show thousands separator when displaying large amounts.
|
|
@ -1 +0,0 @@
|
|||||||
Ensure correct order when verifying external inputs in Bitcoin signing.
|
|
@ -1 +0,0 @@
|
|||||||
Fix Decred transaction weight calculation.
|
|
@ -1 +0,0 @@
|
|||||||
Remove firmware dumping capability.
|
|
@ -1 +0,0 @@
|
|||||||
Refactor and cleanup of Monero code.
|
|
@ -1 +0,0 @@
|
|||||||
Removed support for obsolete Monero hardfork 12 and below
|
|
@ -1 +0,0 @@
|
|||||||
_(Emulator)_ Emulator window will always react to shutdown events, even while waiting for USB packets.
|
|
@ -4,6 +4,39 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
|
## [2.5.2] (17th August 2022)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Add model R emulator [#2230]
|
||||||
|
- Add support for Monero HF15 features. [#2232]
|
||||||
|
- Add basic Trezor Model R hardware support [#2243]
|
||||||
|
- Show the fee rate on the signing confirmation screen. [#2249]
|
||||||
|
- Jump and stay in bootloader from firmware through SVC call reverse trampoline. [#2284]
|
||||||
|
- Expose raw pixel access to Rust [#2297]
|
||||||
|
- Add RGB LED for Model R [#2300]
|
||||||
|
- Boardloader capabilities structure [#2324]
|
||||||
|
- Support for Cardano Babbage era transaction items [#2354]
|
||||||
|
- Add "Show All"/"Show Simple" choice to Cardano transaction signing [#2355]
|
||||||
|
- Documentation for embedded C+Rust debugging [#2380]
|
||||||
|
- Show thousands separator when displaying large amounts. [#2394]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Refactor and cleanup of Monero code. [#642]
|
||||||
|
- Remove power-down power-up cycle from touch controller initialization in firmware [#2130]
|
||||||
|
- Updated secp256k1-zkp. [#2261]
|
||||||
|
- Cardano internal refactors [#2313]
|
||||||
|
- Allow Cardano's `required_signers` in ordinary and multisig transactions
|
||||||
|
Allow Cardano's `datum_hash` in non-script outputs [#2354]
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Removed support for obsolete Monero hardfork 12 and below [#642]
|
||||||
|
- Remove firmware dumping capability. [#2433]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- _(Emulator)_ Emulator window will always react to shutdown events, even while waiting for USB packets. [#973]
|
||||||
|
- Ensure correct order when verifying external inputs in Bitcoin signing. [#2415]
|
||||||
|
- Fix Decred transaction weight calculation. [#2422]
|
||||||
|
|
||||||
|
|
||||||
## 2.5.1 [18th May 2022]
|
## 2.5.1 [18th May 2022]
|
||||||
|
|
||||||
@ -483,10 +516,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
|
|
||||||
[#24]: https://github.com/trezor/trezor-firmware/pull/24
|
[#24]: https://github.com/trezor/trezor-firmware/pull/24
|
||||||
[#379]: https://github.com/trezor/trezor-firmware/pull/379
|
[#379]: https://github.com/trezor/trezor-firmware/pull/379
|
||||||
|
[#642]: https://github.com/trezor/trezor-firmware/pull/642
|
||||||
[#741]: https://github.com/trezor/trezor-firmware/pull/741
|
[#741]: https://github.com/trezor/trezor-firmware/pull/741
|
||||||
[#800]: https://github.com/trezor/trezor-firmware/pull/800
|
[#800]: https://github.com/trezor/trezor-firmware/pull/800
|
||||||
[#948]: https://github.com/trezor/trezor-firmware/pull/948
|
[#948]: https://github.com/trezor/trezor-firmware/pull/948
|
||||||
[#958]: https://github.com/trezor/trezor-firmware/pull/958
|
[#958]: https://github.com/trezor/trezor-firmware/pull/958
|
||||||
|
[#973]: https://github.com/trezor/trezor-firmware/pull/973
|
||||||
[#982]: https://github.com/trezor/trezor-firmware/pull/982
|
[#982]: https://github.com/trezor/trezor-firmware/pull/982
|
||||||
[#1018]: https://github.com/trezor/trezor-firmware/pull/1018
|
[#1018]: https://github.com/trezor/trezor-firmware/pull/1018
|
||||||
[#1027]: https://github.com/trezor/trezor-firmware/pull/1027
|
[#1027]: https://github.com/trezor/trezor-firmware/pull/1027
|
||||||
@ -594,9 +629,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
[#2077]: https://github.com/trezor/trezor-firmware/pull/2077
|
[#2077]: https://github.com/trezor/trezor-firmware/pull/2077
|
||||||
[#2100]: https://github.com/trezor/trezor-firmware/pull/2100
|
[#2100]: https://github.com/trezor/trezor-firmware/pull/2100
|
||||||
[#2114]: https://github.com/trezor/trezor-firmware/pull/2114
|
[#2114]: https://github.com/trezor/trezor-firmware/pull/2114
|
||||||
|
[#2130]: https://github.com/trezor/trezor-firmware/pull/2130
|
||||||
[#2135]: https://github.com/trezor/trezor-firmware/pull/2135
|
[#2135]: https://github.com/trezor/trezor-firmware/pull/2135
|
||||||
[#2144]: https://github.com/trezor/trezor-firmware/pull/2144
|
[#2144]: https://github.com/trezor/trezor-firmware/pull/2144
|
||||||
[#2166]: https://github.com/trezor/trezor-firmware/pull/2166
|
[#2166]: https://github.com/trezor/trezor-firmware/pull/2166
|
||||||
[#2167]: https://github.com/trezor/trezor-firmware/pull/2167
|
[#2167]: https://github.com/trezor/trezor-firmware/pull/2167
|
||||||
[#2181]: https://github.com/trezor/trezor-firmware/pull/2181
|
[#2181]: https://github.com/trezor/trezor-firmware/pull/2181
|
||||||
|
[#2230]: https://github.com/trezor/trezor-firmware/pull/2230
|
||||||
|
[#2232]: https://github.com/trezor/trezor-firmware/pull/2232
|
||||||
[#2239]: https://github.com/trezor/trezor-firmware/pull/2239
|
[#2239]: https://github.com/trezor/trezor-firmware/pull/2239
|
||||||
|
[#2243]: https://github.com/trezor/trezor-firmware/pull/2243
|
||||||
|
[#2249]: https://github.com/trezor/trezor-firmware/pull/2249
|
||||||
|
[#2261]: https://github.com/trezor/trezor-firmware/pull/2261
|
||||||
|
[#2284]: https://github.com/trezor/trezor-firmware/pull/2284
|
||||||
|
[#2297]: https://github.com/trezor/trezor-firmware/pull/2297
|
||||||
|
[#2300]: https://github.com/trezor/trezor-firmware/pull/2300
|
||||||
|
[#2313]: https://github.com/trezor/trezor-firmware/pull/2313
|
||||||
|
[#2324]: https://github.com/trezor/trezor-firmware/pull/2324
|
||||||
|
[#2354]: https://github.com/trezor/trezor-firmware/pull/2354
|
||||||
|
[#2355]: https://github.com/trezor/trezor-firmware/pull/2355
|
||||||
|
[#2380]: https://github.com/trezor/trezor-firmware/pull/2380
|
||||||
|
[#2394]: https://github.com/trezor/trezor-firmware/pull/2394
|
||||||
|
[#2415]: https://github.com/trezor/trezor-firmware/pull/2415
|
||||||
|
[#2422]: https://github.com/trezor/trezor-firmware/pull/2422
|
||||||
|
[#2433]: https://github.com/trezor/trezor-firmware/pull/2433
|
||||||
|
@ -240,6 +240,25 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(
|
|||||||
mod_trezorcrypto_ed25519_cosi_combine_signatures_obj,
|
mod_trezorcrypto_ed25519_cosi_combine_signatures_obj,
|
||||||
mod_trezorcrypto_ed25519_cosi_combine_signatures);
|
mod_trezorcrypto_ed25519_cosi_combine_signatures);
|
||||||
|
|
||||||
|
/// def cosi_commit() -> tuple[bytes, bytes]:
|
||||||
|
/// """
|
||||||
|
/// Generate a nonce and commitment for the CoSi cosigning scheme.
|
||||||
|
/// """
|
||||||
|
STATIC mp_obj_t mod_trezorcrypto_ed25519_cosi_commit() {
|
||||||
|
vstr_t nonce = {0};
|
||||||
|
vstr_t commitment = {0};
|
||||||
|
vstr_init_len(&nonce, 32);
|
||||||
|
vstr_init_len(&commitment, 32);
|
||||||
|
ed25519_cosi_commit(*(ed25519_secret_key *)nonce.buf,
|
||||||
|
*(ed25519_public_key *)commitment.buf);
|
||||||
|
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
|
||||||
|
tuple->items[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &nonce);
|
||||||
|
tuple->items[1] = mp_obj_new_str_from_vstr(&mp_type_bytes, &commitment);
|
||||||
|
return MP_OBJ_FROM_PTR(tuple);
|
||||||
|
}
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorcrypto_ed25519_cosi_commit_obj,
|
||||||
|
mod_trezorcrypto_ed25519_cosi_commit);
|
||||||
|
|
||||||
/// def cosi_sign(
|
/// def cosi_sign(
|
||||||
/// secret_key: bytes,
|
/// secret_key: bytes,
|
||||||
/// message: bytes,
|
/// message: bytes,
|
||||||
@ -272,12 +291,15 @@ STATIC mp_obj_t mod_trezorcrypto_ed25519_cosi_sign(size_t n_args,
|
|||||||
}
|
}
|
||||||
vstr_t sig = {0};
|
vstr_t sig = {0};
|
||||||
vstr_init_len(&sig, sizeof(ed25519_cosi_signature));
|
vstr_init_len(&sig, sizeof(ed25519_cosi_signature));
|
||||||
;
|
if (0 != ed25519_cosi_sign(msg.buf, msg.len,
|
||||||
ed25519_cosi_sign(msg.buf, msg.len, *(const ed25519_secret_key *)sk.buf,
|
*(const ed25519_secret_key *)sk.buf,
|
||||||
*(const ed25519_secret_key *)nonce.buf,
|
*(const ed25519_secret_key *)nonce.buf,
|
||||||
*(const ed25519_public_key *)sigR.buf,
|
*(const ed25519_public_key *)sigR.buf,
|
||||||
*(const ed25519_secret_key *)pk.buf,
|
*(const ed25519_secret_key *)pk.buf,
|
||||||
*(ed25519_cosi_signature *)sig.buf);
|
*(ed25519_cosi_signature *)sig.buf)) {
|
||||||
|
vstr_clear(&sig);
|
||||||
|
mp_raise_ValueError("Signing failed");
|
||||||
|
}
|
||||||
return mp_obj_new_str_from_vstr(&mp_type_bytes, &sig);
|
return mp_obj_new_str_from_vstr(&mp_type_bytes, &sig);
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
|
||||||
@ -301,6 +323,8 @@ STATIC const mp_rom_map_elem_t mod_trezorcrypto_ed25519_globals_table[] = {
|
|||||||
MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_combine_publickeys_obj)},
|
MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_combine_publickeys_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_cosi_combine_signatures),
|
{MP_ROM_QSTR(MP_QSTR_cosi_combine_signatures),
|
||||||
MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_combine_signatures_obj)},
|
MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_combine_signatures_obj)},
|
||||||
|
{MP_ROM_QSTR(MP_QSTR_cosi_commit),
|
||||||
|
MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_commit_obj)},
|
||||||
{MP_ROM_QSTR(MP_QSTR_cosi_sign),
|
{MP_ROM_QSTR(MP_QSTR_cosi_sign),
|
||||||
MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_sign_obj)},
|
MP_ROM_PTR(&mod_trezorcrypto_ed25519_cosi_sign_obj)},
|
||||||
};
|
};
|
||||||
|
@ -53,6 +53,13 @@ def cosi_combine_signatures(R: bytes, signatures: list[bytes]) -> bytes:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h
|
||||||
|
def cosi_commit() -> tuple[bytes, bytes]:
|
||||||
|
"""
|
||||||
|
Generate a nonce and commitment for the CoSi cosigning scheme.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
# extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h
|
# extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h
|
||||||
def cosi_sign(
|
def cosi_sign(
|
||||||
secret_key: bytes,
|
secret_key: bytes,
|
||||||
|
@ -1928,13 +1928,11 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
class CosiCommit(protobuf.MessageType):
|
class CosiCommit(protobuf.MessageType):
|
||||||
address_n: "list[int]"
|
address_n: "list[int]"
|
||||||
data: "bytes | None"
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
address_n: "list[int] | None" = None,
|
address_n: "list[int] | None" = None,
|
||||||
data: "bytes | None" = None,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -26,8 +26,7 @@ class TestCryptoEd25519Cosi(unittest.TestCase):
|
|||||||
nonces = [None] * N
|
nonces = [None] * N
|
||||||
Rs = [None] * N
|
Rs = [None] * N
|
||||||
for j in range(N):
|
for j in range(N):
|
||||||
nonces[j] = ed25519.generate_secret()
|
nonces[j], Rs[j] = ed25519.cosi_commit()
|
||||||
Rs[j] = ed25519.publickey(nonces[j])
|
|
||||||
|
|
||||||
R = ed25519.cosi_combine_publickeys(Rs)
|
R = ed25519.cosi_combine_publickeys(Rs)
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "ed25519.h"
|
#include "ed25519.h"
|
||||||
|
|
||||||
#include "ed25519-hash-custom.h"
|
#include "ed25519-hash-custom.h"
|
||||||
|
#include "rand.h"
|
||||||
#include "memzero.h"
|
#include "memzero.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -50,16 +51,34 @@ ED25519_FN(ed25519_publickey) (const ed25519_secret_key sk, ed25519_public_key p
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
ED25519_FN(ed25519_cosi_commit) (ed25519_secret_key nonce, ed25519_public_key commitment) {
|
||||||
|
bignum256modm r = {0};
|
||||||
|
ge25519 ALIGN(16) R;
|
||||||
|
unsigned char extnonce[64] = {0};
|
||||||
|
|
||||||
|
/* r = random512 mod L */
|
||||||
|
random_buffer(extnonce, sizeof(extnonce));
|
||||||
|
expand256_modm(r, extnonce, sizeof(extnonce));
|
||||||
|
memzero(&extnonce, sizeof(extnonce));
|
||||||
|
contract256_modm(nonce, r);
|
||||||
|
|
||||||
|
/* R = rB */
|
||||||
|
ge25519_scalarmult_base_niels(&R, ge25519_niels_base_multiples, r);
|
||||||
|
memzero(&r, sizeof(r));
|
||||||
|
ge25519_pack(commitment, &R);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
ED25519_FN(ed25519_cosi_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig) {
|
ED25519_FN(ed25519_cosi_sign) (const unsigned char *m, size_t mlen, const ed25519_secret_key sk, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig) {
|
||||||
bignum256modm r = {0}, S = {0}, a = {0};
|
bignum256modm r = {0}, S = {0}, a = {0};
|
||||||
hash_512bits extsk = {0}, extnonce = {0}, hram = {0};
|
hash_512bits extsk = {0}, hram = {0};
|
||||||
|
|
||||||
ed25519_extsk(extsk, sk);
|
ed25519_extsk(extsk, sk);
|
||||||
ed25519_extsk(extnonce, nonce);
|
|
||||||
|
|
||||||
/* r = nonce */
|
/* r */
|
||||||
expand256_modm(r, extnonce, 32);
|
expand_raw256_modm(r, nonce);
|
||||||
memzero(&extnonce, sizeof(extnonce));
|
if (!is_reduced256_modm(r))
|
||||||
|
return -1;
|
||||||
|
|
||||||
/* S = H(R,A,m).. */
|
/* S = H(R,A,m).. */
|
||||||
ed25519_hram(hram, R, pk, m, mlen);
|
ed25519_hram(hram, R, pk, m, mlen);
|
||||||
@ -77,6 +96,8 @@ ED25519_FN(ed25519_cosi_sign) (const unsigned char *m, size_t mlen, const ed2551
|
|||||||
|
|
||||||
/* S = (r + H(R,A,m)a) mod L */
|
/* S = (r + H(R,A,m)a) mod L */
|
||||||
contract256_modm(sig, S);
|
contract256_modm(sig, S);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -155,7 +176,7 @@ ED25519_FN(ed25519_sign_open) (const unsigned char *m, size_t mlen, const ed2551
|
|||||||
/* S */
|
/* S */
|
||||||
expand_raw256_modm(S, RS + 32);
|
expand_raw256_modm(S, RS + 32);
|
||||||
if (!is_reduced256_modm(S))
|
if (!is_reduced256_modm(S))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* SB - H(R,A,m)A */
|
/* SB - H(R,A,m)A */
|
||||||
ge25519_double_scalarmult_vartime(&R, &A, hram, S);
|
ge25519_double_scalarmult_vartime(&R, &A, hram, S);
|
||||||
|
@ -35,7 +35,8 @@ void curve25519_scalarmult_basepoint(curve25519_key mypublic, const curve25519_k
|
|||||||
|
|
||||||
int ed25519_cosi_combine_publickeys(ed25519_public_key res, CONST ed25519_public_key *pks, size_t n);
|
int ed25519_cosi_combine_publickeys(ed25519_public_key res, CONST ed25519_public_key *pks, size_t n);
|
||||||
void ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, CONST ed25519_cosi_signature *sigs, size_t n);
|
void ed25519_cosi_combine_signatures(ed25519_signature res, const ed25519_public_key R, CONST ed25519_cosi_signature *sigs, size_t n);
|
||||||
void ed25519_cosi_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key key, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig);
|
void ed25519_cosi_commit(ed25519_secret_key nonce, ed25519_public_key commitment);
|
||||||
|
int ed25519_cosi_sign(const unsigned char *m, size_t mlen, const ed25519_secret_key key, const ed25519_secret_key nonce, const ed25519_public_key R, const ed25519_public_key pk, ed25519_cosi_signature sig);
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
|
@ -6885,8 +6885,7 @@ START_TEST(test_ed25519_cosi) {
|
|||||||
|
|
||||||
/* phase 1: create nonces, commitments (R values) and combine commitments */
|
/* phase 1: create nonces, commitments (R values) and combine commitments */
|
||||||
for (int j = 0; j < N; j++) {
|
for (int j = 0; j < N; j++) {
|
||||||
generate_rfc6979(nonces[j], &rng);
|
ed25519_cosi_commit(nonces[j], Rs[j]);
|
||||||
ed25519_publickey(nonces[j], Rs[j]);
|
|
||||||
}
|
}
|
||||||
res = ed25519_cosi_combine_publickeys(R, Rs, N);
|
res = ed25519_cosi_combine_publickeys(R, Rs, N);
|
||||||
ck_assert_int_eq(res, 0);
|
ck_assert_int_eq(res, 0);
|
||||||
@ -6894,7 +6893,9 @@ START_TEST(test_ed25519_cosi) {
|
|||||||
MARK_SECRET_DATA(keys, sizeof(keys));
|
MARK_SECRET_DATA(keys, sizeof(keys));
|
||||||
/* phase 2: sign and combine signatures */
|
/* phase 2: sign and combine signatures */
|
||||||
for (int j = 0; j < N; j++) {
|
for (int j = 0; j < N; j++) {
|
||||||
ed25519_cosi_sign(msg, sizeof(msg), keys[j], nonces[j], R, pk, sigs[j]);
|
res = ed25519_cosi_sign(msg, sizeof(msg), keys[j], nonces[j], R, pk,
|
||||||
|
sigs[j]);
|
||||||
|
ck_assert_int_eq(res, 0);
|
||||||
}
|
}
|
||||||
UNMARK_SECRET_DATA(sigs, sizeof(sigs));
|
UNMARK_SECRET_DATA(sigs, sizeof(sigs));
|
||||||
|
|
||||||
|
@ -1 +0,0 @@
|
|||||||
Show the fee rate on the singing confirmation screen.
|
|
@ -1 +0,0 @@
|
|||||||
Updated secp256k1-zkp.
|
|
@ -1 +0,0 @@
|
|||||||
Show thousands separator when displaying large amounts.
|
|
@ -1 +0,0 @@
|
|||||||
Fix rounding in fee rate computation.
|
|
@ -1 +0,0 @@
|
|||||||
Remove firmware dumping capability.
|
|
@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
|
## [1.11.2] (17th August 2022)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Show the fee rate on the signing confirmation screen. [#2249]
|
||||||
|
- Show thousands separator when displaying large amounts. [#2394]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Updated secp256k1-zkp. [#2261]
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- Remove firmware dumping capability. [#2433]
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Fix potential security issues in recovery workflow.
|
||||||
|
- Fix key extraction vulnerability in Cothority Collective Signing (CoSi).
|
||||||
|
- Fix nonce bias in CoSi signing.
|
||||||
|
|
||||||
|
|
||||||
## 1.11.1 [18th May 2022]
|
## 1.11.1 [18th May 2022]
|
||||||
|
|
||||||
@ -543,3 +560,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
[#2144]: https://github.com/trezor/trezor-firmware/pull/2144
|
[#2144]: https://github.com/trezor/trezor-firmware/pull/2144
|
||||||
[#2181]: https://github.com/trezor/trezor-firmware/pull/2181
|
[#2181]: https://github.com/trezor/trezor-firmware/pull/2181
|
||||||
[#2239]: https://github.com/trezor/trezor-firmware/pull/2239
|
[#2239]: https://github.com/trezor/trezor-firmware/pull/2239
|
||||||
|
[#2249]: https://github.com/trezor/trezor-firmware/pull/2249
|
||||||
|
[#2261]: https://github.com/trezor/trezor-firmware/pull/2261
|
||||||
|
[#2394]: https://github.com/trezor/trezor-firmware/pull/2394
|
||||||
|
[#2422]: https://github.com/trezor/trezor-firmware/pull/2422
|
||||||
|
[#2433]: https://github.com/trezor/trezor-firmware/pull/2433
|
||||||
|
@ -44,7 +44,6 @@
|
|||||||
#include "protect.h"
|
#include "protect.h"
|
||||||
#include "recovery.h"
|
#include "recovery.h"
|
||||||
#include "reset.h"
|
#include "reset.h"
|
||||||
#include "rfc6979.h"
|
|
||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
#include "secp256k1.h"
|
#include "secp256k1.h"
|
||||||
#include "signing.h"
|
#include "signing.h"
|
||||||
|
@ -17,6 +17,10 @@
|
|||||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static uint8_t cosi_nonce[32] = {0};
|
||||||
|
static uint8_t cosi_commitment[32] = {0};
|
||||||
|
static bool cosi_nonce_is_set = false;
|
||||||
|
|
||||||
void fsm_msgCipherKeyValue(const CipherKeyValue *msg) {
|
void fsm_msgCipherKeyValue(const CipherKeyValue *msg) {
|
||||||
CHECK_INITIALIZED
|
CHECK_INITIALIZED
|
||||||
|
|
||||||
@ -256,8 +260,6 @@ void fsm_msgCosiCommit(const CosiCommit *msg) {
|
|||||||
|
|
||||||
CHECK_INITIALIZED
|
CHECK_INITIALIZED
|
||||||
|
|
||||||
CHECK_PARAM(msg->has_data, _("No data provided"));
|
|
||||||
|
|
||||||
CHECK_PIN
|
CHECK_PIN
|
||||||
|
|
||||||
if (!fsm_checkCosiPath(msg->address_n_count, msg->address_n)) {
|
if (!fsm_checkCosiPath(msg->address_n_count, msg->address_n)) {
|
||||||
@ -265,30 +267,21 @@ void fsm_msgCosiCommit(const CosiCommit *msg) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes,
|
|
||||||
msg->data.size, false);
|
|
||||||
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
|
|
||||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
|
|
||||||
layoutHome();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
|
const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
|
||||||
msg->address_n_count, NULL);
|
msg->address_n_count, NULL);
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
|
|
||||||
uint8_t nonce[32];
|
if (!cosi_nonce_is_set) {
|
||||||
sha256_Raw(msg->data.bytes, msg->data.size, nonce);
|
ed25519_cosi_commit(cosi_nonce, cosi_commitment);
|
||||||
rfc6979_state rng;
|
cosi_nonce_is_set = true;
|
||||||
init_rfc6979(node->private_key, nonce, NULL, &rng);
|
}
|
||||||
generate_rfc6979(nonce, &rng);
|
|
||||||
|
|
||||||
resp->has_commitment = true;
|
resp->has_commitment = true;
|
||||||
resp->has_pubkey = true;
|
resp->has_pubkey = true;
|
||||||
resp->commitment.size = 32;
|
resp->commitment.size = 32;
|
||||||
resp->pubkey.size = 32;
|
resp->pubkey.size = 32;
|
||||||
|
|
||||||
ed25519_publickey(nonce, resp->commitment.bytes);
|
memcpy(resp->commitment.bytes, cosi_commitment, sizeof(cosi_commitment));
|
||||||
ed25519_publickey(node->private_key, resp->pubkey.bytes);
|
ed25519_publickey(node->private_key, resp->pubkey.bytes);
|
||||||
|
|
||||||
msg_write(MessageType_MessageType_CosiCommitment, resp);
|
msg_write(MessageType_MessageType_CosiCommitment, resp);
|
||||||
@ -306,6 +299,12 @@ void fsm_msgCosiSign(const CosiSign *msg) {
|
|||||||
CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32,
|
CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32,
|
||||||
_("Invalid global pubkey"));
|
_("Invalid global pubkey"));
|
||||||
|
|
||||||
|
if (!cosi_nonce_is_set) {
|
||||||
|
fsm_sendFailure(FailureType_Failure_ProcessError, _("CoSi nonce not set"));
|
||||||
|
layoutHome();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!fsm_checkCosiPath(msg->address_n_count, msg->address_n)) {
|
if (!fsm_checkCosiPath(msg->address_n_count, msg->address_n)) {
|
||||||
layoutHome();
|
layoutHome();
|
||||||
return;
|
return;
|
||||||
@ -313,8 +312,8 @@ void fsm_msgCosiSign(const CosiSign *msg) {
|
|||||||
|
|
||||||
CHECK_PIN
|
CHECK_PIN
|
||||||
|
|
||||||
layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes,
|
layoutCosiSign(msg->address_n, msg->address_n_count, msg->data.bytes,
|
||||||
msg->data.size, true);
|
msg->data.size);
|
||||||
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
|
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
|
||||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
|
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
|
||||||
layoutHome();
|
layoutHome();
|
||||||
@ -325,18 +324,16 @@ void fsm_msgCosiSign(const CosiSign *msg) {
|
|||||||
msg->address_n_count, NULL);
|
msg->address_n_count, NULL);
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
|
|
||||||
uint8_t nonce[32];
|
|
||||||
sha256_Raw(msg->data.bytes, msg->data.size, nonce);
|
|
||||||
rfc6979_state rng;
|
|
||||||
init_rfc6979(node->private_key, nonce, NULL, &rng);
|
|
||||||
generate_rfc6979(nonce, &rng);
|
|
||||||
|
|
||||||
resp->signature.size = 32;
|
resp->signature.size = 32;
|
||||||
|
cosi_nonce_is_set = false;
|
||||||
|
|
||||||
ed25519_cosi_sign(msg->data.bytes, msg->data.size, node->private_key, nonce,
|
if (ed25519_cosi_sign(msg->data.bytes, msg->data.size, node->private_key,
|
||||||
msg->global_commitment.bytes, msg->global_pubkey.bytes,
|
cosi_nonce, msg->global_commitment.bytes,
|
||||||
resp->signature.bytes);
|
msg->global_pubkey.bytes, resp->signature.bytes) == 0) {
|
||||||
|
msg_write(MessageType_MessageType_CosiSignature, resp);
|
||||||
msg_write(MessageType_MessageType_CosiSignature, resp);
|
} else {
|
||||||
|
fsm_sendFailure(FailureType_Failure_FirmwareError, NULL);
|
||||||
|
}
|
||||||
|
memzero(cosi_nonce, sizeof(cosi_nonce));
|
||||||
layoutHome();
|
layoutHome();
|
||||||
}
|
}
|
||||||
|
@ -1220,18 +1220,13 @@ static inline bool is_slip18(const uint32_t *address_n,
|
|||||||
(address_n[1] & PATH_UNHARDEN_MASK) <= 9;
|
(address_n[1] & PATH_UNHARDEN_MASK) <= 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count,
|
void layoutCosiSign(const uint32_t *address_n, size_t address_n_count,
|
||||||
const uint8_t *data, uint32_t len, bool final_sign) {
|
const uint8_t *data, uint32_t len) {
|
||||||
char *desc = final_sign ? _("CoSi sign message?") : _("CoSi commit message?");
|
char *desc = _("CoSi sign message?");
|
||||||
char desc_buf[32] = {0};
|
char desc_buf[32] = {0};
|
||||||
if (is_slip18(address_n, address_n_count)) {
|
if (is_slip18(address_n, address_n_count)) {
|
||||||
if (final_sign) {
|
strlcpy(desc_buf, _("CoSi sign index #?"), sizeof(desc_buf));
|
||||||
strlcpy(desc_buf, _("CoSi sign index #?"), sizeof(desc_buf));
|
desc_buf[16] = '0' + (address_n[1] & PATH_UNHARDEN_MASK);
|
||||||
desc_buf[16] = '0' + (address_n[1] & PATH_UNHARDEN_MASK);
|
|
||||||
} else {
|
|
||||||
strlcpy(desc_buf, _("CoSi commit index #?"), sizeof(desc_buf));
|
|
||||||
desc_buf[18] = '0' + (address_n[1] & PATH_UNHARDEN_MASK);
|
|
||||||
}
|
|
||||||
desc = desc_buf;
|
desc = desc_buf;
|
||||||
}
|
}
|
||||||
char str[4][17] = {0};
|
char str[4][17] = {0};
|
||||||
|
@ -105,8 +105,8 @@ void layoutNEMTransferPayload(const uint8_t *payload, size_t length,
|
|||||||
void layoutNEMMosaicDescription(const char *description);
|
void layoutNEMMosaicDescription(const char *description);
|
||||||
void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network);
|
void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network);
|
||||||
|
|
||||||
void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count,
|
void layoutCosiSign(const uint32_t *address_n, size_t address_n_count,
|
||||||
const uint8_t *data, uint32_t len, bool final_sign);
|
const uint8_t *data, uint32_t len);
|
||||||
|
|
||||||
void layoutConfirmAutoLockDelay(uint32_t delay_ms);
|
void layoutConfirmAutoLockDelay(uint32_t delay_ms);
|
||||||
void layoutConfirmSafetyChecks(SafetyCheckLevel safety_checks_level);
|
void layoutConfirmSafetyChecks(SafetyCheckLevel safety_checks_level);
|
||||||
|
@ -6,7 +6,7 @@ CipherKeyValue.iv max_size:16
|
|||||||
CipheredKeyValue.value max_size:1024
|
CipheredKeyValue.value max_size:1024
|
||||||
|
|
||||||
CosiCommit.address_n max_count:8
|
CosiCommit.address_n max_count:8
|
||||||
CosiCommit.data max_size:32
|
CosiCommit.data type:FT_IGNORE
|
||||||
|
|
||||||
CosiCommitment.commitment max_size:32
|
CosiCommitment.commitment max_size:32
|
||||||
CosiCommitment.pubkey max_size:32
|
CosiCommitment.pubkey max_size:32
|
||||||
|
@ -37,12 +37,12 @@
|
|||||||
/* number of words expected in the new seed */
|
/* number of words expected in the new seed */
|
||||||
static uint32_t word_count;
|
static uint32_t word_count;
|
||||||
|
|
||||||
/* recovery mode:
|
/* recovery mode */
|
||||||
* 0: not recovering
|
static enum {
|
||||||
* 1: recover by scrambled plain text words
|
RECOVERY_NONE = 0, // recovery not in progress
|
||||||
* 2: recover by matrix entry
|
RECOVERY_SCRAMBLED = 1, // standard recovery by scrambled plain text words
|
||||||
*/
|
RECOVERY_MATRIX = 2, // advanced recovery by matrix entry
|
||||||
static int awaiting_word = 0;
|
} recovery_mode = RECOVERY_NONE;
|
||||||
|
|
||||||
/* True if we should not write anything back to config
|
/* True if we should not write anything back to config
|
||||||
* (can be used for testing seed for correctness).
|
* (can be used for testing seed for correctness).
|
||||||
@ -145,7 +145,7 @@ static void format_number(char *dest, int number) {
|
|||||||
static void recovery_request(void) {
|
static void recovery_request(void) {
|
||||||
WordRequest resp = {0};
|
WordRequest resp = {0};
|
||||||
memzero(&resp, sizeof(WordRequest));
|
memzero(&resp, sizeof(WordRequest));
|
||||||
if (awaiting_word == 1) {
|
if (recovery_mode == RECOVERY_SCRAMBLED) {
|
||||||
resp.type = WordRequestType_WordRequestType_Plain;
|
resp.type = WordRequestType_WordRequestType_Plain;
|
||||||
} else if (word_index % 4 == 3) {
|
} else if (word_index % 4 == 3) {
|
||||||
resp.type = WordRequestType_WordRequestType_Matrix6;
|
resp.type = WordRequestType_WordRequestType_Matrix6;
|
||||||
@ -217,7 +217,9 @@ static void recovery_done(void) {
|
|||||||
fsm_sendFailure(FailureType_Failure_DataError,
|
fsm_sendFailure(FailureType_Failure_DataError,
|
||||||
_("Invalid seed, are words in correct order?"));
|
_("Invalid seed, are words in correct order?"));
|
||||||
}
|
}
|
||||||
awaiting_word = 0;
|
memzero(words, sizeof(words));
|
||||||
|
word_pincode = 0;
|
||||||
|
recovery_mode = RECOVERY_NONE;
|
||||||
layoutHome();
|
layoutHome();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,6 +478,9 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection,
|
|||||||
bool _dry_run) {
|
bool _dry_run) {
|
||||||
if (_word_count != 12 && _word_count != 18 && _word_count != 24) return;
|
if (_word_count != 12 && _word_count != 18 && _word_count != 24) return;
|
||||||
|
|
||||||
|
recovery_mode = RECOVERY_NONE;
|
||||||
|
word_pincode = 0;
|
||||||
|
word_index = 0;
|
||||||
word_count = _word_count;
|
word_count = _word_count;
|
||||||
enforce_wordlist = _enforce_wordlist;
|
enforce_wordlist = _enforce_wordlist;
|
||||||
dry_run = _dry_run;
|
dry_run = _dry_run;
|
||||||
@ -504,10 +509,9 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection,
|
|||||||
config_setU2FCounter(u2f_counter);
|
config_setU2FCounter(u2f_counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prefer matrix recovery if the host supports it.
|
||||||
if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) {
|
if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) {
|
||||||
awaiting_word = 2;
|
recovery_mode = RECOVERY_MATRIX;
|
||||||
word_index = 0;
|
|
||||||
word_pincode = 0;
|
|
||||||
next_matrix();
|
next_matrix();
|
||||||
} else {
|
} else {
|
||||||
for (uint32_t i = 0; i < word_count; i++) {
|
for (uint32_t i = 0; i < word_count; i++) {
|
||||||
@ -517,8 +521,7 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection,
|
|||||||
word_order[i] = 0;
|
word_order[i] = 0;
|
||||||
}
|
}
|
||||||
random_permute(word_order, 24);
|
random_permute(word_order, 24);
|
||||||
awaiting_word = 1;
|
recovery_mode = RECOVERY_SCRAMBLED;
|
||||||
word_index = 0;
|
|
||||||
next_word();
|
next_word();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -527,29 +530,18 @@ static void recovery_scrambledword(const char *word) {
|
|||||||
int index = -1;
|
int index = -1;
|
||||||
if (enforce_wordlist) { // check if word is valid
|
if (enforce_wordlist) { // check if word is valid
|
||||||
index = mnemonic_find_word(word);
|
index = mnemonic_find_word(word);
|
||||||
}
|
if (index < 0) { // not found
|
||||||
if (word_pos == 0) { // fake word
|
|
||||||
if (strcmp(word, fake_word) != 0) {
|
|
||||||
if (!dry_run) {
|
if (!dry_run) {
|
||||||
session_clear(true);
|
session_clear(true);
|
||||||
}
|
}
|
||||||
fsm_sendFailure(FailureType_Failure_ProcessError,
|
fsm_sendFailure(FailureType_Failure_DataError,
|
||||||
_("Wrong word retyped"));
|
_("Word not found in a wordlist"));
|
||||||
layoutHome();
|
recovery_abort();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else { // real word
|
}
|
||||||
if (enforce_wordlist) {
|
|
||||||
if (index < 0) { // not found
|
if (word_pos != 0) { // ignore fake words
|
||||||
if (!dry_run) {
|
|
||||||
session_clear(true);
|
|
||||||
}
|
|
||||||
fsm_sendFailure(FailureType_Failure_DataError,
|
|
||||||
_("Word not found in a wordlist"));
|
|
||||||
layoutHome();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
strlcpy(words[word_pos - 1], word, sizeof(words[word_pos - 1]));
|
strlcpy(words[word_pos - 1], word, sizeof(words[word_pos - 1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,11 +557,11 @@ static void recovery_scrambledword(const char *word) {
|
|||||||
* for scrambled recovery.
|
* for scrambled recovery.
|
||||||
*/
|
*/
|
||||||
void recovery_word(const char *word) {
|
void recovery_word(const char *word) {
|
||||||
switch (awaiting_word) {
|
switch (recovery_mode) {
|
||||||
case 2:
|
case RECOVERY_MATRIX:
|
||||||
recovery_digit(word[0]);
|
recovery_digit(word[0]);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case RECOVERY_SCRAMBLED:
|
||||||
recovery_scrambledword(word);
|
recovery_scrambledword(word);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -582,9 +574,11 @@ void recovery_word(const char *word) {
|
|||||||
/* Abort recovery.
|
/* Abort recovery.
|
||||||
*/
|
*/
|
||||||
void recovery_abort(void) {
|
void recovery_abort(void) {
|
||||||
if (awaiting_word) {
|
memzero(words, sizeof(words));
|
||||||
|
word_pincode = 0;
|
||||||
|
if (recovery_mode != RECOVERY_NONE) {
|
||||||
layoutHome();
|
layoutHome();
|
||||||
awaiting_word = 0;
|
recovery_mode = RECOVERY_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
python/.changelog.d/noissue.removed
Normal file
1
python/.changelog.d/noissue.removed
Normal file
@ -0,0 +1 @@
|
|||||||
|
Remove DATA parameter from trezorctl cosi commit.
|
@ -14,7 +14,8 @@
|
|||||||
# You should have received a copy of the License along with this library.
|
# You should have received a copy of the License along with this library.
|
||||||
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
import warnings
|
||||||
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
@ -35,14 +36,17 @@ def cli() -> None:
|
|||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.argument("data")
|
@click.argument("data_deprecated", required=False)
|
||||||
@with_client
|
@with_client
|
||||||
def commit(
|
def commit(
|
||||||
client: "TrezorClient", address: str, data: str
|
client: "TrezorClient", address: str, data_deprecated: Optional[str]
|
||||||
) -> "messages.CosiCommitment":
|
) -> "messages.CosiCommitment":
|
||||||
"""Ask device to commit to CoSi signing."""
|
"""Ask device to commit to CoSi signing."""
|
||||||
|
if data_deprecated is not None:
|
||||||
|
warnings.warn("'data' argument is deprecated")
|
||||||
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
return cosi.commit(client, address_n, bytes.fromhex(data))
|
return cosi.commit(client, address_n)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
|
@ -14,8 +14,9 @@
|
|||||||
# You should have received a copy of the License along with this library.
|
# You should have received a copy of the License along with this library.
|
||||||
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||||
|
|
||||||
|
import warnings
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from typing import TYPE_CHECKING, Iterable, List, Tuple
|
from typing import TYPE_CHECKING, Iterable, List, Optional, Tuple
|
||||||
|
|
||||||
from . import _ed25519, messages
|
from . import _ed25519, messages
|
||||||
from .tools import expect
|
from .tools import expect
|
||||||
@ -141,8 +142,17 @@ def sign_with_privkey(
|
|||||||
|
|
||||||
|
|
||||||
@expect(messages.CosiCommitment)
|
@expect(messages.CosiCommitment)
|
||||||
def commit(client: "TrezorClient", n: "Address", data: bytes) -> "MessageType":
|
def commit(
|
||||||
return client.call(messages.CosiCommit(address_n=n, data=data))
|
client: "TrezorClient", n: "Address", data: Optional[bytes] = None
|
||||||
|
) -> "MessageType":
|
||||||
|
if data is not None:
|
||||||
|
warnings.warn(
|
||||||
|
"'data' argument is deprecated",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
|
return client.call(messages.CosiCommit(address_n=n))
|
||||||
|
|
||||||
|
|
||||||
@expect(messages.CosiSignature)
|
@expect(messages.CosiSignature)
|
||||||
|
@ -24,75 +24,87 @@ from trezorlib.tools import parse_path
|
|||||||
|
|
||||||
pytestmark = pytest.mark.skip_t2
|
pytestmark = pytest.mark.skip_t2
|
||||||
|
|
||||||
|
DIGEST = sha256(b"this is not a pipe").digest()
|
||||||
|
|
||||||
def test_cosi_commit(client: Client):
|
|
||||||
digest = sha256(b"this is a message").digest()
|
|
||||||
|
|
||||||
c0 = cosi.commit(client, parse_path("m/10018h/0h"), digest)
|
def test_cosi_pubkey(client: Client):
|
||||||
c1 = cosi.commit(client, parse_path("m/10018h/1h"), digest)
|
c0 = cosi.commit(client, parse_path("m/10018h/0h"))
|
||||||
c2 = cosi.commit(client, parse_path("m/10018h/2h"), digest)
|
c1 = cosi.commit(client, parse_path("m/10018h/1h"))
|
||||||
|
c2 = cosi.commit(client, parse_path("m/10018h/2h"))
|
||||||
|
|
||||||
assert c0.pubkey != c1.pubkey
|
assert c0.pubkey != c1.pubkey
|
||||||
assert c0.pubkey != c2.pubkey
|
assert c0.pubkey != c2.pubkey
|
||||||
assert c1.pubkey != c2.pubkey
|
assert c1.pubkey != c2.pubkey
|
||||||
|
|
||||||
|
|
||||||
|
def test_cosi_nonce(client: Client):
|
||||||
|
# The nonce/commitment must change after each signing.
|
||||||
|
c0 = cosi.commit(client, parse_path("m/10018h/0h"))
|
||||||
|
cosi.sign(client, parse_path("m/10018h/0h"), DIGEST, c0.commitment, c0.pubkey)
|
||||||
|
c1 = cosi.commit(client, parse_path("m/10018h/0h"))
|
||||||
assert c0.commitment != c1.commitment
|
assert c0.commitment != c1.commitment
|
||||||
assert c0.commitment != c2.commitment
|
|
||||||
assert c1.commitment != c2.commitment
|
|
||||||
|
|
||||||
digestb = sha256(b"this is a different message").digest()
|
|
||||||
|
|
||||||
c0b = cosi.commit(client, parse_path("m/10018h/0h"), digestb)
|
|
||||||
c1b = cosi.commit(client, parse_path("m/10018h/1h"), digestb)
|
|
||||||
c2b = cosi.commit(client, parse_path("m/10018h/2h"), digestb)
|
|
||||||
|
|
||||||
assert c0.pubkey == c0b.pubkey
|
|
||||||
assert c1.pubkey == c1b.pubkey
|
|
||||||
assert c2.pubkey == c2b.pubkey
|
|
||||||
|
|
||||||
assert c0.commitment != c0b.commitment
|
|
||||||
assert c1.commitment != c1b.commitment
|
|
||||||
assert c2.commitment != c2b.commitment
|
|
||||||
|
|
||||||
|
|
||||||
def test_cosi_sign(client: Client):
|
def test_cosi_sign1(client: Client):
|
||||||
digest = sha256(b"this is a message").digest()
|
# Single party signature.
|
||||||
|
commit = cosi.commit(client, parse_path("m/10018h/0h"))
|
||||||
c0 = cosi.commit(client, parse_path("m/10018h/0h"), digest)
|
sig = cosi.sign(
|
||||||
c1 = cosi.commit(client, parse_path("m/10018h/1h"), digest)
|
client, parse_path("m/10018h/0h"), DIGEST, commit.commitment, commit.pubkey
|
||||||
c2 = cosi.commit(client, parse_path("m/10018h/2h"), digest)
|
)
|
||||||
|
signature = cosi.combine_sig(commit.commitment, [sig.signature])
|
||||||
global_pk = cosi.combine_keys([c0.pubkey, c1.pubkey, c2.pubkey])
|
cosi.verify_combined(signature, DIGEST, commit.pubkey)
|
||||||
global_R = cosi.combine_keys([c0.commitment, c1.commitment, c2.commitment])
|
|
||||||
|
|
||||||
# fmt: off
|
|
||||||
sig0 = cosi.sign(client, parse_path("m/10018h/0h"), digest, global_R, global_pk)
|
|
||||||
sig1 = cosi.sign(client, parse_path("m/10018h/1h"), digest, global_R, global_pk)
|
|
||||||
sig2 = cosi.sign(client, parse_path("m/10018h/2h"), digest, global_R, global_pk)
|
|
||||||
# fmt: on
|
|
||||||
|
|
||||||
sig = cosi.combine_sig(global_R, [sig0.signature, sig1.signature, sig2.signature])
|
|
||||||
|
|
||||||
cosi.verify_combined(sig, digest, global_pk)
|
|
||||||
|
|
||||||
|
|
||||||
def test_cosi_compat(client: Client):
|
def test_cosi_sign2(client: Client):
|
||||||
digest = sha256(b"this is not a pipe").digest()
|
# Two party signature.
|
||||||
remote_commit = cosi.commit(client, parse_path("m/10018h/0h"), digest)
|
remote_commit = cosi.commit(client, parse_path("m/10018h/1h"))
|
||||||
|
|
||||||
local_privkey = sha256(b"private key").digest()[:32]
|
local_privkey = sha256(b"private key").digest()[:32]
|
||||||
local_pubkey = cosi.pubkey_from_privkey(local_privkey)
|
local_pubkey = cosi.pubkey_from_privkey(local_privkey)
|
||||||
local_nonce, local_commitment = cosi.get_nonce(local_privkey, digest, 42)
|
local_nonce, local_commitment = cosi.get_nonce(local_privkey, DIGEST, 42)
|
||||||
|
|
||||||
global_pk = cosi.combine_keys([remote_commit.pubkey, local_pubkey])
|
global_pk = cosi.combine_keys([remote_commit.pubkey, local_pubkey])
|
||||||
global_R = cosi.combine_keys([remote_commit.commitment, local_commitment])
|
global_R = cosi.combine_keys([remote_commit.commitment, local_commitment])
|
||||||
|
|
||||||
remote_sig = cosi.sign(
|
remote_sig = cosi.sign(
|
||||||
client, parse_path("m/10018h/0h"), digest, global_R, global_pk
|
client, parse_path("m/10018h/1h"), DIGEST, global_R, global_pk
|
||||||
)
|
)
|
||||||
local_sig = cosi.sign_with_privkey(
|
local_sig = cosi.sign_with_privkey(
|
||||||
digest, local_privkey, global_pk, local_nonce, global_R
|
DIGEST, local_privkey, global_pk, local_nonce, global_R
|
||||||
)
|
)
|
||||||
sig = cosi.combine_sig(global_R, [remote_sig.signature, local_sig])
|
signature = cosi.combine_sig(global_R, [remote_sig.signature, local_sig])
|
||||||
|
|
||||||
cosi.verify_combined(sig, digest, global_pk)
|
cosi.verify_combined(signature, DIGEST, global_pk)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cosi_sign3(client: Client):
|
||||||
|
# Three party signature.
|
||||||
|
remote_commit = cosi.commit(client, parse_path("m/10018h/2h"))
|
||||||
|
|
||||||
|
local_privkey1 = sha256(b"private key").digest()[:32]
|
||||||
|
local_pubkey1 = cosi.pubkey_from_privkey(local_privkey1)
|
||||||
|
local_nonce1, local_commitment1 = cosi.get_nonce(local_privkey1, DIGEST, 42)
|
||||||
|
|
||||||
|
local_privkey2 = sha256(b"private key").digest()[:32]
|
||||||
|
local_pubkey2 = cosi.pubkey_from_privkey(local_privkey2)
|
||||||
|
local_nonce2, local_commitment2 = cosi.get_nonce(local_privkey2, DIGEST, 42)
|
||||||
|
|
||||||
|
global_pk = cosi.combine_keys([remote_commit.pubkey, local_pubkey1, local_pubkey2])
|
||||||
|
global_R = cosi.combine_keys(
|
||||||
|
[remote_commit.commitment, local_commitment1, local_commitment2]
|
||||||
|
)
|
||||||
|
|
||||||
|
remote_sig = cosi.sign(
|
||||||
|
client, parse_path("m/10018h/2h"), DIGEST, global_R, global_pk
|
||||||
|
)
|
||||||
|
local_sig1 = cosi.sign_with_privkey(
|
||||||
|
DIGEST, local_privkey1, global_pk, local_nonce1, global_R
|
||||||
|
)
|
||||||
|
local_sig2 = cosi.sign_with_privkey(
|
||||||
|
DIGEST, local_privkey2, global_pk, local_nonce2, global_R
|
||||||
|
)
|
||||||
|
signature = cosi.combine_sig(
|
||||||
|
global_R, [remote_sig.signature, local_sig1, local_sig2]
|
||||||
|
)
|
||||||
|
|
||||||
|
cosi.verify_combined(signature, DIGEST, global_pk)
|
||||||
|
@ -393,9 +393,11 @@
|
|||||||
"T1_ethereum-test_signtx.py::test_signtx_eip1559[unknown_erc20]": "548c1f22918351e9cbcc1e16d8ba67bc2e7460b9a92cfc6c8bfa0a2b063e68da",
|
"T1_ethereum-test_signtx.py::test_signtx_eip1559[unknown_erc20]": "548c1f22918351e9cbcc1e16d8ba67bc2e7460b9a92cfc6c8bfa0a2b063e68da",
|
||||||
"T1_ethereum-test_signtx.py::test_signtx_eip1559_access_list": "f6c5f398d4e80fc8f93cf70e9b10de24b9a968db04dc6ea21b28d1a273f04ca1",
|
"T1_ethereum-test_signtx.py::test_signtx_eip1559_access_list": "f6c5f398d4e80fc8f93cf70e9b10de24b9a968db04dc6ea21b28d1a273f04ca1",
|
||||||
"T1_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "f6c5f398d4e80fc8f93cf70e9b10de24b9a968db04dc6ea21b28d1a273f04ca1",
|
"T1_ethereum-test_signtx.py::test_signtx_eip1559_access_list_larger": "f6c5f398d4e80fc8f93cf70e9b10de24b9a968db04dc6ea21b28d1a273f04ca1",
|
||||||
"T1_misc-test_cosi.py::test_cosi_commit": "c943c92750d6072a3b272c1a9dca815ee7504293e4c1d85a76d5af9c2e415297",
|
"T1_misc-test_cosi.py::test_cosi_nonce": "6990c238036b79368fea1dc1e3e8871d7788322bbee7425d14c53623bc8182e8",
|
||||||
"T1_misc-test_cosi.py::test_cosi_compat": "dfdc383ac1dd9f1bb63b52c8623d3788491e7a954f6f0374fe0963e823a5e0c5",
|
"T1_misc-test_cosi.py::test_cosi_pubkey": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||||
"T1_misc-test_cosi.py::test_cosi_sign": "54f589eaca23d0e1a055280920b9a40c7ba7a5b34779270090a8361113af4574",
|
"T1_misc-test_cosi.py::test_cosi_sign1": "6990c238036b79368fea1dc1e3e8871d7788322bbee7425d14c53623bc8182e8",
|
||||||
|
"T1_misc-test_cosi.py::test_cosi_sign2": "0852e7433ec54a0ace301b683417107a9805095acd954010b665266503a79f36",
|
||||||
|
"T1_misc-test_cosi.py::test_cosi_sign3": "d04fca2d97f7117ffc79ae52d192086aba2f9c64e89db27e20a930e9048f1d81",
|
||||||
"T1_misc-test_msg_cipherkeyvalue.py::test_decrypt": "a849d9e11e222d1348ce3135680a2a61ed265692adeba4bd48af2fdc65207e61",
|
"T1_misc-test_msg_cipherkeyvalue.py::test_decrypt": "a849d9e11e222d1348ce3135680a2a61ed265692adeba4bd48af2fdc65207e61",
|
||||||
"T1_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
"T1_misc-test_msg_cipherkeyvalue.py::test_decrypt_badlen": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||||
"T1_misc-test_msg_cipherkeyvalue.py::test_encrypt": "e36d5b5db4b3733c9f484b149c0f966b3dd66e8b54e1b5bccf9da5cca7abed91",
|
"T1_misc-test_msg_cipherkeyvalue.py::test_encrypt": "e36d5b5db4b3733c9f484b149c0f966b3dd66e8b54e1b5bccf9da5cca7abed91",
|
||||||
|
Loading…
Reference in New Issue
Block a user