From 6150965c1668bbfbe95d04b95eec1189486d1112 Mon Sep 17 00:00:00 2001 From: Gorachya <38173958+Gorachya@users.noreply.github.com> Date: Wed, 13 Mar 2024 15:43:27 +0800 Subject: [PATCH] Add files via upload --- src/sm9_alg.c | 248 +++-- src/sm9_z256_alg.c | 2458 ++++++++++++++++++++++++++++++++++++++++++++ src/sm9_z256_key.c | 1157 +++++++++++++++++++++ src/sm9_z256_lib.c | 516 ++++++++++ 4 files changed, 4302 insertions(+), 77 deletions(-) create mode 100644 src/sm9_z256_alg.c create mode 100644 src/sm9_z256_key.c create mode 100644 src/sm9_z256_lib.c diff --git a/src/sm9_alg.c b/src/sm9_alg.c index 0da0f188..0c021d73 100644 --- a/src/sm9_alg.c +++ b/src/sm9_alg.c @@ -166,9 +166,6 @@ int sm9_bn_cmp(const sm9_bn_t a, const sm9_bn_t b) return 0; } - - - void sm9_bn_copy(sm9_bn_t r, const sm9_bn_t a) { memcpy(r, a, sizeof(sm9_bn_t)); @@ -328,6 +325,87 @@ void sm9_barrett_bn_sub(sm9_barrett_bn_t ret, const sm9_barrett_bn_t a, const sm } } +// w = -p^-1 mod 2^256 = 0xafd2bac5558a13b3966a4b291522b137181ae39613c8dbaf892bc42c2f2ee42b +// 2^512 mod p = 0x2ea795a656f62fbde479b522d6706e7b88f8105fae1a5d3f27dea312b417e2d2 +const sm9_bn_t SM9_W = {0x2f2ee42b, 0x892bc42c, 0x13c8dbaf, 0x181ae396, 0x1522b137, 0x966a4b29, 0x558a13b3, 0xafd2bac5}; +const sm9_bn_t SM9_2e512modp = {0xb417e2d2, 0x27dea312, 0xae1a5d3f, 0x88f8105f, 0xd6706e7b, 0xe479b522, 0x56f62fbd, 0x2ea795a6}; + +void sm9_fp_to_mont(sm9_fp_t r, const sm9_fp_t a) +{ + sm9_fp_mul_mont(r, a, SM9_2e512modp); +} + +void sm9_fp_from_mont(sm9_fp_t r, const sm9_fp_t a) +{ + sm9_fp_mul_mont(r, a, SM9_ONE); +} + +void sm9_bn_mul(sm9_bn_t r1, sm9_bn_t r2, const sm9_bn_t a, const sm9_bn_t b) +{ + int i, j; + uint64_t s[16]; + uint64_t w; + + for (i = 0; i < 16; i++) { + s[i] = 0; + } + + for (i = 0; i < 8; i++) { + w = 0; + for (j = 0; j < 8; j++) { + w += s[i + j] + a[i] * b[j]; + s[i + j] = w & 0xffffffff; + w >>= 32; + } + s[i + 8] = w; + } + for (i = 0; i < 8; i++) { + r1[i] = s[i]; // low 256 + r2[i] = s[i + 8]; // high 256 + } +} + +void sm9_bn_add_512(sm9_bn_t r1, sm9_bn_t r2, + const sm9_bn_t a1, const sm9_bn_t a2, + const sm9_bn_t b1, const sm9_bn_t b2) +{ + int i, over; + + r1[0] = a1[0] + b1[0]; + for (i = 1; i < 8; i++) { + r1[i] = a1[i] + b1[i] + (r1[i-1] >> 32); + } + r2[0] = a2[0] + b2[0] + (r1[7] >> 32); + for (i = 1; i < 8; i++) { + r2[i] = a2[i] + b2[i] + (r2[i-1] >> 32); + } + for (i = 0; i < 7; i++) { + r1[i] &= 0xffffffff; + r2[i] &= 0xffffffff; + } + r1[7] &= 0xffffffff; +} + +void sm9_fp_mul_mont(sm9_fp_t r, const sm9_fp_t a, const sm9_fp_t b) +{ + sm9_bn_t z1, z2, u1, u2; + int i, j; + + // z = x * y mod 2^256 + sm9_bn_mul(z1, z2, a, b); + + // u = z * w mod 2^256 + sm9_bn_mul(u1, u2, z1, SM9_W); + + // s = (x * y + u * p) + sm9_bn_mul(u1, u2, u1, SM9_P); + sm9_bn_add_512(z1, r, z1, z2, u1, u2); + + if (sm9_bn_cmp(r, SM9_P) >= 0) { + sm9_bn_sub(r, r, SM9_P); + } +} + void sm9_fp_mul(sm9_fp_t r, const sm9_fp_t a, const sm9_fp_t b) { uint64_t s[18]; @@ -583,21 +661,36 @@ void sm9_fp2_neg(sm9_fp2_t r, const sm9_fp2_t a) sm9_fp_neg(r[1], a[1]); } +void sm9_fp2_a_mul_u(sm9_fp2_t r, sm9_fp2_t a) { + sm9_fp_t r0; + + sm9_fp_dbl(r0, a[1]); + sm9_fp_neg(r0, r0); + + sm9_fp_copy(r[1], a[0]); + sm9_fp_copy(r[0], r0); +} + void sm9_fp2_mul(sm9_fp2_t r, const sm9_fp2_t a, const sm9_fp2_t b) { sm9_fp_t r0, r1, t; + + sm9_fp_add(r0, a[0], a[1]); + sm9_fp_add(t, b[0], b[1]); + sm9_fp_mul(r1, t, r0); // r0 = a0 * b0 - 2 * a1 * b1 sm9_fp_mul(r0, a[0], b[0]); sm9_fp_mul(t, a[1], b[1]); + + // r1 = (a0 + a1) * (b0 + b1) - a0 * b0 - a1 * b1 + sm9_fp_sub(r1, r1, r0); + sm9_fp_sub(r1, r1, t); + + // r0 sm9_fp_dbl(t, t); sm9_fp_sub(r0, r0, t); - // r1 = a0 * b1 + a1 * b0 - sm9_fp_mul(r1, a[0], b[1]); - sm9_fp_mul(t, a[1], b[0]); - sm9_fp_add(r1, r1, t); - sm9_fp_copy(r[0], r0); sm9_fp_copy(r[1], r1); } @@ -631,16 +724,17 @@ void sm9_fp2_mul_fp(sm9_fp2_t r, const sm9_fp2_t a, const sm9_fp_t k) void sm9_fp2_sqr(sm9_fp2_t r, const sm9_fp2_t a) { - sm9_fp_t r0, r1, t; - - // a0^2 - 2 * a1^2 - sm9_fp_sqr(r0, a[0]); - sm9_fp_sqr(t, a[1]); - sm9_fp_dbl(t, t); - sm9_fp_sub(r0, r0, t); + sm9_fp_t r0, r1, c0, c1; + + // r0 = (a0 + a1) * (a0 - 2a1) + a0 * a1 + sm9_fp_mul(r1, a[0], a[1]); + sm9_fp_add(c0, a[0], a[1]); + sm9_fp_dbl(c1, a[1]); + sm9_fp_sub(c1, a[0], c1); + sm9_fp_mul(r0, c0, c1); + sm9_fp_add(r0, r0, r1); // r1 = 2 * a0 * a1 - sm9_fp_mul(r1, a[0], a[1]); sm9_fp_dbl(r1, r1); sm9_bn_copy(r[0], r0); @@ -835,18 +929,38 @@ void sm9_fp4_neg(sm9_fp4_t r, const sm9_fp4_t a) sm9_fp2_neg(r[1], a[1]); } +void sm9_fp4_div2(sm9_fp4_t r, const sm9_fp4_t a) +{ + sm9_fp2_div2(r[0], a[0]); + sm9_fp2_div2(r[1], a[1]); +} + +void sm9_fp4_a_mul_v(sm9_fp4_t r, sm9_fp4_t a) { + sm9_fp2_t r0; + + sm9_fp2_a_mul_u(r0, a[1]); + + sm9_fp2_copy(r[1], a[0]); + sm9_fp2_copy(r[0], r0); +} + void sm9_fp4_mul(sm9_fp4_t r, const sm9_fp4_t a, const sm9_fp4_t b) { sm9_fp2_t r0, r1, t; - + + sm9_fp2_add(r0, a[0], a[1]); + sm9_fp2_add(t, b[0], b[1]); + sm9_fp2_mul(r1, t, r0); + sm9_fp2_mul(r0, a[0], b[0]); - sm9_fp2_mul_u(t, a[1], b[1]); + sm9_fp2_mul(t, a[1], b[1]); + + sm9_fp2_sub(r1, r1, r0); + sm9_fp2_sub(r1, r1, t); + + sm9_fp2_a_mul_u(t, t); sm9_fp2_add(r0, r0, t); - sm9_fp2_mul(r1, a[0], b[1]); - sm9_fp2_mul(t, a[1], b[0]); - sm9_fp2_add(r1, r1, t); - sm9_fp2_copy(r[0], r0); sm9_fp2_copy(r[1], r1); } @@ -883,12 +997,18 @@ void sm9_fp4_sqr(sm9_fp4_t r, const sm9_fp4_t a) { sm9_fp2_t r0, r1, t; + sm9_fp2_add(r1, a[0], a[1]); + sm9_fp2_sqr(r1, r1); + sm9_fp2_sqr(r0, a[0]); - sm9_fp2_sqr_u(t, a[1]); + sm9_fp2_sqr(t, a[1]); + + sm9_fp2_sub(r1, r1, r0); + sm9_fp2_sub(r1, r1, t); + + sm9_fp2_a_mul_u(t, t); sm9_fp2_add(r0, r0, t); - - sm9_fp2_mul(r1, a[0], a[1]); - sm9_fp2_dbl(r1, r1); + sm9_fp2_copy(r[0], r0); sm9_fp2_copy(r[1], r1); } @@ -1101,25 +1221,34 @@ void sm9_fp12_neg(sm9_fp12_t r, const sm9_fp12_t a) void sm9_fp12_mul(sm9_fp12_t r, const sm9_fp12_t a, const sm9_fp12_t b) { - sm9_fp4_t r0, r1, r2, t; + sm9_fp4_t r0, r1, r2, t, k0, k1, m0, m1, m2; - sm9_fp4_mul(r0, a[0], b[0]); - sm9_fp4_mul_v(t, a[1], b[2]); - sm9_fp4_add(r0, r0, t); - sm9_fp4_mul_v(t, a[2], b[1]); - sm9_fp4_add(r0, r0, t); + sm9_fp4_mul(m0, a[0], b[0]); + sm9_fp4_mul(m1, a[1], b[1]); + sm9_fp4_mul(m2, a[2], b[2]); + + sm9_fp4_add(k0, a[1], a[2]); + sm9_fp4_add(k1, b[1], b[2]); + sm9_fp4_mul(t, k0, k1); + sm9_fp4_sub(t, t, m1); + sm9_fp4_sub(t, t, m2); + sm9_fp4_a_mul_v(t, t); + sm9_fp4_add(r0, t, m0); - sm9_fp4_mul(r1, a[0], b[1]); - sm9_fp4_mul(t, a[1], b[0]); - sm9_fp4_add(r1, r1, t); - sm9_fp4_mul_v(t, a[2], b[2]); - sm9_fp4_add(r1, r1, t); + sm9_fp4_add(k0, a[0], a[2]); + sm9_fp4_add(k1, b[0], b[2]); + sm9_fp4_mul(t, k0, k1); + sm9_fp4_sub(t, t, m0); + sm9_fp4_sub(t, t, m2); + sm9_fp4_add(r2, t, m1); - sm9_fp4_mul(r2, a[0], b[2]); - sm9_fp4_mul(t, a[1], b[1]); - sm9_fp4_add(r2, r2, t); - sm9_fp4_mul(t, a[2], b[0]); - sm9_fp4_add(r2, r2, t); + sm9_fp4_add(k0, a[0], a[1]); + sm9_fp4_add(k1, b[0], b[1]); + sm9_fp4_mul(t, k0, k1); + sm9_fp4_sub(t, t, m0); + sm9_fp4_sub(t, t, m1); + sm9_fp4_a_mul_v(m2, m2); + sm9_fp4_add(r1, t, m2); sm9_fp4_copy(r[0], r0); sm9_fp4_copy(r[1], r1); @@ -1150,41 +1279,6 @@ void sm9_fp12_mul(sm9_fp12_t r, const sm9_fp12_t a, const sm9_fp12_t b) // sm9_fp4_copy(r[2], r2); // } -void sm9_fp4_div2(sm9_fp4_t r, const sm9_fp4_t a) -{ - sm9_fp2_div2(r[0], a[0]); - sm9_fp2_div2(r[1], a[1]); -} - -void sm9_fp2_a_mul_u(sm9_fp2_t r, sm9_fp2_t a) { - sm9_fp_t r0, a0, a1; - - sm9_fp_copy(a0, a[0]); - sm9_fp_copy(a1, a[1]); - - //r0 = -2 * a1 - sm9_fp_dbl(r0, a1); - sm9_fp_neg(r0, r0); - sm9_fp_copy(r[0], r0); - - //r1 = a0 - sm9_fp_copy(r[1], a0); -} - -void sm9_fp4_a_mul_v(sm9_fp4_t r, sm9_fp4_t a) { - sm9_fp2_t r0, a0, a1; - - sm9_fp2_copy(a0, a[0]); - sm9_fp2_copy(a1, a[1]); - - //r0 = a1 * u - sm9_fp2_a_mul_u(r0, a1); - sm9_fp2_copy(r[0], r0); - - //r1 = a0 - sm9_fp2_copy(r[1], a0); -} - void sm9_fp12_sqr(sm9_fp12_t r, const sm9_fp12_t a) { sm9_fp4_t h0, h1, h2, t; diff --git a/src/sm9_z256_alg.c b/src/sm9_z256_alg.c new file mode 100644 index 00000000..39b2bbb4 --- /dev/null +++ b/src/sm9_z256_alg.c @@ -0,0 +1,2458 @@ +/* + * Copyright 2014-2022 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +const sm9_z256_t SM9_Z256_ZERO = {0,0,0,0}; +const sm9_z256_t SM9_Z256_ONE = {1,0,0,0}; +const sm9_z256_t SM9_Z256_TWO = {2,0,0,0}; +static const sm9_z256_t SM9_Z256_FIVE = {5,0,0,0}; + + +// p = b640000002a3a6f1d603ab4ff58ec74521f2934b1a7aeedbe56f9b27e351457d +// n = b640000002a3a6f1d603ab4ff58ec74449f2934b18ea8beee56ee19cd69ecf25 +// mu_p = 2^512 // p = 167980e0beb5759a655f73aebdcd1312af2665f6d1e36081c71188f90d5c22146 +// mu_n = 2^512 // n +const sm9_z256_t SM9_Z256_P = {0xe56f9b27e351457d, 0x21f2934b1a7aeedb, 0xd603ab4ff58ec745, 0xb640000002a3a6f1}; +const sm9_z256_t SM9_Z256_N = {0xe56ee19cd69ecf25, 0x49f2934b18ea8bee, 0xd603ab4ff58ec744, 0xb640000002a3a6f1}; +// n - 1 +static const sm9_z256_t SM9_Z256_N_MINUS_ONE = {0xe56ee19cd69ecf24, 0x49f2934b18ea8bee, 0xd603ab4ff58ec744, 0xb640000002a3a6f1}; +// 2^256 - n + 1 +static const sm9_z256_t SM9_Z256_2e256_N_MINUS_ONE = {0x1a911e63296130dc, 0xb60d6cb4e7157411, 0x29fc54b00a7138bb, 0x49bffffffd5c590e}; + + +// P1.X 0x93DE051D62BF718FF5ED0704487D01D6E1E4086909DC3280E8C4E4817C66DDDD +// P1.Y 0x21FE8DDA4F21E607631065125C395BBC1C1C00CBFA6024350C464CD70A3EA616 +const SM9_Z256_POINT _SM9_Z256_P1 = { + {0xe8c4e4817c66dddd, 0xe1e4086909dc3280, 0xf5ed0704487d01d6, 0x93de051d62bf718f}, + {0x0c464cd70a3ea616, 0x1c1c00cbfa602435, 0x631065125c395bbc, 0x21fe8dda4f21e607}, + {1,0,0,0} +}; +const SM9_Z256_POINT *SM9_Z256_P1 = &_SM9_Z256_P1; + +/* + X : [0x3722755292130b08d2aab97fd34ec120ee265948d19c17abf9b7213baf82d65bn, + 0x85aef3d078640c98597b6027b441a01ff1dd2c190f5e93c454806c11d8806141n], + Y : [0xa7cf28d519be3da65f3170153d278ff247efba98a71a08116215bba5c999a7c7n, + 0x17509b092e845c1266ba0d262cbee6ed0736a96fa347c8bd856dc76b84ebeb96n], + Z : [1n, 0n], +*/ +const SM9_Z256_TWIST_POINT _SM9_Z256_P2 = { + {{0xF9B7213BAF82D65B, 0xEE265948D19C17AB, 0xD2AAB97FD34EC120, 0x3722755292130B08}, + {0x54806C11D8806141, 0xF1DD2C190F5E93C4, 0x597B6027B441A01F, 0x85AEF3D078640C98}}, + {{0x6215BBA5C999A7C7, 0x47EFBA98A71A0811, 0x5F3170153D278FF2, 0xA7CF28D519BE3DA6}, + {0x856DC76B84EBEB96, 0x0736A96FA347C8BD, 0x66BA0D262CBEE6ED, 0x17509B092E845C12}}, + {{1,0,0,0}, {0,0,0,0}}, +}; +const SM9_Z256_TWIST_POINT *SM9_Z256_P2 = &_SM9_Z256_P2; + + +const SM9_Z256_TWIST_POINT _SM9_Z256_Ppubs = { + {{0x8F14D65696EA5E32, 0x414D2177386A92DD, 0x6CE843ED24A3B573, 0x29DBA116152D1F78}, + {0x0AB1B6791B94C408, 0x1CE0711C5E392CFB, 0xE48AFF4B41B56501, 0x9F64080B3084F733}}, + {{0x0E75C05FB4E3216D, 0x1006E85F5CDFF073, 0x1A7CE027B7A46F74, 0x41E00A53DDA532DA}, + {0xE89E1408D0EF1C25, 0xAD3E2FDB1A77F335, 0xB57329F447E3A0CB, 0x69850938ABEA0112}}, + {{1,0,0,0}, {0,0,0,0}}, +}; +const SM9_Z256_TWIST_POINT *SM9_Z256_Ppubs = &_SM9_Z256_Ppubs; + + +// mont params (mod p) +// mu = p^-1 mod 2^64 = 0x76d43bd3d0d11bd5 +// 2^512 mod p = 0x2ea795a656f62fbde479b522d6706e7b88f8105fae1a5d3f27dea312b417e2d2 +// mont(1) mod p = 2^256 mod p = 0x49bffffffd5c590e29fc54b00a7138bade0d6cb4e58511241a9064d81caeba83 +const uint64_t SM9_Z256_MODP_MU = 0x76d43bd3d0d11bd5; +const sm9_z256_t SM9_Z256_MODP_2e512 = {0x27dea312b417e2d2, 0x88f8105fae1a5d3f, 0xe479b522d6706e7b, 0x2ea795a656f62fbd}; +#define SM9_Z256_NEG_P SM9_Z256_MODP_MONT_ONE +const sm9_z256_t SM9_Z256_MODP_MONT_ONE = {0x1a9064d81caeba83, 0xde0d6cb4e5851124, 0x29fc54b00a7138ba, 0x49bffffffd5c590e}; +static const sm9_z256_t SM9_Z256_MODP_MONT_FIVE = {0xb9f2c1e8c8c71995, 0x125df8f246a377fc, 0x25e650d049188d1c, 0x43fffffed866f63}; + + +const SM9_Z256_POINT _SM9_Z256_MONT_P1 = { + {0x22e935e29860501b, 0xa946fd5e0073282c, 0xefd0cec817a649be, 0x5129787c869140b5}, + {0xee779649eb87f7c7, 0x15563cbdec30a576, 0x326353912824efbf, 0x7215717763c39828}, + {0x1a9064d81caeba83, 0xde0d6cb4e5851124, 0x29fc54b00a7138ba, 0x49bffffffd5c590e} +}; +const SM9_Z256_POINT *SM9_Z256_MONT_P1 = &_SM9_Z256_MONT_P1; + +const SM9_Z256_TWIST_POINT _SM9_Z256_MONT_P2 = { + {{0x260226a68ce2da8f, 0x7ee5645edbf6c06b, 0xf8f57c82b1495444, 0x61fcf018bc47c4d1}, + {0xdb6db4822750a8a6, 0x84c6135a5121f134, 0x1874032f88791d41, 0x905112f2b85f3a37}}, + {{0xc03f138f9171c24a, 0x92fbab45a15a3ca7, 0x2445561e2ff77cdb, 0x108495e0c0f62ece}, + {0xf7b82dac4c89bfbb, 0x3706f3f6a49dc12f, 0x1e29de93d3eef769, 0x81e448c3c76a5d53}}, + {{0x1a9064d81caeba83, 0xde0d6cb4e5851124, 0x29fc54b00a7138ba, 0x49bffffffd5c590e}, {0,0,0,0}}, +}; +const SM9_Z256_TWIST_POINT *SM9_Z256_MONT_P2 = &_SM9_Z256_MONT_P2; + +const SM9_Z256_TWIST_POINT _SM9_Z256_MONT_Ppubs = { + {{0xb2e0a02b40b3d927, 0x153e2b9e897e44a0, 0x47cd0690d256c1a9, 0x5d3123b78630320e}, + {0x2c3c3f7ba9fc143e, 0x1f214aa16a4fa43f, 0x424e7e2f0dbc839b, 0x87eecef7fd6531c9}}, + {{0x07a059838aa95e77, 0x6e65e6d455509cae, 0xf921da6493e4f742, 0x9fcf05bded9f2d36}, + {0xdc4fea9a756fc34e, 0xe4e34e772312a7b1, 0xbfa26e7682b1f64a, 0x7f1337b7cda2bf5e}}, + {{0x1a9064d81caeba83, 0xde0d6cb4e5851124, 0x29fc54b00a7138ba, 0x49bffffffd5c590e}, {0,0,0,0}}, +}; +const SM9_Z256_TWIST_POINT *SM9_Z256_MONT_Ppubs = &_SM9_Z256_MONT_Ppubs; + + +void sm9_z256_to_bits(const sm9_z256_t a, char bits[256]) +{ + int i, j; + for (i = 3; i >= 0; i--) { + uint64_t w = a[i]; + for (j = 0; j < 64; j++) { + *bits++ = (w & 0x8000000000000000) ? '1' : '0'; + w <<= 1; + } + } +} + +int sm9_z256_rand_range(sm9_z256_t r, const sm9_z256_t range) +{ + uint8_t buf[256]; + + do { + rand_bytes(buf, sizeof(buf)); + sm9_z256_from_bytes(r, buf); + } while (sm9_z256_cmp(r, range) >= 0); + return 1; +} + +void sm9_z256_from_bytes(sm9_z256_t r, const uint8_t in[32]) +{ + r[3] = GETU64(in); + r[2] = GETU64(in + 8); + r[1] = GETU64(in + 16); + r[0] = GETU64(in + 24); +} + +void sm9_z256_to_bytes(const sm9_z256_t a, uint8_t out[32]) +{ + PUTU64(out, a[3]); + PUTU64(out + 8, a[2]); + PUTU64(out + 16, a[1]); + PUTU64(out + 24, a[0]); +} + +void sm9_z256_copy(sm9_z256_t r, const sm9_z256_t a) +{ + r[3] = a[3]; + r[2] = a[2]; + r[1] = a[1]; + r[0] = a[0]; +} + +void sm9_z256_copy_conditional(sm9_z256_t dst, const sm9_z256_t src, uint64_t move) +{ + uint64_t mask1 = 0-move; + uint64_t mask2 = ~mask1; + + dst[0] = (src[0] & mask1) ^ (dst[0] & mask2); + dst[1] = (src[1] & mask1) ^ (dst[1] & mask2); + dst[2] = (src[2] & mask1) ^ (dst[2] & mask2); + dst[3] = (src[3] & mask1) ^ (dst[3] & mask2); +} + +void sm9_z256_set_zero(sm9_z256_t r) +{ + sm9_z256_copy(r, SM9_Z256_ZERO); +} + +static uint64_t is_zero(uint64_t in) +{ + in |= (0 - in); + in = ~in; + in >>= 63; + return in; +} + +uint64_t sm9_z256_equ(const sm9_z256_t a, const sm9_z256_t b) +{ + uint64_t res; + + res = a[0] ^ b[0]; + res |= a[1] ^ b[1]; + res |= a[2] ^ b[2]; + res |= a[3] ^ b[3]; + + return is_zero(res); +} + +int sm9_z256_cmp(const sm9_z256_t a, const sm9_z256_t b) +{ + if (a[3] > b[3]) return 1; + else if (a[3] < b[3]) return -1; + if (a[2] > b[2]) return 1; + else if (a[2] < b[2]) return -1; + if (a[1] > b[1]) return 1; + else if (a[1] < b[1]) return -1; + if (a[0] > b[0]) return 1; + else if (a[0] < b[0]) return -1; + return 0; +} + +uint64_t sm9_z256_is_zero(const sm9_z256_t a) +{ + return + is_zero(a[0]) & + is_zero(a[1]) & + is_zero(a[2]) & + is_zero(a[3]); +} + +uint64_t sm9_z256_add(sm9_z256_t r, const sm9_z256_t a, const sm9_z256_t b) +{ + uint64_t t, c = 0; + + t = a[0] + b[0]; + c = t < a[0]; + r[0] = t; + + t = a[1] + c; + c = t < a[1]; + r[1] = t + b[1]; + c += r[1] < t; + + t = a[2] + c; + c = t < a[2]; + r[2] = t + b[2]; + c += r[2] < t; + + t = a[3] + c; + c = t < a[3]; + r[3] = t + b[3]; + c += r[3] < t; + + return c; +} + +uint64_t sm9_z256_sub(sm9_z256_t r, const sm9_z256_t a, const sm9_z256_t b) +{ + uint64_t t, c = 0; + + t = a[0] - b[0]; + c = t > a[0]; + r[0] = t; + + t = a[1] - c; + c = t > a[1]; + r[1] = t - b[1]; + c += r[1] > t; + + t = a[2] - c; + c = t > a[2]; + r[2] = t - b[2]; + c += r[2] > t; + + t = a[3] - c; + c = t > a[3]; + r[3] = t - b[3]; + c += r[3] > t; + + return c; +} + +void sm9_z256_mul(uint64_t r[8], const sm9_z256_t a, const sm9_z256_t b) +{ + uint64_t a_[8]; + uint64_t b_[8]; + uint64_t s[16] = {0}; + uint64_t u; + int i, j; + + for (i = 0; i < 4; i++) { + a_[2 * i] = a[i] & 0xffffffff; + b_[2 * i] = b[i] & 0xffffffff; + a_[2 * i + 1] = a[i] >> 32; + b_[2 * i + 1] = b[i] >> 32; + } + + for (i = 0; i < 8; i++) { + u = 0; + for (j = 0; j < 8; j++) { + u = s[i + j] + a_[i] * b_[j] + u; + s[i + j] = u & 0xffffffff; + u >>= 32; + } + s[i + 8] = u; + } + + for (i = 0; i < 8; i++) { + r[i] = (s[2 * i + 1] << 32) | s[2 * i]; + } +} + +uint64_t sm9_z512_add(uint64_t r[8], const uint64_t a[8], const uint64_t b[8]) +{ + uint64_t t, c = 0; + + t = a[0] + b[0]; + c = t < a[0]; + r[0] = t; + + t = a[1] + c; + c = t < a[1]; + r[1] = t + b[1]; + c += r[1] < t; + + t = a[2] + c; + c = t < a[2]; + r[2] = t + b[2]; + c += r[2] < t; + + t = a[3] + c; + c = t < a[3]; + r[3] = t + b[3]; + c += r[3] < t; + + t = a[4] + c; + c = t < a[4]; + r[4] = t + b[4]; + c += r[4] < t; + + t = a[5] + c; + c = t < a[5]; + r[5] = t + b[5]; + c += r[5] < t; + + t = a[6] + c; + c = t < a[6]; + r[6] = t + b[6]; + c += r[6] < t; + + t = a[7] + c; + c = t < a[7]; + r[7] = t + b[7]; + c += r[7] < t; + + return c; +} + +// TODO: not sm9 yet +//int sm9_z256_get_booth(const sm9_z256_t a, unsigned int window_size, int i) +//{ +// uint64_t mask = (1 << window_size) - 1; +// uint64_t wbits; +// int n, j; +// +// if (i == 0) { +// return ((a[0] << 1) & mask) - (a[0] & mask); +// } +// +// j = i * window_size - 1; +// n = j / 64; +// j = j % 64; +// +// wbits = a[n] >> j; +// if ((64 - j) < (window_size + 1) && n < 3) { +// wbits |= a[n + 1] << (64 - j); +// } +// return (wbits & mask) - ((wbits >> 1) & mask); +//} + +int sm9_z256_from_hex(sm9_z256_t r, const char *hex) +{ + uint8_t buf[32]; + size_t len; + if (hex_to_bytes(hex, 64, buf, &len) < 0) { + return -1; + } + sm9_z256_from_bytes(r, buf); + return 1; +} + +void sm9_z256_to_hex(const sm9_z256_t r, char hex[64]) +{ + int i; + for (i = 3; i >= 0; i--) { + (void)sprintf(hex + 16*(3-i), "%016lx", r[i]); + } +} + +void sm9_z256_print_bn(const char *prefix, const sm9_z256_t a) +{ + char hex[65] = {0}; + sm9_z256_to_hex(a, hex); + printf("%s\n%s\n", prefix, hex); +} + +int sm9_z256_equ_hex(const sm9_z256_t a, const char *hex) +{ + sm9_z256_t b; + sm9_z256_from_hex(b, hex); + if (sm9_z256_cmp(a, b) == 0) { + return 1; + } else { + return 0; + } +} + +int sm9_z256_print(FILE *fp, int ind, int fmt, const char *label, const sm9_z256_t a) +{ + format_print(fp, ind, fmt, "%s: %016lx%016lx%016lx%016lx\n", label, a[3], a[2], a[1], a[0]); + return 1; +} + +int sm9_z512_print(FILE *fp, int ind, int fmt, const char *label, const uint64_t a[8]) +{ + format_print(fp, ind, fmt, "%s: %016lx%016lx%016lx%016lx%016lx%016lx%016lx%016lx\n", + label, a[7], a[6], a[5], a[4], a[3], a[2], a[1], a[0]); + return 1; +} + +void sm9_z256_fp_add(sm9_z256_t r, const sm9_z256_t a, const sm9_z256_t b) +{ + uint64_t c; + c = sm9_z256_add(r, a, b); + + if (c) { + // a + b - p = (a + b - 2^256) + (2^256 - p) + (void)sm9_z256_add(r, r, SM9_Z256_NEG_P); + return; + } + if (sm9_z256_cmp(r, SM9_Z256_P) >= 0) { + (void)sm9_z256_sub(r, r, SM9_Z256_P); + } +} + +void sm9_z256_fp_sub(sm9_z256_t r, const sm9_z256_t a, const sm9_z256_t b) +{ + uint64_t c; + c = sm9_z256_sub(r, a, b); + + if (c) { + // a - b + p = (a - b + 2^256) - (2^256 - p) + (void)sm9_z256_sub(r, r, SM9_Z256_NEG_P); + } +} + +void sm9_z256_fp_dbl(sm9_z256_t r, const sm9_z256_t a) +{ + sm9_z256_fp_add(r, a, a); +} + +void sm9_z256_fp_tri(sm9_z256_t r, const sm9_z256_t a) +{ + sm9_z256_t t; + sm9_z256_fp_add(t, a, a); + sm9_z256_fp_add(r, t, a); +} + +void sm9_z256_fp_div2(sm9_z256_t r, const sm9_z256_t a) +{ + uint64_t c = 0; + + if (a[0] & 1) { + c = sm9_z256_add(r, a, SM9_Z256_P); + } else { + r[0] = a[0]; + r[1] = a[1]; + r[2] = a[2]; + r[3] = a[3]; + } + + r[0] = (r[0] >> 1) | ((r[1] & 1) << 63); + r[1] = (r[1] >> 1) | ((r[2] & 1) << 63); + r[2] = (r[2] >> 1) | ((r[3] & 1) << 63); + r[3] = (r[3] >> 1) | ((c & 1) << 63); +} + +void sm9_z256_fp_neg(sm9_z256_t r, const sm9_z256_t a) +{ + (void)sm9_z256_sub(r, SM9_Z256_P, a); +} + +void sm9_u64_mul_add(uint64_t *w0, uint64_t *w1, + const uint64_t a, const uint64_t b, const uint64_t c, const uint64_t d) +{ + uint64_t a_[2]; + uint64_t b_[2]; + uint64_t s[4] = {0}; + uint64_t u; + uint64_t r[2]; + int i, j; + + a_[0] = a & 0xffffffff; + b_[0] = b & 0xffffffff; + a_[1] = a >> 32; + b_[1] = b >> 32; + + for (i = 0; i < 2; i++) { + u = 0; + for (j = 0; j < 2; j++) { + u = s[i + j] + a_[i] * b_[j] + u; + s[i + j] = u & 0xffffffff; + u >>= 32; + } + s[i + 2] = u; + } + + for (i = 0; i < 2; i++) { + r[i] = (s[2 * i + 1] << 32) | s[2 * i]; + } + + r[0] += c; + if (r[0] < c) { + r[1]++; + } + r[0] += d; + if (r[0] < d) { + r[1]++; + } + + *w0 = r[0]; + *w1 = r[1]; +} + +void sm9_z256_fp_mont_mul(sm9_z256_t r, const sm9_z256_t a, const sm9_z256_t b) +{ + sm9_z256_t d = {0}, e = {0}; + uint64_t q, t0, t1, p0, p1, tmp; + uint64_t pre = SM9_Z256_MODP_MU * b[0]; + int i, j; + + for (j = 0; j < 4; j++) { + q = pre * a[j] + SM9_Z256_MODP_MU * (d[0]-e[0]); + + sm9_u64_mul_add(&tmp, &t0, a[j], b[0], d[0], 0); + sm9_u64_mul_add(&tmp, &t1, q, SM9_Z256_P[0], e[0], 0); + + for (i = 1; i < 4; i++) { + sm9_u64_mul_add(&d[i-1], &t0, a[j], b[i], t0, d[i]); + sm9_u64_mul_add(&e[i-1], &t1, q, SM9_Z256_P[i], t1, e[i]); + } + d[3] = t0; + e[3] = t1; + } + + if (sm9_z256_sub(r, d, e)) { + sm9_z256_add(r, r, SM9_Z256_P); + } +} + +void sm9_z256_fp_to_mont(sm9_z256_t r, const sm9_z256_t a) +{ + sm9_z256_fp_mont_mul(r, a, SM9_Z256_MODP_2e512); +} + +void sm9_z256_fp_from_mont(sm9_z256_t r, const sm9_z256_t a) +{ + sm9_z256_fp_mont_mul(r, a, SM9_Z256_ONE); +} + +void sm9_z256_fp_sqr(sm9_z256_t r, const sm9_z256_t a) +{ + sm9_z256_fp_mul(r, a, a); +} + +void sm9_z256_fp_pow(sm9_z256_t r, const sm9_z256_t a, const sm9_z256_t e) +{ + sm9_z256_t t; + uint64_t w; + int i, j; + + // t = mont(1) (mod p) + sm9_z256_copy(t, SM9_Z256_MODP_MONT_ONE); + + for (i = 3; i >= 0; i--) { + w = e[i]; + for (j = 0; j < 64; j++) { + sm9_z256_fp_sqr(t, t); + if (w & 0x8000000000000000) { + sm9_z256_fp_mul(t, t, a); + } + w <<= 1; + } + } + + sm9_z256_copy(r, t); +} + +// TODO: what is sm2_mont_inv? +void sm9_z256_fp_inv(sm9_z256_t r, const sm9_z256_t a) +{ + sm9_z256_t e; + sm9_z256_sub(e, SM9_Z256_P, SM9_Z256_TWO); + sm9_z256_fp_pow(r, a, e); +} + +int sm9_z256_fp_from_bytes(sm9_z256_t r, const uint8_t buf[32]) +{ + sm9_z256_from_bytes(r, buf); + sm9_z256_fp_to_mont(r, r); + if (sm9_z256_cmp(r, SM9_Z256_P) >= 0) { + error_print(); + return -1; + } + return 1; +} + +void sm9_z256_fp_to_bytes(const sm9_z256_t r, uint8_t out[32]) +{ + sm9_z256_t t; + sm9_z256_fp_from_mont(t, r); + sm9_z256_to_bytes(t, out); +} + +int sm9_z256_fp_from_hex(sm9_z256_t r, const char hex[64]) +{ + if (sm9_z256_from_hex(r, hex) != 1) { + error_print(); + return -1; + } + if (sm9_z256_cmp(r, SM9_Z256_P) >= 0) { + error_print(); + return -1; + } + sm9_z256_fp_to_mont(r, r); + return 1; +} + +void sm9_z256_fp_to_hex(const sm9_z256_t r, char hex[64]) +{ + sm9_z256_t t; + sm9_z256_fp_from_mont(t, r); + int i; + for (i = 3; i >= 0; i--) { + (void)sprintf(hex + 16*(3-i), "%016lx", t[i]); + } +} + + +const sm9_z256_fp2 SM9_Z256_FP2_ZERO = {{0,0,0,0},{0,0,0,0}}; +const sm9_z256_fp2 SM9_Z256_FP2_ONE = {{1,0,0,0},{0,0,0,0}}; +const sm9_z256_fp2 SM9_Z256_FP2_U = {{0,0,0,0},{1,0,0,0}}; +static const sm9_z256_fp2 SM9_Z256_FP2_MONT_5U = {{0,0,0,0},{0xb9f2c1e8c8c71995, 0x125df8f246a377fc, 0x25e650d049188d1c, 0x43fffffed866f63}}; + +void sm9_z256_fp2_set_one(sm9_z256_fp2 r) +{ + sm9_z256_fp_copy(r[0], SM9_Z256_MODP_MONT_ONE); + sm9_z256_fp_set_zero(r[1]); +} + +int sm9_z256_fp2_is_one(const sm9_z256_fp2 r) +{ + return sm9_z256_equ(r[0], SM9_Z256_MODP_MONT_ONE) && sm9_z256_is_zero(r[1]); +} + +int sm9_z256_fp2_equ(const sm9_z256_fp2 a, const sm9_z256_fp2 b) +{ + return sm9_z256_equ(a[0], b[0]) && sm9_z256_equ(a[1], b[1]); +} + +void sm9_z256_fp2_copy(sm9_z256_fp2 r, const sm9_z256_fp2 a) +{ + sm9_z256_copy(r[0], a[0]); + sm9_z256_copy(r[1], a[1]); +} + +int sm9_z256_fp2_rand(sm9_z256_fp2 r) +{ + if (sm9_z256_fp_rand(r[0]) != 1 + || sm9_z256_fp_rand(r[1]) != 1) { + error_print(); + return -1; + } + return 1; +} + +void sm9_z256_fp2_to_bytes(const sm9_z256_fp2 a, uint8_t buf[64]) +{ + sm9_z256_fp_to_bytes(a[1], buf); + sm9_z256_fp_to_bytes(a[0], buf + 32); +} + +int sm9_z256_fp2_from_bytes(sm9_z256_fp2 r, const uint8_t buf[64]) +{ + if (sm9_z256_fp_from_bytes(r[1], buf) != 1 + || sm9_z256_fp_from_bytes(r[0], buf + 32) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_z256_fp2_from_hex(sm9_z256_fp2 r, const char hex[129]) +{ + if (sm9_z256_fp_from_hex(r[1], hex) != 1 + || sm9_z256_fp_from_hex(r[0], hex + 65) != 1) { + error_print(); + return -1; + } + /* + if (hex[64] != SM9_Z256_HEX_SEP) { + error_print(); + return -1; + } + */ + return 1; +} + +void sm9_z256_fp2_to_hex(const sm9_z256_fp2 a, char hex[129]) +{ + sm9_z256_fp_to_hex(a[1], hex); + hex[64] = SM9_Z256_HEX_SEP; + sm9_z256_fp_to_hex(a[0], hex + 65); +} + +void sm9_z256_fp2_add(sm9_z256_fp2 r, const sm9_z256_fp2 a, const sm9_z256_fp2 b) +{ + sm9_z256_fp_add(r[0], a[0], b[0]); + sm9_z256_fp_add(r[1], a[1], b[1]); +} + +void sm9_z256_fp2_dbl(sm9_z256_fp2 r, const sm9_z256_fp2 a) +{ + sm9_z256_fp_dbl(r[0], a[0]); + sm9_z256_fp_dbl(r[1], a[1]); +} + +void sm9_z256_fp2_tri(sm9_z256_fp2 r, const sm9_z256_fp2 a) +{ + sm9_z256_fp_tri(r[0], a[0]); + sm9_z256_fp_tri(r[1], a[1]); +} + +void sm9_z256_fp2_sub(sm9_z256_fp2 r, const sm9_z256_fp2 a, const sm9_z256_fp2 b) +{ + sm9_z256_fp_sub(r[0], a[0], b[0]); + sm9_z256_fp_sub(r[1], a[1], b[1]); +} + +void sm9_z256_fp2_neg(sm9_z256_fp2 r, const sm9_z256_fp2 a) +{ + sm9_z256_fp_neg(r[0], a[0]); + sm9_z256_fp_neg(r[1], a[1]); +} + +void sm9_z256_fp2_a_mul_u(sm9_z256_fp2 r, sm9_z256_fp2 a) +{ + sm9_z256_t r0; + + sm9_z256_fp_dbl(r0, a[1]); + sm9_z256_fp_neg(r0, r0); + + sm9_z256_fp_copy(r[1], a[0]); + sm9_z256_fp_copy(r[0], r0); +} + +void sm9_z256_fp2_mul(sm9_z256_fp2 r, const sm9_z256_fp2 a, const sm9_z256_fp2 b) +{ + sm9_z256_t r0, r1, t; + + sm9_z256_fp_add(r0, a[0], a[1]); + sm9_z256_fp_add(t, b[0], b[1]); + sm9_z256_fp_mul(r1, t, r0); + + // r0 = a0 * b0 - 2 * a1 * b1 + sm9_z256_fp_mul(r0, a[0], b[0]); + sm9_z256_fp_mul(t, a[1], b[1]); + + // r1 = (a0 + a1) * (b0 + b1) - a0 * b0 - a1 * b1 + sm9_z256_fp_sub(r1, r1, r0); + sm9_z256_fp_sub(r1, r1, t); + + // r0 + sm9_z256_fp_dbl(t, t); + sm9_z256_fp_sub(r0, r0, t); + + sm9_z256_fp_copy(r[0], r0); + sm9_z256_fp_copy(r[1], r1); +} + +void sm9_z256_fp2_mul_u(sm9_z256_fp2 r, const sm9_z256_fp2 a, const sm9_z256_fp2 b) +{ + sm9_z256_t r0, r1, t; + + // r0 = -2 * (a0 * b1 + a1 * b0) + sm9_z256_fp_mul(r0, a[0], b[1]); + sm9_z256_fp_mul(t, a[1], b[0]); + sm9_z256_fp_add(r0, r0, t); + sm9_z256_fp_dbl(r0, r0); + sm9_z256_fp_neg(r0, r0); + + // r1 = a0 * b0 - 2 * a1 * b1 + sm9_z256_fp_mul(r1, a[0], b[0]); + sm9_z256_fp_mul(t, a[1], b[1]); + sm9_z256_fp_dbl(t, t); + sm9_z256_fp_sub(r1, r1, t); + + sm9_z256_fp_copy(r[0], r0); + sm9_z256_fp_copy(r[1], r1); +} + +void sm9_z256_fp2_mul_fp(sm9_z256_fp2 r, const sm9_z256_fp2 a, const sm9_z256_t k) +{ + sm9_z256_fp_mul(r[0], a[0], k); + sm9_z256_fp_mul(r[1], a[1], k); +} + +void sm9_z256_fp2_sqr(sm9_z256_fp2 r, const sm9_z256_fp2 a) +{ + sm9_z256_t r0, r1, c0, c1; + + // r0 = (a0 + a1) * (a0 - 2a1) + a0 * a1 + sm9_z256_fp_mul(r1, a[0], a[1]); + sm9_z256_fp_add(c0, a[0], a[1]); + sm9_z256_fp_dbl(c1, a[1]); + sm9_z256_fp_sub(c1, a[0], c1); + sm9_z256_fp_mul(r0, c0, c1); + sm9_z256_fp_add(r0, r0, r1); + + // r1 = 2 * a0 * a1 + sm9_z256_fp_dbl(r1, r1); + + sm9_z256_copy(r[0], r0); + sm9_z256_copy(r[1], r1); +} + +void sm9_z256_fp2_sqr_u(sm9_z256_fp2 r, const sm9_z256_fp2 a) +{ + sm9_z256_t r0, r1, t; + + // r0 = -4 * a0 * a1 + sm9_z256_fp_mul(r0, a[0], a[1]); + sm9_z256_fp_dbl(r0, r0); + sm9_z256_fp_dbl(r0, r0); + sm9_z256_fp_neg(r0, r0); + + // r1 = a0^2 - 2 * a1^2 + sm9_z256_fp_sqr(r1, a[0]); + sm9_z256_fp_sqr(t, a[1]); + sm9_z256_fp_dbl(t, t); + sm9_z256_fp_sub(r1, r1, t); + + sm9_z256_fp_copy(r[0], r0); + sm9_z256_fp_copy(r[1], r1); +} + +void sm9_z256_fp2_inv(sm9_z256_fp2 r, const sm9_z256_fp2 a) +{ + if (sm9_z256_fp_is_zero(a[0])) { + // r0 = 0 + sm9_z256_fp_set_zero(r[0]); + // r1 = -(2 * a1)^-1 + sm9_z256_fp_dbl(r[1], a[1]); + sm9_z256_fp_inv(r[1], r[1]); + sm9_z256_fp_neg(r[1], r[1]); + + } else if (sm9_z256_fp_is_zero(a[1])) { + /* r1 = 0 */ + sm9_z256_fp_set_zero(r[1]); + /* r0 = a0^-1 */ + sm9_z256_fp_inv(r[0], a[0]); + + } else { + sm9_z256_t k, t; + + // k = (a[0]^2 + 2 * a[1]^2)^-1 + sm9_z256_fp_sqr(k, a[0]); + sm9_z256_fp_sqr(t, a[1]); + sm9_z256_fp_dbl(t, t); + sm9_z256_fp_add(k, k, t); + sm9_z256_fp_inv(k, k); + + // r[0] = a[0] * k + sm9_z256_fp_mul(r[0], a[0], k); + + // r[1] = -a[1] * k + sm9_z256_fp_mul(r[1], a[1], k); + sm9_z256_fp_neg(r[1], r[1]); + } +} + +void sm9_z256_fp2_div(sm9_z256_fp2 r, const sm9_z256_fp2 a, const sm9_z256_fp2 b) +{ + sm9_z256_fp2 t; + sm9_z256_fp2_inv(t, b); + sm9_z256_fp2_mul(r, a, t); +} + +void sm9_z256_fp2_div2(sm9_z256_fp2 r, const sm9_z256_fp2 a) +{ + sm9_z256_fp_div2(r[0], a[0]); + sm9_z256_fp_div2(r[1], a[1]); +} + + +const sm9_z256_fp4 SM9_Z256_FP4_ZERO = {{{0,0,0,0},{0,0,0,0}}, {{0,0,0,0},{0,0,0,0}}}; +const sm9_z256_fp4 SM9_Z256_FP4_MONT_ONE = {{{0x1a9064d81caeba83, 0xde0d6cb4e5851124, 0x29fc54b00a7138ba, 0x49bffffffd5c590e},{0,0,0,0}}, {{0,0,0,0},{0,0,0,0}}}; + +int sm9_z256_fp4_equ(const sm9_z256_fp4 a, const sm9_z256_fp4 b) +{ + return sm9_z256_fp2_equ(a[0], b[0]) && sm9_z256_fp2_equ(a[1], b[1]); +} + +int sm9_z256_fp4_rand(sm9_z256_fp4 r) +{ + if (sm9_z256_fp2_rand(r[1]) != 1 + || sm9_z256_fp2_rand(r[0]) != 1) { + error_print(); + return -1; + } + return 1; +} + +void sm9_z256_fp4_copy(sm9_z256_fp4 r, const sm9_z256_fp4 a) +{ + sm9_z256_fp2_copy(r[0], a[0]); + sm9_z256_fp2_copy(r[1], a[1]); +} + +void sm9_z256_fp4_to_bytes(const sm9_z256_fp4 a, uint8_t buf[128]) +{ + sm9_z256_fp2_to_bytes(a[1], buf); + sm9_z256_fp2_to_bytes(a[0], buf + 64); +} + +int sm9_z256_fp4_from_bytes(sm9_z256_fp4 r, const uint8_t buf[128]) +{ + if (sm9_z256_fp2_from_bytes(r[1], buf) != 1 + || sm9_z256_fp2_from_bytes(r[0], buf + 64) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_z256_fp4_from_hex(sm9_z256_fp4 r, const char hex[65 * 4]) +{ + if (sm9_z256_fp2_from_hex(r[1], hex) != 1 + || hex[129] != SM9_Z256_HEX_SEP + || sm9_z256_fp2_from_hex(r[0], hex + 130) != 1) { + error_print(); + return -1; + } + return 1; +} + +void sm9_z256_fp4_to_hex(const sm9_z256_fp4 a, char hex[259]) +{ + sm9_z256_fp2_to_hex(a[1], hex); + hex[129] = SM9_Z256_HEX_SEP; + sm9_z256_fp2_to_hex(a[0], hex + 130); +} + +void sm9_z256_fp4_add(sm9_z256_fp4 r, const sm9_z256_fp4 a, const sm9_z256_fp4 b) +{ + sm9_z256_fp2_add(r[0], a[0], b[0]); + sm9_z256_fp2_add(r[1], a[1], b[1]); +} + +void sm9_z256_fp4_dbl(sm9_z256_fp4 r, const sm9_z256_fp4 a) +{ + sm9_z256_fp2_dbl(r[0], a[0]); + sm9_z256_fp2_dbl(r[1], a[1]); +} + +void sm9_z256_fp4_sub(sm9_z256_fp4 r, const sm9_z256_fp4 a, const sm9_z256_fp4 b) +{ + sm9_z256_fp2_sub(r[0], a[0], b[0]); + sm9_z256_fp2_sub(r[1], a[1], b[1]); +} + +void sm9_z256_fp4_neg(sm9_z256_fp4 r, const sm9_z256_fp4 a) +{ + sm9_z256_fp2_neg(r[0], a[0]); + sm9_z256_fp2_neg(r[1], a[1]); +} + +void sm9_z256_fp4_div2(sm9_z256_fp4 r, const sm9_z256_fp4 a) +{ + sm9_z256_fp2_div2(r[0], a[0]); + sm9_z256_fp2_div2(r[1], a[1]); +} + +void sm9_z256_fp4_a_mul_v(sm9_z256_fp4 r, sm9_z256_fp4 a) +{ + sm9_z256_fp2 r0; + + sm9_z256_fp2_a_mul_u(r0, a[1]); + + sm9_z256_fp2_copy(r[1], a[0]); + sm9_z256_fp2_copy(r[0], r0); +} + +void sm9_z256_fp4_mul(sm9_z256_fp4 r, const sm9_z256_fp4 a, const sm9_z256_fp4 b) +{ + sm9_z256_fp2 r0, r1, t; + + sm9_z256_fp2_add(r0, a[0], a[1]); + sm9_z256_fp2_add(t, b[0], b[1]); + sm9_z256_fp2_mul(r1, t, r0); + + sm9_z256_fp2_mul(r0, a[0], b[0]); + sm9_z256_fp2_mul(t, a[1], b[1]); + + sm9_z256_fp2_sub(r1, r1, r0); + sm9_z256_fp2_sub(r1, r1, t); + + sm9_z256_fp2_a_mul_u(t, t); + sm9_z256_fp2_add(r0, r0, t); + + sm9_z256_fp2_copy(r[0], r0); + sm9_z256_fp2_copy(r[1], r1); +} + +void sm9_z256_fp4_mul_fp(sm9_z256_fp4 r, const sm9_z256_fp4 a, const sm9_z256_t k) +{ + sm9_z256_fp2_mul_fp(r[0], a[0], k); + sm9_z256_fp2_mul_fp(r[1], a[1], k); +} + +void sm9_z256_fp4_mul_fp2(sm9_z256_fp4 r, const sm9_z256_fp4 a, const sm9_z256_fp2 b0) +{ + sm9_z256_fp2_mul(r[0], a[0], b0); + sm9_z256_fp2_mul(r[1], a[1], b0); +} + +void sm9_z256_fp4_mul_v(sm9_z256_fp4 r, const sm9_z256_fp4 a, const sm9_z256_fp4 b) +{ + sm9_z256_fp2 r0, r1, t; + + sm9_z256_fp2_mul_u(r0, a[0], b[1]); + sm9_z256_fp2_mul_u(t, a[1], b[0]); + sm9_z256_fp2_add(r0, r0, t); + + sm9_z256_fp2_mul(r1, a[0], b[0]); + sm9_z256_fp2_mul_u(t, a[1], b[1]); + sm9_z256_fp2_add(r1, r1, t); + + sm9_z256_fp2_copy(r[0], r0); + sm9_z256_fp2_copy(r[1], r1); +} + +void sm9_z256_fp4_sqr(sm9_z256_fp4 r, const sm9_z256_fp4 a) +{ + sm9_z256_fp2 r0, r1, t; + + sm9_z256_fp2_add(r1, a[0], a[1]); + sm9_z256_fp2_sqr(r1, r1); + + sm9_z256_fp2_sqr(r0, a[0]); + sm9_z256_fp2_sqr(t, a[1]); + + sm9_z256_fp2_sub(r1, r1, r0); + sm9_z256_fp2_sub(r1, r1, t); + + sm9_z256_fp2_a_mul_u(t, t); + sm9_z256_fp2_add(r0, r0, t); + + sm9_z256_fp2_copy(r[0], r0); + sm9_z256_fp2_copy(r[1], r1); +} + +void sm9_z256_fp4_sqr_v(sm9_z256_fp4 r, const sm9_z256_fp4 a) +{ + sm9_z256_fp2 r0, r1, t; + + sm9_z256_fp2_mul_u(t, a[0], a[1]); + sm9_z256_fp2_dbl(r0, t); + + sm9_z256_fp2_sqr(r1, a[0]); + sm9_z256_fp2_sqr_u(t, a[1]); + sm9_z256_fp2_add(r1, r1, t); + + sm9_z256_fp2_copy(r[0], r0); + sm9_z256_fp2_copy(r[1], r1); +} + +void sm9_z256_fp4_inv(sm9_z256_fp4 r, const sm9_z256_fp4 a) +{ + sm9_z256_fp2 r0, r1, k; + + sm9_z256_fp2_sqr_u(k, a[1]); + sm9_z256_fp2_sqr(r0, a[0]); + sm9_z256_fp2_sub(k, k, r0); + sm9_z256_fp2_inv(k, k); + + sm9_z256_fp2_mul(r0, a[0], k); + sm9_z256_fp2_neg(r0, r0); + + sm9_z256_fp2_mul(r1, a[1], k); + + sm9_z256_fp2_copy(r[0], r0); + sm9_z256_fp2_copy(r[1], r1); +} + + + + +void sm9_z256_fp12_copy(sm9_z256_fp12 r, const sm9_z256_fp12 a) +{ + sm9_z256_fp4_copy(r[0], a[0]); + sm9_z256_fp4_copy(r[1], a[1]); + sm9_z256_fp4_copy(r[2], a[2]); +} + +int sm9_z256_fp12_rand(sm9_z256_fp12 r) +{ + if (sm9_z256_fp4_rand(r[0]) != 1 + || sm9_z256_fp4_rand(r[1]) != 1 + || sm9_z256_fp4_rand(r[2]) != 1) { + error_print(); + return -1; + } + return 1; +} + +void sm9_z256_fp12_set_zero(sm9_z256_fp12 r) +{ + sm9_z256_fp4_copy(r[0], SM9_Z256_FP4_ZERO); + sm9_z256_fp4_copy(r[1], SM9_Z256_FP4_ZERO); + sm9_z256_fp4_copy(r[2], SM9_Z256_FP4_ZERO); +} + +void sm9_z256_fp12_set_one(sm9_z256_fp12 r) +{ + sm9_z256_fp4_copy(r[0], SM9_Z256_FP4_MONT_ONE); + sm9_z256_fp4_copy(r[1], SM9_Z256_FP4_ZERO); + sm9_z256_fp4_copy(r[2], SM9_Z256_FP4_ZERO); +} + +int sm9_z256_fp12_from_hex(sm9_z256_fp12 r, const char hex[65 * 12 - 1]) +{ + if (sm9_z256_fp4_from_hex(r[2], hex) != 1 + || hex[65 * 4 - 1] != SM9_Z256_HEX_SEP + || sm9_z256_fp4_from_hex(r[1], hex + 65 * 4) != 1 + || hex[65 * 4 - 1] != SM9_Z256_HEX_SEP + || sm9_z256_fp4_from_hex(r[0], hex + 65 * 8) != 1) { + error_print(); + return -1; + } + return 1; +} + +void sm9_z256_fp12_to_hex(const sm9_z256_fp12 a, char hex[65 * 12 - 1]) +{ + sm9_z256_fp4_to_hex(a[2], hex); + hex[65 * 4 - 1] = SM9_Z256_HEX_SEP; + sm9_z256_fp4_to_hex(a[1], hex + 65 * 4); + hex[65 * 8 - 1] = SM9_Z256_HEX_SEP; + sm9_z256_fp4_to_hex(a[0], hex + 65 * 8); +} + +void sm9_z256_fp12_to_bytes(const sm9_z256_fp12 a, uint8_t buf[32 * 12]) +{ + sm9_z256_fp4_to_bytes(a[2], buf); + sm9_z256_fp4_to_bytes(a[1], buf + 32 * 4); + sm9_z256_fp4_to_bytes(a[0], buf + 32 * 8); +} + +void sm9_z256_fp12_print(const char *prefix, const sm9_z256_fp12 a) +{ + char hex[65 * 12]; + sm9_z256_fp12_to_hex(a, hex); + printf("%s\n%s\n", prefix, hex); +} + +void sm9_z256_fp12_set(sm9_z256_fp12 r, const sm9_z256_fp4 a0, const sm9_z256_fp4 a1, const sm9_z256_fp4 a2) +{ + sm9_z256_fp4_copy(r[0], a0); + sm9_z256_fp4_copy(r[1], a1); + sm9_z256_fp4_copy(r[2], a2); +} + +int sm9_z256_fp12_equ(const sm9_z256_fp12 a, const sm9_z256_fp12 b) +{ + return sm9_z256_fp4_equ(a[0], b[0]) + && sm9_z256_fp4_equ(a[1], b[1]) + && sm9_z256_fp4_equ(a[2], b[2]); +} + +void sm9_z256_fp12_add(sm9_z256_fp12 r, const sm9_z256_fp12 a, const sm9_z256_fp12 b) +{ + sm9_z256_fp4_add(r[0], a[0], b[0]); + sm9_z256_fp4_add(r[1], a[1], b[1]); + sm9_z256_fp4_add(r[2], a[2], b[2]); +} + +void sm9_z256_fp12_dbl(sm9_z256_fp12 r, const sm9_z256_fp12 a) +{ + sm9_z256_fp4_dbl(r[0], a[0]); + sm9_z256_fp4_dbl(r[1], a[1]); + sm9_z256_fp4_dbl(r[2], a[2]); +} + +void sm9_z256_fp12_tri(sm9_z256_fp12 r, const sm9_z256_fp12 a) +{ + sm9_z256_fp12 t; + sm9_z256_fp12_dbl(t, a); + sm9_z256_fp12_add(r, t, a); +} + +void sm9_z256_fp12_sub(sm9_z256_fp12 r, const sm9_z256_fp12 a, const sm9_z256_fp12 b) +{ + sm9_z256_fp4_sub(r[0], a[0], b[0]); + sm9_z256_fp4_sub(r[1], a[1], b[1]); + sm9_z256_fp4_sub(r[2], a[2], b[2]); +} + +void sm9_z256_fp12_neg(sm9_z256_fp12 r, const sm9_z256_fp12 a) +{ + sm9_z256_fp4_neg(r[0], a[0]); + sm9_z256_fp4_neg(r[1], a[1]); + sm9_z256_fp4_neg(r[2], a[2]); +} + +void sm9_z256_fp12_mul(sm9_z256_fp12 r, const sm9_z256_fp12 a, const sm9_z256_fp12 b) +{ + sm9_z256_fp4 r0, r1, r2; + sm9_z256_fp4 t, k0, k1; + sm9_z256_fp4 m0, m1, m2; + + sm9_z256_fp4_mul(m0, a[0], b[0]); + sm9_z256_fp4_mul(m1, a[1], b[1]); + sm9_z256_fp4_mul(m2, a[2], b[2]); + + sm9_z256_fp4_add(k0, a[1], a[2]); + sm9_z256_fp4_add(k1, b[1], b[2]); + sm9_z256_fp4_mul(t, k0, k1); + sm9_z256_fp4_sub(t, t, m1); + sm9_z256_fp4_sub(t, t, m2); + sm9_z256_fp4_a_mul_v(t, t); + sm9_z256_fp4_add(r0, t, m0); + + sm9_z256_fp4_add(k0, a[0], a[2]); + sm9_z256_fp4_add(k1, b[0], b[2]); + sm9_z256_fp4_mul(t, k0, k1); + sm9_z256_fp4_sub(t, t, m0); + sm9_z256_fp4_sub(t, t, m2); + sm9_z256_fp4_add(r2, t, m1); + + sm9_z256_fp4_add(k0, a[0], a[1]); + sm9_z256_fp4_add(k1, b[0], b[1]); + sm9_z256_fp4_mul(t, k0, k1); + sm9_z256_fp4_sub(t, t, m0); + sm9_z256_fp4_sub(t, t, m1); + sm9_z256_fp4_a_mul_v(m2, m2); + sm9_z256_fp4_add(r1, t, m2); + + sm9_z256_fp4_copy(r[0], r0); + sm9_z256_fp4_copy(r[1], r1); + sm9_z256_fp4_copy(r[2], r2); +} + +// this is slower than the version below +// void sm9_z256_fp12_sqr(sm9_z256_fp12 r, const sm9_z256_fp12 a) +// { +// sm9_z256_fp4 r0, r1, r2, t; + +// sm9_z256_fp4_sqr(r0, a[0]); +// sm9_z256_fp4_mul_v(t, a[1], a[2]); +// sm9_z256_fp4_dbl(t, t); +// sm9_z256_fp4_add(r0, r0, t); + +// sm9_z256_fp4_mul(r1, a[0], a[1]); +// sm9_z256_fp4_dbl(r1, r1); +// sm9_z256_fp4_sqr_v(t, a[2]); +// sm9_z256_fp4_add(r1, r1, t); + +// sm9_z256_fp4_mul(r2, a[0], a[2]); +// sm9_z256_fp4_dbl(r2, r2); +// sm9_z256_fp4_sqr(t, a[1]); +// sm9_z256_fp4_add(r2, r2, t); + +// sm9_z256_fp4_copy(r[0], r0); +// sm9_z256_fp4_copy(r[1], r1); +// sm9_z256_fp4_copy(r[2], r2); +// } + +void sm9_z256_fp12_sqr(sm9_z256_fp12 r, const sm9_z256_fp12 a) +{ + sm9_z256_fp4 h0, h1, h2, t; + sm9_z256_fp4 s0, s1, s2, s3; + + sm9_z256_fp4_sqr(h0, a[0]); + sm9_z256_fp4_sqr(h1, a[2]); + sm9_z256_fp4_add(s0, a[2], a[0]); + + sm9_z256_fp4_sub(t, s0, a[1]); + sm9_z256_fp4_sqr(s1, t); + + sm9_z256_fp4_add(t, s0, a[1]); + sm9_z256_fp4_sqr(s0, t); + + sm9_z256_fp4_mul(s2, a[1], a[2]); + sm9_z256_fp4_dbl(s2, s2); + + sm9_z256_fp4_add(s3, s0, s1); + sm9_z256_fp4_div2(s3, s3); + + sm9_z256_fp4_sub(t, s3, h1); + sm9_z256_fp4_sub(h2, t, h0); + + sm9_z256_fp4_a_mul_v(h1, h1); + sm9_z256_fp4_add(h1, h1, s0); + sm9_z256_fp4_sub(h1, h1, s2); + sm9_z256_fp4_sub(h1, h1, s3); + + sm9_z256_fp4_a_mul_v(s2, s2); + sm9_z256_fp4_add(h0, h0, s2); + + sm9_z256_fp4_copy(r[0], h0); + sm9_z256_fp4_copy(r[1], h1); + sm9_z256_fp4_copy(r[2], h2); +} + +void sm9_z256_fp12_inv(sm9_z256_fp12 r, const sm9_z256_fp12 a) +{ + if (sm9_z256_fp4_is_zero(a[2])) { + sm9_z256_fp4 k, t; + + sm9_z256_fp4_sqr(k, a[0]); + sm9_z256_fp4_mul(k, k, a[0]); + sm9_z256_fp4_sqr_v(t, a[1]); + sm9_z256_fp4_mul(t, t, a[1]); + sm9_z256_fp4_add(k, k, t); + sm9_z256_fp4_inv(k, k); + + sm9_z256_fp4_sqr(r[2], a[1]); + sm9_z256_fp4_mul(r[2], r[2], k); + + sm9_z256_fp4_mul(r[1], a[0], a[1]); + sm9_z256_fp4_mul(r[1], r[1], k); + sm9_z256_fp4_neg(r[1], r[1]); + + sm9_z256_fp4_sqr(r[0], a[0]); + sm9_z256_fp4_mul(r[0], r[0], k); + + } else { + sm9_z256_fp4 t0, t1, t2, t3; + + sm9_z256_fp4_sqr(t0, a[1]); + sm9_z256_fp4_mul(t1, a[0], a[2]); + sm9_z256_fp4_sub(t0, t0, t1); + + sm9_z256_fp4_mul(t1, a[0], a[1]); + sm9_z256_fp4_sqr_v(t2, a[2]); + sm9_z256_fp4_sub(t1, t1, t2); + + sm9_z256_fp4_sqr(t2, a[0]); + sm9_z256_fp4_mul_v(t3, a[1], a[2]); + sm9_z256_fp4_sub(t2, t2, t3); + + sm9_z256_fp4_sqr(t3, t1); + sm9_z256_fp4_mul(r[0], t0, t2); + sm9_z256_fp4_sub(t3, t3, r[0]); + sm9_z256_fp4_inv(t3, t3); + sm9_z256_fp4_mul(t3, a[2], t3); + + sm9_z256_fp4_mul(r[0], t2, t3); + + sm9_z256_fp4_mul(r[1], t1, t3); + sm9_z256_fp4_neg(r[1], r[1]); + + sm9_z256_fp4_mul(r[2], t0, t3); + } +} + +void sm9_z256_fp12_pow(sm9_z256_fp12 r, const sm9_z256_fp12 a, const sm9_z256_t k) +{ + sm9_z256_fp12 t; + uint64_t w; + int i, j; + + assert(sm9_z256_cmp(k, SM9_Z256_N_MINUS_ONE) < 0); + sm9_z256_fp12_set_one(t); + + for (i = 3; i >=0; i--) { + w = k[i]; + for (j = 0; j < 64; j++) { + sm9_z256_fp12_sqr(t, t); + if (w & 0x8000000000000000) { + sm9_z256_fp12_mul(t, t, a); + } + w <<= 1; + } + } + sm9_z256_fp12_copy(r, t); +} + +void sm9_z256_fp2_conjugate(sm9_z256_fp2 r, const sm9_z256_fp2 a) +{ + sm9_z256_fp_copy(r[0], a[0]); + sm9_z256_fp_neg (r[1], a[1]); +} + +void sm9_z256_fp2_frobenius(sm9_z256_fp2 r, const sm9_z256_fp2 a) +{ + sm9_z256_fp2_conjugate(r, a); +} + +// beta = 0x6c648de5dc0a3f2cf55acc93ee0baf159f9d411806dc5177f5b21fd3da24d011 +// alpha1 = 0x3f23ea58e5720bdb843c6cfa9c08674947c5c86e0ddd04eda91d8354377b698b +// alpha2 = 0xf300000002a3a6f2780272354f8b78f4d5fc11967be65334 +// alpha3 = 0x6c648de5dc0a3f2cf55acc93ee0baf159f9d411806dc5177f5b21fd3da24d011 +// alpha4 = 0xf300000002a3a6f2780272354f8b78f4d5fc11967be65333 +// alpha5 = 0x2d40a38cf6983351711e5f99520347cc57d778a9f8ff4c8a4c949c7fa2a96686 + +// mont version (mod p) +static const sm9_z256_fp2 SM9_MONT_BETA = {{0x39b4ef0f3ee72529, 0xdb043bf508582782, 0xb8554ab054ac91e3, 0x9848eec25498cab5}, {0}}; +static const sm9_z256_t SM9_MONT_ALPHA1 = {0x1a98dfbd4575299f, 0x9ec8547b245c54fd, 0xf51f5eac13df846c, 0x9ef74015d5a16393}; +static const sm9_z256_t SM9_MONT_ALPHA2 = {0xb626197dce4736ca, 0x08296b3557ed0186, 0x9c705db2fd91512a, 0x1c753e748601c992}; +static const sm9_z256_t SM9_MONT_ALPHA3 = {0x39b4ef0f3ee72529, 0xdb043bf508582782, 0xb8554ab054ac91e3, 0x9848eec25498cab5}; +static const sm9_z256_t SM9_MONT_ALPHA4 = {0x81054fcd94e9c1c4, 0x4c0e91cb8ce2df3e, 0x4877b452e8aedfb4, 0x88f53e748b491776}; +static const sm9_z256_t SM9_MONT_ALPHA5 = {0x048baa79dcc34107, 0x5e2e7ac4fe76c161, 0x99399754365bd4bc, 0xaf91aeac819b0e13}; + + +void sm9_z256_fp4_frobenius(sm9_z256_fp4 r, const sm9_z256_fp4 a) +{ + sm9_z256_fp2_conjugate(r[0], a[0]); + sm9_z256_fp2_conjugate(r[1], a[1]); + sm9_z256_fp2_mul(r[1], r[1], SM9_MONT_BETA); +} + +void sm9_z256_fp4_conjugate(sm9_z256_fp4 r, const sm9_z256_fp4 a) +{ + sm9_z256_fp2_copy(r[0], a[0]); + sm9_z256_fp2_neg(r[1], a[1]); +} + +void sm9_z256_fp4_frobenius2(sm9_z256_fp4 r, const sm9_z256_fp4 a) +{ + sm9_z256_fp4_conjugate(r, a); +} + +void sm9_z256_fp4_frobenius3(sm9_z256_fp4 r, const sm9_z256_fp4 a) +{ + sm9_z256_fp2_conjugate(r[0], a[0]); + sm9_z256_fp2_conjugate(r[1], a[1]); + sm9_z256_fp2_mul(r[1], r[1], SM9_MONT_BETA); + sm9_z256_fp2_neg(r[1], r[1]); +} + +void sm9_z256_fp12_frobenius(sm9_z256_fp12 r, const sm9_z256_fp12 x) +{ + const sm9_z256_fp2 *xa = x[0]; + const sm9_z256_fp2 *xb = x[1]; + const sm9_z256_fp2 *xc = x[2]; + + sm9_z256_fp4 ra; + sm9_z256_fp4 rb; + sm9_z256_fp4 rc; + + sm9_z256_fp2_conjugate(ra[0], xa[0]); + sm9_z256_fp2_conjugate(ra[1], xa[1]); + sm9_z256_fp2_mul_fp(ra[1], ra[1], SM9_MONT_ALPHA3); + + sm9_z256_fp2_conjugate(rb[0], xb[0]); + sm9_z256_fp2_mul_fp(rb[0], rb[0], SM9_MONT_ALPHA1); + sm9_z256_fp2_conjugate(rb[1], xb[1]); + sm9_z256_fp2_mul_fp(rb[1], rb[1], SM9_MONT_ALPHA4); + + sm9_z256_fp2_conjugate(rc[0], xc[0]); + sm9_z256_fp2_mul_fp(rc[0], rc[0], SM9_MONT_ALPHA2); + sm9_z256_fp2_conjugate(rc[1], xc[1]); + sm9_z256_fp2_mul_fp(rc[1], rc[1], SM9_MONT_ALPHA5); + + sm9_z256_fp12_set(r, ra, rb, rc); +} + +void sm9_z256_fp12_frobenius2(sm9_z256_fp12 r, const sm9_z256_fp12 x) +{ + sm9_z256_fp4 a; + sm9_z256_fp4 b; + sm9_z256_fp4 c; + + sm9_z256_fp4_conjugate(a, x[0]); + sm9_z256_fp4_conjugate(b, x[1]); + sm9_z256_fp4_mul_fp(b, b, SM9_MONT_ALPHA2); + sm9_z256_fp4_conjugate(c, x[2]); + sm9_z256_fp4_mul_fp(c, c, SM9_MONT_ALPHA4); + + sm9_z256_fp4_copy(r[0], a); + sm9_z256_fp4_copy(r[1], b); + sm9_z256_fp4_copy(r[2], c); +} + +void sm9_z256_fp12_frobenius3(sm9_z256_fp12 r, const sm9_z256_fp12 x) +{ + const sm9_z256_fp2 *xa = x[0]; + const sm9_z256_fp2 *xb = x[1]; + const sm9_z256_fp2 *xc = x[2]; + + sm9_z256_fp4 ra; + sm9_z256_fp4 rb; + sm9_z256_fp4 rc; + + sm9_z256_fp2_conjugate(ra[0], xa[0]); + sm9_z256_fp2_conjugate(ra[1], xa[1]); + sm9_z256_fp2_mul(ra[1], ra[1], SM9_MONT_BETA); + sm9_z256_fp2_neg(ra[1], ra[1]); + + sm9_z256_fp2_conjugate(rb[0], xb[0]); + sm9_z256_fp2_mul(rb[0], rb[0], SM9_MONT_BETA); + sm9_z256_fp2_conjugate(rb[1], xb[1]); + + sm9_z256_fp2_conjugate(rc[0], xc[0]); + sm9_z256_fp2_neg(rc[0], rc[0]); + sm9_z256_fp2_conjugate(rc[1], xc[1]); + sm9_z256_fp2_mul(rc[1], rc[1], SM9_MONT_BETA); + + sm9_z256_fp4_copy(r[0], ra); + sm9_z256_fp4_copy(r[1], rb); + sm9_z256_fp4_copy(r[2], rc); +} + +void sm9_z256_fp12_frobenius6(sm9_z256_fp12 r, const sm9_z256_fp12 x) +{ + sm9_z256_fp4 a; + sm9_z256_fp4 b; + sm9_z256_fp4 c; + + sm9_z256_fp4_copy(a, x[0]); + sm9_z256_fp4_copy(b, x[1]); + sm9_z256_fp4_copy(c, x[2]); + + sm9_z256_fp4_conjugate(a, a); + sm9_z256_fp4_conjugate(b, b); + sm9_z256_fp4_neg(b, b); + sm9_z256_fp4_conjugate(c, c); + + sm9_z256_fp4_copy(r[0], a); + sm9_z256_fp4_copy(r[1], b); + sm9_z256_fp4_copy(r[2], c); +} + + + +void sm9_z256_point_from_hex(SM9_Z256_POINT *R, const char hex[65 * 2]) +{ + sm9_z256_fp_from_hex(R->X, hex); + sm9_z256_fp_from_hex(R->Y, hex + 65); + sm9_z256_copy(R->Z, SM9_Z256_MODP_MONT_ONE); +} + +int sm9_z256_point_is_at_infinity(const SM9_Z256_POINT *P) +{ + return sm9_z256_fp_is_zero(P->Z); +} + +void sm9_z256_point_set_infinity(SM9_Z256_POINT *R) +{ + sm9_z256_copy(R->X, SM9_Z256_MODP_MONT_ONE); + sm9_z256_copy(R->Y, SM9_Z256_MODP_MONT_ONE); + sm9_z256_fp_set_zero(R->Z); +} + +void sm9_z256_point_copy(SM9_Z256_POINT *R, const SM9_Z256_POINT *P) +{ + *R = *P; +} + +// xy from this function are still mont +void sm9_z256_point_get_xy(const SM9_Z256_POINT *P, sm9_z256_t x, sm9_z256_t y) +{ + sm9_z256_t z_inv; + + assert(!sm9_z256_fp_is_zero(P->Z)); + + if (sm9_z256_fp_equ(P->Z, SM9_Z256_MODP_MONT_ONE)) { + sm9_z256_fp_copy(x, P->X); + sm9_z256_fp_copy(y, P->Y); + } + + sm9_z256_fp_inv(z_inv, P->Z); + if (y) + sm9_z256_fp_mul(y, P->Y, z_inv); + sm9_z256_fp_sqr(z_inv, z_inv); + sm9_z256_fp_mul(x, P->X, z_inv); + if (y) + sm9_z256_fp_mul(y, y, z_inv); +} + +int sm9_z256_point_equ(const SM9_Z256_POINT *P, const SM9_Z256_POINT *Q) +{ + sm9_z256_t t1, t2, t3, t4; + sm9_z256_fp_sqr(t1, P->Z); + sm9_z256_fp_sqr(t2, Q->Z); + sm9_z256_fp_mul(t3, P->X, t2); + sm9_z256_fp_mul(t4, Q->X, t1); + if (!sm9_z256_fp_equ(t3, t4)) { + return 0; + } + sm9_z256_fp_mul(t1, t1, P->Z); + sm9_z256_fp_mul(t2, t2, Q->Z); + sm9_z256_fp_mul(t3, P->Y, t2); + sm9_z256_fp_mul(t4, Q->Y, t1); + return sm9_z256_fp_equ(t3, t4); +} + +int sm9_z256_point_is_on_curve(const SM9_Z256_POINT *P) +{ + sm9_z256_t t0, t1, t2; + if (sm9_z256_fp_equ(P->Z, SM9_Z256_MODP_MONT_ONE)) { + sm9_z256_fp_sqr(t0, P->Y); + sm9_z256_fp_sqr(t1, P->X); + sm9_z256_fp_mul(t1, t1, P->X); + sm9_z256_fp_add(t1, t1, SM9_Z256_MODP_MONT_FIVE); + } else { + sm9_z256_fp_sqr(t0, P->X); + sm9_z256_fp_mul(t0, t0, P->X); + sm9_z256_fp_sqr(t1, P->Z); + sm9_z256_fp_sqr(t2, t1); + sm9_z256_fp_mul(t1, t1, t2); + sm9_z256_fp_mul(t1, t1, SM9_Z256_MODP_MONT_FIVE); + sm9_z256_fp_add(t1, t0, t1); + sm9_z256_fp_sqr(t0, P->Y); + } + if (sm9_z256_fp_equ(t0, t1) != 1) { + error_print(); + return 0; + } + return 1; +} + +void sm9_z256_point_dbl(SM9_Z256_POINT *R, const SM9_Z256_POINT *P) +{ + const uint64_t *X1 = P->X; + const uint64_t *Y1 = P->Y; + const uint64_t *Z1 = P->Z; + sm9_z256_t X3, Y3, Z3, T1, T2, T3; + + if (sm9_z256_point_is_at_infinity(P)) { + sm9_z256_point_copy(R, P); + return; + } + + sm9_z256_fp_sqr(T2, X1); + sm9_z256_fp_tri(T2, T2); + sm9_z256_fp_dbl(Y3, Y1); + sm9_z256_fp_mul(Z3, Y3, Z1); + sm9_z256_fp_sqr(Y3, Y3); + sm9_z256_fp_mul(T3, Y3, X1); + sm9_z256_fp_sqr(Y3, Y3); + sm9_z256_fp_div2(Y3, Y3); + sm9_z256_fp_sqr(X3, T2); + sm9_z256_fp_dbl(T1, T3); + sm9_z256_fp_sub(X3, X3, T1); + sm9_z256_fp_sub(T1, T3, X3); + sm9_z256_fp_mul(T1, T1, T2); + sm9_z256_fp_sub(Y3, T1, Y3); + + sm9_z256_fp_copy(R->X, X3); + sm9_z256_fp_copy(R->Y, Y3); + sm9_z256_fp_copy(R->Z, Z3); +} + +void sm9_z256_point_add(SM9_Z256_POINT *R, const SM9_Z256_POINT *P, const SM9_Z256_POINT *Q) +{ + sm9_z256_t x; + sm9_z256_t y; + sm9_z256_point_get_xy(Q, x, y); + + const uint64_t *X1 = P->X; + const uint64_t *Y1 = P->Y; + const uint64_t *Z1 = P->Z; + const uint64_t *x2 = x; + const uint64_t *y2 = y; + sm9_z256_t X3, Y3, Z3, T1, T2, T3, T4; + + if (sm9_z256_point_is_at_infinity(Q)) { + sm9_z256_point_copy(R, P); + return; + } + if (sm9_z256_point_is_at_infinity(P)) { + sm9_z256_point_copy(R, Q); + return; + } + + sm9_z256_fp_sqr(T1, Z1); + sm9_z256_fp_mul(T2, T1, Z1); + sm9_z256_fp_mul(T1, T1, x2); + sm9_z256_fp_mul(T2, T2, y2); + sm9_z256_fp_sub(T1, T1, X1); + sm9_z256_fp_sub(T2, T2, Y1); + + if (sm9_z256_fp_is_zero(T1)) { + if (sm9_z256_fp_is_zero(T2)) { + sm9_z256_point_dbl(R, Q); + return; + } else { + sm9_z256_point_set_infinity(R); + return; + } + } + + sm9_z256_fp_mul(Z3, Z1, T1); + sm9_z256_fp_sqr(T3, T1); + sm9_z256_fp_mul(T4, T3, T1); + sm9_z256_fp_mul(T3, T3, X1); + sm9_z256_fp_dbl(T1, T3); + sm9_z256_fp_sqr(X3, T2); + sm9_z256_fp_sub(X3, X3, T1); + sm9_z256_fp_sub(X3, X3, T4); + sm9_z256_fp_sub(T3, T3, X3); + sm9_z256_fp_mul(T3, T3, T2); + sm9_z256_fp_mul(T4, T4, Y1); + sm9_z256_fp_sub(Y3, T3, T4); + + sm9_z256_fp_copy(R->X, X3); + sm9_z256_fp_copy(R->Y, Y3); + sm9_z256_fp_copy(R->Z, Z3); +} + +void sm9_z256_point_neg(SM9_Z256_POINT *R, const SM9_Z256_POINT *P) +{ + sm9_z256_fp_copy(R->X, P->X); + sm9_z256_fp_neg(R->Y, P->Y); + sm9_z256_fp_copy(R->Z, P->Z); +} + +void sm9_z256_point_sub(SM9_Z256_POINT *R, const SM9_Z256_POINT *P, const SM9_Z256_POINT *Q) +{ + SM9_Z256_POINT _T, *T = &_T; + sm9_z256_point_neg(T, Q); + sm9_z256_point_add(R, P, T); +} + +void sm9_z256_point_mul(SM9_Z256_POINT *R, const sm9_z256_t k, const SM9_Z256_POINT *P) +{ + char kbits[257]; + SM9_Z256_POINT _Q, *Q = &_Q; + int i; + + sm9_z256_to_bits(k, kbits); + sm9_z256_point_set_infinity(Q); + for (i = 0; i < 256; i++) { + sm9_z256_point_dbl(Q, Q); + if (kbits[i] == '1') { + sm9_z256_point_add(Q, Q, P); + } + } + sm9_z256_point_copy(R, Q); +} + +void sm9_z256_point_mul_generator(SM9_Z256_POINT *R, const sm9_z256_t k) +{ + sm9_z256_point_mul(R, k, SM9_Z256_MONT_P1); +} + + +int sm9_z256_point_print(FILE *fp, int fmt, int ind, const char *label, const SM9_Z256_POINT *P) +{ + uint8_t buf[65]; + sm9_z256_point_to_uncompressed_octets(P, buf); + format_bytes(fp, fmt, ind, label, buf, sizeof(buf)); + return 1; +} + +int sm9_z256_twist_point_print(FILE *fp, int fmt, int ind, const char *label, const SM9_Z256_TWIST_POINT *P) +{ + uint8_t buf[129]; + sm9_z256_twist_point_to_uncompressed_octets(P, buf); + format_bytes(fp, fmt, ind, label, buf, sizeof(buf)); + return 1; +} + +void sm9_z256_twist_point_from_hex(SM9_Z256_TWIST_POINT *R, const char hex[65 * 4]) +{ + sm9_z256_fp2_from_hex(R->X, hex); + sm9_z256_fp2_from_hex(R->Y, hex + 65 * 2); + sm9_z256_fp2_set_one(R->Z); +} + +int sm9_z256_twist_point_is_at_infinity(const SM9_Z256_TWIST_POINT *P) +{ + return sm9_z256_fp2_is_zero(P->Z); +} + +void sm9_z256_twist_point_set_infinity(SM9_Z256_TWIST_POINT *R) +{ + sm9_z256_fp2_set_one(R->X); + sm9_z256_fp2_set_one(R->Y); + sm9_z256_fp2_set_zero(R->Z); +} + +void sm9_z256_twist_point_get_xy(const SM9_Z256_TWIST_POINT *P, sm9_z256_fp2 x, sm9_z256_fp2 y) +{ + sm9_z256_fp2 z_inv; + + assert(!sm9_z256_fp2_is_zero(P->Z)); + + if (sm9_z256_fp2_is_one(P->Z)) { + sm9_z256_fp2_copy(x, P->X); + sm9_z256_fp2_copy(y, P->Y); + } + + sm9_z256_fp2_inv(z_inv, P->Z); + if (y) + sm9_z256_fp2_mul(y, P->Y, z_inv); + sm9_z256_fp2_sqr(z_inv, z_inv); + sm9_z256_fp2_mul(x, P->X, z_inv); + if (y) + sm9_z256_fp2_mul(y, y, z_inv); +} + +int sm9_z256_twist_point_equ(const SM9_Z256_TWIST_POINT *P, const SM9_Z256_TWIST_POINT *Q) +{ + sm9_z256_fp2 t1, t2, t3, t4; + + sm9_z256_fp2_sqr(t1, P->Z); + sm9_z256_fp2_sqr(t2, Q->Z); + sm9_z256_fp2_mul(t3, P->X, t2); + sm9_z256_fp2_mul(t4, Q->X, t1); + if (!sm9_z256_fp2_equ(t3, t4)) { + return 0; + } + sm9_z256_fp2_mul(t1, t1, P->Z); + sm9_z256_fp2_mul(t2, t2, Q->Z); + sm9_z256_fp2_mul(t3, P->Y, t2); + sm9_z256_fp2_mul(t4, Q->Y, t1); + return sm9_z256_fp2_equ(t3, t4); +} + +int sm9_z256_twist_point_is_on_curve(const SM9_Z256_TWIST_POINT *P) +{ + sm9_z256_fp2 t0, t1, t2; + + if (sm9_z256_fp2_is_one(P->Z)) { + sm9_z256_fp2_sqr(t0, P->Y); + sm9_z256_fp2_sqr(t1, P->X); + sm9_z256_fp2_mul(t1, t1, P->X); + sm9_z256_fp2_add(t1, t1, SM9_Z256_FP2_MONT_5U); + + } else { + sm9_z256_fp2_sqr(t0, P->X); + sm9_z256_fp2_mul(t0, t0, P->X); + sm9_z256_fp2_sqr(t1, P->Z); + sm9_z256_fp2_sqr(t2, t1); + sm9_z256_fp2_mul(t1, t1, t2); + sm9_z256_fp2_mul(t1, t1, SM9_Z256_FP2_MONT_5U); + sm9_z256_fp2_add(t1, t0, t1); + sm9_z256_fp2_sqr(t0, P->Y); + } + + return sm9_z256_fp2_equ(t0, t1); +} + +void sm9_z256_twist_point_neg(SM9_Z256_TWIST_POINT *R, const SM9_Z256_TWIST_POINT *P) +{ + sm9_z256_fp2_copy(R->X, P->X); + sm9_z256_fp2_neg(R->Y, P->Y); + sm9_z256_fp2_copy(R->Z, P->Z); +} + +void sm9_z256_twist_point_dbl(SM9_Z256_TWIST_POINT *R, const SM9_Z256_TWIST_POINT *P) +{ + const sm9_z256_t *X1 = P->X; + const sm9_z256_t *Y1 = P->Y; + const sm9_z256_t *Z1 = P->Z; + sm9_z256_fp2 X3, Y3, Z3, T1, T2, T3; + + if (sm9_z256_twist_point_is_at_infinity(P)) { + sm9_z256_twist_point_copy(R, P); + return; + } + sm9_z256_fp2_sqr(T2, X1); + sm9_z256_fp2_tri(T2, T2); + sm9_z256_fp2_dbl(Y3, Y1); + sm9_z256_fp2_mul(Z3, Y3, Z1); + sm9_z256_fp2_sqr(Y3, Y3); + sm9_z256_fp2_mul(T3, Y3, X1); + sm9_z256_fp2_sqr(Y3, Y3); + sm9_z256_fp2_div2(Y3, Y3); + sm9_z256_fp2_sqr(X3, T2); + sm9_z256_fp2_dbl(T1, T3); + sm9_z256_fp2_sub(X3, X3, T1); + sm9_z256_fp2_sub(T1, T3, X3); + sm9_z256_fp2_mul(T1, T1, T2); + sm9_z256_fp2_sub(Y3, T1, Y3); + + sm9_z256_fp2_copy(R->X, X3); + sm9_z256_fp2_copy(R->Y, Y3); + sm9_z256_fp2_copy(R->Z, Z3); +} + +void sm9_z256_twist_point_add(SM9_Z256_TWIST_POINT *R, const SM9_Z256_TWIST_POINT *P, const SM9_Z256_TWIST_POINT *Q) +{ + const sm9_z256_t *X1 = P->X; + const sm9_z256_t *Y1 = P->Y; + const sm9_z256_t *Z1 = P->Z; + const sm9_z256_t *x2 = Q->X; + const sm9_z256_t *y2 = Q->Y; + sm9_z256_fp2 X3, Y3, Z3, T1, T2, T3, T4; + + if (sm9_z256_twist_point_is_at_infinity(Q)) { + sm9_z256_twist_point_copy(R, P); + return; + } + if (sm9_z256_twist_point_is_at_infinity(P)) { + sm9_z256_twist_point_copy(R, Q); + return; + } + + sm9_z256_fp2_sqr(T1, Z1); + sm9_z256_fp2_mul(T2, T1, Z1); + sm9_z256_fp2_mul(T1, T1, x2); + sm9_z256_fp2_mul(T2, T2, y2); + sm9_z256_fp2_sub(T1, T1, X1); + sm9_z256_fp2_sub(T2, T2, Y1); + if (sm9_z256_fp2_is_zero(T1)) { + if (sm9_z256_fp2_is_zero(T2)) { + sm9_z256_twist_point_dbl(R, Q); + return; + } else { + sm9_z256_twist_point_set_infinity(R); + return; + } + } + sm9_z256_fp2_mul(Z3, Z1, T1); + sm9_z256_fp2_sqr(T3, T1); + sm9_z256_fp2_mul(T4, T3, T1); + sm9_z256_fp2_mul(T3, T3, X1); + sm9_z256_fp2_dbl(T1, T3); + sm9_z256_fp2_sqr(X3, T2); + sm9_z256_fp2_sub(X3, X3, T1); + sm9_z256_fp2_sub(X3, X3, T4); + sm9_z256_fp2_sub(T3, T3, X3); + sm9_z256_fp2_mul(T3, T3, T2); + sm9_z256_fp2_mul(T4, T4, Y1); + sm9_z256_fp2_sub(Y3, T3, T4); + + sm9_z256_fp2_copy(R->X, X3); + sm9_z256_fp2_copy(R->Y, Y3); + sm9_z256_fp2_copy(R->Z, Z3); +} + +void sm9_z256_twist_point_sub(SM9_Z256_TWIST_POINT *R, const SM9_Z256_TWIST_POINT *P, const SM9_Z256_TWIST_POINT *Q) +{ + SM9_Z256_TWIST_POINT _T, *T = &_T; + sm9_z256_twist_point_neg(T, Q); + sm9_z256_twist_point_add_full(R, P, T); +} + +void sm9_z256_twist_point_add_full(SM9_Z256_TWIST_POINT *R, const SM9_Z256_TWIST_POINT *P, const SM9_Z256_TWIST_POINT *Q) +{ + const sm9_z256_t *X1 = P->X; + const sm9_z256_t *Y1 = P->Y; + const sm9_z256_t *Z1 = P->Z; + const sm9_z256_t *X2 = Q->X; + const sm9_z256_t *Y2 = Q->Y; + const sm9_z256_t *Z2 = Q->Z; + sm9_z256_fp2 T1, T2, T3, T4, T5, T6, T7, T8; + + if (sm9_z256_twist_point_is_at_infinity(Q)) { + sm9_z256_twist_point_copy(R, P); + return; + } + if (sm9_z256_twist_point_is_at_infinity(P)) { + sm9_z256_twist_point_copy(R, Q); + return; + } + + sm9_z256_fp2_sqr(T1, Z1); + sm9_z256_fp2_sqr(T2, Z2); + sm9_z256_fp2_mul(T3, X2, T1); + sm9_z256_fp2_mul(T4, X1, T2); + sm9_z256_fp2_add(T5, T3, T4); + sm9_z256_fp2_sub(T3, T3, T4); + sm9_z256_fp2_mul(T1, T1, Z1); + sm9_z256_fp2_mul(T1, T1, Y2); + sm9_z256_fp2_mul(T2, T2, Z2); + sm9_z256_fp2_mul(T2, T2, Y1); + sm9_z256_fp2_add(T6, T1, T2); + sm9_z256_fp2_sub(T1, T1, T2); + + if (sm9_z256_fp2_is_zero(T1) && sm9_z256_fp2_is_zero(T3)) { + sm9_z256_twist_point_dbl(R, P); + return; + } + if (sm9_z256_fp2_is_zero(T1) && sm9_z256_fp2_is_zero(T6)) { + sm9_z256_twist_point_set_infinity(R); + return; + } + + sm9_z256_fp2_sqr(T6, T1); + sm9_z256_fp2_mul(T7, T3, Z1); + sm9_z256_fp2_mul(T7, T7, Z2); + sm9_z256_fp2_sqr(T8, T3); + sm9_z256_fp2_mul(T5, T5, T8); + sm9_z256_fp2_mul(T3, T3, T8); + sm9_z256_fp2_mul(T4, T4, T8); + sm9_z256_fp2_sub(T6, T6, T5); + sm9_z256_fp2_sub(T4, T4, T6); + sm9_z256_fp2_mul(T1, T1, T4); + sm9_z256_fp2_mul(T2, T2, T3); + sm9_z256_fp2_sub(T1, T1, T2); + + sm9_z256_fp2_copy(R->X, T6); + sm9_z256_fp2_copy(R->Y, T1); + sm9_z256_fp2_copy(R->Z, T7); +} + +void sm9_z256_twist_point_mul(SM9_Z256_TWIST_POINT *R, const sm9_z256_t k, const SM9_Z256_TWIST_POINT *P) +{ + SM9_Z256_TWIST_POINT _Q, *Q = &_Q; + char kbits[256]; + int i; + + sm9_z256_to_bits(k, kbits); + sm9_z256_twist_point_set_infinity(Q); + for (i = 0; i < 256; i++) { + sm9_z256_twist_point_dbl(Q, Q); + if (kbits[i] == '1') { + sm9_z256_twist_point_add_full(Q, Q, P); + } + } + sm9_z256_twist_point_copy(R, Q); +} + +void sm9_z256_twist_point_mul_generator(SM9_Z256_TWIST_POINT *R, const sm9_z256_t k) +{ + sm9_z256_twist_point_mul(R, k, SM9_Z256_MONT_P2); +} + +void sm9_z256_eval_g_tangent(sm9_z256_fp12 num, sm9_z256_fp12 den, const SM9_Z256_TWIST_POINT *P, const SM9_Z256_POINT *Q) +{ + sm9_z256_t x; + sm9_z256_t y; + sm9_z256_point_get_xy(Q, x, y); + + const sm9_z256_t *XP = P->X; + const sm9_z256_t *YP = P->Y; + const sm9_z256_t *ZP = P->Z; + const uint64_t *xQ = x; + const uint64_t *yQ = y; + + sm9_z256_t *a0 = num[0][0]; + sm9_z256_t *a1 = num[0][1]; + sm9_z256_t *a4 = num[2][0]; + sm9_z256_t *b1 = den[0][1]; + + sm9_z256_fp2 t0; + sm9_z256_fp2 t1; + sm9_z256_fp2 t2; + + sm9_z256_fp12_set_zero(num); + sm9_z256_fp12_set_zero(den); + + sm9_z256_fp2_sqr(t0, ZP); + sm9_z256_fp2_mul(t1, t0, ZP); + sm9_z256_fp2_mul(b1, t1, YP); + + sm9_z256_fp2_mul_fp(t2, b1, yQ); + sm9_z256_fp2_neg(a1, t2); + + sm9_z256_fp2_sqr(t1, XP); + sm9_z256_fp2_mul(t0, t0, t1); + sm9_z256_fp2_mul_fp(t0, t0, xQ); + sm9_z256_fp2_tri(t0, t0); + sm9_z256_fp2_div2(a4, t0); + + sm9_z256_fp2_mul(t1, t1, XP); + sm9_z256_fp2_tri(t1, t1); + sm9_z256_fp2_div2(t1, t1); + sm9_z256_fp2_sqr(t0, YP); + sm9_z256_fp2_sub(a0, t0, t1); +} + +void sm9_z256_eval_g_line(sm9_z256_fp12 num, sm9_z256_fp12 den, const SM9_Z256_TWIST_POINT *T, const SM9_Z256_TWIST_POINT *P, const SM9_Z256_POINT *Q) +{ + sm9_z256_t x; + sm9_z256_t y; + sm9_z256_point_get_xy(Q, x, y); + + const sm9_z256_t *XT = T->X; + const sm9_z256_t *YT = T->Y; + const sm9_z256_t *ZT = T->Z; + const sm9_z256_t *XP = P->X; + const sm9_z256_t *YP = P->Y; + const sm9_z256_t *ZP = P->Z; + const uint64_t *xQ = x; + const uint64_t *yQ = y; + + sm9_z256_t *a0 = num[0][0]; + sm9_z256_t *a1 = num[0][1]; + sm9_z256_t *a4 = num[2][0]; + sm9_z256_t *b1 = den[0][1]; + + sm9_z256_fp2 T0, T1, T2, T3, T4; + + + sm9_z256_fp12_set_zero(num); + sm9_z256_fp12_set_zero(den); + + sm9_z256_fp2_sqr(T0, ZP); + sm9_z256_fp2_mul(T1, T0, XT); + sm9_z256_fp2_mul(T0, T0, ZP); + sm9_z256_fp2_sqr(T2, ZT); + sm9_z256_fp2_mul(T3, T2, XP); + sm9_z256_fp2_mul(T2, T2, ZT); + sm9_z256_fp2_mul(T2, T2, YP); + sm9_z256_fp2_sub(T1, T1, T3); + sm9_z256_fp2_mul(T1, T1, ZT); + sm9_z256_fp2_mul(T1, T1, ZP); + sm9_z256_fp2_mul(T4, T1, T0); + sm9_z256_fp2_copy(b1, T4); + sm9_z256_fp2_mul(T1, T1, YP); + sm9_z256_fp2_mul(T3, T0, YT); + sm9_z256_fp2_sub(T3, T3, T2); + sm9_z256_fp2_mul(T0, T0, T3); + sm9_z256_fp2_mul_fp(T0, T0, xQ); + sm9_z256_fp2_copy(a4, T0); + sm9_z256_fp2_mul(T3, T3, XP); + sm9_z256_fp2_mul(T3, T3, ZP); + sm9_z256_fp2_sub(T1, T1, T3); + sm9_z256_fp2_copy(a0, T1); + sm9_z256_fp2_mul_fp(T2, T4, yQ); + sm9_z256_fp2_neg(T2, T2); + sm9_z256_fp2_copy(a1, T2); +} + +void sm9_z256_twist_point_pi1(SM9_Z256_TWIST_POINT *R, const SM9_Z256_TWIST_POINT *P) +{ + // c = 0x3f23ea58e5720bdb843c6cfa9c08674947c5c86e0ddd04eda91d8354377b698b + // mont version + const sm9_z256_t c = {0x1a98dfbd4575299f, 0x9ec8547b245c54fd, 0xf51f5eac13df846c, 0x9ef74015d5a16393}; + sm9_z256_fp2_conjugate(R->X, P->X); + sm9_z256_fp2_conjugate(R->Y, P->Y); + sm9_z256_fp2_conjugate(R->Z, P->Z); + sm9_z256_fp2_mul_fp(R->Z, R->Z, c); + +} + +void sm9_z256_twist_point_pi2(SM9_Z256_TWIST_POINT *R, const SM9_Z256_TWIST_POINT *P) +{ + // c = 0xf300000002a3a6f2780272354f8b78f4d5fc11967be65334 + // mont version + const sm9_z256_t c = {0xb626197dce4736ca, 0x8296b3557ed0186, 0x9c705db2fd91512a, 0x1c753e748601c992}; + sm9_z256_fp2_copy(R->X, P->X); + sm9_z256_fp2_copy(R->Y, P->Y); + sm9_z256_fp2_mul_fp(R->Z, P->Z, c); +} + +void sm9_z256_twist_point_neg_pi2(SM9_Z256_TWIST_POINT *R, const SM9_Z256_TWIST_POINT *P) +{ + // c = 0xf300000002a3a6f2780272354f8b78f4d5fc11967be65334 + // mont version + const sm9_z256_t c = {0xb626197dce4736ca, 0x8296b3557ed0186, 0x9c705db2fd91512a, 0x1c753e748601c992}; + sm9_z256_fp2_copy(R->X, P->X); + sm9_z256_fp2_neg(R->Y, P->Y); + sm9_z256_fp2_mul_fp(R->Z, P->Z, c); +} + + +void sm9_z256_final_exponent_hard_part(sm9_z256_fp12 r, const sm9_z256_fp12 f) +{ + // a2 = 0xd8000000019062ed0000b98b0cb27659 + // a3 = 0x2400000000215d941 + const sm9_z256_t a2 = {0x0000b98b0cb27659, 0xd8000000019062ed, 0, 0}; + const sm9_z256_t a3 = {0x400000000215d941, 0x2, 0, 0}; + const sm9_z256_t nine = {9,0,0,0}; + sm9_z256_fp12 t0, t1, t2, t3; + + sm9_z256_fp12_pow(t0, f, a3); + sm9_z256_fp12_inv(t0, t0); + sm9_z256_fp12_frobenius(t1, t0); + sm9_z256_fp12_mul(t1, t0, t1); + + sm9_z256_fp12_mul(t0, t0, t1); + sm9_z256_fp12_frobenius(t2, f); + sm9_z256_fp12_mul(t3, t2, f); + sm9_z256_fp12_pow(t3, t3, nine); + + sm9_z256_fp12_mul(t0, t0, t3); + sm9_z256_fp12_sqr(t3, f); + sm9_z256_fp12_sqr(t3, t3); + sm9_z256_fp12_mul(t0, t0, t3); + sm9_z256_fp12_sqr(t2, t2); + sm9_z256_fp12_mul(t2, t2, t1); + sm9_z256_fp12_frobenius2(t1, f); + sm9_z256_fp12_mul(t1, t1, t2); + + sm9_z256_fp12_pow(t2, t1, a2); + sm9_z256_fp12_mul(t0, t2, t0); + sm9_z256_fp12_frobenius3(t1, f); + sm9_z256_fp12_mul(t1, t1, t0); + + sm9_z256_fp12_copy(r, t1); +} + +void sm9_z256_final_exponent(sm9_z256_fp12 r, const sm9_z256_fp12 f) +{ + sm9_z256_fp12 t0; + sm9_z256_fp12 t1; + + sm9_z256_fp12_frobenius6(t0, f); + sm9_z256_fp12_inv(t1, f); + sm9_z256_fp12_mul(t0, t0, t1); + sm9_z256_fp12_frobenius2(t1, t0); + sm9_z256_fp12_mul(t0, t0, t1); + sm9_z256_final_exponent_hard_part(t0, t0); + + sm9_z256_fp12_copy(r, t0); +} + +void sm9_z256_pairing(sm9_z256_fp12 r, const SM9_Z256_TWIST_POINT *Q, const SM9_Z256_POINT *P) +{ + const char *abits = "00100000000000000000000000000000000000010000101100020200101000020"; + + SM9_Z256_TWIST_POINT _T, *T = &_T; + SM9_Z256_TWIST_POINT _Q1, *Q1 = &_Q1; + SM9_Z256_TWIST_POINT _Q2, *Q2 = &_Q2; + + sm9_z256_fp12 f_num; + sm9_z256_fp12 f_den; + sm9_z256_fp12 g_num; + sm9_z256_fp12 g_den; + int i; + + sm9_z256_twist_point_copy(T, Q); + + sm9_z256_fp12_set_one(f_num); + sm9_z256_fp12_set_one(f_den); + + for (i = 0; i < strlen(abits); i++) { + sm9_z256_fp12_sqr(f_num, f_num); + sm9_z256_fp12_sqr(f_den, f_den); + sm9_z256_eval_g_tangent(g_num, g_den, T, P); + sm9_z256_fp12_mul(f_num, f_num, g_num); + sm9_z256_fp12_mul(f_den, f_den, g_den); + + sm9_z256_twist_point_dbl(T, T); + + if (abits[i] == '1') { + sm9_z256_eval_g_line(g_num, g_den, T, Q, P); + sm9_z256_fp12_mul(f_num, f_num, g_num); + sm9_z256_fp12_mul(f_den, f_den, g_den); + sm9_z256_twist_point_add_full(T, T, Q); + } else if (abits[i] == '2') { + sm9_z256_twist_point_neg(Q1, Q); + sm9_z256_eval_g_line(g_num, g_den, T, Q1, P); + sm9_z256_fp12_mul(f_num, f_num, g_num); + sm9_z256_fp12_mul(f_den, f_den, g_den); + sm9_z256_twist_point_add_full(T, T, Q1); + } + } + + sm9_z256_twist_point_pi1(Q1, Q); + sm9_z256_twist_point_neg_pi2(Q2, Q); + + sm9_z256_eval_g_line(g_num, g_den, T, Q1, P); + sm9_z256_fp12_mul(f_num, f_num, g_num); + sm9_z256_fp12_mul(f_den, f_den, g_den); + sm9_z256_twist_point_add_full(T, T, Q1); + + sm9_z256_eval_g_line(g_num, g_den, T, Q2, P); + sm9_z256_fp12_mul(f_num, f_num, g_num); + sm9_z256_fp12_mul(f_den, f_den, g_den); + sm9_z256_twist_point_add_full(T, T, Q2); + + sm9_z256_fp12_inv(f_den, f_den); + sm9_z256_fp12_mul(r, f_num, f_den); + + sm9_z256_final_exponent(r, r); +} + + +// mont params (mod n) +// mu = n^-1 mod 2^64 = 0x76d43bd3d0d11bd5 +// 2^512 mod n = 0x2ea795a656f62fbde479b522d6706e7b88f8105fae1a5d3f27dea312b417e2d2 +// mont(1) mod n = 2^256 mod n = 0x49bffffffd5c590e29fc54b00a7138bade0d6cb4e58511241a9064d81caeba83 +const uint64_t SM9_Z256_MODN_MU = 0xe2fd99dcae68b4ad; +const sm9_z256_t SM9_Z256_MODN_2e512 = {0x7598cd79cd750c35, 0xe4a08110bb6daeab, 0xbfee4bae7d78a1f9, 0x8894f5d163695d0e}; +#define SM9_Z256_NEG_N SM9_Z256_MODN_MONT_ONE +const sm9_z256_t SM9_Z256_MODN_MONT_ONE = {0x1a911e63296130db, 0xb60d6cb4e7157411, 0x29fc54b00a7138bb, 0x49bffffffd5c590e}; + + +void sm9_z256_fn_add(sm9_z256_t r, const sm9_z256_t a, const sm9_z256_t b) +{ + uint64_t c; + c = sm9_z256_add(r, a, b); + + if (c) { + // a + b - n = (a + b - 2^256) + (2^256 - n) + (void)sm9_z256_add(r, r, SM9_Z256_NEG_N); + return; + } + if (sm9_z256_cmp(r, SM9_Z256_N) >= 0) { + (void)sm9_z256_sub(r, r, SM9_Z256_N); + } +} + +void sm9_z256_fn_sub(sm9_z256_t r, const sm9_z256_t a, const sm9_z256_t b) +{ + uint64_t c; + c = sm9_z256_sub(r, a, b); + + if (c) { + // a - b + n = (a - b + 2^256) - (2^256 - n) + (void)sm9_z256_sub(r, r, SM9_Z256_NEG_N); + } +} + +void sm9_z256_fn_mont_mul(sm9_z256_t r, const sm9_z256_t a, const sm9_z256_t b) +{ + sm9_z256_t d = {0}, e = {0}; + uint64_t q, t0, t1, p0, p1, tmp; + uint64_t pre = SM9_Z256_MODN_MU * b[0]; + int i, j; + + for (j = 0; j < 4; j++) { + q = pre * a[j] + SM9_Z256_MODN_MU * (d[0]-e[0]); + + sm9_u64_mul_add(&tmp, &t0, a[j], b[0], d[0], 0); + sm9_u64_mul_add(&tmp, &t1, q, SM9_Z256_N[0], e[0], 0); + + for (i = 1; i < 4; i++) { + sm9_u64_mul_add(&d[i-1], &t0, a[j], b[i], t0, d[i]); + sm9_u64_mul_add(&e[i-1], &t1, q, SM9_Z256_N[i], t1, e[i]); + } + d[3] = t0; + e[3] = t1; + } + + if (sm9_z256_sub(r, d, e)) { + sm9_z256_add(r, r, SM9_Z256_N); + } +} + +void sm9_z256_fn_to_mont(sm9_z256_t r, const sm9_z256_t a) +{ + sm9_z256_fn_mont_mul(r, a, SM9_Z256_MODN_2e512); +} + +void sm9_z256_fn_from_mont(sm9_z256_t r, const sm9_z256_t a) +{ + sm9_z256_fn_mont_mul(r, a, SM9_Z256_ONE); +} + +// we use mont_mul for pow and inv, use normal mul for other cases +void sm9_z256_fn_mul(sm9_z256_t r, const sm9_z256_t a, const sm9_z256_t b) +{ + sm9_z256_t x, y; + sm9_z256_fn_to_mont(x, a); + sm9_z256_fn_to_mont(y, b); + sm9_z256_fn_mont_mul(r, x, y); + sm9_z256_fn_from_mont(r, r); +} + +void sm9_z256_fn_pow(sm9_z256_t r, const sm9_z256_t a, const sm9_z256_t e) +{ + sm9_z256_t t, x; + uint64_t w; + int i, j; + + sm9_z256_fn_to_mont(x, a); + + // t = mont(1) (mod n) + sm9_z256_copy(t, SM9_Z256_MODN_MONT_ONE); + + for (i = 3; i >= 0; i--) { + w = e[i]; + for (j = 0; j < 64; j++) { + sm9_z256_fn_mont_mul(t, t, t); + if (w & 0x8000000000000000) { + sm9_z256_fn_mont_mul(t, t, x); + } + w <<= 1; + } + } + + sm9_z256_fn_from_mont(r, t); +} + +void sm9_z256_fn_inv(sm9_z256_t r, const sm9_z256_t a) +{ + sm9_z256_t e; + sm9_z256_sub(e, SM9_Z256_N, SM9_Z256_TWO); + sm9_z256_fn_pow(r, a, e); +} + +int sm9_z256_fn_from_bytes(sm9_z256_t a, const uint8_t in[32]) +{ + sm9_z256_from_bytes(a, in); + return 1; +} + + +// for H1() and H2() +// h = (Ha mod (n-1)) + 1; h in [1, n-1], n is the curve order, Ha is 40 bytes from hash +void sm9_z256_fn_from_hash(sm9_z256_t h, const uint8_t Ha[40]) +{ + int i; + uint64_t res[8] = {0}; + uint64_t tmp[8] = {0}; + + for (i = 0; i < 5; i++) { + res[4-i] = GETU64(Ha + (8*i)); + } + while (res[4] != 0) { + sm9_z256_mul(tmp, res + 4, SM9_Z256_2e256_N_MINUS_ONE); + sm9_z256_set_zero(res + 4); + sm9_z512_add(res, res, tmp); + } + sm9_z256_copy(h, res); + if (sm9_z256_cmp(h, SM9_Z256_N_MINUS_ONE) >= 0) { + sm9_z256_sub(h, h, SM9_Z256_N_MINUS_ONE); + } + sm9_z256_fn_add(h, h, SM9_Z256_ONE); +} + +int sm9_z256_point_to_uncompressed_octets(const SM9_Z256_POINT *P, uint8_t octets[65]) +{ + sm9_z256_t x; + sm9_z256_t y; + sm9_z256_point_get_xy(P, x, y); + octets[0] = 0x04; + sm9_z256_fp_to_bytes(x, octets + 1); // fp_to_bytes include from_mont + sm9_z256_fp_to_bytes(y, octets + 32 + 1); + return 1; +} + +int sm9_z256_point_from_uncompressed_octets(SM9_Z256_POINT *P, const uint8_t octets[65]) +{ + if (octets[0] != 0x04) { + error_print(); + return -1; + } + memset(P, 0, sizeof(*P)); + sm9_z256_fp_from_bytes(P->X, octets + 1); // fp_from_bytes include to_mont + sm9_z256_fp_from_bytes(P->Y, octets + 32 + 1); + sm9_z256_fp_copy(P->Z, SM9_Z256_MODP_MONT_ONE); + if (!sm9_z256_point_is_on_curve(P)) { + error_print(); + return -1; + } + return 1; +} + +int sm9_z256_twist_point_to_uncompressed_octets(const SM9_Z256_TWIST_POINT *P, uint8_t octets[129]) +{ + octets[0] = 0x04; + sm9_z256_fp2 x; + sm9_z256_fp2 y; + sm9_z256_twist_point_get_xy(P, x, y); + sm9_z256_fp2_to_bytes(x, octets + 1); + sm9_z256_fp2_to_bytes(y, octets + 32 * 2 + 1); + return 1; +} + +int sm9_z256_twist_point_from_uncompressed_octets(SM9_Z256_TWIST_POINT *P, const uint8_t octets[129]) +{ + assert(octets[0] == 0x04); + sm9_z256_fp2_from_bytes(P->X, octets + 1); + sm9_z256_fp2_from_bytes(P->Y, octets + 32 * 2 + 1); + sm9_z256_fp2_set_one(P->Z); + if (!sm9_z256_twist_point_is_on_curve(P)) return -1; + return 1; +} diff --git a/src/sm9_z256_key.c b/src/sm9_z256_key.c new file mode 100644 index 00000000..23927ae6 --- /dev/null +++ b/src/sm9_z256_key.c @@ -0,0 +1,1157 @@ +/* + * Copyright 2014-2022 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +extern const sm9_z256_t SM9_Z256_ZERO; +extern const sm9_z256_t SM9_Z256_N; + +// generate h1 in [1, n-1] +int sm9_z256_hash1(sm9_z256_t h1, const char *id, size_t idlen, uint8_t hid) +{ + SM3_CTX ctx; + uint8_t prefix[1] = { SM9_HASH1_PREFIX }; + uint8_t ct1[4] = {0x00, 0x00, 0x00, 0x01}; + uint8_t ct2[4] = {0x00, 0x00, 0x00, 0x02}; + uint8_t Ha[64]; + + sm3_init(&ctx); + sm3_update(&ctx, prefix, sizeof(prefix)); + sm3_update(&ctx, (uint8_t *)id, idlen); + sm3_update(&ctx, &hid, 1); + sm3_update(&ctx, ct1, sizeof(ct1)); + sm3_finish(&ctx, Ha); + + sm3_init(&ctx); + sm3_update(&ctx, prefix, sizeof(prefix)); + sm3_update(&ctx, (uint8_t *)id, idlen); + sm3_update(&ctx, &hid, 1); + sm3_update(&ctx, ct2, sizeof(ct2)); + sm3_finish(&ctx, Ha + 32); + + sm9_z256_fn_from_hash(h1, Ha); + return 1; +} + +int sm9_sign_master_key_to_der(const SM9_SIGN_MASTER_KEY *msk, uint8_t **out, size_t *outlen) +{ + uint8_t ks[32]; + uint8_t Ppubs[1 + 32 * 4]; + size_t len = 0; + + sm9_z256_fn_to_bytes(msk->ks, ks); + sm9_z256_twist_point_to_uncompressed_octets(&msk->Ppubs, Ppubs); + + if (asn1_integer_to_der(ks, sizeof(ks), NULL, &len) != 1 + || asn1_bit_octets_to_der(Ppubs, sizeof(Ppubs), NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_integer_to_der(ks, sizeof(ks), out, outlen) != 1 + || asn1_bit_octets_to_der(Ppubs, sizeof(Ppubs), out, outlen) != 1) { + gmssl_secure_clear(ks, sizeof(ks)); + error_print(); + return -1; + } + gmssl_secure_clear(ks, sizeof(ks)); + return 1; +} + +int sm9_sign_master_key_from_der(SM9_SIGN_MASTER_KEY *msk, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + const uint8_t *ks; + size_t kslen; + const uint8_t *Ppubs; + size_t Ppubslen; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_integer_from_der(&ks, &kslen, &d, &dlen) != 1 + || asn1_bit_octets_from_der(&Ppubs, &Ppubslen, &d, &dlen) != 1 + || asn1_check(kslen == 32) != 1 + || asn1_check(Ppubslen == 1 + 32 * 4) != 1 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + memset(msk, 0, sizeof(*msk)); + if (sm9_z256_fn_from_bytes(msk->ks, ks) != 1 + || sm9_z256_twist_point_from_uncompressed_octets(&msk->Ppubs, Ppubs) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_sign_master_public_key_to_der(const SM9_SIGN_MASTER_KEY *mpk, uint8_t **out, size_t *outlen) +{ + uint8_t Ppubs[1 + 32 * 4]; + size_t len = 0; + + sm9_z256_twist_point_to_uncompressed_octets(&mpk->Ppubs, Ppubs); + if (asn1_bit_octets_to_der(Ppubs, sizeof(Ppubs), NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_bit_octets_to_der(Ppubs, sizeof(Ppubs), out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_sign_master_public_key_from_der(SM9_SIGN_MASTER_KEY *mpk, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + const uint8_t *Ppubs; + size_t Ppubslen; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_bit_octets_from_der(&Ppubs, &Ppubslen, &d, &dlen) != 1 + || asn1_check(Ppubslen == 1 + 32 * 4) != 1 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + memset(mpk, 0, sizeof(*mpk)); + if (sm9_z256_twist_point_from_uncompressed_octets(&mpk->Ppubs, Ppubs) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_sign_key_to_der(const SM9_SIGN_KEY *key, uint8_t **out, size_t *outlen) +{ + uint8_t ds[65]; + uint8_t Ppubs[129]; + size_t len = 0; + + sm9_z256_point_to_uncompressed_octets(&key->ds, ds); + sm9_z256_twist_point_to_uncompressed_octets(&key->Ppubs, Ppubs); + + if (asn1_bit_octets_to_der(ds, sizeof(ds), NULL, &len) != 1 + || asn1_bit_octets_to_der(Ppubs, sizeof(Ppubs), NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_bit_octets_to_der(ds, sizeof(ds), out, outlen) != 1 + || asn1_bit_octets_to_der(Ppubs, sizeof(Ppubs), out, outlen) != 1) { + gmssl_secure_clear(ds, sizeof(ds)); + error_print(); + return -1; + } + gmssl_secure_clear(ds, sizeof(ds)); + return 1; +} + +int sm9_sign_key_from_der(SM9_SIGN_KEY *key, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + const uint8_t *ds; + size_t dslen; + const uint8_t *Ppubs; + size_t Ppubslen; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_bit_octets_from_der(&ds, &dslen, &d, &dlen) != 1 + || asn1_bit_octets_from_der(&Ppubs, &Ppubslen, &d, &dlen) != 1 + || asn1_check(dslen == 65) != 1 + || asn1_check(Ppubslen == 129) != 1 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + memset(key, 0, sizeof(*key)); + if (sm9_z256_point_from_uncompressed_octets(&key->ds, ds) != 1 + || sm9_z256_twist_point_from_uncompressed_octets(&key->Ppubs, Ppubs) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_enc_master_key_to_der(const SM9_ENC_MASTER_KEY *msk, uint8_t **out, size_t *outlen) +{ + uint8_t ke[32]; + uint8_t Ppube[1 + 32 * 2]; + size_t len = 0; + + sm9_z256_fn_to_bytes(msk->ke, ke); + sm9_z256_point_to_uncompressed_octets(&msk->Ppube, Ppube); + + if (asn1_integer_to_der(ke, sizeof(ke), NULL, &len) != 1 + || asn1_bit_octets_to_der(Ppube, sizeof(Ppube), NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_integer_to_der(ke, sizeof(ke), out, outlen) != 1 + || asn1_bit_octets_to_der(Ppube, sizeof(Ppube), out, outlen) != 1) { + gmssl_secure_clear(ke, sizeof(ke)); + error_print(); + return -1; + } + gmssl_secure_clear(ke, sizeof(ke)); + return 1; +} + +int sm9_enc_master_key_from_der(SM9_ENC_MASTER_KEY *msk, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + const uint8_t *ke; + size_t kelen; + const uint8_t *Ppube; + size_t Ppubelen; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_integer_from_der(&ke, &kelen, &d, &dlen) != 1 + || asn1_bit_octets_from_der(&Ppube, &Ppubelen, &d, &dlen) != 1 + || asn1_check(kelen == 32) != 1 + || asn1_check(Ppubelen == 1 + 32 * 2) != 1 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + memset(msk, 0, sizeof(*msk)); + if (sm9_z256_fn_from_bytes(msk->ke, ke) != 1 + || sm9_z256_point_from_uncompressed_octets(&msk->Ppube, Ppube) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_enc_master_public_key_to_der(const SM9_ENC_MASTER_KEY *mpk, uint8_t **out, size_t *outlen) +{ + uint8_t Ppube[1 + 32 * 2]; + size_t len = 0; + + sm9_z256_point_to_uncompressed_octets(&mpk->Ppube, Ppube); + + if (asn1_bit_octets_to_der(Ppube, sizeof(Ppube), NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_bit_octets_to_der(Ppube, sizeof(Ppube), out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_enc_master_public_key_from_der(SM9_ENC_MASTER_KEY *mpk, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + const uint8_t *Ppube; + size_t Ppubelen; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_bit_octets_from_der(&Ppube, &Ppubelen, &d, &dlen) != 1 + || asn1_check(Ppubelen == 1 + 32 * 2) != 1 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + memset(mpk, 0, sizeof(*mpk)); + if (sm9_z256_point_from_uncompressed_octets(&mpk->Ppube, Ppube) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_enc_key_to_der(const SM9_ENC_KEY *key, uint8_t **out, size_t *outlen) +{ + uint8_t de[129]; + uint8_t Ppube[65]; + size_t len = 0; + + sm9_z256_twist_point_to_uncompressed_octets(&key->de, de); + sm9_z256_point_to_uncompressed_octets(&key->Ppube, Ppube); + + if (asn1_bit_octets_to_der(de, sizeof(de), NULL, &len) != 1 + || asn1_bit_octets_to_der(Ppube, sizeof(Ppube), NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_bit_octets_to_der(de, sizeof(de), out, outlen) != 1 + || asn1_bit_octets_to_der(Ppube, sizeof(Ppube), out, outlen) != 1) { + gmssl_secure_clear(de, sizeof(de)); + error_print(); + return -1; + } + gmssl_secure_clear(de, sizeof(de)); + return 1; +} + +int sm9_enc_key_from_der(SM9_ENC_KEY *key, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + const uint8_t *de; + size_t delen; + const uint8_t *Ppube; + size_t Ppubelen; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_bit_octets_from_der(&de, &delen, &d, &dlen) != 1 + || asn1_bit_octets_from_der(&Ppube, &Ppubelen, &d, &dlen) != 1 + || asn1_check(delen == 129) != 1 + || asn1_check(Ppubelen == 65) != 1 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + memset(key, 0, sizeof(*key)); + if (sm9_z256_twist_point_from_uncompressed_octets(&key->de, de) != 1 + || sm9_z256_point_from_uncompressed_octets(&key->Ppube, Ppube) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_sign_master_key_generate(SM9_SIGN_MASTER_KEY *msk) +{ + if (!msk) { + error_print(); + return -1; + } + // k = rand(1, n-1) + if (sm9_z256_fn_rand(msk->ks) != 1) { + error_print(); + return -1; + } + // Ppubs = k * P2 in E'(F_p^2) + sm9_z256_twist_point_mul_generator(&msk->Ppubs, msk->ks); + return 1; +} + +int sm9_enc_master_key_generate(SM9_ENC_MASTER_KEY *msk) +{ + // k = rand(1, n-1) + if (sm9_z256_fn_rand(msk->ke) != 1) { + error_print(); + return -1; + } + // Ppube = ke * P1 in E(F_p) + sm9_z256_point_mul_generator(&msk->Ppube, msk->ke); + return 1; +} + +int sm9_sign_master_key_extract_key(SM9_SIGN_MASTER_KEY *msk, const char *id, size_t idlen, SM9_SIGN_KEY *key) +{ + sm9_z256_t t; + + // t1 = H1(ID || hid, N) + ks + sm9_z256_hash1(t, id, idlen, SM9_HID_SIGN); + sm9_z256_fn_add(t, t, msk->ks); + if (sm9_z256_fn_is_zero(t)) { + // 这是一个严重问题,意味着整个msk都需要作废了 + error_print(); + return -1; + } + + // t2 = ks * t1^-1 + sm9_z256_fn_inv(t, t); + sm9_z256_fn_mul(t, t, msk->ks); + + // ds = t2 * P1 + sm9_z256_point_mul_generator(&key->ds, t); + key->Ppubs = msk->Ppubs; + + return 1; +} + +int sm9_enc_master_key_extract_key(SM9_ENC_MASTER_KEY *msk, const char *id, size_t idlen, + SM9_ENC_KEY *key) +{ + sm9_z256_t t; + + // t1 = H1(ID || hid, N) + ke + sm9_z256_hash1(t, id, idlen, SM9_HID_ENC); + sm9_z256_fn_add(t, t, msk->ke); + if (sm9_z256_fn_is_zero(t)) { + error_print(); + return -1; + } + + // t2 = ke * t1^-1 + sm9_z256_fn_inv(t, t); + sm9_z256_fn_mul(t, t, msk->ke); + + // de = t2 * P2 + sm9_z256_twist_point_mul_generator(&key->de, t); + key->Ppube = msk->Ppube; + + return 1; +} + + +#define OID_SM9 oid_sm_algors,302 +static uint32_t oid_sm9[] = { OID_SM9 }; +static uint32_t oid_sm9sign[] = { OID_SM9,1 }; +static uint32_t oid_sm9keyagreement[] = { OID_SM9,2 }; +static uint32_t oid_sm9encrypt[] = { OID_SM9,3 }; + +static const ASN1_OID_INFO sm9_oids[] = { + { OID_sm9, "sm9", oid_sm9, sizeof(oid_sm9)/sizeof(int) }, + { OID_sm9sign, "sm9sign", oid_sm9sign, sizeof(oid_sm9sign)/sizeof(int) }, + { OID_sm9keyagreement, "sm9keyagreement", oid_sm9keyagreement, sizeof(oid_sm9keyagreement)/sizeof(int) }, + { OID_sm9encrypt, "sm9encrypt", oid_sm9encrypt, sizeof(oid_sm9encrypt)/sizeof(int) }, +}; + +static const int sm9_oids_count = sizeof(sm9_oids)/sizeof(sm9_oids[0]); + + +const char *sm9_oid_name(int oid) +{ + const ASN1_OID_INFO *info; + if (!(info = asn1_oid_info_from_oid(sm9_oids, sm9_oids_count, oid))) { + error_print(); + return NULL; + } + return info->name; +} + +int sm9_oid_from_name(const char *name) +{ + const ASN1_OID_INFO *info; + if (!(info = asn1_oid_info_from_name(sm9_oids, sm9_oids_count, name))) { + error_print(); + return OID_undef; + } + return info->oid; +} + +int sm9_oid_to_der(int oid, uint8_t **out, size_t *outlen) +{ + const ASN1_OID_INFO *info; + if (oid == -1) { + // TODO: 检查其他的oid_to_der是否支持这个default == -1 的特性 + return 0; + } + if (!(info = asn1_oid_info_from_oid(sm9_oids, sm9_oids_count, oid))) { + error_print(); + return -1; + } + if (asn1_object_identifier_to_der(info->nodes, info->nodes_cnt, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_oid_from_der(int *oid, const uint8_t **in, size_t *inlen) +{ + int ret; + const ASN1_OID_INFO *info; + + if ((ret = asn1_oid_info_from_der(&info, sm9_oids, sm9_oids_count, in, inlen)) != 1) { + if (ret < 0) error_print(); + else *oid = -1; + return ret; + } + *oid = info->oid; + return 1; +} + +int sm9_algor_to_der(int alg, int params, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + if (sm9_oid_to_der(alg, NULL, &len) != 1 + || sm9_oid_to_der(params, NULL, &len) < 0 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || sm9_oid_to_der(alg, out, outlen) != 1 + || sm9_oid_to_der(params, out, outlen) < 0) { + error_print(); + return -1; + } + return 1; +} + +int sm9_algor_from_der(int *alg, int *params, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (sm9_oid_from_der(alg, &d, &dlen) != 1 + || sm9_oid_from_der(params, &d, &dlen) < 0 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +static int sm9_private_key_info_to_der(int alg, int params, const uint8_t *prikey, size_t prikey_len, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + if (prikey_len > SM9_MAX_PRIVATE_KEY_SIZE) { + error_print(); + return -1; + } + if (asn1_int_to_der(PKCS8_private_key_info_version, NULL, &len) != 1 + || sm9_algor_to_der(alg, params, NULL, &len) != 1 + || asn1_octet_string_to_der(prikey, prikey_len, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_int_to_der(PKCS8_private_key_info_version, out, outlen) != 1 + || sm9_algor_to_der(alg, params, out, outlen) != 1 + || asn1_octet_string_to_der(prikey, prikey_len, out, outlen) != 1) { + error_print(); + return -1; + } + //printf("alg %s params %s prikey_len %zu: SM9_PRIVATE_KEY_INFO_SIZE %zu\n", sm9_oid_name(alg), sm9_oid_name(params), prikey_len, *outlen); + return 1; +} + +static int sm9_private_key_info_from_der(int *alg, int *params, const uint8_t **prikey, size_t *prikey_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + int ver; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + else error_print(); + return ret; + } + if (asn1_int_from_der(&ver, &d, &dlen) != 1 + || sm9_algor_from_der(alg, params, &d, &dlen) != 1 + || asn1_octet_string_from_der(prikey, prikey_len, &d, &dlen) != 1 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + if (ver != PKCS8_private_key_info_version) { + error_print(); + return -1; + } + if (*prikey_len > SM9_MAX_PRIVATE_KEY_SIZE) { + error_print(); + return -1; + } + return 1; +} + +static int sm9_private_key_info_encrypt_to_der(int alg, int params, const uint8_t *prikey, size_t prikey_len, + const char *pass, uint8_t **out, size_t *outlen) +{ + int ret = -1; + uint8_t pkey_info[SM9_MAX_PRIVATE_KEY_INFO_SIZE]; + uint8_t *p = pkey_info; + size_t pkey_info_len = 0; + uint8_t salt[16]; + int iter = 65536; + uint8_t iv[16]; + uint8_t key[16]; + SM4_KEY sm4_key; + uint8_t enced_pkey_info[sizeof(pkey_info) + 16]; // cbc-padding of pkey_info + size_t enced_pkey_info_len; + + if (sm9_private_key_info_to_der(alg, params, prikey, prikey_len, &p, &pkey_info_len) != 1 + || rand_bytes(salt, sizeof(salt)) != 1 + || rand_bytes(iv, sizeof(iv)) != 1 + || pbkdf2_hmac_sm3_genkey(pass, strlen(pass), salt, sizeof(salt), iter, sizeof(key), key) != 1) { + error_print(); + goto end; + } + sm4_set_encrypt_key(&sm4_key, key); + if (sm4_cbc_padding_encrypt(&sm4_key, iv, pkey_info, pkey_info_len, enced_pkey_info, &enced_pkey_info_len) != 1 + || pkcs8_enced_private_key_info_to_der(salt, sizeof(salt), iter, sizeof(key), + OID_hmac_sm3, OID_sm4_cbc, iv, sizeof(iv), + enced_pkey_info, enced_pkey_info_len, out, outlen) != 1) { + error_print(); + goto end; + } + //printf("SM9_ENCED_PRIVATE_KEY_INFO_SIZE %zu\n", *outlen); + ret = 1; +end: + gmssl_secure_clear(pkey_info, sizeof(pkey_info)); + gmssl_secure_clear(salt, sizeof(salt)); + gmssl_secure_clear(iv, sizeof(iv)); + gmssl_secure_clear(key, sizeof(key)); + return ret; +} + +static int sm9_private_key_info_decrypt_from_der(int *alg, int *params, uint8_t *prikey, size_t *prikey_len, + const char *pass, const uint8_t **in, size_t *inlen) +{ + int ret = -1; + const uint8_t *salt; + size_t saltlen; + int iter; + int keylen; + int prf; + int cipher; + const uint8_t *iv; + size_t ivlen; + uint8_t key[16]; + SM4_KEY sm4_key; + const uint8_t *enced_pkey_info; + size_t enced_pkey_info_len; + uint8_t pkey_info[SM9_MAX_PRIVATE_KEY_INFO_SIZE]; + const uint8_t *cp = pkey_info; + size_t pkey_info_len; + const uint8_t *cp_prikey; + + if (pkcs8_enced_private_key_info_from_der(&salt, &saltlen, &iter, &keylen, &prf, + &cipher, &iv, &ivlen, &enced_pkey_info, &enced_pkey_info_len, in, inlen) != 1 + || asn1_check(keylen == -1 || keylen == 16) != 1 + || asn1_check(prf == - 1 || prf == OID_hmac_sm3) != 1 + || asn1_check(cipher == OID_sm4_cbc) != 1 + || asn1_check(ivlen == 16) != 1 + || asn1_length_le(enced_pkey_info_len, sizeof(pkey_info)) != 1) { + error_print(); + return -1; + } + if (pbkdf2_genkey(DIGEST_sm3(), pass, strlen(pass), salt, saltlen, iter, sizeof(key), key) != 1) { + error_print(); + goto end; + } + sm4_set_decrypt_key(&sm4_key, key); + if (sm4_cbc_padding_decrypt(&sm4_key, iv, enced_pkey_info, enced_pkey_info_len, + pkey_info, &pkey_info_len) != 1 + || sm9_private_key_info_from_der(alg, params, &cp_prikey, prikey_len, // 注意这里的是const uint8_t *,必须拷贝到外面 + &cp, &pkey_info_len) != 1 + || asn1_length_is_zero(pkey_info_len) != 1) { + error_print(); + goto end; + } + memcpy(prikey, cp_prikey, *prikey_len); + ret = 1; +end: + gmssl_secure_clear(&sm4_key, sizeof(sm4_key)); + gmssl_secure_clear(key, sizeof(key)); + gmssl_secure_clear(pkey_info, sizeof(pkey_info)); + return ret; +} + + + +int sm9_sign_master_key_info_encrypt_to_der(const SM9_SIGN_MASTER_KEY *msk, const char *pass, uint8_t **out, size_t *outlen) +{ + uint8_t buf[SM9_SIGN_MASTER_KEY_MAX_SIZE]; + uint8_t *p = buf; + size_t len = 0; + + if (sm9_sign_master_key_to_der(msk, &p, &len) != 1 + || sm9_private_key_info_encrypt_to_der(OID_sm9, OID_sm9sign, buf, len, pass, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + + +int sm9_sign_master_key_info_decrypt_from_der(SM9_SIGN_MASTER_KEY *msk, const char *pass, const uint8_t **in, size_t *inlen) +{ + int ret = -1; + int alg, params; + uint8_t prikey[SM9_MAX_PRIVATE_KEY_SIZE]; + size_t prikey_len; + const uint8_t *cp = prikey; + + if (sm9_private_key_info_decrypt_from_der(&alg, ¶ms, prikey, &prikey_len, pass, in, inlen) != 1) { + error_print(); + goto end; + } + if (alg != OID_sm9) { + error_print(); + goto end; + } + if (params != OID_sm9sign) { + error_print(); + goto end; + } + if (sm9_sign_master_key_from_der(msk, &cp, &prikey_len) != 1 + || asn1_length_is_zero(prikey_len) != 1) { + error_print(); + goto end; + } + ret = 1; +end: + gmssl_secure_clear(prikey, sizeof(prikey)); + return ret; +} + +int sm9_sign_master_key_info_encrypt_to_pem(const SM9_SIGN_MASTER_KEY *msk, const char *pass, FILE *fp) +{ + uint8_t buf[SM9_MAX_ENCED_PRIVATE_KEY_INFO_SIZE]; + uint8_t *p = buf; + size_t len = 0; + + if (sm9_sign_master_key_info_encrypt_to_der(msk, pass, &p, &len) != 1) { + error_print(); + return -1; + } + if (pem_write(fp, PEM_SM9_SIGN_MASTER_KEY, buf, len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_sign_master_key_info_decrypt_from_pem(SM9_SIGN_MASTER_KEY *msk, const char *pass, FILE *fp) +{ + uint8_t buf[SM9_MAX_ENCED_PRIVATE_KEY_INFO_SIZE]; + const uint8_t *cp = buf; + size_t len; + + if (pem_read(fp, PEM_SM9_SIGN_MASTER_KEY, buf, &len, sizeof(buf)) != 1 + || sm9_sign_master_key_info_decrypt_from_der(msk, pass, &cp, &len) != 1 + || asn1_length_is_zero(len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_sign_master_public_key_to_pem(const SM9_SIGN_MASTER_KEY *mpk, FILE *fp) +{ + uint8_t buf[SM9_SIGN_MASTER_PUBLIC_KEY_SIZE]; + uint8_t *p = buf; + size_t len = 0; + + if (sm9_sign_master_public_key_to_der(mpk, &p, &len) != 1) { + error_print(); + return -1; + } + if (pem_write(fp, PEM_SM9_SIGN_MASTER_PUBLIC_KEY, buf, len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_sign_master_public_key_from_pem(SM9_SIGN_MASTER_KEY *mpk, FILE *fp) +{ + uint8_t buf[512]; + const uint8_t *cp = buf; + size_t len; + + if (pem_read(fp, PEM_SM9_SIGN_MASTER_PUBLIC_KEY, buf, &len, sizeof(buf)) != 1 + || sm9_sign_master_public_key_from_der(mpk, &cp, &len) != 1 + || asn1_length_is_zero(len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_sign_key_info_encrypt_to_der(const SM9_SIGN_KEY *key, const char *pass, uint8_t **out, size_t *outlen) +{ + uint8_t buf[SM9_SIGN_KEY_SIZE]; + uint8_t *p = buf; + size_t len = 0; + + if (sm9_sign_key_to_der(key, &p, &len) != 1 + || sm9_private_key_info_encrypt_to_der(OID_sm9sign, -1, buf, len, pass, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_sign_key_info_decrypt_from_der(SM9_SIGN_KEY *key, const char *pass, const uint8_t **in, size_t *inlen) +{ + int ret = -1; + int alg, params; + uint8_t prikey[512]; + size_t prikey_len; + const uint8_t *cp = prikey; + + if (sm9_private_key_info_decrypt_from_der(&alg, ¶ms, prikey, &prikey_len, pass, in, inlen) != 1) { + error_print(); + goto end; + } + if (alg != OID_sm9sign) { + error_print(); + goto end; + } + if (params != -1) { + error_print(); + goto end; + } + if (sm9_sign_key_from_der(key, &cp, &prikey_len) != 1 + || asn1_length_is_zero(prikey_len) != 1) { + error_print(); + goto end; + } + ret = 1; +end: + gmssl_secure_clear(prikey, sizeof(prikey)); + return ret; +} + +int sm9_sign_key_info_encrypt_to_pem(const SM9_SIGN_KEY *key, const char *pass, FILE *fp) +{ + uint8_t buf[SM9_MAX_ENCED_PRIVATE_KEY_INFO_SIZE]; + uint8_t *p = buf; + size_t len = 0; + + if (sm9_sign_key_info_encrypt_to_der(key, pass, &p, &len) != 1) { + error_print(); + return -1; + } + if (pem_write(fp, PEM_SM9_SIGN_PRIVATE_KEY, buf, len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_sign_key_info_decrypt_from_pem(SM9_SIGN_KEY *key, const char *pass, FILE *fp) +{ + uint8_t buf[SM9_MAX_ENCED_PRIVATE_KEY_INFO_SIZE]; + const uint8_t *cp = buf; + size_t len; + + if (pem_read(fp, PEM_SM9_SIGN_PRIVATE_KEY, buf, &len, sizeof(buf)) != 1 + || sm9_sign_key_info_decrypt_from_der(key, pass, &cp, &len) != 1 + || asn1_length_is_zero(len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_enc_master_key_info_encrypt_to_der(const SM9_ENC_MASTER_KEY *msk, const char *pass, uint8_t **out, size_t *outlen) +{ + uint8_t buf[256]; + uint8_t *p = buf; + size_t len = 0; + + if (sm9_enc_master_key_to_der(msk, &p, &len) != 1 + || sm9_private_key_info_encrypt_to_der(OID_sm9, OID_sm9encrypt, buf, len, pass, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_enc_master_key_info_decrypt_from_der(SM9_ENC_MASTER_KEY *msk, const char *pass, const uint8_t **in, size_t *inlen) +{ + int ret = -1; + int alg, params; + uint8_t prikey[512]; + size_t prikey_len; + const uint8_t *cp = prikey; + + if (sm9_private_key_info_decrypt_from_der(&alg, ¶ms, prikey, &prikey_len, pass, in, inlen) != 1) { + error_print(); + goto end; + } + if (alg != OID_sm9) { + error_print(); + goto end; + } + if (params != OID_sm9encrypt) { + error_print(); + goto end; + } + if (sm9_enc_master_key_from_der(msk, &cp, &prikey_len) != 1 + || asn1_length_is_zero(prikey_len) != 1) { + error_print(); + goto end; + } + ret = 1; +end: + gmssl_secure_clear(prikey, sizeof(prikey)); + return 1; +} + +int sm9_enc_master_key_info_encrypt_to_pem(const SM9_ENC_MASTER_KEY *msk, const char *pass, FILE *fp) +{ + uint8_t buf[SM9_MAX_ENCED_PRIVATE_KEY_INFO_SIZE]; + uint8_t *p = buf; + size_t len = 0; + + if (sm9_enc_master_key_info_encrypt_to_der(msk, pass, &p, &len) != 1) { + error_print(); + return -1; + } + if (pem_write(fp, PEM_SM9_ENC_MASTER_KEY, buf, len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_enc_master_key_info_decrypt_from_pem(SM9_ENC_MASTER_KEY *msk, const char *pass, FILE *fp) +{ + uint8_t buf[SM9_MAX_ENCED_PRIVATE_KEY_INFO_SIZE]; + const uint8_t *cp = buf; + size_t len; + + if (pem_read(fp, PEM_SM9_ENC_MASTER_KEY, buf, &len, sizeof(buf)) != 1 + || sm9_enc_master_key_info_decrypt_from_der(msk, pass, &cp, &len) != 1 + || asn1_length_is_zero(len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_enc_master_public_key_to_pem(const SM9_ENC_MASTER_KEY *mpk, FILE *fp) +{ + uint8_t buf[1024]; + uint8_t *p = buf; + size_t len = 0; + + if (sm9_enc_master_public_key_to_der(mpk, &p, &len) != 1) { + error_print(); + return -1; + } + if (pem_write(fp, PEM_SM9_ENC_MASTER_PUBLIC_KEY, buf, len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_enc_master_public_key_from_pem(SM9_ENC_MASTER_KEY *mpk, FILE *fp) +{ + uint8_t buf[512]; + const uint8_t *cp = buf; + size_t len; + + if (pem_read(fp, PEM_SM9_ENC_MASTER_PUBLIC_KEY, buf, &len, sizeof(buf)) != 1 + || sm9_enc_master_public_key_from_der(mpk, &cp, &len) != 1 + || asn1_length_is_zero(len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_enc_key_info_encrypt_to_der(const SM9_ENC_KEY *key, const char *pass, uint8_t **out, size_t *outlen) +{ + uint8_t buf[1024]; + uint8_t *p = buf; + size_t len = 0; + + if (sm9_enc_key_to_der(key, &p, &len) != 1 + || sm9_private_key_info_encrypt_to_der(OID_sm9encrypt, -1, buf, len, pass, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_enc_key_info_decrypt_from_der(SM9_ENC_KEY *key, const char *pass, const uint8_t **in, size_t *inlen) +{ + int ret = -1; + int alg, params; + uint8_t prikey[512]; + size_t prikey_len; + const uint8_t *cp = prikey; + + if (sm9_private_key_info_decrypt_from_der(&alg, ¶ms, prikey, &prikey_len, pass, in, inlen) != 1) { + error_print(); + goto end; + } + if (alg != OID_sm9encrypt) { + error_print(); + goto end; + } + if (params != -1) { + error_print(); + goto end; + } + if (sm9_enc_key_from_der(key, &cp, &prikey_len) != 1 + || asn1_length_is_zero(prikey_len) != 1) { + error_print(); + goto end; + } + ret = 1; +end: + gmssl_secure_clear(prikey, sizeof(prikey)); + return ret; +} + +int sm9_enc_key_info_encrypt_to_pem(const SM9_ENC_KEY *key, const char *pass, FILE *fp) +{ + uint8_t buf[SM9_MAX_ENCED_PRIVATE_KEY_INFO_SIZE]; + uint8_t *p = buf; + size_t len = 0; + + if (sm9_enc_key_info_encrypt_to_der(key, pass, &p, &len) != 1) { + error_print(); + return -1; + } + if (pem_write(fp, PEM_SM9_ENC_PRIVATE_KEY, buf, len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_enc_key_info_decrypt_from_pem(SM9_ENC_KEY *key, const char *pass, FILE *fp) +{ + uint8_t buf[SM9_MAX_ENCED_PRIVATE_KEY_INFO_SIZE]; + const uint8_t *cp = buf; + size_t len; + + if (pem_read(fp, PEM_SM9_ENC_PRIVATE_KEY, buf, &len, sizeof(buf)) != 1 + || sm9_enc_key_info_decrypt_from_der(key, pass, &cp, &len) != 1 + || asn1_length_is_zero(len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_sign_master_key_print(FILE *fp, int fmt, int ind, const char *label, const SM9_SIGN_MASTER_KEY *msk) +{ + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + sm9_z256_fn_print(fp, fmt, ind, "ks", msk->ks); + sm9_z256_twist_point_print(fp, fmt, ind, "Ppubs", &msk->Ppubs); + return 1; +} + +int sm9_sign_master_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SM9_SIGN_MASTER_KEY *mpk) +{ + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + sm9_z256_twist_point_print(fp, fmt, ind, "Ppubs", &mpk->Ppubs); + return 1; +} + +int sm9_sign_key_print(FILE *fp, int fmt, int ind, const char *label, const SM9_SIGN_KEY *key) +{ + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + sm9_z256_point_print(fp, fmt, ind, "ds", &key->ds); + sm9_z256_twist_point_print(fp, fmt, ind, "Ppubs", &key->Ppubs); + return 1; +} + +int sm9_enc_master_key_print(FILE *fp, int fmt, int ind, const char *label, const SM9_ENC_MASTER_KEY *msk) +{ + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + sm9_z256_fn_print(fp, fmt, ind, "ke", msk->ke); + sm9_z256_point_print(fp, fmt, ind, "Ppube", &msk->Ppube); + return 1; +} + +int sm9_enc_master_public_key_print(FILE *fp, int fmt, int ind, const char *label, const SM9_ENC_MASTER_KEY *mpk) +{ + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + sm9_z256_point_print(fp, fmt, ind, "Ppube", &mpk->Ppube); + return 1; +} + +int sm9_enc_key_print(FILE *fp, int fmt, int ind, const char *label, const SM9_ENC_KEY *key) +{ + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + sm9_z256_twist_point_print(fp, fmt, ind, "de", &key->de); + sm9_z256_point_print(fp, fmt, ind, "Ppube", &key->Ppube); + return 1; +} + +int sm9_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen) +{ + const uint8_t *d; + size_t dlen; + const uint8_t *p; + size_t len; + + if (asn1_sequence_from_der(&d, &dlen, &sig, &siglen) != 1 + || asn1_length_is_zero(siglen) != 1) { + error_print(); + return -1; + } + + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + if (asn1_octet_string_from_der(&p, &len, &d, &dlen) != 1) goto err; + format_bytes(fp, fmt, ind, "h", p, len); + if (asn1_bit_octets_from_der(&p, &len, &d, &dlen) != 1) goto err; + format_bytes(fp, fmt, ind, "S", p, len); + if (asn1_length_is_zero(dlen) != 1) goto err; + return 1; +err: + error_print(); + return -1; +} + +int sm9_ciphertext_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen) +{ + const uint8_t *d; + size_t dlen; + int val; + const uint8_t *p; + size_t len; + + if (asn1_sequence_from_der(&d, &dlen, &a, &alen) != 1 + || asn1_length_is_zero(alen) != 1) { + error_print(); + return -1; + } + format_print(fp, fmt, ind, "%s\n", label); + ind += 4; + + if (asn1_int_from_der(&val, &d, &dlen) != 1) goto err; + format_print(fp, fmt, ind, "EnType: %d\n", val); + if (asn1_bit_octets_from_der(&p, &len, &d, &dlen) != 1) goto err; + format_bytes(fp, fmt, ind, "C1", p, len); + if (asn1_octet_string_from_der(&p, &len, &d, &dlen) != 1) goto err; + format_bytes(fp, fmt, ind, "C3", p, len); + if (asn1_octet_string_from_der(&p, &len, &d, &dlen) != 1) goto err; + format_bytes(fp, fmt, ind, "CipherText", p, len); + if (asn1_length_is_zero(dlen) != 1) goto err; + return 1; +err: + error_print(); + return -1; +} diff --git a/src/sm9_z256_lib.c b/src/sm9_z256_lib.c new file mode 100644 index 00000000..c4889d9e --- /dev/null +++ b/src/sm9_z256_lib.c @@ -0,0 +1,516 @@ +/* + * Copyright 2014-2022 The GmSSL Project. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +extern const sm9_z256_t SM9_Z256_ZERO; +extern const sm9_z256_t SM9_Z256_N; +extern const SM9_Z256_POINT *SM9_Z256_MONT_P1; +extern const SM9_Z256_TWIST_POINT *SM9_Z256_MONT_P2; + + +int sm9_signature_to_der(const SM9_SIGNATURE *sig, uint8_t **out, size_t *outlen) +{ + uint8_t hbuf[32]; + uint8_t Sbuf[65]; + size_t len = 0; + + sm9_z256_fn_to_bytes(sig->h, hbuf); + sm9_z256_point_to_uncompressed_octets(&sig->S, Sbuf); + + if (asn1_octet_string_to_der(hbuf, sizeof(hbuf), NULL, &len) != 1 + || asn1_bit_octets_to_der(Sbuf, sizeof(Sbuf), NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_octet_string_to_der(hbuf, sizeof(hbuf), out, outlen) != 1 + || asn1_bit_octets_to_der(Sbuf, sizeof(Sbuf), out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_signature_from_der(SM9_SIGNATURE *sig, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + const uint8_t *h; + size_t hlen; + const uint8_t *S; + size_t Slen; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_octet_string_from_der(&h, &hlen, &d, &dlen) != 1 + || asn1_bit_octets_from_der(&S, &Slen, &d, &dlen) != 1 + || asn1_check(hlen == 32) != 1 + || asn1_check(Slen == 65) != 1 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + if (sm9_z256_fn_from_bytes(sig->h, h) != 1 + || sm9_z256_point_from_uncompressed_octets(&sig->S, S) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_sign_init(SM9_SIGN_CTX *ctx) +{ + const uint8_t prefix[1] = { SM9_HASH2_PREFIX }; + sm3_init(&ctx->sm3_ctx); + sm3_update(&ctx->sm3_ctx, prefix, sizeof(prefix)); + return 1; +} + +int sm9_sign_update(SM9_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) +{ + sm3_update(&ctx->sm3_ctx, data, datalen); + return 1; +} + +int sm9_sign_finish(SM9_SIGN_CTX *ctx, const SM9_SIGN_KEY *key, uint8_t *sig, size_t *siglen) +{ + SM9_SIGNATURE signature; + + if (sm9_do_sign(key, &ctx->sm3_ctx, &signature) != 1) { + error_print(); + return -1; + } + *siglen = 0; + if (sm9_signature_to_der(&signature, &sig, siglen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_do_sign(const SM9_SIGN_KEY *key, const SM3_CTX *sm3_ctx, SM9_SIGNATURE *sig) +{ + sm9_z256_t r; + sm9_z256_fp12 g; + uint8_t wbuf[32 * 12]; + SM3_CTX ctx = *sm3_ctx; + SM3_CTX tmp_ctx; + uint8_t ct1[4] = {0,0,0,1}; + uint8_t ct2[4] = {0,0,0,2}; + uint8_t Ha[64]; + + // A1: g = e(P1, Ppubs) + sm9_z256_pairing(g, &key->Ppubs, SM9_Z256_MONT_P1); + + do { + // A2: rand r in [1, N-1] + if (sm9_z256_fn_rand(r) != 1) { + error_print(); + return -1; + } + + // Only for testing + //sm9_z256_from_hex(r, "00033C8616B06704813203DFD00965022ED15975C662337AED648835DC4B1CBE"); + + // A3: w = g^r + sm9_z256_fp12_pow(g, g, r); + sm9_z256_fp12_to_bytes(g, wbuf); + + // A4: h = H2(M || w, N) + sm3_update(&ctx, wbuf, sizeof(wbuf)); + tmp_ctx = ctx; + sm3_update(&ctx, ct1, sizeof(ct1)); + sm3_finish(&ctx, Ha); + sm3_update(&tmp_ctx, ct2, sizeof(ct2)); + sm3_finish(&tmp_ctx, Ha + 32); + sm9_z256_fn_from_hash(sig->h, Ha); + + // A5: l = (r - h) mod N, if l = 0, goto A2 + sm9_z256_fn_sub(r, r, sig->h); + + } while (sm9_z256_fn_is_zero(r)); + + // A6: S = l * dsA + sm9_z256_point_mul(&sig->S, r, &key->ds); + + gmssl_secure_clear(&r, sizeof(r)); + gmssl_secure_clear(&g, sizeof(g)); + gmssl_secure_clear(wbuf, sizeof(wbuf)); + gmssl_secure_clear(&tmp_ctx, sizeof(tmp_ctx)); + gmssl_secure_clear(Ha, sizeof(Ha)); + + return 1; +} + +int sm9_verify_init(SM9_SIGN_CTX *ctx) +{ + const uint8_t prefix[1] = { SM9_HASH2_PREFIX }; + sm3_init(&ctx->sm3_ctx); + sm3_update(&ctx->sm3_ctx, prefix, sizeof(prefix)); + return 1; +} + +int sm9_verify_update(SM9_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) +{ + sm3_update(&ctx->sm3_ctx, data, datalen); + return 1; +} + +int sm9_verify_finish(SM9_SIGN_CTX *ctx, const uint8_t *sig, size_t siglen, + const SM9_SIGN_MASTER_KEY *mpk, const char *id, size_t idlen) +{ + int ret; + SM9_SIGNATURE signature; + + if (sm9_signature_from_der(&signature, &sig, &siglen) != 1 + || asn1_length_is_zero(siglen) != 1) { + error_print(); + return -1; + } + + if ((ret = sm9_do_verify(mpk, id, idlen, &ctx->sm3_ctx, &signature)) < 0) { + error_print(); + return -1; + } + return ret; +} + +int sm9_do_verify(const SM9_SIGN_MASTER_KEY *mpk, const char *id, size_t idlen, + const SM3_CTX *sm3_ctx, const SM9_SIGNATURE *sig) +{ + sm9_z256_t h1; + sm9_z256_t h2; + sm9_z256_fp12 g; + sm9_z256_fp12 t; + sm9_z256_fp12 u; + sm9_z256_fp12 w; + SM9_Z256_TWIST_POINT P; + uint8_t wbuf[32 * 12]; + SM3_CTX ctx = *sm3_ctx; + SM3_CTX tmp_ctx; + uint8_t ct1[4] = {0,0,0,1}; + uint8_t ct2[4] = {0,0,0,2}; + uint8_t Ha[64]; + + // B1: check h in [1, N-1] + + // B2: check S in G1 + + // B3: g = e(P1, Ppubs) + sm9_z256_pairing(g, &mpk->Ppubs, SM9_Z256_MONT_P1); + + // B4: t = g^h + sm9_z256_fp12_pow(t, g, sig->h); + + // B5: h1 = H1(ID || hid, N) + sm9_z256_hash1(h1, id, idlen, SM9_HID_SIGN); + + // B6: P = h1 * P2 + Ppubs + sm9_z256_twist_point_mul_generator(&P, h1); + sm9_z256_twist_point_add_full(&P, &P, &mpk->Ppubs); + + // B7: u = e(S, P) + sm9_z256_pairing(u, &P, &sig->S); + + // B8: w = u * t + sm9_z256_fp12_mul(w, u, t); + sm9_z256_fp12_to_bytes(w, wbuf); + + // B9: h2 = H2(M || w, N), check h2 == h + sm3_update(&ctx, wbuf, sizeof(wbuf)); + tmp_ctx = ctx; + sm3_update(&ctx, ct1, sizeof(ct1)); + sm3_finish(&ctx, Ha); + sm3_update(&tmp_ctx, ct2, sizeof(ct2)); + sm3_finish(&tmp_ctx, Ha + 32); + sm9_z256_fn_from_hash(h2, Ha); + if (sm9_z256_fn_equ(h2, sig->h) != 1) { + return 0; + } + + return 1; +} + +int sm9_kem_encrypt(const SM9_ENC_MASTER_KEY *mpk, const char *id, size_t idlen, + size_t klen, uint8_t *kbuf, SM9_Z256_POINT *C) +{ + sm9_z256_t r; + sm9_z256_fp12 w; + uint8_t wbuf[32 * 12]; + uint8_t cbuf[65]; + SM3_KDF_CTX kdf_ctx; + + // A1: Q = H1(ID||hid,N) * P1 + Ppube + sm9_z256_hash1(r, id, idlen, SM9_HID_ENC); + sm9_z256_point_mul(C, r, SM9_Z256_MONT_P1); + sm9_z256_point_add(C, C, &mpk->Ppube); + + do { + // A2: rand r in [1, N-1] + if (sm9_z256_fn_rand(r) != 1) { + error_print(); + return -1; + } + + // A3: C1 = r * Q + sm9_z256_point_mul(C, r, C); + sm9_z256_point_to_uncompressed_octets(C, cbuf); + + // A4: g = e(Ppube, P2) + sm9_z256_pairing(w, SM9_Z256_MONT_P2, &mpk->Ppube); + + // A5: w = g^r + sm9_z256_fp12_pow(w, w, r); + sm9_z256_fp12_to_bytes(w, wbuf); + + // A6: K = KDF(C || w || ID_B, klen), if K == 0, goto A2 + sm3_kdf_init(&kdf_ctx, klen); + sm3_kdf_update(&kdf_ctx, cbuf + 1, 64); + sm3_kdf_update(&kdf_ctx, wbuf, sizeof(wbuf)); + sm3_kdf_update(&kdf_ctx, (uint8_t *)id, idlen); + sm3_kdf_finish(&kdf_ctx, kbuf); + + } while (mem_is_zero(kbuf, klen) == 1); + + gmssl_secure_clear(&r, sizeof(r)); + gmssl_secure_clear(&w, sizeof(w)); + gmssl_secure_clear(wbuf, sizeof(wbuf)); + gmssl_secure_clear(&kdf_ctx, sizeof(kdf_ctx)); + + // A7: output (K, C) + return 1; +} + +int sm9_kem_decrypt(const SM9_ENC_KEY *key, const char *id, size_t idlen, const SM9_Z256_POINT *C, + size_t klen, uint8_t *kbuf) +{ + sm9_z256_fp12 w; + uint8_t wbuf[32 * 12]; + uint8_t cbuf[65]; + SM3_KDF_CTX kdf_ctx; + + // B1: check C in G1 + sm9_z256_point_to_uncompressed_octets(C, cbuf); + + // B2: w = e(C, de); + sm9_z256_pairing(w, &key->de, C); + sm9_z256_fp12_to_bytes(w, wbuf); + + // B3: K = KDF(C || w || ID, klen) + sm3_kdf_init(&kdf_ctx, klen); + sm3_kdf_update(&kdf_ctx, cbuf + 1, 64); + sm3_kdf_update(&kdf_ctx, wbuf, sizeof(wbuf)); + sm3_kdf_update(&kdf_ctx, (uint8_t *)id, idlen); + sm3_kdf_finish(&kdf_ctx, kbuf); + + if (mem_is_zero(kbuf, klen)) { + error_print(); + return -1; + } + + gmssl_secure_clear(&w, sizeof(w)); + gmssl_secure_clear(wbuf, sizeof(wbuf)); + gmssl_secure_clear(&kdf_ctx, sizeof(kdf_ctx)); + + // B4: output K + return 1; +} + +int sm9_do_encrypt(const SM9_ENC_MASTER_KEY *mpk, const char *id, size_t idlen, + const uint8_t *in, size_t inlen, + SM9_Z256_POINT *C1, uint8_t *c2, uint8_t c3[SM3_HMAC_SIZE]) +{ + SM3_HMAC_CTX hmac_ctx; + uint8_t K[SM9_MAX_PLAINTEXT_SIZE + 32]; + + if (sm9_kem_encrypt(mpk, id, idlen, sizeof(K), K, C1) != 1) { + error_print(); + return -1; + } + gmssl_memxor(c2, K, in, inlen); + + //sm3_hmac(K + inlen, 32, c2, inlen, c3); + sm3_hmac_init(&hmac_ctx, K + inlen, SM3_HMAC_SIZE); + sm3_hmac_update(&hmac_ctx, c2, inlen); + sm3_hmac_finish(&hmac_ctx, c3); + gmssl_secure_clear(&hmac_ctx, sizeof(hmac_ctx)); + return 1; +} + +int sm9_do_decrypt(const SM9_ENC_KEY *key, const char *id, size_t idlen, + const SM9_Z256_POINT *C1, const uint8_t *c2, size_t c2len, const uint8_t c3[SM3_HMAC_SIZE], + uint8_t *out) +{ + SM3_HMAC_CTX hmac_ctx; + uint8_t k[SM9_MAX_PLAINTEXT_SIZE + SM3_HMAC_SIZE]; + uint8_t mac[SM3_HMAC_SIZE]; + + if (c2len > SM9_MAX_PLAINTEXT_SIZE) { + error_print(); + return -1; + } + + if (sm9_kem_decrypt(key, id, idlen, C1, sizeof(k), k) != 1) { + error_print(); + return -1; + } + //sm3_hmac(k + c2len, SM3_HMAC_SIZE, c2, c2len, mac); + sm3_hmac_init(&hmac_ctx, k + c2len, SM3_HMAC_SIZE); + sm3_hmac_update(&hmac_ctx, c2, c2len); + sm3_hmac_finish(&hmac_ctx, mac); + gmssl_secure_clear(&hmac_ctx, sizeof(hmac_ctx)); + + if (gmssl_secure_memcmp(c3, mac, sizeof(mac)) != 0) { + error_print(); + return -1; + } + gmssl_memxor(out, k, c2, c2len); + return 1; +} + +#define SM9_ENC_TYPE_XOR 0 +#define SM9_ENC_TYPE_ECB 1 +#define SM9_ENC_TYPE_CBC 2 +#define SM9_ENC_TYPE_OFB 4 +#define SM9_ENC_TYPE_CFB 8 + +/* +SM9Cipher ::= SEQUENCE { + EnType INTEGER, -- 0 for XOR + C1 BIT STRING, -- uncompressed octets of ECPoint + C3 OCTET STRING, -- 32 bytes HMAC-SM3 tag + CipherText OCTET STRING, +} +*/ +int sm9_ciphertext_to_der(const SM9_Z256_POINT *C1, const uint8_t *c2, size_t c2len, + const uint8_t c3[SM3_HMAC_SIZE], uint8_t **out, size_t *outlen) +{ + int en_type = SM9_ENC_TYPE_XOR; + uint8_t c1[65]; + size_t len = 0; + + if (sm9_z256_point_to_uncompressed_octets(C1, c1) != 1) { + error_print(); + return -1; + } + if (asn1_int_to_der(en_type, NULL, &len) != 1 + || asn1_bit_octets_to_der(c1, sizeof(c1), NULL, &len) != 1 + || asn1_octet_string_to_der(c3, SM3_HMAC_SIZE, NULL, &len) != 1 + || asn1_octet_string_to_der(c2, c2len, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_int_to_der(en_type, out, outlen) != 1 + || asn1_bit_octets_to_der(c1, sizeof(c1), out, outlen) != 1 + || asn1_octet_string_to_der(c3, SM3_HMAC_SIZE, out, outlen) != 1 + || asn1_octet_string_to_der(c2, c2len, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_ciphertext_from_der(SM9_Z256_POINT *C1, const uint8_t **c2, size_t *c2len, + const uint8_t **c3, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *d; + size_t dlen; + int en_type; + const uint8_t *c1; + size_t c1len; + size_t c3len; + + if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_int_from_der(&en_type, &d, &dlen) != 1 + || asn1_bit_octets_from_der(&c1, &c1len, &d, &dlen) != 1 + || asn1_octet_string_from_der(c3, &c3len, &d, &dlen) != 1 + || asn1_octet_string_from_der(c2, c2len, &d, &dlen) != 1 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + if (en_type != SM9_ENC_TYPE_XOR) { + error_print(); + return -1; + } + if (c1len != 65) { + error_print(); + return -1; + } + if (c3len != SM3_HMAC_SIZE) { + error_print(); + return -1; + } + if (sm9_z256_point_from_uncompressed_octets(C1, c1) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm9_encrypt(const SM9_ENC_MASTER_KEY *mpk, const char *id, size_t idlen, + const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen) +{ + SM9_Z256_POINT C1; + uint8_t c2[SM9_MAX_PLAINTEXT_SIZE]; + uint8_t c3[SM3_HMAC_SIZE]; + + if (inlen > SM9_MAX_PLAINTEXT_SIZE) { + error_print(); + return -1; + } + + if (sm9_do_encrypt(mpk, id, idlen, in, inlen, &C1, c2, c3) != 1) { + error_print(); + return -1; + } + *outlen = 0; + if (sm9_ciphertext_to_der(&C1, c2, inlen, c3, &out, outlen) != 1) { // FIXME: when out == NULL + error_print(); + return -1; + } + return 1; +} + +int sm9_decrypt(const SM9_ENC_KEY *key, const char *id, size_t idlen, + const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen) +{ + SM9_Z256_POINT C1; + const uint8_t *c2; + size_t c2len; + const uint8_t *c3; + + if (sm9_ciphertext_from_der(&C1, &c2, &c2len, &c3, &in, &inlen) != 1 + || asn1_length_is_zero(inlen) != 1) { + error_print(); + return -1; + } + *outlen = c2len; + if (!out) { + return 1; + } + if (sm9_do_decrypt(key, id, idlen, &C1, c2, c2len, c3, out) != 1) { + error_print(); + return -1; + } + return 1; +}