大步小步算法

群論中,大步小步算法(英語:baby-step giant-step)是丹尼爾·尚克斯英語Daniel Shanks發明的一種中途相遇算法,用於計算離散對數或者有限阿貝爾群[1]其中離散對數問題在公鑰加密領域有着非常重要的地位。

許多常用的加密系統都基於離散對數極難計算這一假設——計算越困難,這些系統提供的數據傳輸就越安全。增加離散對數計算難度的一種方法,是把密碼系統建立在更大的群上。

理論

這是一種空間換時間的算法,實質上是求解離散對數的樸素算法(枚舉並試乘)的一個相當簡單的改進。

給出一個   循環群   、該群的一個生成元   和一個元素   。試找到一個整數   滿足

 

大步小步算法把   代換成:

 
 
 
 

於是有:

 
 
 

該算法先對   的不同取值計算出   的值,然後固定一個   ,並對   嘗試不同的取值,帶入上面同餘式的右邊,看是否與某個(已經預先算出的)同餘式左邊的值相匹配。

算法

給出C++17版本的代碼:

#include <cmath>
#include <cstdint>
#include <unordered_map>

std::uint32_t pow_m(std::uint32_t base, std::uint32_t exp, std::uint32_t mod) {
        // 这里需要实现快速幂算法
}


///计算满足 g^x % mod == h 的x
std::optional<std::uint32_t> babystep_giantstep(std::uint32_t g, std::uint32_t h, std::uint32_t mod) {
        const auto m = static_cast<std::uint32_t>(std::ceil(std::sqrt(mod)));
        auto table = std::unordered_map<std::uint32_t, std::uint32_t>{};
        auto e = std::uint64_t{1}; // 临时值可能大于32位整数的范围
        for (auto i = std::uint32_t{0}; i < m; ++i) {
                table[static_cast<std::uint32_t>(e)] = i;
                e = (e * g) % mod;
        }
        const auto factor = pow_m(g, mod-m-1, mod);
        e = h;
        for (auto i = std::uint32_t{}; i < m; ++i) {
                if (auto it = table.find(static_cast<std::uint32_t>(e)); it != table.end()) {
                        return {i*m + it->second};
                }
                e = (e * factor) % mod;
        }
        return std::nullopt;
}

延伸閱讀

參考資料

  1. ^ Daniel Shanks, Class number, a theory of factorization and genera, In Proc. Symp. Pure Math. 20 (Providence, R.I.: American Mathematical Society), 1971, 20: 415—440 (英語)