1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-20 13:38:11 +00:00

feat(core): move Orchard parameters into a separate message

This commit is contained in:
Tomas Krnak 2022-11-17 13:44:46 +07:00
parent 37aed5de58
commit f1a90fcbc9
6 changed files with 76 additions and 47 deletions

View File

@ -198,11 +198,7 @@ message SignTx {
optional uint32 branch_id = 10; // only for Zcash, BRANCH_ID optional uint32 branch_id = 10; // only for Zcash, BRANCH_ID
optional AmountUnit amount_unit = 11 [default=BITCOIN]; // show amounts in optional AmountUnit amount_unit = 11 [default=BITCOIN]; // show amounts in
optional bool decred_staking_ticket = 12 [default=false]; // only for Decred, this is signing a ticket purchase optional bool decred_staking_ticket = 12 [default=false]; // only for Decred, this is signing a ticket purchase
optional zcash.ZcashOrchardParams orchard_params = 13; // only for Zcash
optional uint32 orchard_inputs_count = 13 [default = 0]; // only for Zcash, number of Orchard inputs
optional uint32 orchard_outputs_count = 14 [default = 0]; // only for Zcash, number of Orchard outputs
optional bytes orchard_anchor = 15; // only for Zcash, a root of Orchard Merkle tree
optional uint32 account = 16 [default = 0]; // only for Zcash
} }
/** /**

View File

@ -62,6 +62,17 @@ message ZcashAddress {
optional string address = 1; optional string address = 1;
} }
/**
* Orchard signing params
* @embed
*/
message ZcashOrchardParams {
required uint32 inputs_count = 1;
required uint32 outputs_count = 2;
required bytes anchor = 3;
repeated uint32 address_n = 4;
}
/** /**
* Request: Specify transaction Orchard input. * Request: Specify transaction Orchard input.
* @next TxRequest * @next TxRequest

View File

@ -9,7 +9,6 @@ from trezor.messages import TxRequest, ZcashAck, ZcashOrchardInput, ZcashOrchard
from trezor.wire import DataError from trezor.wire import DataError
from apps.bitcoin.sign_tx import helpers from apps.bitcoin.sign_tx import helpers
from apps.common.paths import HARDENED
from .. import unified from .. import unified
from ..hasher import ZcashHasher from ..hasher import ZcashHasher
@ -61,9 +60,13 @@ class OrchardSigner:
tx_req: TxRequest, tx_req: TxRequest,
) -> None: ) -> None:
assert tx_req.serialized is not None # typing assert tx_req.serialized is not None # typing
params = tx_info.tx.orchard_params
self.inputs_count = tx_info.tx.orchard_inputs_count if params is None:
self.outputs_count = tx_info.tx.orchard_outputs_count self.inputs_count = 0
self.outputs_count = 0
else:
self.inputs_count = params.inputs_count
self.outputs_count = params.outputs_count
if self.inputs_count + self.outputs_count > 0: if self.inputs_count + self.outputs_count > 0:
self.actions_count = max( self.actions_count = max(
@ -84,15 +87,9 @@ class OrchardSigner:
self.tx_req = tx_req self.tx_req = tx_req
assert isinstance(tx_info.sig_hasher, ZcashHasher) assert isinstance(tx_info.sig_hasher, ZcashHasher)
self.sig_hasher: ZcashHasher = tx_info.sig_hasher self.sig_hasher: ZcashHasher = tx_info.sig_hasher
assert params is not None
account = tx_info.tx.account self.anchor = params.anchor
assert account is not None # typing self.key_node = self.keychain.derive(params.address_n)
key_path = [
32 | HARDENED, # ZIP-32 constant
coin.slip44 | HARDENED, # purpose
account | HARDENED, # account
]
self.key_node = self.keychain.derive(key_path)
self.msg_acc = MessageAccumulator( self.msg_acc = MessageAccumulator(
self.keychain.derive_slip21( self.keychain.derive_slip21(
@ -175,15 +172,13 @@ class OrchardSigner:
self.msg_acc.check() self.msg_acc.check()
# hash orchard footer # hash orchard footer
assert self.tx_info.tx.orchard_anchor is not None # typing
self.sig_hasher.orchard.finalize( self.sig_hasher.orchard.finalize(
flags=FLAGS, flags=FLAGS,
value_balance=self.approver.orchard_balance, value_balance=self.approver.orchard_balance,
anchor=self.tx_info.tx.orchard_anchor, anchor=self.anchor,
) )
def derive_shielding_seed(self) -> bytes: def derive_shielding_seed(self) -> bytes:
assert self.tx_info.tx.orchard_anchor is not None # typing
ss_slip21 = self.keychain.derive_slip21( ss_slip21 = self.keychain.derive_slip21(
[b"Zcash Orchard", b"bundle_shielding_seed"], [b"Zcash Orchard", b"bundle_shielding_seed"],
).key() ).key()
@ -191,7 +186,7 @@ class OrchardSigner:
ss_hasher.update(self.sig_hasher.header.digest()) ss_hasher.update(self.sig_hasher.header.digest())
ss_hasher.update(self.sig_hasher.transparent.digest()) ss_hasher.update(self.sig_hasher.transparent.digest())
ss_hasher.update(self.msg_acc.state) ss_hasher.update(self.msg_acc.state)
ss_hasher.update(self.tx_info.tx.orchard_anchor) ss_hasher.update(self.anchor)
ss_hasher.update(ss_slip21) ss_hasher.update(ss_slip21)
return ss_hasher.digest() return ss_hasher.digest()

View File

@ -63,11 +63,10 @@ class Zcash(Bitcoinlike):
coin, coin,
self.tx_req, self.tx_req,
) )
self.tx_info.wallet_path.attribute = [ if self.orchard.inputs_count > 0 and tx.inputs_count > 0:
44 | HARDENED, # BIP-44 constant raise DataError(
coin.slip44 | HARDENED, "Cannot spending transparent and Orchard inputs simultaneously is not supported."
tx.account | HARDENED, )
]
def create_sig_hasher(self, tx: SignTx | PrevTx) -> ZcashHasher: def create_sig_hasher(self, tx: SignTx | PrevTx) -> ZcashHasher:
return ZcashHasher(tx) return ZcashHasher(tx)

View File

@ -455,6 +455,26 @@ if TYPE_CHECKING:
def is_type_of(cls, msg: Any) -> TypeGuard["ZcashAddress"]: def is_type_of(cls, msg: Any) -> TypeGuard["ZcashAddress"]:
return isinstance(msg, cls) return isinstance(msg, cls)
class ZcashOrchardParams(protobuf.MessageType):
inputs_count: "int"
outputs_count: "int"
anchor: "bytes"
address_n: "list[int]"
def __init__(
self,
*,
inputs_count: "int",
outputs_count: "int",
anchor: "bytes",
address_n: "list[int] | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["ZcashOrchardParams"]:
return isinstance(msg, cls)
class ZcashOrchardInput(protobuf.MessageType): class ZcashOrchardInput(protobuf.MessageType):
recipient: "bytes" recipient: "bytes"
value: "int" value: "int"
@ -707,10 +727,7 @@ if TYPE_CHECKING:
branch_id: "int | None" branch_id: "int | None"
amount_unit: "AmountUnit" amount_unit: "AmountUnit"
decred_staking_ticket: "bool" decred_staking_ticket: "bool"
orchard_inputs_count: "int" orchard_params: "ZcashOrchardParams | None"
orchard_outputs_count: "int"
orchard_anchor: "bytes | None"
account: "int"
def __init__( def __init__(
self, self,
@ -726,10 +743,7 @@ if TYPE_CHECKING:
branch_id: "int | None" = None, branch_id: "int | None" = None,
amount_unit: "AmountUnit | None" = None, amount_unit: "AmountUnit | None" = None,
decred_staking_ticket: "bool | None" = None, decred_staking_ticket: "bool | None" = None,
orchard_inputs_count: "int | None" = None, orchard_params: "ZcashOrchardParams | None" = None,
orchard_outputs_count: "int | None" = None,
orchard_anchor: "bytes | None" = None,
account: "int | None" = None,
) -> None: ) -> None:
pass pass

View File

@ -1021,6 +1021,29 @@ class ZcashAddress(protobuf.MessageType):
self.address = address self.address = address
class ZcashOrchardParams(protobuf.MessageType):
MESSAGE_WIRE_TYPE = None
FIELDS = {
1: protobuf.Field("inputs_count", "uint32", repeated=False, required=True),
2: protobuf.Field("outputs_count", "uint32", repeated=False, required=True),
3: protobuf.Field("anchor", "bytes", repeated=False, required=True),
4: protobuf.Field("address_n", "uint32", repeated=True, required=False),
}
def __init__(
self,
*,
inputs_count: "int",
outputs_count: "int",
anchor: "bytes",
address_n: Optional[Sequence["int"]] = None,
) -> None:
self.address_n: Sequence["int"] = address_n if address_n is not None else []
self.inputs_count = inputs_count
self.outputs_count = outputs_count
self.anchor = anchor
class ZcashOrchardInput(protobuf.MessageType): class ZcashOrchardInput(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 906 MESSAGE_WIRE_TYPE = 906
FIELDS = { FIELDS = {
@ -1307,10 +1330,7 @@ class SignTx(protobuf.MessageType):
10: protobuf.Field("branch_id", "uint32", repeated=False, required=False), 10: protobuf.Field("branch_id", "uint32", repeated=False, required=False),
11: protobuf.Field("amount_unit", "AmountUnit", repeated=False, required=False), 11: protobuf.Field("amount_unit", "AmountUnit", repeated=False, required=False),
12: protobuf.Field("decred_staking_ticket", "bool", repeated=False, required=False), 12: protobuf.Field("decred_staking_ticket", "bool", repeated=False, required=False),
13: protobuf.Field("orchard_inputs_count", "uint32", repeated=False, required=False), 13: protobuf.Field("orchard_params", "ZcashOrchardParams", repeated=False, required=False),
14: protobuf.Field("orchard_outputs_count", "uint32", repeated=False, required=False),
15: protobuf.Field("orchard_anchor", "bytes", repeated=False, required=False),
16: protobuf.Field("account", "uint32", repeated=False, required=False),
} }
def __init__( def __init__(
@ -1328,10 +1348,7 @@ class SignTx(protobuf.MessageType):
branch_id: Optional["int"] = None, branch_id: Optional["int"] = None,
amount_unit: Optional["AmountUnit"] = AmountUnit.BITCOIN, amount_unit: Optional["AmountUnit"] = AmountUnit.BITCOIN,
decred_staking_ticket: Optional["bool"] = False, decred_staking_ticket: Optional["bool"] = False,
orchard_inputs_count: Optional["int"] = 0, orchard_params: Optional["ZcashOrchardParams"] = None,
orchard_outputs_count: Optional["int"] = 0,
orchard_anchor: Optional["bytes"] = None,
account: Optional["int"] = 0,
) -> None: ) -> None:
self.outputs_count = outputs_count self.outputs_count = outputs_count
self.inputs_count = inputs_count self.inputs_count = inputs_count
@ -1345,10 +1362,7 @@ class SignTx(protobuf.MessageType):
self.branch_id = branch_id self.branch_id = branch_id
self.amount_unit = amount_unit self.amount_unit = amount_unit
self.decred_staking_ticket = decred_staking_ticket self.decred_staking_ticket = decred_staking_ticket
self.orchard_inputs_count = orchard_inputs_count self.orchard_params = orchard_params
self.orchard_outputs_count = orchard_outputs_count
self.orchard_anchor = orchard_anchor
self.account = account
class TxRequest(protobuf.MessageType): class TxRequest(protobuf.MessageType):