← 首页 ## XMSS 哈希地址方案

XMSS 哈希地址方案

方案使得每个hash函数调用随机化,除了原始消息摘要,还需要额外的key和不同的bitmask给到每一个hash函数调用。

输入:密钥种子,32字节ADRS
输出:n字节(n是安全参数)

下面是ADRS的结构说明(三种不同类型的地址,对应Type字段)

OTS哈希地址

image-20260621105657468

Type = 0

keyAndMask:用于为一个哈希函数调用生成两个不同地址
生成密钥:keyAndMask <—— 0
生成掩码(n Byte):keyAndMask <—— 1

L-树哈希地址

image-20260621105739149

作用:压缩一次性公钥

Type = 1

keyAndMask:用于为一个函数调用生成三个不一样的地址
生成密钥:keyAndMask <—— 0
生成掩码(n Byte):keyAndMask <—— 1 (最高有效n字节)
生成掩码(n Byte):keyAndMask <—— 2 (最高次有效n字节)

哈希树地址

image-20260621105903324

type = 2
Padding = 0

keyAndMask:用于为一个函数调用生成三个不一样的地址
生成密钥:keyAndMask <—— 0
生成掩码(n Byte):keyAndMask <—— 1 (最高有效n字节)
生成掩码(n Byte):keyAndMask <—— 2 (最高次有效n字节)

基w数的字符串

一个字节字符串可以看作是以w为基数的字符串,即集合{0,1,..,w-1}中整数

image-20260621110145238

成员函数

WOTS+

One-Time Signatures

每个私钥只能用于对单个消息进行一次签名。特别是,如果使用私钥对两条不同的消息进行签名,则该方案将变得不安全。

WOTS+ 参数

n:消息长度以及私钥、公钥或签名元素的长度(以字节为单位)。

w:Winternitz参数;它是集合{4,16}的一个成员。

w值越大,签名越短,但总体签名操作越慢;它对安全几乎没有影响。w的选择仅限于值4和16,因为这些值产生最佳的权衡和易于实现。

WOTS+伪随机函数

WOTS+算法使用密钥加密哈希函数F。F使用长度为n的密钥接受并返回长度为n的字节字符串。有关特定实例化的更多详细信息,请参见第5节。第9节讨论了F的安全要求。此外,WOTS+使用伪随机函数PRF。PRF采用一个n字节的键和一个32字节的索引作为输入,并生成长度为n的伪随机输出。有关特定实例化的更多详细信息,请参见第5节。第9节讨论了PRF的安全要求。

WOTS+链接函数

链接函数F(算法2)使用PRF的输出的n字节作为输入,进行迭代。它以一个OTS哈希地址作为输入。此地址将设置前6个32位字来编码此链的地址。在每次迭代中,PRF用于为F生成一个键和一个位掩码,该位掩码在F处理中间结果之前异或到中间结果。在下文中,ADRS是第2.5节中指定的32字节OTS哈希地址,SEED是一个n字节字符串。为了生成密钥和位掩码,调用PRF,以种子作为密钥,ADR作为输入。链函数将n字节字符串X、开始索引i、若干步骤s以及adr和SEED作为输入。链函数使用PRF的输出,将F在输入X上迭代s次得到的值作为输出返回。

Algorithm 2: 链-链函数

输入:
X,输入字符串
i,开始索引
s,步数
SEED,种子
ADRS,地址
输出:
F,X上迭代s次的值

image-20260621111931011

WOTS+私钥

WOTS+中的私钥由sk表示(s表示secret),是一个长度为len的n字节字符串数组。此私钥最多只能用于签署一封邮件。每个n字节字符串必须从均匀分布中随机选择,或者使用加密安全伪随机过程选择。

Algorithm 3: WOTS生成私钥

输入:无输入
输出:WOTS+私钥sk

     for ( i = 0; i < len; i++ ) {
       initialize sk[i] with a uniformly random n-byte string;
     }
     return sk;

WOTS+公钥

WOTS+密钥对定义了一个虚拟结构,该结构由长度为w的len散列链组成。私钥中的lenn字节字符串分别定义一个哈希链的起始节点。公钥由这些散列链的末端节点组成。因此,与私钥一样,公钥也是一个长度为len的n字节字符串数组。为了计算散列链,使用链接函数(算法2)。OTS哈希地址ADR和种子必须由调用算法提供。该地址将在更大的结构中对WOTS+密钥对的地址进行编码。因此,除最后三个32位字外,WOTS+算法不得操纵ADR的任何部分。请注意,此处使用的种子是公开信息,也可供验证人使用。以下伪代码(算法4)描述了用于生成公钥pk的算法,其中sk是私钥。

Algorithm 4: WOTS私钥生成公钥

Input:
sk, WOTS+ private key
ADRS, address
SEED,seed
Output:
pk,WOTS+ public key

     for ( i = 0; i < len; i++ ) {
       ADRS.setChainAddress(i);
       pk[i] = chain(sk[i], 0, w - 1, SEED, ADRS);
     }
     return pk;

WOTS+签名生成

WOTS+签名是由n字节字符串组成的长度为len的数组。WOTS+签名是通过将消息映射到0和w-1之间的len整数生成的。为此,使用第2.6节中定义的base_w函数将消息转换为len_1 base w编号。接下来,使用base_w函数计算校验和,并将其作为len_2 base w数附加到转换后的消息中。注意,校验和可能达到len_1(w-1)2^8的最大整数值,因此取决于参数n和w。对于第5节中给出的参数集,32位无符号整数足以保存校验和。如果使用其他参数设置,则保存校验和整数值的变量的大小必须足够大。每个基w整数用于从不同的哈希链中选择节点。签名是通过连接所选节点形成的。OTS哈希地址ADR和种子必须由调用算法提供。该地址将在更大的结构中对WOTS+密钥对的地址进行编码。因此,WOTS+算法不得操纵该算法的任何部分

除最后三个32位字外的ADR。请注意,此处使用的种子是公开信息,也可供验证人使用。用于生成签名的伪码如下所示(算法5),其中M是消息,sig是结果签名。

Algorithm 5: WOTS签名

Input:
M, Message
sk, WOTS+ private key
ADRS, address
SEED, seed
Output:
sig, WOTS+ signature

csum = 0;

 // Convert message to base w
 msg = base_w(M, w, len_1);

 // Compute checksum
 for ( i = 0; i < len_1; i++ ) {
       csum = csum + w - 1 - msg[i];
 }

 // Convert csum to base w
 csum = csum << ( 8 - ( ( len_2 * lg(w) ) % 8 ));
 len_2_bytes = ceil( ( len_2 * lg(w) ) / 8 );
 msg = msg || base_w(toByte(csum, len_2_bytes), w, len_2);
 for ( i = 0; i < len; i++ ) {
      ADRS.setChainAddress(i);
      sig[i] = chain(sk[i], 0, msg[i], SEED, ADRS);
 }
 return sig;

签名的数据格式:

image-20260621145406219

WOTS+签名验证

为了验证消息M上的签名sig,验证器从签名计算WOTS+公钥值。这可以通过使用消息散列的基w值及其校验和,从签名值开始“完成”链计算来完成。该步骤称为WOTS_pkFromSig,在算法6中描述如下。然后将WOTS_pkFromSig的结果与给定的公钥进行比较。如果值相等,则接受签名。否则,必须拒绝签名。OTS哈希地址ADR和种子必须由调用算法提供。该地址将在更大的结构中对WOTS+密钥对的地址进行编码。因此,除最后三个32位字外,WOTS+算法不得操纵ADR的任何部分。请注意,此处使用的种子是公开信息,也可供验证人使用。

算法6:WOTS从消息及其签名计算WOTS+公钥

Input:
M, Message
sig, WOTS+ signature
ADRS, address
SEED,seed
Output:
tmp_pk,'Temporary' WOTS+ public key

csum=0;

 // Convert message to base w
 msg = base_w(M, w, len_1);

 // Compute checksum
 for ( i = 0; i < len_1; i++ ) {
       csum = csum + w - 1 - msg[i];
 }

 // Convert csum to base w
 csum = csum << ( 8 - ( ( len_2 * lg(w) ) % 8 ));
 len_2_bytes = ceil( ( len_2 * lg(w) ) / 8 );
 msg = msg || base_w(toByte(csum, len_2_bytes), w, len_2);
 for ( i = 0; i < len; i++ ) {
      ADRS.setChainAddress(i);
      tmp_pk[i] = chain(sig[i], msg[i], w - 1 - msg[i], SEED, ADRS);
 }
 return tmp_pk;

伪随机密钥生成

种子seed随机,保密