美文网首页
mp-ecdsa-java-sdk 手册

mp-ecdsa-java-sdk 手册

作者: 雪落无留痕 | 来源:发表于2022-12-19 16:29 被阅读0次

    (t,n)门限签名:n个参与者,其中至少t+1个参与者一起可以完成签名,少于t(含)个无法签名。

    密钥生成阶段

    在密钥生成阶段需要n个参与者都参与,每个参与者生成一个私钥sk_i,最终的私钥为所有sk_i之和。

    在进行密钥生成之前,需要确定给n个参与者排序,标记为1,2,3,...,n.

    下面介绍密钥生成的过程。

    1. ctx=libmpecdsaKeygenCtxInit(),参数及返回值类型如下:
     long libmpecdsaKeygenCtxInit( 
         int i, //输入参数,参与者的序号, i>=1 && i <=n 
         int n, //输入参数,参与者总数 
         int t //输入参数,阈值,在签名阶段>=t+1个参与者才可以完成签名过程。
       )
       //返回值为ctx,rust指针。
    

    该ctx在后面每一轮调用时都作为参数传入。

    1. 调用round1Ans=libmpecdsaKeygenRound1(),参数及返回值如下
    String libmpecdsaKeygenRound1( 
         long ctx,//输入参数,为第1步生成的ctx。 
         int[] bcLength, //长度为1的数组,java创建,rust赋值 
         int[] decomLength//长度为1的数组,java创建,rust赋值 
       ) 
       //返回值为String类型,长度为(bcLength[0]+decomLength[0])
    

    round1Ans为String类型,前bcLength[0]字节为bc, 后面decomLength[0]字节为decom.

    每个参与者将round1Ans中的bc广播给其他n-1个参与者。

    在收到其他所有n-1个参与者的bc之后,将每个bc(包括自己)按照参与者的序号从小到大的顺序级联在一起,组成bcs.假设第i个参与者的bcbc_i, 那bcs=bc_1||bc_2||...||bc_n. 每个bc_i的长度放在数组bciLength中,即bciLength[i]=len(bc_i)

    再 广播decom给其他n-1个参与者,与广播bc的方式一样。接收到所有的decom之后,级联在一起,组成decoms,相应地每个decom的长度存放在数组 decomiLength 中。

    3.执行round2Ans=libmpecdsaKeygenRound2(),参数及返回值如下

    String libmpecdsaKeygenRound2( 
        long ctx, //输入参数,为第1步生成的ctx 
        String bcs, //输入参数,见第2步描述 
        int[] bciLength,//bciLength:长度为n的数组,见第2步描述 
         String decoms, //decoms:输入参数,见第2步描述 
         int[] decomiLength, //decomiLength:长度为n的数组,见第2步描述 
         int[] ciphertextsLength //ciphertextsLength:长度为n-1的数组,java创建,rust赋值 
       ); 
       //返回值为String类型,长度为sum(ciphertextsLength)
    

    round2Ans为String类型, 是需要发送给其他n-1个参与者的消息。如果round2Ans=null,则说明libmpecdsaKeygenRound2函数验证出错,协议终止。

    发给每个参与者的信息是按顺序存放在round2Ans中,对应的长度存放在ciphertextsLength数组中。round2Ans拆分格式如下,假设自己的序号为k

    1. 每个参与者将第3步接收到的其他n-1个参与者的消息,按照参与者(不包括自己)序号从小到大的顺序级联在一起,组成ciphertexts,每个消息的长度存放在数组ciphertextiLength中,数组长度为n-1。假设自己的序号为k,收到的来自参与者i的消息为ciphertexts_i,则ciphertexts=ciphertexts_1||ciphertexts_2||..||ciphertexts_{k-1}||ciphertexts_{k+1}||..||ciphertexts_n.

    调用round3Ans = libmpecdsaKeygenRound3(), 参数及返回值如下

     String libmpecdsaKeygenRound3( 
        long ctx, //输入参数,为第1步生成的ctx 
        String ciphertexts,//输入参数,见上面描述 
        int[] ciphertextiLength //输入参数,见上面描述 
      ) 
      //返回值为vss_scheme
    

    如果round3Ans=null, 则协议终止。

    round3Ans直接广播给其他所有的n-1个参与者。

    1. 每个参与者在接收到其他n-1个参与者的round3Ans之后,按照参与者(不包括自己)的序号从小到哪的顺序级联在一起组成vssSchemes. 每个参与者的round3Ans的长度按照参与者序号从小到大的顺序存放在vssSchemeLength数组中。

      调用round4Ans = libmpecdsaKeygenRound4(), 参数及返回值如下
      
    String libmpecdsaKeygenRound4( 
        long ctx, //输入参数,为第1步生成的ctx 
        String vssSchemes,//输入参数,见上面描述 
        int[] vssSchemeLength //输入参数,见上面描述 
       ) 
       //返回值为dlog_proof
    

    如果round4Ans=null,协议终止。

    round4Ans直接广播给其他所有的n-1个参与者。

    1. 每个参与者接收到其他n-1个参与者的round4Ans,按照参与者(包括自己)的序号从小到哪的顺序级联在一起组成dlog_proofs. 每个参与者的round4Ans的长度按照参与者序号从小到大的顺序存放在dlog_proof_length数组中。

       调用round5Ans=libmpecdsaKeygenRound5(),参数及返回值如下
      
    String libmpecdsaKeygenRound5( 
        long ctx, //输入参数,为第1步生成的ctx 
        String dlogProofs,//输入参数,见上面描述 
        int[] dlofProofLength//输入参数,见上面描述 
      ) 
      //返回值包括公钥、私钥份额等
    

    如果round5Ans=null,协议终止。

    1. 调用libmpecdsaKeygenCtxFree(ctx)释放ctx所指向的rust内存空间。 无论协议是正常执行结束还是协议异常终止,必须要调用该函数释放ctx。

    将round5Ans反序列化,第三个字段为公钥(未压缩形式)。

    由于round5Ans包含隐私信息,最好将round5Ans加密存储, 在签名时解密供签名阶段使用。

    签名阶段

    在签名开始的时候,首先通过相互广播通信确定签名者,签名者的数量必要大于t 且小于等于n。例如假如n = 5, t = 2, 签名者的数量为3, 可以定义 singers = [0, 2, 3]。

    注意: (1) 0,2,3代表参与者的序号,与上述密钥生成过程不同的是,它从 0开始到 n -1。

             (2) [0, 2, 3] 的顺序可以任意改变,例如 [2, 0, 3],[3,2,0]等,但所有签名者对签名者的顺序必须达成并保持一致。
    
    1. 签名者首先需要进行初始化:

    long signCtx1 = instance.libmpecdsaSignCtxInit(N, T);

    public long libmpecdsaSignCtxInit(  
        int n, //密钥生成总人数  
        int t   //门限签名阈值 
       ) 
       //返回值: sigCtx 指针, 作为后续签名过程中的输入
    
    1. 每个签名者分别调用 signRound = instance.libmpecdsaSignRound1(),参数及返回值为:
    public String libmpecdsaSignRound1(    
          long ctx,    //为初始化生成的signCtx    
          String keygenResult, //为上述密钥生成过程的结果,即round5Ans   
          int[] signers,      //参与签名者,所有签名者的signers输入必须保持一致    
          int signersNum,    //参与签名者的人数, 即signers数组的长度    
          int[] commitLength, //长度为1的数组,用于记录返回值commit的长度    
          int[] mAKLength     //长度为1的数组,用于记录返回值mAK的长度 
        ) 
       // 返回值为String类型,为commit||mAK.
    
    1. 每个签名者分别广播commit和mAK, 在接收到其它(signersNum -1)个签名者的commit和mAK后,根据签名者的顺序分别将commit和mAK级联在一起,组合成commits和mAKs。例如假如签名者为 signers = [0, 2, 3],则

      commits = commit_0 || commit_2 || commit_3, 同理 mAKs = mAK_0 || mAK_2 || mAK_3。同时,需要将它们对应的字符串长度分别保存下来,

      即commitsLength = [commit_0_length, commit_2_length, commit_3_length], mAKsLength = [mAK_0_length, mAK_2_length, mAK_3_length]。

    同理, 对mAK的处理类似, 然后每个签名者分别调用 signRound2 = instance.libmpecdsaSignRound2(),相关参数与返回值为:

    public String libmpecdsaSignRound2(      
         long ctx,          //为初始化生成的signCtx      
         String commits,     //见上面所描述      
         int[] commitsLength,  //见上面所描述      
         String mAKs,         //见上面所描述      
         int[] mAKsLength,    //见上面所描述      
         int[] mBGammaLength, // 长度为 signersNum - 1, 用于记录生成mBGamma数组的长度      
         int[] mBWiLength      // 长度为 signersNum - 1, 用于记录生成mBWi数组的长度 
         ) 
      // 返回值为String类型,为 mBGamma_0 || ... || mBGamma_(signersNum - 2) || mBWi_0 || ... || mGWi_(signersNum - 2)
    
    1. 签名者之间分别通过点对点通信,相互传输mBGamma和mBGWi。例如若 singers = [0, 2, 3]

    对于签名者0 的 mBGamma0 = mBGamma0_0 || mBGamma0_1,需要将mBGamma0_0发给2, 将mBGamma0_1发给3

    对于签名者2 的 mBGamma2 = mBGamma2_0 || mBGamma2_1, 需要将mBGamma2_0 发给0, 将mBGamma2_1发给3

    对于签名者3 的 mBGamma3 = mBGamma3_0 || mBGamm3_1, 需要将mBGamma3_0 发给0, 将mBGamma3_1 发给2。

    经过点对点通信后,

    签名者0 得到 mBGamma0' = mBGamma2_0 || mBGamma3_0, mBGamma0'Length = [mBGamma2_0_length, mBGamma3_0_length]

    签名者2 得到 mBGamma2' = mBGamma0_0 || mBGamma3_1, mBGamma2'Length = [mBGamma0_0_length, mBGamma3_1_length]

    签名者2 得到 mBGamma3' = mBGamma0_1 || mBGamma2_1, mBGamma3'Length = [mBGamma0_1_length, mBGamma2_1_length]

    同理, 对mBWi的处理和mBGamma完全类似,然后每个签名者调用:

              signRound3 = instance.libmpecdsaSignRound3()
    

    相关的参数和返回值为:

    public String libmpecdsaSignRound3(       
           long ctx,           //  每个签名者的signCtx       
           String mBGammaRec,  //  每个签名者接收到的mBGamma, size = signersNum - 1,见上描述       
           int[] mBGammaLength,  // 每个签名者接收到mBGamma的长度,size = signersNum - 1, 见上描述       
           String mBWiRec,     // 每个签名者接收到的mBWi, size = signersNum - 1       
           int[] mBWiRecLengh   // 每个签名者接收到的mBWi的长度,size = signersNum - 1 
         ) 
        // 返回值: delta
    
    1. 每个签名者分别广播delta, 接收到其它singersNum -1个delta 后, 按照签名者的顺序级联在一起,例如若 signers = [0, 2, 3]

      则 deltaRec = delta_0 || delta_2 || delta_3, deltaLength = [delta_0_length, delta_2_length, delta_3_length]

    然后每个签名者分别调用: signRound4 = instance.libmpecdsaSignRound4(), 相关参数及返回值为:

      public String libmpecdsaSignRound4(        
              long ctx,          //每个签名者的signCtx       
              String deltaIRec,  //每个签名者接收到的deltaRec, size = singersNum, 同上所描述        
              int[] deltaILength  //deltaRec中的每个delta的长度, size = signersNum, 见上所描述 
           ) 
          // 返回值:decommit
    
    1. 每个签名者分别广播decommit, 在接收到其它signerNum -1 个delta后,将其按照签名者的顺序级联在一起,例如若signers = [0, 2, 3]

      则 decommitRec = decommit_0 || decommit_2 || decommit_3, decommitLength = [decommit_0_length, decommit_2_length, decommit_3_length]

    然后每个签名者分别调用: signRound5 = instance.libmpecdsaSignRound5(), 相关参数及返回值为:

    public String libmpecdsaSignRound5(       
          long ctx,           // 每个签名者的signCtx        
          String decommitRec,   //每个签名者接收到的decommitRec, size = signersNum, 见上所描述        
          int[] decommitLength,  //decommitRec中每个decommit的长度, size = signersNum, 见上所描述        
          int[] rDashProofLength  // 为返回值r, rDash, phase5Proof的长度数组,即rDashProofLength = [r_length, 
                                                          //  rDash_length, phase5Proof_length], size = 3  
         ) 
        //  返回值: r || rDash || phase5Proof
    
    1. 每个签名者分别广播 r, rDash 和 phase5Proof,在接收到其它signerNum - 1个的r, rDash, phase5Proof后,将其分别按照签名者的顺序级联在一起,例如若signers = [0, 2, 3]

      则 rRec = r_0 || r_2 || r_3, rLength = [ r_0_length, r_2_length, r_3_length],

      rDashRec = rDash_0 || rDash_2 || rDash_3,  rDashLength = [ rDash_0_length,  rDash_2_length,  rDash_3_length]
      
      phase5ProofRec = phase5Proof_0 || phase5Proof_2 || phase5Proof_3,   phase5ProofLength = [phase5Proof_0_length, phase5Proof_2_length, phase5Proof_3_length]
      

      注意:需要验证所有的r是相等的, 即 r_0 = r_2 = r_3

    然后每个签名者分别调用:signRound6 = instance.libmpecdsaSignRound6(), 相关参数及返加值为:

    public String libmpecdsaSignRound6(      
         long ctx,      //每个签名者的signCtx      
         String rRec,   //每个签名者接收到的rRec, size = signersNum, 见上所描述      
         int[] rLength,   //rRec中每个r的长度, size = signersNum, 见上所描述         
         String rDashRec,   // 每个签名者接收到的rDashRec, size = signersNum, 见上所描述      
         int[] rDashLength,  // rDashRec中每个rDash中的长茺,size = signersNum, 见上所描述      
         String phase5ProofRec,  // 每个签名者接收到的phase5ProofRec, size = signersNum, 见上所描述      
         int[] phase5ProofLength,  // phase5ProofRec中每个phase5Proof中的长度,size = signersNum,见上所描述      
         int[] sProofTLength     // 为返加值s, homoProof, t 的长度数组,即 sProofTLength = [s_length, homoProof_length, 
                                  // ti_length], size = 3
         ) 
         // 返回值: s || homoProof || ti
    
    

    8.每个签名者分别广播s, homoProof, ti, 然后在接收到其它 signersNum - 1个 s, homoProof, ti后, 将其分别按照签名者顺序级联在一起,例如若signers = [0, 2, 3]

    则 sRec = s_0 || s_2 || s_3, sLength = [s_0_length, s_2_length, s_3_length]

         homoProofRec = homoProof_0 || homoProof_2 || homoProof_3,  则homoProofLength = [homoProof_0_length, homoProof_2_length, homoProof_3_length]
         tiRec = ti_0 || ti_2 || ti_3, tiLength = [ti_0_length, ti_2_length, ti_3_length] 
    

    然后每个签名者调用: signRound7 = instance.libmpecdsaSignRound7(), 相关参数及返回值为:

    public String libmpecdsaSignRound7(     
         long ctx,           //每个签名者的signCtx     
         String sRec,        //每个签名者接收到的sRec, size = signersNum       
         int[] sLength,         //sRec中每个 s 的长度,size = signersNum      
         String homoProofRec,   //每个签名接收到的homoProofRec, size = signersNum      
         int[] homoProofLength,  //homoProofRec中每个homoProof的长度,size = signersNum      
         String tiRec,        //每个签名者接收到的tiRec, size = signersNum      
         int[] tiLength,       //tiRec中每个ti的长度,size = signersNum      
         String messageHash,  //待签名消息的32字节hash值,转换为十六进制后的字符串 
         ) 
         //返加值: sig
    
    1. 每个签名者分别广播sig, 然后在接收到其它signersNum - 1 个 sig 后,将其分别按照签名者顺序级联在一起,例如若signers = [0, 2, 3], 则 localSigRec = sig_0 || sig_2 || sig_3, locoaSigLength = [sig_0_length, sig_2_length, sig_3_length]
    public String libmpecdsaSignRound8(       
          long ctx,           //每个签名者的signCtx       
          String localSigRec,   //每个签名者接收到的localSigRec, size = signersNum        
          int[] localSigLength,  //localSigRec中每个localSig的长度,size = signersNum 
        ) 
        // 返回值为最终生成的签名: signature  
    

    验证阶段

    利用通用ECDSA验证函数即可验证signature。

    参考

    https://github.com/tronprotocol/mp-ecdsa-java-sdk

    https://github.com/tronprotocol/multi-party-ecdsa

    相关文章

      网友评论

          本文标题:mp-ecdsa-java-sdk 手册

          本文链接:https://www.haomeiwen.com/subject/gmeeqdtx.html