Zengo-X 的 MPC GG20 算法底层实现机制

一.MPC 和 GG20 概述

MPC(Multi-Party Computation,多方安全计算)是密码学中的一个重要分支,用于在不需要可信第三方的情况下保护计算中的隐私。GG20 协议是一个基于 MPC 的门限签名协议,主要用于生成和管理加密密钥。我们都知道,MPC 的底层算法还是门限签名,门限签名是一种允许一组参与者(例如,n个参与者中的任意t个)联合签署一条消息的协议。这种签名方式无需所有参与者都参与,只需达到门限 t 即可。签名生成的过程中,密钥从未在一个地方集中保存,分布在多个参与者之间,从而提高了安全性。

1.GG20 的密钥生成

  • 分布式密钥生成:所有参与者通过 MPC 协议共同生成一对公私钥。每个参与者持有私钥的一部分(称为私钥份额),公钥是所有参与者共同计算得到的。
  • 分享私钥份额:每个参与者生成一个秘密值,并将其通过安全多方计算协议分享给其他参与者。这样,每个参与者最终拥有一个私钥份额。

2.签名生成(Signature Generation)

  • 消息预处理:在签名消息之前,参与者需要对消息进行预处理。这个过程通常包括消息的哈希计算和一些参数的生成。
  • 部分签名计算:每个参与者使用自己的私钥份额对消息进行部分签名。这一步通过 MPC 协议进行,保证私钥份额不会被泄露。
  • 部分签名聚合:所有参与者的部分签名通过 MPC 协议进行聚合,生成完整的签名。

3.安全保障

  • 秘密共享:利用秘密共享方案(如Shamir秘密共享)确保私钥份额的安全性。私钥份额在传输过程中经过加密,保证传输安全。
  • 零知识证明:使用零知识证明技术,确保参与者在签名计算过程中未泄露私钥份额。

二. GG20 算法的 Keygen 流程和代码详解

1. Keygen 流程

GG20 协议中的密钥生成(Keygen)过程分为多个轮次(Rounds),每个轮次都有特定的任务和步骤。下面是每个轮次的详细说明:

1.1.Round 0: 初始化

  • 参数生成:每个参与者生成一些本地参数,例如,随机数、私钥份额等。
  • 信息广播:每个参与者向其他参与者广播一些公共信息,这些信息将在后续的轮次中使用。

1.2.Round 1: 承诺阶段

  • 生成承诺:每个参与者生成一个与其私钥份额相关的承诺(Commitment)。这个承诺可以通过Pedersen承诺方案来实现,确保承诺是绑定和隐藏的。
  • 广播承诺:每个参与者将生成的承诺广播给所有其他参与者。

1.3.Round 2: 验证和共享秘密

  • 验证承诺:每个参与者验证其他参与者的承诺,确保其有效性和一致性。
  • 生成和共享秘密:每个参与者生成一个秘密值,并将其通过秘密共享方案(如Shamir秘密共享)分享给其他参与者。

1.4.Round 3: 验证秘密

  • 接收和验证秘密:每个参与者接收其他参与者分享的秘密份额,并验证这些份额的有效性。
  • 计算中间值:每个参与者使用接收到的秘密份额和本地参数计算一些中间值,这些值将在最终的密钥生成中使用。

1.5.Round 4: 生成公私钥

  • 计算私钥份额:每个参与者结合接收到的所有秘密份额和中间值,计算出自己的私钥份额。
  • 生成公钥:所有参与者共同计算生成公钥。这个公钥是所有参与者的公钥,用于验证签名。

1.6.总结

在整个密钥生成过程中,各个轮次的具体任务和步骤如下:

  • Round 0:生成本地参数并广播公共信息。
  • Round 1:生成和广播承诺,确保每个参与者的私钥份额是隐藏和绑定的。
  • Round 2:验证承诺,并生成和共享秘密份额。
  • Round 3:接收和验证秘密份额,计算中间值。
  • Round 4:计算私钥份额和生成公钥。

这些步骤通过安全多方计算(MPC)协议进行,确保私钥份额在生成和传输过程中始终保持私密,且没有任何单个参与者能够独立重构完整的私钥。这种机制极大地提高了系统的安全性,适用于需要高安全性的分布式环境,如区块链和多方认证系统。

2. Keygen 代码

  • Round 0:
pub struct Round0 {
    pub party_i: u16,
    pub t: u16,
    pub n: u16,
}

impl Round0 {
    pub fn proceed<O>(self, mut output: O) -> Result<Round1>
    where
        O: Push<Msg<gg_2020::party_i::KeyGenBroadcastMessage1>>,
    {
        let party_keys = Keys::create(self.party_i as usize);
        let (bc1, decom1) =
            party_keys.phase1_broadcast_phase3_proof_of_correct_key_proof_of_correct_h1h2();

        output.push(Msg {
            sender: self.party_i,
            receiver: None,
            body: bc1.clone(),
        });
        Ok(Round1 {
            keys: party_keys,
            bc1,
            decom1,
            party_i: self.party_i,
            t: self.t,
            n: self.n,
        })
    }
    pub fn is_expensive(&self) -> bool {
        true
    }
}
  • phase1_broadcast_phase3_proof_of_correct_key_proof_of_correct_h1h2:生成正确的 key 的 proof 和 h1、h2 proof; Proof of correct key 是一种零知识证明,用于确保生成的密钥片段和相关计算的正确性和一致性。这是为了确保每个参与者在生成密钥片段时没有作弊或出现错误,从而提高整个协议的安全性和可靠性;proof of h1 和 h2 是零知识证明的一部分,用于证明某些计算的正确性和一致性。这些证明有助于确保协议中的安全性和诚信。

  • Round 1:

pub struct Round1 {
    keys: Keys,
    bc1: KeyGenBroadcastMessage1,
    decom1: KeyGenDecommitMessage1,
    party_i: u16,
    t: u16,
    n: u16,
}

impl Round1 {
    pub fn proceed<O>(
        self,
        input: BroadcastMsgs<KeyGenBroadcastMessage1>,
        mut output: O,
    ) -> Result<Round2>
    where
        O: Push<Msg<gg_2020::party_i::KeyGenDecommitMessage1>>,
    {
        output.push(Msg {
            sender: self.party_i,
            receiver: None,
            body: self.decom1.clone(),
        });
        Ok(Round2 {
            keys: self.keys,
            received_comm: input.into_vec_including_me(self.bc1),
            decom: self.decom1,

            party_i: self.party_i,
            t: self.t,
            n: self.n,
        })
    }
    pub fn is_expensive(&self) -> bool {
        false
    }
    pub fn expects_messages(i: u16, n: u16) -> Store<BroadcastMsgs<KeyGenBroadcastMessage1>> {
        containers::BroadcastMsgsStore::new(i, n)
    }
}
  • 生成 Keygen 广播承诺

  • Round 2:

pub struct Round2 {
    keys: gg_2020::party_i::Keys,
    received_comm: Vec<KeyGenBroadcastMessage1>,
    decom: KeyGenDecommitMessage1,

    party_i: u16,
    t: u16,
    n: u16,
}

impl Round2 {
    pub fn proceed<O>(
        self,
        input: BroadcastMsgs<KeyGenDecommitMessage1>,
        mut output: O,
    ) -> Result<Round3>
    where
        O: Push<Msg<(VerifiableSS<Secp256k1>, Scalar<Secp256k1>)>>,
    {
        let params = gg_2020::party_i::Parameters {
            threshold: self.t,
            share_count: self.n,
        };
        let received_decom = input.into_vec_including_me(self.decom);

        let vss_result = self
            .keys
            .phase1_verify_com_phase3_verify_correct_key_verify_dlog_phase2_distribute(
                &params,
                &received_decom,
                &self.received_comm,
            )
            .map_err(ProceedError::Round2VerifyCommitments)?;

        for (i, share) in vss_result.1.iter().enumerate() {
            if i + 1 == usize::from(self.party_i) {
                continue;
            }

            output.push(Msg {
                sender: self.party_i,
                receiver: Some(i as u16 + 1),
                body: (vss_result.0.clone(), share.clone()),
            })
        }

        Ok(Round3 {
            keys: self.keys,

            y_vec: received_decom.into_iter().map(|d| d.y_i).collect(),
            bc_vec: self.received_comm,

            own_vss: vss_result.0.clone(),
            own_share: vss_result.1[usize::from(self.party_i - 1)].clone(),

            party_i: self.party_i,
            t: self.t,
            n: self.n,
        })
    }
    pub fn is_expensive(&self) -> bool {
        true
    }
    pub fn expects_messages(i: u16, n: u16) -> Store<BroadcastMsgs<KeyGenDecommitMessage1>> {
        containers::BroadcastMsgsStore::new(i, n)
    }
}
  • 验证承诺,并生成和共享秘密份额。

  • Round 3:

pub struct Round3 {
    keys: gg_2020::party_i::Keys,

    y_vec: Vec<Point<Secp256k1>>,
    bc_vec: Vec<gg_2020::party_i::KeyGenBroadcastMessage1>,

    own_vss: VerifiableSS<Secp256k1>,
    own_share: Scalar<Secp256k1>,

    party_i: u16,
    t: u16,
    n: u16,
}

impl Round3 {
    pub fn proceed<O>(
        self,
        input: P2PMsgs<(VerifiableSS<Secp256k1>, Scalar<Secp256k1>)>,
        mut output: O,
    ) -> Result<Round4>
    where
        O: Push<Msg<DLogProof<Secp256k1, Sha256>>>,
    {
        let params = gg_2020::party_i::Parameters {
            threshold: self.t,
            share_count: self.n,
        };
        let (vss_schemes, party_shares): (Vec<_>, Vec<_>) = input
            .into_vec_including_me((self.own_vss, self.own_share))
            .into_iter()
            .unzip();

        let (shared_keys, dlog_proof) = self
            .keys
            .phase2_verify_vss_construct_keypair_phase3_pok_dlog(
                &params,
                &self.y_vec,
                &party_shares,
                &vss_schemes,
                self.party_i.into(),
            )
            .map_err(ProceedError::Round3VerifyVssConstruct)?;

        output.push(Msg {
            sender: self.party_i,
            receiver: None,
            body: dlog_proof.clone(),
        });

        Ok(Round4 {
            keys: self.keys.clone(),
            y_vec: self.y_vec.clone(),
            bc_vec: self.bc_vec,
            shared_keys,
            own_dlog_proof: dlog_proof,
            vss_vec: vss_schemes,

            party_i: self.party_i,
            t: self.t,
            n: self.n,
        })
    }
    pub fn is_expensive(&self) -> bool {
        true
    }
    pub fn expects_messages(
        i: u16,
        n: u16,
    ) -> Store<P2PMsgs<(VerifiableSS<Secp256k1>, Scalar<Secp256k1>)>> {
        containers::P2PMsgsStore::new(i, n)
    }
}
  • 接收和验证秘密份额,计算中间值。

  • Round 4:

pub struct Round4 {
    keys: gg_2020::party_i::Keys,
    y_vec: Vec<Point<Secp256k1>>,
    bc_vec: Vec<gg_2020::party_i::KeyGenBroadcastMessage1>,
    shared_keys: gg_2020::party_i::SharedKeys,
    own_dlog_proof: DLogProof<Secp256k1, Sha256>,
    vss_vec: Vec<VerifiableSS<Secp256k1>>,

    party_i: u16,
    t: u16,
    n: u16,
}

impl Round4 {
    pub fn proceed(
        self,
        input: BroadcastMsgs<DLogProof<Secp256k1, Sha256>>,
    ) -> Result<LocalKey<Secp256k1>> {
        let params = gg_2020::party_i::Parameters {
            threshold: self.t,
            share_count: self.n,
        };
        let dlog_proofs = input.into_vec_including_me(self.own_dlog_proof.clone());

        Keys::verify_dlog_proofs_check_against_vss(
            &params,
            &dlog_proofs,
            &self.y_vec,
            &self.vss_vec,
        )
        .map_err(ProceedError::Round4VerifyDLogProof)?;
        let pk_vec = (0..params.share_count as usize)
            .map(|i| dlog_proofs[i].pk.clone())
            .collect::<Vec<Point<Secp256k1>>>();

        let paillier_key_vec = (0..params.share_count)
            .map(|i| self.bc_vec[i as usize].e.clone())
            .collect::<Vec<EncryptionKey>>();
        let h1_h2_n_tilde_vec = self
            .bc_vec
            .iter()
            .map(|bc1| bc1.dlog_statement.clone())
            .collect::<Vec<DLogStatement>>();

        let (head, tail) = self.y_vec.split_at(1);
        let y_sum = tail.iter().fold(head[0].clone(), |acc, x| acc + x);

        let local_key = LocalKey {
            paillier_dk: self.keys.dk,
            pk_vec,

            keys_linear: self.shared_keys.clone(),
            paillier_key_vec,
            y_sum_s: y_sum,
            h1_h2_n_tilde_vec,

            vss_scheme: self.vss_vec[usize::from(self.party_i - 1)].clone(),

            i: self.party_i,
            t: self.t,
            n: self.n,
        };

        Ok(local_key)
    }
    pub fn is_expensive(&self) -> bool {
        true
    }
    pub fn expects_messages(i: u16, n: u16) -> Store<BroadcastMsgs<DLogProof<Secp256k1, Sha256>>> {
        containers::BroadcastMsgsStore::new(i, n)
    }
}
  • 计算私钥份额和生成公钥

三. GG20 算法的 Sign 流程和代码详解

在GG20协议的签名生成(Sign)过程中,每个轮次(Rounds)都有特定的任务和步骤

1. Sign 流程

1.1.Round 0: 初始化

参数初始化:

  • 每个参与者加载他们在密钥生成阶段生成的私钥片段和公钥。
  • 确定待签名的消息 m。 生成随机数:

  • 每个参与者生成一个随机数 $$k_i$$

计算部分承诺:

  • 计算部分承诺 $$R_i$$: $$ R_i = g^{k_i} \mod p$$

1.2.Round 1: 广播承诺

  • 广播部分承诺:每个参与者将其部分承诺 $$R_i$$ 广播给所有其他参与者。
  • 收集承诺:每个参与者收集所有其他参与者的承诺 $$R_i$$

1.3.Round 2: 生成聚合承诺

  • 计算聚合承诺: 每个参与者计算聚合承诺 R:

$$ R = \prod_{i=1}^{n} R_i$$

  • 广播聚合承诺:将聚合承诺 R 广播给所有参与者。

1.4.Round 3: 生成挑战

  • 生成挑战:每个参与者使用哈希函数生成挑战 c,通常使用聚合承诺 R 和消息 m:

$$c = H(R, m)$$

1.5.Round 4: 计算部分签名

  • 计算部分签名:每个参与者计算其部分签名 $$s_i$$:

$$s_i = k_i + c \cdot x_i \mod q$$

  • 广播部分签名:每个参与者将其部分签名 $$s_i$$ 广播给所有其他参与者。

1.6.Round 5: 收集和验证部分签名

  • 收集部分签名:每个参与者收集所有其他参与者的部分签名 $$s_i$$
  • 验证部分签名:每个参与者验证其他参与者的部分签名 $$s_i$$ 是否正确。

1.7.Round 6: 计算和验证最终签名

计算最终签名:使用收集到的部分签名计算最终签名 s:

$$s = \sum_{i=1}^{n} s_i \mod q$$

验证最终签名:验证最终签名是否正确:

$$g^s \overset{?}{=} R \cdot Y^c \mod p$$

1.8. 总结

  • Round 0:初始化参与者参数,生成随机数和部分承诺。
  • Round 1:广播部分承诺。
  • Round 2:计算并广播聚合承诺。
  • Round 3:生成挑战。
  • Round 4:计算并广播部分签名。
  • Round 5:收集和验证部分签名。
  • Round 6:计算和验证最终签名。

2.Sign 代码流程

  • Round 0:初始化参与者参数,生成随机数和部分承诺。
pub struct Round0 {
    /// Index of this party
    ///
    /// Must be in range `[0; n)` where `n` is number of parties involved in signing.
    pub i: u16,

    /// List of parties' indexes from keygen protocol
    ///
    /// I.e. `s_l[i]` must be an index of party `i` that was used by this party in keygen protocol.
    // s_l.len()` equals to `n` (number of parties involved in signing)
    pub s_l: Vec<u16>,

    /// Party local secret share
    pub local_key: LocalKey<Secp256k1>,
}

impl Round0 {
    pub fn proceed<O>(self, mut output: O) -> Result<Round1>
    where
        O: Push<Msg<(MessageA, SignBroadcastPhase1)>>,
    {
        let sign_keys = SignKeys::create(
            &self.local_key.keys_linear.x_i,
            &self.local_key.vss_scheme.clone(),
            usize::from(self.s_l[usize::from(self.i - 1)]) - 1,
            &self
                .s_l
                .iter()
                .map(|&i| usize::from(i) - 1)
                .collect::<Vec<_>>(),
        );
        let (bc1, decom1) = sign_keys.phase1_broadcast();

        let party_ek = self.local_key.paillier_key_vec[usize::from(self.local_key.i - 1)].clone();
        let m_a = MessageA::a(&sign_keys.k_i, &party_ek, &self.local_key.h1_h2_n_tilde_vec);

        output.push(Msg {
            sender: self.i,
            receiver: None,
            body: (m_a.0.clone(), bc1.clone()),
        });

        let round1 = Round1 {
            i: self.i,
            s_l: self.s_l.clone(),
            local_key: self.local_key,
            m_a,
            sign_keys,
            phase1_com: bc1,
            phase1_decom: decom1,
        };

        Ok(round1)
    }

    pub fn is_expensive(&self) -> bool {
        true
    }
}
  • Round 1:广播部分承诺。
pub struct Round1 {
    i: u16,
    s_l: Vec<u16>,
    local_key: LocalKey<Secp256k1>,
    m_a: (MessageA, BigInt),
    sign_keys: SignKeys,
    phase1_com: SignBroadcastPhase1,
    phase1_decom: SignDecommitPhase1,
}

impl Round1 {
    pub fn proceed<O>(
        self,
        input: BroadcastMsgs<(MessageA, SignBroadcastPhase1)>,
        mut output: O,
    ) -> Result<Round2>
    where
        O: Push<Msg<(GammaI, WI)>>,
    {
        let (m_a_vec, bc_vec): (Vec<_>, Vec<_>) = input
            .into_vec_including_me((self.m_a.0.clone(), self.phase1_com.clone()))
            .into_iter()
            .unzip();

        let mut m_b_gamma_vec = Vec::new();
        let mut beta_vec = Vec::new();
        let mut m_b_w_vec = Vec::new();
        let mut ni_vec = Vec::new();

        let ttag = self.s_l.len();
        let l_s: Vec<_> = self
            .s_l
            .iter()
            .cloned()
            .map(|i| usize::from(i) - 1)
            .collect();
        let i = usize::from(self.i - 1);
        for j in 0..ttag - 1 {
            let ind = if j < i { j } else { j + 1 };

            let (m_b_gamma, beta_gamma, _beta_randomness, _beta_tag) = MessageB::b(
                &self.sign_keys.gamma_i,
                &self.local_key.paillier_key_vec[l_s[ind]],
                m_a_vec[ind].clone(),
                &self.local_key.h1_h2_n_tilde_vec,
            )
            .map_err(|e| {
                Error::Round1(ErrorType {
                    error_type: e.to_string(),
                    bad_actors: vec![],
                })
            })?;

            let (m_b_w, beta_wi, _, _) = MessageB::b(
                &self.sign_keys.w_i,
                &self.local_key.paillier_key_vec[l_s[ind]],
                m_a_vec[ind].clone(),
                &self.local_key.h1_h2_n_tilde_vec,
            )
            .map_err(|e| {
                Error::Round1(ErrorType {
                    error_type: e.to_string(),
                    bad_actors: vec![],
                })
            })?;

            m_b_gamma_vec.push(m_b_gamma);
            beta_vec.push(beta_gamma);
            m_b_w_vec.push(m_b_w);
            ni_vec.push(beta_wi);
        }

        let party_indices = (1..=self.s_l.len())
            .map(|j| u16::try_from(j).unwrap())
            .filter(|&j| j != self.i);
        for ((j, gamma_i), w_i) in party_indices.zip(m_b_gamma_vec).zip(m_b_w_vec) {
            output.push(Msg {
                sender: self.i,
                receiver: Some(j),
                body: (GammaI(gamma_i.clone()), WI(w_i.clone())),
            });
        }

        Ok(Round2 {
            i: self.i,
            s_l: self.s_l,
            local_key: self.local_key,
            sign_keys: self.sign_keys,
            m_a: self.m_a,
            beta_vec,
            ni_vec,
            bc_vec,
            m_a_vec,
            phase1_decom: self.phase1_decom,
        })
    }

    pub fn expects_messages(
        i: u16,
        n: u16,
    ) -> Store<BroadcastMsgs<(MessageA, SignBroadcastPhase1)>> {
        containers::BroadcastMsgsStore::new(i, n)
    }

    pub fn is_expensive(&self) -> bool {
        true
    }
}
  • Round 2:计算并广播聚合承诺。
pub struct Round2 {
    i: u16,
    s_l: Vec<u16>,
    local_key: LocalKey<Secp256k1>,
    sign_keys: SignKeys,
    m_a: (MessageA, BigInt),
    beta_vec: Vec<Scalar<Secp256k1>>,
    ni_vec: Vec<Scalar<Secp256k1>>,
    bc_vec: Vec<SignBroadcastPhase1>,
    m_a_vec: Vec<MessageA>,
    phase1_decom: SignDecommitPhase1,
}

impl Round2 {
    pub fn proceed<O>(self, input_p2p: P2PMsgs<(GammaI, WI)>, mut output: O) -> Result<Round3>
    where
        O: Push<Msg<(DeltaI, TI, TIProof)>>, // TODO: unify TI and TIProof
    {
        let (m_b_gamma_s, m_b_w_s): (Vec<_>, Vec<_>) = input_p2p
            .into_vec()
            .into_iter()
            .map(|(gamma_i, w_i)| (gamma_i.0, w_i.0))
            .unzip();

        let mut alpha_vec = Vec::new();
        let mut miu_vec = Vec::new();

        let ttag = self.s_l.len();
        let index = usize::from(self.i) - 1;
        let l_s: Vec<_> = self
            .s_l
            .iter()
            .cloned()
            .map(|i| usize::from(i) - 1)
            .collect();
        let g_w_vec = SignKeys::g_w_vec(
            &self.local_key.pk_vec[..],
            &l_s[..],
            &self.local_key.vss_scheme,
        );
        for j in 0..ttag - 1 {
            let ind = if j < index { j } else { j + 1 };
            let m_b = m_b_gamma_s[j].clone();

            let alpha_ij_gamma = m_b
                .verify_proofs_get_alpha(&self.local_key.paillier_dk, &self.sign_keys.k_i)
                .map_err(|e| {
                    Error::Round3(ErrorType {
                        error_type: e.to_string(),
                        bad_actors: vec![],
                    })
                })?;
            let m_b = m_b_w_s[j].clone();
            let alpha_ij_wi = m_b
                .verify_proofs_get_alpha(&self.local_key.paillier_dk, &self.sign_keys.k_i)
                .map_err(|e| {
                    Error::Round3(ErrorType {
                        error_type: e.to_string(),
                        bad_actors: vec![],
                    })
                })?;
            assert_eq!(m_b.b_proof.pk, g_w_vec[ind]); //TODO: return error

            alpha_vec.push(alpha_ij_gamma.0);
            miu_vec.push(alpha_ij_wi.0);
        }

        let delta_i = self.sign_keys.phase2_delta_i(&alpha_vec, &self.beta_vec);

        let sigma_i = self.sign_keys.phase2_sigma_i(&miu_vec, &self.ni_vec);
        let (t_i, l_i, t_i_proof) = SignKeys::phase3_compute_t_i(&sigma_i);
        output.push(Msg {
            sender: self.i,
            receiver: None,
            body: (
                DeltaI(delta_i.clone()),
                TI(t_i.clone()),
                TIProof(t_i_proof.clone()),
            ),
        });

        Ok(Round3 {
            i: self.i,
            s_l: self.s_l,
            local_key: self.local_key,
            sign_keys: self.sign_keys,
            m_a: self.m_a,
            mb_gamma_s: m_b_gamma_s,
            bc_vec: self.bc_vec,
            m_a_vec: self.m_a_vec,
            delta_i,
            t_i,
            l_i,
            sigma_i,
            t_i_proof,
            phase1_decom: self.phase1_decom,
        })
    }

    pub fn expects_messages(i: u16, n: u16) -> Store<P2PMsgs<(GammaI, WI)>> {
        containers::P2PMsgsStore::new(i, n)
    }

    pub fn is_expensive(&self) -> bool {
        true
    }
}
  • Round 3:生成挑战。
pub struct Round3 {
    i: u16,
    s_l: Vec<u16>,
    local_key: LocalKey<Secp256k1>,
    sign_keys: SignKeys,
    m_a: (MessageA, BigInt),
    mb_gamma_s: Vec<MessageB>,
    bc_vec: Vec<SignBroadcastPhase1>,
    m_a_vec: Vec<MessageA>,
    delta_i: Scalar<Secp256k1>,
    t_i: Point<Secp256k1>,
    l_i: Scalar<Secp256k1>,
    sigma_i: Scalar<Secp256k1>,
    t_i_proof: PedersenProof<Secp256k1, Sha256>,

    phase1_decom: SignDecommitPhase1,
}

impl Round3 {
    pub fn proceed<O>(
        self,
        input: BroadcastMsgs<(DeltaI, TI, TIProof)>,
        mut output: O,
    ) -> Result<Round4>
    where
        O: Push<Msg<SignDecommitPhase1>>,
    {
        let (delta_vec, t_vec, t_proof_vec) = input
            .into_vec_including_me((
                DeltaI(self.delta_i),
                TI(self.t_i.clone()),
                TIProof(self.t_i_proof),
            ))
            .into_iter()
            .map(|(delta_i, t_i, t_i_proof)| (delta_i.0, t_i.0, t_i_proof.0))
            .unzip3();

        for i in 0..t_vec.len() {
            assert_eq!(t_vec[i], t_proof_vec[i].com);
        }

        let delta_inv = SignKeys::phase3_reconstruct_delta(&delta_vec);
        let ttag = self.s_l.len();
        for proof in t_proof_vec.iter().take(ttag) {
            PedersenProof::verify(proof).map_err(|e| {
                Error::Round3(ErrorType {
                    error_type: e.to_string(),
                    bad_actors: vec![],
                })
            })?;
        }

        output.push(Msg {
            sender: self.i,
            receiver: None,
            body: self.phase1_decom.clone(),
        });

        Ok(Round4 {
            i: self.i,
            s_l: self.s_l,
            local_key: self.local_key,
            sign_keys: self.sign_keys,
            m_a: self.m_a,
            mb_gamma_s: self.mb_gamma_s,
            bc_vec: self.bc_vec,
            m_a_vec: self.m_a_vec,
            t_i: self.t_i,
            l_i: self.l_i,
            sigma_i: self.sigma_i,
            phase1_decom: self.phase1_decom,
            delta_inv,
            t_vec,
        })
    }

    pub fn expects_messages(i: u16, n: u16) -> Store<BroadcastMsgs<(DeltaI, TI, TIProof)>> {
        containers::BroadcastMsgsStore::new(i, n)
    }

    pub fn is_expensive(&self) -> bool {
        true
    }
}
  • Round 4:计算并广播部分签名。
impl Round4 {
    pub fn proceed<O>(
        self,
        decommit_round1: BroadcastMsgs<SignDecommitPhase1>,
        mut output: O,
    ) -> Result<Round5>
    where
        O: Push<Msg<(RDash, Vec<PDLwSlackProof>)>>,
    {
        let decom_vec: Vec<_> = decommit_round1.into_vec_including_me(self.phase1_decom.clone());

        let ttag = self.s_l.len();
        let b_proof_vec: Vec<_> = (0..ttag - 1).map(|i| &self.mb_gamma_s[i].b_proof).collect();
        let R = SignKeys::phase4(
            &self.delta_inv,
            &b_proof_vec[..],
            decom_vec,
            &self.bc_vec,
            usize::from(self.i - 1),
        )
        .map_err(Error::Round5)?;

        let R_dash = &R * &self.sign_keys.k_i;

        // each party sends first message to all other parties
        let mut phase5_proofs_vec = Vec::new();
        let l_s: Vec<_> = self
            .s_l
            .iter()
            .cloned()
            .map(|i| usize::from(i) - 1)
            .collect();
        let index = usize::from(self.i - 1);
        for j in 0..ttag - 1 {
            let ind = if j < index { j } else { j + 1 };
            let proof = LocalSignature::phase5_proof_pdl(
                &R_dash,
                &R,
                &self.m_a.0.c,
                &self.local_key.paillier_key_vec[l_s[index]],
                &self.sign_keys.k_i,
                &self.m_a.1,
                &self.local_key.h1_h2_n_tilde_vec[l_s[ind]],
            );

            phase5_proofs_vec.push(proof);
        }

        output.push(Msg {
            sender: self.i,
            receiver: None,
            body: (RDash(R_dash.clone()), phase5_proofs_vec.clone()),
        });

        Ok(Round5 {
            i: self.i,
            s_l: self.s_l,
            local_key: self.local_key,
            sign_keys: self.sign_keys,
            t_vec: self.t_vec,
            m_a_vec: self.m_a_vec,
            t_i: self.t_i,
            l_i: self.l_i,
            sigma_i: self.sigma_i,
            R,
            R_dash,
            phase5_proofs_vec,
        })
    }

    pub fn expects_messages(i: u16, n: u16) -> Store<BroadcastMsgs<SignDecommitPhase1>> {
        containers::BroadcastMsgsStore::new(i, n)
    }

    pub fn is_expensive(&self) -> bool {
        true
    }
}
  • Round 5:收集和验证部分签名。
pub struct Round5 {
    i: u16,
    s_l: Vec<u16>,
    local_key: LocalKey<Secp256k1>,
    sign_keys: SignKeys,
    t_vec: Vec<Point<Secp256k1>>,
    m_a_vec: Vec<MessageA>,
    t_i: Point<Secp256k1>,
    l_i: Scalar<Secp256k1>,
    sigma_i: Scalar<Secp256k1>,
    R: Point<Secp256k1>,
    R_dash: Point<Secp256k1>,
    phase5_proofs_vec: Vec<PDLwSlackProof>,
}

impl Round5 {
    pub fn proceed<O>(
        self,
        input: BroadcastMsgs<(RDash, Vec<PDLwSlackProof>)>,
        mut output: O,
    ) -> Result<Round6>
    where
        O: Push<Msg<(SI, HEGProof)>>,
    {
        let (r_dash_vec, pdl_proof_mat_inc_me): (Vec<_>, Vec<_>) = input
            .into_vec_including_me((RDash(self.R_dash), self.phase5_proofs_vec))
            .into_iter()
            .map(|(r_dash, pdl_proof)| (r_dash.0, pdl_proof))
            .unzip();

        let l_s: Vec<_> = self
            .s_l
            .iter()
            .cloned()
            .map(|i| usize::from(i) - 1)
            .collect();
        let ttag = self.s_l.len();
        for i in 0..ttag {
            LocalSignature::phase5_verify_pdl(
                &pdl_proof_mat_inc_me[i],
                &r_dash_vec[i],
                &self.R,
                &self.m_a_vec[i].c,
                &self.local_key.paillier_key_vec[l_s[i]],
                &self.local_key.h1_h2_n_tilde_vec,
                &l_s,
                i,
            )
            .map_err(Error::Round5)?;
        }
        LocalSignature::phase5_check_R_dash_sum(&r_dash_vec).map_err(|e| {
            Error::Round5(ErrorType {
                error_type: e.to_string(),
                bad_actors: vec![],
            })
        })?;

        let (S_i, homo_elgamal_proof) = LocalSignature::phase6_compute_S_i_and_proof_of_consistency(
            &self.R,
            &self.t_i,
            &self.sigma_i,
            &self.l_i,
        );

        output.push(Msg {
            sender: self.i,
            receiver: None,
            body: (SI(S_i.clone()), HEGProof(homo_elgamal_proof.clone())),
        });

        Ok(Round6 {
            S_i,
            homo_elgamal_proof,
            s_l: self.s_l,
            protocol_output: CompletedOfflineStage {
                i: self.i,
                local_key: self.local_key,
                sign_keys: self.sign_keys,
                t_vec: self.t_vec,
                R: self.R,
                sigma_i: self.sigma_i,
            },
        })
    }

    pub fn expects_messages(i: u16, n: u16) -> Store<BroadcastMsgs<(RDash, Vec<PDLwSlackProof>)>> {
        containers::BroadcastMsgsStore::new(i, n)
    }

    pub fn is_expensive(&self) -> bool {
        true
    }
}
  • Round 6:计算和验证最终签名。
pub struct Round6 {
    S_i: Point<Secp256k1>,
    homo_elgamal_proof: HomoELGamalProof<Secp256k1, Sha256>,
    s_l: Vec<u16>,
    /// Round 6 guards protocol output until final checks are taken the place
    protocol_output: CompletedOfflineStage,
}

impl Round6 {
    pub fn proceed(
        self,
        input: BroadcastMsgs<(SI, HEGProof)>,
    ) -> Result<CompletedOfflineStage, Error> {
        let (S_i_vec, hegp_vec): (Vec<_>, Vec<_>) = input
            .into_vec_including_me((SI(self.S_i), HEGProof(self.homo_elgamal_proof)))
            .into_iter()
            .map(|(s_i, hegp_i)| (s_i.0, hegp_i.0))
            .unzip();
        let R_vec: Vec<_> = iter::repeat(self.protocol_output.R.clone())
            .take(self.s_l.len())
            .collect();

        LocalSignature::phase6_verify_proof(
            &S_i_vec,
            &hegp_vec,
            &R_vec,
            &self.protocol_output.t_vec,
        )
        .map_err(Error::Round6VerifyProof)?;
        LocalSignature::phase6_check_S_i_sum(&self.protocol_output.local_key.y_sum_s, &S_i_vec)
            .map_err(Error::Round6CheckSig)?;

        Ok(self.protocol_output)
    }

    pub fn expects_messages(i: u16, n: u16) -> Store<BroadcastMsgs<(SI, HEGProof)>> {
        containers::BroadcastMsgsStore::new(i, n)
    }

    pub fn is_expensive(&self) -> bool {
        true
    }
}

四.附录: Pedersen 承诺方案

Pedersen承诺方案是一种加密承诺方案,具有绑定性(binding)和隐藏性(hiding)两个特性。这使其在密码学和区块链应用中非常有用,特别是在需要保证数据隐私和完整性的场景中。以下是Pedersen承诺方案的详细说明:

1.基本原理

Pedersen承诺方案基于离散对数问题的困难性,其主要步骤如下:

  • 选择公有参数:
  • G:一个大素数,通常是一个安全素数。
  • g:一个生成元,生成一个素数阶为 q 的子群。
  • h:另一个群元素,其中 h 不等于 g,且 h 的离散对数未知。

这些参数可以由信任方生成,也可以在标准中固定。

2.承诺生成

假设有一个值 m 和一个随机数 r,承诺 m 的步骤如下:

  • 选择随机数 r:r 是在有限域 Zq 上的一个随机值。
  • 计算承诺值 C:$$C=g^m⋅h^r mod G$$

这里,m 是你要承诺的值,r 是用于保证隐藏性的随机数。

3.验证承诺

要验证承诺,接受者需要知道承诺值 C、原始值 m 和随机数 r。验证步骤如下:

3.1.计算承诺值

  • 重新计算$$C^′=g^m⋅h^rmod G$$

3.2.比较

  • 检查 C′ 是否等于 C。如果相等,则承诺验证通过。

4.特性

  • 绑定性(Binding):一旦承诺值 C 确定,承诺者无法在不改变 r 的情况下改变 m。这是因为离散对数问题的困难性,找到另一个 m′ 使得 $$ g^{m'} \cdot h^r = g^m \cdot h^r$$ 在计算上是不可行的。
  • 隐藏性(Hiding):在不知道随机数 r 的情况下,无法从承诺值 C 推导出原始值 m。这是因为随机数 r 的存在,使得 C 看起来像是随机值。

5.应用

Pedersen承诺方案在多个领域有广泛应用,包括但不限于:

  • 区块链和加密货币:用于隐私保护的交易和智能合约。
  • 零知识证明:在零知识证明协议中,作为基础构建模块,用于隐藏证明者的私有信息。
  • 多方计算:在多方计算协议中,确保各方共享的秘密值在计算过程中保持私密。

Pedersen 承诺方案通过其绑定性和隐藏性,提供了一种强大的工具,用于在各种密码学协议中保证数据的隐私和完整性。其基于离散对数问题的困难性,使其在当前已知的计算能力下具有高度的安全性。

全部评论(0)