Two-party ECDSA Signing

Table of Contents

1. Two-party ECDSA 简介

“Two-party ECDSA”问题是指:由两方组成的群体共同完成 ECDSA 签名,可以看作是 2/2 门限签名。本文以 \(P_1\) 和 \(P_2\) 表示参与共同签名的两方。

1.1. 标准的 ECDSA

假设待签名的消息为 \(m\) ,其哈希为 \(H(m)\) ,用户的私钥为 \(x\) ,我们回顾一下标准的(只涉及一方的)ECDSA 签名算法:

  1. 随机选择 \(k \leftarrow \mathbb{Z}_p\) ;
  2. 计算 \(R = k \cdot G\) ;
  3. 计算 \(r=r_x \bmod q\) ,其中 \(r_x\) 是 \(R\) 的 \(x\) 轴坐标;
  4. 计算 \(s=k^{-1} \cdot (H(m) + r \cdot x) \bmod q\) 。

得到的 \((r,s)\) 就是 ECDSA 签名数据。

2. MacKenzie-Reiter 方案

2001 年,MacKenzie 和 Reiter 在论文 Two-Party Generation of DSA Signaturesfull version)中提出了一个 Two-party ECDSA Signing 方案。

MacKenzie 和 Reiter 提出的思路如下:参与方 \(P_1\) 随机生成 \(x_1, k_1\) (和标准的 ECDSA 一样,其中 \(x_1\) 是需要保存的,而 \(k_1\) 是一次一用的),类似地参与方 \(P_2\) 也随机生成 \(x_2, k_2\) ,这两方所组成的群体的 \(k\) 和 \(x\) 分别由 \(k=k_1 \cdot k_2\) 和 \(x=x_1 \cdot x_2\) 得到,由于 \(P_1\) 不能泄露 \(x_1, k_1\) ,同样 \(P_2\) 也不能泄露 \(x_2, k_2\) ,所以不能直接得到群体的 \(k,x\) 。MacKenzie 和 Reiter 给出了一个方案,可以在各方不泄露自己秘密(即 \(x_i, k_i\) )的情况下构造出群体私钥对消息的签名数据。

2.1. 群体公钥

在介绍如何构造群体签名数据前,先介绍一下如何得到群体的公钥 \(Q = x \cdot G = x_1 \cdot x_2 \cdot G\) 。在各方不泄露各自秘密值 \(x_i\) 的情况下,可以按图 1 所示方法求得 \(Q\) ,这是一个标准的 Diffie–Hellman key exchange 过程。

2p_ecdsa_public_key.svg

Figure 1: 运用 Diffie-Hellman 协议得到群体公钥 \(Q\)

\(P_1\) 发送 \(Q_1=x_1 \cdot G\) 给 \(P_2\) (由 \(Q_1\) 无法倒推出 \(P_1\) 的秘密 \(x_1\) ),\(P_2\) 拿了 \(Q_1\) 再乘上 \(x_2\) 就得到了群体公钥;类似地 \(P_1\) 也可以得到群体公钥 \(Q\) 。

2.2. 群体签名数据 \(r\) 部分

由 ECDSA 知,群体签名数据 \(r\) 是 \(R = k_1 \cdot k_2 \cdot G\) 的 \(x\) 轴坐标,我们只需要求得群体 \(R\) 即可知道 \(r\) 。

和计算群体公钥 \(Q\) 类似,利用 Diffie-Hellman key exchange 方法 \(P_1,P_2\) 都可以得到群体的 \(R\) ,如图 2 所示。

2p_ecdsa_r.svg

Figure 2: 运用 Diffie-Hellman 协议得到群体 \(R\)

2.3. 群体签名数据 \(s\) 部分

群体签名数据的 \(s\) 部分的求解相对 \(r\) 的求解要麻烦一些,我们回顾下标准 ECDSA 的 \(s\) : \[s=k^{-1} \cdot (H(m) + r \cdot x) \bmod q\] 换为两方共同完成签名后, \(s\) 的计算方式相应地调整为: \[s=(k_1 \cdot k_2)^{-1} \cdot (H(m) + r \cdot x_1 \cdot x_2) \bmod q\]

在确保 \(P_1\) 不泄露 \(x_1,k_1\) ,而 \(P_2\) 不泄露 \(x_2,k_2\) 的情况下,如何计算群体签名数据的 \(s\) 部分呢?利用 Paillier Cryptosystem 的“同态加密”性质可以做到。

2.3.1. Paillier 加同态

Paillier Cryptosystem 是一种公钥密码算法。除此外,Paillier 还具备“加同态”性质。

Paillier 具备下面两个性质:

  1. 仅已知公钥和两个加密后的消息 \(E(m_1)\) 和 \(E(m_2)\) ,不接触私钥(也就是说不解密)情况下,可以计算出两个明文 \(m_1\) 和 \(m_2\) 相加后再加密的结果,即 \(E(m_1 + m_2)\) ;我们把同态相加记为 \(\oplus\) ,也就是: \[E(m_1 + m_2) = E(m_1) \oplus E(m_2)\]
  2. 仅已知公钥和密文 \(E(m_1)\) 情况下,可以计算出 \(k \cdot m_1\) 的密文(这里 \(k\) 是常量),即 \(E(k \cdot m_1)\) ,我们把这个运算记为 \(\odot\) ,也就是: \[E(k \cdot m_1) = k \odot E(m_1)\]

这两个性质很有用,可以帮助我们计算群体签名数据中的 \(s\) 部分。

2.3.2. 计算 \(s\) 的具体协议

有了前面介绍的 Paillier,我们可以确保 \(P_1\) 不泄露 \(x_1,k_1\) ,而 \(P_2\) 不泄露 \(x_2,k_2\) 的情况下,计算群体签名数据的 \(s\) 了。

\begin{aligned} s &=(k_1 \cdot k_2)^{-1} \cdot (H(m) + r \cdot x_1 \cdot x_2) \bmod q \\ &= k_2^{-1} \cdot H(m) \cdot {\color{red}{k_1^{-1}}} + r \cdot x_2 \cdot k_2^{-1} {\color{red}{k_1^{-1} \cdot x_1}} \bmod q \end{aligned}

上式中,红色部分是只有 \(P_1\) 知道的,把它加密后,发送给 \(P_2\) , \(P_2\) 利用 Paillier 的同态加密性质在密文上构造出加密后的 \(s\) ,然后发送给 \(P_1\) , \(P_1\) 解密即可得到 \(s\) ,这个过程如图 3 所示。

2p_ecdsa_s.svg

Figure 3: 计算 \(s\) 的具体协议(简化版本)

2.4. MacKenzie-Reiter 方案的缺点

为了防止恶意参与者,Two-party ECDSA 协议需要确保“最终生成的群体签名是正确的”。 \(P_1\) 需要在不泄露 \(k_1\) 的情况下证明他向 \(P_2\) 提供的加密数据中确实包含了 \(k_1^{-1}\) ,这需要借助“零知识证明”来完成。 由于 \(P_2\) 手头掌握的和 \(k_1\) 相关的数据只有 \(R_1 = k_1 \cdot G\) (并不包含 \(k_1^{-1} \cdot G\) ),这个证明过程是很复杂的,涉及很多运算,代价比较大。

Yehuda Lindell 于 2017 年提出了另一种 Two-party ECDSA 方案,其零知识证明过程的代价比 MacKenzie-Reiter 方案要小。

3. Yehuda Lindell 方案

2017 年,Yehuda Lindell 在论文 Fast Secure Two-party ECDSA Signing 提出一个更快的 Two-party ECDSA 方案。除去零知识证明相关内容,和 MacKenzie-Reiter 方案的主要区别在于如何构造群体签名数据的 \(s\) 部分。

Yehuda Lindell 方案中构造群体公钥、群体签名数据 \(r\) 部分的方法和 MacKenzie-Reiter 方案是类似的,这里不介绍。

3.1. 群体签名数据 \(s\) 部分

Yehuda Lindell 方案中,构造群体签名数据 \(s\) 部分的流程如图 4 所示。

\begin{aligned} s &=(k_1 \cdot k_2)^{-1} \cdot (H(m) + r \cdot x_1 \cdot x_2) \bmod q \\ &= \left( k_2^{-1} \cdot H(m) + r \cdot x_2 \cdot k_2^{-1} \cdot {\color{red}{x_1}} \right) {\color{red}{k_1^{-1}}} \bmod q \end{aligned}

2p_ecdsa_s_lindell.svg

Figure 4: Yehuda Lindell 方案(构造群体签名数据的 \(s\) 部分)

这个流程中引入了随机数 \(\rho\) ,这是为了获得更好的安全性,由于在它出现的地方同时乘以了模数 \(q\) ,所以并不会影响到正确性。

3.2. \(x = x_1 + x_2\)

前面的介绍中, \(P_1\) 保存的秘密 \(x_1\) 和 \(P_2\) 保存的秘密 \(x_2\) 的乘积 \(x_1 \cdot x_2\) 就是他们作为群体对外的私钥,即 \(x=x_1 \cdot x_2\) 。我们可以把相乘改为相加吗,即 \(x=x_1+x_2\) ?答案是肯定的。不过协议要相应地调整,下文将具体介绍如何调整。

3.2.1. 群体公钥

和节 2.1 中介绍的方式有一点点区别。现在群体公钥的计算要调整为: \[Q = x \cdot G = (x_1 + x_2) \cdot G = x_1 \cdot G + x_2 \cdot G = Q_1 + Q_2\]

3.2.2. 群体签名数据 \(r\) 部分

由于 \(k=k_1 \cdot k_2\) 没有变化,所以群体签名数据 \(r\) 部分的构造没变化,参考节 2.2

3.2.3. 群体签名数据 \(s\) 部分

构造群体签名数据 \(s\) 部分的协议需要调整,如图 5 所示。

\begin{aligned} s &=(k_1 \cdot k_2)^{-1} \cdot (H(m) + r \cdot (x_1 + x_2)) \bmod q \\ &= \left( k_2^{-1} \cdot H(m) + r \cdot k_2^{-1} \cdot ( x_2 + {\color{red}{x_1}}) \right) {\color{red}{k_1^{-1}}} \bmod q \end{aligned}

2p_ecdsa_s_lindell_x.svg

Figure 5: 采用 \(x=x_1 + x_2\) 方式时,构造 \(s\)

3.3. 开源实现

blockchain-crypto-mpc 中有 Yehuda Lindell 方案的开源实现,在这个实现中,为了更方便地支持“Share Refresh”(即在群体私钥不变的前提下实现 \(x_1,x_2\) 的更新),采用了 \(x = x_1 + x_2\) 的方式。

multi-party-ecdsa 中也有 Yehuda Lindell 方案的开源实现,这个实现中,采用了原始论文 \(x = x_1 \cdot x_2\) 的方式,参考:https://github.com/ZenGo-X/gotham-city/blob/master/white-paper/white-paper.pdf

4. 参考

Author: cig01

Created: <2020-11-13 Fri>

Last updated: <2023-01-06 Fri>

Creator: Emacs 27.1 (Org mode 9.4)