mirror of https://github.com/zcash/zips.git
289 lines
14 KiB
ReStructuredText
289 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: Wallet
|
||
Created: 2020-06-01
|
||
License: MIT
|
||
|
||
|
||
Terminology
|
||
===========
|
||
|
||
The key word "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-spec]_
|
||
|
||
- :math:`\mathsf{MerkleDepth}^\mathsf{Sapling}` and
|
||
:math:`\mathsf{Uncommitted}^\mathsf{Sapling}` [#constants]_
|
||
- :math:`\mathsf{MerkleCRH}^\mathsf{Sapling}` [#merkle-crh]_
|
||
- :math:`\mathsf{DiversifyHash}(d)` [#diversify-hash]_
|
||
- :math:`\mathsf{MixingPedersenHash}(cm, position)` [#mixing-pedersen-hash]_
|
||
- :math:`\mathsf{PRF}^\mathsf{nfSapling}_nk(ρ)` [#prfs]_
|
||
- :math:`\mathsf{SpendAuthSig.RandomizePrivate}(α, sk)`,
|
||
:math:`\mathsf{SpendAuthSig.RandomizePublic}(α, vk)`,
|
||
:math:`\mathsf{SpendAuthSig.Sign}(sk, m)`, and
|
||
:math:`\mathsf{SpendAuthSig.Verify}(vk, m, σ)` [#spend-auth-sig]_
|
||
- :math:`\mathsf{NoteCommit}^\mathsf{Sapling}_rcm(g_d, pk_d, value)` [#note-commit]_
|
||
- :math:`\mathsf{ValueCommit}_rcv(value)` [#value-commit]_
|
||
|
||
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 [#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 1 zatoshi and 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:`(d, pk_d)`,
|
||
- Its corresponding expanded spending key :math:`(ask, nsk, 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:`(ak, nk, ovk)` from the expanded spending key.
|
||
|
||
- Let :math:`g_d = \mathsf{DiversifyHash}(d)`.
|
||
|
||
- Let :math:`cm = \mathsf{NoteCommit}^\mathsf{Sapling}_0(\mathsf{repr}_\mathbb{J}(g_d), \mathsf{repr}_\mathbb{J}(pk_d), 1)`.
|
||
|
||
- Let :math:`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:`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:`rt`. [#merkle-path]_
|
||
|
||
- Let :math:`cv = \mathsf{ValueCommit}_0(1)`.
|
||
|
||
- This is a constant and may be pre-computed.
|
||
|
||
- Let :math:`nf = \mathsf{PRF}^\mathsf{nfSapling}_{\mathsf{repr}_\mathbb{J}(nk)}(\mathsf{repr}_\mathbb{J}(\mathsf{MixingPedersenHash}(cm, 0)))`.
|
||
|
||
- Select a random :math:`α`.
|
||
|
||
- Let :math:`rk = \mathsf{SpendAuthSig.RandomizePublic}(α, ak)`.
|
||
|
||
- Let :math:`zkproof` be a Sapling spend proof with primary input :math:`(rt, cv, nf, rk)`
|
||
and auxiliary input :math:`(path, 0, g_d, pk_d, 1, 0, cm, 0, α, ak, nsk)`.
|
||
[#spend-statement]_
|
||
|
||
- Let :math:`rsk = \mathsf{SpendAuthSig.RandomizePrivate}(α, 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}(rsk, digest)`.
|
||
|
||
- Return :math:`(nf, rk, zkproof, spendAuthSig)`.
|
||
|
||
Verification algorithm
|
||
----------------------
|
||
|
||
The inputs to the verification algorithm are:
|
||
|
||
- The payment address :math:`(d, 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:`(nf, rk, zkproof, spendAuthSig)`.
|
||
|
||
The signature is 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}(rk, digest, spendAuthSig) = 0`, return false.
|
||
|
||
- Let :math:`cm = \mathsf{NoteCommit}^\mathsf{Sapling}_0(\mathsf{repr}_\mathbb{J}(\mathsf{DiversifyHash}(d)), \mathsf{repr}_\mathbb{J}(pk_d), 1)`.
|
||
|
||
- Let :math:`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:`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:`rt`. [#merkle-path]_
|
||
|
||
- Let :math:`cv = \mathsf{ValueCommit}_0(1)`.
|
||
|
||
- This is a constant and may be pre-computed.
|
||
|
||
- Verify :math:`zkproof` as a Sapling spend proof with primary input
|
||
:math:`(rt, cv, nf, rk)`. [#spend-statement]_ If verification fails, return false.
|
||
|
||
- Return true.
|
||
|
||
Signature encoding
|
||
------------------
|
||
|
||
The raw form of a ZIP 304 signature is :math:`nf\,||\,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 '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 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:`rcm` and :math:`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:`rcm` and :math:`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:`nullifier` is a binary public input to :math:`zkproof`.
|
||
- :math:`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] `Key words for use in RFCs to Indicate Requirement Levels <https://tools.ietf.org/html/rfc2119>`_
|
||
.. [#RFC4648] `The Base16, Base32, and Base64 Data Encodings <https://www.rfc-editor.org/rfc/rfc4648>`_
|
||
.. [#protocol-spec] `Zcash Protocol Specification, Version 2020.1.4 or later [Overwinter+Sapling+Blossom+Heartwood] <protocol/protocol.pdf>`_
|
||
.. [#constants] `Section 5.3: Constants. Zcash Protocol Specification, Version 2020.1.4 or later [Overwinter+Sapling+Blossom+Heartwood] <protocol/protocol.pdf#merklepath>`_
|
||
.. [#merkle-crh] `Section 5.4.1.3: Merkle Tree Hash Function. Zcash Protocol Specification, Version 2020.1.4 or later [Overwinter+Sapling+Blossom+Heartwood] <protocol/protocol.pdf#saplingmerklecrh>`_
|
||
.. [#diversify-hash] `Section 5.4.1.6: DiversifyHash Hash Function. Zcash Protocol Specification, Version 2020.1.4 or later [Overwinter+Sapling+Blossom+Heartwood] <protocol/protocol.pdf#concretediversifyhash>`_
|
||
.. [#mixing-pedersen-hash] `Section 5.4.1.8: Mixing Pedersen Hash Function. Zcash Protocol Specification, Version 2020.1.4 or later [Overwinter+Sapling+Blossom+Heartwood] <protocol/protocol.pdf#concretemixinghash>`_
|
||
.. [#prfs] `Section 5.4.2: Pseudo Random Functions. Zcash Protocol Specification, Version 2020.1.4 or later [Overwinter+Sapling+Blossom+Heartwood] <protocol/protocol.pdf#concreteprfs>`_
|
||
.. [#spend-auth-sig] `Section 5.4.6.1: Spend Authorization Signature. Zcash Protocol Specification, Version 2020.1.4 or later [Overwinter+Sapling+Blossom+Heartwood] <protocol/protocol.pdf#concretespendauthsig>`_
|
||
.. [#note-commit] `Section 5.4.7.2: Windowed Pedersen commitments. Zcash Protocol Specification, Version 2020.1.4 or later [Overwinter+Sapling+Blossom+Heartwood] <protocol/protocol.pdf#concretewindowedcommit>`_
|
||
.. [#value-commit] `Section 5.4.7.3: Homomorphic Pedersen commitments. Zcash Protocol Specification, Version 2020.1.4 or later [Overwinter+Sapling+Blossom+Heartwood] <protocol/protocol.pdf#concretehomomorphiccommit>`_
|
||
.. [#jubjub] `Section 5.4.8.3: Jubjub. Zcash Protocol Specification, Version 2020.1.4 or later [Overwinter+Sapling+Blossom+Heartwood] <protocol/protocol.pdf#jubjub>`_
|
||
.. [#slip-0044] `SLIP-0044 : Registered coin types for BIP-0044 <https://github.com/satoshilabs/slips/blob/master/slip-0044.md>`_
|
||
.. [#merkle-path] `Section 4.8: Merkle path validity. Zcash Protocol Specification, Version 2020.1.4 or later [Overwinter+Sapling+Blossom+Heartwood] <protocol/protocol.pdf#merklepath>`_
|
||
.. [#spend-statement] `Section 4.15.2: Spend Statement (Sapling). Zcash Protocol Specification, Version 2020.1.4 or later [Overwinter+Sapling+Blossom+Heartwood] <protocol/protocol.pdf#spendstatement>`_
|