Zcash中的加解密机制

1. 引言

接前序博客 Zcash中的Notes

Sapling note的组成为tuple n = ( d , p k d , v , r c m ) \mathbf{n}=(d, pk_d, v, rcm) n=(d,pkd,v,rcm),其中:

  • d d d:为接收方的shielded payment address对应的diversifier值。【为88bit, B [ l d ] \mathbb{B}^{[l_d]} B[ld]
  • p k d pk_d pkd:为接收方的shielded payment address对应的diversified transmission key。【为Jubjub point, K A S a p l i n g . P u b l i c P r i m e S u b g r o u p KA^{Sapling}.PublicPrimeSubgroup KASapling.PublicPrimeSubgroup
  • v v v:取值范围为 MAX_MONEY \text{MAX\_MONEY} MAX_MONEY,代表note中的value值,单位为zatoshi。
  • r c m rcm rcm:为random commitment trapdoor。【 N o t e C o m m i t S a p l i n g . T r a p d o o r NoteCommit^{Sapling}.Trapdoor NoteCommitSapling.Trapdoor

m e m o memo memo为与该note关联的512字节的memo field。

1.1 相关约定

  • l o v k l_{ovk} lovk:为256。
  • S y m Sym Sym:为Symmetric Encryption scheme。
  • K A KA KA:为Sapling key agreement scheme K A S a p l i n g KA^{Sapling} KASapling
  • K D F KDF KDF:为Sapling key derivation function K D F S a p l i n g KDF^{Sapling} KDFSapling
    在这里插入图片描述
void KDF_Sapling(
    unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE],
    const uint256 &dhsecret,
    const uint256 &epk
)
{
    unsigned char block[64] = {};
    memcpy(block+0, dhsecret.begin(), 32);
    memcpy(block+32, epk.begin(), 32);

    unsigned char personalization[BLAKE2bPersonalBytes] = {};
    memcpy(personalization, "Zcash_SaplingKDF", 16);

    auto state = blake2b_init(NOTEENCRYPTION_CIPHER_KEYSIZE, personalization);
    blake2b_update(state, block, 64);
    blake2b_finalize(state, K, NOTEENCRYPTION_CIPHER_KEYSIZE);
    blake2b_free(state);
}
  • G \mathbb{G} G:为Jubjub中的subgroup J \mathbb{J} J J \mathbb{J} J group具有的order为 h J ⋅ r J h_{\mathbb{J}}\cdot r_{\mathbb{J}} hJrJ,其中 r J r_{\mathbb{J}} rJ为prime。

  • l G l_{\mathbb{G}} lG:为Jubjub中的 l J = 256 l_{\mathbb{J}}=256 lJ=256

  • r e p r J repr_{\mathbb{J}} reprJ:为Jubjub中的 r e p r J repr_{\mathbb{J}} reprJ。即将group point以256-bit表示。

  • a b s t J abst_{\mathbb{J}} abstJ:为将256-bit转换为Jubjub上的group point。

  • E x t r a c t G ( r ) Extract_{\mathbb{G}^{(r)}} ExtractG(r):为Jubjub中的 E x t r a c t J ( r ) Extract_{\mathbb{J}^{(r)}} ExtractJ(r)——Coordinate Extractor for Jubjub。实际即为提取Jubjub point的 u u u坐标值, E x t r a c t J ( r ) ( P ) = l 2 L E B S P l M e r k l e S a p l i n g ( U ( P ) ) Extract_{\mathbb{J}^{(r)}}(P)=l2LEBSP_{l_{Merkle}^{Sapling}}(\mathcal{U}(P)) ExtractJ(r)(P)=l2LEBSPlMerkleSapling(U(P)),其中 U ( P ) = U ( ( u , v ) ) = u \mathcal{U}(P)=\mathcal{U}((u,v))=u U(P)=U((u,v))=u,同时约定,若 P = ( u , v ) ∈ J ( r ) P=(u,v)\in\mathbb{J}^{(r)} P=(u,v)J(r),则 ( u , − v ) ∉ J ( r ) (u,-v)\notin \mathbb{J}^{(r)} (u,v)/J(r) J ( r ) \mathbb{J}^{(r)} J(r)为prime order group。

  • P R F o c k PRF^{ock} PRFock:为Pseudo Random Function P R F o c k S a p l i n g PRF^{ockSapling} PRFockSapling P R F o c k S a p l i n g PRF^{ockSapling} PRFockSapling用于派生the outgoing cipher key o c k ock ock used to encrypt an outgoing ciphertext。其采用BLAKE2b hash函数来实例化:
    P R F o v k o c k S a p l i n g ( c v , c m u , e p h e m e r a l K e y ) = B L A K E 2 b − 256 ( " Z c a s h D e r i v e o c k " , o c k I n p u t ) PRF_{ovk}^{ockSapling}(cv,cmu,ephemeralKey)=BLAKE2b-256("Zcash_Derive_ock", ockInput) PRFovkockSapling(cv,cmu,ephemeralKey)=BLAKE2b256("ZcashDeriveock",ockInput),其中 o c k I n p u t ockInput ockInput为:
    在这里插入图片描述
    B L A K E 2 b − 256 ( " Z c a s h D e r i v e o c k " , o c k I n p u t ) BLAKE2b-256("Zcash_Derive_ock", ockInput) BLAKE2b256("ZcashDeriveock",ockInput)必须为PRF,其输出为对称加密中的秘钥 S y m . K = B [ 256 ] Sym.K=\mathbb{B}^{[256]} Sym.K=B[256](为256-bit key)。

  • D i v e r s i f y H a s h DiversifyHash DiversifyHash:为 D i v e r s i f y H a s h S a p l i n g DiversifyHash^{Sapling} DiversifyHashSapling hash函数,用于派生a diversified base g d g_d gd D i v e r s i f y H a s h S a p l i n g : B [ l d ] → J ( r ) ∗ ∪ { ⊥ } DiversifyHash^{Sapling}: \mathbb{B}^{[l_d]}\rightarrow \mathbb{J}^{(r)^*}\cup \{\perp\} DiversifyHashSapling:B[ld]J(r){},实际实现为:
    D i v e r s i f y H a s h S a p l i n g ( d ) = G r o u p H a s h U J ( r ) ∗ ( " Z c a s h g d " , L E B S 2 O S P l d ( d ) ) DiversifyHash^{Sapling}(d)=GroupHash_{U}^{\mathbb{J}^{(r)^*}}("Zcash_gd", LEBS2OSP_{l_d}(d)) DiversifyHashSapling(d)=GroupHashUJ(r)("Zcashgd",LEBS2OSPld(d))
    其中 U U U为MPC randomness beacon, G r o u p H a s h U J ( r ) ∗ GroupHash_{U}^{\mathbb{J}^{(r)^*}} GroupHashUJ(r)为Group Hash into Jubjub算法,输出为Jubjub point:
    在这里插入图片描述

  • N o t e C o m m i t m e n t NoteCommitment NoteCommitment:为“Notes”章节中的 N o t e C o m m i t m e n t S a p l i n g NoteCommitment^{Sapling} NoteCommitmentSapling
    在这里插入图片描述

  • T o S c a l a r ToScalar ToScalar:为Sapling Key Components中的 T o S c a l a r S a p l i n g ToScalar^{Sapling} ToScalarSapling T o S c a l a r S a p l i n g ( x : B Y [ l P R F e x p a n d / 8 ] ) = L E O S 2 I P l P R F e x p a n d ( x ) ( m o d    r J ) ToScalar^{Sapling}(x:\mathbb{B}^{\mathbb{Y}^{[l_{PRFexpand}/8]}})=LEOS2IP_{l_{PRFexpand}}(x)(\mod r_{\mathbb{J}}) ToScalarSapling(x:BY[lPRFexpand/8])=LEOS2IPlPRFexpand(x)(modrJ),输入为64byte值,输出为Jubjub的Scalar值。

1.2 对称加密

S y m Sym Sym 为authenticated one-time symmetric encryption scheme with keyspace S y m . K Sym.\mathbf{K} Sym.K,对应的明文为 S y m . P Sym.\mathbf{P} Sym.P,对应的密文为 S y m . C Sym.\mathbf{C} Sym.C
【此处的“one-time”是指,honest protocol参与方仅使用特定的key对一个消息进行加密,不会将该key用于重复加密。但是对于adversary来说,其可能对同一key用多个adaptive chosen ciphertext进行query。】

加密算法 S y m . E n c r y p t Sym.Encrypt Sym.Encrypt为: S y m . K × S y m . P → S y m . C Sym.\mathbf{K}\times Sym.\mathbf{P}\rightarrow Sym.\mathbf{C} Sym.K×Sym.PSym.C
解密算法 S y m . D e c r y p t Sym.Decrypt Sym.Decrypt为: S y m . K × S y m . C → S y m . P ∪ { ⊥ } Sym.\mathbf{K}\times Sym.\mathbf{C}\rightarrow Sym.\mathbf{P}\cup \{\perp\} Sym.K×Sym.CSym.P{}

对应任意的 K ∈ S y m . K K\in Sym.\mathbf{K} KSym.K P ∈ S y m . P P\in Sym.\mathbf{P} PSym.P,有 S y m . D e c r y p t K ( S y m . E n c r y p t K ( P ) ) = P Sym.Decrypt_{K}(Sym.Encrypt_{K}(P))=P Sym.DecryptK(Sym.EncryptK(P))=P
⊥ \perp 用于表示the decryption of an invalid ciphertext。

2. In-band secret distribution (Sapling)——in-band秘密分发

在Sapling中,note中需要秘密发送给接收方的信息有 d , v , r c m d,v,rcm d,v,rcm,同时也发送相应的memo field。

为了在不需要out-of-band communication channel的情况下将这些秘密安全的发送给接收方,会使用diversified transmission key p k d pk_d pkd对这些秘密进行加密。拥有相应incoming viewing key i v k ivk ivk的接收方可重构出原始的note和memo field。

与Sprout不同,每个Sapling shielded output会用新的ephemeral public key来加密。

2.1 Encryption (Sapling)

  • p k d pk_d pkd:为 the diversified transmission key for the intended recipient address of a new Sapling note。为Jubjub point, K A . P u b l i c P r i m e S u b g r o u p KA.PublicPrimeSubgroup KA.PublicPrimeSubgroup
  • g d g_d gd:为diversifier d d d对应的diversified base, g d = D i v e r s i f y H a s h ( d ) g_d=DiversifyHash(d) gd=DiversifyHash(d)。为Jubjub point, K A . P u b l i c P r i m e S u b g r o u p KA.PublicPrimeSubgroup KA.PublicPrimeSubgroup

仅在sending notes环节会对Sapling notes进行加密,此处可假设 g d g_d gd已计算且不为 ⊥ \perp 。同时此处也假设ephemeral private key e s k esk esk也已选定。

o v k ovk ovk B Y [ l o v k / 8 ] ∪ { ⊥ } \mathbb{B}^{\mathbb{Y}^{[l_{ovk}/8]}}\cup \{\perp\} BY[lovk/8]{},为可用于decrypt 该payment的outgoing viewing key, o v k ovk ovk的取值可为以下之一:

  • payment发送方(或发送方之一)的outgoing viewing key;
  • the outgoing viewing key for all payments associated with an “account”,具体见ZIP-32中定义。
  • ⊥ \perp ,if the sender should not be able to decrypt the payment once it has deleted its own copy。

n p = ( l e a d B y t e : B Y , d : B [ l d ] , v : { 0.. 2 l v a l u e − 1 } , m e m o : B Y [ 512 ] ) \mathbf{np}=(leadByte:\mathbb{B}^{\mathbb{Y}}, d:\mathbb{B}^{[l_d]},v:\{0..2^{l_{value}}-1\}, memo:\mathbb{B}^{\mathbb{Y}^{[512]}}) np=(leadByte:BY,d:B[ld],v:{0..2lvalue1},memo:BY[512]):为Sapling note plaintext。【实际代码实现时,SaplingNotePlaintext组成为(leadbyte, note, memo),具体见github.com/zcash/zcash/src/zcash/note.hpp中相关定义,即实际 n p = ( l e a d B y t e : B Y , d : B [ l d ] , v : { 0.. 2 l v a l u e − 1 } , m e m o : B Y [ 512 ] , p k d , r c m ) \mathbf{np}=(leadByte:\mathbb{B}^{\mathbb{Y}}, d:\mathbb{B}^{[l_d]},v:\{0..2^{l_{value}}-1\}, memo:\mathbb{B}^{\mathbb{Y}^{[512]}}, pk_d, rcm) np=(leadByte:BY,d:B[ld],v:{0..2lvalue1},memo:BY[512],pkd,rcm)

c v cv cv:为Output description中的value commitment。
c m cm cm:为Output description中的note commitment。

需要使用 c m , c v cm,cv cm,cv来派生the outgoing cipher key o c k ock ock,需要利用outgoing cipher key o c k ock ock来加密生成 outgoing ciphertext C o u t C^{out} Cout

详细的加密流程为:
1)令 P e n c P^{enc} Penc n p \mathbf{np} np的raw encoding。
2)令 e p k = K A . D e r i v e P u b l i c ( e s k , g d ) epk=KA.DerivePublic(esk,g_d) epk=KA.DerivePublic(esk,gd)
3)令 e p h e m e r a l K e y = L E B S 2 O S P l G ( r e p r G ( e p k ) ) ephemeralKey=LEBS2OSP_{l_{\mathbb{G}}}(repr_{\mathbb{G}}(epk)) ephemeralKey=LEBS2OSPlG(reprG(epk))
4)令 s h a r e d S e c r e t = K A . A g r e e ( e s k , p k d ) sharedSecret=KA.Agree(esk,pk_d) sharedSecret=KA.Agree(esk,pkd)
5)令 K e n c = K D F ( s h a r e d S e c r e t , e p h e m e r a l K e y ) K^{enc}=KDF(sharedSecret, ephemeralKey) Kenc=KDF(sharedSecret,ephemeralKey),其输入为the shared Diffie-Hellman secret s h a r e d S e c r e t sharedSecret sharedSecret 和 the ephemeral public key e p k epk epk,输出为对称加密中的秘钥。 K D F S a p l i n g : K A S a p l i n g . S h a r e d S e c r e t × B Y [ l J / 8 ] → S y m . K KDF^{Sapling}:KA^{Sapling}.SharedSecret \times \mathbb{B}^{\mathbb{Y}^{[l_{\mathbb{J}}/8]}}\rightarrow Sym.\mathbf{K} KDFSapling:KASapling.SharedSecret×BY[lJ/8]Sym.K
6)对称加密 C e n c = S y m . E n c r y p t K e n c ( P e n c ) C^{enc}=Sym.Encrypt_{K^{enc}}(P^{enc}) Cenc=Sym.EncryptKenc(Penc)
7.1)若 o v k = ⊥ ovk=\perp ovk=,则选择随机 o c k ← R S y m . K , o p ← R B Y [ ( l G + 256 ) / 8 ] ock\leftarrow_{R} Sym.\mathbf{K}, \mathbf{op}\leftarrow_R\mathbb{B}^{\mathbb{Y}^{[(l_{\mathbb{G}}+256)/8]}} ockRSym.K,opRBY[(lG+256)/8]
7.2)若 o v k ≠ ⊥ ovk\neq \perp ovk=,则有:
c v = L E B S 2 O S P l G ( r e p r G ( c v ) ) cv=LEBS2OSP_{l_{\mathbb{G}}}(repr_{\mathbb{G}}(cv)) cv=LEBS2OSPlG(reprG(cv))
c m ∗ = L E B S 2 O S P 256 ( E x t r a c t G ( r ) ( c m ) ) cm*=LEBS2OSP_{256}(Extract_{\mathbb{G}^{(r)}}(cm)) cm=LEBS2OSP256(ExtractG(r)(cm))。【实际为encode the u u u-coordinate of the note commitment。】
o c k = P R F o v k o c k ( c v , c m ∗ , e p h e m e r a l K e y ) ock=PRF_{ovk}^{ock}(cv,cm*,ephemeralKey) ock=PRFovkock(cv,cm,ephemeralKey)
o p = L E B S 2 O S P l G + 256 ( r e p r G ( p k d ) ∣ ∣ l 2 L E B S P 256 ( e s k ) ) \mathbf{op}=LEBS2OSP_{l_{\mathbb{G}}+256}(repr_{\mathbb{G}}(pk_d) || l2LEBSP_{256}(esk)) op=LEBS2OSPlG+256(reprG(pkd)l2LEBSP256(esk))
8)对称加密 C o u t = S y m . E n c r y p t o c k ( o p ) C^{out}=Sym.Encrypt_{ock}(\mathbf{op}) Cout=Sym.Encryptock(op)

最终加密后的transmitted note ciphertext 为 ( e p h e m e r a l K e y , C e n c , C o u t ) (ephemeralKey, C^{enc}, C^{out}) (ephemeralKey,Cenc,Cout)

注意:若改为依赖于out-of-band transmission of the note to the recipient,从技术角度来看,可将特定note的 C e n c C^{enc} Cenc替换为随机(且不可解密)的密文。此时,为了保证indistinguishability from other Output descriptions,ephemeral key 仍然必须生成为random public key(而不是a random bit sequence)。这种操作模式有其它安全性的考量,如如何validate a Sapling note received out-of-band,在zcash协议文档中未详细阐述。

2.2 采用incoming viewing key来解密(Sapling)【接收方】

  • i v k ivk ivk { 0.. 2 251 − 1 } \{0..2^{251}-1\} {0..22511},为接收方的incoming viewing key。
  • ( e p h e m e r a l K e y , C e n c , C o u t ) (ephemeralKey, C^{enc},C^{out}) (ephemeralKey,Cenc,Cout):为the transmitted note ciphertext from the Output description。
  • c m ∗ cm* cm:为Output description的 c m u cmu cmu field。

接收方将尝试解密transmitted note ciphertext中的 e p h e m e r a l K e y ephemeralKey ephemeralKey C e n c C^{enc} Cenc,具体的解密流程为:
1)令 e p k = a b s t G ( e p h e m e r a l K e y ) epk=abst_{\mathbb{G}}(ephemeralKey) epk=abstG(ephemeralKey),若 e p k = ⊥ epk=\perp epk=,则返回 ⊥ \perp
2)令 s h a r e d S e c r e t = K A . A g r e e ( i v k , e p k ) sharedSecret=KA.Agree(ivk,epk) sharedSecret=KA.Agree(ivk,epk)
3)令 K e n c = K D F ( s h a r e d S e c r e t , e p h e m e r a l K e y ) K^{enc}=KDF(sharedSecret, ephemeralKey) Kenc=KDF(sharedSecret,ephemeralKey),其输入为the shared Diffie-Hellman secret s h a r e d S e c r e t sharedSecret sharedSecret 和 the ephemeral public key e p k epk epk,输出为对称加密中的秘钥。 K D F S a p l i n g : K A S a p l i n g . S h a r e d S e c r e t × B Y [ l J / 8 ] → S y m . K KDF^{Sapling}:KA^{Sapling}.SharedSecret \times \mathbb{B}^{\mathbb{Y}^{[l_{\mathbb{J}}/8]}}\rightarrow Sym.\mathbf{K} KDFSapling:KASapling.SharedSecret×BY[lJ/8]Sym.K
4)对称解密 P e n c = S y m . D e c r y p t K e n c ( C e n c ) P^{enc}=Sym.Decrypt_{K^{enc}}(C^{enc}) Penc=Sym.DecryptKenc(Cenc),若 P e n c = ⊥ P^{enc}=\perp Penc=,则返回 ⊥ \perp
5)decode P e n c P^{enc} Penc,提取 n p = ( l e a d B y t e : B Y , d : B [ l d ] , v : { 0.. 2 l v a l u e − 1 } , m e m o : B Y [ 512 ] , p k d , r c m ) \mathbf{np}=(leadByte:\mathbb{B}^{\mathbb{Y}}, d:\mathbb{B}^{[l_d]},v:\{0..2^{l_{value}}-1\}, memo:\mathbb{B}^{\mathbb{Y}^{[512]}}, pk_d, rcm) np=(leadByte:BY,d:B[ld],v:{0..2lvalue1},memo:BY[512],pkd,rcm)
6)令 r c m = L E O S 2 I P 256 ( r c m ) rcm=LEOS2IP_{256}(rcm) rcm=LEOS2IP256(rcm) g d = D i v e r s i f y H a s h ( d ) g_d=DiversifyHash(d) gd=DiversifyHash(d),若 r c m ≥ r G 或 g d = ⊥ rcm\geq r_{\mathbb{G}}或g_d=\perp rcmrGgd=,则返回 ⊥ \perp
7)计算 p k d = K A . D e r i v e P u b l i c ( i v k , g d ) pk_d=KA.DerivePublic(ivk,g_d) pkd=KA.DerivePublic(ivk,gd)
8)令 n = ( d , p k d , v , r c m ) \mathbf{n}=(d,pk_d,v,rcm) n=(d,pkd,v,rcm)
9)计算 c m ∗ ′ = N o t e C o m m i t m e n t ( n ) cm*'=NoteCommitment(\mathbf{n}) cm=NoteCommitment(n),若 l 2 L E O S P 256 ( E x t r a c t G ( r ) ( c m ∗ ′ ) ) = c m ∗ l2LEOSP_{256}(Extract_{\mathbb{G}^{(r)}}(cm*'))=cm* l2LEOSP256(ExtractG(r)(cm))=cm不成立,则返回 ⊥ \perp
10)最终解密结果为 ( n , m e m o ) (\mathbf{n}, memo) (n,memo)

注意:
1)通常情况下,只有区块交易中的transmitted note ciphertexts 需要被解密。此时,任何received Sapling note都必须为positioned note,使得可快速计算相应的 ρ \rho ρ值。
2)在Sapling中,每个positioned note有关联的 ρ \rho ρ值,该 ρ \rho ρ值可根据note commitment c m cm cm 和 note position p o s pos pos计算出来:
ρ = M i x i n g P e d e r s e n H a s h ( c m , p o s ) \rho = MixingPedersenHash(cm,pos) ρ=MixingPedersenHash(cm,pos)
对于Sapling note,其nullifier n f nf nf 可derived as P R F n k ⋆ n f S a p l i n g ( ρ ⋆ ) PRF_{nk\star}^{nfSapling}(\rho\star) PRFnknfSapling(ρ),其中 n k ⋆ nk\star nk代表与note关联的nullifier deriving key, ρ ⋆ = r e p r J ( ρ ) \rho\star=repr_{\mathbb{J}}(\rho) ρ=reprJ(ρ)
3)判断某个Sapling note是否为unspent的,需用到nullifier deriving key,并根据以上公式计算出nullifier值,判断该nullifier值是否在区块链的nullifier set中,若在,则表示该Sapling note已花费。
4)从区块链节点的角度来看,note由unspent变为spent是通过best valid block chain中的新交易实现的。若区块链重构了,选择了一条不同的best valid block chain,则可能会存在某个note 为output的交易不在区块链中的情况。
5)客户端可能会尝试解密mempool中交易的transmitted note ciphertext。但是,此时,不应假设该交易即将mined,而应将解密后的信息看成是临时的、私有的。???

2.3 采用full viewing key解密(Sapling)【发送方的outgoing viewing key】

  • o v k ovk ovk B Y [ l o v k / 8 ] \mathbb{B}^{\mathbb{Y}^{[l_{ovk}/8]}} BY[lovk/8],为发送方的outgoing viewing key。【若加密过程中使用的 o v k ovk ovk ⊥ \perp ,则该payment无法用本节办法解密。】
  • ( e p h e m e r a l K e y , C e n c , C o u t ) (ephemeralKey, C^{enc},C^{out}) (ephemeralKey,Cenc,Cout):为the transmitted note ciphertext from the Output description。
  • c m ∗ cm* cm:为Output description的 c m u cmu cmu field。
  • c v cv cv:为Output description的 c v cv cv field。

拥有outgoing viewing key的发送方,将尝试解密transmitted note ciphertext中的 e p h e m e r a l K e y ephemeralKey ephemeralKey C e n c C^{enc} Cenc以及 C o u t C^{out} Cout,具体的解密流程为:
1)令 o c k = P R F o v k o c k ( c v , c m ∗ , e p h e m e r a l K e y ) ock=PRF_{ovk}^{ock}(cv,cm*,ephemeralKey) ock=PRFovkock(cv,cm,ephemeralKey)
2)对称解密 o p = S y m . D e c r y p t o c k ( C o u t ) \mathbf{op}=Sym.Decrypt_{ock}(C^{out}) op=Sym.Decryptock(Cout),若 o p = ⊥ \mathbf{op}=\perp op=,则返回 ⊥ \perp
3)从 o p \mathbf{op} op中提取出 ( p k ⋆ d : B [ l G ] , e s k : B Y [ 32 ] ) (pk\star_d:\mathbb{B}^{[l_{\mathbb{G}}]}, esk: \mathbb{B}^{\mathbb{Y}^{[32]}}) (pkd:B[lG],esk:BY[32])
4)令 e s k = L E O S 2 I P 256 ( e s k ) , p k d = a b s t G ( p k ⋆ d ) esk=LEOS2IP_{256}(esk), pk_d=abst_{\mathbb{G}}(pk\star_d) esk=LEOS2IP256(esk),pkd=abstG(pkd),若 e s k ≥ r G esk\geq r_{\mathbb{G}} eskrG p k d = ⊥ pk_d=\perp pkd=,则返回 ⊥ \perp
5)令 s h a r e d S e c r e t = K A . A g r e e ( e s k , p k d ) sharedSecret=KA.Agree(esk, pk_d) sharedSecret=KA.Agree(esk,pkd)
6)令 K e n c = K D F ( s h a r e d S e c r e t , e p h e m e r a l K e y ) K^{enc}=KDF(sharedSecret, ephemeralKey) Kenc=KDF(sharedSecret,ephemeralKey),其输入为the shared Diffie-Hellman secret s h a r e d S e c r e t sharedSecret sharedSecret 和 the ephemeral public key e p k epk epk,输出为对称加密中的秘钥。 K D F S a p l i n g : K A S a p l i n g . S h a r e d S e c r e t × B Y [ l J / 8 ] → S y m . K KDF^{Sapling}:KA^{Sapling}.SharedSecret \times \mathbb{B}^{\mathbb{Y}^{[l_{\mathbb{J}}/8]}}\rightarrow Sym.\mathbf{K} KDFSapling:KASapling.SharedSecret×BY[lJ/8]Sym.K
7)对称解密 P e n c = S y m . D e c r y p t K e n c ( C e n c ) P^{enc}=Sym.Decrypt_{K^{enc}}(C^{enc}) Penc=Sym.DecryptKenc(Cenc),若 P e n c = ⊥ P^{enc}=\perp Penc=,则返回 ⊥ \perp
8)decode P e n c P^{enc} Penc,提取 n p = ( l e a d B y t e : B Y , d : B [ l d ] , v : { 0.. 2 l v a l u e − 1 } , m e m o : B Y [ 512 ] , p k d , r c m ) \mathbf{np}=(leadByte:\mathbb{B}^{\mathbb{Y}}, d:\mathbb{B}^{[l_d]},v:\{0..2^{l_{value}}-1\}, memo:\mathbb{B}^{\mathbb{Y}^{[512]}}, pk_d, rcm) np=(leadByte:BY,d:B[ld],v:{0..2lvalue1},memo:BY[512],pkd,rcm)
9)令 r c m = L E O S 2 I P 256 ( r c m ) rcm=LEOS2IP_{256}(rcm) rcm=LEOS2IP256(rcm) g d = D i v e r s i f y H a s h ( d ) g_d=DiversifyHash(d) gd=DiversifyHash(d),若 r c m ≥ r G 或 g d = ⊥ rcm\geq r_{\mathbb{G}}或g_d=\perp rcmrGgd= p k d ∉ J ( r ) pk_d\notin \mathbb{J}^{(r)} pkd/J(r),则返回 ⊥ \perp 。【注意,此处增加了 要求the decoded point p k d pk_d pkd of a Sapling note to be in the subgroup J ( r ) \mathbb{J}^{(r)} J(r),即判断 若 p k d ∉ J ( r ) , 返 回 ⊥ 若pk_d\notin \mathbb{J}^{(r)},返回\perp pkd/J(r)。】
10)令 n = ( d , p k d , v , r c m ) \mathbf{n}=(d,pk_d,v,rcm) n=(d,pkd,v,rcm)
11)计算 c m ∗ ′ = N o t e C o m m i t m e n t ( n ) cm*'=NoteCommitment(\mathbf{n}) cm=NoteCommitment(n),若 l 2 L E O S P 256 ( E x t r a c t G ( r ) ( c m ∗ ′ ) ) = c m ∗ l2LEOSP_{256}(Extract_{\mathbb{G}^{(r)}}(cm*'))=cm* l2LEOSP256(ExtractG(r)(cm))=cm不成立,则返回 ⊥ \perp
12)若 r e p r G ( K A . D e r i v e P u b l i c ( e s k , g d ) ) ≠ e p h e m e r a l K e y repr_{\mathbb{G}}(KA.DerivePublic(esk,g_d))\neq ephemeralKey reprG(KA.DerivePublic(esk,gd))=ephemeralKey,则返回 ⊥ \perp
10)最终解密结果为 ( n , m e m o ) (\mathbf{n}, memo) (n,memo)

3. Block chain scanning (Sapling)

在Sapling中,区块链扫描仅需 n k nk nk i v k ivk ivk。之前的Sprout中扫描需要spending key。【Sapling中区块扫描的实际代码实现,还额外用到了 a k ak ak,即需要的key参数有 ( a k , n k , i v k ) (ak,nk,ivk) (ak,nk,ivk)。】

已知 ( n k , i v k ) (nk,ivk) (nk,ivk),对区块链扫描可获取 each note sent to the corresponding shielded payment address, its memo field, and its final status (spent or unspent)。完整的扫描流程为:
在这里插入图片描述
注意:
1)以上算法并不需要用到 o v k ovk ovk,或者transmitted note ciphertext中的 C o u t C^{out} Cout。原因在于,当扫描整个区块链时,确实不需要 o v k ovk ovk C o u t C^{out} Cout。之所以支持使用 o v k ovk ovk来解密(如2.3节所示),是为了允许在仅有交易本身的情况下,可恢复交易中发送的note plaintext信息。
2)当扫描区块链中部分区块时,采用 o v k ovk ovk来解密每笔交易中的 C o u t C^{out} Cout是有益的。可以扫描出区块区间中所spent的note信息,尽管该note的receive信息可能在区块区间之外。
3)以上算法无法发现 通过“out-of-band” 或者 with incorrect transmitted note ciphertexts 的notes信息。It is possible to detect whether such notes were spent only if their nullifiers are known。

Zcash的rustzcash.rs实际实现中,计算note nullifier值 n f \mathbf{nf} nf时,不只用到了 n k nk nk,还用到了 a k ak ak

/// Compute Sapling note nullifier.
#[no_mangle]
pub extern "system" fn librustzcash_sapling_compute_nf(
    diversifier: *const [c_uchar; 11],
    pk_d: *const [c_uchar; 32],
    value: uint64_t,
    r: *const [c_uchar; 32],
    ak: *const [c_uchar; 32],
    nk: *const [c_uchar; 32],
    position: uint64_t,
    result: *mut [c_uchar; 32],
) -> bool {
    let note = match priv_get_note(diversifier, pk_d, value, r) {
        Ok(p) => p,
        Err(_) => return false,
    };

    let ak = match edwards::Point::<Bls12, Unknown>::read(&(unsafe { &*ak })[..], &JUBJUB) {
        Ok(p) => p,
        Err(_) => return false,
    };

    let ak = match ak.as_prime_order(&JUBJUB) {
        Some(ak) => ak,
        None => return false,
    };

    let nk = match edwards::Point::<Bls12, Unknown>::read(&(unsafe { &*nk })[..], &JUBJUB) {
        Ok(p) => p,
        Err(_) => return false,
    };

    let nk = match nk.as_prime_order(&JUBJUB) {
        Some(nk) => nk,
        None => return false,
    };

    let vk = ViewingKey { ak, nk };
    let nf = note.nf(&vk, position, &JUBJUB);
    let result = unsafe { &mut *result };
    result.copy_from_slice(&nf);

    true
}

参考资料

[1] Zcash Protocol Specification

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值