iT邦幫忙

2025 iThome 鐵人賽

DAY 15
0
Security

裸機實作 SLH-DSA 簽章:FIPS 205 之演算法實作、測試、防禦與跨平台系列 第 15

Day 15 產生 hypertree signature: HT signature, XMSS signature 和 WOTS+ signature

  • 分享至 

  • xImage
  •  

本日重點:ht_sign, wots_sign, xmss_sign

Hypertree signature 是由一連串的 XMSS signature 所組成,每一個 XMSS signature 都包括了一個 WOTS+ signature. 產生 WOTS+ signature 的 function 就是 wots_sign,演算法如下
https://ithelp.ithome.com.tw/upload/images/20250928/201401295Y2yZdvcm8.png

wots_sign 的 line 15 就是 chain,這是 chain 的演算法
https://ithelp.ithome.com.tw/upload/images/20250928/20140129xhduP3XkyF.png

chain 會進行若干次的更新 hash address,然後每次更新 hash address 就會計算 F

The chain function updates the hash address in ADRS with each iteration to specify the current position in the chain prior to ADRS’s use in F

F 的定義裡,input M 是一個長度為 n 的 bytes 陣列,所以,可以把 tmp 直接設為 out[SPX_N]

chain 的第一個參數 X,雖然演算法只說它是一個 string,不過在整份 FIPS 205 裡,每一次 call chain,X 都是一個長度為 n 的陣列,所以 X 的宣告就直接用 const uint8_t X[SPX_N]

這個 SPX_N 是 parameter sets 的 n,在 SLH-DSA-SHA2-128s 裡,n 就是 16

chain 演算法逐行寫,像這樣

void chain(uint8_t out[SPX_N],
           const uint8_t X[SPX_N], 
           const uint8_t i,
           const uint8_t s,
           const unsigned char pk_seed[SPX_N], 
           ADRS adrs)
{
    // 1: tmp <- X
    memcpy(out, X, SPX_N);

    int last_idx = i + s - 1;
    for(unsigned int j = i; j < last_idx; ++j)
    {
        set_hash_addr(adrs, j);
        // 𝑡𝑚𝑝 ← F(PK.seed, ADRS,𝑡𝑚𝑝)
        F(pk_seed, adrs, out, out)
    }
}

FIPS 205 第 23 頁 [1] 有這一段

The xmss_sign function (Algorithm 10) creates an XMSS signature on an 𝑛-byte message 𝑀

xmss_sign 的 M 就是傳給 wots_sign 的 M,所以 wots_sign 的 M 可以直接定義為 uint8_t M[SPX_N]

wots_sign 的 implementation 大概是這樣

void wots_sign(N_BYTES out[SPX_LEN],
               const uint8_t M[SPX_N], 
               const unsigned char sk_seed[SPX_N], 
               const unsigned char pk_seed[SPX_N], 
               ADRS adrs)
{

    ...

    ADRS skADRS;

    // 8: skADRS ← ADRS ▷ copy address to create key generation key address
    memcpy(skADRS, adrs, 32);

    // 9: skADRS.setTypeAndClear(WOTS_PRF)
    set_type_and_clear(skADRS, WOTS_PRF);

    // 10: skADRS.setKeyPairAddress(ADRS.getKeyPairAddress())
    set_key_pair_addr(skADRS, get_key_pair_addr(adrs));

    uint8_t sk[SPX_N];
    for(int i = 0; i < SPX_LEN; ++i)
    {
        // skADRS.setChainAddress(𝑖)
        set_chain_addr(skADRS, i);

        // 𝑠𝑘 ← PRF(PK.seed, SK.seed, skADRS) ▷ compute chain 𝑖 secret value
        prf(pk_seed, sk_seed, skADRS, sk);

        // ADRS.setChainAddress(𝑖)
        set_chain_addr(adrs, i);

        // 𝑠𝑖𝑔[𝑖] ← chain(𝑠𝑘, 0, 𝑚𝑠𝑔[𝑖], PK.seed, ADRS) ▷ compute chain 𝑖 signature value
        // chain(uint8_t out[SPX_N], ...
        chain(out[i], sk_seed, 0, msg[i], pk_seed, adrs);
    }
}

xmss_sign 會呼叫 wots_sign,其所產生的 WOTS+ signature,會成為 XMSS signature 的一部份。接下來的內容,我將盡量不再提到 WOTS+ signature,也盡量不再提到 wots_sign,因為接下來要說的是 ht_sign 如何用 XMSS signature 和 XMSS public key 產生 hypertree signature。

盡量不提 WOTS+ signature 是為了將焦點放在 XMSS signature 和 XMSS public key。

截錄自 Algorithm 19 slh_sign_internal,FIPS 第 35 頁

SIG𝐻𝑇 ← ht_sign(PK_fors, SK.seed, PK.seed,𝑖𝑑𝑥𝑡𝑟𝑒𝑒,𝑖𝑑𝑥𝑙𝑒𝑎𝑓)

截錄自 Algorithm 12 ht_sign,FIPS 第 27 頁

SIG𝑡𝑚𝑝 ← xmss_sign(𝑀, SK.seed,𝑖𝑑𝑥𝑙𝑒𝑎𝑓, PK.seed, ADRS)
SIG𝐻𝑇 ← SIG𝑡𝑚p
𝑟𝑜𝑜𝑡 ← xmss_pkFromSig(𝑖𝑑𝑥𝑙𝑒𝑎𝑓, SIG𝑡𝑚𝑝, 𝑀, PK.seed, ADRS)
for 𝑗 from 1 to 𝑑 − 1 do
    SIG𝑡𝑚𝑝 ← xmss_sign(𝑟𝑜𝑜𝑡, SK.seed,𝑖𝑑𝑥𝑙𝑒𝑎𝑓, PK.seed, ADRS)
    SIG𝐻𝑇 ← SIG𝐻𝑇 ∥ SIG𝑡𝑚p
    if 𝑗 < 𝑑 − 1 then
        𝑟𝑜𝑜𝑡 ← xmss_pkFromSig(𝑖𝑑𝑥𝑙𝑒𝑎𝑓, SIG𝑡𝑚𝑝, 𝑟𝑜𝑜𝑡, PK.seed, ADRS)
    end if
end for

https://ithelp.ithome.com.tw/upload/images/20250928/20140129kbxHbcmVpq.png

對照著看 Figure 1 (FIPS 205 第8頁),從 slh_sign_internalht_sign 能看出,ht_sign 一開始會拿 FORS public key 做為 xmss_sign 的 input,由 xmss_sign 算出 XMSS signature,於是,ht_sign 就取得了第一個 XMSS signature (記住這一個 XMSS signature,它是 HT signature 的第一個 element)。然後,拿此 XMSS signature 給 xmss_pkFromSig 算出 XMSS public key, 這個 XMSS public key 在這裡就是 root,他會用來算 下一個 XMSS signature。

這裡的重點是,XMSS public key 是用來算出 下一個,不是用來回推原本的 XMSS signature。

記住這個 XMSS public key,他在子樹裡是 root,從這一層開始,就會開始走以下的流程

step 1. 拿 root 去給 xmss_sign 計算 XMSS signature (這個 root 雖然代表這一個子樹的 root, 但這個 root 如果用他的上一層來看, 他就是 leaf)
step 2. 拿 XMSS signature 給 xmss_pk_from_sig 計算 xmss public key
step 3. 這個 XMSS public key 視為 root,在 往上一層 的時候,回到 step 1,拿他來計算 XMSS signature,算出來的是上一層的 XMSS signature

References

  1. FIPS 205 Stateless Hash-Based Digital Signature Standard

上一篇
Day 14 產生 Hypertree Signature
系列文
裸機實作 SLH-DSA 簽章:FIPS 205 之演算法實作、測試、防禦與跨平台15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言