GoPBC实践 (一):适用于链上计算的密文大小固定的属性基加密机制(On-Chain ABE)
关于Go PBC Wrapper库的说明介绍在官方文档中已经详细给出,本系列专栏将不再详细介绍官方文档中已有内容,请读者及时翻阅官方文档查看相关函数。
版本说明
库 | PBC Library | Golang | gpbc |
---|---|---|---|
Version | 0.5.14 | 1.19.1 | v0.0.0-20181205041846-3e516ca0c5d6 |
适用于区块链的密文大小固定的属性基加密机制 (On-Chain Constant-size ABE)
双线性配对
令G,GT\mathbb{G},\mathbb{G}_TG,GT 为两个具有相同阶 ppp 的循环乘法群。ggg 是 G\mathbb{G}G 的生成元。将 e^\hat{e}e^ 表示为双线性配对:G×G→GT\mathbb{G} \times \mathbb{G} \to \mathbb{G}_TG×G→GT。 该双线性配对操作具有以下属性: (1)双线性:e^(ga,gb)=e^(g,g)ab\hat{e}(g^a, g^b)=\hat{e}(g,g)^{ab}e^(ga,gb)=e^(g,g)ab,其中 a,b∈Zp∗a, b \in \mathbb{Z}_p^*a,b∈Zp∗; (2)非退化性:e^(g,g)≠1\hat{e}(g,g) \neq 1e^(g,g)=1; (3)可计算性:对所有的 g1,g2∈Gg_1, g_2 \in \mathbb{G}g1,g2∈G 计算 e^(g1,g2)\hat{e}(g_1,g_2)e^(g1,g2) 是很有效的。
ABE Setup
-
U={η1,η2,...,ηn}\mathcal{U}=\{\eta_1,\eta_2,...,\eta_n\}U={η1,η2,...,ηn} 表示应用系统中的 nnn 个属性,其中每个属性都有多个值。
-
Si={vi,1,vi,2,...,vi,n}S_i=\{ v_{i,1}, v_{i,2},..., v_{i,n} \}Si={vi,1,vi,2,...,vi,n} 表示属性 ηi\eta_iηi 的多个值。
-
Attribute Authority (AA) 选择两个随机大数 x,y∈Zp∗x, y \in \mathbb{Z}_p^{*}x,y∈Zp∗ 作为系统私钥 msk=⟨x,y⟩msk=\left \langle x, y \right \ranglemsk=⟨x,y⟩。H0H_0H0 是一个哈希函数:{0,1}∗→Zp∗\{0,1\}^* \to \mathbb{Z}_p^*{0,1}∗→Zp∗。
-
将属性值 SiS_iSi 与属性 ηi\eta_iηi 进行绑定,即设置 Xi,k,Yi,kX_{i,k}, Y_{i,k}Xi,k,Yi,k: Xi,k=g−H0{x∣∣i∣∣ki},Yi,k=e^(g,g)H0{y∣∣i∣∣ki}X_{i,k}=g^{-H_0\{x||i||k_i\}}, Y_{i,k}=\hat{e}(g, g)^{H_0\{y||i||k_i\}}Xi,k=g−H0{x∣∣i∣∣ki},Yi,k=e^(g,g)H0{y∣∣i∣∣ki}, 其中 i(1≤i≤n)i (1\le i \le n)i(1≤i≤n) 是 U\mathcal{U}U 中的第 iii 个属性 ηi\eta_iηi,ki(1≤ki≤ni)k_i (1 \le k_i \le n_i)ki(1≤ki≤ni) 是属性值集合 SiS_iSi 中的第 kkk 个值。\
-
将系统公钥设置为 mpk=⟨g,{Xi,k,Yi,k}⟩mpk=\left \langle g, \{X_{i,k}, Y_{i,k} \} \right \ranglempk=⟨g,{Xi,k,Yi,k}⟩。
Setup代码实现
type ABEmsk struct {
x []byte
y []byte
}
type ABEmpk struct {
g []byte
X_k [][]string
Y_k [][]string
}
func OCABE() {
params := pbc.GenerateA(160, 512)
pairing := params.NewPairing()
g := pairing.NewG1().Rand()
x := pairing.NewZr().Rand()
y := pairing.NewZr().Rand()
msk := ABEmsk{
x: x.Bytes(),
y: y.Bytes(),
}
U := []string{"h1", "h2", "d1", "d2", "p", "c1", "c2", "M"}
S := [][]string{
{"a", "b", "c"}, {"e", "f", "g"}, {"h", "i", "j", "k"},
{"l", "m", "n", "o"}, {"q", "r"}, {"s", "t", "a"}, {"b", "c", "e", "f"}, {"t", "s", "y", "w"},
}
X_k, Y_k := computeXY(params.String(), g.Bytes(), U, S, msk)
mpk := ABEmpk{
g: g.Bytes(),
X_k: X_k,
Y_k: Y_k,
}
}
func computeXY(params string, g_ []byte, U []string, S [][]string, msk ABEmsk) (Xik, Yik [][]string) {
pairing, _ := pbc.NewPairingFromString(params)
g := pairing.NewG1().SetBytes(g_)
X := make([][]string, len(U))
Y := make([][]string, len(U))
p := pairing.NewGT().Pair(g, g)
for i := 0; i < len(U); i++ {
for j := 0; j < len(S[i]); j++ {
i_j := strconv.Itoa(i) + strconv.Itoa(j)
x_j := i_j + pairing.NewZr().SetBytes(msk.x).String()
x_j_zr := pairing.NewZr().SetFromStringHash(x_j, sha256.New())
x_j_zr = pairing.NewZr().Neg(x_j_zr)
X_i_k := pairing.NewG1().PowZn(g, x_j_zr)
X[i] = append(X[i], X_i_k.String())
y_j := i_j + pairing.NewZr().SetBytes(msk.y).String()
y_j_zr := pairing.NewZr().SetFromStringHash(y_j, sha256.New())
Y_i_k := pairing.NewGT().PowZn(p, y_j_zr)
Y[i] = append(Y[i], Y_i_k.String())
}
}
return X, Y
}
ABE KeyGen
- 令 LLL 表示用户拥有的属性列表。对于属性列表中的每个属性的值,AA随机选择一个值 sk∈RZp∗sk \in_R \mathbb{Z}_p^*sk∈RZp∗ 来绑定属性与其对应的值。H3H_3H3 是一个防碰撞哈希函数:Zp∗→G\mathbb{Z}_p^* \to \mathbb{G}Zp∗→G。
- 对于属性列表 LLL 中的第 iii 个属性和第 kik_iki 个值,其对应的属性密钥 SKL=⟨sk,{σiˉ}⟩SK_L=\left \langle sk, \{\bar{\sigma_i}\} \right \rangleSKL=⟨sk,{σiˉ}⟩。其中 σiˉ=σi,ki=gH0(y∣∣i∣∣ki)H3(sk)H0(x∣∣i∣∣ki)\bar{\sigma_i}=\sigma_{i,k_i}=g^{H_0(y||i||k_i)}H_3(sk)^{H_0(x||i||k_i)}σiˉ=σi,ki=gH0(y∣∣i∣∣ki)H3(sk)H0(x∣∣i∣∣ki)
KeyGen代码实现
func AttrKeyGen(params string, g_ []byte, msk ABEmsk, n int, userAttr map[string][]int) ([]byte, [][]strin) {
// fmt.Println("ABE Attributes Key Gen")
pairing, _ := pbc.NewPairingFromString(params)
g := pairing.NewG1().SetBytes(g_)
x := pairing.NewZr().SetBytes(msk.x)
y := pairing.NewZr().SetBytes(msk.y)
sk := pairing.NewZr().Rand()
h3_sk_g := pairing.NewG1().SetFromStringHash(sk.String(), sha256.New())
sigma_keys := make([][]string, n)
i := 0
for _, v := range userAttr {
for j := 0; j < len(v); j++ {
x_j := strconv.Itoa(i) + strconv.Itoa(v[j]) + x.String()
y_j := strconv.Itoa(i) + strconv.Itoa(v[j]) + y.String()
xjk_zr := pairing.NewZr().SetFromStringHash(x_j, sha256.New())
yjk_zr := pairing.NewZr().SetFromStringHash(y_j, sha256.New())
tmp1 := pairing.NewG1().PowZn(g, yjk_zr)
tmp2 := pairing.NewG1().PowZn(h3_sk_g, xjk_zr)
sigma_key := pairing.NewG1().Mul(tmp1, tmp2)
sigma_keys[i] = append(sigma_keys[i], sigma_key.String())
}
i += 1
}
return sk.Bytes(), sigma_keys
}
ABE ENC
- 由于需要将密文存储的区块链上,所以为了节约存储开销,将密文设置为固定大小。
- 首先将所有的属性和对应的值整合到一个访问策略 A=⋀i∈IAAi\mathbb{A}=\bigwedge_{i \in \mathcal{I}_{\mathbb{A}}}\mathbb{A}_iA=⋀i∈IAAi 中。
- 计算 ⟨XA,YA⟩=⟨∏i∈IAXˉi,∏i∈IAYˉi⟩\left \langle X_{\mathbb{A}}, Y_{\mathbb{A}} \right \rangle = \left \langle \prod\limits_{i \in \mathcal{I}_{\mathbb{A}}} \bar{X}_i, \prod\limits_{i \in \mathcal{I}_{\mathbb{A}}} \bar{Y}_i \right \rangle⟨XA,YA⟩=⟨i∈IA∏Xˉi,i∈IA∏Yˉi⟩,其中 ⟨Xˉi,Yˉi⟩=⟨Xi,k,Yi,k⟩\left \langle \bar{X}_i, \bar{Y}_i \right \rangle=\left \langle X_{i,k}, Y_{i,k} \right \rangle⟨Xˉi,Yˉi⟩=⟨Xi,k,Yi,k⟩.
- 在文献[1]中,作者使用AES密钥 kidk_{id}kid 来加解密文件,并保护文件ID ididid。
- Health Center (HC) 选择一个 s∈RZp∗s \in_R \mathbb{Z}_p^*s∈RZp∗, 并计算 cid=ABE.Enc(mpk,id∣∣kid,A)=⟨A,C0,C1,C2⟩c_{id}=ABE.Enc(mpk, id||k_{id}, \mathbb{A})=\left \langle \mathbb{A}, C_0, C_1, C_2 \right \ranglecid=ABE.Enc(mpk,id∣∣kid,A)=⟨A,C0,C1,C2⟩。其中 C0=(id∣∣kid)⋅YAsC_0=(id||k_{id})\cdot Y_{\mathbb{A}}^sC0=(id∣∣kid)⋅YAs,C1=gsC_1=g^sC1=gs,C2=XAsC_2=X_{\mathbb{A}}^sC2=XAs。
ENC代码实现
func ABEenc(params string, g_ []byte, mpk ABEmpk, policA map[string][]int, U []string, msg_ string) (polic map[string][]int, c0, c1, c2 []byte) {
pairing, _ := pbc.NewPairingFromString(params)
g := pairing.NewG1().SetBytes(g_)
s := pairing.NewZr().Rand()
msg_el, _ := pairing.NewGT().SetString(msg_, 0)
X_A := pairing.NewG1().Set1()
Y_A := pairing.NewGT().Set1()
for k, v := range policA {
index := indexOf(U, k)
x_i := mpk.X_k[index]
y_i := mpk.Y_k[index]
for j := 0; j < len(v); j++ {
k_i := v[j]
xi_el, ok := pairing.NewG1().SetString(x_i[k_i], 0)
if !ok {
fmt.Println("error set string!")
}
yi_el, ok := pairing.NewGT().SetString(y_i[k_i], 0)
if !ok {
fmt.Println("error set string!")
}
X_A = pairing.NewG1().Mul(X_A, xi_el)
Y_A = pairing.NewGT().Mul(Y_A, yi_el)
}
}
Y_A_s := pairing.NewGT().PowZn(Y_A, s)
c0_el := pairing.NewGT().Mul(msg_el, Y_A_s)
c1_el := pairing.NewG1().PowZn(g, s)
c2_el := pairing.NewG1().PowZn(X_A, s)
polic = policA
return polic, c0_el.Bytes(), c1_el.Bytes(), c2_el.Bytes()
}
ABE DEC
- 解密过程,类似解密过程,私钥的整合通过 σA=∏i∈IAσˉi\sigma_{\mathbb{A}}=\prod\limits_{i\in \mathcal{I}_{\mathbb{A}}} \bar{\sigma}_iσA=i∈IA∏σˉi, 其中 σˉi\bar{\sigma}_iσˉi 是用户的属性列表 SKLSK_LSKL。
- id∣∣kid=C0e^(σA,C1)⋅e^(H3(sk),C2)id||k_{id}=\frac{C_0}{\hat{e}(\sigma_{\mathbb{A}}, C_1)\cdot\hat{e}(H_3(sk), C_2)}id∣∣kid=e^(σA,C1)⋅e^(H3(sk),C2)C0。C0,C1,C2C_0, C_1, C_2C0,C1,C2对应的就是如上所述的密文。
DEC代码实现
func ABEdec(params string, c0_, c1_, c2_, sk_ []byte, sigma_keys_ [][]string) (plaintext string) {
pairing, _ := pbc.NewPairingFromString(params)
c0 := pairing.NewGT().SetBytes(c0_)
c1 := pairing.NewG1().SetBytes(c1_)
c2 := pairing.NewG1().SetBytes(c2_)
sk := pairing.NewZr().SetBytes(sk_).String()
sk_h3_el := pairing.NewG1().SetFromStringHash(sk, sha256.New())
tmp1 := pairing.NewGT().Pair(sk_h3_el, c2)
sigma_A := pairing.NewG1().Set1()
for _, sigma_key := range sigma_keys_ {
for j := 0; j < len(sigma_key); j++ {
sigma_key_el, _ := pairing.NewG1().SetString(sigma_key[j], 0)
sigma_A = pairing.NewG1().Mul(sigma_A, sigma_key_el)
}
}
tmp2 := pairing.NewGT().Pair(sigma_A, c1)
tmp3 := pairing.NewGT().Mul(tmp1, tmp2)
plain_msg_el := pairing.NewGT().Div(c0, tmp3)\
plaintext = plain_msg_el.String()
return
}
程序运行结果展示
参考文献
[1] M. Wang, Y. Guo, C. Zhang, C. Wang, H. Huang and X. Jia, "MedShare: A Privacy-Preserving Medical Data Sharing System by Using Blockchain," in IEEE Transactions on Services Computing, doi: 10.1109/TSC.2021.3114719. [2] 李发根,吴威峰著. 基于配对的密码学[M]. 北京:科学出版社, 2014
转载自:https://juejin.cn/post/7153171713641971743