在C++程序中,这些函数可能与全局变量的构造函数和析构函数相关联[Walmsley]——这将确保它们会在主线程创建新的线程分支前的一个适合的时候被调用。它们必须在线程显式(或隐式)地调用missys(通过创建线程特定的Miracl实例)之前被调用。
强烈建议程序在开发时不要实现对多线程的支持。只有程序经过完整的测试和调用,它才应转换到一个线程中(原文:should it be converted into a thread)。
线程编程可能要求其它的操作系统的特殊机制——在链接特殊的库或访问特殊的堆函数方面。这里值得指出的是MIRACL堆访问都是通过mralloc.c模块完成的。
threadwn.cpp程序是一个Windows C++多线程示例。阅读其中的注释——它可以编译和从Windows命令提示符运行。类似地threaduc.cpp是一个Unix的多线程示例。
2.4 受限环境
在版本5的中,有一个对在非常小和受限的环境中的MIRACL实现的新支持。使用config实用程序,它现在支持各种时空交换(time/space trade-offs),最主要的革新是在一个不支持堆的环境中生成和使用MIRACL。通常big变量的空间从堆中分配,但通过在配置头文件中指定MR_STATIC,可以生成一个总是尝试从静态内存或栈,而不是堆中分配内存的版本。
这带来的主要负面影响是big变量的最大尺寸必须在编译时确定(生成库的时候)。如往常一样,在这个过程中最好让config实用程序引导你创建一个合适的配置头文件mirdef.h。
对于C程序员,使用下列方式从栈中为big变量分配内存: big x, y, z;
char mem[MR_BIG_RESERVE(3)]; memset(mem, 0, MR_BIG_RESERVE(3));
为三个big变量分配的空间都在栈上并且被清零,然后每个变量应如下初始化: x = mirvar_mem(mem, 0); y = mirvar_mem(mem, 1);
z = mirvar_mem(mem, 2);
从单个内存块中为多个big变量分配所有空间是有意义的,那样可以更快的初始化,而且可以对变量对齐进行完整的控制——编译器有时会出错。请注意big初始化函数mirvar在这种模式中不再有效,分配操作应像上面描述的那样实现。
最后,可以选择性地在函数末尾调用memset来在离开前清空内存块——出于保密原因,这可能很重要。请参考示例程序brent.c。
这种机制在实现一个使用椭圆曲线的非常小的程序时可能非常有用。椭圆曲线要求的big数字要比其它加密技术的小得多。从栈中为椭圆曲线的点分配内存:
epoint *x, *y, *z;
char mem[MR_ECP_RESERVE(3)]; memset(mem, 0, MR_ECP_RESERVE(3)); 初始化这些点:
x = epoint_init_mem(mem, 0); y = epoint_init_mem(mem, 1); z = epoint_init_mem(mem, 2);
同样,在离开函数前清空相关内存是明智的。
此机制对C++编程同样支持得很好,它与第7章描述的栈分配方法联合工作。pk-demo.cpp是一个使用示例。
在一些极端场合中,可能要求从栈中分配所有内存。这允许使用和重用最多的内存,并且避免宝贵的RAM出现碎片。对于C程序,这可以通过在mirdef.h中定义MR_GENERIC_MT来实现。
这种场合中的典型mirdef.h头文件可能是这个样子的: /*
* MIRACL compiler/hardware definitions - mirdef.h * Copyright (c) 1988-2005 Shamus Software Ltd.
*/
#define MR_LITTLE_ENDIAN #define MIRACL 32 #define mr_utype int #define MR_IBITS 32 #define MR_LBITS 32
#define mr_unsign32 unsigned int #define mr_dltype __int64
#define mr_unsign64 unsigned __int64 #define MR_STATIC 7 #define MR_ALWAYS_BINARY #define MR_NOASM
#define MAXBASE ((mr_small)1<<(MIRACL-1)) #define MR_BITSINCHAR 8 #define MR_SHORT_OF_MEMORY #define MR_GENERIC_MT #define MR_STRIPPED_DOWN
关于使用这种类型的头文件的示例程序,请查看ecsgen_s.c,ecsign_s.c,ecsver_s.c,ecsgen2s.c,ecsign2s.c和ecsver2s.c。这些程序使用Microsoft C++在Pentium上实现了非常小而快速的ECDSA密码生成,数字签名以及校验算法。ecdh.c是另一个很棒的示例,它使用导航预行计算(precomputation)来加速一个EC Diffie-Hellman实现。
注意:不使用堆有一些小问题:结构不能再是可变大小的,因此在这种模式中MIRACL的许多特性都不再可用。例如中国剩余定理(Chinese remainder theorem)程序要求的导航预行计算(precomputation)就无
法支持。但在一个受限环境中,有理由假定诸如导航预行计算(precomputation)将脱机实现,以使将程序固化到ROM中成为可能。
MIRACL模块经过了周密的设计以使对于给定的任务,应用程序都只需要从库中引入最少的模块。这可以帮助应用程序保持最小的尺寸。但是如果程序的尺寸是一个大话题(big issue),则可以手工从模块中删除不需要的函数来达到额外的节约。
2.5 平台特定的信息
2.5.5 Microsoft Visual C++
在Microsoft C++6.0上创建MIRACL应用程序的步骤如下:
1. 创建一个Win32 Console Application的空工程。
2. 选择菜单“Project”——“Add to Project”——“File”。
3. 选择“Library files(.lib)”文件类型,查找预编译的MIRACL库文件ms32.lib,将它添加到工程。 4. 添加一个工程的主文件(例如limlee.cpp)。
5. 如果是C++主工程文件,则再添加其它所需的文件,如big.cpp、zzn.cpp等。主文件的头部注释中列出了所需的文件。
6. 选择菜单“Project”——“Setting”。选中C/C++ Tab页,选择“Preprocesser”目录,在“Additional Include Directoryies”中指定MIRACL头文件路径。
7. 确保应用程序运行目录中的所有程序所需文件均可用,如*.key,*.dss或*.ecs等文件。 8. 生成并运行程序。
在Microsoft C++6.0上创建MIRACL库的步骤:
1. 编译并运行config.c实用程序,将生成的mirdef.tst重命名为mirdef.h。注意Microsoft C拥有一个64位整数类型__int64。
2. 新一个“Win32 Static Library”类型的工程。
3. 添加适当的mr*.c文件,它们在miracl.lst中列出。
4. 选择菜单“Project”——“Setting”。选中C/C++ Tab页,选择“Preprocesser”目录,在“Additional Include Directoryies”中指定MIRACL头文件路径。
5. 编译工程生成MIRACL库。
在Microsoft C++.NET上创建MIRACL应用程序的步骤:
1. 创建一个Win32 Console Application的空工程。
2. 去掉工程中的空主文件,用MIRACL提供的文件(如limlee.cpp)将其替换。请注意现在主函数称为_tmain。
3. 选择菜单“Project”——“Add to Project”——“File”。选择“All files”文件类型,查找预编译的MIRACL库文件ms32.lib,将它添加到工程。
4. 如果是C++主工程文件,则则再添加其它所需的文件,如big.cpp、zzn.cpp等。主文件的头部注释中列出了所需的文件。
5. 选择菜单“Project”——“Properties”。打开C++标签页,到“Precompiled Headers”,选择“Not using precompiled headers”。再打开“General”标签页,指定MIRACL头文件的路径。
6. 生成并运行程序。
在Microsoft C++.NET上创建MIRACL库的步骤:
创建一个“Win32 Project”类型的Visual C++工程。 选择“Application Settings“,选择”Static Library“。 添加相应的mr*.c文件。
选择“Project”——“Properties”。打开C++标签页,到“Precompiled Headers”,选择“Not using precompiled headers”。再打开“General”标签页,指定MIRACL头文件的路径。
生成工程。