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

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

        在商用密码检测中心( 链接: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.h
  Version:
         KDF_V1.1
  Date:
         Sep 24,2016
  Description:
         This headfile provides KDF function needed in SM2 algorithm
  Function List:
    1.SM3_256        //calls SM3_init, SM3_process and SM3_done to calculate hash value
    2.SM3_init       //init the SM3 state
    3.SM3_process    //compress the the first len/64 blocks of the message
    4.SM3_done       //compress the rest message and output the hash value
    5.SM3_compress   //called by SM3_process and SM3_done, compress a single block of message
    6.BiToW          //called by SM3_compress,to calculate W from Bi
    7.WToW1          //called by SM3_compress, calculate W' from W
    8.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 stream
  History:
    1. Date:   Sep 18,2016
       Modification: Adding notes to all the functions
************************************************************************/

#ifndef HEADER_KDF_H
#define HEADER_KDF_H

#include 

#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 
#include "KDF.h"

/****************************************************************
  Function:       BiToW
  Description:    calculate W from Bi
  Calls:
  Called By:      SM3_compress
  Input:          Bi[16]    //a block of a message
  Output:         W[68]
  Return:         null
  Others:
****************************************************************/
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:       WToW1
  Description:    calculate W1 from W
  Calls:
  Called By:      SM3_compress
  Input:          W[68]
  Output:         W1[64]
  Return:         null
  Others:
*****************************************************************/
void WToW1(unsigned long W[], unsigned long W1[])
{
    int i;
    for (i = 0; i <= 63; i++)
    {
        W1[i] = W[i] ^ W[i + 4];
    }
}

/******************************************************************
  Function:       CF
  Description:    calculate the CF compress function and update V
  Calls:
  Called By:      SM3_compress
  Input:          W[68]
                  W1[64]
                  V[8]
  Output:         V[8]
  Return:         null
  Others:
********************************************************************/
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=V0
    A = 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++)
    {
        //SS1
        if (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);

        //SS2
        SS2 = SS1 ^ SM3_rotl32(A, 12);

        //TT1
        if (j <= 15)
        {
            FF = SM3_ff0(A, B, C);
        }

        else
        {
            FF = SM3_ff1(A, B, C);
        }
        TT1 = FF + D + SS2 + *W1;
        W1++;

        //TT2
        if (j <= 15)
        {
            GG = SM3_gg0(E, F, G);
        }
        else
        {
            GG = SM3_gg1(E, F, G);
        }
        TT2 = GG + H + SS1 + *W;
        W++;

        //D
        D = C;

        //C
        C = SM3_rotl32(B, 9);

        //B
        B = A;

        //A
        A = TT1;

        //H
        H = G;

        //G
        G = SM3_rotl32(F, 19);

        //F
        F = E;

        //E
        E = SM3_p0(TT2);
    }

    //update V
    V[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:       BigEndian
  Description:    unsigned int endian converse.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.
  Calls:
  Called By:      SM3_compress, SM3_done
  Input:          src[bytelen]
                  bytelen
  Output:         des[bytelen]
  Return:         null
  Others:         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_init
  Description:    initiate SM3 state
  Calls:
  Called By:      SM3_256
  Input:          SM3_STATE *md
  Output:         SM3_STATE *md
  Return:         null
  Others:
*******************************************************************************/
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_compress
  Description:    compress a single block of message
  Calls:          BigEndian
                  BiToW
                  WToW1
                  CF
  Called By:      SM3_256
  Input:          SM3_STATE *md
  Output:         SM3_STATE *md
  Return:         null
  Others:
*******************************************************************************/
void SM3_compress(SM3_STATE *md)
{
    unsigned long W[68];
    unsigned long W1[64];

    //if CPU uses little-endian, BigEndian function is a necessary call
    BigEndian(md->buf, 64, md->buf);

    BiToW((unsigned long *)md->buf, W);
    WToW1(W, W1);
    CF(W, W1, md->state);
}

/******************************************************************************
  Function:       SM3_process
  Description:    compress the first (len/64) blocks of message
  Calls:          SM3_compress
  Called By:      SM3_256
  Input:          SM3_STATE *md
                  unsigned char buf[len]  //the input message
                  int len                 //bytelen of message
  Output:         SM3_STATE *md
  Return:         null
  Others:
*******************************************************************************/
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_done
  Description:    compress the rest message that the SM3_process has left behind
  Calls:          SM3_compress
  Called By:      SM3_256
  Input:          SM3_STATE *md
  Output:         unsigned char *hash
  Return:         null
  Others:
*******************************************************************************/
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 till
       it reaches 64 bytes, compress the current block, creat a new
       block 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_256
  Description:    calculate a hash value from a given message
  Calls:          SM3_init
                  SM3_process
                  SM3_done
  Called By:
  Input:          unsigned char buf[len]  //the input message
                  int len                 //bytelen of the message
  Output:         unsigned char hash[32]
  Return:         null
  Others:
*******************************************************************************/
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_KDF
  Description:    key derivation function
  Calls:          SM3_init
                  SM3_process
                  SM3_done
  Called By:
  Input:          unsigned char Z[zlen]
                  unsigned short zlen          //bytelen of Z
                  unsigned short klen          //bytelen of K
  Output:         unsigned char K[klen]        //shared secret key
  Return:         null
  Others:
*******************************************************************************/
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;
    else
        t = 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]++;
                }
                else
                    ct[1]++;
            }
            else
                ct[2]++;
        }
        else
            ct[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.h
  Version:
  Date:         Dec 15,2016
  Description:  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 pairing
  Function List:
        1.zzn2_pow                //regular zzn2 powering
        2.set_frobenius_constant  //calculate frobenius_constant X
        3.q_power_frobenius
        4.line
        5.g
        6.fast_pairing
        7.ecap

 Notes:
**************************************************************************/

#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_frobenius
  Description:    F is frobenius_constant X
                  see ake12bnx.cpp for details in MIRACL c++ source file
  Calls:          MIRACL functions
  Called By:      fast_pairing
  Input:          ecn2 A,zzn2 F
  Output:         zzn2 A
  Return:         NULL
  Others:
****************************************************************/
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=F
    if (get_mip()->TWIST == MR_SEXTIC_M)
        zzn2_inv(&r);     // could be precalculated
    zzn2_mul(&r, &r, &w); //w=r*r
    zzn2_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_pow
  Description:    regular zzn2 powering
                  see zzn2.cpp for details in MIRACL c++ source file
  Calls:          MIRACL functions
  Called By:      set_frobenius_constant
  Input:          zzn2 x,big k
  Output:         null
  Return:         zzn2
  Others:
****************************************************************/
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 windowing
    zzn2_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 windows
    zzn2_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 RAM
            n = 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_pairing
  Description:    R-ate Pairing G2 x G1 -> GT
                  P 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 Fp
                  see ake12bnx.cpp for details in MIRACL c++ source file
  Calls:          MIRACL functions,zzn12_init,g,q_power_frobenius
                  zzn12_copy,zzn12_conj,zzn12_div,zzn12_powq,zzn12_inverse
  Called By:      ecap
  Input:          ecn2 P,big Qx,big Qy,big x,zzn2 X
  Output:         zzn12 *r
  Return:         FALSE: r=0
                  TRUE: correct calculation
  Others:
****************************************************************/
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<0
        negify(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 loop
    res.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 Naehrig
    ecn2_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 exponentiation
    zzn12_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. Kachisa
    zzn12_copy(&res, &t0);
    zzn12_powq(X, &t0);
    zzn12_copy(&t0, &x0);
    zzn12_powq(X, &x0); //x0=t0

    zzn12_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=t0
    zzn12_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:       line
  Description:    Line from A to destination C. Let A=(x,y)
                  Line Y-slope.X-c=0, through A, so intercept c=y-slope.x
                  Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0
                  Now evaluate at Q -> return (Qy-y)-slope.(Qx-x)
                  see ake12bnx.cpp for details in MIRACL c++ source file
  Calls:          MIRACL functions,zzn12_init
  Called By:      g
  Input:          ecn2 A,ecn2 *C,ecn2 *B,zzn2 slope,zzn2 extra,BOOL Doubling,big Qx,big Qy
  Output:
  Return:         zzn12
  Others:
****************************************************************/
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-extra
        zzn2_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 simplify
            zzn2_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*Z
        ecn2_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:       g
  Description:    Add A=A+B  (or A=A+A),Return line function value
                  see ake12bnx.cpp for details in MIRACL c++ source file
  Calls:          MIRACL functions,zzn12_init,line
  Called By:
  Input:          ecn2 *A,ecn2 *B,big Qx,big Qy
  Output:
  Return:         zzn12
  Others:
****************************************************************/
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;
    }
    else
        res = line(P, A, B, lam, extra, Doubling, Qx, Qy);
    return res;
}

/****************************************************************
  Function:       set_frobenius_constant
  Description:    calculate frobenius_constant X
                  see ake12bnx.cpp for details in MIRACL c++ source file
  Calls:          MIRACL functions,zzn2_pow
  Called By:      SM9_init
  Input:          NULL
  Output:         zzn2 *X
  Return:         NULL
  Others:
****************************************************************/
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)/2
        break;
    case 3:
        zzn2_from_bigs(one, one, X); // = (1+sqrt(-1))^(p-1)/2
        break;
    case 7:
        zzn2_from_bigs(two, one, X); // = (2+sqrt(-1))^(p-1)/2
    default:
        break;
    }

    decr(p, 1, p);
    subdiv(p, 6, p);

    *X = zzn2_pow(*X, p);
}

/****************************************************************
  Function:       ecap
  Description:    caculate Rate pairing
                  see ake12bnx.cpp for details in MIRACL c++ source file
  Calls:          MIRACL functions,fast_pairing
  Called By:      SM9_Sign,SM9_Verify
  Input:          ecn2 P,epoint *Q,big x,zzn2 X
  Output:         zzn12 *r
  Return:         FALSE: calculation error
                  TRUE: correct calculation
  Others:
****************************************************************/
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:       member
  Description:    ctest if a zzn12 element is of order q
                  test r^q = r^(p+1-t) =1, so test r^p=r^(t-1)
                  see ake12bnx.cpp for details in MIRACL c++ source file
  Calls:          MIRACL functions,zzn12_init,zzn12_copy,zzn12_powq
  Called By:      SM9_Sign,SM9_Verify
  Input:          zzn12 r,big x,zzn2 F
  Output:         NULL
  Return:         FALSE: zzn12 element is not of order q
                  TRUE: zzn12 element is of order q
  Others:
****************************************************************/
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=r
    zzn12_powq(F, &w);
    r = zzn12_pow(r, x);
    r = zzn12_pow(r, x);
    r = zzn12_pow(r, six); // t-1=6x^2
    if (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.h
  Version:
  Date:         Dec 15,2016
  Description:  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 zzn12
        2.zzn12_copy           //copy one zzn12 to another
        3.zzn12_mul            //z=x*y,achieve multiplication with two zzn12
        4.zzn12_conj           //achieve conjugate complex
        5.zzn12_inverse        //element inversion
        6.zzn12_powq           //
        7.zzn12_div            //division operation
        8.zzn12_pow            //regular zzn12 powering

 Notes:
**************************************************************************/

#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 conjugates
  BOOL 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_init
  Description:    Initiate struct zzn12
  Calls:          MIRACL functions
  Called By:
  Input:          zzn12 *x
  Output:         null
  Return:         null
  Others:
****************************************************************/
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_copy
  Description:    copy y=x
  Calls:          MIRACL functions
  Called By:
  Input:          zzn12 *x
  Output:         zzn12 *y
  Return:         null
  Others:
****************************************************************/
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_mul
  Description:    z=x*y,see zzn12a.h and zzn12a.cpp for details in MIRACL c++ source file
  Calls:          MIRACL functions
  Called By:
  Input:          zzn12 x,y
  Output:         zzn12 *z
  Return:         null
  Others:
****************************************************************/
zzn12_mul(zzn12 x, zzn12 y, zzn12 *z)
{
    // Karatsuba
    zzn4 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 SQR2
                zzn4_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    = S0
                zzn4_copy(&x.c, &Z2);
                zzn4_mul(&Z2, &x.b, &Z2);
                zzn4_add(&Z2, &Z2, &Z2); // 2a1.a2  = S3
                zzn4_copy(&x.c, &Z3);
                zzn4_mul(&Z3, &Z3, &Z3);
                ;                            // a2^2    = S4
                zzn4_add(&x.c, &x.a, &z->c); // a0+a2

                zzn4_copy(&x.b, &Z1);
                zzn4_add(&Z1, &z->c, &Z1);
                zzn4_mul(&Z1, &Z1, &Z1); // (a0+a1+a2)^2  =S1
                zzn4_sub(&z->c, &x.b, &z->c);
                zzn4_mul(&z->c, &z->c, &z->c); // (a0-a1+a2)^2  =S2
                zzn4_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
    {
        // Karatsuba
        zero_b = zzn4_iszero(&y.b);
        zero_c = zzn4_iszero(&y.c);

        zzn4_mul(&x.a, &y.a, &Z0); //9
        if (!zero_b)
            zzn4_mul(&x.b, &y.b, &Z2); //+6

        zzn4_add(&x.a, &x.b, &T0);
        zzn4_add(&y.a, &y.b, &T1);
        zzn4_mul(&T0, &T1, &Z1); //+9
        zzn4_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); //+6
        if (!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);
        else
            zzn4_copy(&T0, &Z2);
        zzn4_sub(&Z2, &Z0, &Z2);

        zzn4_copy(&Z1, &z->b);
        if (!zero_c)
        { // exploit special form of BN curve line function
            zzn4_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_conj
  Description:    achieve conjugate complex
                  see zzn12a.h and zzn1212.cpp for details in MIRACL c++ source file
  Calls:          MIRACL functions
  Called By:
  Input:          zzn12 x,y
  Output:         zzn12 *z
  Return:         null
  Others:
****************************************************************/
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_inverse
  Description:    element inversion,
                  see zzn12a.h and zzn1212.cpp for details in MIRACL c++ source file
  Calls:          MIRACL functions,zzn12_init,zzn12_conj
  Called By:
  Input:          zzn12 w
  Output:
  Return:         zzn12
  Others:
****************************************************************/
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_powq
  Description:    Frobenius F=x^p. Assumes p=1 mod 6
                  see zzn12a.h and zzn1212.cpp for details in MIRACL c++ source file
  Calls:          MIRACL functions
  Called By:
  Input:          zzn2 F
  Output:         zzn12 *y
  Return:         NULL
  Others:
****************************************************************/
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_div
  Description:    z=x/y
                  see zzn12a.h and zzn1212.cpp for details in MIRACL c++ source file
  Calls:          MIRACL functions,zzn12_inverse,zzn12_mul
  Called By:
  Input:          zzn12 x,y
  Output:         zzn12 *z
  Return:         NULL
  Others:
****************************************************************/
void zzn12_div(zzn12 x, zzn12 y, zzn12 *z)
{
    y = zzn12_inverse(y);
    zzn12_mul(x, y, z);
}

/****************************************************************
  Function:       zzn12_pow
  Description:    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 file
  Calls:          MIRACL functions,zzn12_inverse,zzn12_mul,zzn12_copy,zzn12_init
  Called By:
  Input:          zzn12 x,big k
  Output:
  Return:         zzn12
  Others:
****************************************************************/
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 
#include 
#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 constant

unsigned 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_ecn2
  Description:    convert 128 bytes into ecn2
  Calls:          MIRACL functions
  Called By:      SM9_Init
  Input:          Ppubs[]
  Output:         ecn2 *res
  Return:         FALSE: execution error
                  TRUE: execute correctly
  Others:
****************************************************************/
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_ElementPrint
  Description:    print all element of struct zzn12
  Calls:          MIRACL functions
  Called By:      SM9_Sign,SM9_Verify
  Input:          zzn12 x
  Output:         NULL
  Return:         NULL
  Others:
****************************************************************/
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_Print
  Description:    print 128 bytes of ecn2
  Calls:          MIRACL functions
  Called By:      SM9_Sign,SM9_Verify
  Input:          ecn2 x
  Output:         NULL
  Return:         NULL
  Others:
****************************************************************/
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:       LinkCharZzn12
  Description:    link two different types(unsigned char and zzn12)to one(unsigned char)
  Calls:          MIRACL functions
  Called By:      SM9_Sign,SM9_Verify
  Input:          message:
                  len:    length of message
                  w:      zzn12 element
  Output:         Z:      the characters array stored message and w
                  Zlen:   length of Z
  Return:         NULL
  Others:
****************************************************************/
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_Point
  Description:    test if the given point is on SM9 curve
  Calls:
  Called By:      SM9_Verify
  Input:          point
  Output:         null
  Return:         0: success
                  1: not a valid point on curve

  Others:
****************************************************************/
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+b
  epoint_get(point, x, y);
  power(x, 3, para_q, x_3); //x_3=x^3 mod p
  multiply(x, para_a, x);
  divide(x, para_q, tmp);
  add(x_3, x, x); //x=x^3+ax+b
  add(x, para_b, x);
  divide(x, para_q, tmp); //x=x^3+ax+b mod p
  power(y, 2, para_q, y); //y=y^2 mod p
  if (mr_compare(x, y) != 0)
    return 1;

  //test infinity
  ecurve_mult(N, point, buf);
  if (point_at_infinity(buf) == FALSE)
    return 1;

  return 0;
}

/****************************************************************
  Function:       Test_Range
  Description:    test if the big x belong to the range[1,n-1]
  Calls:
  Called By:      SM9_Verify
  Input:          big x    ///a miracl data type
  Output:         null
  Return:         0: success
                  1: x==n,fail
  Others:
****************************************************************/
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_Init
  Description:    Initiate SM9 curve
  Calls:          MIRACL functions
  Called By:      SM9_SelfCheck
  Input:          null
  Output:         null
  Return:         0: success;
                  7: base point P1 error
                  8: base point P2 error
  Others:
****************************************************************/
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 coordinates

  if (!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_H1
  Description:    function H1 in SM9 standard 5.4.2.2
  Calls:          MIRACL functions,SM3_KDF
  Called By:      SM9_Verify
  Input:          Z:
                  Zlen:the length of Z
                  n:Frobniues constant X
  Output:         h1=H1(Z,Zlen)
  Return:         0: success;
                  1: asking for memory error
  Others:
****************************************************************/
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_H2
  Description:    function H2 in SM9 standard 5.4.2.3
  Calls:          MIRACL functions,SM3_KDF
  Called By:      SM9_Sign,SM9_Verify
  Input:          Z:
                  Zlen:the length of Z
                  n:Frobniues constant X
  Output:         h2=H2(Z,Zlen)
  Return:         0: success;
                  1: asking for memory error
  Others:
****************************************************************/
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_GenerateSignKey
  Description:    Generate Signed key
  Calls:          MIRACL functions,SM9_H1,xgcd,ecn2_Bytes128_Print
  Called By:      SM9_SelfCheck
  Input:          hid:0x01
                  ID:identification
                  IDlen:the length of ID
                  ks:master private key used to generate signature public key and private key
  Output:         Ppub:signature public key
                  dSA: signature private key
  Return:         0: success;
                  1: asking for memory error
  Others:
****************************************************************/
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)+ks
  xgcd(t1, N, t1, t1, t1); //t1=t1(-1)
  multiply(ks, t1, t2);
  divide(t2, N, rem); //t2=ks*t1(-1)

  //dSA=[t2]P1
  ecurve_mult(t2, P1, dSA);

  //Ppub=[ks]P2
  ecn2_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_Sign
  Description:    SM9 signature algorithm
  Calls:          MIRACL functions,zzn12_init(),ecap(),member(),zzn12_ElementPrint(),
                  zzn12_pow(),LinkCharZzn12(),SM9_H2()
  Called By:      SM9_SelfCheck()
  Input:
                  hid:0x01
                  IDA          //identification of userA
                  message      //the message to be signed
                  len          //the length of message
                  rand         //a random number K lies in [1,N-1]
                  dSA          //signature private key
                  Ppubs        //signature public key

  Output:         H,S        //signature result
  Return:         0: success
                  1: asking for memory error
                  4: element is out of order q
                  5: R-ate calculation error
                  9: parameter L error
  Others:
****************************************************************/
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;

  //initiate
  h1 = 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 q
  if (!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 N
  subtract(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_Verify
  Description:    SM9 signature verification algorithm
  Calls:          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 verified
                  hid          //identification
                  IDA          //identification of userA
                  message      //the message to be signed
                  len          //the length of message
                  Ppubs        //signature public key

  Output:         NULL
  Return:         0: success
                  1: asking for memory error
                  2: H is not in the range[1,N-1]
                  6: S is not on the SM9 curve
                  4: element is out of order q
                  5: R-ate calculation error
                  3: h2!=h,comparison error
  Others:
****************************************************************/
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 G1
  epoint_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 q
  if (!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+Ppubs
  ecn2_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 q
  if (!member(u, para_t, X))
    return SM9_MEMBER_ERR;
  printf("\n************************** u=e(S1,P): *****************************\n");
  zzn12_ElementPrint(u);

  //Step8:w=u*t
  zzn12_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_SelfCheck
  Description:    SM9 self check
  Calls:          MIRACL functions,SM9_Init(),SM9_GenerateSignKey(),
                  SM9_Sign,SM9_Verify
  Called By:
  Input:
  Output:
  Return:         0: self-check success
                  1: asking for memory error
                  2: H is not in the range[1,N-1]
                  3: h2!=h,comparison error
                  4: element is out of order q
                  5: R-ate calculation error
                  6: S is not on the SM9 curve
                  7: base point P1 error
                  8: base point P2 error
                  9: parameter L error
                  A: public key generated error
                  B: private key generated error
                  C: signature result error
  Others:
****************************************************************/
int SM9_SelfCheck()
{
  //the master private key
  unsigned 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]; // Signature
  unsigned 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 signed
  int mlen = strlen(message), tmp;                 //the length of message
  big 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 
#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张图片

 

记录 Windows 下编译一个开源 SM9 签名验签 C 程序的过程_第2张图片

你可能感兴趣的:(MIRACL,密码学与信息安全)