SM9算法C++实现系列目录:

  • 基于JPBC的SM9算法的java实现与测试

  • 国密SM9算法C++实现之0:源码下载地址

  • 国密SM9算法C++实现之一:算法简介

  • 国密SM9算法C++实现之二:测试工具

  • 国密SM9算法C++实现之三:椭圆曲线接口、参数初始化

  • 国密SM9算法C++实现之四:基本功能函数与KGC接口的实现

  • 国密SM9算法C++实现之五:签名验签算法

  • 国密SM9算法C++实现之六:密钥封装解封算法

  • 国密SM9算法C++实现之七:加密解密算法

  • 国密SM9算法C++实现之八:密钥交换算法

  • 国密SM9算法C++实现之九:算法功能与测试例子

国密SM9算法C++实现之三:曲线接口、参数初始化

文章目录

  • 国密SM9算法C++实现之三:曲线接口、参数初始化
    • @[toc]
    • 错误异常处理
    • 数学功能
      • 群G1倍点计算
      • 群G2倍点计算
      • GT群上点的数学运算和R-ate双线性对计算
    • 参数初始化
      • Parameters.h
      • Parameters.cpp
    • 双线性对计算
      • zzn12.h
      • zzn12.cpp

下面的几篇文章将描述一下基于miracl的SM9算法的各部分的实现。

首先,在实现时,底层的数学功能是miracl库提供的,另外封装了一个ZZN12类用来处理双线性对的计算;上层的算法流程使用C++写的。
其次,整个代码大致分为3个模块,第一个模块是数学功能函数的实现、参数初始化和释放,这部分涉及到miracl库中的一些对象,如大数对象,曲线点对象等,因此将其作为底层实现而屏蔽,对于使用SM9算法功能的人不需要关心,这部分实现在 Parameters 和 ZZN12 类中;第二个模块是KGC功能的实现,主要就是主密钥对和用户私钥的生成,包含在KGC类中;第三个模块就是算法功能实现,包括签名验签、密钥封装解封、加密解密、密钥交换,包含在SM9类中。
后两个模块是上层使用的模块,所有SM9中的数据都用std::string来存储,不涉及到底层的大数对象、曲线点对象等东西。另外,对于算法中设计到的包含多个数据部分的结果,都简单地封装为一个类对象。同时,所有的接口都是static的。
最后,所有的错误或异常以std::exception抛出,调用接口时需要捕获。

本篇文章中讨论第一个模块的实现和错误处理。

错误异常处理

对于在SM9文档中出现的需要作为错误处理的地方,我将其提取出来,写了一个Errors类,方便在算法实现中用std::exception抛出。

// Errors.h
#ifndef YY_SM9_ERROR_INCLUDE_H__
#define YY_SM9_ERROR_INCLUDE_H__#pragma once#include <string>
using namespace std;#define SM9_OK                                  0x00000000
#define SM9_ERROR_NOT_INIT                      0x00000001
#define SM9_ERROR_INIT_G1BASEPOINT              0x00000002
#define SM9_ERROR_INIT_G2BASEPOINT              0x00000003
#define SM9_ERROR_CALC_RATE                     0x00000004
#define SM9_ERROR_KGC_GENPRIKEY_T1_IS_ZERO      0x00000005
#define SM9_ERROR_KGC_WRONG_PRIKEY_TYPE         0x00000006
#define SM9_ERROR_VERIFY_H_OUTRANGE             0x00000007
#define SM9_ERROR_VERIFY_S_NOT_ON_G1            0x00000008
#define SM9_ERROR_VERIFY_H_VERIFY_FAILED        0x00000009
#define SM9_ERROR_DECAP_C_NOT_ON_G1             0x0000000A
#define SM9_ERROR_DECAP_K_IS_ZERO               0x0000000B
#define SM9_ERROR_DECRYPT_C1_NOT_ON_G1          0x0000000C
#define SM9_ERROR_DECRYPT_K1_IS_ZERO            0x0000000D
#define SM9_ERROR_DECRYPT_C3_VERIFY_FAILED      0x0000000E
#define SM9_ERROR_KEYEXCHANGE_R_NOT_ON_G1       0x0000000F/**
* 错误值类.
* @author YaoYuan
*/
class Errors {
private:Errors() {}~Errors() {}public:static string getErrorMsg(int errnum) {string msg = "Unknown error";switch( errnum ){case SM9_OK:msg = "Success";break;case SM9_ERROR_NOT_INIT:msg = "Not init";break;case SM9_ERROR_INIT_G1BASEPOINT:msg = "G1 init error";break;case SM9_ERROR_INIT_G2BASEPOINT:msg = "G2 init error";break;case SM9_ERROR_CALC_RATE:msg = "R-ate result is not of order q";break;case SM9_ERROR_VERIFY_H_OUTRANGE:msg = "Verify : h is out range";break;case SM9_ERROR_VERIFY_S_NOT_ON_G1:msg = "Verify : s is not on G1";break;case SM9_ERROR_VERIFY_H_VERIFY_FAILED:msg = "Verify failed, h verify failed";break;case SM9_ERROR_DECAP_C_NOT_ON_G1:msg = "Decapsulate : C is not on G1";break;case SM9_ERROR_DECAP_K_IS_ZERO:msg = "Decapsulate : K is zero";break;case SM9_ERROR_DECRYPT_C1_NOT_ON_G1:msg = "Decrypt : C1 is not on G1";break;case SM9_ERROR_DECRYPT_K1_IS_ZERO:msg = "Decrypt : K is zero";break;case SM9_ERROR_DECRYPT_C3_VERIFY_FAILED:msg = "Decrypt : C3 verify failed";break;case SM9_ERROR_KEYEXCHANGE_R_NOT_ON_G1:msg = "Key Exchange : R not on G1";break;case SM9_ERROR_KGC_GENPRIKEY_T1_IS_ZERO:msg = "t1 is zero while KGC generate private key";break;case SM9_ERROR_KGC_WRONG_PRIKEY_TYPE:msg = "Wrong private key type for generate private key";break;default:break;}return msg;}
};#endif

数学功能

在实现SM9算法时,有几个数学功能需要先实现,即群G1/G2上的倍点计算、GT群上点的数学运算、R-ate双线性对计算。

群G1倍点计算

miracl库中以"ecurve_"开头的函数提供了SM9中素域上的G1群的数学功能。

群G2倍点计算

miracle库中以"ecn2_"开头的函数提供SM9中G1的2次扩域G2群的数学功能。

GT群上点的数学运算和R-ate双线性对计算

miralcl库的源码中的"curve/pairing"目录下提供了12次扩域群的数学功能,和双线性对的实现。在本例中,参考我从网上下载的源码后,把这部分功能封装在ZZN12类中。

参数初始化

参数初始化相关部分放在Parameters类中,包括:

  • 为SM9参数的初始化提供init()函数,为参数释放提供release()函数。
  • 在代码实现中,内部涉及到miracl库的一些结构体对象,如big、zzn2、zzn4、ecn2、epoint等,因此在Parameters类中提供了"init_"和"release_"开头的函数来初始化和释放这些对象。
  • 在代码实现中,需要在内部的结构体对象和string之间进行转换,因此提供了一些"cin_"和"cout_"开头的函数来实现这部分功能。
  • 在SM9算法中有时需要判断一个点是否在G1上,G1上的点用epoint表示,是个底层对象,因此将这个函数放在Parameters中,名为isPointOnG1(epoint* var)。
  • 还有一两个函数是与ZZN12计算有关的,也放在Parameters中。
  • 在init()函数中,使用c++的随机数功能初始化了miracl的随机数生成器。

Parameters类的内容如下:

Parameters.h

// Parameters.h
#ifndef YY_SM9_Parameters_INCLUDE_H__
#define YY_SM9_Parameters_INCLUDE_H__#pragma once#include <string>
using namespace std;#ifdef __cplusplus
extern "C" {
#include "miracl/miracl.h"
}
#endif#define BIG_LEN 2000
#define SELF_CHECK 1class Parameters {
private:Parameters();~Parameters();public:static bool init();static void release();static void init_big(big& var);static void release_big(big& var);static void init_zzn2(zzn2& var);static void release_zzn2(zzn2& var);static void init_zzn4(zzn4& var);static void release_zzn4(zzn4& var);static void init_ecn2(ecn2& var);static void release_ecn2(ecn2& var);static void init_epoint(epoint*& var);static void release_epoint(epoint* var);public:static string cout_big(big& var);static void cin_big(big& var, const unsigned char* buf, int length);static void cin_big(big& var, const char* buf, int length) { cin_big(var, (const unsigned char*)buf, length); }static string cout_ecn2(ecn2& var);static bool cin_ecn2_byte128(ecn2& var, const char* buf);static string cout_epoint(epoint* var);static void cin_epoint(epoint* var, const char* buf);public:static bool isPointOnG1(epoint* var);private:static void setFrobeniusNormCconstant();static void zzn2_pow(zzn2& x, big& k, zzn2& r); // r=x^kstatic string cout_ecn2_big(big& var);public:static int getErrorNum() noexcept { return mErrorNum; }private:static int mErrorNum;
public:static const int BNLEN;public:static big param_a;static big param_b;static big param_N;static big param_q;static big param_t;static epoint* param_P1;static ecn2 param_P2;static zzn2 norm_X; //Frobenius norm constantstatic miracl* mMip;
};#endif

Parameters.cpp

// Parameters.cpp
#include "Parameters.h"
#include "Errors.h"
#include <random>#ifdef _WIN32
#ifdef _DEBUG
#pragma comment(lib, "miracld.lib")
#else
#pragma comment(lib, "miracl.lib")
#endif
#endifunsigned char SM9_q[32] = {0xB6,0x40,0x00,0x00,0x02,0xA3,0xA6,0xF1,0xD6,0x03,0xAB,0x4F,0xF5,0x8E,0xC7,0x45,0x21,0xF2,0x93,0x4B,0x1A,0x7A,0xEE,0xDB,0xE5,0x6F,0x9B,0x27,0xE3,0x51,0x45,0x7D
};unsigned char SM9_N[32] = {0xB6,0x40,0x00,0x00,0x02,0xA3,0xA6,0xF1,0xD6,0x03,0xAB,0x4F,0xF5,0x8E,0xC7,0x44,0x49,0xF2,0x93,0x4B,0x18,0xEA,0x8B,0xEE,0xE5,0x6E,0xE1,0x9C,0xD6,0x9E,0xCF,0x25
};unsigned char SM9_P1x[32] = {0x93,0xDE,0x05,0x1D,0x62,0xBF,0x71,0x8F,0xF5,0xED,0x07,0x04,0x48,0x7D,0x01,0xD6,0xE1,0xE4,0x08,0x69,0x09,0xDC,0x32,0x80,0xE8,0xC4,0xE4,0x81,0x7C,0x66,0xDD,0xDD
};unsigned char SM9_P1y[32] = {0x21,0xFE,0x8D,0xDA,0x4F,0x21,0xE6,0x07,0x63,0x10,0x65,0x12,0x5C,0x39,0x5B,0xBC,0x1C,0x1C,0x00,0xCB,0xFA,0x60,0x24,0x35,0x0C,0x46,0x4C,0xD7,0x0A,0x3E,0xA6,0x16
};unsigned char SM9_P2[128] = {0x85,0xAE,0xF3,0xD0,0x78,0x64,0x0C,0x98,0x59,0x7B,0x60,0x27,0xB4,0x41,0xA0,0x1F,0xF1,0xDD,0x2C,0x19,0x0F,0x5E,0x93,0xC4,0x54,0x80,0x6C,0x11,0xD8,0x80,0x61,0x41,0x37,0x22,0x75,0x52,0x92,0x13,0x0B,0x08,0xD2,0xAA,0xB9,0x7F,0xD3,0x4E,0xC1,0x20,0xEE,0x26,0x59,0x48,0xD1,0x9C,0x17,0xAB,0xF9,0xB7,0x21,0x3B,0xAF,0x82,0xD6,0x5B,0x17,0x50,0x9B,0x09,0x2E,0x84,0x5C,0x12,0x66,0xBA,0x0D,0x26,0x2C,0xBE,0xE6,0xED,0x07,0x36,0xA9,0x6F,0xA3,0x47,0xC8,0xBD,0x85,0x6D,0xC7,0x6B,0x84,0xEB,0xEB,0x96,0xA7,0xCF,0x28,0xD5,0x19,0xBE,0x3D,0xA6,0x5F,0x31,0x70,0x15,0x3D,0x27,0x8F,0xF2,0x47,0xEF,0xBA,0x98,0xA7,0x1A,0x08,0x11,0x62,0x15,0xBB,0xA5,0xC9,0x99,0xA7,0xC7
};unsigned char SM9_t[32] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x58,0xF9,0x8A
};unsigned char SM9_a[32] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};unsigned char SM9_b[32] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05
};int Parameters::mErrorNum = SM9_OK;
const int Parameters::BNLEN = 32;
big Parameters::param_N = NULL;
big Parameters::param_a = NULL;
big Parameters::param_b = NULL;
big Parameters::param_q = NULL;
big Parameters::param_t = NULL;
epoint* Parameters::param_P1 = NULL;
ecn2 Parameters::param_P2;
zzn2 Parameters::norm_X;
miracl* Parameters::mMip = NULL;Parameters::Parameters()
{}Parameters::~Parameters()
{}void Parameters::setFrobeniusNormCconstant()
{big p, zero, one, two;zzn2 tmp_norm_X;init_big(p);init_big(zero);init_big(one);init_big(two);init_zzn2(tmp_norm_X);convert(0, zero);convert(1, one);convert(2, two);copy(mMip->modulus, p);switch( get_mip()->pmod8 ){case 5:zzn2_from_bigs(zero, one, &tmp_norm_X);// = (sqrt(-2)^(p-1)/2break;case 3:zzn2_from_bigs(one, one, &tmp_norm_X); // = (1+sqrt(-1))^(p-1)/2break;case 7:zzn2_from_bigs(two, one, &tmp_norm_X);// = (2+sqrt(-1))^(p-1)/2default: break;}decr(p, 1, p);subdiv(p, 6, p);zzn2_pow(tmp_norm_X, p, norm_X);release_big(p);release_big(zero);release_big(one);release_big(two);release_zzn2(tmp_norm_X);
}bool Parameters::init()
{bool result = false;big P1_x = NULL;big P1_y = NULL; BOOL br = FALSE;mMip = mirsys(BIG_LEN, 16);mMip->IOBASE = 16;mMip->TWIST = MR_SEXTIC_M;// Initialize random seedstd::random_device rd;std::default_random_engine mGenerator;std::uniform_int_distribution<unsigned int> mDistribute(0, UINT_MAX);mGenerator.seed(rd());irand(mDistribute(mGenerator));init_big(P1_x); init_big(P1_y);init_big(param_N);init_big(param_a);init_big(param_b);init_big(param_q);init_big(param_t);init_epoint(param_P1);init_ecn2(param_P2);init_zzn2(norm_X);cin_big(param_N, (char*)SM9_N, sizeof(SM9_N));cin_big(param_a, (char*)SM9_a, sizeof(SM9_a));cin_big(param_b, (char*)SM9_b, sizeof(SM9_b));cin_big(param_q, (char*)SM9_q, sizeof(SM9_q));cin_big(param_t, (char*)SM9_t, sizeof(SM9_t));//Initialize GF(q) elliptic curve, MR_PROJECTIVE specifying projective coordinatesecurve_init(param_a, param_b, param_q, MR_PROJECTIVE); cin_big(P1_x, (char*)SM9_P1x, sizeof(SM9_P1x));cin_big(P1_y, (char*)SM9_P1y, sizeof(SM9_P1y));br = epoint_set(P1_x, P1_y, 0, param_P1);result = br ? true : false;if( result ) {result = cin_ecn2_byte128(param_P2, (const char*)SM9_P2);if( !result ) {mErrorNum = SM9_ERROR_INIT_G2BASEPOINT;goto END;}} else {mErrorNum = SM9_ERROR_INIT_G1BASEPOINT;goto END;}setFrobeniusNormCconstant();result = true;END:release_big(P1_x);release_big(P1_y);if( !result ) {release();}return result;
}void Parameters::release()
{mirkill(param_N);mirkill(param_a);mirkill(param_b);mirkill(param_q);mirkill(param_t);release_epoint(param_P1);release_ecn2(param_P2);release_zzn2(norm_X);mirexit();mErrorNum = SM9_OK;
}void Parameters::init_big(big& var)
{var = mirvar(0);
}void Parameters::release_big(big& var)
{mirkill(var);
}void Parameters::init_zzn2(zzn2& var)
{var.a = mirvar(0);var.b = mirvar(0);
}void Parameters::release_zzn2(zzn2& var)
{mirkill(var.a);mirkill(var.b);
}void Parameters::init_zzn4(zzn4& var)
{var.a.a = mirvar(0);var.a.b = mirvar(0);var.b.a = mirvar(0);var.b.b = mirvar(0);var.unitary = FALSE;
}void Parameters::release_zzn4(zzn4& var)
{mirkill(var.a.a);mirkill(var.a.b);mirkill(var.b.a);mirkill(var.b.b);
}void Parameters::init_ecn2(ecn2& var)
{var.x.a = mirvar(0); var.x.b = mirvar(0); var.y.a = mirvar(0); var.y.b = mirvar(0);var.z.a = mirvar(0); var.z.b = mirvar(0); var.marker = MR_EPOINT_INFINITY;
}void Parameters::release_ecn2(ecn2& var)
{mirkill(var.x.a); mirkill(var.x.b);mirkill(var.y.a); mirkill(var.y.b);mirkill(var.z.a); mirkill(var.z.b);
}void Parameters::init_epoint(epoint*& var)
{var = epoint_init();
}void Parameters::release_epoint(epoint* var)
{epoint_free(var);
}bool Parameters::cin_ecn2_byte128(ecn2& var, const char* buf)
{ecn2 r;zzn2 x, y;big a=NULL, b=NULL;init_ecn2(r);init_zzn2(x);init_zzn2(y);init_big(a);init_big(b);bytes_to_big(BNLEN, (char*)buf, b);bytes_to_big(BNLEN, (char*)buf + BNLEN, a);zzn2_from_bigs(a, b, &x);bytes_to_big(BNLEN, (char*)buf + BNLEN * 2, b);bytes_to_big(BNLEN, (char*)buf + BNLEN * 3, a);zzn2_from_bigs(a, b, &y);BOOL ret = ecn2_set(&x, &y, &r);if(ret) ecn2_copy(&r, &var);release_ecn2(r);release_zzn2(x);release_zzn2(y);release_big(a);release_big(b);return ret ? true : false;
}string Parameters::cout_ecn2_big(big& var)
{big tmp = NULL;init_big(tmp);redc(var, tmp);int length = tmp->len * sizeof(tmp->w);char *buffer = new char[length];int ret = big_to_bytes(length, tmp, buffer, TRUE);string result(buffer, ret);delete[] buffer;release_big(tmp);return result;
}string Parameters::cout_ecn2(ecn2& var)
{string result;result.append(cout_ecn2_big(var.x.b));result.append(cout_ecn2_big(var.x.a));result.append(cout_ecn2_big(var.y.b));result.append(cout_ecn2_big(var.y.a));return result;
}void Parameters::cin_big(big& var, const unsigned char* buf, int length)
{bytes_to_big(length, (const char*)buf, var);
}std::string Parameters::cout_epoint(epoint* var)
{big x = NULL;big y = NULL;string result;init_big(x);init_big(y);epoint_get(var, x, y);result.append(cout_big(x));result.append(cout_big(y));release_big(x);release_big(y);return result;
}void Parameters::cin_epoint(epoint* var, const char* buf)
{big x = NULL;big y = NULL;init_big(x);init_big(y);cin_big(x, buf, BNLEN);cin_big(y, buf+BNLEN, BNLEN);epoint_set(x, y, 0, var);release_big(x);release_big(y);
}string Parameters::cout_big(big& var)
{int length = var->len * sizeof(var->w);char *buffer = new char[length];int ret = big_to_bytes(length, var, buffer, FALSE);string result(buffer, ret);delete[] buffer;return result;
}bool Parameters::isPointOnG1(epoint* var)
{bool result = false;big x = NULL;big y = NULL;big x_3 = NULL;big tmp = NULL;epoint* buf = NULL;init_big(x);init_big(y);init_big(x_3);init_big(tmp);init_epoint(buf);//check y^2=x^3+bepoint_get(var, x, y);power(x, 3, param_q, x_3); //x_3=x^3 mod pmultiply(x, param_a, x);divide(x, param_q, tmp);add(x_3, x, x); //x=x^3+ax+badd(x, param_b, x);divide(x, param_q, tmp); //x=x^3+ax+b mod ppower(y, 2, param_q, y); //y=y^2 mod pif( mr_compare(x, y) != 0 )return 1;//check infinityecurve_mult(param_N, var, buf);if( point_at_infinity(buf) == TRUE )result = true;release_big(x);release_big(y);release_big(x_3);release_big(tmp);release_epoint(buf);return result;
}void Parameters::zzn2_pow(zzn2& x, big& k, zzn2& r)
{int i, j, nb, n, nbw, nzs;big zero;zzn2 u2, t[16];init_big(zero);init_zzn2(u2);    for( i = 0; i < 16; i++ ){init_zzn2(t[i]);}if( zzn2_iszero(&x) ){zzn2_zero(&r);goto END;}if( size(k) == 0 ){zzn2_from_int(1, &r);goto END;}if( size(k) == 1 ) {zzn2_copy(&x, &r);goto END;}// Prepare table for windowingzzn2_mul(&x, &x, &u2);zzn2_copy(&x, &t[0]);for( i = 1; i < 16; i++ ){zzn2_mul(&t[i - 1], &u2, &t[i]);}// Left to right method - with windowszzn2_copy(&x, &r);nb = logb2(k);if( nb > 1 ) for( i = nb - 2; i >= 0;){//Note new parameter of window_size=5. Default to 5, but reduce to 4 (or even 3) to save RAMn = mr_window(k, i, &nbw, &nzs, 5);for( j = 0; j < nbw; j++ ) zzn2_mul(&r, &r, &r);if( n > 0 ) zzn2_mul(&r, &t[n / 2], &r);i -= nbw;if( nzs ){for( j = 0; j < nzs; j++ ) zzn2_mul(&r, &r, &r);i -= nzs;}}END:release_big(zero);release_zzn2(u2);for( i = 0; i < 16; i++ ) {release_zzn2(t[i]);}
}

双线性对计算

双线性对的计算以及GT元素的对象在ZZN12类中,由SM9算法部分使用,KGC部分不用。

zzn12.h


#ifndef YY_SM9_ZZN12_INCLUDE_H__
#define YY_SM9_ZZN12_INCLUDE_H__#pragma once #include <string>
using namespace std;#ifdef __cplusplus
extern "C" {
#include "miracl/miracl.h"
}
#endifclass ZZN12 {
public:ZZN12();ZZN12(const ZZN12& var);ZZN12& operator=(const ZZN12& var);~ZZN12();public:string toByteArray();public:ZZN12 mul(ZZN12& var); // return this*varZZN12 conj();ZZN12 inverse();ZZN12 powq(zzn2& var);ZZN12 div(ZZN12& var); // return this/yZZN12 pow(big k); // return this^kbool isOrderQ(); // pairing
public:static void q_power_frobenius(ecn2 A, zzn2 F);static ZZN12 line(ecn2 A, ecn2 *C, ecn2 *B, zzn2 slope, zzn2 extra, BOOL Doubling, big Qx, big Qy);static ZZN12 g(ecn2 *A, ecn2 *B, big Qx, big Qy);static bool fast_pairing(ZZN12& ret, ecn2 P, big Qx, big Qy, big x, zzn2 X);static bool calcRatePairing(ZZN12& ret, ecn2 P, epoint *Q, big x, zzn2 X);private:void init();void release();string cout_zzn12_big(big& var);private:zzn4 a, b, c;BOOL unitary; // "unitary property means that fast squaring can be used, and inversions are just conjugatesBOOL miller;  // "miller" property means that arithmetic on this instance can ignore multiplications// or divisions by constants - as instance will eventually be raised to (p-1).
};#endif

zzn12.cpp


#include "zzn12.h"
#include "Parameters.h"ZZN12::ZZN12()
{init();
}ZZN12::ZZN12(const ZZN12& var)
{init();zzn4_copy((zzn4*)&var.a, &a); zzn4_copy((zzn4*)&var.b, &b); zzn4_copy((zzn4*)&var.c, &c);miller = var.miller;unitary = var.unitary;
}ZZN12& ZZN12::operator=(const ZZN12& var)
{zzn4_copy((zzn4*)&var.a, &a);zzn4_copy((zzn4*)&var.b, &b);zzn4_copy((zzn4*)&var.c, &c);miller = var.miller;unitary = var.unitary;return *this;
}ZZN12::~ZZN12()
{release();
}void ZZN12::init()
{a.a.a = mirvar(0); a.a.b = mirvar(0);a.b.a = mirvar(0); a.b.b = mirvar(0); a.unitary = FALSE;b.a.a = mirvar(0); b.a.b = mirvar(0);b.b.a = mirvar(0); b.b.b = mirvar(0); b.unitary = FALSE;c.a.a = mirvar(0); c.a.b = mirvar(0);c.b.a = mirvar(0); c.b.b = mirvar(0); c.unitary = FALSE;unitary = FALSE; miller = FALSE;
}void ZZN12::release()
{mirkill(a.a.a); mirkill(a.a.b);mirkill(a.b.a); mirkill(a.b.b);mirkill(b.a.a); mirkill(b.a.b);mirkill(b.b.a); mirkill(b.b.b);mirkill(c.a.a); mirkill(c.a.b);mirkill(c.b.a); mirkill(c.b.b);
}std::string ZZN12::toByteArray()
{string result;result.append(cout_zzn12_big(c.b.b));result.append(cout_zzn12_big(c.b.a));result.append(cout_zzn12_big(c.a.b));result.append(cout_zzn12_big(c.a.a));result.append(cout_zzn12_big(b.b.b));result.append(cout_zzn12_big(b.b.a));result.append(cout_zzn12_big(b.a.b));result.append(cout_zzn12_big(b.a.a));result.append(cout_zzn12_big(a.b.b));result.append(cout_zzn12_big(a.b.a));result.append(cout_zzn12_big(a.a.b));result.append(cout_zzn12_big(a.a.a));return result;
}string ZZN12::cout_zzn12_big(big& var)
{big tmp = NULL;tmp = mirvar(0);redc(var, tmp);int length = tmp->len * sizeof(tmp->w);char *buffer = new char[length];int ret = big_to_bytes(length, tmp, buffer, TRUE);string result(buffer, ret);delete[] buffer;mirkill(tmp);return result;
}ZZN12 ZZN12::mul(ZZN12& var)
{// Karatsubazzn4 Z0, Z1, Z2, Z3, T0, T1;ZZN12 ret(*this);BOOL zero_c, zero_b;Parameters::init_zzn4(Z0);Parameters::init_zzn4(Z1);Parameters::init_zzn4(Z2);Parameters::init_zzn4(Z3);Parameters::init_zzn4(T0);Parameters::init_zzn4(T1);if( zzn4_compare(&a, &var.a) && zzn4_compare(&a, &var.a) && zzn4_compare(&a, &var.a) ){if( unitary == TRUE ){zzn4_copy(&a, &Z0); zzn4_mul(&a, &a, &ret.a); zzn4_copy(&ret.a, &Z3); zzn4_add(&ret.a, &ret.a, &ret.a);zzn4_add(&ret.a, &Z3, &ret.a); zzn4_conj(&Z0, &Z0); zzn4_add(&Z0, &Z0, &Z0); zzn4_sub(&ret.a, &Z0, &ret.a);zzn4_copy(&c, &Z1); zzn4_mul(&Z1, &Z1, &Z1); zzn4_tx(&Z1);zzn4_copy(&Z1, &Z3); zzn4_add(&Z1, &Z1, &Z1); zzn4_add(&Z1, &Z3, &Z1);zzn4_copy(&b, &Z2); zzn4_mul(&Z2, &Z2, &Z2);zzn4_copy(&Z2, &Z3); zzn4_add(&Z2, &Z2, &Z2); zzn4_add(&Z2, &Z3, &Z2);zzn4_conj(&b, &ret.b); zzn4_add(&ret.b, &ret.b, &ret.b);zzn4_conj(&c, &ret.c); zzn4_add(&ret.c, &ret.c, &ret.c); zzn4_negate(&ret.c, &ret.c);zzn4_add(&ret.b, &Z1, &ret.b); zzn4_add(&ret.c, &Z2, &ret.c);} else{if( !miller ){// Chung-Hasan SQR2zzn4_copy(&a, &Z0); zzn4_mul(&Z0, &Z0, &Z0);zzn4_mul(&b, &c, &Z1); zzn4_add(&Z1, &Z1, &Z1);zzn4_copy(&c, &Z2); zzn4_mul(&Z2, &Z2, &Z2);zzn4_mul(&a, &b, &Z3); zzn4_add(&Z3, &Z3, &Z3);zzn4_add(&a, &b, &ret.c); zzn4_add(&ret.c, &c, &ret.c); zzn4_mul(&ret.c, &ret.c, &ret.c);zzn4_tx(&Z1); zzn4_add(&Z0, &Z1, &ret.a);zzn4_tx(&Z2); zzn4_add(&Z3, &Z2, &ret.b);zzn4_add(&Z0, &Z1, &T0); zzn4_add(&T0, &Z2, &T0);zzn4_add(&T0, &Z3, &T0); zzn4_sub(&ret.c, &T0, &ret.c);} else{// Chung-Hasan SQR3 - actually calculate 2x^2 !// Slightly dangerous - but works as will be raised to p^{k/2}-1// which wipes out the 2.zzn4_copy(&a, &Z0); zzn4_mul(&Z0, &Z0, &Z0);// a0^2 = S0zzn4_copy(&c, &Z2); zzn4_mul(&Z2, &b, &Z2); zzn4_add(&Z2, &Z2, &Z2); // 2a1.a2 = S3zzn4_copy(&c, &Z3); zzn4_mul(&Z3, &Z3, &Z3);; // a2^2 = S4zzn4_add(&c, &a, &ret.c); // a0+a2zzn4_copy(&b, &Z1); zzn4_add(&Z1, &ret.c, &Z1); zzn4_mul(&Z1, &Z1, &Z1);// (a0+a1+a2)^2 =S1zzn4_sub(&ret.c, &b, &ret.c); zzn4_mul(&ret.c, &ret.c, &ret.c);// (a0-a1+a2)^2 =S2zzn4_add(&Z2, &Z2, &Z2); zzn4_add(&Z0, &Z0, &Z0); zzn4_add(&Z3, &Z3, &Z3);zzn4_sub(&Z1, &ret.c, &T0); zzn4_sub(&T0, &Z2, &T0);zzn4_sub(&Z1, &Z0, &T1); zzn4_sub(&T1, &Z3, &T1); zzn4_add(&ret.c, &T1, &ret.c);zzn4_tx(&Z3); zzn4_add(&T0, &Z3, &ret.b);zzn4_tx(&Z2); zzn4_add(&Z0, &Z2, &ret.a);}}} else{// Karatsubazero_b = zzn4_iszero(&var.b);zero_c = zzn4_iszero(&var.c);zzn4_mul(&a, &var.a, &Z0); //9if( !zero_b ) zzn4_mul(&b, &var.b, &Z2); //+6zzn4_add(&a, &b, &T0);zzn4_add(&var.a, &var.b, &T1);zzn4_mul(&T0, &T1, &Z1); //+9zzn4_sub(&Z1, &Z0, &Z1);if( !zero_b ) zzn4_sub(&Z1, &Z2, &Z1);zzn4_add(&b, &c, &T0);zzn4_add(&var.b, &var.c, &T1);zzn4_mul(&T0, &T1, &Z3);//+6if( !zero_b ) zzn4_sub(&Z3, &Z2, &Z3);zzn4_add(&a, &c, &T0);zzn4_add(&var.a, &var.c, &T1);zzn4_mul(&T0, &T1, &T0);//+9=39 for "special case"if( !zero_b ) zzn4_add(&Z2, &T0, &Z2);else zzn4_copy(&T0, &Z2);zzn4_sub(&Z2, &Z0, &Z2);zzn4_copy(&Z1, &ret.b);if( !zero_c ){ // exploit special form of BN curve line functionzzn4_mul(&c, &var.c, &T0);zzn4_sub(&Z2, &T0, &Z2);zzn4_sub(&Z3, &T0, &Z3); zzn4_tx(&T0);zzn4_add(&ret.b, &T0, &ret.b);}zzn4_tx(&Z3);zzn4_add(&Z0, &Z3, &ret.a);zzn4_copy(&Z2, &ret.c);if( !var.unitary ) ret.unitary = FALSE;}Parameters::release_zzn4(Z0);Parameters::release_zzn4(Z1);Parameters::release_zzn4(Z2);Parameters::release_zzn4(Z3);Parameters::release_zzn4(T0);Parameters::release_zzn4(T1);return ret;
}ZZN12 ZZN12::conj()
{ZZN12 ret;zzn4_conj(&a, &ret.a);zzn4_conj(&b, &ret.b);zzn4_negate(&ret.b, &ret.b);zzn4_conj(&c, &ret.c);ret.miller = miller;ret.unitary = unitary;return ret;
}ZZN12 ZZN12::inverse()
{zzn4 tmp1, tmp2;ZZN12 ret;Parameters::init_zzn4(tmp1);Parameters::init_zzn4(tmp2);if( unitary ){ret =conj();goto END;}//ret.a=a*a-tx(b*c);zzn4_mul(&a, &a, &ret.a);zzn4_mul(&b, &c, &ret.b); zzn4_tx(&ret.b);zzn4_sub(&ret.a, &ret.b, &ret.a);//ret.b=tx(c*c)-a*b;zzn4_mul(&c, &c, &ret.c); zzn4_tx(&ret.c);zzn4_mul(&a, &b, &ret.b); zzn4_sub(&ret.c, &ret.b, &ret.b);//ret.c=b*b-a*c;zzn4_mul(&b, &b, &ret.c); zzn4_mul(&a, &c, &tmp1); zzn4_sub(&ret.c, &tmp1, &ret.c);//tmp1=tx(b*ret.c)+a*ret.a+tx(c*ret.b);zzn4_mul(&b, &ret.c, &tmp1); zzn4_tx(&tmp1);zzn4_mul(&a, &ret.a, &tmp2); zzn4_add(&tmp1, &tmp2, &tmp1);zzn4_mul(&c, &ret.b, &tmp2); zzn4_tx(&tmp2); zzn4_add(&tmp1, &tmp2, &tmp1);zzn4_inv(&tmp1);zzn4_mul(&ret.a, &tmp1, &ret.a);zzn4_mul(&ret.b, &tmp1, &ret.b);zzn4_mul(&ret.c, &tmp1, &ret.c);END:Parameters::release_zzn4(tmp1);Parameters::release_zzn4(tmp2);return ret;
}ZZN12 ZZN12::powq(zzn2& var)
{ZZN12 ret(*this);zzn2 X2, X3;Parameters::init_zzn2(X2);Parameters::init_zzn2(X3);zzn2_mul(&var, &var, &X2);zzn2_mul(&X2, &var, &X3);zzn4_powq(&X3, &ret.a); zzn4_powq(&X3, &ret.b); zzn4_powq(&X3, &ret.c);zzn4_smul(&ret.b, &Parameters::norm_X, &ret.b);zzn4_smul(&ret.c, &X2, &ret.c);Parameters::release_zzn2(X2);Parameters::release_zzn2(X3);return ret;
}ZZN12 ZZN12::div(ZZN12& var)
{ZZN12 y = var.inverse();return mul(y);
}ZZN12 ZZN12::pow(big k)
{ZZN12 ret;big zero, tmp, tmp1;int nb, i;BOOL invert_it;Parameters::init_big(zero);Parameters::init_big(tmp);Parameters::init_big(tmp1);copy(k, tmp1);invert_it = FALSE;if( mr_compare(tmp1, zero) == 0 ){tmp = get_mip()->one;zzn4_from_big(tmp, &ret.a);goto END;}if( mr_compare(tmp1, zero) < 0 ){negify(tmp1, tmp1); invert_it = TRUE;}nb = logb2(k);ret = *this;if( nb > 1 ) for( i = nb - 2; i >= 0; i-- ){ret = ret.mul(ret);if( mr_testbit(k, i) ) ret = ret.mul(*this);}if( invert_it ) ret = ret.inverse();END:Parameters::release_big(zero);Parameters::release_big(tmp);Parameters::release_big(tmp1);return ret;
}bool ZZN12::isOrderQ()
{bool result = false;ZZN12 v(*this);ZZN12 w(*this);big six;Parameters::init_big(six);convert(6, six);w = w.powq(Parameters::norm_X);v = v.pow(Parameters::param_t);v = v.pow(Parameters::param_t);v = v.pow(six);if( zzn4_compare(&w.a, &v.a) && zzn4_compare(&w.a, &v.a) && zzn4_compare(&w.a, &v.a) ) {result = true;goto END;}END:Parameters::release_big(six);return result;
}void ZZN12::q_power_frobenius(ecn2 A, zzn2 F)
{// Fast multiplication of A by q (for Trace-Zero group members only)zzn2 x, y, z, w, r;Parameters::init_zzn2(x);Parameters::init_zzn2(y);Parameters::init_zzn2(z);Parameters::init_zzn2(w);Parameters::init_zzn2(r);ecn2_get(&A, &x, &y, &z);zzn2_copy(&F, &r);//r=Fif( get_mip()->TWIST == MR_SEXTIC_M ) zzn2_inv(&r); // could be precalculatedzzn2_mul(&r, &r, &w);//w=r*rzzn2_conj(&x, &x); zzn2_mul(&w, &x, &x);zzn2_conj(&y, &y); zzn2_mul(&w, &r, &w); zzn2_mul(&w, &y, &y);zzn2_conj(&z, &z);ecn2_setxyz(&x, &y, &z, &A);Parameters::release_zzn2(x);Parameters::release_zzn2(y);Parameters::release_zzn2(z);Parameters::release_zzn2(w);Parameters::release_zzn2(r);
}ZZN12 ZZN12::line(ecn2 A, ecn2 *C, ecn2 *B, zzn2 slope, zzn2 extra, BOOL Doubling, big Qx, big Qy)
{ZZN12 ret;zzn2 X, Y, Z, Z2, U, QY, CZ;big QX;Parameters::init_big(QX);Parameters::init_zzn2(X);Parameters::init_zzn2(Y);Parameters::init_zzn2(Z);Parameters::init_zzn2(Z2);Parameters::init_zzn2(U);Parameters::init_zzn2(QY);Parameters::init_zzn2(CZ);ecn2_getz(C, &CZ);// Thanks to A. Menezes for pointing out this optimization...if( Doubling ){ecn2_get(&A, &X, &Y, &Z);zzn2_mul(&Z, &Z, &Z2); //Z2=Z*Z//X=slope*X-extrazzn2_mul(&slope, &X, &X);zzn2_sub(&X, &extra, &X);zzn2_mul(&CZ, &Z2, &U);//(-(Z*Z*slope)*Qx);nres(Qx, QX);zzn2_mul(&Z2, &slope, &Y);zzn2_smul(&Y, QX, &Y);zzn2_negate(&Y, &Y);if( get_mip()->TWIST == MR_SEXTIC_M ){ // "multiplied across" by i to simplifyzzn2_from_big(Qy, &QY);zzn2_txx(&QY);zzn2_mul(&U, &QY, &QY);zzn4_from_zzn2s(&QY, &X, &ret.a);zzn2_copy(&Y, &(ret.c.b));}if( get_mip()->TWIST == MR_SEXTIC_D ){zzn2_smul(&U, Qy, &QY);zzn4_from_zzn2s(&QY, &X, &ret.a);zzn2_copy(&Y, &(ret.b.b));}} else{ //slope*X-Y*Zecn2_getxy(B, &X, &Y);zzn2_mul(&slope, &X, &X);zzn2_mul(&Y, &CZ, &Y);zzn2_sub(&X, &Y, &X);//(-slope*Qx)nres(Qx, QX);zzn2_smul(&slope, QX, &Z);zzn2_negate(&Z, &Z);if( get_mip()->TWIST == MR_SEXTIC_M ){zzn2_from_big(Qy, &QY);zzn2_txx(&QY);zzn2_mul(&CZ, &QY, &QY);zzn4_from_zzn2s(&QY, &X, &ret.a);zzn2_copy(&Z, &(ret.c.b));}if( get_mip()->TWIST == MR_SEXTIC_D ){zzn2_smul(&CZ, Qy, &QY);zzn4_from_zzn2s(&QY, &X, &ret.a);zzn2_copy(&Z, &(ret.b.b));}}Parameters::release_big(QX);Parameters::release_zzn2(X);Parameters::release_zzn2(Y);Parameters::release_zzn2(Z);Parameters::release_zzn2(Z2);Parameters::release_zzn2(U);Parameters::release_zzn2(QY);Parameters::release_zzn2(CZ);return ret;
}ZZN12 ZZN12::g(ecn2 *A, ecn2 *B, big Qx, big Qy)
{ZZN12 ret;zzn2 lam, extra;ecn2 P;BOOL Doubling;Parameters::init_zzn2(lam);Parameters::init_zzn2(extra);Parameters::init_ecn2(P);ecn2_copy(A, &P);Doubling = ecn2_add2(B, A, &lam, &extra);if( A->marker == MR_EPOINT_INFINITY ){zzn4_from_int(1, &ret.a);ret.miller = FALSE;ret.unitary = TRUE;} else {ret = line(P, A, B, lam, extra, Doubling, Qx, Qy);}Parameters::release_zzn2(lam);Parameters::release_zzn2(extra);Parameters::release_ecn2(P);return ret;
}bool ZZN12::fast_pairing(ZZN12& ret, ecn2 P, big Qx, big Qy, big x, zzn2 X)
{bool result = false;int i, nb;big n, zero, negify_x;ecn2 A, KA;ZZN12 t0, x0, x1, x2, x3, x4, x5, res, tmp;Parameters::init_big(n);Parameters::init_big(zero);Parameters::init_big(negify_x);Parameters::init_ecn2(A);Parameters::init_ecn2(KA);premult(x, 6, n); incr(n, 2, n);//n=(6*x+2);if( mr_compare(x, zero) < 0 ) //x<0negify(n, n); //n=-(6*x+2);ecn2_copy(&P, &A);nb = logb2(n);zzn4_from_int(1, &res.a);res.unitary = TRUE; //res=1res.miller = TRUE; //Short Miller loopfor( i = nb - 2; i >= 0; i-- ){res = res.mul(res);tmp = g(&A, &A, Qx, Qy);res = res.mul(tmp);if( mr_testbit(n, i) ) {tmp = g(&A, &P, Qx, Qy);res = res.mul(tmp);}}// Combining ideas due to Longa, Aranha et al. and Naehrigecn2_copy(&P, &KA);q_power_frobenius(KA, X);if( mr_compare(x, zero) < 0 ){ecn2_negate(&A, &A);res = res.conj();}tmp = g(&A, &KA, Qx, Qy);res = res.mul(tmp);q_power_frobenius(KA, X);ecn2_negate(&KA, &KA);tmp = g(&A, &KA, Qx, Qy);res = res.mul(tmp);if( zzn4_iszero(&res.a) && zzn4_iszero(&res.b) && zzn4_iszero(&res.c) )goto END;// The final exponentiationres = res.conj().div(res);res.miller = FALSE; res.unitary = FALSE;res = res.powq(X).powq(X).mul(res);res.miller = FALSE; res.unitary = TRUE;// Newer new idea...// See "On the final exponentiation for calculating pairings on ordinary elliptic curves"// Michael Scott and Naomi Benger and Manuel Charlemagne and Luis J. Dominguez Perez and Ezekiel J. Kachisat0 = res.powq(X);x0 = t0.powq(X);x1 = res.mul(t0);x0 = x0.mul(x1).powq(X);x1 = res.inverse();negify(x, negify_x); x4 = res.pow(negify_x);x3 = x4.powq(X);x2 = x4.pow(negify_x);x5 = x2.inverse();t0 = x2.pow(negify_x);x2 = x2.powq(X);x4 = x4.div(x2);x2 = x2.powq(X);res = t0.powq(X);t0 = t0.mul(res);t0 = t0.mul(t0).mul(x4).mul(x5);res = x3.mul(x5).mul(t0);t0 = t0.mul(x2);res = res.mul(res).mul(t0);res = res.mul(res);t0 = res.mul(x1);res = res.mul(x0);t0 = t0.mul(t0).mul(res);ret = t0;result = true;END:Parameters::release_big(n);Parameters::release_big(zero);Parameters::release_big(negify_x);Parameters::release_ecn2(A);Parameters::release_ecn2(KA);return result;
}bool ZZN12::calcRatePairing(ZZN12& ret, ecn2 P, epoint *Q, big x, zzn2 X)
{bool result = false;big Qx, Qy;Parameters::init_big(Qx);Parameters::init_big(Qy);ecn2_norm(&P);epoint_get(Q, Qx, Qy);result = fast_pairing(ret, P, Qx, Qy, x, X);if(result) result = ret.isOrderQ();Parameters::release_big(Qx);Parameters::release_big(Qy);return result;
}

国密SM9算法C++实现之三:椭圆曲线接口、参数初始化相关推荐

  1. 国密SM9算法C++实现之一:算法简介

    SM9算法C++实现系列目录: 基于JPBC的SM9算法的java实现与测试 国密SM9算法C++实现之0:源码下载地址 国密SM9算法C++实现之一:算法简介 国密SM9算法C++实现之二:测试工具 ...

  2. 国密SM9算法C++实现之八:密钥交换算法

    SM9算法C++实现系列目录: 基于JPBC的SM9算法的java实现与测试 国密SM9算法C++实现之0:源码下载地址 国密SM9算法C++实现之一:算法简介 国密SM9算法C++实现之二:测试工具 ...

  3. 国密SM9算法C++实现之七:加密解密算法

    SM9算法C++实现系列目录: 基于JPBC的SM9算法的java实现与测试 国密SM9算法C++实现之0:源码下载地址 国密SM9算法C++实现之一:算法简介 国密SM9算法C++实现之二:测试工具 ...

  4. 国密SM9算法C++实现之九:算法功能与测试例子

    SM9算法C++实现系列目录: 基于JPBC的SM9算法的java实现与测试 国密SM9算法C++实现之0:源码下载地址 国密SM9算法C++实现之一:算法简介 国密SM9算法C++实现之二:测试工具 ...

  5. 国密SM9算法C++实现之五:签名验签算法

    SM9算法C++实现系列目录: 基于JPBC的SM9算法的java实现与测试 国密SM9算法C++实现之0:源码下载地址 国密SM9算法C++实现之一:算法简介 国密SM9算法C++实现之二:测试工具 ...

  6. 国密SM9算法C++实现之六:密钥封装解封算法

    SM9算法C++实现系列目录: 基于JPBC的SM9算法的java实现与测试 国密SM9算法C++实现之0:源码下载地址 国密SM9算法C++实现之一:算法简介 国密SM9算法C++实现之二:测试工具 ...

  7. 国密SM9算法C++实现之四:基本功能函数与KGC接口的实现

    SM9算法C++实现系列目录: 基于JPBC的SM9算法的java实现与测试 国密SM9算法C++实现之0:源码下载地址 国密SM9算法C++实现之一:算法简介 国密SM9算法C++实现之二:测试工具 ...

  8. 国密SM9算法C++实现:算法功能与测试例子

    测试例子 实现完KGC密钥生成和各个算法功能部分后,可以测试一下.  使用SM9算法时只需要包含KGC.h和SM9.h两个文件,上层数据都用std::string储存,不涉及到底层数据结构. #inc ...

  9. 基于商密SM9算法的物联网安全平台设计与应用

    物联网普遍存在遭受网络攻击类型多样化.没有安全保护标准.数据极易被截获或破解等安全风险,核心问题在于缺乏设备.服务提供者.应用.数据.交易等物的安全认证机制.因此,有必要建立一种提供认证鉴权和数据保护 ...

最新文章

  1. 计算机语言中display翻译,display的意思在线翻译,解释display中文英文含义,短语词组,音标读音,例句,词源,同义词,反义词【澳典网ODict.Net】...
  2. java线程之InheritableThreadLocal
  3. Go并发编程中的那些事[译]
  4. 深入理解.NET Core的基元(三) - 深入理解runtimeconfig.json
  5. 常用电子元器件之一:开关
  6. Gpower软件真不错
  7. 这些年,我身边的那些人和事
  8. 本地化差分隐私(Local Differential Privacy)浅析
  9. Python+FFmpeg音视频格式转换
  10. 社保管理系统服务器异常,社保费客户端登录服务器异常
  11. mybatis类型转换器处理PostGis数据库geometry类型转换
  12. CSS实现带阴影效果的三角形
  13. 主成分回归之后预测_回归分析|笔记整理(B)——主成分回归(下),偏最小二乘回归...
  14. 软件设计---过程设计
  15. cmd html 查找汉子字,cmd搜索字符串加换行 在cmd(命令提示符)中怎样换行
  16. substance painter学习1——安装
  17. Linux指令——crontab
  18. 经营资产管理和竞争力分析
  19. [.NET开发] C# 合并、拆分PDF文档
  20. Win10系统设置护眼色

热门文章

  1. Stm32F103R6之器件签名
  2. el-table 值不同颜色_Excel核对对比数据,快速找出两份数据不同之处
  3. dede标签:定义文件夹
  4. 2003邮件服务器维护,Windows 2003邮件服务器配置指南
  5. 北京橄榄山软件网站与大家见面, 可以更多了解橄榄山和其二次开发产品
  6. 查找算法(顺序查找、二分法查找、二叉树查找、hash查找)
  7. python十进制转八进制_Python程序将十进制转换为二进制,八进制和十六进制
  8. 百万年薪的PMO项目经理是如何做好沟通管理和情绪管理的?
  9. 2023年中级计算机软考怎么报考呢?软考证书有用吗?
  10. android sqlite 自定义路径,SQLite数据库创建时自定义路径