Files
GmSSL/src/sm2_recover.c
Zhi Guan 8a0a23f91d Add SM2 AlgorithmIdentifier option
Add option in CMake to support NULL parameters encoding
2023-02-09 11:44:27 +08:00

139 lines
3.1 KiB
C

/*
* Copyright 2014-2022 The GmSSL Project. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
*
* http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <gmssl/sm2.h>
#include <gmssl/error.h>
extern SM2_BN SM2_P;
extern SM2_BN SM2_B;
extern SM2_BN SM2_N;
extern SM2_BN SM2_THREE;
// r = H(Z||M) + x1 (mod n)
// x1 = r - H(Z||M) (mod n) or (r - H(Z||M) (mod n)) + n
// y1 = sqrt(x1^3 + a*x1 + b)
// R = (x1, y1) or (x1, -y1)
// P = (r + s)^-1 * R - (r + s)^-1 * s * G
int sm2_signature_to_public_key_points(const SM2_SIGNATURE *sig, const uint8_t dgst[32],
SM2_POINT points[4], size_t *points_cnt)
{
SM2_BN SM2_P_SUB_N;
SM2_JACOBIAN_POINT P;
SM2_JACOBIAN_POINT R;
SM2_Fp r;
SM2_Fp s;
SM2_Fp e;
SM2_Fn u;
SM2_Fn v;
SM2_Fp x1;
SM2_Fp y1;
// FIXME: check r, s
sm2_bn_from_bytes(r, sig->r);
sm2_bn_from_bytes(s, sig->s);
// u = (r + s)^-1, v = -(r + s)^-1 * s
sm2_fn_add(u, r, s);
sm2_fn_inv(u, u);
sm2_fn_mul(v, u, s);
sm2_fn_neg(v, v);
// e = H(Z||M) (mod n)
sm2_bn_from_bytes(e, dgst);
if (sm2_bn_cmp(e, SM2_N) >= 0) {
sm2_bn_sub(e, e, SM2_N);
}
// x1 = r - e (mod n)
sm2_fn_sub(x1, r, e);
// y1 = sqrt(x1^3 + a*x + b) = sqrt((x1^2 + a)*x1 + b)
sm2_fp_sqr(y1, x1);
sm2_fp_sub(y1, y1, SM2_THREE);
sm2_fp_mul(y1, y1, x1);
sm2_fp_add(y1, y1, SM2_B);
if (sm2_fp_sqrt(y1, y1) != 1) {
error_print();
return -1;
}
sm2_jacobian_point_set_xy(&R, x1, y1);
// P = u * R + v * G
sm2_jacobian_point_mul_sum(&P, u, &R, v);
sm2_jacobian_point_to_bytes(&P, (uint8_t *)&points[0]);
// P' = u * (-R) + v * G
sm2_jacobian_point_neg(&R, &R);
sm2_jacobian_point_mul_sum(&P, u, &R, v);
sm2_jacobian_point_to_bytes(&P, (uint8_t *)&points[1]);
*points_cnt = 2;
// if x1 in [n, p-1], x1 (mod n) in [0, p-n-1]
// ==> if x1 (mod n) in [0, p-n-1], x1 == (x1 (mod n) + n) (mod p)
sm2_bn_sub(SM2_P_SUB_N, SM2_P, SM2_N);
if (sm2_bn_cmp(x1, SM2_P_SUB_N) < 0) {
// x1' = x1 (mod n) + n
sm2_bn_add(x1, x1, SM2_N);
// y1' = sqrt(x1'^3 + a*x' + b)
sm2_fp_sqr(y1, x1);
sm2_fp_sub(y1, y1, SM2_THREE);
sm2_fp_mul(y1, y1, x1);
sm2_fp_add(y1, y1, SM2_B);
if (sm2_fp_sqrt(y1, y1) != 1) {
error_print();
return -1;
}
sm2_jacobian_point_set_xy(&R, x1, y1);
// P = u * R + v * G
sm2_jacobian_point_mul_sum(&P, u, &R, v);
sm2_jacobian_point_to_bytes(&P, (uint8_t *)&points[2]);
// P' = u * (-R) + v * G
sm2_jacobian_point_neg(&R, &R);
sm2_jacobian_point_mul_sum(&P, u, &R, v);
sm2_jacobian_point_to_bytes(&P, (uint8_t *)&points[3]);
*points_cnt = 4;
}
return 1;
}
// verify the xR of R = s * G + (s + r) * P
// so (-r, -s) is also a valid SM2 signature
int sm2_signature_conjugate(const SM2_SIGNATURE *sig, SM2_SIGNATURE *new_sig)
{
SM2_Fn r;
SM2_Fn s;
// FIXME: check r,s
sm2_bn_from_bytes(r, sig->r);
sm2_bn_from_bytes(s, sig->s);
sm2_fn_neg(r, r);
sm2_fn_neg(s, s);
sm2_bn_to_bytes(r, new_sig->r);
sm2_bn_to_bytes(s, new_sig->s);
return 1;
}
// TODO: Add API to support sig,siglen