You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/src/apps/zcash/signer.py

113 lines
4.0 KiB

from micropython import const
from typing import TYPE_CHECKING
from trezor.messages import SignTx
from trezor.utils import ensure
from trezor.wire import DataError, ProcessError
from apps.bitcoin.common import ecdsa_sign
from apps.bitcoin.sign_tx.bitcoinlike import Bitcoinlike
from apps.common.writers import write_compact_size, write_uint32_le
from .hasher import ZcashHasher
if TYPE_CHECKING:
from typing import Sequence
from apps.common.coininfo import CoinInfo
from apps.bitcoin.sign_tx.tx_info import OriginalTxInfo, TxInfo
from apps.bitcoin.writers import Writer
from apps.bitcoin.sign_tx.approvers import Approver
from trezor.utils import HashWriter
from trezor.messages import (
PrevTx,
TxInput,
)
from apps.bitcoin.keychain import Keychain
OVERWINTERED = const(0x8000_0000)
class Zcash(Bitcoinlike):
def __init__(
self,
tx: SignTx,
keychain: Keychain,
coin: CoinInfo,
approver: Approver | None,
) -> None:
ensure(coin.overwintered)
if tx.version != 5:
raise DataError("Expected transaction version 5.")
super().__init__(tx, keychain, coin, approver)
def create_sig_hasher(self, tx: SignTx | PrevTx) -> ZcashHasher:
return ZcashHasher(tx)
def create_hash_writer(self) -> HashWriter:
# Replacement transactions are not supported
# so this should never be called.
raise NotImplementedError
async def step3_verify_inputs(self) -> None:
# Replacement transactions are not supported.
# We don't check prevouts, because BIP-341 techniques
# were adapted in ZIP-244 sighash algorithm.
# see: https://github.com/zcash/zips/issues/574
self.taproot_only = True # turn on taproot behavior
await super().step3_verify_inputs()
self.taproot_only = False # turn off taproot behavior
async def step5_serialize_outputs(self) -> None:
await super().step5_serialize_outputs()
async def sign_nonsegwit_input(self, i_sign: int) -> None:
await self.sign_nonsegwit_bip143_input(i_sign)
def sign_bip143_input(self, i: int, txi: TxInput) -> tuple[bytes, bytes]:
signature_digest = self.tx_info.sig_hasher.hash_zip244(
txi, self.input_derive_script(txi)
)
node = self.keychain.derive(txi.address_n)
signature = ecdsa_sign(node, signature_digest)
return node.public_key(), signature
async def process_original_input(self, txi: TxInput, script_pubkey: bytes) -> None:
raise ProcessError("Replacement transactions are not supported.")
# Zcash transaction fees are very low
# so there is no need to bump the fee.
async def get_tx_digest(
self,
i: int,
txi: TxInput,
tx_info: TxInfo | OriginalTxInfo,
public_keys: Sequence[bytes | memoryview],
threshold: int,
script_pubkey: bytes,
tx_hash: bytes | None = None,
) -> bytes:
return self.tx_info.sig_hasher.hash_zip244(txi, script_pubkey)
def write_tx_header(
self, w: Writer, tx: SignTx | PrevTx, witness_marker: bool
) -> None:
# defined in ZIP-225 (see https://zips.z.cash/zip-0225)
assert tx.version_group_id is not None
assert tx.branch_id is not None # checked in sanitize_*
assert tx.expiry is not None
write_uint32_le(w, tx.version | OVERWINTERED) # nVersion | fOverwintered
write_uint32_le(w, tx.version_group_id) # nVersionGroupId
write_uint32_le(w, tx.branch_id) # nConsensusBranchId
write_uint32_le(w, tx.lock_time) # lock_time
write_uint32_le(w, tx.expiry) # expiryHeight
def write_tx_footer(self, w: Writer, tx: SignTx | PrevTx) -> None:
# serialize Sapling bundle
write_compact_size(w, 0) # nSpendsSapling
write_compact_size(w, 0) # nOutputsSapling
# serialize Orchard bundle
write_compact_size(w, 0) # nActionsOrchard