快速无信任设置的多方门限签名方案

1. 引言

Rosario Gennaro 和 Steven Goldfeder 2018年论文《Fast Multiparty Threshold ECDSA with Fast Trustless Setup》(也称其为GG18论文),发表于ACM CCS 2018。
开源代码实现见:

门限签名方案允许 n n n 个参与者分布式地完成签名,使得任何大小为 t + 1 t+1 t+1 的子集可以生成签名,而大小为 t t t 或更少的子集无法生成签名。尽管已有针对ECDSA签名方案的门限签名方案,但GG18论文中:

  • 提出了首个支持任意 t ≤ n t \leq n tn 的多方签名协议,并实现了高效、无中心节点的密钥生成。
    • 该协议相较于现有方案更快,同时显著减少了通信复杂度。
  • 证明了该方案在存在恶意多数对手的情况下是安全的,并通过实现验证了该方案的效率和实际可部署性。

1.1 从乘法到加法的份额转换协议

假设有两个参与方 Alice 和 Bob,分别持有秘密 a , b ∈ Z q a, b \in \mathbb{Z}_q a,bZq,可以将它们视为秘密 x = a b m o d    q x = ab \mod q x=abmodq 的乘法份额。Alice 和 Bob 希望计算 x x x 的加法份额随机值 α , β \alpha, \beta α,β,满足 α + β = x = a b m o d    q \alpha + \beta = x = ab \mod q α+β=x=abmodq,其中 Alice 持有 α \alpha α(和 a a a),Bob 持有 β \beta β(和 b b b)。
本文提出一个基于加法同态加密方案的协议,这种方案在文献中多次出现(如 [9, 26, 28, 30]),但本文将其适配为当前需求。假设 Alice 关联了一个加法同态加密方案 E \mathcal{E} E 的公钥 E A E_A EA,该方案定义在一个整数 N N N 上。以下称此协议为从乘法到加法的份额转换协议(MtA,Multiplicative to Additive)。此外,假设 B = g b B = g^b B=gb 是公开的,在这种情况下,Bob 会额外检查以确保其使用的 b b b 是正确的。增强后的协议称为 MtAwc(”MtA with check”)。

份额转换协议步骤为:

  • 1)Alice 启动协议
    • 发送 c A = E A ( a ) c_A = E_A(a) cA=EA(a) 给 Bob。
    • 通过零知识证明(ZK)证明她知道 a < q 3 a < q^3 a<q3,通过范围证明实现。
  • 2)Bob 计算
    c B = b × E c A + E E A ( β ′ ) = E A ( a b + β ′ ) c_B = b \times_E c_A +_E E_A(\beta') = E_A(ab + \beta') cB=b×EcA+EEA(β)=EA(ab+β)
    其中 β ′ \beta' β 是在 Z q 5 \mathbb{Z}_{q^5} Zq5 中均匀随机选择的。Bob 设置他的份额为 β = − β ′ m o d    q \beta = -\beta' \mod q β=βmodq。然后他回应 Alice:
    • 发送 c B c_B cB
    • 通过零知识证明(ZK)证明他知道 b < q 3 b < q^3 b<q3, β ′ < q 7 \beta' < q^7 β<q7,使得
      c B = b × E c A + E E A ( β ′ ) c_B = b \times_E c_A +_E E_A(\beta') cB=b×EcA+EEA(β)
    • 如果 B = g b B = g^b B=gb 是公开的,还需证明 B = g b B = g^b B=gb
  • 3)Alice 解密
    Alice 解密 c B c_B cB 得到 α ′ \alpha' α,并设置 α = α ′ m o d    q \alpha = \alpha' \mod q α=αmodq

正确性
假设双方都是诚实的,且 N > q 8 N > q^8 N>q8。注意到 Alice 解密得到的值为 α ′ = a b + β ′ m o d    N \alpha' = ab + \beta' \mod N α=ab+βmodN。由于 β ′ < N − a b \beta' < N - ab β<Nab,因此不会发生模 N N N 的归约操作,意味着协议正确地计算出 α , β \alpha, \beta α,β 使得 α + β = x m o d    q \alpha + \beta = x \mod q α+β=xmodq

模拟性

  • 1)如果攻击者腐化了 Alice,则 Bob 的消息可以在不知道输入 b b b 的情况下进行模拟。模拟器可以随机选择 b ′ ∈ Z q b' \in \mathbb{Z}_q bZq 并充当 Bob。由于“噪声” β ′ \beta' β Z q 5 \mathbb{Z}_{q^5} Zq5 中均匀分布,Alice 解密得到的消息分布与 Bob 使用真实 b b b 的情况统计上接近。
  • 2)如果攻击者腐化了 Bob,则 Alice 的消息可以在不知道输入 a a a 的情况下进行模拟。模拟器可以随机选择 a ′ ∈ Z q a' \in \mathbb{Z}_q aZq 并充当 Alice。此时,由于加密方案 E \mathcal{E} E 的语义安全性,Bob 的视图与真实情况在计算上无法区分。

然而,如果不使用范围证明,恶意的 Alice 或 Bob 可以通过选择较大的输入导致协议“失败”。作为一个独立协议,这并不成问题,因为双方甚至不知道是否发生了模 N N N 的归约操作,且不会泄露关于另一方输入的信息。但在本门限DSA 协议中,这种攻击会导致签名验证失败,并且此信息与另一方输入的大小相关。
如,如果 Alice 使用输入 a ′ = q 7 + a a' = q^7 + a a=q7+a 运行协议:

  • 如果 Bob 的输入较小,则不会发生模 N N N 的归约,协议成功,且最终的签名在门限DSA 协议中可以验证(因为 a ′ = a m o d    q a' = a \mod q a=amodq)。
  • 如果 Bob 的输入较大,则协议会失败。

类似问题也会出现在未检查 b b b β ′ \beta' β 范围的情况下。
因此,在存在一个告诉双方是否发生模 N N N 归约的“预言机”时,需要保证安全性。但由于零知识范围证明,这种归约仅以可忽略的概率发生,因此协议仍然安全。

备注

  • 关于零知识证明和模数 N N N 的大小
    协议中所需的零知识证明使用了类似于 [30](以及已在 [17] 中使用)的简化版本。其安全性依赖于强 RSA 假设。此外,这些证明需要 N ≈ q 8 N \approx q^8 Nq8,如上所述。对于典型的参数选择, N ≈ q 8 N \approx q^8 Nq8(因为 q q q 通常为 256 位,而 N N N 是一个 2048 位的 RSA 模数),因此这一要求并不成问题。然而,参与方必须检查 N N N 的大小,以确保证明的零知识属性。
    • 对于证明 a , b < K a, b < K a,b<K 的简单范围证明,可以选择使用 Boudot 证明的变体 [5],该变体设定 K ∼ q K \sim q Kq,从而使得 N ∼ q 3 N \sim q^3 Nq3。这个证明的效率不如 [17, 30] 中的那些证明,而后者在 MtAwc 协议中是 Bob 所需要的。更重要的是,正如之前所说,实际情况中 N > q 8 N > q^8 N>q8,因此 N N N 的大小改进对 ECDSA 并无实质性影响。
  • 关于之前版本的说明
    在之前的版本中,从 Z N \mathbb{Z}_N ZN 中均匀随机选择 β ′ \beta' β,且未对其施加范围检查。这导致了类似的信息泄露问题,如若选择的 β ′ \beta' β 接近 N N N,归约操作(进而协议失败)会根据输入 a a a 的分布发生。

2. GG18门限多签方案

所有参与者以DSA签名方案中使用的循环群 G , g G, g G,g 为输入。假设每个参与者 P i P_i Pi 关联了一个用于加法同态加密方案 E \mathcal{E} E 的公钥 E i E_i Ei

2.1 密钥生成协议

密钥生成协议分为3个阶段:

  • 1)阶段1
    每个参与者 P i P_i Pi 随机选择 u i ∈ R Z q u_i \in_R \mathbb{Z}_q uiRZq ,计算 [ K G C i , K G D i ] = Com ( g u i ) [KGC_i, KGD_i] = \text{Com}(g^{u_i}) [KGCi,KGDi]=Com(gui) 并广播 K G C i KGC_i KGCi 。每个参与者 P i P_i Pi 广播Paillier密码系统的公钥 E i E_i Ei
  • 2)阶段2
    每个参与者 P i P_i Pi 广播 K G D i KGD_i KGDi ,记 y i y_i yi P i P_i Pi decommitted解承诺后的值。参与者 P i P_i Pi u i u_i ui 进行 ( t , n ) (t, n) (t,n) 的 Feldman-VSS,其中 y i y_i yi 是“指数中的自由项”。公钥设为 y = ∏ i y i y = \prod_i y_i y=iyi 。每个参与者将从 n n n 个 Feldman-VSS 协议中接收到的私有份额相加,得到的值 x i x_i xi 是私钥 x = ∑ i u i x = \sum_i u_i x=iui ( t , n ) (t, n) (t,n) Shamir秘密份额。此外,公开值为 X i = g x i X_i = g^{x_i} Xi=gxi
  • 3)阶段3
    N i = p i q i N_i = p_i q_i Ni=piqi 为与 E i E_i Ei 相关的RSA模数。每个参与者 P i P_i Pi 使用 Schnorr 协议(见CP Schnorr 1991年论文《Efficient signature generation by smart cards》)证明其知道 x i x_i xi ,并使用 Gennaro、Micciancio 和 Rabin 的算法(见1998年论文《An efficient non-interactive statistical zero-knowledge proof system for quasi-safe prime products》)来证明 N i N_i Ni 是square-free的。

其中:

  • Com 是承诺算法。给定输入 pk \text{pk} pk 和消息 M M M,它输出 [ C ( M ) , D ( M ) ] = Com ( pk , M , r ) [C(M), D(M)] = \text{Com}(\text{pk}, M, r) [C(M),D(M)]=Com(pk,M,r),其中 r r r 是随机投掷的结果。 C ( M ) C(M) C(M) 是承诺字符串,而 D ( M ) D(M) D(M) 是解承诺字符串,在揭示之前保持秘密。

2.2 签名生成

签名生成协议中以消息 M M M 的哈希值 m m m 和上述密钥生成协议的输出为输入。注意,该协议为一个 t t t -out-of- n n n 协议(且私钥 x x x 是使用 ( t , n ) (t, n) (t,n) Shamir秘密共享的)。
S ⊆ [ 1.. n ] S \subseteq [1..n] S[1..n] 表示参与签名协议的参与者集合,假设 ∣ S ∣ = t + 1 |S| = t+1 S=t+1 。对于签名协议,可以使用 ( t , t + 1 ) (t, t+1) (t,t+1) 秘密共享方案分发任意ephemeral瞬时秘密,而无需使用 ( t , n ) (t, n) (t,n) 结构。注意,通过适当的Lagrangian系数 λ i , S \lambda_{i,S} λi,S ,集合 S S S 中的每个参与者可以局部地将其 ( t , n ) (t, n) (t,n) 份额 x i x_i xi 映射为 x x x ( t , t + 1 ) (t, t+1) (t,t+1) 份额 w i = ( λ i , S ) ( x i ) w_i = (\lambda_{i,S})(x_i) wi=(λi,S)(xi) ,即 x = ∑ i ∈ S w i x = \sum_{i \in S} w_i x=iSwi 。由于 X i = g x i X_i = g^{x_i} Xi=gxi λ i , S \lambda_{i,S} λi,S 是公开的,所有参与者都可以计算 W i = g w i = ∏ i X i λ i , S W_i = g^{w_i} = \prod_i X_i^{\lambda_{i,S}} Wi=gwi=iXiλi,S

签名生成协议共分为5个阶段:

  • 1)阶段 1
    每个玩家 P i P_i Pi 随机选择 k i , γ i ∈ R Z q k_i, \gamma_i \in_R \mathbb{Z}_q ki,γiRZq ,计算 [ C i , D i ] = Com ( g γ i ) [C_i, D_i] = \text{Com}(g^{\gamma_i}) [Ci,Di]=Com(gγi) 并广播 C i C_i Ci
    定义: k = ∑ i ∈ S k i , γ = ∑ i ∈ S γ i k = \sum_{i \in S} k_i, \quad \gamma = \sum_{i \in S} \gamma_i k=iSki,γ=iSγi
    注意有:
    k γ = ∑ i , j ∈ S k i γ j m o d    q k\gamma = \sum_{i,j \in S} k_i \gamma_j \mod q =i,jSkiγjmodq
    k x = ∑ i , j ∈ S k i w j m o d    q kx = \sum_{i,j \in S} k_i w_j \mod q kx=i,jSkiwjmodq
  • 2)阶段 2
    每对玩家 P i , P j P_i, P_j Pi,Pj 参与两轮multiplicative-to-additive的份额转换子协议:
    • 2.1)子协议1:
      玩家 P i , P j P_i, P_j Pi,Pj 分别使用 k i k_i ki γ j \gamma_j γj 的份额运行 MtA 协议。令 α i j \alpha_{ij} αij β i j \beta_{ij} βij )表示玩家 P i P_i Pi P j P_j Pj )在协议结束时收到的份额,即
      k i γ j = α i j + β i j k_i \gamma_j = \alpha_{ij} + \beta_{ij} kiγj=αij+βij
      玩家 P i P_i Pi 设置: δ i = k i γ i + ∑ j ≠ i α i j + ∑ j ≠ i β j i \delta_i = k_i \gamma_i + \sum_{j \neq i} \alpha_{ij} + \sum_{j \neq i} \beta_{ji} δi=kiγi+j=iαij+j=iβji
      注意, δ i \delta_i δi k γ = ∑ i ∈ S δ i k\gamma = \sum_{i \in S} \delta_i =iSδi ( t , t + 1 ) (t, t+1) (t,t+1) additive sharing加法份额。
    • 2.2)子协议2:
      玩家 P i , P j P_i, P_j Pi,Pj 分别使用 k i k_i ki w j w_j wj 的份额运行 MtAwc 协议。令 μ i j \mu_{ij} μij ν i j \nu_{ij} νij )表示玩家 P i P_i Pi P j P_j Pj )在协议结束时收到的份额,即
      k i w j = μ i j + ν i j k_i w_j = \mu_{ij} + \nu_{ij} kiwj=μij+νij
      玩家 P i P_i Pi 设置: σ i = k i w i + ∑ j ≠ i μ i j + ∑ j ≠ i ν j i \sigma_i = k_i w_i + \sum_{j \neq i} \mu_{ij} + \sum_{j \neq i} \nu_{ji} σi=kiwi+j=iμij+j=iνji
      注意, σ i \sigma_i σi k x = ∑ i ∈ S σ i kx = \sum_{i \in S} \sigma_i kx=iSσi ( t , t + 1 ) (t, t+1) (t,t+1) 加法份额。
  • 3)阶段 3
    每个玩家 P i P_i Pi 广播 δ i \delta_i δi ,且所有玩家重构: δ = ∑ i ∈ S δ i = k γ \delta = \sum_{i \in S} \delta_i = k\gamma δ=iSδi=,然后计算 δ − 1 m o d    q \delta^{-1} \mod q δ1modq
  • 4)阶段 4
    每个玩家 P i P_i Pi 广播 D i D_i Di 。令 Γ i \Gamma_i Γi 表示玩家 P i P_i Pi decommitted解承诺值, P i P_i Pi 通过零知识证明(ZK)证明其知道 γ i \gamma_i γi ,使得 Γ i = g γ i \Gamma_i = g^{\gamma_i} Γi=gγi (使用 Schnorr 协议)。玩家们计算:
    R = [ ∏ i ∈ S Γ i ] δ − 1 = g ( ∑ i ∈ S γ i ) k − 1 γ − 1 = g k − 1 R = \left[\prod_{i \in S} \Gamma_i\right]^{\delta^{-1}} = g^{\left(\sum_{i \in S} \gamma_i\right)k^{-1}\gamma^{-1}} = g^{k^{-1}} R=[iSΓi]δ1=g(iSγi)k1γ1=gk1
    以及 r = H ′ ( R ) r = H'(R) r=H(R)
  • 5)阶段 5
    每个玩家 P i P_i Pi 设置: s i = m k i + r σ i s_i = m k_i + r \sigma_i si=mki+rσi。注意:
    ∑ i ∈ S s i = m ∑ i ∈ S k i + r ∑ i ∈ S σ i = m k + r k x = k ( m + x r ) = s \sum_{i \in S} s_i = m \sum_{i \in S} k_i + r \sum_{i \in S} \sigma_i = mk + rkx = k(m + xr) = s iSsi=miSki+riSσi=mk+rkx=k(m+xr)=s
    s i s_i si s s s ( t , t + 1 ) (t, t+1) (t,t+1) 加法共享。
    • 5.1)(5A) 玩家 P i P_i Pi 随机选择 ℓ i , ρ i ∈ R Z q \ell_i, \rho_i \in_R \mathbb{Z}_q i,ρiRZq ,计算:
      V i = R s i g ℓ i , A i = g ρ i , [ C ^ i , D ^ i ] = Com ( V i , A i ) V_i = R^{s_i} g^{\ell_i}, \quad A_i = g^{\rho_i}, \quad [\hat{C}_i, \hat{D}_i] = \text{Com}(V_i, A_i) Vi=Rsigi,Ai=gρi,[C^i,D^i]=Com(Vi,Ai)
      并广播 C ^ i \hat{C}_i C^i 。定义 ℓ = ∑ i ℓ i , ρ = ∑ i ρ i \ell = \sum_i \ell_i, \quad \rho = \sum_i \rho_i =ii,ρ=iρi
    • 5.2)(5B) 玩家 P i P_i Pi 广播 D ^ i \hat{D}_i D^i ,并通过零知识证明(ZK)证明其知道 s i , ℓ i , ρ i s_i, \ell_i, \rho_i si,i,ρi ,满足: V i = R s i g ℓ i , A i = g ρ i V_i = R^{s_i} g^{\ell_i}, \quad A_i = g^{\rho_i} Vi=Rsigi,Ai=gρi
      如果零知识证明失败,协议终止。
      V = g − m y − r ∏ i ∈ S V i , A = ∏ i ∈ S A i V = g^{-m} y^{-r} \prod_{i \in S} V_i, \quad A = \prod_{i \in S} A_i V=gmyriSVi,A=iSAi
      其中应有: V = g ℓ V=g^{\ell} V=g
    • 5.3)(5C) 玩家 P i P_i Pi 计算: U i = V ρ i , T i = A ℓ i U_i = V^{\rho_i}, \quad T_i = A^{\ell_i} Ui=Vρi,Ti=Ai
      并承诺 [ C ~ i , D ~ i ] = Com ( U i , T i ) [\tilde{C}_i, \tilde{D}_i] = \text{Com}(U_i, T_i) [C~i,D~i]=Com(Ui,Ti) ,然后广播 C ~ i \tilde{C}_i C~i
    • 5.4)(5D) 玩家 P i P_i Pi 广播 D i D_i Di ,decommitted解承诺 U i , T i U_i, T_i Ui,Ti 。如果
      ∏ i ∈ S T i ≠ ∏ i ∈ S U i \prod_{i \in S} T_i \neq \prod_{i \in S} U_i iSTi=iSUi
      则协议终止。
    • 5.5)(5E) 否则,玩家 P i P_i Pi 广播 s i s_i si ,各玩家计算 s = ∑ i ∈ S s i s = \sum_{i \in S} s_i s=iSsi 。如果 ( r , s ) (r, s) (r,s) 不是有效签名,则协议终止,否则协议完成。

阶段5的直观解释
为了避免昂贵的零知识证明(ZK),可能会先构造一个错误的签名,对其进行验证后再决定是否接受或拒绝。一种简单的实现方式是让玩家直接公开 s i s_i si ,然后重构 s = ∑ i s i s = \sum_i s_i s=isi 。但是,这种方式无法在证明中被验证为安全,原因直观上可以理解为:如果对手通过输出无效签名使协议失败,那么他可能从良性玩家持有的 s i s_i si 中获取有价值的信息。
一种直接的改进是让玩家先广播 S i = R s i S_i = R^{s_i} Si=Rsi ,然后根据 DSA 验证算法检查 ∏ i S i = R s = g m y r \prod_i S_i = R^s = g^{m} y^r iSi=Rs=gmyr 。然而,由于类似原因,这一步同样会导致证明失败。
因此,在本协议中,玩家用随机值 g ℓ i g^{\ell_i} gi R s i R^{s_i} Rsi 进行掩码。令
V i = R s i g ℓ i V_i = R^{s_i} g^{\ell_i} Vi=Rsigi

∏ i V i = R s g ℓ \prod_i V_i = R^s g^{\ell} iVi=Rsg
从而 V = g ℓ V = g^{\ell} V=g 。玩家不能直接公开 g ℓ i g^{\ell_i} gi 来验证 V V V 的正确性,因为这会“de-mask去掩码” R s i R^{s_i} Rsi 。因此,通过一个分布式的“Diffie-Hellman”交换机制对聚合值进行随机化,得到
U = g ℓ ρ U = g^{\ell \rho} U=gρ
同时玩家分布式计算 g ℓ ρ g^{\ell \rho} gρ
如果这一分布式随机化签名验证成功,则可以安全地公开各自的 s i s_i si 。但如果签名验证失败,协议会立即终止,良性玩家持有的 s i s_i si 不会被明文泄露。

2.3 零知识证明

在步骤 (5B) 中,玩家 P P P 输出 V = R s g ℓ V = R^s g^{\ell} V=Rsg A = g ρ A = g^{\rho} A=gρ ,并证明其知道满足以下关系的 s , ℓ , ρ s, \ell, \rho s,,ρ

  1. A = g ρ A = g^{\rho} A=gρ 的证明使用经典的 Schnorr 协议。
  2. 对于 V V V ,可以使用以下经典(honest-verifier)ZK proof:
    • Prover选择 a , b ∈ R Z q a, b \in_R \mathbb{Z}_q a,bRZq ,发送 α = R a g b \alpha = R^a g^b α=Ragb
    • Verifier选择随机挑战 c ∈ R Z q c \in_R \mathbb{Z}_q cRZq
    • Prover响应 t = a + c s m o d    q t = a + cs \mod q t=a+csmodq u = b + c ℓ m o d    q u = b + c\ell \mod q u=b+cmodq
    • Verifier检查: R t g u = α V c R^t g^u = \alpha V^c Rtgu=αVc

3. 代码说明

https://github.com/bnb-chain/tss-lib(Go)中实现了:

  • GG18论文的多方 ( t , n ) (t, n) (t,n) -门限ECDSA(Elliptic Curve Digital Signature Algorithm)签名方案:
    • ECDSA 广泛用于比特币、以太坊(secp256k1 曲线)、NEO(NIST P-256 曲线)等加密货币。
  • 以及采用类似方法的 多方 ( t , n ) (t, n) (t,n) -门限EdDSA(Edwards-curve Digital Signature Algorithm)签名方案:
    • EdDSA 广泛用于 Cardano、Aeternity、Stellar Lumens 等加密货币。

其中包含了3个协议:

  • 1)keygen协议:用于创建没有可信dealer的秘密共享的密钥生成。
  • 2)signing协议:即使用秘密份额生成签名。
  • 3)resharing协议:动态组可以在保持秘密的同时改变参与者的组。

对于使用ECDSA和EdDSA的token,此技术可用于创建加密钱包,其中多方必须合作签署交易。

每个参与者在本地存储每个密钥/地址的秘密份额,这些份额由协议保证安全——任何时候都不会向其他人透露。此外,这些份额没有值得信赖的经销商。
与多签解决方案相比:

  • TSS(门限签名) 生成的交易不会透露哪些 t + 1 t+1 t+1个参与者 参与了签名,从而保护了签名者的隐私。
  • 还有一个性能奖励,即区块链节点可以检查签名的有效性,而无需任何额外的 MultiSig 逻辑或处理。

为使用https://github.com/bnb-chain/tss-lib(Go),首先应创建一个LocalParty实例,并为其提供所需的参数,其来自于keygensigning还是sharing取决于具体需要。

3.1 Setup

// When using the keygen party it is recommended that you pre-compute the "safe primes" and Paillier secret beforehand because this can take some time.
// This code will generate those parameters using a concurrency limit equal to the number of available CPU cores.
preParams, _ := keygen.GeneratePreParams(1 * time.Minute)

// Create a `*PartyID` for each participating peer on the network (you should call `tss.NewPartyID` for each one)
parties := tss.SortPartyIDs(getParticipantPartyIDs())

// Set up the parameters
// Note: The `id` and `moniker` fields are for convenience to allow you to easily track participants.
// The `id` should be a unique string representing this party in the network and `moniker` can be anything (even left blank).
// The `uniqueKey` is a unique identifying key for this peer (such as its p2p public key) as a big.Int.
thisParty := tss.NewPartyID(id, moniker, uniqueKey)
ctx := tss.NewPeerContext(parties)

// Select an elliptic curve
// use ECDSA
curve := tss.S256()
// or use EdDSA
// curve := tss.Edwards()

params := tss.NewParameters(curve, ctx, thisParty, len(parties), threshold)

// You should keep a local mapping of `id` strings to `*PartyID` instances so that an incoming message can have its origin party's `*PartyID` recovered for passing to `UpdateFromBytes` (see below)
partyIDMap := make(map[string]*PartyID)
for _, id := range parties {
    partyIDMap[id.Id] = id
}

3.2 keygen

keygen协议中使用keygen.LocalParty,在keygen协议之后,通过endCh收到的数据应保存在安全存储中:

party := keygen.NewLocalParty(params, outCh, endCh, preParams) // Omit the last arg to compute the pre-params in round 1
go func() {
    err := party.Start()
    // handle err ...
}()

3.3 signing

对消息message,使用signing.LocalParty进行签名,需要从 keygen 协议获取的密钥数据。签名完成后将通过endCh发送。

注意, t + 1 t+1 t+1个签名者必须签署消息,为了达到最佳使用效果,不再需要更多的签名者参与其中。每个签名者对 t + 1 t+1 t+1个签名者的身份应有相同的看法。

party := signing.NewLocalParty(message, params, ourKeyData, outCh, endCh)
go func() {
    err := party.Start()
    // handle err ...
}()

3.4 resharing

使用resharing.LocalParty重新分配秘密份额。通过endCh收到的保存数据应覆盖存储中的现有密钥数据,或者如果该方正在接收新份额,则写入新数据。

注意,ReSharingParameters用于向该方提供更多有关应进行的重新共享的上下文信息。

party := resharing.NewLocalParty(params, ourKeyData, outCh, endCh)
go func() {
    err := party.Start()
    // handle err ...
}()

注意:

  • 在重新共享过程中,密钥数据可能会在轮次中被修改。在通过endCh通道接收到最终结构之前,切勿覆盖磁盘上保存的任何数据。

3.5 消息传递

outCh将收集来自一方的传出消息,并且当协议完成时endCh将接收保存的数据或签名。
在协议期间,应该向该方提供从网络上其他参与方收到的更新。
Party有2种线程安全的方法来接收更新:

// The main entry point when updating a party's state from the wire
UpdateFromBytes(wireBytes []byte, from *tss.PartyID, isBroadcast bool) (ok bool, err *tss.Error)
// You may use this entry point to update a party's state when running locally or in tests
Update(msg tss.ParsedMessage) (ok bool, err *tss.Error)

tss.Message具有以下两种为wire将消息转换为数据的方法:

// Returns the encoded message bytes to send over the wire along with routing information
WireBytes() ([]byte, *tss.MessageRouting, error)
// Returns the protobuf wrapper message struct, used only in some exceptional scenarios (i.e. mobile apps)
WireMsg() *tss.MessageWrapper

在典型的用例中,预计传输实现将通过本地Party的out通道使用消息字节,将它们发送到msg.GetTo()的结果中指定的目的地,并将它们传递给UpdateFromBytes接收端。

这样,就不需要处理 Marshal/Unmarshalling 协议缓冲区来实现传输。

3.5 安全说明

消息传输留给应用层,不由此库提供。应仔细阅读并遵循以下每一段,因为实施安全传输以确保协议安全至关重要:

  • 当构建传输时,应该提供广播通道以及连接每对参与方的点对点通道。传输还应在参与方之间采用适当的端到端加密(建议使用带有AEAD加密的 TLS ),以确保参与方只能读取发送给它的消息。
  • 在传输过程中,每条消息都应使用会话 ID进行封装,该 ID 对于密钥生成器、签名或重新共享轮次的单次运行是唯一的。此会话 ID 应在带外达成一致,并且只有参与方在轮次开始前才知道。在收到任何消息时,应用程序应确保收到的会话 ID 与开始时达成一致的会话 ID 相匹配。
  • 此外,传输中应该有一个机制来允许“可靠广播”,这意味着各方可以向其他方广播消息,从而保证每个人都收到相同的消息。网上有几个算法示例,它们通过共享和比较收到的消息的哈希值来实现这一点。
  • 应用程序应处理超时和错误。可以在Party上调用WaitingFor方法以获取仍在等待消息的其他方集。 还可以从*tss.Error中获取导致错误的罪魁祸首集。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值