在这里,我正在回答我自己的问题。我想它一直在 SO 中发生。
OpenSSL 中的 BIGNUM 是一个复杂的结构,包含一个任意大的数字,因此重复创建和释放 BIGNUM 实例将导致相当大的开销。创建并使用 BIGNUM 上下文或 BN_CTX 来节省此开销。
结构
BN_CTX 结构包含两个结构:BN_POOL和BN_STACK。使用BN_POOL链表保留一捆临时 bignum,而BN_STACK管理堆栈帧。
创建时
使用 . 创建一个BN_CTX实例。函数必须首先调用以获取新的堆栈帧。通过调用,OpenSSL 在中查找未使用的 bignum 。如果没有任何可用的临时 bignum,OpenSSL 将创建一个并链接到链表。这必须在作为参数传递给其他函数之前完成。ctxBN_CTX_new()BN_CTX_start()BN_CTX_get(ctx)BN_POOLctxctx
当然,有一种机制可以防止用户创建过多的临时 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);
很好。