mirror of https://github.com/zcash/zips.git
362 lines
16 KiB
ReStructuredText
362 lines
16 KiB
ReStructuredText
::
|
|
|
|
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:
|
|
|
|
Recipient
|
|
A wallet or other software that can receive transfers of assets (such
|
|
as ZEC) or in the future potentially other transaction-based state changes.
|
|
Producer
|
|
A wallet or other software that can create an Address (in which case it is
|
|
normally also a Recipient) or a Viewing Key.
|
|
Consumer
|
|
A wallet or other software that can make use of an Address or Viewing Key
|
|
that it is given.
|
|
Sender
|
|
A wallet or other software that can send transfers of assets, or other
|
|
consensus state side-effects defined in future. Senders are a subset of
|
|
Consumers.
|
|
|
|
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. Analysis of the benefits and drawbacks of each of the proposed
|
|
alternatives is presented at the end of this document.
|
|
|
|
Background
|
|
==========
|
|
|
|
In November of 2023, the Zcash community received notice from the Binance
|
|
cryptocurrency exchange that Zcash was at risk of being delisted from the
|
|
exchange unless the community could provide a mechanism by which Binance could
|
|
refuse deposits from shielded addresses and return them to the depositor. This
|
|
issue was raised and discussed at length in the Zcash Community forum
|
|
[#binance-delisting]_.
|
|
|
|
In the course of that discussion thread, wallet developer and community member
|
|
@hanh [#hanh-profile]_ suggested a wallet-oriented approach [#hanh-suggestion]_
|
|
that involved defining a new encoding for Zcash transparent P2PKH addresses. A
|
|
Consumer of such an address, whether it be a wallet or an exchange, could
|
|
recognize this encoding as a directive that the wallet should only spend
|
|
transparent funds when creating an output to that address.
|
|
|
|
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 not yet understood by preexisting
|
|
Consumers, in order to prevent inadvertent shielded spends when sending to such
|
|
addresses. Then, Consumers that upgrade to support the new encoding will do so
|
|
with the understanding that they must respect the restrictions on sources of
|
|
funds described in this ZIP.
|
|
|
|
Requirements
|
|
============
|
|
|
|
1. A Recipient 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 and other Consumers 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.
|
|
|
|
Alternative 1
|
|
=============
|
|
|
|
This alternative was suggested by @hanh in [#hanh-suggestion]_.
|
|
|
|
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.
|
|
|
|
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 and other Senders sending to a TEX address MUST ensure that only
|
|
transparent UTXOs are spent in the creation of a transaction.
|
|
|
|
Reference Implementation (Alternative 1)
|
|
----------------------------------------
|
|
|
|
Javascript::
|
|
|
|
import bs58check from 'bs58check'
|
|
import {bech32m} from 'bech32'
|
|
|
|
// From t1 to tex
|
|
var b58decoded = bs58check.decode('t1VmmGiyjVNeCjxDZzg7vZmd99WyzVby9yC')
|
|
console.assert(b58decoded.length == 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(pkh2.length == 20, 'Invalid length');
|
|
var t1 = bs58check.encode(Buffer.concat([Uint8Array.from([0x1C, 0xB8]), pkh2]))
|
|
console.log(t1)
|
|
|
|
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. Existing Consumers that support Unified Addresses will automatically
|
|
be able to recognize a Traceable Unified Address as a valid Zcash address, but
|
|
will not be able to send to that address unless they update their code to
|
|
understand the new Receiver Typecode defined in this ZIP. 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 and send to 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
|
|
[#binance-address-expiry]_.
|
|
|
|
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. 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. 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 and other Senders 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 using `zcash_address_wasm` [#zcash_address_wasm]_::
|
|
|
|
import init, { to_traceable_address } from 'zcash_address_wasm';
|
|
init().then(() => {
|
|
var t_address = "t1VmmGiyjVNeCjxDZzg7vZmd99WyzVby9yC";
|
|
|
|
// Create a deposit address that is valid for 30 days
|
|
var expiry_time = new Date();
|
|
expiry_time.setDate(expiry_time.getDate() + 30);
|
|
var expiry_unix_seconds = BigInt(Math.floor(expiry_time.getTime() / 1000));
|
|
|
|
var traceable_address = to_traceable_address(t_address, expiry_unix_seconds);
|
|
console.log(traceable_address);
|
|
});
|
|
|
|
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 })
|
|
}
|
|
}
|
|
|
|
Analysis of Alternative 1
|
|
=========================
|
|
|
|
Pros to Alternative 1
|
|
---------------------
|
|
|
|
- The reencoding from Zcash P2PKH addresses is extremely straightforward and
|
|
relies only upon widely available encoding libraries.
|
|
|
|
Cons to Alternative 1
|
|
---------------------
|
|
|
|
- Existing wallets and other Consumers will regard the new address type as
|
|
entirely invalid, and will not automatically prompt their users that they
|
|
need to upgrade in order to send to this type of address.
|
|
- Creation of a new fully-distinct address type further fragments the Zcash
|
|
address ecosystem. Avoiding such fragmentation and providing smooth upgrade
|
|
paths and good error messages to users is exactly the problem that Unifed
|
|
Addresses [#zip-0316-unified-addresses]_ were intended to avoid.
|
|
- The TEX address type does not provide any mechanism for address expiration.
|
|
One of the questions Binance has asked has been what to do about users who
|
|
have stored their existing transparent deposit address in their wallets, or
|
|
as a withdrawal address for other exchanges or services. This is a
|
|
challenging problem to mitigate now because address expiration was not
|
|
previously implemented. We should not further compound this problem by
|
|
defining a new distinct address type that does not provide a mechanism for
|
|
address expiry.
|
|
|
|
Analysis of Alternative 2
|
|
=========================
|
|
|
|
Pros To Alternative 2
|
|
---------------------
|
|
|
|
- By integrating with the Unified Address framework, Consumers of Traceable
|
|
Addresses that have not yet been upgraded to recognize these addresses can
|
|
automatically be prompted to upgrade their wallets or services to understand
|
|
the unrecognized receiver typecode.
|
|
- It is possible to include address expiration metadata in a Traceable Address,
|
|
which can help to mitigate problems related to stored addresses in the
|
|
future.
|
|
- Regardless of which proposal is adopted, the Zcash Community will need to
|
|
work with exchanges other than Binance to update their address parsing logic
|
|
to understand the new address format. By encouraging Consumers such as
|
|
exchanges to adopt parsing for Unified addresses, this proposal furthers
|
|
the original goal of Unified Addresses to reduce fragmentation in the address
|
|
ecosystem.
|
|
|
|
Cons to Alternative 2
|
|
---------------------
|
|
|
|
- Unified Address encoding is slightly more complex than the proposed TEX address
|
|
encoding, and requires use of the F4Jumble encoding algorithm [#F4Jumble]_.
|
|
However, this can be readily mitigated by providing a purpose-built library for
|
|
Traceable Address encoding to Producers.
|
|
|
|
.. [#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>`_
|
|
.. [#binance-delisting] `Zcash Community Forum thread "Important: Potential Binance Delisting" <https://forum.zcashcommunity.com/t/important-potential-binance-delisting/45954>`_
|
|
.. [#hanh-profile] 'Zcash Community Forum user @hanh <https://forum.zcashcommunity.com/u/hanh/summary>'_
|
|
.. [#hanh-suggestion] 'Ywallet developer @hanh's proposal <https://forum.zcashcommunity.com/t/important-potential-binance-delisting/45954/112>'_
|
|
.. [#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>`_
|
|
.. [#binance-address-expiry] `Zcash Community Forum post describing motivations for address expiry <https://forum.zcashcommunity.com/t/unified-address-expiration/46564/6>`_
|
|
.. [#Base58Check] `Base58Check encoding — Bitcoin Wiki <https://en.bitcoin.it/wiki/Base58Check_encoding>`_
|
|
.. [#F4Jumble] `ZIP 316: F4Jumble encoding <zip-0316#jumbling>`_
|
|
.. [#bip-0350] `BIP 350: Bech32m format for v1+ witness addresses <https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki>`_
|
|
.. [#zcash_address_wasm] `zcash_address_wasm: Proof of concept library for Traceable Address Encoding <https://github.com/nuttycom/zcash_address_wasm>`_
|