只要正确地定义和创建了类型,就可以像使用内置的double和int类型那样来使用新的数据类型。使用C++还可以帮助用户屏蔽MIRACL的内部工作。
MIRACL库通过头文件big.h,flash.h,zzn.h,gf2m.h,ecn.h和ec2.h提供了C++的接口。功能的实现在相关的文件big.cpp,flash.cpp,zzn.cpp,gf2m.cpp,ecn.cpp和ec2.cpp中,它们应链接到任何需要使用它们的应用程序中。中国剩余定理也巧妙地实现为了一个类,其实现在文件crt.h和crt.cpp中,decode.cpp中则有一个使用示例。使用预先计算(precomputation,[ HAC])的Comb快速模幂算法实现在brick.h中,brick.cpp中有使用示例。GF(p)椭圆曲线等值在文件ebrick.h和ebrick.cpp中,GF(2^m)椭圆曲线等值则在ebrick2.h和ebrick2.cpp中。
/*
* Program to calculate factorials. */
#include
#include %using namespace std;
Miracl precision(500,10); // This makes sure that MIRACL // is initialised before main() // is called void main() {
/* calculate factorial of number */ Big nf = 1; /* declare \int n;
cout << \cout << \
cin >> n; while (n > 1)
nf *= (n--); /* nf = n! = n*(n-1)*(n-2)*....3*2*1 */ cout << \}
请注意对用于设置big变量精度的伪类Miracl的使用。它声明在全局范围内以确保MIRACL会在main调用前初始化(注意这不适用于多线程环境)。编译和链接此程序时,别忘了链接实现Big类型的文件big.cpp。
与内部Big类型相互转换很重要: 将十六进制字符串转换为Big: Big x; char c[100]; ...
mip->IOBASE = 16; x = c;
将Big转换为十六进制字符串: mip->IOBASE = 16; c << x;
若要与二进制相互转换,请使用from_binary()和to_binary()友员。 int len; char c[100]; ...
Big x = from_binary(len, c);
// creates Big x from len bytes of binary in c len = to_binary(x, 100, c, FALSE);
// converts Big x to len bytes binary in c[100] len = to_binary(x, 100, c, TRUE);
// converts Big x to len bytes binary in c[100] // (right justified with leading zeros)
在许多示例程序尤其是因式分解程序中,需要进行所有的算术运算。为避免乏味地在每个操作后都要进行降阶(reduction,mod n),使用了一个新的C++类ZZn,它定义在zzn.h中。ZZn的算子将自动进行降价。modulo(n)函数用于设置模数。GF2m类使用类似的方式来处理定义于GF(2^m)上的各个域元素。此时用modulo(m,a,b,c)来设置模数,它同时也指定了一个三项式
tm+ta+1(b = c =0)或五项式(tanomial)
tm+ta+tb+tc+1。详细内容参见IEEE P1363文档:http://grouper.ieee.org/groups/1363/draft.html
ZZn内部使用Montgomery表示法(见zzn.h),但作为C++的一个典型特性,这对程序员是透明的。 ecn.h中定义的类ECn使操作GF(p)椭圆曲线上的点成为一件简单的事情,同样屏蔽了所有麻烦的细节。ec2.h中定义的EC2完成与GF(2^m)相关的同样事情。
几乎所有的MIRACL功能都可以通过C++来访问。
大部分的示例程序的C++版本包含在分发包中,后缀名为.cpp。
用C++维护大对象的一个问题是编译器产生代码来创建/销毁/拷贝临时对象的倾向。默认情况下MIRACL从堆中获取内存给Big和Flash,这可能相当耗时,并且最终这些对象还要清除。从栈中分配内存可能要快一点,尤其对于相对较小的big数。这可以在编译时通过定义开关BIGS=m来做到。例如在Microsoft C++编译器上使用下列命令行:
C:\\miracl>cl /O2 /GX /DBIGS=50 brent.cpp big.cpp zzn.cpp miracl.lib 请注意m的值应小于主程序中调用mirsys(n,0)或Miracl precision=n时n的值。
在有限域上运算时,有效数字总是小于某个固定的模数。例如在有限域(mod n)中,ZZn可以处理关于模数n(512位,通过Modulo(n)指定)的值。在这种情况下可以定义ZZNS=16,从而所有的元素的大小都是16*32=512位并且从栈中创建(这在与Comba机制联合使用时工作得尤其好)。
类似地,当工作在域GF(2^283)上时,可以定义GF2MS=9,从而域上的所有元素都存储在从栈中分配的
固定的9个字中。
在后两种情况中,调用mirsys(n,0)或Miracl precision=n指定的精度值n应至少比ZZNS=m或GF2MS=m中指定的m大2。
开发时或当对象非常大时,不推荐使用这些方法。它仅与C++程序有关。见示例程序ibe_dec和dl.cpp中 有关使用此机制的注释。但同时它的好处也是明显的,程序运行效率可能提升一倍。
最后,这里有一个实现相对来说较复杂的加密协议的C++程序,注意其中对的域元素变量(大写字母)的转换。
/*
* Gunthers’s ID based key exchange - Finite field version * See RFC 1824
* r^r variant (with Perfect Forward Security) */
#include
// hash character string to 160-bit big number int b;
Big h; char s[20]; sha sh; shs_init(&sh);
while (*ID != 0) shs_process(&sh, *ID++); shs_hash(&sh, s); h = from_binary(20, s); return h; }
int main() {
int bits;
ifstream common(\Big p,q,g,x,k,ra,rb,sa,sb,ta,tb,wa,wb; ZZn G,Y,Ra,Rb,Ua,Ub,Va,Vb,Key; ZZn A[4]; Big b[4]; long seed;
miracl *mip = &precision;
cout << \cin >> seed; irand(seed);
// get common data. Its in hex. G^q mod p = 1 common >> bits; mip->IOBASE = 16;