mirror of https://github.com/zcash/zips.git
293 lines
14 KiB
ReStructuredText
293 lines
14 KiB
ReStructuredText
::
|
||
|
||
ZIP: 304
|
||
Title: Sapling Address Signatures
|
||
Owners: Jack Grigg <jack@electriccoin.co>
|
||
Credits: Daira Hopwood <daira@electriccoin.co>
|
||
Sean Bowe <sean@electriccoin.co>
|
||
Status: Draft
|
||
Category: Standards / RPC / Wallet
|
||
Created: 2020-06-01
|
||
License: MIT
|
||
Discussions-To: <https://github.com/zcash/zips/issues/345>
|
||
Pull-Request: <https://github.com/zcash/zips/pull/376>
|
||
|
||
|
||
Terminology
|
||
===========
|
||
|
||
The key words "MUST" and "SHOULD" in this document is to be interpreted as described in
|
||
RFC 2119. [#RFC2119]_
|
||
|
||
|
||
Abstract
|
||
========
|
||
|
||
This proposal describes a mechanism for creating signatures with Sapling addresses,
|
||
suitable for use by the ``signmessage`` and ``verifymessage`` RPC methods in ``zcashd``.
|
||
|
||
|
||
Motivation
|
||
==========
|
||
|
||
There are a variety of situations where it is useful for a user to be able to prove that
|
||
they control a given payment address. For example, before a high-value transfer of funds,
|
||
the sender may want to verify that the recipient will definitely be able to spend them,
|
||
to ensure that the funds won't be stuck in an invalid or unusable address.
|
||
|
||
A payment address is analogous (in some cases, identical) to a public key in a signature
|
||
scheme. A transaction that spends funds received by the address, is authorized by making
|
||
(the equivalent of) a signature with the corresponding spending key. This authorization
|
||
protocol can be repurposed to instead sign a message provided by a third party.
|
||
|
||
Bitcoin Core's ``bitcoind`` provides a ``signmessage`` RPC method that implements message
|
||
signing for Bitcoin addresses, leveraging the fact that a Bitcoin private key is just a
|
||
``secp256k`` private key, and a Bitcoin transaction authorizes spends with a signature.
|
||
``zcashd`` inherited this RPC method, and it can be used to make signatures for
|
||
transparent Zcash addresses.
|
||
|
||
However, support for signing messages with shielded addresses was not possible when Zcash
|
||
launched, because of the design of the Sprout protocol (and the state of zero-knowledge
|
||
proof R&D at the time). Shielded transactions, by design, do not expose the payment
|
||
address of the sender when creating a transaction; in Sprout, this meant that the spending
|
||
key was a private input to the zero-knowledge proof, and not a key that could be used to
|
||
create a signature.
|
||
|
||
One of the R&D achievements behind the Sapling protocol was the ability to use elliptic
|
||
curves inside a circuit. With this primitive available, Sapling keys and payment addresses
|
||
could be designed such that transaction authorization involved a signature. While this was
|
||
designed to enable hardware wallets (which lack the power to create zero-knowledge proofs,
|
||
but can easily create signatures), it also enables the creation of a mechanism for signing
|
||
arbitrary messages. That mechanism is the subject of this ZIP.
|
||
|
||
|
||
Conventions
|
||
===========
|
||
|
||
The following constants and functions used in this ZIP are defined in the Zcash protocol
|
||
specification: [#protocol]_
|
||
|
||
- :math:`\mathsf{MerkleDepth}^\mathsf{Sapling}` and
|
||
:math:`\mathsf{Uncommitted}^\mathsf{Sapling}` [#protocol-constants]_
|
||
- :math:`\mathsf{MerkleCRH}^\mathsf{Sapling}` [#protocol-saplingmerklecrh]_
|
||
- :math:`\mathsf{DiversifyHash}(\mathsf{d})` [#protocol-concretediversifyhash]_
|
||
- :math:`\mathsf{MixingPedersenHash}(\mathsf{cm}, position)` [#protocol-concretemixinghash]_
|
||
- :math:`\mathsf{PRF}^\mathsf{nfSapling}_\mathsf{nk}(ρ)` [#protocol-concreteprfs]_
|
||
- :math:`\mathsf{SpendAuthSig.RandomizePrivate}(α, \mathsf{sk})`,
|
||
:math:`\mathsf{SpendAuthSig.RandomizePublic}(α, \mathsf{vk})`,
|
||
:math:`\mathsf{SpendAuthSig.Sign}(\mathsf{sk}, m)`, and
|
||
:math:`\mathsf{SpendAuthSig.Verify}(\mathsf{vk}, m, σ)` [#protocol-concretespendauthsig]_
|
||
- :math:`\mathsf{NoteCommit}^\mathsf{Sapling}_\mathsf{rcm}(\mathsf{g_d}, \mathsf{pk_d}, value)` [#protocol-concretewindowedcommit]_
|
||
- :math:`\mathsf{ValueCommit}_\mathsf{rcv}(value)` [#protocol-concretehomomorphiccommit]_
|
||
|
||
We also reproduce some notation and functions here for convenience:
|
||
|
||
- :math:`a\,||\,b` means the concatenation of sequences :math:`a` then :math:`b`.
|
||
|
||
- :math:`\mathsf{repr}_\mathbb{J}(P)` is the representation of the Jubjub elliptic curve
|
||
point :math:`P` as a bit sequence, defined in [#protocol-jubjub]_.
|
||
|
||
- :math:`\mathsf{BLAKE2b}\text{-}\mathsf{256}(p, x)` refers to unkeyed BLAKE2b-256 in
|
||
sequential mode, with an output digest length of 32 bytes, 16-byte personalization
|
||
string :math:`p`, and input :math:`x`.
|
||
|
||
|
||
Requirements
|
||
============
|
||
|
||
Given a payment address, a message, and a valid signature, the following properties should
|
||
hold:
|
||
|
||
- **Authentication:** the signature will not verify with any other payment address.
|
||
|
||
- **Binding:** the signature will not verify with any modification, extension, or
|
||
truncation of the message.
|
||
|
||
- **Non-malleability:** it should not be possible to obtain a second valid signature (with
|
||
a different encoding) for the same payment address and message without access to the
|
||
spending key for that payment address.
|
||
|
||
|
||
Non-requirements
|
||
================
|
||
|
||
Multiple signatures by a single payment addresses are not required to be unlinkable.
|
||
|
||
|
||
Specification
|
||
=============
|
||
|
||
A Sapling address signature is created by taking the process for creating a Sapling Spend
|
||
description, and running it with fixed inputs:
|
||
|
||
- A fake Sapling note with a value of :math:`1` zatoshi and :math:`\mathsf{rcm} = 0`.
|
||
- A Sapling commitment tree that is empty except for the commitment for the fake note.
|
||
|
||
Signature algorithm
|
||
-------------------
|
||
|
||
The inputs to the signature algorithm are:
|
||
|
||
- The payment address :math:`(\mathsf{d}, \mathsf{pk_d})`,
|
||
- Its corresponding expanded spending key :math:`(\mathsf{ask}, \mathsf{nsk}, \mathsf{ovk})`,
|
||
- The SLIP-44 [#slip-0044]_ coin type, and
|
||
- The message :math:`msg` to be signed.
|
||
|
||
The signature is created as follows:
|
||
|
||
- Derive the full viewing key :math:`(\mathsf{ak}, \mathsf{nk}, \mathsf{ovk})` from the expanded spending key.
|
||
|
||
- Let :math:`\mathsf{g_d} = \mathsf{DiversifyHash}(\mathsf{d})`.
|
||
|
||
- Let :math:`\mathsf{cm} = \mathsf{NoteCommit}^\mathsf{Sapling}_0(\mathsf{repr}_\mathbb{J}(\mathsf{g_d}), \mathsf{repr}_\mathbb{J}(\mathsf{pk_d}), 1)`.
|
||
|
||
- Let :math:`\mathsf{rt}` be the root of a Merkle tree with depth
|
||
:math:`\mathsf{MerkleDepth}^\mathsf{Sapling}` and hashing function
|
||
:math:`\mathsf{MerkleCRH}^\mathsf{Sapling}`, containing :math:`\mathsf{cm}` at position 0, and
|
||
:math:`\mathsf{Uncommitted}^\mathsf{Sapling}` at all other positions.
|
||
|
||
- Let :math:`path` be the Merkle path from position 0 to :math:`\mathsf{rt}`. [#protocol-merklepath]_
|
||
|
||
- Let :math:`\mathsf{cv} = \mathsf{ValueCommit}_0(1)`.
|
||
|
||
- This is a constant and may be pre-computed.
|
||
|
||
- Let :math:`\mathsf{nf} = \mathsf{PRF}^\mathsf{nfSapling}_{\mathsf{repr}_\mathbb{J}(\mathsf{nk})}(\mathsf{repr}_\mathbb{J}(\mathsf{MixingPedersenHash}(\mathsf{cm}, 0)))`.
|
||
|
||
- Select a random :math:`α`.
|
||
|
||
- Let :math:`\mathsf{rk} = \mathsf{SpendAuthSig.RandomizePublic}(α, \mathsf{ak})`.
|
||
|
||
- Let :math:`zkproof` be the byte sequence representation of a Sapling spend proof with primary input
|
||
:math:`(\mathsf{rt}, \mathsf{cv}, \mathsf{nf}, \mathsf{rk})`
|
||
and auxiliary input :math:`(path, 0, \mathsf{g_d}, \mathsf{pk_d}, 1, 0, \mathsf{cm}, 0, α, \mathsf{ak}, \mathsf{nsk})`.
|
||
[#protocol-spendstatement]_
|
||
|
||
- Let :math:`\mathsf{rsk} = \mathsf{SpendAuthSig.RandomizePrivate}(α, \mathsf{ask})`.
|
||
|
||
- Let :math:`coinType` be the 4-byte little-endian encoding of the coin type in its index
|
||
form, not its hardened form (i.e. 133 for mainnet Zcash).
|
||
|
||
- Let :math:`digest = \mathsf{BLAKE2b}\text{-}\mathsf{256}(\texttt{"ZIP304Signed"}\,||\,coinType, zkproof\,||\,msg)`.
|
||
|
||
- Let :math:`spendAuthSig = \mathsf{SpendAuthSig.Sign}(\mathsf{rsk}, digest)`.
|
||
|
||
- Return :math:`(\mathsf{nf}, \mathsf{rk}, zkproof, spendAuthSig)`.
|
||
|
||
Verification algorithm
|
||
----------------------
|
||
|
||
The inputs to the verification algorithm are:
|
||
|
||
- The payment address :math:`(\mathsf{d}, \mathsf{pk_d})`,
|
||
- The SLIP-44 [#slip-0044]_ coin type,
|
||
- The message :math:`msg` that is claimed to be signed, and
|
||
- The ZIP 304 signature :math:`(\mathsf{nf}, \mathsf{rk}, zkproof, spendAuthSig)`.
|
||
|
||
The signature MUST be verified as follows:
|
||
|
||
- Let :math:`coinType` be the 4-byte little-endian encoding of the coin type in its index
|
||
form, not its hardened form (i.e. 133 for mainnet Zcash).
|
||
|
||
- Let :math:`digest = \mathsf{BLAKE2b}\text{-}\mathsf{256}(\texttt{"ZIP304Signed"}\,||\,coinType, zkproof\,||\,msg)`.
|
||
|
||
- If :math:`\mathsf{SpendAuthSig.Verify}(\mathsf{rk}, digest, spendAuthSig) = 0`, return false.
|
||
|
||
- Let :math:`\mathsf{cm} = \mathsf{NoteCommit}^\mathsf{Sapling}_0(\mathsf{repr}_\mathbb{J}(\mathsf{DiversifyHash}(\mathsf{d})), \mathsf{repr}_\mathbb{J}(\mathsf{pk_d}), 1)`.
|
||
|
||
- Let :math:`\mathsf{rt}` be the root of a Merkle tree with depth
|
||
:math:`\mathsf{MerkleDepth}^\mathsf{Sapling}` and hashing function
|
||
:math:`\mathsf{MerkleCRH}^\mathsf{Sapling}`, containing :math:`\mathsf{cm}` at position 0, and
|
||
:math:`\mathsf{Uncommitted}^\mathsf{Sapling}` at all other positions.
|
||
|
||
- Let :math:`path` be the Merkle path from position 0 to :math:`\mathsf{rt}`. [#protocol-merklepath]_
|
||
|
||
- Let :math:`\mathsf{cv} = \mathsf{ValueCommit}_0(1)`.
|
||
|
||
- This is a constant and may be pre-computed.
|
||
|
||
- Decode and verify :math:`zkproof` as a Sapling spend proof with primary input
|
||
:math:`(\mathsf{rt}, \mathsf{cv}, \mathsf{nf}, \mathsf{rk})`. [#protocol-spendstatement]_ If verification fails, return false.
|
||
|
||
- Return true.
|
||
|
||
Signature encoding
|
||
------------------
|
||
|
||
The raw form of a ZIP 304 signature is
|
||
:math:`\mathsf{nf}\,||\,\mathsf{LEBS2OSP}_{256}(\mathsf{repr}_{\mathbb{J}}(\mathsf{rk}))\,||\,zkproof\,||\,spendAuthSig`,
|
||
for a total size of 320 bytes.
|
||
|
||
When encoding a ZIP 304 signature in a human-readable format, implementations **SHOULD**
|
||
use standard Base64 for compatibility with the ``signmessage`` and ``verifymessage`` RPC
|
||
methods in ``zcashd``. ZIP 304 signatures in this form are 428 bytes. The encoded form is
|
||
the string :math:`\texttt{"zip304:"}` followed by the result of Base64-encoding [#RFC4648]_
|
||
the raw form of the signature.
|
||
|
||
Rationale
|
||
=========
|
||
|
||
We use a fake note within the signature scheme in order to reuse the Sapling Spend circuit
|
||
and its parameters. It is possible to construct a signature scheme with a smaller encoded
|
||
signature, but this would require a new circuit and another parameter-generation ceremony
|
||
(if Groth16 were used).
|
||
|
||
We use a note value of :math:`1` zatoshi instead of zero to ensure that the payment address is
|
||
fully bound to :math:`zkproof`. Notes with zero value have certain constraints disabled
|
||
inside the circuit.
|
||
|
||
We set :math:`\mathsf{rcm}` and :math:`\mathsf{rcv}` to zero because we do not need the hiding properties of
|
||
the note commitment or value commitment schemes (as we are using a fixed-value fake note),
|
||
and can thus omit both :math:`\mathsf{rcm}` and :math:`\mathsf{rcv}` from the signature.
|
||
|
||
|
||
Security and Privacy Considerations
|
||
===================================
|
||
|
||
A normal (and desired) property of signature schemes is that all signatures for a specific
|
||
public key are linkable if the public key is known. ZIP 304 signatures have the additional
|
||
property that all signatures for a specific payment address are linkable without knowing
|
||
the payment address, as the first 32 bytes of each signature will be identical.
|
||
|
||
A signature is bound to a specific diversified address of the spending key. Signatures for
|
||
different diversified addresses of the same spending key are unlinkable, as long as
|
||
:math:`α` is never re-used across signatures.
|
||
|
||
Most of the data within a ZIP 304 signature is inherently non-malleable:
|
||
|
||
- :math:`\mathsf{nf}` is a binary public input to :math:`zkproof`.
|
||
- :math:`\mathsf{rk}` is internally bound to :math:`spendAuthSig` by the design of RedJubjub.
|
||
- RedJubjub signatures are themselves non-malleable.
|
||
|
||
The one component that is inherently malleable is :math:`zkproof`. The zero-knowledge
|
||
property of a Groth16 proof implies that anyone can take a valid proof, and re-randomize
|
||
it to obtain another valid proof with a different encoding. We prevent this by binding the
|
||
encoding of :math:`zkproof` to :math:`spendAuthSig`, by including :math:`zkproof` in the
|
||
message digest.
|
||
|
||
|
||
Reference implementation
|
||
========================
|
||
|
||
https://github.com/zcash/librustzcash/pull/210
|
||
|
||
|
||
References
|
||
==========
|
||
|
||
.. [#RFC2119] `RFC 2119: Key words for use in RFCs to Indicate Requirement Levels <https://www.rfc-editor.org/rfc/rfc2119.html>`_
|
||
.. [#RFC4648] `RFC 4648: The Base16, Base32, and Base64 Data Encodings <https://www.rfc-editor.org/rfc/rfc4648>`_
|
||
.. [#protocol] `Zcash Protocol Specification, Version 2020.1.15 or later <protocol/protocol.pdf>`_
|
||
.. [#protocol-merklepath] `Zcash Protocol Specification, Version 2020.1.15. Section 4.8: Merkle path validity <protocol/protocol.pdf#merklepath>`_
|
||
.. [#protocol-spendstatement] `Zcash Protocol Specification, Version 2020.1.15. Section 4.15.2: Spend Statement (Sapling) <protocol/protocol.pdf#spendstatement>`_
|
||
.. [#protocol-constants] `Zcash Protocol Specification, Version 2020.1.15. Section 5.3: Constants <protocol/protocol.pdf#constants>`_
|
||
.. [#protocol-saplingmerklecrh] `Zcash Protocol Specification, Version 2020.1.15. Section 5.4.1.3: Merkle Tree Hash Function <protocol/protocol.pdf#saplingmerklecrh>`_
|
||
.. [#protocol-concretediversifyhash] `Zcash Protocol Specification, Version 2020.1.15. Section 5.4.1.6: DiversifyHash Hash Function <protocol/protocol.pdf#concretediversifyhash>`_
|
||
.. [#protocol-concretemixinghash] `Zcash Protocol Specification, Version 2020.1.15. Section 5.4.1.8: Mixing Pedersen Hash Function <protocol/protocol.pdf#concretemixinghash>`_
|
||
.. [#protocol-concreteprfs] `Zcash Protocol Specification, Version 2020.1.15. Section 5.4.2: Pseudo Random Functions <protocol/protocol.pdf#concreteprfs>`_
|
||
.. [#protocol-concretespendauthsig] `Zcash Protocol Specification, Version 2020.1.15. Section 5.4.6.1: Spend Authorization Signature <protocol/protocol.pdf#concretespendauthsig>`_
|
||
.. [#protocol-concretewindowedcommit] `Zcash Protocol Specification, Version 2020.1.15. Section 5.4.7.2: Windowed Pedersen commitments <protocol/protocol.pdf#concretewindowedcommit>`_
|
||
.. [#protocol-concretehomomorphiccommit] `Zcash Protocol Specification, Version 2020.1.15. Section 5.4.7.3: Homomorphic Pedersen commitments <protocol/protocol.pdf#concretehomomorphiccommit>`_
|
||
.. [#protocol-jubjub] `Zcash Protocol Specification, Version 2020.1.15. Section 5.4.8.3: Jubjub <protocol/protocol.pdf#jubjub>`_
|
||
.. [#slip-0044] `SLIP-0044 : Registered coin types for BIP-0044 <https://github.com/satoshilabs/slips/blob/master/slip-0044.md>`_
|