mp-ecdsa-java-sdk 手册

2022-12-19  本文已影响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

上一篇下一篇

猜你喜欢

热点阅读