1. 引言
Bünz 等人2020年论文《Transparent SNARKs from DARK Compilers》,首次发表于IACR-EUROCRYPT-2020。
代码实现为:https://github.com/ksju6561/Transparent-SNARKs-from-DARK-Compilers
该代码库采用C++基于RSA group做了相应实现,有点小问题,第一次运行需手工创建下文件夹:
mkdir Txt
mkdir record
编译运行:
bash test_script.sh
2. 库依赖及主要结构体
2.1 库依赖
- gmp:全称为GNU Multiple Precision Arithmetic Library,是一个开源的数学运算库,它可以用于任意精度的数学运算,包括有符号整数、有理数和浮点数。它本身并没有精度限制,只取决于机器的硬件情况。
- crypto:即openssl中的crypto库。所用到的一些接口函数有:
–BN_generate_prime_ex
:generate prime numbers larger than the specified bitsize。
–int BN_mul(BIGNUM *r, BIGNUM *a, BIGNUM *b, BN_CTX *ctx);
:multiplies a and b and places the result in r (“r=a*b”). r may be the same BIGNUM as a or b. For multiplication by powers of 2, use bn_lshift(3)。
–BN_num_bits
:计算bit位数。
–BN_rand_range
:从特定范围内选择随机值。
–BN_gcd
:求最大公约数。
–int BN_mod_exp(BIGNUM *r, BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx);
:computes a to the p-th power modulo m (“r=a^p % m”). This function uses less time and space than BN_exp()。
–BN_dec2bn
:将十进制字符串转换为BIGNUM。
–BN_cmp()
: compares the numbers a and b.
–BN_ucmp()
: compares their absolute values.
2.2 主要结构体
typedef struct{
int security_level;
BIGNUM* G;
BIGNUM* g;
BIGNUM* q;
BIGNUM* p;
}_struct_pp_;
typedef struct{
BIGNUM* C;
BIGNUM* Fhat;
}_struct_commit_;
typedef struct{
BIGNUM** Fx;
BIGNUM* input;
int d;
}_struct_poly_;
读取多项式参数的方法为:
int Read_poly(_struct_poly_* poly)
{
FILE *fp;
int i = 0, flag = 1;
unsigned char *str;//[10000] = {0};
str = (unsigned char *)calloc(sizeof(unsigned char),(10000000+2));
fp = fopen("./Txt/poly.txt", "r");
poly->Fx = (BIGNUM**)calloc(sizeof(BIGNUM*), 10000000+2);
while(1){
poly->Fx[i] = BN_new();
fscanf(fp, "%s", str);
i++;
if(feof(fp) != 0)
break;
}
fseek(fp, 0, SEEK_SET );
poly->d = i-1;
i=0;
while(1){
fscanf(fp, "%s", str);
//printf("F[%d] : %s\n", i, str);
flag &= BN_dec2bn(&(poly->Fx[poly->d-i]), str);
i++;
if(feof(fp) != 0)
break;
}
poly->input = BN_new();
fscanf(fp, "%s", str);
flag &= BN_dec2bn(&(poly->input), str);
fclose(fp);
return flag;
}
3. Setup算法
S
e
t
u
p
(
1
λ
)
Setup(1^{\lambda})
Setup(1λ):随机
G
←
G
G
e
n
(
λ
)
\mathbb{G}\leftarrow GGen(\lambda)
G←GGen(λ)和
g
←
G
g\leftarrow \mathbb{G}
g←G。返回
p
p
=
(
λ
,
G
,
g
,
q
)
pp=(\lambda,\mathbb{G},g,q)
pp=(λ,G,g,q)。
参见source/setup.c
。
代码中设置
λ
=
512
\lambda=512
λ=512,多项式的degree
d
d
d 通过参数
D
D
D传入,满足
d
=
2
D
−
1
d=2^{D-1}
d=2D−1,默认
d
=
2
13
d=2^{13}
d=213。
构建的degree为
d
d
d的多项式(其系数默认为
(
1
,
2
,
⋯
,
d
)
(1,2,\cdots,d)
(1,2,⋯,d)):
make_poly((1<<(DD-1)));
int make_poly(int d)
{
BIGNUM* bn_tmp = BN_new();
FILE *fp;
int i = 0, flag = 1;
unsigned char* str;
fp = fopen("./Txt/poly.txt", "w");
for(int i =0; i<d; i++)
{
flag *= BN_set_word(bn_tmp, 1+i); // random
str = BN_bn2dec(bn_tmp);
flag *= fprintf(fp, "%s ", str);
}
fclose(fp);
BN_free(bn_tmp);
return flag;
}
注意,对于RSA group,要求 q > p 2 log 2 ( d + 1 ) + 1 q>p^{2\log_2(d+1)+1} q>p2log2(d+1)+1:
BN_generate_prime_ex(pp,128,1,NULL,NULL,NULL);
BN_set_word(qq,0);
BN_set_bit(qq,128*(2*DD+1));
#define D 14
int DD;
int security_level = 512;
BIGNUM* pk = BN_new();
BIGNUM* g = BN_new();
BIGNUM* q = BN_new();
BIGNUM* p = BN_new();
if(argc == 2)
DD = atoi(argv[1]);
else
DD = D;
KeyGen_RSAsetup(pk, NULL, g, q, p, security_level);
int KeyGen_RSAsetup( BIGNUM *pk, BIGNUM *sk, BIGNUM *g, BIGNUM *qq, BIGNUM *pp, const int k)
{
BIGNUM* one = BN_new();
BIGNUM* p = BN_new();
BIGNUM* q = BN_new();
BIGNUM* tmp = BN_new();
BN_CTX* ctx = BN_CTX_new();
do{
BN_generate_prime_ex(p,(k>>1),1,NULL,NULL,NULL);
BN_generate_prime_ex(q,(k>>1),1,NULL,NULL,NULL);
BN_mul(pk,p,q, ctx);
}while(BN_num_bits(pk) != k);
//printf("%d\n", BN_num_bits(pk));
if(sk != NULL){
BN_sub_word(p,1);
BN_sub_word(q,1);
BN_mul(sk,p,q,ctx);
}
BN_set_word(one,1);
do{
BN_rand_range(g, pk);
BN_gcd(tmp, g, pk, ctx);
}while(BN_cmp(tmp,one) != 0);
BN_generate_prime_ex(pp,128,1,NULL,NULL,NULL);
BN_set_word(qq,0);
BN_set_bit(qq,128*(2*DD+1));
BN_free(p);
BN_free(q);
BN_free(one);
BN_free(tmp);
BN_CTX_free(ctx);
return 1;
}
4. commit算法
C
o
m
m
i
t
(
p
p
;
f
(
X
)
∈
Z
p
[
X
]
)
Commit(pp;f(X)\in\mathbb{Z}_p[X])
Commit(pp;f(X)∈Zp[X]):计算
C
←
g
f
^
(
q
)
C\leftarrow g^{\hat{f}(q)}
C←gf^(q),返回
(
C
;
f
^
(
X
)
)
(C;\hat{f}(X))
(C;f^(X))。
参见source/commit.c
代码。
Read_pp( &pp ); //读取pp参数
Read_poly(&poly);//读取多项式系数
_struct_commit_ cm;
cm.C = BN_new();
cm.Fhat = BN_new();
commit_new(&cm, pp, poly);
// 计算 C ← g f ^ ( q ) C\leftarrow g^{\hat{f}(q)} C←gf^(q)
int commit_new(_struct_commit_* cm, const _struct_pp_ pp, const _struct_poly_ poly)
{
int flag = 1, i = 0;
BN_CTX* ctx = BN_CTX_new();
BIGNUM* bn_tmp1 = BN_new();
BIGNUM* bn_tmp2 = BN_new();
BN_set_word(bn_tmp1,1);
BN_set_word(bn_tmp2,0);
BN_set_word(cm->Fhat,0);
BN_set_word(cm->C,1);
for(i = poly.d; i >= 0; i--)
{
BN_mod_exp( cm->C, cm->C, pp.q, pp.G, ctx);
BN_mod_exp( bn_tmp1, pp.g, poly.Fx[i], pp.G, ctx);
BN_mod_mul( cm->C, cm->C, bn_tmp1, pp.G, ctx);
}
BN_CTX_free(ctx);
BN_free(bn_tmp1);
BN_free(bn_tmp2);
return flag;
}
5. Evaluation protocol
- Prover的工作参见
source/eval_prover.c
; - Verifier的工作参见
source/eval_verifier.c
。
5.1 Evaluation protocol 的 Prover 部分
- 读取多项式系数,将所有系数范围调整至 [ − p − 1 2 , p − 1 2 ] [-\frac{p-1}{2},\frac{p-1}{2}] [−2p−1,2p−1]
BN_copy(C, cm->C);
BN_copy(p, pp->p);
BN_sub_word(p,1);
BN_rshift1(p,p); //此时p=(p-1)/2
// 这段代码在将系数限定在 [ − p − 1 2 , p − 1 2 ] [-\frac{p-1}{2},\frac{p-1}{2}] [−2p−1,2p−1]是有问题的。。。
BN_set_word(zero,0);
BN_set_word(y,0);
BN_set_word(z,100);
BN_set_word(z_tmp, 1);
i=0;
do{
//BN_mod_inverse(poly->Fx[i], poly->Fx[i], pp->p, ctx);
i++;
}while(i<= poly->d);
i = 0;
do{
BN_mod_mul(zero, poly->Fx[i], z_tmp, pp->p, ctx);
BN_mod_add(y, y, zero, pp->p, ctx);
BN_mod_mul(z_tmp,z_tmp,z, pp->p, ctx);
i++;
}while(i<= poly->d);
- EvalBounded中Prover的部分:
– 若多项式degree d d d为0,直接将常量值 f 0 f_0 f0发送给Verifier:
if(poly->d == 0)
{
Write_proof(NULL, poly->Fx[0]);
}
– 当
d
+
1
d+1
d+1为奇数时:
else if( ((1+poly->d)%2) == 1 )
{
printf("d+1 is odd [d : %d -> d' : %d]\n", poly->d, poly->d + 1);
TimerOn();
BN_mod_exp(*C,*C,pp->q,pp->G,ctx); // C' = C^q
BN_mod_mul(*y,*y,z,pp->p,ctx); // y=y*z mod p
BN_set_word(y_tmp, poly->d);
BN_mul(*b, *b, y_tmp, ctx); // b = bd
poly->d = poly->d + 1; //d = d + 1
if( poly->Fx[poly->d] == NULL)
poly->Fx[poly->d] = BN_new();
for(int i = poly->d-1; i >= 0; i--){// f'(X) = Xf(X);
BN_copy(poly->Fx[i+1], poly->Fx[i]);
}
BN_set_word(poly->Fx[0],0);
RunTime_eval += TimerOff();
EvalBounded(pp, C, z, y, b, poly);
}
–
d
≥
1
d\geq1
d≥1且
d
+
1
d+1
d+1为偶数:
5.2 Evaluation protocol 的 Verifier 部分
- EvalBounded中Verifier的部分:
Spd(spd, pp->p, poly->d);
int Spd(BIGNUM* output, BIGNUM* p, unsigned int d)
{
BN_CTX* ctx = BN_CTX_new();
BIGNUM* bn_tmp = BN_new();
int nbit = 0;
d++;
for(nbit=0; d != 0; (d >>= 1), nbit++);
//printf("%d\n", nbit);
BN_set_word(bn_tmp, nbit);
BN_exp(output, p, bn_tmp, ctx);
//printf("Spd : %s\n", BN_bn2hex(output));
BN_CTX_free(ctx);
BN_free(bn_tmp);
return 1;
}
if(poly->d == 0)
{
TimerOn();
fscanf(fp, "%s", buffer);
BN_hex2bn(&poly->Fx[0], buffer);
RunTime_file_IO += TimerOff();
TimerOn();
BN_mul(z_tmp, *b, spd, ctx);
if(BN_cmp(*b, pp->q) != -1 || BN_cmp(spd, pp->q) != -1){ // 步骤3
printf("bounded fail!! [ b * spd > q]\n");
flag = 0;
}
if(BN_cmp(poly->Fx[0], *b) != -1){ // 步骤4
printf("bounded fail!! [ |f| > b ]\n");
printf("f : %s\n", BN_bn2hex(poly->Fx[0]));
printf("b : %s\n", BN_bn2hex(*b));
flag = 0;
}
BN_mod(z_tmp, *y, pp->p, ctx);
BN_mod(y_tmp, poly->Fx[0], pp->p, ctx);
if(BN_cmp(z_tmp, y_tmp) != 0){ // 步骤5
printf("ERROR : f mod p != y mod p\n");
printf("f : %s\n", BN_bn2hex(y_tmp));
printf("y : %s\n", BN_bn2hex(z_tmp));
flag = 0;
}
BN_mod_exp(z_tmp, pp->g, poly->Fx[0],pp->G, ctx);
if(BN_cmp(z_tmp, *C) != 0){ // 步骤6
printf("ERROR : g^f != C\n");
printf("g^f : %s\n", BN_bn2hex(z_tmp));
printf(" C : %s\n", BN_bn2hex(*C));
flag = 0;
}
RunTime_eval += TimerOff();
if( flag == 1 ) // 步骤7
printf("Verify Success!!\n");
else
printf("Verify Fail.....\n");
}
参考资料
[1] Openssl 接口函数