注:本文不讨论算法具体实现细节,只介绍如何编译一个现有的程序实现。

在商用密码检测中心( 链接:http://www.scctc.org.cn/index.aspx )的网站上,“下载中心” -> “算法源代码”网页( 链接:http://www.scctc.org.cn/templates/Download/index.aspx?nodeid=71 )上发布了国密 SM9 算法的 C 程序源代码。该程序是基于开源的 MIRACL 密码库( 在 github 网站上的链接: https://github.com/miracl/MIRACL )实现的,MIRACL 是一款商业软件,在商业应用中使用它必须先获取许可证。国密 SM9 程序的免责声明链接是:http://www.scctc.org.cn/Upload/accessory/20175/201755105494041082.pdf 。
        通过下载链接 http://www.scctc.org.cn/Upload/accessory/20175/201755103016253196.rar 可以下载到 SM9 算法源码,解压压缩文件后,发现源码放在 PDF 格式文件中,放在四个目录下,分别包含签名验签、封装、密钥协商、加解密这四部分。在本文中,只对签名及验签部分感兴趣,于是手动将相关的那一部分代码复制到一些文本文件格式的源程序中,抽取出这些源码后,尝试在 Windows 下编译,结果遇到了很多问题。对这些问题的简单描述及解决思路介绍如下:
1)从 PDF 文件中粘贴文字到文本文件时,部分代码格式会在复制过程中出错,需要手动修改调整;
2)会遇到不能找到某些宏定义、函数声明、函数实现的错误。原因是这些代码段并未包含在 SM9 签名验签相关的 PDF 文件中,但是在同一网站上发布的 SM2 或 SM3 算法源代码中,或是在 SM9 代码的封装子目录中 PDF 文件里可以找到有关的代码段,需要手工复制粘贴提取出来;
3)对函数的声明和实现写在同一个文件里,有时导致编译器查找不到某些函数,从而报错。为了便于阅读和分析,最好手工将它们分离一下,把函数声明放到对应的头文件中,把函数的实现放到对应的 c 程序文件中;
4)缺少 main( ) 主函数,需要自己手写一个。
        经过对 SM9 签名及验签部分代码的整理,并在 Visual Studio Code 中使用 Alt + Shift + f 组合键对代码进行格式化后,得到了以下 4 个头文件:
KDF.h, R-ate.h, zzn12_operatoin.h, SM9_sv.h
还得到了以下 5 个 c 程序文件:
KDF.c, R-ate.c, zzn12_operation.c, SM9_sv.c, test.c

以上文件的内容如下:
KDF.h

/************************************************************
Note:Codes here were downloaded from:http://www.scctc.org.cn/templates/Download/index.aspx?nodeid=71.The disclaimer was published on the link:http://www.scctc.org.cn/Upload/accessory/20175/201755105494041082.pdf . The codes were slightly modified to pass the check of C complier.
*************************************************************//************************************************************************FileName:KDF.hVersion:KDF_V1.1Date:Sep 24,2016Description:This headfile provides KDF function needed in SM2 algorithmFunction List:1.SM3_256        //calls SM3_init, SM3_process and SM3_done to calculate hash value2.SM3_init       //init the SM3 state3.SM3_process    //compress the the first len/64 blocks of the message4.SM3_done       //compress the rest message and output the hash value5.SM3_compress   //called by SM3_process and SM3_done, compress a single block of message6.BiToW          //called by SM3_compress,to calculate W from Bi7.WToW1          //called by SM3_compress, calculate W' from W8.CF             //called by SM3_compress, to calculate CF function.9.BigEndian      //called by SM3_compress and SM3_done.GM/T 0004-2012 requires to use
big-endian.//if CPU uses little-endian, BigEndian function is a necessary call to
change the//little-endian format into big-endian format.10.SM3_KDF       //calls SM3_init, SM3_process and SM3_done to generate key streamHistory:1. Date:   Sep 18,2016Modification: Adding notes to all the functions
************************************************************************/#ifndef HEADER_KDF_H
#define HEADER_KDF_H#include <string.h>#define SM2_WORDSIZE 8
#define SM2_NUMBITS 256
#define SM2_NUMWORD (SM2_NUMBITS / SM2_WORDSIZE) //32#define SM3_len 256
#define SM3_T1 0x79CC4519
#define SM3_T2 0x7A879D8A
#define SM3_IVA 0x7380166f
#define SM3_IVB 0x4914b2b9
#define SM3_IVC 0x172442d7
#define SM3_IVD 0xda8a0600
#define SM3_IVE 0xa96f30bc
#define SM3_IVF 0x163138aa
#define SM3_IVG 0xe38dee4d
#define SM3_IVH 0xb0fb0e4e/* Various logical functions */
#define SM3_p1(x) (x ^ SM3_rotl32(x, 15) ^ SM3_rotl32(x, 23))
#define SM3_p0(x) (x ^ SM3_rotl32(x, 9) ^ SM3_rotl32(x, 17))
#define SM3_ff0(a, b, c) (a ^ b ^ c)
#define SM3_ff1(a, b, c) ((a & b) | (a & c) | (b & c))
#define SM3_gg0(e, f, g) (e ^ f ^ g)
#define SM3_gg1(e, f, g) ((e & f) | ((~e) & g))
#define SM3_rotl32(x, n) (((x) << n) | ((x) >> (32 - n)))
#define SM3_rotr32(x, n) (((x) >> n) | ((x) << (32 - n)))typedef struct
{unsigned long state[8];unsigned long length;unsigned long curlen;unsigned char buf[64];
} SM3_STATE;void CF(unsigned long Wj[], unsigned long Wj1[], unsigned long V[]);
void BigEndian(unsigned char src[], unsigned int bytelen, unsigned char des[]);
void SM3_init(SM3_STATE *md);
void SM3_compress(SM3_STATE *md);
void SM3_process(SM3_STATE *md, unsigned char *buf, int len);
void SM3_done(SM3_STATE *md, unsigned char hash[]);
void SM3_256(unsigned char buf[], int len, unsigned char hash[]);
void SM3_KDF(unsigned char Z[], unsigned short zlen, unsigned short klen, unsigned char K[]);#endif

KDF.c

/************************************************************
Note:Codes here were downloaded from:http://www.scctc.org.cn/templates/Download/index.aspx?nodeid=71.The disclaimer was published on the link:http://www.scctc.org.cn/Upload/accessory/20175/201755105494041082.pdf . The codes were slightly modified to pass the check of C complier.
*************************************************************/#include <string.h>
#include "KDF.h"/****************************************************************Function:       BiToWDescription:    calculate W from BiCalls:Called By:      SM3_compressInput:          Bi[16]    //a block of a messageOutput:         W[68]Return:         nullOthers:
****************************************************************/
void BiToW(unsigned long Bi[], unsigned long W[])
{int i;unsigned long tmp;for (i = 0; i <= 15; i++){W[i] = Bi[i];}for (i = 16; i <= 67; i++){tmp = W[i - 16] ^ W[i - 9] ^ SM3_rotl32(W[i - 3], 15);W[i] = SM3_p1(tmp) ^ (SM3_rotl32(W[i - 13], 7)) ^ W[i - 6];}
}/*****************************************************************Function:       WToW1Description:    calculate W1 from WCalls:Called By:      SM3_compressInput:          W[68]Output:         W1[64]Return:         nullOthers:
*****************************************************************/
void WToW1(unsigned long W[], unsigned long W1[])
{int i;for (i = 0; i <= 63; i++){W1[i] = W[i] ^ W[i + 4];}
}/******************************************************************Function:       CFDescription:    calculate the CF compress function and update VCalls:Called By:      SM3_compressInput:          W[68]W1[64]V[8]Output:         V[8]Return:         nullOthers:
********************************************************************/
void CF(unsigned long W[], unsigned long W1[], unsigned long V[])
{unsigned long SS1;unsigned long SS2;unsigned long TT1;unsigned long TT2;unsigned long A, B, C, D, E, F, G, H;unsigned long T = SM3_T1;unsigned long FF;unsigned long GG;int j;//reg init,set ABCDEFGH=V0A = V[0];B = V[1];C = V[2];D = V[3];E = V[4];F = V[5];G = V[6];H = V[7];for (j = 0; j <= 63; j++){//SS1if (j == 0){T = SM3_T1;}else if (j == 16){T = SM3_rotl32(SM3_T2, 16);}else{T = SM3_rotl32(T, 1);}SS1 = SM3_rotl32((SM3_rotl32(A, 12) + E + T), 7);//SS2SS2 = SS1 ^ SM3_rotl32(A, 12);//TT1if (j <= 15){FF = SM3_ff0(A, B, C);}else{FF = SM3_ff1(A, B, C);}TT1 = FF + D + SS2 + *W1;W1++;//TT2if (j <= 15){GG = SM3_gg0(E, F, G);}else{GG = SM3_gg1(E, F, G);}TT2 = GG + H + SS1 + *W;W++;//DD = C;//CC = SM3_rotl32(B, 9);//BB = A;//AA = TT1;//HH = G;//GG = SM3_rotl32(F, 19);//FF = E;//EE = SM3_p0(TT2);}//update VV[0] = A ^ V[0];V[1] = B ^ V[1];V[2] = C ^ V[2];V[3] = D ^ V[3];V[4] = E ^ V[4];V[5] = F ^ V[5];V[6] = G ^ V[6];V[7] = H ^ V[7];
}/******************************************************************************Function:       BigEndianDescription:    unsigned int endian converse.GM/T 0004-2012 requires to use big-endian.if CPU uses little-endian, BigEndian function is a necessarycall to change the little-endian format into big-endian format.Calls:Called By:      SM3_compress, SM3_doneInput:          src[bytelen]bytelenOutput:         des[bytelen]Return:         nullOthers:         src and des could implies the same address
*******************************************************************************/
void BigEndian(unsigned char src[], unsigned int bytelen, unsigned char des[])
{unsigned char tmp = 0;unsigned long i = 0;for (i = 0; i < bytelen / 4; i++){tmp = des[4 * i];des[4 * i] = src[4 * i + 3];src[4 * i + 3] = tmp;tmp = des[4 * i + 1];des[4 * i + 1] = src[4 * i + 2];des[4 * i + 2] = tmp;}
}/******************************************************************************Function:       SM3_initDescription:    initiate SM3 stateCalls:Called By:      SM3_256Input:          SM3_STATE *mdOutput:         SM3_STATE *mdReturn:         nullOthers:
*******************************************************************************/
void SM3_init(SM3_STATE *md)
{md->curlen = md->length = 0;md->state[0] = SM3_IVA;md->state[1] = SM3_IVB;md->state[2] = SM3_IVC;md->state[3] = SM3_IVD;md->state[4] = SM3_IVE;md->state[5] = SM3_IVF;md->state[6] = SM3_IVG;md->state[7] = SM3_IVH;
}/******************************************************************************Function:       SM3_compressDescription:    compress a single block of messageCalls:          BigEndianBiToWWToW1CFCalled By:      SM3_256Input:          SM3_STATE *mdOutput:         SM3_STATE *mdReturn:         nullOthers:
*******************************************************************************/
void SM3_compress(SM3_STATE *md)
{unsigned long W[68];unsigned long W1[64];//if CPU uses little-endian, BigEndian function is a necessary callBigEndian(md->buf, 64, md->buf);BiToW((unsigned long *)md->buf, W);WToW1(W, W1);CF(W, W1, md->state);
}/******************************************************************************Function:       SM3_processDescription:    compress the first (len/64) blocks of messageCalls:          SM3_compressCalled By:      SM3_256Input:          SM3_STATE *mdunsigned char buf[len]  //the input messageint len                 //bytelen of messageOutput:         SM3_STATE *mdReturn:         nullOthers:
*******************************************************************************/
void SM3_process(SM3_STATE *md, unsigned char *buf, int len)
{while (len--){/* copy byte */md->buf[md->curlen] = *buf++;md->curlen++;/* is 64 bytes full? */if (md->curlen == 64){SM3_compress(md);md->length += 512;md->curlen = 0;}}
}/******************************************************************************Function:       SM3_doneDescription:    compress the rest message that the SM3_process has left behindCalls:          SM3_compressCalled By:      SM3_256Input:          SM3_STATE *mdOutput:         unsigned char *hashReturn:         nullOthers:
*******************************************************************************/
void SM3_done(SM3_STATE *md, unsigned char hash[])
{int i;unsigned char tmp = 0;/* increase the bit length of the message */md->length += md->curlen << 3;/* append the '1' bit */md->buf[md->curlen] = 0x80;md->curlen++;/* if the length is currently above 56 bytes, appends zeros tillit reaches 64 bytes, compress the current block, creat a newblock by appending zeros and length,and then compress it*/if (md->curlen > 56){for (; md->curlen < 64;){md->buf[md->curlen] = 0;md->curlen++;}SM3_compress(md);md->curlen = 0;}/* if the length is less than 56 bytes, pad upto 56 bytes of zeroes */for (; md->curlen < 56;){md->buf[md->curlen] = 0;md->curlen++;}/* since all messages are under 2^32 bits we mark the top bits zero */for (i = 56; i < 60; i++){md->buf[i] = 0;}/* append length */md->buf[63] = md->length & 0xff;md->buf[62] = (md->length >> 8) & 0xff;md->buf[61] = (md->length >> 16) & 0xff;md->buf[60] = (md->length >> 24) & 0xff;SM3_compress(md);/* copy output */memcpy(hash, md->state, SM3_len / 8);BigEndian(hash, SM3_len / 8, hash); //if CPU uses little-endian, BigEndian function is a necessary call
}/******************************************************************************Function:       SM3_256Description:    calculate a hash value from a given messageCalls:          SM3_initSM3_processSM3_doneCalled By:Input:          unsigned char buf[len]  //the input messageint len                 //bytelen of the messageOutput:         unsigned char hash[32]Return:         nullOthers:
*******************************************************************************/
void SM3_256(unsigned char buf[], int len, unsigned char hash[])
{SM3_STATE md;SM3_init(&md);SM3_process(&md, buf, len);SM3_done(&md, hash);
}/******************************************************************************Function:       SM3_KDFDescription:    key derivation functionCalls:          SM3_initSM3_processSM3_doneCalled By:Input:          unsigned char Z[zlen]unsigned short zlen          //bytelen of Zunsigned short klen          //bytelen of KOutput:         unsigned char K[klen]        //shared secret keyReturn:         nullOthers:
*******************************************************************************/
void SM3_KDF(unsigned char Z[], unsigned short zlen, unsigned short klen, unsigned char K[])
{unsigned short i, j, t;unsigned int bitklen;SM3_STATE md;unsigned char Ha[SM2_NUMWORD];unsigned char ct[4] = {0, 0, 0, 1};bitklen = klen * 8;if (bitklen % SM2_NUMBITS)t = bitklen / SM2_NUMBITS + 1;elset = bitklen / SM2_NUMBITS;//s4:   K=Ha1||Ha2||...for (i = 1; i < t; i++){//s2:   Hai=Hv(Z||ct)SM3_init(&md);SM3_process(&md, Z, zlen);SM3_process(&md, ct, 4);SM3_done(&md, Ha);memcpy((K + SM2_NUMWORD * (i - 1)), Ha, SM2_NUMWORD);if (ct[3] == 0xff){ct[3] = 0;if (ct[2] == 0xff){ct[2] = 0;if (ct[1] == 0xff){ct[1] = 0;ct[0]++;}elsect[1]++;}elsect[2]++;}elsect[3]++;}//s3:  klen/v�������Ĵ���SM3_init(&md);SM3_process(&md, Z, zlen);SM3_process(&md, ct, 4);SM3_done(&md, Ha);if (bitklen % SM2_NUMBITS){i = (SM2_NUMBITS - bitklen + SM2_NUMBITS * (bitklen / SM2_NUMBITS)) / 8;j = (bitklen - SM2_NUMBITS * (bitklen / SM2_NUMBITS)) / 8;memcpy((K + SM2_NUMWORD * (t - 1)), Ha, j);}else{memcpy((K + SM2_NUMWORD * (t - 1)), Ha, SM2_NUMWORD);}
}

R-ate.h

/************************************************************
Note:Codes here were downloaded from:http://www.scctc.org.cn/templates/Download/index.aspx?nodeid=71.The disclaimer was published on the link:http://www.scctc.org.cn/Upload/accessory/20175/201755105494041082.pdf . The codes were slightly modified to pass the check of C complier.
*************************************************************//************************************************************************File name:    R-ate.hVersion:Date:         Dec 15,2016Description:  this code is achieved according to ake12bnx.cpp in MIRCAL C++ source file.see ake12bnx.cpp for details.this code gives calculation of R-ate pairingFunction List:1.zzn2_pow                //regular zzn2 powering2.set_frobenius_constant  //calculate frobenius_constant X3.q_power_frobenius4.line5.g6.fast_pairing7.ecapNotes:
**************************************************************************/#ifndef HEADER_R_ATE_H
#define HEADER_R_ATE_H#include "miracl.h"
#include "zzn12_operation.h"void q_power_frobenius(ecn2 A, zzn2 F);
zzn2 zzn2_pow(zzn2 x, big k);
BOOL fast_pairing(ecn2 P, big Qx, big Qy, big x, zzn2 X, zzn12 *r);
zzn12 line(ecn2 A, ecn2 *C, ecn2 *B, zzn2 slope, zzn2 extra, BOOL Doubling, big Qx, big Qy);
zzn12 g(ecn2 *A, ecn2 *B, big Qx, big Qy);
void set_frobenius_constant(zzn2 *X);
BOOL ecap(ecn2 P, epoint *Q, big x, zzn2 X, zzn12 *r);
BOOL member(zzn12 r, big x, zzn2 F);#endif

R-ate.c

/************************************************************
Note:Codes here were downloaded from:http://www.scctc.org.cn/templates/Download/index.aspx?nodeid=71.The disclaimer was published on the link:http://www.scctc.org.cn/Upload/accessory/20175/201755105494041082.pdf . The codes were slightly modified to pass the check of C complier.
*************************************************************/#include "zzn12_operation.h"
#include "miracl.h"
#include "R-ate.h"miracl *mip;/****************************************************************Function:       q_power_frobeniusDescription:    F is frobenius_constant Xsee ake12bnx.cpp for details in MIRACL c++ source fileCalls:          MIRACL functionsCalled By:      fast_pairingInput:          ecn2 A,zzn2 FOutput:         zzn2 AReturn:         NULLOthers:
****************************************************************/
void 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;x.a = mirvar(0);x.b = mirvar(0);y.a = mirvar(0);y.b = mirvar(0);z.a = mirvar(0);z.b = mirvar(0);w.a = mirvar(0);w.b = mirvar(0);r.a = mirvar(0);r.b = mirvar(0);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);
}/****************************************************************Function:       zzn2_powDescription:    regular zzn2 poweringsee zzn2.cpp for details in MIRACL c++ source fileCalls:          MIRACL functionsCalled By:      set_frobenius_constantInput:          zzn2 x,big kOutput:         nullReturn:         zzn2Others:
****************************************************************/
zzn2 zzn2_pow(zzn2 x, big k)
{int i, j, nb, n, nbw, nzs;big zero;zzn2 res, u2, t[16];zero = mirvar(0);res.a = mirvar(0);res.b = mirvar(0);u2.a = mirvar(0);u2.b = mirvar(0);if (zzn2_iszero(&x)){zzn2_zero(&res);return res;}if (size(k) == 0){zzn2_from_int(1, &res);return res;}if (size(k) == 1)return x;// Prepare table for windowingzzn2_mul(&x, &x, &u2);t[0].a = mirvar(0);t[0].b = mirvar(0);zzn2_copy(&x, &t[0]);for (i = 1; i < 16; i++){t[i].a = mirvar(0);t[i].b = mirvar(0);zzn2_mul(&t[i - 1], &u2, &t[i]);}// Left to right method - with windowszzn2_copy(&x, &res);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(&res, &res, &res);if (n > 0)zzn2_mul(&res, &t[n / 2], &res);i -= nbw;if (nzs){for (j = 0; j < nzs; j++)zzn2_mul(&res, &res, &res);i -= nzs;}}return res;
}/****************************************************************Function:       fast_pairingDescription:    R-ate Pairing G2 x G1 -> GTP is a point of order q in G1. Q(x,y) is a point of order q in G2.Note that P is a point on the sextic twist of the curve over Fp^2,Q(x,y) is a point on the curve over the base field Fpsee ake12bnx.cpp for details in MIRACL c++ source fileCalls:          MIRACL functions,zzn12_init,g,q_power_frobeniuszzn12_copy,zzn12_conj,zzn12_div,zzn12_powq,zzn12_inverseCalled By:      ecapInput:          ecn2 P,big Qx,big Qy,big x,zzn2 XOutput:         zzn12 *rReturn:         FALSE: r=0TRUE: correct calculationOthers:
****************************************************************/
BOOL fast_pairing(ecn2 P, big Qx, big Qy, big x, zzn2 X, zzn12 *r)
{int i, nb;big n, zero, negify_x;ecn2 A, KA;zzn12 t0, x0, x1, x2, x3, x4, x5, res;zero = mirvar(0);n = mirvar(0);negify_x = mirvar(0);A.x.a = mirvar(0);A.x.b = mirvar(0);A.y.a = mirvar(0);A.y.b = mirvar(0);A.z.a = mirvar(0);A.z.b = mirvar(0);A.marker = MR_EPOINT_INFINITY;KA.x.a = mirvar(0);KA.x.b = mirvar(0);KA.y.a = mirvar(0);KA.y.b = mirvar(0);KA.z.a = mirvar(0);KA.z.b = mirvar(0);KA.marker = MR_EPOINT_INFINITY;zzn12_init(&t0);zzn12_init(&x0);zzn12_init(&x1);zzn12_init(&x2);zzn12_init(&x3);zzn12_init(&x4);zzn12_init(&x5);zzn12_init(&res);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=1// Short Miller loopres.miller = TRUE;for (i = nb - 2; i >= 0; i--){zzn12_mul(res, res, &res);zzn12_mul(res, g(&A, &A, Qx, Qy), &res);if (mr_testbit(n, i))zzn12_mul(res, g(&A, &P, Qx, Qy), &res);}// 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);zzn12_conj(&res, &res);}zzn12_mul(res, g(&A, &KA, Qx, Qy), &res);q_power_frobenius(KA, X);ecn2_negate(&KA, &KA);zzn12_mul(res, g(&A, &KA, Qx, Qy), &res);if (zzn4_iszero(&res.a) && zzn4_iszero(&res.b) && zzn4_iszero(&res.c))return FALSE;// The final exponentiationzzn12_copy(&res, &t0); //t0=r;zzn12_conj(&res, &res);zzn12_div(res, t0, &res);res.miller = FALSE;res.unitary = FALSE;zzn12_copy(&res, &t0); //t0=r;zzn12_powq(X, &res);zzn12_powq(X, &res);zzn12_mul(res, t0, &res); // r^[(p^6-1)*(p^2+1)]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. Kachisazzn12_copy(&res, &t0);zzn12_powq(X, &t0);zzn12_copy(&t0, &x0);zzn12_powq(X, &x0); //x0=t0zzn12_mul(res, t0, &x1);zzn12_mul(x0, x1, &x0); // x0*=(res*t0);zzn12_powq(X, &x0);x1 = zzn12_inverse(res); // just a conjugation!negify(x, negify_x);x4 = zzn12_pow(res, negify_x); //negify_x=-x   x is sparse.zzn12_copy(&x4, &x3);zzn12_powq(X, &x3);x2 = zzn12_pow(x4, negify_x);x5 = zzn12_inverse(x2);t0 = zzn12_pow(x2, negify_x);zzn12_powq(X, &x2);zzn12_div(x4, x2, &x4);zzn12_powq(X, &x2);zzn12_copy(&t0, &res); // res=t0zzn12_powq(X, &res);zzn12_mul(t0, res, &t0);zzn12_mul(t0, t0, &t0);zzn12_mul(t0, x4, &t0);zzn12_mul(t0, x5, &t0); //t0*=t0;t0*=x4;t0*=x5;zzn12_mul(x3, x5, &res);zzn12_mul(res, t0, &res); //res=x3*x5;res*=t0;zzn12_mul(t0, x2, &t0);   //t0*=x2;zzn12_mul(res, res, &res);zzn12_mul(res, t0, &res);zzn12_mul(res, res, &res); //res*=res; res*=t0;res*=res;zzn12_mul(res, x1, &t0);   //  t0=res*x1;zzn12_mul(res, x0, &res);  //res*=x0;zzn12_mul(t0, t0, &t0);zzn12_mul(t0, res, &t0); //t0*=t0;t0*=res;zzn12_copy(&t0, r); //r= t0;return TRUE;
}/****************************************************************Function:       lineDescription:    Line from A to destination C. Let A=(x,y)Line Y-slope.X-c=0, through A, so intercept c=y-slope.xLine Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0Now evaluate at Q -> return (Qy-y)-slope.(Qx-x)see ake12bnx.cpp for details in MIRACL c++ source fileCalls:          MIRACL functions,zzn12_initCalled By:      gInput:          ecn2 A,ecn2 *C,ecn2 *B,zzn2 slope,zzn2 extra,BOOL Doubling,big Qx,big QyOutput:Return:         zzn12Others:
****************************************************************/
zzn12 line(ecn2 A, ecn2 *C, ecn2 *B, zzn2 slope, zzn2 extra, BOOL Doubling, big Qx, big Qy)
{zzn12 res;zzn2 X, Y, Z, Z2, U, QY, CZ;big QX;QX = mirvar(0);X.a = mirvar(0);X.b = mirvar(0);Y.a = mirvar(0);Y.b = mirvar(0);Z.a = mirvar(0);Z.b = mirvar(0);Z2.a = mirvar(0);Z2.b = mirvar(0);U.a = mirvar(0);U.b = mirvar(0);QY.a = mirvar(0);QY.b = mirvar(0);CZ.a = mirvar(0);CZ.b = mirvar(0);zzn12_init(&res);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, &res.a);zzn2_copy(&Y, &(res.c.b));}if (get_mip()->TWIST == MR_SEXTIC_D){zzn2_smul(&U, Qy, &QY);zzn4_from_zzn2s(&QY, &X, &res.a);zzn2_copy(&Y, &(res.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, &res.a);zzn2_copy(&Z, &(res.c.b));}if (get_mip()->TWIST == MR_SEXTIC_D){zzn2_smul(&CZ, Qy, &QY);zzn4_from_zzn2s(&QY, &X, &res.a);zzn2_copy(&Z, &(res.b.b));}}return res;
}/****************************************************************Function:       gDescription:    Add A=A+B  (or A=A+A),Return line function valuesee ake12bnx.cpp for details in MIRACL c++ source fileCalls:          MIRACL functions,zzn12_init,lineCalled By:Input:          ecn2 *A,ecn2 *B,big Qx,big QyOutput:Return:         zzn12Others:
****************************************************************/
zzn12 g(ecn2 *A, ecn2 *B, big Qx, big Qy)
{zzn2 lam, extra;BOOL Doubling;ecn2 P;zzn12 res;lam.a = mirvar(0);lam.b = mirvar(0);extra.a = mirvar(0);extra.b = mirvar(0);P.x.a = mirvar(0);P.x.b = mirvar(0);P.y.a = mirvar(0);P.y.b = mirvar(0);P.z.a = mirvar(0);P.z.b = mirvar(0);P.marker = MR_EPOINT_INFINITY;zzn12_init(&res);ecn2_copy(A, &P);Doubling = ecn2_add2(B, A, &lam, &extra);if (A->marker == MR_EPOINT_INFINITY){zzn4_from_int(1, &res.a);res.miller = FALSE;res.unitary = TRUE;}elseres = line(P, A, B, lam, extra, Doubling, Qx, Qy);return res;
}/****************************************************************Function:       set_frobenius_constantDescription:    calculate frobenius_constant Xsee ake12bnx.cpp for details in MIRACL c++ source fileCalls:          MIRACL functions,zzn2_powCalled By:      SM9_initInput:          NULLOutput:         zzn2 *XReturn:         NULLOthers:
****************************************************************/
void set_frobenius_constant(zzn2 *X)
{big p, zero, one, two;p = mirvar(0);zero = mirvar(0);one = mirvar(0);two = mirvar(0);convert(0, zero);convert(1, one);convert(2, two);mip = get_mip();copy(mip->modulus, p);switch (get_mip()->pmod8){case 5:zzn2_from_bigs(zero, one, X); // = (sqrt(-2)^(p-1)/2break;case 3:zzn2_from_bigs(one, one, X); // = (1+sqrt(-1))^(p-1)/2break;case 7:zzn2_from_bigs(two, one, X); // = (2+sqrt(-1))^(p-1)/2default:break;}decr(p, 1, p);subdiv(p, 6, p);*X = zzn2_pow(*X, p);
}/****************************************************************Function:       ecapDescription:    caculate Rate pairingsee ake12bnx.cpp for details in MIRACL c++ source fileCalls:          MIRACL functions,fast_pairingCalled By:      SM9_Sign,SM9_VerifyInput:          ecn2 P,epoint *Q,big x,zzn2 XOutput:         zzn12 *rReturn:         FALSE: calculation errorTRUE: correct calculationOthers:
****************************************************************/
BOOL ecap(ecn2 P, epoint *Q, big x, zzn2 X, zzn12 *r)
{BOOL Ok;big Qx, Qy;Qx = mirvar(0);Qy = mirvar(0);ecn2_norm(&P);epoint_get(Q, Qx, Qy);Ok = fast_pairing(P, Qx, Qy, x, X, r);if (Ok)return TRUE;return FALSE;
}/****************************************************************Function:       memberDescription:    ctest if a zzn12 element is of order qtest r^q = r^(p+1-t) =1, so test r^p=r^(t-1)see ake12bnx.cpp for details in MIRACL c++ source fileCalls:          MIRACL functions,zzn12_init,zzn12_copy,zzn12_powqCalled By:      SM9_Sign,SM9_VerifyInput:          zzn12 r,big x,zzn2 FOutput:         NULLReturn:         FALSE: zzn12 element is not of order qTRUE: zzn12 element is of order qOthers:
****************************************************************/
BOOL member(zzn12 r, big x, zzn2 F)
{zzn12 w;big six;six = mirvar(0);zzn12_init(&w);convert(6, six);zzn12_copy(&r, &w); //w=rzzn12_powq(F, &w);r = zzn12_pow(r, x);r = zzn12_pow(r, x);r = zzn12_pow(r, six); // t-1=6x^2if (zzn4_compare(&w.a, &r.a) && zzn4_compare(&w.a, &r.a) && zzn4_compare(&w.a, &r.a))return TRUE;return FALSE;
}

zzn12_operatoin.h

/************************************************************
Note:Codes here were downloaded from:http://www.scctc.org.cn/templates/Download/index.aspx?nodeid=71.The disclaimer was published on the link:http://www.scctc.org.cn/Upload/accessory/20175/201755105494041082.pdf .The codes were slightly modified to pass the check of C complier.
*************************************************************//************************************************************************File name:    zzn12_operation.hVersion:Date:         Dec 15,2016Description:  this code is achieved according to zzn12a.h and zzn12a.cpp in MIRCAL C++ source
file writen by M. Scott.so,see zzn12a.h and zzn12a.cpp for details.this code define one struct zzn12,and based on it give many fuctions.Function List:1.zzn12_init           //Initiate struct zzn122.zzn12_copy           //copy one zzn12 to another3.zzn12_mul            //z=x*y,achieve multiplication with two zzn124.zzn12_conj           //achieve conjugate complex5.zzn12_inverse        //element inversion6.zzn12_powq           //7.zzn12_div            //division operation8.zzn12_pow            //regular zzn12 poweringNotes:
**************************************************************************/#ifndef HEADER_ZZN12_OPERATION_H
#define HEADER_ZZN12_OPERATION_H#include "miracl.h"typedef struct
{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).
} zzn12;void zzn12_init(zzn12 *x);
void zzn12_copy(zzn12 *x, zzn12 *y);
zzn12_mul(zzn12 x, zzn12 y, zzn12 *z);
void zzn12_conj(zzn12 *x, zzn12 *y);
zzn12 zzn12_inverse(zzn12 w);
void zzn12_powq(zzn2 F, zzn12 *y);
void zzn12_div(zzn12 x, zzn12 y, zzn12 *z);
zzn12 zzn12_pow(zzn12 x, big k);#endif

zzn12_operation.c

/************************************************************
Note:Codes here were downloaded from:http://www.scctc.org.cn/templates/Download/index.aspx?nodeid=71.The disclaimer was published on the link:http://www.scctc.org.cn/Upload/accessory/20175/201755105494041082.pdf .The codes were slightly modified to pass the check of C complier.
*************************************************************/#include "zzn12_operation.h"zzn2 X; //Frobniues constant/****************************************************************Function:       zzn12_initDescription:    Initiate struct zzn12Calls:          MIRACL functionsCalled By:Input:          zzn12 *xOutput:         nullReturn:         nullOthers:
****************************************************************/
void zzn12_init(zzn12 *x)
{x->a.a.a = mirvar(0);x->a.a.b = mirvar(0);x->a.b.a = mirvar(0);x->a.b.b = mirvar(0);x->a.unitary = FALSE;x->b.a.a = mirvar(0);x->b.a.b = mirvar(0);x->b.b.a = mirvar(0);x->b.b.b = mirvar(0);x->b.unitary = FALSE;x->c.a.a = mirvar(0);x->c.a.b = mirvar(0);x->c.b.a = mirvar(0);x->c.b.b = mirvar(0);x->c.unitary = FALSE;x->miller = FALSE;x->unitary = FALSE;
}/****************************************************************Function:       zzn12_copyDescription:    copy y=xCalls:          MIRACL functionsCalled By:Input:          zzn12 *xOutput:         zzn12 *yReturn:         nullOthers:
****************************************************************/
void zzn12_copy(zzn12 *x, zzn12 *y)
{zzn4_copy(&x->a, &y->a);zzn4_copy(&x->b, &y->b);zzn4_copy(&x->c, &y->c);y->miller = x->miller;y->unitary = x->unitary;
}/****************************************************************Function:       zzn12_mulDescription:    z=x*y,see zzn12a.h and zzn12a.cpp for details in MIRACL c++ source fileCalls:          MIRACL functionsCalled By:Input:          zzn12 x,yOutput:         zzn12 *zReturn:         nullOthers:
****************************************************************/
zzn12_mul(zzn12 x, zzn12 y, zzn12 *z)
{// Karatsubazzn4 Z0, Z1, Z2, Z3, T0, T1;BOOL zero_c, zero_b;Z0.a.a = mirvar(0);Z0.a.b = mirvar(0);Z0.b.a = mirvar(0);Z0.b.b = mirvar(0);Z0.unitary = FALSE;Z1.a.a = mirvar(0);Z1.a.b = mirvar(0);Z1.b.a = mirvar(0);Z1.b.b = mirvar(0);Z1.unitary = FALSE;Z2.a.a = mirvar(0);Z2.a.b = mirvar(0);Z2.b.a = mirvar(0);Z2.b.b = mirvar(0);Z2.unitary = FALSE;Z3.a.a = mirvar(0);Z3.a.b = mirvar(0);Z3.b.a = mirvar(0);Z3.b.b = mirvar(0);Z3.unitary = FALSE;T0.a.a = mirvar(0);T0.a.b = mirvar(0);T0.b.a = mirvar(0);T0.b.b = mirvar(0);T0.unitary = FALSE;T1.a.a = mirvar(0);T1.a.b = mirvar(0);T1.b.a = mirvar(0);T1.b.b = mirvar(0);T1.unitary = FALSE;zzn12_copy(&x, z);if (zzn4_compare(&x.a, &y.a) && zzn4_compare(&x.a, &y.a) && zzn4_compare(&x.a, &y.a)){if (x.unitary == TRUE){zzn4_copy(&x.a, &Z0);zzn4_mul(&x.a, &x.a, &z->a);zzn4_copy(&z->a, &Z3);zzn4_add(&z->a, &z->a, &z->a);zzn4_add(&z->a, &Z3, &z->a);zzn4_conj(&Z0, &Z0);zzn4_add(&Z0, &Z0, &Z0);zzn4_sub(&z->a, &Z0, &z->a);zzn4_copy(&x.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(&x.b, &Z2);zzn4_mul(&Z2, &Z2, &Z2);zzn4_copy(&Z2, &Z3);zzn4_add(&Z2, &Z2, &Z2);zzn4_add(&Z2, &Z3, &Z2);zzn4_conj(&x.b, &z->b);zzn4_add(&z->b, &z->b, &z->b);zzn4_conj(&x.c, &z->c);zzn4_add(&z->c, &z->c, &z->c);zzn4_negate(&z->c, &z->c);zzn4_add(&z->b, &Z1, &z->b);zzn4_add(&z->c, &Z2, &z->c);}else{if (!x.miller){ // Chung-Hasan SQR2zzn4_copy(&x.a, &Z0);zzn4_mul(&Z0, &Z0, &Z0);zzn4_mul(&x.b, &x.c, &Z1);zzn4_add(&Z1, &Z1, &Z1);zzn4_copy(&x.c, &Z2);zzn4_mul(&Z2, &Z2, &Z2);zzn4_mul(&x.a, &x.b, &Z3);zzn4_add(&Z3, &Z3, &Z3);zzn4_add(&x.a, &x.b, &z->c);zzn4_add(&z->c, &x.c, &z->c);zzn4_mul(&z->c, &z->c, &z->c);zzn4_tx(&Z1);zzn4_add(&Z0, &Z1, &z->a);zzn4_tx(&Z2);zzn4_add(&Z3, &Z2, &z->b);zzn4_add(&Z0, &Z1, &T0);zzn4_add(&T0, &Z2, &T0);zzn4_add(&T0, &Z3, &T0);zzn4_sub(&z->c, &T0, &z->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(&x.a, &Z0);zzn4_mul(&Z0, &Z0, &Z0); // a0^2    = S0zzn4_copy(&x.c, &Z2);zzn4_mul(&Z2, &x.b, &Z2);zzn4_add(&Z2, &Z2, &Z2); // 2a1.a2  = S3zzn4_copy(&x.c, &Z3);zzn4_mul(&Z3, &Z3, &Z3);;                            // a2^2    = S4zzn4_add(&x.c, &x.a, &z->c); // a0+a2zzn4_copy(&x.b, &Z1);zzn4_add(&Z1, &z->c, &Z1);zzn4_mul(&Z1, &Z1, &Z1); // (a0+a1+a2)^2  =S1zzn4_sub(&z->c, &x.b, &z->c);zzn4_mul(&z->c, &z->c, &z->c); // (a0-a1+a2)^2  =S2zzn4_add(&Z2, &Z2, &Z2);zzn4_add(&Z0, &Z0, &Z0);zzn4_add(&Z3, &Z3, &Z3);zzn4_sub(&Z1, &z->c, &T0);zzn4_sub(&T0, &Z2, &T0);zzn4_sub(&Z1, &Z0, &T1);zzn4_sub(&T1, &Z3, &T1);zzn4_add(&z->c, &T1, &z->c);zzn4_tx(&Z3);zzn4_add(&T0, &Z3, &z->b);zzn4_tx(&Z2);zzn4_add(&Z0, &Z2, &z->a);}}}else{// Karatsubazero_b = zzn4_iszero(&y.b);zero_c = zzn4_iszero(&y.c);zzn4_mul(&x.a, &y.a, &Z0); //9if (!zero_b)zzn4_mul(&x.b, &y.b, &Z2); //+6zzn4_add(&x.a, &x.b, &T0);zzn4_add(&y.a, &y.b, &T1);zzn4_mul(&T0, &T1, &Z1); //+9zzn4_sub(&Z1, &Z0, &Z1);if (!zero_b)zzn4_sub(&Z1, &Z2, &Z1);zzn4_add(&x.b, &x.c, &T0);zzn4_add(&y.b, &y.c, &T1);zzn4_mul(&T0, &T1, &Z3); //+6if (!zero_b)zzn4_sub(&Z3, &Z2, &Z3);zzn4_add(&x.a, &x.c, &T0);zzn4_add(&y.a, &y.c, &T1);zzn4_mul(&T0, &T1, &T0); //+9=39 for "special case"if (!zero_b)zzn4_add(&Z2, &T0, &Z2);elsezzn4_copy(&T0, &Z2);zzn4_sub(&Z2, &Z0, &Z2);zzn4_copy(&Z1, &z->b);if (!zero_c){ // exploit special form of BN curve line functionzzn4_mul(&x.c, &y.c, &T0);zzn4_sub(&Z2, &T0, &Z2);zzn4_sub(&Z3, &T0, &Z3);zzn4_tx(&T0);zzn4_add(&z->b, &T0, &z->b);}zzn4_tx(&Z3);zzn4_add(&Z0, &Z3, &z->a);zzn4_copy(&Z2, &z->c);if (!y.unitary)z->unitary = FALSE;}
}/****************************************************************Function:       zzn12_conjDescription:    achieve conjugate complexsee zzn12a.h and zzn1212.cpp for details in MIRACL c++ source fileCalls:          MIRACL functionsCalled By:Input:          zzn12 x,yOutput:         zzn12 *zReturn:         nullOthers:
****************************************************************/
void zzn12_conj(zzn12 *x, zzn12 *y)
{zzn4_conj(&x->a, &y->a);zzn4_conj(&x->b, &y->b);zzn4_negate(&y->b, &y->b);zzn4_conj(&x->c, &y->c);y->miller = x->miller;y->unitary = x->unitary;
}/****************************************************************Function:       zzn12_inverseDescription:    element inversion,see zzn12a.h and zzn1212.cpp for details in MIRACL c++ source fileCalls:          MIRACL functions,zzn12_init,zzn12_conjCalled By:Input:          zzn12 wOutput:Return:         zzn12Others:
****************************************************************/
zzn12 zzn12_inverse(zzn12 w)
{zzn4 tmp1, tmp2;zzn12 res;tmp1.a.a = mirvar(0);tmp1.a.b = mirvar(0);tmp1.b.a = mirvar(0);tmp1.b.b = mirvar(0);tmp1.unitary = FALSE;tmp2.a.a = mirvar(0);tmp2.a.b = mirvar(0);tmp2.b.a = mirvar(0);tmp2.b.b = mirvar(0);tmp2.unitary = FALSE;zzn12_init(&res);if (w.unitary){zzn12_conj(&w, &res);return res;}//res.a=w.a*w.a-tx(w.b*w.c);zzn4_mul(&w.a, &w.a, &res.a);zzn4_mul(&w.b, &w.c, &res.b);zzn4_tx(&res.b);zzn4_sub(&res.a, &res.b, &res.a);//res.b=tx(w.c*w.c)-w.a*w.b;zzn4_mul(&w.c, &w.c, &res.c);zzn4_tx(&res.c);zzn4_mul(&w.a, &w.b, &res.b);zzn4_sub(&res.c, &res.b, &res.b);//res.c=w.b*w.b-w.a*w.c;zzn4_mul(&w.b, &w.b, &res.c);zzn4_mul(&w.a, &w.c, &tmp1);zzn4_sub(&res.c, &tmp1, &res.c);//tmp1=tx(w.b*res.c)+w.a*res.a+tx(w.c*res.b);zzn4_mul(&w.b, &res.c, &tmp1);zzn4_tx(&tmp1);zzn4_mul(&w.a, &res.a, &tmp2);zzn4_add(&tmp1, &tmp2, &tmp1);zzn4_mul(&w.c, &res.b, &tmp2);zzn4_tx(&tmp2);zzn4_add(&tmp1, &tmp2, &tmp1);zzn4_inv(&tmp1);zzn4_mul(&res.a, &tmp1, &res.a);zzn4_mul(&res.b, &tmp1, &res.b);zzn4_mul(&res.c, &tmp1, &res.c);return res;
}/****************************************************************Function:       zzn12_powqDescription:    Frobenius F=x^p. Assumes p=1 mod 6see zzn12a.h and zzn1212.cpp for details in MIRACL c++ source fileCalls:          MIRACL functionsCalled By:Input:          zzn2 FOutput:         zzn12 *yReturn:         NULLOthers:
****************************************************************/
void zzn12_powq(zzn2 F, zzn12 *y)
{zzn2 X2, X3;X2.a = mirvar(0);X2.b = mirvar(0);X3.a = mirvar(0);X3.b = mirvar(0);zzn2_mul(&F, &F, &X2);zzn2_mul(&X2, &F, &X3);zzn4_powq(&X3, &y->a);zzn4_powq(&X3, &y->b);zzn4_powq(&X3, &y->c);zzn4_smul(&y->b, &X, &y->b);zzn4_smul(&y->c, &X2, &y->c);
}/****************************************************************Function:       zzn12_divDescription:    z=x/ysee zzn12a.h and zzn1212.cpp for details in MIRACL c++ source fileCalls:          MIRACL functions,zzn12_inverse,zzn12_mulCalled By:Input:          zzn12 x,yOutput:         zzn12 *zReturn:         NULLOthers:
****************************************************************/
void zzn12_div(zzn12 x, zzn12 y, zzn12 *z)
{y = zzn12_inverse(y);zzn12_mul(x, y, z);
}/****************************************************************Function:       zzn12_powDescription:    regular zzn12 powering,If k is low Hamming weight this will be just as good.see zzn12a.h and zzn1212.cpp for details in MIRACL c++ source fileCalls:          MIRACL functions,zzn12_inverse,zzn12_mul,zzn12_copy,zzn12_initCalled By:Input:          zzn12 x,big kOutput:Return:         zzn12Others:
****************************************************************/
zzn12 zzn12_pow(zzn12 x, big k)
{big zero, tmp, tmp1;int nb, i;BOOL invert_it;zzn12 res;zero = mirvar(0);tmp = mirvar(0);tmp1 = mirvar(0);zzn12_init(&res);copy(k, tmp1);invert_it = FALSE;if (mr_compare(tmp1, zero) == 0){tmp = get_mip()->one;zzn4_from_big(tmp, &res.a);return res;}if (mr_compare(tmp1, zero) < 0){negify(tmp1, tmp1);invert_it = TRUE;}nb = logb2(k);zzn12_copy(&x, &res);if (nb > 1)for (i = nb - 2; i >= 0; i--){zzn12_mul(res, res, &res);if (mr_testbit(k, i))zzn12_mul(res, x, &res);}if (invert_it)res = zzn12_inverse(res);return res;
}

SM9_sv.h

/************************************************************
Note:Codes here were downloaded from:http://www.scctc.org.cn/templates/Download/index.aspx?nodeid=71.The disclaimer was published on the link:http://www.scctc.org.cn/Upload/accessory/20175/201755105494041082.pdf .The codes were slightly modified to pass the check of C complier.
*************************************************************/#ifndef HEADER_SM9_SV_H
#define HEADER_SM9_SV_H///************************************************************************
//  File name:    SM9_sv.h
//  Version:      SM9_sv_V1.0
//  Date:         Dec 15,2016
//  Description:  implementation of SM9 signature algorithm and verification algorithm
//                all operations based on BN curve line function
//  Function List:
//        1.bytes128_to_ecn2     //convert 128 bytes into ecn2
//        2.zzn12_ElementPrint   //print all element of struct zzn12
//        3.ecn2_Bytes128_Print  //print 128 bytes of ecn2
//        4.LinkCharZzn12        //link two different types(unsigned char and zzn12)to one(unsigned char)
//        5.Test_Point           //test if the given point is on SM9 curve
//        6.Test_Range           //test if the big x belong to the range[1,N-1]
//        7.SM9_Init             //initiate SM9 curve
//        8.SM9_H1               //function H1 in SM9 standard 5.4.2.2
//        9.SM9_H2               //function H2 in SM9 standard 5.4.2.3
//        10.SM9_GenerateSignKey //generate signed private and public key
//        11.SM9_Sign            //SM9 signature algorithm
//        12.SM9_Verify          //SM9 verification
//        13.SM9_SelfCheck()     //SM9 slef-check//
// Notes:
// This SM9 implementation source code can be used for academic, non-profit making or non-commercial use only.
// This SM9 implementation is created on MIRACL. SM9 implementation source code provider does not provide MIRACL library, MIRACL license or any permission to use MIRACL library. Any commercial use of MIRACL requires a license which may be obtained from Shamus Software Ltd.//**************************************************************************/#include <malloc.h>
#include <math.h>
#include "miracl.h"
#include "R-ate.h"#define BNLEN 32 //BN curve with 256bit is used in SM9 algorithm#define SM9_ASK_MEMORY_ERR 0x00000001      //申请内存失败
#define SM9_H_OUTRANGE 0x00000002          //签名H不属于[1,N-1]
#define SM9_DATA_MEMCMP_ERR 0x00000003     //数据对比不一致
#define SM9_MEMBER_ERR 0x00000004          //群的阶错误
#define SM9_MY_ECAP_12A_ERR 0x00000005     //R-ate对计算出现错误
#define SM9_S_NOT_VALID_G1 0x00000006      //S不属于群G1
#define SM9_G1BASEPOINT_SET_ERR 0x00000007 //G1基点设置错误
#define SM9_G2BASEPOINT_SET_ERR 0x00000008 //G2基点设置错误
#define SM9_L_error 0x00000009             //参数L错误
#define SM9_GEPUB_ERR 0x0000000A           //生成公钥错误
#define SM9_GEPRI_ERR 0x0000000B           //生成私钥错误
#define SM9_SIGN_ERR 0x0000000C            //签名错误BOOL bytes128_to_ecn2(unsigned char Ppubs[], ecn2 *res);
void zzn12_ElementPrint(zzn12 x);
void ecn2_Bytes128_Print(ecn2 x);
void LinkCharZzn12(unsigned char *message, int len, zzn12 w, unsigned char *Z, int Zlen);
int Test_Point(epoint *point);
int Test_Range(big x);
int SM9_Init();
int SM9_H1(unsigned char Z[], int Zlen, big n, big h1);
int SM9_H2(unsigned char Z[], int Zlen, big n, big h2);
int SM9_GenerateSignKey(unsigned char hid[], unsigned char *ID, int IDlen,big ks, unsigned char Ppubs[], unsigned char dsa[]);
int SM9_Sign(unsigned char hid[], unsigned char *IDA, unsigned char *message, int len, unsigned char rand[],unsigned char dsa[], unsigned char Ppub[], unsigned char H[], unsigned char S[]);
int SM9_Verify(unsigned char H[], unsigned char S[], unsigned char hid[],unsigned char *IDA, unsigned char *message, int len, unsigned char Ppub[]);
int SM9_SelfCheck();#endif

SM9_sv.c

/************************************************************
Note:Codes here were downloaded from:http://www.scctc.org.cn/templates/Download/index.aspx?nodeid=71.The disclaimer was published on the link:http://www.scctc.org.cn/Upload/accessory/20175/201755105494041082.pdf .The codes were slightly modified to pass the check of C complier.
*************************************************************////************************************************************************
//  File name:    SM9_sv.c
//  Version:      SM9_sv_V1.0
//  Date:         Dec 15,2016
//  Description:  implementation of SM9 signature algorithm and verification algorithm
//                all operations based on BN curve line function
//  Function List:
//        1.bytes128_to_ecn2     //convert 128 bytes into ecn2
//        2.zzn12_ElementPrint   //print all element of struct zzn12
//        3.ecn2_Bytes128_Print  //print 128 bytes of ecn2
//        4.LinkCharZzn12        //link two different types(unsigned char and zzn12)to one(unsigned char)
//        5.Test_Point           //test if the given point is on SM9 curve
//        6.Test_Range           //test if the big x belong to the range[1,N-1]
//        7.SM9_Init             //initiate SM9 curve
//        8.SM9_H1               //function H1 in SM9 standard 5.4.2.2
//        9.SM9_H2               //function H2 in SM9 standard 5.4.2.3
//        10.SM9_GenerateSignKey //generate signed private and public key
//        11.SM9_Sign            //SM9 signature algorithm
//        12.SM9_Verify          //SM9 verification
//        13.SM9_SelfCheck()     //SM9 slef-check//
// Notes:
// This SM9 implementation source code can be used for academic, non-profit making or non-commercial use only.
// This SM9 implementation is created on MIRACL. SM9 implementation source code provider does not provide MIRACL library, MIRACL license or any permission to use MIRACL library. Any commercial use of MIRACL requires a license which may be obtained from Shamus Software Ltd.//**************************************************************************/#include "SM9_sv.h"
#include "kdf.h"extern miracl *mip;
extern zzn2 X; //Frobniues constantunsigned 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};epoint *P1;
ecn2 P2;
big N; //order of group, N(t)
big para_a, para_b, para_t, para_q;/****************************************************************Function:       bytes128_to_ecn2Description:    convert 128 bytes into ecn2Calls:          MIRACL functionsCalled By:      SM9_InitInput:          Ppubs[]Output:         ecn2 *resReturn:         FALSE: execution errorTRUE: execute correctlyOthers:
****************************************************************/
BOOL bytes128_to_ecn2(unsigned char Ppubs[], ecn2 *res)
{zzn2 x, y;big a, b;ecn2 r;r.x.a = mirvar(0);r.x.b = mirvar(0);r.y.a = mirvar(0);r.y.b = mirvar(0);r.z.a = mirvar(0);r.z.b = mirvar(0);r.marker = MR_EPOINT_INFINITY;x.a = mirvar(0);x.b = mirvar(0);y.a = mirvar(0);y.b = mirvar(0);a = mirvar(0);b = mirvar(0);bytes_to_big(BNLEN, Ppubs, b);bytes_to_big(BNLEN, Ppubs + BNLEN, a);zzn2_from_bigs(a, b, &x);bytes_to_big(BNLEN, Ppubs + BNLEN * 2, b);bytes_to_big(BNLEN, Ppubs + BNLEN * 3, a);zzn2_from_bigs(a, b, &y);return ecn2_set(&x, &y, res);
}/****************************************************************Function:       zzn12_ElementPrintDescription:    print all element of struct zzn12Calls:          MIRACL functionsCalled By:      SM9_Sign,SM9_VerifyInput:          zzn12 xOutput:         NULLReturn:         NULLOthers:
****************************************************************/
void zzn12_ElementPrint(zzn12 x)
{big tmp;tmp = mirvar(0);redc(x.c.b.b, tmp);cotnum(tmp, stdout);redc(x.c.b.a, tmp);cotnum(tmp, stdout);redc(x.c.a.b, tmp);cotnum(tmp, stdout);redc(x.c.a.a, tmp);cotnum(tmp, stdout);redc(x.b.b.b, tmp);cotnum(tmp, stdout);redc(x.b.b.a, tmp);cotnum(tmp, stdout);redc(x.b.a.b, tmp);cotnum(tmp, stdout);redc(x.b.a.a, tmp);cotnum(tmp, stdout);redc(x.a.b.b, tmp);cotnum(tmp, stdout);redc(x.a.b.a, tmp);cotnum(tmp, stdout);redc(x.a.a.b, tmp);cotnum(tmp, stdout);redc(x.a.a.a, tmp);cotnum(tmp, stdout);
}/****************************************************************Function:       ecn2_Bytes128_PrintDescription:    print 128 bytes of ecn2Calls:          MIRACL functionsCalled By:      SM9_Sign,SM9_VerifyInput:          ecn2 xOutput:         NULLReturn:         NULLOthers:
****************************************************************/
void ecn2_Bytes128_Print(ecn2 x)
{big tmp;tmp = mirvar(0);redc(x.x.b, tmp);cotnum(tmp, stdout);redc(x.x.a, tmp);cotnum(tmp, stdout);redc(x.y.b, tmp);cotnum(tmp, stdout);redc(x.y.a, tmp);cotnum(tmp, stdout);
}/****************************************************************Function:       LinkCharZzn12Description:    link two different types(unsigned char and zzn12)to one(unsigned char)Calls:          MIRACL functionsCalled By:      SM9_Sign,SM9_VerifyInput:          message:len:    length of messagew:      zzn12 elementOutput:         Z:      the characters array stored message and wZlen:   length of ZReturn:         NULLOthers:
****************************************************************/
void LinkCharZzn12(unsigned char *message, int len, zzn12 w, unsigned char *Z, int Zlen)
{big tmp;tmp = mirvar(0);memcpy(Z, message, len);redc(w.c.b.b, tmp);big_to_bytes(BNLEN, tmp, Z + len, 1);redc(w.c.b.a, tmp);big_to_bytes(BNLEN, tmp, Z + len + BNLEN, 1);redc(w.c.a.b, tmp);big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 2, 1);redc(w.c.a.a, tmp);big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 3, 1);redc(w.b.b.b, tmp);big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 4, 1);redc(w.b.b.a, tmp);big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 5, 1);redc(w.b.a.b, tmp);big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 6, 1);redc(w.b.a.a, tmp);big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 7, 1);redc(w.a.b.b, tmp);big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 8, 1);redc(w.a.b.a, tmp);big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 9, 1);redc(w.a.a.b, tmp);big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 10, 1);redc(w.a.a.a, tmp);big_to_bytes(BNLEN, tmp, Z + len + BNLEN * 11, 1);
}/****************************************************************Function:       Test_PointDescription:    test if the given point is on SM9 curveCalls:Called By:      SM9_VerifyInput:          pointOutput:         nullReturn:         0: success1: not a valid point on curveOthers:
****************************************************************/
int Test_Point(epoint *point)
{big x, y, x_3, tmp;epoint *buf;x = mirvar(0);y = mirvar(0);x_3 = mirvar(0);tmp = mirvar(0);buf = epoint_init();//test if y^2=x^3+bepoint_get(point, x, y);power(x, 3, para_q, x_3); //x_3=x^3 mod pmultiply(x, para_a, x);divide(x, para_q, tmp);add(x_3, x, x); //x=x^3+ax+badd(x, para_b, x);divide(x, para_q, tmp); //x=x^3+ax+b mod ppower(y, 2, para_q, y); //y=y^2 mod pif (mr_compare(x, y) != 0)return 1;//test infinityecurve_mult(N, point, buf);if (point_at_infinity(buf) == FALSE)return 1;return 0;
}/****************************************************************Function:       Test_RangeDescription:    test if the big x belong to the range[1,n-1]Calls:Called By:      SM9_VerifyInput:          big x    ///a miracl data typeOutput:         nullReturn:         0: success1: x==n,failOthers:
****************************************************************/
int Test_Range(big x)
{big one, decr_n;one = mirvar(0);decr_n = mirvar(0);convert(1, one);decr(N, 1, decr_n);if ((mr_compare(x, one) < 0) | (mr_compare(x, decr_n) > 0))return 1;return 0;
}/****************************************************************Function:       SM9_InitDescription:    Initiate SM9 curveCalls:          MIRACL functionsCalled By:      SM9_SelfCheckInput:          nullOutput:         nullReturn:         0: success;7: base point P1 error8: base point P2 errorOthers:
****************************************************************/
int SM9_Init()
{big P1_x, P1_y;mip = mirsys(1000, 16);;mip->IOBASE = 16;para_q = mirvar(0);N = mirvar(0);P1_x = mirvar(0);P1_y = mirvar(0);para_a = mirvar(0);para_b = mirvar(0);para_t = mirvar(0);X.a = mirvar(0);X.b = mirvar(0);P2.x.a = mirvar(0);P2.x.b = mirvar(0);P2.y.a = mirvar(0);P2.y.b = mirvar(0);P2.z.a = mirvar(0);P2.z.b = mirvar(0);P2.marker = MR_EPOINT_INFINITY;P1 = epoint_init();bytes_to_big(BNLEN, SM9_q, para_q);bytes_to_big(BNLEN, SM9_P1x, P1_x);bytes_to_big(BNLEN, SM9_P1y, P1_y);bytes_to_big(BNLEN, SM9_a, para_a);bytes_to_big(BNLEN, SM9_b, para_b);bytes_to_big(BNLEN, SM9_N, N);bytes_to_big(BNLEN, SM9_t, para_t);mip->TWIST = MR_SEXTIC_M;ecurve_init(para_a, para_b, para_q, MR_PROJECTIVE); //Initialises GF(q) elliptic curve//MR_PROJECTIVE specifying projective coordinatesif (!epoint_set(P1_x, P1_y, 0, P1))return SM9_G1BASEPOINT_SET_ERR;if (!(bytes128_to_ecn2(SM9_P2, &P2)))return SM9_G2BASEPOINT_SET_ERR;set_frobenius_constant(&X);return 0;
}/****************************************************************Function:       SM9_H1Description:    function H1 in SM9 standard 5.4.2.2Calls:          MIRACL functions,SM3_KDFCalled By:      SM9_VerifyInput:          Z:Zlen:the length of Zn:Frobniues constant XOutput:         h1=H1(Z,Zlen)Return:         0: success;1: asking for memory errorOthers:
****************************************************************/
int SM9_H1(unsigned char Z[], int Zlen, big n, big h1)
{int hlen, i, ZHlen;big hh, i256, tmp, n1;unsigned char *ZH = NULL, *ha = NULL;hh = mirvar(0);i256 = mirvar(0);tmp = mirvar(0);n1 = mirvar(0);convert(1, i256);ZHlen = Zlen + 1;hlen = (int)ceil((5.0 * logb2(n)) / 32.0);decr(n, 1, n1);ZH = (char *)malloc(sizeof(char) * (ZHlen + 1));if (ZH == NULL)return SM9_ASK_MEMORY_ERR;memcpy(ZH + 1, Z, Zlen);ZH[0] = 0x01;ha = (char *)malloc(sizeof(char) * (hlen + 1));if (ha == NULL)return SM9_ASK_MEMORY_ERR;SM3_KDF(ZH, ZHlen, hlen, ha);for (i = hlen - 1; i >= 0; i--) //key[�Ӵ�С]{premult(i256, ha[i], tmp);add(hh, tmp, hh);premult(i256, 256, i256);divide(i256, n1, tmp);divide(hh, n1, tmp);}incr(hh, 1, h1);free(ZH);free(ha);return 0;
}
/****************************************************************Function:       SM9_H2Description:    function H2 in SM9 standard 5.4.2.3Calls:          MIRACL functions,SM3_KDFCalled By:      SM9_Sign,SM9_VerifyInput:          Z:Zlen:the length of Zn:Frobniues constant XOutput:         h2=H2(Z,Zlen)Return:         0: success;1: asking for memory errorOthers:
****************************************************************/
int SM9_H2(unsigned char Z[], int Zlen, big n, big h2)
{int hlen, ZHlen, i;big hh, i256, tmp, n1;unsigned char *ZH = NULL, *ha = NULL;hh = mirvar(0);i256 = mirvar(0);tmp = mirvar(0);n1 = mirvar(0);convert(1, i256);ZHlen = Zlen + 1;hlen = (int)ceil((5.0 * logb2(n)) / 32.0);decr(n, 1, n1);ZH = (char *)malloc(sizeof(char) * (ZHlen + 1));if (ZH == NULL)return SM9_ASK_MEMORY_ERR;memcpy(ZH + 1, Z, Zlen);ZH[0] = 0x02;ha = (char *)malloc(sizeof(char) * (hlen + 1));if (ha == NULL)return SM9_ASK_MEMORY_ERR;SM3_KDF(ZH, ZHlen, hlen, ha);for (i = hlen - 1; i >= 0; i--) //key[�Ӵ�С]{premult(i256, ha[i], tmp);add(hh, tmp, hh);premult(i256, 256, i256);divide(i256, n1, tmp);divide(hh, n1, tmp);}incr(hh, 1, h2);free(ZH);free(ha);return 0;
}/****************************************************************Function:       SM9_GenerateSignKeyDescription:    Generate Signed keyCalls:          MIRACL functions,SM9_H1,xgcd,ecn2_Bytes128_PrintCalled By:      SM9_SelfCheckInput:          hid:0x01ID:identificationIDlen:the length of IDks:master private key used to generate signature public key and private keyOutput:         Ppub:signature public keydSA: signature private keyReturn:         0: success;1: asking for memory errorOthers:
****************************************************************/
int SM9_GenerateSignKey(unsigned char hid[], unsigned char *ID, int IDlen, big ks, unsigned char Ppubs[], unsigned char dsa[])
{big h1, t1, t2, rem, xdSA, ydSA, tmp;unsigned char *Z = NULL;int Zlen = IDlen + 1, buf;ecn2 Ppub;epoint *dSA;h1 = mirvar(0);t1 = mirvar(0);t2 = mirvar(0);rem = mirvar(0);tmp = mirvar(0);xdSA = mirvar(0);ydSA = mirvar(0);dSA = epoint_init();Ppub.x.a = mirvar(0);Ppub.x.b = mirvar(0);Ppub.y.a = mirvar(0);Ppub.y.b = mirvar(0);Ppub.z.a = mirvar(0);Ppub.z.b = mirvar(0);Ppub.marker = MR_EPOINT_INFINITY;Z = (char *)malloc(sizeof(char) * (Zlen + 1));if (!(Z))return 1;memcpy(Z, ID, IDlen);memcpy(Z + IDlen, hid, 1);buf = SM9_H1(Z, Zlen, N, h1);if (buf != 0)return buf;add(h1, ks, t1);         //t1=H1(IDA||hid,N)+ksxgcd(t1, N, t1, t1, t1); //t1=t1(-1)multiply(ks, t1, t2);divide(t2, N, rem); //t2=ks*t1(-1)//dSA=[t2]P1ecurve_mult(t2, P1, dSA);//Ppub=[ks]P2ecn2_copy(&P2, &Ppub);ecn2_mul(ks, &Ppub);printf("\n*********************The signed key = (xdA, ydA): *********************\n");epoint_get(dSA, xdSA, ydSA);cotnum(xdSA, stdout);cotnum(ydSA, stdout);printf("\n**********************PublicKey Ppubs=[ks]P2: *************************\n");ecn2_Bytes128_Print(Ppub);epoint_get(dSA, xdSA, ydSA);big_to_bytes(BNLEN, xdSA, dsa, 1);big_to_bytes(BNLEN, ydSA, dsa + BNLEN, 1);redc(Ppub.x.b, tmp);big_to_bytes(BNLEN, tmp, Ppubs, 1);redc(Ppub.x.a, tmp);big_to_bytes(BNLEN, tmp, Ppubs + BNLEN, 1);redc(Ppub.y.b, tmp);big_to_bytes(BNLEN, tmp, Ppubs + BNLEN * 2, 1);redc(Ppub.y.a, tmp);big_to_bytes(BNLEN, tmp, Ppubs + BNLEN * 3, 1);free(Z);return 0;
}/****************************************************************Function:       SM9_SignDescription:    SM9 signature algorithmCalls:          MIRACL functions,zzn12_init(),ecap(),member(),zzn12_ElementPrint(),zzn12_pow(),LinkCharZzn12(),SM9_H2()Called By:      SM9_SelfCheck()Input:hid:0x01IDA          //identification of userAmessage      //the message to be signedlen          //the length of messagerand         //a random number K lies in [1,N-1]dSA          //signature private keyPpubs        //signature public keyOutput:         H,S        //signature resultReturn:         0: success1: asking for memory error4: element is out of order q5: R-ate calculation error9: parameter L errorOthers:
****************************************************************/
int SM9_Sign(unsigned char hid[], unsigned char *IDA, unsigned char *message, int len, unsigned char rand[],unsigned char dsa[], unsigned char Ppub[], unsigned char H[], unsigned char S[])
{big h1, r, h, l, xdSA, ydSA;big xS, yS, tmp, zero;zzn12 g, w;epoint *s, *dSA;ecn2 Ppubs;int Zlen, buf;unsigned char *Z = NULL;//initiateh1 = mirvar(0);r = mirvar(0);h = mirvar(0);l = mirvar(0);tmp = mirvar(0);zero = mirvar(0);xS = mirvar(0);yS = mirvar(0);xdSA = mirvar(0);ydSA = mirvar(0);s = epoint_init();dSA = epoint_init();Ppubs.x.a = mirvar(0);Ppubs.x.b = mirvar(0);Ppubs.y.a = mirvar(0);Ppubs.y.b = mirvar(0);Ppubs.z.a = mirvar(0);Ppubs.z.b = mirvar(0);Ppubs.marker = MR_EPOINT_INFINITY;zzn12_init(&g);zzn12_init(&w);bytes_to_big(BNLEN, rand, r);bytes_to_big(BNLEN, dsa, xdSA);bytes_to_big(BNLEN, dsa + BNLEN, ydSA);epoint_set(xdSA, ydSA, 0, dSA);bytes128_to_ecn2(Ppub, &Ppubs);//Step1:g = e(P1, Ppub-s)if (!ecap(Ppubs, P1, para_t, X, &g))return SM9_MY_ECAP_12A_ERR;//test if a ZZn12 element is of order qif (!member(g, para_t, X))return SM9_MEMBER_ERR;printf("\n***********************g=e(P1,Ppubs):****************************\n");zzn12_ElementPrint(g);//Step2:calculate w=g(r)printf("\n***********************randnum r:********************************\n");cotnum(r, stdout);w = zzn12_pow(g, r);printf("\n***************************w=gr:**********************************\n");zzn12_ElementPrint(w);//Step3:calculate h=H2(M||w,N)Zlen = len + 32 * 12;Z = (char *)malloc(sizeof(char) * (Zlen + 1));if (Z == NULL)return SM9_ASK_MEMORY_ERR;LinkCharZzn12(message, len, w, Z, Zlen);buf = SM9_H2(Z, Zlen, N, h);if (buf != 0)return buf;printf("\n****************************h:*************************************\n");cotnum(h, stdout);//Step4:l=(r-h)mod Nsubtract(r, h, l);divide(l, N, tmp);while (mr_compare(l, zero) < 0)add(l, N, l);if (mr_compare(l, zero) == 0)return SM9_L_error;printf("\n**************************l=(r-h)mod N:****************************\n");cotnum(l, stdout);//Step5:S=[l]dSA=(xS,yS)ecurve_mult(l, dSA, s);epoint_get(s, xS, yS);printf("\n**************************S=[l]dSA=(xS,yS):*************************\n");cotnum(xS, stdout);cotnum(yS, stdout);big_to_bytes(32, h, H, 1);big_to_bytes(32, xS, S, 1);big_to_bytes(32, yS, S + 32, 1);free(Z);return 0;
}
/****************************************************************Function:       SM9_VerifyDescription:    SM9 signature verification algorithmCalls:          MIRACL functions,zzn12_init(),Test_Range(),Test_Point(),ecap(),member(),zzn12_ElementPrint(),SM9_H1(),SM9_H2()Called By:      SM9_SelfCheck()Input:H,S          //signature result used to be verifiedhid          //identificationIDA          //identification of userAmessage      //the message to be signedlen          //the length of messagePpubs        //signature public keyOutput:         NULLReturn:         0: success1: asking for memory error2: H is not in the range[1,N-1]6: S is not on the SM9 curve4: element is out of order q5: R-ate calculation error3: h2!=h,comparison errorOthers:
****************************************************************/
int SM9_Verify(unsigned char H[], unsigned char S[], unsigned char hid[], unsigned char *IDA, unsigned char *message, int len,unsigned char Ppub[])
{big h, xS, yS, h1, h2;epoint *S1;zzn12 g, t, u, w;ecn2 P, Ppubs;int Zlen1, Zlen2, buf;unsigned char *Z1 = NULL, *Z2 = NULL;h = mirvar(0);h1 = mirvar(0);h2 = mirvar(0);xS = mirvar(0);yS = mirvar(0);P.x.a = mirvar(0);P.x.b = mirvar(0);P.y.a = mirvar(0);P.y.b = mirvar(0);P.z.a = mirvar(0);P.z.b = mirvar(0);P.marker = MR_EPOINT_INFINITY;Ppubs.x.a = mirvar(0);Ppubs.x.b = mirvar(0);Ppubs.y.a = mirvar(0);Ppubs.y.b = mirvar(0);Ppubs.z.a = mirvar(0);Ppubs.z.b = mirvar(0);Ppubs.marker = MR_EPOINT_INFINITY;S1 = epoint_init();zzn12_init(&g), zzn12_init(&t);zzn12_init(&u);zzn12_init(&w);bytes_to_big(BNLEN, H, h);bytes_to_big(BNLEN, S, xS);bytes_to_big(BNLEN, S + BNLEN, yS);bytes128_to_ecn2(Ppub, &Ppubs);//Step 1:test if h in the rangge [1,N-1]if (Test_Range(h))return SM9_H_OUTRANGE;//Step 2:test if S is on G1epoint_set(xS, yS, 0, S1);if (Test_Point(S1))return SM9_S_NOT_VALID_G1;//Step3:g = e(P1, Ppub-s)if (!ecap(Ppubs, P1, para_t, X, &g))return SM9_MY_ECAP_12A_ERR;//test if a ZZn12 element is of order qif (!member(g, para_t, X))return SM9_MEMBER_ERR;printf("\n***********************g=e(P1,Ppubs): ****************************\n");zzn12_ElementPrint(g);//Step4:calculate t=g(h)t = zzn12_pow(g, h);printf("\n***************************w=gh: **********************************\n");zzn12_ElementPrint(t);//Step5:calculate h1=H1(IDA||hid,N)Zlen1 = strlen(IDA) + 1;Z1 = (char *)malloc(sizeof(char) * (Zlen1 + 1));if (Z1 == NULL)return SM9_ASK_MEMORY_ERR;memcpy(Z1, IDA, strlen(IDA));memcpy(Z1 + strlen(IDA), hid, 1);buf = SM9_H1(Z1, Zlen1, N, h1);if (buf != 0)return buf;printf("\n****************************h1: **********************************\n");cotnum(h1, stdout);//Step6:P=[h1]P2+Ppubsecn2_copy(&P2, &P);ecn2_mul(h1, &P);ecn2_add(&Ppubs, &P);//Step7:u=e(S1,P)if (!ecap(P, S1, para_t, X, &u))return SM9_MY_ECAP_12A_ERR;//test if a ZZn12 element is of order qif (!member(u, para_t, X))return SM9_MEMBER_ERR;printf("\n************************** u=e(S1,P): *****************************\n");zzn12_ElementPrint(u);//Step8:w=u*tzzn12_mul(u, t, &w);printf("\n*************************  w=u*t: **********************************\n");zzn12_ElementPrint(w);//Step9:h2=H2(M||w,N)Zlen2 = len + 32 * 12;Z2 = (char *)malloc(sizeof(char) * (Zlen2 + 1));if (Z2 == NULL)return SM9_ASK_MEMORY_ERR;LinkCharZzn12(message, len, w, Z2, Zlen2);buf = SM9_H2(Z2, Zlen2, N, h2);if (buf != 0)return buf;printf("\n**************************** h2: ***********************************\n");cotnum(h2, stdout);free(Z1);free(Z2);if (mr_compare(h2, h) != 0)return SM9_DATA_MEMCMP_ERR;return 0;
}/****************************************************************Function:       SM9_SelfCheckDescription:    SM9 self checkCalls:          MIRACL functions,SM9_Init(),SM9_GenerateSignKey(),SM9_Sign,SM9_VerifyCalled By:Input:Output:Return:         0: self-check success1: asking for memory error2: H is not in the range[1,N-1]3: h2!=h,comparison error4: element is out of order q5: R-ate calculation error6: S is not on the SM9 curve7: base point P1 error8: base point P2 error9: parameter L errorA: public key generated errorB: private key generated errorC: signature result errorOthers:
****************************************************************/
int SM9_SelfCheck()
{//the master private keyunsigned char dA[32] = {0x00, 0x01, 0x30, 0xE7, 0x84, 0x59, 0xD7, 0x85, 0x45, 0xCB, 0x54, 0xC5, 0x87, 0xE0, 0x2C, 0xF4,0x80, 0xCE, 0x0B, 0x66, 0x34, 0x0F, 0x31, 0x9F, 0x34, 0x8A, 0x1D, 0x5B, 0x1F, 0x2D, 0xC5, 0xF4};unsigned char rand[32] = {0x00, 0x03, 0x3C, 0x86, 0x16, 0xB0, 0x67, 0x04, 0x81, 0x32, 0x03, 0xDF, 0xD0, 0x09, 0x65, 0x02,0x2E, 0xD1, 0x59, 0x75, 0xC6, 0x62, 0x33, 0x7A, 0xED, 0x64, 0x88, 0x35, 0xDC, 0x4B, 0x1C, 0xBE};unsigned char h[32], S[64]; // Signatureunsigned char Ppub[128], dSA[64];unsigned char std_h[32] = {0x82, 0x3C, 0x4B, 0x21, 0xE4, 0xBD, 0x2D, 0xFE, 0x1E, 0xD9, 0x2C, 0x60, 0x66, 0x53, 0xE9, 0x96,0x66, 0x85, 0x63, 0x15, 0x2F, 0xC3, 0x3F, 0x55, 0xD7, 0xBF, 0xBB, 0x9B, 0xD9, 0x70, 0x5A, 0xDB};unsigned char std_S[64] = {0x73, 0xBF, 0x96, 0x92, 0x3C, 0xE5, 0x8B, 0x6A, 0xD0, 0xE1, 0x3E, 0x96, 0x43, 0xA4, 0x06, 0xD8,0xEB, 0x98, 0x41, 0x7C, 0x50, 0xEF, 0x1B, 0x29, 0xCE, 0xF9, 0xAD, 0xB4, 0x8B, 0x6D, 0x59, 0x8C,0x85, 0x67, 0x12, 0xF1, 0xC2, 0xE0, 0x96, 0x8A, 0xB7, 0x76, 0x9F, 0x42, 0xA9, 0x95, 0x86, 0xAE,0xD1, 0x39, 0xD5, 0xB8, 0xB3, 0xE1, 0x58, 0x91, 0x82, 0x7C, 0xC2, 0xAC, 0xED, 0x9B, 0xAA, 0x05};unsigned char std_Ppub[128] = {0x9F, 0x64, 0x08, 0x0B, 0x30, 0x84, 0xF7, 0x33, 0xE4, 0x8A, 0xFF, 0x4B, 0x41, 0xB5, 0x65, 0x01,0x1C, 0xE0, 0x71, 0x1C, 0x5E, 0x39, 0x2C, 0xFB, 0x0A, 0xB1, 0xB6, 0x79, 0x1B, 0x94, 0xC4, 0x08,0x29, 0xDB, 0xA1, 0x16, 0x15, 0x2D, 0x1F, 0x78, 0x6C, 0xE8, 0x43, 0xED, 0x24, 0xA3, 0xB5, 0x73,0x41, 0x4D, 0x21, 0x77, 0x38, 0x6A, 0x92, 0xDD, 0x8F, 0x14, 0xD6, 0x56, 0x96, 0xEA, 0x5E, 0x32,0x69, 0x85, 0x09, 0x38, 0xAB, 0xEA, 0x01, 0x12, 0xB5, 0x73, 0x29, 0xF4, 0x47, 0xE3, 0xA0, 0xCB,0xAD, 0x3E, 0x2F, 0xDB, 0x1A, 0x77, 0xF3, 0x35, 0xE8, 0x9E, 0x14, 0x08, 0xD0, 0xEF, 0x1C, 0x25,0x41, 0xE0, 0x0A, 0x53, 0xDD, 0xA5, 0x32, 0xDA, 0x1A, 0x7C, 0xE0, 0x27, 0xB7, 0xA4, 0x6F, 0x74,0x10, 0x06, 0xE8, 0x5F, 0x5C, 0xDF, 0xF0, 0x73, 0x0E, 0x75, 0xC0, 0x5F, 0xB4, 0xE3, 0x21, 0x6D};unsigned char std_dSA[64] = {0xA5, 0x70, 0x2F, 0x05, 0xCF, 0x13, 0x15, 0x30, 0x5E, 0x2D, 0x6E, 0xB6, 0x4B, 0x0D, 0xEB, 0x92,0x3D, 0xB1, 0xA0, 0xBC, 0xF0, 0xCA, 0xFF, 0x90, 0x52, 0x3A, 0xC8, 0x75, 0x4A, 0xA6, 0x98, 0x20,0x78, 0x55, 0x9A, 0x84, 0x44, 0x11, 0xF9, 0x82, 0x5C, 0x10, 0x9F, 0x5E, 0xE3, 0xF5, 0x2D, 0x72,0x0D, 0xD0, 0x17, 0x85, 0x39, 0x2A, 0x72, 0x7B, 0xB1, 0x55, 0x69, 0x52, 0xB2, 0xB0, 0x13, 0xD3};unsigned char hid[] = {0x01};unsigned char *IDA = "Alice";unsigned char *message = "Chinese IBS standard"; //the message to be signedint mlen = strlen(message), tmp;                 //the length of messagebig ks;tmp = SM9_Init();if (tmp != 0)return tmp;ks = mirvar(0);bytes_to_big(32, dA, ks);printf("\n***********************  SM9 key Generation    ***************************\n");tmp = SM9_GenerateSignKey(hid, IDA, strlen(IDA), ks, Ppub, dSA);if (tmp != 0)return tmp;if (memcmp(Ppub, std_Ppub, 128) != 0)return SM9_GEPUB_ERR;if (memcmp(dSA, std_dSA, 64) != 0)return SM9_GEPRI_ERR;printf("\n**********************  SM9 signature algorithm***************************\n");tmp = SM9_Sign(hid, IDA, message, mlen, rand, dSA, Ppub, h, S);if (tmp != 0)return tmp;if (memcmp(h, std_h, 32) != 0)return SM9_SIGN_ERR;if (memcmp(S, std_S, 64) != 0)return SM9_SIGN_ERR;printf("\n*******************  SM9 verification algorithm *************************\n");tmp = SM9_Verify(h, S, hid, IDA, message, mlen, Ppub);if (tmp != 0)return tmp;return 0;
}

test.c

#include <stdio.h>
#include "SM9_sv.h"int main(void)
{int error_code;if ( error_code = SM9_SelfCheck() ){printf("\nSM9 sign and verify self test falied!.\n");printf("\nError code: 0x%x\n", error_code);return error_code;}else{printf("\nSM9 sign and verify self test succeeded.\n");return 0;}
}

这里使用 Visual Studio Community 2019 创建一个空的控制台项目,将上面的源文件拷贝到该项目所在的目录下,并在“解决方案资源管理器”子窗口中,添加相应的头文件和源文件。编译程序需要用到开源库 MIRACL 相关的头文件和库文件。对于如何在 Windows下 编译 MIRACL,在本博客前面的系列文章(链接: https://blog.csdn.net/henter/article/details/103606333 )中有介绍。需要将 miracl.h 和 mirdef.h 头文件及其所在目录添加到项目属性的“附加包含目录”设置项中,在链接器相关的“附加依赖项”设置中,要设置 MIRACL 相关的库文件路径及文件名,例如 miracl_x86.lib ,然后按组合键 Ctrl + F5 ,就可以编译并运行 SM9 签名验签程序了,运行结果的部分截图如下:

记录 Windows 下编译一个开源 SM9 签名验签 C 程序的过程相关推荐

  1. SM2加解密、签名验签

    导论 SM2是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法,在我们国家商用密码体系中被用来替换RSA算法. 国产SM2算法,是基于ECC的,但二者在签名验签.加密解密过程中或许有些 ...

  2. Windows下编译TensorFlow1.3 C++ library及创建一个简单的TensorFlow C++程序

    参考:https://www.cnblogs.com/jliangqiu2016/p/7642471.html Windows下编译TensorFlow1.3 C++ library及创建一个简单的T ...

  3. Windows下编译语音识别引擎Wenet

    Windows下编译语音识别引擎Wenet 一.Wenet简介 二.Wenet首次编译过程 2.1下载第三方库源码 2.2替换软链接 2.3下载gRPC的third_party 三.Wenet第二次编 ...

  4. Windows下编译OpenCV+opencv_contrib

    文章目录 前言 一.写在前面重要的事 二.正文 1.安装步骤 2.编译及配置 总结 前言 在学习OpenCV特征检测与匹配时,因为OpenCV3.x版本将SIFT.SURF.ORB算子等的源代码从官方 ...

  5. 实战Windows下编译Opencc 1.0.5

    Opencc是中文简繁转换开源项目,支持词汇级别的转换.异体字转换和地区习惯用词转换(中国大陆.台湾.香港). 特点 严格区分「一简对多繁」和「一简对多异」. 完全兼容异体字,可以实现动态替换. 严格 ...

  6. Linux及Windows下编译exosip和osip2源码

    eXosip库及编译流程简介 1.eXosip库的简介 1.1.osip简介 osip2是一个开放源代码的sip协议栈,是开源代码中不多使用C语言写的协议栈之一,它具有短小简洁的特点,专注于sip底层 ...

  7. Windows下编译Chrome V8

    主要还是参考google的官方文档: How to Download and Build V8 Building on Windows 同时也参考了一些其它的中文博客: 脚本引擎小pk:SpiderM ...

  8. fastdfs windows部署_Go在windows下编译Linux可执行文件

    欢迎关注我的头条号:Wooola,专注于Java.Golang.微服务架构,致力于每天分享原创文章.快乐编码和开源技术. 前言 最近楼主做了一个滑块验证码登录功能,但有个问题,悲观估计一天大约会产生两 ...

  9. Windows下编译扩展OpenCV 3.1.0 + opencv_contrib

    在Windows下编译扩展OpenCV 3.1.0 + opencv_contrib 为什么要CMake,这里我陈述自己的想法,作为一个刚使用opencv库的小白来说,有以下大概三点内容 1.由于在学 ...

最新文章

  1. foo php,php – $foo === TRUE和TRUE === $foo有什么区别?
  2. C语言中的一维数组和二维数组
  3. Hadoop集群中添加硬盘
  4. Angular Universal 学习笔记
  5. 五大“领跑者”光伏基地概览
  6. HDFS中心缓存管理
  7. 斐波那契回调线怎么画_外汇MT4平台上的斐波那契回调线怎么使用
  8. 深度强化学习- 最全深度强化学习资料
  9. 第二十四周项目3-动态链表体验
  10. SVN下载、安装、配置及使用方法
  11. 360浏览器邮件扩展添加企业邮箱
  12. 最适合使用外汇跟单软件的人
  13. SOAP Action介绍
  14. Unity2D 简易2D地图 —— 地图的显示
  15. CSS基础学习(二)
  16. 前端生产环境调试工具sourcemap的使用
  17. golang_iota
  18. jquery.webcam.js实现调用摄像头拍照兼容各个浏览器
  19. 细说final的的四种用法-----修饰类,修饰方法,常量,修饰参数 及内部类与final
  20. 使用poi导出excel表基础

热门文章

  1. 我是DM (低级格式化命令)
  2. HP小型机远程控制台(拨入MODEM)的配置步骤
  3. 完美世界游戏客户端程序面试
  4. 帆软相同列合并_合并表格工具_合并表格工具的痛点_合并表格工具哪一款比较好用-帆软...
  5. Android杂谈--ubuntu系统下adb连接小米2
  6. 2021-06-03——CSS属性制作家用电器商品分类表
  7. 常用正则表达式—邮箱
  8. 华为云桌面,开启云上高效办公之旅!
  9. 手机浏览器加载不出来css,如何解决浏览器不加载css文件的问题
  10. vue 引入json地图_使用vue+echarts快速进行全国地图与各省市地图联动(下钻地图), 引入省份js文件...