一种非格 PQC 签名方法:SLH-DSA (SPHINCS+) 和 OpenSSL 3.5

本文介绍了NIST标准化的哈希签名算法SLH-DSA (SPHINCS+),它是ML-DSA(Dilithium)和FN-DSA(Falcon)的替代方案,文章讨论了它的密钥大小、签名过程,以及在OpenSSL 3.5中的代码实现示例, 并与 ML-DSA 和 Falcon 等方案在密钥长度和安全性上进行了对比。

一种非格 PQC 签名方法:SLH-DSA (SPHINCS+) 和 OpenSSL 3.5

OpenSSL 3.5 的发布对于互联网的安全性来说具有变革性意义,我们看到了 ML-KEM、ML-DSA 和 SLH-DSA 的集成。总的来说,一个量子鲁棒的世界可能更关注格方法,ML-KEM(Kyber)取代 ECDH,ML-DSA(Dilithium)和 FN-FSA(Falcon)取代 ECDSA、RSA 和 EdDSA。但是,对于格方法所基于的 LWE(带错误的学习)难题的长期鲁棒性仍然存在一些担忧。

因此,NIST 已将 SLH-DSA(SPHINCS+)标准化为 ML-DSA 和 FN-DSA 的替代方案。与格方法相比,它具有更小的密钥大小(但速度较慢)。总体而言,我们有两棵私钥树,并为它们创建一个根 Merkle 哈希,以及一棵公钥树。对于 128 位哈希方法,我们最终得到一个 64 字节的根私钥和一个 32 字节的公钥。

密钥大小

Dilithium、Falcon 和 SPHINCS+ 的密钥大小与一系列额外的第一轮签名进行了比较(请注意,如果还存储了种子值,则可以在私钥上再添加 32 字节):

Method                           Public key size    Private key size   Signature size  Security level
------------------------------------------------------------------------------------------------------
ML-DSA-44                         1,312              2,528              2,420         1 (128-bit) Lattice
ML-DSA-65                         1,952              4,000              3,293         3 (192-bit) Lattice
ML-DSA-87                         2,592              4,864              4,595

Falcon 512 (Lattice)                    897              1,281                690         1 (128-bit) Lattice
Falcon 1024                           1,793              2,305              1,330         5 (256-bit) Lattice

Sphincs SHA256-128f Simple               32                 64             17,088         1 (128-bit) Hash-based
Sphincs SHA256-192f Simple               48                 96             35,664         3 (192-bit) Hash-based
Sphincs SHA256-256f Simple               64                128             49,856         5 (256-bit) Hash-based

RSA-2048                                256                256                256
ECC 256-bit                              64                 32                256         5 (256-bit) Lattice

总的来说,Bob 将使用他的私钥为 Alice 签署消息,然后她将使用他的公钥进行检查:

SPHINCS+

SPHINCS+ 使用 WOTS 和 HORST 进行基于哈希的树。该代码使用多个参数:

  • n - WOTS/HORST 中哈希的长度(以位为单位)
  • m - 消息哈希的长度(以位为单位)
  • h - 超树的高度
  • d - 超树的层数
  • w - 用于 WOTS 签名的 Winternitz 参数
  • tau - HORST 树中的层数(2^tau 是密钥元素的数量)
  • k - 每个 HORST 签名中公开的密钥元素的数量

在我们使用的例子中:n=256, m=512, h=2, d=1, w=4, tau=8, k=64。

一些操作使用的哈希方法是 BLAKE,ChaCha20 用于生成随机数。

在你的收件箱中获取 Prof Bill Buchanan OBE FRSE 的故事

该方法是:

  • 最初,我们创建 32 个 256 位的随机数。这 32 个值将是我们的私钥。
  • 然后,我们将每个值哈希 256 次。这 32 个值将是我们的公钥。
  • 现在,我们获取消息并使用 SHA-256 对其进行哈希。这将产生 32 个 8 位的值(N1、N2 … N32)。
  • 对于签名,我们获取消息哈希中的每个 8 位值,然后哈希 256-N 次(其中 N 是 8 位值的值)。
  • 为了证明签名,我们获取消息并使用 SHA-256 对其进行哈希,然后获取每个 8 位值。然后,我们将 8 位签名值哈希消息哈希值定义的次数(N1、N2..)。每个操作的结果应等于公钥值。

如下图所示:

编码

使用 OpenSSL 的代码实现位于 [ 这里]:

##include <stdio.h>
##include <string.h>
##include <stdlib.h>
##include <openssl/evp.h>
##include <openssl/pem.h>
##include <openssl/err.h>
##include <openssl/core_names.h>
##include <openssl/params.h>
##include <openssl/ec.h>
static void hexdump(const char *label, const unsigned char *buf, size_t len) {
    printf("%s (%zu bytes): ", label, len);
    for (size_t i = 0; i < len; i++) printf("%02X", buf[i]);
    printf("\n");
}

static EVP_PKEY *generate_slh(unsigned char *type) {

    EVP_PKEY *pkey = NULL;
    EVP_PKEY_CTX *kctx = EVP_PKEY_CTX_new_from_name(NULL, type, NULL);

    EVP_PKEY_keygen_init(kctx);
    EVP_PKEY_keygen(kctx, &pkey);

 printf("Type: %s\n\n",type);
uint8_t pub[2592], priv[4896];
size_t priv_len, pub_len;

EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY,
                                priv, sizeof(priv), &priv_len);
EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY,
                                pub, sizeof(pub), &pub_len);

printf("Private key length: {%d}\n",priv_len);
hexdump("Private key (truncated to 500 bytes):",priv,priv_len); // 私钥(截断为 500 字节):
printf("\nPublic key length: {%d}\n",pub_len);
hexdump("Public key(truncated to 500 bytes):",pub,pub_len); // 公钥(截断为 500 字节):
    EVP_PKEY_CTX_free(kctx);
    return pkey;
}
int main(int argc, char** argv) {

    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();
    unsigned char *type="SLH-DSA-SHA2-128f";
    if (argc > 1) type  =  argv[1];
    EVP_PKEY *slhdsa = generate_slh(type);

    return EXIT_SUCCESS;
}

一个示例运行是 [ 这里]:

Type: SLH-DSA-SHA2-128f

Private key length: {64}
Private key (truncated to 500 bytes): (64 bytes): 260798B197619C57CCD35CC4186B2904A654C8A8D4F7D214092423A781199CA1168331206D539488B24CE1648435D632723643C8852D037766DEC676DE0820D8

Public key length: {32}
Public key(truncated to 500 bytes): (32 bytes): 168331206D539488B24CE1648435D632723643C8852D037766DEC676DE0820D8

对于 SLH-DSA-SHAKE-256f [ 这里]:

Type: SLH-DSA-SHAKE-256f
Private key length: {128}
Private key (truncated to 500 bytes): (128 bytes): 414E827EC8B91444396613B3AB609F3BF4425F2BD49777B10CBB5591849E8C13900709A3AAA4FA415546ACEC5E6AA86FAE0CF1B58D93FB90F2E69569552D8147AD1690175E377221FCADACD93EE2B26A85668C8F8A3CE18BA25E2D3DEA73FCB2AB895859ADCB316865562FA531F509A09DBD94DBA0183A905B4FD6CEEEDBA3D4

Public key length: {64}
Public key(truncated to 500 bytes): (64 bytes): AD1690175E377221FCADACD93EE2B26A85668C8F8A3CE18BA25E2D3DEA73FCB2AB895859ADCB316865562FA531F509A09DBD94DBA0183A905B4FD6CEEEDBA3D4

如果我们假设 OpenSSL 3.5 安装在 Windows 上的 c:\openssl_3_5 文件夹中,我们可以使用以下命令进行编译:

gcc -o openssl_slhdsa slhdsa.c -Ic:\openssl_3_5\include c:\openssl_3_5\lib\libcrypto.lib

参考

[1] Kannwischer, M. J., Rijneveld, J., Schwabe, P., & Stoffelen, K. (2019). pqm4: Testing and Benchmarking NIST PQC on ARM Cortex-M4.

[2] Bernstein, D. J., Hülsing, A., Kölbl, S., Niederhagen, R., Rijneveld, J., & Schwabe, P. (2019, November). The SPHINCS+ signature framework. In Proceedings of the 2019 ACM SIGSAC Conference on Computer and Communications Security (pp. 2129–2146).

  • 原文链接: medium.com/asecuritysite...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
asecuritysite
asecuritysite
江湖只有他的大名,没有他的介绍。