zips/zip-0320.rst

256 lines
10 KiB
ReStructuredText
Raw Normal View History

::
ZIP: 320
Title: Defining an Address Type to which funds can only be sent from Transparent Addresses
Owners: Daira Emma Hopwood <daira@electriccoin.co>
Kris Nuttycombe <kris@nutty.land>
Credits: Hanh
Status: Draft
Category: Standards / Wallet
Created: 2024-01-12
License: MIT
Discussions-To: <https://github.com/zcash/zips/issues/757>
Pull-Request: <https://github.com/zcash/zips/pull/760>
Terminology
===========
The key words "MUST", "MUST NOT", "SHOULD", and "MAY" in this document are
to be interpreted as described in BCP 14 [#BCP14]_ when, and only when, they
appear in all capitals.
The terms below are to be interpreted as follows:
Abstract
========
This ZIP defines a new encoding for transparent Zcash addresses. Wallets must
ensure that no shielded notes are spent in transactions that send to a
transparent address encoded in the specified fashion.
This ZIP is presently in Draft status, and defines two alternate encodings
for consideration.
Motivation
==========
The Binance cryptocurrency exchange requires that funds sent to their deposit
addresses come from source addresses that are readily identifiable using
on-chain information, such that if necessary funds may be rejected by sending
them back to the source address(es). This ZIP is intended to standardize
a transparent address encoding that is only usable by wallets that understand
and will respect this constraint.
Requirements
============
1. An entity wishing to receive funds from exclusively transparent sources
must be able to generate a receiving address such that only transparent
funds will be spent in transactions with an output to this address.
2. Wallets that have not been upgraded to recognize the new address format
cannot mistake the address for another address type or inadvertently
send shielded funds to the address.
3. No changes to recipient infrastructure beyond changes to address encoding
and decoding should be required as a consequence of this ZIP.
Specification (Alternative 1)
=============================
TEX Addresses
-------------
A TEX Address is a ``bech32m`` reencoding of a transparent Zcash P2PKH address
[#protocol-transparentaddrencoding]_.
Motivations for Alternative 1
-----------------------------
The TEX Address is the simplest possible approach to creating a new address
type that indicates that only transparent sources of funds should be used.
Detailed Specification (Alternative 1)
--------------------------------------
A TEX address is produced from a mainnet Zcash P2PKH Address by executing the
following steps:
1. Decode the address to a byte array using the Base58Check decoding
algorithm [#Base58Check]_.
2. If the length of the resulting byte sequence is not 22 bytes or if its two-byte
address prefix is not :math:`\mathtt{[0x1C, 0xB8]}`, return an error. Otherwise,
let the **validating key hash** be the remaining 20 bytes of the array after
removing the two-byte address prefix.
3. Reencode the 20-byte **validating key hash** using the Bech32m encoding
defined in [#bip-0350]_ with the human-readable prefix (HRP) ``"tex"``.
For testnet addresses, the required lead bytes of a P2PKH address in step 2
are :math:`\mathtt{[0x1C, 0xB8]}`, and the ``"textest"`` HRP is used when
reencoding in step 3.
Wallets sending to a TEX address MUST ensure that only transparent UTXOs are
spent in the creation of a transaction.
Reference Implementation (Alternative 1)
----------------------------------------
.. code-block: javascript
import bs58check from 'bs58check'
import {bech32m} from 'bech32'
// From t1 to tex
var b58decoded = bs58check.decode('t1VmmGiyjVNeCjxDZzg7vZmd99WyzVby9yC')
console.assert(len(b58decoded) == 22, 'Invalid length');
console.assert(b58decoded[0] == 0x1C && b58decoded[1] == 0xB8, 'Invalid address prefix');
var pkh = b58decoded.slice(2)
var tex = bech32m.encode('tex', bech32m.toWords(pkh))
console.log(tex)
// From tex to t1
var bech32decoded = bech32m.decode('tex1s2rt77ggv6q989lr49rkgzmh5slsksa9khdgte')
console.assert(bech32decoded.prefix == 'tex', 'Invalid address prefix')
var pkh2 = Uint8Array.from(bech32m.fromWords(bech32decoded.words))
console.assert(len(pkh2) == 20, 'Invalid length');
var t1 = bs58check.encode(Buffer.concat([Uint8Array.from([0x1C, 0xB8]), pkh2]))
console.log(t1)
Specification (Alternative 2)
=============================
Traceable Unified Addresses
---------------------------
A Traceable Unified Address is a reencoding of a transparent Zcash address into
a Unified Address [#zip-0316-unified-addresses]_.
Motivations for Alternative 2
-----------------------------
Traceable Unified Addresses fit into the existing Zcash Unified Address
ecosystem. As such, wallets that support Unified Addresses will be able to
parse (but not necessarily send to) a Traceable Unified Address. Even in the
case that Traceable Receivers are not understood by the sending wallet, a
Unified Address-supporting wallet will be able to automatically provide good
error messages for their users to indicate that the wallet needs to be updated
to understand these addresses.
In addition, by integrating with the Unified Address framework, it becomes
possible for the addresses being generated to include extra metadata, in
particular, metadata items such as an Address Expiry Height or Address Expiry
Date [#zip-0316-address-expiry]_ may be included. For exchange use cases such
as Binance's, it is useful to ensure that an address provided to a user has a
limited utility life, such that after expiration the user must obtain a new
address in order to be able to continue to send funds.
Detailed Specification (Alternative 2)
--------------------------------------
Upon activation of this ZIP, the section `Encoding of Unified Addresses` of ZIP
316 [#zip-0316-unified-addresses]_ will be modified to define a new
Traceable Receiver Type having typecode :math:`\mathtt{0x04}`, the value of
which MUST be the 20-byte **validating key hash** of a Zcash P2PKH Address as
defined in [#protocol-transparentaddrencoding]_.
The "Requirements for both Unified Addresses and Unified Viewing Keys" section
of ZIP 316 [#zip-0316-unified-requirements]_ will be modified as follows —
the text::
A Unified Address or Unified Viewing Key MUST contain at least one
shielded Item (Typecodes :math:`\mathtt{0x02}` and :math:`\mathtt{0x03}`).
The rationale is that the existing P2SH and P2PKH transparent-only
address formats, and the existing P2PKH extended public key format,
suffice for representing transparent Items and are already supported
by the existing ecosystem.
will be replaced by::
A Unified Address MUST contain at least one Receiver and any number
of Metadata Items. The selection of Receivers is further restricted
such that a Unified Address MUST **either** contain at least one shielded
Receiver (Typecodes :math:`\mathtt{0x02}` and :math:`\mathtt{0x03}`), OR
MUST contain **only** a Traceable Address Receiver (Typecode
:math:`\mathtt{0x04}`).
A Unified Viewing Key MUST contain at least one shielded Item (Typecodes
:math:`\mathtt{0x02}` and :math:`\mathtt{0x03}`).
A Traceable Unified Address is produced from a mainnet Zcash P2PKH address by
executing the following steps:
1. Decode the address to a byte array using the Base58Check decoding
algorithm [#Base58Check]_.
2. Remove the two-byte address prefix from the resulting byte array. These
bytes should be equal to :math:`\mathtt{[0x1C, 0xB8]}`. The remainder of the
byte array (the **validating key hash**) should have a length of 20 bytes.
3. Construct a new Unified Address using a single Traceable Receiver
:math:`\mathtt{0x04}` with the 20-byte **validating_key_hash** as
its value. In addition, metadata items such as an Address Expiry Height
or Address Expiry Date [#zip-0316-address-expiry]_ MAY be included.
Wallets sending to a Traceable Unified Address MUST ensure that only
transparent UTXOs are spent in the creation of a transaction.
Reference Implementation (Alternative 2)
----------------------------------------
Javascript library `zcash_address_wasm`:
.. code-block: javascript
import { to_traceable_address } from 'zcash_address_wasm'
// Create a deposit address that is valid for 30 days
var expiry_time = new Date();
expiry_time.setDate(expiry_time.getDate() + 30);
var traceable_addr = to_traceable_address('t1VmmGiyjVNeCjxDZzg7vZmd99WyzVby9yC', expiry_time.getTime() / 1000)
Rust:
.. code-block: rust
use zcash_address::{
unified::{self, Encoding},
Network, ToAddress, TryFromAddress, ZcashAddress,
};
struct TraceableReceiver {
net: Network,
data: [u8; 20],
}
impl TraceableReceiver {
fn to_address(&self, expiry_time: u64) -> ZcashAddress {
let traceable_addr = unified::Address::try_from_items(vec![
unified::Receiver::Unknown {
typecode: 0x04,
data: self.data.to_vec(),
},
unified::Receiver::Unknown {
typecode: 0xE0,
data: expiry_time.to_le_bytes().to_vec(),
},
])
.expect("We know that this produces a valid address.");
ZcashAddress::from_unified(self.net, traceable_addr)
}
}
impl TryFromAddress for TraceableReceiver {
type Error = unified::ParseError;
fn try_from_transparent_p2pkh(
net: Network,
data: [u8; 20],
) -> Result<Self, zcash_address::ConversionError<Self::Error>> {
Ok(TraceableReceiver { net, data })
}
}
.. [#BCP14] `Information on BCP 14 — "RFC 2119: Key words for use in RFCs to Indicate Requirement Levels" and "RFC 8174: Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words" <https://www.rfc-editor.org/info/bcp14>`_
.. [#zip-0316-unified-addresses] `ZIP 316: Unified Addresses <zip-0316#encoding-of-unified-addresses>`_
.. [#zip-0316-unified-requirements] `ZIP 316: Requirements for both Unified Addresses and Unified Viewing Keys <zip-0316#requirements-for-both-unified-addresses-and-unified-viewing-keys>`_
.. [#zip-0316-address-expiry] `ZIP 316: <zip-0316#address-expiration-metadata>`_
.. [#protocol-transparentaddrencoding] `Zcash Protocol Specification, Version 2023.4.0. Section 5.6.1.1 Transparent Addresses <protocol/protocol.pdf#transparentaddrencoding>`_
.. [#Base58Check] `Base58Check encoding — Bitcoin Wiki <https://en.bitcoin.it/wiki/Base58Check_encoding>`_
.. [#bip-0350] `BIP 350: Bech32m format for v1+ witness addresses <https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki>`_