1. 引言
【还有个 o c k ock ock:outgoing cipher key,用于encrypt an outgoing ciphertext。】
在Zcash协议中,用户若想接收shielded payments,则其必须拥有a shielded payment address,该shielded payment address 可由 a spending key 生成。
相比于Sprout,Sapling中增加了更多的key类型。下图中的箭头指向表示了key之间的衍生关系;双线型表示的相同的key,只是做了不同的抽象。
在Sprout中,有:
- receiving key s k e n c sk_{enc} skenc
- incoming viewing key i v k = ( a p k , s k e n c ) ivk=(a_{pk}, sk_{enc}) ivk=(apk,skenc)
- shielded payment address a d d r p k = ( a p k , p k e n c ) addr_{pk}=(a_{pk},pk_{enc}) addrpk=(apk,pkenc)
Sprout中的这些key都衍生自spending key a s k a_{sk} ask
下图摘自博客 Zcash - 各种密钥和签名,你懂吗?:
在Sapling中,有:
-
Spending key s k sk sk,为256bit的random值。
-
Expanded spending key ( a s k , n s k , o v k ) (ask, nsk, ovk) (ask,nsk,ovk),其中 a s k ask ask为Spend authorizing key, n s k nsk nsk为nullifier private key, o v k ovk ovk为outgoing viewing key。 a s k , n s k ask,nsk ask,nsk均为scalar field值, o v k ovk ovk为32byte值。
-
Proof authorizing key ( a k , n s k ) (ak, nsk) (ak,nsk),其中 a k ak ak为Jubjub Point,与 a s k ask ask的关系为 a k = a s k ∗ Jubjub.SpendingKeyGenerator ak=ask\ *\ \text{Jubjub.SpendingKeyGenerator} ak=ask ∗ Jubjub.SpendingKeyGenerator。
let ak = fixed_scalar_mult(ask, FixedGenerators::SpendingKeyGenerator);
- Full viewing key ( a k , n k , o v k ) (ak,nk,ovk) (ak,nk,ovk),其中 n k nk nk为Jubjub Point,与 n s k nsk nsk的关系为 n k = n s k ∗ Jubjub.ProofGenerationKey nk=nsk\ *\ \text{Jubjub.ProofGenerationKey} nk=nsk ∗ Jubjub.ProofGenerationKey。
let nk = fixed_scalar_mult(nsk, FixedGenerators::ProofGenerationKey);
- Incoming viewing key i v k ivk ivk,取值范围为 [ 1 , 2 251 − 1 ] [1,2^{251}-1] [1,2251−1],根据 a k , n k ak,nk ak,nk计算获得。
#[no_mangle]
pub extern "system" fn librustzcash_crh_ivk(
ak: *const [c_uchar; 32],
nk: *const [c_uchar; 32],
result: *mut [c_uchar; 32],
) {
let ak = unsafe { &*ak };
let nk = unsafe { &*nk };
let mut h = Blake2s::with_params(32, &[], &[], CRH_IVK_PERSONALIZATION);
h.update(ak);
h.update(nk);
let mut h = h.finalize().as_ref().to_vec();
// Drop the last five bits, so it can be interpreted as a scalar.
h[31] &= 0b0000_0111;
let result = unsafe { &mut *result };
result.copy_from_slice(&h);
}
- diversified shielded payment address
a
d
d
r
d
=
(
d
,
p
k
d
)
addr_d=(d,pk_d)
addrd=(d,pkd)(由Diversifier
d
d
d和 Transmission key
p
k
d
pk_d
pkd组成)。diversifier
d
d
d为88bit随机值,要求存在与
d
d
d对应的diversified base
g
d
=
D
i
v
e
r
s
i
f
y
H
a
s
h
S
a
p
l
i
n
g
(
d
)
g_d = DiversifyHash^{Sapling}(d)
gd=DiversifyHashSapling(d)。【可借助
encodePaymentAddress()
函数,将 d , p k d d,pk_d d,pkd组合成一串单一的shielded payment address。】
#[no_mangle]
pub extern "system" fn librustzcash_check_diversifier(diversifier: *const [c_uchar; 11]) -> bool {
let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier });
diversifier.g_d::<Bls12>(&JUBJUB).is_some()
}
根据
i
v
k
ivk
ivk和
d
d
d 可生成相应的diversified transmission key
p
k
d
pk_d
pkd,
p
k
d
pk_d
pkd为Jubjub point。
#[no_mangle]
pub extern "system" fn librustzcash_ivk_to_pkd(
ivk: *const [c_uchar; 32],
diversifier: *const [c_uchar; 11],
result: *mut [c_uchar; 32],
) -> bool {
let ivk = read_fs(unsafe { &*ivk });
let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier }); //此处即为Diversify Hash函数。
if let Some(g_d) = diversifier.g_d::<Bls12>(&JUBJUB) {
let pk_d = g_d.mul(ivk, &JUBJUB);
let result = unsafe { &mut *result };
pk_d.write(&mut result[..]).expect("length is 32 bytes");
true
} else {
false
}
}
对于每个spending key,对应有a default diversified payment address with a “random-looking” diversifier。若无法区分default address和以上通过random diversifier生成的地址,则可实现不暴露diversified addresses as a user-visible feature。但是实际zcashd wallet中并未使用default diversified payment address,而是采用ZIP-32 中的方案来生成
注意,整个协议中使用Bech32.encode()
是可能产生vanity address的,从而可能会存在泄漏隐私的问题。软件开发者在实际实现时要注意使用randomly chosen diversifier,同时也建议 diversifiers be randomly chosen unique values used to index into a database, rather than directly encoding the needed data。
Zcash的共识协议不依赖于expanded spending key的构建方式。expanded spending key的构建方式有以下两种:
- 随机生成spending key s k sk sk,基于 s k sk sk生成expanded spending key ( a s k , n s k , o v k ) (ask,nsk,ovk) (ask,nsk,ovk)。
- 根据 ZIP-32,其中包含了expanded spending key的superset。该方式已用于Hierarchical Deterministic Wallet中。但是目前Zcash还不支持Hierarchical Deterministic Wallet address。
在zcashd(Zcash的官方客户端软件)中,所有的Sapling keys和addresses都是根据 ZIP-32生成的。
Sapling中的shielded payment addresses、incoming viewing keys、full viewing keys和spending keys均为a cryptographic protocol detail,这些信息正常来说不应直接暴露给用户。但是,user-visible operations需要知悉shielded payment address、incoming viewing key、(或)来自于spending key或extended spending key的full viewing key。
【在Sapling中,对于每一个spending key,其对应的full viewing key可在无spend authority的情况下,识别出incoming和outgoing notes。具体的解决方案为在每个Output description中增加额外的ciphertext。】
用户可 以一个shielded payment address 来接收来自 多方的支付,事实上,这些支付指向的是同一收款人 这一信息并不会暴露在区块链上,即使是对支付方来说,也无法知悉这些支付指向的是同一收款人。但是,若两个支付方勾结比对了收款方对应的shielded payment address,则可完全确定指向的是同一收款人。为了避免这种情况,收款方可为每个支付方创建不同的shielded payment address。
在Sapling中,提供了一种为同一spending authority 高效生成diversified payment addresses的机制,这些diversified payment addresses共享相同的full viewing key和incoming viewing key。创建大量这样的diversified payment addresses并不会给 扫描区块链以获取相关交易 增加额外开销。
密码学传统上将非对称加密中用于加密的key称为“public key”。transmission key中作为public key的为 p k e n c pk_{enc} pkenc或 p k d pk_d pkd。这个public key不需要单独分发,因为其已包含在shielded payment address中。
同时注意,控制shielded payment address的分发在某些应用场景下是必要的。同时,这也有助于减少整个协议对 note encryption中使用的密码学安全性的依赖。【具体可参见Zcash Protocol Specification 4.17节“In-band secret distribution (Sapling)”中的分析,知道某些 p k d pk_{d} pkd的攻击者可尝试寻找整个密码学系统中的某些假设薄弱点。】
2. Sapling Key Components
Sapling中,有:
- l P R F e x p a n d 为 N = 512 , l s k 为 256 , l i v k S a p l i n g 为 251 , l o v k 为 256 , l d 为 88 l_{PRFexpand}为\mathbb{N}=512, l_{sk}为256, l_{ivk}^{Sapling}为251, l_{ovk}为256, l_{d}为88 lPRFexpand为N=512,lsk为256,livkSapling为251,lovk为256,ld为88 均为常量。
-
J
(
r
)
,
J
(
r
)
∗
,
J
∗
(
r
)
,
r
e
p
r
J
,
r
J
\mathbb{J}^{(r)},\mathbb{J}^{(r)*},\mathbb{J}_{*}^{(r)},repr_{\mathbb{J}},r_{\mathbb{J}}
J(r),J(r)∗,J∗(r),reprJ,rJ 均为Jubjub相关参数,其中:
J ( r ) \mathbb{J}^{(r)} J(r)为order- r J r_{\mathbb{J}} rJ subgroup of J \mathbb{J} J。该subgroup中包含了 O J \mathcal{O}_{\mathbb{J}} OJ。除 O J \mathcal{O}_{\mathbb{J}} OJ之外的,order 为 r J r_{\mathbb{J}} rJ的point set表示为 J ( r ) ∗ \mathbb{J}^{(r)*} J(r)∗。 - F i n d G r o u p H a s h J ( r ) ∗ FindGroupHash^{\mathbb{J}^{(r)*}} FindGroupHashJ(r)∗为“Group Hash into Jubjub”。返回无效point的概率接近 2 − 256 2^{-256} 2−256。
- P R F e x p a n d 和 P R F o c k S a p l i n g PRF^{expand}和PRF^{ockSapling} PRFexpand和PRFockSapling为Pseudo Random Functions。
- K A S a p l i n g KA^{Sapling} KASapling为Sapling Key Agreement。
- C R H i v k CRH^{ivk} CRHivk为 C R H i v k CRH^{ivk} CRHivk Hash Function。
- D i v e r s i f y H a s h S a p l i n g DiversifyHash^{Sapling} DiversifyHashSapling为 D i v e r s i f y H a s h S a p l i n g DiversifyHash^{Sapling} DiversifyHashSapling Hash Function。
- S p e n d A u t h S i g S a p l i n g SpendAuthSig^{Sapling} SpendAuthSigSapling Spend Authorization Signature (Sapling),为a signature scheme with re-randomizable keys。
- LEBS2OSP为
(
l
:
N
)
×
B
[
l
]
−
>
B
Y
[
c
e
i
l
i
n
g
(
l
/
8
)
]
(l:\mathbb{N})\times\mathbb{B}^{[l]}->\mathbb{B}^{\mathbb{Y}^{[ceiling(l/8)]}}
(l:N)×B[l]−>BY[ceiling(l/8)]
LEOS2IP为 ( l : N ∣ l m o d 8 = 0 ) × B B Y [ l / 8 ] − > { 0 ⋯ 2 l − 1 } (l:\mathbb{N}|l\mod 8 = 0)\times\mathbb{B}^{\mathbb{B}^{\mathbb{Y}^{[l/8]}}}->\{0\cdots 2^l-1\} (l:N∣lmod8=0)×BBY[l/8]−>{0⋯2l−1}。
LEBS2OSP和LEOS2IP为“Integers, Bit Sequenes, and Endianness”中相关定义。
3. Sapling Payment Addresses
Sapling 的shielded payment address 为 a d d r d = ( d , p k d ) addr_d=(d,pk_d) addrd=(d,pkd)(由88-bit Diversifier d d d和 256-bit Transmission key p k d pk_d pkd组成)。其raw encoding规则分别为:
- L E B S 2 O S P 88 ( d ) LEBS2OSP_{88}(d) LEBS2OSP88(d)
- L E B S 2 O S P 256 ( r e p r J ( p k d ) ) LEBS2OSP_{256}(repr_{\mathbb{J}}(pk_d)) LEBS2OSP256(reprJ(pkd))
encoding以后再加上某些Human-Readable前缀,如Zcash主网上的shielded payment address以“zs”打头,而Zcash测试网上的shielded payment address则以“ztestsapling”打头。
Shielded payment address 中包含的transmission key p k d pk_d pkd 可用于 a “key-private” asymmetric encryption scheme。所谓"key-private"是指,ciphertexts中不会泄露其加密key的信息,只对拥有加密key对应private key(此处也可称为receiving key)的一方可见。该机制主要用于communicate encrypted output notes on the block chain to their intended recipient,拥有receiving key的一方可扫描区块链来获取notes addressed to them 并 decrypt those notes。
4. Sapling Incoming Viewing Keys
Sapling中的
i
v
k
ivk
ivk取值范围为
[
1
,
2
251
−
1
]
[1,2^{251}-1]
[1,2251−1],实际实现以256-bit表示,其中最高的5个-bit会做置零操作。
Zcash主网上的incoming viewing key前缀为“zivks”,测试网的incoming viewing key前缀为“zivktestsapling”。
5. Sapling Full Viewing Keys
Full viewing key ( a k , n k , o v k ) (ak,nk,ovk) (ak,nk,ovk),其中 a k , n k ak,nk ak,nk为Jubjub point,outgoing viewing key o v k ovk ovk 为32byte值。可将其编码为一个单独的串,编码规则为:
- L E B S 2 O S P 256 ( r e p r J ( a k ) ) LEBS2OSP_{256}(repr_{\mathbb{J}}(ak)) LEBS2OSP256(reprJ(ak))
- L E B S 2 O S P 256 ( r e p r J ( n k ) ) LEBS2OSP_{256}(repr_{\mathbb{J}}(nk)) LEBS2OSP256(reprJ(nk))
- 32-byte o v k ovk ovk
在Zcash主网中,full viewing key前缀为“zviews”,测试网的前缀为“zviewtestsapling”。
在Sapling中,每一个spending key都有相应的full viewing key,full viewing key可用于recognize both incoming and outgoing notes without having spend authority。具体是通过每个Output description中额外的ciphertext—— C o u t C^{out} Cout 来实现的。详细可见博客 Zcash中的加解密机制。
6. Sapling Spending Keys
Sapling中的spending key 以256-bit表示。
Zcash主网中的spending key前缀为“secret-spending-key-main”,测试网的前缀为“secret-spending-key-test”。
Spending key为私钥的一种,拥有spending key的用户可spend the balance of the associated address。对于shielded address,拥有相应spending key的用户可查看address’ balance and transaction data。
参考资料
[1] Zcash Protocol Specification
[2] 博客 Zcash - 各种密钥和签名,你懂吗?
[3] Zcash Protocol Specification
Version 2021.1.22 [NU5 proposal]
[4] Zcash官方文档