(t,n)门限签名:n个参与者,其中至少t+1个参与者一起可以完成签名,少于t(含)个无法签名。
密钥生成阶段
在密钥生成阶段需要n个参与者都参与,每个参与者生成一个私钥sk_i,最终的私钥为所有sk_i之和。
在进行密钥生成之前,需要确定给n个参与者排序,标记为1,2,3,...,n.
下面介绍密钥生成的过程。
- ctx=libmpecdsaKeygenCtxInit(),参数及返回值类型如下:
long libmpecdsaKeygenCtxInit(
int i, //输入参数,参与者的序号, i>=1 && i <=n
int n, //输入参数,参与者总数
int t //输入参数,阈值,在签名阶段>=t+1个参与者才可以完成签名过程。
)
//返回值为ctx,rust指针。
该ctx在后面每一轮调用时都作为参数传入。
- 调用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个参与者的bc
是bc_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
- 每个参与者将第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个参与者。
-
每个参与者在接收到其他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个参与者。
-
每个参与者接收到其他n-1个参与者的
round4Ans
,按照参与者(包括自己)的序号从小到哪的顺序级联在一起组成dlog_proofs
. 每个参与者的round4Ans
的长度按照参与者序号从小到大的顺序存放在dlog_proof_length
数组中。调用round5Ans=libmpecdsaKeygenRound5(),参数及返回值如下
String libmpecdsaKeygenRound5(
long ctx, //输入参数,为第1步生成的ctx
String dlogProofs,//输入参数,见上面描述
int[] dlofProofLength//输入参数,见上面描述
)
//返回值包括公钥、私钥份额等
如果round5Ans=null,协议终止。
- 调用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]等,但所有签名者对签名者的顺序必须达成并保持一致。
- 签名者首先需要进行初始化:
long signCtx1 = instance.libmpecdsaSignCtxInit(N, T);
public long libmpecdsaSignCtxInit(
int n, //密钥生成总人数
int t //门限签名阈值
)
//返回值: sigCtx 指针, 作为后续签名过程中的输入
- 每个签名者分别调用 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.
-
每个签名者分别广播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)
- 签名者之间分别通过点对点通信,相互传输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
-
每个签名者分别广播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
-
每个签名者分别广播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
-
每个签名者分别广播 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
- 每个签名者分别广播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。
网友评论