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

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

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

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

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

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

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

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

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

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

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

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

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

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

文章目录

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

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

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

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

错误异常处理

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

// Errors.h
#ifndef YY_SM9_ERROR_INCLUDE_H__
#define YY_SM9_ERROR_INCLUDE_H__

#pragma once

#include 
using namespace std;

#define SM9_OK									0x00000000
#define SM9_ERROR_NOT_INIT						0x00000001
#define SM9_ERROR_INIT_G1BASEPOINT				0x00000002
#define SM9_ERROR_INIT_G2BASEPOINT				0x00000003
#define SM9_ERROR_CALC_RATE						0x00000004
#define SM9_ERROR_KGC_GENPRIKEY_T1_IS_ZERO		0x00000005
#define SM9_ERROR_KGC_WRONG_PRIKEY_TYPE			0x00000006
#define SM9_ERROR_VERIFY_H_OUTRANGE				0x00000007
#define SM9_ERROR_VERIFY_S_NOT_ON_G1			0x00000008
#define SM9_ERROR_VERIFY_H_VERIFY_FAILED		0x00000009
#define SM9_ERROR_DECAP_C_NOT_ON_G1				0x0000000A
#define SM9_ERROR_DECAP_K_IS_ZERO				0x0000000B
#define SM9_ERROR_DECRYPT_C1_NOT_ON_G1			0x0000000C
#define SM9_ERROR_DECRYPT_K1_IS_ZERO			0x0000000D
#define SM9_ERROR_DECRYPT_C3_VERIFY_FAILED		0x0000000E
#define SM9_ERROR_KEYEXCHANGE_R_NOT_ON_G1		0x0000000F



/**
* 错误值类.
* @author YaoYuan
*/
class Errors {
private:
	Errors() {}
	~Errors() {}

public:
	static string getErrorMsg(int errnum) {
		string msg = "Unknown error";
		switch( errnum )
		{
			case SM9_OK:
				msg = "Success";
				break;
			case SM9_ERROR_NOT_INIT:
				msg = "Not init";
				break;
			case SM9_ERROR_INIT_G1BASEPOINT:
				msg = "G1 init error";
				break;
			case SM9_ERROR_INIT_G2BASEPOINT:
				msg = "G2 init error";
				break;
			case SM9_ERROR_CALC_RATE:
				msg = "R-ate result is not of order q";
				break;
			case SM9_ERROR_VERIFY_H_OUTRANGE:
				msg = "Verify : h is out range";
				break;
			case SM9_ERROR_VERIFY_S_NOT_ON_G1:
				msg = "Verify : s is not on G1";
				break;
			case SM9_ERROR_VERIFY_H_VERIFY_FAILED:
				msg = "Verify failed, h verify failed";
				break;
			case SM9_ERROR_DECAP_C_NOT_ON_G1:
				msg = "Decapsulate : C is not on G1";
				break;
			case SM9_ERROR_DECAP_K_IS_ZERO:
				msg = "Decapsulate : K is zero";
				break;
			case SM9_ERROR_DECRYPT_C1_NOT_ON_G1:
				msg = "Decrypt : C1 is not on G1";
				break;
			case SM9_ERROR_DECRYPT_K1_IS_ZERO:
				msg = "Decrypt : K is zero";
				break;
			case SM9_ERROR_DECRYPT_C3_VERIFY_FAILED:
				msg = "Decrypt : C3 verify failed";
				break;
			case SM9_ERROR_KEYEXCHANGE_R_NOT_ON_G1:
				msg = "Key Exchange : R not on G1";
				break;
			case SM9_ERROR_KGC_GENPRIKEY_T1_IS_ZERO:
				msg = "t1 is zero while KGC generate private key";
				break;
			case SM9_ERROR_KGC_WRONG_PRIKEY_TYPE:
				msg = "Wrong private key type for generate private key";
				break;
			default:
				break;
		}

		return msg;
	}
};


#endif

数学功能

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

群G1倍点计算

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

群G2倍点计算

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

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

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

参数初始化

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

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

Parameters类的内容如下:

Parameters.h

// Parameters.h
#ifndef YY_SM9_Parameters_INCLUDE_H__
#define YY_SM9_Parameters_INCLUDE_H__

#pragma once

#include 
using namespace std;

#ifdef __cplusplus
extern "C" {
#include "miracl/miracl.h"
}
#endif


#define BIG_LEN 2000
#define SELF_CHECK 1

class Parameters {
private:
	Parameters();
	~Parameters();

public:
	static bool init();
	static void release();

	static void init_big(big& var);
	static void release_big(big& var);

	static void init_zzn2(zzn2& var);
	static void release_zzn2(zzn2& var);

	static void init_zzn4(zzn4& var);
	static void release_zzn4(zzn4& var);

	static void init_ecn2(ecn2& var);
	static void release_ecn2(ecn2& var);

	static void init_epoint(epoint*& var);
	static void release_epoint(epoint* var);

public:
	static string cout_big(big& var);
	static void cin_big(big& var, const unsigned char* buf, int length);
	static void cin_big(big& var, const char* buf, int length) { cin_big(var, (const unsigned char*)buf, length); }

	static string cout_ecn2(ecn2& var);
	static bool cin_ecn2_byte128(ecn2& var, const char* buf);

	static string cout_epoint(epoint* var);
	static void cin_epoint(epoint* var, const char* buf);

public:
	static bool isPointOnG1(epoint* var);

private:
	static void setFrobeniusNormCconstant();
	static void zzn2_pow(zzn2& x, big& k, zzn2& r); // r=x^k
	static string cout_ecn2_big(big& var);

public:
	static int getErrorNum() noexcept { return mErrorNum; }

private:
	static int mErrorNum;
public:
	static const int BNLEN;

public:
	static big param_a;
	static big param_b;
	static big param_N;
	static big param_q;
	static big param_t;
	static epoint* param_P1;
	static ecn2 param_P2;
	static zzn2 norm_X; //Frobenius norm constant
	static miracl* mMip;
};

#endif

Parameters.cpp

// Parameters.cpp
#include "Parameters.h"
#include "Errors.h"
#include 

#ifdef _WIN32
#ifdef _DEBUG
#pragma comment(lib, "miracld.lib")
#else
#pragma comment(lib, "miracl.lib")
#endif
#endif

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
};

int Parameters::mErrorNum = SM9_OK;
const int Parameters::BNLEN = 32;
big Parameters::param_N = NULL;
big Parameters::param_a = NULL;
big Parameters::param_b = NULL;
big Parameters::param_q = NULL;
big Parameters::param_t = NULL;
epoint* Parameters::param_P1 = NULL;
ecn2 Parameters::param_P2;
zzn2 Parameters::norm_X;
miracl* Parameters::mMip = NULL;

Parameters::Parameters()
{
	
}

Parameters::~Parameters()
{

}

void Parameters::setFrobeniusNormCconstant()
{
	big p, zero, one, two;
	zzn2 tmp_norm_X;

	init_big(p);
	init_big(zero);
	init_big(one);
	init_big(two);
	init_zzn2(tmp_norm_X);

	convert(0, zero);
	convert(1, one);
	convert(2, two);
	copy(mMip->modulus, p);
	switch( get_mip()->pmod8 )
	{
		case 5:
			zzn2_from_bigs(zero, one, &tmp_norm_X);// = (sqrt(-2)^(p-1)/2
			break;
		case 3:
			zzn2_from_bigs(one, one, &tmp_norm_X); // = (1+sqrt(-1))^(p-1)/2
			break;
		case 7:
			zzn2_from_bigs(two, one, &tmp_norm_X);// = (2+sqrt(-1))^(p-1)/2
		default: break;
	}
	decr(p, 1, p);
	subdiv(p, 6, p);
	zzn2_pow(tmp_norm_X, p, norm_X);

	release_big(p);
	release_big(zero);
	release_big(one);
	release_big(two);
	release_zzn2(tmp_norm_X);
}

bool Parameters::init()
{
	bool result = false;
	big P1_x = NULL;
	big P1_y = NULL; 
	BOOL br = FALSE;

	mMip = mirsys(BIG_LEN, 16);
	mMip->IOBASE = 16;
	mMip->TWIST = MR_SEXTIC_M;

	// Initialize random seed
	std::random_device rd;
	std::default_random_engine mGenerator;
	std::uniform_int_distribution mDistribute(0, UINT_MAX);
	mGenerator.seed(rd());
	irand(mDistribute(mGenerator));

	init_big(P1_x); 
	init_big(P1_y);

	init_big(param_N);
	init_big(param_a);
	init_big(param_b);
	init_big(param_q);
	init_big(param_t);
	init_epoint(param_P1);
	init_ecn2(param_P2);
	init_zzn2(norm_X);

	cin_big(param_N, (char*)SM9_N, sizeof(SM9_N));
	cin_big(param_a, (char*)SM9_a, sizeof(SM9_a));
	cin_big(param_b, (char*)SM9_b, sizeof(SM9_b));
	cin_big(param_q, (char*)SM9_q, sizeof(SM9_q));
	cin_big(param_t, (char*)SM9_t, sizeof(SM9_t));

	//Initialize GF(q) elliptic curve, MR_PROJECTIVE specifying projective coordinates
	ecurve_init(param_a, param_b, param_q, MR_PROJECTIVE); 

	cin_big(P1_x, (char*)SM9_P1x, sizeof(SM9_P1x));
	cin_big(P1_y, (char*)SM9_P1y, sizeof(SM9_P1y));

	br = epoint_set(P1_x, P1_y, 0, param_P1);
	result = br ? true : false;
	if( result ) {
		result = cin_ecn2_byte128(param_P2, (const char*)SM9_P2);
		if( !result ) {
			mErrorNum = SM9_ERROR_INIT_G2BASEPOINT;
			goto END;
		}
	} else {
		mErrorNum = SM9_ERROR_INIT_G1BASEPOINT;
		goto END;
	}

	setFrobeniusNormCconstant();

	result = true;

END:
	release_big(P1_x);
	release_big(P1_y);

	if( !result ) {
		release();
	}

	return result;
}

void Parameters::release()
{
	mirkill(param_N);
	mirkill(param_a);
	mirkill(param_b);
	mirkill(param_q);
	mirkill(param_t);
	release_epoint(param_P1);
	release_ecn2(param_P2);
	release_zzn2(norm_X);
	mirexit();
	mErrorNum = SM9_OK;
}

void Parameters::init_big(big& var)
{
	var = mirvar(0);
}

void Parameters::release_big(big& var)
{
	mirkill(var);
}

void Parameters::init_zzn2(zzn2& var)
{
	var.a = mirvar(0);
	var.b = mirvar(0);
}

void Parameters::release_zzn2(zzn2& var)
{
	mirkill(var.a);
	mirkill(var.b);
}

void Parameters::init_zzn4(zzn4& var)
{
	var.a.a = mirvar(0);
	var.a.b = mirvar(0);
	var.b.a = mirvar(0);
	var.b.b = mirvar(0);
	var.unitary = FALSE;
}

void Parameters::release_zzn4(zzn4& var)
{
	mirkill(var.a.a);
	mirkill(var.a.b);
	mirkill(var.b.a);
	mirkill(var.b.b);
}

void Parameters::init_ecn2(ecn2& var)
{
	var.x.a = mirvar(0); var.x.b = mirvar(0); 
	var.y.a = mirvar(0); var.y.b = mirvar(0);
	var.z.a = mirvar(0); var.z.b = mirvar(0); 
	var.marker = MR_EPOINT_INFINITY;
}

void Parameters::release_ecn2(ecn2& var)
{
	mirkill(var.x.a); mirkill(var.x.b);
	mirkill(var.y.a); mirkill(var.y.b);
	mirkill(var.z.a); mirkill(var.z.b);
}

void Parameters::init_epoint(epoint*& var)
{
	var = epoint_init();
}

void Parameters::release_epoint(epoint* var)
{
	epoint_free(var);
}

bool Parameters::cin_ecn2_byte128(ecn2& var, const char* buf)
{
	ecn2 r;
	zzn2 x, y;
	big a=NULL, b=NULL;
	
	init_ecn2(r);
	init_zzn2(x);
	init_zzn2(y);
	init_big(a);
	init_big(b);

	bytes_to_big(BNLEN, (char*)buf, b);
	bytes_to_big(BNLEN, (char*)buf + BNLEN, a);
	zzn2_from_bigs(a, b, &x);
	bytes_to_big(BNLEN, (char*)buf + BNLEN * 2, b);
	bytes_to_big(BNLEN, (char*)buf + BNLEN * 3, a);
	zzn2_from_bigs(a, b, &y);
	BOOL ret = ecn2_set(&x, &y, &r);
	if(ret) ecn2_copy(&r, &var);

	release_ecn2(r);
	release_zzn2(x);
	release_zzn2(y);
	release_big(a);
	release_big(b);

	return ret ? true : false;
}

string Parameters::cout_ecn2_big(big& var)
{
	big tmp = NULL;
	init_big(tmp);
	redc(var, tmp);

	int length = tmp->len * sizeof(tmp->w);
	char *buffer = new char[length];
	int ret = big_to_bytes(length, tmp, buffer, TRUE);
	string result(buffer, ret);

	delete[] buffer;
	release_big(tmp);
	return result;
}

string Parameters::cout_ecn2(ecn2& var)
{
	string result;
	result.append(cout_ecn2_big(var.x.b));
	result.append(cout_ecn2_big(var.x.a));
	result.append(cout_ecn2_big(var.y.b));
	result.append(cout_ecn2_big(var.y.a));
	return result;
}

void Parameters::cin_big(big& var, const unsigned char* buf, int length)
{
	bytes_to_big(length, (const char*)buf, var);
}

std::string Parameters::cout_epoint(epoint* var)
{
	big x = NULL;
	big y = NULL;
	string result;

	init_big(x);
	init_big(y);

	epoint_get(var, x, y);

	result.append(cout_big(x));
	result.append(cout_big(y));

	release_big(x);
	release_big(y);
	return result;
}

void Parameters::cin_epoint(epoint* var, const char* buf)
{
	big x = NULL;
	big y = NULL;

	init_big(x);
	init_big(y);

	cin_big(x, buf, BNLEN);
	cin_big(y, buf+BNLEN, BNLEN);
	epoint_set(x, y, 0, var);

	release_big(x);
	release_big(y);
}

string Parameters::cout_big(big& var)
{
	int length = var->len * sizeof(var->w);
	char *buffer = new char[length];
	int ret = big_to_bytes(length, var, buffer, FALSE);
	string result(buffer, ret);

	delete[] buffer;
	return result;
}

bool Parameters::isPointOnG1(epoint* var)
{
	bool result = false;
	big x = NULL;
	big y = NULL;
	big x_3 = NULL;
	big tmp = NULL;
	epoint* buf = NULL;

	init_big(x);
	init_big(y);
	init_big(x_3);
	init_big(tmp);
	init_epoint(buf);

	//check y^2=x^3+b
	epoint_get(var, x, y);
	power(x, 3, param_q, x_3); //x_3=x^3 mod p
	multiply(x, param_a, x);
	divide(x, param_q, tmp);
	add(x_3, x, x); //x=x^3+ax+b
	add(x, param_b, x);
	divide(x, param_q, tmp); //x=x^3+ax+b mod p
	power(y, 2, param_q, y); //y=y^2 mod p
	if( mr_compare(x, y) != 0 )
		return 1;

	//check infinity
	ecurve_mult(param_N, var, buf);
	if( point_at_infinity(buf) == TRUE )
		result = true;

	release_big(x);
	release_big(y);
	release_big(x_3);
	release_big(tmp);
	release_epoint(buf);

	return result;
}

void Parameters::zzn2_pow(zzn2& x, big& k, zzn2& r)
{
	int i, j, nb, n, nbw, nzs;
	big zero;
	zzn2 u2, t[16];

	init_big(zero);
	init_zzn2(u2);	
	for( i = 0; i < 16; i++ )
	{
		init_zzn2(t[i]);
	}

	if( zzn2_iszero(&x) )
	{
		zzn2_zero(&r);
		goto END;
	}
	if( size(k) == 0 )
	{
		zzn2_from_int(1, &r);
		goto END;
	}
	if( size(k) == 1 ) {
		zzn2_copy(&x, &r);
		goto END;
	}

	// Prepare table for windowing
	zzn2_mul(&x, &x, &u2);
	zzn2_copy(&x, &t[0]);
	for( i = 1; i < 16; i++ )
	{
		zzn2_mul(&t[i - 1], &u2, &t[i]);
	}
	// Left to right method - with windows
	zzn2_copy(&x, &r);
	nb = logb2(k);
	if( nb > 1 ) for( i = nb - 2; i >= 0;)
	{
		//Note new parameter of window_size=5. Default to 5, but reduce to 4 (or even 3) to save RAM
		n = mr_window(k, i, &nbw, &nzs, 5);
		for( j = 0; j < nbw; j++ ) zzn2_mul(&r, &r, &r);
		if( n > 0 ) zzn2_mul(&r, &t[n / 2], &r);
		i -= nbw;
		if( nzs )
		{
			for( j = 0; j < nzs; j++ ) zzn2_mul(&r, &r, &r);
			i -= nzs;
		}
	}

END:
	release_big(zero);
	release_zzn2(u2);
	for( i = 0; i < 16; i++ ) {
		release_zzn2(t[i]);
	}
}

双线性对计算

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

zzn12.h


#ifndef YY_SM9_ZZN12_INCLUDE_H__
#define YY_SM9_ZZN12_INCLUDE_H__

#pragma once 

#include 
using namespace std;

#ifdef __cplusplus
extern "C" {
#include "miracl/miracl.h"
}
#endif


class ZZN12 {
public:
	ZZN12();
	ZZN12(const ZZN12& var);
	ZZN12& operator=(const ZZN12& var);
	~ZZN12();

public:
	string toByteArray();

public:
	ZZN12 mul(ZZN12& var); // return this*var
	ZZN12 conj();
	ZZN12 inverse();
	ZZN12 powq(zzn2& var);
	ZZN12 div(ZZN12& var); // return this/y
	ZZN12 pow(big k); // return this^k
	bool isOrderQ(); 

// pairing
public:
	static void q_power_frobenius(ecn2 A, zzn2 F);
	static ZZN12 line(ecn2 A, ecn2 *C, ecn2 *B, zzn2 slope, zzn2 extra, BOOL Doubling, big Qx, big Qy);
	static ZZN12 g(ecn2 *A, ecn2 *B, big Qx, big Qy);
	static bool fast_pairing(ZZN12& ret, ecn2 P, big Qx, big Qy, big x, zzn2 X);
	static bool calcRatePairing(ZZN12& ret, ecn2 P, epoint *Q, big x, zzn2 X);
	

private:
	void init();
	void release();
	string cout_zzn12_big(big& var);

private:
	zzn4 a, b, c;
	BOOL unitary; // "unitary property means that fast squaring can be used, and inversions are just 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).
};

#endif

zzn12.cpp


#include "zzn12.h"
#include "Parameters.h"


ZZN12::ZZN12()
{
	init();
}

ZZN12::ZZN12(const ZZN12& var)
{
	init();
	zzn4_copy((zzn4*)&var.a, &a); 
	zzn4_copy((zzn4*)&var.b, &b); 
	zzn4_copy((zzn4*)&var.c, &c);
	miller = var.miller;
	unitary = var.unitary;
}

ZZN12& ZZN12::operator=(const ZZN12& var)
{
	zzn4_copy((zzn4*)&var.a, &a);
	zzn4_copy((zzn4*)&var.b, &b);
	zzn4_copy((zzn4*)&var.c, &c);
	miller = var.miller;
	unitary = var.unitary;
	return *this;
}

ZZN12::~ZZN12()
{
	release();
}


void ZZN12::init()
{
	a.a.a = mirvar(0); a.a.b = mirvar(0);
	a.b.a = mirvar(0); a.b.b = mirvar(0); a.unitary = FALSE;
	b.a.a = mirvar(0); b.a.b = mirvar(0);
	b.b.a = mirvar(0); b.b.b = mirvar(0); b.unitary = FALSE;
	c.a.a = mirvar(0); c.a.b = mirvar(0);
	c.b.a = mirvar(0); c.b.b = mirvar(0); c.unitary = FALSE;
	unitary = FALSE; miller = FALSE;
}

void ZZN12::release()
{
	mirkill(a.a.a); mirkill(a.a.b);
	mirkill(a.b.a); mirkill(a.b.b);
	mirkill(b.a.a); mirkill(b.a.b);
	mirkill(b.b.a); mirkill(b.b.b);
	mirkill(c.a.a); mirkill(c.a.b);
	mirkill(c.b.a); mirkill(c.b.b);
}

std::string ZZN12::toByteArray()
{
	string result;
	result.append(cout_zzn12_big(c.b.b));
	result.append(cout_zzn12_big(c.b.a));
	result.append(cout_zzn12_big(c.a.b));
	result.append(cout_zzn12_big(c.a.a));
	result.append(cout_zzn12_big(b.b.b));
	result.append(cout_zzn12_big(b.b.a));
	result.append(cout_zzn12_big(b.a.b));
	result.append(cout_zzn12_big(b.a.a));
	result.append(cout_zzn12_big(a.b.b));
	result.append(cout_zzn12_big(a.b.a));
	result.append(cout_zzn12_big(a.a.b));
	result.append(cout_zzn12_big(a.a.a));
	return result;
}

string ZZN12::cout_zzn12_big(big& var)
{
	big tmp = NULL;
	tmp = mirvar(0);
	redc(var, tmp);

	int length = tmp->len * sizeof(tmp->w);
	char *buffer = new char[length];
	int ret = big_to_bytes(length, tmp, buffer, TRUE);
	string result(buffer, ret);

	delete[] buffer;
	mirkill(tmp);
	return result;
}

ZZN12 ZZN12::mul(ZZN12& var)
{
	// Karatsuba
	zzn4 Z0, Z1, Z2, Z3, T0, T1;
	ZZN12 ret(*this);
	BOOL zero_c, zero_b;

	Parameters::init_zzn4(Z0);
	Parameters::init_zzn4(Z1);
	Parameters::init_zzn4(Z2);
	Parameters::init_zzn4(Z3);
	Parameters::init_zzn4(T0);
	Parameters::init_zzn4(T1);

	if( zzn4_compare(&a, &var.a) && zzn4_compare(&a, &var.a) && zzn4_compare(&a, &var.a) )
	{
		if( unitary == TRUE )
		{
			zzn4_copy(&a, &Z0); zzn4_mul(&a, &a, &ret.a); zzn4_copy(&ret.a, &Z3); zzn4_add(&ret.a, &ret.a, &ret.a);
			zzn4_add(&ret.a, &Z3, &ret.a); zzn4_conj(&Z0, &Z0); zzn4_add(&Z0, &Z0, &Z0); zzn4_sub(&ret.a, &Z0, &ret.a);
			zzn4_copy(&c, &Z1); zzn4_mul(&Z1, &Z1, &Z1); zzn4_tx(&Z1);
			zzn4_copy(&Z1, &Z3); zzn4_add(&Z1, &Z1, &Z1); zzn4_add(&Z1, &Z3, &Z1);
			zzn4_copy(&b, &Z2); zzn4_mul(&Z2, &Z2, &Z2);
			zzn4_copy(&Z2, &Z3); zzn4_add(&Z2, &Z2, &Z2); zzn4_add(&Z2, &Z3, &Z2);
			zzn4_conj(&b, &ret.b); zzn4_add(&ret.b, &ret.b, &ret.b);
			zzn4_conj(&c, &ret.c); zzn4_add(&ret.c, &ret.c, &ret.c); zzn4_negate(&ret.c, &ret.c);
			zzn4_add(&ret.b, &Z1, &ret.b); zzn4_add(&ret.c, &Z2, &ret.c);
		} else
		{
			if( !miller )
			{// Chung-Hasan SQR2
				zzn4_copy(&a, &Z0); zzn4_mul(&Z0, &Z0, &Z0);
				zzn4_mul(&b, &c, &Z1); zzn4_add(&Z1, &Z1, &Z1);
				zzn4_copy(&c, &Z2); zzn4_mul(&Z2, &Z2, &Z2);
				zzn4_mul(&a, &b, &Z3); zzn4_add(&Z3, &Z3, &Z3);
				zzn4_add(&a, &b, &ret.c); zzn4_add(&ret.c, &c, &ret.c); zzn4_mul(&ret.c, &ret.c, &ret.c);
				zzn4_tx(&Z1); zzn4_add(&Z0, &Z1, &ret.a);
				zzn4_tx(&Z2); zzn4_add(&Z3, &Z2, &ret.b);
				zzn4_add(&Z0, &Z1, &T0); zzn4_add(&T0, &Z2, &T0);
				zzn4_add(&T0, &Z3, &T0); zzn4_sub(&ret.c, &T0, &ret.c);
			} else
			{// Chung-Hasan SQR3 - actually calculate 2x^2 !
			 // Slightly dangerous - but works as will be raised to p^{k/2}-1
			 // which wipes out the 2.
				zzn4_copy(&a, &Z0); zzn4_mul(&Z0, &Z0, &Z0);// a0^2 = S0
				zzn4_copy(&c, &Z2); zzn4_mul(&Z2, &b, &Z2); zzn4_add(&Z2, &Z2, &Z2); // 2a1.a2 = S3
				zzn4_copy(&c, &Z3); zzn4_mul(&Z3, &Z3, &Z3);; // a2^2 = S4
				zzn4_add(&c, &a, &ret.c); // a0+a2
				zzn4_copy(&b, &Z1); zzn4_add(&Z1, &ret.c, &Z1); zzn4_mul(&Z1, &Z1, &Z1);// (a0+a1+a2)^2 =S1
				zzn4_sub(&ret.c, &b, &ret.c); zzn4_mul(&ret.c, &ret.c, &ret.c);// (a0-a1+a2)^2 =S2
				zzn4_add(&Z2, &Z2, &Z2); zzn4_add(&Z0, &Z0, &Z0); zzn4_add(&Z3, &Z3, &Z3);
				zzn4_sub(&Z1, &ret.c, &T0); zzn4_sub(&T0, &Z2, &T0);
				zzn4_sub(&Z1, &Z0, &T1); zzn4_sub(&T1, &Z3, &T1); zzn4_add(&ret.c, &T1, &ret.c);
				zzn4_tx(&Z3); zzn4_add(&T0, &Z3, &ret.b);
				zzn4_tx(&Z2); zzn4_add(&Z0, &Z2, &ret.a);
			}
		}
	} else
	{
		// Karatsuba
		zero_b = zzn4_iszero(&var.b);
		zero_c = zzn4_iszero(&var.c);
		zzn4_mul(&a, &var.a, &Z0); //9
		if( !zero_b ) zzn4_mul(&b, &var.b, &Z2); //+6
		zzn4_add(&a, &b, &T0);
		zzn4_add(&var.a, &var.b, &T1);
		zzn4_mul(&T0, &T1, &Z1); //+9
		zzn4_sub(&Z1, &Z0, &Z1);
		if( !zero_b ) zzn4_sub(&Z1, &Z2, &Z1);
		zzn4_add(&b, &c, &T0);
		zzn4_add(&var.b, &var.c, &T1);
		zzn4_mul(&T0, &T1, &Z3);//+6
		if( !zero_b ) zzn4_sub(&Z3, &Z2, &Z3);
		zzn4_add(&a, &c, &T0);
		zzn4_add(&var.a, &var.c, &T1);
		zzn4_mul(&T0, &T1, &T0);//+9=39 for "special case"
		if( !zero_b ) zzn4_add(&Z2, &T0, &Z2);
		else zzn4_copy(&T0, &Z2);
		zzn4_sub(&Z2, &Z0, &Z2);
		zzn4_copy(&Z1, &ret.b);
		if( !zero_c )
		{ // exploit special form of BN curve line function
			zzn4_mul(&c, &var.c, &T0);
			zzn4_sub(&Z2, &T0, &Z2);
			zzn4_sub(&Z3, &T0, &Z3); zzn4_tx(&T0);
			zzn4_add(&ret.b, &T0, &ret.b);
		}
		zzn4_tx(&Z3);
		zzn4_add(&Z0, &Z3, &ret.a);
		zzn4_copy(&Z2, &ret.c);
		if( !var.unitary ) ret.unitary = FALSE;
	}

	Parameters::release_zzn4(Z0);
	Parameters::release_zzn4(Z1);
	Parameters::release_zzn4(Z2);
	Parameters::release_zzn4(Z3);
	Parameters::release_zzn4(T0);
	Parameters::release_zzn4(T1);

	return ret;
}

ZZN12 ZZN12::conj()
{
	ZZN12 ret;
	zzn4_conj(&a, &ret.a);
	zzn4_conj(&b, &ret.b);
	zzn4_negate(&ret.b, &ret.b);
	zzn4_conj(&c, &ret.c);
	ret.miller = miller;
	ret.unitary = unitary;
	return ret;
}

ZZN12 ZZN12::inverse()
{
	zzn4 tmp1, tmp2;
	ZZN12 ret;
	Parameters::init_zzn4(tmp1);
	Parameters::init_zzn4(tmp2);

	if( unitary )
	{
		ret =conj();
		goto END;
	}
	//ret.a=a*a-tx(b*c);
	zzn4_mul(&a, &a, &ret.a);
	zzn4_mul(&b, &c, &ret.b); zzn4_tx(&ret.b);
	zzn4_sub(&ret.a, &ret.b, &ret.a);

	//ret.b=tx(c*c)-a*b;
	zzn4_mul(&c, &c, &ret.c); zzn4_tx(&ret.c);
	zzn4_mul(&a, &b, &ret.b); zzn4_sub(&ret.c, &ret.b, &ret.b);

	//ret.c=b*b-a*c;
	zzn4_mul(&b, &b, &ret.c); zzn4_mul(&a, &c, &tmp1); zzn4_sub(&ret.c, &tmp1, &ret.c);

	//tmp1=tx(b*ret.c)+a*ret.a+tx(c*ret.b);
	zzn4_mul(&b, &ret.c, &tmp1); zzn4_tx(&tmp1);
	zzn4_mul(&a, &ret.a, &tmp2); zzn4_add(&tmp1, &tmp2, &tmp1);
	zzn4_mul(&c, &ret.b, &tmp2); zzn4_tx(&tmp2); zzn4_add(&tmp1, &tmp2, &tmp1);
	zzn4_inv(&tmp1);
	zzn4_mul(&ret.a, &tmp1, &ret.a);
	zzn4_mul(&ret.b, &tmp1, &ret.b);
	zzn4_mul(&ret.c, &tmp1, &ret.c);

END:
	Parameters::release_zzn4(tmp1);
	Parameters::release_zzn4(tmp2);
	return ret;
}

ZZN12 ZZN12::powq(zzn2& var)
{
	ZZN12 ret(*this);
	zzn2 X2, X3;
	
	Parameters::init_zzn2(X2);
	Parameters::init_zzn2(X3);

	zzn2_mul(&var, &var, &X2);
	zzn2_mul(&X2, &var, &X3);
	zzn4_powq(&X3, &ret.a); zzn4_powq(&X3, &ret.b); zzn4_powq(&X3, &ret.c);
	zzn4_smul(&ret.b, &Parameters::norm_X, &ret.b);
	zzn4_smul(&ret.c, &X2, &ret.c);

	Parameters::release_zzn2(X2);
	Parameters::release_zzn2(X3);
	return ret;
}

ZZN12 ZZN12::div(ZZN12& var)
{
	ZZN12 y = var.inverse();
	return mul(y);
}

ZZN12 ZZN12::pow(big k)
{
	ZZN12 ret;
	big zero, tmp, tmp1;
	int nb, i;
	BOOL invert_it;

	Parameters::init_big(zero);
	Parameters::init_big(tmp);
	Parameters::init_big(tmp1);

	copy(k, tmp1);
	invert_it = FALSE;
	if( mr_compare(tmp1, zero) == 0 )
	{
		tmp = get_mip()->one;
		zzn4_from_big(tmp, &ret.a);
		goto END;
	}
	if( mr_compare(tmp1, zero) < 0 )
	{
		negify(tmp1, tmp1); invert_it = TRUE;
	}
	nb = logb2(k);

	ret = *this;
	if( nb > 1 ) for( i = nb - 2; i >= 0; i-- )
	{
		ret = ret.mul(ret);
		if( mr_testbit(k, i) ) ret = ret.mul(*this);
	}
	if( invert_it ) ret = ret.inverse();

END:
	Parameters::release_big(zero);
	Parameters::release_big(tmp);
	Parameters::release_big(tmp1);
	return ret;
}

bool ZZN12::isOrderQ()
{
	bool result = false;
	ZZN12 v(*this);
	ZZN12 w(*this);
	big six;

	Parameters::init_big(six);

	convert(6, six);

	w = w.powq(Parameters::norm_X);
	v = v.pow(Parameters::param_t);
	v = v.pow(Parameters::param_t);
	v = v.pow(six);

	if( zzn4_compare(&w.a, &v.a) && zzn4_compare(&w.a, &v.a) && zzn4_compare(&w.a, &v.a) ) {
		result = true;
		goto END;
	}

END:
	Parameters::release_big(six);

	return result;
}


void ZZN12::q_power_frobenius(ecn2 A, zzn2 F)
{
	// Fast multiplication of A by q (for Trace-Zero group members only)
	zzn2 x, y, z, w, r;

	Parameters::init_zzn2(x);
	Parameters::init_zzn2(y);
	Parameters::init_zzn2(z);
	Parameters::init_zzn2(w);
	Parameters::init_zzn2(r);

	ecn2_get(&A, &x, &y, &z);
	zzn2_copy(&F, &r);//r=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);

	Parameters::release_zzn2(x);
	Parameters::release_zzn2(y);
	Parameters::release_zzn2(z);
	Parameters::release_zzn2(w);
	Parameters::release_zzn2(r);
}



ZZN12 ZZN12::line(ecn2 A, ecn2 *C, ecn2 *B, zzn2 slope, zzn2 extra, BOOL Doubling, big Qx, big Qy)
{
	ZZN12 ret;
	zzn2 X, Y, Z, Z2, U, QY, CZ;
	big QX;

	Parameters::init_big(QX);
	Parameters::init_zzn2(X);
	Parameters::init_zzn2(Y);
	Parameters::init_zzn2(Z);
	Parameters::init_zzn2(Z2);
	Parameters::init_zzn2(U);
	Parameters::init_zzn2(QY);
	Parameters::init_zzn2(CZ);

	ecn2_getz(C, &CZ);
	// Thanks to A. Menezes for pointing out this optimization...
	if( Doubling )
	{
		ecn2_get(&A, &X, &Y, &Z);
		zzn2_mul(&Z, &Z, &Z2); //Z2=Z*Z
							   //X=slope*X-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, &ret.a);
			zzn2_copy(&Y, &(ret.c.b));
		}
		if( get_mip()->TWIST == MR_SEXTIC_D )
		{
			zzn2_smul(&U, Qy, &QY);
			zzn4_from_zzn2s(&QY, &X, &ret.a);
			zzn2_copy(&Y, &(ret.b.b));
		}
	} else
	{ //slope*X-Y*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, &ret.a);
			zzn2_copy(&Z, &(ret.c.b));
		}
		if( get_mip()->TWIST == MR_SEXTIC_D )
		{
			zzn2_smul(&CZ, Qy, &QY);
			zzn4_from_zzn2s(&QY, &X, &ret.a);
			zzn2_copy(&Z, &(ret.b.b));
		}
	}

	Parameters::release_big(QX);
	Parameters::release_zzn2(X);
	Parameters::release_zzn2(Y);
	Parameters::release_zzn2(Z);
	Parameters::release_zzn2(Z2);
	Parameters::release_zzn2(U);
	Parameters::release_zzn2(QY);
	Parameters::release_zzn2(CZ);
	return ret;
}

ZZN12 ZZN12::g(ecn2 *A, ecn2 *B, big Qx, big Qy)
{
	ZZN12 ret;
	zzn2 lam, extra;
	ecn2 P;
	BOOL Doubling;

	Parameters::init_zzn2(lam);
	Parameters::init_zzn2(extra);
	Parameters::init_ecn2(P);

	ecn2_copy(A, &P);
	Doubling = ecn2_add2(B, A, &lam, &extra);
	if( A->marker == MR_EPOINT_INFINITY )
	{
		zzn4_from_int(1, &ret.a);
		ret.miller = FALSE;
		ret.unitary = TRUE;
	} else {
		ret = line(P, A, B, lam, extra, Doubling, Qx, Qy);
	}

	Parameters::release_zzn2(lam);
	Parameters::release_zzn2(extra);
	Parameters::release_ecn2(P);
	return ret;
}

bool ZZN12::fast_pairing(ZZN12& ret, ecn2 P, big Qx, big Qy, big x, zzn2 X)
{
	bool result = false;
	int i, nb;
	big n, zero, negify_x;
	ecn2 A, KA;
	ZZN12 t0, x0, x1, x2, x3, x4, x5, res, tmp;

	Parameters::init_big(n);
	Parameters::init_big(zero);
	Parameters::init_big(negify_x);
	Parameters::init_ecn2(A);
	Parameters::init_ecn2(KA);

	premult(x, 6, n); incr(n, 2, n);//n=(6*x+2);
	if( mr_compare(x, zero) < 0 ) //x<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
	res.miller = TRUE; //Short Miller loop

	for( i = nb - 2; i >= 0; i-- )
	{
		res = res.mul(res);
		tmp = g(&A, &A, Qx, Qy);
		res = res.mul(tmp);
		if( mr_testbit(n, i) ) {
			tmp = g(&A, &P, Qx, Qy);
			res = res.mul(tmp);
		}
	}
	// Combining ideas due to Longa, Aranha et al. and Naehrig
	ecn2_copy(&P, &KA);
	q_power_frobenius(KA, X);
	if( mr_compare(x, zero) < 0 )
	{
		ecn2_negate(&A, &A);
		res = res.conj();
	}
	tmp = g(&A, &KA, Qx, Qy);
	res = res.mul(tmp);

	q_power_frobenius(KA, X);
	ecn2_negate(&KA, &KA);
	tmp = g(&A, &KA, Qx, Qy);
	res = res.mul(tmp);

	if( zzn4_iszero(&res.a) && zzn4_iszero(&res.b) && zzn4_iszero(&res.c) )
		goto END;

	// The final exponentiation
	res = res.conj().div(res);
	res.miller = FALSE; res.unitary = FALSE;

	res = res.powq(X).powq(X).mul(res);
	res.miller = FALSE; res.unitary = TRUE;

	// Newer new idea...
	// See "On the final exponentiation for calculating pairings on ordinary elliptic curves"
	// Michael Scott and Naomi Benger and Manuel Charlemagne and Luis J. Dominguez Perez and Ezekiel J. Kachisa
	t0 = res.powq(X);
	x0 = t0.powq(X);
	x1 = res.mul(t0);

	x0 = x0.mul(x1).powq(X);
	x1 = res.inverse();

	negify(x, negify_x); 
	x4 = res.pow(negify_x);
	x3 = x4.powq(X);
	x2 = x4.pow(negify_x);

	x5 = x2.inverse();
	t0 = x2.pow(negify_x);

	x2 = x2.powq(X);
	x4 = x4.div(x2);
	x2 = x2.powq(X);

	res = t0.powq(X);
	t0 = t0.mul(res);

	t0 = t0.mul(t0).mul(x4).mul(x5);
	res = x3.mul(x5).mul(t0);

	t0 = t0.mul(x2);
	res = res.mul(res).mul(t0);

	res = res.mul(res);
	t0 = res.mul(x1);

	res = res.mul(x0);
	t0 = t0.mul(t0).mul(res);

	ret = t0;
	result = true;

END:
	Parameters::release_big(n);
	Parameters::release_big(zero);
	Parameters::release_big(negify_x);
	Parameters::release_ecn2(A);
	Parameters::release_ecn2(KA);
	return result;
}

bool ZZN12::calcRatePairing(ZZN12& ret, ecn2 P, epoint *Q, big x, zzn2 X)
{
	bool result = false;
	big Qx, Qy;

	Parameters::init_big(Qx);
	Parameters::init_big(Qy);

	ecn2_norm(&P);
	epoint_get(Q, Qx, Qy);
	result = fast_pairing(ret, P, Qx, Qy, x, X);
	if(result) result = ret.isOrderQ();

	Parameters::release_big(Qx);
	Parameters::release_big(Qy);
	return result;
}

你可能感兴趣的:(程序设计)