mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-22 22:38:08 +00:00
Merge pull request #105 from trezor/tsusanka/multisig
Multisignature signing
This commit is contained in:
commit
6e7a15c088
@ -74,21 +74,21 @@ STATIC mp_obj_t mod_trezorcrypto_HDNode_make_new(const mp_obj_type_t *type, size
|
||||
mp_get_buffer_raise(vals[5].u_obj, &public_key, MP_BUFFER_READ);
|
||||
mp_get_buffer_raise(vals[6].u_obj, &curve_name, MP_BUFFER_READ);
|
||||
|
||||
if (NULL == chain_code.buf || 32 != chain_code.len) {
|
||||
if (32 != chain_code.len) {
|
||||
mp_raise_ValueError("chain_code is invalid");
|
||||
}
|
||||
if (NULL == public_key.buf && NULL == private_key.buf) {
|
||||
if (0 == public_key.len && 0 == private_key.len) {
|
||||
mp_raise_ValueError("either public_key or private_key is required");
|
||||
}
|
||||
if (NULL != private_key.buf && 32 != private_key.len) {
|
||||
if (0 != private_key.len && 32 != private_key.len) {
|
||||
mp_raise_ValueError("private_key is invalid");
|
||||
}
|
||||
if (NULL != public_key.buf && 33 != public_key.len) {
|
||||
if (0 != public_key.len && 33 != public_key.len) {
|
||||
mp_raise_ValueError("public_key is invalid");
|
||||
}
|
||||
|
||||
const curve_info *curve = NULL;
|
||||
if (NULL == curve_name.buf) {
|
||||
if (0 == curve_name.len) {
|
||||
curve = get_curve_by_name(SECP256K1_NAME);
|
||||
} else {
|
||||
curve = get_curve_by_name(curve_name.buf);
|
||||
@ -103,17 +103,17 @@ STATIC mp_obj_t mod_trezorcrypto_HDNode_make_new(const mp_obj_type_t *type, size
|
||||
o->fingerprint = fingerprint;
|
||||
o->hdnode.depth = depth;
|
||||
o->hdnode.child_num = child_num;
|
||||
if (NULL != chain_code.buf && 32 == chain_code.len) {
|
||||
if (32 == chain_code.len) {
|
||||
memcpy(o->hdnode.chain_code, chain_code.buf, 32);
|
||||
} else {
|
||||
memzero(o->hdnode.chain_code, 32);
|
||||
}
|
||||
if (NULL != private_key.buf && 32 == private_key.len) {
|
||||
if (32 == private_key.len) {
|
||||
memcpy(o->hdnode.private_key, private_key.buf, 32);
|
||||
} else {
|
||||
memzero(o->hdnode.private_key, 32);
|
||||
}
|
||||
if (NULL != public_key.buf && 33 == public_key.len) {
|
||||
if (33 == public_key.len) {
|
||||
memcpy(o->hdnode.public_key, public_key.buf, 33);
|
||||
} else {
|
||||
memzero(o->hdnode.public_key, 33);
|
||||
@ -123,16 +123,27 @@ STATIC mp_obj_t mod_trezorcrypto_HDNode_make_new(const mp_obj_type_t *type, size
|
||||
return MP_OBJ_FROM_PTR(o);
|
||||
}
|
||||
|
||||
/// def derive(self, index: int) -> None:
|
||||
/// def derive(self, index: int, public: bool=False) -> None:
|
||||
/// '''
|
||||
/// Derive a BIP0032 child node in place.
|
||||
/// '''
|
||||
STATIC mp_obj_t mod_trezorcrypto_HDNode_derive(mp_obj_t self, mp_obj_t index) {
|
||||
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(self);
|
||||
uint32_t i = mp_obj_get_int_truncated(index);
|
||||
STATIC mp_obj_t mod_trezorcrypto_HDNode_derive(size_t n_args, const mp_obj_t *args) {
|
||||
mp_obj_HDNode_t *o = MP_OBJ_TO_PTR(args[0]);
|
||||
uint32_t i = mp_obj_get_int_truncated(args[1]);
|
||||
uint32_t fp = hdnode_fingerprint(&o->hdnode);
|
||||
bool public = n_args > 2 && args[2] == mp_const_true;
|
||||
|
||||
if (!hdnode_private_ckd(&o->hdnode, i)) {
|
||||
int res;
|
||||
if (public) {
|
||||
res = hdnode_public_ckd(&o->hdnode, i);
|
||||
} else {
|
||||
if (0 == memcmp(o->hdnode.private_key, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32)) {
|
||||
memzero(&o->hdnode, sizeof(o->hdnode));
|
||||
mp_raise_ValueError("Failed to derive, private key not set");
|
||||
}
|
||||
res = hdnode_private_ckd(&o->hdnode, i);
|
||||
}
|
||||
if (!res) {
|
||||
memzero(&o->hdnode, sizeof(o->hdnode));
|
||||
mp_raise_ValueError("Failed to derive");
|
||||
}
|
||||
@ -140,7 +151,7 @@ STATIC mp_obj_t mod_trezorcrypto_HDNode_derive(mp_obj_t self, mp_obj_t index) {
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_HDNode_derive_obj, mod_trezorcrypto_HDNode_derive);
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_HDNode_derive_obj, 2, 3, mod_trezorcrypto_HDNode_derive);
|
||||
|
||||
/// def derive_path(self, path: List[int]) -> None:
|
||||
/// '''
|
||||
|
@ -1,25 +1,45 @@
|
||||
from typing import *
|
||||
|
||||
# extmod/modtrezorconfig/modtrezorconfig.c
|
||||
def init(self) -> None:
|
||||
def init() -> None:
|
||||
'''
|
||||
Initializes the storage. Must be called before any other method is called from this module!
|
||||
Initializes the storage. Must be called before any other method is
|
||||
called from this module!
|
||||
'''
|
||||
|
||||
# extmod/modtrezorconfig/modtrezorconfig.c
|
||||
def get(app: int, key: int) -> bytes:
|
||||
def unlock(pin: int, waitcallback: (int, int -> None)) -> bool:
|
||||
'''
|
||||
Attempts to unlock the storage with given PIN. Returns True on
|
||||
success, False on failure.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorconfig/modtrezorconfig.c
|
||||
def has_pin() -> bool:
|
||||
'''
|
||||
Returns True if storage has a configured PIN, False otherwise.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorconfig/modtrezorconfig.c
|
||||
def change_pin(pin: int, newpin: int, waitcallback: (int, int -> None)) -> bool:
|
||||
'''
|
||||
Change PIN. Returns True on success, False on failure.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorconfig/modtrezorconfig.c
|
||||
def get(app: int, key: int, public: bool=False) -> bytes:
|
||||
'''
|
||||
Gets a value of given key for given app (or empty bytes if not set).
|
||||
'''
|
||||
|
||||
# extmod/modtrezorconfig/modtrezorconfig.c
|
||||
def set(app: int, key: int, value: bytes) -> None:
|
||||
def set(app: int, key: int, value: bytes, public: bool=False) -> None:
|
||||
'''
|
||||
Sets a value of given key for given app.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorconfig/modtrezorconfig.c
|
||||
def wipe(self) -> None:
|
||||
def wipe() -> None:
|
||||
'''
|
||||
Erases the whole config. Use with caution!
|
||||
'''
|
||||
|
@ -22,7 +22,18 @@ class HDNode:
|
||||
BIP0032 HD node structure.
|
||||
'''
|
||||
|
||||
def derive(self, index: int) -> None:
|
||||
def __init__(self,
|
||||
depth: int,
|
||||
fingerprint: int,
|
||||
child_num: int,
|
||||
chain_code: bytes,
|
||||
private_key: bytes = None,
|
||||
public_key: bytes = None,
|
||||
curve_name: str = None) -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
def derive(self, index: int, public: bool=False) -> None:
|
||||
'''
|
||||
Derive a BIP0032 child node in place.
|
||||
'''
|
||||
@ -82,13 +93,9 @@ class HDNode:
|
||||
Compute a base58-encoded address string from the HD node.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-bip32.h
|
||||
class Bip32:
|
||||
'''
|
||||
'''
|
||||
|
||||
def __init__(self):
|
||||
def ethereum_pubkeyhash(self) -> bytes:
|
||||
'''
|
||||
Compute an Ethereum pubkeyhash (aka address) from the HD node.
|
||||
'''
|
||||
|
||||
def deserialize(self, value: str, version_public: int, version_private: int) -> HDNode:
|
||||
@ -96,51 +103,69 @@ class Bip32:
|
||||
Construct a BIP0032 HD node from a base58-serialized value.
|
||||
'''
|
||||
|
||||
def from_seed(self, seed: bytes, curve_name: str) -> HDNode:
|
||||
def from_seed(seed: bytes, curve_name: str) -> HDNode:
|
||||
'''
|
||||
Construct a BIP0032 HD node from a BIP0039 seed value.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-bip39.h
|
||||
class Bip39:
|
||||
'''
|
||||
'''
|
||||
|
||||
def __init__(self):
|
||||
'''
|
||||
'''
|
||||
|
||||
def find_word(self, prefix: str) -> Optional[str]:
|
||||
def find_word(prefix: str) -> Optional[str]:
|
||||
'''
|
||||
Return the first word from the wordlist starting with prefix.
|
||||
'''
|
||||
|
||||
def complete_word(self, prefix: str) -> int:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-bip39.h
|
||||
def complete_word(prefix: str) -> int:
|
||||
'''
|
||||
Return possible 1-letter suffixes for given word prefix.
|
||||
Result is a bitmask, with 'a' on the lowest bit, 'b' on the second lowest, etc.
|
||||
'''
|
||||
|
||||
def generate(self, strength: int) -> str:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-bip39.h
|
||||
def generate(strength: int) -> str:
|
||||
'''
|
||||
Generate a mnemonic of given strength (128, 160, 192, 224 and 256 bits).
|
||||
'''
|
||||
|
||||
def from_data(self, data: bytes) -> str:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-bip39.h
|
||||
def from_data(data: bytes) -> str:
|
||||
'''
|
||||
Generate a mnemonic from given data (of 16, 20, 24, 28 and 32 bytes).
|
||||
'''
|
||||
|
||||
def check(self, mnemonic: str) -> bool:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-bip39.h
|
||||
def check(mnemonic: str) -> bool:
|
||||
'''
|
||||
Check whether given mnemonic is valid.
|
||||
'''
|
||||
|
||||
def seed(self, mnemonic: str, passphrase: str) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-bip39.h
|
||||
def seed(mnemonic: str, passphrase: str) -> bytes:
|
||||
'''
|
||||
Generate seed from mnemonic and passphrase.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-blake256.h
|
||||
class Blake256:
|
||||
'''
|
||||
Blake256 context.
|
||||
'''
|
||||
|
||||
def __init__(self, data: bytes = None) -> None:
|
||||
'''
|
||||
Creates a hash context object.
|
||||
'''
|
||||
|
||||
def update(self, data: bytes) -> None:
|
||||
'''
|
||||
Update the hash context with hashed data.
|
||||
'''
|
||||
|
||||
def digest(self) -> bytes:
|
||||
'''
|
||||
Returns the digest of hashed data.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-blake2b.h
|
||||
class Blake2b:
|
||||
'''
|
||||
@ -183,116 +208,139 @@ class Blake2s:
|
||||
Returns the digest of hashed data.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-chacha20poly1305.h
|
||||
class ChaCha20Poly1305:
|
||||
'''
|
||||
ChaCha20Poly1305 context.
|
||||
'''
|
||||
|
||||
def __init__(self, key: bytes, nonce: bytes) -> None:
|
||||
'''
|
||||
Initialize the ChaCha20 + Poly1305 context for encryption or decryption
|
||||
using a 32 byte key and 12 byte nonce as in the RFC 7539 style.
|
||||
'''
|
||||
|
||||
def encrypt(self, data: bytes) -> bytes:
|
||||
'''
|
||||
Encrypt data (length of data must be divisible by 64 except for the final value).
|
||||
'''
|
||||
|
||||
def decrypt(self, data: bytes) -> bytes:
|
||||
'''
|
||||
Decrypt data (length of data must be divisible by 64 except for the final value).
|
||||
'''
|
||||
|
||||
def auth(self, data: bytes) -> None:
|
||||
'''
|
||||
Include authenticated data in the Poly1305 MAC using the RFC 7539
|
||||
style with 16 byte padding. This must only be called once and prior
|
||||
to encryption or decryption.
|
||||
'''
|
||||
|
||||
def finish(self) -> bytes:
|
||||
'''
|
||||
Compute RFC 7539-style Poly1305 MAC.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-curve25519.h
|
||||
class Curve25519:
|
||||
'''
|
||||
'''
|
||||
|
||||
def __init__(self) -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
def generate_secret(self) -> bytes:
|
||||
def generate_secret() -> bytes:
|
||||
'''
|
||||
Generate secret key.
|
||||
'''
|
||||
|
||||
def publickey(self, secret_key: bytes) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-curve25519.h
|
||||
def publickey(secret_key: bytes) -> bytes:
|
||||
'''
|
||||
Computes public key from secret key.
|
||||
'''
|
||||
|
||||
def multiply(self, secret_key: bytes, public_key: bytes) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-curve25519.h
|
||||
def multiply(secret_key: bytes, public_key: bytes) -> bytes:
|
||||
'''
|
||||
Multiplies point defined by public_key with scalar defined by secret_key.
|
||||
Useful for ECDH.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h
|
||||
class Ed25519:
|
||||
'''
|
||||
'''
|
||||
|
||||
def __init__(self) -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
def generate_secret(self) -> bytes:
|
||||
def generate_secret() -> bytes:
|
||||
'''
|
||||
Generate secret key.
|
||||
'''
|
||||
|
||||
def publickey(self, secret_key: bytes) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h
|
||||
def publickey(secret_key: bytes) -> bytes:
|
||||
'''
|
||||
Computes public key from secret key.
|
||||
'''
|
||||
|
||||
def sign(self, secret_key: bytes, message: bytes) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h
|
||||
def sign(secret_key: bytes, message: bytes) -> bytes:
|
||||
'''
|
||||
Uses secret key to produce the signature of message.
|
||||
'''
|
||||
|
||||
def verify(self, public_key: bytes, signature: bytes, message: bytes) -> bool:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h
|
||||
def verify(public_key: bytes, signature: bytes, message: bytes) -> bool:
|
||||
'''
|
||||
Uses public key to verify the signature of the message.
|
||||
Returns True on success.
|
||||
'''
|
||||
|
||||
def cosi_combine_publickeys(self, public_keys: List[bytes]) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h
|
||||
def cosi_combine_publickeys(public_keys: List[bytes]) -> bytes:
|
||||
'''
|
||||
Combines a list of public keys used in COSI cosigning scheme.
|
||||
'''
|
||||
|
||||
def cosi_combine_signatures(self, R: bytes, signatures: List[bytes]) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h
|
||||
def cosi_combine_signatures(R: bytes, signatures: List[bytes]) -> bytes:
|
||||
'''
|
||||
Combines a list of signatures used in COSI cosigning scheme.
|
||||
'''
|
||||
|
||||
def cosi_sign(self, secret_key: bytes, message: bytes, nonce: bytes, sigR: bytes, combined_pubkey: bytes) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h
|
||||
def cosi_sign(secret_key: bytes, message: bytes, nonce: bytes, sigR: bytes, combined_pubkey: bytes) -> bytes:
|
||||
'''
|
||||
Produce signature of message using COSI cosigning scheme.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h
|
||||
class Nist256p1:
|
||||
'''
|
||||
'''
|
||||
|
||||
def __init__(self) -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
def generate_secret(self) -> bytes:
|
||||
def generate_secret() -> bytes:
|
||||
'''
|
||||
Generate secret key.
|
||||
'''
|
||||
|
||||
def publickey(self, secret_key: bytes, compressed: bool = True) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h
|
||||
def publickey(secret_key: bytes, compressed: bool = True) -> bytes:
|
||||
'''
|
||||
Computes public key from secret key.
|
||||
'''
|
||||
|
||||
def sign(self, secret_key: bytes, digest: bytes, compressed: bool = True) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h
|
||||
def sign(secret_key: bytes, digest: bytes, compressed: bool = True) -> bytes:
|
||||
'''
|
||||
Uses secret key to produce the signature of the digest.
|
||||
'''
|
||||
|
||||
def verify(self, public_key: bytes, signature: bytes, digest: bytes) -> bool:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h
|
||||
def verify(public_key: bytes, signature: bytes, digest: bytes) -> bool:
|
||||
'''
|
||||
Uses public key to verify the signature of the digest.
|
||||
Returns True on success.
|
||||
'''
|
||||
|
||||
def verify_recover(self, signature: bytes, digest: bytes) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h
|
||||
def verify_recover(signature: bytes, digest: bytes) -> bytes:
|
||||
'''
|
||||
Uses signature of the digest to verify the digest and recover the public key.
|
||||
Returns public key on success, None on failure.
|
||||
'''
|
||||
|
||||
def multiply(self, secret_key: bytes, public_key: bytes) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-nist256p1.h
|
||||
def multiply(secret_key: bytes, public_key: bytes) -> bytes:
|
||||
'''
|
||||
Multiplies point defined by public_key with scalar defined by secret_key
|
||||
Useful for ECDH
|
||||
Multiplies point defined by public_key with scalar defined by secret_key.
|
||||
Useful for ECDH.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-pbkdf2.h
|
||||
@ -317,27 +365,21 @@ class Pbkdf2:
|
||||
'''
|
||||
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-random.h
|
||||
class Random:
|
||||
def uniform(n: int) -> int:
|
||||
'''
|
||||
Compute uniform random number from interval 0 ... n - 1.
|
||||
'''
|
||||
|
||||
def __init__(self) -> None:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-random.h
|
||||
def bytes(len: int) -> bytes:
|
||||
'''
|
||||
Generate random bytes sequence of length len.
|
||||
'''
|
||||
|
||||
def uniform(self, n: int) -> int:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-random.h
|
||||
def shuffle(data: list) -> None:
|
||||
'''
|
||||
Compute uniform random number from interval 0 ... n - 1
|
||||
'''
|
||||
|
||||
def bytes(self, len: int) -> bytes:
|
||||
'''
|
||||
Generate random bytes sequence of length len
|
||||
'''
|
||||
|
||||
def shuffle(self, data: list) -> None:
|
||||
'''
|
||||
Shuffles items of given list (in-place)
|
||||
Shuffles items of given list (in-place).
|
||||
'''
|
||||
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-rfc6979.h
|
||||
@ -378,42 +420,39 @@ class Ripemd160:
|
||||
'''
|
||||
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h
|
||||
class Secp256k1:
|
||||
'''
|
||||
'''
|
||||
|
||||
def __init__(self) -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
def generate_secret(self, ) -> bytes:
|
||||
def generate_secret() -> bytes:
|
||||
'''
|
||||
Generate secret key.
|
||||
'''
|
||||
|
||||
def publickey(self, secret_key: bytes, compressed: bool = True) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h
|
||||
def publickey(secret_key: bytes, compressed: bool = True) -> bytes:
|
||||
'''
|
||||
Computes public key from secret key.
|
||||
'''
|
||||
|
||||
def sign(self, secret_key: bytes, digest: bytes, compressed: bool = True) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h
|
||||
def sign(secret_key: bytes, digest: bytes, compressed: bool = True) -> bytes:
|
||||
'''
|
||||
Uses secret key to produce the signature of the digest.
|
||||
'''
|
||||
|
||||
def verify(self, public_key: bytes, signature: bytes, digest: bytes) -> bool:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h
|
||||
def verify(public_key: bytes, signature: bytes, digest: bytes) -> bool:
|
||||
'''
|
||||
Uses public key to verify the signature of the digest.
|
||||
Returns True on success.
|
||||
'''
|
||||
|
||||
def verify_recover(self, signature: bytes, digest: bytes) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h
|
||||
def verify_recover(signature: bytes, digest: bytes) -> bytes:
|
||||
'''
|
||||
Uses signature of the digest to verify the digest and recover the public key.
|
||||
Returns public key on success, None on failure.
|
||||
'''
|
||||
|
||||
def multiply(self, secret_key: bytes, public_key: bytes) -> bytes:
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-secp256k1.h
|
||||
def multiply(secret_key: bytes, public_key: bytes) -> bytes:
|
||||
'''
|
||||
Multiplies point defined by public_key with scalar defined by secret_key.
|
||||
Useful for ECDH.
|
||||
@ -523,22 +562,3 @@ class Sha512:
|
||||
'''
|
||||
Returns the digest of hashed data.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorcrypto/modtrezorcrypto-ssss.h
|
||||
class SSSS:
|
||||
'''
|
||||
'''
|
||||
|
||||
def __init__(self) -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
def split(self, m: int, n: int, secret: bytes) -> tuple:
|
||||
'''
|
||||
Split secret to (M of N) shares using Shamir's Secret Sharing Scheme.
|
||||
'''
|
||||
|
||||
def combine(self, shares: tuple) -> bytes:
|
||||
'''
|
||||
Combine M shares of Shamir's Secret Sharing Scheme into secret.
|
||||
'''
|
||||
|
@ -1,5 +1,87 @@
|
||||
from typing import *
|
||||
|
||||
# extmod/modtrezorio/modtrezorio-flash.h
|
||||
class FlashOTP:
|
||||
'''
|
||||
'''
|
||||
|
||||
def __init__(self) -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
def FlashOTP.write(self, block: int, offset: int, data: bytes) -> None:
|
||||
'''
|
||||
Writes data to OTP flash
|
||||
'''
|
||||
|
||||
def FlashOTP.read(self, block: int, offset: int, data: bytearray) -> None:
|
||||
'''
|
||||
Reads data from OTP flash
|
||||
'''
|
||||
|
||||
def FlashOTP.lock(self, block: int) -> None:
|
||||
'''
|
||||
Lock OTP flash block
|
||||
'''
|
||||
|
||||
def FlashOTP.is_locked(self, block: int) -> bool:
|
||||
'''
|
||||
Is OTP flash block locked?
|
||||
'''
|
||||
|
||||
# extmod/modtrezorio/modtrezorio-hid.h
|
||||
class HID:
|
||||
'''
|
||||
USB HID interface configuration.
|
||||
'''
|
||||
|
||||
def __init__(self,
|
||||
iface_num: int,
|
||||
ep_in: int,
|
||||
ep_out: int,
|
||||
report_desc: bytes,
|
||||
subclass: int = 0,
|
||||
protocol: int = 0,
|
||||
polling_interval: int = 1,
|
||||
max_packet_len: int = 64) -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
def iface_num(self) -> int:
|
||||
'''
|
||||
Returns the configured number of this interface.
|
||||
'''
|
||||
|
||||
def write(self, msg: bytes) -> int:
|
||||
'''
|
||||
Sends message using USB HID (device) or UDP (emulator).
|
||||
'''
|
||||
|
||||
# extmod/modtrezorio/modtrezorio-poll.h
|
||||
def poll(ifaces: Iterable[int], list_ref: List, timeout_us: int) -> bool:
|
||||
'''
|
||||
Wait until one of `ifaces` is ready to read or write (using masks
|
||||
`list_ref`:
|
||||
`list_ref[0]` - the interface number, including the mask
|
||||
`list_ref[1]` - for touch event, tuple of (event_type, x_position, y_position)
|
||||
- for USB read event, received bytes
|
||||
If timeout occurs, False is returned, True otherwise.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorio/modtrezorio-sbu.h
|
||||
class SBU:
|
||||
'''
|
||||
'''
|
||||
|
||||
def __init__(self) -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
def set(self, sbu1: bool, sbu2: bool) -> None:
|
||||
'''
|
||||
Sets SBU wires to sbu1 and sbu2 values respectively
|
||||
'''
|
||||
|
||||
# extmod/modtrezorio/modtrezorio-sdcard.h
|
||||
class SDCard:
|
||||
'''
|
||||
@ -27,12 +109,94 @@ class SDCard:
|
||||
|
||||
def read(self, block_num: int, buf: bytearray) -> bool:
|
||||
'''
|
||||
Reads block_num block from the SD card into buf.
|
||||
Reads blocks starting with block_num from the SD card into buf.
|
||||
Number of bytes read is length of buf rounded down to multiply of SDCARD_BLOCK_SIZE.
|
||||
Returns True if in case of success, False otherwise.
|
||||
'''
|
||||
|
||||
def write(self, block_num: int, buf: bytes) -> bool:
|
||||
'''
|
||||
Writes block_num block from buf to the SD card.
|
||||
Writes blocks starting with block_num from buf to the SD card.
|
||||
Number of bytes written is length of buf rounded down to multiply of SDCARD_BLOCK_SIZE.
|
||||
Returns True if in case of success, False otherwise.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorio/modtrezorio-usb.h
|
||||
class USB:
|
||||
'''
|
||||
USB device configuration.
|
||||
'''
|
||||
|
||||
def __init__(self,
|
||||
vendor_id: int,
|
||||
product_id: int,
|
||||
release_num: int,
|
||||
manufacturer: str='',
|
||||
product: str='',
|
||||
serial_number: str='',
|
||||
configuration: str='',
|
||||
interface: str='') -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
def add(self, iface: Union[HID, VCP, WebUSB]) -> None:
|
||||
'''
|
||||
Registers passed interface into the USB stack.
|
||||
'''
|
||||
|
||||
def open(self) -> None:
|
||||
'''
|
||||
Initializes the USB stack.
|
||||
'''
|
||||
|
||||
def close(self) -> None:
|
||||
'''
|
||||
Cleans up the USB stack.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorio/modtrezorio-vcp.h
|
||||
class VCP:
|
||||
'''
|
||||
USB VCP interface configuration.
|
||||
'''
|
||||
|
||||
def __init__(self,
|
||||
iface_num: int,
|
||||
data_iface_num: int,
|
||||
ep_in: int,
|
||||
ep_out: int,
|
||||
ep_cmd: int) -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
def iface_num(self) -> int:
|
||||
'''
|
||||
Returns the configured number of this interface.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorio/modtrezorio-webusb.h
|
||||
class WebUSB:
|
||||
'''
|
||||
USB WebUSB interface configuration.
|
||||
'''
|
||||
|
||||
def __init__(self,
|
||||
iface_num: int,
|
||||
ep_in: int,
|
||||
ep_out: int,
|
||||
subclass: int = 0,
|
||||
protocol: int = 0,
|
||||
polling_interval: int = 1,
|
||||
max_packet_len: int = 64) -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
def iface_num(self) -> int:
|
||||
'''
|
||||
Returns the configured number of this interface.
|
||||
'''
|
||||
|
||||
def write(self, msg: bytes) -> int:
|
||||
'''
|
||||
Sends message using USB WebUSB (device) or UDP (emulator).
|
||||
'''
|
||||
|
@ -1,83 +0,0 @@
|
||||
from typing import *
|
||||
|
||||
# extmod/modtrezormsg/modtrezormsg.c
|
||||
class HID:
|
||||
'''
|
||||
USB HID interface configuration.
|
||||
'''
|
||||
|
||||
def __init__(self,
|
||||
iface_num: int,
|
||||
ep_in: int,
|
||||
ep_out: int,
|
||||
report_desc: bytes,
|
||||
subclass: int = 0,
|
||||
protocol: int = 0,
|
||||
polling_interval: int = 1,
|
||||
max_packet_len: int = 64) -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
# extmod/modtrezormsg/modtrezormsg.c
|
||||
class VCP:
|
||||
'''
|
||||
USB VCP interface configuration.
|
||||
'''
|
||||
|
||||
def __init__(self,
|
||||
iface_num: int,
|
||||
data_iface_num: int,
|
||||
ep_in: int,
|
||||
ep_out: int,
|
||||
ep_cmd: int) -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
# extmod/modtrezormsg/modtrezormsg.c
|
||||
class USB:
|
||||
'''
|
||||
USB device configuration.
|
||||
'''
|
||||
|
||||
def __init__(self,
|
||||
vendor_id: int,
|
||||
product_id: int,
|
||||
release_num: int,
|
||||
manufacturer_str: str,
|
||||
product_str: str,
|
||||
serial_number_str: str,
|
||||
configuration_str: str = '',
|
||||
interface_str: str = '') -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
# extmod/modtrezormsg/modtrezormsg.c
|
||||
class Msg:
|
||||
'''
|
||||
Interface with USB and touch events.
|
||||
'''
|
||||
|
||||
def __init__(self) -> None:
|
||||
'''
|
||||
'''
|
||||
|
||||
def init_usb(self, usb_info: USB, usb_ifaces: List[Union[HID, VCP]]) -> None:
|
||||
'''
|
||||
Registers passed interfaces and initializes the USB stack.
|
||||
'''
|
||||
|
||||
def deinit_usb(self) -> None:
|
||||
'''
|
||||
Cleans up the USB stack
|
||||
'''
|
||||
|
||||
def send(self, iface: int, message: bytes) -> int:
|
||||
'''
|
||||
Sends message using USB HID (device) or UDP (emulator).
|
||||
'''
|
||||
|
||||
def select(self, timeout_us: int) -> tuple:
|
||||
'''
|
||||
Polls the event queue and returns the event object.
|
||||
Function returns None if timeout specified in microseconds is reached.
|
||||
'''
|
@ -38,10 +38,17 @@ class Display:
|
||||
The image needs to be in TREZOR Optimized Image Format (TOIF) - full-color mode.
|
||||
'''
|
||||
|
||||
def avatar(self, x: int, y: int, image: bytes, fgcolor: int, bgcolor: int) -> None:
|
||||
'''
|
||||
Renders an avatar at position (x,y).
|
||||
The image needs to be in TREZOR Optimized Image Format (TOIF) - full-color mode.
|
||||
Image needs to be of exactly AVATAR_IMAGE_SIZE x AVATAR_IMAGE_SIZE pixels size.
|
||||
'''
|
||||
|
||||
def icon(self, x: int, y: int, icon: bytes, fgcolor: int, bgcolor: int) -> None:
|
||||
'''
|
||||
Renders an icon at position (x,y), fgcolor is used as foreground color, bgcolor as background.
|
||||
The image needs to be in TREZOR Optimized Image Format (TOIF) - gray-scale mode.
|
||||
The icon needs to be in TREZOR Optimized Image Format (TOIF) - gray-scale mode.
|
||||
'''
|
||||
|
||||
def print(self, text: str) -> None:
|
||||
@ -49,19 +56,19 @@ class Display:
|
||||
Renders text using 5x8 bitmap font (using special text mode).
|
||||
'''
|
||||
|
||||
def text(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor: int) -> None:
|
||||
def text(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor: int, minwidth: int=None) -> None:
|
||||
'''
|
||||
Renders left-aligned text at position (x,y) where x is left position and y is baseline.
|
||||
Font font is used for rendering, fgcolor is used as foreground color, bgcolor as background.
|
||||
'''
|
||||
|
||||
def text_center(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor: int) -> None:
|
||||
def text_center(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor: int, minwidth: int=None) -> None:
|
||||
'''
|
||||
Renders text centered at position (x,y) where x is text center and y is baseline.
|
||||
Font font is used for rendering, fgcolor is used as foreground color, bgcolor as background.
|
||||
'''
|
||||
|
||||
def text_right(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor: int) -> None:
|
||||
def text_right(self, x: int, y: int, text: str, font: int, fgcolor: int, bgcolor: int, minwidth: int=None) -> None:
|
||||
'''
|
||||
Renders right-aligned text at position (x,y) where x is right position and y is baseline.
|
||||
Font font is used for rendering, fgcolor is used as foreground color, bgcolor as background.
|
||||
|
@ -1,5 +1,14 @@
|
||||
from typing import *
|
||||
|
||||
# extmod/modtrezorutils/modtrezorutils.c
|
||||
def consteq(sec: bytes, pub: bytes) -> bool:
|
||||
'''
|
||||
Compares the private information in `sec` with public, user-provided
|
||||
information in `pub`. Runs in constant time, corresponding to a length
|
||||
of `pub`. Can access memory behind valid length of `sec`, caller is
|
||||
expected to avoid any invalid memory access.
|
||||
'''
|
||||
|
||||
# extmod/modtrezorutils/modtrezorutils.c
|
||||
def memcpy(dst: bytearray, dst_ofs: int,
|
||||
src: bytearray, src_ofs: int,
|
||||
|
@ -1,3 +1,7 @@
|
||||
import micropython
|
||||
import gc
|
||||
from uctypes import bytes_at, bytearray_at
|
||||
|
||||
from trezor import log
|
||||
from trezor import loop
|
||||
from trezor.utils import unimport
|
||||
@ -5,62 +9,50 @@ from trezor.wire import register, protobuf_workflow
|
||||
from trezor.messages.wire_types import \
|
||||
DebugLinkDecision, DebugLinkGetState, DebugLinkStop, \
|
||||
DebugLinkMemoryRead, DebugLinkMemoryWrite, DebugLinkFlashErase
|
||||
from trezor.messages.DebugLinkMemory import DebugLinkMemory
|
||||
from trezor.messages.DebugLinkState import DebugLinkState
|
||||
from trezor.ui.confirm import CONFIRMED, CANCELLED
|
||||
|
||||
from apps.common.confirm import signal
|
||||
from apps.common import storage
|
||||
from apps.management import reset_device
|
||||
|
||||
|
||||
@unimport
|
||||
async def dispatch_DebugLinkDecision(ctx, msg):
|
||||
from trezor.ui.confirm import CONFIRMED, CANCELLED
|
||||
from apps.common.confirm import signal
|
||||
signal.send(CONFIRMED if msg.yes_no else CANCELLED)
|
||||
|
||||
|
||||
@unimport
|
||||
async def dispatch_DebugLinkGetState(ctx, msg):
|
||||
from trezor.messages.DebugLinkState import DebugLinkState
|
||||
from apps.common import storage
|
||||
from apps.management import reset_device
|
||||
|
||||
m = DebugLinkState()
|
||||
m.mnemonic = storage.get_mnemonic()
|
||||
m.passphrase_protection = storage.has_passphrase()
|
||||
m.reset_entropy = reset_device.internal_entropy
|
||||
m.reset_word = reset_device.current_word
|
||||
|
||||
return m
|
||||
|
||||
|
||||
@unimport
|
||||
async def dispatch_DebugLinkStop(ctx, msg):
|
||||
pass
|
||||
|
||||
|
||||
@unimport
|
||||
async def dispatch_DebugLinkMemoryRead(ctx, msg):
|
||||
from trezor.messages.DebugLinkMemory import DebugLinkMemory
|
||||
from uctypes import bytes_at
|
||||
m = DebugLinkMemory()
|
||||
m.memory = bytes_at(msg.address, msg.length)
|
||||
return m
|
||||
|
||||
|
||||
@unimport
|
||||
async def dispatch_DebugLinkMemoryWrite(ctx, msg):
|
||||
from uctypes import bytearray_at
|
||||
l = len(msg.memory)
|
||||
data = bytearray_at(msg.address, l)
|
||||
data[0:l] = msg.memory
|
||||
|
||||
|
||||
@unimport
|
||||
async def dispatch_DebugLinkFlashErase(ctx, msg):
|
||||
# TODO: erase(msg.sector)
|
||||
pass
|
||||
|
||||
|
||||
async def memory_stats(interval):
|
||||
import micropython
|
||||
import gc
|
||||
|
||||
sleep = loop.sleep(interval * 1000 * 1000)
|
||||
while True:
|
||||
micropython.mem_info()
|
||||
|
@ -1,24 +1,20 @@
|
||||
from micropython import const
|
||||
from trezor import wire, ui
|
||||
from trezor import ui
|
||||
|
||||
|
||||
async def layout_get_address(ctx, msg):
|
||||
from trezor.messages.Address import Address
|
||||
from trezor.messages.InputScriptType import SPENDWITNESS
|
||||
from trezor.messages.FailureType import ProcessError
|
||||
from ..common import coins
|
||||
from ..common import seed
|
||||
from ..wallet.sign_tx import addresses
|
||||
|
||||
if msg.multisig:
|
||||
raise wire.FailureError(ProcessError, 'GetAddress.multisig is unsupported')
|
||||
|
||||
address_n = msg.address_n or ()
|
||||
coin_name = msg.coin_name or 'Bitcoin'
|
||||
coin = coins.by_name(coin_name)
|
||||
|
||||
node = await seed.derive_node(ctx, address_n)
|
||||
address = addresses.get_address(msg.script_type, coin, node)
|
||||
address = addresses.get_address(msg.script_type, coin, node, msg.multisig)
|
||||
|
||||
if msg.show_display:
|
||||
while True:
|
||||
|
@ -21,6 +21,10 @@ async def sign_tx(ctx, msg):
|
||||
raise wire.FailureError(*e.args)
|
||||
except signing.AddressError as e:
|
||||
raise wire.FailureError(*e.args)
|
||||
except signing.ScriptsError as e:
|
||||
raise wire.FailureError(*e.args)
|
||||
except signing.Bip143Error as e:
|
||||
raise wire.FailureError(*e.args)
|
||||
if req.__qualname__ == 'TxRequest':
|
||||
if req.request_type == TXFINISHED:
|
||||
break
|
||||
|
@ -8,6 +8,9 @@ from trezor.messages.CoinType import CoinType
|
||||
from trezor.messages import FailureType
|
||||
from trezor.messages import InputScriptType
|
||||
|
||||
from apps.wallet.sign_tx.scripts import *
|
||||
from apps.wallet.sign_tx.multisig import *
|
||||
|
||||
# supported witness version for bech32 addresses
|
||||
_BECH32_WITVER = const(0x00)
|
||||
|
||||
@ -16,21 +19,50 @@ class AddressError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def get_address(script_type: InputScriptType, coin: CoinType, node) -> str:
|
||||
def get_address(script_type: InputScriptType, coin: CoinType, node, multisig=None) -> str:
|
||||
|
||||
if script_type == InputScriptType.SPENDADDRESS: # p2pkh
|
||||
if script_type == InputScriptType.SPENDADDRESS or script_type == InputScriptType.SPENDMULTISIG:
|
||||
if multisig: # p2sh multisig
|
||||
pubkey = node.public_key()
|
||||
index = multisig_pubkey_index(multisig, pubkey)
|
||||
if index is None:
|
||||
raise AddressError(FailureType.ProcessError,
|
||||
'Public key not found')
|
||||
if coin.address_type_p2sh is None:
|
||||
raise AddressError(FailureType.ProcessError,
|
||||
'Multisig not enabled on this coin')
|
||||
|
||||
pubkeys = multisig_get_pubkeys(multisig)
|
||||
return address_multisig_p2sh(pubkeys, multisig.m, coin.address_type_p2sh)
|
||||
if script_type == InputScriptType.SPENDMULTISIG:
|
||||
raise AddressError(FailureType.ProcessError,
|
||||
'Multisig details required')
|
||||
|
||||
# p2pkh
|
||||
return node.address(coin.address_type)
|
||||
|
||||
elif script_type == InputScriptType.SPENDWITNESS: # native p2wpkh
|
||||
elif script_type == InputScriptType.SPENDWITNESS: # native p2wpkh or native p2wsh
|
||||
if not coin.segwit or not coin.bech32_prefix:
|
||||
raise AddressError(FailureType.ProcessError,
|
||||
'Segwit not enabled on this coin')
|
||||
# native p2wsh multisig
|
||||
if multisig is not None:
|
||||
pubkeys = multisig_get_pubkeys(multisig)
|
||||
return address_multisig_p2wsh(pubkeys, multisig.m, coin.bech32_prefix)
|
||||
|
||||
# native p2wpkh
|
||||
return address_p2wpkh(node.public_key(), coin.bech32_prefix)
|
||||
|
||||
elif script_type == InputScriptType.SPENDP2SHWITNESS: # p2wpkh using p2sh
|
||||
if not coin.segwit or not coin.address_type_p2sh:
|
||||
elif script_type == InputScriptType.SPENDP2SHWITNESS: # p2wpkh or p2wsh nested in p2sh
|
||||
if not coin.segwit or coin.address_type_p2sh is None:
|
||||
raise AddressError(FailureType.ProcessError,
|
||||
'Segwit not enabled on this coin')
|
||||
# p2wsh multisig nested in p2sh
|
||||
if multisig is not None:
|
||||
pubkeys = multisig_get_pubkeys(multisig)
|
||||
return address_multisig_p2wsh_in_p2sh(pubkeys, multisig.m, coin.address_type_p2sh)
|
||||
|
||||
# p2wpkh nested in p2sh
|
||||
return address_p2wpkh_in_p2sh(node.public_key(), coin.address_type_p2sh)
|
||||
|
||||
else:
|
||||
@ -38,21 +70,51 @@ def get_address(script_type: InputScriptType, coin: CoinType, node) -> str:
|
||||
'Invalid script type')
|
||||
|
||||
|
||||
def address_p2wpkh_in_p2sh(pubkey: bytes, addrtype: int) -> str:
|
||||
def address_multisig_p2sh(pubkeys: bytes, m: int, addrtype: int):
|
||||
if addrtype is None:
|
||||
raise AddressError(FailureType.ProcessError,
|
||||
'Multisig not enabled on this coin')
|
||||
redeem_script = output_script_multisig(pubkeys, m)
|
||||
redeem_script_hash = sha256_ripemd160_digest(redeem_script)
|
||||
return address_p2sh(redeem_script_hash, addrtype)
|
||||
|
||||
|
||||
def address_multisig_p2wsh_in_p2sh(pubkeys: bytes, m: int, addrtype: int):
|
||||
if addrtype is None:
|
||||
raise AddressError(FailureType.ProcessError,
|
||||
'Multisig not enabled on this coin')
|
||||
witness_script = output_script_multisig(pubkeys, m)
|
||||
witness_script_hash = sha256(witness_script).digest()
|
||||
return address_p2wsh_in_p2sh(witness_script_hash, addrtype)
|
||||
|
||||
|
||||
def address_multisig_p2wsh(pubkeys: bytes, m: int, hrp: str):
|
||||
if not hrp:
|
||||
raise AddressError(FailureType.ProcessError,
|
||||
'Multisig not enabled on this coin')
|
||||
witness_script = output_script_multisig(pubkeys, m)
|
||||
witness_script_hash = sha256(witness_script).digest()
|
||||
return address_p2wsh(witness_script_hash, hrp)
|
||||
|
||||
|
||||
def address_p2sh(redeem_script_hash: bytes, addrtype: int) -> str:
|
||||
s = bytearray(21)
|
||||
s[0] = addrtype
|
||||
s[1:21] = address_p2wpkh_in_p2sh_raw(pubkey)
|
||||
s[1:21] = redeem_script_hash
|
||||
return base58.encode_check(bytes(s))
|
||||
|
||||
|
||||
def address_p2wpkh_in_p2sh_raw(pubkey: bytes) -> bytes:
|
||||
s = bytearray(22)
|
||||
s[0] = 0x00 # OP_0
|
||||
s[1] = 0x14 # pushing 20 bytes
|
||||
s[2:22] = ecdsa_hash_pubkey(pubkey)
|
||||
h = sha256(s).digest()
|
||||
h = ripemd160(h).digest()
|
||||
return h
|
||||
def address_p2wpkh_in_p2sh(pubkey: bytes, addrtype: int) -> str:
|
||||
pubkey_hash = ecdsa_hash_pubkey(pubkey)
|
||||
redeem_script = output_script_native_p2wpkh_or_p2wsh(pubkey_hash)
|
||||
redeem_script_hash = sha256_ripemd160_digest(redeem_script)
|
||||
return address_p2sh(redeem_script_hash, addrtype)
|
||||
|
||||
|
||||
def address_p2wsh_in_p2sh(witness_script_hash: bytes, addrtype: int) -> str:
|
||||
redeem_script = output_script_native_p2wpkh_or_p2wsh(witness_script_hash)
|
||||
redeem_script_hash = sha256_ripemd160_digest(redeem_script)
|
||||
return address_p2sh(redeem_script_hash, addrtype)
|
||||
|
||||
|
||||
def address_p2wpkh(pubkey: bytes, hrp: str) -> str:
|
||||
@ -64,6 +126,14 @@ def address_p2wpkh(pubkey: bytes, hrp: str) -> str:
|
||||
return address
|
||||
|
||||
|
||||
def address_p2wsh(witness_script_hash: bytes, hrp: str) -> str:
|
||||
address = bech32.encode(hrp, _BECH32_WITVER, witness_script_hash)
|
||||
if address is None:
|
||||
raise AddressError(FailureType.ProcessError,
|
||||
'Invalid address')
|
||||
return address
|
||||
|
||||
|
||||
def decode_bech32_address(prefix: str, address: str) -> bytes:
|
||||
witver, raw = bech32.decode(prefix, address)
|
||||
if witver != _BECH32_WITVER:
|
||||
|
88
src/apps/wallet/sign_tx/multisig.py
Normal file
88
src/apps/wallet/sign_tx/multisig.py
Normal file
@ -0,0 +1,88 @@
|
||||
from trezor.crypto.hashlib import sha256
|
||||
from trezor.crypto import bip32
|
||||
|
||||
from trezor.messages.MultisigRedeemScriptType import MultisigRedeemScriptType
|
||||
from trezor.messages.HDNodePathType import HDNodePathType
|
||||
|
||||
from apps.wallet.sign_tx.writers import *
|
||||
from apps.common.hash_writer import *
|
||||
|
||||
|
||||
class MultisigFingerprint:
|
||||
def __init__(self):
|
||||
self.fingerprint = None # multisig fingerprint bytes
|
||||
self.mismatch = False # flag if multisig input fingerprints are equal
|
||||
|
||||
def add(self, multisig: MultisigRedeemScriptType):
|
||||
fp = multisig_fingerprint(multisig)
|
||||
assert fp is not None
|
||||
if self.fingerprint is None:
|
||||
self.fingerprint = fp
|
||||
elif self.fingerprint != fp:
|
||||
self.mismatch = True
|
||||
|
||||
def matches(self, multisig: MultisigRedeemScriptType):
|
||||
fp = multisig_fingerprint(multisig)
|
||||
assert fp is not None
|
||||
if self.mismatch is False and self.fingerprint == fp:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def multisig_fingerprint(multisig: MultisigRedeemScriptType) -> bytes:
|
||||
pubkeys = multisig.pubkeys
|
||||
m = multisig.m
|
||||
n = len(pubkeys)
|
||||
|
||||
if n < 1 or n > 15 or m < 1 or m > 15:
|
||||
raise SigningError(FailureType.DataError,
|
||||
'Invalid multisig parameters')
|
||||
|
||||
for hd in pubkeys:
|
||||
d = hd.node
|
||||
if len(d.public_key) != 33 or len(d.chain_code) != 32:
|
||||
raise SigningError(FailureType.DataError,
|
||||
'Invalid multisig parameters')
|
||||
|
||||
# casting to bytes(), sorting on bytearray() is not supported in MicroPython
|
||||
pubkeys = sorted(pubkeys, key=lambda hd: bytes(hd.node.public_key))
|
||||
|
||||
h = HashWriter(sha256)
|
||||
write_uint32(h, m)
|
||||
write_uint32(h, n)
|
||||
for hd in pubkeys:
|
||||
d = hd.node
|
||||
write_uint32(h, d.depth)
|
||||
write_uint32(h, d.fingerprint)
|
||||
write_uint32(h, d.child_num)
|
||||
write_bytes(h, d.chain_code)
|
||||
write_bytes(h, d.public_key)
|
||||
|
||||
return h.get_digest()
|
||||
|
||||
|
||||
def multisig_pubkey_index(multisig: MultisigRedeemScriptType, pubkey: bytes) -> int:
|
||||
for i, hd in enumerate(multisig.pubkeys):
|
||||
if multisig_get_pubkey(hd) == pubkey:
|
||||
return i
|
||||
raise SigningError(FailureType.DataError,
|
||||
'Pubkey not found in multisig script')
|
||||
|
||||
|
||||
def multisig_get_pubkey(hd: HDNodePathType) -> bytes:
|
||||
p = hd.address_n
|
||||
n = hd.node
|
||||
node = bip32.HDNode(
|
||||
depth=n.depth,
|
||||
fingerprint=n.fingerprint,
|
||||
child_num=n.child_num,
|
||||
chain_code=n.chain_code,
|
||||
public_key=n.public_key)
|
||||
for i in p:
|
||||
node.derive(i, True)
|
||||
return node.public_key()
|
||||
|
||||
|
||||
def multisig_get_pubkeys(multisig: MultisigRedeemScriptType):
|
||||
return [multisig_get_pubkey(hd) for hd in multisig.pubkeys]
|
@ -1,20 +1,21 @@
|
||||
from trezor.crypto.hashlib import ripemd160, sha256
|
||||
from apps.wallet.sign_tx.multisig import multisig_get_pubkeys
|
||||
from apps.wallet.sign_tx.writers import *
|
||||
|
||||
|
||||
# TX Scripts
|
||||
class ScriptsError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
# P2PKH, P2SH
|
||||
# ===
|
||||
# https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki
|
||||
|
||||
# -------------------------- First gen --------------------------
|
||||
|
||||
# =============== P2PK ===============
|
||||
# obsolete
|
||||
|
||||
|
||||
# =============== P2PKH ===============
|
||||
|
||||
def input_script_p2pkh_or_p2sh(pubkey: bytes, signature: bytes, sighash: int) -> bytearray:
|
||||
w = bytearray_with_cap(5 + len(signature) + 1 + 5 + len(pubkey))
|
||||
append_signature_and_pubkey(w, pubkey, signature, sighash)
|
||||
append_signature(w, signature, sighash)
|
||||
append_pubkey(w, pubkey)
|
||||
return w
|
||||
|
||||
|
||||
@ -29,13 +30,9 @@ def output_script_p2pkh(pubkeyhash: bytes) -> bytearray:
|
||||
return s
|
||||
|
||||
|
||||
# =============== P2SH ===============
|
||||
# see https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki
|
||||
|
||||
# input script (scriptSig) is the same as input_script_p2pkh_or_p2sh
|
||||
|
||||
# output script (scriptPubKey) is A9 14 <scripthash> 87
|
||||
def output_script_p2sh(scripthash: bytes) -> bytearray:
|
||||
# A9 14 <scripthash> 87
|
||||
|
||||
s = bytearray(23)
|
||||
s[0] = 0xA9 # OP_HASH_160
|
||||
s[1] = 0x14 # pushing 20 bytes
|
||||
@ -44,22 +41,28 @@ def output_script_p2sh(scripthash: bytes) -> bytearray:
|
||||
return s
|
||||
|
||||
|
||||
# -------------------------- SegWit --------------------------
|
||||
# SegWit: Native P2WPKH or P2WSH
|
||||
# ===
|
||||
# https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wpkh
|
||||
# https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wsh
|
||||
#
|
||||
# P2WPKH (Pay-to-Witness-Public-Key-Hash) is the segwit native P2PKH.
|
||||
# Not backwards compatible.
|
||||
#
|
||||
# P2WSH (Pay-to-Witness-Script-Hash) is segwit native P2SH.
|
||||
# Not backwards compatible.
|
||||
|
||||
# =============== Native P2WPKH ===============
|
||||
# see https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wpkh
|
||||
# P2WPKH (Pay-to-Witness-Public-Key-Hash) is the segwit native P2PKH
|
||||
# not backwards compatible
|
||||
|
||||
# input script is completely replaced by the witness and therefore empty
|
||||
def input_script_native_p2wpkh_or_p2wsh() -> bytearray:
|
||||
# Completely replaced by the witness and therefore empty.
|
||||
return bytearray(0)
|
||||
|
||||
|
||||
# output script is either:
|
||||
# 00 14 <20-byte-key-hash>
|
||||
# 00 20 <32-byte-script-hash>
|
||||
def output_script_native_p2wpkh_or_p2wsh(witprog: bytes) -> bytearray:
|
||||
# Either:
|
||||
# 00 14 <20-byte-key-hash>
|
||||
# 00 20 <32-byte-script-hash>
|
||||
|
||||
w = bytearray_with_cap(3 + len(witprog))
|
||||
w.append(0x00) # witness version byte
|
||||
w.append(len(witprog)) # pub key hash length is 20 (P2WPKH) or 32 (P2WSH) bytes
|
||||
@ -67,39 +70,139 @@ def output_script_native_p2wpkh_or_p2wsh(witprog: bytes) -> bytearray:
|
||||
return w
|
||||
|
||||
|
||||
# =============== Native P2WPKH nested in P2SH ===============
|
||||
# P2WPKH is nested in P2SH to be backwards compatible
|
||||
# see https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program
|
||||
# SegWit: P2WPKH nested in P2SH
|
||||
# ===
|
||||
# https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#witness-program
|
||||
#
|
||||
# P2WPKH is nested in P2SH to be backwards compatible.
|
||||
# Uses normal P2SH output scripts.
|
||||
|
||||
|
||||
# input script (scriptSig) is 16 00 14 <pubkeyhash>
|
||||
# signature is moved to the witness
|
||||
def input_script_p2wpkh_in_p2sh(pubkeyhash: bytes) -> bytearray:
|
||||
# 16 00 14 <pubkeyhash>
|
||||
# Signature is moved to the witness.
|
||||
|
||||
w = bytearray_with_cap(3 + len(pubkeyhash))
|
||||
w.append(0x16) # 0x16 - length of the redeemScript
|
||||
w.append(0x16) # length of the data
|
||||
w.append(0x00) # witness version byte
|
||||
w.append(0x14) # P2WPKH witness program (pub key hash length)
|
||||
write_bytes(w, pubkeyhash) # pub key hash
|
||||
return w
|
||||
|
||||
# output script (scriptPubKey) is A9 14 <scripthash> 87
|
||||
# which is same as the output_script_p2sh
|
||||
|
||||
# SegWit: P2WSH nested in P2SH
|
||||
# ===
|
||||
# https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wsh-nested-in-bip16-p2sh
|
||||
#
|
||||
# P2WSH is nested in P2SH to be backwards compatible.
|
||||
# Uses normal P2SH output scripts.
|
||||
|
||||
|
||||
# =============== Native P2WSH ===============
|
||||
# see https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#p2wsh
|
||||
# P2WSH (Pay-to-Witness-Script-Hash) is segwit native P2SH
|
||||
# not backwards compatible
|
||||
def input_script_p2wsh_in_p2sh(script_hash: bytes) -> bytearray:
|
||||
# 22 00 20 <redeem script hash>
|
||||
# Signature is moved to the witness.
|
||||
|
||||
# input script is completely replaced by the witness and therefore empty
|
||||
# same as input_script_native_p2wpkh_or_p2wsh
|
||||
if len(script_hash) != 32:
|
||||
raise ScriptsError('Redeem script hash should be 32 bytes long')
|
||||
|
||||
# output script consists of 00 20 <32-byte-key-hash>
|
||||
# same as output_script_native_p2wpkh_or_p2wsh (only different length)
|
||||
w = bytearray_with_cap(3 + len(script_hash))
|
||||
w.append(0x22) # length of the data
|
||||
w.append(0x00) # witness version byte
|
||||
w.append(0x20) # P2WSH witness program (redeem script hash length)
|
||||
write_bytes(w, script_hash)
|
||||
return w
|
||||
|
||||
|
||||
# -------------------------- Others --------------------------
|
||||
# SegWit: Witness getters
|
||||
# ===
|
||||
|
||||
|
||||
def witness_p2wpkh(signature: bytes, pubkey: bytes, sighash: int):
|
||||
w = bytearray_with_cap(1 + 5 + len(signature) + 1 + 5 + len(pubkey))
|
||||
write_varint(w, 0x02) # num of segwit items, in P2WPKH it's always 2
|
||||
append_signature(w, signature, sighash)
|
||||
append_pubkey(w, pubkey)
|
||||
return w
|
||||
|
||||
|
||||
def witness_p2wsh(multisig: MultisigRedeemScriptType, signature: bytes, signature_index: int, sighash: int):
|
||||
signatures = multisig.signatures # other signatures
|
||||
if len(signatures[signature_index]) > 0:
|
||||
raise ScriptsError('Invalid multisig parameters')
|
||||
signatures[signature_index] = signature # our signature
|
||||
|
||||
# filter empty
|
||||
signatures = [s for s in multisig.signatures if len(s) > 0]
|
||||
|
||||
# witness program + signatures + redeem script
|
||||
num_of_witness_items = 1 + len(signatures) + 1
|
||||
|
||||
w = bytearray()
|
||||
write_varint(w, num_of_witness_items)
|
||||
write_varint(w, 0) # version 0 witness program
|
||||
|
||||
for s in signatures:
|
||||
append_signature(w, s, sighash) # size of the witness included
|
||||
|
||||
# redeem script
|
||||
pubkeys = multisig_get_pubkeys(multisig)
|
||||
redeem_script = output_script_multisig(pubkeys, multisig.m)
|
||||
write_varint(w, len(redeem_script))
|
||||
write_bytes(w, redeem_script)
|
||||
return w
|
||||
|
||||
|
||||
# Multisig
|
||||
# ===
|
||||
#
|
||||
# Used either as P2SH, P2WSH, or P2WSH nested in P2SH.
|
||||
|
||||
|
||||
def input_script_multisig(multisig: MultisigRedeemScriptType, signature: bytes, signature_index: int, sighash: int):
|
||||
signatures = multisig.signatures # other signatures
|
||||
if len(signatures[signature_index]) > 0:
|
||||
raise ScriptsError('Invalid multisig parameters')
|
||||
signatures[signature_index] = signature # our signature
|
||||
|
||||
w = bytearray()
|
||||
# Starts with OP_FALSE because of an old OP_CHECKMULTISIG bug, which
|
||||
# consumes one additional item on the stack:
|
||||
# https://bitcoin.org/en/developer-guide#standard-transactions
|
||||
w.append(0x00)
|
||||
|
||||
for s in signatures:
|
||||
if len(s):
|
||||
append_signature(w, s, sighash)
|
||||
|
||||
# redeem script
|
||||
pubkeys = multisig_get_pubkeys(multisig)
|
||||
redeem_script = output_script_multisig(pubkeys, multisig.m)
|
||||
write_op_push(w, len(redeem_script))
|
||||
write_bytes(w, redeem_script)
|
||||
|
||||
return w
|
||||
|
||||
|
||||
def output_script_multisig(pubkeys, m: int) -> bytearray:
|
||||
n = len(pubkeys)
|
||||
if n < 1 or n > 15 or m < 1 or m > 15:
|
||||
raise ScriptsError('Invalid multisig parameters')
|
||||
for pubkey in pubkeys:
|
||||
if len(pubkey) != 33:
|
||||
raise ScriptsError('Invalid multisig parameters')
|
||||
|
||||
w = bytearray()
|
||||
w.append(0x50 + m) # numbers 1 to 16 are pushed as 0x50 + value
|
||||
for p in pubkeys:
|
||||
append_pubkey(w, p)
|
||||
w.append(0x50 + n)
|
||||
w.append(0xAE) # OP_CHECKMULTISIG
|
||||
return w
|
||||
|
||||
|
||||
# OP_RETURN
|
||||
# ===
|
||||
|
||||
# === OP_RETURN script
|
||||
|
||||
def output_script_paytoopreturn(data: bytes) -> bytearray:
|
||||
w = bytearray_with_cap(1 + 5 + len(data))
|
||||
@ -109,12 +212,24 @@ def output_script_paytoopreturn(data: bytes) -> bytearray:
|
||||
return w
|
||||
|
||||
|
||||
# === helpers
|
||||
# Helpers
|
||||
# ===
|
||||
|
||||
def append_signature_and_pubkey(w: bytearray, pubkey: bytes, signature: bytes, sighash: int) -> bytearray:
|
||||
|
||||
def append_signature(w: bytearray, signature: bytes, sighash: int) -> bytearray:
|
||||
write_op_push(w, len(signature) + 1)
|
||||
write_bytes(w, signature)
|
||||
w.append(sighash)
|
||||
return w
|
||||
|
||||
|
||||
def append_pubkey(w: bytearray, pubkey: bytes) -> bytearray:
|
||||
write_op_push(w, len(pubkey))
|
||||
write_bytes(w, pubkey)
|
||||
return w
|
||||
|
||||
|
||||
def sha256_ripemd160_digest(b: bytes) -> bytes:
|
||||
h = sha256(b).digest()
|
||||
h = ripemd160(h).digest()
|
||||
return h
|
||||
|
@ -3,6 +3,8 @@ from trezor.messages.SignTx import SignTx
|
||||
from trezor.messages import InputScriptType, FailureType
|
||||
|
||||
from apps.wallet.sign_tx.writers import *
|
||||
from apps.wallet.sign_tx.scripts import output_script_p2pkh, output_script_multisig
|
||||
from apps.wallet.sign_tx.multisig import multisig_get_pubkeys
|
||||
from apps.common.hash_writer import HashWriter
|
||||
|
||||
|
||||
@ -58,22 +60,21 @@ class Bip143:
|
||||
|
||||
return get_tx_hash(h_preimage, True)
|
||||
|
||||
# this not redeemScript nor scriptPubKey
|
||||
# for P2WPKH this is always 0x1976a914{20-byte-pubkey-hash}88ac
|
||||
# see https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification
|
||||
# item 5 for details
|
||||
def derive_script_code(self, txi: TxInputType, pubkeyhash: bytes) -> bytearray:
|
||||
# p2wpkh in p2sh or native p2wpkh
|
||||
|
||||
if txi.multisig:
|
||||
return output_script_multisig(multisig_get_pubkeys(txi.multisig), txi.multisig.m)
|
||||
|
||||
p2pkh = (txi.script_type == InputScriptType.SPENDWITNESS or
|
||||
txi.script_type == InputScriptType.SPENDP2SHWITNESS or
|
||||
txi.script_type == InputScriptType.SPENDADDRESS)
|
||||
if p2pkh:
|
||||
s = bytearray(25)
|
||||
s[0] = 0x76 # OP_DUP
|
||||
s[1] = 0xA9 # OP_HASH_160
|
||||
s[2] = 0x14 # pushing 20 bytes
|
||||
s[3:23] = pubkeyhash
|
||||
s[23] = 0x88 # OP_EQUALVERIFY
|
||||
s[24] = 0xAC # OP_CHECKSIG
|
||||
return s
|
||||
# for p2wpkh in p2sh or native p2wpkh
|
||||
# the scriptCode is a classic p2pkh
|
||||
return output_script_p2pkh(pubkeyhash)
|
||||
|
||||
else:
|
||||
raise Bip143Error(FailureType.DataError,
|
||||
'Unknown input script type for bip143 script code')
|
||||
|
@ -1,22 +1,21 @@
|
||||
from micropython import const
|
||||
|
||||
from trezor.crypto.hashlib import sha256
|
||||
from trezor.crypto import base58, bip32, der
|
||||
from trezor.crypto.curve import secp256k1
|
||||
from trezor.crypto import base58, der
|
||||
from trezor.crypto.hashlib import sha256
|
||||
|
||||
from trezor.messages.TxRequestSerializedType import TxRequestSerializedType
|
||||
from trezor.messages.TxRequestDetailsType import TxRequestDetailsType
|
||||
from trezor.messages import OutputScriptType
|
||||
from trezor.messages.TxRequestDetailsType import TxRequestDetailsType
|
||||
from trezor.messages.TxRequestSerializedType import TxRequestSerializedType
|
||||
|
||||
from apps.common import address_type
|
||||
from apps.common import coins
|
||||
from apps.common import address_type, coins
|
||||
from apps.common.hash_writer import HashWriter
|
||||
from apps.wallet.sign_tx.addresses import *
|
||||
from apps.wallet.sign_tx.helpers import *
|
||||
from apps.wallet.sign_tx.segwit_bip143 import *
|
||||
from apps.wallet.sign_tx.scripts import *
|
||||
from apps.wallet.sign_tx.writers import *
|
||||
from apps.wallet.sign_tx.segwit_bip143 import *
|
||||
from apps.wallet.sign_tx.tx_weight_calculator import *
|
||||
from apps.common.hash_writer import HashWriter
|
||||
from apps.wallet.sign_tx.writers import *
|
||||
|
||||
# the number of bip32 levels used in a wallet (chain and address)
|
||||
_BIP32_WALLET_DEPTH = const(2)
|
||||
@ -44,20 +43,17 @@ class SigningError(ValueError):
|
||||
# - check inputs, previous transactions, and outputs
|
||||
# - ask for confirmations
|
||||
# - check fee
|
||||
async def check_tx_fee(tx: SignTx, root):
|
||||
|
||||
async def check_tx_fee(tx: SignTx, root: bip32.HDNode):
|
||||
coin = coins.by_name(tx.coin_name)
|
||||
|
||||
# h_first is used to make sure the inputs and outputs streamed in Phase 1
|
||||
# are the same as in Phase 2. it is thus not required to fully hash the
|
||||
# tx, as the SignTx info is streamed only once
|
||||
h_first = HashWriter(sha256) # not a real tx hash
|
||||
bip143 = Bip143()
|
||||
weight = TxWeightCalculator(tx.inputs_count, tx.outputs_count)
|
||||
|
||||
txo_bin = TxOutputBinType()
|
||||
tx_req = TxRequest()
|
||||
tx_req.details = TxRequestDetailsType()
|
||||
bip143 = Bip143() # bip143 transaction hashing
|
||||
multifp = MultisigFingerprint() # control checksum of multisig inputs
|
||||
weight = TxWeightCalculator(tx.inputs_count, tx.outputs_count)
|
||||
|
||||
total_in = 0 # sum of input amounts
|
||||
segwit_in = 0 # sum of segwit input amounts
|
||||
@ -66,28 +62,25 @@ async def check_tx_fee(tx: SignTx, root):
|
||||
wallet_path = [] # common prefix of input paths
|
||||
segwit = {} # dict of booleans stating if input is segwit
|
||||
|
||||
# output structures
|
||||
txo_bin = TxOutputBinType()
|
||||
tx_req = TxRequest()
|
||||
tx_req.details = TxRequestDetailsType()
|
||||
|
||||
for i in range(tx.inputs_count):
|
||||
# STAGE_REQUEST_1_INPUT
|
||||
txi = await request_tx_input(tx_req, i)
|
||||
wallet_path = input_extract_wallet_path(txi, wallet_path)
|
||||
write_tx_input_check(h_first, txi)
|
||||
weight.add_input(txi)
|
||||
bip143.add_prevouts(txi)
|
||||
bip143.add_prevouts(txi) # all inputs are included (non-segwit as well)
|
||||
bip143.add_sequence(txi)
|
||||
is_segwit = (txi.script_type == InputScriptType.SPENDWITNESS or
|
||||
txi.script_type == InputScriptType.SPENDP2SHWITNESS)
|
||||
if coin.force_bip143:
|
||||
is_bip143 = (txi.script_type == InputScriptType.SPENDADDRESS)
|
||||
if not is_bip143:
|
||||
raise SigningError(FailureType.DataError,
|
||||
'Wrong input script type')
|
||||
if not txi.amount:
|
||||
raise SigningError(FailureType.DataError,
|
||||
'BIP 143 input without amount')
|
||||
segwit[i] = False
|
||||
segwit_in += txi.amount
|
||||
total_in += txi.amount
|
||||
elif is_segwit:
|
||||
|
||||
if txi.multisig:
|
||||
multifp.add(txi.multisig)
|
||||
|
||||
if txi.script_type in (InputScriptType.SPENDWITNESS,
|
||||
InputScriptType.SPENDP2SHWITNESS):
|
||||
if not coin.segwit:
|
||||
raise SigningError(FailureType.DataError,
|
||||
'Segwit not enabled on this coin')
|
||||
@ -97,10 +90,21 @@ async def check_tx_fee(tx: SignTx, root):
|
||||
segwit[i] = True
|
||||
segwit_in += txi.amount
|
||||
total_in += txi.amount
|
||||
elif txi.script_type == InputScriptType.SPENDADDRESS:
|
||||
|
||||
elif txi.script_type in (InputScriptType.SPENDADDRESS,
|
||||
InputScriptType.SPENDMULTISIG):
|
||||
if coin.force_bip143:
|
||||
if not txi.amount:
|
||||
raise SigningError(FailureType.DataError,
|
||||
'BIP 143 input without amount')
|
||||
segwit[i] = False
|
||||
segwit_in += txi.amount
|
||||
total_in += txi.amount
|
||||
else:
|
||||
segwit[i] = False
|
||||
total_in += await get_prevtx_output_value(
|
||||
tx_req, txi.prev_hash, txi.prev_index)
|
||||
|
||||
else:
|
||||
raise SigningError(FailureType.DataError,
|
||||
'Wrong input script type')
|
||||
@ -111,14 +115,14 @@ async def check_tx_fee(tx: SignTx, root):
|
||||
txo_bin.amount = txo.amount
|
||||
txo_bin.script_pubkey = output_derive_script(txo, coin, root)
|
||||
weight.add_output(txo_bin.script_pubkey)
|
||||
if output_is_change(txo, wallet_path, segwit_in):
|
||||
if change_out != 0:
|
||||
raise SigningError(FailureType.ProcessError,
|
||||
'Only one change output is valid')
|
||||
|
||||
if change_out == 0 and is_change(txo, wallet_path, segwit_in, multifp):
|
||||
# output is change and does not need confirmation
|
||||
change_out = txo.amount
|
||||
elif not await confirm_output(txo, coin):
|
||||
raise SigningError(FailureType.ActionCancelled,
|
||||
'Output cancelled')
|
||||
|
||||
write_tx_output(h_first, txo_bin)
|
||||
bip143.add_output(txo_bin)
|
||||
total_out += txo_bin.amount
|
||||
@ -141,8 +145,7 @@ async def check_tx_fee(tx: SignTx, root):
|
||||
return h_first, bip143, segwit, total_in, wallet_path
|
||||
|
||||
|
||||
async def sign_tx(tx: SignTx, root):
|
||||
|
||||
async def sign_tx(tx: SignTx, root: bip32.HDNode):
|
||||
tx = sanitize_sign_tx(tx)
|
||||
|
||||
# Phase 1
|
||||
@ -171,7 +174,8 @@ async def sign_tx(tx: SignTx, root):
|
||||
txi_sign = await request_tx_input(tx_req, i_sign)
|
||||
input_check_wallet_path(txi_sign, wallet_path)
|
||||
|
||||
is_bip143 = (txi_sign.script_type == InputScriptType.SPENDADDRESS)
|
||||
is_bip143 = (txi_sign.script_type == InputScriptType.SPENDADDRESS or
|
||||
txi_sign.script_type == InputScriptType.SPENDMULTISIG)
|
||||
if not is_bip143 or txi_sign.amount > authorized_in:
|
||||
raise SigningError(FailureType.ProcessError,
|
||||
'Transaction has changed during signing')
|
||||
@ -182,6 +186,10 @@ async def sign_tx(tx: SignTx, root):
|
||||
bip143_hash = bip143.preimage_hash(
|
||||
tx, txi_sign, ecdsa_hash_pubkey(key_sign_pub), get_hash_type(coin))
|
||||
|
||||
# if multisig, check if singing with a key that is included in multisig
|
||||
if txi_sign.multisig:
|
||||
multisig_pubkey_index(txi_sign.multisig, key_sign_pub)
|
||||
|
||||
signature = ecdsa_sign(key_sign, bip143_hash)
|
||||
tx_ser.signature_index = i_sign
|
||||
tx_ser.signature = signature
|
||||
@ -239,8 +247,18 @@ async def sign_tx(tx: SignTx, root):
|
||||
txi_sign = txi
|
||||
key_sign = node_derive(root, txi.address_n)
|
||||
key_sign_pub = key_sign.public_key()
|
||||
# for the signing process the script_sig is equal
|
||||
# to the previous tx's scriptPubKey (P2PKH) or a redeem script (P2SH)
|
||||
if txi_sign.script_type == InputScriptType.SPENDMULTISIG:
|
||||
txi_sign.script_sig = output_script_multisig(
|
||||
multisig_get_pubkeys(txi_sign.multisig),
|
||||
txi_sign.multisig.m)
|
||||
elif txi_sign.script_type == InputScriptType.SPENDADDRESS:
|
||||
txi_sign.script_sig = output_script_p2pkh(
|
||||
ecdsa_hash_pubkey(key_sign_pub))
|
||||
else:
|
||||
raise SigningError(FailureType.ProcessError,
|
||||
'Unknown transaction type')
|
||||
else:
|
||||
txi.script_sig = bytes()
|
||||
write_tx_input(h_sign, txi)
|
||||
@ -264,6 +282,10 @@ async def sign_tx(tx: SignTx, root):
|
||||
raise SigningError(FailureType.ProcessError,
|
||||
'Transaction has changed during signing')
|
||||
|
||||
# if multisig, check if singing with a key that is included in multisig
|
||||
if txi_sign.multisig:
|
||||
multisig_pubkey_index(txi_sign.multisig, key_sign_pub)
|
||||
|
||||
# compute the signature from the tx digest
|
||||
signature = ecdsa_sign(key_sign, get_tx_hash(h_sign, True))
|
||||
tx_ser.signature_index = i_sign
|
||||
@ -321,7 +343,12 @@ async def sign_tx(tx: SignTx, root):
|
||||
tx, txi, ecdsa_hash_pubkey(key_sign_pub), get_hash_type(coin))
|
||||
|
||||
signature = ecdsa_sign(key_sign, bip143_hash)
|
||||
witness = get_p2wpkh_witness(coin, signature, key_sign_pub)
|
||||
if txi.multisig:
|
||||
# find out place of our signature based on the pubkey
|
||||
signature_index = multisig_pubkey_index(txi.multisig, key_sign_pub)
|
||||
witness = witness_p2wsh(txi.multisig, signature, signature_index, get_hash_type(coin))
|
||||
else:
|
||||
witness = witness_p2wpkh(signature, key_sign_pub, get_hash_type(coin))
|
||||
|
||||
tx_ser.serialized_tx = witness
|
||||
tx_ser.signature_index = i
|
||||
@ -392,7 +419,7 @@ def get_hash_type(coin: CoinType) -> int:
|
||||
return hashtype
|
||||
|
||||
|
||||
def get_tx_header(tx: SignTx, segwit=False):
|
||||
def get_tx_header(tx: SignTx, segwit: bool = False):
|
||||
w_txi = bytearray()
|
||||
write_uint32(w_txi, tx.version)
|
||||
if segwit:
|
||||
@ -402,26 +429,21 @@ def get_tx_header(tx: SignTx, segwit=False):
|
||||
return w_txi
|
||||
|
||||
|
||||
def get_p2wpkh_witness(coin: CoinType, signature: bytes, pubkey: bytes):
|
||||
w = bytearray_with_cap(1 + 5 + len(signature) + 1 + 5 + len(pubkey))
|
||||
write_varint(w, 0x02) # num of segwit items, in P2WPKH it's always 2
|
||||
append_signature_and_pubkey(w, pubkey, signature, get_hash_type(coin))
|
||||
return w
|
||||
|
||||
|
||||
# TX Outputs
|
||||
# ===
|
||||
|
||||
|
||||
def output_derive_script(o: TxOutputType, coin: CoinType, root) -> bytes:
|
||||
def output_derive_script(o: TxOutputType, coin: CoinType, root: bip32.HDNode) -> bytes:
|
||||
|
||||
if o.script_type == OutputScriptType.PAYTOOPRETURN:
|
||||
# op_return output
|
||||
if o.amount != 0:
|
||||
raise SigningError(FailureType.DataError,
|
||||
'OP_RETURN output with non-zero amount')
|
||||
return output_script_paytoopreturn(o.op_return_data)
|
||||
|
||||
if o.address_n: # change output
|
||||
if o.address_n:
|
||||
# change output
|
||||
if o.address:
|
||||
raise SigningError(FailureType.DataError, 'Address in change output')
|
||||
o.address = get_address_for_change(o, coin, root)
|
||||
@ -429,24 +451,27 @@ def output_derive_script(o: TxOutputType, coin: CoinType, root) -> bytes:
|
||||
if not o.address:
|
||||
raise SigningError(FailureType.DataError, 'Missing address')
|
||||
|
||||
if coin.bech32_prefix and o.address.startswith(coin.bech32_prefix): # p2wpkh or p2wsh
|
||||
if coin.bech32_prefix and o.address.startswith(coin.bech32_prefix):
|
||||
# p2wpkh or p2wsh
|
||||
witprog = decode_bech32_address(coin.bech32_prefix, o.address)
|
||||
return output_script_native_p2wpkh_or_p2wsh(witprog)
|
||||
|
||||
raw_address = base58.decode_check(o.address)
|
||||
|
||||
if address_type.check(coin.address_type, raw_address): # p2pkh
|
||||
if address_type.check(coin.address_type, raw_address):
|
||||
# p2pkh
|
||||
pubkeyhash = address_type.strip(coin.address_type, raw_address)
|
||||
return output_script_p2pkh(pubkeyhash)
|
||||
|
||||
elif address_type.check(coin.address_type_p2sh, raw_address): # p2sh
|
||||
elif address_type.check(coin.address_type_p2sh, raw_address):
|
||||
# p2sh
|
||||
scripthash = address_type.strip(coin.address_type_p2sh, raw_address)
|
||||
return output_script_p2sh(scripthash)
|
||||
|
||||
raise SigningError(FailureType.DataError, 'Invalid address type')
|
||||
|
||||
|
||||
def get_address_for_change(o: TxOutputType, coin: CoinType, root):
|
||||
def get_address_for_change(o: TxOutputType, coin: CoinType, root: bip32.HDNode):
|
||||
if o.script_type == OutputScriptType.PAYTOADDRESS:
|
||||
input_script_type = InputScriptType.SPENDADDRESS
|
||||
elif o.script_type == OutputScriptType.PAYTOMULTISIG:
|
||||
@ -457,11 +482,10 @@ def get_address_for_change(o: TxOutputType, coin: CoinType, root):
|
||||
input_script_type = InputScriptType.SPENDP2SHWITNESS
|
||||
else:
|
||||
raise SigningError(FailureType.DataError, 'Invalid script type')
|
||||
return get_address(input_script_type, coin, node_derive(root, o.address_n))
|
||||
return get_address(input_script_type, coin, node_derive(root, o.address_n), o.multisig)
|
||||
|
||||
|
||||
def output_is_change(o: TxOutputType, wallet_path: list, segwit_in: int) -> bool:
|
||||
address_n = o.address_n
|
||||
is_segwit = (o.script_type == OutputScriptType.PAYTOWITNESS or
|
||||
o.script_type == OutputScriptType.PAYTOP2SHWITNESS)
|
||||
if is_segwit and o.amount > segwit_in:
|
||||
@ -469,10 +493,10 @@ def output_is_change(o: TxOutputType, wallet_path: list, segwit_in: int) -> bool
|
||||
# segwit inputs paid. this is to prevent user being tricked into
|
||||
# creating ANYONECANSPEND outputs before full segwit activation.
|
||||
return False
|
||||
return (address_n is not None and wallet_path is not None and
|
||||
wallet_path == address_n[:-_BIP32_WALLET_DEPTH] and
|
||||
address_n[-2] == _BIP32_CHANGE_CHAIN and
|
||||
address_n[-1] <= _BIP32_MAX_LAST_ELEMENT)
|
||||
return (wallet_path is not None and
|
||||
wallet_path == o.address_n[:-_BIP32_WALLET_DEPTH] and
|
||||
o.address_n[-2] <= _BIP32_CHANGE_CHAIN and
|
||||
o.address_n[-1] <= _BIP32_MAX_LAST_ELEMENT)
|
||||
|
||||
|
||||
# Tx Inputs
|
||||
@ -481,11 +505,33 @@ def output_is_change(o: TxOutputType, wallet_path: list, segwit_in: int) -> bool
|
||||
|
||||
def input_derive_script(coin: CoinType, i: TxInputType, pubkey: bytes, signature: bytes=None) -> bytes:
|
||||
if i.script_type == InputScriptType.SPENDADDRESS:
|
||||
return input_script_p2pkh_or_p2sh(pubkey, signature, get_hash_type(coin)) # p2pkh or p2sh
|
||||
if i.script_type == InputScriptType.SPENDP2SHWITNESS: # p2wpkh using p2sh
|
||||
# p2pkh or p2sh
|
||||
return input_script_p2pkh_or_p2sh(
|
||||
pubkey, signature, get_hash_type(coin))
|
||||
|
||||
if i.script_type == InputScriptType.SPENDP2SHWITNESS:
|
||||
# p2wpkh or p2wsh using p2sh
|
||||
|
||||
if i.multisig:
|
||||
# p2wsh in p2sh
|
||||
pubkeys = multisig_get_pubkeys(i.multisig)
|
||||
witness_script = output_script_multisig(pubkeys, i.multisig.m)
|
||||
witness_script_hash = sha256(witness_script).digest()
|
||||
return input_script_p2wsh_in_p2sh(witness_script_hash)
|
||||
|
||||
# p2wpkh in p2sh
|
||||
return input_script_p2wpkh_in_p2sh(ecdsa_hash_pubkey(pubkey))
|
||||
elif i.script_type == InputScriptType.SPENDWITNESS: # native p2wpkh or p2wsh
|
||||
|
||||
elif i.script_type == InputScriptType.SPENDWITNESS:
|
||||
# native p2wpkh or p2wsh
|
||||
return input_script_native_p2wpkh_or_p2wsh()
|
||||
|
||||
elif i.script_type == InputScriptType.SPENDMULTISIG:
|
||||
# p2sh multisig
|
||||
signature_index = multisig_pubkey_index(i.multisig, pubkey)
|
||||
return input_script_multisig(
|
||||
i.multisig, signature, signature_index, get_hash_type(coin))
|
||||
|
||||
else:
|
||||
raise SigningError(FailureType.ProcessError, 'Invalid script type')
|
||||
|
||||
@ -512,13 +558,24 @@ def input_check_wallet_path(txi: TxInputType, wallet_path: list) -> list:
|
||||
'Transaction has changed during signing')
|
||||
|
||||
|
||||
def node_derive(root, address_n: list):
|
||||
def node_derive(root: bip32.HDNode, address_n: list):
|
||||
node = root.clone()
|
||||
node.derive_path(address_n)
|
||||
return node
|
||||
|
||||
|
||||
def ecdsa_sign(node, digest: bytes) -> bytes:
|
||||
def ecdsa_sign(node: bip32.HDNode, digest: bytes) -> bytes:
|
||||
sig = secp256k1.sign(node.private_key(), digest)
|
||||
sigder = der.encode_seq((sig[1:33], sig[33:65]))
|
||||
return sigder
|
||||
|
||||
|
||||
def is_change(
|
||||
txo: TxOutputType,
|
||||
wallet_path: list,
|
||||
segwit_in: int,
|
||||
multifp: MultisigFingerprint) -> bool:
|
||||
if txo.multisig:
|
||||
if not multifp.matches(txo.multisig):
|
||||
return False
|
||||
return output_is_change(txo, wallet_path, segwit_in)
|
||||
|
@ -55,7 +55,7 @@ class TxWeightCalculator:
|
||||
if i.multisig:
|
||||
multisig_script_size = (
|
||||
_TXSIZE_MULTISIGSCRIPT +
|
||||
i.multisig.pubkeys_count * (1 + _TXSIZE_PUBKEY))
|
||||
len(i.multisig.pubkeys) * (1 + _TXSIZE_PUBKEY))
|
||||
input_script_size = (
|
||||
1 + # the OP_FALSE bug in multisig
|
||||
i.multisig.m * (1 + _TXSIZE_SIGNATURE) +
|
||||
|
@ -1,8 +1,8 @@
|
||||
|
||||
from trezor.crypto.hashlib import sha256
|
||||
|
||||
from apps.wallet.sign_tx.writers import *
|
||||
|
||||
|
||||
# TX Serialization
|
||||
# ===
|
||||
|
||||
|
@ -7,3 +7,11 @@ class Address(p.MessageType):
|
||||
1: ('address', p.UnicodeType, 0), # required
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 30
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address: str = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address = address
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class ApplyFlags(p.MessageType):
|
||||
1: ('flags', p.UVarintType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 28
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
flags: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.flags = flags
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -10,3 +10,17 @@ class ApplySettings(p.MessageType):
|
||||
4: ('homescreen', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 25
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
language: str = None,
|
||||
label: str = None,
|
||||
use_passphrase: bool = None,
|
||||
homescreen: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.language = language
|
||||
self.label = label
|
||||
self.use_passphrase = use_passphrase
|
||||
self.homescreen = homescreen
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -4,3 +4,9 @@ import protobuf as p
|
||||
|
||||
class BackupDevice(p.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 34
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
**kwargs,
|
||||
):
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -4,3 +4,9 @@ import protobuf as p
|
||||
|
||||
class ButtonAck(p.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 27
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
**kwargs,
|
||||
):
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,13 @@ class ButtonRequest(p.MessageType):
|
||||
2: ('data', p.UnicodeType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 26
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
code: int = None,
|
||||
data: str = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.code = code
|
||||
self.data = data
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -4,3 +4,9 @@ import protobuf as p
|
||||
|
||||
class Cancel(p.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 20
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
**kwargs,
|
||||
):
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class ChangePin(p.MessageType):
|
||||
1: ('remove', p.BoolType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 4
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
remove: bool = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.remove = remove
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -13,3 +13,23 @@ class CipherKeyValue(p.MessageType):
|
||||
7: ('iv', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 23
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address_n: list = [],
|
||||
key: str = None,
|
||||
value: bytes = None,
|
||||
encrypt: bool = None,
|
||||
ask_on_encrypt: bool = None,
|
||||
ask_on_decrypt: bool = None,
|
||||
iv: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address_n = address_n
|
||||
self.key = key
|
||||
self.value = value
|
||||
self.encrypt = encrypt
|
||||
self.ask_on_encrypt = ask_on_encrypt
|
||||
self.ask_on_decrypt = ask_on_decrypt
|
||||
self.iv = iv
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class CipheredKeyValue(p.MessageType):
|
||||
1: ('value', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 48
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
value: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.value = value
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -4,3 +4,9 @@ import protobuf as p
|
||||
|
||||
class ClearSession(p.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 24
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
**kwargs,
|
||||
):
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -14,5 +14,30 @@ class CoinType(p.MessageType):
|
||||
10: ('xprv_magic', p.UVarintType, 0), # default=76066276
|
||||
11: ('segwit', p.BoolType, 0),
|
||||
12: ('forkid', p.UVarintType, 0),
|
||||
13: ('force_bip143', p.BoolType, 0),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coin_name: str = None,
|
||||
coin_shortcut: str = None,
|
||||
address_type: int = None,
|
||||
maxfee_kb: int = None,
|
||||
address_type_p2sh: int = None,
|
||||
signed_message_header: str = None,
|
||||
xpub_magic: int = None,
|
||||
xprv_magic: int = None,
|
||||
segwit: bool = None,
|
||||
forkid: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.coin_name = coin_name
|
||||
self.coin_shortcut = coin_shortcut
|
||||
self.address_type = address_type
|
||||
self.maxfee_kb = maxfee_kb
|
||||
self.address_type_p2sh = address_type_p2sh
|
||||
self.signed_message_header = signed_message_header
|
||||
self.xpub_magic = xpub_magic
|
||||
self.xprv_magic = xprv_magic
|
||||
self.segwit = segwit
|
||||
self.forkid = forkid
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,13 @@ class CosiCommit(p.MessageType):
|
||||
2: ('data', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 71
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address_n: list = [],
|
||||
data: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address_n = address_n
|
||||
self.data = data
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,13 @@ class CosiCommitment(p.MessageType):
|
||||
2: ('pubkey', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 72
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
commitment: bytes = None,
|
||||
pubkey: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.commitment = commitment
|
||||
self.pubkey = pubkey
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -10,3 +10,17 @@ class CosiSign(p.MessageType):
|
||||
4: ('global_pubkey', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 73
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address_n: list = [],
|
||||
data: bytes = None,
|
||||
global_commitment: bytes = None,
|
||||
global_pubkey: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address_n = address_n
|
||||
self.data = data
|
||||
self.global_commitment = global_commitment
|
||||
self.global_pubkey = global_pubkey
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class CosiSignature(p.MessageType):
|
||||
1: ('signature', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 74
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
signature: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.signature = signature
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class DebugLinkDecision(p.MessageType):
|
||||
1: ('yes_no', p.BoolType, 0), # required
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 100
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
yes_no: bool = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.yes_no = yes_no
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class DebugLinkFlashErase(p.MessageType):
|
||||
1: ('sector', p.UVarintType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 113
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
sector: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.sector = sector
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -4,3 +4,9 @@ import protobuf as p
|
||||
|
||||
class DebugLinkGetState(p.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 101
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
**kwargs,
|
||||
):
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -9,3 +9,15 @@ class DebugLinkLog(p.MessageType):
|
||||
3: ('text', p.UnicodeType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 104
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
level: int = None,
|
||||
bucket: str = None,
|
||||
text: str = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.level = level
|
||||
self.bucket = bucket
|
||||
self.text = text
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class DebugLinkMemory(p.MessageType):
|
||||
1: ('memory', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 111
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
memory: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.memory = memory
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,13 @@ class DebugLinkMemoryRead(p.MessageType):
|
||||
2: ('length', p.UVarintType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 110
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address: int = None,
|
||||
length: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address = address
|
||||
self.length = length
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -9,3 +9,15 @@ class DebugLinkMemoryWrite(p.MessageType):
|
||||
3: ('flash', p.BoolType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 112
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address: int = None,
|
||||
memory: bytes = None,
|
||||
flash: bool = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address = address
|
||||
self.memory = memory
|
||||
self.flash = flash
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -17,3 +17,29 @@ class DebugLinkState(p.MessageType):
|
||||
10: ('recovery_word_pos', p.UVarintType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 102
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
layout: bytes = None,
|
||||
pin: str = None,
|
||||
matrix: str = None,
|
||||
mnemonic: str = None,
|
||||
node: HDNodeType = None,
|
||||
passphrase_protection: bool = None,
|
||||
reset_word: str = None,
|
||||
reset_entropy: bytes = None,
|
||||
recovery_fake_word: str = None,
|
||||
recovery_word_pos: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.layout = layout
|
||||
self.pin = pin
|
||||
self.matrix = matrix
|
||||
self.mnemonic = mnemonic
|
||||
self.node = node
|
||||
self.passphrase_protection = passphrase_protection
|
||||
self.reset_word = reset_word
|
||||
self.reset_entropy = reset_entropy
|
||||
self.recovery_fake_word = recovery_fake_word
|
||||
self.recovery_word_pos = recovery_word_pos
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -4,3 +4,9 @@ import protobuf as p
|
||||
|
||||
class DebugLinkStop(p.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 103
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
**kwargs,
|
||||
):
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -10,3 +10,17 @@ class DecryptMessage(p.MessageType):
|
||||
4: ('hmac', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 51
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address_n: list = [],
|
||||
nonce: bytes = None,
|
||||
message: bytes = None,
|
||||
hmac: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address_n = address_n
|
||||
self.nonce = nonce
|
||||
self.message = message
|
||||
self.hmac = hmac
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,13 @@ class DecryptedMessage(p.MessageType):
|
||||
2: ('address', p.UnicodeType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 52
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: bytes = None,
|
||||
address: str = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.message = message
|
||||
self.address = address
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class ECDHSessionKey(p.MessageType):
|
||||
1: ('session_key', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 62
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
session_key: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.session_key = session_key
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -11,3 +11,19 @@ class EncryptMessage(p.MessageType):
|
||||
5: ('coin_name', p.UnicodeType, 0), # default='Bitcoin'
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 49
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
pubkey: bytes = None,
|
||||
message: bytes = None,
|
||||
display_only: bool = None,
|
||||
address_n: list = [],
|
||||
coin_name: str = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.pubkey = pubkey
|
||||
self.message = message
|
||||
self.display_only = display_only
|
||||
self.address_n = address_n
|
||||
self.coin_name = coin_name
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -9,3 +9,15 @@ class EncryptedMessage(p.MessageType):
|
||||
3: ('hmac', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 50
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
nonce: bytes = None,
|
||||
message: bytes = None,
|
||||
hmac: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.nonce = nonce
|
||||
self.message = message
|
||||
self.hmac = hmac
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class Entropy(p.MessageType):
|
||||
1: ('entropy', p.BytesType, 0), # required
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 10
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
entropy: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.entropy = entropy
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class EntropyAck(p.MessageType):
|
||||
1: ('entropy', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 36
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
entropy: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.entropy = entropy
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -4,3 +4,9 @@ import protobuf as p
|
||||
|
||||
class EntropyRequest(p.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 35
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
**kwargs,
|
||||
):
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -9,3 +9,15 @@ class EstimateTxSize(p.MessageType):
|
||||
3: ('coin_name', p.UnicodeType, 0), # default='Bitcoin'
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 43
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
outputs_count: int = None,
|
||||
inputs_count: int = None,
|
||||
coin_name: str = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.outputs_count = outputs_count
|
||||
self.inputs_count = inputs_count
|
||||
self.coin_name = coin_name
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class EthereumAddress(p.MessageType):
|
||||
1: ('address', p.BytesType, 0), # required
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 57
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address = address
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,13 @@ class EthereumGetAddress(p.MessageType):
|
||||
2: ('show_display', p.BoolType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 56
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address_n: list = [],
|
||||
show_display: bool = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address_n = address_n
|
||||
self.show_display = show_display
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,13 @@ class EthereumMessageSignature(p.MessageType):
|
||||
2: ('signature', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 66
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address: bytes = None,
|
||||
signature: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address = address
|
||||
self.signature = signature
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,13 @@ class EthereumSignMessage(p.MessageType):
|
||||
2: ('message', p.BytesType, 0), # required
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 64
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address_n: list = [],
|
||||
message: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address_n = address_n
|
||||
self.message = message
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -15,3 +15,27 @@ class EthereumSignTx(p.MessageType):
|
||||
9: ('chain_id', p.UVarintType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 58
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address_n: list = [],
|
||||
nonce: bytes = None,
|
||||
gas_price: bytes = None,
|
||||
gas_limit: bytes = None,
|
||||
to: bytes = None,
|
||||
value: bytes = None,
|
||||
data_initial_chunk: bytes = None,
|
||||
data_length: int = None,
|
||||
chain_id: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address_n = address_n
|
||||
self.nonce = nonce
|
||||
self.gas_price = gas_price
|
||||
self.gas_limit = gas_limit
|
||||
self.to = to
|
||||
self.value = value
|
||||
self.data_initial_chunk = data_initial_chunk
|
||||
self.data_length = data_length
|
||||
self.chain_id = chain_id
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class EthereumTxAck(p.MessageType):
|
||||
1: ('data_chunk', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 60
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data_chunk: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.data_chunk = data_chunk
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -10,3 +10,17 @@ class EthereumTxRequest(p.MessageType):
|
||||
4: ('signature_s', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 59
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data_length: int = None,
|
||||
signature_v: int = None,
|
||||
signature_r: bytes = None,
|
||||
signature_s: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.data_length = data_length
|
||||
self.signature_v = signature_v
|
||||
self.signature_r = signature_r
|
||||
self.signature_s = signature_s
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -9,3 +9,15 @@ class EthereumVerifyMessage(p.MessageType):
|
||||
3: ('message', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 65
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address: bytes = None,
|
||||
signature: bytes = None,
|
||||
message: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address = address
|
||||
self.signature = signature
|
||||
self.message = message
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,13 @@ class Failure(p.MessageType):
|
||||
2: ('message', p.UnicodeType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 3
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
code: int = None,
|
||||
message: str = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.code = code
|
||||
self.message = message
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -25,12 +25,51 @@ class Features(p.MessageType):
|
||||
18: ('firmware_present', p.BoolType, 0),
|
||||
19: ('needs_backup', p.BoolType, 0),
|
||||
20: ('flags', p.UVarintType, 0),
|
||||
21: ('model', p.UnicodeType, 0),
|
||||
22: ('fw_major', p.UVarintType, 0),
|
||||
23: ('fw_minor', p.UVarintType, 0),
|
||||
24: ('fw_patch', p.UVarintType, 0),
|
||||
25: ('fw_vendor', p.UnicodeType, 0),
|
||||
26: ('fw_vendor_keys', p.BytesType, 0),
|
||||
27: ('state', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 17
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vendor: str = None,
|
||||
major_version: int = None,
|
||||
minor_version: int = None,
|
||||
patch_version: int = None,
|
||||
bootloader_mode: bool = None,
|
||||
device_id: str = None,
|
||||
pin_protection: bool = None,
|
||||
passphrase_protection: bool = None,
|
||||
language: str = None,
|
||||
label: str = None,
|
||||
coins: list = [],
|
||||
initialized: bool = None,
|
||||
revision: bytes = None,
|
||||
bootloader_hash: bytes = None,
|
||||
imported: bool = None,
|
||||
pin_cached: bool = None,
|
||||
passphrase_cached: bool = None,
|
||||
firmware_present: bool = None,
|
||||
needs_backup: bool = None,
|
||||
flags: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.vendor = vendor
|
||||
self.major_version = major_version
|
||||
self.minor_version = minor_version
|
||||
self.patch_version = patch_version
|
||||
self.bootloader_mode = bootloader_mode
|
||||
self.device_id = device_id
|
||||
self.pin_protection = pin_protection
|
||||
self.passphrase_protection = passphrase_protection
|
||||
self.language = language
|
||||
self.label = label
|
||||
self.coins = coins
|
||||
self.initialized = initialized
|
||||
self.revision = revision
|
||||
self.bootloader_hash = bootloader_hash
|
||||
self.imported = imported
|
||||
self.pin_cached = pin_cached
|
||||
self.passphrase_cached = passphrase_cached
|
||||
self.firmware_present = firmware_present
|
||||
self.needs_backup = needs_backup
|
||||
self.flags = flags
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class FirmwareErase(p.MessageType):
|
||||
1: ('length', p.UVarintType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 6
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
length: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.length = length
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,13 @@ class FirmwareRequest(p.MessageType):
|
||||
2: ('length', p.UVarintType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 8
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
offset: int = None,
|
||||
length: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.offset = offset
|
||||
self.length = length
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,13 @@ class FirmwareUpload(p.MessageType):
|
||||
2: ('hash', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 7
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
payload: bytes = None,
|
||||
hash: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.payload = payload
|
||||
self.hash = hash
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -12,3 +12,19 @@ class GetAddress(p.MessageType):
|
||||
5: ('script_type', p.UVarintType, 0), # default=0
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 29
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address_n: list = [],
|
||||
coin_name: str = None,
|
||||
show_display: bool = None,
|
||||
multisig: MultisigRedeemScriptType = None,
|
||||
script_type: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address_n = address_n
|
||||
self.coin_name = coin_name
|
||||
self.show_display = show_display
|
||||
self.multisig = multisig
|
||||
self.script_type = script_type
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -10,3 +10,15 @@ class GetECDHSessionKey(p.MessageType):
|
||||
3: ('ecdsa_curve_name', p.UnicodeType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 61
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
identity: IdentityType = None,
|
||||
peer_public_key: bytes = None,
|
||||
ecdsa_curve_name: str = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.identity = identity
|
||||
self.peer_public_key = peer_public_key
|
||||
self.ecdsa_curve_name = ecdsa_curve_name
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class GetEntropy(p.MessageType):
|
||||
1: ('size', p.UVarintType, 0), # required
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 9
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
size: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.size = size
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -4,3 +4,9 @@ import protobuf as p
|
||||
|
||||
class GetFeatures(p.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 55
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
**kwargs,
|
||||
):
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -10,3 +10,17 @@ class GetPublicKey(p.MessageType):
|
||||
4: ('coin_name', p.UnicodeType, 0), # default='Bitcoin'
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 11
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address_n: list = [],
|
||||
ecdsa_curve_name: str = None,
|
||||
show_display: bool = None,
|
||||
coin_name: str = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address_n = address_n
|
||||
self.ecdsa_curve_name = ecdsa_curve_name
|
||||
self.show_display = show_display
|
||||
self.coin_name = coin_name
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,13 @@ class HDNodePathType(p.MessageType):
|
||||
1: ('node', HDNodeType, 0), # required
|
||||
2: ('address_n', p.UVarintType, p.FLAG_REPEATED),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
node: HDNodeType = None,
|
||||
address_n: list = [],
|
||||
**kwargs,
|
||||
):
|
||||
self.node = node
|
||||
self.address_n = address_n
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -11,3 +11,21 @@ class HDNodeType(p.MessageType):
|
||||
5: ('private_key', p.BytesType, 0),
|
||||
6: ('public_key', p.BytesType, 0),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
depth: int = None,
|
||||
fingerprint: int = None,
|
||||
child_num: int = None,
|
||||
chain_code: bytes = None,
|
||||
private_key: bytes = None,
|
||||
public_key: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.depth = depth
|
||||
self.fingerprint = fingerprint
|
||||
self.child_num = child_num
|
||||
self.chain_code = chain_code
|
||||
self.private_key = private_key
|
||||
self.public_key = public_key
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -11,3 +11,21 @@ class IdentityType(p.MessageType):
|
||||
5: ('path', p.UnicodeType, 0),
|
||||
6: ('index', p.UVarintType, 0), # default=0
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
proto: str = None,
|
||||
user: str = None,
|
||||
host: str = None,
|
||||
port: str = None,
|
||||
path: str = None,
|
||||
index: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.proto = proto
|
||||
self.user = user
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.path = path
|
||||
self.index = index
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -3,7 +3,10 @@ import protobuf as p
|
||||
|
||||
|
||||
class Initialize(p.MessageType):
|
||||
FIELDS = {
|
||||
1: ('state', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 0
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
**kwargs,
|
||||
):
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -15,3 +15,25 @@ class LoadDevice(p.MessageType):
|
||||
8: ('u2f_counter', p.UVarintType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 13
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
mnemonic: str = None,
|
||||
node: HDNodeType = None,
|
||||
pin: str = None,
|
||||
passphrase_protection: bool = None,
|
||||
language: str = None,
|
||||
label: str = None,
|
||||
skip_checksum: bool = None,
|
||||
u2f_counter: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.mnemonic = mnemonic
|
||||
self.node = node
|
||||
self.pin = pin
|
||||
self.passphrase_protection = passphrase_protection
|
||||
self.language = language
|
||||
self.label = label
|
||||
self.skip_checksum = skip_checksum
|
||||
self.u2f_counter = u2f_counter
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,13 @@ class MessageSignature(p.MessageType):
|
||||
2: ('signature', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 40
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address: str = None,
|
||||
signature: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address = address
|
||||
self.signature = signature
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -73,8 +73,6 @@ CosiCommit = const(71)
|
||||
CosiCommitment = const(72)
|
||||
CosiSign = const(73)
|
||||
CosiSignature = const(74)
|
||||
NEMDecryptMessage = const(75)
|
||||
NEMDecryptedMessage = const(76)
|
||||
DebugLinkDecision = const(100)
|
||||
DebugLinkGetState = const(101)
|
||||
DebugLinkState = const(102)
|
||||
|
@ -9,3 +9,15 @@ class MultisigRedeemScriptType(p.MessageType):
|
||||
2: ('signatures', p.BytesType, p.FLAG_REPEATED),
|
||||
3: ('m', p.UVarintType, 0),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
pubkeys: list = [],
|
||||
signatures: list = [],
|
||||
m: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.pubkeys = pubkeys
|
||||
self.signatures = signatures
|
||||
self.m = m
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class NEMAddress(p.MessageType):
|
||||
1: ('address', p.UnicodeType, 0), # required
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 68
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address: str = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address = address
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,13 @@ class NEMAggregateModification(p.MessageType):
|
||||
1: ('modifications', NEMCosignatoryModification, p.FLAG_REPEATED),
|
||||
2: ('relative_change', p.Sint32Type, 0),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
modifications: list = [],
|
||||
relative_change: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.modifications = modifications
|
||||
self.relative_change = relative_change
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,13 @@ class NEMCosignatoryModification(p.MessageType):
|
||||
1: ('type', p.UVarintType, 0),
|
||||
2: ('public_key', p.BytesType, 0),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type: int = None,
|
||||
public_key: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.type = type
|
||||
self.public_key = public_key
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -1,12 +0,0 @@
|
||||
# Automatically generated by pb2py
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class NEMDecryptMessage(p.MessageType):
|
||||
FIELDS = {
|
||||
1: ('address_n', p.UVarintType, p.FLAG_REPEATED),
|
||||
2: ('network', p.UVarintType, 0),
|
||||
3: ('public_key', p.BytesType, 0),
|
||||
4: ('payload', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 75
|
@ -1,9 +0,0 @@
|
||||
# Automatically generated by pb2py
|
||||
import protobuf as p
|
||||
|
||||
|
||||
class NEMDecryptedMessage(p.MessageType):
|
||||
FIELDS = {
|
||||
1: ('payload', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 76
|
@ -9,3 +9,15 @@ class NEMGetAddress(p.MessageType):
|
||||
3: ('show_display', p.BoolType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 67
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address_n: list = [],
|
||||
network: int = None,
|
||||
show_display: bool = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address_n = address_n
|
||||
self.network = network
|
||||
self.show_display = show_display
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,13 @@ class NEMImportanceTransfer(p.MessageType):
|
||||
1: ('mode', p.UVarintType, 0),
|
||||
2: ('public_key', p.BytesType, 0),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
mode: int = None,
|
||||
public_key: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.mode = mode
|
||||
self.public_key = public_key
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,15 @@ class NEMMosaic(p.MessageType):
|
||||
2: ('mosaic', p.UnicodeType, 0),
|
||||
3: ('quantity', p.UVarintType, 0),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
namespace: str = None,
|
||||
mosaic: str = None,
|
||||
quantity: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.namespace = namespace
|
||||
self.mosaic = mosaic
|
||||
self.quantity = quantity
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -9,3 +9,15 @@ class NEMMosaicCreation(p.MessageType):
|
||||
2: ('sink', p.UnicodeType, 0),
|
||||
3: ('fee', p.UVarintType, 0),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
definition: NEMMosaicDefinition = None,
|
||||
sink: str = None,
|
||||
fee: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.definition = definition
|
||||
self.sink = sink
|
||||
self.fee = fee
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -20,3 +20,39 @@ class NEMMosaicDefinition(p.MessageType):
|
||||
14: ('description', p.UnicodeType, 0),
|
||||
15: ('networks', p.UVarintType, p.FLAG_REPEATED),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str = None,
|
||||
ticker: str = None,
|
||||
namespace: str = None,
|
||||
mosaic: str = None,
|
||||
divisibility: int = None,
|
||||
levy: int = None,
|
||||
fee: int = None,
|
||||
levy_address: str = None,
|
||||
levy_namespace: str = None,
|
||||
levy_mosaic: str = None,
|
||||
supply: int = None,
|
||||
mutable_supply: bool = None,
|
||||
transferable: bool = None,
|
||||
description: str = None,
|
||||
networks: list = [],
|
||||
**kwargs,
|
||||
):
|
||||
self.name = name
|
||||
self.ticker = ticker
|
||||
self.namespace = namespace
|
||||
self.mosaic = mosaic
|
||||
self.divisibility = divisibility
|
||||
self.levy = levy
|
||||
self.fee = fee
|
||||
self.levy_address = levy_address
|
||||
self.levy_namespace = levy_namespace
|
||||
self.levy_mosaic = levy_mosaic
|
||||
self.supply = supply
|
||||
self.mutable_supply = mutable_supply
|
||||
self.transferable = transferable
|
||||
self.description = description
|
||||
self.networks = networks
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -9,3 +9,17 @@ class NEMMosaicSupplyChange(p.MessageType):
|
||||
3: ('type', p.UVarintType, 0),
|
||||
4: ('delta', p.UVarintType, 0),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
namespace: str = None,
|
||||
mosaic: str = None,
|
||||
type: int = None,
|
||||
delta: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.namespace = namespace
|
||||
self.mosaic = mosaic
|
||||
self.type = type
|
||||
self.delta = delta
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -9,3 +9,17 @@ class NEMProvisionNamespace(p.MessageType):
|
||||
3: ('sink', p.UnicodeType, 0),
|
||||
4: ('fee', p.UVarintType, 0),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
namespace: str = None,
|
||||
parent: str = None,
|
||||
sink: str = None,
|
||||
fee: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.namespace = namespace
|
||||
self.parent = parent
|
||||
self.sink = sink
|
||||
self.fee = fee
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -22,3 +22,27 @@ class NEMSignTx(p.MessageType):
|
||||
9: ('importance_transfer', NEMImportanceTransfer, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 69
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transaction: NEMTransactionCommon = None,
|
||||
multisig: NEMTransactionCommon = None,
|
||||
transfer: NEMTransfer = None,
|
||||
cosigning: bool = None,
|
||||
provision_namespace: NEMProvisionNamespace = None,
|
||||
mosaic_creation: NEMMosaicCreation = None,
|
||||
supply_change: NEMMosaicSupplyChange = None,
|
||||
aggregate_modification: NEMAggregateModification = None,
|
||||
importance_transfer: NEMImportanceTransfer = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.transaction = transaction
|
||||
self.multisig = multisig
|
||||
self.transfer = transfer
|
||||
self.cosigning = cosigning
|
||||
self.provision_namespace = provision_namespace
|
||||
self.mosaic_creation = mosaic_creation
|
||||
self.supply_change = supply_change
|
||||
self.aggregate_modification = aggregate_modification
|
||||
self.importance_transfer = importance_transfer
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -8,3 +8,13 @@ class NEMSignedTx(p.MessageType):
|
||||
2: ('signature', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 70
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data: bytes = None,
|
||||
signature: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.data = data
|
||||
self.signature = signature
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -11,3 +11,21 @@ class NEMTransactionCommon(p.MessageType):
|
||||
5: ('deadline', p.UVarintType, 0),
|
||||
6: ('signer', p.BytesType, 0),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
address_n: list = [],
|
||||
network: int = None,
|
||||
timestamp: int = None,
|
||||
fee: int = None,
|
||||
deadline: int = None,
|
||||
signer: bytes = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.address_n = address_n
|
||||
self.network = network
|
||||
self.timestamp = timestamp
|
||||
self.fee = fee
|
||||
self.deadline = deadline
|
||||
self.signer = signer
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -11,3 +11,19 @@ class NEMTransfer(p.MessageType):
|
||||
4: ('public_key', p.BytesType, 0),
|
||||
5: ('mosaics', NEMMosaic, p.FLAG_REPEATED),
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
recipient: str = None,
|
||||
amount: int = None,
|
||||
payload: bytes = None,
|
||||
public_key: bytes = None,
|
||||
mosaics: list = [],
|
||||
**kwargs,
|
||||
):
|
||||
self.recipient = recipient
|
||||
self.amount = amount
|
||||
self.payload = payload
|
||||
self.public_key = public_key
|
||||
self.mosaics = mosaics
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -5,6 +5,13 @@ import protobuf as p
|
||||
class PassphraseAck(p.MessageType):
|
||||
FIELDS = {
|
||||
1: ('passphrase', p.UnicodeType, 0), # required
|
||||
2: ('state', p.BytesType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 42
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
passphrase: str = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.passphrase = passphrase
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -3,7 +3,10 @@ import protobuf as p
|
||||
|
||||
|
||||
class PassphraseRequest(p.MessageType):
|
||||
FIELDS = {
|
||||
1: ('on_device', p.BoolType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 41
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
**kwargs,
|
||||
):
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class PinMatrixAck(p.MessageType):
|
||||
1: ('pin', p.UnicodeType, 0), # required
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 19
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
pin: str = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.pin = pin
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -7,3 +7,11 @@ class PinMatrixRequest(p.MessageType):
|
||||
1: ('type', p.UVarintType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 18
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type: int = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.type = type
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -10,3 +10,17 @@ class Ping(p.MessageType):
|
||||
4: ('passphrase_protection', p.BoolType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 1
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str = None,
|
||||
button_protection: bool = None,
|
||||
pin_protection: bool = None,
|
||||
passphrase_protection: bool = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.message = message
|
||||
self.button_protection = button_protection
|
||||
self.pin_protection = pin_protection
|
||||
self.passphrase_protection = passphrase_protection
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -9,3 +9,13 @@ class PublicKey(p.MessageType):
|
||||
2: ('xpub', p.UnicodeType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 12
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
node: HDNodeType = None,
|
||||
xpub: str = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.node = node
|
||||
self.xpub = xpub
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
@ -15,3 +15,27 @@ class RecoveryDevice(p.MessageType):
|
||||
10: ('dry_run', p.BoolType, 0),
|
||||
}
|
||||
MESSAGE_WIRE_TYPE = 45
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
word_count: int = None,
|
||||
passphrase_protection: bool = None,
|
||||
pin_protection: bool = None,
|
||||
language: str = None,
|
||||
label: str = None,
|
||||
enforce_wordlist: bool = None,
|
||||
type: int = None,
|
||||
u2f_counter: int = None,
|
||||
dry_run: bool = None,
|
||||
**kwargs,
|
||||
):
|
||||
self.word_count = word_count
|
||||
self.passphrase_protection = passphrase_protection
|
||||
self.pin_protection = pin_protection
|
||||
self.language = language
|
||||
self.label = label
|
||||
self.enforce_wordlist = enforce_wordlist
|
||||
self.type = type
|
||||
self.u2f_counter = u2f_counter
|
||||
self.dry_run = dry_run
|
||||
p.MessageType.__init__(self, **kwargs)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user