Files
GmSSL/src/secp256r1.c
Zhi Guan a15e0f34c7 Add ECDSA with curve P-256
for TLS testing
2026-01-24 12:27:12 +08:00

594 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright 2014-2026 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 <stdlib.h>
#include <string.h>
#include <assert.h>
#include <gmssl/bn.h>
#include <gmssl/rand.h>
#include <gmssl/error.h>
#include <gmssl/secp256r1.h>
const secp256r1_t SECP256R1_P = {
0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
0x00000000, 0x00000000, 0x00000001, 0xffffffff,
};
const secp256r1_t SECP256R1_B = {
0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0,
0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8,
};
const secp256r1_t SECP256R1_N = {
0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad,
0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
};
const uint32_t SECP256R1_U_P[9] = {
0x00000003, 0x00000000, 0xffffffff, 0xfffffffe,
0xfffffffe, 0xfffffffe, 0xffffffff, 0x00000000,
0x00000001,
};
const uint32_t SECP256R1_U_N[9] = {
0xeedf9bfe, 0x012ffd85, 0xdf1a6c21, 0x43190552,
0xffffffff, 0xfffffffe, 0xffffffff, 0x00000000,
0x00000001,
};
int secp256r1_is_zero(const secp256r1_t a) {
return bn_is_zero(a, SECP256R1_K);
}
int secp256r1_is_one(const secp256r1_t a) {
return bn_is_one(a, SECP256R1_K);
}
int secp256r1_cmp(const secp256r1_t a, const secp256r1_t b) {
return bn_cmp(a, b, SECP256R1_K);
}
void secp256r1_set_zero(secp256r1_t r) {
bn_set_word(r, 0, SECP256R1_K);
}
void secp256r1_set_one(secp256r1_t r) {
bn_set_word(r, 1, SECP256R1_K);
}
void secp256r1_copy(secp256r1_t r, const secp256r1_t a) {
bn_copy(r, a, SECP256R1_K);
}
void secp256r1_to_32bytes(const secp256r1_t a, uint8_t out[32]) {
bn_to_bytes(a, SECP256R1_K, out);
}
void secp256r1_from_32bytes(secp256r1_t r, const uint8_t in[32]) {
bn_from_bytes(r, SECP256R1_K, in);
}
int secp256r1_print(FILE *fp, int fmt, int ind, const char *label, const secp256r1_t a) {
uint8_t bytes[32];
secp256r1_to_32bytes(a, bytes);
format_bytes(fp, fmt, ind, label, bytes, 32);
return 1;
}
void secp256r1_modp_add(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) {
bn_mod_add(r, a, b, SECP256R1_P, SECP256R1_K);
}
void secp256r1_modp_dbl(secp256r1_t r, const secp256r1_t a) {
bn_mod_add(r, a, a, SECP256R1_P, SECP256R1_K);
}
void secp256r1_modp_tri(secp256r1_t r, const secp256r1_t a) {
secp256r1_t tmp;
// 这里就出错了,真是太奇怪了!
bn_mod_add(tmp, a, a, SECP256R1_P, SECP256R1_K);
bn_mod_add(r, tmp, a, SECP256R1_P, SECP256R1_K);
}
void secp256r1_modp_sub(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) {
bn_mod_sub(r, a, b, SECP256R1_P, SECP256R1_K);
}
void secp256r1_modp_neg(secp256r1_t r, const secp256r1_t a) {
bn_mod_neg(r, a, SECP256R1_P, SECP256R1_K);
}
void secp256r1_modp_haf(secp256r1_t r, const secp256r1_t a) {
int c = 0;
if (a[0] & 1) {
c = bn_add(r, a, SECP256R1_P, SECP256R1_K);
} else {
bn_copy(r, a, SECP256R1_K);
}
r[0] = (r[0] >> 1) | ((r[1] & 1) << 31);
r[1] = (r[1] >> 1) | ((r[2] & 1) << 31);
r[2] = (r[2] >> 1) | ((r[3] & 1) << 31);
r[3] = (r[3] >> 1) | ((r[4] & 1) << 31);
r[4] = (r[4] >> 1) | ((r[5] & 1) << 31);
r[5] = (r[5] >> 1) | ((r[6] & 1) << 31);
r[6] = (r[6] >> 1) | ((r[7] & 1) << 31);
r[7] = (r[7] >> 1) | ((c & 1) << 31);
}
void secp256r1_modp_mul(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) {
uint32_t tmp[6*8 + 4];
bn_barrett_mod_mul(r, a, b, SECP256R1_P, SECP256R1_U_P, tmp, SECP256R1_K);
}
void secp256r1_modp_sqr(secp256r1_t r, const secp256r1_t a) {
uint32_t tmp[6*8 + 4];
bn_barrett_mod_mul(r, a, a, SECP256R1_P, SECP256R1_U_P, tmp, SECP256R1_K);
}
void secp256r1_modp_exp(secp256r1_t r, const secp256r1_t a, const secp256r1_t e) {
uint32_t tmp[7*8 + 4];
bn_barrett_mod_exp(r, a, e, SECP256R1_P, SECP256R1_U_P, tmp, SECP256R1_K);
}
// FIXME: 如果 a = 0 (mod p) 会发生什么
void secp256r1_modp_inv(secp256r1_t r, const secp256r1_t a) {
uint32_t tmp[8*8 + 4];
bn_barrett_mod_inv(r, a, SECP256R1_P, SECP256R1_U_P, tmp, SECP256R1_K);
}
void secp256r1_modn(secp256r1_t r, const secp256r1_t a) {
if (bn_cmp(a, SECP256R1_N, SECP256R1_K) >= 0) {
bn_sub(r, a, SECP256R1_N, SECP256R1_K);
} else {
bn_copy(r, a, SECP256R1_K);
}
}
void secp256r1_modn_add(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) {
bn_mod_add(r, a, b, SECP256R1_N, SECP256R1_K);
}
void secp256r1_modn_dbl(secp256r1_t r, const secp256r1_t a) {
bn_mod_add(r, a, a, SECP256R1_N, SECP256R1_K);
}
void secp256r1_modn_tri(secp256r1_t r, const secp256r1_t a) {
secp256r1_t tmp;
bn_mod_add(tmp, a, a, SECP256R1_N, SECP256R1_K);
bn_mod_add(r, tmp, a, SECP256R1_N, SECP256R1_K);
}
void secp256r1_modn_sub(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) {
bn_mod_sub(r, a, b, SECP256R1_N, SECP256R1_K);
}
void secp256r1_modn_neg(secp256r1_t r, const secp256r1_t a) {
bn_mod_neg(r, a, SECP256R1_N, SECP256R1_K);
}
void secp256r1_modn_mul(secp256r1_t r, const secp256r1_t a, const secp256r1_t b) {
uint32_t tmp[6*8 + 4];
bn_barrett_mod_mul(r, a, b, SECP256R1_N, SECP256R1_U_N, tmp, SECP256R1_K);
}
void secp256r1_modn_sqr(secp256r1_t r, const secp256r1_t a) {
uint32_t tmp[6*8 + 4];
bn_barrett_mod_mul(r, a, a, SECP256R1_N, SECP256R1_U_N, tmp, SECP256R1_K);
}
void secp256r1_modn_exp(secp256r1_t r, const secp256r1_t a, const secp256r1_t e) {
uint32_t tmp[7*8 + 4];
bn_barrett_mod_exp(r, a, e, SECP256R1_N, SECP256R1_U_N, tmp, SECP256R1_K);
}
// FIXME: 如果 a = 0 (mod p) 会发生什么
void secp256r1_modn_inv(secp256r1_t r, const secp256r1_t a) {
uint32_t tmp[8*8 + 4];
bn_barrett_mod_inv(r, a, SECP256R1_N, SECP256R1_U_N, tmp, SECP256R1_K);
}
const SECP256R1_POINT SECP256R1_POINT_G = {
{ 0xd898c296, 0xf4a13945, 0x2deb33a0, 0x77037d81,
0x63a440f2, 0xf8bce6e5, 0xe12c4247, 0x6b17d1f2, },
{ 0x37bf51f5, 0xcbb64068, 0x6b315ece, 0x2bce3357,
0x7c0f9e16, 0x8ee7eb4a, 0xfe1a7f9b, 0x4fe342e2, },
{ 1,0,0,0,0,0,0,0, },
};
void secp256r1_point_set_infinity(SECP256R1_POINT *R)
{
secp256r1_set_one(R->X);
secp256r1_set_one(R->Y);
secp256r1_set_zero(R->Z);
}
int secp256r1_point_is_at_infinity(const SECP256R1_POINT *P)
{
if (secp256r1_is_zero(P->Z)) {
return 1;
}
return 0;
}
int secp256r1_point_is_on_curve(const SECP256R1_POINT *P)
{
secp256r1_t t0;
secp256r1_t t1;
secp256r1_t t2;
if (secp256r1_point_is_at_infinity(P)) {
return 1;
}
// check Y^2 + 3 * X * Z^4 == X^3 + b * Z^6
// t0 = Y^2
secp256r1_modp_sqr(t0, P->Y);
// t1 = Z^2
secp256r1_modp_sqr(t1, P->Z);
// t2 = Z^4
secp256r1_modp_sqr(t2, t1);
// t1 = Z^6
secp256r1_modp_mul(t1, t1, t2);
// t1 = b * Z^6
secp256r1_modp_mul(t1, t1, SECP256R1_B);
// t2 = X * Z^4
secp256r1_modp_mul(t2, t2, P->X);
// t0 = Y^2 + 3 * X * Z^4
secp256r1_modp_add(t0, t0, t2);
secp256r1_modp_add(t0, t0, t2);
secp256r1_modp_add(t0, t0, t2);
// t2 = X^2
secp256r1_modp_sqr(t2, P->X);
// t2 = X^3
secp256r1_modp_mul(t2, t2, P->X);
// t1 = b * Z^6 + X^3
secp256r1_modp_add(t1, t1, t2);
if (secp256r1_cmp(t0, t1) != 0) {
return 0;
}
return 1;
}
void secp256r1_point_copy(SECP256R1_POINT *R, const SECP256R1_POINT *P)
{
secp256r1_copy(R->X, P->X);
secp256r1_copy(R->Y, P->Y);
secp256r1_copy(R->Z, P->Z);
}
int secp256r1_point_set_xy(SECP256R1_POINT *R, const secp256r1_t x, const secp256r1_t y)
{
if (secp256r1_cmp(x, SECP256R1_P) >= 0) {
error_print();
return -1;
}
if (secp256r1_cmp(y, SECP256R1_P) >= 0) {
error_print();
return -1;
}
secp256r1_copy(R->X, x);
secp256r1_copy(R->Y, y);
secp256r1_set_one(R->Z);
if (!secp256r1_point_is_on_curve(R)) {
error_print();
return -1;
}
return 1;
}
int secp256r1_point_get_xy(const SECP256R1_POINT *P, secp256r1_t x, secp256r1_t y)
{
secp256r1_t Z_inv;
if (secp256r1_point_is_at_infinity(P)) {
return 0;
}
secp256r1_modp_inv(Z_inv, P->Z);
secp256r1_modp_mul(y, P->Y, Z_inv);
secp256r1_modp_sqr(Z_inv, Z_inv);
secp256r1_modp_mul(x, P->X, Z_inv);
secp256r1_modp_mul(y, y, Z_inv);
return 1;
}
void secp256r1_point_dbl(SECP256R1_POINT *R, const SECP256R1_POINT *P)
{
/*
secp256r1_t T_0;
secp256r1_t T_1;
secp256r1_t T_2;
secp256r1_t T_3;
secp256r1_t T_4;
if (secp256r1_point_is_at_infinity(P)) {
secp256r1_point_set_infinity(R);
return;
}
secp256r1_modp_sqr(T_0, P->X);
secp256r1_modp_tri(T_0, T_0);
secp256r1_modp_sqr(T_1, T_0);
secp256r1_modp_sqr(T_2, P->Y);
secp256r1_modp_mul(T_3, P->X, T_2);
secp256r1_modp_dbl(T_3, T_3);
secp256r1_modp_dbl(T_3, T_3);
secp256r1_modp_dbl(T_4, T_3);
secp256r1_modp_sub(T_1, T_1, T_4);
secp256r1_modp_sub(T_3, T_3, T_1);
secp256r1_modp_mul(T_0, T_0, T_3);
secp256r1_modp_dbl(T_2, T_2);
secp256r1_modp_sqr(T_2, T_2);
secp256r1_modp_dbl(T_2, T_2);
secp256r1_modp_sub(T_0, T_0, T_2);
secp256r1_modp_mul(T_2, P->Y, P->Z);
secp256r1_modp_dbl(T_2, T_2);
secp256r1_copy(R->X, T_1);
secp256r1_copy(R->Y, T_0);
secp256r1_copy(R->Z, T_2);
*/
const uint32_t *X1 = P->X;
const uint32_t *Y1 = P->Y;
const uint32_t *Z1 = P->Z;
uint32_t *X3 = R->X;
uint32_t *Y3 = R->Y;
uint32_t *Z3 = R->Z;
secp256r1_t S;
secp256r1_t M;
secp256r1_t Zsqr;
secp256r1_t tmp0;
// 1. S = 2Y
secp256r1_modp_dbl(S, Y1);
// 2. Zsqr = Z^2
secp256r1_modp_sqr(Zsqr, Z1);
// 3. S = S^2 = 4Y^2
secp256r1_modp_sqr(S, S);
// 4. Z = Z*Y
secp256r1_modp_mul(Z3, Z1, Y1);
// 5. Z = 2*Z = 2*Y*Z ===> Z3
secp256r1_modp_dbl(Z3, Z3);
// 6. M = X + Zsqr = X + Z^2
secp256r1_modp_add(M, X1, Zsqr);
// 7. Zsqr = X - Zsqr = X - Z^2
secp256r1_modp_sub(Zsqr, X1, Zsqr);
// 8. Y = S^2 = 16Y^4
secp256r1_modp_sqr(Y3, S);
// 9. Y = Y/2 = 8Y^4
secp256r1_modp_haf(Y3, Y3);
// 10. M = M * Zsqr = (X + Z^2)*(X - Z^2) = X^2 - Z^4
secp256r1_modp_mul(M, M, Zsqr);
// 11. M = 3M = 3X^2 - 3Z^4
secp256r1_modp_tri(M, M);
// 12. S = S * X = 4X*Y^2
secp256r1_modp_mul(S, S, X1);
// 13. tmp0 = 2 * S = 8X*Y^2
secp256r1_modp_dbl(tmp0, S);
// 14. X = M^2 = (3X^2 - 3Z^4)^2
secp256r1_modp_sqr(X3, M);
// 15. X = X - tmp0 = (3X^2 - 3Z^4)^2 - 8X*Y^2 ===> X3
secp256r1_modp_sub(X3, X3, tmp0);
// 16. S = S - X3 = 4X*Y^2 - X3
secp256r1_modp_sub(S, S, X3);
// 17. S = S * M = (3X^2 - 3Z^4)*(4X*Y^2 - X3)
secp256r1_modp_mul(S, S, M);
// 18. Y = S - Y = (3X^2 - 3Z^4)*(4X*Y^2 - X3) - 8Y^4 ===> Y3
secp256r1_modp_sub(Y3, S, Y3);
}
void secp256r1_point_add(SECP256R1_POINT *R, const SECP256R1_POINT *P, const SECP256R1_POINT *Q)
{
secp256r1_t T_1;
secp256r1_t T_2;
secp256r1_t T_3;
secp256r1_t T_4;
secp256r1_t T_5;
secp256r1_t T_6;
secp256r1_t T_7;
secp256r1_t T_8;
if (secp256r1_point_is_at_infinity(P)) {
*R = *Q;
return;
}
if (secp256r1_point_is_at_infinity(Q)) {
*R = *P;
return;
}
// 这里的代码是来自zkrypt的不确定是否有问题
secp256r1_modp_sqr(T_1, P->Z); // T_1 = Z_1^2
secp256r1_modp_sqr(T_2, Q->Z); // T_2 = Z_2^2
secp256r1_modp_mul(T_3, Q->X, T_1); // T_3 = X_2 * Z_1^2
secp256r1_modp_mul(T_4, P->X, T_2); // T_4 = X_1 * Z_2^2
secp256r1_modp_add(T_5, T_3, T_4); // T_5 = X_2 * Z_1^2 + X_1 * Z_2^2 = C
secp256r1_modp_sub(T_3, T_3, T_4); // T_3 = X_2 * Z_1^2 - X_1 * Z_2^2 = B
secp256r1_modp_mul(T_1, T_1, P->Z); // T_1 = Z_1^3
secp256r1_modp_mul(T_1, T_1, Q->Y); // T_1 = Y_2 * Z_1^3
secp256r1_modp_mul(T_2, T_2, Q->Z); // T_2 = Z_2^3
secp256r1_modp_mul(T_2, T_2, P->Y); // T_2 = Y_1 * Z_2^3
secp256r1_modp_add(T_6, T_1, T_2); // T_6 = Y_2 * Z_1^3 + Y_1 * Z_2^3 = D
secp256r1_modp_sub(T_1, T_1, T_2); // T_1 = Y_2 * Z_1^3 - Y_1 * Z_2^3 = A
if (secp256r1_is_zero(T_1) && secp256r1_is_zero(T_3)) {
secp256r1_point_dbl(R, P);
return;
}
if (secp256r1_is_one(T_1) && secp256r1_is_zero(T_6)) {
secp256r1_point_set_infinity(R);
return;
}
secp256r1_modp_sqr(T_6, T_1); // T_6 = A^2
secp256r1_modp_mul(T_7, T_3, P->Z); // T_7 = B * Z_1
secp256r1_modp_mul(T_7, T_7, Q->Z); // T_7 = B * Z_1 * Z_2 = Z_3
secp256r1_modp_sqr(T_8, T_3); // T_8 = B^2
secp256r1_modp_mul(T_5, T_5, T_8); // T_5 = B^2 * C
secp256r1_modp_mul(T_3, T_3, T_8); // T_3 = B^3
secp256r1_modp_mul(T_4, T_4, T_8); // T_4 = B^2 * X_1 * Z_2^2
secp256r1_modp_sub(T_6, T_6, T_5); // T_6 = A^2 - B^2 * C = X_3
secp256r1_modp_sub(T_4, T_4, T_6); // T_4 = B^2 * X_1 * Z_2^2 - X_3
secp256r1_modp_mul(T_1, T_1, T_4); // T_1 = A * (B^2 * X_1 * Z_2^2 - X_3)
secp256r1_modp_mul(T_2, T_2, T_3); // T_2 = B^3 * Y_1 * Z_1^3
secp256r1_modp_sub(T_1, T_1, T_2); // T_1 = A * (B^2 * X_1 * Z_2^2 - X_3) - B^3 * Y_1 * Z_1^3 = Y_3
secp256r1_copy(R->X, T_6);
secp256r1_copy(R->Y, T_1);
secp256r1_copy(R->Z, T_7);
}
void secp256r1_point_neg(SECP256R1_POINT *R, const SECP256R1_POINT *P)
{
if (secp256r1_point_is_at_infinity(P)) {
secp256r1_point_set_infinity(R);
return;
}
secp256r1_copy(R->X, P->X);
secp256r1_modp_neg(R->Y, P->Y);
secp256r1_copy(R->Z, P->Z);
}
void secp256r1_point_sub(SECP256R1_POINT *R, const SECP256R1_POINT *P, const SECP256R1_POINT *Q)
{
SECP256R1_POINT T;
secp256r1_point_neg(&T, Q);
secp256r1_point_add(R, P, &T);
}
void secp256r1_point_mul(SECP256R1_POINT *R, const secp256r1_t k, const SECP256R1_POINT *P)
{
uint32_t bits;
int nbits;
int i;
secp256r1_point_set_infinity(R);
for (i = 7; i >= 0; i--) {
bits = k[i];
nbits = 32;
while (nbits-- > 0) {
secp256r1_point_dbl(R, R);
if (bits & 0x80000000) {
secp256r1_point_add(R, R, P);
}
bits <<= 1;
}
}
}
void secp256r1_point_mul_generator(SECP256R1_POINT *R, const secp256r1_t k)
{
secp256r1_point_mul(R, k, &SECP256R1_POINT_G);
}
int secp256r1_point_print(FILE *fp, int fmt, int ind, const char *label, const SECP256R1_POINT *P)
{
uint8_t bytes[32];
format_print(fp, fmt, ind, "%s\n", label);
ind += 4;
secp256r1_to_32bytes(P->X, bytes);
format_bytes(fp, fmt, ind, "X", bytes, 32);
secp256r1_to_32bytes(P->Y, bytes);
format_bytes(fp, fmt, ind, "Y", bytes, 32);
secp256r1_to_32bytes(P->Z, bytes);
format_bytes(fp, fmt, ind, "Z", bytes, 32);
return 1;
}
int secp256r1_point_to_uncompressed_octets(const SECP256R1_POINT *P, uint8_t octets[65])
{
secp256r1_t x;
secp256r1_t y;
if (secp256r1_point_get_xy(P, x, y) != 1) {
error_print();
return -1;
}
octets[0] = 0x04;
secp256r1_to_32bytes(x, octets + 1);
secp256r1_to_32bytes(y, octets + 33);
return 1;
}
int secp256r1_point_from_uncompressed_octets(SECP256R1_POINT *P, const uint8_t octets[65])
{
secp256r1_t x;
secp256r1_t y;
if (octets[0] != 0x04) {
error_print();
return -1;
}
secp256r1_from_32bytes(x, octets + 1);
secp256r1_from_32bytes(y, octets + 33);
if (secp256r1_point_set_xy(P, x, y) != 1) {
error_print();
return -1;
}
return 1;
}
int secp256r1_point_equ(const SECP256R1_POINT *P, const SECP256R1_POINT *Q)
{
uint8_t p_octets[65];
uint8_t q_octets[65];
(void)secp256r1_point_to_uncompressed_octets(P, p_octets);
(void)secp256r1_point_to_uncompressed_octets(Q, q_octets);
if (memcmp(p_octets, q_octets, 65) == 0) {
return 1;
} else {
return 0;
}
}