对照规范文档7.1 数字签名的验证算法
,先略过B3、B4,这块等后续文章实现了国密SM3算法再补充
# B1-2 检验r及s
B1:检验r′ ∈[1,n-1]
是否成立,若不成立则验证不通过;
B2:检验s′ ∈[1,n-1]
是否成立,若不成立则验证不通过;
if (gm_bn_is_zero(r)
|| gm_bn_cmp(r, GM_BN_N) >= 0
|| gm_bn_is_zero(s)
|| gm_bn_cmp(s, GM_BN_N) >= 0) {
return -1;
}
1
2
3
4
5
6
2
3
4
5
6
# B5 计算t
计算t = (r′ + s′) modn, 若t = 0,则验证不通过
// t = r + s (mod n)
// check t != 0
gm_bn_add(t, r, s, GM_BN_N);
if (gm_bn_is_zero(t)) {
return -1;
}
1
2
3
4
5
6
2
3
4
5
6
# B6 计算椭圆曲线点
计算椭圆曲线点
这里PA即用于验签的公钥,代码中用点P表示,算法中只用到了坐标x,所以只取x的值
// Q = s * G + t * P
gm_point_mul(Q, s, GM_MONT_G);
gm_point_mul(P, t, P);
gm_point_add(Q, Q, P);
gm_point_get_xy(Q, x, NULL);
1
2
3
4
5
2
3
4
5
# B7 计算R
计算
// e = H(M)
// r' = e + x (mod n)
gm_bn_copy(e, dgst);
gm_bn_add(e, e, x, GM_BN_N);
// check if r == r'
if (gm_bn_cmp(e, r) == 0) {
return 1;
} else {
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 完整代码
int gm_do_verify(const gm_point_t *key, const gm_bn_t dgst, const unsigned char *sig) {
gm_point_t _P, *P = &_P;
gm_point_t _Q, *Q = &_Q;
gm_bn_t r;
gm_bn_t s;
gm_bn_t e;
gm_bn_t x;
gm_bn_t t;
if (!key || !dgst || !sig) {
return -1;
}
// parse signature values
gm_bn_from_bytes(r, (const uint8_t *)sig);
gm_bn_from_bytes(s, (const uint8_t *)sig + 32);
if (gm_bn_is_zero(r)
|| gm_bn_cmp(r, GM_BN_N) >= 0
|| gm_bn_is_zero(s)
|| gm_bn_cmp(s, GM_BN_N) >= 0) {
return -1;
}
// parse public key
gm_point_copy(P, key);
// t = r + s (mod n)
// check t != 0
gm_bn_add(t, r, s, GM_BN_N);
if (gm_bn_is_zero(t)) {
return -1;
}
// Q = s * G + t * P
gm_point_mul(Q, s, GM_MONT_G);
gm_point_mul(P, t, P);
gm_point_add(Q, Q, P);
gm_point_get_xy(Q, x, NULL);
// e = H(M)
// r' = e + x (mod n)
gm_bn_copy(e, dgst);
gm_bn_add(e, e, x, GM_BN_N);
// check if r == r'
if (gm_bn_cmp(e, r) == 0) {
return 1;
} else {
return 0;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 单元测试
/**
* 国密SM2单元测试
* @param key_hex 私钥十六进制
* @param pubKey_hex 公钥十六进制
* @param sig_hex 预期结果十六进制
* @param algType 算法,0签名及验签,1仅签名,2仅验签
*/
void test_gm_sv(const char * key_hex, const char * pubKey_hex, const char * sig_hex, int algType) {
unsigned char sig_res[256] = {0};
gm_bn_t testK;
gm_bn_t key;
gm_bn_t dgst;
gm_point_t _P, *P = &_P;
int i, j;
gm_bn_from_hex(testK, key_hex);
gm_bn_from_hex(dgst, key_hex);
gm_bn_from_hex(key, key_hex);
gm_point_from_hex(P, pubKey_hex);
if(algType == 0) { // sign and verify
for (i = 0; i < 1000; i++) {
if (gm_do_sign_for_test(key, dgst, sig_res + 64, testK) != 1) {
printf("gm do sign failed.\n");
}
if (gm_do_verify(P, dgst, sig_res + 64) != 1) {
printf("gm do verify failed.\n");
}
for (j = 0; j < 32; j++) {
sig_res[j] = sig_res[64 + j] ^ sig_res[96 + j];
}
gm_bn_from_bytes(dgst, sig_res);
}
}else if(algType == 1) { // sign only
for (i = 0; i < 1000; i++) {
if (gm_do_sign_for_test(key, dgst, sig_res + 64, testK) != 1) {
printf("gm do sign failed.\n");
}
for (j = 0; j < 32; j++) {
sig_res[j] = sig_res[64 + j] ^ sig_res[96 + j];
}
gm_bn_from_bytes(dgst, sig_res);
}
}else if(algType == 2) { // verify only
gm_bn_from_hex(key, sig_hex);
gm_bn_to_bytes(key, sig_res + 64);
gm_bn_from_hex(key, sig_hex + 64);
gm_bn_to_bytes(key, sig_res + 96);
for (i = 0; i < 1000; i++) {
if (gm_do_verify(P, dgst, sig_res + 64) != 1) {
printf("gm do verify failed.\n");
}
}
}
int k;
for (k = 0; k < 64; k++) {
sprintf(sig_res + k * 2, "%02X", (sig_res[64 + k] & 0x0FF));
}
sig_res[129] = 0;
printf("r = %s\n", sig_res);
printf("test result: %s\n", (strcmp(sig_hex, sig_res) == 0 ? "ok" : "fail"));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
main函数增加:
if(strcmp(argv[1], "gm_sv") == 0) {
test_gm_sv("6B8B4567327B23C6643C98696633487374B0DC5119495CFF2AE8944A625558EC",
"0148E6AF89A0E132E4E7CDA26DF2C2AEB53B741FD00AE85C78CF6EBA13E939B12F58B1E8A661EBF3395459F28945D381259BEEDA76B4886FABF5EE0A55ADEEB2",
"D6125763F2825F35494E930245D064E408553678A200D018E6217975E19EEFE68E48E00F0BF9632826F64F84122627A36F0F998CDB120327F4BC7ABF84E86FE4",
0);
}
if(strcmp(argv[1], "gm_sign") == 0) {
test_gm_sv("6B8B4567327B23C6643C98696633487374B0DC5119495CFF2AE8944A625558EC",
"0148E6AF89A0E132E4E7CDA26DF2C2AEB53B741FD00AE85C78CF6EBA13E939B12F58B1E8A661EBF3395459F28945D381259BEEDA76B4886FABF5EE0A55ADEEB2",
"D6125763F2825F35494E930245D064E408553678A200D018E6217975E19EEFE68E48E00F0BF9632826F64F84122627A36F0F998CDB120327F4BC7ABF84E86FE4",
1);
}
if(strcmp(argv[1], "gm_verify") == 0) {
test_gm_sv("6B8B4567327B23C6643C98696633487374B0DC5119495CFF2AE8944A625558EC",
"0148E6AF89A0E132E4E7CDA26DF2C2AEB53B741FD00AE85C78CF6EBA13E939B12F58B1E8A661EBF3395459F28945D381259BEEDA76B4886FABF5EE0A55ADEEB2",
"6CD42C16BC1C04F94924660BD4260B2229EC5070E954455BA3B80304763E929DB86361E8EAF0497DA53DD2DDE83F6CEA3C2C4838E9D3E29BDB269D9C5BF52976",
2);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
算法效率:
saintdeMacBook-Pro:bn saint$ time ./a.out gm_sv
r = D6125763F2825F35494E930245D064E408553678A200D018E6217975E19EEFE68E48E00F0BF9632826F64F84122627A36F0F998CDB120327F4BC7ABF84E86FE4
test result: ok
real 0m19.420s
user 0m18.444s
sys 0m0.205s
saintdeMacBook-Pro:bn saint$ time ./a.out gm_sign
r = D6125763F2825F35494E930245D064E408553678A200D018E6217975E19EEFE68E48E00F0BF9632826F64F84122627A36F0F998CDB120327F4BC7ABF84E86FE4
test result: ok
real 0m6.728s
user 0m6.574s
sys 0m0.047s
saintdeMacBook-Pro:bn saint$ time ./a.out gm_verify
r = 6CD42C16BC1C04F94924660BD4260B2229EC5070E954455BA3B80304763E929DB86361E8EAF0497DA53DD2DDE83F6CEA3C2C4838E9D3E29BDB269D9C5BF52976
test result: ok
real 0m12.129s
user 0m11.840s
sys 0m0.082s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
签名的效率大约是7ms一次,用在APP客户端完全可以满足性能要求,用户无感知,另外代码无任何依赖,没有大的预计算表,可执行文件大概31KB。
未经本人同意,禁止转载!