2023-06-17 10:33:38

by GUO Zihua

[permalink] [raw]
Subject: [RFC PATCH 0/3] crypto: Introduce SM9 key exchange

ID-based key exchange algorithms provides the capability of using a
human-readable ID as the public key and generate corresponding private
key base on that ID. With a pre-defined pattern, the ID could be
generated with openly known knowledge of the opponent, eliminating the
need of a certificate and avoiding the whole verification chain.

Instead of CAs, ID-based crypto algorithm relies on a KGC (Key
Generation Center) for generating and distrubuting of private keys.
Unlike CAs, KGC is not directly involved in any of the crypto
procedures.

SM9 is an ID-based crypto algorithm within the ShangMi family. The key
exchange part of it was accepted in ISO/IEC 11770-3:2021. This patchset
introduces key exchange capability of SM9.

ID-based crypto algorithms are widely accepted as the next gen
asymmetric cryptography for various fileds including telecommunication,
emails, IoT etc..

You can find the technical details in the last two patch.

v4:
Fixed typo in commit message; Marked non-exported function as static.

v3:
Fixed memleaks.

v2:
Updated the identification of initiator, changed function name for
getting sk; Split the patchset into 3 patches in order to ease code
review.

GUO Zihua (3):
MPI: Export mpi_add_ui and mpi_mod for SM9
crypto: Introduce SM9 key exchange algorithm library
crypto: Introduce SM9 key exchange algorithm

crypto/Kconfig | 15 +
crypto/Makefile | 4 +
crypto/sm9.c | 916 ++++++++++++++++++++++++++
crypto/sm9_lib.c | 1584 +++++++++++++++++++++++++++++++++++++++++++++
crypto/sm9_lib.h | 92 +++
lib/mpi/mpi-add.c | 2 +-
lib/mpi/mpi-mod.c | 1 +
7 files changed, 2613 insertions(+), 1 deletion(-)
create mode 100644 crypto/sm9.c
create mode 100644 crypto/sm9_lib.c
create mode 100644 crypto/sm9_lib.h

--
2.17.1



2023-06-17 10:33:38

by GUO Zihua

[permalink] [raw]
Subject: [RFC PATCH 1/3] MPI: Export mpi_add_ui and mpi_mod for SM9

SM9 which could be built as a module would be using mpi_add_ui and mpi_mod.
So export them.

Signed-off-by: GUO Zihua <[email protected]>
---
lib/mpi/mpi-add.c | 2 +-
lib/mpi/mpi-mod.c | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/mpi/mpi-add.c b/lib/mpi/mpi-add.c
index 9056fc5167fc..d34c6c1c6fab 100644
--- a/lib/mpi/mpi-add.c
+++ b/lib/mpi/mpi-add.c
@@ -62,7 +62,7 @@ void mpi_add_ui(MPI w, MPI u, unsigned long v)
w->nlimbs = wsize;
w->sign = wsign;
}
-
+EXPORT_SYMBOL_GPL(mpi_add_ui);

void mpi_add(MPI w, MPI u, MPI v)
{
diff --git a/lib/mpi/mpi-mod.c b/lib/mpi/mpi-mod.c
index 54fcc01564d9..8136f4aff287 100644
--- a/lib/mpi/mpi-mod.c
+++ b/lib/mpi/mpi-mod.c
@@ -26,6 +26,7 @@ void mpi_mod(MPI rem, MPI dividend, MPI divisor)
{
mpi_fdiv_r(rem, dividend, divisor);
}
+EXPORT_SYMBOL_GPL(mpi_mod);

/* This function returns a new context for Barrett based operations on
* the modulus M. This context needs to be released using
--
2.17.1


2023-06-17 10:33:38

by GUO Zihua

[permalink] [raw]
Subject: [RFC PATCH 2/3] crypto: Introduce SM9 key exchange algorithm library

This commit introduces library for SM9 (ShangMi9) key exchange crypto
algorithm.

SM9 is an ID-based crypto algorithm providing asymmetric encryption,
signature and key exchange capability. Within which, the key exchange
algorithm has been accepted in ISO/IEC 11770-3:2021 international
standard.

sm9_lib.c contains mathematical algorithms used by SM9 key exchange
algorithm.

References:
http://c.gb688.cn/bzgk/gb/showGb?type=online&hcno=B7A0D7DFF411CD0AAE76135ADE91886A
http://c.gb688.cn/bzgk/gb/showGb?type=online&hcno=02A8E87248BD500747D2CD484C034EB0
https://github.com/guanzhi/GmSSL

Co-developed-by: LI Shiya <[email protected]>
Signed-off-by: GUO Zihua <[email protected]>
---
crypto/sm9_lib.c | 1584 ++++++++++++++++++++++++++++++++++++++++++++++
crypto/sm9_lib.h | 92 +++
2 files changed, 1676 insertions(+)
create mode 100644 crypto/sm9_lib.c
create mode 100644 crypto/sm9_lib.h

diff --git a/crypto/sm9_lib.c b/crypto/sm9_lib.c
new file mode 100644
index 000000000000..7f8545c9e640
--- /dev/null
+++ b/crypto/sm9_lib.c
@@ -0,0 +1,1584 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Libraries for SM9 key exchange algorithm
+ *
+ * Copyright (c) 2023, Huawei Technology Co., Ltd.
+ * Authors: GUO Zihua <[email protected]>
+ */
+
+#include <linux/module.h>
+#include <linux/mpi.h>
+#include <linux/string.h>
+#include <crypto/sm9.h>
+
+#include "sm9_lib.h"
+
+unsigned int mpi_dump_to_buf(MPI a, u8 *buf, unsigned int expected_size)
+{
+ unsigned int written_size;
+ u8 *mpi_buf;
+
+ if (expected_size < mpi_get_size(a))
+ return 0;
+
+ mpi_buf = mpi_get_buffer(a, &written_size, NULL);
+ if (!mpi_buf)
+ return 0;
+ memcpy(buf + (expected_size - written_size), mpi_buf, expected_size);
+ kfree(mpi_buf);
+ return expected_size;
+}
+
+int mpi_point_jacobian_to_affine(MPI_POINT out, MPI_POINT p, MPI q)
+{
+ MPI z, _q;
+ int rc = -ENOMEM;
+
+ if (!out)
+ return -EINVAL;
+
+ z = mpi_new(0);
+ _q = mpi_new(0);
+ if (!z || !_q)
+ goto out_free;
+
+ mpi_sub_ui(_q, q, 3);
+ mpi_powm(z, p->z, _q, q);
+ mpi_mulm(out->x, p->x, z, q);
+
+ mpi_sub_ui(_q, q, 4);
+ mpi_powm(z, p->z, _q, q);
+ mpi_mulm(out->y, p->y, z, q);
+
+ mpi_set_ui(out->z, 1);
+ rc = 0;
+
+out_free:
+ mpi_free(z);
+ mpi_free(_q);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(mpi_point_jacobian_to_affine);
+
+int mpi_point_export(MPI_POINT P, u8 *buf, size_t size)
+{
+ unsigned int nbytes, x_size;
+ int rc;
+
+ if (size < max(mpi_get_size(P->x), mpi_get_size(P->y)) * 2)
+ return -EINVAL;
+
+ x_size = size / 2;
+ rc = mpi_read_buffer(P->x, buf, x_size, &nbytes, NULL);
+ if (rc)
+ return nbytes;
+
+ rc = mpi_read_buffer(P->y, buf + x_size, x_size, &nbytes, NULL);
+ if (rc)
+ return nbytes;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mpi_point_export);
+
+int mpi_point_from_buf(MPI_POINT P, const u8 *buf, size_t size)
+{
+ size_t x_size;
+ MPI x, y;
+
+ if (size % 2)
+ return -EINVAL;
+
+ x_size = size / 2;
+ x = mpi_read_raw_data(buf, x_size);
+ y = mpi_read_raw_data(buf + x_size, x_size);
+ if (!x || !y) {
+ mpi_free(x);
+ mpi_free(y);
+ return -ENOMEM;
+ }
+
+ mpi_set(P->x, x);
+ mpi_set(P->y, y);
+ mpi_set_ui(P->z, 1);
+
+ mpi_free(x);
+ mpi_free(y);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mpi_point_from_buf);
+
+static void mpi_div2m(MPI out, MPI a, MPI q)
+{
+ mpi_set(out, a);
+
+ if (mpi_test_bit(a, 0))
+ mpi_add(out, out, q);
+ mpi_rshift(out, out, 1);
+ mpi_mod(out, out, q);
+}
+
+static bool sm9_dim_eq(SM9_DIM_FQ2 a, SM9_DIM_FQ2 b)
+{
+ return !(mpi_cmp(a[0], b[0]) && mpi_cmp(a[1], b[1]));
+}
+
+int sm9_dim_init(SM9_DIM_FQ2 dim, unsigned int nbits)
+{
+ if (!dim)
+ return -EINVAL;
+
+ dim[0] = mpi_new(nbits);
+ dim[1] = mpi_new(nbits);
+ if (!dim[0] || !dim[1])
+ return -ENOMEM;
+ return 0;
+}
+
+static int sm9_dim_init_from_buf(SM9_DIM_FQ2 dim, const u8 *buf, size_t size)
+{
+ size_t d_size;
+
+ if (size % 2)
+ return -EINVAL;
+
+ d_size = size / 2;
+ dim[1] = mpi_read_raw_data(buf, d_size);
+ dim[0] = mpi_read_raw_data(buf + d_size, d_size);
+ return 0;
+}
+
+void sm9_dim_deinit(SM9_DIM_FQ2 dim)
+{
+ mpi_free(dim[0]);
+ mpi_free(dim[1]);
+}
+
+void sm9_dim_free(SM9_DIM_FQ2 *dim)
+{
+ if (!dim)
+ return;
+
+ sm9_dim_deinit(*dim);
+ kfree(dim);
+}
+
+SM9_DIM_FQ2 *sm9_dim_alloc(unsigned int nbits)
+{
+ SM9_DIM_FQ2 *res;
+
+ res = kzalloc(sizeof(SM9_DIM_FQ2), GFP_KERNEL);
+ if (!res)
+ return NULL;
+
+ if (sm9_dim_init(*res, nbits)) {
+ kfree(res);
+ res = NULL;
+ }
+ return res;
+}
+
+int sm9_dim_set(SM9_DIM_FQ2 a, SM9_DIM_FQ2 b)
+{
+ mpi_set(a[0], b[0]);
+ mpi_set(a[1], b[1]);
+ return 0;
+}
+
+int sm9_dim_clear(SM9_DIM_FQ2 a)
+{
+ memzero_explicit(a[0]->d, a[0]->alloced * BYTES_PER_MPI_LIMB);
+ mpi_clear(a[0]);
+ memzero_explicit(a[1]->d, a[1]->alloced * BYTES_PER_MPI_LIMB);
+ mpi_clear(a[1]);
+ return 0;
+}
+
+static int sm9_dim_mulm(SM9_DIM_FQ2 out, SM9_DIM_FQ2 _a, SM9_DIM_FQ2 _b, MPI q)
+{
+ MPI tmp;
+ SM9_DIM_FQ2 a, b;
+ int rc;
+
+ if (!out)
+ return -EINVAL;
+
+ tmp = mpi_new(0);
+ if (!tmp)
+ return -ENOMEM;
+
+ rc = sm9_dim_init(a, 0);
+ rc |= sm9_dim_init(b, 0);
+ if (rc)
+ goto out_free;
+ sm9_dim_set(a, _a);
+ sm9_dim_set(b, _b);
+
+ mpi_mulm(out[0], a[0], b[0], q);
+ mpi_mulm(tmp, a[1], b[1], q);
+ mpi_addm(tmp, tmp, tmp, q);
+ mpi_subm(out[0], out[0], tmp, q);
+
+ mpi_mulm(out[1], a[0], b[1], q);
+ mpi_mulm(tmp, a[1], b[0], q);
+ mpi_addm(out[1], out[1], tmp, q);
+
+out_free:
+ sm9_dim_deinit(a);
+ sm9_dim_deinit(b);
+ mpi_free(tmp);
+ return rc;
+}
+
+static int sm9_dim_mulm_u(SM9_DIM_FQ2 out, SM9_DIM_FQ2 _a, SM9_DIM_FQ2 _b,
+ MPI q)
+{
+ MPI tmp;
+ SM9_DIM_FQ2 a, b;
+ int rc;
+
+ if (!out)
+ return -EINVAL;
+
+ tmp = mpi_new(0);
+ if (!tmp)
+ return -ENOMEM;
+
+ rc = sm9_dim_init(a, 0);
+ rc |= sm9_dim_init(b, 0);
+ if (rc)
+ goto out_free;
+ sm9_dim_set(a, _a);
+ sm9_dim_set(b, _b);
+
+ mpi_mulm(out[0], a[0], b[1], q);
+ mpi_mulm(tmp, a[1], b[0], q);
+ mpi_addm(out[0], out[0], tmp, q);
+ mpi_addm(out[0], out[0], out[0], q);
+ mpi_subm(out[0], q, out[0], q);
+
+ mpi_mulm(out[1], a[0], b[0], q);
+ mpi_mulm(tmp, a[1], b[1], q);
+ mpi_addm(tmp, tmp, tmp, q);
+ mpi_subm(out[1], out[1], tmp, q);
+
+out_free:
+ sm9_dim_deinit(a);
+ sm9_dim_deinit(b);
+ mpi_free(tmp);
+ return 0;
+}
+
+static int sm9_dim_mulm_mpi(SM9_DIM_FQ2 out, SM9_DIM_FQ2 P, MPI a, MPI q)
+{
+ mpi_mulm(out[0], P[0], a, q);
+ mpi_mulm(out[1], P[1], a, q);
+ return 0;
+}
+
+static int sm9_dim_mulm_ui(SM9_DIM_FQ2 out, SM9_DIM_FQ2 P, unsigned int a,
+ MPI q)
+{
+ int rc;
+ MPI p = mpi_new(0);
+
+ if (!p)
+ return -ENOMEM;
+
+ mpi_set_ui(p, a);
+ rc = sm9_dim_mulm_mpi(out, P, p, q);
+ mpi_free(p);
+ return rc;
+}
+
+static int sm9_dim_subm(SM9_DIM_FQ2 out, SM9_DIM_FQ2 a, SM9_DIM_FQ2 b, MPI q)
+{
+ if (!out)
+ return -EINVAL;
+
+ mpi_subm(out[0], a[0], b[0], q);
+ mpi_subm(out[1], a[1], b[1], q);
+ return 0;
+}
+
+static int sm9_dim_addm(SM9_DIM_FQ2 out, SM9_DIM_FQ2 a, SM9_DIM_FQ2 b, MPI q)
+{
+ if (!out)
+ return -EINVAL;
+
+ mpi_addm(out[0], a[0], b[0], q);
+ mpi_addm(out[1], a[1], b[1], q);
+ return 0;
+}
+
+static int sm9_dim_negm(SM9_DIM_FQ2 out, SM9_DIM_FQ2 a, MPI q)
+{
+ if (!out)
+ return -EINVAL;
+
+ mpi_subm(out[0], q, a[0], q);
+ mpi_subm(out[1], q, a[1], q);
+ return 0;
+}
+
+static int sm9_dim_div2m(SM9_DIM_FQ2 out, SM9_DIM_FQ2 a, MPI q)
+{
+ if (!out)
+ return -EINVAL;
+
+ mpi_div2m(out[0], a[0], q);
+ mpi_div2m(out[1], a[1], q);
+ return 0;
+}
+
+static int sm9_dim_conjugate(SM9_DIM_FQ2 out, SM9_DIM_FQ2 a, MPI q)
+{
+ if (!out)
+ return -EINVAL;
+
+ mpi_set(out[0], a[0]);
+ mpi_subm(out[1], q, a[1], q);
+ return 0;
+}
+
+static int sm9_dim_copy(SM9_DIM_FQ2 out, SM9_DIM_FQ2 a)
+{
+ if (!out)
+ return -EINVAL;
+
+ mpi_set(out[0], a[0]);
+ mpi_set(out[1], a[1]);
+ return 0;
+}
+
+static int sm9_dim_is_zero(SM9_DIM_FQ2 a)
+{
+ return !(mpi_cmp_ui(a[0], 0) || mpi_cmp_ui(a[1], 0));
+}
+
+static int sm9_dim_invm(SM9_DIM_FQ2 out, SM9_DIM_FQ2 a, MPI q, MPI q_minus_2)
+{
+ MPI t0, t1;
+
+ if (!out)
+ return -EINVAL;
+
+ if (!mpi_cmp_ui(a[0], 0)) {
+ mpi_clear(out[0]);
+ mpi_addm(out[1], a[1], a[1], q);
+ mpi_powm(out[1], out[1], q_minus_2, q);
+ mpi_subm(out[1], q, out[1], q);
+ } else if (!mpi_cmp_ui(a[1], 0)) {
+ mpi_clear(out[1]);
+ mpi_powm(out[0], q_minus_2, a[0], q);
+ } else {
+ t0 = mpi_new(0);
+ t1 = mpi_new(0);
+ if (!t0 || !t1) {
+ mpi_free(t0);
+ mpi_free(t1);
+ return -ENOMEM;
+ }
+
+ mpi_mulm(t0, a[0], a[0], q);
+ mpi_mulm(t1, a[1], a[1], q);
+ mpi_addm(t1, t1, t1, q);
+ mpi_addm(t0, t0, t1, q);
+ mpi_powm(t0, t0, q_minus_2, q);
+
+ mpi_mulm(out[0], a[0], t0, q);
+ mpi_mulm(out[1], a[1], t0, q);
+ mpi_subm(out[1], q, out[1], q);
+
+ mpi_free(t0);
+ mpi_free(t1);
+ }
+ return 0;
+}
+
+static size_t sm9_dim_get_size(SM9_DIM_FQ2 a)
+{
+ size_t size;
+
+ size = mpi_get_size(a[0]);
+ size += mpi_get_size(a[1]);
+ return size;
+}
+
+static ssize_t sm9_dim_to_buf_rev(SM9_DIM_FQ2 a, char *buf, size_t size)
+{
+ unsigned int d_size = size / 2, written_size;
+
+ written_size = mpi_dump_to_buf(a[1], buf, d_size);
+ if (written_size != d_size)
+ return -ENOMEM;
+
+ written_size = mpi_dump_to_buf(a[0], buf + d_size, d_size);
+ if (written_size != d_size)
+ return -ENOMEM;
+ return size;
+}
+
+static int sm9_point_copy(SM9_POINT out, SM9_POINT p)
+{
+ if (!out)
+ return -EINVAL;
+
+ if (out == p)
+ return 0;
+
+ mpi_set(out->xd1, p->xd1);
+ mpi_set(out->xd2, p->xd2);
+ mpi_set(out->yd1, p->yd1);
+ mpi_set(out->yd2, p->yd2);
+ mpi_set(out->zd1, p->zd1);
+ mpi_set(out->zd2, p->zd2);
+ return 0;
+}
+
+void sm9_point_release(SM9_POINT P)
+{
+ if (!P)
+ return;
+
+ sm9_dim_deinit(P->x_fq2);
+ sm9_dim_deinit(P->y_fq2);
+ sm9_dim_deinit(P->z_fq2);
+ kfree(P);
+}
+
+SM9_POINT sm9_point_new(unsigned int nbits)
+{
+ SM9_POINT res;
+
+ res = kzalloc(sizeof(struct sm9_point_fq2), GFP_KERNEL);
+ if (!res)
+ return NULL;
+
+ if (sm9_dim_init(res->x_fq2, nbits) ||
+ sm9_dim_init(res->y_fq2, nbits) ||
+ sm9_dim_init(res->z_fq2, nbits)) {
+ sm9_point_release(res);
+ return NULL;
+ }
+ return res;
+}
+
+SM9_POINT sm9_point_from_buf(const u8 *buf, size_t size)
+{
+ SM9_POINT res;
+ size_t x_size;
+ int rc;
+
+ res = kzalloc(sizeof(struct sm9_point_fq2), GFP_KERNEL);
+ if (!res)
+ return NULL;
+
+ x_size = size / 2;
+ rc = sm9_dim_init_from_buf(res->x_fq2, buf, x_size);
+ if (rc) {
+ kfree(res);
+ return NULL;
+ }
+
+ rc = sm9_dim_init_from_buf(res->y_fq2, buf + x_size, x_size);
+ if (rc) {
+ sm9_dim_deinit(res->x_fq2);
+ kfree(res);
+ return NULL;
+ }
+
+ rc = sm9_dim_init(res->z_fq2, 0);
+ if (rc) {
+ sm9_dim_deinit(res->x_fq2);
+ sm9_dim_deinit(res->y_fq2);
+ kfree(res);
+ }
+ mpi_set_ui(res->zd1, 1);
+ return res;
+}
+EXPORT_SYMBOL_GPL(sm9_point_from_buf);
+
+static bool sm9_point_is_infinity(SM9_POINT p)
+{
+ return !(mpi_cmp_ui(p->zd1, 0) && mpi_cmp_ui(p->zd2, 0));
+}
+
+bool sm9_point_valid(SM9_POINT P, struct sm9_ctx *ctx)
+{
+ SM9_DIM_FQ2 x, y;
+ SM9_POINT Q;
+ MPI q = ctx->sys_cfg->q;
+ bool rc;
+
+ if (sm9_dim_init(x, 0) || sm9_dim_init(y, 0)) {
+ sm9_dim_deinit(x);
+ sm9_dim_deinit(y);
+ return false;
+ }
+
+ sm9_dim_mulm(x, P->x_fq2, P->x_fq2, q);
+ sm9_dim_mulm(x, x, P->x_fq2, q);
+ mpi_addm(x[0], x[0], ctx->sys_cfg->b, q);
+
+ sm9_dim_mulm(y, P->y_fq2, P->y_fq2, q);
+ if (!sm9_dim_eq(x, y)) {
+ sm9_dim_deinit(x);
+ sm9_dim_deinit(y);
+ return false;
+ }
+
+ Q = sm9_point_new(0);
+ if (!Q) {
+ sm9_dim_deinit(x);
+ sm9_dim_deinit(y);
+ return false;
+ }
+ sm9_point_mpi_mulm(Q, P, ctx->sys_cfg->q, ctx);
+ rc = sm9_point_is_infinity(Q);
+
+ sm9_dim_deinit(x);
+ sm9_dim_deinit(y);
+ sm9_point_release(Q);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(sm9_point_valid);
+
+static int sm9_point_addm_same(SM9_POINT out, SM9_POINT _P, struct sm9_ctx *ctx)
+{
+ SM9_DIM_FQ2 x2, x4, y2, y4, tmp;
+ SM9_POINT P;
+ MPI q = ctx->sys_cfg->q;
+ int rc;
+
+ rc = sm9_dim_init(x2, 0);
+ rc |= sm9_dim_init(x4, 0);
+ rc |= sm9_dim_init(y2, 0);
+ rc |= sm9_dim_init(y4, 0);
+ rc |= sm9_dim_init(tmp, 0);
+ if (rc)
+ goto out_free;
+
+ P = sm9_point_new(0);
+ if (!P)
+ goto out_free;
+ sm9_point_copy(P, _P);
+
+ sm9_dim_mulm(x2, P->x_fq2, P->x_fq2, q);
+ sm9_dim_mulm(x4, x2, x2, q);
+ sm9_dim_mulm(y2, P->y_fq2, P->y_fq2, q);
+ sm9_dim_mulm(y4, y2, y2, q);
+
+ /* x3 = 9 * x1^4 - 8 * x1 * y1^2 */
+ sm9_dim_mulm_ui(out->x_fq2, x4, 9, q);
+ sm9_dim_mulm(tmp, P->x_fq2, y2, q);
+ sm9_dim_mulm_ui(tmp, tmp, 8, q);
+ sm9_dim_subm(out->x_fq2, out->x_fq2, tmp, q);
+
+ /* y3 = 3 * x1^2 * (4 * x1 * y1^2 - x3) - 8 * y1^4 */
+ sm9_dim_mulm(out->y_fq2, P->x_fq2, y2, q);
+ sm9_dim_mulm_ui(out->y_fq2, out->y_fq2, 4, q);
+ sm9_dim_subm(out->y_fq2, out->y_fq2, out->x_fq2, q);
+ sm9_dim_mulm(out->y_fq2, out->y_fq2, x2, q);
+ sm9_dim_mulm_ui(out->y_fq2, out->y_fq2, 3, q);
+ sm9_dim_mulm_ui(tmp, y4, 8, q);
+ sm9_dim_subm(out->y_fq2, out->y_fq2, tmp, q);
+
+ /* z3 = 2 * y1 * z1 */
+ sm9_dim_mulm(out->z_fq2, P->y_fq2, P->z_fq2, q);
+ sm9_dim_mulm_ui(out->z_fq2, out->z_fq2, 2, q);
+
+ rc = 0;
+out_free:
+ sm9_dim_deinit(x2);
+ sm9_dim_deinit(x4);
+ sm9_dim_deinit(y2);
+ sm9_dim_deinit(y4);
+ sm9_dim_deinit(tmp);
+ sm9_point_release(P);
+ return rc;
+}
+
+static int sm9_point_addm_diff(SM9_POINT out, SM9_POINT _P, SM9_POINT _Q,
+ struct sm9_ctx *ctx)
+{
+ SM9_DIM_FQ2 u1, u2, s1, s2, h, h2, h3, r, tmp;
+ SM9_POINT P, Q;
+ MPI q = ctx->sys_cfg->q;
+ int rc;
+
+ rc = sm9_dim_init(u1, 0);
+ rc |= sm9_dim_init(u2, 0);
+ rc |= sm9_dim_init(s1, 0);
+ rc |= sm9_dim_init(s2, 0);
+ rc |= sm9_dim_init(h, 0);
+ rc |= sm9_dim_init(h2, 0);
+ rc |= sm9_dim_init(h3, 0);
+ rc |= sm9_dim_init(r, 0);
+ rc |= sm9_dim_init(tmp, 0);
+ if (rc)
+ goto out_free;
+
+ P = sm9_point_new(0);
+ Q = sm9_point_new(0);
+ if (!Q || !P)
+ goto out_free_point;
+ sm9_point_copy(P, _P);
+ sm9_point_copy(Q, _Q);
+
+ /* u1 = x1 * z2^2 */
+ sm9_dim_mulm(u1, Q->z_fq2, Q->z_fq2, q);
+ sm9_dim_mulm(u1, P->x_fq2, u1, q);
+ /* u2 = x2 * z1^2 */
+ sm9_dim_mulm(u2, P->z_fq2, P->z_fq2, q);
+ sm9_dim_mulm(u2, Q->x_fq2, u2, q);
+ /* s1 = y1 * z2^3 */
+ sm9_dim_mulm(s1, Q->z_fq2, Q->z_fq2, q);
+ sm9_dim_mulm(s1, s1, Q->z_fq2, q);
+ sm9_dim_mulm(s1, P->y_fq2, s1, q);
+ /* s2 = y2 * z1^3 */
+ sm9_dim_mulm(s2, P->z_fq2, P->z_fq2, q);
+ sm9_dim_mulm(s2, s2, P->z_fq2, q);
+ sm9_dim_mulm(s2, Q->y_fq2, s2, q);
+ /* h = u2 - u1 */
+ sm9_dim_subm(h, u2, u1, q);
+ /* r = s2 - s1 */
+ sm9_dim_subm(r, s2, s1, q);
+
+ /* x3 = r^2 - h^3 - 2 * u1 * h^2 */
+ sm9_dim_mulm(out->x_fq2, r, r, q);
+ sm9_dim_mulm(out->x_fq2, r, r, q);
+ sm9_dim_mulm(h2, h, h, q);
+ sm9_dim_mulm(h3, h2, h, q);
+ sm9_dim_subm(out->x_fq2, out->x_fq2, h3, q);
+ sm9_dim_mulm(tmp, u1, h2, q);
+ sm9_dim_mulm_ui(tmp, tmp, 2, q);
+ sm9_dim_subm(out->x_fq2, out->x_fq2, tmp, q);
+
+ /* y3 = r * (u1 * h^2 - x3) - s1 * h^3 */
+ sm9_dim_mulm(out->y_fq2, u1, h2, q);
+ sm9_dim_subm(out->y_fq2, out->y_fq2, out->x_fq2, q);
+ sm9_dim_mulm(out->y_fq2, r, out->y_fq2, q);
+ sm9_dim_mulm(tmp, s1, h3, q);
+ sm9_dim_subm(out->y_fq2, out->y_fq2, tmp, q);
+
+ /* z3 = z1 * z2 * h */
+ sm9_dim_mulm(out->z_fq2, P->z_fq2, Q->z_fq2, q);
+ sm9_dim_mulm(out->z_fq2, out->z_fq2, h, q);
+
+ rc = 0;
+out_free_point:
+ sm9_point_release(P);
+ sm9_point_release(Q);
+out_free:
+ sm9_dim_deinit(u1);
+ sm9_dim_deinit(u2);
+ sm9_dim_deinit(s1);
+ sm9_dim_deinit(s2);
+ sm9_dim_deinit(h);
+ sm9_dim_deinit(h2);
+ sm9_dim_deinit(h3);
+ sm9_dim_deinit(r);
+ sm9_dim_deinit(tmp);
+ return rc;
+}
+
+static int sm9_point_same(SM9_POINT a, SM9_POINT b)
+{
+ if (a == b)
+ return 1;
+
+ if (!mpi_cmp(a->xd1, b->xd1) && !mpi_cmp(a->xd2, b->xd2) &&
+ !mpi_cmp(a->yd1, b->yd1) && !mpi_cmp(a->yd2, b->yd2) &&
+ !mpi_cmp(a->zd1, b->zd1) && !mpi_cmp(a->zd2, b->zd2))
+ return 1;
+ return 0;
+}
+
+int sm9_point_addm(SM9_POINT out, SM9_POINT P, SM9_POINT Q, struct sm9_ctx *ctx)
+{
+ if (!out)
+ return -EINVAL;
+
+ if (sm9_dim_is_zero(P->z_fq2)) {
+ sm9_point_copy(out, Q);
+ return 0;
+ } else if (sm9_dim_is_zero(Q->z_fq2)) {
+ sm9_point_copy(out, P);
+ return 0;
+ }
+
+ if (sm9_point_same(P, Q))
+ return sm9_point_addm_same(out, P, ctx);
+ return sm9_point_addm_diff(out, P, Q, ctx);
+}
+EXPORT_SYMBOL_GPL(sm9_point_addm);
+
+int sm9_point_mpi_mulm(SM9_POINT out, SM9_POINT _P, MPI a, struct sm9_ctx *ctx)
+{
+ SM9_POINT P;
+ int i;
+
+ if (!out)
+ return -EINVAL;
+
+ P = sm9_point_new(0);
+ if (!P)
+ return -ENOMEM;
+ mpi_set_ui(P->xd1, 1);
+ mpi_set_ui(P->yd1, 1);
+ mpi_set_ui(P->zd1, 0);
+
+ for (i = mpi_get_nbits(a) - 1; i >= 0; i--) {
+ sm9_point_addm(P, P, P, ctx);
+ if (mpi_test_bit(a, i))
+ sm9_point_addm(P, P, _P, ctx);
+ }
+ sm9_point_copy(out, P);
+ sm9_point_release(P);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sm9_point_mpi_mulm);
+
+int sm9_point_mpi_addm(SM9_POINT out, SM9_POINT P, MPI a, MPI q)
+{
+ if (!out)
+ return -EINVAL;
+
+ mpi_addm(out->xd1, P->xd1, a, q);
+ mpi_addm(out->yd1, P->yd1, a, q);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sm9_point_mpi_addm);
+
+void sm9_point_clear(SM9_POINT p)
+{
+ sm9_dim_clear(p->x_fq2);
+ sm9_dim_clear(p->y_fq2);
+ sm9_dim_clear(p->z_fq2);
+}
+EXPORT_SYMBOL_GPL(sm9_point_clear);
+
+int sm9_dim_fq4_set(SM9_DIM_FQ4 a, SM9_DIM_FQ4 b)
+{
+ sm9_dim_set(a[0], b[0]);
+ sm9_dim_set(a[1], b[1]);
+ return 0;
+}
+
+void sm9_dim_fq4_deinit(SM9_DIM_FQ4 p)
+{
+ sm9_dim_deinit(p[0]);
+ sm9_dim_deinit(p[1]);
+}
+
+int sm9_dim_fq4_init(SM9_DIM_FQ4 p, unsigned int nbits)
+{
+ int i, rc;
+
+ if (!p)
+ return -EINVAL;
+
+ for (i = 0; i < 2; i++) {
+ rc = sm9_dim_init(p[i], 0);
+ if (rc) {
+ sm9_dim_fq4_deinit(p);
+ return rc;
+ }
+ }
+ return 0;
+}
+
+int sm9_dim_fq4_clear(SM9_DIM_FQ4 p)
+{
+ sm9_dim_clear(p[0]);
+ sm9_dim_clear(p[1]);
+ return 0;
+}
+
+static int sm9_dim_fq4_mulm(SM9_DIM_FQ4 out, SM9_DIM_FQ4 _a, SM9_DIM_FQ4 _b,
+ struct sm9_ctx *ctx)
+{
+ SM9_DIM_FQ2 tmp;
+ SM9_DIM_FQ4 a, b;
+ MPI q = ctx->sys_cfg->q;
+ int rc;
+
+ rc = sm9_dim_init(tmp, 0);
+ rc |= sm9_dim_fq4_init(a, 0);
+ rc |= sm9_dim_fq4_init(b, 0);
+ if (rc)
+ goto out_free;
+ sm9_dim_fq4_set(a, _a);
+ sm9_dim_fq4_set(b, _b);
+
+ sm9_dim_mulm(out[0], a[0], b[0], q);
+ sm9_dim_mulm_u(tmp, a[1], b[1], q);
+ sm9_dim_addm(out[0], out[0], tmp, q);
+
+ sm9_dim_mulm(out[1], a[0], b[1], q);
+ sm9_dim_mulm(tmp, a[1], b[0], q);
+ sm9_dim_addm(out[1], out[1], tmp, q);
+
+out_free:
+ sm9_dim_fq4_deinit(a);
+ sm9_dim_fq4_deinit(b);
+ sm9_dim_deinit(tmp);
+ return rc;
+}
+
+static int sm9_dim_fq4_mulm_mpi(SM9_DIM_FQ4 out, SM9_DIM_FQ4 a, MPI b,
+ struct sm9_ctx *ctx)
+{
+ sm9_dim_mulm_mpi(out[0], a[0], b, ctx->sys_cfg->q);
+ sm9_dim_mulm_mpi(out[1], a[1], b, ctx->sys_cfg->q);
+ return 0;
+}
+
+static int sm9_dim_fq4_mulm_v(SM9_DIM_FQ4 out, SM9_DIM_FQ4 _a, SM9_DIM_FQ4 _b,
+ struct sm9_ctx *ctx)
+{
+ SM9_DIM_FQ2 tmp;
+ SM9_DIM_FQ4 a, b;
+ MPI q = ctx->sys_cfg->q;
+ int rc;
+
+ rc = sm9_dim_init(tmp, 0);
+ rc |= sm9_dim_fq4_init(a, 0);
+ rc |= sm9_dim_fq4_init(b, 0);
+ if (rc)
+ goto out_free;
+ sm9_dim_fq4_set(a, _a);
+ sm9_dim_fq4_set(b, _b);
+
+ sm9_dim_mulm_u(out[0], a[1], b[0], q);
+ sm9_dim_mulm_u(tmp, a[0], b[1], q);
+ sm9_dim_addm(out[0], out[0], tmp, q);
+
+ sm9_dim_mulm(out[1], a[0], b[0], q);
+ sm9_dim_mulm_u(tmp, a[1], b[1], q);
+ sm9_dim_addm(out[1], out[1], tmp, q);
+
+out_free:
+ sm9_dim_fq4_deinit(a);
+ sm9_dim_fq4_deinit(b);
+ sm9_dim_deinit(tmp);
+ return 0;
+}
+
+static int sm9_dim_fq4_addm(SM9_DIM_FQ4 out, SM9_DIM_FQ4 a, SM9_DIM_FQ4 b,
+ struct sm9_ctx *ctx)
+{
+ MPI q = ctx->sys_cfg->q;
+
+ sm9_dim_addm(out[0], a[0], b[0], q);
+ sm9_dim_addm(out[1], a[1], b[1], q);
+
+ return 0;
+}
+
+static int sm9_dim_fq4_subm(SM9_DIM_FQ4 out, SM9_DIM_FQ4 a, SM9_DIM_FQ4 b,
+ struct sm9_ctx *ctx)
+{
+ sm9_dim_subm(out[0], a[0], b[0], ctx->sys_cfg->q);
+ sm9_dim_subm(out[1], a[1], b[1], ctx->sys_cfg->q);
+ return 0;
+}
+
+static int sm9_dim_fq4_invm(SM9_DIM_FQ4 out, SM9_DIM_FQ4 a, struct sm9_ctx *ctx)
+{
+ SM9_DIM_FQ2 t0, t1, t2;
+ MPI q = ctx->sys_cfg->q;
+
+ if (sm9_dim_init(t0, 0) || sm9_dim_init(t1, 0) || sm9_dim_init(t2, 0)) {
+ sm9_dim_deinit(t0);
+ sm9_dim_deinit(t1);
+ sm9_dim_deinit(t2);
+ return -ENOMEM;
+ }
+
+ sm9_dim_mulm_u(t2, a[1], a[1], q);
+ sm9_dim_mulm(t0, a[0], a[0], q);
+ sm9_dim_subm(t2, t2, t0, q);
+ sm9_dim_invm(t2, t2, q, ctx->sys_cfg->q_minus_2);
+
+ sm9_dim_mulm(t0, a[0], t2, q);
+ sm9_dim_negm(out[0], t0, q);
+
+ sm9_dim_mulm(out[1], a[1], t2, q);
+
+ sm9_dim_deinit(t0);
+ sm9_dim_deinit(t1);
+ sm9_dim_deinit(t2);
+ return 0;
+}
+
+static int sm9_dim_fq4_is_zero(SM9_DIM_FQ4 a)
+{
+ return sm9_dim_is_zero(a[0]) && sm9_dim_is_zero(a[1]);
+}
+
+static int sm9_dim_fq4_negm(SM9_DIM_FQ4 out, SM9_DIM_FQ4 a, struct sm9_ctx *ctx)
+{
+ sm9_dim_negm(out[0], a[0], ctx->sys_cfg->q);
+ sm9_dim_negm(out[1], a[1], ctx->sys_cfg->q);
+ return 0;
+}
+
+static int sm9_dim_fq4_conjugate(SM9_DIM_FQ4 out, SM9_DIM_FQ4 a,
+ struct sm9_ctx *ctx)
+{
+ sm9_dim_set(out[0], a[0]);
+ sm9_dim_negm(out[1], a[1], ctx->sys_cfg->q);
+ return 0;
+}
+
+static size_t sm9_dim_fq4_get_size(SM9_DIM_FQ4 a)
+{
+ size_t size;
+
+ size = sm9_dim_get_size(a[0]);
+ size += sm9_dim_get_size(a[1]);
+ return size;
+}
+
+static ssize_t sm9_dim_fq4_to_buf_rev(SM9_DIM_FQ4 a, char *buf, size_t size)
+{
+ ssize_t d_size = size / 2, written_size;
+
+ written_size = sm9_dim_to_buf_rev(a[1], buf, d_size);
+ if (written_size < 0)
+ return written_size;
+
+ written_size = sm9_dim_to_buf_rev(a[0], buf + d_size, d_size);
+ if (written_size < 0)
+ return written_size;
+ return size;
+}
+
+int sm9_dim_fq12_set(SM9_DIM_FQ12 a, SM9_DIM_FQ12 b)
+{
+ sm9_dim_fq4_set(a[0], b[0]);
+ sm9_dim_fq4_set(a[1], b[1]);
+ sm9_dim_fq4_set(a[2], b[2]);
+ return 0;
+}
+
+void sm9_dim_fq12_deinit(SM9_DIM_FQ12 d)
+{
+ sm9_dim_fq4_deinit(d[0]);
+ sm9_dim_fq4_deinit(d[1]);
+ sm9_dim_fq4_deinit(d[2]);
+}
+
+int sm9_dim_fq12_init(SM9_DIM_FQ12 d, unsigned int nbits)
+{
+ int rc = 0, i, j;
+
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 2; j++)
+ sm9_dim_init(d[i][j], nbits);
+ }
+ return rc;
+}
+
+int sm9_dim_fq12_clear(SM9_DIM_FQ12 d)
+{
+ int i, j;
+
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 2; j++)
+ sm9_dim_clear(d[i][j]);
+ }
+ return 0;
+}
+
+static int sm9_dim_fq12_mulm(SM9_DIM_FQ12 out, SM9_DIM_FQ12 _a, SM9_DIM_FQ12 _b,
+ struct sm9_ctx *ctx)
+{
+ SM9_DIM_FQ4 tmp;
+ SM9_DIM_FQ12 a, b;
+ int rc;
+
+ rc = sm9_dim_fq4_init(tmp, 0);
+ rc |= sm9_dim_fq12_init(a, 0);
+ rc |= sm9_dim_fq12_init(b, 0);
+ if (rc)
+ goto out_free;
+ sm9_dim_fq12_set(a, _a);
+ sm9_dim_fq12_set(b, _b);
+
+ sm9_dim_fq4_mulm(out[0], a[0], b[0], ctx);
+ sm9_dim_fq4_mulm_v(tmp, a[1], b[2], ctx);
+ sm9_dim_fq4_addm(out[0], out[0], tmp, ctx);
+ sm9_dim_fq4_mulm_v(tmp, a[2], b[1], ctx);
+ sm9_dim_fq4_addm(out[0], out[0], tmp, ctx);
+
+ sm9_dim_fq4_mulm(out[1], a[0], b[1], ctx);
+ sm9_dim_fq4_mulm(tmp, a[1], b[0], ctx);
+ sm9_dim_fq4_addm(out[1], out[1], tmp, ctx);
+ sm9_dim_fq4_mulm_v(tmp, a[2], b[2], ctx);
+ sm9_dim_fq4_addm(out[1], out[1], tmp, ctx);
+
+ sm9_dim_fq4_mulm(out[2], a[0], b[2], ctx);
+ sm9_dim_fq4_mulm(tmp, a[1], b[1], ctx);
+ sm9_dim_fq4_addm(out[2], out[2], tmp, ctx);
+ sm9_dim_fq4_mulm(tmp, a[2], b[0], ctx);
+ sm9_dim_fq4_addm(out[2], out[2], tmp, ctx);
+
+out_free:
+ sm9_dim_fq12_deinit(a);
+ sm9_dim_fq12_deinit(b);
+ sm9_dim_fq4_deinit(tmp);
+ return rc;
+}
+
+int sm9_dim_fq12_powm(SM9_DIM_FQ12 out, SM9_DIM_FQ12 a, MPI b,
+ struct sm9_ctx *ctx)
+{
+ int i;
+ SM9_DIM_FQ12 tmp;
+ int rc = -EINVAL;
+
+ rc = sm9_dim_fq12_init(tmp, 0);
+ if (rc)
+ return -ENOMEM;
+ mpi_set_ui(tmp[0][0][0], 1);
+
+ for (i = mpi_get_nbits(b); i >= 0; i--) {
+ sm9_dim_fq12_mulm(tmp, tmp, tmp, ctx);
+ if (mpi_test_bit(b, i))
+ sm9_dim_fq12_mulm(tmp, a, tmp, ctx);
+ }
+ sm9_dim_fq12_set(out, tmp);
+
+ sm9_dim_fq12_deinit(tmp);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(sm9_dim_fq12_powm);
+
+static int sm9_dim_fq12_powm_ui(SM9_DIM_FQ12 out, SM9_DIM_FQ12 a,
+ unsigned int b, struct sm9_ctx *ctx)
+{
+ MPI i = NULL;
+ int rc;
+
+ i = mpi_new(0);
+ if (!i)
+ return -ENOMEM;
+
+ mpi_set_ui(i, b);
+ rc = sm9_dim_fq12_powm(out, a, i, ctx);
+ mpi_free(i);
+ return rc;
+}
+
+static int sm9_dim_fq12_invm(SM9_DIM_FQ12 out, SM9_DIM_FQ12 _a,
+ struct sm9_ctx *ctx)
+{
+ SM9_DIM_FQ4 t0, t1, t2, t3;
+ SM9_DIM_FQ12 a;
+ int rc;
+
+ rc = sm9_dim_fq4_init(t0, 0);
+ rc |= sm9_dim_fq4_init(t1, 0);
+ rc |= sm9_dim_fq4_init(t2, 0);
+ rc |= sm9_dim_fq4_init(t3, 0);
+ rc |= sm9_dim_fq12_init(a, 0);
+ if (rc)
+ goto out_free;
+ sm9_dim_fq12_set(a, _a);
+
+ if (sm9_dim_fq4_is_zero(a[2])) {
+ sm9_dim_fq4_mulm(t0, a[0], a[0], ctx);
+ sm9_dim_fq4_mulm(t0, t0, a[0], ctx);
+ sm9_dim_fq4_mulm_v(t1, a[1], a[1], ctx);
+ sm9_dim_fq4_mulm(t1, t1, a[1], ctx);
+ sm9_dim_fq4_addm(t0, t0, t1, ctx);
+ sm9_dim_fq4_invm(t0, t0, ctx);
+
+ sm9_dim_fq4_mulm(out[2], a[1], a[1], ctx);
+ sm9_dim_fq4_mulm(out[2], out[2], t0, ctx);
+
+ sm9_dim_fq4_mulm(out[1], a[0], a[1], ctx);
+ sm9_dim_fq4_mulm(out[1], out[1], t0, ctx);
+ sm9_dim_fq4_negm(out[1], out[1], ctx);
+
+ sm9_dim_fq4_mulm(out[0], a[0], a[0], ctx);
+ sm9_dim_fq4_mulm(out[0], out[0], t0, ctx);
+ rc = 0;
+ goto out_free;
+ }
+
+ sm9_dim_fq4_mulm(t0, a[1], a[1], ctx);
+ sm9_dim_fq4_mulm(t1, a[0], a[2], ctx);
+ sm9_dim_fq4_subm(t0, t0, t1, ctx);
+
+ sm9_dim_fq4_mulm(t1, a[0], a[1], ctx);
+ sm9_dim_fq4_mulm_v(t2, a[2], a[2], ctx);
+ sm9_dim_fq4_subm(t1, t1, t2, ctx);
+
+ sm9_dim_fq4_mulm(t2, a[0], a[0], ctx);
+ sm9_dim_fq4_mulm_v(t3, a[1], a[2], ctx);
+ sm9_dim_fq4_subm(t2, t2, t3, ctx);
+
+ sm9_dim_fq4_mulm(t3, t1, t1, ctx);
+ sm9_dim_fq4_mulm(out[0], t0, t2, ctx);
+ sm9_dim_fq4_subm(t3, t3, out[0], ctx);
+ sm9_dim_fq4_invm(t3, t3, ctx);
+ sm9_dim_fq4_mulm(t3, a[2], t3, ctx);
+
+ sm9_dim_fq4_mulm(out[0], t2, t3, ctx);
+ sm9_dim_fq4_mulm(out[1], t1, t3, ctx);
+ sm9_dim_fq4_negm(out[1], out[1], ctx);
+ sm9_dim_fq4_mulm(out[2], t0, t3, ctx);
+
+ rc = 0;
+out_free:
+ sm9_dim_fq12_deinit(a);
+ sm9_dim_fq4_deinit(t0);
+ sm9_dim_fq4_deinit(t1);
+ sm9_dim_fq4_deinit(t2);
+ sm9_dim_fq4_deinit(t3);
+ return rc;
+}
+
+size_t sm9_dim_fq12_get_size(SM9_DIM_FQ12 a)
+{
+ size_t size;
+
+ size = sm9_dim_fq4_get_size(a[0]);
+ size += sm9_dim_fq4_get_size(a[1]);
+ size += sm9_dim_fq4_get_size(a[2]);
+ return size;
+}
+EXPORT_SYMBOL_GPL(sm9_dim_fq12_get_size);
+
+ssize_t sm9_dim_fq12_to_buf_rev(SM9_DIM_FQ12 a, char *buf, size_t size)
+{
+ ssize_t d_size = size / 3, written_size;
+
+ if (size % 3)
+ return -EINVAL;
+
+ written_size = sm9_dim_fq4_to_buf_rev(a[2], buf, d_size);
+ if (written_size < 0)
+ return written_size;
+
+ written_size = sm9_dim_fq4_to_buf_rev(a[1], buf + d_size, d_size);
+ if (written_size < 0)
+ return written_size;
+
+ written_size = sm9_dim_fq4_to_buf_rev(a[0], buf + 2 * d_size, d_size);
+ if (written_size < 0)
+ return written_size;
+ return size;
+}
+EXPORT_SYMBOL_GPL(sm9_dim_fq12_to_buf_rev);
+
+static int sm9_dim_fq12_frobenius_6(SM9_DIM_FQ12 out, SM9_DIM_FQ12 a,
+ struct sm9_ctx *ctx)
+{
+ sm9_dim_fq4_conjugate(out[0], a[0], ctx);
+ sm9_dim_fq4_conjugate(out[1], a[1], ctx);
+ sm9_dim_fq4_negm(out[1], out[1], ctx);
+ sm9_dim_fq4_conjugate(out[2], a[2], ctx);
+ return 0;
+}
+
+static int sm9_dim_fq12_frobenius_3(SM9_DIM_FQ12 out, SM9_DIM_FQ12 a,
+ struct sm9_ctx *ctx)
+{
+ MPI q = ctx->sys_cfg->q;
+ SM9_DIM_FQ2 beta;
+
+ if (sm9_dim_init(beta, 0))
+ return -ENOMEM;
+
+ mpi_set(beta[0], ctx->sys_cfg->beta);
+
+ sm9_dim_conjugate(out[0][0], a[0][0], q);
+ sm9_dim_conjugate(out[0][1], a[0][1], q);
+ sm9_dim_mulm(out[0][1], out[0][1], beta, q);
+ sm9_dim_negm(out[0][1], out[0][1], q);
+
+ sm9_dim_conjugate(out[1][0], a[1][0], q);
+ sm9_dim_mulm(out[1][0], out[1][0], beta, q);
+ sm9_dim_conjugate(out[1][1], a[1][1], q);
+
+ sm9_dim_conjugate(out[2][0], a[2][0], q);
+ sm9_dim_negm(out[2][0], out[2][0], q);
+ sm9_dim_conjugate(out[2][1], a[2][1], q);
+ sm9_dim_mulm(out[2][1], out[2][1], beta, q);
+
+ sm9_dim_deinit(beta);
+ return 0;
+}
+
+static int sm9_dim_fq12_frobenius_2(SM9_DIM_FQ12 out, SM9_DIM_FQ12 a,
+ struct sm9_ctx *ctx)
+{
+ sm9_dim_fq4_conjugate(out[0], a[0], ctx);
+ sm9_dim_fq4_conjugate(out[1], a[1], ctx);
+ sm9_dim_fq4_mulm_mpi(out[1], out[1], ctx->sys_cfg->alpha2, ctx);
+ sm9_dim_fq4_conjugate(out[2], a[2], ctx);
+ sm9_dim_fq4_mulm_mpi(out[2], out[2], ctx->sys_cfg->alpha4, ctx);
+ return 0;
+}
+
+static int sm9_dim_fq12_frobenius(SM9_DIM_FQ12 out, SM9_DIM_FQ12 a,
+ struct sm9_ctx *ctx)
+{
+ MPI q = ctx->sys_cfg->q;
+
+ sm9_dim_conjugate(out[0][0], a[0][0], q);
+ sm9_dim_conjugate(out[0][1], a[0][1], q);
+ sm9_dim_mulm_mpi(out[0][1], out[0][1], ctx->sys_cfg->alpha3, q);
+
+ sm9_dim_conjugate(out[1][0], a[1][0], q);
+ sm9_dim_mulm_mpi(out[1][0], out[1][0], ctx->sys_cfg->alpha1, q);
+ sm9_dim_conjugate(out[1][1], a[1][1], q);
+ sm9_dim_mulm_mpi(out[1][1], out[1][1], ctx->sys_cfg->alpha4, q);
+
+ sm9_dim_conjugate(out[2][0], a[2][0], q);
+ sm9_dim_mulm_mpi(out[2][0], out[2][0], ctx->sys_cfg->alpha2, q);
+ sm9_dim_conjugate(out[2][1], a[2][1], q);
+ sm9_dim_mulm_mpi(out[2][1], out[2][1], ctx->sys_cfg->alpha5, q);
+ return 0;
+}
+
+static int g_V_V_Q(SM9_DIM_FQ12 num, SM9_DIM_FQ12 den, SM9_POINT V, MPI_POINT Q,
+ struct sm9_ctx *ctx)
+{
+ SM9_DIM_FQ2 t0, t1, t2;
+ MPI q = ctx->sys_cfg->q;
+ int rc = -ENOMEM;
+
+ if (sm9_dim_init(t0, 0) || sm9_dim_init(t1, 0) || sm9_dim_init(t2, 0))
+ goto out_free;
+
+ sm9_dim_fq12_clear(num);
+ sm9_dim_fq12_clear(den);
+
+ sm9_dim_mulm(t0, V->z_fq2, V->z_fq2, q);
+ sm9_dim_mulm(t1, t0, V->z_fq2, q);
+ sm9_dim_mulm(den[0][1], t1, V->y_fq2, q);
+
+ sm9_dim_mulm_mpi(t2, den[0][1], Q->y, q);
+ sm9_dim_negm(num[0][1], t2, q);
+
+ sm9_dim_mulm(t1, V->x_fq2, V->x_fq2, q);
+ sm9_dim_mulm(t0, t0, t1, q);
+ sm9_dim_mulm_mpi(t0, t0, Q->x, q);
+ sm9_dim_mulm_ui(t0, t0, 3, q);
+ sm9_dim_div2m(num[2][0], t0, q);
+
+ sm9_dim_mulm(t1, t1, V->x_fq2, q);
+ sm9_dim_mulm_ui(t1, t1, 3, q);
+ sm9_dim_div2m(t1, t1, q);
+ sm9_dim_mulm(t0, V->y_fq2, V->y_fq2, q);
+ sm9_dim_subm(num[0][0], t0, t1, q);
+
+ rc = 0;
+
+out_free:
+ sm9_dim_deinit(t0);
+ sm9_dim_deinit(t1);
+ sm9_dim_deinit(t2);
+ return rc;
+}
+
+static int g_U_V_Q(SM9_DIM_FQ12 num, SM9_DIM_FQ12 den, SM9_POINT U, SM9_POINT V,
+ MPI_POINT Q, struct sm9_ctx *ctx)
+{
+ SM9_DIM_FQ2 t0, t1, t2, t3, t4;
+ MPI q = ctx->sys_cfg->q;
+ int rc = -ENOMEM;
+
+ if (sm9_dim_init(t0, 0) || sm9_dim_init(t1, 0) || sm9_dim_init(t2, 0) ||
+ sm9_dim_init(t3, 0) || sm9_dim_init(t4, 0))
+ goto out_free;
+
+ sm9_dim_fq12_clear(num);
+ sm9_dim_fq12_clear(den);
+
+ sm9_dim_mulm(t0, V->z_fq2, V->z_fq2, q);
+ sm9_dim_mulm(t1, t0, U->x_fq2, q);
+ sm9_dim_mulm(t0, t0, V->z_fq2, q);
+ sm9_dim_mulm(t2, U->z_fq2, U->z_fq2, q);
+ sm9_dim_mulm(t3, t2, V->x_fq2, q);
+ sm9_dim_mulm(t2, t2, U->z_fq2, q);
+ sm9_dim_mulm(t2, t2, V->y_fq2, q);
+ sm9_dim_subm(t1, t1, t3, q);
+ sm9_dim_mulm(t1, t1, U->z_fq2, q);
+ sm9_dim_mulm(t1, t1, V->z_fq2, q);
+ sm9_dim_mulm(den[0][1], t1, t0, q);
+ sm9_dim_mulm(t1, t1, V->y_fq2, q);
+ sm9_dim_mulm(t3, t0, U->y_fq2, q);
+ sm9_dim_subm(t3, t3, t2, q);
+ sm9_dim_mulm(t0, t0, t3, q);
+ sm9_dim_mulm_mpi(num[2][0], t0, Q->x, q);
+ sm9_dim_mulm(t3, t3, V->x_fq2, q);
+ sm9_dim_mulm(t3, t3, V->z_fq2, q);
+ sm9_dim_subm(num[0][0], t1, t3, q);
+ sm9_dim_mulm_mpi(t2, den[0][1], Q->y, q);
+ sm9_dim_negm(num[0][1], t2, q);
+
+ rc = 0;
+out_free:
+ sm9_dim_deinit(t0);
+ sm9_dim_deinit(t1);
+ sm9_dim_deinit(t2);
+ sm9_dim_deinit(t3);
+ sm9_dim_deinit(t4);
+
+ return rc;
+}
+
+static int sm9_point_pi_q(SM9_POINT out, SM9_POINT p, struct sm9_ctx *ctx)
+{
+ MPI q = ctx->sys_cfg->q;
+
+ if (!out)
+ return -EINVAL;
+
+ sm9_dim_conjugate(out->x_fq2, p->x_fq2, q);
+ sm9_dim_conjugate(out->y_fq2, p->y_fq2, q);
+ sm9_dim_conjugate(out->z_fq2, p->z_fq2, q);
+ sm9_dim_mulm_mpi(out->z_fq2, out->z_fq2, ctx->sys_cfg->pi_q_c, q);
+ return 0;
+}
+
+static int sm9_point_neg_pi_q2(SM9_POINT out, SM9_POINT p, struct sm9_ctx *ctx)
+{
+ if (!out)
+ return -EINVAL;
+
+ sm9_dim_copy(out->x_fq2, p->x_fq2);
+ sm9_dim_negm(out->y_fq2, p->y_fq2, ctx->sys_cfg->q);
+ sm9_dim_mulm_mpi(out->z_fq2, p->z_fq2, ctx->sys_cfg->pi_q2_c,
+ ctx->sys_cfg->q);
+ return 0;
+}
+
+static int sm9_final_exponent(SM9_DIM_FQ12 out, SM9_DIM_FQ12 F,
+ struct sm9_ctx *ctx)
+{
+ const char *a2_c = "0xd8000000019062ed0000b98b0cb27659";
+ const char *a3_c = "0x2400000000215d941";
+ SM9_DIM_FQ12 t0, t1, t2, t3, t4, t5;
+ MPI a2 = NULL, a3 = NULL;
+ int rc = -ENOMEM;
+
+ a2 = mpi_scanval(a2_c);
+ a3 = mpi_scanval(a3_c);
+ if (!a2 || !a3)
+ goto out_free_mpi;
+
+ rc = sm9_dim_fq12_init(t0, 0);
+ rc |= sm9_dim_fq12_init(t1, 0);
+ rc |= sm9_dim_fq12_init(t2, 0);
+ rc |= sm9_dim_fq12_init(t3, 0);
+ rc |= sm9_dim_fq12_init(t4, 0);
+ rc |= sm9_dim_fq12_init(t5, 0);
+ if (rc)
+ goto out_free;
+
+ sm9_dim_fq12_frobenius_6(t0, F, ctx);
+ sm9_dim_fq12_invm(t1, F, ctx);
+ sm9_dim_fq12_mulm(t0, t0, t1, ctx);
+ sm9_dim_fq12_frobenius_2(t1, t0, ctx);
+ sm9_dim_fq12_mulm(t0, t0, t1, ctx);
+
+ sm9_dim_fq12_powm(t2, t0, a3, ctx);
+ sm9_dim_fq12_invm(t2, t2, ctx);
+ sm9_dim_fq12_frobenius(t3, t2, ctx);
+ sm9_dim_fq12_mulm(t3, t2, t3, ctx);
+
+ sm9_dim_fq12_mulm(t2, t2, t3, ctx);
+ sm9_dim_fq12_frobenius(t4, t0, ctx);
+ sm9_dim_fq12_mulm(t5, t4, t0, ctx);
+ sm9_dim_fq12_powm_ui(t5, t5, 9, ctx);
+
+ sm9_dim_fq12_mulm(t2, t2, t5, ctx);
+ sm9_dim_fq12_mulm(t5, t0, t0, ctx);
+ sm9_dim_fq12_mulm(t5, t5, t5, ctx);
+ sm9_dim_fq12_mulm(t2, t2, t5, ctx);
+ sm9_dim_fq12_mulm(t4, t4, t4, ctx);
+ sm9_dim_fq12_mulm(t4, t4, t3, ctx);
+ sm9_dim_fq12_frobenius_2(t3, t0, ctx);
+ sm9_dim_fq12_mulm(t3, t3, t4, ctx);
+
+ sm9_dim_fq12_powm(t4, t3, a2, ctx);
+ sm9_dim_fq12_mulm(t2, t4, t2, ctx);
+ sm9_dim_fq12_frobenius_3(t3, t0, ctx);
+ sm9_dim_fq12_mulm(out, t3, t2, ctx);
+
+ rc = 0;
+
+out_free:
+ sm9_dim_fq12_deinit(t0);
+ sm9_dim_fq12_deinit(t1);
+ sm9_dim_fq12_deinit(t2);
+ sm9_dim_fq12_deinit(t3);
+ sm9_dim_fq12_deinit(t4);
+ sm9_dim_fq12_deinit(t5);
+
+out_free_mpi:
+ mpi_free(a2);
+ mpi_free(a3);
+ return rc;
+}
+
+int Rate_pairing(SM9_DIM_FQ12 out, SM9_POINT Q, MPI_POINT P, MPI a,
+ struct sm9_ctx *ctx)
+{
+ SM9_POINT T = NULL;
+ SM9_POINT Q1 = NULL, Q2 = NULL;
+ SM9_DIM_FQ12 f_num, f_den, g_num, g_den;
+ int i;
+ int rc = -ENOMEM;
+
+ Q1 = sm9_point_new(0);
+ Q2 = sm9_point_new(0);
+ T = sm9_point_new(0);
+ if (!Q1 || !Q2 || !T || !P)
+ goto out_free;
+
+ if (sm9_dim_fq12_init(f_num, 0) || sm9_dim_fq12_init(f_den, 0) ||
+ sm9_dim_fq12_init(g_num, 0) || sm9_dim_fq12_init(g_den, 0))
+ goto out_free;
+
+ /* f = 1 */
+ mpi_set_ui(f_num[0][0][0], 1);
+ mpi_set_ui(f_den[0][0][0], 1);
+
+ sm9_point_copy(T, Q);
+
+ for (i = mpi_get_nbits(a) - 2; i >= 0; i--) {
+ sm9_dim_fq12_mulm(f_num, f_num, f_num, ctx);
+ sm9_dim_fq12_mulm(f_den, f_den, f_den, ctx);
+ g_V_V_Q(g_num, g_den, T, P, ctx);
+ sm9_dim_fq12_mulm(f_num, f_num, g_num, ctx);
+ sm9_dim_fq12_mulm(f_den, f_den, g_den, ctx);
+
+ sm9_point_addm(T, T, T, ctx);
+
+ if (mpi_test_bit(a, i)) {
+ g_U_V_Q(g_num, g_den, T, Q, P, ctx);
+ sm9_dim_fq12_mulm(f_num, f_num, g_num, ctx);
+ sm9_dim_fq12_mulm(f_den, f_den, g_den, ctx);
+ sm9_point_addm(T, T, Q, ctx);
+ }
+ }
+
+ sm9_point_pi_q(Q1, Q, ctx);
+ sm9_point_neg_pi_q2(Q2, Q, ctx);
+
+ g_U_V_Q(g_num, g_den, T, Q1, P, ctx);
+ sm9_dim_fq12_mulm(f_num, f_num, g_num, ctx);
+ sm9_dim_fq12_mulm(f_den, f_den, g_den, ctx);
+ sm9_point_addm(T, T, Q1, ctx);
+
+ g_U_V_Q(g_num, g_den, T, Q2, P, ctx);
+ sm9_dim_fq12_mulm(f_num, f_num, g_num, ctx);
+ sm9_dim_fq12_mulm(f_den, f_den, g_den, ctx);
+ sm9_point_addm(T, T, Q2, ctx);
+
+ sm9_dim_fq12_invm(f_den, f_den, ctx);
+ sm9_dim_fq12_mulm(out, f_num, f_den, ctx);
+
+ sm9_final_exponent(out, out, ctx);
+
+ rc = 0;
+out_free:
+ sm9_dim_fq12_deinit(f_num);
+ sm9_dim_fq12_deinit(f_den);
+ sm9_dim_fq12_deinit(g_num);
+ sm9_dim_fq12_deinit(g_den);
+ sm9_point_release(T);
+ sm9_point_release(Q1);
+ sm9_point_release(Q2);
+ return rc;
+}
+
+MPI_POINT bytes_to_point(u8 *src, size_t size)
+{
+ MPI_POINT res;
+ MPI tmp;
+ size_t l = size / 2;
+
+ if (size % 2)
+ return NULL;
+
+ res = mpi_point_new(0);
+ if (!res)
+ return NULL;
+ mpi_set_ui(res->z, 1);
+
+ tmp = mpi_read_raw_data(src, l);
+ if (!tmp) {
+ mpi_point_release(res);
+ return NULL;
+ }
+ mpi_set(res->x, tmp);
+ mpi_free(tmp);
+
+ tmp = mpi_read_raw_data(src + l, l);
+ if (!tmp) {
+ mpi_point_release(res);
+ return NULL;
+ }
+ mpi_set(res->y, tmp);
+ mpi_free(tmp);
+ return res;
+}
+
+int point_to_bytes(MPI_POINT P, u8 **out, size_t *out_size)
+{
+ size_t size;
+ unsigned int write_size;
+
+ if (!P)
+ return -EINVAL;
+
+ size = mpi_get_size(P->x);
+ *out = kzalloc(size * 2, GFP_KERNEL);
+ if (!*out)
+ return -ENOMEM;
+
+ mpi_read_buffer(P->x, *out, size, &write_size, NULL);
+ if (write_size != size) {
+ kfree(*out);
+ *out = NULL;
+ return -EINVAL;
+ }
+
+ mpi_read_buffer(P->y, *out + size, size, &write_size, NULL);
+ if (write_size != size) {
+ kfree(*out);
+ *out = NULL;
+ return -EINVAL;
+ }
+
+ *out_size = size * 2;
+ return 0;
+}
+
+int mpi_point_to_sm9_point(SM9_POINT out, MPI_POINT p)
+{
+ if (!out)
+ return -EINVAL;
+
+ mpi_set(out->xd1, p->x);
+ mpi_set_ui(out->xd2, 0);
+ mpi_set(out->yd1, p->y);
+ mpi_set_ui(out->yd2, 0);
+ mpi_set(out->zd1, p->z);
+ mpi_set_ui(out->zd2, 0);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mpi_point_to_sm9_point);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("GUO Zihua <[email protected]>");
+MODULE_DESCRIPTION("SM9 generic algorithm library");
diff --git a/crypto/sm9_lib.h b/crypto/sm9_lib.h
new file mode 100644
index 000000000000..27c741ca11cd
--- /dev/null
+++ b/crypto/sm9_lib.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Header of libraries for SM9 key exchange algorithm
+ *
+ * Copyright (c) 2023, Huawei Technology Co., Ltd.
+ * Authors: GUO Zihua <[email protected]>
+ */
+
+#include <linux/mpi.h>
+#include <crypto/sm9.h>
+
+#ifndef _LOCAL_SM9_LIB_H
+#define _LOCAL_SM9_LIB_H
+
+struct sm9_point_fq2 {
+ union {
+ SM9_DIM_FQ2 x_fq2;
+ struct {
+ MPI xd1;
+ MPI xd2;
+ };
+ };
+ union {
+ SM9_DIM_FQ2 y_fq2;
+ struct {
+ MPI yd1;
+ MPI yd2;
+ };
+ };
+ union {
+ SM9_DIM_FQ2 z_fq2;
+ struct {
+ MPI zd1;
+ MPI zd2;
+ };
+ };
+};
+
+struct sm9_sys_cfg {
+ u8 cid;
+ MPI q;
+ MPI q_minus_2;
+ MPI q2;
+ MPI q2_minus_2;
+ MPI a, b;
+ MPI N;
+ MPI N_minus_1;
+ unsigned int N_log_2_times_5_roundup;
+ size_t N_size;
+ unsigned int cf;
+ unsigned int k;
+ MPI_POINT P1;
+ SM9_POINT P2;
+ u8 hid;
+ MPI t;
+ MPI tr;
+ MPI pairing_a;
+ MPI pi_q_c;
+ MPI pi_q2_c;
+ MPI beta;
+ MPI alpha1;
+ MPI alpha2;
+ MPI alpha3;
+ MPI alpha4;
+ MPI alpha5;
+
+ struct mpi_ec_ctx *G1;
+};
+
+struct sm9_ctx {
+ struct sm9_sys_cfg *sys_cfg;
+ MPI_POINT R;
+ MPI_POINT Ppub_s;
+ MPI r;
+ SM9_POINT de;
+ unsigned int hid;
+ char *id;
+ size_t id_size;
+ bool initiator;
+};
+
+int Rate_pairing(SM9_DIM_FQ12 out, SM9_POINT Q, MPI_POINT P, MPI t,
+ struct sm9_ctx *ctx);
+MPI_POINT bytes_to_point(u8 *src, size_t size);
+int point_to_bytes(MPI_POINT P, u8 **out, size_t *out_size);
+
+int sm9_point_mpi_addm(SM9_POINT out, SM9_POINT P, MPI a, MPI q);
+int sm9_point_mpi_mulm(SM9_POINT out, SM9_POINT P, MPI a, struct sm9_ctx *ctx);
+int sm9_point_addm(SM9_POINT out, SM9_POINT P, SM9_POINT Q,
+ struct sm9_ctx *ctx);
+int mpi_point_to_sm9_point(SM9_POINT out, MPI_POINT p);
+#endif
--
2.17.1


2023-06-17 10:33:50

by GUO Zihua

[permalink] [raw]
Subject: [RFC PATCH 3/3] crypto: Introduce SM9 key exchange algorithm

This patch introduces a generic implementation of SM9 (ShangMi 9) key
exchange algorithm.

SM9 is an ID-based cryptography algorithm within the ShangMi family whose
key exchange algorithm was accepted in ISO/IEC 11770-3 as an
international standard.

Being an ID-based crypto algorithm, each user would propose a
human-readable ID. The ID is then send to KGC (Key Generation Center),
who would generate private keys for the user.

The operation of SM9 key exchange is quite like that of DH or ECDH,
except with SM9, the caller and callee would be exchanging IDs
beforehand. Public keys are generated based on the id of the opponent,
as well as the private key of the user. Besides, unlike DH and ECDH,
caller and callee would be processing data slightly differently, which
could be noticed within the code.

Due to the difference mentioned above, SM9 does not quite fit into the
current self-test framework, thus self-tests for SM9 is not included yet.

Moreover, due to the fact that the data structure for passing data
around users is not defined by the standard, it is implemented in a
simple length then data style.

References:
http://c.gb688.cn/bzgk/gb/showGb?type=online&hcno=B7A0D7DFF411CD0AAE76135ADE91886A
http://c.gb688.cn/bzgk/gb/showGb?type=online&hcno=02A8E87248BD500747D2CD484C034EB0
https://github.com/guanzhi/GmSSL

Co-developed-by: LI Shiya <[email protected]>
Signed-off-by: GUO Zihua <[email protected]>
---
crypto/Kconfig | 15 +
crypto/Makefile | 4 +
crypto/sm9.c | 916 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 935 insertions(+)
create mode 100644 crypto/sm9.c

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 9c86f7045157..71a52308b563 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -304,6 +304,21 @@ config CRYPTO_ECRDSA
One of the Russian cryptographic standard algorithms (called GOST
algorithms). Only signature verification is implemented.

+config CRYPTO_SM9
+ tristate "SM9 (ShangMi 9 Key Exchange)"
+ select CRYPTO_SM3
+ select CRYPTO_AKCIPHER
+ select CRYPTO_MANAGER
+ select MPILIB
+ help
+ SM9 (ShangMi 9) key exchange algorithm.
+
+ As specified by GB/T 38635.1-2020 and GB/T 38635.2-2020.
+
+ References:
+ http://c.gb688.cn/bzgk/gb/showGb?type=online&hcno=B7A0D7DFF411CD0AAE76135ADE91886A
+ http://c.gb688.cn/bzgk/gb/showGb?type=online&hcno=02A8E87248BD500747D2CD484C034EB0
+
config CRYPTO_SM2
tristate "SM2 (ShangMi 2)"
select CRYPTO_SM3
diff --git a/crypto/Makefile b/crypto/Makefile
index d0126c915834..a4acad6b02f2 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -189,6 +189,10 @@ ecdh_generic-y += ecdh.o
ecdh_generic-y += ecdh_helper.o
obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o

+sm9_generic-y += sm9_lib.o
+sm9_generic-y += sm9.o
+obj-$(CONFIG_CRYPTO_SM9) += sm9_generic.o
+
$(obj)/ecrdsa_params.asn1.o: $(obj)/ecrdsa_params.asn1.c $(obj)/ecrdsa_params.asn1.h
$(obj)/ecrdsa_pub_key.asn1.o: $(obj)/ecrdsa_pub_key.asn1.c $(obj)/ecrdsa_pub_key.asn1.h
$(obj)/ecrdsa.o: $(obj)/ecrdsa_params.asn1.h $(obj)/ecrdsa_pub_key.asn1.h
diff --git a/crypto/sm9.c b/crypto/sm9.c
new file mode 100644
index 000000000000..48c96e9e473c
--- /dev/null
+++ b/crypto/sm9.c
@@ -0,0 +1,916 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * SM9 key exchange algorithm, as specified in
+ * GB/T 38635.1-2020 and GB/T 38635.2-2020
+ *
+ * Copyright (c) 2023, Huawei Technology Co., Ltd.
+ * Authors: GUO Zihua <[email protected]>
+ */
+
+#include <linux/math.h>
+#include <linux/mpi.h>
+#include <linux/bits.h>
+#include <linux/random.h>
+#include <linux/crypto.h>
+#include <crypto/hash.h>
+#include <crypto/kpp.h>
+#include <crypto/sm3.h>
+#include <crypto/sm3_base.h>
+#include <crypto/internal/kpp.h>
+#include <crypto/sm9.h>
+
+#include "sm9_lib.h"
+
+static struct sm9_sys_cfg sys_cfg;
+
+struct sm9_raw_cfg {
+ const char *desc;
+ unsigned int nbits;
+
+ enum gcry_mpi_ec_models model;
+
+ enum ecc_dialects dialect;
+
+ u8 cid;
+ u8 eid;
+ u8 hid;
+
+ const char *q;
+ const char *a, *b;
+ const char *N;
+ unsigned int N_log_2_times_5_roundup;
+ unsigned int cf;
+ unsigned int k;
+ const char *p1_x, *p1_y;
+ const char *p2_xd1, *p2_xd2, *p2_yd1, *p2_yd2;
+ const char *n; /* The order of the base point. */
+ const char *g_x, *g_y; /* Base point. */
+ const char *t;
+ const char *tr;
+ const char *pairing_a;
+ const char *pi_q_c;
+ const char *pi_q2_c;
+ const char *beta;
+ const char *alpha1;
+ const char *alpha2;
+ const char *alpha3;
+ const char *alpha4;
+ const char *alpha5;
+};
+
+static const struct sm9_raw_cfg sm9_default_cfg = {
+ .desc = "sm9Rate",
+ .model = MPI_EC_WEIERSTRASS,
+ .dialect = ECC_DIALECT_STANDARD,
+ .cid = 0x12,
+ .eid = 0x04,
+ .hid = 0x02,
+ .q = "0xB640000002A3A6F1D603AB4FF58EC74521F2934B1A7AEEDBE56F9B27E351457D",
+ .N = "0xB640000002A3A6F1D603AB4FF58EC74449F2934B18EA8BEEE56EE19CD69ECF25",
+ .N_log_2_times_5_roundup = 1278,
+ .a = "0x0",
+ .b = "0x5",
+ .k = 12,
+ .cf = 1,
+
+ .p1_x = "0x93DE051D62BF718FF5ED0704487D01D6E1E4086909DC3280E8C4E4817C66DDDD",
+ .p1_y = "0x21FE8DDA4F21E607631065125C395BBC1C1C00CBFA6024350C464CD70A3EA616",
+ .p2_xd2 =
+ "0x85AEF3D078640C98597B6027B441A01FF1DD2C190F5E93C454806C11D8806141",
+ .p2_xd1 =
+ "0x3722755292130B08D2AAB97FD34EC120EE265948D19C17ABF9B7213BAF82D65B",
+ .p2_yd2 =
+ "0x17509B092E845C1266BA0D262CBEE6ED0736A96FA347C8BD856DC76B84EBEB96",
+ .p2_yd1 =
+ "0xA7CF28D519BE3DA65F3170153D278FF247EFBA98A71A08116215BBA5C999A7C7",
+ .t = "0x600000000058F98A",
+ .tr = "0xD8000000019062ED0000B98B0CB27659",
+ .pairing_a = "0x2400000000215d93e",
+ .pi_q_c =
+ "0x3f23ea58e5720bdb843c6cfa9c08674947c5c86e0ddd04eda91d8354377b698b",
+ .pi_q2_c = "0xf300000002a3a6f2780272354f8b78f4d5fc11967be65334",
+ .beta = "0x6c648de5dc0a3f2cf55acc93ee0baf159f9d411806dc5177f5b21fd3da24d011",
+ .alpha1 =
+ "0x3f23ea58e5720bdb843c6cfa9c08674947c5c86e0ddd04eda91d8354377b698b",
+ .alpha2 = "0xf300000002a3a6f2780272354f8b78f4d5fc11967be65334",
+ .alpha3 =
+ "0x6c648de5dc0a3f2cf55acc93ee0baf159f9d411806dc5177f5b21fd3da24d011",
+ .alpha4 = "0xf300000002a3a6f2780272354f8b78f4d5fc11967be65333",
+ .alpha5 =
+ "0x2d40a38cf6983351711e5f99520347cc57d778a9f8ff4c8a4c949c7fa2a96686"
+};
+
+static struct crypto_shash *hash_tfm;
+
+static int sm9_h(MPI out, u8 *Z, size_t z_size, MPI n, u8 prepend,
+ struct sm9_ctx *ctx)
+{
+ SHASH_DESC_ON_STACK(shash, hash_tfm);
+ u8 *data, *tmp, *tmp_p;
+ u8 hash_result[SM3_DIGEST_SIZE];
+ u32 counter = 1;
+ size_t hlen, tmp_len, hash_digest_size = SM3_DIGEST_SIZE;
+ size_t data_size = z_size + sizeof(counter) + 1;
+ int i, hash_count;
+ int rc = -ENOMEM;
+ MPI mpi_tmp = NULL;
+
+ if (!out)
+ return -EINVAL;
+
+ data = kmalloc(data_size, GFP_KERNEL);
+ if (!data)
+ return rc;
+ memset(data, 0x0, data_size);
+
+ hlen = (roundup(ctx->sys_cfg->N_log_2_times_5_roundup, 32)) / 32;
+ hash_count = roundup(hlen, hash_digest_size) / hash_digest_size;
+
+ tmp = kmalloc(hlen, GFP_KERNEL);
+ if (!tmp)
+ goto out_free;
+
+ shash->tfm = hash_tfm;
+
+ tmp_len = hlen;
+ /* only the counter changes during the loop */
+ data[0] = prepend;
+ memcpy(&data[1], Z, z_size);
+ tmp_p = tmp;
+ for (i = 0; i < hash_count; i++) {
+ cpu_to_be32_array((__be32 *)&data[z_size + 1], &counter,
+ sizeof(counter));
+ crypto_shash_digest(shash, data, data_size, hash_result);
+ memcpy(tmp_p, &hash_result, min(tmp_len, hash_digest_size));
+ counter++;
+ tmp_len -= hash_digest_size;
+ tmp_p += hash_digest_size;
+ }
+
+ mpi_tmp = mpi_read_raw_data(tmp, hlen);
+ if (!mpi_tmp)
+ goto out_free;
+ mpi_set(out, mpi_tmp);
+
+ mpi_sub_ui(mpi_tmp, n, 1);
+ mpi_mod(out, out, mpi_tmp);
+ mpi_add_ui(out, out, 1);
+ rc = 0;
+
+out_free:
+ mpi_free(mpi_tmp);
+ kfree(tmp);
+ kfree(data);
+ return rc;
+}
+
+static int sm9_h1(MPI out, u8 *Z, size_t z_size, MPI n, struct sm9_ctx *ctx)
+{
+ return sm9_h(out, Z, z_size, n, 0x01, ctx);
+}
+
+static int sm9_get_R(MPI_POINT R, MPI ra, const u8 *id, size_t id_size,
+ struct sm9_ctx *ctx)
+{
+ MPI_POINT Q = NULL;
+ MPI tmp = NULL, r = NULL;
+ u8 *buf = NULL, *ra_buf = NULL;
+ int rc = -ENOMEM;
+
+ buf = kmalloc(id_size + sizeof(ctx->sys_cfg->hid), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ memcpy(buf, id, id_size);
+ memcpy(buf + id_size, &ctx->sys_cfg->hid, sizeof(ctx->sys_cfg->hid));
+
+ tmp = mpi_new(0);
+ if (!tmp)
+ goto out_err;
+ sm9_h1(tmp, buf, id_size + sizeof(ctx->sys_cfg->hid), ctx->sys_cfg->N,
+ ctx);
+
+ Q = mpi_point_new(0);
+ if (!Q)
+ goto out_err;
+ /* 1: Q = [H1(ID || hid, N)]P1 + Ppub-e */
+ mpi_ec_mul_point(Q, tmp, ctx->sys_cfg->G1->G, ctx->sys_cfg->G1);
+ mpi_ec_add_points(Q, Q, ctx->Ppub_s, ctx->sys_cfg->G1);
+
+ ra_buf = kzalloc(mpi_get_size(ctx->sys_cfg->N), GFP_KERNEL);
+ if (!ra_buf)
+ goto out_err;
+ r = mpi_new(0);
+ do {
+ get_random_bytes_wait(ra_buf, mpi_get_size(ctx->sys_cfg->N));
+ r = mpi_read_raw_data(ra_buf, mpi_get_size(ctx->sys_cfg->N));
+ if (!r)
+ goto out_err;
+ } while (mpi_cmp(r, ctx->sys_cfg->N_minus_1) > 0 ||
+ mpi_cmp_ui(r, 1) < 0);
+ memzero_explicit(ra_buf, mpi_get_size(ctx->sys_cfg->N));
+
+ mpi_ec_mul_point(R, r, Q, ctx->sys_cfg->G1);
+ mpi_point_jacobian_to_affine(R, R, ctx->sys_cfg->q);
+
+ memzero_explicit(ra->d, mpi_get_size(ra));
+ mpi_set(ra, r);
+ rc = 0;
+
+out_err:
+ mpi_point_release(Q);
+ mpi_free(tmp);
+ mpi_free(r);
+ kfree(buf);
+ kfree(ra_buf);
+ return rc;
+}
+
+static int _sm9_kdf(u8 *k, size_t klen, u8 *Z, size_t Z_size)
+{
+ SHASH_DESC_ON_STACK(shash, hash_tfm);
+ __be32 counter = 1;
+ u8 *buf = NULL, hash_out[SM3_DIGEST_SIZE];
+ size_t buf_size = Z_size + sizeof(counter), kp = 0, cpy_size;
+ int i, hash_times = roundup(klen, SM3_DIGEST_SIZE) / SM3_DIGEST_SIZE;
+
+ if (!Z || !Z_size || !k || !klen)
+ return -EINVAL;
+
+ buf = kmalloc(buf_size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ shash->tfm = hash_tfm;
+
+ memcpy(buf, Z, Z_size);
+ for (i = 0; i < hash_times; i++) {
+ cpu_to_be32_array((__be32 *)&buf[Z_size], &counter,
+ sizeof(counter));
+ counter++;
+ crypto_shash_digest(shash, buf, buf_size, hash_out);
+ cpy_size = min(klen - kp, (size_t)SM3_DIGEST_SIZE);
+ memcpy(k + kp, hash_out, cpy_size);
+ kp += cpy_size;
+ }
+
+ memzero_explicit(buf, buf_size);
+ kfree(buf);
+ memzero_explicit(hash_out, SM3_DIGEST_SIZE);
+ return 0;
+}
+
+static int sm9_kdf(u8 *SK, size_t klen, const u8 *ida, size_t ida_size,
+ const u8 *idb, size_t idb_size, MPI_POINT Ra, MPI_POINT Rb,
+ SM9_DIM_FQ12 g1, SM9_DIM_FQ12 g2, SM9_DIM_FQ12 g3)
+{
+ u8 *buf = NULL, *buf_tmp, *Ra_buf = NULL, *Rb_buf = NULL;
+ size_t buf_size, buf_size_tmp, Ra_buf_size, Rb_buf_size, g_size;
+ int rc = -ENOMEM;
+
+ point_to_bytes(Ra, &Ra_buf, &Ra_buf_size);
+ point_to_bytes(Rb, &Rb_buf, &Rb_buf_size);
+ if (!Ra_buf || !Rb_buf)
+ goto out_free;
+
+ buf_size = ida_size + idb_size;
+ buf_size += Ra_buf_size;
+ buf_size += Rb_buf_size;
+ g_size = sm9_dim_fq12_get_size(g1);
+ buf_size += 3 * g_size;
+ buf = kzalloc(buf_size, GFP_KERNEL);
+ if (!buf)
+ goto out_free;
+
+ buf_tmp = buf;
+ buf_size_tmp = buf_size;
+ memcpy(buf_tmp, ida, ida_size);
+ buf_tmp += ida_size;
+ buf_size_tmp -= ida_size;
+
+ memcpy(buf_tmp, idb, idb_size);
+ buf_tmp += idb_size;
+ buf_size_tmp -= idb_size;
+
+ memcpy(buf_tmp, Ra_buf, Ra_buf_size);
+ buf_tmp += Ra_buf_size;
+ buf_size_tmp -= Ra_buf_size;
+
+ memcpy(buf_tmp, Rb_buf, Rb_buf_size);
+ buf_tmp += Rb_buf_size;
+ buf_size_tmp -= Ra_buf_size;
+
+ sm9_dim_fq12_to_buf_rev(g1, buf_tmp, g_size);
+ buf_tmp += g_size;
+ buf_size_tmp -= g_size;
+
+ sm9_dim_fq12_to_buf_rev(g2, buf_tmp, g_size);
+ buf_tmp += g_size;
+ buf_size_tmp -= g_size;
+
+ sm9_dim_fq12_to_buf_rev(g3, buf_tmp, g_size);
+ buf_tmp += g_size;
+ buf_size_tmp -= g_size;
+
+ rc = _sm9_kdf(SK, klen, buf, buf_size);
+
+out_free:
+ kfree(buf);
+ kfree(Ra_buf);
+ kfree(Rb_buf);
+ return rc;
+}
+
+static int _sm9_get_SK_responder(u8 *SK, size_t klen, MPI_POINT R,
+ const char *id, const size_t id_size,
+ struct sm9_ctx *ctx)
+{
+ SM9_DIM_FQ12 g1, g2, g3;
+ int rc;
+
+ rc = sm9_dim_fq12_init(g1, 0);
+ rc |= sm9_dim_fq12_init(g2, 0);
+ rc |= sm9_dim_fq12_init(g3, 0);
+ if (rc)
+ goto out_free;
+ Rate_pairing(g1, ctx->de, R, ctx->sys_cfg->pairing_a, ctx);
+ Rate_pairing(g2, ctx->sys_cfg->P2, ctx->Ppub_s, ctx->sys_cfg->pairing_a,
+ ctx);
+ sm9_dim_fq12_powm(g2, g2, ctx->r, ctx);
+ sm9_dim_fq12_powm(g3, g1, ctx->r, ctx);
+
+ rc = sm9_kdf(SK, klen, id, id_size, ctx->id, ctx->id_size, R, ctx->R,
+ g1, g2, g3);
+
+out_free:
+ sm9_dim_fq12_deinit(g1);
+ sm9_dim_fq12_deinit(g2);
+ sm9_dim_fq12_deinit(g3);
+ return rc;
+}
+
+static int _sm9_get_SK_initiator(u8 *SK, size_t klen, MPI_POINT R,
+ const char *id, const size_t id_size,
+ struct sm9_ctx *ctx)
+{
+ SM9_DIM_FQ12 g1, g2, g3;
+ int rc;
+
+ rc = sm9_dim_fq12_init(g1, 0);
+ rc |= sm9_dim_fq12_init(g2, 0);
+ rc |= sm9_dim_fq12_init(g3, 0);
+ if (rc)
+ goto out_free;
+ Rate_pairing(g1, ctx->sys_cfg->P2, ctx->Ppub_s, ctx->sys_cfg->pairing_a,
+ ctx);
+ sm9_dim_fq12_powm(g1, g1, ctx->r, ctx);
+ Rate_pairing(g2, ctx->de, R, ctx->sys_cfg->pairing_a, ctx);
+ sm9_dim_fq12_powm(g3, g2, ctx->r, ctx);
+
+ rc = sm9_kdf(SK, klen, ctx->id, ctx->id_size, id, id_size, ctx->R, R,
+ g1, g2, g3);
+
+out_free:
+ sm9_dim_fq12_deinit(g1);
+ sm9_dim_fq12_deinit(g2);
+ sm9_dim_fq12_deinit(g3);
+ return rc;
+}
+
+static int sm9_get_SK(u8 *SK, size_t klen, MPI_POINT R, const char *id,
+ const size_t id_size, struct sm9_ctx *ctx, bool initiator)
+{
+ if (initiator)
+ return _sm9_get_SK_initiator(SK, klen, R, id, id_size, ctx);
+
+ return _sm9_get_SK_responder(SK, klen, R, id, id_size, ctx);
+}
+
+static void sm9_ctx_deinit(struct sm9_ctx *ctx)
+{
+ ctx->sys_cfg = NULL;
+ if (ctx->Ppub_s)
+ mpi_point_release(ctx->Ppub_s);
+ ctx->Ppub_s = NULL;
+
+ if (ctx->R)
+ mpi_point_release(ctx->R);
+ ctx->R = NULL;
+
+ if (ctx->de)
+ sm9_point_release(ctx->de);
+ ctx->de = NULL;
+
+ kfree(ctx->id);
+ ctx->id = NULL;
+
+ if (ctx->r)
+ mpi_free(ctx->r);
+ ctx->r = NULL;
+}
+
+static int sm9_init_tfm(struct crypto_kpp *tfm)
+{
+ struct sm9_ctx *ctx = (struct sm9_ctx *)kpp_tfm_ctx(tfm);
+
+ ctx->sys_cfg = &sys_cfg;
+ return 0;
+}
+
+static void sm9_exit_tfm(struct crypto_kpp *tfm)
+{
+ struct sm9_ctx *ctx = (struct sm9_ctx *)kpp_tfm_ctx(tfm);
+
+ sm9_ctx_deinit(ctx);
+}
+
+static unsigned int sm9_max_size(struct crypto_kpp *tfm)
+{
+ /* Unlimited max size */
+ return PAGE_SIZE;
+}
+
+static int sm9_set_secret(struct crypto_kpp *tfm, const void *buf,
+ unsigned int len)
+{
+ struct sm9_ctx *ctx = (struct sm9_ctx *)kpp_tfm_ctx(tfm);
+ struct sm9_set_secret_data *data;
+ u8 *data_p;
+
+ data = kmemdup(buf, len, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->id_size = be32_to_cpu(data->id_size);
+ data->secret_size = be32_to_cpu(data->secret_size);
+ data->pub_size = be32_to_cpu(data->pub_size);
+
+ if (!data->id_size || !data->secret_size || !data->pub_size ||
+ data->secret_size % 2) {
+ kfree_sensitive(data);
+ return -EINVAL;
+ }
+ data_p = data->data;
+
+ ctx->id = kzalloc(data->id_size, GFP_KERNEL);
+ if (!ctx->id) {
+ kfree_sensitive(data);
+ return -ENOMEM;
+ }
+ memcpy(ctx->id, data_p, data->id_size);
+ ctx->id_size = data->id_size;
+ data_p += data->id_size;
+
+ ctx->de = sm9_point_from_buf(data_p, data->secret_size);
+ if (!ctx->de) {
+ kfree_sensitive(data);
+ kfree(ctx->id);
+ ctx->id = NULL;
+ return -ENOMEM;
+ }
+ data_p += data->secret_size;
+
+ if (sm9_point_valid(ctx->de, ctx)) {
+ kfree_sensitive(data);
+ kfree(ctx->id);
+ ctx->id = NULL;
+ sm9_point_release(ctx->de);
+ ctx->de = NULL;
+ return -EINVAL;
+ }
+
+ ctx->Ppub_s = mpi_point_new(0);
+ if (!ctx->Ppub_s) {
+ kfree_sensitive(data);
+ kfree(ctx->id);
+ ctx->id = NULL;
+ sm9_point_release(ctx->de);
+ ctx->de = NULL;
+ return -ENOMEM;
+ }
+ mpi_point_from_buf(ctx->Ppub_s, data_p, data->pub_size);
+ if (!mpi_ec_curve_point(ctx->Ppub_s, ctx->sys_cfg->G1)) {
+ kfree_sensitive(data);
+ kfree(ctx->id);
+ ctx->id = NULL;
+ sm9_point_release(ctx->de);
+ ctx->de = NULL;
+ mpi_point_release(ctx->Ppub_s);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct sm9_compute_data *retrive_oppo_data(struct kpp_request *req)
+{
+ struct sm9_compute_data *oppo_data;
+ u8 *input_buf = NULL;
+ size_t copied;
+
+ input_buf = kzalloc(req->src_len, GFP_KERNEL);
+ if (!input_buf)
+ return NULL;
+
+ copied = sg_copy_to_buffer(req->src,
+ sg_nents_for_len(req->src, req->src_len),
+ input_buf, req->src_len);
+ if (copied != req->src_len) {
+ kfree(input_buf);
+ return NULL;
+ }
+
+ oppo_data = (struct sm9_compute_data *)input_buf;
+ oppo_data->id_size = be32_to_cpu(oppo_data->id_size);
+ oppo_data->R_size = be32_to_cpu(oppo_data->R_size);
+
+ if (oppo_data->R_size + oppo_data->id_size !=
+ req->src_len - sizeof(oppo_data->R_size) -
+ sizeof(oppo_data->id_size)) {
+ kfree(input_buf);
+ return NULL;
+ }
+ return oppo_data;
+}
+
+static int sm9_generate_public_key(struct kpp_request *req)
+{
+ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
+ struct sm9_ctx *ctx = kpp_tfm_ctx(tfm);
+ struct sm9_compute_data *oppo_data = NULL;
+ struct sm9_compute_data *data = NULL;
+ MPI_POINT P = NULL;
+ u8 *key = NULL, *id_buf = NULL;
+ size_t key_size, data_size, copied;
+ int rc = -ENOMEM;
+
+ if (!ctx->id) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if (!req->src || !req->src_len)
+ return -EINVAL;
+
+ oppo_data = retrive_oppo_data(req);
+ if (!oppo_data)
+ return -ENOMEM;
+
+ id_buf = kmemdup(oppo_data->data, oppo_data->id_size, GFP_KERNEL);
+ if (!id_buf) {
+ kfree(oppo_data);
+ return -ENOMEM;
+ }
+
+ if (ctx->R)
+ mpi_point_release(ctx->R);
+ ctx->R = mpi_point_new(0);
+ if (!ctx->R)
+ goto out_err;
+
+ if (ctx->r)
+ mpi_free(ctx->r);
+ ctx->r = mpi_new(0);
+ if (!ctx->r)
+ goto out_err;
+
+ rc = sm9_get_R(ctx->R, ctx->r, id_buf, oppo_data->id_size, ctx);
+ if (rc)
+ goto out_err;
+
+ P = mpi_point_new(0);
+ if (!P)
+ goto out_err;
+
+ rc = mpi_point_jacobian_to_affine(P, ctx->R, ctx->sys_cfg->q);
+ if (rc)
+ goto out_err;
+
+ key_size = max(mpi_get_size(P->x), mpi_get_size(P->y)) * 2;
+ data_size = sizeof(struct sm9_compute_data) + ctx->id_size + key_size;
+ if (req->dst_len < data_size) {
+ req->dst_len = data_size;
+ rc = -EINVAL;
+ goto out_err;
+ }
+
+ data = kzalloc(data_size, GFP_KERNEL);
+ if (!data)
+ goto out_err;
+ data->id_size = cpu_to_be32(ctx->id_size);
+ data->R_size = cpu_to_be32(key_size);
+ memcpy(data->data, ctx->id, ctx->id_size);
+
+ rc = mpi_point_export(P, data->data + ctx->id_size, key_size);
+ if (rc)
+ goto out_err;
+
+ copied = sg_copy_from_buffer(req->dst,
+ sg_nents_for_len(req->dst, data_size),
+ data, data_size);
+ if (copied != data_size)
+ rc = -EINVAL;
+
+ if (!oppo_data->R_size)
+ ctx->initiator = true;
+ rc = 0;
+ goto out;
+out_err:
+ if (ctx->R)
+ mpi_point_release(ctx->R);
+ ctx->R = NULL;
+ if (ctx->r)
+ mpi_free(ctx->r);
+ ctx->r = NULL;
+out:
+ kfree_sensitive(data);
+ mpi_point_release(P);
+ kfree(key);
+ kfree(oppo_data);
+ kfree(id_buf);
+ return rc;
+}
+
+static int sm9_compute_shared_secret(struct kpp_request *req, const u8 *oppo_id,
+ struct sm9_compute_data *oppo_data,
+ bool initiator)
+{
+ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
+ struct sm9_ctx *ctx = kpp_tfm_ctx(tfm);
+ MPI_POINT R = NULL;
+ u8 *k_buf = NULL;
+ size_t klen = req->dst_len, copied;
+ int rc = -ENOMEM;
+
+ if (!req->src || !req->src_len)
+ return -EINVAL;
+
+ if (!oppo_data->R_size)
+ return -EINVAL;
+
+ R = mpi_point_new(0);
+ if (!R)
+ goto out_free;
+
+ rc = mpi_point_from_buf(R, oppo_data->data + oppo_data->id_size,
+ oppo_data->R_size);
+ if (rc)
+ goto out_free;
+
+ k_buf = kzalloc(klen, GFP_KERNEL);
+ if (!k_buf)
+ goto out_free;
+
+ rc = sm9_get_SK(k_buf, klen, R, oppo_id, oppo_data->id_size, ctx,
+ initiator);
+ if (rc)
+ goto out_free;
+
+ copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, klen),
+ k_buf, klen);
+ if (copied != klen)
+ rc = -ENOMEM;
+
+out_free:
+ kfree_sensitive(k_buf);
+ mpi_point_release(R);
+ return rc;
+}
+
+static int sm9_compute(struct kpp_request *req)
+{
+ struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
+ struct sm9_ctx *ctx = kpp_tfm_ctx(tfm);
+ struct sm9_compute_data *oppo_data;
+ u8 *id_buf = NULL;
+ int rc;
+
+ if (!req->src || !req->src_len)
+ return -EINVAL;
+
+ if (!ctx->R)
+ return -EINVAL;
+
+ oppo_data = retrive_oppo_data(req);
+ if (!oppo_data)
+ return -ENOMEM;
+
+ id_buf = kmemdup(oppo_data->data, oppo_data->id_size, GFP_KERNEL);
+ if (!id_buf) {
+ kfree(oppo_data);
+ return -ENOMEM;
+ }
+
+ rc = sm9_compute_shared_secret(req, id_buf, oppo_data, ctx->initiator);
+
+ ctx->initiator = false;
+ kfree(id_buf);
+ kfree(oppo_data);
+ return rc;
+}
+
+static struct kpp_alg sm9_generic = {
+ .set_secret = sm9_set_secret,
+ .generate_public_key = sm9_generate_public_key,
+ .compute_shared_secret = sm9_compute,
+ .max_size = sm9_max_size,
+ .init = sm9_init_tfm,
+ .exit = sm9_exit_tfm,
+ .base = { .cra_name = "sm9_kpp",
+ .cra_driver_name = "sm9_kpp_generic",
+ .cra_priority = 100,
+ .cra_module = THIS_MODULE,
+ .cra_ctxsize = sizeof(struct sm9_ctx) }
+};
+
+static void sm9_sys_cfg_deinit(void)
+{
+ struct sm9_sys_cfg *cfg = &sys_cfg;
+
+ mpi_free(cfg->q);
+ cfg->q = NULL;
+ mpi_free(cfg->q_minus_2);
+ cfg->q_minus_2 = NULL;
+ mpi_free(cfg->q2);
+ cfg->q2 = NULL;
+ mpi_free(cfg->q2_minus_2);
+ cfg->q2_minus_2 = NULL;
+ mpi_free(cfg->a);
+ cfg->a = NULL;
+ mpi_free(cfg->b);
+ cfg->b = NULL;
+ mpi_free(cfg->t);
+ cfg->t = NULL;
+ mpi_free(cfg->tr);
+ cfg->tr = NULL;
+ mpi_free(cfg->pairing_a);
+ cfg->pairing_a = NULL;
+ mpi_free(cfg->N);
+ cfg->N = NULL;
+ cfg->G1->n = NULL;
+ mpi_free(cfg->N_minus_1);
+ cfg->N_minus_1 = NULL;
+ mpi_free(cfg->pi_q_c);
+ cfg->pi_q_c = NULL;
+ mpi_free(cfg->pi_q2_c);
+ cfg->pi_q2_c = NULL;
+ mpi_free(cfg->beta);
+ cfg->beta = NULL;
+ mpi_free(cfg->alpha1);
+ cfg->alpha1 = NULL;
+ mpi_free(cfg->alpha2);
+ cfg->alpha2 = NULL;
+ mpi_free(cfg->alpha3);
+ cfg->alpha3 = NULL;
+ mpi_free(cfg->alpha4);
+ cfg->alpha4 = NULL;
+ mpi_free(cfg->alpha5);
+ cfg->alpha5 = NULL;
+ mpi_point_release(cfg->P1);
+ cfg->P1 = NULL;
+ sm9_point_release(cfg->P2);
+ cfg->P2 = NULL;
+
+ if (cfg->G1)
+ mpi_ec_deinit(cfg->G1);
+ cfg->G1 = NULL;
+}
+
+static int sm9_ec_ctx_init(void)
+{
+ const struct sm9_raw_cfg *default_cfg = &sm9_default_cfg;
+ struct sm9_sys_cfg *cfg = &sys_cfg;
+ MPI mpi0 = NULL;
+
+ cfg->G1 = kzalloc(sizeof(struct mpi_ec_ctx), GFP_KERNEL);
+ if (!cfg->G1)
+ return -ENOMEM;
+
+ mpi0 = mpi_new(0);
+ if (!mpi0) {
+ kfree(cfg->G1);
+ return -ENOMEM;
+ }
+ mpi_set_ui(mpi0, 0);
+ cfg->G1->G = mpi_point_new(0);
+ if (!cfg->G1->G) {
+ mpi_free(mpi0);
+ kfree(cfg->G1);
+ return -ENOMEM;
+ }
+ cfg->G1->n = cfg->N;
+ cfg->G1->h = cfg->cf;
+ cfg->G1->name = default_cfg->desc;
+ mpi_set(cfg->G1->G->x, cfg->P1->x);
+ mpi_set(cfg->G1->G->y, cfg->P1->y);
+ mpi_set_ui(cfg->G1->G->z, 1);
+ mpi_ec_init(cfg->G1, sm9_default_cfg.model, sm9_default_cfg.dialect, 0,
+ cfg->q, mpi0, cfg->b);
+ mpi_free(mpi0);
+ return 0;
+}
+
+static int sm9_sys_cfg_init(void)
+{
+ const struct sm9_raw_cfg *default_cfg = &sm9_default_cfg;
+ struct sm9_sys_cfg *cfg = &sys_cfg;
+
+ cfg->P1 = mpi_point_new(0);
+ cfg->P2 = sm9_point_new(0);
+ if (!cfg->P1 || !cfg->P2)
+ goto out_err;
+
+ mpi_fromstr(cfg->P1->x, default_cfg->p1_x);
+ mpi_fromstr(cfg->P1->y, default_cfg->p1_y);
+
+ mpi_fromstr(cfg->P2->xd1, default_cfg->p2_xd1);
+ mpi_fromstr(cfg->P2->xd2, default_cfg->p2_xd2);
+ mpi_fromstr(cfg->P2->yd1, default_cfg->p2_yd1);
+ mpi_fromstr(cfg->P2->yd2, default_cfg->p2_yd2);
+ mpi_set_ui(cfg->P2->zd1, 1);
+ mpi_set_ui(cfg->P2->zd2, 0);
+
+ cfg->N = mpi_scanval(default_cfg->N);
+ cfg->N_minus_1 = mpi_new(0);
+ if (!cfg->N || !cfg->N_minus_1)
+ goto out_err;
+ mpi_sub_ui(cfg->N_minus_1, cfg->N, 1);
+
+ cfg->q = mpi_scanval(default_cfg->q);
+ cfg->q_minus_2 = mpi_new(0);
+ cfg->q2 = mpi_new(0);
+ cfg->q2_minus_2 = mpi_new(0);
+ cfg->a = mpi_scanval(default_cfg->a);
+ cfg->b = mpi_scanval(default_cfg->b);
+ cfg->t = mpi_scanval(default_cfg->t);
+ cfg->tr = mpi_scanval(default_cfg->tr);
+ cfg->pairing_a = mpi_scanval(default_cfg->pairing_a);
+ cfg->pi_q_c = mpi_scanval(default_cfg->pi_q_c);
+ cfg->pi_q2_c = mpi_scanval(default_cfg->pi_q2_c);
+ cfg->beta = mpi_scanval(default_cfg->beta);
+ cfg->alpha1 = mpi_scanval(default_cfg->alpha1);
+ cfg->alpha2 = mpi_scanval(default_cfg->alpha2);
+ cfg->alpha3 = mpi_scanval(default_cfg->alpha3);
+ cfg->alpha4 = mpi_scanval(default_cfg->alpha4);
+ cfg->alpha5 = mpi_scanval(default_cfg->alpha5);
+ if (!cfg->q || !cfg->q_minus_2 || !cfg->q2 || !cfg->q2_minus_2 ||
+ !cfg->a || !cfg->b || !cfg->t || !cfg->tr || !cfg->pairing_a ||
+ !cfg->pi_q_c || !cfg->pi_q2_c || !cfg->beta || !cfg->alpha1 ||
+ !cfg->alpha2 || !cfg->alpha3 || !cfg->alpha4 || !cfg->alpha5)
+ goto out_err;
+ mpi_sub_ui(cfg->q_minus_2, cfg->q, 2);
+ mpi_mulm(cfg->q2, cfg->q, cfg->q, cfg->q);
+ mpi_sub_ui(cfg->q2_minus_2, cfg->q2, 2);
+
+ cfg->cid = default_cfg->cid;
+ cfg->k = default_cfg->k;
+ cfg->cf = default_cfg->cf;
+ cfg->N_log_2_times_5_roundup = default_cfg->N_log_2_times_5_roundup;
+ cfg->hid = default_cfg->hid;
+
+ if (sm9_ec_ctx_init())
+ goto out_err;
+
+ return 0;
+out_err:
+ sm9_sys_cfg_deinit();
+ return -ENOMEM;
+}
+
+static int sm9_init(void)
+{
+ int rc;
+
+ hash_tfm = crypto_alloc_shash("sm3", 0, 0);
+ if (IS_ERR(hash_tfm)) {
+ pr_err("Failed to allocate SM3 hash algorithm\n");
+ return PTR_ERR(hash_tfm);
+ }
+
+ rc = sm9_sys_cfg_init();
+ if (rc) {
+ crypto_free_shash(hash_tfm);
+ return rc;
+ }
+
+ rc = crypto_register_kpp(&sm9_generic);
+ if (rc) {
+ crypto_free_shash(hash_tfm);
+ sm9_sys_cfg_deinit();
+ }
+
+ return rc;
+}
+
+static void sm9_exit(void)
+{
+ if (hash_tfm)
+ crypto_free_shash(hash_tfm);
+ sm9_sys_cfg_deinit();
+}
+
+subsys_initcall(sm9_init);
+module_exit(sm9_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("GUO Zihua <[email protected]>");
+MODULE_DESCRIPTION("SM9 generic algorithm");
+MODULE_ALIAS_CRYPTO("sm9-generic");
--
2.17.1