async def sign_tx(ctx, msg): address_n = msg.address_n or () node = await seed.derive_node(ctx, address_n, TEZOS_CURVE) if msg.transaction is not None: to = _get_address_from_contract(msg.transaction.destination) await require_confirm_tx(ctx, to, msg.transaction.amount) await require_confirm_fee(ctx, msg.transaction.amount, msg.transaction.fee) elif msg.origination is not None: source = _get_address_from_contract(msg.origination.source) await require_confirm_origination(ctx, source) # if we are immediately delegating contract if msg.origination.delegate is not None: delegate = _get_address_by_tag(msg.origination.delegate) await require_confirm_delegation_baker(ctx, delegate) await require_confirm_origination_fee( ctx, msg.origination.balance, msg.origination.fee ) elif msg.delegation is not None: source = _get_address_from_contract(msg.delegation.source) delegate = None if msg.delegation.delegate is not None: delegate = _get_address_by_tag(msg.delegation.delegate) if delegate is not None and source != delegate: await require_confirm_delegation_baker(ctx, delegate) await require_confirm_set_delegate(ctx, msg.delegation.fee) # if account registers itself as a delegate else: await require_confirm_register_delegate(ctx, source, msg.delegation.fee) else: raise wire.DataError("Invalid operation") w = bytearray() _get_operation_bytes(w, msg) opbytes = bytes(w) # watermark 0x03 is prefix for transactions, delegations, originations, reveals... watermark = bytes([3]) wm_opbytes = watermark + opbytes wm_opbytes_hash = hashlib.blake2b(wm_opbytes, outlen=32).digest() signature = ed25519.sign(node.private_key(), wm_opbytes_hash) sig_op_contents = opbytes + signature sig_op_contents_hash = hashlib.blake2b(sig_op_contents, outlen=32).digest() ophash = base58_encode_check(sig_op_contents_hash, prefix="o") sig_prefixed = base58_encode_check(signature, prefix=TEZOS_SIGNATURE_PREFIX) return TezosSignedTx( signature=sig_prefixed, sig_op_contents=sig_op_contents, operation_hash=ophash )
def __init__(self) -> None: self.h_prevouts = HashWriter( blake2b(outlen=32, personal=b"ZcashPrevoutHash")) self.h_sequence = HashWriter( blake2b(outlen=32, personal=b"ZcashSequencHash")) self.h_outputs = HashWriter( blake2b(outlen=32, personal=b"ZcashOutputsHash"))
def __init__(self, branch_id): self.branch_id = branch_id self.h_prevouts = HashWriter( blake2b(outlen=32, personal=b"ZcashPrevoutHash")) self.h_sequence = HashWriter( blake2b(outlen=32, personal=b"ZcashSequencHash")) self.h_outputs = HashWriter( blake2b(outlen=32, personal=b"ZcashOutputsHash"))
def __init__(self, hash_type='zcash'): self.h_prevouts = HashWriter( blake2b(outlen=32, personal=b"ZcashPrevoutHash")) self.h_sequence = HashWriter( blake2b(outlen=32, personal=b"ZcashSequencHash")) self.h_outputs = HashWriter( blake2b(outlen=32, personal=b"ZcashOutputsHash")) self.hash_type = hash_type self.hash_lock_offset = 777 if self.hash_type == 'komodo' else 0
def test_digest(self): key = unhexlify( '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f' ) for d, h in self.vectors: self.assertEqual( hashlib.blake2b(unhexlify(d), key).digest(), unhexlify(h))
def digest(self) -> bytes: """ Returns `T.4: orchard_digest` field. see: https://zips.z.cash/zip-0244#t-4-orchard-digest """ return blake2b(outlen=32, personal=b"ZTxIdOrchardHash").digest()
def digest(self) -> bytes: """ Returns `T.3: sapling_digest` field. see: https://zips.z.cash/zip-0244#t-3-sapling-digest """ return blake2b(outlen=32, personal=b"ZTxIdSaplingHash").digest()
def sig_digest( self, txi: TxInput | None, script_pubkey: bytes | None, ) -> bytes: """ Returns `S.2: transparent_sig_digest` field for signature digest computation. see: https://zips.z.cash/zip-0244#s-2-transparent-sig-digest """ if self.empty: assert txi is None assert script_pubkey is None return self.digest() h = HashWriter(blake2b(outlen=32, personal=b"ZTxIdTranspaHash")) # only SIGHASH_ALL is supported in Trezor write_uint8(h, SigHashType.SIGHASH_ALL) # S.2a write_hash(h, self.prevouts.get_digest()) # S.2b write_hash(h, self.amounts.get_digest()) # S.2c write_hash(h, self.scriptpubkeys.get_digest()) # S.2d write_hash(h, self.sequence.get_digest()) # S.2e write_hash(h, self.outputs.get_digest()) # S.2f write_hash(h, _txin_sig_digest(txi, script_pubkey)) # S.2g return h.get_digest()
def test_digest_multi(self): x = hashlib.blake2b() d0 = x.digest() d1 = x.digest() d2 = x.digest() self.assertEqual(d0, d1) self.assertEqual(d0, d2)
async def sign_tx(ctx, msg): keychain = await seed.get_keychain(ctx) progress.init(msg.transactions_count, "Loading data") try: attested = len(msg.inputs) * [False] input_coins_sum = 0 # request transactions tx_req = CardanoTxRequest() for index in range(msg.transactions_count): progress.advance() tx_ack = await request_transaction(ctx, tx_req, index) tx_hash = hashlib.blake2b(data=bytes(tx_ack.transaction), outlen=32).digest() tx_decoded = cbor.decode(tx_ack.transaction) for i, input in enumerate(msg.inputs): if not attested[i] and input.prev_hash == tx_hash: attested[i] = True outputs = tx_decoded[1] amount = outputs[input.prev_index][1] input_coins_sum += amount if not all(attested): raise wire.ProcessError("No tx data sent for input " + str(attested.index(False))) transaction = Transaction(msg.inputs, msg.outputs, keychain, msg.protocol_magic, input_coins_sum) # clear progress bar display_homescreen() for i in msg.inputs: await validate_path(ctx, validate_full_path, keychain, i.address_n, CURVE) # sign the transaction bundle and prepare the result tx_body, tx_hash = transaction.serialise_tx() tx = CardanoSignedTx(tx_body=tx_body, tx_hash=tx_hash) except ValueError as e: if __debug__: log.exception(__name__, e) raise wire.ProcessError("Signing failed") # display the transaction in UI if not await show_tx( ctx, transaction.output_addresses, transaction.outgoing_coins, transaction.fee, transaction.network_name, transaction.inputs, transaction.outputs, ): raise wire.ActionCancelled("Signing cancelled") return tx
def _hash_tx_body(tx_body: dict) -> bytes: tx_body_cbor_chunks = cbor.encode_streamed(tx_body) hashfn = hashlib.blake2b(outlen=32) for chunk in tx_body_cbor_chunks: hashfn.update(chunk) return hashfn.digest()
def preimage_hash( self, txi: TxInput, public_keys: list[bytes], threshold: int, tx: SignTx | PrevTx, coin: coininfo.CoinInfo, sighash_type: int, ) -> bytes: h_preimage = HashWriter( blake2b( outlen=32, personal=b"ZcashSigHash" + struct.pack("<I", tx.branch_id), )) assert tx.version_group_id is not None assert tx.expiry is not None zero_hash = b"\x00" * TX_HASH_SIZE # 1. nVersion | fOverwintered write_uint32(h_preimage, tx.version | OVERWINTERED) # 2. nVersionGroupId write_uint32(h_preimage, tx.version_group_id) # 3. hashPrevouts write_bytes_fixed(h_preimage, get_tx_hash(self.h_prevouts), TX_HASH_SIZE) # 4. hashSequence write_bytes_fixed(h_preimage, get_tx_hash(self.h_sequence), TX_HASH_SIZE) # 5. hashOutputs write_bytes_fixed(h_preimage, get_tx_hash(self.h_outputs), TX_HASH_SIZE) # 6. hashJoinSplits write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 7. hashShieldedSpends write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 8. hashShieldedOutputs write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 9. nLockTime write_uint32(h_preimage, tx.lock_time) # 10. expiryHeight write_uint32(h_preimage, tx.expiry) # 11. valueBalance write_uint64(h_preimage, 0) # 12. nHashType write_uint32(h_preimage, sighash_type) # 13a. outpoint write_bytes_reversed(h_preimage, txi.prev_hash, TX_HASH_SIZE) write_uint32(h_preimage, txi.prev_index) # 13b. scriptCode script_code = derive_script_code(txi, public_keys, threshold, coin) write_bytes_prefixed(h_preimage, script_code) # 13c. value write_uint64(h_preimage, txi.amount) # 13d. nSequence write_uint32(h_preimage, txi.sequence) return get_tx_hash(h_preimage)
def format_asset_fingerprint(policy_id: bytes, asset_name_bytes: bytes) -> str: fingerprint = hashlib.blake2b( # bytearrays are being promoted to bytes: https://github.com/python/mypy/issues/654 # but bytearrays are not concatenable, this casting works around this limitation data=bytes(policy_id) + bytes(asset_name_bytes), outlen=20, ).digest() return bech32.encode("asset", fingerprint)
def preimage_hash( self, coin: CoinInfo, tx: SignTx, txi: TxInputType, pubkeyhash: bytes, sighash: int, ) -> bytes: h_preimage = HashWriter( blake2b(outlen=32, personal=b"ZcashSigHash" + struct.pack("<I", self.branch_id))) ensure(coin.overwintered) ensure(tx.version == 4) write_uint32(h_preimage, tx.version | OVERWINTERED) # 1. nVersion | fOverwintered write_uint32(h_preimage, tx.version_group_id) # 2. nVersionGroupId # 3. hashPrevouts write_bytes_fixed(h_preimage, bytearray(self.get_prevouts_hash()), TX_HASH_SIZE) # 4. hashSequence write_bytes_fixed(h_preimage, bytearray(self.get_sequence_hash()), TX_HASH_SIZE) # 5. hashOutputs write_bytes_fixed(h_preimage, bytearray(self.get_outputs_hash()), TX_HASH_SIZE) zero_hash = b"\x00" * TX_HASH_SIZE write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 6. hashJoinSplits write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 7. hashShieldedSpends write_bytes_fixed(h_preimage, zero_hash, TX_HASH_SIZE) # 8. hashShieldedOutputs write_uint32(h_preimage, tx.lock_time) # 9. nLockTime write_uint32(h_preimage, tx.expiry) # 10. expiryHeight write_uint64(h_preimage, 0) # 11. valueBalance write_uint32(h_preimage, sighash) # 12. nHashType write_bytes_reversed(h_preimage, txi.prev_hash, TX_HASH_SIZE) # 13a. outpoint write_uint32(h_preimage, txi.prev_index) script_code = derive_script_code(txi, pubkeyhash) # 13b. scriptCode write_bytes_prefixed(h_preimage, script_code) write_uint64(h_preimage, txi.amount) # 13c. value write_uint32(h_preimage, txi.sequence) # 13d. nSequence return get_tx_hash(h_preimage)
async def sign_tx(ctx: wire.Context, msg: CardanoSignTxInit, keychain: seed.Keychain) -> CardanoSignTxFinished: await show_transaction_signing_mode(ctx, msg.signing_mode) is_network_id_verifiable = await _validate_tx_signing_request(ctx, msg) # inputs, outputs and fee are mandatory fields, count the number of optional fields present tx_body_map_item_count = 3 + sum(( msg.ttl is not None, msg.certificates_count > 0, msg.withdrawals_count > 0, msg.has_auxiliary_data, msg.validity_interval_start is not None, msg.minting_asset_groups_count > 0, msg.include_network_id, msg.script_data_hash is not None, msg.collateral_inputs_count > 0, msg.required_signers_count > 0, )) account_path_checker = AccountPathChecker() hash_fn = hashlib.blake2b(outlen=32) tx_dict: HashBuilderDict[int, Any] = HashBuilderDict( tx_body_map_item_count, INVALID_TX_SIGNING_REQUEST) tx_dict.start(hash_fn) with tx_dict: await _process_transaction(ctx, msg, keychain, tx_dict, account_path_checker) tx_hash = hash_fn.digest() await _confirm_transaction(ctx, msg, is_network_id_verifiable, tx_hash) try: response_after_witness_requests = await _process_witness_requests( ctx, keychain, tx_hash, msg.witness_requests_count, msg.signing_mode, msg.minting_asset_groups_count > 0, account_path_checker, ) await ctx.call(response_after_witness_requests, CardanoTxHostAck) await ctx.call(CardanoTxBodyHash(tx_hash=tx_hash), CardanoTxHostAck) return CardanoSignTxFinished() except ValueError as e: if __debug__: log.exception(__name__, e) raise wire.ProcessError("Signing failed")
def __init__(self) -> None: self.prevouts = HashWriter( blake2b(outlen=32, personal=b"ZTxIdPrevoutHash") ) # a hasher for fields T.2a & S.2b self.amounts = HashWriter( blake2b(outlen=32, personal=b"ZTxTrAmountsHash") ) # a hasher for field S.2c self.scriptpubkeys = HashWriter( blake2b(outlen=32, personal=b"ZTxTrScriptsHash") ) # a hasher for field S.2d self.sequence = HashWriter( blake2b(outlen=32, personal=b"ZTxIdSequencHash") ) # a hasher for fields T.2b & S.2e self.outputs = HashWriter( blake2b(outlen=32, personal=b"ZTxIdOutputsHash") ) # a hasher for fields T.2c & S.2f self.empty = True # inputs_amount + outputs_amount == 0
def __init__(self, tx: SignTx | PrevTx): h = HashWriter(blake2b(outlen=32, personal=b"ZTxIdHeadersHash")) 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(h, tx.version | (1 << 31)) # T.1a write_uint32(h, tx.version_group_id) # T.1b write_uint32(h, tx.branch_id) # T.1c write_uint32(h, tx.lock_time) # T.1d write_uint32(h, tx.expiry) # T.1e self._digest = h.get_digest()
def txid_digest(self) -> bytes: """ Returns the transaction identifier. see: https://zips.z.cash/zip-0244#id4 """ h = HashWriter(blake2b(outlen=32, personal=self.tx_hash_person)) write_hash(h, self.header.digest()) # T.1 write_hash(h, self.transparent.digest()) # T.2 write_hash(h, self.sapling.digest()) # T.3 write_hash(h, self.orchard.digest()) # T.4 return h.get_digest()
def digest(self) -> bytes: """ Returns `T.2: transparent_digest` field for txid computation. see: https://zips.z.cash/zip-0244#t-2-transparent-digest """ h = HashWriter(blake2b(outlen=32, personal=b"ZTxIdTranspaHash")) if not self.empty: write_hash(h, self.prevouts.get_digest()) # T.2a write_hash(h, self.sequence.get_digest()) # T.2b write_hash(h, self.outputs.get_digest()) # T.2c return h.get_digest()
def test_update(self): key = unhexlify('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f') x = hashlib.blake2b(key=key) x.update(bytes(range(10))) self.assertEqual(x.digest(), unhexlify('4fe181f54ad63a2983feaaf77d1e7235c2beb17fa328b6d9505bda327df19fc37f02c4b6f0368ce23147313a8e5738b5fa2a95b29de1c7f8264eb77b69f585cd')) x.update(bytes(range(10, 30))) self.assertEqual(x.digest(), unhexlify('c6dbc61dec6eaeac81e3d5f755203c8e220551534a0b2fd105a91889945a638550204f44093dd998c076205dffad703a0e5cd3c7f438a7e634cd59fededb539e')) x.update(bytes(range(30, 80))) self.assertEqual(x.digest(), unhexlify('fa1549c9796cd4d303dcf452c1fbd5744fd9b9b47003d920b92de34839d07ef2a29ded68f6fc9e6c45e071a2e48bd50c5084e96b657dd0404045a1ddefe282ed')) x.update(bytes(range(80, 111))) self.assertEqual(x.digest(), unhexlify('2620f687e8625f6a412460b42e2cef67634208ce10a0cbd4dff7044a41b7880077e9f8dc3b8d1216d3376a21e015b58fb279b521d83f9388c7382c8505590b9b')) x.update(bytes(range(111, 127))) self.assertEqual(x.digest(), unhexlify('76d2d819c92bce55fa8e092ab1bf9b9eab237a25267986cacf2b8ee14d214d730dc9a5aa2d7b596e86a1fd8fa0804c77402d2fcd45083688b218b1cdfa0dcbcb')) x.update(bytes(range(127, 255))) self.assertEqual(x.digest(), unhexlify('142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461'))
async def get_address(ctx, msg, keychain): await paths.validate_path(ctx, keychain, msg.address_n) node = keychain.derive(msg.address_n) pk = seed.remove_ed25519_prefix(node.public_key()) pkh = hashlib.blake2b(pk, outlen=helpers.PUBLIC_KEY_HASH_SIZE).digest() address = helpers.base58_encode_check( pkh, prefix=helpers.TEZOS_ED25519_ADDRESS_PREFIX) if msg.show_display: desc = address_n_to_str(msg.address_n) await show_address(ctx, address=address, address_qr=address, desc=desc) return TezosAddress(address=address)
async def sign(self) -> None: hash_fn = hashlib.blake2b(outlen=32) self.tx_dict.start(hash_fn) with self.tx_dict: await self._processs_tx_init() tx_hash = hash_fn.digest() await self._confirm_tx(tx_hash) response_after_witness_requests = await self._process_witness_requests( tx_hash) await self.ctx.call(response_after_witness_requests, messages.CardanoTxHostAck) await self.ctx.call(messages.CardanoTxBodyHash(tx_hash=tx_hash), messages.CardanoTxHostAck)
async def get_address(ctx, msg): address_n = msg.address_n or () node = await seed.derive_node(ctx, address_n, TEZOS_CURVE) pk = seed.remove_ed25519_prefix(node.public_key()) pkh = hashlib.blake2b(pk, outlen=20).digest() address = base58_encode_check(pkh, prefix=TEZOS_ED25519_ADDRESS_PREFIX) if msg.show_display: while True: if await show_address(ctx, address): break if await show_qr(ctx, address): break return TezosAddress(address=address)
def signature_digest( self, txi: TxInput | None, script_pubkey: bytes | None ) -> bytes: """ Returns the transaction signature digest. see: https://zips.z.cash/zip-0244#id13 """ h = HashWriter(blake2b(outlen=32, personal=self.tx_hash_person)) write_hash(h, self.header.digest()) # S.1 write_hash(h, self.transparent.sig_digest(txi, script_pubkey)) # S.2 write_hash(h, self.sapling.digest()) # S.3 write_hash(h, self.orchard.digest()) # S.4 return h.get_digest()
def _create_catalyst_registration_payload_signature( keychain: seed.Keychain, catalyst_registration_payload: CatalystRegistrationPayload, path: list[int], ) -> bytes: node = keychain.derive(path) encoded_catalyst_registration = cbor.encode( {METADATA_KEY_CATALYST_REGISTRATION: catalyst_registration_payload}) catalyst_registration_hash = hashlib.blake2b( data=encoded_catalyst_registration, outlen=CATALYST_REGISTRATION_HASH_SIZE, ).digest() return ed25519.sign_ext(node.private_key(), node.private_key_ext(), catalyst_registration_hash)
def preimage_hash( self, coin: CoinInfo, tx: SignTx, txi: TxInputType, pubkeyhash: bytes, sighash: int, ) -> bytes: h_preimage = HashWriter( blake2b(outlen=32, personal=b"ZcashSigHash\xbb\x09\xb8\x76") ) # BRANCH_ID = 0x76b809bb / Sapling ensure(tx.overwintered) ensure(tx.version == 4) write_uint32(h_preimage, tx.version | OVERWINTERED) # 1. nVersion | fOverwintered write_uint32(h_preimage, tx.version_group_id) # 2. nVersionGroupId write_bytes(h_preimage, bytearray(self.get_prevouts_hash())) # 3. hashPrevouts write_bytes(h_preimage, bytearray(self.get_sequence_hash())) # 4. hashSequence write_bytes(h_preimage, bytearray(self.get_outputs_hash())) # 5. hashOutputs write_bytes(h_preimage, b"\x00" * 32) # 6. hashJoinSplits write_bytes(h_preimage, b"\x00" * 32) # 7. hashShieldedSpends write_bytes(h_preimage, b"\x00" * 32) # 8. hashShieldedOutputs write_uint32(h_preimage, tx.lock_time - self.hash_lock_offset) # 9. nLockTime write_uint32(h_preimage, tx.expiry) # 10. expiryHeight write_uint64(h_preimage, 0) # 11. valueBalance write_uint32(h_preimage, sighash) # 12. nHashType write_bytes_reversed(h_preimage, txi.prev_hash) # 13a. outpoint write_uint32(h_preimage, txi.prev_index) script_code = derive_script_code(txi, pubkeyhash) # 13b. scriptCode write_varint(h_preimage, len(script_code)) write_bytes(h_preimage, script_code) write_uint64(h_preimage, txi.amount) # 13c. value write_uint32(h_preimage, txi.sequence) # 13d. nSequence return get_tx_hash(h_preimage)
async def get_address(ctx, msg, keychain): await paths.validate_path(ctx, helpers.validate_full_path, keychain, msg.address_n, CURVE) node = keychain.derive(msg.address_n, CURVE) pk = seed.remove_ed25519_prefix(node.public_key()) pkh = hashlib.blake2b(pk, outlen=20).digest() address = helpers.base58_encode_check( pkh, prefix=helpers.TEZOS_ED25519_ADDRESS_PREFIX) if msg.show_display: desc = address_n_to_str(msg.address_n) while True: if await show_address(ctx, address, desc=desc): break if await show_qr(ctx, address, desc=desc): break return TezosAddress(address=address)
def preimage_hash( self, coin: CoinInfo, tx: SignTx, txi: TxInputType, pubkeyhash: bytes, sighash: int, ) -> bytes: h_preimage = HashWriter( blake2b( outlen=32, personal=b"ZcashSigHash" + struct.pack("<I", self.branch_id) ) ) ensure(tx.overwintered) ensure(tx.version == 3) write_uint32( h_preimage, tx.version | OVERWINTERED ) # 1. nVersion | fOverwintered write_uint32(h_preimage, tx.version_group_id) # 2. nVersionGroupId write_bytes(h_preimage, bytearray(self.get_prevouts_hash())) # 3. hashPrevouts write_bytes(h_preimage, bytearray(self.get_sequence_hash())) # 4. hashSequence write_bytes(h_preimage, bytearray(self.get_outputs_hash())) # 5. hashOutputs write_bytes(h_preimage, b"\x00" * 32) # 6. hashJoinSplits write_uint32(h_preimage, tx.lock_time) # 7. nLockTime write_uint32(h_preimage, tx.expiry) # 8. expiryHeight write_uint32(h_preimage, sighash) # 9. nHashType write_bytes_reversed(h_preimage, txi.prev_hash) # 10a. outpoint write_uint32(h_preimage, txi.prev_index) script_code = derive_script_code(txi, pubkeyhash) # 10b. scriptCode write_varint(h_preimage, len(script_code)) write_bytes(h_preimage, script_code) write_uint64(h_preimage, txi.amount) # 10c. value write_uint32(h_preimage, txi.sequence) # 10d. nSequence return get_tx_hash(h_preimage)
def _txin_sig_digest( txi: TxInput | None, script_pubkey: bytes | None, ) -> bytes: """ Returns `S.2g: txin_sig_digest` field for signature digest computation. see: https://zips.z.cash/zip-0244#s-2g-txin-sig-digest """ h = HashWriter(blake2b(outlen=32, personal=b"Zcash___TxInHash")) if txi is not None: assert script_pubkey is not None write_prevout(h, txi) # 2.Sg.i write_uint64(h, txi.amount) # 2.Sg.ii write_bytes_prefixed(h, script_pubkey) # 2.Sg.iii write_uint32(h, txi.sequence) # 2.Sg.iv return h.get_digest()
def serialise_tx(self): self._process_inputs() self._process_outputs() inputs_cbor = [] for i, output_index in enumerate(self.output_indexes): inputs_cbor.append( [ self.types[i], cbor.Tagged(24, cbor.encode([self.input_hashes[i], output_index])), ] ) inputs_cbor = cbor.IndefiniteLengthArray(inputs_cbor) outputs_cbor = [] for index, address in enumerate(self.output_addresses): outputs_cbor.append( [cbor.Raw(base58.decode(address)), self.outgoing_coins[index]] ) for index, address in enumerate(self.change_addresses): outputs_cbor.append( [cbor.Raw(base58.decode(address)), self.change_coins[index]] ) outputs_cbor = cbor.IndefiniteLengthArray(outputs_cbor) tx_aux_cbor = [inputs_cbor, outputs_cbor, self.attributes] tx_hash = hashlib.blake2b(data=cbor.encode(tx_aux_cbor), outlen=32).digest() witnesses = self._build_witnesses(tx_hash) tx_body = cbor.encode([tx_aux_cbor, witnesses]) self.fee = self.compute_fee( self.input_coins, self.outgoing_coins, self.change_coins ) return tx_body, tx_hash