加密货币安全基石: MTA协议在Ecdsa门限签名的应用(计算签名中的r)

200 阅读6分钟

声明: 本文纯做技术分享, 不代表任何加密货币投资购买建议

背景: 在之前的加密货币安全基石: 分布式密钥生成协议(GG18, 币安tss-lib keygen部分) 中,我向大家展示了如何进行分布式的密钥生成。在这篇文章中,我将在上篇文章基础更进一步, 讲解如何利用keygen过程中的生成的Paillier 同态加密公私钥对进行门线签名的关键步骤 MTA(multiplicative to additive)协议。 我将从ECDSA签名算法开始,讲解为什么需要用到 MTA协议, MTA协议与Paillier同态加密的关系。最后以币安 tss lib 的单测函数为例,简单过一下MTA协议的golang实现。

需要你有一些密码学, 加密货币, 区块链的前置知识:

  1. 使用 golang 实现一个极简的 区块链
  2. 加密货币安全基石:直观理解ECC椭圆曲线加密算法
  3. 加密货币安全基石:从ECC到ECDSA椭圆曲线签名
  4. 加密货币安全基石: 从拉格朗日插值到shamir共享密钥算法
  5. 加密货币安全基石: 从Shamir到Feldman VSS算法, 以币安tss-lib库为例
  6. 加密货币安全基石: 详解 Paillier 同态加密并使用币安tss-lib库
  7. 加密货币安全基石: 分布式密钥生成协议(GG18, 币安tss-lib keygen部分)

回顾 ECDSA 签名

ECDSA 的详细原理中我之前的 加密货币安全基石:从ECC到ECDSA椭圆曲线签名 中有详细介绍, 这里我们简单回顾一下即可。

定义 G为椭圆曲线 起点, g 为循环群, 私钥 为 d, 公钥Q=dG, n 为 一个大质数, 被签名的原文为 M , 其中 G,Q,M,n 公开, d 为签名方严格保密 签名过程如下:

  1. 对原文进行取哈希操作, 令 z=hash(M)z = hash(M)
  2. [1,n1][1,n-1] 范围内选一个随机数 k, 计算终点 R=(k1)G=g(k1)R = (k-1)G = g^{(k^{-1})}, R 的 横坐标记为 r
  3. 计算 s=k1(z+rd)modns = k^{-1} (z+rd) mod n , 其中 k1k^{-1}kmodn k mod n 的逆元
  4. 最终签名由两部分组成 sign=r,ssign = (r, s)

如果要想去中心化地签名, 就需要去中心化地计算 r 和 s。

MTA协议与计算 ECDSA 签名中的 r 有何关系

我们知道r就是R的横坐标, 想要拆分r实际上就是拆分R. 我们不妨将R虚拟地进行进行如下拆分:

R=g(k1)=g(k1)γγ1=g(kγ1)γR=g^{(k^{-1})}= g^{(k^{-1}) \gamma\gamma^{-1}} = g^{(k\gamma^{-1}) \gamma}

其中 kk 是随机数, γ\gamma 也是随机数,

我们继续对 γ\gamma 进行拆分, 将 其拆成 i 份, 其中 i 为 私钥分片的个数。则上式子可以写成

R=g(k1)=g(k1)γγ1=g(kγ1)γ=g1iγ(kγ1)=(1igγi)(kγ)1R=g^{(k^{-1})}= g^{(k^{-1}) \gamma\gamma^{-1}} = g^{(k\gamma^{-1}) \gamma} = g^{ \textstyle \sum_{1}^{i} \gamma (k\gamma^{-1}) } = ( \prod_{1}^{i} g^{\gamma i } )^ {(k \gamma )^{-1}}

假设 i=2 则上式可以写成:

R=g(k1)=g(k1)γγ1=g(kγ1)γ=g1iγ(kγ1)=(1igγi)(kγ)1=(gγ1gγ2)(kγ)1R=g^{(k^{-1})}= g^{(k^{-1}) \gamma\gamma^{-1}} = g^{(k\gamma^{-1}) \gamma} = g^{ \textstyle \sum_{1}^{i} \gamma (k\gamma^{-1}) } = ( \prod_{1}^{i} g^{\gamma i } )^ {(k \gamma )^{-1}} = (g^{\gamma1} g^{\gamma2})^ {(k \gamma )^{-1}}

我们观察上式, γi \gamma i 由每一个 party 私自持有, 而 gγig^{\gamma i} 公开, 剩下的问题上如何去中心化地协商出 kγk \gamma

我们继续拆分 k , 将 k 也拆成 i 份, i 为 私钥分片数量。假设私钥分片数量为2, 那么 kγk \gamma 可以写成:

kγ=(k1+k2)(γ1+γ2)=k1γ1+k2γ1+k2γ2+k1γ2k \gamma = (k1+k2) (\gamma1 + \gamma2) = k1 \gamma 1 + k2 \gamma1 + k2 \gamma2 + k1 \gamma2

仔细观察上式, 可以看到 k1γ1k1 \gamma1 由 party1(分片1的持有方) 完全掌握, k2γ2k2 \gamma2 由 party2(分片2的持有方) 完全掌握, 剩下的问题就变成了 party1 和 party2 如何在不暴露自己的 k1,γ1k1 , \gamma 1 k2,γ2k2 , \gamma 2 情况下计算出 k2γ1k2 \gamma1 k1γ2k1 \gamma2

我们将 k2γ1 k2 \gamma 1 拆成两个数字的和比如: k2γ1=A+B k2 \gamma 1 = A + B

k1γ2 k1 \gamma 2 拆成两个数字的和比如: k1γ2=C+D k1 \gamma 2 = C + D

有没有一种方法可以在part1不泄露 k1,γ1k1, \gamma 1 party2 不泄露 k2,γ2k2, \gamma 2 的情况下使得 party1 得到 A,C party2 得到 B,C 最终得到 A+B+C+D=k2γ1+k1γ2 A+B+C+D = k2 \gamma 1 + k1 \gamma 2

答案是有的, 就是 MTA(multiplicative to additive)协议 。

MTA 协议

MTA 协议需要两个参与方, 命名为 Alice 和 Bob。 其中Alice 拥有 Paillier 公私钥对, 拥有 秘密值 a. Bob 拥有 秘密值 b 和随机数 β\beta ' .

MTA协议可以做到在 Alice 不泄露 a 的情况下, 在 Bob 不泄露 b 的情况下, 让 Alice得到一个数 α\alpha , 让 Bob 得到一个数字β\beta 使得下列等式成立:

α+β=ξ=ab(modq) \alpha + \beta = \xi = ab (mod q)

这个性质是不是很熟悉, 和上面我们拆分 kγk\gamma 时需要计算的 k1γ2k1\gamma2 的情景是一致的, 需要两方保持各自的秘密, 但是又可以找到两个值通过相加 最终的得到的结果和秘密值相乘 是等价的。

下面来看看 MTA 协议是如何通过 Paillier 同态加密实现的。

  1. Alice 像 Bob 发送 cA= E_A(a), E_A, 其中 E_a 为 Alice 的 Paillier 公钥, E_A(a)表示使用 Paillier公钥对其秘密值 a 进行加密。

  2. Bob 准备一个随机数 β\beta ', 然后计算 cB=bcA+EA(β)=bEA(a)+EA(β)=EA(ab+β)cB = b \cdot cA + E_A(\beta ') = b \cdot E_A(a)+E_A(\beta ') = E_A(ab+ \beta') , 令 β=βmodq\beta = - \beta' mod q

  3. Bob 向 Alice 发送 cB=EA(ab+β)cB=E_A(ab+\beta')

  4. Alice 解密 cBcB , DA(cB)=DA(EA(ab+β))=ab+βD_A(cB)= D_A(E_A(ab+\beta ')) = ab+ \beta ' , 令 α=ab+βmodq\alpha = ab+ \beta ' mod q

然后我们计算 α+β=(αb+β)modq+(β)modq=ab(modq)\alpha + \beta = ( \alpha b + \beta) mod q + (- \beta') mod q = ab (mod q)

就会发现各自秘密值 ab的乘值 已经转换成了各自秘密值 α\alpha β\beta.

我们把这个原理运用到 计算 k2γ1+k1γ2 k2 \gamma 1 + k1 \gamma 2 就是这样的:

  1. party1 对 party2 发起 MTA 协议, part1 使用 k1k1 , part2 使用 γ2\gamma2 作为各自的秘密值, 最终party1和part2得到交换后的秘密值 A,B.
  2. 同上面一样, 不过是party2 对 party1 发起 MTA 协议, part2 使用 k2k2 , part1 使用 γ1\gamma1 作为各自的秘密值, 最终party2和part1得到交换后的秘密值 C,D.

也就是说每一个私钥分片持有方两两进行两次MTA就可以完成对ECDSA签名中R的拆分。

币安 tss lib 中的 MTA 协议

币安 tsslib 中 MTA 协议的函数位于 tss-lib/crypto/mta/share_protocol_test.go 中, 相关注释都已经写好了。 特别的是用到了额外的 range proof, 如果不使用 range proof 则存在可被攻击的漏洞, 通过多次签名即可盗取私钥, 具体可参考这篇文章Alpha-Rays: Key Extraction Attacks on Threshold ECDSA Implementations

func TestShareProtocol(t *testing.T) {
    q := tss.EC().Params().N

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
    defer cancel()
    
    // paillier 公私钥对
    sk, pk, err := paillier.GenerateKeyPair(ctx, rand.Reader, testPaillierKeyLength)
    assert.NoError(t, err)

    a := common.GetRandomPositiveInt(rand.Reader, q)
    b := common.GetRandomPositiveInt(rand.Reader, q)

    // MTA 协议额外的 range proof
    NTildei, h1i, h2i, err := keygen.LoadNTildeH1H2FromTestFixture(0)
    assert.NoError(t, err)
    NTildej, h1j, h2j, err := keygen.LoadNTildeH1H2FromTestFixture(1)
    assert.NoError(t, err)

    // Alice 发送给 Bob
    cA, pf, err := AliceInit(tss.EC(), pk, a, NTildej, h1j, h2j, rand.Reader)
    assert.NoError(t, err)

    // Bob 计算 beta
    _, cB, betaPrm, pfB, err := BobMid(Session, tss.EC(), pk, pf, b, cA, NTildei, h1i, h2i, NTildej, h1j, h2j, rand.Reader)
    assert.NoError(t, err)

    // Alice 计算 alpha
    alpha, err := AliceEnd(Session, tss.EC(), pk, pfB, h1i, h2i, cA, cB, NTildei, sk)
    assert.NoError(t, err)

    // 验证 alpha + beta = a +b mod q
    // expect: alpha = ab + betaPrm
    aTimesB := new(big.Int).Mul(a, b)
    aTimesBPlusBeta := new(big.Int).Add(aTimesB, betaPrm)
    aTimesBPlusBetaModQ := new(big.Int).Mod(aTimesBPlusBeta, q)
    assert.Equal(t, 0, alpha.Cmp(aTimesBPlusBetaModQ))
}

总结

这篇文章中,我向大家推导了如何拆分ECDSA签名中的r部分, 关键步骤是使用基于Paillier同态加密的MTA协议, 最后简单过来一下币安tsslib中的MTA协议。 ECDSA签名由r和s两部分组成, 我会以后更新如何拆分其中的s部分 , 欢迎大家点赞, 收藏, 评论, 关注

Reference

  1. github.com/bnb-chain/t…
  2. medium.com/@asteacherl…
  3. eprint.iacr.org/2021/1621.p…
  4. eprint.iacr.org/2019/114
  5. juejin.cn/post/726388…
  6. juejin.cn/post/737440…
  7. juejin.cn/post/737527…
  8. juejin.cn/post/739224…
  9. juejin.cn/post/739537…
  10. juejin.cn/post/746079…