Skip to content

Commit

Permalink
Extract ZIP 32 hardened-only key derivation from Orchard
Browse files Browse the repository at this point in the history
  • Loading branch information
str4d committed Nov 2, 2024
1 parent 5b76d4b commit ff8eb51
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 14 deletions.
21 changes: 7 additions & 14 deletions zcash_test_vectors/orchard/key_components.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#!/usr/bin/env python3
import sys; assert sys.version_info[0] >= 3, "Python 3 required."

from hashlib import blake2b

from ..ff1 import ff1_aes256_encrypt
from ..sapling.key_components import prf_expand
from ..zip_0032 import CKDh, HardenedOnlyContext, MKGh

from .generators import NULLIFIER_K_BASE, SPENDING_KEY_BASE, group_hash
from .pallas import Fp, Scalar, Point
Expand Down Expand Up @@ -55,26 +54,20 @@ def __init__(self, data):


class ExtendedSpendingKey(SpendingKey):
Orchard = HardenedOnlyContext(b'ZcashIP32Orchard', b'\x81')

def __init__(self, chaincode, data):
SpendingKey.__init__(self, data)
self.chaincode = chaincode

@classmethod
def master(cls, S):
digest = blake2b(person=b'ZcashIP32Orchard')
digest.update(S)
I = digest.digest()
I_L = I[:32]
I_R = I[32:]
return cls(I_R, I_L)
(sk, chaincode) = MKGh(cls.Orchard, S)
return cls(chaincode, sk)

def child(self, i):
assert 0x80000000 <= i and i <= 0xFFFFFFFF

I = prf_expand(self.chaincode, b'\x81' + self.data + i2leosp(32, i))
I_L = I[:32]
I_R = I[32:]
return self.__class__(I_R, I_L)
(sk_i, c_i) = CKDh(self.Orchard, self.data, self.chaincode, i)
return self.__class__(c_i, sk_i)


class FullViewingKey(object):
Expand Down
33 changes: 33 additions & 0 deletions zcash_test_vectors/zip_0032.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from hashlib import blake2b

from .sapling.key_components import prf_expand
from .utils import i2leosp

class HardenedOnlyContext(object):
def __init__(self, MKGDomain, CKDDomain):
assert type(MKGDomain) == bytes
assert len(MKGDomain) == 16
assert type(CKDDomain) == bytes
assert len(CKDDomain) == 1

self.MKGDomain = MKGDomain
self.CKDDomain = CKDDomain

def MKGh(Context, IKM):
assert type(Context) == HardenedOnlyContext

digest = blake2b(person=Context.MKGDomain)
digest.update(IKM)
I = digest.digest()
I_L = I[:32]
I_R = I[32:]
return (I_L, I_R)

def CKDh(Context, sk_par, c_par, i):
assert type(Context) == HardenedOnlyContext
assert 0x80000000 <= i and i <= 0xFFFFFFFF

I = prf_expand(c_par, Context.CKDDomain + sk_par + i2leosp(32, i))
I_L = I[:32]
I_R = I[32:]
return (I_L, I_R)

0 comments on commit ff8eb51

Please sign in to comment.