ZIP 32: add internal key derivation for Sapling and Orchard.

Signed-off-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
Daira Hopwood 2021-12-31 15:39:43 +00:00
parent 98515d003f
commit 79e6a10f0a
5 changed files with 4044 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 89 KiB

View File

@ -253,6 +253,64 @@ let :math:`\mathcal{H}^\mathsf{Sapling}` be as defined in [#protocol-saplingkeyc
- :math:`\mathsf{dk}_i = \mathsf{truncate}_{32}(\mathsf{PRF^{expand}}(I_L, [\texttt{0x16}]`:math:`||\,\mathsf{dk}_{par}))`
- :math:`\mathsf{c}_i = I_R`.
Sapling internal key derivation
-------------------------------
The above derivation mechanisms produce external addresses suitable for giving out to senders.
For each such external address, we also want to produce another address for use by wallets for
internal operations such as change and auto-shielding. Unlike BIP 44 that allows deriving a
stream of external and internal addresses in the same hierarchical derivation tree [#bip-0044]_,
for each external full viewing key we only need to be able to derive a single internal full
viewing key that has viewing authority for just internal transfers. We also need to be able to
derive the corresponding internal spending key if we have the external spending key.
Deriving a Sapling internal spending key
````````````````````````````````````````
Let :math:`(\mathsf{ask}, \mathsf{nsk}, \mathsf{ovk}, \mathsf{dk})` be the external spending key.
- Derive the corresponding :math:`\mathsf{ak}` and :math:`\mathsf{nk}` as specified in [#protocol-saplingkeycomponents]_.
- Let :math:`I = \textsf{BLAKE2b-256}(\texttt{"Zcash_SaplingInt"}, \mathsf{EncodeExtFVKParts}(\mathsf{ak}, \mathsf{nk}, \mathsf{ovk}, \mathsf{dk}))`.
- Let :math:`I_\mathsf{nsk} = \mathsf{ToScalar^{Sapling}}(\mathsf{PRF^{expand}}(I, [\mathtt{0x17}]))`.
- Let :math:`R = \mathsf{PRF^{expand}}(I, [\mathtt{0x18}])`.
- Let :math:`\mathsf{nsk_{internal}} = (I_\mathsf{nsk} + \mathsf{nsk}) \pmod{r_\mathbb{J}}`.
- Split :math:`R` into two 32-byte sequences, :math:`\mathsf{dk_{internal}}` and :math:`\mathsf{ovk_{internal}}`.
- Return the internal spending key as :math:`(\mathsf{ask}, \mathsf{nsk_{internal}}, \mathsf{ovk_{internal}}, \mathsf{dk_{internal}})`.
Deriving a Sapling internal full viewing key
````````````````````````````````````````````
Let :math:`\mathcal{H}^\mathsf{Sapling}` be as defined in [#protocol-saplingkeycomponents]_.
Let :math:`(\mathsf{ak}, \mathsf{nk}, \mathsf{ovk}, \mathsf{dk})` be the external full viewing key.
- Let :math:`I = \textsf{BLAKE2b-256}(\texttt{"Zcash_SaplingInt"}, \mathsf{EncodeExtFVKParts}(\mathsf{ak}, \mathsf{nk}, \mathsf{ovk}, \mathsf{dk}))`.
- Let :math:`I_\mathsf{nsk} = \mathsf{ToScalar^{Sapling}}(\mathsf{PRF^{expand}}(I, [\mathtt{0x17}]))`.
- Let :math:`R = \mathsf{PRF^{expand}}(I, [\mathtt{0x18}])`.
- Let :math:`\mathsf{nk_{internal}} = [I_\mathsf{nsk}] \mathcal{H}^\mathsf{Sapling} + \mathsf{nk}`.
- Split :math:`R` into two 32-byte sequences, :math:`\mathsf{dk_{internal}}` and :math:`\mathsf{ovk_{internal}}`.
- Return the internal full viewing key as :math:`(\mathsf{ak}, \mathsf{nk_{internal}}, \mathsf{ovk_{internal}}, \mathsf{dk_{internal}})`.
This design uses the same technique as non-hardened derivation to obtain a full viewing key
with the same spend authority (the private key corresponding to :math:`\mathsf{ak}`) as the
original, but viewing authority only for internal transfers.
The values of :math:`I`, :math:`I_\mathsf{nsk}`, and :math:`R` are the same between deriving
a full viewing key, and deriving the corresponding spending key. Both of these derivations
are shown in the following diagram:
.. figure:: zip-0032-sapling-internal-key-derivation.png
:width: 900px
:align: center
:figclass: align-center
Diagram of Sapling internal key derivation
(For simplicity, the proof authorizing key is not shown.)
This method of deriving internal keys is applied to external keys that are children of the
Account level. It was implemented in `zcashd` as part of support for ZIP 316 [#zip-0316]_.
Sapling diversifier derivation
------------------------------
@ -323,6 +381,8 @@ Sprout child key derivation
- Use :math:`\mathsf{DecodeASK}(I_L)` as the child spending key :math:`\mathsf{a}_{\mathsf{sk},i}`.
- Use :math:`I_R` as the child chain code :math:`\mathsf{c}_i`.
There is no support for internal key derivation for Sprout.
Specification: Orchard key derivation
=====================================
@ -365,6 +425,51 @@ Orchard child key derivation
- Use :math:`I_L` as the child spending key :math:`\mathsf{sk}_{i}`.
- Use :math:`I_R` as the child chain code :math:`\mathsf{c}_i`.
Orchard internal key derivation
-------------------------------
As in the case of Sapling, for each external address, we want to produce another address
for use by wallets for internal operations such as change and auto-shielding. That is, for
each external full viewing key we need to be able to derive a single internal full viewing
key that has viewing authority for just internal transfers. We also need to be able to
derive the corresponding internal spending key if we have the external spending key.
Let :math:`\mathsf{ask}` be the spend authorizing key if available, and
let :math:`(\mathsf{ak}, \mathsf{nk}, \mathsf{rivk})` be the corresponding external full
viewing key, obtained as specified in [#protocol-orchardkeycomponents]_.
- Let :math:`K = \mathsf{I2LEBSP}_{256}(\mathsf{rivk})`.
- Let :math:`\mathsf{rivk_{internal}} = \mathsf{ToScalar^{Orchard}}(\mathsf{PRF^{expand}}(K, [\mathtt{0x83}] \,||\, \mathsf{I2LEOSP_{256}}(\mathsf{ak}) \,||\, \mathsf{I2LEOSP_{256}}(\mathsf{nk}))`.
Then the expanded internal spending key is :math:`(\mathsf{ask}, \mathsf{nk}, \mathsf{rivk_{internal}})`,
and the internal full viewing key is :math:`(\mathsf{ak}, \mathsf{nk}, \mathsf{rivk_{internal}})`.
Unlike `Sapling internal key derivation`_, we do not base this internal key derivation
procedure on non-hardened derivation, which is not defined for Orchard. We can obtain the
desired separation of viewing authority by modifying only the :math:`\mathsf{rivk_{internal}}`
field relative to the external full viewing key, which results in different
:math:`\mathsf{dk_{internal}}`, :math:`\mathsf{ivk_{internal}}` and :math:`\mathsf{ovk_{internal}}`
fields being derived, as specified in [#protocol-orchardkeycomponents]_.
The values of :math:`K` and :math:`\mathsf{rivk_{internal}}` are the same between deriving
a full viewing key, and deriving the corresponding spending key. Both of these derivations
are shown in the following diagram:
.. figure:: zip-0032-orchard-internal-key-derivation.png
:width: 720px
:align: center
:figclass: align-center
Diagram of Orchard internal key derivation, also showing derivation from the parent extended spending key
Note that there does not exist an :math:`\mathsf{sk}` that directly generates the internal key
components by the procedure described in [#protocol-orchardkeycomponents]_. A similar effect
could be obtained by storing a flag that indicates external or internal usage along with the
original :math:`\mathsf{sk}`, but we do not define a specific format for this.
This method of deriving internal keys is applied to external keys that are children of the
Account level. It was implemented in `zcashd` as part of support for ZIP 316 [#zip-0316]_.
Orchard diversifier derivation
------------------------------
@ -637,9 +742,11 @@ References
.. [#bip-0044] `BIP 44: Multi-Account Hierarchy for Deterministic Wallets <https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki>`_
.. [#slip-0044] `SLIP 44: Registered coin types for BIP-0044 <https://github.com/satoshilabs/slips/blob/master/slip-0044.md>`_
.. [#bip-0173] `BIP 173: Base32 address format for native v0-16 witness outputs <https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki>`_
.. [#zip-0316] `ZIP 316: Unified Addresses and Unified Viewing Keys <zip-0316.rst>`_
.. [#protocol] `Zcash Protocol Specification, Version 2021.2.16 or later [NU5 proposal] <protocol/protocol.pdf>`_
.. [#protocol-networks] `Zcash Protocol Specification, Version 2021.2.16 [NU5 proposal]. Section 3.12: Mainnet and Testnet <protocol/protocol.pdf#networks>`_
.. [#protocol-saplingkeycomponents] `Zcash Protocol Specification, Version 2021.2.16 [NU5 proposal]. Section 4.2.2: Sapling Key Components <protocol/protocol.pdf#saplingkeycomponents>`_
.. [#protocol-orchardkeycomponents] `Zcash Protocol Specification, Version 2021.2.16 [NU5 proposal]. Section 4.2.3: Orchard Key Components <protocol/protocol.pdf#orchardkeycomponents>`_
.. [#protocol-concretediversifyhash] `Zcash Protocol Specification, Version 2021.2.16 [NU5 proposal]. Section 5.4.1.6: DiversifyHash^Sapling and DiversifyHash^Orchard Hash Functions <protocol/protocol.pdf#concretediversifyhash>`_
.. [#protocol-concretespendauthsig] `Zcash Protocol Specification, Version 2021.2.16 [NU5 proposal]. Section 5.4.6.1: Spend Authorization Signature <protocol/protocol.pdf#concretespendauthsig>`_
.. [#protocol-jubjub] `Zcash Protocol Specification, Version 2021.2.16 [NU5 proposal]. Section 5.4.9.3: Jubjub <protocol/protocol.pdf#jubjub>`_