From patchwork Sat Jun 17 10:14:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Guozihua \(Scott\)" X-Patchwork-Id: 693697 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7C742EB64DB for ; Sat, 17 Jun 2023 10:15:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233241AbjFQKPv (ORCPT ); Sat, 17 Jun 2023 06:15:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52814 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234374AbjFQKPu (ORCPT ); Sat, 17 Jun 2023 06:15:50 -0400 Received: from szxga03-in.huawei.com (szxga03-in.huawei.com [45.249.212.189]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C8BDF1BCF for ; Sat, 17 Jun 2023 03:15:48 -0700 (PDT) Received: from dggpemm500024.china.huawei.com (unknown [172.30.72.57]) by szxga03-in.huawei.com (SkyGuard) with ESMTP id 4QjsLm4zVZzLmrh; Sat, 17 Jun 2023 18:13:52 +0800 (CST) Received: from huawei.com (10.67.175.31) by dggpemm500024.china.huawei.com (7.185.36.203) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.23; Sat, 17 Jun 2023 18:15:46 +0800 From: GUO Zihua To: , CC: Subject: [RFC PATCH 1/3] MPI: Export mpi_add_ui and mpi_mod for SM9 Date: Sat, 17 Jun 2023 18:14:41 +0800 Message-ID: <20230617101443.6083-2-guozihua@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20230617101443.6083-1-guozihua@huawei.com> References: <20230617101443.6083-1-guozihua@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.175.31] X-ClientProxiedBy: dggems706-chm.china.huawei.com (10.3.19.183) To dggpemm500024.china.huawei.com (7.185.36.203) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org 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 --- 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 From patchwork Sat Jun 17 10:14:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Guozihua \(Scott\)" X-Patchwork-Id: 694596 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BA394EB64DA for ; Sat, 17 Jun 2023 10:15:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235715AbjFQKPz (ORCPT ); Sat, 17 Jun 2023 06:15:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52836 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232533AbjFQKPx (ORCPT ); Sat, 17 Jun 2023 06:15:53 -0400 Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9055C1BD1 for ; Sat, 17 Jun 2023 03:15:49 -0700 (PDT) Received: from dggpemm500024.china.huawei.com (unknown [172.30.72.57]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4QjsNJ2JDKzTl67; Sat, 17 Jun 2023 18:15:12 +0800 (CST) Received: from huawei.com (10.67.175.31) by dggpemm500024.china.huawei.com (7.185.36.203) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.23; Sat, 17 Jun 2023 18:15:47 +0800 From: GUO Zihua To: , CC: Subject: [RFC PATCH 2/3] crypto: Introduce SM9 key exchange algorithm library Date: Sat, 17 Jun 2023 18:14:42 +0800 Message-ID: <20230617101443.6083-3-guozihua@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20230617101443.6083-1-guozihua@huawei.com> References: <20230617101443.6083-1-guozihua@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.175.31] X-ClientProxiedBy: dggems706-chm.china.huawei.com (10.3.19.183) To dggpemm500024.china.huawei.com (7.185.36.203) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org 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 Signed-off-by: GUO Zihua --- 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 + */ + +#include +#include +#include +#include + +#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 "); +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 + */ + +#include +#include + +#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 From patchwork Sat Jun 17 10:14:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Guozihua \(Scott\)" X-Patchwork-Id: 693696 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 94587EB64DA for ; Sat, 17 Jun 2023 10:16:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232533AbjFQKQD (ORCPT ); Sat, 17 Jun 2023 06:16:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52838 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234374AbjFQKPy (ORCPT ); Sat, 17 Jun 2023 06:15:54 -0400 Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4394C1BCF for ; Sat, 17 Jun 2023 03:15:51 -0700 (PDT) Received: from dggpemm500024.china.huawei.com (unknown [172.30.72.55]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4QjsNK3TfCzTknD; Sat, 17 Jun 2023 18:15:13 +0800 (CST) Received: from huawei.com (10.67.175.31) by dggpemm500024.china.huawei.com (7.185.36.203) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.23; Sat, 17 Jun 2023 18:15:48 +0800 From: GUO Zihua To: , CC: Subject: [RFC PATCH 3/3] crypto: Introduce SM9 key exchange algorithm Date: Sat, 17 Jun 2023 18:14:43 +0800 Message-ID: <20230617101443.6083-4-guozihua@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20230617101443.6083-1-guozihua@huawei.com> References: <20230617101443.6083-1-guozihua@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.175.31] X-ClientProxiedBy: dggems706-chm.china.huawei.com (10.3.19.183) To dggpemm500024.china.huawei.com (7.185.36.203) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org 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 Signed-off-by: GUO Zihua --- 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("SM9 generic algorithm"); +MODULE_ALIAS_CRYPTO("sm9-generic");