1 /*
2 * This file is part of the openHiTLS project.
3 *
4 * openHiTLS is licensed under the Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 *
8 * http://license.coscl.org.cn/MulanPSL2
9 *
10 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13 * See the Mulan PSL v2 for more details.
14 */
15 #include "hitls_build.h"
16 #ifdef HITLS_CRYPTO_SLH_DSA
17
18 #include <stdint.h>
19 #include <stddef.h>
20 #include "securec.h"
21 #include "bsl_err_internal.h"
22 #include "bsl_sal.h"
23 #include "crypt_errno.h"
24 #include "slh_dsa_local.h"
25 #include "slh_dsa_xmss.h"
26 #include "slh_dsa_wots.h"
27
XmssNode(uint8_t * node,uint32_t idx,uint32_t height,SlhDsaAdrs * adrs,const CryptSlhDsaCtx * ctx)28 int32_t XmssNode(uint8_t *node, uint32_t idx, uint32_t height, SlhDsaAdrs *adrs, const CryptSlhDsaCtx *ctx)
29 {
30 int32_t ret;
31 if (node == NULL || adrs == NULL || ctx == NULL) {
32 return CRYPT_NULL_INPUT;
33 }
34
35 uint32_t n = ctx->para.n;
36
37 // If height is 0, compute WOTS+ public key
38 if (height == 0) {
39 ctx->adrsOps.setType(adrs, WOTS_HASH);
40 ctx->adrsOps.setKeyPairAddr(adrs, idx);
41 return WotsGeneratePublicKey(node, adrs, ctx);
42 }
43 // Compute internal node
44 uint8_t leftNode[SLH_DSA_MAX_N] = {0};
45 uint8_t rightNode[SLH_DSA_MAX_N] = {0};
46
47 // Compute left child
48 ret = XmssNode(leftNode, 2 * idx, height - 1, adrs, ctx);
49 if (ret != CRYPT_SUCCESS) {
50 return ret;
51 }
52
53 // Compute right child
54 ret = XmssNode(rightNode, 2 * idx + 1, height - 1, adrs, ctx);
55 if (ret != CRYPT_SUCCESS) {
56 return ret;
57 }
58
59 // Hash children to get parent node
60 ctx->adrsOps.setType(adrs, TREE);
61 ctx->adrsOps.setTreeHeight(adrs, height);
62 ctx->adrsOps.setTreeIndex(adrs, idx);
63
64 uint8_t tmp[SLH_DSA_MAX_N * 2];
65 (void)memcpy_s(tmp, SLH_DSA_MAX_N * 2, leftNode, n);
66 (void)memcpy_s(tmp + n, SLH_DSA_MAX_N * 2 - n, rightNode, n);
67
68 return ctx->hashFuncs.h(ctx, adrs, tmp, 2 * n, node);
69 }
70
XmssSign(const uint8_t * msg,size_t msgLen,uint32_t idx,SlhDsaAdrs * adrs,const CryptSlhDsaCtx * ctx,uint8_t * sig,uint32_t * sigLen)71 int32_t XmssSign(const uint8_t *msg, size_t msgLen, uint32_t idx, SlhDsaAdrs *adrs, const CryptSlhDsaCtx *ctx,
72 uint8_t *sig, uint32_t *sigLen)
73 {
74 int32_t ret;
75
76 uint32_t n = ctx->para.n;
77 uint32_t hp = ctx->para.hp;
78 uint32_t len = 2 * n + 3;
79
80 if (*sigLen < (len + hp) * n) {
81 return CRYPT_SLHDSA_ERR_SIG_LEN_NOT_ENOUGH;
82 }
83
84 for (uint32_t j = 0; j < hp; j++) {
85 uint32_t k = (idx >> j) ^ 1;
86 uint8_t node[SLH_DSA_MAX_N] = {0};
87 ret = XmssNode(node, k, j, adrs, ctx);
88 if (ret != CRYPT_SUCCESS) {
89 return ret;
90 }
91 (void)memcpy_s((sig + (len + j) * n), n, node, n);
92 }
93
94 ctx->adrsOps.setType(adrs, WOTS_HASH);
95 ctx->adrsOps.setKeyPairAddr(adrs, idx);
96 uint32_t tmpLen = len * n;
97 ret = WotsSign(sig, &tmpLen, msg, (uint32_t)msgLen, adrs, ctx);
98 if (ret != CRYPT_SUCCESS) {
99 return ret;
100 }
101 *sigLen = (len + hp) * n;
102 return CRYPT_SUCCESS;
103 }
104
XmssPkFromSig(uint32_t idx,const uint8_t * sig,uint32_t sigLen,const uint8_t * msg,uint32_t msgLen,SlhDsaAdrs * adrs,const CryptSlhDsaCtx * ctx,uint8_t * pk)105 int32_t XmssPkFromSig(uint32_t idx, const uint8_t *sig, uint32_t sigLen, const uint8_t *msg, uint32_t msgLen,
106 SlhDsaAdrs *adrs, const CryptSlhDsaCtx *ctx, uint8_t *pk)
107 {
108 int32_t ret;
109 uint32_t n = ctx->para.n;
110 uint32_t hp = ctx->para.hp;
111 uint32_t len = 2 * n + 3;
112
113 if (sigLen < (len + hp) * n) {
114 return CRYPT_SLHDSA_ERR_SIG_LEN_NOT_ENOUGH;
115 }
116
117 ctx->adrsOps.setType(adrs, WOTS_HASH);
118 ctx->adrsOps.setKeyPairAddr(adrs, idx);
119 uint8_t node0[SLH_DSA_MAX_N] = {0};
120 uint8_t node1[SLH_DSA_MAX_N] = {0};
121 ret = WotsPubKeyFromSig(msg, msgLen, sig, sigLen, adrs, ctx, node0);
122 if (ret != CRYPT_SUCCESS) {
123 return ret;
124 }
125 ctx->adrsOps.setType(adrs, TREE);
126 ctx->adrsOps.setTreeIndex(adrs, idx);
127 for (uint32_t k = 0; k < hp; k++) {
128 ctx->adrsOps.setTreeHeight(adrs, k + 1);
129 uint8_t tmp[SLH_DSA_MAX_N * 2];
130 if (((idx >> k) & 1) != 0) {
131 (void)memcpy_s(tmp, sizeof(tmp), sig + (len + k) * n, n);
132 (void)memcpy_s(tmp + n, sizeof(tmp) - n, node0, n);
133 ctx->adrsOps.setTreeIndex(adrs, (ctx->adrsOps.getTreeIndex(adrs) - 1) >> 1);
134 } else {
135 (void)memcpy_s(tmp, sizeof(tmp), node0, n);
136 (void)memcpy_s(tmp + n, sizeof(tmp) - n, sig + (len + k) * n, n);
137 ctx->adrsOps.setTreeIndex(adrs, ctx->adrsOps.getTreeIndex(adrs) >> 1);
138 }
139 ret = ctx->hashFuncs.h(ctx, adrs, tmp, 2 * n, node1);
140 if (ret != CRYPT_SUCCESS) {
141 return ret;
142 }
143 (void)memcpy_s(node0, sizeof(node0), node1, sizeof(node1));
144 }
145 (void)memcpy_s(pk, n, node0, n);
146 return CRYPT_SUCCESS;
147 }
148
149 #endif // HITLS_CRYPTO_SLH_DSA