在这里,我正在回答我自己的问题。我想它一直在 SO 中发生。
OpenSSL 中的 BIGNUM 是一个复杂的结构,包含一个任意大的数字,因此重复创建和释放 BIGNUM 实例将导致相当大的开销。创建并使用 BIGNUM 上下文或 BN_CTX 来节省此开销。
结构
BN_CTX 结构包含两个结构:BN_POOL
和BN_STACK
。使用BN_POOL
链表保留一捆临时 bignum,而BN_STACK
管理堆栈帧。
创建时
使用 . 创建一个BN_CTX
实例。函数必须首先调用以获取新的堆栈帧。通过调用,OpenSSL 在中查找未使用的 bignum 。如果没有任何可用的临时 bignum,OpenSSL 将创建一个并链接到链表。这必须在作为参数传递给其他函数之前完成。ctx
BN_CTX_new()
BN_CTX_start()
BN_CTX_get(ctx)
BN_POOL
ctx
ctx
当然,有一种机制可以防止用户创建过多的临时 bignums。您可以在 a 中创建的预定义 bignum 数量BN_POOL
为 16。一旦超过限制,可能会在 OpenSSL 库中的随机位置发生分段错误。
退出时
ctx
在函数处理完它从中获取并准备退出 的 BIGNUM 实例后,BN_CTX_end()
将调用以释放临时 bignum,这意味着这些 bignum 变为“未使用”并且可以由 next 请求BN_CTX_get()
。
最后,大概在几次BN_CTX_start()
and之后BN_CTX_end()
,BN_CTX_end()
调用freeBN_STACK
结构,并清除free bignums BN_POOL
。
示例代码
void foo(){
BN_CTX* ctx;
ctx = BN_CTX_new();
/* Using BIGNUM context in a series of BIGNUM operations */
bar(ctx);
bar(ctx);
bar(ctx);
/* Using BIGNUM context in a function called in loops */
while(/*condition*/){
bar(ctx);
}
BN_CTX_free(ctx);
}
这是功能bar( )
void bar(BN_CTX* ctx){
BIGNUM *bn;
BN_CTX_start(ctx);
bn = BN_CTX_get(ctx);
/* Do something with bn */
BN_CTX_end(ctx);
}
该函数foo()
创建一个新的 BIGNUM 上下文并将其作为参数传递给 function bar()
。在第一次bar()
调用时BN_CTX_get()
,会创建一个临时的 bignum 并将其存储在BN_POOL
并返回。BN_CTX_get()
随后bar()
将不会创建新的 bignum 而是返回它首先创建的那个。这个临时的 bignum 最终会被BN_CTX_free()
in清除foo()
。
结论
当关注性能时,BN_CTX
通过将 BIGNUM 创建传递给函数来节省开销
- 需要 BIGNUM 结构来保存临时大数字,并且
- 被顺序调用以执行某些 bignum 操作,或
- 在循环中被重复调用。
请注意,存储在BN_CTX
. 如果性能不是问题,则使用
bn = BN_new();
if (bn)
BN_free(bn);
很好。