From b3688a70b1ce54d3f0124f97b3dd69204a0f8214 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 1 Oct 2024 01:15:18 +0000 Subject: [PATCH 1/5] ZIP 32: Extract a common hardened key derivation process from Orchard --- zips/zip-0032.rst | 74 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 17 deletions(-) diff --git a/zips/zip-0032.rst b/zips/zip-0032.rst index a008a7402..fc68b8697 100644 --- a/zips/zip-0032.rst +++ b/zips/zip-0032.rst @@ -356,12 +356,64 @@ The default diversifier for a Sapling extended key is defined to be :math:`d_j`, least nonnegative integer yielding a valid diversifier. -Specification: Orchard key derivation -===================================== +Specification: Hardened-only key derivation +=========================================== The derivation mechanism for Sapling addresses specified above incurs significant complexity to support non-hardened derivation. In the several years since Sapling was deployed, we have seen no use cases for -non-hardened derivation appear. With that in mind, we only support hardened key derivation for Orchard. +non-hardened derivation appear. With that in mind, we now have a general hardened-only derivation +process that retains compatibility with existing derivation path semantics (to enable deriving the same +path across multiple contexts). + +Instantiation +------------- + +Let :math:`\mathsf{Context}` be the context in which the hardened-only key derivation process is +instantiated (e.g. a shielded protocol). We define two context-specific constants: + +- :math:`\mathsf{Context.MKGDomain}` is a 16-byte domain separator used during master key generation. +- :math:`\mathsf{Context.CKDDomain}` is a 1-byte domain separator used during child key derivation. + This should be tracked as part of the global set of domains defined for :math:`\mathsf{PRF^{expand}}`. + +Hardened-only master key generation +----------------------------------- + +Let :math:`\mathsf{IKM}` be an input key material byte sequence, which MUST use an unambiguous encoding +within the given context, and SHOULD contain at least 256 bits of entropy. + +:math:`\mathsf{MKGh}^\mathsf{Context}(\mathsf{IKM}) \rightarrow (\mathsf{sk}_m, \mathsf{c}_m)` + +- Calculate :math:`I = \mathsf{BLAKE2b}\text{-}\mathsf{512}(\mathsf{Context.MKGDomain}, \mathsf{IKM})`. +- Split :math:`I` into two 32-byte sequences, :math:`I_L` and :math:`I_R`. +- Use :math:`I_L` as the master secret key :math:`\mathsf{sk}_m`. +- Use :math:`I_R` as the master chain code :math:`\mathsf{c}_m`. +- Return :math:`(\mathsf{sk}_m, \mathsf{c}_m)`. + +Hardened-only child key derivation +---------------------------------- + +:math:`\mathsf{CKDh}^\mathsf{Context}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)`:math:`\rightarrow (\mathsf{sk}_i, \mathsf{c}_i)` + +- Check whether :math:`i \geq 2^{31}` (whether the child is a hardened key). + + - If so (hardened child): let + :math:`I = \mathsf{PRF^{expand}}(\mathsf{c}_{par}, \mathsf{Context.CKDDomain}\,||\,\mathsf{sk}_{par}\,||\,\mathsf{I2LEOSP}_{32}(i))`. + - If not (normal child): return failure. + +- Split :math:`I` into two 32-byte sequences, :math:`I_L` and :math:`I_R`. +- Use :math:`I_L` as the child secret key :math:`\mathsf{sk}_i`. +- Use :math:`I_R` as the child chain code :math:`\mathsf{c}_i`. +- Return :math:`(\mathsf{sk}_i, \mathsf{c}_i)`. + + +Specification: Orchard key derivation +===================================== + +We only support hardened key derivation for Orchard. We instantiate the hardened key generation +process with the following constants: + +- :math:`\mathsf{Orchard.MKGDomain} = \texttt{“ZcashIP32Orchard”}` +- :math:`\mathsf{Orchard.CKDDomain} = [\texttt{0x81}]` Orchard extended keys --------------------- @@ -374,11 +426,7 @@ Orchard master key generation Let :math:`S` be a seed byte sequence of a chosen length, which MUST be at least 32 and at most 252 bytes. -- Calculate :math:`I = \mathsf{BLAKE2b}\text{-}\mathsf{512}(\texttt{“ZcashIP32Orchard”}, S)`. -- Split :math:`I` into two 32-byte sequences, :math:`I_L` and :math:`I_R`. -- Use :math:`I_L` as the master spending key :math:`\mathsf{sk}_m`. -- Use :math:`I_R` as the master chain code :math:`\mathsf{c}_m`. -- Return :math:`(\mathsf{sk}_m, \mathsf{c}_m)` as the master extended spending key +- Return :math:`\mathsf{MKGh}^\mathsf{Orchard}(S)` as the master extended spending key :math:`m_\mathsf{Orchard}`. Orchard child key derivation @@ -386,15 +434,7 @@ Orchard child key derivation :math:`\mathsf{CDKsk}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)`:math:`\rightarrow (\mathsf{sk}_{i}, \mathsf{c}_i)` -- Check whether :math:`i \geq 2^{31}` (whether the child is a hardened key). - - - If so (hardened child): let - :math:`I = \mathsf{PRF^{expand}}(\mathsf{c}_{par}, [\texttt{0x81}]\,||\,\mathsf{sk}_{par}\,||\,\mathsf{I2LEOSP}_{32}(i))`. - - If not (normal child): return failure. - -- Split :math:`I` into two 32-byte sequences, :math:`I_L` and :math:`I_R`. -- 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`. +- Return :math:`\mathsf{CKDh}^\mathsf{Orchard}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)` Note that the resulting child spending key may produce an invalid external FVK, as specified in [#protocol-orchardkeycomponents]_, with small probability. The corresponding internal FVK From 01e49d10b8e4ced97cf52ca708e90bf539778f1b Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 1 Oct 2024 02:31:48 +0000 Subject: [PATCH 2/5] ZIP 32: Define an arbitrary key derivation process --- zips/zip-0032.rst | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/zips/zip-0032.rst b/zips/zip-0032.rst index fc68b8697..ce4dc61e8 100644 --- a/zips/zip-0032.rst +++ b/zips/zip-0032.rst @@ -508,6 +508,47 @@ valid diversifiers. The default diversifier for :math:`(\mathsf{sk}_i, \mathsf{c}_i)` is defined to be :math:`d_{i,0}.` +Specification: Arbitrary key derivation +======================================= + +In some contexts there is a need for deriving arbitrary keys with the same derivation path as +existing key material (for example, deriving an arbitrary account-level key), without the need for +ecosystem-wide coordination. The following instantiation of the hardened key generation process may +be used for this purpose. + +Let :math:`\mathsf{ContextString}` be a globally-unique non-empty sequence of at most 65535 bytes +that identifies the desired context. + +We instantiate the hardened key generation process with the following constants: + +- :math:`\mathsf{Arbitrary.MKGDomain} = \texttt{“ZcashArbitraryKD”}` +- :math:`\mathsf{Arbitrary.CKDDomain} = [\texttt{0xAB}]` + +Arbitrary master key generation +------------------------------- + +Let :math:`S` be a seed byte sequence of a chosen length, which MUST be at least 32 and at most 252 bytes. + +The master extended arbitrary key is: + +:math:`m_\mathsf{Arbitrary} = \mathsf{MKGh}^\mathsf{Arbitrary}(` +:math:`\mathsf{I2LEOSP}_{16}(\mathsf{length}(\mathsf{ContextString}))\,||\,\mathsf{ContextString}\,||\,` +:math:`[\mathsf{length}(S)]\,||\,S)`. + +Arbitrary child key derivation +------------------------------ + +:math:`\mathsf{CKDarb}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)`:math:`\rightarrow (\mathsf{sk}_i, \mathsf{c}_i)` + +- Return :math:`\mathsf{CKDh}^\mathsf{Arbitrary}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)` + +If the context requires a 64-byte key (for example, to avoid an entropy bottleneck in its particular +subsequent operations), and :math:`i` is the last element of an HD path, the concatenation +:math:`\mathsf{sk}_i\,||\,\mathsf{c}_i` MAY be used as a key. In this case, +:math:`(\mathsf{sk}_i, \mathsf{c}_i)` MUST NOT be given as input to :math:`\mathsf{CKDarb}` (this +is a restatement of the requirement that :math:`i` is the last element of an HD path). + + Specification: Wallet usage =========================== From 83a5616fa3750671d8f088e713e7964fac7aea74 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 1 Oct 2024 13:56:45 +0100 Subject: [PATCH 3/5] ZIP 32: Apply suggestions from code review Co-authored-by: Daira-Emma Hopwood --- zips/zip-0032.rst | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/zips/zip-0032.rst b/zips/zip-0032.rst index ce4dc61e8..e9aea86ef 100644 --- a/zips/zip-0032.rst +++ b/zips/zip-0032.rst @@ -20,8 +20,8 @@ Terminology =========== -The key words "MUST", "MUST NOT", 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 key words "MUST", "MUST NOT", "SHOULD", "RECOMMENDED", and "MAY" in this document are to be +interpreted as described in BCP 14 [#BCP14]_ when, and only when, they appear in all capitals. "Jubjub" refers to the elliptic curve defined in [#protocol-jubjub]_. @@ -371,15 +371,20 @@ Instantiation Let :math:`\mathsf{Context}` be the context in which the hardened-only key derivation process is instantiated (e.g. a shielded protocol). We define two context-specific constants: -- :math:`\mathsf{Context.MKGDomain}` is a 16-byte domain separator used during master key generation. -- :math:`\mathsf{Context.CKDDomain}` is a 1-byte domain separator used during child key derivation. - This should be tracked as part of the global set of domains defined for :math:`\mathsf{PRF^{expand}}`. +- :math:`\mathsf{Context.MKGDomain}` is a sequence of 16 bytes, used as a domain separator during + master key generation. It SHOULD be disjoint from other domain separators used with BLAKE2b in + Zcash protocols. +- :math:`\mathsf{Context.CKDDomain}` is a byte value, used as a domain separator during child key + derivation. This should be tracked as part of the global set of domains defined for + :math:`\mathsf{PRF^{expand}}`. Hardened-only master key generation ----------------------------------- Let :math:`\mathsf{IKM}` be an input key material byte sequence, which MUST use an unambiguous encoding -within the given context, and SHOULD contain at least 256 bits of entropy. +within the given context, and SHOULD contain at least 256 bits of entropy. It is RECOMMENDED to +use a prefix-free encoding, which may require the use of length fields if multiple fields need +to be encoded. :math:`\mathsf{MKGh}^\mathsf{Context}(\mathsf{IKM}) \rightarrow (\mathsf{sk}_m, \mathsf{c}_m)` @@ -397,7 +402,7 @@ Hardened-only child key derivation - Check whether :math:`i \geq 2^{31}` (whether the child is a hardened key). - If so (hardened child): let - :math:`I = \mathsf{PRF^{expand}}(\mathsf{c}_{par}, \mathsf{Context.CKDDomain}\,||\,\mathsf{sk}_{par}\,||\,\mathsf{I2LEOSP}_{32}(i))`. + :math:`I = \mathsf{PRF^{expand}}(\mathsf{c}_{par}, [\mathsf{Context.CKDDomain}]\,||\,\mathsf{sk}_{par}\,||\,\mathsf{I2LEOSP}_{32}(i))`. - If not (normal child): return failure. - Split :math:`I` into two 32-byte sequences, :math:`I_L` and :math:`I_R`. @@ -413,7 +418,7 @@ We only support hardened key derivation for Orchard. We instantiate the hardened process with the following constants: - :math:`\mathsf{Orchard.MKGDomain} = \texttt{“ZcashIP32Orchard”}` -- :math:`\mathsf{Orchard.CKDDomain} = [\texttt{0x81}]` +- :math:`\mathsf{Orchard.CKDDomain} = \texttt{0x81}` Orchard extended keys --------------------- @@ -516,13 +521,13 @@ existing key material (for example, deriving an arbitrary account-level key), wi ecosystem-wide coordination. The following instantiation of the hardened key generation process may be used for this purpose. -Let :math:`\mathsf{ContextString}` be a globally-unique non-empty sequence of at most 65535 bytes +Let :math:`\mathsf{ContextString}` be a globally-unique non-empty sequence of at most 252 bytes that identifies the desired context. We instantiate the hardened key generation process with the following constants: - :math:`\mathsf{Arbitrary.MKGDomain} = \texttt{“ZcashArbitraryKD”}` -- :math:`\mathsf{Arbitrary.CKDDomain} = [\texttt{0xAB}]` +- :math:`\mathsf{Arbitrary.CKDDomain} = \texttt{0xAB}` Arbitrary master key generation ------------------------------- @@ -531,16 +536,14 @@ Let :math:`S` be a seed byte sequence of a chosen length, which MUST be at least The master extended arbitrary key is: -:math:`m_\mathsf{Arbitrary} = \mathsf{MKGh}^\mathsf{Arbitrary}(` -:math:`\mathsf{I2LEOSP}_{16}(\mathsf{length}(\mathsf{ContextString}))\,||\,\mathsf{ContextString}\,||\,` -:math:`[\mathsf{length}(S)]\,||\,S)`. +:math:`m_\mathsf{Arbitrary} = \mathsf{MKGh}^\mathsf{Arbitrary}([\mathsf{length}(\mathsf{ContextString})]\,||\,\mathsf{ContextString}\,||\,[\mathsf{length}(S)]\,||\,S)\!`. Arbitrary child key derivation ------------------------------ :math:`\mathsf{CKDarb}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)`:math:`\rightarrow (\mathsf{sk}_i, \mathsf{c}_i)` -- Return :math:`\mathsf{CKDh}^\mathsf{Arbitrary}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)` +- Return :math:`\mathsf{CKDh}^\mathsf{Arbitrary}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)\!`. If the context requires a 64-byte key (for example, to avoid an entropy bottleneck in its particular subsequent operations), and :math:`i` is the last element of an HD path, the concatenation From 6e36cde37d1f0da54af8dad303ba89468abecaeb Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 1 Oct 2024 20:02:57 +0000 Subject: [PATCH 4/5] ZIP 32: Fix typo with `s/CDK/CKD` --- zips/zip-0032.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zips/zip-0032.rst b/zips/zip-0032.rst index e9aea86ef..69817e5a3 100644 --- a/zips/zip-0032.rst +++ b/zips/zip-0032.rst @@ -140,7 +140,7 @@ specifications), which is the opposite of BIP 32. We adapt the path notation of BIP 32 [#bip-0032]_ to describe shielded HD paths, using prime marks (:math:`'`) to indicate hardened derivation (:math:`i' = i + 2^{31}`) as in BIP 44 [#bip-0044]_: -- :math:`\mathsf{CDKfvk}(\mathsf{CDKfvk}(\mathsf{CDKfvk}(m_\mathsf{Sapling}, a), b), c)` is written as :math:`m_\mathsf{Sapling} / a / b / c`. +- :math:`\mathsf{CKDfvk}(\mathsf{CKDfvk}(\mathsf{CKDfvk}(m_\mathsf{Sapling}, a), b), c)` is written as :math:`m_\mathsf{Sapling} / a / b / c`. Specification: Sapling key derivation @@ -214,7 +214,7 @@ depends on the type of key being derived, and whether this is a hardened or non- Deriving a child extended spending key `````````````````````````````````````` -:math:`\mathsf{CDKsk}((\mathsf{ask}_{par}, \mathsf{nsk}_{par}, \mathsf{ovk}_{par}, \mathsf{dk}_{par}, \mathsf{c}_{par}), i)`:math:`\rightarrow (\mathsf{ask}_i, \mathsf{nsk}_i, \mathsf{ovk}_i, \mathsf{dk}_i, \mathsf{c}_i)` +:math:`\mathsf{CKDsk}((\mathsf{ask}_{par}, \mathsf{nsk}_{par}, \mathsf{ovk}_{par}, \mathsf{dk}_{par}, \mathsf{c}_{par}), i)`:math:`\rightarrow (\mathsf{ask}_i, \mathsf{nsk}_i, \mathsf{ovk}_i, \mathsf{dk}_i, \mathsf{c}_i)` - Check whether :math:`i \geq 2^{31}` (whether the child is a hardened key). @@ -245,7 +245,7 @@ Deriving a child extended full viewing key Let :math:`\mathcal{G}^\mathsf{Sapling}` be as defined in [#protocol-concretespendauthsig]_ and let :math:`\mathcal{H}^\mathsf{Sapling}` be as defined in [#protocol-saplingkeycomponents]_. -:math:`\mathsf{CDKfvk}((\mathsf{ak}_{par}, \mathsf{nk}_{par}, \mathsf{ovk}_{par}, \mathsf{dk}_{par}, \mathsf{c}_{par}), i)`:math:`\rightarrow (\mathsf{ak}_{i}, \mathsf{nk}_{i}, \mathsf{ovk}_{i}, \mathsf{dk}_{i}, \mathsf{c}_{i})` +:math:`\mathsf{CKDfvk}((\mathsf{ak}_{par}, \mathsf{nk}_{par}, \mathsf{ovk}_{par}, \mathsf{dk}_{par}, \mathsf{c}_{par}), i)`:math:`\rightarrow (\mathsf{ak}_{i}, \mathsf{nk}_{i}, \mathsf{ovk}_{i}, \mathsf{dk}_{i}, \mathsf{c}_{i})` - Check whether :math:`i \geq 2^{31}` (whether the child is a hardened key). @@ -437,7 +437,7 @@ Let :math:`S` be a seed byte sequence of a chosen length, which MUST be at least Orchard child key derivation ---------------------------- -:math:`\mathsf{CDKsk}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)`:math:`\rightarrow (\mathsf{sk}_{i}, \mathsf{c}_i)` +:math:`\mathsf{CKDsk}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)`:math:`\rightarrow (\mathsf{sk}_{i}, \mathsf{c}_i)` - Return :math:`\mathsf{CKDh}^\mathsf{Orchard}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)` From 55173c85f09abb0ddcebacb6bd48aa78b34ffcc8 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 1 Oct 2024 20:03:43 +0000 Subject: [PATCH 5/5] Render manually, while the CI-based rendering is broken --- rendered/zip-0032.html | 153 +++++++++++++++++++++++++++++++++-------- 1 file changed, 126 insertions(+), 27 deletions(-) diff --git a/rendered/zip-0032.html b/rendered/zip-0032.html index 4622c88d0..432702ad2 100644 --- a/rendered/zip-0032.html +++ b/rendered/zip-0032.html @@ -25,7 +25,7 @@ \(% This ZIP makes heavy use of mathematical markup. If you can see this, you may want to instead view the rendered version at https://zips.z.cash/zip-0032 .\)

Terminology

-

The key words "MUST", "MUST NOT", and "MAY" in this document are to be interpreted as described in BCP 14 1 when, and only when, they appear in all capitals.

+

The key words "MUST", "MUST NOT", "SHOULD", "RECOMMENDED", and "MAY" in this document are to be interpreted as described in BCP 14 1 when, and only when, they appear in all capitals.

"Jubjub" refers to the elliptic curve defined in 15.

A "chain code" is a cryptovalue that is needed, in addition to a spending key, in order to derive descendant keys and addresses of that key.

The terms "Testnet" and "Mainnet" are to be interpreted as described in section 3.12 of the Zcash Protocol Specification 10.

@@ -188,7 +188,7 @@ ) as in BIP 44 5:

  • - \(\mathsf{CDKfvk}(\mathsf{CDKfvk}(\mathsf{CDKfvk}(m_\mathsf{Sapling}, a), b), c)\) + \(\mathsf{CKDfvk}(\mathsf{CKDfvk}(\mathsf{CKDfvk}(m_\mathsf{Sapling}, a), b), c)\) is written as \(m_\mathsf{Sapling} / a / b / c\) .
  • @@ -313,7 +313,7 @@ , depends on the type of key being derived, and whether this is a hardened or non-hardened derivation.

    Deriving a child extended spending key

    - \(\mathsf{CDKsk}((\mathsf{ask}_{par}, \mathsf{nsk}_{par}, \mathsf{ovk}_{par}, \mathsf{dk}_{par}, \mathsf{c}_{par}), i)\) + \(\mathsf{CKDsk}((\mathsf{ask}_{par}, \mathsf{nsk}_{par}, \mathsf{ovk}_{par}, \mathsf{dk}_{par}, \mathsf{c}_{par}), i)\) \(\rightarrow (\mathsf{ask}_i, \mathsf{nsk}_i, \mathsf{ovk}_i, \mathsf{dk}_i, \mathsf{c}_i)\)

      @@ -389,7 +389,7 @@ \(\mathcal{H}^\mathsf{Sapling}\) be as defined in 11.

      - \(\mathsf{CDKfvk}((\mathsf{ak}_{par}, \mathsf{nk}_{par}, \mathsf{ovk}_{par}, \mathsf{dk}_{par}, \mathsf{c}_{par}), i)\) + \(\mathsf{CKDfvk}((\mathsf{ak}_{par}, \mathsf{nk}_{par}, \mathsf{ovk}_{par}, \mathsf{dk}_{par}, \mathsf{c}_{par}), i)\) \(\rightarrow (\mathsf{ak}_{i}, \mathsf{nk}_{i}, \mathsf{ovk}_{i}, \mathsf{dk}_{i}, \mathsf{c}_{i})\)

        @@ -578,24 +578,33 @@ is the least nonnegative integer yielding a valid diversifier.

-

Specification: Orchard key derivation

-

The derivation mechanism for Sapling addresses specified above incurs significant complexity to support non-hardened derivation. In the several years since Sapling was deployed, we have seen no use cases for non-hardened derivation appear. With that in mind, we only support hardened key derivation for Orchard.

-

Orchard extended keys

-

We represent an Orchard extended spending key as - \((\mathsf{sk, c}),\) - where - \(\mathsf{sk}\) - is the normal Orchard spending key (opaque 32 bytes), and - \(\mathsf{c}\) - is the chain code.

+

Specification: Hardened-only key derivation

+

The derivation mechanism for Sapling addresses specified above incurs significant complexity to support non-hardened derivation. In the several years since Sapling was deployed, we have seen no use cases for non-hardened derivation appear. With that in mind, we now have a general hardened-only derivation process that retains compatibility with existing derivation path semantics (to enable deriving the same path across multiple contexts).

+

Instantiation

+

Let + \(\mathsf{Context}\) + be the context in which the hardened-only key derivation process is instantiated (e.g. a shielded protocol). We define two context-specific constants:

+
    +
  • + \(\mathsf{Context.MKGDomain}\) + is a sequence of 16 bytes, used as a domain separator during master key generation. It SHOULD be disjoint from other domain separators used with BLAKE2b in Zcash protocols.
  • +
  • + \(\mathsf{Context.CKDDomain}\) + is a byte value, used as a domain separator during child key derivation. This should be tracked as part of the global set of domains defined for + \(\mathsf{PRF^{expand}}\) + .
  • +
-

Orchard master key generation

+

Hardened-only master key generation

Let - \(S\) - be a seed byte sequence of a chosen length, which MUST be at least 32 and at most 252 bytes.

+ \(\mathsf{IKM}\) + be an input key material byte sequence, which MUST use an unambiguous encoding within the given context, and SHOULD contain at least 256 bits of entropy. It is RECOMMENDED to use a prefix-free encoding, which may require the use of length fields if multiple fields need to be encoded.

+

+ \(\mathsf{MKGh}^\mathsf{Context}(\mathsf{IKM}) \rightarrow (\mathsf{sk}_m, \mathsf{c}_m)\) +

  • Calculate - \(I = \mathsf{BLAKE2b}\text{-}\mathsf{512}(\texttt{“ZcashIP32Orchard”}, S)\) + \(I = \mathsf{BLAKE2b}\text{-}\mathsf{512}(\mathsf{Context.MKGDomain}, \mathsf{IKM})\) .
  • Split \(I\) @@ -606,7 +615,7 @@ .
  • Use \(I_L\) - as the master spending key + as the master secret key \(\mathsf{sk}_m\) .
  • Use @@ -616,15 +625,13 @@ .
  • Return \((\mathsf{sk}_m, \mathsf{c}_m)\) - as the master extended spending key - \(m_\mathsf{Orchard}\) .
-

Orchard child key derivation

+

Hardened-only child key derivation

- \(\mathsf{CDKsk}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)\) - \(\rightarrow (\mathsf{sk}_{i}, \mathsf{c}_i)\) + \(\mathsf{CKDh}^\mathsf{Context}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)\) + \(\rightarrow (\mathsf{sk}_i, \mathsf{c}_i)\)

  • Check whether @@ -632,7 +639,7 @@ (whether the child is a hardened key).
    • If so (hardened child): let - \(I = \mathsf{PRF^{expand}}(\mathsf{c}_{par}, [\texttt{0x81}]\,||\,\mathsf{sk}_{par}\,||\,\mathsf{I2LEOSP}_{32}(i))\) + \(I = \mathsf{PRF^{expand}}(\mathsf{c}_{par}, [\mathsf{Context.CKDDomain}]\,||\,\mathsf{sk}_{par}\,||\,\mathsf{I2LEOSP}_{32}(i))\) .
    • If not (normal child): return failure.
    @@ -646,14 +653,60 @@ .
  • Use \(I_L\) - as the child spending key - \(\mathsf{sk}_{i}\) + as the child secret key + \(\mathsf{sk}_i\) .
  • Use \(I_R\) as the child chain code \(\mathsf{c}_i\) .
  • +
  • Return + \((\mathsf{sk}_i, \mathsf{c}_i)\) + .
  • +
+
+
+

Specification: Orchard key derivation

+

We only support hardened key derivation for Orchard. We instantiate the hardened key generation process with the following constants:

+
    +
  • + \(\mathsf{Orchard.MKGDomain} = \texttt{“ZcashIP32Orchard”}\) +
  • +
  • + \(\mathsf{Orchard.CKDDomain} = \texttt{0x81}\) +
  • +
+

Orchard extended keys

+

We represent an Orchard extended spending key as + \((\mathsf{sk, c}),\) + where + \(\mathsf{sk}\) + is the normal Orchard spending key (opaque 32 bytes), and + \(\mathsf{c}\) + is the chain code.

+
+

Orchard master key generation

+

Let + \(S\) + be a seed byte sequence of a chosen length, which MUST be at least 32 and at most 252 bytes.

+
    +
  • Return + \(\mathsf{MKGh}^\mathsf{Orchard}(S)\) + as the master extended spending key + \(m_\mathsf{Orchard}\) + .
  • +
+
+

Orchard child key derivation

+

+ \(\mathsf{CKDsk}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)\) + \(\rightarrow (\mathsf{sk}_{i}, \mathsf{c}_i)\) +

+
    +
  • Return + \(\mathsf{CKDh}^\mathsf{Orchard}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)\) +

Note that the resulting child spending key may produce an invalid external FVK, as specified in 12, with small probability. The corresponding internal FVK derived as specified in the next section may also be invalid with small probability.

@@ -735,6 +788,52 @@

+

Specification: Arbitrary key derivation

+

In some contexts there is a need for deriving arbitrary keys with the same derivation path as existing key material (for example, deriving an arbitrary account-level key), without the need for ecosystem-wide coordination. The following instantiation of the hardened key generation process may be used for this purpose.

+

Let + \(\mathsf{ContextString}\) + be a globally-unique non-empty sequence of at most 252 bytes that identifies the desired context.

+

We instantiate the hardened key generation process with the following constants:

+
    +
  • + \(\mathsf{Arbitrary.MKGDomain} = \texttt{“ZcashArbitraryKD”}\) +
  • +
  • + \(\mathsf{Arbitrary.CKDDomain} = \texttt{0xAB}\) +
  • +
+

Arbitrary master key generation

+

Let + \(S\) + be a seed byte sequence of a chosen length, which MUST be at least 32 and at most 252 bytes.

+

The master extended arbitrary key is:

+

+ \(m_\mathsf{Arbitrary} = \mathsf{MKGh}^\mathsf{Arbitrary}([\mathsf{length}(\mathsf{ContextString})]\,||\,\mathsf{ContextString}\,||\,[\mathsf{length}(S)]\,||\,S)\!\) + .

+
+

Arbitrary child key derivation

+

+ \(\mathsf{CKDarb}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)\) + \(\rightarrow (\mathsf{sk}_i, \mathsf{c}_i)\) +

+
    +
  • Return + \(\mathsf{CKDh}^\mathsf{Arbitrary}((\mathsf{sk}_{par}, \mathsf{c}_{par}), i)\!\) + .
  • +
+

If the context requires a 64-byte key (for example, to avoid an entropy bottleneck in its particular subsequent operations), and + \(i\) + is the last element of an HD path, the concatenation + \(\mathsf{sk}_i\,||\,\mathsf{c}_i\) + MAY be used as a key. In this case, + \((\mathsf{sk}_i, \mathsf{c}_i)\) + MUST NOT be given as input to + \(\mathsf{CKDarb}\) + (this is a restatement of the requirement that + \(i\) + is the last element of an HD path).

+
+

Specification: Wallet usage

Existing Zcash-supporting HD wallets all use BIP 44 5 to organize their derived keys. In order to more easily mesh with existing user experiences, we broadly follow BIP 44's design here. However, we have altered the design where it makes sense to leverage features of shielded addresses.

Key path levels