mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 12:46:44 +00:00
Merge bfd5914a1d into f4817b7a53
This commit is contained in:
commit
75d6ab19e8
20 changed files with 8093 additions and 3697 deletions
106
accounts/usbwallet/data_type.go
Normal file
106
accounts/usbwallet/data_type.go
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
// Copyright 2017 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package usbwallet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
type dataType byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
CustomType dataType = iota
|
||||||
|
IntType
|
||||||
|
UintType
|
||||||
|
AddressType
|
||||||
|
BoolType
|
||||||
|
StringType
|
||||||
|
FixedBytesType
|
||||||
|
BytesType
|
||||||
|
)
|
||||||
|
|
||||||
|
var nameToType = map[string]dataType{
|
||||||
|
"int": IntType,
|
||||||
|
"uint": UintType,
|
||||||
|
"address": AddressType,
|
||||||
|
"bool": BoolType,
|
||||||
|
"string": StringType,
|
||||||
|
"bytes": BytesType,
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseType(data apitypes.TypedData, field apitypes.Type) (dt dataType, name string, byteLength int, arrayLevels []*int, err error) {
|
||||||
|
name = strings.TrimSpace(field.Type)
|
||||||
|
arrayLengths := regexp.MustCompile(`\[(\d*)]`).FindAllStringSubmatch(name, -1)
|
||||||
|
if len(arrayLengths) > 0 {
|
||||||
|
arrayLevels = make([]*int, len(arrayLengths))
|
||||||
|
for i, arrayLength := range arrayLengths {
|
||||||
|
if len(arrayLength[1]) == 0 {
|
||||||
|
arrayLevels[i] = nil // nil means dynamic length
|
||||||
|
} else {
|
||||||
|
length, _ := strconv.Atoi(arrayLength[1]) // guaranteed to be a digit, ignore error
|
||||||
|
arrayLevels[i] = &length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
name = name[0:strings.Index(name, "[")]
|
||||||
|
}
|
||||||
|
if data.Types[name] != nil {
|
||||||
|
dt = CustomType
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
matches := regexp.MustCompile(`^(.+?)(\d*)$`).FindStringSubmatch(name)
|
||||||
|
name = matches[1]
|
||||||
|
lengthStr := matches[2]
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
if dt, ok = nameToType[name]; !ok {
|
||||||
|
err = fmt.Errorf("unknown type: %s", field.Type)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
byteLength, _ = strconv.Atoi(lengthStr)
|
||||||
|
if dt == UintType || dt == IntType {
|
||||||
|
if lengthStr == "" {
|
||||||
|
byteLength = 32
|
||||||
|
} else if byteLength%8 != 0 {
|
||||||
|
err = fmt.Errorf("invalid length for %s: %s", field.Type, lengthStr)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
byteLength /= 8
|
||||||
|
}
|
||||||
|
} else if lengthStr != "" {
|
||||||
|
if dt == BytesType {
|
||||||
|
dt = FixedBytesType
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("invalid type: %s", field.Type)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if dt == AddressType {
|
||||||
|
byteLength = 20 // address is always 20 bytes
|
||||||
|
}
|
||||||
|
if lengthStr != "" && (byteLength < 1 || byteLength > 32) {
|
||||||
|
err = fmt.Errorf("invalid length for %s: %s", field.Type, lengthStr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
@ -26,7 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/karalabe/hid"
|
"github.com/karalabe/usb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LedgerScheme is the protocol scheme prefixing account and wallet URLs.
|
// LedgerScheme is the protocol scheme prefixing account and wallet URLs.
|
||||||
|
|
@ -105,7 +105,7 @@ func NewTrezorHubWithWebUSB() (*Hub, error) {
|
||||||
|
|
||||||
// newHub creates a new hardware wallet manager for generic USB devices.
|
// newHub creates a new hardware wallet manager for generic USB devices.
|
||||||
func newHub(scheme string, vendorID uint16, productIDs []uint16, usageID uint16, endpointID int, makeDriver func(log.Logger) driver) (*Hub, error) {
|
func newHub(scheme string, vendorID uint16, productIDs []uint16, usageID uint16, endpointID int, makeDriver func(log.Logger) driver) (*Hub, error) {
|
||||||
if !hid.Supported() {
|
if !usb.Supported() {
|
||||||
return nil, errors.New("unsupported platform")
|
return nil, errors.New("unsupported platform")
|
||||||
}
|
}
|
||||||
hub := &Hub{
|
hub := &Hub{
|
||||||
|
|
@ -151,7 +151,7 @@ func (hub *Hub) refreshWallets() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Retrieve the current list of USB wallet devices
|
// Retrieve the current list of USB wallet devices
|
||||||
var devices []hid.DeviceInfo
|
var devices []usb.DeviceInfo
|
||||||
|
|
||||||
if runtime.GOOS == "linux" {
|
if runtime.GOOS == "linux" {
|
||||||
// hidapi on Linux opens the device during enumeration to retrieve some infos,
|
// hidapi on Linux opens the device during enumeration to retrieve some infos,
|
||||||
|
|
@ -166,7 +166,7 @@ func (hub *Hub) refreshWallets() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
infos, err := hid.Enumerate(hub.vendorID, 0)
|
infos, err := usb.Enumerate(hub.vendorID, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
failcount := hub.enumFails.Add(1)
|
failcount := hub.enumFails.Add(1)
|
||||||
if runtime.GOOS == "linux" {
|
if runtime.GOOS == "linux" {
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,18 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ledgerOpcode is an enumeration encoding the supported Ledger opcodes.
|
// ledgerOpcode is an enumeration encoding the supported Ledger opcodes.
|
||||||
|
|
@ -48,21 +52,60 @@ type ledgerParam1 byte
|
||||||
// specific opcodes. The same parameter values may be reused between opcodes.
|
// specific opcodes. The same parameter values may be reused between opcodes.
|
||||||
type ledgerParam2 byte
|
type ledgerParam2 byte
|
||||||
|
|
||||||
|
// ledgerStatus is an enumeration encoding ledger status words.
|
||||||
|
type ledgerStatus uint16
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ledgerOpRetrieveAddress ledgerOpcode = 0x02 // Returns the public key and Ethereum address for a given BIP 32 path
|
ledgerOpRetrieveAddress ledgerOpcode = 0x02 // Returns the public key and Ethereum address for a given BIP 32 path
|
||||||
ledgerOpSignTransaction ledgerOpcode = 0x04 // Signs an Ethereum transaction after having the user validate the parameters
|
ledgerOpSignTransaction ledgerOpcode = 0x04 // Signs an Ethereum transaction after having the user validate the parameters
|
||||||
ledgerOpGetConfiguration ledgerOpcode = 0x06 // Returns specific wallet application configuration
|
ledgerOpGetConfiguration ledgerOpcode = 0x06 // Returns specific wallet application configuration
|
||||||
ledgerOpSignTypedMessage ledgerOpcode = 0x0c // Signs an Ethereum message following the EIP 712 specification
|
ledgerOpSignPersonalMessage ledgerOpcode = 0x08 // Signs a personal message following the EIP 712 specification
|
||||||
|
ledgerOpSignTypedMessage ledgerOpcode = 0x0c // Signs an Ethereum message following the EIP 712 specification
|
||||||
|
ledgerOpEip712SendStructDef ledgerOpcode = 0x1a // Sends EIP-712 struct types to the ledger
|
||||||
|
ledgerOpEip712SendStructImpl ledgerOpcode = 0x1c // Sends EIP-712 struct values to the ledger
|
||||||
|
|
||||||
ledgerP1DirectlyFetchAddress ledgerParam1 = 0x00 // Return address directly from the wallet
|
ledgerP1DirectlyFetchAddress ledgerParam1 = 0x00 // Return address directly from the wallet
|
||||||
ledgerP1InitTypedMessageData ledgerParam1 = 0x00 // First chunk of Typed Message data
|
ledgerP1InitTypedMessageData ledgerParam1 = 0x00 // First chunk of Typed Message data
|
||||||
ledgerP1InitTransactionData ledgerParam1 = 0x00 // First transaction data block for signing
|
ledgerP1InitTransactionData ledgerParam1 = 0x00 // First transaction data block for signing
|
||||||
ledgerP1ContTransactionData ledgerParam1 = 0x80 // Subsequent transaction data block for signing
|
ledgerP1ContTransactionData ledgerParam1 = 0x80 // Subsequent transaction data block for signing
|
||||||
|
ledgerP1CompleteSend ledgerParam1 = 0x00 // Complete the value (in one go, or after partial)
|
||||||
|
ledgerP1PartialSend ledgerParam1 = 0x01 // Send partial data
|
||||||
ledgerP2DiscardAddressChainCode ledgerParam2 = 0x00 // Do not return the chain code along with the address
|
ledgerP2DiscardAddressChainCode ledgerParam2 = 0x00 // Do not return the chain code along with the address
|
||||||
|
ledgerP2ProcessAndStartFlow ledgerParam2 = 0x00 // Process and start transaction signing flow
|
||||||
|
ledgerP2V0Implementation ledgerParam2 = 0x00 // EIP-712 V0 implementation (hashes only)
|
||||||
|
ledgerP2StructName ledgerParam2 = 0x00 // Send EIP-712 struct name
|
||||||
|
ledgerP2RootStruct ledgerParam2 = 0x00 // Send EIP-712 root struct
|
||||||
|
ledgerP2Array ledgerParam2 = 0x0f // Send EIP-712 array
|
||||||
|
ledgerP2StructField ledgerParam2 = 0xff // Send EIP-712 struct field
|
||||||
|
ledgerP2FullImplementation ledgerParam2 = 0x01 // EIP-712 full implementation (typed data)
|
||||||
|
|
||||||
ledgerEip155Size int = 3 // Size of the EIP-155 chain_id,r,s in unsigned transactions
|
ledgerStatusNormalEnd ledgerStatus = 0x9000
|
||||||
|
ledgerEip155Size int = 3 // Size of the EIP-155 chain_id,r,s in unsigned transactions
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ledgerStatuses = map[ledgerStatus]string{
|
||||||
|
0x5515: "Device is locked",
|
||||||
|
0x6001: "Mode check fail",
|
||||||
|
0x6501: "TransactionType not supported",
|
||||||
|
0x6502: "Output buffer too small for chainId conversion",
|
||||||
|
0x6511: "Ethereum app not open",
|
||||||
|
//0x68xx: "Internal error (Please report)",
|
||||||
|
0x6982: "Security status not satisfied (Canceled by user)",
|
||||||
|
0x6983: "Wrong Data length",
|
||||||
|
0x6984: "Plugin not installed",
|
||||||
|
0x6985: "Condition not satisfied",
|
||||||
|
0x6A00: "Error without info",
|
||||||
|
0x6A80: "Invalid data",
|
||||||
|
0x6A84: "Insufficient memory",
|
||||||
|
0x6A88: "Data not found",
|
||||||
|
0x6B00: "Incorrect parameter P1 or P2",
|
||||||
|
0x6D00: "Incorrect parameter INS",
|
||||||
|
0x6E00: "Incorrect parameter CLA",
|
||||||
|
0x6F00: "Incorrect parameter CLA",
|
||||||
|
0x6F01: "Technical problem (Internal error, please report)",
|
||||||
|
0x911C: "Command code not supported (i.e. Ledger-PKI not yet available)",
|
||||||
|
}
|
||||||
|
|
||||||
// errLedgerReplyInvalidHeader is the error message returned by a Ledger data exchange
|
// errLedgerReplyInvalidHeader is the error message returned by a Ledger data exchange
|
||||||
// if the device replies with a mismatching header. This usually means the device
|
// if the device replies with a mismatching header. This usually means the device
|
||||||
// is in browser mode.
|
// is in browser mode.
|
||||||
|
|
@ -72,6 +115,10 @@ var errLedgerReplyInvalidHeader = errors.New("ledger: invalid reply header")
|
||||||
// when a response does arrive, but it does not contain the expected data.
|
// when a response does arrive, but it does not contain the expected data.
|
||||||
var errLedgerInvalidVersionReply = errors.New("ledger: invalid version reply")
|
var errLedgerInvalidVersionReply = errors.New("ledger: invalid version reply")
|
||||||
|
|
||||||
|
// errLedgerInvalidStatus is the error message returned if the ledger doesn't respond with a
|
||||||
|
// 0x9000 status.
|
||||||
|
var errLedgerInvalidStatus = errors.New("ledger: invalid status")
|
||||||
|
|
||||||
// ledgerDriver implements the communication with a Ledger hardware wallet.
|
// ledgerDriver implements the communication with a Ledger hardware wallet.
|
||||||
type ledgerDriver struct {
|
type ledgerDriver struct {
|
||||||
device io.ReadWriter // USB device connection to communicate through
|
device io.ReadWriter // USB device connection to communicate through
|
||||||
|
|
@ -119,7 +166,7 @@ func (w *ledgerDriver) Open(device io.ReadWriter, passphrase string) error {
|
||||||
_, err := w.ledgerDerive(accounts.DefaultBaseDerivationPath)
|
_, err := w.ledgerDerive(accounts.DefaultBaseDerivationPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Ethereum app is not running or in browser mode, nothing more to do, return
|
// Ethereum app is not running or in browser mode, nothing more to do, return
|
||||||
if err == errLedgerReplyInvalidHeader {
|
if errors.Is(err, errLedgerReplyInvalidHeader) {
|
||||||
w.browser = true
|
w.browser = true
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -141,7 +188,7 @@ func (w *ledgerDriver) Close() error {
|
||||||
// Heartbeat implements usbwallet.driver, performing a sanity check against the
|
// Heartbeat implements usbwallet.driver, performing a sanity check against the
|
||||||
// Ledger to see if it's still online.
|
// Ledger to see if it's still online.
|
||||||
func (w *ledgerDriver) Heartbeat() error {
|
func (w *ledgerDriver) Heartbeat() error {
|
||||||
if _, err := w.ledgerVersion(); err != nil && err != errLedgerInvalidVersionReply {
|
if _, err := w.ledgerVersion(); err != nil && !errors.Is(err, errLedgerInvalidVersionReply) {
|
||||||
w.failure = err
|
w.failure = err
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -166,7 +213,7 @@ func (w *ledgerDriver) SignTx(path accounts.DerivationPath, tx *types.Transactio
|
||||||
return common.Address{}, nil, accounts.ErrWalletClosed
|
return common.Address{}, nil, accounts.ErrWalletClosed
|
||||||
}
|
}
|
||||||
// Ensure the wallet is capable of signing the given transaction
|
// Ensure the wallet is capable of signing the given transaction
|
||||||
if chainID != nil && (w.version[0] < 1 || (w.version[0] == 1 && w.version[1] == 0 && w.version[2] < 3)) {
|
if chainID != nil && w.version[0] <= 1 && w.version[1] <= 0 && w.version[2] <= 2 {
|
||||||
//lint:ignore ST1005 brand name displayed on the console
|
//lint:ignore ST1005 brand name displayed on the console
|
||||||
return common.Address{}, nil, fmt.Errorf("Ledger v%d.%d.%d doesn't support signing this transaction, please update to v1.0.3 at least", w.version[0], w.version[1], w.version[2])
|
return common.Address{}, nil, fmt.Errorf("Ledger v%d.%d.%d doesn't support signing this transaction, please update to v1.0.3 at least", w.version[0], w.version[1], w.version[2])
|
||||||
}
|
}
|
||||||
|
|
@ -174,11 +221,11 @@ func (w *ledgerDriver) SignTx(path accounts.DerivationPath, tx *types.Transactio
|
||||||
return w.ledgerSign(path, tx, chainID)
|
return w.ledgerSign(path, tx, chainID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignTypedMessage implements usbwallet.driver, sending the message to the Ledger and
|
// SignTypedHash implements usbwallet.driver, sending the message to the Ledger and
|
||||||
// waiting for the user to sign or deny the transaction.
|
// waiting for the user to sign or deny the transaction.
|
||||||
//
|
//
|
||||||
// Note: this was introduced in the ledger 1.5.0 firmware
|
// Note: this was introduced in the ledger 1.5.0 firmware
|
||||||
func (w *ledgerDriver) SignTypedMessage(path accounts.DerivationPath, domainHash []byte, messageHash []byte) ([]byte, error) {
|
func (w *ledgerDriver) SignTypedHash(path accounts.DerivationPath, domainHash []byte, messageHash []byte) ([]byte, error) {
|
||||||
// If the Ethereum app doesn't run, abort
|
// If the Ethereum app doesn't run, abort
|
||||||
if w.offline() {
|
if w.offline() {
|
||||||
return nil, accounts.ErrWalletClosed
|
return nil, accounts.ErrWalletClosed
|
||||||
|
|
@ -189,7 +236,39 @@ func (w *ledgerDriver) SignTypedMessage(path accounts.DerivationPath, domainHash
|
||||||
return nil, fmt.Errorf("Ledger version >= 1.5.0 required for EIP-712 signing (found version v%d.%d.%d)", w.version[0], w.version[1], w.version[2])
|
return nil, fmt.Errorf("Ledger version >= 1.5.0 required for EIP-712 signing (found version v%d.%d.%d)", w.version[0], w.version[1], w.version[2])
|
||||||
}
|
}
|
||||||
// All infos gathered and metadata checks out, request signing
|
// All infos gathered and metadata checks out, request signing
|
||||||
return w.ledgerSignTypedMessage(path, domainHash, messageHash)
|
return w.ledgerSignTypedHash(path, domainHash, messageHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignText implements usbwallet.driver, sending the message to the Ledger and
|
||||||
|
// waiting for the user to confirm or deny the signature.
|
||||||
|
func (w *ledgerDriver) SignText(path accounts.DerivationPath, text []byte) ([]byte, error) {
|
||||||
|
// If the Ethereum app doesn't run, abort
|
||||||
|
if w.offline() {
|
||||||
|
return nil, accounts.ErrWalletClosed
|
||||||
|
}
|
||||||
|
// Ensure the wallet is capable of signing the given transaction
|
||||||
|
if w.version[0] < 1 && w.version[1] < 5 {
|
||||||
|
//lint:ignore ST1005 brand name displayed on the console
|
||||||
|
return nil, fmt.Errorf("Ledger version >= 1.5.0 required for EIP-712 signing (found version v%d.%d.%d)", w.version[0], w.version[1], w.version[2])
|
||||||
|
}
|
||||||
|
// All infos gathered and metadata checks out, request signing
|
||||||
|
return w.ledgerSignPersonalMessage(path, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignedTypedData implements usbwallet.driver, sending the message to the Ledger and
|
||||||
|
// waiting for the user to sign or deny signing an EIP-712 typed data struct.
|
||||||
|
func (w *ledgerDriver) SignedTypedData(path accounts.DerivationPath, data apitypes.TypedData) ([]byte, error) {
|
||||||
|
// If the Ethereum app doesn't run, abort
|
||||||
|
if w.offline() {
|
||||||
|
return nil, accounts.ErrWalletClosed
|
||||||
|
}
|
||||||
|
// Ensure the wallet is capable of signing the given transaction
|
||||||
|
if w.version[0] < 1 && w.version[1] < 5 {
|
||||||
|
//lint:ignore ST1005 brand name displayed on the console
|
||||||
|
return nil, fmt.Errorf("Ledger version >= 1.5.0 required for EIP-712 signing (found version v%d.%d.%d)", w.version[0], w.version[1], w.version[2])
|
||||||
|
}
|
||||||
|
// All infos gathered and metadata checks out, request signing
|
||||||
|
return w.ledgerSignTypedData(path, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ledgerVersion retrieves the current version of the Ethereum wallet app running
|
// ledgerVersion retrieves the current version of the Ethereum wallet app running
|
||||||
|
|
@ -360,7 +439,7 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
|
||||||
|
|
||||||
// Send the request and wait for the response
|
// Send the request and wait for the response
|
||||||
var (
|
var (
|
||||||
op = ledgerP1InitTransactionData
|
p1 = ledgerP1InitTransactionData
|
||||||
reply []byte
|
reply []byte
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -378,13 +457,13 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
|
||||||
chunk = len(payload)
|
chunk = len(payload)
|
||||||
}
|
}
|
||||||
// Send the chunk over, ensuring it's processed correctly
|
// Send the chunk over, ensuring it's processed correctly
|
||||||
reply, err = w.ledgerExchange(ledgerOpSignTransaction, op, 0, payload[:chunk])
|
reply, err = w.ledgerExchange(ledgerOpSignTransaction, p1, ledgerP2ProcessAndStartFlow, payload[:chunk])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Address{}, nil, err
|
return common.Address{}, nil, err
|
||||||
}
|
}
|
||||||
// Shift the payload and ensure subsequent chunks are marked as such
|
// Shift the payload and ensure subsequent chunks are marked as such
|
||||||
payload = payload[chunk:]
|
payload = payload[chunk:]
|
||||||
op = ledgerP1ContTransactionData
|
p1 = ledgerP1ContTransactionData
|
||||||
}
|
}
|
||||||
// Extract the Ethereum signature and do a sanity validation
|
// Extract the Ethereum signature and do a sanity validation
|
||||||
if len(reply) != crypto.SignatureLength {
|
if len(reply) != crypto.SignatureLength {
|
||||||
|
|
@ -414,7 +493,7 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
|
||||||
return sender, signed, nil
|
return sender, signed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ledgerSignTypedMessage sends the transaction to the Ledger wallet, and waits for the user
|
// ledgerSignTypedHash sends the transaction to the Ledger wallet, and waits for the user
|
||||||
// to confirm or deny the transaction.
|
// to confirm or deny the transaction.
|
||||||
//
|
//
|
||||||
// The signing protocol is defined as follows:
|
// The signing protocol is defined as follows:
|
||||||
|
|
@ -441,7 +520,7 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
|
||||||
// signature V | 1 byte
|
// signature V | 1 byte
|
||||||
// signature R | 32 bytes
|
// signature R | 32 bytes
|
||||||
// signature S | 32 bytes
|
// signature S | 32 bytes
|
||||||
func (w *ledgerDriver) ledgerSignTypedMessage(derivationPath []uint32, domainHash []byte, messageHash []byte) ([]byte, error) {
|
func (w *ledgerDriver) ledgerSignTypedHash(derivationPath []uint32, domainHash []byte, messageHash []byte) ([]byte, error) {
|
||||||
// Flatten the derivation path into the Ledger request
|
// Flatten the derivation path into the Ledger request
|
||||||
path := make([]byte, 1+4*len(derivationPath))
|
path := make([]byte, 1+4*len(derivationPath))
|
||||||
path[0] = byte(len(derivationPath))
|
path[0] = byte(len(derivationPath))
|
||||||
|
|
@ -454,13 +533,12 @@ func (w *ledgerDriver) ledgerSignTypedMessage(derivationPath []uint32, domainHas
|
||||||
|
|
||||||
// Send the request and wait for the response
|
// Send the request and wait for the response
|
||||||
var (
|
var (
|
||||||
op = ledgerP1InitTypedMessageData
|
|
||||||
reply []byte
|
reply []byte
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
// Send the message over, ensuring it's processed correctly
|
// Send the message over, ensuring it's processed correctly
|
||||||
reply, err = w.ledgerExchange(ledgerOpSignTypedMessage, op, 0, payload)
|
reply, err = w.ledgerExchange(ledgerOpSignTypedMessage, ledgerP1InitTypedMessageData, ledgerP2V0Implementation, payload)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -474,6 +552,281 @@ func (w *ledgerDriver) ledgerSignTypedMessage(derivationPath []uint32, domainHas
|
||||||
return signature, nil
|
return signature, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ledgerSignPersonalMessage sends the transaction to the Ledger wallet, and waits for the user
|
||||||
|
// to confirm or deny the transaction.
|
||||||
|
//
|
||||||
|
// The signing protocol is defined as follows:
|
||||||
|
//
|
||||||
|
// CLA | INS | P1 | P2 | Lc | Le
|
||||||
|
// ----+-----+----+-----------------------------+-----+---
|
||||||
|
// E0 | 08 | 00 | implementation version : 00 | variable | variable
|
||||||
|
//
|
||||||
|
// Where the input is:
|
||||||
|
//
|
||||||
|
// Description | Length
|
||||||
|
// -------------------------------------------------+----------
|
||||||
|
// Number of BIP 32 derivations to perform (max 10) | 1 byte
|
||||||
|
// First derivation index (big endian) | 4 bytes
|
||||||
|
// ... | 4 bytes
|
||||||
|
// Last derivation index (big endian) | 4 bytes
|
||||||
|
// text | arbitrary
|
||||||
|
//
|
||||||
|
// And the output data is:
|
||||||
|
//
|
||||||
|
// Description | Length
|
||||||
|
// ------------+---------
|
||||||
|
// signature V | 1 byte
|
||||||
|
// signature R | 32 bytes
|
||||||
|
// signature S | 32 bytes
|
||||||
|
func (w *ledgerDriver) ledgerSignPersonalMessage(derivationPath []uint32, text []byte) ([]byte, error) {
|
||||||
|
// Flatten the derivation path into the Ledger request
|
||||||
|
path := make([]byte, 5+4*len(derivationPath))
|
||||||
|
path[0] = byte(len(derivationPath))
|
||||||
|
for i, component := range derivationPath {
|
||||||
|
binary.BigEndian.PutUint32(path[1+4*i:], component)
|
||||||
|
}
|
||||||
|
binary.BigEndian.PutUint32(path[1+4*len(derivationPath):], uint32(len(text)))
|
||||||
|
// Create the 712 message
|
||||||
|
payload := append(path, text...)
|
||||||
|
|
||||||
|
// Send the request and wait for the response
|
||||||
|
var (
|
||||||
|
reply []byte
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
// Send the message over, ensuring it's processed correctly
|
||||||
|
reply, err = w.ledgerExchange(ledgerOpSignPersonalMessage, ledgerP1InitTransactionData, 0, payload)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the Ethereum signature and do a sanity validation
|
||||||
|
if len(reply) != crypto.SignatureLength {
|
||||||
|
return nil, errors.New("reply lacks signature")
|
||||||
|
}
|
||||||
|
signature := append(reply[1:], reply[0])
|
||||||
|
return signature, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ledgerSignTypedData sends the transaction to the Ledger wallet, and waits for the user
|
||||||
|
// to confirm or deny the transaction.
|
||||||
|
//
|
||||||
|
// The typed data struct fields and values need to be sent to the Ledger first.
|
||||||
|
// See https://github.com/LedgerHQ/app-ethereum/blob/develop/doc/eip712.md.
|
||||||
|
//
|
||||||
|
// After the data is sent, the signing protocol is defined as follows:
|
||||||
|
//
|
||||||
|
// CLA | INS | P1 | P2 | Lc | Le
|
||||||
|
// ----+-----+----+-----------------------------+-----+---
|
||||||
|
// E0 | 0C | 00 | implementation version : 00 | variable | variable
|
||||||
|
//
|
||||||
|
// Where the input is:
|
||||||
|
//
|
||||||
|
// Description | Length
|
||||||
|
// -------------------------------------------------+----------
|
||||||
|
// Number of BIP 32 derivations to perform (max 10) | 1 byte
|
||||||
|
// First derivation index (big endian) | 4 bytes
|
||||||
|
// ... | 4 bytes
|
||||||
|
// Last derivation index (big endian) | 4 bytes
|
||||||
|
//
|
||||||
|
// And the output data is:
|
||||||
|
//
|
||||||
|
// Description | Length
|
||||||
|
// ------------+---------
|
||||||
|
// signature V | 1 byte
|
||||||
|
// signature R | 32 bytes
|
||||||
|
// signature S | 32 bytes
|
||||||
|
func (w *ledgerDriver) ledgerSignTypedData(derivationPath []uint32, data apitypes.TypedData) ([]byte, error) {
|
||||||
|
// Check if the EIP712Domain and primary type are present in the data
|
||||||
|
domainStruct := data.Types["EIP712Domain"]
|
||||||
|
if domainStruct == nil {
|
||||||
|
return nil, fmt.Errorf("EIP712Domain type is required")
|
||||||
|
}
|
||||||
|
primaryType := data.Types[data.PrimaryType]
|
||||||
|
if primaryType == nil {
|
||||||
|
return nil, fmt.Errorf("primary type %s not found in types", data.PrimaryType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendField is a function for sending an EIP-712 struct field name + type
|
||||||
|
sendField := func(field apitypes.Type) error {
|
||||||
|
dt, name, byteLength, arrays, err := parseType(data, field)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
typeDesc := byte(dt)
|
||||||
|
|
||||||
|
var typeName []byte
|
||||||
|
var typeSize []byte
|
||||||
|
switch dt {
|
||||||
|
case CustomType:
|
||||||
|
typeName = append([]byte{byte(len(name))}, []byte(name)...)
|
||||||
|
case IntType, UintType, FixedBytesType:
|
||||||
|
typeSize = []byte{byte(byteLength)}
|
||||||
|
typeDesc |= 0x40
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
var arrayLevels []byte
|
||||||
|
if len(arrays) > 0 {
|
||||||
|
typeDesc |= 0x80
|
||||||
|
arrayLevels = []byte{byte(len(arrays))}
|
||||||
|
for _, length := range arrays {
|
||||||
|
if length == nil {
|
||||||
|
arrayLevels = append(arrayLevels, 0)
|
||||||
|
} else {
|
||||||
|
arrayLevels = append(arrayLevels, 1, byte(*length))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
payload := []byte{typeDesc}
|
||||||
|
payload = append(payload, typeName...)
|
||||||
|
payload = append(payload, typeSize...)
|
||||||
|
payload = append(payload, arrayLevels...)
|
||||||
|
payload = append(payload, byte(len(field.Name)))
|
||||||
|
payload = append(payload, []byte(field.Name)...)
|
||||||
|
_, err = w.ledgerExchange(ledgerOpEip712SendStructDef, 0, ledgerP2StructField, payload)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendValue is a recursive function that sends the value of a field
|
||||||
|
var sendValue func(t, name string, value interface{}) error
|
||||||
|
sendValue = func(t, name string, value interface{}) error {
|
||||||
|
if value == nil {
|
||||||
|
return fmt.Errorf("nil value for field %s", name)
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(t, "]") {
|
||||||
|
a, ok := value.([]interface{})
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("expected array for field %s, got %T", name, value)
|
||||||
|
}
|
||||||
|
if _, err := w.ledgerExchange(ledgerOpEip712SendStructImpl, ledgerP1CompleteSend, ledgerP2Array, []byte{byte(len(a))}); err != nil {
|
||||||
|
return fmt.Errorf("failed to send array length: %w", err)
|
||||||
|
}
|
||||||
|
t = t[:strings.LastIndex(t, "[")]
|
||||||
|
for _, item := range a {
|
||||||
|
if err := sendValue(t, name, item); err != nil {
|
||||||
|
return fmt.Errorf("failed to send array item: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
s := data.Types[t]
|
||||||
|
if s != nil {
|
||||||
|
m, ok := value.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("expected struct for field %s, got %T", name, value)
|
||||||
|
}
|
||||||
|
for _, field := range s {
|
||||||
|
if err := sendValue(field.Type, field.Name, m[field.Name]); err != nil {
|
||||||
|
return fmt.Errorf("failed to send struct field %s: %w", field.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var enc []byte
|
||||||
|
var err error
|
||||||
|
switch v := value.(type) {
|
||||||
|
case string:
|
||||||
|
if t == "string" {
|
||||||
|
enc = []byte(v)
|
||||||
|
} else if strings.HasPrefix(v, "0x") {
|
||||||
|
enc, err = hex.DecodeString(v[2:])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to decode hex string for field %s: %w", name, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("invalid string value for field %s: %s", name, v)
|
||||||
|
}
|
||||||
|
case bool:
|
||||||
|
if v {
|
||||||
|
enc = []byte{1}
|
||||||
|
} else {
|
||||||
|
enc = []byte{0}
|
||||||
|
}
|
||||||
|
case float64:
|
||||||
|
enc = new(big.Int).SetInt64(int64(v)).Bytes()
|
||||||
|
case *math.HexOrDecimal256:
|
||||||
|
if v == nil {
|
||||||
|
return fmt.Errorf("nil value for field %s", name)
|
||||||
|
}
|
||||||
|
h := big.Int(*v)
|
||||||
|
enc = (&h).Bytes()
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported type for field %s: %T", name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk := 255
|
||||||
|
payload := binary.BigEndian.AppendUint16([]byte{}, uint16(len(enc)))
|
||||||
|
payload = append(payload, enc...)
|
||||||
|
for len(payload) > 0 {
|
||||||
|
p1 := ledgerP1PartialSend
|
||||||
|
if chunk >= len(payload) {
|
||||||
|
chunk = len(payload)
|
||||||
|
p1 = ledgerP1CompleteSend
|
||||||
|
}
|
||||||
|
if _, err := w.ledgerExchange(ledgerOpEip712SendStructImpl, p1, ledgerP2StructField, payload[:chunk]); err != nil {
|
||||||
|
return fmt.Errorf("failed to send field %s: %w", name, err)
|
||||||
|
}
|
||||||
|
payload = payload[chunk:]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// first send all the EIP-712 struct definitions
|
||||||
|
for name, fields := range data.Types {
|
||||||
|
_, err := w.ledgerExchange(ledgerOpEip712SendStructDef, 0, ledgerP2StructName, []byte(name))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to send type name %s: %w", name, err)
|
||||||
|
}
|
||||||
|
for _, field := range fields {
|
||||||
|
if err := sendField(field); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to send field %s: %w", field.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the EIP-712 domain field values
|
||||||
|
if _, err := w.ledgerExchange(ledgerOpEip712SendStructImpl, ledgerP1CompleteSend, ledgerP2RootStruct, []byte("EIP712Domain")); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to send domain type name: %w", err)
|
||||||
|
}
|
||||||
|
if err := sendValue("EIP712Domain", "domain", data.Domain.Map()); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to send domain fields: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the message field values
|
||||||
|
if _, err := w.ledgerExchange(ledgerOpEip712SendStructImpl, ledgerP1CompleteSend, ledgerP2RootStruct, []byte(data.PrimaryType)); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to send primary type name: %w", err)
|
||||||
|
}
|
||||||
|
if err := sendValue(data.PrimaryType, "message", data.Message); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to send primary type fields: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flatten the derivation path into the Ledger request
|
||||||
|
path := make([]byte, 1+4*len(derivationPath))
|
||||||
|
path[0] = byte(len(derivationPath))
|
||||||
|
for i, component := range derivationPath {
|
||||||
|
binary.BigEndian.PutUint32(path[1+4*i:], component)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the message over, ensuring it's processed correctly
|
||||||
|
reply, err := w.ledgerExchange(ledgerOpSignTypedMessage, 0, ledgerP2FullImplementation, path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the Ethereum signature and do a sanity validation
|
||||||
|
if len(reply) != crypto.SignatureLength {
|
||||||
|
return nil, fmt.Errorf("invalid signature length: %d", len(reply))
|
||||||
|
}
|
||||||
|
signature := append(reply[1:], reply[0])
|
||||||
|
return signature, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ledgerExchange performs a data exchange with the Ledger wallet, sending it a
|
// ledgerExchange performs a data exchange with the Ledger wallet, sending it a
|
||||||
// message and retrieving the response.
|
// message and retrieving the response.
|
||||||
//
|
//
|
||||||
|
|
@ -508,6 +861,16 @@ func (w *ledgerDriver) ledgerSignTypedMessage(derivationPath []uint32, domainHas
|
||||||
// APDU length | 1 byte
|
// APDU length | 1 byte
|
||||||
// Optional APDU data | arbitrary
|
// Optional APDU data | arbitrary
|
||||||
func (w *ledgerDriver) ledgerExchange(opcode ledgerOpcode, p1 ledgerParam1, p2 ledgerParam2, data []byte) ([]byte, error) {
|
func (w *ledgerDriver) ledgerExchange(opcode ledgerOpcode, p1 ledgerParam1, p2 ledgerParam2, data []byte) ([]byte, error) {
|
||||||
|
for i := 1; ; i++ {
|
||||||
|
res, err := w._ledgerExchange(opcode, p1, p2, data)
|
||||||
|
// on failure, try the exchange 3 times in total
|
||||||
|
if err == nil || i == 3 {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *ledgerDriver) _ledgerExchange(opcode ledgerOpcode, p1 ledgerParam1, p2 ledgerParam2, data []byte) ([]byte, error) {
|
||||||
// Construct the message payload, possibly split into multiple chunks
|
// Construct the message payload, possibly split into multiple chunks
|
||||||
apdu := make([]byte, 2, 7+len(data))
|
apdu := make([]byte, 2, 7+len(data))
|
||||||
|
|
||||||
|
|
@ -569,5 +932,16 @@ func (w *ledgerDriver) ledgerExchange(opcode ledgerOpcode, p1 ledgerParam1, p2 l
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(reply) < 2 {
|
||||||
|
return nil, errLedgerInvalidStatus
|
||||||
|
}
|
||||||
|
status := ledgerStatus(binary.BigEndian.Uint16(reply[len(reply)-2:]))
|
||||||
|
if status != ledgerStatusNormalEnd {
|
||||||
|
s := ledgerStatuses[status]
|
||||||
|
if s == "" {
|
||||||
|
s = "unknown error"
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("%w: 0x%s (%s)", errLedgerInvalidStatus, strconv.FormatUint(uint64(status), 16), s)
|
||||||
|
}
|
||||||
return reply[:len(reply)-2], nil
|
return reply[:len(reply)-2], nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/accounts/usbwallet/trezor"
|
"github.com/ethereum/go-ethereum/accounts/usbwallet/trezor"
|
||||||
|
|
@ -34,31 +35,34 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
||||||
|
pin "github.com/reserve-protocol/trezor"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrTrezorPINNeeded is returned if opening the trezor requires a PIN code. In
|
|
||||||
// this case, the calling application should display a pinpad and send back the
|
|
||||||
// encoded passphrase.
|
|
||||||
var ErrTrezorPINNeeded = errors.New("trezor: pin needed")
|
|
||||||
|
|
||||||
// ErrTrezorPassphraseNeeded is returned if opening the trezor requires a passphrase
|
|
||||||
var ErrTrezorPassphraseNeeded = errors.New("trezor: passphrase needed")
|
|
||||||
|
|
||||||
// errTrezorReplyInvalidHeader is the error message returned by a Trezor data exchange
|
// errTrezorReplyInvalidHeader is the error message returned by a Trezor data exchange
|
||||||
// if the device replies with a mismatching header. This usually means the device
|
// if the device replies with a mismatching header. This usually means the device
|
||||||
// is in browser mode.
|
// is in browser mode.
|
||||||
var errTrezorReplyInvalidHeader = errors.New("trezor: invalid reply header")
|
var errTrezorReplyInvalidHeader = errors.New("trezor: invalid reply header")
|
||||||
|
|
||||||
|
type TrezorFailure struct {
|
||||||
|
*trezor.Failure
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface for the TrezorFailure type, returning
|
||||||
|
// a formatted error message containing the failure reason.
|
||||||
|
func (f *TrezorFailure) Error() string {
|
||||||
|
return fmt.Sprintf("trezor: %s", f.GetMessage())
|
||||||
|
}
|
||||||
|
|
||||||
// trezorDriver implements the communication with a Trezor hardware wallet.
|
// trezorDriver implements the communication with a Trezor hardware wallet.
|
||||||
type trezorDriver struct {
|
type trezorDriver struct {
|
||||||
device io.ReadWriter // USB device connection to communicate through
|
device io.ReadWriter // USB device connection to communicate through
|
||||||
version [3]uint32 // Current version of the Trezor firmware
|
version [3]uint32 // Current version of the Trezor firmware
|
||||||
label string // Current textual label of the Trezor device
|
label string // Current textual label of the Trezor device
|
||||||
pinwait bool // Flags whether the device is waiting for PIN entry
|
passphrase string
|
||||||
passphrasewait bool // Flags whether the device is waiting for passphrase entry
|
failure error // Any failure that would make the device unusable
|
||||||
failure error // Any failure that would make the device unusable
|
log log.Logger // Contextual logger to tag the trezor with its id
|
||||||
log log.Logger // Contextual logger to tag the trezor with its id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// newTrezorDriver creates a new instance of a Trezor USB protocol driver.
|
// newTrezorDriver creates a new instance of a Trezor USB protocol driver.
|
||||||
|
|
@ -77,87 +81,32 @@ func (w *trezorDriver) Status() (string, error) {
|
||||||
if w.device == nil {
|
if w.device == nil {
|
||||||
return "Closed", w.failure
|
return "Closed", w.failure
|
||||||
}
|
}
|
||||||
if w.pinwait {
|
|
||||||
return fmt.Sprintf("Trezor v%d.%d.%d '%s' waiting for PIN", w.version[0], w.version[1], w.version[2], w.label), w.failure
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("Trezor v%d.%d.%d '%s' online", w.version[0], w.version[1], w.version[2], w.label), w.failure
|
return fmt.Sprintf("Trezor v%d.%d.%d '%s' online", w.version[0], w.version[1], w.version[2], w.label), w.failure
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open implements usbwallet.driver, attempting to initialize the connection to
|
// Open implements usbwallet.driver, attempting to initialize the connection to
|
||||||
// the Trezor hardware wallet. Initializing the Trezor is a two or three phase operation:
|
// the Trezor hardware wallet.
|
||||||
// - The first phase is to initialize the connection and read the wallet's
|
|
||||||
// features. This phase is invoked if the provided passphrase is empty. The
|
|
||||||
// device will display the pinpad as a result and will return an appropriate
|
|
||||||
// error to notify the user that a second open phase is needed.
|
|
||||||
// - The second phase is to unlock access to the Trezor, which is done by the
|
|
||||||
// user actually providing a passphrase mapping a keyboard keypad to the pin
|
|
||||||
// number of the user (shuffled according to the pinpad displayed).
|
|
||||||
// - If needed the device will ask for passphrase which will require calling
|
|
||||||
// open again with the actual passphrase (3rd phase)
|
|
||||||
func (w *trezorDriver) Open(device io.ReadWriter, passphrase string) error {
|
func (w *trezorDriver) Open(device io.ReadWriter, passphrase string) error {
|
||||||
w.device, w.failure = device, nil
|
w.device, w.passphrase, w.failure = device, passphrase, nil
|
||||||
|
|
||||||
// If phase 1 is requested, init the connection and wait for user callback
|
if _, err := w.trezorExchange(&trezor.EndSession{}, new(trezor.Success)); err != nil {
|
||||||
if passphrase == "" && !w.passphrasewait {
|
return err
|
||||||
// If we're already waiting for a PIN entry, insta-return
|
|
||||||
if w.pinwait {
|
|
||||||
return ErrTrezorPINNeeded
|
|
||||||
}
|
|
||||||
// Initialize a connection to the device
|
|
||||||
features := new(trezor.Features)
|
|
||||||
if _, err := w.trezorExchange(&trezor.Initialize{}, features); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.version = [3]uint32{features.GetMajorVersion(), features.GetMinorVersion(), features.GetPatchVersion()}
|
|
||||||
w.label = features.GetLabel()
|
|
||||||
|
|
||||||
// Do a manual ping, forcing the device to ask for its PIN and Passphrase
|
|
||||||
askPin := true
|
|
||||||
askPassphrase := true
|
|
||||||
res, err := w.trezorExchange(&trezor.Ping{PinProtection: &askPin, PassphraseProtection: &askPassphrase}, new(trezor.PinMatrixRequest), new(trezor.PassphraseRequest), new(trezor.Success))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Only return the PIN request if the device wasn't unlocked until now
|
|
||||||
switch res {
|
|
||||||
case 0:
|
|
||||||
w.pinwait = true
|
|
||||||
return ErrTrezorPINNeeded
|
|
||||||
case 1:
|
|
||||||
w.pinwait = false
|
|
||||||
w.passphrasewait = true
|
|
||||||
return ErrTrezorPassphraseNeeded
|
|
||||||
case 2:
|
|
||||||
return nil // responded with trezor.Success
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Phase 2 requested with actual PIN entry
|
|
||||||
if w.pinwait {
|
|
||||||
w.pinwait = false
|
|
||||||
res, err := w.trezorExchange(&trezor.PinMatrixAck{Pin: &passphrase}, new(trezor.Success), new(trezor.PassphraseRequest))
|
|
||||||
if err != nil {
|
|
||||||
w.failure = err
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if res == 1 {
|
|
||||||
w.passphrasewait = true
|
|
||||||
return ErrTrezorPassphraseNeeded
|
|
||||||
}
|
|
||||||
} else if w.passphrasewait {
|
|
||||||
w.passphrasewait = false
|
|
||||||
if _, err := w.trezorExchange(&trezor.PassphraseAck{Passphrase: &passphrase}, new(trezor.Success)); err != nil {
|
|
||||||
w.failure = err
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
features := new(trezor.Features)
|
||||||
|
if _, err := w.trezorExchange(&trezor.Initialize{}, features); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.version = [3]uint32{features.GetMajorVersion(), features.GetMinorVersion(), features.GetPatchVersion()}
|
||||||
|
w.label = features.GetLabel()
|
||||||
|
|
||||||
|
return w.Heartbeat()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close implements usbwallet.driver, cleaning up and metadata maintained within
|
// Close implements usbwallet.driver, cleaning up and metadata maintained within
|
||||||
// the Trezor driver.
|
// the Trezor driver.
|
||||||
func (w *trezorDriver) Close() error {
|
func (w *trezorDriver) Close() error {
|
||||||
w.version, w.label, w.pinwait = [3]uint32{}, "", false
|
w.version, w.label = [3]uint32{}, ""
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -186,8 +135,236 @@ func (w *trezorDriver) SignTx(path accounts.DerivationPath, tx *types.Transactio
|
||||||
return w.trezorSign(path, tx, chainID)
|
return w.trezorSign(path, tx, chainID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *trezorDriver) SignTypedMessage(path accounts.DerivationPath, domainHash []byte, messageHash []byte) ([]byte, error) {
|
func (w *trezorDriver) SignTypedHash(path accounts.DerivationPath, domainHash []byte, messageHash []byte) ([]byte, error) {
|
||||||
return nil, accounts.ErrNotSupported
|
if w.device == nil {
|
||||||
|
return nil, accounts.ErrWalletClosed
|
||||||
|
}
|
||||||
|
response := new(trezor.EthereumTypedDataSignature)
|
||||||
|
_, err := w.trezorExchange(&trezor.EthereumSignTypedHash{
|
||||||
|
AddressN: path,
|
||||||
|
DomainSeparatorHash: domainHash,
|
||||||
|
MessageHash: messageHash,
|
||||||
|
}, response)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return response.Signature, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *trezorDriver) SignText(path accounts.DerivationPath, text []byte) ([]byte, error) {
|
||||||
|
if w.device == nil {
|
||||||
|
return nil, accounts.ErrWalletClosed
|
||||||
|
}
|
||||||
|
response := new(trezor.EthereumMessageSignature)
|
||||||
|
_, err := w.trezorExchange(&trezor.EthereumSignMessage{
|
||||||
|
AddressN: path,
|
||||||
|
Message: text,
|
||||||
|
}, response)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return response.Signature, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *trezorDriver) SignedTypedData(path accounts.DerivationPath, data apitypes.TypedData) ([]byte, error) {
|
||||||
|
if w.device == nil {
|
||||||
|
return nil, accounts.ErrWalletClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
_, hashes, err := apitypes.TypedDataAndHash(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("trezor: error hashing typed data: %w", err)
|
||||||
|
}
|
||||||
|
domainHash, messageHash := hashes[2:34], hashes[34:66]
|
||||||
|
if w.version[0] == 1 {
|
||||||
|
// legacy Trezor devices don't support typed data; fallback to hash signing:
|
||||||
|
return w.SignTypedHash(path, []byte(domainHash), []byte(messageHash))
|
||||||
|
}
|
||||||
|
|
||||||
|
if w.version[0] == 2 && (w.version[1] < 9 || (w.version[1] == 9 && w.version[2] == 0)) {
|
||||||
|
// ShowMessageHash was introduced in Trezor firmware v2.9.1
|
||||||
|
return nil, fmt.Errorf("trezor: typed data signing requires firmware v2.9.1 or newer")
|
||||||
|
}
|
||||||
|
|
||||||
|
signature := new(trezor.EthereumTypedDataSignature)
|
||||||
|
structRequest := new(trezor.EthereumTypedDataStructRequest)
|
||||||
|
valueRequest := new(trezor.EthereumTypedDataValueRequest)
|
||||||
|
var req proto.Message = &trezor.EthereumSignTypedData{
|
||||||
|
AddressN: path,
|
||||||
|
PrimaryType: &data.PrimaryType,
|
||||||
|
ShowMessageHash: []byte(messageHash),
|
||||||
|
}
|
||||||
|
nestedArray := false
|
||||||
|
for {
|
||||||
|
n, err := w.trezorExchange(req, signature, structRequest, valueRequest)
|
||||||
|
if err != nil {
|
||||||
|
var trezorFailure *TrezorFailure
|
||||||
|
if nestedArray && errors.As(err, &trezorFailure) &&
|
||||||
|
trezorFailure.Code != nil && *trezorFailure.Code == trezor.Failure_Failure_FirmwareError {
|
||||||
|
return nil, fmt.Errorf("trezor: nested arrays are not supported by this firmware version: %w", err)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nestedArray = false
|
||||||
|
switch n {
|
||||||
|
case 0:
|
||||||
|
// No additional data needed, return the signature
|
||||||
|
return signature.Signature, nil
|
||||||
|
case 1:
|
||||||
|
fields := data.Types[structRequest.GetName()]
|
||||||
|
if len(fields) == 0 {
|
||||||
|
return nil, fmt.Errorf("trezor: no fields for struct %s", structRequest.GetName())
|
||||||
|
}
|
||||||
|
ack := &trezor.EthereumTypedDataStructAck{
|
||||||
|
Members: make([]*trezor.EthereumTypedDataStructAck_EthereumStructMember, len(fields)),
|
||||||
|
}
|
||||||
|
for i, field := range fields {
|
||||||
|
dt, name, byteLength, arrays, err := parseType(data, field)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ubyteLength := uint32(byteLength)
|
||||||
|
t := &trezor.EthereumTypedDataStructAck_EthereumFieldType{}
|
||||||
|
inner := t
|
||||||
|
for i := len(arrays) - 1; i >= 0; i-- {
|
||||||
|
dataType := trezor.EthereumTypedDataStructAck_ARRAY
|
||||||
|
inner.DataType = &dataType
|
||||||
|
if arrays[i] != nil {
|
||||||
|
length := uint32(*arrays[i])
|
||||||
|
inner.Size = &length
|
||||||
|
}
|
||||||
|
inner.EntryType = &trezor.EthereumTypedDataStructAck_EthereumFieldType{}
|
||||||
|
inner = inner.EntryType
|
||||||
|
}
|
||||||
|
var dataType trezor.EthereumTypedDataStructAck_EthereumDataType
|
||||||
|
switch dt {
|
||||||
|
case CustomType:
|
||||||
|
inner.StructName = &name
|
||||||
|
dataType = trezor.EthereumTypedDataStructAck_STRUCT
|
||||||
|
members := uint32(len(data.Types[name]))
|
||||||
|
inner.Size = &members
|
||||||
|
case IntType:
|
||||||
|
dataType = trezor.EthereumTypedDataStructAck_INT
|
||||||
|
inner.Size = &ubyteLength
|
||||||
|
case UintType:
|
||||||
|
dataType = trezor.EthereumTypedDataStructAck_UINT
|
||||||
|
inner.Size = &ubyteLength
|
||||||
|
case AddressType:
|
||||||
|
dataType = trezor.EthereumTypedDataStructAck_ADDRESS
|
||||||
|
case BoolType:
|
||||||
|
dataType = trezor.EthereumTypedDataStructAck_BOOL
|
||||||
|
case StringType:
|
||||||
|
dataType = trezor.EthereumTypedDataStructAck_STRING
|
||||||
|
case FixedBytesType:
|
||||||
|
dataType = trezor.EthereumTypedDataStructAck_BYTES
|
||||||
|
inner.Size = &ubyteLength
|
||||||
|
case BytesType:
|
||||||
|
dataType = trezor.EthereumTypedDataStructAck_BYTES
|
||||||
|
}
|
||||||
|
inner.DataType = &dataType
|
||||||
|
ack.Members[i] = &trezor.EthereumTypedDataStructAck_EthereumStructMember{
|
||||||
|
Name: &field.Name,
|
||||||
|
Type: t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req = ack
|
||||||
|
case 2:
|
||||||
|
structType := data.Types[data.PrimaryType]
|
||||||
|
structValue := data.Message
|
||||||
|
if valueRequest.MemberPath[0] == 0 {
|
||||||
|
// populate with domain info
|
||||||
|
structType = data.Types["EIP712Domain"]
|
||||||
|
structValue = data.Domain.Map()
|
||||||
|
}
|
||||||
|
var value []byte
|
||||||
|
for i := 1; i < len(valueRequest.MemberPath); i++ {
|
||||||
|
p := valueRequest.MemberPath[i]
|
||||||
|
if structType == nil {
|
||||||
|
return nil, fmt.Errorf("trezor: no struct type for path %v", path)
|
||||||
|
}
|
||||||
|
if int(p) >= len(structType) {
|
||||||
|
return nil, fmt.Errorf("trezor: invalid field index %d for struct %s", p, structRequest.GetName())
|
||||||
|
}
|
||||||
|
field := structType[p]
|
||||||
|
nextValue := structValue[field.Name]
|
||||||
|
dt, name, byteLength, arrays, err := parseType(data, field)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(arrays) > 1 {
|
||||||
|
nestedArray = true
|
||||||
|
}
|
||||||
|
for j := 0; j < len(arrays) && i < len(valueRequest.MemberPath)-1; i, j = i+1, j+1 {
|
||||||
|
k := reflect.TypeOf(nextValue).Kind()
|
||||||
|
if !(k == reflect.Array || k == reflect.Slice) {
|
||||||
|
return nil, fmt.Errorf("trezor: expected array at path %v, got %T", valueRequest.MemberPath[:i+1], nextValue)
|
||||||
|
}
|
||||||
|
a := reflect.ValueOf(nextValue)
|
||||||
|
p = valueRequest.MemberPath[i+1]
|
||||||
|
if int(p) >= a.Len() {
|
||||||
|
return nil, fmt.Errorf("trezor: invalid array index %d for path %v", p, valueRequest.MemberPath[:i+1])
|
||||||
|
}
|
||||||
|
nextValue = a.Index(int(p)).Interface()
|
||||||
|
}
|
||||||
|
k := reflect.TypeOf(nextValue).Kind()
|
||||||
|
if i < len(valueRequest.MemberPath)-1 {
|
||||||
|
if reflect.TypeOf(nextValue).Kind() != reflect.Map {
|
||||||
|
return nil, fmt.Errorf("trezor: expected map at path %v, got %T", valueRequest.MemberPath[:i+1], nextValue)
|
||||||
|
}
|
||||||
|
structType = data.Types[name]
|
||||||
|
structValue = nextValue.(apitypes.TypedDataMessage)
|
||||||
|
} else if k == reflect.Array || k == reflect.Slice {
|
||||||
|
// Array value, return length as uint16
|
||||||
|
value = binary.BigEndian.AppendUint16([]byte{}, uint16(reflect.ValueOf(nextValue).Len()))
|
||||||
|
} else {
|
||||||
|
// Last value, encode it as a primitive value
|
||||||
|
switch dt {
|
||||||
|
case CustomType:
|
||||||
|
return nil, fmt.Errorf("trezor: cannot encode custom type %s at path %v", name, valueRequest.MemberPath[:i+1])
|
||||||
|
case IntType, UintType, AddressType, FixedBytesType:
|
||||||
|
if str, ok := nextValue.(string); ok {
|
||||||
|
value = common.FromHex(str)
|
||||||
|
} else if f, ok := nextValue.(float64); ok {
|
||||||
|
value = new(big.Int).SetInt64(int64(f)).Bytes()
|
||||||
|
}
|
||||||
|
if len(value) > byteLength {
|
||||||
|
return nil, fmt.Errorf("trezor: value at path %v is too long (%d bytes, expected %d)", valueRequest.MemberPath[:i+1], len(value), byteLength)
|
||||||
|
}
|
||||||
|
for len(value) < byteLength {
|
||||||
|
value = append([]byte{0}, value...)
|
||||||
|
}
|
||||||
|
case BoolType:
|
||||||
|
if b, ok := nextValue.(bool); ok {
|
||||||
|
if b {
|
||||||
|
value = []byte{1}
|
||||||
|
} else {
|
||||||
|
value = []byte{0}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("trezor: expected bool at path %v, got %T", valueRequest.MemberPath[:i+1], nextValue)
|
||||||
|
}
|
||||||
|
case StringType:
|
||||||
|
if str, ok := nextValue.(string); ok {
|
||||||
|
value = []byte(str)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("trezor: expected string at path %v, got %T", valueRequest.MemberPath[:i+1], nextValue)
|
||||||
|
}
|
||||||
|
case BytesType:
|
||||||
|
if str, ok := nextValue.(string); ok {
|
||||||
|
value = common.FromHex(str)
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("trezor: expected bytes at path %v, got %T", valueRequest.MemberPath[:i+1], nextValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req = &trezor.EthereumTypedDataValueAck{
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("trezor: unexpected reply index %d", n)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// trezorDerive sends a derivation request to the Trezor device and returns the
|
// trezorDerive sends a derivation request to the Trezor device and returns the
|
||||||
|
|
@ -197,10 +374,7 @@ func (w *trezorDriver) trezorDerive(derivationPath []uint32) (common.Address, er
|
||||||
if _, err := w.trezorExchange(&trezor.EthereumGetAddress{AddressN: derivationPath}, address); err != nil {
|
if _, err := w.trezorExchange(&trezor.EthereumGetAddress{AddressN: derivationPath}, address); err != nil {
|
||||||
return common.Address{}, err
|
return common.Address{}, err
|
||||||
}
|
}
|
||||||
if addr := address.GetAddressBin(); len(addr) > 0 { // Older firmwares use binary formats
|
if addr := address.GetAddress(); len(addr) > 0 {
|
||||||
return common.BytesToAddress(addr), nil
|
|
||||||
}
|
|
||||||
if addr := address.GetAddressHex(); len(addr) > 0 { // Newer firmwares use hexadecimal formats
|
|
||||||
return common.HexToAddress(addr), nil
|
return common.HexToAddress(addr), nil
|
||||||
}
|
}
|
||||||
return common.Address{}, errors.New("missing derived address")
|
return common.Address{}, errors.New("missing derived address")
|
||||||
|
|
@ -224,8 +398,7 @@ func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction
|
||||||
if to := tx.To(); to != nil {
|
if to := tx.To(); to != nil {
|
||||||
// Non contract deploy, set recipient explicitly
|
// Non contract deploy, set recipient explicitly
|
||||||
hex := to.Hex()
|
hex := to.Hex()
|
||||||
request.ToHex = &hex // Newer firmwares (old will ignore)
|
request.To = &hex
|
||||||
request.ToBin = (*to)[:] // Older firmwares (new will ignore)
|
|
||||||
}
|
}
|
||||||
if length > 1024 { // Send the data chunked if that was requested
|
if length > 1024 { // Send the data chunked if that was requested
|
||||||
request.DataInitialChunk, data = data[:1024], data[1024:]
|
request.DataInitialChunk, data = data[:1024], data[1024:]
|
||||||
|
|
@ -233,7 +406,7 @@ func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction
|
||||||
request.DataInitialChunk, data = data, nil
|
request.DataInitialChunk, data = data, nil
|
||||||
}
|
}
|
||||||
if chainID != nil { // EIP-155 transaction, set chain ID explicitly (only 32 bit is supported!?)
|
if chainID != nil { // EIP-155 transaction, set chain ID explicitly (only 32 bit is supported!?)
|
||||||
id := uint32(chainID.Int64())
|
id := chainID.Uint64()
|
||||||
request.ChainId = &id
|
request.ChainId = &id
|
||||||
}
|
}
|
||||||
// Send the initiation message and stream content until a signature is returned
|
// Send the initiation message and stream content until a signature is returned
|
||||||
|
|
@ -250,11 +423,7 @@ func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Extract the Ethereum signature and do a sanity validation
|
// Extract the Ethereum signature and do a sanity validation
|
||||||
if len(response.GetSignatureR()) == 0 || len(response.GetSignatureS()) == 0 {
|
if len(response.GetSignatureR()) == 0 || len(response.GetSignatureS()) == 0 || response.GetSignatureV() == 0 {
|
||||||
return common.Address{}, nil, errors.New("reply lacks signature")
|
|
||||||
} else if response.GetSignatureV() == 0 && int(chainID.Int64()) <= (math.MaxUint32-36)/2 {
|
|
||||||
// for chainId >= (MaxUint32-36)/2, Trezor returns signature bit only
|
|
||||||
// https://github.com/trezor/trezor-mcu/pull/399
|
|
||||||
return common.Address{}, nil, errors.New("reply lacks signature")
|
return common.Address{}, nil, errors.New("reply lacks signature")
|
||||||
}
|
}
|
||||||
signature := append(append(response.GetSignatureR(), response.GetSignatureS()...), byte(response.GetSignatureV()))
|
signature := append(append(response.GetSignatureR(), response.GetSignatureS()...), byte(response.GetSignatureV()))
|
||||||
|
|
@ -361,12 +530,22 @@ func (w *trezorDriver) trezorExchange(req proto.Message, results ...proto.Messag
|
||||||
if err := proto.Unmarshal(reply, failure); err != nil {
|
if err := proto.Unmarshal(reply, failure); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return 0, errors.New("trezor: " + failure.GetMessage())
|
return 0, &TrezorFailure{Failure: failure}
|
||||||
}
|
}
|
||||||
if kind == uint16(trezor.MessageType_MessageType_ButtonRequest) {
|
if kind == uint16(trezor.MessageType_MessageType_ButtonRequest) {
|
||||||
// Trezor is waiting for user confirmation, ack and wait for the next message
|
// Trezor is waiting for user confirmation, ack and wait for the next message
|
||||||
return w.trezorExchange(&trezor.ButtonAck{}, results...)
|
return w.trezorExchange(&trezor.ButtonAck{}, results...)
|
||||||
}
|
}
|
||||||
|
if kind == uint16(trezor.MessageType_MessageType_PinMatrixRequest) {
|
||||||
|
p, err := pin.GetPIN("Please enter your Trezor PIN")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return w.trezorExchange(&trezor.PinMatrixAck{Pin: &p}, results...)
|
||||||
|
}
|
||||||
|
if kind == uint16(trezor.MessageType_MessageType_PassphraseRequest) {
|
||||||
|
return w.trezorExchange(&trezor.PassphraseAck{Passphrase: &w.passphrase}, results...)
|
||||||
|
}
|
||||||
for i, res := range results {
|
for i, res := range results {
|
||||||
if trezor.Type(res) == kind {
|
if trezor.Type(res) == kind {
|
||||||
return i, proto.Unmarshal(reply, res)
|
return i, proto.Unmarshal(reply, res)
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,18 +1,26 @@
|
||||||
// This file originates from the SatoshiLabs Trezor `common` repository at:
|
// This file originates from the SatoshiLabs Trezor `common` repository at:
|
||||||
// https://github.com/trezor/trezor-common/blob/master/protob/messages-common.proto
|
// https://github.com/trezor/trezor-common/blob/master/protob/messages-common.proto
|
||||||
// dated 28.05.2019, commit 893fd219d4a01bcffa0cd9cfa631856371ec5aa9.
|
// dated 30.06.2025, commit 421b45d4677f2499234692b0f54010bc45b3ae5f.
|
||||||
|
|
||||||
syntax = "proto2";
|
syntax = "proto2";
|
||||||
package hw.trezor.messages.common;
|
package hw.trezor.messages.common;
|
||||||
|
|
||||||
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||||
|
|
||||||
|
// Sugar for easier handling in Java
|
||||||
|
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
||||||
|
option java_outer_classname = "TrezorMessageCommon";
|
||||||
|
|
||||||
|
import "options.proto";
|
||||||
|
|
||||||
|
option (include_in_bitcoin_only) = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Response: Success of the previous request
|
* Response: Success of the previous request
|
||||||
* @end
|
* @end
|
||||||
*/
|
*/
|
||||||
message Success {
|
message Success {
|
||||||
optional string message = 1; // human readable description of action or request-specific payload
|
optional string message = 1 [default=""]; // human readable description of action or request-specific payload
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -20,23 +28,29 @@ message Success {
|
||||||
* @end
|
* @end
|
||||||
*/
|
*/
|
||||||
message Failure {
|
message Failure {
|
||||||
optional FailureType code = 1; // computer-readable definition of the error state
|
optional FailureType code = 1; // computer-readable definition of the error state
|
||||||
optional string message = 2; // human-readable message of the error state
|
optional string message = 2; // human-readable message of the error state
|
||||||
enum FailureType {
|
enum FailureType {
|
||||||
Failure_UnexpectedMessage = 1;
|
Failure_UnexpectedMessage = 1;
|
||||||
Failure_ButtonExpected = 2;
|
Failure_ButtonExpected = 2;
|
||||||
Failure_DataError = 3;
|
Failure_DataError = 3;
|
||||||
Failure_ActionCancelled = 4;
|
Failure_ActionCancelled = 4;
|
||||||
Failure_PinExpected = 5;
|
Failure_PinExpected = 5;
|
||||||
Failure_PinCancelled = 6;
|
Failure_PinCancelled = 6;
|
||||||
Failure_PinInvalid = 7;
|
Failure_PinInvalid = 7;
|
||||||
Failure_InvalidSignature = 8;
|
Failure_InvalidSignature = 8;
|
||||||
Failure_ProcessError = 9;
|
Failure_ProcessError = 9;
|
||||||
Failure_NotEnoughFunds = 10;
|
Failure_NotEnoughFunds = 10;
|
||||||
Failure_NotInitialized = 11;
|
Failure_NotInitialized = 11;
|
||||||
Failure_PinMismatch = 12;
|
Failure_PinMismatch = 12;
|
||||||
Failure_FirmwareError = 99;
|
Failure_WipeCodeMismatch = 13;
|
||||||
}
|
Failure_InvalidSession = 14;
|
||||||
|
Failure_Busy = 15;
|
||||||
|
Failure_ThpUnallocatedSession = 16;
|
||||||
|
Failure_InvalidProtocol = 17;
|
||||||
|
Failure_BufferError = 18;
|
||||||
|
Failure_FirmwareError = 99;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -45,28 +59,39 @@ message Failure {
|
||||||
* @next ButtonAck
|
* @next ButtonAck
|
||||||
*/
|
*/
|
||||||
message ButtonRequest {
|
message ButtonRequest {
|
||||||
optional ButtonRequestType code = 1;
|
optional ButtonRequestType code = 1; // enum identifier of the screen (deprecated)
|
||||||
optional string data = 2;
|
optional uint32 pages = 2; // if the screen is paginated, number of pages
|
||||||
/**
|
|
||||||
* Type of button request
|
// this existed briefly: https://github.com/trezor/trezor-firmware/commit/1012ee8497b241e8ca559e386d936fa549bc0357
|
||||||
*/
|
reserved 3;
|
||||||
enum ButtonRequestType {
|
|
||||||
ButtonRequest_Other = 1;
|
optional string name = 4; // name of the screen
|
||||||
ButtonRequest_FeeOverThreshold = 2;
|
|
||||||
ButtonRequest_ConfirmOutput = 3;
|
/**
|
||||||
ButtonRequest_ResetDevice = 4;
|
* Type of button request
|
||||||
ButtonRequest_ConfirmWord = 5;
|
*/
|
||||||
ButtonRequest_WipeDevice = 6;
|
enum ButtonRequestType {
|
||||||
ButtonRequest_ProtectCall = 7;
|
ButtonRequest_Other = 1;
|
||||||
ButtonRequest_SignTx = 8;
|
ButtonRequest_FeeOverThreshold = 2;
|
||||||
ButtonRequest_FirmwareCheck = 9;
|
ButtonRequest_ConfirmOutput = 3;
|
||||||
ButtonRequest_Address = 10;
|
ButtonRequest_ResetDevice = 4;
|
||||||
ButtonRequest_PublicKey = 11;
|
ButtonRequest_ConfirmWord = 5;
|
||||||
ButtonRequest_MnemonicWordCount = 12;
|
ButtonRequest_WipeDevice = 6;
|
||||||
ButtonRequest_MnemonicInput = 13;
|
ButtonRequest_ProtectCall = 7;
|
||||||
ButtonRequest_PassphraseType = 14;
|
ButtonRequest_SignTx = 8;
|
||||||
ButtonRequest_UnknownDerivationPath = 15;
|
ButtonRequest_FirmwareCheck = 9;
|
||||||
}
|
ButtonRequest_Address = 10;
|
||||||
|
ButtonRequest_PublicKey = 11;
|
||||||
|
ButtonRequest_MnemonicWordCount = 12;
|
||||||
|
ButtonRequest_MnemonicInput = 13;
|
||||||
|
_Deprecated_ButtonRequest_PassphraseType = 14 [deprecated=true];
|
||||||
|
ButtonRequest_UnknownDerivationPath = 15;
|
||||||
|
ButtonRequest_RecoveryHomepage = 16;
|
||||||
|
ButtonRequest_Success = 17;
|
||||||
|
ButtonRequest_Warning = 18;
|
||||||
|
ButtonRequest_PassphraseEntry = 19;
|
||||||
|
ButtonRequest_PinEntry = 20;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -82,15 +107,17 @@ message ButtonAck {
|
||||||
* @next PinMatrixAck
|
* @next PinMatrixAck
|
||||||
*/
|
*/
|
||||||
message PinMatrixRequest {
|
message PinMatrixRequest {
|
||||||
optional PinMatrixRequestType type = 1;
|
optional PinMatrixRequestType type = 1;
|
||||||
/**
|
/**
|
||||||
* Type of PIN request
|
* Type of PIN request
|
||||||
*/
|
*/
|
||||||
enum PinMatrixRequestType {
|
enum PinMatrixRequestType {
|
||||||
PinMatrixRequestType_Current = 1;
|
PinMatrixRequestType_Current = 1;
|
||||||
PinMatrixRequestType_NewFirst = 2;
|
PinMatrixRequestType_NewFirst = 2;
|
||||||
PinMatrixRequestType_NewSecond = 3;
|
PinMatrixRequestType_NewSecond = 3;
|
||||||
}
|
PinMatrixRequestType_WipeCodeFirst = 4;
|
||||||
|
PinMatrixRequestType_WipeCodeSecond = 5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -98,7 +125,7 @@ message PinMatrixRequest {
|
||||||
* @auxend
|
* @auxend
|
||||||
*/
|
*/
|
||||||
message PinMatrixAck {
|
message PinMatrixAck {
|
||||||
required string pin = 1; // matrix encoded PIN entered by user
|
required string pin = 1; // matrix encoded PIN entered by user
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -107,31 +134,36 @@ message PinMatrixAck {
|
||||||
* @next PassphraseAck
|
* @next PassphraseAck
|
||||||
*/
|
*/
|
||||||
message PassphraseRequest {
|
message PassphraseRequest {
|
||||||
optional bool on_device = 1; // passphrase is being entered on the device
|
optional bool _on_device = 1 [deprecated=true]; // <2.3.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request: Send passphrase back
|
* Request: Send passphrase back
|
||||||
* @next PassphraseStateRequest
|
* @auxend
|
||||||
*/
|
*/
|
||||||
message PassphraseAck {
|
message PassphraseAck {
|
||||||
optional string passphrase = 1;
|
optional string passphrase = 1;
|
||||||
optional bytes state = 2; // expected device state
|
optional bytes _state = 2 [deprecated=true]; // <2.3.0
|
||||||
|
optional bool on_device = 3; // user wants to enter passphrase on the device
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Response: Device awaits passphrase state
|
* Response: Device awaits passphrase state
|
||||||
* @next PassphraseStateAck
|
* Deprecated in 2.3.0
|
||||||
|
* @next Deprecated_PassphraseStateAck
|
||||||
*/
|
*/
|
||||||
message PassphraseStateRequest {
|
message Deprecated_PassphraseStateRequest {
|
||||||
optional bytes state = 1; // actual device state
|
option deprecated = true;
|
||||||
|
optional bytes state = 1; // actual device state
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request: Send passphrase state back
|
* Request: Send passphrase state back
|
||||||
|
* Deprecated in 2.3.0
|
||||||
* @auxend
|
* @auxend
|
||||||
*/
|
*/
|
||||||
message PassphraseStateAck {
|
message Deprecated_PassphraseStateAck {
|
||||||
|
option deprecated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -140,10 +172,10 @@ message PassphraseStateAck {
|
||||||
* @embed
|
* @embed
|
||||||
*/
|
*/
|
||||||
message HDNodeType {
|
message HDNodeType {
|
||||||
required uint32 depth = 1;
|
required uint32 depth = 1;
|
||||||
required uint32 fingerprint = 2;
|
required uint32 fingerprint = 2;
|
||||||
required uint32 child_num = 3;
|
required uint32 child_num = 3;
|
||||||
required bytes chain_code = 4;
|
required bytes chain_code = 4;
|
||||||
optional bytes private_key = 5;
|
optional bytes private_key = 5;
|
||||||
optional bytes public_key = 6;
|
required bytes public_key = 6;
|
||||||
}
|
}
|
||||||
608
accounts/usbwallet/trezor/messages-ethereum-eip712.pb.go
Normal file
608
accounts/usbwallet/trezor/messages-ethereum-eip712.pb.go
Normal file
|
|
@ -0,0 +1,608 @@
|
||||||
|
// This file originates from the SatoshiLabs Trezor `common` repository at:
|
||||||
|
// https://github.com/trezor/trezor-common/blob/master/protob/messages-ethereum-eip712.proto
|
||||||
|
// dated 30.06.2025, commit 421b45d4677f2499234692b0f54010bc45b3ae5f.
|
||||||
|
|
||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.36.6
|
||||||
|
// protoc v4.25.3
|
||||||
|
// source: messages-ethereum-eip712.proto
|
||||||
|
|
||||||
|
package trezor
|
||||||
|
|
||||||
|
import (
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
unsafe "unsafe"
|
||||||
|
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type EthereumTypedDataStructAck_EthereumDataType int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
EthereumTypedDataStructAck_UINT EthereumTypedDataStructAck_EthereumDataType = 1
|
||||||
|
EthereumTypedDataStructAck_INT EthereumTypedDataStructAck_EthereumDataType = 2
|
||||||
|
EthereumTypedDataStructAck_BYTES EthereumTypedDataStructAck_EthereumDataType = 3
|
||||||
|
EthereumTypedDataStructAck_STRING EthereumTypedDataStructAck_EthereumDataType = 4
|
||||||
|
EthereumTypedDataStructAck_BOOL EthereumTypedDataStructAck_EthereumDataType = 5
|
||||||
|
EthereumTypedDataStructAck_ADDRESS EthereumTypedDataStructAck_EthereumDataType = 6
|
||||||
|
EthereumTypedDataStructAck_ARRAY EthereumTypedDataStructAck_EthereumDataType = 7
|
||||||
|
EthereumTypedDataStructAck_STRUCT EthereumTypedDataStructAck_EthereumDataType = 8
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for EthereumTypedDataStructAck_EthereumDataType.
|
||||||
|
var (
|
||||||
|
EthereumTypedDataStructAck_EthereumDataType_name = map[int32]string{
|
||||||
|
1: "UINT",
|
||||||
|
2: "INT",
|
||||||
|
3: "BYTES",
|
||||||
|
4: "STRING",
|
||||||
|
5: "BOOL",
|
||||||
|
6: "ADDRESS",
|
||||||
|
7: "ARRAY",
|
||||||
|
8: "STRUCT",
|
||||||
|
}
|
||||||
|
EthereumTypedDataStructAck_EthereumDataType_value = map[string]int32{
|
||||||
|
"UINT": 1,
|
||||||
|
"INT": 2,
|
||||||
|
"BYTES": 3,
|
||||||
|
"STRING": 4,
|
||||||
|
"BOOL": 5,
|
||||||
|
"ADDRESS": 6,
|
||||||
|
"ARRAY": 7,
|
||||||
|
"STRUCT": 8,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x EthereumTypedDataStructAck_EthereumDataType) Enum() *EthereumTypedDataStructAck_EthereumDataType {
|
||||||
|
p := new(EthereumTypedDataStructAck_EthereumDataType)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x EthereumTypedDataStructAck_EthereumDataType) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (EthereumTypedDataStructAck_EthereumDataType) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_messages_ethereum_eip712_proto_enumTypes[0].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (EthereumTypedDataStructAck_EthereumDataType) Type() protoreflect.EnumType {
|
||||||
|
return &file_messages_ethereum_eip712_proto_enumTypes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x EthereumTypedDataStructAck_EthereumDataType) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Do not use.
|
||||||
|
func (x *EthereumTypedDataStructAck_EthereumDataType) UnmarshalJSON(b []byte) error {
|
||||||
|
num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*x = EthereumTypedDataStructAck_EthereumDataType(num)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use EthereumTypedDataStructAck_EthereumDataType.Descriptor instead.
|
||||||
|
func (EthereumTypedDataStructAck_EthereumDataType) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_messages_ethereum_eip712_proto_rawDescGZIP(), []int{2, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
// *
|
||||||
|
// Request: Ask device to sign typed data
|
||||||
|
// @start
|
||||||
|
// @next EthereumTypedDataStructRequest
|
||||||
|
// @next EthereumTypedDataValueRequest
|
||||||
|
// @next EthereumTypedDataSignature
|
||||||
|
// @next Failure
|
||||||
|
type EthereumSignTypedData struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
AddressN []uint32 `protobuf:"varint,1,rep,name=address_n,json=addressN" json:"address_n,omitempty"` // BIP-32 path to derive the key from master node
|
||||||
|
PrimaryType *string `protobuf:"bytes,2,req,name=primary_type,json=primaryType" json:"primary_type,omitempty"` // name of the root message struct
|
||||||
|
MetamaskV4Compat *bool `protobuf:"varint,3,opt,name=metamask_v4_compat,json=metamaskV4Compat,def=1" json:"metamask_v4_compat,omitempty"` // use MetaMask v4 (see https://github.com/MetaMask/eth-sig-util/issues/106)
|
||||||
|
Definitions *EthereumDefinitions `protobuf:"bytes,4,opt,name=definitions" json:"definitions,omitempty"` // network and/or token definitions
|
||||||
|
ShowMessageHash []byte `protobuf:"bytes,5,opt,name=show_message_hash,json=showMessageHash" json:"show_message_hash,omitempty"` // hash of the typed data to be signed (if set, user will be asked to confirm before signing)
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default values for EthereumSignTypedData fields.
|
||||||
|
const (
|
||||||
|
Default_EthereumSignTypedData_MetamaskV4Compat = bool(true)
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x *EthereumSignTypedData) Reset() {
|
||||||
|
*x = EthereumSignTypedData{}
|
||||||
|
mi := &file_messages_ethereum_eip712_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumSignTypedData) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*EthereumSignTypedData) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *EthereumSignTypedData) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_messages_ethereum_eip712_proto_msgTypes[0]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use EthereumSignTypedData.ProtoReflect.Descriptor instead.
|
||||||
|
func (*EthereumSignTypedData) Descriptor() ([]byte, []int) {
|
||||||
|
return file_messages_ethereum_eip712_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumSignTypedData) GetAddressN() []uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.AddressN
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumSignTypedData) GetPrimaryType() string {
|
||||||
|
if x != nil && x.PrimaryType != nil {
|
||||||
|
return *x.PrimaryType
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumSignTypedData) GetMetamaskV4Compat() bool {
|
||||||
|
if x != nil && x.MetamaskV4Compat != nil {
|
||||||
|
return *x.MetamaskV4Compat
|
||||||
|
}
|
||||||
|
return Default_EthereumSignTypedData_MetamaskV4Compat
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumSignTypedData) GetDefinitions() *EthereumDefinitions {
|
||||||
|
if x != nil {
|
||||||
|
return x.Definitions
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumSignTypedData) GetShowMessageHash() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.ShowMessageHash
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// *
|
||||||
|
// Response: Device asks for type information about a struct.
|
||||||
|
// @next EthereumTypedDataStructAck
|
||||||
|
type EthereumTypedDataStructRequest struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` // name of the requested struct
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructRequest) Reset() {
|
||||||
|
*x = EthereumTypedDataStructRequest{}
|
||||||
|
mi := &file_messages_ethereum_eip712_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*EthereumTypedDataStructRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_messages_ethereum_eip712_proto_msgTypes[1]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use EthereumTypedDataStructRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*EthereumTypedDataStructRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_messages_ethereum_eip712_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructRequest) GetName() string {
|
||||||
|
if x != nil && x.Name != nil {
|
||||||
|
return *x.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// *
|
||||||
|
// Request: Type information about a struct.
|
||||||
|
// @next EthereumTypedDataStructRequest
|
||||||
|
type EthereumTypedDataStructAck struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Members []*EthereumTypedDataStructAck_EthereumStructMember `protobuf:"bytes,1,rep,name=members" json:"members,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck) Reset() {
|
||||||
|
*x = EthereumTypedDataStructAck{}
|
||||||
|
mi := &file_messages_ethereum_eip712_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*EthereumTypedDataStructAck) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_messages_ethereum_eip712_proto_msgTypes[2]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use EthereumTypedDataStructAck.ProtoReflect.Descriptor instead.
|
||||||
|
func (*EthereumTypedDataStructAck) Descriptor() ([]byte, []int) {
|
||||||
|
return file_messages_ethereum_eip712_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck) GetMembers() []*EthereumTypedDataStructAck_EthereumStructMember {
|
||||||
|
if x != nil {
|
||||||
|
return x.Members
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// *
|
||||||
|
// Response: Device asks for data at the specific member path.
|
||||||
|
// @next EthereumTypedDataValueAck
|
||||||
|
type EthereumTypedDataValueRequest struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
MemberPath []uint32 `protobuf:"varint,1,rep,name=member_path,json=memberPath" json:"member_path,omitempty"` // member path requested by device
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataValueRequest) Reset() {
|
||||||
|
*x = EthereumTypedDataValueRequest{}
|
||||||
|
mi := &file_messages_ethereum_eip712_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataValueRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*EthereumTypedDataValueRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataValueRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_messages_ethereum_eip712_proto_msgTypes[3]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use EthereumTypedDataValueRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*EthereumTypedDataValueRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_messages_ethereum_eip712_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataValueRequest) GetMemberPath() []uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.MemberPath
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// *
|
||||||
|
// Request: Single value of a specific atomic field.
|
||||||
|
// @next EthereumTypedDataValueRequest
|
||||||
|
type EthereumTypedDataValueAck struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Value []byte `protobuf:"bytes,1,req,name=value" json:"value,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataValueAck) Reset() {
|
||||||
|
*x = EthereumTypedDataValueAck{}
|
||||||
|
mi := &file_messages_ethereum_eip712_proto_msgTypes[4]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataValueAck) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*EthereumTypedDataValueAck) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataValueAck) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_messages_ethereum_eip712_proto_msgTypes[4]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use EthereumTypedDataValueAck.ProtoReflect.Descriptor instead.
|
||||||
|
func (*EthereumTypedDataValueAck) Descriptor() ([]byte, []int) {
|
||||||
|
return file_messages_ethereum_eip712_proto_rawDescGZIP(), []int{4}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataValueAck) GetValue() []byte {
|
||||||
|
if x != nil {
|
||||||
|
return x.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type EthereumTypedDataStructAck_EthereumStructMember struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Type *EthereumTypedDataStructAck_EthereumFieldType `protobuf:"bytes,1,req,name=type" json:"type,omitempty"`
|
||||||
|
Name *string `protobuf:"bytes,2,req,name=name" json:"name,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck_EthereumStructMember) Reset() {
|
||||||
|
*x = EthereumTypedDataStructAck_EthereumStructMember{}
|
||||||
|
mi := &file_messages_ethereum_eip712_proto_msgTypes[5]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck_EthereumStructMember) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*EthereumTypedDataStructAck_EthereumStructMember) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck_EthereumStructMember) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_messages_ethereum_eip712_proto_msgTypes[5]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use EthereumTypedDataStructAck_EthereumStructMember.ProtoReflect.Descriptor instead.
|
||||||
|
func (*EthereumTypedDataStructAck_EthereumStructMember) Descriptor() ([]byte, []int) {
|
||||||
|
return file_messages_ethereum_eip712_proto_rawDescGZIP(), []int{2, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck_EthereumStructMember) GetType() *EthereumTypedDataStructAck_EthereumFieldType {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck_EthereumStructMember) GetName() string {
|
||||||
|
if x != nil && x.Name != nil {
|
||||||
|
return *x.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type EthereumTypedDataStructAck_EthereumFieldType struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
DataType *EthereumTypedDataStructAck_EthereumDataType `protobuf:"varint,1,req,name=data_type,json=dataType,enum=hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck_EthereumDataType" json:"data_type,omitempty"`
|
||||||
|
Size *uint32 `protobuf:"varint,2,opt,name=size" json:"size,omitempty"` // for integer types: size in bytes (uint8 has size 1, uint256 has size 32)
|
||||||
|
// for bytes types: size in bytes, or unset for dynamic
|
||||||
|
// for arrays: size in elements, or unset for dynamic
|
||||||
|
// for structs: number of members
|
||||||
|
// for string, bool and address: unset
|
||||||
|
EntryType *EthereumTypedDataStructAck_EthereumFieldType `protobuf:"bytes,3,opt,name=entry_type,json=entryType" json:"entry_type,omitempty"` // for array types, type of single entry
|
||||||
|
StructName *string `protobuf:"bytes,4,opt,name=struct_name,json=structName" json:"struct_name,omitempty"` // for structs: its name
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck_EthereumFieldType) Reset() {
|
||||||
|
*x = EthereumTypedDataStructAck_EthereumFieldType{}
|
||||||
|
mi := &file_messages_ethereum_eip712_proto_msgTypes[6]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck_EthereumFieldType) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*EthereumTypedDataStructAck_EthereumFieldType) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck_EthereumFieldType) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_messages_ethereum_eip712_proto_msgTypes[6]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use EthereumTypedDataStructAck_EthereumFieldType.ProtoReflect.Descriptor instead.
|
||||||
|
func (*EthereumTypedDataStructAck_EthereumFieldType) Descriptor() ([]byte, []int) {
|
||||||
|
return file_messages_ethereum_eip712_proto_rawDescGZIP(), []int{2, 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck_EthereumFieldType) GetDataType() EthereumTypedDataStructAck_EthereumDataType {
|
||||||
|
if x != nil && x.DataType != nil {
|
||||||
|
return *x.DataType
|
||||||
|
}
|
||||||
|
return EthereumTypedDataStructAck_UINT
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck_EthereumFieldType) GetSize() uint32 {
|
||||||
|
if x != nil && x.Size != nil {
|
||||||
|
return *x.Size
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck_EthereumFieldType) GetEntryType() *EthereumTypedDataStructAck_EthereumFieldType {
|
||||||
|
if x != nil {
|
||||||
|
return x.EntryType
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EthereumTypedDataStructAck_EthereumFieldType) GetStructName() string {
|
||||||
|
if x != nil && x.StructName != nil {
|
||||||
|
return *x.StructName
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_messages_ethereum_eip712_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
const file_messages_ethereum_eip712_proto_rawDesc = "" +
|
||||||
|
"\n" +
|
||||||
|
"\x1emessages-ethereum-eip712.proto\x12\"hw.trezor.messages.ethereum_eip712\x1a\x17messages-ethereum.proto\"\x8b\x02\n" +
|
||||||
|
"\x15EthereumSignTypedData\x12\x1b\n" +
|
||||||
|
"\taddress_n\x18\x01 \x03(\rR\baddressN\x12!\n" +
|
||||||
|
"\fprimary_type\x18\x02 \x02(\tR\vprimaryType\x122\n" +
|
||||||
|
"\x12metamask_v4_compat\x18\x03 \x01(\b:\x04trueR\x10metamaskV4Compat\x12R\n" +
|
||||||
|
"\vdefinitions\x18\x04 \x01(\v20.hw.trezor.messages.ethereum.EthereumDefinitionsR\vdefinitions\x12*\n" +
|
||||||
|
"\x11show_message_hash\x18\x05 \x01(\fR\x0fshowMessageHash\"4\n" +
|
||||||
|
"\x1eEthereumTypedDataStructRequest\x12\x12\n" +
|
||||||
|
"\x04name\x18\x01 \x02(\tR\x04name\"\xb4\x05\n" +
|
||||||
|
"\x1aEthereumTypedDataStructAck\x12m\n" +
|
||||||
|
"\amembers\x18\x01 \x03(\v2S.hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck.EthereumStructMemberR\amembers\x1a\x90\x01\n" +
|
||||||
|
"\x14EthereumStructMember\x12d\n" +
|
||||||
|
"\x04type\x18\x01 \x02(\v2P.hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck.EthereumFieldTypeR\x04type\x12\x12\n" +
|
||||||
|
"\x04name\x18\x02 \x02(\tR\x04name\x1a\xa7\x02\n" +
|
||||||
|
"\x11EthereumFieldType\x12l\n" +
|
||||||
|
"\tdata_type\x18\x01 \x02(\x0e2O.hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck.EthereumDataTypeR\bdataType\x12\x12\n" +
|
||||||
|
"\x04size\x18\x02 \x01(\rR\x04size\x12o\n" +
|
||||||
|
"\n" +
|
||||||
|
"entry_type\x18\x03 \x01(\v2P.hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck.EthereumFieldTypeR\tentryType\x12\x1f\n" +
|
||||||
|
"\vstruct_name\x18\x04 \x01(\tR\n" +
|
||||||
|
"structName\"j\n" +
|
||||||
|
"\x10EthereumDataType\x12\b\n" +
|
||||||
|
"\x04UINT\x10\x01\x12\a\n" +
|
||||||
|
"\x03INT\x10\x02\x12\t\n" +
|
||||||
|
"\x05BYTES\x10\x03\x12\n" +
|
||||||
|
"\n" +
|
||||||
|
"\x06STRING\x10\x04\x12\b\n" +
|
||||||
|
"\x04BOOL\x10\x05\x12\v\n" +
|
||||||
|
"\aADDRESS\x10\x06\x12\t\n" +
|
||||||
|
"\x05ARRAY\x10\a\x12\n" +
|
||||||
|
"\n" +
|
||||||
|
"\x06STRUCT\x10\b\"@\n" +
|
||||||
|
"\x1dEthereumTypedDataValueRequest\x12\x1f\n" +
|
||||||
|
"\vmember_path\x18\x01 \x03(\rR\n" +
|
||||||
|
"memberPath\"1\n" +
|
||||||
|
"\x19EthereumTypedDataValueAck\x12\x14\n" +
|
||||||
|
"\x05value\x18\x01 \x02(\fR\x05valueB}\n" +
|
||||||
|
"#com.satoshilabs.trezor.lib.protobufB\x1bTrezorMessageEthereumEIP712Z9github.com/ethereum/go-ethereum/accounts/usbwallet/trezor"
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_messages_ethereum_eip712_proto_rawDescOnce sync.Once
|
||||||
|
file_messages_ethereum_eip712_proto_rawDescData []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_messages_ethereum_eip712_proto_rawDescGZIP() []byte {
|
||||||
|
file_messages_ethereum_eip712_proto_rawDescOnce.Do(func() {
|
||||||
|
file_messages_ethereum_eip712_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_messages_ethereum_eip712_proto_rawDesc), len(file_messages_ethereum_eip712_proto_rawDesc)))
|
||||||
|
})
|
||||||
|
return file_messages_ethereum_eip712_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_messages_ethereum_eip712_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
|
var file_messages_ethereum_eip712_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
||||||
|
var file_messages_ethereum_eip712_proto_goTypes = []any{
|
||||||
|
(EthereumTypedDataStructAck_EthereumDataType)(0), // 0: hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck.EthereumDataType
|
||||||
|
(*EthereumSignTypedData)(nil), // 1: hw.trezor.messages.ethereum_eip712.EthereumSignTypedData
|
||||||
|
(*EthereumTypedDataStructRequest)(nil), // 2: hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructRequest
|
||||||
|
(*EthereumTypedDataStructAck)(nil), // 3: hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck
|
||||||
|
(*EthereumTypedDataValueRequest)(nil), // 4: hw.trezor.messages.ethereum_eip712.EthereumTypedDataValueRequest
|
||||||
|
(*EthereumTypedDataValueAck)(nil), // 5: hw.trezor.messages.ethereum_eip712.EthereumTypedDataValueAck
|
||||||
|
(*EthereumTypedDataStructAck_EthereumStructMember)(nil), // 6: hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck.EthereumStructMember
|
||||||
|
(*EthereumTypedDataStructAck_EthereumFieldType)(nil), // 7: hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck.EthereumFieldType
|
||||||
|
(*EthereumDefinitions)(nil), // 8: hw.trezor.messages.ethereum.EthereumDefinitions
|
||||||
|
}
|
||||||
|
var file_messages_ethereum_eip712_proto_depIdxs = []int32{
|
||||||
|
8, // 0: hw.trezor.messages.ethereum_eip712.EthereumSignTypedData.definitions:type_name -> hw.trezor.messages.ethereum.EthereumDefinitions
|
||||||
|
6, // 1: hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck.members:type_name -> hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck.EthereumStructMember
|
||||||
|
7, // 2: hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck.EthereumStructMember.type:type_name -> hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck.EthereumFieldType
|
||||||
|
0, // 3: hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck.EthereumFieldType.data_type:type_name -> hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck.EthereumDataType
|
||||||
|
7, // 4: hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck.EthereumFieldType.entry_type:type_name -> hw.trezor.messages.ethereum_eip712.EthereumTypedDataStructAck.EthereumFieldType
|
||||||
|
5, // [5:5] is the sub-list for method output_type
|
||||||
|
5, // [5:5] is the sub-list for method input_type
|
||||||
|
5, // [5:5] is the sub-list for extension type_name
|
||||||
|
5, // [5:5] is the sub-list for extension extendee
|
||||||
|
0, // [0:5] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_messages_ethereum_eip712_proto_init() }
|
||||||
|
func file_messages_ethereum_eip712_proto_init() {
|
||||||
|
if File_messages_ethereum_eip712_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file_messages_ethereum_proto_init()
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_messages_ethereum_eip712_proto_rawDesc), len(file_messages_ethereum_eip712_proto_rawDesc)),
|
||||||
|
NumEnums: 1,
|
||||||
|
NumMessages: 7,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_messages_ethereum_eip712_proto_goTypes,
|
||||||
|
DependencyIndexes: file_messages_ethereum_eip712_proto_depIdxs,
|
||||||
|
EnumInfos: file_messages_ethereum_eip712_proto_enumTypes,
|
||||||
|
MessageInfos: file_messages_ethereum_eip712_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_messages_ethereum_eip712_proto = out.File
|
||||||
|
file_messages_ethereum_eip712_proto_goTypes = nil
|
||||||
|
file_messages_ethereum_eip712_proto_depIdxs = nil
|
||||||
|
}
|
||||||
99
accounts/usbwallet/trezor/messages-ethereum-eip712.proto
Normal file
99
accounts/usbwallet/trezor/messages-ethereum-eip712.proto
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
// This file originates from the SatoshiLabs Trezor `common` repository at:
|
||||||
|
// https://github.com/trezor/trezor-common/blob/master/protob/messages-ethereum-eip712.proto
|
||||||
|
// dated 30.06.2025, commit 421b45d4677f2499234692b0f54010bc45b3ae5f.
|
||||||
|
|
||||||
|
syntax = "proto2";
|
||||||
|
package hw.trezor.messages.ethereum_eip712;
|
||||||
|
|
||||||
|
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||||
|
|
||||||
|
// Sugar for easier handling in Java
|
||||||
|
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
||||||
|
option java_outer_classname = "TrezorMessageEthereumEIP712";
|
||||||
|
|
||||||
|
import "messages-ethereum.proto";
|
||||||
|
|
||||||
|
|
||||||
|
// Separated from messages-ethereum.proto as it is not implemented on T1 side
|
||||||
|
// and defining all the messages and fields could be even impossible as recursive
|
||||||
|
// messages are used here
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Ask device to sign typed data
|
||||||
|
* @start
|
||||||
|
* @next EthereumTypedDataStructRequest
|
||||||
|
* @next EthereumTypedDataValueRequest
|
||||||
|
* @next EthereumTypedDataSignature
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message EthereumSignTypedData {
|
||||||
|
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
||||||
|
required string primary_type = 2; // name of the root message struct
|
||||||
|
optional bool metamask_v4_compat = 3 [default=true]; // use MetaMask v4 (see https://github.com/MetaMask/eth-sig-util/issues/106)
|
||||||
|
optional ethereum.EthereumDefinitions definitions = 4; // network and/or token definitions
|
||||||
|
optional bytes show_message_hash = 5; // hash of the typed data to be signed (if set, user will be asked to confirm before signing)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response: Device asks for type information about a struct.
|
||||||
|
* @next EthereumTypedDataStructAck
|
||||||
|
*/
|
||||||
|
message EthereumTypedDataStructRequest {
|
||||||
|
required string name = 1; // name of the requested struct
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Type information about a struct.
|
||||||
|
* @next EthereumTypedDataStructRequest
|
||||||
|
*/
|
||||||
|
message EthereumTypedDataStructAck {
|
||||||
|
repeated EthereumStructMember members = 1;
|
||||||
|
|
||||||
|
message EthereumStructMember {
|
||||||
|
required EthereumFieldType type = 1;
|
||||||
|
required string name = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message EthereumFieldType {
|
||||||
|
required EthereumDataType data_type = 1;
|
||||||
|
optional uint32 size = 2; // for integer types: size in bytes (uint8 has size 1, uint256 has size 32)
|
||||||
|
// for bytes types: size in bytes, or unset for dynamic
|
||||||
|
// for arrays: size in elements, or unset for dynamic
|
||||||
|
// for structs: number of members
|
||||||
|
// for string, bool and address: unset
|
||||||
|
optional EthereumFieldType entry_type = 3; // for array types, type of single entry
|
||||||
|
optional string struct_name = 4; // for structs: its name
|
||||||
|
}
|
||||||
|
|
||||||
|
enum EthereumDataType {
|
||||||
|
UINT = 1;
|
||||||
|
INT = 2;
|
||||||
|
BYTES = 3;
|
||||||
|
STRING = 4;
|
||||||
|
BOOL = 5;
|
||||||
|
ADDRESS = 6;
|
||||||
|
ARRAY = 7;
|
||||||
|
STRUCT = 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response: Device asks for data at the specific member path.
|
||||||
|
* @next EthereumTypedDataValueAck
|
||||||
|
*/
|
||||||
|
message EthereumTypedDataValueRequest {
|
||||||
|
repeated uint32 member_path = 1; // member path requested by device
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Single value of a specific atomic field.
|
||||||
|
* @next EthereumTypedDataValueRequest
|
||||||
|
*/
|
||||||
|
message EthereumTypedDataValueAck {
|
||||||
|
required bytes value = 1;
|
||||||
|
// * atomic types: value of the member.
|
||||||
|
// Length must match the `size` of the corresponding field type, unless the size is dynamic.
|
||||||
|
// * array types: number of elements, encoded as uint16.
|
||||||
|
// * struct types: undefined, Trezor will not query a struct field.
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
||||||
// This file originates from the SatoshiLabs Trezor `common` repository at:
|
// This file originates from the SatoshiLabs Trezor `common` repository at:
|
||||||
// https://github.com/trezor/trezor-common/blob/master/protob/messages-ethereum.proto
|
// https://github.com/trezor/trezor-common/blob/master/protob/messages-ethereum.proto
|
||||||
// dated 28.05.2019, commit 893fd219d4a01bcffa0cd9cfa631856371ec5aa9.
|
// dated 30.06.2025, commit 421b45d4677f2499234692b0f54010bc45b3ae5f.
|
||||||
|
|
||||||
syntax = "proto2";
|
syntax = "proto2";
|
||||||
package hw.trezor.messages.ethereum;
|
package hw.trezor.messages.ethereum;
|
||||||
|
|
@ -13,7 +13,6 @@ option java_outer_classname = "TrezorMessageEthereum";
|
||||||
|
|
||||||
import "messages-common.proto";
|
import "messages-common.proto";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request: Ask device for public key corresponding to address_n path
|
* Request: Ask device for public key corresponding to address_n path
|
||||||
* @start
|
* @start
|
||||||
|
|
@ -21,8 +20,8 @@ import "messages-common.proto";
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message EthereumGetPublicKey {
|
message EthereumGetPublicKey {
|
||||||
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
||||||
optional bool show_display = 2; // optionally show on display before sending the result
|
optional bool show_display = 2; // optionally show on display before sending the result
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -30,8 +29,8 @@ message EthereumGetPublicKey {
|
||||||
* @end
|
* @end
|
||||||
*/
|
*/
|
||||||
message EthereumPublicKey {
|
message EthereumPublicKey {
|
||||||
optional hw.trezor.messages.common.HDNodeType node = 1; // BIP32 public node
|
required hw.trezor.messages.common.HDNodeType node = 1; // BIP32 public node
|
||||||
optional string xpub = 2; // serialized form of public node
|
required string xpub = 2; // serialized form of public node
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -41,8 +40,10 @@ message EthereumPublicKey {
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message EthereumGetAddress {
|
message EthereumGetAddress {
|
||||||
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
||||||
optional bool show_display = 2; // optionally show on display before sending the result
|
optional bool show_display = 2; // optionally show on display before sending the result
|
||||||
|
optional bytes encoded_network = 3; // encoded Ethereum network, see external-definitions.md for details
|
||||||
|
optional bool chunkify = 4; // display the address in chunks of 4 characters
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -50,30 +51,60 @@ message EthereumGetAddress {
|
||||||
* @end
|
* @end
|
||||||
*/
|
*/
|
||||||
message EthereumAddress {
|
message EthereumAddress {
|
||||||
optional bytes addressBin = 1; // Ethereum address as 20 bytes (legacy firmwares)
|
optional bytes _old_address = 1 [deprecated=true]; // trezor <1.8.0, <2.1.0 - raw bytes of Ethereum address
|
||||||
optional string addressHex = 2; // Ethereum address as hex string (newer firmwares)
|
optional string address = 2; // Ethereum address as hex-encoded string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request: Ask device to sign transaction
|
* Request: Ask device to sign transaction
|
||||||
* All fields are optional from the protocol's point of view. Each field defaults to value `0` if missing.
|
* gas_price, gas_limit and chain_id must be provided and non-zero.
|
||||||
|
* All other fields are optional and default to value `0` if missing.
|
||||||
* Note: the first at most 1024 bytes of data MUST be transmitted as part of this message.
|
* Note: the first at most 1024 bytes of data MUST be transmitted as part of this message.
|
||||||
* @start
|
* @start
|
||||||
* @next EthereumTxRequest
|
* @next EthereumTxRequest
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message EthereumSignTx {
|
message EthereumSignTx {
|
||||||
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
||||||
optional bytes nonce = 2; // <=256 bit unsigned big endian
|
optional bytes nonce = 2 [default='']; // <=256 bit unsigned big endian
|
||||||
optional bytes gas_price = 3; // <=256 bit unsigned big endian (in wei)
|
required bytes gas_price = 3; // <=256 bit unsigned big endian (in wei)
|
||||||
optional bytes gas_limit = 4; // <=256 bit unsigned big endian
|
required bytes gas_limit = 4; // <=256 bit unsigned big endian
|
||||||
optional bytes toBin = 5; // recipient address (20 bytes, legacy firmware)
|
optional string to = 11 [default='']; // recipient address
|
||||||
optional string toHex = 11; // recipient address (hex string, newer firmware)
|
optional bytes value = 6 [default='']; // <=256 bit unsigned big endian (in wei)
|
||||||
optional bytes value = 6; // <=256 bit unsigned big endian (in wei)
|
optional bytes data_initial_chunk = 7 [default='']; // The initial data chunk (<= 1024 bytes)
|
||||||
optional bytes data_initial_chunk = 7; // The initial data chunk (<= 1024 bytes)
|
optional uint32 data_length = 8 [default=0]; // Length of transaction payload
|
||||||
optional uint32 data_length = 8; // Length of transaction payload
|
required uint64 chain_id = 9; // Chain Id for EIP 155
|
||||||
optional uint32 chain_id = 9; // Chain Id for EIP 155
|
optional uint32 tx_type = 10; // Used for Wanchain
|
||||||
optional uint32 tx_type = 10; // (only for Wanchain)
|
optional EthereumDefinitions definitions = 12; // network and/or token definitions for tx
|
||||||
|
optional bool chunkify = 13; // display the address in chunks of 4 characters
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Ask device to sign EIP1559 transaction
|
||||||
|
* Note: the first at most 1024 bytes of data MUST be transmitted as part of this message.
|
||||||
|
* @start
|
||||||
|
* @next EthereumTxRequest
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message EthereumSignTxEIP1559 {
|
||||||
|
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
||||||
|
required bytes nonce = 2; // <=256 bit unsigned big endian
|
||||||
|
required bytes max_gas_fee = 3; // <=256 bit unsigned big endian (in wei)
|
||||||
|
required bytes max_priority_fee = 4; // <=256 bit unsigned big endian (in wei)
|
||||||
|
required bytes gas_limit = 5; // <=256 bit unsigned big endian
|
||||||
|
optional string to = 6 [default='']; // recipient address
|
||||||
|
required bytes value = 7; // <=256 bit unsigned big endian (in wei)
|
||||||
|
optional bytes data_initial_chunk = 8 [default='']; // The initial data chunk (<= 1024 bytes)
|
||||||
|
required uint32 data_length = 9; // Length of transaction payload
|
||||||
|
required uint64 chain_id = 10; // Chain Id for EIP 155
|
||||||
|
repeated EthereumAccessList access_list = 11; // Access List
|
||||||
|
optional EthereumDefinitions definitions = 12; // network and/or token definitions for tx
|
||||||
|
optional bool chunkify = 13; // display the address in chunks of 4 characters
|
||||||
|
|
||||||
|
message EthereumAccessList {
|
||||||
|
required string address = 1;
|
||||||
|
repeated bytes storage_keys = 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -84,10 +115,10 @@ message EthereumSignTx {
|
||||||
* @next EthereumTxAck
|
* @next EthereumTxAck
|
||||||
*/
|
*/
|
||||||
message EthereumTxRequest {
|
message EthereumTxRequest {
|
||||||
optional uint32 data_length = 1; // Number of bytes being requested (<= 1024)
|
optional uint32 data_length = 1; // Number of bytes being requested (<= 1024)
|
||||||
optional uint32 signature_v = 2; // Computed signature (recovery parameter, limited to 27 or 28)
|
optional uint32 signature_v = 2; // Computed signature (recovery parameter, limited to 27 or 28)
|
||||||
optional bytes signature_r = 3; // Computed signature R component (256 bit)
|
optional bytes signature_r = 3; // Computed signature R component (256 bit)
|
||||||
optional bytes signature_s = 4; // Computed signature S component (256 bit)
|
optional bytes signature_s = 4; // Computed signature S component (256 bit)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -95,7 +126,7 @@ message EthereumTxRequest {
|
||||||
* @next EthereumTxRequest
|
* @next EthereumTxRequest
|
||||||
*/
|
*/
|
||||||
message EthereumTxAck {
|
message EthereumTxAck {
|
||||||
optional bytes data_chunk = 1; // Bytes from transaction payload (<= 1024 bytes)
|
required bytes data_chunk = 1; // Bytes from transaction payload (<= 1024 bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -105,8 +136,10 @@ message EthereumTxAck {
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message EthereumSignMessage {
|
message EthereumSignMessage {
|
||||||
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
||||||
optional bytes message = 2; // message to be signed
|
required bytes message = 2; // message to be signed
|
||||||
|
optional bytes encoded_network = 3; // encoded Ethereum network, see external-definitions.md for details
|
||||||
|
optional bool chunkify = 4; // display the address in chunks of 4 characters
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -114,9 +147,8 @@ message EthereumSignMessage {
|
||||||
* @end
|
* @end
|
||||||
*/
|
*/
|
||||||
message EthereumMessageSignature {
|
message EthereumMessageSignature {
|
||||||
optional bytes addressBin = 1; // address used to sign the message (20 bytes, legacy firmware)
|
required bytes signature = 2; // signature of the message
|
||||||
optional bytes signature = 2; // signature of the message
|
required string address = 3; // address used to sign the message
|
||||||
optional string addressHex = 3; // address used to sign the message (hex string, newer firmware)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -126,8 +158,39 @@ message EthereumMessageSignature {
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message EthereumVerifyMessage {
|
message EthereumVerifyMessage {
|
||||||
optional bytes addressBin = 1; // address to verify (20 bytes, legacy firmware)
|
required bytes signature = 2; // signature to verify
|
||||||
optional bytes signature = 2; // signature to verify
|
required bytes message = 3; // message to verify
|
||||||
optional bytes message = 3; // message to verify
|
required string address = 4; // address to verify
|
||||||
optional string addressHex = 4; // address to verify (hex string, newer firmware)
|
optional bool chunkify = 5; // display the address in chunks of 4 characters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Ask device to sign hash of typed data
|
||||||
|
* @start
|
||||||
|
* @next EthereumTypedDataSignature
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message EthereumSignTypedHash {
|
||||||
|
repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node
|
||||||
|
required bytes domain_separator_hash = 2; // Hash of domainSeparator of typed data to be signed
|
||||||
|
optional bytes message_hash = 3; // Hash of the data of typed data to be signed (empty if domain-only data)
|
||||||
|
optional bytes encoded_network = 4; // encoded Ethereum network, see external-definitions.md for details
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response: Signed typed data
|
||||||
|
* @end
|
||||||
|
*/
|
||||||
|
message EthereumTypedDataSignature {
|
||||||
|
required bytes signature = 1; // signature of the typed data
|
||||||
|
required string address = 2; // address used to sign the typed data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains an encoded network and/or token definition. See external-definitions.md for details.
|
||||||
|
* @embed
|
||||||
|
*/
|
||||||
|
message EthereumDefinitions {
|
||||||
|
optional bytes encoded_network = 1; // encoded ethereum network
|
||||||
|
optional bytes encoded_token = 2; // encoded ethereum token
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
||||||
// This file originates from the SatoshiLabs Trezor `common` repository at:
|
// This file originates from the SatoshiLabs Trezor `common` repository at:
|
||||||
// https://github.com/trezor/trezor-common/blob/master/protob/messages-management.proto
|
// https://github.com/trezor/trezor-common/blob/master/protob/messages-management.proto
|
||||||
// dated 28.05.2019, commit 893fd219d4a01bcffa0cd9cfa631856371ec5aa9.
|
// dated 30.06.2025, commit 421b45d4677f2499234692b0f54010bc45b3ae5f.
|
||||||
|
|
||||||
syntax = "proto2";
|
syntax = "proto2";
|
||||||
package hw.trezor.messages.management;
|
package hw.trezor.messages.management;
|
||||||
|
|
@ -11,7 +11,49 @@ option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor"
|
||||||
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
||||||
option java_outer_classname = "TrezorMessageManagement";
|
option java_outer_classname = "TrezorMessageManagement";
|
||||||
|
|
||||||
import "messages-common.proto";
|
import "options.proto";
|
||||||
|
|
||||||
|
option (include_in_bitcoin_only) = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of the mnemonic backup given/received by the device during reset/recovery.
|
||||||
|
*/
|
||||||
|
enum BackupType {
|
||||||
|
Bip39 = 0; // also called "Single Backup", see BIP-0039
|
||||||
|
Slip39_Basic = 1; // also called "Shamir Backup", see SLIP-0039
|
||||||
|
Slip39_Advanced = 2; // also called "Super Shamir" or "Shamir with Groups", see SLIP-0039#two-level-scheme
|
||||||
|
Slip39_Single_Extendable = 3; // extendable single-share Shamir backup
|
||||||
|
Slip39_Basic_Extendable = 4; // extendable multi-share Shamir backup
|
||||||
|
Slip39_Advanced_Extendable = 5; // extendable multi-share Shamir backup with groups
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Level of safety checks for unsafe actions like spending from invalid path namespace or setting high transaction fee.
|
||||||
|
*/
|
||||||
|
enum SafetyCheckLevel {
|
||||||
|
Strict = 0; // disallow unsafe actions, this is the default
|
||||||
|
PromptAlways = 1; // ask user before unsafe action
|
||||||
|
PromptTemporarily = 2; // like PromptAlways but reverts to Strict after reboot
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allowed display rotation angles (in degrees from North)
|
||||||
|
*/
|
||||||
|
enum DisplayRotation {
|
||||||
|
North = 0;
|
||||||
|
East = 90;
|
||||||
|
South = 180;
|
||||||
|
West = 270;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format of the homescreen image
|
||||||
|
*/
|
||||||
|
enum HomescreenFormat {
|
||||||
|
Toif = 1; // full-color toif
|
||||||
|
Jpeg = 2; // jpeg
|
||||||
|
ToiG = 3; // greyscale toif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request: Reset device to default state and ask for device details
|
* Request: Reset device to default state and ask for device details
|
||||||
|
|
@ -19,8 +61,9 @@ import "messages-common.proto";
|
||||||
* @next Features
|
* @next Features
|
||||||
*/
|
*/
|
||||||
message Initialize {
|
message Initialize {
|
||||||
optional bytes state = 1; // assumed device state, clear session if set and different
|
optional bytes session_id = 1; // assumed device session id; Trezor clears caches if it is different or empty
|
||||||
optional bool skip_passphrase = 2; // this session should always assume empty passphrase
|
optional bool _skip_passphrase = 2 [deprecated=true]; // removed as part of passphrase redesign
|
||||||
|
optional bool derive_cardano = 3; // whether to derive Cardano Icarus root keys in this session
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -36,65 +79,193 @@ message GetFeatures {
|
||||||
* @end
|
* @end
|
||||||
*/
|
*/
|
||||||
message Features {
|
message Features {
|
||||||
optional string vendor = 1; // name of the manufacturer, e.g. "trezor.io"
|
optional string vendor = 1; // name of the manufacturer, e.g. "trezor.io"
|
||||||
optional uint32 major_version = 2; // major version of the firmware/bootloader, e.g. 1
|
required uint32 major_version = 2; // major version of the firmware/bootloader, e.g. 1
|
||||||
optional uint32 minor_version = 3; // minor version of the firmware/bootloader, e.g. 0
|
required uint32 minor_version = 3; // minor version of the firmware/bootloader, e.g. 0
|
||||||
optional uint32 patch_version = 4; // patch version of the firmware/bootloader, e.g. 0
|
required uint32 patch_version = 4; // patch version of the firmware/bootloader, e.g. 0
|
||||||
optional bool bootloader_mode = 5; // is device in bootloader mode?
|
optional bool bootloader_mode = 5; // is device in bootloader mode?
|
||||||
optional string device_id = 6; // device's unique identifier
|
optional string device_id = 6; // device's unique identifier
|
||||||
optional bool pin_protection = 7; // is device protected by PIN?
|
optional bool pin_protection = 7; // is device protected by PIN?
|
||||||
optional bool passphrase_protection = 8; // is node/mnemonic encrypted using passphrase?
|
optional bool passphrase_protection = 8; // is node/mnemonic encrypted using passphrase?
|
||||||
optional string language = 9; // device language
|
optional string language = 9; // device language
|
||||||
optional string label = 10; // device description label
|
optional string label = 10; // device description label
|
||||||
optional bool initialized = 12; // does device contain seed?
|
optional bool initialized = 12; // does device contain seed?
|
||||||
optional bytes revision = 13; // SCM revision of firmware
|
optional bytes revision = 13; // SCM revision of firmware
|
||||||
optional bytes bootloader_hash = 14; // hash of the bootloader
|
optional bytes bootloader_hash = 14; // hash of the bootloader
|
||||||
optional bool imported = 15; // was storage imported from an external source?
|
optional bool imported = 15; // was storage imported from an external source?
|
||||||
optional bool pin_cached = 16; // is PIN already cached in session?
|
optional bool unlocked = 16; // is the device unlocked? called "pin_cached" previously
|
||||||
optional bool passphrase_cached = 17; // is passphrase already cached in session?
|
optional bool _passphrase_cached = 17 [deprecated=true]; // is passphrase already cached in session?
|
||||||
optional bool firmware_present = 18; // is valid firmware loaded?
|
optional bool firmware_present = 18; // is valid firmware loaded?
|
||||||
optional bool needs_backup = 19; // does storage need backup? (equals to Storage.needs_backup)
|
optional BackupAvailability backup_availability = 19; // does storage need backup? is repeated backup unlocked?
|
||||||
optional uint32 flags = 20; // device flags (equals to Storage.flags)
|
optional uint32 flags = 20; // device flags (equals to Storage.flags)
|
||||||
optional string model = 21; // device hardware model
|
optional string model = 21; // device hardware model
|
||||||
optional uint32 fw_major = 22; // reported firmware version if in bootloader mode
|
optional uint32 fw_major = 22; // reported firmware version if in bootloader mode
|
||||||
optional uint32 fw_minor = 23; // reported firmware version if in bootloader mode
|
optional uint32 fw_minor = 23; // reported firmware version if in bootloader mode
|
||||||
optional uint32 fw_patch = 24; // reported firmware version if in bootloader mode
|
optional uint32 fw_patch = 24; // reported firmware version if in bootloader mode
|
||||||
optional string fw_vendor = 25; // reported firmware vendor if in bootloader mode
|
optional string fw_vendor = 25; // reported firmware vendor if in bootloader mode
|
||||||
optional bytes fw_vendor_keys = 26; // reported firmware vendor keys (their hash)
|
// optional bytes fw_vendor_keys = 26; // obsoleted, use fw_vendor
|
||||||
optional bool unfinished_backup = 27; // report unfinished backup (equals to Storage.unfinished_backup)
|
optional bool unfinished_backup = 27; // report unfinished backup (equals to Storage.unfinished_backup)
|
||||||
optional bool no_backup = 28; // report no backup (equals to Storage.no_backup)
|
optional bool no_backup = 28; // report no backup (equals to Storage.no_backup)
|
||||||
|
optional RecoveryStatus recovery_status = 29; // whether or not we are in recovery mode and of what kind
|
||||||
|
repeated Capability capabilities = 30; // list of supported capabilities
|
||||||
|
optional BackupType backup_type = 31; // type of device backup (BIP-39 / SLIP-39 basic / SLIP-39 advanced)
|
||||||
|
optional bool sd_card_present = 32; // is SD card present
|
||||||
|
optional bool sd_protection = 33; // is SD Protect enabled
|
||||||
|
optional bool wipe_code_protection = 34; // is wipe code protection enabled
|
||||||
|
optional bytes session_id = 35;
|
||||||
|
optional bool passphrase_always_on_device = 36; // device enforces passphrase entry on Trezor
|
||||||
|
optional SafetyCheckLevel safety_checks = 37; // safety check level, set to Prompt to limit path namespace enforcement
|
||||||
|
optional uint32 auto_lock_delay_ms = 38; // number of milliseconds after which the device locks itself
|
||||||
|
optional DisplayRotation display_rotation = 39; // rotation of display (in degrees from North)
|
||||||
|
optional bool experimental_features = 40; // are experimental message types enabled?
|
||||||
|
optional bool busy = 41; // is the device busy, showing "Do not disconnect"?
|
||||||
|
optional HomescreenFormat homescreen_format = 42; // format of the homescreen, 1 = TOIf, 2 = jpg, 3 = TOIG
|
||||||
|
optional bool hide_passphrase_from_host = 43; // should we hide the passphrase when it comes from host?
|
||||||
|
optional string internal_model = 44; // internal model name
|
||||||
|
optional uint32 unit_color = 45; // color of the unit/device
|
||||||
|
optional bool unit_btconly = 46; // unit/device is intended as bitcoin only
|
||||||
|
optional uint32 homescreen_width = 47; // homescreen width in pixels
|
||||||
|
optional uint32 homescreen_height = 48; // homescreen height in pixels
|
||||||
|
optional bool bootloader_locked = 49; // bootloader is locked
|
||||||
|
optional bool language_version_matches = 50 [default=true]; // translation blob version matches firmware version
|
||||||
|
optional uint32 unit_packaging = 51; // unit/device packaging version
|
||||||
|
optional bool haptic_feedback = 52; // haptic feedback is enabled
|
||||||
|
optional RecoveryType recovery_type = 53; // what type of recovery we are in. NB: this works in conjunction with recovery_status
|
||||||
|
optional uint32 optiga_sec = 54; // Optiga's security event counter.
|
||||||
|
|
||||||
|
enum BackupAvailability {
|
||||||
|
/// Device is already backed up, or a previous backup has failed.
|
||||||
|
NotAvailable = 0;
|
||||||
|
/// Device is not backed up. Backup is required.
|
||||||
|
Required = 1;
|
||||||
|
/// Device is already backed up and can be backed up again.
|
||||||
|
Available = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RecoveryStatus {
|
||||||
|
Nothing = 0; // we are not in recovery mode
|
||||||
|
Recovery = 1; // we are in "Normal" or "DryRun" recovery
|
||||||
|
Backup = 2; // we are in repeated backup mode
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Capability {
|
||||||
|
option (has_bitcoin_only_values) = true;
|
||||||
|
|
||||||
|
Capability_Bitcoin = 1 [(bitcoin_only) = true];
|
||||||
|
Capability_Bitcoin_like = 2; // Altcoins based on the Bitcoin source code
|
||||||
|
Capability_Binance = 3; // BNB Smart Chain
|
||||||
|
Capability_Cardano = 4;
|
||||||
|
Capability_Crypto = 5 [(bitcoin_only) = true]; // generic crypto operations for GPG, SSH, etc.
|
||||||
|
Capability_EOS = 6;
|
||||||
|
Capability_Ethereum = 7;
|
||||||
|
Capability_Lisk = 8 [deprecated = true];
|
||||||
|
Capability_Monero = 9;
|
||||||
|
Capability_NEM = 10;
|
||||||
|
Capability_Ripple = 11;
|
||||||
|
Capability_Stellar = 12;
|
||||||
|
Capability_Tezos = 13;
|
||||||
|
Capability_U2F = 14;
|
||||||
|
Capability_Shamir = 15 [(bitcoin_only) = true];
|
||||||
|
Capability_ShamirGroups = 16 [(bitcoin_only) = true];
|
||||||
|
Capability_PassphraseEntry = 17 [(bitcoin_only) = true]; // the device is capable of passphrase entry directly on the device
|
||||||
|
Capability_Solana = 18;
|
||||||
|
Capability_Translations = 19 [(bitcoin_only) = true];
|
||||||
|
Capability_Brightness = 20 [(bitcoin_only) = true];
|
||||||
|
Capability_Haptic = 21 [(bitcoin_only) = true];
|
||||||
|
Capability_BLE = 22 [(bitcoin_only) = true]; // Bluetooth Low Energy
|
||||||
|
Capability_NFC = 23 [(bitcoin_only) = true]; // Near Field Communications
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request: clear session (removes cached PIN, passphrase, etc).
|
* Request: soft-lock the device. Following actions will require PIN. Passphrases remain cached.
|
||||||
* @start
|
* @start
|
||||||
* @next Success
|
* @next Success
|
||||||
*/
|
*/
|
||||||
message ClearSession {
|
message LockDevice {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request: change language and/or label of the device
|
* Request: Show a "Do not disconnect" dialog instead of the standard homescreen.
|
||||||
* @start
|
* @start
|
||||||
* @next Success
|
* @next Success
|
||||||
|
*/
|
||||||
|
message SetBusy {
|
||||||
|
optional uint32 expiry_ms = 1; // The time in milliseconds after which the dialog will automatically disappear. Overrides any previously set expiry. If not set, then the dialog is hidden.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: end the current sesson. Following actions must call Initialize again.
|
||||||
|
* Cache for the current session is discarded, other sessions remain intact.
|
||||||
|
* Device is not PIN-locked.
|
||||||
|
* @start
|
||||||
|
* @next Success
|
||||||
|
*/
|
||||||
|
message EndSession {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: change some property of the device, e.g. label or homescreen
|
||||||
|
* @start
|
||||||
|
* @next Success
|
||||||
|
* @next DataChunkRequest
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message ApplySettings {
|
message ApplySettings {
|
||||||
optional string language = 1;
|
optional string language = 1 [deprecated=true];
|
||||||
optional string label = 2;
|
optional string label = 2;
|
||||||
optional bool use_passphrase = 3;
|
optional bool use_passphrase = 3;
|
||||||
optional bytes homescreen = 4;
|
optional bytes homescreen = 4; // homescreen image in single array, deprecated for 14
|
||||||
optional PassphraseSourceType passphrase_source = 5;
|
optional uint32 _passphrase_source = 5 [deprecated=true]; // ASK = 0; DEVICE = 1; HOST = 2;
|
||||||
optional uint32 auto_lock_delay_ms = 6;
|
optional uint32 auto_lock_delay_ms = 6;
|
||||||
optional uint32 display_rotation = 7; // in degrees from North
|
optional DisplayRotation display_rotation = 7; // rotation of display (in degrees from North)
|
||||||
/**
|
optional bool passphrase_always_on_device = 8; // do not prompt for passphrase, enforce device entry
|
||||||
* Structure representing passphrase source
|
optional SafetyCheckLevel safety_checks = 9; // Safety check level, set to Prompt to limit path namespace enforcement
|
||||||
*/
|
optional bool experimental_features = 10; // enable experimental message types
|
||||||
enum PassphraseSourceType {
|
optional bool hide_passphrase_from_host = 11; // do not show passphrase coming from host
|
||||||
ASK = 0;
|
optional bool haptic_feedback = 13; // enable haptic feedback
|
||||||
DEVICE = 1;
|
optional uint32 homescreen_length = 14; // byte length of new homescreen, device will request chunks
|
||||||
HOST = 2;
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Request: change the device language via translation data.
|
||||||
|
* Does not send the translation data itself, as they are too large for one message.
|
||||||
|
* Device will request the translation data in chunks.
|
||||||
|
* @start
|
||||||
|
* @next DataChunkRequest
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message ChangeLanguage {
|
||||||
|
// byte length of the whole translation blob (set to 0 for default language - english)
|
||||||
|
required uint32 data_length = 1;
|
||||||
|
// Prompt the user on screen.
|
||||||
|
// In certain conditions (such as freshly installed device), the confirmation prompt
|
||||||
|
// is not mandatory. Setting show_display=false will skip the prompt if that's
|
||||||
|
// the case. If the device does not allow skipping the prompt, a request with
|
||||||
|
// show_display=false will return a failure. (This way the host can safely try
|
||||||
|
// to change the language without invoking a prompt.)
|
||||||
|
// Setting show_display to true will always show the prompt.
|
||||||
|
// Leaving the option unset will show the prompt only when necessary.
|
||||||
|
optional bool show_display = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response: Device asks for more data from translation/homescreen image.
|
||||||
|
* @end
|
||||||
|
* @next DataChunkAck
|
||||||
|
*/
|
||||||
|
message DataChunkRequest {
|
||||||
|
required uint32 data_length = 1; // Number of bytes being requested
|
||||||
|
required uint32 data_offset = 2; // Offset of the first byte being requested
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Translation/homescreen payload data.
|
||||||
|
* @next DataChunkRequest
|
||||||
|
* @next Success
|
||||||
|
*/
|
||||||
|
message DataChunkAck {
|
||||||
|
required bytes data_chunk = 1; // Bytes from translation/homescreen payload
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -104,7 +275,7 @@ message ApplySettings {
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message ApplyFlags {
|
message ApplyFlags {
|
||||||
optional uint32 flags = 1; // bitmask, can only set bits, not unset
|
required uint32 flags = 1; // bitmask, can only set bits, not unset
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -114,7 +285,35 @@ message ApplyFlags {
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message ChangePin {
|
message ChangePin {
|
||||||
optional bool remove = 1; // is PIN removal requested?
|
optional bool remove = 1; // is PIN removal requested?
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Starts workflow for setting/removing the wipe code
|
||||||
|
* @start
|
||||||
|
* @next Success
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message ChangeWipeCode {
|
||||||
|
optional bool remove = 1; // is wipe code removal requested?
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Starts workflow for enabling/regenerating/disabling SD card protection
|
||||||
|
* @start
|
||||||
|
* @next Success
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message SdProtect {
|
||||||
|
required SdProtectOperationType operation = 1;
|
||||||
|
/**
|
||||||
|
* Structure representing SD card protection operation
|
||||||
|
*/
|
||||||
|
enum SdProtectOperationType {
|
||||||
|
DISABLE = 0;
|
||||||
|
ENABLE = 1;
|
||||||
|
REFRESH = 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -123,10 +322,8 @@ message ChangePin {
|
||||||
* @next Success
|
* @next Success
|
||||||
*/
|
*/
|
||||||
message Ping {
|
message Ping {
|
||||||
optional string message = 1; // message to send back in Success message
|
optional string message = 1 [default=""]; // message to send back in Success message
|
||||||
optional bool button_protection = 2; // ask for button press
|
optional bool button_protection = 2; // ask for button press
|
||||||
optional bool pin_protection = 3; // ask for PIN if set in device
|
|
||||||
optional bool passphrase_protection = 4; // ask for passphrase if set in device
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -144,7 +341,7 @@ message Cancel {
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message GetEntropy {
|
message GetEntropy {
|
||||||
required uint32 size = 1; // size of requested entropy
|
required uint32 size = 1; // size of requested entropy
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -152,7 +349,44 @@ message GetEntropy {
|
||||||
* @end
|
* @end
|
||||||
*/
|
*/
|
||||||
message Entropy {
|
message Entropy {
|
||||||
required bytes entropy = 1; // chunk of random generated bytes
|
required bytes entropy = 1; // chunk of random generated bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Get a hash of the installed firmware combined with an optional challenge.
|
||||||
|
* @start
|
||||||
|
* @next FirmwareHash
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message GetFirmwareHash {
|
||||||
|
optional bytes challenge = 1; // Blake2s key up to 32 bytes in length.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response: Hash of the installed firmware combined with the optional challenge.
|
||||||
|
* @end
|
||||||
|
*/
|
||||||
|
message FirmwareHash {
|
||||||
|
required bytes hash = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Request a signature of the provided challenge.
|
||||||
|
* @start
|
||||||
|
* @next AuthenticityProof
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message AuthenticateDevice {
|
||||||
|
required bytes challenge = 1; // A random challenge to sign.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response: Signature of the provided challenge along with a certificate issued by the Trezor company.
|
||||||
|
* @end
|
||||||
|
*/
|
||||||
|
message AuthenticityProof {
|
||||||
|
repeated bytes certificates = 1; // A certificate chain starting with the device certificate, followed by intermediate CA certificates, the last of which is signed by Trezor company's root CA.
|
||||||
|
required bytes signature = 2; // A DER-encoded signature of "\0x13AuthenticateDevice:" + length-prefixed challenge that should be verified using the device certificate.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -171,14 +405,15 @@ message WipeDevice {
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message LoadDevice {
|
message LoadDevice {
|
||||||
optional string mnemonic = 1; // seed encoded as BIP-39 mnemonic (12, 18 or 24 words)
|
repeated string mnemonics = 1; // seed encoded as mnemonic (12, 18 or 24 words for BIP39, 20 or 33 for SLIP39)
|
||||||
optional hw.trezor.messages.common.HDNodeType node = 2; // BIP-32 node
|
optional string pin = 3; // set PIN protection
|
||||||
optional string pin = 3; // set PIN protection
|
optional bool passphrase_protection = 4; // enable master node encryption using passphrase
|
||||||
optional bool passphrase_protection = 4; // enable master node encryption using passphrase
|
optional string language = 5 [deprecated=true]; // deprecated (use ChangeLanguage)
|
||||||
optional string language = 5 [default='english']; // device language
|
optional string label = 6; // device label
|
||||||
optional string label = 6; // device label
|
optional bool skip_checksum = 7; // do not test mnemonic for valid BIP-39 checksum
|
||||||
optional bool skip_checksum = 7; // do not test mnemonic for valid BIP-39 checksum
|
optional uint32 u2f_counter = 8; // U2F counter
|
||||||
optional uint32 u2f_counter = 8; // U2F counter
|
optional bool needs_backup = 9; // set "needs backup" flag
|
||||||
|
optional bool no_backup = 10; // indicate that no backup is going to be made
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -188,15 +423,17 @@ message LoadDevice {
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message ResetDevice {
|
message ResetDevice {
|
||||||
optional bool display_random = 1; // display entropy generated by the device before asking for additional entropy
|
reserved 1; // unused display_random
|
||||||
optional uint32 strength = 2 [default=256]; // strength of seed in bits
|
optional uint32 strength = 2 [default=256]; // strength of seed in bits
|
||||||
optional bool passphrase_protection = 3; // enable master node encryption using passphrase
|
optional bool passphrase_protection = 3; // enable master node encryption using passphrase
|
||||||
optional bool pin_protection = 4; // enable PIN protection
|
optional bool pin_protection = 4; // enable PIN protection
|
||||||
optional string language = 5 [default='english']; // device language
|
optional string language = 5 [deprecated=true]; // deprecated (use ChangeLanguage)
|
||||||
optional string label = 6; // device label
|
optional string label = 6; // device label
|
||||||
optional uint32 u2f_counter = 7; // U2F counter
|
optional uint32 u2f_counter = 7; // U2F counter
|
||||||
optional bool skip_backup = 8; // postpone seed backup to BackupDevice workflow
|
optional bool skip_backup = 8; // postpone seed backup to BackupDevice workflow
|
||||||
optional bool no_backup = 9; // indicate that no backup is going to be made
|
optional bool no_backup = 9; // indicate that no backup is going to be made
|
||||||
|
optional BackupType backup_type = 10 [default=Bip39]; // type of the mnemonic backup
|
||||||
|
optional bool entropy_check = 11; // run with entropy check protocol
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -205,6 +442,12 @@ message ResetDevice {
|
||||||
* @next Success
|
* @next Success
|
||||||
*/
|
*/
|
||||||
message BackupDevice {
|
message BackupDevice {
|
||||||
|
optional uint32 group_threshold = 1;
|
||||||
|
message Slip39Group {
|
||||||
|
required uint32 member_threshold = 1;
|
||||||
|
required uint32 member_count = 2;
|
||||||
|
}
|
||||||
|
repeated Slip39Group groups = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -212,14 +455,34 @@ message BackupDevice {
|
||||||
* @next EntropyAck
|
* @next EntropyAck
|
||||||
*/
|
*/
|
||||||
message EntropyRequest {
|
message EntropyRequest {
|
||||||
|
optional bytes entropy_commitment = 1; // HMAC-SHA256 of Trezor's internal entropy used in entropy check.
|
||||||
|
optional bytes prev_entropy = 2; // Trezor's internal entropy from the previous round of entropy check.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request: Provide additional entropy for seed generation function
|
* Request: Provide additional entropy for seed generation function
|
||||||
* @next Success
|
* @next Success
|
||||||
|
* @next EntropyCheckReady
|
||||||
*/
|
*/
|
||||||
message EntropyAck {
|
message EntropyAck {
|
||||||
optional bytes entropy = 1; // 256 bits (32 bytes) of random data
|
required bytes entropy = 1; // 256 bits (32 bytes) of the host's random data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response: Trezor is ready for the next phase of the entropy check protocol.
|
||||||
|
* @next EntropyCheckContinue
|
||||||
|
* @next GetPublicKey
|
||||||
|
*/
|
||||||
|
message EntropyCheckReady {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Proceed with the next phase of the entropy check protocol, asking Trezor to either reveal its internal entropy or to finish and store the seed.
|
||||||
|
* @next Success
|
||||||
|
* @next EntropyRequest
|
||||||
|
*/
|
||||||
|
message EntropyCheckContinue {
|
||||||
|
optional bool finish = 1 [default=false]; // finish the entropy check protocol, store the seed
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -229,29 +492,35 @@ message EntropyAck {
|
||||||
* @next WordRequest
|
* @next WordRequest
|
||||||
*/
|
*/
|
||||||
message RecoveryDevice {
|
message RecoveryDevice {
|
||||||
optional uint32 word_count = 1; // number of words in BIP-39 mnemonic
|
optional uint32 word_count = 1; // number of words in BIP-39 mnemonic (T1 only)
|
||||||
optional bool passphrase_protection = 2; // enable master node encryption using passphrase
|
optional bool passphrase_protection = 2; // enable master node encryption using passphrase
|
||||||
optional bool pin_protection = 3; // enable PIN protection
|
optional bool pin_protection = 3; // enable PIN protection
|
||||||
optional string language = 4 [default='english']; // device language
|
optional string language = 4 [deprecated=true]; // deprecated (use ChangeLanguage)
|
||||||
optional string label = 5; // device label
|
optional string label = 5; // device label
|
||||||
optional bool enforce_wordlist = 6; // enforce BIP-39 wordlist during the process
|
optional bool enforce_wordlist = 6; // enforce BIP-39 wordlist during the process (T1 only)
|
||||||
// 7 reserved for unused recovery method
|
reserved 7; // unused recovery method
|
||||||
optional RecoveryDeviceType type = 8; // supported recovery type
|
optional RecoveryDeviceInputMethod input_method = 8; // supported recovery input method (T1 only)
|
||||||
optional uint32 u2f_counter = 9; // U2F counter
|
optional uint32 u2f_counter = 9; // U2F counter
|
||||||
optional bool dry_run = 10; // perform dry-run recovery workflow (for safe mnemonic validation)
|
optional RecoveryType type = 10 [default=NormalRecovery]; // the type of recovery to perform
|
||||||
/**
|
/**
|
||||||
* Type of recovery procedure. These should be used as bitmask, e.g.,
|
* Type of recovery procedure. These should be used as bitmask, e.g.,
|
||||||
* `RecoveryDeviceType_ScrambledWords | RecoveryDeviceType_Matrix`
|
* `RecoveryDeviceInputMethod_ScrambledWords | RecoveryDeviceInputMethod_Matrix`
|
||||||
* listing every method supported by the host computer.
|
* listing every method supported by the host computer.
|
||||||
*
|
*
|
||||||
* Note that ScrambledWords must be supported by every implementation
|
* Note that ScrambledWords must be supported by every implementation
|
||||||
* for backward compatibility; there is no way to not support it.
|
* for backward compatibility; there is no way to not support it.
|
||||||
*/
|
*/
|
||||||
enum RecoveryDeviceType {
|
enum RecoveryDeviceInputMethod {
|
||||||
// use powers of two when extending this field
|
// use powers of two when extending this field
|
||||||
RecoveryDeviceType_ScrambledWords = 0; // words in scrambled order
|
ScrambledWords = 0; // words in scrambled order
|
||||||
RecoveryDeviceType_Matrix = 1; // matrix recovery type
|
Matrix = 1; // matrix recovery type
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RecoveryType {
|
||||||
|
NormalRecovery = 0; // recovery from seedphrase on an uninitialized device
|
||||||
|
DryRun = 1; // mnemonic validation
|
||||||
|
UnlockRepeatedBackup = 2; // unlock SLIP-39 repeated backup
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -260,15 +529,15 @@ message RecoveryDevice {
|
||||||
* @next WordAck
|
* @next WordAck
|
||||||
*/
|
*/
|
||||||
message WordRequest {
|
message WordRequest {
|
||||||
optional WordRequestType type = 1;
|
required WordRequestType type = 1;
|
||||||
/**
|
/**
|
||||||
* Type of Recovery Word request
|
* Type of Recovery Word request
|
||||||
*/
|
*/
|
||||||
enum WordRequestType {
|
enum WordRequestType {
|
||||||
WordRequestType_Plain = 0;
|
WordRequestType_Plain = 0;
|
||||||
WordRequestType_Matrix9 = 1;
|
WordRequestType_Matrix9 = 1;
|
||||||
WordRequestType_Matrix6 = 2;
|
WordRequestType_Matrix6 = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -278,7 +547,7 @@ message WordRequest {
|
||||||
* @next Failure
|
* @next Failure
|
||||||
*/
|
*/
|
||||||
message WordAck {
|
message WordAck {
|
||||||
required string word = 1; // one word of mnemonic on asked position
|
required string word = 1; // one word of mnemonic on asked position
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -287,5 +556,137 @@ message WordAck {
|
||||||
* @next Success
|
* @next Success
|
||||||
*/
|
*/
|
||||||
message SetU2FCounter {
|
message SetU2FCounter {
|
||||||
optional uint32 u2f_counter = 1; // counter
|
required uint32 u2f_counter = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Set U2F counter
|
||||||
|
* @start
|
||||||
|
* @next NextU2FCounter
|
||||||
|
*/
|
||||||
|
message GetNextU2FCounter {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Set U2F counter
|
||||||
|
* @end
|
||||||
|
*/
|
||||||
|
message NextU2FCounter {
|
||||||
|
required uint32 u2f_counter = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Ask device to prepare for a preauthorized operation.
|
||||||
|
* @start
|
||||||
|
* @next PreauthorizedRequest
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message DoPreauthorized {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Device awaits a preauthorized operation.
|
||||||
|
* @start
|
||||||
|
* @next SignTx
|
||||||
|
* @next GetOwnershipProof
|
||||||
|
*/
|
||||||
|
message PreauthorizedRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Cancel any outstanding authorization in the current session.
|
||||||
|
* @start
|
||||||
|
* @next Success
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message CancelAuthorization {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Reboot firmware to bootloader
|
||||||
|
* @start
|
||||||
|
* @next Success
|
||||||
|
* @next DataChunkRequest
|
||||||
|
*/
|
||||||
|
message RebootToBootloader {
|
||||||
|
// Action to be performed after rebooting to bootloader
|
||||||
|
optional BootCommand boot_command = 1 [default=STOP_AND_WAIT];
|
||||||
|
// Firmware header to be flashed after rebooting to bootloader
|
||||||
|
optional bytes firmware_header = 2;
|
||||||
|
// Length of language blob to be installed before upgrading firmware
|
||||||
|
optional uint32 language_data_length = 3 [default=0];
|
||||||
|
|
||||||
|
enum BootCommand {
|
||||||
|
// Go to bootloader menu
|
||||||
|
STOP_AND_WAIT = 0;
|
||||||
|
// Connect to host and wait for firmware update
|
||||||
|
INSTALL_UPGRADE = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Ask device to generate a random nonce and store it in the session's cache
|
||||||
|
* @start
|
||||||
|
* @next Nonce
|
||||||
|
*/
|
||||||
|
message GetNonce {
|
||||||
|
option (experimental_message) = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response: Contains a random nonce
|
||||||
|
* @end
|
||||||
|
*/
|
||||||
|
message Nonce {
|
||||||
|
option (experimental_message) = true;
|
||||||
|
|
||||||
|
required bytes nonce = 1; // a 32-byte random value generated by Trezor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Ask device to unlock a subtree of the keychain.
|
||||||
|
* @start
|
||||||
|
* @next UnlockedPathRequest
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message UnlockPath {
|
||||||
|
repeated uint32 address_n = 1; // prefix of the BIP-32 path leading to the account (m / purpose')
|
||||||
|
optional bytes mac = 2; // the MAC returned by UnlockedPathRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Device awaits an operation.
|
||||||
|
* @start
|
||||||
|
* @next SignTx
|
||||||
|
* @next GetPublicKey
|
||||||
|
* @next GetAddress
|
||||||
|
*/
|
||||||
|
message UnlockedPathRequest {
|
||||||
|
required bytes mac = 1; // authentication code for future UnlockPath calls
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Show tutorial screens on the device
|
||||||
|
* @start
|
||||||
|
* @next Success
|
||||||
|
*/
|
||||||
|
message ShowDeviceTutorial {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Unlocks bootloader, !irreversible!
|
||||||
|
* @start
|
||||||
|
* @next Success
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message UnlockBootloader {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Set device brightness
|
||||||
|
* @start
|
||||||
|
* @next Success
|
||||||
|
*/
|
||||||
|
message SetBrightness {
|
||||||
|
optional uint32 value = 1; // if not specified, let the user choose
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,12 +1,12 @@
|
||||||
// This file originates from the SatoshiLabs Trezor `common` repository at:
|
// This file originates from the SatoshiLabs Trezor `common` repository at:
|
||||||
// https://github.com/trezor/trezor-common/blob/master/protob/messages.proto
|
// https://github.com/trezor/trezor-common/blob/master/protob/messages.proto
|
||||||
// dated 28.05.2019, commit 893fd219d4a01bcffa0cd9cfa631856371ec5aa9.
|
// dated 30.06.2025, commit 421b45d4677f2499234692b0f54010bc45b3ae5f.
|
||||||
|
|
||||||
syntax = "proto2";
|
syntax = "proto2";
|
||||||
package hw.trezor.messages;
|
package hw.trezor.messages;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Messages for TREZOR communication
|
* Messages for Trezor communication
|
||||||
*/
|
*/
|
||||||
|
|
||||||
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||||
|
|
@ -15,253 +15,348 @@ option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor"
|
||||||
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
||||||
option java_outer_classname = "TrezorMessage";
|
option java_outer_classname = "TrezorMessage";
|
||||||
|
|
||||||
|
import "options.proto";
|
||||||
|
|
||||||
import "google/protobuf/descriptor.proto";
|
option (include_in_bitcoin_only) = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options for specifying message direction and type of wire (normal/debug)
|
* Mapping between Trezor wire identifier (uint) and a protobuf message
|
||||||
*/
|
|
||||||
extend google.protobuf.EnumValueOptions {
|
|
||||||
optional bool wire_in = 50002; // message can be transmitted via wire from PC to TREZOR
|
|
||||||
optional bool wire_out = 50003; // message can be transmitted via wire from TREZOR to PC
|
|
||||||
optional bool wire_debug_in = 50004; // message can be transmitted via debug wire from PC to TREZOR
|
|
||||||
optional bool wire_debug_out = 50005; // message can be transmitted via debug wire from TREZOR to PC
|
|
||||||
optional bool wire_tiny = 50006; // message is handled by TREZOR when the USB stack is in tiny mode
|
|
||||||
optional bool wire_bootloader = 50007; // message is only handled by TREZOR Bootloader
|
|
||||||
optional bool wire_no_fsm = 50008; // message is not handled by TREZOR unless the USB stack is in tiny mode
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mapping between TREZOR wire identifier (uint) and a protobuf message
|
|
||||||
*/
|
*/
|
||||||
enum MessageType {
|
enum MessageType {
|
||||||
|
option (has_bitcoin_only_values) = true;
|
||||||
|
|
||||||
// Management
|
// Management
|
||||||
MessageType_Initialize = 0 [(wire_in) = true, (wire_tiny) = true];
|
MessageType_Initialize = 0 [(bitcoin_only) = true, (wire_in) = true, (wire_tiny) = true];
|
||||||
MessageType_Ping = 1 [(wire_in) = true];
|
MessageType_Ping = 1 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_Success = 2 [(wire_out) = true];
|
MessageType_Success = 2 [(bitcoin_only) = true, (wire_out) = true, (wire_debug_out) = true];
|
||||||
MessageType_Failure = 3 [(wire_out) = true];
|
MessageType_Failure = 3 [(bitcoin_only) = true, (wire_out) = true, (wire_debug_out) = true];
|
||||||
MessageType_ChangePin = 4 [(wire_in) = true];
|
MessageType_ChangePin = 4 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_WipeDevice = 5 [(wire_in) = true];
|
MessageType_WipeDevice = 5 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_GetEntropy = 9 [(wire_in) = true];
|
MessageType_GetEntropy = 9 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_Entropy = 10 [(wire_out) = true];
|
MessageType_Entropy = 10 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
MessageType_LoadDevice = 13 [(wire_in) = true];
|
MessageType_LoadDevice = 13 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_ResetDevice = 14 [(wire_in) = true];
|
MessageType_ResetDevice = 14 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_Features = 17 [(wire_out) = true];
|
MessageType_SetBusy = 16 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_PinMatrixRequest = 18 [(wire_out) = true];
|
MessageType_Features = 17 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
MessageType_PinMatrixAck = 19 [(wire_in) = true, (wire_tiny) = true, (wire_no_fsm) = true];
|
MessageType_PinMatrixRequest = 18 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
MessageType_Cancel = 20 [(wire_in) = true, (wire_tiny) = true];
|
MessageType_PinMatrixAck = 19 [(bitcoin_only) = true, (wire_in) = true, (wire_tiny) = true, (wire_no_fsm) = true];
|
||||||
MessageType_ClearSession = 24 [(wire_in) = true];
|
MessageType_Cancel = 20 [(bitcoin_only) = true, (wire_in) = true, (wire_tiny) = true];
|
||||||
MessageType_ApplySettings = 25 [(wire_in) = true];
|
MessageType_LockDevice = 24 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_ButtonRequest = 26 [(wire_out) = true];
|
MessageType_ApplySettings = 25 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_ButtonAck = 27 [(wire_in) = true, (wire_tiny) = true, (wire_no_fsm) = true];
|
MessageType_ButtonRequest = 26 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
MessageType_ApplyFlags = 28 [(wire_in) = true];
|
MessageType_ButtonAck = 27 [(bitcoin_only) = true, (wire_in) = true, (wire_tiny) = true, (wire_no_fsm) = true];
|
||||||
MessageType_BackupDevice = 34 [(wire_in) = true];
|
MessageType_ApplyFlags = 28 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_EntropyRequest = 35 [(wire_out) = true];
|
MessageType_GetNonce = 31 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_EntropyAck = 36 [(wire_in) = true];
|
MessageType_Nonce = 33 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
MessageType_PassphraseRequest = 41 [(wire_out) = true];
|
MessageType_BackupDevice = 34 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_PassphraseAck = 42 [(wire_in) = true, (wire_tiny) = true, (wire_no_fsm) = true];
|
MessageType_EntropyRequest = 35 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
MessageType_PassphraseStateRequest = 77 [(wire_out) = true];
|
MessageType_EntropyAck = 36 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_PassphraseStateAck = 78 [(wire_in) = true, (wire_tiny) = true, (wire_no_fsm) = true];
|
MessageType_EntropyCheckReady = 994 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
MessageType_RecoveryDevice = 45 [(wire_in) = true];
|
MessageType_EntropyCheckContinue = 995 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_WordRequest = 46 [(wire_out) = true];
|
MessageType_PassphraseRequest = 41 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
MessageType_WordAck = 47 [(wire_in) = true];
|
MessageType_PassphraseAck = 42 [(bitcoin_only) = true, (wire_in) = true, (wire_tiny) = true, (wire_no_fsm) = true];
|
||||||
MessageType_GetFeatures = 55 [(wire_in) = true];
|
MessageType_RecoveryDevice = 45 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_SetU2FCounter = 63 [(wire_in) = true];
|
MessageType_WordRequest = 46 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
|
MessageType_WordAck = 47 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_GetFeatures = 55 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_SdProtect = 79 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_ChangeWipeCode = 82 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_EndSession = 83 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_DoPreauthorized = 84 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_PreauthorizedRequest = 85 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
|
MessageType_CancelAuthorization = 86 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_RebootToBootloader = 87 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_GetFirmwareHash = 88 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_FirmwareHash = 89 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
|
reserved 90 to 92;
|
||||||
|
MessageType_UnlockPath = 93 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_UnlockedPathRequest = 94 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
|
MessageType_ShowDeviceTutorial = 95 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_UnlockBootloader = 96 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_AuthenticateDevice = 97 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
|
MessageType_AuthenticityProof = 98 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_ChangeLanguage = 990 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_DataChunkRequest = 991 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
|
MessageType_DataChunkAck = 992 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_SetBrightness = 993 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
|
||||||
// Bootloader
|
MessageType_SetU2FCounter = 63 [(wire_in) = true];
|
||||||
MessageType_FirmwareErase = 6 [(wire_in) = true, (wire_bootloader) = true];
|
MessageType_GetNextU2FCounter = 80 [(wire_in) = true];
|
||||||
MessageType_FirmwareUpload = 7 [(wire_in) = true, (wire_bootloader) = true];
|
MessageType_NextU2FCounter = 81 [(wire_out) = true];
|
||||||
MessageType_FirmwareRequest = 8 [(wire_out) = true, (wire_bootloader) = true];
|
|
||||||
MessageType_SelfTest = 32 [(wire_in) = true, (wire_bootloader) = true];
|
|
||||||
|
|
||||||
// Bitcoin
|
// Deprecated messages, kept for protobuf compatibility.
|
||||||
MessageType_GetPublicKey = 11 [(wire_in) = true];
|
MessageType_Deprecated_PassphraseStateRequest = 77 [deprecated = true];
|
||||||
MessageType_PublicKey = 12 [(wire_out) = true];
|
MessageType_Deprecated_PassphraseStateAck = 78 [deprecated = true];
|
||||||
MessageType_SignTx = 15 [(wire_in) = true];
|
|
||||||
MessageType_TxRequest = 21 [(wire_out) = true];
|
|
||||||
MessageType_TxAck = 22 [(wire_in) = true];
|
|
||||||
MessageType_GetAddress = 29 [(wire_in) = true];
|
|
||||||
MessageType_Address = 30 [(wire_out) = true];
|
|
||||||
MessageType_SignMessage = 38 [(wire_in) = true];
|
|
||||||
MessageType_VerifyMessage = 39 [(wire_in) = true];
|
|
||||||
MessageType_MessageSignature = 40 [(wire_out) = true];
|
|
||||||
|
|
||||||
// Crypto
|
// Bootloader
|
||||||
MessageType_CipherKeyValue = 23 [(wire_in) = true];
|
MessageType_FirmwareErase = 6 [(bitcoin_only) = true, (wire_in) = true, (wire_bootloader) = true];
|
||||||
MessageType_CipheredKeyValue = 48 [(wire_out) = true];
|
MessageType_FirmwareUpload = 7 [(bitcoin_only) = true, (wire_in) = true, (wire_bootloader) = true];
|
||||||
MessageType_SignIdentity = 53 [(wire_in) = true];
|
MessageType_FirmwareRequest = 8 [(bitcoin_only) = true, (wire_out) = true, (wire_bootloader) = true];
|
||||||
MessageType_SignedIdentity = 54 [(wire_out) = true];
|
MessageType_ProdTestT1 = 32 [(bitcoin_only) = true, (wire_in) = true, (wire_bootloader) = true];
|
||||||
MessageType_GetECDHSessionKey = 61 [(wire_in) = true];
|
|
||||||
MessageType_ECDHSessionKey = 62 [(wire_out) = true];
|
|
||||||
MessageType_CosiCommit = 71 [(wire_in) = true];
|
|
||||||
MessageType_CosiCommitment = 72 [(wire_out) = true];
|
|
||||||
MessageType_CosiSign = 73 [(wire_in) = true];
|
|
||||||
MessageType_CosiSignature = 74 [(wire_out) = true];
|
|
||||||
|
|
||||||
// Debug
|
// BLE
|
||||||
MessageType_DebugLinkDecision = 100 [(wire_debug_in) = true, (wire_tiny) = true, (wire_no_fsm) = true];
|
MessageType_BleUnpair = 8001 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_DebugLinkGetState = 101 [(wire_debug_in) = true, (wire_tiny) = true];
|
|
||||||
MessageType_DebugLinkState = 102 [(wire_debug_out) = true];
|
|
||||||
MessageType_DebugLinkStop = 103 [(wire_debug_in) = true];
|
|
||||||
MessageType_DebugLinkLog = 104 [(wire_debug_out) = true];
|
|
||||||
MessageType_DebugLinkMemoryRead = 110 [(wire_debug_in) = true];
|
|
||||||
MessageType_DebugLinkMemory = 111 [(wire_debug_out) = true];
|
|
||||||
MessageType_DebugLinkMemoryWrite = 112 [(wire_debug_in) = true];
|
|
||||||
MessageType_DebugLinkFlashErase = 113 [(wire_debug_in) = true];
|
|
||||||
|
|
||||||
// Ethereum
|
// Bitcoin
|
||||||
MessageType_EthereumGetPublicKey = 450 [(wire_in) = true];
|
MessageType_GetPublicKey = 11 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_EthereumPublicKey = 451 [(wire_out) = true];
|
MessageType_PublicKey = 12 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
MessageType_EthereumGetAddress = 56 [(wire_in) = true];
|
MessageType_SignTx = 15 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_EthereumAddress = 57 [(wire_out) = true];
|
MessageType_TxRequest = 21 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
MessageType_EthereumSignTx = 58 [(wire_in) = true];
|
MessageType_TxAck = 22 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_EthereumTxRequest = 59 [(wire_out) = true];
|
MessageType_GetAddress = 29 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_EthereumTxAck = 60 [(wire_in) = true];
|
MessageType_Address = 30 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
MessageType_EthereumSignMessage = 64 [(wire_in) = true];
|
MessageType_TxAckPaymentRequest = 37 [(wire_in) = true];
|
||||||
MessageType_EthereumVerifyMessage = 65 [(wire_in) = true];
|
MessageType_SignMessage = 38 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_EthereumMessageSignature = 66 [(wire_out) = true];
|
MessageType_VerifyMessage = 39 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_MessageSignature = 40 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
|
MessageType_GetOwnershipId = 43 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_OwnershipId = 44 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
|
MessageType_GetOwnershipProof = 49 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_OwnershipProof = 50 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
|
MessageType_AuthorizeCoinJoin = 51 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
|
||||||
// NEM
|
// Crypto
|
||||||
MessageType_NEMGetAddress = 67 [(wire_in) = true];
|
MessageType_CipherKeyValue = 23 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_NEMAddress = 68 [(wire_out) = true];
|
MessageType_CipheredKeyValue = 48 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
MessageType_NEMSignTx = 69 [(wire_in) = true];
|
MessageType_SignIdentity = 53 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_NEMSignedTx = 70 [(wire_out) = true];
|
MessageType_SignedIdentity = 54 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
MessageType_NEMDecryptMessage = 75 [(wire_in) = true];
|
MessageType_GetECDHSessionKey = 61 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_NEMDecryptedMessage = 76 [(wire_out) = true];
|
MessageType_ECDHSessionKey = 62 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
|
// dropped: CosiCommit, CosiCommitment, CosiSign, CosiSignature
|
||||||
|
reserved 71 to 74;
|
||||||
|
|
||||||
// Lisk
|
// Debug
|
||||||
MessageType_LiskGetAddress = 114 [(wire_in) = true];
|
MessageType_DebugLinkDecision = 100 [(bitcoin_only) = true, (wire_debug_in) = true, (wire_tiny) = true, (wire_no_fsm) = true];
|
||||||
MessageType_LiskAddress = 115 [(wire_out) = true];
|
MessageType_DebugLinkGetState = 101 [(bitcoin_only) = true, (wire_debug_in) = true, (wire_tiny) = true];
|
||||||
MessageType_LiskSignTx = 116 [(wire_in) = true];
|
MessageType_DebugLinkState = 102 [(bitcoin_only) = true, (wire_debug_out) = true];
|
||||||
MessageType_LiskSignedTx = 117 [(wire_out) = true];
|
MessageType_DebugLinkStop = 103 [(bitcoin_only) = true, (wire_debug_in) = true];
|
||||||
MessageType_LiskSignMessage = 118 [(wire_in) = true];
|
MessageType_DebugLinkLog = 104 [(bitcoin_only) = true, (wire_debug_out) = true];
|
||||||
MessageType_LiskMessageSignature = 119 [(wire_out) = true];
|
MessageType_DebugLinkMemoryRead = 110 [(bitcoin_only) = true, (wire_debug_in) = true];
|
||||||
MessageType_LiskVerifyMessage = 120 [(wire_in) = true];
|
MessageType_DebugLinkMemory = 111 [(bitcoin_only) = true, (wire_debug_out) = true];
|
||||||
MessageType_LiskGetPublicKey = 121 [(wire_in) = true];
|
MessageType_DebugLinkMemoryWrite = 112 [(bitcoin_only) = true, (wire_debug_in) = true];
|
||||||
MessageType_LiskPublicKey = 122 [(wire_out) = true];
|
MessageType_DebugLinkFlashErase = 113 [(bitcoin_only) = true, (wire_debug_in) = true];
|
||||||
|
MessageType_DebugLinkLayout = 9001 [(bitcoin_only) = true, (wire_debug_out) = true];
|
||||||
|
MessageType_DebugLinkReseedRandom = 9002 [(bitcoin_only) = true, (wire_debug_in) = true];
|
||||||
|
MessageType_DebugLinkRecordScreen = 9003 [(bitcoin_only) = true, (wire_debug_in) = true];
|
||||||
|
MessageType_DebugLinkEraseSdCard = 9005 [(bitcoin_only) = true, (wire_debug_in) = true];
|
||||||
|
MessageType_DebugLinkWatchLayout = 9006 [(bitcoin_only) = true, (wire_debug_in) = true];
|
||||||
|
MessageType_DebugLinkResetDebugEvents = 9007 [(bitcoin_only) = true, (wire_debug_in) = true];
|
||||||
|
MessageType_DebugLinkOptigaSetSecMax = 9008 [(bitcoin_only) = true, (wire_debug_in) = true];
|
||||||
|
MessageType_DebugLinkGetGcInfo = 9009 [(bitcoin_only) = true, (wire_debug_in) = true];
|
||||||
|
MessageType_DebugLinkGcInfo = 9010 [(bitcoin_only) = true, (wire_debug_out) = true];
|
||||||
|
MessageType_DebugLinkGetPairingInfo = 9011 [(bitcoin_only) = true, (wire_debug_in) = true];
|
||||||
|
MessageType_DebugLinkPairingInfo = 9012 [(bitcoin_only) = true, (wire_debug_out) = true];
|
||||||
|
|
||||||
// Tezos
|
// Ethereum
|
||||||
MessageType_TezosGetAddress = 150 [(wire_in) = true];
|
MessageType_EthereumGetPublicKey = 450 [(wire_in) = true];
|
||||||
MessageType_TezosAddress = 151 [(wire_out) = true];
|
MessageType_EthereumPublicKey = 451 [(wire_out) = true];
|
||||||
MessageType_TezosSignTx = 152 [(wire_in) = true];
|
MessageType_EthereumGetAddress = 56 [(wire_in) = true];
|
||||||
MessageType_TezosSignedTx = 153 [(wire_out) = true];
|
MessageType_EthereumAddress = 57 [(wire_out) = true];
|
||||||
MessageType_TezosGetPublicKey = 154 [(wire_in) = true];
|
MessageType_EthereumSignTx = 58 [(wire_in) = true];
|
||||||
MessageType_TezosPublicKey = 155 [(wire_out) = true];
|
MessageType_EthereumSignTxEIP1559 = 452 [(wire_in) = true];
|
||||||
|
MessageType_EthereumTxRequest = 59 [(wire_out) = true];
|
||||||
|
MessageType_EthereumTxAck = 60 [(wire_in) = true];
|
||||||
|
MessageType_EthereumSignMessage = 64 [(wire_in) = true];
|
||||||
|
MessageType_EthereumVerifyMessage = 65 [(wire_in) = true];
|
||||||
|
MessageType_EthereumMessageSignature = 66 [(wire_out) = true];
|
||||||
|
MessageType_EthereumSignTypedData = 464 [(wire_in) = true];
|
||||||
|
MessageType_EthereumTypedDataStructRequest = 465 [(wire_out) = true];
|
||||||
|
MessageType_EthereumTypedDataStructAck = 466 [(wire_in) = true];
|
||||||
|
MessageType_EthereumTypedDataValueRequest = 467 [(wire_out) = true];
|
||||||
|
MessageType_EthereumTypedDataValueAck = 468 [(wire_in) = true];
|
||||||
|
MessageType_EthereumTypedDataSignature = 469 [(wire_out) = true];
|
||||||
|
MessageType_EthereumSignTypedHash = 470 [(wire_in) = true];
|
||||||
|
|
||||||
// Stellar
|
// NEM
|
||||||
MessageType_StellarSignTx = 202 [(wire_in) = true];
|
MessageType_NEMGetAddress = 67 [(wire_in) = true];
|
||||||
MessageType_StellarTxOpRequest = 203 [(wire_out) = true];
|
MessageType_NEMAddress = 68 [(wire_out) = true];
|
||||||
MessageType_StellarGetAddress = 207 [(wire_in) = true];
|
MessageType_NEMSignTx = 69 [(wire_in) = true];
|
||||||
MessageType_StellarAddress = 208 [(wire_out) = true];
|
MessageType_NEMSignedTx = 70 [(wire_out) = true];
|
||||||
MessageType_StellarCreateAccountOp = 210 [(wire_in) = true];
|
MessageType_NEMDecryptMessage = 75 [(wire_in) = true];
|
||||||
MessageType_StellarPaymentOp = 211 [(wire_in) = true];
|
MessageType_NEMDecryptedMessage = 76 [(wire_out) = true];
|
||||||
MessageType_StellarPathPaymentOp = 212 [(wire_in) = true];
|
|
||||||
MessageType_StellarManageOfferOp = 213 [(wire_in) = true];
|
|
||||||
MessageType_StellarCreatePassiveOfferOp = 214 [(wire_in) = true];
|
|
||||||
MessageType_StellarSetOptionsOp = 215 [(wire_in) = true];
|
|
||||||
MessageType_StellarChangeTrustOp = 216 [(wire_in) = true];
|
|
||||||
MessageType_StellarAllowTrustOp = 217 [(wire_in) = true];
|
|
||||||
MessageType_StellarAccountMergeOp = 218 [(wire_in) = true];
|
|
||||||
// omitted: StellarInflationOp is not a supported operation, would be 219
|
|
||||||
MessageType_StellarManageDataOp = 220 [(wire_in) = true];
|
|
||||||
MessageType_StellarBumpSequenceOp = 221 [(wire_in) = true];
|
|
||||||
MessageType_StellarSignedTx = 230 [(wire_out) = true];
|
|
||||||
|
|
||||||
// TRON
|
// Lisk
|
||||||
MessageType_TronGetAddress = 250 [(wire_in) = true];
|
/*
|
||||||
MessageType_TronAddress = 251 [(wire_out) = true];
|
MessageType_LiskGetAddress = 114 [(wire_in) = true];
|
||||||
MessageType_TronSignTx = 252 [(wire_in) = true];
|
MessageType_LiskAddress = 115 [(wire_out) = true];
|
||||||
MessageType_TronSignedTx = 253 [(wire_out) = true];
|
MessageType_LiskSignTx = 116 [(wire_in) = true];
|
||||||
|
MessageType_LiskSignedTx = 117 [(wire_out) = true];
|
||||||
|
MessageType_LiskSignMessage = 118 [(wire_in) = true];
|
||||||
|
MessageType_LiskMessageSignature = 119 [(wire_out) = true];
|
||||||
|
MessageType_LiskVerifyMessage = 120 [(wire_in) = true];
|
||||||
|
MessageType_LiskGetPublicKey = 121 [(wire_in) = true];
|
||||||
|
MessageType_LiskPublicKey = 122 [(wire_out) = true];
|
||||||
|
*/
|
||||||
|
reserved 114 to 122;
|
||||||
|
|
||||||
// Cardano
|
// Tezos
|
||||||
// dropped Sign/VerifyMessage ids 300-302
|
MessageType_TezosGetAddress = 150 [(wire_in) = true];
|
||||||
MessageType_CardanoSignTx = 303 [(wire_in) = true];
|
MessageType_TezosAddress = 151 [(wire_out) = true];
|
||||||
MessageType_CardanoTxRequest = 304 [(wire_out) = true];
|
MessageType_TezosSignTx = 152 [(wire_in) = true];
|
||||||
MessageType_CardanoGetPublicKey = 305 [(wire_in) = true];
|
MessageType_TezosSignedTx = 153 [(wire_out) = true];
|
||||||
MessageType_CardanoPublicKey = 306 [(wire_out) = true];
|
MessageType_TezosGetPublicKey = 154 [(wire_in) = true];
|
||||||
MessageType_CardanoGetAddress = 307 [(wire_in) = true];
|
MessageType_TezosPublicKey = 155 [(wire_out) = true];
|
||||||
MessageType_CardanoAddress = 308 [(wire_out) = true];
|
|
||||||
MessageType_CardanoTxAck = 309 [(wire_in) = true];
|
|
||||||
MessageType_CardanoSignedTx = 310 [(wire_out) = true];
|
|
||||||
|
|
||||||
// Ontology
|
// Stellar
|
||||||
MessageType_OntologyGetAddress = 350 [(wire_in) = true];
|
MessageType_StellarSignTx = 202 [(wire_in) = true];
|
||||||
MessageType_OntologyAddress = 351 [(wire_out) = true];
|
MessageType_StellarTxOpRequest = 203 [(wire_out) = true];
|
||||||
MessageType_OntologyGetPublicKey = 352 [(wire_in) = true];
|
MessageType_StellarGetAddress = 207 [(wire_in) = true];
|
||||||
MessageType_OntologyPublicKey = 353 [(wire_out) = true];
|
MessageType_StellarAddress = 208 [(wire_out) = true];
|
||||||
MessageType_OntologySignTransfer = 354 [(wire_in) = true];
|
MessageType_StellarCreateAccountOp = 210 [(wire_in) = true];
|
||||||
MessageType_OntologySignedTransfer = 355 [(wire_out) = true];
|
MessageType_StellarPaymentOp = 211 [(wire_in) = true];
|
||||||
MessageType_OntologySignWithdrawOng = 356 [(wire_in) = true];
|
MessageType_StellarPathPaymentStrictReceiveOp = 212 [(wire_in) = true];
|
||||||
MessageType_OntologySignedWithdrawOng = 357 [(wire_out) = true];
|
MessageType_StellarManageSellOfferOp = 213 [(wire_in) = true];
|
||||||
MessageType_OntologySignOntIdRegister = 358 [(wire_in) = true];
|
MessageType_StellarCreatePassiveSellOfferOp = 214 [(wire_in) = true];
|
||||||
MessageType_OntologySignedOntIdRegister = 359 [(wire_out) = true];
|
MessageType_StellarSetOptionsOp = 215 [(wire_in) = true];
|
||||||
MessageType_OntologySignOntIdAddAttributes = 360 [(wire_in) = true];
|
MessageType_StellarChangeTrustOp = 216 [(wire_in) = true];
|
||||||
MessageType_OntologySignedOntIdAddAttributes = 361 [(wire_out) = true];
|
MessageType_StellarAllowTrustOp = 217 [(wire_in) = true];
|
||||||
|
MessageType_StellarAccountMergeOp = 218 [(wire_in) = true];
|
||||||
|
reserved 219; // omitted: StellarInflationOp
|
||||||
|
MessageType_StellarManageDataOp = 220 [(wire_in) = true];
|
||||||
|
MessageType_StellarBumpSequenceOp = 221 [(wire_in) = true];
|
||||||
|
MessageType_StellarManageBuyOfferOp = 222 [(wire_in) = true];
|
||||||
|
MessageType_StellarPathPaymentStrictSendOp = 223 [(wire_in) = true];
|
||||||
|
reserved 224; // omitted: StellarCreateClaimableBalanceOp
|
||||||
|
MessageType_StellarClaimClaimableBalanceOp = 225 [(wire_in) = true];
|
||||||
|
MessageType_StellarSignedTx = 230 [(wire_out) = true];
|
||||||
|
|
||||||
// Ripple
|
// Cardano
|
||||||
MessageType_RippleGetAddress = 400 [(wire_in) = true];
|
// dropped Sign/VerifyMessage ids 300-302
|
||||||
MessageType_RippleAddress = 401 [(wire_out) = true];
|
// dropped TxRequest/TxAck ids 304 and 309 (shelley update)
|
||||||
MessageType_RippleSignTx = 402 [(wire_in) = true];
|
// dropped SignTx/SignedTx/SignedTxChunk/SignedTxChunkAck ids 303, 310, 311 and 312
|
||||||
MessageType_RippleSignedTx = 403 [(wire_in) = true];
|
reserved 300 to 304, 309 to 312;
|
||||||
|
MessageType_CardanoGetPublicKey = 305 [(wire_in) = true];
|
||||||
|
MessageType_CardanoPublicKey = 306 [(wire_out) = true];
|
||||||
|
MessageType_CardanoGetAddress = 307 [(wire_in) = true];
|
||||||
|
MessageType_CardanoAddress = 308 [(wire_out) = true];
|
||||||
|
MessageType_CardanoTxItemAck = 313 [(wire_out) = true];
|
||||||
|
MessageType_CardanoTxAuxiliaryDataSupplement = 314 [(wire_out) = true];
|
||||||
|
MessageType_CardanoTxWitnessRequest = 315 [(wire_in) = true];
|
||||||
|
MessageType_CardanoTxWitnessResponse = 316 [(wire_out) = true];
|
||||||
|
MessageType_CardanoTxHostAck = 317 [(wire_in) = true];
|
||||||
|
MessageType_CardanoTxBodyHash = 318 [(wire_out) = true];
|
||||||
|
MessageType_CardanoSignTxFinished = 319 [(wire_out) = true];
|
||||||
|
MessageType_CardanoSignTxInit = 320 [(wire_in) = true];
|
||||||
|
MessageType_CardanoTxInput = 321 [(wire_in) = true];
|
||||||
|
MessageType_CardanoTxOutput = 322 [(wire_in) = true];
|
||||||
|
MessageType_CardanoAssetGroup = 323 [(wire_in) = true];
|
||||||
|
MessageType_CardanoToken = 324 [(wire_in) = true];
|
||||||
|
MessageType_CardanoTxCertificate = 325 [(wire_in) = true];
|
||||||
|
MessageType_CardanoTxWithdrawal = 326 [(wire_in) = true];
|
||||||
|
MessageType_CardanoTxAuxiliaryData = 327 [(wire_in) = true];
|
||||||
|
MessageType_CardanoPoolOwner = 328 [(wire_in) = true];
|
||||||
|
MessageType_CardanoPoolRelayParameters = 329 [(wire_in) = true];
|
||||||
|
MessageType_CardanoGetNativeScriptHash = 330 [(wire_in) = true];
|
||||||
|
MessageType_CardanoNativeScriptHash = 331 [(wire_out) = true];
|
||||||
|
MessageType_CardanoTxMint = 332 [(wire_in) = true];
|
||||||
|
MessageType_CardanoTxCollateralInput = 333 [(wire_in) = true];
|
||||||
|
MessageType_CardanoTxRequiredSigner = 334 [(wire_in) = true];
|
||||||
|
MessageType_CardanoTxInlineDatumChunk = 335 [(wire_in) = true];
|
||||||
|
MessageType_CardanoTxReferenceScriptChunk = 336 [(wire_in) = true];
|
||||||
|
MessageType_CardanoTxReferenceInput = 337 [(wire_in) = true];
|
||||||
|
|
||||||
// Monero
|
// Ripple
|
||||||
MessageType_MoneroTransactionInitRequest = 501 [(wire_out) = true];
|
MessageType_RippleGetAddress = 400 [(wire_in) = true];
|
||||||
MessageType_MoneroTransactionInitAck = 502 [(wire_out) = true];
|
MessageType_RippleAddress = 401 [(wire_out) = true];
|
||||||
MessageType_MoneroTransactionSetInputRequest = 503 [(wire_out) = true];
|
MessageType_RippleSignTx = 402 [(wire_in) = true];
|
||||||
MessageType_MoneroTransactionSetInputAck = 504 [(wire_out) = true];
|
MessageType_RippleSignedTx = 403 [(wire_in) = true];
|
||||||
MessageType_MoneroTransactionInputsPermutationRequest = 505 [(wire_out) = true];
|
|
||||||
MessageType_MoneroTransactionInputsPermutationAck = 506 [(wire_out) = true];
|
|
||||||
MessageType_MoneroTransactionInputViniRequest = 507 [(wire_out) = true];
|
|
||||||
MessageType_MoneroTransactionInputViniAck = 508 [(wire_out) = true];
|
|
||||||
MessageType_MoneroTransactionAllInputsSetRequest = 509 [(wire_out) = true];
|
|
||||||
MessageType_MoneroTransactionAllInputsSetAck = 510 [(wire_out) = true];
|
|
||||||
MessageType_MoneroTransactionSetOutputRequest = 511 [(wire_out) = true];
|
|
||||||
MessageType_MoneroTransactionSetOutputAck = 512 [(wire_out) = true];
|
|
||||||
MessageType_MoneroTransactionAllOutSetRequest = 513 [(wire_out) = true];
|
|
||||||
MessageType_MoneroTransactionAllOutSetAck = 514 [(wire_out) = true];
|
|
||||||
MessageType_MoneroTransactionSignInputRequest = 515 [(wire_out) = true];
|
|
||||||
MessageType_MoneroTransactionSignInputAck = 516 [(wire_out) = true];
|
|
||||||
MessageType_MoneroTransactionFinalRequest = 517 [(wire_out) = true];
|
|
||||||
MessageType_MoneroTransactionFinalAck = 518 [(wire_out) = true];
|
|
||||||
MessageType_MoneroKeyImageExportInitRequest = 530 [(wire_out) = true];
|
|
||||||
MessageType_MoneroKeyImageExportInitAck = 531 [(wire_out) = true];
|
|
||||||
MessageType_MoneroKeyImageSyncStepRequest = 532 [(wire_out) = true];
|
|
||||||
MessageType_MoneroKeyImageSyncStepAck = 533 [(wire_out) = true];
|
|
||||||
MessageType_MoneroKeyImageSyncFinalRequest = 534 [(wire_out) = true];
|
|
||||||
MessageType_MoneroKeyImageSyncFinalAck = 535 [(wire_out) = true];
|
|
||||||
MessageType_MoneroGetAddress = 540 [(wire_in) = true];
|
|
||||||
MessageType_MoneroAddress = 541 [(wire_out) = true];
|
|
||||||
MessageType_MoneroGetWatchKey = 542 [(wire_in) = true];
|
|
||||||
MessageType_MoneroWatchKey = 543 [(wire_out) = true];
|
|
||||||
MessageType_DebugMoneroDiagRequest = 546 [(wire_in) = true];
|
|
||||||
MessageType_DebugMoneroDiagAck = 547 [(wire_out) = true];
|
|
||||||
MessageType_MoneroGetTxKeyRequest = 550 [(wire_in) = true];
|
|
||||||
MessageType_MoneroGetTxKeyAck = 551 [(wire_out) = true];
|
|
||||||
MessageType_MoneroLiveRefreshStartRequest = 552 [(wire_in) = true];
|
|
||||||
MessageType_MoneroLiveRefreshStartAck = 553 [(wire_out) = true];
|
|
||||||
MessageType_MoneroLiveRefreshStepRequest = 554 [(wire_in) = true];
|
|
||||||
MessageType_MoneroLiveRefreshStepAck = 555 [(wire_out) = true];
|
|
||||||
MessageType_MoneroLiveRefreshFinalRequest = 556 [(wire_in) = true];
|
|
||||||
MessageType_MoneroLiveRefreshFinalAck = 557 [(wire_out) = true];
|
|
||||||
|
|
||||||
// EOS
|
// Monero
|
||||||
MessageType_EosGetPublicKey = 600 [(wire_in) = true];
|
MessageType_MoneroTransactionInitRequest = 501 [(wire_out) = true];
|
||||||
MessageType_EosPublicKey = 601 [(wire_out) = true];
|
MessageType_MoneroTransactionInitAck = 502 [(wire_out) = true];
|
||||||
MessageType_EosSignTx = 602 [(wire_in) = true];
|
MessageType_MoneroTransactionSetInputRequest = 503 [(wire_out) = true];
|
||||||
MessageType_EosTxActionRequest = 603 [(wire_out) = true];
|
MessageType_MoneroTransactionSetInputAck = 504 [(wire_out) = true];
|
||||||
MessageType_EosTxActionAck = 604 [(wire_in) = true];
|
MessageType_MoneroTransactionInputViniRequest = 507 [(wire_out) = true];
|
||||||
MessageType_EosSignedTx = 605 [(wire_out) = true];
|
MessageType_MoneroTransactionInputViniAck = 508 [(wire_out) = true];
|
||||||
|
MessageType_MoneroTransactionAllInputsSetRequest = 509 [(wire_out) = true];
|
||||||
|
MessageType_MoneroTransactionAllInputsSetAck = 510 [(wire_out) = true];
|
||||||
|
MessageType_MoneroTransactionSetOutputRequest = 511 [(wire_out) = true];
|
||||||
|
MessageType_MoneroTransactionSetOutputAck = 512 [(wire_out) = true];
|
||||||
|
MessageType_MoneroTransactionAllOutSetRequest = 513 [(wire_out) = true];
|
||||||
|
MessageType_MoneroTransactionAllOutSetAck = 514 [(wire_out) = true];
|
||||||
|
MessageType_MoneroTransactionSignInputRequest = 515 [(wire_out) = true];
|
||||||
|
MessageType_MoneroTransactionSignInputAck = 516 [(wire_out) = true];
|
||||||
|
MessageType_MoneroTransactionFinalRequest = 517 [(wire_out) = true];
|
||||||
|
MessageType_MoneroTransactionFinalAck = 518 [(wire_out) = true];
|
||||||
|
MessageType_MoneroKeyImageExportInitRequest = 530 [(wire_out) = true];
|
||||||
|
MessageType_MoneroKeyImageExportInitAck = 531 [(wire_out) = true];
|
||||||
|
MessageType_MoneroKeyImageSyncStepRequest = 532 [(wire_out) = true];
|
||||||
|
MessageType_MoneroKeyImageSyncStepAck = 533 [(wire_out) = true];
|
||||||
|
MessageType_MoneroKeyImageSyncFinalRequest = 534 [(wire_out) = true];
|
||||||
|
MessageType_MoneroKeyImageSyncFinalAck = 535 [(wire_out) = true];
|
||||||
|
MessageType_MoneroGetAddress = 540 [(wire_in) = true];
|
||||||
|
MessageType_MoneroAddress = 541 [(wire_out) = true];
|
||||||
|
MessageType_MoneroGetWatchKey = 542 [(wire_in) = true];
|
||||||
|
MessageType_MoneroWatchKey = 543 [(wire_out) = true];
|
||||||
|
MessageType_DebugMoneroDiagRequest = 546 [(wire_in) = true];
|
||||||
|
MessageType_DebugMoneroDiagAck = 547 [(wire_out) = true];
|
||||||
|
MessageType_MoneroGetTxKeyRequest = 550 [(wire_in) = true];
|
||||||
|
MessageType_MoneroGetTxKeyAck = 551 [(wire_out) = true];
|
||||||
|
MessageType_MoneroLiveRefreshStartRequest = 552 [(wire_in) = true];
|
||||||
|
MessageType_MoneroLiveRefreshStartAck = 553 [(wire_out) = true];
|
||||||
|
MessageType_MoneroLiveRefreshStepRequest = 554 [(wire_in) = true];
|
||||||
|
MessageType_MoneroLiveRefreshStepAck = 555 [(wire_out) = true];
|
||||||
|
MessageType_MoneroLiveRefreshFinalRequest = 556 [(wire_in) = true];
|
||||||
|
MessageType_MoneroLiveRefreshFinalAck = 557 [(wire_out) = true];
|
||||||
|
|
||||||
// Binance
|
// EOS
|
||||||
MessageType_BinanceGetAddress = 700 [(wire_in) = true];
|
MessageType_EosGetPublicKey = 600 [(wire_in) = true];
|
||||||
MessageType_BinanceAddress = 701 [(wire_out) = true];
|
MessageType_EosPublicKey = 601 [(wire_out) = true];
|
||||||
MessageType_BinanceGetPublicKey = 702 [(wire_in) = true];
|
MessageType_EosSignTx = 602 [(wire_in) = true];
|
||||||
MessageType_BinancePublicKey = 703 [(wire_out) = true];
|
MessageType_EosTxActionRequest = 603 [(wire_out) = true];
|
||||||
MessageType_BinanceSignTx = 704 [(wire_in) = true];
|
MessageType_EosTxActionAck = 604 [(wire_in) = true];
|
||||||
MessageType_BinanceTxRequest = 705 [(wire_out) = true];
|
MessageType_EosSignedTx = 605 [(wire_out) = true];
|
||||||
MessageType_BinanceTransferMsg = 706 [(wire_in) = true];
|
|
||||||
MessageType_BinanceOrderMsg = 707 [(wire_in) = true];
|
// BNB Beacon Chain (deprecated)
|
||||||
MessageType_BinanceCancelMsg = 708 [(wire_in) = true];
|
reserved 700 to 709;
|
||||||
MessageType_BinanceSignedTx = 709 [(wire_out) = true];
|
|
||||||
}
|
// WebAuthn
|
||||||
|
MessageType_WebAuthnListResidentCredentials = 800 [(wire_in) = true];
|
||||||
|
MessageType_WebAuthnCredentials = 801 [(wire_out) = true];
|
||||||
|
MessageType_WebAuthnAddResidentCredential = 802 [(wire_in) = true];
|
||||||
|
MessageType_WebAuthnRemoveResidentCredential = 803 [(wire_in) = true];
|
||||||
|
|
||||||
|
// Solana
|
||||||
|
MessageType_SolanaGetPublicKey = 900 [(wire_in) = true];
|
||||||
|
MessageType_SolanaPublicKey = 901 [(wire_out) = true];
|
||||||
|
MessageType_SolanaGetAddress = 902 [(wire_in) = true];
|
||||||
|
MessageType_SolanaAddress = 903 [(wire_out) = true];
|
||||||
|
MessageType_SolanaSignTx = 904 [(wire_in) = true];
|
||||||
|
MessageType_SolanaTxSignature = 905 [(wire_out) = true];
|
||||||
|
|
||||||
|
// THP
|
||||||
|
MessageType_ThpCreateNewSession = 1000 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
reserved 1001 to 1005; // never appeared in a release, reserved for future use
|
||||||
|
MessageType_ThpPairingRequest = 1006 [(bitcoin_only) = true];
|
||||||
|
MessageType_ThpPairingRequestApproved = 1007 [(bitcoin_only) = true];
|
||||||
|
MessageType_ThpSelectMethod = 1008 [(bitcoin_only) = true];
|
||||||
|
MessageType_ThpPairingPreparationsFinished = 1009 [(bitcoin_only) = true];
|
||||||
|
MessageType_ThpCredentialRequest = 1010 [(bitcoin_only) = true];
|
||||||
|
MessageType_ThpCredentialResponse = 1011 [(bitcoin_only) = true];
|
||||||
|
MessageType_ThpEndRequest = 1012 [(bitcoin_only) = true];
|
||||||
|
MessageType_ThpEndResponse = 1013 [(bitcoin_only) = true];
|
||||||
|
reserved 1014 to 1015;
|
||||||
|
MessageType_ThpCodeEntryCommitment = 1016 [(bitcoin_only) = true];
|
||||||
|
MessageType_ThpCodeEntryChallenge = 1017 [(bitcoin_only) = true];
|
||||||
|
MessageType_ThpCodeEntryCpaceTrezor = 1018 [(bitcoin_only) = true];
|
||||||
|
MessageType_ThpCodeEntryCpaceHostTag = 1019 [(bitcoin_only) = true];
|
||||||
|
MessageType_ThpCodeEntrySecret = 1020 [(bitcoin_only) = true];
|
||||||
|
reserved 1021 to 1023;
|
||||||
|
MessageType_ThpQrCodeTag = 1024 [(bitcoin_only) = true];
|
||||||
|
MessageType_ThpQrCodeSecret = 1025 [(bitcoin_only) = true];
|
||||||
|
reserved 1026 to 1031;
|
||||||
|
MessageType_ThpNfcTagHost = 1032 [(bitcoin_only) = true];
|
||||||
|
MessageType_ThpNfcTagTrezor = 1033 [(bitcoin_only) = true];
|
||||||
|
|
||||||
|
// Nostr
|
||||||
|
MessageType_NostrGetPubkey = 2001 [(wire_in) = true];
|
||||||
|
MessageType_NostrPubkey = 2002 [(wire_out) = true];
|
||||||
|
MessageType_NostrSignEvent = 2003 [(wire_in) = true];
|
||||||
|
MessageType_NostrEventSignature = 2004 [(wire_out) = true];
|
||||||
|
|
||||||
|
// Benchmark
|
||||||
|
MessageType_BenchmarkListNames = 9100 [(bitcoin_only) = true];
|
||||||
|
MessageType_BenchmarkNames = 9101 [(bitcoin_only) = true];
|
||||||
|
MessageType_BenchmarkRun = 9102 [(bitcoin_only) = true];
|
||||||
|
MessageType_BenchmarkResult = 9103 [(bitcoin_only) = true];
|
||||||
|
}
|
||||||
264
accounts/usbwallet/trezor/options.pb.go
Normal file
264
accounts/usbwallet/trezor/options.pb.go
Normal file
|
|
@ -0,0 +1,264 @@
|
||||||
|
// This file originates from the SatoshiLabs Trezor `common` repository at:
|
||||||
|
// https://github.com/trezor/trezor-common/blob/master/protob/options.proto
|
||||||
|
// dated 30.06.2025, commit 421b45d4677f2499234692b0f54010bc45b3ae5f.
|
||||||
|
|
||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.36.6
|
||||||
|
// protoc v4.25.3
|
||||||
|
// source: options.proto
|
||||||
|
|
||||||
|
package trezor
|
||||||
|
|
||||||
|
import (
|
||||||
|
reflect "reflect"
|
||||||
|
unsafe "unsafe"
|
||||||
|
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
descriptorpb "google.golang.org/protobuf/types/descriptorpb"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
var file_options_proto_extTypes = []protoimpl.ExtensionInfo{
|
||||||
|
{
|
||||||
|
ExtendedType: (*descriptorpb.EnumValueOptions)(nil),
|
||||||
|
ExtensionType: (*bool)(nil),
|
||||||
|
Field: 50002,
|
||||||
|
Name: "hw.trezor.messages.wire_in",
|
||||||
|
Tag: "varint,50002,opt,name=wire_in",
|
||||||
|
Filename: "options.proto",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExtendedType: (*descriptorpb.EnumValueOptions)(nil),
|
||||||
|
ExtensionType: (*bool)(nil),
|
||||||
|
Field: 50003,
|
||||||
|
Name: "hw.trezor.messages.wire_out",
|
||||||
|
Tag: "varint,50003,opt,name=wire_out",
|
||||||
|
Filename: "options.proto",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExtendedType: (*descriptorpb.EnumValueOptions)(nil),
|
||||||
|
ExtensionType: (*bool)(nil),
|
||||||
|
Field: 50004,
|
||||||
|
Name: "hw.trezor.messages.wire_debug_in",
|
||||||
|
Tag: "varint,50004,opt,name=wire_debug_in",
|
||||||
|
Filename: "options.proto",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExtendedType: (*descriptorpb.EnumValueOptions)(nil),
|
||||||
|
ExtensionType: (*bool)(nil),
|
||||||
|
Field: 50005,
|
||||||
|
Name: "hw.trezor.messages.wire_debug_out",
|
||||||
|
Tag: "varint,50005,opt,name=wire_debug_out",
|
||||||
|
Filename: "options.proto",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExtendedType: (*descriptorpb.EnumValueOptions)(nil),
|
||||||
|
ExtensionType: (*bool)(nil),
|
||||||
|
Field: 50006,
|
||||||
|
Name: "hw.trezor.messages.wire_tiny",
|
||||||
|
Tag: "varint,50006,opt,name=wire_tiny",
|
||||||
|
Filename: "options.proto",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExtendedType: (*descriptorpb.EnumValueOptions)(nil),
|
||||||
|
ExtensionType: (*bool)(nil),
|
||||||
|
Field: 50007,
|
||||||
|
Name: "hw.trezor.messages.wire_bootloader",
|
||||||
|
Tag: "varint,50007,opt,name=wire_bootloader",
|
||||||
|
Filename: "options.proto",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExtendedType: (*descriptorpb.EnumValueOptions)(nil),
|
||||||
|
ExtensionType: (*bool)(nil),
|
||||||
|
Field: 50008,
|
||||||
|
Name: "hw.trezor.messages.wire_no_fsm",
|
||||||
|
Tag: "varint,50008,opt,name=wire_no_fsm",
|
||||||
|
Filename: "options.proto",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExtendedType: (*descriptorpb.EnumValueOptions)(nil),
|
||||||
|
ExtensionType: (*bool)(nil),
|
||||||
|
Field: 60000,
|
||||||
|
Name: "hw.trezor.messages.bitcoin_only",
|
||||||
|
Tag: "varint,60000,opt,name=bitcoin_only",
|
||||||
|
Filename: "options.proto",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExtendedType: (*descriptorpb.EnumOptions)(nil),
|
||||||
|
ExtensionType: (*bool)(nil),
|
||||||
|
Field: 51001,
|
||||||
|
Name: "hw.trezor.messages.has_bitcoin_only_values",
|
||||||
|
Tag: "varint,51001,opt,name=has_bitcoin_only_values",
|
||||||
|
Filename: "options.proto",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExtendedType: (*descriptorpb.MessageOptions)(nil),
|
||||||
|
ExtensionType: (*bool)(nil),
|
||||||
|
Field: 52001,
|
||||||
|
Name: "hw.trezor.messages.experimental_message",
|
||||||
|
Tag: "varint,52001,opt,name=experimental_message",
|
||||||
|
Filename: "options.proto",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExtendedType: (*descriptorpb.MessageOptions)(nil),
|
||||||
|
ExtensionType: (*uint32)(nil),
|
||||||
|
Field: 52002,
|
||||||
|
Name: "hw.trezor.messages.wire_type",
|
||||||
|
Tag: "varint,52002,opt,name=wire_type",
|
||||||
|
Filename: "options.proto",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExtendedType: (*descriptorpb.MessageOptions)(nil),
|
||||||
|
ExtensionType: (*bool)(nil),
|
||||||
|
Field: 52003,
|
||||||
|
Name: "hw.trezor.messages.internal_only",
|
||||||
|
Tag: "varint,52003,opt,name=internal_only",
|
||||||
|
Filename: "options.proto",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExtendedType: (*descriptorpb.FieldOptions)(nil),
|
||||||
|
ExtensionType: (*bool)(nil),
|
||||||
|
Field: 53001,
|
||||||
|
Name: "hw.trezor.messages.experimental_field",
|
||||||
|
Tag: "varint,53001,opt,name=experimental_field",
|
||||||
|
Filename: "options.proto",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExtendedType: (*descriptorpb.FileOptions)(nil),
|
||||||
|
ExtensionType: (*bool)(nil),
|
||||||
|
Field: 60000,
|
||||||
|
Name: "hw.trezor.messages.include_in_bitcoin_only",
|
||||||
|
Tag: "varint,60000,opt,name=include_in_bitcoin_only",
|
||||||
|
Filename: "options.proto",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extension fields to descriptorpb.EnumValueOptions.
|
||||||
|
var (
|
||||||
|
// optional bool wire_in = 50002;
|
||||||
|
E_WireIn = &file_options_proto_extTypes[0] // message can be transmitted via wire from PC to Trezor
|
||||||
|
// optional bool wire_out = 50003;
|
||||||
|
E_WireOut = &file_options_proto_extTypes[1] // message can be transmitted via wire from Trezor to PC
|
||||||
|
// optional bool wire_debug_in = 50004;
|
||||||
|
E_WireDebugIn = &file_options_proto_extTypes[2] // message can be transmitted via debug wire from PC to Trezor
|
||||||
|
// optional bool wire_debug_out = 50005;
|
||||||
|
E_WireDebugOut = &file_options_proto_extTypes[3] // message can be transmitted via debug wire from Trezor to PC
|
||||||
|
// optional bool wire_tiny = 50006;
|
||||||
|
E_WireTiny = &file_options_proto_extTypes[4] // message is handled by Trezor when the USB stack is in tiny mode
|
||||||
|
// optional bool wire_bootloader = 50007;
|
||||||
|
E_WireBootloader = &file_options_proto_extTypes[5] // message is only handled by Trezor Bootloader
|
||||||
|
// optional bool wire_no_fsm = 50008;
|
||||||
|
E_WireNoFsm = &file_options_proto_extTypes[6] // message is not handled by Trezor unless the USB stack is in tiny mode
|
||||||
|
// optional bool bitcoin_only = 60000;
|
||||||
|
E_BitcoinOnly = &file_options_proto_extTypes[7] // enum value is available on BITCOIN_ONLY build
|
||||||
|
)
|
||||||
|
|
||||||
|
// Extension fields to descriptorpb.EnumOptions.
|
||||||
|
var (
|
||||||
|
// optional bool has_bitcoin_only_values = 51001;
|
||||||
|
E_HasBitcoinOnlyValues = &file_options_proto_extTypes[8] // indicate that some values should be excluded on BITCOIN_ONLY builds
|
||||||
|
)
|
||||||
|
|
||||||
|
// Extension fields to descriptorpb.MessageOptions.
|
||||||
|
var (
|
||||||
|
// optional bool experimental_message = 52001;
|
||||||
|
E_ExperimentalMessage = &file_options_proto_extTypes[9] // indicate that a message is intended for development and beta testing only and its definition may change at any time
|
||||||
|
// optional uint32 wire_type = 52002;
|
||||||
|
E_WireType = &file_options_proto_extTypes[10] // override wire type specified in the MessageType enum
|
||||||
|
// optional bool internal_only = 52003;
|
||||||
|
E_InternalOnly = &file_options_proto_extTypes[11] // indicate that a message is intended for internal use only and should not be transmitted via the wire
|
||||||
|
)
|
||||||
|
|
||||||
|
// Extension fields to descriptorpb.FieldOptions.
|
||||||
|
var (
|
||||||
|
// optional bool experimental_field = 53001;
|
||||||
|
E_ExperimentalField = &file_options_proto_extTypes[12] // indicate that a field is intended for development and beta testing only
|
||||||
|
)
|
||||||
|
|
||||||
|
// Extension fields to descriptorpb.FileOptions.
|
||||||
|
var (
|
||||||
|
// optional bool include_in_bitcoin_only = 60000;
|
||||||
|
E_IncludeInBitcoinOnly = &file_options_proto_extTypes[13] // definitions are available on BITCOIN_ONLY build
|
||||||
|
)
|
||||||
|
|
||||||
|
var File_options_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
const file_options_proto_rawDesc = "" +
|
||||||
|
"\n" +
|
||||||
|
"\roptions.proto\x12\x12hw.trezor.messages\x1a google/protobuf/descriptor.proto:<\n" +
|
||||||
|
"\awire_in\x12!.google.protobuf.EnumValueOptions\x18҆\x03 \x01(\bR\x06wireIn:>\n" +
|
||||||
|
"\bwire_out\x12!.google.protobuf.EnumValueOptions\x18ӆ\x03 \x01(\bR\awireOut:G\n" +
|
||||||
|
"\rwire_debug_in\x12!.google.protobuf.EnumValueOptions\x18Ԇ\x03 \x01(\bR\vwireDebugIn:I\n" +
|
||||||
|
"\x0ewire_debug_out\x12!.google.protobuf.EnumValueOptions\x18Ն\x03 \x01(\bR\fwireDebugOut:@\n" +
|
||||||
|
"\twire_tiny\x12!.google.protobuf.EnumValueOptions\x18ֆ\x03 \x01(\bR\bwireTiny:L\n" +
|
||||||
|
"\x0fwire_bootloader\x12!.google.protobuf.EnumValueOptions\x18׆\x03 \x01(\bR\x0ewireBootloader:C\n" +
|
||||||
|
"\vwire_no_fsm\x12!.google.protobuf.EnumValueOptions\x18؆\x03 \x01(\bR\twireNoFsm:F\n" +
|
||||||
|
"\fbitcoin_only\x12!.google.protobuf.EnumValueOptions\x18\xe0\xd4\x03 \x01(\bR\vbitcoinOnly:U\n" +
|
||||||
|
"\x17has_bitcoin_only_values\x12\x1c.google.protobuf.EnumOptions\x18\xb9\x8e\x03 \x01(\bR\x14hasBitcoinOnlyValues:T\n" +
|
||||||
|
"\x14experimental_message\x12\x1f.google.protobuf.MessageOptions\x18\xa1\x96\x03 \x01(\bR\x13experimentalMessage:>\n" +
|
||||||
|
"\twire_type\x12\x1f.google.protobuf.MessageOptions\x18\xa2\x96\x03 \x01(\rR\bwireType:F\n" +
|
||||||
|
"\rinternal_only\x12\x1f.google.protobuf.MessageOptions\x18\xa3\x96\x03 \x01(\bR\finternalOnly:N\n" +
|
||||||
|
"\x12experimental_field\x12\x1d.google.protobuf.FieldOptions\x18\x89\x9e\x03 \x01(\bR\x11experimentalField:U\n" +
|
||||||
|
"\x17include_in_bitcoin_only\x12\x1c.google.protobuf.FileOptions\x18\xe0\xd4\x03 \x01(\bR\x14includeInBitcoinOnlyBo\n" +
|
||||||
|
"#com.satoshilabs.trezor.lib.protobufB\rTrezorOptionsZ9github.com/ethereum/go-ethereum/accounts/usbwallet/trezor"
|
||||||
|
|
||||||
|
var file_options_proto_goTypes = []any{
|
||||||
|
(*descriptorpb.EnumValueOptions)(nil), // 0: google.protobuf.EnumValueOptions
|
||||||
|
(*descriptorpb.EnumOptions)(nil), // 1: google.protobuf.EnumOptions
|
||||||
|
(*descriptorpb.MessageOptions)(nil), // 2: google.protobuf.MessageOptions
|
||||||
|
(*descriptorpb.FieldOptions)(nil), // 3: google.protobuf.FieldOptions
|
||||||
|
(*descriptorpb.FileOptions)(nil), // 4: google.protobuf.FileOptions
|
||||||
|
}
|
||||||
|
var file_options_proto_depIdxs = []int32{
|
||||||
|
0, // 0: hw.trezor.messages.wire_in:extendee -> google.protobuf.EnumValueOptions
|
||||||
|
0, // 1: hw.trezor.messages.wire_out:extendee -> google.protobuf.EnumValueOptions
|
||||||
|
0, // 2: hw.trezor.messages.wire_debug_in:extendee -> google.protobuf.EnumValueOptions
|
||||||
|
0, // 3: hw.trezor.messages.wire_debug_out:extendee -> google.protobuf.EnumValueOptions
|
||||||
|
0, // 4: hw.trezor.messages.wire_tiny:extendee -> google.protobuf.EnumValueOptions
|
||||||
|
0, // 5: hw.trezor.messages.wire_bootloader:extendee -> google.protobuf.EnumValueOptions
|
||||||
|
0, // 6: hw.trezor.messages.wire_no_fsm:extendee -> google.protobuf.EnumValueOptions
|
||||||
|
0, // 7: hw.trezor.messages.bitcoin_only:extendee -> google.protobuf.EnumValueOptions
|
||||||
|
1, // 8: hw.trezor.messages.has_bitcoin_only_values:extendee -> google.protobuf.EnumOptions
|
||||||
|
2, // 9: hw.trezor.messages.experimental_message:extendee -> google.protobuf.MessageOptions
|
||||||
|
2, // 10: hw.trezor.messages.wire_type:extendee -> google.protobuf.MessageOptions
|
||||||
|
2, // 11: hw.trezor.messages.internal_only:extendee -> google.protobuf.MessageOptions
|
||||||
|
3, // 12: hw.trezor.messages.experimental_field:extendee -> google.protobuf.FieldOptions
|
||||||
|
4, // 13: hw.trezor.messages.include_in_bitcoin_only:extendee -> google.protobuf.FileOptions
|
||||||
|
14, // [14:14] is the sub-list for method output_type
|
||||||
|
14, // [14:14] is the sub-list for method input_type
|
||||||
|
14, // [14:14] is the sub-list for extension type_name
|
||||||
|
0, // [0:14] is the sub-list for extension extendee
|
||||||
|
0, // [0:0] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_options_proto_init() }
|
||||||
|
func file_options_proto_init() {
|
||||||
|
if File_options_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_options_proto_rawDesc), len(file_options_proto_rawDesc)),
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 0,
|
||||||
|
NumExtensions: 14,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_options_proto_goTypes,
|
||||||
|
DependencyIndexes: file_options_proto_depIdxs,
|
||||||
|
ExtensionInfos: file_options_proto_extTypes,
|
||||||
|
}.Build()
|
||||||
|
File_options_proto = out.File
|
||||||
|
file_options_proto_goTypes = nil
|
||||||
|
file_options_proto_depIdxs = nil
|
||||||
|
}
|
||||||
72
accounts/usbwallet/trezor/options.proto
Normal file
72
accounts/usbwallet/trezor/options.proto
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
// This file originates from the SatoshiLabs Trezor `common` repository at:
|
||||||
|
// https://github.com/trezor/trezor-common/blob/master/protob/options.proto
|
||||||
|
// dated 30.06.2025, commit 421b45d4677f2499234692b0f54010bc45b3ae5f.
|
||||||
|
|
||||||
|
syntax = "proto2";
|
||||||
|
package hw.trezor.messages;
|
||||||
|
|
||||||
|
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||||
|
|
||||||
|
// Sugar for easier handling in Java
|
||||||
|
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
||||||
|
option java_outer_classname = "TrezorOptions";
|
||||||
|
|
||||||
|
import "google/protobuf/descriptor.proto";
|
||||||
|
|
||||||
|
/************************* WARNING ***********************
|
||||||
|
Due to the way extensions are accessed in pb2py, there needs to be a globally unique
|
||||||
|
name-ID mapping for extensions. That means that two different extensions, e.g. for
|
||||||
|
EnumValueOptions and FieldOptions, MUST NOT have the same ID.
|
||||||
|
|
||||||
|
Using the same ID indicates the same purpose (protobuf does not allow multiple
|
||||||
|
extensions with the same name), such as EnumValueOptions.bitcoin_only and
|
||||||
|
FileOptions.include_in_bitcoin_only. pb2py can then find the extension under
|
||||||
|
either name.
|
||||||
|
|
||||||
|
The convention to achieve this is as follows:
|
||||||
|
- extensions specific to a type have the same prefix:
|
||||||
|
* 50xxx for EnumValueOptions
|
||||||
|
* 51xxx for EnumOptions
|
||||||
|
* 52xxx for MessageOptions
|
||||||
|
* 53xxx for FieldOptions
|
||||||
|
- extensions that might be used across types have the same "global" prefix 60xxx
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options for specifying message direction and type of wire (normal/debug)
|
||||||
|
*/
|
||||||
|
extend google.protobuf.EnumValueOptions {
|
||||||
|
optional bool wire_in = 50002; // message can be transmitted via wire from PC to Trezor
|
||||||
|
optional bool wire_out = 50003; // message can be transmitted via wire from Trezor to PC
|
||||||
|
optional bool wire_debug_in = 50004; // message can be transmitted via debug wire from PC to Trezor
|
||||||
|
optional bool wire_debug_out = 50005; // message can be transmitted via debug wire from Trezor to PC
|
||||||
|
optional bool wire_tiny = 50006; // message is handled by Trezor when the USB stack is in tiny mode
|
||||||
|
optional bool wire_bootloader = 50007; // message is only handled by Trezor Bootloader
|
||||||
|
optional bool wire_no_fsm = 50008; // message is not handled by Trezor unless the USB stack is in tiny mode
|
||||||
|
|
||||||
|
optional bool bitcoin_only = 60000; // enum value is available on BITCOIN_ONLY build
|
||||||
|
// (messages not marked bitcoin_only will be EXCLUDED)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Options for tagging enum types */
|
||||||
|
extend google.protobuf.EnumOptions {
|
||||||
|
optional bool has_bitcoin_only_values = 51001; // indicate that some values should be excluded on BITCOIN_ONLY builds
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Options for tagging message types */
|
||||||
|
extend google.protobuf.MessageOptions {
|
||||||
|
optional bool experimental_message = 52001; // indicate that a message is intended for development and beta testing only and its definition may change at any time
|
||||||
|
optional uint32 wire_type = 52002; // override wire type specified in the MessageType enum
|
||||||
|
optional bool internal_only = 52003; // indicate that a message is intended for internal use only and should not be transmitted via the wire
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Options for tagging field types */
|
||||||
|
extend google.protobuf.FieldOptions {
|
||||||
|
optional bool experimental_field = 53001; // indicate that a field is intended for development and beta testing only
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Options for tagging files with protobuf definitions */
|
||||||
|
extend google.protobuf.FileOptions {
|
||||||
|
optional bool include_in_bitcoin_only = 60000; // definitions are available on BITCOIN_ONLY build
|
||||||
|
// intentionally identical to `bitcoin_only` from enum
|
||||||
|
}
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
// - Grab the latest Go plugin `go get -u google.golang.org/protobuf/cmd/protoc-gen-go`
|
// - Grab the latest Go plugin `go get -u google.golang.org/protobuf/cmd/protoc-gen-go`
|
||||||
// - Vendor in the latest Go plugin `govendor fetch google.golang.org/protobuf/...`
|
// - Vendor in the latest Go plugin `govendor fetch google.golang.org/protobuf/...`
|
||||||
|
|
||||||
//go:generate protoc -I/usr/local/include:. --go_out=paths=source_relative:. messages.proto messages-common.proto messages-management.proto messages-ethereum.proto
|
//go:generate protoc -I/usr/local/include:. --go_out=paths=source_relative:. options.proto messages.proto messages-common.proto messages-management.proto messages-ethereum.proto messages-ethereum-eip712.proto
|
||||||
|
|
||||||
// Package trezor contains the wire protocol.
|
// Package trezor contains the wire protocol.
|
||||||
package trezor
|
package trezor
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package usbwallet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
@ -31,7 +32,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/karalabe/hid"
|
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
||||||
|
"github.com/karalabe/usb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Maximum time between wallet health checks to detect USB unplugs.
|
// Maximum time between wallet health checks to detect USB unplugs.
|
||||||
|
|
@ -68,7 +70,17 @@ type driver interface {
|
||||||
// or deny the transaction.
|
// or deny the transaction.
|
||||||
SignTx(path accounts.DerivationPath, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error)
|
SignTx(path accounts.DerivationPath, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error)
|
||||||
|
|
||||||
SignTypedMessage(path accounts.DerivationPath, messageHash []byte, domainHash []byte) ([]byte, error)
|
// SignText sends a message to sign to the USB device and waits for the user to confirm
|
||||||
|
// or deny the signature.
|
||||||
|
SignText(path accounts.DerivationPath, text []byte) ([]byte, error)
|
||||||
|
|
||||||
|
// SignTypedHash sends a typed message to sign to the USB device and waits for the user to confirm
|
||||||
|
// or deny the signature.
|
||||||
|
SignTypedHash(path accounts.DerivationPath, messageHash []byte, domainHash []byte) ([]byte, error)
|
||||||
|
|
||||||
|
// SignedTypedData sends a typed data struct to sign to the USB device and waits for the user to confirm
|
||||||
|
// or deny the signature.
|
||||||
|
SignedTypedData(path accounts.DerivationPath, data apitypes.TypedData) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// wallet represents the common functionality shared by all USB hardware
|
// wallet represents the common functionality shared by all USB hardware
|
||||||
|
|
@ -79,8 +91,8 @@ type wallet struct {
|
||||||
driver driver // Hardware implementation of the low level device operations
|
driver driver // Hardware implementation of the low level device operations
|
||||||
url *accounts.URL // Textual URL uniquely identifying this wallet
|
url *accounts.URL // Textual URL uniquely identifying this wallet
|
||||||
|
|
||||||
info hid.DeviceInfo // Known USB device infos about the wallet
|
info usb.DeviceInfo // Known USB device infos about the wallet
|
||||||
device hid.Device // USB device advertising itself as a hardware wallet
|
device usb.Device // USB device advertising itself as a hardware wallet
|
||||||
|
|
||||||
accounts []accounts.Account // List of derive accounts pinned on the hardware wallet
|
accounts []accounts.Account // List of derive accounts pinned on the hardware wallet
|
||||||
paths map[common.Address]accounts.DerivationPath // Known derivation paths for signing operations
|
paths map[common.Address]accounts.DerivationPath // Known derivation paths for signing operations
|
||||||
|
|
@ -530,45 +542,29 @@ func (w *wallet) signHash(account accounts.Account, hash []byte) ([]byte, error)
|
||||||
|
|
||||||
// SignData signs keccak256(data). The mimetype parameter describes the type of data being signed
|
// SignData signs keccak256(data). The mimetype parameter describes the type of data being signed
|
||||||
func (w *wallet) SignData(account accounts.Account, mimeType string, data []byte) ([]byte, error) {
|
func (w *wallet) SignData(account accounts.Account, mimeType string, data []byte) ([]byte, error) {
|
||||||
// Unless we are doing 712 signing, simply dispatch to signHash
|
path, done, err := w.lockAndDerivePath(account)
|
||||||
if !(mimeType == accounts.MimetypeTypedData && len(data) == 66 && data[0] == 0x19 && data[1] == 0x01) {
|
|
||||||
return w.signHash(account, crypto.Keccak256(data))
|
|
||||||
}
|
|
||||||
|
|
||||||
// dispatch to 712 signing if the mimetype is TypedData and the format matches
|
|
||||||
w.stateLock.RLock() // Comms have own mutex, this is for the state fields
|
|
||||||
defer w.stateLock.RUnlock()
|
|
||||||
|
|
||||||
// If the wallet is closed, abort
|
|
||||||
if w.device == nil {
|
|
||||||
return nil, accounts.ErrWalletClosed
|
|
||||||
}
|
|
||||||
// Make sure the requested account is contained within
|
|
||||||
path, ok := w.paths[account.Address]
|
|
||||||
if !ok {
|
|
||||||
return nil, accounts.ErrUnknownAccount
|
|
||||||
}
|
|
||||||
// All infos gathered and metadata checks out, request signing
|
|
||||||
<-w.commsLock
|
|
||||||
defer func() { w.commsLock <- struct{}{} }()
|
|
||||||
|
|
||||||
// Ensure the device isn't screwed with while user confirmation is pending
|
|
||||||
// TODO(karalabe): remove if hotplug lands on Windows
|
|
||||||
w.hub.commsLock.Lock()
|
|
||||||
w.hub.commsPend++
|
|
||||||
w.hub.commsLock.Unlock()
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
w.hub.commsLock.Lock()
|
|
||||||
w.hub.commsPend--
|
|
||||||
w.hub.commsLock.Unlock()
|
|
||||||
}()
|
|
||||||
// Sign the transaction
|
|
||||||
signature, err := w.driver.SignTypedMessage(path, data[2:34], data[34:66])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return signature, nil
|
defer done()
|
||||||
|
|
||||||
|
if mimeType == accounts.MimetypeTypedData {
|
||||||
|
// If the data is exactly 66 bytes and starts with the 0x19 0x01 prefix, treat
|
||||||
|
// it as the raw EIP-712 hash pair (domain and message) to sign.
|
||||||
|
if len(data) == 66 && data[0] == 0x19 && data[1] == 0x01 {
|
||||||
|
return w.driver.SignTypedHash(path, data[2:34], data[34:66])
|
||||||
|
}
|
||||||
|
// Otherwise attempt to parse the data as a JSON encoded EIP-712 struct
|
||||||
|
// and sign it as such.
|
||||||
|
var typedData apitypes.TypedData
|
||||||
|
if err := json.Unmarshal(data, &typedData); err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid typed data: %w", err)
|
||||||
|
}
|
||||||
|
return w.driver.SignedTypedData(path, typedData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're not doing 712 signing, simply dispatch to signHash
|
||||||
|
return w.signHash(account, crypto.Keccak256(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignDataWithPassphrase implements accounts.Wallet, attempting to sign the given
|
// SignDataWithPassphrase implements accounts.Wallet, attempting to sign the given
|
||||||
|
|
@ -578,8 +574,21 @@ func (w *wallet) SignDataWithPassphrase(account accounts.Account, passphrase, mi
|
||||||
return w.SignData(account, mimeType, data)
|
return w.SignData(account, mimeType, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignText implements accounts.Wallet, signing the text as an EIP-712 personal
|
||||||
|
// message.
|
||||||
func (w *wallet) SignText(account accounts.Account, text []byte) ([]byte, error) {
|
func (w *wallet) SignText(account accounts.Account, text []byte) ([]byte, error) {
|
||||||
return w.signHash(account, accounts.TextHash(text))
|
path, done, err := w.lockAndDerivePath(account)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
// Sign the transaction
|
||||||
|
signature, err := w.driver.SignText(path, text)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return signature, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignTx implements accounts.Wallet. It sends the transaction over to the Ledger
|
// SignTx implements accounts.Wallet. It sends the transaction over to the Ledger
|
||||||
|
|
@ -590,33 +599,12 @@ func (w *wallet) SignText(account accounts.Account, text []byte) ([]byte, error)
|
||||||
// too old to sign EIP-155 transactions, but such is requested nonetheless, an error
|
// too old to sign EIP-155 transactions, but such is requested nonetheless, an error
|
||||||
// will be returned opposed to silently signing in Homestead mode.
|
// will be returned opposed to silently signing in Homestead mode.
|
||||||
func (w *wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
|
func (w *wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
|
||||||
w.stateLock.RLock() // Comms have own mutex, this is for the state fields
|
path, done, err := w.lockAndDerivePath(account)
|
||||||
defer w.stateLock.RUnlock()
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
// If the wallet is closed, abort
|
|
||||||
if w.device == nil {
|
|
||||||
return nil, accounts.ErrWalletClosed
|
|
||||||
}
|
}
|
||||||
// Make sure the requested account is contained within
|
defer done()
|
||||||
path, ok := w.paths[account.Address]
|
|
||||||
if !ok {
|
|
||||||
return nil, accounts.ErrUnknownAccount
|
|
||||||
}
|
|
||||||
// All infos gathered and metadata checks out, request signing
|
|
||||||
<-w.commsLock
|
|
||||||
defer func() { w.commsLock <- struct{}{} }()
|
|
||||||
|
|
||||||
// Ensure the device isn't screwed with while user confirmation is pending
|
|
||||||
// TODO(karalabe): remove if hotplug lands on Windows
|
|
||||||
w.hub.commsLock.Lock()
|
|
||||||
w.hub.commsPend++
|
|
||||||
w.hub.commsLock.Unlock()
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
w.hub.commsLock.Lock()
|
|
||||||
w.hub.commsPend--
|
|
||||||
w.hub.commsLock.Unlock()
|
|
||||||
}()
|
|
||||||
// Sign the transaction and verify the sender to avoid hardware fault surprises
|
// Sign the transaction and verify the sender to avoid hardware fault surprises
|
||||||
sender, signed, err := w.driver.SignTx(path, tx, chainID)
|
sender, signed, err := w.driver.SignTx(path, tx, chainID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -628,11 +616,10 @@ func (w *wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID
|
||||||
return signed, nil
|
return signed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignTextWithPassphrase implements accounts.Wallet, however signing arbitrary
|
// SignTextWithPassphrase implements accounts.Wallet, signing the text as an EIP-712
|
||||||
// data is not supported for Ledger wallets, so this method will always return
|
// personal message.
|
||||||
// an error.
|
|
||||||
func (w *wallet) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) {
|
func (w *wallet) SignTextWithPassphrase(account accounts.Account, passphrase string, text []byte) ([]byte, error) {
|
||||||
return w.SignText(account, accounts.TextHash(text))
|
return w.SignText(account, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given
|
// SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given
|
||||||
|
|
@ -641,3 +628,38 @@ func (w *wallet) SignTextWithPassphrase(account accounts.Account, passphrase str
|
||||||
func (w *wallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
|
func (w *wallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
|
||||||
return w.SignTx(account, tx, chainID)
|
return w.SignTx(account, tx, chainID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *wallet) lockAndDerivePath(account accounts.Account) (accounts.DerivationPath, func(), error) {
|
||||||
|
w.stateLock.RLock() // Comms have own mutex, this is for the state fields
|
||||||
|
|
||||||
|
// If the wallet is closed, abort
|
||||||
|
if w.device == nil {
|
||||||
|
w.stateLock.RUnlock()
|
||||||
|
return nil, nil, accounts.ErrWalletClosed
|
||||||
|
}
|
||||||
|
// Make sure the requested account is contained within
|
||||||
|
path, ok := w.paths[account.Address]
|
||||||
|
if !ok {
|
||||||
|
w.stateLock.RUnlock()
|
||||||
|
return nil, nil, accounts.ErrUnknownAccount
|
||||||
|
}
|
||||||
|
// All infos gathered and metadata checks out, request signing
|
||||||
|
<-w.commsLock
|
||||||
|
|
||||||
|
// Ensure the device isn't screwed with while user confirmation is pending
|
||||||
|
// TODO(karalabe): remove if hotplug lands on Windows
|
||||||
|
w.hub.commsLock.Lock()
|
||||||
|
w.hub.commsPend++
|
||||||
|
w.hub.commsLock.Unlock()
|
||||||
|
|
||||||
|
done := func() {
|
||||||
|
w.stateLock.RUnlock()
|
||||||
|
w.commsLock <- struct{}{}
|
||||||
|
|
||||||
|
w.hub.commsLock.Lock()
|
||||||
|
w.hub.commsPend--
|
||||||
|
w.hub.commsLock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
return path, done, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
4
go.mod
4
go.mod
|
|
@ -45,7 +45,7 @@ require (
|
||||||
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
|
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2
|
github.com/jackpal/go-nat-pmp v1.0.2
|
||||||
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267
|
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267
|
||||||
github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52
|
github.com/karalabe/usb v0.0.3-0.20231219215548-8627268f6b0a
|
||||||
github.com/kylelemons/godebug v1.1.0
|
github.com/kylelemons/godebug v1.1.0
|
||||||
github.com/mattn/go-colorable v0.1.13
|
github.com/mattn/go-colorable v0.1.13
|
||||||
github.com/mattn/go-isatty v0.0.20
|
github.com/mattn/go-isatty v0.0.20
|
||||||
|
|
@ -56,6 +56,7 @@ require (
|
||||||
github.com/protolambda/bls12-381-util v0.1.0
|
github.com/protolambda/bls12-381-util v0.1.0
|
||||||
github.com/protolambda/zrnt v0.34.1
|
github.com/protolambda/zrnt v0.34.1
|
||||||
github.com/protolambda/ztyp v0.2.2
|
github.com/protolambda/ztyp v0.2.2
|
||||||
|
github.com/reserve-protocol/trezor v0.0.0-20190523030725-9e38328dde28
|
||||||
github.com/rs/cors v1.7.0
|
github.com/rs/cors v1.7.0
|
||||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
|
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
|
||||||
github.com/status-im/keycard-go v0.2.0
|
github.com/status-im/keycard-go v0.2.0
|
||||||
|
|
@ -127,6 +128,7 @@ require (
|
||||||
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||||
github.com/mitchellh/pointerstructure v1.2.0 // indirect
|
github.com/mitchellh/pointerstructure v1.2.0 // indirect
|
||||||
github.com/naoina/go-stringutil v0.1.0 // indirect
|
github.com/naoina/go-stringutil v0.1.0 // indirect
|
||||||
|
github.com/nsf/termbox-go v0.0.0-20190325093121-288510b9734e // indirect
|
||||||
github.com/opentracing/opentracing-go v1.1.0 // indirect
|
github.com/opentracing/opentracing-go v1.1.0 // indirect
|
||||||
github.com/pion/dtls/v2 v2.2.7 // indirect
|
github.com/pion/dtls/v2 v2.2.7 // indirect
|
||||||
github.com/pion/logging v0.2.2 // indirect
|
github.com/pion/logging v0.2.2 // indirect
|
||||||
|
|
|
||||||
9
go.sum
9
go.sum
|
|
@ -216,8 +216,8 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y
|
||||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||||
github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 h1:msKODTL1m0wigztaqILOtla9HeW1ciscYG4xjLtvk5I=
|
github.com/karalabe/usb v0.0.3-0.20231219215548-8627268f6b0a h1:BGJeMa7efLsbPri2WJxtFOcjDPyjCdNlZWERE11GJAE=
|
||||||
github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52/go.mod h1:qk1sX/IBgppQNcGCRoj90u6EGC056EBoIc1oEjCWla8=
|
github.com/karalabe/usb v0.0.3-0.20231219215548-8627268f6b0a/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
||||||
github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4=
|
github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4=
|
||||||
github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig=
|
github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
|
|
@ -257,6 +257,7 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
|
@ -272,6 +273,8 @@ github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hz
|
||||||
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
|
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
|
||||||
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0=
|
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 h1:shk/vn9oCoOTmwcouEdwIeOtOGA/ELRUw/GwvxwfT+0=
|
||||||
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
|
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
|
||||||
|
github.com/nsf/termbox-go v0.0.0-20190325093121-288510b9734e h1:Vbib8wJAaMEF9jusI/kMSYMr/LtRzM7+F9MJgt/nH8k=
|
||||||
|
github.com/nsf/termbox-go v0.0.0-20190325093121-288510b9734e/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
|
||||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
|
|
@ -325,6 +328,8 @@ github.com/protolambda/ztyp v0.2.2 h1:rVcL3vBu9W/aV646zF6caLS/dyn9BN8NYiuJzicLNy
|
||||||
github.com/protolambda/ztyp v0.2.2/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU=
|
github.com/protolambda/ztyp v0.2.2/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU=
|
||||||
github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4=
|
github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4=
|
||||||
github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HDWuHS8cTvHZzrHWxwOtGOs=
|
github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HDWuHS8cTvHZzrHWxwOtGOs=
|
||||||
|
github.com/reserve-protocol/trezor v0.0.0-20190523030725-9e38328dde28 h1:0XRrYV4bb+Y09cLQKsVE5gQ3HRebPXxY89zx+ZV2Fo0=
|
||||||
|
github.com/reserve-protocol/trezor v0.0.0-20190523030725-9e38328dde28/go.mod h1:Twg3zlQzleALAU+gR5xSK112gdh9YLcQ6owamVh0lbY=
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue