上篇確立了數據結構,本文實現 bignum 的「出生、成長、複製、轉移、死亡」全生命周期函數,這些是所有高層算法調用最頻繁的基石,務必高效、健壯。
void bn_init(bignum *x) {
if (x) {
x->sign = 1; x->alloc = 0; x->used = 0; x->dp = NULL;
}
}
適用場景:臨時變量、結果參數、陣列批量初始化。後續調用 bn_grow 按需分配。
int bn_init_size(bignum *x, size_t nlimbs) {
if (nlimbs > BN_MAX_LIMB) return BN_EXCEED_MAX_LIMB;
if (!x) return 0;
bn_digit *p = (bn_digit*)BN_MALLOC(nlimbs * ciL);
if (!p) return BN_MEMORY_ALLOCATE_FAIL;
memset(p, 0, nlimbs * ciL);
x->sign = 1; x->alloc = nlimbs; x->used = 0; x->dp = p;
return 0;
}
適用場景:已知大致位數(如從字符串導入、固定長度運算),減少重複擴容。
void bn_free(bignum *x) {
if (x && x->dp) {
memset(x->dp, 0, x->alloc * ciL); // 清敏感數據
BN_FREE(x->dp);
x->dp = NULL; // 防雙重釋放
}
if (x) { x->sign = 1; x->alloc = 0; x->used = 0; }
}
安全性: 清零內存防殘留敏感數據(私鑰等);置 NULL 防止 use-after-free。
int bn_grow(bignum *x, size_t nlimbs) {
if (nlimbs > BN_MAX_LIMB) return BN_EXCEED_MAX_LIMB;
if (nlimbs <= x->alloc) return 0; // 已足夠,無操作
bn_digit *p = (bn_digit*)BN_MALLOC(nlimbs * ciL);
if (!p) return BN_MEMORY_ALLOCATE_FAIL;
memset(p, 0, nlimbs * ciL);
if (x->dp) {
memcpy(p, x->dp, x->alloc * ciL); // 保留原數據
memset(x->dp, 0, x->alloc * ciL);
BN_FREE(x->dp);
}
x->dp = p; x->alloc = nlimbs;
return 0;
}
關鍵優化: 僅在需要時才重新分配,避免頻繁 malloc/free。調用者可預估大小調用 bn_init_size 或提前 bn_grow。
int bn_copy(bignum *x, const bignum *y) {
if (x == y) return 0; // 同對象無需操作
int ret; size_t nlimbs = (y->used == 0) ? 1 : y->used;
BN_CHECK(bn_grow(x, nlimbs));
memset(x->dp, 0, x->alloc * ciL);
x->sign = y->sign; x->used = y->used;
if (y->dp && y->used) memcpy(x->dp, y->dp, y->used * ciL);
clean:
return ret;
}
深拷貝: 分配新內存,不共享 dp 指針。used==0 仍分配 1 位,保證 dp[0] 可寫。
int bn_set_word(bignum *x, const bn_digit word) {
int ret;
BN_CHECK(bn_grow(x, 1));
memset(x->dp, 0, ciL);
x->dp[0] = word;
x->used = (word != 0) ? 1 : 0;
x->sign = 1; // 默認非負,負數調用後手動置 -1
clean:
return ret;
}
常用於設置小常數(0, 1, 2, 模數等)。
void bn_swap(bignum *x, bignum *y) {
int tmp_sign = x->sign; x->sign = y->sign; y->sign = tmp_sign;
size_t tmp_alloc = x->alloc; x->alloc = y->alloc; y->alloc = tmp_alloc;
size_t tmp_used = x->used; x->used = y->used; y->used = tmp_used;
bn_digit *tmp_dp = x->dp; x->dp = y->dp; y->dp = tmp_dp;
}
O(1) 交換所有字段,用於算法中臨時變量輪換(如除法中被除數/除數交換)、避免拷貝開銷。
| 函數 | 用途 | 時間複雜度 | 備註 |
|---|---|---|---|
| bn_init | 零成本初始化 | O(1) | 最常用 |
| bn_init_size | 預分配 | O(n) | n 為分配位數 |
| bn_free | 釋放資源 | O(n) | 清零敏感數據 |
| bn_grow | 按需擴容 | O(n) | 僅不足時分配 |
| bn_copy | 深拷貝 | O(n) | n 為源 used |
| bn_set_word | 單精度賦值 | O(1) | 小常數專用 |
| bn_swap | 交換 | O(1) | 指針交換,無拷貝 |
下一篇將講解比較操作:絕對值比較、有符號比較、與單精度數比較,這是條件跳轉、排序、除法試商的基礎。